diff --git a/.forgejo/pre-commit/config.yaml b/.forgejo/pre-commit/config.yaml deleted file mode 100644 index 8ce116dae..000000000 --- a/.forgejo/pre-commit/config.yaml +++ /dev/null @@ -1,23 +0,0 @@ -exclude: ^tests/ref/ - -repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 - hooks: - - id: check-case-conflict - - id: check-executables-have-shebangs - - id: check-illegal-windows-names - - id: check-shebang-scripts-are-executable - - id: check-yaml - - id: end-of-file-fixer - - id: fix-byte-order-marker - - id: mixed-line-ending - - id: trailing-whitespace -- repo: local - hooks: - - id: aarch64-asm-indent - name: fix aarch64 assembly indentation - files: ^.*/aarch64/.*\.S$ - language: script - entry: ./tools/check_arm_indent.sh --apply - pass_filenames: false diff --git a/.forgejo/workflows/lint.yml b/.forgejo/workflows/lint.yml deleted file mode 100644 index e4ffed751..000000000 --- a/.forgejo/workflows/lint.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Lint - -on: - push: - branches: - - release/7.1 - pull_request: - -jobs: - lint: - name: Pre-Commit - runs-on: utilities - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - name: Install pre-commit CI - id: install - run: | - python3 -m venv ~/pre-commit - ~/pre-commit/bin/pip install --upgrade pip setuptools - ~/pre-commit/bin/pip install pre-commit - echo "envhash=$({ python3 --version && cat .forgejo/pre-commit/config.yaml; } | sha256sum | cut -d' ' -f1)" >> $FORGEJO_OUTPUT - - name: Cache - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 - with: - path: ~/.cache/pre-commit - key: pre-commit-${{ steps.install.outputs.envhash }} - - name: Run pre-commit CI - run: ~/pre-commit/bin/pre-commit run -c .forgejo/pre-commit/config.yaml --show-diff-on-failure --color=always --all-files diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml deleted file mode 100644 index 52a82c7b4..000000000 --- a/.forgejo/workflows/test.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: Test - -on: - push: - branches: - - release/7.1 - pull_request: - -jobs: - run_fate: - name: Fate (${{ matrix.runner }}, ${{ matrix.shared }}, ${{ matrix.bits }} bit) - strategy: - fail-fast: false - matrix: - runner: [linux-aarch64] - shared: ['static'] - bits: ['64'] - include: - - runner: linux-amd64 - shared: 'static' - bits: '32' - - runner: linux-amd64 - shared: 'shared' - bits: '64' - runs-on: ${{ matrix.runner }} - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - name: Configure - run: | - ./configure --enable-gpl --enable-nonfree --enable-memory-poisoning --assert-level=2 \ - $([ "${{ matrix.bits }}" != "32" ] || echo --arch=x86_32 --extra-cflags=-m32 --extra-cxxflags=-m32 --extra-ldflags=-m32) \ - $([ "${{ matrix.shared }}" != "shared" ] || echo --enable-shared --disable-static) \ - || CFGRES=$? && CFGRES=$? - cat ffbuild/config.log - exit $CFGRES - - name: Build - run: make -j$(nproc) - - name: Restore Cached Fate-Suite - id: cache - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 - with: - path: fate-suite - key: fate-suite - restore-keys: | - fate-suite- - - name: Sync Fate-Suite - id: fate - run: | - make fate-rsync SAMPLES=$PWD/fate-suite - echo "hash=$(find fate-suite -type f -printf "%P %s %T@\n" | sort | sha256sum | cut -d' ' -f1)" >> $FORGEJO_OUTPUT - - name: Cache Fate-Suite - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 - if: ${{ format('fate-suite-{0}', steps.fate.outputs.hash) != steps.cache.outputs.cache-matched-key }} - with: - path: fate-suite - key: fate-suite-${{ steps.fate.outputs.hash }} - - name: Run Fate - run: LD_LIBRARY_PATH="$(printf "%s:" "$PWD"/lib*)$PWD" make fate fate-build SAMPLES=$PWD/fate-suite -j$(nproc) - compile_only: - name: Fate (Win64, Build-Only) - strategy: - fail-fast: false - matrix: - image: ["ghcr.io/btbn/ffmpeg-builds/win64-gpl-7.1:latest"] - runs-on: linux-amd64 - container: ${{ matrix.image }} - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - name: Configure - run: | - ./configure --pkg-config-flags="--static" $FFBUILD_TARGET_FLAGS $FF_CONFIGURE \ - --cc="$CC" --cxx="$CXX" --ar="$AR" --ranlib="$RANLIB" --nm="$NM" \ - --extra-cflags="$FF_CFLAGS" --extra-cxxflags="$FF_CXXFLAGS" \ - --extra-libs="$FF_LIBS" --extra-ldflags="$FF_LDFLAGS" --extra-ldexeflags="$FF_LDEXEFLAGS" - - name: Build - run: make -j$(nproc) - - name: Run Fate - run: make -j$(nproc) fate-build diff --git a/.mailmap b/.mailmap index fe019b88c..58383fa56 100644 --- a/.mailmap +++ b/.mailmap @@ -26,3 +26,5 @@ rcombs Cosmin Stejerean Cosmin Stejerean via ffmpeg-devel + + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c2b79e452..426f02f34 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ # Note to Github users -Patches should be submitted to the [ffmpeg-devel mailing list](https://ffmpeg.org/mailman/listinfo/ffmpeg-devel) using `git format-patch` or `git send-email`. Github pull requests should be avoided because they are not part of our review process and **will be ignored**. +Patches should be submitted to [Forgejo](https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls) or the [ffmpeg-devel mailing list](https://ffmpeg.org/mailman/listinfo/ffmpeg-devel) using `git format-patch` or `git send-email`. Github pull requests should be avoided because they are not part of our review process and **will be ignored**. See [https://ffmpeg.org/developer.html#Contributing](https://ffmpeg.org/developer.html#Contributing) for more information. diff --git a/Changelog b/Changelog index 57f020872..727b4e60d 100644 --- a/Changelog +++ b/Changelog @@ -1,15 +1,18 @@ Entries are sorted chronologically from oldest to youngest within each release, releases are sorted from youngest to oldest. -version 7.1.4: +version 8.1.1: + avcodec/aac/aacdec_usac_mps212: fix attach_lsb() OOB after huff_decode avcodec/dfpwmdec: Check nb_samples avcodec/alsdec: do not set nbits invalidly swscale/swscale_unscaled: adjust last line copy + swscale/swscale: Check srcSliceY and srcSliceH avformat/avidec: check LIST size in avi_load_index() avformat/avidec: validate INFO list size before parsing avformat/matroskadec: Check audio.sub_packet_h * audio.frame_size libavformat/xwma: fix overflow in seek position avformat/pcm: Use 64bit for byte_rate + avcodec/adpcm: signed integer overflow in ADPCM_N64 avcodec/hevc/ps: validate rep_format dimensions in multi-layer SPS avfilter/vf_kerndeint: Check for minimum height avcodec/ralf: Add the missing return statement after the error log @@ -52,12 +55,16 @@ version 7.1.4: avfilter/vf_ssim360: fix integer overflow in tape_length allocation avcodec/escape130: Initialize old_y_avg avutil/samplefmt: Dont claim that av_get_sample_fmt_string checks sample_fmt + swscale: fix signed integer overflow in color conversion arithmetic avformat: check avio_read() return values in dss/dtshd/mlv + avformat/whip: check RTP history packet size before RTX retransmission avcodec/aac/aacdec_usac: Implement missing bits of otts_bands_phase and residual_bands computation avcodec/alsdec: preserve full float value in zero-truncated samples avcodec/alsdec: propagate read_diff_float_data() errors in read_frame_data() avcodec/alsdec: fix mantissa unpacking in compressed Part A path avfilter/vf_drawtext: fix newline rendered as .notdef glyph + avcodec/pngdec: fix dead overflow check in decode_text_to_exif() + avcodec/vp9: fix cbs fragment leak on error libavfilter/vf_v360: fix operator precedence in stereo loop condition avcodec/alsdec: fix abs(INT_MIN) UB in read_diff_float_data() avformat/rsd: reject short ADPCM_THP extradata reads @@ -66,590 +73,84 @@ version 7.1.4: avfilter/af_pan: fix sscanf() return value checks in parse_channel_name avutil/bswap: fix implicit conversion warning in av_bswap64 avcodec/h2645_sei: don't use provider_code uninitialized - avformat/mpegts: fix descriptor accounting across multiple IOD descriptors - avcodec/xxan: zero-initialize y_buffer - avcodec/exr: Check input space before reverse_lut() - avcodec/cbs_h266_syntax_template: Check tile_y - avcodec/h264_slice: reject slice_num >= 0xFFFF - lavfi/bwdif: fix heap-buffer-overflow with small height videos - avcodec/cbs_h266_syntax_template: Fix w/h typo - aacdec_usac: skip FD-specific decoding for LPD channels - avutil/timecode: Check for integer overflow in av_timecode_init_from_components() - avcodec/cbs_h266_syntax_template: Fix rows vs columns - avformat/mov: do not allocate out-of-range buffers - avfilter/af_lv2: call lilv_instance_activate before lilv_instance_run - avformat/rtmpproto: fix listen_timeout conversion for special negative values - avcodec/aom_film_grain: Remove impossible check - avcodec/aom_film_grain: avoid duplicate indexes in ff_aom_parse_film_grain_sets() - swscale/output: fix integer overflows in chroma in yuv2rgba64_X_c_template() - avcodec/lcldec: Fixes uqvq overflow - fftools/ffmpeg_demux: Check metadata provided filename - avcodec/av1dec: sync frame header and tile group behavior with CBS - avformat/mlvdec: avoid uninitialized read in read_string() - avcodec/magicyuv: fix small median images - swscale/output: Fix integer overflow in alpha in yuv2rgba64_1_c_template() - swscale/utils: Check *Inc - avfilter/vf_scale: Fix integer overflow in config_props() - swscale/output: Fixes integer overflow in yuv2planeX_8_c - swscale/utils: initialize chroma when luma switched to cascade - avcodec/utils: fix duration computation based on frame_bytes - avcodec/cbs_h266_syntax_template: bound slice width/height by remaining tiles - avformat/rtsp: Pass blacklist - avformat/rtsp: Explicitly check protocol - avfilter/vf_convolution: Use avpriv_mirror - avfilter/vf_convolution: Handle corner cases with small frames - avcodec/pnmdec: Check input size against width*height assuming at least 1bit per pixel - avformat/mov: Fix multiple issues related to mov_read_iref_dimg() - avcodec/snowenc: avoid NULL ptr arithmetic - avformat/mov: use 64bit in CENC subsample bounds checks - avutil/eval: Check depth of AVExpr - avformat/vividas: Reset n_audio_subpackets on error - avformat/matroskadec: Check that end_time_ns >= start_time_ns - avcodec/vp3: Sanity check cropping - avformat/dhav: Check avio_seek() return - avformat/segafilm: dont read uninitialized value - avcodec/mpegvideo_enc: Restructure ff_h263_encode_gob_header() relation to update_mb_info() - avcodec/exr: check tile_attr.x/ySize - avformat/demux: Fix integer overflows in select_from_pts_buffer() - avcodec/golomb: Fix get_ur_golomb_jpegls() with esclen = 0 - swresample/resample_template: add casts to avoid undefined overflows - avcodec/h264_parser: Check pts for overflow - avformat/rtpenc: use unsigned type for ssrc option - avformat/wtvdec: Check that language is fully read - avcodec/imm5: Dont pass EAGAIN on as is - avcodec/interplayacm: Check input for fill_block() - avcodec/hdrdec: Check input size before buffer allocation - avcodec/tmv: Move space check before buffer allocation - avcodec/flashsv: Check for input space before (re)allocating frame - avcodec/mdec: Check input space vs minimal block size - avcodec/h264_parser: Check remaining input length in loop in scan_mmco_reset() - avcodec/exr: fix AVERROR typo - avcodec/jpeg2000htdec: Check Lcup and Lref - avcodec/cfhd: Check transform type before continuing - avcodec/cfhd: Add CFHDSegment enum and named identifiers - avcodec/hevc/ps: Check bit_depth_cm in/out relation - avformat/icodec: Check size - avformat/lrcdec: Check ss for finiteness - avformat/http: Also count redirects from the cache - avformat/http: allow adjusting the redirect limit - fftools/ffmpeg_opt: limit recursion of presets - swscale/rgb2rgb_template: fix signed shift into sign bit - swresample: Check ch layouts in swr_alloc_set_opts2() - swresample: Check user chlayout in swr_set_matrix() - avcodec/bmp: fix indention - avcodec/exr: Handle axmax like bxmin in 04d7a6d3db56ea1a93908ff2d3d312e3fc40a58c - avformat/flvdec: Check *size in cts parsing - avformat/cafdec: Check nb_entries in read_info_chunk() - avcodec/vp9: Reallocate on resolution change which does not change tile_cols - avformat/img2dec: Check avio_size() for failure - avformat/mpegtsenc: Check remaining space in SDT - avformat/img2enc: Check split planes packet size - avformat/yuv4mpegen: Sanity check input packet frame dimensions - avformat/iff: Error out with 0 channel loudspeaker configuration - Fix overflow in STSD parser - avcodec/adpcm: Check input buffer size - avformat/scd: Use ffio_read_size() - avcodec/hevc/sei: Use get_bits64() in decode_nal_sei_3d_reference_displays_info() - avformat/hls: Check for integer overflow with #EXTINF: - avcodec/dca_xll: Clear padding in ff_dca_xll_parse() - vfilter/vf_find_rect: Clamp x/y min/max to valid values - avcodec/lzf: Remove size messing from ff_lzf_uncompress() - avcodec/dxv: Clear tex_data padding on reallocation - avcodec/dca_xll: Check get_rice_array() - avutil/dovi_meta: Document valid range for index of av_dovi_get_ext() - avformat/mpegts: Check program_info_length - avformat/mpegts: Check IOD_DESCRIPTOR len - avcodec/qdm2: fix heap-use-after-free in qdm2_decode_frame - avcodec/jpeg2000dec: Print bpno level when erroring out - avcodec/jpeg2000dec: allow M_b == 31 - avcodec/jpeg2000dec: Print M_b value when asking for a sample - avformat/dashdec: check value valid after read value from mpd xml - swscale/utils: zero init filter memory as before - libavfilter/showcwt: fix OOB write for DU/RL position init - lavc/j2kdec: Do not ignore colour association for packed formats - swscale/utils: Sanity check sizeFactor - swscale/utils: Avoid FF_ALLOC_TYPED_ARRAY() and use av_malloc_array() directly - avcodec/mjpegdec: fix segfault on extern_huff and no extradata - avcodec/exr: use av_realloc_array() - avcodec/omx: Check extradata size and nFilledLen - lavc/aacdec_usac: fix CPE channel index in ff_aac_usac_reset_state() - avfilter/scale_eval: Use 64bit for factor_w/h - avfilter/scale_eval: Avoid undefined behavior with double to int cast - avformat/http: Check that the protocol of redirects is http or https - doc/mailing-list-faq.texi: Fix typo in link anchor - avfilter/vf_find_rect: Fix handling odd sized images - avcodec/notchlc: zero-initialize history buffer - avfilter/vf_stack: add checks for the final canvas dimensions - lavc/vvc: Prevent OOB write to slice_top_left_ctu_x in PPS CBS - avcodec/mjpegdec: only test the size bound in sequential mjpeg - avcodec/jpeg2000htdec: Check pLSB - avformat/hls: fix double space - avformat/hls: Check seg size and offset for overflow - avcodec/jpeg2000dec: Make M_b check broader - swscale/output: Use 64bit in addition in yuv2gbrp16_full_X_c() for RGB + Y - avformat/flac_picture: Correct check - avformat/demux: ensure avformat_find_stream_info updates internal stream contexts - avfilter/vf_neighbor_opencl: add error condition when filter name doesn't match - avfilter/vf_libopencv: make sure there is space for null-terminator in shape_str - avcodec/aacdec: Fix heap-use-after-free in USAC decoding - avdevice/gdigrab: suppress int to pointer cast warning - avutil/hwcontext_d3d12va: use hwdev context for logging - fate: add missing options in config template - avformat/hls_sample_encryption: add missing padding for audio setup buffer - (fforge/pr/22824) lavc/videotoolbox_vp9: fix vpcC flags offset + (fforge/pr/22943) avformat/hls_sample_encryption: add missing padding for audio setup buffer + (fforge/pr/22826) lavc/videotoolbox_vp9: fix vpcC flags offset lavc/videotoolboxenc: return SEI parse errors - (fforge/pr/22407) aarch64/hpeldsp_neon: fix out-of-bounds read - (fforge/pr/22406, fforge/pr/22313) avformat/mov: fix cases where we discard iamf packets from enabled streams - avformat/mov: fix setting iamf stream id offsets - (fforge/pr/21698) avcodec/tableprint_vlc: Unbreak hardcoded tables - tests: Fix fate-run.sh to handle busybox-w32 absolute paths - configure: Recognize uname "Windows_NT" as using an .exe suffix - avformat/tests/movenc: Make objects static - (fforge/pr/21626) avcodec/libsvtav1: rename aq_mode for v4.0.0 - (fforge/pr/21563) avformat/mov: add an offset to IAMF streams - (fforge/pr/21443) avfilter/vf_lcevc: attach a reference to the source frame to each passed in base picture - avfilter/vf_lcevc: support LCEVCdec version 4 - avcodec/lcevc: attach a reference to the source frame to each passed in base picture - avcodec/lcevcdec: free pictures on error - avcodec/lcevcdec: fix input dimensions for the base picture - avcodec/lcevcdec: avoid copying the input frame - avcodec/decode: Optimize lcevc away if disabled - avcodec/decode: Put lcevc fields into structure of their own - avcodec/decode: Don't allocate LCEVC context for non-video - avcodec/lcevcdec: support LCEVCdec version 4 - forgejo: backport CI job names - (fforge/pr/21337) avformat/img2dec: reject input images too big to fit into a single packet - (fforge/pr/21331) avformat/iamf_writer: check that stream count is consistent for ambisonic Audio Elements - avformat/iamf_writer: fix writting some ambisonics fields in Audio Elements - avformat/iamf_parse: fix setting denominator in AVIAMFLayer.demixing_matrix - (fforge/pr/21219) fate/ffmpeg: remove comparison against ref from fix_sub_duration_heartbeat - (fforge/pr/21146) configure: Lower libdvdnav and libdvdread minimum versions for EL9 - (fforge/pr/20943) avformat/rtsp: fix leading space in RTSP reason - avformat/rtsp: do not log invalid values - avformat/http: Handle IPv6 Zone ID in hostname - avfilter/af_amerge: fix possible crash with custom layouts - avfilter/stack_internal: fix checkheaders test - all: apply linter fixes - forgejo: apply needed CI changes for 7.1 - forgejo: backport CI to release/7.1 - (fforge/pr/21089) avcodec/vp3: Sync VLCs once during init, fix crash - configure: unbreak glslang build - avformat/iamf_parse: fix compilation error - avfilter/vf_scale: don't attempt to rescale AV_NOPTS_VALUE - avfilter/framesync: don't attempt to rescale AV_NOPTS_VALUE - avformat/iamf_parse: ensure the stream count in a scalable channel representation is equal to the audio element's stream count - avformat/iamf_parse: ensure each layout in an scalable channel representation has an increasing number of channels - fftools/ffmpeg_filter: close all no-longer needed inputs - avfilter/buffersrc: add av_buffersrc_get_status() + vulkan: fix encode feedback query handling + avcodec/cbs_lcevc: fix writing process blocks with size 6 + avformat/mov: don't try to create an LCEVC group if there's a single track + (fforge/pr/22563) aarch64: Add Armv9.3-A GCS (Guarded Control Stack) support + aarch64: hevcdsp: Make returns match the call site + (fforge/pr/22545) avcodec/lcevcdec: don't try to derive final dimensions from SAR + avcodec/lcevc_parser: move the resolution type table to a header + avcodec/cbs_lcevc: don't look for process blocks if the unit was not decomposed + +version 8.1: +- ffprobe -codec option +- EXIF Metadata Parsing +- gfxcapture: Windows.Graphics.Capture based window/monitor capture +- hxvs demuxer for HXVS/HXVT IP camera format +- MPEG-H 3D Audio decoding via mpeghdec +- D3D12 H.264 encoder +- drawvg filter via libcairo +- ffmpeg CLI tiled HEIF support +- D3D12 AV1 encoder +- ProRes Vulkan hwaccel +- DPX Vulkan hwaccel +- Rockchip H.264/HEVC hardware encoder +- Add vf_scale_d3d12 filter +- JPEG-XS parser +- JPEG-XS decoder and encoder through libsvtjpegxs +- JPEG-XS raw bitstream muxer and demuxer +- IAMF Projection mode Ambisonic Audio Elements muxing and demuxing +- Add vf_mestimate_d3d12 filter +- xHE-AAC Mps212 decoding support (experimental) +- Remove the old HLS protocol handler +- Vulkan compute codec optimizations +- swscale Vulkan support +- LCEVC metadata bitstream filter +- Add vf_deinterlace_d3d12 filter +- ffprobe: only show refs field in stream section when reading frames +- ProRes Vulkan encoder +- LCEVC parser +- LCEVC enhancement layer exporting in MPEG-TS -version 7.1.3: - avutil/common: cast GET_BYTE/GET_16BIT returned value - avfilter/vf_drawtext: fix call GET_UTF8 with invalid argument - avfilter/vf_drawtext: fix incorrect text length - avformat/avformat: also clear FFFormatContext packet queue when closing a muxer - avfilter/vf_drawtext: Account for bbox text seperator - avcodec/mediacodecdec_common: Check that the input to mediacodec_wrap_sw_audio_buffer() contains channel * sample_size - avcodec/utvideodec: Set B for the width= 1 case in restore_median_planar_il() - avcodec/osq: Fix 32bit sample overflow - avformat/rtpdec_rfc4175: Only change PayloadContext on success - avformat/rtpdec_rfc4175: Check dimensions - avformat/rtpdec_rfc4175: Fix memleak of sampling - avformat/http: Fix off by 1 error - avcodec/exr: spelling - avcodec/exr: use tile dimensions in pxr24 UINT case - avcodec/exr: Simple check for available channels - avformat/sctp: Check size in sctp_write() - avformat/rtmpproto: consider command line argument lengths - avformat/rtmpproto_ Check tcurl and flashver length - avcodec/g723_1enc: Make min_err 64bit - avcodec/vlc: Clear val8/16 in vlc_multi_gen() by av_mallocz() - avformat/rtpenc_h264_hevc: Check space for nal_length_size in ff_rtp_send_h264_hevc() - swscale/output: Fix integer overflow in yuv2ya16_X_c_template() - avcodec/hevc/sei: prevent storing a potentially bogus num_ref_displays value in HEVCSEITDRDI - avcodec/exr: Check that DWA has 3 channels - avcodec/exr: check ac_size - avcodec/exr: Round dc_w/h up - avcodec/mjpegdec: Explain buf_size/width/height check - avformat/aviobuf: Keep checksum_ptr consistent in avio_seek() - fftools/ffmpeg_sched: prevent demuxers from getting stuck - lavc/aarch64: Fix addp overflow in ff_pred16x16_plane_neon_10 - avcodec/mlpdec: don't depend on context channel layout when setting substream masks - avformat/demux: pass new extradata to the parser - avcodec/svq1enc: restrict Altivec acceleration to big-endian POWER configurations - libavutil/arm: Rename the HWCAP defines - libavutil/arm: Make use of elf_aux_info() on FreeBSD/OpenBSD - avcodec/decode: sync initial_pict_type and intra_only_flag with thread worker's avctx - avcodec/x86/pngdsp: add missing emms at the end of add_png_paeth_prediction - - -version 7.1.2: - doc/examples/vaapi_encode: fix invalid check on fwrite - avcodec/librsvgdec: fix compilation with librsvg 2.50.3 - fftools/ffmpeg: fix gracefully shutdown - fftools/ffmpeg_demux: ensure the display_rotation option is honored - avcodec/mjpegdec: use ff_frame_new_side_data() to export display matrix - aacdec_usac: use RefStruct to track unfinished extension buffers - avcode: Use av_fast_realloc() in ff_lzf_uncompress() - avcodec/dxv: Check coded_height, to avoid invalid av_clip() - avcodec/aac/aacdec: dont allow ff_aac_output_configure() allocating a new frame if it has no frame - avformat/lrcdec: Fix fate-sub-lrc-ms-remux on x86-32 - avcodec/sanm: Check w,h,left,top - avcodec/utvideodec: Clear plane_start array - fftools/ffmpeg_mux_init: Use 64bit for score computation in map_auto_video() - libavfilter/dnn/dnn_backend_tf: Remove redundant av_freep() to avoid double free - avcodec/dxv: Use av_fast_realloc() for op_data - avcodec/dxv: Use av_fast_realloc() and clear all new space - avcodec/dxv: Clear ctex - avcodec/dxv: Check that we initialize op_data - avcodec/exr: Check for pixel type consistency in DWA - avcodec/d3d12va_encode: fix label followed by a declaration warning - avcodec/libvorbisdec: avoid overflow when assinging sample rate from long to int - avcodec/g726: init missing sample rate - avformat/lrcdec: limit input timestamp range to avoid overflows - avcodec/scpr3: Clear clr - avcodec/ilbcdec: Clear cbvec when used with create_augmented_vector() - avcodec/jpeg2000dec: Make sure the 4 extra bytes allocated are initialized - avfilter/avf_showcqt: fix unbounded index when copying to fft_data - avcodec/aac/aacdec_usac: Limit sfo from noise offset to be above -200 - avcodec/aacsbr_template: Check ilb - avcodec/utvideodec: Set B for the width= 1 case - avcodec/ffv1: Clear state on alloc - avcodec/jpeg2000dec: implement cdef remapping during pixel format matching - avcodec/jpeg2000dec: move cdef default check into get_siz() - avcodec/exr: Check rle_raw_data and surroundings - avcodec/exr: Dont access outside xsize/ysize - examples: Add check and replace av_free() to avoid potential memory errors - libavcodec/tests/snowenc: Add av_free() to avoid memory leak - libavfilter/af_firequalizer: Add check for av_malloc_array() - libavcodec/videotoolbox_vp9: Move av_malloc() to avoid memory leak - avcodec/mpc8: init avctx->sample_rate - avcodec/cbs_h266_syntax_template: fix out of bounds access - avformat/libopenmpt: fix seeking weirdness - avformat/hls: add cmfv/cmfa exceptions - avformat/lrcdec: support arbitrary precision timestamp - libavcodec/tests/motion: Add check for avcodec_alloc_context3() - avcodec/tests/avpacket: Add av_free() to avoid memory leak - examples: Add av_freep to avoid potential memory leak - avcodec/tests/avpacket: Add av_packet_free() to avoid memory leak - avcodec/fits: Clear naxis - avcodec/vqavideo; Check bytestream2_get_buffer() reading next_codebook_buffer - avcodec/lzf: Check for input space - avcodec/imc: Clear padding of buf16 - avcodec/iff: Clear ham_buf - avcodec/cri: Check bytestream2_get_buffer() for end - avcodec/cri: Factor read_len out - avformat/dashdec: Allocate space for appended "/" - avcodec/mpegvideo_dec: Fix lowres=3 field select interlaced mpeg4 frame - avformat/mxg: clear AV_INPUT_BUFFER_PADDING_SIZE - avcodec/shorten: Clear the additionally allocated space on realloc - avformat/vqf: Ensure that comm_chunk is fully read - avformat/mov: make sure file_checksum is fully initialized - avcodec/hevc/hevcdec: Clean sao_pixel_buffer_v on allocation - avformat/asfdec_f: Check amount of value read - avcodec/jpegxl_parser: add sanity check for frame size - avcodec/ffv1dec: don't check chroma_planes for f->colorspace > 0 - avcodec/ffv1dec: don't add offsets to more NULL pointers - avformat/concatdec: Clip duration in one more case in get_best_effort_duration() - avcodec/ffv1dec: Check k in get_vlc_symbol() - avcodec/cfhd: Check idwt_buf size before allocation - avcodec/ivi: Check luma/chroma mb_size - avfilter/vaf_spectrumsynth: don't use uninitialized variable as scale - avcodec/motion_est: don't add offsets to NULL pointers - swscale/swscale_unscaled: don't add offsets to NULL pointers - avcodec/ffv1dec: don't add offsets to NULL pointers - libavcodec/alsdec.c: Add check for av_malloc_array() and av_calloc() - avcodec/psd: Move frame allocation after RLE processing - avcodec/smacker: Move buffer allocation to later - fftools/cmdutils: don't try to load arguments from file if not needed - avcodec/opus: don't materialize buf pointer from null - avfilter/avfilter: fix forwarding EOF for simple API filters in filter_activate_default - avcodec/speexdec: consider differing frame sizes in remaining space check - lavc/vvc: Fix condition for using default scaling factor - avformat/mov: Check that sample_count is allocated in mov_parse_heif_items() - avformat/iff: Check nb_channels == 0 in CHNL - avcodec/osq: Request a coding mode 2 sample - avcodec/osq: Switch back to av_ceil_log2() - avcodec/osq: Add note about update_stats() count - avcodec/osq: Fix signed integer overflow in update_stats() - avcodec/mss2dsp: use FF_PTR_ADD to add offsets to a pointer - avformat/movenc: fix writing reserved bits in EC3SpecificBox - avcodec/hevc/hevcdec: Check num_entry_point_offsets - avcodec/speexdec: Pass and check remaining packets to decode functions - swscale/swscale_unscaled: use 8 line alignment for planarCopyWrapper with dithering - aacenc_tns: clamp filter direction energy measurement - fftools/ffmpeg_demux: don't flag timestamps as unreliable if they are generated - avformat/iamf_parse: prevent overreads in update_extradata - avformat/iamf_parse: increase PutBytes buffer when writing AAC extradata - avformat/matroskadec: check that channels fit in signed 32bit int - avcodec/takdec: Check remaining space for first predictors - avcodec/svq3: Check there are bits left before decompression - avcodec/sonic: Check num_taps - avformat/imf_cpl: fix indention after previous commit - avformat/imf_cpl: do not continue looping forever - avformat/mov: reject negative ELST durations - avformat/avidec: Ignore duplicate GAB2 - MAINTAINERS: Add entry for samples-request - avcodec/h264_mb: Fix tmp_cr for arm - avcodec/vorbisdec: Dont treat overread as error - avcodec/hevc/ps: Fix dependant layer id check - avformat/iff: Check nb_channels == 0 in MHDR - tests/fate/filter-video: Fix dependancy for codecview - postproc/postprocess_template: fix dering with a 16x16 image - libpostproc: check minimum size - avformat/hls: Fix flash1.bogulus.cfd support - avformat/hls: Split allowed_segment_extensions off allowed_extensions - avformat/hls: Fix Youtube AAC - avformat/hls: add fmp4 to allowed_extensions - avformat/hls: Add ec3 to allowed_extensions - avformat/hls: Add cmfv and cmfa to allowed_extensions - postproc/postprocess_template: fix handling of first row of dering_C - postproc/postprocess_template: Fix reading uninitialized pixels in dering_C() - configure: Clearer documentation for "disable-safe-bitstream-reader" - avcodec/osq: avoid undefined negation - swscale/output: Fix integer overflow in yuv2gbrp_full_X_c() - avcodec/libtheora: fix setting keyframe_mask - doc: replace http/git by https urls - Revert "avformat/mpegts: update stream info when PMT ES stream_type changes" - avformat/matroska: Support JPEG2000 for demuxing - avformat/matroskadec: Fix VfW extradata size - configure: Use MSYSTEM_CARCH for default arch on msys2 - avcodec/lcevcdec: don't try to write to output frames directly - avfilter/avfiltergraph: fix regression in picking channel layout - avformat/mpegts: update stream info when PMT ES stream_type changes - avcodec/libzvbi-teletextdec: change new lines to \n in ASS header - avformat/wavdec: increase requested probe score for codec probe - avcodec/h264_slice: insert LCEVC side data before get_buffer() call - avformat/hls: Fix get key file error - avcodec/bsf/h264_mp4toannexb: Fix mixed bitstream format - avformat/mov: Reduce seek when interleaved_read is disabled - avfilter/vf_setparams: Fix chroma_location being cleared - configure: Enable -fno-common for Darwin targets, avoid linker warnings - configure: Only try to use the -no_warn_duplicate_libraries flag on Darwin - configure: Silence Xcode warnings about duplicate libraries - avcodec/mediacodecdec_common: Workaround MTK broken crop implementation - avcodec/Makefile: include aom_film_grain.o file for h264_sei component - lsws/ppc/yuv2rgb_altivec: Fix build in non-VSX environments with Clang v2 - lsws/ppc/yuv2rgb_altivec: Fix build in non-VSX environments with Clang - avcodec/libsvtav1: unbreak build with latest svtav1 - fftools/ffmpeg_filter: also remove display matrix side data from buffered frames - - -version 7.1.1: - avformat/hls: Partially revert "reduce default max reload to 3" - avformat/mov: (v4) fix get_eia608_packet - avformat/iff: Check that we have a stream in read_dst_frame() - avcodec/aac/aacdec_lpd: Limit get_unary() - avcodec/aac/aacdec_usac: Simplify decode_usac_scale_factors() - avcodec/aac/aacdec: Clear SFO on error - avformat/mlvdec: fix size checks - avformat/wavdec: Fix overflow of intermediate in block_align check - avformat/mxfdec: Check edit unit for overflow in mxf_set_current_edit_unit() - avformat/hls: Fix twitter - avcodec/vvc/refs: fix negative pps_scaling_win offsets - libavformat/hls: Be more restrictive on mpegts extensions - avformat/hls: .ts is always ok even if its a mov/mp4 - avcodec/h263dec: Check against previous dimensions instead of coded - avformat/hls: Print input format in error message - avformat/hls: Be more picky on extensions - avformat/iamf_parse: ensure there's at most one of each parameter types in audio elements - avformat/iamf_parse: add missing constrains for num_parameters in audio_element_oub() - avformat/iamf_parse: add missing av_free() call on failure path - lavc/hevcdec: unbreak WPP/progress2 code - fate: Add a dependency on ffprobe for fate-flcl1905 - checkasm: aacencdsp: Actually test nonzero values in quant_bands - x86: aacencdsp: Fix negating signed values in aac_quantize_bands - rtmpproto: Avoid rare crashes in the fail: codepath in rtmp_open - configure: Improve the check for the rsync --contimeout option - avutil/downmix_info: add missing semicolon - doc/t2h: Support texinfo 7.1 and 7.2 pretest - avfilter/drawtext: fix memory leak when using "reinit" runtime command - avutil/downmix_info: zero the allocated buffer - avformat/mov: fix overflow in drift timestamp calculation - Changelog: update - avformat/mxfdec: Check avio_read() success in mxf_decrypt_triplet() - avcodec/huffyuvdec: Initialize whole output for decode_gray_bitstream() - avformat/iamf_reader: Initialize padding and check read in ff_iamf_read_packet() - avformat/ipmovie: Check signature_buffer read - avformat/wtvdec: Initialize buf - avcodec/cbs_vp9: Initialize VP9RawSuperframeIndex - avformat/vqf: Propagate errors from add_metadata() - avformat/vqf: Check avio_read() in add_metadata() - avcodec/ffv1enc: Fix RCT for GBR colorspace - avformat/dashdec: Check whitelist - avutil/avstring: dont mess with NULL pointers in av_match_list() - avfilter/vf_v360: Fix NULL pointer use - avcodec/mpegvideo_enc: Check FLV1 resolution limits - avcodec/ffv1enc: Fix handling of 32bit unsigned symbols - avformat/mov: perform sanity checks for heif before index building - avformat/mov: Factorize sanity check out - avcodec/vc1dec: Clear block_index in vc1_decode_reset() - avcodec/aacsbr_template: Clear n_q on error - avformat/iamf_parse: Check output_channel_count - avcodec/osq: Fixes several undefined overflows in do_decode() - swscale/output: Fix undefined overflow in yuv2rgba64_full_X_c_template() - avfilter/af_pan: Fix sscanf() use - avfilter/vf_grayworld: Use the correct pointer for av_log() - avfilter/vf_addroi: Add missing NULL termination to addroi_var_names[]() - avcodec/get_buffer: Use av_buffer_mallocz() for audio same as its done for video - avformat/jpegxl_anim_dec: clear buffer padding - avformat/rmdec: check that buf if completely filled - avcodec/cfhdenc: Clear dwt_tmp - avcodec/hapdec: Clear tex buffer - avformat/mxfdec: Check that key was read sucessfull - avformat/hevc: fix writing hvcC when no arrays are provided in hvcC-formatted input - avformat/rtpdec: int overflow in start_time_realtime - avcodec/decode: Fix incorrect enum type used in side_data_map() - avformat/mov: fix crash when trying to get a fragment time for a non-existing fragment - avformat/libssh: fix credential variables typo - avformat/hlsenc: check return value of avcodec_parameters_copy() - avformat/dashdec: format open_demux_for_component() - avformat/dashdec: check return code of avcodec_parameters_copy() - avformat/dashdec: return ret directly in open_demux_for_component() - avformat/smoothstreamingenc: check return value of avcodec_parameters_copy() - avcodec/cbs_av1: fix variable shadowing in cbs_av1_split_fragment() - doc/demuxers/dvdvideo: seeking is supported, remove outdated statement - avformat/dvdvideodec: check return code of ff_dvdclut_yuv_to_rgb() - avformat/dvdvideodec: fix missing last chapter marker due to off-by-one - avformat/dvdvideodec: don't allow seeking beyond dvdnav reported duration - avformat/dvdvideodec: discard duplicate or partial AC3 samples - avformat/dvdvideodec: drop packets with unset PTS or DTS - avformat/dvdvideodec: remove unnecessary need_parsing argument - avformat/dvdvideodec: open subdemuxer after initializing IFO headers - avformat/dvdvideodec: remove auto value for menu_lu option - avformat/dvdvideodec: default menu_vts option to 1 and clarify description - avformat/dvdvideodec: check the length of a NAV packet when reading titles - avformat/dvdvideodec: reset the subdemuxer on discontinuity instead of flushing - avformat/dvdvideodec: simplify dvdvideo_read_packet() - avformat/dvdvideodec: enable chapter calculation for menus - avformat/dvdvideodec: standardize the NAV packet event signal - avformat/dvdvideodec: move memcpy below missed NAV packet warning - avformat/dvdvideodec: remove "auto" value for -pg option, default to 1 - avformat/dvdvideodec: measure duration of the current menu VOBU in state - avformat/dvdvideodec: fix menu PGC number off-by-one in state - avformat/dvdvideodec: remove unused headers - lavc/aarch64: Fix ff_pred16x16_plane_neon_10 - lavc/aarch64: Fix ff_pred8x8_plane_neon_10 - aarch64/vvc: Fix clip in alf - vp9: recon: Use emulated edge to prevent buffer overflows - arm: vp9mc: Load only 12 pixels in the 4 pixel wide horizontal filter - aarch64: vp9mc: Load only 12 pixels in the 4 pixel wide horizontal filter - avformat/rpl: Fix check for negative values - avformat/mlvdec: Check avio_read() - avcodec/aac/aacdec: Free channel layout - avformat/mov: dereference pointer after null check - avcodec/utils: Fix block align overflow for ADPCM_IMA_WAV - avformat/matroskadec: Check pre_ns for overflow - tools/target_dec_fuzzer: Adjust threshold for EACMV - tools/target_dec_fuzzer: Adjust threshold for MVC1 - tools/target_dec_fuzzer: Adjust Threshold for indeo5 - avutil/timecode: Avoid fps overflow in av_timecode_get_smpte_from_framenum() - avcodec/aac/aacdec_usac: Dont leave type at a invalid value - avcodec/aac/aacdec_usac: Clean ics2->max_sfb when first SCE fails - avcodec/webp: Check ref_x/y - avcodec/ilbcdec: Initialize tempbuff2 - swscale/swscale_unscaled: Fix odd height with nv24_to_yuv420p_chroma() - avcodec/hevc/hevcdec: initialize qp_y_tab - avformat/qcp: Check for read failure in header - avcodec/eatgq: Check bytestream2_get_buffer() for failure - avformat/dxa: check bpc - swscale/slice: clear allocated memory in alloc_lines() - avcodec/h2645_parse: Ignore NAL with nuh_layer_id == 63 - MAINTAINERS: Lauri is still available but is really low on time nowadays - MAINTAINERS: Remove Guillaume Poirier and Romain Dolbeau - avcodec/mjpegdec: Disallow progressive bayer images - avformat/icodec: fix integer overflow with nb_pal - doc/developer: Document relationship between git accounts and MAINTAINERS - doc/infra: Document trac backup system - doc/infra: Document gitolite - avformat/vividas: Check avio_read() for failure - avformat/ilbc: Check avio_read() for failure - avformat/nistspheredec: Clear buffer - avformat/mccdec: Initialize and check rate.den - avformat/rpl: check channels - INSTALL: explain the circular dependency issue and solution - avformat/mpegts: Initialize predefined_SLConfigDescriptor_seen - avformat/mxfdec: Fix overflow in midpoint computation - swscale/output: used unsigned for bit accumulation - swscale/rgb2rgb_template: Fix ff_rgb24toyv12_c() with odd height - avcodec/rangecoder: only perform renorm check/loop for callers that need it - avcodec/ffv1: add a named constant for the quant table size - avcodec/ffv1: RCT is only possible with RGB - avcodec/ffv1enc: Fix RCT with RGB64 - avcodec/ffv1dec: Fix end computation with ec=2 - avcodec/ffv1enc: Move slice termination into threads - avcodec/ffv1enc: Prevent generation of files with broken slices - avformat/matroskadec: Check desc_bytes so bits fit in 64bit - avformat/mov: Avoid overflow in dts - avcodec/ffv1enc: Correct error message about unsupported version - avcodec/ffv1: Store and reuse sx/sy - avcodec/ffv1enc: Slice combination is unsupported - avcodec/ffv1enc: 2Pass mode is not possible with golomb coding - avfilter/buffersrc: check for valid sample rate - avcodec/libdav1d: clear the buffered Dav1dData on decoding failure - avformat/iamf_writer: ensure the stream groups are not empty - avformat/iamf_writer: fix setting num_samples_per_frame for OPUS - avformat/iamf_parse: fix setting duration for the last subblock in a parameter definition - avformat/iamf_parse: add checks to parameter definition durations - avformat/iamf_parse: reject ambisonics mode > 1 - checkasm: Print benchmarks of C-only functions - avcodec/ac3dec: fix downmix logic for eac3 - avcodec/codec_desc: remove Intra Only prop for AAC - avcodec/mediacodecdec: set set keyframe flag in output frames - avcodec/libfdk-aacenc: set keyframe in output packets - avcodec/libfdk-aacdec: set keyframe flag and profile in output frames - avcodec/audiotoolboxnec: set set keyframe flag in output packets - avcodec/audiotoolboxdec: set set keyframe flag in output frames - avcodec/aacenc: set keyframe flag in output packets - avcodec/aac/aacdec: set keyframe flag in output frames - avcodec/aac_parser: set key_frame and profile - avformat/mov: don't unconditionally set all audio packets in fragments as key frames - avformat/matroskadec: set all frames in a keyframe simple box as keyframes - avformat/test/movenc: set audio packets as key frames - avformat/movenc: write stss boxes for xHE-AAC - avformat/spdifdec: parse headers for audio codecs - avformat/movenc: don't disable edit lists when writing CMAF output - avcodec/libfdk-aacenc: export CPB properties - avformat/movenc: don't write a calculated avgBitrate when the provided one is unset - libavutil/riscv: Make use of elf_aux_info() on FreeBSD / OpenBSD riscv - libavutil/ppc: defines involving bit shifts should be unsigned - libavutil/ppc: Include the hardware feature flags like the other archs - lavu/riscv: fix compilation without Vector support - avfilter/f_loop: fix aloop activate logic - avfilter/f_loop: fix length of aloop leftover buffer - avfilter/vf_zscale: align the frame buffers - lavfi/vf_zscale: fix call to av_pix_fmt_count_planes - lavfi/vf_zscale: fix tmp buffer ptr alignment for zimg_filter_graph_process - avfilter/framepool: align the frame buffers - avcodec/h2645_sei: use the RefStruct API for film_grain_characteristics - avcodec/aom_film_grain: allocate film grain metadata dynamically - avformat/mov: use an array of pointers for heif_item - avformat/mov: split off heif item initialization to its own function - avformat/mov: factorize getting the current item - lavc/h264idct: fix RISC-V group multiplier - lavc/h264dsp: move RISC-V fn pointers to .data.rel.ro - avcodec/jpegxl_parser: fix reading lz77-pair as initial entropy symbol - avcodec/jpegxl_parser: check entropy_decoder_read_symbol return value - avcodec/cbs_h266: Fix regression in DVB clip introduced by 93281630a71c06642adfebebb0d4b105a4e02e91 - avcodec/x86/vvc: add prototypes for OF functions - Document stream specifier syntax change from 46cbe4ab5c - fftools/ffplay: fix crash when vk renderer is null - avutil/wchar_filename: re-introduce explicit cast of void* to char* - fate/ffmpeg: add samples dependency to fate-ffmpeg-spec-disposition - fftools/ffmpeg_filter: treat apad filter as a source - lavc/avcodec: fix global/private option precendence - avfilter/framesync: fix forward EOF pts - avcodec/vaapi_encode: fix compilation without CONFIG_VAAPI_1 - libavcodec: x86: Remove an explicit include of config.asm - checkasm: lls: Use relative tolerances rather than absolute ones - arm: Consistently use proper interworking function returns - avcodec/libx265: unbreak build for X265_BUILD >= 213 - fftools: log unconnected filter output label - fftools: do not access out of bounds filtergraph - avcodec/mediacodecenc: Fix access of uninitialized value - avformat/img2enc: Fix integer truncation when frame_pts is enabled - avformat/internal: Add ff_get_frame_filename - avformat/mov: don't return the latest stream when an item stream is expected +version 8.0: +- Whisper filter +- Drop support for OpenSSL < 1.1.0 +- Enable TLS peer certificate verification by default (on next major version bump) +- Drop support for OpenSSL < 1.1.1 +- yasm support dropped, users need to use nasm +- VVC VAAPI decoder +- RealVideo 6.0 decoder +- OpenMAX encoders deprecated +- libx265 alpha layer encoding +- ADPCM IMA Xbox decoder +- Enhanced FLV v2: Multitrack audio/video, modern codec support +- Animated JPEG XL encoding (via libjxl) +- VVC in Matroska +- CENC AV1 support in MP4 muxer +- pngenc: set default prediction method to PAETH +- APV decoder and APV raw bitstream muxing and demuxing +- APV parser +- APV encoding support through a libopenapv wrapper +- VVC decoder supports all content of SCC (Screen Content Coding): + IBC (Inter Block Copy), Palette Mode and ACT (Adaptive Color Transform +- G.728 decoder +- pad_cuda filter +- Sanyo LD-ADPCM decoder +- APV in MP4/ISOBMFF muxing and demuxing +- OpenHarmony hardware decoder/encoder +- Colordetect filter +- Add vf_scale_d3d11 filter +- No longer disabling GCC autovectorization, on X86, ARM and AArch64 +- VP9 Vulkan hwaccel +- AV1 Vulkan encoder +- ProRes RAW decoder +- ProRes RAW Vulkan hwaccel +- ffprobe -codec option +- HDR10+ metadata passthrough when decoding/encoding with libaom-av1 version 7.1: @@ -687,6 +188,11 @@ version 7.1: question mark is a part of or not) - multiple stream types in a single specifier (e.g. :s:s:0) now cause an error, as such a specifier makes no sense +- Mastering Display and Content Light Level metadata support in hevc_nvenc + and av1_nvenc encoders +- libswresample now accepts custom order channel layouts as input, with some + constrains +- FFV1 parser version 7.0: @@ -775,6 +281,7 @@ version 6.1: variable-fields elements within the same parent element - ffprobe -output_format option added as an alias of -of +# codespell:off version 6.0: - Radiance HDR image support diff --git a/FUNDING.json b/FUNDING.json new file mode 100644 index 000000000..3ffd54cec --- /dev/null +++ b/FUNDING.json @@ -0,0 +1,7 @@ +{ + "drips": { + "ethereum": { + "ownedBy": "0x2f3900e7064eE63D30d749971265858612AA7139" + } + } +} diff --git a/INSTALL.md b/INSTALL.md index bdf581401..5b98b45d8 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,5 +1,8 @@ ## Installing FFmpeg +0. If you like to include source plugins, merge them before configure +for example run tools/merge-all-source-plugins + 1. Type `./configure` to create the configuration. A list of configure options is printed by running `configure --help`. @@ -21,5 +24,5 @@ NOTICE for Package Maintainers - It is recommended to build FFmpeg twice, first with minimal external dependencies so that 3rd party packages, which depend on FFmpegs libavutil/libavfilter/libavcodec/libavformat - can then be built. And last build FFmpeg with full dependancies (which may in turn depend on + can then be built. And last build FFmpeg with full dependencies (which may in turn depend on some of these 3rd party packages). This avoids circular dependencies during build. diff --git a/LICENSE.md b/LICENSE.md index 613070e1b..371b0913c 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -12,7 +12,6 @@ configure to activate them. In this case, FFmpeg's license changes to GPL v2+. Specifically, the GPL parts of FFmpeg are: -- libpostproc - optional x86 optimization in the files - `libavcodec/x86/flac_dsp_gpl.asm` - `libavcodec/x86/idct_mmx.c` @@ -45,7 +44,6 @@ Specifically, the GPL parts of FFmpeg are: - `vf_owdenoise.c` - `vf_perspective.c` - `vf_phase.c` - - `vf_pp.c` - `vf_pp7.c` - `vf_pullup.c` - `vf_repeatfields.c` diff --git a/MAINTAINERS b/MAINTAINERS index f8339d919..e47f6c98e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -45,13 +45,15 @@ Commandline utility code: QuickTime faststart: tools/qt-faststart.c Baptiste Coudurier +Execution Graph Printing + fftools/graph, fftools/resources [2] softworkz Miscellaneous Areas =================== documentation Stefano Sabatini, Mike Melanson, Timothy Gu, Gyan Doshi -project server day to day operations (L: root@ffmpeg.org) Árpád Gereöffy, Michael Niedermayer, Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov, Timo Rothenpieler -project server emergencies (L: root@ffmpeg.org) Árpád Gereöffy, Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov, Timo Rothenpieler +project server day to day operations (L: root@ffmpeg.org) Michael Niedermayer, Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov, Timo Rothenpieler +project server emergencies (L: root@ffmpeg.org) Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov, Timo Rothenpieler presets [0] metadata subsystem Aurelien Jacobs release management Michael Niedermayer @@ -83,12 +85,14 @@ Other: aes_ctr.c, aes_ctr.h Eran Kornblau bprint Nicolas George bswap.h + csp.c, csp.h Leo Izen, Ronald S. Bultje des Reimar Doeffinger dynarray.h Nicolas George eval.c, eval.h [2] Michael Niedermayer float_dsp Loren Merritt hash Reimar Doeffinger hwcontext_cuda* Timo Rothenpieler + hwcontext_d3d12va* Wu Jianhua hwcontext_vulkan* [2] Lynne intfloat* Michael Niedermayer integer.c, integer.h Michael Niedermayer @@ -134,8 +138,6 @@ Generic Parts: ratecontrol.c [2] Michael Niedermayer simple IDCT: simple_idct.c, simple_idct.h [2] Michael Niedermayer - postprocessing: - libpostproc/* [2] Michael Niedermayer table generation: tableprint.c, tableprint.h Reimar Doeffinger fixed point FFT: @@ -150,7 +152,7 @@ Codecs: adpcm.c Zane van Iperen alacenc.c Jaikrishnan Menon alsdec.c Thilo Borgmann, Umair Khan - amfenc* Dmitrii Ovchinnikov + amfdec*,amfenc* [2] Dmitrii Ovchinnikov, Araz Iusubov aptx.c Aurelien Jacobs ass* Aurelien Jacobs asv* Michael Niedermayer @@ -177,6 +179,7 @@ Codecs: dss_sp.c Oleksij Rempel dv.c Roman Shaposhnik dvbsubdec.c Anshul Maheshwari + dxv.*, dxvenc.* Emma Worley eacmv*, eaidct*, eat* Peter Ross exif.c, exif.h Thilo Borgmann ffv1* [2] Michael Niedermayer @@ -207,9 +210,8 @@ Codecs: libgsm.c Michel Bardiaux libkvazaar.c Arttu Ylä-Outinen libopenh264enc.c Martin Storsjo, Linjie Fu - libopenjpeg.c Jaikrishnan Menon libopenjpegenc.c Michael Bradshaw - libtheoraenc.c David Conrad + libtheoraenc.c [0] libvorbis.c David Conrad libvpx* James Zern libxavs.c Stefan Gehrer @@ -245,6 +247,7 @@ Codecs: rpza.c Roberto Togni rtjpeg.c, rtjpeg.h Reimar Doeffinger rv10.c Michael Niedermayer + sanm.c Manuel Lauss smc.c Mike Melanson snow* Michael Niedermayer, Loren Merritt sonic.c Alex Beregszaszi @@ -267,7 +270,7 @@ Codecs: vp8 David Conrad, Ronald Bultje vp9 Ronald Bultje vqavideo.c Mike Melanson - vvc [2] Nuo Mi + vvc [2] Nuo Mi, Wu Jianhua, Frank Plowman wmaprodec.c Sascha Sommer wmavoice.c Ronald S. Bultje wmv2.c Michael Niedermayer @@ -275,8 +278,10 @@ Codecs: xface Stefano Sabatini Hardware acceleration: + amf* [2] Dmitrii Ovchinnikov, Araz Iusubov dxva2* Hendrik Leppkes, Laurent Aimar, Steve Lhomme d3d11va* Steve Lhomme + d3d12va* Wu Jianhua d3d12va_encode* Tong Wu mediacodec* Matthieu Bouron, Aman Gupta, Zhao Zhili vaapi* Haihao Xiang @@ -392,7 +397,7 @@ Muxers/Demuxers: dss.c Oleksij Rempel dtsdec.c foo86 dv.c Roman Shaposhnik - dvdvideodec.c Marth64 + dvdvideodec.c [2] Marth64 electronicarts.c Peter Ross evc* Samsung (Dawid Kozinski) ffm* Baptiste Coudurier @@ -446,7 +451,8 @@ Muxers/Demuxers: pva.c Ivo van Poorten r3d.c Baptiste Coudurier raw.c Michael Niedermayer - rcwtenc.c Marth64 + rcwtdec.c [2] Marth64 + rcwtenc.c [2] Marth64 rdt.c Ronald S. Bultje rl2.c Sascha Sommer rmdec.c, rmenc.c Ronald S. Bultje @@ -465,6 +471,7 @@ Muxers/Demuxers: sdp.c Martin Storsjo segafilm.c Mike Melanson segment.c Stefano Sabatini + smush.c Manuel Lauss spdif* Anssi Hannula srtdec.c Aurelien Jacobs swf.c Baptiste Coudurier @@ -476,6 +483,7 @@ Muxers/Demuxers: webm dash (matroskaenc.c) Vignesh Venkatasubramanian webvtt* Matthew J Heaney westwood.c Mike Melanson + whip.c [2] Jack Lau wtv.c Peter Ross Protocols: @@ -512,9 +520,10 @@ Operating systems / CPU architectures Alpha [0] MIPS Manojkumar Bhosale, Shiyou Yin LoongArch [2] Shiyou Yin +Darwin (macOS, iOS) [2] Marvin Scholz Mac OS X / PowerPC [0] Amiga / PowerPC Colin Ward -Linux / PowerPC [1] Lauri Kasanen +Linux / PowerPC [2] Sean McGovern (CC ), Lauri Kasanen RISC-V [2] Rémi Denis-Courmont Windows MinGW Alex Beregszaszi, Ramiro Polla Windows Cygwin Victor Paesa @@ -542,6 +551,7 @@ James Darnley Jan Ekström Joakim Plate Jun Zhao +Kacper Michajłow Kieran Kunhya Kirill Gavrilov Limin Wang @@ -583,6 +593,7 @@ Benoit Fouet B22A 4F4F 43EF 636B BB66 FCDC 0023 AE1E 2985 49C8 Clément Bœsch 52D0 3A82 D445 F194 DB8B 2B16 87EE 2CB8 F4B8 FCF9 Daniel Verkamp 78A6 07ED 782C 653E C628 B8B9 F0EB 8DD8 2F0E 21C7 FFmpeg release signing key FCF9 86EA 15E6 E293 A564 4F10 B432 2F04 D676 58D8 +Frank Plowman 34E2 48D6 B7DF 4769 70C7 3304 03A8 4C6A 098F 2C6B Ganesh Ajjanagadde C96A 848E 97C3 CEA2 AB72 5CE4 45F9 6A2D 3C36 FB1B Gwenole Beauchesne 2E63 B3A6 3E44 37E2 017D 2704 53C7 6266 B153 99C4 Haihao Xiang (haihao) 1F0C 31E8 B4FE F7A4 4DC1 DC99 E0F5 76D4 76FC 437F @@ -608,6 +619,7 @@ Reinhard Tartler 9300 5DC2 7E87 6C37 ED7B CA9A 9808 3544 9453 48A4 Reynaldo H. Verdejo Pinochet 6E27 CD34 170C C78E 4D4F 5F40 C18E 077F 3114 452A Robert Swain EE7A 56EA 4A81 A7B5 2001 A521 67FA 362D A2FC 3E71 Sascha Sommer 38A0 F88B 868E 9D3A 97D4 D6A0 E823 706F 1E07 0D3C +Sean McGovern (Sean_McG) 6D03 BC60 3A33 E615 6E2E 06AD 8C06 8175 6F59 8684 Stefano Sabatini 0D0B AD6B 5330 BBAD D3D6 6A0C 719C 2839 FC43 2D5F Steinar H. Gunderson C2E9 004F F028 C18E 4EAD DB83 7F61 7561 7797 8F76 Stephan Hilb 4F38 0B3A 5F39 B99B F505 E562 8D5C 5554 4E17 8863 diff --git a/Makefile b/Makefile index b350d7748..f296e87ed 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,8 @@ vpath %.asm $(SRC_PATH) vpath %.rc $(SRC_PATH) vpath %.v $(SRC_PATH) vpath %.texi $(SRC_PATH) +vpath %.glsl $(SRC_PATH) +vpath %.spv $(SRC_PATH) vpath %.cu $(SRC_PATH) vpath %.ptx $(SRC_PATH) vpath %.metal $(SRC_PATH) @@ -19,14 +21,20 @@ vpath %/fate_config.sh.template $(SRC_PATH) TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64 audiomatch HOSTPROGS := $(TESTTOOLS:%=tests/%) doc/print_options -ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale swresample +ALLFFLIBS = \ + avcodec \ + avdevice \ + avfilter \ + avformat \ + avutil \ + swscale \ + swresample \ # $(FFLIBS-yes) needs to be in linking order FFLIBS-$(CONFIG_AVDEVICE) += avdevice FFLIBS-$(CONFIG_AVFILTER) += avfilter FFLIBS-$(CONFIG_AVFORMAT) += avformat FFLIBS-$(CONFIG_AVCODEC) += avcodec -FFLIBS-$(CONFIG_POSTPROC) += postproc FFLIBS-$(CONFIG_SWRESAMPLE) += swresample FFLIBS-$(CONFIG_SWSCALE) += swscale @@ -47,31 +55,31 @@ FF_DEP_LIBS := $(DEP_LIBS) FF_STATIC_DEP_LIBS := $(STATIC_DEP_LIBS) $(TOOLS): %$(EXESUF): %.o - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(filter-out $(FF_DEP_LIBS), $^) $(EXTRALIBS-$(*F)) $(EXTRALIBS) $(ELIBS) + $(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(filter-out $(FF_DEP_LIBS), $^) $(EXTRALIBS-$(*F)) $(EXTRALIBS) $(ELIBS)) target_dec_%_fuzzer$(EXESUF): target_dec_%_fuzzer.o $(FF_DEP_LIBS) - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + $(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)) target_enc_%_fuzzer$(EXESUF): target_enc_%_fuzzer.o $(FF_DEP_LIBS) - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + $(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)) tools/target_bsf_%_fuzzer$(EXESUF): tools/target_bsf_%_fuzzer.o $(FF_DEP_LIBS) - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + $(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)) target_dem_%_fuzzer$(EXESUF): target_dem_%_fuzzer.o $(FF_DEP_LIBS) - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + $(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)) tools/target_dem_fuzzer$(EXESUF): tools/target_dem_fuzzer.o $(FF_DEP_LIBS) - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + $(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)) tools/target_io_dem_fuzzer$(EXESUF): tools/target_io_dem_fuzzer.o $(FF_DEP_LIBS) - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + $(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)) tools/target_sws_fuzzer$(EXESUF): tools/target_sws_fuzzer.o $(FF_DEP_LIBS) - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + $(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)) tools/target_swr_fuzzer$(EXESUF): tools/target_swr_fuzzer.o $(FF_DEP_LIBS) - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + $(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)) tools/enum_options$(EXESUF): ELIBS = $(FF_EXTRALIBS) tools/enum_options$(EXESUF): $(FF_DEP_LIBS) @@ -101,10 +109,11 @@ ffbuild/.config: $(CONFIGURABLE_COMPONENTS) SUBDIR_VARS := CLEANFILES FFLIBS HOSTPROGS TESTPROGS TOOLS \ HEADERS ARCH_HEADERS BUILT_HEADERS SKIPHEADERS \ ARMV5TE-OBJS ARMV6-OBJS ARMV8-OBJS VFP-OBJS NEON-OBJS \ - ALTIVEC-OBJS VSX-OBJS MMX-OBJS X86ASM-OBJS \ + ALTIVEC-OBJS VSX-OBJS X86ASM-OBJS \ MIPSFPU-OBJS MIPSDSPR2-OBJS MIPSDSP-OBJS MSA-OBJS \ MMI-OBJS LSX-OBJS LASX-OBJS RV-OBJS RVV-OBJS RVVB-OBJS \ - OBJS SLIBOBJS SHLIBOBJS STLIBOBJS HOSTOBJS TESTOBJS + OBJS SHLIBOBJS STLIBOBJS HOSTOBJS TESTOBJS SIMD128-OBJS \ + SVE-OBJS SVE2-OBJS SME-OBJS SME2-OBJS define RESET $(1) := @@ -138,7 +147,7 @@ else endif %$(PROGSSUF)_g$(EXESUF): $(FF_DEP_LIBS) - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(OBJS-$*) $(FF_EXTRALIBS) + $(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(OBJS-$*) $(FF_EXTRALIBS)) VERSION_SH = $(SRC_PATH)/ffbuild/version.sh ifeq ($(VERSION_TRACKING),yes) @@ -178,7 +187,7 @@ clean:: $(RM) -rf coverage.info coverage.info.in lcov distclean:: clean - $(RM) .version config.asm config.h config_components.h mapfile \ + $(RM) .version config.asm config.h config_components.* mapfile \ ffbuild/.config ffbuild/config.* libavutil/avconfig.h \ version.h libavutil/ffversion.h libavcodec/codec_names.h \ libavcodec/bsf_list.c libavformat/protocol_list.c \ diff --git a/RELEASE b/RELEASE index b7f8ee41e..0e7915245 100644 --- a/RELEASE +++ b/RELEASE @@ -1 +1 @@ -7.1.4 +8.1.1 diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 851701a73..80646e8bd 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,10 +1,10 @@ - ┌──────────────────────────────────────┐ - │ RELEASE NOTES for FFmpeg 7.1 "Péter" │ - └──────────────────────────────────────┘ + ┌──────────────────────────────────────┐ + │ RELEASE NOTES for FFmpeg 8.1 "Hoare" │ + └──────────────────────────────────────┘ - The FFmpeg Project proudly presents FFmpeg 7.1 "Péter", about 6 - months after the release of FFmpeg 7.0. + The FFmpeg Project proudly presents FFmpeg 8.1 "Hoare", about 7 + months after the release of FFmpeg 8.0. A complete Changelog is available at the root of the project, and the complete Git history on https://git.ffmpeg.org/gitweb/ffmpeg.git diff --git a/VERSION b/VERSION index b7f8ee41e..0e7915245 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.1.4 +8.1.1 diff --git a/compat/android/binder.c b/compat/android/binder.c new file mode 100644 index 000000000..a214d977c --- /dev/null +++ b/compat/android/binder.c @@ -0,0 +1,114 @@ +/* + * Android Binder handler + * + * Copyright (c) 2025 Dmitrii Okunev + * + * 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 + */ + + +#if defined(__ANDROID__) + +#include +#include +#include + +#include "libavutil/log.h" +#include "binder.h" + +#define THREAD_POOL_SIZE 1 + +static void *dlopen_libbinder_ndk(void) +{ + /* + * libbinder_ndk.so often does not contain the functions we need, so making + * this dependency optional, thus using dlopen/dlsym instead of linking. + * + * See also: https://source.android.com/docs/core/architecture/aidl/aidl-backends + */ + + void *h = dlopen("libbinder_ndk.so", RTLD_NOW | RTLD_LOCAL); + if (h != NULL) + return h; + + av_log(NULL, AV_LOG_WARNING, + "android/binder: unable to load libbinder_ndk.so: '%s'; skipping binder threadpool init (MediaCodec likely won't work)\n", + dlerror()); + return NULL; +} + +static void android_binder_threadpool_init(void) +{ + typedef int (*set_thread_pool_max_fn)(uint32_t); + typedef void (*start_thread_pool_fn)(void); + + set_thread_pool_max_fn set_thread_pool_max = NULL; + start_thread_pool_fn start_thread_pool = NULL; + + void *h = dlopen_libbinder_ndk(); + if (h == NULL) + return; + + unsigned thead_pool_size = THREAD_POOL_SIZE; + + set_thread_pool_max = + (set_thread_pool_max_fn) dlsym(h, + "ABinderProcess_setThreadPoolMaxThreadCount"); + start_thread_pool = + (start_thread_pool_fn) dlsym(h, "ABinderProcess_startThreadPool"); + + if (start_thread_pool == NULL) { + av_log(NULL, AV_LOG_WARNING, + "android/binder: ABinderProcess_startThreadPool not found; skipping threadpool init (MediaCodec likely won't work)\n"); + return; + } + + if (set_thread_pool_max != NULL) { + int ok = set_thread_pool_max(thead_pool_size); + av_log(NULL, AV_LOG_DEBUG, + "android/binder: ABinderProcess_setThreadPoolMaxThreadCount(%u) => %s\n", + thead_pool_size, ok ? "ok" : "fail"); + } else { + av_log(NULL, AV_LOG_DEBUG, + "android/binder: ABinderProcess_setThreadPoolMaxThreadCount is unavailable; using the library default\n"); + } + + start_thread_pool(); + av_log(NULL, AV_LOG_DEBUG, + "android/binder: ABinderProcess_startThreadPool() called\n"); +} + +void android_binder_threadpool_init_if_required(void) +{ +#if __ANDROID_API__ >= 24 + if (android_get_device_api_level() < 35) { + // the issue with the thread pool was introduced in Android 15 (API 35) + av_log(NULL, AV_LOG_DEBUG, + "android/binder: API<35, thus no need to initialize a thread pool\n"); + return; + } + android_binder_threadpool_init(); +#else + // android_get_device_api_level was introduced in API 24, so we cannot use it + // to detect the API level in API<24. For simplicity we just assume + // libbinder_ndk.so on the system running this code would have API level < 35; + av_log(NULL, AV_LOG_DEBUG, + "android/binder: is built with API<24, assuming this is not Android 15+\n"); +#endif +} + +#endif /* __ANDROID__ */ diff --git a/libavcodec/wmv2enc.h b/compat/android/binder.h similarity index 72% rename from libavcodec/wmv2enc.h rename to compat/android/binder.h index 263265acf..2b1ca53fe 100644 --- a/libavcodec/wmv2enc.h +++ b/compat/android/binder.h @@ -1,5 +1,7 @@ /* - * Copyright (c) 2002 The FFmpeg Project + * Android Binder handler + * + * Copyright (c) 2025 Dmitrii Okunev * * This file is part of FFmpeg. * @@ -18,14 +20,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_WMV2ENC_H -#define AVCODEC_WMV2ENC_H +#ifndef COMPAT_ANDROID_BINDER_H +#define COMPAT_ANDROID_BINDER_H -#include "mpegvideo.h" +/** + * Initialize Android Binder thread pool. + */ +void android_binder_threadpool_init_if_required(void); -int ff_wmv2_encode_picture_header(MpegEncContext * s); -void ff_wmv2_encode_mb(MpegEncContext * s, int16_t block[6][64], - int motion_x, int motion_y); - - -#endif +#endif // COMPAT_ANDROID_BINDER_H diff --git a/compat/cuda/cuda_runtime.h b/compat/cuda/cuda_runtime.h index 699c4b6c7..7614233ea 100644 --- a/compat/cuda/cuda_runtime.h +++ b/compat/cuda/cuda_runtime.h @@ -189,4 +189,7 @@ static inline __device__ float __cosf(float a) { return __nvvm_cos_approx_f(a); static inline __device__ float __expf(float a) { return __nvvm_ex2_approx_f(a * (float)__builtin_log2(__builtin_exp(1))); } static inline __device__ float __powf(float a, float b) { return __nvvm_ex2_approx_f(__nvvm_lg2_approx_f(a) * b); } +// Misc helper functions +extern "C" __device__ int printf(const char*, ...); + #endif /* COMPAT_CUDA_CUDA_RUNTIME_H */ diff --git a/compat/getopt.c b/compat/getopt.c index 41a641f7c..72110a95d 100644 --- a/compat/getopt.c +++ b/compat/getopt.c @@ -38,7 +38,7 @@ static int optind = 1; static int optopt; static char *optarg; -static int getopt(int argc, char *argv[], char *opts) +static int getopt(int argc, char *argv[], const char *opts) { static int sp = 1; int c; diff --git a/compat/solaris/make_sunver.pl b/compat/solaris/make_sunver.pl index 0e9ed1d35..0c9268ea8 100755 --- a/compat/solaris/make_sunver.pl +++ b/compat/solaris/make_sunver.pl @@ -218,7 +218,7 @@ while () { # Lines of the form '} SOME_VERSION_NAME_1.0;' if (/^[ \t]*\}[ \tA-Z0-9_.a-z]+;[ \t]*$/) { $glob = 'glob'; - # We tried to match symbols agains this version, but none matched. + # We tried to match symbols against this version, but none matched. # Emit dummy hidden symbol to avoid marking this version WEAK. if ($matches_attempted && $matched_symbols == 0) { print " hidden:\n"; diff --git a/compat/w32pthreads.h b/compat/w32pthreads.h index 2ff973522..f689d04d5 100644 --- a/compat/w32pthreads.h +++ b/compat/w32pthreads.h @@ -44,13 +44,14 @@ #include "libavutil/internal.h" #include "libavutil/mem.h" #include "libavutil/time.h" +#include "libavutil/wchar_filename.h" -typedef struct pthread_t { +typedef struct w32pthread_t { void *handle; void *(*func)(void* arg); void *arg; void *ret; -} pthread_t; +} *pthread_t; /* use light weight mutex/condition variable API for Windows Vista and later */ typedef SRWLOCK pthread_mutex_t; @@ -71,32 +72,46 @@ typedef CONDITION_VARIABLE pthread_cond_t; #define THREADFUNC_RETTYPE unsigned #endif -static av_unused THREADFUNC_RETTYPE +av_unused static THREADFUNC_RETTYPE __stdcall attribute_align_arg win32thread_worker(void *arg) { - pthread_t *h = (pthread_t*)arg; + pthread_t h = (pthread_t)arg; h->ret = h->func(h->arg); return 0; } -static av_unused int pthread_create(pthread_t *thread, const void *unused_attr, +av_unused static int pthread_create(pthread_t *thread, const void *unused_attr, void *(*start_routine)(void*), void *arg) { - thread->func = start_routine; - thread->arg = arg; + pthread_t ret; + + ret = (pthread_t)av_mallocz(sizeof(*ret)); + if (!ret) + return EAGAIN; + + ret->func = start_routine; + ret->arg = arg; #if HAVE_WINRT - thread->handle = (void*)CreateThread(NULL, 0, win32thread_worker, thread, - 0, NULL); + ret->handle = (void*)CreateThread(NULL, 0, win32thread_worker, ret, + 0, NULL); #else - thread->handle = (void*)_beginthreadex(NULL, 0, win32thread_worker, thread, - 0, NULL); + ret->handle = (void*)_beginthreadex(NULL, 0, win32thread_worker, ret, + 0, NULL); #endif - return !thread->handle; + + if (!ret->handle) { + av_free(ret); + return EAGAIN; + } + + *thread = ret; + + return 0; } -static av_unused int pthread_join(pthread_t thread, void **value_ptr) +av_unused static int pthread_join(pthread_t thread, void **value_ptr) { - DWORD ret = WaitForSingleObject(thread.handle, INFINITE); + DWORD ret = WaitForSingleObject(thread->handle, INFINITE); if (ret != WAIT_OBJECT_0) { if (ret == WAIT_ABANDONED) return EINVAL; @@ -104,8 +119,9 @@ static av_unused int pthread_join(pthread_t thread, void **value_ptr) return EDEADLK; } if (value_ptr) - *value_ptr = thread.ret; - CloseHandle(thread.handle); + *value_ptr = thread->ret; + CloseHandle(thread->handle); + av_free(thread); return 0; } @@ -133,7 +149,7 @@ static inline int pthread_mutex_unlock(pthread_mutex_t *m) typedef INIT_ONCE pthread_once_t; #define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT -static av_unused int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) +av_unused static int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) { BOOL pending = FALSE; InitOnceBeginInitialize(once_control, 0, &pending, NULL); @@ -194,4 +210,38 @@ static inline int pthread_setcancelstate(int state, int *oldstate) return 0; } +static inline int win32_thread_setname(const char *name) +{ +#if !HAVE_UWP + typedef HRESULT (WINAPI *SetThreadDescriptionFn)(HANDLE, PCWSTR); + + // Although SetThreadDescription lives in kernel32.dll, on Windows Server 2016, + // Windows 10 LTSB 2016 and Windows 10 version 1607, it was only available in + // kernelbase.dll. So, load it from there for maximum coverage. + HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll"); + if (!kernelbase) + return AVERROR(ENOSYS); + + SetThreadDescriptionFn pSetThreadDescription = + (SetThreadDescriptionFn)GetProcAddress(kernelbase, "SetThreadDescription"); + if (!pSetThreadDescription) + return AVERROR(ENOSYS); + + wchar_t *wname; + if (utf8towchar(name, &wname) < 0) + return AVERROR(ENOMEM); + + HRESULT hr = pSetThreadDescription(GetCurrentThread(), wname); + av_free(wname); + return SUCCEEDED(hr) ? 0 : AVERROR(EINVAL); +#else + // UWP is not supported because we cannot use LoadLibrary/GetProcAddress to + // detect the availability of the SetThreadDescription API. There is a small + // gap in Windows builds 1507-1607 where it was not available. UWP allows + // querying the availability of APIs with QueryOptionalDelayLoadedAPI, but it + // requires /DELAYLOAD:kernel32.dll during linking, and we cannot enforce that. + return AVERROR(ENOSYS); +#endif +} + #endif /* COMPAT_W32PTHREADS_H */ diff --git a/compat/windows/makedef b/compat/windows/makedef index add8222d1..af42f08fd 100755 --- a/compat/windows/makedef +++ b/compat/windows/makedef @@ -48,7 +48,13 @@ trap 'rm -f -- $libname' EXIT if [ -n "$AR" ]; then $AR rcs ${libname} $@ >/dev/null else - lib.exe -out:${libname} $@ >/dev/null + machine_flag="" + case "$LDFLAGS" in + *"machine:arm64ec"*) + machine_flag="-machine:arm64ec" + ;; + esac + lib.exe ${machine_flag} -out:${libname} $@ >/dev/null fi if [ $? != 0 ]; then echo "Could not create temporary library." >&2 @@ -106,12 +112,21 @@ if [ -n "$NM" ]; then grep -v : | grep -v ^$ | cut -d' ' -f3 | - sed -e "s/^${prefix}//") + sed -e "s/^${prefix}//" -e "s/^#//" | + grep -v '\$entry_thunk' | + grep -v '\$exit_thunk') else - dump=$(dumpbin.exe -linkermember:1 ${libname} | - sed -e '/public symbols/,$!d' -e '/^ \{1,\}Summary/,$d' -e "s/ \{1,\}${prefix}/ /" -e 's/ \{1,\}/ /g' | + member=1 + case "$LDFLAGS" in + *"machine:arm64ec"*) + member=32 + ;; + esac + dump=$(dumpbin.exe -linkermember:${member} ${libname} | + sed -e '/public symbols/,$!d' -e '/^ \{1,\}Summary/,$d' -e 's/^[[:space:]]*[0-9A-Fa-f]\{1,\}[[:space:]]\{1,\}//' -e "s/^${prefix}//" -e 's/^#//' | tail -n +2 | - cut -d' ' -f3) + grep -v '\$entry_thunk' | + grep -v '\$exit_thunk') fi rm ${libname} diff --git a/configure b/configure index 1652b0d4a..175969427 100755 --- a/configure +++ b/configure @@ -108,6 +108,7 @@ Configuration options: --disable-runtime-cpudetect disable detecting CPU capabilities at runtime (smaller binary) --enable-gray enable full grayscale support (slower color) --disable-swscale-alpha disable alpha channel support in swscale + --disable-unstable disable building optional unstable / experimental code --disable-all disable building components, libraries and programs --disable-autodetect disable automatically detected external libraries [no] @@ -130,7 +131,6 @@ Component options: --disable-avformat disable libavformat build --disable-swresample disable libswresample build --disable-swscale disable libswscale build - --disable-postproc disable libpostproc build --disable-avfilter disable libavfilter build --disable-pthreads disable pthreads [autodetect] --disable-w32threads disable Win32 threads [autodetect] @@ -200,6 +200,7 @@ External library support: --disable-avfoundation disable Apple AVFoundation framework [autodetect] --enable-avisynth enable reading of AviSynth script files [no] --disable-bzlib disable bzlib [autodetect] + --enable-cairo enable cairo [no] --disable-coreimage disable Apple CoreImage framework [autodetect] --enable-chromaprint enable audio fingerprinting with chromaprint [no] --enable-frei0r enable frei0r video filtering [no] @@ -236,7 +237,7 @@ External library support: --enable-libfreetype enable libfreetype, needed for drawtext filter [no] --enable-libfribidi enable libfribidi, improves drawtext filter [no] --enable-libharfbuzz enable libharfbuzz, needed for drawtext filter [no] - --enable-libglslang enable GLSL->SPIRV compilation via libglslang [no] + --enable-libglslang enable runtime GLSL->SPIRV compilation via libglslang [no] --enable-libgme enable Game Music Emu via libgme [no] --enable-libgsm enable GSM de/encoding via libgsm [no] --enable-libiec61883 enable iec61883 via libiec61883 [no] @@ -250,12 +251,15 @@ External library support: --enable-liblensfun enable lensfun lens correction [no] --enable-libmodplug enable ModPlug via libmodplug [no] --enable-libmp3lame enable MP3 encoding via libmp3lame [no] + --enable-libmpeghdec enable MPEG-H 3DA decoding via libmpeghdec [no] + --enable-liboapv enable APV encoding via liboapv [no] --enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no] --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no] --enable-libopencv enable video filtering via libopencv [no] --enable-libopenh264 enable H.264 encoding via OpenH264 [no] --enable-libopenjpeg enable JPEG 2000 encoding via OpenJPEG [no] --enable-libopenmpt enable decoding tracked files via libopenmpt [no] + --enable-libopencolorio enable color management via OpenColorIO [no] --enable-libopenvino enable OpenVINO as a DNN module backend for DNN based filters like dnn_processing [no] --enable-libopus enable Opus de/encoding via libopus [no] @@ -269,7 +273,7 @@ External library support: --enable-librsvg enable SVG rasterization via librsvg [no] --enable-librubberband enable rubberband needed for rubberband filter [no] --enable-librtmp enable RTMP[E] support via librtmp [no] - --enable-libshaderc enable GLSL->SPIRV compilation via libshaderc [no] + --enable-libshaderc enable runtime GLSL->SPIRV compilation via libshaderc [no] --enable-libshine enable fixed-point MP3 encoding via libshine [no] --enable-libsmbclient enable Samba protocol via libsmbclient [no] --enable-libsnappy enable Snappy compression, needed for hap encoding [no] @@ -278,6 +282,7 @@ External library support: --enable-libsrt enable Haivision SRT protocol via libsrt [no] --enable-libssh enable SFTP protocol via libssh [no] --enable-libsvtav1 enable AV1 encoding via SVT [no] + --enable-libsvtjpegxs enable JPEGXS encoding/decoding via SVT [no] --enable-libtensorflow enable TensorFlow as a DNN module backend for DNN based filters like sr [no] --enable-libtesseract enable Tesseract, needed for ocr filter [no] @@ -299,7 +304,9 @@ External library support: --enable-libx264 enable H.264 encoding via x264 [no] --enable-libx265 enable HEVC encoding via x265 [no] --enable-libxeve enable EVC encoding via libxeve [no] + --enable-libxeveb enable EVC encoding via libxeve (Base profile) [no] --enable-libxevd enable EVC decoding via libxevd [no] + --enable-libxevdb enable EVC decoding via libxevd (Base profile) [no] --enable-libxavs enable AVS encoding via xavs [no] --enable-libxavs2 enable AVS2 encoding via xavs2 [no] --enable-libxcb enable X11 grabbing using XCB [autodetect] @@ -322,6 +329,7 @@ External library support: --enable-mediafoundation enable encoding via MediaFoundation [auto] --disable-metal disable Apple Metal framework [autodetect] --enable-libmysofa enable libmysofa, needed for sofalizer filter [no] + --enable-ohcodec enable OpenHarmony Codec support [no] --enable-openal enable OpenAL 1.1 capture support [no] --enable-opencl enable OpenCL processing [no] --enable-opengl enable OpenGL rendering [no] @@ -335,6 +343,7 @@ External library support: --disable-securetransport disable Secure Transport, needed for TLS support on OSX if openssl and gnutls are not used [autodetect] --enable-vapoursynth enable VapourSynth demuxer [no] + --enable-whisper enable whisper filter [no] --disable-xlib disable xlib [autodetect] --disable-zlib disable zlib [autodetect] @@ -363,6 +372,7 @@ External library support: --disable-vdpau disable Nvidia Video Decode and Presentation API for Unix code [autodetect] --disable-videotoolbox disable VideoToolbox code [autodetect] --disable-vulkan disable Vulkan code [autodetect] + --enable-vulkan-static statically link to libvulkan [no] Toolchain options: --arch=ARCH select architecture [$arch] @@ -379,10 +389,10 @@ Toolchain options: --target-samples=DIR path to samples directory on target --tempprefix=PATH force fixed dir/prefix instead of mktemp for checks --toolchain=NAME set tool defaults according to NAME - (gcc-asan, clang-asan, gcc-msan, clang-msan, - gcc-tsan, clang-tsan, gcc-usan, clang-usan, - valgrind-massif, valgrind-memcheck, - msvc, icl, gcov, llvm-cov, hardened) + ([-sanitizer[-...]], e.g. clang-asan-ubsan + tools: gcc, clang, msvc, icl, gcov, llvm-cov, + valgrind-memcheck, valgrind-massif, hardened + sanitizers: asan, fuzz, lsan, msan, tsan, ubsan) --nm=NM use nm tool NM [$nm_default] --ar=AR use archive tool AR [$ar_default] --as=AS use assembler AS [$as_default] @@ -396,6 +406,7 @@ Toolchain options: --stdcxx=STDCXX use C standard STDCXX [$stdcxx_default] --objcc=OCC use ObjC compiler OCC [$cc_default] --dep-cc=DEPCC use dependency generator DEPCC [$cc_default] + --glslc=GLSLC use GLSL compiler GLSLC [$glslc_default] --nvcc=NVCC use Nvidia CUDA compiler NVCC or clang [$nvcc_default] --ld=LD use linker LD [$ld_default] --metalcc=METALCC use metal compiler METALCC [$metalcc_default] @@ -413,19 +424,21 @@ Toolchain options: --host-os=OS compiler host OS [$target_os] --extra-cflags=ECFLAGS add ECFLAGS to CFLAGS [$CFLAGS] --extra-cxxflags=ECFLAGS add ECFLAGS to CXXFLAGS [$CXXFLAGS] - --extra-objcflags=FLAGS add FLAGS to OBJCFLAGS [$CFLAGS] + --extra-objcflags=FLAGS add FLAGS to OBJCFLAGS [$OBJCFLAGS] --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS [$LDFLAGS] --extra-ldexeflags=ELDFLAGS add ELDFLAGS to LDEXEFLAGS [$LDEXEFLAGS] --extra-ldsoflags=ELDFLAGS add ELDFLAGS to LDSOFLAGS [$LDSOFLAGS] --extra-libs=ELIBS add ELIBS [$ELIBS] --extra-version=STRING version string suffix [] --optflags=OPTFLAGS override optimization-related compiler flags + --glslcflags=GLSLCFLAGS extra glslc flags [$glslcflags_default] --nvccflags=NVCCFLAGS override nvcc flags [$nvccflags_default] --build-suffix=SUFFIX library name suffix [] --enable-pic build position-independent code --enable-thumb compile for Thumb instruction set --enable-lto[=arg] use link-time optimization --env="ENV=override" override the environment variables + --disable-response-files Don't pass the list of objects to linker in a file [autodetect] Advanced options (experts only): --malloc-prefix=PREFIX prefix malloc and related names with PREFIX @@ -444,8 +457,6 @@ Optimization options (experts only): --disable-altivec disable AltiVec optimizations --disable-vsx disable VSX optimizations --disable-power8 disable POWER8 optimizations - --disable-amd3dnow disable 3DNow! optimizations - --disable-amd3dnowext disable 3DNow! extended optimizations --disable-mmx disable MMX optimizations --disable-mmxext disable MMXEXT optimizations --disable-sse disable SSE optimizations @@ -462,13 +473,20 @@ Optimization options (experts only): --disable-avx512 disable AVX-512 optimizations --disable-avx512icl disable AVX-512ICL optimizations --disable-aesni disable AESNI optimizations + --disable-clmul disable CLMUL optimizations --disable-armv5te disable armv5te optimizations --disable-armv6 disable armv6 optimizations --disable-armv6t2 disable armv6t2 optimizations --disable-vfp disable VFP optimizations --disable-neon disable NEON optimizations + --disable-arm-crc disable ARM/AArch64 CRC optimizations --disable-dotprod disable DOTPROD optimizations --disable-i8mm disable I8MM optimizations + --disable-sve disable SVE optimizations + --disable-sve2 disable SVE2 optimizations + --disable-sme disable SME optimizations + --disable-sme-i16i64 disable SME-I16I64 optimizations + --disable-sme2 disable SME2 optimizations --disable-inline-asm disable use of inline assembly --disable-x86asm disable use of standalone x86 assembly --disable-mipsdsp disable MIPS DSP ASE R1 optimizations @@ -480,6 +498,7 @@ Optimization options (experts only): --disable-lasx disable Loongson LASX optimizations --disable-rvv disable RISC-V Vector optimizations --disable-fast-unaligned consider unaligned accesses slow + --disable-simd128 disable WebAssembly simd128 optimizations Developer options (useful when working on FFmpeg itself): --disable-debug disable debugging symbols @@ -517,7 +536,8 @@ Developer options (useful when working on FFmpeg itself): --enable-linux-perf enable Linux Performance Monitor API --enable-macos-kperf enable macOS kperf (private) API --disable-large-tests disable tests that use a large amount of memory - --disable-ptx-compression don't compress CUDA PTX code even when possible + --disable-shader-compression don't compress shader code even when possible + --disable-resource-compression don't compress resources even when possible --disable-version-tracking don't include the git/release version in the build NOTE: Object files are built at the place where configure is launched. @@ -816,7 +836,7 @@ is_in(){ } # The cfg loop is very hot (several thousands iterations), and in bash also -# potentialy quite slow. Try to abort the iterations early, preferably without +# potentially quite slow. Try to abort the iterations early, preferably without # calling functions. 70%+ of the time cfg is already done or without deps. check_deps(){ for cfg; do @@ -922,7 +942,7 @@ reverse () { ' } -# keeps the last occurence of each non-unique item +# keeps the last occurrence of each non-unique item unique(){ unique_out= eval unique_in=\$$1 @@ -965,6 +985,12 @@ add_objcflags(){ append OBJCFLAGS $($objcflags_filter "$@") } +add_allcflags(){ + add_cflags "$@" + add_cxxflags "$@" + add_objcflags "$@" +} + add_asflags(){ append ASFLAGS $($asflags_filter "$@") } @@ -1025,6 +1051,14 @@ cc_o(){ eval printf '%s\\n' $CC_O } +cxx_e(){ + eval printf '%s\\n' $CXX_E +} + +cxx_o(){ + eval printf '%s\\n' $CXX_O +} + as_o(){ eval printf '%s\\n' $AS_O } @@ -1045,6 +1079,10 @@ hostcc_o(){ eval printf '%s\\n' $HOSTCC_O } +glslc_o(){ + eval printf '%s\\n' $GLSLC_O +} + nvcc_o(){ eval printf '%s\\n' $NVCC_O } @@ -1060,7 +1098,7 @@ test_cxx(){ log test_cxx "$@" cat > $TMPCPP log_file $TMPCPP - test_cmd $cxx $CPPFLAGS $CFLAGS $CXXFLAGS "$@" $CXX_C -o $TMPO $TMPCPP + test_cmd $cxx $CPPFLAGS $CXXFLAGS "$@" $CXX_C $(cxx_o $TMPO) $TMPCPP } test_objcc(){ @@ -1070,6 +1108,26 @@ test_objcc(){ test_cmd $objcc -Werror=missing-prototypes $CPPFLAGS $CFLAGS $OBJCFLAGS "$@" $OBJCC_C $(cc_o $TMPO) $TMPM } +test_glslc(){ + log test_glslc "$@" + cat > $TMPGLSL + log_file $TMPGLSL + test_cmd $glslc $GLSLCFLAGS $glslcflags "$@" $(glslc_o $TMPO) $TMPGLSL +} + +check_glslc(){ + log check_glslc "$@" + name=$1 + shift 1 + disable $name + test_glslc "$@" < $TMPCU @@ -1177,12 +1235,15 @@ check_arch_level(){ enabled tested_arch_level && as_arch_level="$level" } -check_archext_insn(){ - log check_archext_insn "$@" +check_archext_name_insn(){ + log check_archext_name_insn "$@" feature="$1" - instr="$2" + archext="$2" + archextdir=$(printf '%s' "$2" | tr '-' '_') + instr="$3" + instr2="$4" # Check if the assembly is accepted in inline assembly. - check_inline_asm ${feature}_inline "\"$instr\"" + check_inline_asm ${feature}_inline "\"$instr \n\t $instr2\"" # We don't check if the instruction is supported out of the box by the # external assembler (we don't try to set ${feature}_external) as we don't # need to use these instructions in non-runtime detected codepaths. @@ -1191,9 +1252,9 @@ check_archext_insn(){ enabled as_arch_directive && arch_directive=".arch $as_arch_level" || arch_directive="" - # Test if the assembler supports the .arch_extension $feature directive. - arch_extension_directive=".arch_extension $feature" - test_as < $TMPC @@ -1879,7 +2004,7 @@ EXTERNAL_LIBRARY_GPL_LIST=" EXTERNAL_LIBRARY_NONFREE_LIST=" decklink libfdk_aac - libtls + libmpeghdec " EXTERNAL_LIBRARY_VERSION3_LIST=" @@ -1902,6 +2027,7 @@ EXTERNAL_LIBRARY_LIST=" $EXTERNAL_LIBRARY_NONFREE_LIST $EXTERNAL_LIBRARY_VERSION3_LIST $EXTERNAL_LIBRARY_GPLV3_LIST + cairo chromaprint gcrypt gnutls @@ -1937,7 +2063,9 @@ EXTERNAL_LIBRARY_LIST=" libmodplug libmp3lame libmysofa + liboapv libopencv + libopencolorio libopenh264 libopenjpeg libopenmpt @@ -1961,9 +2089,11 @@ EXTERNAL_LIBRARY_LIST=" libsrt libssh libsvtav1 + libsvtjpegxs libtensorflow libtesseract libtheora + libtls libtorch libtwolame libuavs3d @@ -1974,18 +2104,23 @@ EXTERNAL_LIBRARY_LIST=" libvvenc libwebp libxevd + libxevdb libxeve + libxeveb libxml2 libzimg libzmq libzvbi lv2 mediacodec + ohcodec openal opengl openssl pocketsphinx vapoursynth + vulkan_static + whisper " HWACCEL_AUTODETECT_LIBRARY_LIST=" @@ -2048,6 +2183,7 @@ FEATURE_LIST=" small static swscale_alpha + unstable " # this list should be kept in linking order @@ -2055,7 +2191,6 @@ LIBRARY_LIST=" avdevice avfilter swscale - postproc avformat avcodec swresample @@ -2107,7 +2242,8 @@ CONFIG_LIST=" neon_clobber_test ossfuzz pic - ptx_compression + shader_compression + resource_compression thumb valgrind_backtrace xmm_clobber_test @@ -2149,6 +2285,7 @@ ARCH_LIST=" sparc64 tilegx tilepro + wasm x86 x86_32 x86_64 @@ -2159,12 +2296,18 @@ ARCH_EXT_LIST_ARM=" armv6 armv6t2 armv8 + arm_crc dotprod i8mm neon vfp vfpv3 setend + sve + sve2 + sme + sme_i16i64 + sme2 " ARCH_EXT_LIST_MIPS=" @@ -2187,8 +2330,13 @@ ARCH_EXT_LIST_LOONGSON=" lasx " +ARCH_EXT_LIST_WASM=" + simd128 +" + ARCH_EXT_LIST_X86_SIMD=" aesni + clmul amd3dnow amd3dnowext avx @@ -2234,6 +2382,7 @@ ARCH_EXT_LIST=" $ARCH_EXT_LIST_ARM $ARCH_EXT_LIST_PPC $ARCH_EXT_LIST_RISCV + $ARCH_EXT_LIST_WASM $ARCH_EXT_LIST_X86 $ARCH_EXT_LIST_MIPS $ARCH_EXT_LIST_LOONGSON @@ -2245,7 +2394,6 @@ ARCH_FEATURES=" fast_clz fast_cmov fast_float16 - local_aligned simd_align_16 simd_align_32 simd_align_64 @@ -2276,11 +2424,6 @@ HEADERS_LIST=" cdio_paranoia_paranoia_h cuda_h dispatch_dispatch_h - dev_bktr_ioctl_bt848_h - dev_bktr_ioctl_meteor_h - dev_ic_bt8xx_h - dev_video_bktr_ioctl_bt848_h - dev_video_meteor_ioctl_meteor_h direct_h dirent_h dxgidebug_h @@ -2290,11 +2433,7 @@ HEADERS_LIST=" io_h linux_dma_buf_h linux_perf_event_h - machine_ioctl_bt848_h - machine_ioctl_meteor_h malloc_h - opencv2_core_core_c_h - OpenGL_gl3_h poll_h pthread_np_h sys_hwprobe_h @@ -2433,8 +2572,14 @@ SYSTEM_LIBRARIES=" TOOLCHAIN_FEATURES=" as_arch_directive + as_archext_crc_directive as_archext_dotprod_directive as_archext_i8mm_directive + as_archext_sve_directive + as_archext_sve2_directive + as_archext_sme_directive + as_archext_sme_i16i64_directive + as_archext_sme2_directive as_dn_directive as_fpu_directive as_func @@ -2461,9 +2606,12 @@ TOOLCHAIN_FEATURES=" TYPES_LIST=" DPI_AWARENESS_CONTEXT IDXGIOutput5 + __x_ABI_CWindows_CGraphics_CCapture_CIGraphicsCaptureSession5 + IDirect3DDxgiInterfaceAccess kCMVideoCodecType_HEVC kCMVideoCodecType_HEVCWithAlpha kCMVideoCodecType_VP9 + kCMVideoCodecType_AV1 kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange kCVPixelFormatType_422YpCbCr8BiPlanarVideoRange kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange @@ -2471,6 +2619,7 @@ TYPES_LIST=" kCVPixelFormatType_444YpCbCr8BiPlanarVideoRange kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange kCVPixelFormatType_444YpCbCr16BiPlanarVideoRange + kCVPixelFormatType_422YpCbCr8_yuvs kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ kCVImageBufferTransferFunction_ITU_R_2100_HLG kCVImageBufferTransferFunction_Linear @@ -2478,6 +2627,8 @@ TYPES_LIST=" kCVImageBufferColorPrimaries_ITU_R_2020 kCVImageBufferTransferFunction_ITU_R_2020 kCVImageBufferTransferFunction_SMPTE_ST_428_1 + kVTQPModulationLevel_Default + SecPkgContext_KeyingMaterialInfo socklen_t struct_addrinfo struct_group_source_req @@ -2513,6 +2664,7 @@ HAVE_LIST=" $TOOLCHAIN_FEATURES $TYPES_LIST gzip + ioctl_posix libdrm_getfb2 makeinfo makeinfo_html @@ -2525,7 +2677,6 @@ HAVE_LIST=" opencl_videotoolbox perl pod2man - posix_ioctl texi2html xmllint zlib_gzip @@ -2544,15 +2695,22 @@ CONFIG_EXTRA=" bswapdsp cabac cbs + cbs_apv cbs_av1 cbs_h264 cbs_h265 cbs_h266 cbs_jpeg + cbs_lcevc cbs_mpeg2 cbs_vp8 cbs_vp9 + celp_math + d3d12_intra_refresh + d3d12_motion_estimator + d3d12_video_process_reference_info d3d12va_encode + d3d12va_me_precision_eighth_pixel deflate_wrapper dirac_parse dnn @@ -2560,7 +2718,6 @@ CONFIG_EXTRA=" dovi_rpuenc dvprofile evcparse - exif faandct faanidct fdctdsp @@ -2585,7 +2742,6 @@ CONFIG_EXTRA=" iamfdec iamfenc idctdsp - iirfilter inflate_wrapper intrax8 iso_media @@ -2609,6 +2765,7 @@ CONFIG_EXTRA=" mpegvideo mpegvideodec mpegvideoenc + mpegvideoencdsp msmpeg4dec msmpeg4enc mss34dsp @@ -2626,6 +2783,7 @@ CONFIG_EXTRA=" rv34dsp scene_sad sinewin + smpte_436m snappy srtp startcode @@ -2634,12 +2792,13 @@ CONFIG_EXTRA=" tpeldsp vaapi_1 vaapi_encode + vulkan_1_4 vc1dsp videodsp vp3dsp - vp56dsp vp8dsp vulkan_encode + vvc_sei wma_freqs wmv2dsp " @@ -2655,6 +2814,7 @@ CMDLINE_SELECT=" extra_warnings logging optimizations + response_files rpath stripping version_tracking @@ -2703,6 +2863,8 @@ CMDLINE_SET=" ln_s logfile malloc_prefix + glslc + glslcflags metalcc metallib nm @@ -2753,8 +2915,14 @@ intrinsics_sse2_deps="sse2" vfp_deps="arm" vfpv3_deps="vfp" setend_deps="arm" +arm_crc_deps="aarch64" dotprod_deps="aarch64 neon" i8mm_deps="aarch64 neon" +sve_deps="aarch64 neon" +sve2_deps="aarch64 neon sve" +sme_deps="aarch64 neon sve sve2" +sme_i16i64_deps="aarch64 neon sve sve2 sme" +sme2_deps="aarch64 neon sve sve2 sme" map 'eval ${v}_inline_deps=inline_asm' $ARCH_EXT_LIST_ARM @@ -2787,11 +2955,11 @@ mipsdsp_deps="mips" mipsdspr2_deps="mips" msa_deps="mipsfpu" +simd128_deps="wasm" + x86_64_select="i686" x86_64_suggest="fast_cmov" -amd3dnow_deps="mmx" -amd3dnowext_deps="amd3dnow" i686_deps="x86" mmx_deps="x86" mmxext_deps="mmx" @@ -2802,6 +2970,7 @@ ssse3_deps="sse3" sse4_deps="ssse3" sse42_deps="sse4" aesni_deps="sse42" +clmul_deps="sse42" avx_deps="sse42" xop_deps="avx" fma3_deps="avx" @@ -2842,11 +3011,13 @@ w32threads_deps="atomics_native" threads_if_any="$THREADS_LIST" # subsystems +cbs_apv_select="cbs" cbs_av1_select="cbs" cbs_h264_select="cbs" cbs_h265_select="cbs" cbs_h266_select="cbs" cbs_jpeg_select="cbs" +cbs_lcevc_select="cbs" cbs_mpeg2_select="cbs" cbs_vp8_select="cbs" cbs_vp9_select="cbs" @@ -2867,6 +3038,7 @@ h264parse_select="golomb" h264_sei_select="atsc_a53 golomb" hevcparse_select="golomb" hevc_sei_select="atsc_a53 golomb" +iso_writer_select="golomb" frame_thread_encoder_deps="encoders threads" iamfdec_deps="iamf" iamfdec_select="iso_media mpeg4audio" @@ -2879,37 +3051,49 @@ mpeg_er_select="error_resilience" mpegaudio_select="mpegaudiodsp mpegaudioheader" mpegvideo_select="blockdsp hpeldsp idctdsp videodsp" mpegvideodec_select="h264chroma mpegvideo mpeg_er" -mpegvideoenc_select="aandcttables fdctdsp me_cmp mpegvideo pixblockdsp" +mpegvideoenc_select="aandcttables fdctdsp me_cmp mpegvideo mpegvideoencdsp pixblockdsp" msmpeg4dec_select="h263_decoder" msmpeg4enc_select="h263_encoder" -vc1dsp_select="h264chroma qpeldsp startcode" -wmv2dsp_select="qpeldsp" +vc1dsp_select="h264chroma startcode" +vvc_sei_select="atsc_a53 golomb" +wmv2dsp_select="idctdsp" # decoders / encoders aac_decoder_select="adts_header mpeg4audio sinewin" aac_fixed_decoder_select="adts_header mpeg4audio" -aac_encoder_select="audio_frame_queue iirfilter lpc sinewin" +aac_encoder_select="audio_frame_queue lpc sinewin" aac_latm_decoder_select="aac_decoder aac_latm_parser" ac3_decoder_select="ac3_parser ac3dsp bswapdsp fmtconvert" ac3_fixed_decoder_select="ac3_parser ac3dsp bswapdsp" ac3_encoder_select="ac3dsp audiodsp me_cmp" ac3_fixed_encoder_select="ac3dsp audiodsp me_cmp" -acelp_kelvin_decoder_select="audiodsp" +acelp_kelvin_decoder_select="audiodsp celp_math" +adpcm_circus_decoder_deps="lgpl_gpl" adpcm_g722_decoder_select="g722dsp" adpcm_g722_encoder_select="g722dsp" +adpcm_ima_escape_decoder_deps="lgpl_gpl" +adpcm_ima_hvqm2_decoder_deps="lgpl_gpl" +adpcm_ima_hvqm4_decoder_deps="lgpl_gpl" +adpcm_ima_magix_decoder_deps="lgpl_gpl" +adpcm_ima_pda_decoder_deps="lgpl_gpl" +adpcm_n64_decoder_deps="lgpl_gpl" +adpcm_psxc_decoder_deps="lgpl_gpl" agm_decoder_select="idctdsp" +ahx_decoder_deps="lgpl_gpl" +ahx_decoder_select="mpegaudio ahx_to_mp2_bsf" aic_decoder_select="golomb idctdsp" alac_encoder_select="lpc" als_decoder_select="bswapdsp mpeg4audio" -amrnb_decoder_select="lsp" -amrwb_decoder_select="lsp" -amv_decoder_select="sp5x_decoder exif" +amrnb_decoder_select="lsp celp_math" +amrwb_decoder_select="lsp celp_math" +amv_decoder_select="sp5x_decoder" amv_encoder_select="jpegtables mpegvideoenc" ape_decoder_select="bswapdsp llauddsp" apng_decoder_select="inflate_wrapper" apng_encoder_select="deflate_wrapper llvidencdsp" aptx_encoder_select="audio_frame_queue" aptx_hd_encoder_select="audio_frame_queue" +apv_decoder_select="cbs_apv" asv1_decoder_select="blockdsp bswapdsp idctdsp" asv1_encoder_select="aandcttables bswapdsp fdctdsp pixblockdsp" asv2_decoder_select="blockdsp bswapdsp idctdsp" @@ -2929,7 +3113,7 @@ cook_decoder_select="audiodsp sinewin" cri_decoder_select="mjpeg_decoder" cscd_decoder_suggest="zlib" dds_decoder_select="texturedsp" -dirac_decoder_select="dirac_parse dwt golomb mpegvideoenc qpeldsp videodsp" +dirac_decoder_select="dirac_parse dwt golomb mpegvideoencdsp qpeldsp videodsp" dnxhd_decoder_select="blockdsp idctdsp" dnxhd_encoder_select="blockdsp fdctdsp idctdsp mpegvideoenc pixblockdsp videodsp" dvvideo_decoder_select="dvprofile idctdsp" @@ -2943,9 +3127,11 @@ eamad_decoder_select="aandcttables blockdsp bswapdsp" eatgq_decoder_select="aandcttables" eatqi_decoder_select="aandcttables blockdsp bswapdsp" exr_decoder_deps="zlib" +exr_decoder_select="bswapdsp" exr_encoder_deps="zlib" ffv1_decoder_select="rangecoder" ffv1_encoder_select="rangecoder" +ffv1_vulkan_encoder_select="vulkan spirv_compiler" ffvhuff_decoder_select="huffyuv_decoder" ffvhuff_encoder_select="huffyuv_encoder" fic_decoder_select="golomb" @@ -2961,10 +3147,12 @@ fraps_decoder_select="bswapdsp huffman" ftr_decoder_select="adts_header" g2m_decoder_deps="zlib" g2m_decoder_select="blockdsp idctdsp jpegtables" -g729_decoder_select="audiodsp" +g723_1_decoder_select="celp_math" +g723_1_encoder_select="celp_math" +g729_decoder_select="audiodsp celp_math" h261_decoder_select="mpegvideodec" h261_encoder_select="mpegvideoenc" -h263_decoder_select="h263_parser h263dsp mpegvideodec qpeldsp" +h263_decoder_select="h263dsp mpegvideodec" h263_encoder_select="h263dsp mpegvideoenc" h263i_decoder_select="h263_decoder" h263p_decoder_select="h263_decoder" @@ -2990,7 +3178,7 @@ ipu_decoder_select="mpegvideodec" jpegls_decoder_select="mjpeg_decoder" jv_decoder_select="blockdsp" lagarith_decoder_select="llviddsp" -lead_decoder_select="idctdsp jpegtables" +lead_decoder_select="blockdsp idctdsp jpegtables" ljpeg_encoder_select="jpegtables" lscr_decoder_select="inflate_wrapper" magicyuv_decoder_select="llviddsp" @@ -2999,9 +3187,9 @@ mdec_decoder_select="blockdsp bswapdsp idctdsp" media100_decoder_select="media100_to_mjpegb_bsf mjpegb_decoder" metasound_decoder_select="lsp sinewin" mimic_decoder_select="blockdsp bswapdsp hpeldsp idctdsp" -mjpeg_decoder_select="blockdsp hpeldsp exif idctdsp jpegtables" +mjpeg_decoder_select="blockdsp idctdsp jpegtables" mjpeg_encoder_select="jpegtables mpegvideoenc" -mjpegb_decoder_select="mjpeg_decoder" +mjpegb_decoder_select="hpeldsp mjpeg_decoder" mlp_decoder_select="mlp_parser" mlp_encoder_select="lpc audio_frame_queue" mobiclip_decoder_select="bswapdsp golomb" @@ -3023,7 +3211,7 @@ mpeg1video_decoder_select="mpegvideodec" mpeg1video_encoder_select="mpegvideoenc" mpeg2video_decoder_select="mpegvideodec" mpeg2video_encoder_select="mpegvideoenc" -mpeg4_decoder_select="h263_decoder" +mpeg4_decoder_select="h263_decoder qpeldsp" mpeg4_encoder_select="h263_encoder qpeldsp" msa1_decoder_select="mss34dsp" mscc_decoder_select="inflate_wrapper" @@ -3032,12 +3220,12 @@ msmpeg4v2_decoder_select="msmpeg4dec" msmpeg4v2_encoder_select="msmpeg4enc" msmpeg4v3_decoder_select="msmpeg4dec" msmpeg4v3_encoder_select="msmpeg4enc" -mss2_decoder_select="mpegvideodec qpeldsp vc1_decoder" +mss2_decoder_select="mpegvideodec vc1_decoder" mts2_decoder_select="jpegtables mss34dsp" mv30_decoder_select="aandcttables blockdsp" mvha_decoder_select="inflate_wrapper llviddsp" mwsc_decoder_select="inflate_wrapper" -mxpeg_decoder_select="mjpeg_decoder" +mxpeg_decoder_select="hpeldsp mjpeg_decoder" nellymoser_decoder_select="sinewin" nellymoser_encoder_select="audio_frame_queue sinewin" notchlc_decoder_select="lzf" @@ -3051,6 +3239,8 @@ prores_decoder_select="blockdsp idctdsp" prores_encoder_select="fdctdsp" prores_aw_encoder_select="fdctdsp" prores_ks_encoder_select="fdctdsp" +prores_ks_vulkan_encoder_select="vulkan spirv_compiler" +prores_raw_decoder_select="blockdsp idctdsp" qcelp_decoder_select="lsp" qdm2_decoder_select="mpegaudiodsp" ra_144_decoder_select="audiodsp" @@ -3066,12 +3256,13 @@ rv20_decoder_select="h263_decoder" rv20_encoder_select="h263_encoder" rv30_decoder_select="golomb h264pred h264qpel mpegvideodec rv34dsp" rv40_decoder_select="golomb h264pred h264qpel mpegvideodec rv34dsp" +rv60_decoder_select="videodsp golomb" screenpresso_decoder_deps="zlib" shorten_decoder_select="bswapdsp" -sipr_decoder_select="lsp" +sipr_decoder_select="lsp celp_math" smvjpeg_decoder_select="mjpeg_decoder" snow_decoder_select="dwt h264qpel rangecoder videodsp" -snow_encoder_select="dwt h264qpel hpeldsp me_cmp mpegvideoenc rangecoder videodsp" +snow_encoder_select="dwt h264qpel hpeldsp me_cmp mpegvideoencdsp rangecoder videodsp" sonic_decoder_select="golomb rangecoder" sonic_encoder_select="golomb rangecoder" sonic_ls_encoder_select="golomb rangecoder" @@ -3080,7 +3271,7 @@ speedhq_decoder_select="blockdsp idctdsp" speedhq_encoder_select="mpegvideoenc" srgc_decoder_select="inflate_wrapper" svq1_decoder_select="hpeldsp" -svq1_encoder_select="hpeldsp me_cmp mpegvideoenc" +svq1_encoder_select="hpeldsp me_cmp mpegvideoencdsp" svq3_decoder_select="golomb h264dsp h264parse h264pred hpeldsp tpeldsp videodsp" svq3_decoder_suggest="zlib" tak_decoder_select="audiodsp" @@ -3109,16 +3300,16 @@ vc1image_decoder_select="vc1_decoder" vorbis_encoder_select="audio_frame_queue" vp3_decoder_select="hpeldsp vp3dsp videodsp" vp4_decoder_select="vp3_decoder" -vp5_decoder_select="h264chroma hpeldsp videodsp vp3dsp vp56dsp" -vp6_decoder_select="h264chroma hpeldsp huffman videodsp vp3dsp vp56dsp" +vp5_decoder_select="h264chroma hpeldsp videodsp vp3dsp" +vp6_decoder_select="h264chroma hpeldsp huffman videodsp vp3dsp" vp6a_decoder_select="vp6_decoder" vp6f_decoder_select="vp6_decoder" vp7_decoder_select="h264pred videodsp vp8dsp" vp8_decoder_select="h264pred videodsp vp8dsp" -vp9_decoder_select="videodsp vp9_parser vp9_superframe_split_bsf" -vvc_decoder_select="cabac cbs_h266 golomb videodsp" +vp9_decoder_select="videodsp vp9_parser cbs_vp9 vp9_superframe_split_bsf" +vvc_decoder_select="cabac cbs_h266 golomb videodsp vvc_sei" wcmv_decoder_select="inflate_wrapper" -webp_decoder_select="vp8_decoder exif" +webp_decoder_select="vp8_decoder" wmalossless_decoder_select="llauddsp" wmapro_decoder_select="sinewin wma_freqs" wmav1_decoder_select="sinewin wma_freqs" @@ -3128,7 +3319,7 @@ wmav2_encoder_select="sinewin wma_freqs" wmavoice_decoder_select="lsp sinewin" wmv1_decoder_select="msmpeg4dec" wmv1_encoder_select="msmpeg4enc" -wmv2_decoder_select="blockdsp error_resilience idctdsp intrax8 msmpeg4dec videodsp wmv2dsp" +wmv2_decoder_select="blockdsp error_resilience idctdsp intrax8 msmpeg4dec qpeldsp videodsp wmv2dsp" wmv2_encoder_select="msmpeg4enc wmv2dsp" wmv3_decoder_select="vc1_decoder" wmv3image_decoder_select="wmv3_decoder" @@ -3148,7 +3339,7 @@ d3d11va_deps="dxva_h ID3D11VideoDecoder ID3D11VideoContext" d3d12va_deps="dxva_h ID3D12Device ID3D12VideoDecoder" dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" ffnvcodec_deps_any="libdl LoadLibrary" -mediacodec_deps="android mediandk" +mediacodec_deps="android mediandk pthreads" nvdec_deps="ffnvcodec" vaapi_x11_deps="xlib_x11" videotoolbox_hwaccel_deps="videotoolbox pthreads" @@ -3170,8 +3361,14 @@ av1_vaapi_hwaccel_deps="vaapi VADecPictureParameterBufferAV1_bit_depth_idx" av1_vaapi_hwaccel_select="av1_decoder" av1_vdpau_hwaccel_deps="vdpau VdpPictureInfoAV1" av1_vdpau_hwaccel_select="av1_decoder" +av1_videotoolbox_hwaccel_deps="videotoolbox" +av1_videotoolbox_hwaccel_select="av1_decoder" av1_vulkan_hwaccel_deps="vulkan" av1_vulkan_hwaccel_select="av1_decoder" +dpx_vulkan_hwaccel_deps="vulkan spirv_compiler" +dpx_vulkan_hwaccel_select="dpx_decoder" +ffv1_vulkan_hwaccel_deps="vulkan spirv_compiler" +ffv1_vulkan_hwaccel_select="ffv1_decoder" h263_vaapi_hwaccel_deps="vaapi" h263_vaapi_hwaccel_select="h263_decoder" h263_videotoolbox_hwaccel_deps="videotoolbox" @@ -3248,6 +3445,10 @@ mpeg4_videotoolbox_hwaccel_deps="videotoolbox" mpeg4_videotoolbox_hwaccel_select="mpeg4_decoder" prores_videotoolbox_hwaccel_deps="videotoolbox" prores_videotoolbox_hwaccel_select="prores_decoder" +prores_raw_vulkan_hwaccel_deps="vulkan spirv_compiler" +prores_raw_vulkan_hwaccel_select="prores_raw_decoder" +prores_vulkan_hwaccel_deps="vulkan spirv_compiler" +prores_vulkan_hwaccel_select="prores_decoder" vc1_d3d11va_hwaccel_deps="d3d11va" vc1_d3d11va_hwaccel_select="vc1_decoder" vc1_d3d11va2_hwaccel_deps="d3d11va" @@ -3282,6 +3483,10 @@ vp9_vdpau_hwaccel_deps="vdpau VdpPictureInfoVP9" vp9_vdpau_hwaccel_select="vp9_decoder" vp9_videotoolbox_hwaccel_deps="videotoolbox" vp9_videotoolbox_hwaccel_select="vp9_decoder" +vp9_vulkan_hwaccel_deps="vulkan vulkan_1_4" +vp9_vulkan_hwaccel_select="vp9_decoder" +vvc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferVVC" +vvc_vaapi_hwaccel_select="vvc_decoder" wmv3_d3d11va_hwaccel_select="vc1_d3d11va_hwaccel" wmv3_d3d11va2_hwaccel_select="vc1_d3d11va2_hwaccel" wmv3_d3d12va_hwaccel_select="vc1_d3d12va_hwaccel" @@ -3300,6 +3505,7 @@ qsvdec_select="qsv" qsvenc_select="qsv" qsvvpp_select="qsv" vaapi_encode_deps="vaapi" +vulkan_1_4_deps="vulkan" vulkan_encode_deps="vulkan" v4l2_m2m_deps="linux_videodev2_h sem_timedwait" @@ -3319,9 +3525,17 @@ thumbnail_cuda_filter_deps_any="cuda_nvcc cuda_llvm" transpose_npp_filter_deps="ffnvcodec libnpp" overlay_cuda_filter_deps="ffnvcodec" overlay_cuda_filter_deps_any="cuda_nvcc cuda_llvm" +pad_cuda_filter_deps="ffnvcodec" +pad_cuda_filter_deps_any="cuda_nvcc cuda_llvm" sharpen_npp_filter_deps="ffnvcodec libnpp" ddagrab_filter_deps="d3d11va IDXGIOutput1 DXGI_OUTDUPL_FRAME_INFO" +gfxcapture_filter_deps="cxx17 threads d3d11va IGraphicsCaptureItemInterop __x_ABI_CWindows_CGraphics_CCapture_CIGraphicsCaptureSession3" +gfxcapture_filter_extralibs="-lstdc++" +scale_d3d11_filter_deps="d3d11va" +scale_d3d12_filter_deps="d3d12va ID3D12VideoProcessor" +deinterlace_d3d12_filter_deps="d3d12va ID3D12VideoProcessor" +mestimate_d3d12_filter_deps="d3d12va ID3D12VideoMotionEstimator d3d12_motion_estimator" amf_deps_any="libdl LoadLibrary" nvenc_deps="ffnvcodec" @@ -3336,10 +3550,14 @@ amrnb_mediacodec_decoder_select="amr_parser" amrwb_mediacodec_decoder_deps="mediacodec" amrwb_mediacodec_decoder_select="amr_parser" av1_amf_encoder_deps="amf" +av1_amf_decoder_deps="amf" av1_cuvid_decoder_deps="cuvid CUVIDAV1PICPARAMS" +av1_d3d12va_encoder_deps="d3d12va d3d12va_av1_headers" +av1_d3d12va_encoder_select="cbs_av1 d3d12va_encode" av1_mediacodec_decoder_deps="mediacodec" av1_mediacodec_encoder_deps="mediacodec" av1_mediacodec_encoder_select="extract_extradata_bsf" +av1_mf_encoder_deps="mediafoundation" av1_nvenc_encoder_deps="nvenc NV_ENC_PIC_PARAMS_AV1" av1_nvenc_encoder_select="atsc_a53" av1_qsv_decoder_select="qsvdec" @@ -3347,11 +3565,15 @@ av1_qsv_encoder_deps="libvpl" av1_qsv_encoder_select="qsvenc" av1_vaapi_encoder_deps="VAEncPictureParameterBufferAV1" av1_vaapi_encoder_select="cbs_av1 vaapi_encode" +av1_vulkan_encoder_deps="vulkan_1_4" +av1_vulkan_encoder_select="cbs_av1 vulkan_encode" h263_v4l2m2m_decoder_deps="v4l2_m2m h263_v4l2_m2m" h263_v4l2m2m_encoder_deps="v4l2_m2m h263_v4l2_m2m" h264_amf_encoder_deps="amf" +h264_amf_decoder_deps="amf" h264_cuvid_decoder_deps="cuvid" h264_cuvid_decoder_select="h264_mp4toannexb_bsf" +h264_d3d12va_encoder_select="cbs_h264 d3d12va_encode" h264_mediacodec_decoder_deps="mediacodec" h264_mediacodec_decoder_select="h264_mp4toannexb_bsf h264_parser" h264_mediacodec_encoder_deps="mediacodec" @@ -3360,17 +3582,22 @@ h264_mf_encoder_deps="mediafoundation" h264_mmal_decoder_deps="mmal" h264_nvenc_encoder_deps="nvenc" h264_nvenc_encoder_select="atsc_a53" +h264_oh_decoder_deps="ohcodec" +h264_oh_decoder_select="h264_mp4toannexb_bsf" +h264_oh_encoder_deps="ohcodec" h264_omx_encoder_deps="omx" h264_qsv_decoder_select="h264_mp4toannexb_bsf qsvdec" h264_qsv_encoder_select="atsc_a53 qsvenc" h264_rkmpp_decoder_deps="rkmpp" h264_rkmpp_decoder_select="h264_mp4toannexb_bsf" +h264_rkmpp_encoder_deps="rkmpp" h264_vaapi_encoder_select="atsc_a53 cbs_h264 vaapi_encode" -h264_vulkan_encoder_select="cbs_h264 vulkan_encode" +h264_vulkan_encoder_select="atsc_a53 cbs_h264 vulkan_encode" h264_v4l2m2m_decoder_deps="v4l2_m2m h264_v4l2_m2m" h264_v4l2m2m_decoder_select="h264_mp4toannexb_bsf" h264_v4l2m2m_encoder_deps="v4l2_m2m h264_v4l2_m2m" hevc_amf_encoder_deps="amf" +hevc_amf_decoder_deps="amf" hevc_cuvid_decoder_deps="cuvid" hevc_cuvid_decoder_select="hevc_mp4toannexb_bsf" hevc_d3d12va_encoder_select="cbs_h265 d3d12va_encode" @@ -3381,10 +3608,14 @@ hevc_mediacodec_encoder_select="extract_extradata_bsf hevc_metadata" hevc_mf_encoder_deps="mediafoundation" hevc_nvenc_encoder_deps="nvenc" hevc_nvenc_encoder_select="atsc_a53" +hevc_oh_decoder_deps="ohcodec" +hevc_oh_decoder_select="hevc_mp4toannexb_bsf" +hevc_oh_encoder_deps="ohcodec" hevc_qsv_decoder_select="hevc_mp4toannexb_bsf qsvdec" hevc_qsv_encoder_select="hevcparse qsvenc" hevc_rkmpp_decoder_deps="rkmpp" hevc_rkmpp_decoder_select="hevc_mp4toannexb_bsf" +hevc_rkmpp_encoder_deps="rkmpp" hevc_vaapi_encoder_deps="VAEncPictureParameterBufferHEVC" hevc_vaapi_encoder_select="atsc_a53 cbs_h265 vaapi_encode" hevc_vulkan_encoder_select="atsc_a53 cbs_h265 vulkan_encode" @@ -3430,6 +3661,7 @@ vp8_vaapi_encoder_deps="VAEncPictureParameterBufferVP8" vp8_vaapi_encoder_select="vaapi_encode" vp8_v4l2m2m_decoder_deps="v4l2_m2m vp8_v4l2_m2m" vp8_v4l2m2m_encoder_deps="v4l2_m2m vp8_v4l2_m2m" +vp9_amf_decoder_deps="amf" vp9_cuvid_decoder_deps="cuvid" vp9_mediacodec_decoder_deps="mediacodec" vp9_mediacodec_encoder_deps="mediacodec" @@ -3440,36 +3672,44 @@ vp9_vaapi_encoder_select="vaapi_encode" vp9_qsv_encoder_deps="libmfx MFX_CODEC_VP9" vp9_qsv_encoder_select="qsvenc" vp9_v4l2m2m_decoder_deps="v4l2_m2m vp9_v4l2_m2m" +amf_capture_filter_deps="amf" vvc_qsv_decoder_select="vvc_mp4toannexb_bsf qsvdec" # parsers aac_parser_select="adts_header mpeg4audio" +ahx_parser_deps="lgpl_gpl" +apv_parser_select="cbs_apv" av1_parser_select="cbs_av1" evc_parser_select="evcparse" +ffv1_parser_select="rangecoder" ftr_parser_select="adts_header mpeg4audio" h264_parser_select="golomb h264dsp h264parse h264_sei" hevc_parser_select="hevcparse hevc_sei" mpegaudio_parser_select="mpegaudioheader" -mpeg4video_parser_select="h263dsp mpegvideodec qpeldsp" +mpeg4video_parser_select="mpegvideodec" vc1_parser_select="vc1dsp" vvc_parser_select="cbs_h266" # bitstream_filters aac_adtstoasc_bsf_select="adts_header mpeg4audio" +ahx_to_mp2_bsf_deps="lgpl_gpl" av1_frame_merge_bsf_select="cbs_av1" av1_frame_split_bsf_select="cbs_av1" av1_metadata_bsf_select="cbs_av1" dovi_rpu_bsf_select="cbs_h265 cbs_av1 dovi_rpudec dovi_rpuenc" -dts2pts_bsf_select="cbs_h264 h264parse" +dts2pts_bsf_select="cbs_h264 h264parse cbs_h265 hevc_parser" eac3_core_bsf_select="ac3_parser" +eia608_to_smpte436m_bsf_select="smpte_436m" evc_frame_merge_bsf_select="evcparse" filter_units_bsf_select="cbs" h264_metadata_bsf_deps="const_nan" h264_metadata_bsf_select="cbs_h264" h264_redundant_pps_bsf_select="cbs_h264" hevc_metadata_bsf_select="cbs_h265" +lcevc_metadata_bsf_select="cbs_lcevc" mjpeg2jpeg_bsf_select="jpegtables" mpeg2_metadata_bsf_select="cbs_mpeg2" +smpte436m_to_eia608_bsf_select="smpte_436m" trace_headers_bsf_select="cbs cbs_vp8" vp9_metadata_bsf_select="cbs_vp9" vvc_metadata_bsf_select="cbs_h266" @@ -3538,6 +3778,8 @@ libgsm_ms_decoder_deps="libgsm" libgsm_ms_encoder_deps="libgsm" libilbc_decoder_deps="libilbc" libilbc_encoder_deps="libilbc" +libjxl_anim_decoder_deps="libjxl libjxl_threads" +libjxl_anim_encoder_deps="libjxl libjxl_threads" libjxl_decoder_deps="libjxl libjxl_threads" libjxl_encoder_deps="libjxl libjxl_threads" libkvazaar_encoder_deps="libkvazaar" @@ -3547,6 +3789,8 @@ liblc3_encoder_select="audio_frame_queue" libmodplug_demuxer_deps="libmodplug" libmp3lame_encoder_deps="libmp3lame" libmp3lame_encoder_select="audio_frame_queue mpegaudioheader" +libmpeghdec_decoder_deps="libmpeghdec" +liboapv_encoder_deps="liboapv" libopencore_amrnb_decoder_deps="libopencore_amrnb" libopencore_amrnb_encoder_deps="libopencore_amrnb" libopencore_amrnb_encoder_select="audio_frame_queue" @@ -3567,6 +3811,8 @@ libspeex_decoder_deps="libspeex" libspeex_encoder_deps="libspeex" libspeex_encoder_select="audio_frame_queue" libsvtav1_encoder_deps="libsvtav1" +libsvtjpegxs_encoder_deps="libsvtjpegxs" +libsvtjpegxs_decoder_deps="libsvtjpegxs" libsvtav1_encoder_select="dovi_rpuenc" libtheora_encoder_deps="libtheora" libtwolame_encoder_deps="libtwolame" @@ -3591,13 +3837,13 @@ libx265_encoder_deps="libx265" libx265_encoder_select="atsc_a53 dovi_rpuenc" libxavs_encoder_deps="libxavs" libxavs2_encoder_deps="libxavs2" -libxevd_decoder_deps="libxevd" -libxeve_encoder_deps="libxeve" +libxevd_decoder_deps_any="libxevd libxevdb" +libxeve_encoder_deps_any="libxeve libxeveb" libxvid_encoder_deps="libxvid" libzvbi_teletext_decoder_deps="libzvbi" vapoursynth_demuxer_deps="vapoursynth" videotoolbox_suggest="coreservices" -videotoolbox_deps="corefoundation coremedia corevideo" +videotoolbox_deps="corefoundation coremedia corevideo VTDecompressionSessionDecodeFrame" videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames" # demuxers / muxers @@ -3606,12 +3852,13 @@ act_demuxer_select="riffdec" adts_muxer_select="mpeg4audio" aiff_muxer_select="iso_media" amv_muxer_select="riffenc" +apv_demuxer_select="apv_parser" asf_demuxer_select="riffdec" asf_o_demuxer_select="riffdec" asf_muxer_select="riffenc" asf_stream_muxer_select="asf_muxer" av1_demuxer_select="av1_frame_merge_bsf av1_parser" -avi_demuxer_select="riffdec exif" +avi_demuxer_select="riffdec" avi_muxer_select="riffenc" avif_muxer_select="mov_muxer" caf_demuxer_select="iso_media" @@ -3636,7 +3883,8 @@ flv_muxer_select="aac_adtstoasc_bsf iso_writer" gxf_muxer_select="pcm_rechunk_bsf" hds_muxer_select="flv_muxer" hls_demuxer_select="aac_demuxer ac3_demuxer adts_header ac3_parser eac3_demuxer mov_demuxer mpegts_demuxer" -hls_muxer_select="mov_muxer mpegts_muxer" +hls_muxer_select="mov_muxer mpegts_muxer webvtt_muxer" +hxvs_demuxer_select="h264_parser hevc_parser" iamf_demuxer_select="iamfdec" iamf_muxer_select="iamfenc" image2_alias_pix_demuxer_select="image2_demuxer" @@ -3651,6 +3899,9 @@ matroska_audio_muxer_select="matroska_muxer" matroska_demuxer_select="riffdec" matroska_demuxer_suggest="bzlib zlib" matroska_muxer_select="iso_writer mpeg4audio riffenc aac_adtstoasc_bsf pgs_frame_merge_bsf vp9_superframe_bsf" +mcc_demuxer_select="smpte_436m" +mcc_muxer_select="smpte_436m" +mcc_muxer_suggest="eia608_to_smpte436m_bsf" mlp_demuxer_select="mlp_parser" mmf_muxer_select="riffenc" mov_demuxer_select="iso_media riffdec" @@ -3664,6 +3915,7 @@ mpegts_demuxer_select="iso_media" mpegts_muxer_select="ac3_parser adts_muxer latm_muxer h264_mp4toannexb_bsf hevc_mp4toannexb_bsf vvc_mp4toannexb_bsf" mpegtsraw_demuxer_select="mpegts_demuxer" mxf_muxer_select="iso_writer pcm_rechunk_bsf rangecoder" +mxf_muxer_suggest="eia608_to_smpte436m_bsf" mxf_d10_muxer_select="mxf_muxer" mxf_opatom_muxer_select="mxf_muxer" nut_muxer_select="riffenc" @@ -3690,6 +3942,7 @@ spdif_muxer_select="adts_header" spx_muxer_select="ogg_muxer" swf_demuxer_suggest="zlib" tak_demuxer_select="tak_parser" +tee_muxer_select="fifo_muxer" truehd_demuxer_select="mlp_parser" tg2_muxer_select="mov_muxer" tgp_muxer_select="mov_muxer" @@ -3700,6 +3953,7 @@ wav_demuxer_select="riffdec" wav_muxer_select="riffenc" webm_chunk_muxer_select="webm_muxer" webm_dash_manifest_demuxer_select="matroska_demuxer" +whip_muxer_select="dtls_protocol rtp_muxer http_protocol" wtv_demuxer_select="mpegts_demuxer riffdec" wtv_muxer_select="mpegts_muxer riffenc" xmv_demuxer_select="riffdec" @@ -3709,12 +3963,11 @@ xwma_demuxer_select="riffdec" android_camera_indev_deps="android camera2ndk mediandk pthreads" alsa_indev_deps="alsa" alsa_outdev_deps="alsa" -avfoundation_indev_deps="avfoundation corevideo coremedia pthreads" +avfoundation_indev_deps="avfoundation corevideo coremedia pthreads AVCaptureSession" avfoundation_indev_suggest="coregraphics applicationservices" avfoundation_indev_extralibs="-framework Foundation" -audiotoolbox_outdev_deps="audiotoolbox pthreads" +audiotoolbox_outdev_deps="audiotoolbox pthreads AudioObjectPropertyAddress" audiotoolbox_outdev_extralibs="-framework AudioToolbox -framework CoreAudio" -bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" caca_outdev_deps="libcaca" decklink_deps_any="libdl LoadLibrary" decklink_indev_deps="decklink threads" @@ -3739,13 +3992,10 @@ lavfi_indev_deps="avfilter" libcdio_indev_deps="libcdio" libdc1394_indev_deps="libdc1394" openal_indev_deps="openal" -opengl_outdev_deps="opengl" -opengl_outdev_suggest="sdl2" oss_indev_deps_any="sys_soundcard_h" oss_outdev_deps_any="sys_soundcard_h" pulse_indev_deps="libpulse" pulse_outdev_deps="libpulse" -sdl2_outdev_deps="sdl2" sndio_indev_deps="sndio" sndio_outdev_deps="sndio" v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h" @@ -3802,6 +4052,9 @@ srtp_protocol_select="rtp_protocol srtp" tcp_protocol_select="network" tls_protocol_deps_any="gnutls openssl schannel securetransport libtls mbedtls" tls_protocol_select="tcp_protocol" +# TODO: Support libtls. +dtls_protocol_deps_any="openssl schannel gnutls mbedtls" +dtls_protocol_select="udp_protocol" udp_protocol_select="network" udplite_protocol_select="network" unix_protocol_deps="sys_un_h" @@ -3836,16 +4089,17 @@ ass_filter_deps="libass" avgblur_opencl_filter_deps="opencl" avgblur_vulkan_filter_deps="vulkan spirv_compiler" azmq_filter_deps="libzmq" +blackdetect_vulkan_filter_deps="vulkan spirv_library" blackframe_filter_deps="gpl" -blend_vulkan_filter_deps="vulkan spirv_compiler" +blend_vulkan_filter_deps="vulkan spirv_library" boxblur_filter_deps="gpl" boxblur_opencl_filter_deps="opencl gpl" bs2b_filter_deps="libbs2b" bwdif_cuda_filter_deps="ffnvcodec" bwdif_cuda_filter_deps_any="cuda_nvcc cuda_llvm" bwdif_vulkan_filter_deps="vulkan spirv_compiler" -chromaber_vulkan_filter_deps="vulkan spirv_compiler" -color_vulkan_filter_deps="vulkan spirv_compiler" +chromaber_vulkan_filter_deps="vulkan spirv_library" +color_vulkan_filter_deps="vulkan spirv_library" colorkey_opencl_filter_deps="opencl" colormatrix_filter_deps="gpl" convolution_opencl_filter_deps="opencl" @@ -3869,11 +4123,12 @@ dnn_detect_filter_select="dnn" dnn_processing_filter_select="dnn" drawtext_filter_deps="libfreetype libharfbuzz" drawtext_filter_suggest="libfontconfig libfribidi" +drawvg_filter_deps="cairo" elbg_filter_deps="avcodec" eq_filter_deps="gpl" erosion_opencl_filter_deps="opencl" find_rect_filter_deps="avcodec avformat gpl" -flip_vulkan_filter_deps="vulkan spirv_compiler" +flip_vulkan_filter_deps="vulkan spirv_library" flite_filter_deps="libflite threads" framerate_filter_select="scene_sad" freezedetect_filter_select="scene_sad" @@ -3882,14 +4137,15 @@ frei0r_filter_deps="frei0r" frei0r_src_filter_deps="frei0r" fspp_filter_deps="gpl" fsync_filter_deps="avformat" -gblur_vulkan_filter_deps="vulkan spirv_compiler" -hflip_vulkan_filter_deps="vulkan spirv_compiler" +gblur_vulkan_filter_deps="vulkan spirv_library" +hflip_vulkan_filter_deps="vulkan spirv_library" histeq_filter_deps="gpl" hqdn3d_filter_deps="gpl" iccdetect_filter_deps="lcms2" iccgen_filter_deps="lcms2" identity_filter_select="scene_sad" interlace_filter_deps="gpl" +interlace_vulkan_filter_deps="vulkan spirv_library" kerndeint_filter_deps="gpl" ladspa_filter_deps="ladspa libdl" lcevc_filter_deps="liblcevc_dec" @@ -3903,9 +4159,10 @@ mpdecimate_filter_deps="gpl" mpdecimate_filter_select="pixelutils" minterpolate_filter_select="scene_sad" mptestsrc_filter_deps="gpl" +msad_filter_select="scene_sad" negate_filter_deps="lut_filter" nlmeans_opencl_filter_deps="opencl" -nlmeans_vulkan_filter_deps="vulkan spirv_compiler" +nlmeans_vulkan_filter_deps="vulkan spirv_library" nnedi_filter_deps="gpl" ocr_filter_deps="libtesseract" ocv_filter_deps="libopencv" @@ -3913,18 +4170,19 @@ openclsrc_filter_deps="opencl" qrencode_filter_deps="libqrencode" qrencodesrc_filter_deps="libqrencode" quirc_filter_deps="libquirc" +ocio_filter_deps="libopencolorio" +libopencolorio_filter_deps="libopencolorio" overlay_opencl_filter_deps="opencl" overlay_qsv_filter_deps="libmfx" overlay_qsv_filter_select="qsvvpp" overlay_vaapi_filter_deps="vaapi VAProcPipelineCaps_blend_flags" -overlay_vulkan_filter_deps="vulkan spirv_compiler" +overlay_vulkan_filter_deps="vulkan spirv_library" owdenoise_filter_deps="gpl" pad_opencl_filter_deps="opencl" pan_filter_deps="swresample" perspective_filter_deps="gpl" phase_filter_deps="gpl" pp7_filter_deps="gpl" -pp_filter_deps="gpl postproc" prewitt_opencl_filter_deps="opencl" procamp_vaapi_filter_deps="vaapi" program_opencl_filter_deps="opencl" @@ -3937,9 +4195,12 @@ rubberband_filter_deps="librubberband" sab_filter_deps="gpl swscale" scale2ref_filter_deps="swscale" scale_filter_deps="swscale" +sr_amf_filter_deps="amf" +vpp_amf_filter_deps="amf" scale_qsv_filter_deps="libmfx" scale_qsv_filter_select="qsvvpp" scdet_filter_select="scene_sad" +scdet_vulkan_filter_deps="vulkan spirv_library" select_filter_select="scene_sad" sharpness_vaapi_filter_deps="vaapi" showcqt_filter_deps="avformat swscale" @@ -3949,7 +4210,7 @@ smartblur_filter_deps="gpl swscale" sobel_opencl_filter_deps="opencl" sofalizer_filter_deps="libmysofa" spp_filter_deps="gpl avcodec" -spp_filter_select="idctdsp fdctdsp me_cmp pixblockdsp" +spp_filter_select="idctdsp fdctdsp pixblockdsp" sr_filter_deps="avformat swscale" sr_filter_select="dnn" stereo3d_filter_deps="gpl" @@ -3965,11 +4226,11 @@ tonemap_opencl_filter_deps="opencl const_nan" transpose_opencl_filter_deps="opencl" transpose_vaapi_filter_deps="vaapi VAProcPipelineCaps_rotation_flags" transpose_vt_filter_deps="videotoolbox VTPixelRotationSessionCreate" -transpose_vulkan_filter_deps="vulkan spirv_compiler" +transpose_vulkan_filter_deps="vulkan spirv_library" unsharp_opencl_filter_deps="opencl" uspp_filter_deps="gpl avcodec" vaguedenoiser_filter_deps="gpl" -vflip_vulkan_filter_deps="vulkan spirv_compiler" +vflip_vulkan_filter_deps="vulkan spirv_library" vidstabdetect_filter_deps="libvidstab" vidstabtransform_filter_deps="libvidstab" libvmaf_filter_deps="libvmaf" @@ -3979,11 +4240,11 @@ zoompan_filter_deps="swscale" zscale_filter_deps="libzimg const_nan" scale_vaapi_filter_deps="vaapi" scale_vt_filter_deps="videotoolbox VTPixelTransferSessionCreate" -scale_vulkan_filter_deps="vulkan spirv_compiler" +scale_vulkan_filter_deps="vulkan spirv_compiler spirv_library" vpp_qsv_filter_deps="libmfx" vpp_qsv_filter_select="qsvvpp" xfade_opencl_filter_deps="opencl" -xfade_vulkan_filter_deps="vulkan spirv_compiler" +xfade_vulkan_filter_deps="vulkan spirv_library" yadif_cuda_filter_deps="ffnvcodec" yadif_cuda_filter_deps_any="cuda_nvcc cuda_llvm" yadif_videotoolbox_filter_deps="metal corevideo videotoolbox" @@ -3998,6 +4259,7 @@ xstack_qsv_filter_deps="libmfx" xstack_qsv_filter_select="qsvvpp" pad_vaapi_filter_deps="vaapi_1" drawbox_vaapi_filter_deps="vaapi_1" +whisper_filter_deps="whisper" # examples avio_http_serve_files_deps="avformat avutil fork" @@ -4031,22 +4293,21 @@ cws2fws_extralibs="zlib_extralibs" # libraries, in any order avcodec_deps="avutil" -avcodec_suggest="libm stdatomic liblcevc_dec" +avcodec_suggest="libm stdatomic zlib" avdevice_deps="avformat avcodec avutil" avdevice_suggest="libm stdatomic" avfilter_deps="avutil" -avfilter_suggest="libm stdatomic" +avfilter_suggest="libm stdatomic zlib spirv_library" avformat_deps="avcodec avutil" avformat_suggest="libm network zlib stdatomic" -avutil_suggest="clock_gettime ffnvcodec gcrypt libm libdrm libmfx opencl openssl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt stdatomic" -postproc_deps="avutil gpl" -postproc_suggest="libm stdatomic" +avutil_suggest="clock_gettime ffnvcodec gcrypt libm zlib libdrm libmfx opencl openssl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt stdatomic" swresample_deps="avutil" swresample_suggest="libm libsoxr stdatomic" swscale_deps="avutil" -swscale_suggest="libm stdatomic" +swscale_suggest="libm stdatomic spirv_library" +shader_compression_suggest="zlib" -avcodec_extralibs="pthreads_extralibs iconv_extralibs dxva2_extralibs lcms2_extralibs" +avcodec_extralibs="pthreads_extralibs iconv_extralibs dxva2_extralibs liblcevc_dec_extralibs lcms2_extralibs" avfilter_extralibs="pthreads_extralibs" avutil_extralibs="d3d11va_extralibs d3d12va_extralibs mediacodec_extralibs nanosleep_extralibs pthreads_extralibs vaapi_drm_extralibs vaapi_x11_extralibs vaapi_win32_extralibs vdpau_x11_extralibs" @@ -4087,12 +4348,13 @@ mandir_default='${prefix}/share/man' ar_default="ar" cc_default="gcc" stdc_default="c17" -stdcxx_default="c++11" +stdcxx_default="c++17" cxx_default="g++" host_cc_default="gcc" doxygen_default="doxygen" install="install" ln_s_default="ln -s -f" +glslc_default="glslc" metalcc_default="xcrun -sdk macosx metal" metallib_default="xcrun -sdk macosx metallib" nm_default="nm -g" @@ -4104,6 +4366,7 @@ objformat="elf32" x86asmexe_default="nasm" windres_default="windres" striptype="direct" +response_files_default="auto" # OS target_os_default=$(tolower $(uname -s)) @@ -4137,11 +4400,13 @@ enable faan faandct faanidct enable iamf enable large_tests enable optimizations -enable ptx_compression +enable shader_compression +enable resource_compression enable runtime_cpudetect enable safe_bitstream_reader enable static enable swscale_alpha +enable unstable enable valgrind_backtrace sws_max_filter_size_default=256 @@ -4171,6 +4436,7 @@ VERSION_SCRIPT_POSTPROCESS_CMD="cat" asflags_filter=echo cflags_filter=echo +objcflags_filter=echo ldflags_filter=echo AS_C='-c' @@ -4191,6 +4457,7 @@ HOSTCC_C='-c' HOSTCC_E='-E -o $@' HOSTCC_O='-o $@' HOSTLD_O='-o $@' +GLSLC_O='-o $@' NVCC_C='-c' NVCC_O='-o $@' @@ -4238,7 +4505,7 @@ find_things_extern(){ find_filters_extern(){ file=$source_path/$1 - sed -n 's/^extern const AVFilter ff_[avfsinkrc]\{2,5\}_\([[:alnum:]_]\{1,\}\);/\1_filter/p' $file + sed -n 's/^extern const FFFilter ff_[avfsinkrc]\{2,5\}_\([[:alnum:]_]\{1,\}\);/\1_filter/p' $file } FILTER_LIST=$(find_filters_extern libavfilter/allfilters.c) @@ -4252,7 +4519,7 @@ CODEC_LIST=" $ENCODER_LIST $DECODER_LIST " -PARSER_LIST=$(find_things_extern parser AVCodecParser libavcodec/parsers.c) +PARSER_LIST=$(find_things_extern parser FFCodecParser libavcodec/parsers.c) BSF_LIST=$(find_things_extern bsf FFBitStreamFilter libavcodec/bitstream_filters.c) HWACCEL_LIST=$(find_things_extern hwaccel FFHWAccel libavcodec/hwaccels.h) PROTOCOL_LIST=$(find_things_extern protocol URLProtocol libavformat/protocols.c) @@ -4348,6 +4615,9 @@ do_random(){ $action $(rand_list "$@" | awk "BEGIN { srand($random_seed) } \$1 == \"prob\" { prob = \$2; next } rand() < prob { print }") } +# deprecated components (disabled by default) +disable sonic_encoder sonic_ls_encoder + for opt do optval="${opt#*=}" case "$opt" in @@ -4409,16 +4679,6 @@ for opt do test $action = enable && warn_if_gets_disabled $list $action $list ;; - --enable-yasm|--disable-yasm) - warn "The ${opt} option is only provided for compatibility and will be\n"\ - "removed in the future. Use --enable-x86asm / --disable-x86asm instead." - test $opt = --enable-yasm && x86asm=yes || x86asm=no - ;; - --yasmexe=*) - warn "The --yasmexe option is only provided for compatibility and will be\n"\ - "removed in the future. Use --x86asmexe instead." - x86asmexe="$optval" - ;; --enable-?*|--disable-?*) eval $(echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g') if is_in $option $COMPONENT_LIST; then @@ -4466,7 +4726,7 @@ done if disabled autodetect; then - # Unless iconv is explicitely disabled by the user, we still want to probe + # Unless iconv is explicitly disabled by the user, we still want to probe # for the iconv from the libc. disabled iconv || enable libc_iconv @@ -4511,6 +4771,7 @@ enabled gpl && map "die_license_disabled_gpl nonfree" $EXTERNAL_LIBRARY_NONFREE_ map "die_license_disabled nonfree" $HWACCEL_LIBRARY_NONFREE_LIST enabled version3 && { enabled gpl && enable gplv3 || enable lgplv3; } +enabled gpl && enable lgpl_gpl # Files that are marked as LGPL but some developers prefer only building them with --enable-gpl if enabled nonfree; then license="nonfree and unredistributable" @@ -4533,6 +4794,12 @@ enabled_all gnutls mbedtls && enabled_all openssl mbedtls && die "OpenSSL and mbedTLS must not be enabled at the same time." +enabled_all libxevd libxevdb && + die "libxevd and libxevdb must not be enabled at the same time." + +enabled_all libxeve libxeveb && + die "libxeve and libxevdb must not be enabled at the same time." + # Disable all the library-specific components if the library itself # is disabled, see AVCODEC_LIST and following _LIST variables. @@ -4550,31 +4817,31 @@ set >> $logfile test -n "$valgrind" && toolchain="valgrind-memcheck" -enabled ossfuzz && ! echo $CFLAGS | grep -q -- "-fsanitize=" && ! echo $CFLAGS | grep -q -- "-fcoverage-mapping" &&{ - add_cflags -fsanitize=address,undefined -fsanitize-coverage=trace-pc-guard,trace-cmp -fno-omit-frame-pointer - add_ldflags -fsanitize=address,undefined -fsanitize-coverage=trace-pc-guard,trace-cmp -} - add_sanitizer_flags(){ case "$1" in asan) - add_cflags -fsanitize=address + add_allcflags -fsanitize=address add_ldflags -fsanitize=address ;; + fuzz) + add_allcflags -fsanitize=fuzzer-no-link + add_ldflags -fsanitize=fuzzer-no-link + : "${libfuzzer_path:=-fsanitize=fuzzer}" + ;; lsan) - add_cflags -fsanitize=leak + add_allcflags -fsanitize=leak add_ldflags -fsanitize=leak ;; msan) - add_cflags -fsanitize=memory -fsanitize-memory-track-origins + add_allcflags -fsanitize=memory -fsanitize-memory-track-origins add_ldflags -fsanitize=memory ;; tsan) - add_cflags -fsanitize=thread + add_allcflags -fsanitize=thread add_ldflags -fsanitize=thread ;; - usan) - add_cflags -fsanitize=undefined + usan|ubsan) + add_allcflags -fsanitize=undefined add_ldflags -fsanitize=undefined ;; ?*) @@ -4583,19 +4850,29 @@ add_sanitizer_flags(){ esac } +add_sanitizers(){ + IFS=- + set -- $* + unset IFS + for sanitizer; do + add_sanitizer_flags "$sanitizer" + done + add_allcflags -fno-omit-frame-pointer +} + case "$toolchain" in clang-*) - add_sanitizer_flags "${toolchain#clang-}" + add_sanitizers "${toolchain#clang-}" cc_default="clang" cxx_default="clang++" ;; gcc-*) - add_sanitizer_flags "${toolchain#gcc-}" + add_sanitizers "${toolchain#gcc-}" cc_default="gcc" cxx_default="g++" # In case of tsan with gcc, PIC has to be enabled if [ "${toolchain#gcc-}" = "tsan" ]; then - add_cflags -fPIC + add_allcflags -fPIC add_ldflags -fPIC fi ;; @@ -4646,18 +4923,18 @@ case "$toolchain" in TMPDIR=. ;; gcov) - add_cflags -fprofile-arcs -ftest-coverage + add_allcflags -fprofile-arcs -ftest-coverage add_ldflags -fprofile-arcs -ftest-coverage ;; llvm-cov) - add_cflags -fprofile-arcs -ftest-coverage + add_allcflags -fprofile-arcs -ftest-coverage add_ldflags --coverage ;; hardened) add_cppflags -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 - add_cflags -fno-strict-overflow -fstack-protector-all + add_allcflags -fno-strict-overflow -fstack-protector-all add_ldflags -Wl,-z,relro -Wl,-z,now - add_cflags -fPIE + add_allcflags -fPIE add_ldexeflags -fPIE -pie ;; ?*) @@ -4707,10 +4984,13 @@ if enabled cuda_nvcc; then if $nvcc $nvccflags_default 2>&1 | grep -qi unsupported; then nvccflags_default="-gencode arch=compute_60,code=sm_60 -O2" fi + if $nvcc $nvccflags_default 2>&1 | grep -qi unsupported; then + nvccflags_default="-gencode arch=compute_75,code=sm_75 -O2" + fi fi set_default arch cc cxx doxygen pkg_config ranlib strip sysinclude \ - target_exec x86asmexe metalcc metallib stdc stdcxx + target_exec x86asmexe glslc metalcc metallib stdc stdcxx enabled cross_compile || host_cc_default=$cc set_default host_cc @@ -4782,6 +5062,7 @@ tmpfile TMPE $EXESUF tmpfile TMPH .h tmpfile TMPM .m tmpfile TMPCU .cu +tmpfile TMPGLSL .comp.glsl tmpfile TMPO .o tmpfile TMPS .S tmpfile TMPSH .sh @@ -4810,6 +5091,7 @@ armasm_flags(){ # Filter out MSVC cl.exe options from cflags that shouldn't # be passed to gas-preprocessor -M[TD]*) ;; + -guard:signret) ;; *) echo $flag ;; esac done @@ -4851,7 +5133,7 @@ msvc_common_flags(){ -lstdc++) ;; -l*) echo ${flag#-l}.lib ;; -LARGEADDRESSAWARE) echo $flag ;; - -L*) echo -libpath:${flag#-L} ;; + -L*) [ "$_flags_type" = "link" ] && echo -libpath:${flag#-L} ;; -Wl,*) ;; *) echo $flag ;; esac @@ -4863,7 +5145,7 @@ msvc_flags(){ for flag; do case $flag in -Wall) echo -W3 -wd4018 -wd4146 -wd4244 -wd4305 \ - -wd4554 ;; + -wd4554 -wd4267 ;; -Wextra) echo -W4 -wd4244 -wd4127 -wd4018 -wd4389 \ -wd4146 -wd4057 -wd4204 -wd4706 -wd4305 \ -wd4152 -wd4324 -we4013 -wd4100 -wd4214 \ @@ -4873,6 +5155,12 @@ msvc_flags(){ done } +msvc_flags_link(){ + _flags_type=link + msvc_flags "$@" + unset _flags_type +} + icl_flags(){ msvc_common_flags "$@" for flag; do @@ -4944,9 +5232,9 @@ probe_cc(){ _cc=$2 first=$3 - unset _type _ident _cc_c _cc_e _cc_o _flags _cflags + unset _type _ident _cc_c _cc_e _cc_o _flags _cflags _cxxflags unset _ld_o _ldflags _ld_lib _ld_path - unset _depflags _DEPCMD _DEPFLAGS + unset _depflags _DEPCMD _DEPFLAGS _DEPCCFLAGS _DEPCXXFLAGS _flags_filter=echo if $_cc --version 2>&1 | grep -q '^GNU assembler'; then @@ -4984,7 +5272,6 @@ probe_cc(){ _depflags='-MMD' _cflags_speed='-O3' _cflags_size='-Os' - _cflags_noopt='-O1' _flags_filter=icc_flags elif $_cc -v 2>&1 | grep -q xlc; then _type=xlc @@ -5058,7 +5345,7 @@ probe_cc(){ _cc_o='-Fo$@' _cc_e='-P' _flags_filter=icl_flags - _ld_lib='lib%.a' + _ld_lib='%.lib' _ld_path='-libpath:' # -Qdiag-error to make icl error when seeing certain unknown arguments _flags='-nologo -Qdiag-error:4044,10157' @@ -5068,20 +5355,22 @@ probe_cc(){ disable stripping elif $_cc -? 2>/dev/null | grep -q 'LLVM.*Linker'; then # lld can emulate multiple different linkers; in ms link.exe mode, - # the -? parameter gives the help output which contains an identifyable + # the -? parameter gives the help output which contains an identifiable # string, while it gives an error in other modes. _type=lld-link # The link.exe mode doesn't have a switch for getting the version, # but we can force it back to gnu mode and get the version from there. _ident=$($_cc -flavor gnu --version 2>/dev/null) _ld_o='-out:$@' - _flags_filter=msvc_flags - _ld_lib='lib%.a' + _flags_filter=msvc_flags_link + _ld_lib='%.lib' _ld_path='-libpath:' - elif $_cc -nologo- 2>&1 | grep -q Microsoft || { $_cc -v 2>&1 | grep -q clang && $_cc -? > /dev/null 2>&1; }; then + elif VSLANG=1033 $_cc -nologo- 2>&1 | grep -q ^Microsoft || { $_cc -v 2>&1 | grep -q clang && $_cc -? > /dev/null 2>&1; }; then _type=msvc - if $_cc -nologo- 2>&1 | grep -q Microsoft; then - _ident=$($_cc 2>&1 | head -n1 | tr -d '\r') + if VSLANG=1033 $_cc -nologo- 2>&1 | grep -q ^Microsoft; then + # Depending on the tool (cl.exe or link.exe), the version number + # is printed on the first line of stderr or stdout + _ident=$(VSLANG=1033 $_cc 2>&1 | grep ^Microsoft | head -n1 | tr -d '\r') else _ident=$($_cc --version 2>/dev/null | head -n1 | tr -d '\r') fi @@ -5091,21 +5380,24 @@ probe_cc(){ else _DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>&1 | awk '\''/including/ { sub(/^.*file: */, ""); gsub(/\\/, "/"); if (!match($$0, / /)) print "$@:", $$0 }'\'' > $(@:.o=.d)' fi - _DEPFLAGS='$(CPPFLAGS) $(CFLAGS) -showIncludes -Zs' + _DEPFLAGS='$(CPPFLAGS) -showIncludes -Zs' + _DEPCCFLAGS='$(CFLAGS)' + _DEPCXXFLAGS='$(CXXFLAGS)' _cflags_speed="-O2" _cflags_size="-O1" - _cflags_noopt="-O1" if $_cc -nologo- 2>&1 | grep -q Linker; then _ld_o='-out:$@' + _flags_filter=msvc_flags_link else _ld_o='-Fe$@' + _flags_filter=msvc_flags fi _cc_o='-Fo$@' _cc_e='-P -Fi$@' - _flags_filter=msvc_flags - _ld_lib='lib%.a' + _ld_lib='%.lib' _ld_path='-libpath:' _flags='-nologo' + _cxxflags='-Zc:__cplusplus -EHsc' disable stripping elif $_cc --version 2>/dev/null | grep -q ^cparser; then _type=cparser @@ -5126,11 +5418,11 @@ set_ccvars(){ eval ${1}_O=\${_cc_o-\${${1}_O}} if [ -n "$_depflags" ]; then - eval ${1}_DEPFLAGS=\$_depflags + eval "${1}_DEPFLAGS=\"\$_depflags\"" else - eval ${1}DEP=\${_DEPCMD:-\$DEPCMD} - eval ${1}DEP_FLAGS=\${_DEPFLAGS:-\$DEPFLAGS} - eval DEP${1}FLAGS=\$_flags + eval "${1}DEP=\"\${_DEPCMD:-\$DEPCMD}\"" + eval "${1}DEP_FLAGS=\"\${_DEPFLAGS:-\$DEPFLAGS} \${_DEP${1}FLAGS:-\$DEP${1}FLAGS}\"" + eval "DEP${1}FLAGS=\"\$_flags\"" fi } @@ -5140,6 +5432,7 @@ cflags_speed=$_cflags_speed cflags_size=$_cflags_size cflags_noopt=$_cflags_noopt add_cflags $_flags $_cflags +add_cxxflags $_flags $_cxxflags cc_ldflags=$_ldflags set_ccvars CC set_ccvars CXX @@ -5158,7 +5451,7 @@ test -n "$cc_type" && enable $cc_type || : ${dep_cc_default:=$cc} : ${ld_default:=$cc} : ${host_ld_default:=$host_cc} -set_default ar as objcc dep_cc ld ln_s host_ld windres +set_default ar as objcc dep_cc ld ln_s host_ld windres response_files probe_cc as "$as" asflags_filter=$_flags_filter @@ -5186,11 +5479,14 @@ HOSTLD_O=${_ld_o-$HOSTLD_O} if [ -z "$CC_DEPFLAGS" ] && [ "$dep_cc" != "$cc" ]; then probe_cc depcc "$dep_cc" CCDEP=${_DEPCMD:-$DEPCMD} + CXXDEP=${CCDEP} CCDEP_FLAGS=${_DEPFLAGS:=$DEPFLAGS} - DEPCCFLAGS=$_flags + CXXDEP_FLAGS=${CCDEP_FLAGS} + DEPCCFLAGS=$_flags $_cflags + DEPCXXFLAGS=$_flags $_cxxflags fi -if $ar 2>&1 | grep -q Microsoft; then +if VSLANG=1033 $ar 2>&1 | grep -q ^Microsoft; then arflags="-nologo" ar_o='-out:$@' elif $ar 2>&1 | grep -q "\[D\] "; then @@ -5201,6 +5497,12 @@ else ar_o='$@' fi +# Treat unrecognized flags as errors on MSVC +test_cpp_condition windows.h "_MSC_FULL_VER >= 193030705" && + check_cflags -options:strict +test_host_cpp_condition windows.h "_MSC_FULL_VER >= 193030705" && + check_host_cflags -options:strict + add_cflags $extra_cflags add_cxxflags $extra_cxxflags add_objcflags $extra_objcflags @@ -5222,6 +5524,7 @@ if test "$cpu" = host; then case "$cc_type" in gcc|llvm_gcc) check_native(){ + : > $TMPC $cc $1=native -v -c -o $TMPO $TMPC >$TMPE 2>&1 || return sed -n "/cc1.*$1=/{ s/.*$1=\\([^ ]*\\).*/\\1/ @@ -5233,6 +5536,7 @@ if test "$cpu" = host; then ;; clang) check_native(){ + : > $TMPC $cc $1=native -v -c -o $TMPO $TMPC >$TMPE 2>&1 || return sed -n "/cc1.*-target-cpu /{ s/.*-target-cpu \\([^ ]*\\).*/\\1/ @@ -5256,7 +5560,7 @@ case "$arch" in arm*|iPad*|iPhone*) arch="arm" ;; - loongarch*) + loongarch*|loong64) arch="loongarch" ;; mips*|IP*) @@ -5290,6 +5594,9 @@ case "$arch" in tilegx|tile-gx) arch="tilegx" ;; + wasm*) + arch="wasm" + ;; i[3-6]86*|i86pc|BePC|x86pc|x86_64|x86_32|amd64) arch="x86" ;; @@ -5374,11 +5681,10 @@ elif enabled arm; then ;; esac - test_cflags -mfp16-format=ieee && add_cflags -mfp16-format=ieee + check_allcflags -mfp16-format=ieee elif enabled loongarch; then - enable local_aligned enable simd_align_32 enable fast_64bit enable fast_clz @@ -5445,7 +5751,6 @@ elif enabled mips; then ;; # Cores from Loongson loongson2e|loongson2f|loongson3*) - enable local_aligned enable simd_align_16 enable fast_64bit enable fast_clz @@ -5528,7 +5833,7 @@ elif enabled ppc; then cpuflags="-mcpu=$cpu" disable vsx ;; - power[7-8]*) + power[7-9]*|power10) cpuflags="-mcpu=$cpu" ;; cell) @@ -5611,7 +5916,7 @@ else fi if [ "$cpu" != generic ]; then - add_cflags $cpuflags + add_allcflags $cpuflags add_asflags $cpuflags test "$cc_type" = "$ld_type" && add_ldflags $cpuflags fi @@ -5634,6 +5939,8 @@ add_cxxflags -D__STDC_CONSTANT_MACROS check_cxxflags_cc -std=$stdcxx ctype.h "__cplusplus >= 201103L" || { check_cxxflags -std=c++11 && stdcxx="c++11" || { check_cxxflags -std=c++0x && stdcxx="c++0x"; }; } +test_cxxflags_cc -std=$stdcxx ctype.h "__cplusplus >= 201703L" && enable cxx17 + # some compilers silently accept -std=c11, so we also need to check that the # version macro is defined properly check_cflags_cc -std=$stdc ctype.h "__STDC_VERSION__ >= 201112L" || @@ -5728,7 +6035,7 @@ case $target_os in android) disable symver enable section_data_rel_ro - add_cflags -fPIE + add_allcflags -fPIE add_ldexeflags -fPIE -pie SLIB_INSTALL_NAME='$(SLIBNAME)' SLIB_INSTALL_LINKS= @@ -5791,7 +6098,7 @@ case $target_os in enabled x86_32 && append SHFLAGS -Wl,-read_only_relocs,suppress strip="${strip} -x" add_ldflags -Wl,-dynamic,-search_paths_first - check_cflags -Werror=partial-availability + check_allcflags -Werror=partial-availability SLIBSUF=".dylib" SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME).$(LIBVERSION)$(SLIBSUF)' SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME).$(LIBMAJOR)$(SLIBSUF)' @@ -5809,7 +6116,7 @@ case $target_os in # Workaround for Xcode 11 -fstack-check bug if enabled clang; then clang_version=$($cc -dumpversion) - test ${clang_version%%.*} -eq 11 && add_cflags -fno-stack-check + test ${clang_version%%.*} -eq 11 && add_allcflags -fno-stack-check fi # Xcode Clang doesn't default to -fno-common while upstream llvm.org @@ -5880,27 +6187,31 @@ case $target_os in ;; win32|win64) disable symver + LIBSUF=".lib" if enabled shared; then - # Link to the import library instead of the normal static library - # for shared libs. - LD_LIB='%.lib' # Cannot build both shared and static libs with MSVC or icl. disable static + LIBSUF="-static.lib" fi ! enabled small && test_cmd $windres --version && enable gnu_windres enabled x86_32 && check_ldflags -LARGEADDRESSAWARE add_cppflags -DWIN32_LEAN_AND_MEAN shlibdir_default="$bindir_default" + LIBPREF="" SLIBPREF="" SLIBSUF=".dll" SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)' - SLIB_CREATE_DEF_CMD='EXTERN_PREFIX="$(EXTERN_PREFIX)" $(SRC_PATH)/compat/windows/makedef $(SUBDIR)lib$(NAME).ver $(OBJS) > $$(@:$(SLIBSUF)=.def)' + SLIB_CREATE_DEF_CMD='LDFLAGS="$(LDFLAGS)" EXTERN_PREFIX="$(EXTERN_PREFIX)" $(SRC_PATH)/compat/windows/makedef $(SUBDIR)lib$(NAME).ver $(OBJS) > $$(@:$(SLIBSUF)=.def)' SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)' SLIB_INSTALL_LINKS= SLIB_INSTALL_EXTRA_SHLIB='$(SLIBNAME:$(SLIBSUF)=.lib)' SLIB_INSTALL_EXTRA_LIB='$(SLIBNAME_WITH_MAJOR:$(SLIBSUF)=.def)' - SHFLAGS='-dll -def:$$(@:$(SLIBSUF)=.def) -implib:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' + if test $ld_type = "clang"; then + SHFLAGS='-Wl,-dll -Wl,-def:$$(@:$(SLIBSUF)=.def) -Wl,-implib:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' + else + SHFLAGS='-dll -def:$$(@:$(SLIBSUF)=.def) -implib:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' + fi enabled x86_64 && objformat="win64" || objformat="win32" ranlib=: enable dos_paths @@ -6025,17 +6336,19 @@ probe_libc(){ # MinGW headers can be installed on Cygwin, so check for newlib first. elif test_${pfx}cpp_condition newlib.h "defined _NEWLIB_VERSION"; then eval ${pfx}libc_type=newlib - add_${pfx}cppflags -U__STRICT_ANSI__ -D_XOPEN_SOURCE=600 + add_${pfx}cflags -U__STRICT_ANSI__ + add_${pfx}cppflags -D_XOPEN_SOURCE=600 # MinGW64 is backwards compatible with MinGW32, so check for it first. elif test_${pfx}cpp_condition _mingw.h "defined __MINGW64_VERSION_MAJOR"; then eval ${pfx}libc_type=mingw64 if test_${pfx}cpp_condition _mingw.h "__MINGW64_VERSION_MAJOR < 3"; then add_compat msvcrt/snprintf.o - add_cflags "-include $source_path/compat/msvcrt/snprintf.h" + add_allcflags "-include $source_path/compat/msvcrt/snprintf.h" + fi + add_${pfx}cflags -U__STRICT_ANSI__ + if ! test_${pfx}cpp_condition crtdefs.h "defined(_UCRT)"; then + add_${pfx}cppflags -D__USE_MINGW_ANSI_STDIO=1 fi - add_${pfx}cppflags -U__STRICT_ANSI__ -D__USE_MINGW_ANSI_STDIO=1 - eval test \$${pfx_no_}cc_type = "gcc" && - add_${pfx}cppflags -D__printf__=__gnu_printf__ test_${pfx}cpp_condition windows.h "!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600" && add_${pfx}cppflags -D_WIN32_WINNT=0x0600 add_${pfx}cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 @@ -6045,13 +6358,14 @@ probe_libc(){ test_${pfx}cpp_condition _mingw.h "__MINGW32_MAJOR_VERSION > 3 || \ (__MINGW32_MAJOR_VERSION == 3 && __MINGW32_MINOR_VERSION >= 15)" || die "ERROR: MinGW32 runtime version must be >= 3.15." - add_${pfx}cppflags -U__STRICT_ANSI__ -D__USE_MINGW_ANSI_STDIO=1 + add_${pfx}cflags -U__STRICT_ANSI__ + if ! test_${pfx}cpp_condition crtdefs.h "defined(_UCRT)"; then + add_${pfx}cppflags -D__USE_MINGW_ANSI_STDIO=1 + fi test_${pfx}cpp_condition _mingw.h "__MSVCRT_VERSION__ < 0x0700" && add_${pfx}cppflags -D__MSVCRT_VERSION__=0x0700 test_${pfx}cpp_condition windows.h "!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600" && add_${pfx}cppflags -D_WIN32_WINNT=0x0600 - eval test \$${pfx_no_}cc_type = "gcc" && - add_${pfx}cppflags -D__printf__=__gnu_printf__ add_${pfx}cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 elif test_${pfx}cpp_condition crtversion.h "defined _VC_CRT_MAJOR_VERSION"; then eval ${pfx}libc_type=msvcrt @@ -6086,8 +6400,8 @@ probe_libc(){ #endif EOF if [ "$pfx" = "" ]; then - check_func strtoll || add_cflags -Dstrtoll=_strtoi64 - check_func strtoull || add_cflags -Dstrtoull=_strtoui64 + check_func strtoll || add_allcflags -Dstrtoll=_strtoi64 + check_func strtoull || add_allcflags -Dstrtoull=_strtoui64 fi elif test_${pfx}cpp_condition stddef.h "defined __KLIBC__"; then eval ${pfx}libc_type=klibc @@ -6099,7 +6413,7 @@ EOF elif test_${pfx}cpp_condition sys/version.h "defined __DJGPP__"; then eval ${pfx}libc_type=djgpp add_cppflags -U__STRICT_ANSI__ - add_cflags "-include $source_path/compat/djgpp/math.h" + add_allcflags "-include $source_path/compat/djgpp/math.h" add_compat djgpp/math.o fi test_${pfx}cc <= 3 && AVS_MINOR_VER >= 7 && AVS_BUGFIX_VER >= 3 || AVS_MAJOR_VER >= 3 && AVS_MINOR_VER > 7 || AVS_MAJOR_VER > 3" || die "ERROR: AviSynth+ header version must be >= 3.7.3"; } } +enabled cairo && require_pkg_config cairo cairo "cairo.h" cairo_create enabled cuda_nvcc && { check_nvcc cuda_nvcc || die "ERROR: failed checking for nvcc."; } enabled chromaprint && { check_pkg_config chromaprint libchromaprint "chromaprint.h" chromaprint_get_version || require chromaprint chromaprint.h chromaprint_get_version -lchromaprint; } @@ -6887,6 +7233,7 @@ enabled jni && { [ $target_os = "android" ] && check_headers jni.h enabled ladspa && require_headers "ladspa.h dlfcn.h" enabled lcms2 && require_pkg_config lcms2 "lcms2 >= 2.13" lcms2.h cmsCreateContext enabled libaom && require_pkg_config libaom "aom >= 2.0.0" aom/aom_codec.h aom_codec_version +enabled liboapv && require_pkg_config liboapv "oapv >= 0.2.0.0" "oapv/oapv.h" oapve_encode enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "aribb24/aribb24.h" arib_instance_new || { enabled gpl && require_pkg_config libaribb24 aribb24 "aribb24/aribb24.h" arib_instance_new; } || die "ERROR: libaribb24 requires version higher than 1.0.3 or --enable-gpl."; } @@ -6901,7 +7248,7 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 && die "ERROR: libcelt must be installed and version must be >= 0.11.0."; } enabled libcaca && require_pkg_config libcaca caca caca.h caca_create_canvas enabled libcodec2 && require libcodec2 codec2/codec2.h codec2_create -lcodec2 -enabled libdav1d && require_pkg_config libdav1d "dav1d >= 0.5.0" "dav1d/dav1d.h" dav1d_version +enabled libdav1d && require_pkg_config libdav1d "dav1d >= 1.0.0" "dav1d/dav1d.h" dav1d_version enabled libdavs2 && require_pkg_config libdavs2 "davs2 >= 1.6.0" davs2.h davs2_decoder_open enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new enabled libdrm && check_pkg_config libdrm libdrm xf86drm.h drmGetVersion @@ -6920,12 +7267,12 @@ enabled libharfbuzz && require_pkg_config libharfbuzz harfbuzz hb.h hb_buf if enabled libglslang; then spvremap="-lSPVRemapper" require_headers "glslang/build_info.h" && { test_cpp_condition glslang/build_info.h "GLSLANG_VERSION_MAJOR >= 16" && spvremap="" ; } - check_lib spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \ + check_lib spirv_library glslang/Include/glslang_c_interface.h glslang_initialize_process \ -lglslang -lMachineIndependent -lGenericCodeGen \ - ${spvremap} -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm || - require spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \ + ${spvremap} -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lstdc++ $libm_extralibs $pthreads_extralibs || + require spirv_library glslang/Include/glslang_c_interface.h glslang_initialize_process \ -lglslang -lMachineIndependent -lOSDependent -lHLSL -lOGLCompiler -lGenericCodeGen \ - ${spvremap} -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm ; + ${spvremap} -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lstdc++ $libm_extralibs $pthreads_extralibs ; fi enabled libgme && { check_pkg_config libgme libgme gme/gme.h gme_new_emu || require libgme gme/gme.h gme_new_emu -lgme -lstdc++; } @@ -6939,7 +7286,7 @@ enabled libklvanc && require libklvanc libklvanc/vanc.h klvanc_context_c enabled libkvazaar && require_pkg_config libkvazaar "kvazaar >= 2.0.0" kvazaar.h kvz_api_get enabled liblc3 && require_pkg_config liblc3 "lc3 >= 1.1.0" lc3.h lc3_hr_setup_encoder enabled liblensfun && require_pkg_config liblensfun lensfun lensfun.h lf_db_create -enabled liblcevc_dec && require_pkg_config liblcevc_dec "lcevc_dec >= 2.0.0" "LCEVC/lcevc_dec.h" LCEVC_CreateDecoder +enabled liblcevc_dec && require_pkg_config liblcevc_dec "lcevc_dec >= 4.0.0" "LCEVC/lcevc_dec.h" LCEVC_CreateDecoder if enabled libmfx && enabled libvpl; then die "ERROR: can not use libmfx and libvpl together" @@ -6955,7 +7302,7 @@ elif enabled libmfx; then # includedir=/usr/include # Cflags: -I${includedir} # So add -I${includedir}/mfx to CFLAGS - { check_pkg_config libmfx "libmfx >= 1.28 libmfx < 2.0" "mfx/mfxvideo.h" MFXInit && add_cflags -I${libmfx_incdir}/mfx; } || + { check_pkg_config libmfx "libmfx >= 1.28 libmfx < 2.0" "mfx/mfxvideo.h" MFXInit && add_cppflags -I${libmfx_incdir}/mfx; } || { require libmfx "mfxvideo.h mfxdefs.h" MFXInit "-llibmfx $advapi32_extralibs" && { test_cpp_condition mfxdefs.h "MFX_VERSION >= 1028 && MFX_VERSION < 2000" || die "ERROR: libmfx version must be >= 1.28 and < 2.0"; } && warn "using libmfx without pkg-config"; } } && @@ -6966,7 +7313,7 @@ elif enabled libvpl; then # is extracted from "vpl >= 2.6" check_pkg_config libmfx "vpl >= 2.6" "mfxvideo.h mfxdispatcher.h" MFXLoad || \ die "ERROR: libvpl >= 2.6 not found" - add_cflags -DMFX_DEPRECATED_OFF + add_cppflags -DMFX_DEPRECATED_OFF check_type "vpl/mfxdefs.h vpl/mfxvideo.h" "struct mfxConfigInterface" fi @@ -6976,17 +7323,23 @@ fi enabled libmodplug && require_pkg_config libmodplug libmodplug libmodplug/modplug.h ModPlug_Load enabled libmp3lame && require "libmp3lame >= 3.98.3" lame/lame.h lame_set_VBR_quality -lmp3lame $libm_extralibs +enabled libmpeghdec && require_pkg_config libmpeghdec "mpeghdec >= 3.0.0" mpeghdec/mpeghdecoder.h mpeghdecoder_init enabled libmysofa && { check_pkg_config libmysofa libmysofa mysofa.h mysofa_neighborhood_init_withstepdefine || require libmysofa mysofa.h mysofa_neighborhood_init_withstepdefine -lmysofa $zlib_extralibs; } -enabled libnpp && { check_lib libnpp npp.h nppGetLibVersion -lnppig -lnppicc -lnppc -lnppidei -lnppif || +enabled libnpp && { test_cpp_condition "$(cd "$source_path"; pwd)/libavfilter/version_major.h" FF_API_LIBNPP_SUPPORT || + die "ERROR: libnpp support is removed in this version"; } && + { check_lib libnpp npp.h nppGetLibVersion -lnppig -lnppicc -lnppc -lnppidei -lnppif || check_lib libnpp npp.h nppGetLibVersion -lnppi -lnppif -lnppc -lnppidei || - die "ERROR: libnpp not found"; } -enabled libopencore_amrnb && require libopencore_amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init -lopencore-amrnb -enabled libopencore_amrwb && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb -enabled libopencv && { check_headers opencv2/core/core_c.h && - { check_pkg_config libopencv opencv opencv2/core/core_c.h cvCreateImageHeader || - require libopencv opencv2/core/core_c.h cvCreateImageHeader -lopencv_core -lopencv_imgproc; } || - require_pkg_config libopencv opencv opencv/cxcore.h cvCreateImageHeader; } + die "ERROR: libnpp not found"; } && + { check_func_headers "nppi.h" nppiYCbCr420_8u_P2P3R $libnpp_extralibs || + die "ERROR: libnpp support is deprecated, version 13.0 and up are not supported"; } +enabled libopencore_amrnb && { check_pkg_config libopencore_amrnb opencore-amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init || + require libopencore_amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init -lopencore-amrnb; } +enabled libopencore_amrwb && { check_pkg_config libopencore_amrwb opencore-amrwb opencore-amrwb/dec_if.h D_IF_init || + require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb; } +enabled libopencv && { check_pkg_config libopencv opencv4 opencv2/core/core_c.h cvCreateImageHeader || + require libopencv opencv2/core/core_c.h cvCreateImageHeader -lopencv_core -lopencv_imgproc; } +enabled libopencolorio && require_pkg_config_cxx libopencolorio "OpenColorIO" OpenColorIO/OpenColorIO.h OCIO_NAMESPACE::Config enabled libopenh264 && require_pkg_config libopenh264 "openh264 >= 1.3.0" wels/codec_api.h WelsGetCodecVersion enabled libopenjpeg && { check_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version || { require_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } } @@ -7002,7 +7355,7 @@ enabled libopus && { require_pkg_config libopus opus opus_multistream.h opus_multistream_surround_encoder_create } } -enabled libplacebo && require_pkg_config libplacebo "libplacebo >= 4.192.0" libplacebo/vulkan.h pl_vulkan_create +enabled libplacebo && require_pkg_config libplacebo "libplacebo >= 5.229.0" libplacebo/vulkan.h pl_vulkan_create enabled libpulse && require_pkg_config libpulse libpulse pulse/pulseaudio.h pa_context_new enabled libqrencode && require_pkg_config libqrencode libqrencode qrencode.h QRcode_encodeString enabled libquirc && require libquirc quirc.h quirc_decode -lquirc @@ -7012,7 +7365,7 @@ enabled librist && require_pkg_config librist "librist >= 0.2.7" libri enabled librsvg && require_pkg_config librsvg librsvg-2.0 librsvg-2.0/librsvg/rsvg.h rsvg_handle_new_from_data enabled librtmp && require_pkg_config librtmp librtmp librtmp/rtmp.h RTMP_Socket enabled librubberband && require_pkg_config librubberband "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new -lstdc++ && append librubberband_extralibs "-lstdc++" -enabled libshaderc && require_pkg_config spirv_compiler "shaderc >= 2019.1" shaderc/shaderc.h shaderc_compiler_initialize +enabled libshaderc && require_pkg_config spirv_library "shaderc >= 2019.1" shaderc/shaderc.h shaderc_compiler_initialize enabled libshine && require_pkg_config libshine shine shine/layer3.h shine_encode_buffer enabled libsmbclient && { check_pkg_config libsmbclient smbclient libsmbclient.h smbc_init || require libsmbclient libsmbclient.h smbc_init -lsmbclient; } @@ -7022,11 +7375,13 @@ enabled libssh && require_pkg_config libssh "libssh >= 0.6.0" libssh/ enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init enabled libsrt && require_pkg_config libsrt "srt >= 1.3.0" srt/srt.h srt_socket enabled libsvtav1 && require_pkg_config libsvtav1 "SvtAv1Enc >= 0.9.0" EbSvtAv1Enc.h svt_av1_enc_init_handle +enabled libsvtjpegxs && require_pkg_config libsvtjpegxs "SvtJpegxs >= 0.10.0" SvtJpegxsEnc.h svt_jpeg_xs_encoder_init enabled libtensorflow && require libtensorflow tensorflow/c/c_api.h TF_Version -ltensorflow enabled libtesseract && require_pkg_config libtesseract tesseract tesseract/capi.h TessBaseAPICreate enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg -enabled libtls && require_pkg_config libtls libtls tls.h tls_configure -enabled libtorch && check_cxxflags -std=c++17 && require_cpp libtorch torch/torch.h "torch::Tensor" -ltorch -lc10 -ltorch_cpu -lstdc++ -lpthread +enabled libtls && require_pkg_config libtls libtls tls.h tls_configure && + { enabled gpl && ! enabled nonfree && die "ERROR: LibreSSL is incompatible with the gpl"; } +enabled libtorch && check_cxxflags -std=c++17 && require_cxx libtorch torch/torch.h "torch::Tensor" -ltorch -lc10 -ltorch_cpu -lstdc++ -lpthread enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame && { check_lib libtwolame twolame.h twolame_encode_buffer_float32_interleaved -ltwolame || die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; } @@ -7035,10 +7390,13 @@ enabled libv4l2 && require_pkg_config libv4l2 libv4l2 libv4l2.h v4l2_i enabled libvidstab && require_pkg_config libvidstab "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 2.0.0" libvmaf.h vmaf_init enabled libvmaf && check_pkg_config libvmaf_cuda "libvmaf >= 2.0.0" libvmaf_cuda.h vmaf_cuda_state_init -enabled libvo_amrwbenc && require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_init -lvo-amrwbenc +enabled libvo_amrwbenc && { check_pkg_config libvo_amrwbenc vo-amrwbenc vo-amrwbenc/enc_if.h E_IF_init || + require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_init -lvo-amrwbenc; } enabled libvorbis && require_pkg_config libvorbis vorbis vorbis/codec.h vorbis_info_init && require_pkg_config libvorbisenc vorbisenc vorbis/vorbisenc.h vorbis_encode_init +enabled whisper && require_pkg_config whisper "whisper >= 1.7.5" whisper.h whisper_init_from_file_with_params + enabled libvpx && { enabled libvpx_vp8_decoder && { check_pkg_config libvpx_vp8_decoder "vpx >= 1.4.0" "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_vp8_dx || @@ -7076,7 +7434,9 @@ enabled libx265 && require_pkg_config libx265 x265 x265.h x265_api_get enabled libxavs && require libxavs "stdint.h xavs.h" xavs_encoder_encode "-lxavs $pthreads_extralibs $libm_extralibs" enabled libxavs2 && require_pkg_config libxavs2 "xavs2 >= 1.3.0" "stdint.h xavs2.h" xavs2_api_get enabled libxevd && require_pkg_config libxevd "xevd >= 0.4.1" "xevd.h" xevd_decode +enabled libxevdb && require_pkg_config libxevdb "xevdb >= 0.4.1" "xevd.h" xevd_decode enabled libxeve && require_pkg_config libxeve "xeve >= 0.5.1" "xeve.h" xeve_encode +enabled libxeveb && require_pkg_config libxeveb "xeveb >= 0.5.1" "xeve.h" xeve_encode enabled libxvid && require libxvid xvid.h xvid_global -lxvidcore enabled libzimg && require_pkg_config libzimg "zimg >= 2.7.0" zimg.h zimg_get_api_version enabled libzmq && require_pkg_config libzmq "libzmq >= 4.2.1" zmq.h zmq_ctx_new @@ -7088,7 +7448,8 @@ enabled mbedtls && { check_pkg_config mbedtls mbedtls mbedtls/x509_crt check_pkg_config mbedtls mbedtls mbedtls/ssl.h mbedtls_ssl_init || check_lib mbedtls mbedtls/ssl.h mbedtls_ssl_init -lmbedtls -lmbedx509 -lmbedcrypto || die "ERROR: mbedTLS not found"; } -enabled mediacodec && { enabled jni || die "ERROR: mediacodec requires --enable-jni"; } +enabled mediacodec && { enabled jni || die "ERROR: mediacodec requires --enable-jni"; } && + add_compat android/binder.o enabled mmal && { check_lib mmal interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host || { ! enabled cross_compile && add_cflags -isystem/opt/vc/include/ -isystem/opt/vc/include/interface/vmcs_host/linux -isystem/opt/vc/include/interface/vcos/pthreads -fgnu89-inline && @@ -7096,6 +7457,10 @@ enabled mmal && { check_lib mmal interface/mmal/mmal.h mmal_port_co check_lib mmal interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host; } || die "ERROR: mmal not found" && check_func_headers interface/mmal/mmal.h "MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS"; } +enabled ohcodec && { check_lib ohcodec "multimedia/player_framework/native_avcodec_videodecoder.h multimedia/player_framework/native_avcodec_videoencoder.h" \ + "OH_VideoDecoder_CreateByName OH_VideoEncoder_CreateByName" \ + -lnative_media_vdec -lnative_media_venc -lnative_media_codecbase -lnative_media_core -lnative_window || + die "ERROR: missing native_media libs"; } enabled openal && { check_pkg_config openal "openal >= 1.1" "AL/al.h" alGetError || { for al_extralibs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do check_lib openal 'AL/al.h' alGetError "${al_extralibs}" && break; done } || @@ -7121,26 +7486,23 @@ enabled omx_rpi && { test_code cc OMX_Core.h OMX_IndexConfigBrcmVideoR test_code cc OMX_Core.h OMX_IndexConfigBrcmVideoRequestIFrame; } || die "ERROR: OpenMAX IL headers from raspberrypi/firmware not found"; } && enable omx -enabled omx && require_headers OMX_Core.h -enabled openssl && { { check_pkg_config openssl "openssl >= 3.0.0" openssl/ssl.h OPENSSL_init_ssl && +enabled omx && require_headers OMX_Core.h && \ + warn "The OpenMAX encoders are deprecated and will be removed in future versions" + +enabled openssl && { { check_pkg_config openssl "openssl >= 3.0.0" openssl/ssl.h DTLS_get_data_mtu && { enabled gplv3 || ! enabled gpl || enabled nonfree || die "ERROR: OpenSSL >=3.0.0 requires --enable-version3"; }; } || { enabled gpl && ! enabled nonfree && die "ERROR: OpenSSL <3.0.0 is incompatible with the gpl"; } || - check_pkg_config openssl openssl openssl/ssl.h OPENSSL_init_ssl || - check_pkg_config openssl openssl openssl/ssl.h SSL_library_init || - check_lib openssl openssl/ssl.h OPENSSL_init_ssl -lssl -lcrypto || - check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto || - check_lib openssl openssl/ssl.h SSL_library_init -lssl32 -leay32 || - check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 || - die "ERROR: openssl not found"; } + check_pkg_config openssl "openssl >= 1.1.1" openssl/ssl.h DTLS_get_data_mtu || + check_lib openssl openssl/ssl.h DTLS_get_data_mtu -lssl -lcrypto || + check_lib openssl openssl/ssl.h DTLS_get_data_mtu -lssl -lcrypto -lws2_32 -lgdi32 || + die "ERROR: openssl (>= 1.1.1) not found"; } enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init -enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create && - require_pkg_config rockchip_mpp "rockchip_mpp >= 1.3.7" rockchip/rk_mpi.h mpp_create && +enabled rkmpp && { require_pkg_config rkmpp "rockchip_mpp >= 1.3.8" "rockchip/rk_mpi.h rockchip/mpp_buffer.h" "mpp_create mpp_buffer_sync_begin_f" && { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } enabled vapoursynth && require_headers "vapoursynth/VSScript4.h vapoursynth/VapourSynth4.h" - if enabled gcrypt; then GCRYPT_CONFIG="${cross_prefix}libgcrypt-config" if "${GCRYPT_CONFIG}" --version > /dev/null 2>&1; then @@ -7173,8 +7535,8 @@ fi if enabled decklink; then case $target_os in mingw32*|mingw64*|win32|win64) - decklink_outdev_extralibs="$decklink_outdev_extralibs -lole32 -loleaut32" - decklink_indev_extralibs="$decklink_indev_extralibs -lole32 -loleaut32" + decklink_outdev_extralibs="$decklink_outdev_extralibs -lole32 -luuid -loleaut32" + decklink_indev_extralibs="$decklink_indev_extralibs -lole32 -luuid -loleaut32" ;; esac fi @@ -7189,10 +7551,14 @@ enabled securetransport && enabled schannel && check_func_headers "windows.h security.h" InitializeSecurityContext -DSECURITY_WIN32 -lsecur32 && + check_func_headers "windows.h ncrypt.h" NCryptOpenStorageProvider -DSECURITY_WIN32 -lncrypt && + check_func_headers "windows.h wincrypt.h" CertCreateSelfSignCertificate -DSECURITY_WIN32 -lcrypt32 && test_cpp_condition winerror.h "defined(SEC_I_CONTEXT_EXPIRED)" && - schannel_extralibs="-lsecur32" || + schannel_extralibs="-lsecur32 -lncrypt -lcrypt32" || disable schannel +enabled schannel && check_cc dtls_protocol "windows.h security.h schnlsp.h" "int i = SECPKG_ATTR_DTLS_MTU;" -DSECURITY_WIN32 + makeinfo --version > /dev/null 2>&1 && enable makeinfo || disable makeinfo enabled makeinfo \ && [ 0$(makeinfo --version | grep "texinfo" | sed 's/.*texinfo[^0-9]*\([0-9]*\)\..*/\1/') -ge 5 ] \ @@ -7206,7 +7572,7 @@ xmllint --version > /dev/null 2>&1 && enable xmllint || disable xmllint check_headers linux/fb.h check_headers linux/videodev2.h test_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete -test_code cc sys/ioctl.h "int ioctl(int, int, ...)" && enable posix_ioctl +test_code cc sys/ioctl.h "int ioctl(int, int, ...)" && enable ioctl_posix # check V4L2 codecs available in the API if enabled v4l2_m2m; then @@ -7233,12 +7599,6 @@ check_cpp_condition vfwcap_defines vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" check_type "dshow.h" IBaseFilter -# check for ioctl_meteor.h, ioctl_bt848.h and alternatives -check_headers "dev/bktr/ioctl_meteor.h dev/bktr/ioctl_bt848.h" || - check_headers "machine/ioctl_meteor.h machine/ioctl_bt848.h" || - check_headers "dev/video/meteor/ioctl_meteor.h dev/video/bktr/ioctl_bt848.h" || - check_headers "dev/ic/bt8xx.h" - if check_struct sys/soundcard.h audio_buf_info bytes; then enable_sanitized sys/soundcard.h else @@ -7324,6 +7684,7 @@ if enabled vaapi; then check_cpp_condition vaapi_1 "va/va.h" "VA_CHECK_VERSION(1, 0, 0)" check_type "va/va.h va/va_dec_hevc.h" "VAPictureParameterBufferHEVC" + check_type "va/va.h va/va_dec_vvc.h" "VAPictureParameterBufferVVC" check_struct "va/va.h" "VADecPictureParameterBufferVP9" bit_depth check_struct "va/va.h" "VADecPictureParameterBufferAV1" bit_depth_idx check_type "va/va.h va/va_vpp.h" "VAProcFilterParameterBufferHDRToneMapping" @@ -7373,13 +7734,62 @@ enabled vdpau && enabled vdpau && check_lib vdpau_x11 "vdpau/vdpau.h vdpau/vdpau_x11.h" vdp_device_create_x11 -lvdpau -lX11 -if enabled vulkan; then +# Check for the Vulkan headers +if enabled_all vulkan vulkan_static; then + check_pkg_config vulkan "vulkan >= 1.3.277" "vulkan/vulkan.h" "defined VK_VERSION_1_3" || + check_lib vulkan "vulkan/vulkan.h" vkGetInstanceProcAddr -lvulkan +elif enabled vulkan; then check_pkg_config_header_only vulkan "vulkan >= 1.3.277" "vulkan/vulkan.h" "defined VK_VERSION_1_3" || - check_cpp_condition vulkan "vulkan/vulkan.h" "defined(VK_VERSION_1_4) || (defined(VK_VERSION_1_3) && VK_HEADER_VERSION >= 277)" + check_cpp_condition vulkan "vulkan/vulkan.h" "defined(VK_VERSION_1_4) || (defined(VK_VERSION_1_3) && VK_HEADER_VERSION >= 277)" $vulkan_incflags fi -if disabled vulkan; then - disable libglslang libshaderc spirv_compiler +probe_glslc(){ + glslc_probe=$1 + if test_cmd $glslc_probe -v; then + # glslang/glslangValidator + glslc=$glslc_probe + glslcflags="-V --target-env spirv1.6 --glsl-version 460" + glslc_opt_speed="" + glslc_opt_size="-Os" + glslc_opt_none="-Od" + glslc_debug="-gVS" + GLSLC_DEPFLAGS='--depfile $(@:.spv=.d)' + elif test_cmd $glslc_probe --version; then + # glslc + glslc=$glslc_probe + glslcflags="--target-env=vulkan1.4 --target-spv=spv1.6 -std=460" + glslc_opt_speed="-O" + glslc_opt_size="-Os" + glslc_opt_none="-O0" + glslc_debug="-g" + GLSLC_DEPFLAGS='-MD -MF $(@:.spv=.d) -MT $@' + else + disable spirv_compiler + return 1 + fi + check_glslc spirv_compiler || return 0 + + append GLSLCFLAGS $glslcflags + if enabled small; then + append GLSLCFLAGS $glslc_opt_size + elif enabled optimizations; then + append GLSLCFLAGS $glslc_opt_speed + else + append GLSLCFLAGS $glslc_opt_none + fi + if enabled debug; then + append GLSLCFLAGS $glslc_debug + fi +} + +if enabled vulkan; then + check_pkg_config_header_only vulkan_1_4 "vulkan >= 1.4.317" "vulkan/vulkan.h" "defined VK_VERSION_1_4" || + check_cpp_condition vulkan_1_4 "vulkan/vulkan.h" "defined(VK_VERSION_1_5) || (defined(VK_VERSION_1_4) && VK_HEADER_VERSION >= 317)" $vulkan_incflags + for program in $glslc glslc glslang glslangValidator; do + probe_glslc $program && break + done +else + disable libglslang libshaderc spirv_library spirv_compiler fi if enabled x86; then @@ -7422,7 +7832,7 @@ fi enabled amf && check_cpp_condition amf "AMF/core/Version.h" \ - "(AMF_VERSION_MAJOR << 48 | AMF_VERSION_MINOR << 32 | AMF_VERSION_RELEASE << 16 | AMF_VERSION_BUILD_NUM) >= 0x0001000400210000" + "(AMF_VERSION_MAJOR << 48 | AMF_VERSION_MINOR << 32 | AMF_VERSION_RELEASE << 16 | AMF_VERSION_BUILD_NUM) >= 0x0001000400240000" # Funny iconv installations are not unusual, so check it after all flags have been set if enabled libc_iconv; then @@ -7431,36 +7841,55 @@ elif enabled iconv; then check_func_headers iconv.h iconv || check_lib iconv iconv.h iconv -liconv fi -enabled debug && add_cflags -g"$debuglevel" && add_asflags -g"$debuglevel" +enabled debug && add_allcflags -g"$debuglevel" && add_asflags -g"$debuglevel" -# add some useful compiler flags if supported -check_cflags -Wdeclaration-after-statement -check_cflags -Wall -check_cflags -Wdisabled-optimization -check_cflags -Wpointer-arith -check_cflags -Wredundant-decls -check_cflags -Wwrite-strings -check_cflags -Wtype-limits -check_cflags -Wundef -check_cflags -Wmissing-prototypes -check_cflags -Wstrict-prototypes -check_cflags -Wempty-body +for lang in c cxx objc; do + test_${lang}flags -Werror=unused-command-line-argument && + append unknown_warning_${lang}flags "-Werror=unused-command-line-argument" + test_${lang}flags -Werror=unknown-warning-option && + append unknown_warning_${lang}flags "-Werror=unknown-warning-option" +done -if enabled extra_warnings; then - check_cflags -Wcast-qual - check_cflags -Wextra - check_cflags -Wpedantic -fi +check_warning(){ + warning_flag=$1 + flag_to_add=${2:-$1} + test_cflags $unknown_warning_cflags $warning_flag && add_cflags $flag_to_add + test_cxxflags -Werror $unknown_warning_cxxflags $warning_flag && add_cxxflags $flag_to_add + test_objcflags $unknown_warning_objcflags $warning_flag && add_objcflags $flag_to_add +} check_disable_warning(){ warning_flag=-W${1#-Wno-} - test_cflags $unknown_warning_flags $warning_flag && add_cflags $1 + check_warning $warning_flag $1 } -test_cflags -Werror=unused-command-line-argument && - append unknown_warning_flags "-Werror=unused-command-line-argument" -test_cflags -Werror=unknown-warning-option && - append unknown_warning_flags "-Werror=unknown-warning-option" +check_c_warning(){ + warning_flag=$1 + test_cflags $unknown_warning_cflags $warning_flag && add_cflags $warning_flag +} + +# add some useful compiler flags if supported +check_warning -Wall +check_warning -Wdisabled-optimization +check_warning -Wpointer-arith +check_warning -Wredundant-decls +check_warning -Wwrite-strings +check_warning -Wtype-limits +check_warning -Wundef +check_warning -Wempty-body +# Warn about excessive stack usage, using a 120 KiB per-function threshold. +# This roughly matches the default thread stack size on Musl, which is 128 KiB, +# leaving some headroom for caller frames. +check_warning -Wstack-usage=122880 +check_c_warning -Wmissing-prototypes +check_c_warning -Wstrict-prototypes +check_c_warning -Wunterminated-string-initialization + +if enabled extra_warnings; then + check_warning -Wcast-qual + check_warning -Wextra + check_warning -Wpedantic +fi check_disable_warning -Wno-parentheses check_disable_warning -Wno-switch @@ -7469,10 +7898,12 @@ check_disable_warning -Wno-pointer-sign check_disable_warning -Wno-unused-const-variable check_disable_warning -Wno-bool-operation check_disable_warning -Wno-char-subscripts +check_disable_warning -Wno-implicit-const-int-float-conversion +check_disable_warning -Wno-microsoft-enum-forward-reference check_disable_warning_headers(){ warning_flag=-W${1#-Wno-} - test_cflags $warning_flag && add_cflags_headers $1 + test_cflags $unknown_warning_cflags $warning_flag && add_cflags_headers $1 } check_disable_warning_headers -Wno-deprecated-declarations @@ -7483,7 +7914,7 @@ void (^block)(void); EOF # add some linker flags -check_ldflags -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil +check_ldflags -Wl,-rpath-link=:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil enabled rpath && add_ldexeflags -Wl,-rpath,$libdir && add_ldsoflags -Wl,-rpath,$libdir test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic @@ -7546,7 +7977,7 @@ if [ -z "$optflags" ]; then fi check_optflags(){ - check_cflags "$@" + check_allcflags "$@" [ -n "$lto" ] && check_ldflags "$@" } @@ -7580,7 +8011,7 @@ EOF if enabled icc; then # Just warnings, no remarks - check_cflags -w1 + check_allcflags -w1 # -wd: Disable following warnings # 144, 167, 556: -Wno-pointer-sign # 188: enumerated type mixed with another type @@ -7591,7 +8022,7 @@ if enabled icc; then # 10156: ignoring option '-W'; no argument required # 13200: No EMMS instruction before call to function # 13203: No EMMS instruction before return from function - check_cflags -wd144,167,188,556,1292,1419,10006,10148,10156,13200,13203 + check_allcflags -wd144,167,188,556,1292,1419,10006,10148,10156,13200,13203 # 11030: Warning unknown option --as-needed # 10156: ignoring option '-export'; no argument required check_ldflags -wd10156,11030 @@ -7602,18 +8033,36 @@ if enabled icc; then if enabled x86_32; then icc_version=$($cc -dumpversion) test ${icc_version%%.*} -ge 11 && - check_cflags -falign-stack=maintain-16-byte || + check_cppflags -falign-stack=maintain-16-byte || disable aligned_stack fi elif enabled gcc; then - check_optflags -fno-tree-vectorize - check_cflags -Werror=format-security + gcc_version=$($cc -dumpversion) + major_version=${gcc_version%%[!0-9]*} + if [ $major_version -lt 13 ]; then + # Disable tree-vectorize for GCC <13 - it has historically been buggy. + check_optflags -fno-tree-vectorize + else + case $arch in + x86|arm|aarch64) + # Allow the default of having tree-vectorize enabled on well tested + # architectures. + ;; + *) + # Disable tree-vectorize on potentially less tested + # architectures. Known issues: + # - https://gcc.gnu.org/PR121064 on Loongarch + check_optflags -fno-tree-vectorize + ;; + esac + fi check_cflags -Werror=implicit-function-declaration check_cflags -Werror=missing-prototypes - check_cflags -Werror=return-type - check_cflags -Werror=vla - check_cflags -Wformat - check_cflags -fdiagnostics-color=auto + check_allcflags -Werror=format-security + check_allcflags -Werror=return-type + check_allcflags -Werror=vla + check_allcflags -Wformat + check_allcflags -fdiagnostics-color=auto enabled extra_warnings || check_disable_warning -Wno-maybe-uninitialized if enabled x86_32; then case $target_os in @@ -7622,12 +8071,12 @@ elif enabled gcc; then # request GCC to try to maintain 16 byte alignment throughout # function calls. Library entry points that might call assembly # functions align the stack. (The parameter means 2^4 bytes.) - check_cflags -mpreferred-stack-boundary=4 + check_allcflags -mpreferred-stack-boundary=4 ;; esac fi elif enabled llvm_gcc; then - check_cflags -mllvm -stack-alignment=16 + check_allcflags -mllvm -stack-alignment=16 elif enabled clang; then if enabled x86_32; then # Clang doesn't support maintaining alignment without assuming the @@ -7640,18 +8089,18 @@ elif enabled clang; then disable aligned_stack ;; *) - check_cflags -mllvm -stack-alignment=16 - check_cflags -mstack-alignment=16 + check_allcflags -mllvm -stack-alignment=16 + check_allcflags -mstack-alignment=16 ;; esac else - check_cflags -mllvm -stack-alignment=16 - check_cflags -mstack-alignment=16 + check_allcflags -mllvm -stack-alignment=16 + check_allcflags -mstack-alignment=16 fi - check_cflags -Qunused-arguments - check_cflags -Werror=implicit-function-declaration - check_cflags -Werror=missing-prototypes - check_cflags -Werror=return-type + check_allcflags -Qunused-arguments + check_allcflags -Werror=implicit-function-declaration + check_allcflags -Werror=missing-prototypes + check_allcflags -Werror=return-type elif enabled cparser; then add_cflags -Wno-missing-variable-declarations add_cflags -Wno-empty-statement @@ -7686,7 +8135,7 @@ elif enabled_any msvc icl; then fi # msvcrt10 x64 incorrectly enables log2, only msvcrt12 (MSVC 2013) onwards actually has log2. check_cpp_condition log2 crtversion.h "_VC_CRT_MAJOR_VERSION >= 12" - # the new SSA optimzer in VS2015 U3 is mis-optimizing some parts of the code + # the new SSA optimizer in VS2015 U3 is mis-optimizing some parts of the code # Issue has been fixed in MSVC v19.00.24218. test_cpp_condition windows.h "_MSC_FULL_VER >= 190024218" || check_cflags -d2SSAOptimizer- @@ -7717,6 +8166,19 @@ case $ld_type in ;; esac +if [ "$response_files" != "no" ]; then + ar_out=${FFTMPDIR}/test$LIBSUF + respfile="@/dev/null" + out_arg="$(echo $ar_o | sed "s;\$@;$ar_out;g")" + if test_cmd $ar $arflags $out_arg $respfile; then + response_files="yes" + elif [ "$response_files" = "auto" ]; then + response_files="no" + else + die "Response files are not available with this toolchain. Exiting" + fi +fi + enable frame_thread_encoder enabled asm || { arch=c; disable $ARCH_LIST $ARCH_EXT_LIST; } @@ -7735,10 +8197,6 @@ enabled threads || warn \ "environment." case $target_os in -haiku) - disable memalign - disable posix_memalign - ;; *-dos|freedos|opendos) if test_cpp_condition sys/version.h "defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 5"; then disable memalign @@ -7746,6 +8204,13 @@ haiku) ;; esac +if ! enabled_any memalign posix_memalign aligned_malloc; then + if enabled_any asm inline_asm; then + die "ERROR: Building with assembly enabled is not supported on platforms "\ + "without aligned memory allocations! Try reconfiguring with --disable-asm" + fi +fi + flatten_extralibs(){ nested_entries= list_name=$1 @@ -7835,7 +8300,6 @@ enabled fsync_filter && prepend avfilter_deps "avformat" enabled mcdeint_filter && prepend avfilter_deps "avcodec" enabled movie_filter && prepend avfilter_deps "avformat avcodec" enabled pan_filter && prepend avfilter_deps "swresample" -enabled pp_filter && prepend avfilter_deps "postproc" enabled qrencode_filter && prepend avfilter_deps "swscale" enabled qrencodesrc_filter && prepend avfilter_deps "swscale" enabled removelogo_filter && prepend avfilter_deps "avformat avcodec swscale" @@ -7853,10 +8317,6 @@ enabled zoompan_filter && prepend avfilter_deps "swscale" enabled lavfi_indev && prepend avdevice_deps "avfilter" -#FIXME -enabled_any sdl2_outdev opengl_outdev && enabled sdl2 && - add_cflags $(filter_out '-Dmain=SDL_main' $sdl2_cflags) - enabled opus_decoder && prepend avcodec_deps "swresample" # reorder the items at var $1 to align with the items order at var $2 . @@ -7891,9 +8351,6 @@ expand_deps(){ reorder_by ${1}_deps LIBRARY_LIST # linking order is expected later } -#we have to remove gpl from the deps here as some code assumes all lib deps are libs -postproc_deps="$(filter_out 'gpl' $postproc_deps)" - map 'expand_deps $v' $LIBRARY_LIST if test "$quiet" != "yes"; then @@ -7923,11 +8380,10 @@ if enabled x86; then echo "x86 assembler ${x86asmexe}" echo "MMX enabled ${mmx-no}" echo "MMXEXT enabled ${mmxext-no}" - echo "3DNow! enabled ${amd3dnow-no}" - echo "3DNow! extended enabled ${amd3dnowext-no}" echo "SSE enabled ${sse-no}" echo "SSSE3 enabled ${ssse3-no}" echo "AESNI enabled ${aesni-no}" + echo "CLMUL enabled ${clmul-no}" echo "AVX enabled ${avx-no}" echo "AVX2 enabled ${avx2-no}" echo "AVX-512 enabled ${avx512-no}" @@ -7944,6 +8400,11 @@ if enabled aarch64; then echo "NEON enabled ${neon-no}" echo "DOTPROD enabled ${dotprod-no}" echo "I8MM enabled ${i8mm-no}" + echo "SVE enabled ${sve-no}" + echo "SVE2 enabled ${sve2-no}" + echo "SME enabled ${sme-no}" + echo "SME-I16I64 enabled ${sme_i16i64-no}" + echo "SME2 enabled ${sme2-no}" fi if enabled arm; then echo "ARMv5TE enabled ${armv5te-no}" @@ -7982,7 +8443,6 @@ echo "optimize for size ${small-no}" echo "optimizations ${optimizations-no}" echo "static ${static-no}" echo "shared ${shared-no}" -echo "postprocessing support ${postproc-no}" echo "network support ${network-no}" echo "threading support ${thread_type-no}" echo "safe bitstream reader ${safe_bitstream_reader-no}" @@ -7991,6 +8451,7 @@ echo "perl enabled ${perl-no}" echo "pod2man enabled ${pod2man-no}" echo "makeinfo enabled ${makeinfo-no}" echo "makeinfo supports HTML ${makeinfo_html-no}" +echo "experimental features ${unstable-no}" echo "xmllint enabled ${xmllint-no}" test -n "$random_seed" && echo "random seed ${random_seed}" @@ -8088,6 +8549,8 @@ OBJCC=$objcc LD=$ld DEPCC=$dep_cc DEPCCFLAGS=$DEPCCFLAGS \$(CPPFLAGS) +DEPCXX=$dep_cc +DEPCXXFLAGS=$DEPCXXFLAGS \$(CPPFLAGS) DEPAS=$as DEPASFLAGS=$DEPASFLAGS \$(CPPFLAGS) X86ASM=$x86asmexe @@ -8095,9 +8558,11 @@ DEPX86ASM=$x86asmexe DEPX86ASMFLAGS=\$(X86ASMFLAGS) AR=$ar ARFLAGS=$arflags +RESPONSE_FILES=$response_files AR_O=$ar_o AR_CMD=$ar NM_CMD=$nm +GLSLC=$glslc METALCC=$metalcc METALLIB=$metallib RANLIB=$ranlib @@ -8109,8 +8574,9 @@ LN_S=$ln_s CPPFLAGS=$CPPFLAGS CFLAGS=$CFLAGS CXXFLAGS=$CXXFLAGS -OBJCCFLAGS=$OBJCFLAGS +OBJCFLAGS=$OBJCFLAGS ASFLAGS=$ASFLAGS +GLSLCFLAGS=$GLSLCFLAGS NVCCFLAGS=$nvccflags AS_C=$AS_C AS_O=$AS_O @@ -8122,6 +8588,7 @@ CC_E=$CC_E CC_O=$CC_O CXX_C=$CXX_C CXX_O=$CXX_O +GLSLC_O=$GLSLC_O NVCC_C=$NVCC_C NVCC_O=$NVCC_O LD_O=$LD_O @@ -8154,15 +8621,15 @@ EXTRA_VERSION=$extra_version CCDEP=$CCDEP CXXDEP=$CXXDEP CCDEP_FLAGS=$CCDEP_FLAGS +CXXDEP_FLAGS=$CXXDEP_FLAGS ASDEP=$ASDEP ASDEP_FLAGS=$ASDEP_FLAGS -X86ASMDEP=$X86ASMDEP -X86ASMDEP_FLAGS=$X86ASMDEP_FLAGS CC_DEPFLAGS=$CC_DEPFLAGS CXX_DEPFLAGS=$CXX_DEPFLAGS OBJCC_DEPFLAGS=$OBJC_DEPFLAGS AS_DEPFLAGS=$AS_DEPFLAGS X86ASM_DEPFLAGS=$X86ASM_DEPFLAGS +GLSLC_DEPFLAGS=$GLSLC_DEPFLAGS HOSTCC=$host_cc HOSTLD=$host_ld HOSTCFLAGS=$host_cflags @@ -8264,8 +8731,10 @@ echo "#endif /* FFMPEG_CONFIG_H */" >> $TMPH cp_if_changed $TMPH config.h touch ffbuild/.config -# Copy config.asm before printing ALL_COMPONENTS; that's not needed in assembly. -enabled x86asm && cp_if_changed $TMPASM config.asm +# Copy config.asm and reopen a new TMPASM for config_components.asm +enabled x86asm && cp_if_changed $TMPASM config.asm && cat > $TMPASM < $TMPH <> $TMPH echo "endif # FFMPEG_CONFIG_MAK" >> ffbuild/config.mak cp_if_changed $TMPH config_components.h +enabled x86asm && cp_if_changed $TMPASM config_components.asm cat > $TMPH <max_buffered_frames. + +2025-07-07 - eca477da52 - lavc 62.6.100 - packet.h + Add AV_PKT_DATA_RTCP_SR. + +2025-07-01 - 39d5a998bd - lavc 62.4.101 - packet.h + Add AV_PKT_DATA_3D_REFERENCE_DISPLAYS. + +2025-07-01 - b2e4b0e282 - lavu 60.4.101 - frame.h + Add AV_FRAME_DATA_3D_REFERENCE_DISPLAYS. + +2025-07-01 - 80a05bea4f - lavu 60.4.100 - tdrdi.h + Add AV3DReferenceDisplaysInfo and AV3DReferenceDisplay structs. + Add av_tdrdi_alloc() and av_tdrdi_get_display(). + +2025-05-21 - 004cc60f0e3 - lavu 60.3.100 - avassert.h + Add av_unreachable() and av_assume() macros. + +2025-02-15 - e2f39671ae2 - lavfi 10.10.100 - avfilter.h + Add avfilter_link_get_hw_frames_ctx(). + +2025-04-21 - bf1579c904a - lavu 60.2.100 - log.h + Add AV_CLASS_CATEGORY_HWDEVICE. + +2025-04-16 - c818c67991 - libpostproc 59.1.100 - postprocess.h + Deprecate PP_CPU_CAPS_3DNOW. + +2025-04-07 - 19e9a203b7 - lavu 60.01.100 - dict.h + Add AV_DICT_DEDUP. + +2025-03-17 - 49af9746e8f - lavu 59.60.100 - pixfmt.h + Add AV_PIX_FMT_GBRAP32BE and AV_PIX_FMT_GBRAP32LE. + +2025-03-10 - 61fc9b6fee1 - lavu 59.59.100 - pixfmt.h + Add AV_PIX_FMT_YAF16BE, AV_PIX_FMT_YAF16LE, AV_PIX_FMT_YAF32BE, + and AV_PIX_FMT_YAF32LE. + +2025-03-01 - 0245e9382c7 - lavu 59.58.100 - pixfmt.h + Add AV_PIX_FMT_GRAY32BE and AV_PIX_FMT_GRAY32LE. + +2025-02-04 - 0ef678f5c50 - lavu 59.56.000 - pixfmt.h + Add AV_PIX_FMT_AMF_SURFACE. + +2025-01-09 - a73760da537 - lavu 59.55.100 - pixfmt.h + Add AV_PIX_FMT_GBRPF16BE, AV_PIX_FMT_GBRPF16LE, AV_PIX_FMT_GBRAPF16BE, + AV_PIX_FMT_GBRAPF16LE, AV_PIX_FMT_GRAYF16BE, and AV_PIX_FMT_GRAYF16LE. + +2025-02-16 - c79cdae3777 - lavu 59.57.100 - log.h + Add flags AV_LOG_PRINT_TIME and AV_LOG_PRINT_DATETIME. + +2025-02-09 - 9fb806fa577 - lavc 61.32.100 - codec_id.h + Add AV_CODEC_ID_IVTV_VBI. + +2025-01-25 - ea3c3b42dff - lavu 59.56.100 - frame.h + Add AV_SIDE_DATA_PROP_CHANNEL_DEPENDENT. + +2025-01-25 - 6707d970c04 - lavfi 10.9.100 - buffersink.h + Add av_buffersink_get_side_data(). + +2025-01-25 - 7a025e1cb5f - lavfi 10.8.100 - buffersrc.h + Add AVBufferSrcParameters.side_data and AVBufferSrcParameters.nb_side_data + +2025-01-25 - ef1cb1c9c81 - lavfi 10.7.100 - avfilter.h + Add AVFilterLink.side_data and AVFilterLink.nb_side_data + +2025-01-05 - 42e72d5c8b5 - lavu 59.55.100 - frame.h + Add AV_FRAME_SIDE_DATA_FLAG_NEW_REF. + +2025-01-05 - 19c95ecbff8 - lavc 61.31.100 - avcodec.h + Deprecate AVCodecContext->properties. + +2025-01-05 - 2d91f89445d - lavc 61.30.100 - frame.h + Add AV_FRAME_FLAG_LOSSLESS. + +2025-01-03 - f3c40826455 - lavc 61.29.100 - codec_id.h + Add AV_CODEC_ID_JPEGXL_ANIM. + +2025-01-03 - da9dcaba69d - lavu 59.54.100 - frame.h + Add AV_CH_LAYOUT_5POINT1POINT2 and AV_CHANNEL_LAYOUT_5POINT1POINT2. + +2024-12-23 - b88944a8aa5 - lavu 59.53.100 - frame.h + Add av_frame_side_data_remove_by_props(). + +2024-12-23 - 3428a8d8303 - lavu 59.52.100 - frame.h + Add AV_SIDE_DATA_PROP_SIZE_DEPENDENT and AV_FRAME_DATA_PROP_COLOR_DEPENDENT. + +2024-12-23 - 45f0a7ad338 - lsws 8.13.100 - swscale.h + Add enum SwsIntent and SwsContext.intent. + +2024-12-15 - 2ac34d08542 - lavc 61.27.100 packet.h + Add av_container_fifo_alloc_avpacket(). + +2024-12-15 - 56ba57b6725 - lavu 59.51.100 - refstruct.h container_fifo.h + Add a new public header refstruct.h with new API for + reference-counted objects. + + Add a new public header container_fifo.h with new API for + a FIFO of container objects (e.g. AVFrame or AVPacket). + +2024-12-13 - 6eb4bf04e92 - lavu 59.50.100 - channel_layout.h + Add AV_CH_LAYOUT_9POINT1POINT6 and AV_CHANNEL_LAYOUT_9POINT1POINT6. + +2024-12-05 - 06f084468e0 - lavu 59.49.100 - csp.h + Add av_csp_itu_eotf() and av_csp_itu_eotf_inv(). + +2024-12-05 - bf0a6c41111 - lavu 59.48.100 - csp.h + Add av_csp_trc_func_inv_from_id(). + +2024-11-25 - 2a091d4f2ee - lsws 8.12.100 - swscale.h + Allow using sws_frame_scale() dynamically, without first initializing the + SwsContext. Deprecate sws_init_context(). Add sws_frame_setup() instead. + +2024-11-25 - fb169640092 - lsws 8.11.100 - swscale.h + Replace #define-based SWS_* flags by enum SwsFlags. + +2024-11-25 - ed5dd675624 - lsws 8.10.100 - swscale.h + Publicly expose struct SwsContext, enum SwsDither, and enum SwsAlphaBlend. + +2024-11-16 - 46cb7b8d9dc - lavu 59.47.101 - frame.h + av_frame_get_buffer() now also aligns the data pointers according to + the requested alignment. + +2024-11-13 - 20af68b63a4 - lavu 59.47.100 - channel_layout.h + Add AV_CHAN_BINAURAL_LEFT, AV_CHAN_BINAURAL_RIGHT + Add AV_CH_BINAURAL_LEFT, AV_CH_BINAURAL_RIGHT + Add AV_CH_LAYOUT_BINAURAL, AV_CHANNEL_LAYOUT_BINAURAL + +2024-10-26 - e02a3b40a5e - lavu 59.46.100 - pixfmt.h + Add AV_PIX_FMT_XV48. + +2024-10-23 - b03c758600f - lsws 8.9.100 - swscale.h + Add sws_is_noop(). + +2024-10-23 - 5e50a56b9c4 - lsws 8.8.100 - swscale.h + Add frame property testing API: + - sws_test_format() + - sws_test_colorspace() + - sws_test_primaries() + - sws_test_transfer() + - sws_test_frame() + +2024-10-23 - 87baf9ab2c2 - lsws 8.7.100 - swscale.h + Add sws_free_context(). + +2024-10-23 - f462ba05f54 - lavu 59.45.100 - pixfmt.h + Add AV_PIX_FMT_Y216. + +2024-10-15 - 2336e685657 - lavu 59.44.100 - pixfmt.h + Add AV_PIX_FMT_RGB96 and AV_PIX_FMT_RGBA128. + +2024-10-14 - c993a91bea - lavu 59.43.100 - pixfmt.h + Add AV_PIX_FMT_RGBF16. + +2024-10-08 - 29ea34728f1 - lavu 59.42.100 - pixfmt.h + Add AV_PIX_FMT_AYUV, AV_PIX_FMT_UYVA, AV_PIX_FMT_VYU444, + and AV_PIX_FMT_V30X. + +2024-10-01 - 0548ab2e425 - lavu 59.41.100 - log.h + Add AVClass.state_flags_offset and AV_CLASS_STATE_INITIALIZED. + +2024-09-30 - 50d1b89fa0d - lavf 61.9.100 - avformat.h + Add {nb_}coded_side_data to AVStreamGroupTileGrid. + +2024-09-30 - df9b80d21a2 - lavu 59 + Deprecate av_int_list_length_for_size(), av_int_list_length(), and + av_opt_set_int_list() without replacement. All AVOptions using these + should be replaced with AV_OPT_TYPE_FLAG_ARRAY. + +2024-09-30 - 1efcdbc54d9 - lavfi 10.6.100 + Buffersink now has array-type options + - pixel_formats + - colorspaces + - colorranges + replacing the int-list options + - pix_fmts + - color_spaces + - color_ranges + abuffersink now has array-type options + - sample_formats + - samplerates + - channel_layouts + replacing the int-list/string options + - sample_fmts + - sample_rates + - ch_layouts + +-------- 8< --------- FFmpeg 7.1 was cut here -------- 8< --------- + 2024-09-23 - 6940a6de2f0 - lavu 59.38.100 - frame.h Add AV_FRAME_DATA_VIEW_ID. @@ -415,7 +767,7 @@ API changes, most recent first: Deprecate AVFrame.palette_has_changed without replacement. 2023-05-15 - 7d1d61cc5f5 - lavc 60 - avcodec.h - Depreate AVCodecContext.ticks_per_frame in favor of + Deprecate AVCodecContext.ticks_per_frame in favor of AVCodecContext.framerate (encoding) and AV_CODEC_PROP_FIELDS (decoding). @@ -423,7 +775,7 @@ API changes, most recent first: Add AV_CODEC_PROP_FIELDS. 2023-05-15 - 8b20d0dcb5c - lavc 60 - codec.h - Depreate AV_CODEC_CAP_SUBFRAMES without replacement. + Deprecate AV_CODEC_CAP_SUBFRAMES without replacement. 2023-05-07 - c2ae8e30b7f - lavc 60.11.100 - codec_par.h Add AVCodecParameters.framerate. diff --git a/doc/Doxyfile b/doc/Doxyfile index ccd15e0fe..9e0842539 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = FFmpeg # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 7.1.4 +PROJECT_NUMBER = 8.1.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -295,7 +295,7 @@ MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word +# be prevented in individual cases by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. @@ -1093,7 +1093,7 @@ HTML_STYLESHEET = # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. +# standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra stylesheet files is of importance (e.g. the last # stylesheet in the list overrules the setting of the previous ones in the @@ -1636,7 +1636,7 @@ EXTRA_PACKAGES = # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, # $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty string, # for the replacement values of the other commands the user is referred to # HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. diff --git a/doc/Makefile b/doc/Makefile index 98d29f1c6..2112aff73 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -28,6 +28,7 @@ HTMLPAGES = $(AVPROGS-yes:%=doc/%.html) $(AVPROGS-yes:%=doc/%-all.html) $(COMP doc/mailing-list-faq.html \ doc/nut.html \ doc/platform.html \ + doc/drawvg-reference.html \ $(SRC_PATH)/doc/bootstrap.min.css \ $(SRC_PATH)/doc/style.min.css \ $(SRC_PATH)/doc/default.css \ diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi index e1cb87a52..36474d7db 100644 --- a/doc/bitstream_filters.texi +++ b/doc/bitstream_filters.texi @@ -189,6 +189,52 @@ see page 44-46 or section 5.5 of Extract the core from a E-AC-3 stream, dropping extra channels. +@section eia608_to_smpte436m + +Convert from a @code{EIA_608} stream to a @code{SMPTE_436M_ANC} data stream, wrapping the closed captions in CTA-708 CDP VANC packets. + +@table @option +@item line_number +Choose which line number the generated VANC packets should go on. You generally want either line 9 (the default) or 11. +@item wrapping_type +Choose the SMPTE 436M wrapping type, defaults to @samp{vanc_frame}. +It accepts the values: +@table @samp +@item vanc_frame +VANC frame (interlaced or segmented progressive frame) +@item vanc_field_1 +@item vanc_field_2 +@item vanc_progressive_frame +@end table +@item sample_coding +Choose the SMPTE 436M sample coding, defaults to @samp{8bit_luma}. +It accepts the values: +@table @samp +@item 8bit_luma +8-bit component luma samples +@item 8bit_color_diff +8-bit component color difference samples +@item 8bit_luma_and_color_diff +8-bit component luma and color difference samples +@item 10bit_luma +10-bit component luma samples +@item 10bit_color_diff +10-bit component color difference samples +@item 10bit_luma_and_color_diff +10-bit component luma and color difference samples +@item 8bit_luma_parity_error +8-bit component luma samples with parity error +@item 8bit_color_diff_parity_error +8-bit component color difference samples with parity error +@item 8bit_luma_and_color_diff_parity_error +8-bit component luma and color difference samples with parity error +@end table +@item initial_cdp_sequence_cntr +The initial value of the CDP's 16-bit unsigned integer @code{cdp_hdr_sequence_cntr} and @code{cdp_ftr_sequence_cntr} fields. Defaults to 0. +@item cdp_frame_rate +Set the CDP's @code{cdp_frame_rate} field. This doesn't actually change the timing of the data stream, it just changes the values inserted in that field in the generated CDP packets. Defaults to @samp{30000/1001}. +@end table + @section extract_extradata Extract the in-band extradata. @@ -423,9 +469,21 @@ Please note that this filter is auto-inserted for MPEG-TS (muxer @section h264_redundant_pps -This applies a specific fixup to some Blu-ray streams which contain -redundant PPSs modifying irrelevant parameters of the stream which -confuse other transformations which require correct extradata. +This applies a specific fixup to some Blu-ray BDMV H264 streams +which contain redundant PPSs. The PPSs modify irrelevant parameters +of the stream, confusing other transformations which require +the correct extradata. + +The encoder used on these impacted streams adds extra PPSs throughout +the stream, varying the initial QP and whether weighted prediction +was enabled. This causes issues after copying the stream into +a global header container, as the starting PPS is not suitable +for the rest of the stream. One side effect, for example, +is seeking will return garbled output until a new PPS appears. + +This BSF removes the extra PPSs and rewrites the slice headers +such that the stream uses a single leading PPS in the global header, +which resolves the issue. @section hevc_metadata @@ -696,12 +754,12 @@ ffmpeg -i INPUT -c copy -bsf noise=1 output.mkv Drop every video packet not marked as a keyframe after timestamp 30s but do not modify any of the remaining packets. @example -ffmpeg -i INPUT -c copy -bsf:v noise=drop='gt(t\,30)*not(key)' output.mkv +ffmpeg -i INPUT -c copy -bsf:v noise=drop='gt(pts*tb\,30)*not(key)' output.mkv @end example Drop one second of audio every 10 seconds and add some random noise to the rest. @example -ffmpeg -i INPUT -c copy -bsf:a noise=amount=-1:drop='between(mod(t\,10)\,9\,10)' output.mkv +ffmpeg -i INPUT -c copy -bsf:a noise=amount=-1:drop='between(mod(pts*tb\,10)\,9\,10)' output.mkv @end example @section null @@ -855,6 +913,8 @@ Set expressions for PTS, DTS or both. Set expression for duration. @item time_base Set output time base. +@item prescale +Set whether to convert time fields to user-set output time base before evaluation of expressions. Defaults to 0. @end table The expressions are evaluated through the eval API and can contain the following @@ -915,7 +975,7 @@ The next input PTS. The next input duration. @item TB -The timebase of stream packet belongs. +The timebase in which time fields are denominated. The user-set output timebase if prescale is enabled, else the input timebase. @item TB_OUT The output timebase. @@ -936,6 +996,11 @@ ffmpeg -i INPUT -c:a copy -bsf:a setts=pts=DTS out.mkv Log basic packet information. Mainly useful for testing, debugging, and development. +@section smpte436m_to_eia608 + +Convert from a @code{SMPTE_436M_ANC} data stream to a @code{EIA_608} stream, +extracting the closed captions from CTA-708 CDP VANC packets, and ignoring all other data. + @anchor{text2movsub} @section text2movsub diff --git a/doc/build_system.txt b/doc/build_system.txt index a0aa17bda..77841b77a 100644 --- a/doc/build_system.txt +++ b/doc/build_system.txt @@ -30,6 +30,13 @@ fate fate-list List all fate/regression test targets. +fate-list-failing + List the fate tests that failed the last time they were executed. + +fate-clear-reports + Remove the test reports from previous test executions (getting rid of + potentially stale results from fate-list-failing). + install Install headers, libraries and programs. diff --git a/doc/codecs.texi b/doc/codecs.texi index 6bdeb664e..eec5d8e8c 100644 --- a/doc/codecs.texi +++ b/doc/codecs.texi @@ -664,6 +664,8 @@ for codecs that support it. At present, those are H.264 and VP9. @item film_grain Export film grain parameters through frame side data (see @code{AV_FRAME_DATA_FILM_GRAIN_PARAMS}). Supported at present by AV1 decoders. +@item enhancements +Export picture enhancement metadata through frame side data, e.g. LCEVC (see @code{AV_FRAME_DATA_LCEVC}). @end table @item threads @var{integer} (@emph{decoding/encoding,video}) @@ -911,6 +913,14 @@ Possible values: @end table +@item alpha_mode @var{integer} (@emph{decoding/encoding,video}) +Possible values: +@table @samp +@item premultiplied +@item straight +@end table + + @item log_level_offset @var{integer} Set the log level offset. diff --git a/doc/decoders.texi b/doc/decoders.texi index 17bb361ff..1db297f42 100644 --- a/doc/decoders.texi +++ b/doc/decoders.texi @@ -119,16 +119,6 @@ The following options are supported by the libdav1d wrapper. @table @option -@item framethreads -Set amount of frame threads to use during decoding. The default value is 0 (autodetect). -This option is deprecated for libdav1d >= 1.0 and will be removed in the future. Use the -option @code{max_frame_delay} and the global option @code{threads} instead. - -@item tilethreads -Set amount of tile threads to use during decoding. The default value is 0 (autodetect). -This option is deprecated for libdav1d >= 1.0 and will be removed in the future. Use the -global option @code{threads} instead. - @item max_frame_delay Set max amount of frames the decoder may buffer internally. The default value is 0 (autodetect). @@ -356,6 +346,15 @@ value is 0 (disabled). @end table +@section libmpeghdec + +libmpeghdec decoder wrapper. + +libmpeghdec allows libmpeghdec to decode the MPEG-H 3D audio codec. +Requires the presence of the libmpeghdec headers and library during +configuration. You need to explicitly configure the build with +@code{--enable-libmpeghdec --enable-nonfree}. + @section libopencore-amrnb libopencore-amrnb decoder wrapper. @@ -395,7 +394,7 @@ without this library. @c man end AUDIO DECODERS @chapter Subtitles Decoders -@c man begin SUBTILES DECODERS +@c man begin SUBTITLES DECODERS @section libaribb24 @@ -427,7 +426,7 @@ Enabled by default. Yet another ARIB STD-B24 caption decoder using external @dfn{libaribcaption} library. -Implements profiles A and C of the Japanse ARIB STD-B24 standard, +Implements profiles A and C of the Japanese ARIB STD-B24 standard, Brazilian ABNT NBR 15606-1, and Philippines version of ISDB-T. Requires the presence of the libaribcaption headers and library @@ -477,7 +476,7 @@ Specify comma-separated list of font family names to be used for @dfn{bitmap} or @dfn{ass} type subtitle rendering. Only first font name is used for @dfn{ass} type subtitle. -If not specified, use internaly defined default font family. +If not specified, use internally defined default font family. @item -ass_single_rect @var{boolean} ARIB STD-B24 specifies that some captions may be displayed at different @@ -495,7 +494,7 @@ default behavior at compilation. @item -force_outline_text @var{boolean} Specify whether always render outline text for all characters regardless of -the indication by charactor style. +the indication by character style. The default is @var{false}. @@ -696,4 +695,4 @@ box and an end box, typically subtitles. Default value is 0 if @end table -@c man end SUBTILES DECODERS +@c man end SUBTITLES DECODERS diff --git a/doc/demuxers.texi b/doc/demuxers.texi index 2324b3b46..a49d3406f 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -281,7 +281,11 @@ This demuxer accepts the following option: @table @option @item cenc_decryption_key -16-byte key, in hex, to decrypt files encrypted using ISO Common Encryption (CENC/AES-128 CTR; ISO/IEC 23001-7). +Default 16-byte key, in hex, to decrypt files encrypted using ISO Common Encryption (CENC/AES-128 CTR; ISO/IEC 23001-7). + +@item cenc_decryption_keys +Dictionary of 16-byte key ID => 16-byte key, both in hex, to decrypt files encrypted using ISO Common Encryption +(CENC/AES-128 CTR; ISO/IEC 23001-7). @end table @@ -664,30 +668,9 @@ Select a glob wildcard pattern type. The pattern is interpreted like a @code{glob()} pattern. This is only selectable if libavformat was compiled with globbing support. - -@item glob_sequence @emph{(deprecated, will be removed)} -Select a mixed glob wildcard/sequence pattern. - -If your version of libavformat was compiled with globbing support, and -the provided pattern contains at least one glob meta character among -@code{%*?[]@{@}} that is preceded by an unescaped "%", the pattern is -interpreted like a @code{glob()} pattern, otherwise it is interpreted -like a sequence pattern. - -All glob special characters @code{%*?[]@{@}} must be prefixed -with "%". To escape a literal "%" you shall use "%%". - -For example the pattern @code{foo-%*.jpeg} will match all the -filenames prefixed by "foo-" and terminating with ".jpeg", and -@code{foo-%?%?%?.jpeg} will match all the filenames prefixed with -"foo-", followed by a sequence of three characters, and terminating -with ".jpeg". - -This pattern type is deprecated in favor of @var{glob} and -@var{sequence}. @end table -Default value is @var{glob_sequence}. +Default value is @var{sequence}. @item pixel_format Set the pixel format of the images to read. If not specified the pixel format is guessed from the first image file in the sequence. @@ -855,6 +838,32 @@ Set the sample rate for libopenmpt to output. Range is from 1000 to INT_MAX. The value default is 48000. @end table +@anchor{mccdec} +@section mcc + +Demuxer for MacCaption MCC files, it supports MCC versions 1.0 and 2.0. +MCC files store VANC data, which can include closed captions (EIA-608 and CEA-708), ancillary time code, pan-scan data, etc. +By default, for backward compatibility, the MCC demuxer extracts just the EIA-608 and CEA-708 closed captions and returns a @code{EIA_608} stream, ignoring all other VANC data. +You can change it to return all VANC data in a @code{SMPTE_436M_ANC} data stream by setting @option{-eia608_extract 0} + +@subsection Examples + +@itemize +@item +Convert a MCC file to Scenarist (SCC) format: +@example +ffmpeg -i CC.mcc -c:s copy CC.scc +@end example +Note that the SCC format only supports EIA-608, so this will discard all other data such as CEA-708 extensions. + +@item +Merge a MCC file into a MXF file: +@example +ffmpeg -i video_and_audio.mxf -eia608_extract 0 -i CC.mcc -c copy -map 0 -map 1 out.mxf +@end example +This retains all VANC data and inserts it into the output MXF file as a @code{SMPTE_436M_ANC} data stream. +@end itemize + @section mov/mp4/3gp Demuxer for Quicktime File Format & ISO/IEC Base Media File Format (ISO/IEC 14496-12 or MPEG-4 Part 12, ISO/IEC 15444-12 or JPEG 2000 Part 12). @@ -935,7 +944,11 @@ Fixed key used for handling Audible AAX/AAX+ files. It has been pre-set so shoul specify. @item decryption_key -16-byte key, in hex, to decrypt files encrypted using ISO Common Encryption (CENC/AES-128 CTR; ISO/IEC 23001-7). +Default 16-byte key, in hex, to decrypt files encrypted using ISO Common Encryption (CENC/AES-128 CTR; ISO/IEC 23001-7). + +@item decryption_keys +Dictionary of 16-byte key ID => 16-byte key, both in hex, to decrypt files encrypted using ISO Common Encryption +(CENC/AES-128 CTR; ISO/IEC 23001-7). @item max_stts_delta Very high sample deltas written in a trak's stts box may occasionally be intended but usually they are written in @@ -990,7 +1003,7 @@ to 1 (-1 means automatic setting, 1 means enabled, 0 means disabled). Default value is -1. @item merge_pmt_versions -Re-use existing streams when a PMT's version is updated and elementary +Reuse existing streams when a PMT's version is updated and elementary streams move to different PIDs. Default value is 0. @item max_packet_size @@ -1030,6 +1043,11 @@ Set input video frame rate. Default value is 25. @item pixel_format Set the input video pixel format. Default value is @code{yuv420p}. +@item stride +Set frame line size in bytes, only required if there are extra padding. +For multiplane formats, @option{stride} is a list of line size for each +plane. + @item video_size Set the input video size. This value must be specified explicitly. @end table @@ -1042,6 +1060,13 @@ the command: ffplay -f rawvideo -pixel_format rgb24 -video_size 320x240 -framerate 10 input.raw @end example +Read a rawvideo with @command{ffplay}, assuming a pixel format of @code{yuv420p}, +a video size of @code{1080x1920}, has 8 bytes of padding in each line of Y plane, +and 4 bytes of padding with UV plane, +@example +ffplay -f rawvideo -pixel_format yuv420p -video_size 1080x1920 -stride 1088,544,544 input.raw +@end example + @anchor{rcwtdec} @section rcwt diff --git a/doc/developer.texi b/doc/developer.texi index dcfb64e07..f41ba924c 100644 --- a/doc/developer.texi +++ b/doc/developer.texi @@ -45,6 +45,7 @@ maintained and developed. @end itemize All proposed code changes should be submitted for review to +@url{https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls, Forgejo} or @url{mailto:ffmpeg-devel@@ffmpeg.org, the development mailing list}, as described in more detail in the @ref{Submitting patches} chapter. The code should comply with the @ref{Development Policy} and follow the @ref{Coding Rules}. @@ -70,9 +71,6 @@ variable-length arrays; @item complex numbers; - -@item -mixed statements and declarations. @end itemize @subsection SIMD/DSP @@ -115,7 +113,7 @@ Objective-C where required for interacting with macOS-specific interfaces. @section Code formatting conventions -There are the following guidelines regarding the indentation in files: +There are the following guidelines regarding the code style in files: @itemize @bullet @item @@ -135,6 +133,104 @@ K&R coding style is used. @end itemize The presentation is one inspired by 'indent -i4 -kr -nut'. +@subsection Examples +Some notable examples to illustrate common code style in FFmpeg: + +@itemize @bullet + +@item +Space around assignments and after +@code{if}/@code{do}/@code{while}/@code{for} keywords: + +@example c, good +// Good +if (condition) + av_foo(); +@end example + +@example c, good +// Good +for (size_t i = 0; i < len; i++) + av_bar(i); +@end example + +@example c, good +// Good +size_t size = 0; +@end example + +However no spaces between the parentheses and condition, unless it helps +readability of complex conditions, so the following should not be done: + +@example c, bad +// Bad style +if ( condition ) + av_foo(); +@end example + +@item +No unnecessary parentheses, unless it helps readability: + +@example c, good +// Good +int fields = ilace ? 2 : 1; +@end example + +@item +Don't wrap single-line blocks in braces. Use braces only if there is an accompanying else statement. This keeps future code changes easier to keep track of. + +@example c, good +// Good +if (bits_pixel == 24) @{ + avctx->pix_fmt = AV_PIX_FMT_BGR24; +@} else if (bits_pixel == 8) @{ + avctx->pix_fmt = AV_PIX_FMT_GRAY8; +@} else + return AVERROR_INVALIDDATA; + +@end example + +@item +Avoid assignments in conditions where it makes sense: + +@example c, good +// Good +video_enc->chroma_intra_matrix = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64) +if (!video_enc->chroma_intra_matrix) + return AVERROR(ENOMEM); +@end example + +@example c, bad +// Bad style +if (!(video_enc->chroma_intra_matrix = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64))) + return AVERROR(ENOMEM); +@end example + +@example c, good +// Ok +while ((entry = av_dict_iterate(options, entry))) + av_log(ctx, AV_LOG_INFO, "Item '%s': '%s'\n", entry->key, entry->value); +@end example + +@item +When declaring a pointer variable, the @code{*} goes with the variable not the type: + +@example c, good +// Good +AVStream *stream; +@end example + +@example c, bad +// Bad style +AVStream* stream; +@end example + +@end itemize + +If you work on a file that does not follow these guidelines consistently, +change the parts that you are editing to follow these guidelines but do +not make unrelated changes in the file to make it conform to these. + @subsection Vim configuration In order to configure Vim to follow FFmpeg formatting conventions, paste the following snippet into your @file{.vimrc}: @@ -271,6 +367,9 @@ symbols. If in doubt, just avoid names starting with @code{_} altogether. @item Casts should be used only when necessary. Unneeded parentheses should also be avoided if they don't make the code easier to understand. +@item +Where applicable, SI units shall be used. For example timeouts should use seconds as the fundamental unit not micro seconds. +That means a bare value like @samp{1.0} must mean 1 second, @samp{50m} means 50 milliseconds. For weight, gram shall be used. @end itemize @anchor{Development Policy} @@ -451,7 +550,7 @@ FFmpeg also has a defined scope - your new API must fit within it. @subsubheading Replacing existing APIs If your new API is replacing an existing one, it should be strictly superior to -it, so that the advantages of using the new API outweight the cost to the +it, so that the advantages of using the new API outweigh the cost to the callers of changing their code. After adding the new API you should then deprecate the old one and schedule it for removal, as described in @ref{Removing interfaces}. @@ -501,7 +600,7 @@ change in @file{doc/APIchanges}. Backward-incompatible API or ABI changes require incrementing (bumping) the major version number, as described in @ref{Major version bumps}. Major bumps are significant events that happen on a schedule - so if your change -strictly requires one you should add it under @code{#if} preprocesor guards that +strictly requires one you should add it under @code{#if} preprocessor guards that disable it until the next major bump happens. New APIs that can be added without breaking API or ABI compatibility require @@ -627,7 +726,8 @@ and has no lrint()') Also please if you send several patches, send each patch as a separate mail, do not attach several unrelated patches to the same mail. -Patches should be posted to the +Patches should be posted to +@uref{https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls, Forgejo} or the @uref{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-devel, ffmpeg-devel} mailing list. Use @code{git send-email} when possible since it will properly send patches without requiring extra care. If you cannot, then send patches @@ -822,10 +922,10 @@ improves readability. Consider adding a regression test for your code. All new modules should be covered by tests. That includes demuxers, muxers, decoders, encoders filters, bitstream filters, parsers. If its not possible to do that, add -an explanation why to your patchset, its ok to not test if theres a reason. +an explanation why to your patchset, its ok to not test if there's a reason. @item -If you added YASM code please check that things still work with --disable-yasm. +If you added NASM code please check that things still work with --disable-x86asm. @item Test your code with valgrind and or Address Sanitizer to ensure it's free diff --git a/doc/drawvg-reference.texi b/doc/drawvg-reference.texi new file mode 100644 index 000000000..c503bcec0 --- /dev/null +++ b/doc/drawvg-reference.texi @@ -0,0 +1,2793 @@ +@documentencoding UTF-8 + +@settitle drawvg - Language Reference +@titlepage +@center @titlefont{drawvg - Language Reference} +@end titlepage + +@top + +@contents + +@macro codeexample {block} +@cartouche Example +\block\ +@end cartouche +@end macro + +@macro vgscmd {name} +@ref{cmd_\name\,,@code{\name\}} +@end macro + +@chapter Introduction + +drawvg (@emph{draw vector graphics}) is a language to draw +two-dimensional graphics on top of video frames. It is not intended to +be used as a general-purpose language. Since its scope is limited, it +prioritizes being concise and easy to use. + +For example, using the +@uref{https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API,Canvas +API} we can render a triangle running this code in a Web browser: + +@example +const canvas = document.getElementById("canvas"); +const ctx = canvas.getContext("2d"); + +ctx.beginPath(); +ctx.moveTo(125, 50); +ctx.lineTo(100, 100); +ctx.lineTo(150, 100); +ctx.closePath(); +ctx.stroke(); +@end example + +The same triangle can be written with this drawvg script: + +@example +moveto 125 50 +lineto 100 100 150 100 +closepath +stroke +@end example + +It can be shortened using the aliases for @vgscmd{moveto}, @vgscmd{lineto}, +and @vgscmd{closepath}: + +@example +M 125 50 +L 100 100 150 100 +Z +stroke +@end example + +Both newlines (@code{U+000A}) and spaces (@code{U+0020}) can be used +interchangeably as delimiters, so multiple commands can appear on the +same line: + +@example +M 125 50 L 100 100 150 100 Z +stroke +@end example + +@macro ffexprs +@ref{Expression Evaluation,,FFmpeg expressions,ffmpeg-utils} +@end macro + +Finally, drawvg can use @ffexprs{} and frame metadata in command arguments. In +this example, we are using the variables @var{w} (frame width) and @var{h} +(frame height) to create a circle in the middle of the frame. + +@example +circle (w / 2) (h / 2) (w / 3) +stroke +@end example + +Many commands are a direct equivalent to a function in the +@uref{https://www.cairographics.org/,Cairo graphics library}. For such +commands, the reference below provides a link to the related Cairo +documentation. + +@chapter Syntax + +@macro svgpathlink +@uref{https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/path,SVG's @code{}} +@end macro + +The syntax is heavily inspired by languages like +@uref{https://imagemagick.org/script/magick-vector-graphics.php,Magick +Vector Graphics}, or @svgpathlink{}. Many command names are taken from +@uref{https://en.wikipedia.org/wiki/PostScript,PostScript}. + +@section Structure + +A drawvg script consists of a series of commands to describe 2D +graphics. + +A command is an identifier (like @vgscmd{setcolor} or @vgscmd{lineto}) +followed by its arguments. Each item in the code (command name, +arguments, etc.) is separated by any of the following characters: + +@itemize +@item Space (@code{' '}) +@item Comma (@code{','}) +@item Newline (@code{'\n'}) +@item Tabs (@code{'\t'}) +@item Return (@code{'\r'}) +@end itemize + +The beginning of the item indicates how it will be interpreted: + +@table @r +@item @code{//} +Comment +@item @code{0}, @dots{}, @code{9}, @code{+}, @code{-} +Number literal +@item @code{(} +Expression +@item @code{@{}, @code{@}} +Block delimiters +@item Anything else +Name of a command, a color, etc. +@end table + +@section Comments + +Comments start with two slashes (@code{//}), and stop at the end of the +line (either a @code{\n}, or the end of the script). + +@example +circle 100 100 50 // this is ignored +fill + +// this is also ignored +@end example + +@code{//} must appear after a space, or at the beginning of the line. If +@code{//} is preceded by any non-blank character, the parser will +consider @code{//} as part of the previous item. + +For example, in this script: + +@example +circle 10 10 50// something +@end example + +The parser throws an error because it tries to parse @code{50//} as a +number literal. + +@section Commands + +The way commands are parsed is inspired by @svgpathlink{}: + +@itemize +@item +Every command in the script starts with its name, and it is followed by +zero or more arguments. + +@item +There are no explicit delimiters between commands or arguments. + +Most programming languages expect characters like parenthesis, commas, +or semicolons, to separate items. For example: + +@example +moveto(10, 10); lineto(20, 30); +@end example + +The equivalent in drawvg is: + +@example +moveto 10 10 lineto 20 30 +@end example + +@item +If the command has no arguments (like @vgscmd{closepath} or +@vgscmd{stroke}), the next command starts at the next item. + +@end itemize + +@codeexample{ +In the next script there are 4 different commands: + +@example +newpath rect 10 20 30 40 setcolor teal fill +@end example + +@enumerate +@item +@vgscmd{newpath} requires no arguments. + +@item +@vgscmd{rect} requires 4 arguments, so it takes the next 4 numbers. + +@item +@vgscmd{setcolor} requires 1 argument, so it takes the word @code{teal}. + +@item +@vgscmd{fill} requires no arguments. +@end enumerate +} + +@subsection Single-Letter Aliases + +Most commands in @svgpathlink{} are also present in drawvg. For some of them, +there is an alias to a longer name: + +@itemize +@item @vgscmd{curveto} for @vgscmd{C}. +@item @vgscmd{rcurveto} for @vgscmd{c}. +@item @vgscmd{lineto} for @vgscmd{L}. +@item @vgscmd{rlineto} for @vgscmd{l}. +@item @vgscmd{moveto} for @vgscmd{M}. +@item @vgscmd{rmoveto} for @vgscmd{m}. +@item @vgscmd{closepath} for @vgscmd{Z}, @vgscmd{z}. +@end itemize + +Other commands only exist in a single-letter form: + +@itemize +@item @vgscmd{H}, @vgscmd{h} +@item @vgscmd{Q}, @vgscmd{q} +@item @vgscmd{S}, @vgscmd{s} +@item @vgscmd{V}, @vgscmd{v} +@item @vgscmd{T}, @vgscmd{t} +@end itemize + +This makes it possible to use a path in SVG to create the same shape in +a drawvg script. + +@anchor{implicit commands} +@subsection Implicit Commands + +For many commands, the name can be omitted when it is used multiple +times in successive calls. + +In the reference below, these commands has a @emph{Can be Implicit} note +in their signature. + +@codeexample { +For example, in this script: + +@example +M 50 50 +l 10 10 +l 10 -10 +l 10 10 +l 10 -10 +l 10 10 +stroke +@end example + +After the first call to @vgscmd{l} (alias to @vgscmd{rlineto}), the command +can be executed without the name, so it can be written as: + +@example +M 50 50 +l 10 10 10 -10 10 10 10 -10 10 10 +stroke +@end example +} + +To reuse the same command (@vgscmd{l}, in the previous example), the +parser checks if the item after the last argument is a numeric value, +like a number literal or a FFmpeg expression. + +@codeexample{ +In this example: + +@example +l 10 20 30 40 stroke +@end example + +@vgscmd{l} requires 2 arguments, and can be implicit, so the parser +performs this operation: + +@enumerate + +@item +Takes the two next items (@code{10} and @code{20}) and emits the first +instruction. + +@item +Checks if the item after @code{20} is a numeric value. Since it is +@code{30}, it takes @code{30} and @code{40} and emits the second +instruction (@code{l 30 40}). + +@item +Checks if the next item after @code{40} is a numeric value, but it is a +command (@vgscmd{stroke}), so it stops reusing @vgscmd{l}. + +@end enumerate +} + +This is another feature taken from @svgpathlink{}. An important difference with +SVG is that the separator between items is always required. In SVG, it can be +omitted in some cases. For example, the expression @code{m1-2} is equivalent to +@code{m 1 -2} in SVG, but a syntax error in drawvg. + +@section Arguments + +Most commands expect numeric arguments, like number literals, variable +names, or expressions. + +@vgscmd{setcolor} and @vgscmd{colorstop} expect a color. + +@vgscmd{setlinecap} and @vgscmd{setlinejoin} expect a constant value. + +@subsection Number Literals + +A number literal is an item in the script that represents a constant +value. Any item that starts with a decimal digit (between @code{0} and +@code{9}), a @code{-} or a @code{+}, is interpreted as a number literal. + +The value is parsed with +@uref{https://ffmpeg.org/doxygen/trunk/eval_8c.html#a7d21905c92ee5af0bb529d2daf8cb7c3,@code{av_strtod}}. +It supports the prefix @code{0x} to write a value with hexadecimal +digits, and +@uref{https://ffmpeg.org/ffmpeg-utils.html#:~:text=The%20evaluator%20also%20recognizes%20the%20International%20System%20unit%20prefixes,many +units} (like @code{K} or @code{GiB}). + +In the next example, all literals represent the same value: + +@example +10000 +1e4 +10K +0x2710 +@end example + +@subsection Expressions + +@ffexprs{} can be used as arguments for any command that expects a numeric +argument. The expression must be enclosed in parenthesis. + +@codeexample { +The variables @var{w} and @var{h} represent the width and height of the +frame. We can compute the center of the frame by dividing them by @code{2}: + +@example +M (w / 2) (h / 2) +@end example + +They can also contain parenthesis (to group operations, to call functions, +etc): + +@example +moveto + ((w + 10) / 2) // x + (h / (2 * cos(t))) // y +@end example +} + +The variables @var{n} and @var{t} can be used to compute a value that changes +over time. + +@codeexample { +To draw a circle oscillating from left to right, we can use an +expression based on @code{sin(t)} for the @code{x} coordinate: + +@example +circle + (w / 2 + sin(2 * t) * w / 4) // x + (h / 2) // y + (w / 5) // radius + +stroke +@end example +} + +Expressions can be split in multiple lines, but they can't contain +comments within them. + +@example +moveto // This is a comment. + (w // This is part of the expression, not a comment. + + h) +@end example + +@subsection Variable Names + +When an expression is only a reference to a variable, the parenthesis +can be omitted, and the item is just the variable name. + +@codeexample { +The next 3 expressions are equivalent: in all cases, they create a +rectangle covering the whole frame. + +@example +rect (0) (0) (w) (h) + +rect 0 0 w h + +rect (0) 0 (w) h +@end example +} + +It is possible to create a variable with the same name of a command, and +then use it as an argument. In the previous example, the item @var{h} is a +reference to a variable (frame height), but in other contexts it may be +a command (@vgscmd{h}). + +For @ref{implicit commands}, the parser prioritizes +commands over variable names when it has to determine if the command is +reused. + +@codeexample { +In this example, the variable @var{c} is used as the first argument in two +calls to @vgscmd{l}. However, only the first one is valid, because in the +second call the parser recognizes @vgscmd{c} as a command. + +@example +setvar c 5 +l c 10 c 15 +@end example + +This issue can be fixed by surrounding the start of the second call with +parenthesis: + +@example +setvar c 5 +l c 10 (c) 15 +@end example +} + +@anchor{Colors} +@subsection Colors + +The color to stroke and to fill paths can be set with @vgscmd{setcolor}. +Its argument has the same syntax for colors in FFmpeg: + +@itemize +@item +A @ref{Color,,predefined color name,ffmpeg-utils}. + +@item +In @code{#RRGGBB} format. + +@item +Optionally, an @code{@@a} suffix can be added to set the alpha value, +where @code{a} is a number between @code{0} and @code{1}. +@end itemize + +@example +circle 70 70 60 +setcolor #FF0000 +fill + +circle 170 170 60 +setcolor blue@@0.5 +fill +@end example + +The color can be a variable name. In that case, it must be assigned with +@vgscmd{defrgba}, @vgscmd{defhsla}, or @vgscmd{setvar} and a color. + +@example +circle 70 70 60 +setvar CustomGreen #22FF44 +setcolor CustomGreen +fill + +circle 170 170 60 +defhsla CustomBlue 200 0.7 0.5 1 +setcolor CustomBlue +fill +@end example + +The commands @vgscmd{setrgba} and @vgscmd{sethsla} allow setting colors using +expressions. Similar to @vgscmd{defrgba} and @vgscmd{defhsla}, but with no +intermediate variable. + +@subsection Constants + +The argument for @vgscmd{setlinecap} and @vgscmd{setlinejoin} is an +identifier referring to a constant value. + +@example +setlinecap round +@end example + +@chapter Guide + +@section Paths + +A path is a complex shape, composed by lines and curves, that can be +used to fill a region, to stroke an outline, or to establish a clip +region. + +In order to draw anything on top of a video frame, first we have to +define a path, and then use @vgscmd{stroke} or @vgscmd{fill}. + +The +@uref{https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorials/SVG_from_scratch/Paths,tutorial +on paths in MDN} is a good introduction to the topic. It is focused on +@svgpathlink{}, but the same concepts can be applied in drawvg. + +@anchor{current point} +@subsection Current Point + +Some commands require a @emph{current point}. Initially, the +@emph{current point} is set to +@uref{https://en.wikipedia.org/wiki/NaN,@code{NaN}}. It is initialized +with @vgscmd{M} or @vgscmd{moveto}. Other commands, like @vgscmd{lineto} or +@vgscmd{curveto}, updates the @emph{current point} to the new end of the +shape. + +The @emph{current point} can be cleared with @vgscmd{newpath}. Commands +that clear the path, like @vgscmd{stroke} or @vgscmd{fill}, also clear the +@emph{current point}. + +@codeexample { +@vgscmd{rlineto} uses coordinates relative to the @emph{current point}. + +Given this script: + +@example +moveto 20 100 +rlineto 150 -90 +rlineto -50 200 +closepath +stroke +@end example + +These are the coordinates of the @emph{current point} after executing +each command: + +@multitable @columnfractions .5 .5 +@headitem Command @tab Current Point +@item @code{moveto 20 100} @tab @code{20, 100} +@item @code{rlineto 150 -90} @tab @code{170, 10} +@item @code{rlineto -10 50} @tab @code{140, 210} +@item @code{closepath} @tab @code{20, 100} +@end multitable + +The same script can be written with single-letter aliases: + +@example +M 20 100 l 150 -90 -50 200 z stroke +@end example +} + +@subsection Defining a Shape + +A path is defined by adding lines, curves, or basic shapes. + +@itemize +@item Basic shapes + +@itemize +@item @vgscmd{circle} +@item @vgscmd{ellipse} +@item @vgscmd{rect} +@item @vgscmd{roundedrect} +@end itemize + +@item +Lines +@itemize +@item @vgscmd{M}, @vgscmd{moveto} +@item @vgscmd{m}, @vgscmd{rmoveto} +@item @vgscmd{H}, @vgscmd{h} +@item @vgscmd{V}, @vgscmd{v} +@item @vgscmd{L}, @vgscmd{lineto} +@item @vgscmd{l}, @vgscmd{rlineto} +@item @vgscmd{Z}, @vgscmd{z}, @vgscmd{closepath} +@end itemize + +@item +Curves +@itemize +@item @vgscmd{arc}, @vgscmd{arcn} +@item @vgscmd{C}, @vgscmd{curveto}, +@item @vgscmd{c}, @vgscmd{rcurveto} +@item @vgscmd{Q}, @vgscmd{q} +@item @vgscmd{S}, @vgscmd{s} +@item @vgscmd{T}, @vgscmd{t} +@end itemize + +@end itemize + +Single-letter commands are taken from @svgpathlink{}. + +@anchor{fill rules} +@subsection Fill + +The region within the shape defined by a path can be filled with +@vgscmd{fill} or @vgscmd{eofill}. Each command uses a different +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-fill-rule-t,fill +rule}: + +@itemize +@item +@vgscmd{fill} uses the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#CAIRO-FILL-RULE-WINDING:CAPS,winding +rule}, also known as +@uref{https://en.wikipedia.org/wiki/Nonzero-rule,nonzero rule}. +@item +@vgscmd{eofill} uses the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#CAIRO-FILL-RULE-EVEN-ODD:CAPS,even--odd +rule}. +@end itemize + +@codeexample{ +This script shows the difference between the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#CAIRO-FILL-RULE-WINDING:CAPS,winding} +and +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#CAIRO-FILL-RULE-EVEN-ODD:CAPS,even--odd} +rules: + +@example +rect 50 10 100 60 +circle 150 70 40 +setcolor seagreen +fill + +rect 50 130 100 60 +circle 150 190 40 +setcolor skyblue +eofill +@end example +} + +@subsection Stroke + +@vgscmd{stroke} draws a line around the shape defined by the path. The +stroke can be configured with different commands: + +@itemize +@item @vgscmd{setdash} +@item @vgscmd{setdashoffset} +@item @vgscmd{setlinecap} +@item @vgscmd{setlinejoin} +@item @vgscmd{setlinewidth} +@item @vgscmd{resetdash} +@end itemize + +@codeexample{ +This example use @vgscmd{setdashoffset} to animate the stroke: + +@example +moveto 0 0 +lineto w h + +setlinecap round +setdash 50 50 +setlinewidth 20 +setdashoffset (hypot(w, h) * t / -3) +setcolor seagreen + +stroke +@end example +} + +@subsection Clip + +A @uref{https://en.wikipedia.org/wiki/Clipping_(computer_graphics),clip +region} can be established with @vgscmd{clip} and @vgscmd{eoclip}. + +If there is an active clip region, the new clip region will be the +intersection between the existing one and the path. @vgscmd{resetclip} +reset the clip region to the whole frame. + +@vgscmd{eoclip} uses the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#CAIRO-FILL-RULE-EVEN-ODD:CAPS,even--odd +rule} to compute the clip region. + +@codeexample{ +@example +rect 50 50 100 200 +clip + +circle 30 30 150 +setcolor seagreen +fill + +// Draw outside the clip region. +resetclip +circle 30 30 150 +setlinewidth 3 +setcolor skyblue +stroke +@end example +} + +@subsection Preserving Paths + +The path is cleared after any operation on it, like @vgscmd{fill} or +@vgscmd{stroke}. To reuse the same path in multiple operations, +@vgscmd{preserve} must be called before them. + +@codeexample{ +In this example, each path is used twice. + +@example +circle 120 120 50 +setcolor seagreen +preserve stroke +clip + +circle 100 100 50 +setcolor skyblue +preserve fill +setcolor tomato +stroke +@end example +} + +@section Variables + +A drawvg can use some variables, provided by the interpreter, to compute +values in @ffexprs{}: + +@table @var +@item cx +X coordinate of the @ref{current point}. + +@item cy +Y coordinate of the @ref{current point}. + +@item w +Width, in pixels, of the frame. + +@item h +Height, in pixels, of the frame. + +@item i +The loop counter in repeat blocks. + +@item n +Frame number. + +@item t +Timestamp, in seconds. + +@item ts +Timestamp, in seconds, of the first frame. + +@item duration +Duration, in seconds, of the frame. +@end table + +@anchor{User Variables} +@subsection User Variables + +New variables can be created with the @vgscmd{setvar} command. It +associates a name with a numeric value. + +The name must follow these rules: + +@itemize +@item +It must start with an ASCII letter or an underscore (@code{_}). + +@item +It can contain only ASCII letters, underscores, and digits. + +@item +It must not match the name of a variable provided by the interpreter +(like @var{w} or @var{t}). +@end itemize + +The same variable can be assigned multiple times. + +@codeexample{ +In this example, the result of an expression is stored in a variable +with the name @var{progress}. Then, it is used for the @var{x} and +@var{width} arguments of @vgscmd{rect}. + +@example +setvar progress (w * (pow(mod(t / 2 + 0.5, 1), 2.5))) + +rect ((w - progress) / 2) 0 progress h + +setcolor darkblue +fill +@end example +} + +Currently, a script can contain only 20 different variable names, but +this limit can be modified in the future. + +@anchor{current pattern} +@section Patterns + +The pattern for fill and stroke operations can be either a solid color, +or a gradient. + +@itemize +@item Solid colors. + +@itemize +@item @vgscmd{setcolor} +@item @vgscmd{sethsla} +@item @vgscmd{setrgba} +@end itemize + +@item Gradients. + +@itemize +@item @vgscmd{lineargrad} +@item @vgscmd{radialgrad} +@end itemize + +@end itemize + +The pattern is not cleared after being used in a fill or stroke +operation, but it is replaced by any command that sets a new pattern. + +@subsection Gradients + +To configure a gradient, first call to @vgscmd{lineargrad} or +@vgscmd{radialgrad}, and then add color stops by calling @vgscmd{colorstop} +for each stop. + +@codeexample{ +In this example, the whole frame is filled with a linear gradient: + +@example +lineargrad 0 0 w h +colorstop 0 skyblue +colorstop 1 darkblue + +rect 0 0 w h +fill +@end example + +In this example, a radial gradient is used to simulate a sphere: + +@example +radialgrad 90 90 5 120 120 100 +colorstop 0.0 #90DDFF +colorstop 0.9 #000030 +colorstop 1.0 #000000 + +rect 0 0 w h +fill +@end example +} + +@subsection Variables + +@vgscmd{setcolor} and @vgscmd{colorstop} accept a variable name as the +argument. The variable must be assigned with @vgscmd{defrgba}, +@vgscmd{defhsla}, or @vgscmd{setvar} and a color. + +@codeexample{ +@example +// Use color #1020FF, alpha = 50% +setvar someblue #1020FF@@0.5 + +setcolor someblue + +rect 30 30 120 120 +fill + +rect 90 90 120 120 +fill +@end example +} + +If a variable has the same name of a @ref{Color,,known color,ffmpeg-utils}, the +variable has preference, and will be used instead of the predefined color. + +@codeexample{ +@example +setcolor teal +rect 30 30 120 120 +fill + +setvar teal #70AAAA +setcolor teal // Use the new color for `teal`. +rect 90 90 120 120 +fill +@end example +} + +@vgscmd{defrgba} and @vgscmd{defhsla} assign a color to a variable, by providing +an expression for each color component: + +@itemize +@item +For @vgscmd{defrgba}: @emph{red}, @emph{green}, @emph{blue}, and +@emph{alpha}. + +@item +For @vgscmd{defhsla}: @emph{hue}, @emph{saturation}, @emph{lightness}, and +@emph{alpha}. +@end itemize + +Each color component must be in range @code{0} to @code{1}, except +@emph{hue}, which is @code{0} to @code{360}. + +@codeexample{ +@example +defrgba colorA 1 0.5 0.25 1 // colorA = RGB(255, 127, 63) +defhsla colorB 200 0.75 0.25 1 // colorB = HSL(200, 75%, 25%) + +rect 0 0 (w / 2) h +setcolor colorA +fill + +rect (w / 2) 0 (w / 2) h +setcolor colorB +fill +@end example +} + +@anchor{transformation matrix} +@section Transformations + +The coordinates for each command can be scaled, rotated, and translated, +by using the following commands: + +@itemize +@item @vgscmd{rotate} +@item @vgscmd{scale} +@item @vgscmd{scalexy} +@item @vgscmd{translate} +@end itemize + +The transformations are applied when the command is executed. They have +no effect on the existing path, only on the new segments added to it. + +They are done by updating the +@uref{https://www.cairographics.org/manual/cairo-Transformations.html,current +transformation matrix} in the Cairo context. To reset the matrix to its +original state, before any transformation, use @vgscmd{resetmatrix}. + +The transform origin for scale and rotation is initially at @code{0, 0}, +but it can be adjusted with @vgscmd{translate}. + +@codeexample{ +@example +// Map (0, 0) as the center of the frame. +translate (w / 2) (h / 2) + +// Scale the space as if the frame is 1x1 pixel. +scalexy w h + +// Draw multiple lines with the same arguments, +// but each one on a different rotation. +repeat 10 @{ + rotate (PI / 10) + M -0.25 0 + H 0.25 +@} + +// Reset transformations, so the scale does not +// affect stroke. +resetmatrix + +stroke +@end example +} + +@anchor{State Stack} +@section State Stack + +The state of a drawvg script contains all parameters used for drawing +operations, like the current color, the transformation matrix, the +stroke configuration, etc. + +The @vgscmd{save} command pushes a snapshot of the state to an internal +stack. Later, @vgscmd{restore} pops the latest snapshot from the stack, +and uses it as the new state. + +The parameters that can be saved and restored are: + +@itemize +@item +Pattern for stroke and fill operations. + +@itemize +@item @vgscmd{lineargrad} +@item @vgscmd{radialgrad} +@item @vgscmd{setrgba} +@item @vgscmd{setcolor} +@item @vgscmd{sethsla} +@end itemize + +@item Transformation matrix. + +@itemize +@item @vgscmd{resetmatrix} +@item @vgscmd{rotate} +@item @vgscmd{scale} +@item @vgscmd{scalexy} +@item @vgscmd{translate} +@end itemize + +@item Stroke configuration. + +@itemize +@item @vgscmd{setdash} +@item @vgscmd{setdashoffset} +@item @vgscmd{setlinecap} +@item @vgscmd{setlinejoin} +@item @vgscmd{setlinewidth} +@end itemize + +@item +Clip region + +@itemize +@item @vgscmd{clip} +@item @vgscmd{resetclip} +@end itemize + +@end itemize + +@anchor{Frame Metadata} +@section Frame Metadata + +Some FFmpeg filters add metadata to frames. The command +@vgscmd{getmetadata} can read metadata items containing a numeric value, +and store it in a variable that can be used for command arguments. + +@codeexample{ +The @code{cropdetect} filter computes the parameters to remove empty +regions around the video. These parameters are accessible in the +@code{lavfi.cropdetect} keys of the frame metadata. + +@example +// Get metadata from cropdetect filter and store it +// in `cd*` variables. +getmetadata cdx lavfi.cropdetect.x +getmetadata cdy lavfi.cropdetect.y +getmetadata cdw lavfi.cropdetect.w +getmetadata cdh lavfi.cropdetect.h + +rect cdx cdy cdw cdh +setcolor yellow@@0.5 +setlinewidth 10 +stroke +@end example + +To test the script, copy it to a @code{drawcropdetect.vgs} file, and +then execute a command like this: + +@example +ffplay -i example-video.webm -vf 'cropdetect, drawvg=file=drawcropdetect.vgs' +@end example +} + +@section @code{if} / @code{repeat} Statements + +There is limited support for control flow statements: only @vgscmd{if} and +@vgscmd{repeat}. + +Both commands receive two arguments: an expression and a block. + +@example +if (condition) @{ + // commands +@} + +repeat (count) @{ + // commands +@} +@end example + +@vgscmd{if} executes its block if the result of @code{(condition)} is not +zero. + +@vgscmd{repeat} executes its block the number of times specified by +@code{(count)}. In each iteration, the variable @var{i} is used as a +@uref{https://en.wikipedia.org/wiki/For_loop#Loop_counters,loop +counter}. + +If the result of the expression is not a finite number (like +@uref{https://en.wikipedia.org/wiki/NaN,@code{NaN}}) the block is not +executed. + +@anchor{comp-operators} +@subsection Comparison and Logical Operators + +@ffexprs{} only supports arithmetic operators (like @code{+} for addition). +Comparison operators (like @code{!=}) are supported via functions, while +logical operators (like @code{&&} for @code{AND}) can be emulated with +arithmetic operations. + +@multitable @columnfractions .5 .5 +@headitem Expression @tab FFmpeg Equivalent +@item @code{x = y} @tab @code{eq(x, y)} +@item @code{x < y} @tab @code{lt(x, y)} +@item @code{x > y} @tab @code{gt(x, y)} +@item @code{x ≤ y} @tab @code{lte(x, y)} +@item @code{x ≥ y} @tab @code{gte(x, y)} +@item @code{a ≤ x ≤ b} @tab @code{between(x, a, b)} +@end multitable + +Logical operators can be emulated with multiplication (for @code{AND}), +or addition (for @code{OR}): + +@multitable @columnfractions .5 .5 +@headitem Expression @tab FFmpeg Equivalent +@item @code{x OR y} @tab @code{x + y} +@item @code{x AND y} @tab @code{x * y} +@end multitable + +@codeexample{ +In other programming languages, a code like this: + +@example +if (x > y && z != 1) @{ + // … +@} +@end example + +Can be written for drawvg like this: + +@example +if (gt(x, y) * not(eq(z, 1))) @{ + // … +@} +@end example +} + +@subsection Early Exit +@vgscmd{break} causes a @vgscmd{repeat} loop to be terminated immediately. + +If it is executed outside a @vgscmd{repeat} block, it terminates the whole +script, or the current procedure. + +@codeexample{ +In this example, we are using the @ref{func-randomg,@code{randomg}} function +to draw a line with random segments. + +The loop can be executed @code{500} times, but it is interrupted if the X +coordinate of the @ref{current point} (@var{cx}) exceeds the frame width +(@var{w}). The @ref{current point} is updated after each call to +@vgscmd{rlineto}. + +@example +moveto 0 0 + +repeat 500 @{ + rlineto + (randomg(0) * 15) + (randomg(0) * 20) + + if (gt(cx, w)) @{ + break + @} +@} + +stroke +@end example +} + +@anchor{Procedures} +@section Procedures + +A procedure is a name associated with a block that can be executed +multiple times. It can take between 0 and 6 parameters. + +@vgscmd{proc} is used to set the parameter names and the block for a +procedure: + +@example +proc p0 @{ + // … +@} + +proc p1 param1 param2 @{ + // … +@} +@end example + +Inside the block, the arguments can be accessed as regular variables: + +@example +proc square center_x center_y side @{ + rect + (center_x - side / 2) (center_y - side / 2) + side side +@} +@end example + +@vgscmd{call} executes the block assigned to the procedure name. It +requires the name of the procedure, and the value for each parameter +defined in the call to @vgscmd{proc}. + +@example +call p0 + +call p1 1 2 + +call square (w / 2) (h / 2) (w / t) +@end example + +@codeexample{ +In this example, the procedure @code{zigzag} draws multiple lines from +the @ref{current point}. + +@example +setvar len (w / 10) +setlinewidth 5 + +proc zigzag @{ + repeat 10 @{ + l len len len (-len) + @} + + stroke +@} + +setcolor #40C0FF +M 0 60 +call zigzag + +setcolor #00AABB +M 0 120 +call zigzag + +setcolor #20F0B7 +M 0 180 +call zigzag +@end example + +The color and the Y coordinate of the starting point can be sent as +procedure arguments: + +@example +setvar len (w / 10) +setlinewidth 5 + +proc zigzag color y @{ + setcolor color + + M 0 y + repeat 10 @{ + l len len len (-len) + @} + + stroke +@} + +call zigzag #40C0FF 60 +call zigzag #00AABB 120 +call zigzag #20F0B7 180 +@end example +} + +When the procedure returns, the value of the variable for each argument +is restored to the value it had before calling the procedure. Changes in +other variables (with @vgscmd{setvar}, @vgscmd{getmetadata}, @vgscmd{defhsla}, +and @vgscmd{defrgba}) are preserved. + +@codeexample{ +In the next example, the variable @var{A} has the value @code{0} before +calling the procedure @var{P}. During the execution of @var{P}, +@code{A} is @code{1}, but after it, @var{A} is @code{0} again. + +@example +setvar A 0 + +proc P A @{ + print A +@} + +print A +call P 1 +print A +@end example + +It writes the following messages: + +@verbatim +[7:7] A = 0.000 +[4:8] A = 1.000 +[9:7] A = 0.000 +@end verbatim +} + +@vgscmd{break} causes the script to leave the current procedure, similar +to the +@uref{https://en.wikipedia.org/wiki/Return_statement,@code{return} +statement} in other programming languages, unless it is called within a +@vgscmd{repeat} loop. + +The body of the procedure must be defined with @vgscmd{proc} @emph{before} +using @vgscmd{call}. + +@codeexample{ +In this example, when the procedure @code{notyet} is called, its body +has not yet defined, so the execution fails with the error +@code{Missing body for procedure 'notyet'}. + +@example +call notyet + +proc notyet @{ + // ... +@} +@end example +} + +A procedure can be redefined by other calls to @vgscmd{proc} with the same +name. In such case, @vgscmd{call} invokes the last assigned block. + +@codeexample{ +In this example, the procedure @code{example} has two different blocks. + +@example +proc example @{ + // block1 +@} + +call example // executes block1 + +proc example @{ + // block2 +@} + +call example // executes block2 +@end example +} + +@section Functions in Expressions + +There are some functions specific to drawvg available in @ffexprs{}. + +@subsection Function @code{p} + +@code{p(x, y)} returns the color of the pixel at coordinates @code{x, y}, as a +@code{0xRRGGBBAA} value. It can be assigned to a variable, so the color can be +available for @vgscmd{setcolor} and @vgscmd{colorstop} commands. + +If a single expression contains multiple calls to the function, it must return +the value of the last call in order to use it as a color. + +@codeexample{ +In this example, the first call to @code{p(0, 0)} is stored in the variable +@var{0} of the expression. Then, the same expression makes a second call to +@code{p(1, 1)}, and finally it returns the value in the variable @var{0}. + +@example +setvar pixel (st(0, p(0, 0)); p(1, 1); ld(0)) +@end example + +Since the result of the expression is not the last call to @code{p}, the +variable @var{pixel} can not be used as a color, but it still can be used as +a numeric @code{0xRRGGBBAA} value. +} + +If the coordinates are outside the frame, or any of the arguments is not +a finite number (like +@uref{https://en.wikipedia.org/wiki/NaN,@code{NaN}}), the function +returns @code{NaN}. + +The @ref{transformation matrix} is applied to the +arguments. To use the original frame coordinates, call +@vgscmd{resetmatrix} between @vgscmd{save} and @vgscmd{restore}: + +@example +save +resetmatrix +setvar pixel (p(0, 0)) // top-left pixel of the frame. +restore + +setcolor pixel +@end example + +Bitwise operations can be used to extract individual color components: + +@example +setvar pixel (p(x, y)) + +if (not(isnan(pixel))) @{ + setvar px_red (pixel / 0x1000000) + setvar px_green (bitand(pixel / 0x10000, 0xFF)) + setvar px_blue (bitand(pixel / 0x100, 0xFF)) + setvar px_alpha (bitand(pixel, 0xFF)) +@} +@end example + +@subsection Function @code{pathlen} + +@code{pathlen(n)} computes the length of the current path, by adding the +length of each line segment returned by +@uref{https://www.cairographics.org/manual/cairo-Paths.html#cairo-copy-path-flat,@code{cairo_copy_path_flat}}. + +The function expects an argument @var{n}, as the maximum number of line +segments to add to the length, or @code{0} to add all segments. + +@codeexample{ +In this example, @code{pathlen} is used to animate the stroke of a +spiral, in a 5 seconds loop. + +@example +M (w / 2) (h / 2) + +setvar a -1 +repeat 16 @{ + rcurveto + (a * 2 / 3) 0 + (a * 2 / 3) (a) + 0 (a) + + setvar a (-sgn(a) * (abs(a) + 10)) +@} + +setlinewidth 3 +setdash + (pathlen(0) * (1 - mod(t / 5, 1))) + 1e6 + +setcolor teal +stroke +@end example +} + +@anchor{func-randomg} +@subsection Function @code{randomg} + +@code{randomg(idx)} is similar to the @code{random(idx)} function, +available in @ffexprs{}, but its state is global to the frame, instead +of specific to each expression. + +To understand the difference, we need to dive into how +@code{random(idx)} works inside a drawvg script. + +First, each expression in FFmpeg has a set of 10 internal variables, +which can be written with @code{st(idx, value)}, and can be read with +@code{ld(idx)}. @var{idx} is a value between @code{0} and @code{9}. +These variables are initialized to @code{0}. + +When a drawvg script is parsed, each expression is compiled with +@uref{https://ffmpeg.org/doxygen/8.0/eval_8h.html#ad3bf8f3330d1fd139de2ca156c313f34,@code{av_expr_parse}}, +from @uref{https://ffmpeg.org/libavutil.html,libavutil}, and these +compiled expressions are reused for every frame. The changes in the +internal variables (with @code{st(idx, value)}) are visible between +frames, but they are not shared between expressions. + +@codeexample{ +In this example, the expression for the X coordinate updates its +internal variable @code{0} in every frame: + +@example +circle + (st(0, mod(ld(0) + 15, w))) // X + 120 // Y + (ld(0) + 20) // radius + +fill +@end example + +@code{st(idx, value)} returns the updated value, so it can be used as +the result of the expression. + +The radius is not affected because its internal variable (from +@code{ld(0)}) is not updated by the other expression. + +Also, note that this example is just to show how internal variables are +kept between frames. A better approach to create this animation is to +use the variables n or t: + +@example +circle (mod(n * 15, w)) 120 20 +fill +@end example +} + +The function @code{random(idx)} returns a +@uref{https://en.wikipedia.org/wiki/Pseudorandom_number_generator,pseudorandom} +value between @code{0} and @code{1}. @var{idx} is the internal variable +that is used both as the seed and to keep the state of the number +generator. + +@codeexample{ +The next example uses @code{random(0)} to generate a random value for +the center of a circle: + +@example +circle + (random(0) * w) + (random(0) * h) + 10 + +fill +@end example + +The circle in every frame is at a different position, but always on the +diagonal line of the frame. This happens because the values for the +coordinates X and Y are identical, since both number generators use the +same seed. + +To distribute the circles over the whole frame we need different seeds +for each expression. This can be achieved by writing a non-zero value +(like @code{0xF0F0}) to the internal variable of one of expressions, but +only when its value is @code{0}: + +@example +circle + (random(0) * w) + (st(0, if(ld(0), ld(0), 0xF0F0)); random(0) * h) + 10 + +fill +@end example + +This approach is only useful if we need completely different positions +in each frame. In the next example, random values are used to distribute +many circles over the frame, but the position is fixed. The only change +over time is the fill color: + +@example +repeat 20 @{ + circle + (st(0, i + 1e5); random(0) * w) + (st(0, i + 1e10); random(0) * h) + 10 +@} + +sethsla (t * 60) 0.5 0.5 1 +preserve fill + +setcolor black@@0.5 +setlinewidth 1 +stroke +@end example + +This is achieved by using a precomputed state before calling @code{random(0)}. +The variable @var{i}, updated by @vgscmd{repeat}, is needed to compute +different states in each iteration. +} + +The @code{randomg(idx)} function, which is specific to drawvg scripts, +is similar to @code{random(idx)}, but intended to solve the previous +problems: + +@itemize +@item All frames have the same seed. +@item The state is shared between expressions. +@end itemize + +The parameter @var{idx} has two uses: + +@itemize +@item +The last two bits are the index of an internal state, so it is possible +to have 4 different number generators. + +@item +The first call to @code{randomg} with a specific index will use the +argument as the seed for the number generator in that index. +@end itemize + +In a script like this: + +@example +M (randomg(0xFF1)) (randomg(0xFF0)) +l (randomg(0xAA1)) (randomg(0xFF0)) +@end example + +There are 4 calls to @code{randomg}: + +@enumerate +@item +The first call, with the argument @code{0xFF1}, uses the internal state +at index @code{1} (because @code{0xFF1} modulo @code{4} is @code{1}). + +Since this is the first use of that index, the number generator is +initialized with the seed @code{0xFF1}. + +@item +The second call has the same behaviour: it initializes the state at +index @code{0} with the value @code{0xFF0}. + +@item +The third call has the argument @code{0xAA1}, and it uses index +@code{1}. Since that state is already initialized (with the seed +@code{0xFF1}), the value @code{0xAA1} is ignored, and it returns the +next number. + +@end enumerate + +@codeexample{ +This example renders a simple rain animation, moving lines from top to +bottom. + +@code{randomg} is used to distribute the lines over the frame, and to +apply different speeds to each one. + +@example +rect 0 0 w h +setcolor midnightblue +fill + +setcolor white + +repeat 50 @{ + setvar offset (t * (randomg(0) + 1)) + + moveto + (mod(randomg(0) + offset / 6, 1) * w) + (mod(randomg(0) + offset, 1) * h) + + rlineto 6 36 + + setlinewidth (randomg(1) / 2 + 0.2) + stroke +@} +@end example +} + +@section Tracing with @code{print} + +It is possible to trace the execution of a drawvg script by printing the +value of an expression, either with the @vgscmd{print} command, or with +the print function. + +In both cases, the values are written to the FFmpeg log. + +Printing expressions may have a noticeable impact on the performance, so +it is preferable to use it only when necessary. + +@subsection Function print + +The function @code{print(t)} writes the value of t, and returns its +argument. + +@codeexample{ +Given a line line this: + +@example +M (sin(2 * PI * t) * w) 0 +@end example + +We can see the values of @code{sin(2 * PI * t)} by surrounding it with a +call to @code{print()}: + +@example +M (print(sin(2 * PI * t)) * w) 0 +@end example + +Executing this script with a 1 second / 8 FPS video shows the expected +values for the sine function. + +@verbatim +$ ffmpeg \ + -f lavfi \ + -i 'color=r=8:d=1, drawvg=M (print(sin(2 * PI * t)) * w) 0' \ + -f null /dev/null \ + |& grep 'Eval @' + +[Eval @ 0x7f500f502d20] 0.000000 +[Eval @ 0x7f4ff784b420] 0.707107 +[Eval @ 0x7f4ff784ba20] 1.000000 +[Eval @ 0x7f4ff784c020] 0.707107 +[Eval @ 0x7f4ff784c620] 0.000000 +[Eval @ 0x7f4ff784cc20] -0.707107 +[Eval @ 0x7f4ff784d220] -1.000000 +[Eval @ 0x7f4ff784d820] -0.707107 +@end verbatim +} + +@anchor{Command print} +@subsection Command @code{print} + +The command @vgscmd{print} accepts an arbitrary number of arguments, and +for each one it writes: + +@itemize +@item +The source location (line and column). +@item +The source code of the expression. +@item +The result of evaluating the expression. +@end itemize + +When there are multiple expressions, they are separated by the @code{|} +character. + +@codeexample{ +The next script prints the position of the @ref{current point} after the +@vgscmd{l} command: + +@example +M 10 20 +l 100 100 +print cx cy +stroke +@end example + +For each frame, it produces this output: + +@verbatim +[3:7] cx = 110.000000 | [3:10] cy = 120.000000 +@end verbatim + +The next example prints the values of @code{random(0)}: + +@verbatim +$ ffmpeg \ + -f lavfi \ + -i 'color=r=8:d=1, drawvg=print (random(0))' \ + -f null /dev/null \ + |& grep 'drawvg @' + +[drawvg @ 0x50a000000180] [1:7] (random(0)) = 0.229731 +[drawvg @ 0x50a000000180] [1:7] (random(0)) = 0.959813 +[drawvg @ 0x50a000000180] [1:7] (random(0)) = 0.071676 +[drawvg @ 0x50a000000180] [1:7] (random(0)) = 0.044600 +[drawvg @ 0x50a000000180] [1:7] (random(0)) = 0.134127 +[drawvg @ 0x50a000000180] [1:7] (random(0)) = 0.320513 +[drawvg @ 0x50a000000180] [1:7] (random(0)) = 0.857675 +[drawvg @ 0x50a000000180] [1:7] (random(0)) = 0.562456 +@end verbatim +} + +@chapter Commands + +@macro signature {sig} +@b{@code{\sig\}} +@end macro + +@macro signatureimpl {sig} +@signature{\sig\} @ @ @ --- @ref{implicit commands,@i{Can be implicit}} +@end macro + +@anchor{cmd_arc} +@section @code{arc} + +@signatureimpl{arc @var{xc} @var{yc} @var{radius} @var{angle1} @var{angle2}} + +Adds a circular arc of the given @var{radius} to the current path. The +arc is centered at @var{xc, yc}, begins at @var{angle1} and proceeds +in the direction of increasing angles to end at @var{angle2}. + +If there is a @ref{current point}, a line is added from it to the beginning of +the arc. If this is not desired, use @vgscmd{newpath} before @vgscmd{arc} to clear +the @ref{current point}. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-Paths.html#cairo-arc,@code{cairo_arc}} +function for more details. + +@codeexample{ +@example +arc 120 120 60 0 (3 * PI / 2) +stroke +@end example +} + +@anchor{cmd_arcn} +@section @code{arcn} + +@signatureimpl{arcn @var{xc} @var{yc} @var{radius} @var{angle1} @var{angle2}} + +Similar to @vgscmd{arc}, but it differs in the direction of the arc +between the two angles. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-Paths.html#cairo-arc-negative,@code{cairo_arc_negative}} +function for more details. + +@codeexample{ +In this example, both @vgscmd{arc} and @vgscmd{arcn} have the same angles, +but they render different arcs: + +@example +arc 120 90 60 (PI / 2) 0 + +newpath +arcn 120 150 60 (PI / 2) 0 + +stroke +@end example +} + +@vgscmd{newpath} is needed to prevent a line between the two arcs. + +@anchor{cmd_break} +@section @code{break} + +@signature{break} + +@vgscmd{break} terminates the execution of the innermost block, either a +@vgscmd{repeat} loop or a procedure. + +If it is used outside of a @vgscmd{repeat} / @vgscmd{proc} block, it +terminates the script for the current frame. + +@anchor{cmd_call} +@section @code{call} + +@signature{call @var{name} @var{args}*} + +Invokes a procedure defined by @vgscmd{proc}. + +See the @ref{Procedures} section above for more details. + +@anchor{cmd_circle} +@section @code{circle} + +@signatureimpl{circle @var{xc} @var{yc} @var{radius}} + +Adds a circle of the given @var{radius} to the current path. The circle +is centered at @var{xc, yc}. The @ref{current point} is cleared before and +after adding the circle. + +This is a convenience wrapper for @vgscmd{arc}. A call to @vgscmd{circle} is +equivalent to: + +@example +newpath +arc xc yc radius (0) (2 * PI) +newpath +@end example + +@anchor{cmd_clip} +@anchor{cmd_eoclip} +@section @code{clip}, @code{eoclip} + +@signature{clip, eoclip} + +Establishes a new clip region by intersecting the current clip region +with the current path as it would be filled by @vgscmd{fill} or +@vgscmd{eofill}. + +@vgscmd{eoclip} uses the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#CAIRO-FILL-RULE-EVEN-ODD:CAPS,even--odd +rule}. See @ref{fill rules} for more details. + +The path is cleared after updating the clip region, unless the +@vgscmd{preserve} command is used before @vgscmd{clip} or @vgscmd{eoclip}. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-clip,@code{cairo_clip}} +function for more details. + +@anchor{cmd_Z} +@anchor{cmd_z} +@anchor{cmd_closepath} +@section @code{Z}, @code{z}, @code{closepath} + +@signature{Z, z, closepath} + +Adds a line segment to the path from the @ref{current point} to the beginning +of the current sub-path, and closes this sub-path. The beginning is set by any +of the @emph{move} commands (@vgscmd{M}, @vgscmd{m}, @vgscmd{moveto}, +@vgscmd{rmoveto}). + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-Paths.html#cairo-close-path,@code{cairo_close_path}} +function for more details. + +@anchor{cmd_colorstop} +@section @code{colorstop} + +@signatureimpl{colorstop @var{offset} @var{color}} + +Adds a color stop to a gradient pattern. + +@var{offset} is a value between @code{0} and @code{1}, and it specifies +the location along the gradient's control vector. + +This command must be executed after @vgscmd{lineargrad} or +@vgscmd{radialgrad}. + +Color stops can be added in any number of calls to @vgscmd{colorstop}. In +the next example, the 3 blocks define the same gradient: + +@example +// 1 +colorstop 0.0 red +colorstop 0.5 green +colorstop 1.0 blue + +// 2 +colorstop 0 red 0.5 green +colorstop 1 blue + +// 3 +colorstop 0 red 0.5 green 1 blue +@end example + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-cairo-pattern-t.html#cairo-pattern-add-color-stop-rgba,@code{cairo_pattern_add_color_stop_rgba}} +function for more details. + +@codeexample{ +In this example, color stops are added in a @vgscmd{repeat} loop. + +@example +lineargrad 0 0 w h + +repeat 6 @{ + defhsla s (i * 60) 0.8 0.5 1 + colorstop (i / 5) s +@} + +rect 0 0 w h +fill +@end example + +It is possible to avoid transitions between color stops by repeating the +same color in two stops: + +@example +lineargrad 0 0 w h + +repeat 6 @{ + defhsla s (i * 60) 0.8 0.5 1 + colorstop (i / 5) s + colorstop ((i + 1) / 5) s +@} + +rect 0 0 w h +fill +@end example +} + +@anchor{cmd_C} +@anchor{cmd_curveto} +@section @code{C}, @code{curveto} + +@signatureimpl{C, curveto @var{x1} @var{y1} @var{x2} @var{y2} @var{x} @var{y}} + +Draw a cubic Bézier curve from the @ref{current point} to the @emph{end point} +specified by @var{x, y}. The @emph{start control point} is specified by +@var{x1, y1} and the @emph{end control point} is specified by @var{x2, y2}. + +@macro mdncubicbeziercurve +@uref{https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/d#cubic_b%C3%A9zier_curve,Cubic Bézier Curve on MDN} +@end macro + +@macro mdntutorialcurve +@uref{https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorials/SVG_from_scratch/Paths#curve_commands,Curve Commands section of the Paths tutorial on MDN} +@end macro + +The behaviour is identical to the @vgscmd{C} command in @svgpathlink{}. For more +details, see @mdncubicbeziercurve{}, and the @mdntutorialcurve{}. + +@codeexample{ +@example +moveto 20 20 + +curveto + 0 (h / 2) // start control point + w (h / 2) // end control point + (w - 20) (h - 20) // end point + +stroke +@end example +} + +@anchor{cmd_c} +@anchor{cmd_rcurveto} +@section @code{c}, @code{rcurveto} + +@signatureimpl{c, rcurveto @var{dx1} @var{dy1} @var{dx2} @var{dy2} @var{dx} @var{dy}} + +Like @vgscmd{curveto}, but the coordinates are relative to the @ref{current +point}. + +@anchor{cmd_defhsla} +@section @code{defhsla} + +@signature{defhsla varname @var{h} @var{s} @var{l} @var{a}} + +Similar to @vgscmd{sethsla}, but instead of establishing the color for +stroke and fill operations, the computed color is assigned to the +variable @var{varname}. + +@var{varname} can then be used as a color for @vgscmd{setcolor} and +@vgscmd{colorstop}. + +See @vgscmd{sethsla} for more details on how the color is computed. + +@anchor{cmd_defrgba} +@section @code{defrgba} + +@signature{defrgba varname @var{r} @var{g} @var{b} @var{a}} + +Computes a color from the @emph{red}, @emph{green}, @emph{blue}, and +@emph{alpha} components, and assigns it to the variable @var{varname}. + +All components are values between @code{0} and @code{1}. Values outside +that range are clamped to it. + +@anchor{cmd_ellipse} +@section @code{ellipse} + +@signatureimpl{ellipse @var{cx} @var{cy} @var{rx} @var{ry}} + +Adds an ellipse to the current path. Similar to @vgscmd{circle}, but it is +possible to use different radius for both axes. + +@codeexample{ +@verbatim +ellipse 120 120 75 50 +stroke +@end verbatim +} + +@anchor{cmd_fill} +@anchor{cmd_eofill} +@section @code{fill}, @code{eofill} + +@signature{fill, eofill} + +Fill the current path, using the @ref{current pattern} (either +a solid color or a gradient). + +@vgscmd{eofill} uses the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#CAIRO-FILL-RULE-EVEN-ODD:CAPS,even--odd +rule}. See @ref{fill rules} for more details. + +The path is cleared after the operation, unless the @vgscmd{preserve} +command is used before @vgscmd{fill} or @vgscmd{eofill}. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-fill,@code{cairo_fill}} +function for more details. + +@anchor{cmd_getmetadata} +@section @code{getmetadata} + +@signature{getmetadata @var{varname} @var{key}} + +Get the value of a metadata entry created by another filter, and assign +it to the variable @var{varname}. + +If there is no metadata entry for @var{key}, or its value is not a +number, @var{varname} is set to +@uref{https://en.wikipedia.org/wiki/NaN,@code{NaN}}. + +See the @ref{Frame Metadata} section above for an +example. + +@anchor{cmd_H} +@anchor{cmd_h} +@section @code{H}, @code{h} + +@signatureimpl{H, h @var{x}} + +Draw a horizontal line from the @ref{current point} to x. + +The coordinate for @vgscmd{H} is absolute, and for @vgscmd{h} it is relative +to the @ref{current point}. + +@anchor{cmd_if} +@section @code{if} + +@signature{if @var{condition} @{ @var{block} @}} + +Executes a block if the value of @var{condition} is not zero, and a +finite number (unlike +@uref{https://en.wikipedia.org/wiki/NaN,@code{NaN}}). + +See the @ref{comp-operators,Comparison and Logical Operators} section +above for more details on how to write conditional expressions. + +@anchor{cmd_lineargrad} +@section @code{lineargrad} + +@signature{lineargrad @var{x0} @var{y0} @var{x1} @var{y1}} + +Set the @ref{current pattern} to a new linear gradient, along +the line from the coordinates @var{x0, y0} to @var{x1, y1}. + +This gradient can be used for stroke and fill operations. + +Use @vgscmd{colorstop} to set the color for each position in the gradient. + +@anchor{cmd_L} +@anchor{cmd_lineto} +@section @code{L}, @code{lineto} + +@signatureimpl{L, lineto @var{x} @var{y}} + +Draw a line from the @ref{current point} to the coordinates at @var{x, y}. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-Paths.html#cairo-line-to,@code{cairo_line_to}} +function for more details. + +@anchor{cmd_l} +@anchor{cmd_rlineto} +@section @code{l}, @code{rlineto} + +@signatureimpl{l, rlineto @var{dx} @var{dy}} + +Like @vgscmd{lineto}, but the coordinates are relative to the @ref{current +point}. + +@anchor{cmd_M} +@anchor{cmd_moveto} +@section @code{M}, @code{moveto} + +@signatureimpl{M, moveto @var{x} @var{y}} + +Begin a new sub-path, and set the @ref{current point} to @var{x, y}. + +@anchor{cmd_m} +@anchor{cmd_rmoveto} +@section @code{m}, @code{rmoveto} + +@signatureimpl{m, rmoveto @var{dx} @var{dy}} + +Like @vgscmd{moveto}, but the coordinates are relative to the @ref{current +point}. + +@anchor{cmd_newpath} +@section @code{newpath} + +@signature{newpath} + +Begin a new sub-path. Like @vgscmd{moveto}, but there is no +@ref{current point} after it. + +@codeexample{ +In the next example, @vgscmd{newpath} is used in the path on the right to +prevent the line connecting both arcs. + +@verbatim +setlinewidth 3 + +setcolor skyblue +arcn 70 90 20 0 (PI) +arc 70 150 20 0 (PI) +stroke + +setcolor seagreen +arcn 170 90 20 0 (PI) +newpath +arc 170 150 20 0 (PI) +stroke +@end verbatim +} + +@anchor{cmd_preserve} +@section @code{preserve} + +@signature{preserve} + +Indicates that the next operation to fill, stroke, or clip, must +preserve the path, so the same path can be used in multiple operations. + +It has effect on these commands: + +@itemize +@item @vgscmd{clip} +@item @vgscmd{eoclip} +@item @vgscmd{eofill} +@item @vgscmd{fill} +@item @vgscmd{stroke} +@end itemize + +The script can contain any command between @vgscmd{preserve} and the +associated operation. This allows modifying other properties, like the +current color. + +@codeexample{ +In this example, the same path is used for both @vgscmd{fill} and +@vgscmd{stroke}, but with different colors. + +@verbatim +circle (w / 2) (h / 2) (w / 3) + +setcolor skyblue +preserve fill + +setlinewidth 10 +setcolor seagreen +stroke +@end verbatim +} + +@vgscmd{preserve} can be called multiple times, if the same path has to be +used in 3 or more operations. + +@codeexample{ +In this example, the path created by @vgscmd{circle} is used by +@vgscmd{fill}, @vgscmd{stroke}, and @vgscmd{clip}. After @vgscmd{clip}, the +path is cleared. + +@verbatim +circle 100 100 50 + +preserve fill +preserve stroke +clip +@end verbatim +} + +@anchor{cmd_print} +@section @code{print} + +@signatureimpl{print @var{expr}} + +Print its arguments to the FFmpeg log. + +See the @ref{Command print} section above for more details. + +@anchor{cmd_proc} +@section @code{proc} + +@signature{proc @var{name} @var{params}* @{ @var{block} @}} + +Assign the block and the parameters for the procedure @var{name}. The +procedure can be called multiple times with the @vgscmd{call} command. + +See the @ref{Procedures} section above for more details. + +@anchor{cmd_Q} +@section @code{Q} + +@signature{Q x1 y1 @var{x} @var{y}} + +Draw a quadratic Bézier curve from the @ref{current point} to the @emph{end +point} specified by @var{x, y}. The @emph{control point} is specified by +@var{x1, y1}. + +@macro mdnquadbeziercurve +@uref{https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/d#quadratic_b%C3%A9zier_curve,Quadratic Bézier curve on MDN} +@end macro + +The behaviour is identical to the @code{Q} command in @svgpathlink{}. For more +details, see @mdnquadbeziercurve{}, and the @mdntutorialcurve{}. + +@codeexample{ +@verbatim +moveto 20 20 + +Q + 0 h // control point + (w - 20) (h - 20) // end point + +stroke +@end verbatim +} + +@anchor{cmd_q} +@section @code{q} + +@signature{q @var{dx1} @var{dy1} @var{dx} @var{dy}} + +Like @vgscmd{Q}, but the coordinates are relative to the @ref{current point}. + +@anchor{cmd_radialgrad} +@section @code{radialgrad} + +@signature{radialgrad @var{cx0} @var{cy0} @var{radius0} @var{cx1} @var{cy1} @var{radius1}} + +Creates a new radial gradient between the two circles defined by +@var{cx0 cy0 radius0} and @var{cx1 cy1 radius1}. Each set of arguments +is the coordinates of the center and the radius. + +This gradient can be used for stroke and fill operations. + +Use @vgscmd{colorstop} to set the color for each position in the gradient. + +@codeexample{ +The animation in the next example shows how the two circles defined in +the @vgscmd{radialgrad} arguments interact with each other. + +The red circle represent the circle for the @var{cx0 cy0 radius0} +arguments, and the yellow circle is the one for the +@var{cx1 cy1 radius1} arguments. + +@verbatim +setvar cx0 (mod(t * 30, w)) +setvar cy0 120 +setvar radius0 20 + +setvar cx1 120 +setvar cy1 120 +setvar radius1 70 + +radialgrad + cx0 cy0 radius0 + cx1 cy1 radius1 + +colorstop + 0 lightblue + 1 darkblue + +// Fill the frame with the gradient. +rect 0 0 w h +fill + +// Draw inner circle. +circle cx0 cy0 radius0 +setcolor red +stroke + +// Draw outer circle. +circle cx1 cy1 radius1 +setcolor yellow +stroke +@end verbatim +} + +@anchor{cmd_rect} +@section @code{rect} + +@signature{rect @var{x} @var{y} @var{width} @var{height}} + +Adds a rectangle of the given size (@var{width} × @var{height}), at +position @var{x, y}, to the current path. The @ref{current point} is cleared +before and after adding the rectangle. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-Paths.html#cairo-rectangle,@code{cairo_rectangle}} +function for more details. + +@anchor{cmd_repeat} +@section @code{repeat} + +@signature{repeat @var{count} @{ @var{block} @}} + +Executes a block the number of times indicated by @var{count}. + +In each iteration, the variable @var{i} is used as a +@uref{https://en.wikipedia.org/wiki/For_loop#Loop_counters,loop +counter}. It takes the values from @code{0} to @code{count - 1}. When +the loop is terminated, the variable is restored to the value before +starting the loop. + +If @var{count} is less than @code{1}, or it is not a finite number +(like @uref{https://en.wikipedia.org/wiki/NaN,@code{NaN}}), the block is +not executed. + +@anchor{cmd_resetclip} +@section @code{resetclip} + +@signature{resetclip} + +Reset the current clip region to its original state, covering the whole +frame. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-reset-clip,@code{cairo_reset_clip}} +function for more details. + +@anchor{cmd_resetdash} +@section @code{resetdash} + +@signature{resetdash} + +Disable the dash pattern to be used by @vgscmd{stroke}. This reverts any +change made by @vgscmd{setdash} and @vgscmd{setdashoffset}. + +It calls +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-set-dash,@code{cairo_set_dash}} +with @code{num_dashes} set to @code{0}. + +@anchor{cmd_resetmatrix} +@section @code{resetmatrix} + +@signature{resetmatrix} + +Resets the current @ref{transformation matrix}. + +@anchor{cmd_restore} +@section @code{restore} + +@signature{restore} + +Restores the state saved by a preceding call to @vgscmd{save}. + +For more details, see the @ref{State Stack} section above, and the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-restore,@code{cairo_restore}} +function. + +@anchor{cmd_rotate} +@section @code{rotate} + +@signature{rotate @var{angle}} + +Modifies the current @ref{transformation matrix} by rotating the user-space +axes by @var{angle} radians. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-Transformations.html#cairo-rotate,@code{cairo_rotate}} +function for more details. + +@codeexample{ +In this example: + +@itemize +@item @vgscmd{scalexy} maps the coordinates to a 1x1 frame. +@item @vgscmd{translate} put @code{0, 0} at the center of the frame. +@item @vgscmd{rotate} rotates 45°. +@item +@vgscmd{resetmatrix} reverts the transformations before @vgscmd{stroke}, so the +line width is not affected by the scale. +@end itemize + +@verbatim +scalexy w h +translate 0.5 0.5 +rotate (PI / 4) +rect -0.25 -0.25 0.5 0.5 +resetmatrix +stroke +@end verbatim +} + +@anchor{cmd_roundedrect} +@section @code{roundedrect} + +@signatureimpl{roundedrect @var{x} @var{y} @var{width} @var{height} @var{radius}} + +Like @vgscmd{rect}, but a circular arc is used for the corners. + +@codeexample{ +The next example shows the same rectangle, with different values for the +corner radius. + +The radius is computed by multiplying @var{i} (the +@uref{https://en.wikipedia.org/wiki/For_loop#Loop_counters,loop counter}) by +@code{4.5}. This number is chosen to make the last shape a perfect circle. + +@example +repeat 9 @{ + roundedrect + (mod(i, 3) * 80 + 5) // x + (floor(i / 3) * 80 + 5) // y + 70 70 // size + (i * 4.5) // radius +@} + +stroke +@end example +} + +@anchor{cmd_save} +@section @code{save} + +@signature{save} + +Saves a copy of the current state on an internal stack. This copy can be +restored later with @vgscmd{restore}. + +For more details, see the @ref{State Stack} section above, and the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-save,@code{cairo_save}} +function. + +@anchor{cmd_scale} +@section @code{scale} + +@signature{scale @var{sxy}} + +Similar to @vgscmd{scalexy}, but the same value is used for both axes. It +is equivalent to: + +@signature{scalexy @var{sxy} @var{sxy}} + +@anchor{cmd_scalexy} +@section @code{scalexy} + +@signature{scalexy @var{sx} @var{sy}} + +Modifies the current @ref{transformation matrix} by scaling the X and Y +user-space axes by @var{sx} and @var{sy} respectively. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-Transformations.html#cairo-scale,@code{cairo_scale}} +function for more details. + +See @vgscmd{rotate} for an example on combining multiple transformations. + +@anchor{cmd_setcolor} +@section @code{setcolor} + +@signature{setcolor @var{color}} + +Set a solid color as the @ref{current pattern} for stroke and fill operations + +See the @ref{Colors} section above for more details. + +@anchor{cmd_setdash} +@section @code{setdash} + +@signatureimpl{setdash @var{length}} + +Sets the dash pattern to be used by @vgscmd{stroke}. + +Each call to @vgscmd{setdash} adds a length to the pattern, alternating +between @emph{on} and @emph{off} portions of the stroke. + +After a call to @vgscmd{setdash}, @vgscmd{resetdash} is needed either to +create a new pattern, or to discard the current one. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-set-dash,@code{cairo_set_dash}} +function for more details. + +@anchor{cmd_setdashoffset} +@section @code{setdashoffset} + +@signature{setdashoffset @var{offset}} + +Set the offset into the dash pattern at which the stroke should start. + +@vgscmd{setdash} must be called @emph{before} @vgscmd{setdashoffset}. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-set-dash,@code{cairo_set_dash}} +function for more details. + +@codeexample{ +The next animation shows the effect of @vgscmd{setdashoffset} when its +argument changes over time. + +@verbatim +scalexy w h +M 0.5 1 +curveto 0 0.5, 1 0.5, 0.5 0 +resetmatrix + +setdash 20 5 // 20 on, 5 off +setdashoffset (t * 100) + +setlinewidth 20 +stroke +@end verbatim +} + +@anchor{cmd_sethsla} +@section @code{sethsla} + +@signature{sethsla @var{h} @var{s} @var{l} @var{a}} + +Set the @ref{current pattern} to a solid color, given the @emph{hue}, +@emph{saturation}, and @emph{lightness}, and @emph{alpha} components. + +h is the @emph{hue}, a value between @code{0} and @code{359}. Negative +values are clamped to @code{0}, and values greater than @code{359} are +interpreted as modulo 360. + +s (@emph{saturation}), l (@emph{lightness}), and a (@emph{alpha}), are +values between @code{0} and @code{1}. + +The conversion to RGB is implemented according to the +@uref{https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB,formulae from +Wikipedia}. + +@anchor{cmd_setlinecap} +@section @code{setlinecap} + +@signature{setlinecap @var{cap}} + +Set the current line cap style, which determines the shape used to draw +the end points of lines. + +@var{cap} must be one of the following names: + +@itemize +@item @code{butt} +@item @code{round} +@item @code{square} +@end itemize + +It calls to +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-set-line-cap,@code{cairo_set_line_cap}} +to set the line cap style. + +@codeexample{ +This example draws 3 lines with the same length, each one with a +different line cap style: + +@verbatim +setlinewidth 40 + +setlinecap butt +setcolor tomato +M 60 40 v 100 stroke + +setlinecap round +setcolor seagreen +M 120 40 v 100 stroke + +setlinecap square +setcolor skyblue +M 180 40 v 100 stroke + +M 20 40 H 220 m 0 100 H 20 +setcolor black@0.5 +setlinewidth 2 +stroke +@end verbatim +} + +@anchor{cmd_setlinejoin} +@section @code{setlinejoin} + +@signature{setlinejoin @var{join}} + +Sets the current line join style, which determines the shape used to +join two line segments. + +@var{join} must be one of the following names: + +@itemize +@item @code{bevel} +@item @code{miter} +@item @code{round} +@end itemize + +It calls to +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-set-line-join,@code{cairo_set_line_join}} +to set the line join style. + +@codeexample{ +This example draws 3 lines with the same length, each one with a +different line join style: + +@verbatim +setlinewidth 30 + +setlinejoin bevel +setcolor tomato +M 70 20 l 50 50 50 -50 stroke + +setlinejoin miter +setcolor seagreen +M 70 90 l 50 50 50 -50 stroke + +setlinejoin round +setcolor skyblue +M 70 160 l 50 50 50 -50 stroke +@end verbatim +} + +@anchor{cmd_setlinewidth} +@section @code{setlinewidth} + +@signature{setlinewidth @var{width}} + +Set the line width for @vgscmd{stroke}. + +@var{width} is affected by the @ref{transformation matrix}. + +To specify a width that is not affected by other transformations, +@vgscmd{resetmatrix} can be used between @vgscmd{save} / @vgscmd{restore}: + +@verbatim +save + +resetmatrix +setlinewidth 1 +stroke + +// Restore matrix after stroke. +restore +@end verbatim + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-set-line-width,@code{cairo_set_line_width}} +function for more details. + +@anchor{cmd_setrgba} +@section @code{setrgba} + +@signature{setrgba @var{r} @var{g} @var{b} @var{a}} + +Set the @ref{current pattern} to a solid color, given the +@emph{red}, @emph{green}, @emph{blue}, and @emph{alpha} components. + +All components are values between @code{0} and @code{1}. Values outside +that range are clamped to it. + +@anchor{cmd_setvar} +@section @code{setvar} + +@signature{setvar @var{varname} @var{value}} + +Set the variable @var{varname} to @var{value}. + +See the @ref{User Variables} section above for more details. + +@anchor{cmd_stroke} +@section @code{stroke} + +@signature{stroke} + +Strokes the current path according to the current line width, line join, +line cap, and dash settings. + +The path is cleared after the operation, unless the @vgscmd{preserve} +command is used before @vgscmd{stroke}. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-stroke,@code{cairo_stroke}} +function for more details. + +@anchor{cmd_S} +@anchor{cmd_s} +@section @code{S}, @code{s} + +@signatureimpl{S, s @var{x2} @var{y2} @var{x} @var{y}} + +Draw a smooth cubic Bézier curve from the @ref{current point} to the @emph{end +point} specified by @var{x, y}. The @emph{end control point} is specified by +@var{x2, y2}. + +The @emph{start control point} is the reflection of the @emph{end +control point} of the previous curve command about the @emph{current +point}. + +The behaviour is identical to the @code{S} command in @svgpathlink{}. For more +details, see @mdncubicbeziercurve{}, and the @mdntutorialcurve{}. + +@vgscmd{s} is like @vgscmd{S}, but the coordinates are relative to the @ref{current +point}. + +@codeexample{ +@example +M 20 120 + +c 25 -50, 25 50, 50 0 + +repeat 3 @{ + s 20 50, 50 0 +@} + +stroke +@end example +} + +@anchor{cmd_translate} +@section @code{translate} + +@signature{translate @var{tx} @var{ty}} + +Modifies the current @ref{transformation matrix} by +translating the user-space origin by @var{tx, ty}. + +See the documentation of the +@uref{https://www.cairographics.org/manual/cairo-Transformations.html#cairo-translate,@code{cairo_translate}} +function for more details. + +@anchor{cmd_T} +@anchor{cmd_t} +@section @code{T}, @code{t} + +@signatureimpl{T, t @var{x} @var{y}} + +Draw a smooth quadratic Bézier curve from the @ref{current point} to the +@emph{end point} specified by @var{x, y}. + +The @emph{control point} is the reflection of the @emph{control point} +of the previous curve command about the @emph{current point}. + +The behaviour is identical to the @code{T} command in @svgpathlink{}. For more +details, see @mdnquadbeziercurve{}, and the @mdntutorialcurve{}. + +@vgscmd{t} is like @vgscmd{T}, but the coordinates are relative to the +@ref{current point}. + +@codeexample{ +@example +M 20 120 + +q 10 -20, 20 0 + +repeat 9 @{ + t 20 0 +@} + +stroke +@end example +} + +@anchor{cmd_V} +@anchor{cmd_v} +@section @code{V}, @code{v} + +@signatureimpl{V, v @var{y}} + +Draw a vertical line from the @ref{current point} to y. + +The coordinate for @vgscmd{V} is absolute, and for @vgscmd{v} it is relative +to the @ref{current point}. + +@bye diff --git a/doc/encoders.texi b/doc/encoders.texi index 0749417db..610ec9a04 100644 --- a/doc/encoders.texi +++ b/doc/encoders.texi @@ -106,15 +106,8 @@ debugging by setting the option to "disable". Enables the use of the long term prediction extension which increases coding efficiency in very low bandwidth situations such as encoding of voice or solo piano music by extending constant harmonic peaks in bands throughout -frames. This option is implied by profile:a aac_low and is incompatible with -aac_pred. Use in conjunction with @option{-ar} to decrease the samplerate. - -@item aac_pred -Enables the use of a more traditional style of prediction where the spectral -coefficients transmitted are replaced by the difference of the current -coefficients minus the previous "predicted" coefficients. In theory and sometimes -in practice this can improve quality for low to mid bitrate audio. -This option implies the aac_main profile and is incompatible with aac_ltp. +frames. This option is implied by profile:a aac_low. +Use in conjunction with @option{-ar} to decrease the samplerate. @item profile Sets the encoding profile, possible values: @@ -132,10 +125,6 @@ MPEG4 specifications. Long term prediction profile, is enabled by and will enable the @option{aac_ltp} option. Introduced in MPEG4. -@item aac_main -Main-type prediction profile, is enabled by and will enable the @option{aac_pred} -option. Introduced in MPEG2. - @end table If this option is unspecified it is set to @samp{aac_low}. @end table @@ -1049,7 +1038,7 @@ forces a wideband cutoff for bitrates < 15 kbps, unless CELT-only Set channel mapping family to be used by the encoder. The default value of -1 uses mapping family 0 for mono and stereo inputs, and mapping family 1 otherwise. The default also disables the surround masking and LFE bandwidth -optimzations in libopus, and requires that the input contains 8 channels or +optimizations in libopus, and requires that the input contains 8 channels or fewer. Other values include 0 for mono and stereo, 1 for surround sound with masking @@ -1391,6 +1380,48 @@ Higher is better but slower. @end table +@anchor{ffv1} +@section ffv1 + +FFv1 Encoder + +@subsection Options + +The following options are supported by FFmpeg's FFv1 encoder. + +@table @option +@item context +Sets the context size, 0 (default) is small, 1 is big. + +@item coder +Set the coder, +@table @samp +@item rice +Golomb rice coder +@item range_def +Range coder with default table +@item range_tab +Range coder with custom table +@end table + +@item slicecrc +-1 (default, automatic), 1 use crc with zero initial and final state, 2 use crc with non zero initial and final state + +@item qtable +@table @samp +@item default +default, automatic +@item 8bit +use 8bit default +@item greater8bit +use >8bit default +@end table + +@item remap_optimizer +0 - 5, default 3, how much effort the encoder puts into optimizing the remap table. + +@end table + @section GIF GIF image/animation encoder. @@ -1858,6 +1889,42 @@ ffmpeg -i input -c:v libaom-av1 -b:v 500K -aom-params tune=psnr:enable-tpl-model @end table +@section liboapv + +Advanced Professional Video codec encoder wrapper. + +This encoder requires the presence of the liboapv headers and library +during configuration. You need to explicitly configure the build with +@option{--enable-liboapv}. + +@float NOTE +Many liboapv encoder options are mapped to FFmpeg global codec options, +while unique encoder options are provided through private options. +@end float + +The apv project website is at @url{https://github.com/AcademySoftwareFoundation/openapv}. + +@subsection Options + +The following options are supported by the liboapv wrapper. + +@float NOTE +To get a more extensive documentation of the liboapv options, consult the +liboapv documentation. +@end float + +@table @option +@item preset +Set the quality-speed tradeoff [fastest, fast, medium, slow, placebo, default] + +@item qp +Set the quantization parameter value for CQP rate control mode. + +@item oapv-params (@emph{parse_apv_params}) +Set liboapvenc options using a list of @var{key}=@var{value} pairs separated +by ":". See the liboapv encoder user guide for a list of accepted parameters. +@end table + @section libsvtav1 SVT-AV1 encoder wrapper. @@ -1929,6 +1996,49 @@ by ":". See the SVT-AV1 encoder user guide for a list of accepted parameters. @end table +@section libsvtjpegxs + +SVT-JPEG-XS encoder wrapper. + +Requires the presence of the SVT-JPEG-XS headers and library during configuration. +You need to explicitly configure the build with @code{--enable-libsvtjpegxs}. + +@subsection Options + +@table @option +@item decomp_v +Set vertical decomposition level +@item decomp_h +Set horizontal decomposition level + +@item quantization +Set the quantization algorithm. +@table @samp +@item deadzone +@item uniform +@end table + +@item coding-signs +Enable Signs handling strategy +@table @samp +@item disable +@item fast +@item full +@end table + +@item coding-sigf +Enable Significance coding + +@item coding-vpred +Enable Vertical Prediction coding +@table @samp +@item disable +@item no_residuals +@item no_coeffs +@end table + +@end table + @section libjxl libjxl JPEG XL encoder wrapper. @@ -2973,6 +3083,10 @@ Quantizer curve compression factor Normally, when forcing a I-frame type, the encoder can select any type of I-frame. This option forces it to choose an IDR-frame. +@item x265-stats +Specify the file name for 2-pass stats. This is set automatically when using +the @option{-passlogfile} option. + @item udu_sei @var{boolean} Import user data unregistered SEI if available into output. Default is 0 (off). @@ -3275,14 +3389,168 @@ fastest. @end table +@section MediaCodec + +MediaCodec encoder wrapper enables hardware-accelerated video encoding on +Android device. It supports H.264, H.265 (HEVC), VP8, VP9, MPEG-4, and AV1 +encoding (whether works or not is device dependent). + +Android provides two sets of APIs: Java MediaCodec and NDK MediaCodec. The +MediaCodec encoder wrapper supports both. Note that the NDK MediaCodec API +operates without requiring JVM, but may fail to function outside the JVM +environment due to dependencies on system framework services, particularly +after Android 15. + +@table @option +@item ndk_codec @var{boolean} +Use the NDK-based MediaCodec API instead of the Java API. Enabled by default +if @code{av_jni_get_java_vm()} return NULL. + +@item ndk_async @var{boolean} +Use NDK MediaCodec in async mode. Async mode has less overhead than poll in a +loop in sync mode. The drawback of async mode is AV_CODEC_FLAG_GLOBAL_HEADER +doesn't work (use extract_extradata bsf when necessary). It doesn't work and +will be disabled automatically on devices below Android 8.0. + +@item codec_name @var{string} +A codec type can have multiple implementations on a single device, this option +specify which backend to use (via MediaCodec createCodecByName API). It's NULL +by default, and encoder is created by createEncoderByType. + +@item bitrate_mode @var{integer} + +Possible values: +@table @samp +@item cq +Constant quality mode +@item vbr +Variable bitrate mode +@item cbr +Constant bitrate mode +@item cbr_fd +Constant bitrate mode with frame drops +@end table + +@item pts_as_dts @var{boolean} +Use PTS as DTS. This is a workaround since MediaCodec API doesn't provide +decoding timestamp. It is enabled automatically if B frame is 0. + +@item operating_rate @var{integer} +The desired operating rate that the codec will need to operate at, zero for +unspecified. This is used for cases like high-speed/slow-motion video capture, +where the video encoder format contains the target playback rate (e.g. 30fps), +but the component must be able to handle the high operating capture rate (e.g. +240fps). This rate will be used by codec for resource planning and setting the +operating points. + +@item qp_i_min @var{integer} +Minimum quantization parameter for I frame. +@item qp_p_min @var{integer} +Minimum quantization parameter for P frame. +@item qp_b_min @var{integer} +Minimum quantization parameter for B frame. +@item qp_i_max @var{integer} +Maximum quantization parameter for I frame. +@item qp_p_max @var{integer} +Maximum quantization parameter for P frame. +@item qp_b_max @var{integer} +Maximum quantization parameter for B frame. + +@end table + @section MediaFoundation -This provides wrappers to encoders (both audio and video) in the -MediaFoundation framework. It can access both SW and HW encoders. +The following wrappers for encoders in the MediaFoundation framework are +available: + +@itemize +@item h264_mf +@item hevc_mf +@item av1_mf +@end itemize + +These support both software and hardware encoding. + Video encoders can take input in either of nv12 or yuv420p form (some encoders support both, some support only either - in practice, nv12 is the safer choice, especially among HW encoders). +Hardware-accelerated encoding requires D3D11, including hardware +scaling capabilities through the scale_d3d11 filter. + +To list all available options for the MediaFoundation encoders, use: +@command{ffmpeg -h encoder=} e.g. @command{ffmpeg -h encoder=h264_mf} + +@subsection Options + +@table @option +@item rate_control +Select rate control mode. Available modes: + +@table @samp +@item default +Default mode +@item cbr +CBR mode +@item pc_vbr +Peak constrained VBR mode +@item u_vbr +Unconstrained VBR mode +@item quality +Quality mode +@item ld_vbr +Low delay VBR mode (requires Windows 8+) +@item g_vbr +Global VBR mode (requires Windows 8+) +@item gld_vbr +Global low delay VBR mode (requires Windows 8+) +@end table + +@item scenario +Select usage scenario. Available scenarios: + +@table @samp +@item default +Default scenario +@item display_remoting +Display remoting scenario +@item video_conference +Video conference scenario +@item archive +Archive scenario +@item live_streaming +Live streaming scenario +@item camera_record +Camera record scenario +@item display_remoting_with_feature_map +Display remoting with feature map scenario +@end table + +@item quality +Set encoding quality (0-100). -1 means default quality. + +@item hw_encoding +Force hardware encoding (0-1). Default is 0 (disabled). + +@end table + +@subsection Examples + +Hardware encoding: +@example +ffmpeg -i input.mp4 -c:v h264_mf -hw_encoding 1 output.mp4 +@end example + +Hardware-accelerated decoding with hardware encoding: +@example +ffmpeg -hwaccel d3d11va -i input.mp4 -c:v h264_mf -hw_encoding 1 output.mp4 +@end example + +Hardware-accelerated decoding, HW scaling and encoding with quality setting: +@example +ffmpeg -hwaccel d3d11va -hwaccel_output_format d3d11 -i input.mp4 -vf scale_d3d11=1920:1080 -c:v hevc_mf -hw_encoding 1 -quality 80 output.mp4 +@end example + @section Microsoft RLE Microsoft RLE aka MSRLE encoder. @@ -3357,6 +3625,13 @@ Default is 1 (on). PNG image encoder. +@subsection Options + +@table @option +@item compression_level +Sets the compression level, from 0 to 9(default) +@end table + @subsection Private options @table @option @@ -3364,6 +3639,8 @@ PNG image encoder. Set physical density of pixels, in dots per inch, unset by default @item dpm @var{integer} Set physical density of pixels, in dots per meter, unset by default +@item pred @var{method} +Set prediction method (none, sub, up, avg, paeth, mixed), default is paeth @end table @section ProRes @@ -3558,7 +3835,7 @@ For encoders set this flag to ON to reduce power consumption and GPU usage. @end table @subsection Runtime Options -Following options can be used durning qsv encoding. +Following options can be used during qsv encoding. @table @option @item @var{global_quality} @@ -3668,7 +3945,7 @@ improves subjective visual quality. Enabling this flag may have negative impact on performance and objective visual quality metric. @item @var{low_delay_brc} -Setting this flag turns on or off LowDelayBRC feautre in qsv plugin, which provides +Setting this flag turns on or off LowDelayBRC feature in qsv plugin, which provides more accurate bitrate control to minimize the variance of bitstream size frame by frame. Value: -1-default 0-off 1-on @@ -3867,7 +4144,7 @@ improves subjective visual quality. Enabling this flag may have negative impact on performance and objective visual quality metric. @item @var{low_delay_brc} -Setting this flag turns on or off LowDelayBRC feautre in qsv plugin, which provides +Setting this flag turns on or off LowDelayBRC feature in qsv plugin, which provides more accurate bitrate control to minimize the variance of bitstream size frame by frame. Value: -1-default 0-off 1-on @@ -4101,7 +4378,7 @@ Extended bitrate control. Depth of look ahead in number frames, available when extbrc option is enabled. @item @var{low_delay_brc} -Setting this flag turns on or off LowDelayBRC feautre in qsv plugin, which provides +Setting this flag turns on or off LowDelayBRC feature in qsv plugin, which provides more accurate bitrate control to minimize the variance of bitstream size frame by frame. Value: -1-default 0-off 1-on @@ -4457,6 +4734,25 @@ Reduces detail but attempts to preserve color at extremely low bitrates. @chapter Subtitles Encoders @c man begin SUBTITLES ENCODERS +@section dvbsub + +This codec encodes the bitmap subtitle format that is used in DVB +broadcasts and recordings. The bitmaps are typically embedded in a +container such as MPEG-TS as a separate stream. + +@subsection Options + +@table @option +@item min_bpp @var{integer (2, 4, or 8)} +Set a minimum bits-per-pixel value for the subtitle color lookup tables. + +DVB supports 2, 4, and 8 bits-per-pixel color lookup tables. This +option enables forcing a particular bits-per-pixel value regardless of +the number of colors. Since not all players support or properly +support 2 bits-per-pixel, this value defaults to 4. + +@end table + @section dvdsub This codec encodes the bitmap subtitle format that is used in DVDs. @@ -4484,4 +4780,18 @@ one byte per subtitle on average. By default, this work-around is disabled. @end table +@section lrc + +This codec encodes the LRC lyrics format. + +@subsection Options + +@table @option +@item precision +Specify the precision of the fractional part of the timestamp. Time base is +determined based on this value. + +Defaults to 2 for centiseconds. +@end table + @c man end SUBTITLES ENCODERS diff --git a/doc/examples/decode_filter_audio.c b/doc/examples/decode_filter_audio.c index d637ca172..67c8a14aa 100644 --- a/doc/examples/decode_filter_audio.c +++ b/doc/examples/decode_filter_audio.c @@ -30,8 +30,6 @@ * file to be played with ffplay. */ -#include - #include #include #include @@ -96,8 +94,7 @@ static int init_filters(const char *filters_descr) const AVFilter *abuffersink = avfilter_get_by_name("abuffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); - static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 }; - static const int out_sample_rates[] = { 8000, -1 }; + static const int out_sample_rate = 8000; const AVFilterLink *outlink; AVRational time_base = fmt_ctx->streams[audio_stream_index]->time_base; @@ -123,34 +120,40 @@ static int init_filters(const char *filters_descr) } /* buffer audio sink: to terminate the filter chain. */ - ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out", - NULL, NULL, filter_graph); - if (ret < 0) { + buffersink_ctx = avfilter_graph_alloc_filter(filter_graph, abuffersink, "out"); + if (!buffersink_ctx) { av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n"); + ret = AVERROR(ENOMEM); goto end; } - ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1, - AV_OPT_SEARCH_CHILDREN); + ret = av_opt_set(buffersink_ctx, "sample_formats", "s16", + AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n"); goto end; } - ret = av_opt_set(buffersink_ctx, "ch_layouts", "mono", - AV_OPT_SEARCH_CHILDREN); + ret = av_opt_set(buffersink_ctx, "channel_layouts", "mono", + AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n"); goto end; } - ret = av_opt_set_int_list(buffersink_ctx, "sample_rates", out_sample_rates, -1, - AV_OPT_SEARCH_CHILDREN); + ret = av_opt_set_array(buffersink_ctx, "samplerates", AV_OPT_SEARCH_CHILDREN, + 0, 1, AV_OPT_TYPE_INT, &out_sample_rate); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n"); goto end; } + ret = avfilter_init_dict(buffersink_ctx, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot initialize audio buffer sink\n"); + goto end; + } + /* * Set the endpoints for the filter graph. The filter_graph will * be linked to the graph described by filters_descr. diff --git a/doc/examples/decode_filter_video.c b/doc/examples/decode_filter_video.c index b91ca56d4..62ada4bca 100644 --- a/doc/examples/decode_filter_video.c +++ b/doc/examples/decode_filter_video.c @@ -27,8 +27,6 @@ * @example decode_filter_video.c */ -#define _XOPEN_SOURCE 600 /* for usleep */ -#include #include #include @@ -38,6 +36,7 @@ #include #include #include +#include const char *filter_descr = "scale=78:24,transpose=cclock"; /* other way: @@ -99,7 +98,6 @@ static int init_filters(const char *filters_descr) AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base; - enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }; filter_graph = avfilter_graph_alloc(); if (!outputs || !inputs || !filter_graph) { @@ -122,20 +120,26 @@ static int init_filters(const char *filters_descr) } /* buffer video sink: to terminate the filter chain. */ - ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", - NULL, NULL, filter_graph); - if (ret < 0) { + buffersink_ctx = avfilter_graph_alloc_filter(filter_graph, buffersink, "out"); + if (!buffersink_ctx) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n"); + ret = AVERROR(ENOMEM); goto end; } - ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts, - AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); + ret = av_opt_set(buffersink_ctx, "pixel_formats", "gray8", + AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n"); goto end; } + ret = avfilter_init_dict(buffersink_ctx, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot initialize buffer sink\n"); + goto end; + } + /* * Set the endpoints for the filter graph. The filter_graph will * be linked to the graph described by filters_descr. @@ -190,7 +194,7 @@ static void display_frame(const AVFrame *frame, AVRational time_base) delay = av_rescale_q(frame->pts - last_pts, time_base, AV_TIME_BASE_Q); if (delay > 0 && delay < 1000000) - usleep(delay); + av_usleep(delay); } last_pts = frame->pts; } diff --git a/doc/examples/extract_mvs.c b/doc/examples/extract_mvs.c index 5603064d7..b5ed2c554 100644 --- a/doc/examples/extract_mvs.c +++ b/doc/examples/extract_mvs.c @@ -109,6 +109,7 @@ static int open_codec_context(AVFormatContext *fmt_ctx, enum AVMediaType type) ret = avcodec_parameters_to_context(dec_ctx, st->codecpar); if (ret < 0) { fprintf(stderr, "Failed to copy codec parameters to codec context\n"); + avcodec_free_context(&dec_ctx); return ret; } diff --git a/doc/examples/filter_audio.c b/doc/examples/filter_audio.c index 8b237e2ad..ad77bf1f8 100644 --- a/doc/examples/filter_audio.c +++ b/doc/examples/filter_audio.c @@ -270,7 +270,6 @@ int main(int argc, char *argv[]) AVFilterGraph *graph; AVFilterContext *src, *sink; AVFrame *frame; - uint8_t errstr[1024]; float duration; int err, nb_frames, i; @@ -295,6 +294,7 @@ int main(int argc, char *argv[]) md5 = av_md5_alloc(); if (!md5) { + av_frame_free(&frame); fprintf(stderr, "Error allocating the MD5 context\n"); return 1; } @@ -302,8 +302,10 @@ int main(int argc, char *argv[]) /* Set up the filtergraph. */ err = init_filter_graph(&graph, &src, &sink); if (err < 0) { + av_frame_free(&frame); + av_freep(&md5); fprintf(stderr, "Unable to init filter graph:"); - goto fail; + return 1; } /* the main filtering loop */ @@ -354,7 +356,10 @@ int main(int argc, char *argv[]) return 0; fail: - av_strerror(err, errstr, sizeof(errstr)); - fprintf(stderr, "%s\n", errstr); + avfilter_graph_free(&graph); + av_frame_free(&frame); + av_freep(&md5); + + fprintf(stderr, "%s\n", av_err2str(err)); return 1; } diff --git a/doc/examples/hw_decode.c b/doc/examples/hw_decode.c index ac4e44550..ce1881476 100644 --- a/doc/examples/hw_decode.c +++ b/doc/examples/hw_decode.c @@ -215,8 +215,10 @@ int main(int argc, char *argv[]) return AVERROR(ENOMEM); video = input_ctx->streams[video_stream]; - if (avcodec_parameters_to_context(decoder_ctx, video->codecpar) < 0) + if (avcodec_parameters_to_context(decoder_ctx, video->codecpar) < 0) { + avcodec_free_context(&decoder_ctx); return -1; + } decoder_ctx->get_format = get_hw_format; diff --git a/doc/examples/mux.c b/doc/examples/mux.c index 0f3a2bb12..9b22c8dd1 100644 --- a/doc/examples/mux.c +++ b/doc/examples/mux.c @@ -418,7 +418,7 @@ static void open_video(AVFormatContext *oc, const AVCodec *codec, exit(1); } - /* allocate and init a re-usable frame */ + /* allocate and init a reusable frame */ ost->frame = alloc_frame(c->pix_fmt, c->width, c->height); if (!ost->frame) { fprintf(stderr, "Could not allocate video frame\n"); diff --git a/doc/examples/qsv_decode.c b/doc/examples/qsv_decode.c index 5a6f3625a..ec9110948 100644 --- a/doc/examples/qsv_decode.c +++ b/doc/examples/qsv_decode.c @@ -219,11 +219,8 @@ int main(int argc, char **argv) ret = decode_packet(decoder_ctx, frame, sw_frame, NULL, output_ctx); finish: - if (ret < 0) { - char buf[1024]; - av_strerror(ret, buf, sizeof(buf)); - fprintf(stderr, "%s\n", buf); - } + if (ret < 0) + fprintf(stderr, "%s\n", av_err2str(ret)); avformat_close_input(&input_ctx); diff --git a/doc/examples/qsv_transcode.c b/doc/examples/qsv_transcode.c index 665a76af2..c3f507e8e 100644 --- a/doc/examples/qsv_transcode.c +++ b/doc/examples/qsv_transcode.c @@ -101,7 +101,7 @@ static int dynamic_set_parameter(AVCodecContext *avctx) /* Set codec specific option */ if ((ret = av_opt_set_dict(avctx->priv_data, &opts)) < 0) goto fail; - /* There is no "framerate" option in commom option list. Use "-r" to set + /* There is no "framerate" option in common option list. Use "-r" to set * framerate, which is compatible with ffmpeg commandline. The video is * assumed to be average frame rate, so set time_base to 1/framerate. */ e = av_dict_get(opts, "r", NULL, 0); @@ -180,7 +180,7 @@ static int open_input_file(char *filename) decoder = avcodec_find_decoder_by_name("mjpeg_qsv"); break; default: - fprintf(stderr, "Codec is not supportted by qsv\n"); + fprintf(stderr, "Codec is not supported by qsv\n"); return AVERROR(EINVAL); } @@ -289,7 +289,7 @@ static int dec_enc(AVPacket *pkt, const AVCodec *enc_codec, char *optstr) fprintf(stderr, "Failed to set encoding parameter.\n"); goto fail; } - /* There is no "framerate" option in commom option list. Use "-r" to + /* There is no "framerate" option in common option list. Use "-r" to * set framerate, which is compatible with ffmpeg commandline. The * video is assumed to be average frame rate, so set time_base to * 1/framerate. */ @@ -351,6 +351,10 @@ int main(int argc, char **argv) } setting_number = (argc - 5) / 2; dynamic_setting = av_malloc(setting_number * sizeof(*dynamic_setting)); + if (!dynamic_setting) { + ret = AVERROR(ENOMEM); + goto end; + } current_setting_number = 0; for (int i = 0; i < setting_number; i++) { dynamic_setting[i].frame_number = atoi(argv[i*2 + 5]); diff --git a/doc/examples/transcode.c b/doc/examples/transcode.c index cbe5088ef..1dc1b5050 100644 --- a/doc/examples/transcode.c +++ b/doc/examples/transcode.c @@ -171,23 +171,38 @@ static int open_output_file(const char *filename) * sample rate etc.). These properties can be changed for output * streams easily using filters */ if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { + const enum AVPixelFormat *pix_fmts = NULL; + enc_ctx->height = dec_ctx->height; enc_ctx->width = dec_ctx->width; enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio; + + ret = avcodec_get_supported_config(dec_ctx, NULL, + AV_CODEC_CONFIG_PIX_FORMAT, 0, + (const void**)&pix_fmts, NULL); + /* take first format from list of supported formats */ - if (encoder->pix_fmts) - enc_ctx->pix_fmt = encoder->pix_fmts[0]; - else - enc_ctx->pix_fmt = dec_ctx->pix_fmt; + enc_ctx->pix_fmt = (ret >= 0 && pix_fmts) ? + pix_fmts[0] : dec_ctx->pix_fmt; + /* video time_base can be set to whatever is handy and supported by encoder */ enc_ctx->time_base = av_inv_q(dec_ctx->framerate); } else { + const enum AVSampleFormat *sample_fmts = NULL; + enc_ctx->sample_rate = dec_ctx->sample_rate; ret = av_channel_layout_copy(&enc_ctx->ch_layout, &dec_ctx->ch_layout); if (ret < 0) return ret; + + ret = avcodec_get_supported_config(dec_ctx, NULL, + AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, + (const void**)&sample_fmts, NULL); + /* take first format from list of supported formats */ - enc_ctx->sample_fmt = encoder->sample_fmts[0]; + enc_ctx->sample_fmt = (ret >= 0 && sample_fmts) ? + sample_fmts[0] : dec_ctx->sample_fmt; + enc_ctx->time_base = (AVRational){1, enc_ctx->sample_rate}; } @@ -283,10 +298,10 @@ static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, goto end; } - ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", - NULL, NULL, filter_graph); - if (ret < 0) { + buffersink_ctx = avfilter_graph_alloc_filter(filter_graph, buffersink, "out"); + if (!buffersink_ctx) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n"); + ret = AVERROR(ENOMEM); goto end; } @@ -297,6 +312,12 @@ static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n"); goto end; } + + ret = avfilter_init_dict(buffersink_ctx, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot initialize buffer sink\n"); + goto end; + } } else if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { char buf[64]; buffersrc = avfilter_get_by_name("abuffer"); @@ -322,10 +343,10 @@ static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, goto end; } - ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", - NULL, NULL, filter_graph); - if (ret < 0) { + buffersink_ctx = avfilter_graph_alloc_filter(filter_graph, buffersink, "out"); + if (!buffersink_ctx) { av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n"); + ret = AVERROR(ENOMEM); goto end; } @@ -352,6 +373,15 @@ static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n"); goto end; } + + if (enc_ctx->frame_size > 0) + av_buffersink_set_frame_size(buffersink_ctx, enc_ctx->frame_size); + + ret = avfilter_init_dict(buffersink_ctx, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot initialize audio buffer sink\n"); + goto end; + } } else { ret = AVERROR_UNKNOWN; goto end; diff --git a/doc/fate.texi b/doc/fate.texi index 17644ce65..12c884047 100644 --- a/doc/fate.texi +++ b/doc/fate.texi @@ -42,41 +42,60 @@ targets and variables. @chapter Using FATE from your FFmpeg source directory -If you want to run FATE on your machine you need to have the samples -in place. You can get the samples via the build target fate-rsync. -Use this command from the top-level source directory: +If you want to run FATE on your machine, FFmpeg needs to be configured first. +You may specify the location of samples during configuration by adding the +argument @code{--samples=/path/to/fate-suite}. @example -make fate-rsync SAMPLES=fate-suite/ -make fate SAMPLES=fate-suite/ +./configure --enable-somelib --samples=/path/to/fate-suite @end example -The above commands set the samples location by passing a makefile -variable via command line. It is also possible to set the samples -location at source configuration time by invoking configure with -@option{--samples=}. Afterwards you can -invoke the makefile targets without setting the @var{SAMPLES} makefile -variable. This is illustrated by the following commands: +After successful configuration, you need to add and/or update the samples in place: @example -./configure --samples=fate-suite/ +make fate-rsync +@end example + +Now you are ready to run FATE: + +@example +make fate +@end example + +See @ref{makefile variables} for a list of arguments that can be added. + +If you did not set the samples path during configuration, or if you wish to +override it just before starting FATE, you can do so in one of three ways. + +Either by setting a make variable: + +@example +make fate-rsync SAMPLES=/path/to/fate-suite +make fate SAMPLES=/path/to/fate-suite +@end example + +or by setting an environment variable for the current session: + +@example +export FATE_SAMPLES=/path/to/fate-suite make fate-rsync make fate @end example -Yet another way to tell FATE about the location of the sample -directory is by making sure the environment variable FATE_SAMPLES -contains the path to your samples directory. This can be achieved -by e.g. putting that variable in your shell profile or by setting -it in your interactive session. +or in isolation for a single command by prepending it: @example -FATE_SAMPLES=fate-suite/ make fate +FATE_SAMPLES=/path/to/fate-suite make fate-rsync +FATE_SAMPLES=/path/to/fate-suite make fate @end example +This variable can also be set in your shell profile to make it permanent. + @float NOTE Do not put a '~' character in the samples path to indicate a home directory. Because of shell nuances, this will cause FATE to fail. +Also, on Windows the path has to be relative to the build path +which in this case is the FFmpeg source directory. @end float Beware that some assertions are disabled by default, so mind setting @@ -208,11 +227,19 @@ Download/synchronize sample files to the configured samples directory. @item fate-list Will list all fate/regression test targets. +@item fate-list-failing +List the fate tests that failed the last time they were executed. + +@item fate-clear-reports +Remove the test reports from previous test executions (getting rid of +potentially stale results from fate-list-failing). + @item fate Run the FATE test suite (requires the fate-suite dataset). @end table @section Makefile variables +@anchor{makefile variables} @table @env @item V diff --git a/doc/fate_config.sh.template b/doc/fate_config.sh.template index 6400d9dbe..8cd92ae0f 100644 --- a/doc/fate_config.sh.template +++ b/doc/fate_config.sh.template @@ -6,6 +6,7 @@ workdir= # directory in which to do all the work #fate_recv="ssh -T fate@fate.ffmpeg.org" # command to submit report comment= # optional description build_only= # set to "yes" for a compile-only instance that skips tests +skip_clean= # set to "yes" to preserve build/install directories ignore_tests= # the following are optional and map to configure options @@ -13,6 +14,7 @@ arch= cpu= toolchain= cross_prefix= +ar= as= cc= cxx= diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index 013f5f4da..2dae6632b 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -21,22 +21,24 @@ ffmpeg [@var{global_options}] @{[@var{input_file_options}] -i @file{input_url}@} inputs - including live grabbing/recording devices - filter, and transcode them into a plethora of output formats. -@command{ffmpeg} reads from an arbitrary number of input "files" (which can be regular +@command{ffmpeg} reads from an arbitrary number of inputs (which can be regular files, pipes, network streams, grabbing devices, etc.), specified by the -@code{-i} option, and writes to an arbitrary number of output "files", which are -specified by a plain output url. Anything found on the command line which -cannot be interpreted as an option is considered to be an output url. +@code{-i} option, and writes to an arbitrary number of outputs, which are +specified by a plain output url. Anything found on the command line which cannot +be interpreted as an option is considered to be an output url. -Each input or output url can, in principle, contain any number of streams of -different types (video/audio/subtitle/attachment/data). The allowed number and/or -types of streams may be limited by the container format. Selecting which -streams from which inputs will go into which output is either done automatically -or with the @code{-map} option (see the Stream selection chapter). +Each input or output can, in principle, contain any number of elementary streams +of different types (video/audio/subtitle/attachment/data), though the allowed +stream counts and/or types may be limited by the container format. Selecting +which streams from which inputs will go into which output is either done +automatically or with the @code{-map} option (see the @ref{Stream selection} +chapter). -To refer to input files in options, you must use their indices (0-based). E.g. -the first input file is @code{0}, the second is @code{1}, etc. Similarly, streams -within a file are referred to by their indices. E.g. @code{2:3} refers to the -fourth stream in the third input file. Also see the Stream specifiers chapter. +To refer to inputs/outputs in options, you must use their indices (0-based). +E.g. the first input is @code{0}, the second is @code{1}, etc. Similarly, +streams within an input/output are referred to by their indices. E.g. @code{2:3} +refers to the fourth stream in the third input or output. Also see the +@ref{Stream specifiers} chapter. As a general rule, options are applied to the next specified file. Therefore, order is important, and you can have the same @@ -85,140 +87,405 @@ The format option may be needed for raw input files. @chapter Detailed description @c man begin DETAILED DESCRIPTION -The transcoding process in @command{ffmpeg} for each output can be described by -the following diagram: +@command{ffmpeg} builds a transcoding pipeline out of the components listed +below. The program's operation then consists of input data chunks flowing from +the sources down the pipes towards the sinks, while being transformed by the +components they encounter along the way. +The following kinds of components are available: +@itemize +@item +@emph{Demuxers} (short for "demultiplexers") read an input source in order to +extract + +@itemize +@item +global properties such as metadata or chapters; +@item +list of input elementary streams and their properties +@end itemize + +One demuxer instance is created for each @option{-i} option, and sends encoded +@emph{packets} to @emph{decoders} or @emph{muxers}. + +In other literature, demuxers are sometimes called @emph{splitters}, because +their main function is splitting a file into elementary streams (though some +files only contain one elementary stream). + +A schematic representation of a demuxer looks like this: @verbatim - _______ ______________ -| | | | -| input | demuxer | encoded data | decoder -| file | ---------> | packets | -----+ -|_______| |______________| | - v - _________ - | | - | decoded | - | frames | - |_________| - ________ ______________ | -| | | | | -| output | <-------- | encoded data | <----+ -| file | muxer | packets | encoder -|________| |______________| - - +┌──────────┬───────────────────────┐ +│ demuxer │ │ packets for stream 0 +╞══════════╡ elementary stream 0 ├──────────────────────► +│ │ │ +│ global ├───────────────────────┤ +│properties│ │ packets for stream 1 +│ and │ elementary stream 1 ├──────────────────────► +│ metadata │ │ +│ ├───────────────────────┤ +│ │ │ +│ │ ........... │ +│ │ │ +│ ├───────────────────────┤ +│ │ │ packets for stream N +│ │ elementary stream N ├──────────────────────► +│ │ │ +└──────────┴───────────────────────┘ + ▲ + │ + │ read from file, network stream, + │ grabbing device, etc. + │ @end verbatim -@command{ffmpeg} calls the libavformat library (containing demuxers) to read -input files and get packets containing encoded data from them. When there are -multiple input files, @command{ffmpeg} tries to keep them synchronized by -tracking lowest timestamp on any active input stream. +@item +@emph{Decoders} receive encoded (compressed) @emph{packets} for an audio, video, +or subtitle elementary stream, and decode them into raw @emph{frames} (arrays of +pixels for video, PCM for audio). A decoder is typically associated with (and +receives its input from) an elementary stream in a @emph{demuxer}, but sometimes +may also exist on its own (see @ref{Loopback decoders}). + +A schematic representation of a decoder looks like this: +@verbatim + ┌─────────┐ + packets │ │ raw frames +─────────►│ decoder ├────────────► + │ │ + └─────────┘ +@end verbatim + +@item +@emph{Filtergraphs} process and transform raw audio or video @emph{frames}. A +filtergraph consists of one or more individual @emph{filters} linked into a +graph. Filtergraphs come in two flavors - @emph{simple} and @emph{complex}, +configured with the @option{-filter} and @option{-filter_complex} options, +respectively. + +A simple filtergraph is associated with an @emph{output elementary stream}; it +receives the input to be filtered from a @emph{decoder} and sends filtered +output to that output stream's @emph{encoder}. + +A simple video filtergraph that performs deinterlacing (using the @code{yadif} +deinterlacer) followed by resizing (using the @code{scale} filter) can look like +this: +@verbatim + + ┌────────────────────────┐ + │ simple filtergraph │ + frames from ╞════════════════════════╡ frames for + a decoder │ ┌───────┐ ┌───────┐ │ an encoder +────────────►├─►│ yadif ├─►│ scale ├─►│────────────► + │ └───────┘ └───────┘ │ + └────────────────────────┘ +@end verbatim + +A complex filtergraph is standalone and not associated with any specific stream. +It may have multiple (or zero) inputs, potentially of different types (audio or +video), each of which receiving data either from a decoder or another complex +filtergraph's output. It also has one or more outputs that feed either an +encoder or another complex filtergraph's input. + +The following example diagram represents a complex filtergraph with 3 inputs and +2 outputs (all video): +@verbatim + ┌─────────────────────────────────────────────────┐ + │ complex filtergraph │ + ╞═════════════════════════════════════════════════╡ + frames ├───────┐ ┌─────────┐ ┌─────────┐ ┌────────┤ frames +─────────►│input 0├─►│ overlay ├─────►│ overlay ├─►│output 0├────────► + ├───────┘ │ │ │ │ └────────┤ + frames ├───────┐╭►│ │ ╭►│ │ │ +─────────►│input 1├╯ └─────────┘ │ └─────────┘ │ + ├───────┘ │ │ + frames ├───────┐ ┌─────┐ ┌─────┬─╯ ┌────────┤ frames +─────────►│input 2├►│scale├►│split├───────────────►│output 1├────────► + ├───────┘ └─────┘ └─────┘ └────────┤ + └─────────────────────────────────────────────────┘ +@end verbatim +Frames from second input are overlaid over those from the first. Frames from the +third input are rescaled, then the duplicated into two identical streams. One of +them is overlaid over the combined first two inputs, with the result exposed as +the filtergraph's first output. The other duplicate ends up being the +filtergraph's second output. + +@item +@emph{Encoders} receive raw audio, video, or subtitle @emph{frames} and encode +them into encoded @emph{packets}. The encoding (compression) process is +typically @emph{lossy} - it degrades stream quality to make the output smaller; +some encoders are @emph{lossless}, but at the cost of much higher output size. A +video or audio encoder receives its input from some filtergraph's output, +subtitle encoders receive input from a decoder (since subtitle filtering is not +supported yet). Every encoder is associated with some muxer's @emph{output +elementary stream} and sends its output to that muxer. + +A schematic representation of an encoder looks like this: +@verbatim + ┌─────────┐ + raw frames │ │ packets +────────────►│ encoder ├─────────► + │ │ + └─────────┘ +@end verbatim + +@item +@emph{Muxers} (short for "multiplexers") receive encoded @emph{packets} for +their elementary streams from encoders (the @emph{transcoding} path) or directly +from demuxers (the @emph{streamcopy} path), interleave them (when there is more +than one elementary stream), and write the resulting bytes into the output file +(or pipe, network stream, etc.). + +A schematic representation of a muxer looks like this: +@verbatim + ┌──────────────────────┬───────────┐ + packets for stream 0 │ │ muxer │ +──────────────────────►│ elementary stream 0 ╞═══════════╡ + │ │ │ + ├──────────────────────┤ global │ + packets for stream 1 │ │properties │ +──────────────────────►│ elementary stream 1 │ and │ + │ │ metadata │ + ├──────────────────────┤ │ + │ │ │ + │ ........... │ │ + │ │ │ + ├──────────────────────┤ │ + packets for stream N │ │ │ +──────────────────────►│ elementary stream N │ │ + │ │ │ + └──────────────────────┴─────┬─────┘ + │ + write to file, network stream, │ + grabbing device, etc. │ + │ + ▼ +@end verbatim + +@end itemize + +@section Streamcopy +The simplest pipeline in @command{ffmpeg} is single-stream +@emph{streamcopy}, that is copying one @emph{input elementary stream}'s packets +without decoding, filtering, or encoding them. As an example, consider an input +file called @file{INPUT.mkv} with 3 elementary streams, from which we take the +second and write it to file @file{OUTPUT.mp4}. A schematic representation of +such a pipeline looks like this: +@verbatim +┌──────────┬─────────────────────┐ +│ demuxer │ │ unused +╞══════════╡ elementary stream 0 ├────────╳ +│ │ │ +│INPUT.mkv ├─────────────────────┤ ┌──────────────────────┬───────────┐ +│ │ │ packets │ │ muxer │ +│ │ elementary stream 1 ├─────────►│ elementary stream 0 ╞═══════════╡ +│ │ │ │ │OUTPUT.mp4 │ +│ ├─────────────────────┤ └──────────────────────┴───────────┘ +│ │ │ unused +│ │ elementary stream 2 ├────────╳ +│ │ │ +└──────────┴─────────────────────┘ +@end verbatim + +The above pipeline can be constructed with the following commandline: +@example +ffmpeg -i INPUT.mkv -map 0:1 -c copy OUTPUT.mp4 +@end example + +In this commandline +@itemize + +@item +there is a single input @file{INPUT.mkv}; + +@item +there are no input options for this input; + +@item +there is a single output @file{OUTPUT.mp4}; + +@item +there are two output options for this output: + +@itemize +@item +@code{-map 0:1} selects the input stream to be used - from input with index 0 +(i.e. the first one) the stream with index 1 (i.e. the second one); + +@item +@code{-c copy} selects the @code{copy} encoder, i.e. streamcopy with no decoding +or encoding. +@end itemize + +@end itemize + +Streamcopy is useful for changing the elementary stream count, container format, +or modifying container-level metadata. Since there is no decoding or encoding, +it is very fast and there is no quality loss. However, it might not work in some +cases because of a variety of factors (e.g. certain information required by the +target container is not available in the source). Applying filters is obviously +also impossible, since filters work on decoded frames. + +More complex streamcopy scenarios can be constructed - e.g. combining streams +from two input files into a single output: +@verbatim +┌──────────┬────────────────────┐ ┌────────────────────┬───────────┐ +│ demuxer 0│ │ packets │ │ muxer │ +╞══════════╡elementary stream 0 ├────────►│elementary stream 0 ╞═══════════╡ +│INPUT0.mkv│ │ │ │OUTPUT.mp4 │ +└──────────┴────────────────────┘ ├────────────────────┤ │ +┌──────────┬────────────────────┐ │ │ │ +│ demuxer 1│ │ packets │elementary stream 1 │ │ +╞══════════╡elementary stream 0 ├────────►│ │ │ +│INPUT1.aac│ │ └────────────────────┴───────────┘ +└──────────┴────────────────────┘ +@end verbatim +that can be built by the commandline +@example +ffmpeg -i INPUT0.mkv -i INPUT1.aac -map 0:0 -map 1:0 -c copy OUTPUT.mp4 +@end example + +The output @option{-map} option is used twice here, creating two streams in the +output file - one fed by the first input and one by the second. The single +instance of the @option{-c} option selects streamcopy for both of those streams. +You could also use multiple instances of this option together with +@ref{Stream specifiers} to apply different values to each stream, as will be +demonstrated in following sections. + +A converse scenario is splitting multiple streams from a single input into +multiple outputs: +@verbatim +┌──────────┬─────────────────────┐ ┌───────────────────┬───────────┐ +│ demuxer │ │ packets │ │ muxer 0 │ +╞══════════╡ elementary stream 0 ├─────────►│elementary stream 0╞═══════════╡ +│ │ │ │ │OUTPUT0.mp4│ +│INPUT.mkv ├─────────────────────┤ └───────────────────┴───────────┘ +│ │ │ packets ┌───────────────────┬───────────┐ +│ │ elementary stream 1 ├─────────►│ │ muxer 1 │ +│ │ │ │elementary stream 0╞═══════════╡ +└──────────┴─────────────────────┘ │ │OUTPUT1.mp4│ + └───────────────────┴───────────┘ +@end verbatim +built with +@example +ffmpeg -i INPUT.mkv -map 0:0 -c copy OUTPUT0.mp4 -map 0:1 -c copy OUTPUT1.mp4 +@end example +Note how a separate instance of the @option{-c} option is needed for every +output file even though their values are the same. This is because non-global +options (which is most of them) only apply in the context of the file before +which they are placed. + +These examples can of course be further generalized into arbitrary remappings +of any number of inputs into any number of outputs. + +@section Transcoding +@emph{Transcoding} is the process of decoding a stream and then encoding it +again. Since encoding tends to be computationally expensive and in most cases +degrades the stream quality (i.e. it is @emph{lossy}), you should only transcode +when you need to and perform streamcopy otherwise. Typical reasons to transcode +are: + +@itemize +@item +applying filters - e.g. resizing, deinterlacing, or overlaying video; resampling +or mixing audio; + +@item +you want to feed the stream to something that cannot decode the original codec. +@end itemize +Note that @command{ffmpeg} will transcode all audio, video, and subtitle streams +unless you specify @option{-c copy} for them. + +Consider an example pipeline that reads an input file with one audio and one +video stream, transcodes the video and copies the audio into a single output +file. This can be schematically represented as follows +@verbatim +┌──────────┬─────────────────────┐ +│ demuxer │ │ audio packets +╞══════════╡ stream 0 (audio) ├─────────────────────────────────────╮ +│ │ │ │ +│INPUT.mkv ├─────────────────────┤ video ┌─────────┐ raw │ +│ │ │ packets │ video │ video frames │ +│ │ stream 1 (video) ├─────────►│ decoder ├──────────────╮ │ +│ │ │ │ │ │ │ +└──────────┴─────────────────────┘ └─────────┘ │ │ + ▼ ▼ + │ │ +┌──────────┬─────────────────────┐ video ┌─────────┐ │ │ +│ muxer │ │ packets │ video │ │ │ +╞══════════╡ stream 0 (video) │◄─────────┤ encoder ├──────────────╯ │ +│ │ │ │(libx264)│ │ +│OUTPUT.mp4├─────────────────────┤ └─────────┘ │ +│ │ │ │ +│ │ stream 1 (audio) │◄────────────────────────────────────╯ +│ │ │ +└──────────┴─────────────────────┘ +@end verbatim +and implemented with the following commandline: +@example +ffmpeg -i INPUT.mkv -map 0:v -map 0:a -c:v libx264 -c:a copy OUTPUT.mp4 +@end example +Note how it uses stream specifiers @code{:v} and @code{:a} to select input +streams and apply different values of the @option{-c} option to them; see the +@ref{Stream specifiers} section for more details. -Encoded packets are then passed to the decoder (unless streamcopy is selected -for the stream, see further for a description). The decoder produces -uncompressed frames (raw video/PCM audio/...) which can be processed further by -filtering (see next section). After filtering, the frames are passed to the -encoder, which encodes them and outputs encoded packets. Finally, those are -passed to the muxer, which writes the encoded packets to the output file. @section Filtering -Before encoding, @command{ffmpeg} can process raw audio and video frames using -filters from the libavfilter library. Several chained filters form a filter -graph. @command{ffmpeg} distinguishes between two types of filtergraphs: -simple and complex. + +When transcoding, audio and video streams can be filtered before encoding, with +either a @emph{simple} or @emph{complex} filtergraph. @subsection Simple filtergraphs + Simple filtergraphs are those that have exactly one input and output, both of -the same type. In the above diagram they can be represented by simply inserting -an additional step between decoding and encoding: +the same type (audio or video). They are configured with the per-stream +@option{-filter} option (with @option{-vf} and @option{-af} aliases for +@option{-filter:v} (video) and @option{-filter:a} (audio) respectively). Note +that simple filtergraphs are tied to their output stream, so e.g. if you have +multiple audio streams, @option{-af} will create a separate filtergraph for each +one. +Taking the transcoding example from above, adding filtering (and omitting audio, +for clarity) makes it look like this: @verbatim - _________ ______________ -| | | | -| decoded | | encoded data | -| frames |\ _ | packets | -|_________| \ /||______________| - \ __________ / - simple _\|| | / encoder - filtergraph | filtered |/ - | frames | - |__________| - +┌──────────┬───────────────┐ +│ demuxer │ │ ┌─────────┐ +╞══════════╡ video stream │ packets │ video │ frames +│INPUT.mkv │ ├─────────►│ decoder ├─────►───╮ +│ │ │ └─────────┘ │ +└──────────┴───────────────┘ │ + ╭───────────◄───────────╯ + │ ┌────────────────────────┐ + │ │ simple filtergraph │ + │ ╞════════════════════════╡ + │ │ ┌───────┐ ┌───────┐ │ + ╰──►├─►│ yadif ├─►│ scale ├─►├╮ + │ └───────┘ └───────┘ ││ + └────────────────────────┘│ + │ + │ +┌──────────┬───────────────┐ video ┌─────────┐ │ +│ muxer │ │ packets │ video │ │ +╞══════════╡ video stream │◄─────────┤ encoder ├───────◄───────╯ +│OUTPUT.mp4│ │ │ │ +│ │ │ └─────────┘ +└──────────┴───────────────┘ @end verbatim -Simple filtergraphs are configured with the per-stream @option{-filter} option -(with @option{-vf} and @option{-af} aliases for video and audio respectively). -A simple filtergraph for video can look for example like this: - -@verbatim - _______ _____________ _______ ________ -| | | | | | | | -| input | ---> | deinterlace | ---> | scale | ---> | output | -|_______| |_____________| |_______| |________| - -@end verbatim - -Note that some filters change frame properties but not frame contents. E.g. the -@code{fps} filter in the example above changes number of frames, but does not -touch the frame contents. Another example is the @code{setpts} filter, which -only sets timestamps and otherwise passes the frames unchanged. - @subsection Complex filtergraphs + Complex filtergraphs are those which cannot be described as simply a linear -processing chain applied to one stream. This is the case, for example, when the graph has -more than one input and/or output, or when output stream type is different from -input. They can be represented with the following diagram: - -@verbatim - _________ -| | -| input 0 |\ __________ -|_________| \ | | - \ _________ /| output 0 | - \ | | / |__________| - _________ \| complex | / -| | | |/ -| input 1 |---->| filter |\ -|_________| | | \ __________ - /| graph | \ | | - / | | \| output 1 | - _________ / |_________| |__________| -| | / -| input 2 |/ -|_________| - -@end verbatim - -Complex filtergraphs are configured with the @option{-filter_complex} option. -Note that this option is global, since a complex filtergraph, by its nature, -cannot be unambiguously associated with a single stream or file. - -The @option{-lavfi} option is equivalent to @option{-filter_complex}. +processing chain applied to one stream. This is the case, for example, when the +graph has more than one input and/or output, or when output stream type is +different from input. Complex filtergraphs are configured with the +@option{-filter_complex} option. Note that this option is global, since a +complex filtergraph, by its nature, cannot be unambiguously associated with a +single stream or file. Each instance of @option{-filter_complex} creates a new +complex filtergraph, and there can be any number of them. A trivial example of a complex filtergraph is the @code{overlay} filter, which has two video inputs and one video output, containing one video overlaid on top of the other. Its audio counterpart is the @code{amix} filter. -@section Stream copy -Stream copy is a mode selected by supplying the @code{copy} parameter to the -@option{-codec} option. It makes @command{ffmpeg} omit the decoding and encoding -step for the specified stream, so it does only demuxing and muxing. It is useful -for changing the container format or modifying container-level metadata. The -diagram above will, in this case, simplify to this: - -@verbatim - _______ ______________ ________ -| | | | | | -| input | demuxer | encoded data | muxer | output | -| file | ---------> | packets | -------> | file | -|_______| |______________| |________| - -@end verbatim - -Since there is no decoding or encoding, it is very fast and there is no quality -loss. However, it might not work in some cases because of many factors. Applying -filters is obviously also impossible, since filters work on uncompressed data. - +@anchor{Loopback decoders} @section Loopback decoders While decoders are normally associated with demuxer streams, it is also possible to create "loopback" decoders that decode the output from some encoder and allow @@ -259,8 +526,41 @@ reads an input video and @end itemize +Such a transcoding pipeline can be represented with the following diagram: +@verbatim +┌──────────┬───────────────┐ +│ demuxer │ │ ┌─────────┐ ┌─────────┐ ┌────────────────────┐ +╞══════════╡ video stream │ │ video │ │ video │ │ null muxer │ +│ INPUT │ ├──►│ decoder ├──┬────────►│ encoder ├─┬─►│(discards its input)│ +│ │ │ └─────────┘ │ │(libx264)│ │ └────────────────────┘ +└──────────┴───────────────┘ │ └─────────┘ │ + ╭───────◄──╯ ┌─────────┐ │ + │ │loopback │ │ + │ ╭─────◄──────┤ decoder ├────◄──╯ + │ │ └─────────┘ + │ │ + │ │ + │ │ ┌───────────────────┐ + │ │ │complex filtergraph│ + │ │ ╞═══════════════════╡ + │ │ │ ┌─────────────┐ │ + ╰─╫─►├─►│ hstack ├─►├╮ + ╰─►├─►│ │ ││ + │ └─────────────┘ ││ + └───────────────────┘│ + │ +┌──────────┬───────────────┐ ┌─────────┐ │ +│ muxer │ │ │ video │ │ +╞══════════╡ video stream │◄─┤ encoder ├───────◄──────────╯ +│ OUTPUT │ │ │ (ffv1) │ +│ │ │ └─────────┘ +└──────────┴───────────────┘ +@end verbatim + + @c man end DETAILED DESCRIPTION +@anchor{Stream selection} @chapter Stream selection @c man begin STREAM SELECTION @@ -621,24 +921,25 @@ ffmpeg -i INPUT -metadata:s:a:0 language=eng OUTPUT @end example @item -disposition[:stream_specifier] @var{value} (@emph{output,per-stream}) -Sets the disposition for a stream. +Sets the disposition flags for a stream. -By default, the disposition is copied from the input stream, unless the output -stream this option applies to is fed by a complex filtergraph - in that case the -disposition is unset by default. +Default value: by default, all disposition flags are copied from the input stream, +unless the output stream this option applies to is fed by a complex filtergraph +- in that case no disposition flags are set by default. -@var{value} is a sequence of items separated by '+' or '-'. The first item may -also be prefixed with '+' or '-', in which case this option modifies the default -value. Otherwise (the first item is not prefixed) this options overrides the -default value. A '+' prefix adds the given disposition, '-' removes it. It is -also possible to clear the disposition by setting it to 0. +@var{value} is a sequence of disposition flags separated by '+' or '-'. A '+' +prefix adds the given disposition, '-' removes it. If the first flag is also +prefixed with '+' or '-', the resulting disposition is the default value +updated by @var{value}. If the first flag is not prefixed, the resulting +disposition is @var{value}. It is also possible to clear the disposition by +setting it to 0. If no @code{-disposition} options were specified for an output file, ffmpeg will -automatically set the 'default' disposition on the first stream of each type, +automatically set the 'default' disposition flag on the first stream of each type, when there are multiple streams of this type in the output file and no stream of that type is already marked as default. -The @code{-dispositions} option lists the known dispositions. +The @code{-dispositions} option lists the known disposition flags. For example, to make the second audio stream the default stream: @example @@ -656,6 +957,29 @@ To add an embedded cover/thumbnail: ffmpeg -i in.mp4 -i IMAGE -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic out.mp4 @end example +To add the 'original' and remove the 'comment' disposition flag from the first +audio stream without removing its other disposition flags: +@example +ffmpeg -i in.mkv -c copy -disposition:a:0 +original-comment out.mkv +@end example + +To remove the 'original' and add the 'comment' disposition flag to the first +audio stream without removing its other disposition flags: +@example +ffmpeg -i in.mkv -c copy -disposition:a:0 -original+comment out.mkv +@end example + +To set only the 'original' and 'comment' disposition flags on the first audio +stream (and remove its other disposition flags): +@example +ffmpeg -i in.mkv -c copy -disposition:a:0 original+comment out.mkv +@end example + +To remove all disposition flags from the first audio stream: +@example +ffmpeg -i in.mkv -c copy -disposition:a:0 0 out.mkv +@end example + Not all muxers support embedded thumbnails, and those who do, only support a few formats, like JPEG or PNG. @item -program [title=@var{title}:][program_num=@var{program_num}:]st=@var{stream}[:st=@var{stream}...] (@emph{output}) @@ -724,7 +1048,7 @@ The following flags are available: @table @option @item recon_gain -Wether to signal if recon_gain is present as metadata in parameter blocks within frames +Whether to signal if recon_gain is present as metadata in parameter blocks within frames @end table @item output_gain @@ -872,9 +1196,9 @@ ffmpeg -i front.wav -i back.wav -i center.wav -i lfe.wav demixing=parameter_id=998, recon_gain=parameter_id=101, layer=ch_layout=stereo, -layer=ch_layout=5.1, +layer=ch_layout=5.1(side), -stream_group type=iamf_mix_presentation:id=2:stg=0:annotations=en-us=Mix_Presentation, -submix=parameter_id=100:parameter_rate=48000|element=stg=0:parameter_id=100:annotations=en-us=Scalable_Submix|layout=sound_system=stereo|layout=sound_system=5.1 +submix=parameter_id=100:parameter_rate=48000|element=stg=0:parameter_id=100:annotations=en-us=Scalable_Submix|layout=sound_system=stereo|layout=sound_system=5.1(side) -streamid 0:0 -streamid 1:1 -streamid 2:2 -streamid 3:3 output.iamf @end example @@ -1049,31 +1373,62 @@ The properties where a change triggers reinitialization are, for video, frame resolution or pixel format; for audio, sample format, sample rate, channel count or channel layout. +@item -drop_changed[:@var{stream_specifier}] @var{integer} (@emph{input,per-stream}) +This boolean option determines whether a frame with differing frame parameters mid-stream +gets dropped instead of leading to filtergraph reinitialization, as that would lead to loss +of filter state. Generally useful to avoid corrupted yet decodable packets in live streaming +inputs. Default is false. + @item -filter_threads @var{nb_threads} (@emph{global}) Defines how many threads are used to process a filter pipeline. Each pipeline will produce a thread pool with this many threads available for parallel processing. The default is the number of available CPUs. +@item -filter_buffered_frames @var{nb_frames} (@emph{global}) +Defines the maximum number of buffered frames allowed in a filtergraph. Under +normal circumstances, a filtergraph should not buffer more than a few frames, +especially if frames are being fed to it and read from it in a balanced way +(which is the intended behavior in ffmpeg). That said, this option allows you +to limit the total number of frames buffered across all links in a filtergraph. +If more frames are generated, filtering is aborted and an error is returned. +The default value is 0, which means no limit. + @item -pre[:@var{stream_specifier}] @var{preset_name} (@emph{output,per-stream}) Specify the preset for matching stream(s). @item -stats (@emph{global}) -Print encoding progress/statistics. It is on by default, to explicitly -disable it you need to specify @code{-nostats}. +Log encoding progress/statistics as "info"-level log (see @code{-loglevel}). +It is on by default, to explicitly disable it you need to specify @code{-nostats}. @item -stats_period @var{time} (@emph{global}) Set period at which encoding progress/statistics are updated. Default is 0.5 seconds. +@item -print_graphs (@emph{global}) +Prints execution graph details to stderr in the format set via -print_graphs_format. + +@item -print_graphs_file @var{filename} (@emph{global}) +Writes execution graph details to the specified file in the format set via -print_graphs_format. + +@item -print_graphs_format @var{format} (@emph{global}) +Sets the output format (available formats are: default, compact, csv, flat, ini, json, xml, mermaid, mermaidhtml) +The default format is json. + @item -progress @var{url} (@emph{global}) Send program-friendly progress information to @var{url}. Progress information is written periodically and at the end of the encoding process. It is made of "@var{key}=@var{value}" lines. @var{key} consists of only alphanumeric characters. The last key of a sequence of -progress information is always "progress". +progress information is always "progress" with the value "continue" or "end". The update period is set using @code{-stats_period}. +For example, log progress information to stdout: + +@example +ffmpeg -progress pipe:1 -i in.mkv out.mkv +@end example + @anchor{stdin option} @item -stdin Enable interaction on standard input. On by default unless standard input is @@ -1310,6 +1665,7 @@ Force video tag/fourcc. This is an alias for @code{-tag:v}. @item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] (@emph{output,per-stream}) @item -force_key_frames[:@var{stream_specifier}] expr:@var{expr} (@emph{output,per-stream}) @item -force_key_frames[:@var{stream_specifier}] source (@emph{output,per-stream}) +@item -force_key_frames[:@var{stream_specifier}] scd_metadata (@emph{output,per-stream}) @var{force_key_frames} can take arguments of the following form: @@ -1373,6 +1729,14 @@ the current frame being encoded is marked as a key frame in its source. In cases where this particular source frame has to be dropped, enforce the next available frame to become a key frame instead. +@item scd_metadata +If the argument is @code{scd_metadata}, ffmpeg will force a key frame if +the current frame contains a metadata entry with the key @code{lavfi.scd.time}. +The metadata can be added by filters like @code{scdet} and @code{scdet_vulkan}. +Avoid inserting filters that duplicate frames after @code{scdet}, as this can +cause duplicate metadata for multiple frames and repeated insertion of key +frames. + @end table Note that forcing too many keyframes is very harmful for the lookahead @@ -1655,6 +2019,9 @@ transcoding, without copying the frames into the system memory. For it to work, both the decoder and the encoder must support QSV acceleration and no filters must be used. + +@item videotoolbox +Use Video Toolbox hardware acceleration. @end table This option has no effect if the selected hwaccel is not available or not @@ -1995,6 +2362,11 @@ Read input at native frame rate. This is equivalent to setting @code{-readrate 1 @item -readrate_initial_burst @var{seconds} Set an initial read burst time, in seconds, after which @option{-re/-readrate} will be enforced. +@item -readrate_catchup @var{speed} (@emph{input}) +If either the input or output is blocked leading to actual read speed falling behind the +specified readrate, then this rate takes effect till the input catches up with the +specified readrate. Must not be lower than the primary readrate. + @item -vsync @var{parameter} (@emph{global}) @itemx -fps_mode[:@var{stream_specifier}] @var{parameter} (@emph{output,per-stream}) Set video sync method / framerate mode. vsync is applied to all output video streams diff --git a/doc/ffplay.texi b/doc/ffplay.texi index 93f77eeec..5273c158b 100644 --- a/doc/ffplay.texi +++ b/doc/ffplay.texi @@ -208,6 +208,14 @@ Vulkan configuration using a list of @var{key}=@var{value} pairs separated by Use HW accelerated decoding. Enable this option will enable vulkan renderer automatically. +@item -video_bg @var{pattern} +Set the video background pattern used for transparent videos. For solid color +patterns you can use the color name or color code as specified in the +@ref{color syntax,,Color section in the ffmpeg-utils(1) manual,ffmpeg-utils}. +You can also use the special @code{tiles} keyword for a checker board style +pattern. This is also the default. The @code{none} pattern does rendering +without alpha blending effectively ignoring alpha channel. + @end table @section While playing @@ -251,15 +259,13 @@ Pause if the stream is not already paused, step to the next video frame, and pause. @item left/right -Seek backward/forward 10 seconds. +Seek backward/forward by 10 seconds or a custom interval if -seek_interval is set. @item down/up Seek backward/forward 1 minute. @item page down/page up -Seek to the previous/next chapter. -or if there are no chapters -Seek backward/forward 10 minutes. +Seek to previous/next chapter or backward/forward 10 minutes if no chapters. @item right mouse click Seek to percentage in file corresponding to fraction of width. diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi index 6333249a6..41dbba465 100644 --- a/doc/ffprobe.texi +++ b/doc/ffprobe.texi @@ -117,7 +117,8 @@ ffprobe -show_packets -select_streams v:1 INPUT @end example @item -show_data -Show payload data, as a hexadecimal and ASCII dump. Coupled with +Show payload data, as a hexadecimal and ASCII dump (other formats can be +selected using @option{-data_dump_format}). Coupled with @option{-show_packets}, it will dump the packets' data. Coupled with @option{-show_streams}, it will dump the codec extradata. @@ -127,6 +128,11 @@ The dump is printed as the "data" field. It may contain newlines. Show a hash of payload data, for packets with @option{-show_packets} and for codec extradata with @option{-show_streams}. +@item -data_dump_format @var{format} +Select a format used for the data dumps enabled with the @option{-show_data} +option. The default is @code{xxd} which is a hexdump format compatible with the +well-known @command{xxd} program. @code{base64} is also supported. + @item -show_error Show information about the error found when trying to probe the input. @@ -139,13 +145,6 @@ stream. All the container format information is printed within a section with name "FORMAT". -@item -show_format_entry @var{name} -Like @option{-show_format}, but only prints the specified entry of the -container format information, rather than all. This option may be given more -than once, then all specified entries will be shown. - -This option is deprecated, use @code{show_entries} instead. - @item -show_entries @var{section_entries} Set list of entries to show. @@ -351,6 +350,19 @@ while other writers always print them. This option enables one to control this b Valid values are @code{always}/@code{1}, @code{never}/@code{0} and @code{auto}/@code{-1}. Default is @var{auto}. +@item -analyze_frames +Analyze frames and/or their side data up to the provided read interval, +providing additional information that may be useful at a stream level. +Must be paired with the @option{-show_streams} option or it will have no effect. + +Currently, the additional fields provided by this option when enabled are the +@code{closed_captions} and @code{film_grain} fields. + +For example, to analyze the first 20 seconds and populate these fields: +@example +ffprobe -show_streams -analyze_frames -read_intervals "%+20" INPUT +@end example + @item -bitexact Force bitexact output, useful to produce output which is not dependent on the specific build. @@ -362,6 +374,12 @@ Read @var{input_url}. Write output to @var{output_url}. If not specified, the output is sent to stdout. +@item -c:@var{media_specifier} @var{codec_name} +@itemx -codec:@var{media_specifier} @var{codec_name} +Force a specific decoder implementation for the stream identified by +@var{media_specifier}, which can assume the values @code{a} (audio), +@code{v} (video), @code{s} (subtitle), and @code{d} (data). + @end table @c man end diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd index 64e2d8857..c870db7aa 100644 --- a/doc/ffprobe.xsd +++ b/doc/ffprobe.xsd @@ -129,6 +129,7 @@ + @@ -275,6 +276,7 @@ + diff --git a/doc/fftools-common-opts.texi b/doc/fftools-common-opts.texi index 8b0931a86..7b5a11b63 100644 --- a/doc/fftools-common-opts.texi +++ b/doc/fftools-common-opts.texi @@ -98,7 +98,7 @@ These options are shared amongst the ff* tools. @table @option -@item -L +@item -L, -license Show license. @item -h, -?, -help, --help [@var{arg}] @@ -226,6 +226,10 @@ and the "Last message repeated n times" line will be omitted. Indicates that log output should add a @code{[level]} prefix to each message line. This can be used as an alternative to log coloring, e.g. when dumping the log to file. +@item time +Indicates that log lines should be prefixed with time information. +@item datetime +Indicates that log lines should be prefixed with date and time information. @end table Flags can also be used alone by adding a '+'/'-' prefix to set/reset a single flag without affecting other @var{flags} or changing @var{loglevel}. When diff --git a/doc/filter_design.txt b/doc/filter_design.txt index 885b19b6f..b6bfca12f 100644 --- a/doc/filter_design.txt +++ b/doc/filter_design.txt @@ -214,6 +214,7 @@ Frame scheduling FF_FILTER_FORWARD_STATUS(inlink, outlink); FF_FILTER_FORWARD_STATUS_ALL(inlink, filter); FF_FILTER_FORWARD_WANTED(outlink, inlink); + FF_FILTER_FORWARD_WANTED_ANY(filter, inlink); filter_frame ------------ diff --git a/doc/filters.texi b/doc/filters.texi index 428986a1e..5d222c6b9 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -216,7 +216,7 @@ filter input and output pads of all the filterchains are connected. Leading and trailing whitespaces (space, tabs, or line feeds) separating tokens in the filtergraph specification are ignored. This means that the filtergraph -can be expressed using empty lines and spaces to improve redability. +can be expressed using empty lines and spaces to improve readability. For example, the filtergraph: @example @@ -577,6 +577,11 @@ The cross fade is applied for specified duration near the end of first stream. The filter accepts the following options: @table @option +@item inputs, n +Specify the number of inputs to crossfade. When crossfading multiple inputs, +each input will be concatenated and crossfaded in sequence, similar to the +@ref{concat filter}. Default is 2. + @item nb_samples, ns Specify the number of samples for which the cross fade effect has to last. At the end of the cross fade effect the first input audio will be completely @@ -615,6 +620,11 @@ Cross fade from one input to another but without overlapping: @example ffmpeg -i first.flac -i second.flac -filter_complex acrossfade=d=10:o=0:c1=exp:c2=exp output.flac @end example + +Concatenate multiple inputs with cross fade between each: +@example +ffmpeg -i first.flac -i second.flac -i third.flac -filter_complex acrossfade=n=3 output.flac +@end example @end itemize @section acrossover @@ -2426,6 +2436,11 @@ Only used if option named @var{start} is set to @code{-1}. Merge two or more audio streams into a single multi-channel stream. +All inputs must have the same sample rate, and format. + +If inputs do not have the same duration, the output will stop with the +shortest. + The filter accepts the following options: @table @option @@ -2433,15 +2448,25 @@ The filter accepts the following options: @item inputs Set the number of inputs. Default is 2. -@end table +@item layout_mode -If the channel layouts of the inputs are disjoint, and therefore compatible, -the channel layout of the output will be set accordingly and the channels -will be reordered as necessary. If the channel layouts of the inputs are not -disjoint, the output will have all the channels of the first input then all -the channels of the second input, in that order, and the channel layout of -the output will be the default value corresponding to the total number of -channels. +This option controls how the output channel layout is determined and if the +audio channels are reordered during merge. + +@table @option + +@item legacy + +This is the mode how the filter behaved historically so it is the default. + +If the channel layouts of the inputs are known and disjoint, and therefore +compatible, the channel layout of the output will be set accordingly and the +channels will be reordered as necessary. If the channel layouts of the inputs +are not disjoint, some of them are unknown, or they are using special channel +layouts, such as ambisonics, the output will have all the channels of the first +input then all the channels of the second input, in that order, and the channel +layout of the output will be the default value corresponding to the total +number of channels. For example, if the first input is in 2.1 (FL+FR+LF) and the second input is FC+BL+BR, then the output will be in 5.1, with the channels in the @@ -2452,10 +2477,22 @@ On the other hand, if both input are in stereo, the output channels will be in the default order: a1, a2, b1, b2, and the channel layout will be arbitrarily set to 4.0, which may or may not be the expected value. -All inputs must have the same sample rate, and format. +@item reset +This mode ignores the input channel layouts and does no channel reordering. +The output will have all the channels of the first input, then all the channels +of the second input, in that order, and so on. -If inputs do not have the same duration, the output will stop with the -shortest. +The output channel layout will only specify the total channel count. + +@item normal +This mode keeps channel name and designation information from the input +channels and does no channel reordering. The output will have all the channels +of the first input, then all the channels of the second input, in that order, +and so on. + +@end table + +@end table @subsection Examples @@ -3383,7 +3420,7 @@ where applicable, an overall figure is also given. It accepts the following option: @table @option @item length -Short window length in seconds, used for peak and trough RMS measurement. +Short window length in seconds, used for peak and through RMS measurement. Default is @code{0.05} (50 milliseconds). Allowed range is @code{[0 - 10]}. @item metadata @@ -3544,7 +3581,7 @@ standard RMS level measured in dBFS @item RMS_peak @item RMS_trough -peak and trough values for RMS level measured over a short window, +peak and through values for RMS level measured over a short window, measured in dBFS. @item Zero crossings @@ -4376,7 +4413,7 @@ Add a chorus effect to the audio. Can make a single vocal sound like a chorus, but can also be applied to instrumentation. Chorus resembles an echo effect with a short delay, but whereas with echo the delay is -constant, with chorus, it is varied using using sinusoidal or triangular modulation. +constant, with chorus, it is varied using sinusoidal or triangular modulation. The modulation depth defines the range the modulated delay is played before or after the delay. Hence the delayed sound will sound slower or faster, that is the delayed sound tuned around the original one, like in a chorus where some vocals are slightly @@ -5877,6 +5914,11 @@ Options are true or false. Default is false. @item print_format Set print format for stats. Options are summary, json, or none. Default value is none. + +@item stats_file +Write stats to specified file. Format is controlled by @option{print_format}, +which must be set. Specify @code{-} to write to standard output. +Default is unset. @end table @section lowpass @@ -7682,6 +7724,119 @@ There are 6 samples at -4 dB, 62 at -5 dB, 286 at -6 dB, etc. In other words, raising the volume by +4 dB does not cause any clipping, raising it by +5 dB causes clipping for 6 samples, etc. +@anchor{whisper} +@section whisper + +It runs automatic speech recognition using the OpenAI's Whisper model. + +It requires the whisper.cpp library (https://github.com/ggml-org/whisper.cpp) +as a prerequisite. After installing the library it can be enabled using: +@code{./configure --enable-whisper}. + +The filter has following options: + +@table @option +@item model +The file path of the downloaded whisper.cpp model (mandatory). + +@item language +The language to use for transcription ('auto' for auto-detect). +Default value: @code{"auto"} + +@item queue +The maximum size that will be queued into the filter before processing the audio +with whisper. Using a small value the audio stream will be processed more often, +but the transcription quality will be lower and the required processing power +will be higher. Using a large value (e.g. 10-20s) will produce more accurate +results using less CPU (as using the whisper-cli tool), but the transcription +latency will be higher, thus not useful to process real-time streams. +Consider using the vad_model option associated with a large queue value. +Default value: @code{"3"} + +@item use_gpu +If the GPU support should be enabled. +Default value: @code{"true"} + +@item gpu_device +The GPU device index to use. +Default value: @code{"0"} + +@item destination +If set, the transcription output will be sent to the specified file or URL +(use one of the FFmpeg AVIO protocols); otherwise, the output will be logged as +info messages. +The output will also be set in the "lavfi.whisper.text" frame metadata. +If the destination is a file and it already exists, it will be overwritten. + +@item format +The destination format string; it could be "text" (only the transcribed text +will be sent to the destination), "srt" (subtitle format) or "json". +Default value: @code{"text"} + +@item max_len +Maximum segment length in characters. When set to a value greater than 0, +transcription segments will be split to not exceed this length. This is useful +for generating subtitles with shorter lines. +Default value: @code{"0"} + +@item vad_model +Path to the VAD model file. If set, the filter will load an additional voice +activity detection module (https://github.com/snakers4/silero-vad) that will be +used to fragment the audio queue; use this option setting a valid path obtained +from the whisper.cpp repository (e.g. "../whisper.cpp/models/ggml-silero-v5.1.2.bin") +and increase the queue parameter to a higher value (e.g. 20). + +@item vad_threshold +The VAD threshold to use. +Default value: @code{"0.5"} + +@item vad_min_speech_duration +The minimum VAD speaking duration. +Default value: @code{"0.1"} + +@item vad_min_silence_duration +The minimum VAD silence duration. +Default value: @code{"0.5"} + +@end table + +@subsection Examples +@itemize + +@item +Run a transcription with srt file generation: +@example +ffmpeg -i input.mp4 -vn -af "whisper=model=../whisper.cpp/models/ggml-base.en.bin\ +:language=en\ +:queue=3\ +:destination=output.srt\ +:format=srt" -f null - +@end example + +@item +Run a transcription and send the output in JSON format to an HTTP service: +@example +ffmpeg -i input.mp4 -vn -af "whisper=model=../whisper.cpp/models/ggml-base.en.bin\ +:language=en\ +:queue=3\ +:destination=http\\://localhost\\:3000\ +:format=json' -f null - +@end example + +@item +Transcribe the microphone input using the VAD option: +@example +ffmpeg -loglevel warning -f pulse -i default \ +-af 'highpass=f=200,lowpass=f=3000,whisper=model=../whisper.cpp/models/ggml-medium.bin\ +:language=en\ +:queue=10\ +:destination=-\ +:format=json\ +:vad_model=../whisper.cpp/models/ggml-silero-v5.1.2.bin' -f null - +@end example + +@end itemize + @c man end AUDIO FILTERS @chapter Audio Sources @@ -7904,7 +8059,7 @@ Gains are separated by white spaces and each gain is set in dBFS. Default is @code{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}. @item bands, b -Set the custom bands from where custon equalizer gains are set. +Set the custom bands from where custom equalizer gains are set. This must be in strictly increasing order. Only used if the preset option is set to @code{custom}. Bands are separated by white spaces and each band represent frequency in Hz. Default is @code{25 40 63 100 160 250 400 630 1000 1600 2500 4000 6300 10000 16000 24000}. @@ -8619,45 +8774,6 @@ Set planes to filter. Default is first only. This filter supports the all above options as @ref{commands}. -@section bilateral_cuda -CUDA accelerated bilateral filter, an edge preserving filter. -This filter is mathematically accurate thanks to the use of GPU acceleration. -For best output quality, use one to one chroma subsampling, i.e. yuv444p format. - -The filter accepts the following options: -@table @option -@item sigmaS -Set sigma of gaussian function to calculate spatial weight, also called sigma space. -Allowed range is 0.1 to 512. Default is 0.1. - -@item sigmaR -Set sigma of gaussian function to calculate color range weight, also called sigma color. -Allowed range is 0.1 to 512. Default is 0.1. - -@item window_size -Set window size of the bilateral function to determine the number of neighbours to loop on. -If the number entered is even, one will be added automatically. -Allowed range is 1 to 255. Default is 1. -@end table -@subsection Examples - -@itemize -@item -Apply the bilateral filter on a video. - -@example -./ffmpeg -v verbose \ --hwaccel cuda -hwaccel_output_format cuda -i input.mp4 \ --init_hw_device cuda \ --filter_complex \ -" \ -[0:v]scale_cuda=format=yuv444p[scaled_video]; -[scaled_video]bilateral_cuda=window_size=9:sigmaS=3.0:sigmaR=50.0" \ --an -sn -c:v h264_nvenc -cq 20 out.mp4 -@end example - -@end itemize - @section bitplanenoise Show and measure bit plane noise. @@ -8673,7 +8789,7 @@ Filter out noisy pixels from @code{bitplane} set above. Default is disabled. @end table -@section blackdetect +@section blackdetect, blackdetect_vulkan Detect video intervals that are (almost) completely black. Can be useful to detect chapter transitions, commercials, or invalid @@ -8726,6 +8842,12 @@ the input video format, the range is [0-255] for YUV full-range formats and [16-235] for YUV non full-range formats. Default value is 0.10. + +@item alpha +If true, check the alpha channel instead of the luma channel. Detects frames +which are (almost) transparent, instead of frames which are almost black. + +Default value is disabled. @end table The following example sets the maximum pixel threshold to the minimum @@ -9243,63 +9365,11 @@ Only deinterlace frames marked as interlaced. The default value is @code{all}. @end table -@section bwdif_cuda - -Deinterlace the input video using the @ref{bwdif} algorithm, but implemented -in CUDA so that it can work as part of a GPU accelerated pipeline with nvdec -and/or nvenc. - -It accepts the following parameters: - -@table @option -@item mode -The interlacing mode to adopt. It accepts one of the following values: - -@table @option -@item 0, send_frame -Output one frame for each frame. -@item 1, send_field -Output one frame for each field. -@end table - -The default value is @code{send_field}. - -@item parity -The picture field parity assumed for the input interlaced video. It accepts one -of the following values: - -@table @option -@item 0, tff -Assume the top field is first. -@item 1, bff -Assume the bottom field is first. -@item -1, auto -Enable automatic detection of field parity. -@end table - -The default value is @code{auto}. -If the interlacing is unknown or the decoder does not export this information, -top field first will be assumed. - -@item deint -Specify which frames to deinterlace. Accepts one of the following -values: - -@table @option -@item 0, all -Deinterlace all frames. -@item 1, interlaced -Only deinterlace frames marked as interlaced. -@end table - -The default value is @code{all}. -@end table - @section ccrepack Repack CEA-708 closed captioning side data -This filter fixes various issues seen with commerical encoders +This filter fixes various issues seen with commercial encoders related to upstream malformed CEA-708 payloads, specifically incorrect number of tuples (wrong cc_count for the target FPS), and incorrect ordering of tuples (i.e. the CEA-608 tuples are not at @@ -9408,48 +9478,6 @@ ffmpeg -f lavfi -i color=c=black:s=1280x720 -i video.mp4 -shortest -filter_compl @end example @end itemize -@section chromakey_cuda -CUDA accelerated YUV colorspace color/chroma keying. - -This filter works like normal chromakey filter but operates on CUDA frames. -for more details and parameters see @ref{chromakey}. - -@subsection Examples - -@itemize -@item -Make all the green pixels in the input video transparent and use it as an overlay for another video: - -@example -./ffmpeg \ - -hwaccel cuda -hwaccel_output_format cuda -i input_green.mp4 \ - -hwaccel cuda -hwaccel_output_format cuda -i base_video.mp4 \ - -init_hw_device cuda \ - -filter_complex \ - " \ - [0:v]chromakey_cuda=0x25302D:0.1:0.12:1[overlay_video]; \ - [1:v]scale_cuda=format=yuv420p[base]; \ - [base][overlay_video]overlay_cuda" \ - -an -sn -c:v h264_nvenc -cq 20 output.mp4 -@end example - -@item -Process two software sources, explicitly uploading the frames: - -@example -./ffmpeg -init_hw_device cuda=cuda -filter_hw_device cuda \ - -f lavfi -i color=size=800x600:color=white,format=yuv420p \ - -f lavfi -i yuvtestsrc=size=200x200,format=yuv420p \ - -filter_complex \ - " \ - [0]hwupload[under]; \ - [1]hwupload,chromakey_cuda=green:0.1:0.12[over]; \ - [under][over]overlay_cuda" \ - -c:v hevc_nvenc -cq 18 -preset slow output.mp4 -@end example - -@end itemize - @section chromanr Reduce chrominance noise. @@ -9484,19 +9512,19 @@ Mostly useful to speed-up filtering. @item threy Set Y threshold for averaging chrominance values. Set finer control for max allowed difference between Y components -of current pixel and neigbour pixels. +of current pixel and neighbour pixels. Default value is 200. Allowed range is from 1 to 200. @item threu Set U threshold for averaging chrominance values. Set finer control for max allowed difference between U components -of current pixel and neigbour pixels. +of current pixel and neighbour pixels. Default value is 200. Allowed range is from 1 to 200. @item threv Set V threshold for averaging chrominance values. Set finer control for max allowed difference between V components -of current pixel and neigbour pixels. +of current pixel and neighbour pixels. Default value is 200. Allowed range is from 1 to 200. @item distance @@ -9880,6 +9908,33 @@ colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131 This filter supports the all above options as @ref{commands}. +@section colordetect +Analyze the video frames to determine the effective value range and alpha +mode. + +The filter accepts the following options: + +@table @option +@item mode +Set of properties to detect. Unavailable properties, such as alpha mode for +an input image without an alpha channel, will be ignored automatically. + +Accepts a combination of the following flags: + +@table @samp +@item color_range +Detect if the source contains luma pixels outside the limited (MPEG) range, +which indicates that this is a full range YUV source. +@item alpha_mode +Detect if the source contains color values above the alpha channel, which +indicates that the alpha channel is independent (straight), rather than +premultiplied. Also detects if the alpha plane is fully opaque or not. +@item all +Enable detection of all of the above properties. This is the default. +@end table + +@end table + @section colorize Overlay a solid color on the video stream. @@ -10396,6 +10451,18 @@ von Kries whitepoint adaptation identity whitepoint adaptation (i.e. no whitepoint adaptation) @end table +@item clipgamut +Controls how to clip out-of-gamut colors that arise as a result of colorspace conversion. + +The accepted values are: +@table @samp +@item none +No clipping of out of gamut colors. + +@item rgb +Clips the RGB values to the [0, 1] range when building the gamma transfer LUTs. +@end table + @item iall Override all input properties at once. Same accepted values as @ref{all}. @@ -10427,38 +10494,6 @@ For example to convert the input to SMPTE-240M, use the command: colorspace=smpte240m @end example -@section colorspace_cuda - -CUDA accelerated implementation of the colorspace filter. - -It is by no means feature complete compared to the software colorspace filter, -and at the current time only supports color range conversion between jpeg/full -and mpeg/limited range. - -The filter accepts the following options: - -@table @option -@item range -Specify output color range. - -The accepted values are: -@table @samp -@item tv -TV (restricted) range - -@item mpeg -MPEG (restricted) range - -@item pc -PC (full) range - -@item jpeg -JPEG (full) range - -@end table - -@end table - @section colortemperature Adjust color temperature in video to simulate variations in ambient color temperature. @@ -11617,6 +11652,105 @@ Median Do not actually modify frame. Useful when one only wants metadata. @end table +@section deinterlace_d3d12 + +Deinterlace the input video using D3D12 hardware-accelerated video processing. + +This filter uses the DirectX 12 Video Processor to perform deinterlacing on +GPU, supporting both simple bob and driver-defined advanced (motion-adaptive) +algorithms. It requires the input to be in @code{d3d12} hardware pixel format. + +The filter automatically queries the hardware for the required number of +temporal reference frames (if needed) and manages a frame queue to supply them. + +It accepts the following options: + +@table @option + +@item method +The deinterlacing method. It accepts one of the following values: + +@table @samp +@item default +Select the best deinterlacing method available on the hardware. +If the driver supports @code{custom}, that method is used; otherwise +falls back to @code{bob}. This is the default. + +@item bob +Bob deinterlacing. Each field is independently scaled to full +frame height. Simple and fast, but may produce visible bob artifacts +on moving content. + +@item custom +Driver-defined advanced deinterlacing. The exact algorithm is +hardware-specific and typically employs motion-adaptive techniques +with temporal reference frames for higher quality. +@end table + +The default value is @code{default}. + +@item mode +Specify the interlacing mode. It accepts one of the following values: + +@table @samp +@item frame +Send one frame for each frame. The output frame rate equals the input +frame rate. This is the default. + +@item field +Send one frame for each field. The output frame rate is double the +input frame rate. +@end table + +The default value is @code{frame}. + +@item deint +Specify which frames to deinterlace. It accepts one of the following values: + +@table @samp +@item all +Deinterlace all frames. This is the default. + +@item interlaced +Only deinterlace frames marked as interlaced; progressive frames are +passed through unchanged. +@end table + +The default value is @code{all}. +@end table + +@subsection Examples + +@itemize + +@item +Deinterlace an interlaced video using software decoding and the best +available hardware deinterlacing method: +@example +ffmpeg -init_hw_device d3d12va=d3d12 -filter_hw_device d3d12 -i input.ts \ + -vf "format=nv12,hwupload,deinterlace_d3d12=method=default,hwdownload,format=nv12" \ + -c:v libx264 -crf 18 output.mp4 +@end example + +@item +Deinterlace at field rate (double the frame rate) using bob method with +hardware decoding (full d3d12 pipeline): +@example +ffmpeg -hwaccel d3d12va -hwaccel_output_format d3d12 -i input.ts \ + -vf "deinterlace_d3d12=method=bob:mode=field" \ + -c:v h264_d3d12va output.mp4 +@end example + +@item +Deinterlace only interlaced frames, passing progressive frames through: +@example +ffmpeg -init_hw_device d3d12va=d3d12 -filter_hw_device d3d12 -i input.ts \ + -vf "format=nv12,hwupload,deinterlace_d3d12=deint=interlaced,hwdownload,format=nv12" \ + -c:v libx264 -crf 18 output.mp4 +@end example + +@end itemize + @section dejudder Remove judder produced by partially interlaced telecined content. @@ -13052,6 +13186,80 @@ For more information about libfribidi, check: For more information about libharfbuzz, check: @url{https://github.com/harfbuzz/harfbuzz}. +@anchor{drawvg} +@section drawvg + +Draw vector graphics on top of video frames, by executing a script written in +a custom language called VGS (@emph{Vector Graphics Script}). + +The documentation for the language can be found in +@ref{,,drawvg - Language Reference,drawvg-reference}. A version of this reference +with rendered examples can be found at the +@uref{https://ayosec.github.io/ffmpeg-drawvg/playground/docs/langref.html, author's site}. + +Graphics are rendered using the @uref{https://cairographics.org/,cario 2D +graphics library}. + +To enable compilation of this filter, you need to configure FFmpeg with +@code{--enable-cairo}. + +@subsection Parameters + +Either @code{script} or @code{file} must be set. + +@table @option + +@item s, script +Script source to draw the graphics. + +@item file +Path of the file to load the script source. + +@end table + +@subsection Pixel Formats + +Since Cairo only supports RGB images, if the input video is something else (like +YUV 4:2:0), before executing the script the video is converted to a format +compatible with Cairo. Then, you have to use either the @ref{format} filter, +or the @code{-pix_fmt} option, to convert it to the expected format in the +output. + +@subsection Examples + +@itemize +@item +Draw the outline of an ellipse. + +@example +ffmpeg -i input.webm \ + -vf 'drawvg=ellipse (w/2) (h/2) (w/3) (h/3) stroke' \ + -pix_fmt yuv420p \ + output.webm +@end example + +@item + +Draw a square rotating in the middle of the frame. + +The script for drawvg is in a file @code{draw.vgs}: + +@example +translate (w/2) (h/2) +rotate t +rect -100 -100 200 200 +setcolor red@@0.5 +fill +@end example + +Then: + +@example +ffmpeg -i input.webm -vf 'drawvg=file=draw.vgs,format=yuv420p' output.webm +@end example + +@end itemize + @section edgedetect Detect and draw edges. The filter uses the Canny Edge Detection algorithm. @@ -14330,7 +14538,11 @@ A '|'-separated list of color space names, such as @item color_ranges A '|'-separated list of color range names, such as -"color_spaces=tv|pc". +"color_ranges=tv|pc". + +@item alpha_modes +A '|'-separated list of color range names, such as +"alpha_modes=straight|premultiplied". @end table @@ -14706,7 +14918,7 @@ e.g. quality comparison. Each line of the map file must contain three items per input frame, the input PTS (decimal), the output PTS (decimal) and the -output TIMEBASE (decimal/decimal), seperated by a space. +output TIMEBASE (decimal/decimal), separated by a space. This file format corresponds to the output of @code{-stats_mux_pre_fmt="@{ptsi@} @{pts@} @{tb@}"}. @@ -16041,7 +16253,7 @@ If 0, plane will remain unchanged. This filter supports the all above options as @ref{commands}. -@section interlace +@section interlace, interlace_vulkan Simple interlacing filter from progressive contents. This interleaves upper (or lower) lines from odd frames with lower (or upper) lines from even frames, @@ -16372,6 +16584,11 @@ ffmpeg -i input.mov -vf lensfun=make=Canon:model="Canon EOS 100D":lens_model="Ca @end itemize +@section lcevc + +Low Complexity Enhancement Video Codec filter based on liblcevc_dec +(@url{https://github.com/v-novaltd/LCEVCdec}). + @section libplacebo Flexible GPU-accelerated processing filter based on libplacebo @@ -16419,6 +16636,16 @@ and @code{(oh-ph)/2}. Set the output placement width/height expressions, default values are @code{ow} and @code{oh}. +@item rotate +Rotate the input frame clockwise by the specified angle. + +@table @samp +@item 0, 360 +@item 90 +@item 180 +@item 270 +@end table + @item fps Set the output frame rate. This can be rational, e.g. @code{60000/1001}. If set to the special string @code{none} (the default), input timestamps will @@ -16433,13 +16660,18 @@ will be performed. @item force_original_aspect_ratio @item force_divisible_by -Work the same as the identical @ref{scale} filter options. +Work the same as the identical @ref{scale} filter options. Note that +@option{force_divisible_by} also works with @code{fit_sense=constraint}. + +@item reset_sar +If enabled, output frames will always have a pixel aspect ratio of 1:1. If +disabled (the default), any aspect ratio mismatches, including those from +e.g. anamorphic video sources, are forwarded to the output pixel aspect ratio. @item normalize_sar -If enabled, output frames will always have a pixel aspect ratio of 1:1. This -will introduce additional padding/cropping as necessary. If disabled (the -default), any aspect ratio mismatches, including those from e.g. anamorphic -video sources, are forwarded to the output pixel aspect ratio. +Like @option{reset_sar}, but instead of stretching the video content to fill +the new output aspect ratio, the content is instead padded or cropped as +necessary. Mutually exclusive with @option{fit_mode}. Disabled by default. @item pad_crop_ratio Specifies a ratio (between @code{0.0} and @code{1.0}) between padding and @@ -16449,11 +16681,61 @@ content with black borders, while a value of @code{1.0} always crops off parts of the content. Intermediate values are possible, leading to a mix of the two approaches. +@item fit_mode +Specify the content fit strategy according to a list of predefined modes. +Determines how the input image is to be placed inside the destination crop +rectangle (as defined by @code{pos_x/y} and @code{pos_w/h}). The names and +their implementations are taken from the CSS 'object-fit' property. Note that +this option is mutually exclusive with @option{normalize_sar}. Defaults to +@code{fill}. Valid values are: + +@table @samp +@item fill +Stretch the input to the output rectangle, ignoring aspect ratio mismatches. +Note that unless @option{reset_sar} is also enabled, the output will still +have the correct pixel aspect ratio tagged. + +@item contain +Scale the input to fit inside the output, preserving aspect ratio by padding. +Equivalent to @option{normalize_sar} with @option{pad_crop_ratio} set to +@code{0.0}. + +@item cover +Scale the input to fill the output, preserving aspect ratio by cropping. +Equivalent to @option{normalize_sar} with @option{pad_crop_ratio} set to +@code{1.0}. + +@item none, place +Don't scale the input. The input will be placed inside the output rectangle at +its natural size; which may result in additional padding or cropping. + +@item scale_down +Scale the input down as much as needed to fit inside the output. Equivalent +to either @code{contain} or @code{none}, depending on whether the input is +larger than the output or not. +@end table + +@item fit_sense +When @option{fit_mode} is in use, this option controls how the fit strategy +is applied against the specified output resolution. Mutually exclusive with +@option{force_original_aspect_ratio}. Valid values are: + +@table @samp +@item target +The computed output resolution is taken as the exact size of the output frame. +This is the default behavior. + +@item constraint +The computed output resolution is a size reference against which the fit mode +is applied, enlarging or decreasing the true frame size as needed to fit the +content. +@end table + @item fillcolor Set the color used to fill the output area not covered by the output image, for example as a result of @option{normalize_sar}. For the general syntax of this option, check the @ref{color syntax,,"Color" section in the ffmpeg-utils -manual,ffmpeg-utils}. Defaults to @code{black}. +manual,ffmpeg-utils}. Defaults to @code{black@@0}. @item corner_rounding Render frames with rounded corners. The value, given as a float ranging from @@ -16461,6 +16743,36 @@ Render frames with rounded corners. The value, given as a float ranging from square to fully circular. In other words, it gives the radius divided by half the smaller side length. Defaults to @code{0.0}. +@item lut +Specifies a custom LUT (in Adobe .cube format) to apply to the colors +as part of color conversion. The exact interpretation depends on the value +of @option{lut_type}. + +@item lut_type +Controls the interpretation of color values fed to and from the LUT +specified as @option{lut}. Valid values are: + +@table @samp +@item auto +Chooses the interpretation of the LUT automatically from tagged +metadata, and otherwise falls back to @samp{native}. (Default) + +@item native +Applied to raw image contents in its native RGB colorspace (non-linear +light), before conversion to the output color space. + +@item normalized +Applied to the normalized RGB image contents, in linear light, before +conversion to the output color space. + +@item conversion +Fully replaces the conversion from the image color space to the output +color space. If such a LUT is present, it has the highest priority, and +overrides any ICC profiles, as well as options related to tone mapping +and output colorimetry (@option{color_primaries}, @option{color_trc}). + +@end table + @item extra_opts Pass extra libplacebo internal configuration options. These can be specified as a list of @var{key}=@var{value} pairs separated by ':'. The following example @@ -16471,16 +16783,33 @@ to double the input image resolution: -vf "libplacebo=w=iw*2:h=ih*2:extra_opts='upscaler=custom\:upscaler_preset=ewa_lanczos\:upscaler_blur=0.9812505644269356'" @end example + +@item shader_cache +File path of a cache directory that libplacebo will use to store and load +cached shader objects. This cache is not cleaned up automatically. If the +path does not end in a directory separator, the generated filenames will be +effectively prefixed by the last path component. All directories must already +exist. + +@example +-vf "libplacebo=shader_cache=/tmp/pl-shader-" +@end example + @item colorspace @item color_primaries @item color_trc @item range +@item chroma_location Configure the colorspace that output frames will be delivered in. The default value of @code{auto} outputs frames in the same format as the input frames, leading to no change. For any other value, conversion will be performed. See the @ref{setparams} filter for a list of possible values. +@item alpha_mode +Choose the desired output alpha mode, when the output format has an alpha +channel. See the @ref{setparams} filter for a list of possible values. + @item apply_filmgrain Apply film grain (e.g. AV1 or H.274) if present in source frames, and strip it from the output. Enabled by default. @@ -16557,7 +16886,7 @@ Cubic spline approximation of lanczos. No difference in performance, but has very slightly less ringing. @item ewa_lanczos -Elliptically weighted average version of lanczos, based on a jinc-sinc kernel. +Elliptically weighted average version of lanczos, based on a jinc-jinc kernel. This is also popularly referred to as just "Jinc scaling". Slow but very high quality. @@ -16595,11 +16924,6 @@ Linear blend/fade between frames. Especially useful for constructing e.g. slideshows. @end table -@item lut_entries -Configures the size of scaler LUTs, ranging from @code{1} to @code{256}. The -default of @code{0} will pick libplacebo's internal default, typically -@code{64}. - @item antiringing Enables anti-ringing (for non-EWA filters). The value (between @code{0.0} and @code{1.0}) configures the strength of the anti-ringing algorithm. May increase @@ -16610,6 +16934,32 @@ Enable sigmoidal compression during upscaling. Reduces ringing slightly. Enabled by default. @end table +@subsubsection Deinterlacing +Deinterlacing is automatically supported when frames are tagged as interlaced, +however frames are not deinterlaced unless a deinterlacing algorithm is chosen. +@table @option +@item deinterlace +The the deinterlacing algorithm to use. +@table @samp +@item weave +No deinterlacing, weave fields together into a single frame. This is the default. +@item bob +Naive bob deinterlacing, simply repeat each field line twice. +@item yadif +Yet another deinterlacing filter. See the @ref{yadif} filter for more details. +@item bwdif +Bob weaver deinterlacing filter. See the @ref{bwdif} filter for more details. +@end table + +@item skip_spatial_check +Skip the spatial deinterlacing check when using @code{yadif} deinterlacing. + +@item send_fields +Output a frame for each field, rather than for each frame. Note that this will +always double the tagged output frame rate, even if the input does not contain +any interlaced frames. Disabled by default. +@end table + @subsubsection Debanding Libplacebo comes with a built-in debanding filter that is good at counteracting many common sources of banding and blocking. Turning this on is highly @@ -16657,6 +17007,11 @@ coefficients for RGB inputs. @item gamma Gamma adjustment, between @code{0.0} and @code{16.0}. Defaults to @code{1.0}. +@item temperature +Color temperature adjustment. Lower values make the output warmer/redder, +down to @code{1667}, while higher values make the output cooler/bluer, up to +@code{25000}. Defaults to @code{6500} (neutral white). + @item cones Cone model to use for color blindness simulation. Accepts any combination of @code{l}, @code{m} and @code{s}. Here are some examples: @@ -16695,17 +17050,13 @@ process. Enabled by default. @item smoothing_period Peak detection smoothing period, between @code{0.0} and @code{1000.0}. Higher values result in peak detection becoming less responsive to changes in the -input. Defaults to @code{100.0}. - -@item minimum_peak -Lower bound on the detected peak (relative to SDR white), between @code{0.0} -and @code{100.0}. Defaults to @code{1.0}. +input. Defaults to @code{20.0}. @item scene_threshold_low @item scene_threshold_high Lower and upper thresholds for scene change detection. Expressed in a -logarithmic scale between @code{0.0} and @code{100.0}. Default to @code{5.5} -and @code{10.0}, respectively. Setting either to a negative value disables +logarithmic scale between @code{0.0} and @code{100.0}. Default to @code{1.0} +and @code{3.0}, respectively. Setting either to a negative value disables this functionality. @item percentile @@ -16905,10 +17256,6 @@ attempting to squeeze the maximum performance at the cost of quality. @item skip_aa Disable anti-aliasing when downscaling. -@item polar_cutoff -Truncate polar (EWA) scaler kernels below this absolute magnitude, between -@code{0.0} and @code{1.0}. - @item disable_linear Disable linear light scaling. @@ -17859,6 +18206,35 @@ Macroblock size. Default @code{16}. Search parameter. Default @code{7}. @end table +@section mestimate_d3d12 + +Estimate and export motion vectors using D3D12 hardware-accelerated motion estimation. +This filter uses GPU hardware motion estimation capabilities available in +DirectX 12 Video APIs to achieve significant performance improvements +over the software-based @code{mestimate} filter. + +Motion vectors are stored in frame side data to be used by other filters. + +This filter requires the input to be in @code{d3d12} hardware pixel format. +The filter uses quarter-pixel precision for motion vector estimation. + +This filter accepts the following options: +@table @option +@item mb_size +Macroblock size. Only @code{8} and @code{16} are supported. +Default @code{16}. +@end table + +@subsection Examples + +Estimate motion vectors using D3D12 hardware acceleration with 16x16 blocks, +and visualize them: +@example +ffmpeg -hwaccel d3d12va -hwaccel_output_format d3d12 -i input.mp4 \ + -vf mestimate_d3d12=mb_size=16,hwdownload,format=nv12,codecview=mv=pf \ + -c:v libx264 -preset fast -b:v 5M output.mp4 +@end example + @section midequalizer Apply Midway Image Equalization effect using two video streams. @@ -18521,6 +18897,69 @@ normalize=blackpt=red:whitept=cyan Pass the video source unchanged to the output. +@section ocio +OpenColorIO library filter + +This filter allows you to do color management using the OpenColorIO library. +See https://opencolorio.org/ for more details. To Enable +compilation of this filter, you need to configure FFmpeg with @code{--enable-libopencolorio}. + +It accepts the following options: + +@table @option +@item config +By default the filter will use the OCIO config defined by the OCIO environment variable, but this parameter allows you to explicitly specify its location. +If you are getting started, you can use config=ocio://studio-config-v1.0.0_aces-v1.3_ocio-v2.1 which specifies one of the built in defaults. + +@item input +Set the input colorspace. + +@item output +Set the output colorspace. + +@item display +Set the display colorspace, used in combination with view. + +@item view +Set the view colorspace, used in combination with display. + +@item inverse +When used in combination with display and view, this inverts the transform, so going from a display/view to the "input colorspace". + +@item filetransform +Allows you to specify an external file-transform to use instead of the OCIO config file. This is useful for applying a single transform without needing a full OCIO config file. + +@item format +Allow you to specify the output pix_fmt of the OCIO filter. This *has* to be a RGB colorspace, so you really are limited to rgb24, rgba, rgb48, rgba48, gbrp10, gbrp12, gbrpf32le, gbrapf32le, for most encoding we would recommend rgb48 + +@item context_params +Allow you to specify additional context parameters for the OCIO filter. This is a list of key=value pairs, separated by colons. + +@end table + +@subsection Examples + +Map from ACEScg to ACEScct, this assumes the OCIO file is defined with the OCIO environment variable. +@example +input=ACEScg:output=ACEScct:format=rgb48 +@end example + +Map from ACEScg to a sRGB display using the "ACES 1.0 - SDR Video" view transform, this assumes the OCIO file is defined with the OCIO environment variable. Note you will need to wrap the argument in quotes to ensure that the spaces are interpreted correctly. +@example +input=ACEScg:display=sRGB - Display:view=ACES 1.0 - SDR Video:format=rgb48 +@end example + + +As above but using the OCIO file studio-config-v1.0.0_aces-v1.3_ocio-v2.1_ns.ocio rather than the OCIO environment variable. +@example +config=studio-config-v1.0.0_aces-v1.3_ocio-v2.1_ns.ocio:input=ACEScg:display=sRGB - Display:view=ACES 1.0 - SDR Video:format=rgb48 +@end example + +If you are converting to YCrCb you still will want to set the color matrix for the conversion. This is a good example of combining the two. +@example +ffmpeg -y -i SOURCEFRAMES.%05d.exr -c:v libx265 -vf "ocio=input=ACEScg:output=ACEScct:format=rgb48,scale=in_color_matrix=bt709:out_color_matrix=bt709,format=yuv444p10" OUTPUTFILE.mov +@end example + @section ocr Optical Character Recognition @@ -18818,7 +19257,8 @@ See @ref{framesync}. @item alpha Set format of alpha of the overlaid video, it can be @var{straight} or -@var{premultiplied}. Default is @var{straight}. +@var{premultiplied}, or @var{auto} to choose the alpha mode automatically. +Default is @var{auto}. @end table The @option{x}, and @option{y} expressions can contain the following @@ -18972,84 +19412,6 @@ testsrc=s=100x100, split=4 [in0][in1][in2][in3]; @end itemize -@anchor{overlay_cuda} -@section overlay_cuda - -Overlay one video on top of another. - -This is the CUDA variant of the @ref{overlay} filter. -It only accepts CUDA frames. The underlying input pixel formats have to match. - -It takes two inputs and has one output. The first input is the "main" -video on which the second input is overlaid. - -It accepts the following parameters: - -@table @option -@item x -@item y -Set expressions for the x and y coordinates of the overlaid video -on the main video. - -They can contain the following parameters: - -@table @option - -@item main_w, W -@item main_h, H -The main input width and height. - -@item overlay_w, w -@item overlay_h, h -The overlay input width and height. - -@item x -@item y -The computed values for @var{x} and @var{y}. They are evaluated for -each new frame. - -@item n -The ordinal index of the main input frame, starting from 0. - -@item pos -The byte offset position in the file of the main input frame, NAN if unknown. -Deprecated, do not use. - -@item t -The timestamp of the main input frame, expressed in seconds, NAN if unknown. - -@end table - -Default value is "0" for both expressions. - -@item eval -Set when the expressions for @option{x} and @option{y} are evaluated. - -It accepts the following values: -@table @option -@item init -Evaluate expressions once during filter initialization or -when a command is processed. - -@item frame -Evaluate expressions for each incoming frame -@end table - -Default value is @option{frame}. - -@item eof_action -See @ref{framesync}. - -@item shortest -See @ref{framesync}. - -@item repeatlast -See @ref{framesync}. - -@end table - -This filter also supports the @ref{framesync} options. - @section owdenoise Apply Overcomplete Wavelet denoiser. @@ -19614,181 +19976,6 @@ Set window Y position, relative offset on Y axis. This filter supports same @ref{commands} as options. -@section pp - -Enable the specified chain of postprocessing subfilters using libpostproc. This -library should be automatically selected with a GPL build (@code{--enable-gpl}). -Subfilters must be separated by '/' and can be disabled by prepending a '-'. -Each subfilter and some options have a short and a long name that can be used -interchangeably, i.e. dr/dering are the same. - -The filters accept the following options: - -@table @option -@item subfilters -Set postprocessing subfilters string. -@end table - -All subfilters share common options to determine their scope: - -@table @option -@item a/autoq -Honor the quality commands for this subfilter. - -@item c/chrom -Do chrominance filtering, too (default). - -@item y/nochrom -Do luma filtering only (no chrominance). - -@item n/noluma -Do chrominance filtering only (no luma). -@end table - -These options can be appended after the subfilter name, separated by a '|'. - -Available subfilters are: - -@table @option -@item hb/hdeblock[|difference[|flatness]] -Horizontal deblocking filter -@table @option -@item difference -Difference factor where higher values mean more deblocking (default: @code{32}). -@item flatness -Flatness threshold where lower values mean more deblocking (default: @code{39}). -@end table - -@item vb/vdeblock[|difference[|flatness]] -Vertical deblocking filter -@table @option -@item difference -Difference factor where higher values mean more deblocking (default: @code{32}). -@item flatness -Flatness threshold where lower values mean more deblocking (default: @code{39}). -@end table - -@item ha/hadeblock[|difference[|flatness]] -Accurate horizontal deblocking filter -@table @option -@item difference -Difference factor where higher values mean more deblocking (default: @code{32}). -@item flatness -Flatness threshold where lower values mean more deblocking (default: @code{39}). -@end table - -@item va/vadeblock[|difference[|flatness]] -Accurate vertical deblocking filter -@table @option -@item difference -Difference factor where higher values mean more deblocking (default: @code{32}). -@item flatness -Flatness threshold where lower values mean more deblocking (default: @code{39}). -@end table -@end table - -The horizontal and vertical deblocking filters share the difference and -flatness values so you cannot set different horizontal and vertical -thresholds. - -@table @option -@item h1/x1hdeblock -Experimental horizontal deblocking filter - -@item v1/x1vdeblock -Experimental vertical deblocking filter - -@item dr/dering -Deringing filter - -@item tn/tmpnoise[|threshold1[|threshold2[|threshold3]]], temporal noise reducer -@table @option -@item threshold1 -larger -> stronger filtering -@item threshold2 -larger -> stronger filtering -@item threshold3 -larger -> stronger filtering -@end table - -@item al/autolevels[:f/fullyrange], automatic brightness / contrast correction -@table @option -@item f/fullyrange -Stretch luma to @code{0-255}. -@end table - -@item lb/linblenddeint -Linear blend deinterlacing filter that deinterlaces the given block by -filtering all lines with a @code{(1 2 1)} filter. - -@item li/linipoldeint -Linear interpolating deinterlacing filter that deinterlaces the given block by -linearly interpolating every second line. - -@item ci/cubicipoldeint -Cubic interpolating deinterlacing filter deinterlaces the given block by -cubically interpolating every second line. - -@item md/mediandeint -Median deinterlacing filter that deinterlaces the given block by applying a -median filter to every second line. - -@item fd/ffmpegdeint -FFmpeg deinterlacing filter that deinterlaces the given block by filtering every -second line with a @code{(-1 4 2 4 -1)} filter. - -@item l5/lowpass5 -Vertically applied FIR lowpass deinterlacing filter that deinterlaces the given -block by filtering all lines with a @code{(-1 2 6 2 -1)} filter. - -@item fq/forceQuant[|quantizer] -Overrides the quantizer table from the input with the constant quantizer you -specify. -@table @option -@item quantizer -Quantizer to use -@end table - -@item de/default -Default pp filter combination (@code{hb|a,vb|a,dr|a}) - -@item fa/fast -Fast pp filter combination (@code{h1|a,v1|a,dr|a}) - -@item ac -High quality pp filter combination (@code{ha|a|128|7,va|a,dr|a}) -@end table - -@subsection Examples - -@itemize -@item -Apply horizontal and vertical deblocking, deringing and automatic -brightness/contrast: -@example -pp=hb/vb/dr/al -@end example - -@item -Apply default filters without brightness/contrast correction: -@example -pp=de/-al -@end example - -@item -Apply default filters and temporal denoiser: -@example -pp=default/tmpnoise|1|2|3 -@end example - -@item -Apply deblocking on luma only, and switch vertical deblocking on or off -automatically depending on available CPU time: -@example -pp=hb|y/vb|a -@end example -@end itemize - @section pp7 Apply Postprocessing filter 7. It is variant of the @ref{spp} filter, similar to spp = 6 with 7 point DCT, where only the center sample is @@ -19832,6 +20019,20 @@ By default value 0xf, all planes will be processed. Do not require 2nd input for processing, instead use alpha plane from input stream. @end table +@section premultiply_dynamic +Dynamically premultiply or unpremultiply the input video stream as needed, +to match the requirements of the downstream filter graph. This is roughly +equivalent to either @code{premultiply:inplace=yes} or +@code{unpremultiply:inplace=yes}, or otherwise a noop. + +The filter accepts the following option: + +@table @option +@item planes +Set which planes will be processed, unprocessed planes will be copied. +By default value 0xf, all planes will be processed. +@end table + @section prewitt Apply prewitt operator to input video stream. @@ -19985,7 +20186,7 @@ Specifies which version of the stats file format to use. Details of each format are written below. Default value is 1. -@item stats_add_max +@item output_max Determines whether the max value is output to the stats log. Default value is 0. Requires stats_version >= 2. If this is set and stats_version < 2, @@ -20160,7 +20361,7 @@ To enable the compilation of this filter, you need to configure FFmpeg with @code{--enable-libqrencode}. The QR code is generated from the provided text or text pattern. The -corresponding QR code is scaled and overlayed into the video output according to +corresponding QR code is scaled and overlaid into the video output according to the specified options. In case no text is specified, no QR code is overlaied. @@ -21066,7 +21267,38 @@ Set libswscale input parameters for scaling algorithms that need them. See complete documentation. If not explicitly specified the filter applies empty parameters. +@item intent +Set the ICC rendering intent to use when transforming between different color +spaces. It accepts the following values: +@table @samp +@item perceptual +Use a perceptually guided tone and gamut mapping curve. The exact details of +the mapping used may change at any time and should not be relied on as stable. +This intent is recommended for final viewing of image/video content in typical +viewing settings. + +@item relative_colorimetric +Statically clip out-of-gamut colors using a colorimetric clipping curve which +attempts to find the colorimetrically least dissimilar in-gamut color. This +intent performs white point adaptation and black point adaptation. This is +the default. This intent is recommended wherever faithful color reproduction +is of the utmost importance, even at the cost of clipping. + +@item absolute_colorimetric +Hard clip out-of-gamut colors with no attempt at white or black point +reproduction. This intent will reproduce in-gamut colors 1:1 on the output +display as they would appear on the reference display, assuming the output +display is appropriately calibrated. + +@item saturation +Performs saturation mapping - that is, stretches the input color volume +directly onto the output color volume, in non-linear fashion that preserves the +original signal appearance as much as possible. This intent is recommended for +signal content evaluation, as it will not lead to any clipping. It is roughly +analogous to not performing any color mapping, although it still takes into +account the mastering display primaries and any differences in encoding TRC. +@end table @item size, s Set the video size. For the syntax of this option, check the @@ -21153,6 +21385,62 @@ is used by default. Possible values: @item bottom @end table +@item in_primaries +@item out_primaries +Set in/output RGB primaries. + +This allows the autodetected value to be overridden as well as allows forcing +a specific value used for the output and encoder. Possible values: + +@table @samp +@item auto +Choose automatically. This is the default. + +@item bt709 +@item bt470m +@item bt470bg +@item smpte170m +@item smpte240m +@item film +@item bt2020 +@item smpte428 +@item smpte431 +@item smpte432 +@item jedec-p22 +@item ebu3213 +@end table + +@item in_transfer +@item out_transfer +Set in/output transfer response curve (TRC). + +This allows the autodetected value to be overridden as well as allows forcing +a specific value used for the output and encoder. Possible values: + +@table @samp +@item auto +Choose automatically. This is the default. + +@item bt709 +@item bt470m +@item gamma22 +@item bt470bg +@item gamma28 +@item smpte170m +@item smpte240m +@item linear +@item iec61966-2-1 +@item srgb +@item iec61966-2-4 +@item xvycc +@item bt1361e +@item bt2020-10 +@item bt2020-12 +@item smpte2084 +@item smpte428 +@item arib-std-b67 +@end table + @item force_original_aspect_ratio Enable decreasing or increasing output video width or height if necessary to keep the original aspect ratio. Possible values: @@ -21193,6 +21481,14 @@ This option can be handy if you need to have a video fit within or exceed a defined resolution using @option{force_original_aspect_ratio} but also have encoder restrictions on width or height divisibility. +@item reset_sar +Enabling this option leads to the output SAR being reset to 1. +Additionally, if the user requests proportional scaling either +through the width or height expressions, e.g. @code{w=-4:h=360} or @code{w=iw/2:h=-1} +or by enabling @code{force_original_aspect_ratio}, then the input DAR is taken into +account and the output is scaled to produce square pixels. +Default is false. + @end table The values of the @option{w} and @option{h} options are expressions @@ -21353,10 +21649,28 @@ scale='trunc(ih*dar):ih',setsar=1/1 @end example @item -Make pixels square by combining scale and setsar, +Make pixels square using reset_sar, making sure the resulting resolution is even (required by some codecs): @example -scale='trunc(ih*dar/2)*2:trunc(ih/2)*2',setsar=1/1 +scale='-2:ih-mod(ih,2):reset_sar=1' +@end example + +@item +Scale to target exactly, however reset SAR to 1: +@example +scale='400:300:reset_sar=1' +@end example + +@item +Scale to even dimensions that fit within 400x300, preserving input SAR: +@example +scale='400:300:force_original_aspect_ratio=decrease:force_divisible_by=2' +@end example + +@item +Scale to produce square pixels with even dimensions that fit within 400x300: +@example +scale='400:300:force_original_aspect_ratio=decrease:force_divisible_by=2:reset_sar=1' @end example @item @@ -21387,302 +21701,6 @@ If the specified expression is not valid, it is kept at its current value. @end table -@anchor{scale_cuda} -@section scale_cuda - -Scale (resize) and convert (pixel format) the input video, using accelerated CUDA kernels. -Setting the output width and height works in the same way as for the @ref{scale} filter. - -The filter accepts the following options: -@table @option -@item w -@item h -Set the output video dimension expression. Default value is the input dimension. - -Allows for the same expressions as the @ref{scale} filter. - -@item interp_algo -Sets the algorithm used for scaling: - -@table @var -@item nearest -Nearest neighbour - -Used by default if input parameters match the desired output. - -@item bilinear -Bilinear - -@item bicubic -Bicubic - -This is the default. - -@item lanczos -Lanczos - -@end table - -@item format -Controls the output pixel format. By default, or if none is specified, the input -pixel format is used. - -The filter does not support converting between YUV and RGB pixel formats. - -@item passthrough -If set to 0, every frame is processed, even if no conversion is necessary. -This mode can be useful to use the filter as a buffer for a downstream -frame-consumer that exhausts the limited decoder frame pool. - -If set to 1, frames are passed through as-is if they match the desired output -parameters. This is the default behaviour. - -@item param -Algorithm-Specific parameter. - -Affects the curves of the bicubic algorithm. - -@item force_original_aspect_ratio -@item force_divisible_by -Work the same as the identical @ref{scale} filter options. - -@end table - -@subsection Examples - -@itemize -@item -Scale input to 720p, keeping aspect ratio and ensuring the output is yuv420p. -@example -scale_cuda=-2:720:format=yuv420p -@end example - -@item -Upscale to 4K using nearest neighbour algorithm. -@example -scale_cuda=4096:2160:interp_algo=nearest -@end example - -@item -Don't do any conversion or scaling, but copy all input frames into newly allocated ones. -This can be useful to deal with a filter and encode chain that otherwise exhausts the -decoders frame pool. -@example -scale_cuda=passthrough=0 -@end example -@end itemize - -@anchor{scale_npp} -@section scale_npp - -Use the NVIDIA Performance Primitives (libnpp) to perform scaling and/or pixel -format conversion on CUDA video frames. Setting the output width and height -works in the same way as for the @var{scale} filter. - -The following additional options are accepted: -@table @option -@item format -The pixel format of the output CUDA frames. If set to the string "same" (the -default), the input format will be kept. Note that automatic format negotiation -and conversion is not yet supported for hardware frames - -@item interp_algo -The interpolation algorithm used for resizing. One of the following: -@table @option -@item nn -Nearest neighbour. - -@item linear -@item cubic -@item cubic2p_bspline -2-parameter cubic (B=1, C=0) - -@item cubic2p_catmullrom -2-parameter cubic (B=0, C=1/2) - -@item cubic2p_b05c03 -2-parameter cubic (B=1/2, C=3/10) - -@item super -Supersampling - -@item lanczos -@end table - -@item force_original_aspect_ratio -Enable decreasing or increasing output video width or height if necessary to -keep the original aspect ratio. Possible values: - -@table @samp -@item disable -Scale the video as specified and disable this feature. - -@item decrease -The output video dimensions will automatically be decreased if needed. - -@item increase -The output video dimensions will automatically be increased if needed. - -@end table - -One useful instance of this option is that when you know a specific device's -maximum allowed resolution, you can use this to limit the output video to -that, while retaining the aspect ratio. For example, device A allows -1280x720 playback, and your video is 1920x800. Using this option (set it to -decrease) and specifying 1280x720 to the command line makes the output -1280x533. - -Please note that this is a different thing than specifying -1 for @option{w} -or @option{h}, you still need to specify the output resolution for this option -to work. - -@item force_divisible_by -Ensures that both the output dimensions, width and height, are divisible by the -given integer when used together with @option{force_original_aspect_ratio}. This -works similar to using @code{-n} in the @option{w} and @option{h} options. - -This option respects the value set for @option{force_original_aspect_ratio}, -increasing or decreasing the resolution accordingly. The video's aspect ratio -may be slightly modified. - -This option can be handy if you need to have a video fit within or exceed -a defined resolution using @option{force_original_aspect_ratio} but also have -encoder restrictions on width or height divisibility. - -@item eval -Specify when to evaluate @var{width} and @var{height} expression. It accepts the following values: - -@table @samp -@item init -Only evaluate expressions once during the filter initialization or when a command is processed. - -@item frame -Evaluate expressions for each incoming frame. - -@end table - -@end table - -The values of the @option{w} and @option{h} options are expressions -containing the following constants: - -@table @var -@item in_w -@item in_h -The input width and height - -@item iw -@item ih -These are the same as @var{in_w} and @var{in_h}. - -@item out_w -@item out_h -The output (scaled) width and height - -@item ow -@item oh -These are the same as @var{out_w} and @var{out_h} - -@item a -The same as @var{iw} / @var{ih} - -@item sar -input sample aspect ratio - -@item dar -The input display aspect ratio. Calculated from @code{(iw / ih) * sar}. - -@item n -The (sequential) number of the input frame, starting from 0. -Only available with @code{eval=frame}. - -@item t -The presentation timestamp of the input frame, expressed as a number of -seconds. Only available with @code{eval=frame}. - -@item pos -The position (byte offset) of the frame in the input stream, or NaN if -this information is unavailable and/or meaningless (for example in case of synthetic video). -Only available with @code{eval=frame}. -Deprecated, do not use. -@end table - -@section scale2ref_npp - -Use the NVIDIA Performance Primitives (libnpp) to scale (resize) the input -video, based on a reference video. - -See the @ref{scale_npp} filter for available options, scale2ref_npp supports the same -but uses the reference video instead of the main input as basis. scale2ref_npp -also supports the following additional constants for the @option{w} and -@option{h} options: - -@table @var -@item main_w -@item main_h -The main input video's width and height - -@item main_a -The same as @var{main_w} / @var{main_h} - -@item main_sar -The main input video's sample aspect ratio - -@item main_dar, mdar -The main input video's display aspect ratio. Calculated from -@code{(main_w / main_h) * main_sar}. - -@item main_n -The (sequential) number of the main input frame, starting from 0. -Only available with @code{eval=frame}. - -@item main_t -The presentation timestamp of the main input frame, expressed as a number of -seconds. Only available with @code{eval=frame}. - -@item main_pos -The position (byte offset) of the frame in the main input stream, or NaN if -this information is unavailable and/or meaningless (for example in case of synthetic video). -Only available with @code{eval=frame}. -@end table - -@subsection Examples - -@itemize -@item -Scale a subtitle stream (b) to match the main video (a) in size before overlaying -@example -'scale2ref_npp[b][a];[a][b]overlay_cuda' -@end example - -@item -Scale a logo to 1/10th the height of a video, while preserving its display aspect ratio. -@example -[logo-in][video-in]scale2ref_npp=w=oh*mdar:h=ih/10[logo-out][video-out] -@end example -@end itemize - -@section scale_vt - -Scale and convert the color parameters using VTPixelTransferSession. - -The filter accepts the following options: -@table @option -@item w -@item h -Set the output video dimension expression. Default value is the input dimension. - -@item color_matrix -Set the output colorspace matrix. - -@item color_primaries -Set the output color primaries. - -@item color_transfer -Set the output transfer characteristics. - -@end table - @section scharr Apply scharr operator to input video stream. @@ -22106,22 +22124,18 @@ Keep the same chroma location (default). @item bottomleft @item bottom @end table -@end table -@section sharpen_npp -Use the NVIDIA Performance Primitives (libnpp) to perform image sharpening with -border control. +@item alpha_mode +Set the alpha moda. +Available values are: -The following additional options are accepted: -@table @option - -@item border_type -Type of sampling to be used ad frame borders. One of the following: -@table @option - -@item replicate -Replicate pixel values. +@table @samp +@item auto +Keep the same alpha mode (default). +@item unspecified, unknown +@item premultiplied +@item straight @end table @end table @@ -22827,6 +22841,76 @@ input upscaled using bicubic upscaling with proper scale factor. To get full functionality (such as async execution), please use the @ref{dnn_processing} filter. +@anchor{sr_amf} +@section sr_amf + +Upscale (size increasing) for the input video using AMD Advanced Media Framework library for hardware acceleration. +Use advanced algorithms for upscaling with higher output quality. +Setting the output width and height works in the same way as for the @ref{scale} filter. + +The filter accepts the following options: +@table @option +@item w +@item h +Set the output video dimension expression. Default value is the input dimension. + +Allows for the same expressions as the @ref{scale} filter. + +@item algorithm +Sets the algorithm used for scaling: + +@table @var +@item bilinear +Bilinear + +@item bicubic +Bicubic + +@item sr1-0 +Video SR1.0 +This is a default value + +@item point +Point + +@item sr1-1 +Video SR1.1 + +@end table + +@item sharpness +Control hq scaler sharpening. The value is a float in the range of [0.0, 2.0] + +@item format +Controls the output pixel format. By default, or if none is specified, the input +pixel format is used. + +@item keep-ratio +Force the scaler to keep the aspect ratio of the input image when the output size has a different aspect ratio. +Default value is false. + +@item fill +Specifies whether the output image outside the region of interest, +which does not fill the entire output surface should be filled with a solid color. + +@end table + +@subsection Examples + +@itemize +@item +Scale input to 720p, keeping aspect ratio and ensuring the output is yuv420p. +@example +sr_amf=-2:720:format=yuv420p +@end example + +@item +Upscale to 4K with algorithm video SR1.1. +@example +sr_amf=4096:2160:algorithm=sr1-1 +@end example +@end itemize + @section ssim Obtain the SSIM (Structural SImilarity Metric) between two input videos. @@ -23598,7 +23682,7 @@ by progressively selecting a different column from each input frame. The end result is a sort of inverted parallax, so that far away objects move much faster that the ones in the front. The ideal conditions for this video -effect are when there is either very little motion and the backgroud is static, +effect are when there is either very little motion and the background is static, or when there is a lot of motion and a very wide depth of field (e.g. wide panorama, while moving on a train). @@ -23626,7 +23710,7 @@ How many columns should be inserted before end of filtering. Normally the filter shifts and tilts from the very first frame, and stops when the last one is received. However, before filtering starts, normal video may -be preseved, so that the effect is slowly shifted in its place. Similarly, +be preserved, so that the effect is slowly shifted in its place. Similarly, the last video frame may be reconstructed at the end. Alternatively it is possible to just start and end with black. @@ -24212,47 +24296,6 @@ The command above can also be specified as: transpose=1:portrait @end example -@section transpose_npp - -Transpose rows with columns in the input video and optionally flip it. -For more in depth examples see the @ref{transpose} video filter, which shares mostly the same options. - -It accepts the following parameters: - -@table @option - -@item dir -Specify the transposition direction. - -Can assume the following values: -@table @samp -@item cclock_flip -Rotate by 90 degrees counterclockwise and vertically flip. (default) - -@item clock -Rotate by 90 degrees clockwise. - -@item cclock -Rotate by 90 degrees counterclockwise. - -@item clock_flip -Rotate by 90 degrees clockwise and vertically flip. -@end table - -@item passthrough -Do not apply the transposition if the input geometry matches the one -specified by the specified value. It accepts the following values: -@table @samp -@item none -Always apply transposition. (default) -@item portrait -Preserve portrait geometry (when @var{height} >= @var{width}). -@item landscape -Preserve landscape geometry (when @var{width} >= @var{height}). -@end table - -@end table - @section trim Trim the input so that the output contains one continuous subpart of the input. @@ -25565,6 +25608,175 @@ Example: ffmpeg -i ref.mpg -vf vmafmotion -f null - @end example +@anchor{vpp_amf} +@section vpp_amf + +Scale (resize) and convert colorspace, transfer characteristics or color primaries for the input video, using AMD Advanced Media Framework library for hardware acceleration. +Setting the output width and height works in the same way as for the @ref{scale} filter. + +The filter accepts the following options: +@table @option +@item w +@item h +Set the output video dimension expression. Default value is the input dimension. + +Allows for the same expressions as the @ref{scale} filter. + +@item scale_type +Sets the algorithm used for scaling: + +@table @var +@item bilinear +Bilinear + +This is the default. + +@item bicubic +Bicubic + +@end table + +@item format +Controls the output pixel format. By default, or if none is specified, the input +pixel format is used. + + +@item force_original_aspect_ratio +@item force_divisible_by +Work the same as the identical @ref{scale} filter options. + +@item reset_sar +Works the same as the identical @ref{scale} filter option. + +@anchor{color_profile} +@item color_profile +Specify all color properties at once. + +The accepted values are: +@table @samp +@item bt601 +BT.601 + +@item bt709 +BT.709 + +@item bt2020 +BT.2020 + +@end table + +@item trc +Specify output transfer characteristics. + +The accepted values are: +@table @samp +@item bt709 +BT.709 + +@item gamma22 +Constant gamma of 2.2 + +@item gamma28 +Constant gamma of 2.8 + +@item smpte170m +SMPTE-170M + +@item smpte240m +SMPTE-240M + +@item linear +Linear + +@item log +LOG + +@item log-sqrt +LOG_SQRT + +@item iec61966-2-4 +iec61966-2-4 + +@item bt1361-ecg +BT1361_ECG + +@item iec61966-2-1 +iec61966-2-1 + +@item bt2020-10 +BT.2020 for 10-bits content + +@item bt2020-12 +BT.2020 for 12-bits content + +@item smpte2084 +SMPTE2084 + +@item smpte428 +SMPTE428 + +@item arib-std-b67 +ARIB_STD_B67 + +@end table + +@item primaries +Specify output color primaries. + +The accepted values are: +@table @samp +@item bt709 +BT.709 + +@item bt470m +BT.470M + +@item bt470bg +BT.470BG or BT.601-6 625 + +@item smpte170m +SMPTE-170M or BT.601-6 525 + +@item smpte240m +SMPTE-240M + +@item film +film + +@item bt2020 +BT.2020 + +@item smpte428 +SMPTE-428 + +@item smpte431 +SMPTE-431 + +@item smpte432 +SMPTE-432 + +@item jedec-p22 +JEDEC P22 phosphors + +@end table +@end table + +@subsection Examples + +@itemize +@item +Scale input to 720p, keeping aspect ratio and ensuring the output is yuv420p. +@example +vpp_amf=-2:720:format=yuv420p +@end example + +@item +Upscale to 4K and change color profile to bt2020. +@example +vpp_amf=4096:2160:color_profile=bt2020 +@end example +@end itemize + @anchor{vstack} @section vstack Stack input videos vertically. @@ -25819,7 +26031,7 @@ pixel formats are not RGB. @item fitmode, fm Set sample aspect ratio of video output frames. Can be used to configure waveform so it is not -streched too much in one of directions. +stretched too much in one of directions. @table @samp @item none @@ -26270,64 +26482,6 @@ filter"). It accepts the following parameters: -@table @option - -@item mode -The interlacing mode to adopt. It accepts one of the following values: - -@table @option -@item 0, send_frame -Output one frame for each frame. -@item 1, send_field -Output one frame for each field. -@item 2, send_frame_nospatial -Like @code{send_frame}, but it skips the spatial interlacing check. -@item 3, send_field_nospatial -Like @code{send_field}, but it skips the spatial interlacing check. -@end table - -The default value is @code{send_frame}. - -@item parity -The picture field parity assumed for the input interlaced video. It accepts one -of the following values: - -@table @option -@item 0, tff -Assume the top field is first. -@item 1, bff -Assume the bottom field is first. -@item -1, auto -Enable automatic detection of field parity. -@end table - -The default value is @code{auto}. -If the interlacing is unknown or the decoder does not export this information, -top field first will be assumed. - -@item deint -Specify which frames to deinterlace. Accepts one of the following -values: - -@table @option -@item 0, all -Deinterlace all frames. -@item 1, interlaced -Only deinterlace frames marked as interlaced. -@end table - -The default value is @code{all}. -@end table - -@section yadif_cuda - -Deinterlace the input video using the @ref{yadif} algorithm, but implemented -in CUDA so that it can work as part of a GPU accelerated pipeline with nvdec -and/or nvenc. - -It accepts the following parameters: - - @table @option @item mode @@ -26580,6 +26734,7 @@ Possible values are: @item bicubic @item spline16 @item spline36 +@item spline64 @item lanczos @end table @@ -26798,6 +26953,771 @@ value. @c man end VIDEO FILTERS +@chapter CUDA Video Filters +@c man begin CUDA Video Filters + +To enable CUDA and/or NPP filters please refer to configuration guidelines for @ref{CUDA} and for @ref{CUDA NPP} filters. + +Running CUDA filters requires you to initialize a hardware device and to pass that device to all filters in any filter graph. +@table @option + +@item -init_hw_device cuda[=@var{name}][:@var{device}[,@var{key=value}...]] +Initialise a new hardware device of type @var{cuda} called @var{name}, using the +given device parameters. + +@item -filter_hw_device @var{name} +Pass the hardware device called @var{name} to all filters in any filter graph. + +@end table + +For more detailed information see @url{https://www.ffmpeg.org/ffmpeg.html#Advanced-Video-options} + +@itemize +@item +Example of initializing second CUDA device on the system and running scale_cuda and bilateral_cuda filters. +@example +./ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -init_hw_device cuda:1 -filter_complex \ +"[0:v]scale_cuda=format=yuv444p[scaled_video];[scaled_video]bilateral_cuda=window_size=9:sigmaS=3.0:sigmaR=50.0" \ +-an -sn -c:v h264_nvenc -cq 20 out.mp4 +@end example +@end itemize + +Since CUDA filters operate exclusively on GPU memory, frame data must sometimes be uploaded (@ref{hwupload}) to hardware surfaces associated with the appropriate CUDA device before processing, and downloaded (@ref{hwdownload}) back to normal memory afterward, if required. Whether @ref{hwupload} or @ref{hwdownload} is necessary depends on the specific workflow: + +@itemize +@item If the input frames are already in GPU memory (e.g., when using @code{-hwaccel cuda} or @code{-hwaccel_output_format cuda}), explicit use of @ref{hwupload} is not needed, as the data is already in the appropriate memory space. +@item If the input frames are in CPU memory (e.g., software-decoded frames or frames processed by CPU-based filters), it is necessary to use @ref{hwupload} to transfer the data to GPU memory for CUDA processing. +@item If the output of the CUDA filters needs to be further processed by software-based filters or saved in a format not supported by GPU-based encoders, @ref{hwdownload} is required to transfer the data back to CPU memory. +@end itemize +Note that @ref{hwupload} uploads data to a surface with the same layout as the software frame, so it may be necessary to add a @ref{format} filter immediately before @ref{hwupload} to ensure the input is in the correct format. Similarly, @ref{hwdownload} may not support all output formats, so an additional @ref{format} filter may need to be inserted immediately after @ref{hwdownload} in the filter graph to ensure compatibility. + +@anchor{CUDA} +@section CUDA +Below is a description of the currently available Nvidia CUDA video filters. + +Prerequisites: +@itemize +@item Install Nvidia CUDA Toolkit +@end itemize + +Note: If FFmpeg detects the Nvidia CUDA Toolkit during configuration, it will enable CUDA filters automatically without requiring any additional flags. If you want to explicitly enable them, use the following options: + +@itemize +@item Configure FFmpeg with @code{--enable-cuda-nvcc --enable-nonfree}. +@item Configure FFmpeg with @code{--enable-cuda-llvm}. Additional requirement: @code{llvm} lib must be installed. +@end itemize + +@subsection bilateral_cuda +CUDA accelerated bilateral filter, an edge preserving filter. +This filter is mathematically accurate thanks to the use of GPU acceleration. +For best output quality, use one to one chroma subsampling, i.e. yuv444p format. + +The filter accepts the following options: +@table @option +@item sigmaS +Set sigma of gaussian function to calculate spatial weight, also called sigma space. +Allowed range is 0.1 to 512. Default is 0.1. + +@item sigmaR +Set sigma of gaussian function to calculate color range weight, also called sigma color. +Allowed range is 0.1 to 512. Default is 0.1. + +@item window_size +Set window size of the bilateral function to determine the number of neighbours to loop on. +If the number entered is even, one will be added automatically. +Allowed range is 1 to 255. Default is 1. +@end table +@subsubsection Examples + +@itemize +@item +Apply the bilateral filter on a video. + +@example +./ffmpeg -v verbose \ +-hwaccel cuda -hwaccel_output_format cuda -i input.mp4 \ +-init_hw_device cuda \ +-filter_complex \ +" \ +[0:v]scale_cuda=format=yuv444p[scaled_video]; +[scaled_video]bilateral_cuda=window_size=9:sigmaS=3.0:sigmaR=50.0" \ +-an -sn -c:v h264_nvenc -cq 20 out.mp4 +@end example + +@end itemize + +@subsection bwdif_cuda + +Deinterlace the input video using the @ref{bwdif} algorithm, but implemented +in CUDA so that it can work as part of a GPU accelerated pipeline with nvdec +and/or nvenc. + +It accepts the following parameters: + +@table @option +@item mode +The interlacing mode to adopt. It accepts one of the following values: + +@table @option +@item 0, send_frame +Output one frame for each frame. +@item 1, send_field +Output one frame for each field. +@end table + +The default value is @code{send_field}. + +@item parity +The picture field parity assumed for the input interlaced video. It accepts one +of the following values: + +@table @option +@item 0, tff +Assume the top field is first. +@item 1, bff +Assume the bottom field is first. +@item -1, auto +Enable automatic detection of field parity. +@end table + +The default value is @code{auto}. +If the interlacing is unknown or the decoder does not export this information, +top field first will be assumed. + +@item deint +Specify which frames to deinterlace. Accepts one of the following +values: + +@table @option +@item 0, all +Deinterlace all frames. +@item 1, interlaced +Only deinterlace frames marked as interlaced. +@end table + +The default value is @code{all}. +@end table + +@subsection chromakey_cuda +CUDA accelerated YUV colorspace color/chroma keying. + +This filter works like normal chromakey filter but operates on CUDA frames. +for more details and parameters see @ref{chromakey}. + +@subsubsection Examples + +@itemize +@item +Make all the green pixels in the input video transparent and use it as an overlay for another video: + +@example +./ffmpeg \ + -hwaccel cuda -hwaccel_output_format cuda -i input_green.mp4 \ + -hwaccel cuda -hwaccel_output_format cuda -i base_video.mp4 \ + -init_hw_device cuda \ + -filter_complex \ + " \ + [0:v]chromakey_cuda=0x25302D:0.1:0.12:1[overlay_video]; \ + [1:v]scale_cuda=format=yuv420p[base]; \ + [base][overlay_video]overlay_cuda" \ + -an -sn -c:v h264_nvenc -cq 20 output.mp4 +@end example + +@item +Process two software sources, explicitly uploading the frames: + +@example +./ffmpeg -init_hw_device cuda=cuda -filter_hw_device cuda \ + -f lavfi -i color=size=800x600:color=white,format=yuv420p \ + -f lavfi -i yuvtestsrc=size=200x200,format=yuv420p \ + -filter_complex \ + " \ + [0]hwupload[under]; \ + [1]hwupload,chromakey_cuda=green:0.1:0.12[over]; \ + [under][over]overlay_cuda" \ + -c:v hevc_nvenc -cq 18 -preset slow output.mp4 +@end example + +@end itemize + +@subsection colorspace_cuda + +CUDA accelerated implementation of the colorspace filter. + +It is by no means feature complete compared to the software colorspace filter, +and at the current time only supports color range conversion between jpeg/full +and mpeg/limited range. + +The filter accepts the following options: + +@table @option +@item range +Specify output color range. + +The accepted values are: +@table @samp +@item tv +TV (restricted) range + +@item mpeg +MPEG (restricted) range + +@item pc +PC (full) range + +@item jpeg +JPEG (full) range + +@end table + +@end table + +@anchor{overlay_cuda} +@subsection overlay_cuda + +Overlay one video on top of another. + +This is the CUDA variant of the @ref{overlay} filter. +It only accepts CUDA frames. The underlying input pixel formats have to match. + +It takes two inputs and has one output. The first input is the "main" +video on which the second input is overlaid. + +It accepts the following parameters: + +@table @option +@item x +@item y +Set expressions for the x and y coordinates of the overlaid video +on the main video. + +They can contain the following parameters: + +@table @option + +@item main_w, W +@item main_h, H +The main input width and height. + +@item overlay_w, w +@item overlay_h, h +The overlay input width and height. + +@item x +@item y +The computed values for @var{x} and @var{y}. They are evaluated for +each new frame. + +@item n +The ordinal index of the main input frame, starting from 0. + +@item pos +The byte offset position in the file of the main input frame, NAN if unknown. +Deprecated, do not use. + +@item t +The timestamp of the main input frame, expressed in seconds, NAN if unknown. + +@end table + +Default value is "0" for both expressions. + +@item eval +Set when the expressions for @option{x} and @option{y} are evaluated. + +It accepts the following values: +@table @option +@item init +Evaluate expressions once during filter initialization or +when a command is processed. + +@item frame +Evaluate expressions for each incoming frame +@end table + +Default value is @option{frame}. + +@item eof_action +See @ref{framesync}. + +@item shortest +See @ref{framesync}. + +@item repeatlast +See @ref{framesync}. + +@end table + +This filter also supports the @ref{framesync} options. + + +@anchor{pad_cuda} +@subsection pad_cuda +Add paddings to an input video stream using CUDA. + +This filter is the CUDA-accelerated version of the @ref{pad} filter. It accepts the same options and expressions and provides the same core functionality. +For a detailed description of available options, please see the documentation for the @ref{pad} filter. + +@subsubsection Examples + +@itemize +@item +Add a 200-pixel black border to all sides of a video frame: +@example +ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -vf "pad_cuda=w=iw+400:h=ih+400:x=200:y=200" -c:v h264_nvenc out.mp4 +@end example + +@item +Pad the input video to a 16:9 aspect ratio, filling with the color "blue": +@example +ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -vf "pad_cuda=w=ih*16/9/sar:h=ih:x=(ow-iw)/2:y=(oh-ih)/2:color=blue" -c:v h264_nvenc out.mp4 +@end example +@end itemize + +@anchor{scale_cuda} +@subsection scale_cuda + +Scale (resize) and convert (pixel format) the input video, using accelerated CUDA kernels. +Setting the output width and height works in the same way as for the @ref{scale} filter. + +The filter accepts the following options: +@table @option +@item w +@item h +Set the output video dimension expression. Default value is the input dimension. + +Allows for the same expressions as the @ref{scale} filter. + +@item interp_algo +Sets the algorithm used for scaling: + +@table @var +@item nearest +Nearest neighbour + +Used by default if input parameters match the desired output. + +@item bilinear +Bilinear + +@item bicubic +Bicubic + +This is the default. + +@item lanczos +Lanczos + +@end table + +@item format +Controls the output pixel format. By default, or if none is specified, the input +pixel format is used. + +The filter does not support converting between YUV and RGB pixel formats. + +@item passthrough +If set to 0, every frame is processed, even if no conversion is necessary. +This mode can be useful to use the filter as a buffer for a downstream +frame-consumer that exhausts the limited decoder frame pool. + +If set to 1, frames are passed through as-is if they match the desired output +parameters. This is the default behaviour. + +@item param +Algorithm-Specific parameter. + +Affects the curves of the bicubic algorithm. + +@item force_original_aspect_ratio +@item force_divisible_by +Work the same as the identical @ref{scale} filter options. + +@item reset_sar +Works the same as the identical @ref{scale} filter option. + +@end table + +@subsubsection Examples + +@itemize +@item +Scale input to 720p, keeping aspect ratio and ensuring the output is yuv420p. +@example +scale_cuda=-2:720:format=yuv420p +@end example + +@item +Upscale to 4K using nearest neighbour algorithm. +@example +scale_cuda=4096:2160:interp_algo=nearest +@end example + +@item +Don't do any conversion or scaling, but copy all input frames into newly allocated ones. +This can be useful to deal with a filter and encode chain that otherwise exhausts the +decoders frame pool. +@example +scale_cuda=passthrough=0 +@end example +@end itemize + +@subsection thumbnail_cuda + +Select the most representative frame in a given sequence of consecutive frames using CUDA. + +The filter accepts the following options: + +@table @option +@item n +Set the frames batch size to analyze; in a set of @var{n} frames, the filter +will pick one of them, and then handle the next batch of @var{n} frames until +the end. Default is @code{100}. +@end table + +Since the filter keeps track of the whole frames sequence, a bigger @var{n} +value will result in a higher memory usage, so a high value is not recommended. + +@subsubsection Example + +@itemize + +@item +Thumbnails are extracted from every @var{n}=150-frame batch, selecting one per batch. Chosen frames are then scaled with @ref{scale_cuda}. +@example +./ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i ./input.mp4 -vf "thumbnail_cuda=150,scale_cuda=1920:1080,hwdownload,format=nv12" ./output/out%03d.png +@end example + +@end itemize + +@subsection yadif_cuda + +Deinterlace the input video using the @ref{yadif} algorithm, but implemented +in CUDA so that it can work as part of a GPU accelerated pipeline with nvdec +and/or nvenc. + +It accepts the following parameters: + + +@table @option + +@item mode +The interlacing mode to adopt. It accepts one of the following values: + +@table @option +@item 0, send_frame +Output one frame for each frame. +@item 1, send_field +Output one frame for each field. +@item 2, send_frame_nospatial +Like @code{send_frame}, but it skips the spatial interlacing check. +@item 3, send_field_nospatial +Like @code{send_field}, but it skips the spatial interlacing check. +@end table + +The default value is @code{send_frame}. + +@item parity +The picture field parity assumed for the input interlaced video. It accepts one +of the following values: + +@table @option +@item 0, tff +Assume the top field is first. +@item 1, bff +Assume the bottom field is first. +@item -1, auto +Enable automatic detection of field parity. +@end table + +The default value is @code{auto}. +If the interlacing is unknown or the decoder does not export this information, +top field first will be assumed. + +@item deint +Specify which frames to deinterlace. Accepts one of the following +values: + +@table @option +@item 0, all +Deinterlace all frames. +@item 1, interlaced +Only deinterlace frames marked as interlaced. +@end table + +The default value is @code{all}. +@end table + +@anchor{CUDA NPP} +@section CUDA NPP +Below is a description of the currently available NVIDIA Performance Primitives (libnpp) video filters. + +Prerequisites: +@itemize +@item Install Nvidia CUDA Toolkit +@item Install libnpp +@end itemize + +To enable CUDA NPP filters: + +@itemize +@item Configure FFmpeg with @code{--enable-nonfree --enable-libnpp}. +@end itemize + + +@anchor{scale_npp} +@subsection scale_npp + +Use the NVIDIA Performance Primitives (libnpp) to perform scaling and/or pixel +format conversion on CUDA video frames. Setting the output width and height +works in the same way as for the @var{scale} filter. + +The following additional options are accepted: +@table @option +@item format +The pixel format of the output CUDA frames. If set to the string "same" (the +default), the input format will be kept. Note that automatic format negotiation +and conversion is not yet supported for hardware frames + +@item interp_algo +The interpolation algorithm used for resizing. One of the following: +@table @option +@item nn +Nearest neighbour. + +@item linear +@item cubic +@item cubic2p_bspline +2-parameter cubic (B=1, C=0) + +@item cubic2p_catmullrom +2-parameter cubic (B=0, C=1/2) + +@item cubic2p_b05c03 +2-parameter cubic (B=1/2, C=3/10) + +@item super +Supersampling + +@item lanczos +@end table + +@item force_original_aspect_ratio +Enable decreasing or increasing output video width or height if necessary to +keep the original aspect ratio. Possible values: + +@table @samp +@item disable +Scale the video as specified and disable this feature. + +@item decrease +The output video dimensions will automatically be decreased if needed. + +@item increase +The output video dimensions will automatically be increased if needed. + +@end table + +One useful instance of this option is that when you know a specific device's +maximum allowed resolution, you can use this to limit the output video to +that, while retaining the aspect ratio. For example, device A allows +1280x720 playback, and your video is 1920x800. Using this option (set it to +decrease) and specifying 1280x720 to the command line makes the output +1280x533. + +Please note that this is a different thing than specifying -1 for @option{w} +or @option{h}, you still need to specify the output resolution for this option +to work. + +@item force_divisible_by +Ensures that both the output dimensions, width and height, are divisible by the +given integer when used together with @option{force_original_aspect_ratio}. This +works similar to using @code{-n} in the @option{w} and @option{h} options. + +This option respects the value set for @option{force_original_aspect_ratio}, +increasing or decreasing the resolution accordingly. The video's aspect ratio +may be slightly modified. + +This option can be handy if you need to have a video fit within or exceed +a defined resolution using @option{force_original_aspect_ratio} but also have +encoder restrictions on width or height divisibility. + +@item reset_sar +Works the same as the identical @ref{scale} filter option. + +@item eval +Specify when to evaluate @var{width} and @var{height} expression. It accepts the following values: + +@table @samp +@item init +Only evaluate expressions once during the filter initialization or when a command is processed. + +@item frame +Evaluate expressions for each incoming frame. + +@end table + +@end table + +The values of the @option{w} and @option{h} options are expressions +containing the following constants: + +@table @var +@item in_w +@item in_h +The input width and height + +@item iw +@item ih +These are the same as @var{in_w} and @var{in_h}. + +@item out_w +@item out_h +The output (scaled) width and height + +@item ow +@item oh +These are the same as @var{out_w} and @var{out_h} + +@item a +The same as @var{iw} / @var{ih} + +@item sar +input sample aspect ratio + +@item dar +The input display aspect ratio. Calculated from @code{(iw / ih) * sar}. + +@item n +The (sequential) number of the input frame, starting from 0. +Only available with @code{eval=frame}. + +@item t +The presentation timestamp of the input frame, expressed as a number of +seconds. Only available with @code{eval=frame}. + +@item pos +The position (byte offset) of the frame in the input stream, or NaN if +this information is unavailable and/or meaningless (for example in case of synthetic video). +Only available with @code{eval=frame}. +Deprecated, do not use. +@end table + +@subsection scale2ref_npp + +Use the NVIDIA Performance Primitives (libnpp) to scale (resize) the input +video, based on a reference video. + +See the @ref{scale_npp} filter for available options, scale2ref_npp supports the same +but uses the reference video instead of the main input as basis. scale2ref_npp +also supports the following additional constants for the @option{w} and +@option{h} options: + +@table @var +@item main_w +@item main_h +The main input video's width and height + +@item main_a +The same as @var{main_w} / @var{main_h} + +@item main_sar +The main input video's sample aspect ratio + +@item main_dar, mdar +The main input video's display aspect ratio. Calculated from +@code{(main_w / main_h) * main_sar}. + +@item main_n +The (sequential) number of the main input frame, starting from 0. +Only available with @code{eval=frame}. + +@item main_t +The presentation timestamp of the main input frame, expressed as a number of +seconds. Only available with @code{eval=frame}. + +@item main_pos +The position (byte offset) of the frame in the main input stream, or NaN if +this information is unavailable and/or meaningless (for example in case of synthetic video). +Only available with @code{eval=frame}. +@end table + +@subsubsection Examples + +@itemize +@item +Scale a subtitle stream (b) to match the main video (a) in size before overlaying +@example +'scale2ref_npp[b][a];[a][b]overlay_cuda' +@end example + +@item +Scale a logo to 1/10th the height of a video, while preserving its display aspect ratio. +@example +[logo-in][video-in]scale2ref_npp=w=oh*mdar:h=ih/10[logo-out][video-out] +@end example +@end itemize + +@subsection sharpen_npp +Use the NVIDIA Performance Primitives (libnpp) to perform image sharpening with +border control. + +The following additional options are accepted: +@table @option + +@item border_type +Type of sampling to be used ad frame borders. One of the following: +@table @option + +@item replicate +Replicate pixel values. + +@end table +@end table + +@subsection transpose_npp + +Transpose rows with columns in the input video and optionally flip it. +For more in depth examples see the @ref{transpose} video filter, which shares mostly the same options. + +It accepts the following parameters: + +@table @option + +@item dir +Specify the transposition direction. + +Can assume the following values: +@table @samp +@item cclock_flip +Rotate by 90 degrees counterclockwise and vertically flip. (default) + +@item clock +Rotate by 90 degrees clockwise. + +@item cclock +Rotate by 90 degrees counterclockwise. + +@item clock_flip +Rotate by 90 degrees clockwise and vertically flip. +@end table + +@item passthrough +Do not apply the transposition if the input geometry matches the one +specified by the specified value. It accepts the following values: +@table @samp +@item none +Always apply transposition. (default) +@item portrait +Preserve portrait geometry (when @var{height} >= @var{width}). +@item landscape +Preserve landscape geometry (when @var{width} >= @var{height}). +@end table + +@end table + +@c man end CUDA Video Filters + @chapter OpenCL Video Filters @c man begin OPENCL VIDEO FILTERS @@ -28210,6 +29130,106 @@ drawbox=x=-t:y=0.5*(ih-iw/2.4)-t:w=iw+t*2:h=iw/2.4+t*2:t=2:c=red @c man end VAAPI VIDEO FILTERS +@chapter VideoToolbox Video Filters +@c man begin VIDEOTOOLBOX VIDEO FILTERS + +Below is a description of the currently available VideoToolbox video filters. + +VideoToolbox filter depends on VideoToolbox framework, and is auto detected +when building ffmpeg for an Apple platform such as macOS. Add +@code{--enable-videotoolbox} to configure if autodetect is disabled. + +@section scale_vt + +Scale and convert the color parameters using VTPixelTransferSession. + +The filter accepts the following options: +@table @option +@item w +@item h +Set the output video dimension expression. Default value is the input dimension. + +@item color_matrix +Set the output colorspace matrix. + +@item color_primaries +Set the output color primaries. + +@item color_transfer +Set the output transfer characteristics. + +@end table + +@subsection Examples + +@itemize +@item +Perform HDR to SDR conversion, and scale to half size of input +@example +ffmpeg -hwaccel videotoolbox \ + -hwaccel_output_format videotoolbox_vld \ + -i hdr.mov \ + -c:v hevc_videotoolbox \ + -profile:v main \ + -b:v 3M \ + -vf scale_vt=w=iw/2:h=ih/2:color_matrix=bt709:color_primaries=bt709:color_transfer=bt709 \ + -c:a copy \ + -tag:v hvc1 \ + sdr.mp4 +@end example + +@end itemize + +@section transpose_vt + +Transpose rows with columns in the input video and optionally flip it. +For more in depth examples see the @ref{transpose} video filter, which shares mostly the same options. + +It accepts the following parameters: + +@table @option + +@item dir +Specify the transposition direction. + +Can assume the following values: +@table @samp +@item cclock_flip +Rotate by 90 degrees counterclockwise and vertically flip. (default) + +@item clock +Rotate by 90 degrees clockwise. + +@item cclock +Rotate by 90 degrees counterclockwise. + +@item clock_flip +Rotate by 90 degrees clockwise and vertically flip. + +@item hflip +Flip the input video horizontally. + +@item vflip +Flip the input video vertically. + +@end table + +@item passthrough +Do not apply the transposition if the input geometry matches the one +specified by the specified value. It accepts the following values: +@table @samp +@item none +Always apply transposition. (default) +@item portrait +Preserve portrait geometry (when @var{height} >= @var{width}). +@item landscape +Preserve landscape geometry (when @var{width} >= @var{height}). +@end table + +@end table + +@c man end VIDEOTOOLBOX VIDEO FILTERS + @chapter Vulkan Video Filters @c man begin VULKAN VIDEO FILTERS @@ -28235,6 +29255,10 @@ Allocates linear images. Does not apply to decoding. @item disable_multiplane Disables multiplane images. Does not apply to decoding. + +@item avoid_host_import +Avoids the use of dynamic host memory imports, in favor of a regular memcpy() +into a previously mapped buffer. @end table @item -filter_hw_device @var{name} @@ -28461,7 +29485,7 @@ The filter accepts the following options. @table @option @item s -Set denoising strength for all components. Default is 1.0. Must be in range [1.0, 100.0]. +Set denoising strength for all components. Default is 1.0. Must be in range [0.0, 100.0]. @item p Set patch size for all planes. Default is 7. Must be odd number in range [0, 99]. @@ -28470,17 +29494,16 @@ Set patch size for all planes. Default is 7. Must be odd number in range [0, 99] Set research size. Default is 15. Must be odd number in range [0, 99]. @item t -Set parallelism. Default is 36. Must be a number in the range [1, 168]. -Larger values may speed up processing, at the cost of more VRAM. -Lower values will slow it down, reducing VRAM usage. -Only supported on GPUs with atomic float operations (RDNA3+, Ampere+). +Set parallelism. Default is 8. Must be a number in the range [1, 64]. +Larger values will use more VRAM but may not result in greater speed. +The optimal value is hardware and input dependent. @item s0 @item s1 @item s2 @item s3 -Set denoising strength for a specific component. Default is @var{1}, equal to @option{s}. -Must be odd number in range [1, 100]. +Set denoising strength for a specific component. Default is @var{1.0}, equal to @option{s}. +Must be in range [0.0, 100.0]. 0.0 disables denoising in that component. @item p0 @item p1 @@ -28511,54 +29534,6 @@ Default value is @code{0}. @end table -@section transpose_vt - -Transpose rows with columns in the input video and optionally flip it. -For more in depth examples see the @ref{transpose} video filter, which shares mostly the same options. - -It accepts the following parameters: - -@table @option - -@item dir -Specify the transposition direction. - -Can assume the following values: -@table @samp -@item cclock_flip -Rotate by 90 degrees counterclockwise and vertically flip. (default) - -@item clock -Rotate by 90 degrees clockwise. - -@item cclock -Rotate by 90 degrees counterclockwise. - -@item clock_flip -Rotate by 90 degrees clockwise and vertically flip. - -@item hflip -Flip the input video horizontally. - -@item vflip -Flip the input video vertically. - -@end table - -@item passthrough -Do not apply the transposition if the input geometry matches the one -specified by the specified value. It accepts the following values: -@table @samp -@item none -Always apply transposition. (default) -@item portrait -Preserve portrait geometry (when @var{height} >= @var{width}). -@item landscape -Preserve landscape geometry (when @var{width} >= @var{height}). -@end table - -@end table - @section transpose_vulkan Transpose rows with columns in the input video and optionally flip it. @@ -28738,6 +29713,11 @@ A string representing the color range of the buffered video frames. It may be a number corresponding to a color range, or a color range name. +@item alpha_mode +A string representing the alpha mode of the buffered video frames. +It may be a number corresponding to an alpha mode, or an alpha mode +name. + @item pixel_aspect, sar The sample (pixel) aspect ratio of the input video. @@ -29037,6 +30017,165 @@ ddagrab=video_size=800x600:offset_x=100:offset_y=100 @end example +@section gfxcapture + +Capture windows or monitors using Windows.Graphics.Capture API. + +This source provides low overhead capture of application windows or entire monitors. +The filter outputs hardware frames in @code{d3d11} format; use @code{hwdownload,format=} +if system memory frames are required. + +The window to be captured can be selected via regular expressions on its title, +class name or backing executable name, by explicit native handles, or by monitor +index or explicit native handle. A window must match all provided expressions to be +selected. The first matching window will be picked, in whatever order Windows +returns them. + +Explicit handles (@option{hwnd}, @option{hmonitor}) override pattern or index +based selection. If neither handles nor a monitor index are given, the first +window matching the provided regular expressions is captured. + +This source does NOT hold a stable FPS. It returns frames at whatever rate the compositor +provides them, only capped by the @option{max_framerate}. +If you need a stable rate, you need to add an fps filter to drop/duplicate frames as needed. + +If the capture source disappears mid-capture (window closed, monitor disconnected), the filter will return EOF. + +This source accepts the following options: +@table @option +@item window_title +ECMAScript regular expression matched against the window title. Supports a +PCRE style @code{(?i)} prefix for case-insensitive matching. + +@item window_class +As @option{window_title}, but matched against the window class name. + +@item window_exe +As @option{window_title}, but matched against the executable file name of the +window's process. + +@item monitor_idx +Zero-based index of the monitor to capture. + +Can also be set to @code{window} to capture the monitor the selected window +is displayed on at filter initialization time. + +@item hwnd +Explicit native window handle (HWND). + +@item hmonitor +Explicit native monitor handle (HMONITOR). + +@item capture_cursor +Capture the mouse cursor. Enabled by default. + +@item capture_border +Capture the full area of the window, including its window decorarions/border. +Disabled by default. + +@item display_border +Draw a yellow highlight border around the captured window. Disabled by default. + +@item max_framerate +Maximum capture frame rate. Accepts a video rate (e.g. @code{30}, @code{60/1}, +@code{24000/1001}). The default is @code{60} FPS. +The actual rate is the rate at which the compositor renders the window/monitor, +capped by this option. + +@item width +Force the output canvas width. If zero (default) the initial captured source +width is used. If a negative number is provided, the width will be rounded +down to the next multiple of that number. + +See @option{resize_mode}. + +@item height +Force the output canvas height. If zero (default) the initial captured source +height is used. If a negative number is provided, the height will be rounded +down to the next multiple of that number. + +See @option{resize_mode}. + +@item crop_left +Crop this many pixels from the left side of the captured frames. + +@item crop_top +Crop this many pixels from the left side of the captured frames. + +@item crop_right +Crop this many pixels from the left side of the captured frames. + +@item crop_bottom +Crop this many pixels from the left side of the captured frames. + +@item premultiplied +If set to 1, return frames with premultiplied alpha. Default is 0 (straight +alpha). + +@item resize_mode +Defines how the captured content is fitted into the output canvas size. +Possible values: +@table @samp +@item crop +Crop (or pad with black) to the canvas size. (default) +@item scale +Scale the source to fill the canvas, potentially altering aspect ratio. +@item scale_aspect +Scale the source to fit inside the canvas while preserving aspect ratio. +Remaining area is filled with black. +@end table + +@item scale_mode +Scaling algorithm used when resizing is required. + +Possible values: +@table @samp +@item point +Nearest neighbour (pixelated) scaling. +@item bilinear +Bilinear filtering. (default) +@item bicubic +Bicubic filtering. Potentially more blurry, but fewer scaling artifacts depending on contents. +@end table + +@item output_fmt +Desired output pixel format inside the D3D11 hardware frames. + +Possible values: +@table @samp +@item bgra +@item 8bit +8 bit BGRA output (default) +@item x2bgr10 +@item 10bit +10 bit BGR output +@item rgbaf16 +@item 16bit +16bit float RGBA output +@end table + +@end table + +@subsection Examples +@itemize +@item Capture a window by title (case-insensitive) at a maximum of 60 fps: +@example +ffmpeg -filter_complex gfxcapture=window_title='(?i)My Application':max_framerate=60,hwdownload,format=bgra,format=yuv420p -c:v libx264 -crf 15 capture.mp4 +@end example + +@item Capture monitor 1 at native refresh, 10bit color depth, scale to 1920x1080 preserving aspect: +@example +ffmpeg -filter_complex gfxcapture=monitor_idx=1:width=1920:height=1080:resize_mode=scale_aspect:output_fmt=10bit -c:v hevc_nvenc -cq 15 capture.mp4 +@end example + +@item Capture a window by executable name, draw border, force point scaling, fixed 60 fps: +@example +ffmpeg -filter_complex gfxcapture=window_exe='^firefox.exe$':display_border=1:scale_mode=point,fps=60 -rc qvbr -qvbr_quality_level 15 -c:v h264_amf capture.mp4 +@end example + +@end itemize + + @section gradients Generate several gradients. @@ -29167,7 +30306,7 @@ Set the initial y position. Must be a floating point value between Generate various test patterns, as generated by the MPlayer test filter. -The size of the generated video is fixed, and is 256x256. +The size of the generated video is fixed, and is 512x512. This source is useful in particular for testing encoding features. This source accepts the following options: @@ -30441,6 +31580,7 @@ bench=start,selectivecolor=reds=-.2 .12 -.49,bench=stop @end example @end itemize +@anchor{concat filter} @section concat Concatenate audio and video streams, joining them together one after the @@ -31386,6 +32526,12 @@ This filter accepts the following options: @item expr The expression which is evaluated for each frame to construct its timestamp. +@item strip_fps (@emph{video only}) +Boolean option which determines if the original framerate and frame duration +metadata is unset. If set to true, be advised that a sane frame rate should be +explicitly specified if output is sent to a constant frame rate muxer. +Default is @code{false}. + @end table The expression is evaluated through the eval API and can contain the following @@ -32875,10 +34021,41 @@ data in the frame. @end table @item type -Set side data type used with all modes. Must be set for @code{select} mode. For -the list of frame side data types, refer to the @code{AVFrameSideDataType} enum -in @file{libavutil/frame.h}. For example, to choose -@code{AV_FRAME_DATA_PANSCAN} side data, you must specify @code{PANSCAN}. +Set side data type used with all modes. Must be set for @code{select} mode. + +Possible values are: + +@table @samp +@item PANSCAN +@item A53_CC +@item STEREO3D +@item MATRIXENCODING +@item DOWNMIX_INFO +@item REPLAYGAIN +@item DISPLAYMATRIX +@item AFD +@item MOTION_VECTORS +@item SKIP_SAMPLES +@item AUDIO_SERVICE_TYPE +@item MASTERING_DISPLAY_METADATA +@item GOP_TIMECODE +@item SPHERICAL +@item CONTENT_LIGHT_LEVEL +@item ICC_PROFILE +@item S12M_TIMECODE +@item DYNAMIC_HDR_PLUS +@item REGIONS_OF_INTEREST +@item VIDEO_ENC_PARAMS +@item SEI_UNREGISTERED +@item FILM_GRAIN_PARAMS +@item DETECTION_BOUNDING_BOXES +@item DETECTION_BBOXES +@item DOVI_RPU_BUFFER +@item DOVI_METADATA +@item DYNAMIC_HDR_VIVID +@item AMBIENT_VIEWING_ENVIRONMENT +@item VIDEO_HINT +@end table @end table diff --git a/doc/general_contents.texi b/doc/general_contents.texi index 5980ac6f0..47ac1989f 100644 --- a/doc/general_contents.texi +++ b/doc/general_contents.texi @@ -162,7 +162,7 @@ Then pass @code{--enable-libmp3lame} to configure to enable it. @section LCEVCdec -FFmpeg can make use of the liblcevc_dec library for LCEVC enhacement layer +FFmpeg can make use of the liblcevc_dec library for LCEVC enhancement layer decoding on supported bitstreams. Go to @url{https://github.com/v-novaltd/LCEVCdec} and follow the instructions @@ -250,6 +250,14 @@ Go to @url{http://sourceforge.net/projects/opencore-amr/} and follow the instructions for installing the library. Then pass @code{--enable-libfdk-aac} to configure to enable it. +@subsection Fraunhofer MPEG-H 3D Audio decoder library + +FFmpeg can make use of the Fraunhofer MPEG-H decoder library for MPEG-H 3DA decoding. + +Go to @url{https://github.com/Fraunhofer-IIS/mpeghdec} and follow the +instructions for installing the library. +Then pass @code{--enable-libmpeghdec --enable-nonfree} to configure to enable it. + @subsection LC3 library FFmpeg can make use of the Google LC3 library for LC3 decoding & encoding. @@ -295,6 +303,15 @@ Go to @url{https://gitlab.com/AOMediaCodec/SVT-AV1/} and follow the instructions for installing the library. Then pass @code{--enable-libsvtav1} to configure to enable it. +@section SVT-JPEG-XS + +FFmpeg can make use of the Scalable Video Technology for JPEG-XS library for JPEG-XS +decoding and encoding. + +Go to @url{https://github.com/OpenVisualCloud/SVT-JPEG-XS} and follow the instructions +for installing the library. Then pass @code{--enable-libsvtjpegxs} to configure to +enable it. + @section TwoLAME FFmpeg can make use of the TwoLAME library for MP2 encoding. @@ -625,6 +642,7 @@ library: @item raw AMR-NB @tab @tab X @item raw AMR-WB @tab @tab X @item raw APAC @tab @tab X +@item raw APV @tab X @tab X @item raw aptX @tab X @tab X @item raw aptX HD @tab X @tab X @item raw Bonk @tab @tab X @@ -637,6 +655,7 @@ library: @item raw E-AC-3 @tab X @tab X @item raw EVC @tab X @tab X @item raw FLAC @tab X @tab X +@item raw G.728 @tab @tab X @item raw GSM @tab @tab X @item raw H.261 @tab X @tab X @item raw H.263 @tab X @tab X @@ -809,6 +828,8 @@ following image formats are supported: @tab Progressive JPEG is not supported. @item JPEG 2000 @tab X @tab X @item JPEG-LS @tab X @tab X +@item JPEG-XS @tab E @tab E + @tab Supported through external library libsvtjpegxs @item LJPEG @tab X @tab @tab Lossless JPEG @item Media 100 @tab @tab X @@ -895,6 +916,7 @@ following image formats are supported: @tab fourcc: apch,apcn,apcs,apco,ap4h,ap4x @item Apple QuickDraw @tab @tab X @tab fourcc: qdrw +@item APV @tab @tab X @item Argonaut Video @tab @tab X @tab Used in some Argonaut games. @item Asus v1 @tab X @tab X @@ -1109,6 +1131,7 @@ following image formats are supported: @item RealVideo 3.0 @tab @tab X @tab still far from ideal @item RealVideo 4.0 @tab @tab X +@item RealVideo 6.0 @tab @tab X @item Renderware TXD (TeXture Dictionary) @tab @tab X @tab Texture dictionaries used by the Renderware Engine. @item RivaTuner Video @tab @tab X @@ -1232,6 +1255,7 @@ following image formats are supported: @item ADPCM IMA Duck DK4 @tab @tab X @tab Used in some Sega Saturn console games. @item ADPCM IMA Radical @tab @tab X +@item ADPCM IMA Xbox @tab @tab X @item ADPCM Microsoft @tab X @tab X @item ADPCM MS IMA @tab X @tab X @item ADPCM Nintendo Gamecube AFC @tab @tab X @@ -1239,6 +1263,7 @@ following image formats are supported: @item ADPCM Nintendo THP @tab @tab X @item ADPCM Playstation @tab @tab X @item ADPCM QT IMA @tab X @tab X +@item ADPCM Sanyo @tab @tab X @item ADPCM SEGA CRI ADX @tab X @tab X @tab Used in Sega Dreamcast games. @item ADPCM Shockwave Flash @tab X @tab X @@ -1313,6 +1338,7 @@ following image formats are supported: @item FLAC (Free Lossless Audio Codec) @tab X @tab IX @item FTR Voice @tab @tab X @item G.723.1 @tab X @tab X +@item G.728 @tab @tab X @item G.729 @tab @tab X @item GSM @tab E @tab X @tab encoding supported through external library libgsm @@ -1337,6 +1363,8 @@ following image formats are supported: @item MP3 (MPEG audio layer 3) @tab E @tab IX @tab encoding supported through external library LAME, ADU MP3 and MP3onMP4 also supported @item MPEG-4 Audio Lossless Coding (ALS) @tab @tab X +@item MPEG-H 3D Audio @tab @tab E + @tab decoding supported through external library libmpeghdec @item MobiClip FastAudio @tab @tab X @item Musepack SV7 @tab @tab X @item Musepack SV8 @tab @tab X diff --git a/doc/git-howto.texi b/doc/git-howto.texi index 3e050dbd4..e20d114f9 100644 --- a/doc/git-howto.texi +++ b/doc/git-howto.texi @@ -71,7 +71,6 @@ git clone git@@ffmpeg.org:ffmpeg-web This will put the source of the FFmpeg website into the directory @var{} and let you push back your changes to the remote repository. -(Note that @var{gil} stands for GItoLite and is not a typo of @var{git}.) If you don't have write-access to the ffmpeg-web repository, you can create patches after making a read-only ffmpeg-web clone: diff --git a/doc/htmlxref.cnf b/doc/htmlxref.cnf new file mode 100644 index 000000000..0552ab2a6 --- /dev/null +++ b/doc/htmlxref.cnf @@ -0,0 +1,7 @@ +ffmpeg mono ./ffmpeg.html +ffmpeg-filters mono ./ffmpeg-filters.html +ffmpeg-formats mono ./ffmpeg-formats.html +ffmpeg-resampler mono ./ffmpeg-resampler.html +ffmpeg-scaler mono ./ffmpeg-scaler.html +ffmpeg-utils mono ./ffmpeg-utils.html +drawvg-reference mono ./drawvg-reference.html diff --git a/doc/indevs.texi b/doc/indevs.texi index cdf44a663..8822e070f 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -220,41 +220,6 @@ $ ffmpeg -f avfoundation -capture_raw_data true -i "zr100:none" out.dv @end itemize -@section bktr - -BSD video input device. Deprecated and will be removed - please contact -the developers if you are interested in maintaining it. - -@subsection Options - -@table @option - -@item framerate -Set the frame rate. - -@item video_size -Set the video frame size. Default is @code{vga}. - -@item standard - -Available values are: -@table @samp -@item pal - -@item ntsc - -@item secam - -@item paln - -@item palm - -@item ntscj - -@end table - -@end table - @section decklink The decklink input device provides capture capabilities for Blackmagic @@ -739,7 +704,7 @@ Win32 GDI-based screen capture device. This device allows you to capture a region of the display on Windows. -Amongst options for the imput filenames are such elements as: +Amongst options for the input filenames are such elements as: @example desktop @end example diff --git a/doc/infra.txt b/doc/infra.txt index 37aaef34b..b5546aedd 100644 --- a/doc/infra.txt +++ b/doc/infra.txt @@ -1,8 +1,18 @@ FFmpeg Infrastructure: ====================== +Trademark: +~~~~~~~~~~ +ffmpeg trademark registered in france by ffmpeg creator. +Domain + NS: +~~~~~~~~~~~~ +ffmpeg.org domain name +ns1.avcodec.org Primary Name server (provided by Telepoint, hosted at Telepoint in bulgaria) +ns2.avcodec.org Replica Name server (provided by an ffmpeg developer, hosted at Hetzner in germany) +ns3.avcodec.org Replica Name server (provided by an ffmpeg developer, hosted at Prometeus Cdlan in italy) + Servers: ~~~~~~~~ @@ -14,6 +24,26 @@ Our Main server is hosted at telepoint.bg for more details see: https://www.ffmpeg.org/#thanks_sponsor_0001 Nothing runs on our main server directly, instead several VMs run on it. +Main server security: +--------------------- +Telepoint is one of the largest Bulgarian DC providers with multiple sibling companies offering +Internet, SDH, DWDM, peering exchange and hosting. They have multiple DC buildings in Sofia and +FFmpeg is hosted in XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. The building is locked down and accessible +only with personal key cards that are registered. People who are granted access to a rack have +to go through the access center with their ID to get logged and receive a one-time access card +that can open the service elevator and only the hall where the destination rack is. All racks are +locked, once access is granted to someone they will get a key for the rack for the duration of +their visit. There are security cameras everywhere and personnel in the access center 24/7. As for +software security, our BIOS and IPMI are protected by password and encrypted connection, and +the machines can be accessed only by root administrators with their SSH keys. They're using +a Ubuntu LTS release and get regular security updates as they are released. We also get +notified by email for various security related events (e.g. failed sudo). + +Side note - Telepoint provides the rack and physical infrastructure, their sibling company called + Telehouse which is an ISP provides the connectivity, they are directly connected with + over 15 tier-1 service providers and have over 100 PoPs (points of presence) + in various cities. You can see more on www.telehouse.bg + ffmpeg.org VM: -------------- @@ -92,7 +122,47 @@ You need a VM, docker container for FFmpeg? contact root at ffmpeg.org +Multimedia Wiki: +~~~~~~~~~~~~~~~~ +The Multimedia Wiki http://wiki.multimedia.cx is ran by Mike Melanson. +While not directly part of FFmpeg infrastructure, technical codec and format +information written by FFmpeg developers can be found within. +It is our unofficial official tech wiki. For access contact Mike. + + + IRC: ~~~~ irc channels are at https://libera.chat/ irc channel archives are at https://libera.irclog.whitequark.org + +#ffmpeg and #ffmpeg-devel founder/admins: BtbN, Michael, Compn +#ffmpeg-meeting founder/admins: BtbN, Michael + + +Twitter aka X: +~~~~~~~~~~~~~~ +https://twitter.com/FFmpeg or https://x.com/FFmpeg + +If you would like to post to twitter please contact twitter MAINTAINERS +for access. We want more developers posting to twitter! + + + +Reddit: +~~~~~~~ +https://www.reddit.com/r/ffmpeg/ +moderated by Gyan + + + +Facebook: +~~~~~~~~~ +https://www.facebook.com/ffmpeg +??? + + + +Wikipedia entry: +~~~~~~~~~~~~~~~~ +https://en.wikipedia.org/wiki/FFmpeg diff --git a/doc/libav-merge.txt b/doc/libav-merge.txt deleted file mode 100644 index bcd0aacba..000000000 --- a/doc/libav-merge.txt +++ /dev/null @@ -1,115 +0,0 @@ -CONTEXT -======= - -The FFmpeg project merges all the changes from the Libav project -(https://libav.org) since the origin of the fork (around 2011). - -With the exceptions of some commits due to technical/political disagreements or -issues, the changes are merged on a more or less regular schedule (daily for -years thanks to Michael, but more sparse nowadays). - -WHY -=== - -The majority of the active developers believe the project needs to keep this -policy for various reasons. - -The most important one is that we don't want our users to have to choose -between two distributors of libraries of the exact same name in order to have a -different set of features and bugfixes. By taking the responsibility of -unifying the two codebases, we allow users to benefit from the changes from the -two teams. - -Today, FFmpeg has a much larger user database (we are distributed by every -major distribution), so we consider this mission a priority. - -A different approach to the merge could have been to pick the changes we are -interested in and drop most of the cosmetics and other less important changes. -Unfortunately, this makes the following picks much harder, especially since the -Libav project is involved in various deep API changes. As a result, we decide -to virtually take everything done there. - -Any Libav developer is of course welcome anytime to contribute directly to the -FFmpeg tree. Of course, we fully understand and are forced to accept that very -few Libav developers are interested in doing so, but we still want to recognize -their work. This leads us to create merge commits for every single one from -Libav. The original commit appears totally unchanged with full authorship in -our history (and the conflict are solved in the merge one). That way, not a -single thing from Libav will be lost in the future in case some reunification -happens, or that project disappears one way or another. - -DOWNSIDES -========= - -Of course, there are many downsides to this approach. - -- It causes a non negligible merge commits pollution. We make sure there are - not several level of merges entangled (we do a 1:1 merge/commit), but it's - still a non-linear history. - -- Many duplicated work. For instance, we added libavresample in our tree to - keep compatibility with Libav when our libswresample was already covering the - exact same purpose. The same thing happened for various elements such as the - ProRes support (but differences in features, bugs, licenses, ...). There are - many work to do to unify them, and any help is very much welcome. - -- So much manpower from both FFmpeg and Libav is lost because of this mess. We - know it, and we don't know how to fix it. It takes incredible time to do - these merges, so we have even less time to work on things we personally care - about. The bad vibes also do not help with keeping our developers motivated. - -- There is a growing technical risk factor with the merges due to the codebase - differing more and more. - -MERGE GUIDELINES -================ - -The following gives developer guidelines on how to proceed when merging Libav commits. - -Before starting, you can reduce the risk of errors on merge conflicts by using -a different merge conflict style: - - $ git config --global merge.conflictstyle diff3 - -tools/libav-merge-next-commit is a script to help merging the next commit in -the queue. It assumes a remote named libav. It has two modes: merge, and noop. -The noop mode creates a merge with no change to the HEAD. You can pass a hash -as extra argument to reference a justification (it is common that we already -have the change done in FFmpeg). - -Also see tools/murge, you can copy and paste a 3 way conflict into its stdin -and it will display colored diffs. Any arguments to murge (like ones to suppress -whitespace differences) are passed into colordiff. - -TODO/FIXME/UNMERGED -=================== - -Stuff that didn't reach the codebase: -------------------------------------- - -- HEVC DSP and x86 MC SIMD improvements from Libav (see https://ffmpeg.org/pipermail/ffmpeg-devel/2015-December/184777.html) - - 1f821750f hevcdsp: split the qpel functions by width instead of by the subpixel fraction - - 818bfe7f0 hevcdsp: split the epel functions by width - - 688417399 hevcdsp: split the pred functions by width - - a853388d2 hevc: change the stride of the MC buffer to be in bytes instead of elements - - 0cef06df0 checkasm: add HEVC MC tests - - e7078e842 hevcdsp: add x86 SIMD for MC - - 7993ec19a hevc: Add hevc_get_pixel_4/8/12/16/24/32/48/64 -- use av_cpu_max_align() instead of hardcoding alignment requirements (see https://ffmpeg.org/pipermail/ffmpeg-devel/2017-September/215834.html) - - f44ec22e0 lavc: use av_cpu_max_align() instead of hardcoding alignment requirements - - 4de220d2e frame: allow align=0 (meaning automatic) for av_frame_get_buffer() -- Support recovery from an already present HLS playlist (see 16cb06bb30) -- Remove all output devices (see 8e7e042d41, 8d3db95f20, 6ce13070bd, d46cd24986 and https://ffmpeg.org/pipermail/ffmpeg-devel/2017-September/216904.html) -- avcodec/libaomenc: export the Sequence Header OBU as extradata (See a024c3ce9a) - -Collateral damage that needs work locally: ------------------------------------------- - -- Merge proresenc_anatoliy.c and proresenc_kostya.c -- Fix MIPS AC3 downmix - -Extra changes needed to be aligned with Libav: ----------------------------------------------- - -- Switching our examples to the new encode/decode API (see 67d28f4a0f) -- HEVC IDCT bit depth 12-bit support (Libav added 8 and 10 but doesn't have 12) diff --git a/doc/mips.txt b/doc/mips.txt index a42546f0c..f7529bd8e 100644 --- a/doc/mips.txt +++ b/doc/mips.txt @@ -60,6 +60,5 @@ Files that have MIPS copyright notice in them: compute_antialias_float.h lsp_mips.h fmtconvert_mips.c - iirfilter_mips.c mpegaudiodsp_mips_fixed.c mpegaudiodsp_mips_float.c diff --git a/doc/muxers.texi b/doc/muxers.texi index ce93ba148..643981fc2 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -319,7 +319,7 @@ This is the same as the @samp{vob} muxer with a few differences. @table @option @item muxrate @var{rate} Set user-defined mux rate expressed as a number of bits/s. If not -specied the automatically computed mux rate is employed. Default value +specified the automatically computed mux rate is employed. Default value is @code{0}. @item preload @var{delay} @@ -772,7 +772,7 @@ Force a delay expressed in seconds after the last frame of each repetition. Default value is @code{0.0}. @item plays @var{repetitions} -specify how many times to play the content, @code{0} causes an infinte +specify how many times to play the content, @code{0} causes an infinite loop, with @code{1} there is no loop @end table @@ -1770,7 +1770,7 @@ for looping indefinitely (default). @item final_delay @var{delay} Force the delay (expressed in centiseconds) after the last frame. Each frame ends with a delay until the next frame. The default is @code{-1}, which is a -special value to tell the muxer to re-use the previous delay. In case of a +special value to tell the muxer to reuse the previous delay. In case of a loop, you might want to customize this value to mark a pause for instance. @end table @@ -1856,7 +1856,7 @@ This muxer creates an .f4m (Adobe Flash Media Manifest File) manifest, an .abst (Adobe Bootstrap File) for each stream, and segment files in a directory specified as the output. -These needs to be accessed by an HDS player throuhg HTTPS for it to be able to +These needs to be accessed by an HDS player through HTTPS for it to be able to perform playback on the generated stream. @subsection Options @@ -2436,13 +2436,14 @@ ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k \ @item Create a single variant stream. Add the @code{#EXT-X-MEDIA} tag with @code{TYPE=SUBTITLES} in the master playlist with webvtt subtitle group name -'subtitle'. Make sure the input file has one text subtitle stream at least. +'subtitle' and optional subtitle name, e.g. 'English'. Make sure the input +file has one text subtitle stream at least. @example ffmpeg -y -i input_with_subtitle.mkv \ -b:v:0 5250k -c:v h264 -pix_fmt yuv420p -profile:v main -level 4.1 \ -b:a:0 256k \ -c:s webvtt -c:a mp2 -ar 48000 -ac 2 -map 0:v -map 0:a:0 -map 0:s:0 \ - -f hls -var_stream_map "v:0,a:0,s:0,sgroup:subtitle" \ + -f hls -var_stream_map "v:0,a:0,s:0,sgroup:subtitle,sname:English" \ -master_pl_name master.m3u8 -t 300 -hls_time 10 -hls_init_time 4 -hls_list_size \ 10 -master_pl_publish_rate 10 -hls_flags \ delete_segments+discont_start+split_by_time ./tmp/video.m3u8 @@ -2537,7 +2538,7 @@ these applications, audio may be played back on a wide range of devices, e.g., headphones, mobile phones, tablets, TVs, sound bars, home theater systems, and big screens. -This format was promoted and desgined by Alliance for Open Media. +This format was promoted and designed by Alliance for Open Media. For more information about this format, see @url{https://aomedia.org/iamf/}. @@ -2939,6 +2940,44 @@ ffmpeg -i INPUT -f md5 - @end example @end itemize +@anchor{mccenc} +@section mcc +Muxer for MacCaption MCC files, it supports MCC versions 1.0 and 2.0. +MCC files store VANC data, which can include closed captions (EIA-608 and CEA-708), ancillary time code, pan-scan data, etc. + +@subsection Options + +The muxer options are: + +@table @option +@item override_time_code_rate +Override the @code{Time Code Rate} value in the output. Defaults to trying to deduce from the stream's @code{time_base}, which often doesn't work. +@item use_u_alias +Use the @code{U} alias for the byte sequence @code{E1h 00h 00h 00h}. +Disabled by default because some @file{.mcc} files disagree on whether it has 2 or 3 zero bytes. +@item mcc_version +The MCC file format version. Must be either 1 or 2, defaults to 2. +@item creation_program +The creation program. Defaults to this version of FFmpeg. +@item creation_time +The creation time. Defaults to the current time. +@end table + +@subsection Examples +@itemize +@item +Extract a MXF @code{SMPTE_436M_ANC} stream from a MXF file and write it to a MCC file at 30 fps. +@example +ffmpeg -i input.mxf -c copy -map 0:d -override_time_code_rate 30 out.mcc +@end example + +@item +Extract EIA-608/CTA-708 closed captions from a @file{.mp4} file and write them to a MCC file at 29.97 fps. +@example +ffmpeg -f lavfi -i "movie=input.mp4[out+subcc]" -c:s copy -map 0:s -override_time_code_rate 30000/1001 out.mcc +@end example +@end itemize + @section microdvd MicroDVD subtitle format muxer. @@ -3878,4 +3917,69 @@ ffmpeg -f webm_dash_manifest -i video1.webm \ manifest.xml @end example +@anchor{whip} +@section whip + +WebRTC (Real-Time Communication) muxer that supports sub-second latency streaming according to +the WHIP (WebRTC-HTTP ingestion protocol) specification. + +This is an experimental feature. + +It uses HTTP as a signaling protocol to exchange SDP capabilities and ICE lite candidates. Then, +it uses STUN binding requests and responses to establish a session over UDP. Subsequently, it +initiates a DTLS handshake to exchange the SRTP encryption keys. Lastly, it splits video and +audio frames into RTP packets and encrypts them using SRTP. + +Ensure that you use H.264 without B frames and Opus for the audio codec. For example, to convert +an input file with @command{ffmpeg} to WebRTC: +@example +ffmpeg -re -i input.mp4 -acodec libopus -ar 48000 -ac 2 \ + -vcodec libx264 -profile:v baseline -tune zerolatency -threads 1 -bf 0 \ + -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" +@end example + +For this example, we have employed low latency options, resulting in an end-to-end latency of +approximately 150ms. + +@subsection Options + +This muxer supports the following options: + +@table @option + +@item handshake_timeout @var{integer} +Set the timeout in milliseconds for ICE and DTLS handshake. +Default value is 5000. + +@item pkt_size @var{integer} +Set the maximum size, in bytes, of RTP packets that send out. +Default value is 1200. + +@item ts_buffer_size @var{integer} +Set the buffer size, in bytes, of underlying protocol. +Default value is -1(auto). The UDP auto selects a reasonable value. + +@item whip_flags @var{flags} +Possible values: + +@table @samp +@item dtls_active +The muxer will try to set dtls active role and send the first client hello. +@end table + +@item rtp_history @var{integer} +Set the number of RTP history items to store. +Default value is 512. + +@item authorization @var{string} +The optional Bearer token for WHIP Authorization. + +@item cert_file @var{string} +The optional certificate file path for DTLS. + +@item key_file @var{string} +The optional private key file path for DTLS. + +@end table + @c man end MUXERS diff --git a/doc/optimization.txt b/doc/optimization.txt index 3ed29fe38..06ad3ab88 100644 --- a/doc/optimization.txt +++ b/doc/optimization.txt @@ -5,7 +5,7 @@ What to optimize: ----------------- If you plan to do non-x86 architecture specific optimizations (SIMD normally), then take a look in the x86/ directory, as most important functions are -already optimized for MMX. +already optimized for x86. If you want to do x86 optimizations then you can either try to fine-tune the stuff in the x86 directory or find some other functions in the C source to @@ -188,7 +188,7 @@ Code that depends on data in registries being untouched, should be written as a single __asm__() statement. Ideally, a single function contains only one __asm__() block. -Use external asm (nasm/yasm) or inline asm (__asm__()), do not use intrinsics. +Use external asm (nasm) or inline asm (__asm__()), do not use intrinsics. The latter requires a good optimizing compiler which gcc is not. When debugging a x86 external asm compilation issue, if lost in the macro @@ -199,7 +199,7 @@ actual lines causing issues. Inline asm vs. external asm --------------------------- Both inline asm (__asm__("..") in a .c file, handled by a compiler such as gcc) -and external asm (.s or .asm files, handled by an assembler such as nasm/yasm) +and external asm (.s or .asm files, handled by an assembler such as nasm) are accepted in FFmpeg. Which one to use differs per specific case. - if your code is intended to be inlined in a C function, inline asm is always diff --git a/doc/outdevs.texi b/doc/outdevs.texi index 9ee857528..86c78f31b 100644 --- a/doc/outdevs.texi +++ b/doc/outdevs.texi @@ -301,45 +301,6 @@ ffmpeg -re -i INPUT -c:v rawvideo -pix_fmt bgra -f fbdev /dev/fb0 See also @url{http://linux-fbdev.sourceforge.net/}, and fbset(1). -@section opengl -OpenGL output device. Deprecated and will be removed. - -To enable this output device you need to configure FFmpeg with @code{--enable-opengl}. - -This output device allows one to render to OpenGL context. -Context may be provided by application or default SDL window is created. - -When device renders to external context, application must implement handlers for following messages: -@code{AV_DEV_TO_APP_CREATE_WINDOW_BUFFER} - create OpenGL context on current thread. -@code{AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER} - make OpenGL context current. -@code{AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER} - swap buffers. -@code{AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER} - destroy OpenGL context. -Application is also required to inform a device about current resolution by sending @code{AV_APP_TO_DEV_WINDOW_SIZE} message. - -@subsection Options -@table @option - -@item background -Set background color. Black is a default. -@item no_window -Disables default SDL window when set to non-zero value. -Application must provide OpenGL context and both @code{window_size_cb} and @code{window_swap_buffers_cb} callbacks when set. -@item window_title -Set the SDL window title, if not specified default to the filename specified for the output device. -Ignored when @option{no_window} is set. -@item window_size -Set preferred window size, can be a string of the form widthxheight or a video size abbreviation. -If not specified it defaults to the size of the input video, downscaled according to the aspect ratio. -Mostly usable when @option{no_window} is not set. - -@end table - -@subsection Examples -Play a file on SDL window using OpenGL rendering: -@example -ffmpeg -i INPUT -f opengl "window title" -@end example - @section oss OSS (Open Sound System) output device. @@ -406,78 +367,6 @@ Play a file on default device on default server: ffmpeg -i INPUT -f pulse "stream name" @end example -@section sdl - -SDL (Simple DirectMedia Layer) output device. Deprecated and will be removed. - -For monitoring purposes in FFmpeg, pipes and a video player such as ffplay can be used: - -@example -ffmpeg -i INPUT -f nut -c:v rawvideo - | ffplay - -@end example - -"sdl2" can be used as alias for "sdl". - -This output device allows one to show a video stream in an SDL -window. Only one SDL window is allowed per application, so you can -have only one instance of this output device in an application. - -To enable this output device you need libsdl installed on your system -when configuring your build. - -For more information about SDL, check: -@url{http://www.libsdl.org/} - -@subsection Options - -@table @option - -@item window_borderless -Set SDL window border off. -Default value is 0 (enable window border). - -@item window_enable_quit -Enable quit action (using window button or keyboard key) -when non-zero value is provided. -Default value is 1 (enable quit action). - -@item window_fullscreen -Set fullscreen mode when non-zero value is provided. -Default value is zero. - -@item window_size -Set the SDL window size, can be a string of the form -@var{width}x@var{height} or a video size abbreviation. -If not specified it defaults to the size of the input video, -downscaled according to the aspect ratio. - -@item window_title -Set the SDL window title, if not specified default to the filename -specified for the output device. - -@item window_x -@item window_y -Set the position of the window on the screen. -@end table - -@subsection Interactive commands - -The window created by the device can be controlled through the -following interactive commands. - -@table @key -@item q, ESC -Quit the device immediately. -@end table - -@subsection Examples - -The following command shows the @command{ffmpeg} output is an -SDL window, forcing its size to the qcif format: -@example -ffmpeg -i INPUT -c:v rawvideo -pix_fmt yuv420p -window_size qcif -f sdl "SDL output" -@end example - @section sndio sndio audio output device. diff --git a/doc/platform.texi b/doc/platform.texi index 764911d23..5ed6997ce 100644 --- a/doc/platform.texi +++ b/doc/platform.texi @@ -158,7 +158,7 @@ You will need the following prerequisites: To set up a proper environment in MSYS2, you need to run @code{msys_shell.bat} from the Visual Studio or Intel Compiler command prompt. -Place @code{yasm.exe} somewhere in your @code{PATH}. +Place @code{nasm.exe} somewhere in your @code{PATH}. Next, make sure any other headers and libs you want to use, such as zlib, are located in a spot that the compiler can see. Do so by modifying the @code{LIB} @@ -301,7 +301,7 @@ These library packages are only available from @uref{http://sourceware.org/cygwinports/, Cygwin Ports}: @example -yasm, libSDL-devel, libgsm-devel, libmp3lame-devel, +libSDL-devel, libgsm-devel, libmp3lame-devel, speex-devel, libtheora-devel, libxvidcore-devel @end example @@ -330,4 +330,20 @@ and for a build with shared libraries ./configure --target-os=mingw32 --enable-shared --disable-static --extra-cflags=-mno-cygwin --extra-libs=-mno-cygwin @end example +@section ARM64EC + +FFmpeg does not intend to support the Windows ARM64EC build configuration; +patches for changing the individual libraries for the purposes of ARM64EC will +not be accepted. + +It may still be possible to build FFmpeg in this build configuration; +such a build may seem to work to some extent. Such a build may have some +amounts of ABI inconsistencies though - which we are not willing to fix. + +(Changing aarch64 assembly code to strictly support ARM64EC would require +ifdeffing/changing essentially all such assembly code, and would be a +huge maintenance burden. Additionally, changing the library ABI +surfaces to fix ABI inconsistencies could require extensive and intrusive +changes.) + @bye diff --git a/doc/protocols.texi b/doc/protocols.texi index ed70af4b3..ac5299aad 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -71,7 +71,7 @@ client may also set a user/password for authentication. The default for both fields is "guest". Name of virtual host on broker can be set with vhost. The default value is "/". -Muliple subscribers may stream from the broker using the command: +Multiple subscribers may stream from the broker using the command: @example ffplay amqp://[[user]:[password]@@]hostname[:port][/vhost] @end example @@ -352,6 +352,17 @@ means auto (seekable for normal files, non-seekable for named pipes). Many demuxers handle seekable and non-seekable resources differently, overriding this might speed up opening certain files at the cost of losing some features (e.g. accurate seeking). + +@item pkt_size +Set the maximum packet size used for file I/O. A smaller value may reduce +memory usage. A higher value may increase throughput especially with networked +filesystems. + +For reading, if explicitly set, it overrides the default internal buffer size +(32 KB) and limits the maximum amount of data read per operation. + +For writing, this sets the size of each write operation. The default is 256 KB +for regular files, 32 KB otherwise. @end table @section ftp @@ -406,26 +417,6 @@ Gophers protocol. The Gopher protocol with TLS encapsulation. -@section hls - -Read Apple HTTP Live Streaming compliant segmented stream as -a uniform one. The M3U8 playlists describing the segments can be -remote HTTP resources or local files, accessed using the standard -file protocol. -The nested protocol is declared by specifying -"+@var{proto}" after the hls URI scheme name, where @var{proto} -is either "file" or "http". - -@example -hls+http://host/path/to/remote/resource.m3u8 -hls+file://path/to/local/resource.m3u8 -@end example - -Using this protocol is discouraged - the hls demuxer should work -just as well (if not, please report the issues) and is more complete. -To use the hls demuxer instead, simply use the direct URLs to the -m3u8 files. - @section http HTTP (Hyper Text Transfer Protocol). @@ -462,6 +453,28 @@ Set the Referer header. Include 'Referer: URL' header in HTTP request. @item multiple_requests Use persistent connections if set to 1, default is 0. +@item request_size +Limit the size of requests made. This is useful for some pathological servers +that throttle unbounded range requests, as well as when expecting to seek +frequently. Disabled (set to 0) by default. + +Note that if enabling this option, it's strongly recommended to also enable +the @option{multiple_requests} option, as well as setting +@option{short_seek_size} to the same value or higher. Doing so allows FFmpeg +to reuse a single HTTP connection wherever possible. + +@item initial_request_size +Limit the size of initial requests. Similar to @code{request_size}, but only +used during initial format parsing. Useful for formats like MXF or MOV that +require frequent seeks during header parsing. Lasts until the demuxer makes a +read request larger than this size (without a seek in between), after which +the implementation will continue using requests as usual. Disabled (set to 0) +by default. + +Note that if enabling this option, it's strongly recommended to also enable +the @option{multiple_requests} option, as well as setting +@option{short_seek_size} to the same value or higher. + @item post_data Set custom HTTP post data. @@ -607,7 +620,7 @@ The resource requested by a client, when the experimental HTTP server is in use. The HTTP code returned to the client, when the experimental HTTP server is in use. @item short_seek_size -Set the threshold, in bytes, for when a readahead should be prefered over a seek and +Set the threshold, in bytes, for when a readahead should be preferred over a seek and new HTTP request. This is useful, for example, to make sure the same connection is used for reading large video packets with small audio packets in between. @@ -986,6 +999,11 @@ Set TCP_NODELAY to disable Nagle's algorithm. Default value is 0. @emph{Remark: Writing to the socket is currently not optimized to minimize system calls and reduces the efficiency / effect of TCP_NODELAY.} +@item tcp_keepalive=@var{1|0} +Enable the TCP keepalive mechanism to detect dead peers and help maintain long-lived idle connections. Default value is 0. + +Only the basic keepalive option (SO_KEEPALIVE) can be enabled or disabled. Platform-specific tuning parameters such as TCP_KEEPIDLE, TCP_KEEPINTVL, or TCP_KEEPCNT are not configurable and will use the operating system's default values. + @end table For example to read with @command{ffplay} a multimedia resource named @@ -1150,11 +1168,20 @@ ffplay "rtmp://myserver/live/mystream live=1" Real-time Transport Protocol. The required syntax for an RTP URL is: -rtp://@var{hostname}[:@var{port}][?@var{option}=@var{val}...] +@example +rtp://@var{hostname}[:@var{port}][?@var{options}] +@end example @var{port} specifies the RTP port to use. -The following URL options are supported: +@var{options} contains a list of &-separated options of the form +@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for +space) can be used to escape keys and values. + +Options can also can be specified via command line options (or in code via +@code{AVOption}s). + +The list of supported options follows. @table @option @@ -1164,10 +1191,12 @@ Set the TTL (Time-To-Live) value (for multicast only). @item rtcpport=@var{n} Set the remote RTCP port to @var{n}. -@item localrtpport=@var{n} +@item localport, local_rtpport, localrtpport=@var{n} Set the local RTP port to @var{n}. -@item localrtcpport=@var{n}' +Using the localport option name is deprecated and should not be used. + +@item local_rtcpport, localrtcpport=@var{n}' Set the local RTCP port to @var{n}. @item pkt_size=@var{n} @@ -1190,19 +1219,12 @@ List disallowed (blocked) source IP addresses. Send packets to the source address of the latest received packet (if set to 1) or to a default remote address (if set to 0). -@item localport=@var{n} -Set the local RTP port to @var{n}. - @item localaddr=@var{addr} Local IP address of a network interface used for sending packets or joining multicast groups. @item timeout=@var{n} Set timeout (in microseconds) of socket I/O operations to @var{n}. - -This is a deprecated option. Instead, @option{localrtpport} should be -used. - @end table Important notes: @@ -1530,7 +1552,15 @@ The accepted URL syntax is: sctp://@var{host}:@var{port}[?@var{options}] @end example -The protocol accepts the following options: +@var{options} contains a list of &-separated options of the form +@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for +space) can be used to escape keys and values. + +Options can also can be specified via command line options (or in code via +@code{AVOption}s). + +The list of supported options follows. + @table @option @item listen If set to any value, listen for an incoming connection. Outgoing connection is done by default. @@ -1549,18 +1579,13 @@ srt://@var{hostname}:@var{port}[?@var{options}] @end example @var{options} contains a list of &-separated options of the form -@var{key}=@var{val}. +@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for +space) can be used to escape keys and values. -or +Options can also can be specified via command line options (or in code via +@code{AVOption}s). -@example -@var{options} srt://@var{hostname}:@var{port} -@end example - -@var{options} contains a list of '-@var{key} @var{val}' -options. - -This protocol accepts the following options. +The list of supported options follows. @table @option @item connect_timeout=@var{milliseconds} @@ -1913,7 +1938,11 @@ tcp://@var{hostname}:@var{port}[?@var{options}] @end example @var{options} contains a list of &-separated options of the form -@var{key}=@var{val}. +@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for +space) can be used to escape keys and values. + +Options can also can be specified via command line options (or in code via +@code{AVOption}s). The list of supported options follows. @@ -1968,8 +1997,14 @@ The required syntax for a TLS/SSL url is: tls://@var{hostname}:@var{port}[?@var{options}] @end example -The following parameters can be set via command line options -(or in code via @code{AVOption}s): +@var{options} contains a list of &-separated options of the form +@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for +space) can be used to escape keys and values. + +Options can also can be specified via command line options (or in code via +@code{AVOption}s). + +The list of supported options follows. @table @option @@ -1980,7 +2015,7 @@ need to be specified for verification to work, but not all libraries and setups have defaults built in. The file must be in OpenSSL PEM format. -@item tls_verify=@var{1|0} +@item tls_verify, verify=@var{1|0} If enabled, try to verify the peer that we are communicating with. Note, if using OpenSSL, this currently only makes sure that the peer certificate is signed by one of the root certificates in the CA @@ -2024,6 +2059,94 @@ To play back a stream from the TLS/SSL server using @command{ffplay}: ffplay tls://@var{hostname}:@var{port} @end example +@section dtls + +Datagram Transport Layer Security (DTLS) + +The required syntax for a DTLS URL is: +@example +dtls://@var{hostname}:@var{port}[?@var{options}] +@end example + +@var{options} contains a list of &-separated options of the form +@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for +space) can be used to escape keys and values. + +Options can also can be specified via command line options (or in code via +@code{AVOption}s). + +DTLS shares most options with TLS, but operates over UDP instead of TCP. + +The list of supported options follows. + +@table @option + +@item ca_file, cafile=@var{filename} +A file containing certificate authority (CA) root certificates to treat +as trusted. If the linked TLS library contains a default this might not +need to be specified for verification to work, but not all libraries and +setups have defaults built in. +The file must be in OpenSSL PEM format. + +@item tls_verify, verify=@var{1|0} +If enabled, try to verify the peer that we are communicating with. +Note, if using OpenSSL, this currently only makes sure that the +peer certificate is signed by one of the root certificates in the CA +database, but it does not validate that the certificate actually +matches the host name we are trying to connect to. + +This is disabled by default since it requires a CA database to be +provided by the caller in many cases. + +@item cert_file, cert=@var{filename} +A file containing a certificate to use in the handshake with the peer. +(When operating as server, in listen mode, this is more often required +by the peer, while client certificates only are mandated in certain +setups.) + +@item key_file, key=@var{filename} +A file containing the private key for the certificate. + +@item cert_pem=@var{string} +Certificate PEM string + +@item key_pem=@var{string} +Private key PEM string + +@item listen=@var{1|0} +If enabled, listen for connections on the provided port, and assume +the server role in the handshake instead of the client role. + +@item mtu=@var{size} +Set the Maximum Transmission Unit (MTU) for DTLS packets. + +@item use_srtp=@var{1|0} +Enable the use_srtp DTLS extension. +This is used in WebRTC applications to establish SRTP encryption keys +through the DTLS handshake. Default is disabled. + +@item external_sock=@var{1|0} +Use an external socket instead of creating a new one. +This option only makes sense to pass when interacting with the code via +API, enabling this from CLI will cause immediate failure. +Default is disabled. + +@end table + +Example command lines: + +To create a DTLS server: + +@example +ffmpeg -listen 1 -i dtls://@var{hostname}:@var{port} @var{output} +@end example + +To create a DTLS client and send data to server: + +@example +ffmpeg -i @var{input} -f @var{format} dtls://@var{hostname}:@var{port} +@end example + @section udp User Datagram Protocol. @@ -2033,7 +2156,12 @@ The required syntax for an UDP URL is: udp://@var{hostname}:@var{port}[?@var{options}] @end example -@var{options} contains a list of &-separated options of the form @var{key}=@var{val}. +@var{options} contains a list of &-separated options of the form +@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for +space) can be used to escape keys and values. + +Options can also can be specified via command line options (or in code via +@code{AVOption}s). In case threading is enabled on the system, a circular buffer is used to store the incoming data, which allows one to reduce loss of data due to @@ -2072,6 +2200,9 @@ Explicitly allow or disallow reusing UDP sockets. @item ttl=@var{ttl} Set the time to live value (for multicast only). +@item dscp=@var{dscp} +Set the 6-bit DSCP field for outgoing packets. + @item connect=@var{1|0} Initialize the UDP socket with @code{connect()}. In this case, the destination address can't be changed with ff_udp_set_remote_url later. @@ -2153,6 +2284,17 @@ The following parameters can be set via command line options Timeout in ms. @item listen Create the Unix socket in listening mode. +@item type +Select socket type. +@table @samp +@item stream Corresponds to SOCK_STREAM (reliable stream-oriented) +@item datagram Corresponds to SOCK_DGRAM (unreliable packet-oriented) +@item seqpacket Corresponds to SOCK_SEQPACKET (reliable packet-oriented) +@end table +@item pkt_size +Maximum packet size for packet-oriented sockets (SOCK_DGRAM and +SOCK_SEQPACKET). If greater than zero, this value is used as +@code{max_packet_size}. Ignored for SOCK_STREAM. Default is @code{0}. @end table @section zmq diff --git a/doc/scaler.texi b/doc/scaler.texi index eb045de6b..0c2b95239 100644 --- a/doc/scaler.texi +++ b/doc/scaler.texi @@ -68,6 +68,10 @@ Select full chroma input. @item bitexact Enable bitexact output. + +@item unstable +Allow the use of experimental new code. May subtly affect the output or even +produce wrong results. For testing only. @end table @item srcw @var{(API only)} @@ -96,6 +100,9 @@ If value is set to @code{1}, indicates source is full range. Default value is If value is set to @code{1}, enable full range for destination. Default value is @code{0}, which enables limited range. +@item gamma @var{(boolean)} +If value is set to @code{1}, enable gamma correct scaling. Default value is @code{0}. + @anchor{sws_params} @item param0, param1 Set scaling algorithm parameters. The specified values are specific of diff --git a/doc/style.min.css b/doc/style.min.css index 6843fda57..a502310bb 100644 --- a/doc/style.min.css +++ b/doc/style.min.css @@ -20,4 +20,4 @@ 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. - */body{background-color:#313131;color:#e6e6e6;text-align:justify}body, h1, h2, h3, h4, h5, h6{font-family:"Lucida Grande","Lucida Sans Unicode","Lucida Sans","Helvetica Neue",Helvetica,Verdana,Tahoma,sans-serif}a{color:#4cae4c}a strong{color:#e6e6e6}a:hover{color:#7fc77f}a:hover strong{color:#4cae4c}main{width:100% ! important;min-height:600px;margin:auto}h1, h2, h3, h4{font-weight:bold;text-align:left}h1, h2, h3{color:#bebebe}h1 strong, h2 strong, h3 strong{color:#e6e6e6}h4, h5, h6{color:#3c8b3c}h1{border-bottom:4px #bebebe solid;padding:20px 2%}h3{border-bottom:2px #bebebe solid;padding:15px 1%}h4{border-bottom:1px solid #e6e6e6;padding:10px 0;margin:20px 0;color:#e6e6e6}.list-group .list-group-item{background-color:#3e3e3e;border-color:black}.list-group.list-group-big .list-group-item{padding:25px}.list-group a.list-group-item{color:#7fc77f}.list-group a.list-group-item:hover{background-color:#313131;color:#4cae4c}.well{background-color:#242424;border-color:black;color:#bebebe}.well strong{color:#e6e6e6}.well code{background-color:#313131}.well hr{border-color:#3c8b3c}.well h3{margin:5px 0 15px 0;border:0;padding:0}.well a{color:#4cae4c}.well a.btn{color:white}.well small{display:block;padding:0 10px;font-style:italic}.well.example{padding-top:40px;margin-bottom:130px}.well.example pre{margin:50px;margin-bottom:30px;font-size:1.5em}.well.example .btn{margin-right:50px;margin-bottom:20px}.well.well-with-icon{min-height:136px}.well.well-with-icon .pull-right,.well.well-with-icon .pull-left{background-color:#4cae4c;color:#e6e6e6;padding:10px;border-radius:5px;margin:5px}.well.well-with-icon .pull-right{margin-left:20px}.well.well-with-icon .pull-left{margin-right:20px}a.well{display:block}a.well:hover{text-decoration:none;opacity:0.8}.info, .warning{margin:10px;padding:10px;background-color:#3e3e3e;color:#e6e6e6}.info code, .warning code{background-color:#313131}.info{border-left:10px #4cae4c solid}.warning{border-left:10px #ae4c4c solid}.with-icon{padding:30px}.with-icon .pull-left{padding-right:30px}.with-icon .pull-right{padding-left:30px}dd{margin-left:20px}code{background-color:#242424;color:#7fc77f;display:inline-block;margin:5px}.table{margin:20px 0;border-radius:4px}.table th,.table td,.table tr{border:1px solid #171717}.table tr th{background-color:#3e3e3e;border-bottom:2px solid #e6e6e6}.table tr:nth-child(odd){background-color:#242424}#sidebar-wrapper, .navbar{background-color:#171717;overflow-x:hidden}#sidebar-wrapper .sidebar-brand img,#sidebar-wrapper .navbar-brand img, .navbar .sidebar-brand img, .navbar .navbar-brand img{opacity:0.6;margin-right:8px}#sidebar-wrapper .sidebar-brand:hover,#sidebar-wrapper .navbar-brand:hover, .navbar .sidebar-brand:hover, .navbar .navbar-brand:hover{color:#fff}#sidebar-wrapper .sidebar-brand:hover img,#sidebar-wrapper .navbar-brand:hover img, .navbar .sidebar-brand:hover img, .navbar .navbar-brand:hover img{opacity:1}#sidebar-wrapper .sidebar-nav li ul, .navbar .sidebar-nav li ul{list-style-type:none;padding:0}#sidebar-wrapper .sidebar-nav li ul li, .navbar .sidebar-nav li ul li{line-height:20px}#sidebar-wrapper .sidebar-nav li ul li a, .navbar .sidebar-nav li ul li a{padding-left:20px}.content-header{height:auto;background-color:#242424}.content-header h1{color:#e6e6e6;display:block;margin:0;margin-bottom:20px;line-height:normal;border-bottom:none}#download h4, #index h4{margin-top:180px}#download h4.first, #index h4.first{margin-top:20px}#download h4.first small, #index h4.first small{color:inherit;font-size:1em}#download .btn-download-wrapper, #index .btn-download-wrapper{text-align:center;margin:160px auto}#download .btn-download-wrapper .btn, #index .btn-download-wrapper .btn{font-size:3em;padding:3%;display:inline-block;margin-bottom:5px}#download .btn-download-wrapper small, #index .btn-download-wrapper small{display:block;font-size:0.4em}#download h2.description, #index h2.description{color:#e6e6e6;font-size:2em;font-weight:bold;margin:120px 50px;line-height:2em}#download h2.description .label, #index h2.description .label{font-size:0.5em}#download .btn-download-wrapper{margin:40px auto}#download .os-selector{text-align:center;color:#e6e6e6;margin:30px 0}#download .os-selector a.btn-build{color:#e6e6e6;display:block;padding:20px;border-radius:2px}#download .os-selector .btn-build[href="#build-linux"]{background-color:#e43}#download .os-selector .btn-build[href="#build-linux"]:hover{color:#e43;background-color:#e6e6e6}#download .os-selector .btn-build[href="#build-windows"]{background-color:#06a}#download .os-selector .btn-build[href="#build-windows"]:hover{color:#06a;background-color:#e6e6e6}#download .os-selector .btn-build[href="#build-mac"]{background-color:darkgrey}#download .os-selector .btn-build[href="#build-mac"]:hover{color:darkgrey;background-color:#e6e6e6}#download .os-selector .tab-content{margin-top:20px}#download .os-selector #build-linux h3{color:#e43}#download .os-selector #build-windows h3{color:#06a}#download .os-selector #build-mac h3{color:darkgrey}footer{background-color:#242424;border-top:1px #101010 solid;padding:20px 0%}footer a{display:block}footer img[alt="FFmpeg"]{width:50%;display:block;margin:auto} + */body{background-color:#313131;color:#e6e6e6;text-align:justify}body, h1, h2, h3, h4, h5, h6{font-family:"Lucida Grande","Lucida Sans Unicode","Lucida Sans","Helvetica Neue",Helvetica,Verdana,Tahoma,sans-serif}a{color:#4cae4c}a strong{color:#e6e6e6}a:hover{color:#7fc77f}a:hover strong{color:#4cae4c}main{width:100% ! important;min-height:600px;margin:auto}h1, h2, h3, h4{font-weight:bold;text-align:left}h1, h2, h3{color:#bebebe}h1 strong, h2 strong, h3 strong{color:#e6e6e6}h4, h5, h6{color:#3c8b3c}h1{border-bottom:4px #bebebe solid;padding:20px 2%}h3{border-bottom:2px #bebebe solid;padding:15px 1%}h4{border-bottom:1px solid #e6e6e6;padding:10px 0;margin:20px 0;color:#e6e6e6}.list-group .list-group-item{background-color:#3e3e3e;border-color:black}.list-group.list-group-big .list-group-item{padding:25px}.list-group a.list-group-item{color:#7fc77f}.list-group a.list-group-item:hover{background-color:#313131;color:#4cae4c}.well{background-color:#242424;border-color:black;color:#bebebe}.well strong{color:#e6e6e6}.well code{background-color:#313131}.well hr{border-color:#3c8b3c}.well h3{margin:5px 0 15px 0;border:0;padding:0}.well a{color:#4cae4c}.well a.btn{color:white}.well small{display:block;padding:0 10px;font-style:italic}.well.example{padding-top:40px;margin-bottom:130px}.well.example pre{margin:50px;margin-bottom:30px;font-size:1.5em}.well.example .btn{margin-right:50px;margin-bottom:20px}.well.well-with-icon{min-height:136px}.well.well-with-icon .pull-right,.well.well-with-icon .pull-left{background-color:#4cae4c;color:#e6e6e6;padding:10px;border-radius:5px;margin:5px}.well.well-with-icon .pull-right{margin-left:20px}.well.well-with-icon .pull-left{margin-right:20px}a.well{display:block}a.well:hover{text-decoration:none;opacity:0.8}.info, .warning{margin:10px;padding:10px;background-color:#3e3e3e;color:#e6e6e6}.info code, .warning code{background-color:#313131}.info{border-left:10px #4cae4c solid}.warning{border-left:10px #ae4c4c solid}.with-icon{padding:30px}.with-icon .pull-left{padding-right:30px}.with-icon .pull-right{padding-left:30px}dd{margin-left:20px}code{background-color:#242424;color:#7fc77f;display:inline-block;margin:5px}.table{margin:20px 0;border-radius:4px}.table th,.table td,.table tr{border:1px solid #171717}.table tr th{background-color:#3e3e3e;border-bottom:2px solid #e6e6e6}.table tr:nth-child(odd){background-color:#242424}#sidebar-wrapper, .navbar{background-color:#171717;overflow-x:hidden}#sidebar-wrapper .sidebar-brand img,#sidebar-wrapper .navbar-brand img, .navbar .sidebar-brand img, .navbar .navbar-brand img{opacity:0.6;margin-right:8px}#sidebar-wrapper .sidebar-brand:hover,#sidebar-wrapper .navbar-brand:hover, .navbar .sidebar-brand:hover, .navbar .navbar-brand:hover{color:#fff}#sidebar-wrapper .sidebar-brand:hover img,#sidebar-wrapper .navbar-brand:hover img, .navbar .sidebar-brand:hover img, .navbar .navbar-brand:hover img{opacity:1}#sidebar-wrapper .sidebar-nav li ul, .navbar .sidebar-nav li ul{list-style-type:none;padding:0}#sidebar-wrapper .sidebar-nav li ul li, .navbar .sidebar-nav li ul li{line-height:20px}#sidebar-wrapper .sidebar-nav li ul li a, .navbar .sidebar-nav li ul li a{padding-left:20px}.content-header{height:auto;background-color:#242424}.content-header h1{color:#e6e6e6;display:block;margin:0;margin-bottom:20px;line-height:normal;border-bottom:none}#download h4, #index h4{margin-top:180px}#download h4.first, #index h4.first{margin-top:20px}#download h4.first small, #index h4.first small{color:inherit;font-size:1em}#download .btn-download-wrapper, #index .btn-download-wrapper{text-align:center;margin:160px auto}#download .btn-download-wrapper .btn, #index .btn-download-wrapper .btn{font-size:3em;padding:3%;display:inline-block;margin-bottom:5px}#download .btn-download-wrapper small, #index .btn-download-wrapper small{display:block;font-size:0.4em}#download h2.description, #index h2.description{color:#e6e6e6;font-size:2em;font-weight:bold;margin:120px 50px;line-height:2em}#download h2.description .label, #index h2.description .label{font-size:0.5em}#download .btn-download-wrapper{margin:40px auto}#download .os-selector{text-align:center;color:#e6e6e6;margin:30px 0}#download .os-selector a.btn-build{color:#e6e6e6;display:block;padding:20px;border-radius:2px}#download .os-selector .btn-build[href="#build-linux"]{background-color:#e43}#download .os-selector .btn-build[href="#build-linux"]:hover{color:#e43;background-color:#e6e6e6}#download .os-selector .btn-build[href="#build-windows"]{background-color:#06a}#download .os-selector .btn-build[href="#build-windows"]:hover{color:#06a;background-color:#e6e6e6}#download .os-selector .btn-build[href="#build-mac"]{background-color:darkgrey}#download .os-selector .btn-build[href="#build-mac"]:hover{color:darkgrey;background-color:#e6e6e6}#download .os-selector .tab-content{margin-top:20px}#download .os-selector #build-linux h3{color:#e43}#download .os-selector #build-windows h3{color:#06a}#download .os-selector #build-mac h3{color:darkgrey}footer{background-color:#242424;border-top:1px #101010 solid;padding:20px 0%}footer a{display:block}footer img[alt="FFmpeg"]{width:50%;display:block;margin:auto}.example.user-good pre{color:#bfbfbf;border:1px solid #357735;border-left:10px solid #357735;background-color:#242424}.example.user-bad pre{color:#bfbfbf;border:1px solid #ae4c4c;border-left:10px solid #ae4c4c;background-color:#242424} diff --git a/doc/swscale-v2.txt b/doc/swscale-v2.txt new file mode 100644 index 000000000..aa2edceca --- /dev/null +++ b/doc/swscale-v2.txt @@ -0,0 +1,344 @@ +New swscale design to change everything (tm) +============================================ + +SwsGraph +-------- + +The entry point to the new architecture, SwsGraph is what coordinates +multiple "passes". These can include cascaded scaling passes, error diffusion +dithering, and so on. Or we could have separate passes for the vertical and +horizontal scaling. In between each SwsPass lies a fully allocated image buffer. +Graph passes may have different levels of threading, e.g. we can have a single +threaded error diffusion pass following a multi-threaded scaling pass. + +SwsGraph is internally recreated whenever the image format, dimensions or +settings change in any way. sws_scale_frame() is itself just a light-weight +wrapper that runs ff_sws_graph_create() whenever the format changes, splits +interlaced images into separate fields, and calls ff_sws_graph_run() on each. + +From the point of view of SwsGraph itself, all inputs are progressive. + +SwsOp / SwsOpList +----------------- + +This is the newly introduced abstraction layer between the high-level format +handling logic and the low-level backing implementation. Each SwsOp is designed +to be as small and atomic as possible, with the possible exception of the +read / write operations due to their numerous variants. + +The basic idea is to split logic between three major components: + +1. The high-level format "business logic", which generates in a very + naive way a sequence of operations guaranteed to get you from point A + to point B. This logic is written with correctness in mind only, and + ignoring any performance concerns or low-level implementation decisions. + Semantically, everything is always decoded from the input format to + normalized (real valued) RGB, and then encoded back to output format. + + This code lives in libswscale/format.c + +2. The optimizer. This is where the "magic" happens, so to speak. The + optimizer's job is to take the abstract sequence of operations + produced by the high-level format analysis code and incrementally + optimize it. Each optimization step is designed to be minute and provably + lossless, or otherwise guarded behind the BITEXACT flag. This ensures that + the resulting output is always identical, no matter how many layers of + optimization we add. + + This code lives in libswscale/ops.c + +3. The compiler. Once we have a sequence of operations as output by the + optimizer, we "compile" this down to a callable function. This is then + applied by the dispatch wrapper by striping it over the input image. + + See libswscale/ops_backend.c for the reference backend, or + libswscale/x86/ops.c for a more complex SIMD example. + +This overall approach has a considerable number of benefits: + +1. It allows us to verify correctness of logic and spot semantic errors at a + very high level, by simply looking at the sequence of operations (available + by default at debug / verbose log level), without having to dig through the + multiple levels of complicated, interwoven format handling code that is + legacy swscale. + +2. Because most of the brains lives inside the powerful optimizer, we get + fast paths "for free" for any suitable format conversion, rather than having + to enumerate them one by one. SIMD code itself can be written in a very + general way and does need to be tied to specific pixel formats - subsequent + low-level implementations can be strung together without much overhead. + +3. We can in the future, with relative ease, compile these operations + down to SPIR-V (or even LLVM IR) and generate efficient GPU or + target-machine specific implementations. This also opens the window for + adding hardware frame support to libswscale, and even transparently using + GPU acceleration for CPU frames. + +4. Platform-specific SIMD can be reduced down to a comparatively small set of + optimized routines, while still providing 100% coverage for all possible + pixel formats and operations. (As of writing, the x86 example backend has + about 60 unique implementations, of which 20 are trivial swizzles, 10 are + read/write ops, 10 are pixel type conversions and the remaining 20 are the + various logic/arithmetic ops). + +5. Backends hide behind a layer of abstraction offering them a considerable + deal of flexibility in how they want to implement their operations. For + example, the x86 backend has a dedicated function for compiling compatible + operations down to a single in-place pshufb instruction. + + Platform specific low level data is self-contained within its own setup() + function and private data structure, eliminating all reads into SwsContext + or the possibility of conflicts between platforms. + +6. We can compute an exact reference result for each operation with fixed + precision (ff_sws_op_apply_q), and use that to e.g. measure the amount of + error introduced by dithering, or even catch bugs in the reference C + implementation. (In theory - currently checkasm just compares against C) + +Examples of SwsOp in action +--------------------------- + +For illustration, here is the sequence of operations currently generated by +my prototype, for a conversion from RGB24 to YUV444P: + +Unoptimized operation list: + [ u8 .... -> ....] SWS_OP_READ : 3 elem(s) packed >> 0 + [ u8 .... -> ....] SWS_OP_SWIZZLE : 0123 + [ u8 .... -> ....] SWS_OP_RSHIFT : >> 0 + [ u8 .... -> ....] SWS_OP_CLEAR : {_ _ _ 0} + [ u8 .... -> ....] SWS_OP_CONVERT : u8 -> f32 + [f32 .... -> ....] SWS_OP_LINEAR : diag3+alpha [[1/255 0 0 0 0] [0 1/255 0 0 0] [0 0 1/255 0 0] [0 0 0 1 1]] + [f32 .... -> ....] SWS_OP_LINEAR : matrix3 [[0.299000 0.587000 0.114000 0 0] [-0.168736 -0.331264 1/2 0 0] [1/2 -0.418688 -57/701 0 0] [0 0 0 1 0]] + [f32 .... -> ....] SWS_OP_LINEAR : diag3+off3 [[219 0 0 0 16] [0 224 0 0 128] [0 0 224 0 128] [0 0 0 1 0]] + [f32 .... -> ....] SWS_OP_DITHER : 16x16 matrix + [f32 .... -> ....] SWS_OP_MAX : {0 0 0 0} <= x + [f32 .... -> ....] SWS_OP_MIN : x <= {255 255 255 _} + [f32 .... -> ....] SWS_OP_CONVERT : f32 -> u8 + [ u8 .... -> ....] SWS_OP_LSHIFT : << 0 + [ u8 .... -> ....] SWS_OP_SWIZZLE : 0123 + [ u8 .... -> ....] SWS_OP_WRITE : 3 elem(s) planar >> 0 + +This is optimized into the following sequence: + +Optimized operation list: + [ u8 XXXX -> +++X] SWS_OP_READ : 3 elem(s) packed >> 0 + [ u8 ...X -> +++X] SWS_OP_CONVERT : u8 -> f32 + [f32 ...X -> ...X] SWS_OP_LINEAR : matrix3+off3 [[0.256788 0.504129 0.097906 0 16] [-0.148223 -0.290993 112/255 0 128] [112/255 -0.367788 -0.071427 0 128] [0 0 0 1 0]] + [f32 ...X -> ...X] SWS_OP_DITHER : 16x16 matrix + [f32 ...X -> +++X] SWS_OP_CONVERT : f32 -> u8 + [ u8 ...X -> +++X] SWS_OP_WRITE : 3 elem(s) planar >> 0 + (X = unused, + = exact, 0 = zero) + +The extra metadata on the left of the operation list is just a dump of the +internal state used by the optimizer during optimization. It keeps track of +knowledge about the pixel values, such as their value range, whether or not +they're exact integers, and so on. + +In this example, you can see that the input values are exact (except for +the alpha channel, which is undefined), until the first SWS_OP_LINEAR +multiplies them by a noninteger constant. They regain their exact integer +status only after the (truncating) conversion to U8 in the output step. + +Example of more aggressive optimization +--------------------------------------- + +Conversion pass for gray -> rgb48: +Unoptimized operation list: + [ u8 .... -> ....] SWS_OP_READ : 1 elem(s) planar >> 0 + [ u8 .... -> ....] SWS_OP_SWIZZLE : 0123 + [ u8 .... -> ....] SWS_OP_RSHIFT : >> 0 + [ u8 .... -> ....] SWS_OP_CLEAR : {_ 0 0 0} + [ u8 .... -> ....] SWS_OP_CONVERT : u8 -> f32 + [f32 .... -> ....] SWS_OP_LINEAR : luma+alpha [[1/255 0 0 0 0] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 1]] + [f32 .... -> ....] SWS_OP_LINEAR : matrix3 [[1 0 701/500 0 0] [1 -0.344136 -0.714136 0 0] [1 443/250 0 0 0] [0 0 0 1 0]] + [f32 .... -> ....] SWS_OP_LINEAR : diag3 [[65535 0 0 0 0] [0 65535 0 0 0] [0 0 65535 0 0] [0 0 0 1 0]] + [f32 .... -> ....] SWS_OP_MAX : {0 0 0 0} <= x + [f32 .... -> ....] SWS_OP_MIN : x <= {65535 65535 65535 _} + [f32 .... -> ....] SWS_OP_CONVERT : f32 -> u16 + [u16 .... -> ....] SWS_OP_LSHIFT : << 0 + [u16 .... -> ....] SWS_OP_SWIZZLE : 0123 + [u16 .... -> ....] SWS_OP_WRITE : 3 elem(s) packed >> 0 + +Optimized operation list: + [ u8 XXXX -> +XXX] SWS_OP_READ : 1 elem(s) planar >> 0 + [ u8 .XXX -> +XXX] SWS_OP_CONVERT : u8 -> u16 (expand) + [u16 .XXX -> +++X] SWS_OP_SWIZZLE : 0003 + [u16 ...X -> +++X] SWS_OP_WRITE : 3 elem(s) packed >> 0 + (X = unused, + = exact, 0 = zero) + +Here, the optimizer has managed to eliminate all of the unnecessary linear +operations on previously zero'd values, turn the resulting column matrix into +a swizzle operation, avoid the unnecessary dither (and round trip via float) +because the pixel values are guaranteed to be bit exact, and finally, turns +the multiplication by 65535 / 255 = 257 into a simple integer expand operation. + +As a final bonus, the x86 backend further optimizes this into a 12-byte shuffle: + pshufb = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1} + +time=208 us, ref=4212 us, speedup=20.236x faster (single thread) +time=57 us, ref=472 us, speedup=8.160x faster (multi thread) + +Compiler and underlying implementation layer (SwsOpChain) +--------------------------------------------------------- + +While the backend API is flexible enough to permit more exotic implementations +(e.g. using JIT code generation), we establish a common set of helpers for use +in "traditional" SIMD implementations. + +The basic idea is to have one "kernel" (or implementation) per operation, +and then just chain a list of these kernels together as separate function +calls. For best performance, we want to keep data in vector registers in +between function calls using a custom calling convention, thus avoiding any +unnecessary memory accesses. Additionally, we want the per-kernel overhead to +be as low as possible, with each kernel ideally just jumping directly into +the next kernel. + +As a result, we arrive at a design where we first divide the image into small +chunks, or "blocks", and then dispatch the "chain" of kernels on each chunk in +sequence. Each kernel processes a fixed number of pixels, with the overall +entry point taking care of looping. Remaining pixels (the "tail") are handled +generically by the backend-invariant dispatch code (located in ops.c), using a +partial memcpy into a suitably sized temporary buffer. + +To minimize the per-kernel function call overhead, we use a "continuation +passing style" for chaining kernels. Each operation computes its result and +then directly calls the next operation in the sequence, with the appropriate +internal function signature. + +The C reference backend reads data into the stack and then passes the array +pointers to the next continuation as regular function arguments: + + void process(GlobalContext *ctx, OpContext *op, + block_t x, block_t y, block_t z, block_t w) + { + for (int i = 0; i < SWS_BLOCK_SIZE; i++) + // do something with x[i], y[i], z[i], w[i] + + op->next(ctx, &op[1], x, y, z, w); + } + +With type conversions pushing the new data onto the stack as well: + + void convert8to16(GlobalContext *ctx, OpContext *op, + block_t x, block_t y, block_t z, block_t w) + { + /* Pseudo-code */ + u16block_t x16 = (u16block_t) x; + u16block_t y16 = (u16block_t) y; + u16block_t z16 = (u16block_t) z; + u16block_t w16 = (u16block_t) w; + + op->next(ctx, &op[1], x16, y16, z16, w16); + } + +By contrast, the x86 backend always keeps the X/Y/Z/W values pinned in specific +vector registers (ymm0-ymm3 for the lower half, and ymm4-ymm7 for the second +half). + +Each kernel additionally has access to a 32 byte per-op context storing the +pointer to the next kernel plus 16 bytes of arbitrary private data. This is +used during construction of the function chain to place things like small +constants. + +In assembly, the per-kernel overhead looks like this: + + load $tmp, $arg1 + ... + add $arg1, 32 + jump $tmp + +This design gives vastly better performance than the alternative of returning +out to a central loop or "trampoline". This is partly because the order of +kernels within a chain is always the same, so the branch predictor can easily +remember the target address of each "jump" instruction. + +The only way to realistically improve on this design would be to directly +stitch the kernel body together using runtime code generation. + +Future considerations and limitations +------------------------------------- + +My current prototype has a number of severe limitations and opportunities +for improvements: + +1. It does not handle scaling at all. I am not yet entirely sure on how I want + to handle scaling; this includes handling of subsampled content. I have a + number of vague ideas in my head, but nothing where I can say with certainty + that it will work out well. + + It's possible that we won't come up with a perfect solution here, and will + need to decide on which set of compromises we are comfortable accepting: + + 1. Do we need the ability to scale YUV -> YUV by handling luma and chroma + independently? When downscaling 100x100 4:2:0 to 50x50 4:4:4, should we + support the option of reusing the chroma plane directly (even though + this would introduce a subpixel shift for typical chroma siting)? + + Looking towards zimg, I am also thinking that we probably also want to do + scaling on floating point values, since this is best for both performance + and accuracy, especially given that we need to go up to 32-bit intermediates + during scaling anyway. + + So far, the most promising approach seems to be to handle subsampled + input/output as a dedicated read/write operation type; perhaps even with a + fixed/static subsampling kernel. To avoid compromising on performance when + chroma resampling is not necessary, the optimizer could then relax the + pipeline to use non-interpolating read/writes when all intermediate + operations are component-independent. + +2. Since each operation is conceptually defined on 4-component pixels, we end + up defining a lot of variants of each implementation for each possible + *subset*. For example, we have four different implementations for + SWS_OP_SCALE in my current templates: + - op_scale_1000 + - op_scale_1001 + - op_scale_1110 + - op_scale_1111 + + This reflects the four different arrangements of pixel components that are + typically present (or absent). While best for performance, it does turn into + a bit of a chore when implementing these kernels. + + The only real alternative would be to either branch inside the kernel (bad), + or to use separate kernels for each individual component and chain them all + together. I have not yet tested whether the latter approach would be faster + after the latest round of refactors to the kernel glue code. + +3. I do not yet have any support for LUTs. But when I add them, something we + could do is have the optimized pass automatically "promote" a sequence of + operations to LUTs. For example, any sequence that looks like: + + 1. [u8] SWS_OP_CONVERT -> X + 2. [X] ... // only per-component operations + 4. [X] SWS_OP_CONVERT -> Y + 3. [Y] SWS_OP_WRITE + + could be replaced by a LUT with 256 entries. This is especially important + for anything involving packed 8-bit input (e.g. rgb8, rgb4_byte). + + We also definitely want to hook this up to the existing CMS code for + transformations between different primaries. + +4. Because we rely on AVRational math to generate the coefficients for + operations, we need to be able to represent all pixel values as an + AVRational. However, this presents a challenge for 32-bit formats (e.g. + GRAY32, RGBA128), because their size exceeds INT_MAX, which is the maximum + value representable by an AVRational. + + It's possible we may want to introduce an AVRational64 for this, or + perhaps more flexibly, extend AVRational to an AVFloating type which is + represented as { AVRational n; int exp; }, representing n/d * 2^exp. This + would preserve our ability to represent all pixel values exactly, while + opening up the range arbitrarily. + +5. Is there ever a situation where the use of floats introduces the risk of + non bit-exact output? For this reason, and possible performance advantages, + we may want to explore the use of a fixed-point 16 bit path as an alternative + to the floating point math. + + So far, I have managed to avoid any bit exactness issues inside the x86 + backend by ensuring that the order of linear operations is identical + between the C backend and the x86 backend, but this may not be practical + to guarantee on all backends. The x86 float code is also dramatically + faster than the old fixed point code, so I'm tentatively optimistic about + the lack of a need for a fixed point path. diff --git a/doc/utils.texi b/doc/utils.texi index 9968725d2..9c50dac94 100644 --- a/doc/utils.texi +++ b/doc/utils.texi @@ -731,8 +731,12 @@ FL+FR+FC+LFE+BL+BR+SL+SR+TFL+TFR+TBL+TBR FL+FR+FC+LFE+BL+BR+SL+SR+TFL+TFR+TBC+LFE2 @item 9.1.4 FL+FR+FC+LFE+BL+BR+FLC+FRC+SL+SR+TFL+TFR+TBL+TBR +@item 9.1.6 +FL+FR+FC+LFE+BL+BR+FLC+FRC+SL+SR+TFL+TFR+TBL+TBR+TSL+TSR @item hexadecagonal FL+FR+FC+BL+BR+BC+SL+SR+WL+WR+TBL+TBR+TBC+TFC+TFL+TFR +@item binaural +BIL+BIR @item downmix DL+DR @item 22.2 diff --git a/ffbuild/arch.mak b/ffbuild/arch.mak index 3fc40e5e5..13e1eb33b 100644 --- a/ffbuild/arch.mak +++ b/ffbuild/arch.mak @@ -3,6 +3,10 @@ OBJS-$(HAVE_ARMV6) += $(ARMV6-OBJS) $(ARMV6-OBJS-yes) OBJS-$(HAVE_ARMV8) += $(ARMV8-OBJS) $(ARMV8-OBJS-yes) OBJS-$(HAVE_VFP) += $(VFP-OBJS) $(VFP-OBJS-yes) OBJS-$(HAVE_NEON) += $(NEON-OBJS) $(NEON-OBJS-yes) +OBJS-$(HAVE_SVE) += $(SVE-OBJS) $(SVE-OBJS-yes) +OBJS-$(HAVE_SVE2) += $(SVE2-OBJS) $(SVE2-OBJS-yes) +OBJS-$(HAVE_SME) += $(SME-OBJS) $(SME-OBJS-yes) +OBJS-$(HAVE_SME2) += $(SME2-OBJS) $(SME2-OBJS-yes) OBJS-$(HAVE_MIPSFPU) += $(MIPSFPU-OBJS) $(MIPSFPU-OBJS-yes) OBJS-$(HAVE_MIPSDSP) += $(MIPSDSP-OBJS) $(MIPSDSP-OBJS-yes) @@ -19,5 +23,6 @@ OBJS-$(HAVE_RV) += $(RV-OBJS) $(RV-OBJS-yes) OBJS-$(HAVE_RVV) += $(RVV-OBJS) $(RVV-OBJS-yes) OBJS-$(HAVE_RV_ZVBB) += $(RVVB-OBJS) $(RVVB-OBJS-yes) -OBJS-$(HAVE_MMX) += $(MMX-OBJS) $(MMX-OBJS-yes) +OBJS-$(HAVE_SIMD128) += $(SIMD128-OBJS) $(SIMD128-OBJS-yes) + OBJS-$(HAVE_X86ASM) += $(X86ASM-OBJS) $(X86ASM-OBJS-yes) diff --git a/ffbuild/bin2c.c b/ffbuild/bin2c.c index dfeedd766..91f2d81e5 100644 --- a/ffbuild/bin2c.c +++ b/ffbuild/bin2c.c @@ -38,8 +38,10 @@ int main(int argc, char **argv) return -1; output = fopen(argv[2], "wb"); - if (!output) + if (!output) { + fclose(input); return -1; + } if (argc == 4) { name = argv[3]; @@ -67,8 +69,10 @@ int main(int argc, char **argv) fclose(output); - if (ferror(input) || !feof(input)) + if (ferror(input) || !feof(input)) { + fclose(input); return -1; + } fclose(input); diff --git a/ffbuild/common.mak b/ffbuild/common.mak index 87a3ffd2b..06d6f3971 100644 --- a/ffbuild/common.mak +++ b/ffbuild/common.mak @@ -12,14 +12,23 @@ endif ifndef SUBDIR +LINK = $(LD) $(1) + +ifeq ($(LD),$(CC)) +ifneq ($(CXX),) +LDXX := $(CXX) +LINK = $(if $(filter -lstdc++,$(1)),$(LDXX) $(filter-out -lstdc++,$(1)),$(LD) $(1)) +endif +endif + BIN2CEXE = ffbuild/bin2c$(HOSTEXESUF) BIN2C = $(BIN2CEXE) ifndef V Q = @ ECHO = printf "$(1)\t%s\n" $(2) -BRIEF = CC CXX OBJCC HOSTCC HOSTLD AS X86ASM AR LD STRIP CP WINDRES NVCC BIN2C -SILENT = DEPCC DEPHOSTCC DEPAS DEPX86ASM RANLIB RM +BRIEF = CC CXX OBJCC HOSTCC HOSTLD AS X86ASM AR LD LDXX STRIP CP WINDRES GLSLC NVCC BIN2C METALCC METALLIB +SILENT = DEPCC DEPCXX DEPHOSTCC DEPAS DEPX86ASM RANLIB RM MSG = $@ M = @$(call ECHO,$(TAG),$@); @@ -42,7 +51,7 @@ OBJCCFLAGS = $(CPPFLAGS) $(CFLAGS) $(OBJCFLAGS) ASFLAGS := $(CPPFLAGS) $(ASFLAGS) # Use PREPEND here so that later (target-dependent) additions to CPPFLAGS # end up in CXXFLAGS. -$(call PREPEND,CXXFLAGS, CPPFLAGS CFLAGS) +$(call PREPEND,CXXFLAGS, CPPFLAGS) X86ASMFLAGS += $(IFLAGS:%=%/) -I$($@ +RUN_MINIFY = $(M)sed 's!/\\*.*\\*/!!g' $< | tr '\n' ' ' | tr -s ' ' | sed 's/^ //; s/ $$//' > $@ +%.gz: TAG = GZIP +%.min: TAG = MINIFY + +%.spv: %.glsl + $(COMPILE_GLSLC) + +ifdef CONFIG_SHADER_COMPRESSION +%.spv.gz: %.spv + $(RUN_GZIP) + +%.spv.c: %.spv.gz $(BIN2CEXE) + $(RUN_BIN2C) +else +%.spv.c: %.spv $(BIN2CEXE) + $(RUN_BIN2C) +endif + %.metal.air: %.metal $(METALCC) $< -o $@ @@ -122,21 +152,46 @@ $(BIN2CEXE): ffbuild/bin2c_host.o $(METALLIB) --split-module-without-linking $< -o $@ %.metallib.c: %.metallib $(BIN2CEXE) - $(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@))) + $(RUN_BIN2C) %.ptx: %.cu $(SRC_PATH)/compat/cuda/cuda_runtime.h $(COMPILE_NVCC) -ifdef CONFIG_PTX_COMPRESSION -%.ptx.gz: TAG = GZIP +ifdef CONFIG_SHADER_COMPRESSION %.ptx.gz: %.ptx - $(M)gzip -nc9 $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) >$@ + $(RUN_GZIP) %.ptx.c: %.ptx.gz $(BIN2CEXE) - $(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@))) + $(RUN_BIN2C) else %.ptx.c: %.ptx $(BIN2CEXE) - $(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@))) + $(RUN_BIN2C) +endif + +%.css.min: %.css + $(RUN_MINIFY) + +ifdef CONFIG_RESOURCE_COMPRESSION + +%.css.min.gz: %.css.min + $(RUN_GZIP) + +%.css.c: %.css.min.gz $(BIN2CEXE) + $(RUN_BIN2C) + +%.html.gz: %.html + $(RUN_GZIP) + +%.html.c: %.html.gz $(BIN2CEXE) + $(RUN_BIN2C) + +else # NO COMPRESSION + +%.css.c: %.css.min $(BIN2CEXE) + $(RUN_BIN2C) + +%.html.c: %.html $(BIN2CEXE) + $(RUN_BIN2C) endif clean:: @@ -159,7 +214,6 @@ endif include $(SRC_PATH)/ffbuild/arch.mak OBJS += $(OBJS-yes) -SLIBOBJS += $(SLIBOBJS-yes) SHLIBOBJS += $(SHLIBOBJS-yes) STLIBOBJS += $(STLIBOBJS-yes) FFLIBS := $($(NAME)_FFLIBS) $(FFLIBS-yes) $(FFLIBS) @@ -169,7 +223,6 @@ LDLIBS = $(FFLIBS:%=%$(BUILDSUF)) FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(foreach lib,EXTRALIBS-$(NAME) $(FFLIBS:%=EXTRALIBS-%),$($(lib))) $(EXTRALIBS) OBJS := $(sort $(OBJS:%=$(SUBDIR)%)) -SLIBOBJS := $(sort $(SLIBOBJS:%=$(SUBDIR)%)) SHLIBOBJS := $(sort $(SHLIBOBJS:%=$(SUBDIR)%)) STLIBOBJS := $(sort $(STLIBOBJS:%=$(SUBDIR)%)) TESTOBJS := $(TESTOBJS:%=$(SUBDIR)tests/%) $(TESTPROGS:%=$(SUBDIR)tests/%.o) @@ -190,11 +243,11 @@ ALLHEADERS := $(subst $(SRC_DIR)/,$(SUBDIR),$(wildcard $(SRC_DIR)/*.h $(SRC_DIR) SKIPHEADERS += $(ARCH_HEADERS:%=$(ARCH)/%) $(SKIPHEADERS-) SKIPHEADERS := $(SKIPHEADERS:%=$(SUBDIR)%) HOBJS = $(filter-out $(SKIPHEADERS:.h=.h.o),$(ALLHEADERS:.h=.h.o)) +SPVOBJS = $(filter %.spv.o,$(OBJS)) PTXOBJS = $(filter %.ptx.o,$(OBJS)) $(HOBJS): CCFLAGS += $(CFLAGS_HEADERS) checkheaders: $(HOBJS) -.SECONDARY: $(HOBJS:.o=.c) $(PTXOBJS:.o=.c) $(PTXOBJS:.o=.gz) $(PTXOBJS:.o=) - +.SECONDARY: $(HOBJS:.o=.c) $(SPVOBJS:.o=.c) $(SPVOBJS:.o=.gz) $(SPVOBJS:.o=) $(PTXOBJS:.o=.c) $(PTXOBJS:.o=.gz) $(PTXOBJS:.o=) alltools: $(TOOLS) $(HOSTOBJS): %.o: %.c @@ -206,15 +259,14 @@ $(HOSTPROGS): %$(HOSTEXESUF): %.o $(OBJS): | $(sort $(dir $(OBJS))) $(HOBJS): | $(sort $(dir $(HOBJS))) $(HOSTOBJS): | $(sort $(dir $(HOSTOBJS))) -$(SLIBOBJS): | $(sort $(dir $(SLIBOBJS))) $(SHLIBOBJS): | $(sort $(dir $(SHLIBOBJS))) $(STLIBOBJS): | $(sort $(dir $(STLIBOBJS))) $(TESTOBJS): | $(sort $(dir $(TESTOBJS))) $(TOOLOBJS): | tools -OUTDIRS := $(OUTDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SLIBOBJS) $(SHLIBOBJS) $(STLIBOBJS) $(TESTOBJS)) +OUTDIRS := $(OUTDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SHLIBOBJS) $(STLIBOBJS) $(TESTOBJS)) -CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.pc *.ptx *.ptx.gz *.ptx.c *.ver *.version *$(DEFAULT_X86ASMD).asm *~ *.ilk *.pdb +CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.objs *.pc *.ptx *.ptx.gz *.ptx.c *.spv *.spv.gz *.spv.c *.ver *.version *.html.gz *.html.c *.css.min.gz *.css.min *.css.c *$(DEFAULT_X86ASMD).asm *~ *.ilk *.pdb LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a define RULES @@ -224,4 +276,4 @@ endef $(eval $(RULES)) --include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d) $(SHLIBOBJS:.o=.d) $(STLIBOBJS:.o=.d) $(SLIBOBJS:.o=.d)) $(OBJS:.o=$(DEFAULT_X86ASMD).d) +-include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d) $(SHLIBOBJS:.o=.d) $(STLIBOBJS:.o=.d) $(SPVOBJS:.spv.o=.d)) $(OBJS:.o=$(DEFAULT_X86ASMD).d) diff --git a/ffbuild/library.mak b/ffbuild/library.mak index 793e9d41f..91daa9c25 100644 --- a/ffbuild/library.mak +++ b/ffbuild/library.mak @@ -26,7 +26,7 @@ ifdef CONFIG_SHARED # for purely shared builds. # Test programs are always statically linked against their library # to be able to access their library's internals, even with shared builds. -# Yet linking against dependend libraries still uses dynamic linking. +# Yet linking against dependent libraries still uses dynamic linking. # This means that we are in the scenario described above. # In case only static libs are used, the linker will only use # one of these copies; this depends on the duplicated object files @@ -35,8 +35,14 @@ OBJS += $(SHLIBOBJS) endif $(SUBDIR)$(LIBNAME): $(OBJS) $(STLIBOBJS) $(RM) $@ +ifeq ($(RESPONSE_FILES),yes) + $(Q)echo $^ > $@.objs + $(AR) $(ARFLAGS) $(AR_O) @$@.objs +else $(AR) $(ARFLAGS) $(AR_O) $^ +endif $(RANLIB) $@ + -$(RM) $@.objs install-headers: install-lib$(NAME)-headers install-lib$(NAME)-pkgconfig @@ -49,8 +55,12 @@ $(TESTPROGS): THISLIB = $(SUBDIR)$(LIBNAME) $(LIBOBJS): CPPFLAGS += -DBUILDING_$(NAME) +$(NAME)LINK_EXE_ARGS = $(LDFLAGS) $(LDEXEFLAGS) +$(NAME)LINK_SO_ARGS = $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS) +$(NAME)LINK_EXTRA = $(FFEXTRALIBS) + $(TESTPROGS) $(TOOLS): %$(EXESUF): %.o - $$(LD) $(LDFLAGS) $(LDEXEFLAGS) $$(LD_O) $$(filter %.o,$$^) $$(THISLIB) $(FFEXTRALIBS) $$(EXTRALIBS-$$(*F)) $$(ELIBS) + $$(call LINK,$$(call $(NAME)LINK_EXE_ARGS) $$(LD_O) $$(filter %.o,$$^) $$(THISLIB) $$(call $(NAME)LINK_EXTRA) $$(EXTRALIBS-$$(*F)) $$(ELIBS)) $(SUBDIR)lib$(NAME).version: $(SUBDIR)version.h $(SUBDIR)version_major.h | $(SUBDIR) $$(M) $$(SRC_PATH)/ffbuild/libversion.sh $(NAME) $$^ > $$@ @@ -64,10 +74,16 @@ $(SUBDIR)lib$(NAME).ver: $(SUBDIR)lib$(NAME).v $(OBJS) $(SUBDIR)$(SLIBNAME): $(SUBDIR)$(SLIBNAME_WITH_MAJOR) $(Q)cd ./$(SUBDIR) && $(LN_S) $(SLIBNAME_WITH_MAJOR) $(SLIBNAME) -$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SHLIBOBJS) $(SLIBOBJS) $(SUBDIR)lib$(NAME).ver +$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SHLIBOBJS) $(SUBDIR)lib$(NAME).ver $(SLIB_CREATE_DEF_CMD) - $$(LD) $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS) +ifeq ($(RESPONSE_FILES),yes) + $(Q)echo $$(filter %.o,$$^) > $$@.objs + $$(call LINK,$$(call $(NAME)LINK_SO_ARGS) $$(LD_O) @$$@.objs $$(call $(NAME)LINK_EXTRA)) +else + $$(call LINK,$$(call $(NAME)LINK_SO_ARGS) $$(LD_O) $$(filter %.o,$$^) $$(call $(NAME)LINK_EXTRA)) +endif $(SLIB_EXTRA_CMD) + -$(RM) $$@.objs ifdef SUBDIR $(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(DEP_LIBS) diff --git a/ffbuild/pkgconfig_generate.sh b/ffbuild/pkgconfig_generate.sh index e5de6716d..fc6af774a 100755 --- a/ffbuild/pkgconfig_generate.sh +++ b/ffbuild/pkgconfig_generate.sh @@ -50,7 +50,7 @@ includedir=${source_path} prefix= exec_prefix= libdir=\${pcfiledir}/../../../$name -includedir=${source_path} +includedir=${includedir} Name: $fullname Description: $comment diff --git a/fftools/Makefile b/fftools/Makefile index 083a1368c..01b16fa8f 100644 --- a/fftools/Makefile +++ b/fftools/Makefile @@ -9,6 +9,8 @@ AVBASENAMES = ffmpeg ffplay ffprobe ALLAVPROGS = $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF)) ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF)) +include $(SRC_PATH)/fftools/resources/Makefile + OBJS-ffmpeg += \ fftools/ffmpeg_dec.o \ fftools/ffmpeg_demux.o \ @@ -19,10 +21,37 @@ OBJS-ffmpeg += \ fftools/ffmpeg_mux_init.o \ fftools/ffmpeg_opt.o \ fftools/ffmpeg_sched.o \ - fftools/objpool.o \ + fftools/graph/graphprint.o \ fftools/sync_queue.o \ fftools/thread_queue.o \ + fftools/textformat/avtextformat.o \ + fftools/textformat/tf_compact.o \ + fftools/textformat/tf_default.o \ + fftools/textformat/tf_flat.o \ + fftools/textformat/tf_ini.o \ + fftools/textformat/tf_json.o \ + fftools/textformat/tf_mermaid.o \ + fftools/textformat/tf_xml.o \ + fftools/textformat/tw_avio.o \ + fftools/textformat/tw_buffer.o \ + fftools/textformat/tw_stdout.o \ + $(OBJS-resman) \ + $(RESOBJS) \ +OBJS-ffprobe += \ + fftools/textformat/avtextformat.o \ + fftools/textformat/tf_compact.o \ + fftools/textformat/tf_default.o \ + fftools/textformat/tf_flat.o \ + fftools/textformat/tf_ini.o \ + fftools/textformat/tf_json.o \ + fftools/textformat/tf_mermaid.o \ + fftools/textformat/tf_xml.o \ + fftools/textformat/tw_avio.o \ + fftools/textformat/tw_buffer.o \ + fftools/textformat/tw_stdout.o \ + +OBJS-ffmpeg += $(COMPAT_OBJS:%=compat/%) OBJS-ffplay += fftools/ffplay_renderer.o define DOFFTOOL @@ -31,7 +60,7 @@ ifdef HAVE_GNU_WINDRES OBJS-$(1) += fftools/fftoolsres.o endif $(1)$(PROGSSUF)_g$(EXESUF): $$(OBJS-$(1)) -$$(OBJS-$(1)): | fftools +$$(OBJS-$(1)): | fftools fftools/textformat fftools/resources fftools/graph $$(OBJS-$(1)): CFLAGS += $(CFLAGS-$(1)) $(1)$(PROGSSUF)_g$(EXESUF): LDFLAGS += $(LDFLAGS-$(1)) $(1)$(PROGSSUF)_g$(EXESUF): FF_EXTRALIBS += $(EXTRALIBS-$(1)) @@ -44,6 +73,9 @@ all: $(AVPROGS) fftools/ffprobe.o fftools/cmdutils.o: libavutil/ffversion.h | fftools OUTDIRS += fftools +OUTDIRS += fftools/textformat +OUTDIRS += fftools/resources +OUTDIRS += fftools/graph ifdef AVPROGS install: install-progs install-data @@ -62,4 +94,4 @@ uninstall-progs: $(RM) $(addprefix "$(BINDIR)/", $(ALLAVPROGS)) clean:: - $(RM) $(ALLAVPROGS) $(ALLAVPROGS_G) $(CLEANSUFFIXES:%=fftools/%) + $(RM) $(ALLAVPROGS) $(ALLAVPROGS_G) $(CLEANSUFFIXES:%=fftools/%) $(CLEANSUFFIXES:%=fftools/graph/%) $(CLEANSUFFIXES:%=fftools/textformat/%) diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c index f1a41e049..2f9bae9f2 100644 --- a/fftools/cmdutils.c +++ b/fftools/cmdutils.c @@ -263,7 +263,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt, return AVERROR(EINVAL); } - arg_allocated = file_read(arg); + arg_allocated = read_file_to_string(arg); if (!arg_allocated) { av_log(NULL, AV_LOG_FATAL, "Error reading the value for option '%s' from file: %s\n", @@ -275,7 +275,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt, } if (po->flags & OPT_FLAG_SPEC) { - char *p = strchr(opt, ':'); + const char *p = strchr(opt, ':'); char *str; sol = dst; @@ -353,9 +353,11 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt, ret = po->u.func_arg(optctx, opt, arg); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, - "Failed to set value '%s' for option '%s': %s\n", - arg, opt, av_err2str(ret)); + if ((strcmp(opt, "init_hw_device") != 0) || (strcmp(arg, "list") != 0)) { + av_log(NULL, AV_LOG_ERROR, + "Failed to set value '%s' for option '%s': %s\n", + arg, opt, av_err2str(ret)); + } goto finish; } } @@ -493,8 +495,9 @@ int locate_option(int argc, char **argv, const OptionDef *options, for (i = 1; i < argc; i++) { const char *cur_opt = argv[i]; - if (*cur_opt++ != '-') + if (!(cur_opt[0] == '-' && cur_opt[1])) continue; + cur_opt++; po = find_option(options, cur_opt); if (!po->name && cur_opt[0] == 'n' && cur_opt[1] == 'o') @@ -552,11 +555,12 @@ static void check_options(const OptionDef *po) void parse_loglevel(int argc, char **argv, const OptionDef *options) { - int idx = locate_option(argc, argv, options, "loglevel"); + int idx; char *env; check_options(options); + idx = locate_option(argc, argv, options, "loglevel"); if (!idx) idx = locate_option(argc, argv, options, "v"); if (idx && argv[idx + 1]) @@ -958,8 +962,7 @@ FILE *get_preset_file(char *filename, size_t filename_size, datadir, desired_size, sizeof *datadir); if (new_datadir) { datadir = new_datadir; - datadir[datadir_len] = 0; - strncat(datadir, "/ffpresets", desired_size - 1 - datadir_len); + strcpy(datadir + datadir_len, "/ffpresets"); base[2] = datadir; } } @@ -1346,6 +1349,77 @@ int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec) return ret; } +unsigned stream_group_specifier_match(const StreamSpecifier *ss, + const AVFormatContext *s, const AVStreamGroup *stg, + void *logctx) +{ + int start_stream_group = 0, nb_stream_groups; + int nb_matched = 0; + + if (ss->idx >= 0) + return 0; + + switch (ss->stream_list) { + case STREAM_LIST_STREAM_ID: + case STREAM_LIST_ALL: + case STREAM_LIST_PROGRAM: + return 0; + case STREAM_LIST_GROUP_ID: + // stream with given ID makes no sense and should be impossible to request + av_assert0(ss->idx < 0); + // return early if we know for sure the stream does not match + if (stg->id != ss->list_id) + return 0; + start_stream_group = stg->index; + nb_stream_groups = stg->index + 1; + break; + case STREAM_LIST_GROUP_IDX: + start_stream_group = ss->list_id >= 0 ? 0 : stg->index; + nb_stream_groups = stg->index + 1; + break; + default: av_assert0(0); + } + + for (int i = start_stream_group; i < nb_stream_groups; i++) { + const AVStreamGroup *candidate = s->stream_groups[i]; + + if (ss->meta_key) { + const AVDictionaryEntry *tag = av_dict_get(candidate->metadata, + ss->meta_key, NULL, 0); + + if (!tag) + continue; + if (ss->meta_val && strcmp(tag->value, ss->meta_val)) + continue; + } + + if (ss->usable_only) { + switch (candidate->type) { + case AV_STREAM_GROUP_PARAMS_TILE_GRID: { + const AVStreamGroupTileGrid *tg = candidate->params.tile_grid; + if (!tg->coded_width || !tg->coded_height || !tg->nb_tiles || + !tg->width || !tg->height || !tg->nb_tiles) + continue; + break; + } + default: + continue; + } + } + + if (ss->disposition && + (candidate->disposition & ss->disposition) != ss->disposition) + continue; + + if (stg == candidate) + return ss->list_id < 0 || ss->list_id == nb_matched; + + nb_matched++; + } + + return 0; +} + int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, AVFormatContext *s, AVStream *st, const AVCodec *codec, AVDictionary **dst, AVDictionary **opts_used) @@ -1467,9 +1541,12 @@ void *allocate_array_elem(void *ptr, size_t elem_size, int *nb_elems) { void *new_elem; - if (!(new_elem = av_mallocz(elem_size)) || - av_dynarray_add_nofree(ptr, nb_elems, new_elem) < 0) + new_elem = av_mallocz(elem_size); + if (!new_elem) return NULL; + if (av_dynarray_add_nofree(ptr, nb_elems, new_elem) < 0) + av_freep(&new_elem); + return new_elem; } @@ -1491,7 +1568,7 @@ double get_rotation(const int32_t *displaymatrix) } /* read file contents into a string */ -char *file_read(const char *filename) +char *read_file_to_string(const char *filename) { AVIOContext *pb = NULL; int ret = avio_open(&pb, filename, AVIO_FLAG_READ); @@ -1535,3 +1612,28 @@ int check_avoptions(AVDictionary *m) return 0; } + +void dump_dictionary(void *ctx, const AVDictionary *m, + const char *name, const char *indent, + int log_level) +{ + const AVDictionaryEntry *tag = NULL; + + if (!m) + return; + + av_log(ctx, log_level, "%s%s:\n", indent, name); + while ((tag = av_dict_iterate(m, tag))) { + const char *p = tag->value; + av_log(ctx, log_level, "%s %-16s: ", indent, tag->key); + while (*p) { + size_t len = strcspn(p, "\x8\xa\xb\xc\xd"); + av_log(ctx, log_level, "%.*s", (int)(FFMIN(255, len)), p); + p += len; + if (*p == 0xd) av_log(ctx, log_level, " "); + if (*p == 0xa) av_log(ctx, log_level, "\n%s %-16s: ", indent, ""); + if (*p) p++; + } + av_log(ctx, log_level, "\n"); + } +} diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h index 316b6a8c6..85b468f2a 100644 --- a/fftools/cmdutils.h +++ b/fftools/cmdutils.h @@ -158,6 +158,10 @@ unsigned stream_specifier_match(const StreamSpecifier *ss, const AVFormatContext *s, const AVStream *st, void *logctx); +unsigned stream_group_specifier_match(const StreamSpecifier *ss, + const AVFormatContext *s, const AVStreamGroup *stg, + void *logctx); + void stream_specifier_uninit(StreamSpecifier *ss); typedef struct SpecifierOpt { @@ -319,7 +323,7 @@ typedef struct Option { } Option; typedef struct OptionGroupDef { - /**< group name */ + /** group name */ const char *name; /** * Option to be used as group separator. Can be NULL for groups which @@ -535,7 +539,7 @@ void *allocate_array_elem(void *array, size_t elem_size, int *nb_elems); double get_rotation(const int32_t *displaymatrix); /* read file contents into a string */ -char *file_read(const char *filename); +char *read_file_to_string(const char *filename); /* Remove keys in dictionary b from dictionary a */ void remove_avoptions(AVDictionary **a, AVDictionary *b); @@ -545,4 +549,12 @@ int check_avoptions(AVDictionary *m); int cmdutils_isalnum(char c); +/** + * This does the same as libavformat/dump.c corresponding function + * and should probably be kept in sync when the other one changes. + */ +void dump_dictionary(void *ctx, const AVDictionary *m, + const char *name, const char *indent, + int log_level); + #endif /* FFTOOLS_CMDUTILS_H */ diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 99668ada1..b394243f5 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -78,9 +78,13 @@ #include "libavdevice/avdevice.h" #include "cmdutils.h" +#if CONFIG_MEDIACODEC +#include "compat/android/binder.h" +#endif #include "ffmpeg.h" #include "ffmpeg_sched.h" #include "ffmpeg_utils.h" +#include "graph/graphprint.h" const char program_name[] = "ffmpeg"; const int program_birth_year = 2000; @@ -249,7 +253,6 @@ void term_init(void) /* read a key without blocking */ static int read_key(void) { - unsigned char ch; #if HAVE_TERMIOS_H int n = 1; struct timeval tv; @@ -261,6 +264,7 @@ static int read_key(void) tv.tv_usec = 0; n = select(1, &rfds, NULL, NULL, &tv); if (n > 0) { + unsigned char ch; n = read(0, &ch, 1); if (n == 1) return ch; @@ -285,6 +289,7 @@ static int read_key(void) } //Read it if(nchars != 0) { + unsigned char ch; if (read(0, &ch, 1) == 1) return ch; return 0; @@ -308,6 +313,9 @@ const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL }; static void ffmpeg_cleanup(int ret) { + if ((print_graphs || print_graphs_file) && nb_output_files > 0) + print_filtergraphs(filtergraphs, nb_filtergraphs, input_files, nb_input_files, output_files, nb_output_files); + if (do_benchmark) { int64_t maxrss = getmaxrss() / 1024; av_log(NULL, AV_LOG_INFO, "bench: maxrss=%"PRId64"KiB\n", maxrss); @@ -340,6 +348,9 @@ static void ffmpeg_cleanup(int ret) av_freep(&filter_nbthreads); + av_freep(&print_graphs_file); + av_freep(&print_graphs_format); + av_freep(&input_files); av_freep(&output_files); @@ -393,6 +404,7 @@ static void frame_data_free(void *opaque, uint8_t *data) { FrameData *fd = (FrameData *)data; + av_frame_side_data_free(&fd->side_data, &fd->nb_side_data); avcodec_parameters_free(&fd->par_enc); av_free(data); @@ -422,6 +434,8 @@ static int frame_data_ensure(AVBufferRef **dst, int writable) memcpy(fd, fd_src, sizeof(*fd)); fd->par_enc = NULL; + fd->side_data = NULL; + fd->nb_side_data = 0; if (fd_src->par_enc) { int ret = 0; @@ -437,6 +451,16 @@ static int frame_data_ensure(AVBufferRef **dst, int writable) } } + if (fd_src->nb_side_data) { + int ret = clone_side_data(&fd->side_data, &fd->nb_side_data, + fd_src->side_data, fd_src->nb_side_data, 0); + if (ret < 0) { + av_buffer_unref(dst); + av_buffer_unref(&src); + return ret; + } + } + av_buffer_unref(&src); } else { fd->dec.frame_num = UINT64_MAX; @@ -555,7 +579,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti static int64_t last_time = -1; static int first_report = 1; uint64_t nb_frames_dup = 0, nb_frames_drop = 0; - int mins, secs, us; + int mins, secs, ms, us; int64_t hours; const char *hours_sign; int ret; @@ -579,6 +603,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti vid = 0; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC); av_bprint_init(&buf_script, 0, AV_BPRINT_SIZE_AUTOMATIC); + for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) { const float q = ost->enc ? atomic_load(&ost->quality) / (float) FF_QP2LAMBDA : -1; @@ -669,6 +694,15 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti av_bprintf(&buf_script, "speed=%4.3gx\n", speed); } + secs = (int)t; + ms = (int)((t - secs) * 1000); + mins = secs / 60; + secs %= 60; + hours = mins / 60; + mins %= 60; + + av_bprintf(&buf, " elapsed=%"PRId64":%02d:%02d.%02d", hours, mins, secs, ms / 10); + if (print_stats || is_last_report) { const char end = is_last_report ? '\n' : '\r'; if (print_stats==1 && AV_LOG_INFO > av_log_get_level()) { @@ -728,7 +762,7 @@ static void print_stream_maps(void) av_log(NULL, AV_LOG_INFO, " (graph %d)", ost->filter->graph->index); av_log(NULL, AV_LOG_INFO, " -> Stream #%d:%d (%s)\n", ost->file->index, - ost->index, ost->enc_ctx->codec->name); + ost->index, ost->enc->enc_ctx->codec->name); continue; } @@ -737,9 +771,9 @@ static void print_stream_maps(void) ost->ist->index, ost->file->index, ost->index); - if (ost->enc_ctx) { + if (ost->enc) { const AVCodec *in_codec = ost->ist->dec; - const AVCodec *out_codec = ost->enc_ctx->codec; + const AVCodec *out_codec = ost->enc->enc_ctx->codec; const char *decoder_name = "?"; const char *in_codec_name = "?"; const char *encoder_name = "?"; @@ -989,6 +1023,10 @@ int main(int argc, char **argv) goto finish; } +#if CONFIG_MEDIACODEC + android_binder_threadpool_init_if_required(); +#endif + current_time = ti = get_benchmark_time_stamps(); ret = transcode(sch); if (ret >= 0 && do_benchmark) { @@ -1013,5 +1051,8 @@ finish: sch_free(&sch); + av_log(NULL, AV_LOG_VERBOSE, "\n"); + av_log(NULL, AV_LOG_VERBOSE, "Exiting with exit code %d\n", ret); + return ret; } diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 83ccc4134..b4d3a2c2a 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -39,6 +39,7 @@ #include "libavfilter/avfilter.h" #include "libavutil/avutil.h" +#include "libavutil/bprint.h" #include "libavutil/dict.h" #include "libavutil/eval.h" #include "libavutil/fifo.h" @@ -135,6 +136,7 @@ typedef struct StreamMap { int disabled; /* 1 is this mapping is disabled by a negative map */ int file_index; int stream_index; + int group_index; char *linklabel; /* name of an output link, for mapping lavfi outputs */ ViewSpecifier vs; @@ -163,6 +165,7 @@ typedef struct OptionsContext { int loop; int rate_emu; float readrate; + float readrate_catchup; double readrate_initial_burst; int accurate_seek; int thread_queue_size; @@ -231,6 +234,7 @@ typedef struct OptionsContext { SpecifierOptList filter_scripts; #endif SpecifierOptList reinit_filters; + SpecifierOptList drop_changed; SpecifierOptList fix_sub_duration; SpecifierOptList fix_sub_duration_heartbeat; SpecifierOptList canvas_sizes; @@ -263,6 +267,7 @@ enum IFilterFlags { IFILTER_FLAG_REINIT = (1 << 1), IFILTER_FLAG_CFR = (1 << 2), IFILTER_FLAG_CROP = (1 << 3), + IFILTER_FLAG_DROPCHANGED = (1 << 4), }; typedef struct InputFilterOptions { @@ -297,6 +302,8 @@ enum OFilterFlags { // produce 24-bit audio OFILTER_FLAG_AUDIO_24BIT = (1 << 1), OFILTER_FLAG_AUTOSCALE = (1 << 2), + OFILTER_FLAG_AUTOROTATE = (1 << 3), + OFILTER_FLAG_CROP = (1 << 4), }; typedef struct OutputFilterOptions { @@ -318,7 +325,7 @@ typedef struct OutputFilterOptions { AVDictionary *sws_opts; AVDictionary *swr_opts; - const char *nb_threads; + int64_t nb_threads; // A combination of OFilterFlags. unsigned flags; @@ -328,18 +335,33 @@ typedef struct OutputFilterOptions { int height; enum AVColorSpace color_space; enum AVColorRange color_range; + enum AVAlphaMode alpha_mode; + + unsigned crop_top; + unsigned crop_bottom; + unsigned crop_left; + unsigned crop_right; enum VideoSyncMethod vsync_method; + AVRational frame_rate; + AVRational max_frame_rate; int sample_rate; AVChannelLayout ch_layout; - const int *formats; + union { + const enum AVPixelFormat *pix_fmts; + const enum AVSampleFormat *sample_fmts; + }; const int *sample_rates; const AVChannelLayout *ch_layouts; const AVRational *frame_rates; const enum AVColorSpace *color_spaces; const enum AVColorRange *color_ranges; + const enum AVAlphaMode *alpha_modes; + + AVFrameSideData **side_data; + int nb_side_data; // for simple filtergraphs only, view specifier passed // along to the decoder @@ -349,6 +371,18 @@ typedef struct OutputFilterOptions { typedef struct InputFilter { struct FilterGraph *graph; uint8_t *name; + int index; + + // filter data type + enum AVMediaType type; + + AVFilterContext *filter; + + char *input_name; + + /* for filters that are not yet bound to an input stream, + * this stores the input linklabel, if any */ + uint8_t *linklabel; } InputFilter; typedef struct OutputFilter { @@ -356,6 +390,11 @@ typedef struct OutputFilter { struct FilterGraph *graph; uint8_t *name; + int index; + + AVFilterContext *filter; + + char *output_name; /* for filters that are not yet bound to an output stream, * this stores the output linklabel, if any */ @@ -378,6 +417,14 @@ typedef struct FilterGraph { int nb_inputs; OutputFilter **outputs; int nb_outputs; + + // true when the filtergraph is created internally for + // purposes like stream group merging. Meant to be freed + // if unbound. + int is_internal; + + const char *graph_desc; + struct AVBPrint graph_print_buf; } FilterGraph; enum DecoderFlags { @@ -463,16 +510,20 @@ typedef struct InputStream { * currently video and audio only */ InputFilter **filters; int nb_filters; - - /* - * Output targets that do not go through lavfi, i.e. subtitles or - * streamcopy. Those two cases are distinguished by the OutputStream - * having an encoder or not. - */ - struct OutputStream **outputs; - int nb_outputs; } InputStream; +typedef struct InputStreamGroup { + const AVClass *class; + + /* parent source */ + struct InputFile *file; + + int index; + + FilterGraph *fg; + AVStreamGroup *stg; +} InputStreamGroup; + typedef struct InputFile { const AVClass *class; @@ -494,6 +545,10 @@ typedef struct InputFile { * if new streams appear dynamically during demuxing */ InputStream **streams; int nb_streams; + + /* stream groups that ffmpeg is aware of; */ + InputStreamGroup **stream_groups; + int nb_stream_groups; } InputFile; enum forced_keyframes_const { @@ -547,18 +602,13 @@ typedef struct EncStats { int lock_initialized; } EncStats; -extern const char *const forced_keyframes_const_names[]; - -typedef enum { - ENCODER_FINISHED = 1, - MUXER_FINISHED = 2, -} OSTFinished ; - enum { KF_FORCE_SOURCE = 1, #if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP KF_FORCE_SOURCE_NO_DROP = 2, #endif + // force keyframe if lavfi.scd.time metadata is set + KF_FORCE_SCD_METADATA = 3, }; typedef struct KeyframeForceCtx { @@ -577,7 +627,15 @@ typedef struct KeyframeForceCtx { int dropped_keyframe; } KeyframeForceCtx; -typedef struct Encoder Encoder; +typedef struct Encoder { + const AVClass *class; + + AVCodecContext *enc_ctx; + + // number of frames/samples sent to the encoder + uint64_t frames_encoded; + uint64_t samples_encoded; +} Encoder; enum CroppingType { CROP_DISABLED = 0, @@ -596,12 +654,6 @@ typedef struct OutputStream { int index; /* stream index in the output file */ - /** - * Codec parameters for packets submitted to the muxer (i.e. before - * bitstream filtering, if any). - */ - AVCodecParameters *par_in; - /* input stream that is the source for this output stream; * may be NULL for streams with no well-defined source, e.g. * attachments or outputs from complex filtergraphs */ @@ -610,12 +662,8 @@ typedef struct OutputStream { AVStream *st; /* stream in the output file */ Encoder *enc; - AVCodecContext *enc_ctx; /* video only */ - AVRational frame_rate; - AVRational max_frame_rate; - int force_fps; #if FFMPEG_OPT_TOP int top_field_first; #endif @@ -638,9 +686,6 @@ typedef struct OutputStream { /* stats */ // number of packets send to the muxer atomic_uint_least64_t packets_written; - // number of frames/samples sent to the encoder - uint64_t frames_encoded; - uint64_t samples_encoded; /* packet quality factor */ atomic_int quality; @@ -692,6 +737,9 @@ typedef struct FrameData { int64_t wallclock[LATENCY_PROBE_NB]; AVCodecParameters *par_enc; + + AVFrameSideData **side_data; + int nb_side_data; } FrameData; extern InputFile **input_files; @@ -733,7 +781,11 @@ extern float max_error_rate; extern char *filter_nbthreads; extern int filter_complex_nbthreads; +extern int filter_buffered_frames; extern int vstats_version; +extern int print_graphs; +extern char *print_graphs_file; +extern char *print_graphs_format; extern int auto_conversion_filters; extern const AVIOInterruptCB int_cb; @@ -761,13 +813,14 @@ int check_avoptions_used(const AVDictionary *opts, const AVDictionary *opts_used int assert_file_overwrite(const char *filename); int find_codec(void *logctx, const char *name, enum AVMediaType type, int encoder, const AVCodec **codec); -int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global); +int parse_and_set_vsync(const char *arg, enum VideoSyncMethod *vsync_var, int file_idx, int st_idx, int is_global); int filtergraph_is_simple(const FilterGraph *fg); -int init_simple_filtergraph(InputStream *ist, OutputStream *ost, - char *graph_desc, - Scheduler *sch, unsigned sch_idx_enc, - const OutputFilterOptions *opts); +int fg_create_simple(FilterGraph **pfg, + InputStream *ist, + char **graph_desc, + Scheduler *sch, unsigned sched_idx_enc, + const OutputFilterOptions *opts); int fg_finalise_bindings(void); /** @@ -781,17 +834,18 @@ const FrameData *frame_data_c(AVFrame *frame); FrameData *packet_data (AVPacket *pkt); const FrameData *packet_data_c(AVPacket *pkt); -int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, +int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc, const OutputFilterOptions *opts); /** * Create a new filtergraph in the global filtergraph list. * - * @param graph_desc Graph description; an av_malloc()ed string, filtergraph + * @param graph_desc Pointer to graph description; an av_malloc()ed string, filtergraph * takes ownership of it. */ -int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch); +int fg_create(FilterGraph **pfg, char **graph_desc, Scheduler *sch, + const OutputFilterOptions *opts); void fg_free(FilterGraph **pfg); @@ -860,7 +914,7 @@ int dec_request_view(Decoder *dec, const ViewSpecifier *vs, SchedulerNode *src); int enc_alloc(Encoder **penc, const AVCodec *codec, - Scheduler *sch, unsigned sch_idx); + Scheduler *sch, unsigned sch_idx, void *log_parent); void enc_free(Encoder **penc); int enc_open(void *opaque, const AVFrame *frame); @@ -873,7 +927,8 @@ int enc_loopback(Encoder *enc); * * Open the muxer once all the streams have been initialized. */ -int of_stream_init(OutputFile *of, OutputStream *ost); +int of_stream_init(OutputFile *of, OutputStream *ost, + const AVCodecContext *enc_ctx); int of_write_trailer(OutputFile *of); int of_open(const OptionsContext *o, const char *filename, Scheduler *sch); void of_free(OutputFile **pof); @@ -885,7 +940,8 @@ int64_t of_filesize(OutputFile *of); int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch); void ifile_close(InputFile **f); -int ist_output_add(InputStream *ist, OutputStream *ost); +int ist_use(InputStream *ist, int decoding_needed, + const ViewSpecifier *vs, SchedulerNode *src); int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, const ViewSpecifier *vs, InputFilterOptions *opts, SchedulerNode *src); @@ -916,6 +972,15 @@ void opt_match_per_stream_int64(void *logctx, const SpecifierOptList *sol, void opt_match_per_stream_dbl(void *logctx, const SpecifierOptList *sol, AVFormatContext *fc, AVStream *st, double *out); +void opt_match_per_stream_group_str(void *logctx, const SpecifierOptList *sol, + AVFormatContext *fc, AVStreamGroup *stg, const char **out); +void opt_match_per_stream_group_int(void *logctx, const SpecifierOptList *sol, + AVFormatContext *fc, AVStreamGroup *stg, int *out); +void opt_match_per_stream_group_int64(void *logctx, const SpecifierOptList *sol, + AVFormatContext *fc, AVStreamGroup *stg, int64_t *out); +void opt_match_per_stream_group_dbl(void *logctx, const SpecifierOptList *sol, + AVFormatContext *fc, AVStreamGroup *stg, double *out); + int view_specifier_parse(const char **pspec, ViewSpecifier *vs); int muxer_thread(void *arg); diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c index 2723a0312..5020684a2 100644 --- a/fftools/ffmpeg_dec.c +++ b/fftools/ffmpeg_dec.c @@ -733,23 +733,25 @@ static int packet_decode(DecoderPriv *dp, AVPacket *pkt, AVFrame *frame) av_log(dp, AV_LOG_ERROR, "Error submitting %s to decoder: %s\n", pkt ? "packet" : "EOF", av_err2str(ret)); - if (ret != AVERROR_EOF) { - dp->dec.decode_errors++; - if (!exit_on_error) - ret = 0; - } + if (ret == AVERROR_EOF) + return ret; - return ret; + dp->dec.decode_errors++; + if (exit_on_error) + return ret; } while (1) { FrameData *fd; unsigned outputs_mask = 1; + unsigned flags = 0; + if (!dp->dec.frames_decoded) + flags |= AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS; av_frame_unref(frame); update_benchmark(NULL); - ret = avcodec_receive_frame(dec, frame); + ret = avcodec_receive_frame_flags(dec, frame, flags); update_benchmark("decode_%s %s", type_desc, dp->parent_name); if (ret == AVERROR(EAGAIN)) { @@ -1008,7 +1010,7 @@ static int decoder_thread(void *arg) ret = 0; err_rate = (dp->dec.frames_decoded || dp->dec.decode_errors) ? - dp->dec.decode_errors / (dp->dec.frames_decoded + dp->dec.decode_errors) : 0.f; + (float)dp->dec.decode_errors / (dp->dec.frames_decoded + dp->dec.decode_errors) : 0.f; if (err_rate > max_error_rate) { av_log(dp, AV_LOG_FATAL, "Decode error rate %g exceeds maximum %g\n", err_rate, max_error_rate); @@ -1019,6 +1021,7 @@ static int decoder_thread(void *arg) finish: dec_thread_uninit(&dt); + avcodec_free_context(&dp->dec_ctx); return ret; } @@ -1595,7 +1598,7 @@ static int dec_open(DecoderPriv *dp, AVDictionary **dec_opts, if (o->flags & DECODER_FLAG_BITEXACT) dp->dec_ctx->flags |= AV_CODEC_FLAG_BITEXACT; - // we apply cropping outselves + // we apply cropping ourselves dp->apply_cropping = dp->dec_ctx->apply_cropping; dp->dec_ctx->apply_cropping = 0; @@ -1636,8 +1639,14 @@ static int dec_open(DecoderPriv *dp, AVDictionary **dec_opts, param_out->sample_aspect_ratio = dp->dec_ctx->sample_aspect_ratio; param_out->colorspace = dp->dec_ctx->colorspace; param_out->color_range = dp->dec_ctx->color_range; + param_out->alpha_mode = dp->dec_ctx->alpha_mode; } + av_frame_side_data_free(¶m_out->side_data, ¶m_out->nb_side_data); + ret = clone_side_data(¶m_out->side_data, ¶m_out->nb_side_data, + dp->dec_ctx->decoded_side_data, dp->dec_ctx->nb_decoded_side_data, 0); + if (ret < 0) + return ret; param_out->time_base = dp->dec_ctx->pkt_timebase; } diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c index cd12d84d2..7c708ff0f 100644 --- a/fftools/ffmpeg_demux.c +++ b/fftools/ffmpeg_demux.c @@ -68,17 +68,18 @@ typedef struct DemuxStream { int autorotate; int apply_cropping; int force_display_matrix; + int drop_changed; int wrap_correction_done; int saw_first_ts; - ///< dts of the first packet read for this stream (in AV_TIME_BASE units) + /// dts of the first packet read for this stream (in AV_TIME_BASE units) int64_t first_dts; /* predicted dts of the next packet read for this stream or (when there are * several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */ int64_t next_dts; - ///< dts of the last packet read for this stream (in AV_TIME_BASE units) + /// dts of the last packet read for this stream (in AV_TIME_BASE units) int64_t dts; const AVCodecDescriptor *codec_desc; @@ -95,8 +96,21 @@ typedef struct DemuxStream { uint64_t nb_packets; // combined size of all the packets read uint64_t data_size; + // latest wallclock time at which packet reading resumed after a stall - used for readrate + int64_t resume_wc; + // timestamp of first packet sent after the latest stall - used for readrate + int64_t resume_pts; + // measure of how far behind packet reading is against spceified readrate + int64_t lag; } DemuxStream; +typedef struct DemuxStreamGroup { + InputStreamGroup istg; + + // name used for logging + char log_name[32]; +} DemuxStreamGroup; + typedef struct Demuxer { InputFile f; @@ -128,6 +142,7 @@ typedef struct Demuxer { float readrate; double readrate_initial_burst; + float readrate_catchup; Scheduler *sch; @@ -241,7 +256,7 @@ static void ts_discontinuity_detect(Demuxer *d, InputStream *ist, } } else { if (FFABS(delta) > 1LL * dts_error_threshold * AV_TIME_BASE) { - av_log(NULL, AV_LOG_WARNING, + av_log(ist, AV_LOG_WARNING, "DTS %"PRId64", next:%"PRId64" st:%d invalid dropping\n", pkt->dts, ds->next_dts, pkt->stream_index); pkt->dts = AV_NOPTS_VALUE; @@ -250,7 +265,7 @@ static void ts_discontinuity_detect(Demuxer *d, InputStream *ist, int64_t pkt_pts = av_rescale_q(pkt->pts, pkt->time_base, AV_TIME_BASE_Q); delta = pkt_pts - ds->next_dts; if (FFABS(delta) > 1LL * dts_error_threshold * AV_TIME_BASE) { - av_log(NULL, AV_LOG_WARNING, + av_log(ist, AV_LOG_WARNING, "PTS %"PRId64", next:%"PRId64" invalid dropping st:%d\n", pkt->pts, ds->next_dts, pkt->stream_index); pkt->pts = AV_NOPTS_VALUE; @@ -262,7 +277,7 @@ static void ts_discontinuity_detect(Demuxer *d, InputStream *ist, int64_t delta = pkt_dts - d->last_ts; if (FFABS(delta) > 1LL * dts_delta_threshold * AV_TIME_BASE) { d->ts_offset_discont -= delta; - av_log(NULL, AV_LOG_DEBUG, + av_log(ist, AV_LOG_DEBUG, "Inter stream timestamp discontinuity %"PRId64", new offset= %"PRId64"\n", delta, d->ts_offset_discont); pkt->dts -= av_rescale_q(delta, AV_TIME_BASE_Q, pkt->time_base); @@ -477,7 +492,7 @@ static int input_packet_process(Demuxer *d, AVPacket *pkt, unsigned *send_flags) fd->wallclock[LATENCY_PROBE_DEMUX] = av_gettime_relative(); if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "demuxer+ffmpeg -> ist_index:%d:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s off:%s off_time:%s\n", + av_log(ist, AV_LOG_INFO, "demuxer+ffmpeg -> ist_index:%d:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s off:%s off_time:%s\n", f->index, pkt->stream_index, av_get_media_type_string(ist->par->codec_type), av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &pkt->time_base), @@ -496,16 +511,45 @@ static void readrate_sleep(Demuxer *d) (f->start_time_effective != AV_NOPTS_VALUE ? f->start_time_effective * !start_at_zero : 0) + (f->start_time != AV_NOPTS_VALUE ? f->start_time : 0) ); - int64_t burst_until = AV_TIME_BASE * d->readrate_initial_burst; + int64_t initial_burst = AV_TIME_BASE * d->readrate_initial_burst; + int resume_warn = 0; + for (int i = 0; i < f->nb_streams; i++) { InputStream *ist = f->streams[i]; DemuxStream *ds = ds_from_ist(ist); - int64_t stream_ts_offset, pts, now; + int64_t stream_ts_offset, pts, now, wc_elapsed, elapsed, lag, max_pts, limit_pts; + + if (ds->discard) continue; + stream_ts_offset = FFMAX(ds->first_dts != AV_NOPTS_VALUE ? ds->first_dts : 0, file_start); pts = av_rescale(ds->dts, 1000000, AV_TIME_BASE); - now = (av_gettime_relative() - d->wallclock_start) * d->readrate + stream_ts_offset; - if (pts - burst_until > now) - av_usleep(pts - burst_until - now); + now = av_gettime_relative(); + wc_elapsed = now - d->wallclock_start; + + if (pts <= stream_ts_offset + initial_burst) continue; + + max_pts = stream_ts_offset + initial_burst + (int64_t)(wc_elapsed * d->readrate); + lag = FFMAX(max_pts - pts, 0); + if ( (!ds->lag && lag > 0.3 * AV_TIME_BASE) || ( lag > ds->lag + 0.3 * AV_TIME_BASE) ) { + ds->lag = lag; + ds->resume_wc = now; + ds->resume_pts = pts; + av_log_once(ds, AV_LOG_WARNING, AV_LOG_DEBUG, &resume_warn, + "Resumed reading at pts %0.3f with rate %0.3f after a lag of %0.3fs\n", + (float)pts/AV_TIME_BASE, d->readrate_catchup, (float)lag/AV_TIME_BASE); + } + if (ds->lag && !lag) + ds->lag = ds->resume_wc = ds->resume_pts = 0; + if (ds->resume_wc) { + elapsed = now - ds->resume_wc; + limit_pts = ds->resume_pts + (int64_t)(elapsed * d->readrate_catchup); + } else { + elapsed = wc_elapsed; + limit_pts = max_pts; + } + + if (pts > limit_pts) + av_usleep(pts - limit_pts); } } @@ -841,7 +885,6 @@ static void ist_free(InputStream **pist) av_dict_free(&ds->decoder_opts); av_freep(&ist->filters); - av_freep(&ist->outputs); av_freep(&ds->dec_opts.hwaccel_device); avcodec_parameters_free(&ist->par); @@ -853,6 +896,16 @@ static void ist_free(InputStream **pist) av_freep(pist); } +static void istg_free(InputStreamGroup **pistg) +{ + InputStreamGroup *istg = *pistg; + + if (!istg) + return; + + av_freep(pistg); +} + void ifile_close(InputFile **pf) { InputFile *f = *pf; @@ -868,6 +921,10 @@ void ifile_close(InputFile **pf) ist_free(&f->streams[i]); av_freep(&f->streams); + for (int i = 0; i < f->nb_stream_groups; i++) + istg_free(&f->stream_groups[i]); + av_freep(&f->stream_groups); + avformat_close_input(&f->ctx); av_packet_free(&d->pkt_heartbeat); @@ -875,8 +932,8 @@ void ifile_close(InputFile **pf) av_freep(pf); } -static int ist_use(InputStream *ist, int decoding_needed, - const ViewSpecifier *vs, SchedulerNode *src) +int ist_use(InputStream *ist, int decoding_needed, + const ViewSpecifier *vs, SchedulerNode *src) { Demuxer *d = demuxer_from_ifile(ist->file); DemuxStream *ds = ds_from_ist(ist); @@ -985,25 +1042,6 @@ static int ist_use(InputStream *ist, int decoding_needed, return 0; } -int ist_output_add(InputStream *ist, OutputStream *ost) -{ - DemuxStream *ds = ds_from_ist(ist); - SchedulerNode src; - int ret; - - ret = ist_use(ist, ost->enc ? DECODING_FOR_OST : 0, NULL, &src); - if (ret < 0) - return ret; - - ret = GROW_ARRAY(ist->outputs, ist->nb_outputs); - if (ret < 0) - return ret; - - ist->outputs[ist->nb_outputs - 1] = ost; - - return ost->enc ? ds->sch_idx_dec : ds->sch_idx_stream; -} - int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, const ViewSpecifier *vs, InputFilterOptions *opts, SchedulerNode *src) @@ -1096,7 +1134,8 @@ int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, return AVERROR(ENOMEM); opts->flags |= IFILTER_FLAG_AUTOROTATE * !!(ds->autorotate) | - IFILTER_FLAG_REINIT * !!(ds->reinit_filters); + IFILTER_FLAG_REINIT * !!(ds->reinit_filters) | + IFILTER_FLAG_DROPCHANGED* !!(ds->drop_changed); return 0; } @@ -1134,7 +1173,7 @@ static int choose_decoder(const OptionsContext *o, void *logctx, for (int j = 0; config = avcodec_get_hw_config(c, j); j++) { if (config->device_type == hwaccel_device_type) { - av_log(NULL, AV_LOG_VERBOSE, "Selecting decoder '%s' because of requested hwaccel method %s\n", + av_log(logctx, AV_LOG_VERBOSE, "Selecting decoder '%s' because of requested hwaccel method %s\n", c->name, av_hwdevice_get_type_name(hwaccel_device_type)); *pcodec = c; return 0; @@ -1410,6 +1449,17 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona ds->reinit_filters = -1; opt_match_per_stream_int(ist, &o->reinit_filters, ic, st, &ds->reinit_filters); + ds->drop_changed = 0; + opt_match_per_stream_int(ist, &o->drop_changed, ic, st, &ds->drop_changed); + + if (ds->drop_changed && ds->reinit_filters) { + if (ds->reinit_filters > 0) { + av_log(ist, AV_LOG_ERROR, "drop_changed and reinit_filters both enabled. These are mutually exclusive.\n"); + return AVERROR(EINVAL); + } + ds->reinit_filters = 0; + } + ist->user_set_discard = AVDISCARD_NONE; if ((o->video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) || @@ -1560,6 +1610,144 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona return 0; } +static const char *input_stream_group_item_name(void *obj) +{ + const DemuxStreamGroup *dsg = obj; + + return dsg->log_name; +} + +static const AVClass input_stream_group_class = { + .class_name = "InputStreamGroup", + .version = LIBAVUTIL_VERSION_INT, + .item_name = input_stream_group_item_name, + .category = AV_CLASS_CATEGORY_DEMUXER, +}; + +static DemuxStreamGroup *demux_stream_group_alloc(Demuxer *d, AVStreamGroup *stg) +{ + InputFile *f = &d->f; + DemuxStreamGroup *dsg; + + dsg = allocate_array_elem(&f->stream_groups, sizeof(*dsg), &f->nb_stream_groups); + if (!dsg) + return NULL; + + dsg->istg.stg = stg; + dsg->istg.file = f; + dsg->istg.index = stg->index; + dsg->istg.class = &input_stream_group_class; + + snprintf(dsg->log_name, sizeof(dsg->log_name), "istg#%d:%d/%s", + d->f.index, stg->index, avformat_stream_group_name(stg->type)); + + return dsg; +} + +static int istg_parse_tile_grid(const OptionsContext *o, Demuxer *d, InputStreamGroup *istg) +{ + InputFile *f = &d->f; + AVFormatContext *ic = d->f.ctx; + AVStreamGroup *stg = istg->stg; + const AVStreamGroupTileGrid *tg = stg->params.tile_grid; + OutputFilterOptions opts; + AVBPrint bp; + char *graph_str; + int autorotate = 1; + const char *apply_cropping = NULL; + int ret; + + if (tg->nb_tiles == 1) + return 0; + + memset(&opts, 0, sizeof(opts)); + + opt_match_per_stream_group_int(istg, &o->autorotate, ic, stg, &autorotate); + if (autorotate) + opts.flags |= OFILTER_FLAG_AUTOROTATE; + + opts.flags |= OFILTER_FLAG_CROP; + opt_match_per_stream_group_str(istg, &o->apply_cropping, ic, stg, &apply_cropping); + if (apply_cropping) { + char *p; + int crop = strtol(apply_cropping, &p, 0); + if (*p) + return AVERROR(EINVAL); + if (!crop) + opts.flags &= ~OFILTER_FLAG_CROP; + } + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + for (int i = 0; i < tg->nb_tiles; i++) + av_bprintf(&bp, "[%d:g:%d:%d]", f->index, stg->index, tg->offsets[i].idx); + av_bprintf(&bp, "xstack=inputs=%d:layout=", tg->nb_tiles); + for (int i = 0; i < tg->nb_tiles - 1; i++) + av_bprintf(&bp, "%d_%d|", tg->offsets[i].horizontal, + tg->offsets[i].vertical); + av_bprintf(&bp, "%d_%d:fill=0x%02X%02X%02X@0x%02X", tg->offsets[tg->nb_tiles - 1].horizontal, + tg->offsets[tg->nb_tiles - 1].vertical, + tg->background[0], tg->background[1], + tg->background[2], tg->background[3]); + av_bprintf(&bp, "[%d:g:%d]", f->index, stg->index); + ret = av_bprint_finalize(&bp, &graph_str); + if (ret < 0) + return ret; + + if (tg->coded_width != tg->width || tg->coded_height != tg->height) { + opts.crop_top = tg->vertical_offset; + opts.crop_bottom = tg->coded_height - tg->height - tg->vertical_offset; + opts.crop_left = tg->horizontal_offset; + opts.crop_right = tg->coded_width - tg->width - tg->horizontal_offset; + } + + for (int i = 0; i < tg->nb_coded_side_data; i++) { + const AVPacketSideData *sd = &tg->coded_side_data[i]; + + ret = av_packet_side_data_to_frame(&opts.side_data, &opts.nb_side_data, sd, 0); + if (ret < 0 && ret != AVERROR(EINVAL)) + goto fail; + } + + ret = fg_create(NULL, &graph_str, d->sch, &opts); + if (ret < 0) + goto fail; + + istg->fg = filtergraphs[nb_filtergraphs-1]; + istg->fg->is_internal = 1; + + ret = 0; +fail: + if (ret < 0) + av_freep(&graph_str); + + return ret; +} + +static int istg_add(const OptionsContext *o, Demuxer *d, AVStreamGroup *stg) +{ + DemuxStreamGroup *dsg; + InputStreamGroup *istg; + int ret; + + dsg = demux_stream_group_alloc(d, stg); + if (!dsg) + return AVERROR(ENOMEM); + + istg = &dsg->istg; + + switch (stg->type) { + case AV_STREAM_GROUP_PARAMS_TILE_GRID: + ret = istg_parse_tile_grid(o, d, istg); + if (ret < 0) + return ret; + break; + default: + break; + } + + return 0; +} + static int is_windows_reserved_device_name(const char *f) { #if HAVE_DOS_PATHS @@ -1746,6 +1934,7 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) ic = avformat_alloc_context(); if (!ic) return AVERROR(ENOMEM); + ic->name = av_strdup(d->log_name); if (o->audio_sample_rate.nb_opt) { av_dict_set_int(&o->g->format_opts, "sample_rate", o->audio_sample_rate.opt[o->audio_sample_rate.nb_opt - 1].u.i, 0); } @@ -1823,8 +2012,9 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) /* open the input file with generic avformat function */ err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts); if (err < 0) { - av_log(d, AV_LOG_ERROR, - "Error opening input: %s\n", av_err2str(err)); + if (err != AVERROR_EXIT) + av_log(d, AV_LOG_ERROR, + "Error opening input: %s\n", av_err2str(err)); if (err == AVERROR_PROTOCOL_NOT_FOUND) av_log(d, AV_LOG_ERROR, "Did you mean file:%s?\n", filename); return err; @@ -1833,6 +2023,8 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) av_strlcat(d->log_name, "/", sizeof(d->log_name)); av_strlcat(d->log_name, ic->iformat->name, sizeof(d->log_name)); + av_freep(&ic->name); + ic->name = av_strdup(d->log_name); if (scan_all_pmts_set) av_dict_set(&o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE); @@ -1955,9 +2147,22 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) d->readrate_initial_burst); return AVERROR(EINVAL); } - } else if (o->readrate_initial_burst) { - av_log(d, AV_LOG_WARNING, "Option -readrate_initial_burst ignored " - "since neither -readrate nor -re were given\n"); + d->readrate_catchup = o->readrate_catchup ? o->readrate_catchup : d->readrate * 1.05; + if (d->readrate_catchup < d->readrate) { + av_log(d, AV_LOG_ERROR, + "Option -readrate_catchup is %0.3f; it must be at least equal to %0.3f.\n", + d->readrate_catchup, d->readrate); + return AVERROR(EINVAL); + } + } else { + if (o->readrate_initial_burst) { + av_log(d, AV_LOG_WARNING, "Option -readrate_initial_burst ignored " + "since neither -readrate nor -re were given\n"); + } + if (o->readrate_catchup) { + av_log(d, AV_LOG_WARNING, "Option -readrate_catchup ignored " + "since neither -readrate nor -re were given\n"); + } } /* Add all the streams from the given input file to the demuxer */ @@ -1969,6 +2174,13 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) } } + /* Add all the stream groups from the given input file to the demuxer */ + for (int i = 0; i < ic->nb_stream_groups; i++) { + ret = istg_add(o, d, ic->stream_groups[i]); + if (ret < 0) + return ret; + } + /* dump the file content */ av_dump_format(ic, f->index, filename, 0); diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c index c1c8aa0e7..a59591293 100644 --- a/fftools/ffmpeg_enc.c +++ b/fftools/ffmpeg_enc.c @@ -38,7 +38,12 @@ #include "libavcodec/avcodec.h" -struct Encoder { +typedef struct EncoderPriv { + Encoder e; + + void *log_parent; + char log_name[32]; + // combined size of all the packets received from the encoder uint64_t data_size; @@ -50,7 +55,12 @@ struct Encoder { Scheduler *sch; unsigned sch_idx; -}; +} EncoderPriv; + +static EncoderPriv *ep_from_enc(Encoder *enc) +{ + return (EncoderPriv*)enc; +} // data that is local to the decoder thread and not visible outside of it typedef struct EncoderThread { @@ -65,56 +75,90 @@ void enc_free(Encoder **penc) if (!enc) return; + if (enc->enc_ctx) + av_freep(&enc->enc_ctx->stats_in); + avcodec_free_context(&enc->enc_ctx); + av_freep(penc); } -int enc_alloc(Encoder **penc, const AVCodec *codec, - Scheduler *sch, unsigned sch_idx) +static const char *enc_item_name(void *obj) { - Encoder *enc; + const EncoderPriv *ep = obj; + + return ep->log_name; +} + +static const AVClass enc_class = { + .class_name = "Encoder", + .version = LIBAVUTIL_VERSION_INT, + .parent_log_context_offset = offsetof(EncoderPriv, log_parent), + .item_name = enc_item_name, +}; + +int enc_alloc(Encoder **penc, const AVCodec *codec, + Scheduler *sch, unsigned sch_idx, void *log_parent) +{ + EncoderPriv *ep; + int ret = 0; *penc = NULL; - enc = av_mallocz(sizeof(*enc)); - if (!enc) + ep = av_mallocz(sizeof(*ep)); + if (!ep) return AVERROR(ENOMEM); - enc->sch = sch; - enc->sch_idx = sch_idx; + ep->e.class = &enc_class; + ep->log_parent = log_parent; - *penc = enc; + ep->sch = sch; + ep->sch_idx = sch_idx; + + snprintf(ep->log_name, sizeof(ep->log_name), "enc:%s", codec->name); + + ep->e.enc_ctx = avcodec_alloc_context3(codec); + if (!ep->e.enc_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } + + *penc = &ep->e; return 0; +fail: + enc_free((Encoder**)&ep); + return ret; } -static int hw_device_setup_for_encode(OutputStream *ost, AVBufferRef *frames_ref) +static int hw_device_setup_for_encode(Encoder *e, AVCodecContext *enc_ctx, + AVBufferRef *frames_ref) { const AVCodecHWConfig *config; HWDevice *dev = NULL; if (frames_ref && ((AVHWFramesContext*)frames_ref->data)->format == - ost->enc_ctx->pix_fmt) { + enc_ctx->pix_fmt) { // Matching format, will try to use hw_frames_ctx. } else { frames_ref = NULL; } for (int i = 0;; i++) { - config = avcodec_get_hw_config(ost->enc_ctx->codec, i); + config = avcodec_get_hw_config(enc_ctx->codec, i); if (!config) break; if (frames_ref && config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX && (config->pix_fmt == AV_PIX_FMT_NONE || - config->pix_fmt == ost->enc_ctx->pix_fmt)) { - av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using input " + config->pix_fmt == enc_ctx->pix_fmt)) { + av_log(e, AV_LOG_VERBOSE, "Using input " "frames context (format %s) with %s encoder.\n", - av_get_pix_fmt_name(ost->enc_ctx->pix_fmt), - ost->enc_ctx->codec->name); - ost->enc_ctx->hw_frames_ctx = av_buffer_ref(frames_ref); - if (!ost->enc_ctx->hw_frames_ctx) + av_get_pix_fmt_name(enc_ctx->pix_fmt), + enc_ctx->codec->name); + enc_ctx->hw_frames_ctx = av_buffer_ref(frames_ref); + if (!enc_ctx->hw_frames_ctx) return AVERROR(ENOMEM); return 0; } @@ -125,11 +169,11 @@ static int hw_device_setup_for_encode(OutputStream *ost, AVBufferRef *frames_ref } if (dev) { - av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using device %s " + av_log(e, AV_LOG_VERBOSE, "Using device %s " "(type %s) with %s encoder.\n", dev->name, - av_hwdevice_get_type_name(dev->type), ost->enc_ctx->codec->name); - ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref); - if (!ost->enc_ctx->hw_device_ctx) + av_hwdevice_get_type_name(dev->type), enc_ctx->codec->name); + enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref); + if (!enc_ctx->hw_device_ctx) return AVERROR(ENOMEM); } else { // No device required, or no device available. @@ -137,37 +181,13 @@ static int hw_device_setup_for_encode(OutputStream *ost, AVBufferRef *frames_ref return 0; } -static int set_encoder_id(OutputFile *of, OutputStream *ost) -{ - const char *cname = ost->enc_ctx->codec->name; - uint8_t *encoder_string; - int encoder_string_len; - - if (av_dict_get(ost->st->metadata, "encoder", NULL, 0)) - return 0; - - encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(cname) + 2; - encoder_string = av_mallocz(encoder_string_len); - if (!encoder_string) - return AVERROR(ENOMEM); - - if (!of->bitexact && !ost->bitexact) - av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len); - else - av_strlcpy(encoder_string, "Lavc ", encoder_string_len); - av_strlcat(encoder_string, cname, encoder_string_len); - av_dict_set(&ost->st->metadata, "encoder", encoder_string, - AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE); - - return 0; -} - int enc_open(void *opaque, const AVFrame *frame) { OutputStream *ost = opaque; InputStream *ist = ost->ist; Encoder *e = ost->enc; - AVCodecContext *enc_ctx = ost->enc_ctx; + EncoderPriv *ep = ep_from_enc(e); + AVCodecContext *enc_ctx = e->enc_ctx; Decoder *dec = NULL; const AVCodec *enc = enc_ctx->codec; OutputFile *of = ost->file; @@ -175,7 +195,7 @@ int enc_open(void *opaque, const AVFrame *frame) int frame_samples = 0; int ret; - if (e->opened) + if (ep->opened) return 0; // frame is always non-NULL for audio and video @@ -185,25 +205,12 @@ int enc_open(void *opaque, const AVFrame *frame) av_assert0(frame->opaque_ref); fd = (FrameData*)frame->opaque_ref->data; - for (int i = 0; i < frame->nb_side_data; i++) { - const AVSideDataDescriptor *desc = av_frame_side_data_desc(frame->side_data[i]->type); - - if (!(desc->props & AV_SIDE_DATA_PROP_GLOBAL)) - continue; - - ret = av_frame_side_data_clone(&enc_ctx->decoded_side_data, - &enc_ctx->nb_decoded_side_data, - frame->side_data[i], - AV_FRAME_SIDE_DATA_FLAG_UNIQUE); - if (ret < 0) - return ret; - } + ret = clone_side_data(&enc_ctx->decoded_side_data, &enc_ctx->nb_decoded_side_data, + fd->side_data, fd->nb_side_data, AV_FRAME_SIDE_DATA_FLAG_UNIQUE); + if (ret < 0) + return ret; } - ret = set_encoder_id(of, ost); - if (ret < 0) - return ret; - if (ist) dec = ist->decoder; @@ -211,7 +218,6 @@ int enc_open(void *opaque, const AVFrame *frame) if (ost->type == AVMEDIA_TYPE_AUDIO || ost->type == AVMEDIA_TYPE_VIDEO) { enc_ctx->time_base = frame->time_base; enc_ctx->framerate = fd->frame_rate_filter; - ost->st->avg_frame_rate = fd->frame_rate_filter; } switch (enc_ctx->codec_type) { @@ -238,7 +244,7 @@ int enc_open(void *opaque, const AVFrame *frame) frame->height > 0); enc_ctx->width = frame->width; enc_ctx->height = frame->height; - enc_ctx->sample_aspect_ratio = ost->st->sample_aspect_ratio = + enc_ctx->sample_aspect_ratio = ost->frame_aspect_ratio.num ? // overridden by the -aspect cli option av_mul_q(ost->frame_aspect_ratio, (AVRational){ enc_ctx->height, enc_ctx->width }) : frame->sample_aspect_ratio; @@ -251,11 +257,27 @@ int enc_open(void *opaque, const AVFrame *frame) enc_ctx->bits_per_raw_sample = FFMIN(fd->bits_per_raw_sample, av_pix_fmt_desc_get(enc_ctx->pix_fmt)->comp[0].depth); + /** + * The video color properties should always be in sync with the user- + * requested values, since we forward them to the filter graph. + */ enc_ctx->color_range = frame->color_range; enc_ctx->color_primaries = frame->color_primaries; enc_ctx->color_trc = frame->color_trc; enc_ctx->colorspace = frame->colorspace; - enc_ctx->chroma_sample_location = frame->chroma_location; + enc_ctx->alpha_mode = frame->alpha_mode; + + /* Video properties which are not part of filter graph negotiation */ + if (enc_ctx->chroma_sample_location == AVCHROMA_LOC_UNSPECIFIED) { + enc_ctx->chroma_sample_location = frame->chroma_location; + } else if (enc_ctx->chroma_sample_location != frame->chroma_location && + frame->chroma_location != AVCHROMA_LOC_UNSPECIFIED) { + av_log(e, AV_LOG_WARNING, + "Requested chroma sample location '%s' does not match the " + "frame tagged sample location '%s'; result may be incorrect.\n", + av_chroma_location_name(enc_ctx->chroma_sample_location), + av_chroma_location_name(frame->chroma_location)); + } if (enc_ctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) || (frame->flags & AV_FRAME_FLAG_INTERLACED) @@ -312,42 +334,31 @@ int enc_open(void *opaque, const AVFrame *frame) enc_ctx->flags |= AV_CODEC_FLAG_FRAME_DURATION; - ret = hw_device_setup_for_encode(ost, frame ? frame->hw_frames_ctx : NULL); + ret = hw_device_setup_for_encode(e, enc_ctx, frame ? frame->hw_frames_ctx : NULL); if (ret < 0) { - av_log(ost, AV_LOG_ERROR, + av_log(e, AV_LOG_ERROR, "Encoding hardware device setup failed: %s\n", av_err2str(ret)); return ret; } - if ((ret = avcodec_open2(ost->enc_ctx, enc, NULL)) < 0) { + if ((ret = avcodec_open2(enc_ctx, enc, NULL)) < 0) { if (ret != AVERROR_EXPERIMENTAL) - av_log(ost, AV_LOG_ERROR, "Error while opening encoder - maybe " + av_log(e, AV_LOG_ERROR, "Error while opening encoder - maybe " "incorrect parameters such as bit_rate, rate, width or height.\n"); return ret; } - e->opened = 1; + ep->opened = 1; - if (ost->enc_ctx->frame_size) - frame_samples = ost->enc_ctx->frame_size; + if (enc_ctx->frame_size) + frame_samples = enc_ctx->frame_size; - if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000 && - ost->enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */) - av_log(ost, AV_LOG_WARNING, "The bitrate parameter is set too low." + if (enc_ctx->bit_rate && enc_ctx->bit_rate < 1000 && + enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */) + av_log(e, AV_LOG_WARNING, "The bitrate parameter is set too low." " It takes bits/s as argument, not kbits/s\n"); - ret = avcodec_parameters_from_context(ost->par_in, ost->enc_ctx); - if (ret < 0) { - av_log(ost, AV_LOG_FATAL, - "Error initializing the output stream codec context.\n"); - return ret; - } - - // copy timebase while removing common factors - if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0) - ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1}); - - ret = of_stream_init(of, ost); + ret = of_stream_init(of, ost, enc_ctx); if (ret < 0) return ret; @@ -369,19 +380,20 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle * AVPacket *pkt) { Encoder *e = ost->enc; + EncoderPriv *ep = ep_from_enc(e); int subtitle_out_max_size = 1024 * 1024; int subtitle_out_size, nb, i, ret; AVCodecContext *enc; int64_t pts; if (sub->pts == AV_NOPTS_VALUE) { - av_log(ost, AV_LOG_ERROR, "Subtitle packets must have a pts\n"); + av_log(e, AV_LOG_ERROR, "Subtitle packets must have a pts\n"); return exit_on_error ? AVERROR(EINVAL) : 0; } if ((of->start_time != AV_NOPTS_VALUE && sub->pts < of->start_time)) return 0; - enc = ost->enc_ctx; + enc = e->enc_ctx; /* Note: DVB subtitle need one packet to draw them and one other packet to clear them */ @@ -420,11 +432,11 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle * local_sub.rects += i; } - ost->frames_encoded++; + e->frames_encoded++; subtitle_out_size = avcodec_encode_subtitle(enc, pkt->data, pkt->size, &local_sub); if (subtitle_out_size < 0) { - av_log(ost, AV_LOG_FATAL, "Subtitle encoding failed\n"); + av_log(e, AV_LOG_FATAL, "Subtitle encoding failed\n"); return subtitle_out_size; } @@ -442,7 +454,7 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle * } pkt->dts = pkt->pts; - ret = sch_enc_send(e->sch, e->sch_idx, pkt); + ret = sch_enc_send(ep->sch, ep->sch_idx, pkt); if (ret < 0) { av_packet_unref(pkt); return ret; @@ -457,6 +469,7 @@ void enc_stats_write(OutputStream *ost, EncStats *es, uint64_t frame_num) { Encoder *e = ost->enc; + EncoderPriv *ep = ep_from_enc(e); AVIOContext *io = es->io; AVRational tb = frame ? frame->time_base : pkt->time_base; int64_t pts = frame ? frame->pts : pkt->pts; @@ -494,7 +507,7 @@ void enc_stats_write(OutputStream *ost, EncStats *es, if (frame) { switch (c->type) { - case ENC_STATS_SAMPLE_NUM: avio_printf(io, "%"PRIu64, ost->samples_encoded); continue; + case ENC_STATS_SAMPLE_NUM: avio_printf(io, "%"PRIu64, e->samples_encoded); continue; case ENC_STATS_NB_SAMPLES: avio_printf(io, "%d", frame->nb_samples); continue; default: av_assert0(0); } @@ -512,7 +525,7 @@ void enc_stats_write(OutputStream *ost, EncStats *es, } case ENC_STATS_AVG_BITRATE: { double duration = pkt->dts * av_q2d(tb); - avio_printf(io, "%g", duration > 0 ? 8.0 * e->data_size / duration : -1.); + avio_printf(io, "%g", duration > 0 ? 8.0 * ep->data_size / duration : -1.); continue; } default: av_assert0(0); @@ -533,9 +546,10 @@ static inline double psnr(double d) static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_vstats) { Encoder *e = ost->enc; + EncoderPriv *ep = ep_from_enc(e); const uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, NULL); - AVCodecContext *enc = ost->enc_ctx; + AVCodecContext *enc = e->enc_ctx; enum AVPictureType pict_type; int64_t frame_number; double ti1, bitrate, avg_bitrate; @@ -566,7 +580,7 @@ static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_ } } - frame_number = e->packets_encoded; + frame_number = ep->packets_encoded; if (vstats_version <= 1) { fprintf(vstats_file, "frame= %5"PRId64" q= %2.1f ", frame_number, quality / (float)FF_QP2LAMBDA); @@ -586,9 +600,9 @@ static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_ ti1 = 0.01; bitrate = (pkt->size * 8) / av_q2d(enc->time_base) / 1000.0; - avg_bitrate = (double)(e->data_size * 8) / ti1 / 1000.0; + avg_bitrate = (double)(ep->data_size * 8) / ti1 / 1000.0; fprintf(vstats_file, "s_size= %8.0fKiB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", - (double)e->data_size / 1024, ti1, bitrate, avg_bitrate); + (double)ep->data_size / 1024, ti1, bitrate, avg_bitrate); fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(pict_type)); return 0; @@ -598,7 +612,8 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, AVPacket *pkt) { Encoder *e = ost->enc; - AVCodecContext *enc = ost->enc_ctx; + EncoderPriv *ep = ep_from_enc(e); + AVCodecContext *enc = e->enc_ctx; const char *type_desc = av_get_media_type_string(enc->codec_type); const char *action = frame ? "encode" : "flush"; int ret; @@ -613,13 +628,13 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, if (ost->enc_stats_pre.io) enc_stats_write(ost, &ost->enc_stats_pre, frame, NULL, - ost->frames_encoded); + e->frames_encoded); - ost->frames_encoded++; - ost->samples_encoded += frame->nb_samples; + e->frames_encoded++; + e->samples_encoded += frame->nb_samples; if (debug_ts) { - av_log(ost, AV_LOG_INFO, "encoder <- type:%s " + av_log(e, AV_LOG_INFO, "encoder <- type:%s " "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n", type_desc, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base), @@ -634,7 +649,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, ret = avcodec_send_frame(enc, frame); if (ret < 0 && !(ret == AVERROR_EOF && !frame)) { - av_log(ost, AV_LOG_ERROR, "Error submitting %s frame to the encoder\n", + av_log(e, AV_LOG_ERROR, "Error submitting %s frame to the encoder\n", type_desc); return ret; } @@ -659,7 +674,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, return 0; } else if (ret < 0) { if (ret != AVERROR_EOF) - av_log(ost, AV_LOG_ERROR, "%s encoding failed\n", type_desc); + av_log(e, AV_LOG_ERROR, "%s encoding failed\n", type_desc); return ret; } @@ -670,7 +685,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, // attach stream parameters to first packet if requested avcodec_parameters_free(&fd->par_enc); - if (e->attach_par && !e->packets_encoded) { + if (ep->attach_par && !ep->packets_encoded) { fd->par_enc = avcodec_parameters_alloc(); if (!fd->par_enc) return AVERROR(ENOMEM); @@ -690,10 +705,10 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, if (ost->enc_stats_post.io) enc_stats_write(ost, &ost->enc_stats_post, NULL, pkt, - e->packets_encoded); + ep->packets_encoded); if (debug_ts) { - av_log(ost, AV_LOG_INFO, "encoder -> type:%s " + av_log(e, AV_LOG_INFO, "encoder -> type:%s " "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " "duration:%s duration_time:%s\n", type_desc, @@ -702,18 +717,18 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base)); } - e->data_size += pkt->size; + ep->data_size += pkt->size; - e->packets_encoded++; + ep->packets_encoded++; - ret = sch_enc_send(e->sch, e->sch_idx, pkt); + ret = sch_enc_send(ep->sch, ep->sch_idx, pkt); if (ret < 0) { av_packet_unref(pkt); return ret; } } - av_assert0(0); + av_unreachable("encode_frame() loop should return"); } static enum AVPictureType forced_kf_apply(void *logctx, KeyframeForceCtx *kf, @@ -753,6 +768,9 @@ static enum AVPictureType forced_kf_apply(void *logctx, KeyframeForceCtx *kf, } } else if (kf->type == KF_FORCE_SOURCE && (frame->flags & AV_FRAME_FLAG_KEY)) { goto force_keyframe; + } else if (kf->type == KF_FORCE_SCD_METADATA && + av_dict_get(frame->metadata, "lavfi.scd.time", NULL, 0)) { + goto force_keyframe; } return AV_PICTURE_TYPE_NONE; @@ -764,6 +782,7 @@ force_keyframe: static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt) { + Encoder *e = ost->enc; OutputFile *of = ost->file; enum AVMediaType type = ost->type; @@ -781,8 +800,8 @@ static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt) return AVERROR_EOF; if (type == AVMEDIA_TYPE_VIDEO) { - frame->quality = ost->enc_ctx->global_quality; - frame->pict_type = forced_kf_apply(ost, &ost->kf, frame); + frame->quality = e->enc_ctx->global_quality; + frame->pict_type = forced_kf_apply(e, &ost->kf, frame); #if FFMPEG_OPT_TOP if (ost->top_field_first >= 0) { @@ -791,9 +810,9 @@ static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt) } #endif } else { - if (!(ost->enc_ctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) && - ost->enc_ctx->ch_layout.nb_channels != frame->ch_layout.nb_channels) { - av_log(ost, AV_LOG_ERROR, + if (!(e->enc_ctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) && + e->enc_ctx->ch_layout.nb_channels != frame->ch_layout.nb_channels) { + av_log(e, AV_LOG_ERROR, "Audio channel count changed and encoder does not support parameter changes\n"); return 0; } @@ -807,7 +826,7 @@ static void enc_thread_set_name(const OutputStream *ost) { char name[16]; snprintf(name, sizeof(name), "enc%d:%d:%s", ost->file->index, ost->index, - ost->enc_ctx->codec->name); + ost->enc->enc_ctx->codec->name); ff_thread_setname(name); } @@ -842,6 +861,7 @@ int encoder_thread(void *arg) { OutputStream *ost = arg; Encoder *e = ost->enc; + EncoderPriv *ep = ep_from_enc(e); EncoderThread et; int ret = 0, input_status = 0; int name_set = 0; @@ -864,17 +884,17 @@ int encoder_thread(void *arg) } while (!input_status) { - input_status = sch_enc_receive(e->sch, e->sch_idx, et.frame); + input_status = sch_enc_receive(ep->sch, ep->sch_idx, et.frame); if (input_status < 0) { if (input_status == AVERROR_EOF) { - av_log(ost, AV_LOG_VERBOSE, "Encoder thread received EOF\n"); - if (e->opened) + av_log(e, AV_LOG_VERBOSE, "Encoder thread received EOF\n"); + if (ep->opened) break; - av_log(ost, AV_LOG_ERROR, "Could not open encoder before EOF\n"); + av_log(e, AV_LOG_ERROR, "Could not open encoder before EOF\n"); ret = AVERROR(EINVAL); } else { - av_log(ost, AV_LOG_ERROR, "Error receiving a frame for encoding: %s\n", + av_log(e, AV_LOG_ERROR, "Error receiving a frame for encoding: %s\n", av_err2str(ret)); ret = input_status; } @@ -893,9 +913,9 @@ int encoder_thread(void *arg) if (ret < 0) { if (ret == AVERROR_EOF) - av_log(ost, AV_LOG_VERBOSE, "Encoder returned EOF, finishing\n"); + av_log(e, AV_LOG_VERBOSE, "Encoder returned EOF, finishing\n"); else - av_log(ost, AV_LOG_ERROR, "Error encoding a frame: %s\n", + av_log(e, AV_LOG_ERROR, "Error encoding a frame: %s\n", av_err2str(ret)); break; } @@ -905,7 +925,7 @@ int encoder_thread(void *arg) if (ret == 0 || ret == AVERROR_EOF) { ret = frame_encode(ost, NULL, et.pkt); if (ret < 0 && ret != AVERROR_EOF) - av_log(ost, AV_LOG_ERROR, "Error flushing encoder: %s\n", + av_log(e, AV_LOG_ERROR, "Error flushing encoder: %s\n", av_err2str(ret)); } @@ -921,6 +941,7 @@ finish: int enc_loopback(Encoder *enc) { - enc->attach_par = 1; - return enc->sch_idx; + EncoderPriv *ep = ep_from_enc(enc); + ep->attach_par = 1; + return ep->sch_idx; } diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 4eec8fed7..765b65d0e 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -21,6 +21,7 @@ #include #include "ffmpeg.h" +#include "graph/graphprint.h" #include "libavfilter/avfilter.h" #include "libavfilter/buffersink.h" @@ -30,6 +31,7 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" +#include "libavutil/downmix_info.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -38,9 +40,6 @@ #include "libavutil/time.h" #include "libavutil/timestamp.h" -// FIXME private header, used for mid_pred() -#include "libavcodec/mathops.h" - typedef struct FilterGraphPriv { FilterGraph fg; @@ -57,9 +56,7 @@ typedef struct FilterGraphPriv { unsigned nb_outputs_done; - const char *graph_desc; - - char *nb_threads; + int nb_threads; // frame for temporarily holding output from the filtergraph AVFrame *frame; @@ -106,25 +103,20 @@ typedef struct InputFilterPriv { InputFilterOptions opts; - int index; - - AVFilterContext *filter; - // used to hold submitted input AVFrame *frame; - /* for filters that are not yet bound to an input stream, - * this stores the input linklabel, if any */ - uint8_t *linklabel; + // For inputs bound to a filtergraph output + OutputFilter *ofilter_src; - // filter data type - enum AVMediaType type; // source data type: AVMEDIA_TYPE_SUBTITLE for sub2video, // same as type otherwise enum AVMediaType type_src; int eof; int bound; + int drop_warned; + uint64_t nb_dropped; // parameters configured for this input int format; @@ -133,12 +125,16 @@ typedef struct InputFilterPriv { AVRational sample_aspect_ratio; enum AVColorSpace color_space; enum AVColorRange color_range; + enum AVAlphaMode alpha_mode; int sample_rate; AVChannelLayout ch_layout; AVRational time_base; + AVFrameSideData **side_data; + int nb_side_data; + AVFifo *frame_queue; AVBufferRef *hw_frames_ctx; @@ -147,13 +143,16 @@ typedef struct InputFilterPriv { int displaymatrix_applied; int32_t displaymatrix[9]; + int downmixinfo_present; + AVDownmixInfo downmixinfo; + struct { AVFrame *frame; int64_t last_pts; int64_t end_pts; - ///< marks if sub2video_update should force an initialization + /// marks if sub2video_update should force an initialization unsigned int initialize; } sub2video; } InputFilterPriv; @@ -188,14 +187,10 @@ typedef struct FPSConvContext { typedef struct OutputFilterPriv { OutputFilter ofilter; - int index; - void *log_parent; char log_name[32]; - char *name; - - AVFilterContext *filter; + int needed; /* desired output stream properties */ int format; @@ -204,6 +199,15 @@ typedef struct OutputFilterPriv { AVChannelLayout ch_layout; enum AVColorSpace color_space; enum AVColorRange color_range; + enum AVAlphaMode alpha_mode; + + unsigned crop_top; + unsigned crop_bottom; + unsigned crop_left; + unsigned crop_right; + + AVFrameSideData **side_data; + int nb_side_data; // time base in which the output is sent to our downstream // does not need to match the filtersink's timebase @@ -219,11 +223,17 @@ typedef struct OutputFilterPriv { // those are only set if no format is specified and the encoder gives us multiple options // They point directly to the relevant lists of the encoder. - const int *formats; + union { + const enum AVPixelFormat *pix_fmts; + const enum AVSampleFormat *sample_fmts; + }; const AVChannelLayout *ch_layouts; const int *sample_rates; const enum AVColorSpace *color_spaces; const enum AVColorRange *color_ranges; + const enum AVAlphaMode *alpha_modes; + + int32_t displaymatrix[9]; AVRational enc_timebase; int64_t trim_start_us; @@ -273,6 +283,7 @@ static int sub2video_get_blank_frame(InputFilterPriv *ifp) frame->format = ifp->format; frame->colorspace = ifp->color_space; frame->color_range = ifp->color_range; + frame->alpha_mode = ifp->alpha_mode; ret = av_frame_get_buffer(frame, 0); if (ret < 0) @@ -321,11 +332,12 @@ static void sub2video_push_ref(InputFilterPriv *ifp, int64_t pts) av_assert1(frame->data[0]); ifp->sub2video.last_pts = frame->pts = pts; - ret = av_buffersrc_add_frame_flags(ifp->filter, frame, + ret = av_buffersrc_add_frame_flags(ifp->ifilter.filter, frame, AV_BUFFERSRC_FLAG_KEEP_REF | AV_BUFFERSRC_FLAG_PUSH); if (ret != AVERROR_EOF && ret < 0) - av_log(NULL, AV_LOG_WARNING, "Error while add the frame to buffer source(%s).\n", + av_log(ifp->ifilter.graph, AV_LOG_WARNING, + "Error while add the frame to buffer source(%s).\n", av_err2str(ret)); } @@ -355,7 +367,7 @@ static void sub2video_update(InputFilterPriv *ifp, int64_t heartbeat_pts, num_rects = 0; } if (sub2video_get_blank_frame(ifp) < 0) { - av_log(NULL, AV_LOG_ERROR, + av_log(ifp->ifilter.graph, AV_LOG_ERROR, "Impossible to get a blank canvas.\n"); return; } @@ -390,10 +402,10 @@ static void choose_ ## name (OutputFilterPriv *ofp, AVBPrint *bprint) \ av_bprint_chars(bprint, ':', 1); \ } -DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, formats, +DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, pix_fmts, AV_PIX_FMT_NONE, "%s", av_get_pix_fmt_name) -DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats, +DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, sample_fmts, AV_SAMPLE_FMT_NONE, "%s", av_get_sample_fmt_name) DEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0, @@ -405,6 +417,9 @@ DEF_CHOOSE_FORMAT(color_spaces, enum AVColorSpace, color_space, color_spaces, DEF_CHOOSE_FORMAT(color_ranges, enum AVColorRange, color_range, color_ranges, AVCOL_RANGE_UNSPECIFIED, "%s", av_color_range_name); +DEF_CHOOSE_FORMAT(alpha_modes, enum AVAlphaMode, alpha_mode, alpha_modes, + AVALPHA_MODE_UNSPECIFIED, "%s", av_alpha_mode_name); + static void choose_channel_layouts(OutputFilterPriv *ofp, AVBPrint *bprint) { if (av_channel_layout_check(&ofp->ch_layout)) { @@ -425,7 +440,8 @@ static void choose_channel_layouts(OutputFilterPriv *ofp, AVBPrint *bprint) av_bprint_chars(bprint, ':', 1); } -static int read_binary(const char *path, uint8_t **data, int *len) +static int read_binary(void *logctx, const char *path, + uint8_t **data, int *len) { AVIOContext *io = NULL; int64_t fsize; @@ -436,14 +452,14 @@ static int read_binary(const char *path, uint8_t **data, int *len) ret = avio_open2(&io, path, AVIO_FLAG_READ, &int_cb, NULL); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot open file '%s': %s\n", + av_log(logctx, AV_LOG_ERROR, "Cannot open file '%s': %s\n", path, av_err2str(ret)); return ret; } fsize = avio_size(io); if (fsize < 0 || fsize > INT_MAX) { - av_log(NULL, AV_LOG_ERROR, "Cannot obtain size of file %s\n", path); + av_log(logctx, AV_LOG_ERROR, "Cannot obtain size of file %s\n", path); ret = AVERROR(EIO); goto fail; } @@ -456,7 +472,7 @@ static int read_binary(const char *path, uint8_t **data, int *len) ret = avio_read(io, *data, fsize); if (ret != fsize) { - av_log(NULL, AV_LOG_ERROR, "Error reading file %s\n", path); + av_log(logctx, AV_LOG_ERROR, "Error reading file %s\n", path); ret = ret < 0 ? ret : AVERROR(EIO); goto fail; } @@ -473,7 +489,8 @@ fail: return ret; } -static int filter_opt_apply(AVFilterContext *f, const char *key, const char *val) +static int filter_opt_apply(void *logctx, AVFilterContext *f, + const char *key, const char *val) { const AVOption *o = NULL; int ret; @@ -495,14 +512,14 @@ static int filter_opt_apply(AVFilterContext *f, const char *key, const char *val uint8_t *data; int len; - ret = read_binary(val, &data, &len); + ret = read_binary(logctx, val, &data, &len); if (ret < 0) goto err_load; ret = av_opt_set_bin(f, key, data, len, AV_OPT_SEARCH_CHILDREN); av_freep(&data); } else { - char *data = file_read(val); + char *data = read_file_to_string(val); if (!data) { ret = AVERROR(EIO); goto err_load; @@ -517,18 +534,18 @@ static int filter_opt_apply(AVFilterContext *f, const char *key, const char *val return 0; err_apply: - av_log(NULL, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Error applying option '%s' to filter '%s': %s\n", key, f->filter->name, av_err2str(ret)); return ret; err_load: - av_log(NULL, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Error loading value for option '%s' from file '%s'\n", key, val); return ret; } -static int graph_opts_apply(AVFilterGraphSegment *seg) +static int graph_opts_apply(void *logctx, AVFilterGraphSegment *seg) { for (size_t i = 0; i < seg->nb_chains; i++) { AVFilterChain *ch = seg->chains[i]; @@ -540,7 +557,7 @@ static int graph_opts_apply(AVFilterGraphSegment *seg) av_assert0(p->filter); while ((e = av_dict_iterate(p->opts, e))) { - int ret = filter_opt_apply(p->filter, e->key, e->value); + int ret = filter_opt_apply(logctx, p->filter, e->key, e->value); if (ret < 0) return ret; } @@ -552,7 +569,8 @@ static int graph_opts_apply(AVFilterGraphSegment *seg) return 0; } -static int graph_parse(AVFilterGraph *graph, const char *desc, +static int graph_parse(void *logctx, + AVFilterGraph *graph, const char *desc, AVFilterInOut **inputs, AVFilterInOut **outputs, AVBufferRef *hw_device) { @@ -584,7 +602,7 @@ static int graph_parse(AVFilterGraph *graph, const char *desc, } } - ret = graph_opts_apply(seg); + ret = graph_opts_apply(logctx, seg); if (ret < 0) goto fail; @@ -651,10 +669,11 @@ static OutputFilter *ofilter_alloc(FilterGraph *fg, enum AVMediaType type) ofp->format = -1; ofp->color_space = AVCOL_SPC_UNSPECIFIED; ofp->color_range = AVCOL_RANGE_UNSPECIFIED; - ofp->index = fg->nb_outputs - 1; + ofp->alpha_mode = AVALPHA_MODE_UNSPECIFIED; + ofilter->index = fg->nb_outputs - 1; snprintf(ofp->log_name, sizeof(ofp->log_name), "%co%d", - av_get_media_type_string(type)[0], ofp->index); + av_get_media_type_string(type)[0], ofilter->index); return ofilter; } @@ -670,10 +689,10 @@ static int ifilter_bind_ist(InputFilter *ifilter, InputStream *ist, av_assert0(!ifp->bound); ifp->bound = 1; - if (ifp->type != ist->par->codec_type && - !(ifp->type == AVMEDIA_TYPE_VIDEO && ist->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) { + if (ifilter->type != ist->par->codec_type && + !(ifilter->type == AVMEDIA_TYPE_VIDEO && ist->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) { av_log(fgp, AV_LOG_ERROR, "Tried to connect %s stream to %s filtergraph input\n", - av_get_media_type_string(ist->par->codec_type), av_get_media_type_string(ifp->type)); + av_get_media_type_string(ist->par->codec_type), av_get_media_type_string(ifilter->type)); return AVERROR(EINVAL); } @@ -688,8 +707,12 @@ static int ifilter_bind_ist(InputFilter *ifilter, InputStream *ist, if (ret < 0) return ret; + ifilter->input_name = av_strdup(ifp->opts.name); + if (!ifilter->input_name) + return AVERROR(EINVAL); + ret = sch_connect(fgp->sch, - src, SCH_FILTER_IN(fgp->sch_idx, ifp->index)); + src, SCH_FILTER_IN(fgp->sch_idx, ifilter->index)); if (ret < 0) return ret; @@ -724,19 +747,23 @@ static int ifilter_bind_dec(InputFilterPriv *ifp, Decoder *dec, av_assert0(!ifp->bound); ifp->bound = 1; - if (ifp->type != dec->type) { + if (ifp->ifilter.type != dec->type) { av_log(fgp, AV_LOG_ERROR, "Tried to connect %s decoder to %s filtergraph input\n", - av_get_media_type_string(dec->type), av_get_media_type_string(ifp->type)); + av_get_media_type_string(dec->type), av_get_media_type_string(ifp->ifilter.type)); return AVERROR(EINVAL); } - ifp->type_src = ifp->type; + ifp->type_src = ifp->ifilter.type; ret = dec_filter_add(dec, &ifp->ifilter, &ifp->opts, vs, &src); if (ret < 0) return ret; - ret = sch_connect(fgp->sch, src, SCH_FILTER_IN(fgp->sch_idx, ifp->index)); + ifp->ifilter.input_name = av_strdup(ifp->opts.name); + if (!ifp->ifilter.input_name) + return AVERROR(EINVAL); + + ret = sch_connect(fgp->sch, src, SCH_FILTER_IN(fgp->sch_idx, ifp->ifilter.index)); if (ret < 0) return ret; @@ -783,8 +810,7 @@ static int set_channel_layout(OutputFilterPriv *f, const AVChannelLayout *layout return 0; } -int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, - unsigned sched_idx_enc, +int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc, const OutputFilterOptions *opts) { OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); @@ -793,20 +819,21 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, int ret; av_assert0(!ofilter->bound); - av_assert0(ofilter->type == ost->type); + av_assert0(!opts->enc || + ofilter->type == opts->enc->type); - ofilter->bound = 1; + ofp->needed = ofilter->bound = 1; av_freep(&ofilter->linklabel); - ofp->flags = opts->flags; + ofp->flags |= opts->flags; ofp->ts_offset = opts->ts_offset; ofp->enc_timebase = opts->output_tb; ofp->trim_start_us = opts->trim_start_us; ofp->trim_duration_us = opts->trim_duration_us; - ofp->name = av_strdup(opts->name); - if (!ofp->name) + ofilter->output_name = av_strdup(opts->name); + if (!ofilter->output_name) return AVERROR(EINVAL); ret = av_dict_copy(&ofp->sws_opts, opts->sws_opts, 0); @@ -826,7 +853,7 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, ofp->log_parent = NULL; av_strlcpy(ofp->log_name, fgp->log_name, sizeof(ofp->log_name)); } else - av_strlcatf(ofp->log_name, sizeof(ofp->log_name), "->%s", ofp->name); + av_strlcatf(ofp->log_name, sizeof(ofp->log_name), "->%s", ofilter->output_name); switch (ofilter->type) { case AVMEDIA_TYPE_VIDEO: @@ -835,7 +862,7 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, if (opts->format != AV_PIX_FMT_NONE) { ofp->format = opts->format; } else - ofp->formats = opts->formats; + ofp->pix_fmts = opts->pix_fmts; if (opts->color_space != AVCOL_SPC_UNSPECIFIED) ofp->color_space = opts->color_space; @@ -847,6 +874,11 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, else ofp->color_ranges = opts->color_ranges; + if (opts->alpha_mode != AVALPHA_MODE_UNSPECIFIED) + ofp->alpha_mode = opts->alpha_mode; + else + ofp->alpha_modes = opts->alpha_modes; + fgp->disable_conversions |= !!(ofp->flags & OFILTER_FLAG_DISABLE_CONVERT); ofp->fps.last_frame = av_frame_alloc(); @@ -854,10 +886,9 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, return AVERROR(ENOMEM); ofp->fps.vsync_method = opts->vsync_method; - ofp->fps.framerate = ost->frame_rate; - ofp->fps.framerate_max = ost->max_frame_rate; - ofp->fps.framerate_supported = ost->force_fps || !opts->enc ? - NULL : opts->frame_rates; + ofp->fps.framerate = opts->frame_rate; + ofp->fps.framerate_max = opts->max_frame_rate; + ofp->fps.framerate_supported = opts->frame_rates; // reduce frame rate for mpeg4 to be within the spec limits if (opts->enc && opts->enc->id == AV_CODEC_ID_MPEG4) @@ -870,7 +901,7 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, if (opts->format != AV_SAMPLE_FMT_NONE) { ofp->format = opts->format; } else { - ofp->formats = opts->formats; + ofp->sample_fmts = opts->sample_fmts; } if (opts->sample_rate) { ofp->sample_rate = opts->sample_rate; @@ -886,7 +917,7 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, break; } - ret = sch_connect(fgp->sch, SCH_FILTER_OUT(fgp->sch_idx, ofp->index), + ret = sch_connect(fgp->sch, SCH_FILTER_OUT(fgp->sch_idx, ofilter->index), SCH_ENC(sched_idx_enc)); if (ret < 0) return ret; @@ -900,16 +931,18 @@ static int ofilter_bind_ifilter(OutputFilter *ofilter, InputFilterPriv *ifp, OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); av_assert0(!ofilter->bound); - av_assert0(ofilter->type == ifp->type); + av_assert0(ofilter->type == ifp->ifilter.type); - ofilter->bound = 1; + ofp->needed = ofilter->bound = 1; av_freep(&ofilter->linklabel); - ofp->name = av_strdup(opts->name); - if (!ofp->name) + ofilter->output_name = av_strdup(opts->name); + if (!ofilter->output_name) return AVERROR(EINVAL); - av_strlcatf(ofp->log_name, sizeof(ofp->log_name), "->%s", ofp->name); + ifp->ofilter_src = ofilter; + + av_strlcatf(ofp->log_name, sizeof(ofp->log_name), "->%s", ofilter->output_name); return 0; } @@ -925,18 +958,18 @@ static int ifilter_bind_fg(InputFilterPriv *ifp, FilterGraph *fg_src, int out_id av_assert0(!ifp->bound); ifp->bound = 1; - if (ifp->type != ofilter_src->type) { + if (ifp->ifilter.type != ofilter_src->type) { av_log(fgp, AV_LOG_ERROR, "Tried to connect %s output to %s input\n", av_get_media_type_string(ofilter_src->type), - av_get_media_type_string(ifp->type)); + av_get_media_type_string(ifp->ifilter.type)); return AVERROR(EINVAL); } - ifp->type_src = ifp->type; + ifp->type_src = ifp->ifilter.type; memset(&opts, 0, sizeof(opts)); - snprintf(name, sizeof(name), "fg:%d:%d", fgp->fg.index, ifp->index); + snprintf(name, sizeof(name), "fg:%d:%d", fgp->fg.index, ifp->ifilter.index); opts.name = name; ret = ofilter_bind_ifilter(ofilter_src, ifp, &opts); @@ -944,7 +977,7 @@ static int ifilter_bind_fg(InputFilterPriv *ifp, FilterGraph *fg_src, int out_id return ret; ret = sch_connect(fgp->sch, SCH_FILTER_OUT(fg_src->index, out_idx), - SCH_FILTER_IN(fgp->sch_idx, ifp->index)); + SCH_FILTER_IN(fgp->sch_idx, ifp->ifilter.index)); if (ret < 0) return ret; @@ -967,10 +1000,11 @@ static InputFilter *ifilter_alloc(FilterGraph *fg) if (!ifp->frame) return NULL; - ifp->index = fg->nb_inputs - 1; + ifilter->index = fg->nb_inputs - 1; ifp->format = -1; ifp->color_space = AVCOL_SPC_UNSPECIFIED; ifp->color_range = AVCOL_RANGE_UNSPECIFIED; + ifp->alpha_mode = AVALPHA_MODE_UNSPECIFIED; ifp->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW); if (!ifp->frame_queue) @@ -1004,9 +1038,11 @@ void fg_free(FilterGraph **pfg) av_frame_free(&ifp->opts.fallback); av_buffer_unref(&ifp->hw_frames_ctx); - av_freep(&ifp->linklabel); + av_freep(&ifilter->linklabel); av_freep(&ifp->opts.name); + av_frame_side_data_free(&ifp->side_data, &ifp->nb_side_data); av_freep(&ifilter->name); + av_freep(&ifilter->input_name); av_freep(&fg->inputs[j]); } av_freep(&fg->inputs); @@ -1020,14 +1056,14 @@ void fg_free(FilterGraph **pfg) av_freep(&ofilter->linklabel); av_freep(&ofilter->name); + av_freep(&ofilter->output_name); av_freep(&ofilter->apad); - av_freep(&ofp->name); av_channel_layout_uninit(&ofp->ch_layout); + av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data); av_freep(&fg->outputs[j]); } av_freep(&fg->outputs); - av_freep(&fgp->graph_desc); - av_freep(&fgp->nb_threads); + av_freep(&fg->graph_desc); av_frame_free(&fgp->frame); av_frame_free(&fgp->frame_enc); @@ -1049,7 +1085,8 @@ static const AVClass fg_class = { .category = AV_CLASS_CATEGORY_FILTER, }; -int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) +int fg_create(FilterGraph **pfg, char **graph_desc, Scheduler *sch, + const OutputFilterOptions *opts) { FilterGraphPriv *fgp; FilterGraph *fg; @@ -1059,8 +1096,10 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) int ret = 0; fgp = av_mallocz(sizeof(*fgp)); - if (!fgp) + if (!fgp) { + av_freep(graph_desc); return AVERROR(ENOMEM); + } fg = &fgp->fg; if (pfg) { @@ -1069,6 +1108,7 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) } else { ret = av_dynarray_add_nofree(&filtergraphs, &nb_filtergraphs, fgp); if (ret < 0) { + av_freep(graph_desc); av_freep(&fgp); return ret; } @@ -1077,10 +1117,13 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) } fg->class = &fg_class; - fgp->graph_desc = graph_desc; + fg->graph_desc = *graph_desc; fgp->disable_conversions = !auto_conversion_filters; + fgp->nb_threads = -1; fgp->sch = sch; + *graph_desc = NULL; + snprintf(fgp->log_name, sizeof(fgp->log_name), "fc#%d", fg->index); fgp->frame = av_frame_alloc(); @@ -1095,7 +1138,8 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) return AVERROR(ENOMEM);; graph->nb_threads = 1; - ret = graph_parse(graph, fgp->graph_desc, &inputs, &outputs, NULL); + ret = graph_parse(fg, graph, fg->graph_desc, &inputs, &outputs, + hw_device_for_filter()); if (ret < 0) goto fail; @@ -1111,21 +1155,19 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) for (AVFilterInOut *cur = inputs; cur; cur = cur->next) { InputFilter *const ifilter = ifilter_alloc(fg); - InputFilterPriv *ifp; if (!ifilter) { ret = AVERROR(ENOMEM); goto fail; } - ifp = ifp_from_ifilter(ifilter); - ifp->linklabel = cur->name; + ifilter->linklabel = cur->name; cur->name = NULL; - ifp->type = avfilter_pad_get_type(cur->filter_ctx->input_pads, + ifilter->type = avfilter_pad_get_type(cur->filter_ctx->input_pads, cur->pad_idx); - if (ifp->type != AVMEDIA_TYPE_VIDEO && ifp->type != AVMEDIA_TYPE_AUDIO) { + if (ifilter->type != AVMEDIA_TYPE_VIDEO && ifilter->type != AVMEDIA_TYPE_AUDIO) { av_log(fg, AV_LOG_FATAL, "Only video and audio filters supported " "currently.\n"); ret = AVERROR(ENOSYS); @@ -1143,11 +1185,13 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) const enum AVMediaType type = avfilter_pad_get_type(cur->filter_ctx->output_pads, cur->pad_idx); OutputFilter *const ofilter = ofilter_alloc(fg, type); + OutputFilterPriv *ofp; if (!ofilter) { ret = AVERROR(ENOMEM); goto fail; } + ofp = ofp_from_ofilter(ofilter); ofilter->linklabel = cur->name; cur->name = NULL; @@ -1157,6 +1201,25 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) ret = AVERROR(ENOMEM); goto fail; } + + // opts should only be needed in this function to fill fields from filtergraphs + // whose output is meant to be treated as if it was stream, e.g. merged HEIF + // tile groups. + if (opts) { + ofp->flags = opts->flags; + ofp->side_data = opts->side_data; + ofp->nb_side_data = opts->nb_side_data; + + ofp->crop_top = opts->crop_top; + ofp->crop_bottom = opts->crop_bottom; + ofp->crop_left = opts->crop_left; + ofp->crop_right = opts->crop_right; + + const AVFrameSideData *sd = av_frame_side_data_get(ofp->side_data, ofp->nb_side_data, + AV_FRAME_DATA_DISPLAYMATRIX); + if (sd) + memcpy(ofp->displaymatrix, sd->data, sizeof(ofp->displaymatrix)); + } } if (!fg->nb_outputs) { @@ -1182,81 +1245,76 @@ fail: return 0; } -int init_simple_filtergraph(InputStream *ist, OutputStream *ost, - char *graph_desc, - Scheduler *sch, unsigned sched_idx_enc, - const OutputFilterOptions *opts) +int fg_create_simple(FilterGraph **pfg, + InputStream *ist, + char **graph_desc, + Scheduler *sch, unsigned sched_idx_enc, + const OutputFilterOptions *opts) { + const enum AVMediaType type = ist->par->codec_type; FilterGraph *fg; FilterGraphPriv *fgp; int ret; - ret = fg_create(&ost->fg_simple, graph_desc, sch); + ret = fg_create(pfg, graph_desc, sch, NULL); if (ret < 0) return ret; - fg = ost->fg_simple; + fg = *pfg; fgp = fgp_from_fg(fg); fgp->is_simple = 1; snprintf(fgp->log_name, sizeof(fgp->log_name), "%cf%s", - av_get_media_type_string(ost->type)[0], opts->name); + av_get_media_type_string(type)[0], opts->name); if (fg->nb_inputs != 1 || fg->nb_outputs != 1) { av_log(fg, AV_LOG_ERROR, "Simple filtergraph '%s' was expected " "to have exactly 1 input and 1 output. " "However, it had %d input(s) and %d output(s). Please adjust, " "or use a complex filtergraph (-filter_complex) instead.\n", - graph_desc, fg->nb_inputs, fg->nb_outputs); + *graph_desc, fg->nb_inputs, fg->nb_outputs); return AVERROR(EINVAL); } - if (fg->outputs[0]->type != ost->type) { + if (fg->outputs[0]->type != type) { av_log(fg, AV_LOG_ERROR, "Filtergraph has a %s output, cannot connect " "it to %s output stream\n", av_get_media_type_string(fg->outputs[0]->type), - av_get_media_type_string(ost->type)); + av_get_media_type_string(type)); return AVERROR(EINVAL); } - ost->filter = fg->outputs[0]; - ret = ifilter_bind_ist(fg->inputs[0], ist, opts->vs); if (ret < 0) return ret; - ret = ofilter_bind_ost(fg->outputs[0], ost, sched_idx_enc, opts); + ret = ofilter_bind_enc(fg->outputs[0], sched_idx_enc, opts); if (ret < 0) return ret; - if (opts->nb_threads) { - av_freep(&fgp->nb_threads); - fgp->nb_threads = av_strdup(opts->nb_threads); - if (!fgp->nb_threads) - return AVERROR(ENOMEM); - } + if (opts->nb_threads >= 0) + fgp->nb_threads = opts->nb_threads; return 0; } -static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) +static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter, int commit) { - FilterGraphPriv *fgp = fgp_from_fg(fg); InputFilterPriv *ifp = ifp_from_ifilter(ifilter); InputStream *ist = NULL; - enum AVMediaType type = ifp->type; + enum AVMediaType type = ifilter->type; ViewSpecifier vs = { .type = VIEW_SPECIFIER_TYPE_NONE }; const char *spec; char *p; int i, ret; - if (ifp->linklabel && !strncmp(ifp->linklabel, "dec:", 4)) { + if (ifilter->linklabel && !strncmp(ifilter->linklabel, "dec:", 4)) { // bind to a standalone decoder int dec_idx; - dec_idx = strtol(ifp->linklabel + 4, &p, 0); + dec_idx = strtol(ifilter->linklabel + 4, &p, 0); if (dec_idx < 0 || dec_idx >= nb_decoders) { av_log(fg, AV_LOG_ERROR, "Invalid decoder index %d in filtergraph description %s\n", - dec_idx, fgp->graph_desc); + dec_idx, fg->graph_desc); return AVERROR(EINVAL); } @@ -1272,7 +1330,7 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) av_log(fg, AV_LOG_ERROR, "Error binding a decoder to filtergraph input %s\n", ifilter->name); return ret; - } else if (ifp->linklabel) { + } else if (ifilter->linklabel) { StreamSpecifier ss; AVFormatContext *s; AVStream *st = NULL; @@ -1289,25 +1347,30 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) OutputFilter *ofilter = fg_src->outputs[j]; if (!ofilter->bound && ofilter->linklabel && - !strcmp(ofilter->linklabel, ifp->linklabel)) { - av_log(fg, AV_LOG_VERBOSE, - "Binding input with label '%s' to filtergraph output %d:%d\n", - ifp->linklabel, i, j); + !strcmp(ofilter->linklabel, ifilter->linklabel)) { + if (commit) { + av_log(fg, AV_LOG_VERBOSE, + "Binding input with label '%s' to filtergraph output %d:%d\n", + ifilter->linklabel, i, j); - ret = ifilter_bind_fg(ifp, fg_src, j); - if (ret < 0) - av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %s\n", - ifp->linklabel); - return ret; + ret = ifilter_bind_fg(ifp, fg_src, j); + if (ret < 0) { + av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %s\n", + ifilter->linklabel); + return ret; + } + } else + ofp_from_ofilter(ofilter)->needed = 1; + return 0; } } } // bind to an explicitly specified demuxer stream - file_idx = strtol(ifp->linklabel, &p, 0); + file_idx = strtol(ifilter->linklabel, &p, 0); if (file_idx < 0 || file_idx >= nb_input_files) { av_log(fg, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n", - file_idx, fgp->graph_desc); + file_idx, fg->graph_desc); return AVERROR(EINVAL); } s = input_files[file_idx]->ctx; @@ -1341,40 +1404,73 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) stream_specifier_uninit(&ss); if (!st) { av_log(fg, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s " - "matches no streams.\n", p, fgp->graph_desc); + "matches no streams.\n", p, fg->graph_desc); return AVERROR(EINVAL); } ist = input_files[file_idx]->streams[st->index]; - av_log(fg, AV_LOG_VERBOSE, - "Binding input with label '%s' to input stream %d:%d\n", - ifp->linklabel, ist->file->index, ist->index); + if (commit) + av_log(fg, AV_LOG_VERBOSE, + "Binding input with label '%s' to input stream %d:%d\n", + ifilter->linklabel, ist->file->index, ist->index); } else { + // try finding an unbound filtergraph output + for (int i = 0; i < nb_filtergraphs; i++) { + FilterGraph *fg_src = filtergraphs[i]; + + if (fg == fg_src) + continue; + + for (int j = 0; j < fg_src->nb_outputs; j++) { + OutputFilter *ofilter = fg_src->outputs[j]; + + if (!ofilter->bound) { + if (commit) { + av_log(fg, AV_LOG_VERBOSE, + "Binding unlabeled filtergraph input to filtergraph output %d:%d\n", i, j); + + ret = ifilter_bind_fg(ifp, fg_src, j); + if (ret < 0) { + av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %d:%d\n", i, j); + return ret; + } + } else + ofp_from_ofilter(ofilter)->needed = 1; + return 0; + } + } + } + ist = ist_find_unused(type); if (!ist) { - av_log(fg, AV_LOG_FATAL, "Cannot find a matching stream for " - "unlabeled input pad %s\n", ifilter->name); + av_log(fg, AV_LOG_FATAL, + "Cannot find an unused %s input stream to feed the " + "unlabeled input pad %s.\n", + av_get_media_type_string(type), ifilter->name); return AVERROR(EINVAL); } - av_log(fg, AV_LOG_VERBOSE, - "Binding unlabeled input %d to input stream %d:%d\n", - ifp->index, ist->file->index, ist->index); + if (commit) + av_log(fg, AV_LOG_VERBOSE, + "Binding unlabeled input %d to input stream %d:%d\n", + ifilter->index, ist->file->index, ist->index); } av_assert0(ist); - ret = ifilter_bind_ist(ifilter, ist, &vs); - if (ret < 0) { - av_log(fg, AV_LOG_ERROR, - "Error binding an input stream to complex filtergraph input %s.\n", - ifilter->name); - return ret; + if (commit) { + ret = ifilter_bind_ist(ifilter, ist, &vs); + if (ret < 0) { + av_log(fg, AV_LOG_ERROR, + "Error binding an input stream to complex filtergraph input %s.\n", + ifilter->name); + return ret; + } } return 0; } -static int bind_inputs(FilterGraph *fg) +static int bind_inputs(FilterGraph *fg, int commit) { // bind filtergraph inputs to input streams or other filtergraphs for (int i = 0; i < fg->nb_inputs; i++) { @@ -1384,7 +1480,7 @@ static int bind_inputs(FilterGraph *fg) if (ifp->bound) continue; - ret = fg_complex_bind_input(fg, &ifp->ifilter); + ret = fg_complex_bind_input(fg, &ifp->ifilter, commit); if (ret < 0) return ret; } @@ -1397,31 +1493,53 @@ int fg_finalise_bindings(void) int ret; for (int i = 0; i < nb_filtergraphs; i++) { - ret = bind_inputs(filtergraphs[i]); + ret = bind_inputs(filtergraphs[i], 0); if (ret < 0) return ret; } // check that all outputs were bound - for (int i = 0; i < nb_filtergraphs; i++) { + for (int i = nb_filtergraphs - 1; i >= 0; i--) { FilterGraph *fg = filtergraphs[i]; + FilterGraphPriv *fgp = fgp_from_fg(filtergraphs[i]); for (int j = 0; j < fg->nb_outputs; j++) { OutputFilter *output = fg->outputs[j]; - if (!output->bound) { - av_log(fg, AV_LOG_FATAL, - "Filter '%s' has output %d (%s) unconnected\n", + if (!ofp_from_ofilter(output)->needed) { + if (!fg->is_internal) { + av_log(fg, AV_LOG_FATAL, + "Filter '%s' has output %d (%s) unconnected\n", + output->name, j, + output->linklabel ? (const char *)output->linklabel : "unlabeled"); + return AVERROR(EINVAL); + } + + av_log(fg, AV_LOG_DEBUG, + "Internal filter '%s' has output %d (%s) unconnected. Removing graph\n", output->name, j, output->linklabel ? (const char *)output->linklabel : "unlabeled"); - return AVERROR(EINVAL); + sch_remove_filtergraph(fgp->sch, fgp->sch_idx); + fg_free(&filtergraphs[i]); + nb_filtergraphs--; + if (nb_filtergraphs > 0) + memmove(&filtergraphs[i], + &filtergraphs[i + 1], + (nb_filtergraphs - i) * sizeof(*filtergraphs)); + break; } } } + for (int i = 0; i < nb_filtergraphs; i++) { + ret = bind_inputs(filtergraphs[i], 1); + if (ret < 0) + return ret; + } + return 0; } -static int insert_trim(int64_t start_time, int64_t duration, +static int insert_trim(void *logctx, int64_t start_time, int64_t duration, AVFilterContext **last_filter, int *pad_idx, const char *filter_name) { @@ -1437,7 +1555,7 @@ static int insert_trim(int64_t start_time, int64_t duration, trim = avfilter_get_by_name(name); if (!trim) { - av_log(NULL, AV_LOG_ERROR, "%s filter not present, cannot limit " + av_log(logctx, AV_LOG_ERROR, "%s filter not present, cannot limit " "recording time.\n", name); return AVERROR_FILTER_NOT_FOUND; } @@ -1508,14 +1626,61 @@ static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *gr int ret; char name[255]; - snprintf(name, sizeof(name), "out_%s", ofp->name); - ret = avfilter_graph_create_filter(&ofp->filter, + snprintf(name, sizeof(name), "out_%s", ofilter->output_name); + ret = avfilter_graph_create_filter(&ofilter->filter, avfilter_get_by_name("buffersink"), name, NULL, NULL, graph); if (ret < 0) return ret; + if (ofp->flags & OFILTER_FLAG_CROP) { + char crop_buf[64]; + snprintf(crop_buf, sizeof(crop_buf), "w=iw-%u-%u:h=ih-%u-%u:x=%u:y=%u", + ofp->crop_left, ofp->crop_right, + ofp->crop_top, ofp->crop_bottom, + ofp->crop_left, ofp->crop_top); + ret = insert_filter(&last_filter, &pad_idx, "crop", crop_buf); + if (ret < 0) + return ret; + } + + if (ofp->flags & OFILTER_FLAG_AUTOROTATE) { + int32_t *displaymatrix = ofp->displaymatrix; + double theta; + + theta = get_rotation(displaymatrix); + + if (fabs(theta - 90) < 1.0) { + ret = insert_filter(&last_filter, &pad_idx, "transpose", + displaymatrix[3] > 0 ? "cclock_flip" : "clock"); + } else if (fabs(theta - 180) < 1.0) { + if (displaymatrix[0] < 0) { + ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL); + if (ret < 0) + return ret; + } + if (displaymatrix[4] < 0) { + ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL); + } + } else if (fabs(theta - 270) < 1.0) { + ret = insert_filter(&last_filter, &pad_idx, "transpose", + displaymatrix[3] < 0 ? "clock_flip" : "cclock"); + } else if (fabs(theta) > 1.0) { + char rotate_buf[64]; + snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta); + ret = insert_filter(&last_filter, &pad_idx, "rotate", rotate_buf); + } else if (fabs(theta) < 1.0) { + if (displaymatrix && displaymatrix[4] < 0) { + ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL); + } + } + if (ret < 0) + return ret; + + av_frame_side_data_remove(&ofp->side_data, &ofp->nb_side_data, AV_FRAME_DATA_DISPLAYMATRIX); + } + if ((ofp->width || ofp->height) && (ofp->flags & OFILTER_FLAG_AUTOSCALE)) { char args[255]; AVFilterContext *filter; @@ -1528,7 +1693,7 @@ static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *gr av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value); } - snprintf(name, sizeof(name), "scaler_out_%s", ofp->name); + snprintf(name, sizeof(name), "scaler_out_%s", ofilter->output_name); if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), name, args, NULL, graph)) < 0) return ret; @@ -1540,11 +1705,12 @@ static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *gr } av_assert0(!(ofp->flags & OFILTER_FLAG_DISABLE_CONVERT) || - ofp->format != AV_PIX_FMT_NONE || !ofp->formats); + ofp->format != AV_PIX_FMT_NONE || !ofp->pix_fmts); av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED); choose_pix_fmts(ofp, &bprint); choose_color_spaces(ofp, &bprint); choose_color_ranges(ofp, &bprint); + choose_alpha_modes(ofp, &bprint); if (!av_bprint_is_complete(&bprint)) return AVERROR(ENOMEM); @@ -1564,14 +1730,14 @@ static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *gr pad_idx = 0; } - snprintf(name, sizeof(name), "trim_out_%s", ofp->name); - ret = insert_trim(ofp->trim_start_us, ofp->trim_duration_us, + snprintf(name, sizeof(name), "trim_out_%s", ofilter->output_name); + ret = insert_trim(fgp, ofp->trim_start_us, ofp->trim_duration_us, &last_filter, &pad_idx, name); if (ret < 0) return ret; - if ((ret = avfilter_link(last_filter, pad_idx, ofp->filter, 0)) < 0) + if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) return ret; return 0; @@ -1587,14 +1753,12 @@ static int configure_output_audio_filter(FilterGraphPriv *fgp, AVFilterGraph *gr char name[255]; int ret; - snprintf(name, sizeof(name), "out_%s", ofp->name); - ret = avfilter_graph_create_filter(&ofp->filter, + snprintf(name, sizeof(name), "out_%s", ofilter->output_name); + ret = avfilter_graph_create_filter(&ofilter->filter, avfilter_get_by_name("abuffersink"), name, NULL, NULL, graph); if (ret < 0) return ret; - if ((ret = av_opt_set_int(ofp->filter, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0) - return ret; #define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do { \ AVFilterContext *filt_ctx; \ @@ -1627,7 +1791,7 @@ static int configure_output_audio_filter(FilterGraphPriv *fgp, AVFilterGraph *gr if (args.len) { AVFilterContext *format; - snprintf(name, sizeof(name), "format_out_%s", ofp->name); + snprintf(name, sizeof(name), "format_out_%s", ofilter->output_name); ret = avfilter_graph_create_filter(&format, avfilter_get_by_name("aformat"), name, args.str, NULL, graph); @@ -1647,13 +1811,13 @@ static int configure_output_audio_filter(FilterGraphPriv *fgp, AVFilterGraph *gr fgp->have_sources = 1; } - snprintf(name, sizeof(name), "trim for output %s", ofp->name); - ret = insert_trim(ofp->trim_start_us, ofp->trim_duration_us, + snprintf(name, sizeof(name), "trim for output %s", ofilter->output_name); + ret = insert_trim(fgp, ofp->trim_start_us, ofp->trim_duration_us, &last_filter, &pad_idx, name); if (ret < 0) goto fail; - if ((ret = avfilter_link(last_filter, pad_idx, ofp->filter, 0)) < 0) + if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) goto fail; fail: av_bprint_finalize(&args, NULL); @@ -1690,9 +1854,6 @@ static int configure_input_video_filter(FilterGraph *fg, AVFilterGraph *graph, AVFilterContext *last_filter; const AVFilter *buffer_filt = avfilter_get_by_name("buffer"); const AVPixFmtDescriptor *desc; - AVRational fr = ifp->opts.framerate; - AVRational sar; - AVBPrint args; char name[255]; int ret, pad_idx = 0; AVBufferSrcParameters *par = av_buffersrc_parameters_alloc(); @@ -1702,31 +1863,39 @@ static int configure_input_video_filter(FilterGraph *fg, AVFilterGraph *graph, if (ifp->type_src == AVMEDIA_TYPE_SUBTITLE) sub2video_prepare(ifp); - sar = ifp->sample_aspect_ratio; - if(!sar.den) - sar = (AVRational){0,1}; - av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC); - av_bprintf(&args, - "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:" - "pixel_aspect=%d/%d:colorspace=%d:range=%d", - ifp->width, ifp->height, ifp->format, - ifp->time_base.num, ifp->time_base.den, sar.num, sar.den, - ifp->color_space, ifp->color_range); - if (fr.num && fr.den) - av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den); snprintf(name, sizeof(name), "graph %d input from stream %s", fg->index, ifp->opts.name); - - if ((ret = avfilter_graph_create_filter(&ifp->filter, buffer_filt, name, - args.str, NULL, graph)) < 0) + ifilter->filter = avfilter_graph_alloc_filter(graph, buffer_filt, name); + if (!ifilter->filter) { + ret = AVERROR(ENOMEM); goto fail; - par->hw_frames_ctx = ifp->hw_frames_ctx; - ret = av_buffersrc_parameters_set(ifp->filter, par); + } + + par->format = ifp->format; + par->time_base = ifp->time_base; + par->frame_rate = ifp->opts.framerate; + par->width = ifp->width; + par->height = ifp->height; + par->sample_aspect_ratio = ifp->sample_aspect_ratio.den > 0 ? + ifp->sample_aspect_ratio : (AVRational){ 0, 1 }; + par->color_space = ifp->color_space; + par->color_range = ifp->color_range; + par->alpha_mode = ifp->alpha_mode; + par->hw_frames_ctx = ifp->hw_frames_ctx; + par->side_data = ifp->side_data; + par->nb_side_data = ifp->nb_side_data; + + ret = av_buffersrc_parameters_set(ifilter->filter, par); if (ret < 0) goto fail; av_freep(&par); - last_filter = ifp->filter; + + ret = avfilter_init_dict(ifilter->filter, NULL); + if (ret < 0) + goto fail; + + last_filter = ifilter->filter; desc = av_pix_fmt_desc_get(ifp->format); av_assert0(desc); @@ -1782,7 +1951,7 @@ static int configure_input_video_filter(FilterGraph *fg, AVFilterGraph *graph, } snprintf(name, sizeof(name), "trim_in_%s", ifp->opts.name); - ret = insert_trim(ifp->opts.trim_start_us, ifp->opts.trim_end_us, + ret = insert_trim(fg, ifp->opts.trim_start_us, ifp->opts.trim_end_us, &last_filter, &pad_idx, name); if (ret < 0) return ret; @@ -1801,6 +1970,7 @@ static int configure_input_audio_filter(FilterGraph *fg, AVFilterGraph *graph, { InputFilterPriv *ifp = ifp_from_ifilter(ifilter); AVFilterContext *last_filter; + AVBufferSrcParameters *par; const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer"); AVBPrint args; char name[255]; @@ -1819,14 +1989,23 @@ static int configure_input_audio_filter(FilterGraph *fg, AVFilterGraph *graph, av_bprintf(&args, ":channels=%d", ifp->ch_layout.nb_channels); snprintf(name, sizeof(name), "graph_%d_in_%s", fg->index, ifp->opts.name); - if ((ret = avfilter_graph_create_filter(&ifp->filter, abuffer_filt, + if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt, name, args.str, NULL, graph)) < 0) return ret; - last_filter = ifp->filter; + par = av_buffersrc_parameters_alloc(); + if (!par) + return AVERROR(ENOMEM); + par->side_data = ifp->side_data; + par->nb_side_data = ifp->nb_side_data; + ret = av_buffersrc_parameters_set(ifilter->filter, par); + av_free(par); + if (ret < 0) + return ret; + last_filter = ifilter->filter; snprintf(name, sizeof(name), "trim for input stream %s", ifp->opts.name); - ret = insert_trim(ifp->opts.trim_start_us, ifp->opts.trim_end_us, + ret = insert_trim(fg, ifp->opts.trim_start_us, ifp->opts.trim_end_us, &last_filter, &pad_idx, name); if (ret < 0) return ret; @@ -1840,7 +2019,7 @@ static int configure_input_audio_filter(FilterGraph *fg, AVFilterGraph *graph, static int configure_input_filter(FilterGraph *fg, AVFilterGraph *graph, InputFilter *ifilter, AVFilterInOut *in) { - switch (ifp_from_ifilter(ifilter)->type) { + switch (ifilter->type) { case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, graph, ifilter, in); case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, graph, ifilter, in); default: av_assert0(0); return 0; @@ -1850,9 +2029,9 @@ static int configure_input_filter(FilterGraph *fg, AVFilterGraph *graph, static void cleanup_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) { for (int i = 0; i < fg->nb_outputs; i++) - ofp_from_ofilter(fg->outputs[i])->filter = NULL; + fg->outputs[i]->filter = NULL; for (int i = 0; i < fg->nb_inputs; i++) - ifp_from_ifilter(fg->inputs[i])->filter = NULL; + fg->inputs[i]->filter = NULL; avfilter_graph_free(&fgt->graph); } @@ -1887,9 +2066,9 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) FilterGraphPriv *fgp = fgp_from_fg(fg); AVBufferRef *hw_device; AVFilterInOut *inputs, *outputs, *cur; - int ret, i, simple = filtergraph_is_simple(fg); + int ret = AVERROR_BUG, i, simple = filtergraph_is_simple(fg); int have_input_eof = 0; - const char *graph_desc = fgp->graph_desc; + const char *graph_desc = fg->graph_desc; cleanup_filtergraph(fg, fgt); fgt->graph = avfilter_graph_alloc(); @@ -1903,8 +2082,8 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) ret = av_opt_set(fgt->graph, "threads", filter_nbthreads, 0); if (ret < 0) goto fail; - } else if (fgp->nb_threads) { - ret = av_opt_set(fgt->graph, "threads", fgp->nb_threads, 0); + } else if (fgp->nb_threads >= 0) { + ret = av_opt_set_int(fgt->graph, "threads", fgp->nb_threads, 0); if (ret < 0) return ret; } @@ -1929,9 +2108,16 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) fgt->graph->nb_threads = filter_complex_nbthreads; } + if (filter_buffered_frames) { + ret = av_opt_set_int(fgt->graph, "max_buffered_frames", filter_buffered_frames, 0); + if (ret < 0) + return ret; + } + hw_device = hw_device_for_filter(); - if ((ret = graph_parse(fgt->graph, graph_desc, &inputs, &outputs, hw_device)) < 0) + ret = graph_parse(fg, fgt->graph, graph_desc, &inputs, &outputs, hw_device); + if (ret < 0) goto fail; for (cur = inputs, i = 0; cur; cur = cur->next, i++) @@ -1961,9 +2147,11 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) /* limit the lists of allowed formats to the ones selected, to * make sure they stay the same if the filtergraph is reconfigured later */ for (int i = 0; i < fg->nb_outputs; i++) { + const AVFrameSideData *const *sd; + int nb_sd; OutputFilter *ofilter = fg->outputs[i]; OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); - AVFilterContext *sink = ofp->filter; + AVFilterContext *sink = ofilter->filter; ofp->format = av_buffersink_get_format(sink); @@ -1971,6 +2159,7 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) ofp->height = av_buffersink_get_h(sink); ofp->color_space = av_buffersink_get_colorspace(sink); ofp->color_range = av_buffersink_get_color_range(sink); + ofp->alpha_mode = av_buffersink_get_alpha_mode(sink); // If the timing parameters are not locked yet, get the tentative values // here but don't lock them. They will only be used if no output frames @@ -1989,9 +2178,20 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) ret = av_buffersink_get_ch_layout(sink, &ofp->ch_layout); if (ret < 0) goto fail; + sd = av_buffersink_get_side_data(sink, &nb_sd); + if (nb_sd) + for (int j = 0; j < nb_sd; j++) { + ret = av_frame_side_data_clone(&ofp->side_data, &ofp->nb_side_data, + sd[j], AV_FRAME_SIDE_DATA_FLAG_REPLACE); + if (ret < 0) { + av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data); + goto fail; + } + } } for (int i = 0; i < fg->nb_inputs; i++) { + InputFilter *ifilter = fg->inputs[i]; InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]); AVFrame *tmp; while (av_fifo_read(ifp->frame_queue, &tmp, 1) >= 0) { @@ -2002,7 +2202,7 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) if (ifp->displaymatrix_applied) av_frame_remove_side_data(tmp, AV_FRAME_DATA_DISPLAYMATRIX); } - ret = av_buffersrc_add_frame(ifp->filter, tmp); + ret = av_buffersrc_add_frame(ifilter->filter, tmp); } av_frame_free(&tmp); if (ret < 0) @@ -2012,9 +2212,9 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) /* send the EOFs for the finished inputs */ for (int i = 0; i < fg->nb_inputs; i++) { - InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]); + InputFilter *ifilter = fg->inputs[i]; if (fgt->eof_in[i]) { - ret = av_buffersrc_add_frame(ifp->filter, NULL); + ret = av_buffersrc_add_frame(ifilter->filter, NULL); if (ret < 0) goto fail; have_input_eof = 1; @@ -2044,7 +2244,7 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr if (ret < 0) return ret; - ifp->time_base = (ifp->type == AVMEDIA_TYPE_AUDIO) ? (AVRational){ 1, frame->sample_rate } : + ifp->time_base = (ifilter->type == AVMEDIA_TYPE_AUDIO) ? (AVRational){ 1, frame->sample_rate } : (ifp->opts.flags & IFILTER_FLAG_CFR) ? av_inv_q(ifp->opts.framerate) : frame->time_base; @@ -2055,17 +2255,67 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr ifp->sample_aspect_ratio = frame->sample_aspect_ratio; ifp->color_space = frame->colorspace; ifp->color_range = frame->color_range; + ifp->alpha_mode = frame->alpha_mode; ifp->sample_rate = frame->sample_rate; ret = av_channel_layout_copy(&ifp->ch_layout, &frame->ch_layout); if (ret < 0) return ret; + av_frame_side_data_free(&ifp->side_data, &ifp->nb_side_data); + for (int i = 0; i < frame->nb_side_data; i++) { + const AVSideDataDescriptor *desc = av_frame_side_data_desc(frame->side_data[i]->type); + + if (!(desc->props & AV_SIDE_DATA_PROP_GLOBAL) || + frame->side_data[i]->type == AV_FRAME_DATA_DISPLAYMATRIX) + continue; + + ret = av_frame_side_data_clone(&ifp->side_data, + &ifp->nb_side_data, + frame->side_data[i], 0); + if (ret < 0) + return ret; + } + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX); if (sd) memcpy(ifp->displaymatrix, sd->data, sizeof(ifp->displaymatrix)); ifp->displaymatrix_present = !!sd; + /* Copy downmix related side data to InputFilterPriv so it may be propagated + * to the filter chain even though it's not "global", as filters like aresample + * require this information during init and not when remixing a frame */ + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DOWNMIX_INFO); + if (sd) { + ret = av_frame_side_data_clone(&ifp->side_data, + &ifp->nb_side_data, sd, 0); + if (ret < 0) + return ret; + memcpy(&ifp->downmixinfo, sd->data, sizeof(ifp->downmixinfo)); + } + ifp->downmixinfo_present = !!sd; + + return 0; +} + +static int ifilter_parameters_from_ofilter(InputFilter *ifilter, OutputFilter *ofilter) +{ + const OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); + InputFilterPriv *ifp = ifp_from_ifilter(ifilter); + + if (!ifp->opts.framerate.num) { + ifp->opts.framerate = ofp->fps.framerate; + if (ifp->opts.framerate.num > 0 && ifp->opts.framerate.den > 0) + ifp->opts.flags |= IFILTER_FLAG_CFR; + } + + for (int i = 0; i < ofp->nb_side_data; i++) { + int ret = av_frame_side_data_clone(&ifp->side_data, &ifp->nb_side_data, + ofp->side_data[i], AV_FRAME_SIDE_DATA_FLAG_REPLACE); + if (ret < 0) + return ret; + } + return 0; } @@ -2107,12 +2357,11 @@ static int choose_input(const FilterGraph *fg, const FilterGraphThread *fgt) for (int i = 0; i < fg->nb_inputs; i++) { InputFilter *ifilter = fg->inputs[i]; - InputFilterPriv *ifp = ifp_from_ifilter(ifilter); if (fgt->eof_in[i]) continue; - nb_requests = av_buffersrc_get_nb_failed_requests(ifp->filter); + nb_requests = av_buffersrc_get_nb_failed_requests(ifilter->filter); if (nb_requests > nb_requests_max) { nb_requests_max = nb_requests; best_input = i; @@ -2156,7 +2405,7 @@ static int choose_out_timebase(OutputFilterPriv *ofp, AVFrame *frame) fr = fps->framerate; if (!fr.num) { - AVRational fr_sink = av_buffersink_get_frame_rate(ofp->filter); + AVRational fr_sink = av_buffersink_get_frame_rate(ofilter->filter); if (fr_sink.num > 0 && fr_sink.den > 0) fr = fr_sink; } @@ -2201,8 +2450,8 @@ finish: return 0; } -static double adjust_frame_pts_to_encoder_tb(AVFrame *frame, AVRational tb_dst, - int64_t start_time) +static double adjust_frame_pts_to_encoder_tb(void *logctx, AVFrame *frame, + AVRational tb_dst, int64_t start_time) { double float_pts = AV_NOPTS_VALUE; // this is identical to frame.pts but with higher precision @@ -2230,7 +2479,8 @@ static double adjust_frame_pts_to_encoder_tb(AVFrame *frame, AVRational tb_dst, early_exit: if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "filter -> pts:%s pts_time:%s exact:%f time_base:%d/%d\n", + av_log(logctx, AV_LOG_INFO, + "filter -> pts:%s pts_time:%s exact:%f time_base:%d/%d\n", frame ? av_ts2str(frame->pts) : "NULL", av_ts2timestr(frame->pts, &tb_dst), float_pts, tb_dst.num, tb_dst.den); @@ -2239,6 +2489,23 @@ early_exit: return float_pts; } +static int64_t median3(int64_t a, int64_t b, int64_t c) +{ + int64_t max2, min2, m; + + if (a >= b) { + max2 = a; + min2 = b; + } else { + max2 = b; + min2 = a; + } + m = (c >= max2) ? max2 : c; + + return (m >= min2) ? m : min2; +} + + /* Convert frame timestamps to the encoder timebase and decide how many times * should this (and possibly previous) frame be repeated in order to conform to * desired target framerate (if any). @@ -2251,9 +2518,9 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame, double delta0, delta, sync_ipts, duration; if (!frame) { - *nb_frames_prev = *nb_frames = mid_pred(fps->frames_prev_hist[0], - fps->frames_prev_hist[1], - fps->frames_prev_hist[2]); + *nb_frames_prev = *nb_frames = median3(fps->frames_prev_hist[0], + fps->frames_prev_hist[1], + fps->frames_prev_hist[2]); if (!*nb_frames && fps->last_dropped) { atomic_fetch_add(&ofilter->nb_frames_drop, 1); @@ -2265,7 +2532,8 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame, duration = frame->duration * av_q2d(frame->time_base) / av_q2d(ofp->tb_out); - sync_ipts = adjust_frame_pts_to_encoder_tb(frame, ofp->tb_out, ofp->ts_offset); + sync_ipts = adjust_frame_pts_to_encoder_tb(ofilter->graph, frame, + ofp->tb_out, ofp->ts_offset); /* delta0 is the "drift" between the input frame and * where it would fall in the output. */ delta0 = sync_ipts - ofp->next_pts; @@ -2365,14 +2633,12 @@ finish: fps->dropped_keyframe |= fps->last_dropped && (frame->flags & AV_FRAME_FLAG_KEY); } -static void close_input(FilterGraph *fg, int input_idx) +static void close_input(InputFilterPriv *ifp) { - - InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[input_idx]); FilterGraphPriv *fgp = fgp_from_fg(ifp->ifilter.graph); if (!ifp->eof) { - sch_filter_receive_finish(fgp->sch, fgp->sch_idx, input_idx); + sch_filter_receive_finish(fgp->sch, fgp->sch_idx, ifp->ifilter.index); ifp->eof = 1; } } @@ -2406,6 +2672,12 @@ static int close_output(OutputFilterPriv *ofp, FilterGraphThread *fgt) if (!fd) return AVERROR(ENOMEM); + av_frame_side_data_free(&fd->side_data, &fd->nb_side_data); + ret = clone_side_data(&fd->side_data, &fd->nb_side_data, + ofp->side_data, ofp->nb_side_data, 0); + if (ret < 0) + return ret; + fd->frame_rate_filter = ofp->fps.framerate; av_assert0(!frame->buf[0]); @@ -2414,16 +2686,16 @@ static int close_output(OutputFilterPriv *ofp, FilterGraphThread *fgt) "No filtered frames for output stream, trying to " "initialize anyway.\n"); - ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->index, frame); + ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->ofilter.index, frame); if (ret < 0) { av_frame_unref(frame); return ret; } } - fgt->eof_out[ofp->index] = 1; + fgt->eof_out[ofp->ofilter.index] = 1; - ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->index, NULL); + ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->ofilter.index, NULL); return (ret == AVERROR_EOF) ? 0 : ret; } @@ -2476,12 +2748,12 @@ static int fg_output_frame(OutputFilterPriv *ofp, FilterGraphThread *fgt, } // send the frame to consumers - ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->index, frame_out); + ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->ofilter.index, frame_out); if (ret < 0) { av_frame_unref(frame_out); - if (!fgt->eof_out[ofp->index]) { - fgt->eof_out[ofp->index] = 1; + if (!fgt->eof_out[ofp->ofilter.index]) { + fgt->eof_out[ofp->ofilter.index] = 1; fgp->nb_outputs_done++; } @@ -2514,13 +2786,13 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt, AVFrame *frame) { FilterGraphPriv *fgp = fgp_from_fg(ofp->ofilter.graph); - AVFilterContext *filter = ofp->filter; + AVFilterContext *filter = ofp->ofilter.filter; FrameData *fd; int ret; ret = av_buffersink_get_frame_flags(filter, frame, AV_BUFFERSINK_FLAG_NO_REQUEST); - if (ret == AVERROR_EOF && !fgt->eof_out[ofp->index]) { + if (ret == AVERROR_EOF && !fgt->eof_out[ofp->ofilter.index]) { ret = fg_output_frame(ofp, fgt, NULL); return (ret < 0) ? ret : 1; } else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { @@ -2532,7 +2804,7 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt, return ret; } - if (fgt->eof_out[ofp->index]) { + if (fgt->eof_out[ofp->ofilter.index]) { av_frame_unref(frame); return 0; } @@ -2560,6 +2832,14 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt, return AVERROR(ENOMEM); } + av_frame_side_data_free(&fd->side_data, &fd->nb_side_data); + if (!fgt->got_frame) { + ret = clone_side_data(&fd->side_data, &fd->nb_side_data, + ofp->side_data, ofp->nb_side_data, 0); + if (ret < 0) + return ret; + } + fd->wallclock[LATENCY_PROBE_FILTER_POST] = av_gettime_relative(); // only use bits_per_raw_sample passed through from the decoder @@ -2613,25 +2893,6 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt, while (fgp->nb_outputs_done < fg->nb_outputs) { int ret; - ret = avfilter_graph_request_oldest(fgt->graph); - if (ret == AVERROR(EAGAIN)) { - fgt->next_in = choose_input(fg, fgt); - break; - } else if (ret < 0) { - if (ret == AVERROR_EOF) - av_log(fg, AV_LOG_VERBOSE, "Filtergraph returned EOF, finishing\n"); - else - av_log(fg, AV_LOG_ERROR, - "Error requesting a frame from the filtergraph: %s\n", - av_err2str(ret)); - return ret; - } - fgt->next_in = fg->nb_inputs; - - // return after one iteration, so that scheduler can rate-control us - if (did_step && fgp->have_sources) - return 0; - /* Reap all buffers present in the buffer sinks */ for (int i = 0; i < fg->nb_outputs; i++) { OutputFilterPriv *ofp = ofp_from_ofilter(fg->outputs[i]); @@ -2643,10 +2904,30 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt, return ret; } } + + // return after one iteration, so that scheduler can rate-control us + if (did_step && fgp->have_sources) + return 0; + + ret = avfilter_graph_request_oldest(fgt->graph); + if (ret == AVERROR(EAGAIN)) { + fgt->next_in = choose_input(fg, fgt); + return 0; + } else if (ret < 0) { + if (ret == AVERROR_EOF) + av_log(fg, AV_LOG_VERBOSE, "Filtergraph returned EOF, finishing\n"); + else + av_log(fg, AV_LOG_ERROR, + "Error requesting a frame from the filtergraph: %s\n", + av_err2str(ret)); + return ret; + } + fgt->next_in = fg->nb_inputs; + did_step = 1; } - return (fgp->nb_outputs_done == fg->nb_outputs) ? AVERROR_EOF : 0; + return AVERROR_EOF; } static void sub2video_heartbeat(InputFilter *ifilter, int64_t pts, AVRational tb) @@ -2665,7 +2946,7 @@ static void sub2video_heartbeat(InputFilter *ifilter, int64_t pts, AVRational tb if (pts2 >= ifp->sub2video.end_pts || ifp->sub2video.initialize) /* if we have hit the end of the current displayed subpicture, or if we need to initialize the system, update the - overlayed subpicture and its start/end times */ + overlaid subpicture and its start/end times */ sub2video_update(ifp, pts2 + 1, NULL); else sub2video_push_ref(ifp, pts2); @@ -2707,7 +2988,7 @@ static int sub2video_frame(InputFilter *ifilter, AVFrame *frame, int buffer) if (ifp->sub2video.end_pts < INT64_MAX) sub2video_update(ifp, INT64_MAX, NULL); - return av_buffersrc_add_frame(ifp->filter, NULL); + return av_buffersrc_add_frame(ifilter->filter, NULL); } ifp->width = frame->width ? frame->width : ifp->width; @@ -2724,16 +3005,16 @@ static int send_eof(FilterGraphThread *fgt, InputFilter *ifilter, InputFilterPriv *ifp = ifp_from_ifilter(ifilter); int ret; - if (fgt->eof_in[ifp->index]) + if (fgt->eof_in[ifilter->index]) return 0; - fgt->eof_in[ifp->index] = 1; + fgt->eof_in[ifilter->index] = 1; - if (ifp->filter) { + if (ifilter->filter) { pts = av_rescale_q_rnd(pts, tb, ifp->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); - ret = av_buffersrc_close(ifp->filter, pts, AV_BUFFERSRC_FLAG_PUSH); + ret = av_buffersrc_close(ifilter->filter, pts, AV_BUFFERSRC_FLAG_PUSH); if (ret < 0) return ret; } else { @@ -2746,6 +3027,7 @@ static int send_eof(FilterGraphThread *fgt, InputFilter *ifilter, ifp->sample_aspect_ratio = ifp->opts.fallback->sample_aspect_ratio; ifp->color_space = ifp->opts.fallback->colorspace; ifp->color_range = ifp->opts.fallback->color_range; + ifp->alpha_mode = ifp->opts.fallback->alpha_mode; ifp->time_base = ifp->opts.fallback->time_base; ret = av_channel_layout_copy(&ifp->ch_layout, @@ -2753,17 +3035,24 @@ static int send_eof(FilterGraphThread *fgt, InputFilter *ifilter, if (ret < 0) return ret; + av_frame_side_data_free(&ifp->side_data, &ifp->nb_side_data); + ret = clone_side_data(&ifp->side_data, &ifp->nb_side_data, + ifp->opts.fallback->side_data, + ifp->opts.fallback->nb_side_data, 0); + if (ret < 0) + return ret; + if (ifilter_has_all_input_formats(ifilter->graph)) { ret = configure_filtergraph(ifilter->graph, fgt); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error initializing filters!\n"); + av_log(ifilter->graph, AV_LOG_ERROR, "Error initializing filters!\n"); return ret; } } } if (ifp->format < 0) { - av_log(NULL, AV_LOG_ERROR, + av_log(ifilter->graph, AV_LOG_ERROR, "Cannot determine format of input %s after EOF\n", ifp->opts.name); return AVERROR_INVALIDDATA; @@ -2777,7 +3066,8 @@ enum ReinitReason { VIDEO_CHANGED = (1 << 0), AUDIO_CHANGED = (1 << 1), MATRIX_CHANGED = (1 << 2), - HWACCEL_CHANGED = (1 << 3) + DOWNMIX_CHANGED = (1 << 3), + HWACCEL_CHANGED = (1 << 4) }; static const char *unknown_if_null(const char *str) @@ -2788,13 +3078,14 @@ static const char *unknown_if_null(const char *str) static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, InputFilter *ifilter, AVFrame *frame) { + FilterGraphPriv *fgp = fgp_from_fg(fg); InputFilterPriv *ifp = ifp_from_ifilter(ifilter); FrameData *fd; AVFrameSideData *sd; int need_reinit = 0, ret; /* determine if the parameters for this input changed */ - switch (ifp->type) { + switch (ifilter->type) { case AVMEDIA_TYPE_AUDIO: if (ifp->format != frame->format || ifp->sample_rate != frame->sample_rate || @@ -2806,7 +3097,8 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, ifp->width != frame->width || ifp->height != frame->height || ifp->color_space != frame->colorspace || - ifp->color_range != frame->color_range) + ifp->color_range != frame->color_range || + ifp->alpha_mode != frame->alpha_mode) need_reinit |= VIDEO_CHANGED; break; } @@ -2818,6 +3110,20 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, } else if (ifp->displaymatrix_present) need_reinit |= MATRIX_CHANGED; + if (sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DOWNMIX_INFO)) { + if (!ifp->downmixinfo_present || + memcmp(sd->data, &ifp->downmixinfo, sizeof(ifp->downmixinfo))) + need_reinit |= DOWNMIX_CHANGED; + } else if (ifp->downmixinfo_present) + need_reinit |= DOWNMIX_CHANGED; + + if (need_reinit && fgt->graph && (ifp->opts.flags & IFILTER_FLAG_DROPCHANGED)) { + ifp->nb_dropped++; + av_log_once(fg, AV_LOG_WARNING, AV_LOG_DEBUG, &ifp->drop_warned, "Avoiding reinit; dropping frame pts: %s bound for %s\n", av_ts2str(frame->pts), ifilter->name); + av_frame_unref(frame); + return 0; + } + if (!(ifp->opts.flags & IFILTER_FLAG_REINIT) && fgt->graph) need_reinit = 0; @@ -2829,6 +3135,14 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, ret = ifilter_parameters_from_frame(ifilter, frame); if (ret < 0) return ret; + + /* Inputs bound to a filtergraph output will have some fields unset. + * Handle them here */ + if (ifp->ofilter_src) { + ret = ifilter_parameters_from_ofilter(ifilter, ifp->ofilter_src); + if (ret < 0) + return ret; + } } /* (re)init the graph if possible, otherwise buffer the frame and return */ @@ -2866,17 +3180,26 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, const char *pixel_format_name = av_get_pix_fmt_name(frame->format); const char *color_space_name = av_color_space_name(frame->colorspace); const char *color_range_name = av_color_range_name(frame->color_range); - av_bprintf(&reason, "video parameters changed to %s(%s, %s), %dx%d, ", + const char *alpha_mode = av_alpha_mode_name(frame->alpha_mode); + av_bprintf(&reason, "video parameters changed to %s(%s, %s), %dx%d, %s alpha,", unknown_if_null(pixel_format_name), unknown_if_null(color_range_name), - unknown_if_null(color_space_name), frame->width, frame->height); + unknown_if_null(color_space_name), frame->width, frame->height, + unknown_if_null(alpha_mode)); } if (need_reinit & MATRIX_CHANGED) av_bprintf(&reason, "display matrix changed, "); + if (need_reinit & DOWNMIX_CHANGED) + av_bprintf(&reason, "downmix medatata changed, "); if (need_reinit & HWACCEL_CHANGED) av_bprintf(&reason, "hwaccel changed, "); if (reason.len > 1) reason.str[reason.len - 2] = '\0'; // remove last comma av_log(fg, AV_LOG_INFO, "Reconfiguring filter graph%s%s\n", reason.len ? " because " : "", reason.str); + } else { + /* Choke all input to avoid buffering excessive frames while the + * initial filter graph is being configured, and before we have a + * preferred input */ + sch_filter_choke_inputs(fgp->sch, fgp->sch_idx); } ret = configure_filtergraph(fg, fgt); @@ -2898,7 +3221,7 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, return AVERROR(ENOMEM); fd->wallclock[LATENCY_PROBE_FILTER_PRE] = av_gettime_relative(); - ret = av_buffersrc_add_frame_flags(ifp->filter, frame, + ret = av_buffersrc_add_frame_flags(ifilter->filter, frame, AV_BUFFERSRC_FLAG_PUSH); if (ret < 0) { av_frame_unref(frame); @@ -2917,7 +3240,7 @@ static void fg_thread_set_name(const FilterGraph *fg) OutputFilterPriv *ofp = ofp_from_ofilter(fg->outputs[0]); snprintf(name, sizeof(name), "%cf%s", av_get_media_type_string(ofp->ofilter.type)[0], - ofp->name); + ofp->ofilter.output_name); } else { snprintf(name, sizeof(name), "fc%d", fg->index); } @@ -2996,7 +3319,7 @@ static int filter_thread(void *arg) while (1) { InputFilter *ifilter; - InputFilterPriv *ifp; + InputFilterPriv *ifp = NULL; enum FrameOpaque o; unsigned input_idx = fgt.next_in; @@ -3047,17 +3370,19 @@ static int filter_thread(void *arg) if (ret == AVERROR_EOF) { av_log(fg, AV_LOG_VERBOSE, "Input %u no longer accepts new data\n", input_idx); - close_input(fg, input_idx); + close_input(ifp); continue; } if (ret < 0) goto finish; read_frames: - // retrieve all newly avalable frames + // retrieve all newly available frames ret = read_frames(fg, &fgt, fgt.frame); if (ret == AVERROR_EOF) { av_log(fg, AV_LOG_VERBOSE, "All consumers returned EOF\n"); + if (ifp && ifp->opts.flags & IFILTER_FLAG_DROPCHANGED) + av_log(fg, AV_LOG_INFO, "Total changed input frames dropped : %"PRId64"\n", ifp->nb_dropped); break; } else if (ret < 0) { av_log(fg, AV_LOG_ERROR, "Error sending frames to consumers: %s\n", @@ -3068,8 +3393,8 @@ read_frames: // ensure all inputs no longer accepting data are closed for (int i = 0; fgt.graph && i < fg->nb_inputs; i++) { InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]); - if (av_buffersrc_get_status(ifp->filter)) - close_input(fg, i); + if (av_buffersrc_get_status(ifp->ifilter.filter)) + close_input(ifp); } } @@ -3085,6 +3410,10 @@ read_frames: } finish: + + if (print_graphs || print_graphs_file) + print_filtergraph(fg, fgt.graph); + // EOF is normal termination if (ret == AVERROR_EOF) ret = 0; diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 71ff9b45a..25f66dd18 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -581,9 +581,9 @@ static int bsf_init(MuxStream *ms) int ret; if (!ctx) - return avcodec_parameters_copy(ost->st->codecpar, ost->par_in); + return avcodec_parameters_copy(ost->st->codecpar, ms->par_in); - ret = avcodec_parameters_copy(ctx->par_in, ost->par_in); + ret = avcodec_parameters_copy(ctx->par_in, ms->par_in); if (ret < 0) return ret; @@ -608,12 +608,29 @@ static int bsf_init(MuxStream *ms) return 0; } -int of_stream_init(OutputFile *of, OutputStream *ost) +int of_stream_init(OutputFile *of, OutputStream *ost, + const AVCodecContext *enc_ctx) { Muxer *mux = mux_from_of(of); MuxStream *ms = ms_from_ost(ost); int ret; + if (enc_ctx) { + // use upstream time base unless it has been overridden previously + if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0) + ost->st->time_base = av_add_q(enc_ctx->time_base, (AVRational){0, 1}); + + ost->st->avg_frame_rate = enc_ctx->framerate; + ost->st->sample_aspect_ratio = enc_ctx->sample_aspect_ratio; + + ret = avcodec_parameters_from_context(ms->par_in, enc_ctx); + if (ret < 0) { + av_log(ost, AV_LOG_FATAL, + "Error initializing the output stream codec parameters.\n"); + return ret; + } + } + /* initialize bitstream filters for the output stream * needs to be done here, because the codec id for streamcopy is not * known until now */ @@ -644,8 +661,8 @@ static int check_written(OutputFile *of) total_packets_written += packets_written; - if (ost->enc_ctx && - (ost->enc_ctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) + if (ost->enc && + (ost->enc->enc_ctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) != AV_CODEC_FLAG_PASS1) pass1_used = 0; @@ -706,9 +723,9 @@ static void mux_final_stats(Muxer *mux) of->index, j, av_get_media_type_string(type)); if (ost->enc) { av_log(of, AV_LOG_VERBOSE, "%"PRIu64" frames encoded", - ost->frames_encoded); + ost->enc->frames_encoded); if (type == AVMEDIA_TYPE_AUDIO) - av_log(of, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ost->samples_encoded); + av_log(of, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ost->enc->samples_encoded); av_log(of, AV_LOG_VERBOSE, "; "); } @@ -806,7 +823,7 @@ static void ost_free(OutputStream **post) ost->logfile = NULL; } - avcodec_parameters_free(&ost->par_in); + avcodec_parameters_free(&ms->par_in); av_bsf_free(&ms->bsf_ctx); av_packet_free(&ms->bsf_pkt); @@ -820,10 +837,6 @@ static void ost_free(OutputStream **post) av_freep(&ost->attachment_filename); - if (ost->enc_ctx) - av_freep(&ost->enc_ctx->stats_in); - avcodec_free_context(&ost->enc_ctx); - enc_stats_uninit(&ost->enc_stats_pre); enc_stats_uninit(&ost->enc_stats_post); enc_stats_uninit(&ms->stats); diff --git a/fftools/ffmpeg_mux.h b/fftools/ffmpeg_mux.h index 22d728a91..4ca8ab73a 100644 --- a/fftools/ffmpeg_mux.h +++ b/fftools/ffmpeg_mux.h @@ -36,6 +36,12 @@ typedef struct MuxStream { OutputStream ost; + /** + * Codec parameters for packets submitted to the muxer (i.e. before + * bitstream filtering, if any). + */ + AVCodecParameters *par_in; + // name used for logging char log_name[32]; @@ -79,6 +85,10 @@ typedef struct MuxStream { int ts_drop; #endif + AVRational frame_rate; + AVRational max_frame_rate; + int force_fps; + const char *apad; } MuxStream; @@ -113,7 +123,7 @@ typedef struct Muxer { int mux_check_init(void *arg); -static MuxStream *ms_from_ost(OutputStream *ost) +static inline MuxStream *ms_from_ost(OutputStream *ost) { return (MuxStream*)ost; } diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index 2a014c8b9..7e51ce76a 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -67,8 +67,9 @@ static int check_opt_bitexact(void *ctx, const AVDictionary *opts, } static int choose_encoder(const OptionsContext *o, AVFormatContext *s, - OutputStream *ost, const AVCodec **enc) + MuxStream *ms, const AVCodec **enc) { + OutputStream *ost = &ms->ost; enum AVMediaType type = ost->type; const char *codec_name = NULL; @@ -90,20 +91,20 @@ static int choose_encoder(const OptionsContext *o, AVFormatContext *s, } if (!codec_name) { - ost->par_in->codec_id = av_guess_codec(s->oformat, NULL, s->url, NULL, ost->type); - *enc = avcodec_find_encoder(ost->par_in->codec_id); + ms->par_in->codec_id = av_guess_codec(s->oformat, NULL, s->url, NULL, ost->type); + *enc = avcodec_find_encoder(ms->par_in->codec_id); if (!*enc) { av_log(ost, AV_LOG_FATAL, "Automatic encoder selection failed " "Default encoder for format %s (codec %s) is " "probably disabled. Please choose an encoder manually.\n", - s->oformat->name, avcodec_get_name(ost->par_in->codec_id)); + s->oformat->name, avcodec_get_name(ms->par_in->codec_id)); return AVERROR_ENCODER_NOT_FOUND; } } else if (strcmp(codec_name, "copy")) { int ret = find_codec(ost, codec_name, ost->type, 1, enc); if (ret < 0) return ret; - ost->par_in->codec_id = (*enc)->id; + ms->par_in->codec_id = (*enc)->id; } return 0; @@ -423,27 +424,6 @@ static int ost_get_filters(const OptionsContext *o, AVFormatContext *oc, #endif opt_match_per_stream_str(ost, &o->filters, oc, ost->st, &filters); - if (!ost->enc) { - if ( -#if FFMPEG_OPT_FILTER_SCRIPT - filters_script || -#endif - filters) { - av_log(ost, AV_LOG_ERROR, - "%s '%s' was specified, but codec copy was selected. " - "Filtering and streamcopy cannot be used together.\n", -#if FFMPEG_OPT_FILTER_SCRIPT - filters ? "Filtergraph" : "Filtergraph script", - filters ? filters : filters_script -#else - "Filtergraph", filters -#endif - ); - return AVERROR(ENOSYS); - } - return 0; - } - if (!ost->ist) { if ( #if FFMPEG_OPT_FILTER_SCRIPT @@ -473,7 +453,7 @@ static int ost_get_filters(const OptionsContext *o, AVFormatContext *oc, } if (filters_script) - *dst = file_read(filters_script); + *dst = read_file_to_string(filters_script); else #endif if (filters) @@ -502,9 +482,9 @@ static int parse_matrix_coeffs(void *logctx, uint16_t *dest, const char *str) return 0; } -static int fmt_in_list(const int *formats, int format) +static int pixfmt_in_list(const enum AVPixelFormat *formats, enum AVPixelFormat format) { - for (; *formats != -1; formats++) + for (; *formats != AV_PIX_FMT_NONE; formats++) if (*formats == format) return 1; return 0; @@ -554,7 +534,7 @@ static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name) return AV_PIX_FMT_NONE; } - ret = avcodec_get_supported_config(ost->enc_ctx, NULL, AV_CODEC_CONFIG_PIX_FORMAT, + ret = avcodec_get_supported_config(ost->enc->enc_ctx, NULL, AV_CODEC_CONFIG_PIX_FORMAT, 0, (const void **) &fmts, NULL); if (ret < 0) return AV_PIX_FMT_NONE; @@ -564,7 +544,7 @@ static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name) * endianness by av_get_pix_fmt(); * the following code handles the case when the native endianness is not * supported by the encoder, but the other one is */ - if (fmts && !fmt_in_list(fmts, fmt)) { + if (fmts && !pixfmt_in_list(fmts, fmt)) { const char *name_canonical = av_get_pix_fmt_name(fmt); int len = strlen(name_canonical); @@ -577,7 +557,7 @@ static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name) snprintf(name_other, sizeof(name_other), "%s%ce", name, name_canonical[len - 2] == 'l' ? 'b' : 'l'); fmt_other = av_get_pix_fmt(name_other); - if (fmt_other != AV_PIX_FMT_NONE && fmt_in_list(fmts, fmt_other)) { + if (fmt_other != AV_PIX_FMT_NONE && pixfmt_in_list(fmts, fmt_other)) { av_log(ost, AV_LOG_VERBOSE, "Mapping pixel format %s->%s\n", name, name_other); fmt = fmt_other; @@ -585,8 +565,8 @@ static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name) } } - if (fmts && !fmt_in_list(fmts, fmt)) - fmt = choose_pixel_fmt(ost->enc_ctx, fmt); + if (fmts && !pixfmt_in_list(fmts, fmt)) + fmt = choose_pixel_fmt(ost->enc->enc_ctx, fmt); return fmt; } @@ -604,13 +584,13 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, st = ost->st; opt_match_per_stream_str(ost, &o->frame_rates, oc, st, &frame_rate); - if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) { + if (frame_rate && av_parse_video_rate(&ms->frame_rate, frame_rate) < 0) { av_log(ost, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate); return AVERROR(EINVAL); } opt_match_per_stream_str(ost, &o->max_frame_rates, oc, st, &max_frame_rate); - if (max_frame_rate && av_parse_video_rate(&ost->max_frame_rate, max_frame_rate) < 0) { + if (max_frame_rate && av_parse_video_rate(&ms->max_frame_rate, max_frame_rate) < 0) { av_log(ost, AV_LOG_FATAL, "Invalid maximum framerate value: %s\n", max_frame_rate); return AVERROR(EINVAL); } @@ -631,8 +611,8 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, ost->frame_aspect_ratio = q; } - if (ost->enc_ctx) { - AVCodecContext *video_enc = ost->enc_ctx; + if (ost->enc) { + AVCodecContext *video_enc = ost->enc->enc_ctx; const char *p = NULL, *fps_mode = NULL; const char *frame_size = NULL; const char *frame_pix_fmt = NULL; @@ -745,14 +725,19 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, ost->logfile_prefix ? ost->logfile_prefix : DEFAULT_PASS_LOGFILENAME_PREFIX, ost_idx); - if (!strcmp(ost->enc_ctx->codec->name, "libx264") || !strcmp(ost->enc_ctx->codec->name, "libvvenc")) { - if (av_opt_is_set_to_default_by_name(ost->enc_ctx, "stats", + if (!strcmp(video_enc->codec->name, "libx264") || !strcmp(video_enc->codec->name, "libvvenc")) { + if (av_opt_is_set_to_default_by_name(video_enc, "stats", AV_OPT_SEARCH_CHILDREN) > 0) - av_opt_set(ost->enc_ctx, "stats", logfilename, + av_opt_set(video_enc, "stats", logfilename, + AV_OPT_SEARCH_CHILDREN); + } else if (!strcmp(video_enc->codec->name, "libx265")) { + if (av_opt_is_set_to_default_by_name(video_enc, "x265-stats", + AV_OPT_SEARCH_CHILDREN) > 0) + av_opt_set(video_enc, "x265-stats", logfilename, AV_OPT_SEARCH_CHILDREN); } else { if (video_enc->flags & AV_CODEC_FLAG_PASS2) { - char *logbuffer = file_read(logfilename); + char *logbuffer = read_file_to_string(logfilename); if (!logbuffer) { av_log(ost, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n", @@ -774,7 +759,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, } } - opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ost->force_fps); + opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ms->force_fps); #if FFMPEG_OPT_TOP ost->top_field_first = -1; @@ -795,7 +780,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, return ret; } - if ((ost->frame_rate.num || ost->max_frame_rate.num) && + if ((ms->frame_rate.num || ms->max_frame_rate.num) && !(*vsync_method == VSYNC_AUTO || *vsync_method == VSYNC_CFR || *vsync_method == VSYNC_VSCFR)) { av_log(ost, AV_LOG_FATAL, "One of -r/-fpsmax was specified " @@ -804,7 +789,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, } if (*vsync_method == VSYNC_AUTO) { - if (ost->frame_rate.num || ost->max_frame_rate.num) { + if (ms->frame_rate.num || ms->max_frame_rate.num) { *vsync_method = VSYNC_CFR; } else if (!strcmp(oc->oformat->name, "avi")) { *vsync_method = VSYNC_VFR; @@ -841,8 +826,8 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o, AVFormatContext *oc = mux->fc; AVStream *st = ost->st; - if (ost->enc_ctx) { - AVCodecContext *audio_enc = ost->enc_ctx; + if (ost->enc) { + AVCodecContext *audio_enc = ost->enc->enc_ctx; int channels = 0; const char *layout = NULL; const char *sample_fmt = NULL; @@ -880,8 +865,8 @@ static int new_stream_subtitle(Muxer *mux, const OptionsContext *o, st = ost->st; - if (ost->enc_ctx) { - AVCodecContext *subtitle_enc = ost->enc_ctx; + if (ost->enc) { + AVCodecContext *subtitle_enc = ost->enc->enc_ctx; AVCodecDescriptor const *input_descriptor = avcodec_descriptor_get(ost->ist->par->codec_id); @@ -916,14 +901,16 @@ static int new_stream_subtitle(Muxer *mux, const OptionsContext *o, static int ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, - const OptionsContext *o, char *filters, + const OptionsContext *o, AVRational enc_tb, enum VideoSyncMethod vsync_method, int keep_pix_fmt, int autoscale, int threads_manual, - const ViewSpecifier *vs) + const ViewSpecifier *vs, + SchedulerNode *src) { OutputStream *ost = &ms->ost; - AVCodecContext *enc_ctx = ost->enc_ctx; + AVCodecContext *enc_ctx = ost->enc->enc_ctx; char name[16]; + char *filters = NULL; int ret; OutputFilterOptions opts = { @@ -935,7 +922,10 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, .height = enc_ctx->height, .color_space = enc_ctx->colorspace, .color_range = enc_ctx->color_range, + .alpha_mode = enc_ctx->alpha_mode, .vsync_method = vsync_method, + .frame_rate = ms->frame_rate, + .max_frame_rate = ms->max_frame_rate, .sample_rate = enc_ctx->sample_rate, .ch_layout = enc_ctx->ch_layout, .sws_opts = o->g->sws_dict, @@ -946,6 +936,7 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, .ts_offset = mux->of.start_time == AV_NOPTS_VALUE ? 0 : mux->of.start_time, .vs = vs, + .nb_threads = -1, .flags = OFILTER_FLAG_DISABLE_CONVERT * !!keep_pix_fmt | OFILTER_FLAG_AUTOSCALE * !!autoscale | @@ -958,11 +949,11 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, if (!keep_pix_fmt) { ret = avcodec_get_supported_config(enc_ctx, NULL, AV_CODEC_CONFIG_PIX_FORMAT, 0, - (const void **) &opts.formats, NULL); + (const void **) &opts.pix_fmts, NULL); if (ret < 0) return ret; } - if (!ost->force_fps) { + if (!ms->force_fps) { ret = avcodec_get_supported_config(enc_ctx, NULL, AV_CODEC_CONFIG_FRAME_RATE, 0, (const void **) &opts.frame_rates, NULL); @@ -979,10 +970,15 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, (const void **) &opts.color_ranges, NULL); if (ret < 0) return ret; + ret = avcodec_get_supported_config(enc_ctx, NULL, + AV_CODEC_CONFIG_ALPHA_MODE, 0, + (const void **) &opts.alpha_modes, NULL); + if (ret < 0) + return ret; } else { ret = avcodec_get_supported_config(enc_ctx, NULL, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, - (const void **) &opts.formats, NULL); + (const void **) &opts.sample_fmts, NULL); if (ret < 0) return ret; ret = avcodec_get_supported_config(enc_ctx, NULL, @@ -998,46 +994,77 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, } if (threads_manual) { - ret = av_opt_get(enc_ctx, "threads", 0, (uint8_t**)&opts.nb_threads); + ret = av_opt_get_int(enc_ctx, "threads", 0, &opts.nb_threads); if (ret < 0) return ret; } + ret = ost_get_filters(o, mux->fc, ost, &filters); + if (ret < 0) + return ret; + if (ofilter) { + av_assert0(!filters); ost->filter = ofilter; - ret = ofilter_bind_ost(ofilter, ost, ms->sch_idx_enc, &opts); + ret = ofilter_bind_enc(ofilter, ms->sch_idx_enc, &opts); } else { - ret = init_simple_filtergraph(ost->ist, ost, filters, - mux->sch, ms->sch_idx_enc, &opts); + ret = fg_create_simple(&ost->fg_simple, ost->ist, &filters, + mux->sch, ms->sch_idx_enc, &opts); + if (ret >= 0) + ost->filter = ost->fg_simple->outputs[0]; + } - av_freep(&opts.nb_threads); if (ret < 0) return ret; - ret = sch_connect(mux->sch, SCH_ENC(ms->sch_idx_enc), - SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); - if (ret < 0) - return ret; + *src = SCH_ENC(ms->sch_idx_enc); - return ret; + return 0; } -static int streamcopy_init(const Muxer *mux, OutputStream *ost, AVDictionary **encoder_opts) +static int streamcopy_init(const OptionsContext *o, const Muxer *mux, + OutputStream *ost, AVDictionary **encoder_opts) { MuxStream *ms = ms_from_ost(ost); const InputStream *ist = ost->ist; const InputFile *ifile = ist->file; - AVCodecParameters *par = ost->par_in; + AVCodecParameters *par = ms->par_in; uint32_t codec_tag = par->codec_tag; AVCodecContext *codec_ctx = NULL; - AVRational fr = ost->frame_rate; + AVRational fr = ms->frame_rate; int ret = 0; + const char *filters = NULL; +#if FFMPEG_OPT_FILTER_SCRIPT + const char *filters_script = NULL; + + opt_match_per_stream_str(ost, &o->filter_scripts, mux->fc, ost->st, &filters_script); +#endif + opt_match_per_stream_str(ost, &o->filters, mux->fc, ost->st, &filters); + + if ( +#if FFMPEG_OPT_FILTER_SCRIPT + filters_script || +#endif + filters) { + av_log(ost, AV_LOG_ERROR, + "%s '%s' was specified, but codec copy was selected. " + "Filtering and streamcopy cannot be used together.\n", +#if FFMPEG_OPT_FILTER_SCRIPT + filters ? "Filtergraph" : "Filtergraph script", + filters ? filters : filters_script +#else + "Filtergraph", filters +#endif + ); + return AVERROR(EINVAL); + } + codec_ctx = avcodec_alloc_context3(NULL); if (!codec_ctx) return AVERROR(ENOMEM); @@ -1139,6 +1166,28 @@ fail: return ret; } +static int set_encoder_id(OutputStream *ost, const AVCodec *codec) +{ + const char *cname = codec->name; + uint8_t *encoder_string; + int encoder_string_len; + + encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(cname) + 2; + encoder_string = av_mallocz(encoder_string_len); + if (!encoder_string) + return AVERROR(ENOMEM); + + if (!ost->file->bitexact && !ost->bitexact) + av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len); + else + av_strlcpy(encoder_string, "Lavc ", encoder_string_len); + av_strlcat(encoder_string, cname, encoder_string_len); + av_dict_set(&ost->st->metadata, "encoder", encoder_string, + AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE); + + return 0; +} + static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, InputStream *ist, OutputFilter *ofilter, const ViewSpecifier *vs, OutputStream **post) @@ -1148,13 +1197,14 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, OutputStream *ost; const AVCodec *enc; AVStream *st; + SchedulerNode src = { .type = SCH_NODE_TYPE_NONE }; AVDictionary *encoder_opts = NULL; int ret = 0, keep_pix_fmt = 0, autoscale = 1; int threads_manual = 0; AVRational enc_tb = { 0, 0 }; enum VideoSyncMethod vsync_method = VSYNC_AUTO; const char *bsfs = NULL, *time_base = NULL, *codec_tag = NULL; - char *filters = NULL, *next; + char *next; double qscale = -1; st = avformat_new_stream(oc, NULL); @@ -1198,8 +1248,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, } } - ost->par_in = avcodec_parameters_alloc(); - if (!ost->par_in) + ms->par_in = avcodec_parameters_alloc(); + if (!ms->par_in) return AVERROR(ENOMEM); ms->last_mux_dts = AV_NOPTS_VALUE; @@ -1207,27 +1257,23 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, ost->st = st; ost->ist = ist; ost->kf.ref_pts = AV_NOPTS_VALUE; - ost->par_in->codec_type = type; + ms->par_in->codec_type = type; st->codecpar->codec_type = type; - ret = choose_encoder(o, oc, ost, &enc); + ret = choose_encoder(o, oc, ms, &enc); if (ret < 0) { av_log(ost, AV_LOG_FATAL, "Error selecting an encoder\n"); return ret; } if (enc) { - ost->enc_ctx = avcodec_alloc_context3(enc); - if (!ost->enc_ctx) - return AVERROR(ENOMEM); - ret = sch_add_enc(mux->sch, encoder_thread, ost, ost->type == AVMEDIA_TYPE_SUBTITLE ? NULL : enc_open); if (ret < 0) return ret; ms->sch_idx_enc = ret; - ret = enc_alloc(&ost->enc, enc, mux->sch, ms->sch_idx_enc); + ret = enc_alloc(&ost->enc, enc, mux->sch, ms->sch_idx_enc, ost); if (ret < 0) return ret; @@ -1262,21 +1308,21 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (!ms->pkt) return AVERROR(ENOMEM); - if (ost->enc_ctx) { + if (ost->enc) { AVIOContext *s = NULL; char *buf = NULL, *arg = NULL; const char *enc_stats_pre = NULL, *enc_stats_post = NULL, *mux_stats = NULL; const char *enc_time_base = NULL, *preset = NULL; - ret = filter_codec_opts(o->g->codec_opts, ost->enc_ctx->codec_id, - oc, st, ost->enc_ctx->codec, &encoder_opts, + ret = filter_codec_opts(o->g->codec_opts, enc->id, + oc, st, enc, &encoder_opts, &mux->enc_opts_used); if (ret < 0) goto fail; opt_match_per_stream_str(ost, &o->presets, oc, st, &preset); opt_match_per_stream_int(ost, &o->autoscale, oc, st, &autoscale); - if (preset && (!(ret = get_preset_file_2(preset, ost->enc_ctx->codec->name, &s)))) { + if (preset && (!(ret = get_preset_file_2(preset, enc->name, &s)))) { AVBPrint bprint; av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED); do { @@ -1376,7 +1422,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, threads_manual = !!av_dict_get(encoder_opts, "threads", NULL, 0); - ret = av_opt_set_dict2(ost->enc_ctx, &encoder_opts, AV_OPT_SEARCH_CHILDREN); + ret = av_opt_set_dict2(ost->enc->enc_ctx, &encoder_opts, AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(ost, AV_LOG_ERROR, "Error applying encoder options: %s\n", av_err2str(ret)); @@ -1389,7 +1435,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, // default to automatic thread count if (!threads_manual) - ost->enc_ctx->thread_count = 0; + ost->enc->enc_ctx->thread_count = 0; } else { ret = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL, &encoder_opts, @@ -1401,8 +1447,14 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (o->bitexact) { ost->bitexact = 1; - } else if (ost->enc_ctx) { - ost->bitexact = !!(ost->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT); + } else if (ost->enc) { + ost->bitexact = !!(ost->enc->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT); + } + + if (enc) { + ret = set_encoder_id(ost, enc); + if (ret < 0) + return ret; } opt_match_per_stream_str(ost, &o->time_bases, oc, st, &time_base); @@ -1447,15 +1499,15 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, tag = AV_RL32(buf); } ost->st->codecpar->codec_tag = tag; - ost->par_in->codec_tag = tag; - if (ost->enc_ctx) - ost->enc_ctx->codec_tag = tag; + ms->par_in->codec_tag = tag; + if (ost->enc) + ost->enc->enc_ctx->codec_tag = tag; } opt_match_per_stream_dbl(ost, &o->qscale, oc, st, &qscale); - if (ost->enc_ctx && qscale >= 0) { - ost->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE; - ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale; + if (ost->enc && qscale >= 0) { + ost->enc->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE; + ost->enc->enc_ctx->global_quality = FF_QP2LAMBDA * qscale; } if (ms->sch_idx >= 0) { @@ -1477,8 +1529,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, opt_match_per_stream_int(ost, &o->fix_sub_duration_heartbeat, oc, st, &ost->fix_sub_duration_heartbeat); - if (oc->oformat->flags & AVFMT_GLOBALHEADER && ost->enc_ctx) - ost->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + if (oc->oformat->flags & AVFMT_GLOBALHEADER && ost->enc) + ost->enc->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; opt_match_per_stream_int(ost, &o->copy_initial_nonkeyframes, oc, st, &ms->copy_initial_nonkeyframes); @@ -1490,48 +1542,43 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (ret < 0) goto fail; - if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO) { - ret = ost_get_filters(o, oc, ost, &filters); - if (ret < 0) - goto fail; - } - if (ost->enc && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { - ret = ost_bind_filter(mux, ms, ofilter, o, filters, enc_tb, vsync_method, - keep_pix_fmt, autoscale, threads_manual, vs); + ret = ost_bind_filter(mux, ms, ofilter, o, enc_tb, vsync_method, + keep_pix_fmt, autoscale, threads_manual, vs, &src); if (ret < 0) goto fail; } else if (ost->ist) { - int sched_idx = ist_output_add(ost->ist, ost); - if (sched_idx < 0) { + ret = ist_use(ost->ist, !!ost->enc, NULL, &src); + if (ret < 0) { av_log(ost, AV_LOG_ERROR, "Error binding an input stream\n"); - ret = sched_idx; goto fail; } - ms->sch_idx_src = sched_idx; + ms->sch_idx_src = src.idx; + // src refers to a decoder for transcoding, demux stream otherwise if (ost->enc) { - ret = sch_connect(mux->sch, SCH_DEC_OUT(sched_idx, 0), - SCH_ENC(ms->sch_idx_enc)); - if (ret < 0) - goto fail; - - ret = sch_connect(mux->sch, SCH_ENC(ms->sch_idx_enc), - SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); - if (ret < 0) - goto fail; - } else { - ret = sch_connect(mux->sch, SCH_DSTREAM(ost->ist->file->index, sched_idx), - SCH_MSTREAM(ost->file->index, ms->sch_idx)); + ret = sch_connect(mux->sch, + src, SCH_ENC(ms->sch_idx_enc)); if (ret < 0) goto fail; + src = SCH_ENC(ms->sch_idx_enc); } } + if (src.type != SCH_NODE_TYPE_NONE) { + ret = sch_connect(mux->sch, + src, SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); + if (ret < 0) + goto fail; + } else { + // only attachment streams don't have a source + av_assert0(type == AVMEDIA_TYPE_ATTACHMENT && ms->sch_idx < 0); + } + if (ost->ist && !ost->enc) { - ret = streamcopy_init(mux, ost, &encoder_opts); + ret = streamcopy_init(o, mux, ost, &encoder_opts); if (ret < 0) goto fail; } @@ -1556,6 +1603,7 @@ fail: static int map_auto_video(Muxer *mux, const OptionsContext *o) { AVFormatContext *oc = mux->fc; + InputStreamGroup *best_istg = NULL; InputStream *best_ist = NULL; int64_t best_score = 0; int qcr; @@ -1567,14 +1615,49 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o) qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0); for (int j = 0; j < nb_input_files; j++) { InputFile *ifile = input_files[j]; + InputStreamGroup *file_best_istg = NULL; InputStream *file_best_ist = NULL; int64_t file_best_score = 0; + for (int i = 0; i < ifile->nb_stream_groups; i++) { + InputStreamGroup *istg = ifile->stream_groups[i]; + int64_t score = 0; + + if (!istg->fg) + continue; + + for (int j = 0; j < istg->stg->nb_streams; j++) { + AVStream *st = istg->stg->streams[j]; + + if (st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS) { + score = 100000000; + break; + } + } + + switch (istg->stg->type) { + case AV_STREAM_GROUP_PARAMS_TILE_GRID: { + const AVStreamGroupTileGrid *tg = istg->stg->params.tile_grid; + score += tg->width * (int64_t)tg->height + + 5000000*!!(istg->stg->disposition & AV_DISPOSITION_DEFAULT); + break; + } + default: + continue; + } + + if (score > file_best_score) { + file_best_score = score; + file_best_istg = istg; + } + } for (int i = 0; i < ifile->nb_streams; i++) { InputStream *ist = ifile->streams[i]; + const AVCodecDescriptor *desc = avcodec_descriptor_get(ist->st->codecpar->codec_id); int64_t score; if (ist->user_set_discard == AVDISCARD_ALL || - ist->st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) + ist->st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO || + (desc && (desc->props & AV_CODEC_PROP_ENHANCEMENT))) continue; score = ist->st->codecpar->width * (int64_t)ist->st->codecpar->height @@ -1588,6 +1671,15 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o) continue; file_best_score = score; file_best_ist = ist; + file_best_istg = NULL; + } + } + if (file_best_istg) { + file_best_score -= 5000000*!!(file_best_istg->stg->disposition & AV_DISPOSITION_DEFAULT); + if (file_best_score > best_score) { + best_score = file_best_score; + best_istg = file_best_istg; + best_ist = NULL; } } if (file_best_ist) { @@ -1597,9 +1689,19 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o) if (file_best_score > best_score) { best_score = file_best_score; best_ist = file_best_ist; + best_istg = NULL; } } } + if (best_istg) { + FilterGraph *fg = best_istg->fg; + OutputFilter *ofilter = fg->outputs[0]; + + av_assert0(fg->nb_outputs == 1); + av_log(mux, AV_LOG_VERBOSE, "Creating output stream from stream group derived complex filtergraph %d.\n", fg->index); + + return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, NULL, ofilter, NULL, NULL); + } if (best_ist) return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, best_ist, NULL, NULL, NULL); @@ -1799,6 +1901,7 @@ loop_end: static int of_add_attachments(Muxer *mux, const OptionsContext *o) { + MuxStream *ms; OutputStream *ost; int err; @@ -1866,9 +1969,11 @@ read_fail: return err; } + ms = ms_from_ost(ost); + ost->attachment_filename = attachment_filename; - ost->par_in->extradata = attachment; - ost->par_in->extradata_size = len; + ms->par_in->extradata = attachment; + ms->par_in->extradata_size = len; p = strrchr(o->attachments[i], '/'); av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE); @@ -2009,7 +2114,7 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int limit_frames = 0, limit_frames_av_enc = 0; #define IS_AV_ENC(ost, type) \ - (ost->enc_ctx && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) + (ost->enc && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) #define IS_INTERLEAVED(type) (type != AVMEDIA_TYPE_ATTACHMENT) for (int i = 0; i < oc->nb_streams; i++) { @@ -2021,8 +2126,8 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, nb_interleaved += IS_INTERLEAVED(type); nb_av_enc += IS_AV_ENC(ost, type); - nb_audio_fs += (ost->enc_ctx && type == AVMEDIA_TYPE_AUDIO && - !(ost->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)); + nb_audio_fs += (ost->enc && type == AVMEDIA_TYPE_AUDIO && + !(ost->enc->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)); limit_frames |= ms->max_frames < INT64_MAX; limit_frames_av_enc |= (ms->max_frames < INT64_MAX) && IS_AV_ENC(ost, type); @@ -2977,9 +3082,6 @@ static int copy_meta(Muxer *mux, const OptionsContext *o) if (!ost->ist) /* this is true e.g. for attached files */ continue; av_dict_copy(&ost->st->metadata, ost->ist->st->metadata, AV_DICT_DONT_OVERWRITE); - if (ost->enc_ctx) { - av_dict_set(&ost->st->metadata, "encoder", NULL, 0); - } } return 0; @@ -3056,7 +3158,7 @@ finish: return ret; } -const char *const forced_keyframes_const_names[] = { +static const char *const forced_keyframes_const_names[] = { "n", "n_forced", "prev_forced_n", @@ -3158,7 +3260,7 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o) mux->fc, ost->st, &forced_keyframes); if (!(ost->type == AVMEDIA_TYPE_VIDEO && - ost->enc_ctx && forced_keyframes)) + ost->enc && forced_keyframes)) continue; if (!strncmp(forced_keyframes, "expr:", 5)) { @@ -3184,6 +3286,8 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o) "-force_key_frames is deprecated, use just 'source'\n"); ost->kf.type = KF_FORCE_SOURCE; #endif + } else if (!strcmp(forced_keyframes, "scd_metadata")) { + ost->kf.type = KF_FORCE_SCD_METADATA; } else { int ret = parse_forced_key_frames(ost, &ost->kf, mux, forced_keyframes); if (ret < 0) @@ -3385,7 +3489,7 @@ int of_open(const OptionsContext *o, const char *filename, Scheduler *sch) OutputStream *ost = of->streams[i]; if (!ost->enc) { - err = of_stream_init(of, ost); + err = of_stream_init(of, ost, NULL); if (err < 0) return err; } diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 71e7f1467..a2566193b 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -47,12 +47,12 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/stereo3d.h" +#include "graph/graphprint.h" HWDevice *filter_hw_device; char *vstats_filename; -float audio_drift_threshold = 0.1; float dts_delta_threshold = 10; float dts_error_threshold = 3600*30; @@ -75,7 +75,11 @@ int stdin_interaction = 1; float max_error_rate = 2.0/3; char *filter_nbthreads; int filter_complex_nbthreads = 0; +int filter_buffered_frames = 0; int vstats_version = 2; +int print_graphs = 0; +char *print_graphs_file = NULL; +char *print_graphs_format = NULL; int auto_conversion_filters = 1; int64_t stats_period = 500000; @@ -86,6 +90,15 @@ int ignore_unknown_streams = 0; int copy_unknown_streams = 0; int recast_media = 0; +// this struct is passed as the optctx argument +// to func_arg() for global options +typedef struct GlobalOptionsContext { + Scheduler *sch; + + char **filtergraphs; + int nb_filtergraphs; +} GlobalOptionsContext; + static void uninit_options(OptionsContext *o) { /* all OPT_SPEC and OPT_TYPE_STRING can be freed in generic way */ @@ -229,6 +242,70 @@ OPT_MATCH_PER_STREAM(int, int, OPT_TYPE_INT, i); OPT_MATCH_PER_STREAM(int64, int64_t, OPT_TYPE_INT64, i64); OPT_MATCH_PER_STREAM(dbl, double, OPT_TYPE_DOUBLE, dbl); +static unsigned opt_match_per_stream_group(void *logctx, enum OptionType type, + const SpecifierOptList *sol, + AVFormatContext *fc, AVStreamGroup *stg) +{ + int matches = 0, match_idx = -1; + + av_assert0((type == sol->type) || !sol->nb_opt); + + for (int i = 0; i < sol->nb_opt; i++) { + const StreamSpecifier *ss = &sol->opt[i].stream_spec; + + if (stream_group_specifier_match(ss, fc, stg, logctx)) { + match_idx = i; + matches++; + } + } + + if (matches > 1 && sol->opt_canon) { + const SpecifierOpt *so = &sol->opt[match_idx]; + const char *spec = so->specifier && so->specifier[0] ? so->specifier : ""; + + char namestr[128] = ""; + char optval_buf[32]; + const char *optval = optval_buf; + + snprintf(namestr, sizeof(namestr), "-%s", sol->opt_canon->name); + if (sol->opt_canon->flags & OPT_HAS_ALT) { + const char * const *names_alt = sol->opt_canon->u1.names_alt; + for (int i = 0; names_alt[i]; i++) + av_strlcatf(namestr, sizeof(namestr), "/-%s", names_alt[i]); + } + + switch (sol->type) { + case OPT_TYPE_STRING: optval = so->u.str; break; + case OPT_TYPE_INT: snprintf(optval_buf, sizeof(optval_buf), "%d", so->u.i); break; + case OPT_TYPE_INT64: snprintf(optval_buf, sizeof(optval_buf), "%"PRId64, so->u.i64); break; + case OPT_TYPE_FLOAT: snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.f); break; + case OPT_TYPE_DOUBLE: snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.dbl); break; + default: av_assert0(0); + } + + av_log(logctx, AV_LOG_WARNING, "Multiple %s options specified for " + "stream group %d, only the last option '-%s%s%s %s' will be used.\n", + namestr, stg->index, sol->opt_canon->name, spec[0] ? ":" : "", + spec, optval); + } + + return match_idx + 1; +} + +#define OPT_MATCH_PER_STREAM_GROUP(name, type, opt_type, m) \ +void opt_match_per_stream_group_ ## name(void *logctx, const SpecifierOptList *sol, \ + AVFormatContext *fc, AVStreamGroup *stg, type *out) \ +{ \ + unsigned ret = opt_match_per_stream_group(logctx, opt_type, sol, fc, stg); \ + if (ret > 0) \ + *out = sol->opt[ret - 1].u.m; \ +} + +OPT_MATCH_PER_STREAM_GROUP(str, const char *, OPT_TYPE_STRING, str); +OPT_MATCH_PER_STREAM_GROUP(int, int, OPT_TYPE_INT, i); +OPT_MATCH_PER_STREAM_GROUP(int64, int64_t, OPT_TYPE_INT64, i64); +OPT_MATCH_PER_STREAM_GROUP(dbl, double, OPT_TYPE_DOUBLE, dbl); + int view_specifier_parse(const char **pspec, ViewSpecifier *vs) { const char *spec = *pspec; @@ -282,7 +359,7 @@ int view_specifier_parse(const char **pspec, ViewSpecifier *vs) return 0; } -int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global) +int parse_and_set_vsync(const char *arg, enum VideoSyncMethod *vsync_var, int file_idx, int st_idx, int is_global) { if (!av_strcasecmp(arg, "cfr")) *vsync_var = VSYNC_CFR; else if (!av_strcasecmp(arg, "vfr")) *vsync_var = VSYNC_VFR; @@ -345,7 +422,7 @@ static void correct_input_start_times(void) if (copy_ts && start_at_zero) ifile->ts_offset = -new_start_time; else if (!copy_ts) { - abs_start_seek = is->start_time + (ifile->start_time != AV_NOPTS_VALUE) ? ifile->start_time : 0; + abs_start_seek = is->start_time + ((ifile->start_time != AV_NOPTS_VALUE) ? ifile->start_time : 0); ifile->ts_offset = abs_start_seek > new_start_time ? -abs_start_seek : -new_start_time; } else if (copy_ts) ifile->ts_offset = 0; @@ -491,8 +568,10 @@ static int opt_map(void *optctx, const char *opt, const char *arg) } if (arg[0] == '[') { + ViewSpecifier vs; /* this mapping refers to lavfi output */ const char *c = arg + 1; + char *endptr; ret = GROW_ARRAY(o->stream_maps, o->nb_stream_maps); if (ret < 0) @@ -505,6 +584,27 @@ static int opt_map(void *optctx, const char *opt, const char *arg) ret = AVERROR(EINVAL); goto fail; } + + arg++; + + m->group_index = -1; + file_idx = strtol(arg, &endptr, 0); + if (file_idx >= nb_input_files || file_idx < 0) + goto end; + + arg = endptr; + ret = stream_specifier_parse(&ss, *arg == ':' ? arg + 1 : arg, 1, NULL); + if (ret < 0) + goto end; + + arg = ss.remainder ? ss.remainder : ""; + ret = view_specifier_parse(&arg, &vs); + if (ret < 0 || (*arg && strcmp(arg, "]"))) + goto end; + + m->file_index = file_idx; + m->stream_index = ss.idx; + m->group_index = ss.stream_list == STREAM_LIST_GROUP_IDX ? ss.list_id : -1; } else { ViewSpecifier vs; char *endptr; @@ -572,6 +672,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg) m->file_index = file_idx; m->stream_index = i; + m->group_index = ss.stream_list == STREAM_LIST_GROUP_IDX ? ss.list_id : -1; m->vs = vs; } } @@ -591,6 +692,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg) goto fail; } } +end: ret = 0; fail: stream_specifier_uninit(&ss); @@ -613,8 +715,8 @@ static int opt_attach(void *optctx, const char *opt, const char *arg) static int opt_sdp_file(void *optctx, const char *opt, const char *arg) { - Scheduler *sch = optctx; - return sch_sdp_filename(sch, arg); + GlobalOptionsContext *go = optctx; + return sch_sdp_filename(go->sch, arg); } #if CONFIG_VAAPI @@ -1046,7 +1148,8 @@ static int opt_preset(void *optctx, const char *opt, const char *arg) else if (!strcmp(key, "vcodec")) opt_video_codec (o, key, value); else if (!strcmp(key, "scodec")) opt_subtitle_codec(o, key, value); else if (!strcmp(key, "dcodec")) opt_data_codec (o, key, value); - else if (opt_default_new(o, key, value) < 0) { + else if ((parse_option(o, key, value, options) < 0) && + (opt_default_new(o, key, value) < 0)) { av_log(NULL, AV_LOG_FATAL, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, key, value); ret = AVERROR(EINVAL); @@ -1160,26 +1263,46 @@ static int opt_audio_qscale(void *optctx, const char *opt, const char *arg) static int opt_filter_complex(void *optctx, const char *opt, const char *arg) { - Scheduler *sch = optctx; - char *graph_desc = av_strdup(arg); + GlobalOptionsContext *go = optctx; + char *graph_desc; + int ret; + + graph_desc = av_strdup(arg); if (!graph_desc) return AVERROR(ENOMEM); - return fg_create(NULL, graph_desc, sch); + ret = GROW_ARRAY(go->filtergraphs, go->nb_filtergraphs); + if (ret < 0) { + av_freep(&graph_desc); + return ret; + } + go->filtergraphs[go->nb_filtergraphs - 1] = graph_desc; + + return 0; } #if FFMPEG_OPT_FILTER_SCRIPT static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg) { - Scheduler *sch = optctx; - char *graph_desc = file_read(arg); + GlobalOptionsContext *go = optctx; + char *graph_desc; + int ret; + + graph_desc = read_file_to_string(arg); if (!graph_desc) return AVERROR(EINVAL); av_log(NULL, AV_LOG_WARNING, "-%s is deprecated, use -/filter_complex %s instead\n", opt, arg); - return fg_create(NULL, graph_desc, sch); + ret = GROW_ARRAY(go->filtergraphs, go->nb_filtergraphs); + if (ret < 0) { + av_freep(&graph_desc); + return ret; + } + go->filtergraphs[go->nb_filtergraphs - 1] = graph_desc; + + return 0; } #endif @@ -1356,6 +1479,7 @@ static int open_files(OptionGroupList *l, const char *inout, Scheduler *sch, int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch) { + GlobalOptionsContext go = { .sch = sch }; OptionParseContext octx; const char *errmsg = NULL; int ret; @@ -1371,7 +1495,7 @@ int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch) } /* apply global options */ - ret = parse_optgroup(sch, &octx.global_opts, options); + ret = parse_optgroup(&go, &octx.global_opts, options); if (ret < 0) { errmsg = "parsing global options"; goto fail; @@ -1380,6 +1504,14 @@ int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch) /* configure terminal and setup signal handlers */ term_init(); + /* create complex filtergraphs */ + for (int i = 0; i < go.nb_filtergraphs; i++) { + ret = fg_create(NULL, &go.filtergraphs[i], sch, NULL); + go.filtergraphs[i] = NULL; + if (ret < 0) + goto fail; + } + /* open input files */ ret = open_files(&octx.groups[GROUP_INFILE], "input", sch, ifile_open); if (ret < 0) { @@ -1415,6 +1547,10 @@ int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch) goto fail; fail: + for (int i = 0; i < go.nb_filtergraphs; i++) + av_freep(&go.filtergraphs[i]); + av_freep(&go.filtergraphs); + uninit_parse_context(&octx); if (ret < 0 && ret != AVERROR_EXIT) { av_log(NULL, AV_LOG_FATAL, "Error %s: %s\n", @@ -1476,7 +1612,6 @@ static int opt_adrift_threshold(void *optctx, const char *opt, const char *arg) } #endif -static const char *const alt_bsf[] = { "absf", "vbsf", NULL }; static const char *const alt_channel_layout[] = { "ch_layout", NULL}; static const char *const alt_codec[] = { "c", "acodec", "vcodec", "scodec", "dcodec", NULL }; static const char *const alt_filter[] = { "af", "vf", NULL }; @@ -1608,6 +1743,9 @@ const OptionDef options[] = { { "readrate_initial_burst", OPT_TYPE_DOUBLE, OPT_OFFSET | OPT_EXPERT | OPT_INPUT, { .off = OFFSET(readrate_initial_burst) }, "The initial amount of input to burst read before imposing any readrate", "seconds" }, + { "readrate_catchup", OPT_TYPE_FLOAT, OPT_OFFSET | OPT_EXPERT | OPT_INPUT, + { .off = OFFSET(readrate_catchup) }, + "Temporary readrate used to catch up if an input lags behind the specified readrate", "speed" }, { "target", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_PERFILE | OPT_EXPERT | OPT_OUTPUT, { .func_arg = opt_target }, "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\" or \"dv50\" " @@ -1677,6 +1815,9 @@ const OptionDef options[] = { { "filter_threads", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT, { .func_arg = opt_filter_threads }, "number of non-complex filter threads" }, + { "filter_buffered_frames", OPT_TYPE_INT, OPT_EXPERT, + { &filter_buffered_frames }, + "maximum number of buffered frames in a filter graph" }, #if FFMPEG_OPT_FILTER_SCRIPT { "filter_script", OPT_TYPE_STRING, OPT_PERSTREAM | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(filter_scripts) }, @@ -1685,6 +1826,9 @@ const OptionDef options[] = { { "reinit_filter", OPT_TYPE_INT, OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT, { .off = OFFSET(reinit_filters) }, "reinit filtergraph on input parameter changes", "" }, + { "drop_changed", OPT_TYPE_INT, OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT, + { .off = OFFSET(drop_changed) }, + "drop frame instead of reiniting filtergraph on input parameter changes", "" }, { "filter_complex", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex }, "create a complex filtergraph", "graph_description" }, @@ -1699,6 +1843,15 @@ const OptionDef options[] = { { .func_arg = opt_filter_complex_script }, "deprecated, use -/filter_complex instead", "filename" }, #endif + { "print_graphs", OPT_TYPE_BOOL, 0, + { &print_graphs }, + "print execution graph data to stderr" }, + { "print_graphs_file", OPT_TYPE_STRING, 0, + { &print_graphs_file }, + "write execution graph data to the specified file", "filename" }, + { "print_graphs_format", OPT_TYPE_STRING, 0, + { &print_graphs_format }, + "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml, mermaid, mermaidhtml)", "format" }, { "auto_conversion_filters", OPT_TYPE_BOOL, OPT_EXPERT, { &auto_conversion_filters }, "enable automatic conversion filters globally" }, diff --git a/fftools/ffmpeg_sched.c b/fftools/ffmpeg_sched.c index 6b338409a..517ff1ea8 100644 --- a/fftools/ffmpeg_sched.c +++ b/fftools/ffmpeg_sched.c @@ -189,7 +189,6 @@ typedef struct PreMuxQueue { typedef struct SchMuxStream { SchedulerNode src; - SchedulerNode src_sched; unsigned *sub_heartbeat_dst; unsigned nb_sub_heartbeat_dst; @@ -235,7 +234,6 @@ typedef struct SchMux { typedef struct SchFilterIn { SchedulerNode src; - SchedulerNode src_sched; int send_finished; int receive_finished; } SchFilterIn; @@ -249,7 +247,7 @@ typedef struct SchFilterGraph { SchFilterIn *inputs; unsigned nb_inputs; - atomic_uint nb_inputs_finished_send; + unsigned nb_inputs_finished_send; unsigned nb_inputs_finished_receive; SchFilterOut *outputs; @@ -285,8 +283,9 @@ struct Scheduler { pthread_mutex_t mux_ready_lock; unsigned nb_mux_done; - pthread_mutex_t mux_done_lock; - pthread_cond_t mux_done_cond; + unsigned task_failed; + pthread_mutex_t finish_lock; + pthread_cond_t finish_cond; SchDec *dec; @@ -306,7 +305,6 @@ struct Scheduler { enum SchedulerState state; atomic_int terminate; - atomic_int task_failed; pthread_mutex_t schedule_lock; @@ -375,7 +373,6 @@ static int queue_alloc(ThreadQueue **ptq, unsigned nb_streams, unsigned queue_si enum QueueType type) { ThreadQueue *tq; - ObjPool *op; if (queue_size <= 0) { if (type == QUEUE_FRAMES) @@ -390,21 +387,14 @@ static int queue_alloc(ThreadQueue **ptq, unsigned nb_streams, unsigned queue_si // for frames held in queues inside the ffmpeg utility. If this // can ever dynamically change then the corresponding decode // code needs to be updated as well. - av_assert0(queue_size == DEFAULT_FRAME_THREAD_QUEUE_SIZE); + av_assert0(queue_size <= DEFAULT_FRAME_THREAD_QUEUE_SIZE); } - op = (type == QUEUE_PACKETS) ? objpool_alloc_packets() : - objpool_alloc_frames(); - if (!op) + tq = tq_alloc(nb_streams, queue_size, + (type == QUEUE_PACKETS) ? THREAD_QUEUE_PACKETS : THREAD_QUEUE_FRAMES); + if (!tq) return AVERROR(ENOMEM); - tq = tq_alloc(nb_streams, queue_size, op, - (type == QUEUE_PACKETS) ? pkt_move : frame_move); - if (!tq) { - objpool_free(&op); - return AVERROR(ENOMEM); - } - *ptq = tq; return 0; } @@ -415,6 +405,9 @@ static int task_start(SchTask *task) { int ret; + if (!task->parent) + return 0; + av_log(task->func_arg, AV_LOG_VERBOSE, "Starting thread...\n"); av_assert0(!task->thread_running); @@ -464,6 +457,23 @@ static int64_t trailing_dts(const Scheduler *sch, int count_finished) return min_dts == INT64_MAX ? AV_NOPTS_VALUE : min_dts; } +void sch_remove_filtergraph(Scheduler *sch, int idx) +{ + SchFilterGraph *fg = &sch->filters[idx]; + + av_assert0(!fg->task.thread_running); + memset(&fg->task, 0, sizeof(fg->task)); + + tq_free(&fg->queue); + + av_freep(&fg->inputs); + fg->nb_inputs = 0; + av_freep(&fg->outputs); + fg->nb_outputs = 0; + + fg->task_exited = 1; +} + void sch_free(Scheduler **psch) { Scheduler *sch = *psch; @@ -571,8 +581,8 @@ void sch_free(Scheduler **psch) pthread_mutex_destroy(&sch->mux_ready_lock); - pthread_mutex_destroy(&sch->mux_done_lock); - pthread_cond_destroy(&sch->mux_done_cond); + pthread_mutex_destroy(&sch->finish_lock); + pthread_cond_destroy(&sch->finish_cond); av_freep(psch); } @@ -602,11 +612,11 @@ Scheduler *sch_alloc(void) if (ret) goto fail; - ret = pthread_mutex_init(&sch->mux_done_lock, NULL); + ret = pthread_mutex_init(&sch->finish_lock, NULL); if (ret) goto fail; - ret = pthread_cond_init(&sch->mux_done_cond, NULL); + ret = pthread_cond_init(&sch->finish_cond, NULL); if (ret) goto fail; @@ -1111,22 +1121,52 @@ static int mux_task_start(SchMux *mux) return ret; /* flush the pre-muxing queues */ - for (unsigned i = 0; i < mux->nb_streams; i++) { - SchMuxStream *ms = &mux->streams[i]; + while (1) { + int min_stream = -1; + Timestamp min_ts = { .ts = AV_NOPTS_VALUE }; + AVPacket *pkt; - while (av_fifo_read(ms->pre_mux_queue.fifo, &pkt, 1) >= 0) { + // find the stream with the earliest dts or EOF in pre-muxing queue + for (unsigned i = 0; i < mux->nb_streams; i++) { + SchMuxStream *ms = &mux->streams[i]; + + if (av_fifo_peek(ms->pre_mux_queue.fifo, &pkt, 1, 0) < 0) + continue; + + if (!pkt || pkt->dts == AV_NOPTS_VALUE) { + min_stream = i; + break; + } + + if (min_ts.ts == AV_NOPTS_VALUE || + av_compare_ts(min_ts.ts, min_ts.tb, pkt->dts, pkt->time_base) > 0) { + min_stream = i; + min_ts = (Timestamp){ .ts = pkt->dts, .tb = pkt->time_base }; + } + } + + if (min_stream >= 0) { + SchMuxStream *ms = &mux->streams[min_stream]; + + ret = av_fifo_read(ms->pre_mux_queue.fifo, &pkt, 1); + av_assert0(ret >= 0); + if (pkt) { if (!ms->init_eof) - ret = tq_send(mux->queue, i, pkt); + ret = tq_send(mux->queue, min_stream, pkt); av_packet_free(&pkt); if (ret == AVERROR_EOF) ms->init_eof = 1; else if (ret < 0) return ret; } else - tq_send_finish(mux->queue, i); + tq_send_finish(mux->queue, min_stream); + + continue; } + + break; } atomic_store(&mux->mux_started, 1); @@ -1272,11 +1312,11 @@ static void unchoke_downstream(Scheduler *sch, SchedulerNode *dst) } else { // ensure that this filter graph is not stuck waiting for // input from a different upstream demuxer - unchoke_for_stream(sch, fg->inputs[fg->best_input].src_sched); + unchoke_for_stream(sch, fg->inputs[fg->best_input].src); } break; default: - av_assert0(!"Invalid destination node type?"); + av_unreachable("Invalid destination node type?"); break; } } @@ -1285,29 +1325,67 @@ static void unchoke_for_stream(Scheduler *sch, SchedulerNode src) { while (1) { SchFilterGraph *fg; - - // fed directly by a demuxer (i.e. not through a filtergraph) - if (src.type == SCH_NODE_TYPE_DEMUX) { - SchDemux *demux = &sch->demux[src.idx]; + SchDemux *demux; + switch (src.type) { + case SCH_NODE_TYPE_DEMUX: + // fed directly by a demuxer (i.e. not through a filtergraph) + demux = &sch->demux[src.idx]; if (demux->waiter.choked_next == 0) return; // prevent infinite loop demux->waiter.choked_next = 0; for (int i = 0; i < demux->nb_streams; i++) unchoke_downstream(sch, demux->streams[i].dst); return; - } - - av_assert0(src.type == SCH_NODE_TYPE_FILTER_OUT); - fg = &sch->filters[src.idx]; - - // the filtergraph contains internal sources and - // requested to be scheduled directly - if (fg->best_input == fg->nb_inputs) { - fg->waiter.choked_next = 0; + case SCH_NODE_TYPE_DEC: + src = sch->dec[src.idx].src; + continue; + case SCH_NODE_TYPE_ENC: + src = sch->enc[src.idx].src; + continue; + case SCH_NODE_TYPE_FILTER_OUT: + fg = &sch->filters[src.idx]; + // the filtergraph contains internal sources and + // requested to be scheduled directly + if (fg->best_input == fg->nb_inputs) { + fg->waiter.choked_next = 0; + return; + } + src = fg->inputs[fg->best_input].src; + continue; + default: + av_unreachable("Invalid source node type?"); return; } + } +} - src = fg->inputs[fg->best_input].src_sched; +static void choke_demux(const Scheduler *sch, int demux_id, int choked) +{ + av_assert1(demux_id < sch->nb_demux); + SchDemux *demux = &sch->demux[demux_id]; + + for (int i = 0; i < demux->nb_streams; i++) { + SchedulerNode *dst = demux->streams[i].dst; + SchFilterGraph *fg; + + switch (dst->type) { + case SCH_NODE_TYPE_DEC: + tq_choke(sch->dec[dst->idx].queue, choked); + break; + case SCH_NODE_TYPE_ENC: + tq_choke(sch->enc[dst->idx].queue, choked); + break; + case SCH_NODE_TYPE_MUX: + break; + case SCH_NODE_TYPE_FILTER_IN: + fg = &sch->filters[dst->idx]; + if (fg->nb_inputs == 1) + tq_choke(fg->queue, choked); + break; + default: + av_unreachable("Invalid destination node type?"); + break; + } } } @@ -1350,11 +1428,23 @@ static void schedule_update_locked(Scheduler *sch) continue; // resolve the source to unchoke - unchoke_for_stream(sch, ms->src_sched); + unchoke_for_stream(sch, ms->src); have_unchoked = 1; } } + // also unchoke any sources feeding into closed filter graph inputs, so + // that they can observe the downstream EOF + for (unsigned i = 0; i < sch->nb_filters; i++) { + SchFilterGraph *fg = &sch->filters[i]; + + for (unsigned j = 0; j < fg->nb_inputs; j++) { + SchFilterIn *fi = &fg->inputs[j]; + if (fi->receive_finished && !fi->send_finished) + unchoke_for_stream(sch, fi->src); + } + } + // make sure to unchoke at least one source, if still available for (unsigned type = 0; !have_unchoked && type < 2; type++) for (unsigned i = 0; i < (type ? sch->nb_filters : sch->nb_demux); i++) { @@ -1367,13 +1457,16 @@ static void schedule_update_locked(Scheduler *sch) } } - - for (unsigned type = 0; type < 2; type++) + for (unsigned type = 0; type < 2; type++) { for (unsigned i = 0; i < (type ? sch->nb_filters : sch->nb_demux); i++) { SchWaiter *w = type ? &sch->filters[i].waiter : &sch->demux[i].waiter; - if (w->choked_prev != w->choked_next) + if (w->choked_prev != w->choked_next) { waiter_set(w, w->choked_next); + if (!type) + choke_demux(sch, i, w->choked_next); + } } + } } @@ -1383,6 +1476,27 @@ enum { CYCLE_NODE_DONE, }; +// Finds the filtergraph or muxer upstream of a scheduler node +static SchedulerNode src_filtergraph(const Scheduler *sch, SchedulerNode src) +{ + while (1) { + switch (src.type) { + case SCH_NODE_TYPE_DEMUX: + case SCH_NODE_TYPE_FILTER_OUT: + return src; + case SCH_NODE_TYPE_DEC: + src = sch->dec[src.idx].src; + continue; + case SCH_NODE_TYPE_ENC: + src = sch->enc[src.idx].src; + continue; + default: + av_unreachable("Invalid source node type?"); + return (SchedulerNode) {0}; + } + } +} + static int check_acyclic_for_output(const Scheduler *sch, SchedulerNode src, uint8_t *filters_visited, SchedulerNode *filters_stack) @@ -1399,22 +1513,23 @@ check_acyclic_for_output(const Scheduler *sch, SchedulerNode src, // descend into every input, depth first if (src.idx_stream < fg->nb_inputs) { const SchFilterIn *fi = &fg->inputs[src.idx_stream++]; + SchedulerNode node = src_filtergraph(sch, fi->src); // connected to demuxer, no cycles possible - if (fi->src_sched.type == SCH_NODE_TYPE_DEMUX) + if (node.type == SCH_NODE_TYPE_DEMUX) continue; // otherwise connected to another filtergraph - av_assert0(fi->src_sched.type == SCH_NODE_TYPE_FILTER_OUT); + av_assert0(node.type == SCH_NODE_TYPE_FILTER_OUT); // found a cycle - if (filters_visited[fi->src_sched.idx] == CYCLE_NODE_STARTED) + if (filters_visited[node.idx] == CYCLE_NODE_STARTED) return AVERROR(EINVAL); // place current position on stack and descend av_assert0(nb_filters_stack < sch->nb_filters); filters_stack[nb_filters_stack++] = src; - src = (SchedulerNode){ .idx = fi->src_sched.idx, .idx_stream = 0 }; + src = (SchedulerNode){ .idx = node.idx, .idx_stream = 0 }; continue; } @@ -1536,22 +1651,7 @@ static int start_prepare(Scheduler *sch) for (unsigned j = 0; j < mux->nb_streams; j++) { SchMuxStream *ms = &mux->streams[j]; - switch (ms->src.type) { - case SCH_NODE_TYPE_ENC: { - SchEnc *enc = &sch->enc[ms->src.idx]; - if (enc->src.type == SCH_NODE_TYPE_DEC) { - ms->src_sched = sch->dec[enc->src.idx].src; - av_assert0(ms->src_sched.type == SCH_NODE_TYPE_DEMUX); - } else { - ms->src_sched = enc->src; - av_assert0(ms->src_sched.type == SCH_NODE_TYPE_FILTER_OUT); - } - break; - } - case SCH_NODE_TYPE_DEMUX: - ms->src_sched = ms->src; - break; - default: + if (!ms->src.type) { av_log(mux, AV_LOG_ERROR, "Muxer stream #%u not connected to a source\n", j); return AVERROR(EINVAL); @@ -1569,26 +1669,12 @@ static int start_prepare(Scheduler *sch) for (unsigned j = 0; j < fg->nb_inputs; j++) { SchFilterIn *fi = &fg->inputs[j]; - SchDec *dec; if (!fi->src.type) { av_log(fg, AV_LOG_ERROR, "Filtergraph input %u not connected to a source\n", j); return AVERROR(EINVAL); } - - if (fi->src.type == SCH_NODE_TYPE_FILTER_OUT) - fi->src_sched = fi->src; - else { - av_assert0(fi->src.type == SCH_NODE_TYPE_DEC); - dec = &sch->dec[fi->src.idx]; - - switch (dec->src.type) { - case SCH_NODE_TYPE_DEMUX: fi->src_sched = dec->src; break; - case SCH_NODE_TYPE_ENC: fi->src_sched = sch->enc[dec->src.idx].src; break; - default: av_assert0(0); - } - } } for (unsigned j = 0; j < fg->nb_outputs; j++) { @@ -1678,29 +1764,27 @@ fail: int sch_wait(Scheduler *sch, uint64_t timeout_us, int64_t *transcode_ts) { - int ret, err; + int ret; // convert delay to absolute timestamp timeout_us += av_gettime(); - pthread_mutex_lock(&sch->mux_done_lock); + pthread_mutex_lock(&sch->finish_lock); if (sch->nb_mux_done < sch->nb_mux) { struct timespec tv = { .tv_sec = timeout_us / 1000000, .tv_nsec = (timeout_us % 1000000) * 1000 }; - pthread_cond_timedwait(&sch->mux_done_cond, &sch->mux_done_lock, &tv); + pthread_cond_timedwait(&sch->finish_cond, &sch->finish_lock, &tv); } - ret = sch->nb_mux_done == sch->nb_mux; + // abort transcoding if any task failed + ret = sch->nb_mux_done == sch->nb_mux || sch->task_failed; - pthread_mutex_unlock(&sch->mux_done_lock); + pthread_mutex_unlock(&sch->finish_lock); *transcode_ts = atomic_load(&sch->last_dts); - // abort transcoding if any task failed - err = atomic_load(&sch->task_failed); - - return ret || err; + return ret; } static int enc_open(Scheduler *sch, SchEnc *enc, const AVFrame *frame) @@ -1860,7 +1944,7 @@ static int mux_queue_packet(SchMux *mux, SchMuxStream *ms, AVPacket *pkt) if (new_size <= packets) { av_log(mux, AV_LOG_ERROR, "Too many packets buffered for output stream.\n"); - return AVERROR(ENOSPC); + return AVERROR_BUFFER_TOO_SMALL; } ret = av_fifo_grow2(q->fifo, new_size - packets); if (ret < 0) @@ -1923,7 +2007,7 @@ static int send_to_mux(Scheduler *sch, SchMux *mux, unsigned stream_idx, update_schedule: // TODO: use atomics to check whether this changes trailing dts - // to avoid locking unnecesarily + // to avoid locking unnecessarily if (dts != AV_NOPTS_VALUE || !pkt) { pthread_mutex_lock(&sch->schedule_lock); @@ -2166,14 +2250,14 @@ static int mux_done(Scheduler *sch, unsigned mux_idx) pthread_mutex_unlock(&sch->schedule_lock); - pthread_mutex_lock(&sch->mux_done_lock); + pthread_mutex_lock(&sch->finish_lock); av_assert0(sch->nb_mux_done < sch->nb_mux); sch->nb_mux_done++; - pthread_cond_signal(&sch->mux_done_cond); + pthread_cond_signal(&sch->finish_cond); - pthread_mutex_unlock(&sch->mux_done_lock); + pthread_mutex_unlock(&sch->finish_lock); return 0; } @@ -2213,14 +2297,20 @@ static int send_to_filter(Scheduler *sch, SchFilterGraph *fg, if (frame) return tq_send(fg->queue, in_idx, frame); + pthread_mutex_lock(&sch->schedule_lock); + if (!fg->inputs[in_idx].send_finished) { fg->inputs[in_idx].send_finished = 1; tq_send_finish(fg->queue, in_idx); // close the control stream when all actual inputs are done - if (atomic_fetch_add(&fg->nb_inputs_finished_send, 1) == fg->nb_inputs - 1) + if (++fg->nb_inputs_finished_send == fg->nb_inputs) tq_send_finish(fg->queue, fg->nb_inputs); + + schedule_update_locked(sch); } + + pthread_mutex_unlock(&sch->schedule_lock); return 0; } @@ -2471,6 +2561,8 @@ void sch_filter_receive_finish(Scheduler *sch, unsigned fg_idx, unsigned in_idx) av_assert0(in_idx < fg->nb_inputs); fi = &fg->inputs[in_idx]; + pthread_mutex_lock(&sch->schedule_lock); + if (!fi->receive_finished) { fi->receive_finished = 1; tq_receive_finish(fg->queue, in_idx); @@ -2478,13 +2570,18 @@ void sch_filter_receive_finish(Scheduler *sch, unsigned fg_idx, unsigned in_idx) // close the control stream when all actual inputs are done if (++fg->nb_inputs_finished_receive == fg->nb_inputs) tq_receive_finish(fg->queue, fg->nb_inputs); + + schedule_update_locked(sch); } + + pthread_mutex_unlock(&sch->schedule_lock); } int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, AVFrame *frame) { SchFilterGraph *fg; SchedulerNode dst; + int ret; av_assert0(fg_idx < sch->nb_filters); fg = &sch->filters[fg_idx]; @@ -2492,9 +2589,16 @@ int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, AVFrame * av_assert0(out_idx < fg->nb_outputs); dst = fg->outputs[out_idx].dst; - return (dst.type == SCH_NODE_TYPE_ENC) ? - send_to_enc (sch, &sch->enc[dst.idx], frame) : - send_to_filter(sch, &sch->filters[dst.idx], dst.idx_stream, frame); + if (dst.type == SCH_NODE_TYPE_ENC) { + ret = send_to_enc(sch, &sch->enc[dst.idx], frame); + if (ret == AVERROR_EOF) + send_to_enc(sch, &sch->enc[dst.idx], NULL); + } else { + ret = send_to_filter(sch, &sch->filters[dst.idx], dst.idx_stream, frame); + if (ret == AVERROR_EOF) + send_to_filter(sch, &sch->filters[dst.idx], dst.idx_stream, NULL); + } + return ret; } static int filter_done(Scheduler *sch, unsigned fg_idx) @@ -2536,6 +2640,18 @@ int sch_filter_command(Scheduler *sch, unsigned fg_idx, AVFrame *frame) return send_to_filter(sch, fg, fg->nb_inputs, frame); } +void sch_filter_choke_inputs(Scheduler *sch, unsigned fg_idx) +{ + SchFilterGraph *fg; + av_assert0(fg_idx < sch->nb_filters); + fg = &sch->filters[fg_idx]; + + pthread_mutex_lock(&sch->schedule_lock); + fg->best_input = fg->nb_inputs; + schedule_update_locked(sch); + pthread_mutex_unlock(&sch->schedule_lock); +} + static int task_cleanup(Scheduler *sch, SchedulerNode node) { switch (node.type) { @@ -2544,7 +2660,7 @@ static int task_cleanup(Scheduler *sch, SchedulerNode node) case SCH_NODE_TYPE_DEC: return dec_done (sch, node.idx); case SCH_NODE_TYPE_ENC: return enc_done (sch, node.idx); case SCH_NODE_TYPE_FILTER_IN: return filter_done(sch, node.idx); - default: av_assert0(0); + default: av_unreachable("Invalid node type?"); } } @@ -2566,8 +2682,12 @@ static void *task_wrapper(void *arg) // EOF is considered normal termination if (ret == AVERROR_EOF) ret = 0; - if (ret < 0) - atomic_store(&sch->task_failed, 1); + if (ret < 0) { + pthread_mutex_lock(&sch->finish_lock); + sch->task_failed = 1; + pthread_cond_signal(&sch->finish_cond); + pthread_mutex_unlock(&sch->finish_lock); + } av_log(task->func_arg, ret < 0 ? AV_LOG_ERROR : AV_LOG_VERBOSE, "Terminating thread with return code %d (%s)\n", ret, @@ -2581,6 +2701,9 @@ static int task_stop(Scheduler *sch, SchTask *task) int ret; void *thread_ret; + if (!task->parent) + return 0; + if (!task->thread_running) return task_cleanup(sch, task->node); @@ -2605,6 +2728,8 @@ int sch_stop(Scheduler *sch, int64_t *finish_ts) for (unsigned i = 0; i < (type ? sch->nb_demux : sch->nb_filters); i++) { SchWaiter *w = type ? &sch->demux[i].waiter : &sch->filters[i].waiter; waiter_set(w, 1); + if (type) + choke_demux(sch, i, 0); // unfreeze to allow draining } for (unsigned i = 0; i < sch->nb_demux; i++) { diff --git a/fftools/ffmpeg_sched.h b/fftools/ffmpeg_sched.h index 3062c4a6e..2cf303443 100644 --- a/fftools/ffmpeg_sched.h +++ b/fftools/ffmpeg_sched.h @@ -205,6 +205,8 @@ int sch_add_dec_output(Scheduler *sch, unsigned dec_idx); int sch_add_filtergraph(Scheduler *sch, unsigned nb_inputs, unsigned nb_outputs, SchThreadFunc func, void *ctx); +void sch_remove_filtergraph(Scheduler *sch, int idx); + /** * Add a muxer to the scheduler. * @@ -257,7 +259,7 @@ int sch_add_mux(Scheduler *sch, SchThreadFunc func, int (*init)(void *), /** * Default size of a frame thread queue. */ -#define DEFAULT_FRAME_THREAD_QUEUE_SIZE 8 +#define DEFAULT_FRAME_THREAD_QUEUE_SIZE 2 /** * Add a muxed stream for a previously added muxer. @@ -355,7 +357,7 @@ enum DemuxSendFlags { * @retval "non-negative value" success * @retval AVERROR_EOF all consumers for the stream are done * @retval AVERROR_EXIT all consumers are done, should terminate demuxing - * @retval "anoter negative error code" other failure + * @retval "another negative error code" other failure */ int sch_demux_send(Scheduler *sch, unsigned demux_idx, struct AVPacket *pkt, unsigned flags); @@ -436,13 +438,20 @@ void sch_filter_receive_finish(Scheduler *sch, unsigned fg_idx, unsigned in_idx) * * @retval "non-negative value" success * @retval AVERROR_EOF all consumers are done - * @retval "anoter negative error code" other failure + * @retval "another negative error code" other failure */ int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, struct AVFrame *frame); int sch_filter_command(Scheduler *sch, unsigned fg_idx, struct AVFrame *frame); +/** + * Called by filtergraph tasks to choke all filter inputs, preventing them from + * receiving more frames until woken up again by the scheduler. Used during + * initial graph configuration to avoid unnecessary buffering. + */ +void sch_filter_choke_inputs(Scheduler *sch, unsigned fg_idx); + /** * Called by encoder tasks to obtain frames for encoding. Will wait for a frame * to become available and return it in frame. diff --git a/fftools/ffmpeg_utils.h b/fftools/ffmpeg_utils.h index 7939e44cd..9ca3afffa 100644 --- a/fftools/ffmpeg_utils.h +++ b/fftools/ffmpeg_utils.h @@ -44,14 +44,20 @@ static inline int err_merge(int err0, int err1) return (err0 < 0) ? err0 : FFMIN(err1, 0); } -static inline void pkt_move(void *dst, void *src) +/** + * Wrapper calling av_frame_side_data_clone() in a loop for all source entries. + * It does not clear dst beforehand. */ +static inline int clone_side_data(AVFrameSideData ***dst, int *nb_dst, + AVFrameSideData * const *src, int nb_src, + unsigned int flags) { - av_packet_move_ref(dst, src); -} + for (int i = 0; i < nb_src; i++) { + int ret = av_frame_side_data_clone(dst, nb_dst, src[i], flags); + if (ret < 0) + return ret; + } -static inline void frame_move(void *dst, void *src) -{ - av_frame_move_ref(dst, src); + return 0; } #endif // FFTOOLS_FFMPEG_UTILS_H diff --git a/fftools/ffplay.c b/fftools/ffplay.c index 96b0b614b..8d519191a 100644 --- a/fftools/ffplay.c +++ b/fftools/ffplay.c @@ -37,6 +37,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/dict.h" #include "libavutil/fifo.h" +#include "libavutil/parseutils.h" #include "libavutil/samplefmt.h" #include "libavutil/time.h" #include "libavutil/bprint.h" @@ -267,6 +268,7 @@ typedef struct VideoState { AVComplexFloat *rdft_data; int xpos; double last_vis_time; + RenderParams render_params; SDL_Texture *vis_texture; SDL_Texture *sub_texture; SDL_Texture *vid_texture; @@ -350,6 +352,7 @@ static int find_stream_info = 1; static int filter_nbthreads = 0; static int enable_vulkan = 0; static char *vulkan_params = NULL; +static char *video_background = NULL; static const char *hwaccel = NULL; /* current context */ @@ -388,7 +391,6 @@ static const struct TextureFormatEntry { { AV_PIX_FMT_YUV420P, SDL_PIXELFORMAT_IYUV }, { AV_PIX_FMT_YUYV422, SDL_PIXELFORMAT_YUY2 }, { AV_PIX_FMT_UYVY422, SDL_PIXELFORMAT_UYVY }, - { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_UNKNOWN }, }; static int opt_add_vfilter(void *optctx, const char *opt, const char *arg) @@ -895,7 +897,7 @@ static void get_sdl_pix_fmt_and_blendmode(int format, Uint32 *sdl_pix_fmt, SDL_B format == AV_PIX_FMT_BGR32 || format == AV_PIX_FMT_BGR32_1) *sdl_blendmode = SDL_BLENDMODE_BLEND; - for (i = 0; i < FF_ARRAY_ELEMS(sdl_texture_format_map) - 1; i++) { + for (i = 0; i < FF_ARRAY_ELEMS(sdl_texture_format_map); i++) { if (format == sdl_texture_format_map[i].format) { *sdl_pix_fmt = sdl_texture_format_map[i].texture_fmt; return; @@ -941,7 +943,11 @@ static enum AVColorSpace sdl_supported_color_spaces[] = { AVCOL_SPC_BT709, AVCOL_SPC_BT470BG, AVCOL_SPC_SMPTE170M, - AVCOL_SPC_UNSPECIFIED, +}; + +static enum AVAlphaMode sdl_supported_alpha_modes[] = { + AVALPHA_MODE_UNSPECIFIED, + AVALPHA_MODE_STRAIGHT, }; static void set_sdl_yuv_conversion_mode(AVFrame *frame) @@ -960,15 +966,52 @@ static void set_sdl_yuv_conversion_mode(AVFrame *frame) #endif } +static void draw_video_background(VideoState *is) +{ + const int tile_size = VIDEO_BACKGROUND_TILE_SIZE; + SDL_Rect *rect = &is->render_params.target_rect; + SDL_BlendMode blendMode; + + if (!SDL_GetTextureBlendMode(is->vid_texture, &blendMode) && blendMode == SDL_BLENDMODE_BLEND) { + switch (is->render_params.video_background_type) { + case VIDEO_BACKGROUND_TILES: + SDL_SetRenderDrawColor(renderer, 237, 237, 237, 255); + fill_rectangle(rect->x, rect->y, rect->w, rect->h); + SDL_SetRenderDrawColor(renderer, 222, 222, 222, 255); + for (int x = 0; x < rect->w; x += tile_size * 2) + fill_rectangle(rect->x + x, rect->y, FFMIN(tile_size, rect->w - x), rect->h); + for (int y = 0; y < rect->h; y += tile_size * 2) + fill_rectangle(rect->x, rect->y + y, rect->w, FFMIN(tile_size, rect->h - y)); + SDL_SetRenderDrawColor(renderer, 237, 237, 237, 255); + for (int y = 0; y < rect->h; y += tile_size * 2) { + int h = FFMIN(tile_size, rect->h - y); + for (int x = 0; x < rect->w; x += tile_size * 2) + fill_rectangle(x + rect->x, y + rect->y, FFMIN(tile_size, rect->w - x), h); + } + break; + case VIDEO_BACKGROUND_COLOR: { + const uint8_t *c = is->render_params.video_background_color; + SDL_SetRenderDrawColor(renderer, c[0], c[1], c[2], c[3]); + fill_rectangle(rect->x, rect->y, rect->w, rect->h); + break; + } + case VIDEO_BACKGROUND_NONE: + SDL_SetTextureBlendMode(is->vid_texture, SDL_BLENDMODE_NONE); + break; + } + } +} + static void video_image_display(VideoState *is) { Frame *vp; Frame *sp = NULL; - SDL_Rect rect; + SDL_Rect *rect = &is->render_params.target_rect; vp = frame_queue_peek_last(&is->pictq); + calculate_display_rect(rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar); if (vk_renderer) { - vk_renderer_display(vk_renderer, vp->frame); + vk_renderer_display(vk_renderer, vp->frame, &is->render_params); return; } @@ -1017,7 +1060,6 @@ static void video_image_display(VideoState *is) } } - calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar); set_sdl_yuv_conversion_mode(vp->frame); if (!vp->uploaded) { @@ -1029,15 +1071,16 @@ static void video_image_display(VideoState *is) vp->flip_v = vp->frame->linesize[0] < 0; } - SDL_RenderCopyEx(renderer, is->vid_texture, NULL, &rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0); + draw_video_background(is); + SDL_RenderCopyEx(renderer, is->vid_texture, NULL, rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0); set_sdl_yuv_conversion_mode(NULL); if (sp) { #if USE_ONEPASS_SUBTITLE_RENDER - SDL_RenderCopy(renderer, is->sub_texture, NULL, &rect); + SDL_RenderCopy(renderer, is->sub_texture, NULL, rect); #else int i; - double xratio = (double)rect.w / (double)sp->width; - double yratio = (double)rect.h / (double)sp->height; + double xratio = (double)rect->w / (double)sp->width; + double yratio = (double)rect->h / (double)sp->height; for (i = 0; i < sp->sub.num_rects; i++) { SDL_Rect *sub_rect = (SDL_Rect*)sp->sub.rects[i]; SDL_Rect target = {.x = rect.x + sub_rect->x * xratio, @@ -1861,7 +1904,6 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c { enum AVPixelFormat pix_fmts[FF_ARRAY_ELEMS(sdl_texture_format_map)]; char sws_flags_str[512] = ""; - char buffersrc_args[256]; int ret; AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL; AVCodecParameters *codecpar = is->video_st->codecpar; @@ -1875,14 +1917,13 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c return AVERROR(ENOMEM); for (i = 0; i < renderer_info.num_texture_formats; i++) { - for (j = 0; j < FF_ARRAY_ELEMS(sdl_texture_format_map) - 1; j++) { + for (j = 0; j < FF_ARRAY_ELEMS(sdl_texture_format_map); j++) { if (renderer_info.texture_formats[i] == sdl_texture_format_map[j].texture_fmt) { pix_fmts[nb_pix_fmts++] = sdl_texture_format_map[j].format; break; } } } - pix_fmts[nb_pix_fmts] = AV_PIX_FMT_NONE; while ((e = av_dict_iterate(sws_dict, e))) { if (!strcmp(e->key, "sws_flags")) { @@ -1895,36 +1936,55 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c graph->scale_sws_opts = av_strdup(sws_flags_str); - snprintf(buffersrc_args, sizeof(buffersrc_args), - "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d:" - "colorspace=%d:range=%d", - frame->width, frame->height, frame->format, - is->video_st->time_base.num, is->video_st->time_base.den, - codecpar->sample_aspect_ratio.num, FFMAX(codecpar->sample_aspect_ratio.den, 1), - frame->colorspace, frame->color_range); - if (fr.num && fr.den) - av_strlcatf(buffersrc_args, sizeof(buffersrc_args), ":frame_rate=%d/%d", fr.num, fr.den); - if ((ret = avfilter_graph_create_filter(&filt_src, - avfilter_get_by_name("buffer"), - "ffplay_buffer", buffersrc_args, NULL, - graph)) < 0) + filt_src = avfilter_graph_alloc_filter(graph, avfilter_get_by_name("buffer"), + "ffplay_buffer"); + if (!filt_src) { + ret = AVERROR(ENOMEM); goto fail; + } + + par->format = frame->format; + par->time_base = is->video_st->time_base; + par->width = frame->width; + par->height = frame->height; + par->sample_aspect_ratio = codecpar->sample_aspect_ratio; + par->color_space = frame->colorspace; + par->color_range = frame->color_range; + par->alpha_mode = frame->alpha_mode; + par->frame_rate = fr; par->hw_frames_ctx = frame->hw_frames_ctx; ret = av_buffersrc_parameters_set(filt_src, par); if (ret < 0) goto fail; - ret = avfilter_graph_create_filter(&filt_out, - avfilter_get_by_name("buffersink"), - "ffplay_buffersink", NULL, NULL, graph); + ret = avfilter_init_dict(filt_src, NULL); if (ret < 0) goto fail; - if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) + filt_out = avfilter_graph_alloc_filter(graph, avfilter_get_by_name("buffersink"), + "ffplay_buffersink"); + if (!filt_out) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if ((ret = av_opt_set_array(filt_out, "pixel_formats", AV_OPT_SEARCH_CHILDREN, + 0, nb_pix_fmts, AV_OPT_TYPE_PIXEL_FMT, pix_fmts)) < 0) goto fail; if (!vk_renderer && - (ret = av_opt_set_int_list(filt_out, "color_spaces", sdl_supported_color_spaces, AVCOL_SPC_UNSPECIFIED, AV_OPT_SEARCH_CHILDREN)) < 0) + (ret = av_opt_set_array(filt_out, "colorspaces", AV_OPT_SEARCH_CHILDREN, + 0, FF_ARRAY_ELEMS(sdl_supported_color_spaces), + AV_OPT_TYPE_INT, sdl_supported_color_spaces)) < 0) + goto fail; + + if ((ret = av_opt_set_array(filt_out, "alphamodes", AV_OPT_SEARCH_CHILDREN, + 0, FF_ARRAY_ELEMS(sdl_supported_alpha_modes), + AV_OPT_TYPE_INT, sdl_supported_alpha_modes)) < 0) + goto fail; + + ret = avfilter_init_dict(filt_out, NULL); + if (ret < 0) goto fail; last_filter = filt_out; @@ -1994,8 +2054,6 @@ fail: static int configure_audio_filters(VideoState *is, const char *afilters, int force_output_format) { - static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }; - int sample_rates[2] = { 0, -1 }; AVFilterContext *filt_asrc = NULL, *filt_asink = NULL; char aresample_swr_opts[512] = ""; const AVDictionaryEntry *e = NULL; @@ -2029,30 +2087,28 @@ static int configure_audio_filters(VideoState *is, const char *afilters, int for if (ret < 0) goto end; - - ret = avfilter_graph_create_filter(&filt_asink, - avfilter_get_by_name("abuffersink"), "ffplay_abuffersink", - NULL, NULL, is->agraph); - if (ret < 0) + filt_asink = avfilter_graph_alloc_filter(is->agraph, avfilter_get_by_name("abuffersink"), + "ffplay_abuffersink"); + if (!filt_asink) { + ret = AVERROR(ENOMEM); goto end; + } - if ((ret = av_opt_set_int_list(filt_asink, "sample_fmts", sample_fmts, AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) - goto end; - if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0) + if ((ret = av_opt_set(filt_asink, "sample_formats", "s16", AV_OPT_SEARCH_CHILDREN)) < 0) goto end; if (force_output_format) { - av_bprint_clear(&bp); - av_channel_layout_describe_bprint(&is->audio_tgt.ch_layout, &bp); - sample_rates [0] = is->audio_tgt.freq; - if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 0, AV_OPT_SEARCH_CHILDREN)) < 0) + if ((ret = av_opt_set_array(filt_asink, "channel_layouts", AV_OPT_SEARCH_CHILDREN, + 0, 1, AV_OPT_TYPE_CHLAYOUT, &is->audio_tgt.ch_layout)) < 0) goto end; - if ((ret = av_opt_set(filt_asink, "ch_layouts", bp.str, AV_OPT_SEARCH_CHILDREN)) < 0) - goto end; - if ((ret = av_opt_set_int_list(filt_asink, "sample_rates" , sample_rates , -1, AV_OPT_SEARCH_CHILDREN)) < 0) + if ((ret = av_opt_set_array(filt_asink, "samplerates", AV_OPT_SEARCH_CHILDREN, + 0, 1, AV_OPT_TYPE_INT, &is->audio_tgt.freq)) < 0) goto end; } + ret = avfilter_init_dict(filt_asink, NULL); + if (ret < 0) + goto end; if ((ret = configure_filtergraph(is->agraph, afilters, filt_asrc, filt_asink)) < 0) goto end; @@ -2827,6 +2883,7 @@ static int read_thread(void *arg) int st_index[AVMEDIA_TYPE_NB]; AVPacket *pkt = NULL; int64_t stream_start_time; + char metadata_description[96]; int pkt_in_play_range = 0; const AVDictionaryEntry *t; SDL_mutex *wait_mutex = SDL_CreateMutex(); @@ -2934,8 +2991,10 @@ static int read_thread(void *arg) is->realtime = is_realtime(ic); - if (show_status) + if (show_status) { + fprintf(stderr, "\x1b[2K\r"); av_dump_format(ic, 0, is->filename, 0); + } for (i = 0; i < ic->nb_streams; i++) { AVStream *st = ic->streams[i]; @@ -2944,6 +3003,9 @@ static int read_thread(void *arg) if (type >= 0 && wanted_stream_spec[type] && st_index[type] == -1) if (avformat_match_stream_specifier(ic, st, wanted_stream_spec[type]) > 0) st_index[type] = i; + // Clear all pre-existing metadata update flags to avoid printing + // initial metadata as update. + st->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED; } for (i = 0; i < AVMEDIA_TYPE_NB; i++) { if (wanted_stream_spec[i] && st_index[i] == -1) { @@ -3112,6 +3174,19 @@ static int read_thread(void *arg) } else { is->eof = 0; } + + if (show_status && ic->streams[pkt->stream_index]->event_flags & + AVSTREAM_EVENT_FLAG_METADATA_UPDATED) { + fprintf(stderr, "\x1b[2K\r"); + snprintf(metadata_description, + sizeof(metadata_description), + "\r New metadata for stream %d", + pkt->stream_index); + dump_dictionary(NULL, ic->streams[pkt->stream_index]->metadata, + metadata_description, " ", AV_LOG_INFO); + } + ic->streams[pkt->stream_index]->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED; + /* check if packet is in play range specified by user, then queue, otherwise discard */ stream_start_time = ic->streams[pkt->stream_index]->start_time; pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts; @@ -3193,6 +3268,16 @@ static VideoState *stream_open(const char *filename, av_log(NULL, AV_LOG_WARNING, "-volume=%d < 0, setting to 0\n", startup_volume); if (startup_volume > 100) av_log(NULL, AV_LOG_WARNING, "-volume=%d > 100, setting to 100\n", startup_volume); + if (video_background) { + if (!strcmp(video_background, "none")) { + is->render_params.video_background_type = VIDEO_BACKGROUND_NONE; + } else if (strcmp(video_background, "tiles")) { + if (av_parse_color(is->render_params.video_background_color, video_background, -1, NULL) >= 0) + is->render_params.video_background_type = VIDEO_BACKGROUND_COLOR; + else + goto fail; + } + } startup_volume = av_clip(startup_volume, 0, 100); startup_volume = av_clip(SDL_MIX_MAXVOLUME * startup_volume / 100, 0, SDL_MIX_MAXVOLUME); is->audio_volume = startup_volume; @@ -3706,6 +3791,7 @@ static const OptionDef options[] = { { "filter_threads", OPT_TYPE_INT, OPT_EXPERT, { &filter_nbthreads }, "number of filter threads per graph" }, { "enable_vulkan", OPT_TYPE_BOOL, 0, { &enable_vulkan }, "enable vulkan renderer" }, { "vulkan_params", OPT_TYPE_STRING, OPT_EXPERT, { &vulkan_params }, "vulkan configuration using a list of key=value pairs separated by ':'" }, + { "video_bg", OPT_TYPE_STRING, OPT_EXPERT, { &video_background }, "set video background for transparent videos" }, { "hwaccel", OPT_TYPE_STRING, OPT_EXPERT, { &hwaccel }, "use HW accelerated decoding" }, { NULL, }, }; @@ -3740,9 +3826,9 @@ void show_help_default(const char *opt, const char *arg) "c cycle program\n" "w cycle video filters or show modes\n" "s activate frame-step mode\n" - "left/right seek backward/forward 10 seconds or to custom interval if -seek_interval is set\n" + "left/right seek backward/forward by 10 seconds or a custom interval if -seek_interval is set\n" "down/up seek backward/forward 1 minute\n" - "page down/page up seek backward/forward 10 minutes\n" + "page down/page up seek to previous/next chapter or backward/forward 10 minutes if no chapters\n" "right mouse click seek to percentage in file corresponding to fraction of width\n" "left double-click toggle full screen\n" ); diff --git a/fftools/ffplay_renderer.c b/fftools/ffplay_renderer.c index f272cb46f..e7fa7197c 100644 --- a/fftools/ffplay_renderer.c +++ b/fftools/ffplay_renderer.c @@ -43,6 +43,7 @@ #include "libavutil/bprint.h" #include "libavutil/mem.h" +#include "libavutil/internal.h" #endif @@ -53,7 +54,7 @@ struct VkRenderer { int (*get_hw_dev)(VkRenderer *renderer, AVBufferRef **dev); - int (*display)(VkRenderer *renderer, AVFrame *frame); + int (*display)(VkRenderer *renderer, AVFrame *frame, RenderParams *params); int (*resize)(VkRenderer *renderer, int width, int height); @@ -104,36 +105,6 @@ static void vk_log_cb(void *log_priv, enum pl_log_level level, av_log(log_priv, level_map[level], "%s\n", msg); } -// Should keep sync with optional_device_exts inside hwcontext_vulkan.c -static const char *optional_device_exts[] = { - /* Misc or required by other extensions */ - VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME, - VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, - VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, - VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME, - VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME, - VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME, - VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME, - - /* Imports/exports */ - VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, - VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, - VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, - VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, - VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, -#ifdef _WIN32 - VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, - VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, -#endif - - /* Video encoding/decoding */ - VK_KHR_VIDEO_QUEUE_EXTENSION_NAME, - VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME, - VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME, - VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME, - "VK_MESA_video_decode_av1", -}; - static inline int enable_debug(const AVDictionary *opt) { AVDictionaryEntry *entry = av_dict_get(opt, "debug", NULL, 0); @@ -145,14 +116,22 @@ static void hwctx_lock_queue(void *priv, uint32_t qf, uint32_t qidx) { AVHWDeviceContext *avhwctx = priv; const AVVulkanDeviceContext *hwctx = avhwctx->hwctx; +#if FF_API_VULKAN_SYNC_QUEUES +FF_DISABLE_DEPRECATION_WARNINGS hwctx->lock_queue(avhwctx, qf, qidx); +FF_ENABLE_DEPRECATION_WARNINGS +#endif } static void hwctx_unlock_queue(void *priv, uint32_t qf, uint32_t qidx) { AVHWDeviceContext *avhwctx = priv; const AVVulkanDeviceContext *hwctx = avhwctx->hwctx; +#if FF_API_VULKAN_SYNC_QUEUES +FF_DISABLE_DEPRECATION_WARNINGS hwctx->unlock_queue(avhwctx, qf, qidx); +FF_ENABLE_DEPRECATION_WARNINGS +#endif } static int add_instance_extension(const char **ext, unsigned num_ext, @@ -259,8 +238,8 @@ static int create_vk_by_hwcontext(VkRenderer *renderer, ctx->get_proc_addr = hwctx->get_proc_addr; ctx->inst = hwctx->inst; - ctx->placebo_vulkan = pl_vulkan_import(ctx->vk_log, - pl_vulkan_import_params( + + struct pl_vulkan_import_params import_params = { .instance = hwctx->inst, .get_proc_addr = hwctx->get_proc_addr, .phys_device = hwctx->phys_dev, @@ -272,18 +251,36 @@ static int create_vk_by_hwcontext(VkRenderer *renderer, .unlock_queue = hwctx_unlock_queue, .queue_ctx = dev, .queue_graphics = { - .index = hwctx->queue_family_index, - .count = hwctx->nb_graphics_queues, + .index = VK_QUEUE_FAMILY_IGNORED, + .count = 0, }, .queue_compute = { - .index = hwctx->queue_family_comp_index, - .count = hwctx->nb_comp_queues, + .index = VK_QUEUE_FAMILY_IGNORED, + .count = 0, }, .queue_transfer = { - .index = hwctx->queue_family_tx_index, - .count = hwctx->nb_tx_queues, + .index = VK_QUEUE_FAMILY_IGNORED, + .count = 0, }, - )); + }; + for (int i = 0; i < hwctx->nb_qf; i++) { + const AVVulkanDeviceQueueFamily *qf = &hwctx->qf[i]; + + if (qf->flags & VK_QUEUE_GRAPHICS_BIT) { + import_params.queue_graphics.index = qf->idx; + import_params.queue_graphics.count = qf->num; + } + if (qf->flags & VK_QUEUE_COMPUTE_BIT) { + import_params.queue_compute.index = qf->idx; + import_params.queue_compute.count = qf->num; + } + if (qf->flags & VK_QUEUE_TRANSFER_BIT) { + import_params.queue_transfer.index = qf->idx; + import_params.queue_transfer.count = qf->num; + } + } + + ctx->placebo_vulkan = pl_vulkan_import(ctx->vk_log, &import_params); if (!ctx->placebo_vulkan) return AVERROR_EXTERNAL; @@ -295,7 +292,11 @@ static void placebo_lock_queue(struct AVHWDeviceContext *dev_ctx, { RendererContext *ctx = dev_ctx->user_opaque; pl_vulkan vk = ctx->placebo_vulkan; +#if FF_API_VULKAN_SYNC_QUEUES +FF_DISABLE_DEPRECATION_WARNINGS vk->lock_queue(vk, queue_family, index); +FF_ENABLE_DEPRECATION_WARNINGS +#endif } static void placebo_unlock_queue(struct AVHWDeviceContext *dev_ctx, @@ -304,7 +305,11 @@ static void placebo_unlock_queue(struct AVHWDeviceContext *dev_ctx, { RendererContext *ctx = dev_ctx->user_opaque; pl_vulkan vk = ctx->placebo_vulkan; +#if FF_API_VULKAN_SYNC_QUEUES +FF_DISABLE_DEPRECATION_WARNINGS vk->unlock_queue(vk, queue_family, index); +FF_ENABLE_DEPRECATION_WARNINGS +#endif } static int get_decode_queue(VkRenderer *renderer, int *index, int *count) @@ -356,6 +361,8 @@ static int create_vk_by_placebo(VkRenderer *renderer, int decode_index; int decode_count; int ret; + const char **dev_exts; + int num_dev_exts; ctx->get_proc_addr = SDL_Vulkan_GetVkGetInstanceProcAddr(); @@ -370,16 +377,21 @@ static int create_vk_by_placebo(VkRenderer *renderer, } ctx->inst = ctx->placebo_instance->instance; + dev_exts = av_vk_get_optional_device_extensions(&num_dev_exts); + if (!dev_exts) + return AVERROR(ENOMEM); + ctx->placebo_vulkan = pl_vulkan_create(ctx->vk_log, pl_vulkan_params( .instance = ctx->placebo_instance->instance, .get_proc_addr = ctx->placebo_instance->get_proc_addr, .surface = ctx->vk_surface, .allow_software = false, - .opt_extensions = optional_device_exts, - .num_opt_extensions = FF_ARRAY_ELEMS(optional_device_exts), + .opt_extensions = dev_exts, + .num_opt_extensions = num_dev_exts, .extra_queues = VK_QUEUE_VIDEO_DECODE_BIT_KHR, .device_name = select_device(opt), )); + av_free(dev_exts); if (!ctx->placebo_vulkan) return AVERROR_EXTERNAL; ctx->hw_device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VULKAN); @@ -391,8 +403,12 @@ static int create_vk_by_placebo(VkRenderer *renderer, device_ctx->user_opaque = ctx; vk_dev_ctx = device_ctx->hwctx; - vk_dev_ctx->lock_queue = placebo_lock_queue, - vk_dev_ctx->unlock_queue = placebo_unlock_queue; +#if FF_API_VULKAN_SYNC_QUEUES +FF_DISABLE_DEPRECATION_WARNINGS + vk_dev_ctx->lock_queue = placebo_lock_queue; + vk_dev_ctx->unlock_queue = placebo_unlock_queue; +FF_ENABLE_DEPRECATION_WARNINGS +#endif vk_dev_ctx->get_proc_addr = ctx->placebo_instance->get_proc_addr; @@ -408,21 +424,38 @@ static int create_vk_by_placebo(VkRenderer *renderer, vk_dev_ctx->enabled_dev_extensions = ctx->placebo_vulkan->extensions; vk_dev_ctx->nb_enabled_dev_extensions = ctx->placebo_vulkan->num_extensions; - vk_dev_ctx->queue_family_index = ctx->placebo_vulkan->queue_graphics.index; - vk_dev_ctx->nb_graphics_queues = ctx->placebo_vulkan->queue_graphics.count; - - vk_dev_ctx->queue_family_tx_index = ctx->placebo_vulkan->queue_transfer.index; - vk_dev_ctx->nb_tx_queues = ctx->placebo_vulkan->queue_transfer.count; - - vk_dev_ctx->queue_family_comp_index = ctx->placebo_vulkan->queue_compute.index; - vk_dev_ctx->nb_comp_queues = ctx->placebo_vulkan->queue_compute.count; + int nb_qf = 0; + vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) { + .idx = ctx->placebo_vulkan->queue_graphics.index, + .num = ctx->placebo_vulkan->queue_graphics.count, + .flags = VK_QUEUE_GRAPHICS_BIT, + }; + nb_qf++; + vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) { + .idx = ctx->placebo_vulkan->queue_transfer.index, + .num = ctx->placebo_vulkan->queue_transfer.count, + .flags = VK_QUEUE_TRANSFER_BIT, + }; + nb_qf++; + vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) { + .idx = ctx->placebo_vulkan->queue_compute.index, + .num = ctx->placebo_vulkan->queue_compute.count, + .flags = VK_QUEUE_COMPUTE_BIT, + }; + nb_qf++; ret = get_decode_queue(renderer, &decode_index, &decode_count); if (ret < 0) return ret; - vk_dev_ctx->queue_family_decode_index = decode_index; - vk_dev_ctx->nb_decode_queues = decode_count; + vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) { + .idx = decode_index, + .num = decode_count, + .flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR, + }; + nb_qf++; + + vk_dev_ctx->nb_qf = nb_qf; ret = av_hwdevice_ctx_init(ctx->hw_device_ref); if (ret < 0) @@ -690,13 +723,16 @@ static int convert_frame(VkRenderer *renderer, AVFrame *frame) return ret; } -static int display(VkRenderer *renderer, AVFrame *frame) +static int display(VkRenderer *renderer, AVFrame *frame, RenderParams *params) { + SDL_Rect *rect = ¶ms->target_rect; struct pl_swapchain_frame swap_frame = {0}; struct pl_frame pl_frame = {0}; struct pl_frame target = {0}; + struct pl_render_params pl_params = pl_render_default_params; RendererContext *ctx = (RendererContext *) renderer; int ret = 0; + struct pl_color_space hint = {0}; ret = convert_frame(renderer, frame); if (ret < 0) @@ -709,6 +745,8 @@ static int display(VkRenderer *renderer, AVFrame *frame) return AVERROR_EXTERNAL; } + pl_color_space_from_avframe(&hint, frame); + pl_swapchain_colorspace_hint(ctx->swapchain, &hint); if (!pl_swapchain_start_frame(ctx->swapchain, &swap_frame)) { av_log(NULL, AV_LOG_ERROR, "start frame failed\n"); ret = AVERROR_EXTERNAL; @@ -716,8 +754,26 @@ static int display(VkRenderer *renderer, AVFrame *frame) } pl_frame_from_swapchain(&target, &swap_frame); - if (!pl_render_image(ctx->renderer, &pl_frame, &target, - &pl_render_default_params)) { + + target.crop = (pl_rect2df){.x0 = rect->x, .x1 = rect->x + rect->w, + .y0 = rect->y, .y1 = rect->y + rect->h}; + switch (params->video_background_type) { + case VIDEO_BACKGROUND_TILES: + pl_params.background = PL_CLEAR_TILES; + pl_params.tile_size = VIDEO_BACKGROUND_TILE_SIZE * 2; + break; + case VIDEO_BACKGROUND_COLOR: + pl_params.background = PL_CLEAR_COLOR; + for (int i = 0; i < 3; i++) + pl_params.background_color[i] = params->video_background_color[i] / 255.0; + pl_params.background_transparency = (255 - params->video_background_color[3]) / 255.0; + break; + case VIDEO_BACKGROUND_NONE: + pl_frame.repr.alpha = PL_ALPHA_NONE; + break; + } + + if (!pl_render_image(ctx->renderer, &pl_frame, &target, &pl_params)) { av_log(NULL, AV_LOG_ERROR, "pl_render_image failed\n"); ret = AVERROR_EXTERNAL; goto out; @@ -820,9 +876,9 @@ int vk_renderer_get_hw_dev(VkRenderer *renderer, AVBufferRef **dev) return renderer->get_hw_dev(renderer, dev); } -int vk_renderer_display(VkRenderer *renderer, AVFrame *frame) +int vk_renderer_display(VkRenderer *renderer, AVFrame *frame, RenderParams *render_params) { - return renderer->display(renderer, frame); + return renderer->display(renderer, frame, render_params); } int vk_renderer_resize(VkRenderer *renderer, int width, int height) diff --git a/fftools/ffplay_renderer.h b/fftools/ffplay_renderer.h index dd8e9c06e..c4893f6d5 100644 --- a/fftools/ffplay_renderer.h +++ b/fftools/ffplay_renderer.h @@ -25,6 +25,20 @@ typedef struct VkRenderer VkRenderer; +#define VIDEO_BACKGROUND_TILE_SIZE 64 + +enum VideoBackgroundType { + VIDEO_BACKGROUND_TILES, + VIDEO_BACKGROUND_COLOR, + VIDEO_BACKGROUND_NONE, +}; + +typedef struct RenderParams { + SDL_Rect target_rect; + uint8_t video_background_color[4]; + enum VideoBackgroundType video_background_type; +} RenderParams; + VkRenderer *vk_get_renderer(void); int vk_renderer_create(VkRenderer *renderer, SDL_Window *window, @@ -32,7 +46,7 @@ int vk_renderer_create(VkRenderer *renderer, SDL_Window *window, int vk_renderer_get_hw_dev(VkRenderer *renderer, AVBufferRef **dev); -int vk_renderer_display(VkRenderer *renderer, AVFrame *frame); +int vk_renderer_display(VkRenderer *renderer, AVFrame *frame, RenderParams *params); int vk_renderer_resize(VkRenderer *renderer, int width, int height); diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c index 14b98d22a..3c29fc255 100644 --- a/fftools/ffprobe.c +++ b/fftools/ffprobe.c @@ -36,11 +36,11 @@ #include "libavutil/ambient_viewing_environment.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/avutil.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" #include "libavutil/display.h" #include "libavutil/film_grain_params.h" -#include "libavutil/hash.h" #include "libavutil/hdr_dynamic_metadata.h" #include "libavutil/iamf.h" #include "libavutil/mastering_display_metadata.h" @@ -63,25 +63,13 @@ #include "libswscale/version.h" #include "libswresample/swresample.h" #include "libswresample/version.h" -#include "libpostproc/postprocess.h" -#include "libpostproc/version.h" #include "libavfilter/version.h" +#include "textformat/avtextformat.h" #include "cmdutils.h" #include "opt_common.h" #include "libavutil/thread.h" -#if !HAVE_THREADS -# ifdef pthread_mutex_lock -# undef pthread_mutex_lock -# endif -# define pthread_mutex_lock(a) do{}while(0) -# ifdef pthread_mutex_unlock -# undef pthread_mutex_unlock -# endif -# define pthread_mutex_unlock(a) do{}while(0) -#endif - // attached as opaque_ref to packets/frames typedef struct FrameData { int64_t pkt_pos; @@ -104,6 +92,7 @@ typedef struct InputFile { const char program_name[] = "ffprobe"; const int program_birth_year = 2007; +static int do_analyze_frames = 0; static int do_bitexact = 0; static int do_count_frames = 0; static int do_count_packets = 0; @@ -142,6 +131,11 @@ static int use_byte_value_binary_prefix = 0; static int use_value_sexagesimal_format = 0; static int show_private_data = 1; +static const char *audio_codec_name = NULL; +static const char *data_codec_name = NULL; +static const char *subtitle_codec_name = NULL; +static const char *video_codec_name = NULL; + #define SHOW_OPTIONAL_FIELDS_AUTO -1 #define SHOW_OPTIONAL_FIELDS_NEVER 0 #define SHOW_OPTIONAL_FIELDS_ALWAYS 1 @@ -150,6 +144,7 @@ static int show_optional_fields = SHOW_OPTIONAL_FIELDS_AUTO; static char *output_format; static char *stream_specifier; static char *show_data_hash; +static char *data_dump_format; typedef struct ReadInterval { int id; ///< identifier @@ -166,10 +161,7 @@ static int find_stream_info = 1; /* section structure definition */ -#define SECTION_MAX_NB_CHILDREN 11 - typedef enum { - SECTION_ID_NONE = -1, SECTION_ID_CHAPTER, SECTION_ID_CHAPTER_TAGS, SECTION_ID_CHAPTERS, @@ -238,25 +230,6 @@ typedef enum { SECTION_ID_SUBTITLE, } SectionID; -struct section { - int id; ///< unique id identifying a section - const char *name; - -#define SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level -#define SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type -#define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys. - /// For these sections the element_name field is mandatory. -#define SECTION_FLAG_HAS_TYPE 8 ///< the section contains a type to distinguish multiple nested elements - - int flags; - const SectionID children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1 - const char *element_name; ///< name of the contained element, if provided - const char *unique_name; ///< unique section name, in case the name is ambiguous - AVDictionary *entries_to_show; - const char *(* get_type)(const void *data); ///< function returning a type if defined, must be defined when SECTION_FLAG_HAS_TYPE is defined - int show_all_entries; -}; - static const char *get_packet_side_data_type(const void *data) { const AVPacketSideData *sd = (const AVPacketSideData *)data; @@ -280,78 +253,85 @@ static const char *get_stream_group_type(const void *data) return av_x_if_null(avformat_stream_group_name(stg->type), "unknown"); } -static struct section sections[] = { - [SECTION_ID_CHAPTERS] = { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } }, +static const AVTextFormatSection sections[] = { + [SECTION_ID_CHAPTERS] = { SECTION_ID_CHAPTERS, "chapters", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } }, [SECTION_ID_CHAPTER] = { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } }, - [SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" }, + [SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" }, [SECTION_ID_ERROR] = { SECTION_ID_ERROR, "error", 0, { -1 } }, [SECTION_ID_FORMAT] = { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } }, - [SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" }, - [SECTION_ID_FRAMES] = { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, SECTION_ID_SUBTITLE, -1 } }, + [SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" }, + [SECTION_ID_FRAMES] = { SECTION_ID_FRAMES, "frames", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, SECTION_ID_SUBTITLE, -1 } }, [SECTION_ID_FRAME] = { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, SECTION_ID_FRAME_SIDE_DATA_LIST, SECTION_ID_FRAME_LOGS, -1 } }, - [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" }, - [SECTION_ID_FRAME_SIDE_DATA_LIST] ={ SECTION_ID_FRAME_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "frame_side_data_list" }, - [SECTION_ID_FRAME_SIDE_DATA] = { SECTION_ID_FRAME_SIDE_DATA, "side_data", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, -1 }, .unique_name = "frame_side_data", .element_name = "side_datum", .get_type = get_frame_side_data_type }, - [SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, "timecodes", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, -1 } }, + [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" }, + [SECTION_ID_FRAME_SIDE_DATA_LIST] ={ SECTION_ID_FRAME_SIDE_DATA_LIST, "side_data_list", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "frame_side_data_list" }, + [SECTION_ID_FRAME_SIDE_DATA] = { SECTION_ID_FRAME_SIDE_DATA, "side_data", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, -1 }, .unique_name = "frame_side_data", .element_name = "side_datum", .get_type = get_frame_side_data_type }, + [SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, "timecodes", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, -1 } }, [SECTION_ID_FRAME_SIDE_DATA_TIMECODE] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, "timecode", 0, { -1 } }, - [SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, "components", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, -1 }, .element_name = "component", .unique_name = "frame_side_data_components" }, - [SECTION_ID_FRAME_SIDE_DATA_COMPONENT] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, "component", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, -1 }, .unique_name = "frame_side_data_component", .element_name = "component_entry", .get_type = get_raw_string_type }, - [SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, "pieces", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_PIECE, -1 }, .element_name = "piece", .unique_name = "frame_side_data_pieces" }, - [SECTION_ID_FRAME_SIDE_DATA_PIECE] = { SECTION_ID_FRAME_SIDE_DATA_PIECE, "piece", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { -1 }, .element_name = "piece_entry", .unique_name = "frame_side_data_piece", .get_type = get_raw_string_type }, - [SECTION_ID_FRAME_LOGS] = { SECTION_ID_FRAME_LOGS, "logs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_LOG, -1 } }, + [SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, "components", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, -1 }, .element_name = "component", .unique_name = "frame_side_data_components" }, + [SECTION_ID_FRAME_SIDE_DATA_COMPONENT] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, "component", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, -1 }, .unique_name = "frame_side_data_component", .element_name = "component_entry", .get_type = get_raw_string_type }, + [SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, "pieces", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_PIECE, -1 }, .element_name = "piece", .unique_name = "frame_side_data_pieces" }, + [SECTION_ID_FRAME_SIDE_DATA_PIECE] = { SECTION_ID_FRAME_SIDE_DATA_PIECE, "piece", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { -1 }, .element_name = "piece_entry", .unique_name = "frame_side_data_piece", .get_type = get_raw_string_type }, + [SECTION_ID_FRAME_LOGS] = { SECTION_ID_FRAME_LOGS, "logs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_LOG, -1 } }, [SECTION_ID_FRAME_LOG] = { SECTION_ID_FRAME_LOG, "log", 0, { -1 }, }, - [SECTION_ID_LIBRARY_VERSIONS] = { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } }, + [SECTION_ID_LIBRARY_VERSIONS] = { SECTION_ID_LIBRARY_VERSIONS, "library_versions", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } }, [SECTION_ID_LIBRARY_VERSION] = { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } }, - [SECTION_ID_PACKETS] = { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} }, - [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} }, + [SECTION_ID_PACKETS] = { SECTION_ID_PACKETS, "packets", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} }, + [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE, { SECTION_ID_PACKET, -1} }, [SECTION_ID_PACKET] = { SECTION_ID_PACKET, "packet", 0, { SECTION_ID_PACKET_TAGS, SECTION_ID_PACKET_SIDE_DATA_LIST, -1 } }, - [SECTION_ID_PACKET_TAGS] = { SECTION_ID_PACKET_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "packet_tags" }, - [SECTION_ID_PACKET_SIDE_DATA_LIST] ={ SECTION_ID_PACKET_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "packet_side_data_list" }, - [SECTION_ID_PACKET_SIDE_DATA] = { SECTION_ID_PACKET_SIDE_DATA, "side_data", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { -1 }, .unique_name = "packet_side_data", .element_name = "side_datum", .get_type = get_packet_side_data_type }, - [SECTION_ID_PIXEL_FORMATS] = { SECTION_ID_PIXEL_FORMATS, "pixel_formats", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_FORMAT, -1 } }, + [SECTION_ID_PACKET_TAGS] = { SECTION_ID_PACKET_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "packet_tags" }, + [SECTION_ID_PACKET_SIDE_DATA_LIST] ={ SECTION_ID_PACKET_SIDE_DATA_LIST, "side_data_list", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "packet_side_data_list" }, + [SECTION_ID_PACKET_SIDE_DATA] = { SECTION_ID_PACKET_SIDE_DATA, "side_data", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { -1 }, .unique_name = "packet_side_data", .element_name = "side_datum", .get_type = get_packet_side_data_type }, + [SECTION_ID_PIXEL_FORMATS] = { SECTION_ID_PIXEL_FORMATS, "pixel_formats", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_FORMAT, -1 } }, [SECTION_ID_PIXEL_FORMAT] = { SECTION_ID_PIXEL_FORMAT, "pixel_format", 0, { SECTION_ID_PIXEL_FORMAT_FLAGS, SECTION_ID_PIXEL_FORMAT_COMPONENTS, -1 } }, [SECTION_ID_PIXEL_FORMAT_FLAGS] = { SECTION_ID_PIXEL_FORMAT_FLAGS, "flags", 0, { -1 }, .unique_name = "pixel_format_flags" }, - [SECTION_ID_PIXEL_FORMAT_COMPONENTS] = { SECTION_ID_PIXEL_FORMAT_COMPONENTS, "components", SECTION_FLAG_IS_ARRAY, {SECTION_ID_PIXEL_FORMAT_COMPONENT, -1 }, .unique_name = "pixel_format_components" }, + [SECTION_ID_PIXEL_FORMAT_COMPONENTS] = { SECTION_ID_PIXEL_FORMAT_COMPONENTS, "components", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, {SECTION_ID_PIXEL_FORMAT_COMPONENT, -1 }, .unique_name = "pixel_format_components" }, [SECTION_ID_PIXEL_FORMAT_COMPONENT] = { SECTION_ID_PIXEL_FORMAT_COMPONENT, "component", 0, { -1 } }, [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" }, - [SECTION_ID_PROGRAM_STREAM_TAGS] = { SECTION_ID_PROGRAM_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_stream_tags" }, + [SECTION_ID_PROGRAM_STREAM_TAGS] = { SECTION_ID_PROGRAM_STREAM_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_stream_tags" }, [SECTION_ID_PROGRAM] = { SECTION_ID_PROGRAM, "program", 0, { SECTION_ID_PROGRAM_TAGS, SECTION_ID_PROGRAM_STREAMS, -1 } }, - [SECTION_ID_PROGRAM_STREAMS] = { SECTION_ID_PROGRAM_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" }, + [SECTION_ID_PROGRAM_STREAMS] = { SECTION_ID_PROGRAM_STREAMS, "streams", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" }, [SECTION_ID_PROGRAM_STREAM] = { SECTION_ID_PROGRAM_STREAM, "stream", 0, { SECTION_ID_PROGRAM_STREAM_DISPOSITION, SECTION_ID_PROGRAM_STREAM_TAGS, -1 }, .unique_name = "program_stream" }, - [SECTION_ID_PROGRAM_TAGS] = { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" }, + [SECTION_ID_PROGRAM_TAGS] = { SECTION_ID_PROGRAM_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" }, [SECTION_ID_PROGRAM_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } }, - [SECTION_ID_PROGRAMS] = { SECTION_ID_PROGRAMS, "programs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } }, + [SECTION_ID_PROGRAMS] = { SECTION_ID_PROGRAMS, "programs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } }, [SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION] = { SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_group_stream_disposition" }, - [SECTION_ID_STREAM_GROUP_STREAM_TAGS] = { SECTION_ID_STREAM_GROUP_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_stream_tags" }, + [SECTION_ID_STREAM_GROUP_STREAM_TAGS] = { SECTION_ID_STREAM_GROUP_STREAM_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_stream_tags" }, [SECTION_ID_STREAM_GROUP] = { SECTION_ID_STREAM_GROUP, "stream_group", 0, { SECTION_ID_STREAM_GROUP_TAGS, SECTION_ID_STREAM_GROUP_DISPOSITION, SECTION_ID_STREAM_GROUP_COMPONENTS, SECTION_ID_STREAM_GROUP_STREAMS, -1 } }, - [SECTION_ID_STREAM_GROUP_COMPONENTS] = { SECTION_ID_STREAM_GROUP_COMPONENTS, "components", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_COMPONENT, -1 }, .element_name = "component", .unique_name = "stream_group_components" }, - [SECTION_ID_STREAM_GROUP_COMPONENT] = { SECTION_ID_STREAM_GROUP_COMPONENT, "component", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, -1 }, .unique_name = "stream_group_component", .element_name = "component_entry", .get_type = get_stream_group_type }, - [SECTION_ID_STREAM_GROUP_SUBCOMPONENTS] = { SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, "subcomponents", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_SUBCOMPONENT, -1 }, .element_name = "component" }, - [SECTION_ID_STREAM_GROUP_SUBCOMPONENT] = { SECTION_ID_STREAM_GROUP_SUBCOMPONENT, "subcomponent", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_PIECES, -1 }, .element_name = "subcomponent_entry", .get_type = get_raw_string_type }, - [SECTION_ID_STREAM_GROUP_PIECES] = { SECTION_ID_STREAM_GROUP_PIECES, "pieces", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_PIECE, -1 }, .element_name = "piece", .unique_name = "stream_group_pieces" }, - [SECTION_ID_STREAM_GROUP_PIECE] = { SECTION_ID_STREAM_GROUP_PIECE, "piece", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SUBPIECES, -1 }, .unique_name = "stream_group_piece", .element_name = "piece_entry", .get_type = get_raw_string_type }, - [SECTION_ID_STREAM_GROUP_SUBPIECES] = { SECTION_ID_STREAM_GROUP_SUBPIECES, "subpieces", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_SUBPIECE, -1 }, .element_name = "subpiece" }, - [SECTION_ID_STREAM_GROUP_SUBPIECE] = { SECTION_ID_STREAM_GROUP_SUBPIECE, "subpiece", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_BLOCKS, -1 }, .element_name = "subpiece_entry", .get_type = get_raw_string_type }, - [SECTION_ID_STREAM_GROUP_BLOCKS] = { SECTION_ID_STREAM_GROUP_BLOCKS, "blocks", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_BLOCK, -1 }, .element_name = "block" }, - [SECTION_ID_STREAM_GROUP_BLOCK] = { SECTION_ID_STREAM_GROUP_BLOCK, "block", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { -1 }, .element_name = "block_entry", .get_type = get_raw_string_type }, - [SECTION_ID_STREAM_GROUP_STREAMS] = { SECTION_ID_STREAM_GROUP_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_STREAM, -1 }, .unique_name = "stream_group_streams" }, + [SECTION_ID_STREAM_GROUP_COMPONENTS] = { SECTION_ID_STREAM_GROUP_COMPONENTS, "components", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_COMPONENT, -1 }, .element_name = "component", .unique_name = "stream_group_components" }, + [SECTION_ID_STREAM_GROUP_COMPONENT] = { SECTION_ID_STREAM_GROUP_COMPONENT, "component", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, -1 }, .unique_name = "stream_group_component", .element_name = "component_entry", .get_type = get_stream_group_type }, + [SECTION_ID_STREAM_GROUP_SUBCOMPONENTS] = { SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, "subcomponents", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_SUBCOMPONENT, -1 }, .element_name = "component" }, + [SECTION_ID_STREAM_GROUP_SUBCOMPONENT] = { SECTION_ID_STREAM_GROUP_SUBCOMPONENT, "subcomponent", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_PIECES, -1 }, .element_name = "subcomponent_entry", .get_type = get_raw_string_type }, + [SECTION_ID_STREAM_GROUP_PIECES] = { SECTION_ID_STREAM_GROUP_PIECES, "pieces", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_PIECE, -1 }, .element_name = "piece", .unique_name = "stream_group_pieces" }, + [SECTION_ID_STREAM_GROUP_PIECE] = { SECTION_ID_STREAM_GROUP_PIECE, "piece", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SUBPIECES, -1 }, .unique_name = "stream_group_piece", .element_name = "piece_entry", .get_type = get_raw_string_type }, + [SECTION_ID_STREAM_GROUP_SUBPIECES] = { SECTION_ID_STREAM_GROUP_SUBPIECES, "subpieces", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_SUBPIECE, -1 }, .element_name = "subpiece" }, + [SECTION_ID_STREAM_GROUP_SUBPIECE] = { SECTION_ID_STREAM_GROUP_SUBPIECE, "subpiece", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_BLOCKS, -1 }, .element_name = "subpiece_entry", .get_type = get_raw_string_type }, + [SECTION_ID_STREAM_GROUP_BLOCKS] = { SECTION_ID_STREAM_GROUP_BLOCKS, "blocks", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_BLOCK, -1 }, .element_name = "block" }, + [SECTION_ID_STREAM_GROUP_BLOCK] = { SECTION_ID_STREAM_GROUP_BLOCK, "block", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { -1 }, .element_name = "block_entry", .get_type = get_raw_string_type }, + [SECTION_ID_STREAM_GROUP_STREAMS] = { SECTION_ID_STREAM_GROUP_STREAMS, "streams", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_STREAM, -1 }, .unique_name = "stream_group_streams" }, [SECTION_ID_STREAM_GROUP_STREAM] = { SECTION_ID_STREAM_GROUP_STREAM, "stream", 0, { SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION, SECTION_ID_STREAM_GROUP_STREAM_TAGS, -1 }, .unique_name = "stream_group_stream" }, [SECTION_ID_STREAM_GROUP_DISPOSITION] = { SECTION_ID_STREAM_GROUP_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_group_disposition" }, - [SECTION_ID_STREAM_GROUP_TAGS] = { SECTION_ID_STREAM_GROUP_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_tags" }, - [SECTION_ID_STREAM_GROUPS] = { SECTION_ID_STREAM_GROUPS, "stream_groups", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP, -1 } }, - [SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER, + [SECTION_ID_STREAM_GROUP_TAGS] = { SECTION_ID_STREAM_GROUP_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_tags" }, + [SECTION_ID_STREAM_GROUPS] = { SECTION_ID_STREAM_GROUPS, "stream_groups", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP, -1 } }, + [SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER, { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAM_GROUPS, SECTION_ID_STREAMS, SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS, SECTION_ID_PIXEL_FORMATS, -1} }, - [SECTION_ID_STREAMS] = { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } }, + [SECTION_ID_STREAMS] = { SECTION_ID_STREAMS, "streams", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } }, [SECTION_ID_STREAM] = { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, SECTION_ID_STREAM_SIDE_DATA_LIST, -1 } }, [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" }, - [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" }, - [SECTION_ID_STREAM_SIDE_DATA_LIST] ={ SECTION_ID_STREAM_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "stream_side_data_list" }, - [SECTION_ID_STREAM_SIDE_DATA] = { SECTION_ID_STREAM_SIDE_DATA, "side_data", SECTION_FLAG_HAS_TYPE|SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .unique_name = "stream_side_data", .element_name = "side_datum", .get_type = get_packet_side_data_type }, + [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" }, + [SECTION_ID_STREAM_SIDE_DATA_LIST] ={ SECTION_ID_STREAM_SIDE_DATA_LIST, "side_data_list", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "stream_side_data_list" }, + [SECTION_ID_STREAM_SIDE_DATA] = { SECTION_ID_STREAM_SIDE_DATA, "side_data", AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE|AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .unique_name = "stream_side_data", .element_name = "side_datum", .get_type = get_packet_side_data_type }, [SECTION_ID_SUBTITLE] = { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } }, }; +typedef struct EntrySelection { + int show_all_entries; + AVDictionary *entries_to_show; +} EntrySelection; + +static EntrySelection selected_entries[FF_ARRAY_ELEMS(sections)] = { 0 }; + static const OptionDef *options; /* FFprobe context */ @@ -360,22 +340,6 @@ static const char *print_input_filename; static const AVInputFormat *iformat = NULL; static const char *output_filename = NULL; -static struct AVHashContext *hash; - -static const struct { - double bin_val; - double dec_val; - const char *bin_str; - const char *dec_str; -} si_prefixes[] = { - { 1.0, 1.0, "", "" }, - { 1.024e3, 1e3, "Ki", "K" }, - { 1.048576e6, 1e6, "Mi", "M" }, - { 1.073741824e9, 1e9, "Gi", "G" }, - { 1.099511627776e12, 1e12, "Ti", "T" }, - { 1.125899906842624e15, 1e15, "Pi", "P" }, -}; - static const char unit_second_str[] = "s" ; static const char unit_hertz_str[] = "Hz" ; static const char unit_byte_str[] = "byte" ; @@ -385,10 +349,11 @@ static int nb_streams; static uint64_t *nb_streams_packets; static uint64_t *nb_streams_frames; static int *selected_streams; +static int *streams_with_closed_captions; +static int *streams_with_film_grain; + +static AVMutex log_mutex = AV_MUTEX_INITIALIZER; -#if HAVE_THREADS -pthread_mutex_t log_mutex; -#endif typedef struct LogBuffer { char *context_name; int log_level; @@ -401,6 +366,14 @@ typedef struct LogBuffer { static LogBuffer *log_buffer; static int log_buffer_size; +static int is_key_selected_callback(AVTextFormatContext *tctx, const char *key) +{ + const AVTextFormatSection *section = tctx->section[tctx->level]; + const EntrySelection *selection = &selected_entries[section - sections]; + + return selection->show_all_entries || av_dict_get(selection->entries_to_show, key, NULL, 0); +} + static void log_callback(void *ptr, int level, const char *fmt, va_list vl) { AVClass* avc = ptr ? *(AVClass **) ptr : NULL; @@ -415,7 +388,7 @@ static void log_callback(void *ptr, int level, const char *fmt, va_list vl) va_end(vl2); #if HAVE_THREADS - pthread_mutex_lock(&log_mutex); + ff_mutex_lock(&log_mutex); new_log_buffer = av_realloc_array(log_buffer, log_buffer_size + 1, sizeof(*log_buffer)); if (new_log_buffer) { @@ -446,1558 +419,15 @@ static void log_callback(void *ptr, int level, const char *fmt, va_list vl) log_buffer_size ++; } - pthread_mutex_unlock(&log_mutex); + ff_mutex_unlock(&log_mutex); #endif } -struct unit_value { - union { double d; int64_t i; } val; - const char *unit; -}; - -static char *value_string(char *buf, int buf_size, struct unit_value uv) -{ - double vald; - int64_t vali; - int show_float = 0; - - if (uv.unit == unit_second_str) { - vald = uv.val.d; - show_float = 1; - } else { - vald = vali = uv.val.i; - } - - if (uv.unit == unit_second_str && use_value_sexagesimal_format) { - double secs; - int hours, mins; - secs = vald; - mins = (int)secs / 60; - secs = secs - mins * 60; - hours = mins / 60; - mins %= 60; - snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs); - } else { - const char *prefix_string = ""; - - if (use_value_prefix && vald > 1) { - int64_t index; - - if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) { - index = (int64_t) (log2(vald)) / 10; - index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); - vald /= si_prefixes[index].bin_val; - prefix_string = si_prefixes[index].bin_str; - } else { - index = (int64_t) (log10(vald)) / 3; - index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); - vald /= si_prefixes[index].dec_val; - prefix_string = si_prefixes[index].dec_str; - } - vali = vald; - } - - if (show_float || (use_value_prefix && vald != (int64_t)vald)) - snprintf(buf, buf_size, "%f", vald); - else - snprintf(buf, buf_size, "%"PRId64, vali); - av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "", - prefix_string, show_value_unit ? uv.unit : ""); - } - - return buf; -} - -/* WRITERS API */ - -typedef struct WriterContext WriterContext; - -#define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1 -#define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2 - -typedef enum { - WRITER_STRING_VALIDATION_FAIL, - WRITER_STRING_VALIDATION_REPLACE, - WRITER_STRING_VALIDATION_IGNORE, - WRITER_STRING_VALIDATION_NB -} StringValidation; - -typedef struct Writer { - const AVClass *priv_class; ///< private class of the writer, if any - int priv_size; ///< private size for the writer context - const char *name; - - int (*init) (WriterContext *wctx); - void (*uninit)(WriterContext *wctx); - - void (*print_section_header)(WriterContext *wctx, const void *data); - void (*print_section_footer)(WriterContext *wctx); - void (*print_integer) (WriterContext *wctx, const char *, int64_t); - void (*print_rational) (WriterContext *wctx, AVRational *q, char *sep); - void (*print_string) (WriterContext *wctx, const char *, const char *); - int flags; ///< a combination or WRITER_FLAG_* -} Writer; - -#define SECTION_MAX_NB_LEVELS 12 - -struct WriterContext { - const AVClass *class; ///< class of the writer - const Writer *writer; ///< the Writer of which this is an instance - AVIOContext *avio; ///< the I/O context used to write - - void (* writer_w8)(WriterContext *wctx, int b); - void (* writer_put_str)(WriterContext *wctx, const char *str); - void (* writer_printf)(WriterContext *wctx, const char *fmt, ...); - - char *name; ///< name of this writer instance - void *priv; ///< private data for use by the filter - - const struct section *sections; ///< array containing all sections - int nb_sections; ///< number of sections - - int level; ///< current level, starting from 0 - - /** number of the item printed in the given section, starting from 0 */ - unsigned int nb_item[SECTION_MAX_NB_LEVELS]; - - /** section per each level */ - const struct section *section[SECTION_MAX_NB_LEVELS]; - AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section, - /// used by various writers - - unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section - unsigned int nb_section_frame; ///< number of the frame section in case we are in "packets_and_frames" section - unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames - - int string_validation; - char *string_validation_replacement; - unsigned int string_validation_utf8_flags; -}; - -static const char *writer_get_name(void *p) -{ - WriterContext *wctx = p; - return wctx->writer->name; -} - -#define OFFSET(x) offsetof(WriterContext, x) - -static const AVOption writer_options[] = { - { "string_validation", "set string validation mode", - OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" }, - { "sv", "set string validation mode", - OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" }, - { "ignore", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_IGNORE}, .unit = "sv" }, - { "replace", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_REPLACE}, .unit = "sv" }, - { "fail", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_FAIL}, .unit = "sv" }, - { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str=""}}, - { "svr", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str="\xEF\xBF\xBD"}}, - { NULL } -}; - -static void *writer_child_next(void *obj, void *prev) -{ - WriterContext *ctx = obj; - if (!prev && ctx->writer && ctx->writer->priv_class && ctx->priv) - return ctx->priv; - return NULL; -} - -static const AVClass writer_class = { - .class_name = "Writer", - .item_name = writer_get_name, - .option = writer_options, - .version = LIBAVUTIL_VERSION_INT, - .child_next = writer_child_next, -}; - -static int writer_close(WriterContext **wctx) -{ - int i; - int ret = 0; - - if (!*wctx) - return -1; - - if ((*wctx)->writer->uninit) - (*wctx)->writer->uninit(*wctx); - for (i = 0; i < SECTION_MAX_NB_LEVELS; i++) - av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL); - if ((*wctx)->writer->priv_class) - av_opt_free((*wctx)->priv); - av_freep(&((*wctx)->priv)); - av_opt_free(*wctx); - if ((*wctx)->avio) { - avio_flush((*wctx)->avio); - ret = avio_close((*wctx)->avio); - } - av_freep(wctx); - return ret; -} - -static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size) -{ - int i; - av_bprintf(bp, "0X"); - for (i = 0; i < ubuf_size; i++) - av_bprintf(bp, "%02X", ubuf[i]); -} - -static inline void writer_w8_avio(WriterContext *wctx, int b) -{ - avio_w8(wctx->avio, b); -} - -static inline void writer_put_str_avio(WriterContext *wctx, const char *str) -{ - avio_write(wctx->avio, str, strlen(str)); -} - -static inline void writer_printf_avio(WriterContext *wctx, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - avio_vprintf(wctx->avio, fmt, ap); - va_end(ap); -} - -static inline void writer_w8_printf(WriterContext *wctx, int b) -{ - printf("%c", b); -} - -static inline void writer_put_str_printf(WriterContext *wctx, const char *str) -{ - printf("%s", str); -} - -static inline void writer_printf_printf(WriterContext *wctx, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); -} - -static int writer_open(WriterContext **wctx, const Writer *writer, const char *args, - const struct section *sections, int nb_sections, const char *output) -{ - int i, ret = 0; - - if (!(*wctx = av_mallocz(sizeof(WriterContext)))) { - ret = AVERROR(ENOMEM); - goto fail; - } - - if (!((*wctx)->priv = av_mallocz(writer->priv_size))) { - ret = AVERROR(ENOMEM); - goto fail; - } - - (*wctx)->class = &writer_class; - (*wctx)->writer = writer; - (*wctx)->level = -1; - (*wctx)->sections = sections; - (*wctx)->nb_sections = nb_sections; - - av_opt_set_defaults(*wctx); - - if (writer->priv_class) { - void *priv_ctx = (*wctx)->priv; - *((const AVClass **)priv_ctx) = writer->priv_class; - av_opt_set_defaults(priv_ctx); - } - - /* convert options to dictionary */ - if (args) { - AVDictionary *opts = NULL; - const AVDictionaryEntry *opt = NULL; - - if ((ret = av_dict_parse_string(&opts, args, "=", ":", 0)) < 0) { - av_log(*wctx, AV_LOG_ERROR, "Failed to parse option string '%s' provided to writer context\n", args); - av_dict_free(&opts); - goto fail; - } - - while ((opt = av_dict_iterate(opts, opt))) { - if ((ret = av_opt_set(*wctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) { - av_log(*wctx, AV_LOG_ERROR, "Failed to set option '%s' with value '%s' provided to writer context\n", - opt->key, opt->value); - av_dict_free(&opts); - goto fail; - } - } - - av_dict_free(&opts); - } - - /* validate replace string */ - { - const uint8_t *p = (*wctx)->string_validation_replacement; - const uint8_t *endp = p + strlen(p); - while (*p) { - const uint8_t *p0 = p; - int32_t code; - ret = av_utf8_decode(&code, &p, endp, (*wctx)->string_validation_utf8_flags); - if (ret < 0) { - AVBPrint bp; - av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); - bprint_bytes(&bp, p0, p-p0), - av_log(wctx, AV_LOG_ERROR, - "Invalid UTF8 sequence %s found in string validation replace '%s'\n", - bp.str, (*wctx)->string_validation_replacement); - return ret; - } - } - } - - if (!output_filename) { - (*wctx)->writer_w8 = writer_w8_printf; - (*wctx)->writer_put_str = writer_put_str_printf; - (*wctx)->writer_printf = writer_printf_printf; - } else { - if ((ret = avio_open(&(*wctx)->avio, output, AVIO_FLAG_WRITE)) < 0) { - av_log(*wctx, AV_LOG_ERROR, - "Failed to open output '%s' with error: %s\n", output, av_err2str(ret)); - goto fail; - } - (*wctx)->writer_w8 = writer_w8_avio; - (*wctx)->writer_put_str = writer_put_str_avio; - (*wctx)->writer_printf = writer_printf_avio; - } - - for (i = 0; i < SECTION_MAX_NB_LEVELS; i++) - av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED); - - if ((*wctx)->writer->init) - ret = (*wctx)->writer->init(*wctx); - if (ret < 0) - goto fail; - - return 0; - -fail: - writer_close(wctx); - return ret; -} - -static inline void writer_print_section_header(WriterContext *wctx, - const void *data, - int section_id) -{ - int parent_section_id; - wctx->level++; - av_assert0(wctx->level < SECTION_MAX_NB_LEVELS); - parent_section_id = wctx->level ? - (wctx->section[wctx->level-1])->id : SECTION_ID_NONE; - - wctx->nb_item[wctx->level] = 0; - wctx->section[wctx->level] = &wctx->sections[section_id]; - - if (section_id == SECTION_ID_PACKETS_AND_FRAMES) { - wctx->nb_section_packet = wctx->nb_section_frame = - wctx->nb_section_packet_frame = 0; - } else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) { - wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ? - wctx->nb_section_packet : wctx->nb_section_frame; - } - - if (wctx->writer->print_section_header) - wctx->writer->print_section_header(wctx, data); -} - -static inline void writer_print_section_footer(WriterContext *wctx) -{ - int section_id = wctx->section[wctx->level]->id; - int parent_section_id = wctx->level ? - wctx->section[wctx->level-1]->id : SECTION_ID_NONE; - - if (parent_section_id != SECTION_ID_NONE) - wctx->nb_item[wctx->level-1]++; - if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) { - if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++; - else wctx->nb_section_frame++; - } - if (wctx->writer->print_section_footer) - wctx->writer->print_section_footer(wctx); - wctx->level--; -} - -static inline void writer_print_integer(WriterContext *wctx, - const char *key, int64_t val) -{ - const struct section *section = wctx->section[wctx->level]; - - if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) { - wctx->writer->print_integer(wctx, key, val); - wctx->nb_item[wctx->level]++; - } -} - -static inline int validate_string(WriterContext *wctx, char **dstp, const char *src) -{ - const uint8_t *p, *endp; - AVBPrint dstbuf; - int invalid_chars_nb = 0, ret = 0; - - av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED); - - endp = src + strlen(src); - for (p = src; *p;) { - uint32_t code; - int invalid = 0; - const uint8_t *p0 = p; - - if (av_utf8_decode(&code, &p, endp, wctx->string_validation_utf8_flags) < 0) { - AVBPrint bp; - av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); - bprint_bytes(&bp, p0, p-p0); - av_log(wctx, AV_LOG_DEBUG, - "Invalid UTF-8 sequence %s found in string '%s'\n", bp.str, src); - invalid = 1; - } - - if (invalid) { - invalid_chars_nb++; - - switch (wctx->string_validation) { - case WRITER_STRING_VALIDATION_FAIL: - av_log(wctx, AV_LOG_ERROR, - "Invalid UTF-8 sequence found in string '%s'\n", src); - ret = AVERROR_INVALIDDATA; - goto end; - break; - - case WRITER_STRING_VALIDATION_REPLACE: - av_bprintf(&dstbuf, "%s", wctx->string_validation_replacement); - break; - } - } - - if (!invalid || wctx->string_validation == WRITER_STRING_VALIDATION_IGNORE) - av_bprint_append_data(&dstbuf, p0, p-p0); - } - - if (invalid_chars_nb && wctx->string_validation == WRITER_STRING_VALIDATION_REPLACE) { - av_log(wctx, AV_LOG_WARNING, - "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n", - invalid_chars_nb, src, wctx->string_validation_replacement); - } - -end: - av_bprint_finalize(&dstbuf, dstp); - return ret; -} - -#define PRINT_STRING_OPT 1 -#define PRINT_STRING_VALIDATE 2 - -static inline int writer_print_string(WriterContext *wctx, - const char *key, const char *val, int flags) -{ - const struct section *section = wctx->section[wctx->level]; - int ret = 0; - - if (show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER || - (show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO - && (flags & PRINT_STRING_OPT) - && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))) - return 0; - - if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) { - if (flags & PRINT_STRING_VALIDATE) { - char *key1 = NULL, *val1 = NULL; - ret = validate_string(wctx, &key1, key); - if (ret < 0) goto end; - ret = validate_string(wctx, &val1, val); - if (ret < 0) goto end; - wctx->writer->print_string(wctx, key1, val1); - end: - if (ret < 0) { - av_log(wctx, AV_LOG_ERROR, - "Invalid key=value string combination %s=%s in section %s\n", - key, val, section->unique_name); - } - av_free(key1); - av_free(val1); - } else { - wctx->writer->print_string(wctx, key, val); - } - - wctx->nb_item[wctx->level]++; - } - - return ret; -} - -static inline void writer_print_rational(WriterContext *wctx, - const char *key, AVRational q, char sep) -{ - AVBPrint buf; - av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC); - av_bprintf(&buf, "%d%c%d", q.num, sep, q.den); - writer_print_string(wctx, key, buf.str, 0); -} - -static void writer_print_time(WriterContext *wctx, const char *key, - int64_t ts, const AVRational *time_base, int is_duration) -{ - char buf[128]; - - if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) { - writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT); - } else { - double d = ts * av_q2d(*time_base); - struct unit_value uv; - uv.val.d = d; - uv.unit = unit_second_str; - value_string(buf, sizeof(buf), uv); - writer_print_string(wctx, key, buf, 0); - } -} - -static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration) -{ - if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) { - writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT); - } else { - writer_print_integer(wctx, key, ts); - } -} - -static void writer_print_data(WriterContext *wctx, const char *name, - const uint8_t *data, int size) -{ - AVBPrint bp; - int offset = 0, l, i; - - av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); - av_bprintf(&bp, "\n"); - while (size) { - av_bprintf(&bp, "%08x: ", offset); - l = FFMIN(size, 16); - for (i = 0; i < l; i++) { - av_bprintf(&bp, "%02x", data[i]); - if (i & 1) - av_bprintf(&bp, " "); - } - av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2); - for (i = 0; i < l; i++) - av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1); - av_bprintf(&bp, "\n"); - offset += l; - data += l; - size -= l; - } - writer_print_string(wctx, name, bp.str, 0); - av_bprint_finalize(&bp, NULL); -} - -static void writer_print_data_hash(WriterContext *wctx, const char *name, - const uint8_t *data, int size) -{ - char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 }; - - if (!hash) - return; - av_hash_init(hash); - av_hash_update(hash, data, size); - snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(hash)); - p = buf + strlen(buf); - av_hash_final_hex(hash, p, buf + sizeof(buf) - p); - writer_print_string(wctx, name, buf, 0); -} - -static void writer_print_integers(WriterContext *wctx, const char *name, - uint8_t *data, int size, const char *format, - int columns, int bytes, int offset_add) -{ - AVBPrint bp; - int offset = 0, l, i; - - av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); - av_bprintf(&bp, "\n"); - while (size) { - av_bprintf(&bp, "%08x: ", offset); - l = FFMIN(size, columns); - for (i = 0; i < l; i++) { - if (bytes == 1) av_bprintf(&bp, format, *data); - else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data)); - else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data)); - data += bytes; - size --; - } - av_bprintf(&bp, "\n"); - offset += offset_add; - } - writer_print_string(wctx, name, bp.str, 0); - av_bprint_finalize(&bp, NULL); -} - -#define writer_w8(wctx_, b_) (wctx_)->writer_w8(wctx_, b_) -#define writer_put_str(wctx_, str_) (wctx_)->writer_put_str(wctx_, str_) -#define writer_printf(wctx_, fmt_, ...) (wctx_)->writer_printf(wctx_, fmt_, __VA_ARGS__) - -#define MAX_REGISTERED_WRITERS_NB 64 - -static const Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1]; - -static int writer_register(const Writer *writer) -{ - static int next_registered_writer_idx = 0; - - if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB) - return AVERROR(ENOMEM); - - registered_writers[next_registered_writer_idx++] = writer; - return 0; -} - -static const Writer *writer_get_by_name(const char *name) -{ - int i; - - for (i = 0; registered_writers[i]; i++) - if (!strcmp(registered_writers[i]->name, name)) - return registered_writers[i]; - - return NULL; -} - - -/* WRITERS */ - -#define DEFINE_WRITER_CLASS(name) \ -static const char *name##_get_name(void *ctx) \ -{ \ - return #name ; \ -} \ -static const AVClass name##_class = { \ - .class_name = #name, \ - .item_name = name##_get_name, \ - .option = name##_options \ -} - -/* Default output */ - -typedef struct DefaultContext { - const AVClass *class; - int nokey; - int noprint_wrappers; - int nested_section[SECTION_MAX_NB_LEVELS]; -} DefaultContext; - -#undef OFFSET -#define OFFSET(x) offsetof(DefaultContext, x) - -static const AVOption default_options[] = { - { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - { "nw", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(default); - -/* lame uppercasing routine, assumes the string is lower case ASCII */ -static inline char *upcase_string(char *dst, size_t dst_size, const char *src) -{ - int i; - for (i = 0; src[i] && i < dst_size-1; i++) - dst[i] = av_toupper(src[i]); - dst[i] = 0; - return dst; -} - -static void default_print_section_header(WriterContext *wctx, const void *data) -{ - DefaultContext *def = wctx->priv; - char buf[32]; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - av_bprint_clear(&wctx->section_pbuf[wctx->level]); - if (parent_section && - !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) { - def->nested_section[wctx->level] = 1; - av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:", - wctx->section_pbuf[wctx->level-1].str, - upcase_string(buf, sizeof(buf), - av_x_if_null(section->element_name, section->name))); - } - - if (def->noprint_wrappers || def->nested_section[wctx->level]) - return; - - if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) - writer_printf(wctx, "[%s]\n", upcase_string(buf, sizeof(buf), section->name)); -} - -static void default_print_section_footer(WriterContext *wctx) -{ - DefaultContext *def = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - char buf[32]; - - if (def->noprint_wrappers || def->nested_section[wctx->level]) - return; - - if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) - writer_printf(wctx, "[/%s]\n", upcase_string(buf, sizeof(buf), section->name)); -} - -static void default_print_str(WriterContext *wctx, const char *key, const char *value) -{ - DefaultContext *def = wctx->priv; - - if (!def->nokey) - writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); - writer_printf(wctx, "%s\n", value); -} - -static void default_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - DefaultContext *def = wctx->priv; - - if (!def->nokey) - writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); - writer_printf(wctx, "%"PRId64"\n", value); -} - -static const Writer default_writer = { - .name = "default", - .priv_size = sizeof(DefaultContext), - .print_section_header = default_print_section_header, - .print_section_footer = default_print_section_footer, - .print_integer = default_print_int, - .print_string = default_print_str, - .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS, - .priv_class = &default_class, -}; - -/* Compact output */ - -/** - * Apply C-language-like string escaping. - */ -static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) -{ - const char *p; - - for (p = src; *p; p++) { - switch (*p) { - case '\b': av_bprintf(dst, "%s", "\\b"); break; - case '\f': av_bprintf(dst, "%s", "\\f"); break; - case '\n': av_bprintf(dst, "%s", "\\n"); break; - case '\r': av_bprintf(dst, "%s", "\\r"); break; - case '\\': av_bprintf(dst, "%s", "\\\\"); break; - default: - if (*p == sep) - av_bprint_chars(dst, '\\', 1); - av_bprint_chars(dst, *p, 1); - } - } - return dst->str; -} - -/** - * Quote fields containing special characters, check RFC4180. - */ -static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) -{ - char meta_chars[] = { sep, '"', '\n', '\r', '\0' }; - int needs_quoting = !!src[strcspn(src, meta_chars)]; - - if (needs_quoting) - av_bprint_chars(dst, '"', 1); - - for (; *src; src++) { - if (*src == '"') - av_bprint_chars(dst, '"', 1); - av_bprint_chars(dst, *src, 1); - } - if (needs_quoting) - av_bprint_chars(dst, '"', 1); - return dst->str; -} - -static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) -{ - return src; -} - -typedef struct CompactContext { - const AVClass *class; - char *item_sep_str; - char item_sep; - int nokey; - int print_section; - char *escape_mode_str; - const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx); - int nested_section[SECTION_MAX_NB_LEVELS]; - int has_nested_elems[SECTION_MAX_NB_LEVELS]; - int terminate_line[SECTION_MAX_NB_LEVELS]; -} CompactContext; - -#undef OFFSET -#define OFFSET(x) offsetof(CompactContext, x) - -static const AVOption compact_options[]= { - {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 }, - {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 }, - {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 }, - {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 }, - {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(compact); - -static av_cold int compact_init(WriterContext *wctx) -{ - CompactContext *compact = wctx->priv; - - if (strlen(compact->item_sep_str) != 1) { - av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n", - compact->item_sep_str); - return AVERROR(EINVAL); - } - compact->item_sep = compact->item_sep_str[0]; - - if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str; - else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str; - else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str; - else { - av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str); - return AVERROR(EINVAL); - } - - return 0; -} - -static void compact_print_section_header(WriterContext *wctx, const void *data) -{ - CompactContext *compact = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - compact->terminate_line[wctx->level] = 1; - compact->has_nested_elems[wctx->level] = 0; - - av_bprint_clear(&wctx->section_pbuf[wctx->level]); - if (parent_section && - (section->flags & SECTION_FLAG_HAS_TYPE || - (!(section->flags & SECTION_FLAG_IS_ARRAY) && - !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))))) { - - /* define a prefix for elements not contained in an array or - in a wrapper, or for array elements with a type */ - const char *element_name = (char *)av_x_if_null(section->element_name, section->name); - AVBPrint *section_pbuf = &wctx->section_pbuf[wctx->level]; - - compact->nested_section[wctx->level] = 1; - compact->has_nested_elems[wctx->level-1] = 1; - - av_bprintf(section_pbuf, "%s%s", - wctx->section_pbuf[wctx->level-1].str, element_name); - - if (section->flags & SECTION_FLAG_HAS_TYPE) { - // add /TYPE to prefix - av_bprint_chars(section_pbuf, '/', 1); - - // normalize section type, replace special characters and lower case - for (const char *p = section->get_type(data); *p; p++) { - char c = - (*p >= '0' && *p <= '9') || - (*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z') ? av_tolower(*p) : '_'; - av_bprint_chars(section_pbuf, c, 1); - } - } - av_bprint_chars(section_pbuf, ':', 1); - - wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1]; - } else { - if (parent_section && !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)) && - wctx->level && wctx->nb_item[wctx->level-1]) - writer_w8(wctx, compact->item_sep); - if (compact->print_section && - !(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) - writer_printf(wctx, "%s%c", section->name, compact->item_sep); - } -} - -static void compact_print_section_footer(WriterContext *wctx) -{ - CompactContext *compact = wctx->priv; - - if (!compact->nested_section[wctx->level] && - compact->terminate_line[wctx->level] && - !(wctx->section[wctx->level]->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) - writer_w8(wctx, '\n'); -} - -static void compact_print_str(WriterContext *wctx, const char *key, const char *value) -{ - CompactContext *compact = wctx->priv; - AVBPrint buf; - - if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep); - if (!compact->nokey) - writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_put_str(wctx, compact->escape_str(&buf, value, compact->item_sep, wctx)); - av_bprint_finalize(&buf, NULL); -} - -static void compact_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - CompactContext *compact = wctx->priv; - - if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep); - if (!compact->nokey) - writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); - writer_printf(wctx, "%"PRId64, value); -} - -static const Writer compact_writer = { - .name = "compact", - .priv_size = sizeof(CompactContext), - .init = compact_init, - .print_section_header = compact_print_section_header, - .print_section_footer = compact_print_section_footer, - .print_integer = compact_print_int, - .print_string = compact_print_str, - .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS, - .priv_class = &compact_class, -}; - -/* CSV output */ - -#undef OFFSET -#define OFFSET(x) offsetof(CompactContext, x) - -static const AVOption csv_options[] = { - {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 }, - {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 }, - {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 }, - {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 }, - {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(csv); - -static const Writer csv_writer = { - .name = "csv", - .priv_size = sizeof(CompactContext), - .init = compact_init, - .print_section_header = compact_print_section_header, - .print_section_footer = compact_print_section_footer, - .print_integer = compact_print_int, - .print_string = compact_print_str, - .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS, - .priv_class = &csv_class, -}; - -/* Flat output */ - -typedef struct FlatContext { - const AVClass *class; - const char *sep_str; - char sep; - int hierarchical; -} FlatContext; - -#undef OFFSET -#define OFFSET(x) offsetof(FlatContext, x) - -static const AVOption flat_options[]= { - {"sep_char", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 }, - {"s", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 }, - {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(flat); - -static av_cold int flat_init(WriterContext *wctx) -{ - FlatContext *flat = wctx->priv; - - if (strlen(flat->sep_str) != 1) { - av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n", - flat->sep_str); - return AVERROR(EINVAL); - } - flat->sep = flat->sep_str[0]; - - return 0; -} - -static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep) -{ - const char *p; - - for (p = src; *p; p++) { - if (!((*p >= '0' && *p <= '9') || - (*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z'))) - av_bprint_chars(dst, '_', 1); - else - av_bprint_chars(dst, *p, 1); - } - return dst->str; -} - -static const char *flat_escape_value_str(AVBPrint *dst, const char *src) -{ - const char *p; - - for (p = src; *p; p++) { - switch (*p) { - case '\n': av_bprintf(dst, "%s", "\\n"); break; - case '\r': av_bprintf(dst, "%s", "\\r"); break; - case '\\': av_bprintf(dst, "%s", "\\\\"); break; - case '"': av_bprintf(dst, "%s", "\\\""); break; - case '`': av_bprintf(dst, "%s", "\\`"); break; - case '$': av_bprintf(dst, "%s", "\\$"); break; - default: av_bprint_chars(dst, *p, 1); break; - } - } - return dst->str; -} - -static void flat_print_section_header(WriterContext *wctx, const void *data) -{ - FlatContext *flat = wctx->priv; - AVBPrint *buf = &wctx->section_pbuf[wctx->level]; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - /* build section header */ - av_bprint_clear(buf); - if (!parent_section) - return; - av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str); - - if (flat->hierarchical || - !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) { - av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str); - - if (parent_section->flags & SECTION_FLAG_IS_ARRAY) { - int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ? - wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1]; - av_bprintf(buf, "%d%s", n, flat->sep_str); - } - } -} - -static void flat_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - writer_printf(wctx, "%s%s=%"PRId64"\n", wctx->section_pbuf[wctx->level].str, key, value); -} - -static void flat_print_str(WriterContext *wctx, const char *key, const char *value) -{ - FlatContext *flat = wctx->priv; - AVBPrint buf; - - writer_put_str(wctx, wctx->section_pbuf[wctx->level].str); - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_printf(wctx, "%s=", flat_escape_key_str(&buf, key, flat->sep)); - av_bprint_clear(&buf); - writer_printf(wctx, "\"%s\"\n", flat_escape_value_str(&buf, value)); - av_bprint_finalize(&buf, NULL); -} - -static const Writer flat_writer = { - .name = "flat", - .priv_size = sizeof(FlatContext), - .init = flat_init, - .print_section_header = flat_print_section_header, - .print_integer = flat_print_int, - .print_string = flat_print_str, - .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, - .priv_class = &flat_class, -}; - -/* INI format output */ - -typedef struct INIContext { - const AVClass *class; - int hierarchical; -} INIContext; - -#undef OFFSET -#define OFFSET(x) offsetof(INIContext, x) - -static const AVOption ini_options[] = { - {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(ini); - -static char *ini_escape_str(AVBPrint *dst, const char *src) -{ - int i = 0; - char c = 0; - - while (c = src[i++]) { - switch (c) { - case '\b': av_bprintf(dst, "%s", "\\b"); break; - case '\f': av_bprintf(dst, "%s", "\\f"); break; - case '\n': av_bprintf(dst, "%s", "\\n"); break; - case '\r': av_bprintf(dst, "%s", "\\r"); break; - case '\t': av_bprintf(dst, "%s", "\\t"); break; - case '\\': - case '#' : - case '=' : - case ':' : av_bprint_chars(dst, '\\', 1); - default: - if ((unsigned char)c < 32) - av_bprintf(dst, "\\x00%02x", c & 0xff); - else - av_bprint_chars(dst, c, 1); - break; - } - } - return dst->str; -} - -static void ini_print_section_header(WriterContext *wctx, const void *data) -{ - INIContext *ini = wctx->priv; - AVBPrint *buf = &wctx->section_pbuf[wctx->level]; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - av_bprint_clear(buf); - if (!parent_section) { - writer_put_str(wctx, "# ffprobe output\n\n"); - return; - } - - if (wctx->nb_item[wctx->level-1]) - writer_w8(wctx, '\n'); - - av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str); - if (ini->hierarchical || - !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) { - av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name); - - if (parent_section->flags & SECTION_FLAG_IS_ARRAY) { - int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ? - wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1]; - av_bprintf(buf, ".%d", n); - } - } - - if (!(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) - writer_printf(wctx, "[%s]\n", buf->str); -} - -static void ini_print_str(WriterContext *wctx, const char *key, const char *value) -{ - AVBPrint buf; - - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_printf(wctx, "%s=", ini_escape_str(&buf, key)); - av_bprint_clear(&buf); - writer_printf(wctx, "%s\n", ini_escape_str(&buf, value)); - av_bprint_finalize(&buf, NULL); -} - -static void ini_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - writer_printf(wctx, "%s=%"PRId64"\n", key, value); -} - -static const Writer ini_writer = { - .name = "ini", - .priv_size = sizeof(INIContext), - .print_section_header = ini_print_section_header, - .print_integer = ini_print_int, - .print_string = ini_print_str, - .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, - .priv_class = &ini_class, -}; - -/* JSON output */ - -typedef struct JSONContext { - const AVClass *class; - int indent_level; - int compact; - const char *item_sep, *item_start_end; -} JSONContext; - -#undef OFFSET -#define OFFSET(x) offsetof(JSONContext, x) - -static const AVOption json_options[]= { - { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - { NULL } -}; - -DEFINE_WRITER_CLASS(json); - -static av_cold int json_init(WriterContext *wctx) -{ - JSONContext *json = wctx->priv; - - json->item_sep = json->compact ? ", " : ",\n"; - json->item_start_end = json->compact ? " " : "\n"; - - return 0; -} - -static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx) -{ - static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0}; - static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0}; - const char *p; - - for (p = src; *p; p++) { - char *s = strchr(json_escape, *p); - if (s) { - av_bprint_chars(dst, '\\', 1); - av_bprint_chars(dst, json_subst[s - json_escape], 1); - } else if ((unsigned char)*p < 32) { - av_bprintf(dst, "\\u00%02x", *p & 0xff); - } else { - av_bprint_chars(dst, *p, 1); - } - } - return dst->str; -} - -#define JSON_INDENT() writer_printf(wctx, "%*c", json->indent_level * 4, ' ') - -static void json_print_section_header(WriterContext *wctx, const void *data) -{ - JSONContext *json = wctx->priv; - AVBPrint buf; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - if (wctx->level && wctx->nb_item[wctx->level-1]) - writer_put_str(wctx, ",\n"); - - if (section->flags & SECTION_FLAG_IS_WRAPPER) { - writer_put_str(wctx, "{\n"); - json->indent_level++; - } else { - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - json_escape_str(&buf, section->name, wctx); - JSON_INDENT(); - - json->indent_level++; - if (section->flags & SECTION_FLAG_IS_ARRAY) { - writer_printf(wctx, "\"%s\": [\n", buf.str); - } else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) { - writer_printf(wctx, "\"%s\": {%s", buf.str, json->item_start_end); - } else { - writer_printf(wctx, "{%s", json->item_start_end); - - /* this is required so the parser can distinguish between packets and frames */ - if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) { - if (!json->compact) - JSON_INDENT(); - writer_printf(wctx, "\"type\": \"%s\"", section->name); - wctx->nb_item[wctx->level]++; - } - } - av_bprint_finalize(&buf, NULL); - } -} - -static void json_print_section_footer(WriterContext *wctx) -{ - JSONContext *json = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - - if (wctx->level == 0) { - json->indent_level--; - writer_put_str(wctx, "\n}\n"); - } else if (section->flags & SECTION_FLAG_IS_ARRAY) { - writer_w8(wctx, '\n'); - json->indent_level--; - JSON_INDENT(); - writer_w8(wctx, ']'); - } else { - writer_put_str(wctx, json->item_start_end); - json->indent_level--; - if (!json->compact) - JSON_INDENT(); - writer_w8(wctx, '}'); - } -} - -static inline void json_print_item_str(WriterContext *wctx, - const char *key, const char *value) -{ - AVBPrint buf; - - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_printf(wctx, "\"%s\":", json_escape_str(&buf, key, wctx)); - av_bprint_clear(&buf); - writer_printf(wctx, " \"%s\"", json_escape_str(&buf, value, wctx)); - av_bprint_finalize(&buf, NULL); -} - -static void json_print_str(WriterContext *wctx, const char *key, const char *value) -{ - JSONContext *json = wctx->priv; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES)) - writer_put_str(wctx, json->item_sep); - if (!json->compact) - JSON_INDENT(); - json_print_item_str(wctx, key, value); -} - -static void json_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - JSONContext *json = wctx->priv; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - AVBPrint buf; - - if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES)) - writer_put_str(wctx, json->item_sep); - if (!json->compact) - JSON_INDENT(); - - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_printf(wctx, "\"%s\": %"PRId64, json_escape_str(&buf, key, wctx), value); - av_bprint_finalize(&buf, NULL); -} - -static const Writer json_writer = { - .name = "json", - .priv_size = sizeof(JSONContext), - .init = json_init, - .print_section_header = json_print_section_header, - .print_section_footer = json_print_section_footer, - .print_integer = json_print_int, - .print_string = json_print_str, - .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, - .priv_class = &json_class, -}; - -/* XML output */ - -typedef struct XMLContext { - const AVClass *class; - int within_tag; - int indent_level; - int fully_qualified; - int xsd_strict; -} XMLContext; - -#undef OFFSET -#define OFFSET(x) offsetof(XMLContext, x) - -static const AVOption xml_options[] = { - {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {"q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(xml); - -static av_cold int xml_init(WriterContext *wctx) -{ - XMLContext *xml = wctx->priv; - - if (xml->xsd_strict) { - xml->fully_qualified = 1; -#define CHECK_COMPLIANCE(opt, opt_name) \ - if (opt) { \ - av_log(wctx, AV_LOG_ERROR, \ - "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \ - "You need to disable such option with '-no%s'\n", opt_name, opt_name); \ - return AVERROR(EINVAL); \ - } - CHECK_COMPLIANCE(show_private_data, "private"); - CHECK_COMPLIANCE(show_value_unit, "unit"); - CHECK_COMPLIANCE(use_value_prefix, "prefix"); - } - - return 0; -} - -#define XML_INDENT() writer_printf(wctx, "%*c", xml->indent_level * 4, ' ') - -static void xml_print_section_header(WriterContext *wctx, const void *data) -{ - XMLContext *xml = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - if (wctx->level == 0) { - const char *qual = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " - "xmlns:ffprobe=\"http://www.ffmpeg.org/schema/ffprobe\" " - "xsi:schemaLocation=\"http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd\""; - - writer_put_str(wctx, "\n"); - writer_printf(wctx, "<%sffprobe%s>\n", - xml->fully_qualified ? "ffprobe:" : "", - xml->fully_qualified ? qual : ""); - return; - } - - if (xml->within_tag) { - xml->within_tag = 0; - writer_put_str(wctx, ">\n"); - } - - if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) && - wctx->level && wctx->nb_item[wctx->level-1]) - writer_w8(wctx, '\n'); - xml->indent_level++; - - if (section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_HAS_VARIABLE_FIELDS)) { - XML_INDENT(); writer_printf(wctx, "<%s", section->name); - - if (section->flags & SECTION_FLAG_HAS_TYPE) { - AVBPrint buf; - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - av_bprint_escape(&buf, section->get_type(data), NULL, - AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); - writer_printf(wctx, " type=\"%s\"", buf.str); - } - writer_printf(wctx, ">\n", section->name); - } else { - XML_INDENT(); writer_printf(wctx, "<%s ", section->name); - xml->within_tag = 1; - } -} - -static void xml_print_section_footer(WriterContext *wctx) -{ - XMLContext *xml = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - - if (wctx->level == 0) { - writer_printf(wctx, "\n", xml->fully_qualified ? "ffprobe:" : ""); - } else if (xml->within_tag) { - xml->within_tag = 0; - writer_put_str(wctx, "/>\n"); - xml->indent_level--; - } else { - XML_INDENT(); writer_printf(wctx, "\n", section->name); - xml->indent_level--; - } -} - -static void xml_print_value(WriterContext *wctx, const char *key, - const char *str, int64_t num, const int is_int) -{ - AVBPrint buf; - XMLContext *xml = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - - if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) { - xml->indent_level++; - XML_INDENT(); - av_bprint_escape(&buf, key, NULL, - AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); - writer_printf(wctx, "<%s key=\"%s\"", - section->element_name, buf.str); - av_bprint_clear(&buf); - - if (is_int) { - writer_printf(wctx, " value=\"%"PRId64"\"/>\n", num); - } else { - av_bprint_escape(&buf, str, NULL, - AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); - writer_printf(wctx, " value=\"%s\"/>\n", buf.str); - } - xml->indent_level--; - } else { - if (wctx->nb_item[wctx->level]) - writer_w8(wctx, ' '); - - if (is_int) { - writer_printf(wctx, "%s=\"%"PRId64"\"", key, num); - } else { - av_bprint_escape(&buf, str, NULL, - AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); - writer_printf(wctx, "%s=\"%s\"", key, buf.str); - } - } - - av_bprint_finalize(&buf, NULL); -} - -static inline void xml_print_str(WriterContext *wctx, const char *key, const char *value) { - xml_print_value(wctx, key, value, 0, 0); -} - -static void xml_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - xml_print_value(wctx, key, NULL, value, 1); -} - -static Writer xml_writer = { - .name = "xml", - .priv_size = sizeof(XMLContext), - .init = xml_init, - .print_section_header = xml_print_section_header, - .print_section_footer = xml_print_section_footer, - .print_integer = xml_print_int, - .print_string = xml_print_str, - .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, - .priv_class = &xml_class, -}; - -static void writer_register_all(void) -{ - static int initialized; - - if (initialized) - return; - initialized = 1; - - writer_register(&default_writer); - writer_register(&compact_writer); - writer_register(&csv_writer); - writer_register(&flat_writer); - writer_register(&ini_writer); - writer_register(&json_writer); - writer_register(&xml_writer); -} #define print_fmt(k, f, ...) do { \ av_bprint_clear(&pbuf); \ av_bprintf(&pbuf, f, __VA_ARGS__); \ - writer_print_string(w, k, pbuf.str, 0); \ + avtext_print_string(tfc, k, pbuf.str, 0); \ } while (0) #define print_list_fmt(k, f, n, m, ...) do { \ @@ -2009,28 +439,43 @@ static void writer_register_all(void) av_bprintf(&pbuf, f, __VA_ARGS__); \ } \ } \ - writer_print_string(w, k, pbuf.str, 0); \ + avtext_print_string(tfc, k, pbuf.str, 0); \ } while (0) -#define print_int(k, v) writer_print_integer(w, k, v) -#define print_q(k, v, s) writer_print_rational(w, k, v, s) -#define print_str(k, v) writer_print_string(w, k, v, 0) -#define print_str_opt(k, v) writer_print_string(w, k, v, PRINT_STRING_OPT) -#define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE) -#define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0) -#define print_ts(k, v) writer_print_ts(w, k, v, 0) -#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1) -#define print_duration_ts(k, v) writer_print_ts(w, k, v, 1) -#define print_val(k, v, u) do { \ - struct unit_value uv; \ - uv.val.i = v; \ - uv.unit = u; \ - writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \ -} while (0) +#define print_int(k, v) avtext_print_integer(tfc, k, v, 0) +#define print_q(k, v, s) avtext_print_rational(tfc, k, v, s) +#define print_str(k, v) avtext_print_string(tfc, k, v, 0) +#define print_str_opt(k, v) avtext_print_string(tfc, k, v, AV_TEXTFORMAT_PRINT_STRING_OPTIONAL) +#define print_str_validate(k, v) avtext_print_string(tfc, k, v, AV_TEXTFORMAT_PRINT_STRING_VALIDATE) +#define print_time(k, v, tb) avtext_print_time(tfc, k, v, tb, 0) +#define print_ts(k, v) avtext_print_ts(tfc, k, v, 0) +#define print_duration_time(k, v, tb) avtext_print_time(tfc, k, v, tb, 1) +#define print_duration_ts(k, v) avtext_print_ts(tfc, k, v, 1) +#define print_val(k, v, u) avtext_print_unit_integer(tfc, k, v, u) -#define print_section_header(s) writer_print_section_header(w, NULL, s) -#define print_section_header_data(s, d) writer_print_section_header(w, d, s) -#define print_section_footer(s) writer_print_section_footer(w, s) +static void print_integers(AVTextFormatContext *tfc, const char *key, + const void *data, int size, const char *format, + int columns, int bytes, int offset_add) +{ + AVBPrint bp; + unsigned offset = 0; + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); + av_bprint_chars(&bp, '\n', 1); + while (size) { + av_bprintf(&bp, "%08x: ", offset); + for (int i = 0, l = FFMIN(size, columns); i < l; i++) { + if (bytes == 1) av_bprintf(&bp, format, *(const uint8_t*)data); + else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data)); + else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data)); + data = (const char*)data + bytes; + size--; + } + av_bprint_chars(&bp, '\n', 1); + offset += offset_add; + } + avtext_print_string(tfc, key, bp.str, 0); +} #define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n) \ { \ @@ -2040,25 +485,62 @@ static void writer_register_all(void) memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \ } -static inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id) +static inline int show_tags(AVTextFormatContext *tfc, AVDictionary *tags, int section_id) { const AVDictionaryEntry *tag = NULL; int ret = 0; if (!tags) return 0; - writer_print_section_header(w, NULL, section_id); + avtext_print_section_header(tfc, NULL, section_id); while ((tag = av_dict_iterate(tags, tag))) { if ((ret = print_str_validate(tag->key, tag->value)) < 0) break; } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) +static void print_displaymatrix(AVTextFormatContext *tfc, const int32_t matrix[9]) +{ + double rotation = av_display_rotation_get(matrix); + if (isnan(rotation)) + rotation = 0; + print_integers(tfc, "displaymatrix", matrix, 9, " %11d", 3, 4, 1); + print_int("rotation", rotation); +} + +static void print_mastering_display_metadata(AVTextFormatContext *tfc, + const AVMasteringDisplayMetadata *metadata) +{ + if (metadata->has_primaries) { + print_q("red_x", metadata->display_primaries[0][0], '/'); + print_q("red_y", metadata->display_primaries[0][1], '/'); + print_q("green_x", metadata->display_primaries[1][0], '/'); + print_q("green_y", metadata->display_primaries[1][1], '/'); + print_q("blue_x", metadata->display_primaries[2][0], '/'); + print_q("blue_y", metadata->display_primaries[2][1], '/'); + + print_q("white_point_x", metadata->white_point[0], '/'); + print_q("white_point_y", metadata->white_point[1], '/'); + } + + if (metadata->has_luminance) { + print_q("min_luminance", metadata->min_luminance, '/'); + print_q("max_luminance", metadata->max_luminance, '/'); + } +} + +static void print_context_light_level(AVTextFormatContext *tfc, + const AVContentLightMetadata *metadata) +{ + print_int("max_content", metadata->MaxCLL); + print_int("max_average", metadata->MaxFALL); +} + +static void print_dovi_metadata(AVTextFormatContext *tfc, const AVDOVIMetadata *dovi) { if (!dovi) return; @@ -2113,15 +595,15 @@ static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) print_int("num_x_partitions", mapping->num_x_partitions); print_int("num_y_partitions", mapping->num_y_partitions); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); for (int c = 0; c < 3; c++) { const AVDOVIReshapingCurve *curve = &mapping->curves[c]; - writer_print_section_header(w, "Reshaping curve", SECTION_ID_FRAME_SIDE_DATA_COMPONENT); + avtext_print_section_header(tfc, "Reshaping curve", SECTION_ID_FRAME_SIDE_DATA_COMPONENT); print_list_fmt("pivots", "%"PRIu16, curve->num_pivots, 1, curve->pivots[idx]); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST); for (int i = 0; i < curve->num_pivots - 1; i++) { AVBPrint piece_buf; @@ -2139,7 +621,7 @@ static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) } av_bprintf(&piece_buf, " mapping"); - writer_print_section_header(w, piece_buf.str, SECTION_ID_FRAME_SIDE_DATA_PIECE); + avtext_print_section_header(tfc, piece_buf.str, SECTION_ID_FRAME_SIDE_DATA_PIECE); print_int("mapping_idc", curve->mapping_idc[i]); switch (curve->mapping_idc[i]) { case AV_DOVI_MAPPING_POLYNOMIAL: @@ -2163,11 +645,11 @@ static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) } // SECTION_ID_FRAME_SIDE_DATA_PIECE - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } // SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST - writer_print_section_footer(w); + avtext_print_section_footer(tfc); if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) { const AVDOVINLQParams *nlq = &mapping->nlq[c]; @@ -2183,11 +665,11 @@ static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) } // SECTION_ID_FRAME_SIDE_DATA_COMPONENT - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST - writer_print_section_footer(w); + avtext_print_section_footer(tfc); // color metadata print_int("dm_metadata_id", color->dm_metadata_id); @@ -2220,7 +702,7 @@ static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) } } -static void print_dynamic_hdr10_plus(WriterContext *w, const AVDynamicHDRPlus *metadata) +static void print_dynamic_hdr10_plus(AVTextFormatContext *tfc, const AVDynamicHDRPlus *metadata) { if (!metadata) return; @@ -2319,7 +801,7 @@ static void print_dynamic_hdr10_plus(WriterContext *w, const AVDynamicHDRPlus *m } } -static void print_dynamic_hdr_vivid(WriterContext *w, const AVDynamicHDRVivid *metadata) +static void print_dynamic_hdr_vivid(AVTextFormatContext *tfc, const AVDynamicHDRVivid *metadata) { if (!metadata) return; @@ -2389,7 +871,7 @@ static void print_dynamic_hdr_vivid(WriterContext *w, const AVDynamicHDRVivid *m } } -static void print_ambient_viewing_environment(WriterContext *w, +static void print_ambient_viewing_environment(AVTextFormatContext *tfc, const AVAmbientViewingEnvironment *env) { if (!env) @@ -2400,7 +882,7 @@ static void print_ambient_viewing_environment(WriterContext *w, print_q("ambient_light_y", env->ambient_light_y, '/'); } -static void print_film_grain_params(WriterContext *w, +static void print_film_grain_params(AVTextFormatContext *tfc, const AVFilmGrainParams *fgp) { const char *color_range, *color_primaries, *color_trc, *color_space; @@ -2446,10 +928,10 @@ static void print_film_grain_params(WriterContext *w, print_int("overlap_flag", aom->overlap_flag); print_int("limit_output_range", aom->limit_output_range); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); if (aom->num_y_points) { - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); print_int("bit_depth_luma", fgp->bit_depth_luma); print_list_fmt("y_points_value", "%"PRIu8, aom->num_y_points, 1, aom->y_points[idx][0]); @@ -2457,14 +939,14 @@ static void print_film_grain_params(WriterContext *w, print_list_fmt("ar_coeffs_y", "%"PRId8, num_ar_coeffs_y, 1, aom->ar_coeffs_y[idx]); // SECTION_ID_FRAME_SIDE_DATA_COMPONENT - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } for (int uv = 0; uv < 2; uv++) { if (!aom->num_uv_points[uv] && !aom->chroma_scaling_from_luma) continue; - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); print_int("bit_depth_chroma", fgp->bit_depth_chroma); print_list_fmt("uv_points_value", "%"PRIu8, aom->num_uv_points[uv], 1, aom->uv_points[uv][idx][0]); @@ -2475,11 +957,11 @@ static void print_film_grain_params(WriterContext *w, print_int("uv_offset", aom->uv_offset[uv]); // SECTION_ID_FRAME_SIDE_DATA_COMPONENT - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST - writer_print_section_footer(w); + avtext_print_section_footer(tfc); break; } case AV_FILM_GRAIN_PARAMS_H274: { @@ -2488,36 +970,36 @@ static void print_film_grain_params(WriterContext *w, print_int("blending_mode_id", h274->blending_mode_id); print_int("log2_scale_factor", h274->log2_scale_factor); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); for (int c = 0; c < 3; c++) { if (!h274->component_model_present[c]) continue; - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); print_int(c ? "bit_depth_chroma" : "bit_depth_luma", c ? fgp->bit_depth_chroma : fgp->bit_depth_luma); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST); for (int i = 0; i < h274->num_intensity_intervals[c]; i++) { - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE); print_int("intensity_interval_lower_bound", h274->intensity_interval_lower_bound[c][i]); print_int("intensity_interval_upper_bound", h274->intensity_interval_upper_bound[c][i]); print_list_fmt("comp_model_value", "%"PRId16, h274->num_model_values[c], 1, h274->comp_model_value[c][i][idx]); // SECTION_ID_FRAME_SIDE_DATA_PIECE - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } // SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST - writer_print_section_footer(w); + avtext_print_section_footer(tfc); // SECTION_ID_FRAME_SIDE_DATA_COMPONENT - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST - writer_print_section_footer(w); + avtext_print_section_footer(tfc); break; } } @@ -2525,129 +1007,112 @@ static void print_film_grain_params(WriterContext *w, av_bprint_finalize(&pbuf, NULL); } -static void print_pkt_side_data(WriterContext *w, +static void print_pkt_side_data(AVTextFormatContext *tfc, AVCodecParameters *par, const AVPacketSideData *sd, SectionID id_data) { - const char *name = av_packet_side_data_name(sd->type); + const char *name = av_packet_side_data_name(sd->type); - writer_print_section_header(w, sd, id_data); - print_str("side_data_type", name ? name : "unknown"); - if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) { - double rotation = av_display_rotation_get((int32_t *)sd->data); - if (isnan(rotation)) - rotation = 0; - writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1); - print_int("rotation", rotation); - } else if (sd->type == AV_PKT_DATA_STEREO3D) { - const AVStereo3D *stereo = (AVStereo3D *)sd->data; - print_str("type", av_stereo3d_type_name(stereo->type)); - print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT)); - print_str("view", av_stereo3d_view_name(stereo->view)); - print_str("primary_eye", av_stereo3d_primary_eye_name(stereo->primary_eye)); - print_int("baseline", stereo->baseline); - print_q("horizontal_disparity_adjustment", stereo->horizontal_disparity_adjustment, '/'); - print_q("horizontal_field_of_view", stereo->horizontal_field_of_view, '/'); - } else if (sd->type == AV_PKT_DATA_SPHERICAL) { - const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data; - print_str("projection", av_spherical_projection_name(spherical->projection)); - if (spherical->projection == AV_SPHERICAL_CUBEMAP) { - print_int("padding", spherical->padding); - } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) { - size_t l, t, r, b; - av_spherical_tile_bounds(spherical, par->width, par->height, - &l, &t, &r, &b); - print_int("bound_left", l); - print_int("bound_top", t); - print_int("bound_right", r); - print_int("bound_bottom", b); - } - - print_int("yaw", (double) spherical->yaw / (1 << 16)); - print_int("pitch", (double) spherical->pitch / (1 << 16)); - print_int("roll", (double) spherical->roll / (1 << 16)); - } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) { - print_int("skip_samples", AV_RL32(sd->data)); - print_int("discard_padding", AV_RL32(sd->data + 4)); - print_int("skip_reason", AV_RL8(sd->data + 8)); - print_int("discard_reason", AV_RL8(sd->data + 9)); - } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) { - AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data; - - if (metadata->has_primaries) { - print_q("red_x", metadata->display_primaries[0][0], '/'); - print_q("red_y", metadata->display_primaries[0][1], '/'); - print_q("green_x", metadata->display_primaries[1][0], '/'); - print_q("green_y", metadata->display_primaries[1][1], '/'); - print_q("blue_x", metadata->display_primaries[2][0], '/'); - print_q("blue_y", metadata->display_primaries[2][1], '/'); - - print_q("white_point_x", metadata->white_point[0], '/'); - print_q("white_point_y", metadata->white_point[1], '/'); - } - - if (metadata->has_luminance) { - print_q("min_luminance", metadata->min_luminance, '/'); - print_q("max_luminance", metadata->max_luminance, '/'); - } - } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) { - AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data; - print_int("max_content", metadata->MaxCLL); - print_int("max_average", metadata->MaxFALL); - } else if (sd->type == AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT) { - print_ambient_viewing_environment( - w, (const AVAmbientViewingEnvironment *)sd->data); - } else if (sd->type == AV_PKT_DATA_DYNAMIC_HDR10_PLUS) { - AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data; - print_dynamic_hdr10_plus(w, metadata); - } else if (sd->type == AV_PKT_DATA_DOVI_CONF) { - AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data; - const char *comp = "unknown"; - print_int("dv_version_major", dovi->dv_version_major); - print_int("dv_version_minor", dovi->dv_version_minor); - print_int("dv_profile", dovi->dv_profile); - print_int("dv_level", dovi->dv_level); - print_int("rpu_present_flag", dovi->rpu_present_flag); - print_int("el_present_flag", dovi->el_present_flag); - print_int("bl_present_flag", dovi->bl_present_flag); - print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id); - switch (dovi->dv_md_compression) - { - case AV_DOVI_COMPRESSION_NONE: comp = "none"; break; - case AV_DOVI_COMPRESSION_LIMITED: comp = "limited"; break; - case AV_DOVI_COMPRESSION_RESERVED: comp = "reserved"; break; - case AV_DOVI_COMPRESSION_EXTENDED: comp = "extended"; break; - } - print_str("dv_md_compression", comp); - } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) { - enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data; - print_int("service_type", *t); - } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) { - print_int("id", *sd->data); - } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) { - const AVCPBProperties *prop = (AVCPBProperties *)sd->data; - print_int("max_bitrate", prop->max_bitrate); - print_int("min_bitrate", prop->min_bitrate); - print_int("avg_bitrate", prop->avg_bitrate); - print_int("buffer_size", prop->buffer_size); - print_int("vbv_delay", prop->vbv_delay); - } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER || - sd->type == AV_PKT_DATA_WEBVTT_SETTINGS) { - if (do_show_data) - writer_print_data(w, "data", sd->data, sd->size); - writer_print_data_hash(w, "data_hash", sd->data, sd->size); - } else if (sd->type == AV_PKT_DATA_FRAME_CROPPING && sd->size >= sizeof(uint32_t) * 4) { - print_int("crop_top", AV_RL32(sd->data)); - print_int("crop_bottom", AV_RL32(sd->data + 4)); - print_int("crop_left", AV_RL32(sd->data + 8)); - print_int("crop_right", AV_RL32(sd->data + 12)); - } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) { - print_int("active_format", *sd->data); + avtext_print_section_header(tfc, sd, id_data); + print_str("side_data_type", name ? name : "unknown"); + if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) { + print_displaymatrix(tfc, (const int32_t*)sd->data); + } else if (sd->type == AV_PKT_DATA_STEREO3D) { + const AVStereo3D *stereo = (AVStereo3D *)sd->data; + print_str("type", av_stereo3d_type_name(stereo->type)); + print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT)); + print_str("view", av_stereo3d_view_name(stereo->view)); + print_str("primary_eye", av_stereo3d_primary_eye_name(stereo->primary_eye)); + print_int("baseline", stereo->baseline); + print_q("horizontal_disparity_adjustment", stereo->horizontal_disparity_adjustment, '/'); + print_q("horizontal_field_of_view", stereo->horizontal_field_of_view, '/'); + } else if (sd->type == AV_PKT_DATA_SPHERICAL) { + const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data; + print_str("projection", av_spherical_projection_name(spherical->projection)); + if (spherical->projection == AV_SPHERICAL_CUBEMAP) { + print_int("padding", spherical->padding); + } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) { + size_t l, t, r, b; + av_spherical_tile_bounds(spherical, par->width, par->height, + &l, &t, &r, &b); + print_int("bound_left", l); + print_int("bound_top", t); + print_int("bound_right", r); + print_int("bound_bottom", b); } + + print_int("yaw", (double) spherical->yaw / (1 << 16)); + print_int("pitch", (double) spherical->pitch / (1 << 16)); + print_int("roll", (double) spherical->roll / (1 << 16)); + } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) { + print_int("skip_samples", AV_RL32(sd->data)); + print_int("discard_padding", AV_RL32(sd->data + 4)); + print_int("skip_reason", AV_RL8(sd->data + 8)); + print_int("discard_reason", AV_RL8(sd->data + 9)); + } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) { + print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data); + } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) { + print_context_light_level(tfc, (AVContentLightMetadata *)sd->data); + } else if (sd->type == AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT) { + print_ambient_viewing_environment( + tfc, (const AVAmbientViewingEnvironment *)sd->data); + } else if (sd->type == AV_PKT_DATA_DYNAMIC_HDR10_PLUS) { + AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data; + print_dynamic_hdr10_plus(tfc, metadata); + } else if (sd->type == AV_PKT_DATA_DOVI_CONF) { + AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data; + const char *comp = "unknown"; + print_int("dv_version_major", dovi->dv_version_major); + print_int("dv_version_minor", dovi->dv_version_minor); + print_int("dv_profile", dovi->dv_profile); + print_int("dv_level", dovi->dv_level); + print_int("rpu_present_flag", dovi->rpu_present_flag); + print_int("el_present_flag", dovi->el_present_flag); + print_int("bl_present_flag", dovi->bl_present_flag); + print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id); + switch (dovi->dv_md_compression) + { + case AV_DOVI_COMPRESSION_NONE: comp = "none"; break; + case AV_DOVI_COMPRESSION_LIMITED: comp = "limited"; break; + case AV_DOVI_COMPRESSION_RESERVED: comp = "reserved"; break; + case AV_DOVI_COMPRESSION_EXTENDED: comp = "extended"; break; + } + print_str("dv_md_compression", comp); + } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) { + enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data; + print_int("service_type", *t); + } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) { + print_int("id", *sd->data); + } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) { + const AVCPBProperties *prop = (AVCPBProperties *)sd->data; + print_int("max_bitrate", prop->max_bitrate); + print_int("min_bitrate", prop->min_bitrate); + print_int("avg_bitrate", prop->avg_bitrate); + print_int("buffer_size", prop->buffer_size); + print_int("vbv_delay", prop->vbv_delay); + } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER || + sd->type == AV_PKT_DATA_WEBVTT_SETTINGS) { + if (do_show_data) + avtext_print_data(tfc, "data", sd->data, sd->size); + avtext_print_data_hash(tfc, "data_hash", sd->data, sd->size); + } else if (sd->type == AV_PKT_DATA_FRAME_CROPPING && sd->size >= sizeof(uint32_t) * 4) { + print_int("crop_top", AV_RL32(sd->data)); + print_int("crop_bottom", AV_RL32(sd->data + 4)); + print_int("crop_left", AV_RL32(sd->data + 8)); + print_int("crop_right", AV_RL32(sd->data + 12)); + } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) { + print_int("active_format", *sd->data); + } else if (sd->type == AV_PKT_DATA_EXIF) { + print_int("size", sd->size); + } else if (sd->type == AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL && sd->size >= 8) { + print_int("block_additional_id", AV_RB64(sd->data)); + if (do_show_data) + avtext_print_data(tfc, "block_additional_data", sd->data + 8, sd->size - 8); + } } -static void print_private_data(WriterContext *w, void *priv_data) +static void print_private_data(AVTextFormatContext *tfc, void *priv_data) { const AVOption *opt = NULL; while (opt = av_opt_next(priv_data, opt)) { @@ -2660,7 +1125,32 @@ static void print_private_data(WriterContext *w, void *priv_data) } } -static void print_color_range(WriterContext *w, enum AVColorRange color_range) +static void print_pixel_format(AVTextFormatContext *tfc, enum AVPixelFormat pix_fmt) +{ + const char *s = av_get_pix_fmt_name(pix_fmt); + enum AVPixelFormat swapped_pix_fmt; + + if (!s) { + print_str_opt("pix_fmt", "unknown"); + } else if (!do_bitexact || + (swapped_pix_fmt = av_pix_fmt_swap_endianness(pix_fmt)) == AV_PIX_FMT_NONE) { + print_str ("pix_fmt", s); + } else { + const char *s2 = av_get_pix_fmt_name(swapped_pix_fmt); + char buf[128]; + size_t i = 0; + + while (s[i] && s[i] == s2[i] && i < sizeof(buf) - 1) { + buf[i] = s[i]; + i++; + } + buf[i] = '\0'; + + print_str ("pix_fmt", buf); + } +} + +static void print_color_range(AVTextFormatContext *tfc, enum AVColorRange color_range) { const char *val = av_color_range_name(color_range); if (!val || color_range == AVCOL_RANGE_UNSPECIFIED) { @@ -2670,7 +1160,7 @@ static void print_color_range(WriterContext *w, enum AVColorRange color_range) } } -static void print_color_space(WriterContext *w, enum AVColorSpace color_space) +static void print_color_space(AVTextFormatContext *tfc, enum AVColorSpace color_space) { const char *val = av_color_space_name(color_space); if (!val || color_space == AVCOL_SPC_UNSPECIFIED) { @@ -2680,7 +1170,7 @@ static void print_color_space(WriterContext *w, enum AVColorSpace color_space) } } -static void print_primaries(WriterContext *w, enum AVColorPrimaries color_primaries) +static void print_primaries(AVTextFormatContext *tfc, enum AVColorPrimaries color_primaries) { const char *val = av_color_primaries_name(color_primaries); if (!val || color_primaries == AVCOL_PRI_UNSPECIFIED) { @@ -2690,7 +1180,7 @@ static void print_primaries(WriterContext *w, enum AVColorPrimaries color_primar } } -static void print_color_trc(WriterContext *w, enum AVColorTransferCharacteristic color_trc) +static void print_color_trc(AVTextFormatContext *tfc, enum AVColorTransferCharacteristic color_trc) { const char *val = av_color_transfer_name(color_trc); if (!val || color_trc == AVCOL_TRC_UNSPECIFIED) { @@ -2700,7 +1190,7 @@ static void print_color_trc(WriterContext *w, enum AVColorTransferCharacteristic } } -static void print_chroma_location(WriterContext *w, enum AVChromaLocation chroma_location) +static void print_chroma_location(AVTextFormatContext *tfc, enum AVChromaLocation chroma_location) { const char *val = av_chroma_location_name(chroma_location); if (!val || chroma_location == AVCHROMA_LOC_UNSPECIFIED) { @@ -2710,12 +1200,22 @@ static void print_chroma_location(WriterContext *w, enum AVChromaLocation chroma } } +static void print_alpha_mode(AVTextFormatContext *tfc, enum AVAlphaMode alpha_mode) +{ + const char *val = av_alpha_mode_name(alpha_mode); + if (!val || alpha_mode == AVALPHA_MODE_UNSPECIFIED) { + print_str_opt("alpha_mode", "unspecified"); + } else { + print_str("alpha_mode", val); + } +} + static void clear_log(int need_lock) { int i; if (need_lock) - pthread_mutex_lock(&log_mutex); + ff_mutex_lock(&log_mutex); for (i=0; istreams[pkt->stream_index].st; AVBPrint pbuf; const char *s; av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, SECTION_ID_PACKET); + avtext_print_section_header(tfc, NULL, SECTION_ID_PACKET); s = av_get_media_type_string(st->codecpar->codec_type); if (s) print_str ("codec_type", s); @@ -2789,8 +1288,8 @@ static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int p pkt->flags & AV_PKT_FLAG_DISCARD ? 'D' : '_', pkt->flags & AV_PKT_FLAG_CORRUPT ? 'C' : '_'); if (do_show_data) - writer_print_data(w, "data", pkt->data, pkt->size); - writer_print_data_hash(w, "data_hash", pkt->data, pkt->size); + avtext_print_data(tfc, "data", pkt->data, pkt->size); + avtext_print_data_hash(tfc, "data_hash", pkt->data, pkt->size); if (pkt->side_data_elems) { size_t size; @@ -2800,33 +1299,33 @@ static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int p if (side_metadata && size && do_show_packet_tags) { AVDictionary *dict = NULL; if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0) - show_tags(w, dict, SECTION_ID_PACKET_TAGS); + show_tags(tfc, dict, SECTION_ID_PACKET_TAGS); av_dict_free(&dict); } - writer_print_section_header(w, NULL, SECTION_ID_PACKET_SIDE_DATA_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_PACKET_SIDE_DATA_LIST); for (int i = 0; i < pkt->side_data_elems; i++) { - print_pkt_side_data(w, st->codecpar, &pkt->side_data[i], + print_pkt_side_data(tfc, st->codecpar, &pkt->side_data[i], SECTION_ID_PACKET_SIDE_DATA); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); av_bprint_finalize(&pbuf, NULL); fflush(stdout); } -static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream, +static void show_subtitle(AVTextFormatContext *tfc, AVSubtitle *sub, AVStream *stream, AVFormatContext *fmt_ctx) { AVBPrint pbuf; av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, SECTION_ID_SUBTITLE); + avtext_print_section_header(tfc, NULL, SECTION_ID_SUBTITLE); print_str ("media_type", "subtitle"); print_ts ("pts", sub->pts); @@ -2836,31 +1335,27 @@ static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream, print_int ("end_display_time", sub->end_display_time); print_int ("num_rects", sub->num_rects); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); av_bprint_finalize(&pbuf, NULL); fflush(stdout); } -static void print_frame_side_data(WriterContext *w, +static void print_frame_side_data(AVTextFormatContext *tfc, const AVFrame *frame, const AVStream *stream) { - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_LIST); for (int i = 0; i < frame->nb_side_data; i++) { const AVFrameSideData *sd = frame->side_data[i]; const char *name; - writer_print_section_header(w, sd, SECTION_ID_FRAME_SIDE_DATA); + avtext_print_section_header(tfc, sd, SECTION_ID_FRAME_SIDE_DATA); name = av_frame_side_data_name(sd->type); print_str("side_data_type", name ? name : "unknown"); if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) { - double rotation = av_display_rotation_get((int32_t *)sd->data); - if (isnan(rotation)) - rotation = 0; - writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1); - print_int("rotation", rotation); + print_displaymatrix(tfc, (const int32_t*)sd->data); } else if (sd->type == AV_FRAME_DATA_AFD && sd->size > 0) { print_int("active_format", *sd->data); } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) { @@ -2870,65 +1365,48 @@ static void print_frame_side_data(WriterContext *w, } else if (sd->type == AV_FRAME_DATA_S12M_TIMECODE && sd->size == 16) { uint32_t *tc = (uint32_t*)sd->data; int m = FFMIN(tc[0],3); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST); for (int j = 1; j <= m ; j++) { char tcbuf[AV_TIMECODE_STR_SIZE]; av_timecode_make_smpte_tc_string2(tcbuf, stream->avg_frame_rate, tc[j], 0, 0); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_TIMECODE); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_TIMECODE); print_str("value", tcbuf); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) { - AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data; - - if (metadata->has_primaries) { - print_q("red_x", metadata->display_primaries[0][0], '/'); - print_q("red_y", metadata->display_primaries[0][1], '/'); - print_q("green_x", metadata->display_primaries[1][0], '/'); - print_q("green_y", metadata->display_primaries[1][1], '/'); - print_q("blue_x", metadata->display_primaries[2][0], '/'); - print_q("blue_y", metadata->display_primaries[2][1], '/'); - - print_q("white_point_x", metadata->white_point[0], '/'); - print_q("white_point_y", metadata->white_point[1], '/'); - } - - if (metadata->has_luminance) { - print_q("min_luminance", metadata->min_luminance, '/'); - print_q("max_luminance", metadata->max_luminance, '/'); - } + print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data); } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) { AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data; - print_dynamic_hdr10_plus(w, metadata); + print_dynamic_hdr10_plus(tfc, metadata); } else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) { - AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data; - print_int("max_content", metadata->MaxCLL); - print_int("max_average", metadata->MaxFALL); + print_context_light_level(tfc, (AVContentLightMetadata *)sd->data); } else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) { const AVDictionaryEntry *tag = av_dict_get(sd->metadata, "name", NULL, AV_DICT_MATCH_CASE); if (tag) print_str(tag->key, tag->value); print_int("size", sd->size); } else if (sd->type == AV_FRAME_DATA_DOVI_METADATA) { - print_dovi_metadata(w, (const AVDOVIMetadata *)sd->data); + print_dovi_metadata(tfc, (const AVDOVIMetadata *)sd->data); } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_VIVID) { AVDynamicHDRVivid *metadata = (AVDynamicHDRVivid *)sd->data; - print_dynamic_hdr_vivid(w, metadata); + print_dynamic_hdr_vivid(tfc, metadata); } else if (sd->type == AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT) { - print_ambient_viewing_environment(w, (const AVAmbientViewingEnvironment *)sd->data); + print_ambient_viewing_environment(tfc, (const AVAmbientViewingEnvironment *)sd->data); } else if (sd->type == AV_FRAME_DATA_FILM_GRAIN_PARAMS) { AVFilmGrainParams *fgp = (AVFilmGrainParams *)sd->data; - print_film_grain_params(w, fgp); + print_film_grain_params(tfc, fgp); } else if (sd->type == AV_FRAME_DATA_VIEW_ID) { print_int("view_id", *(int*)sd->data); + } else if (sd->type == AV_FRAME_DATA_EXIF) { + print_int("size", sd->size); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } -static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, +static void show_frame(AVTextFormatContext *tfc, AVFrame *frame, AVStream *stream, AVFormatContext *fmt_ctx) { FrameData *fd = frame->opaque_ref ? (FrameData*)frame->opaque_ref->data : NULL; @@ -2938,7 +1416,7 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, SECTION_ID_FRAME); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME); s = av_get_media_type_string(stream->codecpar->codec_type); if (s) print_str ("media_type", s); @@ -2968,9 +1446,7 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, print_int("crop_bottom", frame->crop_bottom); print_int("crop_left", frame->crop_left); print_int("crop_right", frame->crop_right); - s = av_get_pix_fmt_name(frame->format); - if (s) print_str ("pix_fmt", s); - else print_str_opt("pix_fmt", "unknown"); + print_pixel_format(tfc, frame->format); sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame); if (sar.num) { print_q("sample_aspect_ratio", sar, ':'); @@ -2980,13 +1456,15 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, print_fmt("pict_type", "%c", av_get_picture_type_char(frame->pict_type)); print_int("interlaced_frame", !!(frame->flags & AV_FRAME_FLAG_INTERLACED)); print_int("top_field_first", !!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); + print_int("lossless", !!(frame->flags & AV_FRAME_FLAG_LOSSLESS)); print_int("repeat_pict", frame->repeat_pict); - print_color_range(w, frame->color_range); - print_color_space(w, frame->colorspace); - print_primaries(w, frame->color_primaries); - print_color_trc(w, frame->color_trc); - print_chroma_location(w, frame->chroma_location); + print_color_range(tfc, frame->color_range); + print_color_space(tfc, frame->colorspace); + print_primaries(tfc, frame->color_primaries); + print_color_trc(tfc, frame->color_trc); + print_chroma_location(tfc, frame->chroma_location); + print_alpha_mode(tfc, frame->alpha_mode); break; case AVMEDIA_TYPE_AUDIO: @@ -3003,19 +1481,19 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, break; } if (do_show_frame_tags) - show_tags(w, frame->metadata, SECTION_ID_FRAME_TAGS); + show_tags(tfc, frame->metadata, SECTION_ID_FRAME_TAGS); if (do_show_log) - show_log(w, SECTION_ID_FRAME_LOGS, SECTION_ID_FRAME_LOG, do_show_log); + show_log(tfc, SECTION_ID_FRAME_LOGS, SECTION_ID_FRAME_LOG, do_show_log); if (frame->nb_side_data) - print_frame_side_data(w, frame, stream); + print_frame_side_data(tfc, frame, stream); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); av_bprint_finalize(&pbuf, NULL); fflush(stdout); } -static av_always_inline int process_frame(WriterContext *w, +static av_always_inline int process_frame(AVTextFormatContext *tfc, InputFile *ifile, AVFrame *frame, const AVPacket *pkt, int *packet_new) @@ -3069,9 +1547,19 @@ static av_always_inline int process_frame(WriterContext *w, nb_streams_frames[pkt->stream_index]++; if (do_show_frames) if (is_sub) - show_subtitle(w, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx); + show_subtitle(tfc, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx); else - show_frame(w, frame, ifile->streams[pkt->stream_index].st, fmt_ctx); + show_frame(tfc, frame, ifile->streams[pkt->stream_index].st, fmt_ctx); + + if (!is_sub && do_analyze_frames) { + for (int i = 0; i < frame->nb_side_data; i++) { + if (frame->side_data[i]->type == AV_FRAME_DATA_A53_CC) + streams_with_closed_captions[pkt->stream_index] = 1; + else if (frame->side_data[i]->type == AV_FRAME_DATA_FILM_GRAIN_PARAMS) + streams_with_film_grain[pkt->stream_index] = 1; + } + } + if (is_sub) avsubtitle_free(&sub); } @@ -3102,7 +1590,7 @@ static void log_read_interval(const ReadInterval *interval, void *log_ctx, int l av_log(log_ctx, log_level, "\n"); } -static int read_interval_packets(WriterContext *w, InputFile *ifile, +static int read_interval_packets(AVTextFormatContext *tfc, InputFile *ifile, const ReadInterval *interval, int64_t *cur_ts) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; @@ -3154,6 +1642,8 @@ static int read_interval_packets(WriterContext *w, InputFile *ifile, REALLOCZ_ARRAY_STREAM(nb_streams_frames, nb_streams, fmt_ctx->nb_streams); REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams); REALLOCZ_ARRAY_STREAM(selected_streams, nb_streams, fmt_ctx->nb_streams); + REALLOCZ_ARRAY_STREAM(streams_with_closed_captions, nb_streams, fmt_ctx->nb_streams); + REALLOCZ_ARRAY_STREAM(streams_with_film_grain, nb_streams, fmt_ctx->nb_streams); nb_streams = fmt_ctx->nb_streams; } if (selected_streams[pkt->stream_index]) { @@ -3183,7 +1673,7 @@ static int read_interval_packets(WriterContext *w, InputFile *ifile, frame_count++; if (do_read_packets) { if (do_show_packets) - show_packet(w, ifile, pkt, i++); + show_packet(tfc, ifile, pkt, i++); nb_streams_packets[pkt->stream_index]++; } if (do_read_frames) { @@ -3199,7 +1689,7 @@ static int read_interval_packets(WriterContext *w, InputFile *ifile, fd->pkt_pos = pkt->pos; fd->pkt_size = pkt->size; - while (process_frame(w, ifile, frame, pkt, &packet_new) > 0); + while (process_frame(tfc, ifile, frame, pkt, &packet_new) > 0); } } av_packet_unref(pkt); @@ -3209,7 +1699,7 @@ static int read_interval_packets(WriterContext *w, InputFile *ifile, for (i = 0; i < ifile->nb_streams; i++) { pkt->stream_index = i; if (do_read_frames) { - while (process_frame(w, ifile, frame, pkt, &(int){1}) > 0); + while (process_frame(tfc, ifile, frame, pkt, &(int){1}) > 0); if (ifile->streams[i].dec_ctx) avcodec_flush_buffers(ifile->streams[i].dec_ctx); } @@ -3225,7 +1715,7 @@ end: return ret; } -static int read_packets(WriterContext *w, InputFile *ifile) +static int read_packets(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; @@ -3233,10 +1723,10 @@ static int read_packets(WriterContext *w, InputFile *ifile) if (read_intervals_nb == 0) { ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 }; - ret = read_interval_packets(w, ifile, &interval, &cur_ts); + ret = read_interval_packets(tfc, ifile, &interval, &cur_ts); } else { for (i = 0; i < read_intervals_nb; i++) { - ret = read_interval_packets(w, ifile, &read_intervals[i], &cur_ts); + ret = read_interval_packets(tfc, ifile, &read_intervals[i], &cur_ts); if (ret < 0) break; } @@ -3245,22 +1735,22 @@ static int read_packets(WriterContext *w, InputFile *ifile) return ret; } -static void print_dispositions(WriterContext *w, uint32_t disposition, SectionID section_id) +static void print_dispositions(AVTextFormatContext *tfc, uint32_t disposition, SectionID section_id) { - writer_print_section_header(w, NULL, section_id); + avtext_print_section_header(tfc, NULL, section_id); for (int i = 0; i < sizeof(disposition) * CHAR_BIT; i++) { const char *disposition_str = av_disposition_to_string(1U << i); if (disposition_str) print_int(disposition_str, !!(disposition & (1U << i))); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } #define IN_PROGRAM 1 #define IN_STREAM_GROUP 2 -static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int container) +static int show_stream(AVTextFormatContext *tfc, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int container) { AVStream *stream = ist->st; AVCodecParameters *par; @@ -3292,7 +1782,7 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, section_header[container]); + avtext_print_section_header(tfc, NULL, section_header[container]); print_int("index", stream->index); @@ -3330,6 +1820,10 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id print_str("codec_tag_string", av_fourcc2str(par->codec_tag)); print_fmt("codec_tag", "0x%04"PRIx32, par->codec_tag); + av_bprint_clear(&pbuf); + if (!av_mime_codec_str(par, stream->avg_frame_rate, &pbuf)) + print_str("mime_codec_string", pbuf.str); + switch (par->codec_type) { case AVMEDIA_TYPE_VIDEO: print_int("width", par->width); @@ -3337,8 +1831,11 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id if (dec_ctx) { print_int("coded_width", dec_ctx->coded_width); print_int("coded_height", dec_ctx->coded_height); - print_int("closed_captions", !!(dec_ctx->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS)); - print_int("film_grain", !!(dec_ctx->properties & FF_CODEC_PROPERTY_FILM_GRAIN)); + + if (do_analyze_frames) { + print_int("closed_captions", streams_with_closed_captions[stream->index]); + print_int("film_grain", streams_with_film_grain[stream->index]); + } } print_int("has_b_frames", par->video_delay); sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL); @@ -3353,16 +1850,14 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id print_str_opt("sample_aspect_ratio", "N/A"); print_str_opt("display_aspect_ratio", "N/A"); } - s = av_get_pix_fmt_name(par->format); - if (s) print_str ("pix_fmt", s); - else print_str_opt("pix_fmt", "unknown"); + print_pixel_format(tfc, par->format); print_int("level", par->level); - print_color_range(w, par->color_range); - print_color_space(w, par->color_space); - print_color_trc(w, par->color_trc); - print_primaries(w, par->color_primaries); - print_chroma_location(w, par->chroma_location); + print_color_range(tfc, par->color_range); + print_color_space(tfc, par->color_space); + print_color_trc(tfc, par->color_trc); + print_primaries(tfc, par->color_primaries); + print_chroma_location(tfc, par->chroma_location); if (par->field_order == AV_FIELD_PROGRESSIVE) print_str("field_order", "progressive"); @@ -3377,7 +1872,7 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id else print_str_opt("field_order", "unknown"); - if (dec_ctx) + if (dec_ctx && do_read_frames) print_int("refs", dec_ctx->refs); break; @@ -3414,9 +1909,9 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id if (show_private_data) { if (dec_ctx && dec_ctx->codec->priv_class) - print_private_data(w, dec_ctx->priv_data); + print_private_data(tfc, dec_ctx->priv_data); if (fmt_ctx->iformat->priv_class) - print_private_data(w, fmt_ctx->priv_data); + print_private_data(tfc, fmt_ctx->priv_data); } if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%x", stream->id); @@ -3443,113 +1938,113 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id if (nb_streams_packets[stream_idx]) print_fmt ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]); else print_str_opt("nb_read_packets", "N/A"); if (do_show_data) - writer_print_data(w, "extradata", par->extradata, + avtext_print_data(tfc, "extradata", par->extradata, par->extradata_size); if (par->extradata_size > 0) { print_int("extradata_size", par->extradata_size); - writer_print_data_hash(w, "extradata_hash", par->extradata, + avtext_print_data_hash(tfc, "extradata_hash", par->extradata, par->extradata_size); } /* Print disposition information */ if (do_show_stream_disposition) { av_assert0(container < FF_ARRAY_ELEMS(section_disposition)); - print_dispositions(w, stream->disposition, section_disposition[container]); + print_dispositions(tfc, stream->disposition, section_disposition[container]); } if (do_show_stream_tags) { av_assert0(container < FF_ARRAY_ELEMS(section_tags)); - ret = show_tags(w, stream->metadata, section_tags[container]); + ret = show_tags(tfc, stream->metadata, section_tags[container]); } if (stream->codecpar->nb_coded_side_data) { - writer_print_section_header(w, NULL, SECTION_ID_STREAM_SIDE_DATA_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_SIDE_DATA_LIST); for (int i = 0; i < stream->codecpar->nb_coded_side_data; i++) { - print_pkt_side_data(w, stream->codecpar, &stream->codecpar->coded_side_data[i], + print_pkt_side_data(tfc, stream->codecpar, &stream->codecpar->coded_side_data[i], SECTION_ID_STREAM_SIDE_DATA); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); av_bprint_finalize(&pbuf, NULL); fflush(stdout); return ret; } -static int show_streams(WriterContext *w, InputFile *ifile) +static int show_streams(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_STREAMS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAMS); for (i = 0; i < ifile->nb_streams; i++) if (selected_streams[i]) { - ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0); + ret = show_stream(tfc, fmt_ctx, i, &ifile->streams[i], 0); if (ret < 0) break; } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static int show_program(WriterContext *w, InputFile *ifile, AVProgram *program) +static int show_program(AVTextFormatContext *tfc, InputFile *ifile, AVProgram *program) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_PROGRAM); + avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAM); print_int("program_id", program->id); print_int("program_num", program->program_num); print_int("nb_streams", program->nb_stream_indexes); print_int("pmt_pid", program->pmt_pid); print_int("pcr_pid", program->pcr_pid); if (do_show_program_tags) - ret = show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS); + ret = show_tags(tfc, program->metadata, SECTION_ID_PROGRAM_TAGS); if (ret < 0) goto end; - writer_print_section_header(w, NULL, SECTION_ID_PROGRAM_STREAMS); + avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAM_STREAMS); for (i = 0; i < program->nb_stream_indexes; i++) { if (selected_streams[program->stream_index[i]]) { - ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], IN_PROGRAM); + ret = show_stream(tfc, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], IN_PROGRAM); if (ret < 0) break; } } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); end: - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static int show_programs(WriterContext *w, InputFile *ifile) +static int show_programs(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_PROGRAMS); + avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAMS); for (i = 0; i < fmt_ctx->nb_programs; i++) { AVProgram *program = fmt_ctx->programs[i]; if (!program) continue; - ret = show_program(w, ifile, program); + ret = show_program(tfc, ifile, program); if (ret < 0) break; } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static void print_tile_grid_params(WriterContext *w, const AVStreamGroup *stg, +static void print_tile_grid_params(AVTextFormatContext *tfc, const AVStreamGroup *stg, const AVStreamGroupTileGrid *tile_grid) { - writer_print_section_header(w, stg, SECTION_ID_STREAM_GROUP_COMPONENT); + avtext_print_section_header(tfc, stg, SECTION_ID_STREAM_GROUP_COMPONENT); print_int("nb_tiles", tile_grid->nb_tiles); print_int("coded_width", tile_grid->coded_width); print_int("coded_height", tile_grid->coded_height); @@ -3557,19 +2052,19 @@ static void print_tile_grid_params(WriterContext *w, const AVStreamGroup *stg, print_int("vertical_offset", tile_grid->vertical_offset); print_int("width", tile_grid->width); print_int("height", tile_grid->height); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); for (int i = 0; i < tile_grid->nb_tiles; i++) { - writer_print_section_header(w, "tile_offset", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); + avtext_print_section_header(tfc, "tile_offset", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); print_int("stream_index", tile_grid->offsets[i].idx); print_int("tile_horizontal_offset", tile_grid->offsets[i].horizontal); print_int("tile_vertical_offset", tile_grid->offsets[i].vertical); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); + avtext_print_section_footer(tfc); } -static void print_iamf_param_definition(WriterContext *w, const char *name, +static void print_iamf_param_definition(AVTextFormatContext *tfc, const char *name, const AVIAMFParamDefinition *param, SectionID section_id) { SectionID subsection_id, parameter_section_id; @@ -3577,7 +2072,7 @@ static void print_iamf_param_definition(WriterContext *w, const char *name, av_assert0(subsection_id != -1); parameter_section_id = sections[subsection_id].children_ids[0]; av_assert0(parameter_section_id != -1); - writer_print_section_header(w, "IAMF Param Definition", section_id); + avtext_print_section_header(tfc, "IAMF Param Definition", section_id); print_str("name", name); print_int("nb_subblocks", param->nb_subblocks); print_int("type", param->type); @@ -3586,109 +2081,119 @@ static void print_iamf_param_definition(WriterContext *w, const char *name, print_int("duration", param->duration); print_int("constant_subblock_duration", param->constant_subblock_duration); if (param->nb_subblocks > 0) - writer_print_section_header(w, NULL, subsection_id); + avtext_print_section_header(tfc, NULL, subsection_id); for (int i = 0; i < param->nb_subblocks; i++) { const void *subblock = av_iamf_param_definition_get_subblock(param, i); switch(param->type) { case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: { const AVIAMFMixGain *mix = subblock; - writer_print_section_header(w, "IAMF Mix Gain Parameters", parameter_section_id); + avtext_print_section_header(tfc, "IAMF Mix Gain Parameters", parameter_section_id); print_int("subblock_duration", mix->subblock_duration); print_int("animation_type", mix->animation_type); print_q("start_point_value", mix->start_point_value, '/'); print_q("end_point_value", mix->end_point_value, '/'); print_q("control_point_value", mix->control_point_value, '/'); print_q("control_point_relative_time", mix->control_point_relative_time, '/'); - writer_print_section_footer(w); // parameter_section_id + avtext_print_section_footer(tfc); // parameter_section_id break; } case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: { const AVIAMFDemixingInfo *demix = subblock; - writer_print_section_header(w, "IAMF Demixing Info", parameter_section_id); + avtext_print_section_header(tfc, "IAMF Demixing Info", parameter_section_id); print_int("subblock_duration", demix->subblock_duration); print_int("dmixp_mode", demix->dmixp_mode); - writer_print_section_footer(w); // parameter_section_id + avtext_print_section_footer(tfc); // parameter_section_id break; } case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: { const AVIAMFReconGain *recon = subblock; - writer_print_section_header(w, "IAMF Recon Gain", parameter_section_id); + avtext_print_section_header(tfc, "IAMF Recon Gain", parameter_section_id); print_int("subblock_duration", recon->subblock_duration); - writer_print_section_footer(w); // parameter_section_id + avtext_print_section_footer(tfc); // parameter_section_id break; } } } if (param->nb_subblocks > 0) - writer_print_section_footer(w); // subsection_id - writer_print_section_footer(w); // section_id + avtext_print_section_footer(tfc); // subsection_id + avtext_print_section_footer(tfc); // section_id } -static void print_iamf_audio_element_params(WriterContext *w, const AVStreamGroup *stg, +static void print_iamf_audio_element_params(AVTextFormatContext *tfc, const AVStreamGroup *stg, const AVIAMFAudioElement *audio_element) { - writer_print_section_header(w, stg, SECTION_ID_STREAM_GROUP_COMPONENT); + AVBPrint pbuf; + + av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); + + avtext_print_section_header(tfc, stg, SECTION_ID_STREAM_GROUP_COMPONENT); print_int("nb_layers", audio_element->nb_layers); print_int("audio_element_type", audio_element->audio_element_type); print_int("default_w", audio_element->default_w); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); for (int i = 0; i < audio_element->nb_layers; i++) { const AVIAMFLayer *layer = audio_element->layers[i]; char val_str[128]; - writer_print_section_header(w, "IAMF Audio Layer", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); + avtext_print_section_header(tfc, "IAMF Audio Layer", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); av_channel_layout_describe(&layer->ch_layout, val_str, sizeof(val_str)); print_str("channel_layout", val_str); if (audio_element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL) { print_int("output_gain_flags", layer->output_gain_flags); print_q("output_gain", layer->output_gain, '/'); - } else if (audio_element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE) + } else if (audio_element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE) { print_int("ambisonics_mode", layer->ambisonics_mode); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT + if (layer->ambisonics_mode == AV_IAMF_AMBISONICS_MODE_PROJECTION) + print_list_fmt("demixing_matrix", "%d/%d", layer->nb_demixing_matrix, 1, layer->demixing_matrix[idx].num, + layer->demixing_matrix[idx].den); + } + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT } if (audio_element->demixing_info) - print_iamf_param_definition(w, "demixing_info", audio_element->demixing_info, + print_iamf_param_definition(tfc, "demixing_info", audio_element->demixing_info, SECTION_ID_STREAM_GROUP_SUBCOMPONENT); if (audio_element->recon_gain_info) - print_iamf_param_definition(w, "recon_gain_info", audio_element->recon_gain_info, + print_iamf_param_definition(tfc, "recon_gain_info", audio_element->recon_gain_info, SECTION_ID_STREAM_GROUP_SUBCOMPONENT); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_COMPONENT + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_COMPONENT + + av_bprint_finalize(&pbuf, NULL); } -static void print_iamf_submix_params(WriterContext *w, const AVIAMFSubmix *submix) +static void print_iamf_submix_params(AVTextFormatContext *tfc, const AVIAMFSubmix *submix) { - writer_print_section_header(w, "IAMF Submix", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); + avtext_print_section_header(tfc, "IAMF Submix", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); print_int("nb_elements", submix->nb_elements); print_int("nb_layouts", submix->nb_layouts); print_q("default_mix_gain", submix->default_mix_gain, '/'); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_PIECES); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_PIECES); for (int i = 0; i < submix->nb_elements; i++) { const AVIAMFSubmixElement *element = submix->elements[i]; - writer_print_section_header(w, "IAMF Submix Element", SECTION_ID_STREAM_GROUP_PIECE); + avtext_print_section_header(tfc, "IAMF Submix Element", SECTION_ID_STREAM_GROUP_PIECE); print_int("stream_id", element->audio_element_id); print_q("default_mix_gain", element->default_mix_gain, '/'); print_int("headphones_rendering_mode", element->headphones_rendering_mode); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_SUBPIECES); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBPIECES); if (element->annotations) { const AVDictionaryEntry *annotation = NULL; - writer_print_section_header(w, "IAMF Annotations", SECTION_ID_STREAM_GROUP_SUBPIECE); + avtext_print_section_header(tfc, "IAMF Annotations", SECTION_ID_STREAM_GROUP_SUBPIECE); while (annotation = av_dict_iterate(element->annotations, annotation)) print_str(annotation->key, annotation->value); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBPIECE + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBPIECE } if (element->element_mix_config) - print_iamf_param_definition(w, "element_mix_config", element->element_mix_config, + print_iamf_param_definition(tfc, "element_mix_config", element->element_mix_config, SECTION_ID_STREAM_GROUP_SUBPIECE); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBPIECES - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_PIECE + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBPIECES + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_PIECE } if (submix->output_mix_config) - print_iamf_param_definition(w, "output_mix_config", submix->output_mix_config, + print_iamf_param_definition(tfc, "output_mix_config", submix->output_mix_config, SECTION_ID_STREAM_GROUP_PIECE); for (int i = 0; i < submix->nb_layouts; i++) { const AVIAMFSubmixLayout *layout = submix->layouts[i]; char val_str[128]; - writer_print_section_header(w, "IAMF Submix Layout", SECTION_ID_STREAM_GROUP_PIECE); + avtext_print_section_header(tfc, "IAMF Submix Layout", SECTION_ID_STREAM_GROUP_PIECE); av_channel_layout_describe(&layout->sound_system, val_str, sizeof(val_str)); print_str("sound_system", val_str); print_q("integrated_loudness", layout->integrated_loudness, '/'); @@ -3696,51 +2201,51 @@ static void print_iamf_submix_params(WriterContext *w, const AVIAMFSubmix *submi print_q("true_peak", layout->true_peak, '/'); print_q("dialogue_anchored_loudness", layout->dialogue_anchored_loudness, '/'); print_q("album_anchored_loudness", layout->album_anchored_loudness, '/'); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_PIECE + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_PIECE } - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_PIECES - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_PIECES + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT } -static void print_iamf_mix_presentation_params(WriterContext *w, const AVStreamGroup *stg, +static void print_iamf_mix_presentation_params(AVTextFormatContext *tfc, const AVStreamGroup *stg, const AVIAMFMixPresentation *mix_presentation) { - writer_print_section_header(w, stg, SECTION_ID_STREAM_GROUP_COMPONENT); + avtext_print_section_header(tfc, stg, SECTION_ID_STREAM_GROUP_COMPONENT); print_int("nb_submixes", mix_presentation->nb_submixes); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); if (mix_presentation->annotations) { const AVDictionaryEntry *annotation = NULL; - writer_print_section_header(w, "IAMF Annotations", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); + avtext_print_section_header(tfc, "IAMF Annotations", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); while (annotation = av_dict_iterate(mix_presentation->annotations, annotation)) print_str(annotation->key, annotation->value); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT } for (int i = 0; i < mix_presentation->nb_submixes; i++) - print_iamf_submix_params(w, mix_presentation->submixes[i]); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_COMPONENT + print_iamf_submix_params(tfc, mix_presentation->submixes[i]); + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_COMPONENT } -static void print_stream_group_params(WriterContext *w, AVStreamGroup *stg) +static void print_stream_group_params(AVTextFormatContext *tfc, AVStreamGroup *stg) { - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_COMPONENTS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_COMPONENTS); if (stg->type == AV_STREAM_GROUP_PARAMS_TILE_GRID) - print_tile_grid_params(w, stg, stg->params.tile_grid); + print_tile_grid_params(tfc, stg, stg->params.tile_grid); else if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT) - print_iamf_audio_element_params(w, stg, stg->params.iamf_audio_element); + print_iamf_audio_element_params(tfc, stg, stg->params.iamf_audio_element); else if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) - print_iamf_mix_presentation_params(w, stg, stg->params.iamf_mix_presentation); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_COMPONENTS + print_iamf_mix_presentation_params(tfc, stg, stg->params.iamf_mix_presentation); + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_COMPONENTS } -static int show_stream_group(WriterContext *w, InputFile *ifile, AVStreamGroup *stg) +static int show_stream_group(AVTextFormatContext *tfc, InputFile *ifile, AVStreamGroup *stg) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; AVBPrint pbuf; int i, ret = 0; av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP); print_int("index", stg->index); if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%"PRIx64, stg->id); else print_str_opt("id", "N/A"); @@ -3750,60 +2255,60 @@ static int show_stream_group(WriterContext *w, InputFile *ifile, AVStreamGroup * else print_str_opt("type", "unknown"); if (do_show_stream_group_components) - print_stream_group_params(w, stg); + print_stream_group_params(tfc, stg); /* Print disposition information */ if (do_show_stream_group_disposition) - print_dispositions(w, stg->disposition, SECTION_ID_STREAM_GROUP_DISPOSITION); + print_dispositions(tfc, stg->disposition, SECTION_ID_STREAM_GROUP_DISPOSITION); if (do_show_stream_group_tags) - ret = show_tags(w, stg->metadata, SECTION_ID_STREAM_GROUP_TAGS); + ret = show_tags(tfc, stg->metadata, SECTION_ID_STREAM_GROUP_TAGS); if (ret < 0) goto end; - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_STREAMS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_STREAMS); for (i = 0; i < stg->nb_streams; i++) { if (selected_streams[stg->streams[i]->index]) { - ret = show_stream(w, fmt_ctx, stg->streams[i]->index, &ifile->streams[stg->streams[i]->index], IN_STREAM_GROUP); + ret = show_stream(tfc, fmt_ctx, stg->streams[i]->index, &ifile->streams[stg->streams[i]->index], IN_STREAM_GROUP); if (ret < 0) break; } } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); end: av_bprint_finalize(&pbuf, NULL); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static int show_stream_groups(WriterContext *w, InputFile *ifile) +static int show_stream_groups(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUPS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUPS); for (i = 0; i < fmt_ctx->nb_stream_groups; i++) { AVStreamGroup *stg = fmt_ctx->stream_groups[i]; - ret = show_stream_group(w, ifile, stg); + ret = show_stream_group(tfc, ifile, stg); if (ret < 0) break; } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static int show_chapters(WriterContext *w, InputFile *ifile) +static int show_chapters(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_CHAPTERS); + avtext_print_section_header(tfc, NULL, SECTION_ID_CHAPTERS); for (i = 0; i < fmt_ctx->nb_chapters; i++) { AVChapter *chapter = fmt_ctx->chapters[i]; - writer_print_section_header(w, NULL, SECTION_ID_CHAPTER); + avtext_print_section_header(tfc, NULL, SECTION_ID_CHAPTER); print_int("id", chapter->id); print_q ("time_base", chapter->time_base, '/'); print_int("start", chapter->start); @@ -3811,22 +2316,21 @@ static int show_chapters(WriterContext *w, InputFile *ifile) print_int("end", chapter->end); print_time("end_time", chapter->end, &chapter->time_base); if (do_show_chapter_tags) - ret = show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS); - writer_print_section_footer(w); + ret = show_tags(tfc, chapter->metadata, SECTION_ID_CHAPTER_TAGS); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static int show_format(WriterContext *w, InputFile *ifile) +static int show_format(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; - char val_str[128]; int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1; int ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_FORMAT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FORMAT); print_str_validate("filename", fmt_ctx->url); print_int("nb_streams", fmt_ctx->nb_streams); print_int("nb_programs", fmt_ctx->nb_programs); @@ -3844,19 +2348,78 @@ static int show_format(WriterContext *w, InputFile *ifile) else print_str_opt("bit_rate", "N/A"); print_int("probe_score", fmt_ctx->probe_score); if (do_show_format_tags) - ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS); + ret = show_tags(tfc, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); fflush(stdout); return ret; } -static void show_error(WriterContext *w, int err) +static void show_error(AVTextFormatContext *tfc, int err) { - writer_print_section_header(w, NULL, SECTION_ID_ERROR); + avtext_print_section_header(tfc, NULL, SECTION_ID_ERROR); print_int("code", err); print_str("string", av_err2str(err)); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); +} + +static int get_decoder_by_name(const char *codec_name, const AVCodec **codec) +{ + if (codec_name == NULL) + return 0; + + *codec = avcodec_find_decoder_by_name(codec_name); + if (*codec == NULL) { + av_log(NULL, AV_LOG_ERROR, + "No codec could be found with name '%s'\n", codec_name); + return AVERROR(EINVAL); + } + return 0; +} + +static int set_decoders(AVFormatContext *fmt_ctx) +{ + int ret; + +#define GET_DECODER(type_) \ + ret = get_decoder_by_name(type_##_codec_name, &fmt_ctx->type_##_codec); \ + if (ret < 0) return ret; + + GET_DECODER(audio); + GET_DECODER(data); + GET_DECODER(subtitle); + GET_DECODER(video); + return 0; +} + +static const AVCodec *get_decoder_for_stream(AVFormatContext *fmt_ctx, AVStream *stream) +{ + const AVCodec *codec = NULL; + switch (stream->codecpar->codec_type) { + case AVMEDIA_TYPE_VIDEO: codec = fmt_ctx->video_codec; break; + case AVMEDIA_TYPE_AUDIO: codec = fmt_ctx->audio_codec; break; + case AVMEDIA_TYPE_SUBTITLE: codec = fmt_ctx->subtitle_codec; break; + case AVMEDIA_TYPE_DATA: codec = fmt_ctx->data_codec; break; + } + + if (codec != NULL) + return codec; + + if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) { + av_log(NULL, AV_LOG_WARNING, + "Failed to probe codec for input stream %d\n", stream->index); + return NULL; + } + + codec = avcodec_find_decoder(stream->codecpar->codec_id); + if (codec == NULL) { + av_log(NULL, AV_LOG_WARNING, + "Unsupported codec with id %d for input stream %d\n", + stream->codecpar->codec_id, stream->index); + return NULL; + } + + return codec; } static int open_input_file(InputFile *ifile, const char *filename, @@ -3871,6 +2434,9 @@ static int open_input_file(InputFile *ifile, const char *filename, if (!fmt_ctx) return AVERROR(ENOMEM); + err = set_decoders(fmt_ctx); + if (err < 0) + return err; if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) { av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE); scan_all_pmts_set = 1; @@ -3925,20 +2491,10 @@ static int open_input_file(InputFile *ifile, const char *filename, ist->st = stream; - if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) { - av_log(NULL, AV_LOG_WARNING, - "Failed to probe codec for input stream %d\n", - stream->index); + codec = get_decoder_for_stream(fmt_ctx, stream); + if (!codec) continue; - } - codec = avcodec_find_decoder(stream->codecpar->codec_id); - if (!codec) { - av_log(NULL, AV_LOG_WARNING, - "Unsupported codec with id %d for input stream %d\n", - stream->codecpar->codec_id, stream->index); - continue; - } { AVDictionary *opts; @@ -3956,7 +2512,7 @@ static int open_input_file(InputFile *ifile, const char *filename, exit(1); if (do_show_log) { - // For loging it is needed to disable at least frame threads as otherwise + // For logging it is needed to disable at least frame threads as otherwise // the log information would need to be reordered and matches up to contexts and frames // That is in fact possible but not trivial av_dict_set(&codec_opts, "threads", "1", 0); @@ -3998,14 +2554,15 @@ static void close_input_file(InputFile *ifile) avformat_close_input(&ifile->fmt_ctx); } -static int probe_file(WriterContext *wctx, const char *filename, +static int probe_file(AVTextFormatContext *tfc, const char *filename, const char *print_filename) { InputFile ifile = { 0 }; int ret, i; int section_id; - do_read_frames = do_show_frames || do_count_frames; + do_analyze_frames = do_analyze_frames && do_show_streams; + do_read_frames = do_show_frames || do_count_frames || do_analyze_frames; do_read_packets = do_show_packets || do_count_packets; ret = open_input_file(&ifile, filename, print_filename); @@ -4018,6 +2575,8 @@ static int probe_file(WriterContext *wctx, const char *filename, REALLOCZ_ARRAY_STREAM(nb_streams_frames,0,ifile.fmt_ctx->nb_streams); REALLOCZ_ARRAY_STREAM(nb_streams_packets,0,ifile.fmt_ctx->nb_streams); REALLOCZ_ARRAY_STREAM(selected_streams,0,ifile.fmt_ctx->nb_streams); + REALLOCZ_ARRAY_STREAM(streams_with_closed_captions,0,ifile.fmt_ctx->nb_streams); + REALLOCZ_ARRAY_STREAM(streams_with_film_grain,0,ifile.fmt_ctx->nb_streams); for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) { if (stream_specifier) { @@ -4037,40 +2596,40 @@ static int probe_file(WriterContext *wctx, const char *filename, if (do_read_frames || do_read_packets) { if (do_show_frames && do_show_packets && - wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER) + tfc->formatter->flags & AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT) section_id = SECTION_ID_PACKETS_AND_FRAMES; else if (do_show_packets && !do_show_frames) section_id = SECTION_ID_PACKETS; else // (!do_show_packets && do_show_frames) section_id = SECTION_ID_FRAMES; if (do_show_frames || do_show_packets) - writer_print_section_header(wctx, NULL, section_id); - ret = read_packets(wctx, &ifile); + avtext_print_section_header(tfc, NULL, section_id); + ret = read_packets(tfc, &ifile); if (do_show_frames || do_show_packets) - writer_print_section_footer(wctx); + avtext_print_section_footer(tfc); CHECK_END; } if (do_show_programs) { - ret = show_programs(wctx, &ifile); + ret = show_programs(tfc, &ifile); CHECK_END; } if (do_show_stream_groups) { - ret = show_stream_groups(wctx, &ifile); + ret = show_stream_groups(tfc, &ifile); CHECK_END; } if (do_show_streams) { - ret = show_streams(wctx, &ifile); + ret = show_streams(tfc, &ifile); CHECK_END; } if (do_show_chapters) { - ret = show_chapters(wctx, &ifile); + ret = show_chapters(tfc, &ifile); CHECK_END; } if (do_show_format) { - ret = show_format(wctx, &ifile); + ret = show_format(tfc, &ifile); CHECK_END; } @@ -4080,6 +2639,12 @@ end: av_freep(&nb_streams_frames); av_freep(&nb_streams_packets); av_freep(&selected_streams); + av_freep(&streams_with_closed_captions); + av_freep(&streams_with_film_grain); + av_freep(&audio_codec_name); + av_freep(&data_codec_name); + av_freep(&subtitle_codec_name); + av_freep(&video_codec_name); return ret; } @@ -4091,18 +2656,18 @@ static void show_usage(void) av_log(NULL, AV_LOG_INFO, "\n"); } -static void ffprobe_show_program_version(WriterContext *w) +static void ffprobe_show_program_version(AVTextFormatContext *tfc) { AVBPrint pbuf; av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, SECTION_ID_PROGRAM_VERSION); + avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAM_VERSION); print_str("version", FFMPEG_VERSION); print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers", program_birth_year, CONFIG_THIS_YEAR); print_str("compiler_ident", CC_IDENT); print_str("configuration", FFMPEG_CONFIGURATION); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); av_bprint_finalize(&pbuf, NULL); } @@ -4111,20 +2676,20 @@ static void ffprobe_show_program_version(WriterContext *w) do { \ if (CONFIG_##LIBNAME) { \ unsigned int version = libname##_version(); \ - writer_print_section_header(w, NULL, SECTION_ID_LIBRARY_VERSION); \ + avtext_print_section_header(tfc, NULL, SECTION_ID_LIBRARY_VERSION); \ print_str("name", "lib" #libname); \ print_int("major", LIB##LIBNAME##_VERSION_MAJOR); \ print_int("minor", LIB##LIBNAME##_VERSION_MINOR); \ print_int("micro", LIB##LIBNAME##_VERSION_MICRO); \ print_int("version", version); \ print_str("ident", LIB##LIBNAME##_IDENT); \ - writer_print_section_footer(w); \ + avtext_print_section_footer(tfc); \ } \ } while (0) -static void ffprobe_show_library_versions(WriterContext *w) +static void ffprobe_show_library_versions(AVTextFormatContext *tfc) { - writer_print_section_header(w, NULL, SECTION_ID_LIBRARY_VERSIONS); + avtext_print_section_header(tfc, NULL, SECTION_ID_LIBRARY_VERSIONS); SHOW_LIB_VERSION(avutil, AVUTIL); SHOW_LIB_VERSION(avcodec, AVCODEC); SHOW_LIB_VERSION(avformat, AVFORMAT); @@ -4132,8 +2697,7 @@ static void ffprobe_show_library_versions(WriterContext *w) SHOW_LIB_VERSION(avfilter, AVFILTER); SHOW_LIB_VERSION(swscale, SWSCALE); SHOW_LIB_VERSION(swresample, SWRESAMPLE); - SHOW_LIB_VERSION(postproc, POSTPROC); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } #define PRINT_PIX_FMT_FLAG(flagname, name) \ @@ -4141,14 +2705,14 @@ static void ffprobe_show_library_versions(WriterContext *w) print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \ } while (0) -static void ffprobe_show_pixel_formats(WriterContext *w) +static void ffprobe_show_pixel_formats(AVTextFormatContext *tfc) { const AVPixFmtDescriptor *pixdesc = NULL; int i, n; - writer_print_section_header(w, NULL, SECTION_ID_PIXEL_FORMATS); + avtext_print_section_header(tfc, NULL, SECTION_ID_PIXEL_FORMATS); while (pixdesc = av_pix_fmt_desc_next(pixdesc)) { - writer_print_section_header(w, NULL, SECTION_ID_PIXEL_FORMAT); + avtext_print_section_header(tfc, NULL, SECTION_ID_PIXEL_FORMAT); print_str("name", pixdesc->name); print_int("nb_components", pixdesc->nb_components); if ((pixdesc->nb_components >= 3) && !(pixdesc->flags & AV_PIX_FMT_FLAG_RGB)) { @@ -4162,7 +2726,7 @@ static void ffprobe_show_pixel_formats(WriterContext *w) if (n) print_int ("bits_per_pixel", n); else print_str_opt("bits_per_pixel", "N/A"); if (do_show_pixel_format_flags) { - writer_print_section_header(w, NULL, SECTION_ID_PIXEL_FORMAT_FLAGS); + avtext_print_section_header(tfc, NULL, SECTION_ID_PIXEL_FORMAT_FLAGS); PRINT_PIX_FMT_FLAG(BE, "big_endian"); PRINT_PIX_FMT_FLAG(PAL, "palette"); PRINT_PIX_FMT_FLAG(BITSTREAM, "bitstream"); @@ -4170,21 +2734,21 @@ static void ffprobe_show_pixel_formats(WriterContext *w) PRINT_PIX_FMT_FLAG(PLANAR, "planar"); PRINT_PIX_FMT_FLAG(RGB, "rgb"); PRINT_PIX_FMT_FLAG(ALPHA, "alpha"); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } if (do_show_pixel_format_components && (pixdesc->nb_components > 0)) { - writer_print_section_header(w, NULL, SECTION_ID_PIXEL_FORMAT_COMPONENTS); + avtext_print_section_header(tfc, NULL, SECTION_ID_PIXEL_FORMAT_COMPONENTS); for (i = 0; i < pixdesc->nb_components; i++) { - writer_print_section_header(w, NULL, SECTION_ID_PIXEL_FORMAT_COMPONENT); + avtext_print_section_header(tfc, NULL, SECTION_ID_PIXEL_FORMAT_COMPONENT); print_int("index", i + 1); print_int("bit_depth", pixdesc->comp[i].depth); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } static int opt_show_optional_fields(void *optctx, const char *opt, const char *arg) @@ -4217,14 +2781,15 @@ static int opt_format(void *optctx, const char *opt, const char *arg) static inline void mark_section_show_entries(SectionID section_id, int show_all_entries, AVDictionary *entries) { - struct section *section = §ions[section_id]; + EntrySelection *selection = &selected_entries[section_id]; - section->show_all_entries = show_all_entries; + selection->show_all_entries = show_all_entries; if (show_all_entries) { - for (const SectionID *id = section->children_ids; *id != -1; id++) + const AVTextFormatSection *section = §ions[section_id]; + for (const int *id = section->children_ids; *id != -1; id++) mark_section_show_entries(*id, show_all_entries, entries); } else { - av_dict_copy(§ion->entries_to_show, entries, 0); + av_dict_copy(&selection->entries_to_show, entries, 0); } } @@ -4234,7 +2799,7 @@ static int match_section(const char *section_name, int i, ret = 0; for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) { - const struct section *section = §ions[i]; + const struct AVTextFormatSection *section = §ions[i]; if (!strcmp(section_name, section->name) || (section->unique_name && !strcmp(section_name, section->unique_name))) { av_log(NULL, AV_LOG_DEBUG, @@ -4506,13 +3071,13 @@ static int opt_pretty(void *optctx, const char *opt, const char *arg) static void print_section(SectionID id, int level) { - const SectionID *pid; - const struct section *section = §ions[id]; + const int *pid; + const struct AVTextFormatSection *section = §ions[id]; printf("%c%c%c%c", - section->flags & SECTION_FLAG_IS_WRAPPER ? 'W' : '.', - section->flags & SECTION_FLAG_IS_ARRAY ? 'A' : '.', - section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS ? 'V' : '.', - section->flags & SECTION_FLAG_HAS_TYPE ? 'T' : '.'); + section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER ? 'W' : '.', + section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY ? 'A' : '.', + section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS ? 'V' : '.', + section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE ? 'T' : '.'); printf("%*c %s", level * 4, ' ', section->name); if (section->unique_name) printf("/%s", section->unique_name); @@ -4535,6 +3100,36 @@ static int opt_sections(void *optctx, const char *opt, const char *arg) return 0; } +static int opt_codec(void *optctx, const char *opt, const char *arg) +{ + const char *spec = strchr(opt, ':'); + const char **name; + if (!spec) { + av_log(NULL, AV_LOG_ERROR, + "No media specifier was specified for '%s' in option '%s'. Use -%s: " + "where can be one of: 'a' (audio), 'v' (video), 's' (subtitle), 'd' (data)\n", + arg, opt, opt); + return AVERROR(EINVAL); + } + spec++; + + switch (spec[0]) { + case 'a' : name = &audio_codec_name; break; + case 'd' : name = &data_codec_name; break; + case 's' : name = &subtitle_codec_name; break; + case 'v' : name = &video_codec_name; break; + default: + av_log(NULL, AV_LOG_ERROR, + "Invalid media specifier '%s' in option '%s'. " + "Must be one of: 'a' (audio), 'v' (video), 's' (subtitle), 'd' (data)\n", spec, opt); + return AVERROR(EINVAL); + } + + av_freep(name); + *name = av_strdup(arg); + return *name ? 0 : AVERROR(ENOMEM); +} + static int opt_show_versions(void *optctx, const char *opt, const char *arg) { mark_section_show_entries(SECTION_ID_PROGRAM_VERSION, 1, NULL); @@ -4578,6 +3173,7 @@ static const OptionDef real_options[] = { { "of", OPT_TYPE_STRING, 0, { &output_format }, "alias for -output_format", "format" }, { "select_streams", OPT_TYPE_STRING, 0, { &stream_specifier }, "select the specified streams", "stream_specifier" }, { "sections", OPT_TYPE_FUNC, OPT_EXIT, {.func_arg = opt_sections}, "print sections structure and section information, and exit" }, + { "data_dump_format", OPT_TYPE_STRING, 0, { &data_dump_format }, "set data dump format (available formats are: xxd, base64)" }, { "show_data", OPT_TYPE_BOOL, 0, { &do_show_data }, "show packets data" }, { "show_data_hash", OPT_TYPE_STRING, 0, { &show_data_hash }, "show packets data hash" }, { "show_error", OPT_TYPE_FUNC, 0, { .func_arg = &opt_show_error }, "show probing error" }, @@ -4602,6 +3198,7 @@ static const OptionDef real_options[] = { { "show_optional_fields", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = &opt_show_optional_fields }, "show optional fields" }, { "show_private_data", OPT_TYPE_BOOL, 0, { &show_private_data }, "show private data" }, { "private", OPT_TYPE_BOOL, 0, { &show_private_data }, "same as show_private_data" }, + { "analyze_frames", OPT_TYPE_BOOL, 0, { &do_analyze_frames }, "analyze frames to provide additional stream-level information" }, { "bitexact", OPT_TYPE_BOOL, 0, {&do_bitexact}, "force bitexact output" }, { "read_intervals", OPT_TYPE_FUNC, OPT_FUNC_ARG, {.func_arg = opt_read_intervals}, "set read intervals", "read_intervals" }, { "i", OPT_TYPE_FUNC, OPT_FUNC_ARG, {.func_arg = opt_input_file_i}, "read specified file", "input_file"}, @@ -4609,15 +3206,20 @@ static const OptionDef real_options[] = { { "print_filename", OPT_TYPE_FUNC, OPT_FUNC_ARG, {.func_arg = opt_print_filename}, "override the printed input filename", "print_file"}, { "find_stream_info", OPT_TYPE_BOOL, OPT_INPUT | OPT_EXPERT, { &find_stream_info }, "read and decode the streams to fill missing information with heuristics" }, + { "c", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_codec}, "force decoder", "decoder_name" }, + { "codec", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_codec}, "alias for -c (force decoder)", "decoder_name" }, { NULL, }, }; static inline int check_section_show_entries(int section_id) { - struct section *section = §ions[section_id]; - if (sections[section_id].show_all_entries || sections[section_id].entries_to_show) + const EntrySelection *selection = &selected_entries[section_id]; + + if (selection->show_all_entries || selection->entries_to_show) return 1; - for (const SectionID *id = section->children_ids; *id != -1; id++) + + const AVTextFormatSection *section = §ions[section_id]; + for (const int *id = section->children_ids; *id != -1; id++) if (check_section_show_entries(*id)) return 1; return 0; @@ -4630,20 +3232,18 @@ static inline int check_section_show_entries(int section_id) int main(int argc, char **argv) { - const Writer *w; - WriterContext *wctx; + const AVTextFormatter *f; + AVTextFormatContext *tctx; + AVTextWriterContext *wctx; char *buf; - char *w_name = NULL, *w_args = NULL; - int ret, input_ret, i; + char *f_name = NULL, *f_args = NULL; + int ret, input_ret; + AVTextFormatDataDump data_dump_format_id = AV_TEXTFORMAT_DATADUMP_XXD; init_dynload(); -#if HAVE_THREADS - ret = pthread_mutex_init(&log_mutex, NULL); - if (ret != 0) { - goto end; - } -#endif + setvbuf(stderr, NULL, _IONBF, 0); /* win32 runtime needs this */ + av_log_set_flags(AV_LOG_SKIP_REPEATED); options = real_options; @@ -4701,58 +3301,70 @@ int main(int argc, char **argv) goto end; } - writer_register_all(); - if (!output_format) output_format = av_strdup("default"); if (!output_format) { ret = AVERROR(ENOMEM); goto end; } - w_name = av_strtok(output_format, "=", &buf); - if (!w_name) { + f_name = av_strtok(output_format, "=", &buf); + if (!f_name) { av_log(NULL, AV_LOG_ERROR, "No name specified for the output format\n"); ret = AVERROR(EINVAL); goto end; } - w_args = buf; + f_args = buf; - if (show_data_hash) { - if ((ret = av_hash_alloc(&hash, show_data_hash)) < 0) { - if (ret == AVERROR(EINVAL)) { - const char *n; - av_log(NULL, AV_LOG_ERROR, - "Unknown hash algorithm '%s'\nKnown algorithms:", - show_data_hash); - for (i = 0; (n = av_hash_names(i)); i++) - av_log(NULL, AV_LOG_ERROR, " %s", n); - av_log(NULL, AV_LOG_ERROR, "\n"); - } - goto end; - } - } - - w = writer_get_by_name(w_name); - if (!w) { - av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", w_name); + f = avtext_get_formatter_by_name(f_name); + if (!f) { + av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", f_name); ret = AVERROR(EINVAL); goto end; } - if ((ret = writer_open(&wctx, w, w_args, - sections, FF_ARRAY_ELEMS(sections), output_filename)) >= 0) { - if (w == &xml_writer) - wctx->string_validation_utf8_flags |= AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES; + if (data_dump_format) { + if (!strcmp(data_dump_format, "xxd")) { + data_dump_format_id = AV_TEXTFORMAT_DATADUMP_XXD; + } else if (!strcmp(data_dump_format, "base64")) { + data_dump_format_id = AV_TEXTFORMAT_DATADUMP_BASE64; + } else { + av_log(NULL, AV_LOG_ERROR, "Unknown data dump format with name '%s'\n", data_dump_format); + ret = AVERROR(EINVAL); + goto end; + } + } - writer_print_section_header(wctx, NULL, SECTION_ID_ROOT); + if (output_filename) { + ret = avtextwriter_create_file(&wctx, output_filename); + } else + ret = avtextwriter_create_stdout(&wctx); + + if (ret < 0) + goto end; + + AVTextFormatOptions tf_options = { + .is_key_selected = is_key_selected_callback, + .show_optional_fields = show_optional_fields, + .show_value_unit = show_value_unit, + .use_value_prefix = use_value_prefix, + .use_byte_value_binary_prefix = use_byte_value_binary_prefix, + .use_value_sexagesimal_format = use_value_sexagesimal_format, + .data_dump_format = data_dump_format_id, + }; + + if ((ret = avtext_context_open(&tctx, f, wctx, f_args, sections, FF_ARRAY_ELEMS(sections), tf_options, show_data_hash)) >= 0) { + if (f == &avtextformatter_xml) + tctx->string_validation_utf8_flags |= AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES; + + avtext_print_section_header(tctx, NULL, SECTION_ID_ROOT); if (do_show_program_version) - ffprobe_show_program_version(wctx); + ffprobe_show_program_version(tctx); if (do_show_library_versions) - ffprobe_show_library_versions(wctx); + ffprobe_show_library_versions(tctx); if (do_show_pixel_formats) - ffprobe_show_pixel_formats(wctx); + ffprobe_show_pixel_formats(tctx); if (!input_filename && ((do_show_format || do_show_programs || do_show_stream_groups || do_show_streams || do_show_chapters || do_show_packets || do_show_error) || @@ -4762,17 +3374,22 @@ int main(int argc, char **argv) av_log(NULL, AV_LOG_ERROR, "Use -h to get full help or, even better, run 'man %s'.\n", program_name); ret = AVERROR(EINVAL); } else if (input_filename) { - ret = probe_file(wctx, input_filename, print_input_filename); + ret = probe_file(tctx, input_filename, print_input_filename); if (ret < 0 && do_show_error) - show_error(wctx, ret); + show_error(tctx, ret); } input_ret = ret; - writer_print_section_footer(wctx); - ret = writer_close(&wctx); + avtext_print_section_footer(tctx); + + ret = avtextwriter_context_close(&wctx); if (ret < 0) - av_log(NULL, AV_LOG_ERROR, "Writing output failed: %s\n", av_err2str(ret)); + av_log(NULL, AV_LOG_ERROR, "Writing output failed (closing writer): %s\n", av_err2str(ret)); + + ret = avtext_context_close(&tctx); + if (ret < 0) + av_log(NULL, AV_LOG_ERROR, "Writing output failed (closing formatter): %s\n", av_err2str(ret)); ret = FFMIN(ret, input_ret); } @@ -4783,17 +3400,12 @@ end: av_freep(&input_filename); av_freep(&print_input_filename); av_freep(&read_intervals); - av_hash_freep(&hash); uninit_opts(); - for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) - av_dict_free(&(sections[i].entries_to_show)); + for (size_t i = 0; i < FF_ARRAY_ELEMS(selected_entries); ++i) + av_dict_free(&selected_entries[i].entries_to_show); avformat_network_deinit(); -#if HAVE_THREADS - pthread_mutex_destroy(&log_mutex); -#endif - return ret < 0; } diff --git a/fftools/graph/graphprint.c b/fftools/graph/graphprint.c new file mode 100644 index 000000000..5b050506d --- /dev/null +++ b/fftools/graph/graphprint.c @@ -0,0 +1,1078 @@ +/* + * Copyright (c) 2018-2025 - softworkz + * + * 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 + * output writers for filtergraph details + */ + +#include +#include + +#include "graphprint.h" + +#include "fftools/ffmpeg.h" +#include "fftools/ffmpeg_mux.h" + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/pixdesc.h" +#include "libavutil/dict.h" +#include "libavutil/common.h" +#include "libavfilter/avfilter.h" +#include "libavutil/buffer.h" +#include "libavutil/hwcontext.h" +#include "fftools/textformat/avtextformat.h" +#include "fftools/textformat/tf_mermaid.h" +#include "fftools/resources/resman.h" + +typedef enum { + SECTION_ID_ROOT, + SECTION_ID_FILTERGRAPHS, + SECTION_ID_FILTERGRAPH, + SECTION_ID_GRAPH_INPUTS, + SECTION_ID_GRAPH_INPUT, + SECTION_ID_GRAPH_OUTPUTS, + SECTION_ID_GRAPH_OUTPUT, + SECTION_ID_FILTERS, + SECTION_ID_FILTER, + SECTION_ID_FILTER_INPUTS, + SECTION_ID_FILTER_INPUT, + SECTION_ID_FILTER_OUTPUTS, + SECTION_ID_FILTER_OUTPUT, + SECTION_ID_HWFRAMESCONTEXT, + SECTION_ID_INPUTFILES, + SECTION_ID_INPUTFILE, + SECTION_ID_INPUTSTREAMS, + SECTION_ID_INPUTSTREAM, + SECTION_ID_OUTPUTFILES, + SECTION_ID_OUTPUTFILE, + SECTION_ID_OUTPUTSTREAMS, + SECTION_ID_OUTPUTSTREAM, + SECTION_ID_STREAMLINKS, + SECTION_ID_STREAMLINK, + SECTION_ID_DECODERS, + SECTION_ID_DECODER, + SECTION_ID_ENCODERS, + SECTION_ID_ENCODER, +} SectionID; + +static const AVTextFormatSection sections[] = { + [SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER, { SECTION_ID_FILTERGRAPHS, SECTION_ID_INPUTFILES, SECTION_ID_OUTPUTFILES, SECTION_ID_DECODERS, SECTION_ID_ENCODERS, SECTION_ID_STREAMLINKS, -1 } }, + + [SECTION_ID_FILTERGRAPHS] = { SECTION_ID_FILTERGRAPHS, "graphs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FILTERGRAPH, -1 } }, + [SECTION_ID_FILTERGRAPH] = { SECTION_ID_FILTERGRAPH, "graph", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { SECTION_ID_GRAPH_INPUTS, SECTION_ID_GRAPH_OUTPUTS, SECTION_ID_FILTERS, -1 }, .element_name = "graph_info" }, + + [SECTION_ID_GRAPH_INPUTS] = { SECTION_ID_GRAPH_INPUTS, "graph_inputs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_GRAPH_INPUT, -1 }, .id_key = "id" }, + [SECTION_ID_GRAPH_INPUT] = { SECTION_ID_GRAPH_INPUT, "graph_input", 0, { -1 }, .id_key = "filter_id" }, + + [SECTION_ID_GRAPH_OUTPUTS] = { SECTION_ID_GRAPH_OUTPUTS, "graph_outputs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_GRAPH_OUTPUT, -1 }, .id_key = "id" }, + [SECTION_ID_GRAPH_OUTPUT] = { SECTION_ID_GRAPH_OUTPUT, "graph_output", 0, { -1 }, .id_key = "filter_id" }, + + [SECTION_ID_FILTERS] = { SECTION_ID_FILTERS, "filters", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_FILTER, -1 }, .id_key = "graph_id" }, + [SECTION_ID_FILTER] = { SECTION_ID_FILTER, "filter", AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS, { SECTION_ID_FILTER_INPUTS, SECTION_ID_FILTER_OUTPUTS, -1 }, .id_key = "filter_id" }, + + [SECTION_ID_FILTER_INPUTS] = { SECTION_ID_FILTER_INPUTS, "filter_inputs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FILTER_INPUT, -1 } }, + [SECTION_ID_FILTER_INPUT] = { SECTION_ID_FILTER_INPUT, "filter_input", AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS, { SECTION_ID_HWFRAMESCONTEXT, -1 }, .id_key = "filter_id", .src_id_key = "source_filter_id", .dest_id_key = "filter_id" }, + + [SECTION_ID_FILTER_OUTPUTS] = { SECTION_ID_FILTER_OUTPUTS, "filter_outputs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FILTER_OUTPUT, -1 } }, + [SECTION_ID_FILTER_OUTPUT] = { SECTION_ID_FILTER_OUTPUT, "filter_output", AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS, { SECTION_ID_HWFRAMESCONTEXT, -1 }, .id_key = "filter_id", .src_id_key = "filter_id", .dest_id_key = "dest_filter_id" }, + + [SECTION_ID_HWFRAMESCONTEXT] = { SECTION_ID_HWFRAMESCONTEXT, "hw_frames_context", 0, { -1 }, }, + + [SECTION_ID_INPUTFILES] = { SECTION_ID_INPUTFILES, "inputfiles", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_INPUTFILE, -1 }, .id_key = "id" }, + [SECTION_ID_INPUTFILE] = { SECTION_ID_INPUTFILE, "inputfile", AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_INPUTSTREAMS, -1 }, .id_key = "id" }, + + [SECTION_ID_INPUTSTREAMS] = { SECTION_ID_INPUTSTREAMS, "inputstreams", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_INPUTSTREAM, -1 }, .id_key = "id" }, + [SECTION_ID_INPUTSTREAM] = { SECTION_ID_INPUTSTREAM, "inputstream", AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS, { -1 }, .id_key = "id" }, + + [SECTION_ID_OUTPUTFILES] = { SECTION_ID_OUTPUTFILES, "outputfiles", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_OUTPUTFILE, -1 }, .id_key = "id" }, + [SECTION_ID_OUTPUTFILE] = { SECTION_ID_OUTPUTFILE, "outputfile", AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_OUTPUTSTREAMS, -1 }, .id_key = "id" }, + + [SECTION_ID_OUTPUTSTREAMS] = { SECTION_ID_OUTPUTSTREAMS, "outputstreams", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_OUTPUTSTREAM, -1 }, .id_key = "id" }, + [SECTION_ID_OUTPUTSTREAM] = { SECTION_ID_OUTPUTSTREAM, "outputstream", AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS, { -1 }, .id_key = "id", }, + + [SECTION_ID_STREAMLINKS] = { SECTION_ID_STREAMLINKS, "streamlinks", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAMLINK, -1 } }, + [SECTION_ID_STREAMLINK] = { SECTION_ID_STREAMLINK, "streamlink", AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS, { -1 }, .src_id_key = "source_stream_id", .dest_id_key = "dest_stream_id" }, + + [SECTION_ID_DECODERS] = { SECTION_ID_DECODERS, "decoders", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_DECODER, -1 } }, + [SECTION_ID_DECODER] = { SECTION_ID_DECODER, "decoder", AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS | AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS, { -1 }, .id_key = "id", .src_id_key = "source_id", .dest_id_key = "id" }, + + [SECTION_ID_ENCODERS] = { SECTION_ID_ENCODERS, "encoders", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_ENCODER, -1 } }, + [SECTION_ID_ENCODER] = { SECTION_ID_ENCODER, "encoder", AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS | AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS, { -1 }, .id_key = "id", .src_id_key = "id", .dest_id_key = "dest_id" }, +}; + +typedef struct GraphPrintContext { + AVTextFormatContext *tfc; + AVTextWriterContext *wctx; + AVDiagramConfig diagram_config; + + int id_prefix_num; + int is_diagram; + int opt_flags; + int skip_buffer_filters; + AVBPrint pbuf; + +} GraphPrintContext; + +/* Text Format API Shortcuts */ +#define print_id(k, v) print_sanizied_id(gpc, k, v, 0) +#define print_id_noprefix(k, v) print_sanizied_id(gpc, k, v, 1) +#define print_int(k, v) avtext_print_integer(tfc, k, v, 0) +#define print_int_opt(k, v) avtext_print_integer(tfc, k, v, gpc->opt_flags) +#define print_q(k, v, s) avtext_print_rational(tfc, k, v, s) +#define print_str(k, v) avtext_print_string(tfc, k, v, 0) +#define print_str_opt(k, v) avtext_print_string(tfc, k, v, gpc->opt_flags) +#define print_val(k, v, u) avtext_print_unit_integer(tfc, k, v, u) + +#define print_fmt(k, f, ...) do { \ + av_bprint_clear(&gpc->pbuf); \ + av_bprintf(&gpc->pbuf, f, __VA_ARGS__); \ + avtext_print_string(tfc, k, gpc->pbuf.str, 0); \ +} while (0) + +#define print_fmt_opt(k, f, ...) do { \ + av_bprint_clear(&gpc->pbuf); \ + av_bprintf(&gpc->pbuf, f, __VA_ARGS__); \ + avtext_print_string(tfc, k, gpc->pbuf.str, gpc->opt_flags); \ +} while (0) + + +static atomic_int prefix_num = 0; + +static inline char *upcase_string(char *dst, size_t dst_size, const char *src) +{ + unsigned i; + for (i = 0; src[i] && i < dst_size - 1; i++) + dst[i] = (char)av_toupper(src[i]); + dst[i] = 0; + return dst; +} + +static char *get_extension(const char *url) +{ + const char *dot = NULL; + const char *sep = NULL; + const char *end; + + if (!url) + return NULL; + + /* Stop at the first query ('?') or fragment ('#') delimiter so they + * are not considered part of the path. */ + end = strpbrk(url, "?#"); + if (!end) + end = url + strlen(url); + + /* Scan the path component only. */ + for (const char *p = url; p < end; p++) { + if (*p == '.') + dot = p; + else if (*p == '/' || *p == '\\') + sep = p; + } + + /* Validate that we have a proper extension. */ + if (dot && dot != url && (!sep || dot > sep + 1) && (dot + 1) < end) { + /* Use FFmpeg helper to duplicate the substring. */ + return av_strndup(dot + 1, end - (dot + 1)); + } + + return NULL; +} + +static void print_hwdevicecontext(const GraphPrintContext *gpc, const AVHWDeviceContext *hw_device_context) +{ + AVTextFormatContext *tfc = gpc->tfc; + + if (!hw_device_context) + return; + + print_int_opt("has_hw_device_context", 1); + print_str_opt("hw_device_type", av_hwdevice_get_type_name(hw_device_context->type)); +} + +static void print_hwframescontext(const GraphPrintContext *gpc, const AVHWFramesContext *hw_frames_context) +{ + AVTextFormatContext *tfc = gpc->tfc; + const AVPixFmtDescriptor *pix_desc_hw; + const AVPixFmtDescriptor *pix_desc_sw; + + if (!hw_frames_context || !hw_frames_context->device_ctx) + return; + + avtext_print_section_header(tfc, NULL, SECTION_ID_HWFRAMESCONTEXT); + + print_int_opt("has_hw_frames_context", 1); + print_str("hw_device_type", av_hwdevice_get_type_name(hw_frames_context->device_ctx->type)); + + pix_desc_hw = av_pix_fmt_desc_get(hw_frames_context->format); + if (pix_desc_hw) { + print_str("hw_pixel_format", pix_desc_hw->name); + if (pix_desc_hw->alias) + print_str_opt("hw_pixel_format_alias", pix_desc_hw->alias); + } + + pix_desc_sw = av_pix_fmt_desc_get(hw_frames_context->sw_format); + if (pix_desc_sw) { + print_str("sw_pixel_format", pix_desc_sw->name); + if (pix_desc_sw->alias) + print_str_opt("sw_pixel_format_alias", pix_desc_sw->alias); + } + + print_int_opt("width", hw_frames_context->width); + print_int_opt("height", hw_frames_context->height); + print_int_opt("initial_pool_size", hw_frames_context->initial_pool_size); + + avtext_print_section_footer(tfc); // SECTION_ID_HWFRAMESCONTEXT +} + +static void print_link(GraphPrintContext *gpc, AVFilterLink *link) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVBufferRef *hw_frames_ctx; + char layout_string[64]; + + if (!link) + return; + + hw_frames_ctx = avfilter_link_get_hw_frames_ctx(link); + + print_str_opt("media_type", av_get_media_type_string(link->type)); + + switch (link->type) { + case AVMEDIA_TYPE_VIDEO: + + if (hw_frames_ctx && hw_frames_ctx->data) { + AVHWFramesContext * hwfctx = (AVHWFramesContext *)hw_frames_ctx->data; + const AVPixFmtDescriptor *pix_desc_hw = av_pix_fmt_desc_get(hwfctx->format); + const AVPixFmtDescriptor *pix_desc_sw = av_pix_fmt_desc_get(hwfctx->sw_format); + if (pix_desc_hw && pix_desc_sw) + print_fmt("format", "%s | %s", pix_desc_hw->name, pix_desc_sw->name); + } else { + print_str("format", av_x_if_null(av_get_pix_fmt_name(link->format), "?")); + } + + if (link->w && link->h) { + if (tfc->opts.show_value_unit) { + print_fmt("size", "%dx%d", link->w, link->h); + } else { + print_int("width", link->w); + print_int("height", link->h); + } + } + + print_q("sar", link->sample_aspect_ratio, ':'); + + if (link->color_range != AVCOL_RANGE_UNSPECIFIED) + print_str_opt("color_range", av_color_range_name(link->color_range)); + + if (link->colorspace != AVCOL_SPC_UNSPECIFIED) + print_str("color_space", av_color_space_name(link->colorspace)); + break; + + case AVMEDIA_TYPE_SUBTITLE: + ////print_str("format", av_x_if_null(av_get_subtitle_fmt_name(link->format), "?")); + + if (link->w && link->h) { + if (tfc->opts.show_value_unit) { + print_fmt("size", "%dx%d", link->w, link->h); + } else { + print_int("width", link->w); + print_int("height", link->h); + } + } + + break; + + case AVMEDIA_TYPE_AUDIO: + av_channel_layout_describe(&link->ch_layout, layout_string, sizeof(layout_string)); + print_str("channel_layout", layout_string); + print_val("channels", link->ch_layout.nb_channels, "ch"); + if (tfc->opts.show_value_unit) + print_fmt("sample_rate", "%d.1 kHz", link->sample_rate / 1000); + else + print_val("sample_rate", link->sample_rate, "Hz"); + + break; + } + + print_fmt_opt("sample_rate", "%d/%d", link->time_base.num, link->time_base.den); + + if (hw_frames_ctx && hw_frames_ctx->data) + print_hwframescontext(gpc, (AVHWFramesContext *)hw_frames_ctx->data); + av_buffer_unref(&hw_frames_ctx); +} + +static char sanitize_char(const char c) +{ + if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + return c; + return '_'; +} + +static void print_sanizied_id(const GraphPrintContext *gpc, const char *key, const char *id_str, int skip_prefix) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVBPrint buf; + + if (!key || !id_str) + return; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + if (!skip_prefix) + av_bprintf(&buf, "G%d_", gpc->id_prefix_num); + + // sanizize section id + for (const char *p = id_str; *p; p++) + av_bprint_chars(&buf, sanitize_char(*p), 1); + + print_str(key, buf.str); + + av_bprint_finalize(&buf, NULL); +} + +static void print_section_header_id(const GraphPrintContext *gpc, int section_id, const char *id_str, int skip_prefix) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVTextFormatSectionContext sec_ctx = { 0 }; + AVBPrint buf; + + if (!id_str) + return; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + if (!skip_prefix) + av_bprintf(&buf, "G%d_", gpc->id_prefix_num); + + // sanizize section id + for (const char *p = id_str; *p; p++) + av_bprint_chars(&buf, sanitize_char(*p), 1); + + sec_ctx.context_id = buf.str; + + avtext_print_section_header(tfc, &sec_ctx, section_id); + + av_bprint_finalize(&buf, NULL); +} + +static const char *get_filterpad_name(const AVFilterPad *pad) +{ + return pad ? avfilter_pad_get_name(pad, 0) : "pad"; +} + +static void print_filter(GraphPrintContext *gpc, const AVFilterContext *filter, AVDictionary *input_map, AVDictionary *output_map) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVTextFormatSectionContext sec_ctx = { 0 }; + + print_section_header_id(gpc, SECTION_ID_FILTER, filter->name, 0); + + ////print_id("filter_id", filter->name); + + if (filter->filter) { + print_str("filter_name", filter->filter->name); + print_str_opt("description", filter->filter->description); + print_int_opt("nb_inputs", filter->nb_inputs); + print_int_opt("nb_outputs", filter->nb_outputs); + } + + if (filter->hw_device_ctx) { + AVHWDeviceContext *device_context = (AVHWDeviceContext *)filter->hw_device_ctx->data; + print_hwdevicecontext(gpc, device_context); + if (filter->extra_hw_frames > 0) + print_int("extra_hw_frames", filter->extra_hw_frames); + } + + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTER_INPUTS); + + for (unsigned i = 0; i < filter->nb_inputs; i++) { + AVDictionaryEntry *dic_entry; + AVFilterLink *link = filter->inputs[i]; + + sec_ctx.context_type = av_get_media_type_string(link->type); + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_FILTER_INPUT); + sec_ctx.context_type = NULL; + + print_int_opt("input_index", i); + print_str_opt("pad_name", get_filterpad_name(link->dstpad));; + + dic_entry = av_dict_get(input_map, link->src->name, NULL, 0); + if (dic_entry) { + char buf[256]; + (void)snprintf(buf, sizeof(buf), "in_%s", dic_entry->value); + print_id_noprefix("source_filter_id", buf); + } else { + print_id("source_filter_id", link->src->name); + } + + print_str_opt("source_pad_name", get_filterpad_name(link->srcpad)); + print_id("filter_id", filter->name); + + print_link(gpc, link); + + avtext_print_section_footer(tfc); // SECTION_ID_FILTER_INPUT + } + + avtext_print_section_footer(tfc); // SECTION_ID_FILTER_INPUTS + + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTER_OUTPUTS); + + for (unsigned i = 0; i < filter->nb_outputs; i++) { + AVDictionaryEntry *dic_entry; + AVFilterLink *link = filter->outputs[i]; + char buf[256]; + + sec_ctx.context_type = av_get_media_type_string(link->type); + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_FILTER_OUTPUT); + sec_ctx.context_type = NULL; + + dic_entry = av_dict_get(output_map, link->dst->name, NULL, 0); + if (dic_entry) { + (void)snprintf(buf, sizeof(buf), "out_%s", dic_entry->value); + print_id_noprefix("dest_filter_id", buf); + } else { + print_id("dest_filter_id", link->dst->name); + } + + print_int_opt("output_index", i); + print_str_opt("pad_name", get_filterpad_name(link->srcpad)); + ////print_id("dest_filter_id", link->dst->name); + print_str_opt("dest_pad_name", get_filterpad_name(link->dstpad)); + print_id("filter_id", filter->name); + + print_link(gpc, link); + + avtext_print_section_footer(tfc); // SECTION_ID_FILTER_OUTPUT + } + + avtext_print_section_footer(tfc); // SECTION_ID_FILTER_OUTPUTS + + avtext_print_section_footer(tfc); // SECTION_ID_FILTER +} + +static void print_filtergraph_single(GraphPrintContext *gpc, FilterGraph *fg, AVFilterGraph *graph) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVDictionary *input_map = NULL; + AVDictionary *output_map = NULL; + + print_int("graph_index", fg->index); + print_fmt("name", "Graph %d.%d", gpc->id_prefix_num, fg->index); + print_fmt("id", "Graph_%d_%d", gpc->id_prefix_num, fg->index); + print_str("description", fg->graph_desc); + + print_section_header_id(gpc, SECTION_ID_GRAPH_INPUTS, "Input_File", 0); + + for (int i = 0; i < fg->nb_inputs; i++) { + InputFilter *ifilter = fg->inputs[i]; + enum AVMediaType media_type = ifilter->type; + + avtext_print_section_header(tfc, NULL, SECTION_ID_GRAPH_INPUT); + + print_int("input_index", ifilter->index); + + if (ifilter->linklabel) + print_str("link_label", (const char*)ifilter->linklabel); + + if (ifilter->filter) { + print_id("filter_id", ifilter->filter->name); + print_str("filter_name", ifilter->filter->filter->name); + } + + if (ifilter->linklabel && ifilter->filter) + av_dict_set(&input_map, ifilter->filter->name, (const char *)ifilter->linklabel, 0); + else if (ifilter->input_name && ifilter->filter) + av_dict_set(&input_map, ifilter->filter->name, (const char *)ifilter->input_name, 0); + + print_str("media_type", av_get_media_type_string(media_type)); + + avtext_print_section_footer(tfc); // SECTION_ID_GRAPH_INPUT + } + + avtext_print_section_footer(tfc); // SECTION_ID_GRAPH_INPUTS + + print_section_header_id(gpc, SECTION_ID_GRAPH_OUTPUTS, "Output_File", 0); + + for (int i = 0; i < fg->nb_outputs; i++) { + OutputFilter *ofilter = fg->outputs[i]; + + avtext_print_section_header(tfc, NULL, SECTION_ID_GRAPH_OUTPUT); + + print_int("output_index", ofilter->index); + + print_str("name", ofilter->output_name); + + if (fg->outputs[i]->linklabel) + print_str("link_label", (const char*)fg->outputs[i]->linklabel); + + if (ofilter->filter) { + print_id("filter_id", ofilter->filter->name); + print_str("filter_name", ofilter->filter->filter->name); + } + + if (ofilter->output_name && ofilter->filter) + av_dict_set(&output_map, ofilter->filter->name, ofilter->output_name, 0); + + + print_str("media_type", av_get_media_type_string(ofilter->type)); + + avtext_print_section_footer(tfc); // SECTION_ID_GRAPH_OUTPUT + } + + avtext_print_section_footer(tfc); // SECTION_ID_GRAPH_OUTPUTS + + if (graph) { + AVTextFormatSectionContext sec_ctx = { 0 }; + + sec_ctx.context_id = av_asprintf("Graph_%d_%d", gpc->id_prefix_num, fg->index); + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_FILTERS); + + if (gpc->is_diagram) { + print_fmt("name", "Graph %d.%d", gpc->id_prefix_num, fg->index); + print_str("description", fg->graph_desc); + print_str("id", sec_ctx.context_id); + } + + av_freep(&sec_ctx.context_id); + + for (unsigned i = 0; i < graph->nb_filters; i++) { + AVFilterContext *filter = graph->filters[i]; + + if (gpc->skip_buffer_filters) { + if (av_dict_get(input_map, filter->name, NULL, 0)) + continue; + if (av_dict_get(output_map, filter->name, NULL, 0)) + continue; + } + + sec_ctx.context_id = filter->name; + + print_filter(gpc, filter, input_map, output_map); + } + + avtext_print_section_footer(tfc); // SECTION_ID_FILTERS + } + + // Clean up dictionaries + av_dict_free(&input_map); + av_dict_free(&output_map); +} + +static int print_streams(GraphPrintContext *gpc, InputFile **ifiles, int nb_ifiles, OutputFile **ofiles, int nb_ofiles) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVBPrint buf; + AVTextFormatSectionContext sec_ctx = { 0 }; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + print_section_header_id(gpc, SECTION_ID_INPUTFILES, "Inputs", 0); + + for (int n = nb_ifiles - 1; n >= 0; n--) { + InputFile *ifi = ifiles[n]; + AVFormatContext *fc = ifi->ctx; + + sec_ctx.context_id = av_asprintf("Input_%d", n); + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_INPUTFILE); + av_freep(&sec_ctx.context_id); + + print_fmt("index", "%d", ifi->index); + + if (fc) { + print_str("demuxer_name", fc->iformat->name); + if (fc->url) { + char *extension = get_extension(fc->url); + if (extension) { + print_str("file_extension", extension); + av_freep(&extension); + } + print_str("url", fc->url); + } + } + + sec_ctx.context_id = av_asprintf("InputStreams_%d", n); + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_INPUTSTREAMS); + + av_freep(&sec_ctx.context_id); + + for (int i = 0; i < ifi->nb_streams; i++) { + InputStream *ist = ifi->streams[i]; + const AVCodecDescriptor *codec_desc; + + if (!ist || !ist->par) + continue; + + codec_desc = avcodec_descriptor_get(ist->par->codec_id); + + sec_ctx.context_id = av_asprintf("r_in_%d_%d", n, i); + + sec_ctx.context_type = av_get_media_type_string(ist->par->codec_type); + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_INPUTSTREAM); + av_freep(&sec_ctx.context_id); + sec_ctx.context_type = NULL; + + av_bprint_clear(&buf); + + print_fmt("id", "r_in_%d_%d", n, i); + + if (codec_desc && codec_desc->name) { + ////av_bprintf(&buf, "%s", upcase_string(char_buf, sizeof(char_buf), codec_desc->long_name)); + av_bprintf(&buf, "%s", codec_desc->long_name); + } else if (ist->dec) { + char char_buf[256]; + av_bprintf(&buf, "%s", upcase_string(char_buf, sizeof(char_buf), ist->dec->name)); + } else if (ist->par->codec_type == AVMEDIA_TYPE_ATTACHMENT) { + av_bprintf(&buf, "%s", "Attachment"); + } else if (ist->par->codec_type == AVMEDIA_TYPE_DATA) { + av_bprintf(&buf, "%s", "Data"); + } + + print_fmt("name", "%s", buf.str); + print_fmt("index", "%d", ist->index); + + if (ist->dec) + print_str_opt("media_type", av_get_media_type_string(ist->par->codec_type)); + + avtext_print_section_footer(tfc); // SECTION_ID_INPUTSTREAM + } + + avtext_print_section_footer(tfc); // SECTION_ID_INPUTSTREAMS + avtext_print_section_footer(tfc); // SECTION_ID_INPUTFILE + } + + avtext_print_section_footer(tfc); // SECTION_ID_INPUTFILES + + + print_section_header_id(gpc, SECTION_ID_DECODERS, "Decoders", 0); + + for (int n = 0; n < nb_ifiles; n++) { + InputFile *ifi = ifiles[n]; + + for (int i = 0; i < ifi->nb_streams; i++) { + InputStream *ist = ifi->streams[i]; + + if (!ist->decoder) + continue; + + sec_ctx.context_id = av_asprintf("in_%d_%d", n, i); + sec_ctx.context_type = av_get_media_type_string(ist->par->codec_type); + sec_ctx.context_flags = 2; + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_DECODER); + av_freep(&sec_ctx.context_id); + sec_ctx.context_type = NULL; + sec_ctx.context_flags = 0; + + av_bprint_clear(&buf); + + print_fmt("source_id", "r_in_%d_%d", n, i); + print_fmt("id", "in_%d_%d", n, i); + + ////av_bprintf(&buf, "%s", upcase_string(char_buf, sizeof(char_buf), ist->dec->name)); + print_fmt("name", "%s", ist->dec->name); + + print_str_opt("media_type", av_get_media_type_string(ist->par->codec_type)); + + avtext_print_section_footer(tfc); // SECTION_ID_DECODER + } + } + + avtext_print_section_footer(tfc); // SECTION_ID_DECODERS + + + print_section_header_id(gpc, SECTION_ID_ENCODERS, "Encoders", 0); + + for (int n = 0; n < nb_ofiles; n++) { + OutputFile *of = ofiles[n]; + + for (int i = 0; i < of->nb_streams; i++) { + OutputStream *ost = of->streams[i]; + ////const AVCodecDescriptor *codec_desc; + + if (!ost || !ost->st || !ost->st->codecpar || !ost->enc) + continue; + + ////codec_desc = avcodec_descriptor_get(ost->st->codecpar->codec_id); + + sec_ctx.context_id = av_asprintf("out__%d_%d", n, i); + sec_ctx.context_type = av_get_media_type_string(ost->type); + sec_ctx.context_flags = 2; + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_ENCODER); + av_freep(&sec_ctx.context_id); + sec_ctx.context_type = NULL; + sec_ctx.context_flags = 0; + + av_bprint_clear(&buf); + + print_fmt("id", "out__%d_%d", n, i); + print_fmt("dest_id", "r_out__%d_%d", n, i); + + print_fmt("name", "%s", ost->enc->enc_ctx->av_class->item_name(ost->enc->enc_ctx)); + + print_str_opt("media_type", av_get_media_type_string(ost->type)); + + avtext_print_section_footer(tfc); // SECTION_ID_ENCODER + } + } + + avtext_print_section_footer(tfc); // SECTION_ID_ENCODERS + + + print_section_header_id(gpc, SECTION_ID_OUTPUTFILES, "Outputs", 0); + + for (int n = nb_ofiles - 1; n >= 0; n--) { + OutputFile *of = ofiles[n]; + Muxer *muxer = (Muxer *)of; + + if (!muxer->fc) + continue; + + sec_ctx.context_id = av_asprintf("Output_%d", n); + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_OUTPUTFILE); + + av_freep(&sec_ctx.context_id); + + ////print_str_opt("index", av_get_media_type_string(of->index)); + print_fmt("index", "%d", of->index); + ////print_str("url", of->url); + print_str("muxer_name", muxer->fc->oformat->name); + if (of->url) { + char *extension = get_extension(of->url); + if (extension) { + print_str("file_extension", extension); + av_freep(&extension); + } + print_str("url", of->url); + } + + sec_ctx.context_id = av_asprintf("OutputStreams_%d", n); + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_OUTPUTSTREAMS); + + av_freep(&sec_ctx.context_id); + + for (int i = 0; i < of->nb_streams; i++) { + OutputStream *ost = of->streams[i]; + const AVCodecDescriptor *codec_desc = avcodec_descriptor_get(ost->st->codecpar->codec_id); + + sec_ctx.context_id = av_asprintf("r_out__%d_%d", n, i); + sec_ctx.context_type = av_get_media_type_string(ost->type); + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_OUTPUTSTREAM); + av_freep(&sec_ctx.context_id); + sec_ctx.context_type = NULL; + + av_bprint_clear(&buf); + + print_fmt("id", "r_out__%d_%d", n, i); + + if (codec_desc && codec_desc->name) { + av_bprintf(&buf, "%s", codec_desc->long_name); + } else { + av_bprintf(&buf, "%s", "unknown"); + } + + print_fmt("name", "%s", buf.str); + print_fmt("index", "%d", ost->index); + + print_str_opt("media_type", av_get_media_type_string(ost->type)); + + avtext_print_section_footer(tfc); // SECTION_ID_OUTPUTSTREAM + } + + avtext_print_section_footer(tfc); // SECTION_ID_OUTPUTSTREAMS + avtext_print_section_footer(tfc); // SECTION_ID_OUTPUTFILE + } + + avtext_print_section_footer(tfc); // SECTION_ID_OUTPUTFILES + + + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAMLINKS); + + for (int n = 0; n < nb_ofiles; n++) { + OutputFile *of = ofiles[n]; + + for (int i = 0; i < of->nb_streams; i++) { + OutputStream *ost = of->streams[i]; + + if (ost->ist && !ost->filter) { + sec_ctx.context_type = av_get_media_type_string(ost->type); + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_STREAMLINK); + sec_ctx.context_type = NULL; + + if (ost->enc) { + print_fmt("dest_stream_id", "out__%d_%d", n, i); + print_fmt("source_stream_id", "in_%d_%d", ost->ist->file->index, ost->ist->index); + print_str("operation", "Transcode"); + } else { + print_fmt("dest_stream_id", "r_out__%d_%d", n, i); + print_fmt("source_stream_id", "r_in_%d_%d", ost->ist->file->index, ost->ist->index); + print_str("operation", "Stream Copy"); + } + + print_str_opt("media_type", av_get_media_type_string(ost->type)); + + avtext_print_section_footer(tfc); // SECTION_ID_STREAMLINK + } + } + } + + avtext_print_section_footer(tfc); // SECTION_ID_STREAMLINKS + + av_bprint_finalize(&buf, NULL); + return 0; +} + + +static void uninit_graphprint(GraphPrintContext *gpc) +{ + if (gpc->tfc) + avtext_context_close(&gpc->tfc); + + if (gpc->wctx) + avtextwriter_context_close(&gpc->wctx); + + // Finalize the print buffer if it was initialized + av_bprint_finalize(&gpc->pbuf, NULL); + + av_freep(&gpc); +} + +static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf) +{ + const AVTextFormatter *text_formatter; + AVTextFormatContext *tfc = NULL; + AVTextWriterContext *wctx = NULL; + GraphPrintContext *gpc = NULL; + int ret; + + *pgpc = NULL; + + av_bprint_init(target_buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + const char *w_name = print_graphs_format ? print_graphs_format : "json"; + + text_formatter = avtext_get_formatter_by_name(w_name); + if (!text_formatter) { + av_log(NULL, AV_LOG_ERROR, "Unknown filter graph output format with name '%s'\n", w_name); + ret = AVERROR(EINVAL); + goto fail; + } + + ret = avtextwriter_create_buffer(&wctx, target_buf); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "avtextwriter_create_buffer failed. Error code %d\n", ret); + ret = AVERROR(EINVAL); + goto fail; + } + + AVTextFormatOptions tf_options = { .show_optional_fields = -1 }; + const char *w_args = print_graphs_format ? strchr(print_graphs_format, '=') : NULL; + if (w_args) + ++w_args; // consume '=' + ret = avtext_context_open(&tfc, text_formatter, wctx, w_args, sections, FF_ARRAY_ELEMS(sections), tf_options, NULL); + if (ret < 0) { + goto fail; + } + + gpc = av_mallocz(sizeof(GraphPrintContext)); + if (!gpc) { + ret = AVERROR(ENOMEM); + goto fail; + } + + gpc->wctx = wctx; + gpc->tfc = tfc; + av_bprint_init(&gpc->pbuf, 0, AV_BPRINT_SIZE_UNLIMITED); + + gpc->id_prefix_num = atomic_fetch_add(&prefix_num, 1); + gpc->is_diagram = !!(tfc->formatter->flags & AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER); + if (gpc->is_diagram) { + tfc->opts.show_value_unit = 1; + tfc->opts.show_optional_fields = -1; + gpc->opt_flags = AV_TEXTFORMAT_PRINT_STRING_OPTIONAL; + gpc->skip_buffer_filters = 1; + ////} else { + //// gpc->opt_flags = AV_TEXTFORMAT_PRINT_STRING_OPTIONAL; + } + + if (!strcmp(text_formatter->name, "mermaid") || !strcmp(text_formatter->name, "mermaidhtml")) { + gpc->diagram_config.diagram_css = ff_resman_get_string(FF_RESOURCE_GRAPH_CSS); + + if (!strcmp(text_formatter->name, "mermaidhtml")) + gpc->diagram_config.html_template = ff_resman_get_string(FF_RESOURCE_GRAPH_HTML); + + av_diagram_init(tfc, &gpc->diagram_config); + } + + *pgpc = gpc; + + return 0; + +fail: + if (tfc) + avtext_context_close(&tfc); + if (wctx && !tfc) // Only free wctx if tfc didn't take ownership of it + avtextwriter_context_close(&wctx); + av_freep(&gpc); + + return ret; +} + + +int print_filtergraph(FilterGraph *fg, AVFilterGraph *graph) +{ + av_assert2(fg); + + GraphPrintContext *gpc = NULL; + AVTextFormatContext *tfc; + AVBPrint *target_buf = &fg->graph_print_buf; + int ret; + + if (target_buf->len) + av_bprint_finalize(target_buf, NULL); + + ret = init_graphprint(&gpc, target_buf); + if (ret) + return ret; + + tfc = gpc->tfc; + + // Due to the threading model each graph needs to print itself into a buffer + // from its own thread. The actual printing happens short before cleanup in ffmpeg.c + // where all graphs are assembled together. To make this work, we need to put the + // formatting context into the same state like it would be when printing all at once, + // so here we print the section headers and clear the buffer to get into the right state. + avtext_print_section_header(tfc, NULL, SECTION_ID_ROOT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTERGRAPHS); + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTERGRAPH); + + av_bprint_clear(target_buf); + + print_filtergraph_single(gpc, fg, graph); + + if (gpc->is_diagram) { + avtext_print_section_footer(tfc); // SECTION_ID_FILTERGRAPH + avtext_print_section_footer(tfc); // SECTION_ID_FILTERGRAPHS + } + + uninit_graphprint(gpc); + + return 0; +} + +static int print_filtergraphs_priv(FilterGraph **graphs, int nb_graphs, InputFile **ifiles, int nb_ifiles, OutputFile **ofiles, int nb_ofiles) +{ + GraphPrintContext *gpc = NULL; + AVTextFormatContext *tfc; + AVBPrint target_buf; + int ret; + + ret = init_graphprint(&gpc, &target_buf); + if (ret) + goto cleanup; + + tfc = gpc->tfc; + + avtext_print_section_header(tfc, NULL, SECTION_ID_ROOT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTERGRAPHS); + + for (int i = 0; i < nb_graphs; i++) { + AVBPrint *graph_buf = &graphs[i]->graph_print_buf; + + if (graph_buf->len > 0) { + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTERGRAPH); + av_bprint_append_data(&target_buf, graph_buf->str, graph_buf->len); + av_bprint_finalize(graph_buf, NULL); + avtext_print_section_footer(tfc); // SECTION_ID_FILTERGRAPH + } + } + + for (int n = 0; n < nb_ofiles; n++) { + OutputFile *of = ofiles[n]; + + for (int i = 0; i < of->nb_streams; i++) { + OutputStream *ost = of->streams[i]; + + if (ost->fg_simple) { + AVBPrint *graph_buf = &ost->fg_simple->graph_print_buf; + + if (graph_buf->len > 0) { + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTERGRAPH); + av_bprint_append_data(&target_buf, graph_buf->str, graph_buf->len); + av_bprint_finalize(graph_buf, NULL); + avtext_print_section_footer(tfc); // SECTION_ID_FILTERGRAPH + } + } + } + } + + avtext_print_section_footer(tfc); // SECTION_ID_FILTERGRAPHS + + print_streams(gpc, ifiles, nb_ifiles, ofiles, nb_ofiles); + + avtext_print_section_footer(tfc); // SECTION_ID_ROOT + + if (print_graphs_file) { + AVIOContext *avio = NULL; + + if (!strcmp(print_graphs_file, "-")) { + printf("%s", target_buf.str); + } else { + ret = avio_open2(&avio, print_graphs_file, AVIO_FLAG_WRITE, NULL, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Failed to open graph output file, \"%s\": %s\n", print_graphs_file, av_err2str(ret)); + goto cleanup; + } + + avio_write(avio, (const unsigned char *)target_buf.str, FFMIN(target_buf.len, target_buf.size - 1)); + + if ((ret = avio_closep(&avio)) < 0) + av_log(NULL, AV_LOG_ERROR, "Error closing graph output file, loss of information possible: %s\n", av_err2str(ret)); + } + } + + if (print_graphs) + av_log(NULL, AV_LOG_INFO, "%s %c", target_buf.str, '\n'); + +cleanup: + // Properly clean up resources + if (gpc) + uninit_graphprint(gpc); + + // Ensure the target buffer is properly finalized + av_bprint_finalize(&target_buf, NULL); + + return ret; +} + +int print_filtergraphs(FilterGraph **graphs, int nb_graphs, InputFile **ifiles, int nb_ifiles, OutputFile **ofiles, int nb_ofiles) +{ + int ret = print_filtergraphs_priv(graphs, nb_graphs, ifiles, nb_ifiles, ofiles, nb_ofiles); + ff_resman_uninit(); + return ret; +} diff --git a/fftools/graph/graphprint.h b/fftools/graph/graphprint.h new file mode 100644 index 000000000..9f043cc27 --- /dev/null +++ b/fftools/graph/graphprint.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2025 - softworkz + * + * 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 FFTOOLS_GRAPH_GRAPHPRINT_H +#define FFTOOLS_GRAPH_GRAPHPRINT_H + +#include "fftools/ffmpeg.h" + +int print_filtergraphs(FilterGraph **graphs, int nb_graphs, InputFile **ifiles, int nb_ifiles, OutputFile **ofiles, int nb_ofiles); + +int print_filtergraph(FilterGraph *fg, AVFilterGraph *graph); + +#endif /* FFTOOLS_GRAPH_GRAPHPRINT_H */ diff --git a/fftools/objpool.c b/fftools/objpool.c deleted file mode 100644 index 87237cf72..000000000 --- a/fftools/objpool.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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 "libavcodec/packet.h" - -#include "libavutil/common.h" -#include "libavutil/error.h" -#include "libavutil/frame.h" -#include "libavutil/mem.h" - -#include "objpool.h" - -struct ObjPool { - void *pool[32]; - unsigned int pool_count; - - ObjPoolCBAlloc alloc; - ObjPoolCBReset reset; - ObjPoolCBFree free; -}; - -ObjPool *objpool_alloc(ObjPoolCBAlloc cb_alloc, ObjPoolCBReset cb_reset, - ObjPoolCBFree cb_free) -{ - ObjPool *op = av_mallocz(sizeof(*op)); - - if (!op) - return NULL; - - op->alloc = cb_alloc; - op->reset = cb_reset; - op->free = cb_free; - - return op; -} - -void objpool_free(ObjPool **pop) -{ - ObjPool *op = *pop; - - if (!op) - return; - - for (unsigned int i = 0; i < op->pool_count; i++) - op->free(&op->pool[i]); - - av_freep(pop); -} - -int objpool_get(ObjPool *op, void **obj) -{ - if (op->pool_count) { - *obj = op->pool[--op->pool_count]; - op->pool[op->pool_count] = NULL; - } else - *obj = op->alloc(); - - return *obj ? 0 : AVERROR(ENOMEM); -} - -void objpool_release(ObjPool *op, void **obj) -{ - if (!*obj) - return; - - op->reset(*obj); - - if (op->pool_count < FF_ARRAY_ELEMS(op->pool)) - op->pool[op->pool_count++] = *obj; - else - op->free(obj); - - *obj = NULL; -} - -static void *alloc_packet(void) -{ - return av_packet_alloc(); -} -static void *alloc_frame(void) -{ - return av_frame_alloc(); -} - -static void reset_packet(void *obj) -{ - av_packet_unref(obj); -} -static void reset_frame(void *obj) -{ - av_frame_unref(obj); -} - -static void free_packet(void **obj) -{ - AVPacket *pkt = *obj; - av_packet_free(&pkt); - *obj = NULL; -} -static void free_frame(void **obj) -{ - AVFrame *frame = *obj; - av_frame_free(&frame); - *obj = NULL; -} - -ObjPool *objpool_alloc_packets(void) -{ - return objpool_alloc(alloc_packet, reset_packet, free_packet); -} -ObjPool *objpool_alloc_frames(void) -{ - return objpool_alloc(alloc_frame, reset_frame, free_frame); -} diff --git a/fftools/opt_common.c b/fftools/opt_common.c index 021ed7527..2c1f95655 100644 --- a/fftools/opt_common.c +++ b/fftools/opt_common.c @@ -23,6 +23,7 @@ #include #include "cmdutils.h" +#include "fopen_utf8.h" #include "opt_common.h" #include "libavutil/avassert.h" @@ -60,8 +61,6 @@ #include "libswresample/swresample.h" #include "libswresample/version.h" -#include "libpostproc/postprocess.h" -#include "libpostproc/version.h" enum show_muxdemuxers { SHOW_DEFAULT, @@ -191,7 +190,6 @@ static void print_all_libs_info(int flags, int level) PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); PRINT_LIB_INFO(swscale, SWSCALE, flags, level); PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level); - PRINT_LIB_INFO(postproc, POSTPROC, flags, level); } static void print_program_info(int flags, int level) @@ -808,11 +806,11 @@ int show_filters(void *optctx, const char *opt, const char *arg) printf("Filters:\n" " T.. = Timeline support\n" " .S. = Slice threading\n" - " ..C = Command support\n" " A = Audio input/output\n" " V = Video input/output\n" " N = Dynamic number and/or type of input/output\n" - " | = Source or sink filter\n"); + " | = Source or sink filter\n" + " ------\n"); while ((filter = av_filter_iterate(&opaque))) { descr_cur = descr; for (i = 0; i < 2; i++) { @@ -833,10 +831,9 @@ int show_filters(void *optctx, const char *opt, const char *arg) ( i && (filter->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS))) ? 'N' : '|'; } *descr_cur = 0; - printf(" %c%c%c %-17s %-10s %s\n", + printf(" %c%c %-17s %-10s %s\n", filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE ? 'T' : '.', filter->flags & AVFILTER_FLAG_SLICE_THREADS ? 'S' : '.', - filter->process_command ? 'C' : '.', filter->name, descr, filter->description); } #else @@ -995,7 +992,7 @@ int show_pix_fmts(void *optctx, const char *opt, const char *arg) #endif while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) { - enum AVPixelFormat av_unused pix_fmt = av_pix_fmt_desc_get_id(pix_desc); + av_unused enum AVPixelFormat pix_fmt = av_pix_fmt_desc_get_id(pix_desc); printf("%c%c%c%c%c %-16s %d %3d %d", sws_isSupportedInput (pix_fmt) ? 'I' : '.', sws_isSupportedOutput(pix_fmt) ? 'O' : '.', @@ -1209,7 +1206,7 @@ int init_report(const char *env, FILE **file) if (!envlevel) report_file_level = FFMAX(report_file_level, prog_loglevel); - report_file = fopen(filename.str, "w"); + report_file = fopen_utf8(filename.str, "w"); if (!report_file) { int ret = AVERROR(errno); av_log(NULL, AV_LOG_ERROR, "Failed to open report \"%s\": %s\n", @@ -1294,6 +1291,18 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg) } else { flags |= AV_LOG_PRINT_LEVEL; } + } else if (av_strstart(token, "time", &arg)) { + if (cmd == '-') { + flags &= ~AV_LOG_PRINT_TIME; + } else { + flags |= AV_LOG_PRINT_TIME; + } + } else if (av_strstart(token, "datetime", &arg)) { + if (cmd == '-') { + flags &= ~AV_LOG_PRINT_DATETIME; + } else { + flags |= AV_LOG_PRINT_DATETIME; + } } else { break; } @@ -1320,6 +1329,11 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg) "Possible levels are numbers or:\n", arg); for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) av_log(NULL, AV_LOG_FATAL, "\"%s\"\n", log_levels[i].name); + av_log(NULL, AV_LOG_FATAL, "Possible flags are:\n"); + av_log(NULL, AV_LOG_FATAL, "\"repeat\"\n"); + av_log(NULL, AV_LOG_FATAL, "\"level\"\n"); + av_log(NULL, AV_LOG_FATAL, "\"time\"\n"); + av_log(NULL, AV_LOG_FATAL, "\"datetime\"\n"); return AVERROR(EINVAL); } diff --git a/fftools/opt_common.h b/fftools/opt_common.h index 9bb526847..32d53b59b 100644 --- a/fftools/opt_common.h +++ b/fftools/opt_common.h @@ -41,9 +41,9 @@ int show_sources(void *optctx, const char *opt, const char *arg); #if CONFIG_AVDEVICE #define CMDUTILS_COMMON_OPTIONS_AVDEVICE \ - { "sources" , OPT_TYPE_FUNC, OPT_EXIT | OPT_FUNC_ARG | OPT_EXPERT, { .func_arg = show_sources }, \ + { "sources" , OPT_TYPE_FUNC, OPT_EXIT | OPT_EXPERT, { .func_arg = show_sources }, \ "list sources of the input device", "device" }, \ - { "sinks" , OPT_TYPE_FUNC, OPT_EXIT | OPT_FUNC_ARG | OPT_EXPERT, { .func_arg = show_sinks }, \ + { "sinks" , OPT_TYPE_FUNC, OPT_EXIT | OPT_EXPERT, { .func_arg = show_sinks }, \ "list sinks of the output device", "device" }, \ #else @@ -198,6 +198,7 @@ int opt_cpucount(void *optctx, const char *opt, const char *arg); #define CMDUTILS_COMMON_OPTIONS \ { "L", OPT_TYPE_FUNC, OPT_EXIT, { .func_arg = show_license }, "show license" }, \ + { "license", OPT_TYPE_FUNC, OPT_EXIT, { .func_arg = show_license }, "show license" }, \ { "h", OPT_TYPE_FUNC, OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \ { "?", OPT_TYPE_FUNC, OPT_EXIT | OPT_EXPERT, { .func_arg = show_help }, "show help", "topic" }, \ { "help", OPT_TYPE_FUNC, OPT_EXIT | OPT_EXPERT, { .func_arg = show_help }, "show help", "topic" }, \ diff --git a/fftools/resources/Makefile b/fftools/resources/Makefile new file mode 100644 index 000000000..3c936484d --- /dev/null +++ b/fftools/resources/Makefile @@ -0,0 +1,19 @@ +clean:: + $(RM) $(CLEANSUFFIXES:%=fftools/resources/%) + +vpath %.html $(SRC_PATH) +vpath %.css $(SRC_PATH) + +OBJS-resman += \ + fftools/resources/resman.o \ + + +RESOBJS += \ + fftools/resources/graph.html.o \ + fftools/resources/graph.css.o \ + + +$(RESOBJS): CCDEP = +$(RESOBJS): CC_DEPFLAGS = + +.SECONDARY: $(RESOBJS:.o=.gz) $(RESOBJS:.o=.c) $(RESOBJS:%.css.o=%.css.min) $(RESOBJS:%.css.o=%.css.min.gz) $(RESOBJS:%.html.o=%.html.gz) $(RESOBJS:.o=) diff --git a/fftools/resources/graph.css b/fftools/resources/graph.css new file mode 100644 index 000000000..ab480673a --- /dev/null +++ b/fftools/resources/graph.css @@ -0,0 +1,353 @@ +/* Variables */ +.root { + --ff-colvideo: #6eaa7b; + --ff-colaudio: #477fb3; + --ff-colsubtitle: #ad76ab; + --ff-coltext: #666; +} + +/* Common & Misc */ +.ff-inputfiles rect, .ff-outputfiles rect, .ff-inputstreams rect, .ff-outputstreams rect, .ff-decoders rect, .ff-encoders rect { + stroke-width: 0; + stroke: transparent; + filter: none !important; + fill: transparent !important; + display: none !important; +} + +.cluster span { + color: var(--ff-coltext); +} + +.cluster rect { + stroke: #dfdfdf !important; + transform: translateY(-2.3rem); + filter: drop-shadow(1px 2px 2px rgba(185,185,185,0.2)) !important; + rx: 8; + ry: 8; +} + +.cluster-label { + font-size: 1.1rem; +} + + .cluster-label .nodeLabel { + display: block; + font-weight: 500; + color: var(--ff-coltext); + } + + .cluster-label div { + max-width: unset !important; + padding: 3px; + } + + .cluster-label foreignObject { + transform: translateY(-0.7rem); + } + +/* Input and output files */ +.node.ff-inputfile .label foreignObject, .node.ff-outputfile .label foreignObject { + overflow: visible; +} + +.cluster.ff-inputfile .cluster-label foreignObject div:not(foreignObject div div), .cluster.ff-outputfile .cluster-label foreignObject div:not(foreignObject div div) { + display: table !important; +} + +.nodeLabel div.ff-inputfile, .nodeLabel div.ff-outputfile { + font-size: 1.1rem; + font-weight: 500; + min-width: 14rem; + width: 100%; + display: flex; + color: var(--ff-coltext); + margin-top: 0.1rem; + line-height: 1.35; + padding-bottom: 1.9rem; +} + +.nodeLabel div.ff-outputfile { + flex-direction: row-reverse; +} + +.ff-inputfile .index, .ff-outputfile .index { + order: 2; + color: var(--ff-coltext); + text-align: center; + border-radius: 0.45rem; + border: 0.18em solid #666666db; + font-weight: 600; + padding: 0 0.3em; + opacity: 0.8; +} + + .ff-inputfile .index::before { + content: 'In '; + } + + .ff-outputfile .index::before { + content: 'Out '; + } + +.ff-inputfile .demuxer_name, .ff-outputfile .muxer_name { + flex: 1; + order: 1; + font-size: 0.9rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + text-align: center; + max-width: 8rem; + align-content: center; + margin: 0.2rem 0.4rem 0 0.4rem; +} + +.ff-inputfile .file_extension, .ff-outputfile .file_extension { + order: 0; + background-color: #888; + color: white; + text-align: center; + border-radius: 0.45rem; + font-weight: 600; + padding: 0 0.4em; + align-content: center; + opacity: 0.8; +} + +.ff-inputfile .url, .ff-outputfile .url { + order: 4; + text-align: center; + position: absolute; + left: 0; + right: 0; + bottom: 0.75rem; + font-size: 0.7rem; + font-weight: 400; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin: 0 0.3rem; + direction: rtl; + color: #999; +} + +.cluster.ff-inputfile rect, .cluster.ff-outputfile rect { + transform: translateY(-1.8rem); + fill: url(#ff-radgradient); +} + +/* Input and output streams */ +.node.ff-inputstream rect, .node.ff-outputstream rect { + padding: 0 !important; + margin: 0 !important; + border: none !important; + fill: white; + stroke: #e5e5e5 !important; + height: 2.7rem; + transform: translateY(0.2rem); + filter: none; + rx: 3; + ry: 3; +} + +.node.ff-inputstream .label foreignObject, .node.ff-outputstream .label foreignObject { + transform: translateY(-0.2%); + overflow: visible; +} + + .node.ff-inputstream .label foreignObject div:not(foreignObject div div), .node.ff-outputstream .label foreignObject div:not(foreignObject div div) { + display: block !important; + line-height: 1.5 !important; + } + +.nodeLabel div.ff-inputstream, .nodeLabel div.ff-outputstream { + font-size: 1.0rem; + font-weight: 500; + min-width: 12rem; + width: 100%; + display: flex; +} + +.nodeLabel div.ff-outputstream { + flex-direction: row-reverse; +} + +.ff-inputstream .name, .ff-outputstream .name { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + text-align: left; + align-content: center; + margin-bottom: -0.15rem; +} + +.ff-inputstream .index, .ff-outputstream .index { + flex: 0 0 1.4rem; + background-color: #888; + color: white; + text-align: center; + border-radius: 0.3rem; + font-weight: 600; + margin-right: -0.3rem; + margin-left: 0.4rem; + opacity: 0.8; +} + +.ff-outputstream .index { + margin-right: 0.6rem; + margin-left: -0.4rem; +} + +.ff-inputstream::before, .ff-outputstream::before { + font-variant-emoji: text; + flex: 0 0 2rem; + margin-left: -0.8rem; + margin-right: 0.2rem; +} + +.ff-outputstream::before { + margin-left: 0.2rem; + margin-right: -0.6rem; +} + +.ff-inputstream.video::before, .ff-outputstream.video::before { + content: '\239A'; + color: var(--ff-colvideo); + font-size: 2.25rem; + line-height: 0.5; + font-weight: bold; +} + +.ff-inputstream.audio::before, .ff-outputstream.audio::before { + content: '\1F39D'; + color: var(--ff-colaudio); + font-size: 1.75rem; + line-height: 0.9; +} + +.ff-inputstream.subtitle::before, .ff-outputstream.subtitle::before { + content: '\1AC'; + color: var(--ff-colsubtitle); + font-size: 1.2rem; + line-height: 1.1; + transform: scaleX(1.5); + margin-top: 0.050rem; +} + +.ff-inputstream.attachment::before, .ff-outputstream.attachment::before { + content: '\1F4CE'; + font-size: 1.3rem; + line-height: 1.15; +} + +.ff-inputstream.data::before, .ff-outputstream.data::before { + content: '\27E8\2219\2219\2219\27E9'; + font-size: 1.15rem; + line-height: 1.17; + letter-spacing: -0.3px; +} + +/* Filter Graphs */ +.cluster.ff-filters rect { + stroke-dasharray: 6 !important; + stroke-width: 1.3px; + stroke: #d1d1d1 !important; + filter: none !important; +} + +.cluster.ff-filters div.ff-filters .id { + display: none; +} + +.cluster.ff-filters div.ff-filters .name { + margin-right: 0.5rem; + font-size: 0.9rem; +} + +.cluster.ff-filters div.ff-filters .description { + font-weight: 400; + font-size: 0.75rem; + vertical-align: middle; + color: #777; + font-family: Cascadia Code, Lucida Console, monospace; +} + +/* Filter Shapes */ +.node.ff-filter rect { + rx: 10; + ry: 10; + stroke-width: 1px; + stroke: #d3d3d3; + fill: url(#ff-filtergradient); + filter: drop-shadow(1px 1px 2px rgba(0, 0, 0, 0.1)); +} + +.node.ff-filter .label foreignObject { + transform: translateY(-0.4rem); + overflow: visible; +} + +.nodeLabel div.ff-filter { + font-size: 1.0rem; + font-weight: 500; + text-transform: uppercase; + min-width: 5.5rem; + margin-bottom: 0.5rem; +} + + .nodeLabel div.ff-filter span { + color: inherit; + } + +/* Decoders & Encoders */ +.node.ff-decoder rect, .node.ff-encoder rect { + stroke-width: 1px; + stroke: #d3d3d3; + fill: url(#ff-filtergradient); + filter: drop-shadow(1px 1px 2px rgba(0, 0, 0, 0.1)); +} + +.nodeLabel div.ff-decoder, .nodeLabel div.ff-encoder { + font-size: 0.85rem; + font-weight: 500; + min-width: 3.5rem; +} + +/* Links and Arrows */ +path.flowchart-link[id|='video'] { + stroke: var(--ff-colvideo); +} + +path.flowchart-link[id|='audio'] { + stroke: var(--ff-colaudio); +} + +path.flowchart-link[id|='subtitle'] { + stroke: var(--ff-colsubtitle); +} + +marker.marker path { + fill: context-stroke; +} + +.edgeLabel foreignObject { + transform: translateY(-1rem); +} + +.edgeLabel p { + background: transparent; + white-space: nowrap; + margin: 1rem 0.5rem !important; + font-weight: 500; + color: var(--ff-coltext); +} + +.edgeLabel, .labelBkg { + background: transparent; +} + +.edgeLabels .edgeLabel * { + font-size: 0.8rem; +} diff --git a/fftools/resources/graph.html b/fftools/resources/graph.html new file mode 100644 index 000000000..8906f939a --- /dev/null +++ b/fftools/resources/graph.html @@ -0,0 +1,86 @@ + + + + + FFmpeg Graph + + + + +
+__###__
+
+ + + diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c new file mode 100644 index 000000000..aa53e96bf --- /dev/null +++ b/fftools/resources/resman.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2025 - softworkz + * + * 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 + * output writers for filtergraph details + */ + +#include "config.h" + +#include + +#if CONFIG_RESOURCE_COMPRESSION +#include +#endif + +#include "resman.h" +#include "libavutil/avassert.h" +#include "libavutil/pixdesc.h" +#include "libavutil/dict.h" +#include "libavutil/common.h" + +extern const unsigned char ff_graph_html_data[]; +extern const unsigned int ff_graph_html_len; + +extern const unsigned char ff_graph_css_data[]; +extern const unsigned ff_graph_css_len; + +static const FFResourceDefinition resource_definitions[] = { + [FF_RESOURCE_GRAPH_CSS] = { FF_RESOURCE_GRAPH_CSS, "graph.css", &ff_graph_css_data[0], &ff_graph_css_len }, + [FF_RESOURCE_GRAPH_HTML] = { FF_RESOURCE_GRAPH_HTML, "graph.html", &ff_graph_html_data[0], &ff_graph_html_len }, +}; + + +static const AVClass resman_class = { + .class_name = "ResourceManager", +}; + +typedef struct ResourceManagerContext { + const AVClass *class; + AVDictionary *resource_dic; +} ResourceManagerContext; + +static AVMutex mutex = AV_MUTEX_INITIALIZER; + +static ResourceManagerContext resman_ctx = { .class = &resman_class }; + + +#if CONFIG_RESOURCE_COMPRESSION + +static int decompress_gzip(ResourceManagerContext *ctx, uint8_t *in, unsigned in_len, char **out, size_t *out_len) +{ + z_stream strm; + unsigned chunk = 65534; + int ret; + uint8_t *buf; + + *out = NULL; + memset(&strm, 0, sizeof(strm)); + + // Allocate output buffer with extra byte for null termination + buf = (uint8_t *)av_mallocz(chunk + 1); + if (!buf) { + av_log(ctx, AV_LOG_ERROR, "Failed to allocate decompression buffer\n"); + return AVERROR(ENOMEM); + } + + // 15 + 16 tells zlib to detect GZIP or zlib automatically + ret = inflateInit2(&strm, 15 + 16); + if (ret != Z_OK) { + av_log(ctx, AV_LOG_ERROR, "Error during zlib initialization: %s\n", strm.msg); + av_free(buf); + return AVERROR(ENOSYS); + } + + strm.avail_in = in_len; + strm.next_in = in; + strm.avail_out = chunk; + strm.next_out = buf; + + ret = inflate(&strm, Z_FINISH); + if (ret != Z_OK && ret != Z_STREAM_END) { + av_log(ctx, AV_LOG_ERROR, "Inflate failed: %d, %s\n", ret, strm.msg); + inflateEnd(&strm); + av_free(buf); + return (ret == Z_STREAM_END) ? Z_OK : ((ret == Z_OK) ? Z_BUF_ERROR : ret); + } + + if (strm.avail_out == 0) { + // TODO: Error or loop decoding? + av_log(ctx, AV_LOG_WARNING, "Decompression buffer may be too small\n"); + } + + *out_len = chunk - strm.avail_out; + buf[*out_len] = 0; // Ensure null termination + + inflateEnd(&strm); + *out = (char *)buf; + return Z_OK; +} +#endif + +void ff_resman_uninit(void) +{ + ff_mutex_lock(&mutex); + + av_dict_free(&resman_ctx.resource_dic); + + ff_mutex_unlock(&mutex); +} + + +char *ff_resman_get_string(FFResourceId resource_id) +{ + ResourceManagerContext *ctx = &resman_ctx; + FFResourceDefinition resource_definition = { 0 }; + AVDictionaryEntry *dic_entry; + char *res = NULL; + + for (unsigned i = 0; i < FF_ARRAY_ELEMS(resource_definitions); ++i) { + FFResourceDefinition def = resource_definitions[i]; + if (def.resource_id == resource_id) { + resource_definition = def; + break; + } + } + + av_assert1(resource_definition.name); + + ff_mutex_lock(&mutex); + + dic_entry = av_dict_get(ctx->resource_dic, resource_definition.name, NULL, 0); + + if (!dic_entry) { + int dict_ret; + +#if CONFIG_RESOURCE_COMPRESSION + + char *out = NULL; + size_t out_len; + + int ret = decompress_gzip(ctx, (uint8_t *)resource_definition.data, *resource_definition.data_len, &out, &out_len); + + if (ret) { + av_log(ctx, AV_LOG_ERROR, "Unable to decompress the resource with ID %d\n", resource_id); + goto end; + } + + dict_ret = av_dict_set(&ctx->resource_dic, resource_definition.name, out, 0); + if (dict_ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to store decompressed resource in dictionary: %d\n", dict_ret); + av_freep(&out); + goto end; + } + + av_freep(&out); +#else + + dict_ret = av_dict_set(&ctx->resource_dic, resource_definition.name, (const char *)resource_definition.data, 0); + if (dict_ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to store resource in dictionary: %d\n", dict_ret); + goto end; + } + +#endif + dic_entry = av_dict_get(ctx->resource_dic, resource_definition.name, NULL, 0); + + if (!dic_entry) { + av_log(ctx, AV_LOG_ERROR, "Failed to retrieve resource from dictionary after storing it\n"); + goto end; + } + } + + res = dic_entry->value; + +end: + ff_mutex_unlock(&mutex); + return res; +} diff --git a/libpostproc/version.c b/fftools/resources/resman.h similarity index 55% rename from libpostproc/version.c rename to fftools/resources/resman.h index 304abe08e..6485db509 100644 --- a/libpostproc/version.c +++ b/fftools/resources/resman.h @@ -1,5 +1,5 @@ /* - * Version functions. + * Copyright (c) 2025 - softworkz * * This file is part of FFmpeg. * @@ -18,28 +18,33 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#ifndef FFTOOLS_RESOURCES_RESMAN_H +#define FFTOOLS_RESOURCES_RESMAN_H + +#include #include "config.h" -#include "postprocess.h" -#include "version.h" +#include "fftools/ffmpeg.h" +#include "libavutil/avutil.h" +#include "libavutil/bprint.h" +#include "fftools/textformat/avtextformat.h" -#include "libavutil/ffversion.h" -const char postproc_ffversion[] = "FFmpeg version " FFMPEG_VERSION; +typedef enum { + FF_RESOURCE_GRAPH_CSS, + FF_RESOURCE_GRAPH_HTML, +} FFResourceId; -unsigned postproc_version(void) -{ - static_assert(LIBPOSTPROC_VERSION_MICRO >= 100, "micro version starts at 100"); - return LIBPOSTPROC_VERSION_INT; -} +typedef struct FFResourceDefinition { + FFResourceId resource_id; + const char *name; -const char *postproc_configuration(void) -{ - return FFMPEG_CONFIGURATION; -} + const unsigned char *data; + const unsigned *data_len; -const char *postproc_license(void) -{ -#define LICENSE_PREFIX "libpostproc license: " - return &LICENSE_PREFIX FFMPEG_LICENSE[sizeof(LICENSE_PREFIX) - 1]; -} +} FFResourceDefinition; + +void ff_resman_uninit(void); + +char *ff_resman_get_string(FFResourceId resource_id); + +#endif /* FFTOOLS_RESOURCES_RESMAN_H */ diff --git a/fftools/sync_queue.c b/fftools/sync_queue.c index 0e35b5b1c..fbf288c6d 100644 --- a/fftools/sync_queue.c +++ b/fftools/sync_queue.c @@ -20,16 +20,15 @@ #include #include "libavutil/avassert.h" +#include "libavutil/container_fifo.h" #include "libavutil/channel_layout.h" #include "libavutil/cpu.h" #include "libavutil/error.h" -#include "libavutil/fifo.h" #include "libavutil/mathematics.h" #include "libavutil/mem.h" #include "libavutil/samplefmt.h" #include "libavutil/timestamp.h" -#include "objpool.h" #include "sync_queue.h" /* @@ -67,8 +66,11 @@ * frame from stream 1, and all 4 frames from stream 2. */ +#define SQPTR(sq, frame) ((sq->type == SYNC_QUEUE_FRAMES) ? \ + (void*)frame.f : (void*)frame.p) + typedef struct SyncQueueStream { - AVFifo *fifo; + AVContainerFifo *fifo; AVRational tb; /* number of audio samples in fifo */ @@ -104,23 +106,11 @@ struct SyncQueue { SyncQueueStream *streams; unsigned int nb_streams; - // pool of preallocated frames to avoid constant allocations - ObjPool *pool; - int have_limiting; uintptr_t align_mask; }; -static void frame_move(const SyncQueue *sq, SyncQueueFrame dst, - SyncQueueFrame src) -{ - if (sq->type == SYNC_QUEUE_PACKETS) - av_packet_move_ref(dst.p, src.p); - else - av_frame_move_ref(dst.f, src.f); -} - /** * Compute the end timestamp of a frame. If nb_samples is provided, consider * the frame to have this number of audio samples, otherwise use frame duration. @@ -160,7 +150,7 @@ static void tb_update(const SyncQueue *sq, SyncQueueStream *st, return; // timebase should not change after the first frame - av_assert0(!av_fifo_can_read(st->fifo)); + av_assert0(!av_container_fifo_can_read(st->fifo)); if (st->head_ts != AV_NOPTS_VALUE) st->head_ts = av_rescale_q(st->head_ts, st->tb, tb); @@ -308,7 +298,7 @@ static int overflow_heartbeat(SyncQueue *sq, int stream_idx) /* get the chosen stream's tail timestamp */ for (size_t i = 0; tail_ts == AV_NOPTS_VALUE && - av_fifo_peek(st->fifo, &frame, 1, i) >= 0; i++) + av_container_fifo_peek(st->fifo, (void**)&frame, i) >= 0; i++) tail_ts = frame_end(sq, frame, 0); /* overflow triggers when the tail is over specified duration behind the head */ @@ -343,7 +333,6 @@ static int overflow_heartbeat(SyncQueue *sq, int stream_idx) int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame) { SyncQueueStream *st; - SyncQueueFrame dst; int64_t ts; int ret, nb_samples; @@ -360,31 +349,22 @@ int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame) tb_update(sq, st, frame); - ret = objpool_get(sq->pool, (void**)&dst); - if (ret < 0) - return ret; - - frame_move(sq, dst, frame); - - nb_samples = frame_samples(sq, dst); + nb_samples = frame_samples(sq, frame); // make sure frame duration is consistent with sample count if (nb_samples) { - av_assert0(dst.f->sample_rate > 0); - dst.f->duration = av_rescale_q(nb_samples, (AVRational){ 1, dst.f->sample_rate }, - dst.f->time_base); + av_assert0(frame.f->sample_rate > 0); + frame.f->duration = av_rescale_q(nb_samples, (AVRational){ 1, frame.f->sample_rate }, + frame.f->time_base); } - ts = frame_end(sq, dst, 0); + ts = frame_end(sq, frame, 0); av_log(sq->logctx, AV_LOG_DEBUG, "sq: send %u ts %s\n", stream_idx, av_ts2timestr(ts, &st->tb)); - ret = av_fifo_write(st->fifo, &dst, 1); - if (ret < 0) { - frame_move(sq, frame, dst); - objpool_release(sq->pool, (void**)&dst); + ret = av_container_fifo_write(st->fifo, SQPTR(sq, frame), 0); + if (ret < 0) return ret; - } stream_update_ts(sq, stream_idx, ts); @@ -453,7 +433,7 @@ static int receive_samples(SyncQueue *sq, SyncQueueStream *st, av_assert0(st->samples_queued >= nb_samples); - ret = av_fifo_peek(st->fifo, &src, 1, 0); + ret = av_container_fifo_peek(st->fifo, (void**)&src, 0); av_assert0(ret >= 0); // peeked frame has enough samples and its data is aligned @@ -490,7 +470,7 @@ static int receive_samples(SyncQueue *sq, SyncQueueStream *st, while (dst->nb_samples < nb_samples) { int to_copy; - ret = av_fifo_peek(st->fifo, &src, 1, 0); + ret = av_container_fifo_peek(st->fifo, (void**)&src, 0); av_assert0(ret >= 0); to_copy = FFMIN(nb_samples - dst->nb_samples, src.f->nb_samples); @@ -500,11 +480,9 @@ static int receive_samples(SyncQueue *sq, SyncQueueStream *st, if (to_copy < src.f->nb_samples) offset_audio(src.f, to_copy); - else { - av_frame_unref(src.f); - objpool_release(sq->pool, (void**)&src); - av_fifo_drain2(st->fifo, 1); - } + else + av_container_fifo_drain(st->fifo, 1); + st->samples_queued -= to_copy; dst->nb_samples += to_copy; @@ -531,7 +509,7 @@ static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx, av_assert0(stream_idx < sq->nb_streams); st = &sq->streams[stream_idx]; - if (av_fifo_can_read(st->fifo) && + if (av_container_fifo_can_read(st->fifo) && (st->frame_samples <= st->samples_queued || st->finished)) { int nb_samples = st->frame_samples; SyncQueueFrame peek; @@ -541,7 +519,7 @@ static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx, if (st->finished) nb_samples = FFMIN(nb_samples, st->samples_queued); - av_fifo_peek(st->fifo, &peek, 1, 0); + av_container_fifo_peek(st->fifo, (void**)&peek, 0); ts = frame_end(sq, peek, nb_samples); /* check if this stream's tail timestamp does not overtake @@ -560,9 +538,9 @@ static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx, if (ret < 0) return ret; } else { - frame_move(sq, frame, peek); - objpool_release(sq->pool, (void**)&peek); - av_fifo_drain2(st->fifo, 1); + int ret = av_container_fifo_read(st->fifo, SQPTR(sq, frame), 0); + av_assert0(ret >= 0); + av_assert0(st->samples_queued >= frame_samples(sq, frame)); st->samples_queued -= frame_samples(sq, frame); } @@ -577,7 +555,7 @@ static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx, } } - return (sq->finished || (st->finished && !av_fifo_can_read(st->fifo))) ? + return (sq->finished || (st->finished && !av_container_fifo_can_read(st->fifo))) ? AVERROR_EOF : AVERROR(EAGAIN); } @@ -629,7 +607,8 @@ int sq_add_stream(SyncQueue *sq, int limiting) st = &sq->streams[sq->nb_streams]; memset(st, 0, sizeof(*st)); - st->fifo = av_fifo_alloc2(1, sizeof(SyncQueueFrame), AV_FIFO_FLAG_AUTO_GROW); + st->fifo = (sq->type == SYNC_QUEUE_FRAMES) ? + av_container_fifo_alloc_avframe(0) : av_container_fifo_alloc_avpacket(0); if (!st->fifo) return AVERROR(ENOMEM); @@ -686,13 +665,6 @@ SyncQueue *sq_alloc(enum SyncQueueType type, int64_t buf_size_us, void *logctx) sq->head_stream = -1; sq->head_finished_stream = -1; - sq->pool = (type == SYNC_QUEUE_PACKETS) ? objpool_alloc_packets() : - objpool_alloc_frames(); - if (!sq->pool) { - av_freep(&sq); - return NULL; - } - return sq; } @@ -703,17 +675,10 @@ void sq_free(SyncQueue **psq) if (!sq) return; - for (unsigned int i = 0; i < sq->nb_streams; i++) { - SyncQueueFrame frame; - while (av_fifo_read(sq->streams[i].fifo, &frame, 1) >= 0) - objpool_release(sq->pool, (void**)&frame); - - av_fifo_freep2(&sq->streams[i].fifo); - } + for (unsigned int i = 0; i < sq->nb_streams; i++) + av_container_fifo_free(&sq->streams[i].fifo); av_freep(&sq->streams); - objpool_free(&sq->pool); - av_freep(psq); } diff --git a/fftools/textformat/avtextformat.c b/fftools/textformat/avtextformat.c new file mode 100644 index 000000000..47ef6e518 --- /dev/null +++ b/fftools/textformat/avtextformat.c @@ -0,0 +1,694 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 +#include +#include + +#include "libavutil/mem.h" +#include "libavutil/avassert.h" +#include "libavutil/base64.h" +#include "libavutil/bprint.h" +#include "libavutil/error.h" +#include "libavutil/hash.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/macros.h" +#include "libavutil/opt.h" +#include "avtextformat.h" + +#define SECTION_ID_NONE (-1) + +#define SHOW_OPTIONAL_FIELDS_AUTO (-1) +#define SHOW_OPTIONAL_FIELDS_NEVER 0 +#define SHOW_OPTIONAL_FIELDS_ALWAYS 1 + +static const struct { + double bin_val; + double dec_val; + char bin_str[4]; + char dec_str[4]; +} si_prefixes[] = { + { 1.0, 1.0, "", "" }, + { 1.024e3, 1e3, "Ki", "K" }, + { 1.048576e6, 1e6, "Mi", "M" }, + { 1.073741824e9, 1e9, "Gi", "G" }, + { 1.099511627776e12, 1e12, "Ti", "T" }, + { 1.125899906842624e15, 1e15, "Pi", "P" }, +}; + +static const char *textcontext_get_formatter_name(void *p) +{ + AVTextFormatContext *tctx = p; + return tctx->formatter->name; +} + +#define OFFSET(x) offsetof(AVTextFormatContext, x) + +static const AVOption textcontext_options[] = { + { "string_validation", "set string validation mode", + OFFSET(string_validation), AV_OPT_TYPE_INT, { .i64 = AV_TEXTFORMAT_STRING_VALIDATION_REPLACE }, 0, AV_TEXTFORMAT_STRING_VALIDATION_NB - 1, .unit = "sv" }, + { "sv", "set string validation mode", + OFFSET(string_validation), AV_OPT_TYPE_INT, { .i64 = AV_TEXTFORMAT_STRING_VALIDATION_REPLACE }, 0, AV_TEXTFORMAT_STRING_VALIDATION_NB - 1, .unit = "sv" }, + { "ignore", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_TEXTFORMAT_STRING_VALIDATION_IGNORE }, .unit = "sv" }, + { "replace", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_TEXTFORMAT_STRING_VALIDATION_REPLACE }, .unit = "sv" }, + { "fail", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_TEXTFORMAT_STRING_VALIDATION_FAIL }, .unit = "sv" }, + { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, { .str = "" } }, + { "svr", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, { .str = "\xEF\xBF\xBD" } }, + { NULL } +}; + +static void *textcontext_child_next(void *obj, void *prev) +{ + AVTextFormatContext *ctx = obj; + if (!prev && ctx->formatter && ctx->formatter->priv_class && ctx->priv) + return ctx->priv; + return NULL; +} + +static const AVClass textcontext_class = { + .class_name = "AVTextContext", + .item_name = textcontext_get_formatter_name, + .option = textcontext_options, + .version = LIBAVUTIL_VERSION_INT, + .child_next = textcontext_child_next, +}; + +static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size) +{ + av_bprintf(bp, "0X"); + for (unsigned i = 0; i < ubuf_size; i++) + av_bprintf(bp, "%02X", ubuf[i]); +} + +int avtext_context_close(AVTextFormatContext **ptctx) +{ + AVTextFormatContext *tctx = *ptctx; + int ret = 0; + + if (!tctx) + return AVERROR(EINVAL); + + av_hash_freep(&tctx->hash); + + if (tctx->formatter) { + if (tctx->formatter->uninit) + ret = tctx->formatter->uninit(tctx); + if (tctx->formatter->priv_class) + av_opt_free(tctx->priv); + } + for (int i = 0; i < SECTION_MAX_NB_LEVELS; i++) + av_bprint_finalize(&tctx->section_pbuf[i], NULL); + av_freep(&tctx->priv); + av_opt_free(tctx); + av_freep(ptctx); + return ret; +} + + +int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *formatter, AVTextWriterContext *writer_context, const char *args, + const AVTextFormatSection *sections, int nb_sections, AVTextFormatOptions options, char *show_data_hash) +{ + AVTextFormatContext *tctx; + int ret = 0; + + av_assert0(ptctx && formatter); + + if (!(tctx = av_mallocz(sizeof(AVTextFormatContext)))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + for (int i = 0; i < SECTION_MAX_NB_LEVELS; i++) + av_bprint_init(&tctx->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED); + + tctx->class = &textcontext_class; + av_opt_set_defaults(tctx); + + if (!(tctx->priv = av_mallocz(formatter->priv_size))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + tctx->opts = options; + + if (nb_sections > SECTION_MAX_NB_SECTIONS) { + av_log(tctx, AV_LOG_ERROR, "The number of section definitions (%d) is larger than the maximum allowed (%d)\n", nb_sections, SECTION_MAX_NB_SECTIONS); + ret = AVERROR(EINVAL); + goto fail; + } + + tctx->formatter = formatter; + tctx->level = -1; + tctx->sections = sections; + tctx->nb_sections = nb_sections; + tctx->writer = writer_context; + + if (formatter->priv_class) { + void *priv_ctx = tctx->priv; + *(const AVClass **)priv_ctx = formatter->priv_class; + av_opt_set_defaults(priv_ctx); + } + + /* convert options to dictionary */ + if (args) { + AVDictionary *opts = NULL; + const AVDictionaryEntry *opt = NULL; + + if ((ret = av_dict_parse_string(&opts, args, "=", ":", 0)) < 0) { + av_log(tctx, AV_LOG_ERROR, "Failed to parse option string '%s' provided to textformat context\n", args); + av_dict_free(&opts); + goto fail; + } + + while ((opt = av_dict_iterate(opts, opt))) { + if ((ret = av_opt_set(tctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) { + av_log(tctx, AV_LOG_ERROR, "Failed to set option '%s' with value '%s' provided to textformat context\n", + opt->key, opt->value); + av_dict_free(&opts); + goto fail; + } + } + + av_dict_free(&opts); + } + + if (show_data_hash) { + if ((ret = av_hash_alloc(&tctx->hash, show_data_hash)) < 0) { + if (ret == AVERROR(EINVAL)) { + const char *n; + av_log(NULL, AV_LOG_ERROR, "Unknown hash algorithm '%s'\nKnown algorithms:", show_data_hash); + for (unsigned i = 0; (n = av_hash_names(i)); i++) + av_log(NULL, AV_LOG_ERROR, " %s", n); + av_log(NULL, AV_LOG_ERROR, "\n"); + } + goto fail; + } + } + + /* validate replace string */ + { + const uint8_t *p = (uint8_t *)tctx->string_validation_replacement; + const uint8_t *endp = p + strlen((const char *)p); + while (*p) { + const uint8_t *p0 = p; + int32_t code; + ret = av_utf8_decode(&code, &p, endp, tctx->string_validation_utf8_flags); + if (ret < 0) { + AVBPrint bp; + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); + bprint_bytes(&bp, p0, p - p0); + av_log(tctx, AV_LOG_ERROR, + "Invalid UTF8 sequence %s found in string validation replace '%s'\n", + bp.str, tctx->string_validation_replacement); + goto fail; + } + } + } + + if (tctx->formatter->init) + ret = tctx->formatter->init(tctx); + if (ret < 0) + goto fail; + + *ptctx = tctx; + + return 0; + +fail: + avtext_context_close(&tctx); + return ret; +} + +/* Temporary definitions during refactoring */ +static const char unit_second_str[] = "s"; +static const char unit_hertz_str[] = "Hz"; +static const char unit_byte_str[] = "byte"; +static const char unit_bit_per_second_str[] = "bit/s"; + + +void avtext_print_section_header(AVTextFormatContext *tctx, const void *data, int section_id) +{ + if (section_id < 0 || section_id >= tctx->nb_sections) { + av_log(tctx, AV_LOG_ERROR, "Invalid section_id for section_header: %d\n", section_id); + return; + } + + tctx->level++; + av_assert0(tctx->level < SECTION_MAX_NB_LEVELS); + + tctx->nb_item[tctx->level] = 0; + memset(tctx->nb_item_type[tctx->level], 0, sizeof(tctx->nb_item_type[tctx->level])); + tctx->section[tctx->level] = &tctx->sections[section_id]; + + if (tctx->formatter->print_section_header) + tctx->formatter->print_section_header(tctx, data); +} + +void avtext_print_section_footer(AVTextFormatContext *tctx) +{ + if (tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS) { + av_log(tctx, AV_LOG_ERROR, "Invalid level for section_footer: %d\n", tctx->level); + return; + } + + int section_id = tctx->section[tctx->level]->id; + int parent_section_id = tctx->level ? + tctx->section[tctx->level - 1]->id : SECTION_ID_NONE; + + if (parent_section_id != SECTION_ID_NONE) { + tctx->nb_item[tctx->level - 1]++; + tctx->nb_item_type[tctx->level - 1][section_id]++; + } + + if (tctx->formatter->print_section_footer) + tctx->formatter->print_section_footer(tctx); + tctx->level--; +} + +void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t val, int flags) +{ + av_assert0(tctx); + + if (tctx->opts.show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER) + return; + + if (tctx->opts.show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO + && (flags & AV_TEXTFORMAT_PRINT_STRING_OPTIONAL) + && !(tctx->formatter->flags & AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS)) + return; + + av_assert0(key && tctx->level >= 0 && tctx->level < SECTION_MAX_NB_LEVELS); + + if (!tctx->opts.is_key_selected || tctx->opts.is_key_selected(tctx, key)) { + tctx->formatter->print_integer(tctx, key, val); + tctx->nb_item[tctx->level]++; + } +} + +static inline int validate_string(AVTextFormatContext *tctx, char **dstp, const char *src) +{ + const uint8_t *p, *endp, *srcp = (const uint8_t *)src; + AVBPrint dstbuf; + AVBPrint invalid_seq; + int invalid_chars_nb = 0, ret = 0; + + *dstp = NULL; + av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED); + av_bprint_init(&invalid_seq, 0, AV_BPRINT_SIZE_UNLIMITED); + + endp = srcp + strlen(src); + for (p = srcp; *p;) { + int32_t code; + int invalid = 0; + const uint8_t *p0 = p; + + if (av_utf8_decode(&code, &p, endp, tctx->string_validation_utf8_flags) < 0) { + + av_bprint_clear(&invalid_seq); + + bprint_bytes(&invalid_seq, p0, p - p0); + + av_log(tctx, AV_LOG_DEBUG, "Invalid UTF-8 sequence '%s' found in string '%s'\n", invalid_seq.str, src); + invalid = 1; + } + + if (invalid) { + invalid_chars_nb++; + + switch (tctx->string_validation) { + case AV_TEXTFORMAT_STRING_VALIDATION_FAIL: + av_log(tctx, AV_LOG_ERROR, "Invalid UTF-8 sequence found in string '%s'\n", src); + ret = AVERROR_INVALIDDATA; + goto end; + + case AV_TEXTFORMAT_STRING_VALIDATION_REPLACE: + av_bprintf(&dstbuf, "%s", tctx->string_validation_replacement); + break; + } + } + + if (!invalid || tctx->string_validation == AV_TEXTFORMAT_STRING_VALIDATION_IGNORE) + av_bprint_append_data(&dstbuf, p0, p-p0); + } + + if (invalid_chars_nb && tctx->string_validation == AV_TEXTFORMAT_STRING_VALIDATION_REPLACE) + av_log(tctx, AV_LOG_WARNING, + "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n", + invalid_chars_nb, src, tctx->string_validation_replacement); + +end: + av_bprint_finalize(&dstbuf, dstp); + av_bprint_finalize(&invalid_seq, NULL); + return ret; +} + +struct unit_value { + union { + double d; + int64_t i; + } val; + + const char *unit; +}; + +static char *value_string(const AVTextFormatContext *tctx, char *buf, int buf_size, struct unit_value uv) +{ + double vald; + int64_t vali = 0; + int show_float = 0; + + if (uv.unit == unit_second_str) { + vald = uv.val.d; + show_float = 1; + } else { + vald = (double)uv.val.i; + vali = uv.val.i; + } + + if (uv.unit == unit_second_str && tctx->opts.use_value_sexagesimal_format) { + double secs; + int hours, mins; + secs = vald; + mins = (int)secs / 60; + secs = secs - mins * 60; + hours = mins / 60; + mins %= 60; + snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs); + } else { + const char *prefix_string = ""; + + if (tctx->opts.use_value_prefix && vald > 1) { + int64_t index; + + if (uv.unit == unit_byte_str && tctx->opts.use_byte_value_binary_prefix) { + index = (int64_t)(log2(vald) / 10); + index = av_clip64(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); + vald /= si_prefixes[index].bin_val; + prefix_string = si_prefixes[index].bin_str; + } else { + index = (int64_t)(log10(vald) / 3); + index = av_clip64(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); + vald /= si_prefixes[index].dec_val; + prefix_string = si_prefixes[index].dec_str; + } + vali = (int64_t)vald; + } + + if (show_float || (tctx->opts.use_value_prefix && vald != (int64_t)vald)) + snprintf(buf, buf_size, "%f", vald); + else + snprintf(buf, buf_size, "%"PRId64, vali); + + av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || tctx->opts.show_value_unit ? " " : "", + prefix_string, tctx->opts.show_value_unit ? uv.unit : ""); + } + + return buf; +} + + +void avtext_print_unit_integer(AVTextFormatContext *tctx, const char *key, int64_t val, const char *unit) +{ + char val_str[128]; + struct unit_value uv; + uv.val.i = val; + uv.unit = unit; + avtext_print_string(tctx, key, value_string(tctx, val_str, sizeof(val_str), uv), 0); +} + + +int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *val, int flags) +{ + const AVTextFormatSection *section; + int ret = 0; + + av_assert0(key && val && tctx->level >= 0 && tctx->level < SECTION_MAX_NB_LEVELS); + + section = tctx->section[tctx->level]; + + if (tctx->opts.show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER) + return 0; + + if (tctx->opts.show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO + && (flags & AV_TEXTFORMAT_PRINT_STRING_OPTIONAL) + && !(tctx->formatter->flags & AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS)) + return 0; + + if (!tctx->opts.is_key_selected || tctx->opts.is_key_selected(tctx, key)) { + if (flags & AV_TEXTFORMAT_PRINT_STRING_VALIDATE) { + char *key1 = NULL, *val1 = NULL; + ret = validate_string(tctx, &key1, key); + if (ret < 0) goto end; + ret = validate_string(tctx, &val1, val); + if (ret < 0) goto end; + tctx->formatter->print_string(tctx, key1, val1); + end: + if (ret < 0) + av_log(tctx, AV_LOG_ERROR, + "Invalid key=value string combination %s=%s in section %s\n", + key, val, section->unique_name); + av_free(key1); + av_free(val1); + } else { + tctx->formatter->print_string(tctx, key, val); + } + + tctx->nb_item[tctx->level]++; + } + + return ret; +} + +void avtext_print_rational(AVTextFormatContext *tctx, const char *key, AVRational q, char sep) +{ + char buf[44]; + snprintf(buf, sizeof(buf), "%d%c%d", q.num, sep, q.den); + avtext_print_string(tctx, key, buf, 0); +} + +void avtext_print_time(AVTextFormatContext *tctx, const char *key, + int64_t ts, const AVRational *time_base, int is_duration) +{ + if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) { + avtext_print_string(tctx, key, "N/A", AV_TEXTFORMAT_PRINT_STRING_OPTIONAL); + } else { + char buf[128]; + double d = av_q2d(*time_base) * ts; + struct unit_value uv; + uv.val.d = d; + uv.unit = unit_second_str; + value_string(tctx, buf, sizeof(buf), uv); + avtext_print_string(tctx, key, buf, 0); + } +} + +void avtext_print_ts(AVTextFormatContext *tctx, const char *key, int64_t ts, int is_duration) +{ + if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) + avtext_print_string(tctx, key, "N/A", AV_TEXTFORMAT_PRINT_STRING_OPTIONAL); + else + avtext_print_integer(tctx, key, ts, 0); +} + +static void print_data_xxd(AVBPrint *bp, const uint8_t *data, int size) +{ + unsigned offset = 0; + int i; + + av_bprintf(bp, "\n"); + while (size) { + av_bprintf(bp, "%08x: ", offset); + int l = FFMIN(size, 16); + for (i = 0; i < l; i++) { + av_bprintf(bp, "%02x", data[i]); + if (i & 1) + av_bprintf(bp, " "); + } + av_bprint_chars(bp, ' ', 41 - 2 * i - i / 2); + for (i = 0; i < l; i++) + av_bprint_chars(bp, data[i] - 32U < 95 ? data[i] : '.', 1); + av_bprintf(bp, "\n"); + offset += l; + data += l; + size -= l; + } +} + +static void print_data_base64(AVBPrint *bp, const uint8_t *data, int size) +{ + char buf[AV_BASE64_SIZE(60)]; + + av_bprintf(bp, "\n"); + while (size) { + int l = FFMIN(size, 60); + av_base64_encode(buf, sizeof(buf), data, l); + av_bprintf(bp, "%s\n", buf); + data += l; + size -= l; + } +} +void avtext_print_data(AVTextFormatContext *tctx, const char *key, + const uint8_t *data, int size) +{ + AVBPrint bp; + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + switch (tctx->opts.data_dump_format) { + case AV_TEXTFORMAT_DATADUMP_XXD: + print_data_xxd(&bp, data, size); + break; + case AV_TEXTFORMAT_DATADUMP_BASE64: + print_data_base64(&bp, data, size); + break; + default: + av_unreachable("Invalid data dump type"); + } + avtext_print_string(tctx, key, bp.str, 0); + av_bprint_finalize(&bp, NULL); +} + +void avtext_print_data_hash(AVTextFormatContext *tctx, const char *key, + const uint8_t *data, int size) +{ + char buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 }; + int len; + + if (!tctx->hash) + return; + + av_hash_init(tctx->hash); + av_hash_update(tctx->hash, data, size); + len = snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(tctx->hash)); + av_hash_final_hex(tctx->hash, (uint8_t *)&buf[len], (int)sizeof(buf) - len); + avtext_print_string(tctx, key, buf, 0); +} + +static const char *writercontext_get_writer_name(void *p) +{ + AVTextWriterContext *wctx = p; + return wctx->writer->name; +} + +static void *writercontext_child_next(void *obj, void *prev) +{ + AVTextFormatContext *ctx = obj; + if (!prev && ctx->formatter && ctx->formatter->priv_class && ctx->priv) + return ctx->priv; + return NULL; +} + +static const AVClass textwriter_class = { + .class_name = "AVTextWriterContext", + .item_name = writercontext_get_writer_name, + .version = LIBAVUTIL_VERSION_INT, + .child_next = writercontext_child_next, +}; + + +int avtextwriter_context_close(AVTextWriterContext **pwctx) +{ + AVTextWriterContext *wctx = *pwctx; + int ret = 0; + + if (!wctx) + return AVERROR(EINVAL); + + if (wctx->writer) { + if (wctx->writer->uninit) + ret = wctx->writer->uninit(wctx); + if (wctx->writer->priv_class) + av_opt_free(wctx->priv); + } + av_freep(&wctx->priv); + av_freep(pwctx); + return ret; +} + + +int avtextwriter_context_open(AVTextWriterContext **pwctx, const AVTextWriter *writer) +{ + AVTextWriterContext *wctx; + int ret = 0; + + if (!pwctx || !writer) + return AVERROR(EINVAL); + + if (!((wctx = av_mallocz(sizeof(AVTextWriterContext))))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if (writer->priv_size && !((wctx->priv = av_mallocz(writer->priv_size)))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if (writer->priv_class) { + void *priv_ctx = wctx->priv; + *(const AVClass **)priv_ctx = writer->priv_class; + av_opt_set_defaults(priv_ctx); + } + + wctx->class = &textwriter_class; + wctx->writer = writer; + + av_opt_set_defaults(wctx); + + + if (wctx->writer->init) + ret = wctx->writer->init(wctx); + if (ret < 0) + goto fail; + + *pwctx = wctx; + + return 0; + +fail: + avtextwriter_context_close(&wctx); + return ret; +} + +static const AVTextFormatter *const registered_formatters[] = +{ + &avtextformatter_default, + &avtextformatter_compact, + &avtextformatter_csv, + &avtextformatter_flat, + &avtextformatter_ini, + &avtextformatter_json, + &avtextformatter_xml, + &avtextformatter_mermaid, + &avtextformatter_mermaidhtml, + NULL +}; + +const AVTextFormatter *avtext_get_formatter_by_name(const char *name) +{ + for (int i = 0; registered_formatters[i]; i++) { + const char *end; + if (av_strstart(name, registered_formatters[i]->name, &end) && + (*end == '\0' || *end == '=')) + return registered_formatters[i]; + } + + return NULL; +} diff --git a/fftools/textformat/avtextformat.h b/fftools/textformat/avtextformat.h new file mode 100644 index 000000000..edb292d42 --- /dev/null +++ b/fftools/textformat/avtextformat.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 FFTOOLS_TEXTFORMAT_AVTEXTFORMAT_H +#define FFTOOLS_TEXTFORMAT_AVTEXTFORMAT_H + +#include +#include "libavutil/dict.h" +#include "libavformat/avio.h" +#include "libavutil/bprint.h" +#include "libavutil/rational.h" +#include "libavutil/hash.h" +#include "avtextwriters.h" + +#define SECTION_MAX_NB_CHILDREN 11 + +typedef struct AVTextFormatSectionContext { + char *context_id; + const char *context_type; + int context_flags; +} AVTextFormatSectionContext; + + +typedef struct AVTextFormatSection { + int id; ///< unique id identifying a section + const char *name; + +#define AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level +#define AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type +#define AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys. + /// For these sections the element_name field is mandatory. +#define AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE 8 ///< the section contains a type to distinguish multiple nested elements +#define AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE 16 ///< the items in this array section should be numbered individually by type +#define AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE 32 ///< ... +#define AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS 64 ///< ... +#define AV_TEXTFORMAT_SECTION_PRINT_TAGS 128 ///< ... +#define AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH 256 ///< ... + + int flags; + const int children_ids[SECTION_MAX_NB_CHILDREN + 1]; ///< list of children section IDS, terminated by -1 + const char *element_name; ///< name of the contained element, if provided + const char *unique_name; ///< unique section name, in case the name is ambiguous + const char *(*get_type)(const void *data); ///< function returning a type if defined, must be defined when SECTION_FLAG_HAS_TYPE is defined + const char *id_key; ///< name of the key to be used as the id + const char *src_id_key; ///< name of the key to be used as the source id for diagram connections + const char *dest_id_key; ///< name of the key to be used as the target id for diagram connections + const char *linktype_key; ///< name of the key to be used as the link type for diagram connections (AVTextFormatLinkType) +} AVTextFormatSection; + +typedef struct AVTextFormatContext AVTextFormatContext; + +#define AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS 1 +#define AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT 2 +#define AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER 4 + +typedef enum { + AV_TEXTFORMAT_STRING_VALIDATION_FAIL, + AV_TEXTFORMAT_STRING_VALIDATION_REPLACE, + AV_TEXTFORMAT_STRING_VALIDATION_IGNORE, + AV_TEXTFORMAT_STRING_VALIDATION_NB +} StringValidation; + +typedef enum { + AV_TEXTFORMAT_LINKTYPE_SRCDEST, + AV_TEXTFORMAT_LINKTYPE_DESTSRC, + AV_TEXTFORMAT_LINKTYPE_BIDIR, + AV_TEXTFORMAT_LINKTYPE_NONDIR, + AV_TEXTFORMAT_LINKTYPE_HIDDEN, + AV_TEXTFORMAT_LINKTYPE_ONETOMANY = AV_TEXTFORMAT_LINKTYPE_SRCDEST, + AV_TEXTFORMAT_LINKTYPE_MANYTOONE = AV_TEXTFORMAT_LINKTYPE_DESTSRC, + AV_TEXTFORMAT_LINKTYPE_ONETOONE = AV_TEXTFORMAT_LINKTYPE_BIDIR, + AV_TEXTFORMAT_LINKTYPE_MANYTOMANY = AV_TEXTFORMAT_LINKTYPE_NONDIR, +} AVTextFormatLinkType; + +typedef enum { + AV_TEXTFORMAT_DATADUMP_XXD, + AV_TEXTFORMAT_DATADUMP_BASE64, +} AVTextFormatDataDump; + +typedef struct AVTextFormatter { + const AVClass *priv_class; ///< private class of the formatter, if any + int priv_size; ///< private size for the formatter context + const char *name; + + int (*init) (AVTextFormatContext *tctx); + int (*uninit)(AVTextFormatContext *tctx); + + void (*print_section_header)(AVTextFormatContext *tctx, const void *data); + void (*print_section_footer)(AVTextFormatContext *tctx); + void (*print_integer) (AVTextFormatContext *tctx, const char *, int64_t); + void (*print_string) (AVTextFormatContext *tctx, const char *, const char *); + int flags; ///< a combination or AV_TEXTFORMAT__FLAG_* +} AVTextFormatter; + +#define SECTION_MAX_NB_LEVELS 12 +#define SECTION_MAX_NB_SECTIONS 100 + +typedef struct AVTextFormatOptions { + /** + * Callback to discard certain elements based upon the key used. + * It is called before any element with a key is printed. + * If this callback is unset, all elements are printed. + * + * @retval 1 if the element is supposed to be printed + * @retval 0 if the element is supposed to be discarded + */ + int (*is_key_selected)(struct AVTextFormatContext *tctx, const char *key); + int show_optional_fields; + int show_value_unit; + int use_value_prefix; + int use_byte_value_binary_prefix; + int use_value_sexagesimal_format; + AVTextFormatDataDump data_dump_format; +} AVTextFormatOptions; + +struct AVTextFormatContext { + const AVClass *class; ///< class of the formatter + const AVTextFormatter *formatter; ///< the AVTextFormatter of which this is an instance + AVTextWriterContext *writer; ///< the AVTextWriterContext + + char *name; ///< name of this formatter instance + void *priv; ///< private data for use by the filter + + const AVTextFormatSection *sections; ///< array containing all sections + int nb_sections; ///< number of sections + + int level; ///< current level, starting from 0 + + /** number of the item printed in the given section, starting from 0 */ + unsigned int nb_item[SECTION_MAX_NB_LEVELS]; + unsigned int nb_item_type[SECTION_MAX_NB_LEVELS][SECTION_MAX_NB_SECTIONS]; + + /** section per each level */ + const AVTextFormatSection *section[SECTION_MAX_NB_LEVELS]; + AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section, + /// used by various formatters + + AVTextFormatOptions opts; + + struct AVHashContext *hash; + + int string_validation; + char *string_validation_replacement; + unsigned int string_validation_utf8_flags; +}; + +#define AV_TEXTFORMAT_PRINT_STRING_OPTIONAL 1 +#define AV_TEXTFORMAT_PRINT_STRING_VALIDATE 2 + +int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *formatter, AVTextWriterContext *writer_context, const char *args, + const AVTextFormatSection *sections, int nb_sections, AVTextFormatOptions options, char *show_data_hash); + +int avtext_context_close(AVTextFormatContext **tctx); + + +void avtext_print_section_header(AVTextFormatContext *tctx, const void *data, int section_id); + +void avtext_print_section_footer(AVTextFormatContext *tctx); + +void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t val, int flags); + +int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *val, int flags); + +void avtext_print_unit_integer(AVTextFormatContext *tctx, const char *key, int64_t val, const char *unit); + +void avtext_print_rational(AVTextFormatContext *tctx, const char *key, AVRational q, char sep); + +void avtext_print_time(AVTextFormatContext *tctx, const char *key, int64_t ts, const AVRational *time_base, int is_duration); + +void avtext_print_ts(AVTextFormatContext *tctx, const char *key, int64_t ts, int is_duration); + +void avtext_print_data(AVTextFormatContext *tctx, const char *key, const uint8_t *data, int size); + +void avtext_print_data_hash(AVTextFormatContext *tctx, const char *key, const uint8_t *data, int size); + +const AVTextFormatter *avtext_get_formatter_by_name(const char *name); + +extern const AVTextFormatter avtextformatter_default; +extern const AVTextFormatter avtextformatter_compact; +extern const AVTextFormatter avtextformatter_csv; +extern const AVTextFormatter avtextformatter_flat; +extern const AVTextFormatter avtextformatter_ini; +extern const AVTextFormatter avtextformatter_json; +extern const AVTextFormatter avtextformatter_xml; +extern const AVTextFormatter avtextformatter_mermaid; +extern const AVTextFormatter avtextformatter_mermaidhtml; + +#endif /* FFTOOLS_TEXTFORMAT_AVTEXTFORMAT_H */ diff --git a/fftools/textformat/avtextwriters.h b/fftools/textformat/avtextwriters.h new file mode 100644 index 000000000..8457d7a6e --- /dev/null +++ b/fftools/textformat/avtextwriters.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 FFTOOLS_TEXTFORMAT_AVTEXTWRITERS_H +#define FFTOOLS_TEXTFORMAT_AVTEXTWRITERS_H + +#include +#include "libavformat/avio.h" +#include "libavutil/bprint.h" + +typedef struct AVTextWriterContext AVTextWriterContext; + +typedef struct AVTextWriter { + const AVClass *priv_class; ///< private class of the writer, if any + int priv_size; ///< private size for the writer private class + const char *name; + + int (*init)(AVTextWriterContext *wctx); + int (*uninit)(AVTextWriterContext *wctx); + void (*writer_w8)(AVTextWriterContext *wctx, int b); + void (*writer_put_str)(AVTextWriterContext *wctx, const char *str); + void (*writer_vprintf)(AVTextWriterContext *wctx, const char *fmt, va_list vl); +} AVTextWriter; + +typedef struct AVTextWriterContext { + const AVClass *class; ///< class of the writer + const AVTextWriter *writer; + const char *name; + void *priv; ///< private data for use by the writer +} AVTextWriterContext; + + +int avtextwriter_context_open(AVTextWriterContext **pwctx, const AVTextWriter *writer); + +int avtextwriter_context_close(AVTextWriterContext **pwctx); + +int avtextwriter_create_stdout(AVTextWriterContext **pwctx); + +int avtextwriter_create_avio(AVTextWriterContext **pwctx, AVIOContext *avio_ctx, int close_on_uninit); + +int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_filename); + +int avtextwriter_create_buffer(AVTextWriterContext **pwctx, AVBPrint *buffer); + +#endif /* FFTOOLS_TEXTFORMAT_AVTEXTWRITERS_H */ diff --git a/fftools/textformat/tf_compact.c b/fftools/textformat/tf_compact.c new file mode 100644 index 000000000..c6311b5de --- /dev/null +++ b/fftools/textformat/tf_compact.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 +#include +#include + +#include "avtextformat.h" +#include "libavutil/bprint.h" +#include "libavutil/error.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + + +/* Compact output */ + +/** + * Apply C-language-like string escaping. + */ +static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) +{ + const char *p; + + for (p = src; *p; p++) { + switch (*p) { + case '\b': av_bprintf(dst, "%s", "\\b"); break; + case '\f': av_bprintf(dst, "%s", "\\f"); break; + case '\n': av_bprintf(dst, "%s", "\\n"); break; + case '\r': av_bprintf(dst, "%s", "\\r"); break; + case '\\': av_bprintf(dst, "%s", "\\\\"); break; + default: + if (*p == sep) + av_bprint_chars(dst, '\\', 1); + av_bprint_chars(dst, *p, 1); + } + } + return dst->str; +} + +/** + * Quote fields containing special characters, check RFC4180. + */ +static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) +{ + char meta_chars[] = { sep, '"', '\n', '\r', '\0' }; + + int needs_quoting = !!src[strcspn(src, meta_chars)]; + + if (needs_quoting) + av_bprint_chars(dst, '"', 1); + + for (; *src; src++) { + if (*src == '"') + av_bprint_chars(dst, '"', 1); + av_bprint_chars(dst, *src, 1); + } + if (needs_quoting) + av_bprint_chars(dst, '"', 1); + return dst->str; +} + +static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) +{ + return src; +} + +typedef struct CompactContext { + const AVClass *class; + char *item_sep_str; + char item_sep; + int nokey; + int print_section; + char *escape_mode_str; + const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx); + int nested_section[SECTION_MAX_NB_LEVELS]; + int has_nested_elems[SECTION_MAX_NB_LEVELS]; + int terminate_line[SECTION_MAX_NB_LEVELS]; +} CompactContext; + +#undef OFFSET +#define OFFSET(x) offsetof(CompactContext, x) + +static const AVOption compact_options[] = { + { "item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, { .str = "|" }, 0, 0 }, + { "s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, { .str = "|" }, 0, 0 }, + { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, { .str = "c" }, 0, 0 }, + { "e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, { .str = "c" }, 0, 0 }, + { "print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(compact); + +static av_cold int compact_init(AVTextFormatContext *wctx) +{ + CompactContext *compact = wctx->priv; + + if (strlen(compact->item_sep_str) != 1) { + av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n", + compact->item_sep_str); + return AVERROR(EINVAL); + } + compact->item_sep = compact->item_sep_str[0]; + + if (!strcmp(compact->escape_mode_str, "none")) { + compact->escape_str = none_escape_str; + } else if (!strcmp(compact->escape_mode_str, "c" )) { + compact->escape_str = c_escape_str; + } else if (!strcmp(compact->escape_mode_str, "csv" )) { + compact->escape_str = csv_escape_str; + } else { + av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str); + return AVERROR(EINVAL); + } + + return 0; +} + +static void compact_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + CompactContext *compact = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + + if (!section) + return; + + compact->terminate_line[wctx->level] = 1; + compact->has_nested_elems[wctx->level] = 0; + + av_bprint_clear(&wctx->section_pbuf[wctx->level]); + if (parent_section && + (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE || + (!(section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) && + !(parent_section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))))) { + + /* define a prefix for elements not contained in an array or + in a wrapper, or for array elements with a type */ + const char *element_name = (char *)av_x_if_null(section->element_name, section->name); + AVBPrint *section_pbuf = &wctx->section_pbuf[wctx->level]; + + compact->nested_section[wctx->level] = 1; + compact->has_nested_elems[wctx->level - 1] = 1; + + av_bprintf(section_pbuf, "%s%s", + wctx->section_pbuf[wctx->level - 1].str, element_name); + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE) { + // add /TYPE to prefix + av_bprint_chars(section_pbuf, '/', 1); + + // normalize section type, replace special characters and lower case + for (const char *p = section->get_type(data); *p; p++) { + char c = + (*p >= '0' && *p <= '9') || + (*p >= 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z') ? av_tolower(*p) : '_'; + av_bprint_chars(section_pbuf, c, 1); + } + } + av_bprint_chars(section_pbuf, ':', 1); + + wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level - 1]; + } else { + if (parent_section && !(parent_section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY)) && + wctx->level && wctx->nb_item[wctx->level - 1]) + writer_w8(wctx, compact->item_sep); + if (compact->print_section && + !(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))) + writer_printf(wctx, "%s%c", section->name, compact->item_sep); + } +} + +static void compact_print_section_footer(AVTextFormatContext *wctx) +{ + CompactContext *compact = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + + if (!section) + return; + + if (!compact->nested_section[wctx->level] && + compact->terminate_line[wctx->level] && + !(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))) + writer_w8(wctx, '\n'); +} + +static void compact_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + CompactContext *compact = wctx->priv; + AVBPrint buf; + + if (wctx->nb_item[wctx->level]) + writer_w8(wctx, compact->item_sep); + + if (!compact->nokey) + writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); + + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + writer_put_str(wctx, compact->escape_str(&buf, value, compact->item_sep, wctx)); + av_bprint_finalize(&buf, NULL); +} + +static void compact_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + CompactContext *compact = wctx->priv; + + if (wctx->nb_item[wctx->level]) + writer_w8(wctx, compact->item_sep); + + if (!compact->nokey) + writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); + + writer_printf(wctx, "%"PRId64, value); +} + +const AVTextFormatter avtextformatter_compact = { + .name = "compact", + .priv_size = sizeof(CompactContext), + .init = compact_init, + .print_section_header = compact_print_section_header, + .print_section_footer = compact_print_section_footer, + .print_integer = compact_print_int, + .print_string = compact_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS, + .priv_class = &compact_class, +}; + +/* CSV output */ + +#undef OFFSET +#define OFFSET(x) offsetof(CompactContext, x) + +static const AVOption csv_options[] = { + { "item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, { .str = "," }, 0, 0 }, + { "s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, { .str = "," }, 0, 0 }, + { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, { .str = "csv" }, 0, 0 }, + { "e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, { .str = "csv" }, 0, 0 }, + { "print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(csv); + +const AVTextFormatter avtextformatter_csv = { + .name = "csv", + .priv_size = sizeof(CompactContext), + .init = compact_init, + .print_section_header = compact_print_section_header, + .print_section_footer = compact_print_section_footer, + .print_integer = compact_print_int, + .print_string = compact_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS, + .priv_class = &csv_class, +}; diff --git a/fftools/textformat/tf_default.c b/fftools/textformat/tf_default.c new file mode 100644 index 000000000..019bda9d4 --- /dev/null +++ b/fftools/textformat/tf_default.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 +#include +#include + +#include "avtextformat.h" +#include "libavutil/bprint.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + +/* Default output */ + +typedef struct DefaultContext { + const AVClass *class; + int nokey; + int noprint_wrappers; + int nested_section[SECTION_MAX_NB_LEVELS]; +} DefaultContext; + +#undef OFFSET +#define OFFSET(x) offsetof(DefaultContext, x) + +static const AVOption default_options[] = { + { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "nw", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(default); + +/* lame uppercasing routine, assumes the string is lower case ASCII */ +static inline char *upcase_string(char *dst, size_t dst_size, const char *src) +{ + unsigned i; + + for (i = 0; src[i] && i < dst_size - 1; i++) + dst[i] = (char)av_toupper(src[i]); + dst[i] = 0; + return dst; +} + +static void default_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + DefaultContext *def = wctx->priv; + char buf[32]; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + + if (!section) + return; + + av_bprint_clear(&wctx->section_pbuf[wctx->level]); + if (parent_section && + !(parent_section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))) { + def->nested_section[wctx->level] = 1; + av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:", + wctx->section_pbuf[wctx->level - 1].str, + upcase_string(buf, sizeof(buf), + av_x_if_null(section->element_name, section->name))); + } + + if (def->noprint_wrappers || def->nested_section[wctx->level]) + return; + + if (!(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))) + writer_printf(wctx, "[%s]\n", upcase_string(buf, sizeof(buf), section->name)); +} + +static void default_print_section_footer(AVTextFormatContext *wctx) +{ + DefaultContext *def = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + + char buf[32]; + + if (!section) + return; + + if (def->noprint_wrappers || def->nested_section[wctx->level]) + return; + + if (!(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))) + writer_printf(wctx, "[/%s]\n", upcase_string(buf, sizeof(buf), section->name)); +} + +static void default_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + DefaultContext *def = wctx->priv; + + if (!def->nokey) + writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); + writer_printf(wctx, "%s\n", value); +} + +static void default_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + DefaultContext *def = wctx->priv; + + if (!def->nokey) + writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); + writer_printf(wctx, "%"PRId64"\n", value); +} + +const AVTextFormatter avtextformatter_default = { + .name = "default", + .priv_size = sizeof(DefaultContext), + .print_section_header = default_print_section_header, + .print_section_footer = default_print_section_footer, + .print_integer = default_print_int, + .print_string = default_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS, + .priv_class = &default_class, +}; diff --git a/fftools/textformat/tf_flat.c b/fftools/textformat/tf_flat.c new file mode 100644 index 000000000..d5517f109 --- /dev/null +++ b/fftools/textformat/tf_flat.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 +#include +#include + +#include "avtextformat.h" +#include "libavutil/bprint.h" +#include "libavutil/error.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + +/* Flat output */ + +typedef struct FlatContext { + const AVClass *class; + const char *sep_str; + char sep; + int hierarchical; +} FlatContext; + +#undef OFFSET +#define OFFSET(x) offsetof(FlatContext, x) + +static const AVOption flat_options[] = { + { "sep_char", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, { .str = "." }, 0, 0 }, + { "s", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, { .str = "." }, 0, 0 }, + { "hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(flat); + +static av_cold int flat_init(AVTextFormatContext *wctx) +{ + FlatContext *flat = wctx->priv; + + if (strlen(flat->sep_str) != 1) { + av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n", + flat->sep_str); + return AVERROR(EINVAL); + } + flat->sep = flat->sep_str[0]; + + return 0; +} + +static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep) +{ + const char *p; + + for (p = src; *p; p++) { + if (!((*p >= '0' && *p <= '9') || + (*p >= 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z'))) + av_bprint_chars(dst, '_', 1); + else + av_bprint_chars(dst, *p, 1); + } + return dst->str; +} + +static const char *flat_escape_value_str(AVBPrint *dst, const char *src) +{ + const char *p; + + for (p = src; *p; p++) { + switch (*p) { + case '\n': av_bprintf(dst, "%s", "\\n"); break; + case '\r': av_bprintf(dst, "%s", "\\r"); break; + case '\\': av_bprintf(dst, "%s", "\\\\"); break; + case '"': av_bprintf(dst, "%s", "\\\""); break; + case '`': av_bprintf(dst, "%s", "\\`"); break; + case '$': av_bprintf(dst, "%s", "\\$"); break; + default: av_bprint_chars(dst, *p, 1); break; + } + } + return dst->str; +} + +static void flat_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + FlatContext *flat = wctx->priv; + AVBPrint *buf = &wctx->section_pbuf[wctx->level]; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + + if (!section) + return; + + /* build section header */ + av_bprint_clear(buf); + if (!parent_section) + return; + + av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level - 1].str); + + if (flat->hierarchical || + !(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER))) { + av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str); + + if (parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) { + int n = parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE + ? wctx->nb_item_type[wctx->level - 1][section->id] + : wctx->nb_item[wctx->level - 1]; + + av_bprintf(buf, "%d%s", n, flat->sep_str); + } + } +} + +static void flat_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + writer_printf(wctx, "%s%s=%"PRId64"\n", wctx->section_pbuf[wctx->level].str, key, value); +} + +static void flat_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + FlatContext *flat = wctx->priv; + AVBPrint buf; + + writer_put_str(wctx, wctx->section_pbuf[wctx->level].str); + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + writer_printf(wctx, "%s=", flat_escape_key_str(&buf, key, flat->sep)); + av_bprint_clear(&buf); + writer_printf(wctx, "\"%s\"\n", flat_escape_value_str(&buf, value)); + av_bprint_finalize(&buf, NULL); +} + +const AVTextFormatter avtextformatter_flat = { + .name = "flat", + .priv_size = sizeof(FlatContext), + .init = flat_init, + .print_section_header = flat_print_section_header, + .print_integer = flat_print_int, + .print_string = flat_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS | AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT, + .priv_class = &flat_class, +}; diff --git a/fftools/textformat/tf_ini.c b/fftools/textformat/tf_ini.c new file mode 100644 index 000000000..895978529 --- /dev/null +++ b/fftools/textformat/tf_ini.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 +#include +#include + +#include "avtextformat.h" + +#include "libavutil/bprint.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + +/* Default output */ + +typedef struct DefaultContext { + const AVClass *class; + int nokey; + int noprint_wrappers; + int nested_section[SECTION_MAX_NB_LEVELS]; +} DefaultContext; + +/* INI format output */ + +typedef struct INIContext { + const AVClass *class; + int hierarchical; +} INIContext; + +#undef OFFSET +#define OFFSET(x) offsetof(INIContext, x) + +static const AVOption ini_options[] = { + { "hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(ini); + +static char *ini_escape_str(AVBPrint *dst, const char *src) +{ + int i = 0; + char c; + + while ((c = src[i++])) { + switch (c) { + case '\b': av_bprintf(dst, "%s", "\\b"); break; + case '\f': av_bprintf(dst, "%s", "\\f"); break; + case '\n': av_bprintf(dst, "%s", "\\n"); break; + case '\r': av_bprintf(dst, "%s", "\\r"); break; + case '\t': av_bprintf(dst, "%s", "\\t"); break; + case '\\': + case '#': + case '=': + case ':': + av_bprint_chars(dst, '\\', 1); + /* fallthrough */ + default: + if ((unsigned char)c < 32) + av_bprintf(dst, "\\x00%02x", (unsigned char)c); + else + av_bprint_chars(dst, c, 1); + break; + } + } + return dst->str; +} + +static void ini_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + INIContext *ini = wctx->priv; + AVBPrint *buf = &wctx->section_pbuf[wctx->level]; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + + if (!section) + return; + + av_bprint_clear(buf); + if (!parent_section) { + writer_put_str(wctx, "# ffprobe output\n\n"); + return; + } + + if (wctx->nb_item[wctx->level - 1]) + writer_w8(wctx, '\n'); + + av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level - 1].str); + if (ini->hierarchical || + !(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER))) { + av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name); + + if (parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) { + unsigned n = parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE + ? wctx->nb_item_type[wctx->level - 1][section->id] + : wctx->nb_item[wctx->level - 1]; + av_bprintf(buf, ".%u", n); + } + } + + if (!(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER))) + writer_printf(wctx, "[%s]\n", buf->str); +} + +static void ini_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + AVBPrint buf; + + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + writer_printf(wctx, "%s=", ini_escape_str(&buf, key)); + av_bprint_clear(&buf); + writer_printf(wctx, "%s\n", ini_escape_str(&buf, value)); + av_bprint_finalize(&buf, NULL); +} + +static void ini_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + writer_printf(wctx, "%s=%"PRId64"\n", key, value); +} + +const AVTextFormatter avtextformatter_ini = { + .name = "ini", + .priv_size = sizeof(INIContext), + .print_section_header = ini_print_section_header, + .print_integer = ini_print_int, + .print_string = ini_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS | AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT, + .priv_class = &ini_class, +}; diff --git a/fftools/textformat/tf_internal.h b/fftools/textformat/tf_internal.h new file mode 100644 index 000000000..484886b7a --- /dev/null +++ b/fftools/textformat/tf_internal.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 + * Internal utilities for text formatters. + */ + +#ifndef FFTOOLS_TEXTFORMAT_TF_INTERNAL_H +#define FFTOOLS_TEXTFORMAT_TF_INTERNAL_H + +#include "avtextformat.h" + +#define DEFINE_FORMATTER_CLASS(name) \ +static const AVClass name##_class = { \ + .class_name = #name, \ + .item_name = av_default_item_name, \ + .option = name##_options \ +} + + +/** + * Safely validate and access a section at a given level + */ +static inline const AVTextFormatSection *tf_get_section(AVTextFormatContext *tfc, int level) +{ + if (!tfc || level < 0 || level >= SECTION_MAX_NB_LEVELS || !tfc->section[level]) { + if (tfc) + av_log(tfc, AV_LOG_ERROR, "Invalid section access at level %d\n", level); + return NULL; + } + return tfc->section[level]; +} + +/** + * Safely access the parent section + */ +static inline const AVTextFormatSection *tf_get_parent_section(AVTextFormatContext *tfc, int level) +{ + if (level <= 0) + return NULL; + + return tf_get_section(tfc, level - 1); +} + +static inline void writer_w8(AVTextFormatContext *wctx, int b) +{ + wctx->writer->writer->writer_w8(wctx->writer, b); +} + +static inline void writer_put_str(AVTextFormatContext *wctx, const char *str) +{ + wctx->writer->writer->writer_put_str(wctx->writer, str); +} + +static inline void writer_printf(AVTextFormatContext *wctx, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + wctx->writer->writer->writer_vprintf(wctx->writer, fmt, args); + va_end(args); +} + +#endif /* FFTOOLS_TEXTFORMAT_TF_INTERNAL_H */ diff --git a/fftools/textformat/tf_json.c b/fftools/textformat/tf_json.c new file mode 100644 index 000000000..78ea5dc21 --- /dev/null +++ b/fftools/textformat/tf_json.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 +#include +#include + +#include "avtextformat.h" +#include "libavutil/bprint.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + +/* JSON output */ + +typedef struct JSONContext { + const AVClass *class; + int indent_level; + int compact; + const char *item_sep, *item_start_end; +} JSONContext; + +#undef OFFSET +#define OFFSET(x) offsetof(JSONContext, x) + +static const AVOption json_options[] = { + { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { NULL } +}; + +DEFINE_FORMATTER_CLASS(json); + +static av_cold int json_init(AVTextFormatContext *wctx) +{ + JSONContext *json = wctx->priv; + + json->item_sep = json->compact ? ", " : ",\n"; + json->item_start_end = json->compact ? " " : "\n"; + + return 0; +} + +static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx) +{ + static const char json_escape[] = { '"', '\\', '\b', '\f', '\n', '\r', '\t', 0 }; + static const char json_subst[] = { '"', '\\', 'b', 'f', 'n', 'r', 't', 0 }; + const char *p; + + if (!src) { + av_log(log_ctx, AV_LOG_WARNING, "Cannot escape NULL string, returning NULL\n"); + return NULL; + } + + for (p = src; *p; p++) { + char *s = strchr(json_escape, *p); + if (s) { + av_bprint_chars(dst, '\\', 1); + av_bprint_chars(dst, json_subst[s - json_escape], 1); + } else if ((unsigned char)*p < 32) { + av_bprintf(dst, "\\u00%02x", (unsigned char)*p); + } else { + av_bprint_chars(dst, *p, 1); + } + } + return dst->str; +} + +#define JSON_INDENT() writer_printf(wctx, "%*c", json->indent_level * 4, ' ') + +static void json_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + JSONContext *json = wctx->priv; + AVBPrint buf; + + if (!section) + return; + + if (wctx->level && wctx->nb_item[wctx->level - 1]) + writer_put_str(wctx, ",\n"); + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER) { + writer_put_str(wctx, "{\n"); + json->indent_level++; + } else { + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + json_escape_str(&buf, section->name, wctx); + JSON_INDENT(); + + json->indent_level++; + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) { + writer_printf(wctx, "\"%s\": [\n", buf.str); + } else if (parent_section && !(parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY)) { + writer_printf(wctx, "\"%s\": {%s", buf.str, json->item_start_end); + } else { + writer_printf(wctx, "{%s", json->item_start_end); + + /* this is required so the parser can distinguish between packets and frames */ + if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE) { + if (!json->compact) + JSON_INDENT(); + writer_printf(wctx, "\"type\": \"%s\"", section->name); + wctx->nb_item[wctx->level]++; + } + } + av_bprint_finalize(&buf, NULL); + } +} + +static void json_print_section_footer(AVTextFormatContext *wctx) +{ + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + JSONContext *json = wctx->priv; + + if (!section) + return; + + if (wctx->level == 0) { + json->indent_level--; + writer_put_str(wctx, "\n}\n"); + } else if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) { + writer_w8(wctx, '\n'); + json->indent_level--; + JSON_INDENT(); + writer_w8(wctx, ']'); + } else { + writer_put_str(wctx, json->item_start_end); + json->indent_level--; + if (!json->compact) + JSON_INDENT(); + writer_w8(wctx, '}'); + } +} + +static inline void json_print_item_str(AVTextFormatContext *wctx, + const char *key, const char *value) +{ + AVBPrint buf; + + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + writer_printf(wctx, "\"%s\":", json_escape_str(&buf, key, wctx)); + av_bprint_clear(&buf); + writer_printf(wctx, " \"%s\"", json_escape_str(&buf, value, wctx)); + av_bprint_finalize(&buf, NULL); +} + +static void json_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + JSONContext *json = wctx->priv; + + if (!section) + return; + + if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE)) + writer_put_str(wctx, json->item_sep); + if (!json->compact) + JSON_INDENT(); + json_print_item_str(wctx, key, value); +} + +static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + JSONContext *json = wctx->priv; + AVBPrint buf; + + if (!section) + return; + + if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE)) + writer_put_str(wctx, json->item_sep); + if (!json->compact) + JSON_INDENT(); + + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + writer_printf(wctx, "\"%s\": %"PRId64, json_escape_str(&buf, key, wctx), value); + av_bprint_finalize(&buf, NULL); +} + +const AVTextFormatter avtextformatter_json = { + .name = "json", + .priv_size = sizeof(JSONContext), + .init = json_init, + .print_section_header = json_print_section_header, + .print_section_footer = json_print_section_footer, + .print_integer = json_print_int, + .print_string = json_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT, + .priv_class = &json_class, +}; diff --git a/fftools/textformat/tf_mermaid.c b/fftools/textformat/tf_mermaid.c new file mode 100644 index 000000000..fae53d9c4 --- /dev/null +++ b/fftools/textformat/tf_mermaid.c @@ -0,0 +1,676 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 +#include +#include + +#include "avtextformat.h" +#include "tf_internal.h" +#include "tf_mermaid.h" +#include "libavutil/bprint.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" + + +static const char *init_directive = "" + "%%{init: {" + "\"theme\": \"base\"," + "\"curve\": \"monotoneX\"," + "\"rankSpacing\": 10," + "\"nodeSpacing\": 10," + "\"themeCSS\": \"__###__\"," + "\"fontFamily\": \"Roboto,Segoe UI,sans-serif\"," + "\"themeVariables\": { " + "\"clusterBkg\": \"white\", " + "\"primaryBorderColor\": \"gray\", " + "\"lineColor\": \"gray\", " + "\"secondaryTextColor\": \"gray\", " + "\"tertiaryBorderColor\": \"gray\", " + "\"primaryTextColor\": \"#666\", " + "\"secondaryTextColor\": \"red\" " + "}," + "\"flowchart\": { " + "\"subGraphTitleMargin\": { \"top\": -15, \"bottom\": 20 }, " + "\"diagramPadding\": 20, " + "\"curve\": \"monotoneX\" " + "}" + " }}%%\n\n"; + +static const char* init_directive_er = "" + "%%{init: {" + "\"theme\": \"base\"," + "\"layout\": \"elk\"," + "\"curve\": \"monotoneX\"," + "\"rankSpacing\": 65," + "\"nodeSpacing\": 60," + "\"themeCSS\": \"__###__\"," + "\"fontFamily\": \"Roboto,Segoe UI,sans-serif\"," + "\"themeVariables\": { " + "\"clusterBkg\": \"white\", " + "\"primaryBorderColor\": \"gray\", " + "\"lineColor\": \"gray\", " + "\"secondaryTextColor\": \"gray\", " + "\"tertiaryBorderColor\": \"gray\", " + "\"primaryTextColor\": \"#666\", " + "\"secondaryTextColor\": \"red\" " + "}," + "\"er\": { " + "\"diagramPadding\": 12, " + "\"entityPadding\": 4, " + "\"minEntityWidth\": 150, " + "\"minEntityHeight\": 20, " + "\"curve\": \"monotoneX\" " + "}" + " }}%%\n\n"; + +static const char *theme_css_er = "" + + // Variables + ".root { " + "--ff-colvideo: #6eaa7b; " + "--ff-colaudio: #477fb3; " + "--ff-colsubtitle: #ad76ab; " + "--ff-coltext: #666; " + "} " + " g.nodes g.node.default rect.basic.label-container, " + " g.nodes g.node.default path { " + " rx: 1; " + " ry: 1; " + " stroke-width: 1px !important; " + " stroke: #e9e9e9 !important; " + " fill: url(#ff-filtergradient) !important; " + " filter: drop-shadow(0px 0px 5.5px rgba(0, 0, 0, 0.05)); " + " fill: white !important; " + " } " + " " + " .relationshipLine { " + " stroke: gray; " + " stroke-width: 1; " + " fill: none; " + " filter: drop-shadow(0px 0px 3px rgba(0, 0, 0, 0.2)); " + " } " + " " + " g.node.default g.label.name foreignObject > div > span > p, " + " g.nodes g.node.default g.label:not(.attribute-name, .attribute-keys, .attribute-type, .attribute-comment) foreignObject > div > span > p { " + " font-size: 0.95rem; " + " font-weight: 500; " + " text-transform: uppercase; " + " min-width: 5.5rem; " + " margin-bottom: 0.5rem; " + " " + " } " + " " + " .edgePaths path { " + " marker-end: none; " + " marker-start: none; " + " " + "} "; + + +/* Mermaid Graph output */ + +typedef struct MermaidContext { + const AVClass *class; + AVDiagramConfig *diagram_config; + int subgraph_count; + int within_tag; + int indent_level; + int create_html; + + // Options + int enable_link_colors; // Requires Mermaid 11.5 + + struct section_data { + const char *section_id; + const char *section_type; + const char *src_id; + const char *dest_id; + AVTextFormatLinkType link_type; + int current_is_textblock; + int current_is_stadium; + int subgraph_start_incomplete; + } section_data[SECTION_MAX_NB_LEVELS]; + + unsigned nb_link_captions[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section, + AVBPrint link_buf; ///< print buffer for writing diagram links + AVDictionary *link_dict; +} MermaidContext; + +#undef OFFSET +#define OFFSET(x) offsetof(MermaidContext, x) + +static const AVOption mermaid_options[] = { + { "link_coloring", "enable colored links (requires Mermaid >= 11.5)", OFFSET(enable_link_colors), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + ////{"diagram_css", "CSS for the diagram", OFFSET(diagram_css), AV_OPT_TYPE_STRING, {.i64=0}, 0, 1 }, + ////{"html_template", "Template HTML", OFFSET(html_template), AV_OPT_TYPE_STRING, {.i64=0}, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(mermaid); + +void av_diagram_init(AVTextFormatContext *tfc, AVDiagramConfig *diagram_config) +{ + MermaidContext *mmc = tfc->priv; + mmc->diagram_config = diagram_config; +} + +static av_cold int has_link_pair(const AVTextFormatContext *tfc, const char *src, const char *dest) +{ + MermaidContext *mmc = tfc->priv; + AVBPrint buf; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + av_bprintf(&buf, "%s--%s", src, dest); + + if (mmc->link_dict && av_dict_get(mmc->link_dict, buf.str, NULL, 0)) + return 1; + + av_dict_set(&mmc->link_dict, buf.str, buf.str, 0); + + return 0; +} + +static av_cold int mermaid_init(AVTextFormatContext *tfc) +{ + MermaidContext *mmc = tfc->priv; + + av_bprint_init(&mmc->link_buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + ////mmc->enable_link_colors = 1; // Requires Mermaid 11.5 + return 0; +} + +static av_cold int mermaid_init_html(AVTextFormatContext *tfc) +{ + MermaidContext *mmc = tfc->priv; + + int ret = mermaid_init(tfc); + + if (ret < 0) + return ret; + + mmc->create_html = 1; + + return 0; +} + +static av_cold int mermaid_uninit(AVTextFormatContext *tfc) +{ + MermaidContext *mmc = tfc->priv; + + av_bprint_finalize(&mmc->link_buf, NULL); + av_dict_free(&mmc->link_dict); + + for (unsigned i = 0; i < SECTION_MAX_NB_LEVELS; i++) { + av_freep(&mmc->section_data[i].dest_id); + av_freep(&mmc->section_data[i].section_id); + av_freep(&mmc->section_data[i].src_id); + av_freep(&mmc->section_data[i].section_type); + } + + return 0; +} + +static void set_str(const char **dst, const char *src) +{ + if (*dst) + av_freep(dst); + + if (src) + *dst = av_strdup(src); +} + +static void mermaid_subgraph_complete_start(MermaidContext *mmc, AVTextFormatContext *tfc, int level) { + struct section_data parent_sec_data = mmc->section_data[level]; + AVBPrint *parent_buf = &tfc->section_pbuf[level]; + + if (parent_sec_data.subgraph_start_incomplete) { + if (parent_buf->len > 0) + writer_printf(tfc, "%s", parent_buf->str); + + writer_put_str(tfc, "\"]\n"); + + mmc->section_data[level].subgraph_start_incomplete = 0; + } +} + +#define MM_INDENT() writer_printf(tfc, "%*c", mmc->indent_level * 2, ' ') + +static void mermaid_print_section_header(AVTextFormatContext *tfc, const void *data) +{ + const AVTextFormatSection *section = tf_get_section(tfc, tfc->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(tfc, tfc->level); + + if (!section) + return; + AVBPrint *buf = &tfc->section_pbuf[tfc->level]; + MermaidContext *mmc = tfc->priv; + const AVTextFormatSectionContext *sec_ctx = data; + + if (tfc->level == 0) { + char *directive; + AVBPrint css_buf; + const char *diag_directive = mmc->diagram_config->diagram_type == AV_DIAGRAMTYPE_ENTITYRELATIONSHIP ? init_directive_er : init_directive; + char *single_line_css = av_strireplace(mmc->diagram_config->diagram_css, "\n", " "); + (void)theme_css_er; + ////char *single_line_css = av_strireplace(theme_css_er, "\n", " "); + av_bprint_init(&css_buf, 0, AV_BPRINT_SIZE_UNLIMITED); + av_bprint_escape(&css_buf, single_line_css, "'\\", AV_ESCAPE_MODE_BACKSLASH, AV_ESCAPE_FLAG_STRICT); + av_freep(&single_line_css); + + directive = av_strireplace(diag_directive, "__###__", css_buf.str); + if (mmc->create_html) { + uint64_t length; + char *token_pos = av_stristr(mmc->diagram_config->html_template, "__###__"); + if (!token_pos) { + av_log(tfc, AV_LOG_ERROR, "Unable to locate the required token (__###__) in the html template."); + return; + } + + length = token_pos - mmc->diagram_config->html_template; + for (uint64_t i = 0; i < length; i++) + writer_w8(tfc, mmc->diagram_config->html_template[i]); + } + + writer_put_str(tfc, directive); + switch (mmc->diagram_config->diagram_type) { + case AV_DIAGRAMTYPE_GRAPH: + writer_put_str(tfc, "flowchart LR\n"); + ////writer_put_str(tfc, " gradient_def@{ shape: text, label: \"\" }\n"); + writer_put_str(tfc, " gradient_def@{ shape: text, label: \"\" }\n"); + break; + case AV_DIAGRAMTYPE_ENTITYRELATIONSHIP: + writer_put_str(tfc, "erDiagram\n"); + break; + } + + av_bprint_finalize(&css_buf, NULL); + av_freep(&directive); + return; + } + + if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH) { + mermaid_subgraph_complete_start(mmc, tfc, tfc->level - 1); + } + + av_freep(&mmc->section_data[tfc->level].section_id); + av_freep(&mmc->section_data[tfc->level].section_type); + av_freep(&mmc->section_data[tfc->level].src_id); + av_freep(&mmc->section_data[tfc->level].dest_id); + mmc->section_data[tfc->level].current_is_textblock = 0; + mmc->section_data[tfc->level].current_is_stadium = 0; + mmc->section_data[tfc->level].subgraph_start_incomplete = 0; + mmc->section_data[tfc->level].link_type = AV_TEXTFORMAT_LINKTYPE_SRCDEST; + + // NOTE: av_strdup() allocations aren't checked + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH) { + + av_bprint_clear(buf); + writer_put_str(tfc, "\n"); + + mmc->indent_level++; + + if (sec_ctx->context_id) { + MM_INDENT(); + writer_printf(tfc, "subgraph %s[\"
", sec_ctx->context_id, section->name); + } else { + av_log(tfc, AV_LOG_ERROR, "Unable to write subgraph start. Missing id field. Section: %s", section->name); + } + + mmc->section_data[tfc->level].subgraph_start_incomplete = 1; + set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id); + } + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE) { + + av_bprint_clear(buf); + writer_put_str(tfc, "\n"); + + mmc->indent_level++; + + if (sec_ctx->context_id) { + + set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id); + + switch (mmc->diagram_config->diagram_type) { + case AV_DIAGRAMTYPE_GRAPH: + if (sec_ctx->context_flags & 1) { + + MM_INDENT(); + writer_printf(tfc, "%s@{ shape: text, label: \"", sec_ctx->context_id); + mmc->section_data[tfc->level].current_is_textblock = 1; + } else if (sec_ctx->context_flags & 2) { + + MM_INDENT(); + writer_printf(tfc, "%s([\"", sec_ctx->context_id); + mmc->section_data[tfc->level].current_is_stadium = 1; + } else { + MM_INDENT(); + writer_printf(tfc, "%s(\"", sec_ctx->context_id); + } + + break; + case AV_DIAGRAMTYPE_ENTITYRELATIONSHIP: + MM_INDENT(); + writer_printf(tfc, "%s {\n", sec_ctx->context_id); + break; + } + + } else { + av_log(tfc, AV_LOG_ERROR, "Unable to write shape start. Missing id field. Section: %s", section->name); + } + + set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id); + } + + + if (section->flags & AV_TEXTFORMAT_SECTION_PRINT_TAGS) { + + if (sec_ctx && sec_ctx->context_type) + writer_printf(tfc, "
", section->name, sec_ctx->context_type); + else + writer_printf(tfc, "
", section->name); + } + + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS) { + + av_bprint_clear(buf); + mmc->nb_link_captions[tfc->level] = 0; + + if (sec_ctx && sec_ctx->context_type) + set_str(&mmc->section_data[tfc->level].section_type, sec_ctx->context_type); + + ////if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE) { + //// AVBPrint buf; + //// av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + //// av_bprint_escape(&buf, section->get_type(data), NULL, + //// AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); + //// writer_printf(tfc, " type=\"%s\"", buf.str); + } +} + +static void mermaid_print_section_footer(AVTextFormatContext *tfc) +{ + MermaidContext *mmc = tfc->priv; + const AVTextFormatSection *section = tf_get_section(tfc, tfc->level); + + if (!section) + return; + AVBPrint *buf = &tfc->section_pbuf[tfc->level]; + struct section_data sec_data = mmc->section_data[tfc->level]; + + if (section->flags & AV_TEXTFORMAT_SECTION_PRINT_TAGS) + writer_put_str(tfc, "
"); + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE) { + + switch (mmc->diagram_config->diagram_type) { + case AV_DIAGRAMTYPE_GRAPH: + + if (sec_data.current_is_textblock) { + writer_printf(tfc, "\"}\n", section->name); + + if (sec_data.section_id) { + MM_INDENT(); + writer_put_str(tfc, "class "); + writer_put_str(tfc, sec_data.section_id); + writer_put_str(tfc, " ff-"); + writer_put_str(tfc, section->name); + writer_put_str(tfc, "\n"); + } + } else if (sec_data.current_is_stadium) { + writer_printf(tfc, "\"]):::ff-%s\n", section->name); + } else { + writer_printf(tfc, "\"):::ff-%s\n", section->name); + } + + break; + case AV_DIAGRAMTYPE_ENTITYRELATIONSHIP: + MM_INDENT(); + writer_put_str(tfc, "}\n\n"); + break; + } + + mmc->indent_level--; + + } else if ((section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH)) { + + mermaid_subgraph_complete_start(mmc, tfc, tfc->level); + + MM_INDENT(); + writer_put_str(tfc, "end\n"); + + if (sec_data.section_id) { + MM_INDENT(); + writer_put_str(tfc, "class "); + writer_put_str(tfc, sec_data.section_id); + writer_put_str(tfc, " ff-"); + writer_put_str(tfc, section->name); + writer_put_str(tfc, "\n"); + } + + mmc->indent_level--; + } + + if ((section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS)) + if (sec_data.src_id && sec_data.dest_id + && !has_link_pair(tfc, sec_data.src_id, sec_data.dest_id)) + switch (mmc->diagram_config->diagram_type) { + case AV_DIAGRAMTYPE_GRAPH: + + if (sec_data.section_type && mmc->enable_link_colors) + av_bprintf(&mmc->link_buf, "\n %s %s-%s-%s@==", sec_data.src_id, sec_data.section_type, sec_data.src_id, sec_data.dest_id); + else + av_bprintf(&mmc->link_buf, "\n %s ==", sec_data.src_id); + + if (buf->len > 0) { + av_bprintf(&mmc->link_buf, " \"%s", buf->str); + + for (unsigned i = 0; i < mmc->nb_link_captions[tfc->level]; i++) + av_bprintf(&mmc->link_buf, "
 "); + + av_bprintf(&mmc->link_buf, "\" =="); + } + + av_bprintf(&mmc->link_buf, "> %s", sec_data.dest_id); + + break; + case AV_DIAGRAMTYPE_ENTITYRELATIONSHIP: + + + av_bprintf(&mmc->link_buf, "\n %s", sec_data.src_id); + + switch (sec_data.link_type) { + case AV_TEXTFORMAT_LINKTYPE_ONETOMANY: + av_bprintf(&mmc->link_buf, "%s", " ||--o{ "); + break; + case AV_TEXTFORMAT_LINKTYPE_MANYTOONE: + av_bprintf(&mmc->link_buf, "%s", " }o--|| "); + break; + case AV_TEXTFORMAT_LINKTYPE_ONETOONE: + av_bprintf(&mmc->link_buf, "%s", " ||--|| "); + break; + case AV_TEXTFORMAT_LINKTYPE_MANYTOMANY: + av_bprintf(&mmc->link_buf, "%s", " }o--o{ "); + break; + default: + av_bprintf(&mmc->link_buf, "%s", " ||--|| "); + break; + } + + av_bprintf(&mmc->link_buf, "%s : \"\"", sec_data.dest_id); + + break; + } + + if (tfc->level == 0) { + + writer_put_str(tfc, "\n"); + if (mmc->create_html) { + char *token_pos = av_stristr(mmc->diagram_config->html_template, "__###__"); + if (!token_pos) { + av_log(tfc, AV_LOG_ERROR, "Unable to locate the required token (__###__) in the html template."); + return; + } + token_pos += strlen("__###__"); + writer_put_str(tfc, token_pos); + } + } + + if (tfc->level == 1) { + + if (mmc->link_buf.len > 0) { + writer_put_str(tfc, mmc->link_buf.str); + av_bprint_clear(&mmc->link_buf); + } + + writer_put_str(tfc, "\n"); + } +} + +static void mermaid_print_value(AVTextFormatContext *tfc, const char *key, + const char *str, int64_t num, const int is_int) +{ + MermaidContext *mmc = tfc->priv; + const AVTextFormatSection *section = tf_get_section(tfc, tfc->level); + + if (!section) + return; + + AVBPrint *buf = &tfc->section_pbuf[tfc->level]; + struct section_data sec_data = mmc->section_data[tfc->level]; + int exit = 0; + + if (section->id_key && !strcmp(section->id_key, key)) { + set_str(&mmc->section_data[tfc->level].section_id, str); + exit = 1; + } + + if (section->dest_id_key && !strcmp(section->dest_id_key, key)) { + set_str(&mmc->section_data[tfc->level].dest_id, str); + exit = 1; + } + + if (section->src_id_key && !strcmp(section->src_id_key, key)) { + set_str(&mmc->section_data[tfc->level].src_id, str); + exit = 1; + } + + if (section->linktype_key && !strcmp(section->linktype_key, key)) { + mmc->section_data[tfc->level].link_type = (AVTextFormatLinkType)num; + exit = 1; + } + + if (exit) + return; + + if ((section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS)) + || (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH && sec_data.subgraph_start_incomplete)) { + switch (mmc->diagram_config->diagram_type) { + case AV_DIAGRAMTYPE_GRAPH: + + if (is_int) { + writer_printf(tfc, "%s: %"PRId64"", key, key, num); + } else { + const char *tmp = av_strireplace(str, "\"", "'"); + writer_printf(tfc, "%s", key, tmp); + av_freep(&tmp); + } + + break; + case AV_DIAGRAMTYPE_ENTITYRELATIONSHIP: + + if (!is_int && str) + { + const char *col_type; + + if (key[0] == '_') + return; + + if (sec_data.section_id && !strcmp(str, sec_data.section_id)) + col_type = "PK"; + else if (sec_data.dest_id && !strcmp(str, sec_data.dest_id)) + col_type = "FK"; + else if (sec_data.src_id && !strcmp(str, sec_data.src_id)) + col_type = "FK"; + else + col_type = ""; + + MM_INDENT(); + + writer_printf(tfc, " %s %s %s\n", key, str, col_type); + } + break; + } + + } else if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS) { + if (buf->len > 0) + av_bprintf(buf, "%s", "
"); + + av_bprintf(buf, ""); + if (is_int) + av_bprintf(buf, "%s: %"PRId64"", key, num); + else + av_bprintf(buf, "%s", str); + + mmc->nb_link_captions[tfc->level]++; + } +} + +static inline void mermaid_print_str(AVTextFormatContext *tfc, const char *key, const char *value) +{ + mermaid_print_value(tfc, key, value, 0, 0); +} + +static void mermaid_print_int(AVTextFormatContext *tfc, const char *key, int64_t value) +{ + mermaid_print_value(tfc, key, NULL, value, 1); +} + +const AVTextFormatter avtextformatter_mermaid = { + .name = "mermaid", + .priv_size = sizeof(MermaidContext), + .init = mermaid_init, + .uninit = mermaid_uninit, + .print_section_header = mermaid_print_section_header, + .print_section_footer = mermaid_print_section_footer, + .print_integer = mermaid_print_int, + .print_string = mermaid_print_str, + .flags = AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER, + .priv_class = &mermaid_class, +}; + + +const AVTextFormatter avtextformatter_mermaidhtml = { + .name = "mermaidhtml", + .priv_size = sizeof(MermaidContext), + .init = mermaid_init_html, + .uninit = mermaid_uninit, + .print_section_header = mermaid_print_section_header, + .print_section_footer = mermaid_print_section_footer, + .print_integer = mermaid_print_int, + .print_string = mermaid_print_str, + .flags = AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER, + .priv_class = &mermaid_class, +}; diff --git a/fftools/textformat/tf_mermaid.h b/fftools/textformat/tf_mermaid.h new file mode 100644 index 000000000..6e8f2a9b4 --- /dev/null +++ b/fftools/textformat/tf_mermaid.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 FFTOOLS_TEXTFORMAT_TF_MERMAID_H +#define FFTOOLS_TEXTFORMAT_TF_MERMAID_H + +typedef enum { + AV_DIAGRAMTYPE_GRAPH, + AV_DIAGRAMTYPE_ENTITYRELATIONSHIP, +} AVDiagramType; + +typedef struct AVDiagramConfig { + AVDiagramType diagram_type; + const char *diagram_css; + const char *html_template; +} AVDiagramConfig; + + +void av_diagram_init(AVTextFormatContext *tfc, AVDiagramConfig *diagram_config); + +void av_mermaid_set_html_template(AVTextFormatContext *tfc, const char *html_template); + + +#endif /* FFTOOLS_TEXTFORMAT_TF_MERMAID_H */ diff --git a/fftools/textformat/tf_xml.c b/fftools/textformat/tf_xml.c new file mode 100644 index 000000000..d4329110f --- /dev/null +++ b/fftools/textformat/tf_xml.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 "avtextformat.h" +#include "libavutil/bprint.h" +#include "libavutil/error.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + +/* XML output */ + +typedef struct XMLContext { + const AVClass *class; + int within_tag; + int indent_level; + int fully_qualified; + int xsd_strict; +} XMLContext; + +#undef OFFSET +#define OFFSET(x) offsetof(XMLContext, x) + +static const AVOption xml_options[] = { + { "fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(xml); + +static av_cold int xml_init(AVTextFormatContext *wctx) +{ + XMLContext *xml = wctx->priv; + + if (xml->xsd_strict) { + xml->fully_qualified = 1; +#define CHECK_COMPLIANCE(opt, opt_name) \ + if (opt) { \ + av_log(wctx, AV_LOG_ERROR, \ + "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \ + "You need to disable such option with '-no%s'\n", opt_name, opt_name); \ + return AVERROR(EINVAL); \ + } + ////CHECK_COMPLIANCE(show_private_data, "private"); + CHECK_COMPLIANCE(wctx->opts.show_value_unit, "unit"); + CHECK_COMPLIANCE(wctx->opts.use_value_prefix, "prefix"); + } + + return 0; +} + +#define XML_INDENT() writer_printf(wctx, "%*c", xml->indent_level * 4, ' ') + +static void xml_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + XMLContext *xml = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + + if (!section) + return; + + if (wctx->level == 0) { + const char *qual = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + "xmlns:ffprobe=\"http://www.ffmpeg.org/schema/ffprobe\" " + "xsi:schemaLocation=\"http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd\""; + + writer_put_str(wctx, "\n"); + writer_printf(wctx, "<%sffprobe%s>\n", + xml->fully_qualified ? "ffprobe:" : "", + xml->fully_qualified ? qual : ""); + return; + } + + if (xml->within_tag) { + xml->within_tag = 0; + writer_put_str(wctx, ">\n"); + } + + if (parent_section && (parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER) && + wctx->level && wctx->nb_item[wctx->level - 1]) + writer_w8(wctx, '\n'); + xml->indent_level++; + + if (section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS)) { + XML_INDENT(); + writer_printf(wctx, "<%s", section->name); + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE) { + AVBPrint buf; + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + av_bprint_escape(&buf, section->get_type(data), NULL, + AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); + writer_printf(wctx, " type=\"%s\"", buf.str); + } + writer_printf(wctx, ">\n", section->name); + } else { + XML_INDENT(); + writer_printf(wctx, "<%s ", section->name); + xml->within_tag = 1; + } +} + +static void xml_print_section_footer(AVTextFormatContext *wctx) +{ + XMLContext *xml = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + + if (!section) + return; + + if (wctx->level == 0) { + writer_printf(wctx, "\n", xml->fully_qualified ? "ffprobe:" : ""); + } else if (xml->within_tag) { + xml->within_tag = 0; + writer_put_str(wctx, "/>\n"); + xml->indent_level--; + } else { + XML_INDENT(); + writer_printf(wctx, "\n", section->name); + xml->indent_level--; + } +} + +static void xml_print_value(AVTextFormatContext *wctx, const char *key, + const char *str, int64_t num, const int is_int) +{ + AVBPrint buf; + XMLContext *xml = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + + if (!section) + return; + + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS) { + xml->indent_level++; + XML_INDENT(); + av_bprint_escape(&buf, key, NULL, + AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); + writer_printf(wctx, "<%s key=\"%s\"", + section->element_name, buf.str); + av_bprint_clear(&buf); + + if (is_int) { + writer_printf(wctx, " value=\"%"PRId64"\"/>\n", num); + } else { + av_bprint_escape(&buf, str, NULL, + AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); + writer_printf(wctx, " value=\"%s\"/>\n", buf.str); + } + xml->indent_level--; + } else { + if (wctx->nb_item[wctx->level]) + writer_w8(wctx, ' '); + + if (is_int) { + writer_printf(wctx, "%s=\"%"PRId64"\"", key, num); + } else { + av_bprint_escape(&buf, str, NULL, + AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); + writer_printf(wctx, "%s=\"%s\"", key, buf.str); + } + } + + av_bprint_finalize(&buf, NULL); +} + +static inline void xml_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + xml_print_value(wctx, key, value, 0, 0); +} + +static void xml_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + xml_print_value(wctx, key, NULL, value, 1); +} + +const AVTextFormatter avtextformatter_xml = { + .name = "xml", + .priv_size = sizeof(XMLContext), + .init = xml_init, + .print_section_header = xml_print_section_header, + .print_section_footer = xml_print_section_footer, + .print_integer = xml_print_int, + .print_string = xml_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT, + .priv_class = &xml_class, +}; diff --git a/fftools/textformat/tw_avio.c b/fftools/textformat/tw_avio.c new file mode 100644 index 000000000..21d3af27d --- /dev/null +++ b/fftools/textformat/tw_avio.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 + +#include "avtextwriters.h" +#include "libavutil/avassert.h" + +#include "libavutil/error.h" + +/* AVIO Writer */ + +# define WRITER_NAME "aviowriter" + +typedef struct IOWriterContext { + const AVClass *class; + AVIOContext *avio_context; + int close_on_uninit; +} IOWriterContext; + +static av_cold int iowriter_uninit(AVTextWriterContext *wctx) +{ + IOWriterContext *ctx = wctx->priv; + int ret = 0; + + if (ctx->close_on_uninit) + ret = avio_closep(&ctx->avio_context); + return ret; +} + +static void io_w8(AVTextWriterContext *wctx, int b) +{ + IOWriterContext *ctx = wctx->priv; + avio_w8(ctx->avio_context, b); +} + +static void io_put_str(AVTextWriterContext *wctx, const char *str) +{ + IOWriterContext *ctx = wctx->priv; + avio_write(ctx->avio_context, (const unsigned char *)str, (int)strlen(str)); +} + +static void io_vprintf(AVTextWriterContext *wctx, const char *fmt, va_list vl) +{ + IOWriterContext *ctx = wctx->priv; + + avio_vprintf(ctx->avio_context, fmt, vl); +} + + +const AVTextWriter avtextwriter_avio = { + .name = WRITER_NAME, + .priv_size = sizeof(IOWriterContext), + .uninit = iowriter_uninit, + .writer_put_str = io_put_str, + .writer_vprintf = io_vprintf, + .writer_w8 = io_w8 +}; + +int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_filename) +{ + IOWriterContext *ctx; + int ret; + + if (!output_filename || !output_filename[0]) { + av_log(NULL, AV_LOG_ERROR, "The output_filename cannot be NULL or empty\n"); + return AVERROR(EINVAL); + } + + ret = avtextwriter_context_open(pwctx, &avtextwriter_avio); + if (ret < 0) + return ret; + + ctx = (*pwctx)->priv; + + if ((ret = avio_open(&ctx->avio_context, output_filename, AVIO_FLAG_WRITE)) < 0) { + av_log(ctx, AV_LOG_ERROR, + "Failed to open output '%s' with error: %s\n", output_filename, av_err2str(ret)); + avtextwriter_context_close(pwctx); + return ret; + } + + ctx->close_on_uninit = 1; + + return ret; +} + + +int avtextwriter_create_avio(AVTextWriterContext **pwctx, AVIOContext *avio_ctx, int close_on_uninit) +{ + IOWriterContext *ctx; + int ret; + + av_assert0(avio_ctx); + + ret = avtextwriter_context_open(pwctx, &avtextwriter_avio); + if (ret < 0) + return ret; + + ctx = (*pwctx)->priv; + ctx->avio_context = avio_ctx; + ctx->close_on_uninit = close_on_uninit; + + return ret; +} diff --git a/fftools/textformat/tw_buffer.c b/fftools/textformat/tw_buffer.c new file mode 100644 index 000000000..f6e63445d --- /dev/null +++ b/fftools/textformat/tw_buffer.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 "avtextwriters.h" +#include "libavutil/opt.h" +#include "libavutil/bprint.h" + +/* Buffer Writer */ + +# define WRITER_NAME "bufferwriter" + +typedef struct BufferWriterContext { + const AVClass *class; + AVBPrint *buffer; +} BufferWriterContext; + +static const char *bufferwriter_get_name(void *ctx) +{ + return WRITER_NAME; +} + +static const AVClass bufferwriter_class = { + .class_name = WRITER_NAME, + .item_name = bufferwriter_get_name, +}; + +static void buffer_w8(AVTextWriterContext *wctx, int b) +{ + BufferWriterContext *ctx = wctx->priv; + av_bprintf(ctx->buffer, "%c", b); +} + +static void buffer_put_str(AVTextWriterContext *wctx, const char *str) +{ + BufferWriterContext *ctx = wctx->priv; + av_bprintf(ctx->buffer, "%s", str); +} + +static void buffer_vprintf(AVTextWriterContext *wctx, const char *fmt, va_list vl) +{ + BufferWriterContext *ctx = wctx->priv; + + av_vbprintf(ctx->buffer, fmt, vl); +} + + +const AVTextWriter avtextwriter_buffer = { + .name = WRITER_NAME, + .priv_size = sizeof(BufferWriterContext), + .priv_class = &bufferwriter_class, + .writer_put_str = buffer_put_str, + .writer_vprintf = buffer_vprintf, + .writer_w8 = buffer_w8 +}; + +int avtextwriter_create_buffer(AVTextWriterContext **pwctx, AVBPrint *buffer) +{ + BufferWriterContext *ctx; + int ret; + + ret = avtextwriter_context_open(pwctx, &avtextwriter_buffer); + if (ret < 0) + return ret; + + ctx = (*pwctx)->priv; + ctx->buffer = buffer; + + return ret; +} diff --git a/fftools/textformat/tw_stdout.c b/fftools/textformat/tw_stdout.c new file mode 100644 index 000000000..3e2a8dd0d --- /dev/null +++ b/fftools/textformat/tw_stdout.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) The FFmpeg developers + * + * 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 + +#include "avtextwriters.h" +#include "libavutil/opt.h" + +/* STDOUT Writer */ + +# define WRITER_NAME "stdoutwriter" + +typedef struct StdOutWriterContext { + const AVClass *class; +} StdOutWriterContext; + +static const char *stdoutwriter_get_name(void *ctx) +{ + return WRITER_NAME; +} + +static const AVClass stdoutwriter_class = { + .class_name = WRITER_NAME, + .item_name = stdoutwriter_get_name, +}; + +static inline void stdout_w8(AVTextWriterContext *wctx, int b) +{ + printf("%c", b); +} + +static inline void stdout_put_str(AVTextWriterContext *wctx, const char *str) +{ + printf("%s", str); +} + +static inline void stdout_vprintf(AVTextWriterContext *wctx, const char *fmt, va_list vl) +{ + vprintf(fmt, vl); +} + + +static const AVTextWriter avtextwriter_stdout = { + .name = WRITER_NAME, + .priv_size = sizeof(StdOutWriterContext), + .priv_class = &stdoutwriter_class, + .writer_put_str = stdout_put_str, + .writer_vprintf = stdout_vprintf, + .writer_w8 = stdout_w8 +}; + +int avtextwriter_create_stdout(AVTextWriterContext **pwctx) +{ + int ret; + + ret = avtextwriter_context_open(pwctx, &avtextwriter_stdout); + + return ret; +} diff --git a/fftools/thread_queue.c b/fftools/thread_queue.c index fd73cc0a9..eb33431c9 100644 --- a/fftools/thread_queue.c +++ b/fftools/thread_queue.c @@ -20,13 +20,16 @@ #include #include "libavutil/avassert.h" +#include "libavutil/container_fifo.h" #include "libavutil/error.h" #include "libavutil/fifo.h" +#include "libavutil/frame.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/thread.h" -#include "objpool.h" +#include "libavcodec/packet.h" + #include "thread_queue.h" enum { @@ -34,19 +37,15 @@ enum { FINISHED_RECV = (1 << 1), }; -typedef struct FifoElem { - void *obj; - unsigned int stream_idx; -} FifoElem; - struct ThreadQueue { + int choked; int *finished; unsigned int nb_streams; - AVFifo *fifo; + enum ThreadQueueType type; - ObjPool *obj_pool; - void (*obj_move)(void *dst, void *src); + AVContainerFifo *fifo; + AVFifo *fifo_stream_index; pthread_mutex_t lock; pthread_cond_t cond; @@ -59,14 +58,8 @@ void tq_free(ThreadQueue **ptq) if (!tq) return; - if (tq->fifo) { - FifoElem elem; - while (av_fifo_read(tq->fifo, &elem, 1) >= 0) - objpool_release(tq->obj_pool, &elem.obj); - } - av_fifo_freep2(&tq->fifo); - - objpool_free(&tq->obj_pool); + av_container_fifo_free(&tq->fifo); + av_fifo_freep2(&tq->fifo_stream_index); av_freep(&tq->finished); @@ -77,7 +70,7 @@ void tq_free(ThreadQueue **ptq) } ThreadQueue *tq_alloc(unsigned int nb_streams, size_t queue_size, - ObjPool *obj_pool, void (*obj_move)(void *dst, void *src)) + enum ThreadQueueType type) { ThreadQueue *tq; int ret; @@ -104,12 +97,16 @@ ThreadQueue *tq_alloc(unsigned int nb_streams, size_t queue_size, goto fail; tq->nb_streams = nb_streams; - tq->fifo = av_fifo_alloc2(queue_size, sizeof(FifoElem), 0); + tq->type = type; + + tq->fifo = (type == THREAD_QUEUE_FRAMES) ? + av_container_fifo_alloc_avframe(0) : av_container_fifo_alloc_avpacket(0); if (!tq->fifo) goto fail; - tq->obj_pool = obj_pool; - tq->obj_move = obj_move; + tq->fifo_stream_index = av_fifo_alloc2(queue_size, sizeof(unsigned), 0); + if (!tq->fifo_stream_index) + goto fail; return tq; fail: @@ -132,23 +129,21 @@ int tq_send(ThreadQueue *tq, unsigned int stream_idx, void *data) goto finish; } - while (!(*finished & FINISHED_RECV) && !av_fifo_can_write(tq->fifo)) + while (!(*finished & FINISHED_RECV) && !av_fifo_can_write(tq->fifo_stream_index)) pthread_cond_wait(&tq->cond, &tq->lock); if (*finished & FINISHED_RECV) { ret = AVERROR_EOF; *finished |= FINISHED_SEND; } else { - FifoElem elem = { .stream_idx = stream_idx }; - - ret = objpool_get(tq->obj_pool, &elem.obj); + ret = av_fifo_write(tq->fifo_stream_index, &stream_idx, 1); if (ret < 0) goto finish; - tq->obj_move(elem.obj, data); + ret = av_container_fifo_write(tq->fifo, data, 0); + if (ret < 0) + goto finish; - ret = av_fifo_write(tq->fifo, &elem, 1); - av_assert0(ret >= 0); pthread_cond_broadcast(&tq->cond); } @@ -161,18 +156,24 @@ finish: static int receive_locked(ThreadQueue *tq, int *stream_idx, void *data) { - FifoElem elem; unsigned int nb_finished = 0; - while (av_fifo_read(tq->fifo, &elem, 1) >= 0) { - if (tq->finished[elem.stream_idx] & FINISHED_RECV) { - objpool_release(tq->obj_pool, &elem.obj); + if (tq->choked) + return AVERROR(EAGAIN); + + while (av_container_fifo_read(tq->fifo, data, 0) >= 0) { + unsigned idx; + int ret; + + ret = av_fifo_read(tq->fifo_stream_index, &idx, 1); + av_assert0(ret >= 0); + if (tq->finished[idx] & FINISHED_RECV) { + (tq->type == THREAD_QUEUE_FRAMES) ? + av_frame_unref(data) : av_packet_unref(data); continue; } - tq->obj_move(data, elem.obj); - objpool_release(tq->obj_pool, &elem.obj); - *stream_idx = elem.stream_idx; + *stream_idx = idx; return 0; } @@ -202,12 +203,12 @@ int tq_receive(ThreadQueue *tq, int *stream_idx, void *data) pthread_mutex_lock(&tq->lock); while (1) { - size_t can_read = av_fifo_can_read(tq->fifo); + size_t can_read = av_container_fifo_can_read(tq->fifo); ret = receive_locked(tq, stream_idx, data); // signal other threads if the fifo state changed - if (can_read != av_fifo_can_read(tq->fifo)) + if (can_read != av_container_fifo_can_read(tq->fifo)) pthread_cond_broadcast(&tq->cond); if (ret == AVERROR(EAGAIN)) { @@ -233,6 +234,7 @@ void tq_send_finish(ThreadQueue *tq, unsigned int stream_idx) * next time the consumer thread tries to read this stream it will get * an EOF and recv-finished flag will be set */ tq->finished[stream_idx] |= FINISHED_SEND; + tq->choked = 0; pthread_cond_broadcast(&tq->cond); pthread_mutex_unlock(&tq->lock); @@ -252,3 +254,15 @@ void tq_receive_finish(ThreadQueue *tq, unsigned int stream_idx) pthread_mutex_unlock(&tq->lock); } + +void tq_choke(ThreadQueue *tq, int choked) +{ + pthread_mutex_lock(&tq->lock); + + int prev_choked = tq->choked; + tq->choked = choked; + if (choked != prev_choked) + pthread_cond_broadcast(&tq->cond); + + pthread_mutex_unlock(&tq->lock); +} diff --git a/fftools/thread_queue.h b/fftools/thread_queue.h index 0cc8c71eb..ad7669f13 100644 --- a/fftools/thread_queue.h +++ b/fftools/thread_queue.h @@ -21,7 +21,10 @@ #include -#include "objpool.h" +enum ThreadQueueType { + THREAD_QUEUE_FRAMES, + THREAD_QUEUE_PACKETS, +}; typedef struct ThreadQueue ThreadQueue; @@ -32,12 +35,9 @@ typedef struct ThreadQueue ThreadQueue; * maintained * @param queue_size number of items that can be stored in the queue without * blocking - * @param obj_pool object pool that will be used to allocate items stored in the - * queue; the pool becomes owned by the queue - * @param callback that moves the contents between two data pointers */ ThreadQueue *tq_alloc(unsigned int nb_streams, size_t queue_size, - ObjPool *obj_pool, void (*obj_move)(void *dst, void *src)); + enum ThreadQueueType type); void tq_free(ThreadQueue **tq); /** @@ -58,6 +58,15 @@ int tq_send(ThreadQueue *tq, unsigned int stream_idx, void *data); */ void tq_send_finish(ThreadQueue *tq, unsigned int stream_idx); +/** + * Prevent further reads from the thread queue until it is unchoked. Threads + * attempting to read from the queue will block, similar to when the queue is + * empty. + * + * @param choked 1 to choke, 0 to unchoke + */ +void tq_choke(ThreadQueue *tq, int choked); + /** * Read the next item from the queue. * diff --git a/libavcodec/4xm.c b/libavcodec/4xm.c index fd3a45f09..c6b2ce123 100644 --- a/libavcodec/4xm.c +++ b/libavcodec/4xm.c @@ -337,7 +337,8 @@ static inline void mcdc(uint16_t *dst, const uint16_t *src, int log2w, } break; default: - av_assert0(0); + av_unreachable("log2w starts at 3 and gets only decremented during " + "recursive calls to decode_p_block"); } } @@ -927,8 +928,11 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, frame_size = buf_size - 12; } - if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) - return ret; + if ( frame_4cc == AV_RL32("ifr2") || frame_4cc == AV_RL32("ifrm") + || frame_4cc == AV_RL32("pfrm") || frame_4cc == AV_RL32("pfr2")) { + if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) + return ret; + } if (frame_4cc == AV_RL32("ifr2")) { picture->pict_type = AV_PICTURE_TYPE_I; diff --git a/libavcodec/8bps.c b/libavcodec/8bps.c index 0060c46d0..7a01633c9 100644 --- a/libavcodec/8bps.c +++ b/libavcodec/8bps.c @@ -114,14 +114,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, } if (avctx->bits_per_coded_sample <= 8) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = -#endif ff_copy_palette(c->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); } diff --git a/libavcodec/8svx.c b/libavcodec/8svx.c index 43567df3d..6afc2f727 100644 --- a/libavcodec/8svx.c +++ b/libavcodec/8svx.c @@ -198,8 +198,6 @@ const FFCodec ff_eightsvx_fib_decoder = { FF_CODEC_DECODE_CB(eightsvx_decode_frame), .close = eightsvx_decode_close, .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_NONE }, }; #endif #if CONFIG_EIGHTSVX_EXP_DECODER @@ -213,7 +211,5 @@ const FFCodec ff_eightsvx_exp_decoder = { FF_CODEC_DECODE_CB(eightsvx_decode_frame), .close = eightsvx_decode_close, .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_NONE }, }; #endif diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 9d1c1fc30..1410bd814 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -5,7 +5,6 @@ HEADERS = ac3_parser.h \ adts_parser.h \ avcodec.h \ avdct.h \ - avfft.h \ bsf.h \ codec.h \ codec_desc.h \ @@ -16,10 +15,12 @@ HEADERS = ac3_parser.h \ dirac.h \ dv_profile.h \ dxva2.h \ + exif.h \ jni.h \ mediacodec.h \ packet.h \ qsv.h \ + smpte_436m.h \ vdpau.h \ version.h \ version_major.h \ @@ -31,7 +32,6 @@ OBJS = ac3_parser.o \ allcodecs.o \ avcodec.o \ avdct.o \ - avfft.o \ packet.o \ bitstream.o \ bitstream_filters.o \ @@ -43,6 +43,7 @@ OBJS = ac3_parser.o \ dirac.o \ dv_profile.o \ encode.o \ + exif.o \ get_buffer.o \ imgconvert.o \ jni.o \ @@ -55,24 +56,29 @@ OBJS = ac3_parser.o \ profiles.o \ qsv_api.o \ raw.o \ - refstruct.o \ threadprogress.o \ + tiff_common.o \ utils.o \ version.o \ vlc.o \ vorbis_parser.o \ xiph.o \ +SHLIBOBJS = float_scalarproduct.o \ + timecode_internal.o \ + # subsystems include $(SRC_PATH)/libavcodec/aac/Makefile include $(SRC_PATH)/libavcodec/hevc/Makefile include $(SRC_PATH)/libavcodec/opus/Makefile include $(SRC_PATH)/libavcodec/vvc/Makefile +include $(SRC_PATH)/libavcodec/vulkan/Makefile +-include $(SRC_PATH)/libavcodec/$(ARCH)/hevc/Makefile -include $(SRC_PATH)/libavcodec/$(ARCH)/vvc/Makefile OBJS-$(CONFIG_AANDCTTABLES) += aandcttab.o OBJS-$(CONFIG_AC3DSP) += ac3dsp.o ac3.o ac3tab.o OBJS-$(CONFIG_ADTS_HEADER) += adts_header.o mpeg4audio_sample_rates.o -OBJS-$(CONFIG_AMF) += amfenc.o +OBJS-$(CONFIG_AMF) += amfenc.o amfdec.o OBJS-$(CONFIG_AUDIO_FRAME_QUEUE) += audio_frame_queue.o OBJS-$(CONFIG_ATSC_A53) += atsc_a53.o OBJS-$(CONFIG_AUDIODSP) += audiodsp.o @@ -80,21 +86,23 @@ OBJS-$(CONFIG_BLOCKDSP) += blockdsp.o OBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o OBJS-$(CONFIG_CABAC) += cabac.o OBJS-$(CONFIG_CBS) += cbs.o cbs_bsf.o +OBJS-$(CONFIG_CBS_APV) += cbs_apv.o OBJS-$(CONFIG_CBS_AV1) += cbs_av1.o -OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o cbs_sei.o h2645_parse.o -OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o cbs_sei.o h2645_parse.o -OBJS-$(CONFIG_CBS_H266) += cbs_h2645.o cbs_sei.o h2645_parse.o +OBJS-$(CONFIG_CBS_H264) += cbs_h264.o cbs_h2645.o cbs_sei.o h2645_parse.o +OBJS-$(CONFIG_CBS_H265) += cbs_h265.o cbs_h2645.o cbs_sei.o h2645_parse.o +OBJS-$(CONFIG_CBS_H266) += cbs_h266.o cbs_h2645.o cbs_sei.o h2645_parse.o +OBJS-$(CONFIG_CBS_LCEVC) += cbs_lcevc.o cbs_h2645.o cbs_sei.o h2645_parse.o OBJS-$(CONFIG_CBS_JPEG) += cbs_jpeg.o OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o OBJS-$(CONFIG_CBS_VP8) += cbs_vp8.o vp8data.o OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o +OBJS-$(CONFIG_CELP_MATH) += celp_math.o OBJS-$(CONFIG_D3D12VA_ENCODE) += d3d12va_encode.o hw_base_encode.o OBJS-$(CONFIG_DEFLATE_WRAPPER) += zlib_wrapper.o OBJS-$(CONFIG_DOVI_RPUDEC) += dovi_rpu.o dovi_rpudec.o OBJS-$(CONFIG_DOVI_RPUENC) += dovi_rpu.o dovi_rpuenc.o OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o OBJS-$(CONFIG_EVCPARSE) += evc_parse.o evc_ps.o -OBJS-$(CONFIG_EXIF) += exif.o tiff_common.o OBJS-$(CONFIG_FAANDCT) += faandct.o OBJS-$(CONFIG_FAANIDCT) += faanidct.o OBJS-$(CONFIG_FDCTDSP) += fdctdsp.o jfdctfst.o jfdctint.o @@ -116,7 +124,6 @@ OBJS-$(CONFIG_HUFFMAN) += huffman.o OBJS-$(CONFIG_HUFFYUVDSP) += huffyuvdsp.o OBJS-$(CONFIG_HUFFYUVENCDSP) += huffyuvencdsp.o OBJS-$(CONFIG_IDCTDSP) += idctdsp.o simple_idct.o jrevdct.o -OBJS-$(CONFIG_IIRFILTER) += iirfilter.o OBJS-$(CONFIG_INFLATE_WRAPPER) += zlib_wrapper.o OBJS-$(CONFIG_INTRAX8) += intrax8.o intrax8dsp.o msmpeg4_vc1_data.o OBJS-$(CONFIG_IVIDSP) += ivi_dsp.o @@ -144,14 +151,15 @@ OBJS-$(CONFIG_MPEGAUDIOHEADER) += mpegaudiodecheader.o mpegaudiotabs.o OBJS-$(CONFIG_MPEG4AUDIO) += mpeg4audio.o mpeg4audio_sample_rates.o OBJS-$(CONFIG_MPEGVIDEO) += mpegvideo.o rl.o \ mpegvideo_motion.o \ + mpegvideo_unquantize.o \ mpegvideodata.o mpegpicture.o \ to_upper4.o OBJS-$(CONFIG_MPEGVIDEODEC) += mpegvideo_dec.o mpegutils.o OBJS-$(CONFIG_MPEGVIDEOENC) += mpegvideo_enc.o mpeg12data.o \ - motion_est.o ratecontrol.o \ - mpegvideoencdsp.o + motion_est.o ratecontrol.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += mpegvideoencdsp.o OBJS-$(CONFIG_MSMPEG4DEC) += msmpeg4dec.o msmpeg4.o msmpeg4data.o \ - msmpeg4_vc1_data.o + msmpeg4_vc1_data.o mpeg4videodec.o OBJS-$(CONFIG_MSMPEG4ENC) += msmpeg4enc.o msmpeg4.o msmpeg4data.o \ msmpeg4_vc1_data.o OBJS-$(CONFIG_MSS34DSP) += mss34dsp.o jpegquanttables.o @@ -163,6 +171,7 @@ OBJS-$(CONFIG_QSVENC) += qsvenc.o OBJS-$(CONFIG_RANGECODER) += rangecoder.o OBJS-$(CONFIG_RV34DSP) += rv34dsp.o OBJS-$(CONFIG_SINEWIN) += sinewin.o +OBJS-$(CONFIG_SMPTE_436M) += smpte_436m.o OBJS-$(CONFIG_SNAPPY) += snappy.o OBJS-$(CONFIG_STARTCODE) += startcode.o OBJS-$(CONFIG_TEXTUREDSP) += texturedsp.o @@ -170,10 +179,10 @@ OBJS-$(CONFIG_TEXTUREDSPENC) += texturedspenc.o OBJS-$(CONFIG_TPELDSP) += tpeldsp.o OBJS-$(CONFIG_VAAPI_ENCODE) += vaapi_encode.o hw_base_encode.o OBJS-$(CONFIG_AV1_AMF_ENCODER) += amfenc_av1.o +OBJS-$(CONFIG_AV1_AMF_DECODER) += amfdec.o OBJS-$(CONFIG_VC1DSP) += vc1dsp.o OBJS-$(CONFIG_VIDEODSP) += videodsp.o OBJS-$(CONFIG_VP3DSP) += vp3dsp.o -OBJS-$(CONFIG_VP56DSP) += vp56dsp.o OBJS-$(CONFIG_VP8DSP) += vp8dsp.o OBJS-$(CONFIG_V4L2_M2M) += v4l2_m2m.o v4l2_context.o v4l2_buffers.o v4l2_fmt.o OBJS-$(CONFIG_WMA_FREQS) += wma_freqs.o @@ -186,17 +195,17 @@ OBJS-$(CONFIG_A64MULTI5_ENCODER) += a64multienc.o elbg.o OBJS-$(CONFIG_AAC_DECODER) += aactab.o \ aacsbr.o aacps_common.o aacps_float.o \ kbdwin.o \ - sbrdsp.o aacpsdsp_float.o cbrt_data.o + sbrdsp.o aacpsdsp_float.o cbrt_data.o \ + $(if $(!CONFIG_HARDCODED_TABLES), cbrt_tablegen_common.o) OBJS-$(CONFIG_AAC_FIXED_DECODER) += aactab.o \ aacsbr_fixed.o aacps_common.o aacps_fixed.o \ kbdwin.o \ - sbrdsp_fixed.o aacpsdsp_fixed.o cbrt_data_fixed.o + sbrdsp_fixed.o aacpsdsp_fixed.o cbrt_data_fixed.o \ + $(if $(!CONFIG_HARDCODED_TABLES), cbrt_tablegen_common.o) OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o aacenctab.o \ aacpsy.o aactab.o \ aacenc_is.o \ aacenc_tns.o \ - aacenc_ltp.o \ - aacenc_pred.o \ psymodel.o kbdwin.o \ mpeg4audio_sample_rates.o OBJS-$(CONFIG_AAC_MEDIACODEC_DECODER) += mediacodecdec.o @@ -210,8 +219,9 @@ OBJS-$(CONFIG_AC3_ENCODER) += ac3enc_float.o ac3enc.o ac3tab.o \ ac3.o kbdwin.o OBJS-$(CONFIG_AC3_FIXED_ENCODER) += ac3enc_fixed.o ac3enc.o ac3tab.o ac3.o kbdwin.o OBJS-$(CONFIG_AC3_MF_ENCODER) += mfenc.o mf_utils.o -OBJS-$(CONFIG_ACELP_KELVIN_DECODER) += g729dec.o lsp.o celp_math.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o +OBJS-$(CONFIG_ACELP_KELVIN_DECODER) += g729dec.o lsp.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o OBJS-$(CONFIG_AGM_DECODER) += agm.o jpegquanttables.o +OBJS-$(CONFIG_AHX_DECODER) += mpegaudiodec_float.o OBJS-$(CONFIG_AIC_DECODER) += aic.o OBJS-$(CONFIG_ALAC_DECODER) += alac.o alac_data.o alacdsp.o OBJS-$(CONFIG_ALAC_ENCODER) += alacenc.o alac_data.o @@ -219,11 +229,11 @@ OBJS-$(CONFIG_ALIAS_PIX_DECODER) += aliaspixdec.o OBJS-$(CONFIG_ALIAS_PIX_ENCODER) += aliaspixenc.o OBJS-$(CONFIG_ALS_DECODER) += alsdec.o bgmc.o mlz.o OBJS-$(CONFIG_AMRNB_DECODER) += amrnbdec.o celp_filters.o \ - celp_math.o acelp_filters.o \ + acelp_filters.o \ acelp_vectors.o \ acelp_pitch_delay.o OBJS-$(CONFIG_AMRWB_DECODER) += amrwbdec.o celp_filters.o \ - celp_math.o acelp_filters.o \ + acelp_filters.o \ acelp_vectors.o \ acelp_pitch_delay.o OBJS-$(CONFIG_AMRNB_MEDIACODEC_DECODER) += mediacodecdec.o @@ -241,6 +251,7 @@ OBJS-$(CONFIG_APTX_HD_DECODER) += aptxdec.o aptx.o OBJS-$(CONFIG_APTX_HD_ENCODER) += aptxenc.o aptx.o OBJS-$(CONFIG_APNG_DECODER) += png.o pngdec.o pngdsp.o OBJS-$(CONFIG_APNG_ENCODER) += png.o pngenc.o +OBJS-$(CONFIG_APV_DECODER) += apv_decode.o apv_entropy.o apv_dsp.o OBJS-$(CONFIG_ARBC_DECODER) += arbc.o OBJS-$(CONFIG_ARGO_DECODER) += argo.o OBJS-$(CONFIG_SSA_DECODER) += assdec.o ass.o @@ -263,11 +274,14 @@ OBJS-$(CONFIG_AURA_DECODER) += cyuv.o OBJS-$(CONFIG_AURA2_DECODER) += aura.o OBJS-$(CONFIG_AV1_DECODER) += av1dec.o av1_parse.o OBJS-$(CONFIG_AV1_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_AV1_D3D12VA_ENCODER) += d3d12va_encode_av1.o av1_levels.o OBJS-$(CONFIG_AV1_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_AV1_MEDIACODEC_ENCODER) += mediacodecenc.o OBJS-$(CONFIG_AV1_NVENC_ENCODER) += nvenc_av1.o nvenc.o OBJS-$(CONFIG_AV1_QSV_ENCODER) += qsvenc_av1.o OBJS-$(CONFIG_AV1_VAAPI_ENCODER) += vaapi_encode_av1.o av1_levels.o +OBJS-$(CONFIG_AV1_VULKAN_ENCODER) += vulkan_encode.o vulkan_encode_av1.o \ + hw_base_encode.o av1_levels.o OBJS-$(CONFIG_AVRN_DECODER) += avrndec.o OBJS-$(CONFIG_AVRP_DECODER) += r210dec.o OBJS-$(CONFIG_AVRP_ENCODER) += r210enc.o @@ -347,7 +361,7 @@ OBJS-$(CONFIG_DVVIDEO_ENCODER) += dvenc.o dv.o dvdata.o OBJS-$(CONFIG_DXA_DECODER) += dxa.o OBJS-$(CONFIG_DXTORY_DECODER) += dxtory.o OBJS-$(CONFIG_DXV_DECODER) += dxv.o -OBJS-$(CONFIG_DXV_ENCODER) += dxvenc.o +OBJS-$(CONFIG_DXV_ENCODER) += dxvenc.o hashtable.o OBJS-$(CONFIG_EAC3_DECODER) += eac3_data.o OBJS-$(CONFIG_EAC3_ENCODER) += eac3enc.o eac3_data.o OBJS-$(CONFIG_EACMV_DECODER) += eacmv.o @@ -363,11 +377,12 @@ OBJS-$(CONFIG_EIGHTSVX_FIB_DECODER) += 8svx.o OBJS-$(CONFIG_ESCAPE124_DECODER) += escape124.o OBJS-$(CONFIG_ESCAPE130_DECODER) += escape130.o OBJS-$(CONFIG_EVRC_DECODER) += evrcdec.o acelp_vectors.o lsp.o -OBJS-$(CONFIG_EXR_DECODER) += exr.o exrdsp.o half2float.o -OBJS-$(CONFIG_EXR_ENCODER) += exrenc.o float2half.o +OBJS-$(CONFIG_EXR_DECODER) += exr.o exrdsp.o +OBJS-$(CONFIG_EXR_ENCODER) += exrenc.o OBJS-$(CONFIG_FASTAUDIO_DECODER) += fastaudio.o -OBJS-$(CONFIG_FFV1_DECODER) += ffv1dec.o ffv1.o -OBJS-$(CONFIG_FFV1_ENCODER) += ffv1enc.o ffv1.o +OBJS-$(CONFIG_FFV1_DECODER) += ffv1dec.o ffv1_parse.o ffv1.o +OBJS-$(CONFIG_FFV1_ENCODER) += ffv1enc.o ffv1_parse.o ffv1.o +OBJS-$(CONFIG_FFV1_VULKAN_ENCODER) += ffv1enc.o ffv1.o ffv1_vulkan.o ffv1enc_vulkan.o OBJS-$(CONFIG_FFWAVESYNTH_DECODER) += ffwavesynth.o OBJS-$(CONFIG_FIC_DECODER) += fic.o OBJS-$(CONFIG_FITS_DECODER) += fitsdec.o fits.o @@ -388,10 +403,11 @@ OBJS-$(CONFIG_FRWU_DECODER) += frwu.o OBJS-$(CONFIG_FTR_DECODER) += ftr.o OBJS-$(CONFIG_G2M_DECODER) += g2meet.o elsdec.o mjpegdec_common.o OBJS-$(CONFIG_G723_1_DECODER) += g723_1dec.o g723_1.o \ - acelp_vectors.o celp_filters.o celp_math.o + acelp_vectors.o celp_filters.o OBJS-$(CONFIG_G723_1_ENCODER) += g723_1enc.o g723_1.o \ - acelp_vectors.o celp_filters.o celp_math.o -OBJS-$(CONFIG_G729_DECODER) += g729dec.o lsp.o celp_math.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o + acelp_vectors.o celp_filters.o +OBJS-$(CONFIG_G728_DECODER) += g728dec.o celp_filters.o +OBJS-$(CONFIG_G729_DECODER) += g729dec.o lsp.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o OBJS-$(CONFIG_GDV_DECODER) += gdv.o OBJS-$(CONFIG_GEM_DECODER) += gemdec.o OBJS-$(CONFIG_GIF_DECODER) += gifdec.o lzw.o @@ -415,16 +431,22 @@ OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o h264_cavlc.o \ h264_refs.o \ h264_slice.o h264data.o h274.o OBJS-$(CONFIG_H264_AMF_ENCODER) += amfenc_h264.o +OBJS-$(CONFIG_H264_AMF_DECODER) += amfdec.o OBJS-$(CONFIG_H264_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_H264_D3D12VA_ENCODER) += d3d12va_encode_h264.o h264_levels.o \ + h2645data.o hw_base_encode_h264.o OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_H264_MEDIACODEC_ENCODER) += mediacodecenc.o OBJS-$(CONFIG_H264_MF_ENCODER) += mfenc.o mf_utils.o OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o nvenc.o +OBJS-$(CONFIG_H264_OH_DECODER) += ohcodec.o ohdec.o +OBJS-$(CONFIG_H264_OH_ENCODER) += ohcodec.o ohenc.o OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o OBJS-$(CONFIG_H264_RKMPP_DECODER) += rkmppdec.o +OBJS-$(CONFIG_H264_RKMPP_ENCODER) += rkmppenc.o OBJS-$(CONFIG_H264_VAAPI_ENCODER) += vaapi_encode_h264.o h264_levels.o \ h2645data.o hw_base_encode_h264.o OBJS-$(CONFIG_H264_VULKAN_ENCODER) += vulkan_encode.o vulkan_encode_h264.o \ @@ -439,18 +461,22 @@ OBJS-$(CONFIG_HCA_DECODER) += hcadec.o OBJS-$(CONFIG_HCOM_DECODER) += hcom.o OBJS-$(CONFIG_HDR_DECODER) += hdrdec.o OBJS-$(CONFIG_HDR_ENCODER) += hdrenc.o -OBJS-$(CONFIG_HEVC_DECODER) += aom_film_grain.o h274.o container_fifo.o +OBJS-$(CONFIG_HEVC_DECODER) += aom_film_grain.o h274.o OBJS-$(CONFIG_HEVC_AMF_ENCODER) += amfenc_hevc.o +OBJS-$(CONFIG_HEVC_AMF_DECODER) += amfdec.o OBJS-$(CONFIG_HEVC_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_HEVC_D3D12VA_ENCODER) += d3d12va_encode_hevc.o h265_profile_level.o \ - h2645data.o + h2645data.o hw_base_encode_h265.o OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_HEVC_MEDIACODEC_ENCODER) += mediacodecenc.o OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o nvenc.o +OBJS-$(CONFIG_HEVC_OH_DECODER) += ohcodec.o ohdec.o +OBJS-$(CONFIG_HEVC_OH_ENCODER) += ohcodec.o ohenc.o OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc/ps_enc.o OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o +OBJS-$(CONFIG_HEVC_RKMPP_ENCODER) += rkmppenc.o OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o h265_profile_level.o \ h2645data.o hw_base_encode_h265.o OBJS-$(CONFIG_HEVC_VULKAN_ENCODER) += vulkan_encode.o vulkan_encode_h265.o \ @@ -460,8 +486,8 @@ OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_HEVC_V4L2M2M_ENCODER) += v4l2_m2m_enc.o OBJS-$(CONFIG_HEVC_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o -OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadsp.o canopus.o -OBJS-$(CONFIG_HQX_DECODER) += hqx.o hqxvlc.o hqxdsp.o canopus.o +OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadsp.o hq_common.o canopus.o +OBJS-$(CONFIG_HQX_DECODER) += hqx.o hqxdsp.o hq_common.o canopus.o OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o huffyuvdec.o OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o huffyuvenc.o OBJS-$(CONFIG_HYMT_DECODER) += huffyuv.o huffyuvdec.o @@ -524,10 +550,10 @@ OBJS-$(CONFIG_MOVTEXT_ENCODER) += movtextenc.o ass_split.o OBJS-$(CONFIG_MP1_DECODER) += mpegaudiodec_fixed.o OBJS-$(CONFIG_MP1FLOAT_DECODER) += mpegaudiodec_float.o OBJS-$(CONFIG_MP2_DECODER) += mpegaudiodec_fixed.o -OBJS-$(CONFIG_MP2_ENCODER) += mpegaudioenc_float.o mpegaudio.o \ +OBJS-$(CONFIG_MP2_ENCODER) += mpegaudioenc.o mpegaudio.o \ mpegaudiodata.o mpegaudiodsp_data.o \ mpegaudiotabs.o -OBJS-$(CONFIG_MP2FIXED_ENCODER) += mpegaudioenc_fixed.o mpegaudio.o \ +OBJS-$(CONFIG_MP2FIXED_ENCODER) += mpegaudioenc.o mpegaudio.o \ mpegaudiodata.o mpegaudiodsp_data.o \ mpegaudiotabs.o OBJS-$(CONFIG_MP2FLOAT_DECODER) += mpegaudiodec_float.o @@ -543,19 +569,20 @@ OBJS-$(CONFIG_MPC7_DECODER) += mpc7.o mpc.o OBJS-$(CONFIG_MPC8_DECODER) += mpc8.o mpc.o OBJS-$(CONFIG_MPEGVIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o OBJS-$(CONFIG_MPEG1VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o -OBJS-$(CONFIG_MPEG1VIDEO_ENCODER) += mpeg12enc.o mpeg12.o +OBJS-$(CONFIG_MPEG1VIDEO_ENCODER) += mpeg12enc.o OBJS-$(CONFIG_MPEG1_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_MPEG1_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_MPEG2_MMAL_DECODER) += mmaldec.o OBJS-$(CONFIG_MPEG2_QSV_DECODER) += qsvdec.o OBJS-$(CONFIG_MPEG2_QSV_ENCODER) += qsvenc_mpeg2.o OBJS-$(CONFIG_MPEG2VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o -OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpeg12.o +OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o OBJS-$(CONFIG_MPEG2_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_MPEG2_VAAPI_ENCODER) += vaapi_encode_mpeg2.o OBJS-$(CONFIG_MPEG2_V4L2M2M_DECODER) += v4l2_m2m_dec.o -OBJS-$(CONFIG_MPEG4_DECODER) += mpeg4videodsp.o xvididct.o +OBJS-$(CONFIG_MPEG4_DECODER) += mpeg4videodec.o mpeg4videodsp.o \ + xvididct.o OBJS-$(CONFIG_MPEG4_ENCODER) += mpeg4videoenc.o OBJS-$(CONFIG_MPEG4_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o @@ -607,8 +634,8 @@ OBJS-$(CONFIG_PGMYUV_DECODER) += pnmdec.o pnm.o OBJS-$(CONFIG_PGMYUV_ENCODER) += pnmenc.o OBJS-$(CONFIG_PGSSUB_DECODER) += pgssubdec.o OBJS-$(CONFIG_PGX_DECODER) += pgxdec.o -OBJS-$(CONFIG_PHM_DECODER) += pnmdec.o pnm.o half2float.o -OBJS-$(CONFIG_PHM_ENCODER) += pnmenc.o float2half.o +OBJS-$(CONFIG_PHM_DECODER) += pnmdec.o pnm.o +OBJS-$(CONFIG_PHM_ENCODER) += pnmenc.o OBJS-$(CONFIG_PHOTOCD_DECODER) += photocd.o OBJS-$(CONFIG_PICTOR_DECODER) += pictordec.o cga_data.o OBJS-$(CONFIG_PIXLET_DECODER) += pixlet.o @@ -620,7 +647,9 @@ OBJS-$(CONFIG_PPM_ENCODER) += pnmenc.o OBJS-$(CONFIG_PRORES_DECODER) += proresdec.o proresdsp.o proresdata.o OBJS-$(CONFIG_PRORES_ENCODER) += proresenc_anatoliy.o proresdata.o OBJS-$(CONFIG_PRORES_AW_ENCODER) += proresenc_anatoliy.o proresdata.o -OBJS-$(CONFIG_PRORES_KS_ENCODER) += proresenc_kostya.o proresdata.o +OBJS-$(CONFIG_PRORES_KS_ENCODER) += proresenc_kostya.o proresdata.o proresenc_kostya_common.o +OBJS-$(CONFIG_PRORES_KS_VULKAN_ENCODER) += proresenc_kostya_vulkan.o proresdata.o proresenc_kostya_common.o +OBJS-$(CONFIG_PRORES_RAW_DECODER) += prores_raw.o proresdsp.o proresdata.o OBJS-$(CONFIG_PRORES_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o OBJS-$(CONFIG_PROSUMER_DECODER) += prosumer.o OBJS-$(CONFIG_PSD_DECODER) += psd.o @@ -665,6 +694,7 @@ OBJS-$(CONFIG_RV20_DECODER) += rv10.o OBJS-$(CONFIG_RV20_ENCODER) += rv20enc.o OBJS-$(CONFIG_RV30_DECODER) += rv30.o rv34.o rv30dsp.o OBJS-$(CONFIG_RV40_DECODER) += rv40.o rv34.o rv40dsp.o +OBJS-$(CONFIG_RV60_DECODER) += rv60dec.o rv60dsp.o OBJS-$(CONFIG_SAMI_DECODER) += samidec.o ass.o htmlsubtitles.o OBJS-$(CONFIG_S302M_DECODER) += s302m.o OBJS-$(CONFIG_S302M_ENCODER) += s302menc.o @@ -679,7 +709,7 @@ OBJS-$(CONFIG_SGIRLE_DECODER) += sgirledec.o OBJS-$(CONFIG_SHEERVIDEO_DECODER) += sheervideo.o OBJS-$(CONFIG_SHORTEN_DECODER) += shorten.o OBJS-$(CONFIG_SIPR_DECODER) += sipr.o acelp_pitch_delay.o \ - celp_math.o acelp_vectors.o \ + acelp_vectors.o \ acelp_filters.o celp_filters.o \ sipr16k.o OBJS-$(CONFIG_SIREN_DECODER) += siren.o @@ -690,7 +720,8 @@ OBJS-$(CONFIG_SMC_DECODER) += smc.o OBJS-$(CONFIG_SMC_ENCODER) += smcenc.o OBJS-$(CONFIG_SNOW_DECODER) += snowdec.o snow.o snow_dwt.o OBJS-$(CONFIG_SNOW_ENCODER) += snowenc.o snow.o snow_dwt.o \ - h263.o h263data.o ituh263enc.o + h263data.o ituh263enc.o \ + motion_est.o ratecontrol.o OBJS-$(CONFIG_SOL_DPCM_DECODER) += dpcm.o OBJS-$(CONFIG_SONIC_DECODER) += sonic.o OBJS-$(CONFIG_SONIC_ENCODER) += sonic.o @@ -710,12 +741,11 @@ OBJS-$(CONFIG_SUBVIEWER1_DECODER) += textdec.o ass.o OBJS-$(CONFIG_SUBVIEWER_DECODER) += subviewerdec.o ass.o OBJS-$(CONFIG_SUNRAST_DECODER) += sunrast.o OBJS-$(CONFIG_SUNRAST_ENCODER) += sunrastenc.o -OBJS-$(CONFIG_LIBRSVG_DECODER) += librsvgdec.o -OBJS-$(CONFIG_SBC_DECODER) += sbcdec.o sbcdec_data.o sbc.o -OBJS-$(CONFIG_SBC_ENCODER) += sbcenc.o sbc.o sbcdsp.o sbcdsp_data.o +OBJS-$(CONFIG_SBC_DECODER) += sbcdec.o sbc.o +OBJS-$(CONFIG_SBC_ENCODER) += sbcenc.o sbc.o sbcdsp.o OBJS-$(CONFIG_SVQ1_DECODER) += svq1dec.o svq1.o h263data.o OBJS-$(CONFIG_SVQ1_ENCODER) += svq1enc.o svq1.o h263data.o \ - h263.o ituh263enc.o + h263.o ituh263enc.o motion_est.o OBJS-$(CONFIG_SVQ3_DECODER) += svq3.o mpegutils.o h264data.o OBJS-$(CONFIG_TEXT_DECODER) += textdec.o ass.o OBJS-$(CONFIG_TEXT_ENCODER) += srtenc.o ass_split.o @@ -777,7 +807,8 @@ OBJS-$(CONFIG_VORBIS_DECODER) += vorbisdec.o vorbisdsp.o vorbis.o \ OBJS-$(CONFIG_VORBIS_ENCODER) += vorbisenc.o vorbis.o \ vorbis_data.o OBJS-$(CONFIG_VP3_DECODER) += vp3.o jpegquanttables.o -OBJS-$(CONFIG_VP5_DECODER) += vp5.o vp56.o vp56data.o vpx_rac.o +OBJS-$(CONFIG_VP5_DECODER) += vp5.o vp56.o vp56data.o \ + vp5dsp.o vpx_rac.o OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o \ vp6dsp.o vpx_rac.o OBJS-$(CONFIG_VP7_DECODER) += vp8.o vp8data.o vpx_rac.o @@ -793,6 +824,7 @@ OBJS-$(CONFIG_VP8_V4L2M2M_ENCODER) += v4l2_m2m_enc.o OBJS-$(CONFIG_VP9_DECODER) += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9recon.o \ vp9block.o vp9prob.o vp9mvs.o vpx_rac.o \ vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o +OBJS-$(CONFIG_VP9_AMF_DECODER) += amfdec.o OBJS-$(CONFIG_VP9_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_VP9_MEDIACODEC_ENCODER) += mediacodecenc.o @@ -803,6 +835,8 @@ OBJS-$(CONFIG_VPLAYER_DECODER) += textdec.o ass.o OBJS-$(CONFIG_VP9_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o OBJS-$(CONFIG_VQC_DECODER) += vqcdec.o +OBJS-$(CONFIG_VVC_DECODER) += executor.o h2645data.o +OBJS-$(CONFIG_VVC_SEI) += h2645_sei.o aom_film_grain.o h274.o OBJS-$(CONFIG_WADY_DPCM_DECODER) += dpcm.o OBJS-$(CONFIG_WAVARC_DECODER) += wavarc.o OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o wavpackdata.o dsd.o @@ -822,8 +856,8 @@ OBJS-$(CONFIG_WMAV2_ENCODER) += wmaenc.o wma.o wma_common.o aactab.o OBJS-$(CONFIG_WMAVOICE_DECODER) += wmavoice.o \ celp_filters.o \ acelp_vectors.o acelp_filters.o -OBJS-$(CONFIG_WMV2_DECODER) += wmv2dec.o wmv2.o wmv2data.o -OBJS-$(CONFIG_WMV2_ENCODER) += wmv2enc.o wmv2.o wmv2data.o +OBJS-$(CONFIG_WMV2_DECODER) += wmv2dec.o wmv2data.o +OBJS-$(CONFIG_WMV2_ENCODER) += wmv2enc.o wmv2data.o OBJS-$(CONFIG_WNV1_DECODER) += wnv1.o OBJS-$(CONFIG_WRAPPED_AVFRAME_DECODER) += wrapped_avframe.o OBJS-$(CONFIG_WRAPPED_AVFRAME_ENCODER) += wrapped_avframe.o @@ -932,6 +966,7 @@ OBJS-$(CONFIG_ADPCM_AGM_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_AICA_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_ARGO_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_ARGO_ENCODER) += adpcm.o adpcm_data.o adpcmenc.o +OBJS-$(CONFIG_ADPCM_CIRCUS_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_DTK_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o adpcm_data.o @@ -960,9 +995,14 @@ OBJS-$(CONFIG_ADPCM_IMA_DK3_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_DK4_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_EA_EACS_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_EA_SEAD_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_ESCAPE_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_HVQM2_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_HVQM4_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_ISS_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_MAGIX_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_MOFLEX_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_MTF_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_PDA_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_OKI_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_QT_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_QT_ENCODER) += adpcmenc.o adpcm_data.o @@ -974,10 +1014,14 @@ OBJS-$(CONFIG_ADPCM_IMA_WAV_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_WAV_ENCODER) += adpcmenc.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_WS_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_WS_ENCODER) += adpcmenc.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_XBOX_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_MS_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_MS_ENCODER) += adpcmenc.o adpcm_data.o OBJS-$(CONFIG_ADPCM_MTAF_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_N64_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_PSX_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_PSXC_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_SANYO_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SBPRO_2_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SBPRO_3_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SBPRO_4_DECODER) += adpcm.o adpcm_data.o @@ -985,7 +1029,7 @@ OBJS-$(CONFIG_ADPCM_SWF_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SWF_ENCODER) += adpcmenc.o adpcm_data.o OBJS-$(CONFIG_ADPCM_THP_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_THP_LE_DECODER) += adpcm.o adpcm_data.o -OBJS-$(CONFIG_ADPCM_VIMA_DECODER) += vima.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_VIMA_DECODER) += vima.o adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_XA_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_XMD_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER) += adpcm.o adpcm_data.o @@ -1008,7 +1052,10 @@ OBJS-$(CONFIG_AV1_D3D12VA_HWACCEL) += dxva2_av1.o d3d12va_av1.o OBJS-$(CONFIG_AV1_NVDEC_HWACCEL) += nvdec_av1.o OBJS-$(CONFIG_AV1_VAAPI_HWACCEL) += vaapi_av1.o OBJS-$(CONFIG_AV1_VDPAU_HWACCEL) += vdpau_av1.o +OBJS-$(CONFIG_AV1_VIDEOTOOLBOX_HWACCEL) += videotoolbox_av1.o OBJS-$(CONFIG_AV1_VULKAN_HWACCEL) += vulkan_decode.o vulkan_av1.o +OBJS-$(CONFIG_DPX_VULKAN_HWACCEL) += vulkan_decode.o vulkan_dpx.o +OBJS-$(CONFIG_FFV1_VULKAN_HWACCEL) += vulkan_decode.o ffv1_vulkan.o vulkan_ffv1.o OBJS-$(CONFIG_H263_VAAPI_HWACCEL) += vaapi_mpeg4.o OBJS-$(CONFIG_H263_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o OBJS-$(CONFIG_H264_D3D11VA_HWACCEL) += dxva2_h264.o @@ -1061,11 +1108,20 @@ OBJS-$(CONFIG_VP9_NVDEC_HWACCEL) += nvdec_vp9.o OBJS-$(CONFIG_VP9_VAAPI_HWACCEL) += vaapi_vp9.o OBJS-$(CONFIG_VP9_VDPAU_HWACCEL) += vdpau_vp9.o OBJS-$(CONFIG_VP9_VIDEOTOOLBOX_HWACCEL) += videotoolbox_vp9.o +OBJS-$(CONFIG_VP9_VULKAN_HWACCEL) += vulkan_decode.o vulkan_vp9.o OBJS-$(CONFIG_VP8_QSV_HWACCEL) += qsvdec.o +OBJS-$(CONFIG_VVC_VAAPI_HWACCEL) += vaapi_vvc.o +OBJS-$(CONFIG_PRORES_RAW_VULKAN_HWACCEL) += vulkan_decode.o vulkan_prores_raw.o +OBJS-$(CONFIG_PRORES_VULKAN_HWACCEL) += vulkan_decode.o vulkan_prores.o # Objects duplicated from other libraries for shared builds SHLIBOBJS += log2_tab.o reverse.o +SHLIBOBJS-$(CONFIG_EXR_DECODER) += half2float.o float2half.o +SHLIBOBJS-$(CONFIG_EXR_ENCODER) += float2half.o +SHLIBOBJS-$(CONFIG_PHM_DECODER) += half2float.o +SHLIBOBJS-$(CONFIG_PHM_ENCODER) += float2half.o + # General libavformat dependencies OBJS-$(CONFIG_FITS_DEMUXER) += fits.o OBJS-$(CONFIG_TAK_DEMUXER) += tak.o @@ -1076,7 +1132,6 @@ STLIBOBJS-$(CONFIG_ISO_MEDIA) += mpegaudiotabs.o STLIBOBJS-$(CONFIG_FLV_MUXER) += mpeg4audio_sample_rates.o STLIBOBJS-$(CONFIG_HLS_DEMUXER) += ac3_channel_layout_tab.o STLIBOBJS-$(CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER) += jpegxl_parse.o -STLIBOBJS-$(CONFIG_JNI) += ffjni.o STLIBOBJS-$(CONFIG_JPEGXL_ANIM_DEMUXER) += jpegxl_parse.o STLIBOBJS-$(CONFIG_MATROSKA_DEMUXER) += mpeg4audio_sample_rates.o STLIBOBJS-$(CONFIG_MOV_DEMUXER) += ac3_channel_layout_tab.o @@ -1135,6 +1190,8 @@ OBJS-$(CONFIG_LIBKVAZAAR_ENCODER) += libkvazaar.o OBJS-$(CONFIG_LIBLC3_ENCODER) += liblc3enc.o OBJS-$(CONFIG_LIBLC3_DECODER) += liblc3dec.o OBJS-$(CONFIG_LIBMP3LAME_ENCODER) += libmp3lame.o +OBJS-$(CONFIG_LIBMPEGHDEC_DECODER) += libmpeghdec.o +OBJS-$(CONFIG_LIBOAPV_ENCODER) += liboapvenc.o OBJS-$(CONFIG_LIBOPENCORE_AMRNB_DECODER) += libopencore-amr.o OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER) += libopencore-amr.o OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER) += libopencore-amr.o @@ -1146,10 +1203,13 @@ OBJS-$(CONFIG_LIBOPUS_DECODER) += libopusdec.o libopus.o \ OBJS-$(CONFIG_LIBOPUS_ENCODER) += libopusenc.o libopus.o \ vorbis_data.o OBJS-$(CONFIG_LIBRAV1E_ENCODER) += librav1e.o +OBJS-$(CONFIG_LIBRSVG_DECODER) += librsvgdec.o OBJS-$(CONFIG_LIBSHINE_ENCODER) += libshine.o OBJS-$(CONFIG_LIBSPEEX_DECODER) += libspeexdec.o OBJS-$(CONFIG_LIBSPEEX_ENCODER) += libspeexenc.o OBJS-$(CONFIG_LIBSVTAV1_ENCODER) += libsvtav1.o +OBJS-$(CONFIG_LIBSVTJPEGXS_DECODER) += libsvtjpegxsdec.o +OBJS-$(CONFIG_LIBSVTJPEGXS_ENCODER) += libsvtjpegxsenc.o OBJS-$(CONFIG_LIBTHEORA_ENCODER) += libtheoraenc.o OBJS-$(CONFIG_LIBTWOLAME_ENCODER) += libtwolame.o OBJS-$(CONFIG_LIBUAVS3D_DECODER) += libuavs3d.o @@ -1180,7 +1240,9 @@ OBJS-$(CONFIG_AAC_PARSER) += aac_parser.o aac_ac3_parser.o OBJS-$(CONFIG_AC3_PARSER) += aac_ac3_parser.o ac3tab.o \ ac3_channel_layout_tab.o OBJS-$(CONFIG_ADX_PARSER) += adx_parser.o +OBJS-$(CONFIG_AHX_PARSER) += ahx_parser.o OBJS-$(CONFIG_AMR_PARSER) += amr_parser.o +OBJS-$(CONFIG_APV_PARSER) += apv_parser.o OBJS-$(CONFIG_AV1_PARSER) += av1_parser.o av1_parse.o OBJS-$(CONFIG_AVS2_PARSER) += avs2.o avs2_parser.o OBJS-$(CONFIG_AVS3_PARSER) += avs3_parser.o @@ -1192,6 +1254,7 @@ OBJS-$(CONFIG_DCA_PARSER) += dca_parser.o dca_exss.o dca.o \ dca_sample_rate_tab.o OBJS-$(CONFIG_DIRAC_PARSER) += dirac_parser.o OBJS-$(CONFIG_DNXHD_PARSER) += dnxhd_parser.o dnxhddata.o +OBJS-$(CONFIG_DNXUC_PARSER) += dnxuc_parser.o OBJS-$(CONFIG_DOLBY_E_PARSER) += dolby_e_parser.o dolby_e_parse.o OBJS-$(CONFIG_DPX_PARSER) += dpx_parser.o OBJS-$(CONFIG_DVAUDIO_PARSER) += dvaudio_parser.o @@ -1199,6 +1262,7 @@ OBJS-$(CONFIG_DVBSUB_PARSER) += dvbsub_parser.o OBJS-$(CONFIG_DVD_NAV_PARSER) += dvd_nav_parser.o OBJS-$(CONFIG_DVDSUB_PARSER) += dvdsub_parser.o OBJS-$(CONFIG_EVC_PARSER) += evc_parser.o +OBJS-$(CONFIG_FFV1_PARSER) += ffv1_parser.o ffv1_parse.o ffv1.o OBJS-$(CONFIG_FLAC_PARSER) += flac_parser.o flacdata.o flac.o OBJS-$(CONFIG_FTR_PARSER) += ftr_parser.o OBJS-$(CONFIG_G723_1_PARSER) += g723_1_parser.o @@ -1212,19 +1276,22 @@ OBJS-$(CONFIG_HDR_PARSER) += hdr_parser.o OBJS-$(CONFIG_IPU_PARSER) += ipu_parser.o OBJS-$(CONFIG_JPEG2000_PARSER) += jpeg2000_parser.o OBJS-$(CONFIG_JPEGXL_PARSER) += jpegxl_parser.o jpegxl_parse.o +OBJS-$(CONFIG_JPEGXS_PARSER) += jpegxs_parser.o +OBJS-$(CONFIG_LCEVC_PARSER) += lcevc_parser.o lcevctab.o OBJS-$(CONFIG_MISC4_PARSER) += misc4_parser.o OBJS-$(CONFIG_MJPEG_PARSER) += mjpeg_parser.o OBJS-$(CONFIG_MLP_PARSER) += mlp_parse.o mlp_parser.o mlp.o OBJS-$(CONFIG_MPEG4VIDEO_PARSER) += mpeg4video_parser.o h263.o \ mpeg4videodec.o mpeg4video.o \ - ituh263dec.o h263dec.o h263data.o + ituh263dec.o h263data.o OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o -OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \ - mpeg12.o mpeg12data.o +OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o mpeg12data.o OBJS-$(CONFIG_OPUS_PARSER) += vorbis_data.o OBJS-$(CONFIG_PNG_PARSER) += png_parser.o OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o +OBJS-$(CONFIG_PRORES_RAW_PARSER) += prores_raw_parser.o OBJS-$(CONFIG_QOI_PARSER) += qoi_parser.o +OBJS-$(CONFIG_PRORES_PARSER) += prores_parser.o OBJS-$(CONFIG_RV34_PARSER) += rv34_parser.o OBJS-$(CONFIG_SBC_PARSER) += sbc_parser.o OBJS-$(CONFIG_SIPR_PARSER) += sipr_parser.o @@ -1270,7 +1337,7 @@ SKIPHEADERS += %_tablegen.h \ bitstream_template.h \ $(ARCH)/vpx_arith.h \ -SKIPHEADERS-$(CONFIG_AMF) += amfenc.h +SKIPHEADERS-$(CONFIG_AMF) += amfenc.h amfdec.h SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h SKIPHEADERS-$(CONFIG_D3D12VA) += d3d12va_decode.h d3d12va_encode.h SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h @@ -1284,12 +1351,14 @@ SKIPHEADERS-$(CONFIG_MEDIACODEC) += mediacodecdec_common.h mediacodec_surf SKIPHEADERS-$(CONFIG_MEDIAFOUNDATION) += mf_utils.h SKIPHEADERS-$(CONFIG_NVDEC) += nvdec.h SKIPHEADERS-$(CONFIG_NVENC) += nvenc.h +SKIPHEADERS-$(CONFIG_OHCODEC) += ohcodec.h SKIPHEADERS-$(CONFIG_QSV) += qsv.h qsv_internal.h SKIPHEADERS-$(CONFIG_QSVENC) += qsvenc.h SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_decode.h vaapi_hevc.h vaapi_encode.h SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h vdpau_internal.h SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.h vt_internal.h -SKIPHEADERS-$(CONFIG_VULKAN) += vulkan.h vulkan_video.h vulkan_encode.h vulkan_decode.h +SKIPHEADERS-$(CONFIG_VULKAN) += ffv1_vulkan.h prores_vulkan.h vulkan_video.h \ + vulkan_encode.h vulkan_decode.h SKIPHEADERS-$(CONFIG_V4L2_M2M) += v4l2_buffers.h v4l2_context.h v4l2_m2m.h SKIPHEADERS-$(CONFIG_ZLIB) += zlib_wrapper.h @@ -1297,17 +1366,18 @@ TESTPROGS = avcodec \ avpacket \ bitstream_be \ bitstream_le \ - celp_math \ codec_desc \ htmlsubtitles \ jpeg2000dwt \ mathops \ +TESTPROGS-$(CONFIG_APV_DECODER) += apv TESTPROGS-$(CONFIG_AV1_VAAPI_ENCODER) += av1_levels TESTPROGS-$(CONFIG_CABAC) += cabac +TESTPROGS-$(CONFIG_CELP_MATH) += celp_math TESTPROGS-$(CONFIG_GOLOMB) += golomb TESTPROGS-$(CONFIG_IDCTDSP) += dct -TESTPROGS-$(CONFIG_IIRFILTER) += iirfilter +TESTPROGS-$(CONFIG_DXV_ENCODER) += hashtable TESTPROGS-$(CONFIG_MJPEG_ENCODER) += mjpegenc_huffman TESTPROGS-$(HAVE_MMX) += motion TESTPROGS-$(CONFIG_MPEGVIDEO) += mpeg12framerate diff --git a/libavcodec/a64multienc.c b/libavcodec/a64multienc.c index 38edbe3a7..d81718dff 100644 --- a/libavcodec/a64multienc.c +++ b/libavcodec/a64multienc.c @@ -403,7 +403,7 @@ const FFCodec ff_a64multi_encoder = { .init = a64multi_encode_init, FF_CODEC_ENCODE_CB(a64multi_encode_frame), .close = a64multi_close_encoder, - .p.pix_fmts = (const enum AVPixelFormat[]) {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_GRAY8), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif @@ -418,7 +418,7 @@ const FFCodec ff_a64multi5_encoder = { .init = a64multi_encode_init, FF_CODEC_ENCODE_CB(a64multi_encode_frame), .close = a64multi_close_encoder, - .p.pix_fmts = (const enum AVPixelFormat[]) {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_GRAY8), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/aac.h b/libavcodec/aac.h index 78026a588..b77b6e7c1 100644 --- a/libavcodec/aac.h +++ b/libavcodec/aac.h @@ -36,6 +36,10 @@ #define TNS_MAX_ORDER 20 #define MAX_LTP_LONG_SFB 40 +#define MPS_MAX_PARAM_SETS 9 +#define MPS_MAX_PARAM_BANDS 28 +#define MPS_MAX_TIME_SLOTS 16 /* 64 in non-AAC MPEG Surround */ + enum RawDataBlockType { TYPE_SCE, TYPE_CPE, diff --git a/libavcodec/aac/Makefile b/libavcodec/aac/Makefile index 70b1dca27..b1ec21b18 100644 --- a/libavcodec/aac/Makefile +++ b/libavcodec/aac/Makefile @@ -3,6 +3,7 @@ clean:: OBJS-$(CONFIG_AAC_DECODER) += aac/aacdec.o aac/aacdec_tab.o \ aac/aacdec_float.o aac/aacdec_usac.o \ - aac/aacdec_ac.o aac/aacdec_lpd.o + aac/aacdec_ac.o aac/aacdec_lpd.o \ + aac/aacdec_usac_mps212.o OBJS-$(CONFIG_AAC_FIXED_DECODER) += aac/aacdec.o aac/aacdec_tab.o \ aac/aacdec_fixed.o diff --git a/libavcodec/aac/aacdec.c b/libavcodec/aac/aacdec.c index add73d9b1..b8d53036d 100644 --- a/libavcodec/aac/aacdec.c +++ b/libavcodec/aac/aacdec.c @@ -62,7 +62,7 @@ #include "libavutil/opt.h" #include "libavutil/tx.h" #include "libavutil/version.h" -#include "libavcodec/refstruct.h" +#include "libavutil/refstruct.h" /* * supported tools @@ -402,8 +402,8 @@ static uint64_t sniff_channel_order(uint8_t (*layout_map)[3], int tags) FFSWAP(struct elem_to_channel, e2c_vec[6], e2c_vec[4]); // FLc & FRc fifth (final), SiL & SiR seventh FFSWAP(struct elem_to_channel, e2c_vec[7], e2c_vec[6]); // LFE2 seventh (final), SiL & SiR eight (final) FFSWAP(struct elem_to_channel, e2c_vec[9], e2c_vec[8]); // TpFL & TpFR ninth (final), TFC tenth (final) - FFSWAP(struct elem_to_channel, e2c_vec[11], e2c_vec[10]); // TC eleventh (final), TpSiL & TpSiR twelth - FFSWAP(struct elem_to_channel, e2c_vec[12], e2c_vec[11]); // TpBL & TpBR twelth (final), TpSiL & TpSiR thirteenth (final) + FFSWAP(struct elem_to_channel, e2c_vec[11], e2c_vec[10]); // TC eleventh (final), TpSiL & TpSiR twelfth + FFSWAP(struct elem_to_channel, e2c_vec[12], e2c_vec[11]); // TpBL & TpBR twelfth (final), TpSiL & TpSiR thirteenth (final) } else { // For everything else, utilize the AV channel position define as a // stable sort. @@ -437,12 +437,12 @@ static void copy_oc(OutputConfiguration *dst, OutputConfiguration *src) AACUsacElemConfig *dst_e = &dst->usac.elems[i]; /* dst_e->ext.pl_buf is guaranteed to be set to src_e->ext.pl_buf * upon this function's return */ - ff_refstruct_replace(&dst_e->ext.pl_buf, src_e->ext.pl_buf); + av_refstruct_replace(&dst_e->ext.pl_buf, src_e->ext.pl_buf); } /* Unref all additional buffers to close leaks */ for (; i < dst->usac.nb_elems; i++) - ff_refstruct_unref(&dst->usac.elems[i].ext.pl_buf); + av_refstruct_unref(&dst->usac.elems[i].ext.pl_buf); /* Set all other properties */ *dst = *src; @@ -569,7 +569,9 @@ static av_cold void flush(AVCodecContext *avctx) } } +#if CONFIG_AAC_DECODER ff_aac_usac_reset_state(ac, &ac->oc[1]); +#endif } /** @@ -1133,13 +1135,13 @@ static av_cold int decode_close(AVCodecContext *avctx) for (int i = 0; i < 2; i++) { OutputConfiguration *oc = &ac->oc[i]; - av_channel_layout_uninit(&ac->oc[i].ch_layout); - AACUSACConfig *usac = &oc->usac; for (int j = 0; j < usac->nb_elems; j++) { AACUsacElemConfig *ec = &usac->elems[j]; - ff_refstruct_unref(&ec->ext.pl_buf); + av_refstruct_unref(&ec->ext.pl_buf); } + + av_channel_layout_uninit(&ac->oc[i].ch_layout); } for (int type = 0; type < FF_ARRAY_ELEMS(ac->che); type++) { @@ -1757,7 +1759,7 @@ int ff_aac_decode_ics(AACDecContext *ac, SingleChannelElement *sce, } } // I see no textual basis in the spec for this occurring after SSR gain - // control, but this is what both reference and real implmentations do + // control, but this is what both reference and real implementations do if (tns->present && er_syntax) { ret = ff_aac_decode_tns(ac, tns, gb, ics); if (ret < 0) @@ -2420,7 +2422,8 @@ static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, ac->frame = frame; *got_frame_ptr = 0; - if (show_bits(gb, 12) == 0xfff) { + // USAC can't be packed into ADTS due to field size limitations. + if (show_bits(gb, 12) == 0xfff && ac->oc[1].m4ac.object_type != AOT_USAC) { if ((err = parse_adts_frame_header(ac, gb)) < 0) { av_log(avctx, AV_LOG_ERROR, "Error decoding AAC frame header.\n"); goto fail; @@ -2576,12 +2579,10 @@ const FFCodec ff_aac_decoder = { .init = ff_aac_decode_init_float, .close = decode_close, FF_CODEC_DECODE_CB(aac_decode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.ch_layouts = ff_aac_ch_layout, + CODEC_CH_LAYOUTS_ARRAY(ff_aac_ch_layout), .flush = flush, .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), }; @@ -2598,12 +2599,10 @@ const FFCodec ff_aac_fixed_decoder = { .init = ff_aac_decode_init_fixed, .close = decode_close, FF_CODEC_DECODE_CB(aac_decode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.ch_layouts = ff_aac_ch_layout, + CODEC_CH_LAYOUTS_ARRAY(ff_aac_ch_layout), .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), .flush = flush, }; diff --git a/libavcodec/aac/aacdec.h b/libavcodec/aac/aacdec.h index b3763fdcc..978557668 100644 --- a/libavcodec/aac/aacdec.h +++ b/libavcodec/aac/aacdec.h @@ -43,6 +43,7 @@ #include "libavcodec/mpeg4audio.h" #include "aacdec_ac.h" +#include "aacdec_usac_mps212.h" typedef struct AACDecContext AACDecContext; @@ -229,6 +230,33 @@ typedef struct SingleChannelElement { }; } SingleChannelElement; +typedef struct AACUsacMPSData { + /* Framing */ + int framing_type; + int nb_param_sets; + int param_sets[MPS_MAX_PARAM_SETS]; + + /* OTT */ + AACMPSLosslessData ott[MPS_ELE_NB]; + int ott_idx[MPS_ELE_NB][MPS_MAX_PARAM_SETS][MPS_MAX_PARAM_BANDS]; + bool opd_smoothing_mode; + + /* SMG */ + int smooth_mode[MPS_MAX_PARAM_SETS]; + int smooth_time[MPS_MAX_PARAM_SETS]; + int freq_res_stride_smg[MPS_MAX_PARAM_SETS]; + bool smg_data[MPS_MAX_PARAM_SETS][MPS_MAX_PARAM_BANDS]; + + /* TSD */ + bool tsd_enable; + bool temp_shape_enable; + bool temp_shape_enable_ch[2]; + int16_t temp_shape_data[MPS_MAX_TIME_SLOTS]; + + int tsd_num_tr_slots; + int tsd_phase_data[64]; +} AACUsacMPSData; + typedef struct AACUsacStereo { uint8_t common_window; uint8_t common_tw; @@ -244,6 +272,8 @@ typedef struct AACUsacStereo { uint8_t pred_used[128]; + AACUsacMPSData mps; + INTFLOAT_ALIGNED_UNION(32, alpha_q_re, 1024); INTFLOAT_ALIGNED_UNION(32, alpha_q_im, 1024); INTFLOAT_ALIGNED_UNION(32, prev_alpha_q_re, 1024); @@ -332,6 +362,7 @@ typedef struct AACUsacElemConfig { uint8_t high_rate_mode : 1; /* bsHighRateMode */ uint8_t phase_coding : 1; /* bsPhaseCoding */ + uint8_t otts_bands_phase_present; /* bsOttBandsPhasePresent */ uint8_t otts_bands_phase; /* bsOttBandsPhase */ uint8_t residual_coding; /* bsResidualCoding */ uint8_t residual_bands; /* bsResidualBands */ diff --git a/libavcodec/aac/aacdec_ac.c b/libavcodec/aac/aacdec_ac.c index 7e5077cd1..5104604fa 100644 --- a/libavcodec/aac/aacdec_ac.c +++ b/libavcodec/aac/aacdec_ac.c @@ -91,10 +91,7 @@ uint32_t ff_aac_ac_get_pk(uint32_t c) void ff_aac_ac_update_context(AACArithState *state, int idx, uint16_t a, uint16_t b) { - state->cur[0] = a + b + 1; - if (state->cur[0] > 0xF) - state->cur[0] = 0xF; - + state->cur[0] = FFMIN(a + b + 1, 0xF); state->cur[3] = state->cur[2]; state->cur[2] = state->cur[1]; state->cur[1] = state->cur[0]; diff --git a/libavcodec/aac/aacdec_dsp_template.c b/libavcodec/aac/aacdec_dsp_template.c index 8d31af22f..b64944d54 100644 --- a/libavcodec/aac/aacdec_dsp_template.c +++ b/libavcodec/aac/aacdec_dsp_template.c @@ -185,7 +185,7 @@ static void AAC_RENAME(apply_tns)(void *_coef_param, TemporalNoiseShaping *tns, continue; // tns_decode_coef - compute_lpc_coefs(tns->AAC_RENAME(coef)[w][filt], order, lpc, 0, 0, 0); + compute_lpc_coefs(tns->AAC_RENAME(coef)[w][filt], 0, order, lpc, 0, 0, 0, NULL); start = ics->swb_offset[FFMIN(bottom, mmm)]; end = ics->swb_offset[FFMIN( top, mmm)]; diff --git a/libavcodec/aac/aacdec_latm.h b/libavcodec/aac/aacdec_latm.h index 047c11e0f..398d40741 100644 --- a/libavcodec/aac/aacdec_latm.h +++ b/libavcodec/aac/aacdec_latm.h @@ -339,12 +339,10 @@ const FFCodec ff_aac_latm_decoder = { .init = latm_decode_init, .close = decode_close, FF_CODEC_DECODE_CB(latm_decode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.ch_layouts = ff_aac_ch_layout, + CODEC_CH_LAYOUTS_ARRAY(ff_aac_ch_layout), .flush = flush, .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), }; diff --git a/libavcodec/aac/aacdec_lpd.c b/libavcodec/aac/aacdec_lpd.c index a4b91a510..93be7a74d 100644 --- a/libavcodec/aac/aacdec_lpd.c +++ b/libavcodec/aac/aacdec_lpd.c @@ -22,42 +22,6 @@ #include "aacdec_usac.h" #include "libavcodec/unary.h" -const uint8_t ff_aac_lpd_mode_tab[32][4] = { - { 0, 0, 0, 0 }, - { 1, 0, 0, 0 }, - { 0, 1, 0, 0 }, - { 1, 1, 0, 0 }, - { 0, 0, 1, 0 }, - { 1, 0, 1, 0 }, - { 0, 1, 1, 0 }, - { 1, 1, 1, 0 }, - { 0, 0, 0, 1 }, - { 1, 0, 0, 1 }, - { 0, 1, 0, 1 }, - { 1, 1, 0, 1 }, - { 0, 0, 1, 1 }, - { 1, 0, 1, 1 }, - { 0, 1, 1, 1 }, - { 1, 1, 1, 1 }, - { 2, 2, 0, 0 }, - { 2, 2, 1, 0 }, - { 2, 2, 0, 1 }, - { 2, 2, 1, 1 }, - { 0, 0, 2, 2 }, - { 1, 0, 2, 2 }, - { 0, 1, 2, 2 }, - { 1, 1, 2, 2 }, - { 2, 2, 2, 2 }, - { 3, 3, 3, 3 }, - /* Larger values are reserved, but permit them for resilience */ - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, -}; - static void parse_qn(GetBitContext *gb, int *qn, int nk_mode, int no_qn) { if (nk_mode == 1) { @@ -148,8 +112,6 @@ int ff_aac_parse_fac_data(AACUsacElemData *ce, GetBitContext *gb, int ff_aac_ldp_parse_channel_stream(AACDecContext *ac, AACUSACConfig *usac, AACUsacElemData *ce, GetBitContext *gb) { - int k; - const uint8_t *mod; int first_ldp_flag; ce->ldp.acelp_core_mode = get_bits(gb, 3); @@ -159,35 +121,10 @@ int ff_aac_ldp_parse_channel_stream(AACDecContext *ac, AACUSACConfig *usac, ce->ldp.core_mode_last = get_bits1(gb); ce->ldp.fac_data_present = get_bits1(gb); - mod = ff_aac_lpd_mode_tab[ce->ldp.lpd_mode]; - first_ldp_flag = !ce->ldp.core_mode_last; if (first_ldp_flag) ce->ldp.last_lpd_mode = -1; /* last_ldp_mode is a **STATEFUL** value */ - k = 0; - while (k < 0) { - if (!k) { - if (ce->ldp.core_mode_last && ce->ldp.fac_data_present) - ff_aac_parse_fac_data(ce, gb, 0, usac->core_frame_len/8); - } else { - if (!ce->ldp.last_lpd_mode && mod[k] > 0 || - ce->ldp.last_lpd_mode && !mod[k]) - ff_aac_parse_fac_data(ce, gb, 0, usac->core_frame_len/8); - } - if (!mod[k]) { -// parse_acelp_coding(); - ce->ldp.last_lpd_mode = 0; - k++; - } else { -// parse_tcx_coding(); - ce->ldp.last_lpd_mode = mod[k]; - k += (1 << (mod[k] - 1)); - } - } - -// parse_lpc_data(first_lpd_flag); - if (!ce->ldp.core_mode_last && ce->ldp.fac_data_present) { uint16_t len_8 = usac->core_frame_len / 8; uint16_t len_16 = usac->core_frame_len / 16; diff --git a/libavcodec/aac/aacdec_tab.c b/libavcodec/aac/aacdec_tab.c index 45a84a9a7..a78230e3f 100644 --- a/libavcodec/aac/aacdec_tab.c +++ b/libavcodec/aac/aacdec_tab.c @@ -258,17 +258,499 @@ static const int8_t sbr_vlc_offsets[10] = { -60, -60, -24, -24, -31, -31, -12, -12, -31, -12 }; + const VLCElem *ff_aac_sbr_vlc[10]; -static av_cold void aacdec_common_init(void) +static av_cold void init_sbr_tables(void) { - static VLCElem vlc_buf[(304 + 270 + 550 + 300 + 328 + - 294 + 306 + 268 + 510 + 366 + 462) + - (1098 + 1092 + 768 + 1026 + 1058 + + static VLCElem vlc_buf[(1098 + 1092 + 768 + 1026 + 1058 + 1052 + 544 + 544 + 592 + 512)]; VLCInitState state = VLC_INIT_STATE(vlc_buf); const uint8_t (*tab)[2] = sbr_huffman_tab; + // SBR VLC table initialization + for (int i = 0; i < FF_ARRAY_ELEMS(ff_aac_sbr_vlc); i++) { + ff_aac_sbr_vlc[i] = + ff_vlc_init_tables_from_lengths(&state, 9, sbr_huffman_nb_codes[i], + &tab[0][1], 2, + &tab[0][0], 2, 1, + sbr_vlc_offsets[i], 0); + tab += sbr_huffman_nb_codes[i]; + } +} + +const int16_t ff_aac_hcod_firstband_CLD[30][2] = { + { 2, 1 }, { 4, 3 }, { 6, 5 }, { 8, 7 }, { 10, 9 }, + { 12, 11 }, { 14, 13 }, { -8, 15 }, { -9, 16 }, { -10, 17 }, + { -18, 18 }, { -17, -19 }, { -16, 19 }, { -11, -20 }, { -15, -21 }, + { -7, 20 }, { -22, 21 }, { -12, -14 }, { -13, -23 }, { 23, 22 }, + { -24, -31 }, { -6, 24 }, { -25, -26 }, { 26, 25 }, { -5, -27 }, + { -28, 27 }, { -4, 28 }, { -29, 29 }, { -1, -30 }, { -2, -3 }, +}; + +const int16_t ff_aac_hcod1D_CLD[2 /* DT/DF */][30][2] = { + { { -1, 1 }, { -2, 2 }, { -3, 3 }, { -4, 4 }, { -5, 5 }, + { -6, 6 }, { -7, 7 }, { 9, 8 }, { -8, 10 }, { -9, 11 }, + { -10, 12 }, { -11, 13 }, { -12, 14 }, { -13, 15 }, { -14, 16 }, + { -15, 17 }, { -16, 18 }, { -17, 19 }, { -18, 20 }, { -19, -20 }, + { -21, 21 }, { -22, 22 }, { -23, 23 }, { 25, 24 }, { -24, 26 }, + { -25, 27 }, { 29, 28 }, { -26, -31 }, { -29, -30 }, { -27, -28 }, }, + { { -1, 1 }, { -2, 2 }, { -3, 3 }, { -4, 4 }, { -5, 5 }, + { -6, 6 }, { -7, 7 }, { -8, 8 }, { -9, 9 }, { -10, 10 }, + { -11, 11 }, { -12, 12 }, { -13, 13 }, { 15, 14 }, { -14, 16 }, + { -15, 17 }, { -16, 18 }, { -17, 19 }, { -18, 20 }, { -19, 21 }, + { -20, -21 }, { -23, 22 }, { -22, 23 }, { -24, 24 }, { -25, 25 }, + { 27, 26 }, { 29, 28 }, { -30, -31 }, { -28, -29 }, { -26, -27 }, }, +}; + +const int16_t ff_aac_hcod2D_CLD_03[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][15][2] = { + { { { -1, 1 }, { -52, 2 }, { 4, 3 }, { -2, 5 }, { -17, 6 }, + { -18, 7 }, { -36, -51 }, { 9, 8 }, { -35, 10 }, { -34, 11 }, + { -19, -33 }, { -3, 12 }, { -20, 13 }, { -50, 14 }, { -4, -49 }, }, + { { -1, 1 }, { -52, 2 }, { -17, 3 }, { 5, 4 }, { -36, 6 }, + { -33, 7 }, { -2, -18 }, { -20, 8 }, { 10, 9 }, { -34, -49 }, + { -51, 11 }, { -35, 12 }, { -19, 13 }, { -3, 14 }, { -4, -50 }, }, }, + { { { -1, 1 }, { -52, 2 }, { -17, 3 }, { 5, 4 }, { -2, -36 }, + { -18, 6 }, { 8, 7 }, { -51, 9 }, { -33, 10 }, { -34, 11 }, + { -20, -35 }, { -19, 12 }, { -3, 13 }, { -49, 14 }, { -4, -50 }, }, + { { 2, 1 }, { -1, -52 }, { 4, 3 }, { -2, 5 }, { -51, 6 }, + { -17, -18 }, { 8, 7 }, { 10, 9 }, { -3, -36 }, { -19, 11 }, + { -35, -50 }, { -34, 12 }, { -4, 13 }, { -33, 14 }, { -20, -49 }, }, }, +}; + +const int16_t ff_aac_hcod2D_CLD_05[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][35][2] = { + { { { 2, 1 }, { -86, 3 }, { 5, 4 }, { -1, 6 }, { 8, 7 }, + { -17, -18 }, { -2, 9 }, { -70, 10 }, { -85, 11 }, { 13, 12 }, + { -69, 14 }, { -34, 15 }, { 17, 16 }, { -19, 18 }, { -33, -35 }, + { -54, 19 }, { -53, 20 }, { -3, 21 }, { -68, 22 }, { -84, 23 }, + { -50, 24 }, { -52, 25 }, { -51, 26 }, { -20, -36 }, { -49, 27 }, + { -38, 28 }, { -37, 29 }, { -4, -83 }, { -67, 30 }, { -66, 31 }, + { -21, 32 }, { -22, -65 }, { -5, 33 }, { -82, 34 }, { -6, -81 }, }, + { { 2, 1 }, { 4, 3 }, { -86, 5 }, { -1, 6 }, { -17, 7 }, + { -70, 8 }, { 10, 9 }, { -18, 11 }, { -33, 12 }, { -54, 13 }, + { -2, 14 }, { -34, 15 }, { -38, 16 }, { -49, 17 }, { -85, 18 }, + { -50, 19 }, { -69, 20 }, { -53, -65 }, { -22, 21 }, { -66, 22 }, + { -19, 23 }, { -37, 24 }, { -35, -81 }, { -3, 25 }, { -51, 26 }, + { -68, -84 }, { -52, 27 }, { 29, 28 }, { -20, 30 }, { -4, -36 }, + { -83, 31 }, { -67, 32 }, { -21, 33 }, { -5, 34 }, { -6, -82 }, }, }, + { { { 2, 1 }, { -86, 3 }, { -1, 4 }, { -17, 5 }, { 7, 6 }, + { -70, 8 }, { -2, -18 }, { 10, 9 }, { 12, 11 }, { -85, 13 }, + { -33, 14 }, { -34, -54 }, { 16, 15 }, { -69, 17 }, { 19, 18 }, + { -50, -53 }, { -19, 20 }, { -38, 21 }, { -35, -49 }, { -3, 22 }, + { 24, 23 }, { -68, 25 }, { -84, 26 }, { -65, 27 }, { -51, -66 }, + { -22, -37 }, { -52, 28 }, { -20, 29 }, { -36, 30 }, { -81, 31 }, + { -4, -83 }, { -67, 32 }, { -21, 33 }, { -5, 34 }, { -6, -82 }, }, + { { 2, 1 }, { 4, 3 }, { -86, 5 }, { 7, 6 }, { 9, 8 }, + { -1, -2 }, { -85, 10 }, { -18, 11 }, { -17, 12 }, { 14, 13 }, + { -70, 15 }, { 17, 16 }, { -19, -69 }, { -84, 18 }, { -3, 19 }, + { 21, 20 }, { -34, -68 }, { -20, 22 }, { -35, 23 }, { -83, 24 }, + { -33, 25 }, { -4, 26 }, { -53, 27 }, { -54, -67 }, { -36, 28 }, + { -21, -52 }, { -82, 29 }, { -5, -50 }, { -51, 30 }, { -38, 31 }, + { -37, -49 }, { -6, 32 }, { -66, 33 }, { -65, 34 }, { -22, -81 }, }, }, +}; + +const int16_t ff_aac_hcod2D_CLD_07[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][63][2] = { + { { { 2, 1 }, { 4, 3 }, {-120, 5 }, { 7, 6 }, { 9, 8 }, + { -1, 10 }, { -18, 11 }, { -17, 12 }, { -2,-104 }, {-119, 13 }, + { 15, 14 }, {-103, 16 }, { 18, 17 }, { -34, 19 }, { -19, 20 }, + { 22, 21 }, { -35, 23 }, { -33, 24 }, { -88, 25 }, { -87, 26 }, + { 28, 27 }, { -3,-102 }, { -86, 29 }, { -52,-118 }, { 31, 30 }, + { -50, 32 }, { -51, 33 }, { -70, 34 }, { -36, 35 }, { -85, 36 }, + { -20, 37 }, { 39, 38 }, { -69, -71 }, { -72, 40 }, { -49, -67 }, + { 42, 41 }, { -68, 43 }, { -4,-101 }, { -53,-117 }, { -37, 44 }, + { -66, 45 }, { -55, 46 }, { 48, 47 }, { -54, 49 }, { -21, 50 }, + { -84,-100 }, { -56, -65 }, { 52, 51 }, { -82, -83 }, { 54, 53 }, + { -5,-116 }, { -22, 55 }, { -38, 56 }, { -39, -40 }, { 58, 57 }, + { -81,-115 }, { -98, -99 }, { -6, 59 }, { -23, 60 }, { -24, 61 }, + { -7, -97 }, {-114, 62 }, { -8,-113 }, }, + { { 2, 1 }, { 4, 3 }, { 6, 5 }, {-120, 7 }, { -17, 8 }, + { -1,-104 }, { 10, 9 }, { 12, 11 }, { -18, 13 }, { -33, -88 }, + { 15, 14 }, { 17, 16 }, { -2, 18 }, { -34, 19 }, { -72, 20 }, + { -49, 21 }, {-119, 22 }, { -50, 23 }, {-103, 24 }, { -56, 25 }, + { -65, 26 }, { 28, 27 }, { -40, -87 }, { -66, 29 }, { -82, 30 }, + { 32, 31 }, { -19, -81 }, { -71, 33 }, { -97, 34 }, { -35, -55 }, + { -24, 35 }, { 37, 36 }, { -3, -98 }, { -51, 38 }, { -67, 39 }, + { -39,-118 }, {-113, 40 }, {-102, 41 }, { -86, 42 }, { -70, -83 }, + { 44, 43 }, { -20, -54 }, { -52, 45 }, { -36, 46 }, { -4, 47 }, + { -68, 48 }, { -85, 49 }, {-101,-117 }, { -69, 50 }, { 52, 51 }, + { -21, -37 }, { -53, 53 }, { 55, 54 }, { -5,-100 }, {-116, 56 }, + { -84, 57 }, { -38, 58 }, { -22, -99 }, {-115, 59 }, { -6, 60 }, + { -23, 61 }, { -7, 62 }, {-114, 0 }, }, }, + { { { 2, 1 }, {-120, 3 }, { -1, 4 }, { 6, 5 }, { -17, 7 }, + {-104, 8 }, { -18, 9 }, { -2, 10 }, { 12, 11 }, { 14, 13 }, + {-119, 15 }, { -33, 16 }, { -34, -88 }, {-103, 17 }, { 19, 18 }, + { 21, 20 }, { 23, 22 }, { 25, 24 }, { -19, -72 }, { -50, 26 }, + { -49, 27 }, { -87, 28 }, { 30, 29 }, { 32, 31 }, { -3, -35 }, + { 34, 33 }, { -56, 35 }, { -65, -66 }, { -40, 36 }, { -82,-118 }, + { -71, 37 }, { -55, 38 }, { -67,-102 }, { -51, 39 }, { -70, 40 }, + { 42, 41 }, { -81, 43 }, { -86, 44 }, { -52, -97 }, { -98, 45 }, + { -24, -39 }, { -20, 46 }, { -54, -83 }, { -36, 47 }, { -85, 48 }, + { -68, 49 }, { -4, 50 }, { -69,-113 }, {-117, 51 }, { -37,-101 }, + { -53, 52 }, { -21, 53 }, { 55, 54 }, { -84,-100 }, { -5, 56 }, + {-116, 57 }, { -22, 58 }, { -38,-115 }, { 60, 59 }, { -6, -99 }, + { -23, 61 }, {-114, 62 }, { -7, -8 }, }, + { { 2, 1 }, { 4, 3 }, {-120, 5 }, { 7, 6 }, { 9, 8 }, + { 11, 10 }, { -1, 12 }, { -18,-119 }, { -2, 13 }, { 15, 14 }, + { -17, 16 }, {-104, 17 }, { 19, 18 }, { -19, 20 }, {-103, 21 }, + {-118, 22 }, { 24, 23 }, { -3, 25 }, { 27, 26 }, { -34, 28 }, + {-102, 29 }, { -20, 30 }, { -35, 31 }, { 33, 32 }, {-117, 34 }, + { -33, 35 }, { -88, 36 }, { -4, 37 }, { -87, 38 }, { 40, 39 }, + { -36,-101 }, { -86, 41 }, { -21, -37 }, { -85,-100 }, { -52, 42 }, + { -22, 43 }, {-116, 44 }, { -50 , 45 }, { 47, 46 }, { -5, -51 }, + {-115, 48 }, { -70, 49 }, { -84, 50 }, { -38, -49 }, { -72, -99 }, + { -53, 51 }, { -69, -71 }, { -23, 52 }, { -6, -67 }, {-114, 53 }, + { -7, 54 }, { -66, -68 }, { -55, 55 }, { 57, 56 }, { -54, -65 }, + { -8, -56 }, { -82, -83 }, { 59, 58 }, { -39, -40 }, { -81, 60 }, + { -98, 61 }, { -97, 62 }, { -24,-113 }, }, }, +}; + +const int16_t ff_aac_hcod2D_CLD_09[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][99][2] = { + { { { 2, 1 }, { 4, 3 }, {-154, 5 }, { 7, 6 }, { 9, 8 }, + { 11, 10 }, { -1, 12 }, { -18, 13 }, { -17, 14 }, { -2,-138 }, + { 16, 15 }, {-153, 17 }, {-137, 18 }, { 20, 19 }, { 22, 21 }, + { -34, 23 }, { -19, 24 }, { -35, 25 }, { 27, 26 }, { 29, 28 }, + {-121, 30 }, {-120, 31 }, {-136, 32 }, { -33,-122 }, { 34, 33 }, + {-152, 35 }, { -3, 36 }, { -51, 37 }, { -52, 38 }, { -69, 39 }, + { -36, 40 }, { -50, 41 }, { 43, 42 }, { -20, 44 }, {-104, 45 }, + {-103, 46 }, { -87, 47 }, {-119, 48 }, {-105, 49 }, { -86, 50 }, + {-102, 51 }, {-106, 52 }, { -49,-135 }, { -68, 53 }, { 55, 54 }, + { -53, 56 }, { -67,-151 }, { -4, 57 }, { -84, 58 }, { -85, 59 }, + { -66, 60 }, { -37, 61 }, { -70, 62 }, { -54, -88 }, { -21, 63 }, + { 65, 64 }, { -89, 66 }, {-118, 67 }, { -72, 68 }, { -90, 69 }, + { -71, 70 }, { -65,-134 }, {-150, 71 }, { -83, 72 }, { -5, 73 }, + {-101,-117 }, { -82, 74 }, { 76, 75 }, { -99, 77 }, { -38, 78 }, + {-100, 79 }, { -22, 80 }, { -73, 81 }, { -39, -74 }, { 83, 82 }, + { -55, -81 }, { -57, 84 }, {-133,-149 }, { -56, 85 }, { -6, 86 }, + { -98, 87 }, {-132, 88 }, { -23, 89 }, {-114, 90 }, {-116, 91 }, + { -58,-115 }, { -24, 92 }, { -97,-148 }, { -40, -41 }, { -7, -42 }, + {-147, 93 }, { 95, 94 }, {-131, 96 }, { -8,-130 }, { -25,-113 }, + { -9, 97 }, { -26,-129 }, {-146, 98 }, { -10,-145 }, }, + { { 2, 1 }, { 4, 3 }, { 6, 5 }, {-154, 7 }, { 9, 8 }, + { -17, 10 }, {-138, 11 }, { -1, 12 }, { 14, 13 }, { 16, 15 }, + { -33,-122 }, { -18, 17 }, { 19, 18 }, { -34, 20 }, { -2, 21 }, + {-106, 22 }, { -49, 23 }, { 25, 24 }, { -50, 26 }, {-153, 27 }, + { -90, 28 }, {-137, 29 }, { -65, 30 }, { 32, 31 }, { -66, 33 }, + {-121, 34 }, { -74, 35 }, { -81, 36 }, { 38, 37 }, { -42, 39 }, + { -82, 40 }, {-105, 41 }, { -19,-114 }, { -58, 42 }, { -35, 43 }, + { -97, 44 }, { 46, 45 }, {-129, 47 }, { -26, -89 }, { -57, -98 }, + { -51, 48 }, { -3, 49 }, {-113, 50 }, {-130, 51 }, {-152, 52 }, + { -67, -73 }, { -99,-136 }, {-145, 53 }, {-120, 54 }, { -41, 55 }, + { -83, 56 }, { -72, 57 }, {-104, 58 }, {-115, 59 }, { -20, 60 }, + { 62, 61 }, { -36, -88 }, { -84, 63 }, { -52, -56 }, { 65, 64 }, + { -4, -87 }, { -68, 66 }, {-151, 67 }, {-100,-135 }, { 69, 68 }, + { -69,-119 }, {-103, 70 }, { -71, 71 }, { 73, 72 }, { -21, 74 }, + { -85, 75 }, { -37, -53 }, { -86, 76 }, { 78, 77 }, {-102,-150 }, + { -5, 79 }, {-134, 80 }, {-118, 81 }, { -54,-117 }, { 83, 82 }, + { -38, -70 }, { -22, 84 }, { -6, 85 }, { 87, 86 }, { -55, 88 }, + {-101, 89 }, {-133,-149 }, { -24, -39 }, { 91, 90 }, {-132, 92 }, + { -23, 93 }, { -7, 94 }, {-147,-148 }, {-116,-131 }, { -25, 95 }, + { -40, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, }, }, + { { { 2, 1 }, {-154, 3 }, { 5, 4 }, { -1, 6 }, { 8, 7 }, + { -17, 9 }, {-138, 10 }, { -18, 11 }, { -2, 12 }, { 14, 13 }, + { 16, 15 }, {-153, 17 }, { -34, 18 }, { -33,-122 }, { 20, 19 }, + { 22, 21 }, {-137, 23 }, { 25, 24 }, { 27, 26 }, {-106, 28 }, + { 30, 29 }, { -50, 31 }, { -19, 32 }, { -49,-121 }, { 34, 33 }, + { 36, 35 }, { -35, 37 }, { -90, 38 }, { -66, 39 }, { -3, 40 }, + { 42, 41 }, { -65, 43 }, {-105, 44 }, { 46, 45 }, { -74, 47 }, + { -51, 48 }, { -82,-152 }, {-136, 49 }, { -81, 50 }, { -42, -89 }, + {-114, 51 }, { 53, 52 }, { -57, -58 }, {-120, 54 }, { -98, 55 }, + { -67, 56 }, { -97, 57 }, { 59, 58 }, { -99, 60 }, { -73,-104 }, + { -72, 61 }, {-113, 62 }, { -20, -83 }, { -84,-130 }, { -36, 63 }, + { -26, 64 }, { -41, 65 }, { -52,-129 }, { -87, -88 }, { 67, 66 }, + {-115, 68 }, { -68, 69 }, { -56, -69 }, { -4,-100 }, {-151, 70 }, + {-135, 71 }, {-103,-119 }, { 73, 72 }, { -71,-145 }, {-102, 74 }, + { 76, 75 }, { -53, -85 }, { -37, 77 }, { -21, -86 }, { 79, 78 }, + { -5, 80 }, { -54,-134 }, {-150, 81 }, {-118, 82 }, { -70, 83 }, + {-117, 84 }, { -22, -38 }, {-101, 85 }, { -55, 86 }, {-149, 87 }, + { -39, 88 }, {-133, 89 }, { -6, 90 }, {-116, 91 }, { -24, 92 }, + { -7,-132 }, { -23, 93 }, { -40, 94 }, {-131,-148 }, { -25, 95 }, + {-147, 96 }, {-146, 97 }, { -8, 0 }, { 0, 0 }, }, + { { 2, 1 }, { 4, 3 }, { 6, 5 }, {-154, 7 }, { 9, 8 }, + { 11, 10 }, { 13, 12 }, { 15, 14 }, { -18, 16 }, {-153, 17 }, + { -1, -2 }, { 19, 18 }, {-138, 20 }, { -17, 21 }, { 23, 22 }, + { 25, 24 }, { -19,-137 }, { 27, 26 }, {-152, 28 }, { 30, 29 }, + { -3, -34 }, { 32, 31 }, { 34, 33 }, { 36, 35 }, {-136, 37 }, + { -35, 38 }, { -20, 39 }, {-122, 40 }, {-151, 41 }, { -33, 42 }, + {-121, 43 }, { 45, 44 }, { 47, 46 }, { -4, 48 }, { -36,-120 }, + {-135, 49 }, { 51, 50 }, { -21, 52 }, { 54, 53 }, { 56, 55 }, + { -50,-150 }, { 58, 57 }, { -51, 59 }, { 61, 60 }, {-119, 62 }, + { -52, 63 }, { -5, 64 }, { -37, 65 }, {-117,-134 }, { -39, -54 }, + { -22, 66 }, {-106, 67 }, { -69,-102 }, {-132, 68 }, {-105, 69 }, + { -49, 70 }, {-149, 71 }, { -24,-104 }, { 73, 72 }, { -53, 74 }, + { -38,-118 }, {-103, 75 }, { -6, 76 }, { -66, -87 }, {-133,-147 }, + { -23, 77 }, { -67, 78 }, { -68, -86 }, { -70,-101 }, { -40,-148 }, + {-116, 79 }, { -55, 80 }, { -84,-131 }, { 82, 81 }, { -89, -90 }, + { -7, -25 }, { -85, -88 }, { -65, 83 }, { -72,-146 }, { 85, 84 }, + { -9, -71 }, { -83, 86 }, { -82, 87 }, { -8, 88 }, {-100, 89 }, + { -74, -99 }, { -73, 90 }, { -10, -81 }, { -56, 91 }, { -57, -98 }, + { 93, 92 }, { -58,-114 }, { -97,-115 }, { 95, 94 }, { -41, 96 }, + { -42, 97 }, { -26,-129 }, {-113, 98 }, {-130,-145 }, }, + }, +}; + +const int16_t ff_aac_hcod_firstband_ICC[7][2] = { + { 2, 1 }, { -5, 3 }, { -4, -6 }, { -3, 4 }, { -2, 5 }, + { -1, 6 }, { -7, -8 }, +}; + +const int16_t ff_aac_hcod1D_ICC[7][2] = { + { -1, 1 }, { -2, 2 }, { -3, 3 }, { -4, 4 }, { -5, 5 }, + { -6, 6 }, { -7, -8 }, +}; + +const int16_t ff_aac_hcod2D_ICC_01[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][3][2] = { + { { { -1, 1 }, { -18, 2 }, { -2, -17 }, }, + { { -1, 1 }, { -18, 2 }, { -2, -17 }, }, }, + { { { -1, 1 }, { -18, 2 }, { -2, -17 }, }, + { { -1, 1 }, { -18, 2 }, { -2, -17 }, }, }, +}; + +const int16_t ff_aac_hcod2D_ICC_03[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][15][2] = { + { { { -52, 1 }, { -1, 2 }, { 4, 3 }, { -2, 5 }, { -17, -18 }, + { -51, 6 }, { -36, 7 }, { 9, 8 }, { -35, 10 }, { -3, 11 }, + { -19, -34 }, { -33, 12 }, { -50, 13 }, { -20, 14 }, { -4, -49 }, }, + { { 2, 1 }, { -1, -52 }, { -17, 3 }, { 5, 4 }, { -36, 6 }, + { -2, 7 }, { -18, -33 }, { 9, 8 }, { -20, 10 }, { -34, -51 }, + { -49, 11 }, { -35, 12 }, { -19, 13 }, { -3, 14 }, { -4, -50 }, }, }, + { { { -52, 1 }, { -1, 2 }, { 4, 3 }, { -2, -17 }, { -18, 5 }, + { -36, 6 }, { -51, 7 }, { 9, 8 }, { -33, 10 }, { -34, 11 }, + { -35, 12 }, { -19, -20 }, { -3, 13 }, { -49, 14 }, { -4, -50 }, }, + { { 2, 1 }, { -1, -52 }, { -2, 3 }, { 5, 4 }, { -51, 6 }, + { -18, 7 }, { -17, 8 }, { -3, 9 }, { -36, 10 }, { -19, -50 }, + { -35, 11 }, { -4, 12 }, { -34, 13 }, { -33, 14 }, { -20, -49 }, },}, +}; + +const int16_t ff_aac_hcod2D_ICC_05[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][35][2] = { + { { { 2, 1 }, { -86, 3 }, { -1, 4 }, { 6, 5 }, { -18, 7 }, + { -2, -17 }, { 9, 8 }, { -70, 10 }, { -69, -85 }, { -35, 11 }, + { 13, 12 }, { -34, 14 }, { -19, 15 }, { -53, 16 }, { -68, 17 }, + { -33, 18 }, { -3, -52 }, { 20, 19 }, { -54, 21 }, { -84, 22 }, + { -50, 23 }, { -20, -51 }, { -36, 24 }, { 26, 25 }, { -83, 27 }, + { -4, -38 }, { -49, 28 }, { -37, 29 }, { -67, 30 }, { -5, 31 }, + { -21, 32 }, { -65, -66 }, { -82, 33 }, { -22, 34 }, { -6, -81 }, }, + { { 2, 1 }, { -86, 3 }, { -1, 4 }, { -17, 5 }, { 7, 6 }, + { -70, 8 }, { -33, 9 }, { -18, 10 }, { -2, 11 }, { -54, 12 }, + { -49, 13 }, { -38, 14 }, { -34, -65 }, { -85, 15 }, { -50, 16 }, + { -69, 17 }, { -22, 18 }, { -53, 19 }, { 21, 20 }, { -19, -81 }, + { -66, 22 }, { -3, -35 }, { 24, 23 }, { -37, 25 }, { -68, -84 }, + { -51, 26 }, { 28, 27 }, { -20, -52 }, { 30, 29 }, { -4, -36 }, + { -83, 31 }, { -67, 32 }, { -82, 33 }, { -21, 34 }, { -5, -6 }, }, }, + { { { -1, 1 }, { -86, 2 }, { 4, 3 }, { -17, 5 }, { -2, 6 }, + { -18, 7 }, { -70, 8 }, { -85, 9 }, { 11, 10 }, { 13, 12 }, + { -33, 14 }, { 16, 15 }, { -34, -54 }, { -69, 17 }, { -38, 18 }, + { -50, 19 }, { -35, -53 }, { -49, 20 }, { -19, 21 }, { -3, 22 }, + { -65, 23 }, { -68, 24 }, { -22, 25 }, { -81, -84 }, { -66, 26 }, + { -37, 27 }, { -20, -51 }, { 29, 28 }, { -52, 30 }, { -4, -83 }, + { -36, 31 }, { -67, 32 }, { -5, 33 }, { -82, 34 }, { -21, 0 }, }, + { { 2, 1 }, { -86, 3 }, { -1, 4 }, { 6, 5 }, { -2, 7 }, + { -85, 8 }, { -18, 9 }, { 11, 10 }, { -17, 12 }, { 14, 13 }, + { -70, 15 }, { -3, -19 }, { -69, 16 }, { -84, 17 }, { -68, 18 }, + { -20, -35 }, { -34, -83 }, { 20, 19 }, { -4, 21 }, { -33, 22 }, + { -5, 23 }, { -53, 24 }, { -36, -52 }, { -67, 25 }, { -21, -82 }, + { -54, 26 }, { -6, 27 }, { -51, 28 }, { -50, 29 }, { -49, 30 }, + { -37, 31 }, { -38, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, }, }, +}; + +const int16_t ff_aac_hcod2D_ICC_07[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][63][2] = { + { { { 2, 1 }, { -1,-120 }, { 4, 3 }, { 6, 5 }, { -18, 7 }, + { 9, 8 }, { -17, 10 }, { -2, 11 }, {-103, 12 }, { -52, 13 }, + { -35,-104 }, {-119, 14 }, { 16, 15 }, { -69, -86 }, { 18, 17 }, + { -34, 19 }, { -19, 20 }, { 22, 21 }, { -70, 23 }, { -87, 24 }, + {-102, 25 }, { -85, 26 }, { -33, 27 }, { -36, 28 }, { -3, 29 }, + { -88, 30 }, { -51, 31 }, {-118, 32 }, { 34, 33 }, { -68, 35 }, + { -53, 36 }, { -67, 37 }, { -20, 38 }, {-101, 39 }, { -50, 40 }, + { 42, 41 }, { -37, 43 }, {-116, 44 }, {-117, 45 }, { -49, 46 }, + { -21,-100 }, { 48, 47 }, { -55, -71 }, { -4, 49 }, { -22, -84 }, + {-115, 50 }, { -66, -82 }, { -72, 51 }, { -5, -6 }, { -54, 52 }, + { -38, 53 }, { -83, 54 }, { -40, 55 }, { -39, 56 }, { -99, 57 }, + { -23, -56 }, { -7, 58 }, { -65, -97 }, { -8, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, }, + { { 2, 1 }, { 4, 3 }, { -1,-120 }, { 6, 5 }, { 8, 7 }, + { -18, 9 }, { -2, 10 }, { 12, 11 }, { 14, 13 }, { -17,-119 }, + { 16, 15 }, {-103, 17 }, {-104, 18 }, { -52, 19 }, { 21, 20 }, + { -69, 22 }, { 24, 23 }, { -3, -35 }, { -19, 25 }, { -34, -85 }, + { 27, 26 }, { -86, 28 }, {-118, 29 }, { -37, 30 }, { 32, 31 }, + {-102, 33 }, { -20, -22 }, { -4,-117 }, { -87, 34 }, {-100, 35 }, + { -33, -36 }, { 37, 36 }, { -70, -88 }, {-101, 38 }, { -5, 39 }, + { -51, -53 }, { -50, 40 }, {-115, 41 }, { -21, 42 }, {-116, 43 }, + { -38, 44 }, { -23, -84 }, { -49, -99 }, { 46, 45 }, { -6,-114 }, + { -7, -72 }, { -71, 47 }, { -8, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, }, }, + { { { -1, 1 }, {-120, 2 }, { 4, 3 }, { -17, 5 }, { -2, 6 }, + { 8, 7 }, { -18, 9 }, {-104, 10 }, { 12, 11 }, { 14, 13 }, + { 16, 15 }, {-119, 17 }, { -81, 18 }, { 20, 19 }, { -33, 21 }, + { -88, 22 }, {-103, 23 }, { -34, 24 }, { -56, 25 }, { -72, 26 }, + { -49, 27 }, { -82, 28 }, { -50, 29 }, { -65, 30 }, { -55, -87 }, + { -19, 31 }, { -67, 32 }, { -35, -40 }, { 34, 33 }, { -52, -71 }, + { -66, 35 }, { -70, 36 }, { 38, 37 }, { -51, -97 }, { -86,-102 }, + { -3, 39 }, {-118, 40 }, { 42, 41 }, { -24, -85 }, { -54, 43 }, + { -39, 44 }, { -98,-113 }, { -36, -37 }, { -20, -69 }, { -4, 45 }, + { -5, 46 }, { -21, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, }, + { { 2, 1 }, { 4, 3 }, { -1,-120 }, { 6, 5 }, { 8, 7 }, + { -18, 9 }, { -2, 10 }, { 12, 11 }, { 14, 13 }, { -17,-119 }, + { 16, 15 }, {-103, 17 }, {-104, 18 }, { -52, 19 }, { 21, 20 }, + { -69, 22 }, { 24, 23 }, { -3, -35 }, { -19, 25 }, { -34, -85 }, + { 27, 26 }, { -86, 28 }, {-118, 29 }, { -37, 30 }, { 32, 31 }, + {-102, 33 }, { -20, -22 }, { -4,-117 }, { -87, 34 }, {-100, 35 }, + { -33, -36 }, { 37, 36 }, { -70, -88 }, {-101, 38 }, { -5, 39 }, + { -51, -53 }, { -50, 40 }, {-115, 41 }, { -21, 42 }, {-116, 43 }, + { -38, 44 }, { -23, -84 }, { -49, -99 }, { 46, 45 }, { -6,-114 }, + { -7, -72 }, { -71, 47 }, { -8, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 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 int16_t ff_aac_hcod_firstband_IPD[7][2] = { + { -1, 1 }, { -8, 2 }, { -2, 3 }, { 5, 4 }, { -7, 6 }, + { -3, -5 }, { -4, -6 }, +}; + +const int16_t ff_aac_hcod1D_IPD[2 /* DT, DF */ ][7][2] = { + { { -1, 1 }, { -2, 2 }, { -8, 3 }, { -3, 4 }, { -7, 5 }, + { -4, 6 }, { -5, -6 }, }, /* DT */ + { { -1, 1 }, { -8, 2 }, { -2, 3 }, { 5, 4 }, { -3, -7 }, + { -6, 6 }, { -4, -5 }, }, /* DF */ +}; + +const int16_t ff_aac_hcod2D_IPD_01[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][3][2] = { + { { { -1, 1 }, { -18, 2 }, { -17, 0 }, }, + { { -1, 1 }, { -18, 2 }, { -17, 0 }, }, }, + { { { -1, 1 }, { -18, 2 }, { -17, 0 }, }, + { { -1, 1 }, { -18, 2 }, { -17, 0 }, }, }, +}; + +const int16_t ff_aac_hcod2D_IPD_03[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][15][2] = { + { { { -1, 1 }, { 3, 2 }, { -18, 4 }, { -52, 5 }, { -34, -36 }, + { -35, 6 }, { -17, 7 }, { -33, 8 }, { -20, 9 }, { -49, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, }, + { { -1, 1 }, { -36, 2 }, { -18, 3 }, { -35, 4 }, { -52, 5 }, + { 7, 6 }, { -34, 8 }, { -33, -49 }, { -20, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, }, }, + { { { -1, 1 }, { 3, 2 }, { -18, 4 }, { -52, 5 }, { -34, -36 }, + { -35, 6 }, { -17, 7 }, { -33, 8 }, { -20, 9 }, { -49, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, }, + { { -1, 1 }, { -36, 2 }, { -18, 3 }, { -35, 4 }, { -52, 5 }, + { 7, 6 }, { -34, 8 }, { -33, -49 }, { -20, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, }, }, +}; + +const int16_t ff_aac_hcod2D_IPD_05[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][35][2] = { + { { { -1, 1 }, { 3, 2 }, { -52, 4 }, { -86, 5 }, { -35, 6 }, + { -53, 7 }, { -70, 8 }, { -17, 9 }, { -37, 10 }, { 12, 11 }, + { -38, -66 }, { -18, 13 }, { -51, 14 }, { 16, 15 }, { -34, -69 }, + { 18, 17 }, { -54, -65 }, { -50, 19 }, { -33, -49 }, { -22, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, }, + { { -1, 1 }, { 3, 2 }, { 5, 4 }, { -86, 6 }, { -66, 7 }, + { 9, 8 }, { 11, 10 }, { -18, 12 }, { -51, 13 }, { -37, -52 }, + { -69, 14 }, { -38, 15 }, { -53, 16 }, { -35, 17 }, { -50, -70 }, + { -22, -49 }, { -33, 18 }, { -17, 19 }, { -34, -65 }, { -81, 20 }, + { -54, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, }, }, + { { { -1, 1 }, { 3, 2 }, { -52, 4 }, { -86, 5 }, { -35, 6 }, + { -53, 7 }, { -70, 8 }, { -17, 9 }, { -37, 10 }, { 12, 11 }, + { -38, -66 }, { -18, 13 }, { -51, 14 }, { 16, 15 }, { -34, -69 }, + { 18, 17 }, { -54, -65 }, { -50, 19 }, { -33, -49 }, { -22, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, }, + { { -1, 1 }, { 3, 2 }, { 5, 4 }, { -86, 6 }, { -66, 7 }, + { 9, 8 }, { 11, 10 }, { -18, 12 }, { -51, 13 }, { -37, -52 }, + { -69, 14 }, { -38, 15 }, { -53, 16 }, { -35, 17 }, { -50, -70 }, + { -22, -49 }, { -33, 18 }, { -17, 19 }, { -34, -65 }, { -81, 20 }, + { -54, 0 }, { 0, 0 }, { 0, 0 }, { 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 int16_t ff_aac_hcod2D_IPD_07[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][63][2] = { + { { { -1, 1 }, { -69, 2 }, { 4, 3 }, {-120, 5 }, { 7, 6 }, + {-113, 8 }, { -68, 9 }, { 11, 10 }, { -17, 12 }, { -52, 13 }, + { -24, 14 }, { -18, 15 }, { 17, 16 }, {-104, 18 }, { 20, 19 }, + { -54, -70 }, { 22, 21 }, { 24, 23 }, { -86, -97 }, {-103, 25 }, + { -83, 26 }, { -35, 27 }, { -34, -98 }, { -40, 28 }, { -39, -67 }, + { 30, 29 }, { -33, -51 }, { -87, 31 }, { -88, 32 }, { -82, 33 }, + { -55, -81 }, { -56, -71 }, { -72, 34 }, { -50, -66 }, { -65, 35 }, + { -49, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, }, + { { 2, 1 }, { 4, 3 }, { -1, 5 }, { -69, 6 }, {-120, 7 }, + { -68, 8 }, { 10, 9 }, { 12, 11 }, { 14, 13 }, { -52, -54 }, + { -18, 15 }, { -70, 16 }, { -67, 17 }, { 19, 18 }, { -17, 20 }, + {-113, 21 }, { 23, 22 }, { -83, 24 }, { -24, 25 }, {-103,-104 }, + { -51, -55 }, { 27, 26 }, { -71, 28 }, { -86, 29 }, { -35, 30 }, + { -66, 31 }, { -39, -50 }, { -82, -98 }, { -72, 32 }, { -56, -87 }, + { -34, 33 }, { -33, -88 }, { -40, -97 }, { -65, 34 }, { -49, 35 }, + { -81, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, }, }, + { { { -1, 1 }, { -69, 2 }, { 4, 3 }, {-120, 5 }, { 7, 6 }, + {-113, 8 }, { -68, 9 }, { 11, 10 }, { -17, 12 }, { -52, 13 }, + { -24, 14 }, { -18, 15 }, { 17, 16 }, {-104, 18 }, { 20, 19 }, + { -54, -70 }, { 22, 21 }, { 24, 23 }, { -86, -97 }, {-103, 25 }, + { -83, 26 }, { -35, 27 }, { -34, -98 }, { -40, 28 }, { -39, -67 }, + { 30, 29 }, { -33, -51 }, { -87, 31 }, { -88, 32 }, { -82, 33 }, + { -55, -81 }, { -56, -71 }, { -72, 34 }, { -50, -66 }, { -65, 35 }, + { -49, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, }, + { { 2, 1 }, { 4, 3 }, { -1, 5 }, { -69, 6 }, {-120, 7 }, + { -68, 8 }, { 10, 9 }, { 12, 11 }, { 14, 13 }, { -52, -54 }, + { -18, 15 }, { -70, 16 }, { -67, 17 }, { 19, 18 }, { -17, 20 }, + {-113, 21 }, { 23, 22 }, { -83, 24 }, { -24, 25 }, {-103,-104 }, + { -51, -55 }, { 27, 26 }, { -71, 28 }, { -86, 29 }, { -35, 30 }, + { -66, 31 }, { -39, -50 }, { -82, -98 }, { -72, 32 }, { -56, -87 }, + { -34, 33 }, { -33, -88 }, { -40, -97 }, { -65, 34 }, { -49, 35 }, + { -81, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 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 int16_t ff_aac_hcod_lav_idx[3][2] = { + { -1, 1 }, { -2, 2 }, { -3, -4 }, +}; + +const int16_t ff_aac_hcod2D_reshape[39][2] = { + { 2, 1 }, { 4, 3 }, { 6, 5 }, { -33, 7 }, { -17, 8 }, + { -49, 9 }, { -34, 10 }, { 12, 11 }, { -18, -35 }, { -50, 13 }, + { 15, 14 }, { -40, 16 }, { -36, 17 }, { -19, 18 }, { -1, -37 }, + { -51, 19 }, { 21, 20 }, { -38, -65 }, { -2, -39 }, { -20, 22 }, + { -52, 23 }, { 25, 24 }, { -21, 26 }, { -66, 27 }, { -53, 28 }, + { -3, 29 }, { 31, 30 }, { -22, 32 }, { -54, 33 }, { -4, 34 }, + { -56, 35 }, { -24, -67 }, { -23, -55 }, { -8, -72 }, { -5, 36 }, + { -68, 37 }, { -6, 38 }, { -7, -69 }, { -70, -71 }, +}; + +const uint8_t ff_aac_lav_tab_XXX[3][4] = { + { 3, 5, 7, 9 }, { 1, 3, 5, 7 }, { 7, 1, 3, 5 } +}; + +static av_cold void init_base_tables(void) +{ + static VLCElem vlc_buf[(304 + 270 + 550 + 300 + 328 + + 294 + 306 + 268 + 510 + 366 + 462)]; + VLCInitState state = VLC_INIT_STATE(vlc_buf); + for (unsigned i = 0; i < 11; i++) { #define TAB_WRAP_SIZE(name) name[i], sizeof(name[i][0]), sizeof(name[i][0]) ff_vlc_spectral[i] = @@ -287,17 +769,12 @@ static av_cold void aacdec_common_init(void) ff_aac_scalefactor_code, sizeof(ff_aac_scalefactor_code[0]), sizeof(ff_aac_scalefactor_code[0]), 0); +} - // SBR VLC table initialization - for (int i = 0; i < FF_ARRAY_ELEMS(ff_aac_sbr_vlc); i++) { - ff_aac_sbr_vlc[i] = - ff_vlc_init_tables_from_lengths(&state, 9, sbr_huffman_nb_codes[i], - &tab[0][1], 2, - &tab[0][0], 2, 1, - sbr_vlc_offsets[i], 0); - tab += sbr_huffman_nb_codes[i]; - } - +static av_cold void aacdec_common_init(void) +{ + init_base_tables(); + init_sbr_tables(); ff_ps_init_common(); } diff --git a/libavcodec/aac/aacdec_tab.h b/libavcodec/aac/aacdec_tab.h index 70e49af20..e4b57527a 100644 --- a/libavcodec/aac/aacdec_tab.h +++ b/libavcodec/aac/aacdec_tab.h @@ -50,6 +50,33 @@ extern const uint8_t ff_aac_channel_layout_map[16][16][3]; extern const int16_t ff_aac_channel_map[3][4][6]; extern const AVChannelLayout ff_aac_ch_layout[]; + +extern const int16_t ff_aac_hcod_firstband_CLD[30][2]; +extern const int16_t ff_aac_hcod1D_CLD[2 /* DT_/DF_ */][30][2]; +extern const int16_t ff_aac_hcod2D_CLD_03[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][15][2]; +extern const int16_t ff_aac_hcod2D_CLD_05[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][35][2]; +extern const int16_t ff_aac_hcod2D_CLD_07[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][63][2]; +extern const int16_t ff_aac_hcod2D_CLD_09[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][99][2]; + +extern const int16_t ff_aac_hcod_firstband_ICC[7][2]; +extern const int16_t ff_aac_hcod1D_ICC[7][2]; +extern const int16_t ff_aac_hcod2D_ICC_01[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][3][2]; +extern const int16_t ff_aac_hcod2D_ICC_03[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][15][2]; +extern const int16_t ff_aac_hcod2D_ICC_05[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][35][2]; +extern const int16_t ff_aac_hcod2D_ICC_07[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][63][2]; + +extern const int16_t ff_aac_hcod_firstband_IPD[7][2]; +extern const int16_t ff_aac_hcod1D_IPD[2 /* DF, DT */ ][7][2]; +extern const int16_t ff_aac_hcod2D_IPD_01[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][3][2]; +extern const int16_t ff_aac_hcod2D_IPD_03[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][15][2]; +extern const int16_t ff_aac_hcod2D_IPD_05[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][35][2]; +extern const int16_t ff_aac_hcod2D_IPD_07[2 /* _TP/_FP */ ][2 /* DT_/DF_ */ ][63][2]; + +extern const int16_t ff_aac_hcod_lav_idx[3][2]; + +extern const int16_t ff_aac_hcod2D_reshape[39][2]; + +extern const uint8_t ff_aac_lav_tab_XXX[3][4]; FF_VISIBILITY_POP_HIDDEN #endif /* AVCODEC_AAC_AACDEC_TAB_H */ diff --git a/libavcodec/aac/aacdec_usac.c b/libavcodec/aac/aacdec_usac.c index ac68e54ae..2f4db63ba 100644 --- a/libavcodec/aac/aacdec_usac.c +++ b/libavcodec/aac/aacdec_usac.c @@ -29,7 +29,9 @@ #include "libavcodec/unary.h" #include "libavutil/mem.h" -#include "libavcodec/refstruct.h" +#include "libavutil/refstruct.h" + +#include "aacdec_usac_mps212.h" /* Number of scalefactor bands per complex prediction band, equal to 2. */ #define SFB_PER_PRED_BAND 2 @@ -213,8 +215,6 @@ static int decode_usac_element_pair(AACDecContext *ac, if (e->stereo_config_index) { e->mps.freq_res = get_bits(gb, 3); /* bsFreqRes */ - if (!e->mps.freq_res) - return AVERROR_INVALIDDATA; /* value 0 is reserved */ int numBands = ((int[]){0,28,20,14,10,7,5,4})[e->mps.freq_res]; // ISO/IEC 23003-1:2007, 5.2, Table 39 e->mps.fixed_gain = get_bits(gb, 3); /* bsFixedGainDMX */ @@ -223,8 +223,9 @@ static int decode_usac_element_pair(AACDecContext *ac, e->mps.high_rate_mode = get_bits1(gb); /* bsHighRateMode */ e->mps.phase_coding = get_bits1(gb); /* bsPhaseCoding */ + e->mps.otts_bands_phase_present = get_bits1(gb); int otts_bands_phase = ((int[]){0,10,10,7,5,3,2,2})[e->mps.freq_res]; // Table 109 — Default value of bsOttBandsPhase - if (get_bits1(gb)) { /* bsOttBandsPhasePresent */ + if (e->mps.otts_bands_phase_present) { /* bsOttBandsPhasePresent */ otts_bands_phase = get_bits(gb, 5); /* bsOttBandsPhase */ if (otts_bands_phase > numBands) return AVERROR_INVALIDDATA; @@ -1360,6 +1361,164 @@ static void spectrum_decode(AACDecContext *ac, AACUSACConfig *usac, } } +static const uint8_t mps_fr_nb_bands[8] = { + 255 /* Reserved */, 28, 20, 14, 10, 7, 5, 4, +}; + +static const uint8_t mps_fr_stride_smg[4] = { + 1, 2, 5, 28, +}; + +static void decode_tsd(GetBitContext *gb, int *data, + int nb_tr_slots, int nb_slots) +{ + int nb_bits = av_log2(nb_slots / (nb_tr_slots + 1)); + int s = get_bits(gb, nb_bits); + for (int k = 0; k < nb_slots; k++) + data[k]=0; + + int p = nb_tr_slots + 1; + for (int k = nb_slots - 1; k >= 0; k--) { + if (p > k) { + for (; k >= 0; k--) + data[k] = 1; + break; + } + int64_t c = k - p + 1; + for (int h = 2; h <= p; h++) { + c *= k - p + h; + c /= h; + } + if (s >= (int)c) { /* c is long long for up to 32 slots */ + s -= c; + data[k] = 1; + p--; + if (!p) + break; + } + } +} + +static int parse_mps212(AACDecContext *ac, AACUSACConfig *usac, + AACUsacMPSData *mps, AACUsacElemConfig *ec, + GetBitContext *gb, int frame_indep_flag) +{ + int err; + int nb_bands = mps_fr_nb_bands[ec->mps.freq_res]; + + /* Framing info */ + mps->framing_type = 0; + mps->nb_param_sets = 2; + if (ec->mps.high_rate_mode) { + mps->framing_type = get_bits1(gb); + mps->nb_param_sets = get_bits(gb, 3) + 1; + } + int param_slot_bits = usac->core_sbr_frame_len_idx == 4 ? 6 : 5; + int nb_time_slots = usac->core_sbr_frame_len_idx == 4 ? 64 : 32; + + if (mps->framing_type) + for (int i = 0; i < mps->nb_param_sets; i++) + mps->param_sets[i] = get_bits(gb, param_slot_bits); + + int indep = frame_indep_flag; + if (!frame_indep_flag) + indep = get_bits1(gb); + + int extend_frame = mps->param_sets[mps->nb_param_sets - 1] != + (nb_time_slots - 1); + + /* CLD */ + err = ff_aac_ec_data_dec(gb, &mps->ott[MPS_CLD], MPS_CLD, + 0, 0, nb_bands, + indep, indep, mps->nb_param_sets); + if (err < 0) { + av_log(ac->avctx, AV_LOG_ERROR, "Error parsing OTT CLD data!\n"); + return err; + } + ff_aac_map_index_data(&mps->ott[MPS_CLD], MPS_CLD, mps->ott_idx[MPS_CLD], + 0, 0, nb_bands, mps->nb_param_sets, + mps->param_sets, extend_frame); + + /* ICC */ + err = ff_aac_ec_data_dec(gb, &mps->ott[MPS_ICC], MPS_ICC, 0, 0, nb_bands, + indep, indep, mps->nb_param_sets); + if (err < 0) { + av_log(ac->avctx, AV_LOG_ERROR, "Error parsing OTT ICC data!\n"); + return err; + } + ff_aac_map_index_data(&mps->ott[MPS_ICC], MPS_ICC, mps->ott_idx[MPS_ICC], + 0, 0, nb_bands, mps->nb_param_sets, + mps->param_sets, extend_frame); + + /* IPD */ + if (ec->mps.phase_coding) { + if (get_bits1(gb)) { + mps->opd_smoothing_mode = get_bits1(gb); + err = ff_aac_ec_data_dec(gb, &mps->ott[MPS_IPD], MPS_IPD, 0, 0, + ec->mps.otts_bands_phase, + indep, indep, mps->nb_param_sets); + ff_aac_map_index_data(&mps->ott[MPS_IPD], MPS_IPD, mps->ott_idx[MPS_IPD], + 0, 0, nb_bands, mps->nb_param_sets, + mps->param_sets, extend_frame); + if (err < 0) { + av_log(ac->avctx, AV_LOG_ERROR, "Error parsing OTT IPD data!\n"); + return err; + } + } + } + + /* SMG data */ + memset(mps->smooth_mode, 0, sizeof(mps->smooth_mode)); + if (ec->mps.high_rate_mode) { + for (int i = 0; i < mps->nb_param_sets; i++) { + mps->smooth_mode[i] = get_bits(gb, 2); + if (mps->smooth_mode[i] >= 2) + mps->smooth_time[i] = get_bits(gb, 2); + if (mps->smooth_mode[i] >= 3) { + mps->freq_res_stride_smg[i] = get_bits(gb, 2); + int nb_data_bands = (nb_bands - 1); + nb_data_bands /= (mps_fr_stride_smg[mps->freq_res_stride_smg[i]] + 1); + for (int j = 0; j < nb_data_bands; j++) + mps->smg_data[i][j] = get_bits1(gb); + } + } + } + + /* Temp shape data */ + mps->tsd_enable = 0; + if (ec->mps.temp_shape_config == 3) { + mps->tsd_enable = get_bits1(gb); + } else if (ec->mps.temp_shape_config) { + mps->temp_shape_enable = get_bits1(gb); + if (mps->temp_shape_enable) { + for (int i = 0; i < 2; i++) + mps->temp_shape_enable_ch[i] = get_bits1(gb); + if (ec->mps.temp_shape_config == 2) { + err = ff_aac_huff_dec_reshape(gb, mps->temp_shape_data, 16); + if (err < 0) { + av_log(ac->avctx, AV_LOG_ERROR, + "Error parsing TSD reshape data!\n"); + return err; + } + } + } + } + + /* TSD data */ + if (mps->tsd_enable) { + mps->tsd_num_tr_slots = get_bits(gb, param_slot_bits - 1); + int tsd_pos[64]; + decode_tsd(gb, tsd_pos, mps->tsd_num_tr_slots, nb_time_slots); + for (int i = 0; i < nb_time_slots; i++) { + mps->tsd_phase_data[i] = 0; + if (tsd_pos[i]) + mps->tsd_phase_data[i] = get_bits(gb, 3); + } + } + + return 0; +} + static int decode_usac_core_coder(AACDecContext *ac, AACUSACConfig *usac, AACUsacElemConfig *ec, ChannelElement *che, GetBitContext *gb, int indep_flag, int nb_channels) @@ -1481,7 +1640,8 @@ static int decode_usac_core_coder(AACDecContext *ac, AACUSACConfig *usac, if (get_bits1(gb)) { /* fac_data_present */ const uint16_t len_8 = usac->core_frame_len / 8; const uint16_t len_16 = usac->core_frame_len / 16; - const uint16_t fac_len = ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE ? len_16 : len_8; + const uint16_t fac_len = ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE ? + len_16 : len_8; ret = ff_aac_parse_fac_data(ue, gb, 1, fac_len); if (ret < 0) return ret; @@ -1497,11 +1657,12 @@ static int decode_usac_core_coder(AACDecContext *ac, AACUSACConfig *usac, ret = ff_aac_sbr_decode_usac_data(ac, che, ec, gb, sbr_ch, indep_flag); if (ret < 0) return ret; + } - if (ec->stereo_config_index) { - avpriv_report_missing_feature(ac->avctx, "AAC USAC Mps212"); - return AVERROR_PATCHWELCOME; - } + if (ec->stereo_config_index) { + ret = parse_mps212(ac, usac, &us->mps, ec, gb, indep_flag); + if (ret < 0) + return ret; } spectrum_decode(ac, usac, che, core_nb_channels); @@ -1622,8 +1783,8 @@ static int parse_ext_ele(AACDecContext *ac, AACUsacElemConfig *e, * Otherwise, we have to copy it to a buffer and accumulate it. */ if (!(pl_frag_start && pl_frag_end)) { /* Reallocate the data */ - uint8_t *tmp_buf = ff_refstruct_alloc_ext(e->ext.pl_data_offset + len, - FF_REFSTRUCT_FLAG_NO_ZEROING, + uint8_t *tmp_buf = av_refstruct_alloc_ext(e->ext.pl_data_offset + len, + AV_REFSTRUCT_FLAG_NO_ZEROING, NULL, NULL); if (!tmp_buf) return AVERROR(ENOMEM); @@ -1632,7 +1793,7 @@ static int parse_ext_ele(AACDecContext *ac, AACUsacElemConfig *e, if (e->ext.pl_buf) memcpy(tmp_buf, e->ext.pl_buf, e->ext.pl_data_offset); - ff_refstruct_unref(&e->ext.pl_buf); + av_refstruct_unref(&e->ext.pl_buf); e->ext.pl_buf = tmp_buf; /* Readout data to a buffer */ @@ -1667,7 +1828,7 @@ static int parse_ext_ele(AACDecContext *ac, AACUsacElemConfig *e, /* This should never happen */ av_assert0(0); } - ff_refstruct_unref(&e->ext.pl_buf); + av_refstruct_unref(&e->ext.pl_buf); if (ret < 0) return ret; diff --git a/libavcodec/aac/aacdec_usac_mps212.c b/libavcodec/aac/aacdec_usac_mps212.c new file mode 100644 index 000000000..3c1b1cf30 --- /dev/null +++ b/libavcodec/aac/aacdec_usac_mps212.c @@ -0,0 +1,917 @@ +/* + * Copyright (c) 2025 Lynne + * + * 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 "aacdec_tab.h" +#include "libavcodec/get_bits.h" +#include "libavutil/macros.h" +#include "libavutil/avassert.h" + +#include "aacdec_usac_mps212.h" + +static int huff_dec_1D(GetBitContext *gb, const int16_t (*tab)[2]) +{ + int idx = 0; + do { + /* Overreads are not possible here, the array forms a closed set */ + idx = tab[idx][get_bits1(gb)]; + } while (idx > 0); + return idx; +} + +static int huff_dec_2D(GetBitContext *gb, const int16_t (*tab)[2], int16_t ret[2]) +{ + int idx = huff_dec_1D(gb, tab); + if (!idx) { /* Escape */ + ret[0] = 0; + ret[1] = 1; + return 1; + } + + idx = -(idx + 1); + ret[0] = idx >> 4; + ret[1] = idx & 0xf; + return 0; +} + +static int huff_data_1d(GetBitContext *gb, int16_t *data, int data_bands, + enum AACMPSDataType data_type, int diff_freq, int p0_flag) +{ + const int16_t (*hcod_first_band)[2]; + const int16_t (*hcod1D)[2]; + + switch (data_type) { + case MPS_CLD: + hcod_first_band = ff_aac_hcod_firstband_CLD; + hcod1D = ff_aac_hcod1D_CLD[diff_freq]; + break; + case MPS_ICC: + hcod_first_band = ff_aac_hcod_firstband_ICC; + hcod1D = ff_aac_hcod1D_ICC; + break; + case MPS_IPD: + hcod_first_band = ff_aac_hcod_firstband_IPD; + hcod1D = ff_aac_hcod1D_IPD[diff_freq]; + if (data_bands == 1) + hcod1D = ff_aac_hcod1D_IPD[!diff_freq]; + break; + default: + av_unreachable("Invalid data type"); + } + + if (p0_flag) + data[0] = -(huff_dec_1D(gb, hcod_first_band) + 1); + + for (int off = diff_freq; off < data_bands; off++) { + int16_t val = -(huff_dec_1D(gb, hcod1D) + 1); + if (val && data_type != MPS_IPD) + val = get_bits1(gb) ? -val : val; + data[off] = val; + } + + return 0; +} + +static void symmetry_data(GetBitContext *gb, int16_t data[2], + uint8_t lav, enum AACMPSDataType data_type) +{ + int16_t sum = data[0] + data[1]; + int16_t diff = data[0] - data[1]; + + if (sum > lav) { + data[0] = -sum + (2*lav + 1); + data[1] = -diff; + } else { + data[0] = sum; + data[1] = diff; + } + + if ((data_type != MPS_IPD) && (data[0] + data[1])) { + int sym = get_bits1(gb) ? -1 : 1; + data[0] *= sym; + data[1] *= sym; + } + + if (data[0] - data[1]) { + if (get_bits1(gb)) + FFSWAP(int16_t, data[0], data[1]); + } +} + +/* NB: NOT a standard integer log2! */ +static int mps_log2(int s) { + if (s) + s--; + int v = 0; + while (s) { + s >>= 1; + v++; + } + return v; +} + +static void pcm_decode(GetBitContext *gb, int16_t *data0, int16_t *data1, + int16_t offset, int nb_pcm_data_bands, + int nb_quant_steps, int nb_levels) +{ + int max_group_len; + switch (nb_levels) { + case 3: max_group_len = 5; break; + case 7: max_group_len = 6; break; + case 11: max_group_len = 2; break; + case 13: max_group_len = 4; break; + case 19: max_group_len = 4; break; + case 25: max_group_len = 3; break; + case 51: max_group_len = 4; break; + case 4: case 8: case 15: case 16: case 26: case 31: + max_group_len = 1; + break; + default: + return; + }; + + av_assert1(data0 || data1); + + int pcm_chunk_size[7] = { 0 }; + + int tmp = 1; + for (int i = 1; i <= max_group_len; i++) { + tmp *= nb_levels; + pcm_chunk_size[i] = mps_log2(tmp); + } + + for (int i = 0; i < nb_pcm_data_bands; i+= max_group_len) { + int group_len = FFMIN(max_group_len, nb_pcm_data_bands - i); + + int pcm = get_bits(gb, pcm_chunk_size[group_len]); + for (int j = 0; j < group_len; j++) { + int idx = i + (group_len - 1) - j; + int val = pcm % nb_levels; + if (data0 && data1) { + if (idx % 2) + data1[idx / 2] = val - offset; + else + data0[idx / 2] = val - offset; + } else if (!data1) { + data0[idx] = val - offset; + } else if (!data0) { + data1[idx] = val - offset; + } + pcm = (pcm - val) / nb_levels; + } + } +} + +static void huff_data_2d(GetBitContext *gb, int16_t *part0_data[2], int16_t (*data)[2], + int data_bands, int stride, enum AACMPSDataType data_type, + int diff_freq, int freq_pair) +{ + int16_t lav_idx = huff_dec_1D(gb, ff_aac_hcod_lav_idx); + uint8_t lav = ff_aac_lav_tab_XXX[data_type][-(lav_idx + 1)]; + + const int16_t (*hcod1D)[2]; + const int16_t (*hcod2D)[2]; + switch (data_type) { + case MPS_CLD: + hcod1D = ff_aac_hcod_firstband_CLD; + switch (lav) { + case 3: hcod2D = ff_aac_hcod2D_CLD_03[freq_pair][diff_freq]; break; + case 5: hcod2D = ff_aac_hcod2D_CLD_05[freq_pair][diff_freq]; break; + case 7: hcod2D = ff_aac_hcod2D_CLD_07[freq_pair][diff_freq]; break; + case 9: hcod2D = ff_aac_hcod2D_CLD_09[freq_pair][diff_freq]; break; + } + break; + case MPS_ICC: + hcod1D = ff_aac_hcod_firstband_ICC; + switch (lav) { + case 1: hcod2D = ff_aac_hcod2D_ICC_01[freq_pair][diff_freq]; break; + case 3: hcod2D = ff_aac_hcod2D_ICC_03[freq_pair][diff_freq]; break; + case 5: hcod2D = ff_aac_hcod2D_ICC_05[freq_pair][diff_freq]; break; + case 7: hcod2D = ff_aac_hcod2D_ICC_07[freq_pair][diff_freq]; break; + } + break; + case MPS_IPD: + hcod1D = ff_aac_hcod_firstband_IPD; + switch (lav) { + case 1: hcod2D = ff_aac_hcod2D_IPD_01[freq_pair][diff_freq]; break; + case 3: hcod2D = ff_aac_hcod2D_IPD_03[freq_pair][diff_freq]; break; + case 5: hcod2D = ff_aac_hcod2D_IPD_05[freq_pair][diff_freq]; break; + case 7: hcod2D = ff_aac_hcod2D_IPD_07[freq_pair][diff_freq]; break; + } + break; + default: + av_unreachable("Invalid data type"); + } + + if (part0_data[0]) + part0_data[0][0] = -(huff_dec_1D(gb, hcod1D) + 1); + if (part0_data[1]) + part0_data[1][0] = -(huff_dec_1D(gb, hcod1D) + 1); + + int i = 0; + int esc_cnt = 0; + int16_t esc_data[2][28]; + int esc_idx[28]; + for (; i < data_bands; i += stride) { + if (huff_dec_2D(gb, hcod2D, data[i])) + esc_idx[esc_cnt++] = i; /* Escape */ + else + symmetry_data(gb, data[i], lav, data_type); + } + + if (esc_cnt) { + pcm_decode(gb, esc_data[0], esc_data[1], + 0, 2*esc_cnt, 0, (2*lav + 1)); + for (i = 0; i < esc_cnt; i++) { + data[esc_idx[i]][0] = esc_data[0][i] - lav; + data[esc_idx[i]][0] = esc_data[0][i] - lav; + } + } +} + +static int huff_decode(GetBitContext *gb, int16_t *data[2], + enum AACMPSDataType data_type, int diff_freq[2], + int num_val, int *time_pair) +{ + int16_t pair_vec[28][2]; + int num_val_ch[2] = { num_val, num_val }; + int16_t *p0_data[2][2] = { 0 }; + int df_rest_flag[2] = { 0, 0 }; + + /* Coding scheme */ + int dim = get_bits1(gb); + if (dim) { /* 2D */ + *time_pair = 0; + if (data[0] && data[1]) + *time_pair = get_bits1(gb); + + if (*time_pair) { + if (diff_freq[0] || diff_freq[1]) { + p0_data[0][0] = data[0]; + p0_data[0][1] = data[1]; + + data[0] += 1; + data[1] += 1; + + num_val_ch[0] -= 1; + } + + int diff_mode = 1; + if (!diff_freq[0] || !diff_freq[1]) + diff_mode = 0; // time + + huff_data_2d(gb, p0_data[0], pair_vec, num_val_ch[0], 1, data_type, + diff_mode, 0); + + for (int i = 0; i < num_val_ch[0]; i++) { + data[0][i] = pair_vec[i][0]; + data[1][i] = pair_vec[i][1]; + } + } else { + if (data[0]) { + if (diff_freq[0]) { + p0_data[0][0] = data[0]; + p0_data[0][1] = NULL; + + num_val_ch[0] -= 1; + data[0]++; + } + df_rest_flag[0] = num_val_ch[0] % 2; + if (df_rest_flag[0]) + num_val_ch[0] -= 1; + if (num_val_ch[0] < 0) + return AVERROR(EINVAL); + } + + if (data[1]) { + if (diff_freq[1]) { + p0_data[1][0] = NULL; + p0_data[1][1] = data[1]; + + num_val_ch[1] -= 1; + data[1]++; + } + df_rest_flag[1] = num_val_ch[1] % 2; + if (df_rest_flag[1]) + num_val_ch[1] -= 1; + if (num_val_ch[1] < 0) + return AVERROR(EINVAL); + } + + if (data[0]) { + huff_data_2d(gb, p0_data[0], pair_vec, num_val_ch[0], 2, data_type, + diff_freq[0], 1); + if (df_rest_flag[0]) + huff_data_1d(gb, data[0] + num_val_ch[0], 1, + data_type, !diff_freq[0], 0); + } + if (data[1]) { + huff_data_2d(gb, p0_data[1], pair_vec + 1, num_val_ch[1], 2, data_type, + diff_freq[1], 1); + if (df_rest_flag[1]) + huff_data_1d(gb, data[1] + num_val_ch[1], 1, + data_type, !diff_freq[1], 0); + } + } + } else { /* 1D */ + if (data[0]) + huff_data_1d(gb, data[0], num_val, data_type, diff_freq[0], diff_freq[0]); + if (data[1]) + huff_data_1d(gb, data[1], num_val, data_type, diff_freq[1], diff_freq[1]); + } + + return 0; +} + +static void diff_freq_decode(const int16_t *diff, int16_t *out, int nb_val) +{ + int i = 0; + out[0] = diff[0]; + for (i = 1; i < nb_val; i++) + out[i] = out[i - 1] + diff[i]; +} + +static void diff_time_decode_backwards(const int16_t *prev, const int16_t *diff, + int16_t *out, const int mixed_diff_type, + const int nb_val) +{ + if (mixed_diff_type) + out[0] = diff[0]; + for (int i = mixed_diff_type; i < nb_val; i++) + out[i] = prev[i] + diff[i]; +} + +static void diff_time_decode_forwards(const int16_t *prev, const int16_t *diff, + int16_t *out, const int mixed_diff_type, + const int nb_val) +{ + if (mixed_diff_type) + out[0] = diff[0]; + for (int i = mixed_diff_type; i < nb_val; i++) + out[i] = prev[i] - diff[i]; +} + +static void attach_lsb(GetBitContext *gb, int16_t *data_msb, + int offset, int nb_lsb, int nb_val, + int16_t *data) +{ + for (int i = 0; i < nb_val; i++) { + int msb = data_msb[i]; + if (nb_lsb > 0) { + uint32_t lsb = get_bits(gb, nb_lsb); + data[i] = ((msb << nb_lsb) | lsb) - offset; + } else { + data[i] = msb - offset; + } + } +} + +static int ec_pair_dec(GetBitContext *gb, + int16_t set1[MPS_MAX_PARAM_BANDS], + int16_t set2[MPS_MAX_PARAM_BANDS], int16_t *last, + enum AACMPSDataType data_type, int start_band, int nb_bands, + int pair, int coarse, + int diff_time_back) +{ + int attach_lsb_flag = 0; + int quant_levels = 0; + int quant_offset = 0; + + switch (data_type) { + case MPS_CLD: + if (coarse) { + attach_lsb_flag = 0; + quant_levels = 15; + quant_offset = 7; + } else { + attach_lsb_flag = 0; + quant_levels = 31; + quant_offset = 15; + } + break; + case MPS_ICC: + if (coarse) { + attach_lsb_flag = 0; + quant_levels = 4; + quant_offset = 0; + } else { + attach_lsb_flag = 0; + quant_levels = 8; + quant_offset = 0; + } + break; + case MPS_IPD: + if (!coarse) { + attach_lsb_flag = 1; + quant_levels = 16; + quant_offset = 0; + } else { + attach_lsb_flag = 0; + quant_levels = 8; + quant_offset = 0; + } + break; + } + + int16_t last_msb[28] = { 0 }; + int16_t data_pair[2][28] = { 0 }; + int16_t data_diff[2][28] = { 0 }; + int16_t *p_data[2]; + + int pcm_coding = get_bits1(gb); + if (pcm_coding) { /* bsPcmCoding */ + int nb_pcm_vals; + if (pair) { + p_data[0] = data_pair[0]; + p_data[1] = data_pair[1]; + nb_pcm_vals = 2 * nb_bands; + } else { + p_data[0] = data_pair[0]; + p_data[1] = NULL; + nb_pcm_vals = nb_bands; + } + + int nb_quant_steps; + switch (data_type) { + case MPS_CLD: nb_quant_steps = coarse ? 15 : 31; break; + case MPS_ICC: nb_quant_steps = coarse ? 4 : 8; break; + case MPS_IPD: nb_quant_steps = coarse ? 8 : 16; break; + } + pcm_decode(gb, p_data[0], p_data[1], quant_offset, nb_pcm_vals, + nb_quant_steps, quant_levels); + + memcpy(&set1[start_band], data_pair[0], 2*nb_bands); + if (pair) + memcpy(&set2[start_band], data_pair[1], 2*nb_bands); + + return 0; + } + + if (pair) { + p_data[0] = data_diff[0]; + p_data[1] = data_diff[1]; + } else { + p_data[0] = data_diff[0]; + p_data[1] = NULL; + } + + int diff_freq[2] = { 1, 1 }; + int backwards = 1; + + if (pair || diff_time_back) + diff_freq[0] = !get_bits1(gb); + + if (pair && (diff_freq[0] || diff_time_back)) + diff_freq[1] = !get_bits1(gb); + + int time_pair = 0; + huff_decode(gb, p_data, data_type, diff_freq, + nb_bands, &time_pair); + + /* Differential decoding */ + if (!diff_freq[0] || !diff_freq[1]) { + if (0 /* 1 if SAOC */) { + backwards = 1; + } else { + if (pair) { + if (!diff_freq[0] && !diff_time_back) + backwards = 0; + else if (!diff_freq[1]) + backwards = 1; + else + backwards = !get_bits1(gb); + } else { + backwards = 1; + } + } + } + + int mixed_time_pair = (diff_freq[0] != diff_freq[1]) && time_pair; + + if (backwards) { + if (diff_freq[0]) { + diff_freq_decode(data_diff[0], data_pair[0], nb_bands); + } else { + for (int i = 0; i < nb_bands; i++) { + last_msb[i] = last[i + start_band] + quant_offset; + if (attach_lsb_flag) { + last_msb[i] >>= 1; + } + } + diff_time_decode_backwards(last_msb, data_diff[0], data_pair[0], + mixed_time_pair, nb_bands); + } + + if (diff_freq[1]) + diff_freq_decode(data_diff[1], data_pair[1], nb_bands); + else + diff_time_decode_backwards(data_pair[0], data_diff[1], + data_pair[1], mixed_time_pair, nb_bands); + } else { + diff_freq_decode(data_diff[1], data_pair[1], nb_bands); + + if (diff_freq[0]) + diff_freq_decode(data_diff[0], data_pair[0], nb_bands); + else + diff_time_decode_forwards(data_pair[1], data_diff[0], data_pair[0], + mixed_time_pair, nb_bands); + } + + /* Decode LSBs */ + attach_lsb(gb, data_pair[0], quant_offset, attach_lsb_flag, + nb_bands, data_pair[0]); + if (pair) + attach_lsb(gb, data_pair[1], quant_offset, attach_lsb_flag, + nb_bands, data_pair[1]); + + memcpy(&set1[start_band], data_pair[0], 2*nb_bands); + if (pair) + memcpy(&set2[start_band], data_pair[1], 2*nb_bands); + + return 0; +} + +static void coarse_to_fine(int16_t *data, enum AACMPSDataType data_type, + int start_band, int end_band) +{ + for (int i = start_band; i < end_band; i++) + data[i] *= 2; + if (data_type == MPS_CLD) { + for (int i = start_band; i < end_band; i++) { + if (data[i] == -14) + data[i] = -15; + else if (data[i] == 14) + data[i] = 15; + } + } +} + +static void fine_to_coarse(int16_t *data, enum AACMPSDataType data_type, + int start_band, int end_band) +{ + for (int i = start_band; i < end_band; i++) { + if (data_type == MPS_CLD) + data[i] /= 2; + else + data[i] >>= 1; + } +} + +static int get_freq_strides(int16_t *freq_strides, int band_stride, + int start_band, int end_band) +{ + int data_bands = (end_band - start_band - 1) / band_stride + 1; + + freq_strides[0] = start_band; + for (int i = 1; i <= data_bands; i++) + freq_strides[i] = freq_strides[i - 1] + band_stride; + + int offs = 0; + while (freq_strides[data_bands] > end_band) { + if (offs < data_bands) + offs++; + for (int i = offs; i <= data_bands; i++) { + freq_strides[i]--; + } + } + + return data_bands; +} + +static const int stride_table[4] = { 1, 2, 5, 28 }; + +int ff_aac_ec_data_dec(GetBitContext *gb, AACMPSLosslessData *ld, + enum AACMPSDataType data_type, + int default_val, + int start_band, int end_band, int frame_indep_flag, + int indep_flag, int nb_param_sets) +{ + for (int i = 0; i < nb_param_sets; i++) { + ld->data_mode[i] = get_bits(gb, 2); + /* Error checking */ + if ((indep_flag && !i && (ld->data_mode[i] == 1 || ld->data_mode[i] == 2)) || + ((i == (nb_param_sets - 1) && (ld->data_mode[i] == 2)))) { + return AVERROR(EINVAL); + } + } + + int set_idx = 0; + int data_pair = 0; + bool old_coarse = ld->quant_coarse_prev; + + for (int i = 0; i < nb_param_sets; i++) { + if (!ld->data_mode[i]) { + for (int j = start_band; j < end_band; j++) + ld->last_data[j] = default_val; + old_coarse = 0; + } + + if (ld->data_mode[i] != 3) { + continue; + } else if (data_pair) { + data_pair = 0; + continue; + } + + data_pair = get_bits1(gb); + ld->coarse_quant[set_idx] = get_bits1(gb); + ld->freq_res[set_idx] = get_bits(gb, 2); + + if (ld->coarse_quant[set_idx] != old_coarse) { + if (old_coarse) + coarse_to_fine(ld->last_data, data_type, start_band, end_band); + else + fine_to_coarse(ld->last_data, data_type, start_band, end_band); + } + + int16_t freq_stride_map[MPS_MAX_PARAM_BANDS + 1]; + int data_bands = get_freq_strides(freq_stride_map, + stride_table[ld->freq_res[set_idx]], + start_band, end_band); + + if (set_idx + data_pair > MPS_MAX_PARAM_SETS) + return AVERROR(EINVAL); + + for (int j = 0; j < data_bands; j++) + ld->last_data[start_band + j] = ld->last_data[freq_stride_map[j]]; + + int err = ec_pair_dec(gb, + ld->data[set_idx + 0], ld->data[set_idx + 1], + ld->last_data, data_type, start_band, end_band - start_band, + data_pair, ld->coarse_quant[set_idx], + !(indep_flag && (i == 0)) || (set_idx > 0)); + if (err < 0) + return err; + + if (data_type == MPS_IPD) { + const int mask = ld->coarse_quant[set_idx] ? 0x7 : 0xF; + for (int j = 0; j < data_bands; j++) + for (int k = freq_stride_map[j + 0]; k < freq_stride_map[j + 1]; k++) + ld->last_data[k] = ld->data[set_idx + data_pair][start_band + j] & mask; + } else { + for (int j = 0; j < data_bands; j++) + for (int k = freq_stride_map[j + 0]; k < freq_stride_map[j + 1]; k++) + ld->last_data[k] = ld->data[set_idx + data_pair][start_band + j]; + } + + old_coarse = ld->coarse_quant[set_idx]; + if (data_pair) { + ld->coarse_quant[set_idx + 1] = ld->coarse_quant[set_idx]; + ld->freq_res[set_idx + 1] = ld->freq_res[set_idx]; + } + set_idx += data_pair + 1; + } + + ld->quant_coarse_prev = old_coarse; + + return 0; +} + +int ff_aac_huff_dec_reshape(GetBitContext *gb, int16_t *out_data, + int nb_val) +{ + int val, len; + int val_received = 0; + int16_t rl_data[2] = { 0 }; + + while (val_received < nb_val) { + huff_dec_2D(gb, ff_aac_hcod2D_reshape, rl_data); + val = rl_data[0]; + len = rl_data[1] + 1; + if (val_received + len > nb_val) + return AVERROR(EINVAL); + for (int i = val_received; i < val_received + len; i++) + out_data[i] = val; + val_received += len; + } + + return 0; +} + +static void create_mapping(int map[MPS_MAX_PARAM_BANDS + 1], + int start_band, int stop_band, int stride) +{ + int diff[MPS_MAX_PARAM_BANDS + 1]; + int src_bands = stop_band - start_band; + int dst_bands = (src_bands - 1) / stride + 1; + + if (dst_bands < 1) + dst_bands = 1; + + int bands_achived = dst_bands * stride; + int bands_diff = src_bands - bands_achived; + for (int i = 0; i < dst_bands; i++) + diff[i] = stride; + + int incr, k; + if (bands_diff > 0) { + incr = -1; + k = dst_bands - 1; + } else { + incr = 1; + k = 0; + } + + while (bands_diff != 0) { + diff[k] = diff[k] - incr; + k = k + incr; + bands_diff = bands_diff + incr; + if (k >= dst_bands) { + if (bands_diff > 0) { + k = dst_bands - 1; + } else if (bands_diff < 0) { + k = 0; + } + } + } + + map[0] = start_band; + for (int i = 0; i < dst_bands; i++) + map[i + 1] = map[i] + diff[i]; +} + +static void map_freq(int16_t *dst, const int16_t *src, + int *map, int nb_bands) +{ + for (int i = 0; i < nb_bands; i++) { + int value = src[i + map[0]]; + int start_band = map[i]; + int stop_band = map[i + 1]; + for (int j = start_band; j < stop_band; j++) { + dst[j] = value; + } + } +} + +static int deq_idx(int value, enum AACMPSDataType data_type) +{ + int idx = -1; + + switch (data_type) { + case MPS_CLD: + if (((value + 15) >= 0) && ((value + 15) < 31)) + idx = (value + 15); + break; + case MPS_ICC: + if ((value >= 0) && (value < 8)) + idx = value; + break; + case MPS_IPD: + /* (+/-)15 * MAX_PARAMETER_BANDS for differential coding in frequency + * domain (according to rbl) */ + if ((value >= -420) && (value <= 420)) + idx = (value & 0xf); + break; + } + + return idx; +} + +int ff_aac_map_index_data(AACMPSLosslessData *ld, + enum AACMPSDataType data_type, + int dst_idx[MPS_MAX_PARAM_SETS][MPS_MAX_PARAM_BANDS], + int default_value, int start_band, int stop_band, + int nb_param_sets, const int *param_set_idx, + int extend_frame) +{ + if (nb_param_sets > MPS_MAX_PARAM_SETS) + return AVERROR(EINVAL); + + int data_mode_3_idx[MPS_MAX_PARAM_SETS] = { 0 }; + int nb_data_mode_3 = 0; + for (int i = 0; i < nb_param_sets; i++) { + if (ld->data_mode[i] == 3) { + data_mode_3_idx[nb_data_mode_3] = i; + nb_data_mode_3++; + } + } + + int set_idx = 0; + + /* Prepare data */ + int interpolate[MPS_MAX_PARAM_SETS] = { 0 }; + int16_t tmp_idx_data[MPS_MAX_PARAM_SETS][MPS_MAX_PARAM_BANDS] = { 0 }; + for (int i = 0; i < nb_param_sets; i++) { + if (ld->data_mode[i] == 0) { + ld->coarse_quant_no[i] = 0; + for (int band = start_band; band < stop_band; band++) + tmp_idx_data[i][band] = default_value; + for (int band = start_band; band < stop_band; band++) + ld->last_data[band] = tmp_idx_data[i][band]; + ld->quant_coarse_prev = 0; + } + + if (ld->data_mode[i] == 1) { + for (int band = start_band; band < stop_band; band++) + tmp_idx_data[i][band] = ld->last_data[band]; + ld->coarse_quant_no[i] = ld->quant_coarse_prev; + } + + if (ld->data_mode[i] == 2) { + for (int band = start_band; band < stop_band; band++) + tmp_idx_data[i][band] = ld->last_data[band]; + ld->coarse_quant_no[i] = ld->quant_coarse_prev; + interpolate[i] = 1; + } else { + interpolate[i] = 0; + } + + if (ld->data_mode[i] == 3) { + int stride; + + int parmSlot = data_mode_3_idx[set_idx]; + stride = stride_table[ld->freq_res[set_idx]]; + int dataBands = (stop_band - start_band - 1) / stride + 1; + + int tmp[MPS_MAX_PARAM_BANDS + 1]; + create_mapping(tmp, start_band, stop_band, stride); + map_freq(tmp_idx_data[parmSlot], ld->data[set_idx], + tmp, dataBands); + + for (int band = start_band; band < stop_band; band++) + ld->last_data[band] = tmp_idx_data[parmSlot][band]; + + ld->quant_coarse_prev = ld->coarse_quant[set_idx]; + ld->coarse_quant_no[i] = ld->coarse_quant[set_idx]; + + set_idx++; + } + } + + /* Map all coarse data to fine */ + for (int i = 0; i < nb_param_sets; i++) { + if (ld->coarse_quant_no[i] == 1) { + coarse_to_fine(tmp_idx_data[i], data_type, start_band, + stop_band - start_band); + ld->coarse_quant_no[i] = 0; + } + } + + /* Interpolate */ + int i1 = 0; + for (int i = 0; i < nb_param_sets; i++) { + if (interpolate[i] != 1) { + i1 = i; + } else { + int xi, i2, x1, x2; + + for (i2 = i; i2 < nb_param_sets; i2++) + if (interpolate[i2] != 1) + break; + if (i2 >= nb_param_sets) + return AVERROR(EINVAL); + + x1 = param_set_idx[i1]; + xi = param_set_idx[i]; + x2 = param_set_idx[i2]; + + for (int band = start_band; band < stop_band; band++) { + int yi, y1, y2; + y1 = tmp_idx_data[i1][band]; + y2 = tmp_idx_data[i2][band]; + if (x1 != x2) { + yi = y1 + (xi - x1) * (y2 - y1) / (x2 - x1); + } else { + yi = y1 /*+ (xi-x1)*(y2-y1)/1e-12*/; + } + tmp_idx_data[i][band] = yi; + } + } + } + + /* Dequantize data and apply factorCLD if necessary */ + for (int ps = 0; ps < nb_param_sets; ps++) { + /* Dequantize data */ + for (int band = start_band; band < stop_band; band++) { + dst_idx[ps][band] = deq_idx(tmp_idx_data[ps][band], + data_type); + if (dst_idx[ps][band] == -1) + dst_idx[ps][band] = default_value; + } + } + + if (extend_frame) { + if (data_type == MPS_IPD) + ld->coarse_quant[nb_param_sets] = ld->coarse_quant[nb_param_sets - 1]; + for (int band = start_band; band < stop_band; band++) + dst_idx[nb_param_sets][band] = dst_idx[nb_param_sets - 1][band]; + } + + return 0; +} diff --git a/libavcodec/aac/aacdec_usac_mps212.h b/libavcodec/aac/aacdec_usac_mps212.h new file mode 100644 index 000000000..a14e47954 --- /dev/null +++ b/libavcodec/aac/aacdec_usac_mps212.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 Lynne + * + * 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_AAC_AACDEC_USAC_MPS212_H +#define AVCODEC_AAC_AACDEC_USAC_MPS212_H + +#include + +#include "libavcodec/get_bits.h" +#include "libavcodec/aac.h" + +enum AACMPSDataType { + MPS_CLD = 0, + MPS_ICC, + MPS_IPD, + + MPS_ELE_NB, +}; + +typedef struct AACMPSLosslessData { + int16_t data[MPS_MAX_PARAM_SETS][MPS_MAX_PARAM_BANDS]; + int16_t last_data[MPS_MAX_PARAM_BANDS]; + + int16_t data_mode[MPS_MAX_PARAM_SETS]; + bool coarse_quant[MPS_MAX_PARAM_SETS]; + int16_t freq_res[MPS_MAX_PARAM_SETS]; + int16_t coarse_quant_no[MPS_MAX_PARAM_SETS]; + + bool quant_coarse_prev; +} AACMPSLosslessData; + +int ff_aac_ec_data_dec(GetBitContext *gb, AACMPSLosslessData *ld, + enum AACMPSDataType data_type, + int default_val, + int start_band, int end_band, int frame_indep_flag, + int indep_flag, int nb_param_sets); + +int ff_aac_map_index_data(AACMPSLosslessData *ld, + enum AACMPSDataType data_type, + int dst_idx[MPS_MAX_PARAM_SETS][MPS_MAX_PARAM_BANDS], + int default_value, int start_band, int stop_band, + int nb_param_sets, const int *param_set_idx, + int extend_frame); + +int ff_aac_huff_dec_reshape(GetBitContext *gb, int16_t *out_data, + int nb_val); + +#endif /* AVCODEC_AAC_AACDEC_USAC_MPS212_H */ diff --git a/libavcodec/aac_ac3_parser.c b/libavcodec/aac_ac3_parser.c index e2361d353..51c801214 100644 --- a/libavcodec/aac_ac3_parser.c +++ b/libavcodec/aac_ac3_parser.c @@ -147,15 +147,15 @@ get_next: } else { #if CONFIG_AAC_PARSER AACADTSHeaderInfo hdr; - GetBitContext gb; - int profile; - init_get_bits8(&gb, buf, buf_size); + if (buf_size < AV_AAC_ADTS_HEADER_SIZE || - ff_adts_header_parse(&gb, &hdr) < 0) + ff_adts_header_parse_buf(buf, &hdr) < 0) return i; - avctx->profile = hdr.object_type - 1; - s1->key_frame = (avctx->profile == AV_PROFILE_AAC_USAC) ? get_bits1(&gb) : 1; + if (avctx->profile == AV_PROFILE_UNKNOWN) + avctx->profile = hdr.object_type - 1; + /* ADTS does not support USAC */ + s1->key_frame = 1; bit_rate = hdr.bit_rate; #endif } diff --git a/libavcodec/aac_parser.c b/libavcodec/aac_parser.c index 186fcd887..cad36d817 100644 --- a/libavcodec/aac_parser.c +++ b/libavcodec/aac_parser.c @@ -24,6 +24,7 @@ #include "aac_ac3_parser.h" #include "adts_header.h" #include "adts_parser.h" +#include "parser_internal.h" #include "libavutil/intreadwrite.h" static int aac_sync(uint64_t state, int *need_next_header, int *new_frame_start) @@ -51,10 +52,10 @@ static av_cold int aac_parse_init(AVCodecParserContext *s1) } -const AVCodecParser ff_aac_parser = { - .codec_ids = { AV_CODEC_ID_AAC }, +const FFCodecParser ff_aac_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_AAC), .priv_data_size = sizeof(AACAC3ParseContext), - .parser_init = aac_parse_init, - .parser_parse = ff_aac_ac3_parse, - .parser_close = ff_parse_close, + .init = aac_parse_init, + .parse = ff_aac_ac3_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/aaccoder.c b/libavcodec/aaccoder.c index 4ce54ca88..7f1c4cdcc 100644 --- a/libavcodec/aaccoder.c +++ b/libavcodec/aaccoder.c @@ -47,8 +47,6 @@ #include "aacenc_is.h" #include "aacenc_tns.h" -#include "aacenc_ltp.h" -#include "aacenc_pred.h" #include "libavcodec/aaccoder_twoloop.h" @@ -175,7 +173,7 @@ static av_always_inline float quantize_and_encode_band_cost_template( if (BT_ESC) { for (int j = 0; j < 2; j++) { if (ff_aac_codebook_vectors[cb-1][curidx*2+j] == 64.0f) { - int coef = av_clip_uintp2(quant(fabsf(in[i+j]), Q, ROUNDING), 13); + int coef = av_clip(quant(fabsf(in[i+j]), Q, ROUNDING), 16, (1 << 13) - 1); int len = av_log2(coef); put_bits(pb, len - 4 + 1, (1 << (len - 4 + 1)) - 2); @@ -294,120 +292,6 @@ typedef struct BandCodingPath { int run; } BandCodingPath; -/** - * Encode band info for single window group bands. - */ -static void encode_window_bands_info(AACEncContext *s, SingleChannelElement *sce, - int win, int group_len, const float lambda) -{ - BandCodingPath path[120][CB_TOT_ALL]; - int w, swb, cb, start, size; - int i, j; - const int max_sfb = sce->ics.max_sfb; - const int run_bits = sce->ics.num_windows == 1 ? 5 : 3; - const int run_esc = (1 << run_bits) - 1; - int idx, ppos, count; - int stackrun[120], stackcb[120], stack_len; - float next_minrd = INFINITY; - int next_mincb = 0; - - s->aacdsp.abs_pow34(s->scoefs, sce->coeffs, 1024); - start = win*128; - for (cb = 0; cb < CB_TOT_ALL; cb++) { - path[0][cb].cost = 0.0f; - path[0][cb].prev_idx = -1; - path[0][cb].run = 0; - } - for (swb = 0; swb < max_sfb; swb++) { - size = sce->ics.swb_sizes[swb]; - if (sce->zeroes[win*16 + swb]) { - for (cb = 0; cb < CB_TOT_ALL; cb++) { - path[swb+1][cb].prev_idx = cb; - path[swb+1][cb].cost = path[swb][cb].cost; - path[swb+1][cb].run = path[swb][cb].run + 1; - } - } else { - float minrd = next_minrd; - int mincb = next_mincb; - next_minrd = INFINITY; - next_mincb = 0; - for (cb = 0; cb < CB_TOT_ALL; cb++) { - float cost_stay_here, cost_get_here; - float rd = 0.0f; - if (cb >= 12 && sce->band_type[win*16+swb] < aac_cb_out_map[cb] || - cb < aac_cb_in_map[sce->band_type[win*16+swb]] && sce->band_type[win*16+swb] > aac_cb_out_map[cb]) { - path[swb+1][cb].prev_idx = -1; - path[swb+1][cb].cost = INFINITY; - path[swb+1][cb].run = path[swb][cb].run + 1; - continue; - } - for (w = 0; w < group_len; w++) { - FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(win+w)*16+swb]; - rd += quantize_band_cost(s, &sce->coeffs[start + w*128], - &s->scoefs[start + w*128], size, - sce->sf_idx[(win+w)*16+swb], aac_cb_out_map[cb], - lambda / band->threshold, INFINITY, NULL, NULL); - } - cost_stay_here = path[swb][cb].cost + rd; - cost_get_here = minrd + rd + run_bits + 4; - if ( run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run] - != run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run+1]) - cost_stay_here += run_bits; - if (cost_get_here < cost_stay_here) { - path[swb+1][cb].prev_idx = mincb; - path[swb+1][cb].cost = cost_get_here; - path[swb+1][cb].run = 1; - } else { - path[swb+1][cb].prev_idx = cb; - path[swb+1][cb].cost = cost_stay_here; - path[swb+1][cb].run = path[swb][cb].run + 1; - } - if (path[swb+1][cb].cost < next_minrd) { - next_minrd = path[swb+1][cb].cost; - next_mincb = cb; - } - } - } - start += sce->ics.swb_sizes[swb]; - } - - //convert resulting path from backward-linked list - stack_len = 0; - idx = 0; - for (cb = 1; cb < CB_TOT_ALL; cb++) - if (path[max_sfb][cb].cost < path[max_sfb][idx].cost) - idx = cb; - ppos = max_sfb; - while (ppos > 0) { - av_assert1(idx >= 0); - cb = idx; - stackrun[stack_len] = path[ppos][cb].run; - stackcb [stack_len] = cb; - idx = path[ppos-path[ppos][cb].run+1][cb].prev_idx; - ppos -= path[ppos][cb].run; - stack_len++; - } - //perform actual band info encoding - start = 0; - for (i = stack_len - 1; i >= 0; i--) { - cb = aac_cb_out_map[stackcb[i]]; - put_bits(&s->pb, 4, cb); - count = stackrun[i]; - memset(sce->zeroes + win*16 + start, !cb, count); - //XXX: memset when band_type is also uint8_t - for (j = 0; j < count; j++) { - sce->band_type[win*16 + start] = cb; - start++; - } - while (count >= run_esc) { - put_bits(&s->pb, run_bits, run_esc); - count -= run_esc; - } - put_bits(&s->pb, run_bits, count); - } -} - - typedef struct TrellisPath { float cost; int prev; @@ -455,166 +339,6 @@ static void set_special_band_scalefactors(AACEncContext *s, SingleChannelElement } } -static void search_for_quantizers_anmr(AVCodecContext *avctx, AACEncContext *s, - SingleChannelElement *sce, - const float lambda) -{ - int q, w, w2, g, start = 0; - int i, j; - int idx; - TrellisPath paths[TRELLIS_STAGES][TRELLIS_STATES]; - int bandaddr[TRELLIS_STAGES]; - int minq; - float mincost; - float q0f = FLT_MAX, q1f = 0.0f, qnrgf = 0.0f; - int q0, q1, qcnt = 0; - - for (i = 0; i < 1024; i++) { - float t = fabsf(sce->coeffs[i]); - if (t > 0.0f) { - q0f = FFMIN(q0f, t); - q1f = FFMAX(q1f, t); - qnrgf += t*t; - qcnt++; - } - } - - if (!qcnt) { - memset(sce->sf_idx, 0, sizeof(sce->sf_idx)); - memset(sce->zeroes, 1, sizeof(sce->zeroes)); - return; - } - - //minimum scalefactor index is when minimum nonzero coefficient after quantizing is not clipped - q0 = av_clip(coef2minsf(q0f), 0, SCALE_MAX_POS-1); - //maximum scalefactor index is when maximum coefficient after quantizing is still not zero - q1 = av_clip(coef2maxsf(q1f), 1, SCALE_MAX_POS); - if (q1 - q0 > 60) { - int q0low = q0; - int q1high = q1; - //minimum scalefactor index is when maximum nonzero coefficient after quantizing is not clipped - int qnrg = av_clip_uint8(log2f(sqrtf(qnrgf/qcnt))*4 - 31 + SCALE_ONE_POS - SCALE_DIV_512); - q1 = qnrg + 30; - q0 = qnrg - 30; - if (q0 < q0low) { - q1 += q0low - q0; - q0 = q0low; - } else if (q1 > q1high) { - q0 -= q1 - q1high; - q1 = q1high; - } - } - // q0 == q1 isn't really a legal situation - if (q0 == q1) { - // the following is indirect but guarantees q1 != q0 && q1 near q0 - q1 = av_clip(q0+1, 1, SCALE_MAX_POS); - q0 = av_clip(q1-1, 0, SCALE_MAX_POS - 1); - } - - for (i = 0; i < TRELLIS_STATES; i++) { - paths[0][i].cost = 0.0f; - paths[0][i].prev = -1; - } - for (j = 1; j < TRELLIS_STAGES; j++) { - for (i = 0; i < TRELLIS_STATES; i++) { - paths[j][i].cost = INFINITY; - paths[j][i].prev = -2; - } - } - idx = 1; - s->aacdsp.abs_pow34(s->scoefs, sce->coeffs, 1024); - for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { - start = w*128; - for (g = 0; g < sce->ics.num_swb; g++) { - const float *coefs = &sce->coeffs[start]; - float qmin, qmax; - int nz = 0; - - bandaddr[idx] = w * 16 + g; - qmin = INT_MAX; - qmax = 0.0f; - for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { - FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; - if (band->energy <= band->threshold || band->threshold == 0.0f) { - sce->zeroes[(w+w2)*16+g] = 1; - continue; - } - sce->zeroes[(w+w2)*16+g] = 0; - nz = 1; - for (i = 0; i < sce->ics.swb_sizes[g]; i++) { - float t = fabsf(coefs[w2*128+i]); - if (t > 0.0f) - qmin = FFMIN(qmin, t); - qmax = FFMAX(qmax, t); - } - } - if (nz) { - int minscale, maxscale; - float minrd = INFINITY; - float maxval; - //minimum scalefactor index is when minimum nonzero coefficient after quantizing is not clipped - minscale = coef2minsf(qmin); - //maximum scalefactor index is when maximum coefficient after quantizing is still not zero - maxscale = coef2maxsf(qmax); - minscale = av_clip(minscale - q0, 0, TRELLIS_STATES - 1); - maxscale = av_clip(maxscale - q0, 0, TRELLIS_STATES); - if (minscale == maxscale) { - maxscale = av_clip(minscale+1, 1, TRELLIS_STATES); - minscale = av_clip(maxscale-1, 0, TRELLIS_STATES - 1); - } - maxval = find_max_val(sce->ics.group_len[w], sce->ics.swb_sizes[g], s->scoefs+start); - for (q = minscale; q < maxscale; q++) { - float dist = 0; - int cb = find_min_book(maxval, sce->sf_idx[w*16+g]); - for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { - FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; - dist += quantize_band_cost(s, coefs + w2*128, s->scoefs + start + w2*128, sce->ics.swb_sizes[g], - q + q0, cb, lambda / band->threshold, INFINITY, NULL, NULL); - } - minrd = FFMIN(minrd, dist); - - for (i = 0; i < q1 - q0; i++) { - float cost; - cost = paths[idx - 1][i].cost + dist - + ff_aac_scalefactor_bits[q - i + SCALE_DIFF_ZERO]; - if (cost < paths[idx][q].cost) { - paths[idx][q].cost = cost; - paths[idx][q].prev = i; - } - } - } - } else { - for (q = 0; q < q1 - q0; q++) { - paths[idx][q].cost = paths[idx - 1][q].cost + 1; - paths[idx][q].prev = q; - } - } - sce->zeroes[w*16+g] = !nz; - start += sce->ics.swb_sizes[g]; - idx++; - } - } - idx--; - mincost = paths[idx][0].cost; - minq = 0; - for (i = 1; i < TRELLIS_STATES; i++) { - if (paths[idx][i].cost < mincost) { - mincost = paths[idx][i].cost; - minq = i; - } - } - while (idx) { - sce->sf_idx[bandaddr[idx]] = minq + q0; - minq = FFMAX(paths[idx][minq].prev, 0); - idx--; - } - //set the same quantizers inside window groups - for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) - for (g = 0; g < sce->ics.num_swb; g++) - for (w2 = 1; w2 < sce->ics.group_len[w]; w2++) - sce->sf_idx[(w+w2)*16+g] = sce->sf_idx[w*16+g]; -} - static void search_for_quantizers_fast(AVCodecContext *avctx, AACEncContext *s, SingleChannelElement *sce, const float lambda) @@ -1117,70 +841,30 @@ static void search_for_ms(AACEncContext *s, ChannelElement *cpe) } const AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = { - [AAC_CODER_ANMR] = { - search_for_quantizers_anmr, - encode_window_bands_info, - quantize_and_encode_band, - ff_aac_encode_tns_info, - ff_aac_encode_ltp_info, - ff_aac_encode_main_pred, - ff_aac_adjust_common_pred, - ff_aac_adjust_common_ltp, - ff_aac_apply_main_pred, - ff_aac_apply_tns, - ff_aac_update_ltp, - ff_aac_ltp_insert_new_frame, - set_special_band_scalefactors, - search_for_pns, - mark_pns, - ff_aac_search_for_tns, - ff_aac_search_for_ltp, - search_for_ms, - ff_aac_search_for_is, - ff_aac_search_for_pred, - }, [AAC_CODER_TWOLOOP] = { search_for_quantizers_twoloop, codebook_trellis_rate, quantize_and_encode_band, ff_aac_encode_tns_info, - ff_aac_encode_ltp_info, - ff_aac_encode_main_pred, - ff_aac_adjust_common_pred, - ff_aac_adjust_common_ltp, - ff_aac_apply_main_pred, ff_aac_apply_tns, - ff_aac_update_ltp, - ff_aac_ltp_insert_new_frame, set_special_band_scalefactors, search_for_pns, mark_pns, ff_aac_search_for_tns, - ff_aac_search_for_ltp, search_for_ms, ff_aac_search_for_is, - ff_aac_search_for_pred, }, [AAC_CODER_FAST] = { search_for_quantizers_fast, codebook_trellis_rate, quantize_and_encode_band, ff_aac_encode_tns_info, - ff_aac_encode_ltp_info, - ff_aac_encode_main_pred, - ff_aac_adjust_common_pred, - ff_aac_adjust_common_ltp, - ff_aac_apply_main_pred, ff_aac_apply_tns, - ff_aac_update_ltp, - ff_aac_ltp_insert_new_frame, set_special_band_scalefactors, search_for_pns, mark_pns, ff_aac_search_for_tns, - ff_aac_search_for_ltp, search_for_ms, ff_aac_search_for_is, - ff_aac_search_for_pred, }, }; diff --git a/libavcodec/aaccoder_twoloop.h b/libavcodec/aaccoder_twoloop.h index c56abc68a..6ac2af51c 100644 --- a/libavcodec/aaccoder_twoloop.h +++ b/libavcodec/aaccoder_twoloop.h @@ -311,14 +311,14 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, /** * Scale uplims to match rate distortion to quality - * bu applying noisy band depriorization and tonal band priorization. + * bu applying noisy band depriorization and tonal band prioritization. * Maxval-energy ratio gives us an idea of how noisy/tonal the band is. * If maxval^2 ~ energy, then that band is mostly noise, and we can relax * rate distortion requirements. */ memcpy(euplims, uplims, sizeof(euplims)); for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { - /** psy already priorizes transients to some extent */ + /** psy already prioritizes transients to some extent */ float de_psy_factor = (sce->ics.num_windows > 1) ? 8.0f / sce->ics.group_len[w] : 1.0f; start = w*128; for (g = 0; g < sce->ics.num_swb; g++) { @@ -331,7 +331,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, nzslope * cleanup_factor); energy2uplim *= de_psy_factor; if (!(avctx->flags & AV_CODEC_FLAG_QSCALE)) { - /** In ABR, we need to priorize less and let rate control do its thing */ + /** In ABR, we need to prioritize less and let rate control do its thing */ energy2uplim = sqrtf(energy2uplim); } energy2uplim = FFMAX(0.015625f, FFMIN(1.0f, energy2uplim)); @@ -345,7 +345,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, 2.0f); energy2uplim *= de_psy_factor; if (!(avctx->flags & AV_CODEC_FLAG_QSCALE)) { - /** In ABR, we need to priorize less and let rate control do its thing */ + /** In ABR, we need to prioritize less and let rate control do its thing */ energy2uplim = sqrtf(energy2uplim); } energy2uplim = FFMAX(0.015625f, FFMIN(1.0f, energy2uplim)); diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index 3ff61f788..b8df8dc53 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -502,7 +502,7 @@ static void put_ics_info(AACEncContext *s, IndividualChannelStream *info) put_bits(&s->pb, 1, info->use_kb_window[0]); if (info->window_sequence[0] != EIGHT_SHORT_SEQUENCE) { put_bits(&s->pb, 6, info->max_sfb); - put_bits(&s->pb, 1, !!info->predictor_present); + put_bits(&s->pb, 1, 0); /* No predictor present */ } else { put_bits(&s->pb, 4, info->max_sfb); for (w = 1; w < 8; w++) @@ -762,13 +762,8 @@ static int encode_individual_channel(AVCodecContext *avctx, AACEncContext *s, int common_window) { put_bits(&s->pb, 8, sce->sf_idx[0]); - if (!common_window) { + if (!common_window) put_ics_info(s, &sce->ics); - if (s->coder->encode_main_pred) - s->coder->encode_main_pred(s, sce); - if (s->coder->encode_ltp_info) - s->coder->encode_ltp_info(s, sce, 0); - } encode_band_info(s, sce); encode_scale_factors(avctx, s, sce); encode_pulses(s, &sce->pulse); @@ -850,8 +845,6 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } copy_input_samples(s, frame); - if (s->psypp) - ff_psy_preprocess(s->psypp, s->planar_samples, s->channels); if (!avctx->frame_num) return 0; @@ -935,12 +928,6 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, apply_window_and_mdct(s, sce, overlap); - if (s->options.ltp && s->coder->update_ltp) { - s->coder->update_ltp(s, sce); - apply_window[sce->ics.window_sequence[0]](s->fdsp, sce, &sce->ltp_state[0]); - s->mdct1024_fn(s->mdct1024, sce->lcoeffs, sce->ret_buf, sizeof(float)); - } - for (k = 0; k < 1024; k++) { if (!(fabs(cpe->ch[ch].coeffs[k]) < 1E16)) { // Ensure headroom for energy calculation av_log(avctx, AV_LOG_ERROR, "Input contains (near) NaN/+-Inf\n"); @@ -976,10 +963,6 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, for (ch = 0; ch < chans; ch++) { sce = &cpe->ch[ch]; coeffs[ch] = sce->coeffs; - sce->ics.predictor_present = 0; - sce->ics.ltp.present = 0; - memset(sce->ics.ltp.used, 0, sizeof(sce->ics.ltp.used)); - memset(sce->ics.prediction_used, 0, sizeof(sce->ics.prediction_used)); memset(&sce->tns, 0, sizeof(TemporalNoiseShaping)); for (w = 0; w < 128; w++) if (sce->band_type[w] > RESERVED_BT) @@ -1032,24 +1015,6 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, if (cpe->is_mode) is_mode = 1; apply_intensity_stereo(cpe); } - if (s->options.pred) { /* Prediction */ - for (ch = 0; ch < chans; ch++) { - sce = &cpe->ch[ch]; - s->cur_channel = start_ch + ch; - if (s->options.pred && s->coder->search_for_pred) - s->coder->search_for_pred(s, sce); - if (cpe->ch[ch].ics.predictor_present) pred_mode = 1; - } - if (s->coder->adjust_common_pred) - s->coder->adjust_common_pred(s, cpe); - for (ch = 0; ch < chans; ch++) { - sce = &cpe->ch[ch]; - s->cur_channel = start_ch + ch; - if (s->options.pred && s->coder->apply_main_pred) - s->coder->apply_main_pred(s, sce); - } - s->cur_channel = start_ch; - } if (s->options.mid_side) { /* Mid/Side stereo */ if (s->options.mid_side == -1 && s->coder->search_for_ms) s->coder->search_for_ms(s, cpe); @@ -1058,26 +1023,10 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, apply_mid_side_stereo(cpe); } adjust_frame_information(cpe, chans); - if (s->options.ltp) { /* LTP */ - for (ch = 0; ch < chans; ch++) { - sce = &cpe->ch[ch]; - s->cur_channel = start_ch + ch; - if (s->coder->search_for_ltp) - s->coder->search_for_ltp(s, sce, cpe->common_window); - if (sce->ics.ltp.present) pred_mode = 1; - } - s->cur_channel = start_ch; - if (s->coder->adjust_common_ltp) - s->coder->adjust_common_ltp(s, cpe); - } if (chans == 2) { put_bits(&s->pb, 1, cpe->common_window); if (cpe->common_window) { put_ics_info(s, &cpe->ch[0].ics); - if (s->coder->encode_main_pred) - s->coder->encode_main_pred(s, &cpe->ch[0]); - if (s->coder->encode_ltp_info) - s->coder->encode_ltp_info(s, &cpe->ch[0], 1); encode_ms_info(&s->pb, cpe); if (cpe->ms_mode) ms_mode = 1; } @@ -1162,9 +1111,6 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } } while (1); - if (s->options.ltp && s->coder->ltp_insert_new_frame) - s->coder->ltp_insert_new_frame(s); - put_bits(&s->pb, 3, TYPE_END); flush_put_bits(&s->pb); @@ -1193,8 +1139,6 @@ static av_cold int aac_encode_end(AVCodecContext *avctx) av_tx_uninit(&s->mdct128); ff_psy_end(&s->psy); ff_lpc_end(&s->lpc); - if (s->psypp) - ff_psy_preprocess_end(s->psypp); av_freep(&s->buffer.samples); av_freep(&s->cpe); av_freep(&s->fdsp); @@ -1287,14 +1231,13 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) } /* Samplerate */ - for (i = 0; i < 16; i++) - if (avctx->sample_rate == ff_mpeg4audio_sample_rates[i]) + for (int i = 0;; i++) { + av_assert1(i < 13); + if (avctx->sample_rate == ff_mpeg4audio_sample_rates[i]) { + s->samplerate_index = i; break; - s->samplerate_index = i; - ERROR_IF(s->samplerate_index == 16 || - s->samplerate_index >= ff_aac_swb_size_1024_len || - s->samplerate_index >= ff_aac_swb_size_128_len, - "Unsupported sample rate %d\n", avctx->sample_rate); + } + } /* Bitrate limiting */ WARN_IF(1024.0 * avctx->bit_rate / avctx->sample_rate > 6144 * s->channels, @@ -1310,48 +1253,17 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) for (i = 0; i < FF_ARRAY_ELEMS(aacenc_profiles); i++) if (avctx->profile == aacenc_profiles[i]) break; + ERROR_IF(i == FF_ARRAY_ELEMS(aacenc_profiles), "Profile not supported!\n"); if (avctx->profile == AV_PROFILE_MPEG2_AAC_LOW) { avctx->profile = AV_PROFILE_AAC_LOW; - ERROR_IF(s->options.pred, - "Main prediction unavailable in the \"mpeg2_aac_low\" profile\n"); - ERROR_IF(s->options.ltp, - "LTP prediction unavailable in the \"mpeg2_aac_low\" profile\n"); WARN_IF(s->options.pns, "PNS unavailable in the \"mpeg2_aac_low\" profile, turning off\n"); s->options.pns = 0; - } else if (avctx->profile == AV_PROFILE_AAC_LTP) { - s->options.ltp = 1; - ERROR_IF(s->options.pred, - "Main prediction unavailable in the \"aac_ltp\" profile\n"); - } else if (avctx->profile == AV_PROFILE_AAC_MAIN) { - s->options.pred = 1; - ERROR_IF(s->options.ltp, - "LTP prediction unavailable in the \"aac_main\" profile\n"); - } else if (s->options.ltp) { - avctx->profile = AV_PROFILE_AAC_LTP; - WARN_IF(1, - "Chainging profile to \"aac_ltp\"\n"); - ERROR_IF(s->options.pred, - "Main prediction unavailable in the \"aac_ltp\" profile\n"); - } else if (s->options.pred) { - avctx->profile = AV_PROFILE_AAC_MAIN; - WARN_IF(1, - "Chainging profile to \"aac_main\"\n"); - ERROR_IF(s->options.ltp, - "LTP prediction unavailable in the \"aac_main\" profile\n"); } s->profile = avctx->profile; /* Coder limitations */ s->coder = &ff_aac_coders[s->options.coder]; - if (s->options.coder == AAC_CODER_ANMR) { - ERROR_IF(avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL, - "The ANMR coder is considered experimental, add -strict -2 to enable!\n"); - s->options.intensity_stereo = 0; - s->options.pns = 0; - } - ERROR_IF(s->options.ltp && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL, - "The LPT profile requires experimental compliance, add -strict -2 to enable!\n"); /* M/S introduces horrible artifacts with multichannel files, this is temporary */ if (s->channels > 3) @@ -1378,7 +1290,6 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) if ((ret = ff_psy_init(&s->psy, avctx, 2, sizes, lengths, s->chan_map[0], grouping)) < 0) return ret; - s->psypp = ff_psy_preprocess_init(avctx); ff_lpc_init(&s->lpc, 2*avctx->frame_size, TNS_MAX_ORDER, FF_LPC_TYPE_LEVINSON); s->random_state = 0x1f2e3d4c; @@ -1392,15 +1303,12 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) #define AACENC_FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM static const AVOption aacenc_options[] = { {"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_TWOLOOP}, 0, AAC_CODER_NB-1, AACENC_FLAGS, .unit = "coder"}, - {"anmr", "ANMR method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "coder"}, {"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "coder"}, {"fast", "Fast search", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "coder"}, {"aac_ms", "Force M/S stereo coding", offsetof(AACEncContext, options.mid_side), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AACENC_FLAGS}, {"aac_is", "Intensity stereo coding", offsetof(AACEncContext, options.intensity_stereo), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS}, {"aac_pns", "Perceptual noise substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS}, {"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS}, - {"aac_ltp", "Long term prediction", offsetof(AACEncContext, options.ltp), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, - {"aac_pred", "AAC-Main prediction", offsetof(AACEncContext, options.pred), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, {"aac_pce", "Forces the use of PCEs", offsetof(AACEncContext, options.pce), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, FF_AAC_PROFILE_OPTS {NULL} @@ -1430,9 +1338,8 @@ const FFCodec ff_aac_encoder = { FF_CODEC_ENCODE_CB(aac_encode_frame), .close = aac_encode_end, .defaults = aac_encode_defaults, - .p.supported_samplerates = ff_mpeg4audio_sample_rates, + CODEC_SAMPLERATES_ARRAY(ff_mpeg4audio_sample_rates), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &aacenc_class, }; diff --git a/libavcodec/aacenc.h b/libavcodec/aacenc.h index ae15f91e0..51a216e6d 100644 --- a/libavcodec/aacenc.h +++ b/libavcodec/aacenc.h @@ -42,7 +42,6 @@ #define CLIP_AVOIDANCE_FACTOR 0.95f typedef enum AACCoder { - AAC_CODER_ANMR = 0, AAC_CODER_TWOLOOP, AAC_CODER_FAST, @@ -67,24 +66,11 @@ typedef struct AACEncOptions { int coder; int pns; int tns; - int ltp; int pce; - int pred; int mid_side; int intensity_stereo; } AACEncOptions; -/** - * Long Term Prediction - */ -typedef struct LongTermPrediction { - int8_t present; - int16_t lag; - int coef_idx; - float coef; - int8_t used[MAX_LTP_LONG_SFB]; -} LongTermPrediction; - /** * Individual Channel Stream */ @@ -93,17 +79,11 @@ typedef struct IndividualChannelStream { enum WindowSequence window_sequence[2]; uint8_t use_kb_window[2]; ///< If set, use Kaiser-Bessel window, otherwise use a sine window. uint8_t group_len[8]; - LongTermPrediction ltp; const uint16_t *swb_offset; ///< table of offsets to the lowest spectral coefficient of a scalefactor band, sfb, for a particular window const uint8_t *swb_sizes; ///< table of scalefactor band sizes for a particular window int num_swb; ///< number of scalefactor window bands int num_windows; int tns_max_bands; - int predictor_present; - int predictor_initialized; - int predictor_reset_group; - int predictor_reset_count[31]; ///< used to count prediction resets - uint8_t prediction_used[41]; uint8_t window_clipping[8]; ///< set if a certain window is near clipping float clip_avoidance_factor; ///< set if any window is near clipping to the necessary atennuation factor to avoid it } IndividualChannelStream; @@ -138,9 +118,6 @@ typedef struct SingleChannelElement { DECLARE_ALIGNED(32, float, pcoeffs)[1024]; ///< coefficients for IMDCT, pristine DECLARE_ALIGNED(32, float, coeffs)[1024]; ///< coefficients for IMDCT, maybe processed DECLARE_ALIGNED(32, float, ret_buf)[2048]; ///< PCM output buffer - DECLARE_ALIGNED(16, float, ltp_state)[3072]; ///< time signal for LTP - DECLARE_ALIGNED(32, float, lcoeffs)[1024]; ///< MDCT of LTP coefficients - DECLARE_ALIGNED(32, float, prcoeffs)[1024]; ///< Main prediction coefs PredictorState predictor_state[MAX_PREDICTORS]; } SingleChannelElement; @@ -168,22 +145,13 @@ typedef struct AACCoefficientsEncoder { void (*quantize_and_encode_band)(struct AACEncContext *s, PutBitContext *pb, const float *in, float *out, int size, int scale_idx, int cb, const float lambda, int rtz); void (*encode_tns_info)(struct AACEncContext *s, SingleChannelElement *sce); - void (*encode_ltp_info)(struct AACEncContext *s, SingleChannelElement *sce, int common_window); - void (*encode_main_pred)(struct AACEncContext *s, SingleChannelElement *sce); - void (*adjust_common_pred)(struct AACEncContext *s, ChannelElement *cpe); - void (*adjust_common_ltp)(struct AACEncContext *s, ChannelElement *cpe); - void (*apply_main_pred)(struct AACEncContext *s, SingleChannelElement *sce); void (*apply_tns_filt)(struct AACEncContext *s, SingleChannelElement *sce); - void (*update_ltp)(struct AACEncContext *s, SingleChannelElement *sce); - void (*ltp_insert_new_frame)(struct AACEncContext *s); void (*set_special_band_scalefactors)(struct AACEncContext *s, SingleChannelElement *sce); void (*search_for_pns)(struct AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce); void (*mark_pns)(struct AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce); void (*search_for_tns)(struct AACEncContext *s, SingleChannelElement *sce); - void (*search_for_ltp)(struct AACEncContext *s, SingleChannelElement *sce, int common_window); void (*search_for_ms)(struct AACEncContext *s, ChannelElement *cpe); void (*search_for_is)(struct AACEncContext *s, AVCodecContext *avctx, ChannelElement *cpe); - void (*search_for_pred)(struct AACEncContext *s, SingleChannelElement *sce); } AACCoefficientsEncoder; extern const AACCoefficientsEncoder ff_aac_coders[]; @@ -231,7 +199,6 @@ typedef struct AACEncContext { ChannelElement *cpe; ///< channel elements FFPsyContext psy; - struct FFPsyPreprocessContext* psypp; const AACCoefficientsEncoder *coder; int cur_channel; ///< current channel for coder context int random_state; diff --git a/libavcodec/aacenc_is.c b/libavcodec/aacenc_is.c index 4943b6450..4e711382d 100644 --- a/libavcodec/aacenc_is.c +++ b/libavcodec/aacenc_is.c @@ -30,16 +30,27 @@ #include "aacenc_is.h" #include "aacenc_quantization.h" -struct AACISError ff_aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe, - int start, int w, int g, float ener0, - float ener1, float ener01, - int use_pcoeffs, int phase) +/** Frequency in Hz for lower limit of intensity stereo **/ +#define INT_STEREO_LOW_LIMIT 6100 + +struct AACISError { + int pass; /* 1 if dist2 <= dist1 */ + int phase; /* -1 or +1 */ + float error; /* fabs(dist1 - dist2) */ + float dist1; /* From original coeffs */ + float dist2; /* From IS'd coeffs */ + float ener01; +}; + +static struct AACISError aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe, + int start, int w, int g, float ener0, + float ener1, float ener01, int phase) { int i, w2; SingleChannelElement *sce0 = &cpe->ch[0]; SingleChannelElement *sce1 = &cpe->ch[1]; - float *L = use_pcoeffs ? sce0->pcoeffs : sce0->coeffs; - float *R = use_pcoeffs ? sce1->pcoeffs : sce1->coeffs; + float *L = sce0->coeffs; + float *R = sce1->coeffs; float *L34 = &s->scoefs[256*0], *R34 = &s->scoefs[256*1]; float *IS = &s->scoefs[256*2], *I34 = &s->scoefs[256*3]; float dist1 = 0.0f, dist2 = 0.0f; @@ -128,10 +139,10 @@ void ff_aac_search_for_is(AACEncContext *s, AVCodecContext *avctx, ChannelElemen ener01p += (coef0 - coef1)*(coef0 - coef1); } } - ph_err1 = ff_aac_is_encoding_err(s, cpe, start, w, g, - ener0, ener1, ener01p, 0, -1); - ph_err2 = ff_aac_is_encoding_err(s, cpe, start, w, g, - ener0, ener1, ener01, 0, +1); + ph_err1 = aac_is_encoding_err(s, cpe, start, w, g, + ener0, ener1, ener01p, -1); + ph_err2 = aac_is_encoding_err(s, cpe, start, w, g, + ener0, ener1, ener01, +1); best = (ph_err1.pass && ph_err1.error < ph_err2.error) ? &ph_err1 : &ph_err2; if (best->pass) { cpe->is_mask[w*16+g] = 1; diff --git a/libavcodec/aacenc_is.h b/libavcodec/aacenc_is.h index 269fd1a9c..beaa70c79 100644 --- a/libavcodec/aacenc_is.h +++ b/libavcodec/aacenc_is.h @@ -30,22 +30,6 @@ #include "aacenc.h" -/** Frequency in Hz for lower limit of intensity stereo **/ -#define INT_STEREO_LOW_LIMIT 6100 - -struct AACISError { - int pass; /* 1 if dist2 <= dist1 */ - int phase; /* -1 or +1 */ - float error; /* fabs(dist1 - dist2) */ - float dist1; /* From original coeffs */ - float dist2; /* From IS'd coeffs */ - float ener01; -}; - -struct AACISError ff_aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe, - int start, int w, int g, float ener0, - float ener1, float ener01, - int use_pcoeffs, int phase); void ff_aac_search_for_is(AACEncContext *s, AVCodecContext *avctx, ChannelElement *cpe); #endif /* AVCODEC_AACENC_IS_H */ diff --git a/libavcodec/aacenc_ltp.c b/libavcodec/aacenc_ltp.c deleted file mode 100644 index 58f792107..000000000 --- a/libavcodec/aacenc_ltp.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * AAC encoder long term prediction extension - * Copyright (C) 2015 Rostislav Pehlivanov - * - * 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 - * AAC encoder long term prediction extension - * @author Rostislav Pehlivanov ( atomnuker gmail com ) - */ - -#include "aacenc_ltp.h" -#include "aacenc_quantization.h" -#include "aacenc_utils.h" - -/** - * Encode LTP data. - */ -void ff_aac_encode_ltp_info(AACEncContext *s, SingleChannelElement *sce, - int common_window) -{ - int i; - IndividualChannelStream *ics = &sce->ics; - if (s->profile != AV_PROFILE_AAC_LTP || !ics->predictor_present) - return; - if (common_window) - put_bits(&s->pb, 1, 0); - put_bits(&s->pb, 1, ics->ltp.present); - if (!ics->ltp.present) - return; - put_bits(&s->pb, 11, ics->ltp.lag); - put_bits(&s->pb, 3, ics->ltp.coef_idx); - for (i = 0; i < FFMIN(ics->max_sfb, MAX_LTP_LONG_SFB); i++) - put_bits(&s->pb, 1, ics->ltp.used[i]); -} - -void ff_aac_ltp_insert_new_frame(AACEncContext *s) -{ - int i, ch, tag, chans, cur_channel, start_ch = 0; - ChannelElement *cpe; - SingleChannelElement *sce; - for (i = 0; i < s->chan_map[0]; i++) { - cpe = &s->cpe[i]; - tag = s->chan_map[i+1]; - chans = tag == TYPE_CPE ? 2 : 1; - for (ch = 0; ch < chans; ch++) { - sce = &cpe->ch[ch]; - cur_channel = start_ch + ch; - /* New sample + overlap */ - memcpy(&sce->ltp_state[0], &sce->ltp_state[1024], 1024*sizeof(sce->ltp_state[0])); - memcpy(&sce->ltp_state[1024], &s->planar_samples[cur_channel][2048], 1024*sizeof(sce->ltp_state[0])); - memcpy(&sce->ltp_state[2048], &sce->ret_buf[0], 1024*sizeof(sce->ltp_state[0])); - sce->ics.ltp.lag = 0; - } - start_ch += chans; - } -} - -static void get_lag(float *buf, const float *new, LongTermPrediction *ltp) -{ - int i, j, lag = 0, max_corr = 0; - float max_ratio = 0.0f; - for (i = 0; i < 2048; i++) { - float corr, s0 = 0.0f, s1 = 0.0f; - const int start = FFMAX(0, i - 1024); - for (j = start; j < 2048; j++) { - const int idx = j - i + 1024; - s0 += new[j]*buf[idx]; - s1 += buf[idx]*buf[idx]; - } - corr = s1 > 0.0f ? s0/sqrt(s1) : 0.0f; - if (corr > max_corr) { - max_corr = corr; - lag = i; - max_ratio = corr/(2048-start); - } - } - ltp->lag = FFMAX(av_clip_uintp2(lag, 11), 0); - ltp->coef_idx = quant_array_idx(max_ratio, ff_ltp_coef, 8); - ltp->coef = ff_ltp_coef[ltp->coef_idx]; -} - -static void generate_samples(float *buf, LongTermPrediction *ltp) -{ - int i, samples_num = 2048; - if (!ltp->lag) { - ltp->present = 0; - return; - } else if (ltp->lag < 1024) { - samples_num = ltp->lag + 1024; - } - for (i = 0; i < samples_num; i++) - buf[i] = ltp->coef*buf[i + 2048 - ltp->lag]; - memset(&buf[i], 0, (2048 - i)*sizeof(float)); -} - -/** - * Process LTP parameters - * @see Patent WO2006070265A1 - */ -void ff_aac_update_ltp(AACEncContext *s, SingleChannelElement *sce) -{ - float *pred_signal = &sce->ltp_state[0]; - const float *samples = &s->planar_samples[s->cur_channel][1024]; - - if (s->profile != AV_PROFILE_AAC_LTP) - return; - - /* Calculate lag */ - get_lag(pred_signal, samples, &sce->ics.ltp); - generate_samples(pred_signal, &sce->ics.ltp); -} - -void ff_aac_adjust_common_ltp(AACEncContext *s, ChannelElement *cpe) -{ - int sfb, count = 0; - SingleChannelElement *sce0 = &cpe->ch[0]; - SingleChannelElement *sce1 = &cpe->ch[1]; - - if (!cpe->common_window || - sce0->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE || - sce1->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - sce0->ics.ltp.present = 0; - return; - } - - for (sfb = 0; sfb < FFMIN(sce0->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++) { - int sum = sce0->ics.ltp.used[sfb] + sce1->ics.ltp.used[sfb]; - if (sum != 2) { - sce0->ics.ltp.used[sfb] = 0; - } else { - count++; - } - } - - sce0->ics.ltp.present = !!count; - sce0->ics.predictor_present = !!count; -} - -/** - * Mark LTP sfb's - */ -void ff_aac_search_for_ltp(AACEncContext *s, SingleChannelElement *sce, - int common_window) -{ - int w, g, w2, i, start = 0, count = 0; - int saved_bits = -(15 + FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB)); - float *C34 = &s->scoefs[128*0], *PCD = &s->scoefs[128*1]; - float *PCD34 = &s->scoefs[128*2]; - const int max_ltp = FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB); - - if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - if (sce->ics.ltp.lag) { - memset(&sce->ltp_state[0], 0, 3072*sizeof(sce->ltp_state[0])); - memset(&sce->ics.ltp, 0, sizeof(LongTermPrediction)); - } - return; - } - - if (!sce->ics.ltp.lag || s->lambda > 120.0f) - return; - - for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { - start = 0; - for (g = 0; g < sce->ics.num_swb; g++) { - int bits1 = 0, bits2 = 0; - float dist1 = 0.0f, dist2 = 0.0f; - if (w*16+g > max_ltp) { - start += sce->ics.swb_sizes[g]; - continue; - } - for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { - int bits_tmp1, bits_tmp2; - FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; - for (i = 0; i < sce->ics.swb_sizes[g]; i++) - PCD[i] = sce->coeffs[start+(w+w2)*128+i] - sce->lcoeffs[start+(w+w2)*128+i]; - s->aacdsp.abs_pow34(C34, &sce->coeffs[start+(w+w2)*128], sce->ics.swb_sizes[g]); - s->aacdsp.abs_pow34(PCD34, PCD, sce->ics.swb_sizes[g]); - dist1 += quantize_band_cost(s, &sce->coeffs[start+(w+w2)*128], C34, sce->ics.swb_sizes[g], - sce->sf_idx[(w+w2)*16+g], sce->band_type[(w+w2)*16+g], - s->lambda/band->threshold, INFINITY, &bits_tmp1, NULL); - dist2 += quantize_band_cost(s, PCD, PCD34, sce->ics.swb_sizes[g], - sce->sf_idx[(w+w2)*16+g], - sce->band_type[(w+w2)*16+g], - s->lambda/band->threshold, INFINITY, &bits_tmp2, NULL); - bits1 += bits_tmp1; - bits2 += bits_tmp2; - } - if (dist2 < dist1 && bits2 < bits1) { - for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) - for (i = 0; i < sce->ics.swb_sizes[g]; i++) - sce->coeffs[start+(w+w2)*128+i] -= sce->lcoeffs[start+(w+w2)*128+i]; - sce->ics.ltp.used[w*16+g] = 1; - saved_bits += bits1 - bits2; - count++; - } - start += sce->ics.swb_sizes[g]; - } - } - - sce->ics.ltp.present = !!count && (saved_bits >= 0); - sce->ics.predictor_present = !!sce->ics.ltp.present; - - /* Reset any marked sfbs */ - if (!sce->ics.ltp.present && !!count) { - for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { - start = 0; - for (g = 0; g < sce->ics.num_swb; g++) { - if (sce->ics.ltp.used[w*16+g]) { - for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { - for (i = 0; i < sce->ics.swb_sizes[g]; i++) { - sce->coeffs[start+(w+w2)*128+i] += sce->lcoeffs[start+(w+w2)*128+i]; - } - } - } - start += sce->ics.swb_sizes[g]; - } - } - } -} diff --git a/libavcodec/aacenc_ltp.h b/libavcodec/aacenc_ltp.h deleted file mode 100644 index 727687842..000000000 --- a/libavcodec/aacenc_ltp.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * AAC encoder long term prediction extension - * Copyright (C) 2015 Rostislav Pehlivanov - * - * 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 - * AAC encoder long term prediction extension - * @author Rostislav Pehlivanov ( atomnuker gmail com ) - */ - -#ifndef AVCODEC_AACENC_LTP_H -#define AVCODEC_AACENC_LTP_H - -#include "aacenc.h" - -void ff_aac_encode_ltp_info(AACEncContext *s, SingleChannelElement *sce, - int common_window); -void ff_aac_update_ltp(AACEncContext *s, SingleChannelElement *sce); -void ff_aac_adjust_common_ltp(AACEncContext *s, ChannelElement *cpe); -void ff_aac_ltp_insert_new_frame(AACEncContext *s); -void ff_aac_search_for_ltp(AACEncContext *s, SingleChannelElement *sce, - int common_window); - -#endif /* AVCODEC_AACENC_LTP_H */ diff --git a/libavcodec/aacenc_pred.c b/libavcodec/aacenc_pred.c deleted file mode 100644 index a486c44d4..000000000 --- a/libavcodec/aacenc_pred.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * AAC encoder main-type prediction - * Copyright (C) 2015 Rostislav Pehlivanov - * - * 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 - * AAC encoder main-type prediction - * @author Rostislav Pehlivanov ( atomnuker gmail com ) - */ - -#include "aactab.h" -#include "aacenc_pred.h" -#include "aacenc_utils.h" -#include "aacenc_is.h" /* <- Needed for common window distortions */ -#include "aacenc_quantization.h" - -#define RESTORE_PRED(sce, sfb) \ - if (sce->ics.prediction_used[sfb]) {\ - sce->ics.prediction_used[sfb] = 0;\ - sce->band_type[sfb] = sce->band_alt[sfb];\ - } - -static inline float flt16_round(float pf) -{ - union av_intfloat32 tmp; - tmp.f = pf; - tmp.i = (tmp.i + 0x00008000U) & 0xFFFF0000U; - return tmp.f; -} - -static inline float flt16_even(float pf) -{ - union av_intfloat32 tmp; - tmp.f = pf; - tmp.i = (tmp.i + 0x00007FFFU + (tmp.i & 0x00010000U >> 16)) & 0xFFFF0000U; - return tmp.f; -} - -static inline float flt16_trunc(float pf) -{ - union av_intfloat32 pun; - pun.f = pf; - pun.i &= 0xFFFF0000U; - return pun.f; -} - -static inline void predict(PredictorState *ps, float *coef, float *rcoef, int set) -{ - float k2; - const float a = 0.953125; // 61.0 / 64 - const float alpha = 0.90625; // 29.0 / 32 - const float k1 = ps->k1; - const float r0 = ps->r0, r1 = ps->r1; - const float cor0 = ps->cor0, cor1 = ps->cor1; - const float var0 = ps->var0, var1 = ps->var1; - const float e0 = *coef - ps->x_est; - const float e1 = e0 - k1 * r0; - - if (set) - *coef = e0; - - ps->cor1 = flt16_trunc(alpha * cor1 + r1 * e1); - ps->var1 = flt16_trunc(alpha * var1 + 0.5f * (r1 * r1 + e1 * e1)); - ps->cor0 = flt16_trunc(alpha * cor0 + r0 * e0); - ps->var0 = flt16_trunc(alpha * var0 + 0.5f * (r0 * r0 + e0 * e0)); - ps->r1 = flt16_trunc(a * (r0 - k1 * e0)); - ps->r0 = flt16_trunc(a * e0); - - /* Prediction for next frame */ - ps->k1 = ps->var0 > 1 ? ps->cor0 * flt16_even(a / ps->var0) : 0; - k2 = ps->var1 > 1 ? ps->cor1 * flt16_even(a / ps->var1) : 0; - *rcoef = ps->x_est = flt16_round(ps->k1*ps->r0 + k2*ps->r1); -} - -static inline void reset_predict_state(PredictorState *ps) -{ - ps->r0 = 0.0f; - ps->r1 = 0.0f; - ps->k1 = 0.0f; - ps->cor0 = 0.0f; - ps->cor1 = 0.0f; - ps->var0 = 1.0f; - ps->var1 = 1.0f; - ps->x_est = 0.0f; -} - -static inline void reset_all_predictors(PredictorState *ps) -{ - int i; - for (i = 0; i < MAX_PREDICTORS; i++) - reset_predict_state(&ps[i]); -} - -static inline void reset_predictor_group(SingleChannelElement *sce, int group_num) -{ - int i; - PredictorState *ps = sce->predictor_state; - for (i = group_num - 1; i < MAX_PREDICTORS; i += 30) - reset_predict_state(&ps[i]); -} - -void ff_aac_apply_main_pred(AACEncContext *s, SingleChannelElement *sce) -{ - int sfb, k; - const int pmax = FFMIN(sce->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); - - if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) { - for (sfb = 0; sfb < pmax; sfb++) { - for (k = sce->ics.swb_offset[sfb]; k < sce->ics.swb_offset[sfb + 1]; k++) { - predict(&sce->predictor_state[k], &sce->coeffs[k], &sce->prcoeffs[k], - sce->ics.predictor_present && sce->ics.prediction_used[sfb]); - } - } - if (sce->ics.predictor_reset_group) { - reset_predictor_group(sce, sce->ics.predictor_reset_group); - } - } else { - reset_all_predictors(sce->predictor_state); - } -} - -/* If inc = 0 you can check if this returns 0 to see if you can reset freely */ -static inline int update_counters(IndividualChannelStream *ics, int inc) -{ - int i; - for (i = 1; i < 31; i++) { - ics->predictor_reset_count[i] += inc; - if (ics->predictor_reset_count[i] > PRED_RESET_FRAME_MIN) - return i; /* Reset this immediately */ - } - return 0; -} - -void ff_aac_adjust_common_pred(AACEncContext *s, ChannelElement *cpe) -{ - int start, w, w2, g, i, count = 0; - SingleChannelElement *sce0 = &cpe->ch[0]; - SingleChannelElement *sce1 = &cpe->ch[1]; - const int pmax0 = FFMIN(sce0->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); - const int pmax1 = FFMIN(sce1->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); - const int pmax = FFMIN(pmax0, pmax1); - - if (!cpe->common_window || - sce0->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE || - sce1->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) - return; - - for (w = 0; w < sce0->ics.num_windows; w += sce0->ics.group_len[w]) { - start = 0; - for (g = 0; g < sce0->ics.num_swb; g++) { - int sfb = w*16+g; - int sum = sce0->ics.prediction_used[sfb] + sce1->ics.prediction_used[sfb]; - float ener0 = 0.0f, ener1 = 0.0f, ener01 = 0.0f; - struct AACISError ph_err1, ph_err2, *erf; - if (sfb < PRED_SFB_START || sfb > pmax || sum != 2) { - RESTORE_PRED(sce0, sfb); - RESTORE_PRED(sce1, sfb); - start += sce0->ics.swb_sizes[g]; - continue; - } - for (w2 = 0; w2 < sce0->ics.group_len[w]; w2++) { - for (i = 0; i < sce0->ics.swb_sizes[g]; i++) { - float coef0 = sce0->pcoeffs[start+(w+w2)*128+i]; - float coef1 = sce1->pcoeffs[start+(w+w2)*128+i]; - ener0 += coef0*coef0; - ener1 += coef1*coef1; - ener01 += (coef0 + coef1)*(coef0 + coef1); - } - } - ph_err1 = ff_aac_is_encoding_err(s, cpe, start, w, g, - ener0, ener1, ener01, 1, -1); - ph_err2 = ff_aac_is_encoding_err(s, cpe, start, w, g, - ener0, ener1, ener01, 1, +1); - erf = ph_err1.error < ph_err2.error ? &ph_err1 : &ph_err2; - if (erf->pass) { - sce0->ics.prediction_used[sfb] = 1; - sce1->ics.prediction_used[sfb] = 1; - count++; - } else { - RESTORE_PRED(sce0, sfb); - RESTORE_PRED(sce1, sfb); - } - start += sce0->ics.swb_sizes[g]; - } - } - - sce1->ics.predictor_present = sce0->ics.predictor_present = !!count; -} - -static void update_pred_resets(SingleChannelElement *sce) -{ - int i, max_group_id_c, max_frame = 0; - float avg_frame = 0.0f; - IndividualChannelStream *ics = &sce->ics; - - /* Update the counters and immediately update any frame behind schedule */ - if ((ics->predictor_reset_group = update_counters(&sce->ics, 1))) - return; - - for (i = 1; i < 31; i++) { - /* Count-based */ - if (ics->predictor_reset_count[i] > max_frame) { - max_group_id_c = i; - max_frame = ics->predictor_reset_count[i]; - } - avg_frame = (ics->predictor_reset_count[i] + avg_frame)/2; - } - - if (max_frame > PRED_RESET_MIN) { - ics->predictor_reset_group = max_group_id_c; - } else { - ics->predictor_reset_group = 0; - } -} - -void ff_aac_search_for_pred(AACEncContext *s, SingleChannelElement *sce) -{ - int sfb, i, count = 0, cost_coeffs = 0, cost_pred = 0; - const int pmax = FFMIN(sce->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); - float *O34 = &s->scoefs[128*0], *P34 = &s->scoefs[128*1]; - float *SENT = &s->scoefs[128*2], *S34 = &s->scoefs[128*3]; - float *QERR = &s->scoefs[128*4]; - - if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - sce->ics.predictor_present = 0; - return; - } - - if (!sce->ics.predictor_initialized) { - reset_all_predictors(sce->predictor_state); - sce->ics.predictor_initialized = 1; - memcpy(sce->prcoeffs, sce->coeffs, 1024*sizeof(float)); - for (i = 1; i < 31; i++) - sce->ics.predictor_reset_count[i] = i; - } - - update_pred_resets(sce); - memcpy(sce->band_alt, sce->band_type, sizeof(sce->band_type)); - - for (sfb = PRED_SFB_START; sfb < pmax; sfb++) { - int cost1, cost2, cb_p; - float dist1, dist2, dist_spec_err = 0.0f; - const int cb_n = sce->zeroes[sfb] ? 0 : sce->band_type[sfb]; - const int cb_min = sce->zeroes[sfb] ? 0 : 1; - const int cb_max = sce->zeroes[sfb] ? 0 : RESERVED_BT; - const int start_coef = sce->ics.swb_offset[sfb]; - const int num_coeffs = sce->ics.swb_offset[sfb + 1] - start_coef; - const FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[sfb]; - - if (start_coef + num_coeffs > MAX_PREDICTORS || - (s->cur_channel && sce->band_type[sfb] >= INTENSITY_BT2) || - sce->band_type[sfb] == NOISE_BT) - continue; - - /* Normal coefficients */ - s->aacdsp.abs_pow34(O34, &sce->coeffs[start_coef], num_coeffs); - dist1 = ff_quantize_and_encode_band_cost(s, NULL, &sce->coeffs[start_coef], NULL, - O34, num_coeffs, sce->sf_idx[sfb], - cb_n, s->lambda / band->threshold, INFINITY, &cost1, NULL); - cost_coeffs += cost1; - - /* Encoded coefficients - needed for #bits, band type and quant. error */ - for (i = 0; i < num_coeffs; i++) - SENT[i] = sce->coeffs[start_coef + i] - sce->prcoeffs[start_coef + i]; - s->aacdsp.abs_pow34(S34, SENT, num_coeffs); - if (cb_n < RESERVED_BT) - cb_p = av_clip(find_min_book(find_max_val(1, num_coeffs, S34), sce->sf_idx[sfb]), cb_min, cb_max); - else - cb_p = cb_n; - ff_quantize_and_encode_band_cost(s, NULL, SENT, QERR, S34, num_coeffs, - sce->sf_idx[sfb], cb_p, s->lambda / band->threshold, INFINITY, - &cost2, NULL); - - /* Reconstructed coefficients - needed for distortion measurements */ - for (i = 0; i < num_coeffs; i++) - sce->prcoeffs[start_coef + i] += QERR[i] != 0.0f ? (sce->prcoeffs[start_coef + i] - QERR[i]) : 0.0f; - s->aacdsp.abs_pow34(P34, &sce->prcoeffs[start_coef], num_coeffs); - if (cb_n < RESERVED_BT) - cb_p = av_clip(find_min_book(find_max_val(1, num_coeffs, P34), sce->sf_idx[sfb]), cb_min, cb_max); - else - cb_p = cb_n; - dist2 = ff_quantize_and_encode_band_cost(s, NULL, &sce->prcoeffs[start_coef], NULL, - P34, num_coeffs, sce->sf_idx[sfb], - cb_p, s->lambda / band->threshold, INFINITY, NULL, NULL); - for (i = 0; i < num_coeffs; i++) - dist_spec_err += (O34[i] - P34[i])*(O34[i] - P34[i]); - dist_spec_err *= s->lambda / band->threshold; - dist2 += dist_spec_err; - - if (dist2 <= dist1 && cb_p <= cb_n) { - cost_pred += cost2; - sce->ics.prediction_used[sfb] = 1; - sce->band_alt[sfb] = cb_n; - sce->band_type[sfb] = cb_p; - count++; - } else { - cost_pred += cost1; - sce->band_alt[sfb] = cb_p; - } - } - - if (count && cost_coeffs < cost_pred) { - count = 0; - for (sfb = PRED_SFB_START; sfb < pmax; sfb++) - RESTORE_PRED(sce, sfb); - memset(&sce->ics.prediction_used, 0, sizeof(sce->ics.prediction_used)); - } - - sce->ics.predictor_present = !!count; -} - -/** - * Encoder predictors data. - */ -void ff_aac_encode_main_pred(AACEncContext *s, SingleChannelElement *sce) -{ - int sfb; - IndividualChannelStream *ics = &sce->ics; - const int pmax = FFMIN(ics->max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); - - if (s->profile != AV_PROFILE_AAC_MAIN || - !ics->predictor_present) - return; - - put_bits(&s->pb, 1, !!ics->predictor_reset_group); - if (ics->predictor_reset_group) - put_bits(&s->pb, 5, ics->predictor_reset_group); - for (sfb = 0; sfb < pmax; sfb++) - put_bits(&s->pb, 1, ics->prediction_used[sfb]); -} diff --git a/libavcodec/aacenc_pred.h b/libavcodec/aacenc_pred.h deleted file mode 100644 index aa305f45a..000000000 --- a/libavcodec/aacenc_pred.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * AAC encoder main-type prediction - * Copyright (C) 2015 Rostislav Pehlivanov - * - * 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 - * AAC encoder main-type prediction - * @author Rostislav Pehlivanov ( atomnuker gmail com ) - */ - -#ifndef AVCODEC_AACENC_PRED_H -#define AVCODEC_AACENC_PRED_H - -#include "aacenc.h" - -/* Every predictor group needs to get reset at least once in this many frames */ -#define PRED_RESET_FRAME_MIN 240 - -/* Any frame with less than this amount of frames since last reset is ok */ -#define PRED_RESET_MIN 64 - -/* Raise to filter any low frequency artifacts due to prediction */ -#define PRED_SFB_START 10 - -void ff_aac_apply_main_pred(AACEncContext *s, SingleChannelElement *sce); -void ff_aac_adjust_common_pred(AACEncContext *s, ChannelElement *cpe); -void ff_aac_search_for_pred(AACEncContext *s, SingleChannelElement *sce); -void ff_aac_encode_main_pred(AACEncContext *s, SingleChannelElement *sce); - -#endif /* AVCODEC_AACENC_PRED_H */ diff --git a/libavcodec/aacenc_tns.c b/libavcodec/aacenc_tns.c index f9bc033b2..1e71c658c 100644 --- a/libavcodec/aacenc_tns.c +++ b/libavcodec/aacenc_tns.c @@ -117,7 +117,7 @@ void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce) continue; // tns_decode_coef - compute_lpc_coefs(tns->coef[w][filt], order, lpc, 0, 0, 0); + compute_lpc_coefs(tns->coef[w][filt], 0, order, lpc, 0, 0, 0, NULL); start = ics->swb_offset[FFMIN(bottom, mmm)]; end = ics->swb_offset[FFMIN( top, mmm)]; @@ -168,7 +168,7 @@ void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce) const int c_bits = is8 ? TNS_Q_BITS_IS8 == 4 : TNS_Q_BITS == 4; const int sfb_start = av_clip(tns_min_sfb[is8][s->samplerate_index], 0, mmm); const int sfb_end = av_clip(sce->ics.num_swb, 0, mmm); - const int order = is8 ? 7 : s->profile == AV_PROFILE_AAC_LOW ? 12 : TNS_MAX_ORDER; + const int order = is8 ? 7 : 12; const int slant = sce->ics.window_sequence[0] == LONG_STOP_SEQUENCE ? 1 : sce->ics.window_sequence[0] == LONG_START_SEQUENCE ? 0 : 2; const int sfb_len = sfb_end - sfb_start; diff --git a/libavcodec/aacencdsp.h b/libavcodec/aacencdsp.h index 67836d8cf..77aa13369 100644 --- a/libavcodec/aacencdsp.h +++ b/libavcodec/aacencdsp.h @@ -34,6 +34,7 @@ typedef struct AACEncDSPContext { void ff_aacenc_dsp_init_riscv(AACEncDSPContext *s); void ff_aacenc_dsp_init_x86(AACEncDSPContext *s); +void ff_aacenc_dsp_init_aarch64(AACEncDSPContext *s); static inline void abs_pow34_v(float *out, const float *in, const int size) { @@ -49,7 +50,7 @@ static inline void quantize_bands(int *out, const float *in, const float *scaled { for (int i = 0; i < size; i++) { float qc = scaled[i] * Q34; - int tmp = (int)FFMIN(qc + rounding, (float)maxval); + int tmp = (int)FFMIN((float)(qc + rounding), (float)maxval); if (is_signed && in[i] < 0.0f) { tmp = -tmp; } @@ -64,8 +65,10 @@ static inline void ff_aacenc_dsp_init(AACEncDSPContext *s) #if ARCH_RISCV ff_aacenc_dsp_init_riscv(s); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_aacenc_dsp_init_x86(s); +#elif ARCH_AARCH64 + ff_aacenc_dsp_init_aarch64(s); #endif } diff --git a/libavcodec/aacenctab.c b/libavcodec/aacenctab.c index 874365a59..fd40e076e 100644 --- a/libavcodec/aacenctab.c +++ b/libavcodec/aacenctab.c @@ -25,9 +25,7 @@ static const uint8_t swb_size_128_96[] = { 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 }; -static const uint8_t swb_size_128_64[] = { - 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 -}; +#define swb_size_128_64 swb_size_128_96 static const uint8_t swb_size_128_48[] = { 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16 @@ -103,6 +101,3 @@ const uint8_t *const ff_aac_swb_size_1024[] = { swb_size_1024_16, swb_size_1024_16, swb_size_1024_8, swb_size_1024_8 }; - -const int ff_aac_swb_size_128_len = FF_ARRAY_ELEMS(ff_aac_swb_size_128); -const int ff_aac_swb_size_1024_len = FF_ARRAY_ELEMS(ff_aac_swb_size_1024); diff --git a/libavcodec/aacenctab.h b/libavcodec/aacenctab.h index f2d6f597b..fee9c245d 100644 --- a/libavcodec/aacenctab.h +++ b/libavcodec/aacenctab.h @@ -41,9 +41,7 @@ #define AAC_MAX_CHANNELS 16 extern const uint8_t *const ff_aac_swb_size_1024[]; -extern const int ff_aac_swb_size_1024_len; extern const uint8_t *const ff_aac_swb_size_128[]; -extern const int ff_aac_swb_size_128_len; /* Supported layouts without using a PCE */ static const AVChannelLayout aac_normal_chan_layouts[7] = { @@ -125,9 +123,7 @@ static const unsigned char aac_maxval_cb[] = { }; static const int aacenc_profiles[] = { - AV_PROFILE_AAC_MAIN, AV_PROFILE_AAC_LOW, - AV_PROFILE_AAC_LTP, AV_PROFILE_MPEG2_AAC_LOW, }; diff --git a/libavcodec/aacps_tablegen_template.c b/libavcodec/aacps_tablegen_template.c index e05887b9b..df8f91bbc 100644 --- a/libavcodec/aacps_tablegen_template.c +++ b/libavcodec/aacps_tablegen_template.c @@ -23,6 +23,7 @@ #include #define BUILD_TABLES #include "config.h" +#undef ASSERT_LEVEL #undef CONFIG_HARDCODED_TABLES #define CONFIG_HARDCODED_TABLES 0 #include "aac_defines.h" diff --git a/libavcodec/aacpsdsp.h b/libavcodec/aacpsdsp.h index 149121225..daeb0a698 100644 --- a/libavcodec/aacpsdsp.h +++ b/libavcodec/aacpsdsp.h @@ -30,15 +30,15 @@ #define PS_MAX_AP_DELAY 5 typedef struct PSDSPContext { - void (*add_squares)(INTFLOAT *dst, const INTFLOAT (*src)[2], int n); - void (*mul_pair_single)(INTFLOAT (*dst)[2], INTFLOAT (*src0)[2], INTFLOAT *src1, + void (*add_squares)(INTFLOAT *restrict dst, const INTFLOAT (*src)[2], int n); + void (*mul_pair_single)(INTFLOAT (*restrict dst)[2], INTFLOAT (*src0)[2], INTFLOAT *src1, int n); - void (*hybrid_analysis)(INTFLOAT (*out)[2], INTFLOAT (*in)[2], + void (*hybrid_analysis)(INTFLOAT (*restrict out)[2], INTFLOAT (*in)[2], const INTFLOAT (*filter)[8][2], ptrdiff_t stride, int n); - void (*hybrid_analysis_ileave)(INTFLOAT (*out)[32][2], INTFLOAT L[2][38][64], + void (*hybrid_analysis_ileave)(INTFLOAT (*restrict out)[32][2], INTFLOAT L[2][38][64], int i, int len); - void (*hybrid_synthesis_deint)(INTFLOAT out[2][38][64], INTFLOAT (*in)[32][2], + void (*hybrid_synthesis_deint)(INTFLOAT out[2][38][64], INTFLOAT (*restrict in)[32][2], int i, int len); void (*decorrelate)(INTFLOAT (*out)[2], INTFLOAT (*delay)[2], INTFLOAT (*ap_delay)[PS_QMF_TIME_SLOTS+PS_MAX_AP_DELAY][2], diff --git a/libavcodec/aacpsdsp_template.c b/libavcodec/aacpsdsp_template.c index c28ba2c9a..341bf7702 100644 --- a/libavcodec/aacpsdsp_template.c +++ b/libavcodec/aacpsdsp_template.c @@ -228,7 +228,7 @@ av_cold void AAC_RENAME(ff_psdsp_init)(PSDSPContext *s) ff_psdsp_init_aarch64(s); #elif ARCH_RISCV ff_psdsp_init_riscv(s); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_psdsp_init_x86(s); #endif #endif /* !USE_FIXED */ diff --git a/libavcodec/aacpsy.c b/libavcodec/aacpsy.c index 019be09fa..299a0a9f0 100644 --- a/libavcodec/aacpsy.c +++ b/libavcodec/aacpsy.c @@ -97,7 +97,7 @@ enum { #define AAC_BLOCK_SIZE_LONG 1024 ///< long block size #define AAC_BLOCK_SIZE_SHORT 128 ///< short block size #define AAC_NUM_BLOCKS_SHORT 8 ///< number of blocks in a short sequence -#define PSY_LAME_NUM_SUBBLOCKS 3 ///< Number of sub-blocks in each short block +#define PSY_LAME_NUM_SUBBLOCKS 2 ///< Number of sub-blocks in each short block /** * @} @@ -133,6 +133,7 @@ typedef struct AacPsyChannel{ float attack_threshold; ///< attack threshold for this channel float prev_energy_subshort[AAC_NUM_BLOCKS_SHORT * PSY_LAME_NUM_SUBBLOCKS]; int prev_attack; ///< attack value for the last short block in the previous sequence + int next_attack0_zero; ///< whether attack[0] of the next frame is zero }AacPsyChannel; /** @@ -168,7 +169,7 @@ typedef struct AacPsyContext{ * LAME psy model preset struct */ typedef struct PsyLamePreset { - int quality; ///< Quality to map the rest of the vaules to. + int quality; ///< Quality to map the rest of the values to. /* This is overloaded to be both kbps per channel in ABR mode, and * requested quality in constant quality mode. */ @@ -181,19 +182,19 @@ typedef struct PsyLamePreset { static const PsyLamePreset psy_abr_map[] = { /* TODO: Tuning. These were taken from LAME. */ /* kbps/ch st_lrm */ - { 8, 6.60}, - { 16, 6.60}, - { 24, 6.60}, - { 32, 6.60}, - { 40, 6.60}, - { 48, 6.60}, - { 56, 6.60}, - { 64, 6.40}, - { 80, 6.00}, - { 96, 5.60}, - {112, 5.20}, - {128, 5.20}, - {160, 5.20} + { 8, 7.60}, + { 16, 7.60}, + { 24, 7.60}, + { 32, 7.60}, + { 40, 7.60}, + { 48, 7.60}, + { 56, 7.60}, + { 64, 7.40}, + { 80, 7.00}, + { 96, 6.60}, + {112, 6.20}, + {128, 6.20}, + {160, 6.20} }; /** @@ -402,7 +403,7 @@ static const uint8_t window_grouping[9] = { * Tell encoder which window types to use. * @see 3GPP TS26.403 5.4.1 "Blockswitching" */ -static av_unused FFPsyWindowInfo psy_3gpp_window(FFPsyContext *ctx, +av_unused static FFPsyWindowInfo psy_3gpp_window(FFPsyContext *ctx, const int16_t *audio, const int16_t *la, int channel, int prev_type) @@ -593,7 +594,6 @@ static float calc_reduced_thr_3gpp(AacPsyBand *band, float min_snr, return thr; } -#ifndef calc_thr_3gpp static void calc_thr_3gpp(const FFPsyWindowInfo *wi, const int num_bands, AacPsyChannel *pch, const uint8_t *band_sizes, const float *coefs, const int cutoff) { @@ -622,9 +622,7 @@ static void calc_thr_3gpp(const FFPsyWindowInfo *wi, const int num_bands, AacPsy } } } -#endif /* calc_thr_3gpp */ -#ifndef psy_hp_filter static void psy_hp_filter(const float *firbuf, float *hpfsmpl, const float *psy_fir_coeffs) { int i, j; @@ -641,7 +639,6 @@ static void psy_hp_filter(const float *firbuf, float *hpfsmpl, const float *psy_ hpfsmpl[i] = (sum1 + sum2) * 32768.0f; } } -#endif /* psy_hp_filter */ /** * Calculate band thresholds as suggested in 3GPP TS26.403 @@ -904,8 +901,8 @@ static FFPsyWindowInfo psy_lame_window(FFPsyContext *ctx, const float *audio, /* Calculate the energies of each sub-shortblock */ for (i = 0; i < PSY_LAME_NUM_SUBBLOCKS; i++) { energy_subshort[i] = pch->prev_energy_subshort[i + ((AAC_NUM_BLOCKS_SHORT - 1) * PSY_LAME_NUM_SUBBLOCKS)]; - assert(pch->prev_energy_subshort[i + ((AAC_NUM_BLOCKS_SHORT - 2) * PSY_LAME_NUM_SUBBLOCKS + 1)] > 0); - attack_intensity[i] = energy_subshort[i] / pch->prev_energy_subshort[i + ((AAC_NUM_BLOCKS_SHORT - 2) * PSY_LAME_NUM_SUBBLOCKS + 1)]; + assert(pch->prev_energy_subshort[i + ((AAC_NUM_BLOCKS_SHORT - 1) * PSY_LAME_NUM_SUBBLOCKS - 2)] > 0); + attack_intensity[i] = energy_subshort[i] / pch->prev_energy_subshort[i + ((AAC_NUM_BLOCKS_SHORT - 1) * PSY_LAME_NUM_SUBBLOCKS - 2)]; energy_short[0] += energy_subshort[i]; } @@ -916,19 +913,15 @@ static FFPsyWindowInfo psy_lame_window(FFPsyContext *ctx, const float *audio, p = FFMAX(p, fabsf(*pf)); pch->prev_energy_subshort[i] = energy_subshort[i + PSY_LAME_NUM_SUBBLOCKS] = p; energy_short[1 + i / PSY_LAME_NUM_SUBBLOCKS] += p; - /* NOTE: The indexes below are [i + 3 - 2] in the LAME source. - * Obviously the 3 and 2 have some significance, or this would be just [i + 1] - * (which is what we use here). What the 3 stands for is ambiguous, as it is both - * number of short blocks, and the number of sub-short blocks. - * It seems that LAME is comparing each sub-block to sub-block + 1 in the - * previous block. - */ - if (p > energy_subshort[i + 1]) - p = p / energy_subshort[i + 1]; - else if (energy_subshort[i + 1] > p * 10.0f) - p = energy_subshort[i + 1] / (p * 10.0f); + + /* NOTE: The indexes below are [i + 3 - 2] in the LAME source. Compare each sub-block to sub-block - 2 */ + if (p > energy_subshort[i + PSY_LAME_NUM_SUBBLOCKS - 2]) + p = p / energy_subshort[i + PSY_LAME_NUM_SUBBLOCKS - 2]; + else if (energy_subshort[i + PSY_LAME_NUM_SUBBLOCKS - 2] > p * 10.0f) + p = energy_subshort[i + PSY_LAME_NUM_SUBBLOCKS - 2] / (p * 10.0f); else p = 0.0; + attack_intensity[i + PSY_LAME_NUM_SUBBLOCKS] = p; } @@ -947,7 +940,7 @@ static FFPsyWindowInfo psy_lame_window(FFPsyContext *ctx, const float *audio, const float v = energy_short[i]; const float m = FFMAX(u, v); if (m < 40000) { /* (2) */ - if (u < 1.7f * v && v < 1.7f * u) { /* (1) */ + if (u < 2.3f * v && v < 2.3f * u) { /* (1) */ if (i == 1 && attacks[0] < attacks[i]) attacks[0] = 0; attacks[i] = 0; @@ -956,12 +949,18 @@ static FFPsyWindowInfo psy_lame_window(FFPsyContext *ctx, const float *audio, att_sum += attacks[i]; } + if (pch->next_attack0_zero) + attacks[0] = 0; + pch->next_attack0_zero = !attacks[AAC_NUM_BLOCKS_SHORT]; + if (attacks[0] <= pch->prev_attack) attacks[0] = 0; att_sum += attacks[0]; - /* 3 below indicates the previous attack happened in the last sub-block of the previous sequence */ - if (pch->prev_attack == 3 || att_sum) { + + /* If the previous attack happened in the last sub-block of the previous sequence, + * or if there's a new attack, use short window */ + if (pch->prev_attack == PSY_LAME_NUM_SUBBLOCKS || att_sum) { uselongblock = 0; for (i = 1; i < AAC_NUM_BLOCKS_SHORT + 1; i++) @@ -1011,7 +1010,7 @@ static FFPsyWindowInfo psy_lame_window(FFPsyContext *ctx, const float *audio, } pch->next_grouping = window_grouping[grouping]; - pch->prev_attack = attacks[8]; + pch->prev_attack = attacks[AAC_NUM_BLOCKS_SHORT - 1]; return wi; } diff --git a/libavcodec/aacsbr_template.c b/libavcodec/aacsbr_template.c index a126bd6f0..31d2d844c 100644 --- a/libavcodec/aacsbr_template.c +++ b/libavcodec/aacsbr_template.c @@ -59,7 +59,7 @@ static void sbr_turnoff(SpectralBandReplication *sbr) { sbr->start = 0; sbr->usac = 0; sbr->ready_for_dequant = 0; - // Init defults used in pure upsampling mode + // Init defaults used in pure upsampling mode sbr->kx[1] = 32; //Typo in spec, kx' inits to 32 sbr->m[1] = 0; // Reset values for first SBR header @@ -1287,6 +1287,8 @@ int ff_aac_sbr_decode_usac_data(AACDecContext *ac, ChannelElement *che, if ((sbr->data[0].bs_add_harmonic_flag = get_bits1(gb))) get_bits1_vector(gb, sbr->data[0].bs_add_harmonic, sbr->n[1]); } else if (get_bits1(gb)) { /* bs_coupling == 1 */ + sbr->bs_coupling = 1; + /* if (harmonicSBR) ... */ if (read_sbr_grid(ac, sbr, gb, &sbr->data[0])) @@ -1317,7 +1319,10 @@ int ff_aac_sbr_decode_usac_data(AACDecContext *ac, ChannelElement *che, if ((sbr->data[1].bs_add_harmonic_flag = get_bits1(gb))) get_bits1_vector(gb, sbr->data[1].bs_add_harmonic, sbr->n[1]); } else { /* bs_coupling == 0 */ + sbr->bs_coupling = 0; + /* if (harmonicSBR) ... */ + if (read_sbr_grid(ac, sbr, gb, &sbr->data[0])) return -1; if (read_sbr_grid(ac, sbr, gb, &sbr->data[1])) diff --git a/libavcodec/aacsbrdata.h b/libavcodec/aacsbrdata.h index 9c2509824..996e55705 100644 --- a/libavcodec/aacsbrdata.h +++ b/libavcodec/aacsbrdata.h @@ -41,7 +41,7 @@ static const int8_t sbr_offset[6][16] = { {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24}, // 64000 Hz < fs_sbr }; -///< window coefficients for analysis/synthesis QMF banks +/// window coefficients for analysis/synthesis QMF banks static const DECLARE_ALIGNED(32, INTFLOAT, sbr_qmf_window_ds)[320] = { Q31( 0.0000000000f), Q31(-0.0005617692f), Q31(-0.0004875227f), Q31(-0.0005040714f), diff --git a/libavcodec/aactab.c b/libavcodec/aactab.c index 8d4587d24..128bacfdf 100644 --- a/libavcodec/aactab.c +++ b/libavcodec/aactab.c @@ -170,10 +170,6 @@ const uint8_t ff_aac_num_swb_128[] = { 12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15 }; -const uint8_t ff_aac_num_swb_120[] = { - 12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15 -}; - const uint8_t ff_aac_num_swb_96[] = { 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14 }; @@ -1838,13 +1834,7 @@ static const uint16_t swb_offset_768_48[] = 544, 576, 608, 640, 672, 704, 736, 768 }; -static const uint16_t swb_offset_768_32[] = -{ - 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, - 56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 160, 176, - 196, 216, 240, 264, 292, 320, 352, 384, 416, 448, 480, 512, - 544, 576, 608, 640, 672, 704, 736, 768 -}; +#define swb_offset_768_32 swb_offset_768_48 static const uint16_t swb_offset_768_24[] = { @@ -3884,31 +3874,6 @@ const DECLARE_ALIGNED(32, int, ff_aac_eld_window_480_fixed)[1800] = { 0xffedebe1, 0xffee287d, 0xffee654e, 0xffeea23f, }; -/* As specified by ISO/IEC 23003 */ -#define USAC_EMPH_COEFF 0.68 - -DECLARE_ALIGNED(16, const float, ff_aac_deemph_weights)[16] = { - USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF*USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF*USAC_EMPH_COEFF*USAC_EMPH_COEFF, - - 0, - USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF*USAC_EMPH_COEFF, - - 0, - 0, - USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF, - - 0, - 0, - 0, - USAC_EMPH_COEFF, -}; - const int ff_aac_usac_samplerate[32] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, -1, -1, 57600, @@ -3936,12 +3901,3 @@ const float ff_aac_usac_mdst_filt_cur[4 /* Window */][4 /* Shape */][7] = { 0.207421, 0.001416, 0.635010, 0.000000, -0.635010, -0.001416, -0.207421 }, { 0.207421, -0.001416, 0.635010, 0.000000, -0.635010, 0.001416, -0.207421 } } }; - -/* Window type (everything/longstop+stopstart), sine or kbd */ -const float ff_aac_usac_mdst_filt_prev[2 /* Window */][2 /* sine/kbd */][7] = -{ - { { 0.000000, 0.106103, 0.250000, 0.318310, 0.250000, 0.106103, 0.000000 }, - { 0.059509, 0.123714, 0.186579, 0.213077, 0.186579, 0.123714, 0.059509 } }, - { { 0.038498, 0.039212, 0.039645, 0.039790, 0.039645, 0.039212, 0.038498 }, - { 0.026142, 0.026413, 0.026577, 0.026631, 0.026577, 0.026413, 0.026142 } } -}; diff --git a/libavcodec/aactab.h b/libavcodec/aactab.h index 84879aa8f..e7dbbf1ec 100644 --- a/libavcodec/aactab.h +++ b/libavcodec/aactab.h @@ -64,8 +64,6 @@ DECLARE_ALIGNED(32, extern const float, ff_aac_eld_window_480)[1800]; DECLARE_ALIGNED(32, extern const int, ff_aac_eld_window_480_fixed)[1800]; // @} -extern const float ff_aac_deemph_weights[16]; - /* Initializes data shared between float decoder and encoder. */ void ff_aac_float_common_init(void); @@ -78,7 +76,7 @@ extern const uint8_t ff_aac_num_swb_768 []; extern const uint8_t ff_aac_num_swb_512 []; extern const uint8_t ff_aac_num_swb_480 []; extern const uint8_t ff_aac_num_swb_128 []; -extern const uint8_t ff_aac_num_swb_120 []; +#define ff_aac_num_swb_120 ff_aac_num_swb_128 extern const uint8_t ff_aac_num_swb_96 []; // @} @@ -125,7 +123,5 @@ extern const int ff_aac_usac_samplerate[32]; /* Window type (only long+eight, start/stop/stopstart), sine+sine, kbd+kbd, sine+kbd, kbd+sine */ extern const float ff_aac_usac_mdst_filt_cur[4 /* Window */][4 /* Shape */][7]; -/* Window type (everything/longstop+stopstart), sine or kbd */ -extern const float ff_aac_usac_mdst_filt_prev[2 /* Window */][2 /* sine/kbd */][7]; #endif /* AVCODEC_AACTAB_H */ diff --git a/libavcodec/aarch64/Makefile b/libavcodec/aarch64/Makefile index 9affb9278..41ab0257b 100644 --- a/libavcodec/aarch64/Makefile +++ b/libavcodec/aarch64/Makefile @@ -4,21 +4,24 @@ OBJS-$(CONFIG_FDCTDSP) += aarch64/fdctdsp_init_aarch64.o OBJS-$(CONFIG_FMTCONVERT) += aarch64/fmtconvert_init.o OBJS-$(CONFIG_H264CHROMA) += aarch64/h264chroma_init_aarch64.o OBJS-$(CONFIG_H264DSP) += aarch64/h264dsp_init_aarch64.o +OBJS-$(CONFIG_HUFFYUVDSP) += aarch64/huffyuvdsp_init_aarch64.o OBJS-$(CONFIG_H264PRED) += aarch64/h264pred_init.o OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_init_aarch64.o OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_init_aarch64.o OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o OBJS-$(CONFIG_ME_CMP) += aarch64/me_cmp_init_aarch64.o OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_init.o -OBJS-$(CONFIG_MPEGVIDEOENC) += aarch64/mpegvideoencdsp_init.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += aarch64/mpegvideoencdsp_init.o OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o OBJS-$(CONFIG_PIXBLOCKDSP) += aarch64/pixblockdsp_init_aarch64.o +OBJS-$(CONFIG_PNG_DECODER) += aarch64/pngdsp_init.o OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp_init.o OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_init_aarch64.o # decoders/encoders OBJS-$(CONFIG_AAC_DECODER) += aarch64/aacpsdsp_init_aarch64.o \ aarch64/sbrdsp_init_aarch64.o +OBJS-$(CONFIG_AAC_ENCODER) += aarch64/aacencdsp_init.o OBJS-$(CONFIG_DCA_DECODER) += aarch64/synth_filter_init.o OBJS-$(CONFIG_OPUS_DECODER) += aarch64/opusdsp_init.o OBJS-$(CONFIG_RV40_DECODER) += aarch64/rv40dsp_init_aarch64.o @@ -38,6 +41,7 @@ ARMV8-OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp.o # subsystems NEON-OBJS-$(CONFIG_AAC_DECODER) += aarch64/sbrdsp_neon.o +NEON-OBJS-$(CONFIG_AAC_ENCODER) += aarch64/aacencdsp_neon.o NEON-OBJS-$(CONFIG_AC3DSP) += aarch64/ac3dsp_neon.o NEON-OBJS-$(CONFIG_FDCTDSP) += aarch64/fdctdsp_neon.o NEON-OBJS-$(CONFIG_FMTCONVERT) += aarch64/fmtconvert_neon.o @@ -48,12 +52,14 @@ NEON-OBJS-$(CONFIG_H264PRED) += aarch64/h264pred_neon.o NEON-OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_neon.o \ aarch64/hpeldsp_neon.o NEON-OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_neon.o +NEON-OBJS-$(CONFIG_HUFFYUVDSP) += aarch64/huffyuvdsp_neon.o NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_neon.o \ aarch64/simple_idct_neon.o NEON-OBJS-$(CONFIG_ME_CMP) += aarch64/me_cmp_neon.o NEON-OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_neon.o -NEON-OBJS-$(CONFIG_MPEGVIDEOENC) += aarch64/mpegvideoencdsp_neon.o +NEON-OBJS-$(CONFIG_MPEGVIDEOENCDSP) += aarch64/mpegvideoencdsp_neon.o NEON-OBJS-$(CONFIG_PIXBLOCKDSP) += aarch64/pixblockdsp_neon.o +NEON-OBJS-$(CONFIG_PNG_DECODER) += aarch64/pngdsp_neon.o NEON-OBJS-$(CONFIG_VC1DSP) += aarch64/vc1dsp_neon.o NEON-OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_neon.o @@ -69,6 +75,7 @@ NEON-OBJS-$(CONFIG_VP9_DECODER) += aarch64/vp9itxfm_16bpp_neon.o \ aarch64/vp9mc_16bpp_neon.o \ aarch64/vp9mc_neon.o NEON-OBJS-$(CONFIG_HEVC_DECODER) += aarch64/hevcdsp_deblock_neon.o \ + aarch64/hevcdsp_dequant_neon.o \ aarch64/hevcdsp_idct_neon.o \ aarch64/hevcdsp_init_aarch64.o \ aarch64/h26x/epel_neon.o \ diff --git a/libavcodec/arm/vp6dsp_init_arm.c b/libavcodec/aarch64/aacencdsp_init.c similarity index 64% rename from libavcodec/arm/vp6dsp_init_arm.c rename to libavcodec/aarch64/aacencdsp_init.c index a59d61278..23498e789 100644 --- a/libavcodec/arm/vp6dsp_init_arm.c +++ b/libavcodec/aarch64/aacencdsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Mans Rullgard + * Copyright (c) 2025 Krzysztof Aleksander Pyrkosz * * This file is part of FFmpeg. * @@ -18,22 +18,21 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include "config.h" -#include "libavutil/attributes.h" #include "libavutil/arm/cpu.h" +#include "libavutil/attributes.h" +#include "libavcodec/aacencdsp.h" -#include "libavcodec/vp56dsp.h" +void ff_abs_pow34_neon(float *out, const float *in, const int size); +void ff_aac_quant_bands_neon(int *, const float *, const float *, int, int, + int, const float, const float); -void ff_vp6_edge_filter_hor_neon(uint8_t *yuv, ptrdiff_t stride, int t); -void ff_vp6_edge_filter_ver_neon(uint8_t *yuv, ptrdiff_t stride, int t); - -av_cold void ff_vp6dsp_init_arm(VP56DSPContext *s) +av_cold void ff_aacenc_dsp_init_aarch64(AACEncDSPContext *s) { int cpu_flags = av_get_cpu_flags(); + if (!have_neon(cpu_flags)) return; - if (have_neon(cpu_flags)) { - s->edge_filter_hor = ff_vp6_edge_filter_hor_neon; - s->edge_filter_ver = ff_vp6_edge_filter_ver_neon; - } + s->abs_pow34 = ff_abs_pow34_neon; + s->quant_bands = ff_aac_quant_bands_neon; } diff --git a/libavcodec/aarch64/aacencdsp_neon.S b/libavcodec/aarch64/aacencdsp_neon.S new file mode 100644 index 000000000..14f7f667c --- /dev/null +++ b/libavcodec/aarch64/aacencdsp_neon.S @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 Krzysztof Aleksander Pyrkosz + * + * 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/aarch64/asm.S" + +function ff_abs_pow34_neon, export=1 +1: + ld1 {v0.4s}, [x1], #16 + subs w2, w2, #4 + fabs v0.4s, v0.4s + fsqrt v2.4s, v0.4s + fmul v0.4s, v2.4s, v0.4s + fsqrt v0.4s, v0.4s + st1 {v0.4s}, [x0], #16 + b.ne 1b + ret +endfunc + +function ff_aac_quant_bands_neon, export=1 + scvtf s2, w5 + dup v1.4s, v1.s[0] + dup v2.4s, v2.s[0] + cbz w4, 0f + movi v5.4s, 0x80, lsl #24 +.irp signed,1,0 +\signed: + ld1 {v3.4s}, [x2], #16 + subs w3, w3, #4 + fmul v3.4s, v3.4s, v0.s[0] +.if \signed + ld1 {v4.4s}, [x1], #16 +.endif + fadd v3.4s, v3.4s, v1.4s +.if \signed + and v4.16b, v4.16b, v5.16b +.endif + fmin v3.4s, v3.4s, v2.4s +.if \signed + eor v3.16b, v4.16b, v3.16b +.endif + fcvtzs v3.4s, v3.4s + st1 {v3.4s}, [x0], #16 + b.ne \signed\()b + ret +.endr +endfunc diff --git a/libavcodec/aarch64/ac3dsp_neon.S b/libavcodec/aarch64/ac3dsp_neon.S index 7e97cc39f..c28e2082a 100644 --- a/libavcodec/aarch64/ac3dsp_neon.S +++ b/libavcodec/aarch64/ac3dsp_neon.S @@ -69,21 +69,20 @@ function ff_ac3_sum_square_butterfly_int32_neon, export=1 movi v0.2d, #0 movi v1.2d, #0 movi v2.2d, #0 - movi v3.2d, #0 1: ld1 {v4.2s}, [x1], #8 ld1 {v5.2s}, [x2], #8 - add v6.2s, v4.2s, v5.2s - sub v7.2s, v4.2s, v5.2s - smlal v0.2d, v4.2s, v4.2s - smlal v1.2d, v5.2s, v5.2s - smlal v2.2d, v6.2s, v6.2s - smlal v3.2d, v7.2s, v7.2s subs w3, w3, #2 + smlal v0.2d, v4.2s, v4.2s // sum of a^2 + smlal v1.2d, v5.2s, v5.2s // sum of b^2 + sqdmlal v2.2d, v4.2s, v5.2s // sum of 2ab b.gt 1b addp d0, v0.2d addp d1, v1.2d addp d2, v2.2d - addp d3, v3.2d + sub d3, d0, d2 // a^2 + b^2 - 2ab + add d2, d0, d2 + add d3, d3, d1 // a^2 + b^2 + 2ab + add d2, d2, d1 st1 {v0.1d-v3.1d}, [x0] ret endfunc diff --git a/libavcodec/aarch64/h264dsp_init_aarch64.c b/libavcodec/aarch64/h264dsp_init_aarch64.c index 6bf3ecb8a..c68457432 100644 --- a/libavcodec/aarch64/h264dsp_init_aarch64.c +++ b/libavcodec/aarch64/h264dsp_init_aarch64.c @@ -112,55 +112,55 @@ av_cold void ff_h264dsp_init_aarch64(H264DSPContext *c, const int bit_depth, int cpu_flags = av_get_cpu_flags(); if (have_neon(cpu_flags) && bit_depth == 8) { - c->h264_v_loop_filter_luma = ff_h264_v_loop_filter_luma_neon; - c->h264_h_loop_filter_luma = ff_h264_h_loop_filter_luma_neon; - c->h264_v_loop_filter_luma_intra= ff_h264_v_loop_filter_luma_intra_neon; - c->h264_h_loop_filter_luma_intra= ff_h264_h_loop_filter_luma_intra_neon; + c->v_loop_filter_luma = ff_h264_v_loop_filter_luma_neon; + c->h_loop_filter_luma = ff_h264_h_loop_filter_luma_neon; + c->v_loop_filter_luma_intra= ff_h264_v_loop_filter_luma_intra_neon; + c->h_loop_filter_luma_intra= ff_h264_h_loop_filter_luma_intra_neon; - c->h264_v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon; - c->h264_v_loop_filter_chroma_intra = ff_h264_v_loop_filter_chroma_intra_neon; + c->v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon; + c->v_loop_filter_chroma_intra = ff_h264_v_loop_filter_chroma_intra_neon; if (chroma_format_idc <= 1) { - c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon; - c->h264_h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma_intra_neon; - c->h264_h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_mbaff_intra_neon; + c->h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon; + c->h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma_intra_neon; + c->h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_mbaff_intra_neon; } else { - c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma422_neon; - c->h264_h_loop_filter_chroma_mbaff = ff_h264_h_loop_filter_chroma_neon; - c->h264_h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma422_intra_neon; - c->h264_h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_intra_neon; + c->h_loop_filter_chroma = ff_h264_h_loop_filter_chroma422_neon; + c->h_loop_filter_chroma_mbaff = ff_h264_h_loop_filter_chroma_neon; + c->h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma422_intra_neon; + c->h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_intra_neon; } - c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels_16_neon; - c->weight_h264_pixels_tab[1] = ff_weight_h264_pixels_8_neon; - c->weight_h264_pixels_tab[2] = ff_weight_h264_pixels_4_neon; + c->weight_pixels_tab[0] = ff_weight_h264_pixels_16_neon; + c->weight_pixels_tab[1] = ff_weight_h264_pixels_8_neon; + c->weight_pixels_tab[2] = ff_weight_h264_pixels_4_neon; - c->biweight_h264_pixels_tab[0] = ff_biweight_h264_pixels_16_neon; - c->biweight_h264_pixels_tab[1] = ff_biweight_h264_pixels_8_neon; - c->biweight_h264_pixels_tab[2] = ff_biweight_h264_pixels_4_neon; + c->biweight_pixels_tab[0] = ff_biweight_h264_pixels_16_neon; + c->biweight_pixels_tab[1] = ff_biweight_h264_pixels_8_neon; + c->biweight_pixels_tab[2] = ff_biweight_h264_pixels_4_neon; - c->h264_idct_add = ff_h264_idct_add_neon; - c->h264_idct_dc_add = ff_h264_idct_dc_add_neon; - c->h264_idct_add16 = ff_h264_idct_add16_neon; - c->h264_idct_add16intra = ff_h264_idct_add16intra_neon; + c->idct_add = ff_h264_idct_add_neon; + c->idct_dc_add = ff_h264_idct_dc_add_neon; + c->idct_add16 = ff_h264_idct_add16_neon; + c->idct_add16intra = ff_h264_idct_add16intra_neon; if (chroma_format_idc <= 1) - c->h264_idct_add8 = ff_h264_idct_add8_neon; - c->h264_idct8_add = ff_h264_idct8_add_neon; - c->h264_idct8_dc_add = ff_h264_idct8_dc_add_neon; - c->h264_idct8_add4 = ff_h264_idct8_add4_neon; + c->idct_add8 = ff_h264_idct_add8_neon; + c->idct8_add = ff_h264_idct8_add_neon; + c->idct8_dc_add = ff_h264_idct8_dc_add_neon; + c->idct8_add4 = ff_h264_idct8_add4_neon; } else if (have_neon(cpu_flags) && bit_depth == 10) { - c->h264_v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon_10; - c->h264_v_loop_filter_chroma_intra = ff_h264_v_loop_filter_chroma_intra_neon_10; + c->v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon_10; + c->v_loop_filter_chroma_intra = ff_h264_v_loop_filter_chroma_intra_neon_10; if (chroma_format_idc <= 1) { - c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon_10; - c->h264_h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma_intra_neon_10; - c->h264_h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_mbaff_intra_neon_10; + c->h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon_10; + c->h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma_intra_neon_10; + c->h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_mbaff_intra_neon_10; } else { - c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma422_neon_10; - c->h264_h_loop_filter_chroma_mbaff = ff_h264_h_loop_filter_chroma_neon_10; - c->h264_h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma422_intra_neon_10; - c->h264_h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_intra_neon_10; + c->h_loop_filter_chroma = ff_h264_h_loop_filter_chroma422_neon_10; + c->h_loop_filter_chroma_mbaff = ff_h264_h_loop_filter_chroma_neon_10; + c->h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma422_intra_neon_10; + c->h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_intra_neon_10; } } } diff --git a/libavcodec/aarch64/h264pred_init.c b/libavcodec/aarch64/h264pred_init.c index 0ae8f70d2..9819f85f7 100644 --- a/libavcodec/aarch64/h264pred_init.c +++ b/libavcodec/aarch64/h264pred_init.c @@ -25,6 +25,19 @@ #include "libavcodec/avcodec.h" #include "libavcodec/h264pred.h" +/* PERFORMANCE WARNING: + * These assembly optimizations have been identified as "performance regressions." + * Due to advancements in modern CPU micro-architectures and compiler optimization + * the C implementations now consistently outperform these handwritten routines. + * + * Keep them here for historical reference. + * + * New optimizations are highly welcome! If you can provide an optimized + * implementation that demonstrably beats the current C version in rigorous + * benchmarks, please submit a patch. + */ +#define ENABLE_INEFFICIENT_ASM 0 + void ff_pred16x16_vert_neon(uint8_t *src, ptrdiff_t stride); void ff_pred16x16_hor_neon(uint8_t *src, ptrdiff_t stride); void ff_pred16x16_plane_neon(uint8_t *src, ptrdiff_t stride); @@ -69,16 +82,22 @@ static av_cold void h264_pred_init_neon(H264PredContext *h, int codec_id, { if (bit_depth == 8) { if (chroma_format_idc <= 1) { +#if ENABLE_INEFFICIENT_ASM h->pred8x8[VERT_PRED8x8 ] = ff_pred8x8_vert_neon; h->pred8x8[HOR_PRED8x8 ] = ff_pred8x8_hor_neon; +#endif if (codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8) h->pred8x8[PLANE_PRED8x8] = ff_pred8x8_plane_neon; +#if ENABLE_INEFFICIENT_ASM h->pred8x8[DC_128_PRED8x8 ] = ff_pred8x8_128_dc_neon; +#endif if (codec_id != AV_CODEC_ID_RV40 && codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8) { +#if ENABLE_INEFFICIENT_ASM h->pred8x8[DC_PRED8x8 ] = ff_pred8x8_dc_neon; h->pred8x8[LEFT_DC_PRED8x8] = ff_pred8x8_left_dc_neon; h->pred8x8[TOP_DC_PRED8x8 ] = ff_pred8x8_top_dc_neon; +#endif h->pred8x8[ALZHEIMER_DC_L0T_PRED8x8] = ff_pred8x8_l0t_dc_neon; h->pred8x8[ALZHEIMER_DC_0LT_PRED8x8] = ff_pred8x8_0lt_dc_neon; h->pred8x8[ALZHEIMER_DC_L00_PRED8x8] = ff_pred8x8_l00_dc_neon; @@ -86,27 +105,37 @@ static av_cold void h264_pred_init_neon(H264PredContext *h, int codec_id, } } +#if ENABLE_INEFFICIENT_ASM h->pred16x16[DC_PRED8x8 ] = ff_pred16x16_dc_neon; +#endif h->pred16x16[VERT_PRED8x8 ] = ff_pred16x16_vert_neon; h->pred16x16[HOR_PRED8x8 ] = ff_pred16x16_hor_neon; +#if ENABLE_INEFFICIENT_ASM h->pred16x16[LEFT_DC_PRED8x8] = ff_pred16x16_left_dc_neon; h->pred16x16[TOP_DC_PRED8x8 ] = ff_pred16x16_top_dc_neon; h->pred16x16[DC_128_PRED8x8 ] = ff_pred16x16_128_dc_neon; +#endif if (codec_id != AV_CODEC_ID_SVQ3 && codec_id != AV_CODEC_ID_RV40 && codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8) h->pred16x16[PLANE_PRED8x8 ] = ff_pred16x16_plane_neon; } if (bit_depth == 10) { if (chroma_format_idc <= 1) { +#if ENABLE_INEFFICIENT_ASM h->pred8x8[VERT_PRED8x8 ] = ff_pred8x8_vert_neon_10; +#endif h->pred8x8[HOR_PRED8x8 ] = ff_pred8x8_hor_neon_10; if (codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8) h->pred8x8[PLANE_PRED8x8] = ff_pred8x8_plane_neon_10; +#if ENABLE_INEFFICIENT_ASM h->pred8x8[DC_128_PRED8x8 ] = ff_pred8x8_128_dc_neon_10; +#endif if (codec_id != AV_CODEC_ID_RV40 && codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8) { +#if ENABLE_INEFFICIENT_ASM h->pred8x8[DC_PRED8x8 ] = ff_pred8x8_dc_neon_10; h->pred8x8[LEFT_DC_PRED8x8] = ff_pred8x8_left_dc_neon_10; +#endif h->pred8x8[TOP_DC_PRED8x8 ] = ff_pred8x8_top_dc_neon_10; h->pred8x8[ALZHEIMER_DC_L0T_PRED8x8] = ff_pred8x8_l0t_dc_neon_10; h->pred8x8[ALZHEIMER_DC_0LT_PRED8x8] = ff_pred8x8_0lt_dc_neon_10; diff --git a/libavcodec/aarch64/h26x/dsp.h b/libavcodec/aarch64/h26x/dsp.h index 0fefb4d70..6c9100430 100644 --- a/libavcodec/aarch64/h26x/dsp.h +++ b/libavcodec/aarch64/h26x/dsp.h @@ -28,6 +28,10 @@ void ff_h26x_sao_band_filter_8x8_8_neon(uint8_t *_dst, const uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, const int16_t *sao_offset_val, int sao_left_class, int width, int height); +void ff_h26x_sao_band_filter_16x16_8_neon(uint8_t *_dst, const uint8_t *_src, + ptrdiff_t stride_dst, ptrdiff_t stride_src, + const int16_t *sao_offset_val, int sao_left_class, + int width, int height); void ff_hevc_sao_edge_filter_16x16_8_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride_dst, const int16_t *sao_offset_val, int eo, int width, int height); void ff_hevc_sao_edge_filter_8x8_8_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride_dst, @@ -88,6 +92,11 @@ NEON8_FNPROTO(pel_bi_pixels, (uint8_t *dst, ptrdiff_t dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width),); +NEON8_FNPROTO(pel_bi_w_pixels, (uint8_t *_dst, ptrdiff_t _dststride, + const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, + int height, int denom, int wx0, int wx1, + int ox0, int ox1, intptr_t mx, intptr_t my, int width),); + NEON8_FNPROTO(epel_bi_h, (uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, ptrdiff_t srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width),); diff --git a/libavcodec/aarch64/h26x/epel_neon.S b/libavcodec/aarch64/h26x/epel_neon.S index e44a448b1..235e3f5dd 100644 --- a/libavcodec/aarch64/h26x/epel_neon.S +++ b/libavcodec/aarch64/h26x/epel_neon.S @@ -473,6 +473,379 @@ function ff_hevc_put_hevc_pel_bi_pixels64_8_neon, export=1 ret endfunc +.macro load_bi_w_pixels_param + ldrsw x8, [sp] // wx1 +#if defined(__APPLE__) + ldpsw x9, x10, [sp, #4] // ox0, ox1 + ldrsw x11, [sp, #32] // width +#else + ldrsw x9, [sp, #8] // ox0 + ldrsw x10, [sp, #16] // ox1 + ldrsw x11, [sp, #40] // width +#endif +.endm + +function ff_hevc_put_hevc_pel_bi_w_pixels4_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) +1: + ld1 {v4.8b}, [x2], x3 // load src + ld1 {v5.8b}, [x4], x8 // load src2 + subs w5, w5, #1 + mov v3.16b, v2.16b + ushll v4.8h, v4.8b, #6 + smlal v3.4s, v4.4h, v1.4h + smlal v3.4s, v5.4h, v0.4h + sshl v3.4s, v3.4s, v6.4s + sqxtn v3.4h, v3.4s + sqxtun v3.8b, v3.8h + st1 {v3.s}[0], [x0], x1 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels6_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) + sub x1, x1, #4 +1: + ld1 {v4.8b}, [x2], x3 // load src + ld1 {v5.8h}, [x4], x8 // load src2 + subs w5, w5, #1 + mov v3.16b, v2.16b + mov v7.16b, v2.16b + ushll v4.8h, v4.8b, #6 + smlal v3.4s, v4.4h, v1.4h + smlal v3.4s, v5.4h, v0.4h + smlal2 v7.4s, v4.8h, v1.8h + smlal2 v7.4s, v5.8h, v0.8h + sshl v3.4s, v3.4s, v6.4s + sshl v7.4s, v7.4s, v6.4s + sqxtn v3.4h, v3.4s + sqxtn2 v3.8h, v7.4s + sqxtun v3.8b, v3.8h + str s3, [x0], #4 + st1 {v3.h}[2], [x0], x1 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels8_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) +1: + ld1 {v4.8b}, [x2], x3 // load src + ld1 {v5.8h}, [x4], x8 // load src2 + subs w5, w5, #1 + mov v3.16b, v2.16b + mov v7.16b, v2.16b + ushll v4.8h, v4.8b, #6 + smlal v3.4s, v4.4h, v1.4h + smlal v3.4s, v5.4h, v0.4h + smlal2 v7.4s, v4.8h, v1.8h + smlal2 v7.4s, v5.8h, v0.8h + sshl v3.4s, v3.4s, v6.4s + sshl v7.4s, v7.4s, v6.4s + sqxtn v3.4h, v3.4s + sqxtn2 v3.8h, v7.4s + sqxtun v3.8b, v3.8h + st1 {v3.8b}, [x0], x1 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels12_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) + sub x1, x1, #8 +1: + ld1 {v24.16b}, [x2], x3 // load src + ld1 {v20.16b, v21.16b}, [x4], x8 // load src2 + subs w5, w5, #1 + + mov v16.16b, v2.16b + mov v17.16b, v2.16b + mov v18.16b, v2.16b + + ushll v4.8h, v24.8b, #6 + ushll2 v24.8h, v24.16b, #6 + + smlal v16.4s, v4.4h, v1.4h + smlal v16.4s, v20.4h, v0.4h + smlal2 v17.4s, v4.8h, v1.8h + smlal2 v17.4s, v20.8h, v0.8h + smlal v18.4s, v24.4h, v1.4h + smlal v18.4s, v21.4h, v0.4h + + sshl v16.4s, v16.4s, v6.4s + sshl v17.4s, v17.4s, v6.4s + sshl v18.4s, v18.4s, v6.4s + + sqxtn v16.4h, v16.4s + sqxtn2 v16.8h, v17.4s + sqxtn v18.4h, v18.4s + sqxtun v3.8b, v16.8h + sqxtun2 v3.16b, v18.8h + str d3, [x0], #8 + st1 {v3.s}[2], [x0], x1 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels16_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) +1: + ld1 {v24.16b}, [x2], x3 // load src + ld1 {v20.16b, v21.16b}, [x4], x8 // load src2 + subs w5, w5, #1 + + mov v16.16b, v2.16b + mov v17.16b, v2.16b + mov v18.16b, v2.16b + mov v19.16b, v2.16b + + ushll v4.8h, v24.8b, #6 + ushll2 v24.8h, v24.16b, #6 + + smlal v16.4s, v4.4h, v1.4h + smlal v16.4s, v20.4h, v0.4h + smlal2 v17.4s, v4.8h, v1.8h + smlal2 v17.4s, v20.8h, v0.8h + smlal v18.4s, v24.4h, v1.4h + smlal v18.4s, v21.4h, v0.4h + smlal2 v19.4s, v24.8h, v1.8h + smlal2 v19.4s, v21.8h, v0.8h + + sshl v16.4s, v16.4s, v6.4s + sshl v17.4s, v17.4s, v6.4s + sshl v18.4s, v18.4s, v6.4s + sshl v19.4s, v19.4s, v6.4s + + sqxtn v16.4h, v16.4s + sqxtn2 v16.8h, v17.4s + sqxtn v18.4h, v18.4s + sqxtn2 v18.8h, v19.4s + sqxtun v3.8b, v16.8h + sqxtun2 v3.16b, v18.8h + st1 {v3.16b}, [x0], x1 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels24_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) + mov x7, #24 + sub x3, x3, x11 + sub x8, x8, x11, lsl #1 + sub x1, x1, x11 +1: + mov w6, w11 +2: + ld1 {v24.16b, v25.16b}, [x2], x7 + ld1 {v20.8h, v21.8h, v22.8h}, [x4], #48 + + subs w6, w6, #24 + + mov v16.16b, v2.16b + mov v17.16b, v2.16b + mov v18.16b, v2.16b + mov v19.16b, v2.16b + mov v26.16b, v2.16b + mov v27.16b, v2.16b + + ushll v4.8h, v24.8b, #6 + ushll2 v24.8h, v24.16b, #6 + ushll v5.8h, v25.8b, #6 + + smlal v16.4s, v4.4h, v1.4h + smlal v16.4s, v20.4h, v0.4h + smlal2 v17.4s, v4.8h, v1.8h + smlal2 v17.4s, v20.8h, v0.8h + smlal v18.4s, v24.4h, v1.4h + smlal v18.4s, v21.4h, v0.4h + smlal2 v19.4s, v24.8h, v1.8h + smlal2 v19.4s, v21.8h, v0.8h + smlal v26.4s, v5.4h, v1.4h + smlal v26.4s, v22.4h, v0.4h + smlal2 v27.4s, v5.8h, v1.8h + smlal2 v27.4s, v22.8h, v0.8h + + sshl v16.4s, v16.4s, v6.4s + sshl v17.4s, v17.4s, v6.4s + sshl v18.4s, v18.4s, v6.4s + sshl v19.4s, v19.4s, v6.4s + sshl v26.4s, v26.4s, v6.4s + sshl v27.4s, v27.4s, v6.4s + + sqxtn v16.4h, v16.4s + sqxtn2 v16.8h, v17.4s + sqxtn v18.4h, v18.4s + sqxtn2 v18.8h, v19.4s + sqxtn v26.4h, v26.4s + sqxtn2 v26.8h, v27.4s + sqxtun v3.8b, v16.8h + sqxtun2 v3.16b, v18.8h + sqxtun v4.8b, v26.8h + str q3, [x0], #16 + str d4, [x0], #8 + b.ne 2b + + subs w5, w5, #1 + add x0, x0, x1 + add x2, x2, x3 + add x4, x4, x8 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels32_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) + sub x3, x3, x11 + sub x8, x8, x11, lsl #1 + sub x1, x1, x11 +1: + mov w6, w11 +2: + ld1 {v24.16b, v25.16b}, [x2], #32 // load src + ld1 {v20.8h, v21.8h, v22.8h, v23.8h}, [x4], #64 // load src2 + + subs w6, w6, #32 + + mov v16.16b, v2.16b + mov v17.16b, v2.16b + mov v18.16b, v2.16b + mov v19.16b, v2.16b + mov v26.16b, v2.16b + mov v27.16b, v2.16b + mov v28.16b, v2.16b + mov v29.16b, v2.16b + + ushll v4.8h, v24.8b, #6 + ushll2 v24.8h, v24.16b, #6 + ushll v5.8h, v25.8b, #6 + ushll2 v25.8h, v25.16b, #6 + + smlal v16.4s, v4.4h, v1.4h + smlal v16.4s, v20.4h, v0.4h + smlal2 v17.4s, v4.8h, v1.8h + smlal2 v17.4s, v20.8h, v0.8h + smlal v18.4s, v24.4h, v1.4h + smlal v18.4s, v21.4h, v0.4h + smlal2 v19.4s, v24.8h, v1.8h + smlal2 v19.4s, v21.8h, v0.8h + smlal v26.4s, v5.4h, v1.4h + smlal v26.4s, v22.4h, v0.4h + smlal2 v27.4s, v5.8h, v1.8h + smlal2 v27.4s, v22.8h, v0.8h + smlal v28.4s, v25.4h, v1.4h + smlal v28.4s, v23.4h, v0.4h + smlal2 v29.4s, v25.8h, v1.8h + smlal2 v29.4s, v23.8h, v0.8h + + sshl v16.4s, v16.4s, v6.4s + sshl v17.4s, v17.4s, v6.4s + sshl v18.4s, v18.4s, v6.4s + sshl v19.4s, v19.4s, v6.4s + sshl v26.4s, v26.4s, v6.4s + sshl v27.4s, v27.4s, v6.4s + sshl v28.4s, v28.4s, v6.4s + sshl v29.4s, v29.4s, v6.4s + + sqxtn v16.4h, v16.4s + sqxtn2 v16.8h, v17.4s + sqxtn v18.4h, v18.4s + sqxtn2 v18.8h, v19.4s + sqxtn v26.4h, v26.4s + sqxtn2 v26.8h, v27.4s + sqxtn v28.4h, v28.4s + sqxtn2 v28.8h, v29.4s + sqxtun v3.8b, v16.8h + sqxtun2 v3.16b, v18.8h + sqxtun v4.8b, v26.8h + sqxtun2 v4.16b, v28.8h + st1 {v3.16b, v4.16b}, [x0], #32 + b.ne 2b + + subs w5, w5, #1 + add x0, x0, x1 + add x2, x2, x3 + add x4, x4, x8 + b.ne 1b + ret +endfunc function ff_hevc_put_hevc_epel_bi_h4_8_neon, export=1 load_epel_filterb x6, x7 diff --git a/libavcodec/aarch64/h26x/qpel_neon.S b/libavcodec/aarch64/h26x/qpel_neon.S index 5c3f0263b..423db3849 100644 --- a/libavcodec/aarch64/h26x/qpel_neon.S +++ b/libavcodec/aarch64/h26x/qpel_neon.S @@ -552,21 +552,64 @@ function ff_hevc_put_hevc_\type\()_h12_8_neon, export=1 ret mx endfunc +.ifc \type, qpel +// VVC qpel h16: self-contained int16-domain implementation +function ff_vvc_put_qpel_h16_8_neon, export=1 + vvc_load_filter mx + sxtw height, heightw + sub src, src, #3 + mov mx, x30 + mov dststride, #(VVC_MAX_PB_SIZE << 1) + lsl x13, srcstride, #1 // srcstridel + mov x14, #(VVC_MAX_PB_SIZE << 2) + add x10, dst, dststride // dstb + add x12, src, srcstride // srcb +1: ld1 {v16.8b-v18.8b}, [src], x13 + ld1 {v19.8b-v21.8b}, [x12], x13 + uxtl v16.8h, v16.8b + uxtl v19.8h, v19.8b + bl ff_hevc_put_hevc_h16_8_neon + subs height, height, #2 + st1 {v26.8h, v27.8h}, [dst], x14 + st1 {v28.8h, v29.8h}, [x10], x14 + b.gt 1b // double line + ret mx +endfunc + +// HEVC qpel h16: byte-domain widening multiply +function ff_hevc_put_hevc_qpel_h16_8_neon, export=1 + load_qpel_filterb mx, x15 + sxtw height, heightw + sub src, src, #3 + mov dststride, #(HEVC_MAX_PB_SIZE << 1) +1: + ld1 {v16.16b, v17.16b}, [src], srcstride + ext v18.16b, v16.16b, v17.16b, #1 + ext v19.16b, v16.16b, v17.16b, #2 + ext v20.16b, v16.16b, v17.16b, #3 + ext v21.16b, v16.16b, v17.16b, #4 + ext v22.16b, v16.16b, v17.16b, #5 + ext v23.16b, v16.16b, v17.16b, #6 + ext v24.16b, v16.16b, v17.16b, #7 + calc_qpelb v26, v16, v18, v19, v20, v21, v22, v23, v24 + calc_qpelb2 v27, v16, v18, v19, v20, v21, v22, v23, v24 + stp q26, q27, [dst] + add dst, dst, dststride + subs height, height, #1 + b.gt 1b + ret +endfunc + +.else // qpel_uni, qpel_bi + .ifnc \type, qpel_bi function ff_vvc_put_\type\()_h16_8_neon, export=1 vvc_load_filter mx sxtw height, heightw - mov mx, x30 sub src, src, #3 mov mx, x30 -.ifc \type, qpel - mov dststride, #(VVC_MAX_PB_SIZE << 1) - lsl x13, srcstride, #1 // srcstridel - mov x14, #(VVC_MAX_PB_SIZE << 2) -.else lsl x14, dststride, #1 // dststridel lsl x13, srcstride, #1 // srcstridel -.endif b 0f endfunc .endif // !qpel_bi @@ -582,14 +625,8 @@ function ff_hevc_put_hevc_\type\()_h16_8_neon, export=1 .endif sub src, src, #3 mov mx, x30 -.ifc \type, qpel - mov dststride, #(HEVC_MAX_PB_SIZE << 1) - lsl x13, srcstride, #1 // srcstridel - mov x14, #(HEVC_MAX_PB_SIZE << 2) -.else lsl x14, dststride, #1 // dststridel lsl x13, srcstride, #1 // srcstridel -.endif 0: add x10, dst, dststride // dstb add x12, src, srcstride // srcb @@ -602,10 +639,6 @@ function ff_hevc_put_hevc_\type\()_h16_8_neon, export=1 bl ff_hevc_put_hevc_h16_8_neon subs height, height, #2 -.ifc \type, qpel - st1 {v26.8h, v27.8h}, [dst], x14 - st1 {v28.8h, v29.8h}, [x10], x14 -.else .ifc \type, qpel_bi ld1 {v16.8h, v17.8h}, [ x4], x16 ld1 {v18.8h, v19.8h}, [x15], x16 @@ -625,28 +658,96 @@ function ff_hevc_put_hevc_\type\()_h16_8_neon, export=1 .endif st1 {v26.8b, v27.8b}, [dst], x14 st1 {v28.8b, v29.8b}, [x10], x14 -.endif b.gt 1b // double line ret mx endfunc +.endif // qpel vs qpel_uni/qpel_bi + +.ifc \type, qpel +// VVC qpel h32: self-contained int16-domain implementation +function ff_vvc_put_qpel_h32_8_neon, export=1 + vvc_load_filter mx + sxtw height, heightw + mov mx, x30 + sub src, src, #3 + mov dststride, #(VVC_MAX_PB_SIZE << 1) + lsl x13, srcstride, #1 // srcstridel + mov x14, #(VVC_MAX_PB_SIZE << 2) + sub x14, x14, width, uxtw #1 + sub x13, x13, width, uxtw + sub x13, x13, #8 + add x10, dst, dststride // dstb + add x12, src, srcstride // srcb +0: mov w9, width + ld1 {v16.8b}, [src], #8 + ld1 {v19.8b}, [x12], #8 + uxtl v16.8h, v16.8b + uxtl v19.8h, v19.8b +1: + ld1 {v17.8b-v18.8b}, [src], #16 + ld1 {v20.8b-v21.8b}, [x12], #16 + bl ff_hevc_put_hevc_h16_8_neon + subs w9, w9, #16 + mov v16.16b, v18.16b + mov v19.16b, v21.16b + st1 {v26.8h, v27.8h}, [dst], #32 + st1 {v28.8h, v29.8h}, [x10], #32 + b.gt 1b // double line + subs height, height, #2 + add src, src, x13 + add x12, x12, x13 + add dst, dst, x14 + add x10, x10, x14 + b.gt 0b + ret mx +endfunc + +// HEVC qpel h32: byte-domain widening multiply with width loop +function ff_hevc_put_hevc_qpel_h32_8_neon, export=1 + load_qpel_filterb mx, x15 + sxtw height, heightw + sub src, src, #3 + mov dststride, #(HEVC_MAX_PB_SIZE << 1) + sub x13, dststride, width, uxtw #1 // stride adjustment +0: + mov w9, width + mov x10, src + mov x11, dst +1: + ld1 {v16.16b, v17.16b}, [x10] + add x10, x10, #16 + ext v18.16b, v16.16b, v17.16b, #1 + ext v19.16b, v16.16b, v17.16b, #2 + ext v20.16b, v16.16b, v17.16b, #3 + ext v21.16b, v16.16b, v17.16b, #4 + ext v22.16b, v16.16b, v17.16b, #5 + ext v23.16b, v16.16b, v17.16b, #6 + ext v24.16b, v16.16b, v17.16b, #7 + calc_qpelb v26, v16, v18, v19, v20, v21, v22, v23, v24 + calc_qpelb2 v27, v16, v18, v19, v20, v21, v22, v23, v24 + stp q26, q27, [x11], #32 + subs w9, w9, #16 + b.gt 1b + add src, src, srcstride + add dst, dst, x13 + add dst, dst, width, uxtw #1 + subs height, height, #1 + b.gt 0b + ret +endfunc + +.else // qpel_uni, qpel_bi + .ifnc \type, qpel_bi function ff_vvc_put_\type\()_h32_8_neon, export=1 vvc_load_filter mx sxtw height, heightw - mov mx, x30 sub src, src, #3 mov mx, x30 -.ifc \type, qpel - mov dststride, #(VVC_MAX_PB_SIZE << 1) - lsl x13, srcstride, #1 // srcstridel - mov x14, #(VVC_MAX_PB_SIZE << 2) - sub x14, x14, width, uxtw #1 -.else lsl x14, dststride, #1 // dststridel lsl x13, srcstride, #1 // srcstridel sub x14, x14, width, uxtw -.endif b 1f endfunc .endif // !qpel_bi @@ -664,16 +765,9 @@ function ff_hevc_put_hevc_\type\()_h32_8_neon, export=1 .endif sub src, src, #3 mov mx, x30 -.ifc \type, qpel - mov dststride, #(HEVC_MAX_PB_SIZE << 1) - lsl x13, srcstride, #1 // srcstridel - mov x14, #(HEVC_MAX_PB_SIZE << 2) - sub x14, x14, width, uxtw #1 -.else lsl x14, dststride, #1 // dststridel lsl x13, srcstride, #1 // srcstridel sub x14, x14, width, uxtw -.endif 1: sub x13, x13, width, uxtw sub x13, x13, #8 @@ -693,10 +787,6 @@ function ff_hevc_put_hevc_\type\()_h32_8_neon, export=1 mov v16.16b, v18.16b mov v19.16b, v21.16b -.ifc \type, qpel - st1 {v26.8h, v27.8h}, [dst], #32 - st1 {v28.8h, v29.8h}, [x10], #32 -.else .ifc \type, qpel_bi ld1 {v20.8h, v21.8h}, [ x4], #32 ld1 {v22.8h, v23.8h}, [x15], #32 @@ -716,7 +806,6 @@ function ff_hevc_put_hevc_\type\()_h32_8_neon, export=1 .endif st1 {v26.8b, v27.8b}, [dst], #16 st1 {v28.8b, v29.8b}, [x10], #16 -.endif b.gt 1b // double line subs height, height, #2 add src, src, x13 @@ -731,6 +820,8 @@ function ff_hevc_put_hevc_\type\()_h32_8_neon, export=1 ret mx endfunc +.endif // qpel vs qpel_uni/qpel_bi + .unreq height .unreq heightw .unreq width @@ -1511,7 +1602,7 @@ function ff_hevc_put_hevc_qpel_uni_v4_8_neon, export=1 .endm 1: calc_all .purgem calc -2: ret +2: ret endfunc function ff_hevc_put_hevc_qpel_uni_v6_8_neon, export=1 @@ -1540,7 +1631,7 @@ function ff_hevc_put_hevc_qpel_uni_v6_8_neon, export=1 .endm 1: calc_all .purgem calc -2: ret +2: ret endfunc function ff_hevc_put_hevc_qpel_uni_v8_8_neon, export=1 @@ -1567,7 +1658,7 @@ function ff_hevc_put_hevc_qpel_uni_v8_8_neon, export=1 .endm 1: calc_all .purgem calc -2: ret +2: ret endfunc function ff_hevc_put_hevc_qpel_uni_v12_8_neon, export=1 @@ -4141,9 +4232,9 @@ DISABLE_I8MM #endif function vvc_put_qpel_hv4_8_end_neon - vvc_load_qpel_filterh x5 - mov x7, #(VVC_MAX_PB_SIZE * 2) - b 1f + vvc_load_qpel_filterh x5 + mov x7, #(VVC_MAX_PB_SIZE * 2) + b 1f endfunc function hevc_put_hevc_qpel_hv4_8_end_neon diff --git a/libavcodec/aarch64/h26x/sao_neon.S b/libavcodec/aarch64/h26x/sao_neon.S index c43820135..354614eca 100644 --- a/libavcodec/aarch64/h26x/sao_neon.S +++ b/libavcodec/aarch64/h26x/sao_neon.S @@ -35,48 +35,67 @@ // int16_t *sao_offset_val, int sao_left_class, // int width, int height) function ff_h26x_sao_band_filter_8x8_8_neon, export=1 - stp xzr, xzr, [sp, #-64]! + stp xzr, xzr, [sp, #-32]! stp xzr, xzr, [sp, #16] - stp xzr, xzr, [sp, #32] - stp xzr, xzr, [sp, #48] mov w8, #4 -0: ldrsh x9, [x4, x8, lsl #1] // sao_offset_val[k+1] - subs w8, w8, #1 - add w10, w8, w5 // k + sao_left_class +0: + ldrsh x9, [x4, x8, lsl #1] // sao_offset_val[k+1] + subs w8, w8, #1 + add w10, w8, w5 // k + sao_left_class and w10, w10, #0x1F - strh w9, [sp, x10, lsl #1] + strb w9, [sp, x10] bne 0b - add w6, w6, #7 - bic w6, w6, #7 - ld1 {v16.16b-v19.16b}, [sp], #64 - sub x2, x2, x6 - sub x3, x3, x6 - movi v20.8h, #1 -1: mov w8, w6 // beginning of line -2: // Simple layout for accessing 16bit values - // with 8bit LUT. - // - // 00 01 02 03 04 05 06 07 - // +-----------------------------------> - // |xDE#xAD|xCA#xFE|xBE#xEF|xFE#xED|.... - // +-----------------------------------> - // i-0 i-1 i-2 i-3 - ld1 {v2.8b}, [x1], #8 // dst[x] = av_clip_pixel(src[x] + offset_table[src[x] >> shift]); - subs w8, w8, #8 - uxtl v0.8h, v2.8b // load src[x] - ushr v2.8h, v0.8h, #3 // >> BIT_DEPTH - 3 - shl v1.8h, v2.8h, #1 // low (x2, accessing short) - add v3.8h, v1.8h, v20.8h // +1 access upper short - sli v1.8h, v3.8h, #8 // shift insert index to upper byte - tbx v2.16b, {v16.16b-v19.16b}, v1.16b // table - add v1.8h, v0.8h, v2.8h // src[x] + table - sqxtun v4.8b, v1.8h // clip + narrow - st1 {v4.8b}, [x0], #8 // store - // done 8 pixels + ldp q16, q17, [sp], #32 +1: + ld1 {v2.8b}, [x1], x3 + subs w7, w7, #1 + uxtl v0.8h, v2.8b + ushr v3.8b, v2.8b, #3 // >> BIT_DEPTH - 3 + tbl v3.8b, {v16.16b-v17.16b}, v3.8b + sxtl v2.8h, v3.8b + add v0.8h, v0.8h, v2.8h // src[x] + table + sqxtun v0.8b, v0.8h // clip + narrow + st1 {v0.8b}, [x0], x2 + bne 1b + ret +endfunc + +function ff_h26x_sao_band_filter_16x16_8_neon, export=1 + stp xzr, xzr, [sp, #-32]! + stp xzr, xzr, [sp, #16] + mov w8, #4 +0: + ldrsh x9, [x4, x8, lsl #1] // sao_offset_val[k+1] + subs w8, w8, #1 + add w10, w8, w5 // k + sao_left_class + and w10, w10, #0x1F + strb w9, [sp, x10] + bne 0b + add w6, w6, #15 + bic w6, w6, #15 + ldp q16, q17, [sp], #32 + sub x2, x2, x6 + sub x3, x3, x6 +1: + mov w8, w6 // beginning of line +2: + ldr q2, [x1], #16 + subs w8, w8, #16 + uxtl v0.8h, v2.8b + uxtl2 v1.8h, v2.16b + ushr v3.16b, v2.16b, #3 // >> BIT_DEPTH - 3 + tbl v3.16b, {v16.16b-v17.16b}, v3.16b + sxtl v2.8h, v3.8b + sxtl2 v3.8h, v3.16b + add v0.8h, v0.8h, v2.8h // src[x] + table + add v1.8h, v1.8h, v3.8h + sqxtun v0.8b, v0.8h // clip + narrow + sqxtun2 v0.16b, v1.8h + str q0, [x0], #16 bne 2b - subs w7, w7, #1 // finished line, prep. new - add x0, x0, x2 // dst += stride_dst - add x1, x1, x3 // src += stride_src + subs w7, w7, #1 + add x0, x0, x2 // dst += stride_dst + add x1, x1, x3 // src += stride_src bne 1b ret endfunc diff --git a/libavcodec/aarch64/hevcdsp_deblock_neon.S b/libavcodec/aarch64/hevcdsp_deblock_neon.S index 581056a91..7a25fe245 100644 --- a/libavcodec/aarch64/hevcdsp_deblock_neon.S +++ b/libavcodec/aarch64/hevcdsp_deblock_neon.S @@ -511,8 +511,11 @@ function hevc_loop_filter_luma_body_\bitdepth\()_neon, export=0 sqxtun v6.8b, v6.8h sqxtun v7.8b, v7.8h .endif + // Use x15 to signal whether any pixels should be updated or not. + mov x15, #1 + ret +3: mov x15, #0 ret -3: ret x6 endfunc .endm @@ -562,6 +565,7 @@ function ff_hevc_\dir\()_loop_filter_luma_\bitdepth\()_neon, export=1 .endif .endif bl hevc_loop_filter_luma_body_\bitdepth\()_neon + cbz x15, 9f .if \bitdepth > 8 .ifc \dir, v transpose_8x8H v0, v1, v2, v3, v4, v5, v6, v7, v16, v17 @@ -587,6 +591,7 @@ function ff_hevc_\dir\()_loop_filter_luma_\bitdepth\()_neon, export=1 st1 {v6.8b}, [x10], x1 st1 {v7.8b}, [x10] .endif +9: ret x6 endfunc .endm diff --git a/libavcodec/aarch64/hevcdsp_dequant_neon.S b/libavcodec/aarch64/hevcdsp_dequant_neon.S new file mode 100644 index 000000000..af2b01ac4 --- /dev/null +++ b/libavcodec/aarch64/hevcdsp_dequant_neon.S @@ -0,0 +1,371 @@ +/* + * ARM NEON optimised dequant functions for HEVC decoding + * + * Copyright (c) 2026 FFmpeg contributors + * + * 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/aarch64/asm.S" + +// HEVC dequant for 8-bit depth +// +// Algorithm (from dsp_template.c): +// shift = 15 - BIT_DEPTH - log2_size +// offset = 1 << (shift - 1) +// output = (input + offset) >> shift +// +// This is equivalent to: output = ROUND(input >> shift) +// NEON srshr (Signed Rounding Shift Right) does exactly this in one instruction! +// +// For 8-bit: shift = 15 - 8 - log2_size = 7 - log2_size +// +// Block size | log2_size | shift | operation +// 4x4 | 2 | 5 | srshr #5 +// 8x8 | 3 | 4 | srshr #4 +// 16x16 | 4 | 3 | srshr #3 +// 32x32 | 5 | 2 | srshr #2 + +// void ff_hevc_dequant_4x4_8_neon(int16_t *coeffs) +// 4x4 = 16 coeffs, shift=5 +function ff_hevc_dequant_4x4_8_neon, export=1 + ldp q0, q1, [x0] // load 16 int16_t (32 bytes) + srshr v0.8h, v0.8h, #5 // rounding shift right by 5 + srshr v1.8h, v1.8h, #5 + stp q0, q1, [x0] // store + ret +endfunc + +// void ff_hevc_dequant_8x8_8_neon(int16_t *coeffs) +// 8x8 = 64 coeffs, shift=4 +// Fully unrolled - no loop needed for 64 coeffs +function ff_hevc_dequant_8x8_8_neon, export=1 + ld1 {v0.16b-v3.16b}, [x0], #64 + ld1 {v4.16b-v7.16b}, [x0] + sub x0, x0, #64 + srshr v0.8h, v0.8h, #4 + srshr v1.8h, v1.8h, #4 + srshr v2.8h, v2.8h, #4 + srshr v3.8h, v3.8h, #4 + srshr v4.8h, v4.8h, #4 + srshr v5.8h, v5.8h, #4 + srshr v6.8h, v6.8h, #4 + srshr v7.8h, v7.8h, #4 + st1 {v0.16b-v3.16b}, [x0], #64 + st1 {v4.16b-v7.16b}, [x0] + ret +endfunc + +// void ff_hevc_dequant_16x16_8_neon(int16_t *coeffs) +// 16x16 = 256 coeffs, shift=3 +// Pipelined implementation: interleave load/compute/store to hide memory latency +// Uses .irp macro to unroll 4 iterations, processing 64 coeffs per iteration +// x0 = load pointer, x1 = store pointer (both advance through the buffer) +function ff_hevc_dequant_16x16_8_neon, export=1 + mov x1, x0 + ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], #64 +.irp i, 0, 1, 2, 3 + srshr v0.8h, v0.8h, #3 + srshr v1.8h, v1.8h, #3 + ld1 {v4.16b, v5.16b, v6.16b, v7.16b}, [x0], #64 + srshr v2.8h, v2.8h, #3 + srshr v3.8h, v3.8h, #3 + srshr v4.8h, v4.8h, #3 + srshr v5.8h, v5.8h, #3 + st1 {v0.16b - v3.16b}, [x1], #64 + srshr v6.8h, v6.8h, #3 +.if \i < 3 + ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], #64 +.endif + srshr v7.8h, v7.8h, #3 + st1 {v4.16b - v7.16b}, [x1], #64 +.endr + ret +endfunc + +// void ff_hevc_dequant_32x32_8_neon(int16_t *coeffs) +// 32x32 = 1024 coeffs, shift=2 +// Process 128 coeffs per iteration (8 iterations) +// Using all available NEON registers for maximum throughput +// AAPCS64: v0-v7 and v16-v31 are volatile (caller-saved) +// We use v0-v7 and v16-v23 to avoid touching callee-saved v8-v15 +function ff_hevc_dequant_32x32_8_neon, export=1 + mov x2, #8 // loop 8 times (128 coeffs each) +1: + // Group A: q0-q3 (64 bytes / 32 coeffs) + ldp q0, q1, [x0] + ldp q2, q3, [x0, #32] + // Group B: q4-q7 (64 bytes / 32 coeffs) + ldp q4, q5, [x0, #64] + ldp q6, q7, [x0, #96] + subs x2, x2, #1 // Decrement loop counter early for better pipelining + + // Calc Group A (shift right with rounding) + srshr v0.8h, v0.8h, #2 + srshr v1.8h, v1.8h, #2 + srshr v2.8h, v2.8h, #2 + srshr v3.8h, v3.8h, #2 + + // Group C: q16-q19 (64 bytes / 32 coeffs) + // Load into volatile high registers to maximize pipeline usage + ldp q16, q17, [x0, #128] + ldp q18, q19, [x0, #160] + + // Calc Group B + srshr v4.8h, v4.8h, #2 + srshr v5.8h, v5.8h, #2 + srshr v6.8h, v6.8h, #2 + srshr v7.8h, v7.8h, #2 + + // Store Group A (Write back results to memory) + stp q0, q1, [x0] + stp q2, q3, [x0, #32] + + // Group D: q20-q23 (64 bytes / 32 coeffs) + ldp q20, q21, [x0, #192] + ldp q22, q23, [x0, #224] + + // Calc Group C + srshr v16.8h, v16.8h, #2 + srshr v17.8h, v17.8h, #2 + srshr v18.8h, v18.8h, #2 + srshr v19.8h, v19.8h, #2 + + // Store Group B + stp q4, q5, [x0, #64] + stp q6, q7, [x0, #96] + + // Calc Group D + srshr v20.8h, v20.8h, #2 + srshr v21.8h, v21.8h, #2 + srshr v22.8h, v22.8h, #2 + srshr v23.8h, v23.8h, #2 + + // Store Group C + stp q16, q17, [x0, #128] + stp q18, q19, [x0, #160] + + // Store Group D + stp q20, q21, [x0, #192] + stp q22, q23, [x0, #224] + + add x0, x0, #256 // Advance pointer by 128 coeffs (256 bytes) + b.ne 1b + ret +endfunc + +// -------------------------------------------------------------------------- +// HEVC dequant for 10-bit depth +// +// For 10-bit: shift = 15 - 10 - log2_size = 5 - log2_size +// +// Block size | log2_size | shift | operation +// 4x4 | 2 | 3 | srshr #3 +// 8x8 | 3 | 2 | srshr #2 +// 16x16 | 4 | 1 | srshr #1 +// 32x32 | 5 | 0 | no-op (identity) +// -------------------------------------------------------------------------- + +// void ff_hevc_dequant_4x4_10_neon(int16_t *coeffs) +// 4x4 = 16 coeffs, shift=3 +function ff_hevc_dequant_4x4_10_neon, export=1 + ldp q0, q1, [x0] + srshr v0.8h, v0.8h, #3 + srshr v1.8h, v1.8h, #3 + stp q0, q1, [x0] + ret +endfunc + +// void ff_hevc_dequant_8x8_10_neon(int16_t *coeffs) +// 8x8 = 64 coeffs, shift=2 +// Fully unrolled - no loop needed for 64 coeffs +function ff_hevc_dequant_8x8_10_neon, export=1 + ld1 {v0.16b-v3.16b}, [x0], #64 + ld1 {v4.16b-v7.16b}, [x0] + sub x0, x0, #64 + srshr v0.8h, v0.8h, #2 + srshr v1.8h, v1.8h, #2 + srshr v2.8h, v2.8h, #2 + srshr v3.8h, v3.8h, #2 + srshr v4.8h, v4.8h, #2 + srshr v5.8h, v5.8h, #2 + srshr v6.8h, v6.8h, #2 + srshr v7.8h, v7.8h, #2 + st1 {v0.16b-v3.16b}, [x0], #64 + st1 {v4.16b-v7.16b}, [x0] + ret +endfunc + +// void ff_hevc_dequant_16x16_10_neon(int16_t *coeffs) +// 16x16 = 256 coeffs, shift=1 +// Pipelined implementation: interleave load/compute/store to hide memory latency +// Uses .irp macro to unroll 4 iterations, processing 64 coeffs per iteration +// x0 = load pointer, x1 = store pointer (both advance through the buffer) +function ff_hevc_dequant_16x16_10_neon, export=1 + mov x1, x0 + ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], #64 +.irp i, 0, 1, 2, 3 + srshr v0.8h, v0.8h, #1 + srshr v1.8h, v1.8h, #1 + ld1 {v4.16b, v5.16b, v6.16b, v7.16b}, [x0], #64 + srshr v2.8h, v2.8h, #1 + srshr v3.8h, v3.8h, #1 + srshr v4.8h, v4.8h, #1 + srshr v5.8h, v5.8h, #1 + st1 {v0.16b - v3.16b}, [x1], #64 + srshr v6.8h, v6.8h, #1 +.if \i < 3 + ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], #64 +.endif + srshr v7.8h, v7.8h, #1 + st1 {v4.16b - v7.16b}, [x1], #64 +.endr + ret +endfunc + +// void ff_hevc_dequant_32x32_10_neon(int16_t *coeffs) +// 32x32 = 1024 coeffs, shift=0 +// When shift=0: output = (input + 0) >> 0 = input (identity transform) +// No operation needed - just return immediately +function ff_hevc_dequant_32x32_10_neon, export=1 + ret +endfunc + +// -------------------------------------------------------------------------- +// HEVC dequant for 12-bit depth +// +// For 12-bit: shift = 15 - 12 - log2_size = 3 - log2_size +// +// Block size | log2_size | shift | operation +// 4x4 | 2 | 1 | srshr #1 (shift right) +// 8x8 | 3 | 0 | no-op (identity) +// 16x16 | 4 | -1 | shl #1 (shift left) +// 32x32 | 5 | -2 | shl #2 (shift left) +// -------------------------------------------------------------------------- + +// void ff_hevc_dequant_4x4_12_neon(int16_t *coeffs) +// 4x4 = 16 coeffs, shift=1 +function ff_hevc_dequant_4x4_12_neon, export=1 + ldp q0, q1, [x0] + srshr v0.8h, v0.8h, #1 + srshr v1.8h, v1.8h, #1 + stp q0, q1, [x0] + ret +endfunc + +// void ff_hevc_dequant_8x8_12_neon(int16_t *coeffs) +// 8x8 = 64 coeffs, shift=0 +// When shift=0: output = input (identity transform) +// No operation needed - just return immediately +function ff_hevc_dequant_8x8_12_neon, export=1 + ret +endfunc + +// void ff_hevc_dequant_16x16_12_neon(int16_t *coeffs) +// 16x16 = 256 coeffs, shift=-1 (left shift by 1) +// Pipelined implementation: interleave load/compute/store to hide memory latency +// Uses .irp macro to unroll 4 iterations, processing 64 coeffs per iteration +// x0 = load pointer, x1 = store pointer (both advance through the buffer) +function ff_hevc_dequant_16x16_12_neon, export=1 + mov x1, x0 + ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], #64 +.irp i, 0, 1, 2, 3 + shl v0.8h, v0.8h, #1 + shl v1.8h, v1.8h, #1 + ld1 {v4.16b, v5.16b, v6.16b, v7.16b}, [x0], #64 + shl v2.8h, v2.8h, #1 + shl v3.8h, v3.8h, #1 + shl v4.8h, v4.8h, #1 + shl v5.8h, v5.8h, #1 + st1 {v0.16b - v3.16b}, [x1], #64 + shl v6.8h, v6.8h, #1 +.if \i < 3 + ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], #64 +.endif + shl v7.8h, v7.8h, #1 + st1 {v4.16b - v7.16b}, [x1], #64 +.endr + ret +endfunc + +// void ff_hevc_dequant_32x32_12_neon(int16_t *coeffs) +// 32x32 = 1024 coeffs, shift=-2 (left shift by 2) +// Process 128 coeffs per iteration (8 iterations) +// Using pipelined load/compute/store for better performance +function ff_hevc_dequant_32x32_12_neon, export=1 + mov x2, #8 +1: + // Group A: q0-q3 (64 bytes / 32 coeffs) + ldp q0, q1, [x0] + ldp q2, q3, [x0, #32] + // Group B: q4-q7 (64 bytes / 32 coeffs) + ldp q4, q5, [x0, #64] + ldp q6, q7, [x0, #96] + subs x2, x2, #1 // Decrement loop counter early for better pipelining + + // Calc Group A (shift left by 2) + shl v0.8h, v0.8h, #2 + shl v1.8h, v1.8h, #2 + shl v2.8h, v2.8h, #2 + shl v3.8h, v3.8h, #2 + + // Group C: q16-q19 (64 bytes / 32 coeffs) + ldp q16, q17, [x0, #128] + ldp q18, q19, [x0, #160] + + // Calc Group B + shl v4.8h, v4.8h, #2 + shl v5.8h, v5.8h, #2 + shl v6.8h, v6.8h, #2 + shl v7.8h, v7.8h, #2 + + // Store Group A + stp q0, q1, [x0] + stp q2, q3, [x0, #32] + + // Group D: q20-q23 (64 bytes / 32 coeffs) + ldp q20, q21, [x0, #192] + ldp q22, q23, [x0, #224] + + // Calc Group C + shl v16.8h, v16.8h, #2 + shl v17.8h, v17.8h, #2 + shl v18.8h, v18.8h, #2 + shl v19.8h, v19.8h, #2 + + // Store Group B + stp q4, q5, [x0, #64] + stp q6, q7, [x0, #96] + + // Calc Group D + shl v20.8h, v20.8h, #2 + shl v21.8h, v21.8h, #2 + shl v22.8h, v22.8h, #2 + shl v23.8h, v23.8h, #2 + + // Store Group C + stp q16, q17, [x0, #128] + stp q18, q19, [x0, #160] + + // Store Group D + stp q20, q21, [x0, #192] + stp q22, q23, [x0, #224] + + add x0, x0, #256 + b.ne 1b + ret +endfunc diff --git a/libavcodec/aarch64/hevcdsp_idct_neon.S b/libavcodec/aarch64/hevcdsp_idct_neon.S index 3cac6e6db..954ce2407 100644 --- a/libavcodec/aarch64/hevcdsp_idct_neon.S +++ b/libavcodec/aarch64/hevcdsp_idct_neon.S @@ -888,51 +888,65 @@ function ff_hevc_transform_luma_4x4_neon_8, export=1 ret endfunc +.macro idct_8x8_dc_store offset +.irp i, 0x0, 0x20, 0x40, 0x60 + stp q0, q0, [x0, #(\offset + \i)] +.endr +.endm + +.macro idct_16x16_dc_store +.irp index, 0x0, 0x80, 0x100, 0x180 + idct_8x8_dc_store offset=\index +.endr +.endm + // void ff_hevc_idct_NxN_dc_DEPTH_neon(int16_t *coeffs) -.macro idct_dc size, bitdepth -function ff_hevc_idct_\size\()x\size\()_dc_\bitdepth\()_neon, export=1 - ld1r {v4.8h}, [x0] - srshr v4.8h, v4.8h, #1 - srshr v0.8h, v4.8h, #(14 - \bitdepth) - srshr v1.8h, v4.8h, #(14 - \bitdepth) -.if \size > 4 - srshr v2.8h, v4.8h, #(14 - \bitdepth) - srshr v3.8h, v4.8h, #(14 - \bitdepth) -.if \size > 16 /* dc 32x32 */ - mov x2, #4 +.macro idct_dc size +function ff_hevc_idct_\size\()x\size\()_dc_10_neon, export=1 + ldrsh w1, [x0] + add w1, w1, #1 + asr w1, w1, #1 + add w1, w1, #(1 << (13 - 10)) + asr w1, w1, #(14 - 10) + b 2f +endfunc + +function ff_hevc_idct_\size\()x\size\()_dc_12_neon, export=1 + ldrsh w1, [x0] + add w1, w1, #1 + asr w1, w1, #1 + add w1, w1, #(1 << (13 - 12)) + asr w1, w1, #(14 - 12) + b 2f +endfunc + +function ff_hevc_idct_\size\()x\size\()_dc_8_neon, export=1 + ldrsh w1, [x0] + add w1, w1, #1 + asr w1, w1, #1 + add w1, w1, #(1 << (13 - 8)) + asr w1, w1, #(14 - 8) +2: + dup v0.8h, w1 +.if \size < 8 + stp q0, q0, [x0] +.elseif \size < 16 + idct_8x8_dc_store 0x0 +.elseif \size < 32 + idct_16x16_dc_store +.else + add x2, x0, #(32 * 32 * 2) 1: - subs x2, x2, #1 -.endif - add x12, x0, #64 - mov x13, #128 -.if \size > 8 /* dc 16x16 */ - st1 {v0.8h-v3.8h}, [x0], x13 - st1 {v0.8h-v3.8h}, [x12], x13 - st1 {v0.8h-v3.8h}, [x0], x13 - st1 {v0.8h-v3.8h}, [x12], x13 - st1 {v0.8h-v3.8h}, [x0], x13 - st1 {v0.8h-v3.8h}, [x12], x13 -.endif /* dc 8x8 */ - st1 {v0.8h-v3.8h}, [x0], x13 - st1 {v0.8h-v3.8h}, [x12], x13 -.if \size > 16 /* dc 32x32 */ - bne 1b -.endif -.else /* dc 4x4 */ - st1 {v0.8h-v1.8h}, [x0] + idct_16x16_dc_store + add x0, x0, #(16 * 16 * 2) + cmp x0, x2 + b.lt 1b .endif ret endfunc .endm -idct_dc 4, 8 -idct_dc 4, 10 - -idct_dc 8, 8 -idct_dc 8, 10 - -idct_dc 16, 8 -idct_dc 16, 10 - -idct_dc 32, 8 -idct_dc 32, 10 +idct_dc 4 +idct_dc 8 +idct_dc 16 +idct_dc 32 diff --git a/libavcodec/aarch64/hevcdsp_init_aarch64.c b/libavcodec/aarch64/hevcdsp_init_aarch64.c index 386d7c59c..8ff7f632a 100644 --- a/libavcodec/aarch64/hevcdsp_init_aarch64.c +++ b/libavcodec/aarch64/hevcdsp_init_aarch64.c @@ -22,6 +22,7 @@ #include #include "libavutil/attributes.h" +#include "libavutil/avassert.h" #include "libavutil/cpu.h" #include "libavutil/aarch64/cpu.h" #include "libavcodec/aarch64/h26x/dsp.h" @@ -91,8 +92,60 @@ void ff_hevc_idct_4x4_dc_10_neon(int16_t *coeffs); void ff_hevc_idct_8x8_dc_10_neon(int16_t *coeffs); void ff_hevc_idct_16x16_dc_10_neon(int16_t *coeffs); void ff_hevc_idct_32x32_dc_10_neon(int16_t *coeffs); +void ff_hevc_idct_4x4_dc_12_neon(int16_t *coeffs); +void ff_hevc_idct_8x8_dc_12_neon(int16_t *coeffs); +void ff_hevc_idct_16x16_dc_12_neon(int16_t *coeffs); +void ff_hevc_idct_32x32_dc_12_neon(int16_t *coeffs); void ff_hevc_transform_luma_4x4_neon_8(int16_t *coeffs); +void ff_hevc_dequant_4x4_8_neon(int16_t *coeffs); +void ff_hevc_dequant_8x8_8_neon(int16_t *coeffs); +void ff_hevc_dequant_16x16_8_neon(int16_t *coeffs); +void ff_hevc_dequant_32x32_8_neon(int16_t *coeffs); + +void ff_hevc_dequant_4x4_10_neon(int16_t *coeffs); +void ff_hevc_dequant_8x8_10_neon(int16_t *coeffs); +void ff_hevc_dequant_16x16_10_neon(int16_t *coeffs); +void ff_hevc_dequant_32x32_10_neon(int16_t *coeffs); + +void ff_hevc_dequant_4x4_12_neon(int16_t *coeffs); +void ff_hevc_dequant_8x8_12_neon(int16_t *coeffs); +void ff_hevc_dequant_16x16_12_neon(int16_t *coeffs); +void ff_hevc_dequant_32x32_12_neon(int16_t *coeffs); + +static void hevc_dequant_8_neon(int16_t *coeffs, int16_t log2_size) +{ + switch (log2_size) { + case 2: ff_hevc_dequant_4x4_8_neon(coeffs); break; + case 3: ff_hevc_dequant_8x8_8_neon(coeffs); break; + case 4: ff_hevc_dequant_16x16_8_neon(coeffs); break; + case 5: ff_hevc_dequant_32x32_8_neon(coeffs); break; + default: av_unreachable("log2_size must be 2, 3, 4 or 5"); + } +} + +static void hevc_dequant_10_neon(int16_t *coeffs, int16_t log2_size) +{ + switch (log2_size) { + case 2: ff_hevc_dequant_4x4_10_neon(coeffs); break; + case 3: ff_hevc_dequant_8x8_10_neon(coeffs); break; + case 4: ff_hevc_dequant_16x16_10_neon(coeffs); break; + case 5: ff_hevc_dequant_32x32_10_neon(coeffs); break; + default: av_unreachable("log2_size must be 2, 3, 4 or 5"); + } +} + +static void hevc_dequant_12_neon(int16_t *coeffs, int16_t log2_size) +{ + switch (log2_size) { + case 2: ff_hevc_dequant_4x4_12_neon(coeffs); break; + case 3: ff_hevc_dequant_8x8_12_neon(coeffs); break; + case 4: ff_hevc_dequant_16x16_12_neon(coeffs); break; + case 5: ff_hevc_dequant_32x32_12_neon(coeffs); break; + default: av_unreachable("log2_size must be 2, 3, 4 or 5"); + } +} + #define NEON8_FNASSIGN(member, v, h, fn, ext) \ member[1][v][h] = ff_hevc_put_hevc_##fn##4_8_neon##ext; \ member[2][v][h] = ff_hevc_put_hevc_##fn##6_8_neon##ext; \ @@ -130,6 +183,17 @@ void ff_hevc_transform_luma_4x4_neon_8(int16_t *coeffs); member[7][v][h] = ff_hevc_put_hevc_##fn##32_8_neon##ext; \ member[9][v][h] = ff_hevc_put_hevc_##fn##64_8_neon##ext; +#define NEON8_FNASSIGN_PARTIAL_6(member, v, h, fn, ext) \ + member[1][v][h] = ff_hevc_put_hevc_##fn##4_8_neon##ext; \ + member[2][v][h] = ff_hevc_put_hevc_##fn##6_8_neon##ext; \ + member[3][v][h] = ff_hevc_put_hevc_##fn##8_8_neon##ext; \ + member[4][v][h] = ff_hevc_put_hevc_##fn##12_8_neon##ext; \ + member[5][v][h] = ff_hevc_put_hevc_##fn##16_8_neon##ext; \ + member[6][v][h] = ff_hevc_put_hevc_##fn##24_8_neon##ext; \ + member[7][v][h] = ff_hevc_put_hevc_##fn##32_8_neon##ext; \ + member[8][v][h] = ff_hevc_put_hevc_##fn##24_8_neon##ext; \ + member[9][v][h] = ff_hevc_put_hevc_##fn##32_8_neon##ext; + av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth) { int cpu_flags = av_get_cpu_flags(); @@ -153,11 +217,12 @@ av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth) c->idct_dc[2] = ff_hevc_idct_16x16_dc_8_neon; c->idct_dc[3] = ff_hevc_idct_32x32_dc_8_neon; c->transform_4x4_luma = ff_hevc_transform_luma_4x4_neon_8; - c->sao_band_filter[0] = + c->dequant = hevc_dequant_8_neon; + c->sao_band_filter[0] = ff_h26x_sao_band_filter_8x8_8_neon; c->sao_band_filter[1] = c->sao_band_filter[2] = c->sao_band_filter[3] = - c->sao_band_filter[4] = ff_h26x_sao_band_filter_8x8_8_neon; + c->sao_band_filter[4] = ff_h26x_sao_band_filter_16x16_8_neon; c->sao_edge_filter[0] = ff_hevc_sao_edge_filter_8x8_8_neon; c->sao_edge_filter[1] = c->sao_edge_filter[2] = @@ -200,6 +265,8 @@ av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth) NEON8_FNASSIGN(c->put_hevc_epel_bi, 1, 0, epel_bi_v,); NEON8_FNASSIGN(c->put_hevc_qpel_bi, 0, 0, pel_bi_pixels,); NEON8_FNASSIGN(c->put_hevc_qpel_bi, 1, 0, qpel_bi_v,); + NEON8_FNASSIGN_PARTIAL_6(c->put_hevc_qpel_bi_w, 0, 0, pel_bi_w_pixels,); + NEON8_FNASSIGN_PARTIAL_6(c->put_hevc_epel_bi_w, 0, 0, pel_bi_w_pixels,); NEON8_FNASSIGN(c->put_hevc_epel_uni, 0, 0, pel_uni_pixels,); NEON8_FNASSIGN(c->put_hevc_epel_uni, 1, 0, epel_uni_v,); NEON8_FNASSIGN(c->put_hevc_qpel_uni, 0, 0, pel_uni_pixels,); @@ -257,6 +324,7 @@ av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth) c->idct_dc[1] = ff_hevc_idct_8x8_dc_10_neon; c->idct_dc[2] = ff_hevc_idct_16x16_dc_10_neon; c->idct_dc[3] = ff_hevc_idct_32x32_dc_10_neon; + c->dequant = hevc_dequant_10_neon; } if (bit_depth == 12) { c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_neon; @@ -267,5 +335,10 @@ av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth) c->add_residual[1] = ff_hevc_add_residual_8x8_12_neon; c->add_residual[2] = ff_hevc_add_residual_16x16_12_neon; c->add_residual[3] = ff_hevc_add_residual_32x32_12_neon; + c->idct_dc[0] = ff_hevc_idct_4x4_dc_12_neon; + c->idct_dc[1] = ff_hevc_idct_8x8_dc_12_neon; + c->idct_dc[2] = ff_hevc_idct_16x16_dc_12_neon; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_12_neon; + c->dequant = hevc_dequant_12_neon; } } diff --git a/libavcodec/aarch64/huffyuvdsp_init_aarch64.c b/libavcodec/aarch64/huffyuvdsp_init_aarch64.c new file mode 100644 index 000000000..210c58589 --- /dev/null +++ b/libavcodec/aarch64/huffyuvdsp_init_aarch64.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 + * + * 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/cpu.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/huffyuvdsp.h" + +void ff_add_int16_neon(uint16_t *dst, const uint16_t *src, unsigned mask, int w); + +av_cold void ff_huffyuvdsp_init_aarch64(HuffYUVDSPContext *c, enum AVPixelFormat pix_fmt) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + c->add_int16 = ff_add_int16_neon; + } +} diff --git a/libavcodec/aarch64/huffyuvdsp_neon.S b/libavcodec/aarch64/huffyuvdsp_neon.S new file mode 100644 index 000000000..4485777a7 --- /dev/null +++ b/libavcodec/aarch64/huffyuvdsp_neon.S @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 + * + * 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/aarch64/asm.S" + +// Add int16 array with masking +// On entry: +// x0 -> destination array (uint16_t*) +// x1 -> source array (const uint16_t*) +// w2 = mask value +// w3 = number of elements +function ff_add_int16_neon, export=1 + dup v31.8h, w2 + mov x4, x0 + + // Process 32 elements (64 bytes) if available +1: cmp w3, #32 + b.lt 2f + ld1 {v0.8h, v1.8h}, [x1], #32 + ld1 {v2.8h, v3.8h}, [x0], #32 + sub w3, w3, #32 + add v0.8h, v0.8h, v2.8h + ld1 {v4.8h, v5.8h}, [x1], #32 + add v1.8h, v1.8h, v3.8h + ld1 {v6.8h, v7.8h}, [x0], #32 + and v0.16b, v0.16b, v31.16b + and v1.16b, v1.16b, v31.16b + + add v4.8h, v4.8h, v6.8h + add v5.8h, v5.8h, v7.8h + st1 {v0.8h, v1.8h}, [x4], #32 + and v4.16b, v4.16b, v31.16b + and v5.16b, v5.16b, v31.16b + st1 {v4.8h, v5.8h}, [x4], #32 + b 1b + + // Process 8 elements (16 bytes) if available +2: cmp w3, #8 + b.lt 3f + ld1 {v0.8h}, [x1], #16 + ld1 {v1.8h}, [x0] + sub w3, w3, #8 + add v0.8h, v0.8h, v1.8h + and v0.16b, v0.16b, v31.16b + st1 {v0.8h}, [x0], #16 + b 2b + + // Scalar path for remaining elements +3: cbz w3, 4f + ldrh w5, [x1], #2 + ldrh w6, [x0] + add w5, w5, w6 + and w5, w5, w2 + strh w5, [x0], #2 + subs w3, w3, #1 + b.ne 3b + +4: ret +endfunc diff --git a/libavcodec/aarch64/me_cmp_init_aarch64.c b/libavcodec/aarch64/me_cmp_init_aarch64.c index fa2724403..dac667688 100644 --- a/libavcodec/aarch64/me_cmp_init_aarch64.c +++ b/libavcodec/aarch64/me_cmp_init_aarch64.c @@ -21,66 +21,66 @@ #include "config.h" #include "libavutil/attributes.h" #include "libavutil/aarch64/cpu.h" -#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideoenc.h" -int ff_pix_abs16_neon(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs16_neon(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_pix_abs16_xy2_neon(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs16_xy2_neon(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_pix_abs16_x2_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_x2_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_y2_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_y2_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_neon(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs8_neon(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int sse16_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int sse16_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int sse8_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int sse8_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int sse4_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int sse4_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int vsad16_neon(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int vsad16_neon(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int vsad_intra16_neon(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, +int vsad_intra16_neon(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h) ; -int vsad_intra8_neon(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, +int vsad_intra8_neon(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h) ; -int vsse16_neon(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int vsse16_neon(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int vsse_intra16_neon(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, +int vsse_intra16_neon(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); int nsse16_neon(int multiplier, const uint8_t *s, const uint8_t *s2, ptrdiff_t stride, int h); -int nsse16_neon_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int nsse16_neon_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int pix_median_abs16_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int pix_median_abs16_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int pix_median_abs8_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int pix_median_abs8_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_x2_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_x2_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_y2_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_y2_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_xy2_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_xy2_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); int nsse8_neon(int multiplier, const uint8_t *s, const uint8_t *s2, ptrdiff_t stride, int h); -int nsse8_neon_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int nsse8_neon_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int vsse8_neon(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int vsse8_neon(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int vsse_intra8_neon(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, +int vsse_intra8_neon(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); #if HAVE_DOTPROD -int sse16_neon_dotprod(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int sse16_neon_dotprod(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int vsse_intra16_neon_dotprod(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int vsse_intra16_neon_dotprod(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); #endif @@ -129,20 +129,20 @@ av_cold void ff_me_cmp_init_aarch64(MECmpContext *c, AVCodecContext *avctx) #endif } -int nsse16_neon_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int nsse16_neon_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { if (c) - return nsse16_neon(c->avctx->nsse_weight, s1, s2, stride, h); + return nsse16_neon(c->c.avctx->nsse_weight, s1, s2, stride, h); else return nsse16_neon(8, s1, s2, stride, h); } -int nsse8_neon_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int nsse8_neon_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { if (c) - return nsse8_neon(c->avctx->nsse_weight, s1, s2, stride, h); + return nsse8_neon(c->c.avctx->nsse_weight, s1, s2, stride, h); else return nsse8_neon(8, s1, s2, stride, h); } diff --git a/libavcodec/aarch64/me_cmp_neon.S b/libavcodec/aarch64/me_cmp_neon.S index 20e3b33a8..efa28a77a 100644 --- a/libavcodec/aarch64/me_cmp_neon.S +++ b/libavcodec/aarch64/me_cmp_neon.S @@ -534,7 +534,7 @@ function ff_pix_abs16_y2_neon, export=1 ld1 {v2.16b}, [x2], x3 // Load pix3 for first iteration ld1 {v0.16b}, [x1], x3 // Load pix1 for first iteration urhadd v30.16b, v1.16b, v2.16b // Rounding halving add, first iteration - ld1 {v5.16b}, [x2], x3 // Load pix3 for second iteartion + ld1 {v5.16b}, [x2], x3 // Load pix3 for second iteration uabal v29.8h, v0.8b, v30.8b // Absolute difference of lower half, first iteration uabal2 v28.8h, v0.16b, v30.16b // Absolute difference of upper half, first iteration ld1 {v3.16b}, [x1], x3 // Load pix1 for second iteration @@ -606,7 +606,7 @@ function sse16_neon, export=1 uabd v27.16b, v2.16b, v3.16b // Absolute difference, second iteration uadalp v17.4s, v29.8h // Pairwise add, first iteration ld1 {v4.16b}, [x1], x3 // Load pix1 for third iteration - umull v26.8h, v27.8b, v27.8b // Mulitply lower half, second iteration + umull v26.8h, v27.8b, v27.8b // Multiply lower half, second iteration umull2 v25.8h, v27.16b, v27.16b // Multiply upper half, second iteration ld1 {v5.16b}, [x2], x3 // Load pix2 for third iteration uadalp v17.4s, v26.8h // Pairwise add and accumulate, second iteration @@ -616,7 +616,7 @@ function sse16_neon, export=1 umull v23.8h, v24.8b, v24.8b // Multiply lower half, third iteration umull2 v22.8h, v24.16b, v24.16b // Multiply upper half, third iteration uadalp v17.4s, v23.8h // Pairwise add and accumulate, third iteration - ld1 {v7.16b}, [x2], x3 // Load pix2 for fouth iteration + ld1 {v7.16b}, [x2], x3 // Load pix2 for fourth iteration uadalp v17.4s, v22.8h // Pairwise add and accumulate, third iteration uabd v21.16b, v6.16b, v7.16b // Absolute difference, fourth iteration uadalp v17.4s, v28.8h // Pairwise add and accumulate, first iteration @@ -748,7 +748,7 @@ function sse4_neon, export=1 uabdl v28.8h, v4.8b, v5.8b // Absolute difference, third iteration umlal v16.4s, v29.4h, v29.4h // Multiply and accumulate, second iteration sub w4, w4, #4 - uabdl v27.8h, v6.8b, v7.8b // Absolue difference, fourth iteration + uabdl v27.8h, v6.8b, v7.8b // Absolute difference, fourth iteration umlal v16.4s, v28.4h, v28.4h // Multiply and accumulate, third iteration cmp w4, #4 umlal v16.4s, v27.4h, v27.4h // Multiply and accumulate, fourth iteration @@ -1593,7 +1593,7 @@ function sse16_neon_dotprod, export=1 uabd v24.16b, v4.16b, v5.16b // Absolute difference, third iteration ld1 {v6.16b}, [x1], x3 // Load pix1 for fourth iteration udot v17.4s, v24.16b, v24.16b - ld1 {v7.16b}, [x2], x3 // Load pix2 for fouth iteration + ld1 {v7.16b}, [x2], x3 // Load pix2 for fourth iteration uabd v21.16b, v6.16b, v7.16b // Absolute difference, fourth iteration sub w4, w4, #4 // h -= 4 udot v17.4s, v21.16b, v21.16b diff --git a/libavcodec/aarch64/opusdsp_neon.S b/libavcodec/aarch64/opusdsp_neon.S index 253825aa6..990fc44c7 100644 --- a/libavcodec/aarch64/opusdsp_neon.S +++ b/libavcodec/aarch64/opusdsp_neon.S @@ -55,35 +55,28 @@ endfunc function ff_opus_postfilter_neon, export=1 ld1 {v0.4s}, [x2] + sub x5, x0, w1, sxtw #2 + sub x1, x5, #8 dup v1.4s, v0.s[1] dup v2.4s, v0.s[2] dup v0.4s, v0.s[0] - add w1, w1, #2 - sub x1, x0, x1, lsl #2 - - ld1 {v3.4s}, [x1] + ld1 {v3.4s}, [x1], #16 + sub x4, x5, #4 + add x6, x5, #4 fmul v3.4s, v3.4s, v2.4s -1: add x1, x1, #4 - ld1 {v4.4s}, [x1] - add x1, x1, #4 - ld1 {v5.4s}, [x1] - add x1, x1, #4 - ld1 {v6.4s}, [x1] - add x1, x1, #4 - ld1 {v7.4s}, [x1] - +1: ld1 {v7.4s}, [x1], #16 + ld1 {v4.4s}, [x4], #16 fmla v3.4s, v7.4s, v2.4s + ld1 {v6.4s}, [x6], #16 + ld1 {v5.4s}, [x5], #16 fadd v6.4s, v6.4s, v4.4s + fmla v3.4s, v5.4s, v0.4s ld1 {v4.4s}, [x0] - fmla v4.4s, v5.4s, v0.4s - - fmul v6.4s, v6.4s, v1.4s - fadd v6.4s, v6.4s, v3.4s - - fadd v4.4s, v4.4s, v6.4s + fmla v3.4s, v6.4s, v1.4s + fadd v4.4s, v4.4s, v3.4s fmul v3.4s, v7.4s, v2.4s st1 {v4.4s}, [x0], #16 diff --git a/libavcodec/aarch64/pixblockdsp_init_aarch64.c b/libavcodec/aarch64/pixblockdsp_init_aarch64.c index e4bac722f..5f0bf477a 100644 --- a/libavcodec/aarch64/pixblockdsp_init_aarch64.c +++ b/libavcodec/aarch64/pixblockdsp_init_aarch64.c @@ -21,16 +21,14 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/aarch64/cpu.h" -#include "libavcodec/avcodec.h" #include "libavcodec/pixblockdsp.h" -void ff_get_pixels_neon(int16_t *block, const uint8_t *pixels, +void ff_get_pixels_neon(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t stride); -void ff_diff_pixels_neon(int16_t *block, const uint8_t *s1, +void ff_diff_pixels_neon(int16_t *restrict block, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride); av_cold void ff_pixblockdsp_init_aarch64(PixblockDSPContext *c, - AVCodecContext *avctx, unsigned high_bit_depth) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/aarch64/pngdsp_init.c b/libavcodec/aarch64/pngdsp_init.c new file mode 100644 index 000000000..e88814fad --- /dev/null +++ b/libavcodec/aarch64/pngdsp_init.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2026 Zhao Zhili + * + * 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 "libavutil/attributes.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/pngdsp.h" + +void ff_png_add_bytes_l2_neon(uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, int w); +void ff_png_add_paeth_prediction_neon(uint8_t *dst, const uint8_t *src, + const uint8_t *top, int w, int bpp); + +av_cold void ff_pngdsp_init_aarch64(PNGDSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + dsp->add_bytes_l2 = ff_png_add_bytes_l2_neon; + dsp->add_paeth_prediction = ff_png_add_paeth_prediction_neon; + } +} diff --git a/libavcodec/aarch64/pngdsp_neon.S b/libavcodec/aarch64/pngdsp_neon.S new file mode 100644 index 000000000..20ae602a8 --- /dev/null +++ b/libavcodec/aarch64/pngdsp_neon.S @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2026 Zhao Zhili + * + * 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/aarch64/asm.S" + +/* void ff_png_add_bytes_l2_neon(uint8_t *dst, const uint8_t *src1, + * const uint8_t *src2, int w); + * x0: dst + * x1: src1 + * x2: src2 + * w3: w + */ +function ff_png_add_bytes_l2_neon, export=1 + bic w4, w3, #63 + and w3, w3, #63 + cbz w4, 2f +1: + // 64 bytes per loop iteration + ldp q0, q1, [x1] + ldp q2, q3, [x1, #32] + subs w4, w4, #64 + ldp q4, q5, [x2] + ldp q6, q7, [x2, #32] + add x1, x1, #64 + add v0.16b, v0.16b, v4.16b + add v1.16b, v1.16b, v5.16b + add x2, x2, #64 + add v2.16b, v2.16b, v6.16b + add v3.16b, v3.16b, v7.16b + st1 {v0.16b - v3.16b}, [x0], #64 + b.ne 1b +2: + bic w4, w3, #15 + and w3, w3, #15 + cbz w4, 4f +3: + // 16 bytes per loop iteration + ld1 {v0.16b}, [x1], #16 + ld1 {v4.16b}, [x2], #16 + subs w4, w4, #16 + add v0.16b, v0.16b, v4.16b + st1 {v0.16b}, [x0], #16 + b.ne 3b +4: + cbz w3, 6f +5: + ldrb w5, [x1], #1 + ldrb w6, [x2], #1 + subs w3, w3, #1 + add w5, w5, w6 + strb w5, [x0], #1 + b.ne 5b +6: + ret +endfunc + +/* This is an iterative process where dst[n] depends on dst[n-bpp], so + * add_paeth_prediction can only process bpp bytes each time. + * + * There are three state + * 1. load: load data from memory + * 2. shift: simple shift from previous iteration + * 3. extract: extract data from registers which was loaded in state 1. + * Data is assembled by the caller. + */ +.macro add_paeth_prediction, bpp, state + // load data from memory +.ifc \state,load + ld1 {v18.16b, v19.16b, v20.16b}, [x2], x7 + ld1 {v21.16b, v22.16b, v23.16b}, [x1], x7 + mov v1.8b, v18.8b // c = top[i - bpp] + ext v2.16b, v18.16b, v19.16b, #\bpp // b = top[i] + mov v17.16b, v21.16b // src +.endif + // simple shift from previous iteration +.ifc \state,shift + mov v1.8b, v2.8b + ext v2.16b, v2.16b, v2.16b, #(\bpp) + ext v17.16b, v17.16b, v17.16b, #(\bpp) +.endif + // Only the first bpp bytes are useful. + uabd v4.8b, v2.8b, v1.8b // pa = abs(b - c) + uaddl v7.8h, v1.8b, v1.8b // 2 * c + uabd v3.8b, v0.8b, v1.8b // pb = abs(a - c) + uaddl v5.8h, v0.8b, v2.8b // a + b + + cmhs v16.8b, v3.8b, v4.8b // pb >= pa + uabd v5.8h, v5.8h, v7.8h + umin v6.8b, v4.8b, v3.8b // min(pa, pb) + uqxtn v5.8b, v5.8h + + bsl v16.8b, v0.8b, v2.8b // pb >= pa ? a : b + cmhs v6.8b, v5.8b, v6.8b // pc >= min(pa, pb) + bsl v6.8b, v16.8b, v1.8b // pc >= min ? (a or b) : c + + add v0.8b, v6.8b, v17.8b +.if \bpp == 3 || \bpp == 4 + str s0, [x0], #\bpp +.else + str d0, [x0], #\bpp +.endif +.endm + +/* void ff_png_add_paeth_prediction_neon(uint8_t *dst, const uint8_t *src, + * const uint8_t *top, int w, int bpp); + * x0: dst + * x1: src + * x2: top + * w3: w + * w4: bpp + */ +function ff_png_add_paeth_prediction_neon, export=1 + cmp w4, #3 + /* Load 48 bytes from memory in each loop. + * The number of bytes processed in each loop is (48 - bpp) + */ + mov w7, #48 + /* Overwrite 1 byte in SIMD when bpp = 3, and 2 bytes when bpp = 6. + * Let w5 = (w - 2) / (48 -bpp) * (48 -bpp), then fix the overwrite + * in loop tail. + */ + sub w5, w3, #2 + sub w7, w7, w4 // (48 - bpp) + udiv w5, w5, w7 + neg w6, w4 // -bpp + sub x2, x2, w4, uxtw // top - bpp + mul w5, w5, w7 // w5 = (w - 2) / (48 - bpp) * (48 - bpp) + sub w3, w3, w5 + cbz w5, 2f + + ldr d0, [x0, w6, sxtw] + + b.gt 40f +30: // bpp = 3 + // 15 bytes + add_paeth_prediction 3, state=load + subs w5, w5, w7 +.rept 4 + add_paeth_prediction 3, state=shift +.endr + // 15 + 15 = 30 bytes + ext v1.16b, v18.16b, v19.16b, #15 + ext v2.16b, v19.16b, v20.16b, #2 + ext v17.16b, v21.16b, v22.16b, #15 + add_paeth_prediction 3, state=extract +.rept 4 + add_paeth_prediction 3, state=shift +.endr + // 30 + 15 = 45 bytes + ext v1.16b, v19.16b, v20.16b, #14 + ext v2.16b, v20.16b, v20.16b, #1 + ext v17.16b, v22.16b, v23.16b, #14 + add_paeth_prediction 3, state=extract +.rept 4 + add_paeth_prediction 3, state=shift +.endr + b.ne 30b + b 2f + +40: // check bpp = 4 + cmp w4, #4 + b.gt 60f + // 44 bytes per loop +41: + // 16 bytes + add_paeth_prediction 4, state=load + subs w5, w5, w7 +.rept 3 + add_paeth_prediction 4, state=shift +.endr + // 16 + 16 = 32 bytes + mov v1.8b, v19.8b + ext v2.16b, v19.16b, v20.16b, #4 + mov v17.16b, v22.16b + add_paeth_prediction 4, state=extract +.rept 3 + add_paeth_prediction 4, state=shift +.endr + // 32 + 12 bytes + mov v1.8b, v20.8b + ext v2.16b, v20.16b, v20.16b, #4 + mov v17.16b, v23.16b + add_paeth_prediction 4, state=extract +.rept 2 + add_paeth_prediction 4, state=shift +.endr + b.ne 41b + b 2f + +60: // check bpp = 6 + cmp w4, #6 + b.gt 80f +61: + // process 12 bytes + add_paeth_prediction 6, state=load + add_paeth_prediction 6, state=shift + subs w5, w5, w7 + + // 12 + 12 = 24 bytes + ext v1.16b, v18.16b, v19.16b, #12 + ext v2.16b, v19.16b, v20.16b, #2 + ext v17.16b, v21.16b, v22.16b, #12 + add_paeth_prediction 6, state=extract + add_paeth_prediction 6, state=shift + // 24 + 12 = 36 bytes + ext v1.16b, v19.16b, v20.16b, #8 + ext v2.16b, v19.16b, v20.16b, #14 + ext v17.16b, v22.16b, v23.16b, #8 + add_paeth_prediction 6, state=extract + add_paeth_prediction 6, state=shift + // 36 + 6 = 42 bytes + ext v1.16b, v20.16b, v20.16b, #4 + ext v2.16b, v20.16b, v20.16b, #10 + ext v17.16b, v23.16b, v23.16b, #4 + add_paeth_prediction 6, state=extract + + b.ne 61b + b 2f + +80: // 40 bytes per loop + // 16 bytes + add_paeth_prediction 8, state=load + add_paeth_prediction 8, state=shift + subs w5, w5, w7 + + // 16 + 16 = 32 bytes + mov v1.8b, v19.8b + ext v2.16b, v19.16b, v20.16b, #8 + mov v17.16b, v22.16b + add_paeth_prediction 8, state=extract + add_paeth_prediction 8, state=shift + + // 32 + 8 = 40 bytes + mov v1.8b, v20.8b + ext v2.16b, v20.16b, v20.16b, #8 + mov v17.8b, v23.8b + add_paeth_prediction 8, state=extract + + b.ne 80b +2: + cbz w3, 8f +3: + ldrb w7, [x0, w6, sxtw] // a = dst[i - bpp] + ldrb w8, [x2, w4, uxtw] // b = top[i] + ldrb w9, [x2], #1 // c = top[i - bpp] + + sub w10, w8, w9 // p = b - c + sub w11, w7, w9 // a - c + + cmp w10, #0 + cneg w12, w10, lt // pa = abs(b - c) + cmp w11, #0 + add w14, w10, w11 + cneg w13, w11, lt // pb = abs(a - c) + cmp w14, #0 + cneg w14, w14, lt // pc = abs(a + b - 2*c) + + ldrb w16, [x1], #1 + + cmp w13, w14 // pb vs pc + csel w15, w8, w9, le // w15 = (pb <= pc) ? b : c + cmp w12, w13 // pa vs pb + ccmp w12, w14, #2, le // if pa <= pb, check pa vs pc + csel w15, w7, w15, le // p = (pa <= pb && pa <= pc) ? a : w15 + + subs w3, w3, #1 + add w15, w15, w16 + strb w15, [x0], #1 + b.ne 3b +8: + ret +endfunc diff --git a/libavcodec/aarch64/vvc/Makefile b/libavcodec/aarch64/vvc/Makefile index ed8033896..7c336bc03 100644 --- a/libavcodec/aarch64/vvc/Makefile +++ b/libavcodec/aarch64/vvc/Makefile @@ -8,3 +8,4 @@ NEON-OBJS-$(CONFIG_VVC_DECODER) += aarch64/vvc/alf.o \ aarch64/h26x/epel_neon.o \ aarch64/h26x/qpel_neon.o \ aarch64/h26x/sao_neon.o +SME2-OBJS-$(CONFIG_VVC_DECODER) += aarch64/vvc/inter_sme2.o diff --git a/libavcodec/aarch64/vvc/alf.S b/libavcodec/aarch64/vvc/alf.S index 8801b3afb..bd8317aba 100644 --- a/libavcodec/aarch64/vvc/alf.S +++ b/libavcodec/aarch64/vvc/alf.S @@ -291,3 +291,208 @@ function ff_alf_filter_chroma_kernel_10_neon, export=1 1: alf_filter_chroma_kernel 2 endfunc + +#define ALF_BLOCK_SIZE 4 +#define ALF_GRADIENT_STEP 2 +#define ALF_GRADIENT_BORDER 2 +#define ALF_NUM_DIR 4 +#define ALF_GRAD_BORDER_X2 (ALF_GRADIENT_BORDER * 2) +#define ALF_STRIDE_MUL (ALF_GRADIENT_BORDER + 1) +#define ALF_GRAD_X_VSTEP (ALF_GRADIENT_STEP * 8) +#define ALF_GSTRIDE_MUL (ALF_NUM_DIR / ALF_GRADIENT_STEP) + +// Shift right: equal to division by 2 (see ALF_GRADIENT_STEP) +#define ALF_GSTRIDE_XG_BYTES (2 * ALF_NUM_DIR / ALF_GRADIENT_STEP) + +#define ALF_GSTRIDE_SUB_BYTES (2 * ((ALF_BLOCK_SIZE + ALF_GRADIENT_BORDER * 2) / ALF_GRADIENT_STEP) * ALF_NUM_DIR) + +#define ALF_CLASS_INC (ALF_GRADIENT_BORDER / ALF_GRADIENT_STEP) +#define ALF_CLASS_END ((ALF_BLOCK_SIZE + ALF_GRADIENT_BORDER * 2) / ALF_GRADIENT_STEP) + +.macro ff_alf_classify_grad pix_size + // class_idx .req x0 + // transpose_idx .req x1 + // _src .req x2 + // _src_stride .req x3 + // width .req w4 + // height .req w5 + // vb_pos .req w6 + // gradient_tmp .req x7 + + mov w16, #ALF_STRIDE_MUL + add w5, w5, #ALF_GRAD_BORDER_X2 // h = height + ALF_GRAD_BORDER_X2 + mul x16, x3, x16 // ALF_STRIDE_MUL * stride + add w4, w4, #ALF_GRAD_BORDER_X2 // w = width + ALF_GRAD_BORDER_X2 + sub x15, x2, x16 // src -= (ALF_STRIDE_MUL * stride) + mov x17, x7 + .if \pix_size == 1 + sub x15, x15, #ALF_GRADIENT_BORDER + .else + sub x15, x15, #ALF_GRAD_BORDER_X2 + .endif + mov w8, #0 // y loop: y = 0 +1: + add x16, x8, #1 + mul x16, x16, x3 + madd x10, x8, x3, x15 // s0 = src + y * stride + add x14, x16, x3 + add x11, x15, x16 // s1 + add x16, x14, x3 + add x12, x15, x14 // s2 + add x13, x15, x16 // s3 + + // if (y == vb_pos): s3 = s2 + cmp w8, w6 + add w16, w6, #ALF_GRADIENT_BORDER + csel x13, x12, x13, eq + // if (y == vb_pos + 2): s0 = s1 + cmp w8, w16 + csel x10, x11, x10, eq + + .if \pix_size == 1 + sub x10, x10, #1 // s0-1 + sub x11, x11, #2 + sub x12, x12, #2 + .else + sub x10, x10, #2 // s0-1 + sub x11, x11, #4 + sub x12, x12, #4 + .endif + + // x loop + mov w9, #0 + b 11f +2: + // Store operation starts from the second cycle + st2 {v4.8h, v5.8h}, [x17], #32 +11: + .if \pix_size == 1 + // Load 8 pixels: s0 & s1+2 + mov x16, #1 + mov x14, #7 + ld1 {v0.8b}, [x10], x16 // s0-1 + ld1 {v2.8b}, [x13], x16 // s3 + ld1 {v1.8b}, [x10], x14 // s0 + ld1 {v3.8b}, [x13], x14 // s3+1 + uxtl v16.8h, v0.8b + uxtl v20.8h, v1.8b + uxtl v28.8h, v2.8b + uxtl v19.8h, v3.8b + + mov x16, #2 + mov x14, #4 + ld1 {v0.8b}, [x11], x16 // s1-2 + ld1 {v3.8b}, [x12], x16 // s2-2 + ld1 {v1.8b}, [x11], x16 // s1 + ld1 {v4.8b}, [x12], x16 // s2 + ld1 {v2.8b}, [x11], x14 // s1+2 + ld1 {v5.8b}, [x12], x14 // s2+2 + uxtl v17.8h, v0.8b + uxtl v22.8h, v1.8b + uxtl v26.8h, v2.8b + uxtl v18.8h, v3.8b + uxtl v24.8h, v4.8b + uxtl v27.8h, v5.8b + .else + mov x16, #2 + mov x14, #14 + ld1 {v16.8h}, [x10], x16 // s0-1 + ld1 {v28.8h}, [x13], x16 // s3 + ld1 {v20.8h}, [x10], x14 // s0 + ld1 {v19.8h}, [x13], x14 // s3+1 + + mov x16, #4 + mov x14, #8 + ld1 {v17.8h}, [x11], x16 // s1-2 + ld1 {v18.8h}, [x12], x16 // s2-2 + ld1 {v22.8h}, [x11], x16 // s1 + ld1 {v24.8h}, [x12], x16 // s2 + ld1 {v26.8h}, [x11], x14 // s1+2 + ld1 {v27.8h}, [x12], x14 // s2+2 + .endif + + // Grad: Vertical & D0 (interleaved) + trn1 v21.8h, v20.8h, v16.8h // first abs: operand 1 + rev32 v23.8h, v22.8h // second abs: operand 1 + trn2 v29.8h, v28.8h, v19.8h // second abs: operand 2 + trn1 v30.8h, v22.8h, v22.8h + trn2 v31.8h, v24.8h, v24.8h + add v30.8h, v30.8h, v30.8h + add v31.8h, v31.8h, v31.8h + sub v0.8h, v30.8h, v21.8h + sub v1.8h, v31.8h, v23.8h + sabd v4.8h, v0.8h, v24.8h + + // Grad: Horizontal & D1 (interleaved) + trn2 v21.8h, v17.8h, v20.8h // first abs: operand 1 + saba v4.8h, v1.8h, v29.8h + trn2 v23.8h, v22.8h, v18.8h // first abs: operand 2 + trn1 v25.8h, v24.8h, v26.8h // second abs: operand 1 + trn1 v29.8h, v27.8h, v28.8h // second abs: operand 2 + sub v0.8h, v30.8h, v21.8h + sub v1.8h, v31.8h, v25.8h + add w9, w9, #8 // x += 8 + sabd v5.8h, v0.8h, v23.8h + cmp w9, w4 + saba v5.8h, v1.8h, v29.8h + b.lt 2b + + add w8, w8, #ALF_GRADIENT_STEP // y += ALF_GRADIENT_STEP + // 8 pixels -> 4 cycles of generic + // 4 pixels -> paddings => half needs to be saved + st2 {v4.4h, v5.4h}, [x17], #16 + cmp w8, w5 + b.lt 1b + ret +.endm + +.macro ff_alf_classify_sum + ld1 {v0.8h, v1.8h, v2.8h}, [x2], x3 + uaddw v16.4s, v16.4s, v0.4h + uaddw v17.4s, v17.4s, v1.4h + uaddw v18.4s, v18.4s, v2.4h + uaddw2 v16.4s, v16.4s, v0.8h + uaddw2 v17.4s, v17.4s, v1.8h + uaddw2 v18.4s, v18.4s, v2.8h +.endm + +function ff_alf_classify_sum_neon, export=1 + // sum0 .req x0 + // sum1 .req x1 + // grad .req x2 + // gshift .req w3 + // steps .req w4 + lsl w3, w3, #1 + cmp w4, #4 + add w3, w3, #32 + + ld1 {v0.8h, v1.8h, v2.8h}, [x2], x3 + uxtl v16.4s, v0.4h + uxtl v17.4s, v1.4h + uxtl v18.4s, v2.4h + uaddw2 v16.4s, v16.4s, v0.8h + uaddw2 v17.4s, v17.4s, v1.8h + uaddw2 v18.4s, v18.4s, v2.8h + ff_alf_classify_sum + ff_alf_classify_sum + + blt 60f + ff_alf_classify_sum +60: + add v16.4s, v16.4s, v17.4s + add v18.4s, v18.4s, v17.4s + st1 {v16.4s}, [x0] + st1 {v18.4s}, [x1] + ret +endfunc + +function ff_alf_classify_grad_8_neon, export=1 + ff_alf_classify_grad 1 +endfunc + +function ff_alf_classify_grad_10_neon, export=1 +endfunc + +function ff_alf_classify_grad_12_neon, export=1 + ff_alf_classify_grad 2 +endfunc diff --git a/libavcodec/aarch64/vvc/alf_template.c b/libavcodec/aarch64/vvc/alf_template.c index 41f7bf899..03bf9056b 100644 --- a/libavcodec/aarch64/vvc/alf_template.c +++ b/libavcodec/aarch64/vvc/alf_template.c @@ -155,3 +155,120 @@ static void FUNC2(alf_filter_chroma, BIT_DEPTH, _neon)(uint8_t *_dst, } } } + +#define ALF_DIR_VERT 0 +#define ALF_DIR_HORZ 1 +#define ALF_DIR_DIGA0 2 +#define ALF_DIR_DIGA1 3 + +static void FUNC(alf_get_idx)(int *class_idx, int *transpose_idx, const int *sum, const int ac) +{ + static const int arg_var[] = {0, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4 }; + + int hv0, hv1, dir_hv, d0, d1, dir_d, hvd1, hvd0, sum_hv, dir1; + + dir_hv = sum[ALF_DIR_VERT] <= sum[ALF_DIR_HORZ]; + hv1 = FFMAX(sum[ALF_DIR_VERT], sum[ALF_DIR_HORZ]); + hv0 = FFMIN(sum[ALF_DIR_VERT], sum[ALF_DIR_HORZ]); + + dir_d = sum[ALF_DIR_DIGA0] <= sum[ALF_DIR_DIGA1]; + d1 = FFMAX(sum[ALF_DIR_DIGA0], sum[ALF_DIR_DIGA1]); + d0 = FFMIN(sum[ALF_DIR_DIGA0], sum[ALF_DIR_DIGA1]); + + //promote to avoid overflow + dir1 = (uint64_t)d1 * hv0 <= (uint64_t)hv1 * d0; + hvd1 = dir1 ? hv1 : d1; + hvd0 = dir1 ? hv0 : d0; + + sum_hv = sum[ALF_DIR_HORZ] + sum[ALF_DIR_VERT]; + *class_idx = arg_var[av_clip_uintp2(sum_hv * ac >> (BIT_DEPTH - 1), 4)]; + if (hvd1 * 2 > 9 * hvd0) + *class_idx += ((dir1 << 1) + 2) * 5; + else if (hvd1 > 2 * hvd0) + *class_idx += ((dir1 << 1) + 1) * 5; + + *transpose_idx = dir_d * 2 + dir_hv; +} + +static void FUNC(alf_classify)(int *class_idx, int *transpose_idx, + const uint8_t *_src, const ptrdiff_t _src_stride, const int width, const int height, + const int vb_pos, int16_t *gradient_tmp) +{ + int16_t *grad; + + const int w = width + ALF_GRADIENT_BORDER * 2; + const int size = (ALF_BLOCK_SIZE + ALF_GRADIENT_BORDER * 2) / ALF_GRADIENT_STEP; + const int gstride = (w / ALF_GRADIENT_STEP) * ALF_NUM_DIR; + const int gshift = gstride - size * ALF_NUM_DIR; + + for (int y = 0; y < height ; y += ALF_BLOCK_SIZE ) { + int start = 0; + int end = (ALF_BLOCK_SIZE + ALF_GRADIENT_BORDER * 2) / ALF_GRADIENT_STEP; + int ac = 2; + if (y + ALF_BLOCK_SIZE == vb_pos) { + end -= ALF_GRADIENT_BORDER / ALF_GRADIENT_STEP; + ac = 3; + } else if (y == vb_pos) { + start += ALF_GRADIENT_BORDER / ALF_GRADIENT_STEP; + ac = 3; + } + for (int x = 0; x < width; x += (2*ALF_BLOCK_SIZE)) { + const int xg = x / ALF_GRADIENT_STEP; + const int yg = y / ALF_GRADIENT_STEP; + int sum0[ALF_NUM_DIR]; + int sum1[ALF_NUM_DIR]; + grad = gradient_tmp + (yg + start) * gstride + xg * ALF_NUM_DIR; + ff_alf_classify_sum_neon(sum0, sum1, grad, gshift, end-start); + FUNC(alf_get_idx)(class_idx, transpose_idx, sum0, ac); + class_idx++; + transpose_idx++; + FUNC(alf_get_idx)(class_idx, transpose_idx, sum1, ac); + class_idx++; + transpose_idx++; + } + } + +} + +void FUNC2(ff_alf_classify_grad, BIT_DEPTH, _neon)(int *class_idx, int *transpose_idx, + const uint8_t *_src, const ptrdiff_t _src_stride, const int width, const int height, + const int vb_pos, int16_t *gradient_tmp); + +static void FUNC2(alf_classify, BIT_DEPTH, _neon)(int *class_idx, int *transpose_idx, + const uint8_t *_src, const ptrdiff_t _src_stride, const int width, const int height, + const int vb_pos, int *gradient_tmp) +{ + FUNC2(ff_alf_classify_grad, BIT_DEPTH, _neon)(class_idx, transpose_idx, _src, _src_stride, width, height, vb_pos, (int16_t*)gradient_tmp); + FUNC(alf_classify)(class_idx, transpose_idx, _src, _src_stride, width, height, vb_pos, (int16_t*)gradient_tmp); +} + + +void FUNC2(ff_vvc_alf_filter_luma, BIT_DEPTH, _sme2)(uint8_t *dst, const uint8_t *src, const uint64_t strides, + const uint64_t dims, const int16_t *filter, const int16_t *clip, + const int vb_pos); + +#define ALF_ALIGN_BY_4(x) (4*((x - 1) >> 2u)+4) + +static void FUNC2(alf_filter_luma, BIT_DEPTH, _sme2)(uint8_t *_dst, + ptrdiff_t dst_stride, + const uint8_t *_src, + ptrdiff_t src_stride, + const int width, const int height, + const int16_t *filter, + const int16_t *clip, + const int vb_pos) +{ + if ((width >= 16) && (height >= 16)) { + // If compiled without support for SME2 or SME-I16I64, we never assign + // the function pointer anyway, but make sure we don't produce a + // reference to the function which does not exist. +#if HAVE_SME2 && HAVE_SME_I16I64 + int aligned_width = ALF_ALIGN_BY_4(width); // align width by 4 + uint64_t dims = ((uint64_t)height << 32u) | (uint64_t)aligned_width; + uint64_t strides = ((uint64_t)src_stride << 32u) | (uint64_t)dst_stride; + FUNC2(ff_vvc_alf_filter_luma, BIT_DEPTH, _sme2)(_dst, _src, strides, dims, filter, clip, vb_pos); +#endif + } else { + FUNC2(alf_filter_luma, BIT_DEPTH, _neon)(_dst, dst_stride, _src, src_stride, width, height, filter, clip, vb_pos); + } +} diff --git a/libavcodec/aarch64/vvc/dsp_init.c b/libavcodec/aarch64/vvc/dsp_init.c index ad767d17e..956fa0779 100644 --- a/libavcodec/aarch64/vvc/dsp_init.c +++ b/libavcodec/aarch64/vvc/dsp_init.c @@ -27,6 +27,54 @@ #include "libavcodec/vvc/dec.h" #include "libavcodec/vvc/ctu.h" +#define BDOF_BLOCK_SIZE 16 +#define BDOF_MIN_BLOCK_SIZE 4 + +void ff_vvc_put_luma_h8_10_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_h16_10_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_h_x16_10_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_h8_12_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_h16_12_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_h_x16_12_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); + +void ff_vvc_put_luma_v4_10_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_v8_10_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_v16_10_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_v_x16_10_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_v4_12_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_v8_12_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_v16_12_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_v_x16_12_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); + +void ff_vvc_put_luma_hv8_10_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_hv16_10_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_hv_x16_10_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_hv8_12_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_hv16_12_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); +void ff_vvc_put_luma_hv_x16_12_neon(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, + const int height, const int8_t *hf, const int8_t *vf, const int width); + +void ff_alf_classify_sum_neon(int *sum0, int *sum1, int16_t *grad, uint32_t gshift, uint32_t steps); + #define BIT_DEPTH 8 #include "alf_template.c" #undef BIT_DEPTH @@ -52,6 +100,63 @@ void ff_vvc_avg_12_neon(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src0, const int16_t *src1, int width, int height); +void ff_vvc_w_avg_8_neon(uint8_t *_dst, ptrdiff_t _dst_stride, + const int16_t *src0, const int16_t *src1, + int width, int height, + uintptr_t w0_w1, uintptr_t offset_shift); +void ff_vvc_w_avg_10_neon(uint8_t *_dst, ptrdiff_t _dst_stride, + const int16_t *src0, const int16_t *src1, + int width, int height, + uintptr_t w0_w1, uintptr_t offset_shift); +void ff_vvc_w_avg_12_neon(uint8_t *_dst, ptrdiff_t _dst_stride, + const int16_t *src0, const int16_t *src1, + int width, int height, + uintptr_t w0_w1, uintptr_t offset_shift); +/* When passing arguments to functions, Apple platforms diverge from the ARM64 + * standard ABI for functions that require passing arguments on the stack. To + * simplify portability in the assembly function interface, use a different + * function signature that doesn't require passing arguments on the stack. + */ +#define W_AVG_FUN(bit_depth) \ +static void vvc_w_avg_ ## bit_depth(uint8_t *dst, ptrdiff_t dst_stride, \ + const int16_t *src0, const int16_t *src1, int width, int height, \ + int denom, int w0, int w1, int o) \ +{ \ + int shift = denom + FFMAX(3, 15 - bit_depth); \ + int offset = (o * (1 << (bit_depth - 8)) + 1) * (1 << (shift - 1)); \ + uintptr_t w0_w1 = ((uintptr_t)w0 << 32) | (uint32_t)w1; \ + uintptr_t offset_shift = ((uintptr_t)offset << 32) | (uint32_t)shift; \ + ff_vvc_w_avg_ ## bit_depth ## _neon(dst, dst_stride, src0, src1, width, height, w0_w1, offset_shift); \ +} + +W_AVG_FUN(8) +W_AVG_FUN(10) +W_AVG_FUN(12) + +#define DMVR_FUN(fn, bd) \ + void ff_vvc_dmvr_ ## fn ## bd ## _neon(int16_t *dst, \ + const uint8_t *_src, ptrdiff_t _src_stride, int height, \ + intptr_t mx, intptr_t my, int width); + +DMVR_FUN(, 8) +DMVR_FUN(, 12) +DMVR_FUN(h_, 8) +DMVR_FUN(h_, 10) +DMVR_FUN(h_, 12) +DMVR_FUN(v_, 8) +DMVR_FUN(hv_, 8) +DMVR_FUN(hv_, 10) +DMVR_FUN(hv_, 12) + +#define APPLY_BDOF_FUNC(bd) \ + void ff_vvc_apply_bdof_ ## bd ## _neon(uint8_t *_dst, ptrdiff_t _dst_stride, \ + const int16_t *_src0, const int16_t *_src1, \ + int block_w, int block_h); + +APPLY_BDOF_FUNC(8) +APPLY_BDOF_FUNC(10) +APPLY_BDOF_FUNC(12) + void ff_vvc_dsp_init_aarch64(VVCDSPContext *const c, const int bd) { int cpu_flags = av_get_cpu_flags(); @@ -87,6 +192,13 @@ void ff_vvc_dsp_init_aarch64(VVCDSPContext *const c, const int bd) c->inter.put[0][5][1][1] = ff_vvc_put_qpel_hv64_8_neon; c->inter.put[0][6][1][1] = ff_vvc_put_qpel_hv128_8_neon; + c->inter.put[1][1][0][0] = ff_vvc_put_pel_pixels4_8_neon; + c->inter.put[1][2][0][0] = ff_vvc_put_pel_pixels8_8_neon; + c->inter.put[1][3][0][0] = ff_vvc_put_pel_pixels16_8_neon; + c->inter.put[1][4][0][0] = ff_vvc_put_pel_pixels32_8_neon; + c->inter.put[1][5][0][0] = ff_vvc_put_pel_pixels64_8_neon; + c->inter.put[1][6][0][0] = ff_vvc_put_pel_pixels128_8_neon; + c->inter.put[1][1][0][1] = ff_vvc_put_epel_h4_8_neon; c->inter.put[1][2][0][1] = ff_vvc_put_epel_h8_8_neon; c->inter.put[1][3][0][1] = ff_vvc_put_epel_h16_8_neon; @@ -123,14 +235,22 @@ void ff_vvc_dsp_init_aarch64(VVCDSPContext *const c, const int bd) c->inter.put_uni_w[0][6][0][0] = ff_vvc_put_pel_uni_w_pixels128_8_neon; c->inter.avg = ff_vvc_avg_8_neon; + c->inter.w_avg = vvc_w_avg_8; + c->inter.dmvr[0][0] = ff_vvc_dmvr_8_neon; + c->inter.dmvr[0][1] = ff_vvc_dmvr_h_8_neon; + c->inter.dmvr[1][0] = ff_vvc_dmvr_v_8_neon; + c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_8_neon; + c->inter.apply_bdof = ff_vvc_apply_bdof_8_neon; - for (int i = 0; i < FF_ARRAY_ELEMS(c->sao.band_filter); i++) - c->sao.band_filter[i] = ff_h26x_sao_band_filter_8x8_8_neon; + c->sao.band_filter[0] = ff_h26x_sao_band_filter_8x8_8_neon; + for (int i = 1; i < FF_ARRAY_ELEMS(c->sao.band_filter); i++) + c->sao.band_filter[i] = ff_h26x_sao_band_filter_16x16_8_neon; c->sao.edge_filter[0] = ff_vvc_sao_edge_filter_8x8_8_neon; for (int i = 1; i < FF_ARRAY_ELEMS(c->sao.edge_filter); i++) c->sao.edge_filter[i] = ff_vvc_sao_edge_filter_16x16_8_neon; c->alf.filter[LUMA] = alf_filter_luma_8_neon; c->alf.filter[CHROMA] = alf_filter_chroma_8_neon; + c->alf.classify = alf_classify_8_neon; if (have_i8mm(cpu_flags)) { c->inter.put[0][1][0][1] = ff_vvc_put_qpel_h4_8_neon_i8mm; @@ -161,16 +281,72 @@ void ff_vvc_dsp_init_aarch64(VVCDSPContext *const c, const int bd) c->inter.put[1][5][1][1] = ff_vvc_put_epel_hv64_8_neon_i8mm; c->inter.put[1][6][1][1] = ff_vvc_put_epel_hv128_8_neon_i8mm; } + if (have_sme2(cpu_flags) && have_sme_i16i64(cpu_flags)) { + c->alf.filter[LUMA] = alf_filter_luma_8_sme2; + } } else if (bd == 10) { c->inter.avg = ff_vvc_avg_10_neon; + c->inter.w_avg = vvc_w_avg_10; + c->inter.dmvr[0][1] = ff_vvc_dmvr_h_10_neon; + c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_10_neon; + c->inter.apply_bdof = ff_vvc_apply_bdof_10_neon; + c->inter.put[0][2][0][1] = ff_vvc_put_luma_h8_10_neon; + c->inter.put[0][3][0][1] = ff_vvc_put_luma_h16_10_neon; + c->inter.put[0][4][0][1] = + c->inter.put[0][5][0][1] = + c->inter.put[0][6][0][1] = ff_vvc_put_luma_h_x16_10_neon; + + c->inter.put[0][1][1][0] = ff_vvc_put_luma_v4_10_neon; + c->inter.put[0][2][1][0] = ff_vvc_put_luma_v8_10_neon; + c->inter.put[0][3][1][0] = ff_vvc_put_luma_v16_10_neon; + c->inter.put[0][4][1][0] = + c->inter.put[0][5][1][0] = + c->inter.put[0][6][1][0] = ff_vvc_put_luma_v_x16_10_neon; + + c->inter.put[0][2][1][1] = ff_vvc_put_luma_hv8_10_neon; + c->inter.put[0][3][1][1] = ff_vvc_put_luma_hv16_10_neon; + c->inter.put[0][4][1][1] = + c->inter.put[0][5][1][1] = + c->inter.put[0][6][1][1] = ff_vvc_put_luma_hv_x16_10_neon; c->alf.filter[LUMA] = alf_filter_luma_10_neon; c->alf.filter[CHROMA] = alf_filter_chroma_10_neon; + c->alf.classify = alf_classify_10_neon; + if (have_sme2(cpu_flags) && have_sme_i16i64(cpu_flags)) { + c->alf.filter[LUMA] = alf_filter_luma_10_sme2; + } } else if (bd == 12) { c->inter.avg = ff_vvc_avg_12_neon; + c->inter.w_avg = vvc_w_avg_12; + c->inter.dmvr[0][0] = ff_vvc_dmvr_12_neon; + c->inter.dmvr[0][1] = ff_vvc_dmvr_h_12_neon; + c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_12_neon; + c->inter.apply_bdof = ff_vvc_apply_bdof_12_neon; + c->inter.put[0][2][0][1] = ff_vvc_put_luma_h8_12_neon; + c->inter.put[0][3][0][1] = ff_vvc_put_luma_h16_12_neon; + c->inter.put[0][4][0][1] = + c->inter.put[0][5][0][1] = + c->inter.put[0][6][0][1] = ff_vvc_put_luma_h_x16_12_neon; + + c->inter.put[0][2][1][1] = ff_vvc_put_luma_hv8_12_neon; + c->inter.put[0][3][1][1] = ff_vvc_put_luma_hv16_12_neon; + c->inter.put[0][4][1][1] = + c->inter.put[0][5][1][1] = + c->inter.put[0][6][1][1] = ff_vvc_put_luma_hv_x16_12_neon; + + c->inter.put[0][1][1][0] = ff_vvc_put_luma_v4_12_neon; + c->inter.put[0][2][1][0] = ff_vvc_put_luma_v8_12_neon; + c->inter.put[0][3][1][0] = ff_vvc_put_luma_v16_12_neon; + c->inter.put[0][4][1][0] = + c->inter.put[0][5][1][0] = + c->inter.put[0][6][1][0] = ff_vvc_put_luma_v_x16_12_neon; c->alf.filter[LUMA] = alf_filter_luma_12_neon; c->alf.filter[CHROMA] = alf_filter_chroma_12_neon; + c->alf.classify = alf_classify_12_neon; + if (have_sme2(cpu_flags) && have_sme_i16i64(cpu_flags)) { + c->alf.filter[LUMA] = alf_filter_luma_12_sme2; + } } c->inter.sad = ff_vvc_sad_neon; diff --git a/libavcodec/aarch64/vvc/inter.S b/libavcodec/aarch64/vvc/inter.S index 2f69274b8..3a38cd83c 100644 --- a/libavcodec/aarch64/vvc/inter.S +++ b/libavcodec/aarch64/vvc/inter.S @@ -21,10 +21,12 @@ #include "libavutil/aarch64/asm.S" #define VVC_MAX_PB_SIZE 128 +#define BDOF_BLOCK_SIZE 16 +#define BDOF_MIN_BLOCK_SIZE 4 -.macro vvc_avg, bit_depth +.macro vvc_w_avg bit_depth -.macro vvc_avg_\bit_depth\()_2_4, tap +.macro vvc_w_avg_\bit_depth\()_2_4 tap .if \tap == 2 ldr s0, [src0] ldr s2, [src1] @@ -32,9 +34,12 @@ ldr d0, [src0] ldr d2, [src1] .endif - saddl v4.4s, v0.4h, v2.4h - add v4.4s, v4.4s, v16.4s - sqshrn v4.4h, v4.4s, #(15 - \bit_depth) + mov v4.16b, v16.16b + smlal v4.4s, v0.4h, v19.4h + smlal v4.4s, v2.4h, v20.4h + sqshl v4.4s, v4.4s, v22.4s + sqxtun v4.4h, v4.4s + .if \bit_depth == 8 sqxtun v4.8b, v4.8h .if \tap == 2 @@ -44,8 +49,7 @@ .endif .else // bit_depth > 8 - smin v4.4h, v4.4h, v17.4h - smax v4.4h, v4.4h, v18.4h + umin v4.4h, v4.4h, v17.4h .if \tap == 2 str s4, [dst] .else @@ -57,7 +61,7 @@ add dst, dst, dst_stride .endm -function ff_vvc_avg_\bit_depth\()_neon, export=1 +function ff_vvc_w_avg_\bit_depth\()_neon, export=1 dst .req x0 dst_stride .req x1 src0 .req x2 @@ -67,49 +71,56 @@ function ff_vvc_avg_\bit_depth\()_neon, export=1 mov x10, #(VVC_MAX_PB_SIZE * 2) cmp width, #8 -.if \bit_depth == 8 - movi v16.4s, #64 -.else -.if \bit_depth == 10 - mov w6, #1023 - movi v16.4s, #16 -.else - mov w6, #4095 - movi v16.4s, #4 -.endif - movi v18.8h, #0 + lsr x11, x6, #32 // weight0 + mov w12, w6 // weight1 + lsr x13, x7, #32 // offset + mov w14, w7 // shift + + dup v19.8h, w11 + neg w14, w14 // so we can use sqshl + dup v20.8h, w12 + dup v16.4s, w13 + dup v22.4s, w14 + +.if \bit_depth >= 10 + // clip pixel + mov w6, #((1 << \bit_depth) - 1) dup v17.8h, w6 .endif + b.eq 8f b.hi 16f cmp width, #4 b.eq 4f 2: // width == 2 subs height, height, #1 - vvc_avg_\bit_depth\()_2_4 2 + vvc_w_avg_\bit_depth\()_2_4 2 b.ne 2b b 32f 4: // width == 4 subs height, height, #1 - vvc_avg_\bit_depth\()_2_4 4 + vvc_w_avg_\bit_depth\()_2_4 4 b.ne 4b b 32f 8: // width == 8 ld1 {v0.8h}, [src0], x10 ld1 {v2.8h}, [src1], x10 - saddl v4.4s, v0.4h, v2.4h - saddl2 v5.4s, v0.8h, v2.8h - add v4.4s, v4.4s, v16.4s - add v5.4s, v5.4s, v16.4s - sqshrn v4.4h, v4.4s, #(15 - \bit_depth) - sqshrn2 v4.8h, v5.4s, #(15 - \bit_depth) + mov v4.16b, v16.16b + mov v5.16b, v16.16b + smlal v4.4s, v0.4h, v19.4h + smlal v4.4s, v2.4h, v20.4h + smlal2 v5.4s, v0.8h, v19.8h + smlal2 v5.4s, v2.8h, v20.8h + sqshl v4.4s, v4.4s, v22.4s + sqshl v5.4s, v5.4s, v22.4s + sqxtun v4.4h, v4.4s + sqxtun2 v4.8h, v5.4s subs height, height, #1 .if \bit_depth == 8 sqxtun v4.8b, v4.8h st1 {v4.8b}, [dst], dst_stride .else - smin v4.8h, v4.8h, v17.8h - smax v4.8h, v4.8h, v18.8h + umin v4.8h, v4.8h, v17.8h st1 {v4.8h}, [dst], dst_stride .endif b.ne 8b @@ -122,28 +133,34 @@ function ff_vvc_avg_\bit_depth\()_neon, export=1 17: ldp q0, q1, [x7], #32 ldp q2, q3, [x8], #32 - saddl v4.4s, v0.4h, v2.4h - saddl2 v5.4s, v0.8h, v2.8h - saddl v6.4s, v1.4h, v3.4h - saddl2 v7.4s, v1.8h, v3.8h - add v4.4s, v4.4s, v16.4s - add v5.4s, v5.4s, v16.4s - add v6.4s, v6.4s, v16.4s - add v7.4s, v7.4s, v16.4s - sqshrn v4.4h, v4.4s, #(15 - \bit_depth) - sqshrn2 v4.8h, v5.4s, #(15 - \bit_depth) - sqshrn v6.4h, v6.4s, #(15 - \bit_depth) - sqshrn2 v6.8h, v7.4s, #(15 - \bit_depth) + mov v4.16b, v16.16b + mov v5.16b, v16.16b + mov v6.16b, v16.16b + mov v7.16b, v16.16b + smlal v4.4s, v0.4h, v19.4h + smlal v4.4s, v2.4h, v20.4h + smlal2 v5.4s, v0.8h, v19.8h + smlal2 v5.4s, v2.8h, v20.8h + smlal v6.4s, v1.4h, v19.4h + smlal v6.4s, v3.4h, v20.4h + smlal2 v7.4s, v1.8h, v19.8h + smlal2 v7.4s, v3.8h, v20.8h + sqshl v4.4s, v4.4s, v22.4s + sqshl v5.4s, v5.4s, v22.4s + sqshl v6.4s, v6.4s, v22.4s + sqshl v7.4s, v7.4s, v22.4s + sqxtun v4.4h, v4.4s + sqxtun v6.4h, v6.4s + sqxtun2 v4.8h, v5.4s + sqxtun2 v6.8h, v7.4s subs w6, w6, #16 .if \bit_depth == 8 sqxtun v4.8b, v4.8h sqxtun2 v4.16b, v6.8h str q4, [x9], #16 .else - smin v4.8h, v4.8h, v17.8h - smin v6.8h, v6.8h, v17.8h - smax v4.8h, v4.8h, v18.8h - smax v6.8h, v6.8h, v18.8h + umin v4.8h, v4.8h, v17.8h + umin v6.8h, v6.8h, v17.8h stp q4, q6, [x9], #32 .endif b.ne 17b @@ -155,9 +172,2406 @@ function ff_vvc_avg_\bit_depth\()_neon, export=1 b.ne 16b 32: ret + +.unreq dst +.unreq dst_stride +.unreq src0 +.unreq src1 +.unreq width +.unreq height +endfunc +.endm + +vvc_w_avg 8 +vvc_w_avg 10 +vvc_w_avg 12 + +.macro vvc_avg bit_depth +function ff_vvc_avg_\bit_depth\()_neon, export=1 + mov x10, #(VVC_MAX_PB_SIZE * 2) + movi v16.8h, #0 + movi v17.16b, #255 + ushr v17.8h, v17.8h, #(16 - \bit_depth) + + cmp w4, #8 + b.gt 16f + b.eq 8f + cmp w4, #4 + b.eq 4f + +2: // width == 2 + ldr s0, [x2] + subs w5, w5, #1 + ldr s1, [x3] +.if \bit_depth == 8 + shadd v0.4h, v0.4h, v1.4h + sqrshrun v0.8b, v0.8h, #(15 - 1 - \bit_depth) + str h0, [x0] +.else + shadd v0.4h, v0.4h, v1.4h + srshr v0.4h, v0.4h, #(15 - 1 - \bit_depth) + smax v0.4h, v0.4h, v16.4h + smin v0.4h, v0.4h, v17.4h + str s0, [x0] +.endif + add x2, x2, #(VVC_MAX_PB_SIZE * 2) + add x3, x3, #(VVC_MAX_PB_SIZE * 2) + add x0, x0, x1 + b.ne 2b + ret + +4: // width == 4 + ldr d0, [x2] + subs w5, w5, #1 + ldr d1, [x3] +.if \bit_depth == 8 + shadd v0.4h, v0.4h, v1.4h + sqrshrun v0.8b, v0.8h, #(15 - 1 - \bit_depth) + str s0, [x0] +.else + shadd v0.4h, v0.4h, v1.4h + srshr v0.4h, v0.4h, #(15 - 1 - \bit_depth) + smax v0.4h, v0.4h, v16.4h + smin v0.4h, v0.4h, v17.4h + str d0, [x0] +.endif + add x2, x2, #(VVC_MAX_PB_SIZE * 2) + add x3, x3, #(VVC_MAX_PB_SIZE * 2) + add x0, x0, x1 + b.ne 4b + ret + +8: // width == 8 + ldr q0, [x2] + subs w5, w5, #1 + ldr q1, [x3] +.if \bit_depth == 8 + shadd v0.8h, v0.8h, v1.8h + sqrshrun v0.8b, v0.8h, #(15 - 1 - \bit_depth) + str d0, [x0] +.else + shadd v0.8h, v0.8h, v1.8h + srshr v0.8h, v0.8h, #(15 - 1 - \bit_depth) + smax v0.8h, v0.8h, v16.8h + smin v0.8h, v0.8h, v17.8h + str q0, [x0] +.endif + add x2, x2, #(VVC_MAX_PB_SIZE * 2) + add x3, x3, #(VVC_MAX_PB_SIZE * 2) + add x0, x0, x1 + b.ne 8b + ret + +16: // width >= 16 +.if \bit_depth == 8 + sub x1, x1, w4, sxtw +.else + sub x1, x1, w4, sxtw #1 +.endif + sub x10, x10, w4, sxtw #1 +3: + mov w6, w4 // width +1: + ldp q0, q1, [x2], #32 + subs w6, w6, #16 + ldp q2, q3, [x3], #32 +.if \bit_depth == 8 + shadd v4.8h, v0.8h, v2.8h + shadd v5.8h, v1.8h, v3.8h + sqrshrun v0.8b, v4.8h, #6 + sqrshrun2 v0.16b, v5.8h, #6 + st1 {v0.16b}, [x0], #16 +.else + shadd v4.8h, v0.8h, v2.8h + shadd v5.8h, v1.8h, v3.8h + srshr v0.8h, v4.8h, #(15 - 1 - \bit_depth) + srshr v1.8h, v5.8h, #(15 - 1 - \bit_depth) + smax v0.8h, v0.8h, v16.8h + smax v1.8h, v1.8h, v16.8h + smin v0.8h, v0.8h, v17.8h + smin v1.8h, v1.8h, v17.8h + stp q0, q1, [x0], #32 +.endif + b.ne 1b + + subs w5, w5, #1 + add x2, x2, x10 + add x3, x3, x10 + add x0, x0, x1 + b.ne 3b + ret endfunc .endm vvc_avg 8 vvc_avg 10 vvc_avg 12 + +/* x0: int16_t *dst + * x1: const uint8_t *_src + * x2: ptrdiff_t _src_stride + * w3: int height + * x4: intptr_t mx + * x5: intptr_t my + * w6: int width + */ +function ff_vvc_dmvr_8_neon, export=1 + dst .req x0 + src .req x1 + src_stride .req x2 + height .req w3 + mx .req x4 + my .req x5 + width .req w6 + + sxtw x6, w6 + mov x7, #(VVC_MAX_PB_SIZE * 2 + 8) + cmp width, #16 + sub src_stride, src_stride, x6 + cset w15, gt // width > 16 + movi v16.8h, #2 // DMVR_SHIFT + sub x7, x7, x6, lsl #1 +1: + cbz w15, 2f + ldr q0, [src], #16 + ushll v1.8h, v0.8b, #2 + ushll2 v2.8h, v0.16b, #2 + stp q1, q2, [dst], #32 + b 3f +2: + ldr d0, [src], #8 + ushll v1.8h, v0.8b, #2 + str q1, [dst], #16 +3: + subs height, height, #1 + ldr s3, [src], #4 + ushll v4.8h, v3.8b, #2 + st1 {v4.4h}, [dst], x7 + + add src, src, src_stride + b.ne 1b + + ret +endfunc + +function ff_vvc_dmvr_12_neon, export=1 + sxtw x6, w6 + mov x7, #(VVC_MAX_PB_SIZE * 2 + 8) + cmp width, #16 + sub src_stride, src_stride, x6, lsl #1 + cset w15, gt // width > 16 + sub x7, x7, x6, lsl #1 +1: + cbz w15, 2f + ldp q0, q1, [src], #32 + urshr v0.8h, v0.8h, #2 + urshr v1.8h, v1.8h, #2 + + stp q0, q1, [dst], #32 + b 3f +2: + ldr q0, [src], #16 + urshr v0.8h, v0.8h, #2 + str q0, [dst], #16 +3: + subs height, height, #1 + ldr d0, [src], #8 + urshr v0.4h, v0.4h, #2 + st1 {v0.4h}, [dst], x7 + + add src, src, src_stride + b.ne 1b + + ret +endfunc + +function ff_vvc_dmvr_v_8_neon, export=1 + movrel x7, X(ff_vvc_inter_luma_dmvr_filters) + add x7, x7, x5, lsl #1 + ld2r {v0.16b, v1.16b}, [x7] + tbz w6, #4, 12f + + ldr s16, [x1, #16] + ld1 {v2.16b}, [x1], x2 +20: + ldr s17, [x1, #16] + umull v4.8h, v0.8b, v2.8b + umull2 v5.8h, v0.16b, v2.16b + ld1 {v3.16b}, [x1], x2 + umull v16.8h, v0.8b, v16.8b + umull v6.8h, v1.8b, v3.8b + umull2 v7.8h, v1.16b, v3.16b + add v4.8h, v4.8h, v6.8h + umull v18.8h, v1.8b, v17.8b + add v5.8h, v5.8h, v7.8h + urshr v4.8h, v4.8h, #2 + add v19.4h, v16.4h, v18.4h + urshr v5.8h, v5.8h, #2 + urshr v19.4h, v19.4h, #2 + st1 {v4.8h, v5.8h}, [x0], #32 + subs w3, w3, #1 + mov v2.16b, v3.16b + st1 {v19.4h}, [x0], #8 + mov v16.16b, v17.16b + add x0, x0, #(VVC_MAX_PB_SIZE * 2 - 32 - 8) + b.ne 20b + ret + +12: + ldr s16, [x1, #8] + ld1 {v2.8b}, [x1], x2 +2: + ldr s17, [x1, #8] + umull v4.8h, v0.8b, v2.8b + ld1 {v3.8b}, [x1], x2 + umull v16.8h, v0.8b, v16.8b + umull v6.8h, v1.8b, v3.8b + add v4.8h, v4.8h, v6.8h + umull v18.8h, v1.8b, v17.8b + srshr v4.8h, v4.8h, #2 + add v19.4h, v16.4h, v18.4h + srshr v19.4h, v19.4h, #2 + st1 {v4.8h}, [x0], #16 + subs w3, w3, #1 + mov v2.16b, v3.16b + st1 {v19.4h}, [x0], #8 + mov v16.16b, v17.16b + add x0, x0, #(VVC_MAX_PB_SIZE * 2 - 16 - 8) + b.ne 2b + ret +endfunc + +function ff_vvc_dmvr_h_8_neon, export=1 + movrel x7, X(ff_vvc_inter_luma_dmvr_filters) + add x7, x7, x4, lsl #1 + ld2r {v0.16b, v1.16b}, [x7] + tbz w6, #4, 12f +20: + ldur q3, [x1, #1] + ldr q2, [x1] + umull v4.8h, v0.8b, v2.8b + umull2 v5.8h, v0.16b, v2.16b + ldur s17, [x1, #17] + umull v6.8h, v1.8b, v3.8b + ldr s16, [x1, #16] + umull2 v7.8h, v1.16b, v3.16b + add v4.8h, v4.8h, v6.8h + umull v17.8h, v1.8b, v17.8b + add v5.8h, v5.8h, v7.8h + umull v16.8h, v0.8b, v16.8b + srshr v4.8h, v4.8h, #2 + add v16.4h, v16.4h, v17.4h + srshr v5.8h, v5.8h, #2 + srshr v16.4h, v16.4h, #2 + st1 {v4.8h, v5.8h}, [x0], #32 + subs w3, w3, #1 + st1 {v16.4h}, [x0], #8 + add x1, x1, x2 + add x0, x0, #(VVC_MAX_PB_SIZE * 2 - 32 - 8) + b.ne 20b + ret + +12: + ldur d3, [x1, #1] + ldr d2, [x1] + umull v4.8h, v0.8b, v2.8b + ldur s17, [x1, #9] + umull v6.8h, v1.8b, v3.8b + ldr s16, [x1, #8] + add v4.8h, v4.8h, v6.8h + umull v17.8h, v1.8b, v17.8b + umull v16.8h, v0.8b, v16.8b + srshr v4.8h, v4.8h, #2 + add v16.4h, v16.4h, v17.4h + srshr v16.4h, v16.4h, #2 + st1 {v4.8h}, [x0], #16 + subs w3, w3, #1 + st1 {v16.4h}, [x0], #8 + add x1, x1, x2 + add x0, x0, #(VVC_MAX_PB_SIZE * 2 - 16 - 8) + b.ne 12b + ret +endfunc + +.macro vvc_dmvr_h_10 bit_depth +function ff_vvc_dmvr_h_\bit_depth\()_neon, export=1 + movrel x7, X(ff_vvc_inter_luma_dmvr_filters) + add x7, x7, x4, lsl #1 + ld2r {v0.16b, v1.16b}, [x7] + uxtl v0.8h, v0.8b + uxtl v1.8h, v1.8b + tbz w6, #4, 12f +20: + ldur q3, [x1, #2] + ldr q2, [x1] + ldr q22, [x1, #16] + mul v4.8h, v0.8h, v2.8h + mul v6.8h, v1.8h, v3.8h + ldur q23, [x1, #18] + mul v5.8h, v0.8h, v22.8h + ldur d17, [x1, #34] + mul v7.8h, v1.8h, v23.8h + uhadd v4.8h, v4.8h, v6.8h + ldr d16, [x1, #32] + uhadd v5.8h, v5.8h, v7.8h + mul v17.4h, v1.4h, v17.4h + mul v16.4h, v0.4h, v16.4h + urshr v4.8h, v4.8h, #(\bit_depth - 6 - 1) + urshr v5.8h, v5.8h, #(\bit_depth - 6 - 1) + uhadd v16.4h, v16.4h, v17.4h + urshr v16.4h, v16.4h, #(\bit_depth - 6 - 1) + st1 {v4.8h, v5.8h}, [x0], #32 + subs w3, w3, #1 + st1 {v16.4h}, [x0], #8 + add x1, x1, x2 + add x0, x0, #(VVC_MAX_PB_SIZE * 2 - 32 - 8) + b.ne 20b + ret + +12: + ldur q3, [x1, #2] + ldr q2, [x1] + mul v4.8h, v0.8h, v2.8h + ldur d17, [x1, #18] + mul v6.8h, v1.8h, v3.8h + ldr d16, [x1, #16] + uhadd v4.8h, v4.8h, v6.8h + mul v17.4h, v1.4h, v17.4h + mul v16.4h, v0.4h, v16.4h + urshr v4.8h, v4.8h, #(\bit_depth - 6 - 1) + uhadd v16.4h, v16.4h, v17.4h + urshr v16.4h, v16.4h, #(\bit_depth - 6 - 1) + st1 {v4.8h}, [x0], #16 + subs w3, w3, #1 + st1 {v16.4h}, [x0], #8 + add x1, x1, x2 + add x0, x0, #(VVC_MAX_PB_SIZE * 2 - 16 - 8) + b.ne 12b + ret +endfunc +.endm + +vvc_dmvr_h_10 10 +vvc_dmvr_h_10 12 + +function ff_vvc_dmvr_hv_8_neon, export=1 + tmp0 .req x7 + tmp1 .req x8 + + sub sp, sp, #(VVC_MAX_PB_SIZE * 4) + + movrel x9, X(ff_vvc_inter_luma_dmvr_filters) + add x12, x9, mx, lsl #1 + mov tmp0, sp + add tmp1, tmp0, #(VVC_MAX_PB_SIZE * 2) + // We know the value are positive + ld2r {v0.16b, v1.16b}, [x12] + + add x12, x9, my, lsl #1 + ldrb w10, [x12] + ldrb w11, [x12, #1] + sxtw x6, w6 + dup v2.8h, w10 // filter_y[0] + dup v3.8h, w11 // filter_y[1] + + // Valid value for width can only be 8 + 4, 16 + 4 + cmp width, #16 + mov w10, #0 // start filter_y or not + add height, height, #1 + sub dst, dst, #(VVC_MAX_PB_SIZE * 2) + sub src_stride, src_stride, x6 + cset w15, gt // width > 16 +1: + mov x12, tmp0 + mov x13, tmp1 + mov x14, dst + cbz w15, 2f + + // width > 16 + ldur q5, [src, #1] + ldr q4, [src], #16 + umull v6.8h, v4.8b, v0.8b + umull2 v16.8h, v4.16b, v0.16b + umlal v6.8h, v5.8b, v1.8b + umlal2 v16.8h, v5.16b, v1.16b + urshr v6.8h, v6.8h, #(8 - 6) + urshr v7.8h, v16.8h, #(8 - 6) + stp q6, q7, [x13], #32 + + cbz w10, 3f + + ldp q16, q17, [x12], #32 + mul v16.8h, v16.8h, v2.8h + mul v17.8h, v17.8h, v2.8h + mla v16.8h, v6.8h, v3.8h + mla v17.8h, v7.8h, v3.8h + urshr v16.8h, v16.8h, #4 + urshr v17.8h, v17.8h, #4 + stp q16, q17, [x14], #32 + b 3f +2: + // width > 8 + ldur d5, [src, #1] + ldr d4, [src], #8 + umull v6.8h, v4.8b, v0.8b + umlal v6.8h, v5.8b, v1.8b + urshr v6.8h, v6.8h, #(8 - 6) + str q6, [x13], #16 + + cbz w10, 3f + + ldr q16, [x12], #16 + mul v16.8h, v16.8h, v2.8h + mla v16.8h, v6.8h, v3.8h + urshr v16.8h, v16.8h, #4 + str q16, [x14], #16 +3: + ldur s5, [src, #1] + ldr s4, [src], #4 + umull v6.8h, v4.8b, v0.8b + umlal v6.8h, v5.8b, v1.8b + urshr v6.4h, v6.4h, #(8 - 6) + str d6, [x13], #8 + + cbz w10, 4f + + ldr d16, [x12], #8 + mul v16.4h, v16.4h, v2.4h + mla v16.4h, v6.4h, v3.4h + urshr v16.4h, v16.4h, #4 + str d16, [x14], #8 +4: + subs height, height, #1 + mov w10, #1 + add src, src, src_stride + add dst, dst, #(VVC_MAX_PB_SIZE * 2) + eor tmp0, tmp0, tmp1 + eor tmp1, tmp0, tmp1 + eor tmp0, tmp0, tmp1 + b.ne 1b + + add sp, sp, #(VVC_MAX_PB_SIZE * 4) + ret +endfunc + +function ff_vvc_dmvr_hv_12_neon, export=1 + mvni v29.4s, #(12 - 6 - 1) + b 0f +endfunc + +function ff_vvc_dmvr_hv_10_neon, export=1 + mvni v29.4s, #(10 - 6 - 1) +0: + sub sp, sp, #(VVC_MAX_PB_SIZE * 4) + + movrel x9, X(ff_vvc_inter_luma_dmvr_filters) + add x12, x9, mx, lsl #1 + ldrb w10, [x12] + ldrb w11, [x12, #1] + mov tmp0, sp + add tmp1, tmp0, #(VVC_MAX_PB_SIZE * 2) + // We know the value are positive + dup v0.8h, w10 // filter_x[0] + dup v1.8h, w11 // filter_x[1] + + add x12, x9, my, lsl #1 + ldrb w10, [x12] + ldrb w11, [x12, #1] + dup v2.8h, w10 // filter_y[0] + dup v3.8h, w11 // filter_y[1] + + // Valid value for width can only be 8 + 4, 16 + 4 + cmp width, #16 + mov w10, #0 // start filter_y or not + add height, height, #1 + sub dst, dst, #(VVC_MAX_PB_SIZE * 2) + sub src_stride, src_stride, w6, sxtw #1 + cset w15, gt // width > 16 +1: + mov x12, tmp0 + mov x13, tmp1 + mov x14, dst + cbz w15, 2f + + // width > 16 + add x16, src, #2 + ldp q6, q16, [src], #32 + ldp q7, q17, [x16] + umull v4.4s, v6.4h, v0.4h + umull2 v5.4s, v6.8h, v0.8h + umull v18.4s, v16.4h, v0.4h + umull2 v19.4s, v16.8h, v0.8h + umlal v4.4s, v7.4h, v1.4h + umlal2 v5.4s, v7.8h, v1.8h + umlal v18.4s, v17.4h, v1.4h + umlal2 v19.4s, v17.8h, v1.8h + + urshl v4.4s, v4.4s, v29.4s + urshl v5.4s, v5.4s, v29.4s + urshl v18.4s, v18.4s, v29.4s + urshl v19.4s, v19.4s, v29.4s + uqxtn v6.4h, v4.4s + uqxtn2 v6.8h, v5.4s + uqxtn v7.4h, v18.4s + uqxtn2 v7.8h, v19.4s + stp q6, q7, [x13], #32 + + cbz w10, 3f + + ldp q4, q5, [x12], #32 + umull v17.4s, v4.4h, v2.4h + umull2 v18.4s, v4.8h, v2.8h + umull v19.4s, v5.4h, v2.4h + umull2 v20.4s, v5.8h, v2.8h + umlal v17.4s, v6.4h, v3.4h + umlal2 v18.4s, v6.8h, v3.8h + umlal v19.4s, v7.4h, v3.4h + umlal2 v20.4s, v7.8h, v3.8h + uqrshrn v6.4h, v17.4s, #4 + uqrshrn2 v6.8h, v18.4s, #4 + uqrshrn v7.4h, v19.4s, #4 + uqrshrn2 v7.8h, v20.4s, #4 + stp q6, q7, [x14], #32 + b 3f +2: + // width > 8 + ldur q7, [src, #2] + ldr q6, [src], #16 + umull v4.4s, v6.4h, v0.4h + umull2 v5.4s, v6.8h, v0.8h + umlal v4.4s, v7.4h, v1.4h + umlal2 v5.4s, v7.8h, v1.8h + + urshl v4.4s, v4.4s, v29.4s + urshl v5.4s, v5.4s, v29.4s + uqxtn v6.4h, v4.4s + uqxtn2 v6.8h, v5.4s + str q6, [x13], #16 + + cbz w10, 3f + + ldr q16, [x12], #16 + umull v17.4s, v16.4h, v2.4h + umull2 v18.4s, v16.8h, v2.8h + umlal v17.4s, v6.4h, v3.4h + umlal2 v18.4s, v6.8h, v3.8h + urshr v17.4s, v17.4s, #4 + urshr v18.4s, v18.4s, #4 + uqxtn v16.4h, v17.4s + uqxtn2 v16.8h, v18.4s + str q16, [x14], #16 +3: + ldur d7, [src, #2] + ldr d6, [src], #8 + umull v4.4s, v7.4h, v1.4h + umlal v4.4s, v6.4h, v0.4h + urshl v4.4s, v4.4s, v29.4s + uqxtn v6.4h, v4.4s + str d6, [x13], #8 + + cbz w10, 4f + + ldr d16, [x12], #8 + umull v17.4s, v16.4h, v2.4h + umlal v17.4s, v6.4h, v3.4h + urshr v17.4s, v17.4s, #4 + uqxtn v16.4h, v17.4s + str d16, [x14], #8 +4: + subs height, height, #1 + mov w10, #1 + add src, src, src_stride + add dst, dst, #(VVC_MAX_PB_SIZE * 2) + eor tmp0, tmp0, tmp1 + eor tmp1, tmp0, tmp1 + eor tmp0, tmp0, tmp1 + b.ne 1b + + add sp, sp, #(VVC_MAX_PB_SIZE * 4) + ret + +.unreq dst +.unreq src +.unreq src_stride +.unreq height +.unreq mx +.unreq my +.unreq width +.unreq tmp0 +.unreq tmp1 +endfunc + +function ff_vvc_prof_grad_filter_8x_neon, export=1 + gh .req x0 + gv .req x1 + gstride .req x2 + src .req x3 + src_stride .req x4 + width .req w5 + height .req w6 + + lsl src_stride, src_stride, #1 + neg x7, src_stride +1: + mov x10, src + mov w11, width + mov x12, gh + mov x13, gv +2: + ldur q0, [x10, #2] + ldur q1, [x10, #-2] + subs w11, w11, #8 + ldr q2, [x10, src_stride] + ldr q3, [x10, x7] + sshr v0.8h, v0.8h, #6 + sshr v1.8h, v1.8h, #6 + sshr v2.8h, v2.8h, #6 + sshr v3.8h, v3.8h, #6 + sub v0.8h, v0.8h, v1.8h + sub v2.8h, v2.8h, v3.8h + st1 {v0.8h}, [x12], #16 + st1 {v2.8h}, [x13], #16 + add x10, x10, #16 + b.ne 2b + + subs height, height, #1 + add gh, gh, gstride, lsl #1 + add gv, gv, gstride, lsl #1 + add src, src, src_stride + b.ne 1b + ret + +.unreq gh +.unreq gv +.unreq gstride +.unreq src +.unreq src_stride +.unreq width +.unreq height +endfunc + +function vvc_bdof_grad_filter_8x_neon, export=0 + gh0 .req x0 + gh1 .req x1 + gv0 .req x2 + gv1 .req x3 + src0 .req x4 + src1 .req x5 + width .req w6 + height .req w7 + tbnz w6, #4, 16f + +8: + ldur q0, [src0, #2] + ldur q1, [src0, #-2] + ldr q2, [src0, #(VVC_MAX_PB_SIZE << 1)] + ldr q3, [src0, #-(VVC_MAX_PB_SIZE << 1)] + sshr v0.8h, v0.8h, #6 + sshr v1.8h, v1.8h, #6 + ldur q4, [src1, #2] + ldur q5, [src1, #-2] + sshr v2.8h, v2.8h, #6 + sshr v3.8h, v3.8h, #6 + ldr q6, [src1, #(VVC_MAX_PB_SIZE << 1)] + ldr q7, [src1, #-(VVC_MAX_PB_SIZE << 1)] + // results of gradient_h0 + sub v0.8h, v0.8h, v1.8h + // results of gradient_v0 + sub v2.8h, v2.8h, v3.8h + + sshr v4.8h, v4.8h, #6 + sshr v5.8h, v5.8h, #6 + sshr v6.8h, v6.8h, #6 + sshr v7.8h, v7.8h, #6 + // results of gradient_h1 + sub v4.8h, v4.8h, v5.8h + // results of gradient_v1 + sub v6.8h, v6.8h, v7.8h + + // (gradient_h0 + gradient_h1) >> 1 + shadd v1.8h, v0.8h, v4.8h + // gradient_h0 - gradient_h1 + sub v5.8h, v0.8h, v4.8h + + // (gradient_v0 + gradient_v1) >> 1 + shadd v3.8h, v2.8h, v6.8h + // gradient_v0 - gradient_v1 + sub v7.8h, v2.8h, v6.8h + + st1 {v1.8h}, [gh0] + st1 {v5.8h}, [gh1] + st1 {v3.8h}, [gv0] + st1 {v7.8h}, [gv1] + + subs height, height, #1 + add gh0, gh0, #(BDOF_BLOCK_SIZE << 1) + add gv0, gv0, #(BDOF_BLOCK_SIZE << 1) + add src0, src0, #(VVC_MAX_PB_SIZE << 1) + add gh1, gh1, #(BDOF_BLOCK_SIZE << 1) + add gv1, gv1, #(BDOF_BLOCK_SIZE << 1) + add src1, src1, #(VVC_MAX_PB_SIZE << 1) + b.ne 8b + ret + +16: + ldur q0, [src0, #2] + ldur q1, [src0, #18] + ldur q16, [src0, #-2] + sshr v0.8h, v0.8h, #6 + ldur q17, [src0, #14] + sshr v1.8h, v1.8h, #6 + ldp q18, q19, [src0, #-(VVC_MAX_PB_SIZE << 1)] + sshr v16.8h, v16.8h, #6 + ldp q2, q3, [src0, #(VVC_MAX_PB_SIZE << 1)]! + ldur q20, [src1, #2] + sshr v17.8h, v17.8h, #6 + ldur q21, [src1, #18] + sshr v2.8h, v2.8h, #6 + ldur q22, [src1, #-2] + sshr v3.8h, v3.8h, #6 + ldur q23, [src1, #14] + sshr v18.8h, v18.8h, #6 + ldp q26, q27, [src1, #-(VVC_MAX_PB_SIZE << 1)] + sshr v19.8h, v19.8h, #6 + ldp q24, q25, [src1, #(VVC_MAX_PB_SIZE << 1)]! + + // results of gradient_h0 + sub v0.8h, v0.8h, v16.8h + sub v1.8h, v1.8h, v17.8h + + // results of gradient_v0 + sub v2.8h, v2.8h, v18.8h + sub v3.8h, v3.8h, v19.8h + + sshr v20.8h, v20.8h, #6 + sshr v21.8h, v21.8h, #6 + sshr v22.8h, v22.8h, #6 + sshr v23.8h, v23.8h, #6 + + // results of gradient_h1 + sub v20.8h, v20.8h, v22.8h + sub v21.8h, v21.8h, v23.8h + + sshr v24.8h, v24.8h, #6 + sshr v25.8h, v25.8h, #6 + + // gradient_h0 - gradient_h1 + sub v22.8h, v0.8h, v20.8h + sub v23.8h, v1.8h, v21.8h + + // (gradient_h0 + gradient_h1) >> 1 + shadd v16.8h, v0.8h, v20.8h + shadd v17.8h, v1.8h, v21.8h + + st1 {v22.8h, v23.8h}, [gh1], #32 + + sshr v26.8h, v26.8h, #6 + sshr v27.8h, v27.8h, #6 + + st1 {v16.8h, v17.8h}, [gh0], #32 + + // results of gradient_v1 + sub v24.8h, v24.8h, v26.8h + sub v25.8h, v25.8h, v27.8h + + // (gradient_v0 + gradient_v1) >> 1 + shadd v18.8h, v2.8h, v24.8h + shadd v19.8h, v3.8h, v25.8h + + // gradient_v0 - gradient_v1 + sub v26.8h, v2.8h, v24.8h + sub v27.8h, v3.8h, v25.8h + + st1 {v18.8h,v19.8h}, [gv0], #32 + + subs height, height, #1 + st1 {v26.8h,v27.8h}, [gv1], #32 + + b.ne 16b + ret + +.unreq gh0 +.unreq gh1 +.unreq gv0 +.unreq gv1 +.unreq src0 +.unreq src1 +.unreq width +.unreq height +endfunc + +.macro vvc_apply_bdof_block_8x bit_depth + dst .req x0 + dst_stride .req x1 + src0 .req x2 + src1 .req x3 + gh .req x4 + gv .req x5 + vx .req x6 + vy .req x7 + + ldr w8, [sp] + mov x12, #(BDOF_BLOCK_SIZE * 2) + mov x14, #(VVC_MAX_PB_SIZE * 2) +.if \bit_depth >= 10 + // clip pixel + mov w15, #((1 << \bit_depth) - 1) + dup v19.8h, w15 +.endif + +0: + ldr s0, [vx], #(2 * BDOF_MIN_BLOCK_SIZE) + ldr s1, [vy], #(2 * BDOF_MIN_BLOCK_SIZE) + mov w13, #(BDOF_MIN_BLOCK_SIZE) +1: + ld1 {v5.8h}, [src0], x14 + ld1 {v6.8h}, [src1], x14 + + saddl v17.4s, v5.4h, v6.4h + ld1 {v4.8h}, [gv], x12 + saddl2 v16.4s, v5.8h, v6.8h + ld1 {v2.8h}, [gh], x12 + smlal v17.4s, v4.4h, v1.h[0] + smlal2 v16.4s, v4.8h, v1.h[1] + smlal v17.4s, v2.4h, v0.h[0] + smlal2 v16.4s, v2.8h, v0.h[1] + + sqrshrun v5.4h, v17.4s, #(15 - \bit_depth) + sqrshrun2 v5.8h, v16.4s, #(15 - \bit_depth) + subs w13, w13, #1 +.if \bit_depth == 8 + sqxtun v5.8b, v5.8h + st1 {v5.8b}, [dst], dst_stride +.else + smin v5.8h, v5.8h, v19.8h + st1 {v5.8h}, [dst], dst_stride +.endif + b.ne 1b + + subs w8, w8, #(BDOF_MIN_BLOCK_SIZE) + b.ne 0b + ret + +.unreq dst +.unreq dst_stride +.unreq src0 +.unreq src1 +.unreq gh +.unreq gv +.unreq vx +.unreq vy +.endm + +function vvc_apply_bdof_block_8x_8_neon, export=0 + vvc_apply_bdof_block_8x 8 +endfunc + +function vvc_apply_bdof_block_8x_10_neon, export=0 + vvc_apply_bdof_block_8x 10 +endfunc + +function vvc_apply_bdof_block_8x_12_neon, export=0 + vvc_apply_bdof_block_8x 12 +endfunc + +.macro vvc_apply_bdof_block_16x bit_depth + dst .req x0 + dst_stride .req x1 + src0 .req x2 + src1 .req x3 + gh .req x4 + gv .req x5 + vx .req x6 + vy .req x7 + + ldr w8, [sp] + movi v7.4s, #(1 << (14 - \bit_depth)) +.if \bit_depth >= 10 + // clip pixel + mov w15, #((1 << \bit_depth) - 1) + movi v18.8h, #0 + dup v19.8h, w15 +.endif + +0: + ld1r {v0.8h}, [vx], #2 + ld1r {v1.8h}, [vy], #2 + ld1r {v2.8h}, [vx], #2 + ld1r {v3.8h}, [vy], #2 + + mov w13, #(BDOF_MIN_BLOCK_SIZE) + + ld1r {v20.8h}, [vx], #2 + ld1r {v21.8h}, [vy], #2 + ld1r {v22.8h}, [vx], #2 + ld1r {v23.8h}, [vy], #2 + + ins v0.d[1], v2.d[1] + ins v1.d[1], v3.d[1] + ins v20.d[1], v22.d[1] + ins v21.d[1], v23.d[1] +1: + ldp q2, q22, [gh], #(BDOF_BLOCK_SIZE * 2) + ldp q4, q24, [gv], #(BDOF_BLOCK_SIZE * 2) + smull v3.4s, v0.4h, v2.4h + smull2 v16.4s, v0.8h, v2.8h + smlal v3.4s, v1.4h, v4.4h + smlal2 v16.4s, v1.8h, v4.8h + + ldp q5, q25, [src0], #(VVC_MAX_PB_SIZE * 2) + ldp q6, q26, [src1], #(VVC_MAX_PB_SIZE * 2) + + smull v23.4s, v20.4h, v22.4h + smull2 v27.4s, v20.8h, v22.8h + smlal v23.4s, v21.4h, v24.4h + smlal2 v27.4s, v21.8h, v24.8h + + saddl v2.4s, v5.4h, v6.4h + add v2.4s, v2.4s, v7.4s + add v2.4s, v2.4s, v3.4s + saddl2 v4.4s, v5.8h, v6.8h + add v4.4s, v4.4s, v7.4s + add v4.4s, v4.4s, v16.4s + + saddl v22.4s, v25.4h, v26.4h + add v22.4s, v22.4s, v7.4s + add v22.4s, v22.4s, v23.4s + saddl2 v24.4s, v25.8h, v26.8h + add v24.4s, v24.4s, v7.4s + add v24.4s, v24.4s, v27.4s + + sqshrn v5.4h, v2.4s, #(15 - \bit_depth) + sqshrn2 v5.8h, v4.4s, #(15 - \bit_depth) + sqshrn v25.4h, v22.4s, #(15 - \bit_depth) + sqshrn2 v25.8h, v24.4s, #(15 - \bit_depth) + + subs w13, w13, #1 +.if \bit_depth == 8 + sqxtun v5.8b, v5.8h + sqxtun2 v5.16b, v25.8h + str q5, [dst] +.else + smin v5.8h, v5.8h, v19.8h + smax v5.8h, v5.8h, v18.8h + smin v25.8h, v25.8h, v19.8h + smax v25.8h, v25.8h, v18.8h + stp q5, q25, [dst] +.endif + add dst, dst, dst_stride + b.ne 1b + + subs w8, w8, #(BDOF_MIN_BLOCK_SIZE) + b.ne 0b + ret + +.unreq dst +.unreq dst_stride +.unreq src0 +.unreq src1 +.unreq gh +.unreq gv +.unreq vx +.unreq vy +.endm + +function vvc_apply_bdof_block_16x_8_neon, export=0 + vvc_apply_bdof_block_16x 8 +endfunc + +function vvc_apply_bdof_block_16x_10_neon, export=0 + vvc_apply_bdof_block_16x 10 +endfunc + +function vvc_apply_bdof_block_16x_12_neon, export=0 + vvc_apply_bdof_block_16x 12 +endfunc + +const bdof_vx_vy_8x_tbl + .byte 0, 1, 16, 16, 16, 16, 8, 9 + .byte 6, 7, 16, 16, 16, 16, 14, 15 +endconst + +const bdof_vx_vy_16x_tbl + .byte 0, 1, 64, 64, 64, 64, 8, 9 + .byte 6, 7, 64, 64, 64, 64, 16, 17 + .byte 14, 15, 64, 64, 64, 64, 24, 25 + .byte 22, 23, 64, 64, 64, 64, 30, 31 +endconst + +// line(-1), line0, line1, line2, line3, line4 +// line3 and line4 becomes line(-1) and line0 in the next block. +.macro bdof_vx_vy_8x_save_line tmp0, tmp1, tmp2, tmp3, tmp4 + mov \tmp0\().16b, v28.16b + mov \tmp1\().16b, v29.16b + mov \tmp2\().16b, v30.16b + mov \tmp3\().16b, v31.16b + mov \tmp4\().16b, v8.16b +.endm + +.macro bdof_vx_vy_8x_add_line tmp0, tmp1, tmp2, tmp3, tmp4 + add v25.4s, v25.4s, \tmp0\().4s + add v27.4s, v27.4s, \tmp1\().4s + add v23.4s, v23.4s, \tmp2\().4s + sub v26.4s, v26.4s, \tmp3\().4s + sub v24.4s, v24.4s, \tmp4\().4s +.endm + +.macro bdof_vx_vy_8x_padding_left_right src, tmp0, tmp1, dst + tbl \tmp0\().16b, { \src\().16b }, v0.16b + saddl \tmp1\().4s, \tmp0\().4h, \src\().4h + saddl2 \dst\().4s, \tmp0\().8h, \src\().8h + addp \dst\().4s, \tmp1\().4s, \dst\().4s +.endm + +.macro bdof_vx_vy_sign src, tmp0, tmp1, dst + cmlt \tmp0\().8h, \src\().8h, #0 + cmgt \tmp1\().8h, \src\().8h, #0 + sub \dst\().8h, \tmp0\().8h, \tmp1\().8h +.endm + +.macro bdof_vx_vy_clip_mask src, max, min, mask, dst + smin \src\().4s, \src\().4s, \max\().4s + smax \src\().4s, \src\().4s, \min\().4s + cmgt \mask\().4s, \mask\().4s, #0 + and \dst\().16b, \src\().16b, \mask\().16b +.endm + +.macro bdof_vx_vy_16x_save_line tmp0, tmp1, tmp2, tmp3, tmp4 + mov \tmp0\().16b, v29.16b + mov \tmp1\().16b, v30.16b + mov \tmp2\().16b, v31.16b + mov \tmp3\().16b, v8.16b + mov \tmp4\().16b, v9.16b +.endm + +.macro bdof_vx_vy_16x_add_line tmp0, tmp1, tmp2, tmp3, tmp4 + add v25.4s, v25.4s, \tmp0\().4s + add v24.4s, v24.4s, \tmp1\().4s + add v26.4s, v26.4s, \tmp2\().4s + sub v28.4s, v28.4s, \tmp3\().4s + sub v27.4s, v27.4s, \tmp4\().4s +.endm + +.macro bdof_vx_vy_16x_padding_left_right src0, src1, tmp0, tmp1, tmp2, dst + tbl \tmp0\().16b, {\src0\().16b, \src1\().16b}, v0.16b + tbl v2.16b, {\src0\().16b, \src1\().16b}, v1.16b + saddl \tmp1\().4s, \tmp0\().4h, \src0\().4h + saddl \tmp2\().4s, v2.4h, \src1\().4h + saddl2 \tmp0\().4s, \tmp0\().8h, \src0\().8h + saddl2 \dst\().4s, v2.8h, \src1\().8h + addp \tmp0\().4s, \tmp1\().4s, \tmp0\().4s + addp \dst\().4s, \tmp2\().4s, \dst\().4s + addp \dst\().4s, \tmp0\().4s, \dst\().4s +.endm + +/* + * Line tricks: + * We need 6 lines of information, from 4N-1, 4N, 4N+1 to 4N+4. 4N-1 + * and 4N+0 are processed in the last group, so they can be reused. + * + * (4N-1) [xxxxxxxxxxxxx] <--- reuse + * (4N) [xxxxxxxxxxxxx] <--- reuse + * (4N+1) [xxxxxxxxxxxxx] + * (4N+2) [xxxxxxxxxxxxx] + * (4N+3) [xxxxxxxxxxxxx] ---> save for reuse + * (4N+4) [xxxxxxxxxxxxx] ---> save for reuse + * + * Special case: + * 1. Line -1 needs to duplicate line 0. + * 2. Last line +1 needs to duplicate the last line. + * + * --------------------------------------------------------------------- + * Pixel tricks: + * + * [C-1, C0, C1, C2, ... C16] + * + * For each line, we need to sum parameters for 4 * 6 pixels: + * - C-1 + C0 + C1 + C2 + C3 + C4 + * - C3 + C4 + C5 + C6 + C7 + C8 + * - C7 + C8 + C9 + C10 + C11 + C12 + * - C11 + C12 + C13 + C14 + C15 + C16 + * + * C-1 is C0, C16 is C15, so we can do: + * + * [C0, C1, C2, C3, | C4, C5, C6, C7, | C8, ... C15] + * + | + | + * [C0, 0, 0, C4, | C3, 0, 0, C8, | C7, ... C15] + * + * 8x is similar. + * ---------------------------------------------------------------------- + * x0: const int16_t *_src0, + * x1: const int16_t *_src1, + * x2: const int16_t *gradient_h, + * x3: const int16_t *gradient_v, + * x4: int16_t vx[16], + * x5: int16_t vy[16], + * w6: int block_h + */ +function vvc_derive_bdof_vx_vy_8x_neon, export=0 + stp d11, d10, [sp, #-0x20]! + stp d9, d8, [sp, #0x10] + + movrel x11, bdof_vx_vy_8x_tbl + ldr q0, [x11] // table + mvni v2.4s, #30 // -31, for log2 + movi v3.4s, #15 // clip to 15 + mvni v4.4s, #14 // clip to -15 + + mov w11, #0x8 + mov w12, w6 // y = block_h + b 4f + +1: + // save line4 results + bdof_vx_vy_8x_save_line v5, v6, v7, v16, v17 +2: + addp v25.4s, v25.4s, v25.4s + addp v27.4s, v27.4s, v27.4s + addp v26.4s, v26.4s, v26.4s + addp v23.4s, v23.4s, v23.4s + addp v24.4s, v24.4s, v24.4s + + clz v28.4s, v25.4s + add v28.4s, v28.4s, v2.4s // log2 + shl v26.4s, v26.4s, #0x2 + sshl v26.4s, v26.4s, v28.4s + + bdof_vx_vy_clip_mask v26, v3, v4, v25, v25 + sqxtn v26.4h, v25.4s + st1 {v26.s}[0], [x4], x11 + + subs x12, x12, #(BDOF_MIN_BLOCK_SIZE) + + clz v26.4s, v27.4s + add v26.4s, v26.4s, v2.4s + shl v24.4s, v24.4s, #0x2 + mul v23.4s, v25.4s, v23.4s + sshr v23.4s, v23.4s, #0x1 + sub v23.4s, v24.4s, v23.4s + sshl v23.4s, v23.4s, v26.4s + + bdof_vx_vy_clip_mask v23, v3, v4, v27, v23 + sqxtn v23.4h, v23.4s + st1 {v23.s}[0], [x5], x11 + + b.eq 16f +4: + mov x15, #0x0 // dy, inner loop + + movi v25.2d, #0 + movi v27.2d, #0 + movi v23.2d, #0 + movi v26.2d, #0 + movi v24.2d, #0 + b 8f + +5: + // add line(-1) and line0 from previous results + bdof_vx_vy_8x_add_line v18, v19, v20, v21, v22 + bdof_vx_vy_8x_add_line v5, v6, v7, v16, v17 + add x15, x15, #1 +8: + cmp w12, w6 + b.hs 9f + // y < block_h && dy == 0, reuse previous results + cbz x15, 5b +9: + ldr q28, [x0] // src0 + ldr q29, [x1] // src1 + ldr q30, [x2], #(BDOF_BLOCK_SIZE * 2) // (gh0 + gh1) >> 1 + ldr q31, [x3], #(BDOF_BLOCK_SIZE * 2) // (gv0 + gv1) >> 1 + add x0, x0, #(VVC_MAX_PB_SIZE * 2) + add x1, x1, #(VVC_MAX_PB_SIZE * 2) + + sshr v28.8h, v28.8h, #0x4 + sshr v29.8h, v29.8h, #0x4 + sub v8.8h, v28.8h, v29.8h // diff + + abs v28.8h, v30.8h + abs v29.8h, v31.8h + + bdof_vx_vy_8x_padding_left_right v28, v9, v10, v28 + bdof_vx_vy_8x_padding_left_right v29, v9, v10, v29 + + bdof_vx_vy_sign v30, v9, v10, v9 + bdof_vx_vy_sign v31, v10, v31, v31 + + mul v30.8h, v31.8h, v30.8h + mul v9.8h, v9.8h, v8.8h + mul v8.8h, v31.8h, v8.8h + + bdof_vx_vy_8x_padding_left_right v30, v31, v10, v30 + bdof_vx_vy_8x_padding_left_right v9, v31, v10, v31 + bdof_vx_vy_8x_padding_left_right v8, v9, v10, v8 + + bdof_vx_vy_8x_add_line v28, v29, v30, v31, v8 + + cmp w12, w6 + b.ne 10f + cbnz x15, 10f + + // y == block_h && dy == 0, duplicate first line results + bdof_vx_vy_8x_add_line v28, v29, v30, v31, v8 + add x15, x15, #0x1 + b 9b +10: + cmp x15, #(BDOF_MIN_BLOCK_SIZE - 1) + b.eq 11f + cmp x15, #(BDOF_MIN_BLOCK_SIZE) + b.ne 12f + b 1b +11: + // y == BDOF_MIN_BLOCK_SIZE && dy == BDOF_MIN_BLOCK_SIZE - 1 + // duplicate the results and break + cmp x12, #(BDOF_MIN_BLOCK_SIZE) + b.eq 13f + bdof_vx_vy_8x_save_line v18, v19, v20, v21, v22 +12: + add x15, x15, #1 + b 8b +13: + // y == BDOF_MIN_BLOCK_SIZE && dy == BDOF_MIN_BLOCK_SIZE - 1 + // padding bottom then break + bdof_vx_vy_8x_add_line v28, v29, v30, v31, v8 + b 2b +16: + ldp d9, d8, [sp, #0x10] + ldp d11, d10, [sp], #0x20 + ret +endfunc + +/* + * x0: const int16_t *_src0, + * x1: const int16_t *_src1, + * x2: const int16_t *gradient_h, + * x3: const int16_t *gradient_v, + * x4: int16_t vx[16], + * x5: int16_t vy[16], + * w6: int block_h + */ +function vvc_derive_bdof_vx_vy_16x_neon, export=0 + stp d15, d14, [sp, #-0x40]! + stp d13, d12, [sp, #0x10] + stp d11, d10, [sp, #0x20] + stp d9, d8, [sp, #0x30] + + movrel x12, bdof_vx_vy_16x_tbl + ldp q0, q1, [x12] // table + mov w13, w6 // y = block_h + b 4f + +1: + // save line4 + bdof_vx_vy_16x_save_line v6, v7, v16, v17, v18 +2: + clz v3.4s, v25.4s + mvni v5.4s, #0x1e + add v3.4s, v3.4s, v5.4s // -log2() + shl v4.4s, v28.4s, #0x2 + sshl v3.4s, v4.4s, v3.4s + + movi v28.4s, #0xf // clip to 15 + mvni v29.4s, #0xe // clip to -15 + bdof_vx_vy_clip_mask v3, v28, v29, v25, v3 + sqxtn v4.4h, v3.4s + st1 {v4.d}[0], [x4], #(BDOF_MIN_BLOCK_SIZE * 2) + + subs x13, x13, #(BDOF_MIN_BLOCK_SIZE) // y -= BDOF_MIN_BLOCK_SIZE + + clz v4.4s, v24.4s + add v4.4s, v4.4s, v5.4s // -log2() + shl v5.4s, v27.4s, #0x2 + mul v3.4s, v3.4s, v26.4s + sshr v3.4s, v3.4s, #0x1 + sub v3.4s, v5.4s, v3.4s + sshl v3.4s, v3.4s, v4.4s + + bdof_vx_vy_clip_mask v3, v28, v29, v24, v3 + sqxtn v3.4h, v3.4s + st1 {v3.d}[0], [x5], #(BDOF_MIN_BLOCK_SIZE * 2) + b.eq 16f +4: + mov w14, #0x0 // dy, inner loop + + movi v25.2d, #0 + movi v24.2d, #0 + movi v26.2d, #0 + movi v28.2d, #0 + movi v27.2d, #0 + b 8f + +5: + // add line(-1) and line0 from previous results + bdof_vx_vy_16x_add_line v19, v20, v21, v22, v23 + bdof_vx_vy_16x_add_line v6, v7, v16, v17, v18 + add w14, w14, #0x1 + + 8: + cmp w13, w6 + b.hs 9f + // y < block_h && dy == 0, reuse previous results + cbz w14, 5b +9: + ld1 {v29.8h, v30.8h}, [x0] // src0 + sshr v31.8h, v29.8h, #0x4 + ld1 {v8.8h, v9.8h}, [x1] // src1 + sshr v10.8h, v8.8h, #0x4 + ldp q13, q8, [x2], #32 // (gh0 + gh1) >> 1 + sshr v29.8h, v30.8h, #0x4 + sshr v30.8h, v9.8h, #0x4 + ldp q5, q3, [x3], #32 // (gv0 + gv1) >> 1 + sub v31.8h, v31.8h, v10.8h // diff, left half + sub v4.8h, v29.8h, v30.8h // diff, right half + + abs v29.8h, v13.8h + abs v30.8h, v8.8h + abs v9.8h, v5.8h + abs v10.8h, v3.8h + + add x0, x0, #(VVC_MAX_PB_SIZE * 2) + add x1, x1, #(VVC_MAX_PB_SIZE * 2) + + bdof_vx_vy_16x_padding_left_right v29, v30, v11, v12, v14, v29 + bdof_vx_vy_16x_padding_left_right v9, v10, v11, v12, v14, v30 + + bdof_vx_vy_sign v13, v9, v10, v9 + bdof_vx_vy_sign v8, v10, v11, v10 + bdof_vx_vy_sign v5, v11, v5, v5 + bdof_vx_vy_sign v3, v11, v3, v3 + + mul v11.8h, v5.8h, v13.8h + mul v12.8h, v3.8h, v8.8h + mul v8.8h, v9.8h, v31.8h + mul v9.8h, v10.8h, v4.8h + mul v13.8h, v5.8h, v31.8h + mul v14.8h, v3.8h, v4.8h + + bdof_vx_vy_16x_padding_left_right v11, v12, v3, v4, v5, v31 + bdof_vx_vy_16x_padding_left_right v8, v9, v3, v4, v5, v8 + bdof_vx_vy_16x_padding_left_right v13, v14, v3, v4, v5, v9 + + bdof_vx_vy_16x_add_line v29, v30, v31, v8, v9 + // check whether padding top + cmp w13, w6 + b.ne 10f + cbnz w14, 10f + // y == block_h && dy == 0, padding top + bdof_vx_vy_16x_add_line v29, v30, v31, v8, v9 + add w14, w14, #0x1 + b 9b +10: + cmp w14, #(BDOF_MIN_BLOCK_SIZE - 1) + b.eq 11f + cmp w14, #(BDOF_MIN_BLOCK_SIZE) + b.ne 12f + // save line4 + b 1b + 11: + // y == BDOF_MIN_BLOCK_SIZE && dy == BDOF_MIN_BLOCK_SIZE - 1, padding bottom + cmp x13, #(BDOF_MIN_BLOCK_SIZE) + b.eq 13f + // save line3 + bdof_vx_vy_16x_save_line v19, v20, v21, v22, v23 +12: + add w14, w14, #0x1 // dy++ + b 8b +13: + // padding bottom + bdof_vx_vy_16x_add_line v29, v30, v31, v8, v9 + b 2b +16: + // restore + ldp d9, d8, [sp, #0x30] + ldp d11, d10, [sp, #0x20] + ldp d13, d12, [sp, #0x10] + ldp d15, d14, [sp], #0x40 + ret +endfunc + +function ff_vvc_apply_bdof_10_neon, export=1 + mov w6, #10 + b 0f +endfunc + +function ff_vvc_apply_bdof_12_neon, export=1 + mov w6, #12 + b 0f +endfunc + +// int16_t gradient_buf_h[2][BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE + 2] +// int16_t gradient_buf_v[2][BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE + 2] +// int16_t vx[BDOF_BLOCK_SIZE], vy[BDOF_BLOCK_SIZE]; +#define APPLY_BDOF_STACK_SIZE ((BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE + 2) * 8 + BDOF_BLOCK_SIZE * 4) +#define GRADIENT_H0_OFFSET 2 +#define GRADIENT_H1_OFFSET ((BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE + 2) * 2 + 2) +#define GRADIENT_V0_OFFSET ((BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE + 2) * 4 + 2) +#define GRADIENT_V1_OFFSET ((BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE + 2) * 6 + 2) +#define VX_OFFSET ((BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE + 2) * 8) +#define VY_OFFSET ((BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE + 2) * 8 + BDOF_BLOCK_SIZE * 2) +function ff_vvc_apply_bdof_8_neon, export=1 + mov w6, #8 +0: + stp x19, x20, [sp, #-0x40]! + stp x21, x22, [sp, #0x10] + stp x23, x24, [sp, #0x20] + stp x25, x30, [sp, #0x30] + + sub sp, sp, #APPLY_BDOF_STACK_SIZE + mov w19, w6 // bit_depth + mov x20, x0 // dst + mov x21, x1 // dst_stride + mov x22, x2 // src0 + mov x23, x3 // src1 + mov w24, w4 // block_w + mov w25, w5 // block_h + + // int16_t *gradient_h[2] = {&gradient_buf_h[0][1], &gradient_buf_h[1][1]}; + add x0, sp, #GRADIENT_H0_OFFSET + add x1, sp, #GRADIENT_H1_OFFSET + add x2, sp, #GRADIENT_V0_OFFSET + add x3, sp, #GRADIENT_V1_OFFSET + mov x4, x22 + mov x5, x23 + mov w6, w24 + mov w7, w25 + bl vvc_bdof_grad_filter_8x_neon + + cmp w24, #8 + mov x0, x22 // src0 + mov x1, x23 // src1 + add x2, sp, #GRADIENT_H0_OFFSET // gh0 + add x3, sp, #GRADIENT_V0_OFFSET // gv0 + add x4, sp, #VX_OFFSET // vx + add x5, sp, #VY_OFFSET // vy + mov w6, w25 // block_h + + b.gt 16f + + bl vvc_derive_bdof_vx_vy_8x_neon + cmp w19, #10 // check bitdepth + mov x0, x20 // dst + mov x1, x21 // dst_stride + mov x2, x22 // src0 + mov x3, x23 // src1 + add x4, sp, #GRADIENT_H1_OFFSET // gh1 + add x5, sp, #GRADIENT_V1_OFFSET // gv1 + add x6, sp, #VX_OFFSET + add x7, sp, #VY_OFFSET + str w25, [sp] + b.eq 1f + b.gt 2f + // 8bit +0: + bl vvc_apply_bdof_block_8x_8_neon + b 32f +1: + // 10bit + bl vvc_apply_bdof_block_8x_10_neon + b 32f +2: + // 12bit + bl vvc_apply_bdof_block_8x_12_neon + b 32f +16: + bl vvc_derive_bdof_vx_vy_16x_neon + + cmp w19, #10 // check bitdepth + mov x0, x20 // dst + mov x1, x21 // dst_stride + mov x2, x22 // src0 + mov x3, x23 // src1 + add x4, sp, #GRADIENT_H1_OFFSET // gh1 + add x5, sp, #GRADIENT_V1_OFFSET // gv1 + add x6, sp, #VX_OFFSET + add x7, sp, #VY_OFFSET + str w25, [sp] + b.eq 17f + b.gt 18f + // 8bit + bl vvc_apply_bdof_block_16x_8_neon + b 32f +17: + // 10bit + bl vvc_apply_bdof_block_16x_10_neon + b 32f +18: + // 12bit + bl vvc_apply_bdof_block_16x_12_neon +32: + add sp, sp, #APPLY_BDOF_STACK_SIZE + ldp x25, x30, [sp, #0x30] + ldp x23, x24, [sp, #0x20] + ldp x21, x22, [sp, #0x10] + ldp x19, x20, [sp], #0x40 + ret +endfunc + +#undef APPLY_BDOF_STACK_SIZE +#undef GRADIENT_H0_OFFSET +#undef GRADIENT_H1_OFFSET +#undef GRADIENT_V0_OFFSET +#undef GRADIENT_V1_OFFSET +#undef VX_OFFSET +#undef VY_OFFSET + +#define VVC_MAX_PB_SIZE 128 + +.macro put_luma_h_x8_vector_filter shift + // 8 bytes from hf loaded to v0.8h + // 32 bytes from _src loaded to v20.8h & v21.8h where v21.8h is loaded for shift to v1.8h,..,v6.8h,v17.8h + // v24.4h & v25.4h are output vectors to store + ext v1.16b, v20.16b, v21.16b, #2 + ext v2.16b, v20.16b, v21.16b, #4 + ext v3.16b, v20.16b, v21.16b, #6 + ext v4.16b, v20.16b, v21.16b, #8 + ext v5.16b, v20.16b, v21.16b, #10 + ext v6.16b, v20.16b, v21.16b, #12 + ext v17.16b, v20.16b, v21.16b, #14 + smull v24.4s, v20.4h, v0.h[0] + smull2 v25.4s, v20.8h, v0.h[0] + smlal v24.4s, v1.4h, v0.h[1] + smlal2 v25.4s, v1.8h, v0.h[1] + smlal v24.4s, v2.4h, v0.h[2] + smlal2 v25.4s, v2.8h, v0.h[2] + smlal v24.4s, v3.4h, v0.h[3] + smlal2 v25.4s, v3.8h, v0.h[3] + smlal v24.4s, v4.4h, v0.h[4] + smlal2 v25.4s, v4.8h, v0.h[4] + smlal v24.4s, v5.4h, v0.h[5] + smlal2 v25.4s, v5.8h, v0.h[5] + smlal v24.4s, v6.4h, v0.h[6] + smlal2 v25.4s, v6.8h, v0.h[6] + smlal v24.4s, v17.4h, v0.h[7] + smlal2 v25.4s, v17.8h, v0.h[7] + sqshrn v24.4h, v24.4s, #(\shift) + sqshrn v25.4h, v25.4s, #(\shift) +.endm + +.macro put_luma_h8_xx_neon shift + mov x9, #(VVC_MAX_PB_SIZE * 2) + ld1 {v0.8b}, [x4] + sub x1, x1, #6 + sxtl v0.8h, v0.8b +1: + ld1 {v20.8h, v21.8h}, [x1], x2 + put_luma_h_x8_vector_filter \shift + subs w3, w3, #1 + st1 {v24.4h, v25.4h}, [x0], x9 + b.gt 1b + ret +.endm + +.macro put_luma_h16_xx_neon shift + mov x9, #(VVC_MAX_PB_SIZE * 2) + ld1 {v0.8b}, [x4] + sub x9, x9, #16 + sub x1, x1, #6 + sxtl v0.8h, v0.8b +1: + ld1 {v20.8h, v21.8h, v22.8h}, [x1], x2 + put_luma_h_x8_vector_filter \shift + mov v20.16b, v21.16b + mov v21.16b, v22.16b + st1 {v24.4h, v25.4h}, [x0], #16 + put_luma_h_x8_vector_filter \shift + subs w3, w3, #1 + st1 {v24.4h, v25.4h}, [x0], x9 + b.gt 1b + ret +.endm + +.macro put_luma_h_x16_xx_neon shift + mov x9, #(VVC_MAX_PB_SIZE * 2) + ld1 {v0.8b}, [x4] + sub x9, x9, w6, uxtw #1 + sub x2, x2, w6, uxtw #1 + sxtl v0.8h, v0.8b + sub x1, x1, #6 + sub x2, x2, #16 +1: + ld1 {v20.8h}, [x1], #16 + mov w8, w6 +2: + ld1 {v21.8h, v22.8h}, [x1], #32 + put_luma_h_x8_vector_filter \shift + mov v20.16b, v21.16b + mov v21.16b, v22.16b + st1 {v24.4h, v25.4h}, [x0], #16 + put_luma_h_x8_vector_filter \shift + mov v20.16b, v21.16b + subs w8, w8, #16 + st1 {v24.4h, v25.4h}, [x0], #16 + b.gt 2b + subs w3, w3, #1 + add x0, x0, x9 + add x1, x1, x2 + b.gt 1b + ret +.endm + +function ff_vvc_put_luma_h8_10_neon, export=1 + put_luma_h8_xx_neon 2 +endfunc + +function ff_vvc_put_luma_h8_12_neon, export=1 + put_luma_h8_xx_neon 4 +endfunc + +function ff_vvc_put_luma_h16_10_neon, export=1 + put_luma_h16_xx_neon 2 +endfunc + +function ff_vvc_put_luma_h16_12_neon, export=1 + put_luma_h16_xx_neon 4 +endfunc + +function ff_vvc_put_luma_h_x16_10_neon, export=1 + put_luma_h_x16_xx_neon 2 +endfunc + +function ff_vvc_put_luma_h_x16_12_neon, export=1 + put_luma_h_x16_xx_neon 4 +endfunc + +.macro put_luma_v4_xx_neon shift + mov x9, #(VVC_MAX_PB_SIZE * 2) + sub x1, x1, x2, lsl #1 + ld1 {v0.8b}, [x5] + sub x1, x1, x2 + sxtl v0.8h, v0.8b + ld1 {v20.4h}, [x1], x2 + ld1 {v21.4h}, [x1], x2 + ld1 {v22.4h}, [x1], x2 + ld1 {v23.4h}, [x1], x2 + ld1 {v24.4h}, [x1], x2 + ld1 {v25.4h}, [x1], x2 + ld1 {v26.4h}, [x1], x2 +1: + ld1 {v27.4h}, [x1], x2 + + smull v1.4s, v20.4h, v0.h[0] + smull v2.4s, v21.4h, v0.h[1] + smlal v1.4s, v22.4h, v0.h[2] + smlal v2.4s, v23.4h, v0.h[3] + smlal v1.4s, v24.4h, v0.h[4] + smlal v2.4s, v25.4h, v0.h[5] + smlal v1.4s, v26.4h, v0.h[6] + smlal v2.4s, v27.4h, v0.h[7] + + ld1 {v28.4h}, [x1], x2 + + smull v3.4s, v21.4h, v0.h[0] + smull v4.4s, v22.4h, v0.h[1] + smlal v3.4s, v23.4h, v0.h[2] + smlal v4.4s, v24.4h, v0.h[3] + smlal v3.4s, v25.4h, v0.h[4] + smlal v4.4s, v26.4h, v0.h[5] + smlal v3.4s, v27.4h, v0.h[6] + smlal v4.4s, v28.4h, v0.h[7] + add v1.4s, v1.4s, v2.4s + add v3.4s, v3.4s, v4.4s + sqshrn v1.4h, v1.4s, #(\shift) + sqshrn v3.4h, v3.4s, #(\shift) + + st1 {v1.4h}, [x0], x9 + ld1 {v29.4h}, [x1], x2 + st1 {v3.4h}, [x0], x9 + + smull v1.4s, v22.4h, v0.h[0] + smull v2.4s, v23.4h, v0.h[1] + smlal v1.4s, v24.4h, v0.h[2] + smlal v2.4s, v25.4h, v0.h[3] + smlal v1.4s, v26.4h, v0.h[4] + smlal v2.4s, v27.4h, v0.h[5] + smlal v1.4s, v28.4h, v0.h[6] + smlal v2.4s, v29.4h, v0.h[7] + + ld1 {v30.4h}, [x1], x2 + + smull v3.4s, v23.4h, v0.h[0] + smull v4.4s, v24.4h, v0.h[1] + smlal v3.4s, v25.4h, v0.h[2] + smlal v4.4s, v26.4h, v0.h[3] + smlal v3.4s, v27.4h, v0.h[4] + smlal v4.4s, v28.4h, v0.h[5] + smlal v3.4s, v29.4h, v0.h[6] + smlal v4.4s, v30.4h, v0.h[7] + add v1.4s, v1.4s, v2.4s + add v3.4s, v3.4s, v4.4s + sqshrn v1.4h, v1.4s, #(\shift) + sqshrn v3.4h, v3.4s, #(\shift) + + st1 {v1.4h}, [x0], x9 + + mov v20.16b, v24.16b + mov v21.16b, v25.16b + mov v22.16b, v26.16b + mov v23.16b, v27.16b + mov v24.16b, v28.16b + mov v25.16b, v29.16b + mov v26.16b, v30.16b + + subs w3, w3, #4 + st1 {v3.4h}, [x0], x9 + b.gt 1b + ret +.endm + +function ff_vvc_put_luma_v4_10_neon, export=1 + put_luma_v4_xx_neon 2 +endfunc + +function ff_vvc_put_luma_v4_12_neon, export=1 + put_luma_v4_xx_neon 4 +endfunc + +.macro put_luma_v8_xx_neon shift + mov x9, #(VVC_MAX_PB_SIZE * 2) + sub x1, x1, x2, lsl #1 + ld1 {v0.8b}, [x5] + sub x1, x1, x2 + sxtl v0.8h, v0.8b + ld1 {v20.8h}, [x1], x2 + ld1 {v21.8h}, [x1], x2 + ld1 {v22.8h}, [x1], x2 + ld1 {v23.8h}, [x1], x2 + ld1 {v24.8h}, [x1], x2 + ld1 {v25.8h}, [x1], x2 + ld1 {v26.8h}, [x1], x2 +1: + ld1 {v27.8h}, [x1], x2 + + smull v1.4s, v20.4h, v0.h[0] + smull2 v2.4s, v20.8h, v0.h[0] + smlal v1.4s, v21.4h, v0.h[1] + smlal2 v2.4s, v21.8h, v0.h[1] + smlal v1.4s, v22.4h, v0.h[2] + smlal2 v2.4s, v22.8h, v0.h[2] + smlal v1.4s, v23.4h, v0.h[3] + smlal2 v2.4s, v23.8h, v0.h[3] + smlal v1.4s, v24.4h, v0.h[4] + smlal2 v2.4s, v24.8h, v0.h[4] + smlal v1.4s, v25.4h, v0.h[5] + smlal2 v2.4s, v25.8h, v0.h[5] + smlal v1.4s, v26.4h, v0.h[6] + smlal2 v2.4s, v26.8h, v0.h[6] + smlal v1.4s, v27.4h, v0.h[7] + smlal2 v2.4s, v27.8h, v0.h[7] + sqshrn v1.4h, v1.4s, #(\shift) + sqshrn v2.4h, v2.4s, #(\shift) + + ld1 {v28.8h}, [x1], x2 + st1 {v1.4h-v2.4h}, [x0], x9 + + smull v3.4s, v21.4h, v0.h[0] + smull2 v4.4s, v21.8h, v0.h[0] + smlal v3.4s, v22.4h, v0.h[1] + smlal2 v4.4s, v22.8h, v0.h[1] + smlal v3.4s, v23.4h, v0.h[2] + smlal2 v4.4s, v23.8h, v0.h[2] + smlal v3.4s, v24.4h, v0.h[3] + smlal2 v4.4s, v24.8h, v0.h[3] + smlal v3.4s, v25.4h, v0.h[4] + smlal2 v4.4s, v25.8h, v0.h[4] + smlal v3.4s, v26.4h, v0.h[5] + smlal2 v4.4s, v26.8h, v0.h[5] + smlal v3.4s, v27.4h, v0.h[6] + smlal2 v4.4s, v27.8h, v0.h[6] + smlal v3.4s, v28.4h, v0.h[7] + smlal2 v4.4s, v28.8h, v0.h[7] + sqshrn v3.4h, v3.4s, #(\shift) + sqshrn v4.4h, v4.4s, #(\shift) + + ld1 {v29.8h}, [x1], x2 + st1 {v3.4h-v4.4h}, [x0], x9 + + smull v1.4s, v22.4h, v0.h[0] + smull2 v2.4s, v22.8h, v0.h[0] + smlal v1.4s, v23.4h, v0.h[1] + smlal2 v2.4s, v23.8h, v0.h[1] + smlal v1.4s, v24.4h, v0.h[2] + smlal2 v2.4s, v24.8h, v0.h[2] + smlal v1.4s, v25.4h, v0.h[3] + smlal2 v2.4s, v25.8h, v0.h[3] + smlal v1.4s, v26.4h, v0.h[4] + smlal2 v2.4s, v26.8h, v0.h[4] + smlal v1.4s, v27.4h, v0.h[5] + smlal2 v2.4s, v27.8h, v0.h[5] + smlal v1.4s, v28.4h, v0.h[6] + smlal2 v2.4s, v28.8h, v0.h[6] + smlal v1.4s, v29.4h, v0.h[7] + smlal2 v2.4s, v29.8h, v0.h[7] + sqshrn v1.4h, v1.4s, #(\shift) + sqshrn v2.4h, v2.4s, #(\shift) + + ld1 {v30.8h}, [x1], x2 + st1 {v1.4h-v2.4h}, [x0], x9 + + smull v3.4s, v23.4h, v0.h[0] + smull2 v4.4s, v23.8h, v0.h[0] + smlal v3.4s, v24.4h, v0.h[1] + smlal2 v4.4s, v24.8h, v0.h[1] + smlal v3.4s, v25.4h, v0.h[2] + smlal2 v4.4s, v25.8h, v0.h[2] + smlal v3.4s, v26.4h, v0.h[3] + smlal2 v4.4s, v26.8h, v0.h[3] + smlal v3.4s, v27.4h, v0.h[4] + smlal2 v4.4s, v27.8h, v0.h[4] + smlal v3.4s, v28.4h, v0.h[5] + smlal2 v4.4s, v28.8h, v0.h[5] + smlal v3.4s, v29.4h, v0.h[6] + smlal2 v4.4s, v29.8h, v0.h[6] + smlal v3.4s, v30.4h, v0.h[7] + smlal2 v4.4s, v30.8h, v0.h[7] + sqshrn v3.4h, v3.4s, #(\shift) + sqshrn v4.4h, v4.4s, #(\shift) + + mov v20.16b, v24.16b + mov v21.16b, v25.16b + mov v22.16b, v26.16b + mov v23.16b, v27.16b + mov v24.16b, v28.16b + mov v25.16b, v29.16b + mov v26.16b, v30.16b + + subs w3, w3, #4 + st1 {v3.4h-v4.4h}, [x0], x9 + b.gt 1b + ret +.endm + +function ff_vvc_put_luma_v8_10_neon, export=1 + put_luma_v8_xx_neon 2 +endfunc + +function ff_vvc_put_luma_v8_12_neon, export=1 + put_luma_v8_xx_neon 4 +endfunc + +.macro put_luma_v_x16_vector_filter shift + smull v2.4s, v16.4h, v1.h[0] + smull2 v3.4s, v16.8h, v1.h[0] + smlal v2.4s, v18.4h, v1.h[1] + smlal2 v3.4s, v18.8h, v1.h[1] + smlal v2.4s, v20.4h, v1.h[2] + smlal2 v3.4s, v20.8h, v1.h[2] + smlal v2.4s, v22.4h, v1.h[3] + smlal2 v3.4s, v22.8h, v1.h[3] + smlal v2.4s, v24.4h, v1.h[4] + smlal2 v3.4s, v24.8h, v1.h[4] + smlal v2.4s, v26.4h, v1.h[5] + smlal2 v3.4s, v26.8h, v1.h[5] + smlal v2.4s, v28.4h, v1.h[6] + smlal2 v3.4s, v28.8h, v1.h[6] + smlal v2.4s, v30.4h, v1.h[7] + smlal2 v3.4s, v30.8h, v1.h[7] + + smull v4.4s, v17.4h, v1.h[0] + smull2 v5.4s, v17.8h, v1.h[0] + smlal v4.4s, v19.4h, v1.h[1] + smlal2 v5.4s, v19.8h, v1.h[1] + smlal v4.4s, v21.4h, v1.h[2] + smlal2 v5.4s, v21.8h, v1.h[2] + smlal v4.4s, v23.4h, v1.h[3] + smlal2 v5.4s, v23.8h, v1.h[3] + smlal v4.4s, v25.4h, v1.h[4] + smlal2 v5.4s, v25.8h, v1.h[4] + smlal v4.4s, v27.4h, v1.h[5] + smlal2 v5.4s, v27.8h, v1.h[5] + smlal v4.4s, v29.4h, v1.h[6] + smlal2 v5.4s, v29.8h, v1.h[6] + smlal v4.4s, v31.4h, v1.h[7] + smlal2 v5.4s, v31.8h, v1.h[7] + + sqshrn v6.4h, v2.4s, #(\shift) + sqshrn v7.4h, v4.4s, #(\shift) + sqshrn2 v6.8h, v3.4s, #(\shift) + sqshrn2 v7.8h, v5.4s, #(\shift) +.endm + +.macro put_luma_v16_xx_neon shift + mov x9, #(VVC_MAX_PB_SIZE * 2) + sub x1, x1, x2, lsl #1 + ld1 {v0.8b}, [x5] + sub x1, x1, x2 + sxtl v0.8h, v0.8b + ld1 {v16.8h-v17.8h}, [x1], x2 + ld1 {v18.8h-v19.8h}, [x1], x2 + ld1 {v20.8h-v21.8h}, [x1], x2 + ld1 {v22.8h-v23.8h}, [x1], x2 + ld1 {v24.8h-v25.8h}, [x1], x2 + ld1 {v26.8h-v27.8h}, [x1], x2 + ld1 {v28.8h-v29.8h}, [x1], x2 +1: + mov v1.16b, v0.16b + ld1 {v30.8h-v31.8h}, [x1], x2 + + put_luma_v_x16_vector_filter \shift + + ld1 {v16.8h-v17.8h}, [x1], x2 + ext v1.16b, v0.16b, v0.16b, #14 + st1 {v6.8h-v7.8h}, [x0], x9 + + put_luma_v_x16_vector_filter \shift + + ld1 {v18.8h-v19.8h}, [x1], x2 + ext v1.16b, v0.16b, v0.16b, #12 + st1 {v6.8h-v7.8h}, [x0], x9 + + put_luma_v_x16_vector_filter \shift + + ld1 {v20.8h-v21.8h}, [x1], x2 + ext v1.16b, v0.16b, v0.16b, #10 + st1 {v6.8h-v7.8h}, [x0], x9 + + put_luma_v_x16_vector_filter \shift + + subs w3, w3, #4 + st1 {v6.8h-v7.8h}, [x0], x9 + + mov v2.16b, v16.16b + mov v3.16b, v17.16b + mov v16.16b, v24.16b + mov v17.16b, v25.16b + mov v24.16b, v2.16b + mov v25.16b, v3.16b + + mov v2.16b, v18.16b + mov v3.16b, v19.16b + mov v18.16b, v26.16b + mov v19.16b, v27.16b + mov v26.16b, v2.16b + mov v27.16b, v3.16b + + mov v2.16b, v20.16b + mov v3.16b, v21.16b + mov v20.16b, v28.16b + mov v21.16b, v29.16b + mov v28.16b, v2.16b + mov v29.16b, v3.16b + + mov v22.16b, v30.16b + mov v23.16b, v31.16b + b.gt 1b + ret +.endm + +function ff_vvc_put_luma_v16_10_neon, export=1 + put_luma_v16_xx_neon 2 +endfunc + +function ff_vvc_put_luma_v16_12_neon, export=1 + put_luma_v16_xx_neon 4 +endfunc + + +.macro put_luma_v_x16_xx_neon shift + mov x9, #(VVC_MAX_PB_SIZE * 2) + sub x1, x1, x2, lsl #1 + ld1 {v0.8b}, [x5] + sub x1, x1, x2 + sxtl v0.8h, v0.8b +1: + mov w8, #0 +2: + add x11, x1, x8, lsl #1 + add x10, x0, x8, lsl #1 + ld1 {v16.8h-v17.8h}, [x11], x2 + add x8, x8, #16 + ld1 {v18.8h-v19.8h}, [x11], x2 + cmp w8, w6 + ld1 {v20.8h-v21.8h}, [x11], x2 + mov v1.16b, v0.16b + ld1 {v22.8h-v23.8h}, [x11], x2 + ld1 {v24.8h-v25.8h}, [x11], x2 + ld1 {v26.8h-v27.8h}, [x11], x2 + ld1 {v28.8h-v29.8h}, [x11], x2 + ld1 {v30.8h-v31.8h}, [x11], x2 + + put_luma_v_x16_vector_filter \shift + + ld1 {v16.8h-v17.8h}, [x11], x2 + ext v1.16b, v0.16b, v0.16b, #14 + st1 {v6.8h-v7.8h}, [x10], x9 + + put_luma_v_x16_vector_filter \shift + + st1 {v6.8h-v7.8h}, [x10], x9 + ext v1.16b, v0.16b, v0.16b, #12 + ld1 {v18.8h-v19.8h}, [x11], x2 + + put_luma_v_x16_vector_filter \shift + + ld1 {v20.8h-v21.8h}, [x11], x2 + ext v1.16b, v0.16b, v0.16b, #10 + st1 {v6.8h-v7.8h}, [x10], x9 + + put_luma_v_x16_vector_filter \shift + + st1 {v6.8h-v7.8h}, [x10], x9 + b.lt 2b + add x0, x0, x9, lsl #2 + subs w3, w3, #4 + add x1, x1, x2, lsl #2 + b.gt 1b + ret +.endm + +function ff_vvc_put_luma_v_x16_10_neon, export=1 + put_luma_v_x16_xx_neon 2 +endfunc + +function ff_vvc_put_luma_v_x16_12_neon, export=1 + put_luma_v_x16_xx_neon 4 +endfunc + + +.macro put_luma_hv_x8_horizontal_filter shift, dst, src0, src1 + ext v2.16b, \src0\().16b, \src1\().16b, #2 + ext v3.16b, \src0\().16b, \src1\().16b, #4 + ext v4.16b, \src0\().16b, \src1\().16b, #6 + ext v5.16b, \src0\().16b, \src1\().16b, #8 + smull v6.4s, \src0\().4h, v0.h[0] + smull2 v7.4s, \src0\().8h, v0.h[0] + smlal v6.4s, v2.4h, v0.h[1] + smlal2 v7.4s, v2.8h, v0.h[1] + smlal v6.4s, v3.4h, v0.h[2] + smlal2 v7.4s, v3.8h, v0.h[2] + smlal v6.4s, v4.4h, v0.h[3] + smlal2 v7.4s, v4.8h, v0.h[3] + smlal v6.4s, v5.4h, v0.h[4] + smlal2 v7.4s, v5.8h, v0.h[4] + ext v2.16b, \src0\().16b, \src1\().16b, #10 + ext v3.16b, \src0\().16b, \src1\().16b, #12 + ext v4.16b, \src0\().16b, \src1\().16b, #14 + smlal v6.4s, v2.4h, v0.h[5] + smlal2 v7.4s, v2.8h, v0.h[5] + smlal v6.4s, v3.4h, v0.h[6] + smlal2 v7.4s, v3.8h, v0.h[6] + smlal v6.4s, v4.4h, v0.h[7] + smlal2 v7.4s, v4.8h, v0.h[7] + sqshrn \dst\().4h, v6.4s, #(\shift) + sqshrn2 \dst\().8h, v7.4s, #(\shift) +.endm + +.macro put_luma_hv_x8_vertical_filter dst0, dst1, src0, src1, src2, src3, src4, src5, src6, src7 + smull \dst0\().4s, \src0\().4h, v1.h[0] + smull2 \dst1\().4s, \src0\().8h, v1.h[0] + smlal \dst0\().4s, \src1\().4h, v1.h[1] + smlal2 \dst1\().4s, \src1\().8h, v1.h[1] + smlal \dst0\().4s, \src2\().4h, v1.h[2] + smlal2 \dst1\().4s, \src2\().8h, v1.h[2] + smlal \dst0\().4s, \src3\().4h, v1.h[3] + smlal2 \dst1\().4s, \src3\().8h, v1.h[3] + smlal \dst0\().4s, \src4\().4h, v1.h[4] + smlal2 \dst1\().4s, \src4\().8h, v1.h[4] + smlal \dst0\().4s, \src5\().4h, v1.h[5] + smlal2 \dst1\().4s, \src5\().8h, v1.h[5] + smlal \dst0\().4s, \src6\().4h, v1.h[6] + smlal2 \dst1\().4s, \src6\().8h, v1.h[6] + smlal \dst0\().4s, \src7\().4h, v1.h[7] + smlal2 \dst1\().4s, \src7\().8h, v1.h[7] + sqshrn \dst0\().4h, \dst0\().4s, #6 + sqshrn \dst1\().4h, \dst1\().4s, #6 +.endm + +.macro put_luma_hv8_xx_neon shift + // dst .req x0 + // _src .req x1 + // _src_stride .req x2 + // height .req x3 + // hf .req x4 + // vf .req x5 + // width .req x6 + mov x9, #(VVC_MAX_PB_SIZE * 2) + sub x1, x1, #6 + ld1 {v0.8b}, [x4] + sub x1, x1, x2, lsl #1 + sxtl v0.8h, v0.8b + ld1 {v1.8b}, [x5] + sub x1, x1, x2 + sxtl v1.8h, v1.8b + ld1 {v16.8h, v17.8h}, [x1], x2 + ld1 {v18.8h, v19.8h}, [x1], x2 + ld1 {v20.8h, v21.8h}, [x1], x2 + ld1 {v22.8h, v23.8h}, [x1], x2 + ld1 {v24.8h, v25.8h}, [x1], x2 + ld1 {v26.8h, v27.8h}, [x1], x2 + ld1 {v28.8h, v29.8h}, [x1], x2 + put_luma_hv_x8_horizontal_filter \shift, v16, v16, v17 + put_luma_hv_x8_horizontal_filter \shift, v18, v18, v19 + put_luma_hv_x8_horizontal_filter \shift, v20, v20, v21 + put_luma_hv_x8_horizontal_filter \shift, v22, v22, v23 + put_luma_hv_x8_horizontal_filter \shift, v24, v24, v25 + put_luma_hv_x8_horizontal_filter \shift, v26, v26, v27 + put_luma_hv_x8_horizontal_filter \shift, v28, v28, v29 +1: + ld1 {v30.8h, v31.8h}, [x1], x2 + put_luma_hv_x8_horizontal_filter \shift, v30, v30, v31 + put_luma_hv_x8_vertical_filter v2, v3, v16, v18, v20, v22, v24, v26, v28, v30 + ld1 {v16.8h, v17.8h}, [x1], x2 + st1 {v2.4h-v3.4h}, [x0], x9 + put_luma_hv_x8_horizontal_filter \shift, v16, v16, v17 + put_luma_hv_x8_vertical_filter v2, v3, v18, v20, v22, v24, v26, v28, v30, v16 + ld1 {v18.8h, v19.8h}, [x1], x2 + st1 {v2.4h-v3.4h}, [x0], x9 + put_luma_hv_x8_horizontal_filter \shift, v18, v18, v19 + put_luma_hv_x8_vertical_filter v2, v3, v20, v22, v24, v26, v28, v30, v16, v18 + ld1 {v20.8h, v21.8h}, [x1], x2 + st1 {v2.4h-v3.4h}, [x0], x9 + put_luma_hv_x8_horizontal_filter \shift, v20, v20, v21 + put_luma_hv_x8_vertical_filter v2, v3, v22, v24, v26, v28, v30, v16, v18, v20 + st1 {v2.4h-v3.4h}, [x0], x9 + + mov v17.16b, v16.16b + mov v16.16b, v24.16b + mov v24.16b, v17.16b + mov v19.16b, v18.16b + mov v18.16b, v26.16b + mov v26.16b, v19.16b + mov v21.16b, v20.16b + mov v20.16b, v28.16b + mov v28.16b, v21.16b + subs w3, w3, #4 + mov v22.16b, v30.16b + b.gt 1b + ret +.endm + +function ff_vvc_put_luma_hv8_10_neon, export=1 + put_luma_hv8_xx_neon 2 +endfunc + +function ff_vvc_put_luma_hv8_12_neon, export=1 + put_luma_hv8_xx_neon 4 +endfunc + +.macro put_luma_hv16_xx_neon shift + // dst .req x0 + // _src .req x1 + // _src_stride .req x2 + // height .req x3 + // hf .req x4 + // vf .req x5 + // width .req x6 + stp d8, d9, [sp, #-64]! + stp d10, d11, [sp, #16] + stp d12, d13, [sp, #32] + stp d14, d15, [sp, #48] + + mov x9, #(VVC_MAX_PB_SIZE * 2) + sub x1, x1, #6 + ld1 {v0.8b}, [x4] + sub x1, x1, x2, lsl #1 + sxtl v0.8h, v0.8b + ld1 {v1.8b}, [x5] + sub x1, x1, x2 + sxtl v1.8h, v1.8b + ld1 {v8.8h, v9.8h, v10.8h}, [x1], x2 + ld1 {v11.8h, v12.8h, v13.8h}, [x1], x2 + ld1 {v14.8h, v15.8h, v16.8h}, [x1], x2 + ld1 {v17.8h, v18.8h, v19.8h}, [x1], x2 + ld1 {v20.8h, v21.8h, v22.8h}, [x1], x2 + ld1 {v23.8h, v24.8h, v25.8h}, [x1], x2 + ld1 {v26.8h, v27.8h, v28.8h}, [x1], x2 + put_luma_hv_x8_horizontal_filter \shift, v8, v8, v9 + put_luma_hv_x8_horizontal_filter \shift, v9, v9, v10 + put_luma_hv_x8_horizontal_filter \shift, v11, v11, v12 + put_luma_hv_x8_horizontal_filter \shift, v12, v12, v13 + put_luma_hv_x8_horizontal_filter \shift, v14, v14, v15 + put_luma_hv_x8_horizontal_filter \shift, v15, v15, v16 + put_luma_hv_x8_horizontal_filter \shift, v17, v17, v18 + put_luma_hv_x8_horizontal_filter \shift, v18, v18, v19 + put_luma_hv_x8_horizontal_filter \shift, v20, v20, v21 + put_luma_hv_x8_horizontal_filter \shift, v21, v21, v22 + put_luma_hv_x8_horizontal_filter \shift, v23, v23, v24 + put_luma_hv_x8_horizontal_filter \shift, v24, v24, v25 + put_luma_hv_x8_horizontal_filter \shift, v26, v26, v27 + put_luma_hv_x8_horizontal_filter \shift, v27, v27, v28 +1: + ld1 {v29.8h, v30.8h, v31.8h}, [x1], x2 + put_luma_hv_x8_horizontal_filter \shift, v29, v29, v30 + put_luma_hv_x8_horizontal_filter \shift, v30, v30, v31 + put_luma_hv_x8_vertical_filter v2, v3, v8, v11, v14, v17, v20, v23, v26, v29 + put_luma_hv_x8_vertical_filter v4, v5, v9, v12, v15, v18, v21, v24, v27, v30 + ld1 {v8.8h, v9.8h, v10.8h}, [x1], x2 + st1 {v2.4h-v5.4h}, [x0], x9 + put_luma_hv_x8_horizontal_filter \shift, v8, v8, v9 + put_luma_hv_x8_horizontal_filter \shift, v9, v9, v10 + put_luma_hv_x8_vertical_filter v2, v3, v11, v14, v17, v20, v23, v26, v29, v8 + put_luma_hv_x8_vertical_filter v4, v5, v12, v15, v18, v21, v24, v27, v30, v9 + ld1 {v11.8h, v12.8h, v13.8h}, [x1], x2 + st1 {v2.4h-v5.4h}, [x0], x9 + put_luma_hv_x8_horizontal_filter \shift, v11, v11, v12 + put_luma_hv_x8_horizontal_filter \shift, v12, v12, v13 + put_luma_hv_x8_vertical_filter v2, v3, v14, v17, v20, v23, v26, v29, v8, v11 + put_luma_hv_x8_vertical_filter v4, v5, v15, v18, v21, v24, v27, v30, v9, v12 + ld1 {v14.8h, v15.8h, v16.8h}, [x1], x2 + st1 {v2.4h-v5.4h}, [x0], x9 + put_luma_hv_x8_horizontal_filter \shift, v14, v14, v15 + put_luma_hv_x8_horizontal_filter \shift, v15, v15, v16 + put_luma_hv_x8_vertical_filter v2, v3, v17, v20, v23, v26, v29, v8, v11, v14 + put_luma_hv_x8_vertical_filter v4, v5, v18, v21, v24, v27, v30, v9, v12, v15 + st1 {v2.4h-v5.4h}, [x0], x9 + + mov v10.16b, v8.16b + mov v8.16b, v20.16b + mov v20.16b, v10.16b + mov v10.16b, v9.16b + mov v9.16b, v21.16b + mov v21.16b, v10.16b + + mov v13.16b, v11.16b + mov v11.16b, v23.16b + mov v23.16b, v13.16b + mov v13.16b, v12.16b + mov v12.16b, v24.16b + mov v24.16b, v13.16b + + mov v16.16b, v14.16b + mov v14.16b, v26.16b + mov v26.16b, v16.16b + mov v16.16b, v15.16b + mov v15.16b, v27.16b + mov v27.16b, v16.16b + + subs w3, w3, #4 + mov v17.16b, v29.16b + mov v18.16b, v30.16b + b.gt 1b + + ldp d14, d15, [sp, #48] + ldp d12, d13, [sp, #32] + ldp d10, d11, [sp, #16] + ldp d8, d9, [sp], #64 + ret +.endm + +function ff_vvc_put_luma_hv16_10_neon, export=1 + put_luma_hv16_xx_neon 2 +endfunc + +function ff_vvc_put_luma_hv16_12_neon, export=1 + put_luma_hv16_xx_neon 4 +endfunc + +.macro put_luma_hv_x16_xx_neon shift + // dst .req x0 + // _src .req x1 + // _src_stride .req x2 + // height .req x3 + // hf .req x4 + // vf .req x5 + // width .req x6 + uxtw x6, w6 + stp d8, d9, [sp, #-64]! + stp d10, d11, [sp, #16] + stp d12, d13, [sp, #32] + stp d14, d15, [sp, #48] + mov x9, #(VVC_MAX_PB_SIZE * 2) + sub x1, x1, #6 + ld1 {v0.8b}, [x4] + sub x1, x1, x2, lsl #1 + sxtl v0.8h, v0.8b + ld1 {v1.8b}, [x5] + sub x1, x1, x2 + sxtl v1.8h, v1.8b +1: + mov w13, w3 + mov x11, x1 + mov x10, x0 + ld1 {v8.8h, v9.8h, v10.8h}, [x11], x2 + ld1 {v11.8h, v12.8h, v13.8h}, [x11], x2 + ld1 {v14.8h, v15.8h, v16.8h}, [x11], x2 + ld1 {v17.8h, v18.8h, v19.8h}, [x11], x2 + ld1 {v20.8h, v21.8h, v22.8h}, [x11], x2 + ld1 {v23.8h, v24.8h, v25.8h}, [x11], x2 + ld1 {v26.8h, v27.8h, v28.8h}, [x11], x2 + put_luma_hv_x8_horizontal_filter \shift, v8, v8, v9 + put_luma_hv_x8_horizontal_filter \shift, v9, v9, v10 + put_luma_hv_x8_horizontal_filter \shift, v11, v11, v12 + put_luma_hv_x8_horizontal_filter \shift, v12, v12, v13 + put_luma_hv_x8_horizontal_filter \shift, v14, v14, v15 + put_luma_hv_x8_horizontal_filter \shift, v15, v15, v16 + put_luma_hv_x8_horizontal_filter \shift, v17, v17, v18 + put_luma_hv_x8_horizontal_filter \shift, v18, v18, v19 + put_luma_hv_x8_horizontal_filter \shift, v20, v20, v21 + put_luma_hv_x8_horizontal_filter \shift, v21, v21, v22 + put_luma_hv_x8_horizontal_filter \shift, v23, v23, v24 + put_luma_hv_x8_horizontal_filter \shift, v24, v24, v25 + put_luma_hv_x8_horizontal_filter \shift, v26, v26, v27 + put_luma_hv_x8_horizontal_filter \shift, v27, v27, v28 +2: + ld1 {v29.8h, v30.8h, v31.8h}, [x11], x2 + put_luma_hv_x8_horizontal_filter \shift, v29, v29, v30 + put_luma_hv_x8_horizontal_filter \shift, v30, v30, v31 + put_luma_hv_x8_vertical_filter v2, v3, v8, v11, v14, v17, v20, v23, v26, v29 + put_luma_hv_x8_vertical_filter v4, v5, v9, v12, v15, v18, v21, v24, v27, v30 + ld1 {v8.8h, v9.8h, v10.8h}, [x11], x2 + st1 {v2.4h-v5.4h}, [x10], x9 + + put_luma_hv_x8_horizontal_filter \shift, v8, v8, v9 + put_luma_hv_x8_horizontal_filter \shift, v9, v9, v10 + put_luma_hv_x8_vertical_filter v2, v3, v11, v14, v17, v20, v23, v26, v29, v8 + put_luma_hv_x8_vertical_filter v4, v5, v12, v15, v18, v21, v24, v27, v30, v9 + ld1 {v11.8h, v12.8h, v13.8h}, [x11], x2 + st1 {v2.4h-v5.4h}, [x10], x9 + + put_luma_hv_x8_horizontal_filter \shift, v11, v11, v12 + put_luma_hv_x8_horizontal_filter \shift, v12, v12, v13 + put_luma_hv_x8_vertical_filter v2, v3, v14, v17, v20, v23, v26, v29, v8, v11 + put_luma_hv_x8_vertical_filter v4, v5, v15, v18, v21, v24, v27, v30, v9, v12 + ld1 {v14.8h, v15.8h, v16.8h}, [x11], x2 + st1 {v2.4h-v5.4h}, [x10], x9 + + put_luma_hv_x8_horizontal_filter \shift, v14, v14, v15 + put_luma_hv_x8_horizontal_filter \shift, v15, v15, v16 + put_luma_hv_x8_vertical_filter v2, v3, v17, v20, v23, v26, v29, v8, v11, v14 + put_luma_hv_x8_vertical_filter v4, v5, v18, v21, v24, v27, v30, v9, v12, v15 + st1 {v2.4h-v5.4h}, [x10], x9 + + mov v10.16b, v8.16b + mov v8.16b, v20.16b + mov v20.16b, v10.16b + mov v10.16b, v9.16b + mov v9.16b, v21.16b + mov v21.16b, v10.16b + + mov v13.16b, v11.16b + mov v11.16b, v23.16b + mov v23.16b, v13.16b + mov v13.16b, v12.16b + mov v12.16b, v24.16b + mov v24.16b, v13.16b + + mov v16.16b, v14.16b + mov v14.16b, v26.16b + mov v26.16b, v16.16b + mov v16.16b, v15.16b + mov v15.16b, v27.16b + mov v27.16b, v16.16b + + subs w13, w13, #4 + mov v17.16b, v29.16b + mov v18.16b, v30.16b + b.gt 2b + + add x0, x0, #32 + add x1, x1, #32 + subs w6, w6, #16 + b.gt 1b + + ldp d14, d15, [sp, #48] + ldp d12, d13, [sp, #32] + ldp d10, d11, [sp, #16] + ldp d8, d9, [sp], #64 + ret +.endm + +function ff_vvc_put_luma_hv_x16_10_neon, export=1 + put_luma_hv_x16_xx_neon 2 +endfunc + +function ff_vvc_put_luma_hv_x16_12_neon, export=1 + put_luma_hv_x16_xx_neon 4 +endfunc diff --git a/libavcodec/aarch64/vvc/inter_sme2.S b/libavcodec/aarch64/vvc/inter_sme2.S new file mode 100644 index 000000000..093f82382 --- /dev/null +++ b/libavcodec/aarch64/vvc/inter_sme2.S @@ -0,0 +1,657 @@ +/* + * Copyright (c) 2025 Georgii Zagoruiko + * + * 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/aarch64/asm.S" + +#define VVC_MAX_PB_SIZE 128 + +ENABLE_SME2 + +#if HAVE_SME_I16I64 +ENABLE_SME_I16I64 +.macro first_group_filter_luma_offsets breg, shift + // x20-x23: p5[0],p3[-1],p1[0],p0[3] + // x24-x27: p6[0],p4[1],p2[0],p0[-3] + neg x26, x11 + ubfx x20, \breg, #(3+\shift), #2 + ubfx x21, \breg, #(1+\shift), #2 + mul x24, x20, x26 + mul x20, x20, x11 + mul x25, x21, x26 + mul x21, x21, x11 + ubfx x22, \breg, #(\shift), #1 + sub x21, x21, #1 + mul x26, x22, x26 + mul x22, x22, x11 + mov x23, #3 + add x25, x25, #1 + mov x27, #-3 +.endm + +.macro second_group_filter_luma_offsets breg, shift + // x20-x23: p3[ 1],p1[ 2],p1[-1],p0[ 2] + // x24-x27: p4[-1],p2[-2],p2[ 1],p0[-2] + neg x26, x11 + ubfx x20, \breg, #(1+\shift), #2 + ubfx x21, \breg, #(\shift), #1 + mul x24, x20, x26 + mul x20, x20, x11 + mul x25, x21, x26 + mul x26, x21, x26 + mul x21, x21, x11 + add x20, x20, #1 + sub x22, x21, #1 + add x21, x21, #2 + mov x23, #2 + sub x24, x24, #1 + sub x25, x25, #2 + add x26, x26, #1 + mov x27, #-2 +.endm + +.macro third_group_filter_luma_offsets breg, shift + // x20-x23: p3[0],p1[ 1],p1[-2],p0[ 1] + // x24-x27: p4[0],p2[-1],p2[ 2],p0[-1] + neg x26, x11 + ubfx x21, \breg, #(\shift), #1 + ubfx x20, \breg, #(1+\shift), #2 + mul x25, x21, x26 + mul x26, x21, x26 + mul x21, x21, x11 + mul x24, x20, x26 + mul x20, x20, x11 + sub x22, x21, #2 + add x21, x21, #1 + mov x23, #1 + sub x25, x25, #1 + mov x27, #-1 + add x26, x26, #2 +.endm + +.macro kernel_filter_luma_8_sme2 src, zreg, idx + ld1b z20.h, p0/z, [\src, x20] + ld1b z21.h, p0/z, [\src, x21] + ld1b z22.h, p0/z, [\src, x22] + ld1b z23.h, p0/z, [\src, x23] + ld1b z24.h, p0/z, [\src, x24] + ld1b z25.h, p0/z, [\src, x25] + neg z8.h, p0/m, \zreg // -p0 + ld1b z26.h, p0/z, [\src, x26] + ld1b z27.h, p0/z, [\src, x27] + add {z20.h-z23.h}, {z20.h-z23.h}, z8.h + add {z24.h-z27.h}, {z24.h-z27.h}, z8.h + // transpose data vectors + zip {z20.h-z23.h}, {z20.h-z23.h} + zip {z24.h-z27.h}, {z24.h-z27.h} + // clip data + sclamp z20.h, z16.h, z12.h + sclamp z24.h, z16.h, z12.h + sclamp z21.h, z17.h, z13.h + sclamp z25.h, z17.h, z13.h + sclamp z22.h, z18.h, z14.h + sclamp z26.h, z18.h, z14.h + sclamp z23.h, z19.h, z15.h + sclamp z27.h, z19.h, z15.h + sdot za.d[w10, \idx], {z20.h-z23.h}, {z28.h-z31.h} + sdot za.d[w10, \idx], {z24.h-z27.h}, {z28.h-z31.h} +.endm + +function ff_vvc_alf_filter_luma_8_sme2, export=1 + // dst .req x0 + // src .req x1 + // strides .req x2 + // dims .req x3 + // filter .req x4 + // clip .req x5 + // vb .req x6 + sme_entry + stp x29, x30, [sp, #-96]! + mov x29, sp + stp x19, x20, [sp, #16] + stp x21, x22, [sp, #32] + stp x23, x24, [sp, #48] + stp x25, x26, [sp, #64] + stp x27, x28, [sp, #80] + + lsr x7, x3, #32 + cnth x11 + mov w8, w3 + sub w9, w8, #1 + sdiv w9, w9, w11 + msub w9, w9, w11, w8 + whilelo p10.h, xzr, x9 + ptrue p1.h + lsr x11, x2, #32 // src stride + lsr w2, w2, #0 // leave dst stride only + mov w10, #0 + mov w12, #255 + dup z9.h, w10 + dup z10.h, w12 +1: + lsr x20, x3, #32 + mov p0.b, p10.b + sub w20, w20, w7 + mov w12, w9 + sub w6, w6, #6 + // offsets are packed into the format: (M<<3)|(N<<1)|K, where M is p5/p6 offset (multiply), N is p3/p4 offset, K is p1/p2 offset + mov w21, #0 + mov w22, #0xB + mov w23, #0x15 + mov w13, #0x1D // 0x1D == (3<<3)|(2<<1)|1 + mov w14, #0x1D + mov w15, #0x1D + mov w16, #0x1D + // y == vb_pos - 6 + cmp w20, w6 + add w6, w6, #1 + csel w16, w16, w23, ne + // y == vb_pos - 5 + cmp w20, w6 + add w6, w6, #1 + csel w15, w15, w23, ne + csel w16, w16, w22, ne + // y == vb_pos - 4 + cmp w20, w6 + add w6, w6, #1 + csel w14, w14, w23, ne + csel w15, w15, w22, ne + csel w16, w16, w21, ne + // y == vb_pos - 3 + cmp w20, w6 + add w6, w6, #1 + csel w13, w13, w23, ne + csel w14, w14, w22, ne + csel w15, w15, w21, ne + csel w16, w16, w21, ne + // y == vb_pos - 2 + cmp w20, w6 + add w6, w6, #1 + csel w13, w13, w22, ne + csel w14, w14, w21, ne + csel w15, w15, w21, ne + csel w16, w16, w22, ne + // y == vb_pos - 1 + cmp w20, w6 + add w6, w6, #1 + csel w13, w13, w21, ne + csel w14, w14, w21, ne + csel w15, w15, w22, ne + csel w16, w16, w23, ne + // y == vb_pos + cmp w20, w6 + add w6, w6, #1 + csel w13, w13, w21, ne + csel w14, w14, w22, ne + csel w15, w15, w23, ne + // y == vb_pos + 1 + cmp w20, w6 + add w6, w6, #1 + csel w13, w13, w22, ne + csel w14, w14, w23, ne + // y == vb_pos + 2 + cmp w20, w6 + sub w6, w6, #2 + csel w13, w13, w23, ne + orr w13, w13, w14, lsl #8 + orr w13, w13, w15, lsl #16 + orr w13, w13, w16, lsl #24 + mov x14, x1 + mov x19, x0 +2: + // Load clip [12=>3x4 memory layout] + ld3h {z0.h-z2.h}, p0/z, [x5] + // Load filter [12=>3x4 memory layout] + ld3h {z3.h-z5.h}, p0/z, [x4] + add x15, x14, x11 + add x16, x14, x11, lsl #1 + add x17, x15, x11, lsl #1 + add x30, x19, x2, lsl #1 + + mov z12.d, z0.d + mov z13.d, z0.d + mov z14.d, z0.d + mov z15.d, z0.d + // copy filter into 4 vectors and then zip + mov z28.d, z3.d + mov z29.d, z3.d + zip {z12.d-z15.d}, {z12.d-z15.d} + mov z30.d, z3.d + mov z31.d, z3.d + neg z16.h, p1/m, z12.h + neg z17.h, p1/m, z13.h + neg z18.h, p1/m, z14.h + neg z19.h, p1/m, z15.h + zip {z28.d-z31.d}, {z28.d-z31.d} + // p0 (curr) + ld1b z6.h, p0/z, [x14] + ld1b z7.h, p0/z, [x15] + ld1b z0.h, p0/z, [x16] + ld1b z3.h, p0/z, [x17] + // clip & filter (first group): a0,a3,a6,a9, a12... + // {p5[0],p3[-1],p1[0],p0[3]} -> left operand in clip + // {p6[0],p4[1],p2[0],p0[-3]} -> right operand in clip + first_group_filter_luma_offsets x13, 0 + kernel_filter_luma_8_sme2 x14, z6.h, 0 + first_group_filter_luma_offsets x13, 8 + kernel_filter_luma_8_sme2 x15, z7.h, 1 + first_group_filter_luma_offsets x13, 16 + kernel_filter_luma_8_sme2 x16, z0.h, 2 + first_group_filter_luma_offsets x13, 24 + kernel_filter_luma_8_sme2 x17, z3.h, 3 + + mov z12.d, z1.d + mov z13.d, z1.d + mov z14.d, z1.d + mov z15.d, z1.d + // copy filter into 4 vectors and then zip + mov z28.d, z4.d + mov z29.d, z4.d + zip {z12.d-z15.d}, {z12.d-z15.d} + mov z30.d, z4.d + mov z31.d, z4.d + // -clip + neg z16.h, p1/m, z12.h + neg z17.h, p1/m, z13.h + neg z18.h, p1/m, z14.h + neg z19.h, p1/m, z15.h + zip {z28.d-z31.d}, {z28.d-z31.d} + // clip & filter (second group): a1,a4,a7,a10,a13... + // left: {p3[ 1],p1[ 2],p1[-1],p0[ 2]} + // right: {p4[-1],p2[-2],p2[ 1],p0[-2]} + second_group_filter_luma_offsets x13, 0 + kernel_filter_luma_8_sme2 x14, z6.h, 0 + second_group_filter_luma_offsets x13, 8 + kernel_filter_luma_8_sme2 x15, z7.h, 1 + second_group_filter_luma_offsets x13, 16 + kernel_filter_luma_8_sme2 x16, z0.h, 2 + second_group_filter_luma_offsets x13, 24 + kernel_filter_luma_8_sme2 x17, z3.h, 3 + + mov z12.d, z2.d + mov z13.d, z2.d + mov z14.d, z2.d + mov z15.d, z2.d + // copy filter into 4 vectors and then zip + mov z28.d, z5.d + mov z29.d, z5.d + zip {z12.d-z15.d}, {z12.d-z15.d} + mov z30.d, z5.d + mov z31.d, z5.d + // -clip + neg z16.h, p1/m, z12.h + neg z17.h, p1/m, z13.h + neg z18.h, p1/m, z14.h + neg z19.h, p1/m, z15.h + zip {z28.d-z31.d}, {z28.d-z31.d} + // clip & filter (third group): a2,a5,a8,a11,a14... + // left: {p3[0],p1[ 1],p1[-2],p0[ 1]} + // right: {p4[0],p2[-1],p2[ 2],p0[-1]} + third_group_filter_luma_offsets x13, 0 + kernel_filter_luma_8_sme2 x14, z6.h, 0 + third_group_filter_luma_offsets x13, 8 + kernel_filter_luma_8_sme2 x15, z7.h, 1 + third_group_filter_luma_offsets x13, 16 + kernel_filter_luma_8_sme2 x16, z0.h, 2 + third_group_filter_luma_offsets x13, 24 + kernel_filter_luma_8_sme2 x17, z3.h, 3 + mova {z16.d-z19.d}, za.d[w10, 0] + mova {z20.d-z23.d}, za.d[w10, 1] + mova {z24.d-z27.d}, za.d[w10, 2] + mova {z28.d-z31.d}, za.d[w10, 3] + sqrshr z12.h, {z16.d-z19.d}, #7 + sqrshr z13.h, {z20.d-z23.d}, #7 + sqrshr z14.h, {z24.d-z27.d}, #7 + sqrshr z15.h, {z28.d-z31.d}, #7 + tbnz x13, #0, 10f + sqrshr z12.h, {z16.d-z19.d}, #10 +10: + tbnz x13, #8, 11f + sqrshr z13.h, {z20.d-z23.d}, #10 +11: + tbnz x13, #16, 12f + sqrshr z14.h, {z24.d-z27.d}, #10 +12: + tbnz x13, #24, 13f + sqrshr z15.h, {z28.d-z31.d}, #10 +13: + add z12.h, z12.h, z6.h + add z13.h, z13.h, z7.h + add z14.h, z14.h, z0.h + add z15.h, z15.h, z3.h + sclamp {z12.h-z15.h}, z9.h, z10.h + st1b z12.h, p0, [x19] + st1b z13.h, p0, [x19, x2] + st1b z14.h, p0, [x30] + st1b z15.h, p0, [x30, x2] + zero {za} + add x14, x14, x12 + add x19, x19, x12 + ptrue p0.h + subs w8, w8, w12 + add w12, w12, w12, lsl #1 + add x4, x4, x12, lsl #1 + add x5, x5, x12, lsl #1 + cnth x12 + b.gt 2b + mov w8, w3 + subs w7, w7, #4 + add x1, x1, x11, lsl #2 + add x0, x0, x2, lsl #2 + b.gt 1b + + ldp x19, x20, [sp, #16] + ldp x21, x22, [sp, #32] + ldp x23, x24, [sp, #48] + ldp x25, x26, [sp, #64] + ldp x27, x28, [sp, #80] + ldp x29, x30, [sp], #96 + sme_exit + ret +endfunc + +.macro kernel_filter_luma_16_sme2 src, zreg, idx + ld1h z20.h, p0/z, [\src, x20, lsl #1] + ld1h z21.h, p0/z, [\src, x21, lsl #1] + ld1h z22.h, p0/z, [\src, x22, lsl #1] + ld1h z23.h, p0/z, [\src, x23, lsl #1] + ld1h z24.h, p0/z, [\src, x24, lsl #1] + ld1h z25.h, p0/z, [\src, x25, lsl #1] + neg z8.h, p0/m, \zreg // -p0 + ld1h z26.h, p0/z, [\src, x26, lsl #1] + ld1h z27.h, p0/z, [\src, x27, lsl #1] + add {z20.h-z23.h}, {z20.h-z23.h}, z8.h + add {z24.h-z27.h}, {z24.h-z27.h}, z8.h + // transpose data vectors + zip {z20.h-z23.h}, {z20.h-z23.h} + zip {z24.h-z27.h}, {z24.h-z27.h} + // clip data + sclamp z20.h, z16.h, z12.h + sclamp z24.h, z16.h, z12.h + sclamp z21.h, z17.h, z13.h + sclamp z25.h, z17.h, z13.h + sclamp z22.h, z18.h, z14.h + sclamp z26.h, z18.h, z14.h + sclamp z23.h, z19.h, z15.h + sclamp z27.h, z19.h, z15.h + sdot za.d[w10, \idx], {z20.h-z23.h}, {z28.h-z31.h} + sdot za.d[w10, \idx], {z24.h-z27.h}, {z28.h-z31.h} +.endm + +function ff_vvc_alf_filter_luma_12_sme2, export=1 + mov w12, #4095 + b 0f +endfunc + +function ff_vvc_alf_filter_luma_10_sme2, export=1 + // dst .req x0 + // src .req x1 + // strides .req x2 + // dims .req x3 + // filter .req x4 + // clip .req x5 + // vb .req x6 + mov w12, #1023 +0: + sme_entry + stp x29, x30, [sp, #-96]! + mov x29, sp + stp x19, x20, [sp, #16] + stp x21, x22, [sp, #32] + stp x23, x24, [sp, #48] + stp x25, x26, [sp, #64] + stp x27, x28, [sp, #80] + + lsr x7, x3, #32 + cnth x11 + mov w8, w3 + sub w9, w8, #1 + sdiv w9, w9, w11 + msub w9, w9, w11, w8 + whilelo p10.h, xzr, x9 + ptrue p1.h + lsr x11, x2, #33 // src stride + lsr w2, w2, #1 + mov w10, #0 + dup z9.h, w10 + dup z10.h, w12 +1: + lsr x20, x3, #32 + mov p0.b, p10.b + sub w20, w20, w7 + mov w12, w9 + sub w6, w6, #6 + // offsets are packed into the format: (M<<3)|(N<<1)|K, where M is p5/p6 offset (multiply), N is p3/p4 offset, K is p1/p2 offset + mov w21, #0 + mov w22, #0xB + mov w23, #0x15 + mov w13, #0x1D // 0x1D == (3<<3)|(2<<1)|1 + mov w14, #0x1D + mov w15, #0x1D + mov w16, #0x1D + // y == vb_pos - 6 + cmp w20, w6 + add w6, w6, #1 + csel w16, w16, w23, ne + // y == vb_pos - 5 + cmp w20, w6 + add w6, w6, #1 + csel w15, w15, w23, ne + csel w16, w16, w22, ne + // y == vb_pos - 4 + cmp w20, w6 + add w6, w6, #1 + csel w14, w14, w23, ne + csel w15, w15, w22, ne + csel w16, w16, w21, ne + // y == vb_pos - 3 + cmp w20, w6 + add w6, w6, #1 + csel w13, w13, w23, ne + csel w14, w14, w22, ne + csel w15, w15, w21, ne + csel w16, w16, w21, ne + // y == vb_pos - 2 + cmp w20, w6 + add w6, w6, #1 + csel w13, w13, w22, ne + csel w14, w14, w21, ne + csel w15, w15, w21, ne + csel w16, w16, w22, ne + // y == vb_pos - 1 + cmp w20, w6 + add w6, w6, #1 + csel w13, w13, w21, ne + csel w14, w14, w21, ne + csel w15, w15, w22, ne + csel w16, w16, w23, ne + // y == vb_pos + cmp w20, w6 + add w6, w6, #1 + csel w13, w13, w21, ne + csel w14, w14, w22, ne + csel w15, w15, w23, ne + // y == vb_pos + 1 + cmp w20, w6 + add w6, w6, #1 + csel w13, w13, w22, ne + csel w14, w14, w23, ne + // y == vb_pos + 2 + cmp w20, w6 + sub w6, w6, #2 + csel w13, w13, w23, ne + orr w13, w13, w14, lsl #8 + orr w13, w13, w15, lsl #16 + orr w13, w13, w16, lsl #24 + mov x14, x1 + mov x19, x0 +2: + // Load clip [12=>3x4 memory layout] + ld3h {z0.h-z2.h}, p0/z, [x5] + // Load filter [12=>3x4 memory layout] + ld3h {z3.h-z5.h}, p0/z, [x4] + add x15, x14, x11, lsl #1 + add x16, x14, x11, lsl #2 + add x17, x15, x11, lsl #2 + add x30, x19, x2, lsl #2 + + mov z12.d, z0.d + mov z13.d, z0.d + mov z14.d, z0.d + mov z15.d, z0.d + // copy filter into 4 vectors and then zip + mov z28.d, z3.d + mov z29.d, z3.d + zip {z12.d-z15.d}, {z12.d-z15.d} + mov z30.d, z3.d + mov z31.d, z3.d + neg z16.h, p1/m, z12.h + neg z17.h, p1/m, z13.h + neg z18.h, p1/m, z14.h + neg z19.h, p1/m, z15.h + zip {z28.d-z31.d}, {z28.d-z31.d} + // p0 (curr) + ld1h z6.h, p0/z, [x14] + ld1h z7.h, p0/z, [x15] + ld1h z0.h, p0/z, [x16] + ld1h z3.h, p0/z, [x17] + // clip & filter (first group): a0,a3,a6,a9, a12... + // {p5[0],p3[-1],p1[0],p0[3]} -> left operand in clip + // {p6[0],p4[1],p2[0],p0[-3]} -> right operand in clip + first_group_filter_luma_offsets x13, 0 + kernel_filter_luma_16_sme2 x14, z6.h, 0 + first_group_filter_luma_offsets x13, 8 + kernel_filter_luma_16_sme2 x15, z7.h, 1 + first_group_filter_luma_offsets x13, 16 + kernel_filter_luma_16_sme2 x16, z0.h, 2 + first_group_filter_luma_offsets x13, 24 + kernel_filter_luma_16_sme2 x17, z3.h, 3 + + mov z12.d, z1.d + mov z13.d, z1.d + mov z14.d, z1.d + mov z15.d, z1.d + // copy filter into 4 vectors and then zip + mov z28.d, z4.d + mov z29.d, z4.d + zip {z12.d-z15.d}, {z12.d-z15.d} + mov z30.d, z4.d + mov z31.d, z4.d + // -clip + neg z16.h, p1/m, z12.h + neg z17.h, p1/m, z13.h + neg z18.h, p1/m, z14.h + neg z19.h, p1/m, z15.h + zip {z28.d-z31.d}, {z28.d-z31.d} + // clip & filter (second group): a1,a4,a7,a10,a13... + // left: {p3[ 1],p1[ 2],p1[-1],p0[ 2]} + // right: {p4[-1],p2[-2],p2[ 1],p0[-2]} + second_group_filter_luma_offsets x13, 0 + kernel_filter_luma_16_sme2 x14, z6.h, 0 + second_group_filter_luma_offsets x13, 8 + kernel_filter_luma_16_sme2 x15, z7.h, 1 + second_group_filter_luma_offsets x13, 16 + kernel_filter_luma_16_sme2 x16, z0.h, 2 + second_group_filter_luma_offsets x13, 24 + kernel_filter_luma_16_sme2 x17, z3.h, 3 + + mov z12.d, z2.d + mov z13.d, z2.d + mov z14.d, z2.d + mov z15.d, z2.d + // copy filter into 4 vectors and then zip + mov z28.d, z5.d + mov z29.d, z5.d + zip {z12.d-z15.d}, {z12.d-z15.d} + mov z30.d, z5.d + mov z31.d, z5.d + // -clip + neg z16.h, p1/m, z12.h + neg z17.h, p1/m, z13.h + neg z18.h, p1/m, z14.h + neg z19.h, p1/m, z15.h + zip {z28.d-z31.d}, {z28.d-z31.d} + + // clip & filter (third group): a2,a5,a8,a11,a14... + // left: {p3[0],p1[ 1],p1[-2],p0[ 1]} + // right: {p4[0],p2[-1],p2[ 2],p0[-1]} + third_group_filter_luma_offsets x13, 0 + kernel_filter_luma_16_sme2 x14, z6.h, 0 + third_group_filter_luma_offsets x13, 8 + kernel_filter_luma_16_sme2 x15, z7.h, 1 + third_group_filter_luma_offsets x13, 16 + kernel_filter_luma_16_sme2 x16, z0.h, 2 + third_group_filter_luma_offsets x13, 24 + kernel_filter_luma_16_sme2 x17, z3.h, 3 + mova {z16.d-z19.d}, za.d[w10, 0] + mova {z20.d-z23.d}, za.d[w10, 1] + mova {z24.d-z27.d}, za.d[w10, 2] + mova {z28.d-z31.d}, za.d[w10, 3] + sqrshr z12.h, {z16.d-z19.d}, #7 + sqrshr z13.h, {z20.d-z23.d}, #7 + sqrshr z14.h, {z24.d-z27.d}, #7 + sqrshr z15.h, {z28.d-z31.d}, #7 + tbnz x13, #0, 10f + sqrshr z12.h, {z16.d-z19.d}, #10 +10: + tbnz x13, #8, 11f + sqrshr z13.h, {z20.d-z23.d}, #10 +11: + tbnz x13, #16, 12f + sqrshr z14.h, {z24.d-z27.d}, #10 +12: + tbnz x13, #24, 13f + sqrshr z15.h, {z28.d-z31.d}, #10 +13: + add z12.h, z12.h, z6.h + add z13.h, z13.h, z7.h + add z14.h, z14.h, z0.h + add z15.h, z15.h, z3.h + sclamp {z12.h-z15.h}, z9.h, z10.h + st1h z12.h, p0, [x19] + st1h z13.h, p0, [x19, x2, lsl #1] + st1h z14.h, p0, [x30] + st1h z15.h, p0, [x30, x2, lsl #1] + zero {za} + add x14, x14, x12, lsl #1 + add x19, x19, x12, lsl #1 + ptrue p0.h + subs w8, w8, w12 + add w12, w12, w12, lsl #1 + add x4, x4, x12, lsl #1 + add x5, x5, x12, lsl #1 + cnth x12 + b.gt 2b + mov w8, w3 + subs w7, w7, #4 + add x1, x1, x11, lsl #3 + add x0, x0, x2, lsl #3 + b.gt 1b + + ldp x19, x20, [sp, #16] + ldp x21, x22, [sp, #32] + ldp x23, x24, [sp, #48] + ldp x25, x26, [sp, #64] + ldp x27, x28, [sp, #80] + ldp x29, x30, [sp], #96 + sme_exit + ret +endfunc +DISABLE_SME_I16I64 +#endif diff --git a/libavcodec/ac3.h b/libavcodec/ac3.h index 2386c15ad..ccd437f70 100644 --- a/libavcodec/ac3.h +++ b/libavcodec/ac3.h @@ -81,17 +81,6 @@ typedef float SHORTFLOAT; #define AC3_LEVEL(x) ROUND15((x) * FIXR15(M_SQRT1_2)) -/* pre-defined gain values */ -#define LEVEL_PLUS_3DB M_SQRT2 -#define LEVEL_PLUS_1POINT5DB 1.1892071150027209 -#define LEVEL_MINUS_1POINT5DB 0.8408964152537145 -#define LEVEL_MINUS_3DB M_SQRT1_2 -#define LEVEL_MINUS_4POINT5DB 0.5946035575013605 -#define LEVEL_MINUS_6DB 0.5000000000000000 -#define LEVEL_MINUS_9DB 0.3535533905932738 -#define LEVEL_ZERO 0.0000000000000000 -#define LEVEL_ONE 1.0000000000000000 - typedef struct AC3BitAllocParameters { int sr_code; int sr_shift; diff --git a/libavcodec/ac3_parser.c b/libavcodec/ac3_parser.c index 69989690d..232c96d51 100644 --- a/libavcodec/ac3_parser.c +++ b/libavcodec/ac3_parser.c @@ -31,6 +31,7 @@ #include "ac3_parser_internal.h" #include "aac_ac3_parser.h" #include "get_bits.h" +#include "parser_internal.h" #define AC3_HEADER_SIZE 7 @@ -73,6 +74,217 @@ int ff_ac3_find_syncword(const uint8_t *buf, int buf_size) return i; } +/** + * Parse the 'sync info' and 'bit stream info' from the AC-3 bitstream. + * GetBitContext within AC3DecodeContext must point to + * the start of the synchronized AC-3 bitstream. + */ +static int ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) +{ + /* read the rest of the bsi. read twice for dual mono mode. */ + for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) { + hdr->dialog_normalization[i] = -get_bits(gbc, 5); + hdr->compression_exists[i] = get_bits1(gbc); + if (hdr->compression_exists[i]) + hdr->heavy_dynamic_range[i] = get_bits(gbc, 8); + if (get_bits1(gbc)) + skip_bits(gbc, 8); //skip language code + if (get_bits1(gbc)) + skip_bits(gbc, 7); //skip audio production information + } + + skip_bits(gbc, 2); //skip copyright bit and original bitstream bit + + /* skip the timecodes or parse the Alternate Bit Stream Syntax */ + if (hdr->bitstream_id != 6) { + if (get_bits1(gbc)) + skip_bits(gbc, 14); //skip timecode1 + if (get_bits1(gbc)) + skip_bits(gbc, 14); //skip timecode2 + } else { + if (get_bits1(gbc)) { + hdr->preferred_downmix = get_bits(gbc, 2); + hdr->center_mix_level_ltrt = get_bits(gbc, 3); + hdr->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7); + hdr->center_mix_level = get_bits(gbc, 3); + hdr->surround_mix_level = av_clip(get_bits(gbc, 3), 3, 7); + } + if (get_bits1(gbc)) { + hdr->dolby_surround_ex_mode = get_bits(gbc, 2); + hdr->dolby_headphone_mode = get_bits(gbc, 2); + skip_bits(gbc, 10); // skip adconvtyp (1), xbsi2 (8), encinfo (1) + } + } + + /* skip additional bitstream info */ + if (get_bits1(gbc)) { + int i = get_bits(gbc, 6); + do { + skip_bits(gbc, 8); + } while (i--); + } + + return 0; +} + +static int eac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) +{ + if (hdr->frame_type == EAC3_FRAME_TYPE_RESERVED) + return AC3_PARSE_ERROR_FRAME_TYPE; + if (hdr->substreamid) + return AC3_PARSE_ERROR_FRAME_TYPE; + + skip_bits(gbc, 5); // skip bitstream id + + /* volume control params */ + for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) { + hdr->dialog_normalization[i] = -get_bits(gbc, 5); + hdr->compression_exists[i] = get_bits1(gbc); + if (hdr->compression_exists[i]) + hdr->heavy_dynamic_range[i] = get_bits(gbc, 8); + } + + /* dependent stream channel map */ + if (hdr->frame_type == EAC3_FRAME_TYPE_DEPENDENT) { + hdr->channel_map_present = get_bits1(gbc); + if (hdr->channel_map_present) { + int64_t channel_layout = 0; + int channel_map = get_bits(gbc, 16); + + for (int i = 0; i < 16; i++) + if (channel_map & (1 << (EAC3_MAX_CHANNELS - i - 1))) + channel_layout |= ff_eac3_custom_channel_map_locations[i][1]; + + if (av_popcount64(channel_layout) > EAC3_MAX_CHANNELS) { + return AC3_PARSE_ERROR_CHANNEL_MAP; + } + hdr->channel_map = channel_map; + } + } + + /* mixing metadata */ + if (get_bits1(gbc)) { + /* center and surround mix levels */ + if (hdr->channel_mode > AC3_CHMODE_STEREO) { + hdr->preferred_downmix = get_bits(gbc, 2); + if (hdr->channel_mode & 1) { + /* if three front channels exist */ + hdr->center_mix_level_ltrt = get_bits(gbc, 3); + hdr->center_mix_level = get_bits(gbc, 3); + } + if (hdr->channel_mode & 4) { + /* if a surround channel exists */ + hdr->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7); + hdr->surround_mix_level = av_clip(get_bits(gbc, 3), 3, 7); + } + } + + /* lfe mix level */ + if (hdr->lfe_on && (hdr->lfe_mix_level_exists = get_bits1(gbc))) { + hdr->lfe_mix_level = get_bits(gbc, 5); + } + + /* info for mixing with other streams and substreams */ + if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) { + for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) { + // TODO: apply program scale factor + if (get_bits1(gbc)) { + skip_bits(gbc, 6); // skip program scale factor + } + } + if (get_bits1(gbc)) { + skip_bits(gbc, 6); // skip external program scale factor + } + /* skip mixing parameter data */ + switch(get_bits(gbc, 2)) { + case 1: skip_bits(gbc, 5); break; + case 2: skip_bits(gbc, 12); break; + case 3: { + int mix_data_size = (get_bits(gbc, 5) + 2) << 3; + skip_bits_long(gbc, mix_data_size); + break; + } + } + /* skip pan information for mono or dual mono source */ + if (hdr->channel_mode < AC3_CHMODE_STEREO) { + for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) { + if (get_bits1(gbc)) { + /* note: this is not in the ATSC A/52B specification + reference: ETSI TS 102 366 V1.1.1 + section: E.1.3.1.25 */ + skip_bits(gbc, 8); // skip pan mean direction index + skip_bits(gbc, 6); // skip reserved paninfo bits + } + } + } + /* skip mixing configuration information */ + if (get_bits1(gbc)) { + for (int i = 0; i < hdr->num_blocks; i++) { + if (hdr->num_blocks == 1 || get_bits1(gbc)) { + skip_bits(gbc, 5); + } + } + } + } + } + + /* informational metadata */ + if (get_bits1(gbc)) { + hdr->bitstream_mode = get_bits(gbc, 3); + skip_bits(gbc, 2); // skip copyright bit and original bitstream bit + if (hdr->channel_mode == AC3_CHMODE_STEREO) { + hdr->dolby_surround_mode = get_bits(gbc, 2); + hdr->dolby_headphone_mode = get_bits(gbc, 2); + } + if (hdr->channel_mode >= AC3_CHMODE_2F2R) { + hdr->dolby_surround_ex_mode = get_bits(gbc, 2); + } + for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) { + if (get_bits1(gbc)) { + skip_bits(gbc, 8); // skip mix level, room type, and A/D converter type + } + } + if (hdr->sr_code != EAC3_SR_CODE_REDUCED) { + skip_bits1(gbc); // skip source sample rate code + } + } + + /* converter synchronization flag + If frames are less than six blocks, this bit should be turned on + once every 6 blocks to indicate the start of a frame set. + reference: RFC 4598, Section 2.1.3 Frame Sets */ + if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT && hdr->num_blocks != 6) { + skip_bits1(gbc); // skip converter synchronization flag + } + + /* original frame size code if this stream was converted from AC-3 */ + if (hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT && + (hdr->num_blocks == 6 || get_bits1(gbc))) { + skip_bits(gbc, 6); // skip frame size code + } + + /* additional bitstream info */ + if (get_bits1(gbc)) { + int addbsil = get_bits(gbc, 6); + for (int i = 0; i < addbsil + 1; i++) { + if (i == 0) { + /* In this 8 bit chunk, the LSB is equal to flag_ec3_extension_type_a + which can be used to detect Atmos presence */ + skip_bits(gbc, 7); + hdr->eac3_extension_type_a = get_bits1(gbc); + if (hdr->eac3_extension_type_a) { + hdr->complexity_index_type_a = get_bits(gbc, 8); + i++; + } + } else { + skip_bits(gbc, 8); // skip additional bit stream info + } + } + } + + return 0; +} + int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) { int frame_size_code; @@ -133,6 +345,10 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) hdr->frame_size = ff_ac3_frame_size_tab[frame_size_code][hdr->sr_code] * 2; hdr->frame_type = EAC3_FRAME_TYPE_AC3_CONVERT; //EAC3_FRAME_TYPE_INDEPENDENT; hdr->substreamid = 0; + + int ret = ac3_parse_header(gbc, hdr); + if (ret < 0) + return ret; } else { /* Enhanced AC-3 */ hdr->crc1 = 0; @@ -165,6 +381,10 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) hdr->bit_rate = 8LL * hdr->frame_size * hdr->sample_rate / (hdr->num_blocks * 256); hdr->channels = ff_ac3_channels_tab[hdr->channel_mode] + hdr->lfe_on; + + int ret = eac3_parse_header(gbc, hdr); + if (ret < 0) + return ret; } hdr->channel_layout = ff_ac3_channel_layout_tab[hdr->channel_mode]; if (hdr->lfe_on) @@ -202,9 +422,13 @@ int av_ac3_parse_header(const uint8_t *buf, size_t size, { GetBitContext gb; AC3HeaderInfo hdr; + uint8_t tmp[32 + AV_INPUT_BUFFER_PADDING_SIZE]; int err; - err = init_get_bits8(&gb, buf, size); + size = FFMIN(32, size); + memcpy(tmp, buf, size); + memset(tmp + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + err = init_get_bits8(&gb, tmp, size); if (err < 0) return AVERROR_INVALIDDATA; err = ff_ac3_parse_header(&gb, &hdr); @@ -254,12 +478,12 @@ static av_cold int ac3_parse_init(AVCodecParserContext *s1) } -const AVCodecParser ff_ac3_parser = { - .codec_ids = { AV_CODEC_ID_AC3, AV_CODEC_ID_EAC3 }, +const FFCodecParser ff_ac3_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_AC3, AV_CODEC_ID_EAC3), .priv_data_size = sizeof(AACAC3ParseContext), - .parser_init = ac3_parse_init, - .parser_parse = ff_aac_ac3_parse, - .parser_close = ff_parse_close, + .init = ac3_parse_init, + .parse = ff_aac_ac3_parse, + .close = ff_parse_close, }; #else diff --git a/libavcodec/ac3_parser_internal.h b/libavcodec/ac3_parser_internal.h index 46814bfb1..ab5df3400 100644 --- a/libavcodec/ac3_parser_internal.h +++ b/libavcodec/ac3_parser_internal.h @@ -46,6 +46,7 @@ typedef struct AC3HeaderInfo { int substreamid; ///< substream identification int center_mix_level; ///< Center mix level index int surround_mix_level; ///< Surround mix level index + uint8_t channel_map_present; uint16_t channel_map; int num_blocks; ///< number of audio blocks int dolby_surround_mode; @@ -62,6 +63,23 @@ typedef struct AC3HeaderInfo { uint64_t channel_layout; int8_t ac3_bit_rate_code; /** @} */ + + /** @name enhanced eac3 extension coded elements + * @{ + */ + int8_t dialog_normalization[2]; + uint8_t compression_exists[2]; + uint8_t heavy_dynamic_range[2]; + uint8_t center_mix_level_ltrt; ///< Center mix level index + uint8_t surround_mix_level_ltrt; ///< Surround mix level index + uint8_t dolby_headphone_mode; + uint8_t dolby_surround_ex_mode; + uint8_t lfe_mix_level_exists; + uint8_t lfe_mix_level; + uint8_t preferred_downmix; + uint8_t eac3_extension_type_a; + uint8_t complexity_index_type_a; + /** @} */ } AC3HeaderInfo; typedef enum { @@ -71,6 +89,7 @@ typedef enum { AC3_PARSE_ERROR_FRAME_SIZE = -0x4030c0a, AC3_PARSE_ERROR_FRAME_TYPE = -0x5030c0a, AC3_PARSE_ERROR_CRC = -0x6030c0a, + AC3_PARSE_ERROR_CHANNEL_MAP = -0x7030c0a, } AC3ParseError; /** diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c index 3cc20f32a..2f0e7f534 100644 --- a/libavcodec/ac3dec.c +++ b/libavcodec/ac3dec.c @@ -46,142 +46,32 @@ #include "decode.h" #include "kbdwin.h" -/** - * table for ungrouping 3 values in 7 bits. - * used for exponents and bap=2 mantissas - */ -static uint8_t ungroup_3_in_7_bits_tab[128][3]; - -/** tables for ungrouping mantissas */ -static int b1_mantissas[32][3]; -static int b2_mantissas[128][3]; -static int b3_mantissas[8]; -static int b4_mantissas[128][2]; -static int b5_mantissas[16]; - -/** - * Quantization table: levels for symmetric. bits for asymmetric. - * reference: Table 7.18 Mapping of bap to Quantizer - */ -static const uint8_t quantization_tab[16] = { - 0, 3, 5, 7, 11, 15, - 5, 6, 7, 8, 9, 10, 11, 12, 14, 16 -}; - #if (!USE_FIXED) /** dynamic range table. converts codes to scale factors. */ static float dynamic_range_tab[256]; float ff_ac3_heavy_dynamic_range_tab[256]; -#endif - -/** Adjustments in dB gain */ -static const float gain_levels[9] = { - LEVEL_PLUS_3DB, - LEVEL_PLUS_1POINT5DB, - LEVEL_ONE, - LEVEL_MINUS_1POINT5DB, - LEVEL_MINUS_3DB, - LEVEL_MINUS_4POINT5DB, - LEVEL_MINUS_6DB, - LEVEL_ZERO, - LEVEL_MINUS_9DB -}; - -/** Adjustments in dB gain (LFE, +10 to -21 dB) */ -static const float gain_levels_lfe[32] = { - 3.162275, 2.818382, 2.511886, 2.238719, 1.995261, 1.778278, 1.584893, - 1.412536, 1.258924, 1.122018, 1.000000, 0.891251, 0.794328, 0.707946, - 0.630957, 0.562341, 0.501187, 0.446683, 0.398107, 0.354813, 0.316227, - 0.281838, 0.251188, 0.223872, 0.199526, 0.177828, 0.158489, 0.141253, - 0.125892, 0.112201, 0.100000, 0.089125 -}; - -/** - * Table for default stereo downmixing coefficients - * reference: Section 7.8.2 Downmixing Into Two Channels - */ -static const uint8_t ac3_default_coeffs[8][5][2] = { - { { 2, 7 }, { 7, 2 }, }, - { { 4, 4 }, }, - { { 2, 7 }, { 7, 2 }, }, - { { 2, 7 }, { 5, 5 }, { 7, 2 }, }, - { { 2, 7 }, { 7, 2 }, { 6, 6 }, }, - { { 2, 7 }, { 5, 5 }, { 7, 2 }, { 8, 8 }, }, - { { 2, 7 }, { 7, 2 }, { 6, 7 }, { 7, 6 }, }, - { { 2, 7 }, { 5, 5 }, { 7, 2 }, { 6, 7 }, { 7, 6 }, }, -}; - -/** - * Symmetrical Dequantization - * reference: Section 7.3.3 Expansion of Mantissas for Symmetrical Quantization - * Tables 7.19 to 7.23 - */ -static inline int -symmetric_dequant(int code, int levels) -{ - return ((code - (levels >> 1)) * (1 << 24)) / levels; -} /* * Initialize tables at runtime. */ -static av_cold void ac3_tables_init(void) +static av_cold void ac3_float_tables_init(void) { - int i; - - /* generate table for ungrouping 3 values in 7 bits - reference: Section 7.1.3 Exponent Decoding */ - for (i = 0; i < 128; i++) { - ungroup_3_in_7_bits_tab[i][0] = i / 25; - ungroup_3_in_7_bits_tab[i][1] = (i % 25) / 5; - ungroup_3_in_7_bits_tab[i][2] = (i % 25) % 5; - } - - /* generate grouped mantissa tables - reference: Section 7.3.5 Ungrouping of Mantissas */ - for (i = 0; i < 32; i++) { - /* bap=1 mantissas */ - b1_mantissas[i][0] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][0], 3); - b1_mantissas[i][1] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][1], 3); - b1_mantissas[i][2] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][2], 3); - } - for (i = 0; i < 128; i++) { - /* bap=2 mantissas */ - b2_mantissas[i][0] = symmetric_dequant(ungroup_3_in_7_bits_tab[i][0], 5); - b2_mantissas[i][1] = symmetric_dequant(ungroup_3_in_7_bits_tab[i][1], 5); - b2_mantissas[i][2] = symmetric_dequant(ungroup_3_in_7_bits_tab[i][2], 5); - - /* bap=4 mantissas */ - b4_mantissas[i][0] = symmetric_dequant(i / 11, 11); - b4_mantissas[i][1] = symmetric_dequant(i % 11, 11); - } - /* generate ungrouped mantissa tables - reference: Tables 7.21 and 7.23 */ - for (i = 0; i < 7; i++) { - /* bap=3 mantissas */ - b3_mantissas[i] = symmetric_dequant(i, 7); - } - for (i = 0; i < 15; i++) { - /* bap=5 mantissas */ - b5_mantissas[i] = symmetric_dequant(i, 15); - } - -#if (!USE_FIXED) /* generate dynamic range table reference: Section 7.7.1 Dynamic Range Control */ - for (i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) { int v = (i >> 5) - ((i >> 7) << 3) - 5; dynamic_range_tab[i] = powf(2.0f, v) * ((i & 0x1F) | 0x20); } /* generate compr dynamic range table reference: Section 7.7.2 Heavy Compression */ - for (i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) { int v = (i >> 4) - ((i >> 7) << 4) - 4; ff_ac3_heavy_dynamic_range_tab[i] = powf(2.0f, v) * ((i & 0xF) | 0x10); } -#endif + ff_ac3_init_static(); } +#endif static void ac3_downmix(AVCodecContext *avctx) { @@ -206,7 +96,6 @@ static void ac3_downmix(AVCodecContext *avctx) */ static av_cold int ac3_decode_init(AVCodecContext *avctx) { - static AVOnce init_static_once = AV_ONCE_INIT; AC3DecodeContext *s = avctx->priv_data; const float scale = 1.0f; int i, ret; @@ -247,75 +136,24 @@ static av_cold int ac3_decode_init(AVCodecContext *avctx) s->dlyptr[i] = s->delay[i]; } - ff_thread_once(&init_static_once, ac3_tables_init); +#if USE_FIXED + ff_ac3_init_static(); +#else + static AVOnce init_static_once = AV_ONCE_INIT; + ff_thread_once(&init_static_once, ac3_float_tables_init); +#endif return 0; } -/** - * Parse the 'sync info' and 'bit stream info' from the AC-3 bitstream. - * GetBitContext within AC3DecodeContext must point to - * the start of the synchronized AC-3 bitstream. - */ -static int ac3_parse_header(AC3DecodeContext *s) +static av_cold void ac3_decode_flush(AVCodecContext *avctx) { - GetBitContext *gbc = &s->gbc; - int i; + AC3DecodeContext *s = avctx->priv_data; - /* read the rest of the bsi. read twice for dual mono mode. */ - i = !s->channel_mode; - do { - s->dialog_normalization[(!s->channel_mode)-i] = -get_bits(gbc, 5); - if (s->dialog_normalization[(!s->channel_mode)-i] == 0) { - s->dialog_normalization[(!s->channel_mode)-i] = -31; - } - if (s->target_level != 0) { - s->level_gain[(!s->channel_mode)-i] = powf(2.0f, - (float)(s->target_level - - s->dialog_normalization[(!s->channel_mode)-i])/6.0f); - } - if (s->compression_exists[(!s->channel_mode)-i] = get_bits1(gbc)) { - s->heavy_dynamic_range[(!s->channel_mode)-i] = - AC3_HEAVY_RANGE(get_bits(gbc, 8)); - } - if (get_bits1(gbc)) - skip_bits(gbc, 8); //skip language code - if (get_bits1(gbc)) - skip_bits(gbc, 7); //skip audio production information - } while (i--); + memset(&s->frame_type, 0, sizeof(*s) - offsetof(AC3DecodeContext, frame_type)); - skip_bits(gbc, 2); //skip copyright bit and original bitstream bit - - /* skip the timecodes or parse the Alternate Bit Stream Syntax */ - if (s->bitstream_id != 6) { - if (get_bits1(gbc)) - skip_bits(gbc, 14); //skip timecode1 - if (get_bits1(gbc)) - skip_bits(gbc, 14); //skip timecode2 - } else { - if (get_bits1(gbc)) { - s->preferred_downmix = get_bits(gbc, 2); - s->center_mix_level_ltrt = get_bits(gbc, 3); - s->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7); - s->center_mix_level = get_bits(gbc, 3); - s->surround_mix_level = av_clip(get_bits(gbc, 3), 3, 7); - } - if (get_bits1(gbc)) { - s->dolby_surround_ex_mode = get_bits(gbc, 2); - s->dolby_headphone_mode = get_bits(gbc, 2); - skip_bits(gbc, 10); // skip adconvtyp (1), xbsi2 (8), encinfo (1) - } - } - - /* skip additional bitstream info */ - if (get_bits1(gbc)) { - i = get_bits(gbc, 6); - do { - skip_bits(gbc, 8); - } while (i--); - } - - return 0; + AC3_RENAME(ff_kbd_window_init)(s->window, 5.0, 256); + av_lfg_init(&s->dith_state, 0); } /** @@ -345,9 +183,11 @@ static int parse_frame_header(AC3DecodeContext *s) s->frame_size = hdr.frame_size; s->superframe_size += hdr.frame_size; s->preferred_downmix = AC3_DMIXMOD_NOTINDICATED; - s->center_mix_level = hdr.center_mix_level; + if (hdr.bitstream_id <= 10) { + s->center_mix_level = hdr.center_mix_level; + s->surround_mix_level = hdr.surround_mix_level; + } s->center_mix_level_ltrt = 4; // -3.0dB - s->surround_mix_level = hdr.surround_mix_level; s->surround_mix_level_ltrt = 4; // -3.0dB s->lfe_mix_level_exists = 0; s->num_blocks = hdr.num_blocks; @@ -375,10 +215,25 @@ static int parse_frame_header(AC3DecodeContext *s) s->dba_syntax = 1; s->skip_syntax = 1; memset(s->channel_uses_aht, 0, sizeof(s->channel_uses_aht)); - return ac3_parse_header(s); + /* volume control params */ + for (int i = 0; i < (s->channel_mode ? 1 : 2); i++) { + s->dialog_normalization[i] = hdr.dialog_normalization[i]; + if (s->dialog_normalization[i] == 0) { + s->dialog_normalization[i] = -31; + } + if (s->target_level != 0) { + s->level_gain[i] = powf(2.0f, + (float)(s->target_level - s->dialog_normalization[i])/6.0f); + } + s->compression_exists[i] = hdr.compression_exists[i]; + if (s->compression_exists[i]) { + s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(hdr.heavy_dynamic_range[i]); + } + } + return 0; } else if (CONFIG_EAC3_DECODER) { s->eac3 = 1; - return ff_eac3_parse_header(s); + return ff_eac3_parse_header(s, &hdr); } else { av_log(s->avctx, AV_LOG_ERROR, "E-AC-3 support not compiled in\n"); return AVERROR(ENOSYS); @@ -392,8 +247,8 @@ static int parse_frame_header(AC3DecodeContext *s) static int set_downmix_coeffs(AC3DecodeContext *s) { int i; - float cmix = gain_levels[s-> center_mix_level]; - float smix = gain_levels[s->surround_mix_level]; + float cmix = ff_ac3_gain_levels[s-> center_mix_level]; + float smix = ff_ac3_gain_levels[s->surround_mix_level]; float norm0, norm1; float downmix_coeffs[2][AC3_MAX_CHANNELS]; @@ -406,8 +261,8 @@ static int set_downmix_coeffs(AC3DecodeContext *s) } for (i = 0; i < s->fbw_channels; i++) { - downmix_coeffs[0][i] = gain_levels[ac3_default_coeffs[s->channel_mode][i][0]]; - downmix_coeffs[1][i] = gain_levels[ac3_default_coeffs[s->channel_mode][i][1]]; + downmix_coeffs[0][i] = ff_ac3_gain_levels[ff_ac3_default_coeffs[s->channel_mode][i][0]]; + downmix_coeffs[1][i] = ff_ac3_gain_levels[ff_ac3_default_coeffs[s->channel_mode][i][1]]; } if (s->channel_mode > 1 && s->channel_mode & 1) { downmix_coeffs[0][1] = downmix_coeffs[1][1] = cmix; @@ -467,9 +322,9 @@ static int decode_exponents(AC3DecodeContext *s, av_log(s->avctx, AV_LOG_ERROR, "expacc %d is out-of-range\n", expacc); return AVERROR_INVALIDDATA; } - dexp[i++] = ungroup_3_in_7_bits_tab[expacc][0]; - dexp[i++] = ungroup_3_in_7_bits_tab[expacc][1]; - dexp[i++] = ungroup_3_in_7_bits_tab[expacc][2]; + dexp[i++] = ff_ac3_ungroup_3_in_7_bits_tab[expacc][0]; + dexp[i++] = ff_ac3_ungroup_3_in_7_bits_tab[expacc][1]; + dexp[i++] = ff_ac3_ungroup_3_in_7_bits_tab[expacc][2]; } /* convert to absolute exps and expand groups */ @@ -564,9 +419,9 @@ static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, ma mantissa = m->b1_mant[m->b1]; } else { int bits = get_bits(gbc, 5); - mantissa = b1_mantissas[bits][0]; - m->b1_mant[1] = b1_mantissas[bits][1]; - m->b1_mant[0] = b1_mantissas[bits][2]; + mantissa = ff_ac3_bap1_mantissas[bits][0]; + m->b1_mant[1] = ff_ac3_bap1_mantissas[bits][1]; + m->b1_mant[0] = ff_ac3_bap1_mantissas[bits][2]; m->b1 = 2; } break; @@ -576,14 +431,14 @@ static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, ma mantissa = m->b2_mant[m->b2]; } else { int bits = get_bits(gbc, 7); - mantissa = b2_mantissas[bits][0]; - m->b2_mant[1] = b2_mantissas[bits][1]; - m->b2_mant[0] = b2_mantissas[bits][2]; + mantissa = ff_ac3_bap2_mantissas[bits][0]; + m->b2_mant[1] = ff_ac3_bap2_mantissas[bits][1]; + m->b2_mant[0] = ff_ac3_bap2_mantissas[bits][2]; m->b2 = 2; } break; case 3: - mantissa = b3_mantissas[get_bits(gbc, 3)]; + mantissa = ff_ac3_bap3_mantissas[get_bits(gbc, 3)]; break; case 4: if (m->b4) { @@ -591,13 +446,13 @@ static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, ma mantissa = m->b4_mant; } else { int bits = get_bits(gbc, 7); - mantissa = b4_mantissas[bits][0]; - m->b4_mant = b4_mantissas[bits][1]; + mantissa = ff_ac3_bap4_mantissas[bits][0]; + m->b4_mant = ff_ac3_bap4_mantissas[bits][1]; m->b4 = 1; } break; case 5: - mantissa = b5_mantissas[get_bits(gbc, 4)]; + mantissa = ff_ac3_bap5_mantissas[get_bits(gbc, 4)]; break; default: /* 6 to 15 */ /* Shift mantissa and sign-extend it. */ @@ -605,7 +460,7 @@ static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, ma av_log(s->avctx, AV_LOG_ERROR, "bap %d is invalid in plain AC-3\n", bap); bap = 15; } - mantissa = (unsigned)get_sbits(gbc, quantization_tab[bap]) << (24 - quantization_tab[bap]); + mantissa = (unsigned)get_sbits(gbc, ff_ac3_quantization_tab[bap]) << (24 - ff_ac3_quantization_tab[bap]); break; } coeffs[freq] = mantissa >> exps[freq]; @@ -842,16 +697,18 @@ static void decode_band_structure(GetBitContext *gbc, int blk, int eac3, static inline int spx_strategy(AC3DecodeContext *s, int blk) { GetBitContext *bc = &s->gbc; - int fbw_channels = s->fbw_channels; int dst_start_freq, dst_end_freq, src_start_freq, - start_subband, end_subband, ch; + start_subband, end_subband; /* determine which channels use spx */ if (s->channel_mode == AC3_CHMODE_MONO) { s->channel_uses_spx[1] = 1; } else { - for (ch = 1; ch <= fbw_channels; ch++) - s->channel_uses_spx[ch] = get_bits1(bc); + unsigned channel_uses_spx = get_bits(bc, s->fbw_channels); + for (int ch = s->fbw_channels; ch >= 1; --ch) { + s->channel_uses_spx[ch] = channel_uses_spx & 1; + channel_uses_spx >>= 1; + } } /* get the frequency bins of the spx copy region and the spx start @@ -1498,7 +1355,6 @@ static int ac3_decode_frame(AVCodecContext *avctx, AVFrame *frame, uint8_t extended_channel_map[EAC3_MAX_CHANNELS]; const SHORTFLOAT *output[AC3_MAX_CHANNELS]; enum AVMatrixEncoding matrix_encoding; - AVDownmixInfo *downmix_info; uint64_t mask; s->superframe_size = 0; @@ -1562,6 +1418,9 @@ dependent_frame: av_log(avctx, AV_LOG_ERROR, "invalid frame type\n"); } break; + case AC3_PARSE_ERROR_CHANNEL_MAP: + av_log(avctx, AV_LOG_ERROR, "invalid channel map\n"); + return AVERROR_INVALIDDATA; case AC3_PARSE_ERROR_CRC: break; default: // Normal AVERROR do not try to recover. @@ -1607,10 +1466,24 @@ dependent_frame: s->output_mode = AC3_CHMODE_STEREO; } - s->loro_center_mix_level = gain_levels[s-> center_mix_level]; - s->loro_surround_mix_level = gain_levels[s->surround_mix_level]; - s->ltrt_center_mix_level = LEVEL_MINUS_3DB; - s->ltrt_surround_mix_level = LEVEL_MINUS_3DB; + s->loro_center_mix_level = ff_ac3_gain_levels[s-> center_mix_level]; + s->loro_surround_mix_level = ff_ac3_gain_levels[s->surround_mix_level]; + s->ltrt_center_mix_level = ff_ac3_gain_levels[s-> center_mix_level_ltrt]; + s->ltrt_surround_mix_level = ff_ac3_gain_levels[s->surround_mix_level_ltrt]; + switch (s->preferred_downmix) { + case AC3_DMIXMOD_LTRT: + s->preferred_stereo_downmix = AV_DOWNMIX_TYPE_LTRT; + break; + case AC3_DMIXMOD_LORO: + s->preferred_stereo_downmix = AV_DOWNMIX_TYPE_LORO; + break; + case AC3_DMIXMOD_DPLII: + s->preferred_stereo_downmix = AV_DOWNMIX_TYPE_DPLII; + break; + default: + s->preferred_stereo_downmix = AV_DOWNMIX_TYPE_UNKNOWN; + break; + } /* set downmixing coefficients if needed */ if (s->channels != s->out_channels && !((s->output_mode & AC3_OUTPUT_LFEON) && s->fbw_channels == s->out_channels)) { @@ -1811,11 +1684,16 @@ skip: break; } } - if ((ret = ff_side_data_update_matrix_encoding(frame, matrix_encoding)) < 0) + if (matrix_encoding != AV_MATRIX_ENCODING_NONE && + (ret = ff_side_data_update_matrix_encoding(frame, matrix_encoding)) < 0) return ret; /* AVDownmixInfo */ - if ((downmix_info = av_downmix_info_update_side_data(frame))) { + if ( (s->channel_mode > AC3_CHMODE_STEREO) && + ((s->output_mode & ~AC3_OUTPUT_LFEON) > AC3_CHMODE_STEREO)) { + AVDownmixInfo *downmix_info = av_downmix_info_update_side_data(frame); + if (!downmix_info) + return AVERROR(ENOMEM); switch (s->preferred_downmix) { case AC3_DMIXMOD_LTRT: downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_LTRT; @@ -1830,16 +1708,15 @@ skip: downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_UNKNOWN; break; } - downmix_info->center_mix_level = gain_levels[s-> center_mix_level]; - downmix_info->center_mix_level_ltrt = gain_levels[s-> center_mix_level_ltrt]; - downmix_info->surround_mix_level = gain_levels[s-> surround_mix_level]; - downmix_info->surround_mix_level_ltrt = gain_levels[s->surround_mix_level_ltrt]; + downmix_info->center_mix_level = ff_ac3_gain_levels[s-> center_mix_level]; + downmix_info->center_mix_level_ltrt = ff_ac3_gain_levels[s-> center_mix_level_ltrt]; + downmix_info->surround_mix_level = ff_ac3_gain_levels[s-> surround_mix_level]; + downmix_info->surround_mix_level_ltrt = ff_ac3_gain_levels[s->surround_mix_level_ltrt]; if (s->lfe_mix_level_exists) - downmix_info->lfe_mix_level = gain_levels_lfe[s->lfe_mix_level]; + downmix_info->lfe_mix_level = ff_eac3_gain_levels_lfe[s->lfe_mix_level]; else downmix_info->lfe_mix_level = 0.0; // -inf dB - } else - return AVERROR(ENOMEM); + } *got_frame_ptr = 1; diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h index 98de7b5ab..a09926447 100644 --- a/libavcodec/ac3dec.h +++ b/libavcodec/ac3dec.h @@ -75,6 +75,29 @@ typedef struct AC3DecodeContext { AVCodecContext *avctx; ///< parent context GetBitContext gbc; ///< bitstream reader +///@name Optimization + BswapDSPContext bdsp; +#if USE_FIXED + AVFixedDSPContext *fdsp; +#else + AVFloatDSPContext *fdsp; +#endif + AC3DSPContext ac3dsp; + FmtConvertContext fmt_conv; ///< optimized conversion functions +///@} + + AVTXContext *tx_128, *tx_256; + av_tx_fn tx_fn_128, tx_fn_256; + + INTFLOAT *xcfptr[AC3_MAX_CHANNELS]; + INTFLOAT *dlyptr[AC3_MAX_CHANNELS]; + + AVChannelLayout downmix_layout; + SHORTFLOAT *downmix_coeffs[2]; ///< stereo downmix coefficients + +// Start of flushable fields. +// frame_type must be the flushable field, or the offset changed in ac3_decode_flush(). + ///@name Bit stream information ///@{ int frame_type; ///< frame type (strmtyp) @@ -164,7 +187,6 @@ typedef struct AC3DecodeContext { int fbw_channels; ///< number of full-bandwidth channels int channels; ///< number of total channels int lfe_ch; ///< index of LFE channel - SHORTFLOAT *downmix_coeffs[2]; ///< stereo downmix coefficients int downmixed; ///< indicates if coeffs are currently downmixed int output_mode; ///< output channel configuration int prev_output_mode; ///< output channel configuration for previous frame @@ -222,24 +244,9 @@ typedef struct AC3DecodeContext { ///@name IMDCT int block_switch[AC3_MAX_CHANNELS]; ///< block switch flags (blksw) - AVTXContext *tx_128, *tx_256; - av_tx_fn tx_fn_128, tx_fn_256; -///@} - -///@name Optimization - BswapDSPContext bdsp; -#if USE_FIXED - AVFixedDSPContext *fdsp; -#else - AVFloatDSPContext *fdsp; -#endif - AC3DSPContext ac3dsp; - FmtConvertContext fmt_conv; ///< optimized conversion functions ///@} SHORTFLOAT *outptr[AC3_MAX_CHANNELS]; - INTFLOAT *xcfptr[AC3_MAX_CHANNELS]; - INTFLOAT *dlyptr[AC3_MAX_CHANNELS]; ///@name Aligned arrays DECLARE_ALIGNED(16, int, fixed_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< fixed-point transform coefficients @@ -251,15 +258,15 @@ typedef struct AC3DecodeContext { DECLARE_ALIGNED(32, uint8_t, input_buffer)[AC3_FRAME_BUFFER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; ///< temp buffer to prevent overread DECLARE_ALIGNED(32, SHORTFLOAT, output_buffer)[EAC3_MAX_CHANNELS][AC3_BLOCK_SIZE * 6]; ///< final output buffer ///@} - - AVChannelLayout downmix_layout; } AC3DecodeContext; +struct AC3HeaderInfo; + /** * Parse the E-AC-3 frame header. * This parses both the bit stream info and audio frame header. */ -static int ff_eac3_parse_header(AC3DecodeContext *s); +static int ff_eac3_parse_header(AC3DecodeContext *s, const struct AC3HeaderInfo *hdr); /** * Decode mantissas in a single channel for the entire frame. diff --git a/libavcodec/ac3dec_data.c b/libavcodec/ac3dec_data.c index a3794ab22..0f5402c33 100644 --- a/libavcodec/ac3dec_data.c +++ b/libavcodec/ac3dec_data.c @@ -21,10 +21,11 @@ /** * @file - * Tables taken directly from the AC-3 spec. + * Tables taken directly from the AC-3 spec or derived from it. */ #include "ac3dec_data.h" +#include "libavutil/thread.h" /** * Table used to ungroup 3 values stored in 5 bits. @@ -42,6 +43,124 @@ const uint8_t ff_ac3_ungroup_3_in_5_bits_tab[32][3] = { { 3, 0, 1 }, { 3, 0, 2 }, { 3, 1, 0 }, { 3, 1, 1 } }; +/** + * table for ungrouping 3 values in 7 bits. + * used for exponents and bap=2 mantissas + */ +uint8_t ff_ac3_ungroup_3_in_7_bits_tab[128][3]; + +/** + * Symmetrical Dequantization + * reference: Section 7.3.3 Expansion of Mantissas for Symmetrical Quantization + * Tables 7.19 to 7.23 + */ +#define SYMMETRIC_DEQUANT(code, levels) (((code - (levels >> 1)) * (1 << 24)) / levels) +/** + * Ungrouped mantissa tables; the extra entry is padding to avoid range checks + */ +/** + * Table 7.21 + */ +const int ff_ac3_bap3_mantissas[7 + 1] = { + SYMMETRIC_DEQUANT(0, 7), + SYMMETRIC_DEQUANT(1, 7), + SYMMETRIC_DEQUANT(2, 7), + SYMMETRIC_DEQUANT(3, 7), + SYMMETRIC_DEQUANT(4, 7), + SYMMETRIC_DEQUANT(5, 7), + SYMMETRIC_DEQUANT(6, 7), +}; +/** + * Table 7.23 + */ +const int ff_ac3_bap5_mantissas[15 + 1] = { + SYMMETRIC_DEQUANT(0, 15), + SYMMETRIC_DEQUANT(1, 15), + SYMMETRIC_DEQUANT(2, 15), + SYMMETRIC_DEQUANT(3, 15), + SYMMETRIC_DEQUANT(4, 15), + SYMMETRIC_DEQUANT(5, 15), + SYMMETRIC_DEQUANT(6, 15), + SYMMETRIC_DEQUANT(7, 15), + SYMMETRIC_DEQUANT(8, 15), + SYMMETRIC_DEQUANT(9, 15), + SYMMETRIC_DEQUANT(10, 15), + SYMMETRIC_DEQUANT(11, 15), + SYMMETRIC_DEQUANT(12, 15), + SYMMETRIC_DEQUANT(13, 15), + SYMMETRIC_DEQUANT(14, 15), +}; + +int ff_ac3_bap1_mantissas[32][3]; +int ff_ac3_bap2_mantissas[128][3]; +int ff_ac3_bap4_mantissas[128][2]; + +static inline int +symmetric_dequant(int code, int levels) +{ + return SYMMETRIC_DEQUANT(code, levels); +} + +static av_cold void ac3_init_static(void) +{ + /* generate table for ungrouping 3 values in 7 bits + reference: Section 7.1.3 Exponent Decoding */ + for (int i = 0; i < 128; ++i) { + ff_ac3_ungroup_3_in_7_bits_tab[i][0] = i / 25; + ff_ac3_ungroup_3_in_7_bits_tab[i][1] = (i % 25) / 5; + ff_ac3_ungroup_3_in_7_bits_tab[i][2] = (i % 25) % 5; + } + + /* generate grouped mantissa tables + reference: Section 7.3.5 Ungrouping of Mantissas */ + for (int i = 0; i < 32; ++i) { + /* bap=1 mantissas */ + ff_ac3_bap1_mantissas[i][0] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][0], 3); + ff_ac3_bap1_mantissas[i][1] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][1], 3); + ff_ac3_bap1_mantissas[i][2] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][2], 3); + } + for (int i = 0; i < 128; ++i) { + /* bap=2 mantissas */ + ff_ac3_bap2_mantissas[i][0] = symmetric_dequant(ff_ac3_ungroup_3_in_7_bits_tab[i][0], 5); + ff_ac3_bap2_mantissas[i][1] = symmetric_dequant(ff_ac3_ungroup_3_in_7_bits_tab[i][1], 5); + ff_ac3_bap2_mantissas[i][2] = symmetric_dequant(ff_ac3_ungroup_3_in_7_bits_tab[i][2], 5); + + /* bap=4 mantissas */ + ff_ac3_bap4_mantissas[i][0] = symmetric_dequant(i / 11, 11); + ff_ac3_bap4_mantissas[i][1] = symmetric_dequant(i % 11, 11); + } +} + +av_cold void ff_ac3_init_static(void) +{ + static AVOnce ac3_init_static_once = AV_ONCE_INIT; + ff_thread_once(&ac3_init_static_once, ac3_init_static); +} + +/** + * Quantization table: levels for symmetric. bits for asymmetric. + * reference: Table 7.18 Mapping of bap to Quantizer + */ +const uint8_t ff_ac3_quantization_tab[16] = { + 0, 3, 5, 7, 11, 15, + 5, 6, 7, 8, 9, 10, 11, 12, 14, 16 +}; + +/** + * Table for default stereo downmixing coefficients + * reference: Section 7.8.2 Downmixing Into Two Channels + */ +const uint8_t ff_ac3_default_coeffs[8][5][2] = { + { { 2, 7 }, { 7, 2 }, }, + { { 4, 4 }, }, + { { 2, 7 }, { 7, 2 }, }, + { { 2, 7 }, { 5, 5 }, { 7, 2 }, }, + { { 2, 7 }, { 7, 2 }, { 6, 6 }, }, + { { 2, 7 }, { 5, 5 }, { 7, 2 }, { 8, 8 }, }, + { { 2, 7 }, { 7, 2 }, { 6, 7 }, { 7, 6 }, }, + { { 2, 7 }, { 5, 5 }, { 7, 2 }, { 6, 7 }, { 7, 6 }, }, +}; + const uint8_t ff_eac3_hebap_tab[64] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, @@ -57,3 +176,12 @@ const uint8_t ff_eac3_hebap_tab[64] = { */ const uint8_t ff_eac3_default_spx_band_struct[17] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }; + +/** Adjustments in dB gain (LFE, +10 to -21 dB) */ +const float ff_eac3_gain_levels_lfe[32] = { + 3.162275, 2.818382, 2.511886, 2.238719, 1.995261, 1.778278, 1.584893, + 1.412536, 1.258924, 1.122018, 1.000000, 0.891251, 0.794328, 0.707946, + 0.630957, 0.562341, 0.501187, 0.446683, 0.398107, 0.354813, 0.316227, + 0.281838, 0.251188, 0.223872, 0.199526, 0.177828, 0.158489, 0.141253, + 0.125892, 0.112201, 0.100000, 0.089125 +}; diff --git a/libavcodec/ac3dec_data.h b/libavcodec/ac3dec_data.h index 975b52ef2..613871627 100644 --- a/libavcodec/ac3dec_data.h +++ b/libavcodec/ac3dec_data.h @@ -24,9 +24,31 @@ #include +#include "libavutil/attributes_internal.h" + +FF_VISIBILITY_PUSH_HIDDEN + extern const uint8_t ff_ac3_ungroup_3_in_5_bits_tab[32][3]; +extern uint8_t ff_ac3_ungroup_3_in_7_bits_tab[128][3]; + +extern const int ff_ac3_bap3_mantissas[ 7 + 1]; +extern const int ff_ac3_bap5_mantissas[15 + 1]; + +/** tables for ungrouping mantissas */ +extern int ff_ac3_bap1_mantissas[32][3]; +extern int ff_ac3_bap2_mantissas[128][3]; +extern int ff_ac3_bap4_mantissas[128][2]; + +extern const uint8_t ff_ac3_quantization_tab[16]; + +extern const uint8_t ff_ac3_default_coeffs[8][5][2]; extern const uint8_t ff_eac3_hebap_tab[64]; extern const uint8_t ff_eac3_default_spx_band_struct[17]; +extern const float ff_eac3_gain_levels_lfe[32]; + +void ff_ac3_init_static(void); + +FF_VISIBILITY_POP_HIDDEN #endif /* AVCODEC_AC3DEC_DATA_H */ diff --git a/libavcodec/ac3dec_fixed.c b/libavcodec/ac3dec_fixed.c index c9e5cda69..285553c22 100644 --- a/libavcodec/ac3dec_fixed.c +++ b/libavcodec/ac3dec_fixed.c @@ -47,6 +47,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config_components.h" #define USE_FIXED 1 #include "ac3dec.h" #include "codec_internal.h" @@ -152,7 +153,9 @@ static void ac3_downmix_c_fixed16(int16_t **samples, int16_t **matrix, } } +#if CONFIG_EAC3_DECODER #include "eac3dec.c" +#endif #include "ac3dec.c" static const AVOption options[] = { @@ -178,11 +181,11 @@ const FFCodec ff_ac3_fixed_decoder = { .p.priv_class = &ac3_decoder_class, .priv_data_size = sizeof (AC3DecodeContext), .init = ac3_decode_init, + .flush = ac3_decode_flush, .close = ac3_decode_end, FF_CODEC_DECODE_CB(ac3_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/ac3dec_float.c b/libavcodec/ac3dec_float.c index 550a9017d..95a0c424c 100644 --- a/libavcodec/ac3dec_float.c +++ b/libavcodec/ac3dec_float.c @@ -34,20 +34,23 @@ #include "ac3dec.h" #include "codec_internal.h" #include "profiles.h" +#if CONFIG_EAC3_DECODER #include "eac3dec.c" +#endif #include "ac3dec.c" +#define EXPORT (AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY) static const AVOption options[] = { { "cons_noisegen", "enable consistent noise generation", OFFSET(consistent_noise_generation), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR }, { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR }, { "heavy_compr", "enable heavy dynamic range compression", OFFSET(heavy_compression), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR }, { "target_level", "target level in -dBFS (0 not applied)", OFFSET(target_level), AV_OPT_TYPE_INT, {.i64 = 0 }, -31, 0, PAR }, -{"dmix_mode", "Preferred Stereo Downmix Mode", OFFSET(preferred_stereo_downmix), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 2, 0, .unit = "dmix_mode"}, -{"ltrt_cmixlev", "Lt/Rt Center Mix Level", OFFSET(ltrt_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, -{"ltrt_surmixlev", "Lt/Rt Surround Mix Level", OFFSET(ltrt_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, -{"loro_cmixlev", "Lo/Ro Center Mix Level", OFFSET(loro_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, -{"loro_surmixlev", "Lo/Ro Surround Mix Level", OFFSET(loro_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, +{"dmix_mode", "Preferred Stereo Downmix Mode", OFFSET(preferred_stereo_downmix), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 3, EXPORT, .unit = "dmix_mode"}, +{"ltrt_cmixlev", "Lt/Rt Center Mix Level", OFFSET(ltrt_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, EXPORT }, +{"ltrt_surmixlev", "Lt/Rt Surround Mix Level", OFFSET(ltrt_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, EXPORT }, +{"loro_cmixlev", "Lo/Ro Center Mix Level", OFFSET(loro_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, EXPORT }, +{"loro_surmixlev", "Lo/Ro Surround Mix Level", OFFSET(loro_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, EXPORT }, { "downmix", "Request a specific channel layout from the decoder", OFFSET(downmix_layout), AV_OPT_TYPE_CHLAYOUT, {.str = NULL}, .flags = PAR }, @@ -67,13 +70,13 @@ const FFCodec ff_ac3_decoder = { .p.id = AV_CODEC_ID_AC3, .priv_data_size = sizeof (AC3DecodeContext), .init = ac3_decode_init, + .flush = ac3_decode_flush, .close = ac3_decode_end, FF_CODEC_DECODE_CB(ac3_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, CODEC_LONG_NAME("ATSC A/52A (AC-3)"), - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &ac3_eac3_decoder_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; @@ -85,13 +88,13 @@ const FFCodec ff_eac3_decoder = { .p.id = AV_CODEC_ID_EAC3, .priv_data_size = sizeof (AC3DecodeContext), .init = ac3_decode_init, + .flush = ac3_decode_flush, .close = ac3_decode_end, FF_CODEC_DECODE_CB(ac3_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, CODEC_LONG_NAME("ATSC A/52B (AC-3, E-AC-3)"), - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &ac3_eac3_decoder_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_eac3_profiles), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/ac3defs.h b/libavcodec/ac3defs.h index ff92f0ac4..8d6a58d21 100644 --- a/libavcodec/ac3defs.h +++ b/libavcodec/ac3defs.h @@ -34,6 +34,19 @@ #define AC3_CRITICAL_BANDS 50 #define AC3_MAX_CPL_BANDS 18 +#define EAC3_SR_CODE_REDUCED 3 + +/* pre-defined gain values */ +#define LEVEL_PLUS_3DB M_SQRT2 +#define LEVEL_PLUS_1POINT5DB 1.1892071150027209 +#define LEVEL_MINUS_1POINT5DB 0.8408964152537145 +#define LEVEL_MINUS_3DB M_SQRT1_2 +#define LEVEL_MINUS_4POINT5DB 0.5946035575013605 +#define LEVEL_MINUS_6DB 0.5000000000000000 +#define LEVEL_MINUS_9DB 0.3535533905932738 +#define LEVEL_ZERO 0.0000000000000000 +#define LEVEL_ONE 1.0000000000000000 + /* exponent encoding strategy */ #define EXP_REUSE 0 #define EXP_NEW 1 diff --git a/libavcodec/ac3dsp.c b/libavcodec/ac3dsp.c index 730fa70ff..a4a28c867 100644 --- a/libavcodec/ac3dsp.c +++ b/libavcodec/ac3dsp.c @@ -363,7 +363,7 @@ void ff_ac3dsp_downmix(AC3DSPContext *c, float **samples, float **matrix, c->downmix = ac3_downmix_5_to_1_symmetric_c; } -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_ac3dsp_set_downmix_x86(c); #endif } @@ -393,7 +393,7 @@ av_cold void ff_ac3dsp_init(AC3DSPContext *c) ff_ac3dsp_init_aarch64(c); #elif ARCH_ARM ff_ac3dsp_init_arm(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_ac3dsp_init_x86(c); #elif ARCH_MIPS ff_ac3dsp_init_mips(c); diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index 364928986..5a1a3ab63 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -32,7 +32,6 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/crc.h" -#include "libavutil/emms.h" #include "libavutil/internal.h" #include "libavutil/mem.h" #include "libavutil/mem_internal.h" @@ -71,10 +70,7 @@ static const float surmixlev_options[SURMIXLEV_NUM_OPTIONS] = { }; #define EXTMIXLEV_NUM_OPTIONS 8 -static const float extmixlev_options[EXTMIXLEV_NUM_OPTIONS] = { - LEVEL_PLUS_3DB, LEVEL_PLUS_1POINT5DB, LEVEL_ONE, LEVEL_MINUS_1POINT5DB, - LEVEL_MINUS_3DB, LEVEL_MINUS_4POINT5DB, LEVEL_MINUS_6DB, LEVEL_ZERO -}; +#define extmixlev_options ff_ac3_gain_levels /* The first two options apply only to the AC-3 encoders; * the rest is also valid for EAC-3. When modifying it, @@ -948,8 +944,6 @@ static void ac3_process_exponents(AC3EncodeContext *s) compute_exp_strategy(s); encode_exponents(s); - - emms_c(); } @@ -1638,6 +1632,8 @@ static void ac3_output_frame_header(AC3EncodeContext *s, PutBitContext *pb) { AC3EncOptions *opt = &s->options; + put_bits_assume_flushed(pb); + put_bits(pb, 16, 0x0b77); /* frame header */ put_bits(pb, 16, 0); /* crc1: will be filled later */ put_bits(pb, 2, s->bit_alloc.sr_code); diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c index 869e1f27a..42530b0ea 100644 --- a/libavcodec/ac3enc_fixed.c +++ b/libavcodec/ac3enc_fixed.c @@ -119,11 +119,10 @@ const FFCodec ff_ac3_fixed_encoder = { .init = ac3_fixed_encode_init, FF_CODEC_ENCODE_CB(ff_ac3_encode_frame), .close = ff_ac3_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), .p.priv_class = &ff_ac3enc_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.supported_samplerates = ff_ac3_sample_rate_tab, - .p.ch_layouts = ff_ac3_ch_layouts, + CODEC_SAMPLERATES_ARRAY(ff_ac3_sample_rate_tab), + CODEC_CH_LAYOUTS_ARRAY(ff_ac3_ch_layouts), .defaults = ff_ac3_enc_defaults, }; diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c index 94e8ebc42..0ae7ddd7e 100644 --- a/libavcodec/ac3enc_float.c +++ b/libavcodec/ac3enc_float.c @@ -121,11 +121,10 @@ const FFCodec ff_ac3_encoder = { .init = ff_ac3_float_encode_init, FF_CODEC_ENCODE_CB(ff_ac3_encode_frame), .close = ff_ac3_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &ff_ac3enc_class, - .p.supported_samplerates = ff_ac3_sample_rate_tab, - .p.ch_layouts = ff_ac3_ch_layouts, + CODEC_SAMPLERATES_ARRAY(ff_ac3_sample_rate_tab), + CODEC_CH_LAYOUTS_ARRAY(ff_ac3_ch_layouts), .defaults = ff_ac3_enc_defaults, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/ac3tab.c b/libavcodec/ac3tab.c index 48c89a8ba..b38e7237b 100644 --- a/libavcodec/ac3tab.c +++ b/libavcodec/ac3tab.c @@ -25,6 +25,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mathematics.h" #include "ac3tab.h" @@ -147,6 +148,19 @@ const uint16_t ff_ac3_fast_gain_tab[8]= { 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400, }; +/** Adjustments in dB gain */ +const float ff_ac3_gain_levels[9] = { + LEVEL_PLUS_3DB, + LEVEL_PLUS_1POINT5DB, + LEVEL_ONE, + LEVEL_MINUS_1POINT5DB, + LEVEL_MINUS_3DB, + LEVEL_MINUS_4POINT5DB, + LEVEL_MINUS_6DB, + LEVEL_ZERO, + LEVEL_MINUS_9DB +}; + const uint64_t ff_eac3_custom_channel_map_locations[16][2] = { { 1, AV_CH_FRONT_LEFT }, { 1, AV_CH_FRONT_CENTER }, diff --git a/libavcodec/ac3tab.h b/libavcodec/ac3tab.h index dcef643ac..3f83ce7b8 100644 --- a/libavcodec/ac3tab.h +++ b/libavcodec/ac3tab.h @@ -26,6 +26,9 @@ #include "ac3defs.h" +#include "libavutil/attributes_internal.h" + +FF_VISIBILITY_PUSH_HIDDEN extern const uint16_t ff_ac3_frame_size_tab[38][3]; extern const uint8_t ff_ac3_channels_tab[8]; extern const uint16_t ff_ac3_channel_layout_tab[8]; @@ -43,7 +46,9 @@ extern const int16_t ff_ac3_floor_tab[8]; extern const uint16_t ff_ac3_fast_gain_tab[8]; extern const uint8_t ff_ac3_band_start_tab[AC3_CRITICAL_BANDS+1]; extern const uint8_t ff_ac3_bin_to_band_tab[253]; +extern const float ff_ac3_gain_levels[9]; extern const uint64_t ff_eac3_custom_channel_map_locations[16][2]; +FF_VISIBILITY_POP_HIDDEN #define COMMON_CHANNEL_MAP \ { { 0, 1, }, { 0, 1, 2, } },\ diff --git a/libavcodec/acelp_filters.c b/libavcodec/acelp_filters.c index db4908f31..99e899485 100644 --- a/libavcodec/acelp_filters.c +++ b/libavcodec/acelp_filters.c @@ -147,7 +147,7 @@ void ff_tilt_compensation(float *mem, float tilt, float *samples, int size) *mem = new_tilt_mem; } -void ff_acelp_filter_init(ACELPFContext *c) +av_cold void ff_acelp_filter_init(ACELPFContext *c) { c->acelp_interpolatef = ff_acelp_interpolatef; c->acelp_apply_order_2_transfer_function = ff_acelp_apply_order_2_transfer_function; diff --git a/libavcodec/acelp_pitch_delay.c b/libavcodec/acelp_pitch_delay.c index 6cf880e4a..65f659cb2 100644 --- a/libavcodec/acelp_pitch_delay.c +++ b/libavcodec/acelp_pitch_delay.c @@ -90,7 +90,7 @@ float ff_amr_set_fixed_gain(float fixed_gain_factor, float fixed_mean_energy, // Note 10^(0.05 * -10log(average x2)) = 1/sqrt((average x2)). float val = fixed_gain_factor * ff_exp10(0.05 * - (avpriv_scalarproduct_float_c(pred_table, prediction_error, 4) + + (ff_scalarproduct_float_c(pred_table, prediction_error, 4) + energy_mean)) / sqrtf(fixed_mean_energy ? fixed_mean_energy : 1.0); diff --git a/libavcodec/acelp_vectors.c b/libavcodec/acelp_vectors.c index 04cbffd79..99d573bda 100644 --- a/libavcodec/acelp_vectors.c +++ b/libavcodec/acelp_vectors.c @@ -193,7 +193,7 @@ void ff_adaptive_gain_control(float *out, const float *in, float speech_energ, int size, float alpha, float *gain_mem) { int i; - float postfilter_energ = avpriv_scalarproduct_float_c(in, in, size); + float postfilter_energ = ff_scalarproduct_float_c(in, in, size); float gain_scale_factor = 1.0; float mem = *gain_mem; @@ -214,7 +214,7 @@ void ff_scale_vector_to_given_sum_of_squares(float *out, const float *in, float sum_of_squares, const int n) { int i; - float scalefactor = avpriv_scalarproduct_float_c(in, in, n); + float scalefactor = ff_scalarproduct_float_c(in, in, n); if (scalefactor) scalefactor = sqrt(sum_of_squares / scalefactor); for (i = 0; i < n; i++) @@ -255,7 +255,7 @@ void ff_clear_fixed_vector(float *out, const AMRFixed *in, int size) } } -void ff_acelp_vectors_init(ACELPVContext *c) +av_cold void ff_acelp_vectors_init(ACELPVContext *c) { c->weighted_vector_sumf = ff_weighted_vector_sumf; diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index a07e7d779..e06aa7606 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -17,6 +17,7 @@ * Ubisoft ADPCM decoder by Zane van Iperen (zane@zanevaniperen.com) * High Voltage Software ALP decoder by Zane van Iperen (zane@zanevaniperen.com) * Cunning Developments decoder by Zane van Iperen (zane@zanevaniperen.com) + * Sanyo LD-ADPCM decoder by Peter Ross (pross@xvid.org) * * This file is part of FFmpeg. * @@ -45,6 +46,8 @@ #include "codec_internal.h" #include "decode.h" +#include "libavutil/attributes.h" + /** * @file * ADPCM decoders @@ -258,8 +261,12 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) switch(avctx->codec->id) { case AV_CODEC_ID_ADPCM_IMA_AMV: + case AV_CODEC_ID_ADPCM_N64: max_channels = 1; break; + case AV_CODEC_ID_ADPCM_SANYO: + max_channels = 2; + break; case AV_CODEC_ID_ADPCM_AFC: case AV_CODEC_ID_ADPCM_EA_R1: case AV_CODEC_ID_ADPCM_EA_R2: @@ -285,6 +292,11 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) avctx->block_align % (16 * avctx->ch_layout.nb_channels)) return AVERROR_INVALIDDATA; break; + case AV_CODEC_ID_ADPCM_PSXC: + max_channels = 8; + if (avctx->ch_layout.nb_channels <= 0 || avctx->block_align <= 0) + return AVERROR_INVALIDDATA; + break; case AV_CODEC_ID_ADPCM_IMA_DAT4: case AV_CODEC_ID_ADPCM_THP: case AV_CODEC_ID_ADPCM_THP_LE: @@ -307,6 +319,14 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) avctx->block_align != 17 * avctx->ch_layout.nb_channels) return AVERROR_INVALIDDATA; break; + case AV_CODEC_ID_ADPCM_SANYO: + if (avctx->bits_per_coded_sample < 3 || avctx->bits_per_coded_sample > 5) + return AVERROR_INVALIDDATA; + break; + case AV_CODEC_ID_ADPCM_IMA_XBOX: + if (avctx->bits_per_coded_sample != 4) + return AVERROR_INVALIDDATA; + break; case AV_CODEC_ID_ADPCM_ZORK: if (avctx->bits_per_coded_sample != 8) return AVERROR_INVALIDDATA; @@ -321,6 +341,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) case AV_CODEC_ID_ADPCM_IMA_DAT4: case AV_CODEC_ID_ADPCM_IMA_QT: case AV_CODEC_ID_ADPCM_IMA_WAV: + case AV_CODEC_ID_ADPCM_IMA_XBOX: case AV_CODEC_ID_ADPCM_4XM: case AV_CODEC_ID_ADPCM_XA: case AV_CODEC_ID_ADPCM_XMD: @@ -333,9 +354,12 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) case AV_CODEC_ID_ADPCM_AFC: case AV_CODEC_ID_ADPCM_DTK: case AV_CODEC_ID_ADPCM_PSX: + case AV_CODEC_ID_ADPCM_PSXC: + case AV_CODEC_ID_ADPCM_SANYO: case AV_CODEC_ID_ADPCM_MTAF: case AV_CODEC_ID_ADPCM_ARGO: case AV_CODEC_ID_ADPCM_IMA_MOFLEX: + case AV_CODEC_ID_ADPCM_N64: avctx->sample_fmt = AV_SAMPLE_FMT_S16P; break; case AV_CODEC_ID_ADPCM_IMA_WS: @@ -396,6 +420,29 @@ static inline int16_t adpcm_agm_expand_nibble(ADPCMChannelStatus *c, int8_t nibb return pred; } +static inline int16_t adpcm_ima_escape_expand_nibble(ADPCMChannelStatus *c, int8_t nibble) +{ + int step_index; + int predictor; + int sign, delta, diff, step; + + step = ff_adpcm_step_table[c->step_index]; + step_index = c->step_index + ff_adpcm_index_table[(unsigned)nibble]; + step_index = av_clip(step_index, 0, 88); + + sign = nibble & 8; + delta = nibble & 7; + diff = (delta * step) >> 2; + predictor = c->predictor; + if (sign) predictor -= diff; + else predictor += diff; + + c->predictor = av_clip_int16(predictor); + c->step_index = step_index; + + return (int16_t)c->predictor; +} + static inline int16_t adpcm_ima_expand_nibble(ADPCMChannelStatus *c, int8_t nibble, int shift) { int step_index; @@ -493,7 +540,9 @@ static inline int16_t adpcm_ima_wav_expand_nibble(ADPCMChannelStatus *c, GetBitC sign = nibble & (1 << shift); delta = av_zero_extend(nibble, shift); - diff = ((2 * delta + 1) * step) >> shift; + diff = step >> shift; + for (int i = 0; i < shift; i++) + diff += (step >> (shift-1-i)) * !!(delta & (1 << i)); predictor = c->predictor; if (sign) predictor -= diff; else predictor += diff; @@ -504,7 +553,7 @@ static inline int16_t adpcm_ima_wav_expand_nibble(ADPCMChannelStatus *c, GetBitC return (int16_t)c->predictor; } -static inline int adpcm_ima_qt_expand_nibble(ADPCMChannelStatus *c, int nibble) +int16_t ff_adpcm_ima_qt_expand_nibble(ADPCMChannelStatus *c, int nibble) { int step_index; int predictor; @@ -530,6 +579,86 @@ static inline int adpcm_ima_qt_expand_nibble(ADPCMChannelStatus *c, int nibble) return c->predictor; } +static void decode_adpcm_ima_hvqm2(AVCodecContext *avctx, int16_t *outbuf, int samples_to_do, + int frame_format, GetByteContext *gb) +{ + ADPCMDecodeContext *c = avctx->priv_data; + int st = avctx->ch_layout.nb_channels == 2; + uint8_t nibble; + + for (int ch = 0; ch < avctx->ch_layout.nb_channels; ch++) { + unsigned tmp; + + switch (frame_format) { + case 0: /* combined hist+index */ + tmp = bytestream2_get_be16(gb); + c->status[ch].predictor = sign_extend(tmp & 0xFF80, 16); + c->status[ch].step_index = tmp & 0x7f; + *outbuf++ = c->status[ch].predictor; + samples_to_do--; + break; + default: + break; + } + + c->status[ch].step_index = av_clip(c->status[ch].step_index, 0, 88); + } + + for (int i = 0; i < samples_to_do; i++) { + if (!(i&1)) { + nibble = bytestream2_get_byte(gb); + *outbuf++ = ff_adpcm_ima_qt_expand_nibble(&c->status[st], nibble >> 4); + } else { + *outbuf++ = ff_adpcm_ima_qt_expand_nibble(&c->status[ 0], nibble & 0xF); + } + } + + bytestream2_seek(gb, 0, SEEK_END); +} + +static void decode_adpcm_ima_hvqm4(AVCodecContext *avctx, int16_t *outbuf, int samples_to_do, + int frame_format, GetByteContext *gb) +{ + ADPCMDecodeContext *c = avctx->priv_data; + int st = avctx->ch_layout.nb_channels == 2; + unsigned tmp; + + for (int ch = 0; ch < avctx->ch_layout.nb_channels; ch++) { + switch (frame_format) { + case 1: /* combined hist+index */ + tmp = bytestream2_get_be16(gb); + c->status[ch].predictor = sign_extend(tmp & 0xFF80, 16); + c->status[ch].step_index = tmp & 0x7f; + break; + case 2: /* no hist/index (continues from previous frame) */ + default: + break; + case 3: /* separate hist+index */ + tmp = bytestream2_get_be16(gb); + c->status[ch].predictor = sign_extend(tmp, 16); + c->status[ch].step_index = bytestream2_get_byte(gb); + break; + } + + c->status[ch].step_index = av_clip(c->status[ch].step_index, 0, 88); + } + + if (frame_format == 1 || frame_format == 3) { + for (int ch = 0; ch < avctx->ch_layout.nb_channels; ch++) + *outbuf++ = (int16_t)c->status[st - ch].predictor; + samples_to_do--; + } + + for (int i = 0; i < samples_to_do; i += 1+(!st)) { + uint8_t nibble = bytestream2_get_byte(gb); + + *outbuf++ = ff_adpcm_ima_qt_expand_nibble(&c->status[st], nibble & 0xF); + *outbuf++ = ff_adpcm_ima_qt_expand_nibble(&c->status[ 0], nibble >> 4); + } + + bytestream2_seek(gb, 0, SEEK_END); +} + static inline int16_t adpcm_ms_expand_nibble(ADPCMChannelStatus *c, int nibble) { int predictor; @@ -634,6 +763,27 @@ static inline int16_t adpcm_mtaf_expand_nibble(ADPCMChannelStatus *c, uint8_t ni return c->predictor; } +static inline int16_t adpcm_circus_expand_nibble(ADPCMChannelStatus *c, uint8_t nibble) +{ + int32_t sample = c->predictor; + int32_t scale = c->step; + int32_t code = sign_extend(nibble, 8); + + sample += code * (1 << scale); + if (code == 0) { + scale--; + } else if (code == 127 || code == -128) { + scale++; + } + scale = av_clip(scale, 0, 8); + sample = av_clip_int16(sample); + + c->predictor = sample; + c->step = scale; + + return sample; +} + static inline int16_t adpcm_zork_expand_nibble(ADPCMChannelStatus *c, uint8_t nibble) { int16_t index = c->step_index; @@ -832,6 +982,172 @@ int16_t ff_adpcm_argo_expand_nibble(ADPCMChannelStatus *cs, int nibble, int shif return sample; } +static int adpcm_sanyo_expand3(ADPCMChannelStatus *c, int bits) +{ + int sign, delta, add; + + sign = bits & 4; + if (sign) + delta = 4 - (bits & 3); + else + delta = bits; + + switch (delta) { + case 0: + add = 0; + c->step = (3 * c->step) >> 2; + break; + case 1: + add = c->step; + c->step = (4 * c->step - (c->step >> 1)) >> 2; + break; + case 2: + add = 2 * c->step; + c->step = ((c->step >> 1) + add) >> 1; + break; + case 3: + add = 4 * c->step - (c->step >> 1); + c->step = 2 * c->step; + break; + case 4: + add = (11 * c->step) >> 1; + c->step = 3 * c->step; + break; + default: + av_unreachable("There are cases for all control paths when bits is 3-bit"); + } + + if (sign) + add = -add; + + c->predictor = av_clip_int16(c->predictor + add); + c->step = av_clip(c->step, 1, 7281); + return c->predictor; +} + +static int adpcm_sanyo_expand4(ADPCMChannelStatus *c, int bits) +{ + int sign, delta, add; + + sign = bits & 8; + if (sign) + delta = 8 - (bits & 7); + else + delta = bits; + + switch (delta) { + case 0: + add = 0; + c->step = (3 * c->step) >> 2; + break; + case 1: + add = c->step; + c->step = (3 * c->step) >> 2; + break; + case 2: + add = 2 * c->step; + break; + case 3: + add = 3 * c->step; + break; + case 4: + add = 4 * c->step; + break; + case 5: + add = (11 * c->step) >> 1; + c->step += c->step >> 2; + break; + case 6: + add = (15 * c->step) >> 1; + c->step = 2 * c->step; + break; + case 7: + if (sign) + add = (19 * c->step) >> 1; + else + add = (21 * c->step) >> 1; + c->step = (c->step >> 1) + 2 * c->step; + break; + case 8: + add = (25 * c->step) >> 1; + c->step = 5 * c->step; + break; + default: + av_unreachable("There are cases for all control paths when bits is 4-bit"); + } + + if (sign) + add = -add; + + c->predictor = av_clip_int16(c->predictor + add); + c->step = av_clip(c->step, 1, 2621); + return c->predictor; +} + +static int adpcm_sanyo_expand5(ADPCMChannelStatus *c, int bits) +{ + int sign, delta, add; + + sign = bits & 0x10; + if (sign) + delta = 16 - (bits & 0xF); + else + delta = bits; + + add = delta * c->step; + switch (delta) { + case 0: + c->step += (c->step >> 2) - (c->step >> 1); + break; + case 1: + case 2: + case 3: + c->step += (c->step >> 3) - (c->step >> 2); + break; + case 4: + case 5: + c->step += (c->step >> 4) - (c->step >> 3); + break; + case 6: + break; + case 7: + c->step += c->step >> 3; + break; + case 8: + c->step += c->step >> 2; + break; + case 9: + c->step += c->step >> 1; + break; + case 10: + c->step = 2 * c->step - (c->step >> 3); + break; + case 11: + c->step = 2 * c->step + (c->step >> 3); + break; + case 12: + c->step = 2 * c->step + (c->step >> 1) - (c->step >> 3); + break; + case 13: + c->step = 3 * c->step - (c->step >> 2); + break; + case 14: + c->step *= 3; + break; + case 15: + case 16: + c->step = (7 * c->step) >> 1; + break; + } + + if (sign) + add = -add; + + c->predictor = av_clip_int16(c->predictor + add); + c->step = av_clip(c->step, 1, 1024); + return c->predictor; +} + /** * Get the number of samples (per channel) that will be decoded from the packet. * In one case, this is actually the maximum number of samples possible to @@ -872,11 +1188,15 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, return 0; nb_samples = 64; break; + case AV_CODEC_ID_ADPCM_N64: + nb_samples = (buf_size / 9) * 16; + break; /* simple 4-bit adpcm */ case AV_CODEC_ID_ADPCM_CT: case AV_CODEC_ID_ADPCM_IMA_APC: case AV_CODEC_ID_ADPCM_IMA_CUNNING: case AV_CODEC_ID_ADPCM_IMA_EA_SEAD: + case AV_CODEC_ID_ADPCM_IMA_ESCAPE: case AV_CODEC_ID_ADPCM_IMA_OKI: case AV_CODEC_ID_ADPCM_IMA_WS: case AV_CODEC_ID_ADPCM_YAMAHA: @@ -922,6 +1242,23 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, *coded_samples -= *coded_samples % 28; nb_samples = (buf_size - 12) / (ch == 2 ? 30 : 15) * 28; break; + case AV_CODEC_ID_ADPCM_IMA_HVQM2: + nb_samples = ((bytestream2_peek_be64(gb) >> 16) & 0xFFFF); + break; + case AV_CODEC_ID_ADPCM_IMA_HVQM4: + { + int frame_format = bytestream2_get_be16(gb); + int skip = 6; + + if (frame_format == 1) + skip += 2 * ch; + if (frame_format == 3) + skip += 3 * ch; + + nb_samples = (buf_size - skip) * 2 / ch; + bytestream2_seek(gb, 0, SEEK_SET); + } + break; case AV_CODEC_ID_ADPCM_IMA_EA_EACS: has_coded_samples = 1; *coded_samples = bytestream2_get_le32(gb); @@ -972,6 +1309,20 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, buf_size = FFMIN(buf_size, avctx->block_align); nb_samples = (buf_size - 4 * ch) * 2 / ch; break; + case AV_CODEC_ID_ADPCM_IMA_PDA: + if (avctx->block_align > 0) + buf_size = FFMIN(buf_size, avctx->block_align); + nb_samples = (buf_size - 4 * ch) * 2 / ch; + break; + case AV_CODEC_ID_ADPCM_IMA_MAGIX: + if (avctx->block_align > 0) + buf_size = FFMIN(buf_size, avctx->block_align); + nb_samples = (buf_size - 4 * ch) * 2 / ch; + if (ch == 1) { + avpriv_request_sample(avctx, "mono ADPCM Magix"); + return AVERROR_PATCHWELCOME; + } + break; CASE(ADPCM_IMA_WAV, int bsize = ff_adpcm_ima_block_sizes[avctx->bits_per_coded_sample - 2]; int bsamples = ff_adpcm_ima_block_samples[avctx->bits_per_coded_sample - 2]; @@ -981,6 +1332,15 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, return AVERROR_INVALIDDATA; nb_samples = 1 + (buf_size - 4 * ch) / (bsize * ch) * bsamples; ) /* End of CASE */ + CASE(ADPCM_IMA_XBOX, + int bsize = ff_adpcm_ima_block_sizes[avctx->bits_per_coded_sample - 2]; + int bsamples = ff_adpcm_ima_block_samples[avctx->bits_per_coded_sample - 2]; + if (avctx->block_align > 0) + buf_size = FFMIN(buf_size, avctx->block_align); + if (buf_size < 4 * ch) + return AVERROR_INVALIDDATA; + nb_samples = (buf_size - 4 * ch) / (bsize * ch) * bsamples + 1; + ) /* End of CASE */ case AV_CODEC_ID_ADPCM_MS: if (avctx->block_align > 0) buf_size = FFMIN(buf_size, avctx->block_align); @@ -1054,12 +1414,21 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, case AV_CODEC_ID_ADPCM_PSX: nb_samples = buf_size / (16 * ch) * 28; break; + case AV_CODEC_ID_ADPCM_PSXC: + nb_samples = ((buf_size - 1) / ch) * 2; + break; case AV_CODEC_ID_ADPCM_ARGO: nb_samples = buf_size / avctx->block_align * 32; break; + case AV_CODEC_ID_ADPCM_CIRCUS: case AV_CODEC_ID_ADPCM_ZORK: nb_samples = buf_size / ch; break; + case AV_CODEC_ID_ADPCM_SANYO: + if (!avctx->extradata || avctx->extradata_size != 2) + return AVERROR_INVALIDDATA; + nb_samples = AV_RL16(avctx->extradata); + break; } /* validate coded sample count */ @@ -1143,8 +1512,8 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, for (int m = 0; m < 64; m += 2) { int byte = bytestream2_get_byteu(&gb); - samples[m ] = adpcm_ima_qt_expand_nibble(cs, byte & 0x0F); - samples[m + 1] = adpcm_ima_qt_expand_nibble(cs, byte >> 4 ); + samples[m ] = ff_adpcm_ima_qt_expand_nibble(cs, byte & 0x0F); + samples[m + 1] = ff_adpcm_ima_qt_expand_nibble(cs, byte >> 4 ); } } ) /* End of CASE */ @@ -1153,7 +1522,8 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, ADPCMChannelStatus *cs = &c->status[i]; cs->predictor = samples_p[i][0] = sign_extend(bytestream2_get_le16u(&gb), 16); - cs->step_index = sign_extend(bytestream2_get_le16u(&gb), 16); + cs->step_index = bytestream2_get_byteu(&gb); + bytestream2_skipu(&gb, 1); if (cs->step_index > 88u){ av_log(avctx, AV_LOG_ERROR, "ERROR: step_index[%d] = %i\n", i, cs->step_index); @@ -1192,13 +1562,39 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, samples = &samples_p[i][1 + n * 8]; for (int m = 0; m < 8; m += 2) { int v = bytestream2_get_byteu(&gb); - samples[m ] = adpcm_ima_expand_nibble(cs, v & 0x0F, 3); - samples[m + 1] = adpcm_ima_expand_nibble(cs, v >> 4 , 3); + samples[m ] = ff_adpcm_ima_qt_expand_nibble(cs, v & 0x0F); + samples[m + 1] = ff_adpcm_ima_qt_expand_nibble(cs, v >> 4); } } } } ) /* End of CASE */ + CASE(ADPCM_IMA_XBOX, + for (int i = 0; i < channels; i++) { + ADPCMChannelStatus *cs = &c->status[i]; + cs->predictor = samples_p[i][0] = sign_extend(bytestream2_get_le16u(&gb), 16); + + cs->step_index = sign_extend(bytestream2_get_le16u(&gb), 16); + if (cs->step_index > 88u) { + av_log(avctx, AV_LOG_ERROR, "ERROR: step_index[%d] = %i\n", + i, cs->step_index); + return AVERROR_INVALIDDATA; + } + } + + for (int n = 0; n < (nb_samples-1) / 8; n++) { + for (int i = 0; i < channels; i++) { + ADPCMChannelStatus *cs = &c->status[i]; + samples = &samples_p[i][1 + n * 8]; + for (int m = 0; m < 8; m += 2) { + int v = bytestream2_get_byteu(&gb); + samples[m ] = adpcm_ima_expand_nibble(cs, v & 0x0F, 3); + samples[m + 1] = adpcm_ima_expand_nibble(cs, v >> 4 , 3); + } + } + } + frame->nb_samples--; + ) /* End of CASE */ CASE(ADPCM_4XM, for (int i = 0; i < channels; i++) c->status[i].predictor = sign_extend(bytestream2_get_le16u(&gb), 16); @@ -1399,6 +1795,28 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, if ((bytestream2_tell(&gb) & 1)) bytestream2_skip(&gb, 1); ) /* End of CASE */ + CASE(ADPCM_IMA_MAGIX, + for (int channel = 0; channel < channels; channel++) { + ADPCMChannelStatus *cs = &c->status[channel]; + cs->predictor = sign_extend(bytestream2_get_le16u(&gb), 16); + cs->step_index = sign_extend(bytestream2_get_le16u(&gb), 16); + if (cs->step_index > 88u){ + av_log(avctx, AV_LOG_ERROR, "ERROR: step_index[%d] = %i\n", + channel, cs->step_index); + return AVERROR_INVALIDDATA; + } + } + + for (int m = 0; m < channels*nb_samples/16; m ++) { + uint32_t v0 = bytestream2_get_le32u(&gb); + uint32_t v1 = bytestream2_get_le32u(&gb); + + for (int n = 8; n > 0; n--, v0 >>= 4, v1 >>= 4, samples += 2) { + samples[0] = adpcm_ima_expand_nibble(&c->status[0], v0 & 15, 3); + samples[1] = adpcm_ima_expand_nibble(&c->status[1], v1 & 15, 3); + } + } + ) /* End of CASE */ CASE(ADPCM_IMA_ISS, for (int channel = 0; channel < channels; channel++) { ADPCMChannelStatus *cs = &c->status[channel]; @@ -1468,19 +1886,31 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, *samples++ = adpcm_ima_expand_nibble(&c->status[st], v & 0x0F, 3); } ) /* End of CASE */ + CASE(ADPCM_IMA_HVQM2, + int format = bytestream2_get_be16(&gb); + + bytestream2_skip(&gb, 4); + decode_adpcm_ima_hvqm2(avctx, samples, nb_samples, format, &gb); + ) /* End of CASE */ + CASE(ADPCM_IMA_HVQM4, + int format = bytestream2_get_be16(&gb); + + bytestream2_skip(&gb, 4); + decode_adpcm_ima_hvqm4(avctx, samples, nb_samples, format, &gb); + ) /* End of CASE */ CASE(ADPCM_IMA_SSI, for (int n = nb_samples >> (1 - st); n > 0; n--) { int v = bytestream2_get_byteu(&gb); - *samples++ = adpcm_ima_qt_expand_nibble(&c->status[0], v >> 4 ); - *samples++ = adpcm_ima_qt_expand_nibble(&c->status[st], v & 0x0F); + *samples++ = ff_adpcm_ima_qt_expand_nibble(&c->status[0], v >> 4 ); + *samples++ = ff_adpcm_ima_qt_expand_nibble(&c->status[st], v & 0x0F); } ) /* End of CASE */ CASE(ADPCM_IMA_APM, for (int n = nb_samples / 2; n > 0; n--) { for (int channel = 0; channel < channels; channel++) { int v = bytestream2_get_byteu(&gb); - *samples++ = adpcm_ima_qt_expand_nibble(&c->status[channel], v >> 4 ); - samples[st] = adpcm_ima_qt_expand_nibble(&c->status[channel], v & 0x0F); + *samples++ = ff_adpcm_ima_qt_expand_nibble(&c->status[channel], v >> 4 ); + samples[st] = ff_adpcm_ima_qt_expand_nibble(&c->status[channel], v & 0x0F); } samples += channels; } @@ -1620,6 +2050,13 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, bytestream2_skip(&gb, bytes_remaining); } ) /* End of CASE */ + CASE(ADPCM_IMA_ESCAPE, + for (int n = nb_samples >> (1 - st); n > 0; n--) { + int byte = bytestream2_get_byteu(&gb); + *samples++ = adpcm_ima_escape_expand_nibble(&c->status[0], byte >> 4); + *samples++ = adpcm_ima_escape_expand_nibble(&c->status[st], byte & 0xF); + } + ) /* End of CASE */ CASE(ADPCM_IMA_EA_EACS, for (int i = 0; i <= st; i++) { c->status[i].step_index = bytestream2_get_le32u(&gb); @@ -1921,6 +2358,25 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, } } ) /* End of CASE */ + CASE(ADPCM_IMA_PDA, + for (int i = 0; i < channels; i++) { + c->status[i].predictor = sign_extend(bytestream2_get_le16u(&gb), 16); + c->status[i].step_index = bytestream2_get_byteu(&gb); + bytestream2_skipu(&gb, 1); + if (c->status[i].step_index > 88u) { + av_log(avctx, AV_LOG_ERROR, "ERROR: step_index = %i\n", + c->status[i].step_index); + return AVERROR_INVALIDDATA; + } + } + + for (int n = nb_samples >> (1 - st); n > 0; n--) { + int v = bytestream2_get_byteu(&gb); + + *samples++ = ff_adpcm_ima_qt_expand_nibble(&c->status[0 ], v >> 4 ); + *samples++ = ff_adpcm_ima_qt_expand_nibble(&c->status[st], v & 0xf); + } + ) /* End of CASE */ CASE(ADPCM_IMA_SMJPEG, for (int i = 0; i < channels; i++) { c->status[i].predictor = sign_extend(bytestream2_get_be16u(&gb), 16); @@ -1936,8 +2392,8 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, for (int n = nb_samples >> (1 - st); n > 0; n--) { int v = bytestream2_get_byteu(&gb); - *samples++ = adpcm_ima_qt_expand_nibble(&c->status[0 ], v >> 4 ); - *samples++ = adpcm_ima_qt_expand_nibble(&c->status[st], v & 0xf); + *samples++ = ff_adpcm_ima_qt_expand_nibble(&c->status[0 ], v >> 4 ); + *samples++ = ff_adpcm_ima_qt_expand_nibble(&c->status[st], v & 0xf); } ) /* End of CASE */ CASE(ADPCM_CT, @@ -2186,6 +2642,90 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, bytestream2_seek(&gb, 0, SEEK_SET); } ) /* End of CASE */ + CASE(ADPCM_N64, + ADPCMChannelStatus *cs = &c->status[0]; + int coefs[8*2*8] = { 0 }; + + if (avctx->extradata) { + int version, order, entries; + GetByteContext cb; + + bytestream2_init(&cb, avctx->extradata, avctx->extradata_size); + + version = bytestream2_get_be16(&cb); + order = bytestream2_get_be16(&cb); + entries = bytestream2_get_be16(&cb); + if (version != 1 || order != 2 || entries > 8) + return AVERROR_INVALIDDATA; + + for (int n = 0; n < order * entries * 8; n++) + coefs[n] = sign_extend(bytestream2_get_be16(&cb), 16); + } + + for (int block = 0; block < avpkt->size / 9; block++) { + int scale, index, codes[16]; + int16_t hist[8] = { 0 }; + const int order = 2; + int16_t out[16]; + + hist[6] = cs->sample2; + hist[7] = cs->sample1; + + samples = samples_p[0] + block * 16; + + scale = (buf[0] >> 4) & 0xF; + index = (buf[0] >> 0) & 0xF; + scale = 1 << scale; + index = FFMIN(index, 8); + + for (int i = 0, j = 0; i < 16; i += 2, j++) { + int n0 = (buf[j+1] >> 4) & 0xF; + int n1 = (buf[j+1] >> 0) & 0xF; + + if (n0 & 8) + n0 = n0 - 16; + if (n1 & 8) + n1 = n1 - 16; + + codes[i+0] = n0 * scale; + codes[i+1] = n1 * scale; + } + + for (int j = 0; j < 2; j++) { + int *sf_codes = &codes[j*8]; + int16_t *sf_out = &out[j*8]; + + for (int i = 0; i < 8; i++) { + int sample; + unsigned delta = 0; + + for (int o = 0; o < order; o++) + delta += coefs[o*8 + i] * hist[(8 - order) + o]; + + for (int k = i-1; k > -1; k--) { + for (int o = 1; o < order; o++) + delta += sf_codes[(i-1) - k] * (unsigned)coefs[(o*8) + k]; + } + + sample = sf_codes[i] * 2048; + sample = (int)(sample + delta) / 2048; + sample = av_clip_int16(sample); + sf_out[i] = sample; + } + + for (int i = 8 - order; i < 8; i++) + hist[i] = sf_out[i]; + } + + memcpy(samples, out, sizeof(out)); + + cs->sample2 = hist[6]; + cs->sample1 = hist[7]; + + buf += 9; + } + bytestream2_seek(&gb, 0, SEEK_END); + ) /* End of CASE */ CASE(ADPCM_PSX, for (int block = 0; block < avpkt->size / FFMAX(avctx->block_align, 16 * channels); block++) { int nb_samples_per_block = 28 * FFMAX(avctx->block_align, 16 * channels) / (16 * channels); @@ -2227,6 +2767,63 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, } } ) /* End of CASE */ + CASE(ADPCM_PSXC, + for (int block = 0; block < avpkt->size / avctx->block_align; block++) { + int nb_samples_per_block = ((avctx->block_align - 1) / channels) * 2; + for (int channel = 0; channel < channels; channel++) { + int filter, shift, byte; + + samples = samples_p[channel] + block * nb_samples_per_block; + av_assert0((block + 1) * nb_samples_per_block <= nb_samples); + + filter = bytestream2_get_byteu(&gb); + shift = filter & 0xf; + filter = filter >> 4; + if (filter >= FF_ARRAY_ELEMS(xa_adpcm_table)) + return AVERROR_INVALIDDATA; + + for (int n = 0; n < nb_samples_per_block; n++) { + int sample = 0, scale; + + if (n & 1) { + scale = sign_extend(byte >> 4, 4); + } else { + byte = bytestream2_get_byteu(&gb); + scale = sign_extend(byte & 0xF, 4); + } + + scale = scale * (1 << 12); + sample = (int)((scale >> shift) + (c->status[channel].sample1 * xa_adpcm_table[filter][0] + c->status[channel].sample2 * xa_adpcm_table[filter][1]) / 64); + *samples++ = av_clip_int16(sample); + c->status[channel].sample2 = c->status[channel].sample1; + c->status[channel].sample1 = sample; + } + } + } + ) /* End of CASE */ + CASE(ADPCM_SANYO, + int (*expand)(ADPCMChannelStatus *c, int bits); + GetBitContext g; + + switch(avctx->bits_per_coded_sample) { + case 3: expand = adpcm_sanyo_expand3; break; + case 4: expand = adpcm_sanyo_expand4; break; + case 5: expand = adpcm_sanyo_expand5; break; + } + + for (int ch = 0; ch < channels; ch++) { + c->status[ch].predictor = sign_extend(bytestream2_get_le16(&gb), 16); + c->status[ch].step = sign_extend(bytestream2_get_le16(&gb), 16); + } + + init_get_bits8(&g, gb.buffer, bytestream2_get_bytes_left(&gb)); + for (int i = 0; i < nb_samples; i++) + for (int ch = 0; ch < channels; ch++) + samples_p[ch][i] = expand(&c->status[ch], get_bits_le(&g, avctx->bits_per_coded_sample)); + + align_get_bits(&g); + bytestream2_skip(&gb, get_bits_count(&g) / 8); + ) /* End of CASE */ CASE(ADPCM_ARGO, /* * The format of each block: @@ -2264,6 +2861,14 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, } } ) /* End of CASE */ + CASE(ADPCM_CIRCUS, + for (int n = 0; n < nb_samples; n++) { + for (int ch = 0; ch < channels; ch++) { + int v = bytestream2_get_byteu(&gb); + *samples++ = adpcm_circus_expand_nibble(&c->status[ch], v); + } + } + ) /* End of CASE */ CASE(ADPCM_ZORK, for (int n = 0; n < nb_samples * channels; n++) { int v = bytestream2_get_byteu(&gb); @@ -2281,7 +2886,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, } ) /* End of CASE */ default: - av_assert0(0); // unsupported codec_id should not happen + av_unreachable("There are cases for all codec ids using adpcm_decode_frame"); } if (avpkt->size && bytestream2_tell(&gb) == 0) { @@ -2299,7 +2904,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, return bytestream2_tell(&gb); } -static void adpcm_flush(AVCodecContext *avctx) +static av_cold void adpcm_flush(AVCodecContext *avctx) { ADPCMDecodeContext *c = avctx->priv_data; @@ -2341,81 +2946,82 @@ static void adpcm_flush(AVCodecContext *avctx) } -static const enum AVSampleFormat sample_fmts_s16[] = { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }; -static const enum AVSampleFormat sample_fmts_s16p[] = { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }; -static const enum AVSampleFormat sample_fmts_both[] = { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }; - -#define ADPCM_DECODER_0(id_, sample_fmts_, name_, long_name_) -#define ADPCM_DECODER_1(id_, sample_fmts_, name_, long_name_) \ +#define ADPCM_DECODER_0(id_, name_, long_name_) +#define ADPCM_DECODER_1(id_, name_, long_name_) \ const FFCodec ff_ ## name_ ## _decoder = { \ .p.name = #name_, \ CODEC_LONG_NAME(long_name_), \ .p.type = AVMEDIA_TYPE_AUDIO, \ .p.id = id_, \ .p.capabilities = AV_CODEC_CAP_DR1, \ - .p.sample_fmts = sample_fmts_, \ .priv_data_size = sizeof(ADPCMDecodeContext), \ .init = adpcm_decode_init, \ FF_CODEC_DECODE_CB(adpcm_decode_frame), \ .flush = adpcm_flush, \ }; -#define ADPCM_DECODER_2(enabled, codec_id, name, sample_fmts, long_name) \ - ADPCM_DECODER_ ## enabled(codec_id, name, sample_fmts, long_name) -#define ADPCM_DECODER_3(config, codec_id, name, sample_fmts, long_name) \ - ADPCM_DECODER_2(config, codec_id, name, sample_fmts, long_name) -#define ADPCM_DECODER(codec, name, sample_fmts, long_name) \ +#define ADPCM_DECODER_2(enabled, codec_id, name, long_name) \ + ADPCM_DECODER_ ## enabled(codec_id, name, long_name) +#define ADPCM_DECODER_3(config, codec_id, name, long_name) \ + ADPCM_DECODER_2(config, codec_id, name, long_name) +#define ADPCM_DECODER(codec, name, long_name) \ ADPCM_DECODER_3(CONFIG_ ## codec ## _DECODER, AV_CODEC_ID_ ## codec, \ - name, sample_fmts, long_name) + name, long_name) /* Note: Do not forget to add new entries to the Makefile as well. */ -ADPCM_DECODER(ADPCM_4XM, sample_fmts_s16p, adpcm_4xm, "ADPCM 4X Movie") -ADPCM_DECODER(ADPCM_AFC, sample_fmts_s16p, adpcm_afc, "ADPCM Nintendo Gamecube AFC") -ADPCM_DECODER(ADPCM_AGM, sample_fmts_s16, adpcm_agm, "ADPCM AmuseGraphics Movie") -ADPCM_DECODER(ADPCM_AICA, sample_fmts_s16p, adpcm_aica, "ADPCM Yamaha AICA") -ADPCM_DECODER(ADPCM_ARGO, sample_fmts_s16p, adpcm_argo, "ADPCM Argonaut Games") -ADPCM_DECODER(ADPCM_CT, sample_fmts_s16, adpcm_ct, "ADPCM Creative Technology") -ADPCM_DECODER(ADPCM_DTK, sample_fmts_s16p, adpcm_dtk, "ADPCM Nintendo Gamecube DTK") -ADPCM_DECODER(ADPCM_EA, sample_fmts_s16, adpcm_ea, "ADPCM Electronic Arts") -ADPCM_DECODER(ADPCM_EA_MAXIS_XA, sample_fmts_s16, adpcm_ea_maxis_xa, "ADPCM Electronic Arts Maxis CDROM XA") -ADPCM_DECODER(ADPCM_EA_R1, sample_fmts_s16p, adpcm_ea_r1, "ADPCM Electronic Arts R1") -ADPCM_DECODER(ADPCM_EA_R2, sample_fmts_s16p, adpcm_ea_r2, "ADPCM Electronic Arts R2") -ADPCM_DECODER(ADPCM_EA_R3, sample_fmts_s16p, adpcm_ea_r3, "ADPCM Electronic Arts R3") -ADPCM_DECODER(ADPCM_EA_XAS, sample_fmts_s16p, adpcm_ea_xas, "ADPCM Electronic Arts XAS") -ADPCM_DECODER(ADPCM_IMA_ACORN, sample_fmts_s16, adpcm_ima_acorn, "ADPCM IMA Acorn Replay") -ADPCM_DECODER(ADPCM_IMA_AMV, sample_fmts_s16, adpcm_ima_amv, "ADPCM IMA AMV") -ADPCM_DECODER(ADPCM_IMA_APC, sample_fmts_s16, adpcm_ima_apc, "ADPCM IMA CRYO APC") -ADPCM_DECODER(ADPCM_IMA_APM, sample_fmts_s16, adpcm_ima_apm, "ADPCM IMA Ubisoft APM") -ADPCM_DECODER(ADPCM_IMA_CUNNING, sample_fmts_s16p, adpcm_ima_cunning, "ADPCM IMA Cunning Developments") -ADPCM_DECODER(ADPCM_IMA_DAT4, sample_fmts_s16, adpcm_ima_dat4, "ADPCM IMA Eurocom DAT4") -ADPCM_DECODER(ADPCM_IMA_DK3, sample_fmts_s16, adpcm_ima_dk3, "ADPCM IMA Duck DK3") -ADPCM_DECODER(ADPCM_IMA_DK4, sample_fmts_s16, adpcm_ima_dk4, "ADPCM IMA Duck DK4") -ADPCM_DECODER(ADPCM_IMA_EA_EACS, sample_fmts_s16, adpcm_ima_ea_eacs, "ADPCM IMA Electronic Arts EACS") -ADPCM_DECODER(ADPCM_IMA_EA_SEAD, sample_fmts_s16, adpcm_ima_ea_sead, "ADPCM IMA Electronic Arts SEAD") -ADPCM_DECODER(ADPCM_IMA_ISS, sample_fmts_s16, adpcm_ima_iss, "ADPCM IMA Funcom ISS") -ADPCM_DECODER(ADPCM_IMA_MOFLEX, sample_fmts_s16p, adpcm_ima_moflex, "ADPCM IMA MobiClip MOFLEX") -ADPCM_DECODER(ADPCM_IMA_MTF, sample_fmts_s16, adpcm_ima_mtf, "ADPCM IMA Capcom's MT Framework") -ADPCM_DECODER(ADPCM_IMA_OKI, sample_fmts_s16, adpcm_ima_oki, "ADPCM IMA Dialogic OKI") -ADPCM_DECODER(ADPCM_IMA_QT, sample_fmts_s16p, adpcm_ima_qt, "ADPCM IMA QuickTime") -ADPCM_DECODER(ADPCM_IMA_RAD, sample_fmts_s16, adpcm_ima_rad, "ADPCM IMA Radical") -ADPCM_DECODER(ADPCM_IMA_SSI, sample_fmts_s16, adpcm_ima_ssi, "ADPCM IMA Simon & Schuster Interactive") -ADPCM_DECODER(ADPCM_IMA_SMJPEG, sample_fmts_s16, adpcm_ima_smjpeg, "ADPCM IMA Loki SDL MJPEG") -ADPCM_DECODER(ADPCM_IMA_ALP, sample_fmts_s16, adpcm_ima_alp, "ADPCM IMA High Voltage Software ALP") -ADPCM_DECODER(ADPCM_IMA_WAV, sample_fmts_s16p, adpcm_ima_wav, "ADPCM IMA WAV") -ADPCM_DECODER(ADPCM_IMA_WS, sample_fmts_both, adpcm_ima_ws, "ADPCM IMA Westwood") -ADPCM_DECODER(ADPCM_MS, sample_fmts_both, adpcm_ms, "ADPCM Microsoft") -ADPCM_DECODER(ADPCM_MTAF, sample_fmts_s16p, adpcm_mtaf, "ADPCM MTAF") -ADPCM_DECODER(ADPCM_PSX, sample_fmts_s16p, adpcm_psx, "ADPCM Playstation") -ADPCM_DECODER(ADPCM_SBPRO_2, sample_fmts_s16, adpcm_sbpro_2, "ADPCM Sound Blaster Pro 2-bit") -ADPCM_DECODER(ADPCM_SBPRO_3, sample_fmts_s16, adpcm_sbpro_3, "ADPCM Sound Blaster Pro 2.6-bit") -ADPCM_DECODER(ADPCM_SBPRO_4, sample_fmts_s16, adpcm_sbpro_4, "ADPCM Sound Blaster Pro 4-bit") -ADPCM_DECODER(ADPCM_SWF, sample_fmts_s16, adpcm_swf, "ADPCM Shockwave Flash") -ADPCM_DECODER(ADPCM_THP_LE, sample_fmts_s16p, adpcm_thp_le, "ADPCM Nintendo THP (little-endian)") -ADPCM_DECODER(ADPCM_THP, sample_fmts_s16p, adpcm_thp, "ADPCM Nintendo THP") -ADPCM_DECODER(ADPCM_XA, sample_fmts_s16p, adpcm_xa, "ADPCM CDROM XA") -ADPCM_DECODER(ADPCM_XMD, sample_fmts_s16p, adpcm_xmd, "ADPCM Konami XMD") -ADPCM_DECODER(ADPCM_YAMAHA, sample_fmts_s16, adpcm_yamaha, "ADPCM Yamaha") -ADPCM_DECODER(ADPCM_ZORK, sample_fmts_s16, adpcm_zork, "ADPCM Zork") +ADPCM_DECODER(ADPCM_4XM, adpcm_4xm, "ADPCM 4X Movie") +ADPCM_DECODER(ADPCM_AFC, adpcm_afc, "ADPCM Nintendo Gamecube AFC") +ADPCM_DECODER(ADPCM_AGM, adpcm_agm, "ADPCM AmuseGraphics Movie") +ADPCM_DECODER(ADPCM_AICA, adpcm_aica, "ADPCM Yamaha AICA") +ADPCM_DECODER(ADPCM_ARGO, adpcm_argo, "ADPCM Argonaut Games") +ADPCM_DECODER(ADPCM_CIRCUS, adpcm_circus, "ADPCM Circus") +ADPCM_DECODER(ADPCM_CT, adpcm_ct, "ADPCM Creative Technology") +ADPCM_DECODER(ADPCM_DTK, adpcm_dtk, "ADPCM Nintendo Gamecube DTK") +ADPCM_DECODER(ADPCM_EA, adpcm_ea, "ADPCM Electronic Arts") +ADPCM_DECODER(ADPCM_EA_MAXIS_XA, adpcm_ea_maxis_xa, "ADPCM Electronic Arts Maxis CDROM XA") +ADPCM_DECODER(ADPCM_EA_R1, adpcm_ea_r1, "ADPCM Electronic Arts R1") +ADPCM_DECODER(ADPCM_EA_R2, adpcm_ea_r2, "ADPCM Electronic Arts R2") +ADPCM_DECODER(ADPCM_EA_R3, adpcm_ea_r3, "ADPCM Electronic Arts R3") +ADPCM_DECODER(ADPCM_EA_XAS, adpcm_ea_xas, "ADPCM Electronic Arts XAS") +ADPCM_DECODER(ADPCM_IMA_ACORN, adpcm_ima_acorn, "ADPCM IMA Acorn Replay") +ADPCM_DECODER(ADPCM_IMA_AMV, adpcm_ima_amv, "ADPCM IMA AMV") +ADPCM_DECODER(ADPCM_IMA_APC, adpcm_ima_apc, "ADPCM IMA CRYO APC") +ADPCM_DECODER(ADPCM_IMA_APM, adpcm_ima_apm, "ADPCM IMA Ubisoft APM") +ADPCM_DECODER(ADPCM_IMA_CUNNING, adpcm_ima_cunning, "ADPCM IMA Cunning Developments") +ADPCM_DECODER(ADPCM_IMA_DAT4, adpcm_ima_dat4, "ADPCM IMA Eurocom DAT4") +ADPCM_DECODER(ADPCM_IMA_DK3, adpcm_ima_dk3, "ADPCM IMA Duck DK3") +ADPCM_DECODER(ADPCM_IMA_DK4, adpcm_ima_dk4, "ADPCM IMA Duck DK4") +ADPCM_DECODER(ADPCM_IMA_EA_EACS, adpcm_ima_ea_eacs, "ADPCM IMA Electronic Arts EACS") +ADPCM_DECODER(ADPCM_IMA_EA_SEAD, adpcm_ima_ea_sead, "ADPCM IMA Electronic Arts SEAD") +ADPCM_DECODER(ADPCM_IMA_ESCAPE, adpcm_ima_escape, "ADPCM IMA Acorn Escape") +ADPCM_DECODER(ADPCM_IMA_HVQM2, adpcm_ima_hvqm2, "ADPCM IMA HVQM2") +ADPCM_DECODER(ADPCM_IMA_HVQM4, adpcm_ima_hvqm4, "ADPCM IMA HVQM4") +ADPCM_DECODER(ADPCM_IMA_ISS, adpcm_ima_iss, "ADPCM IMA Funcom ISS") +ADPCM_DECODER(ADPCM_IMA_MAGIX, adpcm_ima_magix, "ADPCM IMA Magix") +ADPCM_DECODER(ADPCM_IMA_MOFLEX, adpcm_ima_moflex, "ADPCM IMA MobiClip MOFLEX") +ADPCM_DECODER(ADPCM_IMA_MTF, adpcm_ima_mtf, "ADPCM IMA Capcom's MT Framework") +ADPCM_DECODER(ADPCM_IMA_OKI, adpcm_ima_oki, "ADPCM IMA Dialogic OKI") +ADPCM_DECODER(ADPCM_IMA_PDA, adpcm_ima_pda, "ADPCM IMA PlayDate") +ADPCM_DECODER(ADPCM_IMA_QT, adpcm_ima_qt, "ADPCM IMA QuickTime") +ADPCM_DECODER(ADPCM_IMA_RAD, adpcm_ima_rad, "ADPCM IMA Radical") +ADPCM_DECODER(ADPCM_IMA_SSI, adpcm_ima_ssi, "ADPCM IMA Simon & Schuster Interactive") +ADPCM_DECODER(ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg, "ADPCM IMA Loki SDL MJPEG") +ADPCM_DECODER(ADPCM_IMA_ALP, adpcm_ima_alp, "ADPCM IMA High Voltage Software ALP") +ADPCM_DECODER(ADPCM_IMA_WAV, adpcm_ima_wav, "ADPCM IMA WAV") +ADPCM_DECODER(ADPCM_IMA_WS, adpcm_ima_ws, "ADPCM IMA Westwood") +ADPCM_DECODER(ADPCM_IMA_XBOX, adpcm_ima_xbox, "ADPCM IMA Xbox") +ADPCM_DECODER(ADPCM_MS, adpcm_ms, "ADPCM Microsoft") +ADPCM_DECODER(ADPCM_MTAF, adpcm_mtaf, "ADPCM MTAF") +ADPCM_DECODER(ADPCM_N64, adpcm_n64, "ADPCM Silicon Graphics N64") +ADPCM_DECODER(ADPCM_PSX, adpcm_psx, "ADPCM Playstation") +ADPCM_DECODER(ADPCM_PSXC, adpcm_psxc, "ADPCM Playstation C") +ADPCM_DECODER(ADPCM_SANYO, adpcm_sanyo, "ADPCM Sanyo") +ADPCM_DECODER(ADPCM_SBPRO_2, adpcm_sbpro_2, "ADPCM Sound Blaster Pro 2-bit") +ADPCM_DECODER(ADPCM_SBPRO_3, adpcm_sbpro_3, "ADPCM Sound Blaster Pro 2.6-bit") +ADPCM_DECODER(ADPCM_SBPRO_4, adpcm_sbpro_4, "ADPCM Sound Blaster Pro 4-bit") +ADPCM_DECODER(ADPCM_SWF, adpcm_swf, "ADPCM Shockwave Flash") +ADPCM_DECODER(ADPCM_THP_LE, adpcm_thp_le, "ADPCM Nintendo THP (little-endian)") +ADPCM_DECODER(ADPCM_THP, adpcm_thp, "ADPCM Nintendo THP") +ADPCM_DECODER(ADPCM_XA, adpcm_xa, "ADPCM CDROM XA") +ADPCM_DECODER(ADPCM_XMD, adpcm_xmd, "ADPCM Konami XMD") +ADPCM_DECODER(ADPCM_YAMAHA, adpcm_yamaha, "ADPCM Yamaha") +ADPCM_DECODER(ADPCM_ZORK, adpcm_zork, "ADPCM Zork") diff --git a/libavcodec/adpcm.h b/libavcodec/adpcm.h index 0ffc3da1d..ff70e6207 100644 --- a/libavcodec/adpcm.h +++ b/libavcodec/adpcm.h @@ -44,5 +44,6 @@ typedef struct ADPCMChannelStatus { } ADPCMChannelStatus; int16_t ff_adpcm_argo_expand_nibble(ADPCMChannelStatus *cs, int nibble, int shift, int flag); +int16_t ff_adpcm_ima_qt_expand_nibble(ADPCMChannelStatus *c, int nibble); #endif /* AVCODEC_ADPCM_H */ diff --git a/libavcodec/adpcmenc.c b/libavcodec/adpcmenc.c index 4d7534e47..e350c4113 100644 --- a/libavcodec/adpcmenc.c +++ b/libavcodec/adpcmenc.c @@ -163,13 +163,6 @@ static av_cold int adpcm_encode_init(AVCodecContext *avctx) avctx->block_align = s->block_size; ) /* End of CASE */ CASE(ADPCM_SWF, - if (avctx->sample_rate != 11025 && - avctx->sample_rate != 22050 && - avctx->sample_rate != 44100) { - av_log(avctx, AV_LOG_ERROR, "Sample rate must be 11025, " - "22050 or 44100\n"); - return AVERROR(EINVAL); - } avctx->frame_size = 4096; /* Hardcoded according to the SWF spec. */ avctx->block_align = (2 + channels * (22 + 4 * (avctx->frame_size - 1)) + 7) / 8; ) /* End of CASE */ @@ -179,16 +172,6 @@ static av_cold int adpcm_encode_init(AVCodecContext *avctx) avctx->block_align = s->block_size; break; CASE(ADPCM_IMA_AMV, - if (avctx->sample_rate != 22050) { - av_log(avctx, AV_LOG_ERROR, "Sample rate must be 22050\n"); - return AVERROR(EINVAL); - } - - if (channels != 1) { - av_log(avctx, AV_LOG_ERROR, "Only mono is supported\n"); - return AVERROR(EINVAL); - } - avctx->frame_size = s->block_size; avctx->block_align = 8 + (FFALIGN(avctx->frame_size, 2) / 2); ) /* End of CASE */ @@ -210,7 +193,7 @@ static av_cold int adpcm_encode_init(AVCodecContext *avctx) avctx->block_align = s->block_size; ) /* End of CASE */ default: - return AVERROR(EINVAL); + av_unreachable("there is a case for every codec using adpcm_encode_init()"); } return 0; @@ -968,7 +951,7 @@ static const enum AVSampleFormat sample_fmts_p[] = { AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_NONE }; -static const AVChannelLayout ch_layouts[] = { +static const AVChannelLayout ch_layouts_mono_stereo[] = { AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO, { 0 }, @@ -995,40 +978,42 @@ static const AVClass adpcm_encoder_class = { .version = LIBAVUTIL_VERSION_INT, }; -#define ADPCM_ENCODER_0(id_, name_, sample_fmts_, capabilities_, long_name_) -#define ADPCM_ENCODER_1(id_, name_, sample_fmts_, capabilities_, long_name_) \ +#define ADPCM_ENCODER_0(id_, name_, sample_fmts_, capabilities_, long_name_, ...) +#define ADPCM_ENCODER_1(id_, name_, sample_fmts_, capabilities_, long_name_, ...) \ const FFCodec ff_ ## name_ ## _encoder = { \ .p.name = #name_, \ CODEC_LONG_NAME(long_name_), \ .p.type = AVMEDIA_TYPE_AUDIO, \ .p.id = id_, \ - .p.sample_fmts = sample_fmts_, \ - .p.ch_layouts = ch_layouts, \ .p.capabilities = capabilities_ | AV_CODEC_CAP_DR1 | \ AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, \ - .p.priv_class = &adpcm_encoder_class, \ + CODEC_SAMPLEFMTS_ARRAY(sample_fmts_), \ .priv_data_size = sizeof(ADPCMEncodeContext), \ .init = adpcm_encode_init, \ FF_CODEC_ENCODE_CB(adpcm_encode_frame), \ .close = adpcm_encode_close, \ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \ + __VA_ARGS__, \ }; -#define ADPCM_ENCODER_2(enabled, codec_id, name, sample_fmts, capabilities, long_name) \ - ADPCM_ENCODER_ ## enabled(codec_id, name, sample_fmts, capabilities, long_name) -#define ADPCM_ENCODER_3(config, codec_id, name, sample_fmts, capabilities, long_name) \ - ADPCM_ENCODER_2(config, codec_id, name, sample_fmts, capabilities, long_name) -#define ADPCM_ENCODER(codec, name, sample_fmts, capabilities, long_name) \ +#define ADPCM_ENCODER_2(enabled, codec_id, name, sample_fmts, capabilities, long_name, ...) \ + ADPCM_ENCODER_ ## enabled(codec_id, name, sample_fmts, capabilities, long_name, __VA_ARGS__) +#define ADPCM_ENCODER_3(config, codec_id, name, sample_fmts, capabilities, long_name, ...) \ + ADPCM_ENCODER_2(config, codec_id, name, sample_fmts, capabilities, long_name, __VA_ARGS__) +#define ADPCM_ENCODER(codec, name, sample_fmts, capabilities, long_name, ...) \ ADPCM_ENCODER_3(CONFIG_ ## codec ## _ENCODER, AV_CODEC_ID_ ## codec, \ - name, sample_fmts, capabilities, long_name) + name, sample_fmts, capabilities, long_name, __VA_ARGS__) -ADPCM_ENCODER(ADPCM_ARGO, adpcm_argo, sample_fmts_p, 0, "ADPCM Argonaut Games") -ADPCM_ENCODER(ADPCM_IMA_AMV, adpcm_ima_amv, sample_fmts, 0, "ADPCM IMA AMV") -ADPCM_ENCODER(ADPCM_IMA_APM, adpcm_ima_apm, sample_fmts, AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA Ubisoft APM") -ADPCM_ENCODER(ADPCM_IMA_ALP, adpcm_ima_alp, sample_fmts, AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA High Voltage Software ALP") -ADPCM_ENCODER(ADPCM_IMA_QT, adpcm_ima_qt, sample_fmts_p, 0, "ADPCM IMA QuickTime") -ADPCM_ENCODER(ADPCM_IMA_SSI, adpcm_ima_ssi, sample_fmts, AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA Simon & Schuster Interactive") -ADPCM_ENCODER(ADPCM_IMA_WAV, adpcm_ima_wav, sample_fmts_p, 0, "ADPCM IMA WAV") -ADPCM_ENCODER(ADPCM_IMA_WS, adpcm_ima_ws, sample_fmts, AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA Westwood") -ADPCM_ENCODER(ADPCM_MS, adpcm_ms, sample_fmts, 0, "ADPCM Microsoft") -ADPCM_ENCODER(ADPCM_SWF, adpcm_swf, sample_fmts, 0, "ADPCM Shockwave Flash") -ADPCM_ENCODER(ADPCM_YAMAHA, adpcm_yamaha, sample_fmts, 0, "ADPCM Yamaha") +#define MONO_STEREO CODEC_CH_LAYOUTS_ARRAY(ch_layouts_mono_stereo) +#define AVCLASS .p.priv_class = &adpcm_encoder_class + +ADPCM_ENCODER(ADPCM_ARGO, adpcm_argo, sample_fmts_p, 0, "ADPCM Argonaut Games", MONO_STEREO) +ADPCM_ENCODER(ADPCM_IMA_AMV, adpcm_ima_amv, sample_fmts, 0, "ADPCM IMA AMV", CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), CODEC_SAMPLERATES(22050), AVCLASS) +ADPCM_ENCODER(ADPCM_IMA_APM, adpcm_ima_apm, sample_fmts, AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA Ubisoft APM", MONO_STEREO, AVCLASS) +ADPCM_ENCODER(ADPCM_IMA_ALP, adpcm_ima_alp, sample_fmts, AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA High Voltage Software ALP", MONO_STEREO, AVCLASS) +ADPCM_ENCODER(ADPCM_IMA_QT, adpcm_ima_qt, sample_fmts_p, 0, "ADPCM IMA QuickTime", MONO_STEREO) +ADPCM_ENCODER(ADPCM_IMA_SSI, adpcm_ima_ssi, sample_fmts, AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA Simon & Schuster Interactive", MONO_STEREO, AVCLASS) +ADPCM_ENCODER(ADPCM_IMA_WAV, adpcm_ima_wav, sample_fmts_p, 0, "ADPCM IMA WAV", MONO_STEREO, AVCLASS) +ADPCM_ENCODER(ADPCM_IMA_WS, adpcm_ima_ws, sample_fmts, AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA Westwood", MONO_STEREO, AVCLASS) +ADPCM_ENCODER(ADPCM_MS, adpcm_ms, sample_fmts, 0, "ADPCM Microsoft", MONO_STEREO, AVCLASS) +ADPCM_ENCODER(ADPCM_SWF, adpcm_swf, sample_fmts, 0, "ADPCM Shockwave Flash", MONO_STEREO, CODEC_SAMPLERATES(11025, 22050, 44100)) +ADPCM_ENCODER(ADPCM_YAMAHA, adpcm_yamaha, sample_fmts, 0, "ADPCM Yamaha", MONO_STEREO, AVCLASS) diff --git a/libavcodec/adx_parser.c b/libavcodec/adx_parser.c index 62b4415bc..c897ba223 100644 --- a/libavcodec/adx_parser.c +++ b/libavcodec/adx_parser.c @@ -25,9 +25,9 @@ * Splits packets into individual blocks. */ -#include "libavutil/intreadwrite.h" #include "parser.h" #include "adx.h" +#include "parser_internal.h" typedef struct ADXParseContext { ParseContext pc; @@ -98,9 +98,9 @@ static int adx_parse(AVCodecParserContext *s1, return next; } -const AVCodecParser ff_adx_parser = { - .codec_ids = { AV_CODEC_ID_ADPCM_ADX }, +const FFCodecParser ff_adx_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_ADPCM_ADX), .priv_data_size = sizeof(ADXParseContext), - .parser_parse = adx_parse, - .parser_close = ff_parse_close, + .parse = adx_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/adxdec.c b/libavcodec/adxdec.c index 4300dede5..019fc1a90 100644 --- a/libavcodec/adxdec.c +++ b/libavcodec/adxdec.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "libavutil/intreadwrite.h" #include "avcodec.h" #include "adx.h" @@ -246,7 +247,7 @@ static int adx_decode_frame(AVCodecContext *avctx, AVFrame *frame, return buf - avpkt->data; } -static void adx_decode_flush(AVCodecContext *avctx) +static av_cold void adx_decode_flush(AVCodecContext *avctx) { ADXContext *c = avctx->priv_data; memset(c->prev, 0, sizeof(c->prev)); @@ -264,6 +265,4 @@ const FFCodec ff_adpcm_adx_decoder = { .flush = adx_decode_flush, .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/adxenc.c b/libavcodec/adxenc.c index 796efdab6..5a8d4b862 100644 --- a/libavcodec/adxenc.c +++ b/libavcodec/adxenc.c @@ -197,7 +197,6 @@ const FFCodec ff_adpcm_adx_encoder = { .priv_data_size = sizeof(ADXContext), .init = adx_encode_init, FF_CODEC_ENCODE_CB(adx_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .caps_internal = FF_CODEC_CAP_EOF_FLUSH, }; diff --git a/libavcodec/agm.c b/libavcodec/agm.c index fdf896d61..c13b4d963 100644 --- a/libavcodec/agm.c +++ b/libavcodec/agm.c @@ -24,6 +24,7 @@ #define BITSTREAM_READER_LE +#include "libavutil/attributes.h" #include "libavutil/mem.h" #include "libavutil/mem_internal.h" @@ -1245,7 +1246,7 @@ static av_cold int decode_init(AVCodecContext *avctx) return 0; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { AGMContext *s = avctx->priv_data; diff --git a/libavcodec/ahx_parser.c b/libavcodec/ahx_parser.c new file mode 100644 index 000000000..2aeaf8b56 --- /dev/null +++ b/libavcodec/ahx_parser.c @@ -0,0 +1,79 @@ +/* + * 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 + * AHX audio parser + * + * Splits packets into individual blocks. + */ + +#include "libavutil/intreadwrite.h" +#include "parser.h" +#include "parser_internal.h" + +typedef struct AHXParseContext { + ParseContext pc; + uint32_t header; + int size; +} AHXParseContext; + +static int ahx_parse(AVCodecParserContext *s1, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + AHXParseContext *s = s1->priv_data; + ParseContext *pc = &s->pc; + uint32_t state = pc->state; + int next = END_NOT_FOUND; + + for (int i = 0; i < buf_size; i++) { + state = (state << 8) | buf[i]; + s->size++; + if (s->size == 4 && !s->header) + s->header = state; + if (s->size > 4 && state == s->header) { + next = i - 3; + s->size = 0; + break; + } + } + pc->state = state; + + if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + + s1->duration = 1152; + s1->key_frame = 1; + + *poutbuf = buf; + *poutbuf_size = buf_size; + + return next; +} + +const FFCodecParser ff_ahx_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_AHX), + .priv_data_size = sizeof(AHXParseContext), + .parse = ahx_parse, + .close = ff_parse_close, +}; diff --git a/libavcodec/alacdsp.c b/libavcodec/alacdsp.c index a604566af..c06cc9da9 100644 --- a/libavcodec/alacdsp.c +++ b/libavcodec/alacdsp.c @@ -60,7 +60,7 @@ av_cold void ff_alacdsp_init(ALACDSPContext *c) #if ARCH_RISCV ff_alacdsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_alacdsp_init_x86(c); #endif } diff --git a/libavcodec/alacenc.c b/libavcodec/alacenc.c index caac62421..474200fee 100644 --- a/libavcodec/alacenc.c +++ b/libavcodec/alacenc.c @@ -646,8 +646,6 @@ const FFCodec ff_alac_encoder = { .init = alac_encode_init, FF_CODEC_ENCODE_CB(alac_encode_frame), .close = alac_encode_close, - .p.ch_layouts = ff_alac_ch_layouts, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_CH_LAYOUTS_ARRAY(ff_alac_ch_layouts), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_S16P), }; diff --git a/libavcodec/aliaspixenc.c b/libavcodec/aliaspixenc.c index 90d2a6331..ed9202088 100644 --- a/libavcodec/aliaspixenc.c +++ b/libavcodec/aliaspixenc.c @@ -108,7 +108,5 @@ const FFCodec ff_alias_pix_encoder = { .p.id = AV_CODEC_ID_ALIAS_PIX, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_BGR24, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24, AV_PIX_FMT_GRAY8), }; diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index aa0fc4764..695214f19 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -28,10 +28,13 @@ #include #include "config.h" +#include "libavutil/avassert.h" #include "libavutil/thread.h" +#include "avcodec.h" #include "codec.h" #include "codec_id.h" #include "codec_internal.h" +#include "codec_desc.h" extern const FFCodec ff_a64multi_encoder; extern const FFCodec ff_a64multi5_encoder; @@ -46,6 +49,7 @@ extern const FFCodec ff_anm_decoder; extern const FFCodec ff_ansi_decoder; extern const FFCodec ff_apng_encoder; extern const FFCodec ff_apng_decoder; +extern const FFCodec ff_apv_decoder; extern const FFCodec ff_arbc_decoder; extern const FFCodec ff_argo_decoder; extern const FFCodec ff_asv1_encoder; @@ -116,6 +120,7 @@ extern const FFCodec ff_escape130_decoder; extern const FFCodec ff_exr_encoder; extern const FFCodec ff_exr_decoder; extern const FFCodec ff_ffv1_encoder; +extern const FFCodec ff_ffv1_vulkan_encoder; extern const FFCodec ff_ffv1_decoder; extern const FFCodec ff_ffvhuff_encoder; extern const FFCodec ff_ffvhuff_decoder; @@ -153,11 +158,13 @@ extern const FFCodec ff_h264_mediacodec_encoder; extern const FFCodec ff_h264_mmal_decoder; extern const FFCodec ff_h264_qsv_decoder; extern const FFCodec ff_h264_rkmpp_decoder; +extern const FFCodec ff_h264_rkmpp_encoder; extern const FFCodec ff_hap_encoder; extern const FFCodec ff_hap_decoder; extern const FFCodec ff_hevc_decoder; extern const FFCodec ff_hevc_qsv_decoder; extern const FFCodec ff_hevc_rkmpp_decoder; +extern const FFCodec ff_hevc_rkmpp_encoder; extern const FFCodec ff_hevc_v4l2m2m_decoder; extern const FFCodec ff_hnm4_video_decoder; extern const FFCodec ff_hq_hqa_decoder; @@ -266,6 +273,8 @@ extern const FFCodec ff_prores_encoder; extern const FFCodec ff_prores_decoder; extern const FFCodec ff_prores_aw_encoder; extern const FFCodec ff_prores_ks_encoder; +extern const FFCodec ff_prores_ks_vulkan_encoder; +extern const FFCodec ff_prores_raw_decoder; extern const FFCodec ff_prosumer_decoder; extern const FFCodec ff_psd_decoder; extern const FFCodec ff_ptx_decoder; @@ -296,6 +305,7 @@ extern const FFCodec ff_rv20_encoder; extern const FFCodec ff_rv20_decoder; extern const FFCodec ff_rv30_decoder; extern const FFCodec ff_rv40_decoder; +extern const FFCodec ff_rv60_decoder; extern const FFCodec ff_s302m_encoder; extern const FFCodec ff_s302m_decoder; extern const FFCodec ff_sanm_decoder; @@ -345,12 +355,14 @@ extern const FFCodec ff_utvideo_decoder; extern const FFCodec ff_v210_encoder; extern const FFCodec ff_v210_decoder; extern const FFCodec ff_v210x_decoder; +#if FF_API_V408_CODECID extern const FFCodec ff_v308_encoder; extern const FFCodec ff_v308_decoder; extern const FFCodec ff_v408_encoder; extern const FFCodec ff_v408_decoder; extern const FFCodec ff_v410_encoder; extern const FFCodec ff_v410_decoder; +#endif extern const FFCodec ff_vb_decoder; extern const FFCodec ff_vbn_encoder; extern const FFCodec ff_vbn_decoder; @@ -427,6 +439,7 @@ extern const FFCodec ff_ac3_decoder; extern const FFCodec ff_ac3_fixed_encoder; extern const FFCodec ff_ac3_fixed_decoder; extern const FFCodec ff_acelp_kelvin_decoder; +extern const FFCodec ff_ahx_decoder; extern const FFCodec ff_alac_encoder; extern const FFCodec ff_alac_decoder; extern const FFCodec ff_als_decoder; @@ -471,6 +484,7 @@ extern const FFCodec ff_flac_decoder; extern const FFCodec ff_ftr_decoder; extern const FFCodec ff_g723_1_encoder; extern const FFCodec ff_g723_1_decoder; +extern const FFCodec ff_g728_decoder; extern const FFCodec ff_g729_decoder; extern const FFCodec ff_gsm_decoder; extern const FFCodec ff_gsm_ms_decoder; @@ -640,6 +654,7 @@ extern const FFCodec ff_adpcm_agm_decoder; extern const FFCodec ff_adpcm_aica_decoder; extern const FFCodec ff_adpcm_argo_decoder; extern const FFCodec ff_adpcm_argo_encoder; +extern const FFCodec ff_adpcm_circus_decoder; extern const FFCodec ff_adpcm_ct_decoder; extern const FFCodec ff_adpcm_dtk_decoder; extern const FFCodec ff_adpcm_ea_decoder; @@ -668,10 +683,15 @@ extern const FFCodec ff_adpcm_ima_dk3_decoder; extern const FFCodec ff_adpcm_ima_dk4_decoder; extern const FFCodec ff_adpcm_ima_ea_eacs_decoder; extern const FFCodec ff_adpcm_ima_ea_sead_decoder; +extern const FFCodec ff_adpcm_ima_escape_decoder; +extern const FFCodec ff_adpcm_ima_hvqm2_decoder; +extern const FFCodec ff_adpcm_ima_hvqm4_decoder; extern const FFCodec ff_adpcm_ima_iss_decoder; +extern const FFCodec ff_adpcm_ima_magix_decoder; extern const FFCodec ff_adpcm_ima_moflex_decoder; extern const FFCodec ff_adpcm_ima_mtf_decoder; extern const FFCodec ff_adpcm_ima_oki_decoder; +extern const FFCodec ff_adpcm_ima_pda_decoder; extern const FFCodec ff_adpcm_ima_qt_encoder; extern const FFCodec ff_adpcm_ima_qt_decoder; extern const FFCodec ff_adpcm_ima_rad_decoder; @@ -682,10 +702,14 @@ extern const FFCodec ff_adpcm_ima_wav_encoder; extern const FFCodec ff_adpcm_ima_wav_decoder; extern const FFCodec ff_adpcm_ima_ws_encoder; extern const FFCodec ff_adpcm_ima_ws_decoder; +extern const FFCodec ff_adpcm_ima_xbox_decoder; extern const FFCodec ff_adpcm_ms_encoder; extern const FFCodec ff_adpcm_ms_decoder; extern const FFCodec ff_adpcm_mtaf_decoder; +extern const FFCodec ff_adpcm_n64_decoder; extern const FFCodec ff_adpcm_psx_decoder; +extern const FFCodec ff_adpcm_psxc_decoder; +extern const FFCodec ff_adpcm_sanyo_decoder; extern const FFCodec ff_adpcm_sbpro_2_decoder; extern const FFCodec ff_adpcm_sbpro_3_decoder; extern const FFCodec ff_adpcm_sbpro_4_decoder; @@ -773,11 +797,15 @@ extern const FFCodec ff_libgsm_ms_encoder; extern const FFCodec ff_libgsm_ms_decoder; extern const FFCodec ff_libilbc_encoder; extern const FFCodec ff_libilbc_decoder; +extern const FFCodec ff_libjxl_anim_decoder; +extern const FFCodec ff_libjxl_anim_encoder; extern const FFCodec ff_libjxl_decoder; extern const FFCodec ff_libjxl_encoder; extern const FFCodec ff_liblc3_encoder; extern const FFCodec ff_liblc3_decoder; extern const FFCodec ff_libmp3lame_encoder; +extern const FFCodec ff_libmpeghdec_decoder; +extern const FFCodec ff_liboapv_encoder; extern const FFCodec ff_libopencore_amrnb_encoder; extern const FFCodec ff_libopencore_amrnb_decoder; extern const FFCodec ff_libopencore_amrwb_decoder; @@ -790,6 +818,8 @@ extern const FFCodec ff_libshine_encoder; extern const FFCodec ff_libspeex_encoder; extern const FFCodec ff_libspeex_decoder; extern const FFCodec ff_libsvtav1_encoder; +extern const FFCodec ff_libsvtjpegxs_encoder; +extern const FFCodec ff_libsvtjpegxs_decoder; extern const FFCodec ff_libtheora_encoder; extern const FFCodec ff_libtwolame_encoder; extern const FFCodec ff_libuavs3d_decoder; @@ -832,19 +862,27 @@ extern const FFCodec ff_libaom_av1_decoder; /* hwaccel hooks only, so prefer external decoders */ extern const FFCodec ff_av1_decoder; extern const FFCodec ff_av1_cuvid_decoder; +extern const FFCodec ff_av1_d3d12va_encoder; extern const FFCodec ff_av1_mediacodec_decoder; extern const FFCodec ff_av1_mediacodec_encoder; extern const FFCodec ff_av1_nvenc_encoder; extern const FFCodec ff_av1_qsv_decoder; extern const FFCodec ff_av1_qsv_encoder; extern const FFCodec ff_av1_amf_encoder; +extern const FFCodec ff_av1_amf_decoder; +extern const FFCodec ff_av1_mf_encoder; extern const FFCodec ff_av1_vaapi_encoder; +extern const FFCodec ff_av1_vulkan_encoder; extern const FFCodec ff_libopenh264_encoder; extern const FFCodec ff_libopenh264_decoder; extern const FFCodec ff_h264_amf_encoder; +extern const FFCodec ff_h264_amf_decoder; extern const FFCodec ff_h264_cuvid_decoder; +extern const FFCodec ff_h264_d3d12va_encoder; extern const FFCodec ff_h264_mf_encoder; extern const FFCodec ff_h264_nvenc_encoder; +extern const FFCodec ff_h264_oh_decoder; +extern const FFCodec ff_h264_oh_encoder; extern const FFCodec ff_h264_omx_encoder; extern const FFCodec ff_h264_qsv_encoder; extern const FFCodec ff_h264_v4l2m2m_encoder; @@ -852,12 +890,15 @@ extern const FFCodec ff_h264_vaapi_encoder; extern const FFCodec ff_h264_videotoolbox_encoder; extern const FFCodec ff_h264_vulkan_encoder; extern const FFCodec ff_hevc_amf_encoder; +extern const FFCodec ff_hevc_amf_decoder; extern const FFCodec ff_hevc_cuvid_decoder; extern const FFCodec ff_hevc_d3d12va_encoder; extern const FFCodec ff_hevc_mediacodec_decoder; extern const FFCodec ff_hevc_mediacodec_encoder; extern const FFCodec ff_hevc_mf_encoder; extern const FFCodec ff_hevc_nvenc_encoder; +extern const FFCodec ff_hevc_oh_decoder; +extern const FFCodec ff_hevc_oh_encoder; extern const FFCodec ff_hevc_qsv_encoder; extern const FFCodec ff_hevc_v4l2m2m_encoder; extern const FFCodec ff_hevc_vaapi_encoder; @@ -887,6 +928,7 @@ extern const FFCodec ff_vp8_mediacodec_encoder; extern const FFCodec ff_vp8_qsv_decoder; extern const FFCodec ff_vp8_v4l2m2m_encoder; extern const FFCodec ff_vp8_vaapi_encoder; +extern const FFCodec ff_vp9_amf_decoder; extern const FFCodec ff_vp9_cuvid_decoder; extern const FFCodec ff_vp9_mediacodec_decoder; extern const FFCodec ff_vp9_mediacodec_encoder; @@ -925,14 +967,11 @@ static void av_codec_init_static(void) FF_DISABLE_DEPRECATION_WARNINGS switch (codec->p.type) { case AVMEDIA_TYPE_VIDEO: - codec->get_supported_config(NULL, &codec->p, - AV_CODEC_CONFIG_PIX_FORMAT, 0, - (const void **) &codec->p.pix_fmts, - &dummy); - codec->get_supported_config(NULL, &codec->p, - AV_CODEC_CONFIG_FRAME_RATE, 0, - (const void **) &codec->p.supported_framerates, - &dummy); + if (!codec->p.pix_fmts) + codec->get_supported_config(NULL, &codec->p, + AV_CODEC_CONFIG_PIX_FORMAT, 0, + (const void **) &codec->p.pix_fmts, + &dummy); break; case AVMEDIA_TYPE_AUDIO: codec->get_supported_config(NULL, &codec->p, @@ -981,6 +1020,7 @@ static enum AVCodecID remap_deprecated_codec_id(enum AVCodecID id) static const AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *)) { const AVCodec *p, *experimental = NULL; + av_unused const AVCodecDescriptor *desc = avcodec_descriptor_get(id); void *i = 0; id = remap_deprecated_codec_id(id); @@ -989,6 +1029,7 @@ static const AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *)) if (!x(p)) continue; if (p->id == id) { + av_assert1(!desc || !(desc->props & AV_CODEC_PROP_ENHANCEMENT)); if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) { experimental = p; } else @@ -1001,12 +1042,12 @@ static const AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *)) const AVCodec *avcodec_find_encoder(enum AVCodecID id) { - return find_codec(id, av_codec_is_encoder); + return find_codec(id, ff_codec_is_encoder); } const AVCodec *avcodec_find_decoder(enum AVCodecID id) { - return find_codec(id, av_codec_is_decoder); + return find_codec(id, ff_codec_is_decoder); } static const AVCodec *find_codec_by_name(const char *name, int (*x)(const AVCodec *)) @@ -1029,10 +1070,10 @@ static const AVCodec *find_codec_by_name(const char *name, int (*x)(const AVCode const AVCodec *avcodec_find_encoder_by_name(const char *name) { - return find_codec_by_name(name, av_codec_is_encoder); + return find_codec_by_name(name, ff_codec_is_encoder); } const AVCodec *avcodec_find_decoder_by_name(const char *name) { - return find_codec_by_name(name, av_codec_is_decoder); + return find_codec_by_name(name, ff_codec_is_decoder); } diff --git a/libavcodec/alsdec.c b/libavcodec/alsdec.c index aff393a48..5378d01d4 100644 --- a/libavcodec/alsdec.c +++ b/libavcodec/alsdec.c @@ -38,6 +38,7 @@ #include "internal.h" #include "mlz.h" #include "libavutil/mem.h" +#include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "libavutil/crc.h" #include "libavutil/softfloat_ieee754.h" @@ -194,6 +195,7 @@ typedef struct ALSChannelData { typedef struct ALSDecContext { + AVClass *av_class; AVCodecContext *avctx; ALSSpecificConfig sconf; GetBitContext gb; @@ -222,7 +224,7 @@ typedef struct ALSDecContext { int32_t *quant_cof_buffer; ///< contains all quantized parcor coefficients int32_t **lpc_cof; ///< coefficients of the direct form prediction filter for a channel int32_t *lpc_cof_buffer; ///< contains all coefficients of the direct form prediction filter - int32_t *lpc_cof_reversed_buffer; ///< temporary buffer to set up a reversed versio of lpc_cof_buffer + int32_t *lpc_cof_reversed_buffer; ///< temporary buffer to set up a reversed version of lpc_cof_buffer ALSChannelData **chan_data; ///< channel data for multi-channel correlation ALSChannelData *chan_data_buffer; ///< contains channel data for all channels int *reverted_channels; ///< stores a flag for each reverted channel @@ -239,6 +241,7 @@ typedef struct ALSDecContext { unsigned char *larray; ///< buffer to store the output of masked lz decompression int *nbits; ///< contains the number of bits to read for masked lz decompression for all samples int highest_decoded_channel; + int user_max_order; ///< user specified maximum prediction order } ALSDecContext; @@ -352,6 +355,11 @@ static av_cold int read_specific_config(ALSDecContext *ctx) skip_bits(&gb, 5); // skip 5 reserved bits skip_bits1(&gb); // skip aux_data_enabled + if (sconf->max_order > ctx->user_max_order) { + av_log(avctx, AV_LOG_ERROR, "order %d exceeds specified max %d\n", sconf->max_order, ctx->user_max_order); + return AVERROR_INVALIDDATA; + } + // check for ALSSpecificConfig struct if (als_id != MKBETAG('A','L','S','\0')) @@ -1335,13 +1343,13 @@ static int revert_channel_correlation(ALSDecContext *ctx, ALSBlockData *bd, if (ch[dep].time_diff_sign) { t = -t; if (begin < t) { - av_log(ctx->avctx, AV_LOG_ERROR, "begin %"PTRDIFF_SPECIFIER" smaller than time diff index %d.\n", begin, t); + av_log(ctx->avctx, AV_LOG_ERROR, "begin %td smaller than time diff index %d.\n", begin, t); return AVERROR_INVALIDDATA; } begin -= t; } else { if (end < t) { - av_log(ctx->avctx, AV_LOG_ERROR, "end %"PTRDIFF_SPECIFIER" smaller than time diff index %d.\n", end, t); + av_log(ctx->avctx, AV_LOG_ERROR, "end %td smaller than time diff index %d.\n", end, t); return AVERROR_INVALIDDATA; } end -= t; @@ -1554,7 +1562,7 @@ static int read_diff_float_data(ALSDecContext *ctx, unsigned int ra_frame) { if (highest_byte) { for (i = 0; i < frame_length; ++i) { if (ctx->raw_samples[c][i] != 0) { - //The following logic is taken from Tabel 14.45 and 14.46 from the ISO spec + //The following logic is taken from Table 14.45 and 14.46 from the ISO spec if (av_cmp_sf_ieee754(acf[c], FLOAT_1)) { int nbit = av_log2(FFABSU(ctx->raw_samples[c][i])); if (nbit > 23) @@ -2192,6 +2200,17 @@ static av_cold void flush(AVCodecContext *avctx) ctx->frame_id = 0; } +static const AVOption options[] = { + { "max_order", "Sets the maximum order (ALS simple profile allows max 15)", offsetof(ALSDecContext, user_max_order), AV_OPT_TYPE_INT, { .i64 = 1023 }, 0, 1023, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM }, + { NULL } +}; + +static const AVClass als_class = { + .class_name = "als", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; const FFCodec ff_als_decoder = { .p.name = "als", @@ -2202,11 +2221,8 @@ const FFCodec ff_als_decoder = { .init = decode_init, .close = decode_end, FF_CODEC_DECODE_CB(decode_frame), + .p.priv_class = &als_class, .flush = flush, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/amfdec.c b/libavcodec/amfdec.c new file mode 100644 index 000000000..c178d5d91 --- /dev/null +++ b/libavcodec/amfdec.c @@ -0,0 +1,720 @@ +/* + * 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/hwcontext_amf.h" +#include "libavutil/hwcontext_amf_internal.h" +#include "amfdec.h" +#include "codec_internal.h" +#include "hwconfig.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/time.h" +#include "decode.h" +#include "decode_bsf.h" +#include "libavutil/mastering_display_metadata.h" + +#if CONFIG_D3D11VA +#include "libavutil/hwcontext_d3d11va.h" +#endif +#if CONFIG_DXVA2 +#define COBJMACROS +#include "libavutil/hwcontext_dxva2.h" +#endif + +#ifdef _WIN32 +#include "compat/w32dlfcn.h" +#else +#include +#endif +//will be in public headers soon +#define AMF_VIDEO_DECODER_OUTPUT_FORMAT L"OutputDecodeFormat" + +static const AVCodecHWConfigInternal *const amf_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_AMF_SURFACE, + .methods = AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX | + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, + .device_type = AV_HWDEVICE_TYPE_AMF, + }, + .hwaccel = NULL, + }, + NULL +}; + +static void amf_free_amfsurface(void *opaque, uint8_t *data) +{ + AMFSurface *surface = (AMFSurface*)(data); + surface->pVtbl->Release(surface); +} + +static int amf_legacy_driver_no_bitness_detect(AVAMFDeviceContext *amf_device_ctx) +{ + if( AMF_GET_MAJOR_VERSION(amf_device_ctx->version) <= 1 && + AMF_GET_MINOR_VERSION(amf_device_ctx->version) <= 4 && + AMF_GET_SUBMINOR_VERSION(amf_device_ctx->version) < 36) + return 1; + return 0; +} + +static int amf_init_decoder(AVCodecContext *avctx) +{ + AMFDecoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext*)hw_device_ctx->hwctx; + const wchar_t *codec_id = NULL; + AMF_RESULT res; + AMFBuffer *buffer; + amf_int64 color_profile; + int pool_size = 36; + // way-around for older drivers that don't support dynamic bitness detection - + // define HEVC and VP9 10-bit based on container info + int no_bitness_detect = amf_legacy_driver_no_bitness_detect(amf_device_ctx); + + ctx->drain = 0; + ctx->resolution_changed = 0; + + switch (avctx->codec->id) { + case AV_CODEC_ID_H264: + codec_id = AMFVideoDecoderUVD_H264_AVC; + break; + case AV_CODEC_ID_HEVC: { + codec_id = AMFVideoDecoderHW_H265_HEVC; + if(no_bitness_detect){ + if(avctx->pix_fmt == AV_PIX_FMT_YUV420P10) + codec_id = AMFVideoDecoderHW_H265_MAIN10; + } + } break; + case AV_CODEC_ID_VP9: { + codec_id = AMFVideoDecoderHW_VP9; + if(no_bitness_detect){ + if(avctx->pix_fmt == AV_PIX_FMT_YUV420P10) + codec_id = AMFVideoDecoderHW_VP9_10BIT; + } + } break; + case AV_CODEC_ID_AV1: + codec_id = AMFVideoDecoderHW_AV1; + break; + default: + break; + } + AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id); + + res = amf_device_ctx->factory->pVtbl->CreateComponent(amf_device_ctx->factory, amf_device_ctx->context, codec_id, &ctx->decoder); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res); + + // Color Metadata + /// Color Range (Support for older Drivers) + if (avctx->color_range == AVCOL_RANGE_JPEG) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->decoder, AMF_VIDEO_DECODER_FULL_RANGE_COLOR, 1); + } else if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->decoder, AMF_VIDEO_DECODER_FULL_RANGE_COLOR, 0); + } + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN; + switch (avctx->colorspace) { + case AVCOL_SPC_SMPTE170M: + if (avctx->color_range == AVCOL_RANGE_JPEG) { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601; + } else { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_601; + } + break; + case AVCOL_SPC_BT709: + if (avctx->color_range == AVCOL_RANGE_JPEG) { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709; + } else { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_709; + } + break; + case AVCOL_SPC_BT2020_NCL: + case AVCOL_SPC_BT2020_CL: + if (avctx->color_range == AVCOL_RANGE_JPEG) { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_2020; + } else { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020; + } + break; + } + if (color_profile != AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_COLOR_PROFILE, color_profile); + if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_COLOR_TRANSFER_CHARACTERISTIC, (amf_int64)avctx->color_trc); + + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_COLOR_PRIMARIES, (amf_int64)avctx->color_primaries); + + if (ctx->timestamp_mode != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_TIMESTAMP_MODE, ctx->timestamp_mode); + if (ctx->decoder_mode != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_REORDER_MODE, ctx->decoder_mode); + if (ctx->dpb_size != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_DPB_SIZE, ctx->dpb_size); + if (ctx->lowlatency != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_LOW_LATENCY, ctx->lowlatency); + if (ctx->smart_access_video != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_ENABLE_SMART_ACCESS_VIDEO, ctx->smart_access_video != 0); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "The Smart Access Video is not supported by AMF decoder.\n"); + return AVERROR(EINVAL); + } else { + av_log(avctx, AV_LOG_INFO, "The Smart Access Video (%d) is set.\n", ctx->smart_access_video); + // Set low latency mode if Smart Access Video is enabled + if (ctx->smart_access_video != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_LOW_LATENCY, true); + av_log(avctx, AV_LOG_INFO, "The Smart Access Video set low latency mode for decoder.\n"); + } + } + } + if (ctx->skip_transfer_sav != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_SKIP_TRANSFER_SMART_ACCESS_VIDEO, ctx->skip_transfer_sav); + + if (ctx->copy_output != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_SURFACE_COPY, ctx->copy_output); + + if (avctx->extradata_size) { + const uint8_t *extradata; + int extradata_size; + ff_decode_get_extradata(avctx, &extradata, &extradata_size); + res = amf_device_ctx->context->pVtbl->AllocBuffer(amf_device_ctx->context, AMF_MEMORY_HOST, extradata_size, &buffer); + if (res == AMF_OK) { + memcpy(buffer->pVtbl->GetNative(buffer), extradata, extradata_size); + AMF_ASSIGN_PROPERTY_INTERFACE(res,ctx->decoder, AMF_VIDEO_DECODER_EXTRADATA, buffer); + buffer->pVtbl->Release(buffer); + buffer = NULL; + } + } + if (ctx->surface_pool_size == -1) { + ctx->surface_pool_size = pool_size; + if (avctx->extra_hw_frames > 0) + ctx->surface_pool_size += avctx->extra_hw_frames; + if (avctx->active_thread_type & FF_THREAD_FRAME) + ctx->surface_pool_size += avctx->thread_count; + } + + //at the moment, there is such a restriction in AMF. + //when it is possible, I will remove this code + if (ctx->surface_pool_size > 100) + ctx->surface_pool_size = 100; + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_SURFACE_POOL_SIZE, ctx->surface_pool_size); + res = ctx->decoder->pVtbl->Init(ctx->decoder, AMF_SURFACE_UNKNOWN, avctx->width, avctx->height); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "Decoder initialization failed with error %d\n", res); + return AVERROR(EINVAL); + } + return 0; +} + +static int amf_decode_close(AVCodecContext *avctx) +{ + AMFDecoderContext *ctx = avctx->priv_data; + + if (ctx->decoder) { + ctx->decoder->pVtbl->Terminate(ctx->decoder); + ctx->decoder->pVtbl->Release(ctx->decoder); + ctx->decoder = NULL; + } + + av_buffer_unref(&ctx->device_ctx_ref); + av_packet_free(&ctx->in_pkt); + + return 0; +} + +static int amf_init_frames_context(AVCodecContext *avctx, int sw_format, int new_width, int new_height) +{ + int ret; + AVHWDeviceContext *hwdev_ctx; + AVHWFramesContext *hwframes_ctx; + AMFDecoderContext *ctx; + if (!avctx->hw_frames_ctx || !avctx->hw_device_ctx) + return 0; + hwdev_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; + hwframes_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + ctx = avctx->priv_data; + + if (hwdev_ctx->type != AV_HWDEVICE_TYPE_AMF) + return 0; + + hwframes_ctx->width = new_width; + hwframes_ctx->height = new_height; + hwframes_ctx->format = AV_PIX_FMT_AMF_SURFACE; + hwframes_ctx->sw_format = sw_format; + hwframes_ctx->initial_pool_size = ctx->surface_pool_size + 8; + + ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error initializing a AMF frame pool\n"); + av_buffer_unref(&avctx->hw_frames_ctx); + return ret; + } + return 0; +} + +static int amf_decode_init(AVCodecContext *avctx) +{ + AMFDecoderContext *ctx = avctx->priv_data; + int ret; + ctx->in_pkt = av_packet_alloc(); + if (!ctx->in_pkt) + return AVERROR(ENOMEM); + + if (avctx->hw_device_ctx) { + AVHWDeviceContext *hwdev_ctx; + hwdev_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; + if (hwdev_ctx->type == AV_HWDEVICE_TYPE_AMF) + { + ctx->device_ctx_ref = av_buffer_ref(avctx->hw_device_ctx); + if (!avctx->hw_frames_ctx) { + avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx); + AMF_GOTO_FAIL_IF_FALSE(avctx, !!avctx->hw_frames_ctx, AVERROR(ENOMEM), "av_hwframe_ctx_alloc failed\n"); + } + } else { + ret = av_hwdevice_ctx_create_derived(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, avctx->hw_device_ctx, 0); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret == 0, ret, "Failed to create derived AMF device context: %s\n", av_err2str(ret)); + } + } else { + ret = av_hwdevice_ctx_create(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, NULL, NULL, 0); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret == 0, ret, "Failed to create hardware device context (AMF) : %s\n", av_err2str(ret)); + } + if ((ret = amf_init_decoder(avctx)) == 0) { + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext*)hw_device_ctx->hwctx; + enum AVPixelFormat surf_pix_fmt = AV_PIX_FMT_NONE; + + if(amf_legacy_driver_no_bitness_detect(amf_device_ctx)){ + // if bitness detection is not supported in legacy driver use format from container + switch (avctx->pix_fmt) { + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUVJ420P: + surf_pix_fmt = AV_PIX_FMT_NV12; break; + case AV_PIX_FMT_YUV420P10: + surf_pix_fmt = AV_PIX_FMT_P010; break; + } + }else{ + AMFVariantStruct format_var = {0}; + + ret = ctx->decoder->pVtbl->GetProperty(ctx->decoder, AMF_VIDEO_DECODER_OUTPUT_FORMAT, &format_var); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret == AMF_OK, AVERROR(EINVAL), "Failed to get output format (AMF) : %d\n", ret); + + surf_pix_fmt = av_amf_to_av_format(format_var.int64Value); + } + if(avctx->hw_frames_ctx) + { + // this values should be set for avcodec_open2 + // will be updated after header decoded if not true. + if(surf_pix_fmt == AV_PIX_FMT_NONE) + surf_pix_fmt = AV_PIX_FMT_NV12; // for older drivers + if (!avctx->coded_width) + avctx->coded_width = 1280; + if (!avctx->coded_height) + avctx->coded_height = 720; + ret = amf_init_frames_context(avctx, surf_pix_fmt, avctx->coded_width, avctx->coded_height); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret == 0, ret, "Failed to init frames context (AMF) : %s\n", av_err2str(ret)); + } + else + avctx->pix_fmt = surf_pix_fmt; + + return 0; + } +fail: + amf_decode_close(avctx); + return ret; +} + +static AMF_RESULT amf_get_property_buffer(AMFData *object, const wchar_t *name, AMFBuffer **val) +{ + AMF_RESULT res; + AMFVariantStruct var; + res = AMFVariantInit(&var); + if (res == AMF_OK) { + res = object->pVtbl->GetProperty(object, name, &var); + if (res == AMF_OK) { + if (var.type == AMF_VARIANT_INTERFACE) { + AMFGuid guid_AMFBuffer = IID_AMFBuffer(); + AMFInterface *amf_interface = AMFVariantInterface(&var); + res = amf_interface->pVtbl->QueryInterface(amf_interface, &guid_AMFBuffer, (void**)val); + } else { + res = AMF_INVALID_DATA_TYPE; + } + } + AMFVariantClear(&var); + } + return res; +} + +static int amf_amfsurface_to_avframe(AVCodecContext *avctx, AMFSurface* surface, AVFrame *frame) +{ + AMFVariantStruct var = {0}; + AMFPlane *plane; + int i; + int ret; + int format_amf; + + if (avctx->hw_device_ctx && ((AVHWDeviceContext*)avctx->hw_device_ctx->data)->type == AV_HWDEVICE_TYPE_AMF) { + // prepare frame similar to ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF); + + ret = ff_decode_frame_props(avctx, frame); + if (ret < 0) + return ret; + + avctx->sw_pix_fmt = avctx->pix_fmt; + + ret = ff_attach_decode_data(frame); + if (ret < 0) + return ret; + frame->width = avctx->width; + frame->height = avctx->height; + + //// + frame->buf[0] = av_buffer_create((uint8_t *)surface, sizeof(surface), + amf_free_amfsurface, (void*)avctx, + AV_BUFFER_FLAG_READONLY); + AMF_RETURN_IF_FALSE(avctx, !!frame->buf[0], AVERROR(ENOMEM), "av_buffer_create for amf surface failed."); + + frame->data[0] = (uint8_t *)surface; + frame->format = AV_PIX_FMT_AMF_SURFACE; + format_amf = surface->pVtbl->GetFormat(surface); + avctx->sw_pix_fmt = av_amf_to_av_format(format_amf); + frame->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx); + } else { + ret = surface->pVtbl->Convert(surface, AMF_MEMORY_HOST); + AMF_RETURN_IF_FALSE(avctx, ret == AMF_OK, AVERROR_UNKNOWN, "Convert(amf::AMF_MEMORY_HOST) failed with error %d\n", ret); + + for (i = 0; i < surface->pVtbl->GetPlanesCount(surface); i++) { + plane = surface->pVtbl->GetPlaneAt(surface, i); + frame->data[i] = plane->pVtbl->GetNative(plane); + frame->linesize[i] = plane->pVtbl->GetHPitch(plane); + } + + frame->buf[0] = av_buffer_create((uint8_t *)surface, sizeof(surface), + amf_free_amfsurface, (void*)avctx, + AV_BUFFER_FLAG_READONLY); + AMF_RETURN_IF_FALSE(avctx, !!frame->buf[0], AVERROR(ENOMEM), "av_buffer_create for amf surface failed."); + + format_amf = surface->pVtbl->GetFormat(surface); + frame->format = av_amf_to_av_format(format_amf); + } + + frame->width = avctx->width; + frame->height = avctx->height; + + frame->pts = surface->pVtbl->GetPts(surface); + + surface->pVtbl->GetProperty(surface, L"FFMPEG:dts", &var); + frame->pkt_dts = var.int64Value; + + frame->duration = surface->pVtbl->GetDuration(surface); + if (frame->duration < 0) + frame->duration = 0; + + frame->color_range = avctx->color_range; + frame->colorspace = avctx->colorspace; + frame->color_trc = avctx->color_trc; + frame->color_primaries = avctx->color_primaries; + + if (frame->color_trc == AVCOL_TRC_SMPTE2084) { + AMFBuffer * hdrmeta_buffer = NULL; + ret = amf_get_property_buffer((AMFData *)surface, AMF_VIDEO_DECODER_HDR_METADATA, &hdrmeta_buffer); + if (hdrmeta_buffer != NULL) { + AMFHDRMetadata * hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer); + if (ret != AMF_OK) + return ret; + if (hdrmeta != NULL) { + AVMasteringDisplayMetadata *mastering = av_mastering_display_metadata_create_side_data(frame); + const int chroma_den = 50000; + const int luma_den = 10000; + + if (!mastering) + return AVERROR(ENOMEM); + + mastering->display_primaries[0][0] = av_make_q(hdrmeta->redPrimary[0], chroma_den); + mastering->display_primaries[0][1] = av_make_q(hdrmeta->redPrimary[1], chroma_den); + + mastering->display_primaries[1][0] = av_make_q(hdrmeta->greenPrimary[0], chroma_den); + mastering->display_primaries[1][1] = av_make_q(hdrmeta->greenPrimary[1], chroma_den); + + mastering->display_primaries[2][0] = av_make_q(hdrmeta->bluePrimary[0], chroma_den); + mastering->display_primaries[2][1] = av_make_q(hdrmeta->bluePrimary[1], chroma_den); + + mastering->white_point[0] = av_make_q(hdrmeta->whitePoint[0], chroma_den); + mastering->white_point[1] = av_make_q(hdrmeta->whitePoint[1], chroma_den); + + mastering->max_luminance = av_make_q(hdrmeta->maxMasteringLuminance, luma_den); + mastering->min_luminance = av_make_q(hdrmeta->maxMasteringLuminance, luma_den); + + mastering->has_luminance = 1; + mastering->has_primaries = 1; + if (hdrmeta->maxContentLightLevel) { + AVContentLightMetadata *light = av_content_light_metadata_create_side_data(frame); + + if (!light) + return AVERROR(ENOMEM); + + light->MaxCLL = hdrmeta->maxContentLightLevel; + light->MaxFALL = hdrmeta->maxFrameAverageLightLevel; + } + } + } + } + return 0; +} + +static AMF_RESULT amf_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + AMFDecoderContext *ctx = avctx->priv_data; + AMF_RESULT ret = AMF_OK; + AMFSurface *surface = NULL; + AMFData *data_out = NULL; + + ret = ctx->decoder->pVtbl->QueryOutput(ctx->decoder, &data_out); + if (ret != AMF_OK && ret != AMF_REPEAT) { + return ret; + } + if (data_out == NULL) { + return AMF_REPEAT; + } + + if (data_out) { + AMFGuid guid = IID_AMFSurface(); + data_out->pVtbl->QueryInterface(data_out, &guid, (void**)&surface); // query for buffer interface + data_out->pVtbl->Release(data_out); + data_out = NULL; + } + + ret = amf_amfsurface_to_avframe(avctx, surface, frame); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret >= 0, AMF_FAIL, "Failed to convert AMFSurface to AVFrame = %d\n", ret); + return AMF_OK; +fail: + + if (surface) { + surface->pVtbl->Release(surface); + surface = NULL; + } + return ret; +} + +static AMF_RESULT amf_update_buffer_properties(AVCodecContext *avctx, AMFBuffer* buffer, const AVPacket* pkt) +{ + AMF_RESULT res; + + AMF_RETURN_IF_FALSE(avctx, buffer != NULL, AMF_INVALID_ARG, "update_buffer_properties() - buffer not passed in"); + AMF_RETURN_IF_FALSE(avctx, pkt != NULL, AMF_INVALID_ARG, "update_buffer_properties() - packet not passed in"); + buffer->pVtbl->SetPts(buffer, pkt->pts); + buffer->pVtbl->SetDuration(buffer, pkt->duration); + AMF_ASSIGN_PROPERTY_INT64(res, buffer, L"FFMPEG:dts", pkt->dts); + if (res != AMF_OK) + av_log(avctx, AV_LOG_VERBOSE, "Failed to assign dts value."); + return AMF_OK; +} + +static AMF_RESULT amf_buffer_from_packet(AVCodecContext *avctx, const AVPacket* pkt, AMFBuffer** buffer) +{ + AMFDecoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hw_device_ctx->hwctx; + AMFContext *ctxt = amf_device_ctx->context; + void *mem; + AMF_RESULT err; + AMFBuffer *buf = NULL; + + AMF_RETURN_IF_FALSE(ctxt, pkt != NULL, AMF_INVALID_ARG, "amf_buffer_from_packet() - packet not passed in"); + AMF_RETURN_IF_FALSE(ctxt, buffer != NULL, AMF_INVALID_ARG, "amf_buffer_from_packet() - buffer pointer not passed in"); + + err = ctxt->pVtbl->AllocBuffer(ctxt, AMF_MEMORY_HOST, pkt->size + AV_INPUT_BUFFER_PADDING_SIZE, buffer); + AMF_RETURN_IF_FALSE(ctxt, err == AMF_OK, err, "amf_buffer_from_packet() - failed"); + buf = *buffer; + err = buf->pVtbl->SetSize(buf, pkt->size); + AMF_RETURN_IF_FALSE(ctxt, err == AMF_OK, err, "amf_buffer_from_packet() - SetSize failed"); + // get the memory location and check the buffer was indeed allocated + mem = buf->pVtbl->GetNative(buf); + AMF_RETURN_IF_FALSE(ctxt, mem != NULL, AMF_INVALID_POINTER, "amf_buffer_from_packet() - GetNative failed"); + + // copy the packet memory and clear data padding + memcpy(mem, pkt->data, pkt->size); + memset((amf_int8*)(mem)+pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + return amf_update_buffer_properties(avctx, buf, pkt); +} + +static int amf_decode_frame(AVCodecContext *avctx, struct AVFrame *frame) +{ + AMFDecoderContext *ctx = avctx->priv_data; + AMFBuffer *buf; + AMF_RESULT res; + int got_frame = 0; + AVPacket *avpkt = ctx->in_pkt; + + if (!ctx->decoder) + return AVERROR(EINVAL); + + // get packet if needed + if(!ctx->drain){ + if(ctx->resolution_changed) + ctx->resolution_changed = 0; + else{ + int ret; + av_packet_unref(avpkt); + ret = ff_decode_get_packet(avctx, avpkt); + if (ret < 0 && ret != AVERROR_EOF) + return ret; + if (ret == AVERROR_EOF) { + //nothing to consume, start external drain + ctx->decoder->pVtbl->Drain(ctx->decoder); + ctx->drain = 1; + } + } + } + + if(!ctx->drain){ + // submit frame + res = amf_buffer_from_packet(avctx, avpkt, &buf); + AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, 0, "Cannot convert AVPacket to AMFbuffer"); + do{ + res = ctx->decoder->pVtbl->SubmitInput(ctx->decoder, (AMFData*) buf); + if(res == AMF_DECODER_NO_FREE_SURFACES) + { + av_usleep(100); + } + } while (res == AMF_DECODER_NO_FREE_SURFACES); + + buf->pVtbl->Release(buf); + + if(res == AMF_DECODER_NO_FREE_SURFACES) { + // input is not consumed, need to QueryOutput and submit again + av_log(avctx, AV_LOG_VERBOSE, "SubmitInput() returned NO_FREE_SURFACES and came out of loop - should never happen\n"); + res = AMF_OK; + } else if (res == AMF_RESOLUTION_CHANGED) { + //input is not consumed, start internal drain + ctx->decoder->pVtbl->Drain(ctx->decoder); + ctx->drain = 1; + // process resolution_changed when internal drain is complete + ctx->resolution_changed = 1; + res = AMF_OK; + } else if (res != AMF_OK && res != AMF_NEED_MORE_INPUT && res != AMF_REPEAT) { + av_log(avctx, AV_LOG_ERROR, "SubmitInput() returned error %d\n", res); + return AVERROR(EINVAL); + } + } + + res = amf_receive_frame(avctx, frame); + if (res == AMF_OK) + got_frame = 1; + else if (res == AMF_REPEAT) + // decoder has no output yet + res = AMF_OK; + else if (res == AMF_EOF) { + // drain is complete + ctx->drain = 0; + if(ctx->resolution_changed){ + // re-initialze decoder + AMFVariantStruct size_var = {0}; + AMFVariantStruct format_var = {0}; + res = ctx->decoder->pVtbl->GetProperty(ctx->decoder, AMF_VIDEO_DECODER_CURRENT_SIZE, &size_var); + if (res != AMF_OK) { + return AVERROR(EINVAL); + } + + avctx->width = size_var.sizeValue.width; + avctx->height = size_var.sizeValue.height; + avctx->coded_width = size_var.sizeValue.width; + avctx->coded_height = size_var.sizeValue.height; + res = ctx->decoder->pVtbl->ReInit(ctx->decoder, avctx->width, avctx->height); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "ReInit() returned %d\n", res); + return AVERROR(EINVAL); + } + res = ctx->decoder->pVtbl->GetProperty(ctx->decoder, AMF_VIDEO_DECODER_OUTPUT_FORMAT, &format_var); + if (res != AMF_OK) { + return AVERROR(EINVAL); + } + int ret = amf_init_frames_context(avctx, av_amf_to_av_format(format_var.int64Value), avctx->coded_width, avctx->coded_height); + if (ret < 0) + return ret; + }else + return AVERROR_EOF; + } else { + av_log(avctx, AV_LOG_ERROR, "Unknown result from QueryOutput %d\n", res); + } + return got_frame ? 0 : AVERROR(EAGAIN); +} + +static void amf_decode_flush(AVCodecContext *avctx) +{ + AMFDecoderContext *ctx = avctx->priv_data; + ctx->decoder->pVtbl->Flush(ctx->decoder); +} + +#define OFFSET(x) offsetof(AMFDecoderContext, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM + +static const AVOption options[] = { + // Decoder mode + { "decoder_mode", "Decoder mode", OFFSET(decoder_mode), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_DECODER_MODE_LOW_LATENCY, VD, "decoder_mode" }, + { "regular", "DPB delay is based on number of reference frames + 1", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_DECODER_MODE_REGULAR }, 0, 0, VD, "decoder_mode" }, + { "compliant", "DPB delay is based on profile - up to 16", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_DECODER_MODE_COMPLIANT }, 0, 0, VD, "decoder_mode" }, + { "low_latency", "DPB delay is 0", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_DECODER_MODE_LOW_LATENCY }, 0, 0, VD, "decoder_mode" }, + + // Timestamp mode + { "timestamp_mode", "Timestamp mode", OFFSET(timestamp_mode), AV_OPT_TYPE_INT, { .i64 = AMF_TS_SORT }, -1, AMF_TS_DECODE, VD, "timestamp_mode" }, + { "presentation", "Preserve timestamps from input to output", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_TS_PRESENTATION }, 0, 0, VD, "timestamp_mode" }, + { "sort", "Resort PTS list", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_TS_SORT }, 0, 0, VD, "timestamp_mode" }, + { "decode", "Decode order", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_TS_DECODE }, 0, 0, VD, "timestamp_mode" }, + + // Reference frame management + { "surface_pool_size", "Number of surfaces in the decode pool", OFFSET(surface_pool_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VD, NULL }, + { "dpb_size", "Minimum number of surfaces for reordering", OFFSET(dpb_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 32, VD, NULL }, + + { "lowlatency", "Low latency", OFFSET(lowlatency), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VD, NULL }, + { "smart_access_video", "Smart Access Video", OFFSET(smart_access_video), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VD, NULL }, + { "skip_transfer_sav", "Skip transfer on another GPU when SAV enabled", OFFSET(skip_transfer_sav), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VD, NULL }, + { "copy_output", "Copy Output", OFFSET(copy_output), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VD, NULL }, + + { NULL } +}; + +static const AVClass amf_decode_class = { + .class_name = "amf", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +#define DEFINE_AMF_DECODER(x, X, bsf_name) \ +const FFCodec ff_##x##_amf_decoder = { \ + .p.name = #x "_amf", \ + CODEC_LONG_NAME(#X " AMD AMF video decoder"), \ + .priv_data_size = sizeof(AMFDecoderContext), \ + .p.type = AVMEDIA_TYPE_VIDEO, \ + .p.id = AV_CODEC_ID_##X, \ + .init = amf_decode_init, \ + FF_CODEC_RECEIVE_FRAME_CB(amf_decode_frame), \ + .flush = amf_decode_flush, \ + .close = amf_decode_close, \ + .bsfs = bsf_name, \ + .p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \ + .p.priv_class = &amf_decode_class, \ + .hw_configs = amf_hw_configs, \ + .p.wrapper_name = "amf", \ + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, \ +}; \ + +DEFINE_AMF_DECODER(h264, H264, "h264_mp4toannexb") +DEFINE_AMF_DECODER(hevc, HEVC, NULL) +DEFINE_AMF_DECODER(vp9, VP9, NULL) +DEFINE_AMF_DECODER(av1, AV1, NULL) diff --git a/libavcodec/amfdec.h b/libavcodec/amfdec.h new file mode 100644 index 000000000..205d7a84a --- /dev/null +++ b/libavcodec/amfdec.h @@ -0,0 +1,63 @@ +/* + * 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_AMFDEC_H +#define AVCODEC_AMFDEC_H + +#include +#include +#include +#include +#include +#include +#include + +#include "avcodec.h" +#include "libavformat/avformat.h" +#include "libavutil/fifo.h" +#include "libavutil/frame.h" +#include "libavutil/opt.h" +#include "libavutil/hwcontext_amf.h" +/** +* AMF decoder context +*/ +typedef struct AMFDecoderContext { + AVClass *avclass; + AVBufferRef *device_ctx_ref; + + //decoder + AMFComponent *decoder; ///< AMF decoder object + AMF_SURFACE_FORMAT format; ///< AMF surface format + + // common decoder options + int decoder_mode; + int timestamp_mode; + int surface_pool_size; + int dpb_size; + int lowlatency; + int smart_access_video; + int skip_transfer_sav; + int drain; + int resolution_changed; + int copy_output; + AVPacket* in_pkt; + enum AMF_SURFACE_FORMAT output_format; + +} AMFDecoderContext; + +#endif // AVCODEC_AMFDEC_H diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index a47aea610..329ce2900 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -22,6 +22,8 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_amf.h" +#include "libavutil/hwcontext_amf_internal.h" #if CONFIG_D3D11VA #include "libavutil/hwcontext_d3d11va.h" #endif @@ -38,6 +40,9 @@ #include "internal.h" #include "libavutil/mastering_display_metadata.h" +#define AMF_AV_FRAME_REF L"av_frame_ref" +#define PTS_PROP L"PtsProp" + static int amf_save_hdr_metadata(AVCodecContext *avctx, const AVFrame *frame, AMFHDRMetadata *hdrmeta) { AVFrameSideData *sd_display; @@ -100,7 +105,6 @@ static int amf_save_hdr_metadata(AVCodecContext *avctx, const AVFrame *frame, AM #define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf" -#define PTS_PROP L"PtsProp" const enum AVPixelFormat ff_amf_pix_fmts[] = { AV_PIX_FMT_NV12, @@ -112,288 +116,42 @@ const enum AVPixelFormat ff_amf_pix_fmts[] = { AV_PIX_FMT_DXVA2_VLD, #endif AV_PIX_FMT_P010, + AV_PIX_FMT_AMF_SURFACE, + AV_PIX_FMT_BGR0, + AV_PIX_FMT_RGB0, + AV_PIX_FMT_BGRA, + AV_PIX_FMT_ARGB, + AV_PIX_FMT_RGBA, + AV_PIX_FMT_X2BGR10, + AV_PIX_FMT_RGBAF16, AV_PIX_FMT_NONE }; -typedef struct FormatMap { - enum AVPixelFormat av_format; - enum AMF_SURFACE_FORMAT amf_format; -} FormatMap; - -static const FormatMap format_map[] = -{ - { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN }, - { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 }, - { AV_PIX_FMT_P010, AMF_SURFACE_P010 }, - { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA }, - { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA }, - { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 }, - { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P }, - { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 }, -}; - -static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt) -{ - int i; - for (i = 0; i < amf_countof(format_map); i++) { - if (format_map[i].av_format == fmt) { - return format_map[i].amf_format; - } - } - return AMF_SURFACE_UNKNOWN; -} - -static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis, - const wchar_t *scope, const wchar_t *message) -{ - AmfTraceWriter *tracer = (AmfTraceWriter*)pThis; - av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF -} - -static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis) -{ -} - -static AMFTraceWriterVtbl tracer_vtbl = -{ - .Write = AMFTraceWriter_Write, - .Flush = AMFTraceWriter_Flush, -}; - -static int amf_load_library(AVCodecContext *avctx) -{ - AmfContext *ctx = avctx->priv_data; - AMFInit_Fn init_fun; - AMFQueryVersion_Fn version_fun; - AMF_RESULT res; - - ctx->delayed_frame = av_frame_alloc(); - if (!ctx->delayed_frame) { - return AVERROR(ENOMEM); - } - // hardcoded to current HW queue size - will auto-realloc if too small - ctx->timestamp_list = av_fifo_alloc2(avctx->max_b_frames + 16, sizeof(int64_t), - AV_FIFO_FLAG_AUTO_GROW); - if (!ctx->timestamp_list) { - return AVERROR(ENOMEM); - } - ctx->dts_delay = 0; - - - ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL); - AMF_RETURN_IF_FALSE(ctx, ctx->library != NULL, - AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA); - - init_fun = (AMFInit_Fn)dlsym(ctx->library, AMF_INIT_FUNCTION_NAME); - AMF_RETURN_IF_FALSE(ctx, init_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_INIT_FUNCTION_NAME); - - version_fun = (AMFQueryVersion_Fn)dlsym(ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME); - AMF_RETURN_IF_FALSE(ctx, version_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_QUERY_VERSION_FUNCTION_NAME); - - res = version_fun(&ctx->version); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res); - res = init_fun(AMF_FULL_VERSION, &ctx->factory); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res); - res = ctx->factory->pVtbl->GetTrace(ctx->factory, &ctx->trace); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() failed with error %d\n", res); - res = ctx->factory->pVtbl->GetDebug(ctx->factory, &ctx->debug); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() failed with error %d\n", res); - return 0; -} - -#if CONFIG_D3D11VA -static int amf_init_from_d3d11_device(AVCodecContext *avctx, AVD3D11VADeviceContext *hwctx) -{ - AmfContext *ctx = avctx->priv_data; - AMF_RESULT res; - - res = ctx->context->pVtbl->InitDX11(ctx->context, hwctx->device, AMF_DX11_1); - if (res != AMF_OK) { - if (res == AMF_NOT_SUPPORTED) - av_log(avctx, AV_LOG_ERROR, "AMF via D3D11 is not supported on the given device.\n"); - else - av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D11 device: %d.\n", res); - return AVERROR(ENODEV); - } - - return 0; -} -#endif - -#if CONFIG_DXVA2 -static int amf_init_from_dxva2_device(AVCodecContext *avctx, AVDXVA2DeviceContext *hwctx) -{ - AmfContext *ctx = avctx->priv_data; - HANDLE device_handle; - IDirect3DDevice9 *device; - HRESULT hr; - AMF_RESULT res; - int ret; - - hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &device_handle); - if (FAILED(hr)) { - av_log(avctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr); - return AVERROR_EXTERNAL; - } - - hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, &device, FALSE); - if (SUCCEEDED(hr)) { - IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE); - ret = 0; - } else { - av_log(avctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr); - ret = AVERROR_EXTERNAL; - } - - IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle); - - if (ret < 0) - return ret; - - res = ctx->context->pVtbl->InitDX9(ctx->context, device); - - IDirect3DDevice9_Release(device); - - if (res != AMF_OK) { - if (res == AMF_NOT_SUPPORTED) - av_log(avctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n"); - else - av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res); - return AVERROR(ENODEV); - } - - return 0; -} -#endif - -static int amf_init_context(AVCodecContext *avctx) -{ - AmfContext *ctx = avctx->priv_data; - AMFContext1 *context1 = NULL; - AMF_RESULT res; - av_unused int ret; - - ctx->hwsurfaces_in_queue = 0; - ctx->hwsurfaces_in_queue_max = 16; - - // configure AMF logger - // the return of these functions indicates old state and do not affect behaviour - ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 ); - if (ctx->log_to_dbg) - ctx->trace->pVtbl->SetWriterLevel(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TRACE); - ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_CONSOLE, 0); - ctx->trace->pVtbl->SetGlobalLevel(ctx->trace, AMF_TRACE_TRACE); - - // connect AMF logger to av_log - ctx->tracer.vtbl = &tracer_vtbl; - ctx->tracer.avctx = avctx; - ctx->trace->pVtbl->RegisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID,(AMFTraceWriter*)&ctx->tracer, 1); - ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, AMF_TRACE_TRACE); - - res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res); - - // If a device was passed to the encoder, try to initialise from that. - if (avctx->hw_frames_ctx) { - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - - if (amf_av_to_amf_format(frames_ctx->sw_format) == AMF_SURFACE_UNKNOWN) { - av_log(avctx, AV_LOG_ERROR, "Format of input frames context (%s) is not supported by AMF.\n", - av_get_pix_fmt_name(frames_ctx->sw_format)); - return AVERROR(EINVAL); - } - - switch (frames_ctx->device_ctx->type) { -#if CONFIG_D3D11VA - case AV_HWDEVICE_TYPE_D3D11VA: - ret = amf_init_from_d3d11_device(avctx, frames_ctx->device_ctx->hwctx); - if (ret < 0) - return ret; - break; -#endif -#if CONFIG_DXVA2 - case AV_HWDEVICE_TYPE_DXVA2: - ret = amf_init_from_dxva2_device(avctx, frames_ctx->device_ctx->hwctx); - if (ret < 0) - return ret; - break; -#endif - default: - av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s frames context is not supported.\n", - av_hwdevice_get_type_name(frames_ctx->device_ctx->type)); - return AVERROR(ENOSYS); - } - - ctx->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx); - if (!ctx->hw_frames_ctx) - return AVERROR(ENOMEM); - - if (frames_ctx->initial_pool_size > 0) - ctx->hwsurfaces_in_queue_max = frames_ctx->initial_pool_size - 1; - - } else if (avctx->hw_device_ctx) { - AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; - - switch (device_ctx->type) { -#if CONFIG_D3D11VA - case AV_HWDEVICE_TYPE_D3D11VA: - ret = amf_init_from_d3d11_device(avctx, device_ctx->hwctx); - if (ret < 0) - return ret; - break; -#endif -#if CONFIG_DXVA2 - case AV_HWDEVICE_TYPE_DXVA2: - ret = amf_init_from_dxva2_device(avctx, device_ctx->hwctx); - if (ret < 0) - return ret; - break; -#endif - default: - av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n", - av_hwdevice_get_type_name(device_ctx->type)); - return AVERROR(ENOSYS); - } - - ctx->hw_device_ctx = av_buffer_ref(avctx->hw_device_ctx); - if (!ctx->hw_device_ctx) - return AVERROR(ENOMEM); - - } else { - res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1); - if (res == AMF_OK) { - av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n"); - } else { - res = ctx->context->pVtbl->InitDX9(ctx->context, NULL); - if (res == AMF_OK) { - av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n"); - } else { - AMFGuid guid = IID_AMFContext1(); - res = ctx->context->pVtbl->QueryInterface(ctx->context, &guid, (void**)&context1); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res); - - res = context1->pVtbl->InitVulkan(context1, NULL); - context1->pVtbl->Release(context1); - if (res != AMF_OK) { - if (res == AMF_NOT_SUPPORTED) - av_log(avctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n"); - else - av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res); - return AVERROR(ENOSYS); - } - av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n"); - } - } - } - return 0; -} +static int64_t next_encoder_index = 0; static int amf_init_encoder(AVCodecContext *avctx) { - AmfContext *ctx = avctx->priv_data; - const wchar_t *codec_id = NULL; - AMF_RESULT res; - enum AVPixelFormat pix_fmt; + AMFEncoderContext *ctx = avctx->priv_data; + const wchar_t *codec_id = NULL; + AMF_RESULT res; + enum AVPixelFormat pix_fmt; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hw_device_ctx->hwctx; + int alloc_size; + wchar_t name[512]; + + + alloc_size = swprintf(name, amf_countof(name), L"%s%lld",PTS_PROP, next_encoder_index) + 1; + ctx->pts_property_name = av_memdup(name, alloc_size * sizeof(wchar_t)); + if(!ctx->pts_property_name) + return AVERROR(ENOMEM); + + alloc_size = swprintf(name, amf_countof(name), L"%s%lld",AMF_AV_FRAME_REF, next_encoder_index) + 1; + ctx->av_frame_property_name = av_memdup(name, alloc_size * sizeof(wchar_t)); + if(!ctx->av_frame_property_name) + return AVERROR(ENOMEM); + + next_encoder_index++; switch (avctx->codec->id) { case AV_CODEC_ID_H264: @@ -410,33 +168,32 @@ static int amf_init_encoder(AVCodecContext *avctx) } AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id); - if (ctx->hw_frames_ctx) - pix_fmt = ((AVHWFramesContext*)ctx->hw_frames_ctx->data)->sw_format; + if (avctx->hw_frames_ctx) + pix_fmt = ((AVHWFramesContext*)avctx->hw_frames_ctx->data)->sw_format; else pix_fmt = avctx->pix_fmt; if (pix_fmt == AV_PIX_FMT_P010) { - AMF_RETURN_IF_FALSE(ctx, ctx->version >= AMF_MAKE_FULL_VERSION(1, 4, 32, 0), AVERROR_UNKNOWN, "10-bit encoder is not supported by AMD GPU drivers versions lower than 23.30.\n"); + AMF_RETURN_IF_FALSE(ctx, amf_device_ctx->version >= AMF_MAKE_FULL_VERSION(1, 4, 32, 0), AVERROR_UNKNOWN, "10-bit encoder is not supported by AMD GPU drivers versions lower than 23.30.\n"); } - ctx->format = amf_av_to_amf_format(pix_fmt); + ctx->format = av_av_to_amf_format(pix_fmt); AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL), "Format %s is not supported\n", av_get_pix_fmt_name(pix_fmt)); - res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->context, codec_id, &ctx->encoder); + res = amf_device_ctx->factory->pVtbl->CreateComponent(amf_device_ctx->factory, amf_device_ctx->context, codec_id, &ctx->encoder); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res); + ctx->submitted_frame = 0; + ctx->encoded_frame = 0; + ctx->eof = 0; + return 0; } int av_cold ff_amf_encode_close(AVCodecContext *avctx) { - AmfContext *ctx = avctx->priv_data; - - if (ctx->delayed_surface) { - ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); - ctx->delayed_surface = NULL; - } + AMFEncoderContext *ctx = avctx->priv_data; if (ctx->encoder) { ctx->encoder->pVtbl->Terminate(ctx->encoder); @@ -444,29 +201,22 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx) ctx->encoder = NULL; } - if (ctx->context) { - ctx->context->pVtbl->Terminate(ctx->context); - ctx->context->pVtbl->Release(ctx->context); - ctx->context = NULL; - } - av_buffer_unref(&ctx->hw_device_ctx); - av_buffer_unref(&ctx->hw_frames_ctx); - - if (ctx->trace) { - ctx->trace->pVtbl->UnregisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID); - } - if (ctx->library) { - dlclose(ctx->library); - ctx->library = NULL; - } - ctx->trace = NULL; - ctx->debug = NULL; - ctx->factory = NULL; - ctx->version = 0; - ctx->delayed_drain = 0; - av_frame_free(&ctx->delayed_frame); + av_buffer_unref(&ctx->device_ctx_ref); av_fifo_freep2(&ctx->timestamp_list); + if (ctx->output_list) { + // release remaining AMF output buffers + while(av_fifo_can_read(ctx->output_list)) { + AMFBuffer* buffer = NULL; + av_fifo_read(ctx->output_list, &buffer, 1); + if(buffer != NULL) + buffer->pVtbl->Release(buffer); + } + av_fifo_freep2(&ctx->output_list); + } + av_freep(&ctx->pts_property_name); + av_freep(&ctx->av_frame_property_name); + return 0; } @@ -474,12 +224,12 @@ static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, AMFSurface* surface) { AMFPlane *plane; - uint8_t *dst_data[4]; - int dst_linesize[4]; + uint8_t *dst_data[4] = {0}; + int dst_linesize[4] = {0}; int planes; int i; - planes = surface->pVtbl->GetPlanesCount(surface); + planes = (int)surface->pVtbl->GetPlanesCount(surface); av_assert0(planes < FF_ARRAY_ELEMS(dst_data)); for (i = 0; i < planes; i++) { @@ -496,7 +246,7 @@ static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer) { - AmfContext *ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; int ret; AMFVariantStruct var = {0}; int64_t timestamp = AV_NOPTS_VALUE; @@ -529,11 +279,10 @@ static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buff break; } - buffer->pVtbl->GetProperty(buffer, PTS_PROP, &var); + buffer->pVtbl->GetProperty(buffer, ctx->pts_property_name, &var); pkt->pts = var.int64Value; // original pts - AMF_RETURN_IF_FALSE(ctx, av_fifo_read(ctx->timestamp_list, ×tamp, 1) >= 0, AVERROR_UNKNOWN, "timestamp_list is empty\n"); @@ -558,14 +307,63 @@ static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buff int ff_amf_encode_init(AVCodecContext *avctx) { int ret; + AMFEncoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hwdev_ctx = NULL; - if ((ret = amf_load_library(avctx)) == 0) { - if ((ret = amf_init_context(avctx)) == 0) { - if ((ret = amf_init_encoder(avctx)) == 0) { - return 0; + // hardcoded to current HW queue size - will auto-realloc if too small + ctx->timestamp_list = av_fifo_alloc2(avctx->max_b_frames + 16, sizeof(int64_t), + AV_FIFO_FLAG_AUTO_GROW); + if (!ctx->timestamp_list) { + return AVERROR(ENOMEM); + } + ctx->output_list = av_fifo_alloc2(2, sizeof(AMFBuffer*), AV_FIFO_FLAG_AUTO_GROW); + if (!ctx->output_list) + return AVERROR(ENOMEM); + + ctx->dts_delay = 0; + + ctx->hwsurfaces_in_queue = 0; + + if (avctx->hw_device_ctx) { + hwdev_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; + if (hwdev_ctx->type == AV_HWDEVICE_TYPE_AMF) + { + ctx->device_ctx_ref = av_buffer_ref(avctx->hw_device_ctx); + } + else { + ret = av_hwdevice_ctx_create_derived(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, avctx->hw_device_ctx, 0); + AMF_RETURN_IF_FALSE(ctx, ret == 0, ret, "Failed to create derived AMF device context: %s\n", av_err2str(ret)); + } + } else if (avctx->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + if (frames_ctx->device_ref ) { + if (frames_ctx->format == AV_PIX_FMT_AMF_SURFACE) { + ctx->device_ctx_ref = av_buffer_ref(frames_ctx->device_ref); + } + else { + ret = av_hwdevice_ctx_create_derived(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, frames_ctx->device_ref, 0); + AMF_RETURN_IF_FALSE(ctx, ret == 0, ret, "Failed to create derived AMF device context: %s\n", av_err2str(ret)); } } } + else { + ret = av_hwdevice_ctx_create(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, NULL, NULL, 0); + AMF_RETURN_IF_FALSE(ctx, ret == 0, ret, "Failed to create hardware device context (AMF) : %s\n", av_err2str(ret)); + } + + if (ctx->pa_lookahead_buffer_depth >= ctx->hwsurfaces_in_queue_max) { + av_log(avctx, AV_LOG_WARNING, + "async_depth (%d) too small for lookahead (%d), increasing to (%d)\n", + ctx->hwsurfaces_in_queue_max, + ctx->pa_lookahead_buffer_depth, + ctx->pa_lookahead_buffer_depth + 1); + ctx->hwsurfaces_in_queue_max = ctx->pa_lookahead_buffer_depth + 1; + } + + if ((ret = amf_init_encoder(avctx)) == 0) { + return 0; + } + ff_amf_encode_close(avctx); return ret; } @@ -592,241 +390,96 @@ static AMF_RESULT amf_set_property_buffer(AMFSurface *object, const wchar_t *nam return res; } -static AMF_RESULT amf_get_property_buffer(AMFData *object, const wchar_t *name, AMFBuffer **val) +static AMF_RESULT amf_store_attached_frame_ref(AMFEncoderContext *ctx, const AVFrame *frame, AMFSurface *surface) { - AMF_RESULT res; - AMFVariantStruct var; - res = AMFVariantInit(&var); - if (res == AMF_OK) { - res = object->pVtbl->GetProperty(object, name, &var); - if (res == AMF_OK) { - if (var.type == AMF_VARIANT_INTERFACE) { - AMFGuid guid_AMFBuffer = IID_AMFBuffer(); - AMFInterface *amf_interface = AMFVariantInterface(&var); - res = amf_interface->pVtbl->QueryInterface(amf_interface, &guid_AMFBuffer, (void**)val); - } else { - res = AMF_INVALID_DATA_TYPE; - } - } - AMFVariantClear(&var); + AMF_RESULT res = AMF_FAIL; + int64_t data; + AVFrame *frame_ref = av_frame_clone(frame); + if (frame_ref) { + memcpy(&data, &frame_ref, sizeof(frame_ref)); // store pointer in 8 bytes + AMF_ASSIGN_PROPERTY_INT64(res, surface, ctx->av_frame_property_name, data); } return res; } -static AMFBuffer *amf_create_buffer_with_frame_ref(const AVFrame *frame, AMFContext *context) +static AMF_RESULT amf_release_attached_frame_ref(AMFEncoderContext *ctx, AMFBuffer *buffer) { - AVFrame *frame_ref; - AMFBuffer *frame_ref_storage_buffer = NULL; - AMF_RESULT res; - - res = context->pVtbl->AllocBuffer(context, AMF_MEMORY_HOST, sizeof(frame_ref), &frame_ref_storage_buffer); - if (res == AMF_OK) { - frame_ref = av_frame_clone(frame); - if (frame_ref) { - memcpy(frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), &frame_ref, sizeof(frame_ref)); - } else { - frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); - frame_ref_storage_buffer = NULL; - } + AMFVariantStruct var = {0}; + AMF_RESULT res = buffer->pVtbl->GetProperty(buffer, ctx->av_frame_property_name, &var); + if(res == AMF_OK && var.int64Value){ + AVFrame *frame_ref; + memcpy(&frame_ref, &var.int64Value, sizeof(frame_ref)); + av_frame_free(&frame_ref); } - return frame_ref_storage_buffer; + return res; } -static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffer) +static int amf_submit_frame(AVCodecContext *avctx, AVFrame *frame, AMFSurface **surface_resubmit) { - AVFrame *frame_ref; - memcpy(&frame_ref, frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), sizeof(frame_ref)); - av_frame_free(&frame_ref); - frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); -} + AMFEncoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hw_device_ctx->hwctx; + AMFSurface *surface; + AMF_RESULT res; + int ret; + int hw_surface = 0; + int output_delay = FFMAX(ctx->max_b_frames, 0) + ((avctx->flags & AV_CODEC_FLAG_LOW_DELAY) ? 0 : 1); -int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) -{ - AmfContext *ctx = avctx->priv_data; - AMFSurface *surface; - AMF_RESULT res; - int ret; - AMF_RESULT res_query; - AMFData *data = NULL; - AVFrame *frame = ctx->delayed_frame; - int block_and_wait; - int query_output_data_flag = 0; - AMF_RESULT res_resubmit; - - if (!ctx->encoder) - return AVERROR(EINVAL); - - if (!frame->buf[0]) { - ret = ff_encode_get_frame(avctx, frame); - if (ret < 0 && ret != AVERROR_EOF) - return ret; - } - - if (!frame->buf[0]) { // submit drain - if (!ctx->eof) { // submit drain one time only - if (ctx->delayed_surface != NULL) { - ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet - } else if(!ctx->delayed_drain) { - res = ctx->encoder->pVtbl->Drain(ctx->encoder); - if (res == AMF_INPUT_FULL) { - ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet - } else { - if (res == AMF_OK) { - ctx->eof = 1; // drain started - } - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Drain() failed with error %d\n", res); - } - } - } - } else if (!ctx->delayed_surface) { // submit frame - int hw_surface = 0; - - // prepare surface from frame - switch (frame->format) { +// prepare surface from frame + switch (frame->format) { #if CONFIG_D3D11VA - case AV_PIX_FMT_D3D11: - { - static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } }; - ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; // actual texture - int index = (intptr_t)frame->data[1]; // index is a slice in texture array is - set to tell AMF which slice to use - - av_assert0(frame->hw_frames_ctx && ctx->hw_frames_ctx && - frame->hw_frames_ctx->data == ctx->hw_frames_ctx->data); - + case AV_PIX_FMT_D3D11: + { + static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } }; + ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; // actual texture + int index = (intptr_t)frame->data[1]; // index is a slice in texture array is - set to tell AMF which slice to use + av_assert0(frame->hw_frames_ctx && avctx->hw_frames_ctx && + frame->hw_frames_ctx->data == avctx->hw_frames_ctx->data); texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index); - - res = ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX11Native() failed with error %d\n", res); - + res = amf_device_ctx->context->pVtbl->CreateSurfaceFromDX11Native(amf_device_ctx->context, texture, &surface, NULL); // wrap to AMF surface + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX11Native() failed with error %d\n", res); hw_surface = 1; - } - break; + } + break; #endif #if CONFIG_DXVA2 - case AV_PIX_FMT_DXVA2_VLD: - { - IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture - - res = ctx->context->pVtbl->CreateSurfaceFromDX9Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX9Native() failed with error %d\n", res); - + case AV_PIX_FMT_DXVA2_VLD: + { + IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture + res = amf_device_ctx->context->pVtbl->CreateSurfaceFromDX9Native(amf_device_ctx->context, texture, &surface, NULL); // wrap to AMF surface + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX9Native() failed with error %d\n", res); hw_surface = 1; - } - break; + } + break; #endif - default: - { - res = ctx->context->pVtbl->AllocSurface(ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res); - amf_copy_surface(avctx, frame, surface); - } - break; + case AV_PIX_FMT_AMF_SURFACE: + { + surface = (AMFSurface*)frame->data[0]; + surface->pVtbl->Acquire(surface); + hw_surface = 1; } - - if (hw_surface) { - AMFBuffer *frame_ref_storage_buffer; - - // input HW surfaces can be vertically aligned by 16; tell AMF the real size - surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height); - - frame_ref_storage_buffer = amf_create_buffer_with_frame_ref(frame, ctx->context); - AMF_RETURN_IF_FALSE(ctx, frame_ref_storage_buffer != NULL, AVERROR(ENOMEM), "create_buffer_with_frame_ref() returned NULL\n"); - - res = amf_set_property_buffer(surface, L"av_frame_ref", frame_ref_storage_buffer); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_ref\" with error %d\n", res); - ctx->hwsurfaces_in_queue++; - frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); - } - - // HDR10 metadata - if (frame->color_trc == AVCOL_TRC_SMPTE2084) { - AMFBuffer * hdrmeta_buffer = NULL; - res = ctx->context->pVtbl->AllocBuffer(ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer); - if (res == AMF_OK) { - AMFHDRMetadata * hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer); - if (amf_save_hdr_metadata(avctx, frame, hdrmeta) == 0) { - switch (avctx->codec->id) { - case AV_CODEC_ID_H264: - AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_INPUT_HDR_METADATA, hdrmeta_buffer); break; - case AV_CODEC_ID_HEVC: - AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_INPUT_HDR_METADATA, hdrmeta_buffer); break; - case AV_CODEC_ID_AV1: - AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_INPUT_HDR_METADATA, hdrmeta_buffer); break; - } - res = amf_set_property_buffer(surface, L"av_frame_hdrmeta", hdrmeta_buffer); - AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_hdrmeta\" with error %d\n", res); - } - hdrmeta_buffer->pVtbl->Release(hdrmeta_buffer); - } - } - - surface->pVtbl->SetPts(surface, frame->pts); - AMF_ASSIGN_PROPERTY_INT64(res, surface, PTS_PROP, frame->pts); - - switch (avctx->codec->id) { - case AV_CODEC_ID_H264: - AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud); - break; - case AV_CODEC_ID_HEVC: - AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud); - break; - //case AV_CODEC_ID_AV1 not supported - default: - break; - } - - // submit surface - res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface); - if (res == AMF_INPUT_FULL) { // handle full queue - //store surface for later submission - ctx->delayed_surface = surface; - } else { - int64_t pts = frame->pts; - surface->pVtbl->Release(surface); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res); - - av_frame_unref(frame); - ret = av_fifo_write(ctx->timestamp_list, &pts, 1); - if (ret < 0) - return ret; + break; + default: + { + res = amf_device_ctx->context->pVtbl->AllocSurface(amf_device_ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res); + amf_copy_surface(avctx, frame, surface); } + break; } - - - do { - block_and_wait = 0; - // poll data - if (!avpkt->data && !avpkt->buf) { - res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data); - if (data) { - // copy data to packet - AMFBuffer *buffer; - AMFGuid guid = IID_AMFBuffer(); - query_output_data_flag = 1; - data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface - ret = amf_copy_buffer(avctx, avpkt, buffer); - - buffer->pVtbl->Release(buffer); - - if (data->pVtbl->HasProperty(data, L"av_frame_ref")) { - AMFBuffer* frame_ref_storage_buffer; - res = amf_get_property_buffer(data, L"av_frame_ref", &frame_ref_storage_buffer); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetProperty failed for \"av_frame_ref\" with error %d\n", res); - amf_release_buffer_with_frame_ref(frame_ref_storage_buffer); - ctx->hwsurfaces_in_queue--; - } - - data->pVtbl->Release(data); - - AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret); - } - } - res_resubmit = AMF_OK; - if (ctx->delayed_surface != NULL) { // try to resubmit frame - if (ctx->delayed_surface->pVtbl->HasProperty(ctx->delayed_surface, L"av_frame_hdrmeta")) { - AMFBuffer * hdrmeta_buffer = NULL; - res = amf_get_property_buffer((AMFData *)ctx->delayed_surface, L"av_frame_hdrmeta", &hdrmeta_buffer); - AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "GetProperty failed for \"av_frame_hdrmeta\" with error %d\n", res); + if (hw_surface) { + amf_store_attached_frame_ref(ctx, frame, surface); + ctx->hwsurfaces_in_queue++; + // input HW surfaces can be vertically aligned by 16; tell AMF the real size + surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height); + } + // HDR10 metadata + if (frame->color_trc == AVCOL_TRC_SMPTE2084) { + AMFBuffer * hdrmeta_buffer = NULL; + res = amf_device_ctx->context->pVtbl->AllocBuffer(amf_device_ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer); + if (res == AMF_OK) { + AMFHDRMetadata * hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer); + if (amf_save_hdr_metadata(avctx, frame, hdrmeta) == 0) { switch (avctx->codec->id) { case AV_CODEC_ID_H264: AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_INPUT_HDR_METADATA, hdrmeta_buffer); break; @@ -835,34 +488,202 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) case AV_CODEC_ID_AV1: AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_INPUT_HDR_METADATA, hdrmeta_buffer); break; } - hdrmeta_buffer->pVtbl->Release(hdrmeta_buffer); + res = amf_set_property_buffer(surface, L"av_frame_hdrmeta", hdrmeta_buffer); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_hdrmeta\" with error %d\n", res); } - res_resubmit = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)ctx->delayed_surface); - if (res_resubmit != AMF_INPUT_FULL) { - int64_t pts = ctx->delayed_surface->pVtbl->GetPts(ctx->delayed_surface); - ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); - ctx->delayed_surface = NULL; - av_frame_unref(ctx->delayed_frame); - AMF_RETURN_IF_FALSE(ctx, res_resubmit == AMF_OK, AVERROR_UNKNOWN, "Repeated SubmitInput() failed with error %d\n", res_resubmit); + hdrmeta_buffer->pVtbl->Release(hdrmeta_buffer); + } + } + surface->pVtbl->SetPts(surface, frame->pts); - ret = av_fifo_write(ctx->timestamp_list, &pts, 1); - if (ret < 0) - return ret; - } - } else if (ctx->delayed_drain) { // try to resubmit drain - res = ctx->encoder->pVtbl->Drain(ctx->encoder); - if (res != AMF_INPUT_FULL) { - ctx->delayed_drain = 0; - ctx->eof = 1; // drain started - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated Drain() failed with error %d\n", res); + AMF_ASSIGN_PROPERTY_INT64(res, surface, ctx->pts_property_name, frame->pts); + + switch (avctx->codec->id) { + case AV_CODEC_ID_H264: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud); + switch (frame->pict_type) { + case AV_PICTURE_TYPE_I: + if (ctx->forced_idr) { + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_SPS, 1); + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_PPS, 1); + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_IDR); } else { - av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n"); + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_I); + } + break; + case AV_PICTURE_TYPE_P: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_P); + break; + case AV_PICTURE_TYPE_B: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_B); + break; + } + break; + case AV_CODEC_ID_HEVC: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud); + switch (frame->pict_type) { + case AV_PICTURE_TYPE_I: + if (ctx->forced_idr) { + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_HEADER, 1); + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_IDR); + } else { + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_I); + } + break; + case AV_PICTURE_TYPE_P: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_P); + break; + } + break; + case AV_CODEC_ID_AV1: + if (frame->pict_type == AV_PICTURE_TYPE_I) { + if (ctx->forced_idr) { + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_INSERT_SEQUENCE_HEADER, 1); + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_KEY); + } else { + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_INTRA_ONLY); } } + break; + default: + break; + } + // submit surface + res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface); + if (res == AMF_INPUT_FULL) { // handle full queue + //store surface for later submission + *surface_resubmit = surface; + } else { + surface->pVtbl->Release(surface); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res); + ctx->submitted_frame++; + ret = av_fifo_write(ctx->timestamp_list, &frame->pts, 1); + if (ret < 0) + return ret; + if(ctx->submitted_frame <= ctx->encoded_frame + output_delay) + return AVERROR(EAGAIN); // too soon to poll or wait + } + return 0; +} - if (query_output_data_flag == 0) { - if (res_resubmit == AMF_INPUT_FULL || ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max)) { - block_and_wait = 1; +static int amf_submit_frame_locked(AVCodecContext *avctx, AVFrame *frame, AMFSurface **surface_resubmit) +{ + int ret; + AMFEncoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hw_device_ctx->hwctx; + + if (amf_device_ctx->lock) + amf_device_ctx->lock(amf_device_ctx->lock_ctx); + ret = amf_submit_frame(avctx, frame, surface_resubmit); + if (amf_device_ctx->unlock) + amf_device_ctx->unlock(amf_device_ctx->lock_ctx); + + return ret; +} +static AMF_RESULT amf_query_output(AVCodecContext *avctx, AMFBuffer **buffer) +{ + AMFEncoderContext *ctx = avctx->priv_data; + AMFData *data = NULL; + AMF_RESULT ret = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data); + *buffer = NULL; + if (data) { + AMFGuid guid = IID_AMFBuffer(); + data->pVtbl->QueryInterface(data, &guid, (void**)buffer); // query for buffer interface + data->pVtbl->Release(data); + if (amf_release_attached_frame_ref(ctx, *buffer) == AMF_OK) + ctx->hwsurfaces_in_queue--; + ctx->encoded_frame++; + } + return ret; +} + +int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) +{ + AMFEncoderContext *ctx = avctx->priv_data; + AMFSurface *surface = NULL; + AMF_RESULT res; + int ret; + AMF_RESULT res_query; + AMFBuffer* buffer = NULL; + AVFrame *frame = av_frame_alloc(); + int block_and_wait; + int64_t pts = 0; + int output_delay = FFMAX(ctx->max_b_frames, 0) + ((avctx->flags & AV_CODEC_FLAG_LOW_DELAY) ? 0 : 1); + + if (!ctx->encoder){ + av_frame_free(&frame); + return AVERROR(EINVAL); + } + // check if some outputs are available + av_fifo_read(ctx->output_list, &buffer, 1); + if (buffer != NULL) { // return already retrieved output + ret = amf_copy_buffer(avctx, avpkt, buffer); + buffer->pVtbl->Release(buffer); + return ret; + } + + ret = ff_encode_get_frame(avctx, frame); + if(ret < 0){ + if(ret != AVERROR_EOF){ + av_frame_free(&frame); + if(ret == AVERROR(EAGAIN)){ + if(ctx->submitted_frame <= ctx->encoded_frame + output_delay) // too soon to poll + return ret; + } + } + } + if(ret != AVERROR(EAGAIN)){ + if (!frame->buf[0]) { // submit drain + if (!ctx->eof) { // submit drain one time only + if(!ctx->delayed_drain) { + res = ctx->encoder->pVtbl->Drain(ctx->encoder); + if (res == AMF_INPUT_FULL) { + ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in receive loop + } else { + if (res == AMF_OK) { + ctx->eof = 1; // drain started + } + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Drain() failed with error %d\n", res); + } + } + } + } else { // submit frame + ret = amf_submit_frame_locked(avctx, frame, &surface); + if(ret < 0){ + av_frame_free(&frame); + return ret; + } + pts = frame->pts; + } + } + av_frame_free(&frame); + + do { + block_and_wait = 0; + // poll data + res_query = amf_query_output(avctx, &buffer); + if (buffer) { + ret = amf_copy_buffer(avctx, avpkt, buffer); + buffer->pVtbl->Release(buffer); + + AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret); + + if (ctx->delayed_drain) { // try to resubmit drain + res = ctx->encoder->pVtbl->Drain(ctx->encoder); + if (res != AMF_INPUT_FULL) { + ctx->delayed_drain = 0; + ctx->eof = 1; // drain started + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated Drain() failed with error %d\n", res); + } else { + av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n"); + } + } + } else if (ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max) || surface) { + block_and_wait = 1; + // Only sleep if the driver doesn't support waiting in QueryOutput() + // or if we already have output data so we will skip calling it. + if (!ctx->query_timeout_supported || avpkt->data || avpkt->buf) { av_usleep(1000); } } @@ -870,9 +691,43 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) if (res_query == AMF_EOF) { ret = AVERROR_EOF; - } else if (data == NULL) { + } else if (buffer == NULL) { ret = AVERROR(EAGAIN); } else { + if(surface) { + // resubmit surface + do { + res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface); + if (res != AMF_INPUT_FULL) + break; + + if (!ctx->query_timeout_supported) + av_usleep(1000); + + // Need to free up space in the encoder queue. + // The number of retrieved outputs is limited currently to 21 + amf_query_output(avctx, &buffer); + if (buffer != NULL) { + ret = av_fifo_write(ctx->output_list, &buffer, 1); + if (ret < 0) + return ret; + } + } while(res == AMF_INPUT_FULL); + + surface->pVtbl->Release(surface); + if (res == AMF_INPUT_FULL) { + av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed SubmitInput returned AMF_INPUT_FULL- should not happen\n"); + } else { + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res); + + ret = av_fifo_write(ctx->timestamp_list, &pts, 1); + + ctx->submitted_frame++; + + if (ret < 0) + return ret; + } + } ret = 0; } return ret; @@ -922,5 +777,7 @@ const AVCodecHWConfigInternal *const ff_amfenc_hw_configs[] = { HW_CONFIG_ENCODER_FRAMES(DXVA2_VLD, DXVA2), HW_CONFIG_ENCODER_DEVICE(NONE, DXVA2), #endif + HW_CONFIG_ENCODER_FRAMES(AMF_SURFACE, AMF), + HW_CONFIG_ENCODER_DEVICE(NONE, AMF), NULL, }; diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h index d985d01bb..ff5ce0ba7 100644 --- a/libavcodec/amfenc.h +++ b/libavcodec/amfenc.h @@ -33,54 +33,37 @@ #define MAX_LOOKAHEAD_DEPTH 41 -/** -* AMF trace writer callback class -* Used to capture all AMF logging -*/ - -typedef struct AmfTraceWriter { - AMFTraceWriterVtbl *vtbl; - AVCodecContext *avctx; -} AmfTraceWriter; - /** * AMF encoder context */ -typedef struct AmfContext { +typedef struct AMFEncoderContext { AVClass *avclass; // access to AMF runtime - amf_handle library; ///< handle to DLL library - AMFFactory *factory; ///< pointer to AMF factory - AMFDebug *debug; ///< pointer to AMF debug interface - AMFTrace *trace; ///< pointer to AMF trace interface + AVBufferRef *device_ctx_ref; - amf_uint64 version; ///< version of AMF runtime - AmfTraceWriter tracer; ///< AMF writer registered with AMF - AMFContext *context; ///< AMF context //encoder AMFComponent *encoder; ///< AMF encoder object amf_bool eof; ///< flag indicating EOF happened AMF_SURFACE_FORMAT format; ///< AMF surface format - - AVBufferRef *hw_device_ctx; ///< pointer to HW accelerator (decoder) - AVBufferRef *hw_frames_ctx; ///< pointer to HW accelerator (frame allocator) + wchar_t *pts_property_name; + wchar_t *av_frame_property_name; int hwsurfaces_in_queue; int hwsurfaces_in_queue_max; + int query_timeout_supported; // helpers to handle async calls int delayed_drain; - AMFSurface *delayed_surface; - AVFrame *delayed_frame; // shift dts back by max_b_frames in timing AVFifo *timestamp_list; int64_t dts_delay; + int64_t submitted_frame; + int64_t encoded_frame; + AVFifo *output_list; - // common encoder option options - - int log_to_dbg; + // common encoder options // Static options, have to be set before Init() call int usage; @@ -91,6 +74,8 @@ typedef struct AmfContext { int quality; int b_frame_delta_qp; int ref_b_frame_delta_qp; + int bit_depth; + int smart_access_video; // Dynamic options, can be set after Init() call @@ -114,6 +99,7 @@ typedef struct AmfContext { int max_b_frames; int qvbr_quality_level; int hw_high_motion_quality_boost; + int forced_idr; // HEVC - specific options @@ -123,12 +109,16 @@ typedef struct AmfContext { int max_qp_i; int min_qp_p; int max_qp_p; + int min_qp_b; + int max_qp_b; int tier; // AV1 - specific options - enum AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_ENUM align; - enum AMF_VIDEO_ENCODER_AV1_AQ_MODE_ENUM aq_mode; + /* enum AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_ENUM, use int for AVOption */ + int align; + /* enum AMF_VIDEO_ENCODER_AV1_AQ_MODE_ENUM */ + int aq_mode; // Preanalysis - specific options @@ -150,7 +140,7 @@ typedef struct AmfContext { int pa_adaptive_mini_gop; -} AmfContext; +} AMFEncoderContext; extern const AVCodecHWConfigInternal *const ff_amfenc_hw_configs[]; diff --git a/libavcodec/amfenc_av1.c b/libavcodec/amfenc_av1.c index 2a7a78206..70642a6b5 100644 --- a/libavcodec/amfenc_av1.c +++ b/libavcodec/amfenc_av1.c @@ -26,17 +26,21 @@ #define AMF_VIDEO_ENCODER_AV1_CAP_WIDTH_ALIGNMENT_FACTOR_LOCAL L"Av1WidthAlignmentFactor" // amf_int64; default = 1 #define AMF_VIDEO_ENCODER_AV1_CAP_HEIGHT_ALIGNMENT_FACTOR_LOCAL L"Av1HeightAlignmentFactor" // amf_int64; default = 1 -#define OFFSET(x) offsetof(AmfContext, x) +#define OFFSET(x) offsetof(AMFEncoderContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { { "usage", "Set the encoding usage", OFFSET(usage), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY_HIGH_QUALITY, VE, .unit = "usage" }, { "transcoding", "Generic Transcoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING }, 0, 0, VE, .unit = "usage" }, - { "ultralowlatency", "ultra low latency trancoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, + { "ultralowlatency", "ultra low latency transcoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, { "lowlatency", "Low latency usecase", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, { "webcam", "Webcam", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_WEBCAM }, 0, 0, VE, .unit = "usage" }, - { "high_quality", "high quality trancoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, - { "lowlatency_high_quality","low latency yet high quality trancoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, + { "high_quality", "high quality transcoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, + { "lowlatency_high_quality","low latency yet high quality transcoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, + + { "bitdepth", "Set color bit deph", OFFSET(bit_depth), AV_OPT_TYPE_INT, {.i64 = AMF_COLOR_BIT_DEPTH_UNDEFINED }, AMF_COLOR_BIT_DEPTH_UNDEFINED, AMF_COLOR_BIT_DEPTH_10, VE, .unit = "bitdepth" }, + { "8", "8 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_COLOR_BIT_DEPTH_8 }, 0, 0, VE, .unit = "bitdepth" }, + { "10", "10 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_COLOR_BIT_DEPTH_10 }, 0, 0, VE, .unit = "bitdepth" }, { "profile", "Set the profile", OFFSET(profile), AV_OPT_TYPE_INT,{.i64 = -1 }, -1, AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN, VE, .unit = "profile" }, { "main", "", 0, AV_OPT_TYPE_CONST,{.i64 = AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN }, 0, 0, VE, .unit = "profile" }, @@ -84,7 +88,7 @@ static const AVOption options[] = { { "rc", "Set the rate control mode", OFFSET(rate_control_mode), AV_OPT_TYPE_INT, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_UNKNOWN }, AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_UNKNOWN, AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR, VE, .unit = "rc" }, { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, .unit = "rc" }, { "vbr_latency", "Latency Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, - { "vbr_peak", "Peak Contrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, + { "vbr_peak", "Peak Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, { "cbr", "Constant Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR }, 0, 0, VE, .unit = "rc" }, { "qvbr", "Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, { "hqvbr", "High Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, @@ -97,32 +101,42 @@ static const AVOption options[] = { { "gop", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_GOP_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, { "frame", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_KEY_FRAME_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, + { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, MAX_LOOKAHEAD_DEPTH + 1, VE }, + { "preencode", "Enable preencode", OFFSET(preencode), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, { "filler_data", "Filler Data Enable", OFFSET(filler_data), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, + // B-Frames + { "max_b_frames", "Maximum number of consecutive B Pictures", OFFSET(max_consecutive_b_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 3, VE }, + { "bf", "B Picture Pattern", OFFSET(max_b_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 3, VE }, + { "high_motion_quality_boost_enable", "Enable High motion quality boost mode", OFFSET(hw_high_motion_quality_boost), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, - // min_qp_i -> min_qp_intra, min_qp_p -> min_qp_inter + // min_qp_i -> min_qp_intra, min_qp_p -> min_qp_p min_qp_b -> min_qp_b { "min_qp_i", "min quantization parameter for I-frame", OFFSET(min_qp_i), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "max_qp_i", "max quantization parameter for I-frame", OFFSET(max_qp_i), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "min_qp_p", "min quantization parameter for P-frame", OFFSET(min_qp_p), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "max_qp_p", "max quantization parameter for P-frame", OFFSET(max_qp_p), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, + { "min_qp_b", "min quantization parameter for B-frame", OFFSET(min_qp_b), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, + { "max_qp_b", "max quantization parameter for B-frame", OFFSET(max_qp_b), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "qp_p", "quantization parameter for P-frame", OFFSET(qp_p), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "qp_i", "quantization parameter for I-frame", OFFSET(qp_i), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, + { "qp_b", "quantization parameter for B-frame", OFFSET(qp_b), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "skip_frame", "Rate Control Based Frame Skip", OFFSET(skip_frame), AV_OPT_TYPE_BOOL,{.i64 = -1 }, -1, 1, VE }, { "aq_mode", "adaptive quantization mode", OFFSET(aq_mode), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_VIDEO_ENCODER_AV1_AQ_MODE_CAQ, VE , .unit = "adaptive_quantisation_mode" }, { "none", "no adaptive quantization", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_AQ_MODE_NONE }, 0, 0, VE, .unit = "adaptive_quantisation_mode" }, { "caq", "context adaptive quantization", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_AQ_MODE_CAQ }, 0, 0, VE, .unit = "adaptive_quantisation_mode" }, + { "forced_idr", "Force I frames to be IDR frames", OFFSET(forced_idr), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "align", "alignment mode", OFFSET(align), AV_OPT_TYPE_INT, {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS }, AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY, AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS, VE, .unit = "align" }, { "64x16", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY }, 0, 0, VE, .unit = "align" }, { "1080p", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_1080P_CODED_1082 }, 0, 0, VE, .unit = "align" }, { "none", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS }, 0, 0, VE, .unit = "align" }, - { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg), AV_OPT_TYPE_BOOL,{.i64 = 0 }, 0, 1, VE }, + { "smart_access_video", "Enable Smart Access Video to enhance performance by utilizing both APU and dGPU memory access", OFFSET(smart_access_video), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, //Pre Analysis options { "preanalysis", "Enable preanalysis", OFFSET(preanalysis), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, @@ -134,16 +148,16 @@ static const AVOption options[] = { { "pa_scene_change_detection_enable", "Enable scene change detection", OFFSET(pa_scene_change_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "pa_scene_change_detection_sensitivity", "Set the sensitivity of scene change detection", OFFSET(pa_scene_change_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH, VE, .unit = "scene_change_sensitivity" }, - { "low", "low scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "medium", "medium scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "high", "high scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "low", "low scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "medium", "medium scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "high", "high scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, { "pa_static_scene_detection_enable", "Enable static scene detection", OFFSET(pa_static_scene_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "pa_static_scene_detection_sensitivity", "Set the sensitivity of static scene detection", OFFSET(pa_static_scene_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH, VE , .unit = "static_scene_sensitivity" }, - { "low", "low static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "medium", "medium static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "high", "high static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "low", "low static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "medium", "medium static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "high", "high static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, { "pa_initial_qp_after_scene_change", "The QP value that is used immediately after a scene change", OFFSET(pa_initial_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, { "pa_max_qp_before_force_skip", "The QP threshold to allow a skip frame", OFFSET(pa_max_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, @@ -169,6 +183,9 @@ static const AVOption options[] = { { "pa_high_motion_quality_boost_mode", "Sets the PA high motion quality boost mode", OFFSET(pa_high_motion_quality_boost_mode), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_AUTO, VE , .unit = "high_motion_quality_boost_mode" }, { "none", "no high motion quality boost", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_NONE }, 0, 0, VE, .unit = "high_motion_quality_boost_mode" }, { "auto", "auto high motion quality boost", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_AUTO }, 0, 0, VE, .unit = "high_motion_quality_boost_mode" }, + + { "pa_adaptive_mini_gop", "Enable Adaptive B-frame", OFFSET(pa_adaptive_mini_gop), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, + { NULL } }; @@ -177,15 +194,15 @@ static av_cold int amf_encode_init_av1(AVCodecContext* avctx) { int ret = 0; AMF_RESULT res = AMF_OK; - AmfContext* ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; AMFVariantStruct var = { 0 }; amf_int64 profile = 0; amf_int64 profile_level = 0; - AMFBuffer* buffer; + AMFBuffer *buffer; AMFGuid guid; AMFRate framerate; AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); - amf_int64 color_depth; + amf_int64 bit_depth; amf_int64 color_profile; enum AVPixelFormat pix_fmt; @@ -199,13 +216,7 @@ static av_cold int amf_encode_init_av1(AVCodecContext* avctx) framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); } else { -FF_DISABLE_DEPRECATION_WARNINGS - framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ); -FF_ENABLE_DEPRECATION_WARNINGS + framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num); } if ((ret = ff_amf_encode_init(avctx)) < 0) @@ -237,30 +248,37 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_PROFILE, profile); } - /// Color profile + // Color bit depth + pix_fmt = avctx->hw_frames_ctx ? ((AVHWFramesContext*)avctx->hw_frames_ctx->data)->sw_format + : avctx->pix_fmt; + bit_depth = ctx->bit_depth; + if(bit_depth == AMF_COLOR_BIT_DEPTH_UNDEFINED){ + bit_depth = pix_fmt == AV_PIX_FMT_P010 ? AMF_COLOR_BIT_DEPTH_10 : AMF_COLOR_BIT_DEPTH_8; + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_COLOR_BIT_DEPTH, bit_depth); + + // Color profile color_profile = ff_amf_get_color_profile(avctx); AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PROFILE, color_profile); - /// Color Depth - pix_fmt = avctx->hw_frames_ctx ? ((AVHWFramesContext*)avctx->hw_frames_ctx->data)->sw_format - : avctx->pix_fmt; - color_depth = AMF_COLOR_BIT_DEPTH_8; - if (pix_fmt == AV_PIX_FMT_P010) { - color_depth = AMF_COLOR_BIT_DEPTH_10; + // Color Range + // TODO + + // Color Transfer Characteristics (AMF matches ISO/IEC) + if(avctx->color_primaries != AVCOL_PRI_UNSPECIFIED && (pix_fmt == AV_PIX_FMT_NV12 || pix_fmt == AV_PIX_FMT_P010)){ + // if input is YUV, color_primaries are for VUI only + // AMF VCN color conversion supports only specific output primaries BT2020 for 10-bit and BT709 for 8-bit + // vpp_amf supports more + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_TRANSFER_CHARACTERISTIC, avctx->color_trc); } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_COLOR_BIT_DEPTH, color_depth); - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PROFILE, color_profile); - if (color_depth == AMF_COLOR_BIT_DEPTH_8) { - /// Color Transfer Characteristics (AMF matches ISO/IEC) - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709); - /// Color Primaries (AMF matches ISO/IEC) - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT709); - } else { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE2084); - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT2020); + // Color Primaries (AMF matches ISO/IEC) + if(avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || pix_fmt == AV_PIX_FMT_NV12 || pix_fmt == AV_PIX_FMT_P010 ) + { + // AMF VCN color conversion supports only specific primaries BT2020 for 10-bit and BT709 for 8-bit + // vpp_amf supports more + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PRIMARIES, avctx->color_primaries); } - profile_level = avctx->level; if (profile_level == AV_LEVEL_UNKNOWN) { profile_level = ctx->level; @@ -280,7 +298,9 @@ FF_ENABLE_DEPRECATION_WARNINGS } // Picture control properties - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_GOP_SIZE, avctx->gop_size); + if (avctx->gop_size != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_GOP_SIZE, avctx->gop_size); + } // Setup header insertion mode only if this option was defined explicitly if (ctx->header_insertion_mode != -1) { @@ -292,7 +312,8 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_UNKNOWN) { if (ctx->min_qp_i != -1 || ctx->max_qp_i != -1 || ctx->min_qp_p != -1 || ctx->max_qp_p != -1 || - ctx->qp_i != -1 || ctx->qp_p != -1) { + ctx->min_qp_b != -1 || ctx->max_qp_b != -1 || + ctx->qp_i != -1 || ctx->qp_p != -1 || ctx->qp_b != -1) { ctx->rate_control_mode = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP; av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CQP\n"); } @@ -305,6 +326,21 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\n"); } } + if (ctx->smart_access_video != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_ENABLE_SMART_ACCESS_VIDEO, ctx->smart_access_video != 0); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "The Smart Access Video is not supported by AMF.\n"); + if (ctx->smart_access_video != 0) + return AVERROR(ENOSYS); + } else { + av_log(avctx, AV_LOG_INFO, "The Smart Access Video (%d) is set.\n", ctx->smart_access_video); + // Set low latency mode if Smart Access Video is enabled + if (ctx->smart_access_video != 0) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE, AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_LOWEST_LATENCY); + av_log(avctx, AV_LOG_INFO, "The Smart Access Video set low latency mode.\n"); + } + } + } // Pre-Pass, Pre-Analysis, Two-Pass if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP) { @@ -367,7 +403,7 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_PEAK_BITRATE, avctx->rc_max_rate); } else if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR) { - av_log(ctx, AV_LOG_WARNING, "rate control mode is PEAK_CONSTRAINED_VBR but rc_max_rate is not set\n"); + av_log(ctx, AV_LOG_DEBUG, "rate control mode is vbr_peak but max_rate is not set, default max_rate will be applied.\n"); } if (avctx->bit_rate > 0) { ctx->rate_control_mode = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR; @@ -456,6 +492,9 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->pa_taq_mode != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_TAQ_MODE, ctx->pa_taq_mode); } + if (ctx->pa_adaptive_mini_gop != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_ADAPTIVE_MINIGOP, ((ctx->pa_adaptive_mini_gop == 0) ? false : true)); + } if (ctx->pa_ltr != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_PA_LTR_ENABLE, ((ctx->pa_ltr == 0) ? false : true)); } @@ -467,6 +506,67 @@ FF_ENABLE_DEPRECATION_WARNINGS } } + // B-Frames + AMFVariantStruct is_adaptive_b_frames = { 0 }; + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_ADAPTIVE_MINIGOP, &is_adaptive_b_frames); + if (ctx->max_consecutive_b_frames != -1 || ctx->max_b_frames != -1 || is_adaptive_b_frames.boolValue == true) { + + //Get the capability of encoder + AMFCaps *encoder_caps = NULL; + ctx->encoder->pVtbl->GetCaps(ctx->encoder, &encoder_caps); + if (encoder_caps != NULL) + { + res = encoder_caps->pVtbl->GetProperty(encoder_caps, AMF_VIDEO_ENCODER_AV1_CAP_BFRAMES, &var); + if (res == AMF_OK) { + + //encoder supports AV1 B-frame + if(var.boolValue == true){ + //adaptive b-frames is higher priority than max_b_frames + if (is_adaptive_b_frames.boolValue == true) + { + //force AMF_VIDEO_ENCODER_AV1_MAX_CONSECUTIVE_BPICTURES to 3 + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_CONSECUTIVE_BPICTURES, 3); + + if(ctx->pa_lookahead_buffer_depth < 1) + { + //force AMF_PA_LOOKAHEAD_BUFFER_DEPTH to 1 if not set or smaller than 1 + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, 1); + } + } + else { + if (ctx->max_b_frames != -1) { + //in case user sets B-frames + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_B_PIC_PATTERN, ctx->max_b_frames); + if (res != AMF_OK) { + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_B_PIC_PATTERN, &var); + av_log(ctx, AV_LOG_WARNING, "B-frames=%d is not supported by this GPU, switched to %d\n", ctx->max_b_frames, (int)var.int64Value); + ctx->max_b_frames = (int)var.int64Value; + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_CONSECUTIVE_BPICTURES, ctx->max_b_frames); + } + } + + } + //encoder doesn't support AV1 B-frame + else { + av_log(ctx, AV_LOG_WARNING, "The current GPU in use does not support AV1 B-frame encoding, there will be no B-frame in bitstream.\n"); + } + } else { + //Can't get the capability of encoder + av_log(ctx, AV_LOG_WARNING, "Unable to get AV1 B-frame capability.\n"); + av_log(ctx, AV_LOG_WARNING, "There will be no B-frame in bitstream.\n"); + } + + encoder_caps->pVtbl->Release(encoder_caps); + encoder_caps = NULL; + } + } + + // Wait inside QueryOutput() if supported by the driver + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_QUERY_TIMEOUT, 1); + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_QUERY_TIMEOUT, &var); + ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + // init encoder res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, avctx->height); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); @@ -493,6 +593,13 @@ FF_ENABLE_DEPRECATION_WARNINGS int qval = avctx->qmin > 255 ? 255 : avctx->qmin; AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTER, qval); } + if (ctx->min_qp_b != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTER_B, ctx->min_qp_b); + } + else if (avctx->qmin != -1) { + int qval = avctx->qmin > 255 ? 255 : avctx->qmin; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTER_B, qval); + } if (ctx->max_qp_p != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTER, ctx->max_qp_p); } @@ -500,6 +607,13 @@ FF_ENABLE_DEPRECATION_WARNINGS int qval = avctx->qmax > 255 ? 255 : avctx->qmax; AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTER, qval); } + if (ctx->max_qp_b != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTER_B, ctx->max_qp_b); + } + else if (avctx->qmax != -1) { + int qval = avctx->qmax > 255 ? 255 : avctx->qmax; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTER_B, qval); + } if (ctx->qp_p != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTER, ctx->qp_p); @@ -507,6 +621,9 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->qp_i != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTRA, ctx->qp_i); } + if (ctx->qp_b != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTER_B, ctx->qp_b); + } if (ctx->skip_frame != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_SKIP_FRAME, ((ctx->skip_frame == 0) ? false : true)); @@ -540,7 +657,7 @@ FF_ENABLE_DEPRECATION_WARNINGS buffer->pVtbl->Release(buffer); var.pInterface->pVtbl->Release(var.pInterface); - //processing crop informaiton according to alignment + //processing crop information according to alignment if (ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_CAP_WIDTH_ALIGNMENT_FACTOR_LOCAL, &var) != AMF_OK) // assume older driver and Navi3x width_alignment_factor = 64; @@ -622,13 +739,13 @@ const FFCodec ff_av1_amf_encoder = { .init = amf_encode_init_av1, FF_CODEC_RECEIVE_PACKET_CB(ff_amf_receive_packet), .close = ff_amf_encode_close, - .priv_data_size = sizeof(AmfContext), + .priv_data_size = sizeof(AMFEncoderContext), .p.priv_class = &av1_amf_class, .defaults = defaults, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = ff_amf_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_amf_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .p.wrapper_name = "amf", .hw_configs = ff_amfenc_hw_configs, diff --git a/libavcodec/amfenc_h264.c b/libavcodec/amfenc_h264.c index 8edd39c63..c39a65aea 100644 --- a/libavcodec/amfenc_h264.c +++ b/libavcodec/amfenc_h264.c @@ -24,7 +24,7 @@ #include "codec_internal.h" #include -#define OFFSET(x) offsetof(AmfContext, x) +#define OFFSET(x) offsetof(AMFEncoderContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { @@ -82,7 +82,7 @@ static const AVOption options[] = { { "rc", "Rate Control Method", OFFSET(rate_control_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN }, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR, VE, .unit = "rc" }, { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, .unit = "rc" }, { "cbr", "Constant Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR }, 0, 0, VE, .unit = "rc" }, - { "vbr_peak", "Peak Contrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, + { "vbr_peak", "Peak Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, { "vbr_latency", "Latency Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, { "qvbr", "Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, { "hqvbr", "High Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, @@ -110,6 +110,9 @@ static const AVOption options[] = { /// Header Insertion Spacing { "header_spacing", "Header Insertion Spacing", OFFSET(header_spacing), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1000, VE }, + /// Maximum queued frames + { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, MAX_LOOKAHEAD_DEPTH + 1, VE }, + /// B-Frames // BPicturesPattern=bf { "bf_delta_qp", "B-Picture Delta QP", OFFSET(b_frame_delta_qp), AV_OPT_TYPE_INT, { .i64 = 4 }, -10, 10, VE }, @@ -133,10 +136,10 @@ static const AVOption options[] = { { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, { "me_quarter_pel", "Enable ME Quarter Pixel", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, + { "forced_idr", "Force I frames to be IDR frames", OFFSET(forced_idr) , AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) , AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, - - { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg) , AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "smart_access_video", "Enable Smart Access Video to enhance performance by utilizing both APU and dGPU memory access", OFFSET(smart_access_video), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, //Pre Analysis options { "preanalysis", "Enable preanalysis", OFFSET(preanalysis), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, @@ -148,16 +151,16 @@ static const AVOption options[] = { { "pa_scene_change_detection_enable", "Enable scene change detection", OFFSET(pa_scene_change_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "pa_scene_change_detection_sensitivity", "Set the sensitivity of scene change detection", OFFSET(pa_scene_change_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH, VE, .unit = "scene_change_sensitivity" }, - { "low", "low scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "medium", "medium scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "high", "high scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "low", "low scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "medium", "medium scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "high", "high scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, { "pa_static_scene_detection_enable", "Enable static scene detection", OFFSET(pa_static_scene_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "pa_static_scene_detection_sensitivity", "Set the sensitivity of static scene detection", OFFSET(pa_static_scene_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH, VE , .unit = "static_scene_sensitivity" }, - { "low", "low static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "medium", "medium static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "high", "high static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "low", "low static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "medium", "medium static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "high", "high static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, { "pa_initial_qp_after_scene_change", "The QP value that is used immediately after a scene change", OFFSET(pa_initial_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, { "pa_max_qp_before_force_skip", "The QP threshold to allow a skip frame", OFFSET(pa_max_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, @@ -192,7 +195,7 @@ static av_cold int amf_encode_init_h264(AVCodecContext *avctx) { int ret = 0; AMF_RESULT res = AMF_OK; - AmfContext *ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; AMFVariantStruct var = { 0 }; amf_int64 profile = 0; amf_int64 profile_level = 0; @@ -207,13 +210,7 @@ static av_cold int amf_encode_init_h264(AVCodecContext *avctx) if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); } else { -FF_DISABLE_DEPRECATION_WARNINGS - framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ); -FF_ENABLE_DEPRECATION_WARNINGS + framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num); } if ((ret = ff_amf_encode_init(avctx)) != 0) @@ -391,13 +388,29 @@ FF_ENABLE_DEPRECATION_WARNINGS if (avctx->rc_max_rate) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PEAK_BITRATE, avctx->rc_max_rate); } else if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR) { - av_log(ctx, AV_LOG_WARNING, "rate control mode is PEAK_CONSTRAINED_VBR but rc_max_rate is not set\n"); + av_log(ctx, AV_LOG_DEBUG, "rate control mode is vbr_peak but max_rate is not set, default max_rate will be applied.\n"); } if (ctx->latency != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_LOWLATENCY_MODE, ((ctx->latency == 0) ? false : true)); } + if (ctx->smart_access_video != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_SMART_ACCESS_VIDEO, ctx->smart_access_video != 0); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "The Smart Access Video is not supported by AMF.\n"); + if (ctx->smart_access_video != 0) + return AVERROR(ENOSYS); + } else { + av_log(avctx, AV_LOG_INFO, "The Smart Access Video (%d) is set.\n", ctx->smart_access_video); + // Set low latency mode if Smart Access Video is enabled + if (ctx->smart_access_video != 0) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_LOWLATENCY_MODE, true); + av_log(avctx, AV_LOG_INFO, "The Smart Access Video set low latency mode.\n"); + } + } + } + if (ctx->preanalysis != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_PRE_ANALYSIS_ENABLE, !!((ctx->preanalysis == 0) ? false : true)); } @@ -455,26 +468,61 @@ FF_ENABLE_DEPRECATION_WARNINGS } // B-Frames - if (ctx->max_consecutive_b_frames != -1) { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_CONSECUTIVE_BPICTURES, ctx->max_consecutive_b_frames); - if (ctx->max_b_frames != -1) { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, ctx->max_b_frames); - if (res != AMF_OK) { - res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, &var); - av_log(ctx, AV_LOG_WARNING, "B-frames=%d is not supported by this GPU, switched to %d\n", - ctx->max_b_frames, (int)var.int64Value); - ctx->max_b_frames = (int)var.int64Value; - } - if (ctx->max_consecutive_b_frames < ctx->max_b_frames) { - av_log(ctx, AVERROR_BUG, "Maxium B frames needs to be greater than the specified B frame count.\n"); + AMFVariantStruct is_adaptive_b_frames = { 0 }; + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_ADAPTIVE_MINIGOP, &is_adaptive_b_frames); + if (ctx->max_consecutive_b_frames != -1 || ctx->max_b_frames != -1 || is_adaptive_b_frames.boolValue == true) { + + //Get the capability of encoder + AMFCaps *encoder_caps = NULL; + ctx->encoder->pVtbl->GetCaps(ctx->encoder, &encoder_caps); + if (encoder_caps != NULL) + { + res = encoder_caps->pVtbl->GetProperty(encoder_caps, AMF_VIDEO_ENCODER_CAP_BFRAMES, &var); + if (res == AMF_OK) { + + //encoder supports H.264 B-frame + if(var.boolValue == true){ + //adaptive b-frames is higher priority than max_b_frames + if (is_adaptive_b_frames.boolValue == true) + { + //force AMF_VIDEO_ENCODER_MAX_CONSECUTIVE_BPICTURES to 3 + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_CONSECUTIVE_BPICTURES, 3); + + if(ctx->pa_lookahead_buffer_depth < 1) + { + //force AMF_PA_LOOKAHEAD_BUFFER_DEPTH to 1 if not set or smaller than 1 + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, 1); + } + } + else { + if (ctx->max_b_frames != -1) { + //in case user sets B-frames + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, ctx->max_b_frames); + if (res != AMF_OK) { + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, &var); + av_log(ctx, AV_LOG_WARNING, "B-frames=%d is not supported by this GPU, switched to %d\n", ctx->max_b_frames, (int)var.int64Value); + ctx->max_b_frames = (int)var.int64Value; + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_CONSECUTIVE_BPICTURES, ctx->max_b_frames); + } + } + + } + //encoder doesn't support H.264 B-frame + else { + av_log(ctx, AV_LOG_WARNING, "The current GPU in use does not support H.264 B-frame encoding, there will be no B-frame in bitstream.\n"); + } + } else { + //Can't get the capability of encoder + av_log(ctx, AV_LOG_WARNING, "Unable to get H.264 B-frame capability.\n"); + av_log(ctx, AV_LOG_WARNING, "There will be no B-frame in bitstream.\n"); } + + encoder_caps->pVtbl->Release(encoder_caps); + encoder_caps = NULL; } } - else { - if (ctx->max_b_frames != -1) { - av_log(ctx, AVERROR_BUG, "Maxium number of B frames needs to be specified.\n"); - } - } + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, &var); if ((int)var.int64Value) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_DELTA_QP, ctx->b_frame_delta_qp); @@ -482,6 +530,21 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_REF_B_PIC_DELTA_QP, ctx->ref_b_frame_delta_qp); } + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_VBAQ, 0); + if (ctx->enable_vbaq) + av_log(ctx, AV_LOG_WARNING, "VBAQ is not supported by cqp Rate Control Method, automatically disabled\n"); + } else { + if (ctx->enable_vbaq != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_VBAQ, !!ctx->enable_vbaq); + } + } + + // Wait inside QueryOutput() if supported by the driver + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QUERY_TIMEOUT, 1); + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_QUERY_TIMEOUT, &var); + ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + // Initialize Encoder res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, avctx->height); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); @@ -499,19 +562,12 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_SKIP_FRAME_ENABLE, ((ctx->skip_frame == 0) ? false : true)); } - if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_VBAQ, 0); - if (ctx->enable_vbaq) - av_log(ctx, AV_LOG_WARNING, "VBAQ is not supported by cqp Rate Control Method, automatically disabled\n"); - } else { - if (ctx->enable_vbaq != -1) { - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_VBAQ, !!ctx->enable_vbaq); - } - } AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_DE_BLOCKING_FILTER, !!deblocking_filter); // Keyframe Interval - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_IDR_PERIOD, avctx->gop_size); + if (avctx->gop_size != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_IDR_PERIOD, avctx->gop_size); + } // Header Insertion Spacing if (ctx->header_spacing >= 0) @@ -594,14 +650,14 @@ const FFCodec ff_h264_amf_encoder = { .init = amf_encode_init_h264, FF_CODEC_RECEIVE_PACKET_CB(ff_amf_receive_packet), .close = ff_amf_encode_close, - .priv_data_size = sizeof(AmfContext), + .priv_data_size = sizeof(AMFEncoderContext), .p.priv_class = &h264_amf_class, .defaults = defaults, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = ff_amf_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_amf_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.wrapper_name = "amf", .hw_configs = ff_amfenc_hw_configs, diff --git a/libavcodec/amfenc_hevc.c b/libavcodec/amfenc_hevc.c index 4898824f3..fe1d948c9 100644 --- a/libavcodec/amfenc_hevc.c +++ b/libavcodec/amfenc_hevc.c @@ -23,11 +23,11 @@ #include "codec_internal.h" #include -#define OFFSET(x) offsetof(AmfContext, x) +#define OFFSET(x) offsetof(AMFEncoderContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "usage", "Set the encoding usage", OFFSET(usage), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY_HIGH_QUALITY, VE, .unit = "usage" }, + { "usage", "Set the encoding usage", OFFSET(usage), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY_HIGH_QUALITY, VE, .unit = "usage" }, { "transcoding", "Generic Transcoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCODING }, 0, 0, VE, .unit = "usage" }, { "ultralowlatency", "Ultra low latency usecase", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, { "lowlatency", "Low latency usecase", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, @@ -35,15 +35,19 @@ static const AVOption options[] = { { "high_quality", "High quality usecase", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, { "lowlatency_high_quality", "Low latency yet high quality usecase", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, - { "profile", "Set the profile", OFFSET(profile), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10, VE, .unit = "profile" }, + { "bitdepth", "Set color bit deph", OFFSET(bit_depth), AV_OPT_TYPE_INT, {.i64 = AMF_COLOR_BIT_DEPTH_UNDEFINED }, AMF_COLOR_BIT_DEPTH_UNDEFINED, AMF_COLOR_BIT_DEPTH_10, VE, .unit = "bitdepth" }, + { "8", "8 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_COLOR_BIT_DEPTH_8 }, 0, 0, VE, .unit = "bitdepth" }, + { "10", "10 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_COLOR_BIT_DEPTH_10 }, 0, 0, VE, .unit = "bitdepth" }, + + { "profile", "Set the profile", OFFSET(profile), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10, VE, .unit = "profile" }, { "main", "", 0, AV_OPT_TYPE_CONST,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN }, 0, 0, VE, .unit = "profile" }, { "main10", "", 0, AV_OPT_TYPE_CONST,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10 }, 0, 0, VE, .unit = "profile" }, - { "profile_tier", "Set the profile tier (default main)", OFFSET(tier), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_TIER_HIGH, VE, .unit = "tier" }, + { "profile_tier", "Set the profile tier (default main)", OFFSET(tier), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_TIER_HIGH, VE, .unit = "tier" }, { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_MAIN }, 0, 0, VE, .unit = "tier" }, { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_HIGH }, 0, 0, VE, .unit = "tier" }, - { "level", "Set the encoding level (default auto)", OFFSET(level), AV_OPT_TYPE_INT,{ .i64 = 0 }, 0, AMF_LEVEL_6_2, VE, .unit = "level" }, + { "level", "Set the encoding level (default auto)", OFFSET(level), AV_OPT_TYPE_INT,{ .i64 = 0 }, 0, AMF_LEVEL_6_2, VE, .unit = "level" }, { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, .unit = "level" }, { "1.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_1 }, 0, 0, VE, .unit = "level" }, { "2.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_2 }, 0, 0, VE, .unit = "level" }, @@ -59,37 +63,39 @@ static const AVOption options[] = { { "6.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_6_1 }, 0, 0, VE, .unit = "level" }, { "6.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_6_2 }, 0, 0, VE, .unit = "level" }, - { "quality", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED, VE, .unit = "quality" }, - { "preset", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED, VE, .unit = "quality" }, + { "quality", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED, VE, .unit = "quality" }, + { "preset", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED, VE, .unit = "quality" }, { "quality", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY }, 0, 0, VE, .unit = "quality" }, { "balanced", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_BALANCED }, 0, 0, VE, .unit = "quality" }, { "speed", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED }, 0, 0, VE, .unit = "quality" }, - { "latency", "enables low latency mode", OFFSET(latency), AV_OPT_TYPE_BOOL,{.i64 = -1 }, -1, 1, VE }, + { "latency", "enables low latency mode", OFFSET(latency), AV_OPT_TYPE_BOOL,{.i64 = -1 }, -1, 1, VE }, - { "rc", "Set the rate control mode", OFFSET(rate_control_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN }, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR, VE, .unit = "rc" }, + { "rc", "Set the rate control mode", OFFSET(rate_control_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN }, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR, VE, .unit = "rc" }, { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, .unit = "rc" }, { "cbr", "Constant Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR }, 0, 0, VE, .unit = "rc" }, - { "vbr_peak", "Peak Contrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, + { "vbr_peak", "Peak Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, { "vbr_latency", "Latency Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, { "qvbr", "Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, { "hqvbr", "High Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, { "hqcbr", "High Quality Constant Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR }, 0, 0, VE, .unit = "rc" }, - { "qvbr_quality_level", "Sets the QVBR quality level", OFFSET(qvbr_quality_level), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, + { "qvbr_quality_level", "Sets the QVBR quality level", OFFSET(qvbr_quality_level), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, - { "header_insertion_mode", "Set header insertion mode", OFFSET(header_insertion_mode), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_IDR_ALIGNED, VE, .unit = "hdrmode" }, + { "header_insertion_mode", "Set header insertion mode", OFFSET(header_insertion_mode), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_IDR_ALIGNED, VE, .unit = "hdrmode" }, { "none", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_NONE }, 0, 0, VE, .unit = "hdrmode" }, { "gop", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_GOP_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, { "idr", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_IDR_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, + { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, MAX_LOOKAHEAD_DEPTH + 1, VE }, + { "high_motion_quality_boost_enable", "Enable High motion quality boost mode", OFFSET(hw_high_motion_quality_boost), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "gops_per_idr", "GOPs per IDR 0-no IDR will be inserted", OFFSET(gops_per_idr), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, VE }, { "preencode", "Enable preencode", OFFSET(preencode), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE}, { "vbaq", "Enable VBAQ", OFFSET(enable_vbaq), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE}, { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE}, { "filler_data", "Filler Data Enable", OFFSET(filler_data), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE}, - { "max_au_size", "Maximum Access Unit Size for rate control (in bits)", OFFSET(max_au_size), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, INT_MAX, VE}, + { "max_au_size", "Maximum Access Unit Size for rate control (in bits)", OFFSET(max_au_size), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, INT_MAX, VE}, { "min_qp_i", "min quantization parameter for I-frame", OFFSET(min_qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, { "max_qp_i", "max quantization parameter for I-frame", OFFSET(max_qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, { "min_qp_p", "min quantization parameter for P-frame", OFFSET(min_qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, @@ -100,31 +106,31 @@ static const AVOption options[] = { { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE }, { "me_quarter_pel", "Enable ME Quarter Pixel ", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE }, + { "forced_idr", "Force I frames to be IDR frames", OFFSET(forced_idr) ,AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) ,AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE }, - - { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, + { "smart_access_video", "Enable Smart Access Video to enhance performance by utilizing both APU and dGPU memory access", OFFSET(smart_access_video), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, //Pre Analysis options - { "preanalysis", "Enable preanalysis", OFFSET(preanalysis), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, + { "preanalysis", "Enable preanalysis", OFFSET(preanalysis), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, - { "pa_activity_type", "Set the type of activity analysis", OFFSET(pa_activity_type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_ACTIVITY_YUV, VE, .unit = "activity_type" }, + { "pa_activity_type", "Set the type of activity analysis", OFFSET(pa_activity_type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_ACTIVITY_YUV, VE, .unit = "activity_type" }, { "y", "activity y", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_ACTIVITY_Y }, 0, 0, VE, .unit = "activity_type" }, { "yuv", "activity yuv", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_ACTIVITY_YUV }, 0, 0, VE, .unit = "activity_type" }, - { "pa_scene_change_detection_enable", "Enable scene change detection", OFFSET(pa_scene_change_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, + { "pa_scene_change_detection_enable", "Enable scene change detection", OFFSET(pa_scene_change_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, - { "pa_scene_change_detection_sensitivity", "Set the sensitivity of scene change detection", OFFSET(pa_scene_change_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH, VE, .unit = "scene_change_sensitivity" }, - { "low", "low scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "medium", "medium scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "high", "high scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "pa_scene_change_detection_sensitivity", "Set the sensitivity of scene change detection", OFFSET(pa_scene_change_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH, VE, .unit = "scene_change_sensitivity" }, + { "low", "low scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "medium", "medium scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "high", "high scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "pa_static_scene_detection_enable", "Enable static scene detection", OFFSET(pa_static_scene_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, + { "pa_static_scene_detection_enable", "Enable static scene detection", OFFSET(pa_static_scene_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, - { "pa_static_scene_detection_sensitivity", "Set the sensitivity of static scene detection", OFFSET(pa_static_scene_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH, VE , .unit = "static_scene_sensitivity" }, - { "low", "low static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "medium", "medium static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "high", "high static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "pa_static_scene_detection_sensitivity", "Set the sensitivity of static scene detection", OFFSET(pa_static_scene_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH, VE , .unit = "static_scene_sensitivity" }, + { "low", "low static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "medium", "medium static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "high", "high static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, { "pa_initial_qp_after_scene_change", "The QP value that is used immediately after a scene change", OFFSET(pa_initial_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, { "pa_max_qp_before_force_skip", "The QP threshold to allow a skip frame", OFFSET(pa_max_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, @@ -157,7 +163,7 @@ static av_cold int amf_encode_init_hevc(AVCodecContext *avctx) { int ret = 0; AMF_RESULT res = AMF_OK; - AmfContext *ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; AMFVariantStruct var = {0}; amf_int64 profile = 0; amf_int64 profile_level = 0; @@ -166,20 +172,14 @@ static av_cold int amf_encode_init_hevc(AVCodecContext *avctx) AMFRate framerate; AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); int deblocking_filter = (avctx->flags & AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; - amf_int64 color_depth; + amf_int64 bit_depth; amf_int64 color_profile; enum AVPixelFormat pix_fmt; if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); } else { -FF_DISABLE_DEPRECATION_WARNINGS - framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ); -FF_ENABLE_DEPRECATION_WARNINGS + framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num); } if ((ret = ff_amf_encode_init(avctx)) < 0) @@ -241,35 +241,48 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ASPECT_RATIO, ratio); } - color_profile = ff_amf_get_color_profile(avctx); - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PROFILE, color_profile); - /// Color Range (Support for older Drivers) - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE, !!(avctx->color_range == AVCOL_RANGE_JPEG)); - /// Color Depth - color_depth = AMF_COLOR_BIT_DEPTH_8; + // Color bit depth pix_fmt = avctx->hw_frames_ctx ? ((AVHWFramesContext*)avctx->hw_frames_ctx->data)->sw_format : avctx->pix_fmt; - if (pix_fmt == AV_PIX_FMT_P010) { - color_depth = AMF_COLOR_BIT_DEPTH_10; + + bit_depth = ctx->bit_depth; + if(bit_depth == AMF_COLOR_BIT_DEPTH_UNDEFINED){ + bit_depth = pix_fmt == AV_PIX_FMT_P010 ? AMF_COLOR_BIT_DEPTH_10 : AMF_COLOR_BIT_DEPTH_8; } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_COLOR_BIT_DEPTH, color_depth); - if (color_depth == AMF_COLOR_BIT_DEPTH_8) { - /// Color Transfer Characteristics (AMF matches ISO/IEC) - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709); - /// Color Primaries (AMF matches ISO/IEC) - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT709); - } else { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE2084); - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT2020); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_COLOR_BIT_DEPTH, bit_depth); + + // Color profile + color_profile = ff_amf_get_color_profile(avctx); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PROFILE, color_profile); + + // Color Range (Support for older Drivers) + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE, !!(avctx->color_range == AVCOL_RANGE_JPEG)); + + // Color Transfer Characteristics (AMF matches ISO/IEC) + if(avctx->color_trc != AVCOL_TRC_UNSPECIFIED && (pix_fmt == AV_PIX_FMT_NV12 || pix_fmt == AV_PIX_FMT_P010)){ + // if input is YUV, color_trc is for VUI only - any value + // AMF VCN color conversion supports only specific output transfer characteristic SMPTE2084 for 10-bit and BT709 for 8-bit + // vpp_amf supports more + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_TRANSFER_CHARACTERISTIC, avctx->color_trc); + } + + // Color Primaries (AMF matches ISO/IEC) + if(avctx->color_primaries != AVCOL_PRI_UNSPECIFIED && (pix_fmt == AV_PIX_FMT_NV12 || pix_fmt == AV_PIX_FMT_P010)){ + // if input is YUV, color_primaries are for VUI only + // AMF VCN color conversion supports only specific output primaries BT2020 for 10-bit and BT709 for 8-bit + // vpp_amf supports more + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PRIMARIES, avctx->color_primaries); } // Picture control properties AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_NUM_GOPS_PER_IDR, ctx->gops_per_idr); - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_GOP_SIZE, avctx->gop_size); + if (avctx->gop_size != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_GOP_SIZE, avctx->gop_size); + } if (avctx->slices > 1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_SLICES_PER_FRAME, avctx->slices); } - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_DE_BLOCKING_FILTER_DISABLE, deblocking_filter); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_DE_BLOCKING_FILTER_DISABLE, !deblocking_filter); if (ctx->header_insertion_mode != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE, ctx->header_insertion_mode); @@ -292,6 +305,22 @@ FF_ENABLE_DEPRECATION_WARNINGS } } + if (ctx->smart_access_video != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENABLE_SMART_ACCESS_VIDEO, ctx->smart_access_video != 0); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "The Smart Access Video is not supported by AMF.\n"); + if (ctx->smart_access_video != 0) + return AVERROR(ENOSYS); + } else { + av_log(avctx, AV_LOG_INFO, "The Smart Access Video (%d) is set.\n", ctx->smart_access_video); + // Set low latency mode if Smart Access Video is enabled + if (ctx->smart_access_video != 0) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_LOWLATENCY_MODE, true); + av_log(avctx, AV_LOG_INFO, "The Smart Access Video set low latency mode.\n"); + } + } + } + // Pre-Pass, Pre-Analysis, Two-Pass if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PREENCODE_ENABLE, 0); @@ -369,7 +398,7 @@ FF_ENABLE_DEPRECATION_WARNINGS if (avctx->rc_max_rate) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PEAK_BITRATE, avctx->rc_max_rate); } else if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR) { - av_log(ctx, AV_LOG_WARNING, "rate control mode is PEAK_CONSTRAINED_VBR but rc_max_rate is not set\n"); + av_log(ctx, AV_LOG_DEBUG, "rate control mode is vbr_peak but max_rate is not set, default max_rate will be applied.\n"); } if (ctx->latency != -1) { @@ -429,6 +458,11 @@ FF_ENABLE_DEPRECATION_WARNINGS } } + // Wait inside QueryOutput() if supported by the driver + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QUERY_TIMEOUT, 1); + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QUERY_TIMEOUT, &var); + ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + // init encoder res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, avctx->height); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); @@ -511,6 +545,7 @@ static const FFCodecDefault defaults[] = { { "slices", "1" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "flags", "+loop"}, { NULL }, }; static const AVClass hevc_amf_class = { @@ -528,15 +563,15 @@ const FFCodec ff_hevc_amf_encoder = { .init = amf_encode_init_hevc, FF_CODEC_RECEIVE_PACKET_CB(ff_amf_receive_packet), .close = ff_amf_encode_close, - .priv_data_size = sizeof(AmfContext), + .priv_data_size = sizeof(AMFEncoderContext), .p.priv_class = &hevc_amf_class, .defaults = defaults, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = ff_amf_pix_fmts, - .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ + CODEC_PIXFMTS_ARRAY(ff_amf_pix_fmts), + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.wrapper_name = "amf", .hw_configs = ff_amfenc_hw_configs, }; diff --git a/libavcodec/amr_parser.c b/libavcodec/amr_parser.c index 9484d720e..5ee1829c4 100644 --- a/libavcodec/amr_parser.c +++ b/libavcodec/amr_parser.c @@ -28,6 +28,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "parser.h" +#include "parser_internal.h" static const uint8_t amrnb_packed_size[16] = { 13, 14, 16, 18, 20, 21, 27, 32, 6, 1, 1, 1, 1, 1, 1, 1 @@ -122,10 +123,10 @@ static int amr_parse(AVCodecParserContext *s1, return next; } -const AVCodecParser ff_amr_parser = { - .codec_ids = { AV_CODEC_ID_AMR_NB, AV_CODEC_ID_AMR_WB }, +const FFCodecParser ff_amr_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_AMR_NB, AV_CODEC_ID_AMR_WB), .priv_data_size = sizeof(AMRParseContext), - .parser_init = amr_parse_init, - .parser_parse = amr_parse, - .parser_close = ff_parse_close, + .init = amr_parse_init, + .parse = amr_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/amrnbdec.c b/libavcodec/amrnbdec.c index bfdcbba77..b8e340684 100644 --- a/libavcodec/amrnbdec.c +++ b/libavcodec/amrnbdec.c @@ -1104,6 +1104,4 @@ const FFCodec ff_amrnb_decoder = { .init = amrnb_decode_init, FF_CODEC_DECODE_CB(amrnb_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/amrwbdec.c b/libavcodec/amrwbdec.c index bb0864587..3557b4709 100644 --- a/libavcodec/amrwbdec.c +++ b/libavcodec/amrwbdec.c @@ -556,7 +556,8 @@ static void decode_fixed_vector(float *fixed_vector, const uint16_t *pulse_hi, ((int) pulse_hi[i] << 11), 4, 1); break; default: - av_assert2(0); + av_unreachable("Everything >= MODE_SID is impossible: MODE_SID is patchwelcome," + "> MODE_SID is invalid"); } memset(fixed_vector, 0, sizeof(float) * AMRWB_SFR_SIZE); @@ -1307,6 +1308,4 @@ const FFCodec ff_amrwb_decoder = { .init = amrwb_decode_init, FF_CODEC_DECODE_CB(amrwb_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/ansi.c b/libavcodec/ansi.c index d8d32bafb..bde9edbe6 100644 --- a/libavcodec/ansi.c +++ b/libavcodec/ansi.c @@ -82,7 +82,7 @@ static av_cold int decode_init(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_PAL8; /* defaults */ - s->font = avpriv_vga16_font; + s->font = avpriv_vga16_font_get(); s->font_height = 16; s->fg = DEFAULT_FG_COLOR; s->bg = DEFAULT_BG_COLOR; @@ -217,19 +217,19 @@ static int execute_code(AVCodecContext * avctx, int c) s->args[0] = DEFAULT_SCREEN_MODE; switch(s->args[0]) { case 0: case 1: case 4: case 5: case 13: case 19: //320x200 (25 rows) - s->font = avpriv_cga_font; + s->font = avpriv_cga_font_get(); s->font_height = 8; width = 40<<3; height = 25<<3; break; case 2: case 3: //640x400 (25 rows) - s->font = avpriv_vga16_font; + s->font = avpriv_vga16_font_get(); s->font_height = 16; width = 80<<3; height = 25<<4; break; case 6: case 14: //640x200 (25 rows) - s->font = avpriv_cga_font; + s->font = avpriv_cga_font_get(); s->font_height = 8; width = 80<<3; height = 25<<3; @@ -237,13 +237,13 @@ static int execute_code(AVCodecContext * avctx, int c) case 7: //set line wrapping break; case 15: case 16: //640x350 (43 rows) - s->font = avpriv_cga_font; + s->font = avpriv_cga_font_get(); s->font_height = 8; width = 80<<3; height = 43<<3; break; case 17: case 18: //640x480 (60 rows) - s->font = avpriv_cga_font; + s->font = avpriv_cga_font_get(); s->font_height = 8; width = 80<<3; height = 60<<4; @@ -262,11 +262,6 @@ static int execute_code(AVCodecContext * avctx, int c) AV_GET_BUFFER_FLAG_REF)) < 0) return ret; s->frame->pict_type = AV_PICTURE_TYPE_I; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif set_palette((uint32_t *)s->frame->data[1]); erase_screen(avctx); } else if (c == 'l') { @@ -375,11 +370,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, } s->frame->pict_type = AV_PICTURE_TYPE_I; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif set_palette((uint32_t *)s->frame->data[1]); if (!s->first_frame) { erase_screen(avctx); diff --git a/libavcodec/aom_film_grain.c b/libavcodec/aom_film_grain.c index 440e69331..bb60c5577 100644 --- a/libavcodec/aom_film_grain.c +++ b/libavcodec/aom_film_grain.c @@ -39,7 +39,7 @@ static inline int get_random_number(const int bits, unsigned *const state) { unsigned bit = ((r >> 0) ^ (r >> 1) ^ (r >> 3) ^ (r >> 12)) & 1; *state = (r >> 1) | (bit << 15); - return (*state >> (16 - bits)) & ((1 << bits) - 1); + return av_zero_extend(*state >> (16 - bits), bits); } static inline int round2(const int x, const uint64_t shift) { @@ -200,13 +200,13 @@ int ff_aom_parse_film_grain_sets(AVFilmGrainAFGS1Params *s, fgp->color_trc = get_bits(gb, 8); fgp->color_space = get_bits(gb, 8); fgp->color_range = get_bits1(gb) ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; - if (fgp->color_primaries > AVCOL_PRI_NB || + if (fgp->color_primaries >= AVCOL_PRI_NB || fgp->color_primaries == AVCOL_PRI_RESERVED || fgp->color_primaries == AVCOL_PRI_RESERVED0 || - fgp->color_trc > AVCOL_TRC_NB || + fgp->color_trc >= AVCOL_TRC_NB || fgp->color_trc == AVCOL_TRC_RESERVED || fgp->color_trc == AVCOL_TRC_RESERVED0 || - fgp->color_space > AVCOL_SPC_NB || + fgp->color_space >= AVCOL_SPC_NB || fgp->color_space == AVCOL_SPC_RESERVED) goto error; } @@ -363,17 +363,14 @@ int ff_aom_attach_film_grain_sets(const AVFilmGrainAFGS1Params *s, AVFrame *fram return 0; for (int i = 0; i < FF_ARRAY_ELEMS(s->sets); i++) { - AVBufferRef *buf; - if (!s->sets[i]) continue; - buf = av_buffer_ref(s->sets[i]); - if (!buf || !av_frame_new_side_data_from_buf(frame, - AV_FRAME_DATA_FILM_GRAIN_PARAMS, buf)) { - av_buffer_unref(&buf); + if (!av_frame_side_data_add(&frame->side_data, &frame->nb_side_data, + AV_FRAME_DATA_FILM_GRAIN_PARAMS, + (AVBufferRef**)&s->sets[i], + AV_FRAME_SIDE_DATA_FLAG_NEW_REF)) return AVERROR(ENOMEM); - } } return 0; diff --git a/libavcodec/apac.c b/libavcodec/apac.c index eb05d3863..00e48e763 100644 --- a/libavcodec/apac.c +++ b/libavcodec/apac.c @@ -269,12 +269,6 @@ const FFCodec ff_apac_decoder = { FF_CODEC_DECODE_CB(apac_decode), .close = apac_close, .p.capabilities = AV_CODEC_CAP_DELAY | -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/apedec.c b/libavcodec/apedec.c index d75a85f46..9a184f980 100644 --- a/libavcodec/apedec.c +++ b/libavcodec/apedec.c @@ -22,6 +22,7 @@ #include +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/crc.h" @@ -1729,7 +1730,7 @@ static int ape_decode_frame(AVCodecContext *avctx, AVFrame *frame, return !s->samples ? avpkt->size : 0; } -static void ape_flush(AVCodecContext *avctx) +static av_cold void ape_flush(AVCodecContext *avctx) { APEContext *s = avctx->priv_data; s->samples= 0; @@ -1759,17 +1760,9 @@ const FFCodec ff_ape_decoder = { .init = ape_decode_init, .close = ape_decode_close, FF_CODEC_DECODE_CB(ape_decode_frame), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DELAY | + .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .flush = ape_flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, .p.priv_class = &ape_decoder_class, }; diff --git a/libavcodec/aptx.h b/libavcodec/aptx.h index da0697e65..8e5bf31ab 100644 --- a/libavcodec/aptx.h +++ b/libavcodec/aptx.h @@ -108,7 +108,7 @@ typedef const struct { extern ConstTables ff_aptx_quant_tables[2][NB_SUBBANDS]; -/* Rounded right shift with optionnal clipping */ +/* Rounded right shift with optional clipping */ #define RSHIFT_SIZE(size) \ av_always_inline \ static int##size##_t rshift##size(int##size##_t value, int shift) \ diff --git a/libavcodec/aptxdec.c b/libavcodec/aptxdec.c index 4b083b655..35f50052a 100644 --- a/libavcodec/aptxdec.c +++ b/libavcodec/aptxdec.c @@ -183,9 +183,8 @@ const FFCodec ff_aptx_decoder = { .init = ff_aptx_init, FF_CODEC_DECODE_CB(aptx_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_STEREO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), }; #endif @@ -199,8 +198,7 @@ const FFCodec ff_aptx_hd_decoder = { .init = ff_aptx_init, FF_CODEC_DECODE_CB(aptx_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_STEREO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), }; #endif diff --git a/libavcodec/aptxenc.c b/libavcodec/aptxenc.c index 5e041b9a1..ab0245973 100644 --- a/libavcodec/aptxenc.c +++ b/libavcodec/aptxenc.c @@ -276,10 +276,9 @@ const FFCodec ff_aptx_encoder = { .init = aptx_encode_init, FF_CODEC_ENCODE_CB(aptx_encode_frame), .close = aptx_close, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_STEREO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]) {8000, 16000, 24000, 32000, 44100, 48000, 0}, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), + CODEC_SAMPLERATES(8000, 16000, 24000, 32000, 44100, 48000), }; #endif @@ -294,9 +293,8 @@ const FFCodec ff_aptx_hd_encoder = { .init = aptx_encode_init, FF_CODEC_ENCODE_CB(aptx_encode_frame), .close = aptx_close, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_STEREO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]) {8000, 16000, 24000, 32000, 44100, 48000, 0}, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), + CODEC_SAMPLERATES(8000, 16000, 24000, 32000, 44100, 48000), }; #endif diff --git a/libavcodec/apv.h b/libavcodec/apv.h new file mode 100644 index 000000000..14ca27bf3 --- /dev/null +++ b/libavcodec/apv.h @@ -0,0 +1,89 @@ +/* + * 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_APV_H +#define AVCODEC_APV_H + +// Signature value in APV bitstreams (section 5.3.1). +#define APV_SIGNATURE MKBETAG('a', 'P', 'v', '1') + +// PBU types (section 5.3.3). +enum { + APV_PBU_PRIMARY_FRAME = 1, + APV_PBU_NON_PRIMARY_FRAME = 2, + APV_PBU_PREVIEW_FRAME = 25, + APV_PBU_DEPTH_FRAME = 26, + APV_PBU_ALPHA_FRAME = 27, + APV_PBU_ACCESS_UNIT_INFORMATION = 65, + APV_PBU_METADATA = 66, + APV_PBU_FILLER = 67, +}; + +// Format parameters (section 4.2). +enum { + APV_MAX_NUM_COMP = 4, + APV_MB_WIDTH = 16, + APV_MB_HEIGHT = 16, + APV_TR_SIZE = 8, +}; + +// Chroma formats (section 4.2). +enum { + APV_CHROMA_FORMAT_400 = 0, + APV_CHROMA_FORMAT_422 = 2, + APV_CHROMA_FORMAT_444 = 3, + APV_CHROMA_FORMAT_4444 = 4, +}; + +// Coefficient limits (section 5.3.15). +enum { + APV_BLK_COEFFS = (APV_TR_SIZE * APV_TR_SIZE), + APV_MIN_TRANS_COEFF = -32768, + APV_MAX_TRANS_COEFF = 32767, +}; + +// Profiles (section 10.1.3). +enum { + APV_PROFILE_422_10 = 33, + APV_PROFILE_422_12 = 44, + APV_PROFILE_444_10 = 55, + APV_PROFILE_444_12 = 66, + APV_PROFILE_4444_10 = 77, + APV_PROFILE_4444_12 = 88, + APV_PROFILE_400_10 = 99, +}; + +// General level limits for tiles (section 10.1.4.1). +enum { + APV_MIN_TILE_WIDTH_IN_MBS = 16, + APV_MIN_TILE_HEIGHT_IN_MBS = 8, + APV_MAX_TILE_COLS = 20, + APV_MAX_TILE_ROWS = 20, + APV_MAX_TILE_COUNT = APV_MAX_TILE_COLS * APV_MAX_TILE_ROWS, +}; + +// Metadata types (section 10.3.1). +enum { + APV_METADATA_ITU_T_T35 = 4, + APV_METADATA_MDCV = 5, + APV_METADATA_CLL = 6, + APV_METADATA_FILLER = 10, + APV_METADATA_USER_DEFINED = 170, +}; + +#endif /* AVCODEC_APV_H */ diff --git a/libavcodec/apv_decode.c b/libavcodec/apv_decode.c new file mode 100644 index 000000000..dbe354a79 --- /dev/null +++ b/libavcodec/apv_decode.c @@ -0,0 +1,572 @@ +/* + * 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 "libavutil/attributes.h" +#include "libavutil/mastering_display_metadata.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixdesc.h" +#include "libavutil/thread.h" + +#include "apv.h" +#include "apv_decode.h" +#include "apv_dsp.h" +#include "avcodec.h" +#include "cbs.h" +#include "cbs_apv.h" +#include "codec_internal.h" +#include "decode.h" +#include "internal.h" +#include "thread.h" + + +typedef struct APVDerivedTileInfo { + uint8_t tile_cols; + uint8_t tile_rows; + uint16_t num_tiles; + // The spec uses an extra element on the end of these arrays + // not corresponding to any tile. + uint16_t col_starts[APV_MAX_TILE_COLS + 1]; + uint16_t row_starts[APV_MAX_TILE_ROWS + 1]; +} APVDerivedTileInfo; + +typedef struct APVDecodeContext { + CodedBitstreamContext *cbc; + APVDSPContext dsp; + + CodedBitstreamFragment au; + APVDerivedTileInfo tile_info; + + AVPacket *pkt; + AVFrame *output_frame; + atomic_int tile_errors; + + int nb_unit; + + uint8_t warned_additional_frames; + uint8_t warned_unknown_pbu_types; +} APVDecodeContext; + +static const enum AVPixelFormat apv_format_table[5][5] = { + { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16 }, + { 0 }, // 4:2:0 is not valid. + { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV422P16 }, + { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV444P16 }, + { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, 0 ,AV_PIX_FMT_YUVA444P16 }, +}; + +static APVVLCLUT decode_lut; + +static int apv_decode_check_format(AVCodecContext *avctx, + const APVRawFrameHeader *header) +{ + int err, bit_depth; + + avctx->profile = header->frame_info.profile_idc; + avctx->level = header->frame_info.level_idc; + + bit_depth = header->frame_info.bit_depth_minus8 + 8; + if (bit_depth < 8 || bit_depth > 16 || bit_depth % 2) { + avpriv_request_sample(avctx, "Bit depth %d", bit_depth); + return AVERROR_PATCHWELCOME; + } + avctx->pix_fmt = + apv_format_table[header->frame_info.chroma_format_idc][bit_depth - 4 >> 2]; + + if (!avctx->pix_fmt) { + avpriv_request_sample(avctx, "YUVA444P14"); + return AVERROR_PATCHWELCOME; + } + + err = ff_set_dimensions(avctx, + FFALIGN(header->frame_info.frame_width, 16), + FFALIGN(header->frame_info.frame_height, 16)); + if (err < 0) { + // Unsupported frame size. + return err; + } + avctx->width = header->frame_info.frame_width; + avctx->height = header->frame_info.frame_height; + + avctx->sample_aspect_ratio = (AVRational){ 1, 1 }; + + avctx->color_primaries = header->color_primaries; + avctx->color_trc = header->transfer_characteristics; + avctx->colorspace = header->matrix_coefficients; + avctx->color_range = header->full_range_flag ? AVCOL_RANGE_JPEG + : AVCOL_RANGE_MPEG; + avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; + + avctx->refs = 0; + avctx->has_b_frames = 0; + + return 0; +} + +static const CodedBitstreamUnitType apv_decompose_unit_types[] = { + APV_PBU_PRIMARY_FRAME, + APV_PBU_METADATA, +}; + +static AVOnce apv_entropy_once = AV_ONCE_INIT; + +static av_cold void apv_entropy_build_decode_lut(void) +{ + ff_apv_entropy_build_decode_lut(&decode_lut); +} + +static av_cold int apv_decode_init(AVCodecContext *avctx) +{ + APVDecodeContext *apv = avctx->priv_data; + int err; + + ff_thread_once(&apv_entropy_once, apv_entropy_build_decode_lut); + + err = ff_cbs_init(&apv->cbc, AV_CODEC_ID_APV, avctx); + if (err < 0) + return err; + + apv->cbc->decompose_unit_types = + apv_decompose_unit_types; + apv->cbc->nb_decompose_unit_types = + FF_ARRAY_ELEMS(apv_decompose_unit_types); + + // Extradata could be set here, but is ignored by the decoder. + + apv->pkt = avctx->internal->in_pkt; + ff_apv_dsp_init(&apv->dsp); + + atomic_init(&apv->tile_errors, 0); + + return 0; +} + +static av_cold void apv_decode_flush(AVCodecContext *avctx) +{ + APVDecodeContext *apv = avctx->priv_data; + + apv->nb_unit = 0; + av_packet_unref(apv->pkt); + ff_cbs_fragment_reset(&apv->au); + ff_cbs_flush(apv->cbc); +} + +static av_cold int apv_decode_close(AVCodecContext *avctx) +{ + APVDecodeContext *apv = avctx->priv_data; + + ff_cbs_fragment_free(&apv->au); + ff_cbs_close(&apv->cbc); + + return 0; +} + +static int apv_decode_block(AVCodecContext *avctx, + void *output, + ptrdiff_t pitch, + GetBitContext *gbc, + APVEntropyState *entropy_state, + int bit_depth, + int qp_shift, + const uint16_t *qmatrix) +{ + APVDecodeContext *apv = avctx->priv_data; + int err; + + LOCAL_ALIGNED_32(int16_t, coeff, [64]); + memset(coeff, 0, 64 * sizeof(int16_t)); + + err = ff_apv_entropy_decode_block(coeff, gbc, entropy_state); + if (err < 0) + return err; + + apv->dsp.decode_transquant(output, pitch, + coeff, qmatrix, + bit_depth, qp_shift); + + return 0; +} + +static int apv_decode_tile_component(AVCodecContext *avctx, void *data, + int job, int thread) +{ + APVRawFrame *input = data; + APVDecodeContext *apv = avctx->priv_data; + const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data; + const APVDerivedTileInfo *tile_info = &apv->tile_info; + + int tile_index = job / apv_cbc->num_comp; + int comp_index = job % apv_cbc->num_comp; + + const AVPixFmtDescriptor *pix_fmt_desc = + av_pix_fmt_desc_get(avctx->pix_fmt); + + int sub_w_shift = comp_index == 0 ? 0 : pix_fmt_desc->log2_chroma_w; + int sub_h_shift = comp_index == 0 ? 0 : pix_fmt_desc->log2_chroma_h; + + APVRawTile *tile = &input->tile[tile_index]; + + int tile_y = tile_index / tile_info->tile_cols; + int tile_x = tile_index % tile_info->tile_cols; + + int tile_start_x = tile_info->col_starts[tile_x]; + int tile_start_y = tile_info->row_starts[tile_y]; + + int tile_width = tile_info->col_starts[tile_x + 1] - tile_start_x; + int tile_height = tile_info->row_starts[tile_y + 1] - tile_start_y; + + int tile_mb_width = tile_width / APV_MB_WIDTH; + int tile_mb_height = tile_height / APV_MB_HEIGHT; + + int blk_mb_width = 2 >> sub_w_shift; + int blk_mb_height = 2 >> sub_h_shift; + + int bit_depth; + int qp_shift; + LOCAL_ALIGNED_32(uint16_t, qmatrix_scaled, [64]); + + GetBitContext gbc; + + APVEntropyState entropy_state = { + .log_ctx = avctx, + .decode_lut = &decode_lut, + .prev_dc = 0, + .prev_k_dc = 5, + .prev_k_level = 0, + }; + + int err; + + err = init_get_bits8(&gbc, tile->tile_data[comp_index], + tile->tile_header.tile_data_size[comp_index]); + if (err < 0) + goto fail; + + // Combine the bitstream quantisation matrix with the qp scaling + // in advance. (Including qp_shift as well would overflow 16 bits.) + // Fix the row ordering at the same time. + { + static const uint8_t apv_level_scale[6] = { 40, 45, 51, 57, 64, 71 }; + int qp = tile->tile_header.tile_qp[comp_index]; + int level_scale = apv_level_scale[qp % 6]; + + bit_depth = apv_cbc->bit_depth; + qp_shift = qp / 6; + + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) + qmatrix_scaled[y * 8 + x] = level_scale * + input->frame_header.quantization_matrix.q_matrix[comp_index][x][y]; + } + } + + for (int mb_y = 0; mb_y < tile_mb_height; mb_y++) { + for (int mb_x = 0; mb_x < tile_mb_width; mb_x++) { + for (int blk_y = 0; blk_y < blk_mb_height; blk_y++) { + for (int blk_x = 0; blk_x < blk_mb_width; blk_x++) { + int frame_y = (tile_start_y + + APV_MB_HEIGHT * mb_y + + APV_TR_SIZE * blk_y) >> sub_h_shift; + int frame_x = (tile_start_x + + APV_MB_WIDTH * mb_x + + APV_TR_SIZE * blk_x) >> sub_w_shift; + + ptrdiff_t frame_pitch = apv->output_frame->linesize[comp_index]; + uint8_t *block_start = apv->output_frame->data[comp_index] + + frame_y * frame_pitch + 2 * frame_x; + + err = apv_decode_block(avctx, + block_start, frame_pitch, + &gbc, &entropy_state, + bit_depth, + qp_shift, + qmatrix_scaled); + if (err < 0) { + // Error in block decode means entropy desync, + // so this is not recoverable. + goto fail; + } + } + } + } + } + + av_log(avctx, AV_LOG_DEBUG, + "Decoded tile %d component %d: %dx%d MBs starting at (%d,%d)\n", + tile_index, comp_index, tile_mb_width, tile_mb_height, + tile_start_x, tile_start_y); + + return 0; + +fail: + av_log(avctx, AV_LOG_VERBOSE, + "Decode error in tile %d component %d.\n", + tile_index, comp_index); + atomic_fetch_add_explicit(&apv->tile_errors, 1, memory_order_relaxed); + return err; +} + +static void apv_derive_tile_info(APVDerivedTileInfo *ti, + const APVRawFrameHeader *fh) +{ + int frame_width_in_mbs = (fh->frame_info.frame_width + (APV_MB_WIDTH - 1)) >> 4; + int frame_height_in_mbs = (fh->frame_info.frame_height + (APV_MB_HEIGHT - 1)) >> 4; + int start_mb, i; + + start_mb = 0; + for (i = 0; start_mb < frame_width_in_mbs; i++) { + ti->col_starts[i] = start_mb * APV_MB_WIDTH; + start_mb += fh->tile_info.tile_width_in_mbs; + } + ti->col_starts[i] = frame_width_in_mbs * APV_MB_WIDTH; + ti->tile_cols = i; + + start_mb = 0; + for (i = 0; start_mb < frame_height_in_mbs; i++) { + ti->row_starts[i] = start_mb * APV_MB_HEIGHT; + start_mb += fh->tile_info.tile_height_in_mbs; + } + ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT; + ti->tile_rows = i; + + ti->num_tiles = ti->tile_cols * ti->tile_rows; +} + +static int apv_decode(AVCodecContext *avctx, AVFrame *output, + APVRawFrame *input) +{ + APVDecodeContext *apv = avctx->priv_data; + const AVPixFmtDescriptor *desc = NULL; + APVDerivedTileInfo *tile_info = &apv->tile_info; + int err, job_count; + + err = apv_decode_check_format(avctx, &input->frame_header); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Unsupported format parameters.\n"); + return err; + } + + if (avctx->skip_frame == AVDISCARD_ALL) + return 0; + + desc = av_pix_fmt_desc_get(avctx->pix_fmt); + av_assert0(desc); + + err = ff_thread_get_buffer(avctx, output, 0); + if (err < 0) + return err; + + apv->output_frame = output; + atomic_store_explicit(&apv->tile_errors, 0, memory_order_relaxed); + + apv_derive_tile_info(tile_info, &input->frame_header); + + // Each component within a tile is independent of every other, + // so we can decode all in parallel. + job_count = tile_info->num_tiles * desc->nb_components; + + avctx->execute2(avctx, apv_decode_tile_component, + input, NULL, job_count); + + err = atomic_load_explicit(&apv->tile_errors, memory_order_relaxed); + if (err > 0) { + av_log(avctx, AV_LOG_ERROR, + "Decode errors in %d tile components.\n", err); + if (avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) { + // Output the frame anyway. + output->flags |= AV_FRAME_FLAG_CORRUPT; + } else { + return AVERROR_INVALIDDATA; + } + } + + return 0; +} + +static int apv_decode_metadata(AVCodecContext *avctx, AVFrame *frame, + const APVRawMetadata *md) +{ + int err; + + for (int i = 0; i < md->metadata_count; i++) { + const APVRawMetadataPayload *pl = &md->payloads[i]; + + switch (pl->payload_type) { + case APV_METADATA_MDCV: + { + const APVRawMetadataMDCV *mdcv = &pl->mdcv; + AVMasteringDisplayMetadata *mdm; + + err = ff_decode_mastering_display_new(avctx, frame, &mdm); + if (err < 0) + return err; + + if (mdm) { + for (int j = 0; j < 3; j++) { + mdm->display_primaries[j][0] = + av_make_q(mdcv->primary_chromaticity_x[j], 1 << 16); + mdm->display_primaries[j][1] = + av_make_q(mdcv->primary_chromaticity_y[j], 1 << 16); + } + + mdm->white_point[0] = + av_make_q(mdcv->white_point_chromaticity_x, 1 << 16); + mdm->white_point[1] = + av_make_q(mdcv->white_point_chromaticity_y, 1 << 16); + + mdm->max_luminance = + av_make_q(mdcv->max_mastering_luminance, 1 << 8); + mdm->min_luminance = + av_make_q(mdcv->min_mastering_luminance, 1 << 14); + + mdm->has_primaries = 1; + mdm->has_luminance = 1; + } + } + break; + case APV_METADATA_CLL: + { + const APVRawMetadataCLL *cll = &pl->cll; + AVContentLightMetadata *clm; + + err = ff_decode_content_light_new(avctx, frame, &clm); + if (err < 0) + return err; + + if (clm) { + clm->MaxCLL = cll->max_cll; + clm->MaxFALL = cll->max_fall; + } + } + break; + default: + // Ignore other types of metadata. + break; + } + } + + return 0; +} + +static int apv_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) +{ + APVDecodeContext *apv = avctx->priv_data; + CodedBitstreamFragment *au = &apv->au; + int i, err; + + for (i = apv->nb_unit; i < au->nb_units; i++) { + CodedBitstreamUnit *pbu = &au->units[i]; + + switch (pbu->type) { + case APV_PBU_PRIMARY_FRAME: + err = apv_decode(avctx, frame, pbu->content); + i++; + goto end; + case APV_PBU_METADATA: + apv_decode_metadata(avctx, frame, pbu->content); + break; + case APV_PBU_NON_PRIMARY_FRAME: + case APV_PBU_PREVIEW_FRAME: + case APV_PBU_DEPTH_FRAME: + case APV_PBU_ALPHA_FRAME: + if (!avctx->internal->is_copy && + !apv->warned_additional_frames) { + av_log(avctx, AV_LOG_WARNING, + "Stream contains additional non-primary frames " + "which will be ignored by the decoder.\n"); + apv->warned_additional_frames = 1; + } + break; + case APV_PBU_ACCESS_UNIT_INFORMATION: + case APV_PBU_FILLER: + // Not relevant to the decoder. + break; + default: + if (!avctx->internal->is_copy && + !apv->warned_unknown_pbu_types) { + av_log(avctx, AV_LOG_WARNING, + "Stream contains PBUs with unknown types " + "which will be ignored by the decoder.\n"); + apv->warned_unknown_pbu_types = 1; + } + break; + } + } + + err = AVERROR(EAGAIN); +end: + av_assert0(i <= apv->au.nb_units); + apv->nb_unit = i; + + if ((err < 0 && err != AVERROR(EAGAIN)) || apv->au.nb_units == i) { + av_packet_unref(apv->pkt); + ff_cbs_fragment_reset(&apv->au); + apv->nb_unit = 0; + } + if (!err && !frame->buf[0]) + err = AVERROR(EAGAIN); + + return err; +} + +static int apv_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + APVDecodeContext *apv = avctx->priv_data; + int err; + + do { + if (!apv->au.nb_units) { + err = ff_decode_get_packet(avctx, apv->pkt); + if (err < 0) + return err; + + err = ff_cbs_read_packet(apv->cbc, &apv->au, apv->pkt); + if (err < 0) { + ff_cbs_fragment_reset(&apv->au); + av_packet_unref(apv->pkt); + av_log(avctx, AV_LOG_ERROR, "Failed to read packet.\n"); + return err; + } + + apv->nb_unit = 0; + av_log(avctx, AV_LOG_DEBUG, "Total PBUs on this packet: %d.\n", + apv->au.nb_units); + } + + err = apv_receive_frame_internal(avctx, frame); + } while (err == AVERROR(EAGAIN)); + + return err; +} + +const FFCodec ff_apv_decoder = { + .p.name = "apv", + CODEC_LONG_NAME("Advanced Professional Video"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_APV, + .priv_data_size = sizeof(APVDecodeContext), + .init = apv_decode_init, + .flush = apv_decode_flush, + .close = apv_decode_close, + FF_CODEC_RECEIVE_FRAME_CB(apv_receive_frame), + .p.capabilities = AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_SLICE_THREADS | + AV_CODEC_CAP_FRAME_THREADS, + .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, +}; diff --git a/libavcodec/apv_decode.h b/libavcodec/apv_decode.h new file mode 100644 index 000000000..5671d8955 --- /dev/null +++ b/libavcodec/apv_decode.h @@ -0,0 +1,101 @@ +/* + * 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_APV_DECODE_H +#define AVCODEC_APV_DECODE_H + +#include + +#include "apv.h" +#include "avcodec.h" +#include "get_bits.h" + + +// Number of bits in the entropy look-up tables. +// It may be desirable to tune this per-architecture, as a larger LUT +// trades greater memory use for fewer instructions. +// (N bits -> 24*2^N bytes of tables; 9 -> 12KB of tables.) +#define APV_VLC_LUT_BITS 9 +#define APV_VLC_LUT_SIZE (1 << APV_VLC_LUT_BITS) + +typedef struct APVSingleVLCLUTEntry { + uint16_t result; // Return value if not reading more. + uint8_t consume; // Number of bits to consume. + uint8_t more; // Whether to read additional bits. +} APVSingleVLCLUTEntry; + +typedef struct APVMultiVLCLUTEntry { + // Number of symbols this bit stream resolves to. + uint8_t count; + // k_run after decoding all symbols. + uint8_t k_run : 2; + // k_level after decoding the first level symbol. + uint8_t k_level_0 : 3; + // k_level after decoding all symbols. + uint8_t k_level_1 : 3; + // Run output values. + uint8_t run[2]; + // Level output values. + int16_t level[2]; + // Bit index of the end of each code. + uint8_t offset[4]; +} APVMultiVLCLUTEntry; + +typedef struct APVVLCLUT { + // Single-symbol LUT for VLCs. + // Applies to all coefficients, but used only for DC coefficients + // in the decoder. + APVSingleVLCLUTEntry single_lut[6][APV_VLC_LUT_SIZE]; + // Multi-symbol LUT for run/level combinations, decoding up to four + // symbols per step. Comes in two versions, which to use depends on + // whether the next symbol is a run or a level. + APVMultiVLCLUTEntry run_first_lut[3][5][APV_VLC_LUT_SIZE]; + APVMultiVLCLUTEntry level_first_lut[3][5][APV_VLC_LUT_SIZE]; +} APVVLCLUT; + +typedef struct APVEntropyState { + void *log_ctx; + + const APVVLCLUT *decode_lut; + + // Previous DC level value. + int16_t prev_dc; + // k parameter implied by the previous DC level value. + uint8_t prev_k_dc; + // k parameter implied by the previous first AC level value. + uint8_t prev_k_level; +} APVEntropyState; + + +/** + * Build the decoder VLC look-up tables. + */ +void ff_apv_entropy_build_decode_lut(APVVLCLUT *decode_lut); + +/** + * Entropy decode a single 8x8 block to coefficients. + * + * Outputs nonzero coefficients only to the block row-major order + * (dezigzag is applied within the function). The output block + * must have been filled with zeroes before calling this function. + */ +int ff_apv_entropy_decode_block(int16_t *restrict coeff, + GetBitContext *restrict gbc, + APVEntropyState *restrict state); + +#endif /* AVCODEC_APV_DECODE_H */ diff --git a/libavcodec/apv_dsp.c b/libavcodec/apv_dsp.c new file mode 100644 index 000000000..982ec3691 --- /dev/null +++ b/libavcodec/apv_dsp.c @@ -0,0 +1,140 @@ +/* + * 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 "config.h" +#include "libavutil/attributes.h" +#include "libavutil/common.h" + +#include "apv.h" +#include "apv_dsp.h" + + +static const int8_t apv_trans_matrix[8][8] = { + { 64, 64, 64, 64, 64, 64, 64, 64 }, + { 89, 75, 50, 18, -18, -50, -75, -89 }, + { 84, 35, -35, -84, -84, -35, 35, 84 }, + { 75, -18, -89, -50, 50, 89, 18, -75 }, + { 64, -64, -64, 64, 64, -64, -64, 64 }, + { 50, -89, 18, 75, -75, -18, 89, -50 }, + { 35, -84, 84, -35, -35, 84, -84, 35 }, + { 18, -50, 75, -89, 89, -75, 50, -18 }, +}; + +static void apv_decode_transquant_c(void *output, + ptrdiff_t pitch, + const int16_t *input_flat, + const int16_t *qmatrix_flat, + int bit_depth, + int qp_shift) +{ + const int16_t (*input)[8] = (const int16_t(*)[8])input_flat; + const int16_t (*qmatrix)[8] = (const int16_t(*)[8])qmatrix_flat; + + int16_t scaled_coeff[8][8]; + int32_t recon_sample[8][8]; + + // Dequant. + { + // Note that level_scale was already combined into qmatrix + // before we got here. + int bd_shift = bit_depth + 3 - 5; + + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) { + int coeff = ((int)(input[y][x] * qmatrix[y][x] * (1U << qp_shift) + + (1 << (bd_shift - 1)))) >> bd_shift; + + scaled_coeff[y][x] = + av_clip(coeff, APV_MIN_TRANS_COEFF, + APV_MAX_TRANS_COEFF); + } + } + } + + // Transform. + { + int32_t tmp[8][8]; + + // Vertical transform of columns. + for (int x = 0; x < 8; x++) { + for (int i = 0; i < 8; i++) { + int sum = 0; + for (int j = 0; j < 8; j++) + sum += apv_trans_matrix[j][i] * scaled_coeff[j][x]; + tmp[i][x] = sum; + } + } + + // Renormalise. + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) + tmp[y][x] = (tmp[y][x] + 64) >> 7; + } + + // Horizontal transform of rows. + for (int y = 0; y < 8; y++) { + for (int i = 0; i < 8; i++) { + int sum = 0; + for (int j = 0; j < 8; j++) + sum += apv_trans_matrix[j][i] * tmp[y][j]; + recon_sample[y][i] = sum; + } + } + } + + // Output. + if (bit_depth == 8) { + uint8_t *ptr = output; + int bd_shift = 20 - bit_depth; + + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) { + int sample = ((recon_sample[y][x] + + (1 << (bd_shift - 1))) >> bd_shift) + + (1 << (bit_depth - 1)); + ptr[x] = av_clip_uintp2(sample, bit_depth); + } + ptr += pitch; + } + } else { + uint16_t *ptr = output; + int bd_shift = 20 - bit_depth; + pitch /= 2; // Pitch was in bytes, 2 bytes per sample. + + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) { + int sample = ((recon_sample[y][x] + + (1 << (bd_shift - 1))) >> bd_shift) + + (1 << (bit_depth - 1)); + ptr[x] = av_clip_uintp2(sample, bit_depth); + } + ptr += pitch; + } + } +} + +av_cold void ff_apv_dsp_init(APVDSPContext *dsp) +{ + dsp->decode_transquant = apv_decode_transquant_c; + +#if ARCH_X86_64 && HAVE_X86ASM + ff_apv_dsp_init_x86_64(dsp); +#endif +} diff --git a/libavutil/dict_internal.h b/libavcodec/apv_dsp.h similarity index 59% rename from libavutil/dict_internal.h rename to libavcodec/apv_dsp.h index 6d5b0dc2b..c63d6a88e 100644 --- a/libavutil/dict_internal.h +++ b/libavcodec/apv_dsp.h @@ -16,22 +16,24 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVUTIL_DICT_INTERNAL_H -#define AVUTIL_DICT_INTERNAL_H +#ifndef AVCODEC_APV_DSP_H +#define AVCODEC_APV_DSP_H +#include #include -#include "dict.h" -/** - * Set a dictionary value to an ISO-8601 compliant timestamp string. - * - * @param dict pointer to a pointer to a dictionary struct. If *dict is NULL - * a dictionary struct is allocated and put in *dict. - * @param key metadata key - * @param timestamp unix timestamp in microseconds - * @return <0 on error - */ -int avpriv_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestamp); +typedef struct APVDSPContext { + void (*decode_transquant)(void *output, + ptrdiff_t pitch, + const int16_t *input, + const int16_t *qmatrix, + int bit_depth, + int qp_shift); +} APVDSPContext; -#endif /* AVUTIL_DICT_INTERNAL_H */ +void ff_apv_dsp_init(APVDSPContext *dsp); + +void ff_apv_dsp_init_x86_64(APVDSPContext *dsp); + +#endif /* AVCODEC_APV_DSP_H */ diff --git a/libavcodec/apv_entropy.c b/libavcodec/apv_entropy.c new file mode 100644 index 000000000..30f31a14f --- /dev/null +++ b/libavcodec/apv_entropy.c @@ -0,0 +1,614 @@ +/* + * 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 "apv.h" +#include "apv_decode.h" + +#include "put_bits.h" + + +av_always_inline +static unsigned int apv_read_vlc(GetBitContext *restrict gbc, int k_param, + const APVVLCLUT *restrict lut) +{ + unsigned int next_bits; + const APVSingleVLCLUTEntry *ent; + + next_bits = show_bits(gbc, APV_VLC_LUT_BITS); + ent = &lut->single_lut[k_param][next_bits]; + + if (ent->more) { + unsigned int leading_zeroes; + + skip_bits(gbc, ent->consume); + + next_bits = show_bits(gbc, 16); + leading_zeroes = 15 - av_log2(next_bits); + + if (leading_zeroes == 0) { + // This can't happen mid-stream because the lookup would + // have resolved a leading one into a shorter code, but it + // can happen if we are hitting the end of the buffer. + // Return an invalid code to propagate as an error. + return APV_MAX_TRANS_COEFF + 1; + } + + skip_bits(gbc, leading_zeroes + 1); + + return (2 << k_param) + + ((1 << leading_zeroes) - 1) * (1 << k_param) + + get_bits(gbc, leading_zeroes + k_param); + } else { + skip_bits(gbc, ent->consume); + return ent->result; + } +} + +void ff_apv_entropy_build_decode_lut(APVVLCLUT *decode_lut) +{ + const int code_len = APV_VLC_LUT_BITS; + const int lut_size = APV_VLC_LUT_SIZE; + + // Build the single-symbol VLC table. + for (int k = 0; k <= 5; k++) { + for (unsigned int code = 0; code < lut_size; code++) { + APVSingleVLCLUTEntry *ent = &decode_lut->single_lut[k][code]; + unsigned int first_bit = code & (1 << code_len - 1); + unsigned int remaining_bits = code ^ first_bit; + + if (first_bit) { + ent->consume = 1 + k; + ent->result = remaining_bits >> (code_len - k - 1); + ent->more = 0; + } else { + unsigned int second_bit = code & (1 << code_len - 2); + remaining_bits ^= second_bit; + + if (second_bit) { + unsigned int bits_left = code_len - 2; + unsigned int first_set = bits_left - av_log2(remaining_bits); + unsigned int last_bits = first_set - 1 + k; + + if (first_set + last_bits <= bits_left) { + // Whole code fits here. + ent->consume = 2 + first_set + last_bits; + ent->result = ((2 << k) + + (((1 << first_set - 1) - 1) << k) + + ((code >> bits_left - first_set - last_bits) & (1 << last_bits) - 1)); + ent->more = 0; + } else { + // Need to read more, collapse to default. + ent->consume = 2; + ent->more = 1; + } + } else { + ent->consume = 2 + k; + ent->result = (1 << k) + (remaining_bits >> (code_len - k - 2)); + ent->more = 0; + } + } + } + } + + // Build the multi-symbol VLC table. + for (int start_run = 0; start_run <= 2; start_run++) { + for (int start_level = 0; start_level <= 4; start_level++) { + for (unsigned int code = 0; code < lut_size; code++) { + APVMultiVLCLUTEntry *ent; + int k_run, k_level; + GetBitContext gbc; + PutBitContext pbc; + uint8_t buffer[16]; + uint8_t run_first_buffer[16]; + uint8_t level_first_buffer[16]; + + memset(buffer, 0, sizeof(buffer)); + init_put_bits(&pbc, buffer, sizeof(buffer)); + put_bits(&pbc, APV_VLC_LUT_BITS, code); + flush_put_bits(&pbc); + + memcpy(run_first_buffer, buffer, sizeof(buffer)); + memcpy(level_first_buffer, buffer, sizeof(buffer)); + + k_run = start_run; + k_level = start_level; + + ent = &decode_lut->run_first_lut[k_run][k_level][code]; + memset(ent, 0, sizeof(*ent)); + init_get_bits8(&gbc, run_first_buffer, sizeof(run_first_buffer)); + + ent->count = 0; + for (int i = 0; i <= 1; i++) { + int value, sign, pos; + + value = apv_read_vlc(&gbc, k_run, decode_lut); + pos = get_bits_count(&gbc); + if (pos > APV_VLC_LUT_BITS) + break; + ent->run[i] = value; + ent->offset[ent->count] = pos; + ++ent->count; + k_run = FFMIN(value >> 2, 2); + + value = apv_read_vlc(&gbc, k_level, decode_lut); + sign = get_bits1(&gbc); + pos = get_bits_count(&gbc); + if (pos > APV_VLC_LUT_BITS) + break; + ++value; + ent->level[i] = sign ? -value : value; + ent->offset[ent->count] = pos; + ++ent->count; + k_level = FFMIN(value >> 2, 4); + if (i == 0) + ent->k_level_0 = k_level; + } + if (ent->count > 0 && ent->count < 4) + ent->offset[3] = ent->offset[ent->count - 1]; + ent->k_run = k_run; + ent->k_level_1 = k_level; + + k_run = start_run; + k_level = start_level; + + ent = &decode_lut->level_first_lut[k_run][k_level][code]; + memset(ent, 0, sizeof(*ent)); + init_get_bits8(&gbc, level_first_buffer, sizeof(level_first_buffer)); + + ent->count = 0; + for (int i = 0; i <= 1; i++) { + int value, sign, pos; + + value = apv_read_vlc(&gbc, k_level, decode_lut); + sign = get_bits1(&gbc); + pos = get_bits_count(&gbc); + if (pos > APV_VLC_LUT_BITS) + break; + ++value; + ent->level[i] = sign ? -value : value; + ent->offset[ent->count] = pos; + ++ent->count; + k_level = FFMIN(value >> 2, 4); + if (i == 0) + ent->k_level_0 = k_level; + + value = apv_read_vlc(&gbc, k_run, decode_lut); + pos = get_bits_count(&gbc); + if (pos > APV_VLC_LUT_BITS) + break; + ent->run[i] = value; + ent->offset[ent->count] = pos; + ++ent->count; + k_run = FFMIN(value >> 2, 2); + } + if (ent->count > 0 && ent->count < 4) + ent->offset[3] = ent->offset[ent->count - 1]; + ent->k_run = k_run; + ent->k_level_1 = k_level; + } + } + } +} + +int ff_apv_entropy_decode_block(int16_t *restrict coeff, + GetBitContext *restrict gbc, + APVEntropyState *restrict state) +{ + const APVVLCLUT *lut = state->decode_lut; + int scan_pos; + int k_dc = state->prev_k_dc; + int k_run, k_level; + uint32_t next_bits, lut_bits; + const APVMultiVLCLUTEntry *ent; + + // DC coefficient is likely to be large and cannot be usefully + // combined with other read steps, so extract it separately. + { + int dc_coeff, abs_diff, sign; + + abs_diff = apv_read_vlc(gbc, k_dc, lut); + + if (abs_diff) { + sign = get_bits1(gbc); + if (sign) + dc_coeff = state->prev_dc - abs_diff; + else + dc_coeff = state->prev_dc + abs_diff; + } else { + dc_coeff = state->prev_dc; + } + + + if (dc_coeff < APV_MIN_TRANS_COEFF || + dc_coeff > APV_MAX_TRANS_COEFF) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range DC coefficient value: %d.\n", + dc_coeff); + return AVERROR_INVALIDDATA; + } + + coeff[0] = dc_coeff; + + state->prev_dc = dc_coeff; + state->prev_k_dc = FFMIN(abs_diff >> 1, 5); + } + + // Repeatedly read 18 bits, look up the first half of them in either + // the run-first or the level-first table. If the next code is too + // long the 18 bits will allow resolving a run code (up to 63) + // without reading any more bits, and will allow the exact length + // of a level code to be determined. (Note that reusing the + // single-symbol LUT is never useful here as the multisymbol lookup + // has already determined that the code is too long.) + + // Run a single iteration of the run-first LUT to start, then a + // single iteration of the level-first LUT if that only read a + // single code. This avoids dealing with the first-AC logic inside + // the normal code lookup sequence. + + k_level = state->prev_k_level; + { + next_bits = show_bits(gbc, 18); + lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS); + + ent = &lut->run_first_lut[0][k_level][lut_bits]; + + if (ent->count == 0) { + // One long code. + uint32_t bits, low_bits; + unsigned int leading_zeroes, low_bit_count, low_bit_shift; + int run; + + // Remove the prefix bits. + bits = next_bits & 0xffff; + // Determine code length. + leading_zeroes = 15 - av_log2(bits); + if (leading_zeroes >= 6) { + // 6 zeroes implies run > 64, which is always invalid. + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range run value: %d leading zeroes.\n", + leading_zeroes); + return AVERROR_INVALIDDATA; + } + // Extract the low bits. + low_bit_count = leading_zeroes; + low_bit_shift = 16 - (1 + 2 * leading_zeroes); + low_bits = av_zero_extend(bits >> low_bit_shift, low_bit_count); + // Construct run code. + run = 2 + ((1 << leading_zeroes) - 1) + low_bits; + // Skip over the bits just used. + skip_bits(gbc, 2 + leading_zeroes + 1 + low_bit_count); + + scan_pos = run + 1; + if (scan_pos >= 64) + goto end_of_block; + k_run = FFMIN(run >> 2, 2); + goto first_level; + } else { + // One or more short codes starting with a run; if there is + // a level code then the length needs to be saved for the + // next block. + + scan_pos = ent->run[0] + 1; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[0]); + goto end_of_block; + } + if (ent->count > 1) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[0]; + ++scan_pos; + state->prev_k_level = ent->k_level_0; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[1]); + goto end_of_block; + } + } + if (ent->count > 2) { + scan_pos += ent->run[1]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[2]); + goto end_of_block; + } + } + if (ent->count > 3) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[1]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[3]); + goto end_of_block; + } + } + skip_bits(gbc, ent->offset[3]); + k_run = ent->k_run; + k_level = ent->k_level_1; + if (ent->count == 1) + goto first_level; + else if (ent->count & 1) + goto next_is_level; + else + goto next_is_run; + } + } + + first_level: { + next_bits = show_bits(gbc, 18); + lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS); + + ent = &lut->level_first_lut[k_run][k_level][lut_bits]; + + if (ent->count == 0) { + // One long code. + uint32_t bits; + unsigned int leading_zeroes; + int level, abs_level, sign; + + // Remove the prefix bits. + bits = next_bits & 0xffff; + // Determine code length. + leading_zeroes = 15 - av_log2(bits); + // Skip the prefix and length bits. + skip_bits(gbc, 2 + leading_zeroes + 1); + // Read the rest of the code and construct the level. + // Include the + 1 offset for nonzero value here. + abs_level = (2 << k_level) + + ((1 << leading_zeroes) - 1) * (1 << k_level) + + get_bits(gbc, leading_zeroes + k_level) + 1; + + sign = get_bits(gbc, 1); + if (sign) + level = -abs_level; + else + level = abs_level; + + // Check range (not checked in any other case, only a long + // code can be out of range). + if (level < APV_MIN_TRANS_COEFF || + level > APV_MAX_TRANS_COEFF) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range AC coefficient value at %d: %d.\n", + scan_pos, level); + return AVERROR_INVALIDDATA; + } + coeff[ff_zigzag_direct[scan_pos]] = level; + ++scan_pos; + k_level = FFMIN(abs_level >> 2, 4); + state->prev_k_level = k_level; + if (scan_pos >= 64) + goto end_of_block; + goto next_is_run; + + } else { + // One or more short codes. + + coeff[ff_zigzag_direct[scan_pos]] = ent->level[0]; + ++scan_pos; + state->prev_k_level = ent->k_level_0; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[0]); + goto end_of_block; + } + if (ent->count > 1) { + scan_pos += ent->run[0]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[1]); + goto end_of_block; + } + } + if (ent->count > 2) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[1]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[2]); + goto end_of_block; + } + } + if (ent->count > 3) { + scan_pos += ent->run[1]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[3]); + goto end_of_block; + } + } + skip_bits(gbc, ent->offset[3]); + k_run = ent->k_run; + k_level = ent->k_level_1; + if (ent->count & 1) + goto next_is_run; + else + goto next_is_level; + } + } + + next_is_run: { + next_bits = show_bits(gbc, 18); + lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS); + + ent = &lut->run_first_lut[k_run][k_level][lut_bits]; + + if (ent->count == 0) { + // One long code. + uint32_t bits, low_bits; + unsigned int leading_zeroes, low_bit_count, low_bit_shift; + int run; + + // Remove the prefix bits. + bits = next_bits & 0xffff; + // Determine code length. + leading_zeroes = 15 - av_log2(bits); + if (leading_zeroes >= 6) { + // 6 zeroes implies run > 64, which is always invalid. + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range run value: %d leading zeroes.\n", + leading_zeroes); + return AVERROR_INVALIDDATA; + } + // Extract the low bits. + low_bit_count = leading_zeroes + k_run; + low_bit_shift = 16 - (1 + 2 * leading_zeroes + k_run); + low_bits = av_zero_extend(bits >> low_bit_shift, low_bit_count); + // Construct run code. + run = (2 << k_run) + + ((1 << leading_zeroes) - 1) * (1 << k_run) + + low_bits; + // Skip over the bits just used. + skip_bits(gbc, 2 + leading_zeroes + 1 + low_bit_count); + + scan_pos += run; + if (scan_pos >= 64) + goto end_of_block; + k_run = FFMIN(run >> 2, 2); + goto next_is_level; + + } else { + // One or more short codes. + + scan_pos += ent->run[0]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[0]); + goto end_of_block; + } + if (ent->count > 1) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[0]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[1]); + goto end_of_block; + } + } + if (ent->count > 2) { + scan_pos += ent->run[1]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[2]); + goto end_of_block; + } + } + if (ent->count > 3) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[1]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[3]); + goto end_of_block; + } + } + skip_bits(gbc, ent->offset[3]); + k_run = ent->k_run; + k_level = ent->k_level_1; + if (ent->count & 1) + goto next_is_level; + else + goto next_is_run; + } + } + + next_is_level: { + next_bits = show_bits(gbc, 18); + lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS); + + ent = &lut->level_first_lut[k_run][k_level][lut_bits]; + + if (ent->count == 0) { + // One long code. + uint32_t bits; + unsigned int leading_zeroes; + int level, abs_level, sign; + + // Remove the prefix bits. + bits = next_bits & 0xffff; + // Determine code length. + leading_zeroes = 15 - av_log2(bits); + // Skip the prefix and length bits. + skip_bits(gbc, 2 + leading_zeroes + 1); + // Read the rest of the code and construct the level. + // Include the + 1 offset for nonzero value here. + abs_level = (2 << k_level) + + ((1 << leading_zeroes) - 1) * (1 << k_level) + + get_bits(gbc, leading_zeroes + k_level) + 1; + + sign = get_bits(gbc, 1); + if (sign) + level = -abs_level; + else + level = abs_level; + + // Check range (not checked in any other case, only a long + // code can be out of range). + if (level < APV_MIN_TRANS_COEFF || + level > APV_MAX_TRANS_COEFF) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range AC coefficient value at %d: %d.\n", + scan_pos, level); + return AVERROR_INVALIDDATA; + } + coeff[ff_zigzag_direct[scan_pos]] = level; + ++scan_pos; + k_level = FFMIN(abs_level >> 2, 4); + if (scan_pos >= 64) + goto end_of_block; + goto next_is_run; + + } else { + // One or more short codes. + + coeff[ff_zigzag_direct[scan_pos]] = ent->level[0]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[0]); + goto end_of_block; + } + if (ent->count > 1) { + scan_pos += ent->run[0]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[1]); + goto end_of_block; + } + } + if (ent->count > 2) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[1]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[2]); + goto end_of_block; + } + } + if (ent->count > 3) { + scan_pos += ent->run[1]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[3]); + goto end_of_block; + } + } + skip_bits(gbc, ent->offset[3]); + k_run = ent->k_run; + k_level = ent->k_level_1; + if (ent->count & 1) + goto next_is_run; + else + goto next_is_level; + } + } + + end_of_block: { + if (scan_pos > 64) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Block decode reached invalid scan position %d.\n", + scan_pos); + return AVERROR_INVALIDDATA; + } + return 0; + } +} diff --git a/libavcodec/apv_parser.c b/libavcodec/apv_parser.c new file mode 100644 index 000000000..3417bd751 --- /dev/null +++ b/libavcodec/apv_parser.c @@ -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 + */ + +#include "libavutil/avassert.h" +#include "libavutil/buffer.h" +#include "libavutil/mem.h" + +#include "avcodec.h" +#include "apv.h" +#include "cbs.h" +#include "cbs_apv.h" +#include "parser.h" +#include "parser_internal.h" + +typedef struct APVParseContext { + ParseContext pc; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment au; +} APVParseContext; + +static const enum AVPixelFormat apv_format_table[5][5] = { + { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16 }, + { 0 }, // 4:2:0 is not valid. + { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV422P16 }, + { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV444P16 }, + { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUVA444P16 }, +}; + +static int find_frame_end(APVParseContext *p, const uint8_t *buf, int buf_size) +{ + ParseContext *pc = &p->pc; + int pic_found, i = 0; + uint32_t state; + + pic_found = pc->frame_start_found; + state = pc->state; + + if (buf_size == 0) { + pc->frame_start_found = 0; + pc->state = -1; + return 0; + } + + if (!pic_found) { + for (; i < buf_size; i++) { + state = (state << 8) | buf[i]; + if (state == APV_SIGNATURE) { + i++; + pic_found = 1; + break; + } + } + } + + if (pic_found) { + for(; i < buf_size; i++) { + state = (state << 8) | buf[i]; + if (state == APV_SIGNATURE) { + pc->frame_start_found = 0; + pc->state = -1; + return i - 3; + } + } + } + + pc->frame_start_found = pic_found; + pc->state = state; + return END_NOT_FOUND; +} + +static void dummy_free(void *opaque, uint8_t *data) +{ + av_assert0(opaque == data); +} + +static int parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + APVParseContext *p = s->priv_data; + CodedBitstreamFragment *au = &p->au; + AVBufferRef *ref = NULL; + int next, ret; + + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + } else { + next = find_frame_end(p, buf, buf_size); + + if (ff_combine_frame(&p->pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + } + + *poutbuf = buf; + *poutbuf_size = buf_size; + + if (!buf_size) + return 0; + + ref = av_buffer_create((uint8_t *)buf, buf_size, dummy_free, + (void *)buf, AV_BUFFER_FLAG_READONLY); + if (!ref) + return next; + + p->cbc->log_ctx = avctx; + + ret = ff_cbs_read(p->cbc, au, ref, buf, buf_size); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to parse access unit.\n"); + goto end; + } + + s->key_frame = 1; + s->pict_type = AV_PICTURE_TYPE_I; + s->field_order = AV_FIELD_UNKNOWN; + s->picture_structure = AV_PICTURE_STRUCTURE_FRAME; + + for (int i = 0; i < au->nb_units; i++) { + const CodedBitstreamUnit *pbu = &au->units[i]; + + switch (pbu->type) { + case APV_PBU_PRIMARY_FRAME: { + const APVRawFrame *frame = pbu->content; + const APVRawFrameHeader *header = &frame->frame_header; + const APVRawFrameInfo *info = &header->frame_info; + int bit_depth = info->bit_depth_minus8 + 8; + + if (bit_depth < 8 || bit_depth > 16 || bit_depth % 2) + break; + + s->width = info->frame_width; + s->height = info->frame_height; + s->format = apv_format_table[info->chroma_format_idc][bit_depth - 4 >> 2]; + avctx->profile = info->profile_idc; + avctx->level = info->level_idc; + avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; + avctx->color_primaries = header->color_primaries; + avctx->color_trc = header->transfer_characteristics; + avctx->colorspace = header->matrix_coefficients; + avctx->color_range = header->full_range_flag ? AVCOL_RANGE_JPEG + : AVCOL_RANGE_MPEG; + goto end; + } + default: + break; + } + } + +end: + ff_cbs_fragment_reset(au); + av_assert1(av_buffer_get_ref_count(ref) == 1); + av_buffer_unref(&ref); + p->cbc->log_ctx = NULL; + + return next; +} + +static const CodedBitstreamUnitType decompose_unit_types[] = { + APV_PBU_PRIMARY_FRAME, +}; + +static av_cold int init(AVCodecParserContext *s) +{ + APVParseContext *p = s->priv_data; + int ret; + + ret = ff_cbs_init(&p->cbc, AV_CODEC_ID_APV, NULL); + if (ret < 0) + return ret; + + p->cbc->decompose_unit_types = decompose_unit_types; + p->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types); + + return 0; +} + +static av_cold void close(AVCodecParserContext *s) +{ + APVParseContext *p = s->priv_data; + ParseContext *pc = &p->pc; + + av_freep(&pc->buffer); + ff_cbs_fragment_free(&p->au); + ff_cbs_close(&p->cbc); +} + +const FFCodecParser ff_apv_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_APV), + .priv_data_size = sizeof(APVParseContext), + .init = init, + .parse = parse, + .close = close, +}; diff --git a/libavcodec/arbc.c b/libavcodec/arbc.c index 46b0275e9..537af4d45 100644 --- a/libavcodec/arbc.c +++ b/libavcodec/arbc.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" @@ -192,7 +193,7 @@ static av_cold int decode_init(AVCodecContext *avctx) return 0; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { ARBCContext *s = avctx->priv_data; diff --git a/libavcodec/argo.c b/libavcodec/argo.c index 589feed41..b2e9f3bb1 100644 --- a/libavcodec/argo.c +++ b/libavcodec/argo.c @@ -21,6 +21,7 @@ #include +#include "libavutil/attributes.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" @@ -717,7 +718,7 @@ static av_cold int decode_init(AVCodecContext *avctx) return 0; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { ArgoContext *s = avctx->priv_data; diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile index becf316eb..e32a0bf49 100644 --- a/libavcodec/arm/Makefile +++ b/libavcodec/arm/Makefile @@ -21,7 +21,7 @@ OBJS-$(CONFIG_LLAUDDSP) += arm/lossless_audiodsp_init_arm.o OBJS-$(CONFIG_ME_CMP) += arm/me_cmp_init_arm.o OBJS-$(CONFIG_MPEGAUDIODSP) += arm/mpegaudiodsp_init_arm.o OBJS-$(CONFIG_MPEGVIDEO) += arm/mpegvideo_arm.o -OBJS-$(CONFIG_MPEGVIDEOENC) += arm/mpegvideoencdsp_init_arm.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += arm/mpegvideoencdsp_init_arm.o OBJS-$(CONFIG_NEON_CLOBBER_TEST) += arm/neontest.o OBJS-$(CONFIG_PIXBLOCKDSP) += arm/pixblockdsp_init_arm.o OBJS-$(CONFIG_RV34DSP) += arm/rv34dsp_init_arm.o @@ -42,7 +42,6 @@ OBJS-$(CONFIG_RV40_DECODER) += arm/rv40dsp_init_arm.o OBJS-$(CONFIG_SBC_ENCODER) += arm/sbcdsp_init_arm.o OBJS-$(CONFIG_TRUEHD_DECODER) += arm/mlpdsp_init_arm.o OBJS-$(CONFIG_VORBIS_DECODER) += arm/vorbisdsp_init_arm.o -OBJS-$(CONFIG_VP6_DECODER) += arm/vp6dsp_init_arm.o OBJS-$(CONFIG_VP9_DECODER) += arm/vp9dsp_init_10bpp_arm.o \ arm/vp9dsp_init_12bpp_arm.o \ arm/vp9dsp_init_arm.o @@ -72,7 +71,7 @@ ARMV6-OBJS-$(CONFIG_IDCTDSP) += arm/idctdsp_init_armv6.o \ arm/simple_idct_armv6.o ARMV6-OBJS-$(CONFIG_ME_CMP) += arm/me_cmp_armv6.o ARMV6-OBJS-$(CONFIG_MPEGAUDIODSP) += arm/mpegaudiodsp_fixed_armv6.o -ARMV6-OBJS-$(CONFIG_MPEGVIDEOENC) += arm/mpegvideoencdsp_armv6.o +ARMV6-OBJS-$(CONFIG_MPEGVIDEOENCDSP) += arm/mpegvideoencdsp_armv6.o ARMV6-OBJS-$(CONFIG_PIXBLOCKDSP) += arm/pixblockdsp_armv6.o ARMV6-OBJS-$(CONFIG_STARTCODE) += arm/startcode_armv6.o ARMV6-OBJS-$(CONFIG_VP8DSP) += arm/vp8_armv6.o \ @@ -139,7 +138,6 @@ NEON-OBJS-$(CONFIG_RV40_DECODER) += arm/rv34dsp_neon.o \ arm/rv40dsp_neon.o NEON-OBJS-$(CONFIG_SBC_ENCODER) += arm/sbcdsp_neon.o NEON-OBJS-$(CONFIG_VORBIS_DECODER) += arm/vorbisdsp_neon.o -NEON-OBJS-$(CONFIG_VP6_DECODER) += arm/vp6dsp_neon.o NEON-OBJS-$(CONFIG_VP9_DECODER) += arm/vp9itxfm_16bpp_neon.o \ arm/vp9itxfm_neon.o \ arm/vp9lpf_16bpp_neon.o \ diff --git a/libavcodec/arm/asm-offsets.h b/libavcodec/arm/asm-offsets.h index a2174b0a0..67e1f2ff6 100644 --- a/libavcodec/arm/asm-offsets.h +++ b/libavcodec/arm/asm-offsets.h @@ -28,5 +28,6 @@ #define BLOCK_LAST_INDEX 0x10 #define H263_AIC 0x40 #define INTER_SCANTAB_RASTER_END 0x88 +#define INTRA_SCANTAB_RASTER_END 0x10c #endif /* AVCODEC_ARM_ASM_OFFSETS_H */ diff --git a/libavcodec/arm/h264dsp_init_arm.c b/libavcodec/arm/h264dsp_init_arm.c index 13d499fda..050ceb90b 100644 --- a/libavcodec/arm/h264dsp_init_arm.c +++ b/libavcodec/arm/h264dsp_init_arm.c @@ -76,32 +76,32 @@ static av_cold void h264dsp_init_neon(H264DSPContext *c, const int bit_depth, { #if HAVE_NEON if (bit_depth == 8) { - c->h264_v_loop_filter_luma = ff_h264_v_loop_filter_luma_neon; - c->h264_h_loop_filter_luma = ff_h264_h_loop_filter_luma_neon; - c->h264_v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon; + c->v_loop_filter_luma = ff_h264_v_loop_filter_luma_neon; + c->h_loop_filter_luma = ff_h264_h_loop_filter_luma_neon; + c->v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon; if (chroma_format_idc <= 1) - c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon; + c->h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon; else - c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma422_neon; + c->h_loop_filter_chroma = ff_h264_h_loop_filter_chroma422_neon; - c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels_16_neon; - c->weight_h264_pixels_tab[1] = ff_weight_h264_pixels_8_neon; - c->weight_h264_pixels_tab[2] = ff_weight_h264_pixels_4_neon; + c->weight_pixels_tab[0] = ff_weight_h264_pixels_16_neon; + c->weight_pixels_tab[1] = ff_weight_h264_pixels_8_neon; + c->weight_pixels_tab[2] = ff_weight_h264_pixels_4_neon; - c->biweight_h264_pixels_tab[0] = ff_biweight_h264_pixels_16_neon; - c->biweight_h264_pixels_tab[1] = ff_biweight_h264_pixels_8_neon; - c->biweight_h264_pixels_tab[2] = ff_biweight_h264_pixels_4_neon; + c->biweight_pixels_tab[0] = ff_biweight_h264_pixels_16_neon; + c->biweight_pixels_tab[1] = ff_biweight_h264_pixels_8_neon; + c->biweight_pixels_tab[2] = ff_biweight_h264_pixels_4_neon; - c->h264_idct_add = ff_h264_idct_add_neon; - c->h264_idct_dc_add = ff_h264_idct_dc_add_neon; - c->h264_idct_add16 = ff_h264_idct_add16_neon; - c->h264_idct_add16intra = ff_h264_idct_add16intra_neon; + c->idct_add = ff_h264_idct_add_neon; + c->idct_dc_add = ff_h264_idct_dc_add_neon; + c->idct_add16 = ff_h264_idct_add16_neon; + c->idct_add16intra = ff_h264_idct_add16intra_neon; if (chroma_format_idc <= 1) - c->h264_idct_add8 = ff_h264_idct_add8_neon; - c->h264_idct8_add = ff_h264_idct8_add_neon; - c->h264_idct8_dc_add = ff_h264_idct8_dc_add_neon; - c->h264_idct8_add4 = ff_h264_idct8_add4_neon; + c->idct_add8 = ff_h264_idct_add8_neon; + c->idct8_add = ff_h264_idct8_add_neon; + c->idct8_dc_add = ff_h264_idct8_dc_add_neon; + c->idct8_add4 = ff_h264_idct8_add4_neon; } #endif // HAVE_NEON } diff --git a/libavcodec/arm/hevcdsp_idct_neon.S b/libavcodec/arm/hevcdsp_idct_neon.S index 66ed1c678..feff373ff 100644 --- a/libavcodec/arm/hevcdsp_idct_neon.S +++ b/libavcodec/arm/hevcdsp_idct_neon.S @@ -783,7 +783,7 @@ endfunc transpose8_4x4 d29, d3, d21, d23 store16 d22, d23, d20, d21, d2, d3, d28, d29, r8 - @ reload multiplication coefficiens to q1 + @ reload multiplication coefficients to q1 vld1.s16 {q1}, [r9, :128] .endm diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S index 8fd9d1e0d..e5695027e 100644 --- a/libavcodec/arm/hevcdsp_sao_neon.S +++ b/libavcodec/arm/hevcdsp_sao_neon.S @@ -100,7 +100,7 @@ function ff_hevc_sao_edge_filter_neon_8, export=1 mov r12, r4 // r12 = height mov r6, r0 // r6 = r0 = dst mov r7, r1 // r7 = r1 = src - vld1.8 {d0}, [r11] // edge_idx tabel load in d0 5x8bit + vld1.8 {d0}, [r11] // edge_idx table load in d0 5x8bit vld1.16 {q1}, [r10] // sao_offset_val table load in q1, 5x16bit vmov.u8 d1, #2 vmov.u16 q2, #1 diff --git a/libavcodec/arm/mathops.h b/libavcodec/arm/mathops.h index dc57c5571..9d0385db6 100644 --- a/libavcodec/arm/mathops.h +++ b/libavcodec/arm/mathops.h @@ -81,28 +81,6 @@ static inline av_const int MUL16(int ra, int rb) #endif -#define mid_pred mid_pred -static inline av_const int mid_pred(int a, int b, int c) -{ - int m; - __asm__ ( - "mov %0, %2 \n\t" - "cmp %1, %2 \n\t" - "itt gt \n\t" - "movgt %0, %1 \n\t" - "movgt %1, %2 \n\t" - "cmp %1, %3 \n\t" - "it le \n\t" - "movle %1, %3 \n\t" - "cmp %0, %1 \n\t" - "it gt \n\t" - "movgt %0, %1 \n\t" - : "=&r"(m), "+r"(a) - : "r"(b), "r"(c) - : "cc"); - return m; -} - #endif /* HAVE_INLINE_ASM */ #endif /* AVCODEC_ARM_MATHOPS_H */ diff --git a/libavcodec/arm/me_cmp_init_arm.c b/libavcodec/arm/me_cmp_init_arm.c index 8c556f175..a47e2bc4f 100644 --- a/libavcodec/arm/me_cmp_init_arm.c +++ b/libavcodec/arm/me_cmp_init_arm.c @@ -23,19 +23,18 @@ #include "libavutil/arm/cpu.h" #include "libavcodec/avcodec.h" #include "libavcodec/me_cmp.h" -#include "libavcodec/mpegvideo.h" -int ff_pix_abs16_armv6(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs16_armv6(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_pix_abs16_x2_armv6(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs16_x2_armv6(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_pix_abs16_y2_armv6(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs16_y2_armv6(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_pix_abs8_armv6(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs8_armv6(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_sse16_armv6(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_sse16_armv6(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); av_cold void ff_me_cmp_init_arm(MECmpContext *c, AVCodecContext *avctx) diff --git a/libavcodec/arm/mpegvideo_arm.c b/libavcodec/arm/mpegvideo_arm.c index 28a3f2cdd..593e99818 100644 --- a/libavcodec/arm/mpegvideo_arm.c +++ b/libavcodec/arm/mpegvideo_arm.c @@ -24,6 +24,7 @@ #include "libavutil/arm/cpu.h" #include "libavcodec/avcodec.h" #include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideo_unquantize.h" #include "mpegvideo_arm.h" #include "asm-offsets.h" @@ -37,20 +38,22 @@ CHECK_OFFSET(MpegEncContext, ac_pred, AC_PRED); CHECK_OFFSET(MpegEncContext, block_last_index, BLOCK_LAST_INDEX); CHECK_OFFSET(MpegEncContext, inter_scantable.raster_end, INTER_SCANTAB_RASTER_END); +CHECK_OFFSET(MpegEncContext, intra_scantable.raster_end, + INTRA_SCANTAB_RASTER_END); CHECK_OFFSET(MpegEncContext, h263_aic, H263_AIC); #endif -void ff_dct_unquantize_h263_inter_neon(MpegEncContext *s, int16_t *block, +void ff_dct_unquantize_h263_inter_neon(const MPVContext *s, int16_t *block, int n, int qscale); -void ff_dct_unquantize_h263_intra_neon(MpegEncContext *s, int16_t *block, +void ff_dct_unquantize_h263_intra_neon(const MPVContext *s, int16_t *block, int n, int qscale); -av_cold void ff_mpv_common_init_arm(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_arm(MPVUnquantDSPContext *s, int bitexact) { int cpu_flags = av_get_cpu_flags(); if (have_armv5te(cpu_flags)) - ff_mpv_common_init_armv5te(s); + ff_mpv_unquantize_init_armv5te(s); if (have_neon(cpu_flags)) { s->dct_unquantize_h263_intra = ff_dct_unquantize_h263_intra_neon; diff --git a/libavcodec/arm/mpegvideo_arm.h b/libavcodec/arm/mpegvideo_arm.h index 709ae6b24..93da7a566 100644 --- a/libavcodec/arm/mpegvideo_arm.h +++ b/libavcodec/arm/mpegvideo_arm.h @@ -19,8 +19,8 @@ #ifndef AVCODEC_ARM_MPEGVIDEO_ARM_H #define AVCODEC_ARM_MPEGVIDEO_ARM_H -#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideo_unquantize.h" -void ff_mpv_common_init_armv5te(MpegEncContext *s); +void ff_mpv_unquantize_init_armv5te(MPVUnquantDSPContext *s); #endif /* AVCODEC_ARM_MPEGVIDEO_ARM_H */ diff --git a/libavcodec/arm/mpegvideo_armv5te.c b/libavcodec/arm/mpegvideo_armv5te.c index e20bb4c64..b2790b48f 100644 --- a/libavcodec/arm/mpegvideo_armv5te.c +++ b/libavcodec/arm/mpegvideo_armv5te.c @@ -50,8 +50,8 @@ static inline void dct_unquantize_h263_helper_c(int16_t *block, int qmul, int qa } #endif -static void dct_unquantize_h263_intra_armv5te(MpegEncContext *s, - int16_t *block, int n, int qscale) +static void dct_unquantize_h263_intra_armv5te(const MPVContext *s, + int16_t *block, int n, int qscale) { int level, qmul, qadd; int nCoeffs; @@ -73,14 +73,14 @@ static void dct_unquantize_h263_intra_armv5te(MpegEncContext *s, if(s->ac_pred) nCoeffs=63; else - nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ]; + nCoeffs = s->intra_scantable.raster_end[s->block_last_index[n]]; ff_dct_unquantize_h263_armv5te(block, qmul, qadd, nCoeffs + 1); block[0] = level; } -static void dct_unquantize_h263_inter_armv5te(MpegEncContext *s, - int16_t *block, int n, int qscale) +static void dct_unquantize_h263_inter_armv5te(const MPVContext *s, + int16_t *block, int n, int qscale) { int qmul, qadd; int nCoeffs; @@ -95,7 +95,7 @@ static void dct_unquantize_h263_inter_armv5te(MpegEncContext *s, ff_dct_unquantize_h263_armv5te(block, qmul, qadd, nCoeffs + 1); } -av_cold void ff_mpv_common_init_armv5te(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_armv5te(MPVUnquantDSPContext *s) { s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_armv5te; s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_armv5te; diff --git a/libavcodec/arm/mpegvideo_neon.S b/libavcodec/arm/mpegvideo_neon.S index 1889d7a91..7e42bdf6c 100644 --- a/libavcodec/arm/mpegvideo_neon.S +++ b/libavcodec/arm/mpegvideo_neon.S @@ -36,7 +36,7 @@ function ff_dct_unquantize_h263_neon, export=1 vdup.16 q15, r0 @ qmul vdup.16 q14, r2 @ qadd vneg.s16 q13, q14 - cmp r3, #4 + cmp r3, #8 mov r0, r1 ble 2f 1: @@ -62,14 +62,14 @@ function ff_dct_unquantize_h263_neon, export=1 cmp r3, #8 bgt 1b 2: - vld1.16 {d0}, [r0,:64] - vclt.s16 d3, d0, #0 - vceq.s16 d1, d0, #0 - vmul.s16 d2, d0, d30 - vbsl d3, d26, d28 - vadd.s16 d2, d2, d3 - vbif d0, d2, d1 - vst1.16 {d0}, [r1,:64] + vld1.16 {q0}, [r0,:128] + vclt.s16 q3, q0, #0 + vceq.s16 q1, q0, #0 + vmul.s16 q2, q0, q15 + vbsl q3, q13, q14 + vadd.s16 q2, q2, q3 + vbif q0, q2, q1 + vst1.16 {q0}, [r1,:128] bx lr endfunc @@ -77,7 +77,7 @@ function ff_dct_unquantize_h263_intra_neon, export=1 push {r4-r6,lr} add r12, r0, #BLOCK_LAST_INDEX ldr r6, [r0, #AC_PRED] - add lr, r0, #INTER_SCANTAB_RASTER_END + add lr, r0, #INTRA_SCANTAB_RASTER_END cmp r6, #0 it ne movne r12, #63 diff --git a/libavcodec/arm/pixblockdsp_init_arm.c b/libavcodec/arm/pixblockdsp_init_arm.c index 5481c0178..9d817e400 100644 --- a/libavcodec/arm/pixblockdsp_init_arm.c +++ b/libavcodec/arm/pixblockdsp_init_arm.c @@ -21,25 +21,23 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/arm/cpu.h" -#include "libavcodec/avcodec.h" #include "libavcodec/pixblockdsp.h" -void ff_get_pixels_armv6(int16_t *block, const uint8_t *pixels, +void ff_get_pixels_armv6(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t stride); -void ff_diff_pixels_armv6(int16_t *block, const uint8_t *s1, +void ff_diff_pixels_armv6(int16_t *restrict block, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride); -void ff_get_pixels_neon(int16_t *block, const uint8_t *pixels, +void ff_get_pixels_neon(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t stride); -void ff_get_pixels_unaligned_neon(int16_t *block, const uint8_t *pixels, +void ff_get_pixels_unaligned_neon(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t stride); -void ff_diff_pixels_neon(int16_t *block, const uint8_t *s1, +void ff_diff_pixels_neon(int16_t *restrict block, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride); -void ff_diff_pixels_unaligned_neon(int16_t *block, const uint8_t *s1, +void ff_diff_pixels_unaligned_neon(int16_t *restrict block, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride); av_cold void ff_pixblockdsp_init_arm(PixblockDSPContext *c, - AVCodecContext *avctx, unsigned high_bit_depth) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/arm/vp3dsp_init_arm.c b/libavcodec/arm/vp3dsp_init_arm.c index 65ea53fe0..905c3dd62 100644 --- a/libavcodec/arm/vp3dsp_init_arm.c +++ b/libavcodec/arm/vp3dsp_init_arm.c @@ -30,7 +30,7 @@ void ff_vp3_idct_dc_add_neon(uint8_t *dest, ptrdiff_t stride, int16_t *data); void ff_vp3_v_loop_filter_neon(uint8_t *, int, int *); void ff_vp3_h_loop_filter_neon(uint8_t *, int, int *); -av_cold void ff_vp3dsp_init_arm(VP3DSPContext *c, int flags) +av_cold void ff_vp3dsp_init_arm(VP3DSPContext *c) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/arm/vp6dsp_neon.S b/libavcodec/arm/vp6dsp_neon.S deleted file mode 100644 index 03dd28d1c..000000000 --- a/libavcodec/arm/vp6dsp_neon.S +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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 - */ - -#include "libavutil/arm/asm.S" - -.macro vp6_edge_filter - vdup.16 q3, r2 @ t - vmov.i16 q13, #1 - vsubl.u8 q0, d20, d18 @ p[ 0] - p[-s] - vsubl.u8 q1, d16, d22 @ p[-2*s] - p[ s] - vsubl.u8 q14, d21, d19 - vsubl.u8 q15, d17, d23 - vadd.i16 q2, q0, q0 @ 2*(p[0]-p[-s]) - vadd.i16 d29, d28, d28 - vadd.i16 q0, q0, q1 @ p[0]-p[-s] + p[-2*s]-p[s] - vadd.i16 d28, d28, d30 - vadd.i16 q0, q0, q2 @ 3*(p[0]-p[-s]) + p[-2*s]-p[s] - vadd.i16 d28, d28, d29 - vrshr.s16 q0, q0, #3 @ v - vrshr.s16 d28, d28, #3 - vsub.i16 q8, q3, q13 @ t-1 - vabs.s16 q1, q0 @ V - vshr.s16 q2, q0, #15 @ s - vabs.s16 d30, d28 - vshr.s16 d29, d28, #15 - vsub.i16 q12, q1, q3 @ V-t - vsub.i16 d31, d30, d6 - vsub.i16 q12, q12, q13 @ V-t-1 - vsub.i16 d31, d31, d26 - vcge.u16 q12, q12, q8 @ V-t-1 >= t-1 - vcge.u16 d31, d31, d16 - vadd.i16 q13, q3, q3 @ 2*t - vadd.i16 d16, d6, d6 - vsub.i16 q13, q13, q1 @ 2*t - V - vsub.i16 d16, d16, d30 - vadd.i16 q13, q13, q2 @ += s - vadd.i16 d16, d16, d29 - veor q13, q13, q2 @ ^= s - veor d16, d16, d29 - vbif q0, q13, q12 - vbif d28, d16, d31 - vmovl.u8 q1, d20 - vmovl.u8 q15, d21 - vaddw.u8 q2, q0, d18 - vaddw.u8 q3, q14, d19 - vsub.i16 q1, q1, q0 - vsub.i16 d30, d30, d28 - vqmovun.s16 d18, q2 - vqmovun.s16 d19, q3 - vqmovun.s16 d20, q1 - vqmovun.s16 d21, q15 -.endm - -function ff_vp6_edge_filter_ver_neon, export=1 - sub r0, r0, r1, lsl #1 - vld1.8 {q8}, [r0], r1 @ p[-2*s] - vld1.8 {q9}, [r0], r1 @ p[-s] - vld1.8 {q10}, [r0], r1 @ p[0] - vld1.8 {q11}, [r0] @ p[s] - vp6_edge_filter - sub r0, r0, r1, lsl #1 - sub r1, r1, #8 - vst1.8 {d18}, [r0]! - vst1.32 {d19[0]}, [r0], r1 - vst1.8 {d20}, [r0]! - vst1.32 {d21[0]}, [r0] - bx lr -endfunc - -function ff_vp6_edge_filter_hor_neon, export=1 - sub r3, r0, #1 - sub r0, r0, #2 - vld1.32 {d16[0]}, [r0], r1 - vld1.32 {d18[0]}, [r0], r1 - vld1.32 {d20[0]}, [r0], r1 - vld1.32 {d22[0]}, [r0], r1 - vld1.32 {d16[1]}, [r0], r1 - vld1.32 {d18[1]}, [r0], r1 - vld1.32 {d20[1]}, [r0], r1 - vld1.32 {d22[1]}, [r0], r1 - vld1.32 {d17[0]}, [r0], r1 - vld1.32 {d19[0]}, [r0], r1 - vld1.32 {d21[0]}, [r0], r1 - vld1.32 {d23[0]}, [r0], r1 - vtrn.8 q8, q9 - vtrn.8 q10, q11 - vtrn.16 q8, q10 - vtrn.16 q9, q11 - vp6_edge_filter - vtrn.8 q9, q10 - vst1.16 {d18[0]}, [r3], r1 - vst1.16 {d20[0]}, [r3], r1 - vst1.16 {d18[1]}, [r3], r1 - vst1.16 {d20[1]}, [r3], r1 - vst1.16 {d18[2]}, [r3], r1 - vst1.16 {d20[2]}, [r3], r1 - vst1.16 {d18[3]}, [r3], r1 - vst1.16 {d20[3]}, [r3], r1 - vst1.16 {d19[0]}, [r3], r1 - vst1.16 {d21[0]}, [r3], r1 - vst1.16 {d19[1]}, [r3], r1 - vst1.16 {d21[1]}, [r3], r1 - bx lr -endfunc diff --git a/libavcodec/ass.c b/libavcodec/ass.c index 35861139e..6ae591d84 100644 --- a/libavcodec/ass.c +++ b/libavcodec/ass.c @@ -163,7 +163,7 @@ int ff_ass_add_rect(AVSubtitle *sub, const char *dialog, return ff_ass_add_rect2(sub, dialog, readorder, layer, style, speaker, NULL); } -void ff_ass_decoder_flush(AVCodecContext *avctx) +av_cold void ff_ass_decoder_flush(AVCodecContext *avctx) { FFASSDecoderContext *s = avctx->priv_data; if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP)) diff --git a/libavcodec/ass_split.c b/libavcodec/ass_split.c index 73ef6196c..3f8f5e7ca 100644 --- a/libavcodec/ass_split.c +++ b/libavcodec/ass_split.c @@ -1,5 +1,5 @@ /* - * SSA/ASS spliting functions + * SSA/ASS splitting functions * Copyright (c) 2010 Aurelien Jacobs * * This file is part of FFmpeg. @@ -379,7 +379,7 @@ static int ass_split(ASSSplitContext *ctx, const char *buf) return buf ? 0 : AVERROR_INVALIDDATA; } -ASSSplitContext *ff_ass_split(const char *buf) +av_cold ASSSplitContext *ff_ass_split(const char *buf) { ASSSplitContext *ctx = av_mallocz(sizeof(*ctx)); if (!ctx) @@ -467,7 +467,7 @@ ASSDialog *ff_ass_split_dialog(ASSSplitContext *ctx, const char *buf) return dialog; } -void ff_ass_split_free(ASSSplitContext *ctx) +av_cold void ff_ass_split_free(ASSSplitContext *ctx) { if (ctx) { int i; diff --git a/libavcodec/ass_split.h b/libavcodec/ass_split.h index a45fb9b8a..41191c0f4 100644 --- a/libavcodec/ass_split.h +++ b/libavcodec/ass_split.h @@ -1,5 +1,5 @@ /* - * SSA/ASS spliting functions + * SSA/ASS splitting functions * Copyright (c) 2010 Aurelien Jacobs * * This file is part of FFmpeg. diff --git a/libavcodec/asvenc.c b/libavcodec/asvenc.c index 4f81a4015..883edd046 100644 --- a/libavcodec/asvenc.c +++ b/libavcodec/asvenc.c @@ -26,6 +26,7 @@ #include "config_components.h" #include "libavutil/attributes.h" +#include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/mem_internal.h" @@ -44,49 +45,64 @@ typedef struct ASVEncContext { PutBitContext pb; + void (*get_pixels)(int16_t *restrict block, + const uint8_t *pixels, + ptrdiff_t stride); + PixblockDSPContext pdsp; FDCTDSPContext fdsp; DECLARE_ALIGNED(32, int16_t, block)[6][64]; int q_intra_matrix[64]; } ASVEncContext; +enum { + ASV1_MAX_BLOCK_SIZE = 8 + 10 * FFMAX(2 /* skip */, 5 /* ccp */ + 4 * 11 /* level */) + 5, + ASV1_MAX_MB_SIZE = 6 * ASV1_MAX_BLOCK_SIZE, + ASV2_MAX_BLOCK_SIZE = 4 + 8 + 16 * (6 /* ccp */ + 4 * 13 /* level */), + ASV2_MAX_MB_SIZE = 6 * ASV2_MAX_BLOCK_SIZE, + MAX_MB_SIZE = (FFMAX(ASV1_MAX_MB_SIZE, ASV2_MAX_MB_SIZE) + 7) / 8 +}; + static inline void asv1_put_level(PutBitContext *pb, int level) { unsigned int index = level + 3; + unsigned n, code; if (index <= 6) { - put_bits(pb, ff_asv_level_tab[index][1], ff_asv_level_tab[index][0]); + n = ff_asv_level_tab[index][1]; + code = ff_asv_level_tab[index][0]; } else { - put_bits(pb, 3, 0); /* Escape code */ - put_sbits(pb, 8, level); + n = 3 + 8; + code = (0 /* Escape code */ << 8) | (level & 0xFF); } + put_bits(pb, n, code); } static inline void asv2_put_level(ASVEncContext *a, PutBitContext *pb, int level) { unsigned int index = level + 31; + unsigned n, code; if (index <= 62) { - put_bits_le(pb, ff_asv2_level_tab[index][1], ff_asv2_level_tab[index][0]); + n = ff_asv2_level_tab[index][1]; + code = ff_asv2_level_tab[index][0]; } else { - put_bits_le(pb, 5, 0); /* Escape code */ if (level < -128 || level > 127) { av_log(a->c.avctx, AV_LOG_WARNING, "Clipping level %d, increase qscale\n", level); level = av_clip_int8(level); } - put_bits_le(pb, 8, level & 0xFF); + n = 5 + 8; + code = (level & 0xFF) << 5 | /* Escape code */ 0; } + put_bits_le(pb, n, code); } static inline void asv1_encode_block(ASVEncContext *a, int16_t block[64]) { - int i; - int nc_count = 0; - put_bits(&a->pb, 8, (block[0] + 32) >> 6); block[0] = 0; - for (i = 0; i < 10; i++) { + for (unsigned i = 0, nc_bits = 0, nc_val = 0; i < 10; i++) { const int index = ff_asv_scantab[4 * i]; int ccp = 0; @@ -104,10 +120,11 @@ static inline void asv1_encode_block(ASVEncContext *a, int16_t block[64]) ccp |= 1; if (ccp) { - for (; nc_count; nc_count--) - put_bits(&a->pb, 2, 2); /* Skip */ - - put_bits(&a->pb, ff_asv_ccp_tab[ccp][1], ff_asv_ccp_tab[ccp][0]); + put_bits(&a->pb, nc_bits + ff_asv_ccp_tab[ccp][1], + nc_val << ff_asv_ccp_tab[ccp][1] /* Skip */ | + ff_asv_ccp_tab[ccp][0]); + nc_bits = 0; + nc_val = 0; if (ccp & 8) asv1_put_level(&a->pb, block[index + 0]); @@ -118,7 +135,8 @@ static inline void asv1_encode_block(ASVEncContext *a, int16_t block[64]) if (ccp & 1) asv1_put_level(&a->pb, block[index + 9]); } else { - nc_count++; + nc_bits += 2; + nc_val = (nc_val << 2) | 2; } } put_bits(&a->pb, 5, 0xF); /* End of block */ @@ -137,8 +155,8 @@ static inline void asv2_encode_block(ASVEncContext *a, int16_t block[64]) count >>= 2; - put_bits_le(&a->pb, 4, count); - put_bits_le(&a->pb, 8, (block[0] + 32) >> 6); + put_bits_le(&a->pb, 4 + 8, count /* 4 bits */ | + (/* DC */(block[0] + 32) >> 6) << 4); block[0] = 0; for (i = 0; i <= count; i++) { @@ -177,8 +195,6 @@ static inline void asv2_encode_block(ASVEncContext *a, int16_t block[64]) } } -#define MAX_MB_SIZE (30 * 16 * 16 * 3 / 2 / 8) - static inline int encode_mb(ASVEncContext *a, int16_t block[6][64]) { int i; @@ -207,21 +223,73 @@ static inline void dct_get(ASVEncContext *a, const AVFrame *frame, const uint8_t *ptr_cb = frame->data[1] + (mb_y * 8 * frame->linesize[1]) + mb_x * 8; const uint8_t *ptr_cr = frame->data[2] + (mb_y * 8 * frame->linesize[2]) + mb_x * 8; - a->pdsp.get_pixels(block[0], ptr_y, linesize); - a->pdsp.get_pixels(block[1], ptr_y + 8, linesize); - a->pdsp.get_pixels(block[2], ptr_y + 8 * linesize, linesize); - a->pdsp.get_pixels(block[3], ptr_y + 8 * linesize + 8, linesize); + a->get_pixels(block[0], ptr_y, linesize); + a->get_pixels(block[1], ptr_y + 8, linesize); + a->get_pixels(block[2], ptr_y + 8 * linesize, linesize); + a->get_pixels(block[3], ptr_y + 8 * linesize + 8, linesize); for (i = 0; i < 4; i++) a->fdsp.fdct(block[i]); if (!(a->c.avctx->flags & AV_CODEC_FLAG_GRAY)) { - a->pdsp.get_pixels(block[4], ptr_cb, frame->linesize[1]); - a->pdsp.get_pixels(block[5], ptr_cr, frame->linesize[2]); + a->get_pixels(block[4], ptr_cb, frame->linesize[1]); + a->get_pixels(block[5], ptr_cr, frame->linesize[2]); for (i = 4; i < 6; i++) a->fdsp.fdct(block[i]); } } +static void handle_partial_mb(ASVEncContext *a, const uint8_t *const data[3], + const int linesizes[3], + int valid_width, int valid_height) +{ + const int nb_blocks = a->c.avctx->flags & AV_CODEC_FLAG_GRAY ? 4 : 6; + static const struct Descriptor { + uint8_t x_offset, y_offset; + uint8_t component, subsampling; + } block_descriptor[] = { + { 0, 0, 0, 0 }, { 8, 0, 0, 0 }, { 0, 8, 0, 0 }, { 8, 8, 0, 0 }, + { 0, 0, 1, 1 }, { 0, 0, 2, 1 }, + }; + + for (int i = 0; i < nb_blocks; ++i) { + const struct Descriptor *const desc = block_descriptor + i; + int width_avail = AV_CEIL_RSHIFT(valid_width, desc->subsampling) - desc->x_offset; + int height_avail = AV_CEIL_RSHIFT(valid_height, desc->subsampling) - desc->y_offset; + + if (width_avail <= 0 || height_avail <= 0) { + // This block is outside of the visible part; don't replicate pixels, + // just zero the block, so that only the dc value will be coded. + memset(a->block[i], 0, sizeof(a->block[i])); + continue; + } + width_avail = FFMIN(width_avail, 8); + height_avail = FFMIN(height_avail, 8); + + ptrdiff_t linesize = linesizes[desc->component]; + const uint8_t *src = data[desc->component] + desc->y_offset * linesize + desc->x_offset; + int16_t *block = a->block[i]; + + for (int h = 0;; block += 8, src += linesize) { + int16_t last; + for (int w = 0; w < width_avail; ++w) + last = block[w] = src[w]; + for (int w = width_avail; w < 8; ++w) + block[w] = last; + if (++h == height_avail) + break; + } + const int16_t *const last_row = block; + for (int h = height_avail; h < 8; ++h) { + block += 8; + AV_COPY128(block, last_row); + } + + a->fdsp.fdct(a->block[i]); + } + + encode_mb(a, a->block); +} + static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet) { @@ -229,51 +297,17 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const ASVCommonContext *const c = &a->c; int size, ret; - if (pict->width % 16 || pict->height % 16) { - AVFrame *clone = av_frame_alloc(); - int i; - - if (!clone) - return AVERROR(ENOMEM); - clone->format = pict->format; - clone->width = FFALIGN(pict->width, 16); - clone->height = FFALIGN(pict->height, 16); - ret = av_frame_get_buffer(clone, 0); - if (ret < 0) { - av_frame_free(&clone); - return ret; - } - - ret = av_frame_copy(clone, pict); - if (ret < 0) { - av_frame_free(&clone); - return ret; - } - - for (i = 0; i<3; i++) { - int x, y; - int w = AV_CEIL_RSHIFT(pict->width, !!i); - int h = AV_CEIL_RSHIFT(pict->height, !!i); - int w2 = AV_CEIL_RSHIFT(clone->width, !!i); - int h2 = AV_CEIL_RSHIFT(clone->height, !!i); - for (y=0; ydata[i][x + y*clone->linesize[i]] = - clone->data[i][w - 1 + y*clone->linesize[i]]; - for (y=h; ydata[i][x + y*clone->linesize[i]] = - clone->data[i][x + (h-1)*clone->linesize[i]]; - } - ret = encode_frame(avctx, pkt, clone, got_packet); - - av_frame_free(&clone); + ret = ff_alloc_packet(avctx, pkt, c->mb_height * c->mb_width * MAX_MB_SIZE + 3); + if (ret < 0) return ret; - } - if ((ret = ff_alloc_packet(avctx, pkt, c->mb_height * c->mb_width * MAX_MB_SIZE + - FF_INPUT_BUFFER_MIN_SIZE)) < 0) - return ret; + if (!PIXBLOCKDSP_8BPP_GET_PIXELS_SUPPORTS_UNALIGNED && + ((uintptr_t)pict->data[0] & 7 || pict->linesize[0] & 7 || + (uintptr_t)pict->data[1] & 7 || pict->linesize[1] & 7 || + (uintptr_t)pict->data[2] & 7 || pict->linesize[2] & 7)) + a->get_pixels = a->pdsp.get_pixels_unaligned; + else + a->get_pixels = a->pdsp.get_pixels; init_put_bits(&a->pb, pkt->data, pkt->size); @@ -284,19 +318,37 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, } } - if (c->mb_width2 != c->mb_width) { - int mb_x = c->mb_width2; + if (avctx->width & 15) { + const uint8_t *src[3] = { + pict->data[0] + c->mb_width2 * 16, + pict->data[1] + c->mb_width2 * 8, + pict->data[2] + c->mb_width2 * 8, + }; + int available_width = avctx->width & 15; + for (int mb_y = 0; mb_y < c->mb_height2; mb_y++) { - dct_get(a, pict, mb_x, mb_y); - encode_mb(a, a->block); + handle_partial_mb(a, src, pict->linesize, available_width, 16); + src[0] += 16 * pict->linesize[0]; + src[1] += 8 * pict->linesize[1]; + src[2] += 8 * pict->linesize[2]; } } - if (c->mb_height2 != c->mb_height) { - int mb_y = c->mb_height2; - for (int mb_x = 0; mb_x < c->mb_width; mb_x++) { - dct_get(a, pict, mb_x, mb_y); - encode_mb(a, a->block); + if (avctx->height & 15) { + const uint8_t *src[3] = { + pict->data[0] + c->mb_height2 * 16 * pict->linesize[0], + pict->data[1] + c->mb_height2 * 8 * pict->linesize[1], + pict->data[2] + c->mb_height2 * 8 * pict->linesize[2], + }; + int available_height = avctx->height & 15; + + for (int remaining = avctx->width;; remaining -= 16) { + handle_partial_mb(a, src, pict->linesize, remaining, available_height); + if (remaining <= 16) + break; + src[0] += 16; + src[1] += 8; + src[2] += 8; } } @@ -327,7 +379,7 @@ static av_cold int encode_init(AVCodecContext *avctx) ff_asv_common_init(avctx); ff_fdctdsp_init(&a->fdsp, avctx); - ff_pixblockdsp_init(&a->pdsp, avctx); + ff_pixblockdsp_init(&a->pdsp, 8); if (avctx->global_quality <= 0) avctx->global_quality = 4 * FF_QUALITY_SCALE; @@ -339,8 +391,8 @@ static av_cold int encode_init(AVCodecContext *avctx) if (!avctx->extradata) return AVERROR(ENOMEM); avctx->extradata_size = 8; - AV_WLA(32, avctx->extradata, inv_qscale); - ((uint32_t *) avctx->extradata)[1] = av_le2ne32(AV_RL32("ASUS")); + AV_WL32A(avctx->extradata, inv_qscale); + AV_WL32A(avctx->extradata + 4, MKTAG('A', 'S', 'U', 'S')); for (i = 0; i < 64; i++) { if (a->fdsp.fdct == ff_fdct_ifast) { @@ -365,8 +417,7 @@ const FFCodec ff_asv1_encoder = { .priv_data_size = sizeof(ASVEncContext), .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, }; #endif @@ -381,8 +432,7 @@ const FFCodec ff_asv2_encoder = { .priv_data_size = sizeof(ASVEncContext), .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, }; #endif diff --git a/libavcodec/atrac1.c b/libavcodec/atrac1.c index cdcc7a669..2625b8f87 100644 --- a/libavcodec/atrac1.c +++ b/libavcodec/atrac1.c @@ -49,7 +49,7 @@ #define AT1_SU_SAMPLES 512 ///< number of samples in a sound unit #define AT1_FRAME_SIZE AT1_SU_SIZE * 2 #define AT1_SU_MAX_BITS AT1_SU_SIZE * 8 -#define AT1_MAX_CHANNELS 2 +#define AT1_MAX_CHANNELS 8 #define AT1_QMF_BANDS 3 #define IDX_LOW_BAND 0 @@ -339,7 +339,7 @@ static av_cold int atrac1_decode_init(AVCodecContext *avctx) AVFloatDSPContext *fdsp; int channels = avctx->ch_layout.nb_channels; float scale = -1.0 / (1 << 15); - int ret; + int ret, ch; avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; @@ -380,10 +380,10 @@ static av_cold int atrac1_decode_init(AVCodecContext *avctx) q->bands[2] = q->high; /* Prepare the mdct overlap buffers */ - q->SUs[0].spectrum[0] = q->SUs[0].spec1; - q->SUs[0].spectrum[1] = q->SUs[0].spec2; - q->SUs[1].spectrum[0] = q->SUs[1].spec1; - q->SUs[1].spectrum[1] = q->SUs[1].spec2; + for (ch = 0; ch < AT1_MAX_CHANNELS; ch++) { + q->SUs[ch].spectrum[0] = q->SUs[ch].spec1; + q->SUs[ch].spectrum[1] = q->SUs[ch].spec2; + } return 0; } @@ -399,7 +399,5 @@ const FFCodec ff_atrac1_decoder = { .close = atrac1_decode_end, FF_CODEC_DECODE_CB(atrac1_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/atrac3.c b/libavcodec/atrac3.c index 39ddfd9e4..7f362f453 100644 --- a/libavcodec/atrac3.c +++ b/libavcodec/atrac3.c @@ -526,7 +526,7 @@ static void reverse_matrixing(float *su1, float *su2, int *prev_code, } break; default: - av_assert1(0); + av_unreachable("curr_code/matrix_coeff_index_* values are stored in two bits"); } } } @@ -616,7 +616,7 @@ static int decode_channel_sound_unit(ATRAC3Context *q, GetBitContext *gb, /* calculate number of used MLT/QMF bands according to the amount of coded spectral lines */ - num_bands = (subband_tab[num_subbands] - 1) >> 8; + num_bands = (subband_tab[num_subbands + 1] - 1) >> 8; if (last_tonal >= 0) num_bands = FFMAX((last_tonal + 256) >> 8, num_bands); @@ -1027,13 +1027,7 @@ const FFCodec ff_atrac3_decoder = { .init = atrac3_decode_init, .close = atrac3_decode_close, FF_CODEC_DECODE_CB(atrac3_decode_frame), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + .p.capabilities = AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; @@ -1046,12 +1040,6 @@ const FFCodec ff_atrac3al_decoder = { .init = atrac3_decode_init, .close = atrac3_decode_close, FF_CODEC_DECODE_CB(atrac3al_decode_frame), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + .p.capabilities = AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/atrac3plusdsp.c b/libavcodec/atrac3plusdsp.c index 802f12aec..6942cba50 100644 --- a/libavcodec/atrac3plusdsp.c +++ b/libavcodec/atrac3plusdsp.c @@ -114,7 +114,7 @@ av_cold void ff_atrac3p_init_dsp_static(void) * @param[in] fdsp ptr to floating-point DSP context * @param[in] invert_phase flag indicating 180° phase shift * @param[in] reg_offset region offset for trimming envelope data - * @param[out] out receives sythesized data + * @param[out] out receives synthesized data */ static void waves_synth(Atrac3pWaveSynthParams *synth_param, Atrac3pWavesData *waves_info, diff --git a/libavcodec/atrac9dec.c b/libavcodec/atrac9dec.c index e375f46fd..3c18ae8b4 100644 --- a/libavcodec/atrac9dec.c +++ b/libavcodec/atrac9dec.c @@ -80,7 +80,7 @@ typedef struct ATRAC9BlockData { int cpe_base_channel; int is_signs[30]; - int reuseable; + int reusable; } ATRAC9BlockData; @@ -285,7 +285,7 @@ static inline int read_scalefactors(ATRAC9Context *s, ATRAC9BlockData *b, for (int i = 1; i < b->band_ext_q_unit; i++) { int val = c->scalefactors[i - 1] + get_vlc2(gb, tab, ATRAC9_SF_VLC_BITS, 1); - c->scalefactors[i] = val & ((1 << len) - 1); + c->scalefactors[i] = av_zero_extend(val, len); } for (int i = 0; i < b->band_ext_q_unit; i++) @@ -339,7 +339,7 @@ static inline int read_scalefactors(ATRAC9Context *s, ATRAC9BlockData *b, for (int i = 1; i < unit_cnt; i++) { int val = c->scalefactors[i - 1] + get_vlc2(gb, tab, ATRAC9_SF_VLC_BITS, 1); - c->scalefactors[i] = val & ((1 << len) - 1); + c->scalefactors[i] = av_zero_extend(val, len); } for (int i = 0; i < unit_cnt; i++) @@ -689,7 +689,7 @@ static int atrac9_decode_block(ATRAC9Context *s, GetBitContext *gb, if (!reuse_params) { int stereo_band, ext_band; const int min_band_count = s->samplerate_idx > 7 ? 1 : 3; - b->reuseable = 0; + b->reusable = 0; b->band_count = get_bits(gb, 4) + min_band_count; b->q_unit_cnt = at9_tab_band_q_unit_map[b->band_count]; @@ -721,9 +721,9 @@ static int atrac9_decode_block(ATRAC9Context *s, GetBitContext *gb, } b->band_ext_q_unit = at9_tab_band_q_unit_map[ext_band]; } - b->reuseable = 1; + b->reusable = 1; } - if (!b->reuseable) { + if (!b->reusable) { av_log(s->avctx, AV_LOG_ERROR, "invalid block reused!\n"); return AVERROR_INVALIDDATA; } @@ -820,7 +820,7 @@ static int atrac9_decode_frame(AVCodecContext *avctx, AVFrame *frame, return avctx->block_align; } -static void atrac9_decode_flush(AVCodecContext *avctx) +static av_cold void atrac9_decode_flush(AVCodecContext *avctx) { ATRAC9Context *s = avctx->priv_data; @@ -1006,9 +1006,5 @@ const FFCodec ff_atrac9_decoder = { FF_CODEC_DECODE_CB(atrac9_decode_frame), .flush = atrac9_decode_flush, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, }; diff --git a/libavcodec/audio_frame_queue.c b/libavcodec/audio_frame_queue.c index 10b5d2139..1ca5f7030 100644 --- a/libavcodec/audio_frame_queue.c +++ b/libavcodec/audio_frame_queue.c @@ -33,7 +33,7 @@ av_cold void ff_af_queue_init(AVCodecContext *avctx, AudioFrameQueue *afq) afq->frame_count = 0; } -void ff_af_queue_close(AudioFrameQueue *afq) +av_cold void ff_af_queue_close(AudioFrameQueue *afq) { if(afq->frame_count) av_log(afq->avctx, AV_LOG_WARNING, "%d frames left in the queue on closing\n", afq->frame_count); diff --git a/libavcodec/audiodsp.c b/libavcodec/audiodsp.c index fd6a00345..a4758bb4c 100644 --- a/libavcodec/audiodsp.c +++ b/libavcodec/audiodsp.c @@ -74,7 +74,7 @@ av_cold void ff_audiodsp_init(AudioDSPContext *c) ff_audiodsp_init_ppc(c); #elif ARCH_RISCV ff_audiodsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_audiodsp_init_x86(c); #endif } diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c index 908b56055..d999e5e8a 100644 --- a/libavcodec/audiotoolboxenc.c +++ b/libavcodec/audiotoolboxenc.c @@ -650,13 +650,10 @@ static const AVOption options[] = { .p.priv_class = &ffat_##NAME##_enc_class, \ .p.capabilities = AV_CODEC_CAP_DELAY | \ AV_CODEC_CAP_ENCODER_FLUSH CAPS, \ - .p.ch_layouts = CH_LAYOUTS, \ - .p.sample_fmts = (const enum AVSampleFormat[]) { \ - AV_SAMPLE_FMT_S16, \ - AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NONE \ - }, \ .p.profiles = PROFILES, \ .p.wrapper_name = "at", \ + CODEC_CH_LAYOUTS_ARRAY(CH_LAYOUTS), \ + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8), \ }; static const AVChannelLayout aac_at_ch_layouts[] = { diff --git a/libavcodec/av1_parser.c b/libavcodec/av1_parser.c index 2b79493bf..68a98285e 100644 --- a/libavcodec/av1_parser.c +++ b/libavcodec/av1_parser.c @@ -20,12 +20,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "av1_parse.h" +#include "avcodec.h" #include "cbs.h" #include "cbs_av1.h" -#include "parser.h" +#include "parser_internal.h" typedef struct AV1ParseContext { CodedBitstreamContext *cbc; @@ -82,7 +84,7 @@ static int av1_parser_parse(AVCodecParserContext *ctx, ff_cbs_fragment_reset(td); } - ret = ff_cbs_read(s->cbc, td, data, size); + ret = ff_cbs_read(s->cbc, td, NULL, data, size); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to parse temporal unit.\n"); goto end; @@ -132,6 +134,13 @@ static int av1_parser_parse(AVCodecParserContext *ctx, break; } ctx->picture_structure = AV_PICTURE_STRUCTURE_FRAME; + + /* Extract SAR from render_height_minus_1 & render_width_minus_1 */ + av_reduce(&avctx->sample_aspect_ratio.num, + &avctx->sample_aspect_ratio.den, + (int64_t)ctx->height * (frame->render_width_minus_1 + 1), + (int64_t)ctx->width * (frame->render_height_minus_1 + 1), + INT_MAX); } switch (av1->bit_depth) { @@ -183,6 +192,7 @@ static const CodedBitstreamUnitType decompose_unit_types[] = { AV1_OBU_FRAME_HEADER, AV1_OBU_TILE_GROUP, AV1_OBU_FRAME, + AV1_OBU_REDUNDANT_FRAME_HEADER, }; static av_cold int av1_parser_init(AVCodecParserContext *ctx) @@ -200,7 +210,7 @@ static av_cold int av1_parser_init(AVCodecParserContext *ctx) return 0; } -static void av1_parser_close(AVCodecParserContext *ctx) +static av_cold void av1_parser_close(AVCodecParserContext *ctx) { AV1ParseContext *s = ctx->priv_data; @@ -208,10 +218,10 @@ static void av1_parser_close(AVCodecParserContext *ctx) ff_cbs_close(&s->cbc); } -const AVCodecParser ff_av1_parser = { - .codec_ids = { AV_CODEC_ID_AV1 }, +const FFCodecParser ff_av1_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_AV1), .priv_data_size = sizeof(AV1ParseContext), - .parser_init = av1_parser_init, - .parser_close = av1_parser_close, - .parser_parse = av1_parser_parse, + .init = av1_parser_init, + .close = av1_parser_close, + .parse = av1_parser_parse, }; diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c index d921def59..2b3a36aa5 100644 --- a/libavcodec/av1dec.c +++ b/libavcodec/av1dec.c @@ -20,6 +20,7 @@ #include "config_components.h" +#include "libavutil/attributes.h" #include "libavutil/hdr_dynamic_metadata.h" #include "libavutil/film_grain_params.h" #include "libavutil/mastering_display_metadata.h" @@ -39,9 +40,9 @@ #include "hwconfig.h" #include "profiles.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" -/**< same with Div_Lut defined in spec 7.11.3.7 */ +/** same with Div_Lut defined in spec 7.11.3.7 */ static const uint16_t div_lut[AV1_DIV_LUT_NUM] = { 16384, 16320, 16257, 16194, 16132, 16070, 16009, 15948, 15888, 15828, 15768, 15709, 15650, 15592, 15534, 15477, 15420, 15364, 15308, 15252, 15197, 15142, @@ -282,6 +283,8 @@ static void skip_mode_params(AV1DecContext *s) forward_idx = -1; backward_idx = -1; for (i = 0; i < AV1_REFS_PER_FRAME; i++) { + if (!s->ref[header->ref_frame_idx[i]].raw_frame_header) + return; ref_hint = s->ref[header->ref_frame_idx[i]].raw_frame_header->order_hint; dist = get_relative_dist(seq, ref_hint, header->order_hint); if (dist < 0) { @@ -542,6 +545,7 @@ static int get_pixel_format(AVCodecContext *avctx) CONFIG_AV1_NVDEC_HWACCEL + \ CONFIG_AV1_VAAPI_HWACCEL + \ CONFIG_AV1_VDPAU_HWACCEL + \ + CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + \ CONFIG_AV1_VULKAN_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts; @@ -569,6 +573,9 @@ static int get_pixel_format(AVCodecContext *avctx) #if CONFIG_AV1_VDPAU_HWACCEL *fmtp++ = AV_PIX_FMT_VDPAU; #endif +#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + *fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX; +#endif #if CONFIG_AV1_VULKAN_HWACCEL *fmtp++ = AV_PIX_FMT_VULKAN; #endif @@ -593,6 +600,9 @@ static int get_pixel_format(AVCodecContext *avctx) #if CONFIG_AV1_VDPAU_HWACCEL *fmtp++ = AV_PIX_FMT_VDPAU; #endif +#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + *fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX; +#endif #if CONFIG_AV1_VULKAN_HWACCEL *fmtp++ = AV_PIX_FMT_VULKAN; #endif @@ -679,8 +689,8 @@ static int get_pixel_format(AVCodecContext *avctx) static void av1_frame_unref(AV1Frame *f) { ff_progress_frame_unref(&f->pf); - ff_refstruct_unref(&f->hwaccel_picture_private); - ff_refstruct_unref(&f->header_ref); + av_refstruct_unref(&f->hwaccel_picture_private); + av_refstruct_unref(&f->header_ref); f->raw_frame_header = NULL; f->spatial_id = f->temporal_id = 0; memset(f->skip_mode_frame_idx, 0, @@ -693,13 +703,13 @@ static void av1_frame_replace(AV1Frame *dst, const AV1Frame *src) { av_assert1(dst != src); - ff_refstruct_replace(&dst->header_ref, src->header_ref); + av_refstruct_replace(&dst->header_ref, src->header_ref); dst->raw_frame_header = src->raw_frame_header; ff_progress_frame_replace(&dst->pf, &src->pf); - ff_refstruct_replace(&dst->hwaccel_picture_private, + av_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); dst->spatial_id = src->spatial_id; @@ -739,10 +749,10 @@ static av_cold int av1_decode_free(AVCodecContext *avctx) av1_frame_unref(&s->ref[i]); av1_frame_unref(&s->cur_frame); av_buffer_unref(&s->seq_data_ref); - ff_refstruct_unref(&s->seq_ref); - ff_refstruct_unref(&s->header_ref); - ff_refstruct_unref(&s->cll_ref); - ff_refstruct_unref(&s->mdcv_ref); + av_refstruct_unref(&s->seq_ref); + av_refstruct_unref(&s->header_ref); + av_refstruct_unref(&s->cll_ref); + av_refstruct_unref(&s->mdcv_ref); av_freep(&s->tile_group_info); while (s->itut_t35_fifo && av_fifo_read(s->itut_t35_fifo, &itut_t35, 1) >= 0) @@ -765,11 +775,13 @@ static int set_context_with_sequence(AVCodecContext *avctx, avctx->profile = seq->seq_profile; avctx->level = seq->seq_level_idx[0]; - avctx->color_range = - seq->color_config.color_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; - avctx->color_primaries = seq->color_config.color_primaries; - avctx->colorspace = seq->color_config.matrix_coefficients; - avctx->color_trc = seq->color_config.transfer_characteristics; + if (seq->color_config.color_description_present_flag) { + avctx->color_range = + seq->color_config.color_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + avctx->color_primaries = seq->color_config.color_primaries; + avctx->colorspace = seq->color_config.matrix_coefficients; + avctx->color_trc = seq->color_config.transfer_characteristics; + } switch (seq->color_config.chroma_sample_position) { case AV1_CSP_VERTICAL: @@ -780,10 +792,14 @@ static int set_context_with_sequence(AVCodecContext *avctx, break; } +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS if (seq->film_grain_params_present) avctx->properties |= FF_CODEC_PROPERTY_FILM_GRAIN; else avctx->properties &= ~FF_CODEC_PROPERTY_FILM_GRAIN; +FF_ENABLE_DEPRECATION_WARNINGS +#endif if (avctx->width != width || avctx->height != height) { int ret = ff_set_dimensions(avctx, width, height); @@ -878,7 +894,8 @@ static av_cold int av1_decode_init(AVCodecContext *avctx) seq = ((CodedBitstreamAV1Context *)(s->cbc->priv_data))->sequence_header; if (!seq) { - av_log(avctx, AV_LOG_WARNING, "No sequence header available.\n"); + if (!(avctx->extradata[0] & 0x80)) + av_log(avctx, AV_LOG_WARNING, "No sequence header available in extradata.\n"); goto end; } @@ -953,13 +970,13 @@ static int export_itut_t35(AVCodecContext *avctx, AVFrame *frame, { GetByteContext gb; AV1DecContext *s = avctx->priv_data; - int ret, provider_code; + int ret, provider_code, country_code; bytestream2_init(&gb, itut_t35->payload, itut_t35->payload_size); provider_code = bytestream2_get_be16(&gb); - switch (provider_code) { - case ITU_T_T35_PROVIDER_CODE_ATSC: { + country_code = itut_t35->itu_t_t35_country_code ; + if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_ATSC) { uint32_t user_identifier = bytestream2_get_be32(&gb); switch (user_identifier) { case MKBETAG('G', 'A', '9', '4'): { // closed captions @@ -975,22 +992,23 @@ static int export_itut_t35(AVCodecContext *avctx, AVFrame *frame, if (ret < 0) return ret; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif break; } default: // ignore unsupported identifiers break; } - break; - } - case ITU_T_T35_PROVIDER_CODE_SMTPE: { + } else if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_SAMSUNG) { AVDynamicHDRPlus *hdrplus; int provider_oriented_code = bytestream2_get_be16(&gb); int application_identifier = bytestream2_get_byte(&gb); - if (itut_t35->itu_t_t35_country_code != ITU_T_T35_COUNTRY_CODE_US || - provider_oriented_code != 1 || application_identifier != 4) - break; + if (provider_oriented_code != 1 || application_identifier != 4) + return 0; // ignore hdrplus = av_dynamic_hdr_plus_create_side_data(frame); if (!hdrplus) @@ -1000,28 +1018,23 @@ static int export_itut_t35(AVCodecContext *avctx, AVFrame *frame, bytestream2_get_bytes_left(&gb)); if (ret < 0) return ret; - break; - } - case ITU_T_T35_PROVIDER_CODE_DOLBY: { + } else if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_DOLBY) { int provider_oriented_code = bytestream2_get_be32(&gb); - if (itut_t35->itu_t_t35_country_code != ITU_T_T35_COUNTRY_CODE_US || - provider_oriented_code != 0x800) - break; + if (provider_oriented_code != 0x800) + return 0; // ignore - ret = ff_dovi_rpu_parse(&s->dovi, gb.buffer, gb.buffer_end - gb.buffer, + ret = ff_dovi_rpu_parse(&s->dovi, gb.buffer, bytestream2_get_bytes_left(&gb), avctx->err_recognition); if (ret < 0) { av_log(avctx, AV_LOG_WARNING, "Error parsing DOVI OBU.\n"); - break; // ignore + return 0; // ignore } ret = ff_dovi_attach_side_data(&s->dovi, frame); if (ret < 0) return ret; - break; - } - default: // ignore unsupported provider codes - break; + } else { + // ignore unsupported provider codes } return 0; @@ -1180,12 +1193,6 @@ static int set_output_frame(AVCodecContext *avctx, AVFrame *frame) frame->pts = pkt->pts; frame->pkt_dts = pkt->dts; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frame->pkt_size = pkt->size; - frame->pkt_pos = pkt->pos; -FF_ENABLE_DEPRECATION_WARNINGS -#endif av_packet_unref(pkt); @@ -1210,7 +1217,7 @@ static int get_current_frame(AVCodecContext *avctx) av1_frame_unref(&s->cur_frame); - s->cur_frame.header_ref = ff_refstruct_ref(s->header_ref); + s->cur_frame.header_ref = av_refstruct_ref(s->header_ref); s->cur_frame.raw_frame_header = s->raw_frame_header; @@ -1298,7 +1305,7 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) s->seq_data_ref->data = unit->data; s->seq_data_ref->size = unit->data_size; - ff_refstruct_replace(&s->seq_ref, unit->content_ref); + av_refstruct_replace(&s->seq_ref, unit->content_ref); s->raw_seq = &obu->obu.sequence_header; s->raw_frame_header = NULL; @@ -1315,6 +1322,15 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) s->pix_fmt = AV_PIX_FMT_NONE; + if (FF_HW_HAS_CB(avctx, decode_params)) { + ret = FF_HW_CALL(avctx, decode_params, AV1_OBU_SEQUENCE_HEADER, + s->seq_data_ref->data, s->seq_data_ref->size); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "HW accel decode params fail.\n"); + return ret; + } + } + break; case AV1_OBU_REDUNDANT_FRAME_HEADER: if (s->raw_frame_header) @@ -1328,7 +1344,7 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) goto end; } - ff_refstruct_replace(&s->header_ref, unit->content_ref); + av_refstruct_replace(&s->header_ref, unit->content_ref); raw_tile_group = NULL; @@ -1368,7 +1384,8 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) s->cur_frame.temporal_id = header->temporal_id; if (avctx->hwaccel && s->cur_frame.f) { - ret = FF_HW_CALL(avctx, start_frame, unit->data, unit->data_size); + ret = FF_HW_CALL(avctx, start_frame, s->pkt->buf, + unit->data, unit->data_size); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "HW accel start frame fail.\n"); goto end; @@ -1413,11 +1430,11 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) case AV1_OBU_METADATA: switch (obu->obu.metadata.metadata_type) { case AV1_METADATA_TYPE_HDR_CLL: - ff_refstruct_replace(&s->cll_ref, unit->content_ref); + av_refstruct_replace(&s->cll_ref, unit->content_ref); s->cll = &obu->obu.metadata.metadata.hdr_cll; break; case AV1_METADATA_TYPE_HDR_MDCV: - ff_refstruct_replace(&s->mdcv_ref, unit->content_ref); + av_refstruct_replace(&s->mdcv_ref, unit->content_ref); s->mdcv = &obu->obu.metadata.metadata.hdr_mdcv; break; case AV1_METADATA_TYPE_ITUT_T35: { @@ -1441,12 +1458,16 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) break; default: av_log(avctx, AV_LOG_DEBUG, - "Unknown obu type: %d (%"SIZE_SPECIFIER" bits).\n", + "Unknown obu type: %d (%zu bits).\n", unit->type, unit->data_size); } if (raw_tile_group && (s->tile_num == raw_tile_group->tg_end + 1)) { int show_frame = s->raw_frame_header->show_frame; + // Set nb_unit to point at the next OBU, to indicate which + // OBUs have been processed for this current frame. (If this + // frame gets output, we set nb_unit to this value later too.) + s->nb_unit = i + 1; if (avctx->hwaccel && s->cur_frame.f) { ret = FF_HW_SIMPLE_CALL(avctx, end_frame); if (ret < 0) { @@ -1457,6 +1478,8 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) update_reference_list(avctx); + // Set start_unit to indicate the first OBU of the next frame. + s->start_unit = s->nb_unit; raw_tile_group = NULL; s->raw_frame_header = NULL; @@ -1486,7 +1509,7 @@ end: s->raw_frame_header = NULL; av_packet_unref(s->pkt); ff_cbs_fragment_reset(&s->current_obu); - s->nb_unit = 0; + s->nb_unit = s->start_unit = 0; } if (!ret && !frame->buf[0]) ret = AVERROR(EAGAIN); @@ -1513,7 +1536,7 @@ static int av1_receive_frame(AVCodecContext *avctx, AVFrame *frame) return ret; } - s->nb_unit = 0; + s->nb_unit = s->start_unit = 0; av_log(avctx, AV_LOG_DEBUG, "Total OBUs on this packet: %d.\n", s->current_obu.nb_units); } @@ -1524,7 +1547,7 @@ static int av1_receive_frame(AVCodecContext *avctx, AVFrame *frame) return ret; } -static void av1_decode_flush(AVCodecContext *avctx) +static av_cold void av1_decode_flush(AVCodecContext *avctx) { AV1DecContext *s = avctx->priv_data; AV1RawMetadataITUTT35 itut_t35; @@ -1534,7 +1557,7 @@ static void av1_decode_flush(AVCodecContext *avctx) av1_frame_unref(&s->cur_frame); s->operating_point_idc = 0; - s->nb_unit = 0; + s->nb_unit = s->start_unit = 0; s->raw_frame_header = NULL; s->raw_seq = NULL; s->cll = NULL; @@ -1602,6 +1625,9 @@ const FFCodec ff_av1_decoder = { #if CONFIG_AV1_VDPAU_HWACCEL HWACCEL_VDPAU(av1), #endif +#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(av1), +#endif #if CONFIG_AV1_VULKAN_HWACCEL HWACCEL_VULKAN(av1), #endif diff --git a/libavcodec/av1dec.h b/libavcodec/av1dec.h index 8b2a7b089..10c807f73 100644 --- a/libavcodec/av1dec.h +++ b/libavcodec/av1dec.h @@ -114,7 +114,8 @@ typedef struct AV1DecContext { AV1Frame ref[AV1_NUM_REF_FRAMES]; AV1Frame cur_frame; - int nb_unit; + int nb_unit; ///< The index of the next OBU to be processed. + int start_unit; ///< The index of the first OBU of the current frame. // AVOptions int operating_point; diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c index 1fa8704c9..9ff4c7f31 100644 --- a/libavcodec/avcodec.c +++ b/libavcodec/avcodec.c @@ -23,6 +23,8 @@ * AVCodecContext functions for libavcodec */ +#include + #include "config.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -30,7 +32,6 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/emms.h" -#include "libavutil/fifo.h" #include "libavutil/imgutils.h" #include "libavutil/mem.h" #include "libavutil/opt.h" @@ -41,12 +42,10 @@ #include "codec_desc.h" #include "codec_internal.h" #include "decode.h" -#include "encode.h" #include "frame_thread_encoder.h" #include "hwconfig.h" #include "internal.h" -#include "refstruct.h" -#include "thread.h" +#include "libavutil/refstruct.h" /** * Maximum size in bytes of extradata. @@ -65,6 +64,8 @@ const SideDataMap ff_sd_global_map[] = { { AV_PKT_DATA_CONTENT_LIGHT_LEVEL, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL }, { AV_PKT_DATA_ICC_PROFILE, AV_FRAME_DATA_ICC_PROFILE }, { AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT,AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT }, + { AV_PKT_DATA_3D_REFERENCE_DISPLAYS, AV_FRAME_DATA_3D_REFERENCE_DISPLAYS }, + { AV_PKT_DATA_EXIF, AV_FRAME_DATA_EXIF }, { AV_PKT_DATA_NB }, }; @@ -190,7 +191,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code return AVERROR(EINVAL); } - avci = av_codec_is_decoder(codec) ? + avci = ff_codec_is_decoder(codec) ? ff_decode_internal_alloc() : ff_encode_internal_alloc(); if (!avci) { @@ -254,7 +255,11 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code } } - if (avctx->sample_rate < 0) { + /* AV_CODEC_CAP_CHANNEL_CONF is a decoder-only flag; so the code below + * in particular checks that sample_rate is set for all audio encoders. */ + if (avctx->sample_rate < 0 || + avctx->sample_rate == 0 && avctx->codec_type == AVMEDIA_TYPE_AUDIO && + !(codec->capabilities & AV_CODEC_CAP_CHANNEL_CONF)) { av_log(avctx, AV_LOG_ERROR, "Invalid sample rate: %d\n", avctx->sample_rate); ret = AVERROR(EINVAL); goto free_and_end; @@ -270,7 +275,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && !avctx->ch_layout.nb_channels && !(codec->capabilities & AV_CODEC_CAP_CHANNEL_CONF)) { av_log(avctx, AV_LOG_ERROR, "%s requires channel layout to be set\n", - av_codec_is_decoder(codec) ? "Decoder" : "Encoder"); + ff_codec_is_decoder(codec) ? "Decoder" : "Encoder"); ret = AVERROR(EINVAL); goto free_and_end; } @@ -290,13 +295,13 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code if ((avctx->codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL) && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { - const char *codec_string = av_codec_is_encoder(codec) ? "encoder" : "decoder"; + const char *codec_string = ff_codec_is_encoder(codec) ? "encoder" : "decoder"; const AVCodec *codec2; av_log(avctx, AV_LOG_ERROR, "The %s '%s' is experimental but experimental codecs are not enabled, " "add '-strict %d' if you want to use it.\n", codec_string, codec->name, FF_COMPLIANCE_EXPERIMENTAL); - codec2 = av_codec_is_encoder(codec) ? avcodec_find_encoder(codec->id) : avcodec_find_decoder(codec->id); + codec2 = ff_codec_is_encoder(codec) ? avcodec_find_encoder(codec->id) : avcodec_find_decoder(codec->id); if (!(codec2->capabilities & AV_CODEC_CAP_EXPERIMENTAL)) av_log(avctx, AV_LOG_ERROR, "Alternatively use the non experimental %s '%s'.\n", codec_string, codec2->name); @@ -310,7 +315,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code avctx->time_base.den = avctx->sample_rate; } - if (av_codec_is_encoder(avctx->codec)) + if (ff_codec_is_encoder(avctx->codec)) ret = ff_encode_preinit(avctx); else ret = ff_decode_preinit(avctx); @@ -345,10 +350,12 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code ret=0; - if (av_codec_is_decoder(avctx->codec)) { + if (ff_codec_is_decoder(avctx->codec)) { if (!avctx->bit_rate) avctx->bit_rate = get_bit_rate(avctx); + avci->skip_samples = avctx->delay; + /* validate channel layout from the decoder */ if ((avctx->ch_layout.nb_channels && !av_channel_layout_check(&avctx->ch_layout)) || avctx->ch_layout.nb_channels > FF_SANE_NB_CHANNELS) { @@ -429,16 +436,14 @@ av_cold void ff_codec_close(AVCodecContext *avctx) { int i; - if (!avctx) - return; - if (avcodec_is_open(avctx)) { AVCodecInternal *avci = avctx->internal; - if (CONFIG_FRAME_THREAD_ENCODER && - avci->frame_thread_encoder && avctx->thread_count > 1) { +#if CONFIG_FRAME_THREAD_ENCODER + if (avci->frame_thread_encoder && avctx->thread_count > 1) { ff_frame_thread_encoder_free(avctx); } +#endif if (HAVE_THREADS && avci->thread_ctx) ff_thread_free(avctx); if (avci->needs_close && ffcodec(avctx->codec)->close) @@ -453,8 +458,8 @@ av_cold void ff_codec_close(AVCodecContext *avctx) av_frame_free(&avci->in_frame); av_frame_free(&avci->recon_frame); - ff_refstruct_unref(&avci->pool); - ff_refstruct_pool_uninit(&avci->progress_frame_pool); + av_refstruct_unref(&avci->pool); + av_refstruct_pool_uninit(&avci->progress_frame_pool); if (av_codec_is_decoder(avctx->codec)) ff_decode_internal_uninit(avctx); @@ -462,10 +467,6 @@ av_cold void ff_codec_close(AVCodecContext *avctx) av_bsf_free(&avci->bsf); -#if FF_API_DROPCHANGED - av_channel_layout_uninit(&avci->initial_ch_layout); -#endif - #if CONFIG_LCMS2 ff_icc_context_uninit(&avci->icc); #endif @@ -497,14 +498,6 @@ av_cold void ff_codec_close(AVCodecContext *avctx) avctx->active_thread_type = 0; } -#if FF_API_AVCODEC_CLOSE -int avcodec_close(AVCodecContext *avctx) -{ - ff_codec_close(avctx); - return 0; -} -#endif - static const char *unknown_if_null(const char *str) { return str ? str : "unknown"; @@ -647,12 +640,16 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode) if (encode) { av_bprintf(&bprint, ", q=%d-%d", enc->qmin, enc->qmax); } else { +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS if (enc->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS) av_bprintf(&bprint, ", Closed Captions"); if (enc->properties & FF_CODEC_PROPERTY_FILM_GRAIN) av_bprintf(&bprint, ", Film Grain"); if (enc->properties & FF_CODEC_PROPERTY_LOSSLESS) av_bprintf(&bprint, ", lossless"); +FF_ENABLE_DEPRECATION_WARNINGS +#endif } break; case AVMEDIA_TYPE_AUDIO: @@ -710,48 +707,62 @@ int avcodec_is_open(AVCodecContext *s) return !!s->internal; } -int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) +int attribute_align_arg avcodec_receive_frame_flags(AVCodecContext *avctx, + AVFrame *frame, unsigned flags) { av_frame_unref(frame); - if (av_codec_is_decoder(avctx->codec)) - return ff_decode_receive_frame(avctx, frame); + if (!avcodec_is_open(avctx) || !avctx->codec) + return AVERROR(EINVAL); + + if (ff_codec_is_decoder(avctx->codec)) + return ff_decode_receive_frame(avctx, frame, flags); return ff_encode_receive_frame(avctx, frame); } -#define WRAP_CONFIG(allowed_type, field, field_type, terminator) \ +int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + return avcodec_receive_frame_flags(avctx, frame, 0); +} + +#define WRAP_CONFIG(allowed_type, field, var, field_type, sentinel_check) \ do { \ - static const field_type end = terminator; \ if (codec->type != (allowed_type)) \ return AVERROR(EINVAL); \ - *out_configs = (field); \ - if (out_num_configs) { \ + const field_type *ptr = codec->field; \ + *out_configs = ptr; \ + if (ptr) { \ for (int i = 0;; i++) { \ - if (!(field) || !memcmp(&(field)[i], &end, sizeof(end))) { \ + const field_type var = ptr[i]; \ + if (sentinel_check) { \ *out_num_configs = i; \ break; \ } \ } \ - } \ + } else \ + *out_num_configs = 0; \ return 0; \ } while (0) -static const enum AVColorRange color_range_jpeg[] = { - AVCOL_RANGE_JPEG, AVCOL_RANGE_UNSPECIFIED +static const enum AVColorRange color_range_tab[] = { + AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG, AVCOL_RANGE_UNSPECIFIED, + AVCOL_RANGE_MPEG, AVCOL_RANGE_UNSPECIFIED, }; -static const enum AVColorRange color_range_mpeg[] = { - AVCOL_RANGE_MPEG, AVCOL_RANGE_UNSPECIFIED +static const enum AVAlphaMode alpha_mode_tab[] = { + AVALPHA_MODE_PREMULTIPLIED, AVALPHA_MODE_STRAIGHT, AVALPHA_MODE_UNSPECIFIED, + AVALPHA_MODE_PREMULTIPLIED, AVALPHA_MODE_UNSPECIFIED }; -static const enum AVColorRange color_range_all[] = { - AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG, AVCOL_RANGE_UNSPECIFIED -}; +static_assert((int)AVCOL_RANGE_MPEG == (int)AVALPHA_MODE_PREMULTIPLIED, "unexpected enum values"); +static_assert((int)AVCOL_RANGE_JPEG == (int)AVALPHA_MODE_STRAIGHT, "unexpected enum values"); +static_assert(AVCOL_RANGE_UNSPECIFIED == 0 && AVALPHA_MODE_UNSPECIFIED == 0, "unexpected enum values"); +static_assert(AVCOL_RANGE_NB == 3 && AVALPHA_MODE_NB == 3, "unexpected enum values"); -static const enum AVColorRange *color_range_table[] = { - [AVCOL_RANGE_MPEG] = color_range_mpeg, - [AVCOL_RANGE_JPEG] = color_range_jpeg, - [AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG] = color_range_all, +static const uint8_t offset_tab[] = { + [AVCOL_RANGE_MPEG] = 3, + [AVCOL_RANGE_JPEG] = 1, + [AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG] = 0, }; int ff_default_get_supported_config(const AVCodecContext *avctx, @@ -761,33 +772,49 @@ int ff_default_get_supported_config(const AVCodecContext *avctx, const void **out_configs, int *out_num_configs) { + const FFCodec *codec2 = ffcodec(codec); + switch (config) { FF_DISABLE_DEPRECATION_WARNINGS case AV_CODEC_CONFIG_PIX_FORMAT: - WRAP_CONFIG(AVMEDIA_TYPE_VIDEO, codec->pix_fmts, enum AVPixelFormat, AV_PIX_FMT_NONE); + WRAP_CONFIG(AVMEDIA_TYPE_VIDEO, pix_fmts, pix_fmt, enum AVPixelFormat, pix_fmt == AV_PIX_FMT_NONE); case AV_CODEC_CONFIG_FRAME_RATE: - WRAP_CONFIG(AVMEDIA_TYPE_VIDEO, codec->supported_framerates, AVRational, {0}); + WRAP_CONFIG(AVMEDIA_TYPE_VIDEO, supported_framerates, framerate, AVRational, framerate.num == 0); case AV_CODEC_CONFIG_SAMPLE_RATE: - WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, codec->supported_samplerates, int, 0); + WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, supported_samplerates, samplerate, int, samplerate == 0); case AV_CODEC_CONFIG_SAMPLE_FORMAT: - WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, codec->sample_fmts, enum AVSampleFormat, AV_SAMPLE_FMT_NONE); + WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, sample_fmts, sample_fmt, enum AVSampleFormat, sample_fmt == AV_SAMPLE_FMT_NONE); case AV_CODEC_CONFIG_CHANNEL_LAYOUT: - WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, codec->ch_layouts, AVChannelLayout, {0}); + WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, ch_layouts, ch_layout, AVChannelLayout, ch_layout.nb_channels == 0); FF_ENABLE_DEPRECATION_WARNINGS case AV_CODEC_CONFIG_COLOR_RANGE: if (codec->type != AVMEDIA_TYPE_VIDEO) return AVERROR(EINVAL); - *out_configs = color_range_table[ffcodec(codec)->color_ranges]; - if (out_num_configs) - *out_num_configs = av_popcount(ffcodec(codec)->color_ranges); + unsigned color_ranges = codec2->color_ranges; + if (color_ranges) + *out_configs = color_range_tab + offset_tab[color_ranges]; + else + *out_configs = NULL; + *out_num_configs = av_popcount(color_ranges); return 0; case AV_CODEC_CONFIG_COLOR_SPACE: *out_configs = NULL; - if (out_num_configs) - *out_num_configs = 0; + *out_num_configs = 0; return 0; + + case AV_CODEC_CONFIG_ALPHA_MODE: + if (codec->type != AVMEDIA_TYPE_VIDEO) + return AVERROR(EINVAL); + unsigned alpha_modes = codec2->alpha_modes; + if (alpha_modes) + *out_configs = alpha_mode_tab + offset_tab[alpha_modes]; + else + *out_configs = NULL; + *out_num_configs = av_popcount(alpha_modes); + return 0; + default: return AVERROR(EINVAL); } @@ -811,3 +838,53 @@ int avcodec_get_supported_config(const AVCodecContext *avctx, const AVCodec *cod return ff_default_get_supported_config(avctx, codec, config, flags, out, out_num); } } + +int av_packet_side_data_from_frame(AVPacketSideData **psd, int *pnb_sd, + const AVFrameSideData *src, unsigned int flags) +{ + AVPacketSideData *sd = NULL; + + for (unsigned j = 0; ff_sd_global_map[j].packet < AV_PKT_DATA_NB; j++) { + if (ff_sd_global_map[j].frame != src->type) + continue; + + sd = av_packet_side_data_new(psd, pnb_sd, ff_sd_global_map[j].packet, + src->size, 0); + + if (!sd) + return AVERROR(ENOMEM); + + memcpy(sd->data, src->data, src->size); + break; + } + + if (!sd) + return AVERROR(EINVAL); + + return 0; +} + +int av_packet_side_data_to_frame(AVFrameSideData ***psd, int *pnb_sd, + const AVPacketSideData *src, unsigned int flags) +{ + AVFrameSideData *sd = NULL; + + for (unsigned j = 0; ff_sd_global_map[j].packet < AV_PKT_DATA_NB; j++) { + if (ff_sd_global_map[j].packet != src->type) + continue; + + sd = av_frame_side_data_new(psd, pnb_sd, ff_sd_global_map[j].frame, + src->size, flags); + + if (!sd) + return AVERROR(ENOMEM); + + memcpy(sd->data, src->data, src->size); + break; + } + + if (!sd) + return AVERROR(EINVAL); + + return 0; +} diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 77ca8dee1..6824bfc9a 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -187,17 +187,6 @@ struct AVCodecParameters; * @{ */ -#if FF_API_BUFFER_MIN_SIZE -/** - * @ingroup lavc_encoding - * minimum encoding buffer size - * Used to avoid some checks during header writing. - * @deprecated Unused: avcodec_receive_packet() does not work - * with preallocated packet buffers. - */ -#define AV_INPUT_BUFFER_MIN_SIZE 16384 -#endif - /** * @ingroup lavc_encoding */ @@ -234,18 +223,9 @@ typedef struct RcOverride{ * Use qpel MC. */ #define AV_CODEC_FLAG_QPEL (1 << 4) -#if FF_API_DROPCHANGED -/** - * Don't output frames whose parameters differ from first - * decoded frame in stream. - * - * @deprecated callers should implement this functionality in their own code - */ -#define AV_CODEC_FLAG_DROPCHANGED (1 << 5) -#endif /** * Request the encoder to output reconstructed frames, i.e.\ frames that would - * be produced by decoding the encoded bistream. These frames may be retrieved + * be produced by decoding the encoded bitstream. These frames may be retrieved * by calling avcodec_receive_frame() immediately after a successful call to * avcodec_receive_packet(). * @@ -435,6 +415,14 @@ typedef struct RcOverride{ */ #define AV_GET_ENCODE_BUFFER_FLAG_REF (1 << 0) +/** + * The decoder will bypass frame threading and return the next frame as soon as + * possible. Note that this may deliver frames earlier than the advertised + * `AVCodecContext.delay`. No effect when frame threading is disabled, or on + * encoding. + */ +#define AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS (1 << 0) + /** * main external API structure. * New fields can be added to the end with minor version bumps. @@ -515,16 +503,21 @@ typedef struct AVCodecContext { int flags2; /** - * some codecs need / can use extradata like Huffman tables. - * MJPEG: Huffman tables - * rv10: additional flags - * MPEG-4: global headers (they can be in the bitstream or here) - * The allocated memory should be AV_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. - * Must be allocated with the av_malloc() family of functions. - * - encoding: Set/allocated/freed by libavcodec. - * - decoding: Set/allocated/freed by user. + * Out-of-band global headers that may be used by some codecs. + * + * - decoding: Should be set by the caller when available (typically from a + * demuxer) before opening the decoder; some decoders require this to be + * set and will fail to initialize otherwise. + * + * The array must be allocated with the av_malloc() family of functions; + * allocated size must be at least AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than extradata_size. + * + * - encoding: May be set by the encoder in avcodec_open2() (possibly + * depending on whether the AV_CODEC_FLAG_GLOBAL_HEADER flag is set). + * + * After being set, the array is owned by the codec and freed in + * avcodec_free_context(). */ uint8_t *extradata; int extradata_size; @@ -565,23 +558,6 @@ typedef struct AVCodecContext { */ AVRational framerate; -#if FF_API_TICKS_PER_FRAME - /** - * 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. - * - * @deprecated - * - decoding: Use AVCodecDescriptor.props & AV_CODEC_PROP_FIELDS - * - encoding: Set AVCodecContext.framerate instead - * - */ - attribute_deprecated - int ticks_per_frame; -#endif - /** * Codec delay. * @@ -995,12 +971,16 @@ typedef struct AVCodecContext { */ uint16_t *chroma_intra_matrix; +#if FF_API_INTRA_DC_PRECISION /** * precision of the intra DC coefficient - 8 * - encoding: Set by user. * - decoding: Set by libavcodec + * @deprecated Use the MPEG-2 encoder's private option "intra_dc_precision" instead. */ + attribute_deprecated int intra_dc_precision; +#endif /** * minimum MB Lagrange multiplier @@ -1648,165 +1628,29 @@ typedef struct AVCodecContext { * See the AV_PROFILE_* defines in defs.h. */ int profile; -#if FF_API_FF_PROFILE_LEVEL - /** @deprecated The following defines are deprecated; use AV_PROFILE_* - * in defs.h instead. */ -#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_DNXHD 0 -#define FF_PROFILE_DNXHR_LB 1 -#define FF_PROFILE_DNXHR_SQ 2 -#define FF_PROFILE_DNXHR_HQ 3 -#define FF_PROFILE_DNXHR_HQX 4 -#define FF_PROFILE_DNXHR_444 5 - -#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_DTS_EXPRESS 70 -#define FF_PROFILE_DTS_HD_MA_X 61 -#define FF_PROFILE_DTS_HD_MA_X_IMAX 62 - - -#define FF_PROFILE_EAC3_DDP_ATMOS 30 - -#define FF_PROFILE_TRUEHD_ATMOS 30 - -#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_MULTIVIEW_HIGH 118 -#define FF_PROFILE_H264_HIGH_422 122 -#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA) -#define FF_PROFILE_H264_STEREO_HIGH 128 -#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 1 -#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 2 -#define FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 32768 -#define FF_PROFILE_JPEG2000_DCINEMA_2K 3 -#define FF_PROFILE_JPEG2000_DCINEMA_4K 4 - -#define FF_PROFILE_VP9_0 0 -#define FF_PROFILE_VP9_1 1 -#define FF_PROFILE_VP9_2 2 -#define FF_PROFILE_VP9_3 3 - -#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 -#define FF_PROFILE_HEVC_SCC 9 - -#define FF_PROFILE_VVC_MAIN_10 1 -#define FF_PROFILE_VVC_MAIN_10_444 33 - -#define FF_PROFILE_AV1_MAIN 0 -#define FF_PROFILE_AV1_HIGH 1 -#define FF_PROFILE_AV1_PROFESSIONAL 2 - -#define FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT 0xc0 -#define FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT 0xc1 -#define FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT 0xc2 -#define FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS 0xc3 -#define FF_PROFILE_MJPEG_JPEG_LS 0xf7 - -#define FF_PROFILE_SBC_MSBC 1 - -#define FF_PROFILE_PRORES_PROXY 0 -#define FF_PROFILE_PRORES_LT 1 -#define FF_PROFILE_PRORES_STANDARD 2 -#define FF_PROFILE_PRORES_HQ 3 -#define FF_PROFILE_PRORES_4444 4 -#define FF_PROFILE_PRORES_XQ 5 - -#define FF_PROFILE_ARIB_PROFILE_A 0 -#define FF_PROFILE_ARIB_PROFILE_C 1 - -#define FF_PROFILE_KLVA_SYNC 0 -#define FF_PROFILE_KLVA_ASYNC 1 - -#define FF_PROFILE_EVC_BASELINE 0 -#define FF_PROFILE_EVC_MAIN 1 -#endif /** * Encoding level descriptor. * - encoding: Set by user, corresponds to a specific level defined by the * codec, usually corresponding to the profile level, if not specified it - * is set to FF_LEVEL_UNKNOWN. + * is set to AV_LEVEL_UNKNOWN. * - decoding: Set by libavcodec. * See AV_LEVEL_* in defs.h. */ int level; -#if FF_API_FF_PROFILE_LEVEL - /** @deprecated The following define is deprecated; use AV_LEVEL_UNKOWN - * in defs.h instead. */ -#define FF_LEVEL_UNKNOWN -99 -#endif +#if FF_API_CODEC_PROPS /** * Properties of the stream that gets decoded * - encoding: unused * - decoding: set by libavcodec */ + attribute_deprecated unsigned properties; #define FF_CODEC_PROPERTY_LOSSLESS 0x00000001 #define FF_CODEC_PROPERTY_CLOSED_CAPTIONS 0x00000002 #define FF_CODEC_PROPERTY_FILM_GRAIN 0x00000004 +#endif /** * Skip loop filtering for selected frames. @@ -1895,8 +1739,13 @@ typedef struct AVCodecContext { * 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()) + * + * - encoding: May be set by the caller before avcodec_open2() to an array + * allocated with the av_malloc() family of functions. + * - decoding: May be set by libavcodec in avcodec_open2(). + * + * After being set, the array is owned by the codec and freed in + * avcodec_free_context(). */ int subtitle_header_size; uint8_t *subtitle_header; @@ -2086,6 +1935,13 @@ typedef struct AVCodecContext { */ AVFrameSideData **decoded_side_data; int nb_decoded_side_data; + + /** + * Indicates how the alpha channel of the video is represented. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVAlphaMode alpha_mode; } AVCodecContext; /** @@ -2380,24 +2236,6 @@ int avcodec_parameters_to_context(AVCodecContext *codec, */ int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); -#if FF_API_AVCODEC_CLOSE -/** - * 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() with a non-NULL - * codec. Subsequent calls will do nothing. - * - * @deprecated Do not use this function. Use avcodec_free_context() to destroy a - * codec context (either open or closed). Opening and closing a codec context - * multiple times is not supported anymore -- use multiple codec contexts - * instead. - */ -attribute_deprecated -int avcodec_close(AVCodecContext *avctx); -#endif - /** * Free all allocated data in the given subtitle struct. * @@ -2534,6 +2372,7 @@ int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt); * frame (depending on the decoder type) allocated by the * codec. Note that the function will always call * av_frame_unref(frame) before doing anything else. + * @param flags Combination of AV_CODEC_RECEIVE_FRAME_FLAG_* flags. * * @retval 0 success, a frame was returned * @retval AVERROR(EAGAIN) output is not available in this state - user must @@ -2544,6 +2383,11 @@ int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt); * @ref AV_CODEC_FLAG_RECON_FRAME flag enabled * @retval "other negative error code" legitimate decoding errors */ +int avcodec_receive_frame_flags(AVCodecContext *avctx, AVFrame *frame, unsigned flags); + +/** + * Alias for `avcodec_receive_frame_flags(avctx, frame, 0)`. + */ int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame); /** @@ -2709,6 +2553,7 @@ enum AVCodecConfig { AV_CODEC_CONFIG_CHANNEL_LAYOUT, ///< AVChannelLayout, terminated by {0} AV_CODEC_CONFIG_COLOR_RANGE, ///< AVColorRange, terminated by AVCOL_RANGE_UNSPECIFIED AV_CODEC_CONFIG_COLOR_SPACE, ///< AVColorSpace, terminated by AVCOL_SPC_UNSPECIFIED + AV_CODEC_CONFIG_ALPHA_MODE, ///< AVAlphaMode, terminated by AVALPHA_MODE_UNSPECIFIED }; /** @@ -2905,17 +2750,35 @@ typedef struct AVCodecParserContext { } AVCodecParserContext; typedef struct AVCodecParser { +#if FF_API_PARSER_CODECID int codec_ids[7]; /* several codec IDs are permitted */ +#else + enum AVCodecID codec_ids[7]; /* several codec IDs are permitted */ +#endif +#if FF_API_PARSER_PRIVATE + /***************************************************************** + * All fields below this line are not 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. + ***************************************************************** + */ + attribute_deprecated int priv_data_size; + attribute_deprecated int (*parser_init)(AVCodecParserContext *s); /* This callback never returns an error, a negative value means that * the frame start was in a previous packet. */ + attribute_deprecated int (*parser_parse)(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size); + attribute_deprecated void (*parser_close)(AVCodecParserContext *s); + attribute_deprecated int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); +#endif } AVCodecParser; /** @@ -2929,7 +2792,11 @@ typedef struct AVCodecParser { */ const AVCodecParser *av_parser_iterate(void **opaque); +#if FF_API_PARSER_CODECID AVCodecParserContext *av_parser_init(int codec_id); +#else +AVCodecParserContext *av_parser_init(enum AVCodecID codec_id); +#endif /** * Parse a packet. @@ -3081,7 +2948,7 @@ int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels, * * @note for encoders, this function will only do something if the encoder * declares support for AV_CODEC_CAP_ENCODER_FLUSH. When called, the encoder - * will drain any remaining packets, and can then be re-used for a different + * will drain any remaining packets, and can then be reused for a different * stream (as opposed to sending a null frame which will leave the encoder * in a permanent EOF state after draining). This can be desirable if the * cost of tearing down and replacing the encoder instance is high. @@ -3116,8 +2983,8 @@ void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size); void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size); /** - * @return a positive value if s is open (i.e. avcodec_open2() was called on it - * with no corresponding avcodec_close()), 0 otherwise. + * @return a positive value if s is open (i.e. avcodec_open2() was called on it), + * 0 otherwise. */ int avcodec_is_open(AVCodecContext *s); diff --git a/libavcodec/avcodec_internal.h b/libavcodec/avcodec_internal.h index 184d7b526..06645e91a 100644 --- a/libavcodec/avcodec_internal.h +++ b/libavcodec/avcodec_internal.h @@ -45,7 +45,8 @@ extern const SideDataMap ff_sd_global_map[]; /** * avcodec_receive_frame() implementation for decoders. */ -int ff_decode_receive_frame(struct AVCodecContext *avctx, struct AVFrame *frame); +int ff_decode_receive_frame(struct AVCodecContext *avctx, struct AVFrame *frame, + unsigned flags); /** * avcodec_receive_frame() implementation for encoders. @@ -91,9 +92,10 @@ void ff_thread_flush(struct AVCodecContext *avctx); * Submit available packets for decoding to worker threads, return a * decoded frame if available. Returns AVERROR(EAGAIN) if none is available. * - * Parameters are the same as FFCodec.receive_frame. + * Parameters are the same as FFCodec.receive_frame, plus flags. */ -int ff_thread_receive_frame(struct AVCodecContext *avctx, AVFrame *frame); +int ff_thread_receive_frame(struct AVCodecContext *avctx, AVFrame *frame, + unsigned flags); /** * Do the actual decoding and obtain a decoded frame from the decoder, if diff --git a/libavcodec/avdct.c b/libavcodec/avdct.c index f995e73ea..f7941a457 100644 --- a/libavcodec/avdct.c +++ b/libavcodec/avdct.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "libavutil/mem.h" #include "avcodec.h" #include "idctdsp.h" @@ -68,12 +69,12 @@ static const AVClass avdct_class = { .version = LIBAVUTIL_VERSION_INT, }; -const AVClass *avcodec_dct_get_class(void) +av_cold const AVClass *avcodec_dct_get_class(void) { return &avdct_class; } -AVDCT *avcodec_dct_alloc(void) +av_cold AVDCT *avcodec_dct_alloc(void) { AVDCT *dsp = av_mallocz(sizeof(AVDCT)); @@ -86,7 +87,7 @@ AVDCT *avcodec_dct_alloc(void) return dsp; } -int avcodec_dct_init(AVDCT *dsp) +av_cold int avcodec_dct_init(AVDCT *dsp) { AVCodecContext *avctx = avcodec_alloc_context3(NULL); @@ -119,7 +120,7 @@ int avcodec_dct_init(AVDCT *dsp) #if CONFIG_PIXBLOCKDSP { PixblockDSPContext pdsp; - ff_pixblockdsp_init(&pdsp, avctx); + ff_pixblockdsp_init(&pdsp, dsp->bits_per_sample); COPY(pdsp, get_pixels); COPY(pdsp, get_pixels_unaligned); } diff --git a/libavcodec/avfft.c b/libavcodec/avfft.c deleted file mode 100644 index f6787937f..000000000 --- a/libavcodec/avfft.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * 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 "libavutil/attributes.h" -#include "libavutil/macros.h" -#include "libavutil/mem.h" -#include "libavutil/tx.h" -#include "avfft.h" - -typedef struct AVTXWrapper { - AVTXContext *ctx; - av_tx_fn fn; - - AVTXContext *ctx2; - av_tx_fn fn2; - - ptrdiff_t stride; - int len; - int inv; - - float *tmp; - int out_of_place; -} AVTXWrapper; - -/* FFT */ - -FFTContext *av_fft_init(int nbits, int inverse) -{ - int ret; - float scale = 1.0f; - AVTXWrapper *s = av_mallocz(sizeof(*s)); - if (!s) - return NULL; - - ret = av_tx_init(&s->ctx, &s->fn, AV_TX_FLOAT_FFT, inverse, 1 << nbits, - &scale, AV_TX_INPLACE); - if (ret < 0) { - av_free(s); - return NULL; - } - - return (FFTContext *)s; -} - -void av_fft_permute(FFTContext *s, FFTComplex *z) -{ - /* Empty */ -} - -void av_fft_calc(FFTContext *s, FFTComplex *z) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - w->fn(w->ctx, z, (void *)z, sizeof(AVComplexFloat)); -} - -av_cold void av_fft_end(FFTContext *s) -{ - if (s) { - AVTXWrapper *w = (AVTXWrapper *)s; - av_tx_uninit(&w->ctx); - av_tx_uninit(&w->ctx2); - av_free(w); - } -} - -FFTContext *av_mdct_init(int nbits, int inverse, double scale) -{ - int ret; - float scale_f = scale; - AVTXWrapper *s = av_mallocz(sizeof(*s)); - if (!s) - return NULL; - - ret = av_tx_init(&s->ctx, &s->fn, AV_TX_FLOAT_MDCT, inverse, 1 << (nbits - 1), &scale_f, 0); - if (ret < 0) { - av_free(s); - return NULL; - } - - if (inverse) { - ret = av_tx_init(&s->ctx2, &s->fn2, AV_TX_FLOAT_MDCT, inverse, 1 << (nbits - 1), - &scale_f, AV_TX_FULL_IMDCT); - if (ret < 0) { - av_tx_uninit(&s->ctx); - av_free(s); - return NULL; - } - } - - return (FFTContext *)s; -} - -void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - w->fn2(w->ctx2, output, (void *)input, sizeof(float)); -} - -void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - w->fn(w->ctx, output, (void *)input, sizeof(float)); -} - -void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - w->fn(w->ctx, output, (void *)input, sizeof(float)); -} - -av_cold void av_mdct_end(FFTContext *s) -{ - if (s) { - AVTXWrapper *w = (AVTXWrapper *)s; - av_tx_uninit(&w->ctx2); - av_tx_uninit(&w->ctx); - av_free(w); - } -} - -RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans) -{ - int ret; - float scale = trans == IDFT_C2R ? 0.5f : 1.0f; - AVTXWrapper *s; - - /* The other 2 modes are unconventional, do not form an orthogonal - * transform, have never been useful, and so they're not implemented. */ - if (trans != IDFT_C2R && trans != DFT_R2C) - return NULL; - - s = av_mallocz(sizeof(*s)); - if (!s) - return NULL; - - ret = av_tx_init(&s->ctx, &s->fn, AV_TX_FLOAT_RDFT, trans == IDFT_C2R, - 1 << nbits, &scale, 0x0); - if (ret < 0) { - av_free(s); - return NULL; - } - - s->stride = (trans == DFT_C2R) ? sizeof(AVComplexFloat) : sizeof(float); - s->len = 1 << nbits; - s->inv = trans == IDFT_C2R; - - s->tmp = av_malloc((s->len + 2)*sizeof(float)); - if (!s->tmp) { - av_tx_uninit(&s->ctx); - av_free(s); - return NULL; - } - - return (RDFTContext *)s; -} - -void av_rdft_calc(RDFTContext *s, FFTSample *data) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - float *src = w->inv ? w->tmp : (float *)data; - float *dst = w->inv ? (float *)data : w->tmp; - - if (w->inv) { - memcpy(src, data, w->len*sizeof(float)); - - src[w->len] = src[1]; - src[1] = 0.0f; - } - - w->fn(w->ctx, dst, (void *)src, w->stride); - - if (!w->inv) { - dst[1] = dst[w->len]; - memcpy(data, dst, w->len*sizeof(float)); - } -} - -av_cold void av_rdft_end(RDFTContext *s) -{ - if (s) { - AVTXWrapper *w = (AVTXWrapper *)s; - av_tx_uninit(&w->ctx); - av_free(w->tmp); - av_free(w); - } -} - -DCTContext *av_dct_init(int nbits, enum DCTTransformType inverse) -{ - int ret; - const float scale_map[] = { - [DCT_II] = 0.5f, - [DCT_III] = 1.0f / (1 << nbits), - [DCT_I] = 0.5f, - [DST_I] = 2.0f, - }; - static const enum AVTXType type_map[] = { - [DCT_II] = AV_TX_FLOAT_DCT, - [DCT_III] = AV_TX_FLOAT_DCT, - [DCT_I] = AV_TX_FLOAT_DCT_I, - [DST_I] = AV_TX_FLOAT_DST_I, - }; - - AVTXWrapper *s = av_mallocz(sizeof(*s)); - if (!s) - return NULL; - - s->len = (1 << nbits); - s->out_of_place = (inverse == DCT_I) || (inverse == DST_I); - - ret = av_tx_init(&s->ctx, &s->fn, type_map[inverse], - (inverse == DCT_III), 1 << (nbits - (inverse == DCT_III)), - &scale_map[inverse], s->out_of_place ? 0 : AV_TX_INPLACE); - if (ret < 0) { - av_free(s); - return NULL; - } - - if (s->out_of_place) { - s->tmp = av_malloc((1 << (nbits + 1))*sizeof(float)); - if (!s->tmp) { - av_tx_uninit(&s->ctx); - av_free(s); - return NULL; - } - } - - return (DCTContext *)s; -} - -void av_dct_calc(DCTContext *s, FFTSample *data) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - if (w->out_of_place) { - memcpy(w->tmp, data, w->len*sizeof(float)); - w->fn(w->ctx, (void *)data, w->tmp, sizeof(float)); - } else { - w->fn(w->ctx, data, (void *)data, sizeof(float)); - } -} - -av_cold void av_dct_end(DCTContext *s) -{ - if (s) { - AVTXWrapper *w = (AVTXWrapper *)s; - av_tx_uninit(&w->ctx); - av_free(w->tmp); - av_free(w); - } -} diff --git a/libavcodec/avfft.h b/libavcodec/avfft.h deleted file mode 100644 index e3a0da1eb..000000000 --- a/libavcodec/avfft.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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_AVFFT_H -#define AVCODEC_AVFFT_H - -#include "libavutil/attributes.h" -#include "version_major.h" -#if FF_API_AVFFT - -/** - * @file - * @ingroup lavc_fft - * FFT functions - */ - -/** - * @defgroup lavc_fft FFT functions - * @ingroup lavc_misc - * - * @{ - */ - -typedef float FFTSample; - -typedef struct FFTComplex { - FFTSample re, im; -} FFTComplex; - -typedef struct FFTContext FFTContext; - -/** - * Set up a complex FFT. - * @param nbits log2 of the length of the input array - * @param inverse if 0 perform the forward transform, if 1 perform the inverse - * @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_FFT - */ -attribute_deprecated -FFTContext *av_fft_init(int nbits, int inverse); - -/** - * Do the permutation needed BEFORE calling ff_fft_calc(). - * @deprecated without replacement - */ -attribute_deprecated -void av_fft_permute(FFTContext *s, FFTComplex *z); - -/** - * Do a complex FFT with the parameters defined in av_fft_init(). The - * input data must be permuted before. No 1.0/sqrt(n) normalization is done. - * @deprecated use the av_tx_fn value returned by av_tx_init, which also does permutation - */ -attribute_deprecated -void av_fft_calc(FFTContext *s, FFTComplex *z); - -attribute_deprecated -void av_fft_end(FFTContext *s); - -/** - * @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_MDCT, - * with a flag of AV_TX_FULL_IMDCT for a replacement to av_imdct_calc. - */ -attribute_deprecated -FFTContext *av_mdct_init(int nbits, int inverse, double scale); -attribute_deprecated -void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); -attribute_deprecated -void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input); -attribute_deprecated -void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); -attribute_deprecated -void av_mdct_end(FFTContext *s); - -/* Real Discrete Fourier Transform */ - -enum RDFTransformType { - DFT_R2C, - IDFT_C2R, - IDFT_R2C, - DFT_C2R, -}; - -typedef struct RDFTContext RDFTContext; - -/** - * Set up a real FFT. - * @param nbits log2 of the length of the input array - * @param trans the type of transform - * - * @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_RDFT - */ -attribute_deprecated -RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans); -attribute_deprecated -void av_rdft_calc(RDFTContext *s, FFTSample *data); -attribute_deprecated -void av_rdft_end(RDFTContext *s); - -/* Discrete Cosine Transform */ - -typedef struct DCTContext DCTContext; - -enum DCTTransformType { - DCT_II = 0, - DCT_III, - DCT_I, - DST_I, -}; - -/** - * Set up DCT. - * - * @param nbits size of the input array: - * (1 << nbits) for DCT-II, DCT-III and DST-I - * (1 << nbits) + 1 for DCT-I - * @param type the type of transform - * - * @note the first element of the input of DST-I is ignored - * - * @deprecated use av_tx_init from libavutil/tx.h with an appropriate type of AV_TX_FLOAT_DCT - */ -attribute_deprecated -DCTContext *av_dct_init(int nbits, enum DCTTransformType type); -attribute_deprecated -void av_dct_calc(DCTContext *s, FFTSample *data); -attribute_deprecated -void av_dct_end (DCTContext *s); - -/** - * @} - */ - -#endif /* FF_API_AVFFT */ -#endif /* AVCODEC_AVFFT_H */ diff --git a/libavcodec/avs2_parser.c b/libavcodec/avs2_parser.c index 0d68ab1d0..68b6f20c1 100644 --- a/libavcodec/avs2_parser.c +++ b/libavcodec/avs2_parser.c @@ -23,6 +23,7 @@ #include "avs2.h" #include "get_bits.h" #include "parser.h" +#include "parser_internal.h" static int avs2_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size) { @@ -189,9 +190,9 @@ static int avs2_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_avs2_parser = { - .codec_ids = { AV_CODEC_ID_AVS2 }, +const FFCodecParser ff_avs2_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_AVS2), .priv_data_size = sizeof(ParseContext), - .parser_parse = avs2_parse, - .parser_close = ff_parse_close, + .parse = avs2_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/avs3_parser.c b/libavcodec/avs3_parser.c index ea495b1c7..825eae052 100644 --- a/libavcodec/avs3_parser.c +++ b/libavcodec/avs3_parser.c @@ -24,6 +24,7 @@ #include "avs3.h" #include "get_bits.h" #include "parser.h" +#include "parser_internal.h" static int avs3_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size) { @@ -97,7 +98,7 @@ static void parse_avs3_nal_units(AVCodecParserContext *s, const uint8_t *buf, if (sample_precision == 1) { avctx->pix_fmt = AV_PIX_FMT_YUV420P; } else if (sample_precision == 2) { - avctx->pix_fmt = AV_PIX_FMT_YUV420P10LE; + avctx->pix_fmt = AV_PIX_FMT_YUV420P10; } else { avctx->pix_fmt = AV_PIX_FMT_NONE; } @@ -172,9 +173,9 @@ static int avs3_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_avs3_parser = { - .codec_ids = { AV_CODEC_ID_AVS3 }, +const FFCodecParser ff_avs3_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_AVS3), .priv_data_size = sizeof(ParseContext), - .parser_parse = avs3_parse, - .parser_close = ff_parse_close, + .parse = avs3_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/avuienc.c b/libavcodec/avuienc.c index a2391b31e..0dea87f10 100644 --- a/libavcodec/avuienc.c +++ b/libavcodec/avuienc.c @@ -99,7 +99,7 @@ const FFCodec ff_avui_encoder = { .p.id = AV_CODEC_ID_AVUI, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_EXPERIMENTAL | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_UYVY422, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_UYVY422), .color_ranges = AVCOL_RANGE_MPEG, .init = avui_encode_init, FF_CODEC_ENCODE_CB(avui_encode_frame), diff --git a/libavcodec/bethsoftvideo.c b/libavcodec/bethsoftvideo.c index 6de502822..c06eaba32 100644 --- a/libavcodec/bethsoftvideo.c +++ b/libavcodec/bethsoftvideo.c @@ -63,11 +63,6 @@ static int set_palette(BethsoftvidContext *ctx, GetByteContext *g) palette[a] = 0xFFU << 24 | bytestream2_get_be24u(g) * 4; palette[a] |= palette[a] >> 6 & 0x30303; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - ctx->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif return 0; } diff --git a/libavcodec/bfi.c b/libavcodec/bfi.c index 58158f6ee..1d2d3a720 100644 --- a/libavcodec/bfi.c +++ b/libavcodec/bfi.c @@ -83,19 +83,9 @@ static int bfi_decode_frame(AVCodecContext *avctx, AVFrame *frame, pal++; } memcpy(bfi->pal, frame->data[1], sizeof(bfi->pal)); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } else { frame->pict_type = AV_PICTURE_TYPE_P; frame->flags &= ~AV_FRAME_FLAG_KEY; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 0; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(frame->data[1], bfi->pal, sizeof(bfi->pal)); } diff --git a/libavcodec/bfin/README b/libavcodec/bfin/README deleted file mode 100644 index afb3461b7..000000000 --- a/libavcodec/bfin/README +++ /dev/null @@ -1,6 +0,0 @@ -BFIN optimizations have been removed in -commit 880e2aa23645ed9871c66ee1cbd00f93c72d2d73 -The last revission with the optimizations is fa4e17c14035ebf43130fb369e1728cdd98d0b72 - -If you want to maintain these (or other) BFIN optimizations in ffmpeg, then please -contact ffmpeg-devel@ffmpeg.org diff --git a/libavcodec/bink.c b/libavcodec/bink.c index 04fd90aa1..e5300be00 100644 --- a/libavcodec/bink.c +++ b/libavcodec/bink.c @@ -21,7 +21,6 @@ */ #include "libavutil/attributes.h" -#include "libavutil/emms.h" #include "libavutil/imgutils.h" #include "libavutil/mem.h" #include "libavutil/mem_internal.h" @@ -1297,7 +1296,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if (get_bits_count(&gb) >= bits_count) break; } - emms_c(); if (c->version > 'b') { if ((ret = av_frame_replace(c->last, frame)) < 0) @@ -1411,7 +1409,7 @@ static av_cold int decode_end(AVCodecContext *avctx) return 0; } -static void flush(AVCodecContext *avctx) +static av_cold void flush(AVCodecContext *avctx) { BinkContext * const c = avctx->priv_data; diff --git a/libavcodec/binkaudio.c b/libavcodec/binkaudio.c index 265f93a82..ee75256ec 100644 --- a/libavcodec/binkaudio.c +++ b/libavcodec/binkaudio.c @@ -30,6 +30,7 @@ #include "config_components.h" +#include "libavutil/attributes.h" #include "libavutil/channel_layout.h" #include "libavutil/intfloat.h" #include "libavutil/mem_internal.h" @@ -358,7 +359,7 @@ fail: return ret; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { BinkAudioContext *const s = avctx->priv_data; diff --git a/libavcodec/bintext.c b/libavcodec/bintext.c index b20d6ce17..356042c1f 100644 --- a/libavcodec/bintext.c +++ b/libavcodec/bintext.c @@ -93,10 +93,10 @@ static av_cold int decode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_WARNING, "font height %i not supported\n", s->font_height); s->font_height = 8; case 8: - s->font = avpriv_cga_font; + s->font = avpriv_cga_font_get(); break; case 16: - s->font = avpriv_vga16_font; + s->font = avpriv_vga16_font_get(); break; } } @@ -157,11 +157,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if ((ret = ff_get_buffer(avctx, s->frame, 0)) < 0) return ret; s->frame->pict_type = AV_PICTURE_TYPE_I; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(s->frame->data[1], s->palette, 16 * 4); if (avctx->codec_id == AV_CODEC_ID_XBIN) { diff --git a/libavcodec/bit_depth_template.c b/libavcodec/bit_depth_template.c index d44d47ea4..6a80cdaf3 100644 --- a/libavcodec/bit_depth_template.c +++ b/libavcodec/bit_depth_template.c @@ -30,7 +30,6 @@ # undef pixel4 # undef dctcoef # undef idctin -# undef INIT_CLIP # undef no_rnd_avg_pixel4 # undef rnd_avg_pixel4 # undef AV_RN2P @@ -44,11 +43,13 @@ # undef FUNCC # undef av_clip_pixel # undef PIXEL_SPLAT_X4 +# undef PIXELSIZE #else # define AVCODEC_BIT_DEPTH_TEMPLATE_C #endif #if BIT_DEPTH > 8 +# define PIXELSIZE 16 # define pixel uint16_t # define pixel2 uint32_t # define pixel4 uint64_t @@ -64,7 +65,6 @@ # define idctin int16_t #endif -# define INIT_CLIP # define no_rnd_avg_pixel4 no_rnd_avg64 # define rnd_avg_pixel4 rnd_avg64 # define AV_RN2P AV_RN32 @@ -78,13 +78,13 @@ # define av_clip_pixel(a) av_clip_uintp2(a, BIT_DEPTH) # define CLIP(a) av_clip_uintp2(a, BIT_DEPTH) #else +# define PIXELSIZE 8 # define pixel uint8_t # define pixel2 uint16_t # define pixel4 uint32_t # define dctcoef int16_t # define idctin int16_t -# define INIT_CLIP # define no_rnd_avg_pixel4 no_rnd_avg32 # define rnd_avg_pixel4 rnd_avg32 # define AV_RN2P AV_RN16 @@ -103,6 +103,7 @@ #define FUNC2(a, b, c) FUNC3(a, b, c) #define FUNC(a) FUNC2(a, BIT_DEPTH,) #define FUNCC(a) FUNC2(a, BIT_DEPTH, _c) +#define FUNCC2(a) FUNC2(a, PIXELSIZE, _c) #define FUNC4(a, b, c) a ## _int ## b ## _ ## c ## bit #define FUNC5(a, b, c) FUNC4(a, b, c) #define FUNC6(a) FUNC5(a, IN_IDCT_DEPTH, BIT_DEPTH) diff --git a/libavcodec/bitpacked_enc.c b/libavcodec/bitpacked_enc.c index 3c4e11293..cde3cf83e 100644 --- a/libavcodec/bitpacked_enc.c +++ b/libavcodec/bitpacked_enc.c @@ -114,6 +114,5 @@ const FFCodec ff_bitpacked_encoder = { AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV422P10, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P10), }; diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream.h index 35b7873b9..e4d96af71 100644 --- a/libavcodec/bitstream.h +++ b/libavcodec/bitstream.h @@ -82,6 +82,7 @@ # define bits_init8 bits_init8_le # define bits_tell bits_tell_le # define bits_size bits_size_le +# define bits_bytesize bits_bytesize_le # define bits_left bits_left_le # define bits_read_bit bits_read_bit_le # define bits_read_nz bits_read_nz_le @@ -111,6 +112,7 @@ # define bits_init8 bits_init8_be # define bits_tell bits_tell_be # define bits_size bits_size_be +# define bits_bytesize bits_bytesize_be # define bits_left bits_left_be # define bits_read_bit bits_read_bit_be # define bits_read_nz bits_read_nz_be diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index f923411be..150cca893 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -25,6 +25,8 @@ #include "bsf_internal.h" extern const FFBitStreamFilter ff_aac_adtstoasc_bsf; +extern const FFBitStreamFilter ff_ahx_to_mp2_bsf; +extern const FFBitStreamFilter ff_apv_metadata_bsf; extern const FFBitStreamFilter ff_av1_frame_merge_bsf; extern const FFBitStreamFilter ff_av1_frame_split_bsf; extern const FFBitStreamFilter ff_av1_metadata_bsf; @@ -35,6 +37,7 @@ extern const FFBitStreamFilter ff_dovi_rpu_bsf; extern const FFBitStreamFilter ff_dts2pts_bsf; extern const FFBitStreamFilter ff_dv_error_marker_bsf; extern const FFBitStreamFilter ff_eac3_core_bsf; +extern const FFBitStreamFilter ff_eia608_to_smpte436m_bsf; extern const FFBitStreamFilter ff_evc_frame_merge_bsf; extern const FFBitStreamFilter ff_extract_extradata_bsf; extern const FFBitStreamFilter ff_filter_units_bsf; @@ -45,6 +48,7 @@ extern const FFBitStreamFilter ff_hapqa_extract_bsf; extern const FFBitStreamFilter ff_hevc_metadata_bsf; extern const FFBitStreamFilter ff_hevc_mp4toannexb_bsf; extern const FFBitStreamFilter ff_imx_dump_header_bsf; +extern const FFBitStreamFilter ff_lcevc_metadata_bsf; extern const FFBitStreamFilter ff_media100_to_mjpegb_bsf; extern const FFBitStreamFilter ff_mjpeg2jpeg_bsf; extern const FFBitStreamFilter ff_mjpega_dump_header_bsf; @@ -60,6 +64,7 @@ extern const FFBitStreamFilter ff_prores_metadata_bsf; extern const FFBitStreamFilter ff_remove_extradata_bsf; extern const FFBitStreamFilter ff_setts_bsf; extern const FFBitStreamFilter ff_showinfo_bsf; +extern const FFBitStreamFilter ff_smpte436m_to_eia608_bsf; extern const FFBitStreamFilter ff_text2movsub_bsf; extern const FFBitStreamFilter ff_trace_headers_bsf; extern const FFBitStreamFilter ff_truehd_core_bsf; diff --git a/libavcodec/bitstream_template.h b/libavcodec/bitstream_template.h index bbb8dfa55..773d40ef1 100644 --- a/libavcodec/bitstream_template.h +++ b/libavcodec/bitstream_template.h @@ -156,6 +156,14 @@ static inline int BS_FUNC(size)(const BSCTX *bc) return bc->size_in_bits; } +/** + * Return buffer size in bytes. + */ +static inline int BS_FUNC(bytesize)(const BSCTX *bc, int round_up) +{ + return (bc->size_in_bits + (round_up ? 7 : 0)) >> 3; +} + /** * Return the number of the bits left in a buffer. */ diff --git a/libavcodec/blockdsp.c b/libavcodec/blockdsp.c index 57ca41bd9..793e7664e 100644 --- a/libavcodec/blockdsp.c +++ b/libavcodec/blockdsp.c @@ -69,7 +69,7 @@ av_cold void ff_blockdsp_init(BlockDSPContext *c) ff_blockdsp_init_ppc(c); #elif ARCH_RISCV ff_blockdsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_blockdsp_init_x86(c); #elif ARCH_MIPS ff_blockdsp_init_mips(c); diff --git a/libavcodec/blockdsp.h b/libavcodec/blockdsp.h index 6d751d797..f83068ce5 100644 --- a/libavcodec/blockdsp.h +++ b/libavcodec/blockdsp.h @@ -38,7 +38,6 @@ typedef struct BlockDSPContext { void ff_blockdsp_init(BlockDSPContext *c); -void ff_blockdsp_init_alpha(BlockDSPContext *c); void ff_blockdsp_init_arm(BlockDSPContext *c); void ff_blockdsp_init_ppc(BlockDSPContext *c); void ff_blockdsp_init_riscv(BlockDSPContext *c); diff --git a/libavcodec/bmp.c b/libavcodec/bmp.c index 9e9f62d91..db5d70405 100644 --- a/libavcodec/bmp.c +++ b/libavcodec/bmp.c @@ -207,9 +207,6 @@ static int bmp_decode_frame(AVCodecContext *avctx, AVFrame *p, return AVERROR_INVALIDDATA; } - if ((ret = ff_get_buffer(avctx, p, 0)) < 0) - return ret; - buf = buf0 + hsize; dsize = buf_size - hsize; @@ -225,6 +222,8 @@ static int bmp_decode_frame(AVCodecContext *avctx, AVFrame *p, } av_log(avctx, AV_LOG_ERROR, "data size too small, assuming missing line alignment\n"); } + if ((ret = ff_get_buffer(avctx, p, 0)) < 0) + return ret; // RLE may skip decoding some picture areas, so blank picture before decoding if (comp == BMP_RLE4 || comp == BMP_RLE8) diff --git a/libavcodec/bmp_parser.c b/libavcodec/bmp_parser.c index 3440794b2..5a6e95762 100644 --- a/libavcodec/bmp_parser.c +++ b/libavcodec/bmp_parser.c @@ -28,6 +28,7 @@ #include "libavutil/common.h" #include "parser.h" +#include "parser_internal.h" typedef struct BMPParseContext { ParseContext pc; @@ -105,9 +106,9 @@ flush: return next; } -const AVCodecParser ff_bmp_parser = { - .codec_ids = { AV_CODEC_ID_BMP }, +const FFCodecParser ff_bmp_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_BMP), .priv_data_size = sizeof(BMPParseContext), - .parser_parse = bmp_parse, - .parser_close = ff_parse_close, + .parse = bmp_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/bmpenc.c b/libavcodec/bmpenc.c index 48f25170b..15d6778f2 100644 --- a/libavcodec/bmpenc.c +++ b/libavcodec/bmpenc.c @@ -164,11 +164,9 @@ const FFCodec ff_bmp_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = bmp_encode_init, FF_CODEC_ENCODE_CB(bmp_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR24, - AV_PIX_FMT_RGB565, AV_PIX_FMT_RGB555, AV_PIX_FMT_RGB444, - AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, - AV_PIX_FMT_MONOBLACK, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR24, + AV_PIX_FMT_RGB565, AV_PIX_FMT_RGB555, AV_PIX_FMT_RGB444, + AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, + AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, + AV_PIX_FMT_MONOBLACK), }; diff --git a/libavcodec/bmvvideo.c b/libavcodec/bmvvideo.c index 20f07ca55..e83b7e64d 100644 --- a/libavcodec/bmvvideo.c +++ b/libavcodec/bmvvideo.c @@ -251,11 +251,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, } memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = type & BMV_PALETTE; -FF_ENABLE_DEPRECATION_WARNINGS -#endif outptr = frame->data[0]; srcptr = c->frame; diff --git a/libavcodec/bonk.c b/libavcodec/bonk.c index 14b7457a1..67eb8d6a1 100644 --- a/libavcodec/bonk.c +++ b/libavcodec/bonk.c @@ -427,11 +427,6 @@ const FFCodec ff_bonk_decoder = { FF_CODEC_DECODE_CB(bonk_decode), .close = bonk_close, .p.capabilities = AV_CODEC_CAP_DELAY | -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/brenderpix.c b/libavcodec/brenderpix.c index 07bb47fff..dd48b40b3 100644 --- a/libavcodec/brenderpix.c +++ b/libavcodec/brenderpix.c @@ -245,12 +245,6 @@ static int pix_decode_frame(AVCodecContext *avctx, AVFrame *frame, *pal_out++ = (0xFFU << 24) | bytestream2_get_be32u(&gb); bytestream2_skip(&gb, 8); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - chunk_type = bytestream2_get_be32(&gb); } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { /* no palette supplied, use the default one */ @@ -260,12 +254,6 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(avctx, AV_LOG_WARNING, "Using default palette, colors might be off.\n"); memcpy(pal_out, std_pal_table, sizeof(uint32_t) * 256); - -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } data_len = bytestream2_get_be32(&gb); diff --git a/libavcodec/bsf/Makefile b/libavcodec/bsf/Makefile index 40b7fc6e9..eb090090e 100644 --- a/libavcodec/bsf/Makefile +++ b/libavcodec/bsf/Makefile @@ -2,6 +2,8 @@ clean:: $(RM) $(CLEANSUFFIXES:%=libavcodec/bsf/%) OBJS-$(CONFIG_AAC_ADTSTOASC_BSF) += bsf/aac_adtstoasc.o +OBJS-$(CONFIG_AHX_TO_MP2_BSF) += bsf/ahx_to_mp2.o +OBJS-$(CONFIG_APV_METADATA_BSF) += bsf/apv_metadata.o OBJS-$(CONFIG_AV1_FRAME_MERGE_BSF) += bsf/av1_frame_merge.o OBJS-$(CONFIG_AV1_FRAME_SPLIT_BSF) += bsf/av1_frame_split.o OBJS-$(CONFIG_AV1_METADATA_BSF) += bsf/av1_metadata.o @@ -11,6 +13,7 @@ OBJS-$(CONFIG_DTS2PTS_BSF) += bsf/dts2pts.o OBJS-$(CONFIG_DUMP_EXTRADATA_BSF) += bsf/dump_extradata.o OBJS-$(CONFIG_DV_ERROR_MARKER_BSF) += bsf/dv_error_marker.o OBJS-$(CONFIG_EAC3_CORE_BSF) += bsf/eac3_core.o +OBJS-$(CONFIG_EIA608_TO_SMPTE436M_BSF) += bsf/eia608_to_smpte436m.o OBJS-$(CONFIG_EVC_FRAME_MERGE_BSF) += bsf/evc_frame_merge.o OBJS-$(CONFIG_EXTRACT_EXTRADATA_BSF) += bsf/extract_extradata.o OBJS-$(CONFIG_FILTER_UNITS_BSF) += bsf/filter_units.o @@ -22,6 +25,7 @@ OBJS-$(CONFIG_HEVC_METADATA_BSF) += bsf/h265_metadata.o OBJS-$(CONFIG_DOVI_RPU_BSF) += bsf/dovi_rpu.o OBJS-$(CONFIG_HEVC_MP4TOANNEXB_BSF) += bsf/hevc_mp4toannexb.o OBJS-$(CONFIG_IMX_DUMP_HEADER_BSF) += bsf/imx_dump_header.o +OBJS-$(CONFIG_LCEVC_METADATA_BSF) += bsf/lcevc_metadata.o OBJS-$(CONFIG_MEDIA100_TO_MJPEGB_BSF) += bsf/media100_to_mjpegb.o OBJS-$(CONFIG_MJPEG2JPEG_BSF) += bsf/mjpeg2jpeg.o OBJS-$(CONFIG_MJPEGA_DUMP_HEADER_BSF) += bsf/mjpega_dump_header.o @@ -37,6 +41,7 @@ OBJS-$(CONFIG_PRORES_METADATA_BSF) += bsf/prores_metadata.o OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += bsf/remove_extradata.o OBJS-$(CONFIG_SETTS_BSF) += bsf/setts.o OBJS-$(CONFIG_SHOWINFO_BSF) += bsf/showinfo.o +OBJS-$(CONFIG_SMPTE436M_TO_EIA608_BSF) += bsf/smpte436m_to_eia608.o OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += bsf/movsub.o OBJS-$(CONFIG_TRACE_HEADERS_BSF) += bsf/trace_headers.o OBJS-$(CONFIG_TRUEHD_CORE_BSF) += bsf/truehd_core.o diff --git a/libavcodec/bsf/ahx_to_mp2.c b/libavcodec/bsf/ahx_to_mp2.c new file mode 100644 index 000000000..8e30c5b1d --- /dev/null +++ b/libavcodec/bsf/ahx_to_mp2.c @@ -0,0 +1,64 @@ +/* + * AHX to MP2 bitstream filter + * Copyright (c) 2024 Paul B Mahol + * + * 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 + * AHX to MP2 bitstream filter. + */ + +#include "libavutil/intreadwrite.h" +#include "bsf.h" +#include "bsf_internal.h" + +static av_cold int init(AVBSFContext *ctx) +{ + ctx->par_out->codec_id = AV_CODEC_ID_MP2; + + return 0; +} + +static int filter(AVBSFContext *ctx, AVPacket *pkt) +{ + int ret; + + ret = ff_bsf_get_packet_ref(ctx, pkt); + if (ret < 0) + return ret; + + if (pkt->size < 1044) { + int original_size = pkt->size; + ret = av_grow_packet(pkt, 1044-pkt->size); + if (ret < 0) { + av_packet_unref(pkt); + return ret; + } + memset(pkt->data + original_size, 0, 1044 - original_size); + } + + return 0; +} + +const FFBitStreamFilter ff_ahx_to_mp2_bsf = { + .p.name = "ahx_to_mp2", + .p.codec_ids = (const enum AVCodecID []){ AV_CODEC_ID_AHX, AV_CODEC_ID_NONE }, + .init = init, + .filter = filter, +}; diff --git a/libavcodec/bsf/apv_metadata.c b/libavcodec/bsf/apv_metadata.c new file mode 100644 index 000000000..a1cdcf86c --- /dev/null +++ b/libavcodec/bsf/apv_metadata.c @@ -0,0 +1,134 @@ +/* + * 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/opt.h" + +#include "bsf.h" +#include "bsf_internal.h" +#include "cbs.h" +#include "cbs_bsf.h" +#include "cbs_apv.h" + +typedef struct APVMetadataContext { + CBSBSFContext common; + + int color_primaries; + int transfer_characteristics; + int matrix_coefficients; + int full_range_flag; +} APVMetadataContext; + + +static int apv_metadata_update_frame_header(AVBSFContext *bsf, + APVRawFrameHeader *hdr) +{ + APVMetadataContext *ctx = bsf->priv_data; + + if (ctx->color_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0 || + ctx->full_range_flag >= 0) { + hdr->color_description_present_flag = 1; + + if (ctx->color_primaries >= 0) + hdr->color_primaries = ctx->color_primaries; + if (ctx->transfer_characteristics >= 0) + hdr->transfer_characteristics = ctx->transfer_characteristics; + if (ctx->matrix_coefficients >= 0) + hdr->matrix_coefficients = ctx->matrix_coefficients; + if (ctx->full_range_flag >= 0) + hdr->full_range_flag = ctx->full_range_flag; + } + + return 0; +} + +static int apv_metadata_update_fragment(AVBSFContext *bsf, AVPacket *pkt, + CodedBitstreamFragment *frag) +{ + int err, i; + + for (i = 0; i < frag->nb_units; i++) { + if (frag->units[i].type == APV_PBU_PRIMARY_FRAME) { + APVRawFrame *pbu = frag->units[i].content; + err = apv_metadata_update_frame_header(bsf, &pbu->frame_header); + if (err < 0) + return err; + } + } + + return 0; +} + +static const CBSBSFType apv_metadata_type = { + .codec_id = AV_CODEC_ID_APV, + .fragment_name = "access unit", + .unit_name = "PBU", + .update_fragment = &apv_metadata_update_fragment, +}; + +static int apv_metadata_init(AVBSFContext *bsf) +{ + return ff_cbs_bsf_generic_init(bsf, &apv_metadata_type); +} + +#define OFFSET(x) offsetof(APVMetadataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption apv_metadata_options[] = { + { "color_primaries", "Set color primaries (section 5.3.5)", + OFFSET(color_primaries), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "transfer_characteristics", "Set transfer characteristics (section 5.3.5)", + OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "matrix_coefficients", "Set matrix coefficients (section 5.3.5)", + OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + + { "full_range_flag", "Set full range flag flag (section 5.3.5)", + OFFSET(full_range_flag), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 1, FLAGS, .unit = "cr" }, + { "tv", "TV (limited) range", 0, AV_OPT_TYPE_CONST, + { .i64 = 0 }, .flags = FLAGS, .unit = "cr" }, + { "pc", "PC (full) range", 0, AV_OPT_TYPE_CONST, + { .i64 = 1 }, .flags = FLAGS, .unit = "cr" }, + + { NULL } +}; + +static const AVClass apv_metadata_class = { + .class_name = "apv_metadata_bsf", + .item_name = av_default_item_name, + .option = apv_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID apv_metadata_codec_ids[] = { + AV_CODEC_ID_APV, AV_CODEC_ID_NONE, +}; + +const FFBitStreamFilter ff_apv_metadata_bsf = { + .p.name = "apv_metadata", + .p.codec_ids = apv_metadata_codec_ids, + .p.priv_class = &apv_metadata_class, + .priv_data_size = sizeof(APVMetadataContext), + .init = &apv_metadata_init, + .close = &ff_cbs_bsf_generic_close, + .filter = &ff_cbs_bsf_generic_filter, +}; diff --git a/libavcodec/bsf/dovi_rpu.c b/libavcodec/bsf/dovi_rpu.c index ae04d1636..9fb47f3ab 100644 --- a/libavcodec/bsf/dovi_rpu.c +++ b/libavcodec/bsf/dovi_rpu.c @@ -84,7 +84,8 @@ static int dovi_rpu_update_fragment_hevc(AVBSFContext *bsf, AVPacket *pkt, uint8_t *rpu = NULL; int rpu_size, ret; - if (!nal || nal->type != HEVC_NAL_UNSPEC62) + // HEVC_NAL_UNSPEC62 is Dolby Vision RPU and HEVC_NAL_UNSPEC63 is Dolby Vision EL + if (!nal || (nal->type != HEVC_NAL_UNSPEC62 && nal->type != HEVC_NAL_UNSPEC63)) return 0; if (s->strip) { @@ -92,6 +93,9 @@ static int dovi_rpu_update_fragment_hevc(AVBSFContext *bsf, AVPacket *pkt, return 0; } + if (nal->type == HEVC_NAL_UNSPEC63) + return 0; + ret = update_rpu(bsf, pkt, 0, nal->data + 2, nal->data_size - 2, &rpu, &rpu_size); if (ret < 0) return ret; @@ -224,8 +228,8 @@ static int dovi_rpu_init(AVBSFContext *bsf) } else { av_log(bsf, AV_LOG_WARNING, "No Dolby Vision configuration record " "found? Generating one, but results may be invalid.\n"); - ret = ff_dovi_configure_ext(&s->enc, bsf->par_out, NULL, s->compression, - FF_COMPLIANCE_NORMAL); + ret = ff_dovi_configure_from_codedpar(&s->enc, bsf->par_out, NULL, s->compression, + FF_COMPLIANCE_NORMAL); if (ret < 0) return ret; /* Be conservative in accepting all compressed RPUs */ diff --git a/libavcodec/bsf/dts2pts.c b/libavcodec/bsf/dts2pts.c index 62838d4f7..122661a5d 100644 --- a/libavcodec/bsf/dts2pts.c +++ b/libavcodec/bsf/dts2pts.c @@ -23,6 +23,8 @@ * Derive PTS by reordering DTS from supported streams */ +#include + #include "libavutil/avassert.h" #include "libavutil/fifo.h" #include "libavutil/mem.h" @@ -32,9 +34,11 @@ #include "bsf_internal.h" #include "cbs.h" #include "cbs_h264.h" +#include "cbs_h265.h" #include "h264_parse.h" #include "h264_ps.h" -#include "refstruct.h" +#include "hevc/ps.h" +#include "libavutil/refstruct.h" typedef struct DTS2PTSNode { int64_t dts; @@ -59,10 +63,16 @@ typedef struct DTS2PTSH264Context { int picture_structure; } DTS2PTSH264Context; +typedef struct DTS2PTSHEVCContext { + int gop; + int poc_tid0; + int highest_poc; +} DTS2PTSHEVCContext; + typedef struct DTS2PTSContext { struct AVTreeNode *root; AVFifo *fifo; - FFRefStructPool *node_pool; + AVRefStructPool *node_pool; // Codec specific function pointers and constants int (*init)(AVBSFContext *ctx); @@ -75,6 +85,7 @@ typedef struct DTS2PTSContext { union { DTS2PTSH264Context h264; + DTS2PTSHEVCContext hevc; } u; int nb_frame; @@ -112,7 +123,7 @@ static int dec_poc(void *opaque, void *elem) static int free_node(void *opaque, void *elem) { DTS2PTSNode *node = elem; - ff_refstruct_unref(&node); + av_refstruct_unref(&node); return 0; } @@ -126,7 +137,7 @@ static int alloc_and_insert_node(AVBSFContext *ctx, int64_t ts, int64_t duration DTS2PTSNode *poc_node, *ret; if (!node) return AVERROR(ENOMEM); - poc_node = ff_refstruct_pool_get(s->node_pool); + poc_node = av_refstruct_pool_get(s->node_pool); if (!poc_node) { av_free(node); return AVERROR(ENOMEM); @@ -137,7 +148,7 @@ static int alloc_and_insert_node(AVBSFContext *ctx, int64_t ts, int64_t duration ret = av_tree_insert(&s->root, poc_node, cmp_insert, &node); if (ret && ret != poc_node) { *ret = *poc_node; - ff_refstruct_unref(&poc_node); + av_refstruct_unref(&poc_node); av_free(node); } } @@ -261,6 +272,7 @@ static int h264_filter(AVBSFContext *ctx) if (!sps) { av_log(ctx, AV_LOG_ERROR, "No active SPS for a slice\n"); + ret = AVERROR_INVALIDDATA; goto fail; } // Initialize the SPS struct with the fields ff_h264_init_poc() cares about @@ -362,6 +374,176 @@ static void h264_flush(AVBSFContext *ctx) h264->last_poc = h264->highest_poc = INT_MIN; } +static int hevc_init(AVBSFContext *ctx) +{ + DTS2PTSContext *s = ctx->priv_data; + DTS2PTSHEVCContext *hevc = &s->u.hevc; + + hevc->gop = -1; + hevc->poc_tid0 = 0; + hevc->highest_poc = INT_MIN; + s->nb_frame = -ctx->par_in->video_delay; + + return 0; +} + +static void hevc_flush(AVBSFContext *ctx) +{ + hevc_init(ctx); +} + +static int hevc_init_nb_frame(AVBSFContext *ctx, int poc) +{ + DTS2PTSContext *s = ctx->priv_data; + const CodedBitstreamH265Context *cbs_hevc = s->cbc->priv_data; + const H265RawVPS *vps = cbs_hevc->active_vps; + + if (!vps) + return AVERROR_INVALIDDATA; + + int latency = vps->vps_max_num_reorder_pics[0]; + if (vps->vps_max_latency_increase_plus1[0]) + latency += vps->vps_max_latency_increase_plus1[0] - 1; + + s->nb_frame = poc - latency; + av_log(ctx, AV_LOG_DEBUG, "Latency %d, poc %d, nb_frame %d\n", + latency, poc, s->nb_frame); + + return 0; +} + +static int same_gop(void *opaque, void *elem) +{ + DTS2PTSNode *node = elem; + int gop = ((int *)opaque)[1]; + return FFDIFFSIGN(gop, node->gop); +} + +static int hevc_queue_frame(AVBSFContext *ctx, AVPacket *pkt, int poc, bool *queued) +{ + DTS2PTSContext *s = ctx->priv_data; + DTS2PTSHEVCContext *hevc = &s->u.hevc; + int ret; + + if (hevc->gop == -1) { + ret = hevc_init_nb_frame(ctx, poc); + if (ret < 0) + return ret; + hevc->gop = s->gop; + } + + hevc->highest_poc = FFMAX(hevc->highest_poc, poc); + if (s->nb_frame > hevc->highest_poc) { + s->nb_frame = 0; + s->gop = (s->gop + 1) % s->fifo_size; + hevc->highest_poc = poc; + } + + if (poc < s->nb_frame && hevc->gop == s->gop) { + int tmp[] = {s->nb_frame - poc, s->gop}; + + s->nb_frame -= tmp[0]; + av_tree_enumerate(s->root, tmp, same_gop, dec_poc); + } + + ret = alloc_and_insert_node(ctx, pkt->dts, pkt->duration, s->nb_frame, 1, s->gop); + if (ret < 0) + return ret; + + av_log(ctx, AV_LOG_DEBUG, "Queueing frame with POC %d, GOP %d, nb_frame %d, dts %"PRId64"\n", + poc, s->gop, s->nb_frame, pkt->dts); + s->nb_frame++; + + DTS2PTSFrame frame = { + .pkt = pkt, + .poc = poc, + .poc_diff = 1, + .gop = s->gop, + }; + ret = av_fifo_write(s->fifo, &frame, 1); + if (ret < 0) + return ret; + + *queued = true; + + return 0; +} + +static int hevc_filter(AVBSFContext *ctx) +{ + DTS2PTSContext *s = ctx->priv_data; + DTS2PTSHEVCContext *hevc = &s->u.hevc; + CodedBitstreamFragment *au = &s->au; + AVPacket *in; + bool queued = 0; + int ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + ret = ff_cbs_read_packet(s->cbc, au, in); + if (ret < 0) { + av_log(ctx, AV_LOG_WARNING, "Failed to parse access unit.\n"); + goto fail; + } + + for (int i = 0; i < au->nb_units; i++) { + CodedBitstreamUnit *unit = &au->units[i]; + CodedBitstreamUnitType type = unit->type; + + bool is_slice = type <= HEVC_NAL_RASL_R || (type >= HEVC_NAL_BLA_W_LP && + type <= HEVC_NAL_CRA_NUT); + if (!is_slice) + continue; + + const H265RawSliceHeader *slice = unit->content; + if (!slice->first_slice_segment_in_pic_flag) + continue; + + const CodedBitstreamH265Context *cbs_hevc = s->cbc->priv_data; + const H265RawSPS *sps = cbs_hevc->active_sps; + if (!sps) { + av_log(ctx, AV_LOG_ERROR, "No active SPS for a slice\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + int poc; + if (type == HEVC_NAL_IDR_W_RADL || type == HEVC_NAL_IDR_N_LP) { + poc = 0; + hevc->gop = (hevc->gop + 1) % s->fifo_size; + } else { + unsigned log2_max_poc_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4; + int poc_lsb = slice->slice_pic_order_cnt_lsb; + + poc = ff_hevc_compute_poc2(log2_max_poc_lsb, hevc->poc_tid0, poc_lsb, type); + } + + if (slice->nal_unit_header.nuh_temporal_id_plus1 == 1 && + type != HEVC_NAL_TRAIL_N && type != HEVC_NAL_TSA_N && + type != HEVC_NAL_STSA_N && type != HEVC_NAL_RADL_N && + type != HEVC_NAL_RASL_N && type != HEVC_NAL_RADL_R && + type != HEVC_NAL_RASL_R) { + hevc->poc_tid0 = poc; + } + + ret = hevc_queue_frame(ctx, in, poc, &queued); + if (ret < 0) + goto fail; + break; + } + + if (!queued) { + av_log(ctx, AV_LOG_ERROR, "No slices in access unit\n"); + ret = AVERROR_INVALIDDATA; + } + +fail: + ff_cbs_fragment_reset(au); + if (!queued) + av_packet_free(&in); + return ret; +} + // Core functions static const struct { enum AVCodecID id; @@ -371,6 +553,7 @@ static const struct { size_t fifo_size; } func_tab[] = { { AV_CODEC_ID_H264, h264_init, h264_filter, h264_flush, H264_MAX_DPB_FRAMES * 2 * 2 }, + { AV_CODEC_ID_HEVC, hevc_init, hevc_filter, hevc_flush, HEVC_MAX_DPB_SIZE * 2 }, }; static int dts2pts_init(AVBSFContext *ctx) @@ -396,8 +579,8 @@ static int dts2pts_init(AVBSFContext *ctx) if (!s->fifo) return AVERROR(ENOMEM); - s->node_pool = ff_refstruct_pool_alloc(sizeof(DTS2PTSNode), - FF_REFSTRUCT_POOL_FLAG_NO_ZEROING); + s->node_pool = av_refstruct_pool_alloc(sizeof(DTS2PTSNode), + AV_REFSTRUCT_POOL_FLAG_NO_ZEROING); if (!s->node_pool) return AVERROR(ENOMEM); @@ -467,7 +650,7 @@ static int dts2pts_filter(AVBSFContext *ctx, AVPacket *out) if (!poc_node || poc_node->dts != out->pts) continue; av_tree_insert(&s->root, poc_node, cmp_insert, &node); - ff_refstruct_unref(&poc_node); + av_refstruct_unref(&poc_node); av_free(node); poc_node = av_tree_find(s->root, &dup, cmp_find, NULL); } @@ -485,11 +668,10 @@ static int dts2pts_filter(AVBSFContext *ctx, AVPacket *out) av_packet_unref(out); return ret; } - if (!ret) - av_log(ctx, AV_LOG_DEBUG, "Queueing frame for POC %d, GOP %d, dts %"PRId64", " - "generated from POC %d, GOP %d, dts %"PRId64", duration %"PRId64"\n", - frame.poc, frame.gop, out->pts, - poc_node->poc, poc_node->gop, poc_node->dts, poc_node->duration); + av_log(ctx, AV_LOG_DEBUG, "Queueing frame for POC %d, GOP %d, dts %"PRId64", " + "generated from POC %d, GOP %d, dts %"PRId64", duration %"PRId64"\n", + frame.poc, frame.gop, out->pts, + poc_node->poc, poc_node->gop, poc_node->dts, poc_node->duration); } else av_log(ctx, AV_LOG_WARNING, "No timestamp for POC %d in tree\n", frame.poc); } else @@ -529,13 +711,14 @@ static void dts2pts_close(AVBSFContext *ctx) dts2pts_flush(ctx); av_fifo_freep2(&s->fifo); - ff_refstruct_pool_uninit(&s->node_pool); + av_refstruct_pool_uninit(&s->node_pool); ff_cbs_fragment_free(&s->au); ff_cbs_close(&s->cbc); } static const enum AVCodecID dts2pts_codec_ids[] = { AV_CODEC_ID_H264, + AV_CODEC_ID_HEVC, AV_CODEC_ID_NONE, }; diff --git a/libavcodec/bsf/eia608_to_smpte436m.c b/libavcodec/bsf/eia608_to_smpte436m.c new file mode 100644 index 000000000..096acb596 --- /dev/null +++ b/libavcodec/bsf/eia608_to_smpte436m.c @@ -0,0 +1,277 @@ +/* + * EIA-608 to MXF SMPTE-436M ANC bitstream filter + * Copyright (c) 2025 Jacob Lifshay + * + * 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 "bsf.h" +#include "bsf_internal.h" +#include "codec_id.h" +#include "libavcodec/smpte_436m.h" +#include "libavcodec/smpte_436m_internal.h" +#include "libavutil/avassert.h" +#include "libavutil/avutil.h" +#include "libavutil/error.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/macros.h" +#include "libavutil/opt.h" +#include "libavutil/rational.h" + +typedef struct EIA608ToSMPTE436MContext { + const AVClass *class; + unsigned line_number; + unsigned cdp_sequence_cntr; + unsigned wrapping_type_opt; + unsigned sample_coding_opt; + AVSmpte436mWrappingType wrapping_type; + AVSmpte436mPayloadSampleCoding sample_coding; + AVRational cdp_frame_rate; + uint8_t cdp_frame_rate_byte; +} EIA608ToSMPTE436MContext; + +// clang-format off +static const AVSmpte291mAnc8bit test_anc = { + .did = 0x61, + .sdid_or_dbn = 0x01, + .data_count = 0x49, + .payload = { + // header + 0x96, 0x69, 0x49, 0x7F, 0x43, 0xFA, 0x8D, 0x72, 0xF4, + + // 608 triples + 0xFC, 0x80, 0x80, 0xFD, 0x80, 0x80, + + // 708 padding + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + + // footer + 0x74, 0xFA, 0x8D, 0x81, + }, + .checksum = 0xAB, +}; +// clang-format on + +static av_cold int ff_eia608_to_smpte436m_init(AVBSFContext *ctx) +{ + EIA608ToSMPTE436MContext *priv = ctx->priv_data; + + priv->wrapping_type = priv->wrapping_type_opt; + priv->sample_coding = priv->sample_coding_opt; + + // validate we can handle the selected wrapping type and sample coding + + AVSmpte436mCodedAnc coded_anc; + + int ret = av_smpte_291m_anc_8bit_encode( + &coded_anc, priv->line_number, priv->wrapping_type, priv->sample_coding, &test_anc, ctx); + if (ret < 0) + return ret; + + ctx->par_out->codec_type = AVMEDIA_TYPE_DATA; + ctx->par_out->codec_id = AV_CODEC_ID_SMPTE_436M_ANC; + + static const struct { + AVRational frame_rate; + uint8_t cdp_frame_rate; + } known_frame_rates[] = { + { .frame_rate = { .num = 24000, .den = 1001 }, .cdp_frame_rate = 0x1F }, + { .frame_rate = { .num = 24, .den = 1 }, .cdp_frame_rate = 0x2F }, + { .frame_rate = { .num = 25, .den = 1 }, .cdp_frame_rate = 0x3F }, + { .frame_rate = { .num = 30000, .den = 1001 }, .cdp_frame_rate = 0x4F }, + { .frame_rate = { .num = 30, .den = 1 }, .cdp_frame_rate = 0x5F }, + { .frame_rate = { .num = 50, .den = 1 }, .cdp_frame_rate = 0x6F }, + { .frame_rate = { .num = 60000, .den = 1001 }, .cdp_frame_rate = 0x7F }, + { .frame_rate = { .num = 60, .den = 1 }, .cdp_frame_rate = 0x8F }, + }; + + priv->cdp_frame_rate_byte = 0; + + for (int i = 0; i < FF_ARRAY_ELEMS(known_frame_rates); i++) { + if (known_frame_rates[i].frame_rate.num == priv->cdp_frame_rate.num && known_frame_rates[i].frame_rate.den == priv->cdp_frame_rate.den) { + priv->cdp_frame_rate_byte = known_frame_rates[i].cdp_frame_rate; + break; + } + } + + if (priv->cdp_frame_rate_byte == 0) { + av_log(ctx, + AV_LOG_FATAL, + "cdp_frame_rate not supported: %d/%d\n", + priv->cdp_frame_rate.num, + priv->cdp_frame_rate.den); + return AVERROR(EINVAL); + } + + return 0; +} + +static int ff_eia608_to_smpte436m_filter(AVBSFContext *ctx, AVPacket *out) +{ + EIA608ToSMPTE436MContext *priv = ctx->priv_data; + AVPacket *in; + + int ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + AVSmpte291mAnc8bit anc; + anc.did = 0x61; + anc.sdid_or_dbn = 0x1; + + uint8_t *p = anc.payload; + + *p++ = 0x96; // cdp_identifier -- always 0x9669 + *p++ = 0x69; + + uint8_t *cdp_length_p = p++; + + *p++ = priv->cdp_frame_rate_byte; + + const uint8_t FLAG_CC_DATA_PRESENT = 0x40; + const uint8_t FLAG_CAPTION_SERVICE_ACTIVE = 0x2; + const uint8_t FLAG_RESERVED = 0x1; // must always be set + + *p++ = FLAG_CC_DATA_PRESENT | FLAG_CAPTION_SERVICE_ACTIVE | FLAG_RESERVED; + + AV_WB16(p, priv->cdp_sequence_cntr); + p += 2; + + const uint8_t CC_DATA_SECTION_ID = 0x72; + + *p++ = CC_DATA_SECTION_ID; + + uint8_t *cc_count_p = p++; + + const uint8_t CC_COUNT_MASK = 0x1F; + const int CDP_FOOTER_SIZE = 4; + + int cc_count = in->size / 3; + int space_left = AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY - (p - anc.payload); + int cc_data_space_left = space_left - CDP_FOOTER_SIZE; + int max_cc_count = FFMAX(cc_data_space_left / 3, CC_COUNT_MASK); + + if (cc_count > max_cc_count) { + av_log(ctx, + AV_LOG_ERROR, + "cc_count (%d) is bigger than the maximum supported (%d), truncating captions packet\n", + cc_count, + max_cc_count); + cc_count = max_cc_count; + } + + *cc_count_p = cc_count | ~CC_COUNT_MASK; // other bits are reserved and set to ones + + for (size_t i = 0; i < cc_count; i++) { + size_t start = i * 3; + *p++ = in->data[start] | 0xF8; // fill reserved bits with ones + *p++ = in->data[start + 1]; + *p++ = in->data[start + 2]; + } + + const uint8_t CDP_FOOTER_ID = 0x74; + + *p++ = CDP_FOOTER_ID; + + AV_WB16(p, priv->cdp_sequence_cntr); + p += 2; + + uint8_t *packet_checksum_p = p; + *p++ = 0; + + anc.data_count = p - anc.payload; + *cdp_length_p = anc.data_count; + + int sum = 0; + for (int i = 0; i < anc.data_count; i++) { + sum += anc.payload[i]; + } + // set to an 8-bit value such that the sum of the bytes of the whole CDP mod 2^8 is 0 + *packet_checksum_p = -sum; + + priv->cdp_sequence_cntr++; + // cdp_sequence_cntr wraps around at 16-bits + priv->cdp_sequence_cntr &= 0xFFFFU; + + av_smpte_291m_anc_8bit_fill_checksum(&anc); + + AVSmpte436mCodedAnc coded_anc; + ret = av_smpte_291m_anc_8bit_encode( + &coded_anc, priv->line_number, (AVSmpte436mWrappingType)priv->wrapping_type, priv->sample_coding, &anc, ctx); + if (ret < 0) + goto fail; + + ret = av_smpte_436m_anc_encode(NULL, 0, 1, &coded_anc); + if (ret < 0) + goto fail; + + ret = av_new_packet(out, ret); + if (ret < 0) + goto fail; + + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; + + ret = av_smpte_436m_anc_encode(out->data, out->size, 1, &coded_anc); + if (ret < 0) + goto fail; + + ret = 0; + +fail: + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + return ret; +} + +#define OFFSET(x) offsetof(EIA608ToSMPTE436MContext, x) +#define FLAGS AV_OPT_FLAG_BSF_PARAM +// clang-format off +static const AVOption options[] = { + { "line_number", "line number -- you probably want 9 or 11", OFFSET(line_number), AV_OPT_TYPE_UINT, { .i64 = 9 }, 0, 0xFFFF, FLAGS }, + { "wrapping_type", "wrapping type", OFFSET(wrapping_type_opt), AV_OPT_TYPE_UINT, { .i64 = AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME }, 0, 0xFF, FLAGS, .unit = "wrapping_type" }, + FF_SMPTE_436M_WRAPPING_TYPE_VANC_AVOPTIONS(FLAGS, "wrapping_type"), + { "sample_coding", "payload sample coding", OFFSET(sample_coding_opt), AV_OPT_TYPE_UINT, { .i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA }, 0, 0xFF, FLAGS, .unit = "sample_coding" }, + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ANC_AVOPTIONS(FLAGS, "sample_coding"), + { "initial_cdp_sequence_cntr", "initial cdp_*_sequence_cntr value", OFFSET(cdp_sequence_cntr), AV_OPT_TYPE_UINT, { .i64 = 0 }, 0, 0xFFFF, FLAGS }, + { "cdp_frame_rate", "set the `cdp_frame_rate` fields", OFFSET(cdp_frame_rate), AV_OPT_TYPE_VIDEO_RATE, { .str = "30000/1001" }, 0, INT_MAX, FLAGS }, + { NULL }, +}; +// clang-format on + +static const AVClass eia608_to_smpte436m_class = { + .class_name = "eia608_to_smpte436m bitstream filter", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFBitStreamFilter ff_eia608_to_smpte436m_bsf = { + .p.name = "eia608_to_smpte436m", + .p.codec_ids = (const enum AVCodecID[]){ AV_CODEC_ID_EIA_608, AV_CODEC_ID_NONE }, + .p.priv_class = &eia608_to_smpte436m_class, + .priv_data_size = sizeof(EIA608ToSMPTE436MContext), + .init = ff_eia608_to_smpte436m_init, + .filter = ff_eia608_to_smpte436m_filter, +}; diff --git a/libavcodec/bsf/extract_extradata.c b/libavcodec/bsf/extract_extradata.c index 43f4d6285..6a9a43b0d 100644 --- a/libavcodec/bsf/extract_extradata.c +++ b/libavcodec/bsf/extract_extradata.c @@ -29,6 +29,8 @@ #include "bytestream.h" #include "h2645_parse.h" #include "h264.h" +#include "lcevc.h" +#include "lcevc_parse.h" #include "startcode.h" #include "vc1_common.h" #include "vvc.h" @@ -267,6 +269,179 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt, return 0; } +/** + * Rewrite the NALu stripping the unneeded blocks. + * Given that length fields coded inside the NALu are not aware of any emulation_3bytes + * present in the bitstream, we need to keep track of the raw buffer as we navigate + * the stripped buffer. + */ +static int write_lcevc_nalu(AVBSFContext *ctx, PutByteContext *pbc, const H2645NAL *nal, + int remove) +{ + GetByteContext gbc, raw_gbc; + int sc = 0, gc = 0; + int skipped_byte_pos = 0; + + bytestream2_init(&gbc, nal->data, nal->size); + bytestream2_init(&raw_gbc, nal->raw_data, nal->raw_size); + bytestream2_put_be16(pbc, bytestream2_get_be16(&gbc)); + bytestream2_skip(&raw_gbc, 2); + + while (bytestream2_get_bytes_left(&gbc) > 1) { + GetBitContext gb; + int payload_size_type, payload_type; + uint64_t payload_size; + int block_size, raw_block_size, block_end; + + init_get_bits8(&gb, gbc.buffer, bytestream2_get_bytes_left(&gbc)); + + payload_size_type = get_bits(&gb, 3); + payload_type = get_bits(&gb, 5); + payload_size = payload_size_type; + if (payload_size_type == 6) + return AVERROR_PATCHWELCOME; + if (payload_size_type == 7) + payload_size = get_mb(&gb); + + if (payload_size > INT_MAX - (get_bits_count(&gb) >> 3)) + return AVERROR_INVALIDDATA; + + block_size = raw_block_size = payload_size + (get_bits_count(&gb) >> 3); + if (block_size >= bytestream2_get_bytes_left(&gbc)) + return AVERROR_INVALIDDATA; + + block_end = bytestream2_tell(&gbc) + block_size; + // Take into account removed emulation 3bytes, as payload_size in + // the bitstream is not aware of them. + for (; skipped_byte_pos < nal->skipped_bytes; skipped_byte_pos++) { + if (nal->skipped_bytes_pos[skipped_byte_pos] >= block_end) + break; + raw_block_size++; + } + + switch (payload_type) { + case LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG: + case LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG: + case LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO: + if (remove) + break; + bytestream2_put_buffer(pbc, raw_gbc.buffer, raw_block_size); + sc |= payload_type == LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG; + gc |= payload_type == LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG; + break; + default: + if (!remove) + break; + bytestream2_put_buffer(pbc, raw_gbc.buffer, raw_block_size); + break; + } + + bytestream2_skip(&gbc, block_size); + bytestream2_skip(&raw_gbc, raw_block_size); + } + + if (!remove && !sc && !gc) + return AVERROR_INVALIDDATA; + + bytestream2_put_byte(pbc, 0x80); // rbsp_alignment bits + + return bytestream2_tell_p(pbc); +} + +static int extract_extradata_lcevc(AVBSFContext *ctx, AVPacket *pkt, + uint8_t **data, int *size) +{ + static const int extradata_nal_types[] = { + LCEVC_IDR_NUT, LCEVC_NON_IDR_NUT, + }; + + ExtractExtradataContext *s = ctx->priv_data; + PutByteContext pb_extradata; + int extradata_size = 0, filtered_size = 0; + size_t nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types); + int i, ret = 0; + + ret = ff_h2645_packet_split(&s->h2645_pkt, pkt->data, pkt->size, + ctx, 0, ctx->par_in->codec_id, H2645_FLAG_SMALL_PADDING); + if (ret < 0) + return ret; + + for (i = 0; i < s->h2645_pkt.nb_nals; i++) { + H2645NAL *nal = &s->h2645_pkt.nals[i]; + if (val_in_array(extradata_nal_types, nb_extradata_nal_types, nal->type)) { + // dummy pass to find sc, gc or ai. A dummy pointer is used to prevent + // UB in PutByteContext. Nothing will be written. + bytestream2_init_writer(&pb_extradata, nal->data, 0); + if (!write_lcevc_nalu(ctx, &pb_extradata, nal, 0)) + extradata_size += nal->raw_size + 3; + } + filtered_size += nal->raw_size + 3; + } + + if (extradata_size) { + AVBufferRef *filtered_buf = NULL; + PutByteContext pb_filtered_data; + uint8_t *extradata; + + if (s->remove) { + filtered_buf = av_buffer_alloc(filtered_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!filtered_buf) { + return AVERROR(ENOMEM); + } + memset(filtered_buf->data + filtered_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + } + + extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!extradata) { + av_buffer_unref(&filtered_buf); + return AVERROR(ENOMEM); + } + + bytestream2_init_writer(&pb_extradata, extradata, extradata_size); + if (s->remove) + bytestream2_init_writer(&pb_filtered_data, filtered_buf->data, filtered_size); + + for (i = 0; i < s->h2645_pkt.nb_nals; i++) { + H2645NAL *nal = &s->h2645_pkt.nals[i]; + if (val_in_array(extradata_nal_types, nb_extradata_nal_types, + nal->type)) { + bytestream2_put_be24(&pb_extradata, 1); //startcode + ret = write_lcevc_nalu(ctx, &pb_extradata, nal, 0); + if (ret < 0) { + av_freep(&extradata); + av_buffer_unref(&filtered_buf); + return ret; + } + if (s->remove) { + bytestream2_put_be24(&pb_filtered_data, 1); //startcode + ret = write_lcevc_nalu(ctx, &pb_filtered_data, nal, 1); + if (ret < 0) { + av_freep(&extradata); + av_buffer_unref(&filtered_buf); + return ret; + } + } + } else if (s->remove) { + bytestream2_put_be24(&pb_filtered_data, 1); //startcode + bytestream2_put_bufferu(&pb_filtered_data, nal->raw_data, nal->raw_size); + } + } + *data = extradata; + *size = bytestream2_tell_p(&pb_extradata); + av_assert0(*size <= extradata_size); + + if (s->remove) { + av_assert0(bytestream2_tell_p(&pb_filtered_data) <= filtered_size); + av_buffer_unref(&pkt->buf); + pkt->buf = filtered_buf; + pkt->data = filtered_buf->data; + pkt->size = bytestream2_tell_p(&pb_filtered_data); + } + } + + return 0; +} + static int extract_extradata_vc1(AVBSFContext *ctx, AVPacket *pkt, uint8_t **data, int *size) { @@ -371,6 +546,7 @@ static const struct { { AV_CODEC_ID_CAVS, extract_extradata_mpeg4 }, { AV_CODEC_ID_H264, extract_extradata_h2645 }, { AV_CODEC_ID_HEVC, extract_extradata_h2645 }, + { AV_CODEC_ID_LCEVC, extract_extradata_lcevc }, { AV_CODEC_ID_MPEG1VIDEO, extract_extradata_mpeg12 }, { AV_CODEC_ID_MPEG2VIDEO, extract_extradata_mpeg12 }, { AV_CODEC_ID_MPEG4, extract_extradata_mpeg4 }, @@ -441,6 +617,7 @@ static const enum AVCodecID codec_ids[] = { AV_CODEC_ID_CAVS, AV_CODEC_ID_H264, AV_CODEC_ID_HEVC, + AV_CODEC_ID_LCEVC, AV_CODEC_ID_MPEG1VIDEO, AV_CODEC_ID_MPEG2VIDEO, AV_CODEC_ID_MPEG4, diff --git a/libavcodec/bsf/filter_units.c b/libavcodec/bsf/filter_units.c index 336331733..696a1f37c 100644 --- a/libavcodec/bsf/filter_units.c +++ b/libavcodec/bsf/filter_units.c @@ -35,7 +35,8 @@ typedef struct FilterUnitsContext { const char *pass_types; const char *remove_types; - enum AVDiscard discard; + /* enum AVDiscard, use int for AVOption */ + int discard; int discard_flags; enum { diff --git a/libavcodec/bsf/h266_metadata.c b/libavcodec/bsf/h266_metadata.c index 1f0f875cf..2242c620f 100644 --- a/libavcodec/bsf/h266_metadata.c +++ b/libavcodec/bsf/h266_metadata.c @@ -80,7 +80,7 @@ static int h266_metadata_update_fragment(AVBSFContext *bsf, AVPacket *pkt, } } if (!ph) { - av_log(bsf, AV_LOG_ERROR, "no avaliable picture header"); + av_log(bsf, AV_LOG_ERROR, "no available picture header"); return AVERROR_INVALIDDATA; } diff --git a/libavcodec/bsf/hevc_mp4toannexb.c b/libavcodec/bsf/hevc_mp4toannexb.c index f28118576..60f38ac41 100644 --- a/libavcodec/bsf/hevc_mp4toannexb.c +++ b/libavcodec/bsf/hevc_mp4toannexb.c @@ -126,6 +126,7 @@ static int hevc_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) GetByteContext gb; int got_irap = 0; + int got_ps = 0, seen_irap_ps = 0; int i, ret = 0; ret = ff_bsf_get_packet(ctx, &in); @@ -140,10 +141,37 @@ static int hevc_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) bytestream2_init(&gb, in->data, in->size); + while (!got_irap && bytestream2_get_bytes_left(&gb)) { + uint32_t nalu_size = 0; + int nalu_type; + + if (bytestream2_get_bytes_left(&gb) < s->length_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + for (i = 0; i < s->length_size; i++) + nalu_size = (nalu_size << 8) | bytestream2_get_byte(&gb); + + if (nalu_size < 2 || nalu_size > bytestream2_get_bytes_left(&gb)) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + nalu_type = (bytestream2_peek_byte(&gb) >> 1) & 0x3f; + bytestream2_skip(&gb, nalu_size); + got_irap |= nalu_type >= HEVC_NAL_BLA_W_LP && + nalu_type <= HEVC_NAL_RSV_IRAP_VCL23; + got_ps |= nalu_type >= HEVC_NAL_VPS && nalu_type <= HEVC_NAL_PPS; + } + seen_irap_ps = got_irap && got_ps; + got_irap = got_ps = 0; + + bytestream2_init(&gb, in->data, in->size); + while (bytestream2_get_bytes_left(&gb)) { uint32_t nalu_size = 0; int nalu_type; - int is_irap, add_extradata, extra_size, prev_size; + int is_irap, is_ps, add_extradata, extra_size, prev_size; if (bytestream2_get_bytes_left(&gb) < s->length_size) { ret = AVERROR_INVALIDDATA; @@ -162,9 +190,11 @@ static int hevc_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) /* prepend extradata to IRAP frames */ is_irap = nalu_type >= HEVC_NAL_BLA_W_LP && nalu_type <= HEVC_NAL_RSV_IRAP_VCL23; - add_extradata = is_irap && !got_irap; + is_ps = nalu_type >= HEVC_NAL_VPS && nalu_type <= HEVC_NAL_PPS && seen_irap_ps; + add_extradata = (is_ps || is_irap) && !got_ps && !got_irap; extra_size = add_extradata * ctx->par_out->extradata_size; got_irap |= is_irap; + got_ps |= is_ps; if (FFMIN(INT_MAX, SIZE_MAX) < 4ULL + nalu_size + extra_size) { ret = AVERROR_INVALIDDATA; diff --git a/libavcodec/bsf/lcevc_metadata.c b/libavcodec/bsf/lcevc_metadata.c new file mode 100644 index 000000000..451299921 --- /dev/null +++ b/libavcodec/bsf/lcevc_metadata.c @@ -0,0 +1,204 @@ +/* + * 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/opt.h" + +#include "bsf.h" +#include "bsf_internal.h" +#include "cbs.h" +#include "cbs_bsf.h" +#include "cbs_lcevc.h" +#include "lcevc.h" + +typedef struct LCEVCMetadataContext { + CBSBSFContext common; + + int overscan_appropriate_flag; + + int video_format; + int video_full_range_flag; + int colour_primaries; + int transfer_characteristics; + int matrix_coefficients; + + int chroma_sample_loc_type; + + LCEVCRawAdditionalInfo ai; + + int delete_filler; +} LCEVCMetadataContext; + +static int lcevc_metadata_handle_vui(AVBSFContext *bsf, + CodedBitstreamFragment *au) +{ + LCEVCMetadataContext *ctx = bsf->priv_data; + LCEVCRawProcessBlock *block = NULL; + LCEVCRawAdditionalInfo *ai = &ctx->ai; + LCEVCRawVUI *vui = &ai->vui; + int position, err; + + position = ff_cbs_lcevc_find_process_block(ctx->common.output, au, + LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG, + &block); + if (position < 0) + return 0; + + memset(ai, 0, sizeof(*ai)); + ai->additional_info_type = LCEVC_ADDITIONAL_INFO_TYPE_VUI; + + if (ctx->overscan_appropriate_flag >= 0) { + vui->overscan_info_present_flag = 1; + vui->overscan_appropriate_flag = ctx->overscan_appropriate_flag; + } + + if (ctx->video_format >= 0) { + vui->video_signal_type_present_flag = 1; + vui->video_format = ctx->video_format; + } else + vui->video_format = 5; + + if (ctx->video_full_range_flag >= 0) { + vui->video_signal_type_present_flag = 1; + vui->video_full_range_flag = ctx->video_full_range_flag; + } + + if (ctx->colour_primaries >= 0) { + vui->video_signal_type_present_flag = vui->colour_description_present_flag = 1; + vui->colour_primaries = ctx->colour_primaries; + } else + vui->colour_primaries = 2; + if (ctx->transfer_characteristics >= 0) { + vui->video_signal_type_present_flag = vui->colour_description_present_flag = 1; + vui->transfer_characteristics = ctx->transfer_characteristics; + } else + vui->transfer_characteristics = 2; + if (ctx->matrix_coefficients >= 0) { + vui->video_signal_type_present_flag = vui->colour_description_present_flag = 1; + vui->matrix_coefficients = ctx->matrix_coefficients; + } else + vui->matrix_coefficients = 2; + + if (ctx->chroma_sample_loc_type >= 0) { + vui->chroma_loc_info_present_flag = 1; + vui->chroma_sample_loc_type_top_field = ctx->chroma_sample_loc_type; + vui->chroma_sample_loc_type_top_field = ctx->chroma_sample_loc_type; + } + + err = ff_cbs_lcevc_add_process_block(ctx->common.output, au, position, + LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO, + ai, NULL); + if (err < 0) + return err; + + return 0; +} + +static int lcevc_metadata_update_fragment(AVBSFContext *bsf, AVPacket *pkt, + CodedBitstreamFragment *au) +{ + LCEVCMetadataContext *ctx = bsf->priv_data; + int err; + + if (ctx->overscan_appropriate_flag >= 0 || ctx->video_format >= 0 || + ctx->video_full_range_flag >= 0 || ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || ctx->matrix_coefficients >= 0 || + ctx->chroma_sample_loc_type >= 0) { + err = lcevc_metadata_handle_vui(bsf, au); + if (err < 0) + return err; + } + + if (ctx->delete_filler) { + for (int i = 0; i < au->nb_units; i++) { + if (au->units[i].type == LCEVC_NON_IDR_NUT || + au->units[i].type == LCEVC_IDR_NUT) { + ff_cbs_lcevc_delete_process_block_type(ctx->common.output, au, + LCEVC_PAYLOAD_TYPE_FILLER); + } + } + } + + return 0; +} + +static const CBSBSFType lcevc_metadata_type = { + .codec_id = AV_CODEC_ID_LCEVC, + .fragment_name = "access unit", + .unit_name = "NAL unit", + .update_fragment = &lcevc_metadata_update_fragment, +}; + +static int lcevc_metadata_init(AVBSFContext *bsf) +{ + return ff_cbs_bsf_generic_init(bsf, &lcevc_metadata_type); +} + +#define OFFSET(x) offsetof(LCEVCMetadataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption lcevc_metadata_options[] = { + { "overscan_appropriate_flag", "Set VUI overscan appropriate flag", + OFFSET(overscan_appropriate_flag), AV_OPT_TYPE_BOOL, + { .i64 = -1 }, -1, 1, FLAGS }, + + { "video_format", "Set video format (table E-2)", + OFFSET(video_format), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 5, FLAGS}, + { "video_full_range_flag", "Set video full range flag", + OFFSET(video_full_range_flag), AV_OPT_TYPE_BOOL, + { .i64 = -1 }, -1, 1, FLAGS }, + { "colour_primaries", "Set colour primaries (table E-3)", + OFFSET(colour_primaries), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "transfer_characteristics", "Set transfer characteristics (table E-4)", + OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "matrix_coefficients", "Set matrix coefficients (table E-5)", + OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + + { "chroma_sample_loc_type", "Set chroma sample location type (figure E-1)", + OFFSET(chroma_sample_loc_type), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 5, FLAGS }, + + { "delete_filler", "Delete all filler", + OFFSET(delete_filler), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS}, + + { NULL } +}; + +static const AVClass lcevc_metadata_class = { + .class_name = "lcevc_metadata_bsf", + .item_name = av_default_item_name, + .option = lcevc_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID lcevc_metadata_codec_ids[] = { + AV_CODEC_ID_LCEVC, AV_CODEC_ID_NONE, +}; + +const FFBitStreamFilter ff_lcevc_metadata_bsf = { + .p.name = "lcevc_metadata", + .p.codec_ids = lcevc_metadata_codec_ids, + .p.priv_class = &lcevc_metadata_class, + .priv_data_size = sizeof(LCEVCMetadataContext), + .init = &lcevc_metadata_init, + .close = &ff_cbs_bsf_generic_close, + .filter = &ff_cbs_bsf_generic_filter, +}; diff --git a/libavcodec/bsf/noise.c b/libavcodec/bsf/noise.c index a62285571..3462b30f8 100644 --- a/libavcodec/bsf/noise.c +++ b/libavcodec/bsf/noise.c @@ -18,13 +18,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include #include "bsf.h" #include "bsf_internal.h" #include "libavutil/log.h" -#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/eval.h" @@ -79,24 +78,22 @@ typedef struct NoiseContext { static int noise_init(AVBSFContext *ctx) { NoiseContext *s = ctx->priv_data; + const char *amount_str = s->amount_str; int ret; - if (!s->amount_str) { - s->amount_str = (!s->drop_str && !s->dropamount) ? av_strdup("-1") : av_strdup("0"); - if (!s->amount_str) - return AVERROR(ENOMEM); - } + if (!amount_str) + amount_str = (!s->drop_str && !s->dropamount) ? "-1" : "0"; if (ctx->par_in->codec_id == AV_CODEC_ID_WRAPPED_AVFRAME && - strcmp(s->amount_str, "0")) { + strcmp(amount_str, "0")) { av_log(ctx, AV_LOG_ERROR, "Wrapped AVFrame noising is unsupported\n"); return AVERROR_PATCHWELCOME; } - ret = av_expr_parse(&s->amount_pexpr, s->amount_str, + ret = av_expr_parse(&s->amount_pexpr, amount_str, var_names, NULL, NULL, NULL, NULL, 0, ctx); if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Error in parsing expr for amount: %s\n", s->amount_str); + av_log(ctx, AV_LOG_ERROR, "Error in parsing expr for amount: %s\n", amount_str); return ret; } diff --git a/libavcodec/bsf/setts.c b/libavcodec/bsf/setts.c index 9c27b24a3..c447a506c 100644 --- a/libavcodec/bsf/setts.c +++ b/libavcodec/bsf/setts.c @@ -88,6 +88,8 @@ typedef struct SetTSContext { char *duration_str; AVRational time_base; + int user_outtb; + int prescale; int64_t frame_number; @@ -142,20 +144,32 @@ static int setts_init(AVBSFContext *ctx) } } - if (s->time_base.num > 0 && s->time_base.den > 0) + if (s->time_base.num > 0 && s->time_base.den > 0) { ctx->time_base_out = s->time_base; + s->user_outtb = 1; + } else if (s->time_base.num || !s->time_base.den) { + av_log(ctx, AV_LOG_ERROR, "Invalid value %d/%d specified for output timebase\n", s->time_base.num, s->time_base.den); + return AVERROR_INVALIDDATA; + } else + s->prescale = 0; s->frame_number= 0; s->var_values[VAR_STARTPTS] = AV_NOPTS_VALUE; s->var_values[VAR_STARTDTS] = AV_NOPTS_VALUE; s->var_values[VAR_NOPTS] = AV_NOPTS_VALUE; - s->var_values[VAR_TB] = ctx->time_base_in.den ? av_q2d(ctx->time_base_in) : 0; s->var_values[VAR_TB_OUT]= ctx->time_base_out.den ? av_q2d(ctx->time_base_out) : 0; s->var_values[VAR_SR] = ctx->par_in->sample_rate; + if (s->user_outtb && s->prescale) + s->var_values[VAR_TB] = av_q2d(ctx->time_base_out); + else + s->var_values[VAR_TB] = ctx->time_base_in.den ? av_q2d(ctx->time_base_in) : 0; + return 0; } +#define PRESCALED(x) ( s->prescale ? av_rescale_q(x, ctx->time_base_in, ctx->time_base_out) : x ) + static int setts_filter(AVBSFContext *ctx, AVPacket *pkt) { SetTSContext *s = ctx->priv_data; @@ -172,39 +186,39 @@ static int setts_filter(AVBSFContext *ctx, AVPacket *pkt) } if (s->var_values[VAR_STARTPTS] == AV_NOPTS_VALUE) - s->var_values[VAR_STARTPTS] = s->cur_pkt->pts; + s->var_values[VAR_STARTPTS] = PRESCALED(s->cur_pkt->pts); if (s->var_values[VAR_STARTDTS] == AV_NOPTS_VALUE) - s->var_values[VAR_STARTDTS] = s->cur_pkt->dts; + s->var_values[VAR_STARTDTS] = PRESCALED(s->cur_pkt->dts); s->var_values[VAR_N] = s->frame_number++; - s->var_values[VAR_TS] = s->cur_pkt->dts; + s->var_values[VAR_TS] = PRESCALED(s->cur_pkt->dts); s->var_values[VAR_POS] = s->cur_pkt->pos; - s->var_values[VAR_PTS] = s->cur_pkt->pts; - s->var_values[VAR_DTS] = s->cur_pkt->dts; - s->var_values[VAR_DURATION] = s->cur_pkt->duration; - s->var_values[VAR_PREV_INPTS] = s->prev_inpkt->pts; - s->var_values[VAR_PREV_INDTS] = s->prev_inpkt->dts; - s->var_values[VAR_PREV_INDUR] = s->prev_inpkt->duration; + s->var_values[VAR_PTS] = PRESCALED(s->cur_pkt->pts); + s->var_values[VAR_DTS] = PRESCALED(s->cur_pkt->dts); + s->var_values[VAR_DURATION] = PRESCALED(s->cur_pkt->duration); + s->var_values[VAR_PREV_INPTS] = PRESCALED(s->prev_inpkt->pts); + s->var_values[VAR_PREV_INDTS] = PRESCALED(s->prev_inpkt->dts); + s->var_values[VAR_PREV_INDUR] = PRESCALED(s->prev_inpkt->duration); s->var_values[VAR_PREV_OUTPTS] = s->prev_outpkt->pts; s->var_values[VAR_PREV_OUTDTS] = s->prev_outpkt->dts; s->var_values[VAR_PREV_OUTDUR] = s->prev_outpkt->duration; - s->var_values[VAR_NEXT_PTS] = pkt->pts; - s->var_values[VAR_NEXT_DTS] = pkt->dts; - s->var_values[VAR_NEXT_DUR] = pkt->duration; + s->var_values[VAR_NEXT_PTS] = PRESCALED(pkt->pts); + s->var_values[VAR_NEXT_DTS] = PRESCALED(pkt->dts); + s->var_values[VAR_NEXT_DUR] = PRESCALED(pkt->duration); new_ts = llrint(av_expr_eval(s->ts_expr, s->var_values, NULL)); new_duration = llrint(av_expr_eval(s->duration_expr, s->var_values, NULL)); if (s->pts_str) { - s->var_values[VAR_TS] = s->cur_pkt->pts; + s->var_values[VAR_TS] = PRESCALED(s->cur_pkt->pts); new_pts = llrint(av_expr_eval(s->pts_expr, s->var_values, NULL)); } else { new_pts = new_ts; } if (s->dts_str) { - s->var_values[VAR_TS] = s->cur_pkt->dts; + s->var_values[VAR_TS] = PRESCALED(s->cur_pkt->dts); new_dts = llrint(av_expr_eval(s->dts_expr, s->var_values, NULL)); } else { new_dts = new_ts; @@ -219,6 +233,12 @@ static int setts_filter(AVBSFContext *ctx, AVPacket *pkt) if (ret < 0) return ret; + if (s->user_outtb && !s->prescale) { + new_pts = av_rescale_q(new_pts, ctx->time_base_in, ctx->time_base_out); + new_dts = av_rescale_q(new_dts, ctx->time_base_in, ctx->time_base_out); + new_duration = av_rescale_q(new_duration, ctx->time_base_in, ctx->time_base_out); + } + pkt->pts = new_pts; pkt->dts = new_dts; pkt->duration = new_duration; @@ -257,6 +277,7 @@ static const AVOption options[] = { { "dts", "set expression for packet DTS", OFFSET(dts_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS }, { "duration", "set expression for packet duration", OFFSET(duration_str), AV_OPT_TYPE_STRING, {.str="DURATION"}, 0, 0, FLAGS }, { "time_base", "set output timebase", OFFSET(time_base), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS }, + { "prescale", "convert to output timebase before evaluation", OFFSET(prescale), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, { NULL }, }; diff --git a/libavcodec/bsf/smpte436m_to_eia608.c b/libavcodec/bsf/smpte436m_to_eia608.c new file mode 100644 index 000000000..529ae8879 --- /dev/null +++ b/libavcodec/bsf/smpte436m_to_eia608.c @@ -0,0 +1,91 @@ +/* + * MXF SMPTE-436M ANC to EIA-608 bitstream filter + * Copyright (c) 2025 Jacob Lifshay + * + * 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 "bsf.h" +#include "bsf_internal.h" +#include "codec_id.h" +#include "libavcodec/smpte_436m.h" +#include "libavutil/error.h" + +static av_cold int ff_smpte436m_to_eia608_init(AVBSFContext *ctx) +{ + ctx->par_out->codec_type = AVMEDIA_TYPE_SUBTITLE; + ctx->par_out->codec_id = AV_CODEC_ID_EIA_608; + return 0; +} + +static int ff_smpte436m_to_eia608_filter(AVBSFContext *ctx, AVPacket *out) +{ + AVPacket *in; + int ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + AVSmpte436mAncIterator iter; + ret = av_smpte_436m_anc_iter_init(&iter, in->data, in->size); + if (ret < 0) + goto fail; + AVSmpte436mCodedAnc coded_anc; + while ((ret = av_smpte_436m_anc_iter_next(&iter, &coded_anc)) >= 0) { + AVSmpte291mAnc8bit anc; + ret = av_smpte_291m_anc_8bit_decode( + &anc, coded_anc.payload_sample_coding, coded_anc.payload_sample_count, coded_anc.payload, ctx); + if (ret < 0) + goto fail; + ret = av_smpte_291m_anc_8bit_extract_cta_708(&anc, NULL, ctx); + if (ret == AVERROR(EAGAIN)) + continue; + if (ret < 0) + goto fail; + int cc_count = ret; + + ret = av_new_packet(out, 3 * cc_count); + if (ret < 0) + goto fail; + + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; + + // verified it won't fail by running it above + av_smpte_291m_anc_8bit_extract_cta_708(&anc, out->data, ctx); + + av_packet_free(&in); + + return 0; + } + if (ret != AVERROR_EOF) + return ret; + ret = AVERROR(EAGAIN); + +fail: + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + return ret; +} + +const FFBitStreamFilter ff_smpte436m_to_eia608_bsf = { + .p.name = "smpte436m_to_eia608", + .p.codec_ids = (const enum AVCodecID[]){ AV_CODEC_ID_SMPTE_436M_ANC, AV_CODEC_ID_NONE }, + .init = ff_smpte436m_to_eia608_init, + .filter = ff_smpte436m_to_eia608_filter, +}; diff --git a/libavcodec/bswapdsp.c b/libavcodec/bswapdsp.c index f0ea2b55c..266aeca44 100644 --- a/libavcodec/bswapdsp.c +++ b/libavcodec/bswapdsp.c @@ -24,19 +24,7 @@ static void bswap_buf(uint32_t *dst, const uint32_t *src, int w) { - int i; - - for (i = 0; i + 8 <= w; i += 8) { - dst[i + 0] = av_bswap32(src[i + 0]); - dst[i + 1] = av_bswap32(src[i + 1]); - dst[i + 2] = av_bswap32(src[i + 2]); - dst[i + 3] = av_bswap32(src[i + 3]); - dst[i + 4] = av_bswap32(src[i + 4]); - dst[i + 5] = av_bswap32(src[i + 5]); - dst[i + 6] = av_bswap32(src[i + 6]); - dst[i + 7] = av_bswap32(src[i + 7]); - } - for (; i < w; i++) + for (int i = 0; i < w; i++) dst[i + 0] = av_bswap32(src[i + 0]); } @@ -53,7 +41,7 @@ av_cold void ff_bswapdsp_init(BswapDSPContext *c) #if ARCH_RISCV ff_bswapdsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_bswapdsp_init_x86(c); #endif } diff --git a/libavcodec/bytestream.h b/libavcodec/bytestream.h index 67080604b..9c13a2791 100644 --- a/libavcodec/bytestream.h +++ b/libavcodec/bytestream.h @@ -77,11 +77,11 @@ static av_always_inline type bytestream2_get_ ## name(GetByteContext *g) \ } \ return bytestream2_get_ ## name ## u(g); \ } \ -static av_always_inline type bytestream2_peek_ ## name ## u(GetByteContext *g) \ +static av_always_inline type bytestream2_peek_ ## name ## u(const GetByteContext *g) \ { \ return read(g->buffer); \ } \ -static av_always_inline type bytestream2_peek_ ## name(GetByteContext *g) \ +static av_always_inline type bytestream2_peek_ ## name(const GetByteContext *g)\ { \ if (g->buffer_end - g->buffer < bytes) \ return 0; \ @@ -155,12 +155,12 @@ static av_always_inline void bytestream2_init_writer(PutByteContext *p, p->eof = 0; } -static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g) +static av_always_inline int bytestream2_get_bytes_left(const GetByteContext *g) { return g->buffer_end - g->buffer; } -static av_always_inline int bytestream2_get_bytes_left_p(PutByteContext *p) +static av_always_inline int bytestream2_get_bytes_left_p(const PutByteContext *p) { return p->buffer_end - p->buffer; } @@ -189,22 +189,22 @@ static av_always_inline void bytestream2_skip_p(PutByteContext *p, p->buffer += size2; } -static av_always_inline int bytestream2_tell(GetByteContext *g) +static av_always_inline int bytestream2_tell(const GetByteContext *g) { return (int)(g->buffer - g->buffer_start); } -static av_always_inline int bytestream2_tell_p(PutByteContext *p) +static av_always_inline int bytestream2_tell_p(const PutByteContext *p) { return (int)(p->buffer - p->buffer_start); } -static av_always_inline int bytestream2_size(GetByteContext *g) +static av_always_inline int bytestream2_size(const GetByteContext *g) { return (int)(g->buffer_end - g->buffer_start); } -static av_always_inline int bytestream2_size_p(PutByteContext *p) +static av_always_inline int bytestream2_size_p(const PutByteContext *p) { return (int)(p->buffer_end - p->buffer_start); } diff --git a/libavcodec/c93.c b/libavcodec/c93.c index 2a4fe4595..288b1f0ea 100644 --- a/libavcodec/c93.c +++ b/libavcodec/c93.c @@ -246,11 +246,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, for (i = 0; i < 256; i++) { palette[i] = 0xFFU << 24 | bytestream2_get_be24(&gb); } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - newpic->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } else { if (oldpic->data[1]) memcpy(newpic->data[1], oldpic->data[1], 256 * 4); diff --git a/libavcodec/cabac_functions.h b/libavcodec/cabac_functions.h index c3f08d341..6a2e9ceca 100644 --- a/libavcodec/cabac_functions.h +++ b/libavcodec/cabac_functions.h @@ -137,16 +137,16 @@ static av_always_inline int get_cabac_inline(CABACContext *c, uint8_t * const st } #endif -static int av_noinline av_unused get_cabac_noinline(CABACContext *c, uint8_t * const state){ +av_unused av_noinline static int 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){ +av_unused static int 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){ +av_unused static int get_cabac_bypass(CABACContext *c){ int range; c->low += c->low; @@ -184,7 +184,7 @@ static av_always_inline int get_cabac_bypass_sign(CABACContext *c, int val){ * @return the number of bytes read or 0 if no end */ #ifndef get_cabac_terminate -static int av_unused get_cabac_terminate(CABACContext *c){ +av_unused static int get_cabac_terminate(CABACContext *c){ c->range -= 2; if(c->low < c->range<<(CABAC_BITS+1)){ renorm_cabac_decoder_once(c); @@ -200,7 +200,7 @@ static int av_unused get_cabac_terminate(CABACContext *c){ * @return the address of the first skipped byte or NULL if there's less than @p n bytes left */ #ifndef skip_bytes -static av_unused const uint8_t* skip_bytes(CABACContext *c, int n) { +av_unused static const uint8_t* skip_bytes(CABACContext *c, int n) { const uint8_t *ptr = c->bytestream; if (c->low & 0x1) diff --git a/libavcodec/cavs.c b/libavcodec/cavs.c index 172cc5cc7..4db689245 100644 --- a/libavcodec/cavs.c +++ b/libavcodec/cavs.c @@ -387,7 +387,7 @@ void ff_cavs_modify_mb_i(AVSContext *h, int *pred_mode_uv) ****************************************************************************/ static inline void mc_dir_part(AVSContext *h, AVFrame *pic, int chroma_height, - int delta, int list, uint8_t *dest_y, + int list, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int src_x_offset, int src_y_offset, qpel_mc_func *qpix_op, @@ -452,7 +452,7 @@ static inline void mc_dir_part(AVSContext *h, AVFrame *pic, int chroma_height, chroma_op(dest_cr, src_cr, h->c_stride, chroma_height, mx & 7, my & 7); } -static inline void mc_part_std(AVSContext *h, int chroma_height, int delta, +static inline void mc_part_std(AVSContext *h, int chroma_height, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, @@ -474,7 +474,7 @@ static inline void mc_part_std(AVSContext *h, int chroma_height, int delta, if (mv->ref >= 0) { AVFrame *ref = h->DPB[mv->ref].f; - mc_dir_part(h, ref, chroma_height, delta, 0, + mc_dir_part(h, ref, chroma_height, 0, dest_y, dest_cb, dest_cr, x_offset, y_offset, qpix_op, chroma_op, mv); @@ -484,7 +484,7 @@ static inline void mc_part_std(AVSContext *h, int chroma_height, int delta, if ((mv + MV_BWD_OFFS)->ref >= 0) { AVFrame *ref = h->DPB[0].f; - mc_dir_part(h, ref, chroma_height, delta, 1, + mc_dir_part(h, ref, chroma_height, 1, dest_y, dest_cb, dest_cr, x_offset, y_offset, qpix_op, chroma_op, mv + MV_BWD_OFFS); } @@ -493,32 +493,32 @@ static inline void mc_part_std(AVSContext *h, int chroma_height, int delta, void ff_cavs_inter(AVSContext *h, enum cavs_mb mb_type) { if (ff_cavs_partition_flags[mb_type] == 0) { // 16x16 - mc_part_std(h, 8, 0, h->cy, h->cu, h->cv, 0, 0, + mc_part_std(h, 8, h->cy, h->cu, h->cv, 0, 0, h->cdsp.put_cavs_qpel_pixels_tab[0], h->h264chroma.put_h264_chroma_pixels_tab[0], h->cdsp.avg_cavs_qpel_pixels_tab[0], h->h264chroma.avg_h264_chroma_pixels_tab[0], &h->mv[MV_FWD_X0]); } else { - mc_part_std(h, 4, 0, h->cy, h->cu, h->cv, 0, 0, + mc_part_std(h, 4, h->cy, h->cu, h->cv, 0, 0, h->cdsp.put_cavs_qpel_pixels_tab[1], h->h264chroma.put_h264_chroma_pixels_tab[1], h->cdsp.avg_cavs_qpel_pixels_tab[1], h->h264chroma.avg_h264_chroma_pixels_tab[1], &h->mv[MV_FWD_X0]); - mc_part_std(h, 4, 0, h->cy, h->cu, h->cv, 4, 0, + mc_part_std(h, 4, h->cy, h->cu, h->cv, 4, 0, h->cdsp.put_cavs_qpel_pixels_tab[1], h->h264chroma.put_h264_chroma_pixels_tab[1], h->cdsp.avg_cavs_qpel_pixels_tab[1], h->h264chroma.avg_h264_chroma_pixels_tab[1], &h->mv[MV_FWD_X1]); - mc_part_std(h, 4, 0, h->cy, h->cu, h->cv, 0, 4, + mc_part_std(h, 4, h->cy, h->cu, h->cv, 0, 4, h->cdsp.put_cavs_qpel_pixels_tab[1], h->h264chroma.put_h264_chroma_pixels_tab[1], h->cdsp.avg_cavs_qpel_pixels_tab[1], h->h264chroma.avg_h264_chroma_pixels_tab[1], &h->mv[MV_FWD_X2]); - mc_part_std(h, 4, 0, h->cy, h->cu, h->cv, 4, 4, + mc_part_std(h, 4, h->cy, h->cu, h->cv, 4, 4, h->cdsp.put_cavs_qpel_pixels_tab[1], h->h264chroma.put_h264_chroma_pixels_tab[1], h->cdsp.avg_cavs_qpel_pixels_tab[1], diff --git a/libavcodec/cavs.h b/libavcodec/cavs.h index 244c322b3..d3a88ca40 100644 --- a/libavcodec/cavs.h +++ b/libavcodec/cavs.h @@ -146,7 +146,7 @@ enum cavs_mv_loc { MV_BWD_X3 }; -DECLARE_ALIGNED(8, typedef, struct) { +typedef struct cavs_vector { int16_t x; int16_t y; int16_t dist; @@ -207,7 +207,7 @@ typedef struct AVSContext { D is the macroblock to the top-left (0) the same is repeated for backward motion vectors */ - cavs_vector mv[2*4*3]; + DECLARE_ALIGNED(8, cavs_vector, mv)[2*4*3]; cavs_vector *top_mv[2]; cavs_vector *col_mv; diff --git a/libavcodec/cavs_parser.c b/libavcodec/cavs_parser.c index 4a03effd0..8dccc0923 100644 --- a/libavcodec/cavs_parser.c +++ b/libavcodec/cavs_parser.c @@ -27,6 +27,10 @@ #include "parser.h" #include "cavs.h" +#include "get_bits.h" +#include "mpeg12data.h" +#include "parser_internal.h" +#include "startcode.h" /** @@ -72,6 +76,86 @@ static int cavs_find_frame_end(ParseContext *pc, const uint8_t *buf, return END_NOT_FOUND; } +static int parse_seq_header(AVCodecParserContext *s, AVCodecContext *avctx, + GetBitContext *gb) +{ + int frame_rate_code; + int width, height; + int mb_width, mb_height; + + skip_bits(gb, 8); // profile + skip_bits(gb, 8); // level + skip_bits1(gb); // progressive sequence + + width = get_bits(gb, 14); + height = get_bits(gb, 14); + if (width <= 0 || height <= 0) { + av_log(avctx, AV_LOG_ERROR, "Dimensions invalid\n"); + return AVERROR_INVALIDDATA; + } + mb_width = (width + 15) >> 4; + mb_height = (height + 15) >> 4; + + skip_bits(gb, 2); // chroma format + skip_bits(gb, 3); // sample_precision + skip_bits(gb, 4); // aspect_ratio + frame_rate_code = get_bits(gb, 4); + if (frame_rate_code == 0 || frame_rate_code > 13) { + av_log(avctx, AV_LOG_WARNING, + "frame_rate_code %d is invalid\n", frame_rate_code); + frame_rate_code = 1; + } + + skip_bits(gb, 18); // bit_rate_lower + skip_bits1(gb); // marker_bit + skip_bits(gb, 12); // bit_rate_upper + skip_bits1(gb); // low_delay + + s->width = width; + s->height = height; + s->coded_width = 16 * mb_width; + s->coded_height = 16 * mb_height; + avctx->framerate = ff_mpeg12_frame_rate_tab[frame_rate_code]; + + return 0; +} + +static int cavs_parse_frame(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t *buf, int buf_size) +{ + GetBitContext gb; + const uint8_t *buf_end; + const uint8_t *buf_ptr; + uint32_t stc = -1; + + s->key_frame = 0; + s->pict_type = AV_PICTURE_TYPE_NONE; + + if (buf_size == 0) + return 0; + + buf_ptr = buf; + buf_end = buf + buf_size; + for (;;) { + buf_ptr = avpriv_find_start_code(buf_ptr, buf_end, &stc); + if ((stc & 0xFFFFFE00) || buf_ptr == buf_end) + return 0; + switch (stc) { + case CAVS_START_CODE: + if (init_get_bits8(&gb, buf_ptr, buf_end - buf_ptr) < 0) + return 0; + parse_seq_header(s, avctx, &gb); + break; + case PIC_I_START_CODE: + s->key_frame = 1; + s->pict_type = AV_PICTURE_TYPE_I; + break; + default: + break; + } + } +} + static int cavsvideo_parse(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, @@ -91,14 +175,17 @@ static int cavsvideo_parse(AVCodecParserContext *s, return buf_size; } } + + cavs_parse_frame(s, avctx, buf, buf_size); + *poutbuf = buf; *poutbuf_size = buf_size; return next; } -const AVCodecParser ff_cavsvideo_parser = { - .codec_ids = { AV_CODEC_ID_CAVS }, +const FFCodecParser ff_cavsvideo_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_CAVS), .priv_data_size = sizeof(ParseContext), - .parser_parse = cavsvideo_parse, - .parser_close = ff_parse_close, + .parse = cavsvideo_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c index 3cf8c9fb3..fffe0657f 100644 --- a/libavcodec/cavsdec.c +++ b/libavcodec/cavsdec.c @@ -25,6 +25,7 @@ * @author Stefan Gehrer */ +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/emms.h" #include "libavutil/mem.h" @@ -1184,7 +1185,7 @@ static int decode_seq_header(AVSContext *h) h->profile = get_bits(&h->gb, 8); if (h->profile != 0x20) { avpriv_report_missing_feature(h->avctx, - "only supprt JiZhun profile"); + "only support JiZhun profile"); return AVERROR_PATCHWELCOME; } h->level = get_bits(&h->gb, 8); @@ -1230,7 +1231,7 @@ static int decode_seq_header(AVSContext *h) return 0; } -static void cavs_flush(AVCodecContext * avctx) +static av_cold void cavs_flush(AVCodecContext * avctx) { AVSContext *h = avctx->priv_data; h->got_keyframe = 0; diff --git a/libavcodec/cavsdsp.c b/libavcodec/cavsdsp.c index 69420242d..7444f17bb 100644 --- a/libavcodec/cavsdsp.c +++ b/libavcodec/cavsdsp.c @@ -577,7 +577,7 @@ av_cold void ff_cavsdsp_init(CAVSDSPContext* c) c->cavs_idct8_add = cavs_idct8_add_c; c->idct_perm = FF_IDCT_PERM_NONE; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_cavsdsp_init_x86(c); #endif } diff --git a/libavcodec/cbrt_data.h b/libavcodec/cbrt_data.h index 89117f85b..8ae3b7651 100644 --- a/libavcodec/cbrt_data.h +++ b/libavcodec/cbrt_data.h @@ -23,18 +23,36 @@ #include -#include "config.h" +#define LUT_SIZE (1 << 13) -#if CONFIG_HARDCODED_TABLES +#ifndef BUILD_TABLES +#include "config.h" +#define BUILD_TABLES !CONFIG_HARDCODED_TABLES +#endif + +#if !BUILD_TABLES #define ff_cbrt_tableinit_fixed() #define ff_cbrt_tableinit() -extern const uint32_t ff_cbrt_tab[1 << 13]; -extern const uint32_t ff_cbrt_tab_fixed[1 << 13]; +extern const uint32_t ff_cbrt_tab[LUT_SIZE]; +extern const uint32_t ff_cbrt_tab_fixed[LUT_SIZE]; #else void ff_cbrt_tableinit(void); void ff_cbrt_tableinit_fixed(void); -extern uint32_t ff_cbrt_tab[1 << 13]; -extern uint32_t ff_cbrt_tab_fixed[1 << 13]; + +#define TMP_LUT_SIZE (LUT_SIZE / 2) +/** + * Creates a LUT (of doubles) for the powers of + * the odd integers: tmp_lut[idx] will be set to (2 * idx + 1)^{4/3}. + */ +void ff_cbrt_dbl_tableinit(double tmp_lut[TMP_LUT_SIZE]); + +extern union CBRT { + uint32_t cbrt_tab[LUT_SIZE]; + double tmp[TMP_LUT_SIZE]; +} ff_cbrt_tab_internal, ff_cbrt_tab_internal_fixed; + +#define ff_cbrt_tab ff_cbrt_tab_internal.cbrt_tab +#define ff_cbrt_tab_fixed ff_cbrt_tab_internal_fixed.cbrt_tab #endif #endif diff --git a/libavcodec/cbrt_tablegen.h b/libavcodec/cbrt_tablegen.h index 9af18d8ab..90076dfd8 100644 --- a/libavcodec/cbrt_tablegen.h +++ b/libavcodec/cbrt_tablegen.h @@ -23,11 +23,13 @@ #ifndef AVCODEC_CBRT_TABLEGEN_H #define AVCODEC_CBRT_TABLEGEN_H +#include #include #include #include "libavutil/attributes.h" #include "libavutil/intfloat.h" #include "libavcodec/aac_defines.h" +#include "cbrt_data.h" #if USE_FIXED #define CBRT(x) lrint((x) * 8192) @@ -35,39 +37,30 @@ #define CBRT(x) av_float2int((float)(x)) #endif -uint32_t AAC_RENAME(ff_cbrt_tab)[1 << 13]; +union CBRT AAC_RENAME(ff_cbrt_tab_internal); av_cold void AAC_RENAME(ff_cbrt_tableinit)(void) { - static double cbrt_tab_dbl[1 << 13]; - if (!AAC_RENAME(ff_cbrt_tab)[(1<<13) - 1]) { - int i, j, k; - double cbrt_val; + static_assert(2 * sizeof(AAC_RENAME(ff_cbrt_tab_internal).cbrt_tab[0]) + >= sizeof(AAC_RENAME(ff_cbrt_tab_internal).tmp[0]), + "unexpected sizeofs"); + // We reuse ff_cbrt_tab_internal.tmp as a LUT (of doubles) for the roots + // of the odd integers: tmp[idx] contains (2 * idx + 1)^{4/3}. + ff_cbrt_dbl_tableinit(AAC_RENAME(ff_cbrt_tab_internal).tmp); - for (i = 1; i < 1<<13; i++) - cbrt_tab_dbl[i] = 1; - - /* have to take care of non-squarefree numbers */ - for (i = 2; i < 90; i++) { - if (cbrt_tab_dbl[i] == 1) { - cbrt_val = i * cbrt(i); - for (k = i; k < 1<<13; k *= i) - for (j = k; j < 1<<13; j += k) - cbrt_tab_dbl[j] *= cbrt_val; - } + double cbrt_2 = 2 * cbrt(2); + for (int idx = TMP_LUT_SIZE - 1; idx >= 0; --idx) { + double cbrt_val = AAC_RENAME(ff_cbrt_tab_internal).tmp[idx]; + // Due to i * sizeof(ff_cbrt_tab_internal.cbrt_tab[0]) >= + // 2 * idx * sizeof(ff_cbrt_tab_internal.cbrt_tab[0]) >= idx * sizeof(double) + // we don't clobber the double-LUT entries with index < idx + // in the loop below. This is why we process idx in descending order. + for (int i = 2 * idx + 1; i < LUT_SIZE; i *= 2) { + AAC_RENAME(ff_cbrt_tab_internal).cbrt_tab[i] = CBRT(cbrt_val); + cbrt_val *= cbrt_2; } - - for (i = 91; i <= 8191; i+= 2) { - if (cbrt_tab_dbl[i] == 1) { - cbrt_val = i * cbrt(i); - for (j = i; j < 1<<13; j += i) - cbrt_tab_dbl[j] *= cbrt_val; - } - } - - for (i = 0; i < 1<<13; i++) - AAC_RENAME(ff_cbrt_tab)[i] = CBRT(cbrt_tab_dbl[i]); } + AAC_RENAME(ff_cbrt_tab_internal).cbrt_tab[0] = CBRT(0); } #endif /* AVCODEC_CBRT_TABLEGEN_H */ diff --git a/libavcodec/cbrt_tablegen_common.c b/libavcodec/cbrt_tablegen_common.c new file mode 100644 index 000000000..9b95a6e44 --- /dev/null +++ b/libavcodec/cbrt_tablegen_common.c @@ -0,0 +1,60 @@ +/* + * Common code for AAC cube-root table + * + * Copyright (c) 2010 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 + */ + +#include + +#include "cbrt_data.h" +#include "libavutil/attributes.h" +#ifdef HAVE_AV_CONFIG_H // Only include libm.h when building for the target, not the host +#include "libavutil/libm.h" +#endif + +av_cold void ff_cbrt_dbl_tableinit(double tmp_lut[TMP_LUT_SIZE]) +{ + for (int idx = 0; idx < TMP_LUT_SIZE; ++idx) + tmp_lut[idx] = 1; + + /* have to take care of non-squarefree numbers; notice that sqrt(LUT_SIZE) = 90; + * idx == 44 corresponds to 89. */ + for (int idx = 1; idx < 45; ++idx) { + if (tmp_lut[idx] == 1) { + int i = 2 * idx + 1; + double cbrt_val = i * cbrt(i); + for (int k = i; k < LUT_SIZE; k *= i) { + // We only have to handle k, 3 * k, 5 * k,..., + // because only these are odd. The corresponding indices are + // k >> 1, (k >> 1) + k, (k >> 1) + 2 * k,... + for (int idx2 = k >> 1; idx2 < TMP_LUT_SIZE; idx2 += k) + tmp_lut[idx2] *= cbrt_val; + } + } + } + + for (int idx = 45; idx < TMP_LUT_SIZE; ++idx) { + if (tmp_lut[idx] == 1) { + int i = 2 * idx + 1; + double cbrt_val = i * cbrt(i); + for (int idx2 = idx; idx2 < TMP_LUT_SIZE; idx2 += i) + tmp_lut[idx2] *= cbrt_val; + } + } +} diff --git a/libavcodec/cbrt_tablegen_template.c b/libavcodec/cbrt_tablegen_template.c index 21ed2a686..4f6aa7e48 100644 --- a/libavcodec/cbrt_tablegen_template.c +++ b/libavcodec/cbrt_tablegen_template.c @@ -21,9 +21,10 @@ */ #include -#define CONFIG_HARDCODED_TABLES 0 +#define BUILD_TABLES 1 #include "libavutil/tablegen.h" #include "cbrt_tablegen.h" +#include "cbrt_tablegen_common.c" #include "tableprint.h" int main(void) diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index b26e39eab..b045b73b6 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -18,8 +18,6 @@ #include -#include "config.h" - #include "libavutil/avassert.h" #include "libavutil/buffer.h" #include "libavutil/common.h" @@ -29,65 +27,77 @@ #include "avcodec.h" #include "cbs.h" #include "cbs_internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" static const CodedBitstreamType *const cbs_type_table[] = { -#if CONFIG_CBS_AV1 - &ff_cbs_type_av1, +#if CBS_APV + &CBS_FUNC(type_apv), #endif -#if CONFIG_CBS_H264 - &ff_cbs_type_h264, +#if CBS_AV1 + &CBS_FUNC(type_av1), #endif -#if CONFIG_CBS_H265 - &ff_cbs_type_h265, +#if CBS_H264 + &CBS_FUNC(type_h264), #endif -#if CONFIG_CBS_H266 - &ff_cbs_type_h266, +#if CBS_H265 + &CBS_FUNC(type_h265), #endif -#if CONFIG_CBS_JPEG - &ff_cbs_type_jpeg, +#if CBS_H266 + &CBS_FUNC(type_h266), #endif -#if CONFIG_CBS_MPEG2 - &ff_cbs_type_mpeg2, +#if CBS_LCEVC + &CBS_FUNC(type_lcevc), #endif -#if CONFIG_CBS_VP8 - &ff_cbs_type_vp8, +#if CBS_JPEG + &CBS_FUNC(type_jpeg), #endif -#if CONFIG_CBS_VP9 - &ff_cbs_type_vp9, +#if CBS_MPEG2 + &CBS_FUNC(type_mpeg2), +#endif +#if CBS_VP8 + &CBS_FUNC(type_vp8), +#endif +#if CBS_VP9 + &CBS_FUNC(type_vp9), #endif }; -const enum AVCodecID ff_cbs_all_codec_ids[] = { -#if CONFIG_CBS_AV1 +const enum AVCodecID CBS_FUNC(all_codec_ids)[] = { +#if CBS_APV + AV_CODEC_ID_APV, +#endif +#if CBS_AV1 AV_CODEC_ID_AV1, #endif -#if CONFIG_CBS_H264 +#if CBS_H264 AV_CODEC_ID_H264, #endif -#if CONFIG_CBS_H265 +#if CBS_H265 AV_CODEC_ID_H265, #endif -#if CONFIG_CBS_H266 +#if CBS_H266 AV_CODEC_ID_H266, #endif -#if CONFIG_CBS_JPEG +#if CBS_LCEVC + AV_CODEC_ID_LCEVC, +#endif +#if CBS_JPEG AV_CODEC_ID_MJPEG, #endif -#if CONFIG_CBS_MPEG2 +#if CBS_MPEG2 AV_CODEC_ID_MPEG2VIDEO, #endif -#if CONFIG_CBS_VP8 +#if CBS_VP8 AV_CODEC_ID_VP8, #endif -#if CONFIG_CBS_VP9 +#if CBS_VP9 AV_CODEC_ID_VP9, #endif AV_CODEC_ID_NONE }; -av_cold int ff_cbs_init(CodedBitstreamContext **ctx_ptr, +av_cold int CBS_FUNC(init)(CodedBitstreamContext **ctx_ptr, enum AVCodecID codec_id, void *log_ctx) { CodedBitstreamContext *ctx; @@ -133,13 +143,13 @@ av_cold int ff_cbs_init(CodedBitstreamContext **ctx_ptr, return 0; } -av_cold void ff_cbs_flush(CodedBitstreamContext *ctx) +av_cold void CBS_FUNC(flush)(CodedBitstreamContext *ctx) { if (ctx->codec->flush) ctx->codec->flush(ctx); } -av_cold void ff_cbs_close(CodedBitstreamContext **ctx_ptr) +av_cold void CBS_FUNC(close)(CodedBitstreamContext **ctx_ptr) { CodedBitstreamContext *ctx = *ctx_ptr; @@ -160,7 +170,7 @@ av_cold void ff_cbs_close(CodedBitstreamContext **ctx_ptr) static void cbs_unit_uninit(CodedBitstreamUnit *unit) { - ff_refstruct_unref(&unit->content_ref); + av_refstruct_unref(&unit->content_ref); unit->content = NULL; av_buffer_unref(&unit->data_ref); @@ -169,7 +179,7 @@ static void cbs_unit_uninit(CodedBitstreamUnit *unit) unit->data_bit_padding = 0; } -void ff_cbs_fragment_reset(CodedBitstreamFragment *frag) +void CBS_FUNC(fragment_reset)(CodedBitstreamFragment *frag) { int i; @@ -183,14 +193,15 @@ void ff_cbs_fragment_reset(CodedBitstreamFragment *frag) frag->data_bit_padding = 0; } -av_cold void ff_cbs_fragment_free(CodedBitstreamFragment *frag) +av_cold void CBS_FUNC(fragment_free)(CodedBitstreamFragment *frag) { - ff_cbs_fragment_reset(frag); + CBS_FUNC(fragment_reset)(frag); av_freep(&frag->units); frag->nb_units_allocated = 0; } +#if CBS_READ static int cbs_read_fragment_content(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag) { @@ -208,7 +219,7 @@ static int cbs_read_fragment_content(CodedBitstreamContext *ctx, continue; } - ff_refstruct_unref(&unit->content_ref); + av_refstruct_unref(&unit->content_ref); unit->content = NULL; av_assert0(unit->data && unit->data_ref); @@ -222,11 +233,12 @@ static int cbs_read_fragment_content(CodedBitstreamContext *ctx, av_log(ctx->log_ctx, AV_LOG_VERBOSE, "Skipping decomposition of unit %d " "(type %"PRIu32").\n", i, unit->type); - ff_refstruct_unref(&unit->content_ref); + av_refstruct_unref(&unit->content_ref); unit->content = NULL; } else if (err < 0) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d " - "(type %"PRIu32").\n", i, unit->type); + "(type %"PRIu32"): %s.\n", + i, unit->type, av_err2str(err)); return err; } } @@ -256,7 +268,7 @@ static int cbs_fill_fragment_data(CodedBitstreamFragment *frag, static int cbs_read_data(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, - AVBufferRef *buf, + const AVBufferRef *buf, const uint8_t *data, size_t size, int header) { @@ -283,7 +295,7 @@ static int cbs_read_data(CodedBitstreamContext *ctx, return cbs_read_fragment_content(ctx, frag); } -int ff_cbs_read_extradata(CodedBitstreamContext *ctx, +int CBS_FUNC(read_extradata)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVCodecParameters *par) { @@ -292,7 +304,7 @@ int ff_cbs_read_extradata(CodedBitstreamContext *ctx, par->extradata_size, 1); } -int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx, +int CBS_FUNC(read_extradata_from_codec)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVCodecContext *avctx) { @@ -301,7 +313,7 @@ int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx, avctx->extradata_size, 1); } -int ff_cbs_read_packet(CodedBitstreamContext *ctx, +int CBS_FUNC(read_packet)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVPacket *pkt) { @@ -309,7 +321,7 @@ int ff_cbs_read_packet(CodedBitstreamContext *ctx, pkt->data, pkt->size, 0); } -int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx, +int CBS_FUNC(read_packet_side_data)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVPacket *pkt) { @@ -322,14 +334,17 @@ int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx, side_data, side_data_size, 1); } -int ff_cbs_read(CodedBitstreamContext *ctx, +int CBS_FUNC(read)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, + const AVBufferRef *buf, const uint8_t *data, size_t size) { - return cbs_read_data(ctx, frag, NULL, + return cbs_read_data(ctx, frag, buf, data, size, 0); } +#endif +#if CBS_WRITE /** * Allocate a new internal data buffer of the given size in the unit. * @@ -367,7 +382,7 @@ static int cbs_write_unit_data(CodedBitstreamContext *ctx, if (ret < 0) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " "sufficiently large write buffer (last attempt " - "%"SIZE_SPECIFIER" bytes).\n", ctx->write_buffer_size); + "%zu bytes).\n", ctx->write_buffer_size); return ret; } } @@ -406,7 +421,7 @@ static int cbs_write_unit_data(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, +int CBS_FUNC(write_fragment_data)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag) { int err, i; @@ -442,13 +457,13 @@ int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_write_extradata(CodedBitstreamContext *ctx, +int CBS_FUNC(write_extradata)(CodedBitstreamContext *ctx, AVCodecParameters *par, CodedBitstreamFragment *frag) { int err; - err = ff_cbs_write_fragment_data(ctx, frag); + err = CBS_FUNC(write_fragment_data)(ctx, frag); if (err < 0) return err; @@ -471,14 +486,14 @@ int ff_cbs_write_extradata(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_write_packet(CodedBitstreamContext *ctx, +int CBS_FUNC(write_packet)(CodedBitstreamContext *ctx, AVPacket *pkt, CodedBitstreamFragment *frag) { AVBufferRef *buf; int err; - err = ff_cbs_write_fragment_data(ctx, frag); + err = CBS_FUNC(write_fragment_data)(ctx, frag); if (err < 0) return err; @@ -494,22 +509,26 @@ int ff_cbs_write_packet(CodedBitstreamContext *ctx, return 0; } +#endif -void ff_cbs_trace_header(CodedBitstreamContext *ctx, +void CBS_FUNC(trace_header)(CodedBitstreamContext *ctx, const char *name) { +#if CBS_TRACE if (!ctx->trace_enable) return; av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name); +#endif } -void ff_cbs_trace_read_log(void *trace_context, +void CBS_FUNC(trace_read_log)(void *trace_context, GetBitContext *gbc, int length, const char *str, const int *subscripts, int64_t value) { +#if CBS_TRACE CodedBitstreamContext *ctx = trace_context; char name[256]; char bits[256]; @@ -561,13 +580,15 @@ void ff_cbs_trace_read_log(void *trace_context, av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %"PRId64"\n", position, name, pad, bits, value); +#endif } -void ff_cbs_trace_write_log(void *trace_context, +void CBS_FUNC(trace_write_log)(void *trace_context, PutBitContext *pbc, int length, const char *str, const int *subscripts, int64_t value) { +#if CBS_TRACE CodedBitstreamContext *ctx = trace_context; // Ensure that the syntax element is written to the output buffer, @@ -590,9 +611,11 @@ void ff_cbs_trace_write_log(void *trace_context, skip_bits_long(&gbc, position - length); - ff_cbs_trace_read_log(ctx, &gbc, length, str, subscripts, value); + CBS_FUNC(trace_read_log)(ctx, &gbc, length, str, subscripts, value); +#endif } +#if CBS_READ static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, @@ -628,7 +651,7 @@ static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, +int CBS_FUNC(read_unsigned)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, const int *subscripts, uint32_t *write_to, uint32_t range_min, uint32_t range_max) @@ -637,14 +660,16 @@ int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, write_to, range_min, range_max); } -int ff_cbs_read_simple_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, +int CBS_FUNC(read_simple_unsigned)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, uint32_t *write_to) { return cbs_read_unsigned(ctx, gbc, width, name, NULL, write_to, 0, UINT32_MAX); } +#endif -int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, +#if CBS_WRITE +int CBS_FUNC(write_unsigned)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, const int *subscripts, uint32_t value, uint32_t range_min, uint32_t range_max) @@ -663,24 +688,23 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, if (put_bits_left(pbc) < width) return AVERROR(ENOSPC); - if (width < 32) - put_bits(pbc, width, value); - else - put_bits32(pbc, value); + put_bits63(pbc, width, value); CBS_TRACE_WRITE_END(); return 0; } -int ff_cbs_write_simple_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, +int CBS_FUNC(write_simple_unsigned)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, uint32_t value) { - return ff_cbs_write_unsigned(ctx, pbc, width, name, NULL, + return CBS_FUNC(write_unsigned)(ctx, pbc, width, name, NULL, value, 0, MAX_UINT_BITS(width)); } +#endif -int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, +#if CBS_READ +int CBS_FUNC(read_signed)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, const int *subscripts, int32_t *write_to, int32_t range_min, int32_t range_max) @@ -711,8 +735,10 @@ int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, *write_to = value; return 0; } +#endif -int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, +#if CBS_WRITE +int CBS_FUNC(write_signed)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, const int *subscripts, int32_t value, int32_t range_min, int32_t range_max) @@ -731,15 +757,13 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, if (put_bits_left(pbc) < width) return AVERROR(ENOSPC); - if (width < 32) - put_sbits(pbc, width, value); - else - put_bits32(pbc, value); + put_bits63(pbc, width, zero_extend(value, width)); CBS_TRACE_WRITE_END(); return 0; } +#endif static int cbs_insert_unit(CodedBitstreamFragment *frag, @@ -766,21 +790,19 @@ static int cbs_insert_unit(CodedBitstreamFragment *frag, if (position < frag->nb_units) memcpy(units + position + 1, frag->units + position, (frag->nb_units - position) * sizeof(*units)); - } - memset(units + position, 0, sizeof(*units)); - - if (units != frag->units) { av_free(frag->units); frag->units = units; } + memset(units + position, 0, sizeof(*units)); + ++frag->nb_units; return 0; } -int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, +int CBS_FUNC(insert_unit_content)(CodedBitstreamFragment *frag, int position, CodedBitstreamUnitType type, void *content, @@ -799,7 +821,7 @@ int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, if (content_ref) { // Create our own reference out of the user-supplied one. - content_ref = ff_refstruct_ref(content_ref); + content_ref = av_refstruct_ref(content_ref); } unit = &frag->units[position]; @@ -847,7 +869,7 @@ static int cbs_insert_unit_data(CodedBitstreamFragment *frag, return 0; } -int ff_cbs_append_unit_data(CodedBitstreamFragment *frag, +int CBS_FUNC(append_unit_data)(CodedBitstreamFragment *frag, CodedBitstreamUnitType type, uint8_t *data, size_t data_size, AVBufferRef *data_buf) @@ -857,7 +879,7 @@ int ff_cbs_append_unit_data(CodedBitstreamFragment *frag, frag->nb_units); } -void ff_cbs_delete_unit(CodedBitstreamFragment *frag, +void CBS_FUNC(delete_unit)(CodedBitstreamFragment *frag, int position) { av_assert0(0 <= position && position < frag->nb_units @@ -873,9 +895,9 @@ void ff_cbs_delete_unit(CodedBitstreamFragment *frag, (frag->nb_units - position) * sizeof(*frag->units)); } -static void cbs_default_free_unit_content(FFRefStructOpaque opaque, void *content) +static void cbs_default_free_unit_content(AVRefStructOpaque opaque, void *content) { - const CodedBitstreamUnitTypeDescriptor *desc = opaque.c; + CodedBitstreamUnitTypeDescriptor *desc = opaque.c; for (int i = 0; i < desc->type.ref.nb_offsets; i++) { void **ptr = (void**)((char*)content + desc->type.ref.offsets[i]); @@ -883,11 +905,11 @@ static void cbs_default_free_unit_content(FFRefStructOpaque opaque, void *conten } } -static const CodedBitstreamUnitTypeDescriptor +static CodedBitstreamUnitTypeDescriptor *cbs_find_unit_type_desc(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit) { - const CodedBitstreamUnitTypeDescriptor *desc; + CodedBitstreamUnitTypeDescriptor *desc; int i, j; if (!ctx->codec->unit_types) @@ -911,19 +933,19 @@ static const CodedBitstreamUnitTypeDescriptor return NULL; } -static void *cbs_alloc_content(const CodedBitstreamUnitTypeDescriptor *desc) +static void *cbs_alloc_content(CodedBitstreamUnitTypeDescriptor *desc) { - return ff_refstruct_alloc_ext_c(desc->content_size, 0, - (FFRefStructOpaque){ .c = desc }, + return av_refstruct_alloc_ext_c(desc->content_size, 0, + (AVRefStructOpaque){ .c = desc }, desc->content_type == CBS_CONTENT_TYPE_COMPLEX ? desc->type.complex.content_free : cbs_default_free_unit_content); } -int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, +int CBS_FUNC(alloc_unit_content)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit) { - const CodedBitstreamUnitTypeDescriptor *desc; + CodedBitstreamUnitTypeDescriptor *desc; av_assert0(!unit->content && !unit->content_ref); @@ -941,7 +963,7 @@ int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, static int cbs_clone_noncomplex_unit_content(void **clonep, const CodedBitstreamUnit *unit, - const CodedBitstreamUnitTypeDescriptor *desc) + CodedBitstreamUnitTypeDescriptor *desc) { const uint8_t *src; uint8_t *copy; @@ -989,7 +1011,7 @@ static int cbs_clone_noncomplex_unit_content(void **clonep, return 0; fail: - ff_refstruct_unref(©); + av_refstruct_unref(©); return err; } @@ -1001,7 +1023,7 @@ fail: static int cbs_clone_unit_content(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit) { - const CodedBitstreamUnitTypeDescriptor *desc; + CodedBitstreamUnitTypeDescriptor *desc; void *new_content; int err; @@ -1032,7 +1054,7 @@ static int cbs_clone_unit_content(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, +int CBS_FUNC(make_unit_refcounted)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit) { av_assert0(unit->content); @@ -1041,24 +1063,24 @@ int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, return cbs_clone_unit_content(ctx, unit); } -int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx, +int CBS_FUNC(make_unit_writable)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit) { void *ref = unit->content_ref; int err; av_assert0(unit->content); - if (ref && ff_refstruct_exclusive(ref)) + if (ref && av_refstruct_exclusive(ref)) return 0; err = cbs_clone_unit_content(ctx, unit); if (err < 0) return err; - ff_refstruct_unref(&ref); + av_refstruct_unref(&ref); return 0; } -void ff_cbs_discard_units(CodedBitstreamContext *ctx, +void CBS_FUNC(discard_units)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, enum AVDiscard skip, int flags) @@ -1070,11 +1092,11 @@ void ff_cbs_discard_units(CodedBitstreamContext *ctx, if (ctx->codec->discarded_unit(ctx, &frag->units[i], skip)) { // discard all units if (!(flags & DISCARD_FLAG_KEEP_NON_VCL)) { - ff_cbs_fragment_free(frag); + CBS_FUNC(fragment_free)(frag); return; } - ff_cbs_delete_unit(frag, i); + CBS_FUNC(delete_unit)(frag, i); } } } diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h index d479b1ac2..8c4614479 100644 --- a/libavcodec/cbs.h +++ b/libavcodec/cbs.h @@ -29,6 +29,13 @@ #include "defs.h" #include "packet.h" +#ifndef CBS_PREFIX +#define CBS_PREFIX cbs +#endif + +#define CBS_FUNC_PREFIX_NAME(prefix, name) ff_ ## prefix ## _ ## name +#define CBS_FUNC_NAME(prefix, name) CBS_FUNC_PREFIX_NAME(prefix, name) +#define CBS_FUNC(name) CBS_FUNC_NAME(CBS_PREFIX, name) /* * This defines a framework for converting between a coded bitstream @@ -294,24 +301,24 @@ typedef struct CodedBitstreamContext { * * Terminated by AV_CODEC_ID_NONE. */ -extern const enum AVCodecID ff_cbs_all_codec_ids[]; +extern const enum AVCodecID CBS_FUNC(all_codec_ids)[]; /** * Create and initialise a new context for the given codec. */ -int ff_cbs_init(CodedBitstreamContext **ctx, +int CBS_FUNC(init)(CodedBitstreamContext **ctx, enum AVCodecID codec_id, void *log_ctx); /** * Reset all internal state in a context. */ -void ff_cbs_flush(CodedBitstreamContext *ctx); +void CBS_FUNC(flush)(CodedBitstreamContext *ctx); /** * Close a context and free all internal state. */ -void ff_cbs_close(CodedBitstreamContext **ctx); +void CBS_FUNC(close)(CodedBitstreamContext **ctx); /** @@ -325,7 +332,7 @@ void ff_cbs_close(CodedBitstreamContext **ctx); * The fragment must have been zeroed or reset via ff_cbs_fragment_reset * before use. */ -int ff_cbs_read_extradata(CodedBitstreamContext *ctx, +int CBS_FUNC(read_extradata)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVCodecParameters *par); @@ -336,11 +343,11 @@ int ff_cbs_read_extradata(CodedBitstreamContext *ctx, * This acts identical to ff_cbs_read_extradata() for the case where * you already have a codec context. */ -int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx, +int CBS_FUNC(read_extradata_from_codec)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const struct AVCodecContext *avctx); -int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx, +int CBS_FUNC(read_packet_side_data)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVPacket *pkt); @@ -355,7 +362,7 @@ int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx, * The fragment must have been zeroed or reset via ff_cbs_fragment_reset * before use. */ -int ff_cbs_read_packet(CodedBitstreamContext *ctx, +int CBS_FUNC(read_packet)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVPacket *pkt); @@ -370,8 +377,9 @@ int ff_cbs_read_packet(CodedBitstreamContext *ctx, * The fragment must have been zeroed or reset via ff_cbs_fragment_reset * before use. */ -int ff_cbs_read(CodedBitstreamContext *ctx, +int CBS_FUNC(read)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, + const AVBufferRef *buf, const uint8_t *data, size_t size); @@ -387,7 +395,7 @@ int ff_cbs_read(CodedBitstreamContext *ctx, * with any persistent data from the fragment which may be required to * write following fragments (e.g. parameter sets). */ -int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, +int CBS_FUNC(write_fragment_data)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag); /** @@ -396,7 +404,7 @@ int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, * Modifies context and fragment as ff_cbs_write_fragment_data does and * replaces any existing extradata in the structure. */ -int ff_cbs_write_extradata(CodedBitstreamContext *ctx, +int CBS_FUNC(write_extradata)(CodedBitstreamContext *ctx, AVCodecParameters *par, CodedBitstreamFragment *frag); @@ -410,7 +418,7 @@ int ff_cbs_write_extradata(CodedBitstreamContext *ctx, * fragment; other fields are not touched. On failure, the packet is not * touched at all. */ -int ff_cbs_write_packet(CodedBitstreamContext *ctx, +int CBS_FUNC(write_packet)(CodedBitstreamContext *ctx, AVPacket *pkt, CodedBitstreamFragment *frag); @@ -419,20 +427,20 @@ int ff_cbs_write_packet(CodedBitstreamContext *ctx, * Free the units contained in a fragment as well as the fragment's * own data buffer, but not the units array itself. */ -void ff_cbs_fragment_reset(CodedBitstreamFragment *frag); +void CBS_FUNC(fragment_reset)(CodedBitstreamFragment *frag); /** * Free the units array of a fragment in addition to what * ff_cbs_fragment_reset does. */ -void ff_cbs_fragment_free(CodedBitstreamFragment *frag); +void CBS_FUNC(fragment_free)(CodedBitstreamFragment *frag); /** * Allocate a new internal content buffer matching the type of the unit. * * The content will be zeroed. */ -int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, +int CBS_FUNC(alloc_unit_content)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit); /** @@ -443,7 +451,7 @@ int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, * The content structure continues to be owned by the caller if * content_ref is not supplied. */ -int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, +int CBS_FUNC(insert_unit_content)(CodedBitstreamFragment *frag, int position, CodedBitstreamUnitType type, void *content, @@ -456,7 +464,7 @@ int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, * av_malloc() and will on success become owned by the unit after this * call or freed on error. */ -int ff_cbs_append_unit_data(CodedBitstreamFragment *frag, +int CBS_FUNC(append_unit_data)(CodedBitstreamFragment *frag, CodedBitstreamUnitType type, uint8_t *data, size_t data_size, AVBufferRef *data_buf); @@ -466,7 +474,7 @@ int ff_cbs_append_unit_data(CodedBitstreamFragment *frag, * * Requires position to be >= 0 and < frag->nb_units. */ -void ff_cbs_delete_unit(CodedBitstreamFragment *frag, +void CBS_FUNC(delete_unit)(CodedBitstreamFragment *frag, int position); @@ -479,7 +487,7 @@ void ff_cbs_delete_unit(CodedBitstreamFragment *frag, * It is not valid to call this function on a unit which does not have * decomposed content. */ -int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, +int CBS_FUNC(make_unit_refcounted)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit); /** @@ -495,7 +503,7 @@ int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, * It is not valid to call this function on a unit which does not have * decomposed content. */ -int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx, +int CBS_FUNC(make_unit_writable)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit); enum CbsDiscardFlags { @@ -508,9 +516,9 @@ enum CbsDiscardFlags { }; /** - * Discard units accroding to 'skip'. + * Discard units according to 'skip'. */ -void ff_cbs_discard_units(CodedBitstreamContext *ctx, +void CBS_FUNC(discard_units)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, enum AVDiscard skip, int flags); @@ -522,7 +530,7 @@ void ff_cbs_discard_units(CodedBitstreamContext *ctx, * * Trace context should be set to the CodedBitstreamContext. */ -void ff_cbs_trace_read_log(void *trace_context, +void CBS_FUNC(trace_read_log)(void *trace_context, struct GetBitContext *gbc, int length, const char *str, const int *subscripts, int64_t value); @@ -533,7 +541,7 @@ void ff_cbs_trace_read_log(void *trace_context, * * Trace context should be set to the CodedBitstreamContext. */ -void ff_cbs_trace_write_log(void *trace_context, +void CBS_FUNC(trace_write_log)(void *trace_context, struct PutBitContext *pbc, int length, const char *str, const int *subscripts, int64_t value); diff --git a/libavcodec/cbs_apv.c b/libavcodec/cbs_apv.c new file mode 100644 index 000000000..f6f701b9d --- /dev/null +++ b/libavcodec/cbs_apv.c @@ -0,0 +1,471 @@ +/* + * 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/mem.h" +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_apv.h" + + +static int cbs_apv_get_num_comp(const APVRawFrameHeader *fh) +{ + switch (fh->frame_info.chroma_format_idc) { + case APV_CHROMA_FORMAT_400: + return 1; + case APV_CHROMA_FORMAT_422: + case APV_CHROMA_FORMAT_444: + return 3; + case APV_CHROMA_FORMAT_4444: + return 4; + default: + av_unreachable("Invalid chroma_format_idc"); + } +} + +static void cbs_apv_derive_tile_info(CodedBitstreamContext *ctx, + const APVRawFrameHeader *fh) +{ + CodedBitstreamAPVContext *priv = ctx->priv_data; + int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16; + int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16; + int tile_cols = (frame_width_in_mbs + fh->tile_info.tile_width_in_mbs - 1) / fh->tile_info.tile_width_in_mbs; + int tile_rows = (frame_height_in_mbs + fh->tile_info.tile_height_in_mbs - 1) / fh->tile_info.tile_height_in_mbs; + + av_assert0(tile_cols <= APV_MAX_TILE_COLS && tile_rows <= APV_MAX_TILE_ROWS); + + priv->num_tiles = tile_cols * tile_rows; +} + + +#define HEADER(name) do { \ + CBS_FUNC(trace_header)(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max, 0, ) +#define us(width, name, range_min, range_max, subs, ...) \ + xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ubs(width, name, subs, ...) \ + xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) + +#define fixed(width, name, value) do { \ + av_unused uint32_t fixed_value = value; \ + xu(width, name, fixed_value, value, value, 0, ); \ + } while (0) + + +#if CBS_READ +#define READ +#define READWRITE read +#define RWContext GetBitContext +#define FUNC(name) cbs_apv_read_ ## name + +#define ub(width, name) do { \ + uint32_t value; \ + CHECK(CBS_FUNC(read_simple_unsigned)(ctx, rw, width, #name, \ + &value)); \ + current->name = value; \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(CBS_FUNC(read_unsigned)(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) + +#define infer(name, value) do { \ + current->name = value; \ + } while (0) + +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +#include "cbs_apv_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef FUNC +#undef ub +#undef xu +#undef infer +#undef byte_alignment +#endif // CBS_READ + +#if CBS_WRITE +#define WRITE +#define READWRITE write +#define RWContext PutBitContext +#define FUNC(name) cbs_apv_write_ ## name + +#define ub(width, name) do { \ + uint32_t value = current->name; \ + CHECK(CBS_FUNC(write_simple_unsigned)(ctx, rw, width, #name, \ + value)); \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(CBS_FUNC(write_unsigned)(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) + +#define infer(name, value) do { \ + if (current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, \ + "%s does not match inferred value: " \ + "%"PRId64", but should be %"PRId64".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#include "cbs_apv_syntax_template.c" + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef FUNC +#undef ub +#undef xu +#undef infer +#undef byte_alignment +#endif // CBS_WRITE + + +static int cbs_apv_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ +#if CBS_READ + uint8_t *data = frag->data; + size_t size = frag->data_size; + uint32_t signature; + int err, trace; + + if (header || !frag->data_size) { + // Ignore empty or extradata fragments. + return 0; + } + + if (frag->data_size < 4) { + // Too small to be a valid fragment. + return AVERROR_INVALIDDATA; + } + + // Don't include parsing here in trace output. + trace = ctx->trace_enable; + ctx->trace_enable = 0; + + signature = AV_RB32(data); + if (signature != APV_SIGNATURE) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid APV access unit: bad signature %08x.\n", + signature); + err = AVERROR_INVALIDDATA; + goto fail; + } + data += 4; + size -= 4; + + while (size > 0) { + GetBitContext gbc; + uint32_t pbu_size; + APVRawPBUHeader pbu_header; + + if (size < 8) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: " + "fragment too short (%zu bytes).\n", + size); + err = AVERROR_INVALIDDATA; + goto fail; + } + + pbu_size = AV_RB32(data); + if (pbu_size < 8) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: " + "pbu_size too small (%"PRIu32" bytes).\n", + pbu_size); + err = AVERROR_INVALIDDATA; + goto fail; + } + + data += 4; + size -= 4; + + if (pbu_size > size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: " + "pbu_size too large (%"PRIu32" bytes).\n", + pbu_size); + err = AVERROR_INVALIDDATA; + goto fail; + } + + init_get_bits(&gbc, data, 8 * pbu_size); + + err = cbs_apv_read_pbu_header(ctx, &gbc, &pbu_header); + if (err < 0) + goto fail; + + // Could select/skip frames based on type/group_id here. + + err = CBS_FUNC(append_unit_data)(frag, pbu_header.pbu_type, + data, pbu_size, frag->data_ref); + if (err < 0) + goto fail; + + data += pbu_size; + size -= pbu_size; + } + + err = 0; +fail: + ctx->trace_enable = trace; + return err; +#else + return AVERROR(ENOSYS); +#endif +} + +static int cbs_apv_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ +#if CBS_READ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + err = CBS_FUNC(alloc_unit_content)(ctx, unit); + if (err < 0) + return err; + + switch (unit->type) { + case APV_PBU_PRIMARY_FRAME: + case APV_PBU_NON_PRIMARY_FRAME: + case APV_PBU_PREVIEW_FRAME: + case APV_PBU_DEPTH_FRAME: + case APV_PBU_ALPHA_FRAME: + { + APVRawFrame *frame = unit->content; + + err = cbs_apv_read_frame(ctx, &gbc, frame); + if (err < 0) + return err; + + // Each tile inside the frame has pointers into the unit + // data buffer; make a single reference here for all of + // them together. + frame->tile_data_ref = av_buffer_ref(unit->data_ref); + if (!frame->tile_data_ref) + return AVERROR(ENOMEM); + } + break; + case APV_PBU_ACCESS_UNIT_INFORMATION: + { + err = cbs_apv_read_au_info(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + case APV_PBU_METADATA: + { + err = cbs_apv_read_metadata(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + case APV_PBU_FILLER: + { + err = cbs_apv_read_filler(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + default: + return AVERROR(ENOSYS); + } + + return 0; +#else + return AVERROR(ENOSYS); +#endif +} + +static int cbs_apv_write_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ +#if CBS_WRITE + int err; + + switch (unit->type) { + case APV_PBU_PRIMARY_FRAME: + case APV_PBU_NON_PRIMARY_FRAME: + case APV_PBU_PREVIEW_FRAME: + case APV_PBU_DEPTH_FRAME: + case APV_PBU_ALPHA_FRAME: + { + APVRawFrame *frame = unit->content; + + err = cbs_apv_write_frame(ctx, pbc, frame); + if (err < 0) + return err; + } + break; + case APV_PBU_ACCESS_UNIT_INFORMATION: + { + err = cbs_apv_write_au_info(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + case APV_PBU_METADATA: + { + err = cbs_apv_write_metadata(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + case APV_PBU_FILLER: + { + err = cbs_apv_write_filler(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + default: + return AVERROR(ENOSYS); + } + + return 0; +#else + return AVERROR(ENOSYS); +#endif +} + +static int cbs_apv_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ +#if CBS_WRITE + size_t size = 4, pos; + + for (int i = 0; i < frag->nb_units; i++) + size += frag->units[i].data_size + 4; + + frag->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!frag->data_ref) + return AVERROR(ENOMEM); + frag->data = frag->data_ref->data; + memset(frag->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + AV_WB32(frag->data, APV_SIGNATURE); + pos = 4; + for (int i = 0; i < frag->nb_units; i++) { + AV_WB32(frag->data + pos, frag->units[i].data_size); + pos += 4; + + memcpy(frag->data + pos, frag->units[i].data, + frag->units[i].data_size); + pos += frag->units[i].data_size; + } + av_assert0(pos == size); + frag->data_size = size; + + return 0; +#else + return AVERROR(ENOSYS); +#endif +} + + +static void cbs_apv_free_metadata(AVRefStructOpaque unused, void *content) +{ + APVRawMetadata *md = content; + av_assert0(md->pbu_header.pbu_type == APV_PBU_METADATA); + + for (int i = 0; i < md->metadata_count; i++) { + APVRawMetadataPayload *pl = &md->payloads[i]; + + switch (pl->payload_type) { + case APV_METADATA_MDCV: + case APV_METADATA_CLL: + case APV_METADATA_FILLER: + break; + case APV_METADATA_ITU_T_T35: + av_buffer_unref(&pl->itu_t_t35.data_ref); + break; + case APV_METADATA_USER_DEFINED: + av_buffer_unref(&pl->user_defined.data_ref); + break; + default: + av_buffer_unref(&pl->undefined.data_ref); + } + } +} + +static CodedBitstreamUnitTypeDescriptor cbs_apv_unit_types[] = { + { + .nb_unit_types = CBS_UNIT_TYPE_RANGE, + .unit_type.range = { + .start = APV_PBU_PRIMARY_FRAME, + .end = APV_PBU_ALPHA_FRAME, + }, + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, + .content_size = sizeof(APVRawFrame), + .type.ref = { + .nb_offsets = 1, + .offsets = { offsetof(APVRawFrame, tile_data_ref) - + sizeof(void*) }, + }, + }, + + CBS_UNIT_TYPE_COMPLEX(APV_PBU_METADATA, APVRawMetadata, + &cbs_apv_free_metadata), + + CBS_UNIT_TYPE_POD(APV_PBU_ACCESS_UNIT_INFORMATION, APVRawAUInfo), + CBS_UNIT_TYPE_POD(APV_PBU_FILLER, APVRawFiller), + + CBS_UNIT_TYPE_END_OF_LIST +}; + +const CodedBitstreamType CBS_FUNC(type_apv) = { + .codec_id = AV_CODEC_ID_APV, + + .priv_data_size = sizeof(CodedBitstreamAPVContext), + + .unit_types = cbs_apv_unit_types, + + .split_fragment = &cbs_apv_split_fragment, + .read_unit = &cbs_apv_read_unit, + .write_unit = &cbs_apv_write_unit, + .assemble_fragment = &cbs_apv_assemble_fragment, +}; diff --git a/libavcodec/cbs_apv.h b/libavcodec/cbs_apv.h new file mode 100644 index 000000000..d91372e64 --- /dev/null +++ b/libavcodec/cbs_apv.h @@ -0,0 +1,197 @@ +/* + * 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_CBS_APV_H +#define AVCODEC_CBS_APV_H + +#include +#include + +#include "libavutil/buffer.h" +#include "apv.h" + +// Arbitrary limits to avoid large structures. +#define CBS_APV_MAX_AU_FRAMES 8 +#define CBS_APV_MAX_METADATA_PAYLOADS 8 + + +typedef struct APVRawPBUHeader { + uint8_t pbu_type; + uint16_t group_id; + uint8_t reserved_zero_8bits; +} APVRawPBUHeader; + +typedef struct APVRawFiller { + size_t filler_size; +} APVRawFiller; + +typedef struct APVRawFrameInfo { + uint8_t profile_idc; + uint8_t level_idc; + uint8_t band_idc; + uint8_t reserved_zero_5bits; + uint32_t frame_width; + uint32_t frame_height; + uint8_t chroma_format_idc; + uint8_t bit_depth_minus8; + uint8_t capture_time_distance; + uint8_t reserved_zero_8bits; +} APVRawFrameInfo; + +typedef struct APVRawQuantizationMatrix { + uint8_t q_matrix[APV_MAX_NUM_COMP][APV_TR_SIZE][APV_TR_SIZE]; +} APVRawQuantizationMatrix; + +typedef struct APVRawTileInfo { + uint32_t tile_width_in_mbs; + uint32_t tile_height_in_mbs; + uint8_t tile_size_present_in_fh_flag; + uint32_t tile_size_in_fh[APV_MAX_TILE_COUNT]; +} APVRawTileInfo; + +typedef struct APVRawFrameHeader { + APVRawFrameInfo frame_info; + uint8_t reserved_zero_8bits; + + uint8_t color_description_present_flag; + uint8_t color_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + uint8_t full_range_flag; + + uint8_t use_q_matrix; + APVRawQuantizationMatrix quantization_matrix; + + APVRawTileInfo tile_info; + + uint8_t reserved_zero_8bits_2; +} APVRawFrameHeader; + +typedef struct APVRawTileHeader { + uint16_t tile_header_size; + uint16_t tile_index; + uint32_t tile_data_size[APV_MAX_NUM_COMP]; + uint8_t tile_qp [APV_MAX_NUM_COMP]; + uint8_t reserved_zero_8bits; +} APVRawTileHeader; + +typedef struct APVRawTile { + APVRawTileHeader tile_header; + + uint8_t *tile_data[APV_MAX_NUM_COMP]; + uint8_t *tile_dummy_byte; + uint32_t tile_dummy_byte_size; +} APVRawTile; + +typedef struct APVRawFrame { + APVRawPBUHeader pbu_header; + APVRawFrameHeader frame_header; + uint32_t tile_size[APV_MAX_TILE_COUNT]; + APVRawTile tile [APV_MAX_TILE_COUNT]; + APVRawFiller filler; + + AVBufferRef *tile_data_ref; +} APVRawFrame; + +typedef struct APVRawAUInfo { + uint16_t num_frames; + + uint8_t pbu_type [CBS_APV_MAX_AU_FRAMES]; + uint8_t group_id [CBS_APV_MAX_AU_FRAMES]; + uint8_t reserved_zero_8bits[CBS_APV_MAX_AU_FRAMES]; + APVRawFrameInfo frame_info [CBS_APV_MAX_AU_FRAMES]; + + uint8_t reserved_zero_8bits_2; + + APVRawFiller filler; +} APVRawAUInfo; + +typedef struct APVRawMetadataITUTT35 { + uint8_t itu_t_t35_country_code; + uint8_t itu_t_t35_country_code_extension; + + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; +} APVRawMetadataITUTT35; + +typedef struct APVRawMetadataMDCV { + uint16_t primary_chromaticity_x[3]; + uint16_t primary_chromaticity_y[3]; + uint16_t white_point_chromaticity_x; + uint16_t white_point_chromaticity_y; + uint32_t max_mastering_luminance; + uint32_t min_mastering_luminance; +} APVRawMetadataMDCV; + +typedef struct APVRawMetadataCLL { + uint16_t max_cll; + uint16_t max_fall; +} APVRawMetadataCLL; + +typedef struct APVRawMetadataFiller { + uint32_t payload_size; +} APVRawMetadataFiller; + +typedef struct APVRawMetadataUserDefined { + uint8_t uuid[16]; + + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; +} APVRawMetadataUserDefined; + +typedef struct APVRawMetadataUndefined { + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; +} APVRawMetadataUndefined; + +typedef struct APVRawMetadataPayload { + uint32_t payload_type; + uint32_t payload_size; + union { + APVRawMetadataITUTT35 itu_t_t35; + APVRawMetadataMDCV mdcv; + APVRawMetadataCLL cll; + APVRawMetadataFiller filler; + APVRawMetadataUserDefined user_defined; + APVRawMetadataUndefined undefined; + }; +} APVRawMetadataPayload; + +typedef struct APVRawMetadata { + APVRawPBUHeader pbu_header; + + uint32_t metadata_size; + uint32_t metadata_count; + + APVRawMetadataPayload payloads[CBS_APV_MAX_METADATA_PAYLOADS]; + + APVRawFiller filler; +} APVRawMetadata; + + +typedef struct CodedBitstreamAPVContext { + int bit_depth; + int num_comp; + + uint16_t num_tiles; +} CodedBitstreamAPVContext; + +#endif /* AVCODEC_CBS_APV_H */ diff --git a/libavcodec/cbs_apv_syntax_template.c b/libavcodec/cbs_apv_syntax_template.c new file mode 100644 index 000000000..cd26a4556 --- /dev/null +++ b/libavcodec/cbs_apv_syntax_template.c @@ -0,0 +1,614 @@ +/* + * 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 + */ + +static int FUNC(pbu_header)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawPBUHeader *current) +{ + int err; + + ub(8, pbu_type); + ub(16, group_id); + u(8, reserved_zero_8bits, 0, 0); + + return 0; +} + +static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + + while (byte_alignment(rw) != 0) + fixed(1, alignment_bit_equal_to_zero, 0); + + return 0; +} + +static int FUNC(filler)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawFiller *current) +{ + int err; + +#ifdef READ + current->filler_size = 0; + while (show_bits(rw, 8) == 0xff) { + fixed(8, ff_byte, 0xff); + ++current->filler_size; + } +#else + { + uint32_t i; + for (i = 0; i < current->filler_size; i++) + fixed(8, ff_byte, 0xff); + } +#endif + + return 0; +} + +static int FUNC(frame_info)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawFrameInfo *current) +{ + int err; + + ub(8, profile_idc); + ub(8, level_idc); + ub(3, band_idc); + + u(5, reserved_zero_5bits, 0, 0); + + ub(24, frame_width); + ub(24, frame_height); + + u(4, chroma_format_idc, 0, 4); + if (current->chroma_format_idc == 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "chroma_format_idc 1 for 4:2:0 is not allowed in APV.\n"); + return AVERROR_INVALIDDATA; + } + + u(4, bit_depth_minus8, 2, 8); + + ub(8, capture_time_distance); + + u(8, reserved_zero_8bits, 0, 0); + + return 0; +} + +static int FUNC(quantization_matrix)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawQuantizationMatrix *current) +{ + const CodedBitstreamAPVContext *priv = ctx->priv_data; + int err; + + for (int c = 0; c < priv->num_comp; c++) { + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8 ; x++) { + us(8, q_matrix[c][x][y], 1, 255, 3, c, x, y); + } + } + } + + return 0; +} + +static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawTileInfo *current, + const APVRawFrameHeader *fh) +{ + CodedBitstreamAPVContext *priv = ctx->priv_data; + int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16; + int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16; + uint32_t min_tile_width = FFMAX(APV_MIN_TILE_WIDTH_IN_MBS, + (frame_width_in_mbs + APV_MAX_TILE_COLS - 1) / + APV_MAX_TILE_COLS); + uint32_t min_tile_height = FFMAX(APV_MIN_TILE_HEIGHT_IN_MBS, + (frame_height_in_mbs + APV_MAX_TILE_ROWS - 1) / + APV_MAX_TILE_ROWS); + int err; + + u(20, tile_width_in_mbs, min_tile_width, MAX_UINT_BITS(20)); + u(20, tile_height_in_mbs, min_tile_height, MAX_UINT_BITS(20)); + + ub(1, tile_size_present_in_fh_flag); + + cbs_apv_derive_tile_info(ctx, fh); + + if (current->tile_size_present_in_fh_flag) { + for (int t = 0; t < priv->num_tiles; t++) { + us(32, tile_size_in_fh[t], 10, MAX_UINT_BITS(32), 1, t); + } + } + + return 0; +} + +static int FUNC(frame_header)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawFrameHeader *current) +{ + CodedBitstreamAPVContext *priv = ctx->priv_data; + int err; + + CHECK(FUNC(frame_info)(ctx, rw, ¤t->frame_info)); + + u(8, reserved_zero_8bits, 0, 0); + + ub(1, color_description_present_flag); + if (current->color_description_present_flag) { + ub(8, color_primaries); + ub(8, transfer_characteristics); + ub(8, matrix_coefficients); + ub(1, full_range_flag); + } else { + infer(color_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + infer(full_range_flag, 0); + } + + priv->bit_depth = current->frame_info.bit_depth_minus8 + 8; + priv->num_comp = cbs_apv_get_num_comp(current); + + ub(1, use_q_matrix); + if (current->use_q_matrix) { + CHECK(FUNC(quantization_matrix)(ctx, rw, + ¤t->quantization_matrix)); + } else { + for (int c = 0; c < priv->num_comp; c++) { + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8 ; x++) { + infer(quantization_matrix.q_matrix[c][y][x], 16); + } + } + } + } + + CHECK(FUNC(tile_info)(ctx, rw, ¤t->tile_info, current)); + + u(8, reserved_zero_8bits_2, 0, 0); + + CHECK(FUNC(byte_alignment)(ctx, rw)); + + return 0; +} + +static int FUNC(tile_header)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawTileHeader *current, + int tile_idx, uint32_t tile_size) +{ + const CodedBitstreamAPVContext *priv = ctx->priv_data; + uint16_t expected_tile_header_size; + uint32_t tile_size_remaining; + uint8_t max_qp; + int err; + + expected_tile_header_size = 4 + priv->num_comp * (4 + 1) + 1; + + u(16, tile_header_size, + expected_tile_header_size, expected_tile_header_size); + + u(16, tile_index, tile_idx, tile_idx); + + tile_size_remaining = tile_size - current->tile_header_size; + for (int c = 0; c < priv->num_comp; c++) { + us(32, tile_data_size[c], 1, tile_size_remaining, 1, c); + tile_size_remaining -= current->tile_data_size[c]; + } + + max_qp = 3 + priv->bit_depth * 6; + for (int c = 0; c < priv->num_comp; c++) { + us(8, tile_qp[c], 0, max_qp, 1, c); + } + + u(8, reserved_zero_8bits, 0, 0); + + return 0; +} + +static int FUNC(tile)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawTile *current, + int tile_idx, uint32_t tile_size) +{ + const CodedBitstreamAPVContext *priv = ctx->priv_data; + int err; + + CHECK(FUNC(tile_header)(ctx, rw, ¤t->tile_header, + tile_idx, tile_size)); + + for (int c = 0; c < priv->num_comp; c++) { + uint32_t comp_size = current->tile_header.tile_data_size[c]; +#ifdef READ + int pos = get_bits_count(rw); + av_assert0(pos % 8 == 0); + if (get_bits_left(rw) < 8LL * comp_size) + return AVERROR_INVALIDDATA; + current->tile_data[c] = (uint8_t*)align_get_bits(rw); + skip_bits_long(rw, 8 * comp_size); +#else + if (put_bytes_left(rw, 0) < comp_size) + return AVERROR(ENOSPC); + ff_copy_bits(rw, current->tile_data[c], comp_size * 8); +#endif + } + + return 0; +} + +static int FUNC(frame)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawFrame *current) +{ + const CodedBitstreamAPVContext *priv = ctx->priv_data; + int err; + + HEADER("Frame"); + + CHECK(FUNC(pbu_header)(ctx, rw, ¤t->pbu_header)); + + CHECK(FUNC(frame_header)(ctx, rw, ¤t->frame_header)); + + for (int t = 0; t < priv->num_tiles; t++) { + us(32, tile_size[t], 10, MAX_INT_BITS(32), 1, t); + + CHECK(FUNC(tile)(ctx, rw, ¤t->tile[t], + t, current->tile_size[t])); + } + + CHECK(FUNC(filler)(ctx, rw, ¤t->filler)); + + return 0; +} + +static int FUNC(au_info)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawAUInfo *current) +{ + int err; + + HEADER("Access Unit Information"); + + u(16, num_frames, 1, CBS_APV_MAX_AU_FRAMES); + + for (int i = 0; i < current->num_frames; i++) { + ubs(8, pbu_type[i], 1, i); + ubs(8, group_id[i], 1, i); + + us(8, reserved_zero_8bits[i], 0, 0, 1, i); + + CHECK(FUNC(frame_info)(ctx, rw, ¤t->frame_info[i])); + } + + u(8, reserved_zero_8bits_2, 0, 0); + + return 0; +} + +static int FUNC(metadata_itu_t_t35)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataITUTT35 *current, + size_t payload_size) +{ + int err; + size_t read_size = payload_size - 1; + + HEADER("ITU-T T.35 Metadata"); + + ub(8, itu_t_t35_country_code); + + if (current->itu_t_t35_country_code == 0xff) { + ub(8, itu_t_t35_country_code_extension); + --read_size; + } + +#ifdef READ + current->data_size = read_size; + current->data_ref = av_buffer_alloc(current->data_size); + if (!current->data_ref) + return AVERROR(ENOMEM); + current->data = current->data_ref->data; +#else + if (current->data_size != read_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write size mismatch: " + "payload %zu but expecting %zu\n", + current->data_size, read_size); + return AVERROR(EINVAL); + } +#endif + + for (size_t i = 0; i < current->data_size; i++) { + xu(8, itu_t_t35_payload[i], + current->data[i], 0x00, 0xff, 1, i); + } + + return 0; +} + +static int FUNC(metadata_mdcv)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataMDCV *current) +{ + int err, i; + + HEADER("MDCV Metadata"); + + for (i = 0; i < 3; i++) { + ubs(16, primary_chromaticity_x[i], 1, i); + ubs(16, primary_chromaticity_y[i], 1, i); + } + + ub(16, white_point_chromaticity_x); + ub(16, white_point_chromaticity_y); + + ub(32, max_mastering_luminance); + ub(32, min_mastering_luminance); + + return 0; +} + +static int FUNC(metadata_cll)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataCLL *current) +{ + int err; + + HEADER("CLL Metadata"); + + ub(16, max_cll); + ub(16, max_fall); + + return 0; +} + +static int FUNC(metadata_filler)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataFiller *current, + size_t payload_size) +{ + int err; + + HEADER("Filler Metadata"); + + for (size_t i = 0; i < payload_size; i++) + fixed(8, ff_byte, 0xff); + + return 0; +} + +static int FUNC(metadata_user_defined)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataUserDefined *current, + size_t payload_size) +{ + int err; + + HEADER("User-Defined Metadata"); + + for (int i = 0; i < 16; i++) + ubs(8, uuid[i], 1, i); + +#ifdef READ + current->data_size = payload_size - 16; + current->data_ref = av_buffer_alloc(current->data_size); + if (!current->data_ref) + return AVERROR(ENOMEM); + current->data = current->data_ref->data; +#else + if (current->data_size != payload_size - 16) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write size mismatch: " + "payload %zu but expecting %zu\n", + current->data_size, payload_size - 16); + return AVERROR(EINVAL); + } +#endif + + for (size_t i = 0; i < current->data_size; i++) { + xu(8, user_defined_data_payload[i], + current->data[i], 0x00, 0xff, 1, i); + } + + return 0; +} + +static int FUNC(metadata_undefined)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataUndefined *current, + size_t payload_size) +{ + int err; + + HEADER("Undefined Metadata"); + +#ifdef READ + current->data_size = payload_size; + current->data_ref = av_buffer_alloc(current->data_size); + if (!current->data_ref) + return AVERROR(ENOMEM); + current->data = current->data_ref->data; +#else + if (current->data_size != payload_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write size mismatch: " + "payload %zu but expecting %zu\n", + current->data_size, payload_size - 16); + return AVERROR(EINVAL); + } +#endif + + for (size_t i = 0; i < current->data_size; i++) { + xu(8, undefined_metadata_payload_byte[i], + current->data[i], 0x00, 0xff, 1, i); + } + + return 0; +} + +static int FUNC(metadata_payload)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataPayload *current) +{ + int err; + + switch (current->payload_type) { + case APV_METADATA_ITU_T_T35: + CHECK(FUNC(metadata_itu_t_t35)(ctx, rw, + ¤t->itu_t_t35, + current->payload_size)); + break; + case APV_METADATA_MDCV: + CHECK(FUNC(metadata_mdcv)(ctx, rw, ¤t->mdcv)); + break; + case APV_METADATA_CLL: + CHECK(FUNC(metadata_cll)(ctx, rw, ¤t->cll)); + break; + case APV_METADATA_FILLER: + CHECK(FUNC(metadata_filler)(ctx, rw, + ¤t->filler, + current->payload_size)); + break; + case APV_METADATA_USER_DEFINED: + CHECK(FUNC(metadata_user_defined)(ctx, rw, + ¤t->user_defined, + current->payload_size)); + break; + default: + CHECK(FUNC(metadata_undefined)(ctx, rw, + ¤t->undefined, + current->payload_size)); + } + + return 0; +} + +static int FUNC(metadata)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawMetadata *current) +{ + int err; + +#ifdef READ + uint32_t metadata_bytes_left; +#else + PutBitContext metadata_start_state; + uint32_t metadata_start_position; + int trace; +#endif + + HEADER("Metadata"); + + CHECK(FUNC(pbu_header)(ctx, rw, ¤t->pbu_header)); + +#ifdef READ + ub(32, metadata_size); + + metadata_bytes_left = current->metadata_size; + + for (int p = 0; p < CBS_APV_MAX_METADATA_PAYLOADS; p++) { + APVRawMetadataPayload *pl = ¤t->payloads[p]; + uint32_t tmp; + + pl->payload_type = 0; + while (show_bits(rw, 8) == 0xff) { + fixed(8, ff_byte, 0xff); + pl->payload_type += 255; + --metadata_bytes_left; + } + xu(8, metadata_payload_type, tmp, 0, 254, 0); + pl->payload_type += tmp; + --metadata_bytes_left; + + pl->payload_size = 0; + while (show_bits(rw, 8) == 0xff) { + fixed(8, ff_byte, 0xff); + pl->payload_size += 255; + --metadata_bytes_left; + } + xu(8, metadata_payload_size, tmp, 0, 254, 0); + pl->payload_size += tmp; + --metadata_bytes_left; + + if (pl->payload_size > metadata_bytes_left) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid metadata: " + "payload_size larger than remaining metadata size " + "(%"PRIu32" bytes).\n", pl->payload_size); + return AVERROR_INVALIDDATA; + } + + current->metadata_count = p + 1; + + CHECK(FUNC(metadata_payload)(ctx, rw, pl)); + + metadata_bytes_left -= pl->payload_size; + if (metadata_bytes_left == 0) + break; + } +#else + // Two passes: the first write finds the size (with tracing + // disabled), the second write does the real write. + + metadata_start_state = *rw; + metadata_start_position = put_bits_count(rw); + + trace = ctx->trace_enable; + ctx->trace_enable = 0; + + for (int pass = 1; pass <= 2; pass++) { + *rw = metadata_start_state; + + ub(32, metadata_size); + + for (int p = 0; p < current->metadata_count; p++) { + APVRawMetadataPayload *pl = ¤t->payloads[p]; + uint32_t payload_start_position; + uint32_t tmp; + + tmp = pl->payload_type; + while (tmp >= 255) { + fixed(8, ff_byte, 0xff); + tmp -= 255; + } + xu(8, metadata_payload_type, tmp, 0, 254, 0); + + tmp = pl->payload_size; + while (tmp >= 255) { + fixed(8, ff_byte, 0xff); + tmp -= 255; + } + xu(8, metadata_payload_size, tmp, 0, 254, 0); + + payload_start_position = put_bits_count(rw); + + err = FUNC(metadata_payload)(ctx, rw, pl); + ctx->trace_enable = trace; + if (err < 0) + return err; + + if (pass == 1) { + pl->payload_size = (put_bits_count(rw) - + payload_start_position) / 8; + } + } + + if (pass == 1) { + current->metadata_size = (put_bits_count(rw) - + metadata_start_position) / 8 - 4; + ctx->trace_enable = trace; + } + } +#endif + + CHECK(FUNC(filler)(ctx, rw, ¤t->filler)); + + return 0; +} diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c index 98d745f49..d05352c73 100644 --- a/libavcodec/cbs_av1.c +++ b/libavcodec/cbs_av1.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/opt.h" #include "libavutil/pixfmt.h" @@ -24,9 +25,10 @@ #include "cbs_internal.h" #include "cbs_av1.h" #include "defs.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" +#if CBS_READ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc, const char *name, uint32_t *write_to, uint32_t range_min, uint32_t range_max) @@ -84,7 +86,9 @@ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc, *write_to = value; return 0; } +#endif +#if CBS_WRITE static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc, const char *name, uint32_t value, uint32_t range_min, uint32_t range_max) @@ -115,7 +119,9 @@ static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc, return 0; } +#endif +#if CBS_READ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc, const char *name, uint64_t *write_to) { @@ -146,7 +152,9 @@ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc, *write_to = value; return 0; } +#endif +#if CBS_WRITE static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc, const char *name, uint64_t value, int fixed_length) { @@ -182,7 +190,9 @@ static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc, return 0; } +#endif +#if CBS_READ static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc, uint32_t n, const char *name, const int *subscripts, uint32_t *write_to) @@ -220,7 +230,9 @@ static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc, *write_to = value; return 0; } +#endif +#if CBS_WRITE static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc, uint32_t n, const char *name, const int *subscripts, uint32_t value) @@ -256,7 +268,9 @@ static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc, return 0; } +#endif +#if CBS_READ static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc, uint32_t range_min, uint32_t range_max, const char *name, uint32_t *write_to) @@ -284,7 +298,9 @@ static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc *write_to = value; return 0; } +#endif +#if CBS_WRITE static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pbc, uint32_t range_min, uint32_t range_max, const char *name, uint32_t value) @@ -315,7 +331,9 @@ static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb return 0; } +#endif +#if CBS_READ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc, uint32_t range_max, const char *name, const int *subscripts, uint32_t *write_to) @@ -342,7 +360,7 @@ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc, } if (len < max_len) { - err = ff_cbs_read_simple_unsigned(ctx, gbc, range_bits, + err = CBS_FUNC(read_simple_unsigned)(ctx, gbc, range_bits, "subexp_bits", &value); if (err < 0) return err; @@ -360,7 +378,9 @@ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc, *write_to = value; return err; } +#endif +#if CBS_WRITE static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc, uint32_t range_max, const char *name, const int *subscripts, uint32_t value) @@ -402,7 +422,7 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc, return err; if (len < max_len) { - err = ff_cbs_write_simple_unsigned(ctx, pbc, range_bits, + err = CBS_FUNC(write_simple_unsigned)(ctx, pbc, range_bits, "subexp_bits", value - range_offset); if (err < 0) @@ -420,6 +440,7 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc, return err; } +#endif static int cbs_av1_tile_log2(int blksize, int target) @@ -441,7 +462,7 @@ static int cbs_av1_get_relative_dist(const AV1RawSequenceHeader *seq, return diff; } -static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) +av_unused static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) { GetBitContext tmp = *gbc; size_t size = 0; @@ -454,7 +475,7 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #define HEADER(name) do { \ - ff_cbs_trace_header(ctx, name); \ + CBS_FUNC(trace_header)(ctx, name); \ } while (0) #define CHECK(call) do { \ @@ -469,6 +490,7 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) +#if CBS_READ #define fc(width, name, range_min, range_max) \ xf(width, name, current->name, range_min, range_max, 0, ) #define flag(name) fb(1, name) @@ -496,14 +518,14 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #define fb(width, name) do { \ uint32_t value; \ - CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, \ + CHECK(CBS_FUNC(read_simple_unsigned)(ctx, rw, width, \ #name, &value)); \ current->name = value; \ } while (0) #define xf(width, name, var, range_min, range_max, subs, ...) do { \ uint32_t value; \ - CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + CHECK(CBS_FUNC(read_unsigned)(ctx, rw, width, #name, \ SUBSCRIPTS(subs, __VA_ARGS__), \ &value, range_min, range_max)); \ var = value; \ @@ -511,7 +533,7 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #define xsu(width, name, var, subs, ...) do { \ int32_t value; \ - CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + CHECK(CBS_FUNC(read_signed)(ctx, rw, width, #name, \ SUBSCRIPTS(subs, __VA_ARGS__), &value, \ MIN_INT_BITS(width), \ MAX_INT_BITS(width))); \ @@ -584,25 +606,27 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #undef leb128 #undef infer #undef byte_alignment +#endif // CBS_READ +#if CBS_WRITE #define WRITE #define READWRITE write #define RWContext PutBitContext #define fb(width, name) do { \ - CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \ + CHECK(CBS_FUNC(write_simple_unsigned)(ctx, rw, width, #name, \ current->name)); \ } while (0) #define xf(width, name, var, range_min, range_max, subs, ...) do { \ - CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + CHECK(CBS_FUNC(write_unsigned)(ctx, rw, width, #name, \ SUBSCRIPTS(subs, __VA_ARGS__), \ var, range_min, range_max)); \ } while (0) #define xsu(width, name, var, subs, ...) do { \ - CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + CHECK(CBS_FUNC(write_signed)(ctx, rw, width, #name, \ SUBSCRIPTS(subs, __VA_ARGS__), var, \ MIN_INT_BITS(width), \ MAX_INT_BITS(width))); \ @@ -668,12 +692,13 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #undef leb128 #undef infer #undef byte_alignment - +#endif // CBS_WRITE static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, int header) { +#if CBS_READ GetBitContext gbc; uint8_t *data; size_t size; @@ -689,7 +714,7 @@ static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, if (INT_MAX / 8 < size) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid fragment: " - "too large (%"SIZE_SPECIFIER" bytes).\n", size); + "too large (%zu bytes).\n", size); err = AVERROR_INVALIDDATA; goto fail; } @@ -740,7 +765,7 @@ static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, if (obu_header.obu_has_size_field) { if (get_bits_left(&gbc) < 8) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid OBU: fragment " - "too short (%"SIZE_SPECIFIER" bytes).\n", size); + "too short (%zu bytes).\n", size); err = AVERROR_INVALIDDATA; goto fail; } @@ -757,13 +782,13 @@ static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, if (size < obu_length) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid OBU length: " - "%"PRIu64", but only %"SIZE_SPECIFIER" bytes remaining in fragment.\n", + "%"PRIu64", but only %zu bytes remaining in fragment.\n", obu_length, size); err = AVERROR_INVALIDDATA; goto fail; } - err = ff_cbs_append_unit_data(frag, obu_header.obu_type, + err = CBS_FUNC(append_unit_data)(frag, obu_header.obu_type, data, obu_length, frag->data_ref); if (err < 0) goto fail; @@ -777,12 +802,17 @@ success: fail: ctx->trace_enable = trace; return err; +#else + return AVERROR(ENOSYS); +#endif } +#if CBS_READ static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, GetBitContext *gbc, - AV1RawTileData *td) + AVBufferRef **data_ref, + uint8_t **data, size_t *data_size) { int pos; @@ -795,25 +825,27 @@ static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx, // Must be byte-aligned at this point. av_assert0(pos % 8 == 0); - td->data_ref = av_buffer_ref(unit->data_ref); - if (!td->data_ref) + *data_ref = av_buffer_ref(unit->data_ref); + if (!*data_ref) return AVERROR(ENOMEM); - td->data = unit->data + pos / 8; - td->data_size = unit->data_size - pos / 8; + *data = unit->data + pos / 8; + *data_size = unit->data_size - pos / 8; return 0; } +#endif static int cbs_av1_read_unit(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit) { +#if CBS_READ CodedBitstreamAV1Context *priv = ctx->priv_data; AV1RawOBU *obu; GetBitContext gbc; int err, start_pos, end_pos; - err = ff_cbs_alloc_unit_content(ctx, unit); + err = CBS_FUNC(alloc_unit_content)(ctx, unit); if (err < 0) return err; obu = unit->content; @@ -836,7 +868,7 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, } else { if (unit->data_size < 1 + obu->header.obu_extension_flag) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid OBU length: " - "unit too short (%"SIZE_SPECIFIER").\n", unit->data_size); + "unit too short (%zu).\n", unit->data_size); return AVERROR_INVALIDDATA; } obu->obu_size = unit->data_size - 1 - obu->header.obu_extension_flag; @@ -878,7 +910,7 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, priv->operating_point_idc = sequence_header->operating_point_idc[priv->operating_point]; } - ff_refstruct_replace(&priv->sequence_header_ref, unit->content_ref); + av_refstruct_replace(&priv->sequence_header_ref, unit->content_ref); priv->sequence_header = &obu->obu.sequence_header; } break; @@ -901,32 +933,36 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, return err; } break; - case AV1_OBU_TILE_GROUP: - { - err = cbs_av1_read_tile_group_obu(ctx, &gbc, - &obu->obu.tile_group); - if (err < 0) - return err; - - err = cbs_av1_ref_tile_data(ctx, unit, &gbc, - &obu->obu.tile_group.tile_data); - if (err < 0) - return err; - } - break; case AV1_OBU_FRAME: - { err = cbs_av1_read_frame_obu(ctx, &gbc, &obu->obu.frame, unit->data_ref); if (err < 0) return err; + // fall-through + case AV1_OBU_TILE_GROUP: + { + AV1RawTileGroup *tile_group = obu->header.obu_type == AV1_OBU_FRAME ? &obu->obu.frame.tile_group + : &obu->obu.tile_group; + err = cbs_av1_ref_tile_data(ctx, unit, &gbc, + &tile_group->data_ref, + &tile_group->data, + &tile_group->data_size); + if (err < 0) + return err; + + err = cbs_av1_read_tile_group_obu(ctx, &gbc, tile_group); + if (err < 0) + return err; err = cbs_av1_ref_tile_data(ctx, unit, &gbc, - &obu->obu.frame.tile_group.tile_data); + &tile_group->tile_data.data_ref, + &tile_group->tile_data.data, + &tile_group->tile_data.data_size); if (err < 0) return err; } break; +#if CBS_AV1_OBU_TILE_LIST case AV1_OBU_TILE_LIST: { err = cbs_av1_read_tile_list_obu(ctx, &gbc, @@ -935,11 +971,15 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, return err; err = cbs_av1_ref_tile_data(ctx, unit, &gbc, - &obu->obu.tile_list.tile_data); + &obu->obu.tile_list.tile_data.data_ref, + &obu->obu.tile_list.tile_data.data, + &obu->obu.tile_list.tile_data.data_size); if (err < 0) return err; } break; +#endif +#if CBS_AV1_OBU_METADATA case AV1_OBU_METADATA: { err = cbs_av1_read_metadata_obu(ctx, &gbc, &obu->obu.metadata); @@ -947,6 +987,8 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, return err; } break; +#endif +#if CBS_AV1_OBU_PADDING case AV1_OBU_PADDING: { err = cbs_av1_read_padding_obu(ctx, &gbc, &obu->obu.padding); @@ -954,6 +996,7 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, return err; } break; +#endif default: return AVERROR(ENOSYS); } @@ -976,12 +1019,16 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, } return 0; +#else + return AVERROR(ENOSYS); +#endif } static int cbs_av1_write_obu(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, PutBitContext *pbc) { +#if CBS_WRITE CodedBitstreamAV1Context *priv = ctx->priv_data; AV1RawOBU *obu = unit->content; PutBitContext pbc_tmp; @@ -997,7 +1044,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, av1ctx = *priv; if (priv->sequence_header_ref) { - av1ctx.sequence_header_ref = ff_refstruct_ref(priv->sequence_header_ref); + av1ctx.sequence_header_ref = av_refstruct_ref(priv->sequence_header_ref); } if (priv->frame_header_ref) { @@ -1035,14 +1082,14 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, if (err < 0) goto error; - ff_refstruct_unref(&priv->sequence_header_ref); + av_refstruct_unref(&priv->sequence_header_ref); priv->sequence_header = NULL; - err = ff_cbs_make_unit_refcounted(ctx, unit); + err = CBS_FUNC(make_unit_refcounted)(ctx, unit); if (err < 0) goto error; - priv->sequence_header_ref = ff_refstruct_ref(unit->content_ref); + priv->sequence_header_ref = av_refstruct_ref(unit->content_ref); priv->sequence_header = &obu->obu.sequence_header; } break; @@ -1065,25 +1112,23 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, goto error; } break; - case AV1_OBU_TILE_GROUP: - { - err = cbs_av1_write_tile_group_obu(ctx, pbc, - &obu->obu.tile_group); - if (err < 0) - goto error; - - td = &obu->obu.tile_group.tile_data; - } - break; case AV1_OBU_FRAME: - { err = cbs_av1_write_frame_obu(ctx, pbc, &obu->obu.frame, NULL); if (err < 0) goto error; + // fall-through + case AV1_OBU_TILE_GROUP: + { + AV1RawTileGroup *tile_group = obu->header.obu_type == AV1_OBU_FRAME ? &obu->obu.frame.tile_group + : &obu->obu.tile_group; + err = cbs_av1_write_tile_group_obu(ctx, pbc, tile_group); + if (err < 0) + goto error; - td = &obu->obu.frame.tile_group.tile_data; + td = &tile_group->tile_data; } break; +#if CBS_AV1_OBU_TILE_LIST case AV1_OBU_TILE_LIST: { err = cbs_av1_write_tile_list_obu(ctx, pbc, &obu->obu.tile_list); @@ -1093,6 +1138,8 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, td = &obu->obu.tile_list.tile_data; } break; +#endif +#if CBS_AV1_OBU_METADATA case AV1_OBU_METADATA: { err = cbs_av1_write_metadata_obu(ctx, pbc, &obu->obu.metadata); @@ -1100,6 +1147,8 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, goto error; } break; +#endif +#if CBS_AV1_OBU_PADDING case AV1_OBU_PADDING: { err = cbs_av1_write_padding_obu(ctx, pbc, &obu->obu.padding); @@ -1107,6 +1156,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, goto error; } break; +#endif default: err = AVERROR(ENOSYS); goto error; @@ -1146,7 +1196,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, av_assert0(data_pos <= start_pos); if (8 * obu->obu_size > put_bits_left(pbc)) { - ff_refstruct_unref(&priv->sequence_header_ref); + av_refstruct_unref(&priv->sequence_header_ref); av_buffer_unref(&priv->frame_header_ref); *priv = av1ctx; @@ -1175,15 +1225,19 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, err = 0; error: - ff_refstruct_unref(&av1ctx.sequence_header_ref); + av_refstruct_unref(&av1ctx.sequence_header_ref); av_buffer_unref(&av1ctx.frame_header_ref); return err; +#else + return AVERROR(ENOSYS); +#endif } static int cbs_av1_assemble_fragment(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag) { +#if CBS_WRITE size_t size, pos; int i; @@ -1207,9 +1261,12 @@ static int cbs_av1_assemble_fragment(CodedBitstreamContext *ctx, frag->data_size = size; return 0; +#else + return AVERROR(ENOSYS); +#endif } -static void cbs_av1_flush(CodedBitstreamContext *ctx) +static av_cold void cbs_av1_flush(CodedBitstreamContext *ctx) { CodedBitstreamAV1Context *priv = ctx->priv_data; @@ -1223,15 +1280,16 @@ static void cbs_av1_flush(CodedBitstreamContext *ctx) priv->tile_num = 0; } -static void cbs_av1_close(CodedBitstreamContext *ctx) +static av_cold void cbs_av1_close(CodedBitstreamContext *ctx) { CodedBitstreamAV1Context *priv = ctx->priv_data; - ff_refstruct_unref(&priv->sequence_header_ref); + av_refstruct_unref(&priv->sequence_header_ref); av_buffer_unref(&priv->frame_header_ref); } -static void cbs_av1_free_metadata(FFRefStructOpaque unused, void *content) +#if CBS_AV1_OBU_METADATA +static void cbs_av1_free_metadata(AVRefStructOpaque unused, void *content) { AV1RawOBU *obu = content; AV1RawMetadata *md; @@ -1252,24 +1310,49 @@ static void cbs_av1_free_metadata(FFRefStructOpaque unused, void *content) av_buffer_unref(&md->metadata.unknown.payload_ref); } } +#endif -static const CodedBitstreamUnitTypeDescriptor cbs_av1_unit_types[] = { +static CodedBitstreamUnitTypeDescriptor cbs_av1_unit_types[] = { CBS_UNIT_TYPE_POD(AV1_OBU_SEQUENCE_HEADER, AV1RawOBU), CBS_UNIT_TYPE_POD(AV1_OBU_TEMPORAL_DELIMITER, AV1RawOBU), CBS_UNIT_TYPE_POD(AV1_OBU_FRAME_HEADER, AV1RawOBU), CBS_UNIT_TYPE_POD(AV1_OBU_REDUNDANT_FRAME_HEADER, AV1RawOBU), + { + .nb_unit_types = 1, + .unit_type.list[0] = AV1_OBU_TILE_GROUP, + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, + .content_size = sizeof(AV1RawOBU), + .type.ref = { + .nb_offsets = 2, + .offsets = { offsetof(AV1RawOBU, obu.tile_group.data), + offsetof(AV1RawOBU, obu.tile_group.tile_data.data) } + }, + }, - CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_TILE_GROUP, AV1RawOBU, - obu.tile_group.tile_data.data), - CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_FRAME, AV1RawOBU, - obu.frame.tile_group.tile_data.data), + { + .nb_unit_types = 1, + .unit_type.list[0] = AV1_OBU_FRAME, + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, + .content_size = sizeof(AV1RawOBU), + .type.ref = { + .nb_offsets = 2, + .offsets = { offsetof(AV1RawOBU, obu.frame.tile_group.data), + offsetof(AV1RawOBU, obu.frame.tile_group.tile_data.data) } + }, + }, +#if CBS_AV1_OBU_TILE_LIST CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_TILE_LIST, AV1RawOBU, obu.tile_list.tile_data.data), +#endif +#if CBS_AV1_OBU_PADDING CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_PADDING, AV1RawOBU, obu.padding.payload), +#endif +#if CBS_AV1_OBU_METADATA CBS_UNIT_TYPE_COMPLEX(AV1_OBU_METADATA, AV1RawOBU, &cbs_av1_free_metadata), +#endif CBS_UNIT_TYPE_END_OF_LIST }; @@ -1290,7 +1373,7 @@ static const AVClass cbs_av1_class = { .version = LIBAVUTIL_VERSION_INT, }; -const CodedBitstreamType ff_cbs_type_av1 = { +const CodedBitstreamType CBS_FUNC(type_av1) = { .codec_id = AV_CODEC_ID_AV1, .priv_class = &cbs_av1_class, diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h index 8586f2bf4..874f64561 100644 --- a/libavcodec/cbs_av1.h +++ b/libavcodec/cbs_av1.h @@ -25,6 +25,15 @@ #include "av1.h" #include "cbs.h" +#ifndef CBS_AV1_OBU_METADATA +#define CBS_AV1_OBU_METADATA 1 +#endif +#ifndef CBS_AV1_OBU_TILE_LIST +#define CBS_AV1_OBU_TILE_LIST 1 +#endif +#ifndef CBS_AV1_OBU_PADDING +#define CBS_AV1_OBU_PADDING 1 +#endif typedef struct AV1RawOBUHeader { uint8_t obu_forbidden_bit; @@ -295,6 +304,10 @@ typedef struct AV1RawTileData { } AV1RawTileData; typedef struct AV1RawTileGroup { + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; + uint8_t tile_start_and_end_present_flag; uint16_t tg_start; uint16_t tg_end; @@ -407,9 +420,15 @@ typedef struct AV1RawOBU { AV1RawFrameHeader frame_header; AV1RawFrame frame; AV1RawTileGroup tile_group; +#if CBS_AV1_OBU_TILE_LIST AV1RawTileList tile_list; +#endif +#if CBS_AV1_OBU_METADATA AV1RawMetadata metadata; +#endif +#if CBS_AV1_OBU_PADDING AV1RawPadding padding; +#endif } obu; } AV1RawOBU; diff --git a/libavcodec/cbs_av1_syntax_template.c b/libavcodec/cbs_av1_syntax_template.c index a4a912482..86b9a3161 100644 --- a/libavcodec/cbs_av1_syntax_template.c +++ b/libavcodec/cbs_av1_syntax_template.c @@ -1758,7 +1758,15 @@ static int FUNC(frame_header_obu)(CodedBitstreamContext *ctx, RWContext *rw, } } else { if (redundant) +#ifdef READ HEADER("Redundant Frame Header (used as Frame Header)"); +#else + { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid redundant " + "frame header OBU.\n"); + return AVERROR_INVALIDDATA; + } +#endif else HEADER("Frame Header"); @@ -1865,11 +1873,10 @@ static int FUNC(frame_obu)(CodedBitstreamContext *ctx, RWContext *rw, CHECK(FUNC(byte_alignment)(ctx, rw)); - CHECK(FUNC(tile_group_obu)(ctx, rw, ¤t->tile_group)); - return 0; } +#if CBS_AV1_OBU_TILE_LIST static int FUNC(tile_list_obu)(CodedBitstreamContext *ctx, RWContext *rw, AV1RawTileList *current) { @@ -1884,7 +1891,9 @@ static int FUNC(tile_list_obu)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } +#endif +#if CBS_AV1_OBU_METADATA static int FUNC(metadata_hdr_cll)(CodedBitstreamContext *ctx, RWContext *rw, AV1RawMetadataHDRCLL *current) { @@ -2103,7 +2112,9 @@ static int FUNC(metadata_obu)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } +#endif +#if CBS_AV1_OBU_PADDING static int FUNC(padding_obu)(CodedBitstreamContext *ctx, RWContext *rw, AV1RawPadding *current) { @@ -2127,3 +2138,4 @@ static int FUNC(padding_obu)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } +#endif diff --git a/libavcodec/cbs_bsf.c b/libavcodec/cbs_bsf.c index b25285483..f342e5489 100644 --- a/libavcodec/cbs_bsf.c +++ b/libavcodec/cbs_bsf.c @@ -20,6 +20,8 @@ #include "bsf_internal.h" #include "cbs_bsf.h" +#include "libavutil/attributes.h" + static int cbs_bsf_update_side_data(AVBSFContext *bsf, AVPacket *pkt) { CBSBSFContext *ctx = bsf->priv_data; @@ -107,7 +109,7 @@ fail: return err; } -int ff_cbs_bsf_generic_init(AVBSFContext *bsf, const CBSBSFType *type) +av_cold int ff_cbs_bsf_generic_init(AVBSFContext *bsf, const CBSBSFType *type) { CBSBSFContext *ctx = bsf->priv_data; CodedBitstreamFragment *frag = &ctx->fragment; @@ -152,7 +154,7 @@ fail: return err; } -void ff_cbs_bsf_generic_close(AVBSFContext *bsf) +av_cold void ff_cbs_bsf_generic_close(AVBSFContext *bsf) { CBSBSFContext *ctx = bsf->priv_data; diff --git a/libavcodec/cbs_h264.c b/libavcodec/cbs_h264.c new file mode 100644 index 000000000..8b5a7c71f --- /dev/null +++ b/libavcodec/cbs_h264.c @@ -0,0 +1,788 @@ +/* + * 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/mem.h" +#include "libavutil/refstruct.h" +#include "bytestream.h" +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_h2645.h" +#include "cbs_h264.h" +#include "cbs_sei.h" +#include "get_bits.h" + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME2(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_NAME1(rw, codec, name) FUNC_NAME2(rw, codec, name) +#define FUNC_H264(name) FUNC_NAME1(READWRITE, h264, name) +#define FUNC_NAME2_EXPORT(rw, codec, name) ff_cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_NAME1_EXPORT(rw, codec, name) FUNC_NAME2_EXPORT(rw, codec, name) +#define FUNC_SEI(name) FUNC_NAME1_EXPORT(READWRITE, sei, name) + +#define SEI_FUNC(name, args) \ +static int FUNC_H264(name) args; \ +static int FUNC_H264(name ## _internal)(CodedBitstreamContext *ctx, \ + RWContext *rw, void *cur, \ + SEIMessageState *state) \ +{ \ + return FUNC_H264(name)(ctx, rw, cur, state); \ +} \ +static int FUNC_H264(name) args + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max, 0, ) +#define flag(name) ub(1, name) +#define ue(name, range_min, range_max) \ + xue(name, current->name, range_min, range_max, 0, ) +#define i(width, name, range_min, range_max) \ + xi(width, name, current->name, range_min, range_max, 0, ) +#define ib(width, name) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), 0, ) +#define se(name, range_min, range_max) \ + xse(name, current->name, range_min, range_max, 0, ) + +#define us(width, name, range_min, range_max, subs, ...) \ + xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ubs(width, name, subs, ...) \ + xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define flags(name, subs, ...) \ + xu(1, name, current->name, 0, 1, subs, __VA_ARGS__) +#define ues(name, range_min, range_max, subs, ...) \ + xue(name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define is(width, name, range_min, range_max, subs, ...) \ + xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ibs(width, name, subs, ...) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__) +#define ses(name, range_min, range_max, subs, ...) \ + xse(name, current->name, range_min, range_max, subs, __VA_ARGS__) + +#define fixed(width, name, value) do { \ + av_unused uint32_t fixed_value = value; \ + xu(width, name, fixed_value, value, value, 0, ); \ + } while (0) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define ub(width, name) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \ + &value)); \ + current->name = value; \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xue(name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value; \ + CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ + int32_t value; \ + CHECK(ff_cbs_read_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) + + +#define infer(name, value) do { \ + current->name = value; \ + } while (0) + +#define more_rbsp_data(var) ((var) = ff_cbs_h2645_read_more_rbsp_data(rw)) + +#define bit_position(rw) (get_bits_count(rw)) +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + name ## _ref = av_buffer_allocz(size + \ + AV_INPUT_BUFFER_PADDING_SIZE); \ + if (!name ## _ref) \ + return AVERROR(ENOMEM); \ + name = name ## _ref->data; \ + } while (0) + +#define FUNC(name) FUNC_H264(name) +#include "cbs_h264_syntax_template.c" +#undef FUNC + + +#undef READ +#undef READWRITE +#undef RWContext +#undef ub +#undef xu +#undef xi +#undef xue +#undef xse +#undef infer +#undef more_rbsp_data +#undef bit_position +#undef byte_alignment +#undef allocate +#undef allocate_struct + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define ub(width, name) do { \ + uint32_t value = current->name; \ + CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \ + value)); \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xue(name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value = var; \ + CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ + int32_t value = var; \ + CHECK(ff_cbs_write_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) + +#define infer(name, value) do { \ + if (current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, \ + "%s does not match inferred value: " \ + "%"PRId64", but should be %"PRId64".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define more_rbsp_data(var) (var) + +#define bit_position(rw) (put_bits_count(rw)) +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + if (!name) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \ + "for writing.\n", #name); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define FUNC(name) FUNC_H264(name) +#include "cbs_h264_syntax_template.c" +#undef FUNC + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef ub +#undef xu +#undef xi +#undef xue +#undef xse +#undef u +#undef i +#undef flag +#undef ue +#undef se +#undef infer +#undef more_rbsp_data +#undef bit_position +#undef byte_alignment +#undef allocate + + + +static int cbs_h264_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + enum AVCodecID codec_id = ctx->codec->codec_id; + CodedBitstreamH264Context *priv = ctx->priv_data; + CodedBitstreamH2645Context *h2645 = &priv->common; + GetByteContext gbc; + int err; + + av_assert0(frag->data && frag->nb_units == 0); + if (frag->data_size == 0) + return 0; + + if (header && frag->data[0]) { + // AVCC header. + size_t size, start, end; + int i, count, version; + + h2645->mp4 = 1; + + bytestream2_init(&gbc, frag->data, frag->data_size); + + if (bytestream2_get_bytes_left(&gbc) < 6) + return AVERROR_INVALIDDATA; + + version = bytestream2_get_byte(&gbc); + if (version != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid AVCC header: " + "first byte %u.\n", version); + return AVERROR_INVALIDDATA; + } + + bytestream2_skip(&gbc, 3); + h2645->nal_length_size = (bytestream2_get_byte(&gbc) & 3) + 1; + + // SPS array. + count = bytestream2_get_byte(&gbc) & 0x1f; + start = bytestream2_tell(&gbc); + for (i = 0; i < count; i++) { + if (bytestream2_get_bytes_left(&gbc) < 2 * (count - i)) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if (bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&h2645->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 2, AV_CODEC_ID_H264, + H2645_FLAG_IS_NALFF | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC SPS array.\n"); + return err; + } + err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet); + if (err < 0) + return err; + + // PPS array. + count = bytestream2_get_byte(&gbc); + start = bytestream2_tell(&gbc); + for (i = 0; i < count; i++) { + if (bytestream2_get_bytes_left(&gbc) < 2 * (count - i)) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if (bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&h2645->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 2, AV_CODEC_ID_H264, + H2645_FLAG_IS_NALFF | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC PPS array.\n"); + return err; + } + err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet); + if (err < 0) + return err; + + if (bytestream2_get_bytes_left(&gbc) > 0) { + av_log(ctx->log_ctx, AV_LOG_WARNING, "%u bytes left at end of AVCC " + "header.\n", bytestream2_get_bytes_left(&gbc)); + } + } else { + int flags = (H2645_FLAG_IS_NALFF * !!h2645->mp4) | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF; + // Annex B, or later MP4 with already-known parameters. + + err = ff_h2645_packet_split(&h2645->read_packet, + frag->data, frag->data_size, + ctx->log_ctx, + h2645->nal_length_size, + codec_id, flags); + if (err < 0) + return err; + + err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet); + if (err < 0) + return err; + } + + return 0; +} + +#define cbs_h2645_replace_ps(ps_name, ps_var, id_element) \ +static int cbs_h264_replace_ ## ps_var(CodedBitstreamContext *ctx, \ + CodedBitstreamUnit *unit) \ +{ \ + CodedBitstreamH264Context *priv = ctx->priv_data; \ + H264Raw ## ps_name *ps_var = unit->content; \ + unsigned int id = ps_var->id_element; \ + int err = ff_cbs_make_unit_refcounted(ctx, unit); \ + if (err < 0) \ + return err; \ + if (priv->ps_var[id] == priv->active_ ## ps_var) \ + priv->active_ ## ps_var = NULL ; \ + av_assert0(unit->content_ref); \ + av_refstruct_replace(&priv->ps_var[id], unit->content_ref); \ + return 0; \ +} + +cbs_h2645_replace_ps(SPS, sps, seq_parameter_set_id) +cbs_h2645_replace_ps(PPS, pps, pic_parameter_set_id) + +static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + err = ff_cbs_alloc_unit_content(ctx, unit); + if (err < 0) + return err; + + switch (unit->type) { + case H264_NAL_SPS: + { + H264RawSPS *sps = unit->content; + + err = cbs_h264_read_sps(ctx, &gbc, sps); + if (err < 0) + return err; + + err = cbs_h264_replace_sps(ctx, unit); + if (err < 0) + return err; + } + break; + + case H264_NAL_SPS_EXT: + { + err = cbs_h264_read_sps_extension(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_PPS: + { + H264RawPPS *pps = unit->content; + + err = cbs_h264_read_pps(ctx, &gbc, pps); + if (err < 0) + return err; + + err = cbs_h264_replace_pps(ctx, unit); + if (err < 0) + return err; + } + break; + + case H264_NAL_SLICE: + case H264_NAL_IDR_SLICE: + case H264_NAL_AUXILIARY_SLICE: + { + H264RawSlice *slice = unit->content; + int pos, len; + + err = cbs_h264_read_slice_header(ctx, &gbc, &slice->header); + if (err < 0) + return err; + + if (!ff_cbs_h2645_read_more_rbsp_data(&gbc)) + return AVERROR_INVALIDDATA; + + pos = get_bits_count(&gbc); + len = unit->data_size; + + slice->data_size = len - pos / 8; + slice->data_ref = av_buffer_ref(unit->data_ref); + if (!slice->data_ref) + return AVERROR(ENOMEM); + slice->data = unit->data + pos / 8; + slice->data_bit_start = pos % 8; + } + break; + + case H264_NAL_AUD: + { + err = cbs_h264_read_aud(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_SEI: + { + err = cbs_h264_read_sei(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_FILLER_DATA: + { + err = cbs_h264_read_filler(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_END_SEQUENCE: + case H264_NAL_END_STREAM: + { + err = (unit->type == H264_NAL_END_SEQUENCE ? + cbs_h264_read_end_of_sequence : + cbs_h264_read_end_of_stream)(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + default: + return AVERROR(ENOSYS); + } + + return 0; +} + +static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + switch (unit->type) { + case H264_NAL_SPS: + { + H264RawSPS *sps = unit->content; + + err = cbs_h264_write_sps(ctx, pbc, sps); + if (err < 0) + return err; + + err = cbs_h264_replace_sps(ctx, unit); + if (err < 0) + return err; + } + break; + + case H264_NAL_SPS_EXT: + { + H264RawSPSExtension *sps_ext = unit->content; + + err = cbs_h264_write_sps_extension(ctx, pbc, sps_ext); + if (err < 0) + return err; + } + break; + + case H264_NAL_PPS: + { + H264RawPPS *pps = unit->content; + + err = cbs_h264_write_pps(ctx, pbc, pps); + if (err < 0) + return err; + + err = cbs_h264_replace_pps(ctx, unit); + if (err < 0) + return err; + } + break; + + case H264_NAL_SLICE: + case H264_NAL_IDR_SLICE: + case H264_NAL_AUXILIARY_SLICE: + { + H264RawSlice *slice = unit->content; + + err = cbs_h264_write_slice_header(ctx, pbc, &slice->header); + if (err < 0) + return err; + + if (slice->data) { + err = ff_cbs_h2645_write_slice_data(ctx, pbc, slice->data, + slice->data_size, + slice->data_bit_start); + if (err < 0) + return err; + } else { + // No slice data - that was just the header. + // (Bitstream may be unaligned!) + } + } + break; + + case H264_NAL_AUD: + { + err = cbs_h264_write_aud(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_SEI: + { + err = cbs_h264_write_sei(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_FILLER_DATA: + { + err = cbs_h264_write_filler(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_END_SEQUENCE: + { + err = cbs_h264_write_end_of_sequence(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_END_STREAM: + { + err = cbs_h264_write_end_of_stream(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " + "NAL unit type %"PRIu32".\n", unit->type); + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int cbs_h264_discarded_nal_unit(CodedBitstreamContext *ctx, + const CodedBitstreamUnit *unit, + enum AVDiscard skip) +{ + H264RawNALUnitHeader *header; + H264RawSliceHeader *slice; + int slice_type_i, slice_type_b, slice_type_si; + + if (skip <= AVDISCARD_DEFAULT) + return 0; + + // keep non-VCL + if (unit->type != H264_NAL_SLICE && + unit->type != H264_NAL_IDR_SLICE && + unit->type != H264_NAL_AUXILIARY_SLICE) + return 0; + + if (skip >= AVDISCARD_ALL) + return 1; + + if (skip >= AVDISCARD_NONKEY && unit->type != H264_NAL_IDR_SLICE) + return 1; + + header = (H264RawNALUnitHeader *)unit->content; + if (!header) { + av_log(ctx->log_ctx, AV_LOG_WARNING, + "h264 nal unit header is null, missing decompose?\n"); + return 0; + } + + if (skip >= AVDISCARD_NONREF && !header->nal_ref_idc) + return 1; + + slice = (H264RawSliceHeader *)unit->content; + if (!slice) { + av_log(ctx->log_ctx, AV_LOG_WARNING, + "h264 slice header is null, missing decompose?\n"); + return 0; + } + + slice_type_i = slice->slice_type % 5 == 2; + slice_type_b = slice->slice_type % 5 == 1; + slice_type_si = slice->slice_type % 5 == 4; + + if (skip >= AVDISCARD_BIDIR && slice_type_b) + return 1; + if (skip >= AVDISCARD_NONINTRA && !slice_type_i && !slice_type_si) + return 1; + + return 0; +} + +static av_cold void cbs_h264_flush(CodedBitstreamContext *ctx) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + + for (int i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) + av_refstruct_unref(&h264->sps[i]); + for (int i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) + av_refstruct_unref(&h264->pps[i]); + + h264->active_sps = NULL; + h264->active_pps = NULL; + h264->last_slice_nal_unit_type = 0; +} + +static av_cold void cbs_h264_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + int i; + + ff_h2645_packet_uninit(&h264->common.read_packet); + + for (i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) + av_refstruct_unref(&h264->sps[i]); + for (i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) + av_refstruct_unref(&h264->pps[i]); +} + +static void cbs_h264_free_sei(AVRefStructOpaque unused, void *content) +{ + H264RawSEI *sei = content; + ff_cbs_sei_free_message_list(&sei->message_list); +} + +static CodedBitstreamUnitTypeDescriptor cbs_h264_unit_types[] = { + CBS_UNIT_TYPE_POD(H264_NAL_SPS, H264RawSPS), + CBS_UNIT_TYPE_POD(H264_NAL_SPS_EXT, H264RawSPSExtension), + + CBS_UNIT_TYPE_INTERNAL_REF(H264_NAL_PPS, H264RawPPS, slice_group_id), + + CBS_UNIT_TYPES_INTERNAL_REF((H264_NAL_IDR_SLICE, + H264_NAL_SLICE, + H264_NAL_AUXILIARY_SLICE), H264RawSlice, data), + + CBS_UNIT_TYPE_POD(H264_NAL_AUD, H264RawAUD), + CBS_UNIT_TYPE_POD(H264_NAL_FILLER_DATA, H264RawFiller), + CBS_UNIT_TYPE_POD(H264_NAL_END_SEQUENCE, H264RawNALUnitHeader), + CBS_UNIT_TYPE_POD(H264_NAL_END_STREAM, H264RawNALUnitHeader), + + CBS_UNIT_TYPE_COMPLEX(H264_NAL_SEI, H264RawSEI, &cbs_h264_free_sei), + + CBS_UNIT_TYPE_END_OF_LIST +}; + +const CodedBitstreamType ff_cbs_type_h264 = { + .codec_id = AV_CODEC_ID_H264, + + .priv_data_size = sizeof(CodedBitstreamH264Context), + + .unit_types = cbs_h264_unit_types, + + .split_fragment = &cbs_h264_split_fragment, + .read_unit = &cbs_h264_read_nal_unit, + .write_unit = &cbs_h264_write_nal_unit, + .discarded_unit = &cbs_h264_discarded_nal_unit, + .assemble_fragment = &ff_cbs_h2645_assemble_fragment, + + .flush = &cbs_h264_flush, + .close = &cbs_h264_close, +}; + +// Macro for the read/write pair. +#define SEI_MESSAGE_RW(codec, name) \ + .read = cbs_ ## codec ## _read_ ## name ## _internal, \ + .write = cbs_ ## codec ## _write_ ## name ## _internal + +const SEIMessageTypeDescriptor ff_cbs_sei_h264_types[] = { + { + SEI_TYPE_BUFFERING_PERIOD, + 1, 0, + sizeof(H264RawSEIBufferingPeriod), + SEI_MESSAGE_RW(h264, sei_buffering_period), + }, + { + SEI_TYPE_PIC_TIMING, + 1, 0, + sizeof(H264RawSEIPicTiming), + SEI_MESSAGE_RW(h264, sei_pic_timing), + }, + { + SEI_TYPE_PAN_SCAN_RECT, + 1, 0, + sizeof(H264RawSEIPanScanRect), + SEI_MESSAGE_RW(h264, sei_pan_scan_rect), + }, + { + SEI_TYPE_RECOVERY_POINT, + 1, 0, + sizeof(H264RawSEIRecoveryPoint), + SEI_MESSAGE_RW(h264, sei_recovery_point), + }, + { + SEI_TYPE_FILM_GRAIN_CHARACTERISTICS, + 1, 0, + sizeof(H264RawFilmGrainCharacteristics), + SEI_MESSAGE_RW(h264, film_grain_characteristics), + }, + { + SEI_TYPE_FRAME_PACKING_ARRANGEMENT, + 1, 0, + sizeof(H264RawSEIFramePackingArrangement), + SEI_MESSAGE_RW(h264, sei_frame_packing_arrangement), + }, + { + SEI_TYPE_DISPLAY_ORIENTATION, + 1, 0, + sizeof(H264RawSEIDisplayOrientation), + SEI_MESSAGE_RW(h264, sei_display_orientation), + }, + SEI_MESSAGE_TYPE_END +}; diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c index 2de74691c..bcf614404 100644 --- a/libavcodec/cbs_h2645.c +++ b/libavcodec/cbs_h2645.c @@ -23,17 +23,22 @@ #include "bytestream.h" #include "cbs.h" #include "cbs_internal.h" -#include "cbs_h264.h" -#include "cbs_h265.h" -#include "cbs_h266.h" +#include "cbs_h2645.h" #include "h264.h" #include "h2645_parse.h" -#include "refstruct.h" #include "vvc.h" #include "hevc/hevc.h" -static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, +int ff_cbs_h2645_payload_extension_present(GetBitContext *gbc, uint32_t payload_size, + int cur_pos) +{ + int bits_left = payload_size * 8 - cur_pos; + return (bits_left > 0 && + (bits_left > 7 || show_bits(gbc, bits_left) & MAX_UINT_BITS(bits_left - 1))); +} + +int ff_cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, const char *name, const int *subscripts, uint32_t *write_to, uint32_t range_min, uint32_t range_max) @@ -82,7 +87,7 @@ static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, return 0; } -static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, +int ff_cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, const char *name, const int *subscripts, int32_t *write_to, int32_t range_min, int32_t range_max) @@ -137,7 +142,7 @@ static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, return 0; } -static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, +int ff_cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, const char *name, const int *subscripts, uint32_t value, uint32_t range_min, uint32_t range_max) @@ -169,7 +174,7 @@ static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, return 0; } -static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, +int ff_cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, const char *name, const int *subscripts, int32_t value, int32_t range_min, int32_t range_max) @@ -209,123 +214,7 @@ static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, return 0; } -// payload_extension_present() - true if we are before the last 1-bit -// in the payload structure, which must be in the last byte. -static int cbs_h265_payload_extension_present(GetBitContext *gbc, uint32_t payload_size, - int cur_pos) -{ - int bits_left = payload_size * 8 - cur_pos; - return (bits_left > 0 && - (bits_left > 7 || show_bits(gbc, bits_left) & MAX_UINT_BITS(bits_left - 1))); -} - -#define HEADER(name) do { \ - ff_cbs_trace_header(ctx, name); \ - } while (0) - -#define CHECK(call) do { \ - err = (call); \ - if (err < 0) \ - return err; \ - } while (0) - -#define FUNC_NAME2(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name -#define FUNC_NAME1(rw, codec, name) FUNC_NAME2(rw, codec, name) -#define FUNC_H264(name) FUNC_NAME1(READWRITE, h264, name) -#define FUNC_H265(name) FUNC_NAME1(READWRITE, h265, name) -#define FUNC_H266(name) FUNC_NAME1(READWRITE, h266, name) -#define FUNC_SEI(name) FUNC_NAME1(READWRITE, sei, name) - -#define SEI_FUNC(name, args) \ -static int FUNC(name) args; \ -static int FUNC(name ## _internal)(CodedBitstreamContext *ctx, \ - RWContext *rw, void *cur, \ - SEIMessageState *state) \ -{ \ - return FUNC(name)(ctx, rw, cur, state); \ -} \ -static int FUNC(name) args - -#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) - -#define u(width, name, range_min, range_max) \ - xu(width, name, current->name, range_min, range_max, 0, ) -#define flag(name) ub(1, name) -#define ue(name, range_min, range_max) \ - xue(name, current->name, range_min, range_max, 0, ) -#define i(width, name, range_min, range_max) \ - xi(width, name, current->name, range_min, range_max, 0, ) -#define ib(width, name) \ - xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), 0, ) -#define se(name, range_min, range_max) \ - xse(name, current->name, range_min, range_max, 0, ) - -#define us(width, name, range_min, range_max, subs, ...) \ - xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) -#define ubs(width, name, subs, ...) \ - xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) -#define flags(name, subs, ...) \ - xu(1, name, current->name, 0, 1, subs, __VA_ARGS__) -#define ues(name, range_min, range_max, subs, ...) \ - xue(name, current->name, range_min, range_max, subs, __VA_ARGS__) -#define is(width, name, range_min, range_max, subs, ...) \ - xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) -#define ibs(width, name, subs, ...) \ - xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__) -#define ses(name, range_min, range_max, subs, ...) \ - xse(name, current->name, range_min, range_max, subs, __VA_ARGS__) - -#define fixed(width, name, value) do { \ - av_unused uint32_t fixed_value = value; \ - xu(width, name, fixed_value, value, value, 0, ); \ - } while (0) - - -#define READ -#define READWRITE read -#define RWContext GetBitContext - -#define ub(width, name) do { \ - uint32_t value; \ - CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \ - &value)); \ - current->name = value; \ - } while (0) -#define xu(width, name, var, range_min, range_max, subs, ...) do { \ - uint32_t value; \ - CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ - SUBSCRIPTS(subs, __VA_ARGS__), \ - &value, range_min, range_max)); \ - var = value; \ - } while (0) -#define xue(name, var, range_min, range_max, subs, ...) do { \ - uint32_t value; \ - CHECK(cbs_read_ue_golomb(ctx, rw, #name, \ - SUBSCRIPTS(subs, __VA_ARGS__), \ - &value, range_min, range_max)); \ - var = value; \ - } while (0) -#define xi(width, name, var, range_min, range_max, subs, ...) do { \ - int32_t value; \ - CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ - SUBSCRIPTS(subs, __VA_ARGS__), \ - &value, range_min, range_max)); \ - var = value; \ - } while (0) -#define xse(name, var, range_min, range_max, subs, ...) do { \ - int32_t value; \ - CHECK(cbs_read_se_golomb(ctx, rw, #name, \ - SUBSCRIPTS(subs, __VA_ARGS__), \ - &value, range_min, range_max)); \ - var = value; \ - } while (0) - - -#define infer(name, value) do { \ - current->name = value; \ - } while (0) - -static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) +int ff_cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) { int bits_left = get_bits_left(gbc); if (bits_left > 8) @@ -337,157 +226,7 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) return 0; } -#define more_rbsp_data(var) ((var) = cbs_h2645_read_more_rbsp_data(rw)) - -#define bit_position(rw) (get_bits_count(rw)) -#define byte_alignment(rw) (get_bits_count(rw) % 8) - -/* The CBS SEI code uses the refstruct API for the allocation - * of its child buffers. */ -#define allocate(name, size) do { \ - name = ff_refstruct_allocz(size + \ - AV_INPUT_BUFFER_PADDING_SIZE); \ - if (!name) \ - return AVERROR(ENOMEM); \ - } while (0) - -#define FUNC(name) FUNC_SEI(name) -#include "cbs_sei_syntax_template.c" -#undef FUNC - -#undef allocate - -/* The other code uses the refstruct API for the allocation - * of its child buffers. */ -#define allocate(name, size) do { \ - name ## _ref = av_buffer_allocz(size + \ - AV_INPUT_BUFFER_PADDING_SIZE); \ - if (!name ## _ref) \ - return AVERROR(ENOMEM); \ - name = name ## _ref->data; \ - } while (0) - -#define FUNC(name) FUNC_H264(name) -#include "cbs_h264_syntax_template.c" -#undef FUNC - -#define FUNC(name) FUNC_H265(name) -#include "cbs_h265_syntax_template.c" -#undef FUNC - -#define FUNC(name) FUNC_H266(name) -#include "cbs_h266_syntax_template.c" -#undef FUNC - -#undef READ -#undef READWRITE -#undef RWContext -#undef ub -#undef xu -#undef xi -#undef xue -#undef xse -#undef infer -#undef more_rbsp_data -#undef bit_position -#undef byte_alignment -#undef allocate - - -#define WRITE -#define READWRITE write -#define RWContext PutBitContext - -#define ub(width, name) do { \ - uint32_t value = current->name; \ - CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \ - value)); \ - } while (0) -#define xu(width, name, var, range_min, range_max, subs, ...) do { \ - uint32_t value = var; \ - CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ - SUBSCRIPTS(subs, __VA_ARGS__), \ - value, range_min, range_max)); \ - } while (0) -#define xue(name, var, range_min, range_max, subs, ...) do { \ - uint32_t value = var; \ - CHECK(cbs_write_ue_golomb(ctx, rw, #name, \ - SUBSCRIPTS(subs, __VA_ARGS__), \ - value, range_min, range_max)); \ - } while (0) -#define xi(width, name, var, range_min, range_max, subs, ...) do { \ - int32_t value = var; \ - CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ - SUBSCRIPTS(subs, __VA_ARGS__), \ - value, range_min, range_max)); \ - } while (0) -#define xse(name, var, range_min, range_max, subs, ...) do { \ - int32_t value = var; \ - CHECK(cbs_write_se_golomb(ctx, rw, #name, \ - SUBSCRIPTS(subs, __VA_ARGS__), \ - value, range_min, range_max)); \ - } while (0) - -#define infer(name, value) do { \ - if (current->name != (value)) { \ - av_log(ctx->log_ctx, AV_LOG_ERROR, \ - "%s does not match inferred value: " \ - "%"PRId64", but should be %"PRId64".\n", \ - #name, (int64_t)current->name, (int64_t)(value)); \ - return AVERROR_INVALIDDATA; \ - } \ - } while (0) - -#define more_rbsp_data(var) (var) - -#define bit_position(rw) (put_bits_count(rw)) -#define byte_alignment(rw) (put_bits_count(rw) % 8) - -#define allocate(name, size) do { \ - if (!name) { \ - av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \ - "for writing.\n", #name); \ - return AVERROR_INVALIDDATA; \ - } \ - } while (0) - -#define FUNC(name) FUNC_SEI(name) -#include "cbs_sei_syntax_template.c" -#undef FUNC - -#define FUNC(name) FUNC_H264(name) -#include "cbs_h264_syntax_template.c" -#undef FUNC - -#define FUNC(name) FUNC_H265(name) -#include "cbs_h265_syntax_template.c" -#undef FUNC - -#define FUNC(name) FUNC_H266(name) -#include "cbs_h266_syntax_template.c" -#undef FUNC - -#undef WRITE -#undef READWRITE -#undef RWContext -#undef ub -#undef xu -#undef xi -#undef xue -#undef xse -#undef u -#undef i -#undef flag -#undef ue -#undef se -#undef infer -#undef more_rbsp_data -#undef bit_position -#undef byte_alignment -#undef allocate - - -static int cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, +int ff_cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const H2645Packet *packet) { @@ -523,722 +262,7 @@ static int cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, return 0; } -static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag, - int header) -{ - enum AVCodecID codec_id = ctx->codec->codec_id; - CodedBitstreamH2645Context *priv = ctx->priv_data; - GetByteContext gbc; - int err; - - av_assert0(frag->data && frag->nb_units == 0); - if (frag->data_size == 0) - return 0; - - if (header && frag->data[0] && codec_id == AV_CODEC_ID_H264) { - // AVCC header. - size_t size, start, end; - int i, count, version; - - priv->mp4 = 1; - - bytestream2_init(&gbc, frag->data, frag->data_size); - - if (bytestream2_get_bytes_left(&gbc) < 6) - return AVERROR_INVALIDDATA; - - version = bytestream2_get_byte(&gbc); - if (version != 1) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid AVCC header: " - "first byte %u.\n", version); - return AVERROR_INVALIDDATA; - } - - bytestream2_skip(&gbc, 3); - priv->nal_length_size = (bytestream2_get_byte(&gbc) & 3) + 1; - - // SPS array. - count = bytestream2_get_byte(&gbc) & 0x1f; - start = bytestream2_tell(&gbc); - for (i = 0; i < count; i++) { - if (bytestream2_get_bytes_left(&gbc) < 2 * (count - i)) - return AVERROR_INVALIDDATA; - size = bytestream2_get_be16(&gbc); - if (bytestream2_get_bytes_left(&gbc) < size) - return AVERROR_INVALIDDATA; - bytestream2_skip(&gbc, size); - } - end = bytestream2_tell(&gbc); - - err = ff_h2645_packet_split(&priv->read_packet, - frag->data + start, end - start, - ctx->log_ctx, 2, AV_CODEC_ID_H264, - H2645_FLAG_IS_NALFF | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF); - if (err < 0) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC SPS array.\n"); - return err; - } - err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); - if (err < 0) - return err; - - // PPS array. - count = bytestream2_get_byte(&gbc); - start = bytestream2_tell(&gbc); - for (i = 0; i < count; i++) { - if (bytestream2_get_bytes_left(&gbc) < 2 * (count - i)) - return AVERROR_INVALIDDATA; - size = bytestream2_get_be16(&gbc); - if (bytestream2_get_bytes_left(&gbc) < size) - return AVERROR_INVALIDDATA; - bytestream2_skip(&gbc, size); - } - end = bytestream2_tell(&gbc); - - err = ff_h2645_packet_split(&priv->read_packet, - frag->data + start, end - start, - ctx->log_ctx, 2, AV_CODEC_ID_H264, - H2645_FLAG_IS_NALFF | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF); - if (err < 0) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC PPS array.\n"); - return err; - } - err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); - if (err < 0) - return err; - - if (bytestream2_get_bytes_left(&gbc) > 0) { - av_log(ctx->log_ctx, AV_LOG_WARNING, "%u bytes left at end of AVCC " - "header.\n", bytestream2_get_bytes_left(&gbc)); - } - - } else if (header && frag->data[0] && codec_id == AV_CODEC_ID_HEVC) { - // HVCC header. - size_t size, start, end; - int i, j, nb_arrays, nal_unit_type, nb_nals, version; - - priv->mp4 = 1; - - bytestream2_init(&gbc, frag->data, frag->data_size); - - if (bytestream2_get_bytes_left(&gbc) < 23) - return AVERROR_INVALIDDATA; - - version = bytestream2_get_byte(&gbc); - if (version != 1) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid HVCC header: " - "first byte %u.\n", version); - return AVERROR_INVALIDDATA; - } - - bytestream2_skip(&gbc, 20); - priv->nal_length_size = (bytestream2_get_byte(&gbc) & 3) + 1; - - nb_arrays = bytestream2_get_byte(&gbc); - for (i = 0; i < nb_arrays; i++) { - nal_unit_type = bytestream2_get_byte(&gbc) & 0x3f; - nb_nals = bytestream2_get_be16(&gbc); - - start = bytestream2_tell(&gbc); - for (j = 0; j < nb_nals; j++) { - if (bytestream2_get_bytes_left(&gbc) < 2) - return AVERROR_INVALIDDATA; - size = bytestream2_get_be16(&gbc); - if (bytestream2_get_bytes_left(&gbc) < size) - return AVERROR_INVALIDDATA; - bytestream2_skip(&gbc, size); - } - end = bytestream2_tell(&gbc); - - err = ff_h2645_packet_split(&priv->read_packet, - frag->data + start, end - start, - ctx->log_ctx, 2, AV_CODEC_ID_HEVC, - H2645_FLAG_IS_NALFF | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF); - if (err < 0) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split " - "HVCC array %d (%d NAL units of type %d).\n", - i, nb_nals, nal_unit_type); - return err; - } - err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); - if (err < 0) - return err; - } - - } else if(header && frag->data[0] && codec_id == AV_CODEC_ID_VVC) { - // VVCC header. - int ptl_present_flag, num_arrays; - int b, i, j; - - priv->mp4 = 1; - - bytestream2_init(&gbc, frag->data, frag->data_size); - - b = bytestream2_get_byte(&gbc); - priv->nal_length_size = ((b >> 1) & 3) + 1; - ptl_present_flag = b & 1; - - if(ptl_present_flag) { - int num_sublayers, num_bytes_constraint_info, num_sub_profiles; - num_sublayers = (bytestream2_get_be16u(&gbc) >> 4) & 7; - bytestream2_skip(&gbc, 1); - - // begin VvcPTLRecord(num_sublayers); - num_bytes_constraint_info = bytestream2_get_byte(&gbc) & 0x3f; - bytestream2_skip(&gbc, 2 + num_bytes_constraint_info); - if(num_sublayers > 1) { - int count_present_flags = 0; - b = bytestream2_get_byte(&gbc); - for(i = num_sublayers - 2; i >= 0; i--) { - if((b >> (7 - (num_sublayers - 2 - i))) & 0x01) - count_present_flags++; - } - bytestream2_skip(&gbc, count_present_flags); - } - num_sub_profiles = bytestream2_get_byte(&gbc); - bytestream2_skip(&gbc, num_sub_profiles * 4); - // end VvcPTLRecord(num_sublayers); - - bytestream2_skip(&gbc, 3 * 2); - } - - num_arrays = bytestream2_get_byte(&gbc); - for(j = 0; j < num_arrays; j++) { - size_t start, end, size; - int nal_unit_type = bytestream2_get_byte(&gbc) & 0x1f; - unsigned int num_nalus = 1; - if(nal_unit_type != VVC_DCI_NUT && nal_unit_type != VVC_OPI_NUT) - num_nalus = bytestream2_get_be16(&gbc); - - start = bytestream2_tell(&gbc); - for(i = 0; i < num_nalus; i++) { - if (bytestream2_get_bytes_left(&gbc) < 2) - return AVERROR_INVALIDDATA; - size = bytestream2_get_be16(&gbc); - if (bytestream2_get_bytes_left(&gbc) < size) - return AVERROR_INVALIDDATA; - bytestream2_skip(&gbc, size); - } - end = bytestream2_tell(&gbc); - - err = ff_h2645_packet_split(&priv->read_packet, - frag->data + start, end - start, - ctx->log_ctx, 2, AV_CODEC_ID_VVC, - H2645_FLAG_IS_NALFF | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF); - if (err < 0) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split " - "VVCC array %d (%d NAL units of type %d).\n", - i, num_nalus, nal_unit_type); - return err; - } - err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); - if (err < 0) - return err; - } - } else { - int flags = (H2645_FLAG_IS_NALFF * !!priv->mp4) | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF; - // Annex B, or later MP4 with already-known parameters. - - err = ff_h2645_packet_split(&priv->read_packet, - frag->data, frag->data_size, - ctx->log_ctx, - priv->nal_length_size, - codec_id, flags); - if (err < 0) - return err; - - err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); - if (err < 0) - return err; - } - - return 0; -} - -#define cbs_h2645_replace_ps(h26n, ps_name, ps_var, id_element) \ -static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \ - CodedBitstreamUnit *unit) \ -{ \ - CodedBitstreamH26 ## h26n ## Context *priv = ctx->priv_data; \ - H26 ## h26n ## Raw ## ps_name *ps_var = unit->content; \ - unsigned int id = ps_var->id_element; \ - int err = ff_cbs_make_unit_refcounted(ctx, unit); \ - if (err < 0) \ - return err; \ - if (priv->ps_var[id] == priv->active_ ## ps_var) \ - priv->active_ ## ps_var = NULL ; \ - av_assert0(unit->content_ref); \ - ff_refstruct_replace(&priv->ps_var[id], unit->content_ref); \ - return 0; \ -} - -cbs_h2645_replace_ps(4, SPS, sps, seq_parameter_set_id) -cbs_h2645_replace_ps(4, PPS, pps, pic_parameter_set_id) -cbs_h2645_replace_ps(5, VPS, vps, vps_video_parameter_set_id) -cbs_h2645_replace_ps(5, SPS, sps, sps_seq_parameter_set_id) -cbs_h2645_replace_ps(5, PPS, pps, pps_pic_parameter_set_id) - -#define cbs_h266_replace_ps(h26n, ps_name, ps_var, id_element) \ -static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \ - CodedBitstreamUnit *unit) \ -{ \ - CodedBitstreamH26 ## h26n ## Context *priv = ctx->priv_data; \ - H26 ## h26n ## Raw ## ps_name *ps_var = unit->content; \ - unsigned int id = ps_var->id_element; \ - int err = ff_cbs_make_unit_refcounted(ctx, unit); \ - if (err < 0) \ - return err; \ - av_assert0(unit->content_ref); \ - ff_refstruct_replace(&priv->ps_var[id], unit->content_ref); \ - return 0; \ -} - -cbs_h266_replace_ps(6, VPS, vps, vps_video_parameter_set_id) -cbs_h266_replace_ps(6, PPS, pps, pps_pic_parameter_set_id) - -static int cbs_h266_replace_sps(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit) -{ - CodedBitstreamH266Context *priv = ctx->priv_data; - H266RawSPS *sps = unit->content; - unsigned int id = sps->sps_seq_parameter_set_id; - int err = ff_cbs_make_unit_refcounted(ctx, unit); - if (err < 0) - return err; - av_assert0(unit->content_ref); - if (priv->sps[id] && memcmp(priv->sps[id], unit->content_ref, sizeof(*priv->sps[id]))) { - for (unsigned int i = 0; i < VVC_MAX_PPS_COUNT; i++) { - if (priv->pps[i] && priv->pps[i]->pps_seq_parameter_set_id == id) - ff_refstruct_unref(&priv->pps[i]); - } - } - ff_refstruct_replace(&priv->sps[id], unit->content_ref); - return 0; -} - -static int cbs_h266_replace_ph(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit, - H266RawPictureHeader *ph) -{ - CodedBitstreamH266Context *h266 = ctx->priv_data; - int err; - - err = ff_cbs_make_unit_refcounted(ctx, unit); - if (err < 0) - return err; - av_assert0(unit->content_ref); - ff_refstruct_replace(&h266->ph_ref, unit->content_ref); - h266->ph = ph; - return 0; -} - -static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit) -{ - GetBitContext gbc; - int err; - - err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); - if (err < 0) - return err; - - err = ff_cbs_alloc_unit_content(ctx, unit); - if (err < 0) - return err; - - switch (unit->type) { - case H264_NAL_SPS: - { - H264RawSPS *sps = unit->content; - - err = cbs_h264_read_sps(ctx, &gbc, sps); - if (err < 0) - return err; - - err = cbs_h264_replace_sps(ctx, unit); - if (err < 0) - return err; - } - break; - - case H264_NAL_SPS_EXT: - { - err = cbs_h264_read_sps_extension(ctx, &gbc, unit->content); - if (err < 0) - return err; - } - break; - - case H264_NAL_PPS: - { - H264RawPPS *pps = unit->content; - - err = cbs_h264_read_pps(ctx, &gbc, pps); - if (err < 0) - return err; - - err = cbs_h264_replace_pps(ctx, unit); - if (err < 0) - return err; - } - break; - - case H264_NAL_SLICE: - case H264_NAL_IDR_SLICE: - case H264_NAL_AUXILIARY_SLICE: - { - H264RawSlice *slice = unit->content; - int pos, len; - - err = cbs_h264_read_slice_header(ctx, &gbc, &slice->header); - if (err < 0) - return err; - - if (!cbs_h2645_read_more_rbsp_data(&gbc)) - return AVERROR_INVALIDDATA; - - pos = get_bits_count(&gbc); - len = unit->data_size; - - slice->data_size = len - pos / 8; - slice->data_ref = av_buffer_ref(unit->data_ref); - if (!slice->data_ref) - return AVERROR(ENOMEM); - slice->data = unit->data + pos / 8; - slice->data_bit_start = pos % 8; - } - break; - - case H264_NAL_AUD: - { - err = cbs_h264_read_aud(ctx, &gbc, unit->content); - if (err < 0) - return err; - } - break; - - case H264_NAL_SEI: - { - err = cbs_h264_read_sei(ctx, &gbc, unit->content); - if (err < 0) - return err; - } - break; - - case H264_NAL_FILLER_DATA: - { - err = cbs_h264_read_filler(ctx, &gbc, unit->content); - if (err < 0) - return err; - } - break; - - case H264_NAL_END_SEQUENCE: - case H264_NAL_END_STREAM: - { - err = (unit->type == H264_NAL_END_SEQUENCE ? - cbs_h264_read_end_of_sequence : - cbs_h264_read_end_of_stream)(ctx, &gbc, unit->content); - if (err < 0) - return err; - } - break; - - default: - return AVERROR(ENOSYS); - } - - return 0; -} - -static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit) -{ - GetBitContext gbc; - int err; - - err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); - if (err < 0) - return err; - - err = ff_cbs_alloc_unit_content(ctx, unit); - if (err < 0) - return err; - - switch (unit->type) { - case HEVC_NAL_VPS: - { - H265RawVPS *vps = unit->content; - - err = cbs_h265_read_vps(ctx, &gbc, vps); - if (err < 0) - return err; - - err = cbs_h265_replace_vps(ctx, unit); - if (err < 0) - return err; - } - break; - case HEVC_NAL_SPS: - { - H265RawSPS *sps = unit->content; - - err = cbs_h265_read_sps(ctx, &gbc, sps); - if (err < 0) - return err; - - err = cbs_h265_replace_sps(ctx, unit); - if (err < 0) - return err; - } - break; - - case HEVC_NAL_PPS: - { - H265RawPPS *pps = unit->content; - - err = cbs_h265_read_pps(ctx, &gbc, pps); - if (err < 0) - return err; - - err = cbs_h265_replace_pps(ctx, unit); - if (err < 0) - return err; - } - break; - - case HEVC_NAL_TRAIL_N: - case HEVC_NAL_TRAIL_R: - case HEVC_NAL_TSA_N: - case HEVC_NAL_TSA_R: - case HEVC_NAL_STSA_N: - case HEVC_NAL_STSA_R: - case HEVC_NAL_RADL_N: - case HEVC_NAL_RADL_R: - case HEVC_NAL_RASL_N: - case HEVC_NAL_RASL_R: - case HEVC_NAL_BLA_W_LP: - case HEVC_NAL_BLA_W_RADL: - case HEVC_NAL_BLA_N_LP: - case HEVC_NAL_IDR_W_RADL: - case HEVC_NAL_IDR_N_LP: - case HEVC_NAL_CRA_NUT: - { - H265RawSlice *slice = unit->content; - int pos, len; - - err = cbs_h265_read_slice_segment_header(ctx, &gbc, &slice->header); - if (err < 0) - return err; - - if (!cbs_h2645_read_more_rbsp_data(&gbc)) - return AVERROR_INVALIDDATA; - - pos = get_bits_count(&gbc); - len = unit->data_size; - - slice->data_size = len - pos / 8; - slice->data_ref = av_buffer_ref(unit->data_ref); - if (!slice->data_ref) - return AVERROR(ENOMEM); - slice->data = unit->data + pos / 8; - slice->data_bit_start = pos % 8; - } - break; - - case HEVC_NAL_AUD: - { - err = cbs_h265_read_aud(ctx, &gbc, unit->content); - if (err < 0) - return err; - } - break; - - case HEVC_NAL_FD_NUT: - { - err = cbs_h265_read_filler(ctx, &gbc, unit->content); - if (err < 0) - return err; - } - break; - - case HEVC_NAL_SEI_PREFIX: - case HEVC_NAL_SEI_SUFFIX: - { - err = cbs_h265_read_sei(ctx, &gbc, unit->content, - unit->type == HEVC_NAL_SEI_PREFIX); - - if (err < 0) - return err; - } - break; - - default: - return AVERROR(ENOSYS); - } - - return 0; -} - -static int cbs_h266_read_nal_unit(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit) -{ - GetBitContext gbc; - int err; - - err = init_get_bits8(&gbc, unit->data, unit->data_size); - if (err < 0) - return err; - - err = ff_cbs_alloc_unit_content(ctx, unit); - if (err < 0) - return err; - - switch (unit->type) { - case VVC_DCI_NUT: - { - err = cbs_h266_read_dci(ctx, &gbc, unit->content); - - if (err < 0) - return err; - } - break; - case VVC_OPI_NUT: - { - err = cbs_h266_read_opi(ctx, &gbc, unit->content); - - if (err < 0) - return err; - } - break; - case VVC_VPS_NUT: - { - H266RawVPS *vps = unit->content; - - err = cbs_h266_read_vps(ctx, &gbc, vps); - if (err < 0) - return err; - - err = cbs_h266_replace_vps(ctx, unit); - if (err < 0) - return err; - } - break; - case VVC_SPS_NUT: - { - H266RawSPS *sps = unit->content; - - err = cbs_h266_read_sps(ctx, &gbc, sps); - if (err < 0) - return err; - - err = cbs_h266_replace_sps(ctx, unit); - if (err < 0) - return err; - } - break; - - case VVC_PPS_NUT: - { - H266RawPPS *pps = unit->content; - - err = cbs_h266_read_pps(ctx, &gbc, pps); - if (err < 0) - return err; - - err = cbs_h266_replace_pps(ctx, unit); - if (err < 0) - return err; - } - break; - - case VVC_PREFIX_APS_NUT: - case VVC_SUFFIX_APS_NUT: - { - err = cbs_h266_read_aps(ctx, &gbc, unit->content, - unit->type == VVC_PREFIX_APS_NUT); - - if (err < 0) - return err; - } - break; - case VVC_PH_NUT: - { - H266RawPH *ph = unit->content; - err = cbs_h266_read_ph(ctx, &gbc, ph); - if (err < 0) - return err; - err = cbs_h266_replace_ph(ctx, unit, &ph->ph_picture_header); - if (err < 0) - return err; - } - break; - - case VVC_TRAIL_NUT: - case VVC_STSA_NUT: - case VVC_RADL_NUT: - case VVC_RASL_NUT: - case VVC_IDR_W_RADL: - case VVC_IDR_N_LP: - case VVC_CRA_NUT: - case VVC_GDR_NUT: - { - H266RawSlice *slice = unit->content; - int pos, len; - - err = cbs_h266_read_slice_header(ctx, &gbc, &slice->header); - if (err < 0) - return err; - - if (!cbs_h2645_read_more_rbsp_data(&gbc)) - return AVERROR_INVALIDDATA; - - pos = get_bits_count(&gbc); - len = unit->data_size; - - if (slice->header.sh_picture_header_in_slice_header_flag) { - err = cbs_h266_replace_ph(ctx, unit, &slice->header.sh_picture_header); - if (err < 0) - return err; - } - - slice->header_size = pos / 8; - slice->data_size = len - pos / 8; - slice->data_ref = av_buffer_ref(unit->data_ref); - if (!slice->data_ref) - return AVERROR(ENOMEM); - slice->data = unit->data + pos / 8; - slice->data_bit_start = pos % 8; - } - break; - - case VVC_AUD_NUT: - { - err = cbs_h266_read_aud(ctx, &gbc, unit->content); - if (err < 0) - return err; - } - break; - - case VVC_PREFIX_SEI_NUT: - case VVC_SUFFIX_SEI_NUT: - { - err = cbs_h266_read_sei(ctx, &gbc, unit->content, - unit->type == VVC_PREFIX_SEI_NUT); - - if (err < 0) - return err; - } - break; - - default: - return AVERROR(ENOSYS); - } - return 0; -} - -static int cbs_h2645_write_slice_data(CodedBitstreamContext *ctx, +int ff_cbs_h2645_write_slice_data(CodedBitstreamContext *ctx, PutBitContext *pbc, const uint8_t *data, size_t data_size, int data_bit_start) { @@ -1296,518 +320,7 @@ static int cbs_h2645_write_slice_data(CodedBitstreamContext *ctx, return 0; } -static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit, - PutBitContext *pbc) -{ - int err; - - switch (unit->type) { - case H264_NAL_SPS: - { - H264RawSPS *sps = unit->content; - - err = cbs_h264_write_sps(ctx, pbc, sps); - if (err < 0) - return err; - - err = cbs_h264_replace_sps(ctx, unit); - if (err < 0) - return err; - } - break; - - case H264_NAL_SPS_EXT: - { - H264RawSPSExtension *sps_ext = unit->content; - - err = cbs_h264_write_sps_extension(ctx, pbc, sps_ext); - if (err < 0) - return err; - } - break; - - case H264_NAL_PPS: - { - H264RawPPS *pps = unit->content; - - err = cbs_h264_write_pps(ctx, pbc, pps); - if (err < 0) - return err; - - err = cbs_h264_replace_pps(ctx, unit); - if (err < 0) - return err; - } - break; - - case H264_NAL_SLICE: - case H264_NAL_IDR_SLICE: - case H264_NAL_AUXILIARY_SLICE: - { - H264RawSlice *slice = unit->content; - - err = cbs_h264_write_slice_header(ctx, pbc, &slice->header); - if (err < 0) - return err; - - if (slice->data) { - err = cbs_h2645_write_slice_data(ctx, pbc, slice->data, - slice->data_size, - slice->data_bit_start); - if (err < 0) - return err; - } else { - // No slice data - that was just the header. - // (Bitstream may be unaligned!) - } - } - break; - - case H264_NAL_AUD: - { - err = cbs_h264_write_aud(ctx, pbc, unit->content); - if (err < 0) - return err; - } - break; - - case H264_NAL_SEI: - { - err = cbs_h264_write_sei(ctx, pbc, unit->content); - if (err < 0) - return err; - } - break; - - case H264_NAL_FILLER_DATA: - { - err = cbs_h264_write_filler(ctx, pbc, unit->content); - if (err < 0) - return err; - } - break; - - case H264_NAL_END_SEQUENCE: - { - err = cbs_h264_write_end_of_sequence(ctx, pbc, unit->content); - if (err < 0) - return err; - } - break; - - case H264_NAL_END_STREAM: - { - err = cbs_h264_write_end_of_stream(ctx, pbc, unit->content); - if (err < 0) - return err; - } - break; - - default: - av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " - "NAL unit type %"PRIu32".\n", unit->type); - return AVERROR_PATCHWELCOME; - } - - return 0; -} - -static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit, - PutBitContext *pbc) -{ - int err; - - switch (unit->type) { - case HEVC_NAL_VPS: - { - H265RawVPS *vps = unit->content; - - err = cbs_h265_write_vps(ctx, pbc, vps); - if (err < 0) - return err; - - err = cbs_h265_replace_vps(ctx, unit); - if (err < 0) - return err; - } - break; - - case HEVC_NAL_SPS: - { - H265RawSPS *sps = unit->content; - - err = cbs_h265_write_sps(ctx, pbc, sps); - if (err < 0) - return err; - - err = cbs_h265_replace_sps(ctx, unit); - if (err < 0) - return err; - } - break; - - case HEVC_NAL_PPS: - { - H265RawPPS *pps = unit->content; - - err = cbs_h265_write_pps(ctx, pbc, pps); - if (err < 0) - return err; - - err = cbs_h265_replace_pps(ctx, unit); - if (err < 0) - return err; - } - break; - - case HEVC_NAL_TRAIL_N: - case HEVC_NAL_TRAIL_R: - case HEVC_NAL_TSA_N: - case HEVC_NAL_TSA_R: - case HEVC_NAL_STSA_N: - case HEVC_NAL_STSA_R: - case HEVC_NAL_RADL_N: - case HEVC_NAL_RADL_R: - case HEVC_NAL_RASL_N: - case HEVC_NAL_RASL_R: - case HEVC_NAL_BLA_W_LP: - case HEVC_NAL_BLA_W_RADL: - case HEVC_NAL_BLA_N_LP: - case HEVC_NAL_IDR_W_RADL: - case HEVC_NAL_IDR_N_LP: - case HEVC_NAL_CRA_NUT: - { - H265RawSlice *slice = unit->content; - - err = cbs_h265_write_slice_segment_header(ctx, pbc, &slice->header); - if (err < 0) - return err; - - if (slice->data) { - err = cbs_h2645_write_slice_data(ctx, pbc, slice->data, - slice->data_size, - slice->data_bit_start); - if (err < 0) - return err; - } else { - // No slice data - that was just the header. - } - } - break; - - case HEVC_NAL_AUD: - { - err = cbs_h265_write_aud(ctx, pbc, unit->content); - if (err < 0) - return err; - } - break; - - case HEVC_NAL_FD_NUT: - { - err = cbs_h265_write_filler(ctx, pbc, unit->content); - if (err < 0) - return err; - } - break; - - case HEVC_NAL_SEI_PREFIX: - case HEVC_NAL_SEI_SUFFIX: - { - err = cbs_h265_write_sei(ctx, pbc, unit->content, - unit->type == HEVC_NAL_SEI_PREFIX); - - if (err < 0) - return err; - } - break; - - default: - av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " - "NAL unit type %"PRIu32".\n", unit->type); - return AVERROR_PATCHWELCOME; - } - - return 0; -} - -static int cbs_h264_discarded_nal_unit(CodedBitstreamContext *ctx, - const CodedBitstreamUnit *unit, - enum AVDiscard skip) -{ - H264RawNALUnitHeader *header; - H264RawSliceHeader *slice; - int slice_type_i, slice_type_b, slice_type_si; - - if (skip <= AVDISCARD_DEFAULT) - return 0; - - // keep non-VCL - if (unit->type != H264_NAL_SLICE && - unit->type != H264_NAL_IDR_SLICE && - unit->type != H264_NAL_AUXILIARY_SLICE) - return 0; - - if (skip >= AVDISCARD_ALL) - return 1; - - if (skip >= AVDISCARD_NONKEY && unit->type != H264_NAL_IDR_SLICE) - return 1; - - header = (H264RawNALUnitHeader *)unit->content; - if (!header) { - av_log(ctx->log_ctx, AV_LOG_WARNING, - "h264 nal unit header is null, missing decompose?\n"); - return 0; - } - - if (skip >= AVDISCARD_NONREF && !header->nal_ref_idc) - return 1; - - slice = (H264RawSliceHeader *)unit->content; - if (!slice) { - av_log(ctx->log_ctx, AV_LOG_WARNING, - "h264 slice header is null, missing decompose?\n"); - return 0; - } - - slice_type_i = slice->slice_type % 5 == 2; - slice_type_b = slice->slice_type % 5 == 1; - slice_type_si = slice->slice_type % 5 == 4; - - if (skip >= AVDISCARD_BIDIR && slice_type_b) - return 1; - if (skip >= AVDISCARD_NONINTRA && !slice_type_i && !slice_type_si) - return 1; - - return 0; -} - -static int cbs_h265_discarded_nal_unit(CodedBitstreamContext *ctx, - const CodedBitstreamUnit *unit, - enum AVDiscard skip) -{ - H265RawSliceHeader *slice; - - if (skip <= AVDISCARD_DEFAULT) - return 0; - - switch (unit->type) { - case HEVC_NAL_BLA_W_LP: - case HEVC_NAL_BLA_W_RADL: - case HEVC_NAL_BLA_N_LP: - case HEVC_NAL_IDR_W_RADL: - case HEVC_NAL_IDR_N_LP: - case HEVC_NAL_CRA_NUT: - // IRAP slice - if (skip < AVDISCARD_ALL) - return 0; - break; - - case HEVC_NAL_TRAIL_R: - case HEVC_NAL_TRAIL_N: - case HEVC_NAL_TSA_N: - case HEVC_NAL_TSA_R: - case HEVC_NAL_STSA_N: - case HEVC_NAL_STSA_R: - case HEVC_NAL_RADL_N: - case HEVC_NAL_RADL_R: - case HEVC_NAL_RASL_N: - case HEVC_NAL_RASL_R: - // Slice - break; - default: - // Don't discard non-slice nal. - return 0; - } - - if (skip >= AVDISCARD_NONKEY) - return 1; - - slice = (H265RawSliceHeader *)unit->content; - if (!slice) { - av_log(ctx->log_ctx, AV_LOG_WARNING, - "h265 slice header is null, missing decompose?\n"); - return 0; - } - - if (skip >= AVDISCARD_NONINTRA && slice->slice_type != HEVC_SLICE_I) - return 1; - if (skip >= AVDISCARD_BIDIR && slice->slice_type == HEVC_SLICE_B) - return 1; - - if (skip >= AVDISCARD_NONREF) { - switch (unit->type) { - case HEVC_NAL_TRAIL_N: - case HEVC_NAL_TSA_N: - case HEVC_NAL_STSA_N: - case HEVC_NAL_RADL_N: - case HEVC_NAL_RASL_N: - case HEVC_NAL_VCL_N10: - case HEVC_NAL_VCL_N12: - case HEVC_NAL_VCL_N14: - // non-ref - return 1; - default: - break; - } - } - - return 0; -} - -static int cbs_h266_write_nal_unit(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit, - PutBitContext *pbc) -{ - int err; - - switch (unit->type) { - case VVC_DCI_NUT: - { - H266RawDCI *dci = unit->content; - - err = cbs_h266_write_dci(ctx, pbc, dci); - if (err < 0) - return err; - } - break; - case VVC_OPI_NUT: - { - H266RawOPI *opi = unit->content; - - err = cbs_h266_write_opi(ctx, pbc, opi); - if (err < 0) - return err; - } - break; - case VVC_VPS_NUT: - { - H266RawVPS *vps = unit->content; - - err = cbs_h266_write_vps(ctx, pbc, vps); - if (err < 0) - return err; - - err = cbs_h266_replace_vps(ctx, unit); - if (err < 0) - return err; - } - break; - case VVC_SPS_NUT: - { - H266RawSPS *sps = unit->content; - - err = cbs_h266_write_sps(ctx, pbc, sps); - if (err < 0) - return err; - - err = cbs_h266_replace_sps(ctx, unit); - if (err < 0) - return err; - } - break; - - case VVC_PPS_NUT: - { - H266RawPPS *pps = unit->content; - - err = cbs_h266_write_pps(ctx, pbc, pps); - if (err < 0) - return err; - - err = cbs_h266_replace_pps(ctx, unit); - if (err < 0) - return err; - } - break; - - case VVC_PREFIX_APS_NUT: - case VVC_SUFFIX_APS_NUT: - { - err = cbs_h266_write_aps(ctx, pbc, unit->content, - unit->type == VVC_PREFIX_APS_NUT); - if (err < 0) - return err; - } - break; - case VVC_PH_NUT: - { - H266RawPH *ph = unit->content; - err = cbs_h266_write_ph(ctx, pbc, ph); - if (err < 0) - return err; - - err = cbs_h266_replace_ph(ctx, unit, &ph->ph_picture_header); - if (err < 0) - return err; - } - break; - - case VVC_TRAIL_NUT: - case VVC_STSA_NUT: - case VVC_RADL_NUT: - case VVC_RASL_NUT: - case VVC_IDR_W_RADL: - case VVC_IDR_N_LP: - case VVC_CRA_NUT: - case VVC_GDR_NUT: - { - H266RawSlice *slice = unit->content; - - err = cbs_h266_write_slice_header(ctx, pbc, &slice->header); - if (err < 0) - return err; - - if (slice->header.sh_picture_header_in_slice_header_flag) { - err = cbs_h266_replace_ph(ctx, unit, &slice->header.sh_picture_header); - if (err < 0) - return err; - } - - if (slice->data) { - err = cbs_h2645_write_slice_data(ctx, pbc, slice->data, - slice->data_size, - slice->data_bit_start); - if (err < 0) - return err; - } else { - // No slice data - that was just the header. - } - } - break; - - case VVC_AUD_NUT: - { - err = cbs_h266_write_aud(ctx, pbc, unit->content); - if (err < 0) - return err; - } - break; - - case VVC_PREFIX_SEI_NUT: - case VVC_SUFFIX_SEI_NUT: - { - err = cbs_h266_write_sei(ctx, pbc, unit->content, - unit->type == VVC_PREFIX_SEI_NUT); - - if (err < 0) - return err; - } - break; - - default: - av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " - "NAL unit type %"PRIu32".\n", unit->type); - return AVERROR_PATCHWELCOME; - } - - return 0; -} - -static int cbs_h2645_unit_requires_zero_byte(enum AVCodecID codec_id, +int ff_cbs_h2645_unit_requires_zero_byte(enum AVCodecID codec_id, CodedBitstreamUnitType type, int nal_unit_index) { @@ -1825,7 +338,7 @@ static int cbs_h2645_unit_requires_zero_byte(enum AVCodecID codec_id, return 0; } -static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, +int ff_cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag) { uint8_t *data; @@ -1859,7 +372,7 @@ static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, frag->data_bit_padding = unit->data_bit_padding; } - if (cbs_h2645_unit_requires_zero_byte(ctx->codec->codec_id, unit->type, i)) { + if (ff_cbs_h2645_unit_requires_zero_byte(ctx->codec->codec_id, unit->type, i)) { // zero_byte data[dp++] = 0; } @@ -1904,441 +417,3 @@ static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, return 0; } - -static void cbs_h264_flush(CodedBitstreamContext *ctx) -{ - CodedBitstreamH264Context *h264 = ctx->priv_data; - - for (int i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) - ff_refstruct_unref(&h264->sps[i]); - for (int i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) - ff_refstruct_unref(&h264->pps[i]); - - h264->active_sps = NULL; - h264->active_pps = NULL; - h264->last_slice_nal_unit_type = 0; -} - -static void cbs_h264_close(CodedBitstreamContext *ctx) -{ - CodedBitstreamH264Context *h264 = ctx->priv_data; - int i; - - ff_h2645_packet_uninit(&h264->common.read_packet); - - for (i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) - ff_refstruct_unref(&h264->sps[i]); - for (i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) - ff_refstruct_unref(&h264->pps[i]); -} - -static void cbs_h265_flush(CodedBitstreamContext *ctx) -{ - CodedBitstreamH265Context *h265 = ctx->priv_data; - - for (int i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) - ff_refstruct_unref(&h265->vps[i]); - for (int i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) - ff_refstruct_unref(&h265->sps[i]); - for (int i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) - ff_refstruct_unref(&h265->pps[i]); - - h265->active_vps = NULL; - h265->active_sps = NULL; - h265->active_pps = NULL; -} - -static void cbs_h265_close(CodedBitstreamContext *ctx) -{ - CodedBitstreamH265Context *h265 = ctx->priv_data; - int i; - - ff_h2645_packet_uninit(&h265->common.read_packet); - - for (i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) - ff_refstruct_unref(&h265->vps[i]); - for (i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) - ff_refstruct_unref(&h265->sps[i]); - for (i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) - ff_refstruct_unref(&h265->pps[i]); -} - -static void cbs_h266_flush(CodedBitstreamContext *ctx) -{ - CodedBitstreamH266Context *h266 = ctx->priv_data; - - for (int i = 0; i < FF_ARRAY_ELEMS(h266->vps); i++) - ff_refstruct_unref(&h266->vps[i]); - for (int i = 0; i < FF_ARRAY_ELEMS(h266->sps); i++) - ff_refstruct_unref(&h266->sps[i]); - for (int i = 0; i < FF_ARRAY_ELEMS(h266->pps); i++) - ff_refstruct_unref(&h266->pps[i]); - ff_refstruct_unref(&h266->ph_ref); -} - -static void cbs_h266_close(CodedBitstreamContext *ctx) -{ - CodedBitstreamH266Context *h266 = ctx->priv_data; - - cbs_h266_flush(ctx); - ff_h2645_packet_uninit(&h266->common.read_packet); - } - -static void cbs_h264_free_sei(FFRefStructOpaque unused, void *content) -{ - H264RawSEI *sei = content; - ff_cbs_sei_free_message_list(&sei->message_list); -} - -static const CodedBitstreamUnitTypeDescriptor cbs_h264_unit_types[] = { - CBS_UNIT_TYPE_POD(H264_NAL_SPS, H264RawSPS), - CBS_UNIT_TYPE_POD(H264_NAL_SPS_EXT, H264RawSPSExtension), - - CBS_UNIT_TYPE_INTERNAL_REF(H264_NAL_PPS, H264RawPPS, slice_group_id), - - CBS_UNIT_TYPES_INTERNAL_REF((H264_NAL_IDR_SLICE, - H264_NAL_SLICE, - H264_NAL_AUXILIARY_SLICE), H264RawSlice, data), - - CBS_UNIT_TYPE_POD(H264_NAL_AUD, H264RawAUD), - CBS_UNIT_TYPE_POD(H264_NAL_FILLER_DATA, H264RawFiller), - CBS_UNIT_TYPE_POD(H264_NAL_END_SEQUENCE, H264RawNALUnitHeader), - CBS_UNIT_TYPE_POD(H264_NAL_END_STREAM, H264RawNALUnitHeader), - - CBS_UNIT_TYPE_COMPLEX(H264_NAL_SEI, H264RawSEI, &cbs_h264_free_sei), - - CBS_UNIT_TYPE_END_OF_LIST -}; - -static void cbs_h265_free_sei(FFRefStructOpaque unused, void *content) -{ - H265RawSEI *sei = content; - ff_cbs_sei_free_message_list(&sei->message_list); -} - -static const CodedBitstreamUnitTypeDescriptor cbs_h265_unit_types[] = { - CBS_UNIT_TYPE_INTERNAL_REF(HEVC_NAL_VPS, H265RawVPS, extension_data.data), - CBS_UNIT_TYPE_INTERNAL_REF(HEVC_NAL_SPS, H265RawSPS, extension_data.data), - CBS_UNIT_TYPE_INTERNAL_REF(HEVC_NAL_PPS, H265RawPPS, extension_data.data), - - CBS_UNIT_TYPE_POD(HEVC_NAL_AUD, H265RawAUD), - CBS_UNIT_TYPE_POD(HEVC_NAL_FD_NUT, H265RawFiller), - - // Slices of non-IRAP pictures. - CBS_UNIT_RANGE_INTERNAL_REF(HEVC_NAL_TRAIL_N, HEVC_NAL_RASL_R, - H265RawSlice, data), - // Slices of IRAP pictures. - CBS_UNIT_RANGE_INTERNAL_REF(HEVC_NAL_BLA_W_LP, HEVC_NAL_CRA_NUT, - H265RawSlice, data), - - CBS_UNIT_TYPES_COMPLEX((HEVC_NAL_SEI_PREFIX, HEVC_NAL_SEI_SUFFIX), - H265RawSEI, cbs_h265_free_sei), - - CBS_UNIT_TYPE_END_OF_LIST -}; - -static void cbs_h266_free_sei(FFRefStructOpaque unused, void *content) -{ - H266RawSEI *sei = content; - ff_cbs_sei_free_message_list(&sei->message_list); -} - -static const CodedBitstreamUnitTypeDescriptor cbs_h266_unit_types[] = { - CBS_UNIT_TYPE_INTERNAL_REF(VVC_DCI_NUT, H266RawDCI, extension_data.data), - CBS_UNIT_TYPE_INTERNAL_REF(VVC_OPI_NUT, H266RawOPI, extension_data.data), - CBS_UNIT_TYPE_INTERNAL_REF(VVC_VPS_NUT, H266RawVPS, extension_data.data), - { - .nb_unit_types = 1, - .unit_type.list[0] = VVC_SPS_NUT, - .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, - .content_size = sizeof(H266RawSPS), - .type.ref = { - .nb_offsets = 2, - .offsets = { offsetof(H266RawSPS, extension_data.data), - offsetof(H266RawSPS, vui.extension_data.data) } - }, - }, - CBS_UNIT_TYPE_INTERNAL_REF(VVC_PPS_NUT, H266RawPPS, extension_data.data), - CBS_UNIT_TYPE_INTERNAL_REF(VVC_PREFIX_APS_NUT, H266RawAPS, extension_data.data), - CBS_UNIT_TYPE_INTERNAL_REF(VVC_SUFFIX_APS_NUT, H266RawAPS, extension_data.data), - - CBS_UNIT_TYPE_POD(VVC_PH_NUT , H266RawPH), - CBS_UNIT_TYPE_POD(VVC_AUD_NUT, H266RawAUD), - - CBS_UNIT_RANGE_INTERNAL_REF(VVC_TRAIL_NUT, VVC_RASL_NUT, - H266RawSlice, data), - - CBS_UNIT_RANGE_INTERNAL_REF(VVC_IDR_W_RADL, VVC_GDR_NUT, - H266RawSlice, data), - - CBS_UNIT_TYPES_COMPLEX((VVC_PREFIX_SEI_NUT, VVC_SUFFIX_SEI_NUT), - H266RawSEI, cbs_h266_free_sei), - - CBS_UNIT_TYPE_END_OF_LIST -}; - -const CodedBitstreamType ff_cbs_type_h264 = { - .codec_id = AV_CODEC_ID_H264, - - .priv_data_size = sizeof(CodedBitstreamH264Context), - - .unit_types = cbs_h264_unit_types, - - .split_fragment = &cbs_h2645_split_fragment, - .read_unit = &cbs_h264_read_nal_unit, - .write_unit = &cbs_h264_write_nal_unit, - .discarded_unit = &cbs_h264_discarded_nal_unit, - .assemble_fragment = &cbs_h2645_assemble_fragment, - - .flush = &cbs_h264_flush, - .close = &cbs_h264_close, -}; - -const CodedBitstreamType ff_cbs_type_h265 = { - .codec_id = AV_CODEC_ID_HEVC, - - .priv_data_size = sizeof(CodedBitstreamH265Context), - - .unit_types = cbs_h265_unit_types, - - .split_fragment = &cbs_h2645_split_fragment, - .read_unit = &cbs_h265_read_nal_unit, - .write_unit = &cbs_h265_write_nal_unit, - .discarded_unit = &cbs_h265_discarded_nal_unit, - .assemble_fragment = &cbs_h2645_assemble_fragment, - - .flush = &cbs_h265_flush, - .close = &cbs_h265_close, -}; - -const CodedBitstreamType ff_cbs_type_h266 = { - .codec_id = AV_CODEC_ID_VVC, - - .priv_data_size = sizeof(CodedBitstreamH266Context), - - .unit_types = cbs_h266_unit_types, - - .split_fragment = &cbs_h2645_split_fragment, - .read_unit = &cbs_h266_read_nal_unit, - .write_unit = &cbs_h266_write_nal_unit, - .assemble_fragment = &cbs_h2645_assemble_fragment, - - .flush = &cbs_h266_flush, - .close = &cbs_h266_close, -}; - -// Macro for the read/write pair. -#define SEI_MESSAGE_RW(codec, name) \ - .read = cbs_ ## codec ## _read_ ## name ## _internal, \ - .write = cbs_ ## codec ## _write_ ## name ## _internal - -static const SEIMessageTypeDescriptor cbs_sei_common_types[] = { - { - SEI_TYPE_FILLER_PAYLOAD, - 1, 1, - sizeof(SEIRawFillerPayload), - SEI_MESSAGE_RW(sei, filler_payload), - }, - { - SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35, - 1, 1, - sizeof(SEIRawUserDataRegistered), - SEI_MESSAGE_RW(sei, user_data_registered), - }, - { - SEI_TYPE_USER_DATA_UNREGISTERED, - 1, 1, - sizeof(SEIRawUserDataUnregistered), - SEI_MESSAGE_RW(sei, user_data_unregistered), - }, - { - SEI_TYPE_FRAME_PACKING_ARRANGEMENT, - 1, 0, - sizeof(SEIRawFramePackingArrangement), - SEI_MESSAGE_RW(sei, frame_packing_arrangement), - }, - { - SEI_TYPE_DECODED_PICTURE_HASH, - 0, 1, - sizeof(SEIRawDecodedPictureHash), - SEI_MESSAGE_RW(sei, decoded_picture_hash), - }, - { - SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME, - 1, 0, - sizeof(SEIRawMasteringDisplayColourVolume), - SEI_MESSAGE_RW(sei, mastering_display_colour_volume), - }, - { - SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO, - 1, 0, - sizeof(SEIRawContentLightLevelInfo), - SEI_MESSAGE_RW(sei, content_light_level_info), - }, - { - SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS, - 1, 0, - sizeof(SEIRawAlternativeTransferCharacteristics), - SEI_MESSAGE_RW(sei, alternative_transfer_characteristics), - }, - { - SEI_TYPE_AMBIENT_VIEWING_ENVIRONMENT, - 1, 0, - sizeof(SEIRawAmbientViewingEnvironment), - SEI_MESSAGE_RW(sei, ambient_viewing_environment), - }, - SEI_MESSAGE_TYPE_END, -}; - -static const SEIMessageTypeDescriptor cbs_sei_h264_types[] = { - { - SEI_TYPE_BUFFERING_PERIOD, - 1, 0, - sizeof(H264RawSEIBufferingPeriod), - SEI_MESSAGE_RW(h264, sei_buffering_period), - }, - { - SEI_TYPE_PIC_TIMING, - 1, 0, - sizeof(H264RawSEIPicTiming), - SEI_MESSAGE_RW(h264, sei_pic_timing), - }, - { - SEI_TYPE_PAN_SCAN_RECT, - 1, 0, - sizeof(H264RawSEIPanScanRect), - SEI_MESSAGE_RW(h264, sei_pan_scan_rect), - }, - { - SEI_TYPE_RECOVERY_POINT, - 1, 0, - sizeof(H264RawSEIRecoveryPoint), - SEI_MESSAGE_RW(h264, sei_recovery_point), - }, - { - SEI_TYPE_FILM_GRAIN_CHARACTERISTICS, - 1, 0, - sizeof(H264RawFilmGrainCharacteristics), - SEI_MESSAGE_RW(h264, film_grain_characteristics), - }, - { - SEI_TYPE_FRAME_PACKING_ARRANGEMENT, - 1, 0, - sizeof(H264RawSEIFramePackingArrangement), - SEI_MESSAGE_RW(h264, sei_frame_packing_arrangement), - }, - { - SEI_TYPE_DISPLAY_ORIENTATION, - 1, 0, - sizeof(H264RawSEIDisplayOrientation), - SEI_MESSAGE_RW(h264, sei_display_orientation), - }, - SEI_MESSAGE_TYPE_END -}; - -static const SEIMessageTypeDescriptor cbs_sei_h265_types[] = { - { - SEI_TYPE_BUFFERING_PERIOD, - 1, 0, - sizeof(H265RawSEIBufferingPeriod), - SEI_MESSAGE_RW(h265, sei_buffering_period), - }, - { - SEI_TYPE_PIC_TIMING, - 1, 0, - sizeof(H265RawSEIPicTiming), - SEI_MESSAGE_RW(h265, sei_pic_timing), - }, - { - SEI_TYPE_PAN_SCAN_RECT, - 1, 0, - sizeof(H265RawSEIPanScanRect), - SEI_MESSAGE_RW(h265, sei_pan_scan_rect), - }, - { - SEI_TYPE_RECOVERY_POINT, - 1, 0, - sizeof(H265RawSEIRecoveryPoint), - SEI_MESSAGE_RW(h265, sei_recovery_point), - }, - { - SEI_TYPE_FILM_GRAIN_CHARACTERISTICS, - 1, 0, - sizeof(H265RawFilmGrainCharacteristics), - SEI_MESSAGE_RW(h265, film_grain_characteristics), - }, - { - SEI_TYPE_DISPLAY_ORIENTATION, - 1, 0, - sizeof(H265RawSEIDisplayOrientation), - SEI_MESSAGE_RW(h265, sei_display_orientation), - }, - { - SEI_TYPE_ACTIVE_PARAMETER_SETS, - 1, 0, - sizeof(H265RawSEIActiveParameterSets), - SEI_MESSAGE_RW(h265, sei_active_parameter_sets), - }, - { - SEI_TYPE_DECODED_PICTURE_HASH, - 0, 1, - sizeof(H265RawSEIDecodedPictureHash), - SEI_MESSAGE_RW(h265, sei_decoded_picture_hash), - }, - { - SEI_TYPE_TIME_CODE, - 1, 0, - sizeof(H265RawSEITimeCode), - SEI_MESSAGE_RW(h265, sei_time_code), - }, - { - SEI_TYPE_ALPHA_CHANNEL_INFO, - 1, 0, - sizeof(H265RawSEIAlphaChannelInfo), - SEI_MESSAGE_RW(h265, sei_alpha_channel_info), - }, - { - SEI_TYPE_THREE_DIMENSIONAL_REFERENCE_DISPLAYS_INFO, - 1, 0, - sizeof(H265RawSEI3DReferenceDisplaysInfo), - SEI_MESSAGE_RW(h265, sei_3d_reference_displays_info), - }, - SEI_MESSAGE_TYPE_END -}; - -static const SEIMessageTypeDescriptor cbs_sei_h266_types[] = { - SEI_MESSAGE_TYPE_END -}; - -const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx, - int payload_type) -{ - const SEIMessageTypeDescriptor *codec_list; - int i; - - switch (ctx->codec->codec_id) { - case AV_CODEC_ID_H264: - codec_list = cbs_sei_h264_types; - break; - case AV_CODEC_ID_H265: - codec_list = cbs_sei_h265_types; - break; - case AV_CODEC_ID_H266: - codec_list = cbs_sei_h266_types; - break; - default: - return NULL; - } - - for (i = 0; codec_list[i].type >= 0; i++) { - if (codec_list[i].type == payload_type) - return &codec_list[i]; - } - - for (i = 0; cbs_sei_common_types[i].type >= 0; i++) { - if (cbs_sei_common_types[i].type == payload_type) - return &cbs_sei_common_types[i]; - } - - return NULL; -} diff --git a/libavcodec/cbs_h2645.h b/libavcodec/cbs_h2645.h index f4c987a51..2d117ae3e 100644 --- a/libavcodec/cbs_h2645.h +++ b/libavcodec/cbs_h2645.h @@ -19,6 +19,7 @@ #ifndef AVCODEC_CBS_H2645_H #define AVCODEC_CBS_H2645_H +#include "cbs.h" #include "h2645_parse.h" @@ -32,5 +33,48 @@ typedef struct CodedBitstreamH2645Context { H2645Packet read_packet; } CodedBitstreamH2645Context; +struct GetBitContext; +struct PutBitContext; + +int ff_cbs_read_ue_golomb(CodedBitstreamContext *ctx, struct GetBitContext *gbc, + const char *name, const int *subscripts, + uint32_t *write_to, + uint32_t range_min, uint32_t range_max); +int ff_cbs_read_se_golomb(CodedBitstreamContext *ctx, struct GetBitContext *gbc, + const char *name, const int *subscripts, + int32_t *write_to, + int32_t range_min, int32_t range_max); +int ff_cbs_write_ue_golomb(CodedBitstreamContext *ctx, struct PutBitContext *pbc, + const char *name, const int *subscripts, + uint32_t value, + uint32_t range_min, uint32_t range_max); +int ff_cbs_write_se_golomb(CodedBitstreamContext *ctx, struct PutBitContext *pbc, + const char *name, const int *subscripts, + int32_t value, + int32_t range_min, int32_t range_max); + +int ff_cbs_h2645_read_more_rbsp_data(struct GetBitContext *gbc); + +int ff_cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const H2645Packet *packet); + +int ff_cbs_h2645_write_slice_data(CodedBitstreamContext *ctx, + struct PutBitContext *pbc, const uint8_t *data, + size_t data_size, int data_bit_start); + +int ff_cbs_h2645_unit_requires_zero_byte(enum AVCodecID codec_id, + CodedBitstreamUnitType type, + int nal_unit_index); + +int ff_cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); + +/** + * payload_extension_present() - true if we are before the last 1-bit + * in the payload structure, which must be in the last byte. + */ +int ff_cbs_h2645_payload_extension_present(struct GetBitContext *gbc, uint32_t payload_size, + int cur_pos); #endif /* AVCODEC_CBS_H2645_H */ diff --git a/libavcodec/cbs_h265.c b/libavcodec/cbs_h265.c new file mode 100644 index 000000000..21df609d0 --- /dev/null +++ b/libavcodec/cbs_h265.c @@ -0,0 +1,828 @@ +/* + * 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/mem.h" +#include "libavutil/refstruct.h" +#include "bytestream.h" +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_h2645.h" +#include "cbs_h265.h" +#include "cbs_sei.h" +#include "get_bits.h" + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME2(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_NAME1(rw, codec, name) FUNC_NAME2(rw, codec, name) +#define FUNC_H265(name) FUNC_NAME1(READWRITE, h265, name) +#define FUNC_NAME2_EXPORT(rw, codec, name) ff_cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_NAME1_EXPORT(rw, codec, name) FUNC_NAME2_EXPORT(rw, codec, name) +#define FUNC_SEI(name) FUNC_NAME1_EXPORT(READWRITE, sei, name) + +#define SEI_FUNC(name, args) \ +static int FUNC_H265(name) args; \ +static int FUNC_H265(name ## _internal)(CodedBitstreamContext *ctx, \ + RWContext *rw, void *cur, \ + SEIMessageState *state) \ +{ \ + return FUNC_H265(name)(ctx, rw, cur, state); \ +} \ +static int FUNC_H265(name) args + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max, 0, ) +#define flag(name) ub(1, name) +#define ue(name, range_min, range_max) \ + xue(name, current->name, range_min, range_max, 0, ) +#define i(width, name, range_min, range_max) \ + xi(width, name, current->name, range_min, range_max, 0, ) +#define ib(width, name) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), 0, ) +#define se(name, range_min, range_max) \ + xse(name, current->name, range_min, range_max, 0, ) + +#define us(width, name, range_min, range_max, subs, ...) \ + xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ubs(width, name, subs, ...) \ + xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define flags(name, subs, ...) \ + xu(1, name, current->name, 0, 1, subs, __VA_ARGS__) +#define ues(name, range_min, range_max, subs, ...) \ + xue(name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define is(width, name, range_min, range_max, subs, ...) \ + xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ibs(width, name, subs, ...) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__) +#define ses(name, range_min, range_max, subs, ...) \ + xse(name, current->name, range_min, range_max, subs, __VA_ARGS__) + +#define fixed(width, name, value) do { \ + av_unused uint32_t fixed_value = value; \ + xu(width, name, fixed_value, value, value, 0, ); \ + } while (0) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define ub(width, name) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \ + &value)); \ + current->name = value; \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xue(name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value; \ + CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ + int32_t value; \ + CHECK(ff_cbs_read_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) + + +#define infer(name, value) do { \ + current->name = value; \ + } while (0) + +#define more_rbsp_data(var) ((var) = ff_cbs_h2645_read_more_rbsp_data(rw)) + +#define bit_position(rw) (get_bits_count(rw)) +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + name ## _ref = av_buffer_allocz(size + \ + AV_INPUT_BUFFER_PADDING_SIZE); \ + if (!name ## _ref) \ + return AVERROR(ENOMEM); \ + name = name ## _ref->data; \ + } while (0) + +#define FUNC(name) FUNC_H265(name) +#include "cbs_h265_syntax_template.c" +#undef FUNC + + +#undef READ +#undef READWRITE +#undef RWContext +#undef ub +#undef xu +#undef xi +#undef xue +#undef xse +#undef infer +#undef more_rbsp_data +#undef bit_position +#undef byte_alignment +#undef allocate +#undef allocate_struct + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define ub(width, name) do { \ + uint32_t value = current->name; \ + CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \ + value)); \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xue(name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value = var; \ + CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ + int32_t value = var; \ + CHECK(ff_cbs_write_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) + +#define infer(name, value) do { \ + if (current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, \ + "%s does not match inferred value: " \ + "%"PRId64", but should be %"PRId64".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define more_rbsp_data(var) (var) + +#define bit_position(rw) (put_bits_count(rw)) +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + if (!name) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \ + "for writing.\n", #name); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define FUNC(name) FUNC_H265(name) +#include "cbs_h265_syntax_template.c" +#undef FUNC + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef ub +#undef xu +#undef xi +#undef xue +#undef xse +#undef u +#undef i +#undef flag +#undef ue +#undef se +#undef infer +#undef more_rbsp_data +#undef bit_position +#undef byte_alignment +#undef allocate + + + +static int cbs_h265_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + enum AVCodecID codec_id = ctx->codec->codec_id; + CodedBitstreamH265Context *priv = ctx->priv_data; + CodedBitstreamH2645Context *h2645 = &priv->common; + GetByteContext gbc; + int err; + + av_assert0(frag->data && frag->nb_units == 0); + if (frag->data_size == 0) + return 0; + + if (header && frag->data[0]) { + // HVCC header. + size_t size, start, end; + int i, j, nb_arrays, nal_unit_type, nb_nals, version; + + h2645->mp4 = 1; + + bytestream2_init(&gbc, frag->data, frag->data_size); + + if (bytestream2_get_bytes_left(&gbc) < 23) + return AVERROR_INVALIDDATA; + + version = bytestream2_get_byte(&gbc); + if (version != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid HVCC header: " + "first byte %u.\n", version); + return AVERROR_INVALIDDATA; + } + + bytestream2_skip(&gbc, 20); + h2645->nal_length_size = (bytestream2_get_byte(&gbc) & 3) + 1; + + nb_arrays = bytestream2_get_byte(&gbc); + for (i = 0; i < nb_arrays; i++) { + nal_unit_type = bytestream2_get_byte(&gbc) & 0x3f; + nb_nals = bytestream2_get_be16(&gbc); + + start = bytestream2_tell(&gbc); + for (j = 0; j < nb_nals; j++) { + if (bytestream2_get_bytes_left(&gbc) < 2) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if (bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&h2645->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 2, AV_CODEC_ID_HEVC, + H2645_FLAG_IS_NALFF | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split " + "HVCC array %d (%d NAL units of type %d).\n", + i, nb_nals, nal_unit_type); + return err; + } + err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet); + if (err < 0) + return err; + } + } else { + int flags = (H2645_FLAG_IS_NALFF * !!h2645->mp4) | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF; + // Annex B, or later MP4 with already-known parameters. + + err = ff_h2645_packet_split(&h2645->read_packet, + frag->data, frag->data_size, + ctx->log_ctx, + h2645->nal_length_size, + codec_id, flags); + if (err < 0) + return err; + + err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet); + if (err < 0) + return err; + } + + return 0; +} + +#define cbs_h2645_replace_ps(ps_name, ps_var, id_element) \ +static int cbs_h265_replace_ ## ps_var(CodedBitstreamContext *ctx, \ + CodedBitstreamUnit *unit) \ +{ \ + CodedBitstreamH265Context *priv = ctx->priv_data; \ + H265Raw## ps_name *ps_var = unit->content; \ + unsigned int id = ps_var->id_element; \ + int err = ff_cbs_make_unit_refcounted(ctx, unit); \ + if (err < 0) \ + return err; \ + if (priv->ps_var[id] == priv->active_ ## ps_var) \ + priv->active_ ## ps_var = NULL ; \ + av_assert0(unit->content_ref); \ + av_refstruct_replace(&priv->ps_var[id], unit->content_ref); \ + return 0; \ +} + +cbs_h2645_replace_ps(VPS, vps, vps_video_parameter_set_id) +cbs_h2645_replace_ps(SPS, sps, sps_seq_parameter_set_id) +cbs_h2645_replace_ps(PPS, pps, pps_pic_parameter_set_id) + +static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + err = ff_cbs_alloc_unit_content(ctx, unit); + if (err < 0) + return err; + + switch (unit->type) { + case HEVC_NAL_VPS: + { + H265RawVPS *vps = unit->content; + + err = cbs_h265_read_vps(ctx, &gbc, vps); + if (err < 0) + return err; + + err = cbs_h265_replace_vps(ctx, unit); + if (err < 0) + return err; + } + break; + case HEVC_NAL_SPS: + { + H265RawSPS *sps = unit->content; + + err = cbs_h265_read_sps(ctx, &gbc, sps); + if (err < 0) + return err; + + err = cbs_h265_replace_sps(ctx, unit); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_PPS: + { + H265RawPPS *pps = unit->content; + + err = cbs_h265_read_pps(ctx, &gbc, pps); + if (err < 0) + return err; + + err = cbs_h265_replace_pps(ctx, unit); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TRAIL_R: + case HEVC_NAL_TSA_N: + case HEVC_NAL_TSA_R: + case HEVC_NAL_STSA_N: + case HEVC_NAL_STSA_R: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + case HEVC_NAL_BLA_W_LP: + case HEVC_NAL_BLA_W_RADL: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_W_RADL: + case HEVC_NAL_IDR_N_LP: + case HEVC_NAL_CRA_NUT: + { + H265RawSlice *slice = unit->content; + int pos, len; + + err = cbs_h265_read_slice_segment_header(ctx, &gbc, &slice->header); + if (err < 0) + return err; + + if (!ff_cbs_h2645_read_more_rbsp_data(&gbc)) + return AVERROR_INVALIDDATA; + + pos = get_bits_count(&gbc); + len = unit->data_size; + + slice->data_size = len - pos / 8; + slice->data_ref = av_buffer_ref(unit->data_ref); + if (!slice->data_ref) + return AVERROR(ENOMEM); + slice->data = unit->data + pos / 8; + slice->data_bit_start = pos % 8; + } + break; + + case HEVC_NAL_AUD: + { + err = cbs_h265_read_aud(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_FD_NUT: + { + err = cbs_h265_read_filler(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_SEI_PREFIX: + case HEVC_NAL_SEI_SUFFIX: + { + err = cbs_h265_read_sei(ctx, &gbc, unit->content, + unit->type == HEVC_NAL_SEI_PREFIX); + + if (err < 0) + return err; + } + break; + + default: + return AVERROR(ENOSYS); + } + + return 0; +} + +static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + switch (unit->type) { + case HEVC_NAL_VPS: + { + H265RawVPS *vps = unit->content; + + err = cbs_h265_write_vps(ctx, pbc, vps); + if (err < 0) + return err; + + err = cbs_h265_replace_vps(ctx, unit); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_SPS: + { + H265RawSPS *sps = unit->content; + + err = cbs_h265_write_sps(ctx, pbc, sps); + if (err < 0) + return err; + + err = cbs_h265_replace_sps(ctx, unit); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_PPS: + { + H265RawPPS *pps = unit->content; + + err = cbs_h265_write_pps(ctx, pbc, pps); + if (err < 0) + return err; + + err = cbs_h265_replace_pps(ctx, unit); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TRAIL_R: + case HEVC_NAL_TSA_N: + case HEVC_NAL_TSA_R: + case HEVC_NAL_STSA_N: + case HEVC_NAL_STSA_R: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + case HEVC_NAL_BLA_W_LP: + case HEVC_NAL_BLA_W_RADL: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_W_RADL: + case HEVC_NAL_IDR_N_LP: + case HEVC_NAL_CRA_NUT: + { + H265RawSlice *slice = unit->content; + + err = cbs_h265_write_slice_segment_header(ctx, pbc, &slice->header); + if (err < 0) + return err; + + if (slice->data) { + err = ff_cbs_h2645_write_slice_data(ctx, pbc, slice->data, + slice->data_size, + slice->data_bit_start); + if (err < 0) + return err; + } else { + // No slice data - that was just the header. + } + } + break; + + case HEVC_NAL_AUD: + { + err = cbs_h265_write_aud(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_FD_NUT: + { + err = cbs_h265_write_filler(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_SEI_PREFIX: + case HEVC_NAL_SEI_SUFFIX: + { + err = cbs_h265_write_sei(ctx, pbc, unit->content, + unit->type == HEVC_NAL_SEI_PREFIX); + + if (err < 0) + return err; + } + break; + + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " + "NAL unit type %"PRIu32".\n", unit->type); + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int cbs_h265_discarded_nal_unit(CodedBitstreamContext *ctx, + const CodedBitstreamUnit *unit, + enum AVDiscard skip) +{ + H265RawSliceHeader *slice; + + if (skip <= AVDISCARD_DEFAULT) + return 0; + + switch (unit->type) { + case HEVC_NAL_BLA_W_LP: + case HEVC_NAL_BLA_W_RADL: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_W_RADL: + case HEVC_NAL_IDR_N_LP: + case HEVC_NAL_CRA_NUT: + // IRAP slice + if (skip < AVDISCARD_ALL) + return 0; + break; + + case HEVC_NAL_TRAIL_R: + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TSA_N: + case HEVC_NAL_TSA_R: + case HEVC_NAL_STSA_N: + case HEVC_NAL_STSA_R: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + // Slice + break; + default: + // Don't discard non-slice nal. + return 0; + } + + if (skip >= AVDISCARD_NONKEY) + return 1; + + slice = (H265RawSliceHeader *)unit->content; + if (!slice) { + av_log(ctx->log_ctx, AV_LOG_WARNING, + "h265 slice header is null, missing decompose?\n"); + return 0; + } + + if (skip >= AVDISCARD_NONINTRA && slice->slice_type != HEVC_SLICE_I) + return 1; + if (skip >= AVDISCARD_BIDIR && slice->slice_type == HEVC_SLICE_B) + return 1; + + if (skip >= AVDISCARD_NONREF) { + switch (unit->type) { + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TSA_N: + case HEVC_NAL_STSA_N: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RASL_N: + case HEVC_NAL_VCL_N10: + case HEVC_NAL_VCL_N12: + case HEVC_NAL_VCL_N14: + // non-ref + return 1; + default: + break; + } + } + + return 0; +} + +static av_cold void cbs_h265_flush(CodedBitstreamContext *ctx) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + + for (int i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) + av_refstruct_unref(&h265->vps[i]); + for (int i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) + av_refstruct_unref(&h265->sps[i]); + for (int i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) + av_refstruct_unref(&h265->pps[i]); + + h265->active_vps = NULL; + h265->active_sps = NULL; + h265->active_pps = NULL; +} + +static av_cold void cbs_h265_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + int i; + + ff_h2645_packet_uninit(&h265->common.read_packet); + + for (i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) + av_refstruct_unref(&h265->vps[i]); + for (i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) + av_refstruct_unref(&h265->sps[i]); + for (i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) + av_refstruct_unref(&h265->pps[i]); +} + +static void cbs_h265_free_sei(AVRefStructOpaque unused, void *content) +{ + H265RawSEI *sei = content; + ff_cbs_sei_free_message_list(&sei->message_list); +} + +static CodedBitstreamUnitTypeDescriptor cbs_h265_unit_types[] = { + CBS_UNIT_TYPE_INTERNAL_REF(HEVC_NAL_VPS, H265RawVPS, extension_data.data), + CBS_UNIT_TYPE_INTERNAL_REF(HEVC_NAL_SPS, H265RawSPS, extension_data.data), + CBS_UNIT_TYPE_INTERNAL_REF(HEVC_NAL_PPS, H265RawPPS, extension_data.data), + + CBS_UNIT_TYPE_POD(HEVC_NAL_AUD, H265RawAUD), + CBS_UNIT_TYPE_POD(HEVC_NAL_FD_NUT, H265RawFiller), + + // Slices of non-IRAP pictures. + CBS_UNIT_RANGE_INTERNAL_REF(HEVC_NAL_TRAIL_N, HEVC_NAL_RASL_R, + H265RawSlice, data), + // Slices of IRAP pictures. + CBS_UNIT_RANGE_INTERNAL_REF(HEVC_NAL_BLA_W_LP, HEVC_NAL_CRA_NUT, + H265RawSlice, data), + + CBS_UNIT_TYPES_COMPLEX((HEVC_NAL_SEI_PREFIX, HEVC_NAL_SEI_SUFFIX), + H265RawSEI, cbs_h265_free_sei), + + CBS_UNIT_TYPE_END_OF_LIST +}; + +// Macro for the read/write pair. +#define SEI_MESSAGE_RW(codec, name) \ + .read = cbs_ ## codec ## _read_ ## name ## _internal, \ + .write = cbs_ ## codec ## _write_ ## name ## _internal + +const SEIMessageTypeDescriptor ff_cbs_sei_h265_types[] = { + { + SEI_TYPE_BUFFERING_PERIOD, + 1, 0, + sizeof(H265RawSEIBufferingPeriod), + SEI_MESSAGE_RW(h265, sei_buffering_period), + }, + { + SEI_TYPE_PIC_TIMING, + 1, 0, + sizeof(H265RawSEIPicTiming), + SEI_MESSAGE_RW(h265, sei_pic_timing), + }, + { + SEI_TYPE_PAN_SCAN_RECT, + 1, 0, + sizeof(H265RawSEIPanScanRect), + SEI_MESSAGE_RW(h265, sei_pan_scan_rect), + }, + { + SEI_TYPE_RECOVERY_POINT, + 1, 0, + sizeof(H265RawSEIRecoveryPoint), + SEI_MESSAGE_RW(h265, sei_recovery_point), + }, + { + SEI_TYPE_FILM_GRAIN_CHARACTERISTICS, + 1, 0, + sizeof(H265RawFilmGrainCharacteristics), + SEI_MESSAGE_RW(h265, film_grain_characteristics), + }, + { + SEI_TYPE_DISPLAY_ORIENTATION, + 1, 0, + sizeof(H265RawSEIDisplayOrientation), + SEI_MESSAGE_RW(h265, sei_display_orientation), + }, + { + SEI_TYPE_ACTIVE_PARAMETER_SETS, + 1, 0, + sizeof(H265RawSEIActiveParameterSets), + SEI_MESSAGE_RW(h265, sei_active_parameter_sets), + }, + { + SEI_TYPE_DECODED_PICTURE_HASH, + 0, 1, + sizeof(H265RawSEIDecodedPictureHash), + SEI_MESSAGE_RW(h265, sei_decoded_picture_hash), + }, + { + SEI_TYPE_TIME_CODE, + 1, 0, + sizeof(H265RawSEITimeCode), + SEI_MESSAGE_RW(h265, sei_time_code), + }, + { + SEI_TYPE_ALPHA_CHANNEL_INFO, + 1, 0, + sizeof(H265RawSEIAlphaChannelInfo), + SEI_MESSAGE_RW(h265, sei_alpha_channel_info), + }, + { + SEI_TYPE_THREE_DIMENSIONAL_REFERENCE_DISPLAYS_INFO, + 1, 0, + sizeof(H265RawSEI3DReferenceDisplaysInfo), + SEI_MESSAGE_RW(h265, sei_3d_reference_displays_info), + }, + SEI_MESSAGE_TYPE_END +}; + +const CodedBitstreamType ff_cbs_type_h265 = { + .codec_id = AV_CODEC_ID_HEVC, + + .priv_data_size = sizeof(CodedBitstreamH265Context), + + .unit_types = cbs_h265_unit_types, + + .split_fragment = &cbs_h265_split_fragment, + .read_unit = &cbs_h265_read_nal_unit, + .write_unit = &cbs_h265_write_nal_unit, + .discarded_unit = &cbs_h265_discarded_nal_unit, + .assemble_fragment = &ff_cbs_h2645_assemble_fragment, + + .flush = &cbs_h265_flush, + .close = &cbs_h265_close, +}; diff --git a/libavcodec/cbs_h265_syntax_template.c b/libavcodec/cbs_h265_syntax_template.c index e976c38b8..2842c4058 100644 --- a/libavcodec/cbs_h265_syntax_template.c +++ b/libavcodec/cbs_h265_syntax_template.c @@ -67,7 +67,7 @@ static int FUNC(extension_data)(CodedBitstreamContext *ctx, RWContext *rw, GetBitContext start; uint8_t bit; start = *rw; - for (k = 0; cbs_h2645_read_more_rbsp_data(rw); k++) + for (k = 0; ff_cbs_h2645_read_more_rbsp_data(rw); k++) skip_bits(rw, 1); current->bit_length = k; if (k > 0) { @@ -1915,7 +1915,7 @@ SEI_FUNC(sei_buffering_period, (CodedBitstreamContext *ctx, RWContext *rw, #ifdef READ end_pos = get_bits_count(rw); - if (cbs_h265_payload_extension_present(rw, sei->payload_size, + if (ff_cbs_h2645_payload_extension_present(rw, sei->payload_size, end_pos - start_pos)) flag(use_alt_cpb_params_flag); else diff --git a/libavcodec/cbs_h266.c b/libavcodec/cbs_h266.c new file mode 100644 index 000000000..8c92b4f55 --- /dev/null +++ b/libavcodec/cbs_h266.c @@ -0,0 +1,809 @@ +/* + * 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/intmath.h" +#include "libavutil/mem.h" +#include "libavutil/refstruct.h" +#include "bytestream.h" +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_h2645.h" +#include "cbs_h266.h" +#include "cbs_sei.h" +#include "get_bits.h" + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME2(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_NAME1(rw, codec, name) FUNC_NAME2(rw, codec, name) +#define FUNC_H266(name) FUNC_NAME1(READWRITE, h266, name) +#define FUNC_NAME2_EXPORT(rw, codec, name) ff_cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_NAME1_EXPORT(rw, codec, name) FUNC_NAME2_EXPORT(rw, codec, name) +#define FUNC_SEI(name) FUNC_NAME1_EXPORT(READWRITE, sei, name) + +#define SEI_FUNC(name, args) \ +static int FUNC_H266(name) args; \ +static int FUNC_H266(name ## _internal)(CodedBitstreamContext *ctx, \ + RWContext *rw, void *cur, \ + SEIMessageState *state) \ +{ \ + return FUNC_H266(name)(ctx, rw, cur, state); \ +} \ +static int FUNC_H266(name) args + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max, 0, ) +#define flag(name) ub(1, name) +#define ue(name, range_min, range_max) \ + xue(name, current->name, range_min, range_max, 0, ) +#define i(width, name, range_min, range_max) \ + xi(width, name, current->name, range_min, range_max, 0, ) +#define ib(width, name) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), 0, ) +#define se(name, range_min, range_max) \ + xse(name, current->name, range_min, range_max, 0, ) + +#define us(width, name, range_min, range_max, subs, ...) \ + xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ubs(width, name, subs, ...) \ + xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define flags(name, subs, ...) \ + xu(1, name, current->name, 0, 1, subs, __VA_ARGS__) +#define ues(name, range_min, range_max, subs, ...) \ + xue(name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define is(width, name, range_min, range_max, subs, ...) \ + xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ibs(width, name, subs, ...) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__) +#define ses(name, range_min, range_max, subs, ...) \ + xse(name, current->name, range_min, range_max, subs, __VA_ARGS__) + +#define fixed(width, name, value) do { \ + av_unused uint32_t fixed_value = value; \ + xu(width, name, fixed_value, value, value, 0, ); \ + } while (0) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define ub(width, name) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \ + &value)); \ + current->name = value; \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xue(name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value; \ + CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ + int32_t value; \ + CHECK(ff_cbs_read_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) + + +#define infer(name, value) do { \ + current->name = value; \ + } while (0) + +#define more_rbsp_data(var) ((var) = ff_cbs_h2645_read_more_rbsp_data(rw)) + +#define bit_position(rw) (get_bits_count(rw)) +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + name ## _ref = av_buffer_allocz(size + \ + AV_INPUT_BUFFER_PADDING_SIZE); \ + if (!name ## _ref) \ + return AVERROR(ENOMEM); \ + name = name ## _ref->data; \ + } while (0) + +#define FUNC(name) FUNC_H266(name) +#include "cbs_h266_syntax_template.c" +#undef FUNC + + +#undef READ +#undef READWRITE +#undef RWContext +#undef ub +#undef xu +#undef xi +#undef xue +#undef xse +#undef infer +#undef more_rbsp_data +#undef bit_position +#undef byte_alignment +#undef allocate +#undef allocate_struct + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define ub(width, name) do { \ + uint32_t value = current->name; \ + CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \ + value)); \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xue(name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value = var; \ + CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ + int32_t value = var; \ + CHECK(ff_cbs_write_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) + +#define infer(name, value) do { \ + if (current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, \ + "%s does not match inferred value: " \ + "%"PRId64", but should be %"PRId64".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define more_rbsp_data(var) (var) + +#define bit_position(rw) (put_bits_count(rw)) +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + if (!name) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \ + "for writing.\n", #name); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define FUNC(name) FUNC_H266(name) +#include "cbs_h266_syntax_template.c" +#undef FUNC + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef ub +#undef xu +#undef xi +#undef xue +#undef xse +#undef u +#undef i +#undef flag +#undef ue +#undef se +#undef infer +#undef more_rbsp_data +#undef bit_position +#undef byte_alignment +#undef allocate + + + +static int cbs_h266_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + enum AVCodecID codec_id = ctx->codec->codec_id; + CodedBitstreamH266Context *priv = ctx->priv_data; + CodedBitstreamH2645Context *h2645 = &priv->common; + GetByteContext gbc; + int err; + + av_assert0(frag->data && frag->nb_units == 0); + if (frag->data_size == 0) + return 0; + + if(header && frag->data[0]) { + // VVCC header. + int ptl_present_flag, num_arrays; + int b, i, j; + + h2645->mp4 = 1; + + bytestream2_init(&gbc, frag->data, frag->data_size); + + b = bytestream2_get_byte(&gbc); + h2645->nal_length_size = ((b >> 1) & 3) + 1; + ptl_present_flag = b & 1; + + if(ptl_present_flag) { + int num_sublayers, num_bytes_constraint_info, num_sub_profiles; + num_sublayers = (bytestream2_get_be16u(&gbc) >> 4) & 7; + bytestream2_skip(&gbc, 1); + + // begin VvcPTLRecord(num_sublayers); + num_bytes_constraint_info = bytestream2_get_byte(&gbc) & 0x3f; + bytestream2_skip(&gbc, 2 + num_bytes_constraint_info); + if(num_sublayers > 1) { + int count_present_flags = 0; + b = bytestream2_get_byte(&gbc); + for(i = num_sublayers - 2; i >= 0; i--) { + if((b >> (7 - (num_sublayers - 2 - i))) & 0x01) + count_present_flags++; + } + bytestream2_skip(&gbc, count_present_flags); + } + num_sub_profiles = bytestream2_get_byte(&gbc); + bytestream2_skip(&gbc, num_sub_profiles * 4); + // end VvcPTLRecord(num_sublayers); + + bytestream2_skip(&gbc, 3 * 2); + } + + num_arrays = bytestream2_get_byte(&gbc); + for(j = 0; j < num_arrays; j++) { + size_t start, end, size; + int nal_unit_type = bytestream2_get_byte(&gbc) & 0x1f; + unsigned int num_nalus = 1; + if(nal_unit_type != VVC_DCI_NUT && nal_unit_type != VVC_OPI_NUT) + num_nalus = bytestream2_get_be16(&gbc); + + start = bytestream2_tell(&gbc); + for(i = 0; i < num_nalus; i++) { + if (bytestream2_get_bytes_left(&gbc) < 2) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if (bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&h2645->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 2, AV_CODEC_ID_VVC, + H2645_FLAG_IS_NALFF | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split " + "VVCC array %d (%d NAL units of type %d).\n", + i, num_nalus, nal_unit_type); + return err; + } + err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet); + if (err < 0) + return err; + } + } else { + int flags = (H2645_FLAG_IS_NALFF * !!h2645->mp4) | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF; + // Annex B, or later MP4 with already-known parameters. + + err = ff_h2645_packet_split(&h2645->read_packet, + frag->data, frag->data_size, + ctx->log_ctx, + h2645->nal_length_size, + codec_id, flags); + if (err < 0) + return err; + + err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet); + if (err < 0) + return err; + } + + return 0; +} + +#define cbs_h266_replace_ps(ps_name, ps_var, id_element) \ +static int cbs_h266_replace_ ## ps_var(CodedBitstreamContext *ctx, \ + CodedBitstreamUnit *unit) \ +{ \ + CodedBitstreamH266Context *priv = ctx->priv_data; \ + H266Raw ## ps_name *ps_var = unit->content; \ + unsigned int id = ps_var->id_element; \ + int err = ff_cbs_make_unit_refcounted(ctx, unit); \ + if (err < 0) \ + return err; \ + av_assert0(unit->content_ref); \ + av_refstruct_replace(&priv->ps_var[id], unit->content_ref); \ + return 0; \ +} + +cbs_h266_replace_ps(VPS, vps, vps_video_parameter_set_id) +cbs_h266_replace_ps(PPS, pps, pps_pic_parameter_set_id) + +static int cbs_h266_replace_sps(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + CodedBitstreamH266Context *priv = ctx->priv_data; + H266RawSPS *sps = unit->content; + unsigned int id = sps->sps_seq_parameter_set_id; + int err = ff_cbs_make_unit_refcounted(ctx, unit); + if (err < 0) + return err; + av_assert0(unit->content_ref); + if (priv->sps[id] && memcmp(priv->sps[id], unit->content_ref, sizeof(*priv->sps[id]))) { + for (unsigned int i = 0; i < VVC_MAX_PPS_COUNT; i++) { + if (priv->pps[i] && priv->pps[i]->pps_seq_parameter_set_id == id) + av_refstruct_unref(&priv->pps[i]); + } + } + av_refstruct_replace(&priv->sps[id], unit->content_ref); + return 0; +} + +static int cbs_h266_replace_ph(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + H266RawPictureHeader *ph) +{ + CodedBitstreamH266Context *h266 = ctx->priv_data; + int err; + + err = ff_cbs_make_unit_refcounted(ctx, unit); + if (err < 0) + return err; + av_assert0(unit->content_ref); + av_refstruct_replace(&h266->ph_ref, unit->content_ref); + h266->ph = ph; + return 0; +} + +static int cbs_h266_read_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + CodedBitstreamH266Context *h266 = ctx->priv_data; + + err = init_get_bits8(&gbc, unit->data, unit->data_size); + if (err < 0) + return err; + + err = ff_cbs_alloc_unit_content(ctx, unit); + if (err < 0) + return err; + + switch (unit->type) { + case VVC_DCI_NUT: + { + err = cbs_h266_read_dci(ctx, &gbc, unit->content); + + if (err < 0) + return err; + } + break; + case VVC_OPI_NUT: + { + err = cbs_h266_read_opi(ctx, &gbc, unit->content); + + if (err < 0) + return err; + } + break; + case VVC_VPS_NUT: + { + H266RawVPS *vps = unit->content; + + err = cbs_h266_read_vps(ctx, &gbc, vps); + if (err < 0) + return err; + + err = cbs_h266_replace_vps(ctx, unit); + if (err < 0) + return err; + } + break; + case VVC_SPS_NUT: + { + H266RawSPS *sps = unit->content; + + err = cbs_h266_read_sps(ctx, &gbc, sps); + if (err < 0) + return err; + + err = cbs_h266_replace_sps(ctx, unit); + if (err < 0) + return err; + } + break; + + case VVC_PPS_NUT: + { + H266RawPPS *pps = unit->content; + + err = cbs_h266_read_pps(ctx, &gbc, pps); + if (err < 0) + return err; + + err = cbs_h266_replace_pps(ctx, unit); + if (err < 0) + return err; + } + break; + + case VVC_PREFIX_APS_NUT: + case VVC_SUFFIX_APS_NUT: + { + err = cbs_h266_read_aps(ctx, &gbc, unit->content, + unit->type == VVC_PREFIX_APS_NUT); + + if (err < 0) + return err; + } + break; + case VVC_PH_NUT: + { + H266RawPH *ph = unit->content; + err = cbs_h266_read_ph(ctx, &gbc, ph); + if (err < 0) + return err; + err = cbs_h266_replace_ph(ctx, unit, &ph->ph_picture_header); + if (err < 0) + return err; + } + break; + + case VVC_TRAIL_NUT: + case VVC_STSA_NUT: + case VVC_RADL_NUT: + case VVC_RASL_NUT: + case VVC_IDR_W_RADL: + case VVC_IDR_N_LP: + case VVC_CRA_NUT: + case VVC_GDR_NUT: + { + H266RawSlice *slice = unit->content; + int pos, len; + + err = cbs_h266_read_slice_header(ctx, &gbc, &slice->header); + if (err < 0) + return err; + + if (!ff_cbs_h2645_read_more_rbsp_data(&gbc)) + return AVERROR_INVALIDDATA; + + pos = get_bits_count(&gbc); + len = unit->data_size; + + if (slice->header.sh_picture_header_in_slice_header_flag) { + err = cbs_h266_replace_ph(ctx, unit, &slice->header.sh_picture_header); + if (err < 0) + return err; + slice->ph_ref = NULL; + } else { + slice->ph_ref = av_refstruct_ref(h266->ph_ref); + } + slice->ph = h266->ph; + slice->pps = av_refstruct_ref(h266->pps[slice->ph->ph_pic_parameter_set_id]); + slice->sps = av_refstruct_ref(h266->sps[slice->pps->pps_seq_parameter_set_id]); + + slice->header_size = pos / 8; + slice->data_size = len - pos / 8; + slice->data_ref = av_buffer_ref(unit->data_ref); + if (!slice->data_ref) + return AVERROR(ENOMEM); + slice->data = unit->data + pos / 8; + slice->data_bit_start = pos % 8; + } + break; + + case VVC_AUD_NUT: + { + err = cbs_h266_read_aud(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + case VVC_PREFIX_SEI_NUT: + case VVC_SUFFIX_SEI_NUT: + { + err = cbs_h266_read_sei(ctx, &gbc, unit->content, + unit->type == VVC_PREFIX_SEI_NUT); + + if (err < 0) + return err; + } + break; + + default: + return AVERROR(ENOSYS); + } + return 0; +} + +static int cbs_h266_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + switch (unit->type) { + case VVC_DCI_NUT: + { + H266RawDCI *dci = unit->content; + + err = cbs_h266_write_dci(ctx, pbc, dci); + if (err < 0) + return err; + } + break; + case VVC_OPI_NUT: + { + H266RawOPI *opi = unit->content; + + err = cbs_h266_write_opi(ctx, pbc, opi); + if (err < 0) + return err; + } + break; + case VVC_VPS_NUT: + { + H266RawVPS *vps = unit->content; + + err = cbs_h266_write_vps(ctx, pbc, vps); + if (err < 0) + return err; + + err = cbs_h266_replace_vps(ctx, unit); + if (err < 0) + return err; + } + break; + case VVC_SPS_NUT: + { + H266RawSPS *sps = unit->content; + + err = cbs_h266_write_sps(ctx, pbc, sps); + if (err < 0) + return err; + + err = cbs_h266_replace_sps(ctx, unit); + if (err < 0) + return err; + } + break; + + case VVC_PPS_NUT: + { + H266RawPPS *pps = unit->content; + + err = cbs_h266_write_pps(ctx, pbc, pps); + if (err < 0) + return err; + + err = cbs_h266_replace_pps(ctx, unit); + if (err < 0) + return err; + } + break; + + case VVC_PREFIX_APS_NUT: + case VVC_SUFFIX_APS_NUT: + { + err = cbs_h266_write_aps(ctx, pbc, unit->content, + unit->type == VVC_PREFIX_APS_NUT); + if (err < 0) + return err; + } + break; + case VVC_PH_NUT: + { + H266RawPH *ph = unit->content; + err = cbs_h266_write_ph(ctx, pbc, ph); + if (err < 0) + return err; + + err = cbs_h266_replace_ph(ctx, unit, &ph->ph_picture_header); + if (err < 0) + return err; + } + break; + + case VVC_TRAIL_NUT: + case VVC_STSA_NUT: + case VVC_RADL_NUT: + case VVC_RASL_NUT: + case VVC_IDR_W_RADL: + case VVC_IDR_N_LP: + case VVC_CRA_NUT: + case VVC_GDR_NUT: + { + H266RawSlice *slice = unit->content; + + err = cbs_h266_write_slice_header(ctx, pbc, &slice->header); + if (err < 0) + return err; + + if (slice->header.sh_picture_header_in_slice_header_flag) { + err = cbs_h266_replace_ph(ctx, unit, &slice->header.sh_picture_header); + if (err < 0) + return err; + } + + if (slice->data) { + err = ff_cbs_h2645_write_slice_data(ctx, pbc, slice->data, + slice->data_size, + slice->data_bit_start); + if (err < 0) + return err; + } else { + // No slice data - that was just the header. + } + } + break; + + case VVC_AUD_NUT: + { + err = cbs_h266_write_aud(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + case VVC_PREFIX_SEI_NUT: + case VVC_SUFFIX_SEI_NUT: + { + err = cbs_h266_write_sei(ctx, pbc, unit->content, + unit->type == VVC_PREFIX_SEI_NUT); + + if (err < 0) + return err; + } + break; + + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " + "NAL unit type %"PRIu32".\n", unit->type); + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static av_cold void cbs_h266_flush(CodedBitstreamContext *ctx) +{ + CodedBitstreamH266Context *h266 = ctx->priv_data; + + for (int i = 0; i < FF_ARRAY_ELEMS(h266->vps); i++) + av_refstruct_unref(&h266->vps[i]); + for (int i = 0; i < FF_ARRAY_ELEMS(h266->sps); i++) + av_refstruct_unref(&h266->sps[i]); + for (int i = 0; i < FF_ARRAY_ELEMS(h266->pps); i++) + av_refstruct_unref(&h266->pps[i]); + av_refstruct_unref(&h266->ph_ref); +} + +static av_cold void cbs_h266_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamH266Context *h266 = ctx->priv_data; + + cbs_h266_flush(ctx); + ff_h2645_packet_uninit(&h266->common.read_packet); +} + +static void cbs_h266_free_slice(AVRefStructOpaque unused, void *content) +{ + H266RawSlice *slice = content; + av_buffer_unref(&slice->data_ref); + av_refstruct_unref(&slice->sps); + av_refstruct_unref(&slice->pps); + av_refstruct_unref(&slice->ph_ref); +} + + +static void cbs_h266_free_sei(AVRefStructOpaque unused, void *content) +{ + H266RawSEI *sei = content; + ff_cbs_sei_free_message_list(&sei->message_list); +} + +static CodedBitstreamUnitTypeDescriptor cbs_h266_unit_types[] = { + CBS_UNIT_TYPE_INTERNAL_REF(VVC_DCI_NUT, H266RawDCI, extension_data.data), + CBS_UNIT_TYPE_INTERNAL_REF(VVC_OPI_NUT, H266RawOPI, extension_data.data), + CBS_UNIT_TYPE_INTERNAL_REF(VVC_VPS_NUT, H266RawVPS, extension_data.data), + { + .nb_unit_types = 1, + .unit_type.list[0] = VVC_SPS_NUT, + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, + .content_size = sizeof(H266RawSPS), + .type.ref = { + .nb_offsets = 2, + .offsets = { offsetof(H266RawSPS, extension_data.data), + offsetof(H266RawSPS, vui.extension_data.data) } + }, + }, + CBS_UNIT_TYPE_INTERNAL_REF(VVC_PPS_NUT, H266RawPPS, extension_data.data), + CBS_UNIT_TYPE_INTERNAL_REF(VVC_PREFIX_APS_NUT, H266RawAPS, extension_data.data), + CBS_UNIT_TYPE_INTERNAL_REF(VVC_SUFFIX_APS_NUT, H266RawAPS, extension_data.data), + + CBS_UNIT_TYPE_POD(VVC_PH_NUT , H266RawPH), + CBS_UNIT_TYPE_POD(VVC_AUD_NUT, H266RawAUD), + + CBS_UNIT_TYPES_COMPLEX((VVC_TRAIL_NUT, VVC_STSA_NUT, VVC_RADL_NUT), + H266RawSlice, cbs_h266_free_slice), + CBS_UNIT_TYPES_COMPLEX((VVC_RASL_NUT, VVC_IDR_W_RADL, VVC_IDR_N_LP), + H266RawSlice, cbs_h266_free_slice), + CBS_UNIT_TYPES_COMPLEX((VVC_CRA_NUT, VVC_GDR_NUT), + H266RawSlice, cbs_h266_free_slice), + + CBS_UNIT_TYPES_COMPLEX((VVC_PREFIX_SEI_NUT, VVC_SUFFIX_SEI_NUT), + H266RawSEI, cbs_h266_free_sei), + + CBS_UNIT_TYPE_END_OF_LIST +}; + +const CodedBitstreamType ff_cbs_type_h266 = { + .codec_id = AV_CODEC_ID_VVC, + + .priv_data_size = sizeof(CodedBitstreamH266Context), + + .unit_types = cbs_h266_unit_types, + + .split_fragment = &cbs_h266_split_fragment, + .read_unit = &cbs_h266_read_nal_unit, + .write_unit = &cbs_h266_write_nal_unit, + .assemble_fragment = &ff_cbs_h2645_assemble_fragment, + + .flush = &cbs_h266_flush, + .close = &cbs_h266_close, +}; diff --git a/libavcodec/cbs_h266.h b/libavcodec/cbs_h266.h index d24a8e931..8d851a0bf 100644 --- a/libavcodec/cbs_h266.h +++ b/libavcodec/cbs_h266.h @@ -593,6 +593,8 @@ typedef struct H266RawPPS { uint16_t sub_pic_id_val[VVC_MAX_SLICES]; ///< SubpicIdVal uint16_t col_width_val[VVC_MAX_TILE_COLUMNS]; ///< ColWidthVal uint16_t row_height_val[VVC_MAX_TILE_ROWS]; ///< RowHeightVal + uint16_t slice_top_left_tile_idx[VVC_MAX_SLICES]; + uint16_t num_slices_in_tile[VVC_MAX_SLICES]; } H266RawPPS; typedef struct H266RawAPS { @@ -846,6 +848,11 @@ typedef struct H266RawSlice { size_t header_size; size_t data_size; int data_bit_start; + + H266RawSPS *sps; ///< RefStruct reference to referred-to SPS + H266RawPPS *pps; ///< RefStruct reference to referred-to PPS + H266RawPictureHeader *ph; + void *ph_ref; ///< RefStruct reference backing referred-to PH above } H266RawSlice; typedef struct H266RawSEI { diff --git a/libavcodec/cbs_h266_syntax_template.c b/libavcodec/cbs_h266_syntax_template.c index 851f2734a..98a895494 100644 --- a/libavcodec/cbs_h266_syntax_template.c +++ b/libavcodec/cbs_h266_syntax_template.c @@ -318,7 +318,7 @@ static int FUNC(payload_extension) (CodedBitstreamContext *ctx, RWContext *rw, GetBitContext tmp; int bits_left, payload_zero_bits; - if (!cbs_h265_payload_extension_present(rw, payload_size, cur_pos)) + if (!ff_cbs_h2645_payload_extension_present(rw, payload_size, cur_pos)) return 0; bits_left = 8 * payload_size - cur_pos; @@ -373,7 +373,7 @@ static int FUNC(extension_data) (CodedBitstreamContext *ctx, RWContext *rw, GetBitContext start; uint8_t bit; start = *rw; - for (k = 0; cbs_h2645_read_more_rbsp_data(rw); k++) + for (k = 0; ff_cbs_h2645_read_more_rbsp_data(rw); k++) skip_bits(rw, 1); current->bit_length = k; if (k > 0) { @@ -1057,7 +1057,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, H266RawSPS *current) { CodedBitstreamH266Context *h266 = ctx->priv_data; - int err, i, j; + int err, i, j, max_width_minus1, max_height_minus1; unsigned int ctb_log2_size_y, min_cb_log2_size_y, min_qt_log2_size_intra_y, min_qt_log2_size_inter_y, ctb_size_y, max_num_merge_cand, tmp_width_val, tmp_height_val; @@ -1078,7 +1078,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, ub(4, sps_seq_parameter_set_id); ub(4, sps_video_parameter_set_id); if (current->sps_video_parameter_set_id == 0 && !h266->vps[0]) { - H266RawVPS *vps = ff_refstruct_allocz(sizeof(*vps)); + H266RawVPS *vps = av_refstruct_allocz(sizeof(*vps)); if (!vps) return AVERROR(ENOMEM); vps->vps_max_layers_minus1 = 0; @@ -1130,6 +1130,8 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, ctb_log2_size_y); tmp_height_val = AV_CEIL_RSHIFT(current->sps_pic_height_max_in_luma_samples, ctb_log2_size_y); + max_width_minus1 = tmp_width_val - 1; + max_height_minus1 = tmp_height_val - 1; flag(sps_subpic_info_present_flag); if (current->sps_subpic_info_present_flag) { @@ -1145,13 +1147,13 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, infer(sps_subpic_ctu_top_left_x[0], 0); infer(sps_subpic_ctu_top_left_y[0], 0); if (current->sps_pic_width_max_in_luma_samples > ctb_size_y) - ubs(wlen, sps_subpic_width_minus1[0], 1, 0); + us(wlen, sps_subpic_width_minus1[0], 0, max_width_minus1, 1, 0); else - infer(sps_subpic_width_minus1[0], tmp_width_val - 1); + infer(sps_subpic_width_minus1[0], max_width_minus1); if (current->sps_pic_height_max_in_luma_samples > ctb_size_y) - ubs(hlen, sps_subpic_height_minus1[0], 1, 0); + us(hlen, sps_subpic_height_minus1[0], 0, max_height_minus1, 1, 0); else - infer(sps_subpic_height_minus1[0], tmp_height_val - 1); + infer(sps_subpic_height_minus1[0], max_height_minus1); if (!current->sps_independent_subpics_flag) { flags(sps_subpic_treated_as_pic_flag[0], 1, 0); flags(sps_loop_filter_across_subpic_enabled_flag[0], 1, 0); @@ -1161,58 +1163,54 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, } for (i = 1; i <= current->sps_num_subpics_minus1; i++) { if (!current->sps_subpic_same_size_flag) { - if (current->sps_pic_width_max_in_luma_samples > ctb_size_y) { - const int win_right_edge = - current->sps_pic_width_max_in_luma_samples - - current->sps_conf_win_right_offset * sub_width_c; - us(wlen, sps_subpic_ctu_top_left_x[i], 0, - AV_CEIL_RSHIFT(win_right_edge, ctb_log2_size_y) - 1, - 1, i); - } else + const int win_right_edge = + current->sps_pic_width_max_in_luma_samples - + current->sps_conf_win_right_offset * sub_width_c; + const int win_bottom_edge = + current->sps_pic_height_max_in_luma_samples - + current->sps_conf_win_bottom_offset * sub_height_c; + const int win_left_edge = + current->sps_conf_win_left_offset * sub_width_c; + const int win_top_edge = + current->sps_conf_win_top_offset * sub_height_c; + const int win_left_edge_ctus = + AV_CEIL_RSHIFT(win_left_edge, ctb_log2_size_y); + const int win_right_edge_ctus = + AV_CEIL_RSHIFT(win_right_edge, ctb_log2_size_y); + const int win_top_edge_ctus = + AV_CEIL_RSHIFT(win_top_edge, ctb_log2_size_y); + const int win_bottom_edge_ctus = + AV_CEIL_RSHIFT(win_bottom_edge, ctb_log2_size_y); + const int min_width = + FFMAX(win_left_edge_ctus - current->sps_subpic_ctu_top_left_x[i], 0); + const int min_height = + FFMAX(win_top_edge_ctus - current->sps_subpic_ctu_top_left_y[i], 0); + + if (current->sps_pic_width_max_in_luma_samples > ctb_size_y) + us(wlen, sps_subpic_ctu_top_left_x[i], 0, win_right_edge_ctus - 1, 1, i); + else infer(sps_subpic_ctu_top_left_x[i], 0); - if (current->sps_pic_height_max_in_luma_samples > - ctb_size_y) { - const int win_bottom_edge = - current->sps_pic_height_max_in_luma_samples - - current->sps_conf_win_bottom_offset * sub_height_c; - us(hlen, sps_subpic_ctu_top_left_y[i], 0, - AV_CEIL_RSHIFT(win_bottom_edge, ctb_log2_size_y) - 1, - 1, i); - } else + + if (current->sps_pic_height_max_in_luma_samples > ctb_size_y) + us(hlen, sps_subpic_ctu_top_left_y[i], 0, win_bottom_edge_ctus - 1, 1, i); + else infer(sps_subpic_ctu_top_left_y[i], 0); + + max_width_minus1 = tmp_width_val - current->sps_subpic_ctu_top_left_x[i] - 1; + max_height_minus1 = tmp_height_val - current->sps_subpic_ctu_top_left_y[i] - 1; + if (i < current->sps_num_subpics_minus1 && - current->sps_pic_width_max_in_luma_samples > - ctb_size_y) { - const int win_left_edge = - current->sps_conf_win_left_offset * sub_width_c; - const int win_left_edge_ctus = - AV_CEIL_RSHIFT(win_left_edge, ctb_log2_size_y); - us(wlen, sps_subpic_width_minus1[i], - win_left_edge_ctus > current->sps_subpic_ctu_top_left_x[i] - ? win_left_edge_ctus - current->sps_subpic_ctu_top_left_x[i] - : 0, - MAX_UINT_BITS(wlen), 1, i); + current->sps_pic_width_max_in_luma_samples > ctb_size_y) { + us(wlen, sps_subpic_width_minus1[i], min_width, max_width_minus1, 1, i); } else { - infer(sps_subpic_width_minus1[i], - tmp_width_val - - current->sps_subpic_ctu_top_left_x[i] - 1); + infer(sps_subpic_width_minus1[i], max_width_minus1); } + if (i < current->sps_num_subpics_minus1 && - current->sps_pic_height_max_in_luma_samples > - ctb_size_y) { - const int win_top_edge = - current->sps_conf_win_top_offset * sub_height_c; - const int win_top_edge_ctus = - AV_CEIL_RSHIFT(win_top_edge, ctb_log2_size_y); - us(hlen, sps_subpic_height_minus1[i], - win_top_edge_ctus > current->sps_subpic_ctu_top_left_y[i] - ? win_top_edge_ctus - current->sps_subpic_ctu_top_left_y[i] - : 0, - MAX_UINT_BITS(hlen), 1, i); + current->sps_pic_height_max_in_luma_samples > ctb_size_y) { + us(hlen, sps_subpic_height_minus1[i], min_height, max_height_minus1, 1, i); } else { - infer(sps_subpic_height_minus1[i], - tmp_height_val - - current->sps_subpic_ctu_top_left_y[i] - 1); + infer(sps_subpic_height_minus1[i], max_height_minus1); } } else { int num_subpic_cols = tmp_width_val / @@ -1245,8 +1243,8 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, } else { infer(sps_subpic_ctu_top_left_x[0], 0); infer(sps_subpic_ctu_top_left_y[0], 0); - infer(sps_subpic_width_minus1[0], tmp_width_val - 1); - infer(sps_subpic_height_minus1[0], tmp_height_val - 1); + infer(sps_subpic_width_minus1[0], max_width_minus1); + infer(sps_subpic_height_minus1[0], max_height_minus1); } ue(sps_subpic_id_len_minus1, 0, 15); if ((1 << (current->sps_subpic_id_len_minus1 + 1)) < @@ -1273,8 +1271,8 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, infer(sps_subpic_id_mapping_explicitly_signalled_flag, 0); infer(sps_subpic_ctu_top_left_x[0], 0); infer(sps_subpic_ctu_top_left_y[0], 0); - infer(sps_subpic_width_minus1[0], tmp_width_val - 1); - infer(sps_subpic_height_minus1[0], tmp_height_val - 1); + infer(sps_subpic_width_minus1[0], max_width_minus1); + infer(sps_subpic_height_minus1[0], max_height_minus1); } @@ -1727,7 +1725,7 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, current->pps_pic_height_in_luma_samples != sps->sps_pic_height_max_in_luma_samples)) { av_log(ctx->log_ctx, AV_LOG_ERROR, - "Resoltuion change is not allowed, " + "Resolution change is not allowed, " "in max resolution (%ux%u) mismatched with pps(%ux%u).\n", sps->sps_pic_width_max_in_luma_samples, sps->sps_pic_height_max_in_luma_samples, @@ -1960,7 +1958,7 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, infer(pps_single_slice_per_subpic_flag, 1); if (current->pps_rect_slice_flag && !current->pps_single_slice_per_subpic_flag) { - int j; + int j, num_slices = 0; uint16_t tile_idx = 0, tile_x, tile_y, ctu_x, ctu_y; uint16_t slice_top_left_ctu_x[VVC_MAX_SLICES]; uint16_t slice_top_left_ctu_y[VVC_MAX_SLICES]; @@ -1970,6 +1968,7 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, else infer(pps_tile_idx_delta_present_flag, 0); for (i = 0; i < current->pps_num_slices_in_pic_minus1; i++) { + current->slice_top_left_tile_idx[i] = tile_idx; tile_x = tile_idx % current->num_tile_columns; tile_y = tile_idx / current->num_tile_columns; if (tile_y >= current->num_tile_rows) @@ -2002,14 +2001,13 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, if (current->pps_slice_width_in_tiles_minus1[i] == 0 && current->pps_slice_height_in_tiles_minus1[i] == 0 && current->row_height_val[tile_y] > 1) { - int num_slices_in_tile, - uniform_slice_height, remaining_height_in_ctbs_y; + int uniform_slice_height, remaining_height_in_ctbs_y; remaining_height_in_ctbs_y = current->row_height_val[tile_y]; ues(pps_num_exp_slices_in_tile[i], 0, current->row_height_val[tile_y] - 1, 1, i); if (current->pps_num_exp_slices_in_tile[i] == 0) { - num_slices_in_tile = 1; + current->num_slices_in_tile[i] = 1; current->slice_height_in_ctus[i] = current->row_height_val[tile_y]; slice_top_left_ctu_x[i] = ctu_x; slice_top_left_ctu_y[i] = ctu_y; @@ -2024,7 +2022,7 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, for (j = 0; j < current->pps_num_exp_slices_in_tile[i]; j++) { ues(pps_exp_slice_height_in_ctus_minus1[i][j], 0, - current->row_height_val[tile_y] - 1, 2, + remaining_height_in_ctbs_y - 1, 2, i, j); slice_height_in_ctus = current-> @@ -2065,12 +2063,18 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, slice_top_left_ctu_y[i + j] = ctu_y; j++; } - num_slices_in_tile = j; + current->num_slices_in_tile[i] = j; } - i += num_slices_in_tile - 1; + for (int k = 0; k < current->num_slices_in_tile[i]; k++) + current->slice_top_left_tile_idx[i + k] = tile_idx; + i += current->num_slices_in_tile[i] - 1; } else { uint16_t height = 0; infer(pps_num_exp_slices_in_tile[i], 0); + if (current->pps_slice_width_in_tiles_minus1[i] == 0 && + current->pps_slice_height_in_tiles_minus1[i] == 0) + current->num_slices_in_tile[i] = 1; + for (j = 0; j <= current->pps_slice_height_in_tiles_minus1[i]; j++) { @@ -2110,6 +2114,8 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, if (i == current->pps_num_slices_in_pic_minus1) { uint16_t height = 0; + current->slice_top_left_tile_idx[i] = tile_idx; + current->num_slices_in_tile[i] = 1; tile_x = tile_idx % current->num_tile_columns; tile_y = tile_idx / current->num_tile_columns; if (tile_y >= current->num_tile_rows) @@ -2156,7 +2162,10 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, current->num_slices_in_subpic[i]++; } } + num_slices += current->num_slices_in_subpic[i]; } + if (current->pps_num_slices_in_pic_minus1 + 1 != num_slices) + return AVERROR_INVALIDDATA; } else { if (current->pps_no_pic_partition_flag) infer(pps_num_slices_in_pic_minus1, 0); @@ -2812,7 +2821,7 @@ static int FUNC(picture_header) (CodedBitstreamContext *ctx, RWContext *rw, 0, 2 * (ctb_log2_size_y - min_cb_log2_size_y)); if (sps->sps_max_mtt_hierarchy_depth_intra_slice_chroma != 0) { unsigned int min_qt_log2_size_intra_c = - sps->sps_log2_diff_min_qt_min_cb_intra_slice_chroma + + current->ph_log2_diff_min_qt_min_cb_intra_slice_chroma + min_cb_log2_size_y; ue(ph_log2_diff_max_bt_min_qt_intra_slice_chroma, 0, FFMIN(6, ctb_log2_size_y) - min_qt_log2_size_intra_c); @@ -3254,6 +3263,12 @@ static int FUNC(slice_header) (CodedBitstreamContext *ctx, RWContext *rw, FFMIN(ref_pic_lists->rpl_ref_list[i].num_ref_entries, pps->pps_num_ref_idx_default_active_minus1[i] + 1); } + + if (current->num_ref_idx_active[i] <= 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Inter slice but no reference pictures available for RPL%d.\n", i); + return AVERROR_INVALIDDATA; + } } else { current->num_ref_idx_active[i] = 0; } @@ -3440,13 +3455,50 @@ static int FUNC(slice_header) (CodedBitstreamContext *ctx, RWContext *rw, for (i = 0; i < current->curr_subpic_idx; i++) { slice_idx += pps->num_slices_in_subpic[i]; } - width_in_tiles = - pps->pps_slice_width_in_tiles_minus1[slice_idx] + 1; - if (entropy_sync) - height = pps->slice_height_in_ctus[slice_idx]; - else - height = pps->pps_slice_height_in_tiles_minus1[slice_idx] + 1; + if (pps->pps_single_slice_per_subpic_flag) { + const int width_in_ctus = sps->sps_subpic_width_minus1[slice_idx] + 1; + const int subpic_l = sps->sps_subpic_ctu_top_left_x[slice_idx]; + const int subpic_r = subpic_l + width_in_ctus; + + int ctb_x = 0, tile_x = 0; + for (; ctb_x < subpic_l && tile_x < pps->num_tile_columns; tile_x++) + ctb_x += pps->col_width_val[tile_x]; + + width_in_tiles = 0; + for (; ctb_x < subpic_r && tile_x < pps->num_tile_columns; tile_x++) { + ctb_x += pps->col_width_val[tile_x]; + width_in_tiles++; + } + + if (entropy_sync) { + height = sps->sps_subpic_height_minus1[slice_idx] + 1; + } else { + const int height_in_ctus = sps->sps_subpic_height_minus1[slice_idx] + 1; + const int subpic_t = sps->sps_subpic_ctu_top_left_y[slice_idx]; + const int subpic_b = subpic_t + height_in_ctus; + + int ctb_y = 0, tile_y = 0, height_in_tiles; + for (; ctb_y < subpic_t && tile_y < pps->num_tile_rows; tile_y++) + ctb_y += pps->row_height_val[tile_y]; + + height_in_tiles = 0; + for (; ctb_y < subpic_b && tile_y < pps->num_tile_rows; tile_y++) { + ctb_y += pps->row_height_val[tile_y]; + height_in_tiles++; + } + + height = height_in_tiles; + } + } else { + width_in_tiles = + pps->pps_slice_width_in_tiles_minus1[slice_idx] + 1; + + if (entropy_sync) + height = pps->slice_height_in_ctus[slice_idx]; + else + height = pps->pps_slice_height_in_tiles_minus1[slice_idx] + 1; + } current->num_entry_points = width_in_tiles * height; } else { diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h index d982262bd..2af8075f7 100644 --- a/libavcodec/cbs_internal.h +++ b/libavcodec/cbs_internal.h @@ -22,14 +22,56 @@ #include #include +#include "config.h" + #include "libavutil/log.h" #include "cbs.h" #include "codec_id.h" #include "get_bits.h" #include "put_bits.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" +#ifndef CBS_READ +#define CBS_READ 1 +#endif +#ifndef CBS_WRITE +#define CBS_WRITE 1 +#endif +#ifndef CBS_TRACE +#define CBS_TRACE 1 +#endif + +#ifndef CBS_APV +#define CBS_APV CONFIG_CBS_APV +#endif +#ifndef CBS_AV1 +#define CBS_AV1 CONFIG_CBS_AV1 +#endif +#ifndef CBS_H264 +#define CBS_H264 CONFIG_CBS_H264 +#endif +#ifndef CBS_H265 +#define CBS_H265 CONFIG_CBS_H265 +#endif +#ifndef CBS_H266 +#define CBS_H266 CONFIG_CBS_H266 +#endif +#ifndef CBS_LCEVC +#define CBS_LCEVC CONFIG_CBS_LCEVC +#endif +#ifndef CBS_JPEG +#define CBS_JPEG CONFIG_CBS_JPEG +#endif +#ifndef CBS_MPEG2 +#define CBS_MPEG2 CONFIG_CBS_MPEG2 +#endif +#ifndef CBS_VP8 +#define CBS_VP8 CONFIG_CBS_VP8 +#endif +#ifndef CBS_VP9 +#define CBS_VP9 CONFIG_CBS_VP9 +#endif enum CBSContentType { // Unit content may contain some references to other structures, but all @@ -93,7 +135,7 @@ typedef const struct CodedBitstreamUnitTypeDescriptor { } ref; struct { - void (*content_free)(FFRefStructOpaque opaque, void *content); + void (*content_free)(AVRefStructOpaque opaque, void *content); int (*content_clone)(void **new_content, CodedBitstreamUnit *unit); } complex; } type; @@ -112,7 +154,7 @@ typedef struct CodedBitstreamType { // List of unit type descriptors for this codec. // Terminated by a descriptor with nb_unit_types equal to zero. - const CodedBitstreamUnitTypeDescriptor *unit_types; + CodedBitstreamUnitTypeDescriptor *unit_types; // Split frag->data into coded bitstream units, creating the // frag->units array. Fill data but not content on each unit. @@ -155,7 +197,7 @@ typedef struct CodedBitstreamType { // Helper functions for trace output. -void ff_cbs_trace_header(CodedBitstreamContext *ctx, +void CBS_FUNC(trace_header)(CodedBitstreamContext *ctx, const char *name); @@ -165,28 +207,28 @@ void ff_cbs_trace_header(CodedBitstreamContext *ctx, // (i.e. only limited by the amount of bits used) and they lack // the ability to use subscripts. -int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, +int CBS_FUNC(read_unsigned)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, const int *subscripts, uint32_t *write_to, uint32_t range_min, uint32_t range_max); -int ff_cbs_read_simple_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, +int CBS_FUNC(read_simple_unsigned)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, uint32_t *write_to); -int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, +int CBS_FUNC(write_unsigned)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, const int *subscripts, uint32_t value, uint32_t range_min, uint32_t range_max); -int ff_cbs_write_simple_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, +int CBS_FUNC(write_simple_unsigned)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, uint32_t value); -int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, +int CBS_FUNC(read_signed)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, const int *subscripts, int32_t *write_to, int32_t range_min, int32_t range_max); -int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, +int CBS_FUNC(write_signed)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, const int *subscripts, int32_t value, int32_t range_min, int32_t range_max); @@ -204,6 +246,7 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, #define MIN_INT_BITS(length) (-(INT64_C(1) << ((length) - 1))) +#if CBS_TRACE // Start of a syntax element during read tracing. #define CBS_TRACE_READ_START() \ GetBitContext trace_start; \ @@ -233,7 +276,7 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, } while (0) // End of a syntax element which is made up of subelements which -// are aleady traced, so we are only showing the value. +// are already traced, so we are only showing the value. #define CBS_TRACE_READ_END_VALUE_ONLY() \ do { \ if (ctx->trace_enable) { \ @@ -270,7 +313,7 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, } while (0) // End of a syntax element which is made up of subelements which are -// aleady traced, so we are only showing the value. This forges a +// already traced, so we are only showing the value. This forges a // PutBitContext to point to the position of the start of the syntax // element, but the other state doesn't matter because length is zero. #define CBS_TRACE_WRITE_END_VALUE_ONLY() \ @@ -284,6 +327,17 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, } \ } while (0) +#else // CBS_TRACE +#define CBS_TRACE_READ_START() do { } while (0) +#define CBS_TRACE_READ_END() do { } while (0) +#define CBS_TRACE_READ_END_NO_SUBSCRIPTS() do { } while (0) +#define CBS_TRACE_READ_END_VALUE_ONLY() do { } while (0) +#define CBS_TRACE_WRITE_START() do { } while (0) +#define CBS_TRACE_WRITE_END() do { } while (0) +#define CBS_TRACE_WRITE_END_NO_SUBSCRIPTS() do { } while (0) +#define CBS_TRACE_WRITE_END_VALUE_ONLY() do { } while (0) +#endif // CBS_TRACE + #define TYPE_LIST(...) { __VA_ARGS__ } #define CBS_UNIT_TYPE_POD(type_, structure) { \ .nb_unit_types = 1, \ @@ -335,14 +389,16 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, #define CBS_UNIT_TYPE_END_OF_LIST { .nb_unit_types = 0 } -extern const CodedBitstreamType ff_cbs_type_av1; -extern const CodedBitstreamType ff_cbs_type_h264; -extern const CodedBitstreamType ff_cbs_type_h265; -extern const CodedBitstreamType ff_cbs_type_h266; -extern const CodedBitstreamType ff_cbs_type_jpeg; -extern const CodedBitstreamType ff_cbs_type_mpeg2; -extern const CodedBitstreamType ff_cbs_type_vp8; -extern const CodedBitstreamType ff_cbs_type_vp9; +extern const CodedBitstreamType CBS_FUNC(type_apv); +extern const CodedBitstreamType CBS_FUNC(type_av1); +extern const CodedBitstreamType CBS_FUNC(type_h264); +extern const CodedBitstreamType CBS_FUNC(type_h265); +extern const CodedBitstreamType CBS_FUNC(type_h266); +extern const CodedBitstreamType CBS_FUNC(type_lcevc); +extern const CodedBitstreamType CBS_FUNC(type_jpeg); +extern const CodedBitstreamType CBS_FUNC(type_mpeg2); +extern const CodedBitstreamType CBS_FUNC(type_vp8); +extern const CodedBitstreamType CBS_FUNC(type_vp9); #endif /* AVCODEC_CBS_INTERNAL_H */ diff --git a/libavcodec/cbs_jpeg.c b/libavcodec/cbs_jpeg.c index 406147c08..d64e2baec 100644 --- a/libavcodec/cbs_jpeg.c +++ b/libavcodec/cbs_jpeg.c @@ -417,7 +417,7 @@ static int cbs_jpeg_assemble_fragment(CodedBitstreamContext *ctx, return 0; } -static const CodedBitstreamUnitTypeDescriptor cbs_jpeg_unit_types[] = { +static CodedBitstreamUnitTypeDescriptor cbs_jpeg_unit_types[] = { CBS_UNIT_RANGE_POD(JPEG_MARKER_SOF0, JPEG_MARKER_SOF3, JPEGRawFrameHeader), CBS_UNIT_RANGE_INTERNAL_REF(JPEG_MARKER_APPN, JPEG_MARKER_APPN + 15, diff --git a/libavcodec/cbs_lcevc.c b/libavcodec/cbs_lcevc.c new file mode 100644 index 000000000..62fbacab1 --- /dev/null +++ b/libavcodec/cbs_lcevc.c @@ -0,0 +1,836 @@ +/* + * 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/mem.h" +#include "libavutil/refstruct.h" +#include "bytestream.h" +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_h2645.h" +#include "cbs_lcevc.h" +#include "cbs_sei.h" +#include "get_bits.h" + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME2(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_NAME1(rw, codec, name) FUNC_NAME2(rw, codec, name) +#define FUNC_LCEVC(name) FUNC_NAME1(READWRITE, lcevc, name) +#define FUNC_NAME2_EXPORT(rw, codec, name) ff_cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_NAME1_EXPORT(rw, codec, name) FUNC_NAME2_EXPORT(rw, codec, name) +#define FUNC_SEI(name) FUNC_NAME1_EXPORT(READWRITE, sei, name) + +#define SEI_FUNC(name, args) \ +static int FUNC_LCEVC(name) args; \ +static int FUNC_LCEVC(name ## _internal)(CodedBitstreamContext *ctx, \ + RWContext *rw, void *cur, \ + SEIMessageState *state) \ +{ \ + return FUNC_LCEVC(name)(ctx, rw, cur, state); \ +} \ +static int FUNC_LCEVC(name) args + +#define LCEVC_BLOCK_FUNC(name, args) \ +static int FUNC(name) args; \ +static int FUNC(name ## _internal)(CodedBitstreamContext *ctx, \ + RWContext *rw, void *cur, \ + LCEVCProcessBlockState *state, \ + int nal_unit_type) \ +{ \ + return FUNC(name)(ctx, rw, cur, state, nal_unit_type); \ +} \ +static int FUNC(name) args + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max, 0, ) +#define flag(name) ub(1, name) +#define ue(name, range_min, range_max) \ + xue(name, current->name, range_min, range_max, 0, ) +#define i(width, name, range_min, range_max) \ + xi(width, name, current->name, range_min, range_max, 0, ) +#define ib(width, name) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), 0, ) +#define se(name, range_min, range_max) \ + xse(name, current->name, range_min, range_max, 0, ) + +#define us(width, name, range_min, range_max, subs, ...) \ + xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ubs(width, name, subs, ...) \ + xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define flags(name, subs, ...) \ + xu(1, name, current->name, 0, 1, subs, __VA_ARGS__) +#define ues(name, range_min, range_max, subs, ...) \ + xue(name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define is(width, name, range_min, range_max, subs, ...) \ + xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ibs(width, name, subs, ...) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__) +#define ses(name, range_min, range_max, subs, ...) \ + xse(name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define mb(name) \ + xmb(name, current->name) + +#define fixed(width, name, value) do { \ + av_unused uint32_t fixed_value = value; \ + xu(width, name, fixed_value, value, value, 0, ); \ + } while (0) + + +static int cbs_read_multi_byte(CodedBitstreamContext *ctx, GetBitContext *gbc, + const char *name, uint32_t *write_to) +{ + uint64_t value; + uint32_t byte; + int i; + + CBS_TRACE_READ_START(); + + value = 0; + for (i = 0; i < 10; i++) { + if (get_bits_left(gbc) < 8) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid multi byte at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + byte = get_bits(gbc, 8); + value = (value << 7) | (byte & 0x7f); + if (!(byte & 0x80)) + break; + } + + if (value > UINT32_MAX) + return AVERROR_INVALIDDATA; + + CBS_TRACE_READ_END_NO_SUBSCRIPTS(); + + *write_to = value; + return 0; +} + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define ub(width, name) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \ + &value)); \ + current->name = value; \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xue(name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value; \ + CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ + int32_t value; \ + CHECK(ff_cbs_read_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xmb(name, var) do { \ + uint32_t value; \ + CHECK(cbs_read_multi_byte(ctx, rw, #name, &value)); \ + var = value; \ + } while (0) + +#define infer(name, value) do { \ + current->name = value; \ + } while (0) + +#define more_rbsp_data(var) ((var) = ff_cbs_h2645_read_more_rbsp_data(rw)) + +#define bit_position(rw) (get_bits_count(rw)) +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +/* The CBS LCEVC code uses the refstruct API for the allocation + * of its child buffers. */ +#define allocate(name, size) do { \ + name = av_refstruct_allocz(size + \ + AV_INPUT_BUFFER_PADDING_SIZE); \ + if (!name) \ + return AVERROR(ENOMEM); \ + } while (0) + +#define FUNC(name) FUNC_LCEVC(name) +#include "cbs_lcevc_syntax_template.c" +#undef FUNC + + +#undef READ +#undef READWRITE +#undef RWContext +#undef ub +#undef xu +#undef xi +#undef xue +#undef xse +#undef xmb +#undef infer +#undef more_rbsp_data +#undef bit_position +#undef byte_alignment +#undef allocate + + +static int cbs_write_multi_byte(CodedBitstreamContext *ctx, PutBitContext *pbc, + const char *name, uint32_t value) +{ + int len, i; + uint8_t byte; + + CBS_TRACE_WRITE_START(); + + len = (av_log2(value) + 7) / 7; + + for (i = len - 1; i >= 0; i--) { + if (put_bits_left(pbc) < 8) + return AVERROR(ENOSPC); + + byte = value >> (7 * i) & 0x7f; + if (i > 0) + byte |= 0x80; + + put_bits(pbc, 8, byte); + } + + CBS_TRACE_WRITE_END_NO_SUBSCRIPTS(); + + return 0; +} + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define ub(width, name) do { \ + uint32_t value = current->name; \ + CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \ + value)); \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xue(name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value = var; \ + CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ + int32_t value = var; \ + CHECK(ff_cbs_write_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xmb(name, var) do { \ + uint32_t value = var; \ + CHECK(cbs_write_multi_byte(ctx, rw, #name, value)); \ + } while (0) + +#define infer(name, value) do { \ + if (current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, \ + "%s does not match inferred value: " \ + "%"PRId64", but should be %"PRId64".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define more_rbsp_data(var) (var) + +#define bit_position(rw) (put_bits_count(rw)) +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + if (!name) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \ + "for writing.\n", #name); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define FUNC(name) FUNC_LCEVC(name) +#include "cbs_lcevc_syntax_template.c" +#undef FUNC + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef ub +#undef xu +#undef xi +#undef xue +#undef xse +#undef xmb +#undef u +#undef i +#undef flag +#undef ue +#undef se +#undef infer +#undef more_rbsp_data +#undef bit_position +#undef byte_alignment +#undef allocate + + +static int cbs_lcevc_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + enum AVCodecID codec_id = ctx->codec->codec_id; + CodedBitstreamLCEVCContext *priv = ctx->priv_data; + CodedBitstreamH2645Context *h2645 = &priv->common; + GetByteContext gbc; + int err; + + av_assert0(frag->data && frag->nb_units == 0); + if (frag->data_size == 0) + return 0; + + if (header && frag->data[0]) { + // LVCC header. + size_t size, start, end; + int i, j, nb_arrays, nal_unit_type, nb_nals, version; + + h2645->mp4 = 1; + + bytestream2_init(&gbc, frag->data, frag->data_size); + + if (bytestream2_get_bytes_left(&gbc) < 14) + return AVERROR_INVALIDDATA; + + version = bytestream2_get_byte(&gbc); + if (version != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid LVCC header: " + "first byte %u.\n", version); + return AVERROR_INVALIDDATA; + } + + bytestream2_skip(&gbc, 3); + h2645->nal_length_size = (bytestream2_get_byte(&gbc) >> 6) + 1; + + bytestream2_skip(&gbc, 9); + nb_arrays = bytestream2_get_byte(&gbc); + + for (i = 0; i < nb_arrays; i++) { + nal_unit_type = bytestream2_get_byte(&gbc) & 0x3f; + nb_nals = bytestream2_get_be16(&gbc); + + start = bytestream2_tell(&gbc); + for (j = 0; j < nb_nals; j++) { + if (bytestream2_get_bytes_left(&gbc) < 2) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if (bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&h2645->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 2, AV_CODEC_ID_LCEVC, + H2645_FLAG_IS_NALFF | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split " + "LVCC array %d (%d NAL units of type %d).\n", + i, nb_nals, nal_unit_type); + return err; + } + err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet); + if (err < 0) + return err; + } + } else { + int flags = (H2645_FLAG_IS_NALFF * !!h2645->mp4) | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF; + // Annex B, or later MP4 with already-known parameters. + + err = ff_h2645_packet_split(&h2645->read_packet, + frag->data, frag->data_size, + ctx->log_ctx, + h2645->nal_length_size, + codec_id, flags); + if (err < 0) + return err; + + err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet); + if (err < 0) + return err; + } + + return 0; +} + +static int cbs_lcevc_read_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + + err = init_get_bits8(&gbc, unit->data, unit->data_size); + if (err < 0) + return err; + + err = ff_cbs_alloc_unit_content(ctx, unit); + if (err < 0) + return err; + + switch (unit->type) { + case LCEVC_NON_IDR_NUT: + case LCEVC_IDR_NUT: + { + LCEVCRawNAL *nal = unit->content; + LCEVCRawProcessBlockList *block_list; + + err = cbs_lcevc_read_nal(ctx, &gbc, unit->content, unit->type); + + if (err < 0) + return err; + + block_list = &nal->process_block_list; + for (int i = 0; i < block_list->nb_blocks; i++) { + LCEVCRawProcessBlock *block = &block_list->blocks[i]; + LCEVCRawEncodedData *slice; + + if (block->payload_type != LCEVC_PAYLOAD_TYPE_ENCODED_DATA) + continue; + + slice = block->payload; + slice->data_ref = av_buffer_ref(unit->data_ref); + if (!slice->data_ref) + return AVERROR(ENOMEM); + slice->data = unit->data + slice->header_size; + } + + if (err < 0) + return err; + } + break; + default: + return AVERROR(ENOSYS); + } + + return 0; +} + +static int cbs_lcevc_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + switch (unit->type) { + case LCEVC_NON_IDR_NUT: + case LCEVC_IDR_NUT: + { + err = cbs_lcevc_write_nal(ctx, pbc, unit->content, unit->type); + + if (err < 0) + return err; + } + break; + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " + "NAL unit type %"PRIu32".\n", unit->type); + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static void free_picture_config(AVRefStructOpaque unused, void *obj) +{ + LCEVCRawPictureConfig *picture_config = obj; + + av_refstruct_unref(&picture_config->gc); +} + +static void free_encoded_data(AVRefStructOpaque unused, void *obj) +{ + LCEVCRawEncodedData *slice = obj; + + av_buffer_unref(&slice->data_ref); + + av_refstruct_unref(&slice->sc); + av_refstruct_unref(&slice->gc); + av_refstruct_unref(&slice->pc); +} + +static void free_additional_info(AVRefStructOpaque unused, void *obj) +{ + LCEVCRawAdditionalInfo *additional_info = obj; + LCEVCRawSEI *sei = &additional_info->sei; + SEIRawMessage *message = &sei->message; + + av_refstruct_unref(&additional_info->payload_ref); + av_refstruct_unref(&sei->payload_ref); + av_refstruct_unref(&message->payload_ref); + av_refstruct_unref(&message->extension_data); +} + +int ff_cbs_lcevc_alloc_process_block_payload(LCEVCRawProcessBlock *block, + const LCEVCProcessBlockTypeDescriptor *desc) +{ + void (*free_func)(AVRefStructOpaque, void*); + + av_assert0(block->payload == NULL && + block->payload_ref == NULL); + block->payload_type = desc->payload_type; + + if (desc->payload_type == LCEVC_PAYLOAD_TYPE_PICTURE_CONFIG) + free_func = &free_picture_config; + else if (desc->payload_type == LCEVC_PAYLOAD_TYPE_ENCODED_DATA) + free_func = &free_encoded_data; + else if (desc->payload_type == LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO) + free_func = &free_additional_info; + else + free_func = NULL; + + block->payload_ref = av_refstruct_alloc_ext(desc->payload_size, 0, + NULL, free_func); + if (!block->payload_ref) + return AVERROR(ENOMEM); + block->payload = block->payload_ref; + + return 0; +} + +int ff_cbs_lcevc_list_add(LCEVCRawProcessBlockList *list, int position) +{ + LCEVCRawProcessBlock *blocks; + + if (position == -1) + position = list->nb_blocks; + av_assert0(position >= 0 && position <= list->nb_blocks); + + if (list->nb_blocks < list->nb_blocks_allocated) { + blocks = list->blocks; + + if (position < list->nb_blocks) + memmove(blocks + position + 1, blocks + position, + (list->nb_blocks - position) * sizeof(*blocks)); + } else { + blocks = av_malloc_array(list->nb_blocks*2 + 1, sizeof(*blocks)); + if (!blocks) + return AVERROR(ENOMEM); + + list->nb_blocks_allocated = 2*list->nb_blocks_allocated + 1; + + if (position > 0) + memcpy(blocks, list->blocks, position * sizeof(*blocks)); + + if (position < list->nb_blocks) + memcpy(blocks + position + 1, list->blocks + position, + (list->nb_blocks - position) * sizeof(*blocks)); + + av_free(list->blocks); + list->blocks = blocks; + } + + memset(blocks + position, 0, sizeof(*blocks)); + + ++list->nb_blocks; + + return 0; +} + +void ff_cbs_lcevc_free_process_block_list(LCEVCRawProcessBlockList *list) +{ + for (int i = 0; i < list->nb_blocks; i++) { + LCEVCRawProcessBlock *block = &list->blocks[i]; + av_refstruct_unref(&block->payload_ref); + av_refstruct_unref(&block->extension_data); + } + av_free(list->blocks); +} + +static int cbs_lcevc_get_process_block_list(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + LCEVCRawProcessBlockList **list) +{ + LCEVCRawNAL *nal = unit->content; + if (unit->type != LCEVC_NON_IDR_NUT && unit->type != LCEVC_IDR_NUT) + return AVERROR(EINVAL); + *list = &nal->process_block_list; + + return 0; +} + +int ff_cbs_lcevc_add_process_block(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + int position, + uint32_t payload_type, + void *payload_data, + void *payload_ref) +{ + const LCEVCProcessBlockTypeDescriptor *desc; + CodedBitstreamUnit *unit = NULL; + LCEVCRawProcessBlockList *list; + LCEVCRawProcessBlock *block; + int err; + + desc = ff_cbs_lcevc_process_block_find_type(ctx, payload_type); + if (!desc) + return AVERROR(EINVAL); + + for (int i = 0; i < au->nb_units; i++) { + if (au->units[i].type == LCEVC_NON_IDR_NUT || + au->units[i].type == LCEVC_IDR_NUT) { + unit = &au->units[i]; + break; + } + } + if (!unit) + return AVERROR(EINVAL); + + // Find the block list inside the codec-dependent unit. + err = cbs_lcevc_get_process_block_list(ctx, unit, &list); + if (err < 0) + return err; + + // Add a new block to the message list. + err = ff_cbs_lcevc_list_add(list, position); + if (err < 0) + return err; + + if (payload_ref) { + /* The following just increments payload_ref's refcount, + * so that payload_ref is now owned by us. */ + payload_ref = av_refstruct_ref(payload_ref); + } + + block = &list->blocks[position]; + + block->payload_type = payload_type; + block->payload = payload_data; + block->payload_ref = payload_ref; + + return 0; +} + +int ff_cbs_lcevc_find_process_block(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + uint32_t payload_type, + LCEVCRawProcessBlock **iter) +{ + int err, found; + + found = 0; + for (int i = 0; i < au->nb_units; i++) { + CodedBitstreamUnit *unit = &au->units[i]; + LCEVCRawProcessBlockList *list; + + if (!unit->content) + continue; + + err = cbs_lcevc_get_process_block_list(ctx, unit, &list); + if (err < 0) + continue; + + for (int j = 0; j < list->nb_blocks; j++) { + LCEVCRawProcessBlock *block = &list->blocks[j]; + + if (block->payload_type == payload_type) { + if (!*iter || found) { + *iter = block; + return j; + } + if (block == *iter) + found = 1; + } + } + } + + return AVERROR(ENOENT); +} + +static void cbs_lcevc_delete_process_block(LCEVCRawProcessBlockList *list, + int position) +{ + LCEVCRawProcessBlock *block; + + av_assert0(0 <= position && position < list->nb_blocks); + + block = &list->blocks[position]; + av_refstruct_unref(&block->payload_ref); + + --list->nb_blocks; + + if (list->nb_blocks > 0) { + memmove(list->blocks + position, + list->blocks + position + 1, + (list->nb_blocks - position) * sizeof(*list->blocks)); + } +} + +void ff_cbs_lcevc_delete_process_block_type(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + uint32_t payload_type) +{ + int err; + + for (int i = 0; i < au->nb_units; i++) { + CodedBitstreamUnit *unit = &au->units[i]; + LCEVCRawProcessBlockList *list; + + err = cbs_lcevc_get_process_block_list(ctx, unit, &list); + if (err < 0) + continue; + + for (int j = list->nb_blocks - 1; j >= 0; j--) { + if (list->blocks[j].payload_type == payload_type) + cbs_lcevc_delete_process_block(list, j); + } + } +} + +static av_cold void cbs_lcevc_flush(CodedBitstreamContext *ctx) +{ + CodedBitstreamLCEVCContext *lcevc = ctx->priv_data; + + av_refstruct_unref(&lcevc->sc); + av_refstruct_unref(&lcevc->gc); + av_refstruct_unref(&lcevc->pc); +} + +static av_cold void cbs_lcevc_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamLCEVCContext *lcevc = ctx->priv_data; + + cbs_lcevc_flush(ctx); + ff_h2645_packet_uninit(&lcevc->common.read_packet); +} + +static void cbs_lcevc_free_nal(AVRefStructOpaque unused, void *content) +{ + LCEVCRawNAL *nal = content; + ff_cbs_lcevc_free_process_block_list(&nal->process_block_list); +} + +static CodedBitstreamUnitTypeDescriptor cbs_lcevc_unit_types[] = { + CBS_UNIT_TYPES_COMPLEX((LCEVC_NON_IDR_NUT, LCEVC_IDR_NUT), + LCEVCRawNAL, cbs_lcevc_free_nal), + + CBS_UNIT_TYPE_END_OF_LIST +}; + +// Macro for the read/write pair. +#define LCEVC_PROCESS_BLOCK_RW(codec, name) \ + .read = cbs_ ## codec ## _read_ ## name ## _internal, \ + .write = cbs_ ## codec ## _write_ ## name ## _internal + +static const LCEVCProcessBlockTypeDescriptor cbs_lcevc_process_block_types[] = { + { + LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG, + sizeof(LCEVCRawSequenceConfig), + LCEVC_PROCESS_BLOCK_RW(lcevc, sequence_config), + }, + { + LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG, + sizeof(LCEVCRawGlobalConfig), + LCEVC_PROCESS_BLOCK_RW(lcevc, global_config), + }, + { + LCEVC_PAYLOAD_TYPE_PICTURE_CONFIG, + sizeof(LCEVCRawPictureConfig), + LCEVC_PROCESS_BLOCK_RW(lcevc, picture_config), + }, + { + LCEVC_PAYLOAD_TYPE_ENCODED_DATA, + sizeof(LCEVCRawEncodedData), + LCEVC_PROCESS_BLOCK_RW(lcevc, encoded_data), + }, + { + LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO, + sizeof(LCEVCRawAdditionalInfo), + LCEVC_PROCESS_BLOCK_RW(lcevc, additional_info), + }, + { + LCEVC_PAYLOAD_TYPE_FILLER, + sizeof(LCEVCRawFiller), + LCEVC_PROCESS_BLOCK_RW(lcevc, filler), + }, + LCEVC_PROCESS_BLOCK_TYPE_END, +}; + +const LCEVCProcessBlockTypeDescriptor + *ff_cbs_lcevc_process_block_find_type(CodedBitstreamContext *ctx, + int payload_type) +{ + for (int i = 0; cbs_lcevc_process_block_types[i].payload_type >= 0; i++) { + if (cbs_lcevc_process_block_types[i].payload_type == payload_type) + return &cbs_lcevc_process_block_types[i]; + } + + return NULL; +} + +const CodedBitstreamType ff_cbs_type_lcevc = { + .codec_id = AV_CODEC_ID_LCEVC, + + .priv_data_size = sizeof(CodedBitstreamLCEVCContext), + + .unit_types = cbs_lcevc_unit_types, + + .split_fragment = &cbs_lcevc_split_fragment, + .read_unit = &cbs_lcevc_read_nal_unit, + .write_unit = &cbs_lcevc_write_nal_unit, + .assemble_fragment = &ff_cbs_h2645_assemble_fragment, + + .flush = &cbs_lcevc_flush, + .close = &cbs_lcevc_close, +}; diff --git a/libavcodec/cbs_lcevc.h b/libavcodec/cbs_lcevc.h new file mode 100644 index 000000000..371c7912e --- /dev/null +++ b/libavcodec/cbs_lcevc.h @@ -0,0 +1,308 @@ +/* + * 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_CBS_LCEVC_H +#define AVCODEC_CBS_LCEVC_H + +#include +#include + +#include "cbs_h2645.h" +#include "cbs_sei.h" +#include "lcevc.h" + +typedef struct LCEVCRawNALUnitHeader { + uint8_t nal_unit_type; + uint16_t reserved_flag; +} LCEVCRawNALUnitHeader; + +typedef struct LCEVCRawSequenceConfig { + uint8_t profile_idc; + uint8_t level_idc; + uint8_t sublevel_idc; + uint8_t conformance_window_flag; + uint8_t reserved_zeros_5bit; + uint8_t extended_profile_idc; + uint8_t extended_level_idc; + uint8_t reserved_zeros_1bit; + uint32_t conf_win_left_offset; + uint32_t conf_win_right_offset; + uint32_t conf_win_top_offset; + uint32_t conf_win_bottom_offset; +} LCEVCRawSequenceConfig; + +typedef struct LCEVCRawGlobalConfig { + uint8_t processed_planes_type_flag; + uint8_t resolution_type; + uint8_t transform_type; + uint8_t chroma_sampling_type; + uint8_t base_depth_type; + uint8_t enhancement_depth_type; + uint8_t temporal_step_width_modifier_signalled_flag; + uint8_t predicted_residual_mode_flag; + uint8_t temporal_tile_intra_signalling_enabled_flag; + uint8_t temporal_enabled_flag; + uint8_t upsample_type; + uint8_t level1_filtering_signalled_flag; + uint8_t scaling_mode_level1; + uint8_t scaling_mode_level2; + uint8_t tile_dimensions_type; + uint8_t user_data_enabled; + uint8_t level1_depth_flag; + uint8_t chroma_step_width_flag; + uint8_t planes_type; + uint8_t reserved_zeros_4bit; + uint8_t temporal_step_width_modifier; + uint16_t upsampler_coeff1; + uint16_t upsampler_coeff2; + uint16_t upsampler_coeff3; + uint16_t upsampler_coeff4; + uint8_t level1_filtering_first_coefficient; + uint8_t level1_filtering_second_coefficient; + uint16_t custom_tile_width; + uint16_t custom_tile_height; + uint16_t reserved_zeros_5bit; + uint8_t compression_type_entropy_enabled_per_tile_flag; + uint8_t compression_type_size_per_tile; + uint16_t custom_resolution_width; + uint16_t custom_resolution_height; + uint8_t chroma_step_width_multiplier; +} LCEVCRawGlobalConfig; + +typedef struct LCEVCRawPictureConfig { + uint8_t no_enhancement_bit_flag; + uint8_t quant_matrix_mode; + uint8_t dequant_offset_signalled_flag; + uint8_t picture_type_bit_flag; + uint8_t temporal_refresh_bit_flag; + uint8_t step_width_sublayer1_enabled_flag; + uint16_t step_width_sublayer2; + uint8_t dithering_control_flag; + uint8_t reserved_zeros_4bit; + uint8_t temporal_signalling_present_flag; + uint8_t field_type_bit_flag; + uint8_t reserved_zeros_7bit; + uint16_t step_width_sublayer1; + uint8_t level1_filtering_enabled_flag; + uint8_t qm_coefficient_0[16]; + uint8_t qm_coefficient_1[16]; + uint8_t dequant_offset_mode_flag; + uint8_t dequant_offset; + uint8_t dithering_type; + uint8_t reserverd_zero; + uint8_t dithering_strength; + uint8_t reserved_zeros_5bit; + + LCEVCRawGlobalConfig *gc; ///< RefStruct references +} LCEVCRawPictureConfig; + +typedef struct LCEVCRawEncodedData { + LCEVCRawNALUnitHeader nal_unit_header; + + uint8_t surfaces_entropy_enabled_flag[3][3][16]; + uint8_t surfaces_rle_only_flag[3][3][16]; + uint8_t temporal_surfaces_entropy_enabled_flag[3]; + uint8_t temporal_surfaces_rle_only_flag[3]; + + uint8_t *data; + AVBufferRef *data_ref; + size_t header_size; + size_t data_size; + + LCEVCRawSequenceConfig *sc; ///< RefStruct references + LCEVCRawGlobalConfig *gc; ///< RefStruct references + LCEVCRawPictureConfig *pc; ///< RefStruct references +} LCEVCRawEncodedData; + +typedef struct LCEVCRawVUI { + uint8_t aspect_ratio_info_present_flag; + uint8_t aspect_ratio_idc; + uint16_t sar_width; + uint8_t sar_height; + uint8_t overscan_info_present_flag; + uint8_t overscan_appropriate_flag; + uint8_t video_signal_type_present_flag; + uint8_t video_format; + uint8_t video_full_range_flag; + uint8_t colour_description_present_flag; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + uint8_t chroma_loc_info_present_flag; + uint8_t chroma_sample_loc_type_top_field; + uint8_t chroma_sample_loc_type_bottom_field; +} LCEVCRawVUI; + +typedef struct LCEVCRawSEI { + SEIRawMessage message; + + uint8_t payload_type; + uint32_t payload_size; + void *payload; + void *payload_ref; ///< RefStruct reference +} LCEVCRawSEI; + +typedef struct LCEVCRawAdditionalInfo { + uint8_t additional_info_type; + + LCEVCRawSEI sei; + LCEVCRawVUI vui; + + uint32_t payload_size; + void *payload; + void *payload_ref; ///< RefStruct reference +} LCEVCRawAdditionalInfo; + +typedef struct LCEVCRawFiller { + uint32_t filler_size; +} LCEVCRawFiller; + +typedef struct LCEVCRawProcessBlock { + uint32_t payload_type; + uint32_t payload_size; + void *payload; + void *payload_ref; ///< RefStruct reference + uint8_t *extension_data; ///< RefStruct reference + size_t extension_bit_length; +} LCEVCRawProcessBlock; + +typedef struct LCEVCRawProcessBlockList { + LCEVCRawProcessBlock *blocks; + int nb_blocks; + int nb_blocks_allocated; +} LCEVCRawProcessBlockList; + +typedef struct LCEVCRawNAL { + LCEVCRawNALUnitHeader nal_unit_header; + + LCEVCRawProcessBlockList process_block_list; +} LCEVCRawNAL; + +typedef struct LCEVCProcessBlockState { + // The type of the payload being written. + uint32_t payload_type; + // When reading, contains the size of the payload to allow finding the + // end of variable-length fields (such as user_data_payload_byte[]). + // (When writing, the size will be derived from the total number of + // bytes actually written.) + uint32_t payload_size; + // When writing, indicates that payload extension data is present so + // all extended fields must be written. May be updated by the writer + // to indicate that extended fields have been written, so the extension + // end bits must be written too. + uint8_t extension_present; +} LCEVCProcessBlockState; + +typedef int (*LCEVCRawProcessBlockReadFunction)(CodedBitstreamContext *ctx, + struct GetBitContext *rw, + void *current, + LCEVCProcessBlockState *state, + int nal_unit_type); + +typedef int (*LCEVCRawProcessBlockWriteFunction)(CodedBitstreamContext *ctx, + struct PutBitContext *rw, + void *current, + LCEVCProcessBlockState *state, + int nal_unit_type); + +typedef struct LCEVCProcessBlockTypeDescriptor { + // Payload type for the block. (-1 in this field ends a list.) + int payload_type; + // Size of the decomposed structure. + size_t payload_size; + // Read bitstream into Process Block. + LCEVCRawProcessBlockReadFunction read; + // Write bitstream from Process Block. + LCEVCRawProcessBlockWriteFunction write; +} LCEVCProcessBlockTypeDescriptor; + +// End-of-list sentinel element. +#define LCEVC_PROCESS_BLOCK_TYPE_END { .payload_type = -1 } + +typedef struct CodedBitstreamLCEVCContext { + // Reader/writer context in common with the H.264 implementation. + CodedBitstreamH2645Context common; + + int dithering_control_flag; + + // All currently available parameter sets. These are updated when + // any parameter set NAL unit is read/written with this context. + LCEVCRawSequenceConfig *sc; ///< RefStruct references + LCEVCRawGlobalConfig *gc; ///< RefStruct references + LCEVCRawPictureConfig *pc; ///< RefStruct references +} CodedBitstreamLCEVCContext; + +/** + * Find the type descriptor for the given payload type. + * + * Returns NULL if the payload type is not known. + */ +const LCEVCProcessBlockTypeDescriptor *ff_cbs_lcevc_process_block_find_type(CodedBitstreamContext *ctx, + int payload_type); + +/** + * Allocate a new payload for the given Process Block. + */ +int ff_cbs_lcevc_alloc_process_block_payload(LCEVCRawProcessBlock *block, + const LCEVCProcessBlockTypeDescriptor *desc); + +/** + * Allocate a new empty Process Block in a block list at a given position. + */ +int ff_cbs_lcevc_list_add(LCEVCRawProcessBlockList *list, int position); + +/** + * Free all Process Block in a block list. + */ +void ff_cbs_lcevc_free_process_block_list(LCEVCRawProcessBlockList *list); + +/** + * Add a process block to an access unit. + * + * An existing NAL unit of type IDR or NON_IDR are required. + * + * If set, payload_ref must be a RefStruct reference backing payload_data. + * This function creates a new reference to payload_ref in this case. + * If payload_ref is NULL, the new message will not be reference counted. + */ +int ff_cbs_lcevc_add_process_block(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + int position, + uint32_t payload_type, + void *payload_data, + void *payload_ref); + +/** + * Iterate over blocks with the given payload type in an access unit. + * + * Set block to NULL in the first call. Returns 0 while more blocks + * are available, AVERROR(ENOENT) when all blocks have been found. + */ +int ff_cbs_lcevc_find_process_block(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + uint32_t payload_type, + LCEVCRawProcessBlock **block); + +/** + * Delete all blocks with the given payload type from an access unit. + */ +void ff_cbs_lcevc_delete_process_block_type(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + uint32_t payload_type); + +#endif /* AVCODEC_CBS_LCEVC_H */ diff --git a/libavcodec/cbs_lcevc_syntax_template.c b/libavcodec/cbs_lcevc_syntax_template.c new file mode 100644 index 000000000..b24c1bf36 --- /dev/null +++ b/libavcodec/cbs_lcevc_syntax_template.c @@ -0,0 +1,676 @@ +/* + * 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 + */ + +static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + + // ISO/IEC 23094-2:2021/FDAM 1:2023(E) 7.3.12 + while (byte_alignment(rw) != 0) + fixed(1, alignment_bit_equal_to_zero, 0); + + return 0; +} + +static int FUNC(rbsp_trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + + fixed(1, rbsp_stop_one_bit, 1); + while (byte_alignment(rw) != 0) + fixed(1, rbsp_alignment_zero_bit, 0); + + return 0; +} + +static int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawNALUnitHeader *current, + uint32_t valid_type_mask) +{ + int err; + + fixed(1, forbidden_zero_bit, 0); + fixed(1, forbidden_one_bit, 1); + ub(5, nal_unit_type); + + if (!(1 << current->nal_unit_type & valid_type_mask)) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid NAL unit type %d.\n", + current->nal_unit_type); + return AVERROR_INVALIDDATA; + } + + ub(9, reserved_flag); + + return 0; +} + +LCEVC_BLOCK_FUNC(global_config, (CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawGlobalConfig *current, + LCEVCProcessBlockState *state, + int nal_unit_type)) +{ + CodedBitstreamLCEVCContext *priv = ctx->priv_data; + int err; + + HEADER("Global Config"); + + flag(processed_planes_type_flag); + ub(6, resolution_type); + ub(1, transform_type); + ub(2, chroma_sampling_type); + ub(2, base_depth_type); + ub(2, enhancement_depth_type); + flag(temporal_step_width_modifier_signalled_flag); + flag(predicted_residual_mode_flag); + flag(temporal_tile_intra_signalling_enabled_flag); + flag(temporal_enabled_flag); + ub(3, upsample_type); + flag(level1_filtering_signalled_flag); + ub(2, scaling_mode_level1); + ub(2, scaling_mode_level2); + ub(2, tile_dimensions_type); + ub(2, user_data_enabled); + flag(level1_depth_flag); + flag(chroma_step_width_flag); + + if (current->processed_planes_type_flag) { + ub(4, planes_type); + ub(4, reserved_zeros_4bit); + } else + infer(planes_type, 0); + + if (current->temporal_step_width_modifier_signalled_flag) { + ub(8, temporal_step_width_modifier); + } + + if (current->upsample_type == 4) { + ub(16, upsampler_coeff1); + ub(16, upsampler_coeff2); + ub(16, upsampler_coeff3); + ub(16, upsampler_coeff4); + } + + if (current->level1_filtering_signalled_flag) { + ub(4, level1_filtering_first_coefficient); + ub(4, level1_filtering_second_coefficient); + } + + if (current->tile_dimensions_type > 0) { + if (current->tile_dimensions_type == 3) { + ub(16, custom_tile_width); + ub(16, custom_tile_height); + } + ub(5, reserved_zeros_5bit); + flag(compression_type_entropy_enabled_per_tile_flag); + ub(2, compression_type_size_per_tile); + } + + if (current->resolution_type == 63) { + ub(16, custom_resolution_width); + ub(16, custom_resolution_height); + } + if (current->chroma_step_width_flag) { + ub(8, chroma_step_width_multiplier); + } else { + infer(chroma_step_width_multiplier, 64); + } + + av_refstruct_replace(&priv->gc, current); + + return 0; +} + +LCEVC_BLOCK_FUNC(sequence_config, (CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawSequenceConfig *current, + LCEVCProcessBlockState *state, + int nal_unit_type)) +{ + CodedBitstreamLCEVCContext *priv = ctx->priv_data; + int err; + + HEADER("Sequence Config"); + + ub(4, profile_idc); + ub(4, level_idc); + ub(2, sublevel_idc); + flag(conformance_window_flag); + ub(5, reserved_zeros_5bit); + + if (current->profile_idc == 15 || current->level_idc == 15) { + ub(3, profile_idc); + ub(4, level_idc); + ub(1, reserved_zeros_1bit); + } + if (current->conformance_window_flag == 1) { + mb(conf_win_left_offset); + mb(conf_win_right_offset); + mb(conf_win_top_offset); + mb(conf_win_bottom_offset); + } + + av_refstruct_replace(&priv->sc, current); + + return 0; +} + +LCEVC_BLOCK_FUNC(picture_config, (CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawPictureConfig *current, + LCEVCProcessBlockState *state, + int nal_unit_type)) +{ + CodedBitstreamLCEVCContext *priv = ctx->priv_data; + int nlayers, err; + + HEADER("Picture Config"); + + if (!priv->gc) + return AVERROR_INVALIDDATA; + + flag(no_enhancement_bit_flag); + if (current->no_enhancement_bit_flag == 0) { + ub(3, quant_matrix_mode); + flag(dequant_offset_signalled_flag); + flag(picture_type_bit_flag); + flag(temporal_refresh_bit_flag); + flag(step_width_sublayer1_enabled_flag); + ub(15, step_width_sublayer2); + flag(dithering_control_flag); + priv->dithering_control_flag = current->dithering_control_flag; + infer(temporal_signalling_present_flag, priv->gc->temporal_enabled_flag && + !current->temporal_refresh_bit_flag); + } else { + infer(quant_matrix_mode, 0); + infer(dequant_offset_signalled_flag, 0); + ub(4, reserved_zeros_4bit); + flag(picture_type_bit_flag); + flag(temporal_refresh_bit_flag); + infer(step_width_sublayer1_enabled_flag, 0); + infer(dithering_control_flag, nal_unit_type == LCEVC_IDR_NUT + ? 0 + : priv->dithering_control_flag); + priv->dithering_control_flag = current->dithering_control_flag; + flag(temporal_signalling_present_flag); + } + + if (current->picture_type_bit_flag == 1) { + flag(field_type_bit_flag); + ub(7, reserved_zeros_7bit); + } + + if (current->step_width_sublayer1_enabled_flag == 1) { + ub(15, step_width_sublayer1); + flag(level1_filtering_enabled_flag); + } else + infer(level1_filtering_enabled_flag, 0); + + nlayers = priv->gc->transform_type ? 16 : 4; + if (current->quant_matrix_mode == 2 || + current->quant_matrix_mode == 3 || + current->quant_matrix_mode == 5) { + for (int layer_idx = 0; layer_idx < nlayers; layer_idx++) + ubs(8, qm_coefficient_0[layer_idx], 1, layer_idx); + } + + if (current->quant_matrix_mode == 4 || current->quant_matrix_mode == 5) { + for (int layer_idx = 0; layer_idx < nlayers; layer_idx++) + ubs(8, qm_coefficient_1[layer_idx], 1, layer_idx); + } + + if (current->dequant_offset_signalled_flag) { + flag(dequant_offset_mode_flag); + ub(7, dequant_offset); + } + + if (current->dithering_control_flag == 1) { + ub(2, dithering_type); + ub(1, reserverd_zero); + if (current->dithering_type != 0) { + ub(5, dithering_strength); + } else { + ub(5, reserved_zeros_5bit); + } + } + + av_refstruct_replace(&priv->pc, current); + av_refstruct_replace(¤t->gc, priv->gc); + + return 0; +} + +LCEVC_BLOCK_FUNC(encoded_data, (CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawEncodedData *current, + LCEVCProcessBlockState *state, + int nal_unit_type)) +{ + CodedBitstreamLCEVCContext *priv = ctx->priv_data; + int nplanes, nlayers, err; +#ifdef READ + int start = get_bits_count(rw); +#endif + + HEADER("Encoded Data"); + + if (!priv->gc || !priv->pc) + return AVERROR_INVALIDDATA; + + nplanes = priv->gc->planes_type ? 3 : 1; + nlayers = priv->gc->transform_type ? 16 : 4; + for (int plane_idx = 0; plane_idx < nplanes; plane_idx++) { + if (priv->pc->no_enhancement_bit_flag == 0) { + for (int level_idx = 1; level_idx <= 2; level_idx++) { + for (int layer_idx = 0; layer_idx < nlayers; layer_idx++) { + ubs(1, surfaces_entropy_enabled_flag[plane_idx][level_idx][layer_idx], 3, plane_idx, level_idx, layer_idx); + ubs(1, surfaces_rle_only_flag[plane_idx][level_idx][layer_idx], 3, plane_idx, level_idx, layer_idx); + } + } + } + if (priv->pc->temporal_signalling_present_flag == 1) { + ubs(1, temporal_surfaces_entropy_enabled_flag[plane_idx], 1, plane_idx); + ubs(1, temporal_surfaces_rle_only_flag[plane_idx], 1, plane_idx); + } + } + + CHECK(FUNC(byte_alignment)(ctx, rw)); + +#ifdef READ + if (!ff_cbs_h2645_read_more_rbsp_data(rw)) + return AVERROR_INVALIDDATA; + + int pos = get_bits_count(rw) - start; + int len = state->payload_size; + + current->header_size = pos / 8; + current->data_size = len - pos / 8; + skip_bits_long(rw, current->data_size * 8); +#else + err = ff_cbs_h2645_write_slice_data(ctx, rw, current->data, + current->data_size, 0); + if (err < 0) + return err; +#endif + + av_refstruct_replace(¤t->sc, priv->sc); + av_refstruct_replace(¤t->gc, priv->gc); + av_refstruct_replace(¤t->pc, priv->pc); + + return 0; +} + +static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawSEI *current, int payload_size) +{ + SEIRawMessage *message = ¤t->message; + int sei_type; + int i, err; + + ub(8, payload_type); + + if (current->payload_type == 1) + sei_type = SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME; + else if (current->payload_type == 2) + sei_type = SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO; + else if (current->payload_type == 4) + sei_type = SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35; + else if (current->payload_type == 5) + sei_type = SEI_TYPE_USER_DATA_UNREGISTERED; + else { + uint8_t *data; + +#ifdef READ + current->payload_size = payload_size; + allocate(current->payload_ref, current->payload_size); + current->payload = current->payload_ref; +#else + allocate(current->payload, current->payload_size); +#endif + data = current->payload; + + for (i = 0; i < current->payload_size; i++) + xu(8, reserved_sei_message_payload_byte[i], data[i], 0, 255, 1, i); + + return 0; + } + + message->payload_type = sei_type; + message->payload_size = payload_size; + + CHECK(FUNC_SEI(message)(ctx, rw, message)); + + return 0; +} + +static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawVUI *current) +{ + int err; + + HEADER("VUI Parameters"); + + flag(aspect_ratio_info_present_flag); + if (current->aspect_ratio_info_present_flag) { + ub(8, aspect_ratio_idc); + + if (current->aspect_ratio_idc == 255) { + ub(16, sar_width); + ub(16, sar_height); + } + } else { + infer(aspect_ratio_idc, 0); + } + + flag(overscan_info_present_flag); + if (current->overscan_info_present_flag) + flag(overscan_appropriate_flag); + else + infer(overscan_appropriate_flag, 0); + + flag(video_signal_type_present_flag); + if (current->video_signal_type_present_flag) { + u(3, video_format, 0, 5); + flag(video_full_range_flag); + flag(colour_description_present_flag); + if (current->colour_description_present_flag) { + ub(8, colour_primaries); + ub(8, transfer_characteristics); + ub(8, matrix_coefficients); + } else { + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + } else { + infer(video_format, 5); + infer(video_full_range_flag, 0); + infer(colour_description_present_flag, 0); + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + flag(chroma_loc_info_present_flag); + if (current->chroma_loc_info_present_flag) { + ue(chroma_sample_loc_type_top_field, 0, 5); + ue(chroma_sample_loc_type_bottom_field, 0, 5); + } else { + infer(chroma_sample_loc_type_top_field, 0); + infer(chroma_sample_loc_type_bottom_field, 0); + } + + return 0; +} + +LCEVC_BLOCK_FUNC(additional_info, (CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawAdditionalInfo *current, + LCEVCProcessBlockState *state, + int nal_unit_type)) +{ + int i, err; + + HEADER("Additional Info"); + + ub(8, additional_info_type); + + if (current->additional_info_type == LCEVC_ADDITIONAL_INFO_TYPE_SEI) { + CHECK(FUNC(sei_payload)(ctx, rw, ¤t->sei, state->payload_size - 2)); + } else if (current->additional_info_type == LCEVC_ADDITIONAL_INFO_TYPE_VUI) + CHECK(FUNC(vui_parameters)(ctx, rw, ¤t->vui)); + else { + uint8_t *data; + +#ifdef READ + current->payload_size = state->payload_size - 1; + allocate(current->payload_ref, current->payload_size); + current->payload = current->payload_ref; +#else + allocate(current->payload, current->payload_size); +#endif + data = current->payload; + + for (i = 0; i < current->payload_size; i++) + xu(8, additional_info_byte[i], data[i], 0, 255, 1, i); + } + + return 0; +} + +LCEVC_BLOCK_FUNC(filler, (CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawFiller *current, + LCEVCProcessBlockState *state, + int nal_unit_type)) +{ + int err; + + HEADER("Filler"); + + +#ifdef READ + while (show_bits(rw, 8) == 0xaa) { + fixed(8, filler_byte, 0xaa); + ++current->filler_size; + } + if (state->payload_size != current->filler_size) + return AVERROR_INVALIDDATA; + +#else + for (int i = 0; i < current->filler_size; i++) + fixed(8, filler_byte, 0xaa); +#endif + + return 0; +} + +static int FUNC(process_block)(CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawProcessBlock *current, + int nal_unit_type) +{ + const LCEVCProcessBlockTypeDescriptor *desc; + int err, i; + + desc = ff_cbs_lcevc_process_block_find_type(ctx, current->payload_type); + if (desc) { + LCEVCProcessBlockState state = { + .payload_type = current->payload_type, + .payload_size = current->payload_size, + .extension_present = current->extension_bit_length > 0, + }; + int start_position, current_position, bits_written; + +#ifdef READ + CHECK(ff_cbs_lcevc_alloc_process_block_payload(current, desc)); +#endif + + start_position = bit_position(rw); + + CHECK(desc->READWRITE(ctx, rw, current->payload, &state, nal_unit_type)); + + current_position = bit_position(rw); + bits_written = current_position - start_position; + + if (byte_alignment(rw) || state.extension_present || + bits_written < 8 * current->payload_size) { + size_t bits_left; + +#ifdef READ + GetBitContext tmp = *rw; + int trailing_bits, trailing_zero_bits; + + bits_left = 8 * current->payload_size - bits_written; + if (bits_left > 8) + skip_bits_long(&tmp, bits_left - 8); + trailing_bits = get_bits(&tmp, FFMIN(bits_left, 8)); + if (trailing_bits == 0) { + // The trailing bits must contain a payload_bit_equal_to_one, so + // they can't all be zero. + return AVERROR_INVALIDDATA; + } + trailing_zero_bits = ff_ctz(trailing_bits); + current->extension_bit_length = + bits_left - 1 - trailing_zero_bits; +#endif + + if (current->extension_bit_length > 0) { + allocate(current->extension_data, + (current->extension_bit_length + 7) / 8); + + bits_left = current->extension_bit_length; + for (i = 0; bits_left > 0; i++) { + int length = FFMIN(bits_left, 8); + xu(length, reserved_payload_extension_data, + current->extension_data[i], + 0, MAX_UINT_BITS(length), 0); + bits_left -= length; + } + } + + fixed(1, payload_bit_equal_to_one, 1); + while (byte_alignment(rw)) + fixed(1, payload_bit_equal_to_zero, 0); + } + +#ifdef WRITE + current->payload_size = (put_bits_count(rw) - start_position) / 8; +#endif + } else { + uint8_t *data; + +#ifdef READ + allocate(current->payload_ref, current->payload_size); + current->payload = current->payload_ref; +#else + allocate(current->payload, current->payload_size); +#endif + data = current->payload; + + for (i = 0; i < current->payload_size; i++) + xu(8, payload_byte[i], data[i], 0, 255, 1, i); + } + + return 0; +} + +static int FUNC(process_block_list)(CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawProcessBlockList *current, + int nal_unit_type) +{ + LCEVCRawProcessBlock *block; + int err, k; + +#ifdef READ + for (k = 0;; k++) { + int payload_size_type; + int payload_type; + uint32_t payload_size; + uint32_t tmp; + GetBitContext payload_gbc; + + HEADER("Process Block"); + + xu(3, payload_size_type, tmp, 0, MAX_UINT_BITS(3), 0); + payload_size_type = tmp; + xu(5, payload_type, tmp, 0, MAX_UINT_BITS(5), 0); + payload_type = tmp; + + if (payload_size_type == 6) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "payload_size_type == 6\n"); + return AVERROR_INVALIDDATA; + } + + payload_size = payload_size_type; + if (payload_size_type == 7) + xmb(custom_byte_size, payload_size); + + // There must be space remaining for the payload + if (payload_size > get_bits_left(rw) / 8) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid process block: payload_size too large " + "(%"PRIu32" bytes).\n", payload_size); + return AVERROR_INVALIDDATA; + } + CHECK(init_get_bits(&payload_gbc, rw->buffer, + get_bits_count(rw) + 8 * payload_size)); + skip_bits_long(&payload_gbc, get_bits_count(rw)); + + CHECK(ff_cbs_lcevc_list_add(current, -1)); + block = ¤t->blocks[k]; + + block->payload_type = payload_type; + block->payload_size = payload_size; + + CHECK(FUNC(process_block)(ctx, &payload_gbc, block, nal_unit_type)); + + skip_bits_long(rw, 8 * payload_size); + + if (!ff_cbs_h2645_read_more_rbsp_data(rw)) + break; + } +#else + for (k = 0; k < current->nb_blocks; k++) { + PutBitContext start_state; + uint32_t tmp; + int trace, i; + + block = ¤t->blocks[k]; + + // We write the payload twice in order to find the size. Trace + // output is switched off for the first write. + trace = ctx->trace_enable; + ctx->trace_enable = 0; + + start_state = *rw; + for (i = 0; i < 2; i++) { + *rw = start_state; + + tmp = FFMIN(block->payload_size, 7); + if (tmp == 6) + tmp = 7; + xu(3, payload_size_type, tmp, 0, 7, 0); + xu(5, payload_type, block->payload_type, 0, MAX_UINT_BITS(5), 0); + + if (tmp == 7) + xmb(custom_byte_size, block->payload_size); + + err = FUNC(process_block)(ctx, rw, block, nal_unit_type); + ctx->trace_enable = trace; + if (err < 0) + return err; + } + } +#endif + + return 0; +} + +static int FUNC(nal)(CodedBitstreamContext *ctx, RWContext *rw, + LCEVCRawNAL *current, int nal_unit_type) +{ + int err; + + if (nal_unit_type == LCEVC_NON_IDR_NUT) + HEADER("Non IDR"); + else + HEADER("IDR"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + (1 << LCEVC_IDR_NUT) | (1 << LCEVC_NON_IDR_NUT))); + + CHECK(FUNC(process_block_list) (ctx, rw, ¤t->process_block_list, + current->nal_unit_header.nal_unit_type)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} diff --git a/libavcodec/cbs_mpeg2.c b/libavcodec/cbs_mpeg2.c index 37fc28a4e..87401d154 100644 --- a/libavcodec/cbs_mpeg2.c +++ b/libavcodec/cbs_mpeg2.c @@ -397,7 +397,7 @@ static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx, return 0; } -static const CodedBitstreamUnitTypeDescriptor cbs_mpeg2_unit_types[] = { +static CodedBitstreamUnitTypeDescriptor cbs_mpeg2_unit_types[] = { CBS_UNIT_TYPE_INTERNAL_REF(MPEG2_START_PICTURE, MPEG2RawPictureHeader, extra_information_picture.extra_information), diff --git a/libavcodec/cbs_sei.c b/libavcodec/cbs_sei.c index 458751d92..f354a1002 100644 --- a/libavcodec/cbs_sei.c +++ b/libavcodec/cbs_sei.c @@ -23,24 +23,224 @@ #include "cbs_h265.h" #include "cbs_h266.h" #include "cbs_sei.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" -static void cbs_free_user_data_registered(FFRefStructOpaque unused, void *obj) +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME2(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_NAME1(rw, codec, name) FUNC_NAME2(rw, codec, name) +#define FUNC_NAME2_EXPORT(rw, codec, name) ff_cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_NAME1_EXPORT(rw, codec, name) FUNC_NAME2_EXPORT(rw, codec, name) +#define FUNC_SEI(name) FUNC_NAME1(READWRITE, sei, name) +#define FUNC_SEI_EXPORT(name) FUNC_NAME1_EXPORT(READWRITE, sei, name) + +#define SEI_FUNC(name, args) \ +static int FUNC_SEI(name) args; \ +static int FUNC_SEI(name ## _internal)(CodedBitstreamContext *ctx, \ + RWContext *rw, void *cur, \ + SEIMessageState *state) \ +{ \ + return FUNC_SEI(name)(ctx, rw, cur, state); \ +} \ +static int FUNC_SEI(name) args + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max, 0, ) +#define flag(name) ub(1, name) +#define ue(name, range_min, range_max) \ + xue(name, current->name, range_min, range_max, 0, ) +#define i(width, name, range_min, range_max) \ + xi(width, name, current->name, range_min, range_max, 0, ) +#define ib(width, name) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), 0, ) +#define se(name, range_min, range_max) \ + xse(name, current->name, range_min, range_max, 0, ) + +#define us(width, name, range_min, range_max, subs, ...) \ + xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ubs(width, name, subs, ...) \ + xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define flags(name, subs, ...) \ + xu(1, name, current->name, 0, 1, subs, __VA_ARGS__) +#define ues(name, range_min, range_max, subs, ...) \ + xue(name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define is(width, name, range_min, range_max, subs, ...) \ + xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ibs(width, name, subs, ...) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__) +#define ses(name, range_min, range_max, subs, ...) \ + xse(name, current->name, range_min, range_max, subs, __VA_ARGS__) + +#define fixed(width, name, value) do { \ + av_unused uint32_t fixed_value = value; \ + xu(width, name, fixed_value, value, value, 0, ); \ + } while (0) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define ub(width, name) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \ + &value)); \ + current->name = value; \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xue(name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(ff_cbs_read_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value; \ + CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ + int32_t value; \ + CHECK(ff_cbs_read_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) + + +#define infer(name, value) do { \ + current->name = value; \ + } while (0) + +#define more_rbsp_data(var) ((var) = ff_cbs_h2645_read_more_rbsp_data(rw)) + +#define bit_position(rw) (get_bits_count(rw)) +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +/* The CBS SEI code uses the refstruct API for the allocation + * of its child buffers. */ +#define allocate(name, size) do { \ + name = av_refstruct_allocz(size + \ + AV_INPUT_BUFFER_PADDING_SIZE); \ + if (!name) \ + return AVERROR(ENOMEM); \ + } while (0) + +#define FUNC(name) FUNC_SEI_EXPORT(name) +#include "cbs_sei_syntax_template.c" +#undef FUNC + +#undef READ +#undef READWRITE +#undef RWContext +#undef ub +#undef xu +#undef xi +#undef xue +#undef xse +#undef infer +#undef more_rbsp_data +#undef bit_position +#undef byte_alignment +#undef allocate + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define ub(width, name) do { \ + uint32_t value = current->name; \ + CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \ + value)); \ + } while (0) +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xue(name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value = var; \ + CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ + int32_t value = var; \ + CHECK(ff_cbs_write_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) + +#define infer(name, value) do { \ + if (current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, \ + "%s does not match inferred value: " \ + "%"PRId64", but should be %"PRId64".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define more_rbsp_data(var) (var) + +#define bit_position(rw) (put_bits_count(rw)) +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + if (!name) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \ + "for writing.\n", #name); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define FUNC(name) FUNC_SEI_EXPORT(name) +#include "cbs_sei_syntax_template.c" +#undef FUNC + +static void cbs_free_user_data_registered(AVRefStructOpaque unused, void *obj) { SEIRawUserDataRegistered *udr = obj; - ff_refstruct_unref(&udr->data); + av_refstruct_unref(&udr->data_ref); } -static void cbs_free_user_data_unregistered(FFRefStructOpaque unused, void *obj) +static void cbs_free_user_data_unregistered(AVRefStructOpaque unused, void *obj) { SEIRawUserDataUnregistered *udu = obj; - ff_refstruct_unref(&udu->data); + av_refstruct_unref(&udu->data_ref); } int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message, const SEIMessageTypeDescriptor *desc) { - void (*free_func)(FFRefStructOpaque, void*); + void (*free_func)(AVRefStructOpaque, void*); av_assert0(message->payload == NULL && message->payload_ref == NULL); @@ -54,7 +254,7 @@ int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message, free_func = NULL; } - message->payload_ref = ff_refstruct_alloc_ext(desc->size, 0, + message->payload_ref = av_refstruct_alloc_ext(desc->size, 0, NULL, free_func); if (!message->payload_ref) return AVERROR(ENOMEM); @@ -92,8 +292,8 @@ void ff_cbs_sei_free_message_list(SEIRawMessageList *list) { for (int i = 0; i < list->nb_messages; i++) { SEIRawMessage *message = &list->messages[i]; - ff_refstruct_unref(&message->payload_ref); - ff_refstruct_unref(&message->extension_data); + av_refstruct_unref(&message->payload_ref); + av_refstruct_unref(&message->extension_data); } av_free(list->messages); } @@ -299,7 +499,7 @@ int ff_cbs_sei_add_message(CodedBitstreamContext *ctx, if (payload_ref) { /* The following just increments payload_ref's refcount, * so that payload_ref is now owned by us. */ - payload_ref = ff_refstruct_ref(payload_ref); + payload_ref = av_refstruct_ref(payload_ref); } message = &list->messages[list->nb_messages - 1]; @@ -352,8 +552,8 @@ static void cbs_sei_delete_message(SEIRawMessageList *list, av_assert0(0 <= position && position < list->nb_messages); message = &list->messages[position]; - ff_refstruct_unref(&message->payload_ref); - ff_refstruct_unref(&message->extension_data); + av_refstruct_unref(&message->payload_ref); + av_refstruct_unref(&message->extension_data); --list->nb_messages; @@ -384,3 +584,123 @@ void ff_cbs_sei_delete_message_type(CodedBitstreamContext *ctx, } } } + +// Macro for the read/write pair. +#define SEI_MESSAGE_RW(codec, name) \ + .read = cbs_ ## codec ## _read_ ## name ## _internal, \ + .write = cbs_ ## codec ## _write_ ## name ## _internal + +static const SEIMessageTypeDescriptor cbs_sei_common_types[] = { + { + SEI_TYPE_FILLER_PAYLOAD, + 1, 1, + sizeof(SEIRawFillerPayload), + SEI_MESSAGE_RW(sei, filler_payload), + }, + { + SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35, + 1, 1, + sizeof(SEIRawUserDataRegistered), + SEI_MESSAGE_RW(sei, user_data_registered), + }, + { + SEI_TYPE_USER_DATA_UNREGISTERED, + 1, 1, + sizeof(SEIRawUserDataUnregistered), + SEI_MESSAGE_RW(sei, user_data_unregistered), + }, + { + SEI_TYPE_FRAME_PACKING_ARRANGEMENT, + 1, 0, + sizeof(SEIRawFramePackingArrangement), + SEI_MESSAGE_RW(sei, frame_packing_arrangement), + }, + { + SEI_TYPE_DECODED_PICTURE_HASH, + 0, 1, + sizeof(SEIRawDecodedPictureHash), + SEI_MESSAGE_RW(sei, decoded_picture_hash), + }, + { + SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME, + 1, 0, + sizeof(SEIRawMasteringDisplayColourVolume), + SEI_MESSAGE_RW(sei, mastering_display_colour_volume), + }, + { + SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO, + 1, 0, + sizeof(SEIRawContentLightLevelInfo), + SEI_MESSAGE_RW(sei, content_light_level_info), + }, + { + SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS, + 1, 0, + sizeof(SEIRawAlternativeTransferCharacteristics), + SEI_MESSAGE_RW(sei, alternative_transfer_characteristics), + }, + { + SEI_TYPE_AMBIENT_VIEWING_ENVIRONMENT, + 1, 0, + sizeof(SEIRawAmbientViewingEnvironment), + SEI_MESSAGE_RW(sei, ambient_viewing_environment), + }, + SEI_MESSAGE_TYPE_END, +}; + +static const SEIMessageTypeDescriptor cbs_sei_h274_types[] = { + { + SEI_TYPE_FILM_GRAIN_CHARACTERISTICS, + 1, 0, + sizeof(SEIRawFilmGrainCharacteristics), + SEI_MESSAGE_RW(sei, film_grain_characteristics), + }, + { + SEI_TYPE_DISPLAY_ORIENTATION, + 1, 0, + sizeof(SEIRawDisplayOrientation), + SEI_MESSAGE_RW(sei, display_orientation) + }, + { + SEI_TYPE_FRAME_FIELD_INFO, + 1, 0, + sizeof(SEIRawFrameFieldInformation), + SEI_MESSAGE_RW(sei, frame_field_information) + }, + SEI_MESSAGE_TYPE_END, +}; + +const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx, + int payload_type) +{ + const SEIMessageTypeDescriptor *codec_list = NULL; + int i; + + switch (ctx->codec->codec_id) { +#if CBS_H264 + case AV_CODEC_ID_H264: + codec_list = ff_cbs_sei_h264_types; + break; +#endif +#if CBS_H265 + case AV_CODEC_ID_H265: + codec_list = ff_cbs_sei_h265_types; + break; +#endif + case AV_CODEC_ID_H266: + codec_list = cbs_sei_h274_types; + break; + } + + for (i = 0; codec_list && codec_list[i].type >= 0; i++) { + if (codec_list[i].type == payload_type) + return &codec_list[i]; + } + + for (i = 0; cbs_sei_common_types[i].type >= 0; i++) { + if (cbs_sei_common_types[i].type == payload_type) + return &cbs_sei_common_types[i]; + } + + return NULL; +} diff --git a/libavcodec/cbs_sei.h b/libavcodec/cbs_sei.h index 15ef3415a..e3e309710 100644 --- a/libavcodec/cbs_sei.h +++ b/libavcodec/cbs_sei.h @@ -33,13 +33,15 @@ typedef struct SEIRawFillerPayload { typedef struct SEIRawUserDataRegistered { uint8_t itu_t_t35_country_code; uint8_t itu_t_t35_country_code_extension_byte; - uint8_t *data; ///< RefStruct reference + uint8_t *data; + uint8_t *data_ref; ///< RefStruct reference size_t data_length; } SEIRawUserDataRegistered; typedef struct SEIRawUserDataUnregistered { uint8_t uuid_iso_iec_11578[16]; - uint8_t *data; ///< RefStruct reference + uint8_t *data; + uint8_t *data_ref; ///< RefStruct reference size_t data_length; } SEIRawUserDataUnregistered; @@ -97,6 +99,46 @@ typedef struct SEIRawAmbientViewingEnvironment { uint16_t ambient_light_y; } SEIRawAmbientViewingEnvironment; +typedef struct SEIRawFilmGrainCharacteristics { + uint8_t fg_characteristics_cancel_flag; + uint8_t fg_model_id; + uint8_t fg_separate_colour_description_present_flag; + uint8_t fg_bit_depth_luma_minus8; + uint8_t fg_bit_depth_chroma_minus8; + uint8_t fg_full_range_flag; + uint8_t fg_colour_primaries; + uint8_t fg_transfer_characteristics; + uint8_t fg_matrix_coeffs; + uint8_t fg_blending_mode_id; + uint8_t fg_log2_scale_factor; + uint8_t fg_comp_model_present_flag[3]; + uint8_t fg_num_intensity_intervals_minus1[3]; + uint8_t fg_num_model_values_minus1[3]; + uint8_t fg_intensity_interval_lower_bound[3][256]; + uint8_t fg_intensity_interval_upper_bound[3][256]; + int16_t fg_comp_model_value[3][256][6]; + uint8_t fg_characteristics_persistence_flag; +} SEIRawFilmGrainCharacteristics; + +typedef struct SEIRawDisplayOrientation { + uint8_t display_orientation_cancel_flag; + uint8_t display_orientation_persistence_flag; + uint8_t display_orientation_transform_type; + uint8_t display_orientation_reserved_zero_3bits; +} SEIRawDisplayOrientation; + +typedef struct SEIRawFrameFieldInformation { + uint8_t ffi_field_pic_flag; + uint8_t ffi_bottom_field_flag; + uint8_t ffi_pairing_indicated_flag; + uint8_t ffi_paired_with_next_field_flag; + uint8_t ffi_display_fields_from_frame_flag; + uint8_t ffi_top_field_first_flag; + uint8_t ffi_display_elemental_periods_minus1; + uint8_t ffi_source_scan_type; + uint8_t ffi_duplicate_flag; +} SEIRawFrameFieldInformation; + typedef struct SEIRawMessage { uint32_t payload_type; uint32_t payload_size; @@ -160,6 +202,9 @@ typedef struct SEIMessageTypeDescriptor { #define SEI_MESSAGE_TYPE_END { .type = -1 } +extern const SEIMessageTypeDescriptor ff_cbs_sei_h264_types[]; +extern const SEIMessageTypeDescriptor ff_cbs_sei_h265_types[]; + /** * Find the type descriptor for the given payload type. * @@ -221,4 +266,13 @@ void ff_cbs_sei_delete_message_type(CodedBitstreamContext *ctx, CodedBitstreamFragment *au, uint32_t payload_type); +int ff_cbs_sei_read_message_list(CodedBitstreamContext *ctx, struct GetBitContext *rw, + SEIRawMessageList *current, int prefix); +int ff_cbs_sei_write_message_list(CodedBitstreamContext *ctx, struct PutBitContext *rw, + SEIRawMessageList *current, int prefix); +int ff_cbs_sei_read_message(CodedBitstreamContext *ctx, struct GetBitContext *rw, + SEIRawMessage *current); +int ff_cbs_sei_write_message(CodedBitstreamContext *ctx, struct PutBitContext *rw, + SEIRawMessage *current); + #endif /* AVCODEC_CBS_SEI_H */ diff --git a/libavcodec/cbs_sei_syntax_template.c b/libavcodec/cbs_sei_syntax_template.c index 0205bb47a..4fc306172 100644 --- a/libavcodec/cbs_sei_syntax_template.c +++ b/libavcodec/cbs_sei_syntax_template.c @@ -57,9 +57,16 @@ SEI_FUNC(user_data_registered, (CodedBitstreamContext *ctx, RWContext *rw, return AVERROR_INVALIDDATA; } current->data_length = state->payload_size - i; -#endif + allocate(current->data_ref, state->payload_size); + current->data = current->data_ref; + + *current->data++ = current->itu_t_t35_country_code; + if (current->itu_t_t35_country_code == 0xff) + *current->data++ = current->itu_t_t35_country_code_extension_byte; +#else allocate(current->data, current->data_length); +#endif for (j = 0; j < current->data_length; j++) xu(8, itu_t_t35_payload_byte[], current->data[j], 0x00, 0xff, 1, i + j); @@ -86,7 +93,13 @@ SEI_FUNC(user_data_unregistered, (CodedBitstreamContext *ctx, RWContext *rw, for (i = 0; i < 16; i++) us(8, uuid_iso_iec_11578[i], 0x00, 0xff, 1, i); +#ifdef READ + allocate(current->data_ref, state->payload_size); + memcpy(current->data_ref, current->uuid_iso_iec_11578, sizeof(current->uuid_iso_iec_11578)); + current->data = current->data_ref + 16; +#else allocate(current->data, current->data_length); +#endif for (i = 0; i < current->data_length; i++) xu(8, user_data_payload_byte[i], current->data[i], 0x00, 0xff, 1, i); @@ -224,7 +237,104 @@ SEI_FUNC(ambient_viewing_environment, return 0; } -static int FUNC(message)(CodedBitstreamContext *ctx, RWContext *rw, +SEI_FUNC(film_grain_characteristics, + (CodedBitstreamContext *ctx, RWContext *rw, + SEIRawFilmGrainCharacteristics *current, + SEIMessageState *state)) +{ + int err, c, i, j; + + HEADER("Film Grain Characteristics"); + + flag(fg_characteristics_cancel_flag); + if (!current->fg_characteristics_cancel_flag) { + int filmGrainBitDepth[3]; + + u(2, fg_model_id, 0, 1); + flag(fg_separate_colour_description_present_flag); + if (current->fg_separate_colour_description_present_flag) { + ub(3, fg_bit_depth_luma_minus8); + ub(3, fg_bit_depth_chroma_minus8); + flag(fg_full_range_flag); + ub(8, fg_colour_primaries); + ub(8, fg_transfer_characteristics); + ub(8, fg_matrix_coeffs); + } + + filmGrainBitDepth[0] = current->fg_bit_depth_luma_minus8 + 8; + filmGrainBitDepth[1] = + filmGrainBitDepth[2] = current->fg_bit_depth_chroma_minus8 + 8; + + u(2, fg_blending_mode_id, 0, 1); + ub(4, fg_log2_scale_factor); + for (c = 0; c < 3; c++) + flags(fg_comp_model_present_flag[c], 1, c); + + for (c = 0; c < 3; c++) { + if (current->fg_comp_model_present_flag[c]) { + ubs(8, fg_num_intensity_intervals_minus1[c], 1, c); + us(3, fg_num_model_values_minus1[c], 0, 5, 1, c); + for (i = 0; i <= current->fg_num_intensity_intervals_minus1[c]; i++) { + ubs(8, fg_intensity_interval_lower_bound[c][i], 2, c, i); + ubs(8, fg_intensity_interval_upper_bound[c][i], 2, c, i); + for (j = 0; j <= current->fg_num_model_values_minus1[c]; j++) + ses(fg_comp_model_value[c][i][j], 0 - current->fg_model_id * (1 << (filmGrainBitDepth[c] - 1)), + ((1 << filmGrainBitDepth[c]) - 1) - current->fg_model_id * (1 << (filmGrainBitDepth[c] - 1)), + 3, c, i, j); + } + } + } + flag(fg_characteristics_persistence_flag); + } + + return 0; +} + +SEI_FUNC(display_orientation, (CodedBitstreamContext *ctx, RWContext *rw, + SEIRawDisplayOrientation *current, + SEIMessageState *state)) +{ + int err; + + HEADER("Display Orientation"); + + flag(display_orientation_cancel_flag); + if (!current->display_orientation_cancel_flag) { + flag(display_orientation_persistence_flag); + u(3, display_orientation_transform_type, 0, 7); + ub(3, display_orientation_reserved_zero_3bits); + } + + return 0; +} + +SEI_FUNC(frame_field_information, (CodedBitstreamContext *ctx, RWContext *rw, + SEIRawFrameFieldInformation *current, + SEIMessageState *state)) +{ + int err; + + HEADER("Frame-field information"); + + flag(ffi_field_pic_flag); + if (current->ffi_field_pic_flag) { + flag(ffi_bottom_field_flag); + flag(ffi_pairing_indicated_flag); + if (current->ffi_pairing_indicated_flag) + flag(ffi_paired_with_next_field_flag); + } else { + flag(ffi_display_fields_from_frame_flag); + if (current->ffi_display_fields_from_frame_flag) + flag(ffi_top_field_first_flag); + u(8, ffi_display_elemental_periods_minus1, 0, 0xff); + } + u(2, ffi_source_scan_type, 0, 3); + flag(ffi_duplicate_flag); + + return 0; +} + +int FUNC(message)(CodedBitstreamContext *ctx, RWContext *rw, SEIRawMessage *current) { const SEIMessageTypeDescriptor *desc; @@ -312,7 +422,7 @@ static int FUNC(message)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } -static int FUNC(message_list)(CodedBitstreamContext *ctx, RWContext *rw, +int FUNC(message_list)(CodedBitstreamContext *ctx, RWContext *rw, SEIRawMessageList *current, int prefix) { SEIRawMessage *message; @@ -361,7 +471,7 @@ static int FUNC(message_list)(CodedBitstreamContext *ctx, RWContext *rw, skip_bits_long(rw, 8 * payload_size); - if (!cbs_h2645_read_more_rbsp_data(rw)) + if (!ff_cbs_h2645_read_more_rbsp_data(rw)) break; } #else diff --git a/libavcodec/cbs_vp8.c b/libavcodec/cbs_vp8.c index 1f80f34fa..7724cb3d7 100644 --- a/libavcodec/cbs_vp8.c +++ b/libavcodec/cbs_vp8.c @@ -366,7 +366,7 @@ static int cbs_vp8_assemble_fragment(CodedBitstreamContext *ctx, return AVERROR_PATCHWELCOME; } -static const CodedBitstreamUnitTypeDescriptor cbs_vp8_unit_types[] = { +static CodedBitstreamUnitTypeDescriptor cbs_vp8_unit_types[] = { CBS_UNIT_TYPE_INTERNAL_REF(0, VP8RawFrame, data), CBS_UNIT_TYPE_END_OF_LIST, }; diff --git a/libavcodec/cbs_vp9.c b/libavcodec/cbs_vp9.c index ff99fe32f..37015f5c7 100644 --- a/libavcodec/cbs_vp9.c +++ b/libavcodec/cbs_vp9.c @@ -415,7 +415,7 @@ static int cbs_vp9_split_fragment(CodedBitstreamContext *ctx, } if (pos + index_size != frag->data_size) { av_log(ctx->log_ctx, AV_LOG_WARNING, "Extra padding at " - "end of superframe: %"SIZE_SPECIFIER" bytes.\n", + "end of superframe: %zu bytes.\n", frag->data_size - (pos + index_size)); } @@ -587,14 +587,14 @@ static int cbs_vp9_assemble_fragment(CodedBitstreamContext *ctx, return 0; } -static void cbs_vp9_flush(CodedBitstreamContext *ctx) +static av_cold void cbs_vp9_flush(CodedBitstreamContext *ctx) { CodedBitstreamVP9Context *vp9 = ctx->priv_data; memset(vp9->ref, 0, sizeof(vp9->ref)); } -static const CodedBitstreamUnitTypeDescriptor cbs_vp9_unit_types[] = { +static CodedBitstreamUnitTypeDescriptor cbs_vp9_unit_types[] = { CBS_UNIT_TYPE_INTERNAL_REF(0, VP9RawFrame, data), CBS_UNIT_TYPE_END_OF_LIST }; diff --git a/libavcodec/cbs_vp9.h b/libavcodec/cbs_vp9.h index af15eb4ba..588765b87 100644 --- a/libavcodec/cbs_vp9.h +++ b/libavcodec/cbs_vp9.h @@ -206,6 +206,14 @@ typedef struct CodedBitstreamVP9Context { uint8_t subsampling_y; int bit_depth; + int8_t loop_filter_ref_deltas[VP9_MAX_REF_FRAMES]; + int8_t loop_filter_mode_deltas[2]; + uint8_t segmentation_tree_probs[7]; + uint8_t segmentation_pred_prob[3]; + uint8_t feature_enabled[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + uint8_t feature_value[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + uint8_t feature_sign[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + VP9ReferenceFrameState ref[VP9_NUM_REF_FRAMES]; } CodedBitstreamVP9Context; diff --git a/libavcodec/cbs_vp9_syntax_template.c b/libavcodec/cbs_vp9_syntax_template.c index 2f08eccf1..0669cbed0 100644 --- a/libavcodec/cbs_vp9_syntax_template.c +++ b/libavcodec/cbs_vp9_syntax_template.c @@ -172,6 +172,8 @@ static int FUNC(loop_filter_params)(CodedBitstreamContext *ctx, RWContext *rw, ss(6, loop_filter_mode_deltas[i], 1, i); } } + } else { + infer(loop_filter_delta_update, 0); } return 0; @@ -196,7 +198,6 @@ static int FUNC(segmentation_params)(CodedBitstreamContext *ctx, RWContext *rw, { static const uint8_t segmentation_feature_bits[VP9_SEG_LVL_MAX] = { 8, 6, 2, 0 }; static const uint8_t segmentation_feature_signed[VP9_SEG_LVL_MAX] = { 1, 1, 0, 0 }; - int err, i, j; f(1, segmentation_enabled); @@ -236,6 +237,8 @@ static int FUNC(segmentation_params)(CodedBitstreamContext *ctx, RWContext *rw, } } } + } else { + infer(segmentation_update_data, 0); } return 0; @@ -371,6 +374,58 @@ static int FUNC(uncompressed_header)(CodedBitstreamContext *ctx, RWContext *rw, } } + // Update top-level loop filter and segmentation state with changes + // from this frame. + if (current->frame_type == VP9_KEY_FRAME || + current->intra_only || + current->error_resilient_mode) { + // setup_past_independence() - fill with the initial values. + + vp9->loop_filter_ref_deltas[VP9_INTRA_FRAME] = 1; + vp9->loop_filter_ref_deltas[VP9_LAST_FRAME] = 0; + vp9->loop_filter_ref_deltas[VP9_GOLDEN_FRAME] = -1; + vp9->loop_filter_ref_deltas[VP9_ALTREF_FRAME] = -1; + + vp9->loop_filter_mode_deltas[0] = 0; + vp9->loop_filter_mode_deltas[1] = 0; + + memset(vp9->feature_enabled, 0, sizeof(vp9->feature_enabled)); + memset(vp9->feature_value, 0, sizeof(vp9->feature_value)); + memset(vp9->feature_sign, 0, sizeof(vp9->feature_sign)); + } + + // Modify previous state based on updates in this frame. + if (current->loop_filter_delta_update) { + for (i = 0; i < 4; i++) { + if (current->update_ref_delta[i]) + vp9->loop_filter_ref_deltas[i] = + current->loop_filter_ref_deltas[i]; + } + for (i = 0; i < 2; i++) { + if (current->update_mode_delta[i]) + vp9->loop_filter_mode_deltas[i] = + current->loop_filter_mode_deltas[i]; + } + } + + if (current->segmentation_update_data) { + memcpy(vp9->feature_enabled, current->feature_enabled, + sizeof(vp9->feature_enabled)); + memcpy(vp9->feature_value, current->feature_value, + sizeof(vp9->feature_value)); + memcpy(vp9->feature_sign, current->feature_sign, + sizeof(vp9->feature_sign)); + + if (current->segmentation_update_map) { + memcpy(vp9->segmentation_tree_probs, + current->segmentation_tree_probs, + sizeof(vp9->segmentation_tree_probs)); + memcpy(vp9->segmentation_pred_prob, + current->segmentation_pred_prob, + sizeof(vp9->segmentation_pred_prob)); + } + } + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Frame: size %dx%d " "subsample %dx%d bit_depth %d tiles %dx%d.\n", vp9->frame_width, vp9->frame_height, diff --git a/libavcodec/ccaption_dec.c b/libavcodec/ccaption_dec.c index d8b992bb9..9b6c766d8 100644 --- a/libavcodec/ccaption_dec.c +++ b/libavcodec/ccaption_dec.c @@ -23,6 +23,7 @@ #include "avcodec.h" #include "ass.h" #include "codec_internal.h" +#include "libavutil/attributes.h" #include "libavutil/opt.h" #define SCREEN_ROWS 15 @@ -253,6 +254,7 @@ struct Screen { typedef struct CCaptionSubContext { AVClass *class; + void *logctx; int real_time; int real_time_latency_msec; int data_field; @@ -280,6 +282,8 @@ static av_cold int init_decoder(AVCodecContext *avctx) { CCaptionSubContext *ctx = avctx->priv_data; + ctx->logctx = avctx; + av_bprint_init(&ctx->buffer[0], 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&ctx->buffer[1], 0, AV_BPRINT_SIZE_UNLIMITED); /* taking by default roll up to 2 */ @@ -306,7 +310,7 @@ static av_cold int close_decoder(AVCodecContext *avctx) return 0; } -static void flush_decoder(AVCodecContext *avctx) +static av_cold void flush_decoder(AVCodecContext *avctx) { CCaptionSubContext *ctx = avctx->priv_data; ctx->screen[0].row_used = 0; @@ -359,7 +363,7 @@ static void write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch) return; } else { - av_log(ctx, AV_LOG_WARNING, "Data ignored due to columns exceeding screen width\n"); + av_log(ctx->logctx, AV_LOG_WARNING, "Data ignored due to columns exceeding screen width\n"); return; } } @@ -649,7 +653,7 @@ static void handle_pac(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) int indent, i; if (row_map[index] <= 0) { - av_log(ctx, AV_LOG_DEBUG, "Invalid pac index encountered\n"); + av_log(ctx->logctx, AV_LOG_DEBUG, "Invalid pac index encountered\n"); return; } @@ -749,9 +753,9 @@ static void handle_char(CCaptionSubContext *ctx, char hi, char lo) ctx->screen_touched = 1; if (lo) - ff_dlog(ctx, "(%c,%c)\n", hi, lo); + ff_dlog(ctx->logctx, "(%c,%c)\n", hi, lo); else - ff_dlog(ctx, "(%c)\n", hi); + ff_dlog(ctx->logctx, "(%c)\n", hi); } static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) @@ -803,7 +807,7 @@ static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) break; case 0x2d: /* carriage return */ - ff_dlog(ctx, "carriage return\n"); + ff_dlog(ctx->logctx, "carriage return\n"); if (!ctx->real_time) ret = capture_screen(ctx); roll_up(ctx); @@ -811,7 +815,7 @@ static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) break; case 0x2e: /* erase buffered (non displayed) memory */ - // Only in realtime mode. In buffered mode, we re-use the inactive screen + // Only in realtime mode. In buffered mode, we reuse the inactive screen // for our own buffering. if (ctx->real_time) { struct Screen *screen = ctx->screen + !ctx->active_screen; @@ -820,11 +824,11 @@ static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) break; case 0x2f: /* end of caption */ - ff_dlog(ctx, "handle_eoc\n"); + ff_dlog(ctx->logctx, "handle_eoc\n"); ret = handle_eoc(ctx); break; default: - ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo); + ff_dlog(ctx->logctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo); break; } } else if (hi >= 0x11 && hi <= 0x13) { @@ -842,7 +846,7 @@ static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) } } else { /* Ignoring all other non data code */ - ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo); + ff_dlog(ctx->logctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo); } return ret; @@ -888,7 +892,7 @@ static int decode(AVCodecContext *avctx, AVSubtitle *sub, update_time(ctx, in_time); if (ctx->buffer[bidx].str[0] || ctx->real_time) { - ff_dlog(ctx, "cdp writing data (%s)\n", ctx->buffer[bidx].str); + ff_dlog(avctx, "cdp writing data (%s)\n", ctx->buffer[bidx].str); start_time = ctx->buffer_time[0]; sub->pts = start_time; end_time = ctx->buffer_time[1]; diff --git a/libavcodec/cdgraphics.c b/libavcodec/cdgraphics.c index f33f7fbf0..1b5a37875 100644 --- a/libavcodec/cdgraphics.c +++ b/libavcodec/cdgraphics.c @@ -24,6 +24,8 @@ #include "codec_internal.h" #include "decode.h" +#include "libavutil/attributes.h" + /** * @file * @brief CD Graphics Video Decoder @@ -125,11 +127,6 @@ static void cdg_load_palette(CDGraphicsContext *cc, uint8_t *data, int low) b = ((color ) & 0x000F) * 17; palette[i + array_offset] = (uint32_t)cc->alpha[i + array_offset] << 24 | r << 16 | g << 8 | b; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - cc->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } static int cdg_tile_block(CDGraphicsContext *cc, uint8_t *data, int b) @@ -372,7 +369,7 @@ static int cdg_decode_frame(AVCodecContext *avctx, AVFrame *frame, return avpkt->size; } -static void cdg_decode_flush(AVCodecContext *avctx) +static av_cold void cdg_decode_flush(AVCodecContext *avctx) { CDGraphicsContext *cc = avctx->priv_data; diff --git a/libavcodec/cdtoons.c b/libavcodec/cdtoons.c index 89b6d76d8..f96c89115 100644 --- a/libavcodec/cdtoons.c +++ b/libavcodec/cdtoons.c @@ -385,11 +385,6 @@ static int cdtoons_decode_frame(AVCodecContext *avctx, AVFrame *rframe, } /* first palette entry indicates transparency */ c->pal[0] = 0; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - c->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } } @@ -425,7 +420,7 @@ static av_cold int cdtoons_decode_init(AVCodecContext *avctx) return 0; } -static void cdtoons_flush(AVCodecContext *avctx) +static av_cold void cdtoons_flush(AVCodecContext *avctx) { CDToonsContext *c = avctx->priv_data; diff --git a/libavcodec/celp_filters.c b/libavcodec/celp_filters.c index 4f627e009..d3381e3ee 100644 --- a/libavcodec/celp_filters.c +++ b/libavcodec/celp_filters.c @@ -25,6 +25,7 @@ #include "config.h" #include "celp_filters.h" +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/common.h" @@ -210,7 +211,7 @@ void ff_celp_lp_zero_synthesis_filterf(float *out, const float *filter_coeffs, } } -void ff_celp_filter_init(CELPFContext *c) +void av_cold ff_celp_filter_init(CELPFContext *c) { c->celp_lp_synthesis_filterf = ff_celp_lp_synthesis_filterf; c->celp_lp_zero_synthesis_filterf = ff_celp_lp_zero_synthesis_filterf; diff --git a/libavcodec/celp_math.c b/libavcodec/celp_math.c index a5fe7f2ea..658937dcc 100644 --- a/libavcodec/celp_math.c +++ b/libavcodec/celp_math.c @@ -23,12 +23,16 @@ #include #include "config.h" -#include "libavutil/avassert.h" + +#include "libavutil/attributes.h" +#include "libavutil/float_dsp.h" #include "libavutil/intmath.h" #include "mathops.h" #include "celp_math.h" #ifdef G729_BITEXACT +#include "libavutil/avassert.h" + static const uint16_t exp2a[]= { 0, 1435, 2901, 4400, 5931, 7496, 9096, 10730, @@ -107,20 +111,9 @@ int64_t ff_dot_product(const int16_t *a, const int16_t *b, int length) return sum; } -float ff_dot_productf(const float* a, const float* b, int length) +av_cold void ff_celp_math_init(CELPMContext *c) { - float sum = 0; - int i; - - for(i=0; idot_productf = ff_dot_productf; + c->dot_productf = ff_scalarproduct_float_c; #if HAVE_MIPSFPU ff_celp_math_init_mips(c); diff --git a/libavcodec/celp_math.h b/libavcodec/celp_math.h index 99a047071..8228d560e 100644 --- a/libavcodec/celp_math.h +++ b/libavcodec/celp_math.h @@ -84,14 +84,4 @@ static inline unsigned bidir_sal(unsigned value, int offset) else return value << offset; } -/** - * Return the dot product. - * @param a input data array - * @param b input data array - * @param length number of elements - * - * @return dot product = sum of elementwise products - */ -float ff_dot_productf(const float* a, const float* b, int length); - #endif /* AVCODEC_CELP_MATH_H */ diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c index 30a25c9c7..4d430e32e 100644 --- a/libavcodec/cfhd.c +++ b/libavcodec/cfhd.c @@ -118,10 +118,8 @@ static inline int dequant_and_decompand(CFHDContext *s, int level, int quantisat static inline void difference_coding(int16_t *band, int width, int height) { - - int i,j; - for (i = 0; i < height; i++) { - for (j = 1; j < width; j++) { + for (int i = 0; i < height; i++) { + for (int j = 1; j < width; j++) { band[j] += band[j-1]; } band += width; @@ -130,17 +128,15 @@ static inline void difference_coding(int16_t *band, int width, int height) static inline void peak_table(int16_t *band, Peak *peak, int length) { - int i; - for (i = 0; i < length; i++) + for (int i = 0; i < length; i++) if (abs(band[i]) > peak->level) band[i] = bytestream2_get_le16(&peak->base); } static inline void process_alpha(int16_t *alpha, int width) { - int i, channel; - for (i = 0; i < width; i++) { - channel = alpha[i]; + for (int i = 0; i < width; i++) { + int channel = alpha[i]; channel -= ALPHA_COMPAND_DC_OFFSET; channel <<= 3; channel *= ALPHA_COMPAND_GAIN; @@ -197,11 +193,9 @@ static inline void process_bayer(AVFrame *frame, int bpc) static inline void interlaced_vertical_filter(int16_t *output, int16_t *low, int16_t *high, int width, int linesize, int plane) { - int i; - int16_t even, odd; - for (i = 0; i < width; i++) { - even = (low[i] - high[i])/2; - odd = (low[i] + high[i])/2; + for (int i = 0; i < width; i++) { + int16_t even = (low[i] - high[i])/2; + int16_t odd = (low[i] + high[i])/2; output[i] = av_clip_uintp2(even, 10); output[i + linesize] = av_clip_uintp2(odd, 10); } @@ -220,21 +214,19 @@ static inline void inverse_temporal_filter(int16_t *low, int16_t *high, int widt static void free_buffers(CFHDContext *s) { - int i, j; - - for (i = 0; i < FF_ARRAY_ELEMS(s->plane); i++) { + for (size_t i = 0; i < FF_ARRAY_ELEMS(s->plane); i++) { Plane *p = &s->plane[i]; av_freep(&s->plane[i].idwt_buf); av_freep(&s->plane[i].idwt_tmp); s->plane[i].idwt_size = 0; - for (j = 0; j < SUBBAND_COUNT_3D; j++) + for (int j = 0; j < SUBBAND_COUNT_3D; j++) s->plane[i].subband[j] = NULL; - for (j = 0; j < 10; j++) + for (int j = 0; j < 10; j++) s->plane[i].l_h[j] = NULL; - for (j = 0; j < DWT_LEVELS_3D; j++) + for (int j = 0; j < DWT_LEVELS_3D; j++) p->band[j][0].read_ok = p->band[j][1].read_ok = p->band[j][2].read_ok = @@ -248,9 +240,8 @@ static void free_buffers(CFHDContext *s) static int alloc_buffers(AVCodecContext *avctx) { CFHDContext *s = avctx->priv_data; - int i, j, ret, planes, bayer = 0; + int ret, planes, bayer = 0; int chroma_x_shift, chroma_y_shift; - unsigned k; if ((ret = ff_set_dimensions(avctx, s->coded_width, s->coded_height)) < 0) return ret; @@ -270,7 +261,7 @@ static int alloc_buffers(AVCodecContext *avctx) bayer = 1; } - for (i = 0; i < planes; i++) { + for (int i = 0; i < planes; i++) { int w8, h8, w4, h4, w2, h2; int width = (i || bayer) ? s->coded_width >> chroma_x_shift : s->coded_width; int height = (i || bayer) ? s->coded_height >> chroma_y_shift : s->coded_height; @@ -335,17 +326,17 @@ static int alloc_buffers(AVCodecContext *avctx) } if (s->transform_type == 0) { - for (j = 0; j < DWT_LEVELS; j++) { - for (k = 0; k < FF_ARRAY_ELEMS(s->plane[i].band[j]); k++) { + for (int j = 0; j < DWT_LEVELS; j++) { + for (unsigned k = 0; k < FF_ARRAY_ELEMS(s->plane[i].band[j]); k++) { s->plane[i].band[j][k].a_width = w8 << j; s->plane[i].band[j][k].a_height = h8 << j; } } } else { - for (j = 0; j < DWT_LEVELS_3D; j++) { + for (int j = 0; j < DWT_LEVELS_3D; j++) { int t = j < 1 ? 0 : (j < 3 ? 1 : 2); - for (k = 0; k < FF_ARRAY_ELEMS(s->plane[i].band[j]); k++) { + for (unsigned k = 0; k < FF_ARRAY_ELEMS(s->plane[i].band[j]); k++) { s->plane[i].band[j][k].a_width = w8 << t; s->plane[i].band[j][k].a_height = h8 << t; } @@ -383,8 +374,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, CFHDContext *s = avctx->priv_data; CFHDDSPContext *dsp = &s->dsp; GetByteContext gb; - int ret = 0, i, j, plane, got_buffer = 0; - int16_t *coeff_data; + int ret = 0, got_buffer = 0; init_frame_defaults(s); s->planes = av_pix_fmt_count_planes(s->coded_format); @@ -399,6 +389,8 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, uint16_t abstag = abs(tag); int8_t abs_tag8 = abs(tag8); uint16_t data = bytestream2_get_be16(&gb); + int16_t *coeff_data; + if (abs_tag8 >= 0x60 && abs_tag8 <= 0x6f) { av_log(avctx, AV_LOG_DEBUG, "large len %x\n", ((tagu & 0xff) << 16) | data); } else if (tag == SampleFlags) { @@ -481,7 +473,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, s->quantisation = data; av_log(avctx, AV_LOG_DEBUG, "Quantisation: %"PRIu16"\n", data); } else if (tag == PrescaleTable) { - for (i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) s->prescale_table[i] = (data >> (14 - i * 2)) & 0x3; av_log(avctx, AV_LOG_DEBUG, "Prescale table: %x\n", data); } else if (tag == BandEncoding) { @@ -533,7 +525,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, ret = AVERROR_INVALIDDATA; goto end; } - for (i = 0; i < data; i++) { + for (int i = 0; i < data; i++) { uint32_t offset = bytestream2_get_be32(&gb); av_log(avctx, AV_LOG_DEBUG, "Offset = %"PRIu32"\n", offset); } @@ -755,8 +747,8 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, } av_log(avctx, AV_LOG_DEBUG, "Start of lowpass coeffs component %d height:%d, width:%d\n", s->channel_num, lowpass_height, lowpass_width); - for (i = 0; i < lowpass_height; i++) { - for (j = 0; j < lowpass_width; j++) + for (int i = 0; i < lowpass_height; i++) { + for (int j = 0; j < lowpass_width; j++) coeff_data[j] = bytestream2_get_be16u(&gb); coeff_data += lowpass_width; @@ -781,7 +773,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, if (tag == BandHeader || tag == BandSecondPass) { int highpass_height, highpass_width, highpass_a_width, highpass_a_height, highpass_stride, a_expected; int expected; - int level, run, coeff; + GetBitContext gbit; int count = 0, bytes; if (!s->a_width || !s->a_height) { @@ -811,11 +803,11 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, av_log(avctx, AV_LOG_DEBUG, "Start subband coeffs plane %i level %i codebook %i expected %i\n", s->channel_num, s->level, s->codebook, expected); - ret = init_get_bits8(&s->gb, gb.buffer, bytestream2_get_bytes_left(&gb)); + ret = init_get_bits8(&gbit, gb.buffer, bytestream2_get_bytes_left(&gb)); if (ret < 0) goto end; { - OPEN_READER(re, &s->gb); + OPEN_READER(re, &gbit); const int lossless = s->band_encoding == 5; @@ -823,8 +815,10 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, s->codebook = 1; if (!s->codebook) { while (1) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, s->table_9_rl_vlc, + int level, run, coeff; + + UPDATE_CACHE(re, &gbit); + GET_RL_VLC(level, run, re, &gbit, s->table_9_rl_vlc, VLC_BITS, 3, 1); /* escape */ @@ -843,19 +837,21 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, if (tag == BandSecondPass) { const uint16_t q = s->quantisation; - for (i = 0; i < run; i++) { + for (int i = 0; i < run; i++) { *coeff_data |= coeff * 256U; *coeff_data++ *= q; } } else { - for (i = 0; i < run; i++) + for (int i = 0; i < run; i++) *coeff_data++ = coeff; } } } else { while (1) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, s->table_18_rl_vlc, + int level, run, coeff; + + UPDATE_CACHE(re, &gbit); + GET_RL_VLC(level, run, re, &gbit, s->table_18_rl_vlc, VLC_BITS, 3, 1); /* escape */ @@ -874,17 +870,17 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, if (tag == BandSecondPass) { const uint16_t q = s->quantisation; - for (i = 0; i < run; i++) { + for (int i = 0; i < run; i++) { *coeff_data |= coeff * 256U; *coeff_data++ *= q; } } else { - for (i = 0; i < run; i++) + for (int i = 0; i < run; i++) *coeff_data++ = coeff; } } } - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &gbit); } if (count > expected) { @@ -897,7 +893,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, if (s->difference_coding) difference_coding(s->plane[s->channel_num].subband[s->subband_num_actual], highpass_width, highpass_height); - bytes = FFALIGN(AV_CEIL_RSHIFT(get_bits_count(&s->gb), 3), 4); + bytes = FFALIGN(AV_CEIL_RSHIFT(get_bits_count(&gbit), 3), 4); if (bytes > bytestream2_get_bytes_left(&gb)) { av_log(avctx, AV_LOG_ERROR, "Bitstream overread error\n"); ret = AVERROR(EINVAL); @@ -935,14 +931,12 @@ finish: goto end; } - for (plane = 0; plane < s->planes; plane++) { - int o, level; - - for (level = 0; level < (s->transform_type == 0 ? DWT_LEVELS : DWT_LEVELS_3D) ; level++) { + for (int plane = 0; plane < s->planes; plane++) { + for (int level = 0; level < (s->transform_type == 0 ? DWT_LEVELS : DWT_LEVELS_3D) ; level++) { if (s->transform_type == 2) if (level == 2 || level == 5) continue; - for (o = !!level; o < 4 ; o++) { + for (int o = !!level; o < 4 ; o++) { if (!s->plane[plane].band[level][o].read_ok) { ret = AVERROR_INVALIDDATA; goto end; @@ -952,7 +946,7 @@ finish: } if (s->transform_type == 0 && s->sample_type != 1) { - for (plane = 0; plane < s->planes && !ret; plane++) { + for (int plane = 0; plane < s->planes && !ret; plane++) { /* level 1 */ int lowpass_height = s->plane[plane].band[0][0].height; int output_stride = s->plane[plane].band[0][0].a_width; @@ -996,8 +990,8 @@ finish: dsp->horiz_filter(output, output_stride, low, output_stride, high, output_stride, lowpass_width, lowpass_height * 2); if (s->bpc == 12) { output = s->plane[plane].subband[0]; - for (i = 0; i < lowpass_height * 2; i++) { - for (j = 0; j < lowpass_width * 2; j++) + for (int i = 0; i < lowpass_height * 2; i++) { + for (int j = 0; j < lowpass_width * 2; j++) output[j] *= 4; output += output_stride * 2; @@ -1036,8 +1030,8 @@ finish: dsp->horiz_filter(output, output_stride, low, output_stride, high, output_stride, lowpass_width, lowpass_height * 2); output = s->plane[plane].subband[0]; - for (i = 0; i < lowpass_height * 2; i++) { - for (j = 0; j < lowpass_width * 2; j++) + for (int i = 0; i < lowpass_height * 2; i++) { + for (int j = 0; j < lowpass_width * 2; j++) output[j] *= 4; output += output_stride * 2; @@ -1087,7 +1081,7 @@ finish: goto end; } - for (i = 0; i < s->plane[act_plane].height; i++) { + for (int i = 0; i < s->plane[act_plane].height; i++) { dsp->horiz_filter_clip(dst, low, high, lowpass_width, s->bpc); if (avctx->pix_fmt == AV_PIX_FMT_GBRAP12 && act_plane == 3) process_alpha(dst, lowpass_width * 2); @@ -1111,7 +1105,7 @@ finish: dst = (int16_t *)pic->data[act_plane]; low = s->plane[plane].l_h[6]; high = s->plane[plane].l_h[7]; - for (i = 0; i < s->plane[act_plane].height / 2; i++) { + for (int i = 0; i < s->plane[act_plane].height / 2; i++) { interlaced_vertical_filter(dst, low, high, lowpass_width * 2, pic->linesize[act_plane]/2, act_plane); low += output_stride * 2; high += output_stride * 2; @@ -1120,7 +1114,7 @@ finish: } } } else if (s->transform_type == 2 && (avctx->internal->is_copy || s->frame_index == 1 || s->sample_type != 1)) { - for (plane = 0; plane < s->planes && !ret; plane++) { + for (int plane = 0; plane < s->planes && !ret; plane++) { int lowpass_height = s->plane[plane].band[0][0].height; int output_stride = s->plane[plane].band[0][0].a_width; int lowpass_width = s->plane[plane].band[0][0].width; @@ -1162,8 +1156,8 @@ finish: dsp->horiz_filter(output, output_stride, low, output_stride, high, output_stride, lowpass_width, lowpass_height * 2); if (s->bpc == 12) { output = s->plane[plane].l_h[7]; - for (i = 0; i < lowpass_height * 2; i++) { - for (j = 0; j < lowpass_width * 2; j++) + for (int i = 0; i < lowpass_height * 2; i++) { + for (int j = 0; j < lowpass_width * 2; j++) output[j] *= 4; output += output_stride * 2; @@ -1201,8 +1195,8 @@ finish: dsp->horiz_filter(output, output_stride, low, output_stride, high, output_stride, lowpass_width, lowpass_height * 2); output = s->plane[plane].l_h[7]; - for (i = 0; i < lowpass_height * 2; i++) { - for (j = 0; j < lowpass_width * 2; j++) + for (int i = 0; i < lowpass_height * 2; i++) { + for (int j = 0; j < lowpass_width * 2; j++) output[j] *= 4; output += output_stride * 2; } @@ -1239,7 +1233,7 @@ finish: low = s->plane[plane].l_h[7]; high = s->plane[plane].l_h[9]; output = s->plane[plane].l_h[7]; - for (i = 0; i < lowpass_height; i++) { + for (int i = 0; i < lowpass_height; i++) { inverse_temporal_filter(low, high, lowpass_width); low += output_stride; high += output_stride; @@ -1286,7 +1280,7 @@ finish: low = s->plane[plane].l_h[6]; high = s->plane[plane].l_h[7]; - for (i = 0; i < s->plane[act_plane].height; i++) { + for (int i = 0; i < s->plane[act_plane].height; i++) { dsp->horiz_filter_clip(dst, low, high, lowpass_width, s->bpc); low += output_stride; high += output_stride; @@ -1320,7 +1314,7 @@ finish: dst = (int16_t *)pic->data[act_plane]; low = s->plane[plane].l_h[6]; high = s->plane[plane].l_h[7]; - for (i = 0; i < s->plane[act_plane].height / 2; i++) { + for (int i = 0; i < s->plane[act_plane].height / 2; i++) { interlaced_vertical_filter(dst, low, high, lowpass_width * 2, pic->linesize[act_plane]/2, act_plane); low += output_stride * 2; high += output_stride * 2; @@ -1335,7 +1329,7 @@ finish: int output_stride, lowpass_height, lowpass_width; ptrdiff_t dst_linesize; - for (plane = 0; plane < s->planes; plane++) { + for (int plane = 0; plane < s->planes; plane++) { int act_plane = plane == 1 ? 2 : plane == 2 ? 1 : plane; if (avctx->pix_fmt == AV_PIX_FMT_BAYER_RGGB16) { @@ -1377,7 +1371,7 @@ finish: goto end; } - for (i = 0; i < s->plane[act_plane].height; i++) { + for (int i = 0; i < s->plane[act_plane].height; i++) { dsp->horiz_filter_clip(dst, low, high, lowpass_width, s->bpc); low += output_stride; high += output_stride; @@ -1387,7 +1381,7 @@ finish: dst = (int16_t *)pic->data[act_plane]; low = s->plane[plane].l_h[8]; high = s->plane[plane].l_h[9]; - for (i = 0; i < s->plane[act_plane].height / 2; i++) { + for (int i = 0; i < s->plane[act_plane].height / 2; i++) { interlaced_vertical_filter(dst, low, high, lowpass_width * 2, pic->linesize[act_plane]/2, act_plane); low += output_stride * 2; high += output_stride * 2; diff --git a/libavcodec/cfhd.h b/libavcodec/cfhd.h index 445a0362b..880c0e1e9 100644 --- a/libavcodec/cfhd.h +++ b/libavcodec/cfhd.h @@ -25,7 +25,6 @@ #include "avcodec.h" #include "bytestream.h" -#include "get_bits.h" #include "cfhddsp.h" enum CFHDParam { @@ -107,7 +106,7 @@ enum CFHDSegment { typedef struct CFHD_RL_VLC_ELEM { int16_t level; - int8_t len; + int8_t len8; uint16_t run; } CFHD_RL_VLC_ELEM; @@ -153,8 +152,6 @@ typedef struct CFHDContext { int lut[2][256]; - GetBitContext gb; - int planes; int frame_type; int frame_index; diff --git a/libavcodec/cfhddata.c b/libavcodec/cfhddata.c index a3948a14c..72b14baf2 100644 --- a/libavcodec/cfhddata.c +++ b/libavcodec/cfhddata.c @@ -136,22 +136,22 @@ static av_cold int cfhd_init_vlc(CFHD_RL_VLC_ELEM out[], unsigned out_size, /** Similar to dv.c, generate signed VLC tables **/ for (unsigned i = j = 0; i < table_size; i++, j++) { - tmp[j].len = table_vlc[i].len; + tmp[j].len8 = table_vlc[i].len; tmp[j].run = table_vlc[i].run; tmp[j].level = table_vlc[i].level; /* Don't include the zero level nor escape bits */ if (table_vlc[i].level && table_vlc[i].run) { - tmp[j].len++; + tmp[j].len8++; j++; - tmp[j].len = table_vlc[i].len + 1; + tmp[j].len8 = table_vlc[i].len + 1; tmp[j].run = table_vlc[i].run; tmp[j].level = -table_vlc[i].level; } } ret = ff_vlc_init_from_lengths(&vlc, VLC_BITS, j, - &tmp[0].len, sizeof(tmp[0]), + &tmp[0].len8, sizeof(tmp[0]), NULL, 0, 0, 0, 0, logctx); if (ret < 0) return ret; @@ -169,7 +169,7 @@ static av_cold int cfhd_init_vlc(CFHD_RL_VLC_ELEM out[], unsigned out_size, run = tmp[code].run; level = tmp[code].level; } - out[i].len = len; + out[i].len8 = len; out[i].level = level; out[i].run = run; } diff --git a/libavcodec/cfhddsp.c b/libavcodec/cfhddsp.c index a141db524..05757d651 100644 --- a/libavcodec/cfhddsp.c +++ b/libavcodec/cfhddsp.c @@ -112,7 +112,7 @@ av_cold void ff_cfhddsp_init(CFHDDSPContext *c, int depth, int bayer) else c->horiz_filter_clip = horiz_filter_clip; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_cfhddsp_init_x86(c, depth, bayer); #endif } diff --git a/libavcodec/cfhdenc.c b/libavcodec/cfhdenc.c index b3bd8edb5..db435f321 100644 --- a/libavcodec/cfhdenc.c +++ b/libavcodec/cfhdenc.c @@ -864,12 +864,7 @@ const FFCodec ff_cfhd_encoder = { .init = cfhd_encode_init, .close = cfhd_encode_close, FF_CODEC_ENCODE_CB(cfhd_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUV422P10, - AV_PIX_FMT_GBRP12, - AV_PIX_FMT_GBRAP12, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12), .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cfhdencdsp.c b/libavcodec/cfhdencdsp.c index a122bcaf1..06801aef6 100644 --- a/libavcodec/cfhdencdsp.c +++ b/libavcodec/cfhdencdsp.c @@ -73,7 +73,7 @@ av_cold void ff_cfhdencdsp_init(CFHDEncDSPContext *c) c->horiz_filter = horiz_filter; c->vert_filter = vert_filter; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_cfhdencdsp_init_x86(c); #endif } diff --git a/libavcodec/cinepak.c b/libavcodec/cinepak.c index 2ec0ce888..9ec7ac5a8 100644 --- a/libavcodec/cinepak.c +++ b/libavcodec/cinepak.c @@ -476,14 +476,7 @@ static int cinepak_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return ret; if (s->palette_video) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif } if ((ret = cinepak_decode(s)) < 0) { diff --git a/libavcodec/cinepakenc.c b/libavcodec/cinepakenc.c index f6145131a..104a9f485 100644 --- a/libavcodec/cinepakenc.c +++ b/libavcodec/cinepakenc.c @@ -1223,7 +1223,7 @@ const FFCodec ff_cinepak_encoder = { .init = cinepak_encode_init, FF_CODEC_ENCODE_CB(cinepak_encode_frame), .close = cinepak_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB24, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_GRAY8), .p.priv_class = &cinepak_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cljrenc.c b/libavcodec/cljrenc.c index 4698dfd72..3b71a85aa 100644 --- a/libavcodec/cljrenc.c +++ b/libavcodec/cljrenc.c @@ -116,8 +116,7 @@ const FFCodec ff_cljr_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(CLJRContext), FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV411P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV411P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &cljr_class, }; diff --git a/libavcodec/cngdec.c b/libavcodec/cngdec.c index bacbd54fa..eb37c33eb 100644 --- a/libavcodec/cngdec.c +++ b/libavcodec/cngdec.c @@ -97,7 +97,7 @@ static void make_lpc_coefs(float *lpc, const float *refl, int order) memcpy(lpc, cur, sizeof(*lpc) * order); } -static void cng_decode_flush(AVCodecContext *avctx) +static av_cold void cng_decode_flush(AVCodecContext *avctx) { CNGContext *p = avctx->priv_data; p->inited = 0; @@ -173,8 +173,6 @@ const FFCodec ff_comfortnoise_decoder = { FF_CODEC_DECODE_CB(cng_decode_frame), .flush = cng_decode_flush, .close = cng_decode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cngenc.c b/libavcodec/cngenc.c index c43013680..69501dae6 100644 --- a/libavcodec/cngenc.c +++ b/libavcodec/cngenc.c @@ -108,8 +108,7 @@ const FFCodec ff_comfortnoise_encoder = { .init = cng_encode_init, FF_CODEC_ENCODE_CB(cng_encode_frame), .close = cng_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, { 0 } }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/codec.h b/libavcodec/codec.h index f7541ffc4..f509e5d94 100644 --- a/libavcodec/codec.h +++ b/libavcodec/codec.h @@ -80,21 +80,6 @@ */ #define AV_CODEC_CAP_SMALL_LAST_FRAME (1 << 6) -#if FF_API_SUBFRAMES -/** - * 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 carrying 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 AV_CODEC_CAP_SUBFRAMES (1 << 8) -#endif - /** * Codec is experimental and is thus avoided in favor of non experimental * encoders diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index d58c3d889..a9f21f815 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -905,7 +905,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_VIDEO, .name = "tgq", .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts TGQ video"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .props = AV_CODEC_PROP_LOSSY, }, { .id = AV_CODEC_ID_TQI, @@ -1146,6 +1146,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Dxtory"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, +#if FF_API_V408_CODECID { .id = AV_CODEC_ID_V410, .type = AVMEDIA_TYPE_VIDEO, @@ -1153,6 +1154,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:4:4 10-bit"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, +#endif { .id = AV_CODEC_ID_XWD, .type = AVMEDIA_TYPE_VIDEO, @@ -1275,7 +1277,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_VIDEO, .name = "hevc", .long_name = NULL_IF_CONFIG_SMALL("H.265 / HEVC (High Efficiency Video Coding)"), - .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS | AV_CODEC_PROP_REORDER, .profiles = NULL_IF_CONFIG_SMALL(ff_hevc_profiles), }, { @@ -1477,6 +1479,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Pinnacle TARGA CineWave YUV16"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, +#if FF_API_V408_CODECID { .id = AV_CODEC_ID_V308, .type = AVMEDIA_TYPE_VIDEO, @@ -1491,6 +1494,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed QT 4:4:4:4"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, +#endif { .id = AV_CODEC_ID_YUV4, .type = AVMEDIA_TYPE_VIDEO, @@ -1644,7 +1648,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_VIDEO, .name = "av1", .long_name = NULL_IF_CONFIG_SMALL("Alliance for Open Media AV1"), - .props = AV_CODEC_PROP_LOSSY, + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, .profiles = NULL_IF_CONFIG_SMALL(ff_av1_profiles), }, { @@ -1959,6 +1963,52 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("LEAD MCMP"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_DNXUC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dnxuc", + .long_name = NULL_IF_CONFIG_SMALL("DNxUncompressed / SMPTE RDD 50"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_RV60, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rv60", + .long_name = NULL_IF_CONFIG_SMALL("RealVideo 6.0"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_JPEGXL_ANIM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "jpegxl_anim", + .long_name = NULL_IF_CONFIG_SMALL("JPEG XL animated"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/jxl"), + }, + { + .id = AV_CODEC_ID_APV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "apv", + .long_name = NULL_IF_CONFIG_SMALL("Advanced Professional Video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PRORES_RAW, + .type = AVMEDIA_TYPE_VIDEO, + .name = "prores_raw", + .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes RAW"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .profiles = NULL_IF_CONFIG_SMALL(ff_prores_raw_profiles), + }, + { + .id = AV_CODEC_ID_JPEGXS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "jpegxs", + .long_name = NULL_IF_CONFIG_SMALL("JPEG XS"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | + AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/jxs"), + }, /* various PCM "codecs" */ { @@ -2579,6 +2629,76 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM Konami XMD"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_IMA_XBOX, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_xbox", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Xbox"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_SANYO, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_sanyo", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Sanyo"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_HVQM4, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_hvqm4", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA HVQM4"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_PDA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_pda", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA PlayDate"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_N64, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_n64", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Silicon Graphics N64"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_HVQM2, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_hvqm2", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA HVQM2"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_MAGIX, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_magix", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Magix"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_PSXC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_psxc", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Playstation C"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_CIRCUS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_circus", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Circus"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_ESCAPE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_escape", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Acorn Escape"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* AMR */ { @@ -3433,6 +3553,20 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("LC3 (Low Complexity Communication Codec)"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_G728, + .type = AVMEDIA_TYPE_AUDIO, + .name = "g728", + .long_name = NULL_IF_CONFIG_SMALL("G.728"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_AHX, + .type = AVMEDIA_TYPE_AUDIO, + .name = "ahx", + .long_name = NULL_IF_CONFIG_SMALL("CRI AHX"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* subtitle codecs */ { @@ -3616,6 +3750,12 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ARIB STD-B24 caption"), .profiles = NULL_IF_CONFIG_SMALL(ff_arib_caption_profiles), }, + { + .id = AV_CODEC_ID_IVTV_VBI, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "ivtv_vbi", + .long_name = NULL_IF_CONFIG_SMALL("ivtv VBI captions"), + }, /* other kind of codecs and pseudo-codecs */ { @@ -3698,9 +3838,16 @@ static const AVCodecDescriptor codec_descriptors[] = { }, { .id = AV_CODEC_ID_LCEVC, - .type = AVMEDIA_TYPE_DATA, + .type = AVMEDIA_TYPE_VIDEO, .name = "lcevc", .long_name = NULL_IF_CONFIG_SMALL("LCEVC (Low Complexity Enhancement Video Coding) / MPEG-5 LCEVC / MPEG-5 part 2"), + .props = AV_CODEC_PROP_ENHANCEMENT, + }, + { + .id = AV_CODEC_ID_SMPTE_436M_ANC, + .type = AVMEDIA_TYPE_DATA, + .name = "smpte_436m_anc", + .long_name = NULL_IF_CONFIG_SMALL("MXF SMPTE-436M ANC"), }, { .id = AV_CODEC_ID_MPEG2TS, diff --git a/libavcodec/codec_desc.h b/libavcodec/codec_desc.h index 96afd2020..1186433c9 100644 --- a/libavcodec/codec_desc.h +++ b/libavcodec/codec_desc.h @@ -96,6 +96,14 @@ typedef struct AVCodecDescriptor { */ #define AV_CODEC_PROP_FIELDS (1 << 4) +/** + * Video codec contains enhancement information meant to be applied to other + * existing frames, and can't generate usable image data on its own. + * A standalone decoder is unlikely to be available for it and should not + * be expected. + */ +#define AV_CODEC_PROP_ENHANCEMENT (1 << 5) + /** * Subtitle codec is bitmap based * Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field. diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index 0a8d3bed1..6529f0a6b 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -206,7 +206,9 @@ enum AVCodecID { AV_CODEC_ID_BMV_VIDEO, AV_CODEC_ID_VBLE, AV_CODEC_ID_DXTORY, +#if FF_API_V408_CODECID AV_CODEC_ID_V410, +#endif AV_CODEC_ID_XWD, AV_CODEC_ID_CDXL, AV_CODEC_ID_XBM, @@ -254,8 +256,10 @@ enum AVCodecID { AV_CODEC_ID_012V, AV_CODEC_ID_AVUI, AV_CODEC_ID_TARGA_Y216, +#if FF_API_V408_CODECID AV_CODEC_ID_V308, AV_CODEC_ID_V408, +#endif AV_CODEC_ID_YUV4, AV_CODEC_ID_AVRN, AV_CODEC_ID_CPIA, @@ -322,6 +326,12 @@ enum AVCodecID { AV_CODEC_ID_RTV1, AV_CODEC_ID_VMIX, AV_CODEC_ID_LEAD, + AV_CODEC_ID_DNXUC, + AV_CODEC_ID_RV60, + AV_CODEC_ID_JPEGXL_ANIM, + AV_CODEC_ID_APV, + AV_CODEC_ID_PRORES_RAW, + AV_CODEC_ID_JPEGXS, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs @@ -416,6 +426,16 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_IMA_MOFLEX, AV_CODEC_ID_ADPCM_IMA_ACORN, AV_CODEC_ID_ADPCM_XMD, + AV_CODEC_ID_ADPCM_IMA_XBOX, + AV_CODEC_ID_ADPCM_SANYO, + AV_CODEC_ID_ADPCM_IMA_HVQM4, + AV_CODEC_ID_ADPCM_IMA_PDA, + AV_CODEC_ID_ADPCM_N64, + AV_CODEC_ID_ADPCM_IMA_HVQM2, + AV_CODEC_ID_ADPCM_IMA_MAGIX, + AV_CODEC_ID_ADPCM_PSXC, + AV_CODEC_ID_ADPCM_CIRCUS, + AV_CODEC_ID_ADPCM_IMA_ESCAPE, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, @@ -544,6 +564,8 @@ enum AVCodecID { AV_CODEC_ID_OSQ, AV_CODEC_ID_QOA, AV_CODEC_ID_LC3, + AV_CODEC_ID_G728, + AV_CODEC_ID_AHX, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. @@ -573,6 +595,7 @@ enum AVCodecID { AV_CODEC_ID_HDMV_TEXT_SUBTITLE, AV_CODEC_ID_TTML, AV_CODEC_ID_ARIB_CAPTION, + AV_CODEC_ID_IVTV_VBI, /* 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. @@ -590,6 +613,7 @@ enum AVCodecID { AV_CODEC_ID_BIN_DATA, AV_CODEC_ID_SMPTE_2038, AV_CODEC_ID_LCEVC, + AV_CODEC_ID_SMPTE_436M_ANC, AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it diff --git a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h index 5b2db7459..eea982e56 100644 --- a/libavcodec/codec_internal.h +++ b/libavcodec/codec_internal.h @@ -22,7 +22,6 @@ #include #include "libavutil/attributes.h" -#include "avcodec.h" #include "codec.h" #include "config.h" @@ -102,6 +101,7 @@ typedef struct FFCodecDefault { struct AVCodecContext; struct AVSubtitle; struct AVPacket; +enum AVCodecConfig; enum FFCodecType { /* The codec is a decoder using the decode callback; @@ -133,7 +133,12 @@ typedef struct FFCodec { /** * Internal codec capabilities FF_CODEC_CAP_*. */ - unsigned caps_internal:27; + unsigned caps_internal:24; + + /** + * Is this a decoder? + */ + unsigned is_decoder:1; /** * This field determines the video color ranges supported by an encoder. @@ -141,6 +146,12 @@ typedef struct FFCodec { */ unsigned color_ranges:2; + /** + * This field determines the alpha modes supported by an encoder. + * Should be set to a bitmask of AVALPHA_MODE_PREMULTIPLIED and AVALPHA_MODE_STRAIGHT. + */ + unsigned alpha_modes:2; + /** * This field determines the type of the codec (decoder/encoder) * and also the exact callback cb implemented by the codec. @@ -268,7 +279,7 @@ typedef struct FFCodec { * ff_default_get_supported_config() will be used. `out_num_configs` will * always be set to a valid pointer. */ - int (*get_supported_config)(const AVCodecContext *avctx, + int (*get_supported_config)(const struct AVCodecContext *avctx, const AVCodec *codec, enum AVCodecConfig config, unsigned flags, @@ -276,6 +287,31 @@ typedef struct FFCodec { int *out_num_configs); } FFCodec; +static av_always_inline const FFCodec *ffcodec(const AVCodec *codec) +{ + return (const FFCodec*)codec; +} + +/** + * Internal version of av_codec_is_encoder(). Must not be called with + * a NULL AVCodec*. + */ +static inline int ff_codec_is_encoder(const AVCodec *avcodec) +{ + const FFCodec *const codec = ffcodec(avcodec); + return !codec->is_decoder; +} + +/** + * Internal version of av_codec_is_decoder(). Must not be called with + * a NULL AVCodec*. + */ +static inline int ff_codec_is_decoder(const AVCodec *avcodec) +{ + const FFCodec *const codec = ffcodec(avcodec); + return codec->is_decoder; +} + /** * Default implementation for avcodec_get_supported_config(). Will return the * relevant fields from AVCodec if present, or NULL otherwise. @@ -283,7 +319,7 @@ typedef struct FFCodec { * For AVCODEC_CONFIG_COLOR_RANGE, the output will depend on the bitmask in * FFCodec.color_ranges, with a value of 0 returning NULL. */ -int ff_default_get_supported_config(const AVCodecContext *avctx, +int ff_default_get_supported_config(const struct AVCodecContext *avctx, const AVCodec *codec, enum AVCodecConfig config, unsigned flags, @@ -309,27 +345,56 @@ int ff_default_get_supported_config(const AVCodecContext *avctx, #endif #define FF_CODEC_DECODE_CB(func) \ + .is_decoder = 1, \ .cb_type = FF_CODEC_CB_TYPE_DECODE, \ .cb.decode = (func) #define FF_CODEC_DECODE_SUB_CB(func) \ + .is_decoder = 1, \ .cb_type = FF_CODEC_CB_TYPE_DECODE_SUB, \ .cb.decode_sub = (func) #define FF_CODEC_RECEIVE_FRAME_CB(func) \ + .is_decoder = 1, \ .cb_type = FF_CODEC_CB_TYPE_RECEIVE_FRAME, \ .cb.receive_frame = (func) #define FF_CODEC_ENCODE_CB(func) \ + .is_decoder = 0, \ .cb_type = FF_CODEC_CB_TYPE_ENCODE, \ .cb.encode = (func) #define FF_CODEC_ENCODE_SUB_CB(func) \ + .is_decoder = 0, \ .cb_type = FF_CODEC_CB_TYPE_ENCODE_SUB, \ .cb.encode_sub = (func) #define FF_CODEC_RECEIVE_PACKET_CB(func) \ + .is_decoder = 0, \ .cb_type = FF_CODEC_CB_TYPE_RECEIVE_PACKET, \ .cb.receive_packet = (func) -static av_always_inline const FFCodec *ffcodec(const AVCodec *codec) -{ - return (const FFCodec*)codec; -} +#ifdef __clang__ +#define DISABLE_DEPRECATION_WARNINGS FF_DISABLE_DEPRECATION_WARNINGS +#define ENABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS +#else +#define DISABLE_DEPRECATION_WARNINGS +#define ENABLE_DEPRECATION_WARNINGS +#endif + +#define CODEC_CH_LAYOUTS(...) CODEC_CH_LAYOUTS_ARRAY(((const AVChannelLayout[]) { __VA_ARGS__, { 0 } })) +#define CODEC_CH_LAYOUTS_ARRAY(array) CODEC_ARRAY(ch_layouts, (array)) + +#define CODEC_SAMPLERATES(...) CODEC_SAMPLERATES_ARRAY(((const int[]) { __VA_ARGS__, 0 })) +#define CODEC_SAMPLERATES_ARRAY(array) CODEC_ARRAY(supported_samplerates, (array)) + +#define CODEC_SAMPLEFMTS(...) CODEC_SAMPLEFMTS_ARRAY(((const enum AVSampleFormat[]) { __VA_ARGS__, AV_SAMPLE_FMT_NONE })) +#define CODEC_SAMPLEFMTS_ARRAY(array) CODEC_ARRAY(sample_fmts, (array)) + +#define CODEC_FRAMERATES(...) CODEC_FRAMERATES_ARRAY(((const AVRational[]) { __VA_ARGS__, { 0, 0 } })) +#define CODEC_FRAMERATES_ARRAY(array) CODEC_ARRAY(supported_framerates, (array)) + +#define CODEC_PIXFMTS(...) CODEC_PIXFMTS_ARRAY(((const enum AVPixelFormat[]) { __VA_ARGS__, AV_PIX_FMT_NONE })) +#define CODEC_PIXFMTS_ARRAY(array) CODEC_ARRAY(pix_fmts, (array)) + +#define CODEC_ARRAY(field, array) \ + DISABLE_DEPRECATION_WARNINGS \ + .p.field = (array) \ + ENABLE_DEPRECATION_WARNINGS #endif /* AVCODEC_CODEC_INTERNAL_H */ diff --git a/libavcodec/codec_par.c b/libavcodec/codec_par.c index 790ea01d1..ddf349cee 100644 --- a/libavcodec/codec_par.c +++ b/libavcodec/codec_par.c @@ -51,6 +51,7 @@ static void codec_parameters_reset(AVCodecParameters *par) par->framerate = (AVRational){ 0, 1 }; par->profile = AV_PROFILE_UNKNOWN; par->level = AV_LEVEL_UNKNOWN; + par->alpha_mode = AVALPHA_MODE_UNSPECIFIED; } AVCodecParameters *avcodec_parameters_alloc(void) @@ -165,6 +166,7 @@ int avcodec_parameters_from_context(AVCodecParameters *par, par->sample_aspect_ratio = codec->sample_aspect_ratio; par->video_delay = codec->has_b_frames; par->framerate = codec->framerate; + par->alpha_mode = codec->alpha_mode; break; case AVMEDIA_TYPE_AUDIO: par->format = codec->sample_fmt; @@ -229,6 +231,7 @@ int avcodec_parameters_to_context(AVCodecContext *codec, codec->sample_aspect_ratio = par->sample_aspect_ratio; codec->has_b_frames = par->video_delay; codec->framerate = par->framerate; + codec->alpha_mode = par->alpha_mode; break; case AVMEDIA_TYPE_AUDIO: codec->sample_fmt = par->format; diff --git a/libavcodec/codec_par.h b/libavcodec/codec_par.h index f4b9bb5c0..2697605d4 100644 --- a/libavcodec/codec_par.h +++ b/libavcodec/codec_par.h @@ -148,7 +148,7 @@ typedef struct AVCodecParameters { * durations. Should be set to { 0, 1 } when some frames have differing * durations or if the value is not known. * - * @note This field correponds to values that are stored in codec-level + * @note This field corresponds to values that are stored in codec-level * headers and is typically overridden by container/transport-layer * timestamps, when available. It should thus be used only as a last resort, * when no higher-level timing information is available. @@ -212,6 +212,11 @@ typedef struct AVCodecParameters { * Audio only. Number of samples to skip after a discontinuity. */ int seek_preroll; + + /** + * Video with alpha channel only. Alpha channel handling + */ + enum AVAlphaMode alpha_mode; } AVCodecParameters; /** diff --git a/libavcodec/container_fifo.c b/libavcodec/container_fifo.c deleted file mode 100644 index 82e86d946..000000000 --- a/libavcodec/container_fifo.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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/error.h" -#include "libavutil/fifo.h" -#include "libavutil/frame.h" -#include "libavutil/mem.h" - -#include "container_fifo.h" -#include "refstruct.h" - -struct ContainerFifo { - AVFifo *fifo; - FFRefStructPool *pool; - - void* (*container_alloc)(void); - void (*container_reset)(void *obj); - void (*container_free) (void *obj); - int (*fifo_write) (void *dst, void *src); - int (*fifo_read) (void *dst, void *src); - -}; - -static int container_fifo_init_entry(FFRefStructOpaque opaque, void *obj) -{ - ContainerFifo *cf = opaque.nc; - void **pobj = obj; - - *pobj = cf->container_alloc(); - if (!*pobj) - return AVERROR(ENOMEM); - - return 0; -} - -static void container_fifo_reset_entry(FFRefStructOpaque opaque, void *obj) -{ - ContainerFifo *cf = opaque.nc; - cf->container_reset(*(void**)obj); -} - -static void container_fifo_free_entry(FFRefStructOpaque opaque, void *obj) -{ - ContainerFifo *cf = opaque.nc; - cf->container_free(*(void**)obj); -} - -ContainerFifo* -ff_container_fifo_alloc(void* (*container_alloc)(void), - void (*container_reset)(void *obj), - void (*container_free) (void *obj), - int (*fifo_write) (void *dst, void *src), - int (*fifo_read) (void *dst, void *src)) -{ - ContainerFifo *cf; - - cf = av_mallocz(sizeof(*cf)); - if (!cf) - return NULL; - - cf->container_alloc = container_alloc; - cf->container_reset = container_reset; - cf->container_free = container_free; - cf->fifo_write = fifo_write; - cf->fifo_read = fifo_read; - - cf->fifo = av_fifo_alloc2(1, sizeof(void*), AV_FIFO_FLAG_AUTO_GROW); - if (!cf->fifo) - goto fail; - - cf->pool = ff_refstruct_pool_alloc_ext(sizeof(void*), 0, cf, - container_fifo_init_entry, - container_fifo_reset_entry, - container_fifo_free_entry, - NULL); - if (!cf->pool) - goto fail; - - return cf; -fail: - ff_container_fifo_free(&cf); - return NULL; -} - -void ff_container_fifo_free(ContainerFifo **pcf) -{ - ContainerFifo *cf; - - if (!*pcf) - return; - - cf = *pcf; - - if (cf->fifo) { - void *obj; - while (av_fifo_read(cf->fifo, &obj, 1) >= 0) - ff_refstruct_unref(&obj); - av_fifo_freep2(&cf->fifo); - } - - ff_refstruct_pool_uninit(&cf->pool); - - av_freep(pcf); -} - -int ff_container_fifo_read(ContainerFifo *cf, void *obj) -{ - void **psrc; - int ret; - - ret = av_fifo_read(cf->fifo, &psrc, 1); - if (ret < 0) - return ret; - - ret = cf->fifo_read(obj, *psrc); - ff_refstruct_unref(&psrc); - - return ret; -} - -int ff_container_fifo_write(ContainerFifo *cf, void *obj) -{ - void **pdst; - int ret; - - pdst = ff_refstruct_pool_get(cf->pool); - if (!pdst) - return AVERROR(ENOMEM); - - ret = cf->fifo_write(*pdst, obj); - if (ret < 0) - goto fail; - - ret = av_fifo_write(cf->fifo, &pdst, 1); - if (ret < 0) - goto fail; - - return 0; -fail: - ff_refstruct_unref(&pdst); - return ret; -} - -size_t ff_container_fifo_can_read(ContainerFifo *cf) -{ - return av_fifo_can_read(cf->fifo); -} - -static void *frame_alloc(void) -{ - return av_frame_alloc(); -} - -static void frame_reset(void *obj) -{ - av_frame_unref(obj); -} - -static void frame_free(void *obj) -{ - AVFrame *frame = obj; - av_frame_free(&frame); -} - -static int frame_ref(void *dst, void *src) -{ - return av_frame_ref(dst, src); -} - -static int frame_move_ref(void *dst, void *src) -{ - av_frame_move_ref(dst, src); - return 0; -} - -ContainerFifo *ff_container_fifo_alloc_avframe(unsigned flags) -{ - return ff_container_fifo_alloc(frame_alloc, frame_reset, frame_free, - frame_ref, frame_move_ref); -} diff --git a/libavcodec/container_fifo.h b/libavcodec/container_fifo.h deleted file mode 100644 index dd8b1d380..000000000 --- a/libavcodec/container_fifo.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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_CONTAINER_FIFO_H -#define AVCODEC_CONTAINER_FIFO_H - -#include - -/** - * ContainerFifo is a FIFO for "containers" - dynamically allocated reusable - * structs (e.g. AVFrame or AVPacket). ContainerFifo uses an internal pool of - * such containers to avoid allocating and freeing them repeatedly. - */ -typedef struct ContainerFifo ContainerFifo; - -/** - * Allocate a new ContainerFifo for the container type defined by provided - * callbacks. - * - * @param container_alloc allocate a new container instance and return a pointer - * to it, or NULL on failure - * @param container_reset reset the provided container instance to a clean state - * @param container_free free the provided container instance - * @param fifo_write transfer the contents of src to dst, where src is a - * container instance provided to ff_container_fifo_write() - * @param fifo_read transfer the contents of src to dst in other cases - * - * @note fifo_read() and fifo_write() are different parameters in order to allow - * fifo_write() implementations that make a new reference in dst, leaving - * src untouched (see e.g. ff_container_fifo_alloc_avframe()) - */ -ContainerFifo* -ff_container_fifo_alloc(void* (*container_alloc)(void), - void (*container_reset)(void *obj), - void (*container_free) (void *obj), - int (*fifo_write) (void *dst, void *src), - int (*fifo_read) (void *dst, void *src)); - -/** - * Allocate a ContainerFifo instance for AVFrames. - * Note that ff_container_fifo_write() will call av_frame_ref() on src, making a - * new reference in dst and leaving src untouched. - * - * @param flags unused currently - */ -ContainerFifo *ff_container_fifo_alloc_avframe(unsigned flags); - -/** - * Free a ContainerFifo and everything in it. - */ -void ff_container_fifo_free(ContainerFifo **pf); - -/** - * Write the contents of obj to the FIFO. - * - * The fifo_write() callback previously provided to ff_container_fifo_alloc() - * will be called with obj as src in order to perform the actual transfer. - */ -int ff_container_fifo_write(ContainerFifo *pf, void *obj); - -/** - * Read the next available object from the FIFO into obj. - * - * The fifo_read() callback previously provided to ff_container_fifo_alloc() - * will be called with obj as dst in order to perform the actual transfer. - */ -int ff_container_fifo_read(ContainerFifo *pf, void *obj); - -/** - * @return number of objects available for reading - */ -size_t ff_container_fifo_can_read(ContainerFifo *pf); - -#endif // AVCODEC_CONTAINER_FIFO_H diff --git a/libavcodec/cook.c b/libavcodec/cook.c index dbe6b5b96..cc6005d3f 100644 --- a/libavcodec/cook.c +++ b/libavcodec/cook.c @@ -1308,7 +1308,5 @@ const FFCodec ff_cook_decoder = { .close = cook_decode_close, FF_CODEC_DECODE_CB(cook_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cook_parser.c b/libavcodec/cook_parser.c index 0d9473845..8e8f6db4c 100644 --- a/libavcodec/cook_parser.c +++ b/libavcodec/cook_parser.c @@ -28,7 +28,8 @@ #include #include "libavutil/intreadwrite.h" -#include "parser.h" +#include "avcodec.h" +#include "parser_internal.h" typedef struct CookParseContext { int duration; @@ -53,8 +54,8 @@ static int cook_parse(AVCodecParserContext *s1, AVCodecContext *avctx, return buf_size; } -const AVCodecParser ff_cook_parser = { - .codec_ids = { AV_CODEC_ID_COOK }, +const FFCodecParser ff_cook_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_COOK), .priv_data_size = sizeof(CookParseContext), - .parser_parse = cook_parse, + .parse = cook_parse, }; diff --git a/libavcodec/cri.c b/libavcodec/cri.c index f9ae257ba..f38059723 100644 --- a/libavcodec/cri.c +++ b/libavcodec/cri.c @@ -27,6 +27,7 @@ #define BITSTREAM_READER_LE +#include "libavutil/attributes_internal.h" #include "libavutil/intfloat.h" #include "libavutil/display.h" #include "avcodec.h" @@ -51,7 +52,6 @@ typedef struct CRIContext { static av_cold int cri_decode_init(AVCodecContext *avctx) { CRIContext *s = avctx->priv_data; - const AVCodec *codec; int ret; s->jpgframe = av_frame_alloc(); @@ -62,16 +62,14 @@ static av_cold int cri_decode_init(AVCodecContext *avctx) if (!s->jpkt) return AVERROR(ENOMEM); - codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG); - if (!codec) - return AVERROR_BUG; - s->jpeg_avctx = avcodec_alloc_context3(codec); + EXTERN const FFCodec ff_mjpeg_decoder; + s->jpeg_avctx = avcodec_alloc_context3(&ff_mjpeg_decoder.p); if (!s->jpeg_avctx) return AVERROR(ENOMEM); s->jpeg_avctx->flags = avctx->flags; s->jpeg_avctx->flags2 = avctx->flags2; s->jpeg_avctx->idct_algo = avctx->idct_algo; - ret = avcodec_open2(s->jpeg_avctx, codec, NULL); + ret = avcodec_open2(s->jpeg_avctx, NULL, NULL); if (ret < 0) return ret; diff --git a/libavcodec/cri_parser.c b/libavcodec/cri_parser.c index 9295f823c..cd0c45f41 100644 --- a/libavcodec/cri_parser.c +++ b/libavcodec/cri_parser.c @@ -28,6 +28,7 @@ #include "libavutil/common.h" #include "parser.h" +#include "parser_internal.h" typedef struct CRIParser { ParseContext pc; @@ -97,9 +98,9 @@ static int cri_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_cri_parser = { - .codec_ids = { AV_CODEC_ID_CRI }, +const FFCodecParser ff_cri_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_CRI), .priv_data_size = sizeof(CRIParser), - .parser_parse = cri_parse, - .parser_close = ff_parse_close, + .parse = cri_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/cuviddec.c b/libavcodec/cuviddec.c index 3fae9c12e..be183fce3 100644 --- a/libavcodec/cuviddec.c +++ b/libavcodec/cuviddec.c @@ -131,7 +131,7 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form CUVIDDECODECREATEINFO cuinfo; int surface_fmt; int chroma_444; - int fifo_size_inc; + int old_nb_surfaces, fifo_size_inc, fifo_size_mul = 1; int old_width = avctx->width; int old_height = avctx->height; @@ -178,15 +178,59 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form switch (format->bit_depth_luma_minus8) { case 0: // 8-bit - pix_fmts[1] = chroma_444 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_NV12; + if (chroma_444) { + pix_fmts[1] = AV_PIX_FMT_YUV444P; +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (format->chroma_format == cudaVideoChromaFormat_422) { + pix_fmts[1] = AV_PIX_FMT_NV16; +#endif + } else { + pix_fmts[1] = AV_PIX_FMT_NV12; + } caps = &ctx->caps8; break; case 2: // 10-bit - pix_fmts[1] = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P010; + if (chroma_444) { +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = AV_PIX_FMT_YUV444P16; +#else + pix_fmts[1] = AV_PIX_FMT_YUV444P10MSB; +#endif +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (format->chroma_format == cudaVideoChromaFormat_422) { +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = AV_PIX_FMT_P216; +#else + pix_fmts[1] = AV_PIX_FMT_P210; +#endif +#endif + } else { + pix_fmts[1] = AV_PIX_FMT_P010; + } caps = &ctx->caps10; break; case 4: // 12-bit - pix_fmts[1] = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P016; + if (chroma_444) { +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = AV_PIX_FMT_YUV444P16; +#else + pix_fmts[1] = AV_PIX_FMT_YUV444P12MSB; +#endif +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (format->chroma_format == cudaVideoChromaFormat_422) { +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = AV_PIX_FMT_P216; +#else + pix_fmts[1] = AV_PIX_FMT_P212; +#endif +#endif + } else { +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = AV_PIX_FMT_P016; +#else + pix_fmts[1] = AV_PIX_FMT_P012; +#endif + } caps = &ctx->caps12; break; default: @@ -304,6 +348,14 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form case AV_PIX_FMT_P016: cuinfo.OutputFormat = cudaVideoSurfaceFormat_P016; break; +#ifdef NVDEC_HAVE_422_SUPPORT + case AV_PIX_FMT_NV16: + cuinfo.OutputFormat = cudaVideoSurfaceFormat_NV16; + break; + case AV_PIX_FMT_P216: + cuinfo.OutputFormat = cudaVideoSurfaceFormat_P216; + break; +#endif case AV_PIX_FMT_YUV444P: cuinfo.OutputFormat = cudaVideoSurfaceFormat_YUV444; break; @@ -317,20 +369,24 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form return 0; } - fifo_size_inc = ctx->nb_surfaces; - ctx->nb_surfaces = FFMAX(ctx->nb_surfaces, format->min_num_decode_surfaces + 3); + if (ctx->deint_mode_current != cudaVideoDeinterlaceMode_Weave && !ctx->drop_second_field) { + avctx->framerate = av_mul_q(avctx->framerate, (AVRational){2, 1}); + fifo_size_mul = 2; + } + old_nb_surfaces = ctx->nb_surfaces; + ctx->nb_surfaces = FFMAX(ctx->nb_surfaces, format->min_num_decode_surfaces + 3); if (avctx->extra_hw_frames > 0) ctx->nb_surfaces += avctx->extra_hw_frames; - fifo_size_inc = ctx->nb_surfaces - fifo_size_inc; + fifo_size_inc = ctx->nb_surfaces * fifo_size_mul - av_fifo_can_read(ctx->frame_queue) - av_fifo_can_write(ctx->frame_queue); if (fifo_size_inc > 0 && av_fifo_grow2(ctx->frame_queue, fifo_size_inc) < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to grow frame queue on video sequence callback\n"); ctx->internal_error = AVERROR(ENOMEM); return 0; } - if (fifo_size_inc > 0 && av_reallocp_array(&ctx->key_frame, ctx->nb_surfaces, sizeof(int)) < 0) { + if (ctx->nb_surfaces > old_nb_surfaces && av_reallocp_array(&ctx->key_frame, ctx->nb_surfaces, sizeof(int)) < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to grow key frame array on video sequence callback\n"); ctx->internal_error = AVERROR(ENOMEM); return 0; @@ -342,9 +398,6 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form cuinfo.bitDepthMinus8 = format->bit_depth_luma_minus8; cuinfo.DeinterlaceMode = ctx->deint_mode_current; - if (ctx->deint_mode_current != cudaVideoDeinterlaceMode_Weave && !ctx->drop_second_field) - avctx->framerate = av_mul_q(avctx->framerate, (AVRational){2, 1}); - ctx->internal_error = CHECK_CU(ctx->cvdl->cuvidCreateDecoder(&ctx->cudecoder, &cuinfo)); if (ctx->internal_error < 0) return 0; @@ -391,6 +444,7 @@ static int CUDAAPI cuvid_handle_picture_display(void *opaque, CUVIDPARSERDISPINF AVCodecContext *avctx = opaque; CuvidContext *ctx = avctx->priv_data; CuvidParsedFrame parsed_frame = { { 0 } }; + int ret; parsed_frame.dispinfo = *dispinfo; ctx->internal_error = 0; @@ -399,13 +453,20 @@ static int CUDAAPI cuvid_handle_picture_display(void *opaque, CUVIDPARSERDISPINF parsed_frame.dispinfo.progressive_frame = ctx->progressive_sequence; if (ctx->deint_mode_current == cudaVideoDeinterlaceMode_Weave) { - av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + ret = av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "Writing frame to fifo failed!\n"); } else { parsed_frame.is_deinterlacing = 1; - av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + ret = av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "Writing first frame to fifo failed!\n"); + if (!ctx->drop_second_field) { parsed_frame.second_field = 1; - av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + ret = av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "Writing second frame to fifo failed!\n"); } } @@ -416,11 +477,12 @@ static int cuvid_is_buffer_full(AVCodecContext *avctx) { CuvidContext *ctx = avctx->priv_data; - int delay = ctx->cuparseinfo.ulMaxDisplayDelay; + int shift = 0; if (ctx->deint_mode != cudaVideoDeinterlaceMode_Weave && !ctx->drop_second_field) - delay *= 2; + shift = 1; - return av_fifo_can_read(ctx->frame_queue) + delay >= ctx->nb_surfaces; + // shift/divide frame count to ensure the buffer is still signalled full if one half-frame has already been returned when deinterlacing. + return ((av_fifo_can_read(ctx->frame_queue) + shift) >> shift) + ctx->cuparseinfo.ulMaxDisplayDelay >= ctx->nb_surfaces; } static int cuvid_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt) @@ -463,7 +525,12 @@ static int cuvid_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt) ctx->decoder_flushing = 1; } - ret = CHECK_CU(ctx->cvdl->cuvidParseVideoData(ctx->cuparser, &cupkt)); + // When flushing, only actually flush cuvid when the output buffer has been fully emptied. + // CUVID happily dumps out a ton of frames with no regard for its own available surfaces. + if (!ctx->decoder_flushing || (ctx->decoder_flushing && !av_fifo_can_read(ctx->frame_queue))) + ret = CHECK_CU(ctx->cvdl->cuvidParseVideoData(ctx->cuparser, &cupkt)); + else + ret = 0; if (ret < 0) goto error; @@ -578,6 +645,10 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame) } else if (avctx->pix_fmt == AV_PIX_FMT_NV12 || avctx->pix_fmt == AV_PIX_FMT_P010 || avctx->pix_fmt == AV_PIX_FMT_P016 || +#ifdef NVDEC_HAVE_422_SUPPORT + avctx->pix_fmt == AV_PIX_FMT_NV16 || + avctx->pix_fmt == AV_PIX_FMT_P216 || +#endif avctx->pix_fmt == AV_PIX_FMT_YUV444P || avctx->pix_fmt == AV_PIX_FMT_YUV444P16) { unsigned int offset = 0; @@ -659,12 +730,6 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame) * So set pkt_pts and clear all the other pkt_ fields. */ frame->duration = 0; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frame->pkt_pos = -1; - frame->pkt_size = -1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif if (!parsed_frame.is_deinterlacing && !parsed_frame.dispinfo.progressive_frame) frame->flags |= AV_FRAME_FLAG_INTERLACED; @@ -730,7 +795,7 @@ static int cuvid_test_capabilities(AVCodecContext *avctx, const CUVIDPARSERPARAMS *cuparseinfo, int probed_width, int probed_height, - int bit_depth) + int bit_depth, int is_yuv422, int is_yuv444) { CuvidContext *ctx = avctx->priv_data; CUVIDDECODECAPS *caps; @@ -753,8 +818,14 @@ static int cuvid_test_capabilities(AVCodecContext *avctx, ctx->caps8.eCodecType = ctx->caps10.eCodecType = ctx->caps12.eCodecType = cuparseinfo->CodecType; + ctx->caps8.eChromaFormat = ctx->caps10.eChromaFormat = ctx->caps12.eChromaFormat - = cudaVideoChromaFormat_420; + = is_yuv444 ? cudaVideoChromaFormat_444 : +#ifdef NVDEC_HAVE_422_SUPPORT + (is_yuv422 ? cudaVideoChromaFormat_422 : cudaVideoChromaFormat_420); +#else + cudaVideoChromaFormat_420; +#endif ctx->caps8.nBitDepthMinus8 = 0; ctx->caps10.nBitDepthMinus8 = 2; @@ -790,12 +861,12 @@ static int cuvid_test_capabilities(AVCodecContext *avctx, } if (!ctx->caps8.bIsSupported) { - av_log(avctx, AV_LOG_ERROR, "Codec %s is not supported.\n", avctx->codec->name); + av_log(avctx, AV_LOG_ERROR, "Codec %s is not supported with this chroma format.\n", avctx->codec->name); return AVERROR(EINVAL); } if (!caps->bIsSupported) { - av_log(avctx, AV_LOG_ERROR, "Bit depth %d is not supported.\n", bit_depth); + av_log(avctx, AV_LOG_ERROR, "Bit depth %d with this chroma format is not supported.\n", bit_depth); return AVERROR(EINVAL); } @@ -839,7 +910,7 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) int probed_width = avctx->coded_width ? avctx->coded_width : 1280; int probed_height = avctx->coded_height ? avctx->coded_height : 720; - int probed_bit_depth = 8, is_yuv444 = 0; + int probed_bit_depth = 8, is_yuv444 = 0, is_yuv422 = 0; const AVPixFmtDescriptor *probe_desc = av_pix_fmt_desc_get(avctx->pix_fmt); if (probe_desc && probe_desc->nb_components) @@ -848,17 +919,29 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) if (probe_desc && !probe_desc->log2_chroma_w && !probe_desc->log2_chroma_h) is_yuv444 = 1; +#ifdef NVDEC_HAVE_422_SUPPORT + if (probe_desc && probe_desc->log2_chroma_w && !probe_desc->log2_chroma_h) + is_yuv422 = 1; +#endif + // Pick pixel format based on bit depth and chroma sampling. - // Only 420 and 444 sampling are supported by HW so far, no need to check for 422. switch (probed_bit_depth) { case 10: - pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P010; +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P16 : (is_yuv422 ? AV_PIX_FMT_P216 : AV_PIX_FMT_P010); +#else + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P10MSB : (is_yuv422 ? AV_PIX_FMT_P210 : AV_PIX_FMT_P010); +#endif break; case 12: - pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P016; +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P16 : (is_yuv422 ? AV_PIX_FMT_P216 : AV_PIX_FMT_P016); +#else + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P12MSB : (is_yuv422 ? AV_PIX_FMT_P212 : AV_PIX_FMT_P012); +#endif break; default: - pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_NV12; + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P : (is_yuv422 ? AV_PIX_FMT_NV16 : AV_PIX_FMT_NV12); break; } @@ -1059,7 +1142,7 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) ret = cuvid_test_capabilities(avctx, &ctx->cuparseinfo, probed_width, probed_height, - probed_bit_depth); + probed_bit_depth, is_yuv422, is_yuv444); if (ret < 0) goto error; @@ -1162,6 +1245,7 @@ static const AVCodecHWConfigInternal *const cuvid_hw_configs[] = { .public = { .pix_fmt = AV_PIX_FMT_CUDA, .methods = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX | + AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX | AV_CODEC_HW_CONFIG_METHOD_INTERNAL, .device_type = AV_HWDEVICE_TYPE_CUDA }, diff --git a/libavcodec/d3d12va_av1.c b/libavcodec/d3d12va_av1.c index 4a4d207b4..fdc7195d1 100644 --- a/libavcodec/d3d12va_av1.c +++ b/libavcodec/d3d12va_av1.c @@ -45,7 +45,10 @@ typedef struct AV1DecodePictureContext { unsigned bitstream_size; } AV1DecodePictureContext; -static int d3d12va_av1_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int d3d12va_av1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const AV1DecContext *h = avctx->priv_data; AV1DecodePictureContext *ctx_pic = h->cur_frame.hwaccel_picture_private; @@ -151,7 +154,7 @@ static int d3d12va_av1_end_frame(AVCodecContext *avctx) return ret; } -static int d3d12va_av1_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_av1_decode_init(AVCodecContext *avctx) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); D3D12AV1DecodeContext *av1_ctx = D3D12_AV1_DECODE_CONTEXT(avctx); @@ -179,7 +182,7 @@ static int d3d12va_av1_decode_init(AVCodecContext *avctx) return 0; } -static int d3d12va_av1_decode_uninit(AVCodecContext *avctx) +static av_cold int d3d12va_av1_decode_uninit(AVCodecContext *avctx) { D3D12AV1DecodeContext *ctx = D3D12_AV1_DECODE_CONTEXT(avctx); diff --git a/libavcodec/d3d12va_decode.c b/libavcodec/d3d12va_decode.c index 3b8978635..4e714efb1 100644 --- a/libavcodec/d3d12va_decode.c +++ b/libavcodec/d3d12va_decode.c @@ -41,6 +41,100 @@ typedef struct HelperObjects { uint64_t fence_value; } HelperObjects; +typedef struct ReferenceFrame { + ID3D12Resource *resource; + int used; + ID3D12Resource *output_resource; +} ReferenceFrame; + +static ID3D12Resource *get_reference_only_resource(AVCodecContext *avctx, ID3D12Resource *output_resource) +{ + D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); + AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx; + int i = 0; + ID3D12Resource *resource = NULL; + D3D12_HEAP_PROPERTIES props = { .Type = D3D12_HEAP_TYPE_DEFAULT }; + D3D12_RESOURCE_DESC desc; + ReferenceFrame *reference_only_map = ctx->reference_only_map; + if (reference_only_map == NULL) { + av_log(avctx, AV_LOG_ERROR, "Reference frames are not allocated!\n"); + return NULL; + } + + // find unused resource + for (i = 0; i < ctx->max_num_ref; i++) { + if (!reference_only_map[i].used && reference_only_map[i].resource != NULL) { + reference_only_map[i].used = 1; + resource = reference_only_map[i].resource; + reference_only_map[i].output_resource = output_resource; + return resource; + } + } + + // find space to allocate + for (i = 0; i < ctx->max_num_ref; i++) { + if (reference_only_map[i].resource == NULL) + break; + } + + if (i == ctx->max_num_ref) { + av_log(avctx, AV_LOG_ERROR, "No space for new Reference frame!\n"); + return NULL; + } + + // allocate frame + output_resource->lpVtbl->GetDesc(output_resource, &desc); + desc.Flags = D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; + + if (FAILED(ID3D12Device_CreateCommittedResource(device_hwctx->device, &props, D3D12_HEAP_FLAG_NONE, &desc, + D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&reference_only_map[i].resource))) { + av_log(ctx, AV_LOG_ERROR, "Failed to create D3D12 Reference Resource!\n"); + return NULL; + } + + reference_only_map[i].used = 1; + resource = reference_only_map[i].resource; + reference_only_map[i].output_resource = output_resource; + + return resource; +} + +static void free_reference_only_resources(AVCodecContext *avctx) +{ + D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); + int i; + ReferenceFrame *reference_only_map = ctx->reference_only_map; + if (reference_only_map != NULL) { + for (i = 0; i < ctx->max_num_ref; i++) { + if (reference_only_map[i].resource != NULL) { + D3D12_OBJECT_RELEASE(reference_only_map[i].resource); + } + } + av_freep(&ctx->reference_only_map); + av_freep(&ctx->ref_only_resources); + } +} + +static void prepare_reference_only_resources(AVCodecContext *avctx) +{ + D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); + int i, j; + ReferenceFrame *reference_only_map = ctx->reference_only_map; + if (reference_only_map == NULL) + return; + memset(ctx->ref_only_resources, 0, ctx->max_num_ref * sizeof(*(ctx->ref_only_resources))); + for (j = 0; j < ctx->max_num_ref; j++) { + for (i = 0; i < ctx->max_num_ref; i++) { + if (reference_only_map[j].used && reference_only_map[j].output_resource == ctx->ref_resources[i]) { + ctx->ref_only_resources[i] = reference_only_map[j].resource; + break; + } + } + if (i == ctx->max_num_ref) + reference_only_map[j].used = 0; + } +} + int ff_d3d12va_get_suitable_max_bitstream_size(AVCodecContext *avctx) { AVHWFramesContext *frames_ctx = D3D12VA_FRAMES_CONTEXT(avctx); @@ -250,6 +344,18 @@ static int d3d12va_create_decoder(AVCodecContext *avctx) return AVERROR_PATCHWELCOME; } + ctx->reference_only_map = NULL; + ctx->ref_only_resources = NULL; + if (feature.ConfigurationFlags & D3D12_VIDEO_DECODE_CONFIGURATION_FLAG_REFERENCE_ONLY_ALLOCATIONS_REQUIRED) { + av_log(avctx, AV_LOG_VERBOSE, "Reference-Only Allocations are required for this D3D12 decoder configuration.\n"); + ctx->reference_only_map = av_calloc(ctx->max_num_ref + 1, sizeof(ReferenceFrame)); + if (!ctx->reference_only_map) + return AVERROR(ENOMEM); + ctx->ref_only_resources = av_calloc(ctx->max_num_ref, sizeof(*ctx->ref_only_resources)); + if (!ctx->ref_only_resources) + return AVERROR(ENOMEM); + } + desc = (D3D12_VIDEO_DECODER_DESC) { .NodeMask = 0, .Configuration = ctx->cfg, @@ -280,7 +386,7 @@ int ff_d3d12va_common_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames return 0; } -int ff_d3d12va_decode_init(AVCodecContext *avctx) +av_cold int ff_d3d12va_decode_init(AVCodecContext *avctx) { int ret; AVHWFramesContext *frames_ctx; @@ -370,7 +476,7 @@ fail: return AVERROR(EINVAL); } -int ff_d3d12va_decode_uninit(AVCodecContext *avctx) +av_cold int ff_d3d12va_decode_uninit(AVCodecContext *avctx) { int num_allocator = 0; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); @@ -394,6 +500,7 @@ int ff_d3d12va_decode_uninit(AVCodecContext *avctx) av_log(avctx, AV_LOG_VERBOSE, "Total number of command allocators reused: %d\n", num_allocator); } + free_reference_only_resources(avctx); av_fifo_freep2(&ctx->objects_queue); @@ -412,14 +519,15 @@ static inline int d3d12va_update_reference_frames_state(AVCodecContext *avctx, D ID3D12Resource *current_resource, int state_before, int state_end) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); + ID3D12Resource **ref_resources = ctx->ref_only_resources ? ctx->ref_only_resources : ctx->ref_resources; int num_barrier = 0; for (int i = 0; i < ctx->max_num_ref; i++) { - if (((ctx->used_mask >> i) & 0x1) && ctx->ref_resources[i] && ctx->ref_resources[i] != current_resource) { + if (((ctx->used_mask >> i) & 0x1) && ref_resources[i] && ref_resources[i] != current_resource) { barriers[num_barrier].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barriers[num_barrier].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barriers[num_barrier].Transition = (D3D12_RESOURCE_TRANSITION_BARRIER){ - .pResource = ctx->ref_resources[i], + barriers[num_barrier].Transition = (D3D12_RESOURCE_TRANSITION_BARRIER) { + .pResource = ref_resources[i], .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, .StateBefore = state_before, .StateAfter = state_end, @@ -440,8 +548,9 @@ int ff_d3d12va_common_end_frame(AVCodecContext *avctx, AVFrame *frame, D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); ID3D12Resource *buffer = NULL; ID3D12CommandAllocator *command_allocator = NULL; - AVD3D12VAFrame *f = (AVD3D12VAFrame *)frame->data[0]; - ID3D12Resource *resource = (ID3D12Resource *)f->texture; + AVD3D12VAFrame *f = (AVD3D12VAFrame*)frame->data[0]; + ID3D12Resource *output_resource = (ID3D12Resource*)f->texture; + ID3D12Resource *ref_resource = NULL; ID3D12VideoDecodeCommandList *cmd_list = ctx->command_list; D3D12_RESOURCE_BARRIER barriers[32] = { 0 }; @@ -466,25 +575,55 @@ int ff_d3d12va_common_end_frame(AVCodecContext *avctx, AVFrame *frame, D3D12_VIDEO_DECODE_OUTPUT_STREAM_ARGUMENTS output_args = { .ConversionArguments = { 0 }, .OutputSubresource = 0, - .pOutputTexture2D = resource, + .pOutputTexture2D = output_resource, }; + memset(ctx->ref_subresources, 0, sizeof(UINT) * ctx->max_num_ref); + input_args.ReferenceFrames.NumTexture2Ds = ctx->max_num_ref; + input_args.ReferenceFrames.pSubresources = ctx->ref_subresources; + + if (ctx->reference_only_map) { + ref_resource = get_reference_only_resource(avctx, output_resource); + if (ref_resource == NULL) { + av_log(avctx, AV_LOG_ERROR, "Failed to get reference frame!\n"); + goto fail; + } + prepare_reference_only_resources(avctx); + + output_args.ConversionArguments.Enable = 1; + input_args.ReferenceFrames.ppTexture2Ds = ctx->ref_only_resources; + output_args.ConversionArguments.pReferenceTexture2D = ref_resource; + output_args.ConversionArguments.ReferenceSubresource = 0; + } else { + ref_resource = output_resource; + input_args.ReferenceFrames.ppTexture2Ds = ctx->ref_resources; + } + UINT num_barrier = 1; barriers[0] = (D3D12_RESOURCE_BARRIER) { .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, .Transition = { - .pResource = resource, + .pResource = output_resource, .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, .StateBefore = D3D12_RESOURCE_STATE_COMMON, .StateAfter = D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE, }, }; - memset(ctx->ref_subresources, 0, sizeof(UINT) * ctx->max_num_ref); - input_args.ReferenceFrames.NumTexture2Ds = ctx->max_num_ref; - input_args.ReferenceFrames.ppTexture2Ds = ctx->ref_resources; - input_args.ReferenceFrames.pSubresources = ctx->ref_subresources; + if (ctx->reference_only_map) { + barriers[1] = (D3D12_RESOURCE_BARRIER) { + .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, + .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, + .Transition = { + .pResource = ref_resource, + .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, + .StateBefore = D3D12_RESOURCE_STATE_COMMON, + .StateAfter = D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE, + }, + }; + num_barrier++; + } ret = d3d12va_fence_completion(&f->sync_ctx); if (ret < 0) @@ -505,7 +644,7 @@ int ff_d3d12va_common_end_frame(AVCodecContext *avctx, AVFrame *frame, DX_CHECK(ID3D12VideoDecodeCommandList_Reset(cmd_list, command_allocator)); - num_barrier += d3d12va_update_reference_frames_state(avctx, &barriers[1], resource, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_DECODE_READ); + num_barrier += d3d12va_update_reference_frames_state(avctx, &barriers[num_barrier], ref_resource, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_DECODE_READ); ID3D12VideoDecodeCommandList_ResourceBarrier(cmd_list, num_barrier, barriers); diff --git a/libavcodec/d3d12va_decode.h b/libavcodec/d3d12va_decode.h index b64994760..c77100422 100644 --- a/libavcodec/d3d12va_decode.h +++ b/libavcodec/d3d12va_decode.h @@ -119,6 +119,19 @@ typedef struct D3D12VADecodeContext { * Private to the FFmpeg AVHWAccel implementation */ unsigned report_id; + + /** + * The Reference-Only feature in DirectX 12 is a memory optimization + * technique designed for video decoding/encoding scenarios. + * This feature requires that reference resources must be allocated + * with the `D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY` resource flag. + * Reference textures must also be separated from output textures. + * reference_only_map used as a storage for reference only frames + * ref_only_resources used as a shadow for ref_resources + */ + void *reference_only_map; + ID3D12Resource **ref_only_resources; + } D3D12VADecodeContext; /** diff --git a/libavcodec/d3d12va_encode.c b/libavcodec/d3d12va_encode.c index 897544fe1..2cca179b8 100644 --- a/libavcodec/d3d12va_encode.c +++ b/libavcodec/d3d12va_encode.c @@ -29,6 +29,7 @@ #include "libavutil/hwcontext_d3d12va_internal.h" #include "libavutil/hwcontext_d3d12va.h" +#include "config_components.h" #include "avcodec.h" #include "d3d12va_encode.h" #include "encode.h" @@ -38,6 +39,29 @@ const AVCodecHWConfigInternal *const ff_d3d12va_encode_hw_configs[] = { NULL, }; +void ff_d3d12va_encode_check_encoder_feature_flags(void *log_ctx, + D3D12_VIDEO_ENCODER_VALIDATION_FLAGS flags) +{ + if (flags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_CODEC_NOT_SUPPORTED) + av_log(log_ctx, AV_LOG_ERROR, " - Codec not supported\n"); + if (flags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_INPUT_FORMAT_NOT_SUPPORTED) + av_log(log_ctx, AV_LOG_ERROR, " - Input format not supported\n"); + if (flags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_CODEC_CONFIGURATION_NOT_SUPPORTED) + av_log(log_ctx, AV_LOG_ERROR, " - Codec configuration not supported\n"); + if (flags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_MODE_NOT_SUPPORTED) + av_log(log_ctx, AV_LOG_ERROR, " - Rate control mode not supported\n"); + if (flags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_CONFIGURATION_NOT_SUPPORTED) + av_log(log_ctx, AV_LOG_ERROR, " - Rate control configuration not supported\n"); + if (flags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_INTRA_REFRESH_MODE_NOT_SUPPORTED) + av_log(log_ctx, AV_LOG_ERROR, " - Intra refresh mode not supported\n"); + if (flags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_SUBREGION_LAYOUT_MODE_NOT_SUPPORTED) + av_log(log_ctx, AV_LOG_ERROR, " - Subregion layout mode not supported\n"); + if (flags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RESOLUTION_NOT_SUPPORTED_IN_LIST) + av_log(log_ctx, AV_LOG_ERROR, " - Resolution not supported\n"); + if (flags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_GOP_STRUCTURE_NOT_SUPPORTED) + av_log(log_ctx, AV_LOG_ERROR, " - GOP structure not supported\n"); +} + static int d3d12va_fence_completion(AVD3D12VASyncContext *psync_ctx) { uint64_t completion = ID3D12Fence_GetCompletedValue(psync_ctx->fence); @@ -139,11 +163,116 @@ static int d3d12va_encode_wait(AVCodecContext *avctx, return 0; } +static int d3d12va_encode_setup_roi(AVCodecContext *avctx, + D3D12VAEncodePicture *pic, + const uint8_t *data, size_t size) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + const AVRegionOfInterest *roi; + uint32_t roi_size; + int nb_roi, i; + int block_width, block_height; + int block_size, qp_range; + int is_av1 = 0; + + // Use the QP map region size reported by the driver + block_size = ctx->qp_map_region_size; + + // Determine QP range and element size based on codec + switch (ctx->codec->d3d12_codec) { + case D3D12_VIDEO_ENCODER_CODEC_H264: + case D3D12_VIDEO_ENCODER_CODEC_HEVC: + qp_range = 51; + is_av1 = 0; + break; +#if CONFIG_AV1_D3D12VA_ENCODER + case D3D12_VIDEO_ENCODER_CODEC_AV1: + qp_range = 255; + is_av1 = 1; + break; +#endif + default: + av_log(avctx, AV_LOG_ERROR, "Unsupported codec for ROI.\n"); + return AVERROR(EINVAL); + } + + // Calculate map dimensions using ceil division as required by D3D12 + block_width = (avctx->width + block_size - 1) / block_size; + block_height = (avctx->height + block_size - 1) / block_size; + + // Allocate QP map with correct type based on codec + if (is_av1) { + pic->qp_map = av_calloc(block_width * block_height, sizeof(int16_t)); + } else { + pic->qp_map = av_calloc(block_width * block_height, sizeof(int8_t)); + } + if (!pic->qp_map) + return AVERROR(ENOMEM); + + // Process ROI regions + roi = (const AVRegionOfInterest *)data; + roi_size = roi->self_size; + av_assert0(roi_size && size % roi_size == 0); + nb_roi = size / roi_size; + + // Iterate in reverse for priority (first region in array takes priority on overlap) + for (i = nb_roi - 1; i >= 0; i--) { + int startx, endx, starty, endy; + int delta_qp; + int x, y; + + roi = (const AVRegionOfInterest *)(data + roi_size * i); + + // Convert pixel coordinates to block coordinates + starty = FFMIN(block_height, roi->top / block_size); + endy = FFMIN(block_height, (roi->bottom + block_size - 1) / block_size); + startx = FFMIN(block_width, roi->left / block_size); + endx = FFMIN(block_width, (roi->right + block_size - 1) / block_size); + + if (roi->qoffset.den == 0) { + av_freep(&pic->qp_map); + av_log(avctx, AV_LOG_ERROR, "AVRegionOfInterest.qoffset.den must not be zero.\n"); + return AVERROR(EINVAL); + } + + // Convert qoffset to delta QP + delta_qp = roi->qoffset.num * qp_range / roi->qoffset.den; + + av_log(avctx, AV_LOG_DEBUG, "ROI: (%d,%d)-(%d,%d) -> %+d.\n", + roi->top, roi->left, roi->bottom, roi->right, delta_qp); + + // Fill QP map for this ROI region with correct type + if (is_av1) { + int16_t *qp_map_int16 = (int16_t *)pic->qp_map; + delta_qp = av_clip_int16(delta_qp); + for (y = starty; y < endy; y++) + for (x = startx; x < endx; x++) + qp_map_int16[x + y * block_width] = delta_qp; + } else { + int8_t *qp_map_int8 = (int8_t *)pic->qp_map; + delta_qp = av_clip_int8(delta_qp); + for (y = starty; y < endy; y++) + for (x = startx; x < endx; x++) + qp_map_int8[x + y * block_width] = delta_qp; + } + } + + pic->qp_map_size = block_width * block_height; + + return 0; +} + static int d3d12va_encode_create_metadata_buffers(AVCodecContext *avctx, D3D12VAEncodePicture *pic) { D3D12VAEncodeContext *ctx = avctx->priv_data; int width = sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA) + sizeof(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA); +#if CONFIG_AV1_D3D12VA_ENCODER + if (ctx->codec->d3d12_codec == D3D12_VIDEO_ENCODER_CODEC_AV1) { + width += sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES) + + sizeof(D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES); + } +#endif D3D12_HEAP_PROPERTIES encoded_meta_props = { .Type = D3D12_HEAP_TYPE_DEFAULT }, resolved_meta_props; D3D12_HEAP_TYPE resolved_heap_type = D3D12_HEAP_TYPE_READBACK; HRESULT hr; @@ -191,7 +320,7 @@ static int d3d12va_encode_issue(AVCodecContext *avctx, FFHWBaseEncodeContext *base_ctx = avctx->priv_data; D3D12VAEncodeContext *ctx = avctx->priv_data; D3D12VAEncodePicture *pic = base_pic->priv; - AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx; + AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx; int err, i, j; HRESULT hr; char data[MAX_PARAM_BUFFER_SIZE]; @@ -201,15 +330,24 @@ static int d3d12va_encode_issue(AVCodecContext *avctx, ID3D12VideoEncodeCommandList2 *cmd_list = ctx->command_list; D3D12_RESOURCE_BARRIER barriers[32] = { 0 }; D3D12_VIDEO_ENCODE_REFERENCE_FRAMES d3d12_refs = { 0 }; + int barriers_ref_index = 0; + D3D12_RESOURCE_BARRIER *barriers_ref = NULL; + + D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS seq_flags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE; + + // Request intra refresh if enabled + if (ctx->intra_refresh.Mode != D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE) { + seq_flags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_REQUEST_INTRA_REFRESH; + } D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS input_args = { .SequenceControlDesc = { - .Flags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE, - .IntraRefreshConfig = { 0 }, + .Flags = seq_flags, + .IntraRefreshConfig = ctx->intra_refresh, .RateControl = ctx->rc, .PictureTargetResolution = ctx->resolution, .SelectedLayoutMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME, - .FrameSubregionsLayoutData = { 0 }, + .FrameSubregionsLayoutData = ctx->subregions_layout, .CodecGopSequence = ctx->gop, }, .pInputFrame = pic->input_surface->texture, @@ -268,6 +406,8 @@ static int d3d12va_encode_issue(AVCodecContext *avctx, av_log(avctx, AV_LOG_DEBUG, "Recon surface is %p.\n", pic->recon_surface->texture); + pic->subresource_index = ctx->is_texture_array ? pic->recon_surface->subresource_index : 0; + pic->output_buffer_ref = av_buffer_pool_get(ctx->output_buffer_pool); if (!pic->output_buffer_ref) { err = AVERROR(ENOMEM); @@ -281,6 +421,20 @@ static int d3d12va_encode_issue(AVCodecContext *avctx, if (err < 0) goto fail; + // Process ROI side data if present and supported + AVFrameSideData *sd = av_frame_get_side_data(base_pic->input_image, + AV_FRAME_DATA_REGIONS_OF_INTEREST); + if (sd && base_ctx->roi_allowed) { + err = d3d12va_encode_setup_roi(avctx, pic, sd->data, sd->size); + if (err < 0) + goto fail; + + // Enable delta QP flag in rate control only if supported + input_args.SequenceControlDesc.RateControl.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP; + av_log(avctx, AV_LOG_DEBUG, "ROI delta QP map created with %d blocks (region size: %d pixels).\n", + pic->qp_map_size, ctx->qp_map_region_size); + } + if (ctx->codec->init_picture_params) { err = ctx->codec->init_picture_params(avctx, base_pic); if (err < 0) { @@ -299,21 +453,20 @@ static int d3d12va_encode_issue(AVCodecContext *avctx, "header: %d.\n", err); goto fail; } + pic->header_size = (int)bit_len / 8; + pic->aligned_header_size = pic->header_size % ctx->req.CompressedBitstreamBufferAccessAlignment ? + FFALIGN(pic->header_size, ctx->req.CompressedBitstreamBufferAccessAlignment) : + pic->header_size; + + hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&ptr); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + goto fail; + } + + memcpy(ptr, data, pic->aligned_header_size); + ID3D12Resource_Unmap(pic->output_buffer, 0, NULL); } - - pic->header_size = (int)bit_len / 8; - pic->aligned_header_size = pic->header_size % ctx->req.CompressedBitstreamBufferAccessAlignment ? - FFALIGN(pic->header_size, ctx->req.CompressedBitstreamBufferAccessAlignment) : - pic->header_size; - - hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&ptr); - if (FAILED(hr)) { - err = AVERROR_UNKNOWN; - goto fail; - } - - memcpy(ptr, data, pic->aligned_header_size); - ID3D12Resource_Unmap(pic->output_buffer, 0, NULL); } d3d12_refs.NumTexture2Ds = base_pic->nb_refs[0] + base_pic->nb_refs[1]; @@ -325,14 +478,31 @@ static int d3d12va_encode_issue(AVCodecContext *avctx, goto fail; } + if (ctx->is_texture_array) { + d3d12_refs.pSubresources = av_calloc(d3d12_refs.NumTexture2Ds, + sizeof(*d3d12_refs.pSubresources)); + if (!d3d12_refs.pSubresources) { + err = AVERROR(ENOMEM); + goto fail; + } + } + i = 0; - for (j = 0; j < base_pic->nb_refs[0]; j++) - d3d12_refs.ppTexture2Ds[i++] = ((D3D12VAEncodePicture *)base_pic->refs[0][j]->priv)->recon_surface->texture; - for (j = 0; j < base_pic->nb_refs[1]; j++) - d3d12_refs.ppTexture2Ds[i++] = ((D3D12VAEncodePicture *)base_pic->refs[1][j]->priv)->recon_surface->texture; + for (j = 0; j < base_pic->nb_refs[0]; j++) { + d3d12_refs.ppTexture2Ds[i] = ((D3D12VAEncodePicture *)base_pic->refs[0][j]->priv)->recon_surface->texture; + if (ctx->is_texture_array) + d3d12_refs.pSubresources[i] = ((D3D12VAEncodePicture *)base_pic->refs[0][j]->priv)->subresource_index; + i++; + } + for (j = 0; j < base_pic->nb_refs[1]; j++) { + d3d12_refs.ppTexture2Ds[i] = ((D3D12VAEncodePicture *)base_pic->refs[1][j]->priv)->recon_surface->texture; + if (ctx->is_texture_array) + d3d12_refs.pSubresources[i] = ((D3D12VAEncodePicture *)base_pic->refs[1][j]->priv)->subresource_index; + i++; + } } - input_args.PictureControlDesc.IntraRefreshFrameIndex = 0; + input_args.PictureControlDesc.IntraRefreshFrameIndex = ctx->intra_refresh_frame_index; if (base_pic->is_reference) input_args.PictureControlDesc.Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE; @@ -343,7 +513,7 @@ static int d3d12va_encode_issue(AVCodecContext *avctx, output_args.Bitstream.pBuffer = pic->output_buffer; output_args.Bitstream.FrameStartOffset = pic->aligned_header_size; output_args.ReconstructedPicture.pReconstructedPicture = pic->recon_surface->texture; - output_args.ReconstructedPicture.ReconstructedPictureSubresource = 0; + output_args.ReconstructedPicture.ReconstructedPictureSubresource = ctx->is_texture_array ? pic->subresource_index : 0; output_args.EncoderOutputMetadata.pBuffer = pic->encoded_metadata; output_args.EncoderOutputMetadata.Offset = 0; @@ -369,52 +539,89 @@ static int d3d12va_encode_issue(AVCodecContext *avctx, goto fail; } -#define TRANSITION_BARRIER(res, before, after) \ +#define TRANSITION_BARRIER(res, subres, before, after) \ (D3D12_RESOURCE_BARRIER) { \ .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, \ .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, \ .Transition = { \ .pResource = res, \ - .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, \ + .Subresource = subres, \ .StateBefore = before, \ .StateAfter = after, \ }, \ } barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ); barriers[1] = TRANSITION_BARRIER(pic->output_buffer, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE); - barriers[2] = TRANSITION_BARRIER(pic->recon_surface->texture, + barriers[2] = TRANSITION_BARRIER(pic->encoded_metadata, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE); - barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata, - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE); - barriers[4] = TRANSITION_BARRIER(pic->resolved_metadata, + barriers[3] = TRANSITION_BARRIER(pic->resolved_metadata, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE); - ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 5, barriers); + ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 4, barriers); - if (d3d12_refs.NumTexture2Ds) { - D3D12_RESOURCE_BARRIER refs_barriers[3]; + if (ctx->is_texture_array) + barriers_ref = av_calloc(base_ctx->recon_frames->initial_pool_size * ctx->plane_count, + sizeof(D3D12_RESOURCE_BARRIER)); + else + barriers_ref = av_calloc(MAX_DPB_SIZE, sizeof(D3D12_RESOURCE_BARRIER)); - for (i = 0; i < d3d12_refs.NumTexture2Ds; i++) - refs_barriers[i] = TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i], - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ); + if (ctx->is_texture_array) { + D3D12_RESOURCE_DESC references_tex_array_desc = { 0 }; + pic->recon_surface->texture->lpVtbl->GetDesc(pic->recon_surface->texture, &references_tex_array_desc); - ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, d3d12_refs.NumTexture2Ds, - refs_barriers); + for (uint32_t reference_subresource = 0; reference_subresource < references_tex_array_desc.DepthOrArraySize; + reference_subresource++) { + + uint32_t array_size = references_tex_array_desc.DepthOrArraySize; + uint32_t mip_slice = reference_subresource % references_tex_array_desc.MipLevels; + uint32_t array_slice = (reference_subresource / references_tex_array_desc.MipLevels) % array_size; + + for (uint32_t plane_slice = 0; plane_slice < ctx->plane_count; plane_slice++) { + uint32_t outputSubresource = mip_slice + array_slice * references_tex_array_desc.MipLevels + + plane_slice * references_tex_array_desc.MipLevels * array_size; + if (reference_subresource == pic->subresource_index) { + barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(pic->recon_surface->texture, outputSubresource, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE); + } else { + barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(pic->recon_surface->texture, outputSubresource, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ); + } + } + } + } else { + barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(pic->recon_surface->texture, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE); + + if (d3d12_refs.NumTexture2Ds) { + for (i = 0; i < d3d12_refs.NumTexture2Ds; i++) + barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i], + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ); + } } + ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, barriers_ref_index, barriers_ref); ID3D12VideoEncodeCommandList2_EncodeFrame(cmd_list, ctx->encoder, ctx->encoder_heap, &input_args, &output_args); barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE, D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ); @@ -422,35 +629,32 @@ static int d3d12va_encode_issue(AVCodecContext *avctx, ID3D12VideoEncodeCommandList2_ResolveEncoderOutputMetadata(cmd_list, &input_metadata, &output_metadata); - if (d3d12_refs.NumTexture2Ds) { - D3D12_RESOURCE_BARRIER refs_barriers[3]; + if (barriers_ref_index > 0) { + for (i = 0; i < barriers_ref_index; i++) + FFSWAP(D3D12_RESOURCE_STATES, barriers_ref[i].Transition.StateBefore, barriers_ref[i].Transition.StateAfter); - for (i = 0; i < d3d12_refs.NumTexture2Ds; i++) - refs_barriers[i] = TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i], - D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ, - D3D12_RESOURCE_STATE_COMMON); - - ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, d3d12_refs.NumTexture2Ds, - refs_barriers); + ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, barriers_ref_index, + barriers_ref); } barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ, D3D12_RESOURCE_STATE_COMMON); barriers[1] = TRANSITION_BARRIER(pic->output_buffer, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE, D3D12_RESOURCE_STATE_COMMON); - barriers[2] = TRANSITION_BARRIER(pic->recon_surface->texture, - D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE, - D3D12_RESOURCE_STATE_COMMON); - barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata, + barriers[2] = TRANSITION_BARRIER(pic->encoded_metadata, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ, D3D12_RESOURCE_STATE_COMMON); - barriers[4] = TRANSITION_BARRIER(pic->resolved_metadata, + barriers[3] = TRANSITION_BARRIER(pic->resolved_metadata, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE, D3D12_RESOURCE_STATE_COMMON); - ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 5, barriers); + ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 4, barriers); hr = ID3D12VideoEncodeCommandList2_Close(cmd_list); if (FAILED(hr)) { @@ -486,9 +690,21 @@ static int d3d12va_encode_issue(AVCodecContext *avctx, pic->fence_value = ctx->sync_ctx.fence_value; + // Update intra refresh frame index for next frame + if (ctx->intra_refresh.Mode != D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE) { + ctx->intra_refresh_frame_index = + (ctx->intra_refresh_frame_index + 1) % ctx->intra_refresh.IntraRefreshDuration; + } + if (d3d12_refs.ppTexture2Ds) av_freep(&d3d12_refs.ppTexture2Ds); + if (ctx->is_texture_array && d3d12_refs.pSubresources) + av_freep(&d3d12_refs.pSubresources); + + if (barriers_ref) + av_freep(&barriers_ref); + return 0; fail: @@ -498,6 +714,12 @@ fail: if (d3d12_refs.ppTexture2Ds) av_freep(&d3d12_refs.ppTexture2Ds); + if (ctx->is_texture_array && d3d12_refs.pSubresources) + av_freep(&d3d12_refs.pSubresources); + + if (barriers_ref) + av_freep(&barriers_ref); + if (ctx->codec->free_picture_params) ctx->codec->free_picture_params(pic); @@ -583,6 +805,9 @@ static int d3d12va_encode_free(AVCodecContext *avctx, FFHWBaseEncodePicture *pic if (ctx->codec->free_picture_params) ctx->codec->free_picture_params(priv); + // Free ROI QP map if allocated + av_freep(&priv->qp_map); + return 0; } @@ -634,7 +859,7 @@ static int d3d12va_encode_get_coded_data(AVCodecContext *avctx, goto end; total_size += pic->header_size; - av_log(avctx, AV_LOG_DEBUG, "Output buffer size %"PRId64"\n", total_size); + av_log(avctx, AV_LOG_DEBUG, "Output buffer size %zu\n", total_size); hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&mapped_data); if (FAILED(hr)) { @@ -666,16 +891,21 @@ end: static int d3d12va_encode_output(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic, AVPacket *pkt) { + D3D12VAEncodeContext *ctx = avctx->priv_data; FFHWBaseEncodeContext *base_ctx = avctx->priv_data; - D3D12VAEncodePicture *pic = base_pic->priv; - AVPacket *pkt_ptr = pkt; - int err; + D3D12VAEncodePicture *pic = base_pic->priv; + AVPacket *pkt_ptr = pkt; + int err = 0; err = d3d12va_encode_wait(avctx, base_pic); if (err < 0) return err; - err = d3d12va_encode_get_coded_data(avctx, pic, pkt); + if (ctx->codec->get_coded_data) + err = ctx->codec->get_coded_data(avctx, pic, pkt); + else + err = d3d12va_encode_get_coded_data(avctx, pic, pkt); + if (err < 0) return err; @@ -787,6 +1017,21 @@ static int d3d12va_encode_init_rate_control(AVCodecContext *avctx) int fr_num, fr_den; const D3D12VAEncodeRCMode *rc_mode; +#define SET_QP_RANGE(ctl) do { \ + if (avctx->qmin > 0 || avctx->qmax > 0) { \ + ctl->MinQP = avctx->qmin; \ + ctl->MaxQP = avctx->qmax; \ + ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE; \ + } \ + } while(0) + +#define SET_MAX_FRAME_SIZE(ctl) do { \ + if (ctx->max_frame_size > 0) { \ + ctl->MaxFrameBitSize = ctx->max_frame_size * 8; \ + ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE; \ + } \ + } while(0) + // Rate control mode selection: // * If the user has set a mode explicitly with the rc_mode option, // use it and fail if it is not available. @@ -987,11 +1232,8 @@ rc_mode_found: cbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness; ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES; - if (avctx->qmin > 0 || avctx->qmax > 0) { - cbr_ctl->MinQP = avctx->qmin; - cbr_ctl->MaxQP = avctx->qmax; - ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE; - } + SET_QP_RANGE(cbr_ctl); + SET_MAX_FRAME_SIZE(cbr_ctl); ctx->rc.ConfigParams.pConfiguration_CBR = cbr_ctl; break; @@ -1010,11 +1252,8 @@ rc_mode_found: vbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness; ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES; - if (avctx->qmin > 0 || avctx->qmax > 0) { - vbr_ctl->MinQP = avctx->qmin; - vbr_ctl->MaxQP = avctx->qmax; - ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE; - } + SET_QP_RANGE(vbr_ctl); + SET_MAX_FRAME_SIZE(vbr_ctl); ctx->rc.ConfigParams.pConfiguration_VBR = vbr_ctl; break; @@ -1031,11 +1270,8 @@ rc_mode_found: qvbr_ctl->PeakBitRate = rc_peak_bitrate; qvbr_ctl->ConstantQualityTarget = rc_quality; - if (avctx->qmin > 0 || avctx->qmax > 0) { - qvbr_ctl->MinQP = avctx->qmin; - qvbr_ctl->MaxQP = avctx->qmax; - ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE; - } + SET_QP_RANGE(qvbr_ctl); + SET_MAX_FRAME_SIZE(qvbr_ctl); ctx->rc.ConfigParams.pConfiguration_QVBR = qvbr_ctl; break; @@ -1057,6 +1293,9 @@ static int d3d12va_encode_init_gop_structure(AVCodecContext *avctx) union { D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264; D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC hevc; +#if CONFIG_AV1_D3D12VA_ENCODER + D3D12_VIDEO_ENCODER_CODEC_AV1_PICTURE_CONTROL_SUPPORT av1; +#endif } codec_support; support.NodeIndex = 0; @@ -1074,6 +1313,13 @@ static int d3d12va_encode_init_gop_structure(AVCodecContext *avctx) support.PictureSupport.pHEVCSupport = &codec_support.hevc; break; +#if CONFIG_AV1_D3D12VA_ENCODER + case D3D12_VIDEO_ENCODER_CODEC_AV1: + memset(&codec_support.av1, 0, sizeof(codec_support.av1)); + support.PictureSupport.DataSize = sizeof(codec_support.av1); + support.PictureSupport.pAV1Support = &codec_support.av1; + break; +#endif default: av_assert0(0); } @@ -1087,16 +1333,25 @@ static int d3d12va_encode_init_gop_structure(AVCodecContext *avctx) switch (ctx->codec->d3d12_codec) { case D3D12_VIDEO_ENCODER_CODEC_H264: ref_l0 = FFMIN(support.PictureSupport.pH264Support->MaxL0ReferencesForP, - support.PictureSupport.pH264Support->MaxL1ReferencesForB); + support.PictureSupport.pH264Support->MaxL1ReferencesForB ? + support.PictureSupport.pH264Support->MaxL1ReferencesForB : UINT_MAX); ref_l1 = support.PictureSupport.pH264Support->MaxL1ReferencesForB; break; case D3D12_VIDEO_ENCODER_CODEC_HEVC: ref_l0 = FFMIN(support.PictureSupport.pHEVCSupport->MaxL0ReferencesForP, - support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB); + support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB ? + support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB : UINT_MAX); ref_l1 = support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB; break; +#if CONFIG_AV1_D3D12VA_ENCODER + case D3D12_VIDEO_ENCODER_CODEC_AV1: + ref_l0 = support.PictureSupport.pAV1Support->MaxUniqueReferencesPerFrame; + // AV1 doesn't use traditional L1 references like H.264/HEVC + ref_l1 = 0; + break; +#endif default: av_assert0(0); } @@ -1117,6 +1372,81 @@ static int d3d12va_encode_init_gop_structure(AVCodecContext *avctx) return 0; } +static int d3d12va_encode_init_intra_refresh(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + + if (ctx->intra_refresh.Mode == D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE) + return 0; + + // Check for SDK API availability +#if CONFIG_D3D12_INTRA_REFRESH + HRESULT hr; + D3D12_VIDEO_ENCODER_LEVEL_SETTING level = { 0 }; + D3D12_VIDEO_ENCODER_LEVELS_H264 h264_level = { 0 }; + D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC hevc_level = { 0 }; +#if CONFIG_AV1_D3D12VA_ENCODER + D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS av1_level = { 0 }; +#endif + + switch (ctx->codec->d3d12_codec) { + case D3D12_VIDEO_ENCODER_CODEC_H264: + level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVELS_H264); + level.pH264LevelSetting = &h264_level; + break; + case D3D12_VIDEO_ENCODER_CODEC_HEVC: + level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC); + level.pHEVCLevelSetting = &hevc_level; + break; +#if CONFIG_AV1_D3D12VA_ENCODER + case D3D12_VIDEO_ENCODER_CODEC_AV1: + level.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS); + level.pAV1LevelSetting = &av1_level; + break; +#endif + default: + av_assert0(0); + } + + D3D12_FEATURE_DATA_VIDEO_ENCODER_INTRA_REFRESH_MODE intra_refresh_support = { + .NodeIndex = 0, + .Codec = ctx->codec->d3d12_codec, + .Profile = ctx->profile->d3d12_profile, + .Level = level, + .IntraRefreshMode = ctx->intra_refresh.Mode, + }; + + hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, + D3D12_FEATURE_VIDEO_ENCODER_INTRA_REFRESH_MODE, + &intra_refresh_support, sizeof(intra_refresh_support)); + + if (FAILED(hr) || !intra_refresh_support.IsSupported) { + av_log(avctx, AV_LOG_ERROR, "Requested intra refresh mode not supported by driver.\n"); + return AVERROR(ENOTSUP); + } +#else + // Older SDK - validation will occur in init_sequence_params via D3D12_FEATURE_VIDEO_ENCODER_SUPPORT + av_log(avctx, AV_LOG_VERBOSE, "Intra refresh explicit check not available in this SDK.\n" + "Support will be validated during encoder initialization.\n"); +#endif + + // Set duration: use GOP size if not specified + if (ctx->intra_refresh.IntraRefreshDuration == 0) { + ctx->intra_refresh.IntraRefreshDuration = base_ctx->gop_size; + av_log(avctx, AV_LOG_VERBOSE, "Intra refresh duration set to GOP size: %d\n", + ctx->intra_refresh.IntraRefreshDuration); + } + + // Initialize frame index + ctx->intra_refresh_frame_index = 0; + + av_log(avctx, AV_LOG_VERBOSE, "Intra refresh: mode=%d, duration=%d frames\n", + ctx->intra_refresh.Mode, ctx->intra_refresh.IntraRefreshDuration); + + return 0; +} + static int d3d12va_create_encoder(AVCodecContext *avctx) { FFHWBaseEncodeContext *base_ctx = avctx->priv_data; @@ -1131,7 +1461,7 @@ static int d3d12va_create_encoder(AVCodecContext *avctx) .EncodeProfile = ctx->profile->d3d12_profile, .InputFormat = frames_hwctx->format, .CodecConfiguration = ctx->codec_conf, - .MaxMotionEstimationPrecision = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM, + .MaxMotionEstimationPrecision = ctx->me_precision, }; hr = ID3D12VideoDevice3_CreateVideoEncoder(ctx->video_device3, &desc, &IID_ID3D12VideoEncoder, @@ -1151,7 +1481,7 @@ static int d3d12va_create_encoder_heap(AVCodecContext *avctx) D3D12_VIDEO_ENCODER_HEAP_DESC desc = { .NodeMask = 0, - .Flags = D3D12_VIDEO_ENCODER_FLAG_NONE, + .Flags = D3D12_VIDEO_ENCODER_HEAP_FLAG_NONE, .EncodeCodec = ctx->codec->d3d12_codec, .EncodeProfile = ctx->profile->d3d12_profile, .EncodeLevel = ctx->level, @@ -1263,7 +1593,7 @@ static int d3d12va_encode_create_command_objects(AVCodecContext *avctx) { D3D12VAEncodeContext *ctx = avctx->priv_data; ID3D12CommandAllocator *command_allocator = NULL; - int err; + int err = AVERROR_UNKNOWN; HRESULT hr; D3D12_COMMAND_QUEUE_DESC queue_desc = { @@ -1338,6 +1668,7 @@ fail: static int d3d12va_encode_create_recon_frames(AVCodecContext *avctx) { FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; AVD3D12VAFramesContext *hwctx; enum AVPixelFormat recon_format; int err; @@ -1358,8 +1689,12 @@ static int d3d12va_encode_create_recon_frames(AVCodecContext *avctx) base_ctx->recon_frames->width = base_ctx->surface_width; base_ctx->recon_frames->height = base_ctx->surface_height; - hwctx->flags = D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY | - D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; + hwctx->resource_flags = D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY | + D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; + if (ctx->is_texture_array) { + base_ctx->recon_frames->initial_pool_size = MAX_DPB_SIZE + 1; + hwctx->flags |= AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY; + } err = av_hwframe_ctx_init(base_ctx->recon_frames_ref); if (err < 0) { @@ -1393,6 +1728,7 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx) FFHWBaseEncodeContext *base_ctx = avctx->priv_data; D3D12VAEncodeContext *ctx = avctx->priv_data; D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT support = { 0 }; + D3D12_FEATURE_DATA_FORMAT_INFO format_info = { 0 }; int err; HRESULT hr; @@ -1428,10 +1764,25 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx) goto fail; } + format_info.Format = ((AVD3D12VAFramesContext *)base_ctx->input_frames->hwctx)->format; + if (FAILED(ID3D12VideoDevice_CheckFeatureSupport(ctx->hwctx->device, D3D12_FEATURE_FORMAT_INFO, + &format_info, sizeof(format_info)))) { + av_log(avctx, AV_LOG_ERROR, "Failed to query format plane count: %#lx\n", hr); + err = AVERROR_EXTERNAL; + goto fail; + } + ctx->plane_count = format_info.PlaneCount; + err = d3d12va_encode_set_profile(avctx); if (err < 0) goto fail; + if (ctx->codec->set_tile) { + err = ctx->codec->set_tile(avctx); + if (err < 0) + goto fail; + } + err = d3d12va_encode_init_rate_control(avctx); if (err < 0) goto fail; @@ -1446,6 +1797,10 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx) if (err < 0) goto fail; + err = d3d12va_encode_init_intra_refresh(avctx); + if (err < 0) + goto fail; + if (!(ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL) && avctx->slices > 0) { av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested " "but this codec does not support controlling slices.\n"); @@ -1455,10 +1810,6 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx) if (err < 0) goto fail; - err = d3d12va_encode_create_recon_frames(avctx); - if (err < 0) - goto fail; - err = d3d12va_encode_prepare_output_buffers(avctx); if (err < 0) goto fail; @@ -1484,6 +1835,10 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx) goto fail; } + err = d3d12va_encode_create_recon_frames(avctx); + if (err < 0) + goto fail; + base_ctx->output_delay = base_ctx->b_per_p; base_ctx->decode_delay = base_ctx->max_b_depth; diff --git a/libavcodec/d3d12va_encode.h b/libavcodec/d3d12va_encode.h index 3b0b8153d..f059ae980 100644 --- a/libavcodec/d3d12va_encode.h +++ b/libavcodec/d3d12va_encode.h @@ -52,9 +52,15 @@ typedef struct D3D12VAEncodePicture { ID3D12Resource *encoded_metadata; ID3D12Resource *resolved_metadata; + int subresource_index; + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA pic_ctl; int fence_value; + + // ROI delta QP map (void* to support both INT8 for H.264/HEVC and INT16 for AV1) + void *qp_map; + int qp_map_size; } D3D12VAEncodePicture; typedef struct D3D12VAEncodeProfile { @@ -149,6 +155,11 @@ typedef struct D3D12VAEncodeContext { */ const struct D3D12VAEncodeType *codec; + /** + * Max frame size + */ + int max_frame_size; + /** * Explicitly set RC mode (otherwise attempt to pick from * available modes). @@ -189,6 +200,16 @@ typedef struct D3D12VAEncodeContext { */ AVBufferPool *output_buffer_pool; + /** + * Flag indicates if the HW is texture array mode. + */ + int is_texture_array; + + /** + * The number of planes in the input DXGI FORMAT. + */ + int plane_count; + /** * D3D12 video encoder. */ @@ -247,6 +268,28 @@ typedef struct D3D12VAEncodeContext { D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE gop; D3D12_VIDEO_ENCODER_LEVEL_SETTING level; + + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA subregions_layout; + + /** + * Intra refresh configuration + */ + D3D12_VIDEO_ENCODER_INTRA_REFRESH intra_refresh; + + /** + * Current frame index within intra refresh cycle + */ + UINT intra_refresh_frame_index; + + /** + * Motion estimation precision mode + */ + D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE me_precision; + + /** + * QP map region pixel size (block size for QP map) + */ + int qp_map_region_size; } D3D12VAEncodeContext; typedef struct D3D12VAEncodeType { @@ -289,6 +332,11 @@ typedef struct D3D12VAEncodeType { */ int (*set_level)(AVCodecContext *avctx); + /** + * Set codec-specific tile setting. + */ + int (*set_tile)(AVCodecContext *avctx); + /** * The size of any private data structure associated with each * picture (can be zero if not required). @@ -310,6 +358,12 @@ typedef struct D3D12VAEncodeType { */ int (*write_sequence_header)(AVCodecContext *avctx, char *data, size_t *data_len); + + /** + * Fill the coded data into AVPacket + */ + int (*get_coded_data)(AVCodecContext *avctx, + D3D12VAEncodePicture *pic, AVPacket *pkt); } D3D12VAEncodeType; int ff_d3d12va_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt); @@ -317,6 +371,62 @@ int ff_d3d12va_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt); int ff_d3d12va_encode_init(AVCodecContext *avctx); int ff_d3d12va_encode_close(AVCodecContext *avctx); +void ff_d3d12va_encode_check_encoder_feature_flags(void *log_ctx, + D3D12_VIDEO_ENCODER_VALIDATION_FLAGS flags); + +#define D3D12VA_ENCODE_INTRA_REFRESH_MODE(name, mode, desc) \ + { #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ ## mode }, \ + 0, 0, FLAGS, .unit = "intra_refresh_mode" } + +#if CONFIG_D3D12VA_ME_PRECISION_EIGHTH_PIXEL +#define D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAX_VALUE D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_EIGHTH_PIXEL +#else +#define D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAX_VALUE D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_QUARTER_PIXEL +#endif + +#define D3D12VA_ENCODE_ME_PRECISION_MODE(name, mode, desc) \ + { #name, #desc " pixel precision", 0, AV_OPT_TYPE_CONST, \ + { .i64 = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_ ## mode }, \ + 0, 0, FLAGS, .unit = "me_precision" } + +#if CONFIG_D3D12VA_ME_PRECISION_EIGHTH_PIXEL +#define FFPP_D3D12VA_ME_PRECISION_EIGHTH_PIXEL \ + , D3D12VA_ENCODE_ME_PRECISION_MODE(eighth_pixel, EIGHTH_PIXEL, Eighth) +#else +#define FFPP_D3D12VA_ME_PRECISION_EIGHTH_PIXEL +#endif + +#define D3D12VA_ENCODE_COMMON_OPTIONS \ + { "max_frame_size", \ + "Maximum frame size (in bytes)",\ + OFFSET(common.max_frame_size), AV_OPT_TYPE_INT, \ + { .i64 = 0 }, 0, INT_MAX / 8, FLAGS }, \ + { "intra_refresh_mode", \ + "Set intra refresh mode", \ + OFFSET(common.intra_refresh.Mode), AV_OPT_TYPE_INT, \ + { .i64 = D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE }, \ + D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE, \ + D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ROW_BASED, FLAGS, .unit = "intra_refresh_mode" }, \ + D3D12VA_ENCODE_INTRA_REFRESH_MODE(none, NONE, "Disable intra refresh"), \ + D3D12VA_ENCODE_INTRA_REFRESH_MODE(row_based, ROW_BASED, "Row-based intra refresh"), \ + { "intra_refresh_duration", \ + "Number of frames over which to spread intra refresh (0 = GOP size)", \ + OFFSET(common.intra_refresh.IntraRefreshDuration), AV_OPT_TYPE_INT, \ + { .i64 = 0 }, 0, INT_MAX, FLAGS }, \ + { "me_precision", "Motion estimation precision mode", \ + OFFSET(common.me_precision), AV_OPT_TYPE_INT, \ + { .i64 = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM }, \ + D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM, \ + D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAX_VALUE, \ + FLAGS, .unit = "me_precision" }, \ + { "maximum", "Maximum (best quality, slowest)", 0, AV_OPT_TYPE_CONST, \ + { .i64 = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM }, \ + 0, 0, FLAGS, .unit = "me_precision" }, \ + D3D12VA_ENCODE_ME_PRECISION_MODE(full_pixel, FULL_PIXEL, Full), \ + D3D12VA_ENCODE_ME_PRECISION_MODE(half_pixel, HALF_PIXEL, Half), \ + D3D12VA_ENCODE_ME_PRECISION_MODE(quarter_pixel, QUARTER_PIXEL, Quarter) \ + FFPP_D3D12VA_ME_PRECISION_EIGHTH_PIXEL + #define D3D12VA_ENCODE_RC_MODE(name, desc) \ { #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_ ## name }, \ 0, 0, FLAGS, .unit = "rc_mode" } diff --git a/libavcodec/d3d12va_encode_av1.c b/libavcodec/d3d12va_encode_av1.c new file mode 100644 index 000000000..8d2edec49 --- /dev/null +++ b/libavcodec/d3d12va_encode_av1.c @@ -0,0 +1,1208 @@ +/* + * Direct3D 12 HW acceleration video encoder + * + * Copyright (c) 2024 Intel Corporation + * + * 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/opt.h" +#include "libavutil/common.h" +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" +#include "libavutil/hwcontext_d3d12va_internal.h" + +#include "config_components.h" +#include "avcodec.h" +#include "cbs.h" +#include "cbs_av1.h" +#include "av1_levels.h" +#include "codec_internal.h" +#include "d3d12va_encode.h" +#include "encode.h" +#include "hw_base_encode.h" + +#include +#include + +#ifndef D3D12_VIDEO_ENCODER_AV1_INVALID_DPB_RESOURCE_INDEX +#define D3D12_VIDEO_ENCODER_AV1_INVALID_DPB_RESOURCE_INDEX ( 0xff ) +#endif + +typedef struct D3D12VAHWBaseEncodeAV1 { + AV1RawOBU raw_sequence_header; + AV1RawOBU raw_frame_header; + AV1RawOBU raw_tile_group; +} D3D12VAHWBaseEncodeAV1; + +typedef struct D3D12VAHWBaseEncodeAV1Opts { + int tier; // 0: Main tier, 1: High tier + int level; // AV1 level (2.0-7.3 map to 0-23) + + int enable_cdef; // Constrained Directional Enhancement Filter + int enable_restoration; // loop restoration + int enable_superres; // super-resolution + int enable_ref_frame_mvs; + + int enable_jnt_comp; + int enable_128x128_superblock; + + int enable_warped_motion; + int enable_intra_edge_filter; + int enable_interintra_compound; + int enable_masked_compound; + int enable_filter_intra; + + int enable_loop_filter; + int enable_loop_filter_delta; + int enable_dual_filter; + + int enable_palette; + int enable_intra_block_copy; +} D3D12VAHWBaseEncodeAV1Opts; + +typedef struct D3D12VAEncodeAV1Picture { + uint8_t temporal_id; + uint8_t spatial_id; + uint8_t show_frame; + uint8_t frame_type; + uint16_t last_idr_frame; + uint8_t slot; +} D3D12VAEncodeAV1Picture; + +typedef struct D3D12VAEncodeAV1Context { + D3D12VAEncodeContext common; + // User options. + int qp; + int profile; + int level; + int tier; + + uint8_t q_idx_idr; + uint8_t q_idx_p; + + // Writer structures. + D3D12VAHWBaseEncodeAV1 units; + D3D12VAHWBaseEncodeAV1Opts unit_opts; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_obu; + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAGS post_encode_values_flag; + AVFifo *picture_header_list; +} D3D12VAEncodeAV1Context; + +typedef struct D3D12VAEncodeAV1Level { + uint8_t level; + D3D12_VIDEO_ENCODER_AV1_LEVELS d3d12_level; +} D3D12VAEncodeAV1Level; + + +static const D3D12VAEncodeAV1Level av1_levels[] = { + { 0, D3D12_VIDEO_ENCODER_AV1_LEVELS_2_0 }, + { 1, D3D12_VIDEO_ENCODER_AV1_LEVELS_2_1 }, + { 2, D3D12_VIDEO_ENCODER_AV1_LEVELS_2_2 }, + { 3, D3D12_VIDEO_ENCODER_AV1_LEVELS_2_3 }, + { 4, D3D12_VIDEO_ENCODER_AV1_LEVELS_3_0 }, + { 5, D3D12_VIDEO_ENCODER_AV1_LEVELS_3_1 }, + { 6, D3D12_VIDEO_ENCODER_AV1_LEVELS_3_2 }, + { 7, D3D12_VIDEO_ENCODER_AV1_LEVELS_3_3 }, + { 8, D3D12_VIDEO_ENCODER_AV1_LEVELS_4_0 }, + { 9, D3D12_VIDEO_ENCODER_AV1_LEVELS_4_1 }, + { 10, D3D12_VIDEO_ENCODER_AV1_LEVELS_4_2 }, + { 11, D3D12_VIDEO_ENCODER_AV1_LEVELS_4_3 }, + { 12, D3D12_VIDEO_ENCODER_AV1_LEVELS_5_0 }, + { 13, D3D12_VIDEO_ENCODER_AV1_LEVELS_5_1 }, + { 14, D3D12_VIDEO_ENCODER_AV1_LEVELS_5_2 }, + { 15, D3D12_VIDEO_ENCODER_AV1_LEVELS_5_3 }, + { 16, D3D12_VIDEO_ENCODER_AV1_LEVELS_6_0 }, + { 17, D3D12_VIDEO_ENCODER_AV1_LEVELS_6_1 }, + { 18, D3D12_VIDEO_ENCODER_AV1_LEVELS_6_2 }, + { 19, D3D12_VIDEO_ENCODER_AV1_LEVELS_6_3 }, + { 20, D3D12_VIDEO_ENCODER_AV1_LEVELS_7_0 }, + { 21, D3D12_VIDEO_ENCODER_AV1_LEVELS_7_1 }, + { 22, D3D12_VIDEO_ENCODER_AV1_LEVELS_7_2 }, + { 23, D3D12_VIDEO_ENCODER_AV1_LEVELS_7_3 }, +}; + +static const D3D12_VIDEO_ENCODER_AV1_PROFILE profile_main = D3D12_VIDEO_ENCODER_AV1_PROFILE_MAIN; +static const D3D12_VIDEO_ENCODER_AV1_PROFILE profile_high = D3D12_VIDEO_ENCODER_AV1_PROFILE_HIGH; +static const D3D12_VIDEO_ENCODER_AV1_PROFILE profile_professional = D3D12_VIDEO_ENCODER_AV1_PROFILE_PROFESSIONAL; + +#define D3D_PROFILE_DESC(name) \ + { sizeof(D3D12_VIDEO_ENCODER_AV1_PROFILE), { .pAV1Profile = (D3D12_VIDEO_ENCODER_AV1_PROFILE *)&profile_ ## name } } +static const D3D12VAEncodeProfile d3d12va_encode_av1_profiles[] = { + { AV_PROFILE_AV1_MAIN, 8, 3, 1, 1, D3D_PROFILE_DESC(main) }, + { AV_PROFILE_AV1_MAIN, 10, 3, 1, 1, D3D_PROFILE_DESC(main) }, + { AV_PROFILE_AV1_HIGH, 10, 3, 1, 1, D3D_PROFILE_DESC(high) }, + { AV_PROFILE_AV1_PROFESSIONAL, 8, 3, 1, 1, D3D_PROFILE_DESC(professional) }, + { AV_PROFILE_AV1_PROFESSIONAL, 10, 3, 1, 1, D3D_PROFILE_DESC(professional) }, + { AV_PROFILE_AV1_PROFESSIONAL, 12, 3, 1, 1, D3D_PROFILE_DESC(professional) }, + { AV_PROFILE_UNKNOWN }, +}; + +static int d3d12va_encode_av1_write_obu(AVCodecContext *avctx, + char *data, size_t *data_len, + CodedBitstreamFragment *obu) +{ + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + int err = 0; + + err = ff_cbs_write_fragment_data(priv->cbc, obu); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed OBU data.\n"); + return err; + } + + memcpy(data, obu->data, obu->data_size); + *data_len = (8 * obu->data_size) - obu->data_bit_padding; + + return 0; +} + +static int d3d12va_encode_av1_add_obu(AVCodecContext* avctx, + CodedBitstreamFragment* au, + CodedBitstreamUnitType obu_type, + void* obu_unit) +{ + int err = 0; + + err = ff_cbs_insert_unit_content(au, -1, obu_type, obu_unit, NULL); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to add OBU unit: " + "type = %d.\n", obu_type); + return err; + } + return 0; +} + +static int d3d12va_encode_av1_write_sequence_header(AVCodecContext *avctx, + char *data, size_t *data_len) +{ + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + CodedBitstreamFragment *obu = &priv->current_obu; + int err = 0; + + priv->units.raw_sequence_header.header.obu_type = AV1_OBU_SEQUENCE_HEADER; + err = d3d12va_encode_av1_add_obu(avctx, obu, AV1_OBU_SEQUENCE_HEADER, &priv->units.raw_sequence_header); + if (err < 0) + goto fail; + + err = d3d12va_encode_av1_write_obu(avctx, data, data_len, obu); + +fail: + ff_cbs_fragment_reset(obu); + return err; +} + +static int d3d12va_encode_av1_update_current_frame_picture_header(AVCodecContext *avctx, + D3D12VAEncodePicture *pic, + AV1RawOBU *frameheader_obu) +{ + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + AV1RawFrameHeader *fh = &frameheader_obu->obu.frame_header; + uint8_t *data = NULL; + HRESULT hr = S_OK; + int err = 0; + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES *post_encode_values = NULL; + + // Update the frame header according to the picture post_encode_values + hr = ID3D12Resource_Map(pic->resolved_metadata, 0, NULL, (void **)&data); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + return err; + } + post_encode_values = (D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES*) (data + + sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA) + + sizeof(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA) + + sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES)); + + if (priv->post_encode_values_flag & D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_QUANTIZATION) { + fh->base_q_idx = post_encode_values->Quantization.BaseQIndex; + fh->delta_q_y_dc = post_encode_values->Quantization.YDCDeltaQ; + fh->delta_q_u_dc = post_encode_values->Quantization.UDCDeltaQ; + fh->delta_q_u_ac = post_encode_values->Quantization.UACDeltaQ; + fh->delta_q_v_dc = post_encode_values->Quantization.VDCDeltaQ; + fh->delta_q_v_ac = post_encode_values->Quantization.VACDeltaQ; + fh->using_qmatrix = post_encode_values->Quantization.UsingQMatrix; + fh->qm_y = post_encode_values->Quantization.QMY; + fh->qm_u = post_encode_values->Quantization.QMU; + fh->qm_v = post_encode_values->Quantization.QMV; + } + + if (priv->post_encode_values_flag & D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_LOOP_FILTER) { + fh->loop_filter_level[0] = post_encode_values->LoopFilter.LoopFilterLevel[0]; + fh->loop_filter_level[1] = post_encode_values->LoopFilter.LoopFilterLevel[1]; + fh->loop_filter_level[2] = post_encode_values->LoopFilter.LoopFilterLevelU; + fh->loop_filter_level[3] = post_encode_values->LoopFilter.LoopFilterLevelV; + fh->loop_filter_sharpness = post_encode_values->LoopFilter.LoopFilterSharpnessLevel; + fh->loop_filter_delta_enabled = post_encode_values->LoopFilter.LoopFilterDeltaEnabled; + if (fh->loop_filter_delta_enabled) { + for (int i = 0; i < AV1_TOTAL_REFS_PER_FRAME; i++) { + fh->loop_filter_ref_deltas[i] = post_encode_values->LoopFilter.RefDeltas[i]; + fh->update_ref_delta[i] = post_encode_values->LoopFilter.RefDeltas[i]; + } + for (int i = 0; i < 2; i++) { + fh->loop_filter_mode_deltas[i] = post_encode_values->LoopFilter.ModeDeltas[i]; + fh->update_mode_delta[i] = post_encode_values->LoopFilter.ModeDeltas[i]; + } + } + } + if (priv->post_encode_values_flag & D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_CDEF_DATA) { + fh->cdef_damping_minus_3 = post_encode_values->CDEF.CdefDampingMinus3; + fh->cdef_bits = post_encode_values->CDEF.CdefBits; + for (int i = 0; i < 8; i++) { + fh->cdef_y_pri_strength[i] = post_encode_values->CDEF.CdefYPriStrength[i]; + fh->cdef_y_sec_strength[i] = post_encode_values->CDEF.CdefYSecStrength[i]; + fh->cdef_uv_pri_strength[i] = post_encode_values->CDEF.CdefUVPriStrength[i]; + fh->cdef_uv_sec_strength[i] = post_encode_values->CDEF.CdefUVSecStrength[i]; + } + } + if (priv->post_encode_values_flag & D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_QUANTIZATION_DELTA) { + fh->delta_q_present = post_encode_values->QuantizationDelta.DeltaQPresent; + fh->delta_q_res = post_encode_values->QuantizationDelta.DeltaQRes; + } + + if (priv->post_encode_values_flag & D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_REFERENCE_INDICES) { + for (int i = 0; i < AV1_REFS_PER_FRAME; i++) { + fh->ref_frame_idx[i] = post_encode_values->ReferenceIndices[i]; + } + } + + ID3D12Resource_Unmap(pic->resolved_metadata, 0, NULL); + return 0; +} + +static int d3d12va_encode_av1_write_picture_header(AVCodecContext *avctx, + D3D12VAEncodePicture *pic, + char *data, size_t *data_len) +{ + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + CodedBitstreamFragment *obu = &priv->current_obu; + AV1RawOBU *frameheader_obu = av_mallocz(sizeof(AV1RawOBU)); + int err = 0; + + av_fifo_read(priv->picture_header_list, frameheader_obu, 1); + err = d3d12va_encode_av1_update_current_frame_picture_header(avctx, pic,frameheader_obu); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to update current frame picture header: %d.\n", err); + return err; + } + + // Add the frame header OBU + frameheader_obu->header.obu_has_size_field = 1; + + err = d3d12va_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, frameheader_obu); + if (err < 0) + goto fail; + err = d3d12va_encode_av1_write_obu(avctx, data, data_len, obu); + +fail: + ff_cbs_fragment_reset(obu); + av_freep(&frameheader_obu); + return err; +} + +static int d3d12va_encode_av1_write_tile_group(AVCodecContext *avctx, + uint8_t* tile_group, + uint32_t tile_group_size, + char *data, size_t *data_len) +{ + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + CodedBitstreamFragment *obu = &priv->current_obu; + AV1RawOBU *tile_group_obu = &priv->units.raw_tile_group; + AV1RawTileGroup *tg = &tile_group_obu->obu.tile_group; + int err = 0; + + tg->tile_data.data = tile_group; + tg->tile_data.data_ref = NULL; + tg->tile_data.data_size = tile_group_size; + tile_group_obu->header.obu_has_size_field = 1; + tile_group_obu->header.obu_type = AV1_OBU_TILE_GROUP; + + err = d3d12va_encode_av1_add_obu(avctx, obu, AV1_OBU_TILE_GROUP, tile_group_obu); + if (err < 0) + goto fail; + err = d3d12va_encode_av1_write_obu(avctx, data, data_len, obu); + +fail: + ff_cbs_fragment_reset(obu); + return err; +} + +static int d3d12va_encode_av1_get_buffer_size(AVCodecContext *avctx, + D3D12VAEncodePicture *pic, size_t *size) +{ + D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *subregion_meta = NULL; + uint8_t *data = NULL; + HRESULT hr = S_OK; + int err = 0; + + hr = ID3D12Resource_Map(pic->resolved_metadata, 0, NULL, (void **)&data); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + return err; + } + + subregion_meta = (D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA*)(data + sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA)); + if (subregion_meta->bSize == 0) { + av_log(avctx, AV_LOG_ERROR, "No subregion metadata found\n"); + err = AVERROR(EINVAL); + return err; + } + *size = subregion_meta->bSize; + + ID3D12Resource_Unmap(pic->resolved_metadata, 0, NULL); + + return 0; +} + +static int d3d12va_encode_av1_get_coded_data(AVCodecContext *avctx, + D3D12VAEncodePicture *pic, AVPacket *pkt) +{ + int err = 0; + uint8_t *ptr = NULL; + uint8_t *mapped_data = NULL; + size_t total_size = 0; + HRESULT hr = S_OK; + size_t av1_pic_hd_size = 0; + int tile_group_extra_size = 0; + size_t bit_len = 0; + + char pic_hd_data[MAX_PARAM_BUFFER_SIZE] = { 0 }; + + err = d3d12va_encode_av1_get_buffer_size(avctx, pic, &total_size); + if (err < 0) + goto end; + + // Update the picture header and calculate the picture header size + memset(pic_hd_data, 0, sizeof(pic_hd_data)); + err = d3d12va_encode_av1_write_picture_header(avctx, pic, pic_hd_data, &av1_pic_hd_size); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write picture header: %d.\n", err); + return err; + } + av1_pic_hd_size /= 8; + av_log(avctx, AV_LOG_DEBUG, "AV1 picture header size: %zu bytes.\n", av1_pic_hd_size); + + + tile_group_extra_size = (av_log2(total_size) + 7) / 7 + 1; // 1 byte for obu header, rest for tile group LEB128 size + av_log(avctx, AV_LOG_DEBUG, "Tile group extra size: %d bytes.\n", tile_group_extra_size); + + total_size += (pic->header_size + tile_group_extra_size + av1_pic_hd_size); + av_log(avctx, AV_LOG_DEBUG, "Output buffer size %zu\n", total_size); + + hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&mapped_data); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + goto end; + } + + err = ff_get_encode_buffer(avctx, pkt, total_size, 0); + if (err < 0) + goto end; + ptr = pkt->data; + + memcpy(ptr, mapped_data, pic->header_size); + + ptr += pic->header_size; + mapped_data += pic->aligned_header_size; + total_size -= pic->header_size; + + memcpy(ptr, pic_hd_data, av1_pic_hd_size); + ptr += av1_pic_hd_size; + total_size -= av1_pic_hd_size; + av_log(avctx, AV_LOG_DEBUG, "AV1 total_size after write picture header: %zu.\n", total_size); + + total_size -= tile_group_extra_size; + err = d3d12va_encode_av1_write_tile_group(avctx, mapped_data, total_size, ptr, &bit_len); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write tile group: %d.\n", err); + goto end; + } + assert((total_size + tile_group_extra_size) * 8 == bit_len); + + ID3D12Resource_Unmap(pic->output_buffer, 0, NULL); + +end: + av_buffer_unref(&pic->output_buffer_ref); + pic->output_buffer = NULL; + return err; +} + +static int d3d12va_hw_base_encode_init_params_av1(FFHWBaseEncodeContext *base_ctx, + AVCodecContext *avctx, + D3D12VAHWBaseEncodeAV1 *common, + D3D12VAHWBaseEncodeAV1Opts *opts) +{ + AV1RawOBU *seqheader_obu = &common->raw_sequence_header; + AV1RawSequenceHeader *seq = &seqheader_obu->obu.sequence_header; + const AVPixFmtDescriptor *desc; + + seq->seq_profile = avctx->profile; + if (!seq->seq_force_screen_content_tools) + seq->seq_force_integer_mv = AV1_SELECT_INTEGER_MV; + seq->seq_tier[0] = opts->tier; + + desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format); + seq->color_config = (AV1RawColorConfig){ + .high_bitdepth = desc->comp[0].depth == 8 ? 0 : 1, + .color_primaries = avctx->color_primaries, + .transfer_characteristics = avctx->color_trc, + .matrix_coefficients = avctx->colorspace, + .color_description_present_flag = (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED), + .color_range = avctx->color_range == AVCOL_RANGE_JPEG, + .subsampling_x = desc->log2_chroma_w, + .subsampling_y = desc->log2_chroma_h, + }; + + switch (avctx->chroma_sample_location) { + case AVCHROMA_LOC_LEFT: + seq->color_config.chroma_sample_position = AV1_CSP_VERTICAL; + break; + case AVCHROMA_LOC_TOPLEFT: + seq->color_config.chroma_sample_position = AV1_CSP_COLOCATED; + break; + default: + seq->color_config.chroma_sample_position = AV1_CSP_UNKNOWN; + break; + } + + if (avctx->level != AV_LEVEL_UNKNOWN) { + seq->seq_level_idx[0] = avctx->level; + } + else { + const AV1LevelDescriptor *level; + float framerate; + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) + framerate = avctx->framerate.num / avctx->framerate.den; + else + framerate = 0; + + //currently only supporting 1 tile + level = ff_av1_guess_level(avctx->bit_rate, opts->tier, + base_ctx->surface_width, base_ctx->surface_height, + /*priv->tile_rows*/1 * 1/*priv->tile_cols*/, + /*priv->tile_cols*/1, framerate); + if (level) { + av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); + seq->seq_level_idx[0] = level->level_idx; + } + else { + av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to " + "any normal level, using maximum parameters level by default.\n"); + seq->seq_level_idx[0] = 31; + seq->seq_tier[0] = 1; + } + } + + // Still picture mode + seq->still_picture = (base_ctx->gop_size == 1); + seq->reduced_still_picture_header = seq->still_picture; + + // Feature flags + seq->enable_filter_intra = opts->enable_filter_intra; + seq->enable_intra_edge_filter = opts->enable_intra_edge_filter; + seq->enable_interintra_compound = opts->enable_interintra_compound; + seq->enable_masked_compound = opts->enable_masked_compound; + seq->enable_warped_motion = opts->enable_warped_motion; + seq->enable_dual_filter = opts->enable_dual_filter; + seq->enable_order_hint = !seq->still_picture; + if (seq->enable_order_hint) { + seq->order_hint_bits_minus_1 = 7; + } + seq->enable_jnt_comp = opts->enable_jnt_comp && seq->enable_order_hint; + seq->enable_ref_frame_mvs = opts->enable_ref_frame_mvs && seq->enable_order_hint; + seq->enable_superres = opts->enable_superres; + seq->enable_cdef = opts->enable_cdef; + seq->enable_restoration = opts->enable_restoration; + + return 0; + +} + +static int d3d12va_encode_av1_init_sequence_params(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + AVD3D12VAFramesContext *hwctx = base_ctx->input_frames->hwctx; + AV1RawOBU *seqheader_obu = &priv->units.raw_sequence_header; + AV1RawSequenceHeader *seq = &priv->units.raw_sequence_header.obu.sequence_header; + + D3D12_VIDEO_ENCODER_AV1_PROFILE profile = D3D12_VIDEO_ENCODER_AV1_PROFILE_MAIN; + D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS level = { 0 }; + HRESULT hr; + int err; + + D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 support = { + .NodeIndex = 0, + .Codec = D3D12_VIDEO_ENCODER_CODEC_AV1, + .InputFormat = hwctx->format, + .RateControl = ctx->rc, + .IntraRefresh = ctx->intra_refresh.Mode, + .SubregionFrameEncoding = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME, + .ResolutionsListCount = 1, + .pResolutionList = &ctx->resolution, + .CodecGopSequence = ctx->gop, + .MaxReferenceFramesInDPB = AV1_NUM_REF_FRAMES, + .CodecConfiguration = ctx->codec_conf, + .SuggestedProfile.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_PROFILE), + .SuggestedProfile.pAV1Profile = &profile, + .SuggestedLevel.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS), + .SuggestedLevel.pAV1LevelSetting = &level, + .pResolutionDependentSupport = &ctx->res_limits, + .SubregionFrameEncodingData.pTilesPartition_AV1 = ctx->subregions_layout.pTilesPartition_AV1, + }; + + hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1, + &support, sizeof(support)); + + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to check encoder support(%lx).\n", (long)hr); + return AVERROR(EINVAL); + } + + if (!(support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK)) { + av_log(avctx, AV_LOG_ERROR, "Driver does not support requested features. ValidationFlags: %#x\n", + support.ValidationFlags); + ff_d3d12va_encode_check_encoder_feature_flags(avctx, support.ValidationFlags); + return AVERROR(EINVAL); + } + + if (support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) { + ctx->is_texture_array = 1; + av_log(avctx, AV_LOG_DEBUG, "D3D12 video encode on this device uses texture array mode.\n"); + } + + // Check if the configuration with DELTA_QP is supported + if (support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_DELTA_QP_AVAILABLE) { + base_ctx->roi_allowed = 1; + // Store the QP map region size from resolution limits + ctx->qp_map_region_size = ctx->res_limits.QPMapRegionPixelsSize; + av_log(avctx, AV_LOG_DEBUG, "ROI encoding is supported via delta QP " + "(QP map region size: %d pixels).\n", ctx->qp_map_region_size); + } else { + base_ctx->roi_allowed = 0; + av_log(avctx, AV_LOG_DEBUG, "ROI encoding not supported by hardware for current rate control mode \n"); + } + + // Check motion estimation precision mode support + if (ctx->me_precision != D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM) { + if (!(support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_MOTION_ESTIMATION_PRECISION_MODE_LIMIT_AVAILABLE)) { + av_log(avctx, AV_LOG_ERROR, "Hardware does not support motion estimation " + "precision mode limits.\n"); + return AVERROR(ENOTSUP); + } + av_log(avctx, AV_LOG_VERBOSE, "Hardware supports motion estimation " + "precision mode limits.\n"); + } + + memset(seqheader_obu, 0, sizeof(*seqheader_obu)); + seq->seq_profile = profile; + seq->seq_level_idx[0] = level.Level; + seq->seq_tier[0] = level.Tier; + + seq->max_frame_width_minus_1 = ctx->resolution.Width - 1; + seq->max_frame_height_minus_1 = ctx->resolution.Height - 1; + seq->frame_width_bits_minus_1 = av_log2(ctx->resolution.Width); + seq->frame_height_bits_minus_1 = av_log2(ctx->resolution.Height); + + seqheader_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER; + + err = d3d12va_hw_base_encode_init_params_av1(base_ctx, avctx, + &priv->units, &priv->unit_opts); + if (err < 0) + return err; + + if (avctx->level == AV_LEVEL_UNKNOWN) + avctx->level = level.Level; + + return 0; +} + +static int d3d12va_encode_av1_get_encoder_caps(AVCodecContext *avctx) +{ + HRESULT hr = S_OK; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + + D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION *config; + D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT av1_caps; + + D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT codec_caps = { + .NodeIndex = 0, + .Codec = D3D12_VIDEO_ENCODER_CODEC_AV1, + .Profile = ctx->profile->d3d12_profile, + .CodecSupportLimits.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT), + }; + + codec_caps.CodecSupportLimits.pAV1Support = &av1_caps; + + hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, + &codec_caps, sizeof(codec_caps)); + if (!(SUCCEEDED(hr) && codec_caps.IsSupported)) + return AVERROR(EINVAL); + + ctx->codec_conf.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION); + ctx->codec_conf.pAV1Config = av_mallocz(ctx->codec_conf.DataSize); + if (!ctx->codec_conf.pAV1Config) + return AVERROR(ENOMEM); + + priv->post_encode_values_flag = av1_caps.PostEncodeValuesFlags; + config = ctx->codec_conf.pAV1Config; + + config->FeatureFlags = D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_NONE; + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK) { + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK; + priv->unit_opts.enable_128x128_superblock = 1; + } + + base_ctx->surface_width = FFALIGN(avctx->width, priv->unit_opts.enable_128x128_superblock ? 128 : 64); + base_ctx->surface_height = FFALIGN(avctx->height, priv->unit_opts.enable_128x128_superblock ? 128 : 64); + + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER) { + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER; + priv->unit_opts.enable_loop_filter = 1; + } + + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING) { + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING; + priv->unit_opts.enable_palette = 1; + } + + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY) { + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY; + priv->unit_opts.enable_intra_block_copy = 1; + } + + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS) { + // Loop filter deltas + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS; + priv->unit_opts.enable_loop_filter_delta = 1; + } + + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING) { + // CDEF (Constrained Directional Enhancement Filter) + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING; + priv->unit_opts.enable_cdef = 1; + } + + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER) { + // Dual filter + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER; + priv->unit_opts.enable_dual_filter = 1; + } + + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP) { + // Joint compound prediction + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP; + priv->unit_opts.enable_jnt_comp = 1; + } + + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS) { + // Frame reference motion vectors + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS; + priv->unit_opts.enable_ref_frame_mvs = 1; + } + + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION) { + // Super-resolution + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION; + priv->unit_opts.enable_superres = 1; + } + + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION) { + // Warped motion + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION; + priv->unit_opts.enable_warped_motion = 1; + } + + if (av1_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND) { + // Inter-intra compound prediction + config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND; + priv->unit_opts.enable_interintra_compound = 1; + } + + return 0; +} + +static int d3d12va_encode_av1_configure(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + int err = 0; + int fixed_qp_key, fixed_qp_inter; + + err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_AV1, avctx); + if (err < 0) + return err; + + if (ctx->rc.Mode == D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP) { + D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP *cqp_ctl; + fixed_qp_inter = av_clip_uintp2(ctx->rc_quality, 8); + + if (avctx->i_quant_factor > 0.0) + fixed_qp_key = av_clip_uintp2((avctx->i_quant_factor * fixed_qp_inter + + avctx->i_quant_offset) + 0.5, 8); + else + fixed_qp_key = fixed_qp_inter; + + av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = " + "%d / %d for Key / Inter frames.\n", + fixed_qp_key, fixed_qp_inter); + + ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP); + cqp_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize); + if (!cqp_ctl) + return AVERROR(ENOMEM); + + cqp_ctl->ConstantQP_FullIntracodedFrame = fixed_qp_key; + cqp_ctl->ConstantQP_InterPredictedFrame_PrevRefOnly = fixed_qp_inter; + cqp_ctl->ConstantQP_InterPredictedFrame_BiDirectionalRef = fixed_qp_inter; + + ctx->rc.ConfigParams.pConfiguration_CQP = cqp_ctl; + + priv->q_idx_idr = fixed_qp_key; + priv->q_idx_p = fixed_qp_inter; + + } + + // GOP configuration for AV1 + ctx->gop.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_SEQUENCE_STRUCTURE); + ctx->gop.pAV1SequenceStructure = av_mallocz(ctx->gop.DataSize); + if (!ctx->gop.pAV1SequenceStructure) + return AVERROR(ENOMEM); + + ctx->gop.pAV1SequenceStructure->IntraDistance = base_ctx->gop_size; + ctx->gop.pAV1SequenceStructure->InterFramePeriod = base_ctx->b_per_p + 1; + + return 0; +} + +static int d3d12va_encode_av1_set_level(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + int i = 0; + + ctx->level.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS); + ctx->level.pAV1LevelSetting = av_mallocz(ctx->level.DataSize); + if (!ctx->level.pAV1LevelSetting) + return AVERROR(ENOMEM); + + if (avctx->level != AV_LEVEL_UNKNOWN) { + for (i = 0; i < FF_ARRAY_ELEMS(av1_levels); i++) { + if (avctx->level == av1_levels[i].level) { + ctx->level.pAV1LevelSetting->Level = av1_levels[i].d3d12_level; + break; + } + } + + if (i == FF_ARRAY_ELEMS(av1_levels) ) { + av_log(avctx, AV_LOG_ERROR, "Invalid AV1 level %d.\n", avctx->level); + return AVERROR(EINVAL); + } + } else { + ctx->level.pAV1LevelSetting->Level = D3D12_VIDEO_ENCODER_AV1_LEVELS_5_2; + avctx->level = D3D12_VIDEO_ENCODER_AV1_LEVELS_5_2; + av_log(avctx, AV_LOG_DEBUG, "Using default AV1 level 5.2\n"); + } + + if (priv->tier == 1 || avctx->bit_rate > 30000000) { + ctx->level.pAV1LevelSetting->Tier = D3D12_VIDEO_ENCODER_AV1_TIER_HIGH; + av_log(avctx, AV_LOG_DEBUG, "Using AV1 High tier\n"); + } else { + ctx->level.pAV1LevelSetting->Tier = D3D12_VIDEO_ENCODER_AV1_TIER_MAIN; + av_log(avctx, AV_LOG_DEBUG, "Using AV1 Main tier\n"); + } + + if (priv->tier >= 0) { + ctx->level.pAV1LevelSetting->Tier = priv->tier == 0 ? + D3D12_VIDEO_ENCODER_AV1_TIER_MAIN : + D3D12_VIDEO_ENCODER_AV1_TIER_HIGH; + } + + av_log(avctx, AV_LOG_DEBUG, "AV1 level set to %d, tier: %s\n", + ctx->level.pAV1LevelSetting->Level, + ctx->level.pAV1LevelSetting->Tier == D3D12_VIDEO_ENCODER_AV1_TIER_MAIN ? "Main" : "High"); + + return 0; +} + +static int d3d12va_encode_av1_set_tile(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + + ctx->subregions_layout.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES); + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES *tiles_layout = av_mallocz(ctx->subregions_layout.DataSize); + ctx->subregions_layout.pTilesPartition_AV1 = tiles_layout; + + // Currently only support 1 tile + tiles_layout->RowCount = 1; + tiles_layout->ColCount = 1; + + return 0; +} + +static void d3d12va_encode_av1_free_picture_params(D3D12VAEncodePicture *pic) +{ + if (!pic->pic_ctl.pAV1PicData) + return; + + av_freep(&pic->pic_ctl.pAV1PicData); +} + +static int d3d12va_encode_av1_init_picture_params(AVCodecContext *avctx, + FFHWBaseEncodePicture *pic) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodePicture *d3d12va_pic = pic->priv; + D3D12VAEncodeAV1Picture *hpic = pic->codec_priv; + CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data; + AV1RawOBU *frameheader_obu = &priv->units.raw_frame_header; + AV1RawFrameHeader *fh = &frameheader_obu->obu.frame_header; + + FFHWBaseEncodePicture *ref; + D3D12VAEncodeAV1Picture *href; + int i; + + static const int8_t default_loop_filter_ref_deltas[AV1_TOTAL_REFS_PER_FRAME] = + { 1, 0, 0, 0, -1, 0, -1, -1 }; + + memset(frameheader_obu, 0, sizeof(*frameheader_obu)); + + frameheader_obu->header.obu_type = AV1_OBU_FRAME_HEADER; + + d3d12va_pic->pic_ctl.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_CODEC_DATA); + d3d12va_pic->pic_ctl.pAV1PicData = av_mallocz(d3d12va_pic->pic_ctl.DataSize); + if (!d3d12va_pic->pic_ctl.pAV1PicData) + return AVERROR(ENOMEM); + + // Initialize frame type and reference frame management + switch(pic->type) { + case FF_HW_PICTURE_TYPE_IDR: + fh->frame_type = AV1_FRAME_KEY; + fh->refresh_frame_flags = 0xFF; + fh->base_q_idx = priv->q_idx_idr; + hpic->slot = 0; + hpic->last_idr_frame = pic->display_order; + fh->tx_mode = AV1_TX_MODE_LARGEST; + break; + + case FF_HW_PICTURE_TYPE_P: + fh->frame_type = AV1_FRAME_INTER; + fh->base_q_idx = priv->q_idx_p; + fh->tx_mode = AV1_TX_MODE_SELECT; + + ref = pic->refs[0][pic->nb_refs[0] - 1]; + href = ref->codec_priv; + + /** + * The encoder uses a simple alternating reference frame strategy: + * - For P-frames, it uses the last reconstructed frame as a reference. + * - To simplify the reference model of the encoder, the encoder alternates between + * two reference frame slots (typically slot 0 and slot 1) for storing reconstructed + * images and providing prediction references for the next frame. + */ + if (base_ctx->ref_l0 > 1) { + hpic->slot = !href->slot; + } else { + hpic->slot = 0; + } + hpic->last_idr_frame = href->last_idr_frame; + fh->refresh_frame_flags = 1 << hpic->slot; + + // Set the nearest frame in L0 as all reference frame. + for (i = 0; i < AV1_REFS_PER_FRAME; i++) + fh->ref_frame_idx[i] = href->slot; + + fh->primary_ref_frame = href->slot; + fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame; + + // Set the 2nd nearest frame in L0 as Golden frame. + if (pic->nb_refs[0] > 1) { + ref = pic->refs[0][pic->nb_refs[0] - 2]; + href = ref->codec_priv; + // Reference frame index 3 is the GOLDEN_FRAME + fh->ref_frame_idx[3] = href->slot; + fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame; + } else if (base_ctx->ref_l0 == 1) { + fh->ref_order_hint[!href->slot] = cbctx->ref[!href->slot].order_hint; + } + break; + + case FF_HW_PICTURE_TYPE_B: + av_log(avctx, AV_LOG_ERROR, "D3D12 AV1 video encode on this device requires B-frame support, " + "but it's not implemented.\n"); + return AVERROR_PATCHWELCOME; + default: + av_log(avctx, AV_LOG_ERROR, "Unsupported picture type %d.\n", pic->type); + } + + + cbctx->seen_frame_header = 0; + + fh->show_frame = pic->display_order <= pic->encode_order; + fh->showable_frame = fh->frame_type != AV1_FRAME_KEY; + fh->order_hint = pic->display_order - hpic->last_idr_frame; + fh->frame_width_minus_1 = ctx->resolution.Width - 1; + fh->frame_height_minus_1 = ctx->resolution.Height - 1; + fh->render_width_minus_1 = fh->frame_width_minus_1; + fh->render_height_minus_1 = fh->frame_height_minus_1; + fh->is_filter_switchable = 1; + fh->interpolation_filter = AV1_INTERPOLATION_FILTER_SWITCHABLE; + fh->uniform_tile_spacing_flag = 1; + fh->width_in_sbs_minus_1[0] = (ctx->resolution.Width + 63 >> 6) -1; // 64x64 superblock size + fh->height_in_sbs_minus_1[0] = (ctx->resolution.Height + 63 >> 6) -1; // 64x64 superblock size + + memcpy(fh->loop_filter_ref_deltas, default_loop_filter_ref_deltas, + AV1_TOTAL_REFS_PER_FRAME * sizeof(int8_t)); + + if (fh->frame_type == AV1_FRAME_KEY && fh->show_frame) + fh->error_resilient_mode = 1; + + if (fh->frame_type == AV1_FRAME_KEY || fh->error_resilient_mode) + fh->primary_ref_frame = AV1_PRIMARY_REF_NONE; + + d3d12va_pic->pic_ctl.pAV1PicData->FrameType = fh->frame_type; + d3d12va_pic->pic_ctl.pAV1PicData->TxMode = fh->tx_mode; + d3d12va_pic->pic_ctl.pAV1PicData->RefreshFrameFlags = fh->refresh_frame_flags; + d3d12va_pic->pic_ctl.pAV1PicData->TemporalLayerIndexPlus1 = hpic->temporal_id + 1; + d3d12va_pic->pic_ctl.pAV1PicData->SpatialLayerIndexPlus1 = hpic->spatial_id + 1; + d3d12va_pic->pic_ctl.pAV1PicData->PictureIndex = pic->display_order; + d3d12va_pic->pic_ctl.pAV1PicData->InterpolationFilter = D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_SWITCHABLE; + d3d12va_pic->pic_ctl.pAV1PicData->PrimaryRefFrame = fh->primary_ref_frame; + if (fh->error_resilient_mode) + d3d12va_pic->pic_ctl.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_ERROR_RESILIENT_MODE; + + if (pic->type == FF_HW_PICTURE_TYPE_IDR) + { + for (int i = 0; i < AV1_NUM_REF_FRAMES; i++) { + d3d12va_pic->pic_ctl.pAV1PicData->ReferenceFramesReconPictureDescriptors[i].ReconstructedPictureResourceIndex = + D3D12_VIDEO_ENCODER_AV1_INVALID_DPB_RESOURCE_INDEX; + } + } else if (pic->type == FF_HW_PICTURE_TYPE_P) { + for (i = 0; i < pic->nb_refs[0]; i++) { + FFHWBaseEncodePicture *ref_pic = pic->refs[0][i]; + d3d12va_pic->pic_ctl.pAV1PicData->ReferenceFramesReconPictureDescriptors[i].ReconstructedPictureResourceIndex = + ((D3D12VAEncodeAV1Picture*)ref_pic->codec_priv)->slot; + } + } + // Set reference frame management + memset(d3d12va_pic->pic_ctl.pAV1PicData->ReferenceIndices, 0, sizeof(UINT) * AV1_REFS_PER_FRAME); + if (pic->type == FF_HW_PICTURE_TYPE_P) { + for (i = 0; i < AV1_REFS_PER_FRAME; i++) + d3d12va_pic->pic_ctl.pAV1PicData->ReferenceIndices[i] = fh->ref_frame_idx[i]; + } + + // Process ROI side data if present and supported + if (base_ctx->roi_allowed && d3d12va_pic->qp_map && d3d12va_pic->qp_map_size > 0) { + d3d12va_pic->pic_ctl.pAV1PicData->QPMapValuesCount = d3d12va_pic->qp_map_size; + d3d12va_pic->pic_ctl.pAV1PicData->pRateControlQPMap = (INT16 *)d3d12va_pic->qp_map; + } + + return av_fifo_write(priv->picture_header_list, &priv->units.raw_frame_header, 1); +} + + +static const D3D12VAEncodeType d3d12va_encode_type_av1 = { + .profiles = d3d12va_encode_av1_profiles, + + .d3d12_codec = D3D12_VIDEO_ENCODER_CODEC_AV1, + + .flags = FF_HW_FLAG_B_PICTURES | + FF_HW_FLAG_B_PICTURE_REFERENCES | + FF_HW_FLAG_NON_IDR_KEY_PICTURES, + + .default_quality = 25, + + .get_encoder_caps = &d3d12va_encode_av1_get_encoder_caps, + + .configure = &d3d12va_encode_av1_configure, + + .set_level = &d3d12va_encode_av1_set_level, + + .set_tile = &d3d12va_encode_av1_set_tile, + + .picture_priv_data_size = sizeof(D3D12VAEncodeAV1Picture), + + .init_sequence_params = &d3d12va_encode_av1_init_sequence_params, + + .init_picture_params = &d3d12va_encode_av1_init_picture_params, + + .free_picture_params = &d3d12va_encode_av1_free_picture_params, + + .write_sequence_header = &d3d12va_encode_av1_write_sequence_header, + +#ifdef CONFIG_AV1_D3D12VA_ENCODER + .get_coded_data = &d3d12va_encode_av1_get_coded_data, +#endif +}; + +static int d3d12va_encode_av1_init(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + + ctx->codec = &d3d12va_encode_type_av1; + + if (avctx->profile == AV_PROFILE_UNKNOWN) + avctx->profile = priv->profile; + if (avctx->level == AV_LEVEL_UNKNOWN) + avctx->level = priv->level; + + if (avctx->level != AV_LEVEL_UNKNOWN && avctx->level & ~0xff) { + av_log(avctx, AV_LOG_ERROR, "Invalid level %d: must fit " + "in 8-bit unsigned integer.\n", avctx->level); + return AVERROR(EINVAL); + } + + if (priv->qp > 0) + ctx->explicit_qp = priv->qp; + + priv->picture_header_list = av_fifo_alloc2(2, sizeof(AV1RawOBU), AV_FIFO_FLAG_AUTO_GROW); + + return ff_d3d12va_encode_init(avctx); +} + +static int d3d12va_encode_av1_close(AVCodecContext *avctx) +{ + D3D12VAEncodeAV1Context *priv = avctx->priv_data; + + ff_cbs_fragment_free(&priv->current_obu); + ff_cbs_close(&priv->cbc); + + av_freep(&priv->common.codec_conf.pAV1Config); + av_freep(&priv->common.gop.pAV1SequenceStructure); + av_freep(&priv->common.level.pAV1LevelSetting); + av_freep(&priv->common.subregions_layout.pTilesPartition_AV1); + + av_fifo_freep2(&priv->picture_header_list); + + return ff_d3d12va_encode_close(avctx); +} + +#define OFFSET(x) offsetof(D3D12VAEncodeAV1Context, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +static const AVOption d3d12va_encode_av1_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, + D3D12VA_ENCODE_COMMON_OPTIONS, + D3D12VA_ENCODE_RC_OPTIONS, + + { "qp", "Constant QP (for P-frames; scaled by qfactor/qoffset for I/B)", + OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 52, FLAGS }, + + { "profile", "Set profile (general_profile_idc)", + OFFSET(profile), AV_OPT_TYPE_INT, + { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, 0xff, FLAGS, "profile" }, + +#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "profile" + { PROFILE("main", AV_PROFILE_AV1_MAIN) }, + { PROFILE("high", AV_PROFILE_AV1_HIGH) }, + { PROFILE("professional", AV_PROFILE_AV1_PROFESSIONAL) }, +#undef PROFILE + + { "tier", "Set tier (general_tier_flag)", + OFFSET(unit_opts.tier), AV_OPT_TYPE_INT, + { .i64 = 0 }, 0, 1, FLAGS, "tier" }, + { "main", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = 0 }, 0, 0, FLAGS, "tier" }, + { "high", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = 1 }, 0, 0, FLAGS, "tier" }, + + { "level", "Set level (general_level_idc)", + OFFSET(level), AV_OPT_TYPE_INT, + { .i64 = AV_LEVEL_UNKNOWN }, AV_LEVEL_UNKNOWN, 0xff, FLAGS, "level" }, + +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "level" + { LEVEL("2.0", 0) }, + { LEVEL("2.1", 1) }, + { LEVEL("2.2", 2) }, + { LEVEL("2.3", 3) }, + { LEVEL("3.0", 4) }, + { LEVEL("3.1", 5) }, + { LEVEL("3.2", 6) }, + { LEVEL("3.3", 7) }, + { LEVEL("4.0", 8) }, + { LEVEL("4.1", 9) }, + { LEVEL("4.2", 10) }, + { LEVEL("4.3", 11) }, + { LEVEL("5.0", 12) }, + { LEVEL("5.1", 13) }, + { LEVEL("5.2", 14) }, + { LEVEL("5.3", 15) }, + { LEVEL("6.0", 16) }, + { LEVEL("6.1", 17) }, + { LEVEL("6.2", 18) }, + { LEVEL("6.3", 19) }, + { LEVEL("7.0", 20) }, + { LEVEL("7.1", 21) }, + { LEVEL("7.2", 22) }, + { LEVEL("7.3", 23) }, +#undef LEVEL + { NULL }, +}; + +static const FFCodecDefault d3d12va_encode_av1_defaults[] = { + { "b", "0" }, + { "bf", "0" }, + { "g", "120" }, + { "i_qfactor", "1" }, + { "i_qoffset", "0" }, + { "b_qfactor", "1" }, + { "b_qoffset", "0" }, + { "qmin", "-1" }, + { "qmax", "-1" }, + { "refs", "0" }, + { NULL }, +}; + +static const AVClass d3d12va_encode_av1_class = { + .class_name = "av1_d3d12va", + .item_name = av_default_item_name, + .option = d3d12va_encode_av1_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_av1_d3d12va_encoder = { + .p.name = "av1_d3d12va", + CODEC_LONG_NAME("D3D12VA av1 encoder"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_AV1, + .priv_data_size = sizeof(D3D12VAEncodeAV1Context), + .init = &d3d12va_encode_av1_init, + FF_CODEC_RECEIVE_PACKET_CB(&ff_d3d12va_encode_receive_packet), + .close = &d3d12va_encode_av1_close, + .p.priv_class = &d3d12va_encode_av1_class, + .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | + AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, + .defaults = d3d12va_encode_av1_defaults, + CODEC_PIXFMTS(AV_PIX_FMT_D3D12), + .hw_configs = ff_d3d12va_encode_hw_configs, + .p.wrapper_name = "d3d12va", +}; diff --git a/libavcodec/d3d12va_encode_h264.c b/libavcodec/d3d12va_encode_h264.c new file mode 100644 index 000000000..47c6953d1 --- /dev/null +++ b/libavcodec/d3d12va_encode_h264.c @@ -0,0 +1,693 @@ +/* + * Direct3D 12 HW acceleration video encoder + * + * 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/opt.h" +#include "libavutil/common.h" +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" +#include "libavutil/hwcontext_d3d12va_internal.h" + +#include "avcodec.h" +#include "cbs.h" +#include "cbs_h264.h" +#include "hw_base_encode_h264.h" +#include "h2645data.h" +#include "h264_levels.h" +#include "codec_internal.h" +#include "d3d12va_encode.h" + +typedef struct D3D12VAEncodeH264Picture { + int pic_order_cnt; + int64_t last_idr_frame; +} D3D12VAEncodeH264Picture; + +typedef struct D3D12VAEncodeH264Context { + D3D12VAEncodeContext common; + + // User options. + int qp; + int profile; + int level; + int deblock; + int idr_pic_id; + + // Writer structures. + FFHWBaseEncodeH264 units; + FFHWBaseEncodeH264Opts unit_opts; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_access_unit; +} D3D12VAEncodeH264Context; + +typedef struct D3D12VAEncodeH264Level { + int level; + D3D12_VIDEO_ENCODER_LEVELS_H264 d3d12_level; +} D3D12VAEncodeH264Level; + +static const D3D12VAEncodeH264Level h264_levels[] = { + { 10, D3D12_VIDEO_ENCODER_LEVELS_H264_1 }, + { 11, D3D12_VIDEO_ENCODER_LEVELS_H264_11 }, + { 12, D3D12_VIDEO_ENCODER_LEVELS_H264_12 }, + { 13, D3D12_VIDEO_ENCODER_LEVELS_H264_13 }, + { 20, D3D12_VIDEO_ENCODER_LEVELS_H264_2 }, + { 21, D3D12_VIDEO_ENCODER_LEVELS_H264_21 }, + { 22, D3D12_VIDEO_ENCODER_LEVELS_H264_22 }, + { 30, D3D12_VIDEO_ENCODER_LEVELS_H264_3 }, + { 31, D3D12_VIDEO_ENCODER_LEVELS_H264_31 }, + { 32, D3D12_VIDEO_ENCODER_LEVELS_H264_32 }, + { 40, D3D12_VIDEO_ENCODER_LEVELS_H264_4 }, + { 41, D3D12_VIDEO_ENCODER_LEVELS_H264_41 }, + { 42, D3D12_VIDEO_ENCODER_LEVELS_H264_42 }, + { 50, D3D12_VIDEO_ENCODER_LEVELS_H264_5 }, + { 51, D3D12_VIDEO_ENCODER_LEVELS_H264_51 }, + { 52, D3D12_VIDEO_ENCODER_LEVELS_H264_52 }, + { 60, D3D12_VIDEO_ENCODER_LEVELS_H264_6 }, + { 61, D3D12_VIDEO_ENCODER_LEVELS_H264_61 }, + { 62, D3D12_VIDEO_ENCODER_LEVELS_H264_62 }, +}; + +static const D3D12_VIDEO_ENCODER_PROFILE_H264 profile_main = D3D12_VIDEO_ENCODER_PROFILE_H264_MAIN; +static const D3D12_VIDEO_ENCODER_PROFILE_H264 profile_high = D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH; +static const D3D12_VIDEO_ENCODER_PROFILE_H264 profile_high_10 = D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH_10; + +#define D3D_PROFILE_DESC(name) \ + { sizeof(D3D12_VIDEO_ENCODER_PROFILE_H264), { .pH264Profile = (D3D12_VIDEO_ENCODER_PROFILE_H264 *)&profile_ ## name } } +static const D3D12VAEncodeProfile d3d12va_encode_h264_profiles[] = { + { AV_PROFILE_H264_MAIN, 8, 3, 1, 1, D3D_PROFILE_DESC(main) }, + { AV_PROFILE_H264_HIGH, 8, 3, 1, 1, D3D_PROFILE_DESC(high) }, + { AV_PROFILE_H264_HIGH_10, 10, 3, 1, 1, D3D_PROFILE_DESC(high_10) }, + { AV_PROFILE_UNKNOWN }, +}; + +static int d3d12va_encode_h264_write_access_unit(AVCodecContext *avctx, + char *data, size_t *data_len, + CodedBitstreamFragment *au) +{ + D3D12VAEncodeH264Context *priv = avctx->priv_data; + int err; + + err = ff_cbs_write_fragment_data(priv->cbc, au); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return err; + } + + if (*data_len < 8 * au->data_size - au->data_bit_padding) { + av_log(avctx, AV_LOG_ERROR, "Access unit too large: " + "%zu < %zu.\n", *data_len, + 8 * au->data_size - au->data_bit_padding); + return AVERROR(ENOSPC); + } + + memcpy(data, au->data, au->data_size); + *data_len = 8 * au->data_size - au->data_bit_padding; + + return 0; +} + +static int d3d12va_encode_h264_add_nal(AVCodecContext *avctx, + CodedBitstreamFragment *au, + void *nal_unit) +{ + H264RawNALUnitHeader *header = nal_unit; + int err; + + err = ff_cbs_insert_unit_content(au, -1, + header->nal_unit_type, nal_unit, NULL); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to add NAL unit: " + "type = %d.\n", header->nal_unit_type); + return err; + } + + return 0; +} + +static int d3d12va_encode_h264_write_sequence_header(AVCodecContext *avctx, + char *data, size_t *data_len) +{ + D3D12VAEncodeH264Context *priv = avctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err; + + err = d3d12va_encode_h264_add_nal(avctx, au, &priv->units.raw_sps); + if (err < 0) + goto fail; + + err = d3d12va_encode_h264_add_nal(avctx, au, &priv->units.raw_pps); + if (err < 0) + goto fail; + + err = d3d12va_encode_h264_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_reset(au); + return err; +} + +static int d3d12va_encode_h264_init_sequence_params(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeH264Context *priv = avctx->priv_data; + AVD3D12VAFramesContext *hwctx = base_ctx->input_frames->hwctx; + H264RawSPS *sps = &priv->units.raw_sps; + H264RawPPS *pps = &priv->units.raw_pps; + D3D12_VIDEO_ENCODER_PROFILE_H264 profile = D3D12_VIDEO_ENCODER_PROFILE_H264_MAIN; + D3D12_VIDEO_ENCODER_LEVELS_H264 level = { 0 }; + const AVPixFmtDescriptor *desc; + HRESULT hr; + int err; + + D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT support = { + .NodeIndex = 0, + .Codec = D3D12_VIDEO_ENCODER_CODEC_H264, + .InputFormat = hwctx->format, + .RateControl = ctx->rc, + .IntraRefresh = ctx->intra_refresh.Mode, + .SubregionFrameEncoding = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME, + .ResolutionsListCount = 1, + .pResolutionList = &ctx->resolution, + .CodecGopSequence = ctx->gop, + .MaxReferenceFramesInDPB = MAX_DPB_SIZE - 1, + .CodecConfiguration = ctx->codec_conf, + .SuggestedProfile.DataSize = sizeof(D3D12_VIDEO_ENCODER_PROFILE_H264), + .SuggestedProfile.pH264Profile = &profile, + .SuggestedLevel.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVELS_H264), + .SuggestedLevel.pH264LevelSetting = &level, + .pResolutionDependentSupport = &ctx->res_limits, + }; + + hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT, + &support, sizeof(support)); + + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to check encoder support(%lx).\n", (long)hr); + return AVERROR(EINVAL); + } + + if (!(support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK)) { + av_log(avctx, AV_LOG_ERROR, "Driver does not support requested features. ValidationFlags: %#x\n", + support.ValidationFlags); + ff_d3d12va_encode_check_encoder_feature_flags(avctx, support.ValidationFlags); + return AVERROR(EINVAL); + } + + if (support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) { + ctx->is_texture_array = 1; + av_log(avctx, AV_LOG_DEBUG, "D3D12 video encode on this device uses texture array mode.\n"); + } + + // Check if the configuration with DELTA_QP is supported + if (support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_DELTA_QP_AVAILABLE) { + base_ctx->roi_allowed = 1; + // Store the QP map region size from resolution limits + ctx->qp_map_region_size = ctx->res_limits.QPMapRegionPixelsSize; + av_log(avctx, AV_LOG_DEBUG, "ROI encoding is supported via delta QP " + "(QP map region size: %d pixels).\n", ctx->qp_map_region_size); + } else { + base_ctx->roi_allowed = 0; + av_log(avctx, AV_LOG_DEBUG, "ROI encoding not supported by hardware for current rate control mode \n"); + } + + // Check motion estimation precision mode support + if (ctx->me_precision != D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM) { + if (!(support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_MOTION_ESTIMATION_PRECISION_MODE_LIMIT_AVAILABLE)) { + av_log(avctx, AV_LOG_ERROR, "Hardware does not support motion estimation " + "precision mode limits.\n"); + return AVERROR(ENOTSUP); + } + av_log(avctx, AV_LOG_VERBOSE, "Hardware supports motion estimation " + "precision mode limits.\n"); + } + + desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format); + av_assert0(desc); + + sps->pic_width_in_mbs_minus1 = ((base_ctx->surface_width + 0x0F) >> 4) - 1; + sps->pic_height_in_map_units_minus1 = ((base_ctx->surface_height + 0x0F) >> 4) - 1; + + priv->unit_opts.mb_width = sps->pic_width_in_mbs_minus1 + 1; + priv->unit_opts.mb_height = sps->pic_height_in_map_units_minus1 +1; + + err = ff_hw_base_encode_init_params_h264(base_ctx, avctx, + &priv->units, &priv->unit_opts); + if (err < 0) + return err; + + avctx->level = priv->units.raw_sps.level_idc; + + ctx->gop.pH264GroupOfPictures->pic_order_cnt_type = sps->pic_order_cnt_type; + + // override the default value according to the gop size + sps->log2_max_frame_num_minus4 = FFMAX(av_ceil_log2(base_ctx->gop_size) - 4, 0); + ctx->gop.pH264GroupOfPictures->log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4; + pps->deblocking_filter_control_present_flag = 1; + + return 0; +} + +static int d3d12va_encode_h264_get_encoder_caps(AVCodecContext *avctx) +{ + HRESULT hr; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeH264Context *priv = avctx->priv_data; + + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 *config; + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264 h264_caps; + + D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT codec_caps = { + .NodeIndex = 0, + .Codec = D3D12_VIDEO_ENCODER_CODEC_H264, + .Profile = ctx->profile->d3d12_profile, + .CodecSupportLimits.DataSize = sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264), + }; + + codec_caps.CodecSupportLimits.pH264Support = &h264_caps; + hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, + &codec_caps, sizeof(codec_caps)); + if (!(SUCCEEDED(hr) && codec_caps.IsSupported)) + return AVERROR(EINVAL); + + ctx->codec_conf.DataSize = sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264); + ctx->codec_conf.pH264Config = av_mallocz(ctx->codec_conf.DataSize); + if (!ctx->codec_conf.pH264Config) + return AVERROR(ENOMEM); + + config = ctx->codec_conf.pH264Config; + + config->ConfigurationFlags = D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_NONE; + + // Deblocking filter configuration + if (priv->deblock) { + if (h264_caps.DisableDeblockingFilterSupportedModes & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODE_FLAG_0_ALL_LUMA_CHROMA_SLICE_BLOCK_EDGES_ALWAYS_FILTERED) { + config->DisableDeblockingFilterConfig = D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODE_0_ALL_LUMA_CHROMA_SLICE_BLOCK_EDGES_ALWAYS_FILTERED; + } else { + av_log(avctx, AV_LOG_ERROR, "Requested deblocking filter enable mode not supported by driver.\n"); + return AVERROR(ENOTSUP); + } + } else { + if (h264_caps.DisableDeblockingFilterSupportedModes & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODE_FLAG_1_DISABLE_ALL_SLICE_BLOCK_EDGES) { + config->DisableDeblockingFilterConfig = D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODE_1_DISABLE_ALL_SLICE_BLOCK_EDGES; + } else { + av_log(avctx, AV_LOG_ERROR, "Requested deblocking filter disable mode not supported by driver.\n"); + return AVERROR(ENOTSUP); + } + } + + // Entropy coder configuration + if (priv->unit_opts.cabac) { + if (h264_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264_FLAG_CABAC_ENCODING_SUPPORT) { + config->ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING; + } else { + av_log(avctx, AV_LOG_WARNING, "CABAC entropy coding is not supported by the driver, falling back to CAVLC.\n"); + priv->unit_opts.cabac = 0; + } + } + + base_ctx->surface_width = FFALIGN(avctx->width, 16); + base_ctx->surface_height = FFALIGN(avctx->height, 16); + + return 0; +} + +static int d3d12va_encode_h264_configure(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeH264Context *priv = avctx->priv_data; + int fixed_qp_idr, fixed_qp_p, fixed_qp_b; + int err; + + err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_H264, avctx); + if (err < 0) + return err; + + // Rate control + if (ctx->rc.Mode == D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP) { + D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP *cqp_ctl; + fixed_qp_p = av_clip(ctx->rc_quality, 1, 51); + if (avctx->i_quant_factor > 0.0) + fixed_qp_idr = av_clip((avctx->i_quant_factor * fixed_qp_p + + avctx->i_quant_offset) + 0.5, 1, 51); + else + fixed_qp_idr = fixed_qp_p; + if (avctx->b_quant_factor > 0.0) + fixed_qp_b = av_clip((avctx->b_quant_factor * fixed_qp_p + + avctx->b_quant_offset) + 0.5, 1, 51); + else + fixed_qp_b = fixed_qp_p; + + av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = " + "%d / %d / %d for IDR- / P- / B-frames.\n", + fixed_qp_idr, fixed_qp_p, fixed_qp_b); + + ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP); + cqp_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize); + if (!cqp_ctl) + return AVERROR(ENOMEM); + + cqp_ctl->ConstantQP_FullIntracodedFrame = fixed_qp_idr; + cqp_ctl->ConstantQP_InterPredictedFrame_PrevRefOnly = fixed_qp_p; + cqp_ctl->ConstantQP_InterPredictedFrame_BiDirectionalRef = fixed_qp_b; + + ctx->rc.ConfigParams.pConfiguration_CQP = cqp_ctl; + } + priv->unit_opts.fixed_qp_idr = 26; + + // GOP + ctx->gop.DataSize = sizeof(D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264); + ctx->gop.pH264GroupOfPictures = av_mallocz(ctx->gop.DataSize); + if (!ctx->gop.pH264GroupOfPictures) + return AVERROR(ENOMEM); + + ctx->gop.pH264GroupOfPictures->GOPLength = base_ctx->gop_size; + ctx->gop.pH264GroupOfPictures->PPicturePeriod = base_ctx->b_per_p + 1; + ctx->gop.pH264GroupOfPictures->log2_max_frame_num_minus4 = FFMAX(av_ceil_log2(base_ctx->gop_size) - 4, 0); + + return 0; +} + +static int d3d12va_encode_h264_set_level(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + int i; + + ctx->level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVELS_H264); + ctx->level.pH264LevelSetting = av_mallocz(ctx->level.DataSize); + if (!ctx->level.pH264LevelSetting) + return AVERROR(ENOMEM); + + for (i = 0; i < FF_ARRAY_ELEMS(h264_levels); i++) { + if (avctx->level == h264_levels[i].level) { + *ctx->level.pH264LevelSetting = h264_levels[i].d3d12_level; + break; + } + } + + if (i == FF_ARRAY_ELEMS(h264_levels)) { + av_log(avctx, AV_LOG_ERROR, "Invalid level %d.\n", avctx->level); + return AVERROR(EINVAL); + } + + return 0; +} + +static void d3d12va_encode_h264_free_picture_params(D3D12VAEncodePicture *pic) +{ + if (!pic->pic_ctl.pH264PicData) + return; + + av_freep(&pic->pic_ctl.pH264PicData->pList0ReferenceFrames); + av_freep(&pic->pic_ctl.pH264PicData->pList1ReferenceFrames); + av_freep(&pic->pic_ctl.pH264PicData->pReferenceFramesReconPictureDescriptors); + av_freep(&pic->pic_ctl.pH264PicData); +} + +static int d3d12va_encode_h264_init_picture_params(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeH264Context *ctx = avctx->priv_data; + D3D12VAEncodePicture *pic = base_pic->priv; + D3D12VAEncodeH264Picture *hpic = base_pic->codec_priv; + FFHWBaseEncodePicture *prev = base_pic->prev; + D3D12VAEncodeH264Picture *hprev = prev ? prev->codec_priv : NULL; + D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264 *pd = NULL; + UINT *ref_list0 = NULL, *ref_list1 = NULL; + int i, idx = 0; + + pic->pic_ctl.DataSize = sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264); + pic->pic_ctl.pH264PicData = av_mallocz(pic->pic_ctl.DataSize); + if (!pic->pic_ctl.pH264PicData) + return AVERROR(ENOMEM); + + if (base_pic->type == FF_HW_PICTURE_TYPE_IDR) { + av_assert0(base_pic->display_order == base_pic->encode_order); + hpic->last_idr_frame = base_pic->display_order; + ctx->idr_pic_id++; + } else { + av_assert0(prev); + hpic->last_idr_frame = hprev->last_idr_frame; + } + hpic->pic_order_cnt = base_pic->display_order - hpic->last_idr_frame; + + switch(base_pic->type) { + case FF_HW_PICTURE_TYPE_IDR: + pic->pic_ctl.pH264PicData->FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME; + pic->pic_ctl.pH264PicData->idr_pic_id = ctx->idr_pic_id; + break; + case FF_HW_PICTURE_TYPE_I: + pic->pic_ctl.pH264PicData->FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME; + break; + case FF_HW_PICTURE_TYPE_P: + pic->pic_ctl.pH264PicData->FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME; + break; + case FF_HW_PICTURE_TYPE_B: + pic->pic_ctl.pH264PicData->FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME; + break; + default: + av_assert0(0 && "invalid picture type"); + } + + pic->pic_ctl.pH264PicData->PictureOrderCountNumber = hpic->pic_order_cnt; + pic->pic_ctl.pH264PicData->FrameDecodingOrderNumber = hpic->pic_order_cnt; + + if (base_pic->type == FF_HW_PICTURE_TYPE_P || base_pic->type == FF_HW_PICTURE_TYPE_B) { + pd = av_calloc(MAX_PICTURE_REFERENCES, sizeof(*pd)); + if (!pd) + return AVERROR(ENOMEM); + + ref_list0 = av_calloc(MAX_PICTURE_REFERENCES, sizeof(*ref_list0)); + if (!ref_list0) + return AVERROR(ENOMEM); + + pic->pic_ctl.pH264PicData->List0ReferenceFramesCount = base_pic->nb_refs[0]; + for (i = 0; i < base_pic->nb_refs[0]; i++) { + FFHWBaseEncodePicture *ref = base_pic->refs[0][i]; + D3D12VAEncodeH264Picture *href; + + av_assert0(ref && ref->encode_order < base_pic->encode_order); + href = ref->codec_priv; + + ref_list0[i] = idx; + pd[idx].ReconstructedPictureResourceIndex = idx; + pd[idx].PictureOrderCountNumber = href->pic_order_cnt; + idx++; + } + } + + if (base_pic->type == FF_HW_PICTURE_TYPE_B) { + ref_list1 = av_calloc(MAX_PICTURE_REFERENCES, sizeof(*ref_list1)); + if (!ref_list1) + return AVERROR(ENOMEM); + + pic->pic_ctl.pH264PicData->List1ReferenceFramesCount = base_pic->nb_refs[1]; + for (i = 0; i < base_pic->nb_refs[1]; i++) { + FFHWBaseEncodePicture *ref = base_pic->refs[1][i]; + D3D12VAEncodeH264Picture *href; + + av_assert0(ref && ref->encode_order < base_pic->encode_order); + href = ref->codec_priv; + + ref_list1[i] = idx; + pd[idx].ReconstructedPictureResourceIndex = idx; + pd[idx].PictureOrderCountNumber = href->pic_order_cnt; + idx++; + } + } + + pic->pic_ctl.pH264PicData->pList0ReferenceFrames = ref_list0; + pic->pic_ctl.pH264PicData->pList1ReferenceFrames = ref_list1; + pic->pic_ctl.pH264PicData->ReferenceFramesReconPictureDescriptorsCount = idx; + pic->pic_ctl.pH264PicData->pReferenceFramesReconPictureDescriptors = pd; + + // Process ROI side data if present and supported + if (base_ctx->roi_allowed && pic->qp_map && pic->qp_map_size > 0) { + pic->pic_ctl.pH264PicData->QPMapValuesCount = pic->qp_map_size; + pic->pic_ctl.pH264PicData->pRateControlQPMap = (INT8 *)pic->qp_map; + } + + return 0; +} + +static const D3D12VAEncodeType d3d12va_encode_type_h264 = { + .profiles = d3d12va_encode_h264_profiles, + + .d3d12_codec = D3D12_VIDEO_ENCODER_CODEC_H264, + + .flags = FF_HW_FLAG_B_PICTURES | + FF_HW_FLAG_B_PICTURE_REFERENCES | + FF_HW_FLAG_NON_IDR_KEY_PICTURES, + + .default_quality = 25, + + .get_encoder_caps = &d3d12va_encode_h264_get_encoder_caps, + + .configure = &d3d12va_encode_h264_configure, + + .set_level = &d3d12va_encode_h264_set_level, + + .picture_priv_data_size = sizeof(D3D12VAEncodeH264Picture), + + .init_sequence_params = &d3d12va_encode_h264_init_sequence_params, + + .init_picture_params = &d3d12va_encode_h264_init_picture_params, + + .free_picture_params = &d3d12va_encode_h264_free_picture_params, + + .write_sequence_header = &d3d12va_encode_h264_write_sequence_header, +}; + +static int d3d12va_encode_h264_init(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeH264Context *priv = avctx->priv_data; + + ctx->codec = &d3d12va_encode_type_h264; + + if (avctx->profile == AV_PROFILE_UNKNOWN) + avctx->profile = priv->profile; + if (avctx->level == AV_LEVEL_UNKNOWN) + avctx->level = priv->level; + + if (avctx->level != AV_LEVEL_UNKNOWN && avctx->level & ~0xff) { + av_log(avctx, AV_LOG_ERROR, "Invalid level %d: must fit " + "in 8-bit unsigned integer.\n", avctx->level); + return AVERROR(EINVAL); + } + + if (priv->qp > 0) + ctx->explicit_qp = priv->qp; + + return ff_d3d12va_encode_init(avctx); +} + +static int d3d12va_encode_h264_close(AVCodecContext *avctx) +{ + D3D12VAEncodeH264Context *priv = avctx->priv_data; + + ff_cbs_fragment_free(&priv->current_access_unit); + ff_cbs_close(&priv->cbc); + + av_freep(&priv->common.codec_conf.pH264Config); + av_freep(&priv->common.gop.pH264GroupOfPictures); + av_freep(&priv->common.level.pH264LevelSetting); + + if (priv->common.rc.ConfigParams.pConfiguration_CQP != NULL) { + av_freep(&priv->common.rc.ConfigParams.pConfiguration_CQP); + } + + return ff_d3d12va_encode_close(avctx); +} + +#define OFFSET(x) offsetof(D3D12VAEncodeH264Context, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +static const AVOption d3d12va_encode_h264_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, + D3D12VA_ENCODE_COMMON_OPTIONS, + D3D12VA_ENCODE_RC_OPTIONS, + + { "qp", "Constant QP (for P-frames; scaled by qfactor/qoffset for I/B)", + OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 52, FLAGS }, + + { "profile", "Set profile (general_profile_idc)", + OFFSET(profile), AV_OPT_TYPE_INT, + { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, 0xff, FLAGS, "profile" }, + +#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "profile" + { PROFILE("main", AV_PROFILE_H264_MAIN) }, + { PROFILE("high", AV_PROFILE_H264_HIGH) }, + { PROFILE("high10", AV_PROFILE_H264_HIGH_10) }, +#undef PROFILE + + { "level", "Set level (general_level_idc)", + OFFSET(level), AV_OPT_TYPE_INT, + { .i64 = AV_LEVEL_UNKNOWN }, AV_LEVEL_UNKNOWN, 0xff, FLAGS, "level" }, + +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "level" + { LEVEL("1", 10) }, + { LEVEL("1.1", 11) }, + { LEVEL("1.2", 12) }, + { LEVEL("1.3", 13) }, + { LEVEL("2", 20) }, + { LEVEL("2.1", 21) }, + { LEVEL("2.2", 22) }, + { LEVEL("3", 30) }, + { LEVEL("3.1", 31) }, + { LEVEL("3.2", 32) }, + { LEVEL("4", 40) }, + { LEVEL("4.1", 41) }, + { LEVEL("4.2", 42) }, + { LEVEL("5", 50) }, + { LEVEL("5.1", 51) }, + { LEVEL("5.2", 52) }, + { LEVEL("6", 60) }, + { LEVEL("6.1", 61) }, + { LEVEL("6.2", 62) }, +#undef LEVEL + + { "deblock", "Deblocking filter mode", + OFFSET(deblock), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, + + { "coder", "Entropy coder type", + OFFSET(unit_opts.cabac), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS, "coder" }, + { "cavlc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS, "coder" }, + { "cabac", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, FLAGS, "coder" }, + + { NULL }, +}; + +static const FFCodecDefault d3d12va_encode_h264_defaults[] = { + { "b", "0" }, + { "bf", "2" }, + { "g", "120" }, + { "qmin", "-1" }, + { "qmax", "-1" }, + { NULL }, +}; + +static const AVClass d3d12va_encode_h264_class = { + .class_name = "h264_d3d12va", + .item_name = av_default_item_name, + .option = d3d12va_encode_h264_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_h264_d3d12va_encoder = { + .p.name = "h264_d3d12va", + CODEC_LONG_NAME("D3D12VA h264 encoder"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_H264, + .priv_data_size = sizeof(D3D12VAEncodeH264Context), + .init = &d3d12va_encode_h264_init, + FF_CODEC_RECEIVE_PACKET_CB(&ff_d3d12va_encode_receive_packet), + .close = &d3d12va_encode_h264_close, + .p.priv_class = &d3d12va_encode_h264_class, + .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | + AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, + .defaults = d3d12va_encode_h264_defaults, + CODEC_PIXFMTS(AV_PIX_FMT_D3D12), + .hw_configs = ff_d3d12va_encode_hw_configs, + .p.wrapper_name = "d3d12va", +}; diff --git a/libavcodec/d3d12va_encode_hevc.c b/libavcodec/d3d12va_encode_hevc.c index 571ce5738..8cae7a8b6 100644 --- a/libavcodec/d3d12va_encode_hevc.c +++ b/libavcodec/d3d12va_encode_hevc.c @@ -28,6 +28,7 @@ #include "avcodec.h" #include "cbs.h" #include "cbs_h265.h" +#include "hw_base_encode_h265.h" #include "h2645data.h" #include "h265_profile_level.h" #include "codec_internal.h" @@ -44,13 +45,11 @@ typedef struct D3D12VAEncodeHEVCContext { // User options. int qp; int profile; - int tier; int level; // Writer structures. - H265RawVPS raw_vps; - H265RawSPS raw_sps; - H265RawPPS raw_pps; + FFHWBaseEncodeH265 units; + FFHWBaseEncodeH265Opts unit_opts; CodedBitstreamContext *cbc; CodedBitstreamFragment current_access_unit; @@ -212,15 +211,15 @@ static int d3d12va_encode_hevc_write_sequence_header(AVCodecContext *avctx, CodedBitstreamFragment *au = &priv->current_access_unit; int err; - err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->raw_vps); + err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->units.raw_vps); if (err < 0) goto fail; - err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->raw_sps); + err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->units.raw_sps); if (err < 0) goto fail; - err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->raw_pps); + err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->units.raw_pps); if (err < 0) goto fail; @@ -237,25 +236,21 @@ static int d3d12va_encode_hevc_init_sequence_params(AVCodecContext *avctx) D3D12VAEncodeContext *ctx = avctx->priv_data; D3D12VAEncodeHEVCContext *priv = avctx->priv_data; AVD3D12VAFramesContext *hwctx = base_ctx->input_frames->hwctx; - H265RawVPS *vps = &priv->raw_vps; - H265RawSPS *sps = &priv->raw_sps; - H265RawPPS *pps = &priv->raw_pps; - H265RawProfileTierLevel *ptl = &vps->profile_tier_level; - H265RawVUI *vui = &sps->vui; + H265RawSPS *sps = &priv->units.raw_sps; + H265RawPPS *pps = &priv->units.raw_pps; D3D12_VIDEO_ENCODER_PROFILE_HEVC profile = D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN; D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC level = { 0 }; const AVPixFmtDescriptor *desc; uint8_t min_cu_size, max_cu_size, min_tu_size, max_tu_size; - int chroma_format, bit_depth; HRESULT hr; - int i; + int err; D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT support = { .NodeIndex = 0, .Codec = D3D12_VIDEO_ENCODER_CODEC_HEVC, .InputFormat = hwctx->format, .RateControl = ctx->rc, - .IntraRefresh = D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE, + .IntraRefresh = ctx->intra_refresh.Mode, .SubregionFrameEncoding = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME, .ResolutionsListCount = 1, .pResolutionList = &ctx->resolution, @@ -278,148 +273,58 @@ static int d3d12va_encode_hevc_init_sequence_params(AVCodecContext *avctx) } if (!(support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK)) { - av_log(avctx, AV_LOG_ERROR, "Driver does not support some request features. %#x\n", + av_log(avctx, AV_LOG_ERROR, "Driver does not support requested features. ValidationFlags: %#x\n", support.ValidationFlags); + ff_d3d12va_encode_check_encoder_feature_flags(avctx, support.ValidationFlags); return AVERROR(EINVAL); } if (support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) { - av_log(avctx, AV_LOG_ERROR, "D3D12 video encode on this device requires texture array support, " - "but it's not implemented.\n"); - return AVERROR_PATCHWELCOME; + ctx->is_texture_array = 1; + av_log(avctx, AV_LOG_DEBUG, "D3D12 video encode on this device uses texture array mode.\n"); } - memset(vps, 0, sizeof(*vps)); - memset(sps, 0, sizeof(*sps)); - memset(pps, 0, sizeof(*pps)); + // Check if the configuration with DELTA_QP is supported + if (support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_DELTA_QP_AVAILABLE) { + base_ctx->roi_allowed = 1; + // Store the QP map region size from resolution limits + ctx->qp_map_region_size = ctx->res_limits.QPMapRegionPixelsSize; + av_log(avctx, AV_LOG_DEBUG, "ROI encoding is supported via delta QP " + "(QP map region size: %d pixels).\n", ctx->qp_map_region_size); + } else { + base_ctx->roi_allowed = 0; + av_log(avctx, AV_LOG_DEBUG, "ROI encoding not supported by hardware for current rate control mode \n"); + } + + // Check motion estimation precision mode support + if (ctx->me_precision != D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM) { + if (!(support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_MOTION_ESTIMATION_PRECISION_MODE_LIMIT_AVAILABLE)) { + av_log(avctx, AV_LOG_ERROR, "Hardware does not support motion estimation " + "precision mode limits.\n"); + return AVERROR(ENOTSUP); + } + av_log(avctx, AV_LOG_VERBOSE, "Hardware supports motion estimation " + "precision mode limits.\n"); + } desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format); av_assert0(desc); - if (desc->nb_components == 1) { - chroma_format = 0; - } else { - if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 1) { - chroma_format = 1; - } else if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 0) { - chroma_format = 2; - } else if (desc->log2_chroma_w == 0 && desc->log2_chroma_h == 0) { - chroma_format = 3; - } else { - av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format " - "%s is not supported.\n", desc->name); - return AVERROR(EINVAL); - } - } - bit_depth = desc->comp[0].depth; min_cu_size = d3d12va_encode_hevc_map_cusize(ctx->codec_conf.pHEVCConfig->MinLumaCodingUnitSize); max_cu_size = d3d12va_encode_hevc_map_cusize(ctx->codec_conf.pHEVCConfig->MaxLumaCodingUnitSize); min_tu_size = d3d12va_encode_hevc_map_tusize(ctx->codec_conf.pHEVCConfig->MinLumaTransformUnitSize); max_tu_size = d3d12va_encode_hevc_map_tusize(ctx->codec_conf.pHEVCConfig->MaxLumaTransformUnitSize); - // VPS + // cu_qp_delta always required to be 1 in https://github.com/microsoft/DirectX-Specs/blob/master/d3d/D3D12VideoEncoding.md + priv->unit_opts.cu_qp_delta_enabled_flag = 1; + priv->unit_opts.nb_slices = 1; - vps->nal_unit_header = (H265RawNALUnitHeader) { - .nal_unit_type = HEVC_NAL_VPS, - .nuh_layer_id = 0, - .nuh_temporal_id_plus1 = 1, - }; + err = ff_hw_base_encode_init_params_h265(base_ctx, avctx, + &priv->units, &priv->unit_opts); + if (err < 0) + return err; - vps->vps_video_parameter_set_id = 0; - - vps->vps_base_layer_internal_flag = 1; - vps->vps_base_layer_available_flag = 1; - vps->vps_max_layers_minus1 = 0; - vps->vps_max_sub_layers_minus1 = 0; - vps->vps_temporal_id_nesting_flag = 1; - - ptl->general_profile_space = 0; - ptl->general_profile_idc = avctx->profile; - ptl->general_tier_flag = priv->tier; - - ptl->general_profile_compatibility_flag[ptl->general_profile_idc] = 1; - - ptl->general_progressive_source_flag = 1; - ptl->general_interlaced_source_flag = 0; - ptl->general_non_packed_constraint_flag = 1; - ptl->general_frame_only_constraint_flag = 1; - - ptl->general_max_14bit_constraint_flag = bit_depth <= 14; - ptl->general_max_12bit_constraint_flag = bit_depth <= 12; - ptl->general_max_10bit_constraint_flag = bit_depth <= 10; - ptl->general_max_8bit_constraint_flag = bit_depth == 8; - - ptl->general_max_422chroma_constraint_flag = chroma_format <= 2; - ptl->general_max_420chroma_constraint_flag = chroma_format <= 1; - ptl->general_max_monochrome_constraint_flag = chroma_format == 0; - - ptl->general_intra_constraint_flag = base_ctx->gop_size == 1; - ptl->general_one_picture_only_constraint_flag = 0; - - ptl->general_lower_bit_rate_constraint_flag = 1; - - if (avctx->level != FF_LEVEL_UNKNOWN) { - ptl->general_level_idc = avctx->level; - } else { - const H265LevelDescriptor *level; - - level = ff_h265_guess_level(ptl, avctx->bit_rate, - base_ctx->surface_width, base_ctx->surface_height, - 1, 1, 1, (base_ctx->b_per_p > 0) + 1); - if (level) { - av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); - ptl->general_level_idc = level->level_idc; - } else { - av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to " - "any normal level; using level 8.5.\n"); - ptl->general_level_idc = 255; - // The tier flag must be set in level 8.5. - ptl->general_tier_flag = 1; - } - avctx->level = ptl->general_level_idc; - } - - vps->vps_sub_layer_ordering_info_present_flag = 0; - vps->vps_max_dec_pic_buffering_minus1[0] = base_ctx->max_b_depth + 1; - vps->vps_max_num_reorder_pics[0] = base_ctx->max_b_depth; - vps->vps_max_latency_increase_plus1[0] = 0; - - vps->vps_max_layer_id = 0; - vps->vps_num_layer_sets_minus1 = 0; - vps->layer_id_included_flag[0][0] = 1; - - vps->vps_timing_info_present_flag = 1; - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { - vps->vps_num_units_in_tick = avctx->framerate.den; - vps->vps_time_scale = avctx->framerate.num; - vps->vps_poc_proportional_to_timing_flag = 1; - vps->vps_num_ticks_poc_diff_one_minus1 = 0; - } else { - vps->vps_num_units_in_tick = avctx->time_base.num; - vps->vps_time_scale = avctx->time_base.den; - vps->vps_poc_proportional_to_timing_flag = 0; - } - vps->vps_num_hrd_parameters = 0; - - // SPS - - sps->nal_unit_header = (H265RawNALUnitHeader) { - .nal_unit_type = HEVC_NAL_SPS, - .nuh_layer_id = 0, - .nuh_temporal_id_plus1 = 1, - }; - - sps->sps_video_parameter_set_id = vps->vps_video_parameter_set_id; - - sps->sps_max_sub_layers_minus1 = vps->vps_max_sub_layers_minus1; - sps->sps_temporal_id_nesting_flag = vps->vps_temporal_id_nesting_flag; - - sps->profile_tier_level = vps->profile_tier_level; - - sps->sps_seq_parameter_set_id = 0; - - sps->chroma_format_idc = chroma_format; - sps->separate_colour_plane_flag = 0; + avctx->level = priv->units.raw_vps.profile_tier_level.general_level_idc; av_assert0(ctx->res_limits.SubregionBlockPixelsSize % min_cu_size == 0); @@ -441,22 +346,8 @@ static int d3d12va_encode_hevc_init_sequence_params(AVCodecContext *avctx) sps->conformance_window_flag = 0; } - sps->bit_depth_luma_minus8 = bit_depth - 8; - sps->bit_depth_chroma_minus8 = bit_depth - 8; - sps->log2_max_pic_order_cnt_lsb_minus4 = ctx->gop.pHEVCGroupOfPictures->log2_max_pic_order_cnt_lsb_minus4; - sps->sps_sub_layer_ordering_info_present_flag = - vps->vps_sub_layer_ordering_info_present_flag; - for (i = 0; i <= sps->sps_max_sub_layers_minus1; i++) { - sps->sps_max_dec_pic_buffering_minus1[i] = - vps->vps_max_dec_pic_buffering_minus1[i]; - sps->sps_max_num_reorder_pics[i] = - vps->vps_max_num_reorder_pics[i]; - sps->sps_max_latency_increase_plus1[i] = - vps->vps_max_latency_increase_plus1[i]; - } - sps->log2_min_luma_coding_block_size_minus3 = (uint8_t)(av_log2(min_cu_size) - 3); sps->log2_diff_max_min_luma_coding_block_size = (uint8_t)(av_log2(max_cu_size) - av_log2(min_cu_size)); sps->log2_min_luma_transform_block_size_minus2 = (uint8_t)(av_log2(min_tu_size) - 2); @@ -469,100 +360,21 @@ static int d3d12va_encode_hevc_init_sequence_params(AVCodecContext *avctx) D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION); sps->sample_adaptive_offset_enabled_flag = !!(ctx->codec_conf.pHEVCConfig->ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER); - sps->sps_temporal_mvp_enabled_flag = 0; - sps->pcm_enabled_flag = 0; - - sps->vui_parameters_present_flag = 1; - - if (avctx->sample_aspect_ratio.num != 0 && - avctx->sample_aspect_ratio.den != 0) { - int num, den, i; - av_reduce(&num, &den, avctx->sample_aspect_ratio.num, - avctx->sample_aspect_ratio.den, 65535); - for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) { - if (num == ff_h2645_pixel_aspect[i].num && - den == ff_h2645_pixel_aspect[i].den) { - vui->aspect_ratio_idc = i; - break; - } - } - if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) { - vui->aspect_ratio_idc = 255; - vui->sar_width = num; - vui->sar_height = den; - } - vui->aspect_ratio_info_present_flag = 1; - } - - // Unspecified video format, from table E-2. - vui->video_format = 5; - vui->video_full_range_flag = - avctx->color_range == AVCOL_RANGE_JPEG; - vui->colour_primaries = avctx->color_primaries; - vui->transfer_characteristics = avctx->color_trc; - vui->matrix_coefficients = avctx->colorspace; - if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || - avctx->color_trc != AVCOL_TRC_UNSPECIFIED || - avctx->colorspace != AVCOL_SPC_UNSPECIFIED) - vui->colour_description_present_flag = 1; - if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED || - vui->colour_description_present_flag) - vui->video_signal_type_present_flag = 1; - - if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) { - vui->chroma_loc_info_present_flag = 1; - vui->chroma_sample_loc_type_top_field = - vui->chroma_sample_loc_type_bottom_field = - avctx->chroma_sample_location - 1; - } - - vui->vui_timing_info_present_flag = 1; - vui->vui_num_units_in_tick = vps->vps_num_units_in_tick; - vui->vui_time_scale = vps->vps_time_scale; - vui->vui_poc_proportional_to_timing_flag = vps->vps_poc_proportional_to_timing_flag; - vui->vui_num_ticks_poc_diff_one_minus1 = vps->vps_num_ticks_poc_diff_one_minus1; - vui->vui_hrd_parameters_present_flag = 0; - - vui->bitstream_restriction_flag = 1; - vui->motion_vectors_over_pic_boundaries_flag = 1; - vui->restricted_ref_pic_lists_flag = 1; - vui->max_bytes_per_pic_denom = 0; - vui->max_bits_per_min_cu_denom = 0; - vui->log2_max_mv_length_horizontal = 15; - vui->log2_max_mv_length_vertical = 15; - - // PPS - - pps->nal_unit_header = (H265RawNALUnitHeader) { - .nal_unit_type = HEVC_NAL_PPS, - .nuh_layer_id = 0, - .nuh_temporal_id_plus1 = 1, - }; - - pps->pps_pic_parameter_set_id = 0; - pps->pps_seq_parameter_set_id = sps->sps_seq_parameter_set_id; pps->cabac_init_present_flag = 1; - pps->num_ref_idx_l0_default_active_minus1 = 0; - pps->num_ref_idx_l1_default_active_minus1 = 0; - pps->init_qp_minus26 = 0; pps->transform_skip_enabled_flag = !!(ctx->codec_conf.pHEVCConfig->ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING); - // cu_qp_delta always required to be 1 in https://github.com/microsoft/DirectX-Specs/blob/master/d3d/D3D12VideoEncoding.md - pps->cu_qp_delta_enabled_flag = 1; - - pps->diff_cu_qp_delta_depth = 0; - pps->pps_slice_chroma_qp_offsets_present_flag = 1; pps->tiles_enabled_flag = 0; // no tiling in D3D12 pps->pps_loop_filter_across_slices_enabled_flag = !(ctx->codec_conf.pHEVCConfig->ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES); + pps->deblocking_filter_control_present_flag = 1; return 0; @@ -729,7 +541,7 @@ static int d3d12va_encode_hevc_set_level(AVCodecContext *avctx) return AVERROR(EINVAL); } - ctx->level.pHEVCLevelSetting->Tier = priv->raw_vps.profile_tier_level.general_tier_flag == 0 ? + ctx->level.pHEVCLevelSetting->Tier = priv->units.raw_vps.profile_tier_level.general_tier_flag == 0 ? D3D12_VIDEO_ENCODER_TIER_HEVC_MAIN : D3D12_VIDEO_ENCODER_TIER_HEVC_HIGH; @@ -750,6 +562,7 @@ static void d3d12va_encode_hevc_free_picture_params(D3D12VAEncodePicture *pic) static int d3d12va_encode_hevc_init_picture_params(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic) { + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; D3D12VAEncodePicture *pic = base_pic->priv; D3D12VAEncodeHEVCPicture *hpic = base_pic->codec_priv; FFHWBaseEncodePicture *prev = base_pic->prev; @@ -843,6 +656,12 @@ static int d3d12va_encode_hevc_init_picture_params(AVCodecContext *avctx, pic->pic_ctl.pHEVCPicData->ReferenceFramesReconPictureDescriptorsCount = idx; pic->pic_ctl.pHEVCPicData->pReferenceFramesReconPictureDescriptors = pd; + // Process ROI side data if present and supported + if (base_ctx->roi_allowed && pic->qp_map && pic->qp_map_size > 0) { + pic->pic_ctl.pHEVCPicData->QPMapValuesCount = pic->qp_map_size; + pic->pic_ctl.pHEVCPicData->pRateControlQPMap = (INT8 *)pic->qp_map; + } + return 0; } @@ -883,10 +702,10 @@ static int d3d12va_encode_hevc_init(AVCodecContext *avctx) if (avctx->profile == AV_PROFILE_UNKNOWN) avctx->profile = priv->profile; - if (avctx->level == FF_LEVEL_UNKNOWN) + if (avctx->level == AV_LEVEL_UNKNOWN) avctx->level = priv->level; - if (avctx->level != FF_LEVEL_UNKNOWN && avctx->level & ~0xff) { + if (avctx->level != AV_LEVEL_UNKNOWN && avctx->level & ~0xff) { av_log(avctx, AV_LOG_ERROR, "Invalid level %d: must fit " "in 8-bit unsigned integer.\n", avctx->level); return AVERROR(EINVAL); @@ -916,6 +735,7 @@ static int d3d12va_encode_hevc_close(AVCodecContext *avctx) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption d3d12va_encode_hevc_options[] = { HW_BASE_ENCODE_COMMON_OPTIONS, + D3D12VA_ENCODE_COMMON_OPTIONS, D3D12VA_ENCODE_RC_OPTIONS, { "qp", "Constant QP (for P-frames; scaled by qfactor/qoffset for I/B)", @@ -932,7 +752,7 @@ static const AVOption d3d12va_encode_hevc_options[] = { #undef PROFILE { "tier", "Set tier (general_tier_flag)", - OFFSET(tier), AV_OPT_TYPE_INT, + OFFSET(unit_opts.tier), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS, "tier" }, { "main", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "tier" }, @@ -941,7 +761,7 @@ static const AVOption d3d12va_encode_hevc_options[] = { { "level", "Set level (general_level_idc)", OFFSET(level), AV_OPT_TYPE_INT, - { .i64 = FF_LEVEL_UNKNOWN }, FF_LEVEL_UNKNOWN, 0xff, FLAGS, "level" }, + { .i64 = AV_LEVEL_UNKNOWN }, AV_LEVEL_UNKNOWN, 0xff, FLAGS, "level" }, #define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ { .i64 = value }, 0, 0, FLAGS, "level" @@ -973,6 +793,7 @@ static const FFCodecDefault d3d12va_encode_hevc_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -998,10 +819,7 @@ const FFCodec ff_hevc_d3d12va_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = d3d12va_encode_hevc_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_D3D12, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_D3D12), .hw_configs = ff_d3d12va_encode_hw_configs, .p.wrapper_name = "d3d12va", }; diff --git a/libavcodec/d3d12va_h264.c b/libavcodec/d3d12va_h264.c index b2fe2955c..dec9344aa 100644 --- a/libavcodec/d3d12va_h264.c +++ b/libavcodec/d3d12va_h264.c @@ -50,8 +50,9 @@ static void fill_slice_short(DXVA_Slice_H264_Short *slice, } static int d3d12va_h264_start_frame(AVCodecContext *avctx, - av_unused const uint8_t *buffer, - av_unused uint32_t size) + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const H264Context *h = avctx->priv_data; H264DecodePictureContext *ctx_pic = h->cur_pic_ptr->hwaccel_picture_private; @@ -173,7 +174,7 @@ static int d3d12va_h264_end_frame(AVCodecContext *avctx) return ret; } -static int d3d12va_h264_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_h264_decode_init(AVCodecContext *avctx) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); DXVA_PicParams_H264 pp; diff --git a/libavcodec/d3d12va_hevc.c b/libavcodec/d3d12va_hevc.c index 7686f0eb6..e72d49b7d 100644 --- a/libavcodec/d3d12va_hevc.c +++ b/libavcodec/d3d12va_hevc.c @@ -49,7 +49,10 @@ static void fill_slice_short(DXVA_Slice_HEVC_Short *slice, unsigned position, un slice->wBadSliceChopping = 0; } -static int d3d12va_hevc_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int d3d12va_hevc_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const HEVCContext *h = avctx->priv_data; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); @@ -160,7 +163,7 @@ static int d3d12va_hevc_end_frame(AVCodecContext *avctx) scale ? &ctx_pic->qm : NULL, scale ? sizeof(ctx_pic->qm) : 0, update_input_arguments); } -static int d3d12va_hevc_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_hevc_decode_init(AVCodecContext *avctx) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); DXVA_PicParams_HEVC pp; diff --git a/libavcodec/d3d12va_mpeg2.c b/libavcodec/d3d12va_mpeg2.c index 86a7d97b3..47e453dd5 100644 --- a/libavcodec/d3d12va_mpeg2.c +++ b/libavcodec/d3d12va_mpeg2.c @@ -40,7 +40,10 @@ typedef struct D3D12DecodePictureContext { unsigned bitstream_size; } D3D12DecodePictureContext; -static int d3d12va_mpeg2_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int d3d12va_mpeg2_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const MpegEncContext *s = avctx->priv_data; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); @@ -150,7 +153,7 @@ static int d3d12va_mpeg2_end_frame(AVCodecContext *avctx) return ret; } -static int d3d12va_mpeg2_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_mpeg2_decode_init(AVCodecContext *avctx) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); diff --git a/libavcodec/d3d12va_vc1.c b/libavcodec/d3d12va_vc1.c index dccc0fbff..e64a8e063 100644 --- a/libavcodec/d3d12va_vc1.c +++ b/libavcodec/d3d12va_vc1.c @@ -41,7 +41,10 @@ typedef struct D3D12DecodePictureContext { unsigned bitstream_size; } D3D12DecodePictureContext; -static int d3d12va_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int d3d12va_vc1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const VC1Context *v = avctx->priv_data; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); @@ -162,7 +165,7 @@ static int d3d12va_vc1_end_frame(AVCodecContext *avctx) update_input_arguments); } -static int d3d12va_vc1_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_vc1_decode_init(AVCodecContext *avctx) { int ret; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); diff --git a/libavcodec/d3d12va_vp9.c b/libavcodec/d3d12va_vp9.c index 3476768e6..6f1f933fd 100644 --- a/libavcodec/d3d12va_vp9.c +++ b/libavcodec/d3d12va_vp9.c @@ -45,7 +45,10 @@ static void fill_slice_short(DXVA_Slice_VPx_Short *slice, unsigned position, uns slice->wBadSliceChopping = 0; } -static int d3d12va_vp9_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int d3d12va_vp9_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const VP9SharedContext *h = avctx->priv_data; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); @@ -126,7 +129,7 @@ static int d3d12va_vp9_end_frame(AVCodecContext *avctx) &ctx_pic->pp, sizeof(ctx_pic->pp), NULL, 0, update_input_arguments); } -static int d3d12va_vp9_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_vp9_decode_init(AVCodecContext *avctx) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); DXVA_PicParams_VP9 pp; diff --git a/libavcodec/dca_parser.c b/libavcodec/dca_parser.c index eb0ef55d4..aaf4f4222 100644 --- a/libavcodec/dca_parser.c +++ b/libavcodec/dca_parser.c @@ -29,6 +29,7 @@ #include "dca_syncwords.h" #include "get_bits.h" #include "parser.h" +#include "parser_internal.h" typedef struct DCAParseContext { ParseContext pc; @@ -343,10 +344,10 @@ static int dca_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_dca_parser = { - .codec_ids = { AV_CODEC_ID_DTS }, +const FFCodecParser ff_dca_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_DTS), .priv_data_size = sizeof(DCAParseContext), - .parser_init = dca_parse_init, - .parser_parse = dca_parse, - .parser_close = ff_parse_close, + .init = dca_parse_init, + .parse = dca_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/dca_xll.c b/libavcodec/dca_xll.c index cecaee202..6eedad7eb 100644 --- a/libavcodec/dca_xll.c +++ b/libavcodec/dca_xll.c @@ -315,7 +315,7 @@ static int chs_parse_header(DCAXllDecoder *s, DCAXllChSet *c, DCAExssAsset *asse b->highest_pred_order = b->adapt_pred_order[i]; } if (b->highest_pred_order > s->nsegsamples) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL adaptive predicition order\n"); + av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL adaptive prediction order\n"); return AVERROR_INVALIDDATA; } @@ -674,7 +674,7 @@ static void chs_filter_band_data(DCAXllDecoder *s, DCAXllChSet *c, int band) } } - // Inverse pairwise channel decorrellation + // Inverse pairwise channel decorrelation if (b->decor_enabled) { int32_t *tmp[DCA_XLL_CHANNELS_MAX]; diff --git a/libavcodec/dcadec.c b/libavcodec/dcadec.c index 86d86ea45..0d7bf1c53 100644 --- a/libavcodec/dcadec.c +++ b/libavcodec/dcadec.c @@ -416,8 +416,6 @@ const FFCodec ff_dca_decoder = { .close = dcadec_close, .flush = dcadec_flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, .p.priv_class = &dcadec_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_dca_profiles), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/dcadsp.c b/libavcodec/dcadsp.c index 5ad1f644f..a0be67669 100644 --- a/libavcodec/dcadsp.c +++ b/libavcodec/dcadsp.c @@ -54,7 +54,7 @@ static void decode_joint_c(int32_t **dst, int32_t **src, } } -static void lfe_fir_float_c(float *pcm_samples, int32_t *lfe_samples, +static void lfe_fir_float_c(float *pcm_samples, const int32_t *lfe_samples, const float *filter_coeff, ptrdiff_t npcmblocks, int dec_select) { @@ -84,13 +84,13 @@ static void lfe_fir_float_c(float *pcm_samples, int32_t *lfe_samples, } } -static void lfe_fir0_float_c(float *pcm_samples, int32_t *lfe_samples, +static void lfe_fir0_float_c(float *pcm_samples, const int32_t *lfe_samples, const float *filter_coeff, ptrdiff_t npcmblocks) { lfe_fir_float_c(pcm_samples, lfe_samples, filter_coeff, npcmblocks, 0); } -static void lfe_fir1_float_c(float *pcm_samples, int32_t *lfe_samples, +static void lfe_fir1_float_c(float *pcm_samples, const int32_t *lfe_samples, const float *filter_coeff, ptrdiff_t npcmblocks) { lfe_fir_float_c(pcm_samples, lfe_samples, filter_coeff, npcmblocks, 1); @@ -193,7 +193,7 @@ static void sub_qmf64_float_c(SynthFilterContext *synth, } } -static void lfe_fir_fixed_c(int32_t *pcm_samples, int32_t *lfe_samples, +static void lfe_fir_fixed_c(int32_t *pcm_samples, const int32_t *lfe_samples, const int32_t *filter_coeff, ptrdiff_t npcmblocks) { // Select decimation factor @@ -487,7 +487,7 @@ av_cold void ff_dcadsp_init(DCADSPContext *s) s->lbr_bank = lbr_bank_c; s->lfe_iir = lfe_iir_c; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_dcadsp_init_x86(s); #endif } diff --git a/libavcodec/dcadsp.h b/libavcodec/dcadsp.h index c29755267..b99ec5561 100644 --- a/libavcodec/dcadsp.h +++ b/libavcodec/dcadsp.h @@ -40,7 +40,7 @@ typedef struct DCADSPContext { ptrdiff_t sb_start, ptrdiff_t sb_end, ptrdiff_t ofs, ptrdiff_t len); - void (*lfe_fir_float[2])(float *pcm_samples, int32_t *lfe_samples, + void (*lfe_fir_float[2])(float *pcm_samples, const int32_t *lfe_samples, const float *filter_coeff, ptrdiff_t npcmblocks); void (*lfe_x96_float)(float *dst, const float *src, @@ -56,7 +56,7 @@ typedef struct DCADSPContext { const float *filter_coeff, ptrdiff_t npcmblocks, float scale); - void (*lfe_fir_fixed)(int32_t *pcm_samples, int32_t *lfe_samples, + void (*lfe_fir_fixed)(int32_t *pcm_samples, const int32_t *lfe_samples, const int32_t *filter_coeff, ptrdiff_t npcmblocks); void (*lfe_x96_fixed)(int32_t *dst, const int32_t *src, diff --git a/libavcodec/dcaenc.c b/libavcodec/dcaenc.c index 83f13472d..6387f7b5e 100644 --- a/libavcodec/dcaenc.c +++ b/libavcodec/dcaenc.c @@ -199,7 +199,7 @@ static av_cold void dcaenc_init_static_tables(void) create_enc_table(&bitalloc_12_table[i][1], 12, &src_table); } -static int encode_init(AVCodecContext *avctx) +static av_cold int encode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; DCAEncContext *c = avctx->priv_data; @@ -854,7 +854,7 @@ static int init_quantization_noise(DCAEncContext *c, int noise, int forbid_zero) if (c->lfe_channel) c->consumed_bits += 72; - /* attempt to guess the bit distribution based on the prevoius frame */ + /* attempt to guess the bit distribution based on the previous frame */ for (ch = 0; ch < c->fullband_channels; ch++) { for (band = 0; band < 32; band++) { int snr_cb = c->peak_cb[ch][band] - c->band_masking_cb[band] - noise; @@ -1322,17 +1322,11 @@ const FFCodec ff_dca_encoder = { .close = encode_close, FF_CODEC_ENCODE_CB(encode_frame), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = sample_rates, - .p.ch_layouts = (const AVChannelLayout[]){ - AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - AV_CHANNEL_LAYOUT_2_2, - AV_CHANNEL_LAYOUT_5POINT0, - AV_CHANNEL_LAYOUT_5POINT1, - { 0 }, - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32), + CODEC_SAMPLERATES_ARRAY(sample_rates), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO, + AV_CHANNEL_LAYOUT_2_2, AV_CHANNEL_LAYOUT_5POINT0, + AV_CHANNEL_LAYOUT_5POINT1), .defaults = defaults, .p.priv_class = &dcaenc_class, }; diff --git a/libavcodec/dct.h b/libavcodec/dct.h index 17c881a69..17135207b 100644 --- a/libavcodec/dct.h +++ b/libavcodec/dct.h @@ -27,11 +27,11 @@ #include #include -void ff_j_rev_dct(int16_t *data); -void ff_j_rev_dct4(int16_t *data); -void ff_j_rev_dct2(int16_t *data); -void ff_j_rev_dct1(int16_t *data); -void ff_jref_idct_put(uint8_t *dest, ptrdiff_t line_size, int16_t *block); -void ff_jref_idct_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_j_rev_dct(int16_t data[64]); +void ff_j_rev_dct4(int16_t data[64]); +void ff_j_rev_dct2(int16_t data[64]); +void ff_j_rev_dct1(int16_t data[64]); +void ff_jref_idct_put(uint8_t *dest, ptrdiff_t line_size, int16_t block[64]); +void ff_jref_idct_add(uint8_t *dest, ptrdiff_t line_size, int16_t block[64]); #endif /* AVCODEC_DCT_H */ diff --git a/libavcodec/dds.c b/libavcodec/dds.c index 2af7f5c98..bd16b41e4 100644 --- a/libavcodec/dds.c +++ b/libavcodec/dds.c @@ -653,11 +653,6 @@ static int dds_decode(AVCodecContext *avctx, AVFrame *frame, ((unsigned)frame->data[1][3+i*4]<<24) ); } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif if (bytestream2_get_bytes_left(gbc) < frame->height * frame->width / 2) { av_log(avctx, AV_LOG_ERROR, "Buffer is too small (%d < %d).\n", @@ -687,12 +682,6 @@ FF_ENABLE_DEPRECATION_WARNINGS (frame->data[1][0+i*4]<<16)+ ((unsigned)frame->data[1][3+i*4]<<24) ); - -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } if (bytestream2_get_bytes_left(gbc) < frame->height * linesize) { diff --git a/libavcodec/decode.c b/libavcodec/decode.c index 0ab0f4bb4..5de5a8403 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -19,6 +19,7 @@ */ #include +#include #include #include "config.h" @@ -46,13 +47,14 @@ #include "codec_desc.h" #include "codec_internal.h" #include "decode.h" +#include "exif.h" #include "hwaccel_internal.h" #include "hwconfig.h" #include "internal.h" #include "lcevcdec.h" #include "packet_internal.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadprogress.h" @@ -96,6 +98,8 @@ typedef struct DecodeContext { struct { FFLCEVCContext *ctx; int frame; + int base_width; + int base_height; int width; int height; } lcevc; @@ -175,10 +179,6 @@ static int extract_packet_props(AVCodecInternal *avci, const AVPacket *pkt) av_packet_unref(avci->last_pkt_props); if (pkt) { ret = av_packet_copy_props(avci->last_pkt_props, pkt); -#if FF_API_FRAME_PKT - if (!ret) - avci->last_pkt_props->stream_index = pkt->size; // Needed for ff_decode_frame_props(). -#endif } return ret; } @@ -220,7 +220,7 @@ fail: #if !HAVE_THREADS #define ff_thread_get_packet(avctx, pkt) (AVERROR_BUG) -#define ff_thread_receive_frame(avctx, frame) (AVERROR_BUG) +#define ff_thread_receive_frame(avctx, frame, flags) (AVERROR_BUG) #endif static int decode_get_packet(AVCodecContext *avctx, AVPacket *pkt) @@ -447,14 +447,6 @@ static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame, if (!(codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS)) frame->pkt_dts = pkt->dts; - if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) { -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - if(!avctx->has_b_frames) - frame->pkt_pos = pkt->pos; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - } emms_c(); if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) { @@ -510,10 +502,6 @@ FF_ENABLE_DEPRECATION_WARNINGS pkt->pts = AV_NOPTS_VALUE; pkt->dts = AV_NOPTS_VALUE; if (!(codec->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS)) { -#if FF_API_FRAME_PKT - // See extract_packet_props() comment. - avci->last_pkt_props->stream_index = avci->last_pkt_props->stream_index - consumed; -#endif avci->last_pkt_props->pts = AV_NOPTS_VALUE; avci->last_pkt_props->dts = AV_NOPTS_VALUE; } @@ -586,6 +574,8 @@ static int fill_frame_props(const AVCodecContext *avctx, AVFrame *frame) frame->color_range = avctx->color_range; if (frame->chroma_location == AVCHROMA_LOC_UNSPECIFIED) frame->chroma_location = avctx->chroma_sample_location; + if (frame->alpha_mode == AVALPHA_MODE_UNSPECIFIED) + frame->alpha_mode = avctx->alpha_mode; if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { if (!frame->sample_aspect_ratio.num) frame->sample_aspect_ratio = avctx->sample_aspect_ratio; @@ -657,14 +647,15 @@ int ff_decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) return ret; } -static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) +static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame, + unsigned flags) { AVCodecInternal *avci = avctx->internal; DecodeContext *dc = decode_ctx(avci); int ret, ok; if (avctx->active_thread_type & FF_THREAD_FRAME) - ret = ff_thread_receive_frame(avctx, frame); + ret = ff_thread_receive_frame(avctx, frame, flags); else ret = ff_decode_receive_frame_internal(avctx, frame); @@ -689,28 +680,17 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) return ret; } -#if FF_API_FRAME_KEY -FF_DISABLE_DEPRECATION_WARNINGS - frame->key_frame = !!(frame->flags & AV_FRAME_FLAG_KEY); -FF_ENABLE_DEPRECATION_WARNINGS -#endif -#if FF_API_INTERLACED_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - frame->interlaced_frame = !!(frame->flags & AV_FRAME_FLAG_INTERLACED); - frame->top_field_first = !!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST); -FF_ENABLE_DEPRECATION_WARNINGS -#endif frame->best_effort_timestamp = guess_correct_pts(dc, frame->pts, frame->pkt_dts); /* the only case where decode data is not set should be decoders * that do not call ff_get_buffer() */ - av_assert0((frame->private_ref && frame->private_ref->size == sizeof(FrameDecodeData)) || + av_assert0(frame->private_ref || !(avctx->codec->capabilities & AV_CODEC_CAP_DR1)); if (frame->private_ref) { - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FrameDecodeData *fdd = frame->private_ref; if (fdd->post_process) { ret = fdd->post_process(avctx, frame); @@ -723,7 +703,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } /* free the per-frame decode data */ - av_buffer_unref(&frame->private_ref); + av_refstruct_unref(&frame->private_ref); return ret; } @@ -753,7 +733,7 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke dc->draining_started = 1; if (!avci->buffer_frame->buf[0] && !dc->draining_started) { - ret = decode_receive_frame_internal(avctx, avci->buffer_frame); + ret = decode_receive_frame_internal(avctx, avci->buffer_frame, 0); if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) return ret; } @@ -770,8 +750,8 @@ static int apply_cropping(AVCodecContext *avctx, AVFrame *frame) (frame->crop_top + frame->crop_bottom) >= frame->height) { av_log(avctx, AV_LOG_WARNING, "Invalid cropping information set by a decoder: " - "%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER" " - "(frame size %dx%d). This is a bug, please report it\n", + "%zu/%zu/%zu/%zu (frame size %dx%d). " + "This is a bug, please report it\n", frame->crop_left, frame->crop_right, frame->crop_top, frame->crop_bottom, frame->width, frame->height); frame->crop_left = 0; @@ -815,18 +795,15 @@ fail: return AVERROR_BUG; } -int ff_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame) +int ff_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame, unsigned flags) { AVCodecInternal *avci = avctx->internal; int ret; - if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec)) - return AVERROR(EINVAL); - if (avci->buffer_frame->buf[0]) { av_frame_move_ref(frame, avci->buffer_frame); } else { - ret = decode_receive_frame_internal(avctx, frame); + ret = decode_receive_frame_internal(avctx, frame, flags); if (ret < 0) return ret; } @@ -843,53 +820,6 @@ int ff_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame) avctx->frame_num++; -#if FF_API_DROPCHANGED - if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED) { - - if (avctx->frame_num == 1) { - avci->initial_format = frame->format; - switch(avctx->codec_type) { - case AVMEDIA_TYPE_VIDEO: - avci->initial_width = frame->width; - avci->initial_height = frame->height; - break; - case AVMEDIA_TYPE_AUDIO: - avci->initial_sample_rate = frame->sample_rate ? frame->sample_rate : - avctx->sample_rate; - ret = av_channel_layout_copy(&avci->initial_ch_layout, &frame->ch_layout); - if (ret < 0) - goto fail; - break; - } - } - - if (avctx->frame_num > 1) { - int changed = avci->initial_format != frame->format; - - switch(avctx->codec_type) { - case AVMEDIA_TYPE_VIDEO: - changed |= avci->initial_width != frame->width || - avci->initial_height != frame->height; - break; - case AVMEDIA_TYPE_AUDIO: - changed |= avci->initial_sample_rate != frame->sample_rate || - avci->initial_sample_rate != avctx->sample_rate || - av_channel_layout_compare(&avci->initial_ch_layout, &frame->ch_layout); - break; - } - - if (changed) { - avci->changed_frames_dropped++; - av_log(avctx, AV_LOG_INFO, "dropped changed frame #%"PRId64" pts %"PRId64 - " drop count: %d \n", - avctx->frame_num, frame->pts, - avci->changed_frames_dropped); - ret = AVERROR_INPUT_CHANGED; - goto fail; - } - } - } -#endif return 0; fail: av_frame_unref(frame); @@ -1177,6 +1107,7 @@ int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, const AVCodecHWConfigInternal *hw_config; const FFHWAccel *hwa; int i, ret; + bool clean_priv_data = false; for (i = 0;; i++) { hw_config = ffcodec(avctx->codec)->hw_configs[i]; @@ -1201,6 +1132,7 @@ int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, av_buffer_unref(&frames_ref); return AVERROR(ENOMEM); } + clean_priv_data = true; } ret = hwa->frame_params(avctx, frames_ref); @@ -1221,6 +1153,8 @@ int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, *out_frames_ref = frames_ref; } else { + if (clean_priv_data) + av_freep(&avctx->internal->hwaccel_priv_data); av_buffer_unref(&frames_ref); } return ret; @@ -1464,6 +1398,78 @@ static int side_data_stereo3d_merge(AVFrameSideData *sd_frame, return 0; } +static int side_data_exif_parse(AVFrame *dst, const AVPacketSideData *sd_pkt) +{ + AVExifMetadata ifd = { 0 }; + AVExifEntry *entry = NULL; + AVBufferRef *buf = NULL; + AVFrameSideData *sd_frame; + int ret; + + ret = av_exif_parse_buffer(NULL, sd_pkt->data, sd_pkt->size, &ifd, + AV_EXIF_TIFF_HEADER); + if (ret < 0) + return ret; + + ret = av_exif_get_entry(NULL, &ifd, av_exif_get_tag_id("Orientation"), 0, &entry); + if (ret < 0) + goto end; + + if (!entry) { + ret = av_exif_ifd_to_dict(NULL, &ifd, &dst->metadata); + if (ret < 0) + goto end; + + sd_frame = av_frame_side_data_new(&dst->side_data, &dst->nb_side_data, AV_FRAME_DATA_EXIF, + sd_pkt->size, 0); + if (sd_frame) + memcpy(sd_frame->data, sd_pkt->data, sd_pkt->size); + ret = sd_frame ? 0 : AVERROR(ENOMEM); + + goto end; + } else if (entry->count <= 0 || entry->type != AV_TIFF_SHORT) { + ret = AVERROR_INVALIDDATA; + goto end; + } + + // If a display matrix already exists in the frame, give it priority + if (av_frame_side_data_get(dst->side_data, dst->nb_side_data, AV_FRAME_DATA_DISPLAYMATRIX)) + goto finish; + + sd_frame = av_frame_side_data_new(&dst->side_data, &dst->nb_side_data, AV_FRAME_DATA_DISPLAYMATRIX, + sizeof(int32_t) * 9, 0); + if (!sd_frame) { + ret = AVERROR(ENOMEM); + goto end; + } + + ret = av_exif_orientation_to_matrix((int32_t *)sd_frame->data, entry->value.uint[0]); + if (ret < 0) + goto end; + +finish: + av_exif_remove_entry(NULL, &ifd, entry->id, 0); + + ret = av_exif_ifd_to_dict(NULL, &ifd, &dst->metadata); + if (ret < 0) + goto end; + + ret = av_exif_write(NULL, &ifd, &buf, AV_EXIF_TIFF_HEADER); + if (ret < 0) + goto end; + + if (!av_frame_side_data_add(&dst->side_data, &dst->nb_side_data, AV_FRAME_DATA_EXIF, &buf, 0)) { + ret = AVERROR(ENOMEM); + goto end; + } + + ret = 0; +end: + av_buffer_unref(&buf); + av_exif_free(&ifd); + return ret; +} + static int side_data_map(AVFrame *dst, const AVPacketSideData *sd_src, int nb_sd_src, const SideDataMap *map) @@ -1490,11 +1496,21 @@ static int side_data_map(AVFrame *dst, continue; } - sd_frame = av_frame_new_side_data(dst, type_frame, sd_pkt->size); - if (!sd_frame) - return AVERROR(ENOMEM); + switch (type_pkt) { + case AV_PKT_DATA_EXIF: { + int ret = side_data_exif_parse(dst, sd_pkt); + if (ret < 0) + return ret; + break; + } + default: + sd_frame = av_frame_new_side_data(dst, type_frame, sd_pkt->size); + if (!sd_frame) + return AVERROR(ENOMEM); - memcpy(sd_frame->data, sd_pkt->data, sd_pkt->size); + memcpy(sd_frame->data, sd_pkt->data, sd_pkt->size); + break; + } } return 0; @@ -1529,12 +1545,6 @@ int ff_decode_frame_props_from_pkt(const AVCodecContext *avctx, frame->pts = pkt->pts; frame->duration = pkt->duration; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frame->pkt_pos = pkt->pos; - frame->pkt_size = pkt->size; -FF_ENABLE_DEPRECATION_WARNINGS -#endif ret = side_data_map(frame, pkt->side_data, pkt->side_data_elems, ff_sd_global_map); if (ret < 0) @@ -1569,17 +1579,21 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame) if (ret < 0) return ret; + for (int i = 0; i < avctx->nb_decoded_side_data; i++) { + const AVFrameSideData *src = avctx->decoded_side_data[i]; + if (av_frame_get_side_data(frame, src->type)) + continue; + ret = av_frame_side_data_clone(&frame->side_data, &frame->nb_side_data, src, 0); + if (ret < 0) + return ret; + } + if (!(ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS)) { const AVPacket *pkt = avctx->internal->last_pkt_props; ret = ff_decode_frame_props_from_pkt(avctx, frame, pkt); if (ret < 0) return ret; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frame->pkt_size = pkt->stream_index; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } ret = fill_frame_props(avctx, frame); @@ -1622,44 +1636,34 @@ static void validate_avframe_allocation(AVCodecContext *avctx, AVFrame *frame) } } -static void decode_data_free(void *opaque, uint8_t *data) +static void decode_data_free(AVRefStructOpaque unused, void *obj) { - FrameDecodeData *fdd = (FrameDecodeData*)data; + FrameDecodeData *fdd = obj; if (fdd->post_process_opaque_free) fdd->post_process_opaque_free(fdd->post_process_opaque); if (fdd->hwaccel_priv_free) fdd->hwaccel_priv_free(fdd->hwaccel_priv); - - av_freep(&fdd); } int ff_attach_decode_data(AVFrame *frame) { - AVBufferRef *fdd_buf; FrameDecodeData *fdd; av_assert1(!frame->private_ref); - av_buffer_unref(&frame->private_ref); + av_refstruct_unref(&frame->private_ref); - fdd = av_mallocz(sizeof(*fdd)); + fdd = av_refstruct_alloc_ext(sizeof(*fdd), 0, NULL, decode_data_free); if (!fdd) return AVERROR(ENOMEM); - fdd_buf = av_buffer_create((uint8_t*)fdd, sizeof(*fdd), decode_data_free, - NULL, AV_BUFFER_FLAG_READONLY); - if (!fdd_buf) { - av_freep(&fdd); - return AVERROR(ENOMEM); - } - - frame->private_ref = fdd_buf; + frame->private_ref = fdd; return 0; } -static void update_frame_props(AVCodecContext *avctx, AVFrame *frame) +static int update_frame_props(AVCodecContext *avctx, AVFrame *frame) { #if CONFIG_LIBLCEVC_DEC AVCodecInternal *avci = avctx->internal; @@ -1669,12 +1673,23 @@ static void update_frame_props(AVCodecContext *avctx, AVFrame *frame) av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC); if (dc->lcevc.frame) { - dc->lcevc.width = frame->width; - dc->lcevc.height = frame->height; - frame->width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1); - frame->height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1); + int ret = ff_lcevc_parse_frame(dc->lcevc.ctx, frame, + &dc->lcevc.width, &dc->lcevc.height, avctx); + if (ret < 0) + return ret; + + // force get_buffer2() to allocate the base frame using the same dimensions + // as the final enhanced frame, in order to prevent reinitializing the buffer + // pools unnecessarely + if (dc->lcevc.width && dc->lcevc.height) { + dc->lcevc.base_width = frame->width; + dc->lcevc.base_height = frame->height; + frame->width = dc->lcevc.width; + frame->height = dc->lcevc.height; + } } #endif + return 0; } static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame) @@ -1684,10 +1699,15 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame) DecodeContext *dc = decode_ctx(avci); if (dc->lcevc.frame) { - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FrameDecodeData *fdd = frame->private_ref; FFLCEVCFrame *frame_ctx; int ret; + if (!dc->lcevc.width || !dc->lcevc.height) { + dc->lcevc.frame = 0; + return 0; + } + frame_ctx = av_mallocz(sizeof(*frame_ctx)); if (!frame_ctx) return AVERROR(ENOMEM); @@ -1698,13 +1718,13 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame) return AVERROR(ENOMEM); } - frame_ctx->lcevc = ff_refstruct_ref(dc->lcevc.ctx); - frame_ctx->frame->width = frame->width; - frame_ctx->frame->height = frame->height; + frame_ctx->lcevc = av_refstruct_ref(dc->lcevc.ctx); + frame_ctx->frame->width = dc->lcevc.width; + frame_ctx->frame->height = dc->lcevc.height; frame_ctx->frame->format = frame->format; - frame->width = dc->lcevc.width; - frame->height = dc->lcevc.height; + frame->width = dc->lcevc.base_width; + frame->height = dc->lcevc.base_height; ret = avctx->get_buffer2(avctx, frame_ctx->frame, 0); if (ret < 0) { @@ -1730,7 +1750,7 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) int override_dimensions = 1; int ret; - av_assert0(av_codec_is_decoder(avctx->codec)); + av_assert0(ff_codec_is_decoder(avctx->codec)); if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { if ((unsigned)avctx->width > INT_MAX - STRIDE_ALIGN || @@ -1769,7 +1789,9 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) } } else { avctx->sw_pix_fmt = avctx->pix_fmt; - update_frame_props(avctx, frame); + ret = update_frame_props(avctx, frame); + if (ret < 0) + goto fail; } ret = avctx->get_buffer2(avctx, frame, flags); @@ -1865,11 +1887,11 @@ static void check_progress_consistency(const ProgressFrame *f) int ff_progress_frame_alloc(AVCodecContext *avctx, ProgressFrame *f) { - FFRefStructPool *pool = avctx->internal->progress_frame_pool; + AVRefStructPool *pool = avctx->internal->progress_frame_pool; av_assert1(!f->f && !f->progress); - f->progress = ff_refstruct_pool_get(pool); + f->progress = av_refstruct_pool_get(pool); if (!f->progress) return AVERROR(ENOMEM); @@ -1879,19 +1901,14 @@ int ff_progress_frame_alloc(AVCodecContext *avctx, ProgressFrame *f) int ff_progress_frame_get_buffer(AVCodecContext *avctx, ProgressFrame *f, int flags) { - int ret; - - check_progress_consistency(f); - if (!f->f) { - ret = ff_progress_frame_alloc(avctx, f); - if (ret < 0) - return ret; - } + int ret = ff_progress_frame_alloc(avctx, f); + if (ret < 0) + return ret; ret = ff_thread_get_buffer(avctx, f->progress->f, flags); if (ret < 0) { f->f = NULL; - ff_refstruct_unref(&f->progress); + av_refstruct_unref(&f->progress); return ret; } return 0; @@ -1902,14 +1919,14 @@ void ff_progress_frame_ref(ProgressFrame *dst, const ProgressFrame *src) av_assert1(src->progress && src->f && src->f == src->progress->f); av_assert1(!dst->f && !dst->progress); dst->f = src->f; - dst->progress = ff_refstruct_ref(src->progress); + dst->progress = av_refstruct_ref(src->progress); } void ff_progress_frame_unref(ProgressFrame *f) { check_progress_consistency(f); f->f = NULL; - ff_refstruct_unref(&f->progress); + av_refstruct_unref(&f->progress); } void ff_progress_frame_replace(ProgressFrame *dst, const ProgressFrame *src) @@ -1939,7 +1956,7 @@ enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) } #endif /* !HAVE_THREADS */ -static av_cold int progress_frame_pool_init_cb(FFRefStructOpaque opaque, void *obj) +static av_cold int progress_frame_pool_init_cb(AVRefStructOpaque opaque, void *obj) { const AVCodecContext *avctx = opaque.nc; ProgressInternal *progress = obj; @@ -1956,7 +1973,7 @@ static av_cold int progress_frame_pool_init_cb(FFRefStructOpaque opaque, void *o return 0; } -static void progress_frame_pool_reset_cb(FFRefStructOpaque unused, void *obj) +static void progress_frame_pool_reset_cb(AVRefStructOpaque unused, void *obj) { ProgressInternal *progress = obj; @@ -1964,7 +1981,7 @@ static void progress_frame_pool_reset_cb(FFRefStructOpaque unused, void *obj) av_frame_unref(progress->f); } -static av_cold void progress_frame_pool_free_entry_cb(FFRefStructOpaque opaque, void *obj) +static av_cold void progress_frame_pool_free_entry_cb(AVRefStructOpaque opaque, void *obj) { ProgressInternal *progress = obj; @@ -1972,7 +1989,7 @@ static av_cold void progress_frame_pool_free_entry_cb(FFRefStructOpaque opaque, av_frame_free(&progress->f); } -int ff_decode_preinit(AVCodecContext *avctx) +av_cold int ff_decode_preinit(AVCodecContext *avctx) { AVCodecInternal *avci = avctx->internal; DecodeContext *dc = decode_ctx(avci); @@ -2079,8 +2096,8 @@ int ff_decode_preinit(AVCodecContext *avctx) if (ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_USES_PROGRESSFRAMES) { avci->progress_frame_pool = - ff_refstruct_pool_alloc_ext(sizeof(ProgressInternal), - FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, + av_refstruct_pool_alloc_ext(sizeof(ProgressInternal), + AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, avctx, progress_frame_pool_init_cb, progress_frame_pool_reset_cb, progress_frame_pool_free_entry_cb, NULL); @@ -2094,18 +2111,13 @@ int ff_decode_preinit(AVCodecContext *avctx) if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS)) { if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { #if CONFIG_LIBLCEVC_DEC - ret = ff_lcevc_alloc(&dc->lcevc.ctx); + ret = ff_lcevc_alloc(&dc->lcevc.ctx, avctx); if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) return ret; #endif } } -#if FF_API_DROPCHANGED - if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED) - av_log(avctx, AV_LOG_WARNING, "The dropchanged flag is deprecated.\n"); -#endif - return 0; } @@ -2279,7 +2291,7 @@ int ff_copy_palette(void *dst, const AVPacket *src, void *logctx) return 1; } else if (pal) { av_log(logctx, AV_LOG_ERROR, - "Palette size %"SIZE_SPECIFIER" is wrong\n", size); + "Palette size %zu is wrong\n", size); } return 0; } @@ -2300,11 +2312,11 @@ int ff_hwaccel_frame_priv_alloc(AVCodecContext *avctx, void **hwaccel_picture_pr return AVERROR(EINVAL); frames_ctx = (AVHWFramesContext *) avctx->hw_frames_ctx->data; - *hwaccel_picture_private = ff_refstruct_alloc_ext(hwaccel->frame_priv_data_size, 0, + *hwaccel_picture_private = av_refstruct_alloc_ext(hwaccel->frame_priv_data_size, 0, frames_ctx->device_ctx, hwaccel->free_frame_priv); } else { - *hwaccel_picture_private = ff_refstruct_allocz(hwaccel->frame_priv_data_size); + *hwaccel_picture_private = av_refstruct_allocz(hwaccel->frame_priv_data_size); } if (!*hwaccel_picture_private) @@ -2313,7 +2325,7 @@ int ff_hwaccel_frame_priv_alloc(AVCodecContext *avctx, void **hwaccel_picture_pr return 0; } -void ff_decode_flush_buffers(AVCodecContext *avctx) +av_cold void ff_decode_flush_buffers(AVCodecContext *avctx) { AVCodecInternal *avci = avctx->internal; DecodeContext *dc = decode_ctx(avci); @@ -2331,29 +2343,133 @@ void ff_decode_flush_buffers(AVCodecContext *avctx) dc->draining_started = 0; } -AVCodecInternal *ff_decode_internal_alloc(void) +av_cold AVCodecInternal *ff_decode_internal_alloc(void) { return av_mallocz(sizeof(DecodeContext)); } -void ff_decode_internal_sync(AVCodecContext *dst, const AVCodecContext *src) +av_cold void ff_decode_internal_sync(AVCodecContext *dst, const AVCodecContext *src) { const DecodeContext *src_dc = decode_ctx(src->internal); DecodeContext *dst_dc = decode_ctx(dst->internal); dst_dc->initial_pict_type = src_dc->initial_pict_type; dst_dc->intra_only_flag = src_dc->intra_only_flag; + dst_dc->side_data_pref_mask = src_dc->side_data_pref_mask; #if CONFIG_LIBLCEVC_DEC - ff_refstruct_replace(&dst_dc->lcevc.ctx, src_dc->lcevc.ctx); + av_refstruct_replace(&dst_dc->lcevc.ctx, src_dc->lcevc.ctx); + dst_dc->lcevc.width = src_dc->lcevc.width; + dst_dc->lcevc.height = src_dc->lcevc.height; #endif } -void ff_decode_internal_uninit(AVCodecContext *avctx) +av_cold void ff_decode_internal_uninit(AVCodecContext *avctx) { #if CONFIG_LIBLCEVC_DEC AVCodecInternal *avci = avctx->internal; DecodeContext *dc = decode_ctx(avci); - ff_refstruct_unref(&dc->lcevc.ctx); + av_refstruct_unref(&dc->lcevc.ctx); #endif } + +static int attach_displaymatrix(AVCodecContext *avctx, AVFrame *frame, int orientation) +{ + AVFrameSideData *sd = NULL; + int32_t *matrix; + int ret; + /* invalid orientation */ + if (orientation < 1 || orientation > 8) + return AVERROR_INVALIDDATA; + ret = ff_frame_new_side_data(avctx, frame, AV_FRAME_DATA_DISPLAYMATRIX, sizeof(int32_t) * 9, &sd); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not allocate frame side data: %s\n", av_err2str(ret)); + return ret; + } + if (sd) { + matrix = (int32_t *) sd->data; + ret = av_exif_orientation_to_matrix(matrix, orientation); + } + + return ret; +} + +static int exif_attach_ifd(AVCodecContext *avctx, AVFrame *frame, const AVExifMetadata *ifd, AVBufferRef **pbuf) +{ + const AVExifEntry *orient = NULL; + AVExifMetadata *cloned = NULL; + int ret; + + for (size_t i = 0; i < ifd->count; i++) { + const AVExifEntry *entry = &ifd->entries[i]; + if (entry->id == av_exif_get_tag_id("Orientation") && + entry->count > 0 && entry->type == AV_TIFF_SHORT) { + orient = entry; + break; + } + } + + if (orient) { + av_log(avctx, AV_LOG_DEBUG, "found EXIF orientation: %" PRIu64 "\n", orient->value.uint[0]); + ret = attach_displaymatrix(avctx, frame, orient->value.uint[0]); + if (ret < 0) { + av_log(avctx, AV_LOG_WARNING, "unable to attach displaymatrix from EXIF\n"); + } else { + cloned = av_exif_clone_ifd(ifd); + if (!cloned) { + ret = AVERROR(ENOMEM); + goto end; + } + av_exif_remove_entry(avctx, cloned, orient->id, 0); + ifd = cloned; + } + } + + ret = av_exif_ifd_to_dict(avctx, ifd, &frame->metadata); + if (ret < 0) + goto end; + + if (cloned || !*pbuf) { + av_buffer_unref(pbuf); + ret = av_exif_write(avctx, ifd, pbuf, AV_EXIF_TIFF_HEADER); + if (ret < 0) + goto end; + } + + ret = ff_frame_new_side_data_from_buf(avctx, frame, AV_FRAME_DATA_EXIF, pbuf); + if (ret < 0) + goto end; + + ret = 0; + +end: + av_buffer_unref(pbuf); + av_exif_free(cloned); + av_free(cloned); + return ret; +} + +int ff_decode_exif_attach_ifd(AVCodecContext *avctx, AVFrame *frame, const AVExifMetadata *ifd) +{ + AVBufferRef *dummy = NULL; + return exif_attach_ifd(avctx, frame, ifd, &dummy); +} + +int ff_decode_exif_attach_buffer(AVCodecContext *avctx, AVFrame *frame, AVBufferRef **pbuf, + enum AVExifHeaderMode header_mode) +{ + int ret; + AVBufferRef *data = *pbuf; + AVExifMetadata ifd = { 0 }; + + ret = av_exif_parse_buffer(avctx, data->data, data->size, &ifd, header_mode); + if (ret < 0) + goto end; + + ret = exif_attach_ifd(avctx, frame, &ifd, pbuf); + +end: + av_buffer_unref(pbuf); + av_exif_free(&ifd); + return ret; +} diff --git a/libavcodec/decode.h b/libavcodec/decode.h index 6cafb48cd..e4a250e7b 100644 --- a/libavcodec/decode.h +++ b/libavcodec/decode.h @@ -224,4 +224,34 @@ int ff_decode_content_light_new(const AVCodecContext *avctx, AVFrame *frame, int ff_decode_content_light_new_ext(const AVCodecContext *avctx, AVFrameSideData ***sd, int *nb_sd, struct AVContentLightMetadata **clm); + +enum AVExifHeaderMode; + +/** + * Attach the data buffer to the frame. This is mostly a wrapper for + * av_side_data_new_from_buffer, but it checks if the orientation tag is + * present in the provided EXIF buffer. If it is, it zeroes it out and + * attaches that information as an AV_FRAME_DATA_DISPLAYMATRIX instead + * of including it in the AV_FRAME_DATA_EXIF side data buffer. + * + * *buf is ALWAYS consumed by this function and NULL written in its place, even + * on failure. + */ +int ff_decode_exif_attach_buffer(AVCodecContext *avctx, AVFrame *frame, AVBufferRef **buf, + enum AVExifHeaderMode header_mode); + +struct AVExifMetadata; + +/** + * Attach an already-parsed EXIF metadata struct to the frame as a side data + * buffer. It writes the EXIF IFD into the buffer and attaches the buffer to + * the frame. + * + * If the metadata struct contains an orientation tag, it will be zeroed before + * writing, and instead, an AV_FRAME_DATA_DISPLAYMATRIX will be attached in + * addition to the AV_FRAME_DATA_EXIF side data. + */ +int ff_decode_exif_attach_ifd(AVCodecContext *avctx, AVFrame *frame, + const struct AVExifMetadata *ifd); + #endif /* AVCODEC_DECODE_H */ diff --git a/libavcodec/decode_bsf.h b/libavcodec/decode_bsf.h new file mode 100644 index 000000000..9ea9ab70c --- /dev/null +++ b/libavcodec/decode_bsf.h @@ -0,0 +1,42 @@ +/* + * 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_DECODE_BSF_H +#define AVCODEC_DECODE_BSF_H + +#include + +#include "avcodec.h" +#include "bsf.h" +#include "internal.h" + +/** + * Helper function for decoders that may use a BSF that changes extradata. + * This function will get the extradata from the BSF. + */ +static inline void ff_decode_get_extradata(const AVCodecContext *avctx, + const uint8_t **extradata, + int *extradata_size) +{ + // Given that we unconditionally insert a null BSF when no BSF is + // explicitly requested, we can just use the BSF's par_out here. + *extradata = avctx->internal->bsf->par_out->extradata; + *extradata_size = avctx->internal->bsf->par_out->extradata_size; +} + +#endif /* AVCODEC_DECODE_BSF_H */ diff --git a/libavcodec/defs.h b/libavcodec/defs.h index 24250f8af..b13e983b1 100644 --- a/libavcodec/defs.h +++ b/libavcodec/defs.h @@ -185,6 +185,9 @@ #define AV_PROFILE_PRORES_4444 4 #define AV_PROFILE_PRORES_XQ 5 +#define AV_PROFILE_PRORES_RAW 0 +#define AV_PROFILE_PRORES_RAW_HQ 1 + #define AV_PROFILE_ARIB_PROFILE_A 0 #define AV_PROFILE_ARIB_PROFILE_C 1 @@ -194,6 +197,14 @@ #define AV_PROFILE_EVC_BASELINE 0 #define AV_PROFILE_EVC_MAIN 1 +#define AV_PROFILE_APV_422_10 33 +#define AV_PROFILE_APV_422_12 44 +#define AV_PROFILE_APV_444_10 55 +#define AV_PROFILE_APV_444_12 66 +#define AV_PROFILE_APV_4444_10 77 +#define AV_PROFILE_APV_4444_12 88 +#define AV_PROFILE_APV_400_10 99 + #define AV_LEVEL_UNKNOWN -99 @@ -325,6 +336,20 @@ typedef struct AVProducerReferenceTime { int flags; } AVProducerReferenceTime; +/** + * RTCP SR (Sender Report) information + * + * The received sender report information for an RTSP + * stream, exposed as AV_PKT_DATA_RTCP_SR side data. + */ +typedef struct AVRTCPSenderReport { + uint32_t ssrc; ///< Synchronization source identifier + uint64_t ntp_timestamp; ///< NTP time when the report was sent + uint32_t rtp_timestamp; ///< RTP time when the report was sent + uint32_t sender_nb_packets; ///< Total number of packets sent + uint32_t sender_nb_bytes; ///< Total number of bytes sent (excluding headers or padding) +} AVRTCPSenderReport; + /** * Encode extradata length to a buffer. Used by xiph codecs. * diff --git a/libavcodec/dfa.c b/libavcodec/dfa.c index 9114feb0b..1efaefcb6 100644 --- a/libavcodec/dfa.c +++ b/libavcodec/dfa.c @@ -367,11 +367,6 @@ static int dfa_decode_frame(AVCodecContext *avctx, AVFrame *frame, s->pal[i] = bytestream2_get_be24(&gb) << 2; s->pal[i] |= 0xFFU << 24 | (s->pal[i] >> 6) & 0x30303; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } else if (chunk_type <= 9) { if (decoder[chunk_type - 2](&gb, s->frame_buf, avctx->width, avctx->height)) { av_log(avctx, AV_LOG_ERROR, "Error decoding %s chunk\n", diff --git a/libavcodec/dfpwmenc.c b/libavcodec/dfpwmenc.c index 5318b04a3..1adc4c754 100644 --- a/libavcodec/dfpwmenc.c +++ b/libavcodec/dfpwmenc.c @@ -25,14 +25,14 @@ * DFPWM1a encoder */ -#include "libavutil/internal.h" #include "avcodec.h" #include "codec_id.h" #include "codec_internal.h" #include "encode.h" +#include "internal.h" typedef struct { - int fq, q, s, lt; + int q, s, lt; } DFPWMState; // DFPWM codec from https://github.com/ChenThread/dfpwm/blob/master/1a/ @@ -79,12 +79,15 @@ static av_cold int dfpwm_enc_init(struct AVCodecContext *ctx) { DFPWMState *state = ctx->priv_data; - state->fq = 0; state->q = 0; state->s = 0; state->lt = -128; ctx->bits_per_coded_sample = 1; + // Pad so that nb_samples * nb_channels is always a multiple of eight. + ctx->internal->pad_samples = (const uint8_t[]){ 1, 8, 4, 8, 2, 8, 4, 8 }[ctx->ch_layout.nb_channels & 7]; + if (ctx->frame_size <= 0 || ctx->frame_size * ctx->ch_layout.nb_channels % 8U) + ctx->frame_size = 4096; return 0; } @@ -93,7 +96,7 @@ static int dfpwm_enc_frame(struct AVCodecContext *ctx, struct AVPacket *packet, const struct AVFrame *frame, int *got_packet) { DFPWMState *state = ctx->priv_data; - int size = frame->nb_samples * frame->ch_layout.nb_channels / 8 + (frame->nb_samples % 8 > 0 ? 1 : 0); + int size = frame->nb_samples * frame->ch_layout.nb_channels / 8U; int ret = ff_get_encode_buffer(ctx, packet, size, 0); if (ret) { @@ -112,10 +115,9 @@ const FFCodec ff_dfpwm_encoder = { CODEC_LONG_NAME("DFPWM1a audio"), .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_DFPWM, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(DFPWMState), .init = dfpwm_enc_init, FF_CODEC_ENCODE_CB(dfpwm_enc_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NONE}, - .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_VARIABLE_FRAME_SIZE | - AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8), }; diff --git a/libavcodec/dirac_dwt.c b/libavcodec/dirac_dwt.c index d473f64da..0d92ad06d 100644 --- a/libavcodec/dirac_dwt.c +++ b/libavcodec/dirac_dwt.c @@ -59,7 +59,7 @@ int ff_spatial_idwt_init(DWTContext *d, DWTPlane *p, enum dwt_type type, return AVERROR_INVALIDDATA; } -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM if (bit_depth == 8) ff_spatial_idwt_init_x86(d, type); #endif diff --git a/libavcodec/dirac_parser.c b/libavcodec/dirac_parser.c index 912f59424..d9cf44383 100644 --- a/libavcodec/dirac_parser.c +++ b/libavcodec/dirac_parser.c @@ -29,10 +29,12 @@ #include +#include "libavutil/attributes.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" -#include "parser.h" +#include "avcodec.h" +#include "parser_internal.h" #define DIRAC_PARSE_INFO_PREFIX 0x42424344 @@ -265,7 +267,7 @@ static int dirac_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -static void dirac_parse_close(AVCodecParserContext *s) +static av_cold void dirac_parse_close(AVCodecParserContext *s) { DiracParseContext *pc = s->priv_data; @@ -273,9 +275,9 @@ static void dirac_parse_close(AVCodecParserContext *s) av_freep(&pc->buffer); } -const AVCodecParser ff_dirac_parser = { - .codec_ids = { AV_CODEC_ID_DIRAC }, +const FFCodecParser ff_dirac_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_DIRAC), .priv_data_size = sizeof(DiracParseContext), - .parser_parse = dirac_parse, - .parser_close = dirac_parse_close, + .parse = dirac_parse, + .close = dirac_parse_close, }; diff --git a/libavcodec/diracdec.c b/libavcodec/diracdec.c index 76209aebb..2eabf7427 100644 --- a/libavcodec/diracdec.c +++ b/libavcodec/diracdec.c @@ -826,7 +826,7 @@ static int subband_coeffs(const DiracContext *s, int x, int y, int p, int level, coef = 0; for (level = 0; level < s->wavelet_depth; level++) { SliceCoeffs *o = &c[level]; - const SubBand *b = &s->plane[p].band[level][3]; /* orientation doens't matter */ + const SubBand *b = &s->plane[p].band[level][3]; /* orientation doesn't matter */ o->top = b->height * y / s->num_y; o->left = b->width * x / s->num_x; o->tot_h = ((b->width * (x + 1)) / s->num_x) - o->left; diff --git a/libavcodec/diracdsp.c b/libavcodec/diracdsp.c index 284f914f9..a02a23974 100644 --- a/libavcodec/diracdsp.c +++ b/libavcodec/diracdsp.c @@ -247,7 +247,7 @@ av_cold void ff_diracdsp_init(DiracDSPContext *c) PIXFUNC(avg, 16); PIXFUNC(avg, 32); -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_diracdsp_init_x86(c); #endif } diff --git a/libavcodec/dnxhd_parser.c b/libavcodec/dnxhd_parser.c index 631ac8386..3ab08d097 100644 --- a/libavcodec/dnxhd_parser.c +++ b/libavcodec/dnxhd_parser.c @@ -26,6 +26,7 @@ #include "parser.h" #include "dnxhddata.h" +#include "parser_internal.h" typedef struct { ParseContext pc; @@ -138,9 +139,9 @@ static int dnxhd_parse(AVCodecParserContext *s, return next; } -const AVCodecParser ff_dnxhd_parser = { - .codec_ids = { AV_CODEC_ID_DNXHD }, +const FFCodecParser ff_dnxhd_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_DNXHD), .priv_data_size = sizeof(DNXHDParserContext), - .parser_parse = dnxhd_parse, - .parser_close = ff_parse_close, + .parse = dnxhd_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/dnxhddec.c b/libavcodec/dnxhddec.c index fe0809a5f..7ec61f9eb 100644 --- a/libavcodec/dnxhddec.c +++ b/libavcodec/dnxhddec.c @@ -333,7 +333,7 @@ static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame, if (ctx->mb_height > FF_ARRAY_ELEMS(ctx->mb_scan_index)) { av_log(ctx->avctx, AV_LOG_ERROR, - "mb_height too big (%d > %"SIZE_SPECIFIER").\n", ctx->mb_height, FF_ARRAY_ELEMS(ctx->mb_scan_index)); + "mb_height too big (%d > %zu).\n", ctx->mb_height, FF_ARRAY_ELEMS(ctx->mb_scan_index)); return AVERROR_INVALIDDATA; } diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c index b12a2e885..844731f6c 100644 --- a/libavcodec/dnxhdenc.c +++ b/libavcodec/dnxhdenc.c @@ -38,7 +38,6 @@ #include "mpegvideo.h" #include "mpegvideoenc.h" #include "pixblockdsp.h" -#include "packet_internal.h" #include "profiles.h" #include "dnxhdenc.h" @@ -117,12 +116,12 @@ void dnxhd_10bit_get_pixels_8x4_sym(int16_t *restrict block, memcpy(block + 4 * 8, pixels + 3 * line_size, 8 * sizeof(*block)); } -static int dnxhd_10bit_dct_quantize_444(MpegEncContext *ctx, int16_t *block, +static int dnxhd_10bit_dct_quantize_444(MPVEncContext *ctx, int16_t *block, int n, int qscale, int *overflow) { int i, j, level, last_non_zero, start_i; const int *qmat; - const uint8_t *scantable= ctx->intra_scantable.scantable; + const uint8_t *scantable = ctx->c.intra_scantable.scantable; int bias; int max = 0; unsigned int threshold1, threshold2; @@ -169,17 +168,17 @@ static int dnxhd_10bit_dct_quantize_444(MpegEncContext *ctx, int16_t *block, *overflow = ctx->max_qcoeff < max; //overflow might have happened /* we need this permutation so that we correct the IDCT, we only permute the !=0 elements */ - if (ctx->idsp.perm_type != FF_IDCT_PERM_NONE) - ff_block_permute(block, ctx->idsp.idct_permutation, + if (ctx->c.idsp.perm_type != FF_IDCT_PERM_NONE) + ff_block_permute(block, ctx->c.idsp.idct_permutation, scantable, last_non_zero); return last_non_zero; } -static int dnxhd_10bit_dct_quantize(MpegEncContext *ctx, int16_t *block, +static int dnxhd_10bit_dct_quantize(MPVEncContext *ctx, int16_t *block, int n, int qscale, int *overflow) { - const uint8_t *scantable= ctx->intra_scantable.scantable; + const uint8_t *scantable = ctx->c.intra_scantable.scantable; const int *qmat = n<4 ? ctx->q_intra_matrix[qscale] : ctx->q_chroma_intra_matrix[qscale]; int last_non_zero = 0; int i; @@ -200,8 +199,8 @@ static int dnxhd_10bit_dct_quantize(MpegEncContext *ctx, int16_t *block, } /* we need this permutation so that we correct the IDCT, we only permute the !=0 elements */ - if (ctx->idsp.perm_type != FF_IDCT_PERM_NONE) - ff_block_permute(block, ctx->idsp.idct_permutation, + if (ctx->c.idsp.perm_type != FF_IDCT_PERM_NONE) + ff_block_permute(block, ctx->c.idsp.idct_permutation, scantable, last_non_zero); return last_non_zero; @@ -266,34 +265,33 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias) { // init first elem to 1 to avoid div by 0 in convert_matrix uint16_t weight_matrix[64] = { 1, }; // convert_matrix needs uint16_t* - int qscale, i; const uint8_t *luma_weight_table = ctx->cid_table->luma_weight; const uint8_t *chroma_weight_table = ctx->cid_table->chroma_weight; - if (!FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_l, ctx->m.avctx->qmax + 1) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_c, ctx->m.avctx->qmax + 1) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_l16, ctx->m.avctx->qmax + 1) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_c16, ctx->m.avctx->qmax + 1)) + if (!FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_l, ctx->m.c.avctx->qmax + 1) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_c, ctx->m.c.avctx->qmax + 1) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_l16, ctx->m.c.avctx->qmax + 1) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_c16, ctx->m.c.avctx->qmax + 1)) return AVERROR(ENOMEM); if (ctx->bit_depth == 8) { - for (i = 1; i < 64; i++) { - int j = ctx->m.idsp.idct_permutation[ff_zigzag_direct[i]]; + for (int i = 1; i < 64; i++) { + int j = ctx->m.c.idsp.idct_permutation[ff_zigzag_direct[i]]; weight_matrix[j] = ctx->cid_table->luma_weight[i]; } ff_convert_matrix(&ctx->m, ctx->qmatrix_l, ctx->qmatrix_l16, weight_matrix, ctx->intra_quant_bias, 1, - ctx->m.avctx->qmax, 1); - for (i = 1; i < 64; i++) { - int j = ctx->m.idsp.idct_permutation[ff_zigzag_direct[i]]; + ctx->m.c.avctx->qmax, 1); + for (int i = 1; i < 64; i++) { + int j = ctx->m.c.idsp.idct_permutation[ff_zigzag_direct[i]]; weight_matrix[j] = ctx->cid_table->chroma_weight[i]; } ff_convert_matrix(&ctx->m, ctx->qmatrix_c, ctx->qmatrix_c16, weight_matrix, ctx->intra_quant_bias, 1, - ctx->m.avctx->qmax, 1); + ctx->m.c.avctx->qmax, 1); - for (qscale = 1; qscale <= ctx->m.avctx->qmax; qscale++) { - for (i = 0; i < 64; i++) { + for (int qscale = 1; qscale <= ctx->m.c.avctx->qmax; qscale++) { + for (int i = 0; i < 64; i++) { ctx->qmatrix_l[qscale][i] <<= 2; ctx->qmatrix_c[qscale][i] <<= 2; ctx->qmatrix_l16[qscale][0][i] <<= 2; @@ -304,8 +302,8 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias) } } else { // 10-bit - for (qscale = 1; qscale <= ctx->m.avctx->qmax; qscale++) { - for (i = 1; i < 64; i++) { + for (int qscale = 1; qscale <= ctx->m.c.avctx->qmax; qscale++) { + for (int i = 1; i < 64; i++) { int j = ff_zigzag_direct[i]; /* The quantization formula from the VC-3 standard is: @@ -337,12 +335,12 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias) static av_cold int dnxhd_init_rc(DNXHDEncContext *ctx) { - if (!FF_ALLOCZ_TYPED_ARRAY(ctx->mb_rc, (ctx->m.avctx->qmax + 1) * ctx->m.mb_num)) + if (!FF_ALLOCZ_TYPED_ARRAY(ctx->mb_rc, (ctx->m.c.avctx->qmax + 1) * ctx->m.c.mb_num)) return AVERROR(ENOMEM); - if (ctx->m.avctx->mb_decision != FF_MB_DECISION_RD) { - if (!FF_ALLOCZ_TYPED_ARRAY(ctx->mb_cmp, ctx->m.mb_num) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_cmp_tmp, ctx->m.mb_num)) + if (ctx->m.c.avctx->mb_decision != FF_MB_DECISION_RD) { + if (!FF_ALLOCZ_TYPED_ARRAY(ctx->mb_cmp, ctx->m.c.mb_num) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_cmp_tmp, ctx->m.c.mb_num)) return AVERROR(ENOMEM); } ctx->frame_bits = (ctx->coding_unit_size - @@ -414,21 +412,21 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) ctx->cid_table = ff_dnxhd_get_cid_table(ctx->cid); av_assert0(ctx->cid_table); - ctx->m.avctx = avctx; - ctx->m.mb_intra = 1; - ctx->m.h263_aic = 1; + ctx->m.c.avctx = avctx; + ctx->m.c.mb_intra = 1; + ctx->m.c.h263_aic = 1; avctx->bits_per_raw_sample = ctx->bit_depth; - ff_blockdsp_init(&ctx->m.bdsp); + ff_blockdsp_init(&ctx->m.c.bdsp); ff_fdctdsp_init(&ctx->m.fdsp, avctx); - ff_mpv_idct_init(&ctx->m); + ff_mpv_idct_init(&ctx->m.c); ff_mpegvideoencdsp_init(&ctx->m.mpvencdsp, avctx); - ff_pixblockdsp_init(&ctx->m.pdsp, avctx); + ff_pixblockdsp_init(&ctx->m.pdsp, ctx->bit_depth); ff_dct_encode_init(&ctx->m); if (ctx->profile != AV_PROFILE_DNXHD) - ff_videodsp_init(&ctx->m.vdsp, ctx->bit_depth); + ff_videodsp_init(&ctx->m.c.vdsp, ctx->bit_depth); if (ctx->is_444 || ctx->profile == AV_PROFILE_DNXHR_HQX) { ctx->m.dct_quantize = dnxhd_10bit_dct_quantize_444; @@ -445,12 +443,12 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) ff_dnxhdenc_init(ctx); - ctx->m.mb_height = (avctx->height + 15) / 16; - ctx->m.mb_width = (avctx->width + 15) / 16; + ctx->m.c.mb_height = (avctx->height + 15) / 16; + ctx->m.c.mb_width = (avctx->width + 15) / 16; if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) { ctx->interlaced = 1; - ctx->m.mb_height /= 2; + ctx->m.c.mb_height /= 2; } if (ctx->interlaced && ctx->profile != AV_PROFILE_DNXHD) { @@ -459,7 +457,7 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - ctx->m.mb_num = ctx->m.mb_height * ctx->m.mb_width; + ctx->m.c.mb_num = ctx->m.c.mb_height * ctx->m.c.mb_width; if (ctx->cid_table->frame_size == DNXHD_VARIABLE) { ctx->frame_size = ff_dnxhd_get_hr_frame_size(ctx->cid, @@ -471,8 +469,8 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) ctx->coding_unit_size = ctx->cid_table->coding_unit_size; } - if (ctx->m.mb_height > 68) - ctx->data_offset = 0x170 + (ctx->m.mb_height << 2); + if (ctx->m.c.mb_height > 68) + ctx->data_offset = 0x170 + (ctx->m.c.mb_height << 2); else ctx->data_offset = 0x280; @@ -490,10 +488,10 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) if ((ret = dnxhd_init_rc(ctx)) < 0) return ret; - if (!FF_ALLOCZ_TYPED_ARRAY(ctx->slice_size, ctx->m.mb_height) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->slice_offs, ctx->m.mb_height) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_bits, ctx->m.mb_num) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_qscale, ctx->m.mb_num)) + if (!FF_ALLOCZ_TYPED_ARRAY(ctx->slice_size, ctx->m.c.mb_height) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->slice_offs, ctx->m.c.mb_height) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_bits, ctx->m.c.mb_num) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_qscale, ctx->m.c.mb_num)) return AVERROR(ENOMEM); if (avctx->active_thread_type == FF_THREAD_SLICE) { @@ -548,8 +546,8 @@ static int dnxhd_write_header(AVCodecContext *avctx, uint8_t *buf) buf[0x5f] = 0x01; // UDL buf[0x167] = 0x02; // reserved - AV_WB16(buf + 0x16a, ctx->m.mb_height * 4 + 4); // MSIPS - AV_WB16(buf + 0x16c, ctx->m.mb_height); // Ns + AV_WB16(buf + 0x16a, ctx->m.c.mb_height * 4 + 4); // MSIPS + AV_WB16(buf + 0x16c, ctx->m.c.mb_height); // Ns buf[0x16f] = 0x10; // reserved ctx->msip = buf + 0x170; @@ -581,7 +579,7 @@ void dnxhd_encode_block(PutBitContext *pb, DNXHDEncContext *ctx, ctx->m.last_dc[n] = block[0]; for (i = 1; i <= last_index; i++) { - j = ctx->m.intra_scantable.permutated[i]; + j = ctx->m.c.intra_scantable.permutated[i]; slevel = block[j]; if (slevel) { int run_level = i - last_non_zero - 1; @@ -613,7 +611,7 @@ void dnxhd_unquantize_c(DNXHDEncContext *ctx, int16_t *block, int n, } for (i = 1; i <= last_index; i++) { - int j = ctx->m.intra_scantable.permutated[i]; + int j = ctx->m.c.intra_scantable.permutated[i]; level = block[j]; if (level) { if (level < 0) { @@ -661,7 +659,7 @@ int dnxhd_calc_ac_bits(DNXHDEncContext *ctx, int16_t *block, int last_index) int bits = 0; int i, j, level; for (i = 1; i <= last_index; i++) { - j = ctx->m.intra_scantable.permutated[i]; + j = ctx->m.c.intra_scantable.permutated[i]; level = block[j]; if (level) { int run_level = i - last_non_zero - 1; @@ -680,36 +678,36 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) const int bw = 1 << bs; int dct_y_offset = ctx->dct_y_offset; int dct_uv_offset = ctx->dct_uv_offset; - int linesize = ctx->m.linesize; - int uvlinesize = ctx->m.uvlinesize; + int linesize = ctx->m.c.linesize; + int uvlinesize = ctx->m.c.uvlinesize; const uint8_t *ptr_y = ctx->thread[0]->src[0] + - ((mb_y << 4) * ctx->m.linesize) + (mb_x << bs + 1); + ((mb_y << 4) * ctx->m.c.linesize) + (mb_x << bs + 1); const uint8_t *ptr_u = ctx->thread[0]->src[1] + - ((mb_y << 4) * ctx->m.uvlinesize) + (mb_x << bs + ctx->is_444); + ((mb_y << 4) * ctx->m.c.uvlinesize) + (mb_x << bs + ctx->is_444); const uint8_t *ptr_v = ctx->thread[0]->src[2] + - ((mb_y << 4) * ctx->m.uvlinesize) + (mb_x << bs + ctx->is_444); + ((mb_y << 4) * ctx->m.c.uvlinesize) + (mb_x << bs + ctx->is_444); PixblockDSPContext *pdsp = &ctx->m.pdsp; - VideoDSPContext *vdsp = &ctx->m.vdsp; + VideoDSPContext *vdsp = &ctx->m.c.vdsp; - if (ctx->bit_depth != 10 && vdsp->emulated_edge_mc && ((mb_x << 4) + 16 > ctx->m.avctx->width || - (mb_y << 4) + 16 > ctx->m.avctx->height)) { - int y_w = ctx->m.avctx->width - (mb_x << 4); - int y_h = ctx->m.avctx->height - (mb_y << 4); + if (ctx->bit_depth != 10 && vdsp->emulated_edge_mc && ((mb_x << 4) + 16 > ctx->m.c.avctx->width || + (mb_y << 4) + 16 > ctx->m.c.avctx->height)) { + int y_w = ctx->m.c.avctx->width - (mb_x << 4); + int y_h = ctx->m.c.avctx->height - (mb_y << 4); int uv_w = (y_w + 1) / 2; int uv_h = y_h; linesize = 16; uvlinesize = 8; vdsp->emulated_edge_mc(&ctx->edge_buf_y[0], ptr_y, - linesize, ctx->m.linesize, + linesize, ctx->m.c.linesize, linesize, 16, 0, 0, y_w, y_h); vdsp->emulated_edge_mc(&ctx->edge_buf_uv[0][0], ptr_u, - uvlinesize, ctx->m.uvlinesize, + uvlinesize, ctx->m.c.uvlinesize, uvlinesize, 16, 0, 0, uv_w, uv_h); vdsp->emulated_edge_mc(&ctx->edge_buf_uv[1][0], ptr_v, - uvlinesize, ctx->m.uvlinesize, + uvlinesize, ctx->m.c.uvlinesize, uvlinesize, 16, 0, 0, uv_w, uv_h); @@ -718,25 +716,25 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) ptr_y = &ctx->edge_buf_y[0]; ptr_u = &ctx->edge_buf_uv[0][0]; ptr_v = &ctx->edge_buf_uv[1][0]; - } else if (ctx->bit_depth == 10 && vdsp->emulated_edge_mc && ((mb_x << 4) + 16 > ctx->m.avctx->width || - (mb_y << 4) + 16 > ctx->m.avctx->height)) { - int y_w = ctx->m.avctx->width - (mb_x << 4); - int y_h = ctx->m.avctx->height - (mb_y << 4); + } else if (ctx->bit_depth == 10 && vdsp->emulated_edge_mc && ((mb_x << 4) + 16 > ctx->m.c.avctx->width || + (mb_y << 4) + 16 > ctx->m.c.avctx->height)) { + int y_w = ctx->m.c.avctx->width - (mb_x << 4); + int y_h = ctx->m.c.avctx->height - (mb_y << 4); int uv_w = ctx->is_444 ? y_w : (y_w + 1) / 2; int uv_h = y_h; linesize = 32; uvlinesize = 16 + 16 * ctx->is_444; vdsp->emulated_edge_mc(&ctx->edge_buf_y[0], ptr_y, - linesize, ctx->m.linesize, + linesize, ctx->m.c.linesize, linesize / 2, 16, 0, 0, y_w, y_h); vdsp->emulated_edge_mc(&ctx->edge_buf_uv[0][0], ptr_u, - uvlinesize, ctx->m.uvlinesize, + uvlinesize, ctx->m.c.uvlinesize, uvlinesize / 2, 16, 0, 0, uv_w, uv_h); vdsp->emulated_edge_mc(&ctx->edge_buf_uv[1][0], ptr_v, - uvlinesize, ctx->m.uvlinesize, + uvlinesize, ctx->m.c.uvlinesize, uvlinesize / 2, 16, 0, 0, uv_w, uv_h); @@ -753,7 +751,7 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) pdsp->get_pixels(ctx->blocks[2], ptr_u, uvlinesize); pdsp->get_pixels(ctx->blocks[3], ptr_v, uvlinesize); - if (mb_y + 1 == ctx->m.mb_height && ctx->m.avctx->height == 1080) { + if (mb_y + 1 == ctx->m.c.mb_height && ctx->m.c.avctx->height == 1080) { if (ctx->interlaced) { ctx->get_pixels_8x4_sym(ctx->blocks[4], ptr_y + dct_y_offset, @@ -768,10 +766,10 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) ptr_v + dct_uv_offset, uvlinesize); } else { - ctx->m.bdsp.clear_block(ctx->blocks[4]); - ctx->m.bdsp.clear_block(ctx->blocks[5]); - ctx->m.bdsp.clear_block(ctx->blocks[6]); - ctx->m.bdsp.clear_block(ctx->blocks[7]); + ctx->m.c.bdsp.clear_block(ctx->blocks[4]); + ctx->m.c.bdsp.clear_block(ctx->blocks[5]); + ctx->m.c.bdsp.clear_block(ctx->blocks[6]); + ctx->m.c.bdsp.clear_block(ctx->blocks[7]); } } else { pdsp->get_pixels(ctx->blocks[4], @@ -819,7 +817,7 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, int jobnr, int threadnr) { DNXHDEncContext *ctx = avctx->priv_data; - int mb_y = jobnr, mb_x; + int mb_y = jobnr; int qscale = ctx->qscale; LOCAL_ALIGNED_16(int16_t, block, [64]); ctx = ctx->thread[threadnr]; @@ -828,8 +826,8 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, ctx->m.last_dc[1] = ctx->m.last_dc[2] = 1 << (ctx->bit_depth + 2); - for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { - unsigned mb = mb_y * ctx->m.mb_width + mb_x; + for (int mb_x = 0; mb_x < ctx->m.c.mb_width; mb_x++) { + unsigned mb = mb_y * ctx->m.c.mb_width + mb_x; int ssd = 0; int ac_bits = 0; int dc_bits = 0; @@ -861,12 +859,12 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, if (avctx->mb_decision == FF_MB_DECISION_RD || !RC_VARIANCE) { dnxhd_unquantize_c(ctx, block, i, qscale, last_index); - ctx->m.idsp.idct(block); + ctx->m.c.idsp.idct(block); ssd += dnxhd_ssd_block(block, src_block); } } - ctx->mb_rc[(qscale * ctx->m.mb_num) + mb].ssd = ssd; - ctx->mb_rc[(qscale * ctx->m.mb_num) + mb].bits = ac_bits + dc_bits + 12 + + ctx->mb_rc[(qscale * ctx->m.c.mb_num) + mb].ssd = ssd; + ctx->mb_rc[(qscale * ctx->m.c.mb_num) + mb].bits = ac_bits + dc_bits + 12 + (1 + ctx->is_444) * 8 * ctx->vlc_bits[0]; } return 0; @@ -877,7 +875,7 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg, { DNXHDEncContext *ctx = avctx->priv_data; PutBitContext pb0, *const pb = &pb0; - int mb_y = jobnr, mb_x; + int mb_y = jobnr; ctx = ctx->thread[threadnr]; init_put_bits(pb, (uint8_t *)arg + ctx->data_offset + ctx->slice_offs[jobnr], ctx->slice_size[jobnr]); @@ -885,8 +883,8 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg, ctx->m.last_dc[0] = ctx->m.last_dc[1] = ctx->m.last_dc[2] = 1 << (ctx->bit_depth + 2); - for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { - unsigned mb = mb_y * ctx->m.mb_width + mb_x; + for (int mb_x = 0; mb_x < ctx->m.c.mb_width; mb_x++) { + unsigned mb = mb_y * ctx->m.c.mb_width + mb_x; int qscale = ctx->mb_qscale[mb]; int i; @@ -912,14 +910,12 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg, static void dnxhd_setup_threads_slices(DNXHDEncContext *ctx) { - int mb_y, mb_x; - int offset = 0; - for (mb_y = 0; mb_y < ctx->m.mb_height; mb_y++) { + for (int mb_y = 0, offset = 0; mb_y < ctx->m.c.mb_height; mb_y++) { int thread_size; ctx->slice_offs[mb_y] = offset; ctx->slice_size[mb_y] = 0; - for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { - unsigned mb = mb_y * ctx->m.mb_width + mb_x; + for (int mb_x = 0; mb_x < ctx->m.c.mb_width; mb_x++) { + unsigned mb = mb_y * ctx->m.c.mb_width + mb_x; ctx->slice_size[mb_y] += ctx->mb_bits[mb]; } ctx->slice_size[mb_y] = (ctx->slice_size[mb_y] + 31U) & ~31U; @@ -933,28 +929,28 @@ static int dnxhd_mb_var_thread(AVCodecContext *avctx, void *arg, int jobnr, int threadnr) { DNXHDEncContext *ctx = avctx->priv_data; - int mb_y = jobnr, mb_x, x, y; - int partial_last_row = (mb_y == ctx->m.mb_height - 1) && + int mb_y = jobnr, x, y; + int partial_last_row = (mb_y == ctx->m.c.mb_height - 1) && ((avctx->height >> ctx->interlaced) & 0xF); ctx = ctx->thread[threadnr]; if (ctx->bit_depth == 8) { - const uint8_t *pix = ctx->thread[0]->src[0] + ((mb_y << 4) * ctx->m.linesize); - for (mb_x = 0; mb_x < ctx->m.mb_width; ++mb_x, pix += 16) { - unsigned mb = mb_y * ctx->m.mb_width + mb_x; + const uint8_t *pix = ctx->thread[0]->src[0] + ((mb_y << 4) * ctx->m.c.linesize); + for (int mb_x = 0; mb_x < ctx->m.c.mb_width; ++mb_x, pix += 16) { + unsigned mb = mb_y * ctx->m.c.mb_width + mb_x; int sum; int varc; if (!partial_last_row && mb_x * 16 <= avctx->width - 16 && (avctx->width % 16) == 0) { - sum = ctx->m.mpvencdsp.pix_sum(pix, ctx->m.linesize); - varc = ctx->m.mpvencdsp.pix_norm1(pix, ctx->m.linesize); + sum = ctx->m.mpvencdsp.pix_sum(pix, ctx->m.c.linesize); + varc = ctx->m.mpvencdsp.pix_norm1(pix, ctx->m.c.linesize); } else { int bw = FFMIN(avctx->width - 16 * mb_x, 16); int bh = FFMIN((avctx->height >> ctx->interlaced) - 16 * mb_y, 16); sum = varc = 0; for (y = 0; y < bh; y++) { for (x = 0; x < bw; x++) { - uint8_t val = pix[x + y * ctx->m.linesize]; + uint8_t val = pix[x + y * ctx->m.c.linesize]; sum += val; varc += val * val; } @@ -966,11 +962,11 @@ static int dnxhd_mb_var_thread(AVCodecContext *avctx, void *arg, ctx->mb_cmp[mb].mb = mb; } } else { // 10-bit - const int linesize = ctx->m.linesize >> 1; - for (mb_x = 0; mb_x < ctx->m.mb_width; ++mb_x) { + const int linesize = ctx->m.c.linesize >> 1; + for (int mb_x = 0; mb_x < ctx->m.c.mb_width; ++mb_x) { const uint16_t *pix = (const uint16_t *)ctx->thread[0]->src[0] + ((mb_y << 4) * linesize) + (mb_x << 4); - unsigned mb = mb_y * ctx->m.mb_width + mb_x; + unsigned mb = mb_y * ctx->m.c.mb_width + mb_x; int sum = 0; int sqsum = 0; int bw = FFMIN(avctx->width - 16 * mb_x, 16); @@ -1001,12 +997,11 @@ static int dnxhd_encode_rdo(AVCodecContext *avctx, DNXHDEncContext *ctx) { int lambda, up_step, down_step; int last_lower = INT_MAX, last_higher = 0; - int x, y, q; - for (q = 1; q < avctx->qmax; q++) { + for (int q = 1; q < avctx->qmax; q++) { ctx->qscale = q; avctx->execute2(avctx, dnxhd_calc_bits_thread, - NULL, NULL, ctx->m.mb_height); + NULL, NULL, ctx->m.c.mb_height); } up_step = down_step = 2 << LAMBDA_FRAC_BITS; lambda = ctx->lambda; @@ -1018,14 +1013,14 @@ static int dnxhd_encode_rdo(AVCodecContext *avctx, DNXHDEncContext *ctx) lambda++; end = 1; // need to set final qscales/bits } - for (y = 0; y < ctx->m.mb_height; y++) { - for (x = 0; x < ctx->m.mb_width; x++) { + for (int y = 0; y < ctx->m.c.mb_height; y++) { + for (int x = 0; x < ctx->m.c.mb_width; x++) { unsigned min = UINT_MAX; int qscale = 1; - int mb = y * ctx->m.mb_width + x; + int mb = y * ctx->m.c.mb_width + x; int rc = 0; - for (q = 1; q < avctx->qmax; q++) { - int i = (q*ctx->m.mb_num) + mb; + for (int q = 1; q < avctx->qmax; q++) { + int i = (q*ctx->m.c.mb_num) + mb; unsigned score = ctx->mb_rc[i].bits * lambda + ((unsigned) ctx->mb_rc[i].ssd << LAMBDA_FRAC_BITS); if (score < min) { @@ -1082,18 +1077,17 @@ static int dnxhd_find_qscale(DNXHDEncContext *ctx) int last_higher = 0; int last_lower = INT_MAX; int qscale; - int x, y; qscale = ctx->qscale; for (;;) { bits = 0; ctx->qscale = qscale; // XXX avoid recalculating bits - ctx->m.avctx->execute2(ctx->m.avctx, dnxhd_calc_bits_thread, - NULL, NULL, ctx->m.mb_height); - for (y = 0; y < ctx->m.mb_height; y++) { - for (x = 0; x < ctx->m.mb_width; x++) - bits += ctx->mb_rc[(qscale*ctx->m.mb_num) + (y*ctx->m.mb_width+x)].bits; + ctx->m.c.avctx->execute2(ctx->m.c.avctx, dnxhd_calc_bits_thread, + NULL, NULL, ctx->m.c.mb_height); + for (int y = 0; y < ctx->m.c.mb_height; y++) { + for (int x = 0; x < ctx->m.c.mb_width; x++) + bits += ctx->mb_rc[(qscale*ctx->m.c.mb_num) + (y*ctx->m.c.mb_width+x)].bits; bits = (bits+31)&~31; // padding if (bits > ctx->frame_bits) break; @@ -1122,7 +1116,7 @@ static int dnxhd_find_qscale(DNXHDEncContext *ctx) else qscale += up_step++; down_step = 1; - if (qscale >= ctx->m.avctx->qmax) + if (qscale >= ctx->m.c.avctx->qmax) return AVERROR(EINVAL); } } @@ -1189,24 +1183,24 @@ static void radix_sort(RCCMPEntry *data, RCCMPEntry *tmp, int size) static int dnxhd_encode_fast(AVCodecContext *avctx, DNXHDEncContext *ctx) { int max_bits = 0; - int ret, x, y; + int ret; if ((ret = dnxhd_find_qscale(ctx)) < 0) return ret; - for (y = 0; y < ctx->m.mb_height; y++) { - for (x = 0; x < ctx->m.mb_width; x++) { - int mb = y * ctx->m.mb_width + x; - int rc = (ctx->qscale * ctx->m.mb_num ) + mb; + for (int y = 0; y < ctx->m.c.mb_height; y++) { + for (int x = 0; x < ctx->m.c.mb_width; x++) { + int mb = y * ctx->m.c.mb_width + x; + int rc = (ctx->qscale * ctx->m.c.mb_num ) + mb; int delta_bits; ctx->mb_qscale[mb] = ctx->qscale; ctx->mb_bits[mb] = ctx->mb_rc[rc].bits; max_bits += ctx->mb_rc[rc].bits; if (!RC_VARIANCE) { delta_bits = ctx->mb_rc[rc].bits - - ctx->mb_rc[rc + ctx->m.mb_num].bits; + ctx->mb_rc[rc + ctx->m.c.mb_num].bits; ctx->mb_cmp[mb].mb = mb; ctx->mb_cmp[mb].value = delta_bits ? ((ctx->mb_rc[rc].ssd - - ctx->mb_rc[rc + ctx->m.mb_num].ssd) * 100) / + ctx->mb_rc[rc + ctx->m.c.mb_num].ssd) * 100) / delta_bits : INT_MIN; // avoid increasing qscale } @@ -1216,17 +1210,17 @@ static int dnxhd_encode_fast(AVCodecContext *avctx, DNXHDEncContext *ctx) if (!ret) { if (RC_VARIANCE) avctx->execute2(avctx, dnxhd_mb_var_thread, - NULL, NULL, ctx->m.mb_height); - radix_sort(ctx->mb_cmp, ctx->mb_cmp_tmp, ctx->m.mb_num); + NULL, NULL, ctx->m.c.mb_height); + radix_sort(ctx->mb_cmp, ctx->mb_cmp_tmp, ctx->m.c.mb_num); retry: - for (x = 0; x < ctx->m.mb_num && max_bits > ctx->frame_bits; x++) { + for (int x = 0; x < ctx->m.c.mb_num && max_bits > ctx->frame_bits; x++) { int mb = ctx->mb_cmp[x].mb; - int rc = (ctx->qscale * ctx->m.mb_num ) + mb; + int rc = (ctx->qscale * ctx->m.c.mb_num ) + mb; max_bits -= ctx->mb_rc[rc].bits - - ctx->mb_rc[rc + ctx->m.mb_num].bits; + ctx->mb_rc[rc + ctx->m.c.mb_num].bits; if (ctx->mb_qscale[mb] < 255) ctx->mb_qscale[mb]++; - ctx->mb_bits[mb] = ctx->mb_rc[rc + ctx->m.mb_num].bits; + ctx->mb_bits[mb] = ctx->mb_rc[rc + ctx->m.c.mb_num].bits; } if (max_bits > ctx->frame_bits) @@ -1237,13 +1231,11 @@ retry: static void dnxhd_load_picture(DNXHDEncContext *ctx, const AVFrame *frame) { - int i; - - for (i = 0; i < ctx->m.avctx->thread_count; i++) { - ctx->thread[i]->m.linesize = frame->linesize[0] << ctx->interlaced; - ctx->thread[i]->m.uvlinesize = frame->linesize[1] << ctx->interlaced; - ctx->thread[i]->dct_y_offset = ctx->m.linesize *8; - ctx->thread[i]->dct_uv_offset = ctx->m.uvlinesize*8; + for (int i = 0; i < ctx->m.c.avctx->thread_count; i++) { + ctx->thread[i]->m.c.linesize = frame->linesize[0] << ctx->interlaced; + ctx->thread[i]->m.c.uvlinesize = frame->linesize[1] << ctx->interlaced; + ctx->thread[i]->dct_y_offset = ctx->m.c.linesize *8; + ctx->thread[i]->dct_uv_offset = ctx->m.c.uvlinesize*8; } ctx->cur_field = (frame->flags & AV_FRAME_FLAG_INTERLACED) && @@ -1286,13 +1278,13 @@ encode_coding_unit: dnxhd_setup_threads_slices(ctx); offset = 0; - for (i = 0; i < ctx->m.mb_height; i++) { + for (i = 0; i < ctx->m.c.mb_height; i++) { AV_WB32(ctx->msip + i * 4, offset); offset += ctx->slice_size[i]; av_assert1(!(ctx->slice_size[i] & 3)); } - avctx->execute2(avctx, dnxhd_encode_thread, buf, NULL, ctx->m.mb_height); + avctx->execute2(avctx, dnxhd_encode_thread, buf, NULL, ctx->m.c.mb_height); av_assert1(ctx->data_offset + offset + 4 <= ctx->coding_unit_size); memset(buf + ctx->data_offset + offset, 0, @@ -1307,7 +1299,7 @@ encode_coding_unit: goto encode_coding_unit; } - ff_side_data_set_encoder_stats(pkt, ctx->qscale * FF_QP2LAMBDA, NULL, 0, AV_PICTURE_TYPE_I); + ff_encode_add_stats_side_data(pkt, ctx->qscale * FF_QP2LAMBDA, NULL, 0, AV_PICTURE_TYPE_I); *got_packet = 1; return 0; @@ -1360,13 +1352,8 @@ const FFCodec ff_dnxhd_encoder = { .init = dnxhd_encode_init, FF_CODEC_ENCODE_CB(dnxhd_encode_picture), .close = dnxhd_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUV422P, - AV_PIX_FMT_YUV422P10, - AV_PIX_FMT_YUV444P10, - AV_PIX_FMT_GBRP10, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUV444P10, AV_PIX_FMT_GBRP10), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &dnxhd_class, .defaults = dnxhd_defaults, @@ -1376,7 +1363,7 @@ const FFCodec ff_dnxhd_encoder = { void ff_dnxhdenc_init(DNXHDEncContext *ctx) { -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_dnxhdenc_init_x86(ctx); #endif } diff --git a/libavcodec/dnxhdenc.h b/libavcodec/dnxhdenc.h index 00d486bab..7540607cd 100644 --- a/libavcodec/dnxhdenc.h +++ b/libavcodec/dnxhdenc.h @@ -28,7 +28,7 @@ #include "libavutil/mem_internal.h" -#include "mpegvideo.h" +#include "mpegvideoenc.h" #include "dnxhddata.h" typedef struct RCCMPEntry { @@ -43,7 +43,7 @@ typedef struct RCEntry { typedef struct DNXHDEncContext { AVClass *class; - MpegEncContext m; ///< Used for quantization dsp functions + MPVEncContext m; ///< Used for quantization dsp functions int cid; int profile; diff --git a/libavcodec/dnxuc_parser.c b/libavcodec/dnxuc_parser.c new file mode 100644 index 000000000..b14cd519a --- /dev/null +++ b/libavcodec/dnxuc_parser.c @@ -0,0 +1,90 @@ +/* + * Avid DNxUncomressed / SMPTE RDD 50 parser + * Copyright (c) 2024 Martin Schitter + * + * 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 + */ + +/* + * This parser for DNxUncompressed video data is mostly based on the public + * SMPTE RDD 50:2019 specification. + */ + +#include "parser.h" +#include "parser_internal.h" +#include "libavutil/bswap.h" + +typedef struct DNxUcParseContext { + ParseContext pc; + uint32_t remaining; +} DNxUcParseContext; + +static int dnxuc_parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + DNxUcParseContext *ipc = s->priv_data; + int next = END_NOT_FOUND; + + s->pict_type = AV_PICTURE_TYPE_NONE; + + *poutbuf_size = 0; + *poutbuf = NULL; + + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + } else { + if (ipc->remaining == 0) { + uint64_t state = ipc->pc.state64; + for (int i = 0; i < buf_size; i++) { + state = (state << 8) | buf[i]; + if (ipc->pc.index + i >= 7 && (uint32_t)state == MKBETAG('p','a','c','k')) { + uint32_t size = av_bswap32(state >> 32); + if (size >= 8) { + next = i - 7; + ipc->remaining = size + FFMIN(next, 0); + break; + } + } + } + ipc->pc.state64 = state; + } else if (ipc->remaining <= buf_size) { + next = ipc->remaining; + ipc->remaining = 0; + } else { + ipc->remaining -= buf_size; + } + if (ff_combine_frame(&ipc->pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + } + + *poutbuf = buf; + *poutbuf_size = buf_size; + + return next; +} + +const FFCodecParser ff_dnxuc_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_DNXUC), + .priv_data_size = sizeof(DNxUcParseContext), + .parse = dnxuc_parse, + .close = ff_parse_close, +}; diff --git a/libavcodec/dolby_e.c b/libavcodec/dolby_e.c index 9c3f6006c..2d32ac283 100644 --- a/libavcodec/dolby_e.c +++ b/libavcodec/dolby_e.c @@ -1310,6 +1310,5 @@ const FFCodec ff_dolby_e_decoder = { .close = dolby_e_close, .flush = dolby_e_flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/dolby_e_parse.c b/libavcodec/dolby_e_parse.c index ffedcd99a..fc20eae5b 100644 --- a/libavcodec/dolby_e_parse.c +++ b/libavcodec/dolby_e_parse.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "get_bits.h" #include "put_bits.h" #include "dolby_e.h" @@ -88,7 +89,7 @@ int ff_dolby_e_convert_input(DBEContext *s, int nb_words, int key) AV_WB24(dst, AV_RB24(src) ^ key); break; default: - av_assert0(0); + av_unreachable("ff_dolby_e_parse_header() only sets 16, 20, 24 and errors out otherwise"); } return init_get_bits(&s->gb, s->buffer, nb_words * s->word_bits); diff --git a/libavcodec/dolby_e_parser.c b/libavcodec/dolby_e_parser.c index d2566e544..b7150795c 100644 --- a/libavcodec/dolby_e_parser.c +++ b/libavcodec/dolby_e_parser.c @@ -21,6 +21,7 @@ #include "libavutil/channel_layout.h" #include "avcodec.h" #include "dolby_e.h" +#include "parser_internal.h" typedef struct DBEParseContext { DBEContext dectx; @@ -65,8 +66,8 @@ end: return buf_size; } -const AVCodecParser ff_dolby_e_parser = { - .codec_ids = { AV_CODEC_ID_DOLBY_E }, +const FFCodecParser ff_dolby_e_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_DOLBY_E), .priv_data_size = sizeof(DBEParseContext), - .parser_parse = dolby_e_parse, + .parse = dolby_e_parse, }; diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c index 5130a9598..f19c1922f 100644 --- a/libavcodec/dovi_rpu.c +++ b/libavcodec/dovi_rpu.c @@ -21,17 +21,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "libavutil/mem.h" #include "dovi_rpu.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" void ff_dovi_ctx_unref(DOVIContext *s) { - ff_refstruct_unref(&s->dm); + av_refstruct_unref(&s->dm); for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr); i++) - ff_refstruct_unref(&s->vdr[i]); - ff_refstruct_unref(&s->ext_blocks); + av_refstruct_unref(&s->vdr[i]); + av_refstruct_unref(&s->ext_blocks); av_free(s->rpu_buf); *s = (DOVIContext) { @@ -39,12 +40,12 @@ void ff_dovi_ctx_unref(DOVIContext *s) }; } -void ff_dovi_ctx_flush(DOVIContext *s) +av_cold void ff_dovi_ctx_flush(DOVIContext *s) { - ff_refstruct_unref(&s->dm); + av_refstruct_unref(&s->dm); for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr); i++) - ff_refstruct_unref(&s->vdr[i]); - ff_refstruct_unref(&s->ext_blocks); + av_refstruct_unref(&s->vdr[i]); + av_refstruct_unref(&s->ext_blocks); *s = (DOVIContext) { .logctx = s->logctx, @@ -62,10 +63,10 @@ void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0) s->header = s0->header; s->mapping = s0->mapping; s->color = s0->color; - ff_refstruct_replace(&s->dm, s0->dm); + av_refstruct_replace(&s->dm, s0->dm); for (int i = 0; i <= DOVI_MAX_DM_ID; i++) - ff_refstruct_replace(&s->vdr[i], s0->vdr[i]); - ff_refstruct_replace(&s->ext_blocks, s0->ext_blocks); + av_refstruct_replace(&s->vdr[i], s0->vdr[i]); + av_refstruct_replace(&s->ext_blocks, s0->ext_blocks); } int ff_dovi_guess_profile_hevc(const AVDOVIRpuDataHeader *hdr) diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h index f3ccc27ae..1b7498320 100644 --- a/libavcodec/dovi_rpu.h +++ b/libavcodec/dovi_rpu.h @@ -133,9 +133,10 @@ int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame); /** * Configure the encoder for Dolby Vision encoding. Generates a configuration - * record in s->cfg, and attaches it to avctx->coded_side_data. Sets the correct - * profile and compatibility ID based on the tagged AVCodecParameters colorspace - * metadata, and the correct level based on the resolution and tagged framerate. + * record in s->cfg, and attaches it to codecpar->coded_side_data. Sets the + * correct profile and compatibility ID based on the tagged AVCodecParameters + * colorspace metadata, and the correct level based on the resolution and + * tagged framerate. * * `metadata` should point to the first frame's RPU, if available. If absent, * auto-detection will be performed, but this can sometimes lead to inaccurate @@ -143,13 +144,13 @@ int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame); * * Returns 0 or a negative error code. */ -int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, - const AVDOVIMetadata *metadata, - enum AVDOVICompression compression, - int strict_std_compliance); +int ff_dovi_configure_from_codedpar(DOVIContext *s, AVCodecParameters *codecpar, + const AVDOVIMetadata *metadata, + enum AVDOVICompression compression, + int strict_std_compliance); /** - * Helper wrapper around `ff_dovi_configure_ext` which infers the codec + * Variant of `ff_dovi_configure_from_codedpar` which infers the codec * parameters from an AVCodecContext. */ int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx); diff --git a/libavcodec/dovi_rpudec.c b/libavcodec/dovi_rpudec.c index 878950d66..d210ba52c 100644 --- a/libavcodec/dovi_rpudec.c +++ b/libavcodec/dovi_rpudec.c @@ -28,7 +28,7 @@ #include "dovi_rpu.h" #include "golomb.h" #include "get_bits.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" int ff_dovi_get_metadata(DOVIContext *s, AVDOVIMetadata **out_metadata) { @@ -188,8 +188,7 @@ static int parse_ext_v1(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm) dm->l255.dm_debug[i] = get_bits(gb, 8); break; default: - av_log(s->logctx, AV_LOG_WARNING, - "Unknown Dolby Vision DM v1 level: %u\n", dm->level); + avpriv_request_sample(s->logctx, "Dolby Vision DM v1 level %u", dm->level); } return 0; @@ -262,20 +261,15 @@ static int parse_ext_v2(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm, dm->l11.whitepoint = get_bits(gb, 4); dm->l11.reference_mode_flag = get_bits1(gb); skip_bits(gb, 3); /* reserved */ - dm->l11.sharpness = get_bits(gb, 2); - dm->l11.noise_reduction = get_bits(gb, 2); - dm->l11.mpeg_noise_reduction = get_bits(gb, 2); - dm->l11.frame_rate_conversion = get_bits(gb, 2); - dm->l11.brightness = get_bits(gb, 2); - dm->l11.color = get_bits(gb, 2); + skip_bits(gb, 8); /* reserved */ + skip_bits(gb, 8); /* reserved */ break; case 254: dm->l254.dm_mode = get_bits(gb, 8); dm->l254.dm_version_index = get_bits(gb, 8); break; default: - av_log(s->logctx, AV_LOG_WARNING, - "Unknown Dolby Vision DM v2 level: %u\n", dm->level); + avpriv_request_sample(s->logctx, "Dolby Vision DM v2 level %u", dm->level); } return 0; @@ -291,7 +285,7 @@ static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver, align_get_bits(gb); if (num_ext_blocks && !ext) { - ext = s->ext_blocks = ff_refstruct_allocz(sizeof(*s->ext_blocks)); + ext = s->ext_blocks = av_refstruct_allocz(sizeof(*s->ext_blocks)); if (!ext) return AVERROR(ENOMEM); } @@ -328,12 +322,15 @@ static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver, switch (ver) { case 1: ret = parse_ext_v1(s, gb, dm); break; case 2: ret = parse_ext_v2(s, gb, dm, ext_block_length); break; - default: return AVERROR_BUG; + default: + avpriv_request_sample(s->logctx, "Dolby Vision DM v%d", ver); + goto skip; } if (ret < 0) return ret; +skip: parsed_bits = get_bits_count(gb) - start_pos; if (parsed_bits > ext_block_length * 8) return AVERROR_INVALIDDATA; @@ -364,7 +361,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, /* Container */ if (s->cfg.dv_profile == 10 /* dav1.10 */) { - /* DV inside AV1 re-uses an EMDF container skeleton, but with fixed + /* DV inside AV1 reuses an EMDF container skeleton, but with fixed * values - so we can effectively treat this as a magic byte sequence. * * The exact fields are, as follows: @@ -408,22 +405,6 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, VALIDATE(rpu[0], 25, 25); /* NAL prefix */ rpu++; rpu_size--; - /* Strip trailing padding bytes */ - while (rpu_size && rpu[rpu_size - 1] == 0) - rpu_size--; - } - - if (!rpu_size || rpu[rpu_size - 1] != 0x80) - return AVERROR_INVALIDDATA; - - if (err_recognition & AV_EF_CRCCHECK) { - uint32_t crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), - -1, rpu, rpu_size - 1)); /* exclude 0x80 */ - if (crc) { - av_log(s->logctx, AV_LOG_ERROR, "RPU CRC mismatch: %X\n", crc); - if (err_recognition & AV_EF_EXPLODE) - return AVERROR_INVALIDDATA; - } } if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0) @@ -556,7 +537,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, int vdr_rpu_id = get_ue_golomb_31(gb); VALIDATE(vdr_rpu_id, 0, DOVI_MAX_DM_ID); if (!s->vdr[vdr_rpu_id]) { - s->vdr[vdr_rpu_id] = ff_refstruct_allocz(sizeof(AVDOVIDataMapping)); + s->vdr[vdr_rpu_id] = av_refstruct_allocz(sizeof(AVDOVIDataMapping)); if (!s->vdr[vdr_rpu_id]) { ff_dovi_ctx_unref(s); return AVERROR(ENOMEM); @@ -675,7 +656,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, } if (!s->dm) { - s->dm = ff_refstruct_allocz(sizeof(AVDOVIColorMetadata)); + s->dm = av_refstruct_allocz(sizeof(AVDOVIColorMetadata)); if (!s->dm) { ff_dovi_ctx_unref(s); return AVERROR(ENOMEM); @@ -735,7 +716,28 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, } } else { s->color = &ff_dovi_color_default; - ff_refstruct_unref(&s->ext_blocks); + av_refstruct_unref(&s->ext_blocks); + } + + align_get_bits(gb); + skip_bits(gb, 32); /* CRC32 */ + if (get_bits(gb, 8) != 0x80) { + avpriv_request_sample(s->logctx, "Unexpected RPU format"); + ff_dovi_ctx_unref(s); + return AVERROR_PATCHWELCOME; + } + + if (err_recognition & AV_EF_CRCCHECK) { + rpu_size = get_bits_count(gb) / 8; + uint32_t crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), + -1, rpu, rpu_size - 1)); /* exclude 0x80 */ + if (crc) { + av_log(s->logctx, AV_LOG_ERROR, "RPU CRC mismatch: %X\n", crc); + if (err_recognition & AV_EF_EXPLODE) { + ff_dovi_ctx_unref(s); + return AVERROR_INVALIDDATA; + } + } } return 0; diff --git a/libavcodec/dovi_rpuenc.c b/libavcodec/dovi_rpuenc.c index 8113ec44b..0c22bf34e 100644 --- a/libavcodec/dovi_rpuenc.c +++ b/libavcodec/dovi_rpuenc.c @@ -20,18 +20,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/crc.h" #include "libavutil/mem.h" +#include "libavutil/refstruct.h" #include "avcodec.h" #include "dovi_rpu.h" #include "itut35.h" #include "put_bits.h" #include "put_golomb.h" -#include "refstruct.h" -static struct { +static const struct { uint64_t pps; // maximum pixels per second int width; // maximum width int main; // maximum bitrate in main tier @@ -52,10 +53,18 @@ static struct { [13] = {7680*4320*120u, 7680, 240, 800}, }; -int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, - const AVDOVIMetadata *metadata, - enum AVDOVICompression compression, - int strict_std_compliance) +static av_cold int dovi_configure_ext(DOVIContext *s, enum AVCodecID codec_id, + const AVDOVIMetadata *metadata, + enum AVDOVICompression compression, + int strict_std_compliance, + int width, int height, + AVRational framerate, + enum AVPixelFormat pix_format, + enum AVColorSpace color_space, + enum AVColorPrimaries color_primaries, + enum AVColorTransferCharacteristic color_trc, + AVPacketSideData **coded_side_data, + int *nb_coded_side_data) { AVDOVIDecoderConfigurationRecord *cfg; const AVDOVIRpuDataHeader *hdr = NULL; @@ -76,7 +85,7 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, compression > AV_DOVI_COMPRESSION_EXTENDED) return AVERROR(EINVAL); - switch (codecpar->codec_id) { + switch (codec_id) { case AV_CODEC_ID_AV1: dv_profile = 10; break; case AV_CODEC_ID_H264: dv_profile = 9; break; case AV_CODEC_ID_HEVC: @@ -86,25 +95,23 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, } /* This is likely to be proprietary IPTPQc2 */ - if (codecpar->color_space == AVCOL_SPC_IPT_C2 || - (codecpar->color_space == AVCOL_SPC_UNSPECIFIED && - codecpar->color_trc == AVCOL_TRC_UNSPECIFIED)) + if (color_space == AVCOL_SPC_IPT_C2 || + (color_space == AVCOL_SPC_UNSPECIFIED && + color_trc == AVCOL_TRC_UNSPECIFIED)) dv_profile = 5; else dv_profile = 8; break; default: - /* No other encoder should be calling this! */ - av_assert0(0); - return AVERROR_BUG; + av_unreachable("ff_dovi_configure only used with AV1, H.264 and HEVC"); } if (strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { if (dv_profile == 9) { - if (codecpar->format != AV_PIX_FMT_YUV420P) + if (pix_format != AV_PIX_FMT_YUV420P) dv_profile = 0; } else { - if (codecpar->format != AV_PIX_FMT_YUV420P10) + if (pix_format != AV_PIX_FMT_YUV420P10) dv_profile = 0; } } @@ -131,17 +138,17 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, } /* fall through */ case 8: /* HEVC (or AV1) with BL compatibility */ - if (codecpar->color_space == AVCOL_SPC_BT2020_NCL && - codecpar->color_primaries == AVCOL_PRI_BT2020 && - codecpar->color_trc == AVCOL_TRC_SMPTE2084) { + if (color_space == AVCOL_SPC_BT2020_NCL && + color_primaries == AVCOL_PRI_BT2020 && + color_trc == AVCOL_TRC_SMPTE2084) { bl_compat_id = 1; - } else if (codecpar->color_space == AVCOL_SPC_BT2020_NCL && - codecpar->color_primaries == AVCOL_PRI_BT2020 && - codecpar->color_trc == AVCOL_TRC_ARIB_STD_B67) { + } else if (color_space == AVCOL_SPC_BT2020_NCL && + color_primaries == AVCOL_PRI_BT2020 && + color_trc == AVCOL_TRC_ARIB_STD_B67) { bl_compat_id = 4; - } else if (codecpar->color_space == AVCOL_SPC_BT709 && - codecpar->color_primaries == AVCOL_PRI_BT709 && - codecpar->color_trc == AVCOL_TRC_BT709) { + } else if (color_space == AVCOL_SPC_BT709 && + color_primaries == AVCOL_PRI_BT709 && + color_trc == AVCOL_TRC_BT709) { bl_compat_id = 2; } } @@ -175,9 +182,9 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, } } - pps = codecpar->width * codecpar->height; - if (codecpar->framerate.num) { - pps = pps * codecpar->framerate.num / codecpar->framerate.den; + pps = width * height; + if (framerate.num) { + pps = pps * framerate.num / framerate.den; } else { pps *= 25; /* sanity fallback */ } @@ -186,7 +193,7 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, for (int i = 1; i < FF_ARRAY_ELEMS(dv_levels); i++) { if (pps > dv_levels[i].pps) continue; - if (codecpar->width > dv_levels[i].width) + if (width > dv_levels[i].width) continue; /* In theory, we should also test the bitrate when known, and * distinguish between main and high tier. In practice, just ignore @@ -199,12 +206,12 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, if (!dv_level) { if (strict_std_compliance >= FF_COMPLIANCE_STRICT) { av_log(s->logctx, AV_LOG_ERROR, "Coded PPS (%"PRIu64") and width (%d) " - "exceed Dolby Vision limitations\n", pps, codecpar->width); + "exceed Dolby Vision limitations\n", pps, width); return AVERROR(EINVAL); } else { av_log(s->logctx, AV_LOG_WARNING, "Coded PPS (%"PRIu64") and width (%d) " "exceed Dolby Vision limitations. Ignoring, resulting file " - "may be non-conforming.\n", pps, codecpar->width); + "may be non-conforming.\n", pps, width); dv_level = FF_ARRAY_ELEMS(dv_levels) - 1; } } @@ -213,8 +220,8 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, if (!cfg) return AVERROR(ENOMEM); - if (!av_packet_side_data_add(&codecpar->coded_side_data, - &codecpar->nb_coded_side_data, + if (!av_packet_side_data_add(coded_side_data, + nb_coded_side_data, AV_PKT_DATA_DOVI_CONF, cfg, cfg_size, 0)) { av_free(cfg); return AVERROR(ENOMEM); @@ -238,19 +245,22 @@ skip: return 0; } -int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx) +av_cold int ff_dovi_configure_from_codedpar(DOVIContext *s, AVCodecParameters *par, + const AVDOVIMetadata *metadata, + enum AVDOVICompression compression, + int strict_std_compliance) +{ + return dovi_configure_ext(s, par->codec_id, metadata, compression, + strict_std_compliance, par->width, par->height, + par->framerate, par->format, par->color_space, + par->color_primaries, par->color_trc, + &par->coded_side_data, &par->nb_coded_side_data); +} + +av_cold int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx) { - int ret; - const AVFrameSideData *sd; const AVDOVIMetadata *metadata = NULL; - AVCodecParameters *codecpar = avcodec_parameters_alloc(); - if (!codecpar) - return AVERROR(ENOMEM); - - ret = avcodec_parameters_from_context(codecpar, avctx); - if (ret < 0) - goto fail; - + const AVFrameSideData *sd; sd = av_frame_side_data_get(avctx->decoded_side_data, avctx->nb_decoded_side_data, AV_FRAME_DATA_DOVI_METADATA); @@ -258,16 +268,11 @@ int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx) metadata = (const AVDOVIMetadata *) sd->data; /* Current encoders cannot handle metadata compression during encoding */ - ret = ff_dovi_configure_ext(s, codecpar, metadata, AV_DOVI_COMPRESSION_NONE, - avctx->strict_std_compliance); - if (ret < 0) - goto fail; - - ret = avcodec_parameters_to_context(avctx, codecpar); - -fail: - avcodec_parameters_free(&codecpar); - return ret; + return dovi_configure_ext(s, avctx->codec_id, metadata, AV_DOVI_COMPRESSION_NONE, + avctx->strict_std_compliance, avctx->width, + avctx->height, avctx->framerate, avctx->pix_fmt, + avctx->colorspace, avctx->color_primaries, avctx->color_trc, + &avctx->coded_side_data, &avctx->nb_coded_side_data); } /* Compares only the static DM metadata parts of AVDOVIColorMetadata (excluding @@ -295,7 +300,7 @@ static int cmp_dm_level0(const AVDOVIColorMetadata *dm1, sizeof(AVDOVIColorMetadata) -offsetof(AVDOVIColorMetadata, signal_eotf)); } -/* Tries to re-use the static ext blocks. May reorder `ext->dm_static` */ +/* Tries to reuse the static ext blocks. May reorder `ext->dm_static` */ static int try_reuse_ext(DOVIExt *ext, const AVDOVIMetadata *metadata) { int i, j, idx = 0; @@ -334,12 +339,12 @@ static inline void put_ue_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr switch (hdr->coef_data_type) { case RPU_COEFF_FIXED: set_ue_golomb(pb, coef >> hdr->coef_log2_denom); - put_bits64(pb, hdr->coef_log2_denom, + put_bits63(pb, hdr->coef_log2_denom, coef & ((1LL << hdr->coef_log2_denom) - 1)); break; case RPU_COEFF_FLOAT: fpart.f32 = coef / (float) (1LL << hdr->coef_log2_denom); - put_bits64(pb, hdr->coef_log2_denom, fpart.u32); + put_bits63(pb, hdr->coef_log2_denom, fpart.u32); break; } } @@ -352,12 +357,12 @@ static inline void put_se_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr switch (hdr->coef_data_type) { case RPU_COEFF_FIXED: set_se_golomb(pb, coef >> hdr->coef_log2_denom); - put_bits64(pb, hdr->coef_log2_denom, + put_bits63(pb, hdr->coef_log2_denom, coef & ((1LL << hdr->coef_log2_denom) - 1)); break; case RPU_COEFF_FLOAT: fpart.f32 = coef / (float) (1LL << hdr->coef_log2_denom); - put_bits64(pb, hdr->coef_log2_denom, fpart.u32); + put_bits63(pb, hdr->coef_log2_denom, fpart.u32); break; } } @@ -541,12 +546,8 @@ static void generate_ext_v2(PutBitContext *pb, const AVDOVIDmData *dm) put_bits(pb, 4, dm->l11.whitepoint); put_bits(pb, 1, dm->l11.reference_mode_flag); put_bits(pb, 3, 0); /* reserved */ - put_bits(pb, 2, dm->l11.sharpness); - put_bits(pb, 2, dm->l11.noise_reduction); - put_bits(pb, 2, dm->l11.mpeg_noise_reduction); - put_bits(pb, 2, dm->l11.frame_rate_conversion); - put_bits(pb, 2, dm->l11.brightness); - put_bits(pb, 2, dm->l11.color); + put_bits(pb, 8, 0); /* reserved */ + put_bits(pb, 8, 0); /* reserved */ break; case 254: put_bits(pb, 8, dm->l254.dm_mode); @@ -601,7 +602,7 @@ int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, use_prev_vdr_rpu = 0; if (!s->vdr[vdr_rpu_id]) { - s->vdr[vdr_rpu_id] = ff_refstruct_allocz(sizeof(AVDOVIDataMapping)); + s->vdr[vdr_rpu_id] = av_refstruct_allocz(sizeof(AVDOVIDataMapping)); if (!s->vdr[vdr_rpu_id]) return AVERROR(ENOMEM); } @@ -625,12 +626,12 @@ int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, * references requires extended compression */ for (int i = 0; i <= DOVI_MAX_DM_ID; i++) { if (i != vdr_rpu_id) - ff_refstruct_unref(&s->vdr[i]); + av_refstruct_unref(&s->vdr[i]); } } if (metadata->num_ext_blocks && !s->ext_blocks) { - s->ext_blocks = ff_refstruct_allocz(sizeof(*s->ext_blocks)); + s->ext_blocks = av_refstruct_allocz(sizeof(*s->ext_blocks)); if (!s->ext_blocks) return AVERROR(ENOMEM); } @@ -640,7 +641,7 @@ int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, vdr_dm_metadata_present = 1; if (vdr_dm_metadata_present && !s->dm) { - s->dm = ff_refstruct_allocz(sizeof(AVDOVIColorMetadata)); + s->dm = av_refstruct_allocz(sizeof(AVDOVIColorMetadata)); if (!s->dm) return AVERROR(ENOMEM); } @@ -864,7 +865,7 @@ int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, } } else { s->color = &ff_dovi_color_default; - ff_refstruct_unref(&s->ext_blocks); + av_refstruct_unref(&s->ext_blocks); } flush_put_bits(pb); diff --git a/libavcodec/dpcm.c b/libavcodec/dpcm.c index eff658740..39df47dcf 100644 --- a/libavcodec/dpcm.c +++ b/libavcodec/dpcm.c @@ -43,6 +43,8 @@ #include "decode.h" #include "mathops.h" +#include "libavutil/attributes.h" + typedef struct DPCMContext { int16_t array[256]; int sample[2]; ///< previous sample (for SOL_DPCM and WADY_DPCM) @@ -457,32 +459,32 @@ static int dpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, return avpkt->size; } -static void dpcm_flush(AVCodecContext *avctx) +static av_cold void dpcm_flush(AVCodecContext *avctx) { DPCMContext *s = avctx->priv_data; s->sample[0] = s->sample[1] = 0; } -#define DPCM_DECODER(id_, name_, long_name_) \ -const FFCodec ff_ ## name_ ## _decoder = { \ - .p.name = #name_, \ - CODEC_LONG_NAME(long_name_), \ +#define DPCM_DECODER(ID, NAME, FLUSH, LONG_NAME) \ +const FFCodec ff_ ## NAME ## _decoder = { \ + .p.name = #NAME, \ + CODEC_LONG_NAME(LONG_NAME), \ .p.type = AVMEDIA_TYPE_AUDIO, \ - .p.id = id_, \ + .p.id = ID, \ .p.capabilities = AV_CODEC_CAP_DR1, \ .priv_data_size = sizeof(DPCMContext), \ .init = dpcm_decode_init, \ - .flush = dpcm_flush, \ + .flush = FLUSH, \ FF_CODEC_DECODE_CB(dpcm_decode_frame), \ } -DPCM_DECODER(AV_CODEC_ID_CBD2_DPCM, cbd2_dpcm, "DPCM Cuberoot-Delta-Exact"); -DPCM_DECODER(AV_CODEC_ID_DERF_DPCM, derf_dpcm, "DPCM Xilam DERF"); -DPCM_DECODER(AV_CODEC_ID_GREMLIN_DPCM, gremlin_dpcm, "DPCM Gremlin"); -DPCM_DECODER(AV_CODEC_ID_INTERPLAY_DPCM, interplay_dpcm, "DPCM Interplay"); -DPCM_DECODER(AV_CODEC_ID_ROQ_DPCM, roq_dpcm, "DPCM id RoQ"); -DPCM_DECODER(AV_CODEC_ID_SDX2_DPCM, sdx2_dpcm, "DPCM Squareroot-Delta-Exact"); -DPCM_DECODER(AV_CODEC_ID_SOL_DPCM, sol_dpcm, "DPCM Sol"); -DPCM_DECODER(AV_CODEC_ID_XAN_DPCM, xan_dpcm, "DPCM Xan"); -DPCM_DECODER(AV_CODEC_ID_WADY_DPCM, wady_dpcm, "DPCM Marble WADY"); +DPCM_DECODER(AV_CODEC_ID_CBD2_DPCM, cbd2_dpcm, dpcm_flush, "DPCM Cuberoot-Delta-Exact"); +DPCM_DECODER(AV_CODEC_ID_DERF_DPCM, derf_dpcm, dpcm_flush, "DPCM Xilam DERF"); +DPCM_DECODER(AV_CODEC_ID_GREMLIN_DPCM, gremlin_dpcm, dpcm_flush, "DPCM Gremlin"); +DPCM_DECODER(AV_CODEC_ID_INTERPLAY_DPCM, interplay_dpcm, NULL, "DPCM Interplay"); +DPCM_DECODER(AV_CODEC_ID_ROQ_DPCM, roq_dpcm, NULL, "DPCM id RoQ"); +DPCM_DECODER(AV_CODEC_ID_SDX2_DPCM, sdx2_dpcm, dpcm_flush, "DPCM Squareroot-Delta-Exact"); +DPCM_DECODER(AV_CODEC_ID_SOL_DPCM, sol_dpcm, dpcm_flush, "DPCM Sol"); +DPCM_DECODER(AV_CODEC_ID_XAN_DPCM, xan_dpcm, NULL, "DPCM Xan"); +DPCM_DECODER(AV_CODEC_ID_WADY_DPCM, wady_dpcm, dpcm_flush, "DPCM Marble WADY"); diff --git a/libavcodec/dpx.c b/libavcodec/dpx.c index 80616d98a..52a03501e 100644 --- a/libavcodec/dpx.c +++ b/libavcodec/dpx.c @@ -27,38 +27,12 @@ #include "avcodec.h" #include "codec_internal.h" #include "decode.h" +#include "dpx.h" -enum DPX_TRC { - DPX_TRC_USER_DEFINED = 0, - DPX_TRC_PRINTING_DENSITY = 1, - DPX_TRC_LINEAR = 2, - DPX_TRC_LOGARITHMIC = 3, - DPX_TRC_UNSPECIFIED_VIDEO = 4, - DPX_TRC_SMPTE_274 = 5, - DPX_TRC_ITU_R_709_4 = 6, - DPX_TRC_ITU_R_601_625 = 7, - DPX_TRC_ITU_R_601_525 = 8, - DPX_TRC_SMPTE_170 = 9, - DPX_TRC_ITU_R_624_4_PAL = 10, - DPX_TRC_Z_LINEAR = 11, - DPX_TRC_Z_HOMOGENEOUS = 12, -}; - -enum DPX_COL_SPEC { - DPX_COL_SPEC_USER_DEFINED = 0, - DPX_COL_SPEC_PRINTING_DENSITY = 1, - /* 2 = N/A */ - /* 3 = N/A */ - DPX_COL_SPEC_UNSPECIFIED_VIDEO = 4, - DPX_COL_SPEC_SMPTE_274 = 5, - DPX_COL_SPEC_ITU_R_709_4 = 6, - DPX_COL_SPEC_ITU_R_601_625 = 7, - DPX_COL_SPEC_ITU_R_601_525 = 8, - DPX_COL_SPEC_SMPTE_170 = 9, - DPX_COL_SPEC_ITU_R_624_4_PAL = 10, - /* 11 = N/A */ - /* 12 = N/A */ -}; +#include "thread.h" +#include "hwconfig.h" +#include "hwaccel_internal.h" +#include "config_components.h" static unsigned int read16(const uint8_t **ptr, int is_big) { @@ -149,25 +123,178 @@ static uint16_t read12in32(const uint8_t **ptr, uint32_t *lbuf, } } +static void unpack_frame(AVCodecContext *avctx, AVFrame *p, const uint8_t *buf, + int elements, int endian) +{ + int i, x, y; + DPXDecContext *dpx = avctx->priv_data; + + uint8_t *ptr[AV_NUM_DATA_POINTERS]; + unsigned int rgbBuffer = 0; + int n_datum = 0; + + for (i=0; idata[i]; + + switch (avctx->bits_per_raw_sample) { + case 10: + for (x = 0; x < avctx->height; x++) { + uint16_t *dst[4] = {(uint16_t*)ptr[0], + (uint16_t*)ptr[1], + (uint16_t*)ptr[2], + (uint16_t*)ptr[3]}; + int shift = elements > 1 ? dpx->packing == 1 ? 22 : 20 : dpx->packing == 1 ? 2 : 0; + for (y = 0; y < avctx->width; y++) { + if (elements >= 3) + *dst[2]++ = read10in32(&buf, &rgbBuffer, + &n_datum, endian, shift); + if (elements == 1) + *dst[0]++ = read10in32_gray(&buf, &rgbBuffer, + &n_datum, endian, shift); + else + *dst[0]++ = read10in32(&buf, &rgbBuffer, + &n_datum, endian, shift); + if (elements >= 2) + *dst[1]++ = read10in32(&buf, &rgbBuffer, + &n_datum, endian, shift); + if (elements == 4) + *dst[3]++ = + read10in32(&buf, &rgbBuffer, + &n_datum, endian, shift); + } + if (!dpx->unpadded_10bit) + n_datum = 0; + for (i = 0; i < elements; i++) + ptr[i] += p->linesize[i]; + } + break; + case 12: + for (x = 0; x < avctx->height; x++) { + uint16_t *dst[4] = {(uint16_t*)ptr[0], + (uint16_t*)ptr[1], + (uint16_t*)ptr[2], + (uint16_t*)ptr[3]}; + int shift = dpx->packing == 1 ? 4 : 0; + for (y = 0; y < avctx->width; y++) { + if (dpx->packing) { + if (elements >= 3) + *dst[2]++ = read16(&buf, endian) >> shift & 0xFFF; + *dst[0]++ = read16(&buf, endian) >> shift & 0xFFF; + if (elements >= 2) + *dst[1]++ = read16(&buf, endian) >> shift & 0xFFF; + if (elements == 4) + *dst[3]++ = read16(&buf, endian) >> shift & 0xFFF; + } else { + if (elements >= 3) + *dst[2]++ = read12in32(&buf, &rgbBuffer, + &n_datum, endian); + *dst[0]++ = read12in32(&buf, &rgbBuffer, + &n_datum, endian); + if (elements >= 2) + *dst[1]++ = read12in32(&buf, &rgbBuffer, + &n_datum, endian); + if (elements == 4) + *dst[3]++ = read12in32(&buf, &rgbBuffer, + &n_datum, endian); + } + } + n_datum = 0; + for (i = 0; i < elements; i++) + ptr[i] += p->linesize[i]; + // Jump to next aligned position + buf += dpx->need_align; + } + break; + case 32: + if (elements == 1) { + av_image_copy_plane(ptr[0], p->linesize[0], + buf, dpx->stride, + elements * avctx->width * 4, avctx->height); + } else { + for (y = 0; y < avctx->height; y++) { + ptr[0] = p->data[0] + y * p->linesize[0]; + ptr[1] = p->data[1] + y * p->linesize[1]; + ptr[2] = p->data[2] + y * p->linesize[2]; + ptr[3] = p->data[3] + y * p->linesize[3]; + for (x = 0; x < avctx->width; x++) { + AV_WN32(ptr[2], AV_RN32(buf)); + AV_WN32(ptr[0], AV_RN32(buf + 4)); + AV_WN32(ptr[1], AV_RN32(buf + 8)); + if (avctx->pix_fmt == AV_PIX_FMT_GBRAPF32BE || + avctx->pix_fmt == AV_PIX_FMT_GBRAPF32LE) { + AV_WN32(ptr[3], AV_RN32(buf + 12)); + buf += 4; + ptr[3] += 4; + } + + buf += 12; + ptr[2] += 4; + ptr[0] += 4; + ptr[1] += 4; + } + } + } + break; + case 16: + elements *= 2; + // fall-through + case 8: + if ( avctx->pix_fmt == AV_PIX_FMT_YUVA444P + || avctx->pix_fmt == AV_PIX_FMT_YUV444P) { + for (x = 0; x < avctx->height; x++) { + ptr[0] = p->data[0] + x * p->linesize[0]; + ptr[1] = p->data[1] + x * p->linesize[1]; + ptr[2] = p->data[2] + x * p->linesize[2]; + ptr[3] = p->data[3] + x * p->linesize[3]; + for (y = 0; y < avctx->width; y++) { + *ptr[1]++ = *buf++; + *ptr[0]++ = *buf++; + *ptr[2]++ = *buf++; + if (avctx->pix_fmt == AV_PIX_FMT_YUVA444P) + *ptr[3]++ = *buf++; + } + } + } else { + av_image_copy_plane(ptr[0], p->linesize[0], + buf, dpx->stride, + elements * avctx->width, avctx->height); + } + break; + } +} + +static enum AVPixelFormat get_pixel_format(AVCodecContext *avctx, + enum AVPixelFormat pix_fmt) +{ + enum AVPixelFormat pix_fmts[] = { +#if CONFIG_DPX_VULKAN_HWACCEL + AV_PIX_FMT_VULKAN, +#endif + pix_fmt, + AV_PIX_FMT_NONE, + }; + + return ff_get_format(avctx, pix_fmts); +} + static int decode_frame(AVCodecContext *avctx, AVFrame *p, int *got_frame, AVPacket *avpkt) { + DPXDecContext *dpx = avctx->priv_data; + + enum AVPixelFormat pix_fmt; const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; - uint8_t *ptr[AV_NUM_DATA_POINTERS]; uint32_t header_version, version = 0; char creator[101] = { 0 }; char input_device[33] = { 0 }; unsigned int offset; - int magic_num, endian; - int x, y, stride, i, j, ret; - int w, h, bits_per_color, descriptor, elements, packing; + int magic_num; + int i, j, ret; + int w, h, descriptor; int yuv, color_trc, color_spec; - int encoding, need_align = 0, unpadded_10bit = 0; - - unsigned int rgbBuffer = 0; - int n_datum = 0; + int encoding; if (avpkt->size <= 1634) { av_log(avctx, AV_LOG_ERROR, "Packet too small for DPX header\n"); @@ -180,15 +307,15 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, /* Check if the files "magic number" is "SDPX" which means it uses * big-endian or XPDS which is for little-endian files */ if (magic_num == AV_RL32("SDPX")) { - endian = 0; + dpx->endian = 0; } else if (magic_num == AV_RB32("SDPX")) { - endian = 1; + dpx->endian = 1; } else { av_log(avctx, AV_LOG_ERROR, "DPX marker not found\n"); return AVERROR_INVALIDDATA; } - offset = read32(&buf, endian); + offset = read32(&buf, dpx->endian); if (avpkt->size <= offset) { av_log(avctx, AV_LOG_ERROR, "Invalid data start offset\n"); return AVERROR_INVALIDDATA; @@ -205,7 +332,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, // Check encryption buf = avpkt->data + 660; - ret = read32(&buf, endian); + ret = read32(&buf, dpx->endian); if (ret != 0xFFFFFFFF) { avpriv_report_missing_feature(avctx, "Encryption"); av_log(avctx, AV_LOG_WARNING, "The image is encrypted and may " @@ -214,8 +341,8 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, // Need to end in 0x304 offset from start of file buf = avpkt->data + 0x304; - w = read32(&buf, endian); - h = read32(&buf, endian); + w = read32(&buf, dpx->endian); + h = read32(&buf, dpx->endian); if ((ret = ff_set_dimensions(avctx, w, h)) < 0) return ret; @@ -228,23 +355,22 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, // Need to end in 0x323 to read the bits per color buf += 3; - avctx->bits_per_raw_sample = - bits_per_color = buf[0]; + avctx->bits_per_raw_sample = buf[0]; buf++; - packing = read16(&buf, endian); - encoding = read16(&buf, endian); + dpx->packing = read16(&buf, dpx->endian); + encoding = read16(&buf, dpx->endian); if (encoding) { avpriv_report_missing_feature(avctx, "Encoding %d", encoding); return AVERROR_PATCHWELCOME; } - if (bits_per_color > 31) + if (avctx->bits_per_raw_sample > 31) return AVERROR_INVALIDDATA; buf += 820; - avctx->sample_aspect_ratio.num = read32(&buf, endian); - avctx->sample_aspect_ratio.den = read32(&buf, endian); + avctx->sample_aspect_ratio.num = read32(&buf, dpx->endian); + avctx->sample_aspect_ratio.den = read32(&buf, dpx->endian); if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) av_reduce(&avctx->sample_aspect_ratio.num, &avctx->sample_aspect_ratio.den, avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den, @@ -255,7 +381,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, /* preferred frame rate from Motion-picture film header */ if (offset >= 1724 + 4) { buf = avpkt->data + 1724; - i = read32(&buf, endian); + i = read32(&buf, dpx->endian); if(i && i != 0xFFFFFFFF) { AVRational q = av_d2q(av_int2float(i), 4096); if (q.num > 0 && q.den > 0) @@ -267,7 +393,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, if (offset >= 1940 + 4 && !(avctx->framerate.num && avctx->framerate.den)) { buf = avpkt->data + 1940; - i = read32(&buf, endian); + i = read32(&buf, dpx->endian); if(i && i != 0xFFFFFFFF) { AVRational q = av_d2q(av_int2float(i), 4096); if (q.num > 0 && q.den > 0) @@ -284,7 +410,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, buf = avpkt->data + 1920; // read32 to native endian, av_bswap32 to opposite of native for // compatibility with av_timecode_make_smpte_tc_string2 etc - tc = av_bswap32(read32(&buf, endian)); + tc = av_bswap32(read32(&buf, dpx->endian)); if (i != 0xFFFFFFFF) { AVFrameSideData *tcside; @@ -308,21 +434,21 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, /* color range from television header */ if (offset >= 1964 + 4) { buf = avpkt->data + 1952; - i = read32(&buf, endian); + i = read32(&buf, dpx->endian); buf = avpkt->data + 1964; - j = read32(&buf, endian); + j = read32(&buf, dpx->endian); if (i != 0xFFFFFFFF && j != 0xFFFFFFFF) { float minCV, maxCV; minCV = av_int2float(i); maxCV = av_int2float(j); - if (bits_per_color >= 1 && - minCV == 0.0f && maxCV == ((1U<bits_per_raw_sample >= 1 && + minCV == 0.0f && maxCV == ((1U<bits_per_raw_sample) - 1)) { avctx->color_range = AVCOL_RANGE_JPEG; - } else if (bits_per_color >= 8 && - minCV == (1 <<(bits_per_color - 4)) && - maxCV == (235<<(bits_per_color - 8))) { + } else if (avctx->bits_per_raw_sample >= 8 && + minCV == (1 <<(avctx->bits_per_raw_sample - 4)) && + maxCV == (235<<(avctx->bits_per_raw_sample - 8))) { avctx->color_range = AVCOL_RANGE_MPEG; } } @@ -334,28 +460,28 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, case 3: // B case 4: // A case 6: // Y - elements = 1; + dpx->components = 1; yuv = 1; break; case 50: // RGB - elements = 3; + dpx->components = 3; yuv = 0; break; case 52: // ABGR case 51: // RGBA - elements = 4; + dpx->components = 4; yuv = 0; break; case 100: // UYVY422 - elements = 2; + dpx->components = 2; yuv = 1; break; case 102: // UYV444 - elements = 3; + dpx->components = 3; yuv = 1; break; case 103: // UYVA4444 - elements = 4; + dpx->components = 4; yuv = 1; break; default: @@ -363,40 +489,40 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, return AVERROR_PATCHWELCOME; } - switch (bits_per_color) { + switch (avctx->bits_per_raw_sample) { case 8: - stride = avctx->width * elements; + dpx->stride = avctx->width * dpx->components; break; case 10: - if (!packing) { + if (!dpx->packing) { av_log(avctx, AV_LOG_ERROR, "Packing to 32bit required\n"); return -1; } - stride = (avctx->width * elements + 2) / 3 * 4; + dpx->stride = (avctx->width * dpx->components + 2) / 3 * 4; break; case 12: - stride = avctx->width * elements; - if (packing) { - stride *= 2; + dpx->stride = avctx->width * dpx->components; + if (dpx->packing) { + dpx->stride *= 2; } else { - stride *= 3; - if (stride % 8) { - stride /= 8; - stride++; - stride *= 8; + dpx->stride *= 3; + if (dpx->stride % 8) { + dpx->stride /= 8; + dpx->stride++; + dpx->stride *= 8; } - stride /= 2; + dpx->stride /= 2; } break; case 16: - stride = 2 * avctx->width * elements; + dpx->stride = 2 * avctx->width * dpx->components; break; case 32: - stride = 4 * avctx->width * elements; + dpx->stride = 4 * avctx->width * dpx->components; break; case 1: case 64: - avpriv_report_missing_feature(avctx, "Depth %d", bits_per_color); + avpriv_report_missing_feature(avctx, "Depth %d", avctx->bits_per_raw_sample); return AVERROR_PATCHWELCOME; default: return AVERROR_INVALIDDATA; @@ -487,10 +613,11 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, av_dict_set(&p->metadata, "Input Device", input_device, 0); // Some devices do not pad 10bit samples to whole 32bit words per row + dpx->unpadded_10bit = 0; if (!memcmp(input_device, "Scanity", 7) || !memcmp(creator, "Lasergraphics Inc.", 18)) { - if (bits_per_color == 10) - unpadded_10bit = 1; + if (avctx->bits_per_raw_sample == 10) + dpx->unpadded_10bit = 1; } // Table 3c: Runs will always break at scan line boundaries. Packing @@ -498,24 +625,24 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, // Unfortunately, the encoder produced invalid files, so attempt // to detect it // Also handle special case with unpadded content - need_align = FFALIGN(stride, 4); - if (need_align*avctx->height + (int64_t)offset > avpkt->size && - (!unpadded_10bit || (avctx->width * avctx->height * elements + 2) / 3 * 4 + (int64_t)offset > avpkt->size)) { + dpx->need_align = FFALIGN(dpx->stride, 4); + if (dpx->need_align*avctx->height + (int64_t)offset > avpkt->size && + (!dpx->unpadded_10bit || (avctx->width * avctx->height * dpx->components + 2) / 3 * 4 + (int64_t)offset > avpkt->size)) { // Alignment seems unappliable, try without - if (stride*avctx->height + (int64_t)offset > avpkt->size || unpadded_10bit) { + if (dpx->stride*avctx->height + (int64_t)offset > avpkt->size || dpx->unpadded_10bit) { av_log(avctx, AV_LOG_ERROR, "Overread buffer. Invalid header?\n"); return AVERROR_INVALIDDATA; } else { av_log(avctx, AV_LOG_INFO, "Decoding DPX without scanline " "alignment.\n"); - need_align = 0; + dpx->need_align = 0; } } else { - need_align -= stride; - stride = FFALIGN(stride, 4); + dpx->need_align -= dpx->stride; + dpx->stride = FFALIGN(dpx->stride, 4); } - switch (1000 * descriptor + 10 * bits_per_color + endian) { + switch (1000 * descriptor + 10 * avctx->bits_per_raw_sample + dpx->endian) { case 1081: case 1080: case 2081: @@ -526,103 +653,113 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, case 4080: case 6081: case 6080: - avctx->pix_fmt = AV_PIX_FMT_GRAY8; + pix_fmt = AV_PIX_FMT_GRAY8; break; case 6121: case 6120: - avctx->pix_fmt = AV_PIX_FMT_GRAY12; + pix_fmt = AV_PIX_FMT_GRAY12; break; case 1320: case 2320: case 3320: case 4320: case 6320: - avctx->pix_fmt = AV_PIX_FMT_GRAYF32LE; + pix_fmt = AV_PIX_FMT_GRAYF32LE; break; case 1321: case 2321: case 3321: case 4321: case 6321: - avctx->pix_fmt = AV_PIX_FMT_GRAYF32BE; + pix_fmt = AV_PIX_FMT_GRAYF32BE; break; case 50081: case 50080: - avctx->pix_fmt = AV_PIX_FMT_RGB24; + pix_fmt = AV_PIX_FMT_RGB24; break; case 52081: case 52080: - avctx->pix_fmt = AV_PIX_FMT_ABGR; + pix_fmt = AV_PIX_FMT_ABGR; break; case 51081: case 51080: - avctx->pix_fmt = AV_PIX_FMT_RGBA; + pix_fmt = AV_PIX_FMT_RGBA; break; case 50100: case 50101: - avctx->pix_fmt = AV_PIX_FMT_GBRP10; + pix_fmt = AV_PIX_FMT_GBRP10; break; case 51100: case 51101: - avctx->pix_fmt = AV_PIX_FMT_GBRAP10; + pix_fmt = AV_PIX_FMT_GBRAP10; break; case 50120: case 50121: - avctx->pix_fmt = AV_PIX_FMT_GBRP12; + pix_fmt = AV_PIX_FMT_GBRP12; break; case 51120: case 51121: - avctx->pix_fmt = AV_PIX_FMT_GBRAP12; + pix_fmt = AV_PIX_FMT_GBRAP12; break; case 6100: case 6101: - avctx->pix_fmt = AV_PIX_FMT_GRAY10; + pix_fmt = AV_PIX_FMT_GRAY10; break; case 6161: - avctx->pix_fmt = AV_PIX_FMT_GRAY16BE; + pix_fmt = AV_PIX_FMT_GRAY16BE; break; case 6160: - avctx->pix_fmt = AV_PIX_FMT_GRAY16LE; + pix_fmt = AV_PIX_FMT_GRAY16LE; break; case 50161: - avctx->pix_fmt = AV_PIX_FMT_RGB48BE; + pix_fmt = AV_PIX_FMT_RGB48BE; break; case 50160: - avctx->pix_fmt = AV_PIX_FMT_RGB48LE; + pix_fmt = AV_PIX_FMT_RGB48LE; break; case 51161: - avctx->pix_fmt = AV_PIX_FMT_RGBA64BE; + pix_fmt = AV_PIX_FMT_RGBA64BE; break; case 51160: - avctx->pix_fmt = AV_PIX_FMT_RGBA64LE; + pix_fmt = AV_PIX_FMT_RGBA64LE; break; case 50320: - avctx->pix_fmt = AV_PIX_FMT_GBRPF32LE; + pix_fmt = AV_PIX_FMT_GBRPF32LE; break; case 50321: - avctx->pix_fmt = AV_PIX_FMT_GBRPF32BE; + pix_fmt = AV_PIX_FMT_GBRPF32BE; break; case 51320: - avctx->pix_fmt = AV_PIX_FMT_GBRAPF32LE; + pix_fmt = AV_PIX_FMT_GBRAPF32LE; break; case 51321: - avctx->pix_fmt = AV_PIX_FMT_GBRAPF32BE; + pix_fmt = AV_PIX_FMT_GBRAPF32BE; break; case 100081: - avctx->pix_fmt = AV_PIX_FMT_UYVY422; + pix_fmt = AV_PIX_FMT_UYVY422; break; case 102081: - avctx->pix_fmt = AV_PIX_FMT_YUV444P; + pix_fmt = AV_PIX_FMT_YUV444P; break; case 103081: - avctx->pix_fmt = AV_PIX_FMT_YUVA444P; + pix_fmt = AV_PIX_FMT_YUVA444P; break; default: av_log(avctx, AV_LOG_ERROR, "Unsupported format %d\n", - 1000 * descriptor + 10 * bits_per_color + endian); + 1000 * descriptor + 10 * avctx->bits_per_raw_sample + dpx->endian); return AVERROR_PATCHWELCOME; } + if (pix_fmt != dpx->pix_fmt) { + dpx->pix_fmt = pix_fmt; + + ret = get_pixel_format(avctx, pix_fmt); + if (ret < 0) + return ret; + + avctx->pix_fmt = ret; + } + ff_set_sar(avctx, avctx->sample_aspect_ratio); if ((ret = ff_get_buffer(avctx, p, 0)) < 0) @@ -630,145 +767,84 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, // Move pointer to offset from start of file buf = avpkt->data + offset; + dpx->frame = p; - for (i=0; idata[i]; + /* Start */ + if (avctx->hwaccel) { + const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel); - switch (bits_per_color) { - case 10: - for (x = 0; x < avctx->height; x++) { - uint16_t *dst[4] = {(uint16_t*)ptr[0], - (uint16_t*)ptr[1], - (uint16_t*)ptr[2], - (uint16_t*)ptr[3]}; - int shift = elements > 1 ? packing == 1 ? 22 : 20 : packing == 1 ? 2 : 0; - for (y = 0; y < avctx->width; y++) { - if (elements >= 3) - *dst[2]++ = read10in32(&buf, &rgbBuffer, - &n_datum, endian, shift); - if (elements == 1) - *dst[0]++ = read10in32_gray(&buf, &rgbBuffer, - &n_datum, endian, shift); - else - *dst[0]++ = read10in32(&buf, &rgbBuffer, - &n_datum, endian, shift); - if (elements >= 2) - *dst[1]++ = read10in32(&buf, &rgbBuffer, - &n_datum, endian, shift); - if (elements == 4) - *dst[3]++ = - read10in32(&buf, &rgbBuffer, - &n_datum, endian, shift); - } - if (!unpadded_10bit) - n_datum = 0; - for (i = 0; i < elements; i++) - ptr[i] += p->linesize[i]; - } - break; - case 12: - for (x = 0; x < avctx->height; x++) { - uint16_t *dst[4] = {(uint16_t*)ptr[0], - (uint16_t*)ptr[1], - (uint16_t*)ptr[2], - (uint16_t*)ptr[3]}; - int shift = packing == 1 ? 4 : 0; - for (y = 0; y < avctx->width; y++) { - if (packing) { - if (elements >= 3) - *dst[2]++ = read16(&buf, endian) >> shift & 0xFFF; - *dst[0]++ = read16(&buf, endian) >> shift & 0xFFF; - if (elements >= 2) - *dst[1]++ = read16(&buf, endian) >> shift & 0xFFF; - if (elements == 4) - *dst[3]++ = read16(&buf, endian) >> shift & 0xFFF; - } else { - if (elements >= 3) - *dst[2]++ = read12in32(&buf, &rgbBuffer, - &n_datum, endian); - *dst[0]++ = read12in32(&buf, &rgbBuffer, - &n_datum, endian); - if (elements >= 2) - *dst[1]++ = read12in32(&buf, &rgbBuffer, - &n_datum, endian); - if (elements == 4) - *dst[3]++ = read12in32(&buf, &rgbBuffer, - &n_datum, endian); - } - } - n_datum = 0; - for (i = 0; i < elements; i++) - ptr[i] += p->linesize[i]; - // Jump to next aligned position - buf += need_align; - } - break; - case 32: - if (elements == 1) { - av_image_copy_plane(ptr[0], p->linesize[0], - buf, stride, - elements * avctx->width * 4, avctx->height); - } else { - for (y = 0; y < avctx->height; y++) { - ptr[0] = p->data[0] + y * p->linesize[0]; - ptr[1] = p->data[1] + y * p->linesize[1]; - ptr[2] = p->data[2] + y * p->linesize[2]; - ptr[3] = p->data[3] + y * p->linesize[3]; - for (x = 0; x < avctx->width; x++) { - AV_WN32(ptr[2], AV_RN32(buf)); - AV_WN32(ptr[0], AV_RN32(buf + 4)); - AV_WN32(ptr[1], AV_RN32(buf + 8)); - if (avctx->pix_fmt == AV_PIX_FMT_GBRAPF32BE || - avctx->pix_fmt == AV_PIX_FMT_GBRAPF32LE) { - AV_WN32(ptr[3], AV_RN32(buf + 12)); - buf += 4; - ptr[3] += 4; - } + ret = ff_hwaccel_frame_priv_alloc(avctx, &dpx->hwaccel_picture_private); + if (ret < 0) + return ret; - buf += 12; - ptr[2] += 4; - ptr[0] += 4; - ptr[1] += 4; - } - } - } - break; - case 16: - elements *= 2; - case 8: - if ( avctx->pix_fmt == AV_PIX_FMT_YUVA444P - || avctx->pix_fmt == AV_PIX_FMT_YUV444P) { - for (x = 0; x < avctx->height; x++) { - ptr[0] = p->data[0] + x * p->linesize[0]; - ptr[1] = p->data[1] + x * p->linesize[1]; - ptr[2] = p->data[2] + x * p->linesize[2]; - ptr[3] = p->data[3] + x * p->linesize[3]; - for (y = 0; y < avctx->width; y++) { - *ptr[1]++ = *buf++; - *ptr[0]++ = *buf++; - *ptr[2]++ = *buf++; - if (avctx->pix_fmt == AV_PIX_FMT_YUVA444P) - *ptr[3]++ = *buf++; - } - } - } else { - av_image_copy_plane(ptr[0], p->linesize[0], - buf, stride, - elements * avctx->width, avctx->height); - } - break; + ret = hwaccel->start_frame(avctx, avpkt->buf, buf, avpkt->size - offset); + if (ret < 0) + return ret; + + ret = hwaccel->decode_slice(avctx, buf, avpkt->size - offset); + if (ret < 0) + return ret; + + ret = hwaccel->end_frame(avctx); + if (ret < 0) + return ret; + + av_refstruct_unref(&dpx->hwaccel_picture_private); + } else { + unpack_frame(avctx, p, buf, dpx->components, dpx->endian); } + p->pict_type = AV_PICTURE_TYPE_I; + p->flags |= AV_FRAME_FLAG_KEY; + *got_frame = 1; return buf_size; } +#if HAVE_THREADS +static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) +{ + DPXDecContext *ssrc = src->priv_data; + DPXDecContext *sdst = dst->priv_data; + + sdst->pix_fmt = ssrc->pix_fmt; + + return 0; +} +#endif + +static av_cold int decode_end(AVCodecContext *avctx) +{ + DPXDecContext *dpx = avctx->priv_data; + av_refstruct_unref(&dpx->hwaccel_picture_private); + return 0; +} + +static av_cold int decode_init(AVCodecContext *avctx) +{ + DPXDecContext *dpx = avctx->priv_data; + dpx->pix_fmt = AV_PIX_FMT_NONE; + return 0; +} + const FFCodec ff_dpx_decoder = { .p.name = "dpx", CODEC_LONG_NAME("DPX (Digital Picture Exchange) image"), + .priv_data_size = sizeof(DPXDecContext), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_DPX, FF_CODEC_DECODE_CB(decode_frame), - .p.capabilities = AV_CODEC_CAP_DR1, + .init = decode_init, + .close = decode_end, + UPDATE_THREAD_CONTEXT(update_thread_context), + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .hw_configs = (const AVCodecHWConfigInternal *const []) { +#if CONFIG_DPX_VULKAN_HWACCEL + HWACCEL_VULKAN(dpx), +#endif + NULL + }, }; diff --git a/libavcodec/dpx.h b/libavcodec/dpx.h new file mode 100644 index 000000000..c9d95af1f --- /dev/null +++ b/libavcodec/dpx.h @@ -0,0 +1,73 @@ +/* + * DPX (.dpx) image decoder + * Copyright (c) 2009 Jimmy Christensen + * + * 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_DPX_H +#define AVCODEC_DPX_H + +#include "libavutil/frame.h" +#include "libavutil/pixfmt.h" + +enum DPX_TRC { + DPX_TRC_USER_DEFINED = 0, + DPX_TRC_PRINTING_DENSITY = 1, + DPX_TRC_LINEAR = 2, + DPX_TRC_LOGARITHMIC = 3, + DPX_TRC_UNSPECIFIED_VIDEO = 4, + DPX_TRC_SMPTE_274 = 5, + DPX_TRC_ITU_R_709_4 = 6, + DPX_TRC_ITU_R_601_625 = 7, + DPX_TRC_ITU_R_601_525 = 8, + DPX_TRC_SMPTE_170 = 9, + DPX_TRC_ITU_R_624_4_PAL = 10, + DPX_TRC_Z_LINEAR = 11, + DPX_TRC_Z_HOMOGENEOUS = 12, +}; + +enum DPX_COL_SPEC { + DPX_COL_SPEC_USER_DEFINED = 0, + DPX_COL_SPEC_PRINTING_DENSITY = 1, + /* 2 = N/A */ + /* 3 = N/A */ + DPX_COL_SPEC_UNSPECIFIED_VIDEO = 4, + DPX_COL_SPEC_SMPTE_274 = 5, + DPX_COL_SPEC_ITU_R_709_4 = 6, + DPX_COL_SPEC_ITU_R_601_625 = 7, + DPX_COL_SPEC_ITU_R_601_525 = 8, + DPX_COL_SPEC_SMPTE_170 = 9, + DPX_COL_SPEC_ITU_R_624_4_PAL = 10, + /* 11 = N/A */ + /* 12 = N/A */ +}; + +typedef struct DPXDecContext { + AVFrame *frame; + void *hwaccel_picture_private; + enum AVPixelFormat pix_fmt; + + int packing; + int stride; + int endian; + int components; + int unpadded_10bit; + int need_align; +} DPXDecContext; + +#endif /* AVCODEC_DPX_H */ diff --git a/libavcodec/dpx_parser.c b/libavcodec/dpx_parser.c index b74e6c5c6..2b21d0f7a 100644 --- a/libavcodec/dpx_parser.c +++ b/libavcodec/dpx_parser.c @@ -28,6 +28,7 @@ #include "libavutil/common.h" #include "parser.h" +#include "parser_internal.h" typedef struct DPXParseContext { ParseContext pc; @@ -108,9 +109,9 @@ flush: return next; } -const AVCodecParser ff_dpx_parser = { - .codec_ids = { AV_CODEC_ID_DPX }, +const FFCodecParser ff_dpx_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_DPX), .priv_data_size = sizeof(DPXParseContext), - .parser_parse = dpx_parse, - .parser_close = ff_parse_close, + .parse = dpx_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/dpxenc.c b/libavcodec/dpxenc.c index e136cc1b9..e136c7a24 100644 --- a/libavcodec/dpxenc.c +++ b/libavcodec/dpxenc.c @@ -26,6 +26,7 @@ #include "codec_internal.h" #include "encode.h" #include "version.h" +#include "dpx.h" typedef struct DPXContext { int big_endian; @@ -178,6 +179,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, DPXContext *s = avctx->priv_data; int size, ret, need_align, len; uint8_t *buf; + int color_trc, color_spec; #define HEADER_SIZE 1664 /* DPX Generic header */ if (s->bits_per_component == 10) @@ -217,8 +219,46 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, write32(buf + 772, avctx->width); write32(buf + 776, avctx->height); buf[800] = s->descriptor; - buf[801] = 2; /* linear transfer */ - buf[802] = 2; /* linear colorimetric */ + + switch (avctx->color_trc) { + case AVCOL_TRC_BT709: + color_trc = DPX_TRC_ITU_R_709_4; + break; + default: + av_log(avctx, AV_LOG_WARNING, "unsupported color transfer\n"); + case AVCOL_TRC_UNSPECIFIED: + color_trc = DPX_TRC_UNSPECIFIED_VIDEO; + break; + case AVCOL_TRC_GAMMA28: + color_trc = DPX_TRC_ITU_R_624_4_PAL; + break; + case AVCOL_TRC_SMPTE170M: + color_trc = DPX_TRC_SMPTE_170; + break; + case AVCOL_TRC_LINEAR: + color_trc = DPX_TRC_LINEAR; + break; + } + buf[801] = color_trc; + + switch (avctx->color_primaries) { + case AVCOL_PRI_BT709: + color_spec = DPX_COL_SPEC_ITU_R_709_4; + break; + default: + av_log(avctx, AV_LOG_WARNING, "unsupported colorimetric specification\n"); + case AVCOL_PRI_UNSPECIFIED: + color_spec = DPX_COL_SPEC_UNSPECIFIED_VIDEO; + break; + case AVCOL_PRI_BT470BG: + color_spec = DPX_COL_SPEC_ITU_R_624_4_PAL; + break; + case AVCOL_PRI_SMPTE170M: + color_spec = DPX_COL_SPEC_SMPTE_170; + break; + } + buf[802] = color_spec; + buf[803] = s->bits_per_component; write16(buf + 804, (s->bits_per_component == 10 || s->bits_per_component == 12) ? 1 : 0); /* packing method */ @@ -283,13 +323,11 @@ const FFCodec ff_dpx_encoder = { .priv_data_size = sizeof(DPXContext), .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_GRAY8, - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, - AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE, - AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE, - AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE, - AV_PIX_FMT_GBRP10LE, AV_PIX_FMT_GBRP10BE, - AV_PIX_FMT_GBRP12LE, AV_PIX_FMT_GBRP12BE, - AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_GRAY8, + AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, + AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE, + AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE, + AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE, + AV_PIX_FMT_GBRP10LE, AV_PIX_FMT_GBRP10BE, + AV_PIX_FMT_GBRP12LE, AV_PIX_FMT_GBRP12BE), }; diff --git a/libavcodec/dsddec.c b/libavcodec/dsddec.c index dd1ea8378..2d337a7d0 100644 --- a/libavcodec/dsddec.c +++ b/libavcodec/dsddec.c @@ -52,7 +52,7 @@ static av_cold int decode_init(AVCodecContext *avctx) ff_init_dsd_data(); - s = av_malloc_array(sizeof(DSDContext), avctx->ch_layout.nb_channels); + s = av_malloc_array(avctx->ch_layout.nb_channels, sizeof(*s)); if (!s) return AVERROR(ENOMEM); @@ -126,8 +126,6 @@ const FFCodec ff_ ## name_ ## _decoder = { \ .init = decode_init, \ FF_CODEC_DECODE_CB(decode_frame), \ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS, \ - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, \ - AV_SAMPLE_FMT_NONE }, \ }; DSD_DECODER(DSD_LSBF, dsd_lsbf, "DSD (Direct Stream Digital), least significant bit first") diff --git a/libavcodec/dsicinaudio.c b/libavcodec/dsicinaudio.c index aa14966c7..abe7ba991 100644 --- a/libavcodec/dsicinaudio.c +++ b/libavcodec/dsicinaudio.c @@ -81,6 +81,8 @@ static av_cold int cinaudio_decode_init(AVCodecContext *avctx) cin->initial_decode_frame = 1; cin->delta = 0; avctx->sample_fmt = AV_SAMPLE_FMT_S16; + if (!avctx->sample_rate) + avctx->sample_rate = 8000; av_channel_layout_uninit(&avctx->ch_layout); avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; diff --git a/libavcodec/dsicinvideo.c b/libavcodec/dsicinvideo.c index 10b536d40..7001a195e 100644 --- a/libavcodec/dsicinvideo.c +++ b/libavcodec/dsicinvideo.c @@ -294,11 +294,6 @@ static int cinvideo_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return res; memcpy(cin->frame->data[1], cin->palette, sizeof(cin->palette)); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - cin->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif for (y = 0; y < cin->avctx->height; ++y) memcpy(cin->frame->data[0] + (cin->avctx->height - 1 - y) * cin->frame->linesize[0], cin->bitmap_table[CIN_CUR_BMP] + y * cin->avctx->width, diff --git a/libavcodec/dstdec.c b/libavcodec/dstdec.c index 4b1762db3..d74767014 100644 --- a/libavcodec/dstdec.c +++ b/libavcodec/dstdec.c @@ -392,6 +392,4 @@ const FFCodec ff_dst_decoder = { .init = decode_init, FF_CODEC_DECODE_CB(decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/dvaudio_parser.c b/libavcodec/dvaudio_parser.c index ef6bd4558..4edd254a2 100644 --- a/libavcodec/dvaudio_parser.c +++ b/libavcodec/dvaudio_parser.c @@ -23,8 +23,9 @@ * Determines the duration for each packet. */ -#include "parser.h" +#include "avcodec.h" #include "dvaudio.h" +#include "parser_internal.h" static int dvaudio_parse(AVCodecParserContext *s1, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, @@ -40,7 +41,7 @@ static int dvaudio_parse(AVCodecParserContext *s1, AVCodecContext *avctx, return buf_size; } -const AVCodecParser ff_dvaudio_parser = { - .codec_ids = { AV_CODEC_ID_DVAUDIO }, - .parser_parse = dvaudio_parse, +const FFCodecParser ff_dvaudio_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_DVAUDIO), + .parse = dvaudio_parse, }; diff --git a/libavcodec/dvbsub_parser.c b/libavcodec/dvbsub_parser.c index b2d544686..4527e4dd7 100644 --- a/libavcodec/dvbsub_parser.c +++ b/libavcodec/dvbsub_parser.c @@ -25,6 +25,7 @@ #include "libavutil/intreadwrite.h" #include "avcodec.h" +#include "parser_internal.h" /* Parser (mostly) copied from dvdsub.c */ @@ -163,8 +164,8 @@ static int dvbsub_parse(AVCodecParserContext *s, return buf_size; } -const AVCodecParser ff_dvbsub_parser = { - .codec_ids = { AV_CODEC_ID_DVB_SUBTITLE }, +const FFCodecParser ff_dvbsub_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_DVB_SUBTITLE), .priv_data_size = sizeof(DVBSubParseContext), - .parser_parse = dvbsub_parse, + .parse = dvbsub_parse, }; diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c index 4553c45b3..db8a9d1eb 100644 --- a/libavcodec/dvbsubdec.c +++ b/libavcodec/dvbsubdec.c @@ -35,7 +35,7 @@ #define DVBSUB_CLUT_SEGMENT 0x12 #define DVBSUB_OBJECT_SEGMENT 0x13 #define DVBSUB_DISPLAYDEFINITION_SEGMENT 0x14 -#define DVBSUB_DISPLAY_SEGMENT 0x80 +#define DVBSUB_END_DISPLAY_SEGMENT 0x80 #define cm (ff_crop_tab + MAX_NEG_CROP) @@ -612,15 +612,16 @@ static int dvbsub_read_8bit_string(AVCodecContext *avctx, const uint8_t **srcbuf, int buf_size, int non_mod, uint8_t *map_table, int x_pos) { - const uint8_t *sbuf_end = (*srcbuf) + buf_size; int bits; int run_length; int pixels_read = x_pos; + GetByteContext gb0, *const gb = &gb0; + bytestream2_init(gb, *srcbuf, buf_size); destbuf += x_pos; - while (*srcbuf < sbuf_end && pixels_read < dbuf_len) { - bits = *(*srcbuf)++; + while (bytestream2_get_bytes_left(gb) && pixels_read < dbuf_len) { + bits = bytestream2_get_byteu(gb); if (bits) { if (non_mod != 1 || bits != 1) { @@ -631,16 +632,17 @@ static int dvbsub_read_8bit_string(AVCodecContext *avctx, } pixels_read++; } else { - bits = *(*srcbuf)++; + bits = bytestream2_get_byte(gb); run_length = bits & 0x7f; if ((bits & 0x80) == 0) { if (run_length == 0) { + *srcbuf += bytestream2_tell(gb); return pixels_read; } bits = 0; } else { - bits = *(*srcbuf)++; + bits = bytestream2_get_byte(gb); } if (non_mod == 1 && bits == 1) pixels_read += run_length; @@ -655,9 +657,14 @@ static int dvbsub_read_8bit_string(AVCodecContext *avctx, } } - if (*(*srcbuf)++) + if (bytestream2_get_byte(gb)) av_log(avctx, AV_LOG_ERROR, "line overflow\n"); + /* Workaround our own buggy encoder which only put one zero at the end */ + if (!bytestream2_peek_byte(gb)) + bytestream2_get_byte(gb); + + *srcbuf += bytestream2_tell(gb); return pixels_read; } @@ -1147,7 +1154,7 @@ static int dvbsub_parse_region_segment(AVCodecContext *avctx, const uint8_t *buf_end = buf + buf_size; int region_id, object_id; - int av_unused version; + av_unused int version; DVBSubRegion *region; DVBSubObject *object; DVBSubObjectDisplay *display; @@ -1451,8 +1458,11 @@ static int dvbsub_decode(AVCodecContext *avctx, AVSubtitle *sub, int segment_length; int i; int ret = 0; - int got_segment = 0; - int got_dds = 0; + int got_page = 0; + int got_region = 0; + int got_object = 0; + int got_end_display = 0; + int got_displaydef = 0; ff_dlog(avctx, "DVB sub packet:\n"); @@ -1497,34 +1507,28 @@ static int dvbsub_decode(AVCodecContext *avctx, AVSubtitle *sub, switch (segment_type) { case DVBSUB_PAGE_SEGMENT: ret = dvbsub_parse_page_segment(avctx, p, segment_length, sub, got_sub_ptr); - got_segment |= 1; + got_page = 1; break; case DVBSUB_REGION_SEGMENT: ret = dvbsub_parse_region_segment(avctx, p, segment_length); - got_segment |= 2; + got_region = 1; break; case DVBSUB_CLUT_SEGMENT: ret = dvbsub_parse_clut_segment(avctx, p, segment_length); if (ret < 0) goto end; - got_segment |= 4; break; case DVBSUB_OBJECT_SEGMENT: ret = dvbsub_parse_object_segment(avctx, p, segment_length); - got_segment |= 8; + got_object = 1; break; case DVBSUB_DISPLAYDEFINITION_SEGMENT: ret = dvbsub_parse_display_definition_segment(avctx, p, segment_length); - got_dds = 1; + got_displaydef = 1; break; - case DVBSUB_DISPLAY_SEGMENT: + case DVBSUB_END_DISPLAY_SEGMENT: ret = dvbsub_display_end_segment(avctx, p, segment_length, sub, got_sub_ptr); - if (got_segment == 15 && !got_dds && !avctx->width && !avctx->height) { - // Default from ETSI EN 300 743 V1.3.1 (7.2.1) - avctx->width = 720; - avctx->height = 576; - } - got_segment |= 16; + got_end_display = 1; break; default: ff_dlog(avctx, "Subtitling segment type 0x%x, page id %d, length %d\n", @@ -1537,13 +1541,24 @@ static int dvbsub_decode(AVCodecContext *avctx, AVSubtitle *sub, p += segment_length; } - // Some streams do not send a display segment but if we have all the other - // segments then we need no further data. - if (got_segment == 15) { - av_log(avctx, AV_LOG_DEBUG, "Missing display_end_segment, emulating\n"); - dvbsub_display_end_segment(avctx, p, 0, sub, got_sub_ptr); - } + // Even though not mandated by the spec, we're imposing a minimum requirement + // for a useful packet to have at least one page, region and object segment. + if (got_page && got_region && got_object) { + + if (!got_displaydef && !avctx->width && !avctx->height) { + // Default from ETSI EN 300 743 V1.3.1 (7.2.1) + avctx->width = 720; + avctx->height = 576; + } + + // Some streams do not send an end-of-display segment but if we have all the other + // segments then we need no further data. + if (!got_end_display) { + av_log(avctx, AV_LOG_DEBUG, "Missing display_end_segment, emulating\n"); + dvbsub_display_end_segment(avctx, p, 0, sub, got_sub_ptr); + } + } end: if (ret < 0) { return ret; diff --git a/libavcodec/dvbsubenc.c b/libavcodec/dvbsubenc.c index 822e3a530..6f42b1f13 100644 --- a/libavcodec/dvbsubenc.c +++ b/libavcodec/dvbsubenc.c @@ -22,9 +22,12 @@ #include "bytestream.h" #include "codec_internal.h" #include "libavutil/colorspace.h" +#include "libavutil/opt.h" typedef struct DVBSubtitleContext { + AVClass * class; int object_version; + int min_bpp; } DVBSubtitleContext; #define PUTBITS2(val)\ @@ -258,7 +261,8 @@ static int dvb_encode_rle8(uint8_t **pq, int buf_size, x += len; } /* end of line */ - // 00000000 end of 8-bit/pixel_code_string + // 00000000 00000000 end of 8-bit/pixel_code_string + *q++ = 0x00; *q++ = 0x00; *q++ = 0xf0; bitmap += linesize; @@ -274,16 +278,30 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, { DVBSubtitleContext *s = avctx->priv_data; uint8_t *q, *pseg_len; - int page_id, region_id, clut_id, object_id, i, bpp_index, page_state; + int page_id, region_id, clut_id, object_id, i, bpp_index, page_state, min_colors; q = outbuf; page_id = 1; + switch(s->min_bpp) { + case 2: + case 4: + case 8: + min_colors = 1 << s->min_bpp; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Invalid min_bpp value %d.\n", s->min_bpp); + return AVERROR(EINVAL); + } + if (h->num_rects && !h->rects) return AVERROR(EINVAL); + if (h->num_rects >= 256) + return AVERROR(EINVAL); + if (avctx->width > 0 && avctx->height > 0) { if (buf_size < 11) return AVERROR_BUFFER_TOO_SMALL; @@ -326,24 +344,24 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, if (h->num_rects) { for (clut_id = 0; clut_id < h->num_rects; clut_id++) { - if (buf_size < 6 + h->rects[clut_id]->nb_colors * 6) - return AVERROR_BUFFER_TOO_SMALL; - /* CLUT segment */ + int nb_colors = FFMAX(min_colors, h->rects[clut_id]->nb_colors); - if (h->rects[clut_id]->nb_colors <= 4) { + if (nb_colors <= 4U) { /* 2 bpp, some decoders do not support it correctly */ bpp_index = 0; - } else if (h->rects[clut_id]->nb_colors <= 16) { + } else if (nb_colors <= 16U) { /* 4 bpp, standard encoding */ bpp_index = 1; - } else if (h->rects[clut_id]->nb_colors <= 256) { + } else if (nb_colors <= 256U) { /* 8 bpp, standard encoding */ bpp_index = 2; } else { return AVERROR(EINVAL); } + if (buf_size < 6 + h->rects[clut_id]->nb_colors * 6) + return AVERROR_BUFFER_TOO_SMALL; /* CLUT segment */ *q++ = 0x0f; /* sync byte */ @@ -381,14 +399,15 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, for (region_id = 0; region_id < h->num_rects; region_id++) { /* region composition segment */ + int nb_colors = FFMAX(min_colors, h->rects[region_id]->nb_colors); - if (h->rects[region_id]->nb_colors <= 4) { + if (nb_colors <= 4) { /* 2 bpp, some decoders do not support it correctly */ bpp_index = 0; - } else if (h->rects[region_id]->nb_colors <= 16) { + } else if (nb_colors <= 16) { /* 4 bpp, standard encoding */ bpp_index = 1; - } else if (h->rects[region_id]->nb_colors <= 256) { + } else if (nb_colors <= 256) { /* 8 bpp, standard encoding */ bpp_index = 2; } else { @@ -424,17 +443,19 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, const uint8_t *bitmap, int linesize, int w, int h); + int nb_colors = FFMAX(min_colors, h->rects[object_id]->nb_colors); + if (buf_size < 13) return AVERROR_BUFFER_TOO_SMALL; /* bpp_index maths */ - if (h->rects[object_id]->nb_colors <= 4) { + if (nb_colors <= 4) { /* 2 bpp, some decoders do not support it correctly */ dvb_encode_rle = dvb_encode_rle2; - } else if (h->rects[object_id]->nb_colors <= 16) { + } else if (nb_colors <= 16) { /* 4 bpp, standard encoding */ dvb_encode_rle = dvb_encode_rle4; - } else if (h->rects[object_id]->nb_colors <= 256) { + } else if (nb_colors <= 256) { /* 8 bpp, standard encoding */ dvb_encode_rle = dvb_encode_rle8; } else { @@ -506,6 +527,20 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, return q - outbuf; } +#define OFFSET(x) offsetof(DVBSubtitleContext, x) +#define SE AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + {"min_bpp", "minimum bits-per-pixel for subtitle colors (2, 4 or 8)", OFFSET(min_bpp), AV_OPT_TYPE_INT, {.i64 = 4}, 2, 8, SE}, + { NULL }, +}; + +static const AVClass dvbsubenc_class = { + .class_name = "DVBSUB subtitle encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + const FFCodec ff_dvbsub_encoder = { .p.name = "dvbsub", CODEC_LONG_NAME("DVB subtitles"), @@ -513,4 +548,5 @@ const FFCodec ff_dvbsub_encoder = { .p.id = AV_CODEC_ID_DVB_SUBTITLE, .priv_data_size = sizeof(DVBSubtitleContext), FF_CODEC_ENCODE_SUB_CB(dvbsub_encode), + .p.priv_class = &dvbsubenc_class, }; diff --git a/libavcodec/dvd_nav_parser.c b/libavcodec/dvd_nav_parser.c index 3ea4cd1ef..ec4aba18f 100644 --- a/libavcodec/dvd_nav_parser.c +++ b/libavcodec/dvd_nav_parser.c @@ -18,9 +18,10 @@ * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + #include "avcodec.h" -#include "get_bits.h" -#include "parser.h" +#include "parser_internal.h" +#include "libavutil/intreadwrite.h" #define PCI_SIZE 980 #define DSI_SIZE 1018 @@ -107,9 +108,9 @@ static int dvd_nav_parse(AVCodecParserContext *s, return buf_size; } -const AVCodecParser ff_dvd_nav_parser = { - .codec_ids = { AV_CODEC_ID_DVD_NAV }, +const FFCodecParser ff_dvd_nav_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_DVD_NAV), .priv_data_size = sizeof(DVDNavParseContext), - .parser_init = dvd_nav_parse_init, - .parser_parse = dvd_nav_parse, + .init = dvd_nav_parse_init, + .parse = dvd_nav_parse, }; diff --git a/libavcodec/dvdec.c b/libavcodec/dvdec.c index 8297b6d2f..4799ec96d 100644 --- a/libavcodec/dvdec.c +++ b/libavcodec/dvdec.c @@ -36,7 +36,6 @@ */ #include "libavutil/avassert.h" -#include "libavutil/emms.h" #include "libavutil/internal.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" @@ -159,15 +158,15 @@ static av_cold void dv_init_static(void) /* it's faster to include sign bit in a generic VLC parsing scheme */ for (i = 0, j = 0; i < NB_DV_VLC; i++, j++) { - tmp[j].len = ff_dv_vlc_len[i]; + tmp[j].len8 = ff_dv_vlc_len[i]; tmp[j].run = ff_dv_vlc_run[i]; tmp[j].level = ff_dv_vlc_level[i]; if (ff_dv_vlc_level[i]) { - tmp[j].len++; + tmp[j].len8++; j++; - tmp[j].len = ff_dv_vlc_len[i] + 1; + tmp[j].len8 = ff_dv_vlc_len[i] + 1; tmp[j].run = ff_dv_vlc_run[i]; tmp[j].level = -ff_dv_vlc_level[i]; } @@ -176,7 +175,7 @@ static av_cold void dv_init_static(void) /* NOTE: as a trick, we use the fact the no codes are unused * to accelerate the parsing of partial codes */ ff_vlc_init_from_lengths(&dv_vlc, TEX_VLC_BITS, j, - &tmp[0].len, sizeof(tmp[0]), + &tmp[0].len8, sizeof(tmp[0]), NULL, 0, 0, 0, VLC_INIT_USE_STATIC, NULL); av_assert1(dv_vlc.table_size == 1664); @@ -193,7 +192,7 @@ static av_cold void dv_init_static(void) run = tmp[code].run + 1; level = tmp[code].level; } - dv_rl_vlc[i].len = len; + dv_rl_vlc[i].len8 = len; dv_rl_vlc[i].level = level; dv_rl_vlc[i].run = run; } @@ -301,7 +300,7 @@ static void dv_decode_ac(GetBitContext *gb, BlockInfo *mb, int16_t *block) pos, SHOW_UBITS(re, gb, 16), re_index); /* our own optimized GET_RL_VLC */ index = NEG_USR32(re_cache, TEX_VLC_BITS); - vlc_len = dv_rl_vlc[index].len; + vlc_len = dv_rl_vlc[index].len8; if (vlc_len < 0) { index = NEG_USR32((unsigned) re_cache << TEX_VLC_BITS, -vlc_len) + dv_rl_vlc[index].level; @@ -683,8 +682,6 @@ static int dvvideo_decode_frame(AVCodecContext *avctx, AVFrame *frame, avctx->execute(avctx, dv_decode_video_segment, s->work_chunks, NULL, dv_work_pool_size(s->sys), sizeof(DVwork_chunk)); - emms_c(); - /* return image */ *got_frame = 1; diff --git a/libavcodec/dvdsub_parser.c b/libavcodec/dvdsub_parser.c index 400bdb8b9..6ac218315 100644 --- a/libavcodec/dvdsub_parser.c +++ b/libavcodec/dvdsub_parser.c @@ -24,6 +24,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "avcodec.h" +#include "parser_internal.h" /* parser definition */ typedef struct DVDSubParseContext { @@ -84,9 +85,9 @@ static av_cold void dvdsub_parse_close(AVCodecParserContext *s) av_freep(&pc->packet); } -const AVCodecParser ff_dvdsub_parser = { - .codec_ids = { AV_CODEC_ID_DVD_SUBTITLE }, +const FFCodecParser ff_dvdsub_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_DVD_SUBTITLE), .priv_data_size = sizeof(DVDSubParseContext), - .parser_parse = dvdsub_parse, - .parser_close = dvdsub_parse_close, + .parse = dvdsub_parse, + .close = dvdsub_parse_close, }; diff --git a/libavcodec/dvdsubdec.c b/libavcodec/dvdsubdec.c index f8769353a..9f9845bf8 100644 --- a/libavcodec/dvdsubdec.c +++ b/libavcodec/dvdsubdec.c @@ -217,8 +217,8 @@ static void reset_rects(AVSubtitle *sub_header) #define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a)) -static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, - const uint8_t *buf, int buf_size) +static int decode_dvd_subtitles(void *logctx, DVDSubContext *ctx, + AVSubtitle *sub_header, const uint8_t *buf, int buf_size) { int cmd_pos, pos, cmd, x1, y1, x2, y2, next_cmd_pos; int big_offsets, offset_size, is_8bit = 0; @@ -248,7 +248,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, if (cmd_pos < 0 || cmd_pos > buf_size - 2 - offset_size) { if (cmd_pos > size) { - av_log(ctx, AV_LOG_ERROR, "Discarding invalid packet\n"); + av_log(logctx, AV_LOG_ERROR, "Discarding invalid packet\n"); return 0; } return AVERROR(EAGAIN); @@ -257,7 +257,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) { date = AV_RB16(buf + cmd_pos); next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2); - ff_dlog(NULL, "cmd_pos=0x%04x next=0x%04x date=%d\n", + ff_dlog(logctx, "cmd_pos=0x%04x next=0x%04x date=%d\n", cmd_pos, next_cmd_pos, date); pos = cmd_pos + 2 + offset_size; offset1 = -1; @@ -265,7 +265,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, x1 = y1 = x2 = y2 = 0; while (pos < buf_size) { cmd = buf[pos++]; - ff_dlog(NULL, "cmd=%02x\n", cmd); + ff_dlog(logctx, "cmd=%02x\n", cmd); switch(cmd) { case 0x00: /* menu subpicture */ @@ -298,7 +298,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, alpha[1] = buf[pos + 1] >> 4; alpha[0] = buf[pos + 1] & 0x0f; pos += 2; - ff_dlog(NULL, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]); + ff_dlog(logctx, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]); break; case 0x05: case 0x85: @@ -310,7 +310,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5]; if (cmd & 0x80) is_8bit = 1; - ff_dlog(NULL, "x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2); + ff_dlog(logctx, "x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2); pos += 6; break; case 0x06: @@ -318,7 +318,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, goto fail; offset1 = AV_RB16(buf + pos); offset2 = AV_RB16(buf + pos + 2); - ff_dlog(NULL, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2); + ff_dlog(logctx, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2); pos += 4; break; case 0x86: @@ -326,7 +326,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, goto fail; offset1 = AV_RB32(buf + pos); offset2 = AV_RB32(buf + pos + 4); - ff_dlog(NULL, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2); + ff_dlog(logctx, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2); pos += 8; break; @@ -349,7 +349,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, case 0xff: goto the_end; default: - ff_dlog(NULL, "unrecognised subpicture command 0x%x\n", cmd); + ff_dlog(logctx, "unrecognised subpicture command 0x%x\n", cmd); goto the_end; } } @@ -412,7 +412,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, } } if (next_cmd_pos < cmd_pos) { - av_log(ctx, AV_LOG_ERROR, "Invalid command offset\n"); + av_log(logctx, AV_LOG_ERROR, "Invalid command offset\n"); break; } if (next_cmd_pos == cmd_pos) @@ -535,7 +535,7 @@ static int dvdsub_decode(AVCodecContext *avctx, AVSubtitle *sub, appended = 1; } - is_menu = decode_dvd_subtitles(ctx, sub, buf, buf_size); + is_menu = decode_dvd_subtitles(avctx, ctx, sub, buf, buf_size); if (is_menu == AVERROR(EAGAIN)) { *data_size = 0; return appended ? 0 : append_to_cached_buf(avctx, buf, buf_size); @@ -560,7 +560,7 @@ static int dvdsub_decode(AVCodecContext *avctx, AVSubtitle *sub, return buf_size; } -static int parse_ifo_palette(DVDSubContext *ctx, char *p) +static int parse_ifo_palette(void *logctx, DVDSubContext *ctx, char *p) { FILE *ifo; char ifostr[12]; @@ -572,11 +572,11 @@ static int parse_ifo_palette(DVDSubContext *ctx, char *p) ctx->has_palette = 0; if ((ifo = avpriv_fopen_utf8(p, "r")) == NULL) { - av_log(ctx, AV_LOG_WARNING, "Unable to open IFO file \"%s\": %s\n", p, av_err2str(AVERROR(errno))); + av_log(logctx, AV_LOG_WARNING, "Unable to open IFO file \"%s\": %s\n", p, av_err2str(AVERROR(errno))); return AVERROR_EOF; } if (fread(ifostr, 12, 1, ifo) != 1 || memcmp(ifostr, "DVDVIDEO-VTS", 12)) { - av_log(ctx, AV_LOG_WARNING, "\"%s\" is not a proper IFO file\n", p); + av_log(logctx, AV_LOG_WARNING, "\"%s\" is not a proper IFO file\n", p); ret = AVERROR_INVALIDDATA; goto end; } @@ -612,7 +612,7 @@ static int parse_ifo_palette(DVDSubContext *ctx, char *p) } } if (ctx->has_palette == 0) { - av_log(ctx, AV_LOG_WARNING, "Failed to read palette from IFO file \"%s\"\n", p); + av_log(logctx, AV_LOG_WARNING, "Failed to read palette from IFO file \"%s\"\n", p); ret = AVERROR_INVALIDDATA; } end: @@ -624,10 +624,10 @@ static int dvdsub_parse_extradata(AVCodecContext *avctx) { DVDSubContext *ctx = (DVDSubContext*) avctx->priv_data; char *dataorig, *data; - int ret = 1; + int ret; if (!avctx->extradata || !avctx->extradata_size) - return 1; + return 0; dataorig = data = av_malloc(avctx->extradata_size+1); if (!data) @@ -656,6 +656,7 @@ static int dvdsub_parse_extradata(AVCodecContext *avctx) data += strspn(data, "\n\r"); } + ret = 0; fail: av_free(dataorig); return ret; @@ -670,7 +671,7 @@ static av_cold int dvdsub_init(AVCodecContext *avctx) return ret; if (ctx->ifo_str) - parse_ifo_palette(ctx, ctx->ifo_str); + parse_ifo_palette(avctx, ctx, ctx->ifo_str); if (ctx->palette_str) { ctx->has_palette = 1; ff_dvdsub_parse_palette(ctx->palette, ctx->palette_str); @@ -683,10 +684,10 @@ static av_cold int dvdsub_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_DEBUG, "\n"); } - return 1; + return 0; } -static void dvdsub_flush(AVCodecContext *avctx) +static av_cold void dvdsub_flush(AVCodecContext *avctx) { DVDSubContext *ctx = avctx->priv_data; ctx->buf_size = 0; diff --git a/libavcodec/dvdsubenc.c b/libavcodec/dvdsubenc.c index c6110c29f..2a5463b8d 100644 --- a/libavcodec/dvdsubenc.c +++ b/libavcodec/dvdsubenc.c @@ -250,9 +250,9 @@ static void copy_rectangle(AVSubtitleRect *dst, AVSubtitleRect *src, int cmap[]) } } -static int encode_dvd_subtitles(AVCodecContext *avctx, - uint8_t *outbuf, int outbuf_size, - const AVSubtitle *h) +static int dvdsub_encode(AVCodecContext *avctx, + uint8_t *outbuf, int outbuf_size, + const AVSubtitle *h) { DVDSubtitleContext *dvdc = avctx->priv_data; uint8_t *q, *qq; @@ -411,7 +411,7 @@ static int encode_dvd_subtitles(AVCodecContext *avctx, qq = outbuf; bytestream_put_be16(&qq, q - outbuf); - av_log(NULL, AV_LOG_DEBUG, "subtitle_packet size=%"PTRDIFF_SPECIFIER"\n", q - outbuf); + av_log(NULL, AV_LOG_DEBUG, "subtitle_packet size=%td\n", q - outbuf); ret = q - outbuf; fail: @@ -442,7 +442,7 @@ static int bprint_to_extradata(AVCodecContext *avctx, struct AVBPrint *buf) return 0; } -static int dvdsub_init(AVCodecContext *avctx) +static av_cold int dvdsub_init(AVCodecContext *avctx) { DVDSubtitleContext *dvdc = avctx->priv_data; static const uint32_t default_palette[16] = { @@ -476,17 +476,6 @@ static int dvdsub_init(AVCodecContext *avctx) return 0; } -static int dvdsub_encode(AVCodecContext *avctx, - unsigned char *buf, int buf_size, - const AVSubtitle *sub) -{ - //DVDSubtitleContext *s = avctx->priv_data; - int ret; - - ret = encode_dvd_subtitles(avctx, buf, buf_size, sub); - return ret; -} - #define OFFSET(x) offsetof(DVDSubtitleContext, x) #define SE AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { diff --git a/libavcodec/dvenc.c b/libavcodec/dvenc.c index db79497b5..f25c3ddfe 100644 --- a/libavcodec/dvenc.c +++ b/libavcodec/dvenc.c @@ -56,13 +56,15 @@ typedef struct DVEncContext { AVCodecContext *avctx; uint8_t *buf; - void (*get_pixels)(int16_t *block, const uint8_t *pixels, ptrdiff_t linesize); + void (*get_pixels)(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t linesize); void (*fdct[2])(int16_t *block); me_cmp_func ildct_cmp; DVwork_chunk work_chunks[4 * 12 * 27]; int quant_deadzone; + + PixblockDSPContext pdsp; } DVEncContext; @@ -70,7 +72,6 @@ static av_cold int dvvideo_encode_init(AVCodecContext *avctx) { DVEncContext *s = avctx->priv_data; FDCTDSPContext fdsp; - PixblockDSPContext pdsp; int ret; s->avctx = avctx; @@ -108,12 +109,10 @@ static av_cold int dvvideo_encode_init(AVCodecContext *avctx) } memset(&fdsp,0, sizeof(fdsp)); - memset(&pdsp,0, sizeof(pdsp)); ff_fdctdsp_init(&fdsp, avctx); - ff_pixblockdsp_init(&pdsp, avctx); - s->get_pixels = pdsp.get_pixels; s->fdct[0] = fdsp.fdct; s->fdct[1] = fdsp.fdct248; + ff_pixblockdsp_init(&s->pdsp, 8); #if !CONFIG_HARDCODED_TABLES { @@ -1201,6 +1200,14 @@ static int dvvideo_encode_frame(AVCodecContext *c, AVPacket *pkt, DVEncContext *s = c->priv_data; int ret; + if (!PIXBLOCKDSP_8BPP_GET_PIXELS_SUPPORTS_UNALIGNED && + ((uintptr_t)frame->data[0] & 7 || frame->linesize[0] & 7 || + (uintptr_t)frame->data[1] & 7 || frame->linesize[1] & 7 || + (uintptr_t)frame->data[2] & 7 || frame->linesize[2] & 7)) + s->get_pixels = s->pdsp.get_pixels_unaligned; + else + s->get_pixels = s->pdsp.get_pixels; + if ((ret = ff_get_encode_buffer(c, pkt, s->sys->frame_size, 0)) < 0) return ret; /* Fixme: Only zero the part that is not overwritten later. */ @@ -1247,10 +1254,7 @@ const FFCodec ff_dvvideo_encoder = { .priv_data_size = sizeof(DVEncContext), .init = dvvideo_encode_init, FF_CODEC_ENCODE_CB(dvvideo_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV422P, - AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &dvvideo_encode_class, }; diff --git a/libavcodec/dxa.c b/libavcodec/dxa.c index 59e2411d8..5b429781d 100644 --- a/libavcodec/dxa.c +++ b/libavcodec/dxa.c @@ -213,7 +213,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, unsigned long dsize; int i, j, compr, ret; int stride; - int pc = 0; GetByteContext gb; bytestream2_init(&gb, avpkt->data, avpkt->size); @@ -224,17 +223,11 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, for(i = 0; i < 256; i++){ c->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&gb); } - pc = 1; } if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) return ret; memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = pc; -FF_ENABLE_DEPRECATION_WARNINGS -#endif outptr = frame->data[0]; srcptr = c->decomp_buf; diff --git a/libavcodec/dxv.c b/libavcodec/dxv.c index b043709af..626dd75a3 100644 --- a/libavcodec/dxv.c +++ b/libavcodec/dxv.c @@ -1077,7 +1077,7 @@ static int dxv_decode(AVCodecContext *avctx, AVFrame *frame, return avpkt->size; } -static int dxv_init(AVCodecContext *avctx) +static av_cold int dxv_init(AVCodecContext *avctx) { DXVContext *ctx = avctx->priv_data; int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx); @@ -1097,7 +1097,7 @@ static int dxv_init(AVCodecContext *avctx) return 0; } -static int dxv_close(AVCodecContext *avctx) +static av_cold int dxv_close(AVCodecContext *avctx) { DXVContext *ctx = avctx->priv_data; diff --git a/libavcodec/dxv.h b/libavcodec/dxv.h index 71cfddec8..184813e42 100644 --- a/libavcodec/dxv.h +++ b/libavcodec/dxv.h @@ -1,6 +1,6 @@ /* * Resolume DXV common - * Copyright (C) 2024 Connor Worley + * Copyright (C) 2024 Emma Worley * * This file is part of FFmpeg. * diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c index 22ecd5aca..a282e6c0c 100644 --- a/libavcodec/dxva2.c +++ b/libavcodec/dxva2.c @@ -773,7 +773,6 @@ unsigned ff_dxva2_get_surface_index(const AVCodecContext *avctx, int curr) { void *surface = get_surface(avctx, frame); - unsigned i; #if CONFIG_D3D12VA if (avctx->pix_fmt == AV_PIX_FMT_D3D12) { @@ -790,7 +789,7 @@ unsigned ff_dxva2_get_surface_index(const AVCodecContext *avctx, } #endif #if CONFIG_DXVA2 - for (i = 0; i < DXVA_CONTEXT_COUNT(avctx, ctx); i++) { + for (unsigned i = 0; i < DXVA_CONTEXT_COUNT(avctx, ctx); i++) { if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD && ctx->dxva2.surface[i] == surface) return i; } diff --git a/libavcodec/dxva2_av1.c b/libavcodec/dxva2_av1.c index ea97fcb87..47866ff4c 100644 --- a/libavcodec/dxva2_av1.c +++ b/libavcodec/dxva2_av1.c @@ -272,6 +272,7 @@ int ff_dxva2_av1_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACont } static int dxva2_av1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { @@ -450,7 +451,7 @@ static int dxva2_av1_end_frame(AVCodecContext *avctx) return ret; } -static int dxva2_av1_uninit(AVCodecContext *avctx) +static av_cold int dxva2_av1_uninit(AVCodecContext *avctx) { struct AV1DXVAContext *ctx = avctx->internal->hwaccel_priv_data; diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c index 0fe415262..dd9dccbf8 100644 --- a/libavcodec/dxva2_h264.c +++ b/libavcodec/dxva2_h264.c @@ -444,6 +444,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, static int dxva2_h264_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/dxva2_hevc.c b/libavcodec/dxva2_hevc.c index d01d1e76e..85698dfcc 100644 --- a/libavcodec/dxva2_hevc.c +++ b/libavcodec/dxva2_hevc.c @@ -363,6 +363,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, static int dxva2_hevc_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h index 224a867eb..6cbd0e42d 100644 --- a/libavcodec/dxva2_internal.h +++ b/libavcodec/dxva2_internal.h @@ -171,11 +171,15 @@ void ff_dxva2_h264_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACo void ff_dxva2_h264_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_Qmatrix_H264 *qm); +#if CONFIG_HEVC_D3D12VA_HWACCEL || CONFIG_HEVC_D3D11VA_HWACCEL || CONFIG_HEVC_D3D11VA2_HWACCEL || CONFIG_HEVC_DXVA2_HWACCEL void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_HEVC *pp); void ff_dxva2_hevc_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_Qmatrix_HEVC *qm); +#endif +#if CONFIG_VP9_D3D12VA_HWACCEL || CONFIG_VP9_D3D11VA_HWACCEL || CONFIG_VP9_D3D11VA2_HWACCEL || CONFIG_VP9_DXVA2_HWACCEL int ff_dxva2_vp9_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_VP9 *pp); +#endif #if CONFIG_AV1_D3D12VA_HWACCEL || CONFIG_AV1_D3D11VA_HWACCEL || CONFIG_AV1_D3D11VA2_HWACCEL || CONFIG_AV1_DXVA2_HWACCEL int ff_dxva2_av1_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_AV1 *pp); diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c index d88e78241..7955bcdea 100644 --- a/libavcodec/dxva2_mpeg2.c +++ b/libavcodec/dxva2_mpeg2.c @@ -257,6 +257,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, } static int dxva2_mpeg2_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/dxva2_vc1.c b/libavcodec/dxva2_vc1.c index bc9ad9648..f1dcea1e8 100644 --- a/libavcodec/dxva2_vc1.c +++ b/libavcodec/dxva2_vc1.c @@ -108,7 +108,7 @@ void ff_dxva2_vc1_fill_picture_parameters(AVCodecContext *avctx, pp->bRcontrol = v->rnd; pp->bPicSpatialResid8 = (v->panscanflag << 7) | (v->refdist_flag << 6) | - (s->loop_filter << 5) | + (v->loop_filter << 5) | (v->fastuvmc << 4) | (v->extended_mv << 3) | (v->dquant << 1) | @@ -117,11 +117,11 @@ void ff_dxva2_vc1_fill_picture_parameters(AVCodecContext *avctx, (v->multires << 5) | (v->resync_marker << 4) | (v->rangered << 3) | - (s->max_b_frames ); + (v->max_b_frames ); pp->bPicExtrapolation = (!v->interlace || v->fcm == PROGRESSIVE) ? 1 : 2; pp->bPicDeblocked = ((!pp->bPicBackwardPrediction && v->overlap) << 6) | ((v->profile != PROFILE_ADVANCED && v->rangeredfrm) << 5) | - (s->loop_filter << 1); + (v->loop_filter << 1); pp->bPicDeblockConfined = (v->postprocflag << 7) | (v->broadcast << 6) | (v->interlace << 5) | @@ -177,7 +177,7 @@ void ff_dxva2_vc1_fill_slice(AVCodecContext *avctx, DXVA_SliceInfo *slice, slice->dwSliceDataLocation = position; slice->bStartCodeBitOffset = 0; slice->bReservedBits = (s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type) ? v->bfraction_lut_index + 9 : 0; - slice->wMBbitOffset = v->p_frame_skipped ? 0xffff : get_bits_count(&s->gb) + (avctx->codec_id == AV_CODEC_ID_VC1 ? 32 : 0); + slice->wMBbitOffset = v->p_frame_skipped ? 0xffff : get_bits_count(&v->gb) + (avctx->codec_id == AV_CODEC_ID_VC1 ? 32 : 0); /* XXX We store the index of the first MB and it will be fixed later */ slice->wNumberMBsInSlice = (s->mb_y >> v->field_mode) * s->mb_width + s->mb_x; slice->wQuantizerScaleCode = v->pq; @@ -315,6 +315,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, } static int dxva2_vc1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/dxva2_vp9.c b/libavcodec/dxva2_vp9.c index f4ab91c58..cffa95e1d 100644 --- a/libavcodec/dxva2_vp9.c +++ b/libavcodec/dxva2_vp9.c @@ -254,6 +254,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, static int dxva2_vp9_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/dxvenc.c b/libavcodec/dxvenc.c index 822943837..0a2dd8077 100644 --- a/libavcodec/dxvenc.c +++ b/libavcodec/dxvenc.c @@ -1,6 +1,6 @@ /* * Resolume DXV encoder - * Copyright (C) 2024 Connor Worley + * Copyright (C) 2024 Emma Worley * * This file is part of FFmpeg. * @@ -21,7 +21,7 @@ #include -#include "libavutil/crc.h" +#include "libavcodec/hashtable.h" #include "libavutil/imgutils.h" #include "libavutil/mem.h" #include "libavutil/opt.h" @@ -34,77 +34,19 @@ #define DXV_HEADER_LENGTH 12 +/* + * Resolume will refuse to display frames that are not padded to 16x16 pixels. + */ +#define DXV_ALIGN(x) FFALIGN(x, 16) + /* * DXV uses LZ-like back-references to avoid copying words that have already * appeared in the decompressed stream. Using a simple hash table (HT) * significantly speeds up the lookback process while encoding. */ -#define LOOKBACK_HT_ELEMS 0x40000 +#define LOOKBACK_HT_ELEMS 0x20202 #define LOOKBACK_WORDS 0x20202 -typedef struct HTEntry { - uint32_t key; - uint32_t pos; -} HTEntry; - -static void ht_init(HTEntry *ht) -{ - for (size_t i = 0; i < LOOKBACK_HT_ELEMS; i++) { - ht[i].pos = -1; - } -} - -static uint32_t ht_lookup_and_upsert(HTEntry *ht, const AVCRC *hash_ctx, - uint32_t key, uint32_t pos) -{ - uint32_t ret = -1; - size_t hash = av_crc(hash_ctx, 0, (uint8_t*)&key, 4) % LOOKBACK_HT_ELEMS; - for (size_t i = hash; i < hash + LOOKBACK_HT_ELEMS; i++) { - size_t wrapped_index = i % LOOKBACK_HT_ELEMS; - HTEntry *entry = &ht[wrapped_index]; - if (entry->key == key || entry->pos == -1) { - ret = entry->pos; - entry->key = key; - entry->pos = pos; - break; - } - } - return ret; -} - -static void ht_delete(HTEntry *ht, const AVCRC *hash_ctx, - uint32_t key, uint32_t pos) -{ - HTEntry *removed_entry = NULL; - size_t removed_hash; - size_t hash = av_crc(hash_ctx, 0, (uint8_t*)&key, 4) % LOOKBACK_HT_ELEMS; - - for (size_t i = hash; i < hash + LOOKBACK_HT_ELEMS; i++) { - size_t wrapped_index = i % LOOKBACK_HT_ELEMS; - HTEntry *entry = &ht[wrapped_index]; - if (entry->pos == -1) - return; - if (removed_entry) { - size_t candidate_hash = av_crc(hash_ctx, 0, (uint8_t*)&entry->key, 4) % LOOKBACK_HT_ELEMS; - if ((wrapped_index > removed_hash && (candidate_hash <= removed_hash || candidate_hash > wrapped_index)) || - (wrapped_index < removed_hash && (candidate_hash <= removed_hash && candidate_hash > wrapped_index))) { - *removed_entry = *entry; - entry->pos = -1; - removed_entry = entry; - removed_hash = wrapped_index; - } - } else if (entry->key == key) { - if (entry->pos <= pos) { - entry->pos = -1; - removed_entry = entry; - removed_hash = wrapped_index; - } else { - return; - } - } - } -} - typedef struct DXVEncContext { AVClass *class; @@ -121,10 +63,9 @@ typedef struct DXVEncContext { DXVTextureFormat tex_fmt; int (*compress_tex)(AVCodecContext *avctx); - const AVCRC *crc_ctx; - - HTEntry color_lookback_ht[LOOKBACK_HT_ELEMS]; - HTEntry lut_lookback_ht[LOOKBACK_HT_ELEMS]; + FFHashtableContext *color_ht; + FFHashtableContext *lut_ht; + FFHashtableContext *combo_ht; } DXVEncContext; /* Converts an index offset value to a 2-bit opcode and pushes it to a stream. @@ -159,58 +100,59 @@ static int dxv_compress_dxt1(AVCodecContext *avctx) DXVEncContext *ctx = avctx->priv_data; PutByteContext *pbc = &ctx->pbc; void *value; - uint32_t color, lut, idx, color_idx, lut_idx, prev_pos, state = 16, pos = 2, op = 0; + uint32_t idx, combo_idx, prev_pos, old_pos, state = 16, pos = 0, op = 0; - ht_init(ctx->color_lookback_ht); - ht_init(ctx->lut_lookback_ht); + ff_hashtable_clear(ctx->color_ht); + ff_hashtable_clear(ctx->lut_ht); + ff_hashtable_clear(ctx->combo_ht); + + ff_hashtable_set(ctx->combo_ht, ctx->tex_data, &pos); bytestream2_put_le32(pbc, AV_RL32(ctx->tex_data)); + ff_hashtable_set(ctx->color_ht, ctx->tex_data, &pos); + pos++; bytestream2_put_le32(pbc, AV_RL32(ctx->tex_data + 4)); - - ht_lookup_and_upsert(ctx->color_lookback_ht, ctx->crc_ctx, AV_RL32(ctx->tex_data), 0); - ht_lookup_and_upsert(ctx->lut_lookback_ht, ctx->crc_ctx, AV_RL32(ctx->tex_data + 4), 1); + ff_hashtable_set(ctx->lut_ht, ctx->tex_data + 4, &pos); + pos++; while (pos + 2 <= ctx->tex_size / 4) { - idx = 0; - - color = AV_RL32(ctx->tex_data + pos * 4); - prev_pos = ht_lookup_and_upsert(ctx->color_lookback_ht, ctx->crc_ctx, color, pos); - color_idx = prev_pos != -1 ? pos - prev_pos : 0; - if (pos >= LOOKBACK_WORDS) { - uint32_t old_pos = pos - LOOKBACK_WORDS; - uint32_t old_color = AV_RL32(ctx->tex_data + old_pos * 4); - ht_delete(ctx->color_lookback_ht, ctx->crc_ctx, old_color, old_pos); - } - pos++; - - lut = AV_RL32(ctx->tex_data + pos * 4); - if (color_idx && lut == AV_RL32(ctx->tex_data + (pos - color_idx) * 4)) { - idx = color_idx; - } else { - idx = 0; - prev_pos = ht_lookup_and_upsert(ctx->lut_lookback_ht, ctx->crc_ctx, lut, pos); - lut_idx = prev_pos != -1 ? pos - prev_pos : 0; - } - if (pos >= LOOKBACK_WORDS) { - uint32_t old_pos = pos - LOOKBACK_WORDS; - uint32_t old_lut = AV_RL32(ctx->tex_data + old_pos * 4); - ht_delete(ctx->lut_lookback_ht, ctx->crc_ctx, old_lut, old_pos); - } - pos++; - + combo_idx = ff_hashtable_get(ctx->combo_ht, ctx->tex_data + pos * 4, &prev_pos) ? pos - prev_pos : 0; + idx = combo_idx; PUSH_OP(2); - - if (!idx) { - idx = color_idx; - PUSH_OP(2); - if (!idx) - bytestream2_put_le32(pbc, color); - - idx = lut_idx; - PUSH_OP(2); - if (!idx) - bytestream2_put_le32(pbc, lut); + if (pos >= LOOKBACK_WORDS) { + old_pos = pos - LOOKBACK_WORDS; + if (ff_hashtable_get(ctx->combo_ht, ctx->tex_data + old_pos * 4, &prev_pos) && prev_pos <= old_pos) + ff_hashtable_delete(ctx->combo_ht, ctx->tex_data + old_pos * 4); } + ff_hashtable_set(ctx->combo_ht, ctx->tex_data + pos * 4, &pos); + + if (!combo_idx) { + idx = ff_hashtable_get(ctx->color_ht, ctx->tex_data + pos * 4, &prev_pos) ? pos - prev_pos : 0; + PUSH_OP(2); + if (!idx) + bytestream2_put_le32(pbc, AV_RL32(ctx->tex_data + pos * 4)); + } + if (pos >= LOOKBACK_WORDS) { + old_pos = pos - LOOKBACK_WORDS; + if (ff_hashtable_get(ctx->color_ht, ctx->tex_data + old_pos * 4, &prev_pos) && prev_pos <= old_pos) + ff_hashtable_delete(ctx->color_ht, ctx->tex_data + old_pos * 4); + } + ff_hashtable_set(ctx->color_ht, ctx->tex_data + pos * 4, &pos); + pos++; + + if (!combo_idx) { + idx = ff_hashtable_get(ctx->lut_ht, ctx->tex_data + pos * 4, &prev_pos) ? pos - prev_pos : 0; + PUSH_OP(2); + if (!idx) + bytestream2_put_le32(pbc, AV_RL32(ctx->tex_data + pos * 4)); + } + if (pos >= LOOKBACK_WORDS) { + old_pos = pos - LOOKBACK_WORDS; + if (ff_hashtable_get(ctx->lut_ht, ctx->tex_data + old_pos * 4, &prev_pos) && prev_pos <= old_pos) + ff_hashtable_delete(ctx->lut_ht, ctx->tex_data + old_pos * 4); + } + ff_hashtable_set(ctx->lut_ht, ctx->tex_data + pos * 4, &pos); + pos++; } return 0; @@ -231,12 +173,51 @@ static int dxv_encode(AVCodecContext *avctx, AVPacket *pkt, return ret; if (ctx->enc.tex_funct) { + uint8_t *safe_data[4] = {frame->data[0], 0, 0, 0}; + int safe_linesize[4] = {frame->linesize[0], 0, 0, 0}; + + if (avctx->width != DXV_ALIGN(avctx->width) || avctx->height != DXV_ALIGN(avctx->height)) { + ret = av_image_alloc( + safe_data, + safe_linesize, + DXV_ALIGN(avctx->width), + DXV_ALIGN(avctx->height), + avctx->pix_fmt, + 1); + if (ret < 0) + return ret; + + av_image_copy2( + safe_data, + safe_linesize, + frame->data, + frame->linesize, + avctx->pix_fmt, + avctx->width, + avctx->height); + + if (avctx->width != DXV_ALIGN(avctx->width)) { + av_assert0(frame->format == AV_PIX_FMT_RGBA); + for (int y = 0; y < avctx->height; y++) { + memset(safe_data[0] + y * safe_linesize[0] + 4*avctx->width, 0, safe_linesize[0] - 4*avctx->width); + } + } + if (avctx->height != DXV_ALIGN(avctx->height)) { + for (int y = avctx->height; y < DXV_ALIGN(avctx->height); y++) { + memset(safe_data[0] + y * safe_linesize[0], 0, safe_linesize[0]); + } + } + } + ctx->enc.tex_data.out = ctx->tex_data; - ctx->enc.frame_data.in = frame->data[0]; - ctx->enc.stride = frame->linesize[0]; - ctx->enc.width = avctx->width; - ctx->enc.height = avctx->height; + ctx->enc.frame_data.in = safe_data[0]; + ctx->enc.stride = safe_linesize[0]; + ctx->enc.width = DXV_ALIGN(avctx->width); + ctx->enc.height = DXV_ALIGN(avctx->height); ff_texturedsp_exec_compress_threads(avctx, &ctx->enc); + + if (safe_data[0] != frame->data[0]) + av_freep(&safe_data[0]); } else { /* unimplemented: YCoCg formats */ return AVERROR_INVALIDDATA; @@ -275,14 +256,6 @@ static av_cold int dxv_init(AVCodecContext *avctx) return ret; } - if (avctx->width % TEXTURE_BLOCK_W || avctx->height % TEXTURE_BLOCK_H) { - av_log(avctx, - AV_LOG_ERROR, - "Video size %dx%d is not multiple of "AV_STRINGIFY(TEXTURE_BLOCK_W)"x"AV_STRINGIFY(TEXTURE_BLOCK_H)".\n", - avctx->width, avctx->height); - return AVERROR_INVALIDDATA; - } - ff_texturedspenc_init(&texdsp); switch (ctx->tex_fmt) { @@ -296,21 +269,25 @@ static av_cold int dxv_init(AVCodecContext *avctx) return AVERROR_INVALIDDATA; } ctx->enc.raw_ratio = 16; - ctx->tex_size = avctx->width / TEXTURE_BLOCK_W * - avctx->height / TEXTURE_BLOCK_H * + ctx->tex_size = DXV_ALIGN(avctx->width) / TEXTURE_BLOCK_W * + DXV_ALIGN(avctx->height) / TEXTURE_BLOCK_H * ctx->enc.tex_ratio; - ctx->enc.slice_count = av_clip(avctx->thread_count, 1, avctx->height / TEXTURE_BLOCK_H); + ctx->enc.slice_count = av_clip(avctx->thread_count, 1, DXV_ALIGN(avctx->height) / TEXTURE_BLOCK_H); ctx->tex_data = av_malloc(ctx->tex_size); if (!ctx->tex_data) { return AVERROR(ENOMEM); } - ctx->crc_ctx = av_crc_get_table(AV_CRC_32_IEEE); - if (!ctx->crc_ctx) { - av_log(avctx, AV_LOG_ERROR, "Could not initialize CRC table.\n"); - return AVERROR_BUG; - } + ret = ff_hashtable_alloc(&ctx->color_ht, sizeof(uint32_t), sizeof(uint32_t), LOOKBACK_HT_ELEMS); + if (ret < 0) + return ret; + ret = ff_hashtable_alloc(&ctx->lut_ht, sizeof(uint32_t), sizeof(uint32_t), LOOKBACK_HT_ELEMS); + if (ret < 0) + return ret; + ret = ff_hashtable_alloc(&ctx->combo_ht, sizeof(uint64_t), sizeof(uint32_t), LOOKBACK_HT_ELEMS); + if (ret < 0) + return ret; return 0; } @@ -321,6 +298,10 @@ static av_cold int dxv_close(AVCodecContext *avctx) av_freep(&ctx->tex_data); + ff_hashtable_freep(&ctx->color_ht); + ff_hashtable_freep(&ctx->lut_ht); + ff_hashtable_freep(&ctx->combo_ht); + return 0; } @@ -351,8 +332,6 @@ const FFCodec ff_dxv_encoder = { AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, .p.priv_class = &dxvenc_class, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGBA), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/dynamic_hdr_vivid.c b/libavcodec/dynamic_hdr_vivid.c index a9b691079..319d13b90 100644 --- a/libavcodec/dynamic_hdr_vivid.c +++ b/libavcodec/dynamic_hdr_vivid.c @@ -116,17 +116,6 @@ int ff_parse_itu_t_t35_to_dynamic_hdr_vivid(AVDynamicHDRVivid *s, const uint8_t three_spline->th_delta2 = (AVRational){get_bits(gb, 10), 1023}; three_spline->enable_strength = (AVRational){get_bits(gb, 8), 255}; } -#if FF_API_HDR_VIVID_THREE_SPLINE - three_spline = &tm_params->three_spline[0]; -FF_DISABLE_DEPRECATION_WARNINGS - tm_params->three_Spline_TH_mode = three_spline->th_mode; - tm_params->three_Spline_TH_enable_MB = three_spline->th_enable_mb; - tm_params->three_Spline_TH_enable = three_spline->th_enable; - tm_params->three_Spline_TH_Delta1 = three_spline->th_delta1; - tm_params->three_Spline_TH_Delta2 = three_spline->th_delta2; - tm_params->three_Spline_enable_Strength = three_spline->enable_strength; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } } } diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c index 2b3bffda6..c5095b191 100644 --- a/libavcodec/eac3dec.c +++ b/libavcodec/eac3dec.c @@ -53,8 +53,6 @@ typedef enum { EAC3_GAQ_124 } EAC3GaqMode; -#define EAC3_SR_CODE_REDUCED 3 - static void ff_eac3_apply_spectral_extension(AC3DecodeContext *s) { int bin, bnd, ch, i; @@ -287,7 +285,7 @@ static void ff_eac3_decode_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch) } } -static int ff_eac3_parse_header(AC3DecodeContext *s) +static int ff_eac3_parse_header(AC3DecodeContext *s, const AC3HeaderInfo *hdr) { int i, blk, ch; int ac3_exponent_strategy, parse_aht_info, parse_spx_atten_data; @@ -323,11 +321,10 @@ static int ff_eac3_parse_header(AC3DecodeContext *s) avpriv_request_sample(s->avctx, "Reduced sampling rate"); return AVERROR_PATCHWELCOME; } - skip_bits(gbc, 5); // skip bitstream id /* volume control params */ for (i = 0; i < (s->channel_mode ? 1 : 2); i++) { - s->dialog_normalization[i] = -get_bits(gbc, 5); + s->dialog_normalization[i] = hdr->dialog_normalization[i]; if (s->dialog_normalization[i] == 0) { s->dialog_normalization[i] = -31; } @@ -335,147 +332,30 @@ static int ff_eac3_parse_header(AC3DecodeContext *s) s->level_gain[i] = powf(2.0f, (float)(s->target_level - s->dialog_normalization[i])/6.0f); } - s->compression_exists[i] = get_bits1(gbc); - if (s->compression_exists[i]) { - s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(get_bits(gbc, 8)); + if (hdr->compression_exists[i]) { + s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(hdr->heavy_dynamic_range[i]); } } - /* dependent stream channel map */ - if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) { - if (get_bits1(gbc)) { - int64_t channel_layout = 0; - int channel_map = get_bits(gbc, 16); - av_log(s->avctx, AV_LOG_DEBUG, "channel_map: %0X\n", channel_map); - - for (i = 0; i < 16; i++) - if (channel_map & (1 << (EAC3_MAX_CHANNELS - i - 1))) - channel_layout |= ff_eac3_custom_channel_map_locations[i][1]; - - if (av_popcount64(channel_layout) > EAC3_MAX_CHANNELS) { - return AVERROR_INVALIDDATA; - } - s->channel_map = channel_map; - } - } + s->channel_map = hdr->channel_map; /* mixing metadata */ - if (get_bits1(gbc)) { - /* center and surround mix levels */ - if (s->channel_mode > AC3_CHMODE_STEREO) { - s->preferred_downmix = get_bits(gbc, 2); - if (s->channel_mode & 1) { - /* if three front channels exist */ - s->center_mix_level_ltrt = get_bits(gbc, 3); - s->center_mix_level = get_bits(gbc, 3); - } - if (s->channel_mode & 4) { - /* if a surround channel exists */ - s->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7); - s->surround_mix_level = av_clip(get_bits(gbc, 3), 3, 7); - } - } - - /* lfe mix level */ - if (s->lfe_on && (s->lfe_mix_level_exists = get_bits1(gbc))) { - s->lfe_mix_level = get_bits(gbc, 5); - } - - /* info for mixing with other streams and substreams */ - if (s->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) { - for (i = 0; i < (s->channel_mode ? 1 : 2); i++) { - // TODO: apply program scale factor - if (get_bits1(gbc)) { - skip_bits(gbc, 6); // skip program scale factor - } - } - if (get_bits1(gbc)) { - skip_bits(gbc, 6); // skip external program scale factor - } - /* skip mixing parameter data */ - switch(get_bits(gbc, 2)) { - case 1: skip_bits(gbc, 5); break; - case 2: skip_bits(gbc, 12); break; - case 3: { - int mix_data_size = (get_bits(gbc, 5) + 2) << 3; - skip_bits_long(gbc, mix_data_size); - break; - } - } - /* skip pan information for mono or dual mono source */ - if (s->channel_mode < AC3_CHMODE_STEREO) { - for (i = 0; i < (s->channel_mode ? 1 : 2); i++) { - if (get_bits1(gbc)) { - /* note: this is not in the ATSC A/52B specification - reference: ETSI TS 102 366 V1.1.1 - section: E.1.3.1.25 */ - skip_bits(gbc, 8); // skip pan mean direction index - skip_bits(gbc, 6); // skip reserved paninfo bits - } - } - } - /* skip mixing configuration information */ - if (get_bits1(gbc)) { - for (blk = 0; blk < s->num_blocks; blk++) { - if (s->num_blocks == 1 || get_bits1(gbc)) { - skip_bits(gbc, 5); - } - } - } - } - } + s->preferred_downmix = hdr->preferred_downmix; + s->center_mix_level_ltrt = hdr->center_mix_level_ltrt; + s->center_mix_level = hdr->center_mix_level; + s->surround_mix_level_ltrt = hdr->surround_mix_level_ltrt; + s->surround_mix_level = hdr->surround_mix_level; + s->lfe_mix_level_exists = hdr->lfe_mix_level_exists; + s->lfe_mix_level = hdr->lfe_mix_level; + s->dolby_surround_mode = hdr->dolby_surround_mode; + s->dolby_headphone_mode = hdr->dolby_headphone_mode; + s->dolby_surround_ex_mode = hdr->dolby_surround_ex_mode; /* informational metadata */ - if (get_bits1(gbc)) { - s->bitstream_mode = get_bits(gbc, 3); - skip_bits(gbc, 2); // skip copyright bit and original bitstream bit - if (s->channel_mode == AC3_CHMODE_STEREO) { - s->dolby_surround_mode = get_bits(gbc, 2); - s->dolby_headphone_mode = get_bits(gbc, 2); - } - if (s->channel_mode >= AC3_CHMODE_2F2R) { - s->dolby_surround_ex_mode = get_bits(gbc, 2); - } - for (i = 0; i < (s->channel_mode ? 1 : 2); i++) { - if (get_bits1(gbc)) { - skip_bits(gbc, 8); // skip mix level, room type, and A/D converter type - } - } - if (s->bit_alloc_params.sr_code != EAC3_SR_CODE_REDUCED) { - skip_bits1(gbc); // skip source sample rate code - } - } - - /* converter synchronization flag - If frames are less than six blocks, this bit should be turned on - once every 6 blocks to indicate the start of a frame set. - reference: RFC 4598, Section 2.1.3 Frame Sets */ - if (s->frame_type == EAC3_FRAME_TYPE_INDEPENDENT && s->num_blocks != 6) { - skip_bits1(gbc); // skip converter synchronization flag - } - - /* original frame size code if this stream was converted from AC-3 */ - if (s->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT && - (s->num_blocks == 6 || get_bits1(gbc))) { - skip_bits(gbc, 6); // skip frame size code - } + s->bitstream_mode = hdr->bitstream_mode; /* additional bitstream info */ - if (get_bits1(gbc)) { - int addbsil = get_bits(gbc, 6); - for (i = 0; i < addbsil + 1; i++) { - if (i == 0) { - /* In this 8 bit chunk, the LSB is equal to flag_ec3_extension_type_a - which can be used to detect Atmos presence */ - skip_bits(gbc, 7); - if (get_bits1(gbc)) { - s->eac3_extension_type_a = 1; - } - } else { - skip_bits(gbc, 8); // skip additional bit stream info - } - } - } + s->eac3_extension_type_a = hdr->eac3_extension_type_a; /* audio frame syntax flags, strategy data, and per-frame data */ diff --git a/libavcodec/eac3enc.c b/libavcodec/eac3enc.c index 8ef3e7e77..10b1ab337 100644 --- a/libavcodec/eac3enc.c +++ b/libavcodec/eac3enc.c @@ -135,6 +135,8 @@ static void eac3_output_frame_header(AC3EncodeContext *s, PutBitContext *pb) int blk, ch; AC3EncOptions *opt = &s->options; + put_bits_assume_flushed(pb); + put_bits(pb, 16, 0x0b77); /* sync word */ /* BSI header */ @@ -273,11 +275,10 @@ const FFCodec ff_eac3_encoder = { .init = eac3_encode_init, FF_CODEC_ENCODE_CB(ff_ac3_encode_frame), .close = ff_ac3_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &eac3enc_class, - .p.supported_samplerates = ff_ac3_sample_rate_tab, - .p.ch_layouts = ff_ac3_ch_layouts, + CODEC_SAMPLERATES_ARRAY(ff_ac3_sample_rate_tab), + CODEC_CH_LAYOUTS_ARRAY(ff_ac3_ch_layouts), .defaults = ff_ac3_enc_defaults, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/eamad.c b/libavcodec/eamad.c index 1c3f97653..44dac4608 100644 --- a/libavcodec/eamad.c +++ b/libavcodec/eamad.c @@ -58,8 +58,6 @@ typedef struct MadContext { unsigned int bitstream_buf_size; DECLARE_ALIGNED(32, int16_t, block)[64]; uint16_t quant_matrix[64]; - int mb_x; - int mb_y; } MadContext; static av_cold int decode_init(AVCodecContext *avctx) @@ -148,11 +146,8 @@ static inline int decode_block_intra(MadContext *s, int16_t * block) break; } else if (level != 0) { i += run; - if (i > 63) { - av_log(s->avctx, AV_LOG_ERROR, - "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y); + if (i > 63) return -1; - } j = scantable[i]; level = (level*quant_matrix[j]) >> 4; level = (level-1)|1; @@ -160,18 +155,13 @@ static inline int decode_block_intra(MadContext *s, int16_t * block) LAST_SKIP_BITS(re, &s->gb, 1); } else { /* escape */ - UPDATE_CACHE(re, &s->gb); level = SHOW_SBITS(re, &s->gb, 10); SKIP_BITS(re, &s->gb, 10); - UPDATE_CACHE(re, &s->gb); run = SHOW_UBITS(re, &s->gb, 6)+1; LAST_SKIP_BITS(re, &s->gb, 6); i += run; - if (i > 63) { - av_log(s->avctx, AV_LOG_ERROR, - "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y); + if (i > 63) return -1; - } j = scantable[i]; if (level < 0) { level = -level; @@ -202,7 +192,7 @@ static int decode_motion(GetBitContext *gb) return value; } -static int decode_mb(MadContext *s, AVFrame *frame, int inter) +static int decode_mb(MadContext *s, AVFrame *frame, int inter, int mb_x, int mb_y) { int mv_map = 0; int av_uninit(mv_x), av_uninit(mv_y); @@ -221,12 +211,15 @@ static int decode_mb(MadContext *s, AVFrame *frame, int inter) if (mv_map & (1<gb); if (s->last_frame->data[0]) - comp_block(s, frame, s->mb_x, s->mb_y, j, mv_x, mv_y, add); + comp_block(s, frame, mb_x, mb_y, j, mv_x, mv_y, add); } else { s->bdsp.clear_block(s->block); - if(decode_block_intra(s, s->block) < 0) + if (decode_block_intra(s, s->block) < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "ac-tex damaged at %d %d\n", mb_x, mb_y); return -1; - idct_put(s, frame, s->block, s->mb_x, s->mb_y, j); + } + idct_put(s, frame, s->block, mb_x, mb_y, j); } } return 0; @@ -310,9 +303,9 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, memset((uint8_t*)s->bitstream_buf + bytestream2_get_bytes_left(&gb), 0, AV_INPUT_BUFFER_PADDING_SIZE); init_get_bits(&s->gb, s->bitstream_buf, 8*(bytestream2_get_bytes_left(&gb))); - for (s->mb_y=0; s->mb_y < (avctx->height+15)/16; s->mb_y++) - for (s->mb_x=0; s->mb_x < (avctx->width +15)/16; s->mb_x++) - if(decode_mb(s, frame, inter) < 0) + for (int mb_y = 0; mb_y < (avctx->height + 15) / 16; mb_y++) + for (int mb_x = 0; mb_x < (avctx->width + 15) / 16; mb_x++) + if (decode_mb(s, frame, inter, mb_x, mb_y) < 0) return AVERROR_INVALIDDATA; *got_frame = 1; diff --git a/libavcodec/eatgq.c b/libavcodec/eatgq.c index c6fcb062d..efcad62df 100644 --- a/libavcodec/eatgq.c +++ b/libavcodec/eatgq.c @@ -36,12 +36,14 @@ #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" +#include "copy_block.h" #include "decode.h" #include "eaidct.h" #include "get_bits.h" typedef struct TgqContext { AVCodecContext *avctx; + AVFrame *last_frame; int width, height; int qtable[64]; DECLARE_ALIGNED(16, int16_t, block)[6][64]; @@ -53,6 +55,9 @@ static av_cold int tgq_decode_init(AVCodecContext *avctx) s->avctx = avctx; avctx->framerate = (AVRational){ 15, 1 }; avctx->pix_fmt = AV_PIX_FMT_YUV420P; + s->last_frame = av_frame_alloc(); + if (!s->last_frame) + return AVERROR(ENOMEM); return 0; } @@ -156,7 +161,6 @@ static int tgq_decode_mb(TgqContext *s, GetByteContext *gbyte, { int mode; int i; - int8_t dc[6]; mode = bytestream2_get_byte(gbyte); if (mode > 12) { @@ -173,7 +177,34 @@ static int tgq_decode_mb(TgqContext *s, GetByteContext *gbyte, tgq_idct_put_mb(s, s->block, frame, mb_x, mb_y); bytestream2_skip(gbyte, mode); } else { - if (mode == 3) { + int8_t dc[6]; + if (mode == 1) { + int x, y; + int mv = bytestream2_get_byte(gbyte); + int mv_x = mv >> 4; + int mv_y = mv & 0x0F; + if (!s->last_frame->data[0]) { + av_log(s->avctx, AV_LOG_ERROR, "missing reference frame\n"); + return -1; + } + if (mv_x >= 8) mv_x -= 16; + if (mv_y >= 8) mv_y -= 16; + x = mb_x * 16 - mv_x; + y = mb_y * 16 - mv_y; + if (x < 0 || x + 16 > s->width || y < 0 || y + 16 > s->height) { + av_log(s->avctx, AV_LOG_ERROR, "invalid motion vector\n"); + return -1; + } + copy_block16(frame->data[0] + (mb_y * 16 * frame->linesize[0]) + mb_x * 16, + s->last_frame->data[0] + y * s->last_frame->linesize[0] + x, + frame->linesize[0], s->last_frame->linesize[0], 16); + for (int p = 1; p < 3; p++) + copy_block8(frame->data[p] + (mb_y * 8 * frame->linesize[p]) + mb_x * 8, + s->last_frame->data[p] + (y >> 1) * s->last_frame->linesize[p] + (x >> 1), + frame->linesize[p], s->last_frame->linesize[p], 8); + frame->flags &= ~AV_FRAME_FLAG_KEY; + return 0; + } else if (mode == 3) { memset(dc, bytestream2_get_byte(gbyte), 4); dc[4] = bytestream2_get_byte(gbyte); dc[5] = bytestream2_get_byte(gbyte); @@ -229,9 +260,12 @@ static int tgq_decode_frame(AVCodecContext *avctx, AVFrame *frame, s->height = bytestream2_get_le16u(&gbyte); } - ret = ff_set_dimensions(s->avctx, s->width, s->height); - if (ret < 0) - return ret; + if (s->avctx->width != s->width || s->avctx->height != s->height) { + av_frame_unref(s->last_frame); + ret = ff_set_dimensions(s->avctx, s->width, s->height); + if (ret < 0) + return ret; + } tgq_calculate_qtable(s, bytestream2_get_byteu(&gbyte)); bytestream2_skipu(&gbyte, 3); @@ -239,16 +273,27 @@ static int tgq_decode_frame(AVCodecContext *avctx, AVFrame *frame, if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; + frame->flags |= AV_FRAME_FLAG_KEY; for (y = 0; y < FFALIGN(avctx->height, 16) >> 4; y++) for (x = 0; x < FFALIGN(avctx->width, 16) >> 4; x++) if (tgq_decode_mb(s, &gbyte, frame, y, x) < 0) return AVERROR_INVALIDDATA; + if ((ret = av_frame_replace(s->last_frame, frame)) < 0) + return ret; + *got_frame = 1; return avpkt->size; } +static av_cold int tgq_decode_close(AVCodecContext *avctx) +{ + TgqContext *s = avctx->priv_data; + av_frame_free(&s->last_frame); + return 0; +} + const FFCodec ff_eatgq_decoder = { .p.name = "eatgq", CODEC_LONG_NAME("Electronic Arts TGQ video"), @@ -256,6 +301,7 @@ const FFCodec ff_eatgq_decoder = { .p.id = AV_CODEC_ID_TGQ, .priv_data_size = sizeof(TgqContext), .init = tgq_decode_init, + .close = tgq_decode_close, FF_CODEC_DECODE_CB(tgq_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, }; diff --git a/libavcodec/encode.c b/libavcodec/encode.c index 3baf5b810..f1a65a9b2 100644 --- a/libavcodec/encode.c +++ b/libavcodec/encode.c @@ -18,13 +18,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/emms.h" #include "libavutil/frame.h" -#include "libavutil/imgutils.h" #include "libavutil/internal.h" +#include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/samplefmt.h" @@ -214,21 +213,6 @@ int ff_encode_get_frame(AVCodecContext *avctx, AVFrame *frame) av_frame_move_ref(frame, avci->buffer_frame); -#if FF_API_FRAME_KEY -FF_DISABLE_DEPRECATION_WARNINGS - if (frame->key_frame) - frame->flags |= AV_FRAME_FLAG_KEY; -FF_ENABLE_DEPRECATION_WARNINGS -#endif -#if FF_API_INTERLACED_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - if (frame->interlaced_frame) - frame->flags |= AV_FRAME_FLAG_INTERLACED; - if (frame->top_field_first) - frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - return 0; } @@ -252,7 +236,7 @@ int ff_encode_encode_cb(AVCodecContext *avctx, AVPacket *avpkt, int ret; ret = codec->cb.encode(avctx, avpkt, frame, got_packet); - emms_c(); + ff_assert1_fpu(); av_assert0(ret <= 0); if (!ret && *got_packet) { @@ -333,12 +317,13 @@ static int encode_simple_internal(AVCodecContext *avctx, AVPacket *avpkt) av_assert0(codec->cb_type == FF_CODEC_CB_TYPE_ENCODE); - if (CONFIG_FRAME_THREAD_ENCODER && avci->frame_thread_encoder) +#if CONFIG_FRAME_THREAD_ENCODER + if (avci->frame_thread_encoder) /* This will unref frame. */ ret = ff_thread_video_encode_frame(avctx, avpkt, frame, &got_packet); - else { + else +#endif ret = ff_encode_encode_cb(avctx, avpkt, frame, &got_packet); - } if (avci->draining && !got_packet) avci->draining_done = 1; @@ -372,8 +357,6 @@ static int encode_receive_packet_internal(AVCodecContext *avctx, AVPacket *avpkt if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) { if ((avctx->flags & AV_CODEC_FLAG_PASS1) && avctx->stats_out) avctx->stats_out[0] = '\0'; - if (av_image_check_size2(avctx->width, avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx)) - return AVERROR(EINVAL); } if (ffcodec(avctx->codec)->cb_type == FF_CODEC_CB_TYPE_RECEIVE_PACKET) { @@ -566,7 +549,7 @@ static int encode_preinit_video(AVCodecContext *avctx) const enum AVPixelFormat *pix_fmts; int ret, i, num_pix_fmts; - if (!av_get_pix_fmt_name(avctx->pix_fmt)) { + if (!pixdesc) { av_log(avctx, AV_LOG_ERROR, "Invalid video pixel format: %d\n", avctx->pix_fmt); return AVERROR(EINVAL); @@ -602,6 +585,33 @@ static int encode_preinit_video(AVCodecContext *avctx) avctx->color_range = AVCOL_RANGE_JPEG; } + if (pixdesc->flags & AV_PIX_FMT_FLAG_ALPHA) { + const enum AVAlphaMode *alpha_modes; + int num_alpha_modes; + ret = avcodec_get_supported_config(avctx, NULL, AV_CODEC_CONFIG_ALPHA_MODE, + 0, (const void **) &alpha_modes, &num_alpha_modes); + if (ret < 0) + return ret; + + if (avctx->alpha_mode != AVALPHA_MODE_UNSPECIFIED && alpha_modes) { + for (i = 0; i < num_alpha_modes; i++) { + if (avctx->alpha_mode == alpha_modes[i]) + break; + } + if (i == num_alpha_modes) { + av_log(avctx, AV_LOG_ERROR, + "Specified alpha mode '%s' is not supported by the %s encoder.\n", + av_alpha_mode_name(avctx->alpha_mode), c->name); + av_log(avctx, AV_LOG_ERROR, "Supported alpha modes:\n"); + for (int p = 0; alpha_modes[p] != AVALPHA_MODE_UNSPECIFIED; p++) { + av_log(avctx, AV_LOG_ERROR, " %s\n", + av_alpha_mode_name(alpha_modes[p])); + } + return AVERROR(EINVAL); + } + } + } + if ( avctx->bits_per_raw_sample < 0 || (avctx->bits_per_raw_sample > 8 && pixdesc->comp[0].depth <= 8)) { av_log(avctx, AV_LOG_WARNING, "Specified bit depth %d not possible with the specified pixel formats depth %d\n", @@ -613,20 +623,6 @@ static int encode_preinit_video(AVCodecContext *avctx) return AVERROR(EINVAL); } -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->ticks_per_frame && avctx->time_base.num && - avctx->ticks_per_frame > INT_MAX / avctx->time_base.num) { - av_log(avctx, AV_LOG_ERROR, - "ticks_per_frame %d too large for the timebase %d/%d.", - avctx->ticks_per_frame, - avctx->time_base.num, - avctx->time_base.den); - return AVERROR(EINVAL); - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (avctx->hw_frames_ctx) { AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; if (frames_ctx->format != avctx->pix_fmt) { @@ -662,11 +658,6 @@ static int encode_preinit_audio(AVCodecContext *avctx) avctx->sample_fmt); return AVERROR(EINVAL); } - if (avctx->sample_rate <= 0) { - av_log(avctx, AV_LOG_ERROR, "Invalid audio sample rate: %d\n", - avctx->sample_rate); - return AVERROR(EINVAL); - } ret = avcodec_get_supported_config(avctx, NULL, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, (const void **) &sample_fmts, @@ -835,11 +826,11 @@ int ff_encode_preinit(AVCodecContext *avctx) memcpy(sd_packet->data, sd_frame->data, sd_frame->size); } - if (CONFIG_FRAME_THREAD_ENCODER) { - ret = ff_frame_thread_encoder_init(avctx); - if (ret < 0) - return ret; - } +#if CONFIG_FRAME_THREAD_ENCODER + ret = ff_frame_thread_encoder_init(avctx); + if (ret < 0) + return ret; +#endif return 0; } @@ -848,24 +839,12 @@ int ff_encode_alloc_frame(AVCodecContext *avctx, AVFrame *frame) { int ret; - switch (avctx->codec->type) { - case AVMEDIA_TYPE_VIDEO: - frame->format = avctx->pix_fmt; - if (frame->width <= 0 || frame->height <= 0) { - frame->width = FFMAX(avctx->width, avctx->coded_width); - frame->height = FFMAX(avctx->height, avctx->coded_height); - } + av_assert1(avctx->codec_type == AVMEDIA_TYPE_VIDEO); - break; - case AVMEDIA_TYPE_AUDIO: - frame->sample_rate = avctx->sample_rate; - frame->format = avctx->sample_fmt; - if (!frame->ch_layout.nb_channels) { - ret = av_channel_layout_copy(&frame->ch_layout, &avctx->ch_layout); - if (ret < 0) - return ret; - } - break; + frame->format = avctx->pix_fmt; + if (frame->width <= 0 || frame->height <= 0) { + frame->width = avctx->width; + frame->height = avctx->height; } ret = avcodec_default_get_buffer2(avctx, frame, 0); @@ -936,3 +915,47 @@ AVCPBProperties *ff_encode_add_cpb_side_data(AVCodecContext *avctx) return props; } + +int ff_encode_add_stats_side_data(AVPacket *pkt, int quality, const int64_t error[], + int error_count, enum AVPictureType pict_type) +{ + uint8_t *side_data; + size_t side_data_size; + + side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, &side_data_size); + if (!side_data) { + side_data_size = 4+4+8*error_count; + side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, + side_data_size); + } + + if (!side_data || side_data_size < 4+4+8*error_count) + return AVERROR(ENOMEM); + + AV_WL32(side_data, quality); + side_data[4] = pict_type; + side_data[5] = error_count; + for (int i = 0; i < error_count; ++i) + AV_WL64(side_data+8 + 8*i , error[i]); + + return 0; +} + +int ff_check_codec_matrices(AVCodecContext *avctx, unsigned types, uint16_t min, uint16_t max) +{ + uint16_t *matrices[] = {avctx->intra_matrix, avctx->inter_matrix, avctx->chroma_intra_matrix}; + const char *names[] = {"Intra", "Inter", "Chroma Intra"}; + static_assert(FF_ARRAY_ELEMS(matrices) == FF_ARRAY_ELEMS(names), "matrix count mismatch"); + for (int m = 0; m < FF_ARRAY_ELEMS(matrices); m++) { + uint16_t *matrix = matrices[m]; + if (matrix && (types & (1U << m))) { + for (int i = 0; i < 64; i++) { + if (matrix[i] < min || matrix[i] > max) { + av_log(avctx, AV_LOG_ERROR, "%s matrix[%d] is %d which is out of the allowed range [%"PRIu16"-%"PRIu16"].\n", names[m], i, matrix[i], min, max); + return AVERROR(EINVAL); + } + } + } + } + return 0; +} diff --git a/libavcodec/encode.h b/libavcodec/encode.h index 85331e04b..b66b38703 100644 --- a/libavcodec/encode.h +++ b/libavcodec/encode.h @@ -84,6 +84,9 @@ int ff_encode_encode_cb(AVCodecContext *avctx, AVPacket *avpkt, */ AVCPBProperties *ff_encode_add_cpb_side_data(AVCodecContext *avctx); +int ff_encode_add_stats_side_data(AVPacket *pkt, int quality, const int64_t error[], + int error_count, enum AVPictureType pict_type); + /** * Rescale from sample rate to AVCodecContext.time_base. */ @@ -96,4 +99,25 @@ static av_always_inline int64_t ff_samples_to_time_base(const AVCodecContext *av avctx->time_base); } +/** + * Rescale from time base to AVCodecContext.sample_rate. + */ +static av_always_inline int64_t ff_samples_from_time_base(const AVCodecContext *avctx, + int64_t duration) +{ + if (!duration) + return duration; + return av_rescale_q(duration, avctx->time_base, + (AVRational){ 1, avctx->sample_rate }); +} + +/** + * Check if the elements of codec context matrices (intra_matrix, inter_matrix or + * chroma_intra_matrix) are within the specified range. + */ +#define FF_MATRIX_TYPE_INTRA (1U << 0) +#define FF_MATRIX_TYPE_INTER (1U << 1) +#define FF_MATRIX_TYPE_CHROMA_INTRA (1U << 2) +int ff_check_codec_matrices(AVCodecContext *avctx, unsigned types, uint16_t min, uint16_t max); + #endif /* AVCODEC_ENCODE_H */ diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c index 6edc2dc15..8cf5bc6a3 100644 --- a/libavcodec/error_resilience.c +++ b/libavcodec/error_resilience.c @@ -27,15 +27,36 @@ #include +#include "libavutil/avassert.h" +#include "libavutil/attributes.h" #include "libavutil/mem.h" #include "avcodec.h" #include "error_resilience.h" +#include "mathops.h" #include "me_cmp.h" #include "mpegutils.h" #include "mpegvideo.h" #include "threadframe.h" #include "threadprogress.h" +av_cold int ff_er_init(ERContext *const s) +{ + MECmpContext mecc; + unsigned mb_array_size = s->mb_height * s->mb_stride; + + s->error_status_table = av_mallocz(mb_array_size); + if (!s->error_status_table) + return AVERROR(ENOMEM); + s->er_temp_buffer = av_malloc_array(mb_array_size, 4*sizeof(int) + 1); + if (!s->er_temp_buffer) + return AVERROR(ENOMEM); + + ff_me_cmp_init(&mecc, s->avctx); + s->sad = mecc.sad[0]; + + return 0; +} + /** * @param stride the number of MVs to get to the next row * @param mv_step the number of MVs per row or column in a macroblock @@ -793,13 +814,6 @@ void ff_er_frame_start(ERContext *s) if (!s->avctx->error_concealment) return; - if (!s->mecc_inited) { - MECmpContext mecc; - ff_me_cmp_init(&mecc, s->avctx); - s->sad = mecc.sad[0]; - s->mecc_inited = 1; - } - memset(s->error_status_table, ER_MB_ERROR | VP_START | ER_MB_END, s->mb_stride * s->mb_height * sizeof(uint8_t)); atomic_init(&s->error_count, 3 * s->mb_num); diff --git a/libavcodec/error_resilience.h b/libavcodec/error_resilience.h index a1b9b9ec1..1beae5a6b 100644 --- a/libavcodec/error_resilience.h +++ b/libavcodec/error_resilience.h @@ -23,9 +23,8 @@ #include #include "avcodec.h" -#include "me_cmp.h" -///< current MB is the first after a resync marker +/// current MB is the first after a resync marker #define VP_START 1 #define ER_AC_ERROR 2 #define ER_DC_ERROR 4 @@ -37,6 +36,8 @@ #define ER_MB_ERROR (ER_AC_ERROR|ER_DC_ERROR|ER_MV_ERROR) #define ER_MB_END (ER_AC_END|ER_DC_END|ER_MV_END) +typedef struct MPVEncContext MPVEncContext; + typedef struct ERPicture { AVFrame *f; const struct ThreadFrame *tf; @@ -53,8 +54,8 @@ typedef struct ERPicture { typedef struct ERContext { AVCodecContext *avctx; - me_cmp_func sad; - int mecc_inited; + int (*sad)(MPVEncContext *unused, const uint8_t *blk1, + const uint8_t *blk2, ptrdiff_t stride, int h); int *mb_index2xy; int mb_num; @@ -89,6 +90,8 @@ typedef struct ERContext { void *opaque; } ERContext; +int ff_er_init(ERContext *const s); + void ff_er_frame_start(ERContext *s); /** diff --git a/libavcodec/escape130.c b/libavcodec/escape130.c index 9b2c6204f..a19283114 100644 --- a/libavcodec/escape130.c +++ b/libavcodec/escape130.c @@ -212,9 +212,6 @@ static int escape130_decode_frame(AVCodecContext *avctx, AVFrame *pic, return AVERROR_INVALIDDATA; } - if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) - return ret; - if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0) return ret; skip_bits_long(&gb, 16 * 8); @@ -310,6 +307,9 @@ static int escape130_decode_frame(AVCodecContext *avctx, AVFrame *pic, skip--; } + if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) + return ret; + new_y = s->new_y; new_cb = s->new_u; new_cr = s->new_v; diff --git a/libavcodec/evc.h b/libavcodec/evc.h index d68dc7499..418c05a8e 100644 --- a/libavcodec/evc.h +++ b/libavcodec/evc.h @@ -56,7 +56,7 @@ enum EVCNALUnitType { EVC_RSV_VCL_NUT22 = 22, EVC_RSV_VCL_NUT23 = 23, EVC_SPS_NUT = 24, /* Sequence parameter set */ - EVC_PPS_NUT = 25, /* Picture paremeter set */ + EVC_PPS_NUT = 25, /* Picture parameter set */ EVC_APS_NUT = 26, /* Adaptation parameter set */ EVC_FD_NUT = 27, /* Filler data */ EVC_SEI_NUT = 28, /* Supplemental enhancement information */ diff --git a/libavcodec/evc_parse.h b/libavcodec/evc_parse.h index 471231082..4452c32d6 100644 --- a/libavcodec/evc_parse.h +++ b/libavcodec/evc_parse.h @@ -31,7 +31,7 @@ #include "evc.h" #include "evc_ps.h" -// The sturcture reflects Slice Header RBSP(raw byte sequence payload) layout +// The structure reflects Slice Header RBSP(raw byte sequence payload) layout // @see ISO_IEC_23094-1 section 7.3.2.6 // // The following descriptors specify the parsing process of each element diff --git a/libavcodec/evc_parser.c b/libavcodec/evc_parser.c index 8590ebcda..f08006d00 100644 --- a/libavcodec/evc_parser.c +++ b/libavcodec/evc_parser.c @@ -24,6 +24,9 @@ #include "bytestream.h" #include "evc.h" #include "evc_parse.h" +#include "parser_internal.h" + +#include "libavutil/attributes.h" typedef struct EVCParserContext { EVCParamSets ps; @@ -362,16 +365,16 @@ static int evc_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -static void evc_parser_close(AVCodecParserContext *s) +static av_cold void evc_parser_close(AVCodecParserContext *s) { EVCParserContext *ctx = s->priv_data; ff_evc_ps_free(&ctx->ps); } -const AVCodecParser ff_evc_parser = { - .codec_ids = { AV_CODEC_ID_EVC }, +const FFCodecParser ff_evc_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_EVC), .priv_data_size = sizeof(EVCParserContext), - .parser_parse = evc_parse, - .parser_close = evc_parser_close, + .parse = evc_parse, + .close = evc_parser_close, }; diff --git a/libavcodec/evc_ps.h b/libavcodec/evc_ps.h index 336953b17..dd0e151c4 100644 --- a/libavcodec/evc_ps.h +++ b/libavcodec/evc_ps.h @@ -102,7 +102,7 @@ typedef struct VUIParameters { HRDParameters hrd_parameters; } VUIParameters; -// The sturcture reflects SPS RBSP(raw byte sequence payload) layout +// The structure reflects SPS RBSP(raw byte sequence payload) layout // @see ISO_IEC_23094-1 section 7.3.2.1 // // The following descriptors specify the parsing process of each element diff --git a/libavcodec/evrcdec.c b/libavcodec/evrcdec.c index 44d5bee72..974c967b4 100644 --- a/libavcodec/evrcdec.c +++ b/libavcodec/evrcdec.c @@ -182,7 +182,7 @@ static evrc_packet_rate buf_size2bitrate(const int buf_size) * * @param avctx the AV codec context * @param buf_size length of the buffer - * @param buf the bufffer + * @param buf the buffer * * @return the bitrate on success, * RATE_ERRS if the bitrate cannot be satisfactorily determined @@ -239,6 +239,8 @@ static av_cold int evrc_decode_init(AVCodecContext *avctx) av_channel_layout_uninit(&avctx->ch_layout); avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; avctx->sample_fmt = AV_SAMPLE_FMT_FLT; + if (!avctx->sample_rate) + avctx->sample_rate = 8000; for (i = 0; i < FILTER_ORDER; i++) { e->prev_lspf[i] = (i + 1) * 0.048; diff --git a/libavcodec/executor.c b/libavcodec/executor.c new file mode 100644 index 000000000..3bf60bedb --- /dev/null +++ b/libavcodec/executor.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2024 Nuo Mi + * + * 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 "config.h" + +#include + +#include "libavutil/mem.h" +#include "libavutil/thread.h" + +#include "executor.h" + +#if !HAVE_THREADS + +#define ExecutorThread char + +#define executor_thread_create(t, a, s, ar) 0 +#define executor_thread_join(t, r) do {} while(0) + +#else + +#define ExecutorThread pthread_t + +#define executor_thread_create(t, a, s, ar) pthread_create(t, a, s, ar) +#define executor_thread_join(t, r) pthread_join(t, r) + +#endif //!HAVE_THREADS + +typedef struct ThreadInfo { + FFExecutor *e; + ExecutorThread thread; +} ThreadInfo; + +typedef struct Queue { + FFTask *head; + FFTask *tail; +} Queue; + +struct FFExecutor { + FFTaskCallbacks cb; + int thread_count; + bool recursive; + + ThreadInfo *threads; + uint8_t *local_contexts; + + AVMutex lock; + AVCond cond; + int die; + + Queue *q; +}; + +static FFTask* remove_task(Queue *q) +{ + FFTask *t = q->head; + if (t) { + q->head = t->next; + t->next = NULL; + if (!q->head) + q->tail = NULL; + } + return t; +} + +static void add_task(Queue *q, FFTask *t) +{ + t->next = NULL; + if (!q->head) + q->tail = q->head = t; + else + q->tail = q->tail->next = t; +} + +static int run_one_task(FFExecutor *e, void *lc) +{ + FFTaskCallbacks *cb = &e->cb; + FFTask *t = NULL; + + for (int i = 0; i < e->cb.priorities && !t; i++) + t = remove_task(e->q + i); + + if (t) { + if (e->thread_count > 0) + ff_mutex_unlock(&e->lock); + cb->run(t, lc, cb->user_data); + if (e->thread_count > 0) + ff_mutex_lock(&e->lock); + return 1; + } + return 0; +} + +#if HAVE_THREADS +static void *executor_worker_task(void *data) +{ + ThreadInfo *ti = (ThreadInfo*)data; + FFExecutor *e = ti->e; + void *lc = e->local_contexts + (ti - e->threads) * e->cb.local_context_size; + + ff_mutex_lock(&e->lock); + while (1) { + if (e->die) break; + + if (!run_one_task(e, lc)) { + //no task in one loop + ff_cond_wait(&e->cond, &e->lock); + } + } + ff_mutex_unlock(&e->lock); + return NULL; +} +#endif + +static av_cold void executor_free(FFExecutor *e, const int has_lock, const int has_cond) +{ + if (e->thread_count) { + //signal die + ff_mutex_lock(&e->lock); + e->die = 1; + ff_cond_broadcast(&e->cond); + ff_mutex_unlock(&e->lock); + + for (int i = 0; i < e->thread_count; i++) + executor_thread_join(e->threads[i].thread, NULL); + } + if (has_cond) + ff_cond_destroy(&e->cond); + if (has_lock) + ff_mutex_destroy(&e->lock); + + av_free(e->threads); + av_free(e->q); + av_free(e->local_contexts); + + av_free(e); +} + +av_cold FFExecutor* ff_executor_alloc(const FFTaskCallbacks *cb, int thread_count) +{ + FFExecutor *e; + int has_lock = 0, has_cond = 0; + if (!cb || !cb->user_data || !cb->run || !cb->priorities) + return NULL; + + e = av_mallocz(sizeof(*e)); + if (!e) + return NULL; + e->cb = *cb; + + e->local_contexts = av_calloc(FFMAX(thread_count, 1), e->cb.local_context_size); + if (!e->local_contexts) + goto free_executor; + + e->q = av_calloc(e->cb.priorities, sizeof(Queue)); + if (!e->q) + goto free_executor; + + e->threads = av_calloc(FFMAX(thread_count, 1), sizeof(*e->threads)); + if (!e->threads) + goto free_executor; + + if (!thread_count) + return e; + + has_lock = !ff_mutex_init(&e->lock, NULL); + has_cond = !ff_cond_init(&e->cond, NULL); + + if (!has_lock || !has_cond) + goto free_executor; + + for (/* nothing */; e->thread_count < thread_count; e->thread_count++) { + ThreadInfo *ti = e->threads + e->thread_count; + ti->e = e; + if (executor_thread_create(&ti->thread, NULL, executor_worker_task, ti)) + goto free_executor; + } + return e; + +free_executor: + executor_free(e, has_lock, has_cond); + return NULL; +} + +av_cold void ff_executor_free(FFExecutor **executor) +{ + int thread_count; + + if (!executor || !*executor) + return; + thread_count = (*executor)->thread_count; + executor_free(*executor, thread_count, thread_count); + *executor = NULL; +} + +void ff_executor_execute(FFExecutor *e, FFTask *t) +{ + if (e->thread_count) + ff_mutex_lock(&e->lock); + if (t) + add_task(e->q + t->priority % e->cb.priorities, t); + if (e->thread_count) { + ff_cond_signal(&e->cond); + ff_mutex_unlock(&e->lock); + } + + if (!e->thread_count || !HAVE_THREADS) { + if (e->recursive) + return; + e->recursive = true; + // We are running in a single-threaded environment, so we must handle all tasks ourselves + while (run_one_task(e, e->local_contexts)) + /* nothing */; + e->recursive = false; + } +} diff --git a/libavcodec/executor.h b/libavcodec/executor.h new file mode 100644 index 000000000..cd13d4c51 --- /dev/null +++ b/libavcodec/executor.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2024 Nuo Mi + * + * 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 + */ + +/* + * We still need several refactors to improve the current VVC decoder's performance, + * which will frequently break the API/ABI. To mitigate this, we've copied the executor from + * avutil to avcodec. Once the API/ABI is stable, we will move this class back to avutil + */ + +#ifndef AVCODEC_EXECUTOR_H +#define AVCODEC_EXECUTOR_H + +typedef struct FFExecutor FFExecutor; +typedef struct FFTask FFTask; + +struct FFTask { + FFTask *next; + int priority; // task priority should >= 0 and < AVTaskCallbacks.priorities +}; + +typedef struct FFTaskCallbacks { + void *user_data; + + int local_context_size; + + // how many priorities do we have? + int priorities; + + // run the task + int (*run)(FFTask *t, void *local_context, void *user_data); +} FFTaskCallbacks; + +/** + * Alloc executor + * @param callbacks callback structure for executor + * @param thread_count worker thread number, 0 for run on caller's thread directly + * @return return the executor + */ +FFExecutor* ff_executor_alloc(const FFTaskCallbacks *callbacks, int thread_count); + +/** + * Free executor + * @param e pointer to executor + */ +void ff_executor_free(FFExecutor **e); + +/** + * Add task to executor + * @param e pointer to executor + * @param t pointer to task. If NULL, it will wakeup one work thread + */ +void ff_executor_execute(FFExecutor *e, FFTask *t); + +#endif //AVCODEC_EXECUTOR_H diff --git a/libavcodec/exif.c b/libavcodec/exif.c index 959d114d0..e422b28b8 100644 --- a/libavcodec/exif.c +++ b/libavcodec/exif.c @@ -1,6 +1,7 @@ /* * EXIF metadata parser * Copyright (c) 2013 Thilo Borgmann + * Copyright (c) 2024-2025 Leo Izen * * This file is part of FFmpeg. * @@ -23,16 +24,39 @@ * @file * EXIF metadata parser * @author Thilo Borgmann + * @author Leo Izen */ -#include "exif.h" +#include + +#include "libavutil/avconfig.h" +#include "libavutil/bprint.h" +#include "libavutil/display.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" + +#include "bytestream.h" +#include "exif_internal.h" #include "tiff_common.h" +#define EXIF_II_LONG 0x49492a00 +#define EXIF_MM_LONG 0x4d4d002a + +#define BASE_TAG_SIZE 12 +#define IFD_EXTRA_SIZE 6 + #define EXIF_TAG_NAME_LENGTH 32 +#define MAKERNOTE_TAG 0x927c +#define ORIENTATION_TAG 0x112 +#define EXIFIFD_TAG 0x8769 +#define IMAGE_WIDTH_TAG 0x100 +#define IMAGE_LENGTH_TAG 0x101 +#define PIXEL_X_TAG 0xa002 +#define PIXEL_Y_TAG 0xa003 struct exif_tag { - char name[EXIF_TAG_NAME_LENGTH]; - uint16_t id; + const char name[EXIF_TAG_NAME_LENGTH]; + uint16_t id; }; static const struct exif_tag tag_list[] = { // JEITA CP-3451 EXIF specification: @@ -152,15 +176,63 @@ static const struct exif_tag tag_list[] = { // JEITA CP-3451 EXIF specification: {"Saturation", 0xA409}, {"Sharpness", 0xA40A}, {"DeviceSettingDescription", 0xA40B}, - {"SubjectDistanceRange", 0xA40C} -// {"InteroperabilityIndex", 0x1}, // <- Table 13 Interoperability IFD Attribute Information + {"SubjectDistanceRange", 0xA40C}, + + /* InteropIFD tags */ + {"RelatedImageFileFormat", 0x1000}, + {"RelatedImageWidth", 0x1001}, + {"RelatedImageLength", 0x1002}, + + /* private EXIF tags */ + {"PrintImageMatching", 0xC4A5}, // <- undocumented meaning + + /* IFD tags */ + {"ExifIFD", 0x8769}, // <- An IFD pointing to standard Exif metadata + {"GPSInfo", 0x8825}, // <- An IFD pointing to GPS Exif Metadata + {"InteropIFD", 0xA005}, // <- Table 13 Interoperability IFD Attribute Information + {"GlobalParametersIFD", 0x0190}, + {"ProfileIFD", 0xc6f5}, + + /* Extra FFmpeg tags */ + { "IFD1", 0xFFFC}, + { "IFD2", 0xFFFB}, + { "IFD3", 0xFFFA}, + { "IFD4", 0xFFF9}, + { "IFD5", 0xFFF8}, + { "IFD6", 0xFFF7}, + { "IFD7", 0xFFF6}, + { "IFD8", 0xFFF5}, + { "IFD9", 0xFFF4}, + { "IFD10", 0xFFF3}, + { "IFD11", 0xFFF2}, + { "IFD12", 0xFFF1}, + { "IFD13", 0xFFF0}, + { "IFD14", 0xFFEF}, + { "IFD15", 0xFFEE}, + { "IFD16", 0xFFED}, }; -static const char *exif_get_tag_name(uint16_t id) -{ - int i; +/* same as type_sizes but with string == 1 */ +static const size_t exif_sizes[] = { + [0] = 0, + [AV_TIFF_BYTE] = 1, + [AV_TIFF_STRING] = 1, + [AV_TIFF_SHORT] = 2, + [AV_TIFF_LONG] = 4, + [AV_TIFF_RATIONAL] = 8, + [AV_TIFF_SBYTE] = 1, + [AV_TIFF_UNDEFINED] = 1, + [AV_TIFF_SSHORT] = 2, + [AV_TIFF_SLONG] = 4, + [AV_TIFF_SRATIONAL] = 8, + [AV_TIFF_FLOAT] = 4, + [AV_TIFF_DOUBLE] = 8, + [AV_TIFF_IFD] = 4, +}; - for (i = 0; i < FF_ARRAY_ELEMS(tag_list); i++) { +const char *av_exif_get_tag_name(uint16_t id) +{ + for (size_t i = 0; i < FF_ARRAY_ELEMS(tag_list); i++) { if (tag_list[i].id == id) return tag_list[i].name; } @@ -168,106 +240,1301 @@ static const char *exif_get_tag_name(uint16_t id) return NULL; } - -static int exif_add_metadata(void *logctx, int count, int type, - const char *name, const char *sep, - GetByteContext *gb, int le, - AVDictionary **metadata) +int32_t av_exif_get_tag_id(const char *name) { - switch(type) { - case 0: - av_log(logctx, AV_LOG_WARNING, - "Invalid TIFF tag type 0 found for %s with size %d\n", - name, count); - return 0; - case TIFF_DOUBLE : return ff_tadd_doubles_metadata(count, name, sep, gb, le, metadata); - case TIFF_SSHORT : return ff_tadd_shorts_metadata(count, name, sep, gb, le, 1, metadata); - case TIFF_SHORT : return ff_tadd_shorts_metadata(count, name, sep, gb, le, 0, metadata); - case TIFF_SBYTE : return ff_tadd_bytes_metadata(count, name, sep, gb, le, 1, metadata); - case TIFF_BYTE : - case TIFF_UNDEFINED: return ff_tadd_bytes_metadata(count, name, sep, gb, le, 0, metadata); - case TIFF_STRING : return ff_tadd_string_metadata(count, name, gb, le, metadata); - case TIFF_SRATIONAL: - case TIFF_RATIONAL : return ff_tadd_rational_metadata(count, name, sep, gb, le, metadata); - case TIFF_SLONG : - case TIFF_LONG : return ff_tadd_long_metadata(count, name, sep, gb, le, metadata); - default: - avpriv_request_sample(logctx, "TIFF tag type (%u)", type); - return 0; - }; + if (!name) + return -1; + + for (size_t i = 0; i < FF_ARRAY_ELEMS(tag_list); i++) { + if (!strcmp(tag_list[i].name, name)) + return tag_list[i].id; + } + + return -1; } - -static int exif_decode_tag(void *logctx, GetByteContext *gbytes, int le, - int depth, AVDictionary **metadata) +static inline void tput16(PutByteContext *pb, const int le, const uint16_t value) { - int ret, cur_pos; - unsigned id, count; - enum TiffTypes type; + le ? bytestream2_put_le16(pb, value) : bytestream2_put_be16(pb, value); +} - if (depth > 2) { - return 0; +static inline void tput32(PutByteContext *pb, const int le, const uint32_t value) +{ + le ? bytestream2_put_le32(pb, value) : bytestream2_put_be32(pb, value); +} + +static inline void tput64(PutByteContext *pb, const int le, const uint64_t value) +{ + le ? bytestream2_put_le64(pb, value) : bytestream2_put_be64(pb, value); +} + +static int exif_read_values(void *logctx, GetByteContext *gb, int le, AVExifEntry *entry) +{ + if (exif_sizes[entry->type] * entry->count > bytestream2_get_bytes_left(gb)) + return AVERROR_INVALIDDATA; + + switch (entry->type) { + case AV_TIFF_SHORT: + case AV_TIFF_LONG: + entry->value.uint = av_calloc(entry->count, sizeof(*entry->value.uint)); + break; + case AV_TIFF_SSHORT: + case AV_TIFF_SLONG: + entry->value.sint = av_calloc(entry->count, sizeof(*entry->value.sint)); + break; + case AV_TIFF_DOUBLE: + case AV_TIFF_FLOAT: + entry->value.dbl = av_calloc(entry->count, sizeof(*entry->value.dbl)); + break; + case AV_TIFF_RATIONAL: + case AV_TIFF_SRATIONAL: + entry->value.rat = av_calloc(entry->count, sizeof(*entry->value.rat)); + break; + case AV_TIFF_UNDEFINED: + case AV_TIFF_BYTE: + entry->value.ubytes = av_mallocz(entry->count); + break; + case AV_TIFF_SBYTE: + entry->value.sbytes = av_mallocz(entry->count); + break; + case AV_TIFF_STRING: + entry->value.str = av_mallocz(entry->count + 1); + break; + case AV_TIFF_IFD: + av_log(logctx, AV_LOG_WARNING, "Bad IFD type for non-IFD tag\n"); + return AVERROR_INVALIDDATA; + } + if (!entry->value.ptr) + return AVERROR(ENOMEM); + switch (entry->type) { + case AV_TIFF_SHORT: + for (size_t i = 0; i < entry->count; i++) + entry->value.uint[i] = ff_tget_short(gb, le); + break; + case AV_TIFF_LONG: + for (size_t i = 0; i < entry->count; i++) + entry->value.uint[i] = ff_tget_long(gb, le); + break; + case AV_TIFF_SSHORT: + for (size_t i = 0; i < entry->count; i++) + entry->value.sint[i] = (int16_t) ff_tget_short(gb, le); + break; + case AV_TIFF_SLONG: + for (size_t i = 0; i < entry->count; i++) + entry->value.sint[i] = (int32_t) ff_tget_long(gb, le); + break; + case AV_TIFF_DOUBLE: + for (size_t i = 0; i < entry->count; i++) + entry->value.dbl[i] = ff_tget_double(gb, le); + break; + case AV_TIFF_FLOAT: + for (size_t i = 0; i < entry->count; i++) { + av_alias32 alias = { .u32 = ff_tget_long(gb, le) }; + entry->value.dbl[i] = alias.f32; + } + break; + case AV_TIFF_RATIONAL: + case AV_TIFF_SRATIONAL: + for (size_t i = 0; i < entry->count; i++) { + int32_t num = ff_tget_long(gb, le); + int32_t den = ff_tget_long(gb, le); + entry->value.rat[i] = av_make_q(num, den); + } + break; + case AV_TIFF_UNDEFINED: + case AV_TIFF_BYTE: + /* these three fields are aliased to entry->value.ptr via a union */ + /* and entry->value.ptr will always be nonzero here */ + av_assert0(entry->value.ubytes); + bytestream2_get_buffer(gb, entry->value.ubytes, entry->count); + break; + case AV_TIFF_SBYTE: + av_assert0(entry->value.sbytes); + bytestream2_get_buffer(gb, entry->value.sbytes, entry->count); + break; + case AV_TIFF_STRING: + av_assert0(entry->value.str); + bytestream2_get_buffer(gb, entry->value.str, entry->count); + break; } - ff_tread_tag(gbytes, le, &id, &type, &count, &cur_pos); + return 0; +} - if (!bytestream2_tell(gbytes)) { - bytestream2_seek(gbytes, cur_pos, SEEK_SET); - return 0; +static void exif_write_values(PutByteContext *pb, int le, const AVExifEntry *entry) +{ + switch (entry->type) { + case AV_TIFF_SHORT: + for (size_t i = 0; i < entry->count; i++) + tput16(pb, le, entry->value.uint[i]); + break; + case AV_TIFF_LONG: + for (size_t i = 0; i < entry->count; i++) + tput32(pb, le, entry->value.uint[i]); + break; + case AV_TIFF_SSHORT: + for (size_t i = 0; i < entry->count; i++) + tput16(pb, le, entry->value.sint[i]); + break; + case AV_TIFF_SLONG: + for (size_t i = 0; i < entry->count; i++) + tput32(pb, le, entry->value.sint[i]); + break; + case AV_TIFF_DOUBLE: + for (size_t i = 0; i < entry->count; i++) { + const av_alias64 a = { .f64 = entry->value.dbl[i] }; + tput64(pb, le, a.u64); + } + break; + case AV_TIFF_FLOAT: + for (size_t i = 0; i < entry->count; i++) { + const av_alias32 a = { .f32 = entry->value.dbl[i] }; + tput32(pb, le, a.u32); + } + break; + case AV_TIFF_RATIONAL: + case AV_TIFF_SRATIONAL: + for (size_t i = 0; i < entry->count; i++) { + tput32(pb, le, entry->value.rat[i].num); + tput32(pb, le, entry->value.rat[i].den); + } + break; + case AV_TIFF_UNDEFINED: + case AV_TIFF_BYTE: + bytestream2_put_buffer(pb, entry->value.ubytes, entry->count); + break; + case AV_TIFF_SBYTE: + bytestream2_put_buffer(pb, entry->value.sbytes, entry->count); + break; + case AV_TIFF_STRING: + bytestream2_put_buffer(pb, entry->value.str, entry->count); + break; + } +} + +static const uint8_t aoc_header[] = { 'A', 'O', 'C', 0, }; +static const uint8_t casio_header[] = { 'Q', 'V', 'C', 0, 0, 0, }; +static const uint8_t foveon_header[] = { 'F', 'O', 'V', 'E', 'O', 'N', 0, 0, }; +static const uint8_t fuji_header[] = { 'F', 'U', 'J', 'I', }; +static const uint8_t nikon_header[] = { 'N', 'i', 'k', 'o', 'n', 0, }; +static const uint8_t olympus1_header[] = { 'O', 'L', 'Y', 'M', 'P', 0, }; +static const uint8_t olympus2_header[] = { 'O', 'L', 'Y', 'M', 'P', 'U', 'S', 0, 'I', 'I', }; +static const uint8_t panasonic_header[] = { 'P', 'a', 'n', 'a', 's', 'o', 'n', 'i', 'c', 0, 0, 0, }; +static const uint8_t sigma_header[] = { 'S', 'I', 'G', 'M', 'A', 0, 0, 0, }; +static const uint8_t sony_header[] = { 'S', 'O', 'N', 'Y', ' ', 'D', 'S', 'C', ' ', 0, 0, 0, }; + +struct exif_makernote_data { + const uint8_t *header; + size_t header_size; + int result; +}; + +#define MAKERNOTE_STRUCT(h, r) { \ + .header = (h), \ + .header_size = sizeof((h)), \ + .result = (r), \ +} + +static const struct exif_makernote_data makernote_data[] = { + MAKERNOTE_STRUCT(aoc_header, 6), + MAKERNOTE_STRUCT(casio_header, -1), + MAKERNOTE_STRUCT(foveon_header, 10), + MAKERNOTE_STRUCT(fuji_header, -1), + MAKERNOTE_STRUCT(olympus1_header, 8), + MAKERNOTE_STRUCT(olympus2_header, -1), + MAKERNOTE_STRUCT(panasonic_header, 12), + MAKERNOTE_STRUCT(sigma_header, 10), + MAKERNOTE_STRUCT(sony_header, 12), +}; + +/* + * derived from Exiv2 MakerNote's article + * https://exiv2.org/makernote.html or archived at + * https://web.archive.org/web/20250311155857/https://exiv2.org/makernote.html + */ +static int exif_get_makernote_offset(GetByteContext *gb) +{ + if (bytestream2_get_bytes_left(gb) < BASE_TAG_SIZE) + return -1; + + for (int i = 0; i < FF_ARRAY_ELEMS(makernote_data); i++) { + if (!memcmp(gb->buffer, makernote_data[i].header, makernote_data[i].header_size)) + return makernote_data[i].result; } - // read count values and add it metadata - // store metadata or proceed with next IFD - ret = ff_tis_ifd(id); - if (ret) { - ret = ff_exif_decode_ifd(logctx, gbytes, le, depth + 1, metadata); - } else { - const char *name = exif_get_tag_name(id); - char buf[7]; + if (!memcmp(gb->buffer, nikon_header, sizeof(nikon_header))) { + if (bytestream2_get_bytes_left(gb) < 14) + return -1; + else if (AV_RB32(gb->buffer + 10) == EXIF_MM_LONG || AV_RB32(gb->buffer + 10) == EXIF_II_LONG) + return -1; + return 8; + } - if (!name) { - name = buf; - snprintf(buf, sizeof(buf), "0x%04X", id); + return 0; +} + +static int exif_parse_ifd_list(void *logctx, GetByteContext *gb, int le, + int depth, AVExifMetadata *ifd, int guess); + +static int exif_decode_tag(void *logctx, GetByteContext *gb, int le, + int depth, AVExifEntry *entry) +{ + int ret = 0, makernote_offset = -1, tell, is_ifd, count; + enum AVTiffDataType type; + uint32_t payload; + + /* safety check to prevent infinite recursion on malicious IFDs */ + if (depth > 3) + return AVERROR_INVALIDDATA; + + tell = bytestream2_tell(gb); + + entry->id = ff_tget_short(gb, le); + type = ff_tget_short(gb, le); + count = ff_tget_long(gb, le); + payload = ff_tget_long(gb, le); + + av_log(logctx, AV_LOG_DEBUG, "TIFF Tag: id: 0x%04x, type: %d, count: %u, offset: %d, " + "payload: %" PRIu32 "\n", entry->id, type, count, tell, payload); + + if (!type) { + av_log(logctx, AV_LOG_DEBUG, "Skipping invalid TIFF tag 0\n"); + goto end; + } + + /* AV_TIFF_IFD is the largest, numerically */ + if (type > AV_TIFF_IFD || count >= INT_MAX/8U) + return AVERROR_INVALIDDATA; + + is_ifd = type == AV_TIFF_IFD || ff_tis_ifd(entry->id) || entry->id == MAKERNOTE_TAG; + + if (is_ifd) { + if (!payload) + goto end; + bytestream2_seek(gb, payload, SEEK_SET); + } + + if (entry->id == MAKERNOTE_TAG) { + makernote_offset = exif_get_makernote_offset(gb); + if (makernote_offset < 0) + is_ifd = 0; + } + + if (is_ifd) { + entry->type = AV_TIFF_IFD; + entry->count = 1; + entry->ifd_offset = makernote_offset > 0 ? makernote_offset : 0; + if (entry->ifd_offset) { + entry->ifd_lead = av_malloc(entry->ifd_offset); + if (!entry->ifd_lead) + return AVERROR(ENOMEM); + bytestream2_get_buffer(gb, entry->ifd_lead, entry->ifd_offset); + } + ret = exif_parse_ifd_list(logctx, gb, le, depth + 1, &entry->value.ifd, entry->id == MAKERNOTE_TAG); + if (ret < 0 && entry->id == MAKERNOTE_TAG) { + /* + * we guessed that MakerNote was an IFD + * but we were probably incorrect at this + * point so we try again as a binary blob + */ + av_log(logctx, AV_LOG_DEBUG, "unrecognized MakerNote IFD, retrying as blob\n"); + is_ifd = 0; } - - ret = exif_add_metadata(logctx, count, type, name, NULL, - gbytes, le, metadata); } - bytestream2_seek(gbytes, cur_pos, SEEK_SET); + /* inverted condition instead of else so we can fall through from above */ + if (!is_ifd) { + entry->type = type == AV_TIFF_IFD ? AV_TIFF_UNDEFINED : type; + entry->count = count; + bytestream2_seek(gb, count * exif_sizes[type] > 4 ? payload : tell + 8, SEEK_SET); + ret = exif_read_values(logctx, gb, le, entry); + } + +end: + bytestream2_seek(gb, tell + BASE_TAG_SIZE, SEEK_SET); return ret; } - -int ff_exif_decode_ifd(void *logctx, GetByteContext *gbytes, - int le, int depth, AVDictionary **metadata) +static int exif_parse_ifd_list(void *logctx, GetByteContext *gb, int le, + int depth, AVExifMetadata *ifd, int guess) { - int i, ret; - int entries; + uint32_t entries; + size_t required_size; + void *temp; + int ret = 0; - entries = ff_tget_short(gbytes, le); + av_log(logctx, AV_LOG_DEBUG, "parsing IFD list at offset: %d\n", bytestream2_tell(gb)); - if (bytestream2_get_bytes_left(gbytes) < entries * 12) { - return AVERROR_INVALIDDATA; + if (bytestream2_get_bytes_left(gb) < 2) { + av_log(logctx, guess ? AV_LOG_DEBUG : AV_LOG_ERROR, + "not enough bytes remaining in EXIF buffer: 2 required\n"); + ret = AVERROR_INVALIDDATA; + goto end; } - for (i = 0; i < entries; i++) { - if ((ret = exif_decode_tag(logctx, gbytes, le, depth, metadata)) < 0) { - return ret; + entries = ff_tget_short(gb, le); + if (bytestream2_get_bytes_left(gb) < entries * BASE_TAG_SIZE) { + av_log(logctx, guess ? AV_LOG_DEBUG : AV_LOG_ERROR, + "not enough bytes remaining in EXIF buffer. entries: %" PRIu32 "\n", entries); + ret = AVERROR_INVALIDDATA; + goto end; + } + if (entries > 4096) { + /* that is a lot of entries, probably an error */ + av_log(logctx, guess ? AV_LOG_DEBUG : AV_LOG_ERROR, + "too many entries: %" PRIu32 "\n", entries); + ret = AVERROR_INVALIDDATA; + goto end; + } + + ifd->count = entries; + av_log(logctx, AV_LOG_DEBUG, "entry count for IFD: %u\n", ifd->count); + + /* empty IFD is technically legal but equivalent to no metadata present */ + if (!ifd->count) { + ret = 0; + goto end; + } + + if (av_size_mult(ifd->count, sizeof(*ifd->entries), &required_size) < 0) { + ret = AVERROR(ENOMEM); + goto end; + } + temp = av_fast_realloc(ifd->entries, &ifd->size, required_size); + if (!temp) { + av_freep(&ifd->entries); + ret = AVERROR(ENOMEM); + goto end; + } + ifd->entries = temp; + + /* entries have pointers in them which can cause issues if */ + /* they are freed or realloc'd when garbage */ + memset(ifd->entries, 0, required_size); + + for (uint32_t i = 0; i < entries; i++) { + ret = exif_decode_tag(logctx, gb, le, depth, &ifd->entries[i]); + if (ret < 0) + goto end; + } + +end: + if (ret < 0) { + av_exif_free(ifd); + return ret; + } + /* + * at the end of an IFD is an pointer to the next IFD + * or zero if there are no more IFDs, which is usually the case + */ + ret = ff_tget_long(gb, le); + + /* overflow */ + if (ret < 0) { + ret = AVERROR_INVALIDDATA; + av_exif_free(ifd); + } + + return ret; +} + +/* + * note that this function does not free the entry pointer itself + * because it's probably part of a larger array that should be freed + * all at once + */ +static void exif_free_entry(AVExifEntry *entry) +{ + if (!entry) + return; + if (entry->type == AV_TIFF_IFD) + av_exif_free(&entry->value.ifd); + else + av_freep(&entry->value.ptr); + av_freep(&entry->ifd_lead); +} + +void av_exif_free(AVExifMetadata *ifd) +{ + if (!ifd) + return; + if (!ifd->entries) { + ifd->count = 0; + ifd->size = 0; + return; + } + for (size_t i = 0; i < ifd->count; i++) { + AVExifEntry *entry = &ifd->entries[i]; + exif_free_entry(entry); + } + av_freep(&ifd->entries); + ifd->count = 0; + ifd->size = 0; +} + +static size_t exif_get_ifd_size(const AVExifMetadata *ifd) +{ + /* 6 == 4 + 2; 2-byte entry-count at the beginning */ + /* plus 4-byte next-IFD pointer at the end */ + size_t total_size = IFD_EXTRA_SIZE; + for (size_t i = 0; i < ifd->count; i++) { + const AVExifEntry *entry = &ifd->entries[i]; + if (entry->type == AV_TIFF_IFD) { + total_size += BASE_TAG_SIZE + exif_get_ifd_size(&entry->value.ifd) + entry->ifd_offset; + } else { + size_t payload_size = entry->count * exif_sizes[entry->type]; + total_size += BASE_TAG_SIZE + (payload_size > 4 ? payload_size : 0); + } + } + return total_size; +} + +static int exif_write_ifd(void *logctx, PutByteContext *pb, int le, int depth, const AVExifMetadata *ifd) +{ + int offset, ret, tell, tell2; + tell = bytestream2_tell_p(pb); + tput16(pb, le, ifd->count); + offset = tell + IFD_EXTRA_SIZE + BASE_TAG_SIZE * (uint32_t) ifd->count; + av_log(logctx, AV_LOG_DEBUG, "writing IFD with %u entries and initial offset %d\n", ifd->count, offset); + for (size_t i = 0; i < ifd->count; i++) { + const AVExifEntry *entry = &ifd->entries[i]; + av_log(logctx, AV_LOG_DEBUG, "writing TIFF entry: id: 0x%04" PRIx16 ", type: %d, count: %" + PRIu32 ", offset: %d, offset value: %d\n", + entry->id, entry->type, entry->count, + bytestream2_tell_p(pb), offset); + tput16(pb, le, entry->id); + if (entry->id == MAKERNOTE_TAG && entry->type == AV_TIFF_IFD) { + size_t ifd_size = exif_get_ifd_size(&entry->value.ifd); + tput16(pb, le, AV_TIFF_UNDEFINED); + tput32(pb, le, ifd_size); + } else { + tput16(pb, le, entry->type); + tput32(pb, le, entry->count); + } + if (entry->type == AV_TIFF_IFD) { + tput32(pb, le, offset); + tell2 = bytestream2_tell_p(pb); + bytestream2_seek_p(pb, offset, SEEK_SET); + if (entry->ifd_offset) + bytestream2_put_buffer(pb, entry->ifd_lead, entry->ifd_offset); + ret = exif_write_ifd(logctx, pb, le, depth + 1, &entry->value.ifd); + if (ret < 0) + return ret; + offset += ret + entry->ifd_offset; + bytestream2_seek_p(pb, tell2, SEEK_SET); + } else { + size_t payload_size = entry->count * exif_sizes[entry->type]; + if (payload_size > 4) { + tput32(pb, le, offset); + tell2 = bytestream2_tell_p(pb); + bytestream2_seek_p(pb, offset, SEEK_SET); + exif_write_values(pb, le, entry); + offset += payload_size; + bytestream2_seek_p(pb, tell2, SEEK_SET); + } else { + /* zero uninitialized excess payload values */ + AV_WN32(pb->buffer, 0); + exif_write_values(pb, le, entry); + bytestream2_seek_p(pb, 4 - payload_size, SEEK_CUR); + } } } - // return next IDF offset or 0x000000000 or a value < 0 for failure - return ff_tget_long(gbytes, le); + /* + * we write 0 if this is the top-level exif IFD + * indicating that there are no more IFD pointers + */ + tput32(pb, le, depth ? offset : 0); + return offset - tell; } +int av_exif_write(void *logctx, const AVExifMetadata *ifd, AVBufferRef **buffer, enum AVExifHeaderMode header_mode) +{ + AVBufferRef *buf = NULL; + size_t size, headsize = 8; + PutByteContext pb; + int ret = 0, off = 0, next; + AVExifMetadata *ifd_new = NULL; + AVExifMetadata extra_ifds[16] = { 0 }; + + int le = 1; + + if (*buffer) { + ret = AVERROR(EINVAL); + goto end; + } + + size = exif_get_ifd_size(ifd); + switch (header_mode) { + case AV_EXIF_EXIF00: + off = 6; + break; + case AV_EXIF_T_OFF: + off = 4; + break; + case AV_EXIF_ASSUME_BE: + le = 0; + headsize = 0; + break; + case AV_EXIF_ASSUME_LE: + le = 1; + headsize = 0; + break; + } + + ret = av_buffer_realloc(&buf, size + off + headsize); + if (ret < 0) + goto end; + + if (header_mode == AV_EXIF_EXIF00) { + AV_WL32(buf->data, MKTAG('E','x','i','f')); + AV_WN16(buf->data + 4, 0); + } else if (header_mode == AV_EXIF_T_OFF) { + AV_WN32(buf->data, 0); + } + + bytestream2_init_writer(&pb, buf->data + off, buf->size - off); + + if (header_mode != AV_EXIF_ASSUME_BE && header_mode != AV_EXIF_ASSUME_LE) { + /* these constants are be32 in both cases */ + /* le == 1 always in this case */ + bytestream2_put_be32(&pb, EXIF_II_LONG); + tput32(&pb, le, 8); + } + + int extras = 0; + for (int i = 0; i < FF_ARRAY_ELEMS(extra_ifds); i++) { + AVExifEntry *extra_entry = NULL; + uint16_t extra_tag = 0xFFFCu - i; + ret = av_exif_get_entry(logctx, (AVExifMetadata *) ifd, extra_tag, 0, &extra_entry); + if (ret < 0) + break; + if (!ret) + continue; + av_log(logctx, AV_LOG_DEBUG, "found extra IFD tag: %04x\n", extra_tag); + if (!ifd_new) { + ifd_new = av_exif_clone_ifd(ifd); + if (!ifd_new) + break; + ifd = ifd_new; + } + /* calling remove_entry will call av_exif_free on the original */ + AVExifMetadata *cloned = av_exif_clone_ifd(&extra_entry->value.ifd); + if (!cloned) + break; + extra_ifds[extras++] = *cloned; + /* don't use av_exif_free here, we want to preserve internals */ + av_free(cloned); + ret = av_exif_remove_entry(logctx, ifd_new, extra_tag, 0); + if (ret < 0) + break; + } + + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, "error popping additional IFD: %s\n", av_err2str(ret)); + goto end; + } + + next = bytestream2_tell_p(&pb); + ret = exif_write_ifd(logctx, &pb, le, 0, ifd); + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, "error writing EXIF data: %s\n", av_err2str(ret)); + goto end; + } + next += ret; + + for (int i = 0; i < extras; i++) { + av_log(logctx, AV_LOG_DEBUG, "writing additional ifd at: %d\n", next); + /* exif_write_ifd always writes 0 i.e. last ifd so we overwrite that here */ + bytestream2_seek_p(&pb, -4, SEEK_CUR); + tput32(&pb, le, next); + bytestream2_seek_p(&pb, next, SEEK_SET); + ret = exif_write_ifd(logctx, &pb, le, 0, &extra_ifds[i]); + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, "error writing additional IFD: %s\n", av_err2str(ret)); + goto end; + } + next += ret; + } + + /* shrink the buffer to the amount of data we actually used */ + /* extras don't contribute the initial BASE_TAG_SIZE each */ + ret = av_buffer_realloc(&buf, buf->size - BASE_TAG_SIZE * extras); + if (ret < 0) + goto end; + + *buffer = buf; + ret = 0; + +end: + av_exif_free(ifd_new); + av_freep(&ifd_new); + for (int i = 0; i < FF_ARRAY_ELEMS(extra_ifds); i++) + av_exif_free(&extra_ifds[i]); + if (ret < 0) + av_buffer_unref(&buf); + + return ret; +} + +int av_exif_parse_buffer(void *logctx, const uint8_t *buf, size_t size, + AVExifMetadata *ifd, enum AVExifHeaderMode header_mode) +{ + int ret, le; + GetByteContext gbytes; + if (size > INT_MAX) + return AVERROR(EINVAL); + size_t off = 0; + switch (header_mode) { + case AV_EXIF_EXIF00: + if (size < 6) + return AVERROR_INVALIDDATA; + off = 6; + /* fallthrough */ + case AV_EXIF_T_OFF: + if (size < 4) + return AVERROR_INVALIDDATA; + if (!off) + off = AV_RB32(buf) + 4; + /* fallthrough */ + case AV_EXIF_TIFF_HEADER: { + int ifd_offset; + if (size <= off) + return AVERROR_INVALIDDATA; + bytestream2_init(&gbytes, buf + off, size - off); + // read TIFF header + ret = ff_tdecode_header(&gbytes, &le, &ifd_offset); + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, "invalid TIFF header in EXIF data: %s\n", av_err2str(ret)); + return ret; + } + bytestream2_seek(&gbytes, ifd_offset, SEEK_SET); + break; + } + case AV_EXIF_ASSUME_LE: + le = 1; + bytestream2_init(&gbytes, buf, size); + break; + case AV_EXIF_ASSUME_BE: + le = 0; + bytestream2_init(&gbytes, buf, size); + break; + default: + return AVERROR(EINVAL); + } + + /* + * parse IFD0 here. If the return value is positive that tells us + * there is subimage metadata, but we don't parse that IFD here + */ + ret = exif_parse_ifd_list(logctx, &gbytes, le, 0, ifd, 0); + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, "error decoding EXIF data: %s\n", av_err2str(ret)); + return ret; + } + if (!ret) + goto finish; + int next = ret; + bytestream2_seek(&gbytes, next, SEEK_SET); + + /* cap at 16 extra IFDs for sanity/parse security */ + for (int extra_tag = 0xFFFCu; extra_tag > 0xFFECu; extra_tag--) { + AVExifMetadata extra_ifd = { 0 }; + ret = exif_parse_ifd_list(logctx, &gbytes, le, 0, &extra_ifd, 1); + if (ret < 0) { + av_exif_free(&extra_ifd); + break; + } + next = ret; + av_log(logctx, AV_LOG_DEBUG, "found extra IFD: %04x with next=%d\n", extra_tag, ret); + bytestream2_seek(&gbytes, next, SEEK_SET); + ret = av_exif_set_entry(logctx, ifd, extra_tag, AV_TIFF_IFD, 1, NULL, 0, &extra_ifd); + av_exif_free(&extra_ifd); + if (ret < 0 || !next || bytestream2_get_bytes_left(&gbytes) <= 0) + break; + } + +finish: + return bytestream2_tell(&gbytes) + off; +} + +#define COLUMN_SEP(i, c) ((i) ? ((i) % (c) ? ", " : "\n") : "") + +static int exif_ifd_to_dict(void *logctx, const char *prefix, const AVExifMetadata *ifd, AVDictionary **metadata) +{ + AVBPrint bp; + int ret = 0; + char *key = NULL; + char *value = NULL; + + if (!prefix) + prefix = ""; + + for (uint16_t i = 0; i < ifd->count; i++) { + const AVExifEntry *entry = &ifd->entries[i]; + const char *name = av_exif_get_tag_name(entry->id); + av_bprint_init(&bp, entry->count * 10, AV_BPRINT_SIZE_UNLIMITED); + if (*prefix) + av_bprintf(&bp, "%s/", prefix); + if (name) + av_bprintf(&bp, "%s", name); + else + av_bprintf(&bp, "0x%04X", entry->id); + ret = av_bprint_finalize(&bp, &key); + if (ret < 0) + goto end; + av_bprint_init(&bp, entry->count * 10, AV_BPRINT_SIZE_UNLIMITED); + switch (entry->type) { + case AV_TIFF_IFD: + ret = exif_ifd_to_dict(logctx, key, &entry->value.ifd, metadata); + if (ret < 0) + goto end; + break; + case AV_TIFF_SHORT: + case AV_TIFF_LONG: + for (uint32_t j = 0; j < entry->count; j++) + av_bprintf(&bp, "%s%7" PRIu32, COLUMN_SEP(j, 8), (uint32_t)entry->value.uint[j]); + break; + case AV_TIFF_SSHORT: + case AV_TIFF_SLONG: + for (uint32_t j = 0; j < entry->count; j++) + av_bprintf(&bp, "%s%7" PRId32, COLUMN_SEP(j, 8), (int32_t)entry->value.sint[j]); + break; + case AV_TIFF_RATIONAL: + case AV_TIFF_SRATIONAL: + for (uint32_t j = 0; j < entry->count; j++) + av_bprintf(&bp, "%s%7i:%-7i", COLUMN_SEP(j, 4), entry->value.rat[j].num, entry->value.rat[j].den); + break; + case AV_TIFF_DOUBLE: + case AV_TIFF_FLOAT: + for (uint32_t j = 0; j < entry->count; j++) + av_bprintf(&bp, "%s%.15g", COLUMN_SEP(j, 4), entry->value.dbl[j]); + break; + case AV_TIFF_STRING: + av_bprintf(&bp, "%s", entry->value.str); + break; + case AV_TIFF_UNDEFINED: + case AV_TIFF_BYTE: + for (uint32_t j = 0; j < entry->count; j++) + av_bprintf(&bp, "%s%3i", COLUMN_SEP(j, 16), entry->value.ubytes[j]); + break; + case AV_TIFF_SBYTE: + for (uint32_t j = 0; j < entry->count; j++) + av_bprintf(&bp, "%s%3i", COLUMN_SEP(j, 16), entry->value.sbytes[j]); + break; + } + if (entry->type != AV_TIFF_IFD) { + if (!av_bprint_is_complete(&bp)) { + av_bprint_finalize(&bp, NULL); + ret = AVERROR(ENOMEM); + goto end; + } + ret = av_bprint_finalize(&bp, &value); + if (ret < 0) + goto end; + ret = av_dict_set(metadata, key, value, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + key = NULL; + value = NULL; + if (ret < 0) + goto end; + } else { + av_freep(&key); + } + } + +end: + av_freep(&key); + av_freep(&value); + return ret; +} + +int av_exif_ifd_to_dict(void *logctx, const AVExifMetadata *ifd, AVDictionary **metadata) +{ + return exif_ifd_to_dict(logctx, "", ifd, metadata); +} + +#if LIBAVCODEC_VERSION_MAJOR < 63 int avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size, int le, int depth, AVDictionary **metadata) { + AVExifMetadata ifd = { 0 }; GetByteContext gb; - + int ret; bytestream2_init(&gb, buf, size); + ret = exif_parse_ifd_list(logctx, &gb, le, depth, &ifd, 0); + if (ret < 0) + return ret; + ret = av_exif_ifd_to_dict(logctx, &ifd, metadata); + av_exif_free(&ifd); + return ret; +} +#endif - return ff_exif_decode_ifd(logctx, &gb, le, depth, metadata); +#define EXIF_COPY(fname, srcname) do { \ + size_t sz; \ + if (av_size_mult(src->count, sizeof(*(fname)), &sz) < 0) { \ + ret = AVERROR(ENOMEM); \ + goto end; \ + } \ + (fname) = av_memdup((srcname), sz); \ + if (!(fname)) { \ + ret = AVERROR(ENOMEM); \ + goto end; \ + } \ +} while (0) + +static int exif_clone_entry(AVExifEntry *dst, const AVExifEntry *src) +{ + int ret = 0; + + memset(dst, 0, sizeof(*dst)); + + dst->count = src->count; + dst->id = src->id; + dst->type = src->type; + + dst->ifd_offset = src->ifd_offset; + if (src->ifd_lead) { + dst->ifd_lead = av_memdup(src->ifd_lead, src->ifd_offset); + if (!dst->ifd_lead) { + ret = AVERROR(ENOMEM); + goto end; + } + } else { + dst->ifd_lead = NULL; + } + + switch(src->type) { + case AV_TIFF_IFD: { + AVExifMetadata *cloned = av_exif_clone_ifd(&src->value.ifd); + if (!cloned) { + ret = AVERROR(ENOMEM); + goto end; + } + dst->value.ifd = *cloned; + av_freep(&cloned); + break; + } + case AV_TIFF_SHORT: + case AV_TIFF_LONG: + EXIF_COPY(dst->value.uint, src->value.uint); + break; + case AV_TIFF_SLONG: + case AV_TIFF_SSHORT: + EXIF_COPY(dst->value.sint, src->value.sint); + break; + case AV_TIFF_RATIONAL: + case AV_TIFF_SRATIONAL: + EXIF_COPY(dst->value.rat, src->value.rat); + break; + case AV_TIFF_DOUBLE: + case AV_TIFF_FLOAT: + EXIF_COPY(dst->value.dbl, src->value.dbl); + break; + case AV_TIFF_BYTE: + case AV_TIFF_UNDEFINED: + EXIF_COPY(dst->value.ubytes, src->value.ubytes); + break; + case AV_TIFF_SBYTE: + EXIF_COPY(dst->value.sbytes, src->value.sbytes); + break; + case AV_TIFF_STRING: + dst->value.str = av_memdup(src->value.str, src->count+1); + if (!dst->value.str) { + ret = AVERROR(ENOMEM); + goto end; + } + break; + } + + return 0; + +end: + av_freep(&dst->ifd_lead); + if (src->type == AV_TIFF_IFD) + av_exif_free(&dst->value.ifd); + else + av_freep(&dst->value.ptr); + memset(dst, 0, sizeof(*dst)); + + return ret; +} + +static int exif_get_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int depth, AVExifEntry **value) +{ + int offset = 1; + + if (!ifd || ifd->count && !ifd->entries || !value) + return AVERROR(EINVAL); + + for (size_t i = 0; i < ifd->count; i++) { + if (ifd->entries[i].id == id) { + *value = &ifd->entries[i]; + return i + offset; + } + if (ifd->entries[i].type == AV_TIFF_IFD) { + if (depth < 3) { + int ret = exif_get_entry(logctx, &ifd->entries[i].value.ifd, id, depth + 1, value); + if (ret) + return ret < 0 ? ret : ret + offset; + } + offset += ifd->entries[i].value.ifd.count; + } + } + + return 0; +} + +int av_exif_get_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags, AVExifEntry **value) +{ + return exif_get_entry(logctx, ifd, id, (flags & AV_EXIF_FLAG_RECURSIVE) ? 0 : INT_MAX, value); +} + +int av_exif_set_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, enum AVTiffDataType type, + uint32_t count, const uint8_t *ifd_lead, uint32_t ifd_offset, const void *value) +{ + void *temp; + int ret = 0; + AVExifEntry *entry = NULL; + AVExifEntry src = { 0 }; + + if (!ifd || ifd->count && !ifd->entries + || ifd_lead && !ifd_offset || !ifd_lead && ifd_offset + || !value || ifd->count == 0xFFFFu) + return AVERROR(EINVAL); + + ret = av_exif_get_entry(logctx, ifd, id, 0, &entry); + if (ret < 0) + return ret; + + if (entry) { + exif_free_entry(entry); + } else { + size_t required_size; + ret = av_size_mult(ifd->count + 1, sizeof(*ifd->entries), &required_size); + if (ret < 0) + return AVERROR(ENOMEM); + temp = av_fast_realloc(ifd->entries, &ifd->size, required_size); + if (!temp) + return AVERROR(ENOMEM); + ifd->entries = temp; + entry = &ifd->entries[ifd->count++]; + } + + src.count = count; + src.id = id; + src.type = type; + src.ifd_lead = (uint8_t *) ifd_lead; + src.ifd_offset = ifd_offset; + if (type == AV_TIFF_IFD) + src.value.ifd = * (const AVExifMetadata *) value; + else + src.value.ptr = (void *) value; + + ret = exif_clone_entry(entry, &src); + + if (ret < 0) + ifd->count--; + + return ret; +} + +static int exif_remove_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int depth) +{ + int32_t index = -1; + int ret = 0; + + if (!ifd || ifd->count && !ifd->entries) + return AVERROR(EINVAL); + + for (size_t i = 0; i < ifd->count; i++) { + if (ifd->entries[i].id == id) { + index = i; + break; + } + if (ifd->entries[i].type == AV_TIFF_IFD && depth < 3) { + ret = exif_remove_entry(logctx, &ifd->entries[i].value.ifd, id, depth + 1); + if (ret) + return ret; + } + } + + if (index < 0) + return 0; + exif_free_entry(&ifd->entries[index]); + + if (index == --ifd->count) { + if (!index) + av_freep(&ifd->entries); + return 1; + } + + memmove(&ifd->entries[index], &ifd->entries[index + 1], (ifd->count - index) * sizeof(*ifd->entries)); + + return 1 + (ifd->count - index); +} + +int av_exif_remove_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags) +{ + return exif_remove_entry(logctx, ifd, id, (flags & AV_EXIF_FLAG_RECURSIVE) ? 0 : INT_MAX); +} + +AVExifMetadata *av_exif_clone_ifd(const AVExifMetadata *ifd) +{ + AVExifMetadata *ret = av_mallocz(sizeof(*ret)); + if (!ret) + return NULL; + + ret->count = ifd->count; + if (ret->count) { + size_t required_size; + if (av_size_mult(ret->count, sizeof(*ret->entries), &required_size) < 0) + goto fail; + av_fast_mallocz(&ret->entries, &ret->size, required_size); + if (!ret->entries) + goto fail; + } + + for (size_t i = 0; i < ret->count; i++) { + const AVExifEntry *entry = &ifd->entries[i]; + AVExifEntry *ret_entry = &ret->entries[i]; + int status = exif_clone_entry(ret_entry, entry); + if (status < 0) + goto fail; + } + + return ret; + +fail: + av_exif_free(ret); + av_free(ret); + return NULL; +} + +static const int rotation_lut[2][4] = { + {1, 8, 3, 6}, {4, 7, 2, 5}, +}; + +int av_exif_matrix_to_orientation(const int32_t *matrix) +{ + double rotation = av_display_rotation_get(matrix); + // determinant + int vflip = ((int64_t)matrix[0] * (int64_t)matrix[4] + - (int64_t)matrix[1] * (int64_t)matrix[3]) < 0; + if (!isfinite(rotation)) + return 0; + int rot = (int)(rotation + 0.5); + rot = (((rot % 360) + 360) % 360) / 90; + return rotation_lut[vflip][rot]; +} + +int av_exif_orientation_to_matrix(int32_t *matrix, int orientation) +{ + switch (orientation) { + case 1: + av_display_rotation_set(matrix, 0.0); + break; + case 2: + av_display_rotation_set(matrix, 0.0); + av_display_matrix_flip(matrix, 1, 0); + break; + case 3: + av_display_rotation_set(matrix, 180.0); + break; + case 4: + av_display_rotation_set(matrix, 180.0); + av_display_matrix_flip(matrix, 1, 0); + break; + case 5: + av_display_rotation_set(matrix, 90.0); + av_display_matrix_flip(matrix, 1, 0); + break; + case 6: + av_display_rotation_set(matrix, 90.0); + break; + case 7: + av_display_rotation_set(matrix, -90.0); + av_display_matrix_flip(matrix, 1, 0); + break; + case 8: + av_display_rotation_set(matrix, -90.0); + break; + default: + return AVERROR(EINVAL); + } + + return 0; +} + +int ff_exif_sanitize_ifd(void *logctx, const AVFrame *frame, AVExifMetadata *ifd) +{ + int ret = 0; + AVFrameSideData *sd_orient = NULL; + AVExifEntry *or = NULL; + AVExifEntry *iw = NULL; + AVExifEntry *ih = NULL; + AVExifEntry *pw = NULL; + AVExifEntry *ph = NULL; + uint64_t orientation = 1; + uint64_t w = frame->width; + uint64_t h = frame->height; + int rewrite = 0; + + sd_orient = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX); + + if (sd_orient) + orientation = av_exif_matrix_to_orientation((int32_t *) sd_orient->data); + if (orientation != 1) + av_log(logctx, AV_LOG_DEBUG, "matrix contains nontrivial EXIF orientation: %" PRIu64 "\n", orientation); + + for (size_t i = 0; i < ifd->count; i++) { + AVExifEntry *entry = &ifd->entries[i]; + if (entry->id == ORIENTATION_TAG && entry->count > 0 && entry->type == AV_TIFF_SHORT) { + or = entry; + continue; + } + if (entry->id == IMAGE_WIDTH_TAG && entry->count > 0 && entry->type == AV_TIFF_LONG) { + iw = entry; + continue; + } + if (entry->id == IMAGE_LENGTH_TAG && entry->count > 0 && entry->type == AV_TIFF_LONG) { + ih = entry; + continue; + } + if (entry->id == EXIFIFD_TAG && entry->type == AV_TIFF_IFD) { + AVExifMetadata *exif = &entry->value.ifd; + for (size_t j = 0; j < exif->count; j++) { + AVExifEntry *exifentry = &exif->entries[j]; + if (exifentry->id == PIXEL_X_TAG && exifentry->count > 0 && exifentry->type == AV_TIFF_SHORT) { + pw = exifentry; + continue; + } + if (exifentry->id == PIXEL_Y_TAG && exifentry->count > 0 && exifentry->type == AV_TIFF_SHORT) { + ph = exifentry; + continue; + } + } + } + } + + if (or && or->value.uint[0] != orientation) { + rewrite = 1; + or->value.uint[0] = orientation; + } + if (iw && iw->value.uint[0] != w) { + rewrite = 1; + iw->value.uint[0] = w; + } + if (ih && ih->value.uint[0] != h) { + rewrite = 1; + ih->value.uint[0] = h; + } + if (pw && pw->value.uint[0] != w) { + rewrite = 1; + pw->value.uint[0] = w; + } + if (ph && ph->value.uint[0] != h) { + rewrite = 1; + ph->value.uint[0] = h; + } + if (!or && orientation != 1) { + rewrite = 1; + ret = av_exif_set_entry(logctx, ifd, ORIENTATION_TAG, AV_TIFF_SHORT, 1, NULL, 0, &orientation); + if (ret < 0) + goto end; + } + if (!iw && w) { + rewrite = 1; + ret = av_exif_set_entry(logctx, ifd, IMAGE_WIDTH_TAG, AV_TIFF_LONG, 1, NULL, 0, &w); + if (ret < 0) + goto end; + } + if (!ih && h) { + rewrite = 1; + ret = av_exif_set_entry(logctx, ifd, IMAGE_LENGTH_TAG, AV_TIFF_LONG, 1, NULL, 0, &h); + if (ret < 0) + goto end; + } + if (!pw && w && w < 0xFFFFu || !ph && h && h < 0xFFFFu) { + AVExifMetadata *exif; + AVExifEntry *exif_entry; + int exif_found = av_exif_get_entry(logctx, ifd, EXIFIFD_TAG, 0, &exif_entry); + rewrite = 1; + if (exif_found < 0) + goto end; + if (exif_found > 0) { + exif = &exif_entry->value.ifd; + } else { + AVExifMetadata exif_new = { 0 }; + ret = av_exif_set_entry(logctx, ifd, EXIFIFD_TAG, AV_TIFF_IFD, 1, NULL, 0, &exif_new); + if (ret < 0) { + av_exif_free(&exif_new); + goto end; + } + exif = &ifd->entries[ifd->count - 1].value.ifd; + } + if (!pw && w && w < 0xFFFFu) { + ret = av_exif_set_entry(logctx, exif, PIXEL_X_TAG, AV_TIFF_SHORT, 1, NULL, 0, &w); + if (ret < 0) + goto end; + } + if (!ph && h && h < 0xFFFFu) { + ret = av_exif_set_entry(logctx, exif, PIXEL_Y_TAG, AV_TIFF_SHORT, 1, NULL, 0, &h); + if (ret < 0) + goto end; + } + } + + return rewrite; + +end: + return ret; +} + +int ff_exif_get_buffer(void *logctx, const AVFrame *frame, AVBufferRef **buffer_ptr, enum AVExifHeaderMode header_mode) +{ + AVFrameSideData *sd_exif = NULL; + AVBufferRef *buffer = NULL; + AVExifMetadata ifd = { 0 }; + int ret = 0; + int rewrite = 0; + + if (!buffer_ptr || *buffer_ptr) + return AVERROR(EINVAL); + + sd_exif = av_frame_get_side_data(frame, AV_FRAME_DATA_EXIF); + if (!sd_exif) + return 0; + + ret = av_exif_parse_buffer(logctx, sd_exif->data, sd_exif->size, &ifd, AV_EXIF_TIFF_HEADER); + if (ret < 0) + goto end; + + rewrite = ff_exif_sanitize_ifd(logctx, frame, &ifd); + if (rewrite < 0) { + ret = rewrite; + goto end; + } + + if (rewrite) { + ret = av_exif_write(logctx, &ifd, &buffer, header_mode); + if (ret < 0) + goto end; + + *buffer_ptr = buffer; + } else { + *buffer_ptr = av_buffer_ref(sd_exif->buf); + if (!*buffer_ptr) { + ret = AVERROR(ENOMEM); + goto end; + } + } + + av_exif_free(&ifd); + return rewrite; + +end: + av_exif_free(&ifd); + return ret; } diff --git a/libavcodec/exif.h b/libavcodec/exif.h index f70d21391..1824a38d1 100644 --- a/libavcodec/exif.h +++ b/libavcodec/exif.h @@ -1,6 +1,7 @@ /* * EXIF metadata parser * Copyright (c) 2013 Thilo Borgmann + * Copyright (c) 2024-2025 Leo Izen * * This file is part of FFmpeg. * @@ -23,21 +24,206 @@ * @file * EXIF metadata parser * @author Thilo Borgmann + * @author Leo Izen */ #ifndef AVCODEC_EXIF_H #define AVCODEC_EXIF_H +#include #include + +#include "libavutil/buffer.h" #include "libavutil/dict.h" -#include "bytestream.h" +#include "libavutil/rational.h" +#include "version_major.h" -/** Recursively decodes all IFD's and - * adds included TAGS into the metadata dictionary. */ -int avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size, - int le, int depth, AVDictionary **metadata); +/** Data type identifiers for TIFF tags */ +enum AVTiffDataType { + AV_TIFF_BYTE = 1, + AV_TIFF_STRING, + AV_TIFF_SHORT, + AV_TIFF_LONG, + AV_TIFF_RATIONAL, + AV_TIFF_SBYTE, + AV_TIFF_UNDEFINED, + AV_TIFF_SSHORT, + AV_TIFF_SLONG, + AV_TIFF_SRATIONAL, + AV_TIFF_FLOAT, + AV_TIFF_DOUBLE, + AV_TIFF_IFD, +}; -int ff_exif_decode_ifd(void *logctx, GetByteContext *gbytes, int le, - int depth, AVDictionary **metadata); +enum AVExifHeaderMode { + /** + * The TIFF header starts with 0x49492a00, or 0x4d4d002a. + * This one is used internally by FFmpeg. + */ + AV_EXIF_TIFF_HEADER, + /** skip the TIFF header, assume little endian */ + AV_EXIF_ASSUME_LE, + /** skip the TIFF header, assume big endian */ + AV_EXIF_ASSUME_BE, + /** The first four bytes point to the actual start, then it's AV_EXIF_TIFF_HEADER */ + AV_EXIF_T_OFF, + /** The first six bytes contain "Exif\0\0", then it's AV_EXIF_TIFF_HEADER */ + AV_EXIF_EXIF00, +}; + +typedef struct AVExifEntry AVExifEntry; + +typedef struct AVExifMetadata { + /* array of EXIF metadata entries */ + AVExifEntry *entries; + /* number of entries in this array */ + unsigned int count; + /* size of the buffer, used for av_fast_realloc */ + unsigned int size; +} AVExifMetadata; + +struct AVExifEntry { + uint16_t id; + enum AVTiffDataType type; + uint32_t count; + + /* + * These are for IFD-style MakerNote + * entries which occur after a fixed + * offset rather than at the start of + * the entry. The ifd_lead field contains + * the leading bytes which typically + * identify the type of MakerNote. + */ + uint32_t ifd_offset; + uint8_t *ifd_lead; + + /* + * An array of entries of size count + * Unless it's an IFD, in which case + * it's not an array and count = 1 + */ + union { + void *ptr; + int64_t *sint; + uint64_t *uint; + double *dbl; + char *str; + uint8_t *ubytes; + int8_t *sbytes; + AVRational *rat; + AVExifMetadata ifd; + } value; +}; + +/** + * Retrieves the tag name associated with the provided tag ID. + * If the tag ID is unknown, NULL is returned. + * + * For example, av_exif_get_tag_name(0x112) returns "Orientation". + */ +const char *av_exif_get_tag_name(uint16_t id); + +/** + * Retrieves the tag ID associated with the provided tag string name. + * If the tag name is unknown, a negative number is returned. Otherwise + * it always fits inside a uint16_t integer. + * + * For example, av_exif_get_tag_id("Orientation") returns 274 (0x0112). + */ +int32_t av_exif_get_tag_id(const char *name); + +/** + * Add an entry to the provided EXIF metadata struct. If one already exists with the provided + * ID, it will set the existing one to have the other information provided. Otherwise, it + * will allocate a new entry. + * + * This function reallocates ifd->entries using av_realloc and allocates (using av_malloc) + * a new value member of the entry, then copies the contents of value into that buffer. + */ +int av_exif_set_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, enum AVTiffDataType type, + uint32_t count, const uint8_t *ifd_lead, uint32_t ifd_offset, const void *value); + +/** + * Also check subdirectories. + */ +#define AV_EXIF_FLAG_RECURSIVE (1 << 0) + +/** + * Get an entry with the tagged ID from the EXIF metadata struct. A pointer to the entry + * will be written into *value. + * + * If the entry was present and returned successfully, a positive number is returned. + * If the entry was not found, *value is left untouched and zero is returned. + * If an error occurred, a negative number is returned. + */ +int av_exif_get_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags, AVExifEntry **value); + +/** + * Remove an entry from the provided EXIF metadata struct. + * + * If the entry was present and removed successfully, a positive number is returned. + * If the entry was not found, zero is returned. + * If an error occurred, a negative number is returned. + */ +int av_exif_remove_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags); + +/** + * Decodes the EXIF data provided in the buffer and writes it into the + * struct *ifd. If this function succeeds, the IFD is owned by the caller + * and must be cleared after use by calling av_exif_free(); If this function + * fails and returns a negative value, it will call av_exif_free(ifd) before + * returning. + */ +int av_exif_parse_buffer(void *logctx, const uint8_t *data, size_t size, + AVExifMetadata *ifd, enum AVExifHeaderMode header_mode); + +/** + * Allocates a buffer using av_malloc of an appropriate size and writes the + * EXIF data represented by ifd into that buffer. + * + * Upon error, *buffer will be NULL. The buffer becomes owned by the caller upon + * success. The *buffer argument must be NULL before calling. + */ +int av_exif_write(void *logctx, const AVExifMetadata *ifd, AVBufferRef **buffer, enum AVExifHeaderMode header_mode); + +/** + * Frees all resources associated with the given EXIF metadata struct. + * Does not free the pointer passed itself, in case it is stack-allocated. + * The pointer passed to this function must be freed by the caller, + * if it is heap-allocated. Passing NULL is permitted. + */ +void av_exif_free(AVExifMetadata *ifd); + +/** + * Recursively reads all tags from the IFD and stores them in the + * provided metadata dictionary. + */ +int av_exif_ifd_to_dict(void *logctx, const AVExifMetadata *ifd, AVDictionary **metadata); + +/** + * Allocates a duplicate of the provided EXIF metadata struct. The caller owns + * the duplicate and must free it with av_exif_free. Returns NULL if the duplication + * process failed. + */ +AVExifMetadata *av_exif_clone_ifd(const AVExifMetadata *ifd); + +/** + * Convert a display matrix used by AV_FRAME_DATA_DISPLAYMATRIX + * into an orientation constant used by EXIF's orientation tag. + * + * Returns an EXIF orientation between 1 and 8 (inclusive) depending + * on the rotation and flip factors. Returns 0 if the matrix is singular. + */ +int av_exif_matrix_to_orientation(const int32_t *matrix); + +/** + * Convert an orientation constant used by EXIF's orientation tag + * into a display matrix used by AV_FRAME_DATA_DISPLAYMATRIX. + * + * Returns 0 on success and negative if the orientation is invalid, + * i.e. not between 1 and 8 (inclusive). + */ +int av_exif_orientation_to_matrix(int32_t *matrix, int orientation); #endif /* AVCODEC_EXIF_H */ diff --git a/libavcodec/exif_internal.h b/libavcodec/exif_internal.h new file mode 100644 index 000000000..c0d2b3ef6 --- /dev/null +++ b/libavcodec/exif_internal.h @@ -0,0 +1,67 @@ +/* + * EXIF metadata parser - internal functions + * Copyright (c) 2013 Thilo Borgmann + * Copyright (c) 2024-2025 Leo Izen + * + * 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 + * EXIF metadata parser - internal functions + * @author Thilo Borgmann + * @author Leo Izen + */ + +#ifndef AVCODEC_EXIF_INTERNAL_H +#define AVCODEC_EXIF_INTERNAL_H + +#include "libavutil/buffer.h" +#include "libavutil/frame.h" + +#include "exif.h" +#include "version_major.h" + +#if LIBAVCODEC_VERSION_MAJOR < 63 +/* Used by the AVI demuxer */ +int avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size, + int le, int depth, AVDictionary **metadata); +#endif + +/** + * Compares values in the IFD with data in the provided AVFrame and sets the values + * in that IFD to match the ones in that AVFrame. This is mostly useful for an + * encoder that wishes to use ff_exif_get_buffer, but would prefer to modify the + * IFD after it is sanitized and call av_exif_write afterward. + */ +int ff_exif_sanitize_ifd(void *logctx, const AVFrame *frame, AVExifMetadata *ifd); + +/** + * Gets all relevant side data, collects it into an IFD, and writes it into the + * corresponding buffer pointer. This includes both AV_FRAME_DATA_EXIF and other + * side data types that are included in the frame data, such as possibly an + * instance of AV_FRAME_DATA_DISPLAYMATRIX. It also sets width and height tags + * to match those of the AVFrame if they are different. + * + * Upon error, *buffer will be NULL. The buffer becomes owned by the caller upon + * success. The *buffer argument must be NULL before calling. If *buffer is NULL + * upon return then a negative return value indicates an error, and a zero return + * value indicates that there was no EXIF data to write. + */ +int ff_exif_get_buffer(void *logctx, const AVFrame *frame, AVBufferRef **buffer, enum AVExifHeaderMode header_mode); + +#endif /* AVCODEC_EXIF_INTERNAL_H */ diff --git a/libavcodec/exr.c b/libavcodec/exr.c index 2b47ab50a..c7fcd302c 100644 --- a/libavcodec/exr.c +++ b/libavcodec/exr.c @@ -42,6 +42,7 @@ #include "libavutil/avstring.h" #include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavutil/float2half.h" #include "libavutil/half2float.h" #include "avcodec.h" @@ -191,12 +192,16 @@ typedef struct EXRContext { const char *layer; int selected_part; - enum AVColorTransferCharacteristic apply_trc_type; - float gamma; - union av_intfloat32 gamma_table[65536]; uint8_t *offset_table; +#if FF_API_EXR_GAMMA + enum AVColorTransferCharacteristic apply_trc_type; + float gamma; + uint16_t gamma_table[65536]; +#endif + + Float2HalfTables f2h_tables; Half2FloatTables h2f_tables; } EXRContext; @@ -1138,6 +1143,10 @@ static int dwa_uncompress(const EXRContext *s, const uint8_t *src, int compresse for (int y = 0; y < td->ysize; y += 8) { for (int x = 0; x < td->xsize; x += 8) { + const int o = s->nb_channels == 4; + float *yb = td->block[0]; + float *ub = td->block[1]; + float *vb = td->block[2]; int bw = FFMIN(8, td->xsize - x); int bh = FFMIN(8, td->ysize - y); @@ -1156,17 +1165,37 @@ static int dwa_uncompress(const EXRContext *s, const uint8_t *src, int compresse dct_inverse(block); } - { - const int o = s->nb_channels == 4; + if (s->pixel_type == EXR_HALF) { + uint16_t *bo = ((uint16_t *)td->uncompressed_data) + + y * td->xsize * s->nb_channels + td->xsize * (o + 0) + x; + uint16_t *go = ((uint16_t *)td->uncompressed_data) + + y * td->xsize * s->nb_channels + td->xsize * (o + 1) + x; + uint16_t *ro = ((uint16_t *)td->uncompressed_data) + + y * td->xsize * s->nb_channels + td->xsize * (o + 2) + x; + + for (int yy = 0; yy < bh; yy++) { + for (int xx = 0; xx < bw; xx++) { + const int idx = xx + yy * 8; + float b, g, r; + + convert(yb[idx], ub[idx], vb[idx], &b, &g, &r); + + bo[xx] = float2half(av_float2int(to_linear(b, 1.f)), &s->f2h_tables); + go[xx] = float2half(av_float2int(to_linear(g, 1.f)), &s->f2h_tables); + ro[xx] = float2half(av_float2int(to_linear(r, 1.f)), &s->f2h_tables); + } + + bo += td->xsize * s->nb_channels; + go += td->xsize * s->nb_channels; + ro += td->xsize * s->nb_channels; + } + } else { float *bo = ((float *)td->uncompressed_data) + y * td->xsize * s->nb_channels + td->xsize * (o + 0) + x; float *go = ((float *)td->uncompressed_data) + y * td->xsize * s->nb_channels + td->xsize * (o + 1) + x; float *ro = ((float *)td->uncompressed_data) + y * td->xsize * s->nb_channels + td->xsize * (o + 2) + x; - float *yb = td->block[0]; - float *ub = td->block[1]; - float *vb = td->block[2]; for (int yy = 0; yy < bh; yy++) { for (int xx = 0; xx < bw; xx++) { @@ -1190,15 +1219,26 @@ static int dwa_uncompress(const EXRContext *s, const uint8_t *src, int compresse if (s->nb_channels < 4) return 0; - for (int y = 0; y < td->ysize && have_rle; y++) { - uint32_t *ao = ((uint32_t *)td->uncompressed_data) + y * td->xsize * s->nb_channels; - uint8_t *ai0 = td->rle_raw_data + y * td->xsize; - uint8_t *ai1 = td->rle_raw_data + y * td->xsize + rle_raw_size / 2; + if (s->pixel_type == EXR_HALF) { + for (int y = 0; y < td->ysize && have_rle; y++) { + uint16_t *ao = ((uint16_t *)td->uncompressed_data) + y * td->xsize * s->nb_channels; + uint8_t *ai0 = td->rle_raw_data + y * td->xsize; + uint8_t *ai1 = td->rle_raw_data + y * td->xsize + rle_raw_size / 2; - for (int x = 0; x < td->xsize; x++) { - uint16_t ha = ai0[x] | (ai1[x] << 8); + for (int x = 0; x < td->xsize; x++) + ao[x] = ai0[x] | (ai1[x] << 8); + } + } else { + for (int y = 0; y < td->ysize && have_rle; y++) { + uint32_t *ao = ((uint32_t *)td->uncompressed_data) + y * td->xsize * s->nb_channels; + uint8_t *ai0 = td->rle_raw_data + y * td->xsize; + uint8_t *ai1 = td->rle_raw_data + y * td->xsize + rle_raw_size / 2; - ao[x] = half2float(ha, &s->h2f_tables); + for (int x = 0; x < td->xsize; x++) { + uint16_t ha = ai0[x] | (ai1[x] << 8); + + ao[x] = half2float(ha, &s->h2f_tables); + } } } @@ -1219,14 +1259,16 @@ static int decode_block(AVCodecContext *avctx, void *tdata, int line, col = 0; uint64_t tile_x, tile_y, tile_level_x, tile_level_y; const uint8_t *src; - int step = s->desc->flags & AV_PIX_FMT_FLAG_FLOAT ? 4 : 2 * s->desc->nb_components; + int step = s->desc->comp[0].step; int bxmin = 0, axmax = 0, window_xoffset = 0; int window_xmin, window_xmax, window_ymin, window_ymax; int data_xoffset, data_yoffset, data_window_offset, xsize, ysize; int i, x, buf_size = s->buf_size; int c, rgb_channel_count; +#if FF_API_EXR_GAMMA float one_gamma = 1.0f / s->gamma; av_csp_trc_function trc_func = av_csp_trc_func_from_id(s->apply_trc_type); +#endif int ret; line_offset = AV_RL64(s->gb.buffer + jobnr * 8); @@ -1387,77 +1429,62 @@ static int decode_block(AVCodecContext *avctx, void *tdata, data_yoffset = FFABS(FFMIN(0, line)); data_window_offset = (data_yoffset * td->channel_line_size) + data_xoffset; + if (s->channel_offsets[3] >= 0) + channel_buffer[3] = src + (td->xsize * s->channel_offsets[3]) + data_window_offset; if (!s->is_luma) { channel_buffer[0] = src + (td->xsize * s->channel_offsets[0]) + data_window_offset; channel_buffer[1] = src + (td->xsize * s->channel_offsets[1]) + data_window_offset; channel_buffer[2] = src + (td->xsize * s->channel_offsets[2]) + data_window_offset; rgb_channel_count = 3; - } else { /* put y data in the first channel_buffer */ + } else { /* put y data in the first channel_buffer and if needed, alpha in the second */ channel_buffer[0] = src + (td->xsize * s->channel_offsets[1]) + data_window_offset; + if (!(s->desc->flags & AV_PIX_FMT_FLAG_PLANAR)) + channel_buffer[1] = channel_buffer[3]; rgb_channel_count = 1; } - if (s->channel_offsets[3] >= 0) - channel_buffer[3] = src + (td->xsize * s->channel_offsets[3]) + data_window_offset; if (s->desc->flags & AV_PIX_FMT_FLAG_FLOAT) { - /* todo: change this when a floating point pixel format with luma with alpha is implemented */ - int channel_count = s->channel_offsets[3] >= 0 ? 4 : rgb_channel_count; - if (s->is_luma) { - channel_buffer[1] = channel_buffer[0]; - channel_buffer[2] = channel_buffer[0]; - } - - for (c = 0; c < channel_count; c++) { + for (c = 0; c < s->desc->nb_components; c++) { int plane = s->desc->comp[c].plane; - ptr = p->data[plane] + window_ymin * p->linesize[plane] + (window_xmin * 4); + ptr = p->data[plane] + window_ymin * p->linesize[plane] + (window_xmin * step) + s->desc->comp[c].offset; for (i = 0; i < ysize; i++, ptr += p->linesize[plane]) { - const uint8_t *src; - union av_intfloat32 *ptr_x; - - src = channel_buffer[c]; - ptr_x = (union av_intfloat32 *)ptr; + const uint8_t *src = channel_buffer[c]; + uint8_t *ptr_x = ptr + window_xoffset * step; // Zero out the start if xmin is not 0 - memset(ptr_x, 0, bxmin); - ptr_x += window_xoffset; + if (s->desc->flags & AV_PIX_FMT_FLAG_PLANAR || !c) + memset(ptr, 0, bxmin); - if (s->pixel_type == EXR_FLOAT || - s->compression == EXR_DWAA || - s->compression == EXR_DWAB) { + if (s->pixel_type == EXR_FLOAT) { // 32-bit - union av_intfloat32 t; - if (trc_func && c < 3) { - for (x = 0; x < xsize; x++) { - t.i = bytestream_get_le32(&src); - t.f = trc_func(t.f); - *ptr_x++ = t; +#if FF_API_EXR_GAMMA + if (trc_func && (!c || (c < 3 && s->desc->flags & AV_PIX_FMT_FLAG_PLANAR))) { + for (int x = 0; x < xsize; x++, ptr_x += step) { + float f = av_int2float(bytestream_get_le32(&src)); + AV_WN32A(ptr_x, av_float2int(trc_func(f))); } } else if (one_gamma != 1.f) { - for (x = 0; x < xsize; x++) { - t.i = bytestream_get_le32(&src); - if (t.f > 0.0f && c < 3) /* avoid negative values */ - t.f = powf(t.f, one_gamma); - *ptr_x++ = t; + for (int x = 0; x < xsize; x++, ptr_x += step) { + float f = av_int2float(bytestream_get_le32(&src)); + if (f > 0.0f && c < 3) /* avoid negative values */ + f = powf(f, one_gamma); + AV_WN32A(ptr_x, av_float2int(f)); } - } else { - for (x = 0; x < xsize; x++) { - t.i = bytestream_get_le32(&src); - *ptr_x++ = t; - } - } + } else +#endif + for (int x = 0; x < xsize; x++, ptr_x += step) + AV_WN32A(ptr_x, bytestream_get_le32(&src)); } else if (s->pixel_type == EXR_HALF) { // 16-bit - if (c < 3 || !trc_func) { - for (x = 0; x < xsize; x++) { - *ptr_x++ = s->gamma_table[bytestream_get_le16(&src)]; - } - } else { - for (x = 0; x < xsize; x++) { - ptr_x[0].i = half2float(bytestream_get_le16(&src), &s->h2f_tables); - ptr_x++; - } - } +#if FF_API_EXR_GAMMA + if (one_gamma != 1.f || (trc_func && (!c || (c < 3 && s->desc->flags & AV_PIX_FMT_FLAG_PLANAR)))) { + for (int x = 0; x < xsize; x++, ptr_x += step) + AV_WN16A(ptr_x, s->gamma_table[bytestream_get_le16(&src)]); + } else +#endif + for (int x = 0; x < xsize; x++, ptr_x += step) + AV_WN16A(ptr_x, bytestream_get_le16(&src)); } // Zero out the end if xmax+1 is not w @@ -2103,12 +2130,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, if ((ret = decode_header(s, picture)) < 0) return ret; - if ((s->compression == EXR_DWAA || s->compression == EXR_DWAB) && - s->pixel_type == EXR_HALF) { - s->current_channel_offset *= 2; - for (int i = 0; i < 4; i++) - s->channel_offsets[i] *= 2; - } if (s->compression == EXR_DWAA || s->compression == EXR_DWAB) { for (int i = 0; inb_channels; i++) { @@ -2121,14 +2142,27 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, } switch (s->pixel_type) { - case EXR_FLOAT: case EXR_HALF: + if (s->channel_offsets[3] >= 0) { + if (!s->is_luma) { + avctx->pix_fmt = AV_PIX_FMT_GBRAPF16; + } else { + avctx->pix_fmt = AV_PIX_FMT_YAF16; + } + } else { + if (!s->is_luma) { + avctx->pix_fmt = AV_PIX_FMT_GBRPF16; + } else { + avctx->pix_fmt = AV_PIX_FMT_GRAYF16; + } + } + break; + case EXR_FLOAT: if (s->channel_offsets[3] >= 0) { if (!s->is_luma) { avctx->pix_fmt = AV_PIX_FMT_GBRAPF32; } else { - /* todo: change this when a floating point pixel format with luma with alpha is implemented */ - avctx->pix_fmt = AV_PIX_FMT_GBRAPF32; + avctx->pix_fmt = AV_PIX_FMT_YAF32; } } else { if (!s->is_luma) { @@ -2158,9 +2192,14 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, return AVERROR_INVALIDDATA; } + if (s->channel_offsets[3] >= 0) + avctx->alpha_mode = AVALPHA_MODE_PREMULTIPLIED; + +#if FF_API_EXR_GAMMA if (s->apply_trc_type != AVCOL_TRC_UNSPECIFIED) avctx->color_trc = s->apply_trc_type; else if (s->gamma > 0.9999f && s->gamma < 1.0001f) +#endif avctx->color_trc = AVCOL_TRC_LINEAR; switch (s->compression) { @@ -2207,13 +2246,8 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, if (!s->desc) return AVERROR_INVALIDDATA; - if (s->desc->flags & AV_PIX_FMT_FLAG_FLOAT) { - planes = s->desc->nb_components; - out_line_size = avctx->width * 4; - } else { - planes = 1; - out_line_size = avctx->width * 2 * s->desc->nb_components; - } + planes = av_pix_fmt_count_planes(avctx->pix_fmt); + out_line_size = avctx->width * s->desc->comp[0].step; if (s->is_tile) { if (s->tile_attr.ySize <= 0 || s->tile_attr.xSize <= 0) @@ -2293,11 +2327,14 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, static av_cold int decode_init(AVCodecContext *avctx) { EXRContext *s = avctx->priv_data; +#if FF_API_EXR_GAMMA uint32_t i; union av_intfloat32 t; float one_gamma = 1.0f / s->gamma; av_csp_trc_function trc_func = NULL; +#endif + ff_init_float2half_tables(&s->f2h_tables); ff_init_half2float_tables(&s->h2f_tables); s->avctx = avctx; @@ -2308,31 +2345,27 @@ static av_cold int decode_init(AVCodecContext *avctx) ff_bswapdsp_init(&s->bbdsp); #endif +#if FF_API_EXR_GAMMA trc_func = av_csp_trc_func_from_id(s->apply_trc_type); if (trc_func) { for (i = 0; i < 65536; ++i) { t.i = half2float(i, &s->h2f_tables); t.f = trc_func(t.f); - s->gamma_table[i] = t; + s->gamma_table[i] = float2half(av_float2int(t.f), &s->f2h_tables); } - } else { - if (one_gamma > 0.9999f && one_gamma < 1.0001f) { - for (i = 0; i < 65536; ++i) { - s->gamma_table[i].i = half2float(i, &s->h2f_tables); - } - } else { - for (i = 0; i < 65536; ++i) { - t.i = half2float(i, &s->h2f_tables); - /* If negative value we reuse half value */ - if (t.f <= 0.0f) { - s->gamma_table[i] = t; - } else { - t.f = powf(t.f, one_gamma); - s->gamma_table[i] = t; - } + } else if (one_gamma != 1.0f) { + for (i = 0; i < 65536; ++i) { + t.i = half2float(i, &s->h2f_tables); + /* If negative value we reuse half value */ + if (t.f <= 0.0f) { + s->gamma_table[i] = i; + } else { + t.f = powf(t.f, one_gamma); + s->gamma_table[i] = float2half(t.i, &s->f2h_tables); } } } +#endif // allocate thread data, used for non EXR_RAW compression types s->thread_data = av_calloc(avctx->thread_count, sizeof(*s->thread_data)); @@ -2375,12 +2408,13 @@ static const AVOption options[] = { AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD }, { "part", "Set the decoding part", OFFSET(selected_part), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VD }, - { "gamma", "Set the float gamma value when decoding", OFFSET(gamma), - AV_OPT_TYPE_FLOAT, { .dbl = 1.0f }, 0.001, FLT_MAX, VD }, +#if FF_API_EXR_GAMMA + { "gamma", "Set the float gamma value when decoding (deprecated, use a scaler)", OFFSET(gamma), + AV_OPT_TYPE_FLOAT, { .dbl = 1.0f }, 0.001, FLT_MAX, VD | AV_OPT_FLAG_DEPRECATED }, // XXX: Note the abuse of the enum using AVCOL_TRC_UNSPECIFIED to subsume the existing gamma option - { "apply_trc", "color transfer characteristics to apply to EXR linear input", OFFSET(apply_trc_type), - AV_OPT_TYPE_INT, {.i64 = AVCOL_TRC_UNSPECIFIED }, 1, AVCOL_TRC_NB-1, VD, .unit = "apply_trc_type"}, + { "apply_trc", "color transfer characteristics to apply to EXR linear input (deprecated, use a scaler)", OFFSET(apply_trc_type), + AV_OPT_TYPE_INT, {.i64 = AVCOL_TRC_UNSPECIFIED }, 1, AVCOL_TRC_NB-1, VD | AV_OPT_FLAG_DEPRECATED, .unit = "apply_trc_type"}, { "bt709", "BT.709", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT709 }, INT_MIN, INT_MAX, VD, .unit = "apply_trc_type"}, { "gamma", "gamma", 0, @@ -2413,6 +2447,7 @@ static const AVOption options[] = { AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_SMPTEST2084 }, INT_MIN, INT_MAX, VD, .unit = "apply_trc_type"}, { "smpte428_1", "SMPTE ST 428-1", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_SMPTEST428_1 }, INT_MIN, INT_MAX, VD, .unit = "apply_trc_type"}, +#endif { NULL }, }; diff --git a/libavcodec/exrdsp.c b/libavcodec/exrdsp.c index 248cb93c5..70914b7e5 100644 --- a/libavcodec/exrdsp.c +++ b/libavcodec/exrdsp.c @@ -63,7 +63,7 @@ av_cold void ff_exrdsp_init(ExrDSPContext *c) #if ARCH_RISCV ff_exrdsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_exrdsp_init_x86(c); #endif } diff --git a/libavcodec/exrenc.c b/libavcodec/exrenc.c index 71ec07054..68eb683aa 100644 --- a/libavcodec/exrenc.c +++ b/libavcodec/exrenc.c @@ -27,6 +27,7 @@ #include #include "libavutil/avassert.h" +#include "libavutil/intfloat.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/imgutils.h" @@ -551,9 +552,6 @@ const FFCodec ff_exr_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_GRAYF32, - AV_PIX_FMT_GBRPF32, - AV_PIX_FMT_GBRAPF32, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_GRAYF32, AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32), + .alpha_modes = AVALPHA_MODE_PREMULTIPLIED, }; diff --git a/libavcodec/fastaudio.c b/libavcodec/fastaudio.c index 33ad26f8a..d361b410b 100644 --- a/libavcodec/fastaudio.c +++ b/libavcodec/fastaudio.c @@ -21,6 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/intfloat.h" #include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" @@ -195,6 +196,4 @@ const FFCodec ff_fastaudio_decoder = { FF_CODEC_DECODE_CB(fastaudio_decode), .close = fastaudio_close, .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/fflcms2.c b/libavcodec/fflcms2.c index 3b67e62d3..3c7f3dc07 100644 --- a/libavcodec/fflcms2.c +++ b/libavcodec/fflcms2.c @@ -50,10 +50,7 @@ void ff_icc_context_uninit(FFIccContext *s) static int get_curve(FFIccContext *s, enum AVColorTransferCharacteristic trc, cmsToneCurve **out_curve) { - if (trc >= AVCOL_TRC_NB) - return AVERROR_INVALIDDATA; - - if (s->curves[trc]) + if ((unsigned)trc < AVCOL_TRC_NB && s->curves[trc]) goto done; switch (trc) { @@ -128,6 +125,7 @@ static int get_curve(FFIccContext *s, enum AVColorTransferCharacteristic trc, case AVCOL_TRC_BT1361_ECG: case AVCOL_TRC_SMPTE2084: case AVCOL_TRC_ARIB_STD_B67: + case AVCOL_TRC_V_LOG: return AVERROR_PATCHWELCOME; default: diff --git a/libavcodec/ffv1.c b/libavcodec/ffv1.c index cb3e76740..812989a89 100644 --- a/libavcodec/ffv1.c +++ b/libavcodec/ffv1.c @@ -31,12 +31,10 @@ #include "avcodec.h" #include "ffv1.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" -av_cold int ff_ffv1_common_init(AVCodecContext *avctx) +av_cold int ff_ffv1_common_init(AVCodecContext *avctx, FFV1Context *s) { - FFV1Context *s = avctx->priv_data; - if (!avctx->width || !avctx->height) return AVERROR_INVALIDDATA; @@ -53,7 +51,7 @@ av_cold int ff_ffv1_common_init(AVCodecContext *avctx) return 0; } -static void planes_free(FFRefStructOpaque opaque, void *obj) +static void planes_free(AVRefStructOpaque opaque, void *obj) { PlaneContext *planes = obj; @@ -67,7 +65,7 @@ static void planes_free(FFRefStructOpaque opaque, void *obj) PlaneContext* ff_ffv1_planes_alloc(void) { - return ff_refstruct_alloc_ext(sizeof(PlaneContext) * MAX_PLANES, + return av_refstruct_alloc_ext(sizeof(PlaneContext) * MAX_PLANES, 0, NULL, planes_free); } @@ -126,6 +124,19 @@ int ff_need_new_slices(int width, int num_h_slices, int chroma_shift) { return width % mpw && (width - i) % mpw == 0; } +int ff_slice_coord(const FFV1Context *f, int width, int sx, int num_h_slices, int chroma_shift) { + int mpw = 1<combined_version <= 0x40002) + return width * sx / num_h_slices; + + sx = (2LL * awidth * sx + num_h_slices * mpw) / (2 * num_h_slices * mpw) * mpw; + if (sx == awidth) + sx = width; + return sx; +} + av_cold int ff_ffv1_init_slice_contexts(FFV1Context *f) { int max_slice_count = f->num_h_slices * f->num_v_slices; @@ -142,10 +153,10 @@ av_cold int ff_ffv1_init_slice_contexts(FFV1Context *f) FFV1SliceContext *sc = &f->slices[i]; int sx = i % f->num_h_slices; int sy = i / f->num_h_slices; - int sxs = f->avctx->width * sx / f->num_h_slices; - int sxe = f->avctx->width * (sx + 1) / f->num_h_slices; - int sys = f->avctx->height * sy / f->num_v_slices; - int sye = f->avctx->height * (sy + 1) / f->num_v_slices; + int sxs = ff_slice_coord(f, f->avctx->width , sx , f->num_h_slices, f->chroma_h_shift); + int sxe = ff_slice_coord(f, f->avctx->width , sx + 1, f->num_h_slices, f->chroma_h_shift); + int sys = ff_slice_coord(f, f->avctx->height, sy , f->num_v_slices, f->chroma_v_shift); + int sye = ff_slice_coord(f, f->avctx->height, sy + 1, f->num_v_slices, f->chroma_v_shift); sc->slice_width = sxe - sxs; sc->slice_height = sye - sys; @@ -208,10 +219,50 @@ void ff_ffv1_clear_slice_state(const FFV1Context *f, FFV1SliceContext *sc) } } +void ff_ffv1_compute_bits_per_plane(const FFV1Context *f, FFV1SliceContext *sc, int bits[4], int *offset, int mask[4], int bits_per_raw_sample) +{ + // to simplify we use the remap_count as the symbol range in each plane + if (!sc->remap) { + sc->remap_count[0] = + sc->remap_count[1] = + sc->remap_count[2] = + sc->remap_count[3] = 1 << (bits_per_raw_sample > 0 ? bits_per_raw_sample : 8); + } -av_cold int ff_ffv1_close(AVCodecContext *avctx) + if (sc->remap) + av_assert0(bits_per_raw_sample > 8); //breaks with lbd, needs review if added + + //bits with no RCT + for (int p=0; p<3+f->transparency; p++) { + bits[p] = av_ceil_log2(sc->remap_count[p]); + if (mask) + mask[p] = (1<slice_coding_mode == 0) { + *offset = sc->remap_count[0]; + + bits[0] = av_ceil_log2(FFMAX3(sc->remap_count[0], sc->remap_count[1], sc->remap_count[2])); + bits[1] = av_ceil_log2(sc->remap_count[0] + sc->remap_count[1]); + bits[2] = av_ceil_log2(sc->remap_count[0] + sc->remap_count[2]); + + //old version coded a bit more than needed + if (f->combined_version < 0x40008) { + bits[0]++; + if(f->transparency) + bits[3]++; + } + } +} + +int ff_ffv1_get_symbol(RangeCoder *c, uint8_t *state, int is_signed) +{ + return get_symbol_inline(c, state, is_signed); +} + +av_cold void ff_ffv1_close(FFV1Context *s) { - FFV1Context *s = avctx->priv_data; int i, j; for (j = 0; j < s->max_slice_count; j++) { @@ -219,13 +270,18 @@ av_cold int ff_ffv1_close(AVCodecContext *avctx) av_freep(&sc->sample_buffer); av_freep(&sc->sample_buffer32); + for(int p = 0; p < 4 ; p++) { + av_freep(&sc->fltmap[p]); + av_freep(&sc->fltmap32[p]); + sc->fltmap_size [p] = 0; + sc->fltmap32_size[p] = 0; + } - ff_refstruct_unref(&sc->plane); + av_refstruct_unref(&sc->plane); } - ff_refstruct_unref(&s->slice_damaged); + av_refstruct_unref(&s->slice_damaged); - av_freep(&avctx->stats_out); for (j = 0; j < s->quant_table_count; j++) { av_freep(&s->initial_states[j]); for (i = 0; i < s->max_slice_count; i++) { @@ -236,6 +292,4 @@ av_cold int ff_ffv1_close(AVCodecContext *avctx) } av_freep(&s->slices); - - return 0; } diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h index 5c1490771..8a48e8e68 100644 --- a/libavcodec/ffv1.h +++ b/libavcodec/ffv1.h @@ -28,6 +28,7 @@ * FF Video Codec 1 (a lossless codec) */ +#include "libavutil/attributes.h" #include "avcodec.h" #include "get_bits.h" #include "mathops.h" @@ -54,8 +55,8 @@ #define AC_RANGE_DEFAULT_TAB_FORCE -2 typedef struct VlcState { + uint32_t error_sum; int16_t drift; - uint16_t error_sum; int8_t bias; uint8_t count; } VlcState; @@ -83,6 +84,7 @@ typedef struct FFV1SliceContext { int slice_coding_mode; int slice_rct_by_coef; int slice_rct_ry_coef; + int remap; // RefStruct reference, array of MAX_PLANES elements PlaneContext *plane; @@ -104,6 +106,17 @@ typedef struct FFV1SliceContext { uint64_t (*rc_stat2[MAX_QUANT_TABLES])[32][2]; }; }; + int remap_count[4]; + + uint32_t *bitmap [4]; //float encode + uint16_t *fltmap [4]; //halffloat encode & decode + uint32_t *fltmap32[4]; //float decode + unsigned int fltmap_size[4]; + unsigned int fltmap32_size[4]; + struct Unit { + uint32_t val; //this is unneeded if you accept a dereference on each access + uint32_t ndx; + } *unit[4]; } FFV1SliceContext; typedef struct FFV1Context { @@ -113,6 +126,7 @@ typedef struct FFV1Context { uint64_t (*rc_stat2[MAX_QUANT_TABLES])[32][2]; int version; int micro_version; + int combined_version; int width, height; int chroma_planes; int chroma_h_shift, chroma_v_shift; @@ -121,6 +135,12 @@ typedef struct FFV1Context { int64_t picture_number; int key_frame; ProgressFrame picture, last_picture; + void *hwaccel_picture_private, *hwaccel_last_picture_private; + uint32_t crcref; + enum AVPixelFormat pix_fmt; + enum AVPixelFormat configured_pix_fmt; + int configured_width, configured_height; + int configured_ac; const AVFrame *cur_enc_frame; int plane_count; @@ -130,6 +150,10 @@ typedef struct FFV1Context { uint8_t state_transition[256]; uint8_t (*initial_states[MAX_QUANT_TABLES])[32]; int colorspace; + int flt; + int remap_mode; + int remap_optimizer; + int maxsize_warned; int use32bit; @@ -137,6 +161,7 @@ typedef struct FFV1Context { int intra; int key_frame_ok; int context_model; + int qtable; int bits_per_raw_sample; int packed_at_lsb; @@ -165,15 +190,26 @@ typedef struct FFV1Context { uint8_t frame_damaged; } FFV1Context; -int ff_ffv1_common_init(AVCodecContext *avctx); +int ff_ffv1_common_init(AVCodecContext *avctx, FFV1Context *s); int ff_ffv1_init_slice_state(const FFV1Context *f, FFV1SliceContext *sc); int ff_ffv1_init_slices_state(FFV1Context *f); int ff_ffv1_init_slice_contexts(FFV1Context *f); PlaneContext *ff_ffv1_planes_alloc(void); int ff_ffv1_allocate_initial_states(FFV1Context *f); void ff_ffv1_clear_slice_state(const FFV1Context *f, FFV1SliceContext *sc); -int ff_ffv1_close(AVCodecContext *avctx); +void ff_ffv1_close(FFV1Context *s); int ff_need_new_slices(int width, int num_h_slices, int chroma_shift); +int ff_ffv1_parse_header(FFV1Context *f, RangeCoder *c, uint8_t *state); +int ff_ffv1_read_extra_header(FFV1Context *f); +int ff_ffv1_read_quant_tables(RangeCoder *c, + int16_t quant_table[MAX_CONTEXT_INPUTS][256]); +void ff_ffv1_compute_bits_per_plane(const FFV1Context *f, FFV1SliceContext *sc, int bits[4], int *offset, int mask[4], int bits_per_raw_sample); +int ff_ffv1_get_symbol(RangeCoder *c, uint8_t *state, int is_signed); + +/** + * This is intended for both width and height + */ +int ff_slice_coord(const FFV1Context *f, int width, int sx, int num_h_slices, int chroma_shift); static av_always_inline int fold(int diff, int bits) { @@ -214,4 +250,29 @@ static inline void update_vlc_state(VlcState *const state, const int v) state->count = count; } + +static inline av_flatten int get_symbol_inline(RangeCoder *c, uint8_t *state, + int is_signed) +{ + if (get_rac(c, state + 0)) + return 0; + else { + int e; + unsigned a; + e = 0; + while (get_rac(c, state + 1 + FFMIN(e, 9))) { // 1..10 + e++; + if (e > 31) + return AVERROR_INVALIDDATA; + } + + a = 1; + for (int i = e - 1; i >= 0; i--) + a += a + get_rac(c, state + 22 + FFMIN(i, 9)); // 22..31 + + e = -(is_signed && get_rac(c, state + 11 + FFMIN(e, 10))); // 11..21 + return (a ^ e) - e; + } +} + #endif /* AVCODEC_FFV1_H */ diff --git a/libavcodec/ffv1_parse.c b/libavcodec/ffv1_parse.c new file mode 100644 index 000000000..10f3652ff --- /dev/null +++ b/libavcodec/ffv1_parse.c @@ -0,0 +1,443 @@ +/* + * 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/crc.h" +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" +#include "rangecoder.h" +#include "ffv1.h" + +static int read_quant_table(RangeCoder *c, int16_t *quant_table, int scale) +{ + int v; + int i = 0; + uint8_t state[CONTEXT_SIZE]; + + memset(state, 128, sizeof(state)); + + for (v = 0; i < 128; v++) { + unsigned len = ff_ffv1_get_symbol(c, state, 0) + 1U; + + if (len > 128 - i || !len) + return AVERROR_INVALIDDATA; + + while (len--) { + quant_table[i] = scale * v; + i++; + } + } + + for (i = 1; i < 128; i++) + quant_table[256 - i] = -quant_table[i]; + quant_table[128] = -quant_table[127]; + + return 2 * v - 1; +} + +int ff_ffv1_read_quant_tables(RangeCoder *c, + int16_t quant_table[MAX_CONTEXT_INPUTS][256]) +{ + int i; + int context_count = 1; + + for (i = 0; i < 5; i++) { + int ret = read_quant_table(c, quant_table[i], context_count); + if (ret < 0) + return ret; + context_count *= ret; + if (context_count > 32768U) { + return AVERROR_INVALIDDATA; + } + } + return (context_count + 1) / 2; +} + +int ff_ffv1_read_extra_header(FFV1Context *f) +{ + RangeCoder c; + uint8_t state[CONTEXT_SIZE]; + int ret; + uint8_t state2[32][CONTEXT_SIZE]; + unsigned crc = 0; + + memset(state2, 128, sizeof(state2)); + memset(state, 128, sizeof(state)); + + ff_init_range_decoder(&c, f->avctx->extradata, f->avctx->extradata_size); + ff_build_rac_states(&c, 0.05 * (1LL << 32), 256 - 8); + + f->version = ff_ffv1_get_symbol(&c, state, 0); + if (f->version < 2) { + av_log(f->avctx, AV_LOG_ERROR, "Invalid version in global header\n"); + return AVERROR_INVALIDDATA; + } + if (f->version > 4) { + av_log(f->avctx, AV_LOG_ERROR, "unsupported version %d\n", + f->version); + return AVERROR_PATCHWELCOME; + } + f->combined_version = f->version << 16; + if (f->version > 2) { + c.bytestream_end -= 4; + f->micro_version = ff_ffv1_get_symbol(&c, state, 0); + if (f->micro_version < 0 || f->micro_version > 65535) + return AVERROR_INVALIDDATA; + f->combined_version += f->micro_version; + } + f->ac = ff_ffv1_get_symbol(&c, state, 0); + + if (f->ac == AC_RANGE_CUSTOM_TAB) { + for (int i = 1; i < 256; i++) + f->state_transition[i] = ff_ffv1_get_symbol(&c, state, 1) + c.one_state[i]; + } else { + RangeCoder rc; + ff_build_rac_states(&rc, 0.05 * (1LL << 32), 256 - 8); + for (int i = 1; i < 256; i++) + f->state_transition[i] = rc.one_state[i]; + } + + f->colorspace = ff_ffv1_get_symbol(&c, state, 0); //YUV cs type + f->avctx->bits_per_raw_sample = ff_ffv1_get_symbol(&c, state, 0); + f->chroma_planes = get_rac(&c, state); + f->chroma_h_shift = ff_ffv1_get_symbol(&c, state, 0); + f->chroma_v_shift = ff_ffv1_get_symbol(&c, state, 0); + f->transparency = get_rac(&c, state); + f->plane_count = 1 + (f->chroma_planes || f->version<4) + f->transparency; + f->num_h_slices = 1 + ff_ffv1_get_symbol(&c, state, 0); + f->num_v_slices = 1 + ff_ffv1_get_symbol(&c, state, 0); + + if (f->chroma_h_shift > 4U || f->chroma_v_shift > 4U) { + av_log(f->avctx, AV_LOG_ERROR, "chroma shift parameters %d %d are invalid\n", + f->chroma_h_shift, f->chroma_v_shift); + return AVERROR_INVALIDDATA; + } + + if (f->num_h_slices > (unsigned)f->width || !f->num_h_slices || + f->num_v_slices > (unsigned)f->height || !f->num_v_slices + ) { + av_log(f->avctx, AV_LOG_ERROR, "slice count invalid\n"); + return AVERROR_INVALIDDATA; + } + + if (f->num_h_slices > MAX_SLICES / f->num_v_slices) { + av_log(f->avctx, AV_LOG_ERROR, "slice count unsupported\n"); + return AVERROR_PATCHWELCOME; + } + + f->quant_table_count = ff_ffv1_get_symbol(&c, state, 0); + if (f->quant_table_count > (unsigned)MAX_QUANT_TABLES || !f->quant_table_count) { + av_log(f->avctx, AV_LOG_ERROR, "quant table count %d is invalid\n", f->quant_table_count); + f->quant_table_count = 0; + return AVERROR_INVALIDDATA; + } + + for (int i = 0; i < f->quant_table_count; i++) { + f->context_count[i] = ff_ffv1_read_quant_tables(&c, f->quant_tables[i]); + if (f->context_count[i] < 0) { + av_log(f->avctx, AV_LOG_ERROR, "read_quant_table error\n"); + return AVERROR_INVALIDDATA; + } + } + if ((ret = ff_ffv1_allocate_initial_states(f)) < 0) + return ret; + + for (int i = 0; i < f->quant_table_count; i++) + if (get_rac(&c, state)) { + for (int j = 0; j < f->context_count[i]; j++) + for (int k = 0; k < CONTEXT_SIZE; k++) { + int pred = j ? f->initial_states[i][j - 1][k] : 128; + f->initial_states[i][j][k] = + (pred + ff_ffv1_get_symbol(&c, state2[k], 1)) & 0xFF; + } + } + + if (f->version > 2) { + f->ec = ff_ffv1_get_symbol(&c, state, 0); + if (f->ec >= 2) + f->crcref = 0x7a8c4079; + if (f->combined_version >= 0x30003) + f->intra = ff_ffv1_get_symbol(&c, state, 0); + if (f->combined_version >= 0x40004) + f->flt = ff_ffv1_get_symbol(&c, state, 0); + } + + if (f->version > 2) { + unsigned v; + v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), f->crcref, + f->avctx->extradata, f->avctx->extradata_size); + if (v != f->crcref || f->avctx->extradata_size < 4) { + av_log(f->avctx, AV_LOG_ERROR, "CRC mismatch %X!\n", v); + return AVERROR_INVALIDDATA; + } + crc = AV_RB32(f->avctx->extradata + f->avctx->extradata_size - 4); + } + + if (f->avctx->debug & FF_DEBUG_PICT_INFO) + av_log(f->avctx, AV_LOG_DEBUG, + "global: ver:%d.%d, coder:%d, colorspace: %d bpr:%d chroma:%d(%d:%d), alpha:%d slices:%dx%d qtabs:%d ec:%d intra:%d CRC:0x%08X\n", + f->version, f->micro_version, + f->ac, + f->colorspace, + f->avctx->bits_per_raw_sample, + f->chroma_planes, f->chroma_h_shift, f->chroma_v_shift, + f->transparency, + f->num_h_slices, f->num_v_slices, + f->quant_table_count, + f->ec, + f->intra, + crc + ); + return 0; +} + +int ff_ffv1_parse_header(FFV1Context *f, RangeCoder *c, uint8_t *state) +{ + if (f->version < 2) { + int chroma_planes, chroma_h_shift, chroma_v_shift, transparency, colorspace, bits_per_raw_sample; + unsigned v= ff_ffv1_get_symbol(c, state, 0); + if (v >= 2) { + av_log(f->avctx, AV_LOG_ERROR, "invalid version %d in ver01 header\n", v); + return AVERROR_INVALIDDATA; + } + f->version = v; + f->ac = ff_ffv1_get_symbol(c, state, 0); + + if (f->ac == AC_RANGE_CUSTOM_TAB) { + for (int i = 1; i < 256; i++) { + int st = ff_ffv1_get_symbol(c, state, 1) + c->one_state[i]; + if (st < 1 || st > 255) { + av_log(f->avctx, AV_LOG_ERROR, "invalid state transition %d\n", st); + return AVERROR_INVALIDDATA; + } + f->state_transition[i] = st; + } + } else { + RangeCoder rc; + ff_build_rac_states(&rc, 0.05 * (1LL << 32), 256 - 8); + for (int i = 1; i < 256; i++) + f->state_transition[i] = rc.one_state[i]; + } + + colorspace = ff_ffv1_get_symbol(c, state, 0); //YUV cs type + bits_per_raw_sample = f->version > 0 ? ff_ffv1_get_symbol(c, state, 0) : f->avctx->bits_per_raw_sample; + chroma_planes = get_rac(c, state); + chroma_h_shift = ff_ffv1_get_symbol(c, state, 0); + chroma_v_shift = ff_ffv1_get_symbol(c, state, 0); + transparency = get_rac(c, state); + if (colorspace == 0 && f->avctx->skip_alpha) + transparency = 0; + + if (f->plane_count) { + if (colorspace != f->colorspace || + bits_per_raw_sample != f->avctx->bits_per_raw_sample || + chroma_planes != f->chroma_planes || + chroma_h_shift != f->chroma_h_shift || + chroma_v_shift != f->chroma_v_shift || + transparency != f->transparency) { + av_log(f->avctx, AV_LOG_ERROR, "Invalid change of global parameters\n"); + return AVERROR_INVALIDDATA; + } + } + + if (chroma_h_shift > 4U || chroma_v_shift > 4U) { + av_log(f->avctx, AV_LOG_ERROR, "chroma shift parameters %d %d are invalid\n", + chroma_h_shift, chroma_v_shift); + return AVERROR_INVALIDDATA; + } + + f->colorspace = colorspace; + f->avctx->bits_per_raw_sample = bits_per_raw_sample; + f->chroma_planes = chroma_planes; + f->chroma_h_shift = chroma_h_shift; + f->chroma_v_shift = chroma_v_shift; + f->transparency = transparency; + + f->plane_count = 2 + f->transparency; + } + + if (f->colorspace == 0) { + if (!f->transparency && !f->chroma_planes) { + if (f->avctx->bits_per_raw_sample <= 8) + f->pix_fmt = AV_PIX_FMT_GRAY8; + else if (f->avctx->bits_per_raw_sample == 9) { + f->packed_at_lsb = 1; + f->pix_fmt = AV_PIX_FMT_GRAY9; + } else if (f->avctx->bits_per_raw_sample == 10) { + f->packed_at_lsb = 1; + f->pix_fmt = AV_PIX_FMT_GRAY10; + } else if (f->avctx->bits_per_raw_sample == 12) { + f->packed_at_lsb = 1; + f->pix_fmt = AV_PIX_FMT_GRAY12; + } else if (f->avctx->bits_per_raw_sample == 14) { + f->packed_at_lsb = 1; + f->pix_fmt = AV_PIX_FMT_GRAY14; + } else if (f->avctx->bits_per_raw_sample == 16) { + f->packed_at_lsb = 1; + if (f->flt) { + f->pix_fmt = AV_PIX_FMT_GRAYF16; + } else + f->pix_fmt = AV_PIX_FMT_GRAY16; + } else if (f->avctx->bits_per_raw_sample < 16) { + f->pix_fmt = AV_PIX_FMT_GRAY16; + } else + return AVERROR(ENOSYS); + } else if (f->transparency && !f->chroma_planes) { + if (f->avctx->bits_per_raw_sample <= 8 && !f->flt) { + f->pix_fmt = AV_PIX_FMT_YA8; + } else if (f->avctx->bits_per_raw_sample == 16 && f->flt) { + f->pix_fmt = AV_PIX_FMT_YAF16; + } else + return AVERROR(ENOSYS); + } else if (f->avctx->bits_per_raw_sample<=8 && !f->transparency) { + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUV444P; break; + case 0x01: f->pix_fmt = AV_PIX_FMT_YUV440P; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUV420P; break; + case 0x20: f->pix_fmt = AV_PIX_FMT_YUV411P; break; + case 0x22: f->pix_fmt = AV_PIX_FMT_YUV410P; break; + } + } else if (f->avctx->bits_per_raw_sample <= 8 && f->transparency) { + switch(16*f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUVA444P; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUVA422P; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUVA420P; break; + } + } else if (f->avctx->bits_per_raw_sample == 9 && !f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUV444P9; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P9; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUV420P9; break; + } + } else if (f->avctx->bits_per_raw_sample == 9 && f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUVA444P9; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUVA422P9; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUVA420P9; break; + } + } else if (f->avctx->bits_per_raw_sample == 10 && !f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUV444P10; break; + case 0x01: f->pix_fmt = AV_PIX_FMT_YUV440P10; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P10; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUV420P10; break; + } + } else if (f->avctx->bits_per_raw_sample == 10 && f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUVA444P10; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUVA422P10; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUVA420P10; break; + } + } else if (f->avctx->bits_per_raw_sample == 12 && !f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUV444P12; break; + case 0x01: f->pix_fmt = AV_PIX_FMT_YUV440P12; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P12; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUV420P12; break; + } + } else if (f->avctx->bits_per_raw_sample == 12 && f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUVA444P12; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUVA422P12; break; + } + } else if (f->avctx->bits_per_raw_sample == 14 && !f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUV444P14; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P14; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUV420P14; break; + } + } else if (f->avctx->bits_per_raw_sample == 16 && !f->transparency){ + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUV444P16; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P16; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUV420P16; break; + } + } else if (f->avctx->bits_per_raw_sample == 16 && f->transparency){ + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUVA444P16; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUVA422P16; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUVA420P16; break; + } + } + } else if (f->colorspace == 1) { + if (f->chroma_h_shift || f->chroma_v_shift) { + av_log(f->avctx, AV_LOG_ERROR, + "chroma subsampling not supported in this colorspace\n"); + return AVERROR(ENOSYS); + } + if ( f->avctx->bits_per_raw_sample <= 8 && !f->transparency) + f->pix_fmt = AV_PIX_FMT_0RGB32; + else if (f->avctx->bits_per_raw_sample <= 8 && f->transparency) + f->pix_fmt = AV_PIX_FMT_RGB32; + else if (f->avctx->bits_per_raw_sample == 9 && !f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRP9; + else if (f->avctx->bits_per_raw_sample == 10 && !f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRP10; + else if (f->avctx->bits_per_raw_sample == 10 && f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRAP10; + else if (f->avctx->bits_per_raw_sample == 12 && !f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRP12; + else if (f->avctx->bits_per_raw_sample == 12 && f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRAP12; + else if (f->avctx->bits_per_raw_sample == 14 && !f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRP14; + else if (f->avctx->bits_per_raw_sample == 14 && f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRAP14; + else if (f->avctx->bits_per_raw_sample == 16 && !f->transparency) { + if (f->flt) { + f->pix_fmt = AV_PIX_FMT_GBRPF16; + } else + f->pix_fmt = AV_PIX_FMT_GBRP16; + f->use32bit = 1; + } else if (f->avctx->bits_per_raw_sample == 16 && f->transparency) { + if (f->flt) { + f->pix_fmt = AV_PIX_FMT_GBRAPF16; + } else + f->pix_fmt = AV_PIX_FMT_GBRAP16; + f->use32bit = 1; + } else if (f->avctx->bits_per_raw_sample == 32 && !f->transparency) { + if (f->flt) { + f->pix_fmt = AV_PIX_FMT_GBRPF32; + } + f->use32bit = 1; + } else if (f->avctx->bits_per_raw_sample == 32 && f->transparency) { + if (f->flt) { + f->pix_fmt = AV_PIX_FMT_GBRAPF32; + } + f->use32bit = 1; + } + } else { + av_log(f->avctx, AV_LOG_ERROR, "colorspace not supported\n"); + return AVERROR(ENOSYS); + } + if (f->pix_fmt == AV_PIX_FMT_NONE) { + av_log(f->avctx, AV_LOG_ERROR, "format not supported\n"); + return AVERROR(ENOSYS); + } + + return 0; +} diff --git a/libavcodec/ffv1_parser.c b/libavcodec/ffv1_parser.c new file mode 100644 index 000000000..f378970bf --- /dev/null +++ b/libavcodec/ffv1_parser.c @@ -0,0 +1,89 @@ +/* + * 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 "avcodec.h" +#include "ffv1.h" +#include "parser_internal.h" +#include "rangecoder.h" + +#include "libavutil/attributes.h" + +typedef struct FFV1ParseContext { + FFV1Context f; + int got_first; +} FFV1ParseContext; + +static int parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + FFV1ParseContext *p = s->priv_data; + FFV1Context *f = &p->f; + RangeCoder c; + uint8_t keystate = 128; + + *poutbuf = buf; + *poutbuf_size = buf_size; + + if (!p->got_first) { + int ret = ff_ffv1_common_init(avctx, f); + p->got_first = 1; + if (ret < 0) + return buf_size; + + if (avctx->extradata_size > 0 && (ret = ff_ffv1_read_extra_header(f)) < 0) + return buf_size; + } + + ff_init_range_decoder(&c, buf, buf_size); + ff_build_rac_states(&c, 0.05 * (1LL << 32), 256 - 8); + + f->avctx = avctx; + s->key_frame = get_rac(&c, &keystate); + s->pict_type = AV_PICTURE_TYPE_I; + s->field_order = AV_FIELD_UNKNOWN; + s->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN; + + if (s->key_frame) { + uint8_t state[CONTEXT_SIZE]; + memset(state, 128, sizeof(state)); + ff_ffv1_parse_header(f, &c, state); + } + + s->width = f->width; + s->height = f->height; + s->format = f->pix_fmt; + + return buf_size; +} + +static av_cold void ffv1_close(AVCodecParserContext *s) +{ + FFV1ParseContext *p = s->priv_data; + + p->f.avctx = NULL; + ff_ffv1_close(&p->f); +} + +const FFCodecParser ff_ffv1_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_FFV1), + .priv_data_size = sizeof(FFV1ParseContext), + .parse = parse, + .close = ffv1_close, +}; diff --git a/libavcodec/ffv1_vulkan.c b/libavcodec/ffv1_vulkan.c new file mode 100644 index 000000000..2a2226016 --- /dev/null +++ b/libavcodec/ffv1_vulkan.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025 Lynne + * + * 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 "ffv1_vulkan.h" +#include "libavutil/crc.h" + +void ff_ffv1_vk_set_common_sl(AVCodecContext *avctx, FFV1Context *f, + VkSpecializationInfo *sl, + enum AVPixelFormat sw_format) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(sw_format); + int color_planes = av_pix_fmt_desc_get(sw_format)->nb_components; + int is_rgb = !(f->colorspace == 0 && sw_format != AV_PIX_FMT_YA8) && + !(sw_format == AV_PIX_FMT_YA8); + + SPEC_LIST_ADD(sl, 2, 32, f->version); + SPEC_LIST_ADD(sl, 3, 32, f->quant_table_count); + + for (int i = 0; i < f->quant_table_count; i++) { + if (f->quant_tables[i][3][127] || f->quant_tables[i][4][127]) { + SPEC_LIST_ADD(sl, 4, 32, 1); + break; + } + } + + int bits = desc->comp[0].depth; + SPEC_LIST_ADD(sl, 5, 32, 1 << bits); + SPEC_LIST_ADD(sl, 6, 32, f->colorspace); + SPEC_LIST_ADD(sl, 7, 32, f->transparency); + SPEC_LIST_ADD(sl, 8, 32, ff_vk_mt_is_np_rgb(sw_format) && + (desc->flags & AV_PIX_FMT_FLAG_PLANAR)); + SPEC_LIST_ADD(sl, 9, 32, f->plane_count); + SPEC_LIST_ADD(sl, 10, 32, color_planes); + SPEC_LIST_ADD(sl, 11, 32, av_pix_fmt_count_planes(sw_format)); + SPEC_LIST_ADD(sl, 12, 32, bits + is_rgb); + + SPEC_LIST_ADD(sl, 13, 32, f->chroma_h_shift); + SPEC_LIST_ADD(sl, 14, 32, f->chroma_v_shift); +} + +static void set_crc_tab(uint32_t *buf) +{ + for (uint32_t i = 0; i < 256; i++) { + uint32_t c = i << 24; + for (int j = 0; j < 8; j++) + c = (c << 1) ^ (0x04C11DB7 & (((int32_t) c) >> 31)); + buf[i] = av_bswap32(c); + } +} + +static void set_rc_state_tab(FFV1Context *f, uint8_t *buf) +{ + for (int i = 1; i < 256; i++) { + buf[256 + i] = f->state_transition[i]; + buf[256 - i] = 256 - (int)f->state_transition[i]; + } +} + +int ff_ffv1_vk_init_consts(FFVulkanContext *s, FFVkBuffer *vkb, FFV1Context *f) +{ + int err; + + uint8_t *buf_mapped; + size_t buf_len = 256*sizeof(uint32_t) + /* CRC */ + 512*sizeof(uint8_t) + /* Rangecoder */ + MAX_QUANT_TABLES* + MAX_CONTEXT_INPUTS* + MAX_QUANT_TABLE_SIZE*sizeof(int16_t); + + RET(ff_vk_create_buf(s, vkb, + buf_len, + NULL, NULL, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + RET(ff_vk_map_buffer(s, vkb, (void *)&buf_mapped, 0)); + + set_crc_tab((uint32_t *)buf_mapped); + + set_rc_state_tab(f, buf_mapped + 256*sizeof(uint32_t)); + + memcpy(buf_mapped + 256*sizeof(uint32_t) + 512*sizeof(uint8_t), + f->quant_tables, sizeof(f->quant_tables)); + + RET(ff_vk_unmap_buffer(s, vkb, 1)); + +fail: + return err; +} diff --git a/libavcodec/ffv1_vulkan.h b/libavcodec/ffv1_vulkan.h new file mode 100644 index 000000000..9a206afac --- /dev/null +++ b/libavcodec/ffv1_vulkan.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 Lynne + * + * 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_FFV1_VULKAN_H +#define AVCODEC_FFV1_VULKAN_H + +#include "libavutil/vulkan.h" +#include "ffv1.h" + +void ff_ffv1_vk_set_common_sl(AVCodecContext *avctx, FFV1Context *f, + VkSpecializationInfo *sl, + enum AVPixelFormat sw_format); + +int ff_ffv1_vk_init_consts(FFVulkanContext *s, FFVkBuffer *vkb, FFV1Context *f); + +typedef struct FFv1ShaderParams { + VkDeviceAddress slice_data; + + uint32_t extend_lookup[8]; + uint16_t context_count[8]; + + int fmt_lut[4]; + uint16_t img_size[2]; + + uint32_t plane_state_size; + uint32_t key_frame; + uint32_t crcref; + int micro_version; + + /* Encoder-only */ + int sar[2]; + int pic_mode; + uint32_t slice_size_max; +} FFv1ShaderParams; + +#endif /* AVCODEC_FFV1_VULKAN_H */ diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c index 19a325405..28e6ec3c4 100644 --- a/libavcodec/ffv1dec.c +++ b/libavcodec/ffv1dec.c @@ -38,37 +38,12 @@ #include "mathops.h" #include "ffv1.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" - -static inline av_flatten int get_symbol_inline(RangeCoder *c, uint8_t *state, - int is_signed) -{ - if (get_rac(c, state + 0)) - return 0; - else { - int e; - unsigned a; - e = 0; - while (get_rac(c, state + 1 + FFMIN(e, 9))) { // 1..10 - e++; - if (e > 31) - return AVERROR_INVALIDDATA; - } - - a = 1; - for (int i = e - 1; i >= 0; i--) - a += a + get_rac(c, state + 22 + FFMIN(i, 9)); // 22..31 - - e = -(is_signed && get_rac(c, state + 11 + FFMIN(e, 10))); // 11..21 - return (a ^ e) - e; - } -} - -static av_noinline int get_symbol(RangeCoder *c, uint8_t *state, int is_signed) -{ - return get_symbol_inline(c, state, is_signed); -} +#include "decode.h" +#include "hwconfig.h" +#include "hwaccel_internal.h" +#include "config_components.h" static inline int get_vlc_symbol(GetBitContext *gb, VlcState *const state, int bits) @@ -125,11 +100,20 @@ static int is_input_end(RangeCoder *c, GetBitContext *gb, int ac) static int decode_plane(FFV1Context *f, FFV1SliceContext *sc, GetBitContext *gb, uint8_t *src, int w, int h, int stride, int plane_index, - int pixel_stride) + int remap_index, int pixel_stride, int ac) { - const int ac = f->ac; int x, y; int16_t *sample[2]; + int bits; + unsigned mask; + + if (sc->remap) { + bits = av_ceil_log2(sc->remap_count[remap_index]); + mask = (1<avctx->bits_per_raw_sample; + } + sample[0] = sc->sample_buffer + 3; sample[1] = sc->sample_buffer + w + 6 + 3; @@ -150,19 +134,36 @@ static int decode_plane(FFV1Context *f, FFV1SliceContext *sc, int ret = decode_line(f, sc, gb, w, sample, plane_index, 8, ac); if (ret < 0) return ret; + if (sc->remap) + for (x = 0; x < w; x++) + sample[1][x] = sc->fltmap[remap_index][sample[1][x]]; for (x = 0; x < w; x++) src[x*pixel_stride + stride * y] = sample[1][x]; } else { - int ret = decode_line(f, sc, gb, w, sample, plane_index, f->avctx->bits_per_raw_sample, ac); + int ret = decode_line(f, sc, gb, w, sample, plane_index, bits, ac); if (ret < 0) return ret; - if (f->packed_at_lsb) { - for (x = 0; x < w; x++) { - ((uint16_t*)(src + stride*y))[x*pixel_stride] = sample[1][x]; + + if (sc->remap) { + if (f->packed_at_lsb || f->avctx->bits_per_raw_sample == 16) { + for (x = 0; x < w; x++) { + ((uint16_t*)(src + stride*y))[x*pixel_stride] = sc->fltmap[remap_index][sample[1][x] & mask]; + } + } else { + for (x = 0; x < w; x++) { + int v = sc->fltmap[remap_index][sample[1][x] & mask]; + ((uint16_t*)(src + stride*y))[x*pixel_stride] = v << (16 - f->avctx->bits_per_raw_sample) | v >> (2 * f->avctx->bits_per_raw_sample - 16); + } } } else { - for (x = 0; x < w; x++) { - ((uint16_t*)(src + stride*y))[x*pixel_stride] = sample[1][x] << (16 - f->avctx->bits_per_raw_sample) | ((uint16_t **)sample)[1][x] >> (2 * f->avctx->bits_per_raw_sample - 16); + if (f->packed_at_lsb || f->avctx->bits_per_raw_sample == 16) { + for (x = 0; x < w; x++) { + ((uint16_t*)(src + stride*y))[x*pixel_stride] = sample[1][x]; + } + } else { + for (x = 0; x < w; x++) { + ((uint16_t*)(src + stride*y))[x*pixel_stride] = sample[1][x] << (16 - f->avctx->bits_per_raw_sample) | ((uint16_t **)sample)[1][x] >> (2 * f->avctx->bits_per_raw_sample - 16); + } } } } @@ -179,10 +180,10 @@ static int decode_slice_header(const FFV1Context *f, int sx, sy, sw, sh; memset(state, 128, sizeof(state)); - sx = get_symbol(c, state, 0); - sy = get_symbol(c, state, 0); - sw = get_symbol(c, state, 0) + 1U; - sh = get_symbol(c, state, 0) + 1U; + sx = ff_ffv1_get_symbol(c, state, 0); + sy = ff_ffv1_get_symbol(c, state, 0); + sw = ff_ffv1_get_symbol(c, state, 0) + 1U; + sh = ff_ffv1_get_symbol(c, state, 0) + 1U; av_assert0(f->version > 2); @@ -192,10 +193,10 @@ static int decode_slice_header(const FFV1Context *f, if (sx > f->num_h_slices - sw || sy > f->num_v_slices - sh) return AVERROR_INVALIDDATA; - sc->slice_x = sx * (int64_t)f->width / f->num_h_slices; - sc->slice_y = sy * (int64_t)f->height / f->num_v_slices; - sc->slice_width = (sx + sw) * (int64_t)f->width / f->num_h_slices - sc->slice_x; - sc->slice_height = (sy + sh) * (int64_t)f->height / f->num_v_slices - sc->slice_y; + sc->slice_x = ff_slice_coord(f, f->width , sx , f->num_h_slices, f->chroma_h_shift); + sc->slice_y = ff_slice_coord(f, f->height, sy , f->num_v_slices, f->chroma_v_shift); + sc->slice_width = ff_slice_coord(f, f->width , sx + sw, f->num_h_slices, f->chroma_h_shift) - sc->slice_x; + sc->slice_height = ff_slice_coord(f, f->height, sy + sh, f->num_v_slices, f->chroma_v_shift) - sc->slice_y; av_assert0((unsigned)sc->slice_width <= f->width && (unsigned)sc->slice_height <= f->height); @@ -207,7 +208,7 @@ static int decode_slice_header(const FFV1Context *f, for (unsigned i = 0; i < f->plane_count; i++) { PlaneContext * const p = &sc->plane[i]; - int idx = get_symbol(c, state, 0); + int idx = ff_ffv1_get_symbol(c, state, 0); if (idx >= (unsigned)f->quant_table_count) { av_log(f->avctx, AV_LOG_ERROR, "quant_table_index out of range\n"); return -1; @@ -222,7 +223,7 @@ static int decode_slice_header(const FFV1Context *f, p->context_count = context_count; } - ps = get_symbol(c, state, 0); + ps = ff_ffv1_get_symbol(c, state, 0); if (ps == 1) { frame->flags |= AV_FRAME_FLAG_INTERLACED; frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; @@ -232,8 +233,8 @@ static int decode_slice_header(const FFV1Context *f, } else if (ps == 3) { frame->flags &= ~AV_FRAME_FLAG_INTERLACED; } - frame->sample_aspect_ratio.num = get_symbol(c, state, 0); - frame->sample_aspect_ratio.den = get_symbol(c, state, 0); + frame->sample_aspect_ratio.num = ff_ffv1_get_symbol(c, state, 0); + frame->sample_aspect_ratio.den = ff_ffv1_get_symbol(c, state, 0); if (av_image_check_sar(f->width, f->height, frame->sample_aspect_ratio) < 0) { @@ -245,15 +246,29 @@ static int decode_slice_header(const FFV1Context *f, if (f->version > 3) { sc->slice_reset_contexts = get_rac(c, state); - sc->slice_coding_mode = get_symbol(c, state, 0); + sc->slice_coding_mode = ff_ffv1_get_symbol(c, state, 0); if (sc->slice_coding_mode != 1 && f->colorspace == 1) { - sc->slice_rct_by_coef = get_symbol(c, state, 0); - sc->slice_rct_ry_coef = get_symbol(c, state, 0); + sc->slice_rct_by_coef = ff_ffv1_get_symbol(c, state, 0); + sc->slice_rct_ry_coef = ff_ffv1_get_symbol(c, state, 0); if ((uint64_t)sc->slice_rct_by_coef + (uint64_t)sc->slice_rct_ry_coef > 4) { av_log(f->avctx, AV_LOG_ERROR, "slice_rct_y_coef out of range\n"); return AVERROR_INVALIDDATA; } } + if (f->combined_version >= 0x40004) { + sc->remap = ff_ffv1_get_symbol(c, state, 0); + if (sc->remap > 2U || + sc->remap && !f->flt) { + av_log(f->avctx, AV_LOG_ERROR, "unsupported remap %d\n", sc->remap); + return AVERROR_INVALIDDATA; + } + } + } + if (f->avctx->bits_per_raw_sample == 32) { + if (!sc->remap) { + av_log(f->avctx, AV_LOG_ERROR, "unsupported remap\n"); + return AVERROR_INVALIDDATA; + } } return 0; @@ -269,15 +284,89 @@ static void slice_set_damaged(FFV1Context *f, FFV1SliceContext *sc) f->frame_damaged = 1; } +static int decode_current_mul(RangeCoder *rc, uint8_t state[32], int *mul, int mul_count, int64_t i) +{ + int ndx = (i * mul_count) >> 32; + av_assert2(ndx <= 4096U); + + if (mul[ndx] < 0) + mul[ndx] = ff_ffv1_get_symbol(rc, state, 0) & 0x3FFFFFFF; + + return mul[ndx]; +} + +static int decode_remap(FFV1Context *f, FFV1SliceContext *sc) +{ + unsigned int end = (1LL<avctx->bits_per_raw_sample) - 1; + int flip = sc->remap == 2 ? (end>>1) : 0; + const int pixel_num = sc->slice_width * sc->slice_height; + + for (int p= 0; p < 1 + 2*f->chroma_planes + f->transparency; p++) { + int j = 0; + int lu = 0; + uint8_t state[2][3][32]; + int64_t i; + int mul[4096+1]; + int mul_count; + + memset(state, 128, sizeof(state)); + mul_count = ff_ffv1_get_symbol(&sc->c, state[0][0], 0); + + if (mul_count > 4096U) + return AVERROR_INVALIDDATA; + for (int i = 0; ic, state[lu][0], 0); + unsigned run0 = lu ? 0 : run; + unsigned run1 = lu ? run : 1; + + i += run0 * current_mul; + + while (run1--) { + if (current_mul > 1) { + int delta = get_symbol_inline(&sc->c, state[lu][1], 1); + if (delta <= -current_mul || delta > current_mul/2) + return AVERROR_INVALIDDATA; //not sure we should check this + i += current_mul - 1 + delta; + } + if (i - 1 >= end) + break; + if (j >= pixel_num) + return AVERROR_INVALIDDATA; + if (end <= 0xFFFF) { + sc->fltmap [p][j++] = i ^ ((i& 0x8000) ? 0 : flip); + } else + sc->fltmap32[p][j++] = i ^ ((i&0x80000000) ? 0 : flip); + i++; + current_mul = decode_current_mul(&sc->c, state[0][2], mul, mul_count, i); + } + if (lu) { + i += current_mul; + } + lu ^= !run; + } + sc->remap_count[p] = j; + } + return 0; +} + static int decode_slice(AVCodecContext *c, void *arg) { FFV1Context *f = c->priv_data; FFV1SliceContext *sc = arg; int width, height, x, y, ret; - const int ps = av_pix_fmt_desc_get(c->pix_fmt)->comp[0].step; + const int ps = av_pix_fmt_desc_get(f->pix_fmt)->comp[0].step; AVFrame * const p = f->picture.f; const int si = sc - f->slices; GetBitContext gb; + int ac = f->ac || sc->slice_coding_mode == 1; if (!(p->flags & AV_FRAME_FLAG_KEY) && f->last_picture.f) ff_progress_frame_await(&f->last_picture, si); @@ -310,8 +399,28 @@ static int decode_slice(AVCodecContext *c, void *arg) x = sc->slice_x; y = sc->slice_y; - if (f->ac == AC_GOLOMB_RICE) { - if (f->version == 3 && f->micro_version > 1 || f->version > 3) + if (sc->remap) { + const int pixel_num = sc->slice_width * sc->slice_height; + + for(int p = 0; p < 1 + 2*f->chroma_planes + f->transparency ; p++) { + if (f->avctx->bits_per_raw_sample == 32) { + av_fast_malloc(&sc->fltmap32[p], &sc->fltmap32_size[p], pixel_num * sizeof(*sc->fltmap32[p])); + if (!sc->fltmap32[p]) + return AVERROR(ENOMEM); + } else { + av_fast_malloc(&sc->fltmap[p], &sc->fltmap_size[p], pixel_num * sizeof(*sc->fltmap[p])); + if (!sc->fltmap[p]) + return AVERROR(ENOMEM); + } + } + + ret = decode_remap(f, sc); + if (ret < 0) + return ret; + } + + if (ac == AC_GOLOMB_RICE) { + if (f->combined_version >= 0x30002) get_rac(&sc->c, (uint8_t[]) { 129 }); sc->ac_byte_count = f->version > 2 || (!x && !y) ? sc->c.bytestream - sc->c.bytestream_start - 1 : 0; init_get_bits(&gb, @@ -325,17 +434,18 @@ static int decode_slice(AVCodecContext *c, void *arg) const int chroma_height = AV_CEIL_RSHIFT(height, f->chroma_v_shift); const int cx = x >> f->chroma_h_shift; const int cy = y >> f->chroma_v_shift; - decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 1); + decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 0, 1, ac); if (f->chroma_planes) { - decode_plane(f, sc, &gb, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1); - decode_plane(f, sc, &gb, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 1); + decode_plane(f, sc, &gb, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1, 1, ac); + decode_plane(f, sc, &gb, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 2, 1, ac); } if (f->transparency) - decode_plane(f, sc, &gb, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], (f->version >= 4 && !f->chroma_planes) ? 1 : 2, 1); + decode_plane(f, sc, &gb, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], (f->version >= 4 && !f->chroma_planes) ? 1 : 2, + (f->version >= 4 && !f->chroma_planes) ? 1 : 3, 1, ac); } else if (f->colorspace == 0) { - decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] , width, height, p->linesize[0], 0, 2); - decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] + 1, width, height, p->linesize[0], 1, 2); + decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] , width, height, p->linesize[0], 0, 0, 2, ac); + decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] + (ps>>1), width, height, p->linesize[0], 1, 1, 2, ac); } else if (f->use32bit) { uint8_t *planes[4] = { p->data[0] + ps * x + y * p->linesize[0], p->data[1] + ps * x + y * p->linesize[1], @@ -353,7 +463,7 @@ static int decode_slice(AVCodecContext *c, void *arg) } decode_rgb_frame(f, sc, &gb, planes, width, height, p->linesize); } - if (f->ac != AC_GOLOMB_RICE && f->version > 2) { + if (ac != AC_GOLOMB_RICE && f->version > 2) { int v; get_rac(&sc->c, (uint8_t[]) { 129 }); v = sc->c.bytestream_end - sc->c.bytestream - 2 - 5*!!f->ec; @@ -363,410 +473,64 @@ static int decode_slice(AVCodecContext *c, void *arg) } } + if (sc->slice_damaged && (f->avctx->err_recognition & AV_EF_EXPLODE)) + return AVERROR_INVALIDDATA; + if ((c->active_thread_type & FF_THREAD_FRAME) && !f->frame_damaged) ff_progress_frame_report(&f->picture, si); return 0; } -static int read_quant_table(RangeCoder *c, int16_t *quant_table, int scale) +static enum AVPixelFormat get_pixel_format(FFV1Context *f) { - int v; - int i = 0; - uint8_t state[CONTEXT_SIZE]; + enum AVPixelFormat pix_fmts[] = { +#if CONFIG_FFV1_VULKAN_HWACCEL + AV_PIX_FMT_VULKAN, +#endif + f->pix_fmt, + AV_PIX_FMT_NONE, + }; - memset(state, 128, sizeof(state)); - - for (v = 0; i < 128; v++) { - unsigned len = get_symbol(c, state, 0) + 1U; - - if (len > 128 - i || !len) - return AVERROR_INVALIDDATA; - - while (len--) { - quant_table[i] = scale * v; - i++; - } - } - - for (i = 1; i < 128; i++) - quant_table[256 - i] = -quant_table[i]; - quant_table[128] = -quant_table[127]; - - return 2 * v - 1; + return ff_get_format(f->avctx, pix_fmts); } -static int read_quant_tables(RangeCoder *c, - int16_t quant_table[MAX_CONTEXT_INPUTS][256]) -{ - int i; - int context_count = 1; - - for (i = 0; i < 5; i++) { - int ret = read_quant_table(c, quant_table[i], context_count); - if (ret < 0) - return ret; - context_count *= ret; - if (context_count > 32768U) { - return AVERROR_INVALIDDATA; - } - } - return (context_count + 1) / 2; -} - -static int read_extra_header(FFV1Context *f) -{ - RangeCoder c; - uint8_t state[CONTEXT_SIZE]; - int ret; - uint8_t state2[32][CONTEXT_SIZE]; - unsigned crc = 0; - - memset(state2, 128, sizeof(state2)); - memset(state, 128, sizeof(state)); - - ff_init_range_decoder(&c, f->avctx->extradata, f->avctx->extradata_size); - ff_build_rac_states(&c, 0.05 * (1LL << 32), 256 - 8); - - f->version = get_symbol(&c, state, 0); - if (f->version < 2) { - av_log(f->avctx, AV_LOG_ERROR, "Invalid version in global header\n"); - return AVERROR_INVALIDDATA; - } - if (f->version > 4) { - av_log(f->avctx, AV_LOG_ERROR, "unsupported version %d\n", - f->version); - return AVERROR_PATCHWELCOME; - } - if (f->version > 2) { - c.bytestream_end -= 4; - f->micro_version = get_symbol(&c, state, 0); - if (f->micro_version < 0) - return AVERROR_INVALIDDATA; - } - f->ac = get_symbol(&c, state, 0); - - if (f->ac == AC_RANGE_CUSTOM_TAB) { - for (int i = 1; i < 256; i++) - f->state_transition[i] = get_symbol(&c, state, 1) + c.one_state[i]; - } - - f->colorspace = get_symbol(&c, state, 0); //YUV cs type - f->avctx->bits_per_raw_sample = get_symbol(&c, state, 0); - f->chroma_planes = get_rac(&c, state); - f->chroma_h_shift = get_symbol(&c, state, 0); - f->chroma_v_shift = get_symbol(&c, state, 0); - f->transparency = get_rac(&c, state); - f->plane_count = 1 + (f->chroma_planes || f->version<4) + f->transparency; - f->num_h_slices = 1 + get_symbol(&c, state, 0); - f->num_v_slices = 1 + get_symbol(&c, state, 0); - - if (f->chroma_h_shift > 4U || f->chroma_v_shift > 4U) { - av_log(f->avctx, AV_LOG_ERROR, "chroma shift parameters %d %d are invalid\n", - f->chroma_h_shift, f->chroma_v_shift); - return AVERROR_INVALIDDATA; - } - - if (f->num_h_slices > (unsigned)f->width || !f->num_h_slices || - f->num_v_slices > (unsigned)f->height || !f->num_v_slices - ) { - av_log(f->avctx, AV_LOG_ERROR, "slice count invalid\n"); - return AVERROR_INVALIDDATA; - } - - if (f->num_h_slices > MAX_SLICES / f->num_v_slices) { - av_log(f->avctx, AV_LOG_ERROR, "slice count unsupported\n"); - return AVERROR_PATCHWELCOME; - } - - f->quant_table_count = get_symbol(&c, state, 0); - if (f->quant_table_count > (unsigned)MAX_QUANT_TABLES || !f->quant_table_count) { - av_log(f->avctx, AV_LOG_ERROR, "quant table count %d is invalid\n", f->quant_table_count); - f->quant_table_count = 0; - return AVERROR_INVALIDDATA; - } - - for (int i = 0; i < f->quant_table_count; i++) { - f->context_count[i] = read_quant_tables(&c, f->quant_tables[i]); - if (f->context_count[i] < 0) { - av_log(f->avctx, AV_LOG_ERROR, "read_quant_table error\n"); - return AVERROR_INVALIDDATA; - } - } - if ((ret = ff_ffv1_allocate_initial_states(f)) < 0) - return ret; - - for (int i = 0; i < f->quant_table_count; i++) - if (get_rac(&c, state)) { - for (int j = 0; j < f->context_count[i]; j++) - for (int k = 0; k < CONTEXT_SIZE; k++) { - int pred = j ? f->initial_states[i][j - 1][k] : 128; - f->initial_states[i][j][k] = - (pred + get_symbol(&c, state2[k], 1)) & 0xFF; - } - } - - if (f->version > 2) { - f->ec = get_symbol(&c, state, 0); - if (f->micro_version > 2) - f->intra = get_symbol(&c, state, 0); - } - - if (f->version > 2) { - unsigned v; - v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, - f->avctx->extradata, f->avctx->extradata_size); - if (v || f->avctx->extradata_size < 4) { - av_log(f->avctx, AV_LOG_ERROR, "CRC mismatch %X!\n", v); - return AVERROR_INVALIDDATA; - } - crc = AV_RB32(f->avctx->extradata + f->avctx->extradata_size - 4); - } - - if (f->avctx->debug & FF_DEBUG_PICT_INFO) - av_log(f->avctx, AV_LOG_DEBUG, - "global: ver:%d.%d, coder:%d, colorspace: %d bpr:%d chroma:%d(%d:%d), alpha:%d slices:%dx%d qtabs:%d ec:%d intra:%d CRC:0x%08X\n", - f->version, f->micro_version, - f->ac, - f->colorspace, - f->avctx->bits_per_raw_sample, - f->chroma_planes, f->chroma_h_shift, f->chroma_v_shift, - f->transparency, - f->num_h_slices, f->num_v_slices, - f->quant_table_count, - f->ec, - f->intra, - crc - ); - return 0; -} - -static int read_header(FFV1Context *f) +static int read_header(FFV1Context *f, RangeCoder *c) { uint8_t state[CONTEXT_SIZE]; int context_count = -1; //-1 to avoid warning - RangeCoder *const c = &f->slices[0].c; + int ret; memset(state, 128, sizeof(state)); - if (f->version < 2) { - int chroma_planes, chroma_h_shift, chroma_v_shift, transparency, colorspace, bits_per_raw_sample; - unsigned v= get_symbol(c, state, 0); - if (v >= 2) { - av_log(f->avctx, AV_LOG_ERROR, "invalid version %d in ver01 header\n", v); - return AVERROR_INVALIDDATA; - } - f->version = v; - f->ac = get_symbol(c, state, 0); + ret = ff_ffv1_parse_header(f, c, state); + if (ret < 0) + return ret; - if (f->ac == AC_RANGE_CUSTOM_TAB) { - for (int i = 1; i < 256; i++) { - int st = get_symbol(c, state, 1) + c->one_state[i]; - if (st < 1 || st > 255) { - av_log(f->avctx, AV_LOG_ERROR, "invalid state transition %d\n", st); - return AVERROR_INVALIDDATA; - } - f->state_transition[i] = st; - } - } - - colorspace = get_symbol(c, state, 0); //YUV cs type - bits_per_raw_sample = f->version > 0 ? get_symbol(c, state, 0) : f->avctx->bits_per_raw_sample; - chroma_planes = get_rac(c, state); - chroma_h_shift = get_symbol(c, state, 0); - chroma_v_shift = get_symbol(c, state, 0); - transparency = get_rac(c, state); - if (colorspace == 0 && f->avctx->skip_alpha) - transparency = 0; - - if (f->plane_count) { - if (colorspace != f->colorspace || - bits_per_raw_sample != f->avctx->bits_per_raw_sample || - chroma_planes != f->chroma_planes || - chroma_h_shift != f->chroma_h_shift || - chroma_v_shift != f->chroma_v_shift || - transparency != f->transparency) { - av_log(f->avctx, AV_LOG_ERROR, "Invalid change of global parameters\n"); - return AVERROR_INVALIDDATA; - } - } - - if (chroma_h_shift > 4U || chroma_v_shift > 4U) { - av_log(f->avctx, AV_LOG_ERROR, "chroma shift parameters %d %d are invalid\n", - chroma_h_shift, chroma_v_shift); - return AVERROR_INVALIDDATA; - } - - f->colorspace = colorspace; - f->avctx->bits_per_raw_sample = bits_per_raw_sample; - f->chroma_planes = chroma_planes; - f->chroma_h_shift = chroma_h_shift; - f->chroma_v_shift = chroma_v_shift; - f->transparency = transparency; - - f->plane_count = 2 + f->transparency; - } - - if (f->colorspace == 0) { - if (!f->transparency && !f->chroma_planes) { - if (f->avctx->bits_per_raw_sample <= 8) - f->avctx->pix_fmt = AV_PIX_FMT_GRAY8; - else if (f->avctx->bits_per_raw_sample == 9) { - f->packed_at_lsb = 1; - f->avctx->pix_fmt = AV_PIX_FMT_GRAY9; - } else if (f->avctx->bits_per_raw_sample == 10) { - f->packed_at_lsb = 1; - f->avctx->pix_fmt = AV_PIX_FMT_GRAY10; - } else if (f->avctx->bits_per_raw_sample == 12) { - f->packed_at_lsb = 1; - f->avctx->pix_fmt = AV_PIX_FMT_GRAY12; - } else if (f->avctx->bits_per_raw_sample == 14) { - f->packed_at_lsb = 1; - f->avctx->pix_fmt = AV_PIX_FMT_GRAY14; - } else if (f->avctx->bits_per_raw_sample == 16) { - f->packed_at_lsb = 1; - f->avctx->pix_fmt = AV_PIX_FMT_GRAY16; - } else if (f->avctx->bits_per_raw_sample < 16) { - f->avctx->pix_fmt = AV_PIX_FMT_GRAY16; - } else - return AVERROR(ENOSYS); - } else if (f->transparency && !f->chroma_planes) { - if (f->avctx->bits_per_raw_sample <= 8) - f->avctx->pix_fmt = AV_PIX_FMT_YA8; - else - return AVERROR(ENOSYS); - } else if (f->avctx->bits_per_raw_sample<=8 && !f->transparency) { - switch(16 * f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P; break; - case 0x01: f->avctx->pix_fmt = AV_PIX_FMT_YUV440P; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P; break; - case 0x20: f->avctx->pix_fmt = AV_PIX_FMT_YUV411P; break; - case 0x22: f->avctx->pix_fmt = AV_PIX_FMT_YUV410P; break; - } - } else if (f->avctx->bits_per_raw_sample <= 8 && f->transparency) { - switch(16*f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P; break; - } - } else if (f->avctx->bits_per_raw_sample == 9 && !f->transparency) { - f->packed_at_lsb = 1; - switch(16 * f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P9; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P9; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P9; break; - } - } else if (f->avctx->bits_per_raw_sample == 9 && f->transparency) { - f->packed_at_lsb = 1; - switch(16 * f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P9; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P9; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P9; break; - } - } else if (f->avctx->bits_per_raw_sample == 10 && !f->transparency) { - f->packed_at_lsb = 1; - switch(16 * f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P10; break; - case 0x01: f->avctx->pix_fmt = AV_PIX_FMT_YUV440P10; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P10; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P10; break; - } - } else if (f->avctx->bits_per_raw_sample == 10 && f->transparency) { - f->packed_at_lsb = 1; - switch(16 * f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P10; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P10; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P10; break; - } - } else if (f->avctx->bits_per_raw_sample == 12 && !f->transparency) { - f->packed_at_lsb = 1; - switch(16 * f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P12; break; - case 0x01: f->avctx->pix_fmt = AV_PIX_FMT_YUV440P12; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P12; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P12; break; - } - } else if (f->avctx->bits_per_raw_sample == 12 && f->transparency) { - f->packed_at_lsb = 1; - switch(16 * f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P12; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P12; break; - } - } else if (f->avctx->bits_per_raw_sample == 14 && !f->transparency) { - f->packed_at_lsb = 1; - switch(16 * f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P14; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P14; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P14; break; - } - } else if (f->avctx->bits_per_raw_sample == 16 && !f->transparency){ - f->packed_at_lsb = 1; - switch(16 * f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P16; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P16; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P16; break; - } - } else if (f->avctx->bits_per_raw_sample == 16 && f->transparency){ - f->packed_at_lsb = 1; - switch(16 * f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P16; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P16; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P16; break; - } - } - } else if (f->colorspace == 1) { - if (f->chroma_h_shift || f->chroma_v_shift) { - av_log(f->avctx, AV_LOG_ERROR, - "chroma subsampling not supported in this colorspace\n"); - return AVERROR(ENOSYS); - } - if ( f->avctx->bits_per_raw_sample <= 8 && !f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_0RGB32; - else if (f->avctx->bits_per_raw_sample <= 8 && f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_RGB32; - else if (f->avctx->bits_per_raw_sample == 9 && !f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_GBRP9; - else if (f->avctx->bits_per_raw_sample == 10 && !f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_GBRP10; - else if (f->avctx->bits_per_raw_sample == 10 && f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_GBRAP10; - else if (f->avctx->bits_per_raw_sample == 12 && !f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_GBRP12; - else if (f->avctx->bits_per_raw_sample == 12 && f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_GBRAP12; - else if (f->avctx->bits_per_raw_sample == 14 && !f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_GBRP14; - else if (f->avctx->bits_per_raw_sample == 14 && f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_GBRAP14; - else if (f->avctx->bits_per_raw_sample == 16 && !f->transparency) { - f->avctx->pix_fmt = AV_PIX_FMT_GBRP16; - f->use32bit = 1; - } - else if (f->avctx->bits_per_raw_sample == 16 && f->transparency) { - f->avctx->pix_fmt = AV_PIX_FMT_GBRAP16; - f->use32bit = 1; - } - } else { - av_log(f->avctx, AV_LOG_ERROR, "colorspace not supported\n"); - return AVERROR(ENOSYS); - } - if (f->avctx->pix_fmt == AV_PIX_FMT_NONE) { - av_log(f->avctx, AV_LOG_ERROR, "format not supported\n"); - return AVERROR(ENOSYS); + if (f->configured_pix_fmt != f->pix_fmt || + f->configured_width != f->width || + f->configured_height != f->height || + f->configured_ac != f->ac) { + f->avctx->pix_fmt = get_pixel_format(f); + if (f->avctx->pix_fmt < 0) + return AVERROR(EINVAL); + f->configured_pix_fmt = f->pix_fmt; + f->configured_width = f->width; + f->configured_height = f->height; + f->configured_ac = f->ac; } ff_dlog(f->avctx, "%d %d %d\n", - f->chroma_h_shift, f->chroma_v_shift, f->avctx->pix_fmt); + f->chroma_h_shift, f->chroma_v_shift, f->pix_fmt); if (f->version < 2) { - context_count = read_quant_tables(c, f->quant_tables[0]); + context_count = ff_ffv1_read_quant_tables(c, f->quant_tables[0]); if (context_count < 0) { av_log(f->avctx, AV_LOG_ERROR, "read_quant_table error\n"); return AVERROR_INVALIDDATA; } f->slice_count = f->max_slice_count; } else if (f->version < 3) { - f->slice_count = get_symbol(c, state, 0); + f->slice_count = ff_ffv1_get_symbol(c, state, 0); } else { const uint8_t *p = c->bytestream_end; for (f->slice_count = 0; @@ -784,8 +548,8 @@ static int read_header(FFV1Context *f) return AVERROR_INVALIDDATA; } - ff_refstruct_unref(&f->slice_damaged); - f->slice_damaged = ff_refstruct_allocz(f->slice_count * sizeof(*f->slice_damaged)); + av_refstruct_unref(&f->slice_damaged); + f->slice_damaged = av_refstruct_allocz(f->slice_count * sizeof(*f->slice_damaged)); if (!f->slice_damaged) return AVERROR(ENOMEM); @@ -793,10 +557,10 @@ static int read_header(FFV1Context *f) FFV1SliceContext *sc = &f->slices[j]; if (f->version == 2) { - int sx = get_symbol(c, state, 0); - int sy = get_symbol(c, state, 0); - int sw = get_symbol(c, state, 0) + 1U; - int sh = get_symbol(c, state, 0) + 1U; + int sx = ff_ffv1_get_symbol(c, state, 0); + int sy = ff_ffv1_get_symbol(c, state, 0); + int sw = ff_ffv1_get_symbol(c, state, 0) + 1U; + int sh = ff_ffv1_get_symbol(c, state, 0) + 1U; if (sx < 0 || sy < 0 || sw <= 0 || sh <= 0) return AVERROR_INVALIDDATA; @@ -814,7 +578,7 @@ static int read_header(FFV1Context *f) && (unsigned)sc->slice_y + (uint64_t)sc->slice_height <= f->height); } - ff_refstruct_unref(&sc->plane); + av_refstruct_unref(&sc->plane); sc->plane = ff_ffv1_planes_alloc(); if (!sc->plane) return AVERROR(ENOMEM); @@ -823,7 +587,7 @@ static int read_header(FFV1Context *f) PlaneContext *const p = &sc->plane[i]; if (f->version == 2) { - int idx = get_symbol(c, state, 0); + int idx = ff_ffv1_get_symbol(c, state, 0); if (idx >= (unsigned)f->quant_table_count) { av_log(f->avctx, AV_LOG_ERROR, "quant_table_index out of range\n"); @@ -847,10 +611,13 @@ static av_cold int decode_init(AVCodecContext *avctx) FFV1Context *f = avctx->priv_data; int ret; - if ((ret = ff_ffv1_common_init(avctx)) < 0) + f->pix_fmt = AV_PIX_FMT_NONE; + f->configured_pix_fmt = AV_PIX_FMT_NONE; + + if ((ret = ff_ffv1_common_init(avctx, f)) < 0) return ret; - if (avctx->extradata_size > 0 && (ret = read_extra_header(f)) < 0) + if (avctx->extradata_size > 0 && (ret = ff_ffv1_read_extra_header(f)) < 0) return ret; if ((ret = ff_ffv1_init_slice_contexts(f)) < 0) @@ -859,31 +626,52 @@ static av_cold int decode_init(AVCodecContext *avctx) return 0; } -static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, - int *got_frame, AVPacket *avpkt) +static int find_next_slice(AVCodecContext *avctx, + uint8_t *buf, uint8_t *buf_end, int idx, + uint8_t **pos, uint32_t *len) { - uint8_t *buf = avpkt->data; - int buf_size = avpkt->size; - FFV1Context *f = avctx->priv_data; - RangeCoder *const c = &f->slices[0].c; - int ret, key_frame; + FFV1Context *f = avctx->priv_data; + + /* Length field */ + uint32_t v = buf_end - buf; + if (idx || f->version > 2) { + /* Three bytes of length, plus flush bit + CRC */ + uint32_t trailer = 3 + 5*!!f->ec; + if (trailer > buf_end - buf) + v = INT_MAX; + else + v = AV_RB24(buf_end - trailer) + trailer; + } + + if (buf_end - buf < v) { + av_log(avctx, AV_LOG_ERROR, "Slice pointer chain broken\n"); + ff_progress_frame_report(&f->picture, INT_MAX); + return AVERROR_INVALIDDATA; + } + + *len = v; + if (idx) + *pos = buf_end - v; + else + *pos = buf; + + return 0; +} + +static int decode_header(AVCodecContext *avctx, RangeCoder *c, + uint8_t *buf, size_t buf_size) +{ + int ret; + FFV1Context *f = avctx->priv_data; + uint8_t keystate = 128; - uint8_t *buf_p; - AVFrame *p; - - ff_progress_frame_unref(&f->last_picture); - FFSWAP(ProgressFrame, f->picture, f->last_picture); - - - f->avctx = avctx; - f->frame_damaged = 0; ff_init_range_decoder(c, buf, buf_size); ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8); if (get_rac(c, &keystate)) { - key_frame = AV_FRAME_FLAG_KEY; + f->key_frame = AV_FRAME_FLAG_KEY; f->key_frame_ok = 0; - if ((ret = read_header(f)) < 0) + if ((ret = read_header(f, c)) < 0) return ret; f->key_frame_ok = 1; } else { @@ -892,7 +680,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, "Cannot decode non-keyframe without valid keyframe\n"); return AVERROR_INVALIDDATA; } - key_frame = 0; + f->key_frame = 0; } if (f->ac != AC_GOLOMB_RICE) { @@ -911,51 +699,36 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, return AVERROR_INVALIDDATA; } - ret = ff_progress_frame_get_buffer(avctx, &f->picture, - AV_GET_BUFFER_FLAG_REF); - if (ret < 0) - return ret; + return 0; +} - p = f->picture.f; +static int decode_slices(AVCodecContext *avctx, RangeCoder c, + AVPacket *avpkt) +{ + FFV1Context *f = avctx->priv_data; + AVFrame *p = f->picture.f; - p->pict_type = AV_PICTURE_TYPE_I; //FIXME I vs. P - p->flags = (p->flags & ~AV_FRAME_FLAG_KEY) | key_frame; + uint8_t *buf = avpkt->data; + size_t buf_size = avpkt->size; + uint8_t *buf_end = buf + buf_size; - if (f->version < 3 && avctx->field_order > AV_FIELD_PROGRESSIVE) { - /* we have interlaced material flagged in container */ - p->flags |= AV_FRAME_FLAG_INTERLACED; - if (avctx->field_order == AV_FIELD_TT || avctx->field_order == AV_FIELD_TB) - p->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; - } - - if (avctx->debug & FF_DEBUG_PICT_INFO) - av_log(avctx, AV_LOG_DEBUG, "ver:%d keyframe:%d coder:%d ec:%d slices:%d bps:%d\n", - f->version, !!(p->flags & AV_FRAME_FLAG_KEY), f->ac, f->ec, f->slice_count, f->avctx->bits_per_raw_sample); - - ff_thread_finish_setup(avctx); - - buf_p = buf + buf_size; for (int i = f->slice_count - 1; i >= 0; i--) { FFV1SliceContext *sc = &f->slices[i]; - int trailer = 3 + 5*!!f->ec; - int v; + + uint8_t *pos; + uint32_t len; + int err = find_next_slice(avctx, buf, buf_end, i, + &pos, &len); + if (err < 0) + return err; + + buf_end -= len; sc->slice_damaged = 0; - if (i || f->version > 2) { - if (trailer > buf_p - buf) v = INT_MAX; - else v = AV_RB24(buf_p-trailer) + trailer; - } else v = buf_p - c->bytestream_start; - if (buf_p - c->bytestream_start < v) { - av_log(avctx, AV_LOG_ERROR, "Slice pointer chain broken\n"); - ff_progress_frame_report(&f->picture, INT_MAX); - return AVERROR_INVALIDDATA; - } - buf_p -= v; - if (f->ec) { - unsigned crc = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, buf_p, v); - if (crc) { + unsigned crc = av_crc(av_crc_get_table(AV_CRC_32_IEEE), f->crcref, pos, len); + if (crc != f->crcref) { int64_t ts = avpkt->pts != AV_NOPTS_VALUE ? avpkt->pts : avpkt->dts; av_log(f->avctx, AV_LOG_ERROR, "slice CRC mismatch %X!", crc); if (ts != AV_NOPTS_VALUE && avctx->pkt_timebase.num) { @@ -968,16 +741,17 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, slice_set_damaged(f, sc); } if (avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(avctx, AV_LOG_DEBUG, "slice %d, CRC: 0x%08"PRIX32"\n", i, AV_RB32(buf_p + v - 4)); + av_log(avctx, AV_LOG_DEBUG, "slice %d, CRC: 0x%08"PRIX32"\n", i, AV_RB32(pos + len - 4)); } } if (i) { - ff_init_range_decoder(&sc->c, buf_p, v); + ff_init_range_decoder(&sc->c, pos, len); ff_build_rac_states(&sc->c, 0.05 * (1LL << 32), 256 - 8); - } else - sc->c.bytestream_end = buf_p + v; - + } else { + sc->c = c; + sc->c.bytestream_end = pos + len; + } } avctx->execute(avctx, @@ -990,7 +764,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, for (int i = f->slice_count - 1; i >= 0; i--) { FFV1SliceContext *sc = &f->slices[i]; if (sc->slice_damaged && f->last_picture.f) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(f->pix_fmt); const uint8_t *src[4]; uint8_t *dst[4]; ff_progress_frame_await(&f->last_picture, INT_MAX); @@ -1007,22 +781,125 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, av_image_copy(dst, p->linesize, src, f->last_picture.f->linesize, - avctx->pix_fmt, + f->pix_fmt, sc->slice_width, sc->slice_height); f->slice_damaged[i] = 1; } } + + return 0; +} + +static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, + int *got_frame, AVPacket *avpkt) +{ + FFV1Context *f = avctx->priv_data; + int ret; + AVFrame *p; + const FFHWAccel *hwaccel = NULL; + + /* This is copied onto the first slice's range coder context */ + RangeCoder c; + + ff_progress_frame_unref(&f->last_picture); + av_refstruct_unref(&f->hwaccel_last_picture_private); + + FFSWAP(ProgressFrame, f->picture, f->last_picture); + FFSWAP(void *, f->hwaccel_picture_private, f->hwaccel_last_picture_private); + + f->avctx = avctx; + f->frame_damaged = 0; + + ret = decode_header(avctx, &c, avpkt->data, avpkt->size); + if (ret < 0) + return ret; + + if (avctx->debug & FF_DEBUG_PICT_INFO) + av_log(avctx, AV_LOG_DEBUG, "ver:%d keyframe:%d coder:%d ec:%d slices:%d bps:%d\n", + f->version, !!f->key_frame, f->ac, f->ec, f->slice_count, f->avctx->bits_per_raw_sample); + + if (avctx->skip_frame >= AVDISCARD_ALL) + return avpkt->size; + + if (avctx->hwaccel) + hwaccel = ffhwaccel(avctx->hwaccel); + + ret = ff_progress_frame_get_buffer(avctx, &f->picture, + AV_GET_BUFFER_FLAG_REF); + if (ret < 0) + return ret; + + ret = ff_hwaccel_frame_priv_alloc(avctx, &f->hwaccel_picture_private); + if (ret < 0) + return ret; + + p = f->picture.f; + + p->pict_type = AV_PICTURE_TYPE_I; //FIXME I vs. P + p->flags = (p->flags & ~AV_FRAME_FLAG_KEY) | f->key_frame; + + if (f->version < 3 && avctx->field_order > AV_FIELD_PROGRESSIVE) { + /* we have interlaced material flagged in container */ + p->flags |= AV_FRAME_FLAG_INTERLACED; + if (avctx->field_order == AV_FIELD_TT || avctx->field_order == AV_FIELD_TB) + p->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; + } + + /* Start */ + if (hwaccel) { + ret = hwaccel->start_frame(avctx, avpkt->buf, avpkt->data, avpkt->size); + if (ret < 0) + return ret; + } + + ff_thread_finish_setup(avctx); + + /* Decode slices */ + if (hwaccel) { + uint8_t *buf_end = avpkt->data + avpkt->size; + + if (!(p->flags & AV_FRAME_FLAG_KEY) && f->last_picture.f) + ff_progress_frame_await(&f->last_picture, f->slice_count - 1); + + for (int i = f->slice_count - 1; i >= 0; i--) { + uint8_t *pos; + uint32_t len; + ret = find_next_slice(avctx, avpkt->data, buf_end, i, + &pos, &len); + if (ret < 0) + return ret; + + buf_end -= len; + + ret = hwaccel->decode_slice(avctx, pos, len); + if (ret < 0) + return ret; + } + } else { + ret = decode_slices(avctx, c, avpkt); + if (ret < 0) + return ret; + } + + /* Finalize */ + if (hwaccel) { + ret = hwaccel->end_frame(avctx); + if (ret < 0) + return ret; + } + ff_progress_frame_report(&f->picture, INT_MAX); ff_progress_frame_unref(&f->last_picture); + av_refstruct_unref(&f->hwaccel_last_picture_private); if ((ret = av_frame_ref(rframe, f->picture.f)) < 0) return ret; *got_frame = 1; - return buf_size; + return avpkt->size; } #if HAVE_THREADS @@ -1036,6 +913,7 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) fdst->version = fsrc->version; fdst->micro_version = fsrc->micro_version; + fdst->combined_version = fsrc->combined_version; fdst->chroma_planes = fsrc->chroma_planes; fdst->chroma_h_shift = fsrc->chroma_h_shift; fdst->chroma_v_shift = fsrc->chroma_v_shift; @@ -1043,6 +921,11 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) fdst->plane_count = fsrc->plane_count; fdst->ac = fsrc->ac; fdst->colorspace = fsrc->colorspace; + fdst->pix_fmt = fsrc->pix_fmt; + fdst->configured_pix_fmt = fsrc->configured_pix_fmt; + fdst->configured_ac = fsrc->configured_ac; + fdst->configured_width = fsrc->configured_width; + fdst->configured_height = fsrc->configured_height; fdst->ec = fsrc->ec; fdst->intra = fsrc->intra; @@ -1063,7 +946,7 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) FFV1SliceContext *sc = &fdst->slices[i]; const FFV1SliceContext *sc0 = &fsrc->slices[i]; - ff_refstruct_replace(&sc->plane, sc0->plane); + av_refstruct_replace(&sc->plane, sc0->plane); if (fsrc->version < 3) { sc->slice_x = sc0->slice_x; @@ -1073,11 +956,13 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) } } - ff_refstruct_replace(&fdst->slice_damaged, fsrc->slice_damaged); + av_refstruct_replace(&fdst->slice_damaged, fsrc->slice_damaged); av_assert1(fdst->max_slice_count == fsrc->max_slice_count); ff_progress_frame_replace(&fdst->picture, &fsrc->picture); + av_refstruct_replace(&fdst->hwaccel_picture_private, + fsrc->hwaccel_picture_private); return 0; } @@ -1088,9 +973,14 @@ static av_cold int ffv1_decode_close(AVCodecContext *avctx) FFV1Context *const s = avctx->priv_data; ff_progress_frame_unref(&s->picture); - ff_progress_frame_unref(&s->last_picture); + av_refstruct_unref(&s->hwaccel_picture_private); - return ff_ffv1_close(avctx); + ff_progress_frame_unref(&s->last_picture); + av_refstruct_unref(&s->hwaccel_last_picture_private); + + ff_ffv1_close(s); + + return 0; } const FFCodec ff_ffv1_decoder = { @@ -1106,5 +996,12 @@ const FFCodec ff_ffv1_decoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_USES_PROGRESSFRAMES, + .hw_configs = (const AVCodecHWConfigInternal *const []) { +#if CONFIG_FFV1_VULKAN_HWACCEL + HWACCEL_VULKAN(ffv1), +#endif + NULL + }, }; diff --git a/libavcodec/ffv1dec_template.c b/libavcodec/ffv1dec_template.c index 2da6bd935..b88195cfb 100644 --- a/libavcodec/ffv1dec_template.c +++ b/libavcodec/ffv1dec_template.c @@ -36,6 +36,12 @@ RENAME(decode_line)(FFV1Context *f, FFV1SliceContext *sc, int run_mode = 0; int run_index = sc->run_index; + if (bits == 0) { + for (x = 0; x < w; x++) + sample[1][x] = 0; + return 0; + } + if (is_input_end(c, gb, ac)) return AVERROR_INVALIDDATA; @@ -138,10 +144,15 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, int x, y, p; TYPE *sample[4][2]; int lbd = f->avctx->bits_per_raw_sample <= 8; - int bits = f->avctx->bits_per_raw_sample > 0 ? f->avctx->bits_per_raw_sample : 8; - int offset = 1 << bits; + int bits[4], offset; int transparency = f->transparency; int ac = f->ac; + unsigned mask[4]; + + ff_ffv1_compute_bits_per_plane(f, sc, bits, &offset, mask, f->avctx->bits_per_raw_sample); + + if (sc->slice_coding_mode == 1) + ac = 1; for (x = 0; x < 4; x++) { sample[x][0] = RENAME(sc->sample_buffer) + x * 2 * (w + 6) + 3; @@ -162,10 +173,10 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, sample[p][1][-1]= sample[p][0][0 ]; sample[p][0][ w]= sample[p][0][w-1]; - if (lbd && sc->slice_coding_mode == 0) + if (bits[p] == 9) ret = RENAME(decode_line)(f, sc, gb, w, sample[p], (p + 1)/2, 9, ac); else - ret = RENAME(decode_line)(f, sc, gb, w, sample[p], (p + 1)/2, bits + (sc->slice_coding_mode != 1), ac); + ret = RENAME(decode_line)(f, sc, gb, w, sample[p], (p + 1)/2, bits[p], ac); if (ret < 0) return ret; } @@ -182,10 +193,31 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, b += g; r += g; } + if (sc->remap) { + if (f->avctx->bits_per_raw_sample == 32) { + g = sc->fltmap32[0][g & mask[0]]; + b = sc->fltmap32[1][b & mask[1]]; + r = sc->fltmap32[2][r & mask[2]]; + if (transparency) + a = sc->fltmap32[3][a & mask[3]]; + } else { + g = sc->fltmap[0][g & mask[0]]; + b = sc->fltmap[1][b & mask[1]]; + r = sc->fltmap[2][r & mask[2]]; + if (transparency) + a = sc->fltmap[3][a & mask[3]]; + } + } - if (lbd) + if (lbd) { *((uint32_t*)(src[0] + x*4 + stride[0]*y)) = b + ((unsigned)g<<8) + ((unsigned)r<<16) + ((unsigned)a<<24); - else if (sizeof(TYPE) == 4 || transparency) { + } else if (f->avctx->bits_per_raw_sample == 32) { + *((uint32_t*)(src[0] + x*4 + stride[0]*y)) = g; + *((uint32_t*)(src[1] + x*4 + stride[1]*y)) = b; + *((uint32_t*)(src[2] + x*4 + stride[2]*y)) = r; + if (transparency) + *((uint32_t*)(src[3] + x*4 + stride[3]*y)) = a; + } else if (sizeof(TYPE) == 4 || transparency) { *((uint16_t*)(src[0] + x*2 + stride[0]*y)) = g; *((uint16_t*)(src[1] + x*2 + stride[1]*y)) = b; *((uint16_t*)(src[2] + x*2 + stride[2]*y)) = r; diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index 7b8ed7acc..b6d25013f 100644 --- a/libavcodec/ffv1enc.c +++ b/libavcodec/ffv1enc.c @@ -31,6 +31,7 @@ #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" +#include "libavutil/qsort.h" #include "avcodec.h" #include "encode.h" @@ -39,6 +40,7 @@ #include "put_golomb.h" #include "rangecoder.h" #include "ffv1.h" +#include "ffv1enc.h" static const int8_t quant5_10bit[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, @@ -248,7 +250,7 @@ static inline void put_vlc_symbol(PutBitContext *pb, VlcState *const state, i += i; } - av_assert2(k <= 13); + av_assert2(k <= 16); code = v ^ ((2 * state->drift + state->count) >> 31); @@ -271,15 +273,16 @@ static inline void put_vlc_symbol(PutBitContext *pb, VlcState *const state, static int encode_plane(FFV1Context *f, FFV1SliceContext *sc, const uint8_t *src, int w, int h, - int stride, int plane_index, int pixel_stride) + int stride, int plane_index, int remap_index, int pixel_stride, int ac) { int x, y, i, ret; - const int ac = f->ac; const int pass1 = !!(f->avctx->flags & AV_CODEC_FLAG_PASS1); const int ring_size = f->context_model ? 3 : 2; int16_t *sample[3]; sc->run_index = 0; + sample[2] = sc->sample_buffer; // dummy to avoid UB pointer arithmetic + memset(sc->sample_buffer, 0, ring_size * (w + 6) * sizeof(*sc->sample_buffer)); for (y = 0; y < h; y++) { @@ -288,21 +291,30 @@ static int encode_plane(FFV1Context *f, FFV1SliceContext *sc, sample[0][-1]= sample[1][0 ]; sample[1][ w]= sample[1][w-1]; + if (f->bits_per_raw_sample <= 8) { for (x = 0; x < w; x++) sample[0][x] = src[x * pixel_stride + stride * y]; + if (sc->remap) + for (x = 0; x < w; x++) + sample[0][x] = sc->fltmap[remap_index][ sample[0][x] ]; + if((ret = encode_line(f, sc, f->avctx, w, sample, plane_index, 8, ac, pass1)) < 0) return ret; } else { if (f->packed_at_lsb) { for (x = 0; x < w; x++) { - sample[0][x] = ((uint16_t*)(src + stride*y))[x]; + sample[0][x] = ((uint16_t*)(src + stride*y))[x * pixel_stride]; } } else { for (x = 0; x < w; x++) { - sample[0][x] = ((uint16_t*)(src + stride*y))[x] >> (16 - f->bits_per_raw_sample); + sample[0][x] = ((uint16_t*)(src + stride*y))[x * pixel_stride] >> (16 - f->bits_per_raw_sample); } } + if (sc->remap) + for (x = 0; x < w; x++) + sample[0][x] = sc->fltmap[remap_index][ (uint16_t)sample[0][x] ]; + if((ret = encode_line(f, sc, f->avctx, w, sample, plane_index, f->bits_per_raw_sample, ac, pass1)) < 0) return ret; } @@ -310,6 +322,30 @@ static int encode_plane(FFV1Context *f, FFV1SliceContext *sc, return 0; } +static void load_plane(FFV1Context *f, FFV1SliceContext *sc, + const uint8_t *src, int w, int h, + int stride, int remap_index, int pixel_stride) +{ + int x, y; + + memset(sc->fltmap[remap_index], 0, 65536 * sizeof(*sc->fltmap[remap_index])); + + for (y = 0; y < h; y++) { + if (f->bits_per_raw_sample <= 8) { + for (x = 0; x < w; x++) + sc->fltmap[remap_index][ src[x * pixel_stride + stride * y] ] = 1; + } else { + if (f->packed_at_lsb) { + for (x = 0; x < w; x++) + sc->fltmap[remap_index][ ((uint16_t*)(src + stride*y))[x * pixel_stride] ] = 1; + } else { + for (x = 0; x < w; x++) + sc->fltmap[remap_index][ ((uint16_t*)(src + stride*y))[x * pixel_stride] >> (16 - f->bits_per_raw_sample) ] = 1; + } + } + } +} + static void write_quant_table(RangeCoder *c, int16_t *quant_table) { int last = 0; @@ -392,8 +428,26 @@ static void write_header(FFV1Context *f) } } -static int write_extradata(FFV1Context *f) +static void set_micro_version(FFV1Context *f) { + f->combined_version = f->version << 16; + if (f->version > 2) { + if (f->version == 3) { + f->micro_version = 4; + } else if (f->version == 4) { + f->micro_version = 9; + } else + av_assert0(0); + + f->combined_version += f->micro_version; + } else + av_assert0(f->micro_version == 0); +} + +av_cold int ff_ffv1_write_extradata(AVCodecContext *avctx) +{ + FFV1Context *f = avctx->priv_data; + RangeCoder c; uint8_t state[CONTEXT_SIZE]; int i, j, k; @@ -412,13 +466,8 @@ static int write_extradata(FFV1Context *f) ff_build_rac_states(&c, 0.05 * (1LL << 32), 256 - 8); put_symbol(&c, state, f->version, 0); - if (f->version > 2) { - if (f->version == 3) { - f->micro_version = 4; - } else if (f->version == 4) - f->micro_version = 2; + if (f->version > 2) put_symbol(&c, state, f->micro_version, 0); - } put_symbol(&c, state, f->ac, 0); if (f->ac == AC_RANGE_CUSTOM_TAB) @@ -458,7 +507,7 @@ static int write_extradata(FFV1Context *f) } f->avctx->extradata_size = ff_rac_terminate(&c, 0); - v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, f->avctx->extradata, f->avctx->extradata_size); + v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), f->crcref, f->avctx->extradata, f->avctx->extradata_size) ^ (f->crcref ? 0x8CD88196 : 0); AV_WL32(f->avctx->extradata + f->avctx->extradata_size, v); f->avctx->extradata_size += 4; @@ -513,17 +562,47 @@ static int sort_stt(FFV1Context *s, uint8_t stt[256]) return print; } -static av_cold int encode_init(AVCodecContext *avctx) + +int ff_ffv1_encode_determine_slices(AVCodecContext *avctx) +{ + FFV1Context *s = avctx->priv_data; + int plane_count = 1 + 2*s->chroma_planes + s->transparency; + int max_h_slices = AV_CEIL_RSHIFT(avctx->width , s->chroma_h_shift); + int max_v_slices = AV_CEIL_RSHIFT(avctx->height, s->chroma_v_shift); + s->num_v_slices = (avctx->width > 352 || avctx->height > 288 || !avctx->slices) ? 2 : 1; + s->num_v_slices = FFMIN(s->num_v_slices, max_v_slices); + for (; s->num_v_slices <= 32; s->num_v_slices++) { + for (s->num_h_slices = s->num_v_slices; s->num_h_slices <= 2*s->num_v_slices; s->num_h_slices++) { + int maxw = (avctx->width + s->num_h_slices - 1) / s->num_h_slices; + int maxh = (avctx->height + s->num_v_slices - 1) / s->num_v_slices; + if (s->num_h_slices > max_h_slices || s->num_v_slices > max_v_slices) + continue; + if (maxw * maxh * (int64_t)(s->bits_per_raw_sample+1) * plane_count > 8<<24) + continue; + if (s->version < 4) + if ( ff_need_new_slices(avctx->width , s->num_h_slices, s->chroma_h_shift) + ||ff_need_new_slices(avctx->height, s->num_v_slices, s->chroma_v_shift)) + continue; + if (avctx->slices == s->num_h_slices * s->num_v_slices && avctx->slices <= MAX_SLICES) + return 0; + if (maxw*maxh > 360*288) + continue; + if (!avctx->slices) + return 0; + } + } + av_log(avctx, AV_LOG_ERROR, + "Unsupported number %d of slices requested, please specify a " + "supported number with -slices (ex:4,6,9,12,16, ...)\n", + avctx->slices); + return AVERROR(ENOSYS); +} + +av_cold int ff_ffv1_encode_init(AVCodecContext *avctx) { FFV1Context *s = avctx->priv_data; - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); int i, j, k, m, ret; - if ((ret = ff_ffv1_common_init(avctx)) < 0) - return ret; - - s->version = 0; - if ((avctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) || avctx->slices > 1) s->version = FFMAX(s->version, 2); @@ -546,168 +625,31 @@ static av_cold int encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } s->version = avctx->level; - } + } else if (s->version < 3) + s->version = 3; if (s->ec < 0) { - s->ec = (s->version >= 3); + if (s->version >= 4) { + s->ec = 2; + } else if (s->version >= 3) { + s->ec = 1; + } else + s->ec = 0; } // CRC requires version 3+ - if (s->ec) + if (s->ec == 1) s->version = FFMAX(s->version, 3); + if (s->ec == 2) { + s->version = FFMAX(s->version, 4); + s->crcref = 0x7a8c4079; + } if ((s->version == 2 || s->version>3) && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { av_log(avctx, AV_LOG_ERROR, "Version 2 or 4 needed for requested features but version 2 or 4 is experimental and not enabled\n"); return AVERROR_INVALIDDATA; } - if (s->ac == 1) // Compatbility with common command line usage - s->ac = AC_RANGE_CUSTOM_TAB; - else if (s->ac == AC_RANGE_DEFAULT_TAB_FORCE) - s->ac = AC_RANGE_DEFAULT_TAB; - - s->plane_count = 3; - switch(avctx->pix_fmt) { - case AV_PIX_FMT_GRAY9: - case AV_PIX_FMT_YUV444P9: - case AV_PIX_FMT_YUV422P9: - case AV_PIX_FMT_YUV420P9: - case AV_PIX_FMT_YUVA444P9: - case AV_PIX_FMT_YUVA422P9: - case AV_PIX_FMT_YUVA420P9: - if (!avctx->bits_per_raw_sample) - s->bits_per_raw_sample = 9; - case AV_PIX_FMT_GRAY10: - case AV_PIX_FMT_YUV444P10: - case AV_PIX_FMT_YUV440P10: - case AV_PIX_FMT_YUV420P10: - case AV_PIX_FMT_YUV422P10: - case AV_PIX_FMT_YUVA444P10: - case AV_PIX_FMT_YUVA422P10: - case AV_PIX_FMT_YUVA420P10: - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) - s->bits_per_raw_sample = 10; - case AV_PIX_FMT_GRAY12: - case AV_PIX_FMT_YUV444P12: - case AV_PIX_FMT_YUV440P12: - case AV_PIX_FMT_YUV420P12: - case AV_PIX_FMT_YUV422P12: - case AV_PIX_FMT_YUVA444P12: - case AV_PIX_FMT_YUVA422P12: - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) - s->bits_per_raw_sample = 12; - case AV_PIX_FMT_GRAY14: - case AV_PIX_FMT_YUV444P14: - case AV_PIX_FMT_YUV420P14: - case AV_PIX_FMT_YUV422P14: - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) - s->bits_per_raw_sample = 14; - s->packed_at_lsb = 1; - case AV_PIX_FMT_GRAY16: - case AV_PIX_FMT_YUV444P16: - case AV_PIX_FMT_YUV422P16: - case AV_PIX_FMT_YUV420P16: - case AV_PIX_FMT_YUVA444P16: - case AV_PIX_FMT_YUVA422P16: - case AV_PIX_FMT_YUVA420P16: - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) { - s->bits_per_raw_sample = 16; - } else if (!s->bits_per_raw_sample) { - s->bits_per_raw_sample = avctx->bits_per_raw_sample; - } - if (s->bits_per_raw_sample <= 8) { - av_log(avctx, AV_LOG_ERROR, "bits_per_raw_sample invalid\n"); - return AVERROR_INVALIDDATA; - } - s->version = FFMAX(s->version, 1); - case AV_PIX_FMT_GRAY8: - case AV_PIX_FMT_YA8: - case AV_PIX_FMT_YUV444P: - case AV_PIX_FMT_YUV440P: - case AV_PIX_FMT_YUV422P: - case AV_PIX_FMT_YUV420P: - case AV_PIX_FMT_YUV411P: - case AV_PIX_FMT_YUV410P: - case AV_PIX_FMT_YUVA444P: - case AV_PIX_FMT_YUVA422P: - case AV_PIX_FMT_YUVA420P: - s->chroma_planes = desc->nb_components < 3 ? 0 : 1; - s->colorspace = 0; - s->transparency = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) - s->bits_per_raw_sample = 8; - else if (!s->bits_per_raw_sample) - s->bits_per_raw_sample = 8; - break; - case AV_PIX_FMT_RGB32: - s->colorspace = 1; - s->transparency = 1; - s->chroma_planes = 1; - s->bits_per_raw_sample = 8; - break; - case AV_PIX_FMT_RGBA64: - s->colorspace = 1; - s->transparency = 1; - s->chroma_planes = 1; - s->bits_per_raw_sample = 16; - s->use32bit = 1; - s->version = FFMAX(s->version, 1); - break; - case AV_PIX_FMT_RGB48: - s->colorspace = 1; - s->chroma_planes = 1; - s->bits_per_raw_sample = 16; - s->use32bit = 1; - s->version = FFMAX(s->version, 1); - break; - case AV_PIX_FMT_0RGB32: - s->colorspace = 1; - s->chroma_planes = 1; - s->bits_per_raw_sample = 8; - break; - case AV_PIX_FMT_GBRP9: - if (!avctx->bits_per_raw_sample) - s->bits_per_raw_sample = 9; - case AV_PIX_FMT_GBRP10: - case AV_PIX_FMT_GBRAP10: - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) - s->bits_per_raw_sample = 10; - case AV_PIX_FMT_GBRP12: - case AV_PIX_FMT_GBRAP12: - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) - s->bits_per_raw_sample = 12; - case AV_PIX_FMT_GBRP14: - case AV_PIX_FMT_GBRAP14: - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) - s->bits_per_raw_sample = 14; - case AV_PIX_FMT_GBRP16: - case AV_PIX_FMT_GBRAP16: - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) - s->bits_per_raw_sample = 16; - else if (!s->bits_per_raw_sample) - s->bits_per_raw_sample = avctx->bits_per_raw_sample; - s->transparency = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); - s->colorspace = 1; - s->chroma_planes = 1; - if (s->bits_per_raw_sample >= 16) { - s->use32bit = 1; - } - s->version = FFMAX(s->version, 1); - break; - default: - av_log(avctx, AV_LOG_ERROR, "format not supported\n"); - return AVERROR(ENOSYS); - } - av_assert0(s->bits_per_raw_sample >= 8); - - if (s->bits_per_raw_sample > 8) { - if (s->ac == AC_GOLOMB_RICE) { - av_log(avctx, AV_LOG_INFO, - "bits_per_raw_sample > 8, forcing range coder\n"); - s->ac = AC_RANGE_CUSTOM_TAB; - } - } - if (s->ac == AC_RANGE_CUSTOM_TAB) { for (i = 1; i < 256; i++) s->state_transition[i] = ver2_state[i]; @@ -718,9 +660,9 @@ static av_cold int encode_init(AVCodecContext *avctx) s->state_transition[i] = c.one_state[i]; } - for (i = 0; i < MAX_QUANT_TABLE_SIZE; i++) { + for (i = 0; i < 256; i++) { s->quant_table_count = 2; - if (s->bits_per_raw_sample <= 8) { + if ((s->qtable == -1 && s->bits_per_raw_sample <= 8) || s->qtable == 1) { s->quant_tables[0][0][i]= quant11[i]; s->quant_tables[0][1][i]= 11*quant11[i]; s->quant_tables[0][2][i]= 11*11*quant11[i]; @@ -753,10 +695,6 @@ static av_cold int encode_init(AVCodecContext *avctx) if (!s->chroma_planes && s->version > 3) s->plane_count--; - ret = av_pix_fmt_get_chroma_sub_sample (avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift); - if (ret) - return ret; - s->picture_number = 0; if (avctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) { @@ -849,37 +787,228 @@ static av_cold int encode_init(AVCodecContext *avctx) av_freep(&best_state); } - if (s->version > 1) { - int plane_count = 1 + 2*s->chroma_planes + s->transparency; - int max_h_slices = AV_CEIL_RSHIFT(avctx->width , s->chroma_h_shift); - int max_v_slices = AV_CEIL_RSHIFT(avctx->height, s->chroma_v_shift); - s->num_v_slices = (avctx->width > 352 || avctx->height > 288 || !avctx->slices) ? 2 : 1; + if (s->version <= 1) { + /* Disable slices when the version doesn't support them */ + s->num_h_slices = 1; + s->num_v_slices = 1; + } - s->num_v_slices = FFMIN(s->num_v_slices, max_v_slices); + set_micro_version(s); - for (; s->num_v_slices < 32; s->num_v_slices++) { - for (s->num_h_slices = s->num_v_slices; s->num_h_slices < 2*s->num_v_slices; s->num_h_slices++) { - int maxw = (avctx->width + s->num_h_slices - 1) / s->num_h_slices; - int maxh = (avctx->height + s->num_v_slices - 1) / s->num_v_slices; - if (s->num_h_slices > max_h_slices || s->num_v_slices > max_v_slices) - continue; - if (maxw * maxh * (int64_t)(s->bits_per_raw_sample+1) * plane_count > 8<<24) - continue; - if (s->version < 4) - if ( ff_need_new_slices(avctx->width , s->num_h_slices, s->chroma_h_shift) - ||ff_need_new_slices(avctx->height, s->num_v_slices, s->chroma_v_shift)) - continue; - if (avctx->slices == s->num_h_slices * s->num_v_slices && avctx->slices <= MAX_SLICES || !avctx->slices) - goto slices_ok; - } + return 0; +} + +av_cold int ff_ffv1_encode_setup_plane_info(AVCodecContext *avctx, + enum AVPixelFormat pix_fmt) +{ + FFV1Context *s = avctx->priv_data; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + + s->plane_count = 3; + switch(pix_fmt) { + case AV_PIX_FMT_GRAY9: + case AV_PIX_FMT_YUV444P9: + case AV_PIX_FMT_YUV422P9: + case AV_PIX_FMT_YUV420P9: + case AV_PIX_FMT_YUVA444P9: + case AV_PIX_FMT_YUVA422P9: + case AV_PIX_FMT_YUVA420P9: + if (!avctx->bits_per_raw_sample) + s->bits_per_raw_sample = 9; + case AV_PIX_FMT_GRAY10: + case AV_PIX_FMT_YUV444P10: + case AV_PIX_FMT_YUV440P10: + case AV_PIX_FMT_YUV420P10: + case AV_PIX_FMT_YUV422P10: + case AV_PIX_FMT_YUVA444P10: + case AV_PIX_FMT_YUVA422P10: + case AV_PIX_FMT_YUVA420P10: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 10; + case AV_PIX_FMT_GRAY12: + case AV_PIX_FMT_YUV444P12: + case AV_PIX_FMT_YUV440P12: + case AV_PIX_FMT_YUV420P12: + case AV_PIX_FMT_YUV422P12: + case AV_PIX_FMT_YUVA444P12: + case AV_PIX_FMT_YUVA422P12: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 12; + case AV_PIX_FMT_GRAY14: + case AV_PIX_FMT_YUV444P14: + case AV_PIX_FMT_YUV420P14: + case AV_PIX_FMT_YUV422P14: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 14; + s->packed_at_lsb = 1; + case AV_PIX_FMT_GRAY16: + case AV_PIX_FMT_P016: + case AV_PIX_FMT_P216: + case AV_PIX_FMT_P416: + case AV_PIX_FMT_YUV444P16: + case AV_PIX_FMT_YUV422P16: + case AV_PIX_FMT_YUV420P16: + case AV_PIX_FMT_YUVA444P16: + case AV_PIX_FMT_YUVA422P16: + case AV_PIX_FMT_YUVA420P16: + case AV_PIX_FMT_GRAYF16: + case AV_PIX_FMT_YAF16: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) { + s->bits_per_raw_sample = 16; + } else if (!s->bits_per_raw_sample) { + s->bits_per_raw_sample = avctx->bits_per_raw_sample; } - av_log(avctx, AV_LOG_ERROR, - "Unsupported number %d of slices requested, please specify a " - "supported number with -slices (ex:4,6,9,12,16, ...)\n", - avctx->slices); + if (s->bits_per_raw_sample <= 8) { + av_log(avctx, AV_LOG_ERROR, "bits_per_raw_sample invalid\n"); + return AVERROR_INVALIDDATA; + } + s->version = FFMAX(s->version, 1); + case AV_PIX_FMT_GRAY8: + case AV_PIX_FMT_YA8: + case AV_PIX_FMT_NV12: + case AV_PIX_FMT_NV16: + case AV_PIX_FMT_NV24: + case AV_PIX_FMT_YUV444P: + case AV_PIX_FMT_YUV440P: + case AV_PIX_FMT_YUV422P: + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUV411P: + case AV_PIX_FMT_YUV410P: + case AV_PIX_FMT_YUVA444P: + case AV_PIX_FMT_YUVA422P: + case AV_PIX_FMT_YUVA420P: + s->chroma_planes = desc->nb_components < 3 ? 0 : 1; + s->colorspace = 0; + s->transparency = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 8; + else if (!s->bits_per_raw_sample) + s->bits_per_raw_sample = 8; + break; + case AV_PIX_FMT_RGB32: + s->colorspace = 1; + s->transparency = 1; + s->chroma_planes = 1; + s->bits_per_raw_sample = 8; + break; + case AV_PIX_FMT_RGBA64: + s->colorspace = 1; + s->transparency = 1; + s->chroma_planes = 1; + s->bits_per_raw_sample = 16; + s->use32bit = 1; + s->version = FFMAX(s->version, 1); + break; + case AV_PIX_FMT_RGB48: + s->colorspace = 1; + s->chroma_planes = 1; + s->bits_per_raw_sample = 16; + s->use32bit = 1; + s->version = FFMAX(s->version, 1); + break; + case AV_PIX_FMT_GBRP: + case AV_PIX_FMT_0RGB32: + s->colorspace = 1; + s->chroma_planes = 1; + s->bits_per_raw_sample = 8; + break; + case AV_PIX_FMT_GBRP9: + if (!avctx->bits_per_raw_sample) + s->bits_per_raw_sample = 9; + case AV_PIX_FMT_X2BGR10: + case AV_PIX_FMT_X2RGB10: + case AV_PIX_FMT_GBRP10: + case AV_PIX_FMT_GBRAP10: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 10; + case AV_PIX_FMT_GBRP12: + case AV_PIX_FMT_GBRAP12: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 12; + case AV_PIX_FMT_GBRP14: + case AV_PIX_FMT_GBRAP14: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 14; + case AV_PIX_FMT_GBRP16: + case AV_PIX_FMT_GBRAP16: + case AV_PIX_FMT_GBRPF16: + case AV_PIX_FMT_GBRAPF16: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 16; + case AV_PIX_FMT_GBRPF32: + case AV_PIX_FMT_GBRAPF32: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 32; + else if (!s->bits_per_raw_sample) + s->bits_per_raw_sample = avctx->bits_per_raw_sample; + s->transparency = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); + s->colorspace = 1; + s->chroma_planes = 1; + if (s->bits_per_raw_sample >= 16) { + s->use32bit = 1; + } + s->version = FFMAX(s->version, 1); + break; + default: + av_log(avctx, AV_LOG_ERROR, "format %s not supported\n", + av_get_pix_fmt_name(pix_fmt)); return AVERROR(ENOSYS); -slices_ok: - if ((ret = write_extradata(s)) < 0) + } + s->flt = !!(desc->flags & AV_PIX_FMT_FLAG_FLOAT); + if (s->flt || s->remap_mode > 0) + s->version = FFMAX(s->version, 4); + av_assert0(s->bits_per_raw_sample >= 8); + + if (s->remap_mode < 0) + s->remap_mode = s->flt ? 2 : 0; + if (s->remap_mode == 0 && s->bits_per_raw_sample == 32) { + av_log(avctx, AV_LOG_ERROR, "32bit requires remap\n"); + return AVERROR(EINVAL); + } + if (s->remap_mode == 2 && + !((s->bits_per_raw_sample == 16 || s->bits_per_raw_sample == 32 || s->bits_per_raw_sample == 64) && s->flt)) { + av_log(avctx, AV_LOG_ERROR, "remap 2 is for float16/32/64 only\n"); + return AVERROR(EINVAL); + } + + return av_pix_fmt_get_chroma_sub_sample(pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift); +} + +static av_cold int encode_init_internal(AVCodecContext *avctx) +{ + int ret; + FFV1Context *s = avctx->priv_data; + + if ((ret = ff_ffv1_common_init(avctx, s)) < 0) + return ret; + + if (s->ac == 1) // Compatibility with common command line usage + s->ac = AC_RANGE_CUSTOM_TAB; + else if (s->ac == AC_RANGE_DEFAULT_TAB_FORCE) + s->ac = AC_RANGE_DEFAULT_TAB; + + ret = ff_ffv1_encode_setup_plane_info(avctx, avctx->pix_fmt); + if (ret < 0) + return ret; + + if (s->bits_per_raw_sample > (s->version > 3 ? 16 : 8) && !s->remap_mode) { + if (s->ac == AC_GOLOMB_RICE) { + av_log(avctx, AV_LOG_INFO, + "high bits_per_raw_sample, forcing range coder\n"); + s->ac = AC_RANGE_CUSTOM_TAB; + } + } + + + ret = ff_ffv1_encode_init(avctx); + if (ret < 0) + return ret; + + if (s->version > 1) { + if ((ret = ff_ffv1_encode_determine_slices(avctx)) < 0) + return ret; + + if ((ret = ff_ffv1_write_extradata(avctx)) < 0) return ret; } @@ -888,14 +1017,35 @@ slices_ok: s->slice_count = s->max_slice_count; for (int j = 0; j < s->slice_count; j++) { + FFV1SliceContext *sc = &s->slices[j]; + for (int i = 0; i < s->plane_count; i++) { PlaneContext *const p = &s->slices[j].plane[i]; p->quant_table_index = s->context_model; p->context_count = s->context_count[p->quant_table_index]; } + av_assert0(s->remap_mode >= 0); + if (s->remap_mode) { + for (int p = 0; p < 1 + 2*s->chroma_planes + s->transparency ; p++) { + if (s->bits_per_raw_sample == 32) { + sc->unit[p] = av_malloc_array(sc->slice_width, sc->slice_height * sizeof(**sc->unit)); + if (!sc->unit[p]) + return AVERROR(ENOMEM); + sc->bitmap[p] = av_malloc_array(sc->slice_width * sc->slice_height, sizeof(*sc->bitmap[p])); + if (!sc->bitmap[p]) + return AVERROR(ENOMEM); + } else { + sc->fltmap[p] = av_malloc_array(65536, sizeof(*sc->fltmap[p])); + if (!sc->fltmap[p]) + return AVERROR(ENOMEM); + } + } + } ff_build_rac_states(&s->slices[j].c, 0.05 * (1LL << 32), 256 - 8); + + s->slices[j].remap = s->remap_mode; } if ((ret = ff_ffv1_init_slices_state(s)) < 0) @@ -906,8 +1056,8 @@ slices_ok: avctx->stats_out = av_mallocz(STATS_OUT_SIZE); if (!avctx->stats_out) return AVERROR(ENOMEM); - for (i = 0; i < s->quant_table_count; i++) - for (j = 0; j < s->max_slice_count; j++) { + for (int i = 0; i < s->quant_table_count; i++) + for (int j = 0; j < s->max_slice_count; j++) { FFV1SliceContext *sc = &s->slices[j]; av_assert0(!sc->rc_stat2[i]); sc->rc_stat2[i] = av_mallocz(s->context_count[i] * @@ -950,6 +1100,7 @@ static void encode_slice_header(FFV1Context *f, FFV1SliceContext *sc) put_symbol(c, state, sc->slice_rct_by_coef, 0); put_symbol(c, state, sc->slice_rct_ry_coef, 0); } + put_symbol(c, state, sc->remap, 0); } } @@ -1048,6 +1199,367 @@ static void choose_rct_params(const FFV1Context *f, FFV1SliceContext *sc, sc->slice_rct_ry_coef = rct_y_coeff[best][0]; } +static void encode_histogram_remap(FFV1Context *f, FFV1SliceContext *sc) +{ + int len = 1 << f->bits_per_raw_sample; + int flip = sc->remap == 2 ? 0x7FFF : 0; + + for (int p= 0; p < 1 + 2*f->chroma_planes + f->transparency; p++) { + int j = 0; + int lu = 0; + uint8_t state[2][32]; + int run = 0; + + memset(state, 128, sizeof(state)); + put_symbol(&sc->c, state[0], 0, 0); + memset(state, 128, sizeof(state)); + for (int i= 0; ifltmap[p][ri]; + sc->fltmap[p][ri] = j; + j+= u; + + if (lu == u) { + run ++; + } else { + put_symbol_inline(&sc->c, state[lu], run, 0, NULL, NULL); + if (run == 0) + lu = u; + run = 0; + } + } + if (run) + put_symbol(&sc->c, state[lu], run, 0); + sc->remap_count[p] = j; + } +} + +static void load_rgb_float32_frame(FFV1Context *f, FFV1SliceContext *sc, + const uint8_t *src[4], + int w, int h, const int stride[4]) +{ + int x, y; + int transparency = f->transparency; + int i = 0; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + int b, g, r, av_uninit(a); + + g = *((const uint32_t *)(src[0] + x*4 + stride[0]*y)); + b = *((const uint32_t *)(src[1] + x*4 + stride[1]*y)); + r = *((const uint32_t *)(src[2] + x*4 + stride[2]*y)); + if (transparency) + a = *((const uint32_t *)(src[3] + x*4 + stride[3]*y)); + + if (sc->remap == 2) { +#define FLIP(f) (((f)&0x80000000) ? (f) : (f)^0x7FFFFFFF); + g = FLIP(g); + b = FLIP(b); + r = FLIP(r); + } + // We cannot build a histogram as we do for 16bit, we need a bit of magic here + // Its possible to reduce the memory needed at the cost of more dereferencing + sc->unit[0][i].val = g; + sc->unit[0][i].ndx = x + y*w; + + sc->unit[1][i].val = b; + sc->unit[1][i].ndx = x + y*w; + + sc->unit[2][i].val = r; + sc->unit[2][i].ndx = x + y*w; + + if (transparency) { + sc->unit[3][i].val = a; + sc->unit[3][i].ndx = x + y*w; + } + i++; + } + } + + //TODO switch to radix sort +#define CMP(A,B) ((A)->val - (int64_t)(B)->val) + AV_QSORT(sc->unit[0], i, struct Unit, CMP); + AV_QSORT(sc->unit[1], i, struct Unit, CMP); + AV_QSORT(sc->unit[2], i, struct Unit, CMP); + if (transparency) + AV_QSORT(sc->unit[3], i, struct Unit, CMP); +} + +static int encode_float32_remap_segment(FFV1SliceContext *sc, + int p, int mul_count, int *mul_tab, int update, int final) +{ + const int pixel_num = sc->slice_width * sc->slice_height; + uint8_t state[2][3][32]; + int mul[4096+1]; + RangeCoder rc = sc->c; + int lu = 0; + int run = 0; + int64_t last_val = -1; + int compact_index = -1; + int i = 0; + int current_mul_index = -1; + int run1final = 0; + int run1start_i; + int run1start_last_val; + int run1start_mul_index; + + memcpy(mul, mul_tab, sizeof(*mul_tab)*(mul_count+1)); + memset(state, 128, sizeof(state)); + put_symbol(&rc, state[0][0], mul_count, 0); + memset(state, 128, sizeof(state)); + + for (; i < pixel_num+1; i++) { + int current_mul = current_mul_index < 0 ? 1 : FFABS(mul[current_mul_index]); + int64_t val; + if (i == pixel_num) { + if (last_val == 0xFFFFFFFF && (!run || run1final)) { + break; + } else { + val = last_val + ((1LL<<32) - last_val + current_mul - 1) / current_mul * current_mul; + av_assert2(val >= (1LL<<32)); + val += lu * current_mul; //ensure a run1 ends + } + } else + val = sc->unit[p][i].val; + + if (last_val != val) { + int64_t delta = val - last_val; + int64_t step = FFMAX(1, (delta + current_mul/2) / current_mul); + av_assert2(last_val < val); + av_assert2(current_mul > 0); + + delta -= step*current_mul; + av_assert2(delta <= current_mul/2); + av_assert2(delta > -current_mul); + + av_assert2(step > 0); + if (lu) { + if (!run) { + run1start_i = i - 1; + run1start_last_val = last_val; + run1start_mul_index= current_mul_index; + } + if (step == 1) { + if (run1final) { + if (current_mul>1) + put_symbol_inline(&rc, state[lu][1], delta, 1, NULL, NULL); + } + run ++; + av_assert2(last_val + current_mul + delta == val); + } else { + if (run1final) { + if (run == 0) + lu ^= 1; + i--; // we did not encode val so we need to backstep + last_val += current_mul; + } else { + put_symbol_inline(&rc, state[lu][0], run, 0, NULL, NULL); + i = run1start_i; + last_val = run1start_last_val; // we could compute this instead of storing + current_mul_index = run1start_mul_index; + } + run1final ^= 1; + + run = 0; + continue; + } + } else { + av_assert2(run == 0); + av_assert2(run1final == 0); + put_symbol_inline(&rc, state[lu][0], step - 1, 0, NULL, NULL); + + if (current_mul > 1) + put_symbol_inline(&rc, state[lu][1], delta, 1, NULL, NULL); + if (step == 1) + lu ^= 1; + + av_assert2(last_val + step * current_mul + delta == val); + } + last_val = val; + current_mul_index = ((last_val + 1) * mul_count) >> 32; + if (!run || run1final) { + av_assert2(mul[ current_mul_index ]); + if (mul[ current_mul_index ] < 0) { + av_assert2(i < pixel_num); + mul[ current_mul_index ] *= -1; + put_symbol_inline(&rc, state[0][2], mul[ current_mul_index ], 0, NULL, NULL); + } + if (i < pixel_num) + compact_index ++; + } + } + if (!run || run1final) + if (final && i < pixel_num) + sc->bitmap[p][sc->unit[p][i].ndx] = compact_index; + } + + if (update) { + sc->c = rc; + sc->remap_count[p] = compact_index + 1; + } + return get_rac_count(&rc); +} + +static void encode_float32_remap(FFV1Context *f, FFV1SliceContext *sc, + const uint8_t *src[4]) +{ + int pixel_num = sc->slice_width * sc->slice_height; + const int max_log2_mul_count = ((int[]){ 1, 1, 1, 9, 9, 10})[f->remap_optimizer]; + const int log2_mul_count_step = ((int[]){ 1, 1, 1, 9, 9, 1})[f->remap_optimizer]; + const int max_log2_mul = ((int[]){ 1, 8, 8, 9, 22, 22})[f->remap_optimizer]; + const int log2_mul_step = ((int[]){ 1, 8, 1, 1, 1, 1})[f->remap_optimizer]; + const int bruteforce_count = ((int[]){ 0, 0, 0, 1, 1, 1})[f->remap_optimizer]; + const int stair_mode = ((int[]){ 0, 0, 0, 1, 0, 0})[f->remap_optimizer]; + const int magic_log2 = ((int[]){ 1, 1, 1, 1, 0, 0})[f->remap_optimizer]; + + for (int p= 0; p < 1 + 2*f->chroma_planes + f->transparency; p++) { + int best_log2_mul_count = 0; + float score_sum[11] = {0}; + int mul_all[11][1025]; + + for (int log2_mul_count= 0; log2_mul_count <= max_log2_mul_count; log2_mul_count += log2_mul_count_step) { + float score_tab_all[1025][23] = {0}; + int64_t last_val = -1; + int *mul_tab = mul_all[log2_mul_count]; + int last_mul_index = -1; + int mul_count = 1 << log2_mul_count; + + score_sum[log2_mul_count] = 2 * log2_mul_count; + if (magic_log2) + score_sum[log2_mul_count] = av_float2int((float)mul_count * mul_count); + for (int i= 0; iunit[p][i].val; + int mul_index = (val + 1LL)*mul_count >> 32; + if (val != last_val) { + float *score_tab = score_tab_all[(last_val + 1LL)*mul_count >> 32]; + av_assert2(last_val < val); + for(int si= 0; si <= max_log2_mul; si += log2_mul_step) { + int64_t delta = val - last_val; + int mul; + int64_t cost; + + if (last_val < 0) { + mul = 1; + } else if (stair_mode && mul_count == 512 && si == max_log2_mul ) { + if (mul_index >= 0x378/8 && mul_index <= 23 + 0x378/8) { + mul = (0x800080 >> (mul_index - 0x378/8)); + } else + mul = 1; + } else { + mul = (0x10001LL)<> 16; + } + + cost = FFMAX((delta + mul/2) / mul, 1); + float score = 1; + if (mul > 1) { + score *= (FFABS(delta - cost*mul)+1); + if (mul_count > 1) + score *= score; + } + score *= cost; + score *= score; + if (mul_index != last_mul_index) + score *= mul; + if (magic_log2) { + score_tab[si] += av_float2int(score); + } else + score_tab[si] += log2f(score); + } + } + last_val = val; + last_mul_index = mul_index; + } + for(int i= 0; i= 0x378/8 && i <= 23 + 0x378/8) { + mul_tab[i] = -(0x800080 >> (i - 0x378/8)); + } else + mul_tab[i] = -1; + } else + mul_tab[i] = -((0x10001LL)<> 16); + score_sum[log2_mul_count] += score_tab[ best_index ]; + } + mul_tab[mul_count] = 1; + + if (bruteforce_count) + score_sum[log2_mul_count] = encode_float32_remap_segment(sc, p, mul_count, mul_all[log2_mul_count], 0, 0); + + if (score_sum[log2_mul_count] < score_sum[best_log2_mul_count]) + best_log2_mul_count = log2_mul_count; + } + + encode_float32_remap_segment(sc, p, 1<context_model ? 3 : 2; + int32_t *sample[4][3]; + const int pass1 = !!(f->avctx->flags & AV_CODEC_FLAG_PASS1); + int bits[4], offset; + int transparency = f->transparency; + + ff_ffv1_compute_bits_per_plane(f, sc, bits, &offset, NULL, f->bits_per_raw_sample); + + sc->run_index = 0; + + for (int p = 0; p < MAX_PLANES; ++p) + sample[p][2] = sc->sample_buffer32; // dummy to avoid UB pointer arithmetic + + memset(RENAME(sc->sample_buffer), 0, ring_size * MAX_PLANES * + (w + 6) * sizeof(*RENAME(sc->sample_buffer))); + + for (y = 0; y < h; y++) { + for (i = 0; i < ring_size; i++) + for (p = 0; p < MAX_PLANES; p++) + sample[p][i]= RENAME(sc->sample_buffer) + p*ring_size*(w+6) + ((h+i-y)%ring_size)*(w+6) + 3; + + for (x = 0; x < w; x++) { + int b, g, r, av_uninit(a); + g = sc->bitmap[0][x + w*y]; + b = sc->bitmap[1][x + w*y]; + r = sc->bitmap[2][x + w*y]; + if (transparency) + a = sc->bitmap[3][x + w*y]; + + if (sc->slice_coding_mode != 1) { + b -= g; + r -= g; + g += (b * sc->slice_rct_by_coef + r * sc->slice_rct_ry_coef) >> 2; + b += offset; + r += offset; + } + + sample[0][0][x] = g; + sample[1][0][x] = b; + sample[2][0][x] = r; + sample[3][0][x] = a; + } + for (p = 0; p < 3 + transparency; p++) { + int ret; + sample[p][0][-1] = sample[p][1][0 ]; + sample[p][1][ w] = sample[p][1][w-1]; + ret = encode_line32(f, sc, f->avctx, w, sample[p], (p + 1) / 2, + bits[p], ac, pass1); + if (ret < 0) + return ret; + } + } + return 0; +} + + static int encode_slice(AVCodecContext *c, void *arg) { FFV1SliceContext *sc = arg; @@ -1060,10 +1572,13 @@ static int encode_slice(AVCodecContext *c, void *arg) const int ps = av_pix_fmt_desc_get(c->pix_fmt)->comp[0].step; int ret; RangeCoder c_bak = sc->c; + const int chroma_width = AV_CEIL_RSHIFT(width, f->chroma_h_shift); + const int chroma_height = AV_CEIL_RSHIFT(height, f->chroma_v_shift); const uint8_t *planes[4] = {p->data[0] + ps*x + y*p->linesize[0], p->data[1] ? p->data[1] + ps*x + y*p->linesize[1] : NULL, p->data[2] ? p->data[2] + ps*x + y*p->linesize[2] : NULL, p->data[3] ? p->data[3] + ps*x + y*p->linesize[3] : NULL}; + int ac = f->ac; sc->slice_coding_mode = 0; if (f->version > 3 && f->colorspace == 1) { @@ -1079,37 +1594,73 @@ retry: if (f->version > 2) { encode_slice_header(f, sc); } - if (f->ac == AC_GOLOMB_RICE) { + + if (sc->remap) { + //Both the 16bit and 32bit remap do exactly the same thing but with 16bits we can + //Implement this using a "histogram" while for 32bit that would be gb sized, thus a more + //complex implementation sorting pairs is used. + if (f->bits_per_raw_sample != 32) { + if (f->colorspace == 0 && c->pix_fmt != AV_PIX_FMT_YA8 && c->pix_fmt != AV_PIX_FMT_YAF16) { + const int cx = x >> f->chroma_h_shift; + const int cy = y >> f->chroma_v_shift; + + //TODO decide on the order for the encoded remaps and loads. with golomb rice it + // easier to have all range coded ones together, otherwise it may be nicer to handle each plane as a whole? + + load_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 1); + + if (f->chroma_planes) { + load_plane(f, sc, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1); + load_plane(f, sc, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 2, 1); + } + if (f->transparency) + load_plane(f, sc, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 3, 1); + } else if (c->pix_fmt == AV_PIX_FMT_YA8 || c->pix_fmt == AV_PIX_FMT_YAF16) { + load_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 2); + load_plane(f, sc, p->data[0] + (ps>>1) + ps*x + y*p->linesize[0], width, height, p->linesize[0], 1, 2); + } else if (f->use32bit) { + load_rgb_frame32(f, sc, planes, width, height, p->linesize); + } else + load_rgb_frame (f, sc, planes, width, height, p->linesize); + + encode_histogram_remap(f, sc); + } else { + load_rgb_float32_frame(f, sc, planes, width, height, p->linesize); + encode_float32_remap(f, sc, planes); + } + } + + if (ac == AC_GOLOMB_RICE) { sc->ac_byte_count = f->version > 2 || (!x && !y) ? ff_rac_terminate(&sc->c, f->version > 2) : 0; init_put_bits(&sc->pb, sc->c.bytestream_start + sc->ac_byte_count, sc->c.bytestream_end - sc->c.bytestream_start - sc->ac_byte_count); } - if (f->colorspace == 0 && c->pix_fmt != AV_PIX_FMT_YA8) { - const int chroma_width = AV_CEIL_RSHIFT(width, f->chroma_h_shift); - const int chroma_height = AV_CEIL_RSHIFT(height, f->chroma_v_shift); + if (f->colorspace == 0 && c->pix_fmt != AV_PIX_FMT_YA8 && c->pix_fmt != AV_PIX_FMT_YAF16) { const int cx = x >> f->chroma_h_shift; const int cy = y >> f->chroma_v_shift; - ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 1); + ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 0, 1, ac); if (f->chroma_planes) { - ret |= encode_plane(f, sc, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1); - ret |= encode_plane(f, sc, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 1); + ret |= encode_plane(f, sc, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1, 1, ac); + ret |= encode_plane(f, sc, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 2, 1, ac); } if (f->transparency) - ret |= encode_plane(f, sc, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2, 1); - } else if (c->pix_fmt == AV_PIX_FMT_YA8) { - ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 2); - ret |= encode_plane(f, sc, p->data[0] + 1 + ps*x + y*p->linesize[0], width, height, p->linesize[0], 1, 2); + ret |= encode_plane(f, sc, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2, 3, 1, ac); + } else if (c->pix_fmt == AV_PIX_FMT_YA8 || c->pix_fmt == AV_PIX_FMT_YAF16) { + ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 0, 2, ac); + ret |= encode_plane(f, sc, p->data[0] + (ps>>1) + ps*x + y*p->linesize[0], width, height, p->linesize[0], 1, 1, 2, ac); + } else if (f->bits_per_raw_sample == 32) { + ret = encode_float32_rgb_frame(f, sc, planes, width, height, p->linesize, ac); } else if (f->use32bit) { - ret = encode_rgb_frame32(f, sc, planes, width, height, p->linesize); + ret = encode_rgb_frame32(f, sc, planes, width, height, p->linesize, ac); } else { - ret = encode_rgb_frame(f, sc, planes, width, height, p->linesize); + ret = encode_rgb_frame(f, sc, planes, width, height, p->linesize, ac); } - if (f->ac != AC_GOLOMB_RICE) { + if (ac != AC_GOLOMB_RICE) { sc->ac_byte_count = ff_rac_terminate(&sc->c, 1); } else { flush_put_bits(&sc->pb); // FIXME: nicer padding @@ -1118,11 +1669,12 @@ retry: if (ret < 0) { av_assert0(sc->slice_coding_mode == 0); - if (f->version < 4 || !f->ac) { + if (f->version < 4) { av_log(c, AV_LOG_ERROR, "Buffer too small\n"); return ret; } av_log(c, AV_LOG_DEBUG, "Coding slice as PCM\n"); + ac = 1; sc->slice_coding_mode = 1; sc->c = c_bak; goto retry; @@ -1131,6 +1683,30 @@ retry: return 0; } +size_t ff_ffv1_encode_buffer_size(AVCodecContext *avctx) +{ + FFV1Context *f = avctx->priv_data; + + int w = avctx->width + f->num_h_slices; + int h = avctx->height + f->num_v_slices; + size_t maxsize = w*h * (1 + f->transparency); + if (f->chroma_planes) + maxsize += AV_CEIL_RSHIFT(w, f->chroma_h_shift) * AV_CEIL_RSHIFT(h, f->chroma_v_shift) * 2; + maxsize += f->slice_count * 800; //for slice header + if (f->version > 3) { + maxsize *= f->bits_per_raw_sample + 1; + if (f->remap_mode) + maxsize += f->slice_count * 70000 * (1 + 2*f->chroma_planes + f->transparency); + } else { + maxsize += f->slice_count * 2 * (avctx->width + avctx->height); //for bug with slices that code some pixels more than once + maxsize *= 8*(2*f->bits_per_raw_sample + 5); + } + maxsize >>= 3; + maxsize += FF_INPUT_BUFFER_MIN_SIZE; + + return maxsize; +} + static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet) { @@ -1139,8 +1715,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, uint8_t keystate = 128; uint8_t *buf_p; int i, ret; - int64_t maxsize = FF_INPUT_BUFFER_MIN_SIZE - + avctx->width*avctx->height*37LL*4; + int64_t maxsize; if(!pict) { if (avctx->flags & AV_CODEC_FLAG_PASS1) { @@ -1188,11 +1763,15 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } - if (f->version > 3) - maxsize = FF_INPUT_BUFFER_MIN_SIZE + avctx->width*avctx->height*3LL*4; + /* Maximum packet size */ + maxsize = ff_ffv1_encode_buffer_size(avctx); if (maxsize > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE - 32) { - av_log(avctx, AV_LOG_WARNING, "Cannot allocate worst case packet size, the encoding could fail\n"); + FFV1Context *f = avctx->priv_data; + if (!f->maxsize_warned) { + av_log(avctx, AV_LOG_WARNING, "Cannot allocate worst case packet size, the encoding could fail\n"); + f->maxsize_warned++; + } maxsize = INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE - 32; } @@ -1251,7 +1830,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, if (f->ec) { unsigned v; buf_p[bytes++] = 0; - v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, buf_p, bytes); + v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), f->crcref, buf_p, bytes) ^ (f->crcref ? 0x8CD88196 : 0); AV_WL32(buf_p + bytes, v); bytes += 4; } @@ -1269,10 +1848,29 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } +static av_cold int encode_close(AVCodecContext *avctx) +{ + FFV1Context *const s = avctx->priv_data; + + for (int j = 0; j < s->max_slice_count; j++) { + FFV1SliceContext *sc = &s->slices[j]; + + for(int p = 0; p<4; p++) { + av_freep(&sc->unit[p]); + av_freep(&sc->bitmap[p]); + } + } + + av_freep(&avctx->stats_out); + ff_ffv1_close(s); + + return 0; +} + #define OFFSET(x) offsetof(FFV1Context, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "slicecrc", "Protect slices with CRCs", OFFSET(ec), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, + { "slicecrc", "Protect slices with CRCs", OFFSET(ec), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 2, VE }, { "coder", "Coder type", OFFSET(ac), AV_OPT_TYPE_INT, { .i64 = 0 }, -2, 2, VE, .unit = "coder" }, { "rice", "Golomb rice", 0, AV_OPT_TYPE_CONST, @@ -1285,6 +1883,24 @@ static const AVOption options[] = { { .i64 = 1 }, INT_MIN, INT_MAX, VE, .unit = "coder" }, { "context", "Context model", OFFSET(context_model), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, + { "qtable", "Quantization table", OFFSET(qtable), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 2, VE , .unit = "qtable"}, + { "default", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_DEFAULT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + { "8bit", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_8BIT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + { "greater8bit", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_GT8BIT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + { "remap_mode", "Remap Mode", OFFSET(remap_mode), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 2, VE, .unit = "remap_mode" }, + { "auto", "Automatic", 0, AV_OPT_TYPE_CONST, + { .i64 = -1 }, INT_MIN, INT_MAX, VE, .unit = "remap_mode" }, + { "off", "Disabled", 0, AV_OPT_TYPE_CONST, + { .i64 = 0 }, INT_MIN, INT_MAX, VE, .unit = "remap_mode" }, + { "dualrle", "Dual RLE", 0, AV_OPT_TYPE_CONST, + { .i64 = 1 }, INT_MIN, INT_MAX, VE, .unit = "remap_mode" }, + { "flipdualrle", "Dual RLE", 0, AV_OPT_TYPE_CONST, + { .i64 = 2 }, INT_MIN, INT_MAX, VE, .unit = "remap_mode" }, + { "remap_optimizer", "Remap Optimizer", OFFSET(remap_optimizer), AV_OPT_TYPE_INT, { .i64 = 3 }, 0, 5, VE, .unit = "remap_optimizer" }, { NULL } }; @@ -1305,10 +1921,10 @@ const FFCodec ff_ffv1_encoder = { AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(FFV1Context), - .init = encode_init, + .init = encode_init_internal, FF_CODEC_ENCODE_CB(encode_frame), - .close = ff_ffv1_close, - .p.pix_fmts = (const enum AVPixelFormat[]) { + .close = encode_close, + CODEC_PIXFMTS( AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_0RGB32, AV_PIX_FMT_RGB32, AV_PIX_FMT_YUV420P16, @@ -1329,9 +1945,9 @@ const FFCodec ff_ffv1_encoder = { AV_PIX_FMT_GRAY9, AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV440P10, AV_PIX_FMT_YUV440P12, - AV_PIX_FMT_NONE - - }, + AV_PIX_FMT_YAF16, + AV_PIX_FMT_GRAYF16, + AV_PIX_FMT_GBRPF16, AV_PIX_FMT_GBRPF32), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ffv1_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_EOF_FLUSH, diff --git a/libavcodec/ffv1enc.h b/libavcodec/ffv1enc.h new file mode 100644 index 000000000..42d521a74 --- /dev/null +++ b/libavcodec/ffv1enc.h @@ -0,0 +1,42 @@ +/* + * FFV1 encoder + * + * Copyright (c) 2003-2013 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 AVCODEC_FFV1ENC_H +#define AVCODEC_FFV1ENC_H + +#include "avcodec.h" + +enum { + QTABLE_DEFAULT = -1, + QTABLE_8BIT, + QTABLE_GT8BIT, +}; + +av_cold int ff_ffv1_encode_init(AVCodecContext *avctx); +av_cold int ff_ffv1_encode_determine_slices(AVCodecContext *avctx); +av_cold int ff_ffv1_write_extradata(AVCodecContext *avctx); +av_cold int ff_ffv1_encode_setup_plane_info(AVCodecContext *avctx, + enum AVPixelFormat pix_fmt); + +size_t ff_ffv1_encode_buffer_size(AVCodecContext *avctx); + +#endif /* AVCODEC_FFV1ENC_H */ diff --git a/libavcodec/ffv1enc_template.c b/libavcodec/ffv1enc_template.c index a60490f65..63eb99b92 100644 --- a/libavcodec/ffv1enc_template.c +++ b/libavcodec/ffv1enc_template.c @@ -25,7 +25,7 @@ static av_always_inline int RENAME(encode_line)(FFV1Context *f, FFV1SliceContext *sc, void *logctx, - int w, TYPE *sample[3], int plane_index, int bits, + int w, TYPE *const sample[3], int plane_index, int bits, int ac, int pass1) { PlaneContext *const p = &sc->plane[plane_index]; @@ -35,19 +35,16 @@ RENAME(encode_line)(FFV1Context *f, FFV1SliceContext *sc, int run_count = 0; int run_mode = 0; - if (ac != AC_GOLOMB_RICE) { - if (c->bytestream_end - c->bytestream < w * 35) { - av_log(logctx, AV_LOG_ERROR, "encoded frame too large\n"); - return AVERROR_INVALIDDATA; - } - } else { - if (put_bytes_left(&sc->pb, 0) < w * 4) { - av_log(logctx, AV_LOG_ERROR, "encoded frame too large\n"); - return AVERROR_INVALIDDATA; - } - } + if (bits == 0) + return 0; if (sc->slice_coding_mode == 1) { + av_assert0(ac != AC_GOLOMB_RICE); + if (c->bytestream_end - c->bytestream < (w * bits + 7LL)>>3) { + av_log(logctx, AV_LOG_ERROR, "encoded Range Coder frame too large\n"); + return AVERROR_INVALIDDATA; + } + for (x = 0; x < w; x++) { int i; int v = sample[0][x]; @@ -59,6 +56,18 @@ RENAME(encode_line)(FFV1Context *f, FFV1SliceContext *sc, return 0; } + if (ac != AC_GOLOMB_RICE) { + if (c->bytestream_end - c->bytestream < w * 35) { + av_log(logctx, AV_LOG_ERROR, "encoded Range Coder frame too large\n"); + return AVERROR_INVALIDDATA; + } + } else { + if (put_bytes_left(&sc->pb, 0) < w * 4) { + av_log(logctx, AV_LOG_ERROR, "encoded Golomb Rice frame too large\n"); + return AVERROR_INVALIDDATA; + } + } + for (x = 0; x < w; x++) { int diff, context; @@ -127,24 +136,62 @@ RENAME(encode_line)(FFV1Context *f, FFV1SliceContext *sc, return 0; } +static void RENAME(load_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, + const uint8_t *src[4], + int w, int h, const int stride[4]) +{ + int x, y; + int transparency = f->transparency; + + for (int p = 0; p<3 + transparency; p++) + memset(sc->fltmap[p], 0, 65536 * sizeof(**sc->fltmap)); + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + int b, g, r, av_uninit(a); + + if (sizeof(TYPE) == 4 || transparency) { + g = *((const uint16_t *)(src[0] + x*2 + stride[0]*y)); + b = *((const uint16_t *)(src[1] + x*2 + stride[1]*y)); + r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y)); + if (transparency) + a = *((const uint16_t *)(src[3] + x*2 + stride[3]*y)); + } else { + b = *((const uint16_t *)(src[0] + x*2 + stride[0]*y)); + g = *((const uint16_t *)(src[1] + x*2 + stride[1]*y)); + r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y)); + } + + sc->fltmap[0][g] = 1; + sc->fltmap[1][b] = 1; + sc->fltmap[2][r] = 1; + if (transparency) + sc->fltmap[3][a] = 1; + } + } +} + static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, const uint8_t *src[4], - int w, int h, const int stride[4]) + int w, int h, const int stride[4], int ac) { int x, y, p, i; const int ring_size = f->context_model ? 3 : 2; TYPE *sample[4][3]; - const int ac = f->ac; const int pass1 = !!(f->avctx->flags & AV_CODEC_FLAG_PASS1); int lbd = f->bits_per_raw_sample <= 8; int packed = !src[1]; - int bits = f->bits_per_raw_sample > 0 ? f->bits_per_raw_sample : 8; - int offset = 1 << bits; + int bits[4], offset; int transparency = f->transparency; int packed_size = (3 + transparency)*2; + ff_ffv1_compute_bits_per_plane(f, sc, bits, &offset, NULL, f->bits_per_raw_sample); + sc->run_index = 0; + for (int p = 0; p < MAX_PLANES; ++p) + sample[p][2] = RENAME(sc->sample_buffer); + memset(RENAME(sc->sample_buffer), 0, ring_size * MAX_PLANES * (w + 6) * sizeof(*RENAME(sc->sample_buffer))); @@ -180,6 +227,14 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y)); } + if (sc->remap) { + g = sc->fltmap[0][g]; + b = sc->fltmap[1][b]; + r = sc->fltmap[2][r]; + if (transparency) + a = sc->fltmap[3][a]; + } + if (sc->slice_coding_mode != 1) { b -= g; r -= g; @@ -197,11 +252,11 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, int ret; sample[p][0][-1] = sample[p][1][0 ]; sample[p][1][ w] = sample[p][1][w-1]; - if (lbd && sc->slice_coding_mode == 0) + if (bits[p] == 9) ret = RENAME(encode_line)(f, sc, f->avctx, w, sample[p], (p + 1) / 2, 9, ac, pass1); else ret = RENAME(encode_line)(f, sc, f->avctx, w, sample[p], (p + 1) / 2, - bits + (sc->slice_coding_mode != 1), ac, pass1); + bits[p], ac, pass1); if (ret < 0) return ret; } diff --git a/libavcodec/ffv1enc_vulkan.c b/libavcodec/ffv1enc_vulkan.c new file mode 100644 index 000000000..0e891f088 --- /dev/null +++ b/libavcodec/ffv1enc_vulkan.c @@ -0,0 +1,1367 @@ +/* + * Copyright (c) 2024 Lynne + * + * 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/mem.h" +#include "libavutil/vulkan.h" + +#include "avcodec.h" +#include "internal.h" +#include "hwconfig.h" +#include "encode.h" +#include "libavutil/opt.h" +#include "codec_internal.h" + +#include "ffv1.h" +#include "ffv1enc.h" +#include "ffv1_vulkan.h" + +/* Parallel Golomb alignment */ +#define LG_ALIGN_W 32 +#define LG_ALIGN_H 32 + +/* Unlike the decoder, we need 4 lines (but really only 3) */ +#define RGB_LINECACHE 4 + +typedef struct VulkanEncodeFFv1FrameData { + /* Output data */ + AVBufferRef *out_data_ref; + + /* Copied from the source */ + int64_t pts; + int64_t duration; + void *frame_opaque; + AVBufferRef *frame_opaque_ref; + + int key_frame; + int idx; +} VulkanEncodeFFv1FrameData; + +typedef struct VulkanEncodeFFv1Context { + FFV1Context ctx; + AVFrame *frame; + + FFVulkanContext s; + AVVulkanDeviceQueueFamily *qf; + FFVkExecPool exec_pool; + + AVVulkanDeviceQueueFamily *transfer_qf; + FFVkExecPool transfer_exec_pool; + + VkBufferCopy *buf_regions; + VulkanEncodeFFv1FrameData *exec_ctx_info; + int in_flight; + int async_depth; + size_t max_heap_size; + + FFVulkanShader setup; + FFVulkanShader rct_search; + FFVulkanShader reset; + FFVulkanShader enc; + + /* Constant read-only buffers */ + FFVkBuffer consts_buf; + + /* Results buffer */ + FFVkBuffer results_buf; + + /* Slice data buffer pool */ + AVBufferPool *slice_data_pool; + AVBufferRef *keyframe_slice_data_ref; + + /* Output data buffer */ + AVBufferPool *out_data_pool; + + /* Intermediate frame pool */ + AVBufferRef *intermediate_frames_ref; + + int num_h_slices; + int num_v_slices; + int force_pcm; + int optimize_rct; + + int is_rgb; + int ppi; + int chunks; +} VulkanEncodeFFv1Context; + +extern const char *ff_source_common_comp; +extern const char *ff_source_rangecoder_comp; +extern const char *ff_source_ffv1_vlc_comp; +extern const char *ff_source_ffv1_common_comp; +extern const char *ff_source_ffv1_enc_comp; + +extern const unsigned char ff_ffv1_enc_setup_comp_spv_data[]; +extern const unsigned int ff_ffv1_enc_setup_comp_spv_len; + +extern const unsigned char ff_ffv1_enc_reset_comp_spv_data[]; +extern const unsigned int ff_ffv1_enc_reset_comp_spv_len; + +extern const unsigned char ff_ffv1_enc_reset_golomb_comp_spv_data[]; +extern const unsigned int ff_ffv1_enc_reset_golomb_comp_spv_len; + +extern const unsigned char ff_ffv1_enc_comp_spv_data[]; +extern const unsigned int ff_ffv1_enc_comp_spv_len; + +extern const unsigned char ff_ffv1_enc_rgb_comp_spv_data[]; +extern const unsigned int ff_ffv1_enc_rgb_comp_spv_len; + +extern const unsigned char ff_ffv1_enc_golomb_comp_spv_data[]; +extern const unsigned int ff_ffv1_enc_golomb_comp_spv_len; + +extern const unsigned char ff_ffv1_enc_rgb_golomb_comp_spv_data[]; +extern const unsigned int ff_ffv1_enc_rgb_golomb_comp_spv_len; + +extern const unsigned char ff_ffv1_enc_rct_search_comp_spv_data[]; +extern const unsigned int ff_ffv1_enc_rct_search_comp_spv_len; + +static int run_rct_search(AVCodecContext *avctx, FFVkExecContext *exec, + AVFrame *enc_in, VkImageView *enc_in_views, + FFVkBuffer *slice_data_buf, uint32_t slice_data_size, + FFv1ShaderParams *pd) +{ + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + FFVulkanFunctions *vk = &fv->s.vkfn; + + /* Update descriptors */ + ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->rct_search, + 1, 0, 0, + slice_data_buf, + 0, slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_img_array(&fv->s, exec, &fv->rct_search, + enc_in, enc_in_views, + 1, 1, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + + ff_vk_exec_bind_shader(&fv->s, exec, &fv->rct_search); + ff_vk_shader_update_push_const(&fv->s, exec, &fv->rct_search, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(FFv1ShaderParams), pd); + + vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1); + + return 0; +} + +static int vulkan_encode_ffv1_submit_frame(AVCodecContext *avctx, + FFVkExecContext *exec, + const AVFrame *pict) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + FFVulkanFunctions *vk = &fv->s.vkfn; + + VulkanEncodeFFv1FrameData *fd = exec->opaque; + + /* Slice data */ + AVBufferRef *slice_data_ref; + FFVkBuffer *slice_data_buf; + uint32_t plane_state_size; + uint32_t slice_state_size; + uint32_t slice_data_size; + + /* Output data */ + size_t maxsize; + FFVkBuffer *out_data_buf; + + int has_inter = avctx->gop_size > 1; + uint32_t context_count = f->context_count[f->context_model]; + + VkImageMemoryBarrier2 img_bar[37]; + int nb_img_bar = 0; + VkBufferMemoryBarrier2 buf_bar[8]; + int nb_buf_bar = 0; + + /* Frame state */ + f->cur_enc_frame = pict; + if (avctx->gop_size == 0 || f->picture_number % avctx->gop_size == 0) { + av_buffer_unref(&fv->keyframe_slice_data_ref); + f->key_frame = fd->key_frame = 1; + f->gob_count++; + } else { + f->key_frame = fd->key_frame = 0; + } + + f->slice_count = f->max_slice_count; + + /* Allocate slice buffer data */ + if (f->ac == AC_GOLOMB_RICE) + plane_state_size = 8; + else + plane_state_size = CONTEXT_SIZE; + + plane_state_size *= context_count; + slice_state_size = plane_state_size*f->plane_count; + + slice_data_size = 256; /* Overestimation for the SliceContext struct */ + slice_state_size += slice_data_size; + slice_state_size = FFALIGN(slice_state_size, 8); + + /* Allocate slice data buffer */ + slice_data_ref = fv->keyframe_slice_data_ref; + if (!slice_data_ref) { + RET(ff_vk_get_pooled_buffer(&fv->s, &fv->slice_data_pool, + &slice_data_ref, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + NULL, slice_state_size*f->slice_count, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); + + /* Only save it if we're going to use it again */ + if (has_inter) + fv->keyframe_slice_data_ref = slice_data_ref; + } + slice_data_buf = (FFVkBuffer *)slice_data_ref->data; + + /* Output buffer size */ + maxsize = ff_ffv1_encode_buffer_size(avctx); + maxsize = FFMIN(maxsize, fv->s.props_11.maxMemoryAllocationSize); + + /* Allocate output buffer */ + VkMemoryPropertyFlagBits out_buf_flags; + if (maxsize < fv->max_heap_size) { + out_buf_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + /* If we can't map host memory, we can't let the GPU copy its buffer. */ + if (!(fv->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY)) + out_buf_flags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + } else { + out_buf_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + fv->s.host_cached_flag; + } + + RET(ff_vk_get_pooled_buffer(&fv->s, &fv->out_data_pool, + &fd->out_data_ref, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + NULL, maxsize, out_buf_flags)); + out_data_buf = (FFVkBuffer *)fd->out_data_ref->data; + + /* Image views */ + AVFrame *src = (AVFrame *)pict; + VkImageView src_views[AV_NUM_DATA_POINTERS]; + + AVFrame *tmp = NULL; + VkImageView tmp_views[AV_NUM_DATA_POINTERS]; + if (fv->is_rgb) { + /* Create a temporaty frame */ + tmp = av_frame_alloc(); + if (!(tmp)) + return AVERROR(ENOMEM); + + RET(av_hwframe_get_buffer(fv->intermediate_frames_ref, + tmp, 0)); + } + + /* With everything allocated, setup push data */ + FFv1ShaderParams pd = { + .slice_data = out_data_buf->address, + + .img_size[0] = fv->s.frames->width, + .img_size[1] = fv->s.frames->height, + + .plane_state_size = plane_state_size, + .key_frame = f->key_frame, + .crcref = f->crcref, + .micro_version = f->micro_version, + + .sar[0] = pict->sample_aspect_ratio.num, + .sar[1] = pict->sample_aspect_ratio.den, + .pic_mode = !(pict->flags & AV_FRAME_FLAG_INTERLACED) ? 3 : + !(pict->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? 2 : 1, + .slice_size_max = out_data_buf->size / f->slice_count, + }; + + for (int i = 0; i < f->quant_table_count; i++) { + pd.context_count[i] = f->context_count[i]; + pd.extend_lookup[i] = f->quant_tables[i][3][127] || + f->quant_tables[i][4][127]; + } + + /* For some reason the C FFv1 encoder/decoder treats these differently */ + if (avctx->sw_pix_fmt == AV_PIX_FMT_GBRP10 || + avctx->sw_pix_fmt == AV_PIX_FMT_GBRP12 || + avctx->sw_pix_fmt == AV_PIX_FMT_GBRP14) + memcpy(pd.fmt_lut, (int [4]) { 2, 1, 0, 3 }, 4*sizeof(int)); + else + ff_vk_set_perm(avctx->sw_pix_fmt, pd.fmt_lut, 1); + + /* Start recording */ + ff_vk_exec_start(&fv->s, exec); + fd->idx = exec->idx; + + RET(ff_vk_create_imageviews(&fv->s, exec, src_views, src, + FF_VK_REP_NATIVE)); + + ff_vk_exec_add_dep_buf(&fv->s, exec, &slice_data_ref, 1, has_inter); + ff_vk_exec_add_dep_buf(&fv->s, exec, &fd->out_data_ref, 1, 1); + + RET(ff_vk_exec_add_dep_frame(&fv->s, exec, src, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + if (fv->is_rgb) + RET(ff_vk_exec_add_dep_frame(&fv->s, exec, tmp, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + + /* Run RCT search if needed */ + if (fv->optimize_rct) { + /* Prepare the frame for reading */ + ff_vk_frame_barrier(&fv->s, exec, src, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + nb_img_bar = 0; + + RET(run_rct_search(avctx, exec, + src, src_views, + slice_data_buf, slice_data_size, &pd)); + + /* Make sure the writes are visible to the setup shader */ + ff_vk_buf_barrier(buf_bar[nb_buf_bar++], slice_data_buf, + COMPUTE_SHADER_BIT, SHADER_READ_BIT, SHADER_WRITE_BIT, + COMPUTE_SHADER_BIT, SHADER_READ_BIT, SHADER_WRITE_BIT, + 0, slice_data_size*f->slice_count); + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + nb_buf_bar = 0; + } + + /* Setup shader */ + ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->setup, + 1, 0, 0, + slice_data_buf, + 0, slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + + ff_vk_exec_bind_shader(&fv->s, exec, &fv->setup); + ff_vk_shader_update_push_const(&fv->s, exec, &fv->setup, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(FFv1ShaderParams), &pd); + + vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1); + + /* Clean up temporary image if needed */ + if (fv->is_rgb) { + AVVkFrame *vkf = (AVVkFrame *)tmp->data[0]; + vkf->layout[0] = VK_IMAGE_LAYOUT_UNDEFINED; + vkf->access[0] = VK_ACCESS_2_NONE; + + RET(ff_vk_create_imageviews(&fv->s, exec, tmp_views, + tmp, + FF_VK_REP_NATIVE)); + + ff_vk_frame_barrier(&fv->s, exec, tmp, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_CLEAR_BIT, + VK_ACCESS_2_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + nb_img_bar = 0; + + vk->CmdClearColorImage(exec->buf, vkf->img[0], VK_IMAGE_LAYOUT_GENERAL, + &((VkClearColorValue) { 0 }), + 1, &((VkImageSubresourceRange) { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + })); + } + + /* Run reset shader */ + if (f->key_frame || fv->force_pcm) { + ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->reset, + 1, 0, 0, + slice_data_buf, + 0, slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->reset, + 1, 1, 0, + slice_data_buf, + f->slice_count*256, + VK_WHOLE_SIZE, + VK_FORMAT_UNDEFINED); + + ff_vk_exec_bind_shader(&fv->s, exec, &fv->reset); + ff_vk_shader_update_push_const(&fv->s, exec, &fv->reset, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(FFv1ShaderParams), &pd); + + vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, + f->plane_count); + } + + /* Sync between reset and encode shaders */ + ff_vk_buf_barrier(buf_bar[nb_buf_bar++], slice_data_buf, + COMPUTE_SHADER_BIT, SHADER_WRITE_BIT, NONE_KHR, + COMPUTE_SHADER_BIT, SHADER_READ_BIT, SHADER_WRITE_BIT, + 0, slice_data_size*f->slice_count); + if (f->key_frame || fv->force_pcm) + ff_vk_buf_barrier(buf_bar[nb_buf_bar++], slice_data_buf, + COMPUTE_SHADER_BIT, SHADER_WRITE_BIT, NONE_KHR, + COMPUTE_SHADER_BIT, SHADER_READ_BIT, SHADER_WRITE_BIT, + slice_data_size*f->slice_count, VK_WHOLE_SIZE); + else + ff_vk_buf_barrier(buf_bar[nb_buf_bar++], slice_data_buf, + COMPUTE_SHADER_BIT, SHADER_READ_BIT, SHADER_WRITE_BIT, + COMPUTE_SHADER_BIT, SHADER_READ_BIT, SHADER_WRITE_BIT, + slice_data_size*f->slice_count, VK_WHOLE_SIZE); + + ff_vk_frame_barrier(&fv->s, exec, src, img_bar, &nb_img_bar, + fv->optimize_rct ? VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT : + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + if (fv->is_rgb) + ff_vk_frame_barrier(&fv->s, exec, tmp, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_CLEAR_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + nb_img_bar = 0; + nb_buf_bar = 0; + + /* Main encode shader */ + ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->enc, + 1, 0, 0, + slice_data_buf, + 0, slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&fv->s, exec, + &fv->enc, 1, 1, 0, + &fv->results_buf, + fd->idx*f->max_slice_count*sizeof(uint32_t), + f->slice_count*sizeof(uint32_t), + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->enc, + 1, 2, 0, + slice_data_buf, + f->slice_count*256, + VK_WHOLE_SIZE, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_img_array(&fv->s, exec, &fv->enc, + src, src_views, + 1, 3, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + if (fv->is_rgb) + ff_vk_shader_update_img_array(&fv->s, exec, &fv->enc, + tmp, tmp_views, + 1, 4, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + + ff_vk_exec_bind_shader(&fv->s, exec, &fv->enc); + ff_vk_shader_update_push_const(&fv->s, exec, &fv->enc, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(FFv1ShaderParams), &pd); + vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1); + + /* Submit */ + err = ff_vk_exec_submit(&fv->s, exec); + if (err < 0) + return err; + + f->picture_number++; + + /* This, if needed, was referenced by the execution context + * as it was declared as a dependency. */ + av_frame_free(&tmp); + return 0; + +fail: + av_frame_free(&tmp); + ff_vk_exec_discard_deps(&fv->s, exec); + + return err; +} + +static int transfer_slices(AVCodecContext *avctx, + VkBufferCopy *buf_regions, int nb_regions, + VulkanEncodeFFv1FrameData *fd, + uint8_t *dst, AVBufferRef *dst_ref) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFVulkanFunctions *vk = &fv->s.vkfn; + FFVkExecContext *exec; + + FFVkBuffer *out_data_buf = (FFVkBuffer *)fd->out_data_ref->data; + + AVBufferRef *mapped_ref; + FFVkBuffer *mapped_buf; + + VkBufferMemoryBarrier2 buf_bar[8]; + int nb_buf_bar = 0; + + err = ff_vk_host_map_buffer(&fv->s, &mapped_ref, dst, dst_ref, + VK_BUFFER_USAGE_TRANSFER_DST_BIT); + if (err < 0) + return err; + + mapped_buf = (FFVkBuffer *)mapped_ref->data; + + /* Transfer the slices */ + exec = ff_vk_exec_get(&fv->s, &fv->transfer_exec_pool); + ff_vk_exec_start(&fv->s, exec); + + ff_vk_exec_add_dep_buf(&fv->s, exec, &fd->out_data_ref, 1, 0); + fd->out_data_ref = NULL; /* Ownership passed */ + + ff_vk_exec_add_dep_buf(&fv->s, exec, &mapped_ref, 1, 0); + mapped_ref = NULL; /* Ownership passed */ + + /* Ensure the output buffer is finished */ + ff_vk_buf_barrier(buf_bar[nb_buf_bar++], out_data_buf, + COMPUTE_SHADER_BIT, SHADER_WRITE_BIT, NONE_KHR, + TRANSFER_BIT, TRANSFER_READ_BIT, NONE_KHR, + 0, VK_WHOLE_SIZE); + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + nb_buf_bar = 0; + + for (int i = 0; i < nb_regions; i++) + buf_regions[i].dstOffset += mapped_buf->virtual_offset; + + vk->CmdCopyBuffer(exec->buf, + out_data_buf->buf, mapped_buf->buf, + nb_regions, buf_regions); + + /* Submit */ + err = ff_vk_exec_submit(&fv->s, exec); + if (err < 0) + return err; + + /* We need the encoded data immediately */ + ff_vk_exec_wait(&fv->s, exec); + + return 0; +} + +static int get_packet(AVCodecContext *avctx, FFVkExecContext *exec, + AVPacket *pkt) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + FFVulkanFunctions *vk = &fv->s.vkfn; + VulkanEncodeFFv1FrameData *fd = exec->opaque; + + FFVkBuffer *out_data_buf = (FFVkBuffer *)fd->out_data_ref->data; + uint32_t slice_size_max = out_data_buf->size / f->slice_count; + + /* Make sure encoding's done */ + ff_vk_exec_wait(&fv->s, exec); + + /* Invalidate slice/output data if needed */ + uint32_t rb_off = fd->idx*f->max_slice_count*sizeof(uint32_t); + if (!(fv->results_buf.flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + VkMappedMemoryRange invalidate_data = { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = fv->results_buf.mem, + .offset = rb_off, + .size = f->slice_count*sizeof(uint32_t), + }; + vk->InvalidateMappedMemoryRanges(fv->s.hwctx->act_dev, + 1, &invalidate_data); + } + + /* Calculate final size */ + pkt->size = 0; + uint8_t *rb = fv->results_buf.mapped_mem + rb_off; + for (int i = 0; i < f->slice_count; i++) { + uint32_t sl_len = AV_RN32(rb + i*4); + av_log(avctx, AV_LOG_DEBUG, "Slice %i size = %u\n", i, sl_len); + + fv->buf_regions[i] = (VkBufferCopy) { + .srcOffset = i*slice_size_max, + .dstOffset = pkt->size, + .size = sl_len, + }; + pkt->size += sl_len; + } + av_log(avctx, AV_LOG_VERBOSE, "Encoded data: %iMiB\n", pkt->size / (1024*1024)); + + /* Allocate packet */ + if ((err = ff_get_encode_buffer(avctx, pkt, pkt->size, 0)) < 0) + return err; + + pkt->pts = fd->pts; + pkt->dts = fd->pts; + pkt->duration = fd->duration; + pkt->flags |= AV_PKT_FLAG_KEY * fd->key_frame; + + if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { + pkt->opaque = fd->frame_opaque; + pkt->opaque_ref = fd->frame_opaque_ref; + fd->frame_opaque_ref = NULL; + } + + /* Try using host mapped memory transfers first */ + if (fv->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) { + err = transfer_slices(avctx, fv->buf_regions, f->slice_count, fd, + pkt->data, pkt->buf); + if (err >= 0) + return err; + } + + /* Invalidate slice/output data if needed */ + if (!(out_data_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + VkMappedMemoryRange invalidate_data = { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = out_data_buf->mem, + .offset = 0, + .size = VK_WHOLE_SIZE, + }; + vk->InvalidateMappedMemoryRanges(fv->s.hwctx->act_dev, + 1, &invalidate_data); + } + + /* Copy each slice */ + for (int i = 0; i < f->slice_count; i++) { + VkBufferCopy *region = &fv->buf_regions[i]; + memcpy(pkt->data + region->dstOffset, + out_data_buf->mapped_mem + region->srcOffset, + region->size); + } + + av_buffer_unref(&fd->out_data_ref); + + return 0; +} + +static int vulkan_encode_ffv1_receive_packet(AVCodecContext *avctx, + AVPacket *pkt) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + VulkanEncodeFFv1FrameData *fd; + FFVkExecContext *exec; + AVFrame *frame; + + while (1) { + /* Roll an execution context */ + exec = ff_vk_exec_get(&fv->s, &fv->exec_pool); + + /* If it had a frame, immediately output it */ + if (exec->had_submission) { + exec->had_submission = 0; + fv->in_flight--; + return get_packet(avctx, exec, pkt); + } + + /* Get next frame to encode */ + frame = fv->frame; + err = ff_encode_get_frame(avctx, frame); + if (err < 0 && err != AVERROR_EOF) { + return err; + } else if (err == AVERROR_EOF) { + if (!fv->in_flight) + return err; + continue; + } + + /* Encode frame */ + fd = exec->opaque; + fd->pts = frame->pts; + fd->duration = frame->duration; + if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { + fd->frame_opaque = frame->opaque; + fd->frame_opaque_ref = frame->opaque_ref; + frame->opaque_ref = NULL; + } + + err = vulkan_encode_ffv1_submit_frame(avctx, exec, frame); + av_frame_unref(frame); + if (err < 0) + return err; + + fv->in_flight++; + if (fv->in_flight < fv->async_depth) + return AVERROR(EAGAIN); + } + + return 0; +} + +static int init_indirect(AVCodecContext *avctx, enum AVPixelFormat sw_format) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + AVHWFramesContext *frames_ctx; + AVVulkanFramesContext *vk_frames; + + fv->intermediate_frames_ref = av_hwframe_ctx_alloc(fv->s.device_ref); + if (!fv->intermediate_frames_ref) + return AVERROR(ENOMEM); + + frames_ctx = (AVHWFramesContext *)fv->intermediate_frames_ref->data; + frames_ctx->format = AV_PIX_FMT_VULKAN; + frames_ctx->sw_format = sw_format; + frames_ctx->width = fv->s.frames->width; + frames_ctx->height = f->num_v_slices*RGB_LINECACHE; + + vk_frames = frames_ctx->hwctx; + vk_frames->tiling = VK_IMAGE_TILING_OPTIMAL; + vk_frames->usage = VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT; + vk_frames->img_flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + + err = av_hwframe_ctx_init(fv->intermediate_frames_ref); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to initialize frame pool with format %s: %s\n", + av_get_pix_fmt_name(sw_format), av_err2str(err)); + av_buffer_unref(&fv->intermediate_frames_ref); + return err; + } + + return 0; +} + +static int init_rct_search_shader(AVCodecContext *avctx, VkSpecializationInfo *sl) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFVulkanShader *shd = &fv->rct_search; + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { 32, 32, 1 }, 0); + + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1ShaderParams), + VK_SHADER_STAGE_COMPUTE_BIT); + + const FFVulkanDescriptorSetBinding desc_set_const[] = { + { /* rangecoder_buf */ + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set_const, 1, 1, 0); + + const FFVulkanDescriptorSetBinding desc_set[] = { + { /* slice_data_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* src */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .elems = av_pix_fmt_count_planes(fv->s.frames->sw_format), + }, + }; + ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 0, 0); + + RET(ff_vk_shader_link(&fv->s, shd, + ff_ffv1_enc_rct_search_comp_spv_data, + ff_ffv1_enc_rct_search_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd)); + +fail: + return err; +} + +static int init_setup_shader(AVCodecContext *avctx, VkSpecializationInfo *sl) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFVulkanShader *shd = &fv->setup; + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { 1, 1, 1 }, 0); + + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1ShaderParams), + VK_SHADER_STAGE_COMPUTE_BIT); + + const FFVulkanDescriptorSetBinding desc_set_const[] = { + { /* rangecoder_buf */ + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set_const, 1, 1, 0); + + const FFVulkanDescriptorSetBinding desc_set[] = { + { /* slice_data_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 1, 0, 0); + + RET(ff_vk_shader_link(&fv->s, shd, + ff_ffv1_enc_setup_comp_spv_data, + ff_ffv1_enc_setup_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd)); + +fail: + return err; +} + +static int init_reset_shader(AVCodecContext *avctx, VkSpecializationInfo *sl) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFVulkanShader *shd = &fv->reset; + + int wg_dim = FFMIN(fv->s.props.properties.limits.maxComputeWorkGroupSize[0], 1024); + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { wg_dim, 1, 1 }, 0); + + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1ShaderParams), + VK_SHADER_STAGE_COMPUTE_BIT); + + const FFVulkanDescriptorSetBinding desc_set_const[] = { + { /* rangecoder_buf */ + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set_const, 1, 1, 0); + + const FFVulkanDescriptorSetBinding desc_set[] = { + { /* slice_data_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* slice_state_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 0, 0); + + if (fv->ctx.ac == AC_GOLOMB_RICE) + RET(ff_vk_shader_link(&fv->s, shd, + ff_ffv1_enc_reset_golomb_comp_spv_data, + ff_ffv1_enc_reset_golomb_comp_spv_len, "main")); + else + RET(ff_vk_shader_link(&fv->s, shd, + ff_ffv1_enc_reset_comp_spv_data, + ff_ffv1_enc_reset_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd)); + +fail: + return err; +} + +static int init_encode_shader(AVCodecContext *avctx, VkSpecializationInfo *sl) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFVulkanShader *shd = &fv->enc; + + uint32_t wg_x = fv->ctx.ac != AC_GOLOMB_RICE ? CONTEXT_SIZE : 1; + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { wg_x, 1, 1 }, 0); + + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1ShaderParams), + VK_SHADER_STAGE_COMPUTE_BIT); + + const FFVulkanDescriptorSetBinding desc_set_const[] = { + { /* rangecoder_buf */ + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* quant_buf */ + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* crc_ieee_buf */ + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set_const, 3, 1, 0); + + const FFVulkanDescriptorSetBinding desc_set[] = { + { /* slice_data_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* slice_results_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* slice_state_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* src */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .elems = av_pix_fmt_count_planes(fv->s.frames->sw_format), + }, + { /* tmp */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 4 + fv->is_rgb, 0, 0); + + if (fv->ctx.ac == AC_GOLOMB_RICE) { + if (fv->is_rgb) + ff_vk_shader_link(&fv->s, shd, + ff_ffv1_enc_rgb_golomb_comp_spv_data, + ff_ffv1_enc_rgb_golomb_comp_spv_len, "main"); + else + ff_vk_shader_link(&fv->s, shd, + ff_ffv1_enc_golomb_comp_spv_data, + ff_ffv1_enc_golomb_comp_spv_len, "main"); + } else { + if (fv->is_rgb) + ff_vk_shader_link(&fv->s, shd, + ff_ffv1_enc_rgb_comp_spv_data, + ff_ffv1_enc_rgb_comp_spv_len, "main"); + else + ff_vk_shader_link(&fv->s, shd, + ff_ffv1_enc_comp_spv_data, + ff_ffv1_enc_comp_spv_len, "main"); + } + + RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd)); + +fail: + return err; +} + +static av_cold int vulkan_encode_ffv1_init(AVCodecContext *avctx) +{ + int err; + size_t maxsize, max_heap_size, max_host_size; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + + if ((err = ff_ffv1_common_init(avctx, f)) < 0) + return err; + + if (f->ac == 1) + f->ac = AC_RANGE_CUSTOM_TAB; + + err = ff_ffv1_encode_setup_plane_info(avctx, avctx->sw_pix_fmt); + if (err < 0) + return err; + + /* Target version 3 by default */ + f->version = 3; + + err = ff_ffv1_encode_init(avctx); + if (err < 0) + return err; + + /* Rice coding did not support high bit depths */ + if (f->bits_per_raw_sample > (f->version > 3 ? 16 : 8)) { + if (f->ac == AC_GOLOMB_RICE) { + av_log(avctx, AV_LOG_WARNING, "bits_per_raw_sample > 8, " + "forcing range coder\n"); + f->ac = AC_RANGE_CUSTOM_TAB; + } + } + + if (f->version < 4 && avctx->gop_size > 1) { + av_log(avctx, AV_LOG_ERROR, "Using inter frames requires version 4 (-level 4)\n"); + return AVERROR_INVALIDDATA; + } + + if (f->version == 4 && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { + av_log(avctx, AV_LOG_ERROR, "Version 4 is experimental and requires -strict -2\n"); + return AVERROR_INVALIDDATA; + } + + /* We target version 4.3 */ + if (f->version == 4 && f->micro_version > 4) + f->micro_version = 3; + + f->num_h_slices = fv->num_h_slices; + f->num_v_slices = fv->num_v_slices; + + if (f->num_h_slices <= 0 && f->num_v_slices <= 0) { + if (avctx->slices) { + err = ff_ffv1_encode_determine_slices(avctx); + if (err < 0) + return err; + } else { + f->num_h_slices = 32; + f->num_v_slices = 32; + } + } else if (f->num_h_slices && f->num_v_slices <= 0) { + f->num_v_slices = MAX_SLICES / f->num_h_slices; + } else if (f->num_v_slices && f->num_h_slices <= 0) { + f->num_h_slices = MAX_SLICES / f->num_v_slices; + } + + f->num_h_slices = FFMIN(f->num_h_slices, avctx->width); + f->num_v_slices = FFMIN(f->num_v_slices, avctx->height); + + if (f->num_h_slices * f->num_v_slices > MAX_SLICES) { + av_log(avctx, AV_LOG_ERROR, "Too many slices (%i), maximum supported " + "by the standard is %i\n", + f->num_h_slices * f->num_v_slices, MAX_SLICES); + return AVERROR_PATCHWELCOME; + } + + f->max_slice_count = f->num_h_slices * f->num_v_slices; + + if ((err = ff_ffv1_write_extradata(avctx)) < 0) + return err; + + if (f->version < 4) { + if (((f->chroma_h_shift > 0) && (avctx->width % (64 << f->chroma_h_shift))) || + ((f->chroma_v_shift > 0) && (avctx->height % (64 << f->chroma_v_shift)))) { + av_log(avctx, AV_LOG_ERROR, "Encoding frames with subsampling and unaligned " + "dimensions is only supported in version 4 (-level 4)\n"); + return AVERROR_PATCHWELCOME; + } + } + + if (fv->force_pcm) { + if (f->version < 4) { + av_log(avctx, AV_LOG_ERROR, "PCM coding only supported by version 4 (-level 4)\n"); + return AVERROR_INVALIDDATA; + } else if (f->ac == AC_GOLOMB_RICE) { + av_log(avctx, AV_LOG_ERROR, "PCM coding requires range coding\n"); + return AVERROR_INVALIDDATA; + } + } + + /* Init Vulkan */ + err = ff_vk_init(&fv->s, avctx, NULL, avctx->hw_frames_ctx); + if (err < 0) + return err; + + fv->qf = ff_vk_qf_find(&fv->s, VK_QUEUE_COMPUTE_BIT, 0); + if (!fv->qf) { + av_log(avctx, AV_LOG_ERROR, "Device has no compute queues!\n"); + return err; + } + + /* Try to measure VRAM size */ + max_heap_size = 0; + max_host_size = 0; + for (int i = 0; i < fv->s.mprops.memoryHeapCount; i++) { + if (fv->s.mprops.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) + max_heap_size = FFMAX(fv->max_heap_size, + fv->s.mprops.memoryHeaps[i].size); + if (!(fv->s.mprops.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)) + max_host_size = FFMAX(max_host_size, + fv->s.mprops.memoryHeaps[i].size); + } + fv->max_heap_size = max_heap_size; + + maxsize = ff_ffv1_encode_buffer_size(avctx); + if (maxsize > fv->s.props_11.maxMemoryAllocationSize) { + av_log(avctx, AV_LOG_WARNING, "Encoding buffer size (%zu) larger " + "than maximum device allocation (%zu), clipping\n", + maxsize, fv->s.props_11.maxMemoryAllocationSize); + maxsize = fv->s.props_11.maxMemoryAllocationSize; + } + + if (max_heap_size < maxsize) { + av_log(avctx, AV_LOG_WARNING, "Encoding buffer (%zu) larger than VRAM (%zu), " + "using host memory (slower)\n", + maxsize, fv->max_heap_size); + + /* Keep 1/2th of RAM as headroom */ + max_heap_size = max_host_size - (max_host_size >> 1); + } else { + /* Keep 1/8th of VRAM as headroom */ + max_heap_size = max_heap_size - (max_heap_size >> 3); + } + + av_log(avctx, AV_LOG_INFO, "Async buffers: %zuMiB per context, %zuMiB total, depth: %i\n", + maxsize / (1024*1024), + (fv->async_depth * maxsize) / (1024*1024), + fv->async_depth); + + err = ff_vk_exec_pool_init(&fv->s, fv->qf, &fv->exec_pool, + fv->async_depth, + 0, 0, 0, NULL); + if (err < 0) + return err; + + fv->transfer_qf = ff_vk_qf_find(&fv->s, VK_QUEUE_TRANSFER_BIT, 0); + if (!fv->transfer_qf) { + av_log(avctx, AV_LOG_ERROR, "Device has no transfer queues!\n"); + return err; + } + + err = ff_vk_exec_pool_init(&fv->s, fv->transfer_qf, &fv->transfer_exec_pool, + 1, + 0, 0, 0, NULL); + if (err < 0) + return err; + + /* Detect the special RGB coding mode */ + fv->is_rgb = !(f->colorspace == 0 && avctx->sw_pix_fmt != AV_PIX_FMT_YA8) && + !(avctx->sw_pix_fmt == AV_PIX_FMT_YA8); + + /* Init rct search shader */ + fv->optimize_rct = fv->is_rgb && f->version >= 4 && + !fv->force_pcm && fv->optimize_rct; + + /* Init shader specialization consts */ + SPEC_LIST_CREATE(sl, 18, 18*sizeof(uint32_t)) + SPEC_LIST_ADD(sl, 0, 32, RGB_LINECACHE); + SPEC_LIST_ADD(sl, 1, 32, f->ec); + ff_ffv1_vk_set_common_sl(avctx, f, sl, fv->s.frames->sw_format); + SPEC_LIST_ADD(sl, 15, 32, fv->force_pcm); + SPEC_LIST_ADD(sl, 16, 32, fv->optimize_rct); + SPEC_LIST_ADD(sl, 17, 32, f->context_model); + + if (fv->optimize_rct) { + err = init_rct_search_shader(avctx, sl); + if (err < 0) + return err; + } + + /* Init setup shader */ + err = init_setup_shader(avctx, sl); + if (err < 0) + return err; + + /* Init reset shader */ + err = init_reset_shader(avctx, sl); + if (err < 0) + return err; + + if (fv->is_rgb) + RET(init_indirect(avctx, fv->ctx.use32bit ? + AV_PIX_FMT_RGBA128 : AV_PIX_FMT_RGBA64)); + + /* Encode shader */ + err = init_encode_shader(avctx, sl); + if (err < 0) + return err; + + /* Constant data */ + err = ff_ffv1_vk_init_consts(&fv->s, &fv->consts_buf, f); + if (err < 0) + return err; + + /* Update setup global descriptors */ + RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0], + &fv->setup, 0, 0, 0, + &fv->consts_buf, + 256*sizeof(uint32_t), 512*sizeof(uint8_t), + VK_FORMAT_UNDEFINED)); + + /* Update encode global descriptors */ + RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0], + &fv->enc, 0, 0, 0, + &fv->consts_buf, + 256*sizeof(uint32_t), 512*sizeof(uint8_t), + VK_FORMAT_UNDEFINED)); + RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0], + &fv->enc, 0, 1, 0, + &fv->consts_buf, + 256*sizeof(uint32_t) + 512*sizeof(uint8_t), + VK_WHOLE_SIZE, + VK_FORMAT_UNDEFINED)); + RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0], + &fv->enc, 0, 2, 0, + &fv->consts_buf, + 0, 256*sizeof(uint32_t), + VK_FORMAT_UNDEFINED)); + + /* Temporary frame */ + fv->frame = av_frame_alloc(); + if (!fv->frame) + return AVERROR(ENOMEM); + + /* Async data pool */ + fv->async_depth = fv->exec_pool.pool_size; + fv->exec_ctx_info = av_calloc(fv->async_depth, sizeof(*fv->exec_ctx_info)); + if (!fv->exec_ctx_info) + return AVERROR(ENOMEM); + for (int i = 0; i < fv->async_depth; i++) + fv->exec_pool.contexts[i].opaque = &fv->exec_ctx_info[i]; + + fv->buf_regions = av_malloc_array(f->max_slice_count, sizeof(*fv->buf_regions)); + if (!fv->buf_regions) + return AVERROR(ENOMEM); + + /* Buffers */ + RET(ff_vk_create_buf(&fv->s, &fv->results_buf, + fv->async_depth*f->max_slice_count*sizeof(uint32_t), + NULL, NULL, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + RET(ff_vk_map_buffer(&fv->s, &fv->results_buf, NULL, 0)); + +fail: + return err; +} + +static av_cold int vulkan_encode_ffv1_close(AVCodecContext *avctx) +{ + VulkanEncodeFFv1Context *fv = avctx->priv_data; + + ff_vk_exec_pool_free(&fv->s, &fv->exec_pool); + ff_vk_exec_pool_free(&fv->s, &fv->transfer_exec_pool); + + ff_vk_shader_free(&fv->s, &fv->enc); + ff_vk_shader_free(&fv->s, &fv->reset); + ff_vk_shader_free(&fv->s, &fv->setup); + ff_vk_shader_free(&fv->s, &fv->rct_search); + + if (fv->exec_ctx_info) { + for (int i = 0; i < fv->async_depth; i++) { + VulkanEncodeFFv1FrameData *fd = &fv->exec_ctx_info[i]; + av_buffer_unref(&fd->out_data_ref); + av_buffer_unref(&fd->frame_opaque_ref); + } + } + av_free(fv->exec_ctx_info); + + av_buffer_unref(&fv->intermediate_frames_ref); + + av_buffer_pool_uninit(&fv->out_data_pool); + + av_buffer_unref(&fv->keyframe_slice_data_ref); + av_buffer_pool_uninit(&fv->slice_data_pool); + + ff_vk_free_buf(&fv->s, &fv->results_buf); + + ff_vk_free_buf(&fv->s, &fv->consts_buf); + + av_free(fv->buf_regions); + av_frame_free(&fv->frame); + ff_vk_uninit(&fv->s); + + return 0; +} + +#define OFFSET(x) offsetof(VulkanEncodeFFv1Context, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption vulkan_encode_ffv1_options[] = { + { "slicecrc", "Protect slices with CRCs", OFFSET(ctx.ec), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 2, VE }, + { "context", "Context model", OFFSET(ctx.context_model), AV_OPT_TYPE_INT, + { .i64 = 0 }, 0, 1, VE }, + { "coder", "Coder type", OFFSET(ctx.ac), AV_OPT_TYPE_INT, + { .i64 = AC_RANGE_CUSTOM_TAB }, -2, 2, VE, .unit = "coder" }, + { "rice", "Golomb rice", 0, AV_OPT_TYPE_CONST, + { .i64 = AC_GOLOMB_RICE }, INT_MIN, INT_MAX, VE, .unit = "coder" }, + { "range_def", "Range with default table", 0, AV_OPT_TYPE_CONST, + { .i64 = AC_RANGE_DEFAULT_TAB_FORCE }, INT_MIN, INT_MAX, VE, .unit = "coder" }, + { "range_tab", "Range with custom table", 0, AV_OPT_TYPE_CONST, + { .i64 = AC_RANGE_CUSTOM_TAB }, INT_MIN, INT_MAX, VE, .unit = "coder" }, + { "qtable", "Quantization table", OFFSET(ctx.qtable), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 2, VE , .unit = "qtable"}, + { "default", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_DEFAULT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + { "8bit", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_8BIT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + { "greater8bit", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_GT8BIT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + + { "slices_h", "Number of horizontal slices", OFFSET(num_h_slices), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, MAX_SLICES, VE }, + { "slices_v", "Number of vertical slices", OFFSET(num_v_slices), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, MAX_SLICES, VE }, + + { "force_pcm", "Code all slices with no prediction", OFFSET(force_pcm), AV_OPT_TYPE_BOOL, + { .i64 = 0 }, 0, 1, VE }, + + { "rct_search", "Run a search for RCT parameters (level 4 only)", OFFSET(optimize_rct), AV_OPT_TYPE_BOOL, + { .i64 = 1 }, 0, 1, VE }, + + { "async_depth", "Internal parallelization depth", OFFSET(async_depth), AV_OPT_TYPE_INT, + { .i64 = 1 }, 1, INT_MAX, VE }, + + { NULL } +}; + +static const FFCodecDefault vulkan_encode_ffv1_defaults[] = { + { "g", "1" }, + { NULL }, +}; + +static const AVClass vulkan_encode_ffv1_class = { + .class_name = "ffv1_vulkan", + .item_name = av_default_item_name, + .option = vulkan_encode_ffv1_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVCodecHWConfigInternal *const vulkan_encode_ffv1_hw_configs[] = { + HW_CONFIG_ENCODER_FRAMES(VULKAN, VULKAN), + NULL, +}; + +const FFCodec ff_ffv1_vulkan_encoder = { + .p.name = "ffv1_vulkan", + CODEC_LONG_NAME("FFmpeg video codec #1 (Vulkan)"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_FFV1, + .priv_data_size = sizeof(VulkanEncodeFFv1Context), + .init = &vulkan_encode_ffv1_init, + FF_CODEC_RECEIVE_PACKET_CB(&vulkan_encode_ffv1_receive_packet), + .close = &vulkan_encode_ffv1_close, + .p.priv_class = &vulkan_encode_ffv1_class, + .p.capabilities = AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_HARDWARE | + AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_ENCODER_FLUSH | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_EOF_FLUSH, + .defaults = vulkan_encode_ffv1_defaults, + CODEC_PIXFMTS(AV_PIX_FMT_VULKAN), + .hw_configs = vulkan_encode_ffv1_hw_configs, + .p.wrapper_name = "vulkan", +}; diff --git a/libavcodec/fic.c b/libavcodec/fic.c index ec26e3154..b3468d751 100644 --- a/libavcodec/fic.c +++ b/libavcodec/fic.c @@ -56,7 +56,6 @@ typedef struct FICContext { int aligned_width, aligned_height; int num_slices, slice_h; - uint8_t cursor_buf[4096]; int skip_cursor; } FICContext; @@ -86,6 +85,7 @@ static const uint8_t fic_header[7] = { 0, 0, 1, 'F', 'I', 'C', 'V' }; #define FIC_HEADER_SIZE 27 #define CURSOR_OFFSET 59 +#define CURSOR_SIZE 4096 static av_always_inline void fic_idct(int16_t *blk, int step, int shift, int rnd) { @@ -214,10 +214,11 @@ static av_always_inline void fic_alpha_blend(uint8_t *dst, uint8_t *src, dst[i] += ((src[i] - dst[i]) * alpha[i]) >> 8; } -static void fic_draw_cursor(AVCodecContext *avctx, int cur_x, int cur_y) +static void fic_draw_cursor(AVCodecContext *avctx, const uint8_t cursor_buf[CURSOR_SIZE], + int cur_x, int cur_y) { FICContext *ctx = avctx->priv_data; - uint8_t *ptr = ctx->cursor_buf; + const uint8_t *ptr = cursor_buf; uint8_t *dstptr[3]; uint8_t planes[4][1024]; uint8_t chroma[3][256]; @@ -281,9 +282,6 @@ static int fic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int skip_cursor = ctx->skip_cursor; const uint8_t *sdata; - if ((ret = ff_reget_buffer(avctx, ctx->frame, 0)) < 0) - return ret; - /* Header + at least one slice (4) */ if (avpkt->size < FIC_HEADER_SIZE + 4) { av_log(avctx, AV_LOG_ERROR, "Frame data is too small.\n"); @@ -296,10 +294,14 @@ static int fic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, /* Is it a skip frame? */ if (src[17]) { - if (!ctx->final_frame) { + if (!ctx->final_frame->data[0]) { av_log(avctx, AV_LOG_WARNING, "Initial frame is skipped\n"); return AVERROR_INVALIDDATA; } + ret = ff_reget_buffer(avctx, ctx->final_frame, + FF_REGET_BUFFER_FLAG_READONLY); + if (ret < 0) + return ret; goto skip; } @@ -346,9 +348,8 @@ static int fic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, skip_cursor = 1; } - if (!skip_cursor && avpkt->size < CURSOR_OFFSET + sizeof(ctx->cursor_buf)) { + if (!skip_cursor && avpkt->size < CURSOR_OFFSET + CURSOR_SIZE) skip_cursor = 1; - } /* Slice height for all but the last slice. */ ctx->slice_h = 16 * (ctx->aligned_height >> 4) / nslices; @@ -403,6 +404,9 @@ static int fic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, ctx->slice_data[slice].y_off = y_off; } + if ((ret = ff_reget_buffer(avctx, ctx->frame, 0)) < 0) + return ret; + if ((ret = avctx->execute(avctx, fic_decode_slice, ctx->slice_data, NULL, nslices, sizeof(ctx->slice_data[0]))) < 0) return ret; @@ -416,29 +420,24 @@ static int fic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, break; } } - av_frame_free(&ctx->final_frame); - ctx->final_frame = av_frame_clone(ctx->frame); - if (!ctx->final_frame) { - av_log(avctx, AV_LOG_ERROR, "Could not clone frame buffer.\n"); - return AVERROR(ENOMEM); - } - - /* Make sure we use a user-supplied buffer. */ - if ((ret = ff_reget_buffer(avctx, ctx->final_frame, 0)) < 0) { - av_log(avctx, AV_LOG_ERROR, "Could not make frame writable.\n"); + ret = av_frame_replace(ctx->final_frame, ctx->frame); + if (ret < 0) return ret; - } - /* Draw cursor. */ + /* Draw cursor if needed. */ if (!skip_cursor) { - memcpy(ctx->cursor_buf, src + CURSOR_OFFSET, sizeof(ctx->cursor_buf)); - fic_draw_cursor(avctx, cur_x, cur_y); + /* Make frame writable. */ + ret = ff_reget_buffer(avctx, ctx->final_frame, 0); + if (ret < 0) + return ret; + + fic_draw_cursor(avctx, src + CURSOR_OFFSET, cur_x, cur_y); } skip: - *got_frame = 1; if ((ret = av_frame_ref(rframe, ctx->final_frame)) < 0) return ret; + *got_frame = 1; return avpkt->size; } @@ -469,6 +468,9 @@ static av_cold int fic_decode_init(AVCodecContext *avctx) ctx->frame = av_frame_alloc(); if (!ctx->frame) return AVERROR(ENOMEM); + ctx->final_frame = av_frame_alloc(); + if (!ctx->final_frame) + return AVERROR(ENOMEM); return 0; } @@ -496,4 +498,5 @@ const FFCodec ff_fic_decoder = { .close = fic_decode_close, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS, .p.priv_class = &fic_decoder_class, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/fitsenc.c b/libavcodec/fitsenc.c index 86ea11f0c..2a3151406 100644 --- a/libavcodec/fitsenc.c +++ b/libavcodec/fitsenc.c @@ -117,11 +117,6 @@ const FFCodec ff_fits_encoder = { .p.id = AV_CODEC_ID_FITS, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(fits_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_GBRAP16BE, - AV_PIX_FMT_GBRP16BE, - AV_PIX_FMT_GBRP, - AV_PIX_FMT_GBRAP, - AV_PIX_FMT_GRAY16BE, - AV_PIX_FMT_GRAY8, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_GBRAP16BE, AV_PIX_FMT_GBRP16BE, AV_PIX_FMT_GBRP, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY8), }; diff --git a/libavcodec/flac_parse.h b/libavcodec/flac_parse.h index b0cbad825..78485b332 100644 --- a/libavcodec/flac_parse.h +++ b/libavcodec/flac_parse.h @@ -58,7 +58,7 @@ typedef struct FLACFrameInfo { * @param[out] s where parsed information is stored * @param[in] buffer pointer to start of 34-byte streaminfo data * - * @return negative error code on faiure or >= 0 on success + * @return negative error code on failure or >= 0 on success */ int ff_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo *s, const uint8_t *buffer); diff --git a/libavcodec/flac_parser.c b/libavcodec/flac_parser.c index d9c47801f..9a5f5fd03 100644 --- a/libavcodec/flac_parser.c +++ b/libavcodec/flac_parser.c @@ -36,6 +36,7 @@ #include "libavutil/crc.h" #include "libavutil/mem.h" #include "flac_parse.h" +#include "parser_internal.h" /** maximum number of adjacent headers that compare CRCs against each other */ #define FLAC_MAX_SEQUENTIAL_HEADERS 4 @@ -887,7 +888,7 @@ static av_cold int flac_parse_init(AVCodecParserContext *c) return 0; } -static void flac_parse_close(AVCodecParserContext *c) +static av_cold void flac_parse_close(AVCodecParserContext *c) { FLACParseContext *fpc = c->priv_data; FLACHeaderMarker *curr = fpc->headers, *temp; @@ -902,10 +903,10 @@ static void flac_parse_close(AVCodecParserContext *c) av_freep(&fpc->wrap_buf); } -const AVCodecParser ff_flac_parser = { - .codec_ids = { AV_CODEC_ID_FLAC }, +const FFCodecParser ff_flac_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_FLAC), .priv_data_size = sizeof(FLACParseContext), - .parser_init = flac_parse_init, - .parser_parse = flac_parse, - .parser_close = flac_parse_close, + .init = flac_parse_init, + .parse = flac_parse, + .close = flac_parse_close, }; diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c index ad921a1bd..0c88f577a 100644 --- a/libavcodec/flacdec.c +++ b/libavcodec/flacdec.c @@ -827,10 +827,7 @@ const FFCodec ff_flac_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P), .p.priv_class = &flac_decoder_class, }; diff --git a/libavcodec/flacdsp.c b/libavcodec/flacdsp.c index f5362bf66..f8b48770f 100644 --- a/libavcodec/flacdsp.c +++ b/libavcodec/flacdsp.c @@ -94,7 +94,7 @@ static void flac_lpc_33_c(int64_t *decoded, const int32_t *residual, int64_t sum = 0; for (j = 0; j < pred_order; j++) sum += (int64_t)coeffs[j] * (uint64_t)decoded[j]; - decoded[j] = residual[i] + (sum >> qlevel); + decoded[j] = (uint64_t)residual[i] + (uint64_t)(sum >> qlevel); } } @@ -154,7 +154,7 @@ av_cold void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt, int cha ff_flacdsp_init_arm(c, fmt, channels); #elif ARCH_RISCV ff_flacdsp_init_riscv(c, fmt, channels); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_flacdsp_init_x86(c, fmt, channels); #endif } diff --git a/libavcodec/flacdsp.h b/libavcodec/flacdsp.h index 3b7b35a11..fb76c55ae 100644 --- a/libavcodec/flacdsp.h +++ b/libavcodec/flacdsp.h @@ -35,10 +35,6 @@ typedef struct FLACDSPContext { void (*wasted32)(int32_t *decoded, int wasted, int len); void (*wasted33)(int64_t *decoded, const int32_t *residual, int wasted, int len); - void (*lpc16_encode)(int32_t *res, const int32_t *smp, int len, int order, - const int32_t coefs[32], int shift); - void (*lpc32_encode)(int32_t *res, const int32_t *smp, int len, int order, - const int32_t coefs[32], int shift); } FLACDSPContext; void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt, int channels); diff --git a/libavcodec/flacenc.c b/libavcodec/flacenc.c index 3a9578f5c..ead2c55f1 100644 --- a/libavcodec/flacenc.c +++ b/libavcodec/flacenc.c @@ -57,7 +57,7 @@ enum CodingMode { typedef struct CompressionOptions { int compression_level; int block_time_ms; - enum FFLPCType lpc_type; + int /* enum FFLPCType */ lpc_type; int lpc_passes; int lpc_coeff_precision; int min_prediction_order; @@ -1172,7 +1172,7 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch) static int count_frame_header(FlacEncodeContext *s) { - uint8_t av_unused tmp; + av_unused uint8_t tmp; int count; /* @@ -1760,9 +1760,7 @@ const FFCodec ff_flac_encoder = { .init = flac_encode_init, FF_CODEC_ENCODE_CB(flac_encode_frame), .close = flac_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), .p.priv_class = &flac_encoder_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_EOF_FLUSH, }; diff --git a/libavcodec/flacencdsp.c b/libavcodec/flacencdsp.c index 46e5a0352..251b3c2d4 100644 --- a/libavcodec/flacencdsp.c +++ b/libavcodec/flacencdsp.c @@ -34,7 +34,7 @@ av_cold void ff_flacencdsp_init(FLACEncDSPContext *c) c->lpc16_encode = flac_lpc_encode_c_16; c->lpc32_encode = flac_lpc_encode_c_32; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_flacencdsp_init_x86(c); #endif } diff --git a/libavcodec/flashsv2enc.c b/libavcodec/flashsv2enc.c index 6156d00d0..17e0bc1b3 100644 --- a/libavcodec/flashsv2enc.c +++ b/libavcodec/flashsv2enc.c @@ -786,7 +786,7 @@ static int optimum_block_height(FlashSV2Context * s) static int optimum_use15_7(FlashSV2Context * s) { #ifndef FLASHSV2_DUMB - double ideal = ((double)(s->avctx->bit_rate * s->avctx->time_base.den * s->avctx->ticks_per_frame)) / + double ideal = ((double)(s->avctx->bit_rate * s->avctx->time_base.den)) / ((double) s->avctx->time_base.num) * s->avctx->frame_num; if (ideal + use15_7_threshold < s->total_bits) { return 1; @@ -802,8 +802,7 @@ static int optimum_dist(FlashSV2Context * s) { #ifndef FLASHSV2_DUMB double ideal = - s->avctx->bit_rate * s->avctx->time_base.den * - s->avctx->ticks_per_frame; + s->avctx->bit_rate * s->avctx->time_base.den; int dist = pow((s->total_bits / ideal) * color15_7_factor, 3); av_log(s->avctx, AV_LOG_DEBUG, "dist: %d\n", dist); return dist; @@ -920,6 +919,6 @@ const FFCodec ff_flashsv2_encoder = { .init = flashsv2_encode_init, FF_CODEC_ENCODE_CB(flashsv2_encode_frame), .close = flashsv2_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/flashsvenc.c b/libavcodec/flashsvenc.c index 5cf0602f5..bd4c8651e 100644 --- a/libavcodec/flashsvenc.c +++ b/libavcodec/flashsvenc.c @@ -67,6 +67,7 @@ typedef struct FlashSVContext { unsigned packet_size; int64_t last_key_frame; uint8_t tmpblock[3 * 256 * 256]; + int compression_level; } FlashSVContext; static int copy_region_enc(const uint8_t *sptr, uint8_t *dptr, int dx, int dy, @@ -121,6 +122,10 @@ static av_cold int flashsv_encode_init(AVCodecContext *avctx) nb_blocks = h_blocks * v_blocks; s->packet_size = 4 + nb_blocks * (2 + 3 * BLOCK_WIDTH * BLOCK_HEIGHT); + s->compression_level = avctx->compression_level == FF_COMPRESSION_DEFAULT + ? Z_DEFAULT_COMPRESSION + : av_clip(avctx->compression_level, 0, 9); + return 0; } @@ -170,9 +175,10 @@ static int encode_bitstream(FlashSVContext *s, const AVFrame *p, uint8_t *buf, p->linesize[0], previous_frame); if (res || *I_frame) { - unsigned long zsize = 3 * block_width * block_height; + unsigned long zsize = 3 * block_width * block_height + 12; ret = compress2(ptr + 2, &zsize, s->tmpblock, - 3 * cur_blk_width * cur_blk_height, 9); + 3 * cur_blk_width * cur_blk_height, + s->compression_level); if (ret != Z_OK) av_log(s->avctx, AV_LOG_ERROR, @@ -256,5 +262,5 @@ const FFCodec ff_flashsv_encoder = { .init = flashsv_encode_init, FF_CODEC_ENCODE_CB(flashsv_encode_frame), .close = flashsv_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24), }; diff --git a/libavcodec/flicvideo.c b/libavcodec/flicvideo.c index 43f3f83bf..f17e61a9f 100644 --- a/libavcodec/flicvideo.c +++ b/libavcodec/flicvideo.c @@ -682,11 +682,6 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, /* make the palette available on the way out */ memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); if (s->new_palette) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif s->new_palette = 0; } diff --git a/libavcodec/vulkan.h b/libavcodec/float_scalarproduct.c similarity index 87% rename from libavcodec/vulkan.h rename to libavcodec/float_scalarproduct.c index b15efd4ad..647f0ec72 100644 --- a/libavcodec/vulkan.h +++ b/libavcodec/float_scalarproduct.c @@ -16,9 +16,4 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VULKAN_H -#define AVCODEC_VULKAN_H - -#include "libavutil/vulkan.h" - -#endif /* AVCODEC_VULKAN_H */ +#include "libavutil/float_scalarproduct.c" diff --git a/libavcodec/flvdec.c b/libavcodec/flvdec.c index f4bfd9941..0f6eaad5c 100644 --- a/libavcodec/flvdec.c +++ b/libavcodec/flvdec.c @@ -26,31 +26,31 @@ #include "mpegvideo.h" #include "mpegvideodec.h" -int ff_flv_decode_picture_header(MpegEncContext *s) +int ff_flv_decode_picture_header(H263DecContext *const h) { int format, width, height; /* picture header */ - if (get_bits(&s->gb, 17) != 1) { - av_log(s->avctx, AV_LOG_ERROR, "Bad picture start code\n"); + if (get_bits(&h->gb, 17) != 1) { + av_log(h->c.avctx, AV_LOG_ERROR, "Bad picture start code\n"); return AVERROR_INVALIDDATA; } - format = get_bits(&s->gb, 5); + format = get_bits(&h->gb, 5); if (format != 0 && format != 1) { - av_log(s->avctx, AV_LOG_ERROR, "Bad picture format\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Bad picture format\n"); return AVERROR_INVALIDDATA; } - s->h263_flv = format + 1; - s->picture_number = get_bits(&s->gb, 8); /* picture timestamp */ - format = get_bits(&s->gb, 3); + h->flv = format; + h->picture_number = get_bits(&h->gb, 8); /* picture timestamp */ + format = get_bits(&h->gb, 3); switch (format) { case 0: - width = get_bits(&s->gb, 8); - height = get_bits(&s->gb, 8); + width = get_bits(&h->gb, 8); + height = get_bits(&h->gb, 8); break; case 1: - width = get_bits(&s->gb, 16); - height = get_bits(&s->gb, 16); + width = get_bits(&h->gb, 16); + height = get_bits(&h->gb, 16); break; case 2: width = 352; @@ -76,36 +76,32 @@ int ff_flv_decode_picture_header(MpegEncContext *s) width = height = 0; break; } - if (av_image_check_size(width, height, 0, s->avctx)) + if (av_image_check_size(width, height, 0, h->c.avctx)) return AVERROR(EINVAL); - s->width = width; - s->height = height; + h->c.width = width; + h->c.height = height; - s->pict_type = AV_PICTURE_TYPE_I + get_bits(&s->gb, 2); - s->droppable = s->pict_type > AV_PICTURE_TYPE_P; - if (s->droppable) - s->pict_type = AV_PICTURE_TYPE_P; + h->c.pict_type = AV_PICTURE_TYPE_I + get_bits(&h->gb, 2); + h->c.droppable = h->c.pict_type > AV_PICTURE_TYPE_P; + if (h->c.droppable) + h->c.pict_type = AV_PICTURE_TYPE_P; - skip_bits1(&s->gb); /* deblocking flag */ - s->chroma_qscale = s->qscale = get_bits(&s->gb, 5); + skip_bits1(&h->gb); /* deblocking flag */ + h->c.chroma_qscale = h->c.qscale = get_bits(&h->gb, 5); - s->h263_plus = 0; - - s->h263_long_vectors = 0; + h->h263_long_vectors = 0; /* PEI */ - if (skip_1stop_8data_bits(&s->gb) < 0) + if (skip_1stop_8data_bits(&h->gb) < 0) return AVERROR_INVALIDDATA; - s->f_code = 1; + if (h->ehc_mode) + h->c.avctx->sample_aspect_ratio= (AVRational){1,2}; - if (s->ehc_mode) - s->avctx->sample_aspect_ratio= (AVRational){1,2}; - - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, "%c esc_type:%d, qp:%d num:%d\n", - s->droppable ? 'D' : av_get_picture_type_char(s->pict_type), - s->h263_flv - 1, s->qscale, s->picture_number); + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "%c esc_type:%d, qp:%d num:%d\n", + h->c.droppable ? 'D' : av_get_picture_type_char(h->c.pict_type), + h->flv, h->c.qscale, h->picture_number); } return 0; @@ -116,7 +112,7 @@ const FFCodec ff_flv_decoder = { CODEC_LONG_NAME("FLV / Sorenson Spark / Sorenson H.263 (Flash Video)"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_FLV1, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(H263DecContext), .init = ff_h263_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, diff --git a/libavcodec/flvdec.h b/libavcodec/flvdec.h index d5aff74a9..e0f6d299c 100644 --- a/libavcodec/flvdec.h +++ b/libavcodec/flvdec.h @@ -21,8 +21,8 @@ #ifndef AVCODEC_FLVDEC_H #define AVCODEC_FLVDEC_H -#include "mpegvideo.h" +struct H263DecContext; -int ff_flv_decode_picture_header(MpegEncContext *s); +int ff_flv_decode_picture_header(struct H263DecContext *const h); #endif /* AVCODEC_FLVDEC_H */ diff --git a/libavcodec/flvenc.c b/libavcodec/flvenc.c index 40eec07b3..0b6e73b11 100644 --- a/libavcodec/flvenc.c +++ b/libavcodec/flvenc.c @@ -20,76 +20,51 @@ #include "codec_internal.h" #include "flvenc.h" -#include "h263data.h" #include "mpegvideo.h" -#include "mpegvideodata.h" #include "mpegvideoenc.h" +#include "put_bits.h" -void ff_flv_encode_picture_header(MpegEncContext *s) +int ff_flv_encode_picture_header(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int format; - align_put_bits(&s->pb); + put_bits_assume_flushed(&s->pb); put_bits(&s->pb, 17, 1); /* 0: H.263 escape codes 1: 11-bit escape codes */ - put_bits(&s->pb, 5, (s->h263_flv - 1)); + put_bits(&s->pb, 5, 1); put_bits(&s->pb, 8, - (((int64_t) s->picture_number * 30 * s->avctx->time_base.num) / // FIXME use timestamp - s->avctx->time_base.den) & 0xff); /* TemporalReference */ - if (s->width == 352 && s->height == 288) + (((int64_t) s->picture_number * 30 * s->c.avctx->time_base.num) / // FIXME use timestamp + s->c.avctx->time_base.den) & 0xff); /* TemporalReference */ + if (s->c.width == 352 && s->c.height == 288) format = 2; - else if (s->width == 176 && s->height == 144) + else if (s->c.width == 176 && s->c.height == 144) format = 3; - else if (s->width == 128 && s->height == 96) + else if (s->c.width == 128 && s->c.height == 96) format = 4; - else if (s->width == 320 && s->height == 240) + else if (s->c.width == 320 && s->c.height == 240) format = 5; - else if (s->width == 160 && s->height == 120) + else if (s->c.width == 160 && s->c.height == 120) format = 6; - else if (s->width <= 255 && s->height <= 255) + else if (s->c.width <= 255 && s->c.height <= 255) format = 0; /* use 1 byte width & height */ else format = 1; /* use 2 bytes width & height */ put_bits(&s->pb, 3, format); /* PictureSize */ if (format == 0) { - put_bits(&s->pb, 8, s->width); - put_bits(&s->pb, 8, s->height); + put_bits(&s->pb, 8, s->c.width); + put_bits(&s->pb, 8, s->c.height); } else if (format == 1) { - put_bits(&s->pb, 16, s->width); - put_bits(&s->pb, 16, s->height); + put_bits(&s->pb, 16, s->c.width); + put_bits(&s->pb, 16, s->c.height); } - put_bits(&s->pb, 2, s->pict_type == AV_PICTURE_TYPE_P); /* PictureType */ + put_bits(&s->pb, 2, s->c.pict_type == AV_PICTURE_TYPE_P); /* PictureType */ put_bits(&s->pb, 1, 1); /* DeblockingFlag: on */ - put_bits(&s->pb, 5, s->qscale); /* Quantizer */ + put_bits(&s->pb, 5, s->c.qscale); /* Quantizer */ put_bits(&s->pb, 1, 0); /* ExtraInformation */ - if (s->h263_aic) { - s->y_dc_scale_table = - s->c_dc_scale_table = ff_aic_dc_scale_table; - } else { - s->y_dc_scale_table = - s->c_dc_scale_table = ff_mpeg1_dc_scale_table; - } -} - -void ff_flv2_encode_ac_esc(PutBitContext *pb, int slevel, int level, - int run, int last) -{ - if (level < 64) { // 7-bit level - put_bits(pb, 1, 0); - put_bits(pb, 1, last); - put_bits(pb, 6, run); - - put_sbits(pb, 7, slevel); - } else { - /* 11-bit level */ - put_bits(pb, 1, 1); - put_bits(pb, 1, last); - put_bits(pb, 6, run); - - put_sbits(pb, 11, slevel); - } + return 0; } const FFCodec ff_flv_encoder = { @@ -98,13 +73,12 @@ const FFCodec ff_flv_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_FLV1, .p.priv_class = &ff_mpv_enc_class, - .priv_data_size = sizeof(MpegEncContext), + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .priv_data_size = sizeof(MPVMainEncContext), .init = ff_mpv_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, }; diff --git a/libavcodec/flvenc.h b/libavcodec/flvenc.h index 1ecbb46b1..a244145e4 100644 --- a/libavcodec/flvenc.h +++ b/libavcodec/flvenc.h @@ -21,11 +21,8 @@ #ifndef AVCODEC_FLVENC_H #define AVCODEC_FLVENC_H -#include "mpegvideo.h" -#include "put_bits.h" +typedef struct MPVMainEncContext MPVMainEncContext; -void ff_flv_encode_picture_header(MpegEncContext *s); -void ff_flv2_encode_ac_esc(PutBitContext *pb, int slevel, int level, int run, - int last); +int ff_flv_encode_picture_header(MPVMainEncContext *const m); #endif /* AVCODEC_FLV_H */ diff --git a/libavcodec/fmtconvert.c b/libavcodec/fmtconvert.c index d889e61ac..77d69f821 100644 --- a/libavcodec/fmtconvert.c +++ b/libavcodec/fmtconvert.c @@ -54,7 +54,7 @@ av_cold void ff_fmt_convert_init(FmtConvertContext *c) ff_fmt_convert_init_ppc(c); #elif ARCH_RISCV ff_fmt_convert_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_fmt_convert_init_x86(c); #endif #if HAVE_MIPSFPU diff --git a/libavcodec/ftr.c b/libavcodec/ftr.c index 7cf1b1586..31aef538f 100644 --- a/libavcodec/ftr.c +++ b/libavcodec/ftr.c @@ -22,6 +22,8 @@ #include "get_bits.h" #include "decode.h" +#include "libavutil/attributes.h" + typedef struct FTRContext { AVCodecContext *aac_avctx[64]; // wrapper context for AAC int nb_context; @@ -51,7 +53,7 @@ static av_cold int ftr_init(AVCodecContext *avctx) codec = avcodec_find_decoder(AV_CODEC_ID_AAC); if (!codec) - return AVERROR_BUG; + return AVERROR_DECODER_NOT_FOUND; for (int i = 0; i < s->nb_context; i++) { s->aac_avctx[i] = avcodec_alloc_context3(codec); @@ -173,7 +175,7 @@ static int ftr_decode_frame(AVCodecContext *avctx, AVFrame *frame, return get_bits_count(&gb) >> 3; } -static void ftr_flush(AVCodecContext *avctx) +static av_cold void ftr_flush(AVCodecContext *avctx) { FTRContext *s = avctx->priv_data; @@ -203,10 +205,6 @@ const FFCodec ff_ftr_decoder = { .close = ftr_close, .flush = ftr_flush, .priv_data_size = sizeof(FTRContext), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, + .p.capabilities = AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/ftr_parser.c b/libavcodec/ftr_parser.c index 656fd289f..a45edcf45 100644 --- a/libavcodec/ftr_parser.c +++ b/libavcodec/ftr_parser.c @@ -28,6 +28,7 @@ #include "adts_header.h" #include "adts_parser.h" #include "mpeg4audio.h" +#include "parser_internal.h" typedef struct FTRParseContext { ParseContext pc; @@ -96,9 +97,9 @@ static int ftr_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_ftr_parser = { - .codec_ids = { AV_CODEC_ID_FTR }, +const FFCodecParser ff_ftr_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_FTR), .priv_data_size = sizeof(FTRParseContext), - .parser_parse = ftr_parse, - .parser_close = ff_parse_close, + .parse = ftr_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/g2meet.c b/libavcodec/g2meet.c index f952a06f1..a4900641e 100644 --- a/libavcodec/g2meet.c +++ b/libavcodec/g2meet.c @@ -890,7 +890,7 @@ static int epic_jb_decode_tile(G2MContext *c, int tile_x, int tile_y, } if (src_size < els_dsize) { - av_log(avctx, AV_LOG_ERROR, "ePIC: data too short, needed %"SIZE_SPECIFIER", got %"SIZE_SPECIFIER"\n", + av_log(avctx, AV_LOG_ERROR, "ePIC: data too short, needed %zu, got %zu\n", els_dsize, src_size); return AVERROR_INVALIDDATA; } diff --git a/libavcodec/g722dec.c b/libavcodec/g722dec.c index 231f1d32e..cc89737b3 100644 --- a/libavcodec/g722dec.c +++ b/libavcodec/g722dec.c @@ -63,6 +63,8 @@ static av_cold int g722_decode_init(AVCodecContext * avctx) av_channel_layout_uninit(&avctx->ch_layout); avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; avctx->sample_fmt = AV_SAMPLE_FMT_S16; + if (!avctx->sample_rate) + avctx->sample_rate = 16000; c->band[0].scale_factor = 8; c->band[1].scale_factor = 2; diff --git a/libavcodec/g722dsp.c b/libavcodec/g722dsp.c index 302283688..5807635ce 100644 --- a/libavcodec/g722dsp.c +++ b/libavcodec/g722dsp.c @@ -73,7 +73,7 @@ av_cold void ff_g722dsp_init(G722DSPContext *c) ff_g722dsp_init_arm(c); #elif ARCH_RISCV ff_g722dsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_g722dsp_init_x86(c); #endif } diff --git a/libavcodec/g722enc.c b/libavcodec/g722enc.c index 19ab0f8b5..fc3db7cc8 100644 --- a/libavcodec/g722enc.c +++ b/libavcodec/g722enc.c @@ -382,9 +382,7 @@ const FFCodec ff_adpcm_g722_encoder = { .init = g722_encode_init, .close = g722_encode_close, FF_CODEC_ENCODE_CB(g722_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]){ - AV_CHANNEL_LAYOUT_MONO, { 0 } - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/g723_1_parser.c b/libavcodec/g723_1_parser.c index 2ed1a8ab1..e2fba33ca 100644 --- a/libavcodec/g723_1_parser.c +++ b/libavcodec/g723_1_parser.c @@ -23,6 +23,7 @@ #include "parser.h" #include "g723_1.h" +#include "parser_internal.h" typedef struct G723_1ParseContext { ParseContext pc; @@ -52,9 +53,9 @@ static int g723_1_parse(AVCodecParserContext *s1, AVCodecContext *avctx, return next; } -const AVCodecParser ff_g723_1_parser = { - .codec_ids = { AV_CODEC_ID_G723_1 }, +const FFCodecParser ff_g723_1_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_G723_1), .priv_data_size = sizeof(G723_1ParseContext), - .parser_parse = g723_1_parse, - .parser_close = ff_parse_close, + .parse = g723_1_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/g723_1dec.c b/libavcodec/g723_1dec.c index 5fe4a21d9..67a5df55f 100644 --- a/libavcodec/g723_1dec.c +++ b/libavcodec/g723_1dec.c @@ -1118,10 +1118,6 @@ const FFCodec ff_g723_1_decoder = { .priv_data_size = sizeof(G723_1_Context), .init = g723_1_decode_init, FF_CODEC_DECODE_CB(g723_1_decode_frame), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, + .p.capabilities = AV_CODEC_CAP_DR1, .p.priv_class = &g723_1dec_class, }; diff --git a/libavcodec/g723_1enc.c b/libavcodec/g723_1enc.c index d686c4bef..4fd4567a8 100644 --- a/libavcodec/g723_1enc.c +++ b/libavcodec/g723_1enc.c @@ -1246,10 +1246,6 @@ const FFCodec ff_g723_1_encoder = { .init = g723_1_encode_init, FF_CODEC_ENCODE_CB(g723_1_encode_frame), .defaults = defaults, - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE - }, - .p.ch_layouts = (const AVChannelLayout[]){ - AV_CHANNEL_LAYOUT_MONO, { 0 } - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), }; diff --git a/libavcodec/g726.c b/libavcodec/g726.c index b1be487f7..f41df3073 100644 --- a/libavcodec/g726.c +++ b/libavcodec/g726.c @@ -410,8 +410,7 @@ const FFCodec ff_adpcm_g726_encoder = { .priv_data_size = sizeof(G726Context), .init = g726_encode_init, FF_CODEC_ENCODE_CB(g726_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.priv_class = &g726_class, .defaults = defaults, }; @@ -428,8 +427,7 @@ const FFCodec ff_adpcm_g726le_encoder = { .priv_data_size = sizeof(G726Context), .init = g726_encode_init, FF_CODEC_ENCODE_CB(g726_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.priv_class = &g726_class, .defaults = defaults, }; diff --git a/libavcodec/g728_template.c b/libavcodec/g728_template.c new file mode 100644 index 000000000..dd1b1a441 --- /dev/null +++ b/libavcodec/g728_template.c @@ -0,0 +1,65 @@ +/* + * G.728 / RealAudio 2.0 (28.8K) decoder + * + * 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 + */ + +static void convolve(float *tgt, const float *src, int len, int n) +{ + for (; n >= 0; n--) + tgt[n] = ff_scalarproduct_float_c(src, src - n, len); + +} + +/** + * Hybrid window filtering, see blocks 36 and 49 of the G.728 specification. + * + * @param order filter order + * @param n input length + * @param non_rec number of non-recursive samples + * @param out filter output + * @param hist pointer to the input history of the filter + * @param out pointer to the non-recursive part of the output + * @param out2 pointer to the recursive part of the output + * @param window pointer to the windowing function table + */ +static void do_hybrid_window(void (*vector_fmul)(float *dst, const float *src0, const float *src1, int len), + int order, int n, int non_rec, float *out, + const float *hist, float *out2, const float *window) +{ + int i; + float buffer1[MAX_BACKWARD_FILTER_ORDER + 1]; + float buffer2[MAX_BACKWARD_FILTER_ORDER + 1]; + LOCAL_ALIGNED(32, float, work, [FFALIGN(MAX_BACKWARD_FILTER_ORDER + + MAX_BACKWARD_FILTER_LEN + + MAX_BACKWARD_FILTER_NONREC, 16)]); + + av_assert2(order>=0); + + vector_fmul(work, window, hist, FFALIGN(order + n + non_rec, 16)); + + convolve(buffer1, work + order , n , order); + convolve(buffer2, work + order + n, non_rec, order); + + for (i=0; i <= order; i++) { + out2[i] = out2[i] * ATTEN + buffer1[i]; + out [i] = out2[i] + buffer2[i]; + } + + /* Multiply by the white noise correcting factor (WNCF). */ + *out *= 257.0 / 256.0; +} diff --git a/libavcodec/g728data.h b/libavcodec/g728data.h new file mode 100644 index 000000000..a2ddf5682 --- /dev/null +++ b/libavcodec/g728data.h @@ -0,0 +1,70 @@ +/* + * G.728 decoder + * + * 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_G728DATA_H +#define AVCODEC_G728DATA_H + +#include +#include "libavutil/macros.h" + +#define IDIM 5 /* Vector dimension (excitation block size) */ +#define LPC 50 /* Synthesis filter order */ +#define LPCLG 10 /* Log-gain predictor order */ +#define NFRSZ 20 /* Frame size (adaptation cycle size in samples */ +#define NONR 35 /* Number of non-recursive window samples for synthesis filter */ +#define NONRLG 20 /* Number of non-recursive window samples for log-gain predictor */ +#define NUPDATE 4 /* Predictor update period (in terms of vectors) */ + +#define NSBSZ (LPC + NONR + NFRSZ) +#define NSBGSZ (LPCLG + NONRLG + NUPDATE) + +// Hybrid window for the synthesis filter +static const uint16_t g728_wnr[NSBSZ] = { + 1565, 3127, 4681, 6225, 7755, 9266, 10757, 12223, 13661, 15068, + 16441, 17776, 19071, 20322, 21526, 22682, 23786, 24835, 25828, 26761, + 27634, 28444, 29188, 29866, 30476, 31016, 31486, 31884, 32208, 32460, + 32637, 32739, 32767, 32721, 32599, 32403, 32171, 31940, 31711, 31484, + 31259, 31034, 30812, 30591, 30372, 30154, 29938, 29724, 29511, 29299, + 29089, 28881, 28674, 28468, 28264, 28062, 27861, 27661, 27463, 27266, + 27071, 26877, 26684, 26493, 26303, 26114, 25927, 25742, 25557, 25374, + 25192, 25012, 24832, 24654, 24478, 24302, 24128, 23955, 23784, 23613, + 23444, 23276, 23109, 22943, 22779, 22616, 22454, 22293, 22133, 21974, + 21817, 21661, 21505, 21351, 21198, 21046, 20896, 20746, 20597, 20450, + 20303, 20157, 20013, 19870, 19727 +}; + +// Hybrid window for the log-gain predictor +static const uint16_t g728_wnrg[NSBGSZ] = { + 3026, 6025, 8973, 11845, 14615, 17261, 19759, 22088, 24228, 26162, + 27872, 29344, 30565, 31525, 32216, 32631, 32767, 32625, 32203, 31506, + 30540, 29461, 28420, 27416, 26448, 25514, 24613, 23743, 22905, 22096, + 21315, 20562, 19836, 19135 +}; + +// Values for bandwidth broadcasting +static const uint16_t g728_facv[LPC] = { + 16192, 16002, 15815, 15629, 15446, 15265, 15086, 14910, 14735, 14562, + 14391, 14223, 14056, 13891, 13729, 13568, 13409, 13252, 13096, 12943, + 12791, 12641, 12493, 12347, 12202, 12059, 11918, 11778, 11640, 11504, + 11369, 11236, 11104, 10974, 10845, 10718, 10593, 10468, 10346, 10225, + 10105, 9986, 9869, 9754, 9639, 9526, 9415, 9304, 9195, 9088 +}; + +#endif /* AVCODEC_G728DATA_H */ diff --git a/libavcodec/g728dec.c b/libavcodec/g728dec.c new file mode 100644 index 000000000..6403bcae4 --- /dev/null +++ b/libavcodec/g728dec.c @@ -0,0 +1,220 @@ +/* + * G.728 decoder + * Copyright (c) 2025 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 + */ + +#include "avcodec.h" +#include "celp_filters.h" +#include "codec_internal.h" +#include "decode.h" +#include "get_bits.h" +#include "g728data.h" +#include "lpc_functions.h" +#include "ra288.h" +#include "libavutil/float_dsp.h" +#include "libavutil/mem.h" +#include "libavutil/mem_internal.h" +#include "libavutil/opt.h" +#include "libavutil/thread.h" + +#define MAX_BACKWARD_FILTER_ORDER LPC +#define MAX_BACKWARD_FILTER_LEN NFRSZ +#define MAX_BACKWARD_FILTER_NONREC NONR +#define ATTEN 0.75f +#include "g728_template.c" + +#define LPCW 10 /* Perceptual weighting filter order */ +#define GOFF 32.0f /* Log-gain offset value */ + +static float g728_gq_db[8]; +static float g728_y_db[128]; +static DECLARE_ALIGNED(32, float, g728_wnr_r)[FFALIGN(NSBSZ,16)]; +static DECLARE_ALIGNED(32, float, g728_wnrg_r)[FFALIGN(NSBGSZ, 16)]; +static DECLARE_ALIGNED(32, float, g728_facv_f)[FFALIGN(LPC, 16)]; + +static av_cold void g728_init_static_data(void) +{ + for(int i = 0; i < FF_ARRAY_ELEMS(amptable); i++) + g728_gq_db[i] = 10.0f*log10f(amptable[i] * amptable[i]); + + for (int i = 0; i < FF_ARRAY_ELEMS(codetable); i++) { + float cby[IDIM]; + for (int j = 0; j < IDIM; j++) + cby[j] = codetable[i][j] * (1.0f/(1<<11)); + g728_y_db[i] = 10.0f*log10f(ff_scalarproduct_float_c(cby, cby, IDIM) / IDIM); + } + + for (int i = 0; i < NSBSZ; i++) + g728_wnr_r[i] = g728_wnr[NSBSZ - 1 - i] * (1.0f/(1<<15)); + for (int i = 0; i < NSBGSZ; i++) + g728_wnrg_r[i] = g728_wnrg[NSBGSZ - 1 - i] * (1.0f/(1<<15)); + for (int i = 0; i < LPC; i++) + g728_facv_f[i] = g728_facv[i] * (1.0f/(1<<14)); +} + +typedef struct { + AVFloatDSPContext *fdsp; + int valid; + float a[LPC]; + DECLARE_ALIGNED(32, float, sb)[NSBSZ]; + DECLARE_ALIGNED(32, float, sbg)[NSBGSZ]; + DECLARE_ALIGNED(32, float, gp)[FFALIGN(LPCLG, 16)]; + DECLARE_ALIGNED(32, float, atmp)[FFALIGN(LPC, 16)]; + float rexp[LPC + 1]; + float rexpg[LPCLG + 1]; + float r[LPC + 1]; + float alpha; +} G728Context; + +static av_cold int g728_decode_init(AVCodecContext *avctx) +{ + static AVOnce init_static_once = AV_ONCE_INIT; + G728Context *s = avctx->priv_data; + + s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); + if (!s->fdsp) + return AVERROR(ENOMEM); + + s->gp[0] = -1.0f; + for (int i = 0; i < NUPDATE; i++) + s->sbg[NSBGSZ - 1 -i] = -GOFF; + + avctx->sample_fmt = AV_SAMPLE_FMT_FLT; + if (!avctx->sample_rate) + avctx->sample_rate = 8000; + + av_channel_layout_uninit(&avctx->ch_layout); + avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; + + ff_thread_once(&init_static_once, g728_init_static_data); + return 0; +} + +static av_cold int g728_decode_close(AVCodecContext *avctx) +{ + G728Context *s = avctx->priv_data; + av_freep(&s->fdsp); + return 0; +} + +static int hybrid_window(AVFloatDSPContext *fdsp, + int order, int n, int non_rec, float *out, + const float *hist, float *out2, const float *window) +{ + do_hybrid_window(fdsp->vector_fmul, order, n, non_rec, out, hist, out2, window); + return out[order] != 0.0f; +} + +static void decode_frame(G728Context *s, GetBitContext *gb, float *dst) +{ + float *gstate = s->sbg + NSBGSZ - 2; + + for (int idx = 0; idx < NUPDATE; idx++) { + DECLARE_ALIGNED(32, float, et)[IDIM]; + float *statelpc = s->sb + NSBSZ - NFRSZ + idx*IDIM; + float gain, gain_db; + int is, ig; + + gain_db = 0.0f; + for (int i = 0; i < LPCLG; i++) + gain_db -= s->gp[i] * gstate[-i]; + gain_db = av_clipf(gain_db, -GOFF, 28.0f); + + is = get_bits(gb, 7); // shape index + ig = get_bits(gb, 3); // gain index + + gain = powf(10.0f, (gain_db + GOFF) * .05f) * amptable[ig] * (1.0f/(1<<11)); + for (int i = 0; i < IDIM; i++) + et[i] = codetable[is][i] * gain; + + ff_celp_lp_synthesis_filterf(statelpc, s->a, et, IDIM, LPC); + + for (int i = 0; i < IDIM; i++) { + statelpc[i] = av_clipf(statelpc[i], -4095.0f, 4095.0f); + dst[idx*IDIM + i] = statelpc[i] * (1.0f/(1<<12)); + } + + gstate++; + *gstate = FFMAX(-GOFF, g728_gq_db[ig] + g728_y_db[is] + gain_db); + + if (idx == 0) { + DECLARE_ALIGNED(32, float, gptmp)[FFALIGN(LPCLG, 16)]; + if (s->valid && (s->valid = !compute_lpc_coefs(s->r + 1, LPCW, LPC, s->atmp, 0, 0, 1, &s->alpha))) { + s->fdsp->vector_fmul(s->atmp, s->atmp, g728_facv_f, FFALIGN(LPC, 16)); + } + if (hybrid_window(s->fdsp, LPCLG, NUPDATE, NONRLG, s->r, s->sbg, s->rexpg, g728_wnrg_r) && + !compute_lpc_coefs(s->r, 0, LPCLG, gptmp, 0, 0, 1, &s->alpha)) { + s->fdsp->vector_fmul(s->gp, gptmp, gain_bw_tab, FFALIGN(LPCLG, 16)); + } + memmove(s->sbg, s->sbg + NUPDATE, sizeof(float)*(LPCLG + NONRLG)); + gstate = s->sbg + NSBGSZ - 1 - NUPDATE; + } else if (idx == 1) { + if (s->valid) + memcpy(s->a, s->atmp, sizeof(float)*LPC); + } + } + + s->valid = 0; + if (hybrid_window(s->fdsp, LPC, NFRSZ, NONR, s->r, s->sb, s->rexp, g728_wnr_r)) { + s->valid = !compute_lpc_coefs(s->r, 0, LPCW, s->atmp, 0, 0, 1, &s->alpha); + } + + memmove(s->sb, s->sb + NFRSZ, sizeof(float)*(LPC + NONR)); +} + +static int g728_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, AVPacket *avpkt) +{ + G728Context *s = avctx->priv_data; + GetBitContext gb; + int ret; + int nb_frames = avpkt->size / 5; + + if (!nb_frames) + return AVERROR_INVALIDDATA; + + if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0) + return ret; + +#define SAMPLES_PER_FRAME 20 + + frame->nb_samples = nb_frames * SAMPLES_PER_FRAME; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + for (int i = 0; i < nb_frames; i++) + decode_frame(s, &gb, (float *)frame->data[0] + i * 20); + + *got_frame_ptr = 1; + + return nb_frames * 5; +} + +const FFCodec ff_g728_decoder = { + .p.name = "g728", + CODEC_LONG_NAME("G.728)"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_G728, + .priv_data_size = sizeof(G728Context), + .init = g728_decode_init, + .close = g728_decode_close, + FF_CODEC_DECODE_CB(g728_decode_frame), + .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | + AV_CODEC_CAP_DR1, +}; diff --git a/libavcodec/g729_parser.c b/libavcodec/g729_parser.c index d51a78877..5e085aab2 100644 --- a/libavcodec/g729_parser.c +++ b/libavcodec/g729_parser.c @@ -27,6 +27,7 @@ #include "parser.h" #include "g729.h" +#include "parser_internal.h" typedef struct G729ParseContext { ParseContext pc; @@ -84,9 +85,9 @@ static int g729_parse(AVCodecParserContext *s1, AVCodecContext *avctx, return next; } -const AVCodecParser ff_g729_parser = { - .codec_ids = { AV_CODEC_ID_G729, AV_CODEC_ID_ACELP_KELVIN }, +const FFCodecParser ff_g729_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_G729, AV_CODEC_ID_ACELP_KELVIN), .priv_data_size = sizeof(G729ParseContext), - .parser_parse = g729_parse, - .parser_close = ff_parse_close, + .parse = g729_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/g729dec.c b/libavcodec/g729dec.c index bf10a6dd3..7499ed744 100644 --- a/libavcodec/g729dec.c +++ b/libavcodec/g729dec.c @@ -761,11 +761,7 @@ const FFCodec ff_g729_decoder = { .init = decoder_init, FF_CODEC_DECODE_CB(decode_frame), .close = decode_close, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, + .p.capabilities = AV_CODEC_CAP_DR1, }; const FFCodec ff_acelp_kelvin_decoder = { @@ -777,9 +773,5 @@ const FFCodec ff_acelp_kelvin_decoder = { .init = decoder_init, FF_CODEC_DECODE_CB(decode_frame), .close = decode_close, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, + .p.capabilities = AV_CODEC_CAP_DR1, }; diff --git a/libavcodec/g729postfilter.c b/libavcodec/g729postfilter.c index b1880b2fe..824253477 100644 --- a/libavcodec/g729postfilter.c +++ b/libavcodec/g729postfilter.c @@ -211,8 +211,8 @@ static int16_t long_term_filter(AudioDSPContext *adsp, int pitch_delay_int, /* Compute signals with non-integer delay k (with 1/8 precision), where k is in [0;6] range. Entire delay is qual to best_delay+(k+1)/8 - This is archieved by applying an interpolation filter of - legth 33 to source signal. */ + This is achieved by applying an interpolation filter of + length 33 to source signal. */ for (k = 0; k < ANALYZED_FRAC_DELAYS; k++) { ff_acelp_interpolate(&delayed_signal[k][0], &sig_scaled[RES_PREV_DATA_SIZE - best_delay_int], diff --git a/libavcodec/gemdec.c b/libavcodec/gemdec.c index 5ece2e2ee..07f01a24a 100644 --- a/libavcodec/gemdec.c +++ b/libavcodec/gemdec.c @@ -182,11 +182,6 @@ static int gem_decode_frame(AVCodecContext *avctx, AVFrame *p, p->pict_type = AV_PICTURE_TYPE_I; p->flags |= AV_FRAME_FLAG_KEY; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - p->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif palette = (uint32_t *)p->data[1]; if (tag == AV_RB32("STTT")) { diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h index fe2f6378b..a22c9755a 100644 --- a/libavcodec/get_bits.h +++ b/libavcodec/get_bits.h @@ -76,6 +76,7 @@ typedef BitstreamContext GetBitContext; #define get_bits_count bits_tell +#define get_bits_bytesize bits_bytesize #define get_bits_left bits_left #define skip_bits_long bits_skip #define skip_bits bits_skip @@ -106,7 +107,7 @@ typedef BitstreamContext GetBitContext; #else // CACHED_BITSTREAM_READER typedef struct GetBitContext { - const uint8_t *buffer, *buffer_end; + const uint8_t *buffer; int index; int size_in_bits; int size_in_bits_plus8; @@ -163,24 +164,24 @@ static inline unsigned int show_bits(GetBitContext *s, int n); * For examples see get_bits, show_bits, skip_bits, get_vlc. */ -#if defined LONG_BITSTREAM_READER -# define MIN_CACHE_BITS 32 -#else -# define MIN_CACHE_BITS 25 -#endif +#define MIN_CACHE_BITS 25 + +#define OPEN_READER_NOSIZE_NOCACHE(name, gb) \ + unsigned int name ## _index = (gb)->index #define OPEN_READER_NOSIZE(name, gb) \ - unsigned int name ## _index = (gb)->index; \ - unsigned int av_unused name ## _cache + OPEN_READER_NOSIZE_NOCACHE(name, gb); \ + unsigned int name ## _cache #if UNCHECKED_BITSTREAM_READER #define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb) - +#define OPEN_READER_SIZE(name, gb) ((void)0) #define BITS_AVAILABLE(name, gb) 1 #else +#define OPEN_READER_SIZE(name, gb) unsigned int name ## _size_plus8 = (gb)->size_in_bits_plus8 #define OPEN_READER(name, gb) \ OPEN_READER_NOSIZE(name, gb); \ - unsigned int name ## _size_plus8 = (gb)->size_in_bits_plus8 + OPEN_READER_SIZE(name, gb) #define BITS_AVAILABLE(name, gb) name ## _index < name ## _size_plus8 #endif @@ -195,24 +196,11 @@ static inline unsigned int show_bits(GetBitContext *s, int n); /* Using these two macros ensures that 32 bits are available. */ # define UPDATE_CACHE_LE_32(name, gb) UPDATE_CACHE_LE_EXT(name, (gb), 64, 32) - # define UPDATE_CACHE_BE_32(name, gb) UPDATE_CACHE_BE_EXT(name, (gb), 64, 32) -# ifdef LONG_BITSTREAM_READER - -# define UPDATE_CACHE_LE(name, gb) UPDATE_CACHE_LE_32(name, (gb)) - -# define UPDATE_CACHE_BE(name, gb) UPDATE_CACHE_BE_32(name, (gb)) - -#else - # define UPDATE_CACHE_LE(name, gb) UPDATE_CACHE_LE_EXT(name, (gb), 32, 32) - # define UPDATE_CACHE_BE(name, gb) UPDATE_CACHE_BE_EXT(name, (gb), 32, 32) -#endif - - #ifdef BITSTREAM_READER_LE # define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb) @@ -268,6 +256,20 @@ static inline int get_bits_count(const GetBitContext *s) return s->index; } +/** + * Get the size of the GetBitContext's buffer in bytes. + * + * @param s the GetBitContext + * @param round_up If set, the number of bits will be rounded up to full bytes; + * this does not matter if the number of bits is known to be + * a multiple of eight, e.g. if the GetBitContext has been + * initialized with init_get_bits8. + */ +static inline int get_bits_bytesize(const GetBitContext *s, int round_up) +{ + return (s->size_in_bits + (round_up ? 7 : 0)) >> 3; +} + /** * Skips the specified number of bits. * @param n the number of bits to skip, @@ -380,7 +382,8 @@ static inline unsigned int show_bits(GetBitContext *s, int n) static inline void skip_bits(GetBitContext *s, int n) { - OPEN_READER(re, s); + OPEN_READER_NOSIZE_NOCACHE(re, s); + OPEN_READER_SIZE(re, s); LAST_SKIP_BITS(re, s, n); CLOSE_READER(re, s); } @@ -514,7 +517,6 @@ static inline unsigned int show_bits_long(GetBitContext *s, int n) 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 - FFMAX(7, AV_INPUT_BUFFER_PADDING_SIZE*8) || bit_size < 0 || !buffer) { @@ -523,12 +525,9 @@ static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, 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; @@ -611,7 +610,7 @@ static inline const uint8_t *align_get_bits(GetBitContext *s) \ index = SHOW_UBITS(name, gb, bits); \ level = table[index].level; \ - n = table[index].len; \ + n = table[index].len8; \ \ if (max_depth > 1 && n < 0) { \ SKIP_BITS(name, gb, bits); \ @@ -623,7 +622,7 @@ static inline const uint8_t *align_get_bits(GetBitContext *s) \ index = SHOW_UBITS(name, gb, nb_bits) + level; \ level = table[index].level; \ - n = table[index].len; \ + n = table[index].len8; \ if (max_depth > 2 && n < 0) { \ LAST_SKIP_BITS(name, gb, nb_bits); \ if (need_update) { \ @@ -633,7 +632,7 @@ static inline const uint8_t *align_get_bits(GetBitContext *s) \ index = SHOW_UBITS(name, gb, nb_bits) + level; \ level = table[index].level; \ - n = table[index].len; \ + n = table[index].len8; \ } \ } \ run = table[index].run; \ @@ -665,10 +664,10 @@ static av_always_inline int get_vlc2(GetBitContext *s, const VLCElem *table, } static inline int get_vlc_multi(GetBitContext *s, uint8_t *dst, - const VLC_MULTI_ELEM *const Jtable, + av_unused const VLC_MULTI_ELEM *const Jtable, const VLCElem *const table, const int bits, const int max_depth, - const int symbols_size) + av_unused const int symbols_size) { dst[0] = get_vlc2(s, table, bits, max_depth); return 1; diff --git a/libavcodec/get_buffer.c b/libavcodec/get_buffer.c index 7e705380f..b391adf24 100644 --- a/libavcodec/get_buffer.c +++ b/libavcodec/get_buffer.c @@ -32,7 +32,7 @@ #include "avcodec.h" #include "internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" typedef struct FramePool { /** @@ -53,7 +53,7 @@ typedef struct FramePool { int samples; } FramePool; -static void frame_pool_free(FFRefStructOpaque unused, void *obj) +static void frame_pool_free(AVRefStructOpaque unused, void *obj) { FramePool *pool = obj; int i; @@ -77,7 +77,7 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame) return 0; } - pool = ff_refstruct_alloc_ext(sizeof(*pool), 0, NULL, frame_pool_free); + pool = av_refstruct_alloc_ext(sizeof(*pool), 0, NULL, frame_pool_free); if (!pool) return AVERROR(ENOMEM); @@ -160,12 +160,12 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame) default: av_assert0(0); } - ff_refstruct_unref(&avctx->internal->pool); + av_refstruct_unref(&avctx->internal->pool); avctx->internal->pool = pool; return 0; fail: - ff_refstruct_unref(&pool); + av_refstruct_unref(&pool); return ret; } diff --git a/libavcodec/gif.c b/libavcodec/gif.c index c36fa6673..132ce07e6 100644 --- a/libavcodec/gif.c +++ b/libavcodec/gif.c @@ -30,6 +30,7 @@ * @see http://www.w3.org/Graphics/GIF/spec-gif89a.txt */ +#include "libavutil/attributes.h" #include "libavutil/imgutils_internal.h" #include "libavutil/mem.h" #include "libavutil/opt.h" @@ -491,6 +492,8 @@ static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt, memcpy(s->palette, palette, AVPALETTE_SIZE); s->transparent_index = get_palette_transparency_index(palette); s->palette_loaded = 1; + if (s->use_global_palette) + palette = NULL; } else if (!memcmp(s->palette, palette, AVPALETTE_SIZE)) { palette = NULL; } @@ -518,7 +521,7 @@ static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } -static int gif_encode_close(AVCodecContext *avctx) +static av_cold int gif_encode_close(AVCodecContext *avctx) { GIFContext *s = avctx->priv_data; @@ -559,10 +562,8 @@ const FFCodec ff_gif_encoder = { .init = gif_encode_init, FF_CODEC_ENCODE_CB(gif_encode_frame), .close = gif_encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, + AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8), .p.priv_class = &gif_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/gif.h b/libavcodec/gif.h index 7fb61495b..7848b8876 100644 --- a/libavcodec/gif.h +++ b/libavcodec/gif.h @@ -31,8 +31,10 @@ #include -static const uint8_t gif87a_sig[6] = "GIF87a"; -static const uint8_t gif89a_sig[6] = "GIF89a"; +#include "libavutil/attributes_internal.h" + +static attribute_nonstring const uint8_t gif87a_sig[6] = "GIF87a"; +static attribute_nonstring const uint8_t gif89a_sig[6] = "GIF89a"; #define GCE_DISPOSAL_NONE 0 #define GCE_DISPOSAL_INPLACE 1 diff --git a/libavcodec/gif_parser.c b/libavcodec/gif_parser.c index f5903585f..7204d71d5 100644 --- a/libavcodec/gif_parser.c +++ b/libavcodec/gif_parser.c @@ -26,6 +26,7 @@ #include "gif.h" #include "parser.h" +#include "parser_internal.h" typedef enum GIFParseStates { GIF_HEADER = 1, @@ -200,9 +201,9 @@ static int gif_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_gif_parser = { - .codec_ids = { AV_CODEC_ID_GIF }, +const FFCodecParser ff_gif_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_GIF), .priv_data_size = sizeof(GIFParseContext), - .parser_parse = gif_parse, - .parser_close = ff_parse_close, + .parse = gif_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/gsm_parser.c b/libavcodec/gsm_parser.c index 349280605..5d448cc3e 100644 --- a/libavcodec/gsm_parser.c +++ b/libavcodec/gsm_parser.c @@ -28,6 +28,7 @@ #include "libavutil/avassert.h" #include "parser.h" #include "gsm.h" +#include "parser_internal.h" typedef struct GSMParseContext { ParseContext pc; @@ -83,9 +84,9 @@ static int gsm_parse(AVCodecParserContext *s1, AVCodecContext *avctx, return next; } -const AVCodecParser ff_gsm_parser = { - .codec_ids = { AV_CODEC_ID_GSM, AV_CODEC_ID_GSM_MS }, +const FFCodecParser ff_gsm_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_GSM, AV_CODEC_ID_GSM_MS), .priv_data_size = sizeof(GSMParseContext), - .parser_parse = gsm_parse, - .parser_close = ff_parse_close, + .parse = gsm_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/gsmdec.c b/libavcodec/gsmdec.c index 14e236434..b20cdb754 100644 --- a/libavcodec/gsmdec.c +++ b/libavcodec/gsmdec.c @@ -26,6 +26,7 @@ #include "config_components.h" +#include "libavutil/attributes.h" #include "libavutil/channel_layout.h" #include "avcodec.h" #include "codec_internal.h" @@ -106,7 +107,7 @@ static int gsm_decode_frame(AVCodecContext *avctx, AVFrame *frame, return avctx->block_align; } -static void gsm_flush(AVCodecContext *avctx) +static av_cold void gsm_flush(AVCodecContext *avctx) { GSMContext *s = avctx->priv_data; memset(s, 0, sizeof(*s)); diff --git a/libavcodec/h261.c b/libavcodec/h261.c index 8e0e13459..babbd48dc 100644 --- a/libavcodec/h261.c +++ b/libavcodec/h261.c @@ -60,14 +60,13 @@ static void h261_loop_filter(uint8_t *src, ptrdiff_t stride) void ff_h261_loop_filter(MpegEncContext *s) { - H261Context *const h = s->private_ctx; const ptrdiff_t linesize = s->linesize; const ptrdiff_t uvlinesize = s->uvlinesize; uint8_t *dest_y = s->dest[0]; uint8_t *dest_cb = s->dest[1]; uint8_t *dest_cr = s->dest[2]; - if (!(IS_FIL(h->mtype))) + if (!(IS_FIL(s->mtype))) return; h261_loop_filter(dest_y, linesize); diff --git a/libavcodec/h261.h b/libavcodec/h261.h index 4279a1267..14d5b4a2f 100644 --- a/libavcodec/h261.h +++ b/libavcodec/h261.h @@ -29,16 +29,8 @@ #define AVCODEC_H261_H #include "mpegutils.h" -#include "mpegvideo.h" #include "rl.h" -/** - * H261Context - */ -typedef struct H261Context { - int mtype; -} H261Context; - #define MB_TYPE_H261_FIL MB_TYPE_CODEC_SPECIFIC extern const uint8_t ff_h261_mba_code[35]; @@ -54,6 +46,7 @@ extern const uint16_t ff_h261_tcoeff_vlc[65][2]; extern const int8_t ff_h261_tcoeff_level[64]; extern const int8_t ff_h261_tcoeff_run[64]; -void ff_h261_loop_filter(MpegEncContext *s); +struct MpegEncContext; +void ff_h261_loop_filter(struct MpegEncContext *s); #endif /* AVCODEC_H261_H */ diff --git a/libavcodec/h261_parser.c b/libavcodec/h261_parser.c index e0b84c509..c08cff334 100644 --- a/libavcodec/h261_parser.c +++ b/libavcodec/h261_parser.c @@ -26,6 +26,7 @@ */ #include "parser.h" +#include "parser_internal.h" static int h261_find_frame_end(ParseContext *pc, AVCodecContext *avctx, const uint8_t *buf, int buf_size) @@ -86,9 +87,9 @@ static int h261_parse(AVCodecParserContext *s, return next; } -const AVCodecParser ff_h261_parser = { - .codec_ids = { AV_CODEC_ID_H261 }, +const FFCodecParser ff_h261_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_H261), .priv_data_size = sizeof(ParseContext), - .parser_parse = h261_parse, - .parser_close = ff_parse_close, + .parse = h261_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/h261dec.c b/libavcodec/h261dec.c index cabca33c8..566143cc5 100644 --- a/libavcodec/h261dec.c +++ b/libavcodec/h261dec.c @@ -25,17 +25,22 @@ * H.261 decoder. */ -#include "libavutil/avassert.h" +#include "libavutil/mem_internal.h" #include "libavutil/thread.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" +#include "get_bits.h" #include "mpeg_er.h" #include "mpegutils.h" #include "mpegvideo.h" #include "mpegvideodec.h" #include "h261.h" +#define SLICE_OK 0 +#define SLICE_ERROR -1 +#define SLICE_END -2 ///framerate = (AVRational) { 30000, 1001 }; - s->private_ctx = &h->common; + /* The H.261 analog of intra/key frames is setting the freeze picture release flag, + * but this does not guarantee that the frame uses intra-only encoding, + * so we still need to allocate dummy frames. So set pict_type to P here + * for all frames and override it after having decoded the frame. */ + s->pict_type = AV_PICTURE_TYPE_P; + // set defaults ret = ff_mpv_decode_init(s, avctx); if (ret < 0) @@ -124,18 +136,18 @@ static int h261_decode_gob_header(H261DecContext *h) if (!h->gob_start_code_skipped) { /* Check for GOB Start Code */ - val = show_bits(&s->gb, 15); + val = show_bits(&h->gb, 15); if (val) return -1; /* We have a GBSC */ - skip_bits(&s->gb, 16); + skip_bits(&h->gb, 16); } h->gob_start_code_skipped = 0; - h->gob_number = get_bits(&s->gb, 4); /* GN */ - s->qscale = get_bits(&s->gb, 5); /* GQUANT */ + h->gob_number = get_bits(&h->gb, 4); /* GN */ + s->qscale = get_bits(&h->gb, 5); /* GQUANT */ /* Check if gob_number is valid */ if (s->mb_height == 18) { // CIF @@ -148,13 +160,14 @@ static int h261_decode_gob_header(H261DecContext *h) } /* GEI */ - if (skip_1stop_8data_bits(&s->gb) < 0) + if (skip_1stop_8data_bits(&h->gb) < 0) return AVERROR_INVALIDDATA; if (s->qscale == 0) { av_log(s->avctx, AV_LOG_ERROR, "qscale has forbidden 0 value\n"); if (s->avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_COMPLIANT)) return -1; + s->qscale = 1; } /* For the first transmitted macroblock in a GOB, MBA is the absolute @@ -169,9 +182,8 @@ static int h261_decode_gob_header(H261DecContext *h) /** * Decode skipped macroblocks. - * @return 0 */ -static int h261_decode_mb_skipped(H261DecContext *h, int mba1, int mba2) +static void h261_decode_mb_skipped(H261DecContext *h, int mba1, int mba2) { MpegEncContext *const s = &h->s; int i; @@ -195,7 +207,7 @@ static int h261_decode_mb_skipped(H261DecContext *h, int mba1, int mba2) s->mv[0][0][0] = 0; s->mv[0][0][1] = 0; s->mb_skipped = 1; - h->common.mtype &= ~MB_TYPE_H261_FIL; + s->mtype &= ~MB_TYPE_H261_FIL; if (s->cur_pic.motion_val[0]) { int b_stride = 2*s->mb_width + 1; @@ -204,10 +216,8 @@ static int h261_decode_mb_skipped(H261DecContext *h, int mba1, int mba2) s->cur_pic.motion_val[0][b_xy][1] = s->mv[0][0][1]; } - ff_mpv_reconstruct_mb(s, s->block); + ff_mpv_reconstruct_mb(s, h->block); } - - return 0; } static int decode_mv_component(GetBitContext *gb, int v) @@ -251,7 +261,7 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded scan_table = s->intra_scantable.permutated; if (s->mb_intra) { /* DC coef */ - level = get_bits(&s->gb, 8); + level = get_bits(&h->gb, 8); // 0 (00000000b) and -128 (10000000b) are FORBIDDEN if ((level & 0x7F) == 0) { av_log(s->avctx, AV_LOG_ERROR, "illegal dc %d at %d %d\n", @@ -262,17 +272,17 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded * being coded as 1111 1111. */ if (level == 255) level = 128; - block[0] = level * s->y_dc_scale; + block[0] = level * 8; i = 1; } else if (coded) { // Run Level Code // EOB Not possible for first level when cbp is available (that's why the table is different) // 0 1 1s // * * 0* - int check = show_bits(&s->gb, 2); + int check = show_bits(&h->gb, 2); i = 0; if (check & 0x2) { - skip_bits(&s->gb, 2); + skip_bits(&h->gb, 2); block[0] = qmul + qadd; block[0] *= (check & 0x1) ? -1 : 1; i = 1; @@ -285,14 +295,14 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded return 0; } { - OPEN_READER(re, &s->gb); + OPEN_READER(re, &h->gb); i--; // offset by -1 to allow direct indexing of scan_table for (;;) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, rl->rl_vlc[0], TCOEFF_VLC_BITS, 2, 0); + UPDATE_CACHE(re, &h->gb); + GET_RL_VLC(level, run, re, &h->gb, rl->rl_vlc[0], TCOEFF_VLC_BITS, 2, 0); if (run == 66) { if (level) { - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); av_log(s->avctx, AV_LOG_ERROR, "illegal ac vlc code at %dx%d\n", s->mb_x, s->mb_y); return -1; @@ -301,25 +311,25 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded /* The remaining combinations of (run, level) are encoded with a * 20-bit word consisting of 6 bits escape, 6 bits run and 8 bits * level. */ - run = SHOW_UBITS(re, &s->gb, 6) + 1; - SKIP_CACHE(re, &s->gb, 6); - level = SHOW_SBITS(re, &s->gb, 8); + run = SHOW_UBITS(re, &h->gb, 6) + 1; + SKIP_CACHE(re, &h->gb, 6); + level = SHOW_SBITS(re, &h->gb, 8); if (level > 0) level = level * qmul + qadd; else if (level < 0) level = level * qmul - qadd; - SKIP_COUNTER(re, &s->gb, 6 + 8); + SKIP_COUNTER(re, &h->gb, 6 + 8); } else if (level == 0) { break; } else { level = level * qmul + qadd; - if (SHOW_UBITS(re, &s->gb, 1)) + if (SHOW_UBITS(re, &h->gb, 1)) level = -level; - SKIP_COUNTER(re, &s->gb, 1); + SKIP_COUNTER(re, &h->gb, 1); } i += run; if (i >= 64) { - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); av_log(s->avctx, AV_LOG_ERROR, "run overflow at %dx%d\n", s->mb_x, s->mb_y); return -1; @@ -327,7 +337,7 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded j = scan_table[i]; block[j] = level; } - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); } s->block_last_index[n] = i; return 0; @@ -336,13 +346,12 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded static int h261_decode_mb(H261DecContext *h) { MpegEncContext *const s = &h->s; - H261Context *const com = &h->common; int i, cbp, xy; cbp = 63; // Read mba do { - h->mba_diff = get_vlc2(&s->gb, h261_mba_vlc, + h->mba_diff = get_vlc2(&h->gb, h261_mba_vlc, H261_MBA_VLC_BITS, 2); /* Check for slice end */ @@ -354,7 +363,7 @@ static int h261_decode_mb(H261DecContext *h) } while (h->mba_diff == MBA_STUFFING); // stuffing if (h->mba_diff < 0) { - if (get_bits_left(&s->gb) <= 7) + if (get_bits_left(&h->gb) <= 7) return SLICE_END; av_log(s->avctx, AV_LOG_ERROR, "illegal mba at %d %d\n", s->mb_x, s->mb_y); @@ -373,20 +382,23 @@ static int h261_decode_mb(H261DecContext *h) h261_init_dest(s); // Read mtype - com->mtype = get_vlc2(&s->gb, h261_mtype_vlc, H261_MTYPE_VLC_BITS, 2); - if (com->mtype < 0) { + s->mtype = get_vlc2(&h->gb, h261_mtype_vlc, H261_MTYPE_VLC_BITS, 2); + if (s->mtype < 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid mtype index\n"); return SLICE_ERROR; } // Read mquant - if (IS_QUANT(com->mtype)) - ff_set_qscale(s, get_bits(&s->gb, 5)); + if (IS_QUANT(s->mtype)) { + s->qscale = get_bits(&h->gb, 5); + if (!s->qscale) + s->qscale = 1; + } - s->mb_intra = IS_INTRA4x4(com->mtype); + s->mb_intra = IS_INTRA4x4(s->mtype); // Read mv - if (IS_16X16(com->mtype)) { + if (IS_16X16(s->mtype)) { /* Motion vector data is included for all MC macroblocks. MVD is * obtained from the macroblock vector by subtracting the vector * of the preceding macroblock. For this calculation the vector @@ -401,16 +413,16 @@ static int h261_decode_mb(H261DecContext *h) h->current_mv_y = 0; } - h->current_mv_x = decode_mv_component(&s->gb, h->current_mv_x); - h->current_mv_y = decode_mv_component(&s->gb, h->current_mv_y); + h->current_mv_x = decode_mv_component(&h->gb, h->current_mv_x); + h->current_mv_y = decode_mv_component(&h->gb, h->current_mv_y); } else { h->current_mv_x = 0; h->current_mv_y = 0; } // Read cbp - if (HAS_CBP(com->mtype)) - cbp = get_vlc2(&s->gb, h261_cbp_vlc, H261_CBP_VLC_BITS, 1) + 1; + if (HAS_CBP(s->mtype)) + cbp = get_vlc2(&h->gb, h261_cbp_vlc, H261_CBP_VLC_BITS, 1) + 1; if (s->mb_intra) { s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; @@ -433,10 +445,10 @@ static int h261_decode_mb(H261DecContext *h) intra: /* decode each block */ - if (s->mb_intra || HAS_CBP(com->mtype)) { - s->bdsp.clear_blocks(s->block[0]); + if (s->mb_intra || HAS_CBP(s->mtype)) { + s->bdsp.clear_blocks(h->block[0]); for (i = 0; i < 6; i++) { - if (h261_decode_block(h, s->block[i], i, cbp & 32) < 0) + if (h261_decode_block(h, h->block[i], i, cbp & 32) < 0) return SLICE_ERROR; cbp += cbp; } @@ -445,7 +457,7 @@ intra: s->block_last_index[i] = -1; } - ff_mpv_reconstruct_mb(s, s->block); + ff_mpv_reconstruct_mb(s, h->block); return SLICE_OK; } @@ -454,14 +466,13 @@ intra: * Decode the H.261 picture header. * @return <0 if no startcode found */ -static int h261_decode_picture_header(H261DecContext *h) +static int h261_decode_picture_header(H261DecContext *h, int *is_key) { MpegEncContext *const s = &h->s; - int format, i; uint32_t startcode = 0; - for (i = get_bits_left(&s->gb); i > 24; i -= 1) { - startcode = ((startcode << 1) | get_bits(&s->gb, 1)) & 0x000FFFFF; + for (int i = get_bits_left(&h->gb); i > 24; i -= 1) { + startcode = ((startcode << 1) | get_bits(&h->gb, 1)) & 0x000FFFFF; if (startcode == 0x10) break; @@ -473,14 +484,14 @@ static int h261_decode_picture_header(H261DecContext *h) } /* temporal reference */ - skip_bits(&s->gb, 5); /* picture timestamp */ + skip_bits(&h->gb, 5); /* picture timestamp */ /* PTYPE starts here */ - skip_bits1(&s->gb); /* split screen off */ - skip_bits1(&s->gb); /* camera off */ - skip_bits1(&s->gb); /* freeze picture release off */ + skip_bits1(&h->gb); /* split screen off */ + skip_bits1(&h->gb); /* camera off */ + *is_key = get_bits1(&h->gb); /* freeze picture release off */ - format = get_bits1(&s->gb); + int format = get_bits1(&h->gb); // only 2 formats possible if (format == 0) { // QCIF @@ -491,18 +502,13 @@ static int h261_decode_picture_header(H261DecContext *h) s->height = 288; } - skip_bits1(&s->gb); /* still image mode off */ - skip_bits1(&s->gb); /* Reserved */ + skip_bits1(&h->gb); /* still image mode off */ + skip_bits1(&h->gb); /* Reserved */ /* PEI */ - if (skip_1stop_8data_bits(&s->gb) < 0) + if (skip_1stop_8data_bits(&h->gb) < 0) return AVERROR_INVALIDDATA; - /* H.261 has no I-frames, but if we pass AV_PICTURE_TYPE_I for the first - * frame, the codec crashes if it does not contain all I-blocks - * (e.g. when a packet is lost). */ - s->pict_type = AV_PICTURE_TYPE_P; - h->gob_number = 0; return 0; } @@ -511,8 +517,6 @@ static int h261_decode_gob(H261DecContext *h) { MpegEncContext *const s = &h->s; - ff_set_qscale(s, s->qscale); - /* decode mb's */ while (h->current_mba <= MBA_STUFFING) { int ret; @@ -536,20 +540,6 @@ static int h261_decode_gob(H261DecContext *h) return -1; } -/** - * returns the number of bytes consumed for building the current frame - */ -static int get_consumed_bytes(MpegEncContext *s, int buf_size) -{ - int pos = get_bits_count(&s->gb) >> 3; - if (pos == 0) - pos = 1; // avoid infinite loops (i doubt that is needed but ...) - if (pos + 10 > buf_size) - pos = buf_size; // oops ;) - - return pos; -} - static int h261_decode_frame(AVCodecContext *avctx, AVFrame *pict, int *got_frame, AVPacket *avpkt) { @@ -557,16 +547,16 @@ static int h261_decode_frame(AVCodecContext *avctx, AVFrame *pict, const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; MpegEncContext *s = &h->s; - int ret; + int ret, is_key; ff_dlog(avctx, "*****frame %"PRId64" size=%d\n", avctx->frame_num, buf_size); ff_dlog(avctx, "bytes=%x %x %x %x\n", buf[0], buf[1], buf[2], buf[3]); h->gob_start_code_skipped = 0; - init_get_bits(&s->gb, buf, buf_size * 8); + init_get_bits(&h->gb, buf, buf_size * 8); - ret = h261_decode_picture_header(h); + ret = h261_decode_picture_header(h, &is_key); /* skip if the header was thrashed */ if (ret < 0) { @@ -587,8 +577,7 @@ static int h261_decode_frame(AVCodecContext *avctx, AVFrame *pict, return ret; } - if ((avctx->skip_frame >= AVDISCARD_NONREF && s->pict_type == AV_PICTURE_TYPE_B) || - (avctx->skip_frame >= AVDISCARD_NONKEY && s->pict_type != AV_PICTURE_TYPE_I) || + if ((avctx->skip_frame >= AVDISCARD_NONINTRA && !is_key) || avctx->skip_frame >= AVDISCARD_ALL) return buf_size; @@ -608,7 +597,10 @@ static int h261_decode_frame(AVCodecContext *avctx, AVFrame *pict, } ff_mpv_frame_end(s); - av_assert0(s->pict_type == s->cur_pic.ptr->f->pict_type); + if (is_key) { + s->cur_pic.ptr->f->pict_type = AV_PICTURE_TYPE_I; + s->cur_pic.ptr->f->flags |= AV_FRAME_FLAG_KEY; + } if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) return ret; @@ -616,7 +608,7 @@ static int h261_decode_frame(AVCodecContext *avctx, AVFrame *pict, *got_frame = 1; - return get_consumed_bytes(s, buf_size); + return buf_size; } const FFCodec ff_h261_decoder = { @@ -630,4 +622,5 @@ const FFCodec ff_h261_decoder = { .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DR1, .p.max_lowres = 3, + .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, }; diff --git a/libavcodec/h261enc.c b/libavcodec/h261enc.c index f417366e7..d13511a6f 100644 --- a/libavcodec/h261enc.c +++ b/libavcodec/h261enc.c @@ -35,23 +35,28 @@ #include "h261.h" #include "h261enc.h" #include "mpegvideoenc.h" +#include "put_bits.h" #define H261_MAX_RUN 26 #define H261_MAX_LEVEL 15 #define H261_ESC_LEN (6 + 6 + 8) +#define MV_TAB_OFFSET 32 static struct VLCLUT { uint8_t len; uint16_t code; } vlc_lut[H261_MAX_RUN + 1][32 /* 0..2 * H261_MAX_LEN are used */]; +// Not const despite never being initialized because doing so would +// put it into .rodata instead of .bss and bloat the binary. +// mv_penalty exists so that the motion estimation code can avoid branches. +static uint8_t mv_penalty[MAX_FCODE + 1][MAX_DMV * 2 + 1]; static uint8_t uni_h261_rl_len [64 * 128]; static uint8_t uni_h261_rl_len_last[64 * 128]; +static uint8_t h261_mv_codes[64][2]; typedef struct H261EncContext { - MpegEncContext s; - - H261Context common; + MPVMainEncContext s; int gob_number; enum { @@ -60,25 +65,23 @@ typedef struct H261EncContext { } format; } H261EncContext; -void ff_h261_encode_picture_header(MpegEncContext *s) +static int h261_encode_picture_header(MPVMainEncContext *const m) { - H261EncContext *const h = (H261EncContext *)s; + H261EncContext *const h = (H261EncContext *)m; + MPVEncContext *const s = &h->s.s; int temp_ref; - align_put_bits(&s->pb); - - /* Update the pointer to last GOB */ - s->ptr_lastgob = put_bits_ptr(&s->pb); + put_bits_assume_flushed(&s->pb); put_bits(&s->pb, 20, 0x10); /* PSC */ - temp_ref = s->picture_number * 30000LL * s->avctx->time_base.num / - (1001LL * s->avctx->time_base.den); // FIXME maybe this should use a timestamp + temp_ref = s->picture_number * 30000LL * s->c.avctx->time_base.num / + (1001LL * s->c.avctx->time_base.den); // FIXME maybe this should use a timestamp put_sbits(&s->pb, 5, temp_ref); /* TemporalReference */ put_bits(&s->pb, 1, 0); /* split screen off */ put_bits(&s->pb, 1, 0); /* camera off */ - put_bits(&s->pb, 1, s->pict_type == AV_PICTURE_TYPE_I); /* freeze picture release on/off */ + put_bits(&s->pb, 1, s->c.pict_type == AV_PICTURE_TYPE_I); /* freeze picture release on/off */ put_bits(&s->pb, 1, h->format); /* 0 == QCIF, 1 == CIF */ @@ -88,12 +91,14 @@ void ff_h261_encode_picture_header(MpegEncContext *s) put_bits(&s->pb, 1, 0); /* no PEI */ h->gob_number = h->format - 1; s->mb_skip_run = 0; + + return 0; } /** * Encode a group of blocks header. */ -static void h261_encode_gob_header(MpegEncContext *s, int mb_line) +static void h261_encode_gob_header(MPVEncContext *const s, int mb_line) { H261EncContext *const h = (H261EncContext *)s; if (h->format == H261_QCIF) { @@ -103,65 +108,53 @@ static void h261_encode_gob_header(MpegEncContext *s, int mb_line) } put_bits(&s->pb, 16, 1); /* GBSC */ put_bits(&s->pb, 4, h->gob_number); /* GN */ - put_bits(&s->pb, 5, s->qscale); /* GQUANT */ + put_bits(&s->pb, 5, s->c.qscale); /* GQUANT */ put_bits(&s->pb, 1, 0); /* no GEI */ s->mb_skip_run = 0; - s->last_mv[0][0][0] = 0; - s->last_mv[0][0][1] = 0; + s->c.last_mv[0][0][0] = 0; + s->c.last_mv[0][0][1] = 0; } -void ff_h261_reorder_mb_index(MpegEncContext *s) +void ff_h261_reorder_mb_index(MPVEncContext *const s) { const H261EncContext *const h = (H261EncContext*)s; - int index = s->mb_x + s->mb_y * s->mb_width; + int index = s->c.mb_x + s->c.mb_y * s->c.mb_width; if (index % 11 == 0) { if (index % 33 == 0) h261_encode_gob_header(s, 0); - s->last_mv[0][0][0] = 0; - s->last_mv[0][0][1] = 0; + s->c.last_mv[0][0][0] = 0; + s->c.last_mv[0][0][1] = 0; } /* for CIF the GOB's are fragmented in the middle of a scanline * that's why we need to adjust the x and y index of the macroblocks */ if (h->format == H261_CIF) { - s->mb_x = index % 11; + s->c.mb_x = index % 11; index /= 11; - s->mb_y = index % 3; + s->c.mb_y = index % 3; index /= 3; - s->mb_x += 11 * (index % 2); + s->c.mb_x += 11 * (index % 2); index /= 2; - s->mb_y += 3 * index; + s->c.mb_y += 3 * index; - ff_init_block_index(s); - ff_update_block_index(s, 8, 0, 1); + ff_init_block_index(&s->c); + ff_update_block_index(&s->c, 8, 0, 1); } } static void h261_encode_motion(PutBitContext *pb, int val) { - int sign, code; - if (val == 0) { - // Corresponds to ff_h261_mv_tab[0] - put_bits(pb, 1, 1); - } else { - if (val > 15) - val -= 32; - if (val < -16) - val += 32; - sign = val < 0; - code = sign ? -val : val; - put_bits(pb, ff_h261_mv_tab[code][1], ff_h261_mv_tab[code][0]); - put_bits(pb, 1, sign); - } + put_bits(pb, h261_mv_codes[MV_TAB_OFFSET + val][1], + h261_mv_codes[MV_TAB_OFFSET + val][0]); } -static inline int get_cbp(MpegEncContext *s, int16_t block[6][64]) +static inline int get_cbp(const int block_last_index[6]) { int i, cbp; cbp = 0; for (i = 0; i < 6; i++) - if (s->block_last_index[i] >= 0) + if (block_last_index[i] >= 0) cbp |= 1 << (5 - i); return cbp; } @@ -173,10 +166,10 @@ static inline int get_cbp(MpegEncContext *s, int16_t block[6][64]) */ static void h261_encode_block(H261EncContext *h, int16_t *block, int n) { - MpegEncContext *const s = &h->s; + MPVEncContext *const s = &h->s.s; int level, run, i, j, last_index, last_non_zero; - if (s->mb_intra) { + if (s->c.mb_intra) { /* DC coef */ level = block[0]; /* 255 cannot be represented, so we clamp */ @@ -195,7 +188,7 @@ static void h261_encode_block(H261EncContext *h, int16_t *block, int n) put_bits(&s->pb, 8, level); i = 1; } else if ((block[0] == 1 || block[0] == -1) && - (s->block_last_index[n] > -1)) { + (s->c.block_last_index[n] > -1)) { // special case put_bits(&s->pb, 2, block[0] > 0 ? 2 : 3); i = 1; @@ -204,10 +197,10 @@ static void h261_encode_block(H261EncContext *h, int16_t *block, int n) } /* AC coefs */ - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; last_non_zero = i - 1; for (; i <= last_index; i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; level = block[j]; if (level) { run = i - last_non_zero - 1; @@ -231,22 +224,21 @@ static void h261_encode_block(H261EncContext *h, int16_t *block, int n) put_bits(&s->pb, 2, 0x2); // EOB } -void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], - int motion_x, int motion_y) +static void h261_encode_mb(MPVEncContext *const s, int16_t block[6][64], + int motion_x, int motion_y) { /* The following is only allowed because this encoder * does not use slice threading. */ H261EncContext *const h = (H261EncContext *)s; - H261Context *const com = &h->common; int mvd, mv_diff_x, mv_diff_y, i, cbp; cbp = 63; // avoid warning mvd = 0; - com->mtype = 0; + s->c.mtype = 0; - if (!s->mb_intra) { + if (!s->c.mb_intra) { /* compute cbp */ - cbp = get_cbp(s, block); + cbp = get_cbp(s->c.block_last_index); /* mvd indicates if this block is motion compensated */ mvd = motion_x | motion_y; @@ -254,9 +246,9 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], if ((cbp | mvd) == 0) { /* skip macroblock */ s->mb_skip_run++; - s->last_mv[0][0][0] = 0; - s->last_mv[0][0][1] = 0; - s->qscale -= s->dquant; + s->c.last_mv[0][0][0] = 0; + s->c.last_mv[0][0][1] = 0; + s->c.qscale -= s->dquant; return; } } @@ -268,44 +260,44 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], s->mb_skip_run = 0; /* calculate MTYPE */ - if (!s->mb_intra) { - com->mtype++; + if (!s->c.mb_intra) { + s->c.mtype++; if (mvd || s->loop_filter) - com->mtype += 3; + s->c.mtype += 3; if (s->loop_filter) - com->mtype += 3; + s->c.mtype += 3; if (cbp) - com->mtype++; - av_assert1(com->mtype > 1); + s->c.mtype++; + av_assert1(s->c.mtype > 1); } if (s->dquant && cbp) { - com->mtype++; + s->c.mtype++; } else - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; put_bits(&s->pb, - ff_h261_mtype_bits[com->mtype], - ff_h261_mtype_code[com->mtype]); + ff_h261_mtype_bits[s->c.mtype], + ff_h261_mtype_code[s->c.mtype]); - com->mtype = ff_h261_mtype_map[com->mtype]; + s->c.mtype = ff_h261_mtype_map[s->c.mtype]; - if (IS_QUANT(com->mtype)) { - ff_set_qscale(s, s->qscale + s->dquant); - put_bits(&s->pb, 5, s->qscale); + if (IS_QUANT(s->c.mtype)) { + ff_set_qscale(&s->c, s->c.qscale + s->dquant); + put_bits(&s->pb, 5, s->c.qscale); } - if (IS_16X16(com->mtype)) { - mv_diff_x = (motion_x >> 1) - s->last_mv[0][0][0]; - mv_diff_y = (motion_y >> 1) - s->last_mv[0][0][1]; - s->last_mv[0][0][0] = (motion_x >> 1); - s->last_mv[0][0][1] = (motion_y >> 1); + if (IS_16X16(s->c.mtype)) { + mv_diff_x = (motion_x >> 1) - s->c.last_mv[0][0][0]; + mv_diff_y = (motion_y >> 1) - s->c.last_mv[0][0][1]; + s->c.last_mv[0][0][0] = (motion_x >> 1); + s->c.last_mv[0][0][1] = (motion_y >> 1); h261_encode_motion(&s->pb, mv_diff_x); h261_encode_motion(&s->pb, mv_diff_y); } - if (HAS_CBP(com->mtype)) { + if (HAS_CBP(s->c.mtype)) { av_assert1(cbp > 0); put_bits(&s->pb, ff_h261_cbp_tab[cbp - 1][1], @@ -315,14 +307,15 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], /* encode each block */ h261_encode_block(h, block[i], i); - if (!IS_16X16(com->mtype)) { - s->last_mv[0][0][0] = 0; - s->last_mv[0][0][1] = 0; + if (!IS_16X16(s->c.mtype)) { + s->c.last_mv[0][0][0] = 0; + s->c.last_mv[0][0][1] = 0; } } static av_cold void h261_encode_init_static(void) { + uint8_t (*const mv_codes)[2] = h261_mv_codes + MV_TAB_OFFSET; memset(uni_h261_rl_len, H261_ESC_LEN, sizeof(uni_h261_rl_len)); memset(uni_h261_rl_len_last, H261_ESC_LEN + 2 /* EOB */, sizeof(uni_h261_rl_len_last)); @@ -341,35 +334,53 @@ static av_cold void h261_encode_init_static(void) uni_h261_rl_len_last[UNI_AC_ENC_INDEX(run, 64 + level)] = len + 2; uni_h261_rl_len_last[UNI_AC_ENC_INDEX(run, 64 - level)] = len + 2; } + + for (ptrdiff_t i = 1;; i++) { + // sign-one MV codes; diff -16..-1, 16..31 + mv_codes[32 - i][0] = mv_codes[-i][0] = (ff_h261_mv_tab[i][0] << 1) | 1 /* sign */; + mv_codes[32 - i][1] = mv_codes[-i][1] = ff_h261_mv_tab[i][1] + 1; + if (i == 16) + break; + // sign-zero MV codes: diff -31..-17, 1..15 + mv_codes[i][0] = mv_codes[i - 32][0] = ff_h261_mv_tab[i][0] << 1; + mv_codes[i][1] = mv_codes[i - 32][1] = ff_h261_mv_tab[i][1] + 1; + } + // MV code for difference zero; has no sign + mv_codes[0][0] = 1; + mv_codes[0][1] = 1; } -av_cold int ff_h261_encode_init(MpegEncContext *s) +static av_cold int h261_encode_init(AVCodecContext *avctx) { - H261EncContext *const h = (H261EncContext*)s; static AVOnce init_static_once = AV_ONCE_INIT; + H261EncContext *const h = avctx->priv_data; + MPVEncContext *const s = &h->s.s; - if (s->width == 176 && s->height == 144) { + if (avctx->width == 176 && avctx->height == 144) { h->format = H261_QCIF; - } else if (s->width == 352 && s->height == 288) { + } else if (avctx->width == 352 && avctx->height == 288) { h->format = H261_CIF; } else { - av_log(s->avctx, AV_LOG_ERROR, + av_log(avctx, AV_LOG_ERROR, "The specified picture size of %dx%d is not valid for the " "H.261 codec.\nValid sizes are 176x144, 352x288\n", - s->width, s->height); + avctx->width, avctx->height); return AVERROR(EINVAL); } - s->private_ctx = &h->common; + h->s.encode_picture_header = h261_encode_picture_header; + s->encode_mb = h261_encode_mb; s->min_qcoeff = -127; s->max_qcoeff = 127; s->ac_esc_length = H261_ESC_LEN; + s->me.mv_penalty = mv_penalty; + s->intra_ac_vlc_length = s->inter_ac_vlc_length = uni_h261_rl_len; s->intra_ac_vlc_last_length = s->inter_ac_vlc_last_length = uni_h261_rl_len_last; ff_thread_once(&init_static_once, h261_encode_init_static); - return 0; + return ff_mpv_encode_init(avctx); } const FFCodec ff_h261_encoder = { @@ -378,13 +389,12 @@ const FFCodec ff_h261_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H261, .p.priv_class = &ff_mpv_enc_class, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(H261EncContext), - .init = ff_mpv_encode_init, + .init = h261_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, }; diff --git a/libavcodec/h261enc.h b/libavcodec/h261enc.h index d8fdcad7a..77f072a5e 100644 --- a/libavcodec/h261enc.h +++ b/libavcodec/h261enc.h @@ -28,12 +28,8 @@ #ifndef AVCODEC_H261ENC_H #define AVCODEC_H261ENC_H -#include "mpegvideo.h" +typedef struct MPVEncContext MPVEncContext; -void ff_h261_reorder_mb_index(MpegEncContext *s); -void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], - int motion_x, int motion_y); -void ff_h261_encode_picture_header(MpegEncContext *s); -int ff_h261_encode_init(MpegEncContext *s); +void ff_h261_reorder_mb_index(MPVEncContext *s); #endif diff --git a/libavcodec/h263.c b/libavcodec/h263.c index 19eb3ba52..6d2de715a 100644 --- a/libavcodec/h263.c +++ b/libavcodec/h263.c @@ -27,17 +27,19 @@ * H.263/MPEG-4 codec. */ +#include "config.h" + #include "libavutil/thread.h" #include "mpegvideo.h" #include "h263.h" #include "h263data.h" #include "h263dsp.h" -#include "idctdsp.h" #include "mathops.h" #include "mpegpicture.h" #include "mpegutils.h" #include "rl.h" +#if CONFIG_MPEGVIDEO static av_cold void h263_init_rl_inter(void) { static uint8_t h263_rl_inter_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; @@ -49,6 +51,7 @@ av_cold void ff_h263_init_rl_inter(void) static AVOnce init_static_once = AV_ONCE_INIT; ff_thread_once(&init_static_once, h263_init_rl_inter); } +#endif void ff_h263_update_motion_val(MpegEncContext * s){ const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; diff --git a/libavcodec/h263.h b/libavcodec/h263.h index 27a5f31c5..2fee0df4c 100644 --- a/libavcodec/h263.h +++ b/libavcodec/h263.h @@ -27,6 +27,16 @@ #define H263_GOB_HEIGHT(h) ((h) <= 400 ? 1 : (h) <= 800 ? 2 : 4) +static inline int ff_h263_round_chroma(int x) +{ + //FIXME static or not? + static const uint8_t h263_chroma_roundtab[16] = { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, + }; + return h263_chroma_roundtab[x & 0xf] + (x >> 3); +} + av_const int ff_h263_aspect_to_info(AVRational aspect); int16_t *ff_h263_pred_motion(MpegEncContext * s, int block, int dir, int *px, int *py); @@ -34,4 +44,12 @@ void ff_h263_init_rl_inter(void); void ff_h263_update_motion_val(MpegEncContext * s); void ff_h263_loop_filter(MpegEncContext * s); +static inline void ff_h263_clean_intra_table_entries(MpegEncContext *s, int xy) +{ + if (s->mbintra_table[xy]) { + s->mbintra_table[xy] = 0; + ff_clean_intra_table_entries(s); + } +} + #endif /* AVCODEC_H263_H */ diff --git a/libavcodec/h263_parser.c b/libavcodec/h263_parser.c index f70a79117..3fc969c33 100644 --- a/libavcodec/h263_parser.c +++ b/libavcodec/h263_parser.c @@ -25,6 +25,7 @@ */ #include "parser.h" +#include "parser_internal.h" static int h263_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size) { @@ -87,9 +88,9 @@ static int h263_parse(AVCodecParserContext *s, return next; } -const AVCodecParser ff_h263_parser = { - .codec_ids = { AV_CODEC_ID_H263 }, +const FFCodecParser ff_h263_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_H263), .priv_data_size = sizeof(ParseContext), - .parser_parse = h263_parse, - .parser_close = ff_parse_close, + .parse = h263_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/h263data.h b/libavcodec/h263data.h index 06554bdf0..e733089e8 100644 --- a/libavcodec/h263data.h +++ b/libavcodec/h263data.h @@ -59,6 +59,10 @@ extern const uint16_t ff_inter_vlc[103][2]; extern const int8_t ff_inter_level[102]; extern const int8_t ff_inter_run[102]; +/* the following defines are valid for both ff_h263_rl_inter and ff_rl_intra_aic */ +#define H263_RL_NB_ELEMS 102 // does not include escape +#define H263_RL_NON_LAST_CODES 58 +#define H263_ESCAPE_CODE_LENGTH 7 extern RLTable ff_h263_rl_inter; extern RLTable ff_rl_intra_aic; diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c index 5eefdc460..23fd16b72 100644 --- a/libavcodec/h263dec.c +++ b/libavcodec/h263dec.c @@ -41,9 +41,10 @@ #include "mpeg_er.h" #include "mpeg4video.h" #include "mpeg4videodec.h" -#include "mpeg4videodefs.h" #include "mpegvideo.h" +#include "mpegvideodata.h" #include "mpegvideodec.h" +#include "mpegvideo_unquantize.h" #include "msmpeg4dec.h" #include "thread.h" #include "wmv2dec.h" @@ -89,7 +90,9 @@ static enum AVPixelFormat h263_get_format(AVCodecContext *avctx) av_cold int ff_h263_decode_init(AVCodecContext *avctx) { - MpegEncContext *s = avctx->priv_data; + H263DecContext *const h = avctx->priv_data; + MPVContext *const s = &h->c; + MPVUnquantDSPContext unquant_dsp_ctx; int ret; s->out_format = FMT_H263; @@ -99,24 +102,33 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx) if (ret < 0) return ret; - s->decode_mb = ff_h263_decode_mb; + h->decode_mb = ff_h263_decode_mb; s->low_delay = 1; + s->y_dc_scale_table = + s->c_dc_scale_table = ff_mpeg1_dc_scale_table; + + ff_permute_scantable(h->permutated_intra_h_scantable, ff_alternate_horizontal_scan, + s->idsp.idct_permutation); + ff_permute_scantable(h->permutated_intra_v_scantable, ff_alternate_vertical_scan, + s->idsp.idct_permutation); + + ff_mpv_unquantize_init(&unquant_dsp_ctx, + avctx->flags & AV_CODEC_FLAG_BITEXACT, 0); // dct_unquantize defaults for H.263; - // they might change on a per-frame basis for MPEG-4. - s->dct_unquantize_intra = s->dct_unquantize_h263_intra; - s->dct_unquantize_inter = s->dct_unquantize_h263_inter; + // they might change on a per-frame basis for MPEG-4; + // dct_unquantize_inter will be unset for MSMPEG4 codecs later. + s->dct_unquantize_intra = unquant_dsp_ctx.dct_unquantize_h263_intra; + s->dct_unquantize_inter = unquant_dsp_ctx.dct_unquantize_h263_inter; /* select sub codec */ switch (avctx->codec->id) { case AV_CODEC_ID_H263: case AV_CODEC_ID_H263P: avctx->chroma_sample_location = AVCHROMA_LOC_CENTER; + h->decode_header = ff_h263_decode_picture_header; break; case AV_CODEC_ID_MPEG4: - // dct_unquantize_inter is only used with MPEG-2 quantizers, - // so we can already set dct_unquantize_inter here once and for all. - s->dct_unquantize_inter = s->dct_unquantize_mpeg2_inter; break; case AV_CODEC_ID_MSMPEG4V1: s->h263_pred = 1; @@ -138,22 +150,26 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx) s->h263_pred = 1; s->msmpeg4_version = MSMP4_WMV2; break; - case AV_CODEC_ID_H263I: case AV_CODEC_ID_RV10: case AV_CODEC_ID_RV20: break; - case AV_CODEC_ID_FLV1: - s->h263_flv = 1; +#if CONFIG_H263I_DECODER + case AV_CODEC_ID_H263I: + h->decode_header = ff_intel_h263_decode_picture_header; break; +#endif +#if CONFIG_FLV_DECODER + case AV_CODEC_ID_FLV1: + h->decode_header = ff_flv_decode_picture_header; + break; +#endif default: - av_log(avctx, AV_LOG_ERROR, "Unsupported codec %d\n", - avctx->codec->id); - return AVERROR(ENOSYS); + av_unreachable("Switch contains a case for every codec using ff_h263_decode_init()"); } if (avctx->codec_tag == AV_RL32("L263") || avctx->codec_tag == AV_RL32("S263")) if (avctx->extradata_size == 56 && avctx->extradata[0] == 1) - s->ehc_mode = 1; + h->ehc_mode = 1; /* for H.263, we allocate the images after having read the header */ if (avctx->codec->id != AV_CODEC_ID_H263 && @@ -170,254 +186,252 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx) return 0; } -/** - * Return the number of bytes consumed for building the current frame. - */ -static int get_consumed_bytes(MpegEncContext *s, int buf_size) +static void report_decode_progress(H263DecContext *const h) { - int pos = (get_bits_count(&s->gb) + 7) >> 3; - - if (s->divx_packed || s->avctx->hwaccel) { - /* We would have to scan through the whole buf to handle the weird - * reordering ... */ - return buf_size; - } else { - // avoid infinite loops (maybe not needed...) - if (pos == 0) - pos = 1; - // oops ;) - if (pos + 10 > buf_size) - pos = buf_size; - - return pos; - } + if (h->c.pict_type != AV_PICTURE_TYPE_B && !h->partitioned_frame && !h->c.er.error_occurred) + ff_thread_progress_report(&h->c.cur_pic.ptr->progress, h->c.mb_y); } -static int decode_slice(MpegEncContext *s) +static int decode_slice(H263DecContext *const h) { - const int part_mask = s->partitioned_frame + const int part_mask = h->partitioned_frame ? (ER_AC_END | ER_AC_ERROR) : 0x7F; - const int mb_size = 16 >> s->avctx->lowres; + const int mb_size = 16 >> h->c.avctx->lowres; int ret; - s->last_resync_gb = s->gb; - s->first_slice_line = 1; - s->resync_mb_x = s->mb_x; - s->resync_mb_y = s->mb_y; + h->last_resync_gb = h->gb; + h->c.first_slice_line = 1; + h->c.resync_mb_x = h->c.mb_x; + h->c.resync_mb_y = h->c.mb_y; - ff_set_qscale(s, s->qscale); + ff_set_qscale(&h->c, h->c.qscale); - if (s->studio_profile) { - if ((ret = ff_mpeg4_decode_studio_slice_header(s->avctx->priv_data)) < 0) +#if CONFIG_MPEG4_DECODER + if (h->c.studio_profile) { + if ((ret = ff_mpeg4_decode_studio_slice_header(h)) < 0) return ret; } +#endif - if (s->avctx->hwaccel) { - const uint8_t *start = s->gb.buffer + get_bits_count(&s->gb) / 8; - ret = FF_HW_CALL(s->avctx, decode_slice, start, s->gb.buffer_end - start); + if (h->c.avctx->hwaccel) { + const uint8_t *start = h->gb.buffer + get_bits_count(&h->gb) / 8; + ret = FF_HW_CALL(h->c.avctx, decode_slice, start, + get_bits_bytesize(&h->gb, 0) - get_bits_count(&h->gb) / 8); // ensure we exit decode loop - s->mb_y = s->mb_height; + h->c.mb_y = h->c.mb_height; return ret; } - if (s->partitioned_frame) { - const int qscale = s->qscale; +#if CONFIG_MPEG4_DECODER + if (h->partitioned_frame) { + const int qscale = h->c.qscale; - if (CONFIG_MPEG4_DECODER && s->codec_id == AV_CODEC_ID_MPEG4) - if ((ret = ff_mpeg4_decode_partitions(s->avctx->priv_data)) < 0) - return ret; + av_assert1(h->c.codec_id == AV_CODEC_ID_MPEG4); + + ret = ff_mpeg4_decode_partitions(h); + if (ret < 0) + return ret; /* restore variables which were modified */ - s->first_slice_line = 1; - s->mb_x = s->resync_mb_x; - s->mb_y = s->resync_mb_y; - ff_set_qscale(s, qscale); + h->c.first_slice_line = 1; + h->c.mb_x = h->c.resync_mb_x; + h->c.mb_y = h->c.resync_mb_y; + ff_set_qscale(&h->c, qscale); } +#endif - for (; s->mb_y < s->mb_height; s->mb_y++) { + for (; h->c.mb_y < h->c.mb_height; h->c.mb_y++) { /* per-row end of slice checks */ - if (s->msmpeg4_version != MSMP4_UNUSED) { - if (s->resync_mb_y + s->slice_height == s->mb_y) { - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x - 1, s->mb_y, ER_MB_END); + if (h->c.msmpeg4_version != MSMP4_UNUSED) { + if (h->c.resync_mb_y + h->slice_height == h->c.mb_y) { + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x - 1, h->c.mb_y, ER_MB_END); return 0; } } - if (s->msmpeg4_version == MSMP4_V1) { - s->last_dc[0] = - s->last_dc[1] = - s->last_dc[2] = 128; + if (h->c.msmpeg4_version == MSMP4_V1) { + h->last_dc[0] = + h->last_dc[1] = + h->last_dc[2] = 128; } - ff_init_block_index(s); - for (; s->mb_x < s->mb_width; s->mb_x++) { + ff_init_block_index(&h->c); + for (; h->c.mb_x < h->c.mb_width; h->c.mb_x++) { int ret; - ff_update_block_index(s, s->avctx->bits_per_raw_sample, - s->avctx->lowres, s->chroma_x_shift); + ff_update_block_index(&h->c, h->c.avctx->bits_per_raw_sample, + h->c.avctx->lowres, h->c.chroma_x_shift); - if (s->resync_mb_x == s->mb_x && s->resync_mb_y + 1 == s->mb_y) - s->first_slice_line = 0; + if (h->c.resync_mb_x == h->c.mb_x && h->c.resync_mb_y + 1 == h->c.mb_y) + h->c.first_slice_line = 0; /* DCT & quantize */ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - ff_dlog(s, "%d %06X\n", - get_bits_count(&s->gb), show_bits(&s->gb, 24)); + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + ff_dlog(h->c.avctx, "%d %06X\n", + get_bits_count(&h->gb), show_bits(&h->gb, 24)); - ff_tlog(NULL, "Decoding MB at %dx%d\n", s->mb_x, s->mb_y); - ret = s->decode_mb(s, s->block); + ff_tlog(NULL, "Decoding MB at %dx%d\n", h->c.mb_x, h->c.mb_y); + ret = h->decode_mb(h); - if (s->pict_type != AV_PICTURE_TYPE_B) - ff_h263_update_motion_val(s); + if (h->c.h263_pred || h->c.h263_aic) { + int mb_xy = h->c.mb_y * h->c.mb_stride + h->c.mb_x; + if (!h->c.mb_intra) { + ff_h263_clean_intra_table_entries(&h->c, mb_xy); + } else + h->c.mbintra_table[mb_xy] = 1; + } + + if (h->c.pict_type != AV_PICTURE_TYPE_B) + ff_h263_update_motion_val(&h->c); if (ret < 0) { - const int xy = s->mb_x + s->mb_y * s->mb_stride; + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; if (ret == SLICE_END) { - ff_mpv_reconstruct_mb(s, s->block); - if (s->loop_filter) - ff_h263_loop_filter(s); + ff_mpv_reconstruct_mb(&h->c, h->block); + if (h->loop_filter) + ff_h263_loop_filter(&h->c); - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x, s->mb_y, ER_MB_END & part_mask); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x, h->c.mb_y, ER_MB_END & part_mask); - s->padding_bug_score--; + h->padding_bug_score--; - if (++s->mb_x >= s->mb_width) { - s->mb_x = 0; - ff_mpeg_draw_horiz_band(s, s->mb_y * mb_size, mb_size); - ff_mpv_report_decode_progress(s); - s->mb_y++; + if (++h->c.mb_x >= h->c.mb_width) { + h->c.mb_x = 0; + report_decode_progress(h); + ff_mpeg_draw_horiz_band(&h->c, h->c.mb_y * mb_size, mb_size); + h->c.mb_y++; } return 0; } else if (ret == SLICE_NOEND) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "Slice mismatch at MB: %d\n", xy); - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x + 1, s->mb_y, + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x + 1, h->c.mb_y, ER_MB_END & part_mask); return AVERROR_INVALIDDATA; } - av_log(s->avctx, AV_LOG_ERROR, "Error at MB: %d\n", xy); - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x, s->mb_y, ER_MB_ERROR & part_mask); + av_log(h->c.avctx, AV_LOG_ERROR, "Error at MB: %d\n", xy); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x, h->c.mb_y, ER_MB_ERROR & part_mask); - if ((s->avctx->err_recognition & AV_EF_IGNORE_ERR) && get_bits_left(&s->gb) > 0) + if ((h->c.avctx->err_recognition & AV_EF_IGNORE_ERR) && get_bits_left(&h->gb) > 0) continue; return AVERROR_INVALIDDATA; } - ff_mpv_reconstruct_mb(s, s->block); - if (s->loop_filter) - ff_h263_loop_filter(s); + ff_mpv_reconstruct_mb(&h->c, h->block); + if (h->loop_filter) + ff_h263_loop_filter(&h->c); } - ff_mpeg_draw_horiz_band(s, s->mb_y * mb_size, mb_size); - ff_mpv_report_decode_progress(s); + report_decode_progress(h); + ff_mpeg_draw_horiz_band(&h->c, h->c.mb_y * mb_size, mb_size); - s->mb_x = 0; + h->c.mb_x = 0; } - av_assert1(s->mb_x == 0 && s->mb_y == s->mb_height); + av_assert1(h->c.mb_x == 0 && h->c.mb_y == h->c.mb_height); // Detect incorrect padding with wrong stuffing codes used by NEC N-02B - if (s->codec_id == AV_CODEC_ID_MPEG4 && - (s->workaround_bugs & FF_BUG_AUTODETECT) && - get_bits_left(&s->gb) >= 48 && - show_bits(&s->gb, 24) == 0x4010 && - !s->data_partitioning) - s->padding_bug_score += 32; + if (h->c.codec_id == AV_CODEC_ID_MPEG4 && + (h->c.workaround_bugs & FF_BUG_AUTODETECT) && + get_bits_left(&h->gb) >= 48 && + show_bits(&h->gb, 24) == 0x4010 && + !h->data_partitioning) + h->padding_bug_score += 32; /* try to detect the padding bug */ - if (s->codec_id == AV_CODEC_ID_MPEG4 && - (s->workaround_bugs & FF_BUG_AUTODETECT) && - get_bits_left(&s->gb) >= 0 && - get_bits_left(&s->gb) < 137 && - !s->data_partitioning) { - const int bits_count = get_bits_count(&s->gb); - const int bits_left = s->gb.size_in_bits - bits_count; + if (h->c.codec_id == AV_CODEC_ID_MPEG4 && + (h->c.workaround_bugs & FF_BUG_AUTODETECT) && + get_bits_left(&h->gb) >= 0 && + get_bits_left(&h->gb) < 137 && + !h->data_partitioning) { + const int bits_count = get_bits_count(&h->gb); + const int bits_left = h->gb.size_in_bits - bits_count; if (bits_left == 0) { - s->padding_bug_score += 16; + h->padding_bug_score += 16; } else if (bits_left != 1) { - int v = show_bits(&s->gb, 8); + int v = show_bits(&h->gb, 8); v |= 0x7F >> (7 - (bits_count & 7)); if (v == 0x7F && bits_left <= 8) - s->padding_bug_score--; - else if (v == 0x7F && ((get_bits_count(&s->gb) + 8) & 8) && + h->padding_bug_score--; + else if (v == 0x7F && ((get_bits_count(&h->gb) + 8) & 8) && bits_left <= 16) - s->padding_bug_score += 4; + h->padding_bug_score += 4; else - s->padding_bug_score++; + h->padding_bug_score++; } } - if (s->codec_id == AV_CODEC_ID_H263 && - (s->workaround_bugs & FF_BUG_AUTODETECT) && - get_bits_left(&s->gb) >= 8 && - get_bits_left(&s->gb) < 300 && - s->pict_type == AV_PICTURE_TYPE_I && - show_bits(&s->gb, 8) == 0 && - !s->data_partitioning) { + if (h->c.codec_id == AV_CODEC_ID_H263 && + (h->c.workaround_bugs & FF_BUG_AUTODETECT) && + get_bits_left(&h->gb) >= 8 && + get_bits_left(&h->gb) < 300 && + h->c.pict_type == AV_PICTURE_TYPE_I && + show_bits(&h->gb, 8) == 0 && + !h->data_partitioning) { - s->padding_bug_score += 32; + h->padding_bug_score += 32; } - if (s->codec_id == AV_CODEC_ID_H263 && - (s->workaround_bugs & FF_BUG_AUTODETECT) && - get_bits_left(&s->gb) >= 64 && - AV_RB64(s->gb.buffer_end - 8) == 0xCDCDCDCDFC7F0000) { + if (h->c.codec_id == AV_CODEC_ID_H263 && + (h->c.workaround_bugs & FF_BUG_AUTODETECT) && + get_bits_left(&h->gb) >= 64 && + AV_RB64(h->gb.buffer + (get_bits_bytesize(&h->gb, 0) - 8)) == 0xCDCDCDCDFC7F0000) { - s->padding_bug_score += 32; + h->padding_bug_score += 32; } - if (s->workaround_bugs & FF_BUG_AUTODETECT) { + if (h->c.workaround_bugs & FF_BUG_AUTODETECT) { if ( - (s->padding_bug_score > -2 && !s->data_partitioning)) - s->workaround_bugs |= FF_BUG_NO_PADDING; + (h->padding_bug_score > -2 && !h->data_partitioning)) + h->c.workaround_bugs |= FF_BUG_NO_PADDING; else - s->workaround_bugs &= ~FF_BUG_NO_PADDING; + h->c.workaround_bugs &= ~FF_BUG_NO_PADDING; } // handle formats which don't have unique end markers - if (s->msmpeg4_version != MSMP4_UNUSED || (s->workaround_bugs & FF_BUG_NO_PADDING)) { // FIXME perhaps solve this more cleanly - int left = get_bits_left(&s->gb); + if (h->c.msmpeg4_version != MSMP4_UNUSED || (h->c.workaround_bugs & FF_BUG_NO_PADDING)) { // FIXME perhaps solve this more cleanly + int left = get_bits_left(&h->gb); int max_extra = 7; /* no markers in M$ crap */ - if (s->msmpeg4_version != MSMP4_UNUSED && s->pict_type == AV_PICTURE_TYPE_I) + if (h->c.msmpeg4_version != MSMP4_UNUSED && h->c.pict_type == AV_PICTURE_TYPE_I) max_extra += 17; /* buggy padding but the frame should still end approximately at * the bitstream end */ - if ((s->workaround_bugs & FF_BUG_NO_PADDING) && - (s->avctx->err_recognition & (AV_EF_BUFFER|AV_EF_AGGRESSIVE))) + if ((h->c.workaround_bugs & FF_BUG_NO_PADDING) && + (h->c.avctx->err_recognition & (AV_EF_BUFFER|AV_EF_AGGRESSIVE))) max_extra += 48; - else if ((s->workaround_bugs & FF_BUG_NO_PADDING)) + else if ((h->c.workaround_bugs & FF_BUG_NO_PADDING)) max_extra += 256 * 256 * 256 * 64; if (left > max_extra) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "discarding %d junk bits at end, next would be %X\n", - left, show_bits(&s->gb, 24)); + left, show_bits(&h->gb, 24)); else if (left < 0) - av_log(s->avctx, AV_LOG_ERROR, "overreading %d bits\n", -left); + av_log(h->c.avctx, AV_LOG_ERROR, "overreading %d bits\n", -left); else - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x - 1, s->mb_y, ER_MB_END); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x - 1, h->c.mb_y, ER_MB_END); return 0; } - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "slice end not reached but screenspace end (%d left %06X, score= %d)\n", - get_bits_left(&s->gb), show_bits(&s->gb, 24), s->padding_bug_score); + get_bits_left(&h->gb), show_bits(&h->gb, 24), h->padding_bug_score); - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, h->c.mb_x, h->c.mb_y, ER_MB_END & part_mask); return AVERROR_INVALIDDATA; @@ -426,9 +440,10 @@ static int decode_slice(MpegEncContext *s) int ff_h263_decode_frame(AVCodecContext *avctx, AVFrame *pict, int *got_frame, AVPacket *avpkt) { + H263DecContext *const h = avctx->priv_data; + MPVContext *const s = &h->c; const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; - MpegEncContext *s = avctx->priv_data; int ret; int slice_ret = 0; int bak_width, bak_height; @@ -436,22 +451,19 @@ int ff_h263_decode_frame(AVCodecContext *avctx, AVFrame *pict, /* no supplementary picture */ if (buf_size == 0) { /* special case for last picture */ - if (s->low_delay == 0 && s->next_pic.ptr) { - if ((ret = av_frame_ref(pict, s->next_pic.ptr->f)) < 0) + if ((!h->c.low_delay || h->skipped_last_frame) && h->c.next_pic.ptr) { + if ((ret = av_frame_ref(pict, h->c.next_pic.ptr->f)) < 0) return ret; - ff_mpv_unref_picture(&s->next_pic); + if (h->skipped_last_frame) { + /* If the stream ended with an NVOP, we output the last frame + * in display order, but with the props from the last input + * packet so that the stream's end time is correct. */ + ret = ff_decode_frame_props(avctx, pict); + if (ret < 0) + return ret; + } - *got_frame = 1; - } else if (s->skipped_last_frame && s->cur_pic.ptr) { - /* Output the last picture we decoded again if the stream ended with - * an NVOP */ - if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) - return ret; - /* Copy props from the last input packet. Otherwise, props from the last - * returned picture would be reused */ - if ((ret = ff_decode_frame_props(avctx, pict)) < 0) - return ret; - ff_mpv_unref_picture(&s->cur_pic); + ff_mpv_unref_picture(&h->c.next_pic); *got_frame = 1; } @@ -459,102 +471,61 @@ int ff_h263_decode_frame(AVCodecContext *avctx, AVFrame *pict, return 0; } -retry: - if (s->divx_packed && s->bitstream_buffer_size) { - int i; - for(i=0; i < buf_size-3; i++) { - if (buf[i]==0 && buf[i+1]==0 && buf[i+2]==1) { - if (buf[i+3]==0xB0) { - av_log(s->avctx, AV_LOG_WARNING, "Discarding excessive bitstream in packed xvid\n"); - s->bitstream_buffer_size = 0; - } - break; - } - } - } - - if (s->bitstream_buffer_size && (s->divx_packed || buf_size <= MAX_NVOP_SIZE)) // divx 5.01+/xvid frame reorder - ret = init_get_bits8(&s->gb, s->bitstream_buffer, - s->bitstream_buffer_size); - else - ret = init_get_bits8(&s->gb, buf, buf_size); - - s->bitstream_buffer_size = 0; + // h->gb might be overridden in ff_mpeg4_decode_picture_header() below. + ret = init_get_bits8(&h->gb, buf, buf_size); if (ret < 0) return ret; - bak_width = s->width; - bak_height = s->height; + bak_width = h->c.width; + bak_height = h->c.height; /* let's go :-) */ - if (CONFIG_WMV2_DECODER && s->msmpeg4_version == MSMP4_WMV2) { - ret = ff_wmv2_decode_picture_header(s); -#if CONFIG_MSMPEG4DEC - } else if (s->msmpeg4_version != MSMP4_UNUSED) { - ret = ff_msmpeg4_decode_picture_header(s); -#endif - } else if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4) { - ret = ff_mpeg4_decode_picture_header(avctx->priv_data, &s->gb, 0, 0); - s->skipped_last_frame = (ret == FRAME_SKIPPED); - } else if (CONFIG_H263I_DECODER && s->codec_id == AV_CODEC_ID_H263I) { - ret = ff_intel_h263_decode_picture_header(s); - } else if (CONFIG_FLV_DECODER && s->h263_flv) { - ret = ff_flv_decode_picture_header(s); - } else { - ret = ff_h263_decode_picture_header(s); - } - + ret = h->decode_header(h); if (ret < 0 || ret == FRAME_SKIPPED) { - if ( s->width != bak_width - || s->height != bak_height) { - av_log(s->avctx, AV_LOG_WARNING, "Reverting picture dimensions change due to header decoding failure\n"); - s->width = bak_width; - s->height= bak_height; + if ( h->c.width != bak_width + || h->c.height != bak_height) { + av_log(h->c.avctx, AV_LOG_WARNING, "Reverting picture dimensions change due to header decoding failure\n"); + h->c.width = bak_width; + h->c.height= bak_height; } } if (ret == FRAME_SKIPPED) - return get_consumed_bytes(s, buf_size); + return buf_size; /* skip if the header was thrashed */ if (ret < 0) { - av_log(s->avctx, AV_LOG_ERROR, "header damaged\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "header damaged\n"); return ret; } - if (!s->context_initialized) { + if (!h->c.context_initialized) { avctx->pix_fmt = h263_get_format(avctx); if ((ret = ff_mpv_common_init(s)) < 0) return ret; } - avctx->has_b_frames = !s->low_delay; + avctx->has_b_frames = !h->c.low_delay; - if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4) { - if (s->pict_type != AV_PICTURE_TYPE_B && s->mb_num/2 > get_bits_left(&s->gb)) +#if CONFIG_MPEG4_DECODER + if (avctx->codec_id == AV_CODEC_ID_MPEG4) { + if (h->c.pict_type != AV_PICTURE_TYPE_B && h->c.mb_num/2 > get_bits_left(&h->gb)) return AVERROR_INVALIDDATA; - if (ff_mpeg4_workaround_bugs(avctx) == 1) - goto retry; - if (s->studio_profile != (s->idsp.idct == NULL)) + ff_mpeg4_workaround_bugs(avctx); + if (h->c.studio_profile != (h->c.idsp.idct == NULL)) ff_mpv_idct_init(s); - if (s->mpeg_quant) { - s->dct_unquantize_intra = s->dct_unquantize_mpeg2_intra; - } else { - s->dct_unquantize_intra = s->dct_unquantize_h263_intra; - } } +#endif /* After H.263 & MPEG-4 header decode we have the height, width, - * and other parameters. So then we could init the picture. - * FIXME: By the way H.263 decoder is evolving it should have - * an H263EncContext */ - if (s->width != avctx->coded_width || - s->height != avctx->coded_height || - s->context_reinit) { + * and other parameters. So then we could init the picture. */ + if (h->c.width != avctx->coded_width || + h->c.height != avctx->coded_height || + h->c.context_reinit) { /* H.263 could change picture size any time */ - s->context_reinit = 0; + h->c.context_reinit = 0; - ret = ff_set_dimensions(avctx, s->width, s->height); + ret = ff_set_dimensions(avctx, h->c.width, h->c.height); if (ret < 0) return ret; @@ -570,43 +541,39 @@ retry: } } - if (s->codec_id == AV_CODEC_ID_H263 || - s->codec_id == AV_CODEC_ID_H263P || - s->codec_id == AV_CODEC_ID_H263I) - s->gob_index = H263_GOB_HEIGHT(s->height); - /* skip B-frames if we don't have reference frames */ - if (!s->last_pic.ptr && - (s->pict_type == AV_PICTURE_TYPE_B || s->droppable)) - return get_consumed_bytes(s, buf_size); + if (!h->c.last_pic.ptr && + (h->c.pict_type == AV_PICTURE_TYPE_B || h->c.droppable)) + return buf_size; if ((avctx->skip_frame >= AVDISCARD_NONREF && - s->pict_type == AV_PICTURE_TYPE_B) || + h->c.pict_type == AV_PICTURE_TYPE_B) || (avctx->skip_frame >= AVDISCARD_NONKEY && - s->pict_type != AV_PICTURE_TYPE_I) || + h->c.pict_type != AV_PICTURE_TYPE_I) || avctx->skip_frame >= AVDISCARD_ALL) - return get_consumed_bytes(s, buf_size); + return buf_size; if ((ret = ff_mpv_frame_start(s, avctx)) < 0) return ret; - if (!s->divx_packed && !avctx->hwaccel) + if (!h->divx_packed) ff_thread_finish_setup(avctx); if (avctx->hwaccel) { - ret = FF_HW_CALL(avctx, start_frame, - s->gb.buffer, s->gb.buffer_end - s->gb.buffer); + ret = FF_HW_CALL(avctx, start_frame, NULL, + h->gb.buffer, get_bits_bytesize(&h->gb, 0)); if (ret < 0 ) return ret; } - ff_mpeg_er_frame_start(s); + ff_mpv_er_frame_start_ext(s, h->partitioned_frame, + s->pp_time, s->pb_time); /* the second part of the wmv2 header contains the MB skip bits which * are stored in current_picture->mb_type which is not available before * ff_mpv_frame_start() */ #if CONFIG_WMV2_DECODER - if (s->msmpeg4_version == MSMP4_WMV2) { - ret = ff_wmv2_decode_secondary_picture_header(s); + if (h->c.msmpeg4_version == MSMP4_WMV2) { + ret = ff_wmv2_decode_secondary_picture_header(h); if (ret < 0) return ret; if (ret == 1) @@ -615,40 +582,39 @@ retry: #endif /* decode each macroblock */ - s->mb_x = 0; - s->mb_y = 0; + h->c.mb_x = 0; + h->c.mb_y = 0; - slice_ret = decode_slice(s); - while (s->mb_y < s->mb_height) { - if (s->msmpeg4_version != MSMP4_UNUSED) { - if (s->slice_height == 0 || s->mb_x != 0 || slice_ret < 0 || - (s->mb_y % s->slice_height) != 0 || get_bits_left(&s->gb) < 0) + slice_ret = decode_slice(h); + while (h->c.mb_y < h->c.mb_height) { + if (h->c.msmpeg4_version != MSMP4_UNUSED) { + if (h->slice_height == 0 || h->c.mb_x != 0 || slice_ret < 0 || + (h->c.mb_y % h->slice_height) != 0 || get_bits_left(&h->gb) < 0) break; } else { - int prev_x = s->mb_x, prev_y = s->mb_y; - if (ff_h263_resync(s) < 0) + int prev_x = h->c.mb_x, prev_y = h->c.mb_y; + if (ff_h263_resync(h) < 0) break; - if (prev_y * s->mb_width + prev_x < s->mb_y * s->mb_width + s->mb_x) - s->er.error_occurred = 1; + if (prev_y * h->c.mb_width + prev_x < h->c.mb_y * h->c.mb_width + h->c.mb_x) + h->c.er.error_occurred = 1; } - if (s->msmpeg4_version < MSMP4_WMV1 && s->h263_pred) + if (h->c.msmpeg4_version < MSMP4_WMV1 && h->c.h263_pred) ff_mpeg4_clean_buffers(s); - if (decode_slice(s) < 0) + if (decode_slice(h) < 0) slice_ret = AVERROR_INVALIDDATA; } - if (s->msmpeg4_version != MSMP4_UNUSED && s->msmpeg4_version < MSMP4_WMV1 && - s->pict_type == AV_PICTURE_TYPE_I) + if (h->c.msmpeg4_version != MSMP4_UNUSED && h->c.msmpeg4_version < MSMP4_WMV1 && + h->c.pict_type == AV_PICTURE_TYPE_I) if (!CONFIG_MSMPEG4DEC || - ff_msmpeg4_decode_ext_header(s, buf_size) < 0) - s->er.error_status_table[s->mb_num - 1] = ER_MB_ERROR; + ff_msmpeg4_decode_ext_header(h, buf_size) < 0) + h->c.er.error_status_table[h->c.mb_num - 1] = ER_MB_ERROR; - av_assert1(s->bitstream_buffer_size == 0); frame_end: - if (!s->studio_profile) - ff_er_frame_end(&s->er, NULL); + if (!h->c.studio_profile) + ff_er_frame_end(&h->c.er, NULL); if (avctx->hwaccel) { ret = FF_HW_SIMPLE_CALL(avctx, end_frame); @@ -658,28 +624,27 @@ frame_end: ff_mpv_frame_end(s); - if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4) - ff_mpeg4_frame_end(avctx, buf, buf_size); +#if CONFIG_MPEG4_DECODER + if (avctx->codec_id == AV_CODEC_ID_MPEG4) + ff_mpeg4_frame_end(avctx, avpkt); +#endif - if (!s->divx_packed && avctx->hwaccel) - ff_thread_finish_setup(avctx); - - av_assert1(s->pict_type == s->cur_pic.ptr->f->pict_type); - if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) { - if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) + av_assert1(h->c.pict_type == h->c.cur_pic.ptr->f->pict_type); + if (h->c.pict_type == AV_PICTURE_TYPE_B || h->c.low_delay) { + if ((ret = av_frame_ref(pict, h->c.cur_pic.ptr->f)) < 0) return ret; - ff_print_debug_info(s, s->cur_pic.ptr, pict); - ff_mpv_export_qp_table(s, pict, s->cur_pic.ptr, FF_MPV_QSCALE_TYPE_MPEG1); - } else if (s->last_pic.ptr) { - if ((ret = av_frame_ref(pict, s->last_pic.ptr->f)) < 0) + ff_print_debug_info(s, h->c.cur_pic.ptr, pict); + ff_mpv_export_qp_table(s, pict, h->c.cur_pic.ptr, FF_MPV_QSCALE_TYPE_MPEG1); + } else if (h->c.last_pic.ptr) { + if ((ret = av_frame_ref(pict, h->c.last_pic.ptr->f)) < 0) return ret; - ff_print_debug_info(s, s->last_pic.ptr, pict); - ff_mpv_export_qp_table(s, pict, s->last_pic.ptr, FF_MPV_QSCALE_TYPE_MPEG1); + ff_print_debug_info(s, h->c.last_pic.ptr, pict); + ff_mpv_export_qp_table(s, pict, h->c.last_pic.ptr, FF_MPV_QSCALE_TYPE_MPEG1); } - if (s->last_pic.ptr || s->low_delay) { + if (h->c.last_pic.ptr || h->c.low_delay) { if ( pict->format == AV_PIX_FMT_YUV420P - && (s->codec_tag == AV_RL32("GEOV") || s->codec_tag == AV_RL32("GEOX"))) { + && (h->c.codec_tag == AV_RL32("GEOV") || h->c.codec_tag == AV_RL32("GEOX"))) { for (int p = 0; p < 3; p++) { int h = AV_CEIL_RSHIFT(pict->height, !!p); @@ -693,7 +658,7 @@ frame_end: if (slice_ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) return slice_ret; else - return get_consumed_bytes(s, buf_size); + return buf_size; } static const AVCodecHWConfigInternal *const h263_hw_config_list[] = { @@ -717,7 +682,7 @@ const FFCodec ff_h263_decoder = { CODEC_LONG_NAME("H.263 / H.263-1996, H.263+ / H.263-1998 / H.263 version 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H263, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(H263DecContext), .init = ff_h263_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, @@ -735,7 +700,7 @@ const FFCodec ff_h263p_decoder = { CODEC_LONG_NAME("H.263 / H.263-1996, H.263+ / H.263-1998 / H.263 version 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H263P, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(H263DecContext), .init = ff_h263_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, diff --git a/libavcodec/h263dec.h b/libavcodec/h263dec.h index 633d4aa57..ab647f522 100644 --- a/libavcodec/h263dec.h +++ b/libavcodec/h263dec.h @@ -20,13 +20,10 @@ #ifndef AVCODEC_H263DEC_H #define AVCODEC_H263DEC_H +#include "get_bits.h" #include "mpegvideo.h" #include "vlc.h" - -/** - * Return value for header parsers if frame is not coded. - * */ -#define FRAME_SKIPPED 100 +#include "libavutil/mem_internal.h" // The defines below define the number of bits that are read at once for // reading vlc values. Changing these may improve speed and data cache needs @@ -43,24 +40,86 @@ extern VLCElem ff_h263_inter_MCBPC_vlc[]; extern VLCElem ff_h263_cbpy_vlc[]; extern VLCElem ff_h263_mv_vlc[]; -int ff_h263_decode_motion(MpegEncContext * s, int pred, int f_code); +typedef struct H263DecContext { + MPVContext c; + + GetBitContext gb; + + int mb_num_left; ///< number of MBs left in this video packet (for partitioned slices only) + + int picture_number; + + int pb_frame; ///< PB-frame mode (0 = none, 1 = base, 2 = improved) + + /* motion compensation */ + int h263_long_vectors; ///< use horrible H.263v1 long vector mode + + /* FLV specific */ + int flv; ///< use flv H.263 header + + /* H.263 specific */ + int ehc_mode; + int gob_index; + + /* H.263+ specific */ + int custom_pcf; + int umvplus; ///< == H.263+ && unrestricted_mv + int h263_slice_structured; + int alt_inter_vlc; ///< alternative inter vlc + int loop_filter; + int modified_quant; + + /* MPEG-4 specific */ + int padding_bug_score; ///< used to detect the VERY common padding bug in MPEG-4 + int skipped_last_frame; + int divx_packed; ///< divx specific, used to workaround (many) bugs in divx5 + int data_partitioning; ///< data partitioning flag from header + int partitioned_frame; ///< is current frame partitioned + + /* MSMPEG4 specific */ + int slice_height; ///< in macroblocks + + /* MPEG-4 (Studio Profile), MSMPEG4 and RV10 specific */ + int last_dc[3]; ///< last DC values, used by MPEG4, MSMPEG4V1, RV10 + + /* RV10 specific */ + int rv10_version; ///< RV10 version: 0 or 3 + int rv10_first_dc_coded[3]; + + int (*decode_header)(struct H263DecContext *const h); +#define FRAME_SKIPPED 100 ///< Frame is not coded + + int (*decode_mb)(struct H263DecContext *h); +#define SLICE_OK 0 +#define SLICE_ERROR -1 +#define SLICE_END -2 ///pb, x, f_code); ff_h263_encode_motion(&s->pb, y, f_code); } -static inline int get_p_cbp(MpegEncContext * s, +static inline int get_p_cbp(MPVEncContext *const s, int16_t block[6][64], int motion_x, int motion_y){ int cbp; @@ -53,7 +52,7 @@ static inline int get_p_cbp(MpegEncContext * s, int best_cbpy_score = INT_MAX; int best_cbpc_score = INT_MAX; int cbpc = (-1), cbpy = (-1); - const int offset = (s->mv_type == MV_TYPE_16X16 ? 0 : 16) + (s->dquant ? 8 : 0); + const int offset = (s->c.mv_type == MV_TYPE_16X16 ? 0 : 16) + (s->dquant ? 8 : 0); const int lambda = s->lambda2 >> (FF_LAMBDA_SHIFT - 6); for (int i = 0; i < 4; i++) { @@ -80,21 +79,21 @@ static inline int get_p_cbp(MpegEncContext * s, } } cbp = cbpc + 4 * cbpy; - if (!(motion_x | motion_y | s->dquant) && s->mv_type == MV_TYPE_16X16) { + if (!(motion_x | motion_y | s->dquant) && s->c.mv_type == MV_TYPE_16X16) { if (best_cbpy_score + best_cbpc_score + 2 * lambda >= 0) cbp= 0; } for (int i = 0; i < 6; i++) { - if (s->block_last_index[i] >= 0 && !((cbp >> (5 - i)) & 1)) { - s->block_last_index[i] = -1; - s->bdsp.clear_block(s->block[i]); + if (s->c.block_last_index[i] >= 0 && !((cbp >> (5 - i)) & 1)) { + s->c.block_last_index[i] = -1; + s->c.bdsp.clear_block(s->block[i]); } } } else { cbp = 0; for (int i = 0; i < 6; i++) { - if (s->block_last_index[i] >= 0) + if (s->c.block_last_index[i] >= 0) cbp |= 1 << (5 - i); } } diff --git a/libavcodec/h2645_parse.c b/libavcodec/h2645_parse.c index 82816999e..659e81839 100644 --- a/libavcodec/h2645_parse.c +++ b/libavcodec/h2645_parse.c @@ -22,6 +22,7 @@ #include "config.h" +#include "libavutil/error.h" #include "libavutil/intmath.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" @@ -148,6 +149,47 @@ nsc: return si; } +static const char *const lcevc_nal_type_name[32] = { + "UNSPEC0", // LCEVC_UNSPEC0_NUT + "UNSPEC1", // LCEVC_UNSPEC1_NUT + "UNSPEC2", // LCEVC_UNSPEC2_NUT + "UNSPEC3", // LCEVC_UNSPEC3_NUT + "UNSPEC4", // LCEVC_UNSPEC4_NUT + "UNSPEC5", // LCEVC_UNSPEC5_NUT + "UNSPEC6", // LCEVC_UNSPEC6_NUT + "UNSPEC7", // LCEVC_UNSPEC7_NUT + "UNSPEC8", // LCEVC_UNSPEC8_NUT + "UNSPEC9", // LCEVC_UNSPEC9_NUT + "UNSPEC10", // LCEVC_UNSPEC10_NUT + "UNSPEC11", // LCEVC_UNSPEC11_NUT + "UNSPEC12", // LCEVC_UNSPEC12_NUT + "UNSPEC13", // LCEVC_UNSPEC13_NUT + "UNSPEC14", // LCEVC_UNSPEC14_NUT + "UNSPEC15", // LCEVC_UNSPEC15_NUT + "UNSPEC16", // LCEVC_UNSPEC16_NUT + "UNSPEC17", // LCEVC_UNSPEC17_NUT + "UNSPEC18", // LCEVC_UNSPEC18_NUT + "UNSPEC19", // LCEVC_UNSPEC19_NUT + "UNSPEC20", // LCEVC_UNSPEC20_NUT + "UNSPEC21", // LCEVC_UNSPEC21_NUT + "UNSPEC22", // LCEVC_UNSPEC22_NUT + "UNSPEC23", // LCEVC_UNSPEC23_NUT + "UNSPEC24", // LCEVC_UNSPEC24_NUT + "UNSPEC25", // LCEVC_UNSPEC25_NUT + "UNSPEC26", // LCEVC_UNSPEC26_NUT + "UNSPEC27", // LCEVC_UNSPEC27_NUT + "NON_IDR_NUT", //LCEVC_NON_IDR_NUT + "IDR_NUT", // LCEVC_IDR_NUT + "RSV_NUT", // LCEVC_RSV_NUT + "UNSPEC31", // LCEVC_UNSPEC31_NUT +}; + +static const char *lcevc_nal_unit_name(int nal_type) +{ + av_assert0(nal_type >= 0 && nal_type < 32); + return lcevc_nal_type_name[nal_type]; +} + static const char *const vvc_nal_type_name[32] = { "TRAIL_NUT", // VVC_TRAIL_NUT "STSA_NUT", // VVC_STSA_NUT @@ -337,6 +379,26 @@ static int get_bit_length(H2645NAL *nal, int min_size, int skip_trailing_zeros) * @return AVERROR_INVALIDDATA if the packet is not a valid NAL unit, * 0 otherwise */ + +static int lcevc_parse_nal_header(H2645NAL *nal, void *logctx) +{ + GetBitContext *gb = &nal->gb; + + if (get_bits1(gb) != 0) //forbidden_zero_bit + return AVERROR_INVALIDDATA; + + if (get_bits1(gb) != 1) //forbidden_one_bit + return AVERROR_INVALIDDATA; + + nal->type = get_bits(gb, 5); + + av_log(logctx, AV_LOG_DEBUG, + "nal_unit_type: %d(%s)\n", + nal->type, lcevc_nal_unit_name(nal->type)); + + return 0; +} + static int vvc_parse_nal_header(H2645NAL *nal, void *logctx) { GetBitContext *gb = &nal->gb; @@ -581,6 +643,8 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, if (codec_id == AV_CODEC_ID_VVC) ret = vvc_parse_nal_header(nal, logctx); + else if (codec_id == AV_CODEC_ID_LCEVC) + ret = lcevc_parse_nal_header(nal, logctx); else if (codec_id == AV_CODEC_ID_HEVC) { ret = hevc_parse_nal_header(nal, logctx); if (nal->nuh_layer_id == 63) @@ -588,8 +652,9 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, } else ret = h264_parse_nal_header(nal, logctx); if (ret < 0) { - av_log(logctx, AV_LOG_WARNING, "Invalid NAL unit %d, skipping.\n", - nal->type); + av_log(logctx, AV_LOG_WARNING, + "Failed to parse header of NALU (type %d): \"%s\". Skipping NALU.\n", + nal->type, av_err2str(ret)); continue; } diff --git a/libavcodec/h2645_sei.c b/libavcodec/h2645_sei.c index 9ff8fb8a3..638362fbf 100644 --- a/libavcodec/h2645_sei.c +++ b/libavcodec/h2645_sei.c @@ -32,6 +32,7 @@ #include "libavutil/film_grain_params.h" #include "libavutil/mastering_display_metadata.h" #include "libavutil/mem.h" +#include "libavutil/refstruct.h" #include "libavutil/stereo3d.h" #include "atsc_a53.h" @@ -42,10 +43,10 @@ #include "golomb.h" #include "h2645_sei.h" #include "itut35.h" -#include "refstruct.h" -#define IS_H264(codec_id) (CONFIG_H264_SEI && CONFIG_HEVC_SEI ? codec_id == AV_CODEC_ID_H264 : CONFIG_H264_SEI) -#define IS_HEVC(codec_id) (CONFIG_H264_SEI && CONFIG_HEVC_SEI ? codec_id == AV_CODEC_ID_HEVC : CONFIG_HEVC_SEI) +#define IS_H264(codec_id) (CONFIG_H264_SEI && (CONFIG_HEVC_SEI || CONFIG_VVC_SEI ) ? codec_id == AV_CODEC_ID_H264 : CONFIG_H264_SEI) +#define IS_HEVC(codec_id) (CONFIG_HEVC_SEI && (CONFIG_H264_SEI || CONFIG_VVC_SEI ) ? codec_id == AV_CODEC_ID_HEVC : CONFIG_HEVC_SEI) +#define IS_VVC(codec_id) (CONFIG_VVC_SEI && (CONFIG_H264_SEI || CONFIG_HEVC_SEI) ? codec_id == AV_CODEC_ID_VVC : CONFIG_VVC_SEI ) #if CONFIG_HEVC_SEI static int decode_registered_user_data_dynamic_hdr_plus(HEVCSEIDynamicHDRPlus *s, @@ -157,111 +158,129 @@ static int decode_registered_user_data(H2645SEI *h, GetByteContext *gb, bytestream2_skipu(gb, 1); // itu_t_t35_country_code_extension_byte } - if (country_code != ITU_T_T35_COUNTRY_CODE_US && - country_code != ITU_T_T35_COUNTRY_CODE_UK && - country_code != ITU_T_T35_COUNTRY_CODE_CN) { - av_log(logctx, AV_LOG_VERBOSE, - "Unsupported User Data Registered ITU-T T35 SEI message (country_code = %d)\n", - country_code); - return 0; - } - /* itu_t_t35_payload_byte follows */ - provider_code = bytestream2_get_be16u(gb); - switch (provider_code) { - case ITU_T_T35_PROVIDER_CODE_ATSC: { - uint32_t user_identifier; + switch (country_code) { + case ITU_T_T35_COUNTRY_CODE_US: + provider_code = bytestream2_get_be16u(gb); - if (bytestream2_get_bytes_left(gb) < 4) + switch (provider_code) { + case ITU_T_T35_PROVIDER_CODE_ATSC: { + uint32_t user_identifier; + + if (bytestream2_get_bytes_left(gb) < 4) + return AVERROR_INVALIDDATA; + + user_identifier = bytestream2_get_be32u(gb); + switch (user_identifier) { + case MKBETAG('D', 'T', 'G', '1'): // afd_data + return decode_registered_user_data_afd(&h->afd, gb); + case MKBETAG('G', 'A', '9', '4'): // closed captions + return decode_registered_user_data_closed_caption(&h->a53_caption, gb); + default: + av_log(logctx, AV_LOG_VERBOSE, + "Unsupported User Data Registered ITU-T T35 SEI message (atsc user_identifier = 0x%04x)\n", + user_identifier); + break; + } + break; + } +#if CONFIG_HEVC_SEI + case ITU_T_T35_PROVIDER_CODE_AOM: { + const uint16_t aom_grain_provider_oriented_code = 0x0001; + uint16_t provider_oriented_code; + + if (!IS_HEVC(codec_id)) + break; + + if (bytestream2_get_bytes_left(gb) < 2) + return AVERROR_INVALIDDATA; + + provider_oriented_code = bytestream2_get_byteu(gb); + if (provider_oriented_code == aom_grain_provider_oriented_code) { + return ff_aom_parse_film_grain_sets(&h->aom_film_grain, + gb->buffer, + bytestream2_get_bytes_left(gb)); + } + break; + } + case ITU_T_T35_PROVIDER_CODE_SAMSUNG: { + // A/341 Amendment - 2094-40 + const uint16_t smpte2094_40_provider_oriented_code = 0x0001; + const uint8_t smpte2094_40_application_identifier = 0x04; + uint16_t provider_oriented_code; + uint8_t application_identifier; + + if (!IS_HEVC(codec_id)) + break; + + if (bytestream2_get_bytes_left(gb) < 3) + return AVERROR_INVALIDDATA; + + provider_oriented_code = bytestream2_get_be16u(gb); + application_identifier = bytestream2_get_byteu(gb); + if (provider_oriented_code == smpte2094_40_provider_oriented_code && + application_identifier == smpte2094_40_application_identifier) { + return decode_registered_user_data_dynamic_hdr_plus(&h->dynamic_hdr_plus, gb); + } + break; + } +#endif + default: + break; + } + break; + case ITU_T_T35_COUNTRY_CODE_UK: + bytestream2_skipu(gb, 1); // t35_uk_country_code_second_octet + if (bytestream2_get_bytes_left(gb) < 2) return AVERROR_INVALIDDATA; - user_identifier = bytestream2_get_be32u(gb); - switch (user_identifier) { - case MKBETAG('D', 'T', 'G', '1'): // afd_data - return decode_registered_user_data_afd(&h->afd, gb); - case MKBETAG('G', 'A', '9', '4'): // closed captions - return decode_registered_user_data_closed_caption(&h->a53_caption, gb); + provider_code = bytestream2_get_be16u(gb); + + switch (provider_code) { + case ITU_T_T35_PROVIDER_CODE_VNOVA: + if (bytestream2_get_bytes_left(gb) < 2) + return AVERROR_INVALIDDATA; + + return decode_registered_user_data_lcevc(&h->lcevc, gb); + default: + break; + } + break; +#if CONFIG_HEVC_SEI + case ITU_T_T35_COUNTRY_CODE_CN: { + const uint16_t cuva_provider_oriented_code = 0x0005; + uint16_t provider_oriented_code; + + provider_code = bytestream2_get_be16u(gb); + + switch (provider_code) { + case ITU_T_T35_PROVIDER_CODE_HDR_VIVID: + if (!IS_HEVC(codec_id)) + break; + + if (bytestream2_get_bytes_left(gb) < 2) + return AVERROR_INVALIDDATA; + + provider_oriented_code = bytestream2_get_be16u(gb); + if (provider_oriented_code == cuva_provider_oriented_code) { + return decode_registered_user_data_dynamic_hdr_vivid(&h->dynamic_hdr_vivid, gb); + } + break; default: - av_log(logctx, AV_LOG_VERBOSE, - "Unsupported User Data Registered ITU-T T35 SEI message (atsc user_identifier = 0x%04x)\n", - user_identifier); break; } break; } - case ITU_T_T35_PROVIDER_CODE_LCEVC: { - if (bytestream2_get_bytes_left(gb) < 2) - return AVERROR_INVALIDDATA; - - bytestream2_skipu(gb, 1); // user_data_type_code - return decode_registered_user_data_lcevc(&h->lcevc, gb); - } -#if CONFIG_HEVC_SEI - case ITU_T_T35_PROVIDER_CODE_CUVA: { - const uint16_t cuva_provider_oriented_code = 0x0005; - uint16_t provider_oriented_code; - - if (!IS_HEVC(codec_id)) - goto unsupported_provider_code; - - if (bytestream2_get_bytes_left(gb) < 2) - return AVERROR_INVALIDDATA; - - provider_oriented_code = bytestream2_get_be16u(gb); - if (provider_oriented_code == cuva_provider_oriented_code) { - return decode_registered_user_data_dynamic_hdr_vivid(&h->dynamic_hdr_vivid, gb); - } - break; - } - case ITU_T_T35_PROVIDER_CODE_SMTPE: { - // A/341 Amendment - 2094-40 - const uint16_t smpte2094_40_provider_oriented_code = 0x0001; - const uint8_t smpte2094_40_application_identifier = 0x04; - uint16_t provider_oriented_code; - uint8_t application_identifier; - - if (!IS_HEVC(codec_id)) - goto unsupported_provider_code; - - if (bytestream2_get_bytes_left(gb) < 3) - return AVERROR_INVALIDDATA; - - provider_oriented_code = bytestream2_get_be16u(gb); - application_identifier = bytestream2_get_byteu(gb); - if (provider_oriented_code == smpte2094_40_provider_oriented_code && - application_identifier == smpte2094_40_application_identifier) { - return decode_registered_user_data_dynamic_hdr_plus(&h->dynamic_hdr_plus, gb); - } - break; - } - case 0x5890: { // aom_provider_code - const uint16_t aom_grain_provider_oriented_code = 0x0001; - uint16_t provider_oriented_code; - - if (!IS_HEVC(codec_id)) - goto unsupported_provider_code; - - if (bytestream2_get_bytes_left(gb) < 2) - return AVERROR_INVALIDDATA; - - provider_oriented_code = bytestream2_get_byteu(gb); - if (provider_oriented_code == aom_grain_provider_oriented_code) { - return ff_aom_parse_film_grain_sets(&h->aom_film_grain, - gb->buffer, - bytestream2_get_bytes_left(gb)); - } - break; - } - unsupported_provider_code: #endif default: - av_log(logctx, AV_LOG_VERBOSE, - "Unsupported User Data Registered ITU-T T35 SEI message (provider_code = %d)\n", - provider_code); break; } + av_log(logctx, AV_LOG_VERBOSE, + "Unsupported User Data Registered ITU-T T35 SEI message (country_code = %d, provider_code = %d)\n", + country_code, provider_code); + return 0; } @@ -427,7 +446,7 @@ static int decode_film_grain_characteristics(H2645SEIFilmGrainCharacteristics *h } } } - if (IS_HEVC(codec_id)) + if (!IS_H264(codec_id)) h->persistence_flag = get_bits1(gb); else h->repetition_period = get_ue_golomb_long(gb); @@ -496,8 +515,8 @@ int ff_h2645_sei_message_decode(H2645SEI *h, enum SEIType type, case SEI_TYPE_DISPLAY_ORIENTATION: return decode_display_orientation(&h->display_orientation, gb); case SEI_TYPE_FILM_GRAIN_CHARACTERISTICS: - ff_refstruct_unref(&h->film_grain_characteristics); - h->film_grain_characteristics = ff_refstruct_allocz(sizeof(*h->film_grain_characteristics)); + av_refstruct_unref(&h->film_grain_characteristics); + h->film_grain_characteristics = av_refstruct_allocz(sizeof(*h->film_grain_characteristics)); if (!h->film_grain_characteristics) return AVERROR(ENOMEM); return decode_film_grain_characteristics(h->film_grain_characteristics, codec_id, gb); @@ -556,7 +575,11 @@ int ff_h2645_sei_ctx_replace(H2645SEI *dst, const H2645SEI *src) } dst->aom_film_grain.enable = src->aom_film_grain.enable; - ff_refstruct_replace(&dst->film_grain_characteristics, + dst->ambient_viewing_environment = src->ambient_viewing_environment; + dst->mastering_display = src->mastering_display; + dst->content_light = src->content_light; + + av_refstruct_replace(&dst->film_grain_characteristics, src->film_grain_characteristics); return 0; @@ -804,7 +827,11 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei, if (!sd) av_buffer_unref(&a53->buf_ref); a53->buf_ref = NULL; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif } ret = h2645_sei_to_side_data(avctx, sei, &frame->side_data, &frame->nb_side_data); @@ -847,7 +874,7 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei, fgp->subsampling_x = fgp->subsampling_y = 0; h274->model_id = fgc->model_id; - if (fgc->separate_colour_description_present_flag) { + if (IS_VVC(codec_id) || fgc->separate_colour_description_present_flag) { fgp->bit_depth_luma = fgc->bit_depth_luma; fgp->bit_depth_chroma = fgc->bit_depth_chroma; fgp->color_range = fgc->full_range + 1; @@ -868,17 +895,6 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei, h274->blending_mode_id = fgc->blending_mode_id; h274->log2_scale_factor = fgc->log2_scale_factor; -#if FF_API_H274_FILM_GRAIN_VCS -FF_DISABLE_DEPRECATION_WARNINGS - h274->bit_depth_luma = fgp->bit_depth_luma; - h274->bit_depth_chroma = fgp->bit_depth_chroma; - h274->color_range = fgp->color_range; - h274->color_primaries = fgp->color_primaries; - h274->color_trc = fgp->color_trc; - h274->color_space = fgp->color_space; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - memcpy(&h274->component_model_present, &fgc->comp_model_present_flag, sizeof(h274->component_model_present)); memcpy(&h274->num_intensity_intervals, &fgc->num_intensity_intervals, @@ -897,7 +913,11 @@ FF_ENABLE_DEPRECATION_WARNINGS else fgc->present = fgc->persistence_flag; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_FILM_GRAIN; +FF_ENABLE_DEPRECATION_WARNINGS +#endif } #if CONFIG_HEVC_SEI @@ -931,6 +951,6 @@ void ff_h2645_sei_reset(H2645SEI *s) s->mastering_display.present = 0; s->content_light.present = 0; - ff_refstruct_unref(&s->film_grain_characteristics); + av_refstruct_unref(&s->film_grain_characteristics); ff_aom_uninit_film_grain_params(&s->aom_film_grain); } diff --git a/libavcodec/h2645_sei.h b/libavcodec/h2645_sei.h index abc49760d..f2ad7147c 100644 --- a/libavcodec/h2645_sei.h +++ b/libavcodec/h2645_sei.h @@ -108,7 +108,7 @@ typedef struct H2645SEIFilmGrainCharacteristics { uint8_t intensity_interval_upper_bound[3][256]; int16_t comp_model_value[3][256][6]; int repetition_period; //< H.264 only - int persistence_flag; //< HEVC only + int persistence_flag; //< HEVC/VVC } H2645SEIFilmGrainCharacteristics; typedef struct H2645SEIMasteringDisplay { diff --git a/libavcodec/h2645_vui.c b/libavcodec/h2645_vui.c index e5c7bf46f..0e576c156 100644 --- a/libavcodec/h2645_vui.c +++ b/libavcodec/h2645_vui.c @@ -67,11 +67,16 @@ void ff_h2645_decode_common_vui_params(GetBitContext *gb, H2645VUI *vui, void *l vui->matrix_coeffs = get_bits(gb, 8); // Set invalid values to "unspecified" - if (!av_color_primaries_name(vui->colour_primaries)) + if (vui->colour_primaries == AVCOL_PRI_RESERVED0 || + vui->colour_primaries == AVCOL_PRI_RESERVED || + !av_color_primaries_name(vui->colour_primaries)) vui->colour_primaries = AVCOL_PRI_UNSPECIFIED; - if (!av_color_transfer_name(vui->transfer_characteristics)) + if (vui->transfer_characteristics == AVCOL_TRC_RESERVED0 || + vui->transfer_characteristics == AVCOL_TRC_RESERVED || + !av_color_transfer_name(vui->transfer_characteristics)) vui->transfer_characteristics = AVCOL_TRC_UNSPECIFIED; - if (!av_color_space_name(vui->matrix_coeffs)) + if (vui->matrix_coeffs == AVCOL_SPC_RESERVED || + !av_color_space_name(vui->matrix_coeffs)) vui->matrix_coeffs = AVCOL_SPC_UNSPECIFIED; } } diff --git a/libavcodec/h264_loopfilter.c b/libavcodec/h264_loopfilter.c index c164a289b..e2fc886bb 100644 --- a/libavcodec/h264_loopfilter.c +++ b/libavcodec/h264_loopfilter.c @@ -113,9 +113,9 @@ static av_always_inline void filter_mb_edgev(uint8_t *pix, int stride, tc[1] = tc0_table[index_a][bS[1]]; tc[2] = tc0_table[index_a][bS[2]]; tc[3] = tc0_table[index_a][bS[3]]; - h->h264dsp.h264_h_loop_filter_luma(pix, stride, alpha, beta, tc); + h->h264dsp.h_loop_filter_luma(pix, stride, alpha, beta, tc); } else { - h->h264dsp.h264_h_loop_filter_luma_intra(pix, stride, alpha, beta); + h->h264dsp.h_loop_filter_luma_intra(pix, stride, alpha, beta); } } @@ -135,9 +135,9 @@ static av_always_inline void filter_mb_edgecv(uint8_t *pix, int stride, tc[1] = tc0_table[index_a][bS[1]]+1; tc[2] = tc0_table[index_a][bS[2]]+1; tc[3] = tc0_table[index_a][bS[3]]+1; - h->h264dsp.h264_h_loop_filter_chroma(pix, stride, alpha, beta, tc); + h->h264dsp.h_loop_filter_chroma(pix, stride, alpha, beta, tc); } else { - h->h264dsp.h264_h_loop_filter_chroma_intra(pix, stride, alpha, beta); + h->h264dsp.h_loop_filter_chroma_intra(pix, stride, alpha, beta); } } @@ -158,9 +158,9 @@ static av_always_inline void filter_mb_mbaff_edgev(const H264Context *h, uint8_t tc[1] = tc0_table[index_a][bS[1*bsi]]; tc[2] = tc0_table[index_a][bS[2*bsi]]; tc[3] = tc0_table[index_a][bS[3*bsi]]; - h->h264dsp.h264_h_loop_filter_luma_mbaff(pix, stride, alpha, beta, tc); + h->h264dsp.h_loop_filter_luma_mbaff(pix, stride, alpha, beta, tc); } else { - h->h264dsp.h264_h_loop_filter_luma_mbaff_intra(pix, stride, alpha, beta); + h->h264dsp.h_loop_filter_luma_mbaff_intra(pix, stride, alpha, beta); } } @@ -181,9 +181,9 @@ static av_always_inline void filter_mb_mbaff_edgecv(const H264Context *h, tc[1] = tc0_table[index_a][bS[1*bsi]] + 1; tc[2] = tc0_table[index_a][bS[2*bsi]] + 1; tc[3] = tc0_table[index_a][bS[3*bsi]] + 1; - h->h264dsp.h264_h_loop_filter_chroma_mbaff(pix, stride, alpha, beta, tc); + h->h264dsp.h_loop_filter_chroma_mbaff(pix, stride, alpha, beta, tc); } else { - h->h264dsp.h264_h_loop_filter_chroma_mbaff_intra(pix, stride, alpha, beta); + h->h264dsp.h_loop_filter_chroma_mbaff_intra(pix, stride, alpha, beta); } } @@ -203,9 +203,9 @@ static av_always_inline void filter_mb_edgeh(uint8_t *pix, int stride, tc[1] = tc0_table[index_a][bS[1]]; tc[2] = tc0_table[index_a][bS[2]]; tc[3] = tc0_table[index_a][bS[3]]; - h->h264dsp.h264_v_loop_filter_luma(pix, stride, alpha, beta, tc); + h->h264dsp.v_loop_filter_luma(pix, stride, alpha, beta, tc); } else { - h->h264dsp.h264_v_loop_filter_luma_intra(pix, stride, alpha, beta); + h->h264dsp.v_loop_filter_luma_intra(pix, stride, alpha, beta); } } @@ -225,9 +225,9 @@ static av_always_inline void filter_mb_edgech(uint8_t *pix, int stride, tc[1] = tc0_table[index_a][bS[1]]+1; tc[2] = tc0_table[index_a][bS[2]]+1; tc[3] = tc0_table[index_a][bS[3]]+1; - h->h264dsp.h264_v_loop_filter_chroma(pix, stride, alpha, beta, tc); + h->h264dsp.v_loop_filter_chroma(pix, stride, alpha, beta, tc); } else { - h->h264dsp.h264_v_loop_filter_chroma_intra(pix, stride, alpha, beta); + h->h264dsp.v_loop_filter_chroma_intra(pix, stride, alpha, beta); } } @@ -368,8 +368,8 @@ static av_always_inline void h264_filter_mb_fast_internal(const H264Context *h, int mask_edge0 = 3*((mask_edge1>>1) & ((5*left_type)>>5)&1); // (mb_type & (MB_TYPE_16x16 | MB_TYPE_8x16)) && (h->left_type[LTOP] & (MB_TYPE_16x16 | MB_TYPE_8x16)) ? 3 : 0; int step = 1+(mb_type>>24); //IS_8x8DCT(mb_type) ? 2 : 1; edges = 4 - 3*((mb_type>>3) & !(sl->cbp & 15)); //(mb_type & MB_TYPE_16x16) && !(h->cbp & 15) ? 1 : 4; - h->h264dsp.h264_loop_filter_strength(bS, sl->non_zero_count_cache, sl->ref_cache, sl->mv_cache, - sl->list_count==2, edges, step, mask_edge0, mask_edge1, FIELD_PICTURE(h)); + h->h264dsp.loop_filter_strength(bS, sl->non_zero_count_cache, sl->ref_cache, sl->mv_cache, + sl->list_count==2, edges, step, mask_edge0, mask_edge1, FIELD_PICTURE(h)); } if( IS_INTRA(left_type) ) AV_WN64A(bS[0][0], 0x0004000400040004ULL); @@ -419,7 +419,7 @@ void ff_h264_filter_mb_fast(const H264Context *h, H264SliceContext *sl, unsigned int linesize, unsigned int uvlinesize) { av_assert2(!FRAME_MBAFF(h)); - if(!h->h264dsp.h264_loop_filter_strength || h->ps.pps->chroma_qp_diff) { + if (!h->h264dsp.loop_filter_strength || h->ps.pps->chroma_qp_diff) { ff_h264_filter_mb(h, sl, mb_x, mb_y, img_y, img_cb, img_cr, linesize, uvlinesize); return; } diff --git a/libavcodec/h264_mb.c b/libavcodec/h264_mb.c index 2db067047..67fa980de 100644 --- a/libavcodec/h264_mb.c +++ b/libavcodec/h264_mb.c @@ -529,7 +529,7 @@ static av_always_inline void xchg_mb_border(const H264Context *h, H264SliceConte } if (sl->deblocking_filter == 2) { - deblock_topleft = h->slice_table[sl->mb_xy - 1 - h->mb_stride] == sl->slice_num; + deblock_topleft = h->slice_table[sl->mb_xy - 1 - (h->mb_stride << MB_FIELD(sl))] == sl->slice_num; deblock_top = sl->top_type; } else { deblock_topleft = (sl->mb_x > 0); @@ -629,10 +629,10 @@ static av_always_inline void hl_decode_mb_predict_luma(const H264Context *h, if (IS_8x8DCT(mb_type)) { if (transform_bypass) { idct_dc_add = - idct_add = h->h264dsp.h264_add_pixels8_clear; + idct_add = h->h264dsp.add_pixels8_clear; } else { - idct_dc_add = h->h264dsp.h264_idct8_dc_add; - idct_add = h->h264dsp.h264_idct8_add; + idct_dc_add = h->h264dsp.idct8_dc_add; + idct_add = h->h264dsp.idct8_add; } for (i = 0; i < 16; i += 4) { uint8_t *const ptr = dest_y + block_offset[i]; @@ -658,11 +658,11 @@ static av_always_inline void hl_decode_mb_predict_luma(const H264Context *h, } } else { if (transform_bypass) { - idct_dc_add = - idct_add = h->h264dsp.h264_add_pixels4_clear; + idct_dc_add = + idct_add = h->h264dsp.add_pixels4_clear; } else { - idct_dc_add = h->h264dsp.h264_idct_dc_add; - idct_add = h->h264dsp.h264_idct_add; + idct_dc_add = h->h264dsp.idct_dc_add; + idct_add = h->h264dsp.idct_add; } for (i = 0; i < 16; i++) { uint8_t *const ptr = dest_y + block_offset[i]; @@ -705,9 +705,9 @@ static av_always_inline void hl_decode_mb_predict_luma(const H264Context *h, h->hpc.pred16x16[sl->intra16x16_pred_mode](dest_y, linesize); if (sl->non_zero_count_cache[scan8[LUMA_DC_BLOCK_INDEX + p]]) { if (!transform_bypass) - h->h264dsp.h264_luma_dc_dequant_idct(sl->mb + (p * 256 << pixel_shift), - sl->mb_luma_dc[p], - h->ps.pps->dequant4_coeff[p][qscale][0]); + h->h264dsp.luma_dc_dequant_idct(sl->mb + (p * 256 << pixel_shift), + sl->mb_luma_dc[p], + h->ps.pps->dequant4_coeff[p][qscale][0]); else { static const uint8_t dc_mapping[16] = { 0 * 16, 1 * 16, 4 * 16, 5 * 16, @@ -749,21 +749,21 @@ static av_always_inline void hl_decode_mb_idct_luma(const H264Context *h, H264Sl for (i = 0; i < 16; i++) if (sl->non_zero_count_cache[scan8[i + p * 16]] || dctcoef_get(sl->mb, pixel_shift, i * 16 + p * 256)) - h->h264dsp.h264_add_pixels4_clear(dest_y + block_offset[i], - sl->mb + (i * 16 + p * 256 << pixel_shift), - linesize); + h->h264dsp.add_pixels4_clear(dest_y + block_offset[i], + sl->mb + (i * 16 + p * 256 << pixel_shift), + linesize); } } else { - h->h264dsp.h264_idct_add16intra(dest_y, block_offset, - sl->mb + (p * 256 << pixel_shift), - linesize, - sl->non_zero_count_cache + p * 5 * 8); + h->h264dsp.idct_add16intra(dest_y, block_offset, + sl->mb + (p * 256 << pixel_shift), + linesize, + sl->non_zero_count_cache + p * 5 * 8); } } else if (sl->cbp & 15) { if (transform_bypass) { const int di = IS_8x8DCT(mb_type) ? 4 : 1; - idct_add = IS_8x8DCT(mb_type) ? h->h264dsp.h264_add_pixels8_clear - : h->h264dsp.h264_add_pixels4_clear; + idct_add = IS_8x8DCT(mb_type) ? h->h264dsp.add_pixels8_clear + : h->h264dsp.add_pixels4_clear; for (i = 0; i < 16; i += di) if (sl->non_zero_count_cache[scan8[i + p * 16]]) idct_add(dest_y + block_offset[i], @@ -771,15 +771,15 @@ static av_always_inline void hl_decode_mb_idct_luma(const H264Context *h, H264Sl linesize); } else { if (IS_8x8DCT(mb_type)) - h->h264dsp.h264_idct8_add4(dest_y, block_offset, - sl->mb + (p * 256 << pixel_shift), - linesize, - sl->non_zero_count_cache + p * 5 * 8); + h->h264dsp.idct8_add4(dest_y, block_offset, + sl->mb + (p * 256 << pixel_shift), + linesize, + sl->non_zero_count_cache + p * 5 * 8); else - h->h264dsp.h264_idct_add16(dest_y, block_offset, - sl->mb + (p * 256 << pixel_shift), - linesize, - sl->non_zero_count_cache + p * 5 * 8); + h->h264dsp.idct_add16(dest_y, block_offset, + sl->mb + (p * 256 << pixel_shift), + linesize, + sl->non_zero_count_cache + p * 5 * 8); } } } diff --git a/libavcodec/h264_mb_template.c b/libavcodec/h264_mb_template.c index d5ea26a6e..ee8c81a10 100644 --- a/libavcodec/h264_mb_template.c +++ b/libavcodec/h264_mb_template.c @@ -174,16 +174,16 @@ static av_noinline void FUNC(hl_decode_mb)(const H264Context *h, H264SliceContex h->h264chroma.put_h264_chroma_pixels_tab, h->h264qpel.avg_h264_qpel_pixels_tab, h->h264chroma.avg_h264_chroma_pixels_tab, - h->h264dsp.weight_h264_pixels_tab, - h->h264dsp.biweight_h264_pixels_tab); + h->h264dsp.weight_pixels_tab, + h->h264dsp.biweight_pixels_tab); } else { FUNC(hl_motion_420)(h, sl, dest_y, dest_cb, dest_cr, h->h264qpel.put_h264_qpel_pixels_tab, h->h264chroma.put_h264_chroma_pixels_tab, h->h264qpel.avg_h264_qpel_pixels_tab, h->h264chroma.avg_h264_chroma_pixels_tab, - h->h264dsp.weight_h264_pixels_tab, - h->h264dsp.biweight_h264_pixels_tab); + h->h264dsp.weight_pixels_tab, + h->h264dsp.biweight_pixels_tab); } } @@ -206,7 +206,7 @@ static av_noinline void FUNC(hl_decode_mb)(const H264Context *h, H264SliceContex sl->mb + (16 * 16 * 2 << PIXEL_SHIFT), uvlinesize); } else { - idct_add = h->h264dsp.h264_add_pixels4_clear; + idct_add = h->h264dsp.add_pixels4_clear; for (j = 1; j < 3; j++) { for (i = j * 16; i < j * 16 + 4; i++) if (sl->non_zero_count_cache[scan8[i]] || @@ -234,14 +234,14 @@ static av_noinline void FUNC(hl_decode_mb)(const H264Context *h, H264SliceContex qp[1] = sl->chroma_qp[1]; } if (sl->non_zero_count_cache[scan8[CHROMA_DC_BLOCK_INDEX + 0]]) - h->h264dsp.h264_chroma_dc_dequant_idct(sl->mb + (16 * 16 * 1 << PIXEL_SHIFT), - h->ps.pps->dequant4_coeff[IS_INTRA(mb_type) ? 1 : 4][qp[0]][0]); + h->h264dsp.chroma_dc_dequant_idct(sl->mb + (16 * 16 * 1 << PIXEL_SHIFT), + h->ps.pps->dequant4_coeff[IS_INTRA(mb_type) ? 1 : 4][qp[0]][0]); if (sl->non_zero_count_cache[scan8[CHROMA_DC_BLOCK_INDEX + 1]]) - h->h264dsp.h264_chroma_dc_dequant_idct(sl->mb + (16 * 16 * 2 << PIXEL_SHIFT), - h->ps.pps->dequant4_coeff[IS_INTRA(mb_type) ? 2 : 5][qp[1]][0]); - h->h264dsp.h264_idct_add8(dest, block_offset, - sl->mb, uvlinesize, - sl->non_zero_count_cache); + h->h264dsp.chroma_dc_dequant_idct(sl->mb + (16 * 16 * 2 << PIXEL_SHIFT), + h->ps.pps->dequant4_coeff[IS_INTRA(mb_type) ? 2 : 5][qp[1]][0]); + h->h264dsp.idct_add8(dest, block_offset, + sl->mb, uvlinesize, + sl->non_zero_count_cache); } } } @@ -341,8 +341,8 @@ static av_noinline void FUNC(hl_decode_mb_444)(const H264Context *h, H264SliceCo h->h264chroma.put_h264_chroma_pixels_tab, h->h264qpel.avg_h264_qpel_pixels_tab, h->h264chroma.avg_h264_chroma_pixels_tab, - h->h264dsp.weight_h264_pixels_tab, - h->h264dsp.biweight_h264_pixels_tab); + h->h264dsp.weight_pixels_tab, + h->h264dsp.biweight_pixels_tab); } for (p = 0; p < plane_count; p++) diff --git a/libavcodec/h264_mvpred.h b/libavcodec/h264_mvpred.h index bc9fef50e..1fa548732 100644 --- a/libavcodec/h264_mvpred.h +++ b/libavcodec/h264_mvpred.h @@ -931,7 +931,7 @@ static void fill_decode_caches(const H264Context *h, H264SliceContext *sl, int m /** * decodes a P_SKIP or B_SKIP macroblock */ -static void av_unused decode_mb_skip(const H264Context *h, H264SliceContext *sl) +av_unused static void decode_mb_skip(const H264Context *h, H264SliceContext *sl) { const int mb_xy = sl->mb_xy; int mb_type = 0; diff --git a/libavcodec/h264_parse.h b/libavcodec/h264_parse.h index 3481451c1..ad5099edb 100644 --- a/libavcodec/h264_parse.h +++ b/libavcodec/h264_parse.h @@ -36,7 +36,7 @@ #define MB_TYPE_REF0 MB_TYPE_CODEC_SPECIFIC #define MB_TYPE_8x8DCT 0x01000000 -// This table must be here because scan8[constant] must be known at compiletime +// This table must be here because scan8[constant] must be known at compile time static const uint8_t scan8[16 * 3 + 3] = { 4 + 1 * 8, 5 + 1 * 8, 4 + 2 * 8, 5 + 2 * 8, 6 + 1 * 8, 7 + 1 * 8, 6 + 2 * 8, 7 + 2 * 8, diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c index 450456185..607eb5502 100644 --- a/libavcodec/h264_parser.c +++ b/libavcodec/h264_parser.c @@ -29,6 +29,7 @@ #include +#include "libavutil/attributes.h" #include "libavutil/avutil.h" #include "libavutil/error.h" #include "libavutil/log.h" @@ -47,7 +48,8 @@ #include "h264data.h" #include "mpegutils.h" #include "parser.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" +#include "parser_internal.h" #include "startcode.h" typedef struct H264ParseContext { @@ -377,7 +379,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, goto fail; } - ff_refstruct_replace(&p->ps.pps, p->ps.pps_list[pps_id]); + av_refstruct_replace(&p->ps.pps, p->ps.pps_list[pps_id]); p->ps.sps = p->ps.pps->sps; sps = p->ps.sps; @@ -667,7 +669,7 @@ static int h264_parse(AVCodecParserContext *s, return next; } -static void h264_close(AVCodecParserContext *s) +static av_cold void h264_close(AVCodecParserContext *s) { H264ParseContext *p = s->priv_data; ParseContext *pc = &p->pc; @@ -688,10 +690,10 @@ static av_cold int init(AVCodecParserContext *s) return 0; } -const AVCodecParser ff_h264_parser = { - .codec_ids = { AV_CODEC_ID_H264 }, +const FFCodecParser ff_h264_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_H264), .priv_data_size = sizeof(H264ParseContext), - .parser_init = init, - .parser_parse = h264_parse, - .parser_close = h264_close, + .init = init, + .parse = h264_parse, + .close = h264_close, }; diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c index 3234141db..aa3d2629c 100644 --- a/libavcodec/h264_picture.c +++ b/libavcodec/h264_picture.c @@ -30,10 +30,10 @@ #include "error_resilience.h" #include "avcodec.h" #include "h264dec.h" +#include "h274.h" #include "hwaccel_internal.h" #include "mpegutils.h" -#include "refstruct.h" -#include "thread.h" +#include "libavutil/refstruct.h" #include "threadframe.h" void ff_h264_unref_picture(H264Picture *pic) @@ -46,35 +46,35 @@ void ff_h264_unref_picture(H264Picture *pic) ff_thread_release_ext_buffer(&pic->tf); av_frame_unref(pic->f_grain); - ff_refstruct_unref(&pic->hwaccel_picture_private); + av_refstruct_unref(&pic->hwaccel_picture_private); - ff_refstruct_unref(&pic->qscale_table_base); - ff_refstruct_unref(&pic->mb_type_base); - ff_refstruct_unref(&pic->pps); + av_refstruct_unref(&pic->qscale_table_base); + av_refstruct_unref(&pic->mb_type_base); + av_refstruct_unref(&pic->pps); for (i = 0; i < 2; i++) { - ff_refstruct_unref(&pic->motion_val_base[i]); - ff_refstruct_unref(&pic->ref_index[i]); + av_refstruct_unref(&pic->motion_val_base[i]); + av_refstruct_unref(&pic->ref_index[i]); } - ff_refstruct_unref(&pic->decode_error_flags); + av_refstruct_unref(&pic->decode_error_flags); memset((uint8_t*)pic + off, 0, sizeof(*pic) - off); } static void h264_copy_picture_params(H264Picture *dst, const H264Picture *src) { - ff_refstruct_replace(&dst->qscale_table_base, src->qscale_table_base); - ff_refstruct_replace(&dst->mb_type_base, src->mb_type_base); - ff_refstruct_replace(&dst->pps, src->pps); + av_refstruct_replace(&dst->qscale_table_base, src->qscale_table_base); + av_refstruct_replace(&dst->mb_type_base, src->mb_type_base); + av_refstruct_replace(&dst->pps, src->pps); for (int i = 0; i < 2; i++) { - ff_refstruct_replace(&dst->motion_val_base[i], src->motion_val_base[i]); - ff_refstruct_replace(&dst->ref_index[i], src->ref_index[i]); + av_refstruct_replace(&dst->motion_val_base[i], src->motion_val_base[i]); + av_refstruct_replace(&dst->ref_index[i], src->ref_index[i]); } - ff_refstruct_replace(&dst->hwaccel_picture_private, + av_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); - ff_refstruct_replace(&dst->decode_error_flags, src->decode_error_flags); + av_refstruct_replace(&dst->decode_error_flags, src->decode_error_flags); dst->qscale_table = src->qscale_table; dst->mb_type = src->mb_type; @@ -213,7 +213,7 @@ int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup) err = AVERROR_INVALIDDATA; if (sd) // a decoding error may have happened before the side data could be allocated - err = ff_h274_apply_film_grain(cur->f_grain, cur->f, &h->h274db, + err = ff_h274_apply_film_grain(cur->f_grain, cur->f, (AVFilmGrainParams *) sd->data); if (err < 0) { av_log(h->avctx, AV_LOG_WARNING, "Failed synthesizing film " diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c index 3c8fc33c7..ac204172c 100644 --- a/libavcodec/h264_ps.c +++ b/libavcodec/h264_ps.c @@ -34,7 +34,7 @@ #include "h2645_vui.h" #include "h264_ps.h" #include "golomb.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #define MIN_LOG2_MAX_FRAME_NUM 4 @@ -86,7 +86,7 @@ static const int level_max_dpb_mbs[][2] = { static void remove_pps(H264ParamSets *s, int id) { - ff_refstruct_unref(&s->pps_list[id]); + av_refstruct_unref(&s->pps_list[id]); } static void remove_sps(H264ParamSets *s, int id) @@ -100,7 +100,7 @@ static void remove_sps(H264ParamSets *s, int id) remove_pps(s, i); } #endif - ff_refstruct_unref(&s->sps_list[id]); + av_refstruct_unref(&s->sps_list[id]); } static inline int decode_hrd_parameters(GetBitContext *gb, void *logctx, @@ -272,12 +272,12 @@ void ff_h264_ps_uninit(H264ParamSets *ps) int i; for (i = 0; i < MAX_SPS_COUNT; i++) - ff_refstruct_unref(&ps->sps_list[i]); + av_refstruct_unref(&ps->sps_list[i]); for (i = 0; i < MAX_PPS_COUNT; i++) - ff_refstruct_unref(&ps->pps_list[i]); + av_refstruct_unref(&ps->pps_list[i]); - ff_refstruct_unref(&ps->pps); + av_refstruct_unref(&ps->pps); ps->sps = NULL; } @@ -290,11 +290,11 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, SPS *sps; int ret; - sps = ff_refstruct_allocz(sizeof(*sps)); + sps = av_refstruct_allocz(sizeof(*sps)); if (!sps) return AVERROR(ENOMEM); - sps->data_size = gb->buffer_end - gb->buffer; + sps->data_size = get_bits_bytesize(gb, 1); if (sps->data_size > sizeof(sps->data)) { av_log(avctx, AV_LOG_DEBUG, "Truncating likely oversized SPS\n"); sps->data_size = sizeof(sps->data); @@ -578,7 +578,7 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, * otherwise drop all PPSes that depend on it */ if (ps->sps_list[sps_id] && !memcmp(ps->sps_list[sps_id], sps, sizeof(*sps))) { - ff_refstruct_unref(&sps); + av_refstruct_unref(&sps); } else { remove_sps(ps, sps_id); ps->sps_list[sps_id] = sps; @@ -587,7 +587,7 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, return 0; fail: - ff_refstruct_unref(&sps); + av_refstruct_unref(&sps); return AVERROR_INVALIDDATA; } @@ -686,11 +686,11 @@ static int more_rbsp_data_in_pps(const SPS *sps, void *logctx) return 1; } -static void pps_free(FFRefStructOpaque unused, void *obj) +static void pps_free(AVRefStructOpaque unused, void *obj) { PPS *pps = obj; - ff_refstruct_unref(&pps->sps); + av_refstruct_unref(&pps->sps); } int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avctx, @@ -708,14 +708,14 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct return AVERROR_INVALIDDATA; } - pps = ff_refstruct_alloc_ext(sizeof(*pps), 0, NULL, pps_free); + pps = av_refstruct_alloc_ext(sizeof(*pps), 0, NULL, pps_free); if (!pps) return AVERROR(ENOMEM); - pps->data_size = gb->buffer_end - gb->buffer; + pps->data_size = get_bits_bytesize(gb, 1); if (pps->data_size > sizeof(pps->data)) { av_log(avctx, AV_LOG_DEBUG, "Truncating likely oversized PPS " - "(%"SIZE_SPECIFIER" > %"SIZE_SPECIFIER")\n", + "(%zu > %zu)\n", pps->data_size, sizeof(pps->data)); pps->data_size = sizeof(pps->data); } @@ -733,7 +733,7 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct ret = AVERROR_INVALIDDATA; goto fail; } - pps->sps = ff_refstruct_ref_c(ps->sps_list[pps->sps_id]); + pps->sps = av_refstruct_ref_c(ps->sps_list[pps->sps_id]); sps = pps->sps; if (sps->bit_depth_luma > 14) { @@ -840,6 +840,6 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct return 0; fail: - ff_refstruct_unref(&pps); + av_refstruct_unref(&pps); return ret; } diff --git a/libavcodec/h264_ps.h b/libavcodec/h264_ps.h index 80af4832f..f216e4989 100644 --- a/libavcodec/h264_ps.h +++ b/libavcodec/h264_ps.h @@ -57,7 +57,7 @@ typedef struct SPS { int ref_frame_count; ///< num_ref_frames int gaps_in_frame_num_allowed_flag; int mb_width; ///< pic_width_in_mbs_minus1 + 1 - ///< (pic_height_in_map_units_minus1 + 1) * (2 - frame_mbs_only_flag) + /// (pic_height_in_map_units_minus1 + 1) * (2 - frame_mbs_only_flag) int mb_height; int frame_mbs_only_flag; int mb_aff; ///< mb_adaptive_frame_field_flag diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index c7dc429ae..b743858cd 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -335,7 +335,7 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) break; } if (i >= 0) - ref->pic_id = pred; + pic_id = pred; break; } case 2: { @@ -352,7 +352,6 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) ref = h->long_ref[long_idx]; assert(!(ref && !ref->reference)); if (ref && (ref->reference & pic_structure)) { - ref->pic_id = pic_id; assert(ref->long_ref); i = 0; } else { @@ -369,12 +368,15 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) i < 0 ? "reference picture missing during reorder\n" : "mismatching reference\n" ); + if (h->avctx->err_recognition & AV_EF_EXPLODE) { + return AVERROR_INVALIDDATA; + } memset(&sl->ref_list[list][index], 0, sizeof(sl->ref_list[0][0])); // FIXME } else { for (i = index; i + 1 < sl->ref_count[list]; i++) { if (sl->ref_list[list][i].parent && ref->long_ref == sl->ref_list[list][i].parent->long_ref && - ref->pic_id == sl->ref_list[list][i].pic_id) + pic_id == sl->ref_list[list][i].pic_id) break; } for (; i > index; i--) { @@ -391,6 +393,10 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) for (int index = 0; index < sl->ref_count[list]; index++) { if ( !sl->ref_list[list][index].parent || (!FIELD_PICTURE(h) && (sl->ref_list[list][index].reference&3) != 3)) { + if (h->avctx->err_recognition & AV_EF_EXPLODE) { + av_log(h->avctx, AV_LOG_ERROR, "Missing reference picture\n"); + return AVERROR_INVALIDDATA; + } av_log(h->avctx, AV_LOG_ERROR, "Missing reference picture, default is %d\n", h->default_ref[list].poc); for (int i = 0; i < FF_ARRAY_ELEMS(h->last_pocs); i++) @@ -407,7 +413,7 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) if (h->default_ref[list2].parent && !h->default_ref[list2].parent->gray && !(!FIELD_PICTURE(h) && (h->default_ref[list2].reference&3) != 3)) { sl->ref_list[list][index] = h->default_ref[list2]; - av_log(h, AV_LOG_DEBUG, "replacement of gray gap frame\n"); + av_log(h->avctx, AV_LOG_DEBUG, "replacement of gray gap frame\n"); break; } } diff --git a/libavcodec/h264_sei.h b/libavcodec/h264_sei.h index bb9275e56..8c8f6e6c7 100644 --- a/libavcodec/h264_sei.h +++ b/libavcodec/h264_sei.h @@ -129,12 +129,6 @@ struct H264ParamSets; int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, const struct H264ParamSets *ps, void *logctx); -static inline int ff_h264_sei_ctx_replace(H264SEIContext *dst, - const H264SEIContext *src) -{ - return ff_h2645_sei_ctx_replace(&dst->common, &src->common); -} - /** * Reset SEI values at the beginning of the frame. */ diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index bbccd1fc4..dbf7f6023 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -45,7 +45,7 @@ #include "mathops.h" #include "mpegutils.h" #include "rectangle.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadframe.h" @@ -166,19 +166,19 @@ static int init_table_pools(H264Context *h) const int b4_stride = h->mb_width * 4 + 1; const int b4_array_size = b4_stride * h->mb_height * 4; - h->qscale_table_pool = ff_refstruct_pool_alloc(big_mb_num + h->mb_stride, 0); - h->mb_type_pool = ff_refstruct_pool_alloc((big_mb_num + h->mb_stride) * + h->qscale_table_pool = av_refstruct_pool_alloc(big_mb_num + h->mb_stride, 0); + h->mb_type_pool = av_refstruct_pool_alloc((big_mb_num + h->mb_stride) * sizeof(uint32_t), 0); - h->motion_val_pool = ff_refstruct_pool_alloc(2 * (b4_array_size + 4) * + h->motion_val_pool = av_refstruct_pool_alloc(2 * (b4_array_size + 4) * sizeof(int16_t), 0); - h->ref_index_pool = ff_refstruct_pool_alloc(4 * mb_array_size, 0); + h->ref_index_pool = av_refstruct_pool_alloc(4 * mb_array_size, 0); if (!h->qscale_table_pool || !h->mb_type_pool || !h->motion_val_pool || !h->ref_index_pool) { - ff_refstruct_pool_uninit(&h->qscale_table_pool); - ff_refstruct_pool_uninit(&h->mb_type_pool); - ff_refstruct_pool_uninit(&h->motion_val_pool); - ff_refstruct_pool_uninit(&h->ref_index_pool); + av_refstruct_pool_uninit(&h->qscale_table_pool); + av_refstruct_pool_uninit(&h->mb_type_pool); + av_refstruct_pool_uninit(&h->motion_val_pool); + av_refstruct_pool_uninit(&h->ref_index_pool); return AVERROR(ENOMEM); } @@ -218,7 +218,7 @@ static int alloc_picture(H264Context *h, H264Picture *pic) goto fail; if (h->decode_error_flags_pool) { - pic->decode_error_flags = ff_refstruct_pool_get(h->decode_error_flags_pool); + pic->decode_error_flags = av_refstruct_pool_get(h->decode_error_flags_pool); if (!pic->decode_error_flags) goto fail; atomic_init(pic->decode_error_flags, 0); @@ -243,8 +243,8 @@ static int alloc_picture(H264Context *h, H264Picture *pic) goto fail; } - pic->qscale_table_base = ff_refstruct_pool_get(h->qscale_table_pool); - pic->mb_type_base = ff_refstruct_pool_get(h->mb_type_pool); + pic->qscale_table_base = av_refstruct_pool_get(h->qscale_table_pool); + pic->mb_type_base = av_refstruct_pool_get(h->mb_type_pool); if (!pic->qscale_table_base || !pic->mb_type_base) goto fail; @@ -252,15 +252,15 @@ static int alloc_picture(H264Context *h, H264Picture *pic) pic->qscale_table = pic->qscale_table_base + 2 * h->mb_stride + 1; for (i = 0; i < 2; i++) { - pic->motion_val_base[i] = ff_refstruct_pool_get(h->motion_val_pool); - pic->ref_index[i] = ff_refstruct_pool_get(h->ref_index_pool); + pic->motion_val_base[i] = av_refstruct_pool_get(h->motion_val_pool); + pic->ref_index[i] = av_refstruct_pool_get(h->ref_index_pool); if (!pic->motion_val_base[i] || !pic->ref_index[i]) goto fail; pic->motion_val[i] = pic->motion_val_base[i] + 4; } - pic->pps = ff_refstruct_ref_c(h->ps.pps); + pic->pps = av_refstruct_ref_c(h->ps.pps); pic->mb_width = h->mb_width; pic->mb_height = h->mb_height; @@ -365,11 +365,11 @@ int ff_h264_update_thread_context(AVCodecContext *dst, // SPS/PPS for (int i = 0; i < FF_ARRAY_ELEMS(h->ps.sps_list); i++) - ff_refstruct_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]); + av_refstruct_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) - ff_refstruct_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]); + av_refstruct_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]); - ff_refstruct_replace(&h->ps.pps, h1->ps.pps); + av_refstruct_replace(&h->ps.pps, h1->ps.pps); h->ps.sps = h1->ps.sps; if (need_reinit || !inited) { @@ -444,13 +444,11 @@ int ff_h264_update_thread_context(AVCodecContext *dst, h->frame_recovered = h1->frame_recovered; - ret = ff_h264_sei_ctx_replace(&h->sei, &h1->sei); + ret = ff_h2645_sei_ctx_replace(&h->sei.common, &h1->sei.common); if (ret < 0) return ret; h->sei.common.unregistered.x264_build = h1->sei.common.unregistered.x264_build; - h->sei.common.mastering_display = h1->sei.common.mastering_display; - h->sei.common.content_light = h1->sei.common.content_light; if (!h->cur_pic_ptr) return 0; @@ -816,6 +814,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) #endif #if CONFIG_H264_VULKAN_HWACCEL *fmt++ = AV_PIX_FMT_VULKAN; +#endif +#if CONFIG_H264_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; #endif if (CHROMA444(h)) { if (h->avctx->colorspace == AVCOL_SPC_RGB) { @@ -1059,7 +1060,7 @@ static int h264_init_ps(H264Context *h, const H264SliceContext *sl, int first_sl int needs_reinit = 0, must_reinit, ret; if (first_slice) - ff_refstruct_replace(&h->ps.pps, h->ps.pps_list[sl->pps_id]); + av_refstruct_replace(&h->ps.pps, h->ps.pps_list[sl->pps_id]); if (h->ps.sps != h->ps.pps->sps) { h->ps.sps = h->ps.pps->sps; @@ -1149,7 +1150,7 @@ static int h264_init_ps(H264Context *h, const H264SliceContext *sl, int first_sl if (flush_changes) ff_h264_flush_change(h); - if ((ret = get_pixel_format(h, 1)) < 0) + if ((ret = get_pixel_format(h, must_reinit || needs_reinit)) < 0) return ret; h->avctx->pix_fmt = ret; @@ -2111,7 +2112,7 @@ int ff_h264_queue_decode_slice(H264Context *h, const H2645NAL *nal) if (ret < 0) return ret; } else if (h->cur_pic_ptr && !FIELD_PICTURE(h) && !h->first_field && h->nal_unit_type == H264_NAL_IDR_SLICE) { - av_log(h, AV_LOG_WARNING, "Broken frame packetizing\n"); + av_log(h->avctx, AV_LOG_WARNING, "Broken frame packetizing\n"); ret = ff_h264_field_end(h, h->slice_ctx, 1); ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 0); ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 1); @@ -2643,10 +2644,10 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg) goto finish; } if (sl->cabac.bytestream > sl->cabac.bytestream_end + 2 ) - av_log(h->avctx, AV_LOG_DEBUG, "bytestream overread %"PTRDIFF_SPECIFIER"\n", sl->cabac.bytestream_end - sl->cabac.bytestream); + av_log(h->avctx, AV_LOG_DEBUG, "bytestream overread %td\n", sl->cabac.bytestream_end - sl->cabac.bytestream); if (ret < 0 || sl->cabac.bytestream > sl->cabac.bytestream_end + 4) { av_log(h->avctx, AV_LOG_ERROR, - "error while decoding MB %d %d, bytestream %"PTRDIFF_SPECIFIER"\n", + "error while decoding MB %d %d, bytestream %td\n", sl->mb_x, sl->mb_y, sl->cabac.bytestream_end - sl->cabac.bytestream); er_add_slice(sl, sl->resync_mb_x, sl->resync_mb_y, sl->mb_x, diff --git a/libavcodec/h264chroma.c b/libavcodec/h264chroma.c index 1eeab7bc4..0d152de59 100644 --- a/libavcodec/h264chroma.c +++ b/libavcodec/h264chroma.c @@ -32,11 +32,9 @@ c->put_h264_chroma_pixels_tab[0] = put_h264_chroma_mc8_ ## depth ## _c; \ c->put_h264_chroma_pixels_tab[1] = put_h264_chroma_mc4_ ## depth ## _c; \ c->put_h264_chroma_pixels_tab[2] = put_h264_chroma_mc2_ ## depth ## _c; \ - c->put_h264_chroma_pixels_tab[3] = put_h264_chroma_mc1_ ## depth ## _c; \ c->avg_h264_chroma_pixels_tab[0] = avg_h264_chroma_mc8_ ## depth ## _c; \ c->avg_h264_chroma_pixels_tab[1] = avg_h264_chroma_mc4_ ## depth ## _c; \ c->avg_h264_chroma_pixels_tab[2] = avg_h264_chroma_mc2_ ## depth ## _c; \ - c->avg_h264_chroma_pixels_tab[3] = avg_h264_chroma_mc1_ ## depth ## _c; \ av_cold void ff_h264chroma_init(H264ChromaContext *c, int bit_depth) { @@ -52,7 +50,7 @@ av_cold void ff_h264chroma_init(H264ChromaContext *c, int bit_depth) ff_h264chroma_init_arm(c, bit_depth); #elif ARCH_PPC ff_h264chroma_init_ppc(c, bit_depth); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_h264chroma_init_x86(c, bit_depth); #elif ARCH_MIPS ff_h264chroma_init_mips(c, bit_depth); diff --git a/libavcodec/h264chroma_template.c b/libavcodec/h264chroma_template.c index b9d24f5a0..b58be192c 100644 --- a/libavcodec/h264chroma_template.c +++ b/libavcodec/h264chroma_template.c @@ -26,40 +26,6 @@ #include "bit_depth_template.c" #define H264_CHROMA_MC(OPNAME, OP)\ -static void FUNCC(OPNAME ## h264_chroma_mc1)(uint8_t *_dst /*align 8*/, const uint8_t *_src /*align 1*/, ptrdiff_t stride, int h, int x, int y){\ - pixel *dst = (pixel*)_dst;\ - const pixel *src = (const pixel*)_src;\ - const int A=(8-x)*(8-y);\ - const int B=( x)*(8-y);\ - const int C=(8-x)*( y);\ - const int D=( x)*( y);\ - int i;\ - stride >>= sizeof(pixel)-1;\ - \ - av_assert2(x<8 && y<8 && x>=0 && y>=0);\ -\ - if(D){\ - for(i=0; imb2b_xy); av_freep(&h->mb2br_xy); - ff_refstruct_pool_uninit(&h->qscale_table_pool); - ff_refstruct_pool_uninit(&h->mb_type_pool); - ff_refstruct_pool_uninit(&h->motion_val_pool); - ff_refstruct_pool_uninit(&h->ref_index_pool); + av_refstruct_pool_uninit(&h->qscale_table_pool); + av_refstruct_pool_uninit(&h->mb_type_pool); + av_refstruct_pool_uninit(&h->motion_val_pool); + av_refstruct_pool_uninit(&h->ref_index_pool); #if CONFIG_ERROR_RESILIENCE av_freep(&h->er.mb_index2xy); @@ -219,8 +220,6 @@ int ff_h264_alloc_tables(H264Context *h) } if (CONFIG_ERROR_RESILIENCE) { - const int er_size = h->mb_height * h->mb_stride * (4*sizeof(int) + 1); - int mb_array_size = h->mb_height * h->mb_stride; int y_size = (2 * h->mb_width + 1) * (2 * h->mb_height + 1); int yc_size = y_size + 2 * big_mb_num; @@ -238,8 +237,6 @@ int ff_h264_alloc_tables(H264Context *h) // error resilience code looks cleaner with this if (!FF_ALLOCZ_TYPED_ARRAY(er->mb_index2xy, h->mb_num + 1) || - !FF_ALLOCZ_TYPED_ARRAY(er->error_status_table, mb_array_size) || - !FF_ALLOCZ_TYPED_ARRAY(er->er_temp_buffer, er_size) || !FF_ALLOCZ_TYPED_ARRAY(h->dc_val_base, yc_size)) return AVERROR(ENOMEM); // ff_h264_free_tables will clean up for us @@ -254,6 +251,8 @@ int ff_h264_alloc_tables(H264Context *h) er->dc_val[2] = er->dc_val[1] + big_mb_num; for (int i = 0; i < yc_size; i++) h->dc_val_base[i] = 1024; + + return ff_er_init(er); } return 0; @@ -313,7 +312,7 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h) ff_h264_sei_uninit(&h->sei); if (avctx->active_thread_type & FF_THREAD_FRAME) { - h->decode_error_flags_pool = ff_refstruct_pool_alloc(sizeof(atomic_int), 0); + h->decode_error_flags_pool = av_refstruct_pool_alloc(sizeof(atomic_int), 0); if (!h->decode_error_flags_pool) return AVERROR(ENOMEM); } @@ -364,7 +363,7 @@ static av_cold int h264_decode_end(AVCodecContext *avctx) h->cur_pic_ptr = NULL; - ff_refstruct_pool_uninit(&h->decode_error_flags_pool); + av_refstruct_pool_uninit(&h->decode_error_flags_pool); av_freep(&h->slice_ctx); h->nb_slice_ctx = 0; @@ -397,12 +396,6 @@ static av_cold int h264_decode_init(AVCodecContext *avctx) return AVERROR_UNKNOWN; } -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - avctx->ticks_per_frame = 2; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (!avctx->internal->is_copy) { if (avctx->extradata_size > 0 && avctx->extradata) { ret = ff_h264_decode_extradata(avctx->extradata, avctx->extradata_size, @@ -480,7 +473,7 @@ void ff_h264_flush_change(H264Context *h) h->mmco_reset = 1; } -static void h264_decode_flush(AVCodecContext *avctx) +static av_cold void h264_decode_flush(AVCodecContext *avctx) { H264Context *h = avctx->priv_data; int i; @@ -587,7 +580,8 @@ static void debug_green_metadata(const H264SEIGreenMetaData *gm, void *logctx) } } -static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) +static int decode_nal_units(H264Context *h, AVBufferRef *buf_ref, + const uint8_t *buf, int buf_size) { AVCodecContext *const avctx = h->avctx; int nals_needed = 0; ///< number of NALs that need decoding before the next frame thread starts @@ -668,7 +662,8 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) } if (h->avctx->hwaccel && - (ret = FF_HW_CALL(h->avctx, start_frame, buf, buf_size)) < 0) + (ret = FF_HW_CALL(h->avctx, start_frame, buf_ref, + buf, buf_size)) < 0) goto end; } @@ -742,8 +737,10 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) nal->type, nal->size_bits); } - if (err < 0) { + if (err < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) { av_log(h->avctx, AV_LOG_ERROR, "decode_slice_header error\n"); + ret = err; + goto end; } } @@ -756,7 +753,7 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) if (h->cur_pic_ptr->decode_error_flags) { /* Frame-threading in use */ atomic_int *decode_error = h->cur_pic_ptr->decode_error_flags; - /* Using atomics here is not supposed to provide syncronisation; + /* Using atomics here is not supposed to provide synchronisation; * they are merely used to allow to set decode_error from both * decoding threads in case of coded slices. */ atomic_fetch_or_explicit(decode_error, FF_DECODE_ERROR_DECODE_SLICES, @@ -825,19 +822,6 @@ end: return (ret < 0) ? ret : buf_size; } -/** - * Return the number of bytes consumed for building the current frame. - */ -static int get_consumed_bytes(int pos, int buf_size) -{ - if (pos == 0) - pos = 1; // avoid infinite loops (I doubt that is needed but...) - if (pos + 10 > buf_size) - pos = buf_size; // oops ;) - - return pos; -} - static int h264_export_enc_params(AVFrame *f, const H264Picture *p) { AVVideoEncParams *par; @@ -1064,7 +1048,7 @@ static int h264_decode_frame(AVCodecContext *avctx, AVFrame *pict, avctx->err_recognition, avctx); } - buf_index = decode_nal_units(h, buf, buf_size); + buf_index = decode_nal_units(h, avpkt->buf, buf, buf_size); if (buf_index < 0) return AVERROR_INVALIDDATA; @@ -1098,7 +1082,7 @@ static int h264_decode_frame(AVCodecContext *avctx, AVFrame *pict, ff_h264_unref_picture(&h->last_pic_for_ec); - return get_consumed_bytes(buf_index, buf_size); + return buf_size; } #define OFFSET(x) offsetof(H264Context, x) diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index ccd7583bf..74fd09dfa 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -28,7 +28,6 @@ #ifndef AVCODEC_H264DEC_H #define AVCODEC_H264DEC_H -#include "libavutil/buffer.h" #include "libavutil/mem_internal.h" #include "cabac.h" @@ -41,7 +40,6 @@ #include "h264dsp.h" #include "h264pred.h" #include "h264qpel.h" -#include "h274.h" #include "mpegutils.h" #include "threadframe.h" #include "videodsp.h" @@ -305,11 +303,11 @@ typedef struct H264SliceContext { DECLARE_ALIGNED(8, uint16_t, sub_mb_type)[4]; - ///< as a DCT coefficient is int32_t in high depth, we need to reserve twice the space. + /// as a DCT coefficient is int32_t in high depth, we need to reserve twice the space. DECLARE_ALIGNED(16, int16_t, mb)[16 * 48 * 2]; DECLARE_ALIGNED(16, int16_t, mb_luma_dc)[3][16 * 2]; - ///< as mb is addressed by scantable[i] and scantable is uint8_t we can either - ///< check that i is not too large or ensure that there is some unused stuff after mb + /// as mb is addressed by scantable[i] and scantable is uint8_t we can either + /// check that i is not too large or ensure that there is some unused stuff after mb int16_t mb_padding[256 * 2]; uint8_t (*mvd_table[2])[2]; @@ -344,7 +342,6 @@ typedef struct H264Context { H264DSPContext h264dsp; H264ChromaContext h264chroma; H264QpelContext h264qpel; - H274FilmGrainDatabase h274db; H264Picture DPB[H264_MAX_PICTURE_COUNT]; H264Picture *cur_pic_ptr; @@ -541,7 +538,7 @@ typedef struct H264Context { * all subsequently output fraames are also marked as recovered * * In effect, if you want all subsequent DECODED frames marked as recovered, set frame_recovered - * If you want all subsequent DISPAYED frames marked as recovered, set the frame->recovered + * If you want all subsequent DISPLAYED frames marked as recovered, set the frame->recovered */ int frame_recovered; @@ -570,11 +567,11 @@ typedef struct H264Context { H264SEIContext sei; - struct FFRefStructPool *qscale_table_pool; - struct FFRefStructPool *mb_type_pool; - struct FFRefStructPool *motion_val_pool; - struct FFRefStructPool *ref_index_pool; - struct FFRefStructPool *decode_error_flags_pool; + struct AVRefStructPool *qscale_table_pool; + struct AVRefStructPool *mb_type_pool; + struct AVRefStructPool *motion_val_pool; + struct AVRefStructPool *ref_index_pool; + struct AVRefStructPool *decode_error_flags_pool; int ref2frm[MAX_SLICES][2][64]; ///< reference to frame number lists, used in the loop filter, the first 2 are for -2,-1 int non_gray; ///< Did we encounter a intra frame after a gray gap frame diff --git a/libavcodec/h264dsp.c b/libavcodec/h264dsp.c index 1ba936be1..f61235359 100644 --- a/libavcodec/h264dsp.c +++ b/libavcodec/h264dsp.c @@ -69,68 +69,68 @@ av_cold void ff_h264dsp_init(H264DSPContext *c, const int bit_depth, #undef FUNC #define FUNC(a, depth) a ## _ ## depth ## _c -#define ADDPX_DSP(depth) \ - c->h264_add_pixels4_clear = FUNC(ff_h264_add_pixels4, depth);\ - c->h264_add_pixels8_clear = FUNC(ff_h264_add_pixels8, depth) +#define SET_PIXSIZE_FUNCS(depth) \ + c->luma_dc_dequant_idct = FUNC(ff_h264_luma_dc_dequant_idct, depth);\ + if (chroma_format_idc <= 1)\ + c->chroma_dc_dequant_idct = FUNC(ff_h264_chroma_dc_dequant_idct, depth);\ + else\ + c->chroma_dc_dequant_idct = FUNC(ff_h264_chroma422_dc_dequant_idct, depth);\ + c->add_pixels4_clear = FUNC(ff_h264_add_pixels4, depth);\ + c->add_pixels8_clear = FUNC(ff_h264_add_pixels8, depth) if (bit_depth > 8 && bit_depth <= 16) { - ADDPX_DSP(16); + SET_PIXSIZE_FUNCS(16); } else { - ADDPX_DSP(8); + SET_PIXSIZE_FUNCS(8); } #define H264_DSP(depth) \ - c->h264_idct_add= FUNC(ff_h264_idct_add, depth);\ - c->h264_idct8_add= FUNC(ff_h264_idct8_add, depth);\ - c->h264_idct_dc_add= FUNC(ff_h264_idct_dc_add, depth);\ - c->h264_idct8_dc_add= FUNC(ff_h264_idct8_dc_add, depth);\ - c->h264_idct_add16 = FUNC(ff_h264_idct_add16, depth);\ - c->h264_idct8_add4 = FUNC(ff_h264_idct8_add4, depth);\ + c->idct_add = FUNC(ff_h264_idct_add, depth);\ + c->idct8_add = FUNC(ff_h264_idct8_add, depth);\ + c->idct_dc_add = FUNC(ff_h264_idct_dc_add, depth);\ + c->idct8_dc_add = FUNC(ff_h264_idct8_dc_add, depth);\ + c->idct_add16 = FUNC(ff_h264_idct_add16, depth);\ + c->idct8_add4 = FUNC(ff_h264_idct8_add4, depth);\ if (chroma_format_idc <= 1)\ - c->h264_idct_add8 = FUNC(ff_h264_idct_add8, depth);\ + c->idct_add8 = FUNC(ff_h264_idct_add8, depth);\ else\ - c->h264_idct_add8 = FUNC(ff_h264_idct_add8_422, depth);\ - c->h264_idct_add16intra= FUNC(ff_h264_idct_add16intra, depth);\ - c->h264_luma_dc_dequant_idct= FUNC(ff_h264_luma_dc_dequant_idct, depth);\ - if (chroma_format_idc <= 1)\ - c->h264_chroma_dc_dequant_idct= FUNC(ff_h264_chroma_dc_dequant_idct, depth);\ - else\ - c->h264_chroma_dc_dequant_idct= FUNC(ff_h264_chroma422_dc_dequant_idct, depth);\ + c->idct_add8 = FUNC(ff_h264_idct_add8_422, depth);\ + c->idct_add16intra = FUNC(ff_h264_idct_add16intra, depth);\ \ - c->weight_h264_pixels_tab[0]= FUNC(weight_h264_pixels16, depth);\ - c->weight_h264_pixels_tab[1]= FUNC(weight_h264_pixels8, depth);\ - c->weight_h264_pixels_tab[2]= FUNC(weight_h264_pixels4, depth);\ - c->weight_h264_pixels_tab[3]= FUNC(weight_h264_pixels2, depth);\ - c->biweight_h264_pixels_tab[0]= FUNC(biweight_h264_pixels16, depth);\ - c->biweight_h264_pixels_tab[1]= FUNC(biweight_h264_pixels8, depth);\ - c->biweight_h264_pixels_tab[2]= FUNC(biweight_h264_pixels4, depth);\ - c->biweight_h264_pixels_tab[3]= FUNC(biweight_h264_pixels2, depth);\ + c->weight_pixels_tab[0] = FUNC(weight_h264_pixels16, depth);\ + c->weight_pixels_tab[1] = FUNC(weight_h264_pixels8, depth);\ + c->weight_pixels_tab[2] = FUNC(weight_h264_pixels4, depth);\ + c->weight_pixels_tab[3] = FUNC(weight_h264_pixels2, depth);\ + c->biweight_pixels_tab[0] = FUNC(biweight_h264_pixels16, depth);\ + c->biweight_pixels_tab[1] = FUNC(biweight_h264_pixels8, depth);\ + c->biweight_pixels_tab[2] = FUNC(biweight_h264_pixels4, depth);\ + c->biweight_pixels_tab[3] = FUNC(biweight_h264_pixels2, depth);\ \ - c->h264_v_loop_filter_luma= FUNC(h264_v_loop_filter_luma, depth);\ - c->h264_h_loop_filter_luma= FUNC(h264_h_loop_filter_luma, depth);\ - c->h264_h_loop_filter_luma_mbaff= FUNC(h264_h_loop_filter_luma_mbaff, depth);\ - c->h264_v_loop_filter_luma_intra= FUNC(h264_v_loop_filter_luma_intra, depth);\ - c->h264_h_loop_filter_luma_intra= FUNC(h264_h_loop_filter_luma_intra, depth);\ - c->h264_h_loop_filter_luma_mbaff_intra= FUNC(h264_h_loop_filter_luma_mbaff_intra, depth);\ - c->h264_v_loop_filter_chroma= FUNC(h264_v_loop_filter_chroma, depth);\ + c->v_loop_filter_luma = FUNC(h264_v_loop_filter_luma, depth);\ + c->h_loop_filter_luma = FUNC(h264_h_loop_filter_luma, depth);\ + c->h_loop_filter_luma_mbaff = FUNC(h264_h_loop_filter_luma_mbaff, depth);\ + c->v_loop_filter_luma_intra = FUNC(h264_v_loop_filter_luma_intra, depth);\ + c->h_loop_filter_luma_intra = FUNC(h264_h_loop_filter_luma_intra, depth);\ + c->h_loop_filter_luma_mbaff_intra = FUNC(h264_h_loop_filter_luma_mbaff_intra, depth);\ + c->v_loop_filter_chroma = FUNC(h264_v_loop_filter_chroma, depth);\ if (chroma_format_idc <= 1)\ - c->h264_h_loop_filter_chroma= FUNC(h264_h_loop_filter_chroma, depth);\ + c->h_loop_filter_chroma = FUNC(h264_h_loop_filter_chroma, depth);\ else\ - c->h264_h_loop_filter_chroma= FUNC(h264_h_loop_filter_chroma422, depth);\ + c->h_loop_filter_chroma = FUNC(h264_h_loop_filter_chroma422, depth);\ if (chroma_format_idc <= 1)\ - c->h264_h_loop_filter_chroma_mbaff= FUNC(h264_h_loop_filter_chroma_mbaff, depth);\ + c->h_loop_filter_chroma_mbaff = FUNC(h264_h_loop_filter_chroma_mbaff, depth);\ else\ - c->h264_h_loop_filter_chroma_mbaff= FUNC(h264_h_loop_filter_chroma422_mbaff, depth);\ - c->h264_v_loop_filter_chroma_intra= FUNC(h264_v_loop_filter_chroma_intra, depth);\ + c->h_loop_filter_chroma_mbaff = FUNC(h264_h_loop_filter_chroma422_mbaff, depth);\ + c->v_loop_filter_chroma_intra= FUNC(h264_v_loop_filter_chroma_intra, depth);\ if (chroma_format_idc <= 1)\ - c->h264_h_loop_filter_chroma_intra= FUNC(h264_h_loop_filter_chroma_intra, depth);\ + c->h_loop_filter_chroma_intra = FUNC(h264_h_loop_filter_chroma_intra, depth);\ else\ - c->h264_h_loop_filter_chroma_intra= FUNC(h264_h_loop_filter_chroma422_intra, depth);\ + c->h_loop_filter_chroma_intra = FUNC(h264_h_loop_filter_chroma422_intra, depth);\ if (chroma_format_idc <= 1)\ - c->h264_h_loop_filter_chroma_mbaff_intra= FUNC(h264_h_loop_filter_chroma_mbaff_intra, depth);\ + c->h_loop_filter_chroma_mbaff_intra = FUNC(h264_h_loop_filter_chroma_mbaff_intra, depth);\ else\ - c->h264_h_loop_filter_chroma_mbaff_intra= FUNC(h264_h_loop_filter_chroma422_mbaff_intra, depth);\ - c->h264_loop_filter_strength= NULL; + c->h_loop_filter_chroma_mbaff_intra = FUNC(h264_h_loop_filter_chroma422_mbaff_intra, depth);\ + c->loop_filter_strength = NULL; switch (bit_depth) { case 9: @@ -160,7 +160,7 @@ av_cold void ff_h264dsp_init(H264DSPContext *c, const int bit_depth, ff_h264dsp_init_ppc(c, bit_depth, chroma_format_idc); #elif ARCH_RISCV ff_h264dsp_init_riscv(c, bit_depth, chroma_format_idc); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_h264dsp_init_x86(c, bit_depth, chroma_format_idc); #elif ARCH_MIPS ff_h264dsp_init_mips(c, bit_depth, chroma_format_idc); diff --git a/libavcodec/h264dsp.h b/libavcodec/h264dsp.h index 4a9cb1568..f40d324a4 100644 --- a/libavcodec/h264dsp.h +++ b/libavcodec/h264dsp.h @@ -41,71 +41,71 @@ typedef void (*h264_biweight_func)(uint8_t *dst, uint8_t *src, */ typedef struct H264DSPContext { /* weighted MC */ - h264_weight_func weight_h264_pixels_tab[4]; - h264_biweight_func biweight_h264_pixels_tab[4]; + h264_weight_func weight_pixels_tab[4]; + h264_biweight_func biweight_pixels_tab[4]; /* loop filter */ - void (*h264_v_loop_filter_luma)(uint8_t *pix /*align 16*/, ptrdiff_t stride, - int alpha, int beta, int8_t *tc0); - void (*h264_h_loop_filter_luma)(uint8_t *pix /*align 4 */, ptrdiff_t stride, - int alpha, int beta, int8_t *tc0); - void (*h264_h_loop_filter_luma_mbaff)(uint8_t *pix /*align 16*/, ptrdiff_t stride, - int alpha, int beta, int8_t *tc0); + void (*v_loop_filter_luma)(uint8_t *pix /*align 16*/, ptrdiff_t stride, + int alpha, int beta, int8_t *tc0); + void (*h_loop_filter_luma)(uint8_t *pix /*align 4 */, ptrdiff_t stride, + int alpha, int beta, int8_t *tc0); + void (*h_loop_filter_luma_mbaff)(uint8_t *pix /*align 16*/, ptrdiff_t stride, + int alpha, int beta, int8_t *tc0); /* v/h_loop_filter_luma_intra: align 16 */ - void (*h264_v_loop_filter_luma_intra)(uint8_t *pix, ptrdiff_t stride, - int alpha, int beta); - void (*h264_h_loop_filter_luma_intra)(uint8_t *pix, ptrdiff_t stride, - int alpha, int beta); - void (*h264_h_loop_filter_luma_mbaff_intra)(uint8_t *pix /*align 16*/, - ptrdiff_t stride, int alpha, int beta); - void (*h264_v_loop_filter_chroma)(uint8_t *pix /*align 8*/, ptrdiff_t stride, - int alpha, int beta, int8_t *tc0); - void (*h264_h_loop_filter_chroma)(uint8_t *pix /*align 4*/, ptrdiff_t stride, - int alpha, int beta, int8_t *tc0); - void (*h264_h_loop_filter_chroma_mbaff)(uint8_t *pix /*align 8*/, - ptrdiff_t stride, int alpha, int beta, - int8_t *tc0); - void (*h264_v_loop_filter_chroma_intra)(uint8_t *pix /*align 8*/, - ptrdiff_t stride, int alpha, int beta); - void (*h264_h_loop_filter_chroma_intra)(uint8_t *pix /*align 8*/, - ptrdiff_t stride, int alpha, int beta); - void (*h264_h_loop_filter_chroma_mbaff_intra)(uint8_t *pix /*align 8*/, - ptrdiff_t stride, int alpha, int beta); - // h264_loop_filter_strength: simd only. the C version is inlined in h264_loopfilter.c - void (*h264_loop_filter_strength)(int16_t bS[2][4][4], uint8_t nnz[40], - int8_t ref[2][40], int16_t mv[2][40][2], - int bidir, int edges, int step, - int mask_mv0, int mask_mv1, int field); + void (*v_loop_filter_luma_intra)(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); + void (*h_loop_filter_luma_intra)(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); + void (*h_loop_filter_luma_mbaff_intra)(uint8_t *pix /*align 16*/, + ptrdiff_t stride, int alpha, int beta); + void (*v_loop_filter_chroma)(uint8_t *pix /*align 8*/, ptrdiff_t stride, + int alpha, int beta, int8_t *tc0); + void (*h_loop_filter_chroma)(uint8_t *pix /*align 4*/, ptrdiff_t stride, + int alpha, int beta, int8_t *tc0); + void (*h_loop_filter_chroma_mbaff)(uint8_t *pix /*align 8*/, + ptrdiff_t stride, int alpha, int beta, + int8_t *tc0); + void (*v_loop_filter_chroma_intra)(uint8_t *pix /*align 8*/, + ptrdiff_t stride, int alpha, int beta); + void (*h_loop_filter_chroma_intra)(uint8_t *pix /*align 8*/, + ptrdiff_t stride, int alpha, int beta); + void (*h_loop_filter_chroma_mbaff_intra)(uint8_t *pix /*align 8*/, + ptrdiff_t stride, int alpha, int beta); + // loop_filter_strength: simd only. the C version is inlined in h264_loopfilter.c + void (*loop_filter_strength)(int16_t bS[2][4][4], uint8_t nnz[40], + int8_t ref[2][40], int16_t mv[2][40][2], + int bidir, int edges, int step, + int mask_mv0, int mask_mv1, int field); /* IDCT */ - void (*h264_idct_add)(uint8_t *dst /*align 4*/, - int16_t *block /*align 16*/, int stride); - void (*h264_idct8_add)(uint8_t *dst /*align 8*/, - int16_t *block /*align 16*/, int stride); - void (*h264_idct_dc_add)(uint8_t *dst /*align 4*/, - int16_t *block /*align 16*/, int stride); - void (*h264_idct8_dc_add)(uint8_t *dst /*align 8*/, - int16_t *block /*align 16*/, int stride); + void (*idct_add)(uint8_t *dst /*align 4*/, + int16_t *block /*align 16*/, int stride); + void (*idct8_add)(uint8_t *dst /*align 8*/, + int16_t *block /*align 16*/, int stride); + void (*idct_dc_add)(uint8_t *dst /*align 4*/, + int16_t *block /*align 16*/, int stride); + void (*idct8_dc_add)(uint8_t *dst /*align 8*/, + int16_t *block /*align 16*/, int stride); - void (*h264_idct_add16)(uint8_t *dst /*align 16*/, const int *blockoffset, - int16_t *block /*align 16*/, int stride, - const uint8_t nnzc[5 * 8]); - void (*h264_idct8_add4)(uint8_t *dst /*align 16*/, const int *blockoffset, - int16_t *block /*align 16*/, int stride, - const uint8_t nnzc[5 * 8]); - void (*h264_idct_add8)(uint8_t **dst /*align 16*/, const int *blockoffset, - int16_t *block /*align 16*/, int stride, - const uint8_t nnzc[15 * 8]); - void (*h264_idct_add16intra)(uint8_t *dst /*align 16*/, const int *blockoffset, - int16_t *block /*align 16*/, - int stride, const uint8_t nnzc[5 * 8]); - void (*h264_luma_dc_dequant_idct)(int16_t *output, - int16_t *input /*align 16*/, int qmul); - void (*h264_chroma_dc_dequant_idct)(int16_t *block, int qmul); + void (*idct_add16)(uint8_t *dst /*align 16*/, const int *blockoffset, + int16_t *block /*align 16*/, int stride, + const uint8_t nnzc[5 * 8]); + void (*idct8_add4)(uint8_t *dst /*align 16*/, const int *blockoffset, + int16_t *block /*align 16*/, int stride, + const uint8_t nnzc[5 * 8]); + void (*idct_add8)(uint8_t **dst /*align 16*/, const int *blockoffset, + int16_t *block /*align 16*/, int stride, + const uint8_t nnzc[15 * 8]); + void (*idct_add16intra)(uint8_t *dst /*align 16*/, const int *blockoffset, + int16_t *block /*align 16*/, + int stride, const uint8_t nnzc[5 * 8]); + void (*luma_dc_dequant_idct)(int16_t *output, + int16_t *input /*align 16*/, int qmul); + void (*chroma_dc_dequant_idct)(int16_t *block, int qmul); /* bypass-transform */ - void (*h264_add_pixels8_clear)(uint8_t *dst, int16_t *block, int stride); - void (*h264_add_pixels4_clear)(uint8_t *dst, int16_t *block, int stride); + void (*add_pixels8_clear)(uint8_t *dst, int16_t *block, int stride); + void (*add_pixels4_clear)(uint8_t *dst, int16_t *block, int stride); /** * Search buf from the start for up to size bytes. Return the index diff --git a/libavcodec/h264idct.h b/libavcodec/h264idct.h index 6f18df9e5..42e93ed17 100644 --- a/libavcodec/h264idct.h +++ b/libavcodec/h264idct.h @@ -31,9 +31,6 @@ void ff_h264_idct_add16intra_ ## depth ## _c(uint8_t *dst, const int *blockoffse void ff_h264_idct8_add4_ ## depth ## _c(uint8_t *dst, const int *blockoffset, int16_t *block, int stride, const uint8_t nnzc[5 * 8]);\ void ff_h264_idct_add8_422_ ## depth ## _c(uint8_t **dest, const int *blockoffset, int16_t *block, int stride, const uint8_t nnzc[15 * 8]);\ void ff_h264_idct_add8_ ## depth ## _c(uint8_t **dest, const int *blockoffset, int16_t *block, int stride, const uint8_t nnzc[15 * 8]);\ -void ff_h264_luma_dc_dequant_idct_ ## depth ## _c(int16_t *output, int16_t *input, int qmul);\ -void ff_h264_chroma422_dc_dequant_idct_ ## depth ## _c(int16_t *block, int qmul);\ -void ff_h264_chroma_dc_dequant_idct_ ## depth ## _c(int16_t *block, int qmul); H264_IDCT( 8) H264_IDCT( 9) @@ -41,4 +38,12 @@ H264_IDCT(10) H264_IDCT(12) H264_IDCT(14) +#define H264_IDCT2(pixsize) \ +void ff_h264_luma_dc_dequant_idct_ ## pixsize ## _c(int16_t *output, int16_t *input, int qmul);\ +void ff_h264_chroma422_dc_dequant_idct_ ## pixsize ## _c(int16_t *block, int qmul);\ +void ff_h264_chroma_dc_dequant_idct_ ## pixsize ## _c(int16_t *block, int qmul); + +H264_IDCT2( 8) +H264_IDCT2(16) + #endif /* AVCODEC_H264IDCT_H */ diff --git a/libavcodec/h264idct_template.c b/libavcodec/h264idct_template.c index db19b5f9f..64f5faddc 100644 --- a/libavcodec/h264idct_template.c +++ b/libavcodec/h264idct_template.c @@ -244,11 +244,13 @@ void FUNCC(ff_h264_idct_add8_422)(uint8_t **dest, const int *block_offset, int16 } } +#if BIT_DEPTH == 8 || BIT_DEPTH == 9 /** * IDCT transforms the 16 dc values and dequantizes them. * @param qmul quantization parameter */ -void FUNCC(ff_h264_luma_dc_dequant_idct)(int16_t *_output, int16_t *_input, int qmul){ +void FUNCC2(ff_h264_luma_dc_dequant_idct)(int16_t *_output, int16_t *_input, int qmul) +{ #define stride 16 int i; int temp[16]; @@ -283,7 +285,8 @@ void FUNCC(ff_h264_luma_dc_dequant_idct)(int16_t *_output, int16_t *_input, int #undef stride } -void FUNCC(ff_h264_chroma422_dc_dequant_idct)(int16_t *_block, int qmul){ +void FUNCC2(ff_h264_chroma422_dc_dequant_idct)(int16_t *_block, int qmul) +{ const int stride= 16*2; const int xStride= 16; int i; @@ -310,7 +313,8 @@ void FUNCC(ff_h264_chroma422_dc_dequant_idct)(int16_t *_block, int qmul){ } } -void FUNCC(ff_h264_chroma_dc_dequant_idct)(int16_t *_block, int qmul){ +void FUNCC2(ff_h264_chroma_dc_dequant_idct)(int16_t *_block, int qmul) +{ const int stride= 16*2; const int xStride= 16; SUINT a,b,c,d,e; @@ -331,3 +335,4 @@ void FUNCC(ff_h264_chroma_dc_dequant_idct)(int16_t *_block, int qmul){ block[stride*1 + xStride*0]= (int)((a-c)*qmul) >> 7; block[stride*1 + xStride*1]= (int)((e-b)*qmul) >> 7; } +#endif diff --git a/libavcodec/h264pred.c b/libavcodec/h264pred.c index 25f9995a0..fbd8d2b91 100644 --- a/libavcodec/h264pred.c +++ b/libavcodec/h264pred.c @@ -592,7 +592,7 @@ av_cold void ff_h264_pred_init(H264PredContext *h, int codec_id, ff_h264_pred_init_aarch64(h, codec_id, bit_depth, chroma_format_idc); #elif ARCH_ARM ff_h264_pred_init_arm(h, codec_id, bit_depth, chroma_format_idc); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_h264_pred_init_x86(h, codec_id, bit_depth, chroma_format_idc); #elif ARCH_MIPS ff_h264_pred_init_mips(h, codec_id, bit_depth, chroma_format_idc); diff --git a/libavcodec/h264pred_template.c b/libavcodec/h264pred_template.c index b5bc942a5..face13f7c 100644 --- a/libavcodec/h264pred_template.c +++ b/libavcodec/h264pred_template.c @@ -113,28 +113,28 @@ static void FUNCC(pred4x4_128_dc)(uint8_t *_src, const uint8_t *topright, #define LOAD_TOP_RIGHT_EDGE\ - const unsigned av_unused t4 = topright[0];\ - const unsigned av_unused t5 = topright[1];\ - const unsigned av_unused t6 = topright[2];\ - const unsigned av_unused t7 = topright[3];\ + av_unused const unsigned t4 = topright[0];\ + av_unused const unsigned t5 = topright[1];\ + av_unused const unsigned t6 = topright[2];\ + av_unused const unsigned t7 = topright[3];\ #define LOAD_DOWN_LEFT_EDGE\ - const unsigned av_unused l4 = src[-1+4*stride];\ - const unsigned av_unused l5 = src[-1+5*stride];\ - const unsigned av_unused l6 = src[-1+6*stride];\ - const unsigned av_unused l7 = src[-1+7*stride];\ + av_unused const unsigned l4 = src[-1+4*stride];\ + av_unused const unsigned l5 = src[-1+5*stride];\ + av_unused const unsigned l6 = src[-1+6*stride];\ + av_unused const unsigned l7 = src[-1+7*stride];\ #define LOAD_LEFT_EDGE\ - const unsigned av_unused l0 = src[-1+0*stride];\ - const unsigned av_unused l1 = src[-1+1*stride];\ - const unsigned av_unused l2 = src[-1+2*stride];\ - const unsigned av_unused l3 = src[-1+3*stride];\ + av_unused const unsigned l0 = src[-1+0*stride];\ + av_unused const unsigned l1 = src[-1+1*stride];\ + av_unused const unsigned l2 = src[-1+2*stride];\ + av_unused const unsigned l3 = src[-1+3*stride];\ #define LOAD_TOP_EDGE\ - const unsigned av_unused t0 = src[ 0-1*stride];\ - const unsigned av_unused t1 = src[ 1-1*stride];\ - const unsigned av_unused t2 = src[ 2-1*stride];\ - const unsigned av_unused t3 = src[ 3-1*stride];\ + av_unused const unsigned t0 = src[ 0-1*stride];\ + av_unused const unsigned t1 = src[ 1-1*stride];\ + av_unused const unsigned t2 = src[ 2-1*stride];\ + av_unused const unsigned t3 = src[ 3-1*stride];\ static void FUNCC(pred4x4_down_right)(uint8_t *_src, const uint8_t *topright, ptrdiff_t _stride) @@ -414,7 +414,6 @@ static inline void FUNCC(pred16x16_plane_compat)(uint8_t *_src, { int i, j, k; int a; - INIT_CLIP pixel *src = (pixel*)_src; int stride = _stride>>(sizeof(pixel)-1); const pixel * const src0 = src +7-stride; @@ -748,7 +747,6 @@ static void FUNCC(pred8x8_plane)(uint8_t *_src, ptrdiff_t _stride) { int j, k; int a; - INIT_CLIP pixel *src = (pixel*)_src; int stride = _stride>>(sizeof(pixel)-1); const pixel * const src0 = src +3-stride; @@ -784,7 +782,6 @@ static void FUNCC(pred8x16_plane)(uint8_t *_src, ptrdiff_t _stride) { int j, k; int a; - INIT_CLIP pixel *src = (pixel*)_src; int stride = _stride>>(sizeof(pixel)-1); const pixel * const src0 = src +3-stride; @@ -829,7 +826,7 @@ static void FUNCC(pred8x16_plane)(uint8_t *_src, ptrdiff_t _stride) const int l0 = ((has_topleft ? SRC(-1,-1) : SRC(-1,0)) \ + 2*SRC(-1,0) + SRC(-1,1) + 2) >> 2; \ PL(1) PL(2) PL(3) PL(4) PL(5) PL(6) \ - const int l7 av_unused = (SRC(-1,6) + 3*SRC(-1,7) + 2) >> 2 + av_unused const int l7 = (SRC(-1,6) + 3*SRC(-1,7) + 2) >> 2 #define PT(x) \ const int t##x = (SRC(x-1,-1) + 2*SRC(x,-1) + SRC(x+1,-1) + 2) >> 2; @@ -837,7 +834,7 @@ static void FUNCC(pred8x16_plane)(uint8_t *_src, ptrdiff_t _stride) const int t0 = ((has_topleft ? SRC(-1,-1) : SRC(0,-1)) \ + 2*SRC(0,-1) + SRC(1,-1) + 2) >> 2; \ PT(1) PT(2) PT(3) PT(4) PT(5) PT(6) \ - const int t7 av_unused = ((has_topright ? SRC(8,-1) : SRC(7,-1)) \ + av_unused const int t7 = ((has_topright ? SRC(8,-1) : SRC(7,-1)) \ + 2*SRC(7,-1) + SRC(6,-1) + 2) >> 2 #define PTR(x) \ diff --git a/libavcodec/h264qpel.c b/libavcodec/h264qpel.c index 65fef0330..c64d35b73 100644 --- a/libavcodec/h264qpel.c +++ b/libavcodec/h264qpel.c @@ -20,6 +20,7 @@ */ #include "libavutil/attributes.h" +#include "libavutil/common.h" #include "h264qpel.h" #define pixeltmp int16_t @@ -73,7 +74,6 @@ av_cold void ff_h264qpel_init(H264QpelContext *c, int bit_depth) dspfunc2(put_h264_qpel, 0, 16, depth); \ dspfunc2(put_h264_qpel, 1, 8, depth); \ dspfunc2(put_h264_qpel, 2, 4, depth); \ - dspfunc2(put_h264_qpel, 3, 2, depth); \ dspfunc2(avg_h264_qpel, 0, 16, depth); \ dspfunc2(avg_h264_qpel, 1, 8, depth); \ dspfunc2(avg_h264_qpel, 2, 4, depth) @@ -102,7 +102,9 @@ av_cold void ff_h264qpel_init(H264QpelContext *c, int bit_depth) ff_h264qpel_init_arm(c, bit_depth); #elif ARCH_PPC ff_h264qpel_init_ppc(c, bit_depth); -#elif ARCH_X86 +#elif ARCH_RISCV + ff_h264qpel_init_riscv(c, bit_depth); +#elif ARCH_X86 && HAVE_X86ASM ff_h264qpel_init_x86(c, bit_depth); #elif ARCH_MIPS ff_h264qpel_init_mips(c, bit_depth); diff --git a/libavcodec/h264qpel.h b/libavcodec/h264qpel.h index 0259e8de2..f198a9483 100644 --- a/libavcodec/h264qpel.h +++ b/libavcodec/h264qpel.h @@ -25,8 +25,8 @@ #include "qpeldsp.h" typedef struct H264QpelContext { - qpel_mc_func put_h264_qpel_pixels_tab[4][16]; - qpel_mc_func avg_h264_qpel_pixels_tab[4][16]; + qpel_mc_func put_h264_qpel_pixels_tab[3][16]; + qpel_mc_func avg_h264_qpel_pixels_tab[3][16]; } H264QpelContext; void ff_h264qpel_init(H264QpelContext *c, int bit_depth); @@ -34,6 +34,7 @@ void ff_h264qpel_init(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_aarch64(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_arm(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_ppc(H264QpelContext *c, int bit_depth); +void ff_h264qpel_init_riscv(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_x86(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_mips(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_loongarch(H264QpelContext *c, int bit_depth); diff --git a/libavcodec/h264qpel_template.c b/libavcodec/h264qpel_template.c index f7fabe4aa..875ac86d1 100644 --- a/libavcodec/h264qpel_template.c +++ b/libavcodec/h264qpel_template.c @@ -75,88 +75,9 @@ static inline void FUNC(copy_block16)(uint8_t *dst, const uint8_t *restrict src, } #define H264_LOWPASS(OPNAME, OP, OP2) \ -static av_unused void FUNC(OPNAME ## h264_qpel2_h_lowpass)(uint8_t *p_dst, const uint8_t *restrict p_src, int dstStride, int srcStride)\ -{\ - const int h=2;\ - INIT_CLIP\ - int i;\ - pixel *dst = (pixel*)p_dst;\ - const pixel *restrict src = (const pixel*)p_src;\ - dstStride >>= sizeof(pixel)-1;\ - srcStride >>= sizeof(pixel)-1;\ - for(i=0; i>= sizeof(pixel)-1;\ - srcStride >>= sizeof(pixel)-1;\ - for(i=0; i>= sizeof(pixel)-1;\ - srcStride >>= sizeof(pixel)-1;\ - src -= 2*srcStride;\ - for(i=0; i>10)+1)>>1) #define op2_put(a, b) a = CLIP(((b) + 512)>>10) +#ifndef SNOW H264_LOWPASS(put_ , op_put, op2_put) H264_LOWPASS(avg_ , op_avg, op2_avg) -H264_MC(put_, 2) -H264_MC(put_, 4) -H264_MC(put_, 8) -H264_MC(put_, 16) -H264_MC(avg_, 4) -H264_MC(avg_, 8) -H264_MC(avg_, 16) +H264_MC(put_, h264, 4) +H264_MC(put_, h264, 8) +H264_MC(put_, h264, 16) +H264_MC(avg_, h264, 4) +H264_MC(avg_, h264, 8) +H264_MC(avg_, h264, 16) +#endif #undef op_avg #undef op_put diff --git a/libavcodec/h274.c b/libavcodec/h274.c index 570920032..93ad2d101 100644 --- a/libavcodec/h274.c +++ b/libavcodec/h274.c @@ -25,11 +25,27 @@ * @author Niklas Haas */ +#include + #include "libavutil/avassert.h" +#include "libavutil/bswap.h" +#include "libavcodec/bswapdsp.h" +#include "libavutil/crc.h" #include "libavutil/imgutils.h" +#include "libavutil/md5.h" +#include "libavutil/mem.h" +#include "libavutil/thread.h" #include "h274.h" +typedef struct H274FilmGrainDatabase { + // Database of film grain patterns, lazily computed as-needed + int8_t db[13 /* h */][13 /* v */][64][64]; + atomic_uint residency[6]; +} H274FilmGrainDatabase; + +static H274FilmGrainDatabase film_grain_db; + static const int8_t Gaussian_LUT[2048+4]; static const uint32_t Seed_LUT[256]; static const int8_t R64T[64][64]; @@ -42,8 +58,7 @@ static void prng_shift(uint32_t *state) *state = (x << 1) | (feedback & 1u); } -static void init_slice_c(int8_t out[64][64], uint8_t h, uint8_t v, - int16_t tmp[64][64]) +static void init_slice_c(int8_t out[64][64], uint8_t h, uint8_t v) { static const uint8_t deblock_factors[13] = { 64, 71, 77, 84, 90, 96, 103, 109, 116, 122, 128, 128, 128 @@ -52,6 +67,9 @@ static void init_slice_c(int8_t out[64][64], uint8_t h, uint8_t v, const uint8_t deblock_coeff = deblock_factors[v]; const uint8_t freq_h = ((h + 3) << 2) - 1; const uint8_t freq_v = ((v + 3) << 2) - 1; + // Temporary buffer for slice generation + // FIXME: Static or not? + static int16_t tmp[64][64]; uint32_t seed = Seed_LUT[h + v * 13]; // Initialize with random gaussian values, using the output array as a @@ -92,7 +110,7 @@ static void init_slice_c(int8_t out[64][64], uint8_t h, uint8_t v, } } - // Deblock horizontal edges by simple attentuation of values + // Deblock horizontal edges by simple attenuation of values for (int y = 0; y < 64; y += 8) { for (int x = 0; x < 64; x++) { out[y + 0][x] = (out[y + 0][x] * deblock_coeff) >> 7; @@ -101,13 +119,24 @@ static void init_slice_c(int8_t out[64][64], uint8_t h, uint8_t v, } } -static void init_slice(H274FilmGrainDatabase *database, uint8_t h, uint8_t v) +static void init_slice(uint8_t h, uint8_t v) { - if (database->residency[h] & (1 << v)) + static AVMutex mutex = AV_MUTEX_INITIALIZER; + unsigned bitpos = h * 13 + v; + unsigned res = atomic_load_explicit(&film_grain_db.residency[bitpos / 32], + memory_order_acquire); + + if (res & (1U << (bitpos & 31))) return; - database->residency[h] |= (1 << v); - init_slice_c(database->db[h][v], h, v, database->slice_tmp); + ff_mutex_lock(&mutex); + res = atomic_load_explicit(&film_grain_db.residency[bitpos / 32], memory_order_relaxed); + if (!(res & (1U << (bitpos & 31)))) { + init_slice_c(film_grain_db.db[h][v], h, v); + atomic_store_explicit(&film_grain_db.residency[bitpos / 32], + res | (1U << (bitpos & 31)), memory_order_release); + } + ff_mutex_unlock(&mutex); } // Computes the average of an 8x8 block @@ -155,7 +184,6 @@ static void deblock_8x8_c(int8_t *out, const int out_stride) // deblocking step (note that this implies writing to the previous block). static av_always_inline void generate(int8_t *out, int out_stride, const uint8_t *in, int in_stride, - H274FilmGrainDatabase *database, const AVFilmGrainH274Params *h274, int c, int invert, int deblock, int y_offset, int x_offset) @@ -193,14 +221,14 @@ static av_always_inline void generate(int8_t *out, int out_stride, h = av_clip(h274->comp_model_value[c][s][1], 2, 14) - 2; v = av_clip(h274->comp_model_value[c][s][2], 2, 14) - 2; - init_slice(database, h, v); + init_slice(h, v); scale = h274->comp_model_value[c][s][0]; if (invert) scale = -scale; synth_grain_8x8_c(out, out_stride, scale, shift, - &database->db[h][v][y_offset][x_offset]); + &film_grain_db.db[h][v][y_offset][x_offset]); if (deblock) deblock_8x8_c(out, out_stride); @@ -215,7 +243,6 @@ static void add_8x8_clip_c(uint8_t *out, const uint8_t *a, const int8_t *b, } int ff_h274_apply_film_grain(AVFrame *out_frame, const AVFrame *in_frame, - H274FilmGrainDatabase *database, const AVFilmGrainParams *params) { AVFilmGrainH274Params h274 = params->codec.h274; @@ -235,7 +262,7 @@ int ff_h274_apply_film_grain(AVFrame *out_frame, const AVFrame *in_frame, uint8_t * const out = out_frame->data[c]; const int out_stride = out_frame->linesize[c]; - int8_t * const grain = out_frame->data[c]; // re-use output buffer for grain + int8_t * const grain = out_frame->data[c]; // reuse output buffer for grain const int grain_stride = out_stride; const uint8_t * const in = in_frame->data[c]; const int in_stride = in_frame->linesize[c]; @@ -270,7 +297,7 @@ int ff_h274_apply_film_grain(AVFrame *out_frame, const AVFrame *in_frame, for (int xx = 0; xx < 16 && x+xx < width; xx += 8) { generate(grain + (y+yy) * grain_stride + (x+xx), grain_stride, in + (y+yy) * in_stride + (x+xx), in_stride, - database, &h274, c, invert, (x+xx) > 0, + &h274, c, invert, (x+xx) > 0, y_offset + yy, x_offset + xx); } } @@ -790,3 +817,195 @@ static const int8_t R64T[64][64] = { 17, -16, 15, -14, 13, -12, 11, -10, 9, -8, 7, -6, 4, -3, 2, -1, } }; + +struct H274HashContext { + int type; + struct AVMD5 *ctx; + +#if HAVE_BIGENDIAN + BswapDSPContext bdsp; + uint8_t *buf; + int buf_size; +#endif +}; + +static av_always_inline void bswap16_buf_if_be(H274HashContext *s, const int ps, const uint8_t **src, const int w) +{ +#if HAVE_BIGENDIAN + if (ps) { + s->bdsp.bswap16_buf((uint16_t *)s->buf, + (const uint16_t *)*src, w); + *src = s->buf; + } +#endif +} + +static int verify_plane_md5(H274HashContext *s, + const uint8_t *_src, const int w, const int h, const int stride, + const int ps, const uint8_t *expected) +{ +#define MD5_SIZE 16 + struct AVMD5 *ctx = s->ctx; + uint8_t md5[MD5_SIZE]; + + av_md5_init(ctx); + for (int j = 0; j < h; j++) { + const uint8_t *src = &_src[j * stride]; + bswap16_buf_if_be(s, ps, &src, w); + av_md5_update(ctx, src, w << ps); + src += stride; + } + av_md5_final(ctx, md5); + + if (memcmp(md5, expected, MD5_SIZE)) + return AVERROR_INVALIDDATA; + + return 0; +} + +static int verify_plane_crc(H274HashContext *s, const uint8_t *_src, const int w, const int h, const int stride, + const int ps, uint16_t expected) +{ + uint32_t crc = 0x0F1D; // CRC-16-CCITT-AUG + const AVCRC *ctx = av_crc_get_table(AV_CRC_16_CCITT); + + for (int j = 0; j < h; j++) { + const uint8_t *src = &_src[j * stride]; + bswap16_buf_if_be(s, ps, &src, w); + crc = av_crc(ctx, crc, src, w << ps); + src += stride; + } + crc = av_bswap16(crc); + + if (crc != expected) + return AVERROR_INVALIDDATA; + + return 0; +} + +#define CAL_CHECKSUM(pixel) ((pixel) ^ xor_mask) +static int verify_plane_checksum(const uint8_t *src, const int w, const int h, const int stride, const int ps, + uint32_t expected) +{ + uint32_t checksum = 0; + expected = av_le2ne32(expected); + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + const int xor_mask = (x & 0xFF) ^ (y & 0xFF) ^ (x >> 8) ^ (y >> 8); + checksum += CAL_CHECKSUM(src[x << ps]); + if (ps) + checksum += CAL_CHECKSUM(src[(x << ps) + 1]); + } + src += stride; + } + + if (checksum != expected) + return AVERROR_INVALIDDATA; + + return 0; +} + +enum { + HASH_MD5SUM, + HASH_CRC, + HASH_CHECKSUM, + HASH_LAST = HASH_CHECKSUM, +}; + +void ff_h274_hash_freep(H274HashContext **ctx) +{ + if (*ctx) { + H274HashContext *c = *ctx; + if (c->ctx) + av_free(c->ctx); + av_freep(ctx); +#if HAVE_BIGENDIAN + av_freep(&c->buf); +#endif + } +} + +int ff_h274_hash_init(H274HashContext **ctx, const int type) +{ + H274HashContext *c; + + if (type > HASH_LAST || !ctx) + return AVERROR(EINVAL); + + c = *ctx; + if (c) { + if (c->type != type) { + if (c->type == HASH_MD5SUM) + av_freep(&c->ctx); + c->type = type; + } + } else { + c = av_mallocz(sizeof(H274HashContext)); + if (!c) + return AVERROR(ENOMEM); + c->type = type; + *ctx = c; + } + + if (type == HASH_MD5SUM && !c->ctx) { + c->ctx = av_md5_alloc(); + if (!c->ctx) + return AVERROR(ENOMEM); + } + +#if HAVE_BIGENDIAN + ff_bswapdsp_init(&c->bdsp); +#endif + + return 0; +} + +int ff_h274_hash_verify(H274HashContext *c, const H274SEIPictureHash *hash, + const AVFrame *frame, const int coded_width, const int coded_height) +{ + const AVPixFmtDescriptor *desc; + int err = 0; + + if (!c || !hash || !frame) + return AVERROR(EINVAL); + + if (c->type != hash->hash_type) + return AVERROR(EINVAL); + + desc = av_pix_fmt_desc_get(frame->format); + if (!desc) + return AVERROR(EINVAL); + + for (int i = 0; i < desc->nb_components; i++) { + const int w = i ? (coded_width >> desc->log2_chroma_w) : coded_width; + const int h = i ? (coded_height >> desc->log2_chroma_h) : coded_height; + const int ps = desc->comp[i].step - 1; + const uint8_t *src = frame->data[i]; + const int stride = frame->linesize[i]; + +#if HAVE_BIGENDIAN + if (c->type != HASH_CHECKSUM) { + if (ps) { + av_fast_malloc(&c->buf, &c->buf_size, + FFMAX3(frame->linesize[0], frame->linesize[1], + frame->linesize[2])); + if (!c->buf) + return AVERROR(ENOMEM); + } + } +#endif + + if (c->type == HASH_MD5SUM) + err = verify_plane_md5(c, src, w, h, stride, ps, hash->md5[i]); + else if (c->type == HASH_CRC) + err = verify_plane_crc(c, src, w, h, stride, ps, hash->crc[i]); + else if (c->type == HASH_CHECKSUM) + err = verify_plane_checksum(src, w, h, stride, ps, hash->checksum[i]); + if (err < 0) + goto fail; + } + +fail: + return err; +} diff --git a/libavcodec/h274.h b/libavcodec/h274.h index cebc8becb..7bbc3e8aa 100644 --- a/libavcodec/h274.h +++ b/libavcodec/h274.h @@ -30,16 +30,6 @@ #include "libavutil/film_grain_params.h" -// Must be initialized to {0} prior to first usage -typedef struct H274FilmGrainDatabase { - // Database of film grain patterns, lazily computed as-needed - int8_t db[13 /* h */][13 /* v */][64][64]; - uint16_t residency[13 /* h */]; // bit field of v - - // Temporary buffer for slice generation - int16_t slice_tmp[64][64]; -} H274FilmGrainDatabase; - /** * Check whether ff_h274_apply_film_grain() supports the given parameter combination. * @@ -61,7 +51,31 @@ static inline int ff_h274_film_grain_params_supported(int model_id, enum AVPixel // ff_h274_film_grain_params_supported() coincide with actual values // from the frames and params. int ff_h274_apply_film_grain(AVFrame *out, const AVFrame *in, - H274FilmGrainDatabase *db, const AVFilmGrainParams *params); +typedef struct H274HashContext H274HashContext; + +typedef struct H274SEIPictureHash { + int present; + union { + uint8_t md5[3][16]; + uint16_t crc[3]; + uint32_t checksum[3]; + }; + uint8_t hash_type; +} H274SEIPictureHash; + +int ff_h274_hash_init(H274HashContext **c, int type); +int ff_h274_hash_verify(H274HashContext *c, const H274SEIPictureHash *hash, + const AVFrame *frame, int coded_width, int coded_height); +void ff_h274_hash_freep(H274HashContext **c); + +typedef struct H274SEIFrameFieldInfo { + int present; + int picture_struct; + uint8_t display_elemental_periods; + uint8_t source_scan_type; + uint8_t duplicate_flag; +} H274SEIFrameFieldInfo; + #endif /* AVCODEC_H274_H */ diff --git a/libavcodec/hap.h b/libavcodec/hap.h index 1de6d4542..b07f8a4b1 100644 --- a/libavcodec/hap.h +++ b/libavcodec/hap.h @@ -62,7 +62,8 @@ typedef struct HapContext { GetByteContext gbc; - enum HapTextureFormat opt_tex_fmt; /* Texture type (encoder only) */ + /* enum HapTextureFormat, use int for AVOption */ + int opt_tex_fmt; /* Texture type (encoder only) */ int opt_chunk_count; /* User-requested chunk count (encoder only) */ int opt_compressor; /* User-requested compressor (encoder only) */ diff --git a/libavcodec/hapenc.c b/libavcodec/hapenc.c index 8dc12a851..6882b1e56 100644 --- a/libavcodec/hapenc.c +++ b/libavcodec/hapenc.c @@ -121,7 +121,7 @@ static int hap_compress_frame(AVCodecContext *avctx, uint8_t *dst) /* If there is no gain from snappy, just use the raw texture. */ if (chunk->compressed_size >= chunk->uncompressed_size) { av_log(avctx, AV_LOG_VERBOSE, - "Snappy buffer bigger than uncompressed (%"SIZE_SPECIFIER" >= %"SIZE_SPECIFIER" bytes).\n", + "Snappy buffer bigger than uncompressed (%zu >= %zu bytes).\n", chunk->compressed_size, chunk->uncompressed_size); memcpy(chunk_dst, chunk_src, chunk->uncompressed_size); chunk->compressor = HAP_COMP_NONE; @@ -305,7 +305,7 @@ static av_cold int hap_init(AVCodecContext *avctx) } break; default: - av_log(avctx, AV_LOG_ERROR, "Invalid compresor %02X\n", ctx->opt_compressor); + av_log(avctx, AV_LOG_ERROR, "Invalid compressor %02X\n", ctx->opt_compressor); return AVERROR_INVALIDDATA; } if (corrected_chunk_count != ctx->opt_chunk_count) { @@ -361,8 +361,6 @@ const FFCodec ff_hap_encoder = { .init = hap_init, FF_CODEC_ENCODE_CB(hap_encode), .close = hap_close, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGBA), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/hashtable.c b/libavcodec/hashtable.c new file mode 100644 index 000000000..d18e872f4 --- /dev/null +++ b/libavcodec/hashtable.c @@ -0,0 +1,212 @@ +/* + * Generic hashtable + * Copyright (C) 2025 Emma Worley + * + * 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 "libavutil/attributes.h" +#include "libavutil/crc.h" +#include "libavutil/error.h" +#include "libavutil/macros.h" +#include "libavutil/mem.h" +#include "hashtable.h" + +#define ALIGN _Alignof(size_t) + +struct FFHashtableContext { + size_t key_size; + size_t val_size; + size_t entry_size; + size_t max_entries; + size_t nb_entries; + const AVCRC *crc; + uint8_t *table; + uint8_t swapbuf[]; +}; + +/* + * Hash table entries are comprised of a probe sequence length (PSL), key, and + * value. When the PSL of an entry is zero, it means it is not occupied by a + * key/value pair. When the PSL is non-zero, it represents the "distance" of + * the entry from its "home" location plus one, where the "home" location is + * hash(key) % max_entries. + */ + +#define ENTRY_PSL_VAL(entry) (*(size_t*)(entry)) +#define ENTRY_KEY_PTR(entry) ((entry) + sizeof(size_t)) +#define ENTRY_VAL_PTR(entry) (ENTRY_KEY_PTR(entry) + ctx->key_size) + +#define KEYS_EQUAL(k1, k2) (!memcmp((k1), (k2), ctx->key_size)) + +av_cold int ff_hashtable_alloc(FFHashtableContext **ctx, size_t key_size, + size_t val_size, size_t max_entries) +{ + const size_t keyval_size = key_size + val_size; + + if (keyval_size < key_size || // did (unsigned,defined) wraparound happen? + keyval_size > FFMIN(SIZE_MAX - sizeof(size_t) - (ALIGN - 1), + (SIZE_MAX - sizeof(FFHashtableContext)) / 2)) + return AVERROR(ERANGE); + + FFHashtableContext *res = av_mallocz(sizeof(*res) + 2 * keyval_size); + if (!res) + return AVERROR(ENOMEM); + res->key_size = key_size; + res->val_size = val_size; + res->entry_size = FFALIGN(sizeof(size_t) + keyval_size, ALIGN); + res->max_entries = max_entries; + res->nb_entries = 0; + res->crc = av_crc_get_table(AV_CRC_32_IEEE); + if (!res->crc) { + ff_hashtable_freep(&res); + return AVERROR_BUG; + } + res->table = av_calloc(res->max_entries, res->entry_size); + if (!res->table) { + ff_hashtable_freep(&res); + return AVERROR(ENOMEM); + } + + *ctx = res; + return 0; +} + +static size_t hash_key(const struct FFHashtableContext *ctx, const void *key) +{ + return av_crc(ctx->crc, 0, key, ctx->key_size) % ctx->max_entries; +} + +int ff_hashtable_get(const struct FFHashtableContext *ctx, const void *key, void *val) +{ + if (!ctx->nb_entries) + return 0; + + size_t hash = hash_key(ctx, key); + + for (size_t psl = 1; psl <= ctx->max_entries; psl++) { + size_t wrapped_index = (hash + psl) % ctx->max_entries; + uint8_t *entry = ctx->table + wrapped_index * ctx->entry_size; + if (ENTRY_PSL_VAL(entry) < psl) + // When PSL stops increasing it means there are no further entries + // with the same key hash. + return 0; + if (KEYS_EQUAL(ENTRY_KEY_PTR(entry), key)) { + memcpy(val, ENTRY_VAL_PTR(entry), ctx->val_size); + return 1; + } + } + return 0; +} + +int ff_hashtable_set(struct FFHashtableContext *ctx, const void *key, const void *val) +{ + int swapping = 0; + size_t psl = 1; + size_t hash = hash_key(ctx, key); + size_t wrapped_index = hash % ctx->max_entries; + uint8_t *set = ctx->swapbuf; + uint8_t *tmp = ctx->swapbuf + ctx->key_size + ctx->val_size; + + memcpy(set, key, ctx->key_size); + memcpy(set + ctx->key_size, val, ctx->val_size); + + for (size_t i = 0; i < ctx->max_entries; i++) { + if (++wrapped_index == ctx->max_entries) + wrapped_index = 0; + uint8_t *entry = ctx->table + wrapped_index * ctx->entry_size; + if (!ENTRY_PSL_VAL(entry) || (!swapping && KEYS_EQUAL(ENTRY_KEY_PTR(entry), set))) { + if (!ENTRY_PSL_VAL(entry)) + ctx->nb_entries++; + ENTRY_PSL_VAL(entry) = psl; + memcpy(ENTRY_KEY_PTR(entry), set, ctx->key_size + ctx->val_size); + return 1; + } + if (ENTRY_PSL_VAL(entry) < psl) { + // When PSL stops increasing it means there are no further entries + // with the same key hash. We can only hope to find an unoccupied + // entry. + if (ctx->nb_entries == ctx->max_entries) + // The table is full so inserts are impossible. + return 0; + // Robin Hood hash tables "steal from the rich" by minimizing the + // PSL of the inserted entry. + swapping = 1; + // set needs to swap with entry + memcpy(tmp, ENTRY_KEY_PTR(entry), ctx->key_size + ctx->val_size); + memcpy(ENTRY_KEY_PTR(entry), set, ctx->key_size + ctx->val_size); + FFSWAP(uint8_t*, set, tmp); + FFSWAP(size_t, psl, ENTRY_PSL_VAL(entry)); + } + psl++; + } + return 0; +} + +int ff_hashtable_delete(struct FFHashtableContext *ctx, const void *key) +{ + if (!ctx->nb_entries) + return 0; + + uint8_t *next_entry; + size_t hash = hash_key(ctx, key); + size_t wrapped_index = hash % ctx->max_entries; + + for (size_t psl = 1; psl <= ctx->max_entries; psl++) { + if (++wrapped_index == ctx->max_entries) + wrapped_index = 0; + uint8_t *entry = ctx->table + wrapped_index * ctx->entry_size; + if (ENTRY_PSL_VAL(entry) < psl) + // When PSL stops increasing it means there are no further entries + // with the same key hash. + return 0; + if (KEYS_EQUAL(ENTRY_KEY_PTR(entry), key)) { + ENTRY_PSL_VAL(entry) = 0; + // Shift each following entry that will benefit from a reduced PSL. + for (psl++; psl <= ctx->max_entries; psl++) { + if (++wrapped_index == ctx->max_entries) + wrapped_index = 0; + next_entry = ctx->table + wrapped_index * ctx->entry_size; + if (ENTRY_PSL_VAL(next_entry) <= 1) { + ctx->nb_entries--; + return 1; + } + memcpy(entry, next_entry, ctx->entry_size); + ENTRY_PSL_VAL(entry)--; + ENTRY_PSL_VAL(next_entry) = 0; + entry = next_entry; + } + } + } + return 0; +} + +void ff_hashtable_clear(struct FFHashtableContext *ctx) +{ + memset(ctx->table, 0, ctx->entry_size * ctx->max_entries); +} + +av_cold void ff_hashtable_freep(FFHashtableContext **ctx) +{ + if (*ctx) { + av_freep(&(*ctx)->table); + av_freep(ctx); + } +} diff --git a/libavcodec/hashtable.h b/libavcodec/hashtable.h new file mode 100644 index 000000000..f81b4bb93 --- /dev/null +++ b/libavcodec/hashtable.h @@ -0,0 +1,94 @@ +/* + * Generic hashtable + * Copyright (C) 2024 Emma Worley + * + * 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_HASHTABLE_H +#define AVCODEC_HASHTABLE_H + +#include + +/* Implements a hash table using Robin Hood open addressing. + * See: https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf + * + * Keys are placed in the table based on their CRC value and are considered + * equal when they are bytewise-identical. + */ + +typedef struct FFHashtableContext FFHashtableContext; + +/** + * Create a fixed-sized Robin Hood hash table. + * + * @param ctx context to allocate and initialize + * @param key_size size of key type in bytes + * @param val_size size of value type in bytes + * @param max_entries maximum number of key-value pairs to store + * + * @return zero on success, nonzero on error + */ +int ff_hashtable_alloc(struct FFHashtableContext **ctx, size_t key_size, size_t val_size, size_t max_entries); + +/** + * Look up a value from a hash table given a key. + * + * @param ctx hash table context + * @param key pointer to key data + * @param val destination pointer for value data + * + * @return 1 if the key is found, zero if the key is not found + */ +int ff_hashtable_get(const struct FFHashtableContext *ctx, const void *key, void *val); + +/** + * Store a value in a hash table given a key. + * + * @param ctx hash table context + * @param key pointer to key data + * @param val pointer for value data + * + * @return 1 if the key is written, zero if the key is not written due to the hash table reaching max capacity + */ +int ff_hashtable_set(struct FFHashtableContext *ctx, const void *key, const void *val); + +/** + * Delete a value from a hash table given a key. + * + * @param ctx hash table context + * @param key pointer to key data + * + * @return 1 if the key is deleted, zero if the key is not deleted due to not being found + */ +int ff_hashtable_delete(struct FFHashtableContext *ctx, const void *key); + +/** + * Delete all values from a hash table. + * + * @param ctx hash table context + */ +void ff_hashtable_clear(struct FFHashtableContext *ctx); + +/** + * Free a hash table. + * + * @param ctx hash table context + */ +void ff_hashtable_freep(struct FFHashtableContext **ctx); + +#endif diff --git a/libavcodec/hcadec.c b/libavcodec/hcadec.c index e8f877c3c..2eac70b60 100644 --- a/libavcodec/hcadec.c +++ b/libavcodec/hcadec.c @@ -245,6 +245,7 @@ static int init_hca(AVCodecContext *avctx, const uint8_t *extradata, c->base_band_count = bytestream2_get_byteu(gb); c->stereo_band_count = bytestream2_get_byte (gb); c->bands_per_hfr_group = bytestream2_get_byte (gb); + bytestream2_skipu(gb, 2); } else if (chunk == MKBETAG('d', 'e', 'c', 0)) { bytestream2_skipu(gb, 2); bytestream2_skipu(gb, 1); @@ -634,6 +635,4 @@ const FFCodec ff_hca_decoder = { .close = decode_close, .p.capabilities = AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/hdr_parser.c b/libavcodec/hdr_parser.c index 915fd3822..0fdfcb5c5 100644 --- a/libavcodec/hdr_parser.c +++ b/libavcodec/hdr_parser.c @@ -26,6 +26,7 @@ #include "libavutil/intreadwrite.h" #include "parser.h" +#include "parser_internal.h" typedef struct HDRParseContext { ParseContext pc; @@ -71,9 +72,9 @@ static int hdr_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_hdr_parser = { - .codec_ids = { AV_CODEC_ID_RADIANCE_HDR }, +const FFCodecParser ff_hdr_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_RADIANCE_HDR), .priv_data_size = sizeof(HDRParseContext), - .parser_parse = hdr_parse, - .parser_close = ff_parse_close, + .parse = hdr_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/hdrenc.c b/libavcodec/hdrenc.c index a7bf36946..71478475e 100644 --- a/libavcodec/hdrenc.c +++ b/libavcodec/hdrenc.c @@ -182,9 +182,6 @@ const FFCodec ff_hdr_encoder = { .init = hdr_encode_init, FF_CODEC_ENCODE_CB(hdr_encode_frame), .close = hdr_encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_GBRPF32, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_GBRPF32), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/hevc/dsp.c b/libavcodec/hevc/dsp.c index 60f059292..5ae779f9f 100644 --- a/libavcodec/hevc/dsp.c +++ b/libavcodec/hevc/dsp.c @@ -265,7 +265,11 @@ int i = 0; ff_hevc_dsp_init_arm(hevcdsp, bit_depth); #elif ARCH_PPC ff_hevc_dsp_init_ppc(hevcdsp, bit_depth); -#elif ARCH_X86 +#elif ARCH_RISCV + ff_hevc_dsp_init_riscv(hevcdsp, bit_depth); +#elif ARCH_WASM + ff_hevc_dsp_init_wasm(hevcdsp, bit_depth); +#elif ARCH_X86 && HAVE_X86ASM ff_hevc_dsp_init_x86(hevcdsp, bit_depth); #elif ARCH_MIPS ff_hevc_dsp_init_mips(hevcdsp, bit_depth); diff --git a/libavcodec/hevc/dsp.h b/libavcodec/hevc/dsp.h index 02b8e0e8e..b884cd36b 100644 --- a/libavcodec/hevc/dsp.h +++ b/libavcodec/hevc/dsp.h @@ -50,7 +50,7 @@ typedef struct HEVCDSPContext { void (*add_residual[4])(uint8_t *dst, const int16_t *res, ptrdiff_t stride); - void (*dequant)(int16_t *coeffs, int16_t log2_size); + void (*dequant)(int16_t *coeffs /* align 32 */, int16_t log2_size); void (*transform_rdpcm)(int16_t *coeffs, int16_t log2_size, int mode); @@ -133,6 +133,8 @@ extern const int8_t ff_hevc_qpel_filters[4][16]; void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_arm(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_ppc(HEVCDSPContext *c, const int bit_depth); +void ff_hevc_dsp_init_riscv(HEVCDSPContext *c, const int bit_depth); +void ff_hevc_dsp_init_wasm(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_mips(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_loongarch(HEVCDSPContext *c, const int bit_depth); diff --git a/libavcodec/hevc/dsp_template.c b/libavcodec/hevc/dsp_template.c index a0f79c267..f703f6d07 100644 --- a/libavcodec/hevc/dsp_template.c +++ b/libavcodec/hevc/dsp_template.c @@ -106,13 +106,33 @@ static void FUNC(transform_rdpcm)(int16_t *_coeffs, int16_t log2_size, int mode) } } +/** + * HEVC transform dequantization (ITU-T H.265 8.6.3) + * + * @param coeffs transform coefficient buffer (in-place) + * @param log2_size log2 of transform block size, range: 2..5 (4x4 to 32x32) + * This value comes from recursive split_transform_flag parsing + * in the bitstream, bounded by log2_min_tb_size (min 2) and + * log2_max_trafo_size (max 5) from SPS. + * + * Formula: shift = 15 - BIT_DEPTH - log2_size + * + * bit_depth | 4x4 (2) | 8x8 (3) | 16x16 (4) | 32x32 (5) + * ----------+---------+---------+-----------+---------- + * 8-bit | 5 | 4 | 3 | 2 (shift right) + * 10-bit | 3 | 2 | 1 | 0 (shift right / no-op) + * 12-bit | 1 | 0 | -1 | -2 (shift right / no-op / shift left) + * + * When shift == 0, output equals input (identity transform), so we skip + * the loop entirely for better performance. + */ static void FUNC(dequant)(int16_t *coeffs, int16_t log2_size) { int shift = 15 - BIT_DEPTH - log2_size; int x, y; int size = 1 << log2_size; - if (shift > 0) { + if (BIT_DEPTH <= 9 || shift > 0) { int offset = 1 << (shift - 1); for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { @@ -120,7 +140,7 @@ static void FUNC(dequant)(int16_t *coeffs, int16_t log2_size) coeffs++; } } - } else { + } else if (BIT_DEPTH > 10 && shift < 0) { for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { *coeffs = *(uint16_t*)coeffs << -shift; @@ -128,6 +148,7 @@ static void FUNC(dequant)(int16_t *coeffs, int16_t log2_size) } } } + /* shift == 0: no operation needed (identity transform) */ } #define SET(dst, x) (dst) = (x) diff --git a/libavcodec/hevc/hevc.h b/libavcodec/hevc/hevc.h index 8bd59142d..710786a89 100644 --- a/libavcodec/hevc/hevc.h +++ b/libavcodec/hevc/hevc.h @@ -162,5 +162,17 @@ enum { HEVC_MAX_PALETTE_PREDICTOR_SIZE = 128, }; +enum HEVCScalabilityMask { + HEVC_SCALABILITY_DEPTH = 1 << (15 - 0), + HEVC_SCALABILITY_MULTIVIEW = 1 << (15 - 1), + HEVC_SCALABILITY_SPATIAL = 1 << (15 - 2), + HEVC_SCALABILITY_AUXILIARY = 1 << (15 - 3), + HEVC_SCALABILITY_MASK_MAX = 0xFFFF, +}; + +enum HEVCAuxId { + HEVC_AUX_ALPHA = 1, + HEVC_AUX_DEPTH = 2, +}; #endif /* AVCODEC_HEVC_HEVC_H */ diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c index 7bd3a706a..ae5f0fe69 100644 --- a/libavcodec/hevc/hevcdec.c +++ b/libavcodec/hevc/hevcdec.c @@ -28,6 +28,7 @@ #include "libavutil/attributes.h" #include "libavutil/avstring.h" #include "libavutil/common.h" +#include "libavutil/container_fifo.h" #include "libavutil/film_grain_params.h" #include "libavutil/internal.h" #include "libavutil/md5.h" @@ -35,15 +36,16 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/stereo3d.h" +#include "libavutil/tdrdi.h" #include "libavutil/timecode.h" #include "aom_film_grain.h" #include "bswapdsp.h" #include "cabac_functions.h" #include "codec_internal.h" -#include "container_fifo.h" #include "decode.h" #include "golomb.h" +#include "h274.h" #include "hevc.h" #include "parse.h" #include "hevcdec.h" @@ -52,7 +54,7 @@ #include "internal.h" #include "profiles.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadprogress.h" @@ -92,8 +94,8 @@ static void pic_arrays_free(HEVCLayerContext *l) av_freep(&l->sao_pixel_buffer_v[i]); } - ff_refstruct_pool_uninit(&l->tab_mvf_pool); - ff_refstruct_pool_uninit(&l->rpl_tab_pool); + av_refstruct_pool_uninit(&l->tab_mvf_pool); + av_refstruct_pool_uninit(&l->rpl_tab_pool); } /* allocate arrays that depend on frame dimensions */ @@ -139,8 +141,8 @@ static int pic_arrays_init(HEVCLayerContext *l, const HEVCSPS *sps) if (!l->horizontal_bs || !l->vertical_bs) goto fail; - l->tab_mvf_pool = ff_refstruct_pool_alloc(min_pu_size * sizeof(MvField), 0); - l->rpl_tab_pool = ff_refstruct_pool_alloc(ctb_count * sizeof(RefPicListTab), 0); + l->tab_mvf_pool = av_refstruct_pool_alloc(min_pu_size * sizeof(MvField), 0); + l->rpl_tab_pool = av_refstruct_pool_alloc(ctb_count * sizeof(RefPicListTab), 0); if (!l->tab_mvf_pool || !l->rpl_tab_pool) goto fail; @@ -174,11 +176,8 @@ static int pred_weight_table(SliceHeader *sh, void *logctx, { 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]; int luma_log2_weight_denom; + unsigned luma_weight_flags, chroma_weight_flags; luma_log2_weight_denom = get_ue_golomb_long(gb); if (luma_log2_weight_denom < 0 || luma_log2_weight_denom > 7) { @@ -195,29 +194,22 @@ static int pred_weight_table(SliceHeader *sh, void *logctx, sh->chroma_log2_weight_denom = chroma_log2_weight_denom; } + luma_weight_flags = get_bits(gb, sh->nb_refs[L0]); + chroma_weight_flags = sps->chroma_format_idc != 0 ? get_bits(gb, sh->nb_refs[L0]) : 0; for (i = 0; i < sh->nb_refs[L0]; i++) { - luma_weight_l0_flag[i] = get_bits1(gb); - if (!luma_weight_l0_flag[i]) { - sh->luma_weight_l0[i] = 1 << sh->luma_log2_weight_denom; - sh->luma_offset_l0[i] = 0; - } - } - if (sps->chroma_format_idc != 0) { - for (i = 0; i < sh->nb_refs[L0]; i++) - chroma_weight_l0_flag[i] = get_bits1(gb); - } else { - for (i = 0; i < sh->nb_refs[L0]; i++) - chroma_weight_l0_flag[i] = 0; - } - for (i = 0; i < sh->nb_refs[L0]; i++) { - if (luma_weight_l0_flag[i]) { + unsigned flag_bit = 1 << (sh->nb_refs[L0] - 1 - i); + + if (luma_weight_flags & flag_bit) { int delta_luma_weight_l0 = get_se_golomb(gb); if ((int8_t)delta_luma_weight_l0 != delta_luma_weight_l0) return AVERROR_INVALIDDATA; sh->luma_weight_l0[i] = (1 << sh->luma_log2_weight_denom) + delta_luma_weight_l0; sh->luma_offset_l0[i] = get_se_golomb(gb); + } else { + sh->luma_weight_l0[i] = 1 << sh->luma_log2_weight_denom; + sh->luma_offset_l0[i] = 0; } - if (chroma_weight_l0_flag[i]) { + if (chroma_weight_flags & flag_bit) { for (j = 0; j < 2; j++) { int delta_chroma_weight_l0 = get_se_golomb(gb); int delta_chroma_offset_l0 = get_se_golomb(gb); @@ -239,29 +231,22 @@ static int pred_weight_table(SliceHeader *sh, void *logctx, } } if (sh->slice_type == HEVC_SLICE_B) { + luma_weight_flags = get_bits(gb, sh->nb_refs[L1]); + chroma_weight_flags = sps->chroma_format_idc != 0 ? get_bits(gb, sh->nb_refs[L1]) : 0; for (i = 0; i < sh->nb_refs[L1]; i++) { - luma_weight_l1_flag[i] = get_bits1(gb); - if (!luma_weight_l1_flag[i]) { - sh->luma_weight_l1[i] = 1 << sh->luma_log2_weight_denom; - sh->luma_offset_l1[i] = 0; - } - } - if (sps->chroma_format_idc != 0) { - for (i = 0; i < sh->nb_refs[L1]; i++) - chroma_weight_l1_flag[i] = get_bits1(gb); - } else { - for (i = 0; i < sh->nb_refs[L1]; i++) - chroma_weight_l1_flag[i] = 0; - } - for (i = 0; i < sh->nb_refs[L1]; i++) { - if (luma_weight_l1_flag[i]) { + unsigned flag_bit = 1 << (sh->nb_refs[L1] - 1 - i); + + if (luma_weight_flags & flag_bit) { int delta_luma_weight_l1 = get_se_golomb(gb); if ((int8_t)delta_luma_weight_l1 != delta_luma_weight_l1) return AVERROR_INVALIDDATA; sh->luma_weight_l1[i] = (1 << sh->luma_log2_weight_denom) + delta_luma_weight_l1; sh->luma_offset_l1[i] = get_se_golomb(gb); + } else { + sh->luma_weight_l1[i] = 1 << sh->luma_log2_weight_denom; + sh->luma_offset_l1[i] = 0; } - if (chroma_weight_l1_flag[i]) { + if (chroma_weight_flags & flag_bit) { for (j = 0; j < 2; j++) { int delta_chroma_weight_l1 = get_se_golomb(gb); int delta_chroma_offset_l1 = get_se_golomb(gb); @@ -403,8 +388,12 @@ static int export_stream_params_from_sei(HEVCContext *s) { AVCodecContext *avctx = s->avctx; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS if (s->sei.common.a53_caption.buf_ref) s->avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif if (s->sei.common.alternative_transfer.present && av_color_transfer_name(s->sei.common.alternative_transfer.preferred_transfer_characteristics) && @@ -412,9 +401,13 @@ static int export_stream_params_from_sei(HEVCContext *s) avctx->color_trc = s->sei.common.alternative_transfer.preferred_transfer_characteristics; } +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS if ((s->sei.common.film_grain_characteristics && s->sei.common.film_grain_characteristics->present) || s->sei.common.aom_film_grain.enable) avctx->properties |= FF_CODEC_PROPERTY_FILM_GRAIN; +FF_ENABLE_DEPRECATION_WARNINGS +#endif return 0; } @@ -458,6 +451,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps) return 0; } +int ff_hevc_is_alpha_video(const HEVCContext *s) +{ + const HEVCVPS *vps = s->vps; + int ret = 0; + + if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1]) + return 0; + + /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other + * than alpha cannot reach here. + */ + ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY); + + av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n", + ret ? "is" : "not"); + + return ret; +} + static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps) { unsigned layers_active_output = 0, highest_layer; @@ -465,6 +477,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps) s->layers_active_output = 1; s->layers_active_decode = 1; + if (ff_hevc_is_alpha_video(s)) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt); + + if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)) + return 0; + + s->layers_active_decode = (1 << vps->nb_layers) - 1; + s->layers_active_output = 1; + + return 0; + } + // nothing requested - decode base layer only if (!s->nb_view_ids) return 0; @@ -522,6 +546,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps) return 0; } +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s, + enum AVPixelFormat pix_fmt) +{ + switch (pix_fmt) { + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUVJ420P: + return AV_PIX_FMT_YUVA420P; + case AV_PIX_FMT_YUV420P10: + return AV_PIX_FMT_YUVA420P10; + case AV_PIX_FMT_YUV444P: + return AV_PIX_FMT_YUVA444P; + case AV_PIX_FMT_YUV422P: + return AV_PIX_FMT_YUVA422P; + case AV_PIX_FMT_YUV422P10LE: + return AV_PIX_FMT_YUVA422P10LE; + case AV_PIX_FMT_YUV444P10: + return AV_PIX_FMT_YUVA444P10; + case AV_PIX_FMT_YUV444P12: + return AV_PIX_FMT_YUVA444P12; + case AV_PIX_FMT_YUV422P12: + return AV_PIX_FMT_YUVA422P12; + default: + av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n", + av_get_pix_fmt_name(pix_fmt)); + return AV_PIX_FMT_NONE; + } +} + static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) { #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \ @@ -532,9 +584,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \ CONFIG_HEVC_VDPAU_HWACCEL + \ CONFIG_HEVC_VULKAN_HWACCEL) - enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts; + enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts; + enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE; int ret; + if (ff_hevc_is_alpha_video(s)) + alpha_fmt = map_to_alpha_format(s, sps->pix_fmt); + switch (sps->pix_fmt) { case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUVJ420P: @@ -618,6 +674,9 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_VULKAN_HWACCEL *fmt++ = AV_PIX_FMT_VULKAN; +#endif +#if CONFIG_HEVC_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; #endif break; case AV_PIX_FMT_YUV444P10: @@ -646,10 +705,15 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_VULKAN_HWACCEL *fmt++ = AV_PIX_FMT_VULKAN; +#endif +#if CONFIG_HEVC_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; #endif break; } + if (alpha_fmt != AV_PIX_FMT_NONE) + *fmt++ = alpha_fmt; *fmt++ = sps->pix_fmt; *fmt = AV_PIX_FMT_NONE; @@ -677,8 +741,8 @@ static int set_sps(HEVCContext *s, HEVCLayerContext *l, const HEVCSPS *sps) int ret; pic_arrays_free(l); - ff_refstruct_unref(&l->sps); - ff_refstruct_unref(&s->vps); + av_refstruct_unref(&l->sps); + av_refstruct_unref(&s->vps); if (!sps) return 0; @@ -691,14 +755,14 @@ static int set_sps(HEVCContext *s, HEVCLayerContext *l, const HEVCSPS *sps) ff_hevc_dsp_init (&s->hevcdsp, sps->bit_depth); ff_videodsp_init (&s->vdsp, sps->bit_depth); - l->sps = ff_refstruct_ref_c(sps); - s->vps = ff_refstruct_ref_c(sps->vps); + l->sps = av_refstruct_ref_c(sps); + s->vps = av_refstruct_ref_c(sps->vps); return 0; fail: pic_arrays_free(l); - ff_refstruct_unref(&l->sps); + av_refstruct_unref(&l->sps); return ret; } @@ -853,6 +917,7 @@ static int hls_slice_header(SliceHeader *sh, const HEVCContext *s, GetBitContext sh->short_term_ref_pic_set_size = 0; sh->short_term_rps = NULL; sh->long_term_ref_pic_set_size = 0; + sh->long_term_rps.nb_refs = 0; sh->slice_temporal_mvp_enabled_flag = 0; } @@ -1092,12 +1157,18 @@ static int hls_slice_header(SliceHeader *sh, const HEVCContext *s, GetBitContext } ret = get_bits1(gb); - if (!ret) { + if (!ret && get_bits_left(gb) >= 0) { av_log(s->avctx, AV_LOG_ERROR, "alignment_bit_equal_to_one=0\n"); return AVERROR_INVALIDDATA; } sh->data_offset = align_get_bits(gb) - gb->buffer; + 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; + } + // Inferred parameters sh->slice_qp = 26U + pps->pic_init_qp_minus26 + sh->slice_qp_delta; if (sh->slice_qp > 51 || @@ -1118,12 +1189,6 @@ static int hls_slice_header(SliceHeader *sh, const HEVCContext *s, GetBitContext 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; - } - return 0; } @@ -1597,16 +1662,12 @@ static int hls_pcm_sample(HEVCLocalContext *lc, const HEVCLayerContext *l, GetBitContext gb; int cb_size = 1 << log2_cb_size; ptrdiff_t stride0 = s->cur_frame->f->linesize[0]; - ptrdiff_t stride1 = s->cur_frame->f->linesize[1]; - ptrdiff_t stride2 = s->cur_frame->f->linesize[2]; uint8_t *dst0 = &s->cur_frame->f->data[0][y0 * stride0 + (x0 << sps->pixel_shift)]; - uint8_t *dst1 = &s->cur_frame->f->data[1][(y0 >> sps->vshift[1]) * stride1 + ((x0 >> sps->hshift[1]) << sps->pixel_shift)]; - uint8_t *dst2 = &s->cur_frame->f->data[2][(y0 >> sps->vshift[2]) * stride2 + ((x0 >> sps->hshift[2]) << sps->pixel_shift)]; - int length = cb_size * cb_size * sps->pcm.bit_depth + + int length = cb_size * cb_size * sps->pcm.bit_depth + (sps->chroma_format_idc != 0 ? (((cb_size >> sps->hshift[1]) * (cb_size >> sps->vshift[1])) + ((cb_size >> sps->hshift[2]) * (cb_size >> sps->vshift[2]))) * - sps->pcm.bit_depth_chroma; + sps->pcm.bit_depth_chroma : 0); const uint8_t *pcm = skip_bytes(&lc->cc, (length + 7) >> 3); int ret; @@ -1617,8 +1678,13 @@ static int hls_pcm_sample(HEVCLocalContext *lc, const HEVCLayerContext *l, if (ret < 0) return ret; - s->hevcdsp.put_pcm(dst0, stride0, cb_size, cb_size, &gb, sps->pcm.bit_depth); + s->hevcdsp.put_pcm(dst0, stride0, cb_size, cb_size, &gb, sps->pcm.bit_depth); if (sps->chroma_format_idc) { + ptrdiff_t stride1 = s->cur_frame->f->linesize[1]; + ptrdiff_t stride2 = s->cur_frame->f->linesize[2]; + uint8_t *dst1 = &s->cur_frame->f->data[1][(y0 >> sps->vshift[1]) * stride1 + ((x0 >> sps->hshift[1]) << sps->pixel_shift)]; + uint8_t *dst2 = &s->cur_frame->f->data[2][(y0 >> sps->vshift[2]) * stride2 + ((x0 >> sps->hshift[2]) << sps->pixel_shift)]; + s->hevcdsp.put_pcm(dst1, stride1, cb_size >> sps->hshift[1], cb_size >> sps->vshift[1], @@ -2032,9 +2098,10 @@ static void hls_prediction_unit(HEVCLocalContext *lc, int x0, int y0, int nPbW, int nPbH, int log2_cb_size, int partIdx, int idx) { -#define POS(c_idx, x, y) \ +#define POS(c_idx, x, y) \ + s->cur_frame->f->data[c_idx] ? \ &s->cur_frame->f->data[c_idx][((y) >> sps->vshift[c_idx]) * linesize[c_idx] + \ - (((x) >> sps->hshift[c_idx]) << sps->pixel_shift)] + (((x) >> sps->hshift[c_idx]) << sps->pixel_shift)] : NULL const HEVCContext *const s = lc->parent; int merge_idx = 0; struct MvField current_mv = {{{ 0 }}}; @@ -2045,7 +2112,7 @@ static void hls_prediction_unit(HEVCLocalContext *lc, const RefPicList *refPicList = s->cur_frame->refPicList; const HEVCFrame *ref0 = NULL, *ref1 = NULL; const int *linesize = s->cur_frame->f->linesize; - uint8_t *dst0 = POS(0, x0, y0); + uint8_t *dst0 = s->cur_frame->f->data[0] + y0 * linesize[0] + (x0 << sps->pixel_shift); uint8_t *dst1 = POS(1, x0, y0); uint8_t *dst2 = POS(2, x0, y0); int log2_min_cb_size = sps->log2_min_cb_size; @@ -2688,7 +2755,7 @@ static int hls_decode_entry(HEVCContext *s, GetBitContext *gb) const HEVCPPS *const pps = s->pps; const HEVCSPS *const sps = pps->sps; const uint8_t *slice_data = gb->buffer + s->sh.data_offset; - const size_t slice_size = gb->buffer_end - gb->buffer - s->sh.data_offset; + const size_t slice_size = get_bits_bytesize(gb, 1) - s->sh.data_offset; int ctb_size = 1 << sps->log2_ctb_size; int more_data = 1; int x_ctb = 0; @@ -3087,14 +3154,11 @@ static int set_side_data(HEVCContext *s) return ret; if (s->sei.common.dynamic_hdr_vivid.info) { - AVBufferRef *info_ref = av_buffer_ref(s->sei.common.dynamic_hdr_vivid.info); - if (!info_ref) + if (!av_frame_side_data_add(&out->side_data, &out->nb_side_data, + AV_FRAME_DATA_DYNAMIC_HDR_VIVID, + &s->sei.common.dynamic_hdr_vivid.info, + AV_FRAME_SIDE_DATA_FLAG_NEW_REF)) return AVERROR(ENOMEM); - - if (!av_frame_new_side_data_from_buf(out, AV_FRAME_DATA_DYNAMIC_HDR_VIVID, info_ref)) { - av_buffer_unref(&info_ref); - return AVERROR(ENOMEM); - } } return 0; @@ -3162,7 +3226,7 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, return AVERROR_INVALIDDATA; } - ff_refstruct_replace(&s->pps, pps); + av_refstruct_replace(&s->pps, pps); if (l->sps != sps) { const HEVCSPS *sps_base = s->layers[0].sps; enum AVPixelFormat pix_fmt = sps->pix_fmt; @@ -3182,6 +3246,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, !sps->vui.common.video_signal_type_present_flag) pix_fmt = sps_base->pix_fmt; + // Ignore range mismatch between base layer and alpha layer + if (ff_hevc_is_alpha_video(s) && + sps_base->pix_fmt == AV_PIX_FMT_YUV420P && + pix_fmt == AV_PIX_FMT_YUVJ420P) + pix_fmt = sps_base->pix_fmt; + if (pix_fmt != sps_base->pix_fmt || sps->width != sps_base->width || sps->height != sps_base->height) { @@ -3223,9 +3293,19 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, s->first_nal_type = s->nal_unit_type; s->poc = s->sh.poc; - if (IS_IRAP(s)) + if (IS_IRAP(s)) { s->no_rasl_output_flag = IS_IDR(s) || IS_BLA(s) || (s->nal_unit_type == HEVC_NAL_CRA_NUT && s->last_eos); + s->recovery_poc = HEVC_RECOVERY_END; + } + + if (s->recovery_poc != HEVC_RECOVERY_END && + s->sei.recovery_point.has_recovery_poc) { + if (s->recovery_poc == HEVC_RECOVERY_UNSPECIFIED) + s->recovery_poc = s->poc + s->sei.recovery_point.recovery_poc_cnt; + else if (s->poc >= s->recovery_poc) + s->recovery_poc = HEVC_RECOVERY_END; + } /* 8.3.1 */ if (s->temporal_id == 0 && @@ -3308,7 +3388,10 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, goto fail; if (s->avctx->hwaccel) { - ret = FF_HW_CALL(s->avctx, start_frame, NULL, 0); + AVCodecInternal *avci = s->avctx->internal; + AVPacket *avpkt = avci->in_pkt; + ret = FF_HW_CALL(s->avctx, start_frame, + avpkt->buf, NULL, 0); if (ret < 0) goto fail; } @@ -3329,7 +3412,6 @@ fail: ff_hevc_unref_frame(l->cur_frame, ~0); l->cur_frame = NULL; s->cur_frame = s->collocated_ref = NULL; - s->slice_initialized = 0; return ret; } @@ -3416,8 +3498,7 @@ static int hevc_frame_end(HEVCContext *s, HEVCLayerContext *l) av_assert0(0); return AVERROR_BUG; case AV_FILM_GRAIN_PARAMS_H274: - ret = ff_h274_apply_film_grain(out->frame_grain, out->f, - &s->h274db, fgp); + ret = ff_h274_apply_film_grain(out->frame_grain, out->f, fgp); break; case AV_FILM_GRAIN_PARAMS_AV1: ret = ff_aom_apply_film_grain(out->frame_grain, out->f, fgp); @@ -3463,9 +3544,11 @@ static int decode_slice(HEVCContext *s, unsigned nal_idx, GetBitContext *gb) return 0; ret = hls_slice_header(&s->sh, s, gb); + // Once hls_slice_header has been called, the context is inconsistent with the slice header + // until the context is reinitialized according to the contents of the new slice header + // at the start of decode_slice_data. + s->slice_initialized = 0; if (ret < 0) { - // hls_slice_header() does not cleanup on failure thus the state now is inconsistant so we cannot use it on depandant slices - s->slice_initialized = 0; return ret; } @@ -3583,10 +3666,11 @@ static int decode_nal_unit(HEVCContext *s, unsigned nal_idx) case HEVC_NAL_EOB_NUT: case HEVC_NAL_AUD: case HEVC_NAL_FD_NUT: - case HEVC_NAL_UNSPEC62: + case HEVC_NAL_UNSPEC62: // Dolby Vision RPU + case HEVC_NAL_UNSPEC63: // Dolby Vision EL break; default: - av_log(s->avctx, AV_LOG_INFO, + av_log(s->avctx, AV_LOG_VERBOSE, "Skipping NAL unit %d\n", s->nal_unit_type); } @@ -3601,6 +3685,12 @@ fail: return ret; } +static void decode_reset_recovery_point(HEVCContext *s) +{ + s->recovery_poc = HEVC_RECOVERY_UNSPECIFIED; + s->sei.recovery_point.has_recovery_poc = 0; +} + static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) { int i, ret = 0; @@ -3611,6 +3701,8 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) s->last_eos = s->eos; s->eos = 0; s->slice_initialized = 0; + if (s->last_eos) + decode_reset_recovery_point(s); for (int i = 0; i < FF_ARRAY_ELEMS(s->layers); i++) { HEVCLayerContext *l = &s->layers[i]; @@ -3632,6 +3724,7 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) s->pkt.nals[i].type == HEVC_NAL_EOS_NUT) { if (eos_at_start) { s->last_eos = 1; + decode_reset_recovery_point(s); } else { s->eos = 1; } @@ -3658,8 +3751,10 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) } s->rpu_buf = av_buffer_alloc(nal->raw_size - 2); - if (!s->rpu_buf) - return AVERROR(ENOMEM); + if (!s->rpu_buf) { + ret = AVERROR(ENOMEM); + goto fail; + } memcpy(s->rpu_buf->data, nal->raw_data + 2, nal->raw_size - 2); ret = ff_dovi_rpu_parse(&s->dovi_ctx, nal->data + 2, nal->size - 2, @@ -3748,7 +3843,7 @@ static int hevc_receive_frame(AVCodecContext *avctx, AVFrame *frame) s->pkt_dts = AV_NOPTS_VALUE; - if (ff_container_fifo_can_read(s->output_fifo)) + if (av_container_fifo_can_read(s->output_fifo)) goto do_output; av_packet_unref(avpkt); @@ -3786,7 +3881,7 @@ static int hevc_receive_frame(AVCodecContext *avctx, AVFrame *frame) return ret; do_output: - if (ff_container_fifo_read(s->output_fifo, frame) >= 0) { + if (av_container_fifo_read(s->output_fifo, frame, 0) >= 0) { if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN)) av_frame_remove_side_data(frame, AV_FRAME_DATA_FILM_GRAIN_PARAMS); @@ -3811,10 +3906,10 @@ static int hevc_ref_frame(HEVCFrame *dst, const HEVCFrame *src) dst->needs_fg = 1; } - dst->pps = ff_refstruct_ref_c(src->pps); - dst->tab_mvf = ff_refstruct_ref(src->tab_mvf); - dst->rpl_tab = ff_refstruct_ref(src->rpl_tab); - dst->rpl = ff_refstruct_ref(src->rpl); + dst->pps = av_refstruct_ref_c(src->pps); + dst->tab_mvf = av_refstruct_ref(src->tab_mvf); + dst->rpl_tab = av_refstruct_ref(src->rpl_tab); + dst->rpl = av_refstruct_ref(src->rpl); dst->nb_rpl_elems = src->nb_rpl_elems; dst->poc = src->poc; @@ -3823,7 +3918,7 @@ static int hevc_ref_frame(HEVCFrame *dst, const HEVCFrame *src) dst->base_layer_frame = src->base_layer_frame; - ff_refstruct_replace(&dst->hwaccel_picture_private, + av_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); return 0; @@ -3835,18 +3930,18 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx) for (int i = 0; i < FF_ARRAY_ELEMS(s->layers); i++) { pic_arrays_free(&s->layers[i]); - ff_refstruct_unref(&s->layers[i].sps); + av_refstruct_unref(&s->layers[i].sps); } - ff_refstruct_unref(&s->vps); - ff_refstruct_unref(&s->pps); + av_refstruct_unref(&s->vps); + av_refstruct_unref(&s->pps); ff_dovi_ctx_unref(&s->dovi_ctx); av_buffer_unref(&s->rpu_buf); av_freep(&s->md5_ctx); - ff_container_fifo_free(&s->output_fifo); + av_container_fifo_free(&s->output_fifo); for (int layer = 0; layer < FF_ARRAY_ELEMS(s->layers); layer++) { HEVCLayerContext *l = &s->layers[layer]; @@ -3890,7 +3985,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx) s->local_ctx[0].logctx = avctx; s->local_ctx[0].common_cabac_state = &s->cabac; - s->output_fifo = ff_container_fifo_alloc_avframe(0); + s->output_fifo = av_container_fifo_alloc_avframe(0); if (!s->output_fifo) return AVERROR(ENOMEM); @@ -3945,16 +4040,16 @@ static int hevc_update_thread_context(AVCodecContext *dst, } for (int i = 0; i < FF_ARRAY_ELEMS(s->ps.vps_list); i++) - ff_refstruct_replace(&s->ps.vps_list[i], s0->ps.vps_list[i]); + av_refstruct_replace(&s->ps.vps_list[i], s0->ps.vps_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(s->ps.sps_list); i++) - ff_refstruct_replace(&s->ps.sps_list[i], s0->ps.sps_list[i]); + av_refstruct_replace(&s->ps.sps_list[i], s0->ps.sps_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(s->ps.pps_list); i++) - ff_refstruct_replace(&s->ps.pps_list[i], s0->ps.pps_list[i]); + av_refstruct_replace(&s->ps.pps_list[i], s0->ps.pps_list[i]); // PPS do not persist between frames - ff_refstruct_unref(&s->pps); + av_refstruct_unref(&s->pps); s->poc_tid0 = s0->poc_tid0; s->eos = s0->eos; @@ -4003,14 +4098,63 @@ static int hevc_update_thread_context(AVCodecContext *dst, s->sei.common.frame_packing = s0->sei.common.frame_packing; s->sei.common.display_orientation = s0->sei.common.display_orientation; s->sei.common.alternative_transfer = s0->sei.common.alternative_transfer; - s->sei.common.mastering_display = s0->sei.common.mastering_display; - s->sei.common.content_light = s0->sei.common.content_light; s->sei.tdrdi = s0->sei.tdrdi; + s->sei.recovery_point = s0->sei.recovery_point; + s->recovery_poc = s0->recovery_poc; return 0; } #endif +static int hevc_sei_to_context(AVCodecContext *avctx, HEVCSEI *sei) +{ + int ret; + + if (sei->tdrdi.present) { + AVBufferRef *buf; + size_t size; + AV3DReferenceDisplaysInfo *tdrdi = av_tdrdi_alloc(sei->tdrdi.num_ref_displays, &size); + + if (!tdrdi) + return AVERROR(ENOMEM); + + buf = av_buffer_create((uint8_t *)tdrdi, size, NULL, NULL, 0); + if (!buf) { + av_free(tdrdi); + return AVERROR(ENOMEM); + } + + tdrdi->prec_ref_display_width = sei->tdrdi.prec_ref_display_width; + tdrdi->ref_viewing_distance_flag = sei->tdrdi.ref_viewing_distance_flag; + tdrdi->prec_ref_viewing_dist = sei->tdrdi.prec_ref_viewing_dist; + tdrdi->num_ref_displays = sei->tdrdi.num_ref_displays; + for (int i = 0; i < sei->tdrdi.num_ref_displays; i++) { + AV3DReferenceDisplay *display = av_tdrdi_get_display(tdrdi, i); + + display->left_view_id = sei->tdrdi.left_view_id[i]; + display->right_view_id = sei->tdrdi.right_view_id[i]; + display->exponent_ref_display_width = sei->tdrdi.exponent_ref_display_width[i]; + display->mantissa_ref_display_width = sei->tdrdi.mantissa_ref_display_width[i]; + display->exponent_ref_viewing_distance = sei->tdrdi.exponent_ref_viewing_distance[i]; + display->mantissa_ref_viewing_distance = sei->tdrdi.mantissa_ref_viewing_distance[i]; + display->additional_shift_present_flag = sei->tdrdi.additional_shift_present_flag[i]; + display->num_sample_shift = sei->tdrdi.num_sample_shift[i]; + } + ret = ff_frame_new_side_data_from_buf_ext(avctx, &avctx->decoded_side_data, &avctx->nb_decoded_side_data, + AV_FRAME_DATA_3D_REFERENCE_DISPLAYS, &buf); + if (ret < 0) { + av_buffer_unref(&buf); + return ret; + } + } + + ret = ff_h2645_sei_to_context(avctx, &sei->common); + if (ret < 0) + return ret; + + return 0; +} + static av_cold int hevc_decode_init(AVCodecContext *avctx) { HEVCContext *s = avctx->priv_data; @@ -4034,7 +4178,7 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx) return ret; } - ret = ff_h2645_sei_to_context(avctx, &s->sei.common); + ret = hevc_sei_to_context(avctx, &s->sei); if (ret < 0) return ret; } @@ -4047,7 +4191,7 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx) return 0; } -static void hevc_decode_flush(AVCodecContext *avctx) +static av_cold void hevc_decode_flush(AVCodecContext *avctx) { HEVCContext *s = avctx->priv_data; ff_hevc_flush_dpb(s); @@ -4066,7 +4210,7 @@ static void hevc_decode_flush(AVCodecContext *avctx) static const AVOption options[] = { { "apply_defdispwin", "Apply default display window from VUI", OFFSET(apply_defdispwin), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, PAR }, - { "strict-displaywin", "stricly apply default display window size", OFFSET(apply_defdispwin), + { "strict-displaywin", "strictly apply default display window size", OFFSET(apply_defdispwin), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, PAR }, { "view_ids", "Array of view IDs that should be decoded and output; a single -1 to decode all views", .offset = OFFSET(view_ids), .type = AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h index 473709b4e..8394740c4 100644 --- a/libavcodec/hevc/hevcdec.h +++ b/libavcodec/hevc/hevcdec.h @@ -32,9 +32,7 @@ #include "libavcodec/bswapdsp.h" #include "libavcodec/cabac.h" #include "libavcodec/dovi_rpu.h" -#include "libavcodec/get_bits.h" #include "libavcodec/h2645_parse.h" -#include "libavcodec/h274.h" #include "libavcodec/progressframe.h" #include "libavcodec/videodsp.h" @@ -78,6 +76,10 @@ (s)->nal_unit_type == HEVC_NAL_BLA_N_LP) #define IS_IRAP(s) ((s)->nal_unit_type >= HEVC_NAL_BLA_W_LP && (s)->nal_unit_type <= HEVC_NAL_RSV_IRAP_VCL23) +#define HEVC_RECOVERY_UNSPECIFIED INT_MAX +#define HEVC_RECOVERY_END INT_MIN +#define HEVC_IS_RECOVERING(s) ((s)->recovery_poc != HEVC_RECOVERY_UNSPECIFIED && (s)->recovery_poc != HEVC_RECOVERY_END) + enum RPSType { ST_CURR_BEF = 0, ST_CURR_AFT, @@ -203,9 +205,9 @@ typedef struct RefPicListTab { typedef struct SliceHeader { unsigned int pps_id; - ///< address (in raster order) of the first block in the current slice segment + /// 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 + /// address (in raster order) of the first block in the current slice unsigned int slice_addr; enum HEVCSliceType slice_type; @@ -219,7 +221,7 @@ typedef struct SliceHeader { uint8_t colour_plane_id; uint8_t inter_layer_pred; - ///< RPS coded in the slice header itself is stored here + /// RPS coded in the slice header itself is stored here int short_term_ref_pic_set_sps_flag; int short_term_ref_pic_set_size; ShortTermRPS slice_rps; @@ -353,6 +355,7 @@ typedef struct DBParams { #define HEVC_FRAME_FLAG_SHORT_REF (1 << 1) #define HEVC_FRAME_FLAG_LONG_REF (1 << 2) #define HEVC_FRAME_FLAG_UNAVAILABLE (1 << 3) +#define HEVC_FRAME_FLAG_CORRUPT (1 << 4) typedef struct HEVCFrame { union { @@ -480,8 +483,8 @@ typedef struct HEVCLayerContext { uint8_t *sao_pixel_buffer_h[3]; uint8_t *sao_pixel_buffer_v[3]; - struct FFRefStructPool *tab_mvf_pool; - struct FFRefStructPool *rpl_tab_pool; + struct AVRefStructPool *tab_mvf_pool; + struct AVRefStructPool *rpl_tab_pool; } HEVCLayerContext; typedef struct HEVCContext { @@ -502,13 +505,13 @@ typedef struct HEVCContext { /** 1 if the independent slice segment header was successfully parsed */ uint8_t slice_initialized; - struct ContainerFifo *output_fifo; + struct AVContainerFifo *output_fifo; HEVCParamSets ps; HEVCSEI sei; struct AVMD5 *md5_ctx; - ///< candidate references for the current frame + /// candidate references for the current frame RefPicList rps[NB_RPS_TYPE]; const HEVCVPS *vps; ///< RefStruct reference @@ -523,6 +526,7 @@ typedef struct HEVCContext { 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 recovery_poc; // NoRaslOutputFlag associated with the last IRAP frame int no_rasl_output_flag; @@ -531,7 +535,6 @@ typedef struct HEVCContext { HEVCDSPContext hevcdsp; VideoDSPContext vdsp; BswapDSPContext bdsp; - H274FilmGrainDatabase h274db; /** used on BE to byteswap the lines for checksumming */ uint8_t *checksum_buf; @@ -714,6 +717,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps, void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size); +int ff_hevc_is_alpha_video(const HEVCContext *s); + 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]; diff --git a/libavcodec/hevc/parser.c b/libavcodec/hevc/parser.c index 16b40e2b1..62bcd9117 100644 --- a/libavcodec/hevc/parser.c +++ b/libavcodec/hevc/parser.c @@ -25,6 +25,7 @@ #include "golomb.h" #include "hevc.h" +#include "parser_internal.h" #include "parse.h" #include "ps.h" #include "sei.h" @@ -352,9 +353,9 @@ static void hevc_parser_close(AVCodecParserContext *s) av_freep(&ctx->pc.buffer); } -const AVCodecParser ff_hevc_parser = { - .codec_ids = { AV_CODEC_ID_HEVC }, +const FFCodecParser ff_hevc_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_HEVC), .priv_data_size = sizeof(HEVCParserContext), - .parser_parse = hevc_parse, - .parser_close = hevc_parser_close, + .parse = hevc_parse, + .close = hevc_parser_close, }; diff --git a/libavcodec/hevc/ps.c b/libavcodec/hevc/ps.c index 87d922579..c67aab151 100644 --- a/libavcodec/hevc/ps.c +++ b/libavcodec/hevc/ps.c @@ -30,7 +30,7 @@ #include "data.h" #include "ps.h" #include "profiles.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" static const uint8_t default_scaling_list_intra[] = { 16, 16, 16, 16, 17, 18, 21, 24, @@ -69,9 +69,9 @@ static void remove_sps(HEVCParamSets *s, int id) /* drop all PPS that depend on this SPS */ for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++) if (s->pps_list[i] && s->pps_list[i]->sps_id == id) - ff_refstruct_unref(&s->pps_list[i]); + av_refstruct_unref(&s->pps_list[i]); - ff_refstruct_unref(&s->sps_list[id]); + av_refstruct_unref(&s->sps_list[id]); } } @@ -82,7 +82,7 @@ static void remove_vps(HEVCParamSets *s, int id) for (i = 0; i < FF_ARRAY_ELEMS(s->sps_list); i++) if (s->sps_list[i] && s->sps_list[i]->vps_id == id) remove_sps(s, i); - ff_refstruct_unref(&s->vps_list[id]); + av_refstruct_unref(&s->vps_list[id]); } } @@ -238,7 +238,6 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, static int decode_profile_tier_level(GetBitContext *gb, AVCodecContext *avctx, PTLCommon *ptl) { - const char *profile_name = NULL; int i; if (get_bits_left(gb) < 2+1+5 + 32 + 4 + 43 + 1) @@ -249,14 +248,15 @@ static int decode_profile_tier_level(GetBitContext *gb, AVCodecContext *avctx, ptl->profile_idc = get_bits(gb, 5); #if !CONFIG_SMALL + const char *profile_name = NULL; for (int i = 0; ff_hevc_profiles[i].profile != AV_PROFILE_UNKNOWN; i++) if (ff_hevc_profiles[i].profile == ptl->profile_idc) { profile_name = ff_hevc_profiles[i].name; break; } -#endif av_log(avctx, profile_name ? AV_LOG_DEBUG : AV_LOG_WARNING, "%s profile bitstream\n", profile_name ? profile_name : "Unknown"); +#endif for (i = 0; i < 32; i++) { ptl->profile_compatibility_flag[i] = get_bits1(gb); @@ -442,7 +442,7 @@ static int decode_hrd(GetBitContext *gb, int common_inf_present, return 0; } -static void hevc_vps_free(FFRefStructOpaque opaque, void *obj) +static void hevc_vps_free(AVRefStructOpaque opaque, void *obj) { HEVCVPS *vps = obj; @@ -450,14 +450,6 @@ static void hevc_vps_free(FFRefStructOpaque opaque, void *obj) av_freep(&vps->data); } -enum ScalabilityMask { - HEVC_SCALABILITY_DEPTH = 0, - HEVC_SCALABILITY_MULTIVIEW = 1, - HEVC_SCALABILITY_SPATIAL = 2, - HEVC_SCALABILITY_AUXILIARY = 3, - HEVC_SCALABILITY_MASK_MAX = 15, -}; - enum DependencyType { HEVC_DEP_TYPE_SAMPLE = 0, HEVC_DEP_TYPE_MV = 1, @@ -468,14 +460,17 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps uint64_t layer1_id_included) { PTL ptl_dummy; - uint8_t max_sub_layers[HEVC_MAX_LAYERS]; + uint8_t max_sub_layers[HEVC_MAX_LAYERS] = {1, 1}; + uint8_t dimension_id_len[16] = {0}; + uint8_t dimension_id[16] = {0}; + unsigned n; - int splitting_flag, dimension_id_len, view_id_len, num_add_olss, + int splitting_flag, view_id_len, num_add_olss, num_scalability_types, default_output_layer_idc, direct_dep_type_len, direct_dep_type, sub_layers_max_present, sub_layer_flag_info_present_flag, nb_ptl; unsigned non_vui_extension_length; - if (vps->vps_max_layers == 1 || vps->vps_num_layer_sets == 1) { + if (vps->vps_max_layers == 1) { av_log(avctx, AV_LOG_VERBOSE, "Ignoring VPS extensions with a single layer\n"); return 0; } @@ -528,20 +523,35 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps */ vps->nb_layers = 2; + /* vps_base_layer_internal_flag is true has been checked before */ if (parse_ptl(gb, avctx, 0, &ptl_dummy, vps->vps_max_sub_layers) < 0) return AVERROR_INVALIDDATA; splitting_flag = get_bits1(gb); - for (int i = 0; i <= HEVC_SCALABILITY_MASK_MAX; i++) { - int scalability_mask_flag = get_bits1(gb); - if (scalability_mask_flag != (i == HEVC_SCALABILITY_MULTIVIEW)) { - av_log(avctx, AV_LOG_ERROR, "Scalability type %d not supported\n", i); - return AVERROR_PATCHWELCOME; - } + vps->scalability_mask_flag = get_bits(gb, 16); + num_scalability_types = av_popcount(vps->scalability_mask_flag); + if (!num_scalability_types) { + av_log(avctx, AV_LOG_ERROR, "Missing scalability mask\n"); + return AVERROR_INVALIDDATA; } - if (!splitting_flag) - dimension_id_len = get_bits(gb, 3) + 1; + if (!(vps->scalability_mask_flag & + (HEVC_SCALABILITY_MULTIVIEW | HEVC_SCALABILITY_AUXILIARY))) { + av_log(avctx, AV_LOG_ERROR, "Scalability type %d not supported\n", + 15 - ff_ctz(vps->scalability_mask_flag)); + return AVERROR_PATCHWELCOME; + } + // x265 specify MULTIVIEW when the stream really is alpha video only. + if (num_scalability_types > 1) + av_log(avctx, AV_LOG_WARNING, "Multiple scalability types presented\n"); + + n = 0; + for (int i = 0; i < num_scalability_types - splitting_flag; i++) { + dimension_id_len[i] = get_bits(gb, 3) + 1; + n += dimension_id_len[i]; + } + if (splitting_flag) + dimension_id_len[num_scalability_types - 1] = 5 - n; if (get_bits1(gb)) { /* vps_nuh_layer_id_present_flag */ int layer_id_in_nuh = get_bits(gb, 6); @@ -558,28 +568,57 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps } if (!splitting_flag) { - int view_idx = get_bits(gb, dimension_id_len); - if (view_idx != 1) { - av_log(avctx, AV_LOG_ERROR, "Unexpected ViewOrderIdx: %d\n", view_idx); + int index = 0; + + for (int i = 0; i < num_scalability_types; i++) + dimension_id[i] = get_bits(gb, dimension_id_len[i]); + + if (vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW) + index++; + + /* AuxId 1 is alpha, 2 is depth. Only support alpha */ + if (vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY && + dimension_id[index] != HEVC_AUX_ALPHA) { + av_log(avctx, AV_LOG_WARNING, + "Unsupported dimension_id %d for HEVC_SCALABILITY_AUXILIARY\n", + dimension_id[index]); return AVERROR_PATCHWELCOME; } } view_id_len = get_bits(gb, 4); - if (view_id_len) - for (int i = 0; i < 2 /* NumViews */; i++) + if (view_id_len) { + n = (vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW) ? 2 : 1; + for (int i = 0; i < n; i++) vps->view_id[i] = get_bits(gb, view_id_len); - - if (!get_bits1(gb) /* direct_dependency_flag */) { - av_log(avctx, AV_LOG_WARNING, "Independent output layers not supported\n"); - return AVERROR_PATCHWELCOME; } - vps->num_direct_ref_layers[1] = 1; + + /* direct_dependency_flag */ + vps->num_direct_ref_layers[1] = get_bits1(gb); + if (!vps->num_direct_ref_layers[1]) { + vps->num_add_layer_sets = get_ue_golomb(gb); + if (vps->num_add_layer_sets > 1) { + av_log(avctx, AV_LOG_WARNING, + "Unsupported num_add_layer_sets: %d\n", vps->num_add_layer_sets); + return AVERROR_PATCHWELCOME; + } + + if (vps->num_add_layer_sets) { + /* highest_layer_idx_plus1 */ + if (!get_bits1(gb)) + return AVERROR_PATCHWELCOME; + } + } + vps->num_output_layer_sets = vps->vps_num_layer_sets + vps->num_add_layer_sets; + if (vps->num_output_layer_sets != 2) + return AVERROR_INVALIDDATA; sub_layers_max_present = get_bits1(gb); // vps_sub_layers_max_minus1_present_flag - for (int i = 0; i < vps->vps_max_layers; i++) - max_sub_layers[i] = sub_layers_max_present ? get_bits(gb, 3) + 1 : - vps->vps_max_sub_layers; + if (sub_layers_max_present) { + for (int i = 0; i < vps->vps_max_layers; i++) + max_sub_layers[i] = sub_layers_max_present ? get_bits(gb, 3) + 1 : + vps->vps_max_sub_layers; + } if (get_bits1(gb) /* max_tid_ref_present_flag */) skip_bits(gb, 3); // max_tid_il_ref_pics_plus1 @@ -612,18 +651,25 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps } /* Consequence of established layer dependencies */ - if (layer1_id_included != ((1ULL << vps->layer_id_in_nuh[0]) | + if (layer1_id_included && + layer1_id_included != ((1ULL << vps->layer_id_in_nuh[0]) | (1ULL << vps->layer_id_in_nuh[1]))) { - av_log(avctx, AV_LOG_ERROR, "Dependent layer not included in layer ID?\n"); - return AVERROR_PATCHWELCOME; + av_log(avctx, AV_LOG_ERROR, + "Dependent layer not included in layer ID?\n"); + return AVERROR_PATCHWELCOME; } + if (!layer1_id_included) + vps->ols[1] = 2; + else + vps->ols[1] = 3; - vps->num_output_layer_sets = 2; - vps->ols[1] = 3; + if (vps->vps_num_layer_sets == 1 || default_output_layer_idc == 2) + skip_bits1(gb); + if (nb_ptl > 1) for (int j = 0; j < av_popcount64(vps->ols[1]); j++) { int ptl_idx = get_bits(gb, av_ceil_log2(nb_ptl)); - if (ptl_idx < 1 || ptl_idx >= nb_ptl) { + if (ptl_idx >= nb_ptl) { av_log(avctx, AV_LOG_ERROR, "Invalid PTL index: %d\n", ptl_idx); return AVERROR_INVALIDDATA; } @@ -666,6 +712,8 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps vps->max_one_active_ref_layer = get_bits1(gb); vps->poc_lsb_aligned = get_bits1(gb); + if (!vps->num_direct_ref_layers[1]) + vps->poc_lsb_not_present = get_bits1(gb) << 1; sub_layer_flag_info_present_flag = get_bits1(gb); for (int j = 0; j < FFMAX(max_sub_layers[0], max_sub_layers[1]); j++) { @@ -687,12 +735,14 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps return AVERROR_INVALIDDATA; } - skip_bits1(gb); /* direct_depenency_all_layers_flag */ - direct_dep_type = get_bits_long(gb, direct_dep_type_len); - if (direct_dep_type > HEVC_DEP_TYPE_BOTH) { - av_log(avctx, AV_LOG_WARNING, "Unsupported direct_dep_type: %d\n", - direct_dep_type); - return AVERROR_PATCHWELCOME; + /* direct_depenency_all_layers_flag */ + if (get_bits1(gb)) { + direct_dep_type = get_bits_long(gb, direct_dep_type_len); + if (direct_dep_type > HEVC_DEP_TYPE_BOTH) { + av_log(avctx, AV_LOG_WARNING, "Unsupported direct_dep_type: %d\n", + direct_dep_type); + return AVERROR_PATCHWELCOME; + } } non_vui_extension_length = get_ue_golomb(gb); @@ -714,9 +764,10 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, { int i; int vps_id = get_bits(gb, 4); - ptrdiff_t nal_size = gb->buffer_end - gb->buffer; + ptrdiff_t nal_size = get_bits_bytesize(gb, 1); int ret = AVERROR_INVALIDDATA; uint64_t layer1_id_included = 0; + unsigned vps_base_layer_internal_flag, vps_base_layer_available_flag; HEVCVPS *vps; if (ps->vps_list[vps_id]) { @@ -726,7 +777,7 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, return 0; } - vps = ff_refstruct_alloc_ext(sizeof(*vps), 0, NULL, hevc_vps_free); + vps = av_refstruct_alloc_ext(sizeof(*vps), 0, NULL, hevc_vps_free); if (!vps) return AVERROR(ENOMEM); @@ -740,8 +791,12 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, } vps->vps_id = vps_id; - if (get_bits(gb, 2) != 3) { // vps_reserved_three_2bits - av_log(avctx, AV_LOG_ERROR, "vps_reserved_three_2bits is not three\n"); + vps_base_layer_internal_flag = get_bits1(gb); + vps_base_layer_available_flag = get_bits1(gb); + if (!vps_base_layer_internal_flag || !vps_base_layer_available_flag) { + av_log(avctx, AV_LOG_ERROR, + "vps_base_layer_internal_flag or vps_base_layer_available_flag not set\n"); + ret = AVERROR_PATCHWELCOME; goto err; } @@ -860,7 +915,7 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, return 0; err: - ff_refstruct_unref(&vps); + av_refstruct_unref(&vps); return ret; } @@ -1154,6 +1209,7 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, HEVCWindow *ow; int ret = 0; int bit_depth_chroma, num_comps, multi_layer_ext; + int vps_max_sub_layers; int i; // Coded parameters @@ -1166,7 +1222,7 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->vps_id); return AVERROR_INVALIDDATA; } - sps->vps = ff_refstruct_ref_c(vps_list[sps->vps_id]); + sps->vps = av_refstruct_ref_c(vps_list[sps->vps_id]); } sps->max_sub_layers = get_bits(gb, 3) + 1; @@ -1178,7 +1234,10 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->max_sub_layers = sps->vps->vps_max_sub_layers; } - if (sps->max_sub_layers > HEVC_MAX_SUB_LAYERS) { + vps_max_sub_layers = sps->vps ? sps->vps->vps_max_sub_layers + : FFMIN(sps->max_sub_layers, HEVC_MAX_SUB_LAYERS); + + if (sps->max_sub_layers > vps_max_sub_layers) { av_log(avctx, AV_LOG_ERROR, "sps_max_sub_layers out of range: %d\n", sps->max_sub_layers); return AVERROR_INVALIDDATA; @@ -1203,6 +1262,12 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, if (multi_layer_ext) { const RepFormat *rf = &sps->vps->rep_format; + if (sps->vps->nb_layers == 1) { + av_log(avctx, AV_LOG_WARNING, "SPS %d references an unsupported VPS extension. Ignoring\n", + *sps_id); + return AVERROR(ENOSYS); + } + if (get_bits1(gb) && // update_rep_format_flag get_bits(gb, 8)) { // sps_rep_format_idx av_log(avctx, AV_LOG_ERROR, "sps_rep_format_idx!=0\n"); @@ -1621,11 +1686,11 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, return 0; } -static void hevc_sps_free(FFRefStructOpaque opaque, void *obj) +static void hevc_sps_free(AVRefStructOpaque opaque, void *obj) { HEVCSPS *sps = obj; - ff_refstruct_unref(&sps->vps); + av_refstruct_unref(&sps->vps); av_freep(&sps->data); } @@ -1640,7 +1705,7 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, HEVCParamSets *ps, unsigned nuh_layer_id, int apply_defdispwin) { - HEVCSPS *sps = ff_refstruct_alloc_ext(sizeof(*sps), 0, NULL, hevc_sps_free); + HEVCSPS *sps = av_refstruct_alloc_ext(sizeof(*sps), 0, NULL, hevc_sps_free); unsigned int sps_id; int ret; @@ -1649,7 +1714,7 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, av_log(avctx, AV_LOG_DEBUG, "Decoding SPS\n"); - sps->data_size = gb->buffer_end - gb->buffer; + sps->data_size = get_bits_bytesize(gb, 1); sps->data = av_memdup(gb->buffer, sps->data_size); if (!sps->data) { ret = AVERROR(ENOMEM); @@ -1677,7 +1742,7 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, * otherwise drop all PPSes that depend on it */ if (ps->sps_list[sps_id] && compare_sps(ps->sps_list[sps_id], sps)) { - ff_refstruct_unref(&sps); + av_refstruct_unref(&sps); } else { remove_sps(ps, sps_id); ps->sps_list[sps_id] = sps; @@ -1685,15 +1750,15 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, return 0; err: - ff_refstruct_unref(&sps); + av_refstruct_unref(&sps); return ret; } -static void hevc_pps_free(FFRefStructOpaque unused, void *obj) +static void hevc_pps_free(AVRefStructOpaque unused, void *obj) { HEVCPPS *pps = obj; - ff_refstruct_unref(&pps->sps); + av_refstruct_unref(&pps->sps); av_freep(&pps->column_width); av_freep(&pps->row_height); @@ -2108,7 +2173,7 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, const HEVCSPS *sps = NULL; const HEVCVPS *vps = NULL; int i, ret = 0; - ptrdiff_t nal_size = gb->buffer_end - gb->buffer; + ptrdiff_t nal_size = get_bits_bytesize(gb, 1); unsigned int pps_id = get_ue_golomb_long(gb); unsigned log2_parallel_merge_level_minus2; HEVCPPS *pps; @@ -2127,7 +2192,7 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, return 0; } - pps = ff_refstruct_alloc_ext(sizeof(*pps), 0, NULL, hevc_pps_free); + pps = av_refstruct_alloc_ext(sizeof(*pps), 0, NULL, hevc_pps_free); if (!pps) return AVERROR(ENOMEM); @@ -2164,7 +2229,7 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, sps = ps->sps_list[pps->sps_id]; vps = ps->vps_list[sps->vps_id]; - pps->sps = ff_refstruct_ref_c(sps); + pps->sps = av_refstruct_ref_c(sps); pps->dependent_slice_segments_enabled_flag = get_bits1(gb); pps->output_flag_present_flag = get_bits1(gb); @@ -2364,13 +2429,13 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, "Overread PPS by %d bits\n", -get_bits_left(gb)); } - ff_refstruct_unref(&ps->pps_list[pps_id]); + av_refstruct_unref(&ps->pps_list[pps_id]); ps->pps_list[pps_id] = pps; return 0; err: - ff_refstruct_unref(&pps); + av_refstruct_unref(&pps); return ret; } @@ -2379,16 +2444,16 @@ void ff_hevc_ps_uninit(HEVCParamSets *ps) int i; for (i = 0; i < FF_ARRAY_ELEMS(ps->vps_list); i++) - ff_refstruct_unref(&ps->vps_list[i]); + av_refstruct_unref(&ps->vps_list[i]); for (i = 0; i < FF_ARRAY_ELEMS(ps->sps_list); i++) - ff_refstruct_unref(&ps->sps_list[i]); + av_refstruct_unref(&ps->sps_list[i]); for (i = 0; i < FF_ARRAY_ELEMS(ps->pps_list); i++) - ff_refstruct_unref(&ps->pps_list[i]); + av_refstruct_unref(&ps->pps_list[i]); } -int ff_hevc_compute_poc(const HEVCSPS *sps, int pocTid0, int poc_lsb, int nal_unit_type) +int ff_hevc_compute_poc2(unsigned log2_max_poc_lsb, int pocTid0, int poc_lsb, int nal_unit_type) { - int max_poc_lsb = 1 << sps->log2_max_poc_lsb; + int max_poc_lsb = 1 << log2_max_poc_lsb; int prev_poc_lsb = pocTid0 % max_poc_lsb; int prev_poc_msb = pocTid0 - prev_poc_lsb; int poc_msb; diff --git a/libavcodec/hevc/ps.h b/libavcodec/hevc/ps.h index 6f5b1f875..d620887b8 100644 --- a/libavcodec/hevc/ps.h +++ b/libavcodec/hevc/ps.h @@ -205,6 +205,8 @@ typedef struct HEVCVPS { */ int nb_layers; + uint16_t scalability_mask_flag; + // LayerIdxInVps[nuh_layer_id], i.e. a mapping of nuh_layer_id to VPS layer // indices. Valid values are between 0 and HEVC_VPS_MAX_LAYERS. Entries for // unmapped values of nuh_layer_id are set to -1. @@ -235,6 +237,7 @@ typedef struct HEVCVPS { // NumDirectRefLayers[layer_idx] uint8_t num_direct_ref_layers[HEVC_VPS_MAX_LAYERS]; + uint8_t num_add_layer_sets; RepFormat rep_format; @@ -343,7 +346,7 @@ typedef struct HEVCSPS { int sps_palette_predictor_initializer[3][HEVC_MAX_PALETTE_PREDICTOR_SIZE]; int motion_vector_resolution_control_idc; - ///< coded frame dimension in various units + /// coded frame dimension in various units int width; int height; int ctb_width; @@ -543,6 +546,11 @@ int ff_hevc_encode_nal_vps(HEVCVPS *vps, unsigned int id, /** * Compute POC of the current frame and return it. */ -int ff_hevc_compute_poc(const HEVCSPS *sps, int pocTid0, int poc_lsb, int nal_unit_type); +int ff_hevc_compute_poc2(unsigned log2_max_poc_lsb, int pocTid0, int poc_lsb, int nal_unit_type); + +static inline int ff_hevc_compute_poc(const HEVCSPS *sps, int pocTid0, int poc_lsb, int nal_unit_type) +{ + return ff_hevc_compute_poc2(sps->log2_max_poc_lsb, pocTid0, poc_lsb, nal_unit_type); +} #endif /* AVCODEC_HEVC_PS_H */ diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c index 19bd8886d..1faede4e3 100644 --- a/libavcodec/hevc/refs.c +++ b/libavcodec/hevc/refs.c @@ -21,33 +21,36 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/container_fifo.h" #include "libavutil/mem.h" #include "libavutil/stereo3d.h" -#include "container_fifo.h" #include "decode.h" #include "hevc.h" #include "hevcdec.h" #include "progressframe.h" -#include "refstruct.h" +#include "thread.h" +#include "libavutil/refstruct.h" void ff_hevc_unref_frame(HEVCFrame *frame, int flags) { frame->flags &= ~flags; + if (!(frame->flags & ~HEVC_FRAME_FLAG_CORRUPT)) + frame->flags = 0; if (!frame->flags) { ff_progress_frame_unref(&frame->tf); av_frame_unref(frame->frame_grain); frame->needs_fg = 0; - ff_refstruct_unref(&frame->pps); - ff_refstruct_unref(&frame->tab_mvf); + av_refstruct_unref(&frame->pps); + av_refstruct_unref(&frame->tab_mvf); - ff_refstruct_unref(&frame->rpl); + av_refstruct_unref(&frame->rpl); frame->nb_rpl_elems = 0; - ff_refstruct_unref(&frame->rpl_tab); + av_refstruct_unref(&frame->rpl_tab); frame->refPicList = NULL; - ff_refstruct_unref(&frame->hwaccel_picture_private); + av_refstruct_unref(&frame->hwaccel_picture_private); } } @@ -79,6 +82,31 @@ void ff_hevc_flush_dpb(HEVCContext *s) } } +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base) +{ + AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3); + uintptr_t data = (uintptr_t)alpha->data[0]; + int ret; + + for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) { + AVBufferRef *buf = alpha->buf[i]; + uintptr_t buf_begin = (uintptr_t)buf->data; + + if (data >= buf_begin && data < buf_begin + buf->size) { + ret = av_buffer_replace(&alpha->buf[i], base_a); + if (ret < 0) + return ret; + + alpha->linesize[0] = base->linesize[3]; + alpha->data[0] = base->data[3]; + + return 0; + } + } + + return AVERROR_BUG; +} + static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l) { const HEVCVPS *vps = l->sps->vps; @@ -103,7 +131,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l) } // add view ID side data if it's nontrivial - if (vps->nb_layers > 1 || view_id) { + if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) { HEVCSEITDRDI *tdrdi = &s->sei.tdrdi; AVFrameSideData *sd = av_frame_side_data_new(&frame->f->side_data, &frame->f->nb_side_data, @@ -130,24 +158,23 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l) } } - ret = ff_progress_frame_get_buffer(s->avctx, &frame->tf, - AV_GET_BUFFER_FLAG_REF); + ret = ff_thread_get_buffer(s->avctx, frame->f, AV_GET_BUFFER_FLAG_REF); if (ret < 0) - return NULL; + goto fail; size_t rpl_bytes; if (av_size_mult(s->pkt.nb_nals, sizeof(*frame->rpl), &rpl_bytes) < 0) goto fail; - frame->rpl = ff_refstruct_allocz(rpl_bytes); + frame->rpl = av_refstruct_allocz(rpl_bytes); if (!frame->rpl) goto fail; frame->nb_rpl_elems = s->pkt.nb_nals; - frame->tab_mvf = ff_refstruct_pool_get(l->tab_mvf_pool); + frame->tab_mvf = av_refstruct_pool_get(l->tab_mvf_pool); if (!frame->tab_mvf) goto fail; - frame->rpl_tab = ff_refstruct_pool_get(l->rpl_tab_pool); + frame->rpl_tab = av_refstruct_pool_get(l->rpl_tab_pool); if (!frame->rpl_tab) goto fail; frame->ctb_count = l->sps->ctb_width * l->sps->ctb_height; @@ -164,7 +191,14 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l) if (ret < 0) goto fail; - frame->pps = ff_refstruct_ref_c(s->pps); + frame->pps = av_refstruct_ref_c(s->pps); + if (l != &s->layers[0] && ff_hevc_is_alpha_video(s)) { + AVFrame *alpha = frame->f; + AVFrame *base = s->layers[0].cur_frame->f; + ret = replace_alpha_plane(alpha, base); + if (ret < 0) + goto fail; + } return frame; fail: @@ -179,6 +213,7 @@ int ff_hevc_set_new_ref(HEVCContext *s, HEVCLayerContext *l, int poc) { HEVCFrame *ref; int i; + int no_output; /* check that this POC doesn't already exist */ for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { @@ -202,7 +237,11 @@ int ff_hevc_set_new_ref(HEVCContext *s, HEVCLayerContext *l, int poc) ref->base_layer_frame = (l != &s->layers[0] && s->layers[0].cur_frame) ? s->layers[0].cur_frame - s->layers[0].DPB : -1; - if (s->sh.pic_output_flag) + no_output = !IS_IRAP(s) && (s->poc < s->recovery_poc) && + HEVC_IS_RECOVERING(s) && + !(s->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) && + !(s->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL); + if (s->sh.pic_output_flag && !no_output) ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF; else ref->flags = HEVC_FRAME_FLAG_SHORT_REF; @@ -269,8 +308,10 @@ int ff_hevc_output_frames(HEVCContext *s, int output = !discard && (layers_active_output & (1 << min_layer)); if (output) { + if (frame->flags & HEVC_FRAME_FLAG_CORRUPT) + f->flags |= AV_FRAME_FLAG_CORRUPT; f->pkt_dts = s->pkt_dts; - ret = ff_container_fifo_write(s->output_fifo, f); + ret = av_container_fifo_write(s->output_fifo, f, AV_CONTAINER_FIFO_FLAG_REF); } ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT); if (ret < 0) @@ -465,6 +506,20 @@ static int add_candidate_ref(HEVCContext *s, HEVCLayerContext *l, if (ref == s->cur_frame || list->nb_refs >= HEVC_MAX_REFS) return AVERROR_INVALIDDATA; + if (!IS_IRAP(s)) { + int ref_corrupt = !ref || ref->flags & (HEVC_FRAME_FLAG_CORRUPT | + HEVC_FRAME_FLAG_UNAVAILABLE); + int recovering = HEVC_IS_RECOVERING(s); + + if (ref_corrupt && !recovering) { + if (!(s->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) && + !(s->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL)) + return AVERROR_INVALIDDATA; + + s->cur_frame->flags |= HEVC_FRAME_FLAG_CORRUPT; + } + } + if (!ref) { ref = generate_missing_ref(s, l, poc); if (!ref) @@ -574,10 +629,8 @@ int ff_hevc_frame_nb_refs(const SliceHeader *sh, const HEVCPPS *pps, ret += !!(rps->used & (1 << i)); } - if (long_rps) { - for (i = 0; i < long_rps->nb_refs; i++) - ret += !!long_rps->used[i]; - } + for (i = 0; i < long_rps->nb_refs; i++) + ret += !!long_rps->used[i]; if (sh->inter_layer_pred) { av_assert0(pps->sps->vps->num_direct_ref_layers[layer_idx] < 2); diff --git a/libavcodec/hevc/sei.c b/libavcodec/hevc/sei.c index 462ce37de..e12803f1d 100644 --- a/libavcodec/hevc/sei.c +++ b/libavcodec/hevc/sei.c @@ -79,6 +79,21 @@ static int decode_nal_sei_pic_timing(HEVCSEI *s, GetBitContext *gb, return 0; } +static int decode_nal_sei_recovery_point(HEVCSEI *s, GetBitContext *gb) +{ + HEVCSEIRecoveryPoint *rec = &s->recovery_point; + int recovery_poc_cnt = get_se_golomb(gb); + + if (recovery_poc_cnt > INT16_MAX || recovery_poc_cnt < INT16_MIN) + return AVERROR_INVALIDDATA; + rec->recovery_poc_cnt = recovery_poc_cnt; + rec->exact_match_flag = get_bits1(gb); + rec->broken_link_flag = get_bits1(gb); + rec->has_recovery_poc = 1; + + return 0; +} + static int decode_nal_sei_active_parameter_sets(HEVCSEI *s, GetBitContext *gb, void *logctx) { int num_sps_ids_minus1; @@ -202,6 +217,8 @@ static int decode_nal_sei_3d_reference_displays_info(HEVCSEITDRDI *s, GetBitCont } s->three_dimensional_reference_displays_extension_flag = get_bits1(gb); + s->present = 1; + return 0; } @@ -214,6 +231,8 @@ static int decode_nal_sei_prefix(GetBitContext *gb, GetByteContext *gbyte, return decode_nal_sei_decoded_picture_hash(&s->picture_hash, gbyte); case SEI_TYPE_PIC_TIMING: return decode_nal_sei_pic_timing(s, gb, ps, logctx); + case SEI_TYPE_RECOVERY_POINT: + return decode_nal_sei_recovery_point(s, gb); case SEI_TYPE_ACTIVE_PARAMETER_SETS: return decode_nal_sei_active_parameter_sets(s, gb, logctx); case SEI_TYPE_TIME_CODE: diff --git a/libavcodec/hevc/sei.h b/libavcodec/hevc/sei.h index 5239ec93a..59bd2b45f 100644 --- a/libavcodec/hevc/sei.h +++ b/libavcodec/hevc/sei.h @@ -93,8 +93,16 @@ typedef struct HEVCSEITDRDI { uint8_t additional_shift_present_flag[32]; int16_t num_sample_shift[32]; uint8_t three_dimensional_reference_displays_extension_flag; + int present; } HEVCSEITDRDI; +typedef struct HEVCSEIRecoveryPoint { + int16_t recovery_poc_cnt; + uint8_t exact_match_flag; + uint8_t broken_link_flag; + uint8_t has_recovery_poc; +} HEVCSEIRecoveryPoint; + typedef struct HEVCSEI { H2645SEI common; HEVCSEIPictureHash picture_hash; @@ -102,6 +110,7 @@ typedef struct HEVCSEI { int active_seq_parameter_set_id; HEVCSEITimeCode timecode; HEVCSEITDRDI tdrdi; + HEVCSEIRecoveryPoint recovery_point; } HEVCSEI; struct HEVCParamSets; @@ -109,11 +118,6 @@ struct HEVCParamSets; int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEI *s, const struct HEVCParamSets *ps, enum HEVCNALUnitType type); -static inline int ff_hevc_sei_ctx_replace(HEVCSEI *dst, const HEVCSEI *src) -{ - return ff_h2645_sei_ctx_replace(&dst->common, &src->common); -} - /** * Reset SEI values that are stored on the Context. * e.g. Caption data that was extracted during NAL @@ -123,6 +127,8 @@ static inline int ff_hevc_sei_ctx_replace(HEVCSEI *dst, const HEVCSEI *src) */ static inline void ff_hevc_reset_sei(HEVCSEI *sei) { + sei->timecode.present = 0; + sei->tdrdi.present = 0; ff_h2645_sei_reset(&sei->common); } diff --git a/libavcodec/hpel_template.c b/libavcodec/hpel_template.c index fccfe7610..67bee665a 100644 --- a/libavcodec/hpel_template.c +++ b/libavcodec/hpel_template.c @@ -29,9 +29,9 @@ static inline void FUNC(OPNAME ## _pixels8_l2)(uint8_t *dst, \ const uint8_t *src1, \ const uint8_t *src2, \ - int dst_stride, \ - int src_stride1, \ - int src_stride2, \ + ptrdiff_t dst_stride, \ + ptrdiff_t src_stride1, \ + ptrdiff_t src_stride2, \ int h) \ { \ int i; \ @@ -40,9 +40,9 @@ static inline void FUNC(OPNAME ## _pixels8_l2)(uint8_t *dst, \ a = AV_RN4P(&src1[i * src_stride1]); \ b = AV_RN4P(&src2[i * src_stride2]); \ OP(*((pixel4 *) &dst[i * dst_stride]), rnd_avg_pixel4(a, b)); \ - a = AV_RN4P(&src1[i * src_stride1 + 4 * sizeof(pixel)]); \ - b = AV_RN4P(&src2[i * src_stride2 + 4 * sizeof(pixel)]); \ - OP(*((pixel4 *) &dst[i * dst_stride + 4 * sizeof(pixel)]), \ + a = AV_RN4P(&src1[i * src_stride1 + 4 * (int)sizeof(pixel)]); \ + b = AV_RN4P(&src2[i * src_stride2 + 4 * (int)sizeof(pixel)]); \ + OP(*((pixel4 *) &dst[i * dst_stride + 4 * (int)sizeof(pixel)]), \ rnd_avg_pixel4(a, b)); \ } \ } \ @@ -50,9 +50,9 @@ static inline void FUNC(OPNAME ## _pixels8_l2)(uint8_t *dst, \ static inline void FUNC(OPNAME ## _pixels4_l2)(uint8_t *dst, \ const uint8_t *src1, \ const uint8_t *src2, \ - int dst_stride, \ - int src_stride1, \ - int src_stride2, \ + ptrdiff_t dst_stride, \ + ptrdiff_t src_stride1, \ + ptrdiff_t src_stride2, \ int h) \ { \ int i; \ @@ -67,9 +67,9 @@ static inline void FUNC(OPNAME ## _pixels4_l2)(uint8_t *dst, \ static inline void FUNC(OPNAME ## _pixels2_l2)(uint8_t *dst, \ const uint8_t *src1, \ const uint8_t *src2, \ - int dst_stride, \ - int src_stride1, \ - int src_stride2, \ + ptrdiff_t dst_stride, \ + ptrdiff_t src_stride1, \ + ptrdiff_t src_stride2, \ int h) \ { \ int i; \ @@ -84,9 +84,9 @@ static inline void FUNC(OPNAME ## _pixels2_l2)(uint8_t *dst, \ static inline void FUNC(OPNAME ## _pixels16_l2)(uint8_t *dst, \ const uint8_t *src1, \ const uint8_t *src2, \ - int dst_stride, \ - int src_stride1, \ - int src_stride2, \ + ptrdiff_t dst_stride, \ + ptrdiff_t src_stride1, \ + ptrdiff_t src_stride2, \ int h) \ { \ FUNC(OPNAME ## _pixels8_l2)(dst, src1, src2, dst_stride, \ diff --git a/libavcodec/hpeldsp.c b/libavcodec/hpeldsp.c index 80494c974..e753d6216 100644 --- a/libavcodec/hpeldsp.c +++ b/libavcodec/hpeldsp.c @@ -39,9 +39,9 @@ static inline void OPNAME ## _no_rnd_pixels8_l2_8(uint8_t *dst, \ const uint8_t *src1, \ const uint8_t *src2, \ - int dst_stride, \ - int src_stride1, \ - int src_stride2, \ + ptrdiff_t dst_stride, \ + ptrdiff_t src_stride1,\ + ptrdiff_t src_stride2,\ int h) \ { \ int i; \ @@ -314,9 +314,6 @@ CALL_2X_PIXELS(OPNAME ## _pixels16_y2_8_c, \ CALL_2X_PIXELS(OPNAME ## _pixels16_xy2_8_c, \ OPNAME ## _pixels8_xy2_8_c, \ 8) \ -CALL_2X_PIXELS(OPNAME ## _no_rnd_pixels16_8_c, \ - OPNAME ## _pixels8_8_c, \ - 8) \ CALL_2X_PIXELS(OPNAME ## _no_rnd_pixels16_x2_8_c, \ OPNAME ## _no_rnd_pixels8_x2_8_c, \ 8) \ @@ -330,6 +327,8 @@ CALL_2X_PIXELS(OPNAME ## _no_rnd_pixels16_xy2_8_c, \ #define op_avg(a, b) a = rnd_avg32(a, b) #define op_put(a, b) a = b #define put_no_rnd_pixels8_8_c put_pixels8_8_c +#define put_no_rnd_pixels16_8_c put_pixels16_8_c +#define avg_no_rnd_pixels16_8_c avg_pixels16_8_c PIXOP2(avg, op_avg) PIXOP2(put, op_put) #undef op_avg @@ -361,7 +360,7 @@ av_cold void ff_hpeldsp_init(HpelDSPContext *c, int flags) ff_hpeldsp_init_arm(c, flags); #elif ARCH_PPC ff_hpeldsp_init_ppc(c, flags); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_hpeldsp_init_x86(c, flags); #elif ARCH_MIPS ff_hpeldsp_init_mips(c, flags); diff --git a/libavcodec/hpeldsp.h b/libavcodec/hpeldsp.h index 45e81b10a..6c9fdce0c 100644 --- a/libavcodec/hpeldsp.h +++ b/libavcodec/hpeldsp.h @@ -31,11 +31,12 @@ #include #include -/* add and put pixel (decoding) */ -// blocksizes for hpel_pixels_func are 8x4,8x8 16x8 16x16 -// h for hpel_pixels_func is limited to {width/2, width} but never larger -// than 16 and never smaller than 4 -typedef void (*op_pixels_func)(uint8_t *block /*align width (8 or 16)*/, +/** + * Average and put pixel + * Widths can be 16, 8, 4 or 2. For for widths 2 and 4, h is always a positive + * multiple of 2; otherwise, it is a positive multiple of 4. + */ +typedef void (*op_pixels_func)(uint8_t *block /* align width */, const uint8_t *pixels /*align 1*/, ptrdiff_t line_size, int h); @@ -46,8 +47,8 @@ typedef struct HpelDSPContext { /** * Halfpel motion compensation with rounding (a+b+1)>>1. * this is an array[4][4] of motion compensation functions for 4 - * horizontal blocksizes (8,16) and the 4 halfpel positions
- * *pixels_tab[ 0->16xH 1->8xH ][ xhalfpel + 2*yhalfpel ] + * horizontal blocksizes (2,4,8,16) and the 4 halfpel positions
+ * *pixels_tab[ 0->16xH 1->8xH 2->4xH 3->2xH ][ xhalfpel + 2*yhalfpel ] * @param block destination where the result is stored * @param pixels source * @param line_size number of bytes in a horizontal line of block @@ -58,8 +59,8 @@ typedef struct HpelDSPContext { /** * Halfpel motion compensation with rounding (a+b+1)>>1. * This is an array[4][4] of motion compensation functions for 4 - * horizontal blocksizes (8,16) and the 4 halfpel positions
- * *pixels_tab[ 0->16xH 1->8xH ][ xhalfpel + 2*yhalfpel ] + * horizontal blocksizes (2,4,8,16) and the 4 halfpel positions
+ * *pixels_tab[ 0->16xH 1->8xH 2->4xH 3->2xH ][ xhalfpel + 2*yhalfpel ] * @param block destination into which the result is averaged (a+b+1)>>1 * @param pixels source * @param line_size number of bytes in a horizontal line of block @@ -76,16 +77,16 @@ typedef struct HpelDSPContext { * @param pixels source * @param line_size number of bytes in a horizontal line of block * @param h height - * @note The size is kept at [4][4] to match the above pixel_tabs and avoid - * out of bounds reads in the motion estimation code. + * @note The size is kept at [3][4] to avoid out of bounds accesses + * in the motion estimation code. */ - op_pixels_func put_no_rnd_pixels_tab[4][4]; + op_pixels_func put_no_rnd_pixels_tab[3][4]; /** * Halfpel motion compensation with no rounding (a+b)>>1. * this is an array[4] of motion compensation functions for 1 * horizontal blocksize (16) and the 4 halfpel positions
- * *pixels_tab[0][ xhalfpel + 2*yhalfpel ] + * *pixels_tab[ xhalfpel + 2*yhalfpel ] * @param block destination into which the result is averaged (a+b)>>1 * @param pixels source * @param line_size number of bytes in a horizontal line of block @@ -97,7 +98,6 @@ typedef struct HpelDSPContext { void ff_hpeldsp_init(HpelDSPContext *c, int flags); void ff_hpeldsp_init_aarch64(HpelDSPContext *c, int flags); -void ff_hpeldsp_init_alpha(HpelDSPContext *c, int flags); void ff_hpeldsp_init_arm(HpelDSPContext *c, int flags); void ff_hpeldsp_init_ppc(HpelDSPContext *c, int flags); void ff_hpeldsp_init_x86(HpelDSPContext *c, int flags); diff --git a/libavcodec/hq_common.c b/libavcodec/hq_common.c new file mode 100644 index 000000000..9f56c819f --- /dev/null +++ b/libavcodec/hq_common.c @@ -0,0 +1,44 @@ +/* + * 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 "hq_common.h" + +#define REPEAT(x) x x +#define ELEM(_sym, _len) {.sym = _sym << 4 | _sym, .len = _len }, +#define LEN5(sym) ELEM(sym, 5) +#define LEN4(sym) REPEAT(ELEM(sym, 4)) +#define LEN2(sym) REPEAT(REPEAT(REPEAT(ELEM(sym, 2)))) + +const VLCElem ff_hq_cbp_vlc[1 << HQ_CBP_VLC_BITS] = { + LEN2(0xF) + LEN4(0x0) + LEN4(0xE) + LEN4(0xD) + LEN4(0xB) + LEN4(0x7) + LEN4(0x3) + LEN4(0xC) + LEN4(0x5) + LEN4(0xA) + LEN5(0x9) + LEN5(0x6) + LEN5(0x1) + LEN5(0x2) + LEN5(0x4) + LEN5(0x8) +}; diff --git a/libavcodec/hq_common.h b/libavcodec/hq_common.h new file mode 100644 index 000000000..e438ac7d0 --- /dev/null +++ b/libavcodec/hq_common.h @@ -0,0 +1,29 @@ +/* + * 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_HQ_COMMON_H +#define AVCODEC_HQ_COMMON_H + +#include "vlc.h" +#include "libavutil/attributes_internal.h" + +#define HQ_CBP_VLC_BITS 5 + +EXTERN const VLCElem ff_hq_cbp_vlc[1 << HQ_CBP_VLC_BITS]; + +#endif /* AVCODEC_HQ_COMMON_H */ diff --git a/libavcodec/hq_hqa.c b/libavcodec/hq_hqa.c index 738ed9868..94945a404 100644 --- a/libavcodec/hq_hqa.c +++ b/libavcodec/hq_hqa.c @@ -30,6 +30,7 @@ #include "codec_internal.h" #include "decode.h" #include "get_bits.h" +#include "hq_common.h" #include "hq_hqadata.h" #include "hq_hqadsp.h" #include "vlc.h" @@ -57,8 +58,9 @@ typedef struct HQContext { DECLARE_ALIGNED(16, int16_t, block)[12][64]; } HQContext; -static VLCElem hq_ac_vlc[1184]; -static VLCElem hqa_cbp_vlc[32]; +static const int32_t *hq_quants[NUM_HQ_QUANTS][2][4]; + +static RL_VLC_ELEM hq_ac_rvlc[1184]; static inline void put_blocks(HQContext *c, AVFrame *pic, int plane, int x, int y, int ilace, @@ -76,9 +78,6 @@ static int hq_decode_block(HQContext *c, GetBitContext *gb, int16_t block[64], int qsel, int is_chroma, int is_hqa) { const int32_t *q; - int val, pos = 1; - - memset(block, 0, 64 * sizeof(*block)); if (!is_hqa) { block[0] = get_sbits(gb, 9) * 64; @@ -88,17 +87,22 @@ static int hq_decode_block(HQContext *c, GetBitContext *gb, int16_t block[64], block[0] = get_sbits(gb, 9) * 64; } - for (;;) { - val = get_vlc2(gb, hq_ac_vlc, 9, 2); - if (val < 0) + OPEN_READER(re, gb); + for (int pos = 0;;) { + int level, run; + UPDATE_CACHE(re, gb); + GET_RL_VLC(level, run, re, gb, hq_ac_rvlc, 9, 2, 0); + if (run == HQ_AC_INVALID_RUN) { + CLOSE_READER(re, gb); return AVERROR_INVALIDDATA; + } - pos += hq_ac_skips[val]; + pos += run; if (pos >= 64) break; - block[ff_zigzag_direct[pos]] = (int)(hq_ac_syms[val] * (unsigned)q[pos]) >> 12; - pos++; + block[ff_zigzag_direct[pos]] = (int)(level * (unsigned)q[pos]) >> 12; } + CLOSE_READER(re, gb); return 0; } @@ -109,6 +113,8 @@ static int hq_decode_mb(HQContext *c, AVFrame *pic, int qgroup, flag; int i, ret; + memset(c->block, 0, 8 * sizeof(c->block[0])); + qgroup = get_bits(gb, 4); flag = get_bits1(gb); @@ -131,7 +137,7 @@ static int hq_decode_frame(HQContext *ctx, AVFrame *pic, GetByteContext *gbc, { const HQProfile *profile; GetBitContext gb; - const uint8_t *perm, *src = gbc->buffer; + const uint8_t *src = gbc->buffer; uint32_t slice_off[21]; int slice, start_off, next_off, i, ret; @@ -143,6 +149,9 @@ static int hq_decode_frame(HQContext *ctx, AVFrame *pic, GetByteContext *gbc, av_log(ctx->avctx, AV_LOG_VERBOSE, "HQ Profile %d\n", prof_num); } + if (bytestream2_get_bytes_left(gbc) < 3 * (profile->num_slices + 1)) + return AVERROR_INVALIDDATA; + ctx->avctx->coded_width = FFALIGN(profile->width, 16); ctx->avctx->coded_height = FFALIGN(profile->height, 16); ctx->avctx->width = profile->width; @@ -156,19 +165,19 @@ static int hq_decode_frame(HQContext *ctx, AVFrame *pic, GetByteContext *gbc, /* Offsets are stored from CUV position, so adjust them accordingly. */ for (i = 0; i < profile->num_slices + 1; i++) - slice_off[i] = bytestream2_get_be24(gbc) - 4; + slice_off[i] = bytestream2_get_be24u(gbc) - 4; next_off = 0; + const uint8_t *perm = hq_perms + profile->tab_offset; for (slice = 0; slice < profile->num_slices; slice++) { start_off = next_off; next_off = profile->tab_h * (slice + 1) / profile->num_slices; - perm = profile->perm_tab + start_off * profile->tab_w * 2; if (slice_off[slice] < (profile->num_slices + 1) * 3 || slice_off[slice] >= slice_off[slice + 1] || slice_off[slice + 1] > data_size) { av_log(ctx->avctx, AV_LOG_ERROR, - "Invalid slice size %"SIZE_SPECIFIER".\n", data_size); + "Invalid slice size %zu.\n", data_size); break; } init_get_bits(&gb, src + slice_off[slice], @@ -192,22 +201,19 @@ static int hqa_decode_mb(HQContext *c, AVFrame *pic, int qgroup, GetBitContext *gb, int x, int y) { int flag = 0; - int i, ret, cbp; + int i, ret; if (get_bits_left(gb) < 1) return AVERROR_INVALIDDATA; - cbp = get_vlc2(gb, hqa_cbp_vlc, 5, 1); - - for (i = 0; i < 12; i++) - memset(c->block[i], 0, sizeof(*c->block)); + memset(c->block, 0, 12 * sizeof(c->block[0])); for (i = 0; i < 12; i++) c->block[i][0] = -128 * (1 << 6); + int cbp = get_vlc2(gb, ff_hq_cbp_vlc, HQ_CBP_VLC_BITS, 1); if (cbp) { flag = get_bits1(gb); - cbp |= cbp << 4; if (cbp & 0x3) cbp |= 0x500; if (cbp & 0xC) @@ -258,14 +264,13 @@ static int hqa_decode_frame(HQContext *ctx, AVFrame *pic, GetByteContext *gbc, s const int num_slices = 8; uint32_t slice_off[9]; int i, slice, ret; - int width, height, quant; const uint8_t *src = gbc->buffer; if (bytestream2_get_bytes_left(gbc) < 8 + 4*(num_slices + 1)) return AVERROR_INVALIDDATA; - width = bytestream2_get_be16(gbc); - height = bytestream2_get_be16(gbc); + int width = bytestream2_get_be16u(gbc); + int height = bytestream2_get_be16u(gbc); ret = ff_set_dimensions(ctx->avctx, width, height); if (ret < 0) @@ -278,8 +283,8 @@ static int hqa_decode_frame(HQContext *ctx, AVFrame *pic, GetByteContext *gbc, s av_log(ctx->avctx, AV_LOG_VERBOSE, "HQA Profile\n"); - quant = bytestream2_get_byte(gbc); - bytestream2_skip(gbc, 3); + int quant = bytestream2_get_byteu(gbc); + bytestream2_skipu(gbc, 3); if (quant >= NUM_HQ_QUANTS) { av_log(ctx->avctx, AV_LOG_ERROR, "Invalid quantization matrix %d.\n", quant); @@ -292,14 +297,14 @@ static int hqa_decode_frame(HQContext *ctx, AVFrame *pic, GetByteContext *gbc, s /* Offsets are stored from HQA1 position, so adjust them accordingly. */ for (i = 0; i < num_slices + 1; i++) - slice_off[i] = bytestream2_get_be32(gbc) - 4; + slice_off[i] = bytestream2_get_be32u(gbc) - 4; for (slice = 0; slice < num_slices; slice++) { if (slice_off[slice] < (num_slices + 1) * 3 || slice_off[slice] >= slice_off[slice + 1] || slice_off[slice + 1] > data_size) { av_log(ctx->avctx, AV_LOG_ERROR, - "Invalid slice size %"SIZE_SPECIFIER".\n", data_size); + "Invalid slice size %zu.\n", data_size); break; } init_get_bits(&gb, src + slice_off[slice], @@ -318,29 +323,26 @@ static int hq_hqa_decode_frame(AVCodecContext *avctx, AVFrame *pic, { HQContext *ctx = avctx->priv_data; GetByteContext gbc0, *const gbc = &gbc0; - uint32_t info_tag; unsigned int data_size; int ret; - unsigned tag; - bytestream2_init(gbc, avpkt->data, avpkt->size); - if (bytestream2_get_bytes_left(gbc) < 4 + 4) { + if (avpkt->size < 4 + 4) { av_log(avctx, AV_LOG_ERROR, "Frame is too small (%d).\n", avpkt->size); return AVERROR_INVALIDDATA; } + bytestream2_init(gbc, avpkt->data, avpkt->size); - info_tag = bytestream2_peek_le32(gbc); + uint32_t info_tag = bytestream2_peek_le32u(gbc); if (info_tag == MKTAG('I', 'N', 'F', 'O')) { - int info_size; - bytestream2_skip(gbc, 4); - info_size = bytestream2_get_le32(gbc); + bytestream2_skipu(gbc, 4); + int info_size = bytestream2_get_le32u(gbc); if (info_size < 0 || bytestream2_get_bytes_left(gbc) < info_size) { av_log(avctx, AV_LOG_ERROR, "Invalid INFO size (%d).\n", info_size); return AVERROR_INVALIDDATA; } ff_canopus_parse_info_tag(avctx, gbc->buffer, info_size); - bytestream2_skip(gbc, info_size); + bytestream2_skipu(gbc, info_size); } data_size = bytestream2_get_bytes_left(gbc); @@ -352,7 +354,7 @@ static int hq_hqa_decode_frame(AVCodecContext *avctx, AVFrame *pic, /* HQ defines dimensions and number of slices, and thus slice traversal * order. HQA has no size constraint and a fixed number of slices, so it * needs a separate scheme for it. */ - tag = bytestream2_get_le32(gbc); + unsigned tag = bytestream2_get_le32u(gbc); if ((tag & 0x00FFFFFF) == (MKTAG('U', 'V', 'C', ' ') & 0x00FFFFFF)) { ret = hq_decode_frame(ctx, pic, gbc, tag >> 24, data_size); } else if (tag == MKTAG('H', 'Q', 'A', '1')) { @@ -371,13 +373,33 @@ static int hq_hqa_decode_frame(AVCodecContext *avctx, AVFrame *pic, return avpkt->size; } -static av_cold void hq_init_vlcs(void) +static av_cold void hq_init_static(void) { - VLC_INIT_STATIC_TABLE(hqa_cbp_vlc, 5, FF_ARRAY_ELEMS(cbp_vlc_lens), - cbp_vlc_lens, 1, 1, cbp_vlc_bits, 1, 1, 0); + VLC_INIT_STATIC_TABLE_FROM_LENGTHS(hq_ac_rvlc, 9, NUM_HQ_AC_ENTRIES, + hq_ac_lens, 1, hq_ac_sym, 2, 2, 0, 0); - VLC_INIT_STATIC_TABLE(hq_ac_vlc, 9, NUM_HQ_AC_ENTRIES, - hq_ac_bits, 1, 1, hq_ac_codes, 2, 2, 0); + for (size_t i = 0; i < FF_ARRAY_ELEMS(hq_ac_rvlc); ++i) { + int len = hq_ac_rvlc[i].len; + int sym = (int16_t)hq_ac_rvlc[i].sym, level = sym; + + // The invalid code has been remapped to HQ_AC_INVALID_RUN, + // so the VLC is complete. + av_assert1(len != 0); + + if (len > 0) { + level = sym >> 7; + hq_ac_rvlc[i].run = sym & 0x7F; + } + hq_ac_rvlc[i].len8 = len; + hq_ac_rvlc[i].level = level; + } + + for (size_t i = 0; i < FF_ARRAY_ELEMS(hq_quants); ++i) { + for (size_t j = 0; j < FF_ARRAY_ELEMS(hq_quants[0]); ++j) { + for (size_t k = 0; k < FF_ARRAY_ELEMS(hq_quants[0][0]); ++k) + hq_quants[i][j][k] = qmats[hq_quant_map[i][j][k]]; + } + } } static av_cold int hq_hqa_decode_init(AVCodecContext *avctx) @@ -388,7 +410,7 @@ static av_cold int hq_hqa_decode_init(AVCodecContext *avctx) ff_hqdsp_init(&ctx->hqhqadsp); - ff_thread_once(&init_static_once, hq_init_vlcs); + ff_thread_once(&init_static_once, hq_init_static); return 0; } diff --git a/libavcodec/hq_hqadata.h b/libavcodec/hq_hqadata.h index 2faf47f00..75f9ab92c 100644 --- a/libavcodec/hq_hqadata.h +++ b/libavcodec/hq_hqadata.h @@ -21,31 +21,99 @@ #ifndef AVCODEC_HQ_HQADATA_H #define AVCODEC_HQ_HQADATA_H +#include #include -#define NUM_HQ_AC_ENTRIES 746 +#define NUM_HQ_AC_ENTRIES 747 // includes one invalid entry #define NUM_HQ_PROFILES 22 #define NUM_HQ_QUANTS 16 -typedef struct HQProfile { - const uint8_t *perm_tab; - int width, height; - int num_slices; - int tab_w, tab_h; -} HQProfile; +enum { + QMAT00, + QMAT01, + QMAT02, + QMAT03, + QMAT04, + QMAT05, + QMAT06, + QMAT07, + QMAT08, + QMAT09, + QMAT0A, + QMAT0B, + QMAT0C, + QMAT0D, + QMAT0E, + QMAT0F, + QMAT10, + QMAT11, + QMAT12, + QMAT13, + QMAT14, + QMAT15, + QMAT16, + QMAT17, + QMAT18, + QMAT19, + QMAT1A, + QMAT1B, + QMAT1C, + QMAT1D, + QMAT1E, + QMAT1F, + QMAT20, + QMAT21, + QMAT22, + QMAT23, + QMAT24, + QMAT25, + QMAT26, + QMAT27, + QMAT28, + QMAT29, + QMAT2A, + QMAT2B, + QMAT2C, + QMAT2D, + QMAT2E, + QMAT2F, + QMAT30, + QMAT31, + QMAT32, + QMAT33, + QMAT34, + QMAT35, + QMAT36, + QMAT37, + QMAT38, + QMAT39, + QMAT3A, + QMAT3B, + QMAT3C, + QMAT3D, + QMAT3E, + QMAT3F, + QMAT40, + QMAT41, + QMAT42, + QMAT43, + QMAT44, + QMAT45, + QMAT46, + QMAT47, + QMAT48, + QMAT49, + QMAT4A, + QMAT4B, + QMAT4C, + QMAT4D, + NUM_QMATS +}; #define MAT_SIZE 64 -static const uint8_t cbp_vlc_bits[16] = { - 0x04, 0x1C, 0x1D, 0x09, 0x1E, 0x0B, 0x1B, 0x08, - 0x1F, 0x1A, 0x0C, 0x07, 0x0A, 0x06, 0x05, 0x00, -}; - -static const uint8_t cbp_vlc_lens[16] = { - 4, 5, 5, 4, 5, 4, 5, 4, 5, 5, 4, 4, 4, 4, 4, 2, -}; - -static const int32_t qmat00[MAT_SIZE] = { +static const int32_t qmats[NUM_QMATS][MAT_SIZE] = { +[QMAT00] = { 0x0040000, 0x000B18B, 0x00058C5, 0x000B1B1, 0x00082D3, 0x000B1B1, 0x000A953, 0x000827B, 0x00104F7, 0x000A953, 0x0009000, 0x000EADD, 0x001037B, 0x000756E, 0x0009000, 0x000776D, 0x000696A, 0x000E987, @@ -57,9 +125,8 @@ static const int32_t qmat00[MAT_SIZE] = { 0x00229B2, 0x001FCB2, 0x0019FA3, 0x000D94C, 0x000CFD2, 0x0007F2D, 0x000DEED, 0x0014D5E, 0x0029ABD, 0x0037BB5, 0x002D16B, 0x001FECE, 0x000B45B, 0x0011521, 0x0022A42, 0x0012B9C, -}; - -static const int32_t qmat01[MAT_SIZE] = { +}, +[QMAT01] = { 0x0040000, 0x000B18B, 0x00058C5, 0x000B1B1, 0x00082D3, 0x000B1B1, 0x000EB2D, 0x000B53A, 0x0016A73, 0x000EB2D, 0x000D000, 0x0014632, 0x0016314, 0x000A319, 0x000D000, 0x000A36D, 0x0009041, 0x0014BDA, @@ -71,9 +138,8 @@ static const int32_t qmat01[MAT_SIZE] = { 0x0045365, 0x007FD2A, 0x00675E5, 0x0036A1F, 0x0033AF3, 0x001FF4B, 0x001C010, 0x0029E24, 0x0053C47, 0x007003E, 0x005A9C7, 0x004024C, 0x0016A72, 0x0022A42, 0x0045485, 0x0025738, -}; - -static const int32_t qmat02[MAT_SIZE] = { +}, +[QMAT02] = { 0x0040000, 0x0016315, 0x000B18B, 0x0016363, 0x00105A6, 0x0016363, 0x00152A7, 0x00104F7, 0x00209EE, 0x00152A7, 0x0012000, 0x001D5B9, 0x00206F6, 0x000EADD, 0x0012000, 0x000EEDA, 0x000D2D4, 0x001D30D, @@ -85,9 +151,8 @@ static const int32_t qmat02[MAT_SIZE] = { 0x0045365, 0x003F964, 0x0033F47, 0x001B297, 0x0019FA3, 0x000FE59, 0x001BDDA, 0x0029ABD, 0x0053579, 0x006F76A, 0x005A2D7, 0x003FD9D, 0x00168B6, 0x0022A42, 0x0045485, 0x0025738, -}; - -static const int32_t qmat03[MAT_SIZE] = { +}, +[QMAT03] = { 0x0040000, 0x0016315, 0x000B18B, 0x0016363, 0x00105A6, 0x0016363, 0x001D65A, 0x0016A73, 0x002D4E7, 0x001D65A, 0x001A000, 0x0028C65, 0x002C628, 0x0014632, 0x001A000, 0x00146D9, 0x0012081, 0x00297B5, @@ -99,9 +164,8 @@ static const int32_t qmat03[MAT_SIZE] = { 0x008A6CA, 0x00FFA54, 0x00CEBCA, 0x006D43E, 0x00675E5, 0x003FE95, 0x003801F, 0x0053C47, 0x00A788E, 0x00E007C, 0x00B538D, 0x0080498, 0x002D4E3, 0x0045485, 0x008A90A, 0x004AE71, -}; - -static const int32_t qmat04[MAT_SIZE] = { +}, +[QMAT04] = { 0x0040000, 0x00214A0, 0x0010A50, 0x0021514, 0x0018879, 0x0021514, 0x001FBFA, 0x0018772, 0x0030EE5, 0x001FBFA, 0x001B000, 0x002C096, 0x0030A71, 0x001604B, 0x001B000, 0x0016647, 0x0013C3F, 0x002BC94, @@ -113,9 +177,8 @@ static const int32_t qmat04[MAT_SIZE] = { 0x0067D17, 0x005F616, 0x004DEEA, 0x0028BE3, 0x0026F75, 0x0017D86, 0x0029CC8, 0x003E81B, 0x007D036, 0x00A731F, 0x0087442, 0x005FC6B, 0x0021D11, 0x0033F64, 0x0067EC7, 0x00382D5, -}; - -static const int32_t qmat05[MAT_SIZE] = { +}, +[QMAT05] = { 0x0040000, 0x00214A0, 0x0010A50, 0x0021514, 0x0018879, 0x0021514, 0x002C186, 0x0021FAD, 0x0043F5A, 0x002C186, 0x0027000, 0x003D297, 0x004293C, 0x001E94C, 0x0027000, 0x001EA46, 0x001B0C2, 0x003E38F, @@ -127,9 +190,8 @@ static const int32_t qmat05[MAT_SIZE] = { 0x00CFA2F, 0x017F77F, 0x01361B0, 0x00A3E5C, 0x009B0D8, 0x005FDE0, 0x005402F, 0x007DA6B, 0x00FB4D5, 0x01500BA, 0x010FD54, 0x00C06E5, 0x0043F55, 0x0067EC7, 0x00CFD8F, 0x00705A9, -}; - -static const int32_t qmat06[MAT_SIZE] = { +}, +[QMAT06] = { 0x0040000, 0x002C62A, 0x0016315, 0x002C6C5, 0x0020B4C, 0x002C6C5, 0x002A54E, 0x00209EE, 0x00413DC, 0x002A54E, 0x0024000, 0x003AB73, 0x0040DEC, 0x001D5B9, 0x0024000, 0x001DDB4, 0x001A5A9, 0x003A61B, @@ -141,9 +203,8 @@ static const int32_t qmat06[MAT_SIZE] = { 0x008A6CA, 0x007F2C9, 0x0067E8E, 0x003652F, 0x0033F47, 0x001FCB2, 0x0037BB5, 0x0053579, 0x00A6AF3, 0x00DEED4, 0x00B45AE, 0x007FB39, 0x002D16B, 0x0045485, 0x008A90A, 0x004AE71, -}; - -static const int32_t qmat07[MAT_SIZE] = { +}, +[QMAT07] = { 0x0040000, 0x002C62A, 0x0016315, 0x002C6C5, 0x0020B4C, 0x002C6C5, 0x003ACB3, 0x002D4E7, 0x005A9CE, 0x003ACB3, 0x0034000, 0x00518CA, 0x0058C50, 0x0028C65, 0x0034000, 0x0028DB3, 0x0024102, 0x0052F69, @@ -155,9 +216,8 @@ static const int32_t qmat07[MAT_SIZE] = { 0x0114D94, 0x01FF4A9, 0x019D795, 0x00DA87B, 0x00CEBCA, 0x007FD2A, 0x007003E, 0x00A788E, 0x014F11C, 0x01C00F8, 0x016A71B, 0x0100931, 0x005A9C7, 0x008A90A, 0x0115214, 0x0095CE2, -}; - -static const int32_t qmat08[MAT_SIZE] = { +}, +[QMAT08] = { 0x0040000, 0x00377B5, 0x001BBDA, 0x0037876, 0x0028E1E, 0x0037876, 0x0034EA1, 0x0028C69, 0x00518D3, 0x0034EA1, 0x002D000, 0x004964F, 0x0051167, 0x0024B28, 0x002D000, 0x0025521, 0x0020F13, 0x0048FA1, @@ -169,9 +229,8 @@ static const int32_t qmat08[MAT_SIZE] = { 0x00AD07C, 0x009EF7B, 0x0081E31, 0x0043E7A, 0x0040F19, 0x0027BDF, 0x0045AA2, 0x00682D8, 0x00D05B0, 0x0116A89, 0x00E1719, 0x009FA07, 0x00385C6, 0x00569A6, 0x00AD34C, 0x005DA0D, -}; - -static const int32_t qmat09[MAT_SIZE] = { +}, +[QMAT09] = { 0x0040000, 0x00377B5, 0x001BBDA, 0x0037876, 0x0028E1E, 0x0037876, 0x00497E0, 0x0038A21, 0x0071441, 0x00497E0, 0x0041000, 0x0065EFC, 0x006EF64, 0x0032F7E, 0x0041000, 0x003311F, 0x002D143, 0x0067B44, @@ -183,9 +242,8 @@ static const int32_t qmat09[MAT_SIZE] = { 0x015A0F9, 0x027F1D3, 0x0204D7A, 0x011129A, 0x01026BD, 0x009FC75, 0x008C04E, 0x00D16B2, 0x01A2D64, 0x0230136, 0x01C50E1, 0x0140B7D, 0x0071438, 0x00AD34C, 0x015A699, 0x00BB41A, -}; - -static const int32_t qmat0A[MAT_SIZE] = { +}, +[QMAT0A] = { 0x0040000, 0x004293F, 0x00214A0, 0x0042A28, 0x00310F1, 0x0042A28, 0x003F7F5, 0x0030EE5, 0x0061DCA, 0x003F7F5, 0x0036000, 0x005812C, 0x00614E2, 0x002C096, 0x0036000, 0x002CC8E, 0x002787D, 0x0057928, @@ -197,9 +255,8 @@ static const int32_t qmat0A[MAT_SIZE] = { 0x00CFA2F, 0x00BEC2D, 0x009BDD5, 0x00517C6, 0x004DEEA, 0x002FB0B, 0x005398F, 0x007D036, 0x00FA06C, 0x014E63E, 0x010E885, 0x00BF8D6, 0x0043A21, 0x0067EC7, 0x00CFD8F, 0x00705A9, -}; - -static const int32_t qmat0B[MAT_SIZE] = { +}, +[QMAT0B] = { 0x0040000, 0x004293F, 0x00214A0, 0x0042A28, 0x00310F1, 0x0042A28, 0x005830D, 0x0043F5A, 0x0087EB5, 0x005830D, 0x004E000, 0x007A52F, 0x0085278, 0x003D297, 0x004E000, 0x003D48C, 0x0036183, 0x007C71E, @@ -211,9 +268,8 @@ static const int32_t qmat0B[MAT_SIZE] = { 0x019F45E, 0x02FEEFD, 0x026C35F, 0x0147CB9, 0x01361B0, 0x00BFBBF, 0x00A805D, 0x00FB4D5, 0x01F69AB, 0x02A0174, 0x021FAA8, 0x0180DC9, 0x0087EAA, 0x00CFD8F, 0x019FB1E, 0x00E0B52, -}; - -static const int32_t qmat0C[MAT_SIZE] = { +}, +[QMAT0C] = { 0x0040000, 0x004DACA, 0x0026D65, 0x004DBD9, 0x00393C4, 0x004DBD9, 0x004A148, 0x0039160, 0x00722C1, 0x004A148, 0x003F000, 0x0066C09, 0x007185D, 0x0033604, 0x003F000, 0x00343FB, 0x002E1E8, 0x00662AF, @@ -225,9 +281,8 @@ static const int32_t qmat0C[MAT_SIZE] = { 0x00F23E1, 0x00DE8DF, 0x00B5D78, 0x005F111, 0x005AEBC, 0x0037A38, 0x006187D, 0x0091D95, 0x0123B29, 0x01861F3, 0x013B9F0, 0x00DF7A4, 0x004EE7C, 0x00793E9, 0x00F27D1, 0x0083145, -}; - -static const int32_t qmat0D[MAT_SIZE] = { +}, +[QMAT0D] = { 0x0040000, 0x004DACA, 0x0026D65, 0x004DBD9, 0x00393C4, 0x004DBD9, 0x0066E3A, 0x004F494, 0x009E928, 0x0066E3A, 0x005B000, 0x008EB61, 0x009B58C, 0x00475B1, 0x005B000, 0x00477F9, 0x003F1C4, 0x00912F8, @@ -239,9 +294,8 @@ static const int32_t qmat0D[MAT_SIZE] = { 0x01E47C3, 0x037EC27, 0x02D3944, 0x017E6D8, 0x0169CA2, 0x00DFB0A, 0x00C406D, 0x01252F9, 0x024A5F2, 0x03101B2, 0x027A46F, 0x01C1016, 0x009E91C, 0x00F27D1, 0x01E4FA3, 0x010628B, -}; - -static const int32_t qmat0E[MAT_SIZE] = { +}, +[QMAT0E] = { 0x0040000, 0x0058C54, 0x002C62A, 0x0058D8A, 0x0041697, 0x0058D8A, 0x0054A9C, 0x00413DC, 0x00827B8, 0x0054A9C, 0x0048000, 0x00756E5, 0x0081BD8, 0x003AB73, 0x0048000, 0x003BB68, 0x0034B52, 0x0074C35, @@ -253,9 +307,8 @@ static const int32_t qmat0E[MAT_SIZE] = { 0x0114D94, 0x00FE591, 0x00CFD1C, 0x006CA5D, 0x0067E8E, 0x003F964, 0x006F76A, 0x00A6AF3, 0x014D5E6, 0x01BDDA8, 0x0168B5C, 0x00FF672, 0x005A2D7, 0x008A90A, 0x0115214, 0x0095CE2, -}; - -static const int32_t qmat0F[MAT_SIZE] = { +}, +[QMAT0F] = { 0x0040000, 0x0058C54, 0x002C62A, 0x0058D8A, 0x0041697, 0x0058D8A, 0x0075967, 0x005A9CE, 0x00B539C, 0x0075967, 0x0068000, 0x00A3194, 0x00B18A0, 0x00518CA, 0x0068000, 0x0051B65, 0x0048204, 0x00A5ED3, @@ -267,9 +320,8 @@ static const int32_t qmat0F[MAT_SIZE] = { 0x0229B27, 0x03FE951, 0x033AF2A, 0x01B50F6, 0x019D795, 0x00FFA54, 0x00E007C, 0x014F11C, 0x029E239, 0x03801F0, 0x02D4E36, 0x0201262, 0x00B538D, 0x0115214, 0x022A428, 0x012B9C3, -}; - -static const int32_t qmat10[MAT_SIZE] = { +}, +[QMAT10] = { 0x0040000, 0x006EF69, 0x00377B5, 0x006F0ED, 0x0051C3D, 0x006F0ED, 0x0069D43, 0x00518D3, 0x00A31A6, 0x0069D43, 0x005A000, 0x0092C9F, 0x00A22CD, 0x004964F, 0x005A000, 0x004AA42, 0x0041E26, 0x0091F43, @@ -281,9 +333,8 @@ static const int32_t qmat10[MAT_SIZE] = { 0x015A0F9, 0x013DEF5, 0x0103C63, 0x0087CF4, 0x0081E31, 0x004F7BD, 0x008B544, 0x00D05B0, 0x01A0B5F, 0x022D511, 0x01C2E32, 0x013F40F, 0x0070B8D, 0x00AD34C, 0x015A699, 0x00BB41A, -}; - -static const int32_t qmat11[MAT_SIZE] = { +}, +[QMAT11] = { 0x0040000, 0x006EF69, 0x00377B5, 0x006F0ED, 0x0051C3D, 0x006F0ED, 0x0092FC0, 0x0071441, 0x00E2883, 0x0092FC0, 0x0082000, 0x00CBDF9, 0x00DDEC8, 0x0065EFC, 0x0082000, 0x006623F, 0x005A285, 0x00CF687, @@ -295,9 +346,8 @@ static const int32_t qmat11[MAT_SIZE] = { 0x02B41F1, 0x04FE3A6, 0x0409AF4, 0x0222534, 0x0204D7A, 0x013F8E9, 0x011809B, 0x01A2D64, 0x0345AC7, 0x046026C, 0x038A1C3, 0x02816FA, 0x00E2871, 0x015A699, 0x02B4D32, 0x0176834, -}; - -static const int32_t qmat12[MAT_SIZE] = { +}, +[QMAT12] = { 0x0040000, 0x008527E, 0x004293F, 0x0085450, 0x00621E3, 0x0085450, 0x007EFEA, 0x0061DCA, 0x00C3B94, 0x007EFEA, 0x006C000, 0x00B0258, 0x00C29C3, 0x005812C, 0x006C000, 0x005991C, 0x004F0FB, 0x00AF250, @@ -309,9 +359,8 @@ static const int32_t qmat12[MAT_SIZE] = { 0x019F45E, 0x017D85A, 0x0137BAA, 0x00A2F8C, 0x009BDD5, 0x005F616, 0x00A731F, 0x00FA06C, 0x01F40D9, 0x029CC7B, 0x021D109, 0x017F1AB, 0x0087442, 0x00CFD8F, 0x019FB1E, 0x00E0B52, -}; - -static const int32_t qmat13[MAT_SIZE] = { +}, +[QMAT13] = { 0x0040000, 0x008527E, 0x004293F, 0x0085450, 0x00621E3, 0x0085450, 0x00B061A, 0x0087EB5, 0x010FD69, 0x00B061A, 0x009C000, 0x00F4A5E, 0x010A4F0, 0x007A52F, 0x009C000, 0x007A918, 0x006C307, 0x00F8E3C, @@ -323,9 +372,8 @@ static const int32_t qmat13[MAT_SIZE] = { 0x033E8BB, 0x05FDDFA, 0x04D86BE, 0x028F971, 0x026C35F, 0x017F77F, 0x01500BA, 0x01F69AB, 0x03ED355, 0x05402E9, 0x043F550, 0x0301B93, 0x010FD54, 0x019FB1E, 0x033F63C, 0x01C16A5, -}; - -static const int32_t qmat14[MAT_SIZE] = { +}, +[QMAT14] = { 0x0040000, 0x009B593, 0x004DACA, 0x009B7B2, 0x0072789, 0x009B7B2, 0x0094291, 0x00722C1, 0x00E4582, 0x0094291, 0x007E000, 0x00CD812, 0x00E30B9, 0x0066C09, 0x007E000, 0x00687F5, 0x005C3CF, 0x00CC55D, @@ -337,9 +385,8 @@ static const int32_t qmat14[MAT_SIZE] = { 0x01E47C3, 0x01BD1BE, 0x016BAF1, 0x00BE223, 0x00B5D78, 0x006F46F, 0x00C30F9, 0x0123B29, 0x0247652, 0x030C3E5, 0x02773E0, 0x01BEF48, 0x009DCF8, 0x00F27D1, 0x01E4FA3, 0x010628B, -}; - -static const int32_t qmat15[MAT_SIZE] = { +}, +[QMAT15] = { 0x0040000, 0x009B593, 0x004DACA, 0x009B7B2, 0x0072789, 0x009B7B2, 0x00CDC74, 0x009E928, 0x013D250, 0x00CDC74, 0x00B6000, 0x011D6C3, 0x0136B18, 0x008EB61, 0x00B6000, 0x008EFF2, 0x007E388, 0x01225F0, @@ -351,9 +398,8 @@ static const int32_t qmat15[MAT_SIZE] = { 0x03C8F85, 0x06FD84F, 0x05A7289, 0x02FCDAF, 0x02D3944, 0x01BF614, 0x01880D9, 0x024A5F2, 0x0494BE4, 0x0620365, 0x04F48DE, 0x038202B, 0x013D237, 0x01E4FA3, 0x03C9F46, 0x020C516, -}; - -static const int32_t qmat16[MAT_SIZE] = { +}, +[QMAT16] = { 0x0040000, 0x00B18A8, 0x0058C54, 0x00B1B15, 0x0082D2E, 0x00B1B15, 0x00A9538, 0x00827B8, 0x0104F6F, 0x00A9538, 0x0090000, 0x00EADCB, 0x01037AF, 0x00756E5, 0x0090000, 0x00776CF, 0x00696A4, 0x00E986B, @@ -365,9 +411,8 @@ static const int32_t qmat16[MAT_SIZE] = { 0x0229B27, 0x01FCB22, 0x019FA38, 0x00D94BA, 0x00CFD1C, 0x007F2C9, 0x00DEED4, 0x014D5E6, 0x029ABCC, 0x037BB4F, 0x02D16B7, 0x01FECE4, 0x00B45AE, 0x0115214, 0x022A428, 0x012B9C3, -}; - -static const int32_t qmat17[MAT_SIZE] = { +}, +[QMAT17] = { 0x0040000, 0x00B18A8, 0x0058C54, 0x00B1B15, 0x0082D2E, 0x00B1B15, 0x00EB2CD, 0x00B539C, 0x016A737, 0x00EB2CD, 0x00D0000, 0x0146328, 0x0163140, 0x00A3194, 0x00D0000, 0x00A36CB, 0x0090409, 0x014BDA5, @@ -379,9 +424,8 @@ static const int32_t qmat17[MAT_SIZE] = { 0x045364F, 0x07FD2A3, 0x0675E53, 0x036A1ED, 0x033AF2A, 0x01FF4A9, 0x01C00F8, 0x029E239, 0x053C472, 0x07003E1, 0x05A9C6B, 0x04024C4, 0x016A71B, 0x022A428, 0x0454850, 0x0257386, -}; - -static const int32_t qmat18[MAT_SIZE] = { +}, +[QMAT18] = { 0x0040000, 0x00C7BBD, 0x0063DDF, 0x00C7E77, 0x00932D4, 0x00C7E77, 0x00BE7DF, 0x0092CAF, 0x012595D, 0x00BE7DF, 0x00A2000, 0x0108384, 0x0123EA5, 0x00841C2, 0x00A2000, 0x00865A9, 0x0076978, 0x0106B78, @@ -393,9 +437,8 @@ static const int32_t qmat18[MAT_SIZE] = { 0x026EE8C, 0x023C486, 0x01D397F, 0x00F4751, 0x00E9CBF, 0x008F122, 0x00FACAE, 0x01770A2, 0x02EE145, 0x03EB2B9, 0x032B98E, 0x023EA81, 0x00CAE64, 0x0137C56, 0x026F8AD, 0x01510FC, -}; - -static const int32_t qmat19[MAT_SIZE] = { +}, +[QMAT19] = { 0x0040000, 0x00C7BBD, 0x0063DDF, 0x00C7E77, 0x00932D4, 0x00C7E77, 0x0108927, 0x00CBE0F, 0x0197C1E, 0x0108927, 0x00EA000, 0x016EF8D, 0x018F768, 0x00B77C6, 0x00EA000, 0x00B7DA4, 0x00A248A, 0x017555A, @@ -407,9 +450,8 @@ static const int32_t qmat19[MAT_SIZE] = { 0x04DDD19, 0x08FCCF7, 0x0744A1D, 0x03D762A, 0x03A250F, 0x023F33E, 0x01F8117, 0x02F1E80, 0x05E3D00, 0x07E045D, 0x065EFF9, 0x048295C, 0x0197BFE, 0x026F8AD, 0x04DF15A, 0x02A21F7, -}; - -static const int32_t qmat1A[MAT_SIZE] = { +}, +[QMAT1A] = { 0x0040000, 0x00DDED2, 0x006EF69, 0x00DE1DA, 0x00A387A, 0x00DE1DA, 0x00D3A86, 0x00A31A6, 0x014634B, 0x00D3A86, 0x00B4000, 0x012593E, 0x014459B, 0x0092C9F, 0x00B4000, 0x0095483, 0x0083C4D, 0x0123E85, @@ -421,9 +463,8 @@ static const int32_t qmat1A[MAT_SIZE] = { 0x02B41F1, 0x027BDEB, 0x02078C6, 0x010F9E9, 0x0103C63, 0x009EF7B, 0x0116A89, 0x01A0B5F, 0x03416BE, 0x045AA23, 0x0385C65, 0x027E81E, 0x00E1719, 0x015A699, 0x02B4D32, 0x0176834, -}; - -static const int32_t qmat1B[MAT_SIZE] = { +}, +[QMAT1B] = { 0x0040000, 0x00DDED2, 0x006EF69, 0x00DE1DA, 0x00A387A, 0x00DE1DA, 0x0125F81, 0x00E2883, 0x01C5105, 0x0125F81, 0x0104000, 0x0197BF2, 0x01BBD90, 0x00CBDF9, 0x0104000, 0x00CC47E, 0x00B450B, 0x019ED0E, @@ -435,9 +476,8 @@ static const int32_t qmat1B[MAT_SIZE] = { 0x05683E3, 0x09FC74C, 0x08135E8, 0x0444A68, 0x0409AF4, 0x027F1D3, 0x0230136, 0x0345AC7, 0x068B58E, 0x08C04D9, 0x0714386, 0x0502DF5, 0x01C50E1, 0x02B4D32, 0x0569A64, 0x02ED068, -}; - -static const int32_t qmat1C[MAT_SIZE] = { +}, +[QMAT1C] = { 0x0040000, 0x00F41E7, 0x007A0F4, 0x00F453D, 0x00B3E20, 0x00F453D, 0x00E8D2D, 0x00B369D, 0x0166D39, 0x00E8D2D, 0x00C6000, 0x0142EF7, 0x0164C91, 0x00A177B, 0x00C6000, 0x00A435D, 0x0090F21, 0x0141193, @@ -449,9 +489,8 @@ static const int32_t qmat1C[MAT_SIZE] = { 0x02F9556, 0x02BB74F, 0x023B80D, 0x012AC80, 0x011DC06, 0x00AEDD4, 0x0132863, 0x01CA61C, 0x0394C38, 0x04CA18D, 0x03DFF3C, 0x02BE5BA, 0x00F7FCF, 0x017D0DB, 0x02FA1B7, 0x019BF6C, -}; - -static const int32_t qmat1D[MAT_SIZE] = { +}, +[QMAT1D] = { 0x0040000, 0x00F41E7, 0x007A0F4, 0x00F453D, 0x00B3E20, 0x00F453D, 0x01435DA, 0x00F92F6, 0x01F25EC, 0x01435DA, 0x011E000, 0x01C0857, 0x01E83B8, 0x00E042B, 0x011E000, 0x00E0B57, 0x00C658C, 0x01C84C3, @@ -463,9 +502,8 @@ static const int32_t qmat1D[MAT_SIZE] = { 0x05F2AAD, 0x0AFC1A0, 0x08E21B2, 0x04B1EA5, 0x04710D9, 0x02BF068, 0x0268155, 0x039970E, 0x0732E1D, 0x09A0555, 0x07C9713, 0x058328D, 0x01F25C5, 0x02FA1B7, 0x05F436E, 0x0337ED9, -}; - -static const int32_t qmat1E[MAT_SIZE] = { +}, +[QMAT1E] = { 0x0040000, 0x010A4FD, 0x008527E, 0x010A89F, 0x00C43C5, 0x010A89F, 0x00FDFD3, 0x00C3B94, 0x0187727, 0x00FDFD3, 0x00D8000, 0x01604B0, 0x0185387, 0x00B0258, 0x00D8000, 0x00B3237, 0x009E1F6, 0x015E4A0, @@ -477,9 +515,8 @@ static const int32_t qmat1E[MAT_SIZE] = { 0x033E8BB, 0x02FB0B3, 0x026F754, 0x0145F17, 0x0137BAA, 0x00BEC2D, 0x014E63E, 0x01F40D9, 0x03E81B1, 0x05398F7, 0x043A213, 0x02FE357, 0x010E885, 0x019FB1E, 0x033F63C, 0x01C16A5, -}; - -static const int32_t qmat1F[MAT_SIZE] = { +}, +[QMAT1F] = { 0x0040000, 0x010A4FD, 0x008527E, 0x010A89F, 0x00C43C5, 0x010A89F, 0x0160C34, 0x010FD69, 0x021FAD3, 0x0160C34, 0x0138000, 0x01E94BC, 0x02149E1, 0x00F4A5E, 0x0138000, 0x00F5230, 0x00D860D, 0x01F1C78, @@ -491,9 +528,8 @@ static const int32_t qmat1F[MAT_SIZE] = { 0x067D176, 0x0BFBBF4, 0x09B0D7D, 0x051F2E3, 0x04D86BE, 0x02FEEFD, 0x02A0174, 0x03ED355, 0x07DA6AB, 0x0A805D1, 0x087EAA1, 0x0603726, 0x021FAA8, 0x033F63C, 0x067EC78, 0x0382D4A, -}; - -static const int32_t qmat20[MAT_SIZE] = { +}, +[QMAT20] = { 0x0040000, 0x0136B27, 0x009B593, 0x0136F64, 0x00E4F11, 0x0136F64, 0x0128521, 0x00E4582, 0x01C8B03, 0x0128521, 0x00FC000, 0x019B023, 0x01C6172, 0x00CD812, 0x00FC000, 0x00D0FEB, 0x00B879F, 0x0198ABB, @@ -505,9 +541,8 @@ static const int32_t qmat20[MAT_SIZE] = { 0x03C8F85, 0x037A37C, 0x02D75E2, 0x017C446, 0x016BAF1, 0x00DE8DF, 0x01861F3, 0x0247652, 0x048ECA4, 0x06187CA, 0x04EE7C1, 0x037DE90, 0x013B9F0, 0x01E4FA3, 0x03C9F46, 0x020C516, -}; - -static const int32_t qmat21[MAT_SIZE] = { +}, +[QMAT21] = { 0x0040000, 0x0136B27, 0x009B593, 0x0136F64, 0x00E4F11, 0x0136F64, 0x019B8E7, 0x013D250, 0x027A4A1, 0x019B8E7, 0x016C000, 0x023AD86, 0x026D631, 0x011D6C3, 0x016C000, 0x011DFE3, 0x00FC70F, 0x0244BE1, @@ -519,9 +554,8 @@ static const int32_t qmat21[MAT_SIZE] = { 0x0791F0A, 0x0DFB09D, 0x0B4E511, 0x05F9B5E, 0x05A7289, 0x037EC27, 0x03101B2, 0x0494BE4, 0x09297C7, 0x0C406C9, 0x09E91BC, 0x0704057, 0x027A46F, 0x03C9F46, 0x0793E8C, 0x0418A2B, -}; - -static const int32_t qmat22[MAT_SIZE] = { +}, +[QMAT22] = { 0x0040000, 0x0163151, 0x00B18A8, 0x0163629, 0x0105A5D, 0x0163629, 0x0152A6F, 0x0104F6F, 0x0209EDF, 0x0152A6F, 0x0120000, 0x01D5B96, 0x0206F5E, 0x00EADCB, 0x0120000, 0x00EED9F, 0x00D2D48, 0x01D30D5, @@ -533,9 +567,8 @@ static const int32_t qmat22[MAT_SIZE] = { 0x045364F, 0x03F9644, 0x033F46F, 0x01B2974, 0x019FA38, 0x00FE591, 0x01BDDA8, 0x029ABCC, 0x0535797, 0x06F769E, 0x05A2D6E, 0x03FD9C9, 0x0168B5C, 0x022A428, 0x0454850, 0x0257386, -}; - -static const int32_t qmat23[MAT_SIZE] = { +}, +[QMAT23] = { 0x0040000, 0x0163151, 0x00B18A8, 0x0163629, 0x0105A5D, 0x0163629, 0x01D659B, 0x016A737, 0x02D4E6E, 0x01D659B, 0x01A0000, 0x028C650, 0x02C6281, 0x0146328, 0x01A0000, 0x0146D96, 0x0120812, 0x0297B4A, @@ -547,9 +580,8 @@ static const int32_t qmat23[MAT_SIZE] = { 0x08A6C9E, 0x0FFA546, 0x0CEBCA6, 0x06D43D9, 0x0675E53, 0x03FE951, 0x03801F0, 0x053C472, 0x0A788E4, 0x0E007C1, 0x0B538D6, 0x0804988, 0x02D4E36, 0x0454850, 0x08A90A0, 0x04AE70D, -}; - -static const int32_t qmat24[MAT_SIZE] = { +}, +[QMAT24] = { 0x0040000, 0x018F77B, 0x00C7BBD, 0x018FCEF, 0x01265A8, 0x018FCEF, 0x017CFBD, 0x012595D, 0x024B2BB, 0x017CFBD, 0x0144000, 0x0210708, 0x0247D4A, 0x0108384, 0x0144000, 0x010CB53, 0x00ED2F1, 0x020D6F0, @@ -561,9 +593,8 @@ static const int32_t qmat24[MAT_SIZE] = { 0x04DDD19, 0x047890D, 0x03A72FD, 0x01E8EA3, 0x01D397F, 0x011E243, 0x01F595C, 0x02EE145, 0x05DC28A, 0x07D6572, 0x065731C, 0x047D502, 0x0195CC7, 0x026F8AD, 0x04DF15A, 0x02A21F7, -}; - -static const int32_t qmat25[MAT_SIZE] = { +}, +[QMAT25] = { 0x0040000, 0x018F77B, 0x00C7BBD, 0x018FCEF, 0x01265A8, 0x018FCEF, 0x021124E, 0x0197C1E, 0x032F83C, 0x021124E, 0x01D4000, 0x02DDF1A, 0x031EED1, 0x016EF8D, 0x01D4000, 0x016FB49, 0x0144914, 0x02EAAB3, @@ -575,9 +606,8 @@ static const int32_t qmat25[MAT_SIZE] = { 0x09BBA32, 0x11F99EF, 0x0E8943B, 0x07AEC54, 0x0744A1D, 0x047E67C, 0x03F022E, 0x05E3D00, 0x0BC7A00, 0x0FC08BA, 0x0CBDFF1, 0x09052B9, 0x032F7FC, 0x04DF15A, 0x09BE2B4, 0x05443EE, -}; - -static const int32_t qmat26[MAT_SIZE] = { +}, +[QMAT26] = { 0x0040000, 0x01BBDA5, 0x00DDED2, 0x01BC3B4, 0x01470F4, 0x01BC3B4, 0x01A750B, 0x014634B, 0x028C697, 0x01A750B, 0x0168000, 0x024B27B, 0x0288B36, 0x012593E, 0x0168000, 0x012A906, 0x010789A, 0x0247D0B, @@ -589,9 +619,8 @@ static const int32_t qmat26[MAT_SIZE] = { 0x05683E3, 0x04F7BD5, 0x040F18B, 0x021F3D1, 0x02078C6, 0x013DEF5, 0x022D511, 0x03416BE, 0x0682D7D, 0x08B5446, 0x070B8CA, 0x04FD03B, 0x01C2E32, 0x02B4D32, 0x0569A64, 0x02ED068, -}; - -static const int32_t qmat27[MAT_SIZE] = { +}, +[QMAT27] = { 0x0040000, 0x01BBDA5, 0x00DDED2, 0x01BC3B4, 0x01470F4, 0x01BC3B4, 0x024BF01, 0x01C5105, 0x038A20A, 0x024BF01, 0x0208000, 0x032F7E4, 0x0377B21, 0x0197BF2, 0x0208000, 0x01988FB, 0x0168A16, 0x033DA1D, @@ -603,9 +632,8 @@ static const int32_t qmat27[MAT_SIZE] = { 0x0AD07C5, 0x13F8E97, 0x1026BD0, 0x08894CF, 0x08135E8, 0x04FE3A6, 0x046026C, 0x068B58E, 0x0D16B1D, 0x11809B2, 0x0E2870C, 0x0A05BEA, 0x038A1C3, 0x0569A64, 0x0AD34C8, 0x05DA0D0, -}; - -static const int32_t qmat28[MAT_SIZE] = { +}, +[QMAT28] = { 0x0040000, 0x01E83CF, 0x00F41E7, 0x01E8A79, 0x0167C3F, 0x01E8A79, 0x01D1A59, 0x0166D39, 0x02CDA72, 0x01D1A59, 0x018C000, 0x0285DEE, 0x02C9921, 0x0142EF7, 0x018C000, 0x01486BA, 0x0121E43, 0x0282325, @@ -617,9 +645,8 @@ static const int32_t qmat28[MAT_SIZE] = { 0x05F2AAD, 0x0576E9E, 0x0477019, 0x0255900, 0x023B80D, 0x015DBA7, 0x02650C6, 0x0394C38, 0x0729870, 0x0994319, 0x07BFE78, 0x057CB74, 0x01EFF9E, 0x02FA1B7, 0x05F436E, 0x0337ED9, -}; - -static const int32_t qmat29[MAT_SIZE] = { +}, +[QMAT29] = { 0x0040000, 0x01E83CF, 0x00F41E7, 0x01E8A79, 0x0167C3F, 0x01E8A79, 0x0286BB5, 0x01F25EC, 0x03E4BD8, 0x0286BB5, 0x023C000, 0x03810AE, 0x03D0771, 0x01C0857, 0x023C000, 0x01C16AE, 0x018CB18, 0x0390986, @@ -631,9 +658,8 @@ static const int32_t qmat29[MAT_SIZE] = { 0x0BE5559, 0x15F8340, 0x11C4364, 0x0963D4B, 0x08E21B2, 0x057E0D0, 0x04D02AB, 0x0732E1D, 0x0E65C39, 0x1340AAA, 0x0F92E27, 0x0B0651B, 0x03E4B8A, 0x05F436E, 0x0BE86DC, 0x066FDB2, -}; - -static const int32_t qmat2A[MAT_SIZE] = { +}, +[QMAT2A] = { 0x0040000, 0x02149F9, 0x010A4FD, 0x021513E, 0x018878B, 0x021513E, 0x01FBFA7, 0x0187727, 0x030EE4E, 0x01FBFA7, 0x01B0000, 0x02C0961, 0x030A70D, 0x01604B0, 0x01B0000, 0x016646E, 0x013C3EC, 0x02BC940, @@ -645,9 +671,8 @@ static const int32_t qmat2A[MAT_SIZE] = { 0x067D176, 0x05F6166, 0x04DEEA7, 0x028BE2E, 0x026F754, 0x017D85A, 0x029CC7B, 0x03E81B1, 0x07D0363, 0x0A731ED, 0x0874425, 0x05FC6AD, 0x021D109, 0x033F63C, 0x067EC78, 0x0382D4A, -}; - -static const int32_t qmat2B[MAT_SIZE] = { +}, +[QMAT2B] = { 0x0040000, 0x02149F9, 0x010A4FD, 0x021513E, 0x018878B, 0x021513E, 0x02C1868, 0x021FAD3, 0x043F5A6, 0x02C1868, 0x0270000, 0x03D2978, 0x04293C1, 0x01E94BC, 0x0270000, 0x01EA461, 0x01B0C1A, 0x03E38EF, @@ -659,9 +684,8 @@ static const int32_t qmat2B[MAT_SIZE] = { 0x0CFA2ED, 0x17F77E9, 0x1361AF9, 0x0A3E5C6, 0x09B0D7D, 0x05FDDFA, 0x05402E9, 0x07DA6AB, 0x0FB4D56, 0x1500BA2, 0x10FD541, 0x0C06E4C, 0x043F550, 0x067EC78, 0x0CFD8F0, 0x0705A93, -}; - -static const int32_t qmat2C[MAT_SIZE] = { +}, +[QMAT2C] = { 0x0040000, 0x0241023, 0x0120812, 0x0241803, 0x01A92D7, 0x0241803, 0x02264F5, 0x01A8115, 0x035022A, 0x02264F5, 0x01D4000, 0x02FB4D3, 0x034B4F9, 0x017DA6A, 0x01D4000, 0x0184222, 0x0156995, 0x02F6F5B, @@ -673,9 +697,8 @@ static const int32_t qmat2C[MAT_SIZE] = { 0x0707840, 0x067542F, 0x0546D35, 0x02C235D, 0x02A369B, 0x019D50C, 0x02D4830, 0x043B72B, 0x0876E56, 0x0B520C1, 0x09289D3, 0x067C1E6, 0x024A275, 0x0384AC1, 0x0709582, 0x03CDBBA, -}; - -static const int32_t qmat2D[MAT_SIZE] = { +}, +[QMAT2D] = { 0x0040000, 0x0241023, 0x0120812, 0x0241803, 0x01A92D7, 0x0241803, 0x02FC51B, 0x024CFBA, 0x0499F73, 0x02FC51B, 0x02A4000, 0x0424242, 0x0482011, 0x0212121, 0x02A4000, 0x0213214, 0x01D4D1D, 0x0436858, @@ -687,9 +710,8 @@ static const int32_t qmat2D[MAT_SIZE] = { 0x0E0F081, 0x19F6C92, 0x14FF28E, 0x0B18E41, 0x0A7F947, 0x067DB24, 0x05B0327, 0x0881F39, 0x1103E72, 0x16C0C9A, 0x1267C5C, 0x0D0777D, 0x0499F17, 0x0709582, 0x0E12B04, 0x079B775, -}; - -static const int32_t qmat2E[MAT_SIZE] = { +}, +[QMAT2E] = { 0x0040000, 0x026D64D, 0x0136B27, 0x026DEC9, 0x01C9E22, 0x026DEC9, 0x0250A43, 0x01C8B03, 0x0391606, 0x0250A43, 0x01F8000, 0x0336046, 0x038C2E5, 0x019B023, 0x01F8000, 0x01A1FD6, 0x0170F3E, 0x0331575, @@ -701,9 +723,8 @@ static const int32_t qmat2E[MAT_SIZE] = { 0x0791F0A, 0x06F46F7, 0x05AEBC3, 0x02F888B, 0x02D75E2, 0x01BD1BE, 0x030C3E5, 0x048ECA4, 0x091D948, 0x0C30F95, 0x09DCF81, 0x06FBD20, 0x02773E0, 0x03C9F46, 0x0793E8C, 0x0418A2B, -}; - -static const int32_t qmat2F[MAT_SIZE] = { +}, +[QMAT2F] = { 0x0040000, 0x026D64D, 0x0136B27, 0x026DEC9, 0x01C9E22, 0x026DEC9, 0x03371CF, 0x027A4A1, 0x04F4941, 0x03371CF, 0x02D8000, 0x0475B0C, 0x04DAC61, 0x023AD86, 0x02D8000, 0x023BFC6, 0x01F8E1F, 0x04897C2, @@ -715,9 +736,8 @@ static const int32_t qmat2F[MAT_SIZE] = { 0x0F23E14, 0x1BF613A, 0x169CA23, 0x0BF36BC, 0x0B4E511, 0x06FD84F, 0x0620365, 0x09297C7, 0x1252F8F, 0x1880D93, 0x13D2377, 0x0E080AE, 0x04F48DE, 0x0793E8C, 0x0F27D18, 0x0831457, -}; - -static const int32_t qmat30[MAT_SIZE] = { +}, +[QMAT30] = { 0x0040000, 0x02C62A1, 0x0163151, 0x02C6C53, 0x020B4B9, 0x02C6C53, 0x02A54DF, 0x0209EDF, 0x0413DBE, 0x02A54DF, 0x0240000, 0x03AB72B, 0x040DEBC, 0x01D5B96, 0x0240000, 0x01DDB3E, 0x01A5A90, 0x03A61AB, @@ -729,9 +749,8 @@ static const int32_t qmat30[MAT_SIZE] = { 0x08A6C9E, 0x07F2C88, 0x067E8DF, 0x03652E8, 0x033F46F, 0x01FCB22, 0x037BB4F, 0x0535797, 0x0A6AF2E, 0x0DEED3C, 0x0B45ADD, 0x07FB392, 0x02D16B7, 0x0454850, 0x08A90A0, 0x04AE70D, -}; - -static const int32_t qmat31[MAT_SIZE] = { +}, +[QMAT31] = { 0x0040000, 0x02C62A1, 0x0163151, 0x02C6C53, 0x020B4B9, 0x02C6C53, 0x03ACB35, 0x02D4E6E, 0x05A9CDD, 0x03ACB35, 0x0340000, 0x0518CA0, 0x058C501, 0x028C650, 0x0340000, 0x028DB2C, 0x0241023, 0x052F694, @@ -743,9 +762,8 @@ static const int32_t qmat31[MAT_SIZE] = { 0x114D93C, 0x1FF4A8C, 0x19D794C, 0x0DA87B2, 0x0CEBCA6, 0x07FD2A3, 0x07003E1, 0x0A788E4, 0x14F11C8, 0x1C00F83, 0x16A71AD, 0x1009310, 0x05A9C6B, 0x08A90A0, 0x1152140, 0x095CE1A, -}; - -static const int32_t qmat32[MAT_SIZE] = { +}, +[QMAT32] = { 0x0040000, 0x031EEF6, 0x018F77B, 0x031F9DD, 0x024CB50, 0x031F9DD, 0x02F9F7A, 0x024B2BB, 0x0496575, 0x02F9F7A, 0x0288000, 0x0420E11, 0x048FA94, 0x0210708, 0x0288000, 0x02196A5, 0x01DA5E2, 0x041ADE0, @@ -757,9 +775,8 @@ static const int32_t qmat32[MAT_SIZE] = { 0x09BBA32, 0x08F1219, 0x074E5FB, 0x03D1D45, 0x03A72FD, 0x023C486, 0x03EB2B9, 0x05DC28A, 0x0BB8514, 0x0FACAE4, 0x0CAE638, 0x08FAA04, 0x032B98E, 0x04DF15A, 0x09BE2B4, 0x05443EE, -}; - -static const int32_t qmat33[MAT_SIZE] = { +}, +[QMAT33] = { 0x0040000, 0x031EEF6, 0x018F77B, 0x031F9DD, 0x024CB50, 0x031F9DD, 0x042249C, 0x032F83C, 0x065F078, 0x042249C, 0x03A8000, 0x05BBE34, 0x063DDA2, 0x02DDF1A, 0x03A8000, 0x02DF691, 0x0289228, 0x05D5567, @@ -771,9 +788,8 @@ static const int32_t qmat33[MAT_SIZE] = { 0x1377463, 0x23F33DD, 0x1D12876, 0x0F5D8A9, 0x0E8943B, 0x08FCCF7, 0x07E045D, 0x0BC7A00, 0x178F401, 0x1F81173, 0x197BFE2, 0x120A572, 0x065EFF9, 0x09BE2B4, 0x137C568, 0x0A887DD, -}; - -static const int32_t qmat34[MAT_SIZE] = { +}, +[QMAT34] = { 0x0040000, 0x0377B4A, 0x01BBDA5, 0x0378768, 0x028E1E8, 0x0378768, 0x034EA16, 0x028C697, 0x0518D2D, 0x034EA16, 0x02D0000, 0x04964F6, 0x051166B, 0x024B27B, 0x02D0000, 0x025520D, 0x020F134, 0x048FA15, @@ -785,9 +801,8 @@ static const int32_t qmat34[MAT_SIZE] = { 0x0AD07C5, 0x09EF7AA, 0x081E317, 0x043E7A2, 0x040F18B, 0x027BDEB, 0x045AA23, 0x0682D7D, 0x0D05AFA, 0x116A88B, 0x0E17194, 0x09FA076, 0x0385C65, 0x0569A64, 0x0AD34C8, 0x05DA0D0, -}; - -static const int32_t qmat35[MAT_SIZE] = { +}, +[QMAT35] = { 0x0040000, 0x0377B4A, 0x01BBDA5, 0x0378768, 0x028E1E8, 0x0378768, 0x0497E02, 0x038A20A, 0x0714414, 0x0497E02, 0x0410000, 0x065EFC8, 0x06EF642, 0x032F7E4, 0x0410000, 0x03311F7, 0x02D142C, 0x067B439, @@ -799,9 +814,8 @@ static const int32_t qmat35[MAT_SIZE] = { 0x15A0F8B, 0x27F1D2F, 0x204D79F, 0x111299F, 0x1026BD0, 0x09FC74C, 0x08C04D9, 0x0D16B1D, 0x1A2D63A, 0x2301364, 0x1C50E18, 0x140B7D4, 0x0714386, 0x0AD34C8, 0x15A6990, 0x0BB41A0, -}; - -static const int32_t qmat36[MAT_SIZE] = { +}, +[QMAT36] = { 0x0040000, 0x03D079E, 0x01E83CF, 0x03D14F2, 0x02CF87F, 0x03D14F2, 0x03A34B2, 0x02CDA72, 0x059B4E5, 0x03A34B2, 0x0318000, 0x050BBDC, 0x0593243, 0x0285DEE, 0x0318000, 0x0290D75, 0x0243C86, 0x050464B, @@ -813,9 +827,8 @@ static const int32_t qmat36[MAT_SIZE] = { 0x0BE5559, 0x0AEDD3B, 0x08EE032, 0x04AB1FF, 0x0477019, 0x02BB74F, 0x04CA18D, 0x0729870, 0x0E530E0, 0x1328633, 0x0F7FCEF, 0x0AF96E8, 0x03DFF3C, 0x05F436E, 0x0BE86DC, 0x066FDB2, -}; - -static const int32_t qmat37[MAT_SIZE] = { +}, +[QMAT37] = { 0x0040000, 0x03D079E, 0x01E83CF, 0x03D14F2, 0x02CF87F, 0x03D14F2, 0x050D769, 0x03E4BD8, 0x07C97B0, 0x050D769, 0x0478000, 0x070215C, 0x07A0EE2, 0x03810AE, 0x0478000, 0x0382D5C, 0x0319630, 0x072130C, @@ -827,9 +840,8 @@ static const int32_t qmat37[MAT_SIZE] = { 0x17CAAB2, 0x2BF0680, 0x23886C9, 0x12C7A95, 0x11C4364, 0x0AFC1A0, 0x09A0555, 0x0E65C39, 0x1CCB873, 0x2681554, 0x1F25C4D, 0x160CA36, 0x07C9713, 0x0BE86DC, 0x17D0DB8, 0x0CDFB63, -}; - -static const int32_t qmat38[MAT_SIZE] = { +}, +[QMAT38] = { 0x0040000, 0x04293F2, 0x02149F9, 0x042A27C, 0x0310F16, 0x042A27C, 0x03F7F4E, 0x030EE4E, 0x061DC9D, 0x03F7F4E, 0x0360000, 0x05812C1, 0x0614E1A, 0x02C0961, 0x0360000, 0x02CC8DC, 0x02787D8, 0x0579280, @@ -841,9 +853,8 @@ static const int32_t qmat38[MAT_SIZE] = { 0x0CFA2ED, 0x0BEC2CC, 0x09BDD4E, 0x0517C5D, 0x04DEEA7, 0x02FB0B3, 0x05398F7, 0x07D0363, 0x0FA06C5, 0x14E63DA, 0x10E884B, 0x0BF8D5B, 0x043A213, 0x067EC78, 0x0CFD8F0, 0x0705A93, -}; - -static const int32_t qmat39[MAT_SIZE] = { +}, +[QMAT39] = { 0x0040000, 0x04293F2, 0x02149F9, 0x042A27C, 0x0310F16, 0x042A27C, 0x05830D0, 0x043F5A6, 0x087EB4B, 0x05830D0, 0x04E0000, 0x07A52F0, 0x0852782, 0x03D2978, 0x04E0000, 0x03D48C2, 0x0361835, 0x07C71DE, @@ -855,9 +866,8 @@ static const int32_t qmat39[MAT_SIZE] = { 0x19F45DA, 0x2FEEFD2, 0x26C35F2, 0x147CB8C, 0x1361AF9, 0x0BFBBF4, 0x0A805D1, 0x0FB4D56, 0x1F69AAC, 0x2A01744, 0x21FAA83, 0x180DC98, 0x087EAA1, 0x0CFD8F0, 0x19FB1E0, 0x0E0B527, -}; - -static const int32_t qmat3A[MAT_SIZE] = { +}, +[QMAT3A] = { 0x0040000, 0x0482046, 0x0241023, 0x0483007, 0x03525AD, 0x0483007, 0x044C9EA, 0x035022A, 0x06A0454, 0x044C9EA, 0x03A8000, 0x05F69A7, 0x06969F2, 0x02FB4D3, 0x03A8000, 0x0308444, 0x02AD32A, 0x05EDEB5, @@ -869,9 +879,8 @@ static const int32_t qmat3A[MAT_SIZE] = { 0x0E0F081, 0x0CEA85D, 0x0A8DA6A, 0x05846BA, 0x0546D35, 0x033AA17, 0x05A9060, 0x0876E56, 0x10EDCAB, 0x16A4182, 0x12513A7, 0x0CF83CD, 0x04944EA, 0x0709582, 0x0E12B04, 0x079B775, -}; - -static const int32_t qmat3B[MAT_SIZE] = { +}, +[QMAT3B] = { 0x0040000, 0x0482046, 0x0241023, 0x0483007, 0x03525AD, 0x0483007, 0x05F8A36, 0x0499F73, 0x0933EE7, 0x05F8A36, 0x0548000, 0x0848484, 0x0904022, 0x0424242, 0x0548000, 0x0426427, 0x03A9A39, 0x086D0B1, @@ -883,9 +892,8 @@ static const int32_t qmat3B[MAT_SIZE] = { 0x1C1E101, 0x33ED923, 0x29FE51C, 0x1631C82, 0x14FF28E, 0x0CFB649, 0x0B6064D, 0x1103E72, 0x2207CE5, 0x2D81935, 0x24CF8B9, 0x1A0EEFA, 0x0933E2E, 0x0E12B04, 0x1C25608, 0x0F36EEA, -}; - -static const int32_t qmat3C[MAT_SIZE] = { +}, +[QMAT3C] = { 0x0040000, 0x04DAC9A, 0x026D64D, 0x04DBD91, 0x0393C44, 0x04DBD91, 0x04A1486, 0x0391606, 0x0722C0C, 0x04A1486, 0x03F0000, 0x066C08C, 0x07185C9, 0x0336046, 0x03F0000, 0x0343FAC, 0x02E1E7C, 0x0662AEB, @@ -897,9 +905,8 @@ static const int32_t qmat3C[MAT_SIZE] = { 0x0F23E14, 0x0DE8DEE, 0x0B5D786, 0x05F1117, 0x05AEBC3, 0x037A37C, 0x06187CA, 0x091D948, 0x123B291, 0x1861F29, 0x13B9F02, 0x0DF7A3F, 0x04EE7C1, 0x0793E8C, 0x0F27D18, 0x0831457, -}; - -static const int32_t qmat3D[MAT_SIZE] = { +}, +[QMAT3D] = { 0x0040000, 0x04DAC9A, 0x026D64D, 0x04DBD91, 0x0393C44, 0x04DBD91, 0x066E39D, 0x04F4941, 0x09E9282, 0x066E39D, 0x05B0000, 0x08EB618, 0x09B58C2, 0x0475B0C, 0x05B0000, 0x0477F8D, 0x03F1C3D, 0x0912F83, @@ -911,9 +918,8 @@ static const int32_t qmat3D[MAT_SIZE] = { 0x1E47C29, 0x37EC275, 0x2D39446, 0x17E6D78, 0x169CA23, 0x0DFB09D, 0x0C406C9, 0x1252F8F, 0x24A5F1E, 0x3101B25, 0x27A46EE, 0x1C1015C, 0x09E91BC, 0x0F27D18, 0x1E4FA30, 0x10628AD, -}; - -static const int32_t qmat3E[MAT_SIZE] = { +}, +[QMAT3E] = { 0x0040000, 0x058C543, 0x02C62A1, 0x058D8A6, 0x0416973, 0x058D8A6, 0x054A9BD, 0x0413DBE, 0x0827B7B, 0x054A9BD, 0x0480000, 0x0756E57, 0x081BD78, 0x03AB72B, 0x0480000, 0x03BB67B, 0x034B520, 0x074C355, @@ -925,9 +931,8 @@ static const int32_t qmat3E[MAT_SIZE] = { 0x114D93C, 0x0FE5910, 0x0CFD1BE, 0x06CA5D1, 0x067E8DF, 0x03F9644, 0x06F769E, 0x0A6AF2E, 0x14D5E5C, 0x1BDDA78, 0x168B5B9, 0x0FF6724, 0x05A2D6E, 0x08A90A0, 0x1152140, 0x095CE1A, -}; - -static const int32_t qmat3F[MAT_SIZE] = { +}, +[QMAT3F] = { 0x0040000, 0x058C543, 0x02C62A1, 0x058D8A6, 0x0416973, 0x058D8A6, 0x075966A, 0x05A9CDD, 0x0B539BA, 0x075966A, 0x0680000, 0x0A31940, 0x0B18A03, 0x0518CA0, 0x0680000, 0x051B658, 0x0482046, 0x0A5ED28, @@ -939,9 +944,8 @@ static const int32_t qmat3F[MAT_SIZE] = { 0x229B278, 0x3FE9518, 0x33AF299, 0x1B50F65, 0x19D794C, 0x0FFA546, 0x0E007C1, 0x14F11C8, 0x29E2390, 0x3801F06, 0x2D4E359, 0x2012620, 0x0B538D6, 0x1152140, 0x22A4280, 0x12B9C33, -}; - -static const int32_t qmat40[MAT_SIZE] = { +}, +[QMAT40] = { 0x0040000, 0x063DDEB, 0x031EEF6, 0x063F3BB, 0x04996A1, 0x063F3BB, 0x05F3EF5, 0x0496575, 0x092CAEB, 0x05F3EF5, 0x0510000, 0x0841C22, 0x091F527, 0x0420E11, 0x0510000, 0x0432D4B, 0x03B4BC4, 0x0835BC0, @@ -953,9 +957,8 @@ static const int32_t qmat40[MAT_SIZE] = { 0x1377463, 0x11E2432, 0x0E9CBF6, 0x07A3A8B, 0x074E5FB, 0x047890D, 0x07D6572, 0x0BB8514, 0x1770A28, 0x1F595C7, 0x195CC70, 0x11F5408, 0x065731C, 0x09BE2B4, 0x137C568, 0x0A887DD, -}; - -static const int32_t qmat41[MAT_SIZE] = { +}, +[QMAT41] = { 0x0040000, 0x063DDEB, 0x031EEF6, 0x063F3BB, 0x04996A1, 0x063F3BB, 0x0844938, 0x065F078, 0x0CBE0F1, 0x0844938, 0x0750000, 0x0B77C68, 0x0C7BB43, 0x05BBE34, 0x0750000, 0x05BED23, 0x051244F, 0x0BAAACD, @@ -967,9 +970,8 @@ static const int32_t qmat41[MAT_SIZE] = { 0x26EE8C7, 0x47E67BB, 0x3A250EC, 0x1EBB151, 0x1D12876, 0x11F99EF, 0x0FC08BA, 0x178F401, 0x2F1E802, 0x3F022E7, 0x32F7FC4, 0x2414AE4, 0x0CBDFF1, 0x137C568, 0x26F8AD0, 0x1510FBA, -}; - -static const int32_t qmat42[MAT_SIZE] = { +}, +[QMAT42] = { 0x0040000, 0x06EF693, 0x0377B4A, 0x06F0ECF, 0x051C3CF, 0x06F0ECF, 0x069D42D, 0x0518D2D, 0x0A31A5A, 0x069D42D, 0x05A0000, 0x092C9ED, 0x0A22CD6, 0x04964F6, 0x05A0000, 0x04AA41A, 0x041E268, 0x091F42B, @@ -981,9 +983,8 @@ static const int32_t qmat42[MAT_SIZE] = { 0x15A0F8B, 0x13DEF54, 0x103C62D, 0x087CF45, 0x081E317, 0x04F7BD5, 0x08B5446, 0x0D05AFA, 0x1A0B5F3, 0x22D5116, 0x1C2E328, 0x13F40EC, 0x070B8CA, 0x0AD34C8, 0x15A6990, 0x0BB41A0, -}; - -static const int32_t qmat43[MAT_SIZE] = { +}, +[QMAT43] = { 0x0040000, 0x06EF693, 0x0377B4A, 0x06F0ECF, 0x051C3CF, 0x06F0ECF, 0x092FC05, 0x0714414, 0x0E28828, 0x092FC05, 0x0820000, 0x0CBDF90, 0x0DDEC84, 0x065EFC8, 0x0820000, 0x06623EE, 0x05A2858, 0x0CF6872, @@ -995,9 +996,8 @@ static const int32_t qmat43[MAT_SIZE] = { 0x2B41F16, 0x4FE3A5E, 0x409AF3F, 0x222533E, 0x204D79F, 0x13F8E97, 0x11809B2, 0x1A2D63A, 0x345AC74, 0x46026C7, 0x38A1C30, 0x2816FA7, 0x0E2870C, 0x15A6990, 0x2B4D320, 0x1768340, -}; - -static const int32_t qmat44[MAT_SIZE] = { +}, +[QMAT44] = { 0x0040000, 0x07A0F3C, 0x03D079E, 0x07A29E4, 0x059F0FE, 0x07A29E4, 0x0746964, 0x059B4E5, 0x0B369CA, 0x0746964, 0x0630000, 0x0A177B8, 0x0B26485, 0x050BBDC, 0x0630000, 0x0521AE9, 0x048790C, 0x0A08C95, @@ -1009,9 +1009,8 @@ static const int32_t qmat44[MAT_SIZE] = { 0x17CAAB2, 0x15DBA76, 0x11DC065, 0x09563FF, 0x08EE032, 0x0576E9E, 0x0994319, 0x0E530E0, 0x1CA61BF, 0x2650C65, 0x1EFF9DF, 0x15F2DD1, 0x07BFE78, 0x0BE86DC, 0x17D0DB8, 0x0CDFB63, -}; - -static const int32_t qmat45[MAT_SIZE] = { +}, +[QMAT45] = { 0x0040000, 0x07A0F3C, 0x03D079E, 0x07A29E4, 0x059F0FE, 0x07A29E4, 0x0A1AED2, 0x07C97B0, 0x0F92F5F, 0x0A1AED2, 0x08F0000, 0x0E042B8, 0x0F41DC4, 0x070215C, 0x08F0000, 0x0705AB9, 0x0632C61, 0x0E42617, @@ -1023,9 +1022,8 @@ static const int32_t qmat45[MAT_SIZE] = { 0x2F95565, 0x57E0D01, 0x4710D92, 0x258F52A, 0x23886C9, 0x15F8340, 0x1340AAA, 0x1CCB873, 0x39970E6, 0x4D02AA8, 0x3E4B89B, 0x2C1946B, 0x0F92E27, 0x17D0DB8, 0x2FA1B6F, 0x19BF6C7, -}; - -static const int32_t qmat46[MAT_SIZE] = { +}, +[QMAT46] = { 0x0040000, 0x08527E4, 0x04293F2, 0x08544F9, 0x0621E2C, 0x08544F9, 0x07EFE9C, 0x061DC9D, 0x0C3B939, 0x07EFE9C, 0x06C0000, 0x0B02582, 0x0C29C34, 0x05812C1, 0x06C0000, 0x05991B9, 0x04F0FAF, 0x0AF2500, @@ -1037,9 +1035,8 @@ static const int32_t qmat46[MAT_SIZE] = { 0x19F45DA, 0x17D8598, 0x137BA9D, 0x0A2F8B9, 0x09BDD4E, 0x05F6166, 0x0A731ED, 0x0FA06C5, 0x1F40D8B, 0x29CC7B4, 0x21D1096, 0x17F1AB5, 0x0874425, 0x0CFD8F0, 0x19FB1E0, 0x0E0B527, -}; - -static const int32_t qmat47[MAT_SIZE] = { +}, +[QMAT47] = { 0x0040000, 0x08527E4, 0x04293F2, 0x08544F9, 0x0621E2C, 0x08544F9, 0x0B061A0, 0x087EB4B, 0x10FD696, 0x0B061A0, 0x09C0000, 0x0F4A5E0, 0x10A4F04, 0x07A52F0, 0x09C0000, 0x07A9184, 0x06C3069, 0x0F8E3BC, @@ -1051,9 +1048,8 @@ static const int32_t qmat47[MAT_SIZE] = { 0x33E8BB4, 0x5FDDFA4, 0x4D86BE5, 0x28F9717, 0x26C35F2, 0x17F77E9, 0x1500BA2, 0x1F69AAC, 0x3ED3558, 0x5402E89, 0x43F5506, 0x301B92F, 0x10FD541, 0x19FB1E0, 0x33F63BF, 0x1C16A4D, -}; - -static const int32_t qmat48[MAT_SIZE] = { +}, +[QMAT48] = { 0x0040000, 0x090408D, 0x0482046, 0x090600E, 0x06A4B5A, 0x090600E, 0x08993D3, 0x06A0454, 0x0D408A9, 0x08993D3, 0x0750000, 0x0BED34D, 0x0D2D3E3, 0x05F69A7, 0x0750000, 0x0610888, 0x055A653, 0x0BDBD6A, @@ -1065,9 +1061,8 @@ static const int32_t qmat48[MAT_SIZE] = { 0x1C1E101, 0x19D50BB, 0x151B4D4, 0x0B08D73, 0x0A8DA6A, 0x067542F, 0x0B520C1, 0x10EDCAB, 0x21DB956, 0x2D48303, 0x24A274D, 0x19F079A, 0x09289D3, 0x0E12B04, 0x1C25608, 0x0F36EEA, -}; - -static const int32_t qmat49[MAT_SIZE] = { +}, +[QMAT49] = { 0x0040000, 0x090408D, 0x0482046, 0x090600E, 0x06A4B5A, 0x090600E, 0x0BF146D, 0x0933EE7, 0x1267DCE, 0x0BF146D, 0x0A90000, 0x1090908, 0x1208045, 0x0848484, 0x0A90000, 0x084C84F, 0x0753472, 0x10DA161, @@ -1079,9 +1074,8 @@ static const int32_t qmat49[MAT_SIZE] = { 0x383C203, 0x67DB247, 0x53FCA38, 0x2C63904, 0x29FE51C, 0x19F6C92, 0x16C0C9A, 0x2207CE5, 0x440F9CA, 0x5B0326A, 0x499F171, 0x341DDF3, 0x1267C5C, 0x1C25608, 0x384AC0F, 0x1E6DDD4, -}; - -static const int32_t qmat4A[MAT_SIZE] = { +}, +[QMAT4A] = { 0x0040000, 0x09B5935, 0x04DAC9A, 0x09B7B22, 0x0727888, 0x09B7B22, 0x094290B, 0x0722C0C, 0x0E45818, 0x094290B, 0x07E0000, 0x0CD8118, 0x0E30B92, 0x066C08C, 0x07E0000, 0x0687F58, 0x05C3CF7, 0x0CC55D5, @@ -1093,9 +1087,8 @@ static const int32_t qmat4A[MAT_SIZE] = { 0x1E47C29, 0x1BD1BDD, 0x16BAF0C, 0x0BE222D, 0x0B5D786, 0x06F46F7, 0x0C30F95, 0x123B291, 0x2476522, 0x30C3E52, 0x2773E04, 0x1BEF47E, 0x09DCF81, 0x0F27D18, 0x1E4FA30, 0x10628AD, -}; - -static const int32_t qmat4B[MAT_SIZE] = { +}, +[QMAT4B] = { 0x0040000, 0x09B5935, 0x04DAC9A, 0x09B7B22, 0x0727888, 0x09B7B22, 0x0CDC73A, 0x09E9282, 0x13D2505, 0x0CDC73A, 0x0B60000, 0x11D6C30, 0x136B185, 0x08EB618, 0x0B60000, 0x08EFF19, 0x07E387B, 0x1225F06, @@ -1107,9 +1100,8 @@ static const int32_t qmat4B[MAT_SIZE] = { 0x3C8F852, 0x6FD84EA, 0x5A7288B, 0x2FCDAF0, 0x2D39446, 0x1BF613A, 0x1880D93, 0x24A5F1E, 0x494BE3C, 0x620364A, 0x4F48DDC, 0x38202B7, 0x13D2377, 0x1E4FA30, 0x3C9F45F, 0x20C515A, -}; - -static const int32_t qmat4C[MAT_SIZE] = { +}, +[QMAT4C] = { 0x0040000, 0x1208119, 0x090408D, 0x120C01B, 0x0D496B4, 0x120C01B, 0x11327A7, 0x0D408A9, 0x1A81151, 0x11327A7, 0x0EA0000, 0x17DA69B, 0x1A5A7C7, 0x0BED34D, 0x0EA0000, 0x0C21110, 0x0AB4CA7, 0x17B7AD5, @@ -1121,9 +1113,8 @@ static const int32_t qmat4C[MAT_SIZE] = { 0x383C203, 0x33AA175, 0x2A369A9, 0x1611AE6, 0x151B4D4, 0x0CEA85D, 0x16A4182, 0x21DB956, 0x43B72AC, 0x5A90607, 0x4944E9A, 0x33E0F34, 0x12513A7, 0x1C25608, 0x384AC0F, 0x1E6DDD4, -}; - -static const int32_t qmat4D[MAT_SIZE] = { +}, +[QMAT4D] = { 0x0040000, 0x1208119, 0x090408D, 0x120C01B, 0x0D496B4, 0x120C01B, 0x17E28DA, 0x1267DCE, 0x24CFB9B, 0x17E28DA, 0x1520000, 0x2121210, 0x2410089, 0x1090908, 0x1520000, 0x109909D, 0x0EA68E4, 0x21B42C3, @@ -1135,323 +1126,295 @@ static const int32_t qmat4D[MAT_SIZE] = { 0x7078406, 0xCFB648E, 0xA7F9470, 0x58C7207, 0x53FCA38, 0x33ED923, 0x2D81935, 0x440F9CA, 0x881F394, 0xB6064D3, 0x933E2E2, 0x683BBE7, 0x24CF8B9, 0x384AC0F, 0x709581F, 0x3CDBBA7, +}, }; -static const int32_t *const hq_quants[NUM_HQ_QUANTS][2][4] = { - { { qmat00, qmat02, qmat06, qmat0E }, { qmat01, qmat03, qmat07, qmat0F } }, - { { qmat02, qmat06, qmat0E, qmat16 }, { qmat03, qmat07, qmat0F, qmat17 } }, - { { qmat04, qmat0A, qmat12, qmat1E }, { qmat05, qmat0B, qmat13, qmat1F } }, - { { qmat06, qmat0E, qmat16, qmat22 }, { qmat07, qmat0F, qmat17, qmat23 } }, - { { qmat08, qmat10, qmat1A, qmat26 }, { qmat09, qmat11, qmat1B, qmat27 } }, - { { qmat0A, qmat12, qmat1E, qmat2A }, { qmat0B, qmat13, qmat1F, qmat2B } }, - { { qmat0C, qmat14, qmat20, qmat2E }, { qmat0D, qmat15, qmat21, qmat2F } }, - { { qmat0E, qmat16, qmat22, qmat30 }, { qmat0F, qmat17, qmat23, qmat31 } }, - { { qmat16, qmat22, qmat30, qmat3E }, { qmat17, qmat23, qmat31, qmat3F } }, - { { qmat18, qmat24, qmat32, qmat40 }, { qmat19, qmat25, qmat33, qmat41 } }, - { { qmat1A, qmat26, qmat34, qmat42 }, { qmat1B, qmat27, qmat35, qmat43 } }, - { { qmat1C, qmat28, qmat36, qmat44 }, { qmat1D, qmat29, qmat37, qmat45 } }, - { { qmat1E, qmat2A, qmat38, qmat46 }, { qmat1F, qmat2B, qmat39, qmat47 } }, - { { qmat20, qmat2E, qmat3C, qmat4A }, { qmat21, qmat2F, qmat3D, qmat4B } }, - { { qmat2C, qmat3A, qmat48, qmat4C }, { qmat2D, qmat3B, qmat49, qmat4D } }, - { { qmat3A, qmat48, qmat4C, qmat4C }, { qmat3B, qmat49, qmat4D, qmat4D } }, +static const uint8_t hq_quant_map[NUM_HQ_QUANTS][2][4] = +{ + { { QMAT00, QMAT02, QMAT06, QMAT0E }, { QMAT01, QMAT03, QMAT07, QMAT0F } }, + { { QMAT02, QMAT06, QMAT0E, QMAT16 }, { QMAT03, QMAT07, QMAT0F, QMAT17 } }, + { { QMAT04, QMAT0A, QMAT12, QMAT1E }, { QMAT05, QMAT0B, QMAT13, QMAT1F } }, + { { QMAT06, QMAT0E, QMAT16, QMAT22 }, { QMAT07, QMAT0F, QMAT17, QMAT23 } }, + { { QMAT08, QMAT10, QMAT1A, QMAT26 }, { QMAT09, QMAT11, QMAT1B, QMAT27 } }, + { { QMAT0A, QMAT12, QMAT1E, QMAT2A }, { QMAT0B, QMAT13, QMAT1F, QMAT2B } }, + { { QMAT0C, QMAT14, QMAT20, QMAT2E }, { QMAT0D, QMAT15, QMAT21, QMAT2F } }, + { { QMAT0E, QMAT16, QMAT22, QMAT30 }, { QMAT0F, QMAT17, QMAT23, QMAT31 } }, + { { QMAT16, QMAT22, QMAT30, QMAT3E }, { QMAT17, QMAT23, QMAT31, QMAT3F } }, + { { QMAT18, QMAT24, QMAT32, QMAT40 }, { QMAT19, QMAT25, QMAT33, QMAT41 } }, + { { QMAT1A, QMAT26, QMAT34, QMAT42 }, { QMAT1B, QMAT27, QMAT35, QMAT43 } }, + { { QMAT1C, QMAT28, QMAT36, QMAT44 }, { QMAT1D, QMAT29, QMAT37, QMAT45 } }, + { { QMAT1E, QMAT2A, QMAT38, QMAT46 }, { QMAT1F, QMAT2B, QMAT39, QMAT47 } }, + { { QMAT20, QMAT2E, QMAT3C, QMAT4A }, { QMAT21, QMAT2F, QMAT3D, QMAT4B } }, + { { QMAT2C, QMAT3A, QMAT48, QMAT4C }, { QMAT2D, QMAT3B, QMAT49, QMAT4D } }, + { { QMAT3A, QMAT48, QMAT4C, QMAT4C }, { QMAT3B, QMAT49, QMAT4D, QMAT4D } }, }; -static const uint8_t hq_ac_bits[NUM_HQ_AC_ENTRIES] = { - 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, - 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 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, 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, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, +#define HQ_AC_INVALID_RUN 0 + +#define E(level, skip) ((level * (1 << 7)) | (skip + 1)) +// The invalid entry has length 16 and is mapped to an invalid run. +#define INVALID_ENT HQ_AC_INVALID_RUN +#define INV 16 + +static const int16_t hq_ac_sym[NUM_HQ_AC_ENTRIES] = { + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 0, 64), + E( 1, 1), E( -1, 1), E( 3, 0), E( -3, 0), E( 4, 0), + E( -4, 0), E( 1, 2), E( -1, 2), E( 2, 1), E( -2, 1), + E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), E( 1, 3), + E( -1, 3), E( 1, 4), E( -1, 4), E( 7, 0), E( -7, 0), + E( 8, 0), E( -8, 0), E( 1, 5), E( -1, 5), E( 1, 6), + E( -1, 6), E( 2, 2), E( -2, 2), E( 3, 1), E( -3, 1), + E( 4, 1), E( -4, 1), E( 9, 0), E( -9, 0), E( 10, 0), + E( -10, 0), E( 11, 0), E( -11, 0), E( 1, 7), E( -1, 7), + E( 1, 8), E( -1, 8), E( 1, 9), E( -1, 9), E( 1, 10), + E( -1, 10), E( 2, 3), E( -2, 3), E( 2, 4), E( -2, 4), + E( 3, 2), E( -3, 2), E( 5, 1), E( -5, 1), E( 6, 1), + E( -6, 1), E( 7, 1), E( -7, 1), E( 12, 0), E( -12, 0), + E( 13, 0), E( -13, 0), E( 14, 0), E( -14, 0), E( 15, 0), + E( -15, 0), E( 16, 0), E( -16, 0), E( 17, 0), E( -17, 0), + E( 1, 11), E( -1, 11), E( 1, 12), E( -1, 12), E( 1, 13), + E( -1, 13), E( 1, 14), E( -1, 14), E( 2, 5), E( -2, 5), + E( 2, 6), E( -2, 6), E( 3, 3), E( -3, 3), E( 3, 4), + E( -3, 4), E( 4, 2), E( -4, 2), E( 5, 2), E( -5, 2), + E( 8, 1), E( -8, 1), E( 18, 0), E( -18, 0), E( 19, 0), + E( -19, 0), E( 20, 0), E( -20, 0), E( 21, 0), E( -21, 0), + E( 22, 0), E( -22, 0), E( 3, 5), E( -3, 5), E( 4, 3), + E( -4, 3), E( 5, 3), E( -5, 3), E( 6, 2), E( -6, 2), + E( 9, 1), E( -9, 1), E( 10, 1), E( -10, 1), E( 11, 1), + E( -11, 1), E( 0, 0), E( 0, 1), E( 3, 6), E( -3, 6), + E( 4, 4), E( -4, 4), E( 6, 3), E( -6, 3), E( 12, 1), + E( -12, 1), E( 13, 1), E( -13, 1), E( 14, 1), E( -14, 1), + E( 0, 2), E( 0, 3), E( 0, 4), E( 0, 5), E( 2, 7), + E( -2, 7), E( 2, 8), E( -2, 8), E( 2, 9), E( -2, 9), + E( 2, 10), E( -2, 10), E( 3, 7), E( -3, 7), E( 3, 8), + E( -3, 8), E( 5, 4), E( -5, 4), E( 7, 3), E( -7, 3), + E( 7, 2), E( -7, 2), E( 8, 2), E( -8, 2), E( 9, 2), + E( -9, 2), E( 10, 2), E( -10, 2), E( 11, 2), E( -11, 2), + E( 15, 1), E( -15, 1), E( 16, 1), E( -16, 1), E( 17, 1), + E( -17, 1), E( 0, 0), E( 0, 1), E( 0, 2), E( 0, 3), + E( 0, 4), E( 0, 5), E( 0, 6), E( 0, 7), E( 0, 8), + E( 0, 9), E( 0, 10), E( 0, 11), E( 0, 12), E( 0, 13), + E( 0, 14), E( 0, 15), E( 0, 16), E( 0, 17), E( 0, 18), + E( 0, 19), E( 0, 20), E( 0, 21), E( 0, 22), E( 0, 23), + E( 0, 24), E( 0, 25), E( 0, 26), E( 0, 27), E( 0, 28), + E( 0, 29), E( 0, 30), E( 0, 31), E( 0, 32), E( 0, 33), + E( 0, 34), E( 0, 35), E( 0, 36), E( 0, 37), E( 0, 38), + E( 0, 39), E( 0, 40), E( 0, 41), E( 0, 42), E( 0, 43), + E( 0, 44), E( 0, 45), E( 0, 46), E( 0, 47), E( 0, 48), + E( 0, 49), E( 0, 50), E( 0, 51), E( 0, 52), E( 0, 53), + E( 0, 54), E( 0, 55), E( 0, 56), E( 0, 57), E( 0, 58), + E( 0, 59), E( 0, 60), E( 0, 61), E( 0, 62), E( 0, 63), + E( 0, 0), INVALID_ENT, E( 1, 0), E( -1, 0), E( 2, 0), + E( -2, 0), E( 3, 0), E( -3, 0), E( 4, 0), E( -4, 0), + E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), E( 7, 0), + E( -7, 0), E( 8, 0), E( -8, 0), E( 9, 0), E( -9, 0), + E( 10, 0), E( -10, 0), E( 11, 0), E( -11, 0), E( 12, 0), + E( -12, 0), E( 13, 0), E( -13, 0), E( 14, 0), E( -14, 0), + E( 15, 0), E( -15, 0), E( 16, 0), E( -16, 0), E( 17, 0), + E( -17, 0), E( 18, 0), E( -18, 0), E( 19, 0), E( -19, 0), + E( 20, 0), E( -20, 0), E( 21, 0), E( -21, 0), E( 22, 0), + E( -22, 0), E( 23, 0), E( -23, 0), E( 24, 0), E( -24, 0), + E( 25, 0), E( -25, 0), E( 26, 0), E( -26, 0), E( 27, 0), + E( -27, 0), E( 28, 0), E( -28, 0), E( 29, 0), E( -29, 0), + E( 30, 0), E( -30, 0), E( 31, 0), E( -31, 0), E( 32, 0), + E( -32, 0), E( 33, 0), E( -33, 0), E( 34, 0), E( -34, 0), + E( 35, 0), E( -35, 0), E( 36, 0), E( -36, 0), E( 37, 0), + E( -37, 0), E( 38, 0), E( -38, 0), E( 39, 0), E( -39, 0), + E( 40, 0), E( -40, 0), E( 41, 0), E( -41, 0), E( 42, 0), + E( -42, 0), E( 43, 0), E( -43, 0), E( 44, 0), E( -44, 0), + E( 45, 0), E( -45, 0), E( 46, 0), E( -46, 0), E( 47, 0), + E( -47, 0), E( 48, 0), E( -48, 0), E( 49, 0), E( -49, 0), + E( 50, 0), E( -50, 0), E( 51, 0), E( -51, 0), E( 52, 0), + E( -52, 0), E( 53, 0), E( -53, 0), E( 54, 0), E( -54, 0), + E( 55, 0), E( -55, 0), E( 56, 0), E( -56, 0), E( 57, 0), + E( -57, 0), E( 58, 0), E( -58, 0), E( 59, 0), E( -59, 0), + E( 60, 0), E( -60, 0), E( 61, 0), E( -61, 0), E( 62, 0), + E( -62, 0), E( 63, 0), E( -63, 0), E( 64, 0), E( -64, 0), + E( 65, 0), E( -65, 0), E( 66, 0), E( -66, 0), E( 67, 0), + E( -67, 0), E( 68, 0), E( -68, 0), E( 69, 0), E( -69, 0), + E( 70, 0), E( -70, 0), E( 71, 0), E( -71, 0), E( 72, 0), + E( -72, 0), E( 73, 0), E( -73, 0), E( 74, 0), E( -74, 0), + E( 75, 0), E( -75, 0), E( 76, 0), E( -76, 0), E( 77, 0), + E( -77, 0), E( 78, 0), E( -78, 0), E( 79, 0), E( -79, 0), + E( 80, 0), E( -80, 0), E( 81, 0), E( -81, 0), E( 82, 0), + E( -82, 0), E( 83, 0), E( -83, 0), E( 84, 0), E( -84, 0), + E( 85, 0), E( -85, 0), E( 86, 0), E( -86, 0), E( 87, 0), + E( -87, 0), E( 88, 0), E( -88, 0), E( 89, 0), E( -89, 0), + E( 90, 0), E( -90, 0), E( 91, 0), E( -91, 0), E( 92, 0), + E( -92, 0), E( 93, 0), E( -93, 0), E( 94, 0), E( -94, 0), + E( 95, 0), E( -95, 0), E( 96, 0), E( -96, 0), E( 97, 0), + E( -97, 0), E( 98, 0), E( -98, 0), E( 99, 0), E( -99, 0), + E( 100, 0), E(-100, 0), E( 101, 0), E(-101, 0), E( 102, 0), + E(-102, 0), E( 103, 0), E(-103, 0), E( 104, 0), E(-104, 0), + E( 105, 0), E(-105, 0), E( 106, 0), E(-106, 0), E( 107, 0), + E(-107, 0), E( 108, 0), E(-108, 0), E( 109, 0), E(-109, 0), + E( 110, 0), E(-110, 0), E( 111, 0), E(-111, 0), E( 112, 0), + E(-112, 0), E( 113, 0), E(-113, 0), E( 114, 0), E(-114, 0), + E( 115, 0), E(-115, 0), E( 116, 0), E(-116, 0), E( 117, 0), + E(-117, 0), E( 118, 0), E(-118, 0), E( 119, 0), E(-119, 0), + E( 120, 0), E(-120, 0), E( 121, 0), E(-121, 0), E( 122, 0), + E(-122, 0), E( 123, 0), E(-123, 0), E( 124, 0), E(-124, 0), + E( 125, 0), E(-125, 0), E( 126, 0), E(-126, 0), E( 127, 0), + E(-127, 0), E( 128, 0), E(-128, 0), E( 129, 0), E(-129, 0), + E( 130, 0), E(-130, 0), E( 131, 0), E(-131, 0), E( 132, 0), + E(-132, 0), E( 133, 0), E(-133, 0), E( 134, 0), E(-134, 0), + E( 135, 0), E(-135, 0), E( 136, 0), E(-136, 0), E( 137, 0), + E(-137, 0), E( 138, 0), E(-138, 0), E( 139, 0), E(-139, 0), + E( 140, 0), E(-140, 0), E( 141, 0), E(-141, 0), E( 142, 0), + E(-142, 0), E( 143, 0), E(-143, 0), E( 144, 0), E(-144, 0), + E( 145, 0), E(-145, 0), E( 146, 0), E(-146, 0), E( 147, 0), + E(-147, 0), E( 148, 0), E(-148, 0), E( 149, 0), E(-149, 0), + E( 150, 0), E(-150, 0), E( 151, 0), E(-151, 0), E( 152, 0), + E(-152, 0), E( 153, 0), E(-153, 0), E( 154, 0), E(-154, 0), + E( 155, 0), E(-155, 0), E( 156, 0), E(-156, 0), E( 157, 0), + E(-157, 0), E( 158, 0), E(-158, 0), E( 159, 0), E(-159, 0), + E( 160, 0), E(-160, 0), E( 161, 0), E(-161, 0), E( 162, 0), + E(-162, 0), E( 163, 0), E(-163, 0), E( 164, 0), E(-164, 0), + E( 165, 0), E(-165, 0), E( 166, 0), E(-166, 0), E( 167, 0), + E(-167, 0), E( 168, 0), E(-168, 0), E( 169, 0), E(-169, 0), + E( 170, 0), E(-170, 0), E( 171, 0), E(-171, 0), E( 172, 0), + E(-172, 0), E( 173, 0), E(-173, 0), E( 174, 0), E(-174, 0), + E( 175, 0), E(-175, 0), E( 176, 0), E(-176, 0), E( 177, 0), + E(-177, 0), E( 178, 0), E(-178, 0), E( 179, 0), E(-179, 0), + E( 180, 0), E(-180, 0), E( 181, 0), E(-181, 0), E( 182, 0), + E(-182, 0), E( 183, 0), E(-183, 0), E( 184, 0), E(-184, 0), + E( 185, 0), E(-185, 0), E( 186, 0), E(-186, 0), E( 187, 0), + E(-187, 0), E( 188, 0), E(-188, 0), E( 189, 0), E(-189, 0), + E( 190, 0), E(-190, 0), E( 191, 0), E(-191, 0), E( 192, 0), + E(-192, 0), E( 193, 0), E(-193, 0), E( 194, 0), E(-194, 0), + E( 195, 0), E(-195, 0), E( 196, 0), E(-196, 0), E( 197, 0), + E(-197, 0), E( 198, 0), E(-198, 0), E( 199, 0), E(-199, 0), + E( 200, 0), E(-200, 0), E( 201, 0), E(-201, 0), E( 202, 0), + E(-202, 0), E( 203, 0), E(-203, 0), E( 204, 0), E(-204, 0), + E( 205, 0), E(-205, 0), E( 206, 0), E(-206, 0), E( 207, 0), + E(-207, 0), E( 208, 0), E(-208, 0), E( 209, 0), E(-209, 0), + E( 210, 0), E(-210, 0), E( 211, 0), E(-211, 0), E( 212, 0), + E(-212, 0), E( 213, 0), E(-213, 0), E( 214, 0), E(-214, 0), + E( 215, 0), E(-215, 0), E( 216, 0), E(-216, 0), E( 217, 0), + E(-217, 0), E( 218, 0), E(-218, 0), E( 219, 0), E(-219, 0), + E( 220, 0), E(-220, 0), E( 221, 0), E(-221, 0), E( 222, 0), + E(-222, 0), E( 223, 0), E(-223, 0), E( 224, 0), E(-224, 0), + E( 225, 0), E(-225, 0), E( 226, 0), E(-226, 0), E( 227, 0), + E(-227, 0), E( 228, 0), E(-228, 0), E( 229, 0), E(-229, 0), + E( 230, 0), E(-230, 0), E( 231, 0), E(-231, 0), E( 232, 0), + E(-232, 0), E( 233, 0), E(-233, 0), E( 234, 0), E(-234, 0), + E( 235, 0), E(-235, 0), E( 236, 0), E(-236, 0), E( 237, 0), + E(-237, 0), E( 238, 0), E(-238, 0), E( 239, 0), E(-239, 0), + E( 240, 0), E(-240, 0), E( 241, 0), E(-241, 0), E( 242, 0), + E(-242, 0), E( 243, 0), E(-243, 0), E( 244, 0), E(-244, 0), + E( 245, 0), E(-245, 0), E( 246, 0), E(-246, 0), E( 247, 0), + E(-247, 0), E( 248, 0), E(-248, 0), E( 249, 0), E(-249, 0), + E( 250, 0), E(-250, 0), E( 251, 0), E(-251, 0), E( 252, 0), + E(-252, 0), E( 253, 0), E(-253, 0), E( 254, 0), E(-254, 0), + E( 255, 0), E(-255, 0), }; -static const uint16_t hq_ac_codes[NUM_HQ_AC_ENTRIES] = { - 0x0000, 0x0001, 0x0004, 0x0005, 0x0006, 0x000E, 0x000F, 0x0010, - 0x0011, 0x0012, 0x0013, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, - 0x002D, 0x002E, 0x002F, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, - 0x0065, 0x0066, 0x0067, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, - 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, - 0x00DD, 0x00DE, 0x00DF, 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, - 0x01C5, 0x01C6, 0x01C7, 0x01C8, 0x01C9, 0x01CA, 0x01CB, 0x01CC, - 0x01CD, 0x01CE, 0x01CF, 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, - 0x01D5, 0x01D6, 0x01D7, 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, - 0x01DD, 0x01DE, 0x01DF, 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, - 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, - 0x03CD, 0x03CE, 0x03CF, 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, - 0x03D5, 0x03D6, 0x03D7, 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, - 0x03DD, 0x03DE, 0x03DF, 0x07C0, 0x07C1, 0x07C2, 0x07C3, 0x07C4, - 0x07C5, 0x07C6, 0x07C7, 0x07C8, 0x07C9, 0x07CA, 0x07CB, 0x07CC, - 0x07CD, 0x07CE, 0x07CF, 0x0FA0, 0x0FA1, 0x0FA2, 0x0FA3, 0x0FA4, - 0x0FA5, 0x0FA6, 0x0FA7, 0x0FA8, 0x0FA9, 0x0FAA, 0x0FAB, 0x0FAC, - 0x0FAD, 0x0FAE, 0x0FAF, 0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, - 0x1F65, 0x1F66, 0x1F67, 0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, - 0x1F6D, 0x1F6E, 0x1F6F, 0x1F70, 0x1F71, 0x1F72, 0x1F73, 0x1F74, - 0x1F75, 0x1F76, 0x1F77, 0x1F78, 0x1F79, 0x1F7A, 0x1F7B, 0x1F7C, - 0x1F7D, 0x1F7E, 0x1F7F, 0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, - 0x1F85, 0x1F86, 0x1F87, 0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, - 0x1F8D, 0x1F8E, 0x1F8F, 0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, - 0x1F95, 0x1F96, 0x1F97, 0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, - 0x1F9D, 0x1F9E, 0x1F9F, 0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, - 0x1FA5, 0x1FA6, 0x1FA7, 0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, - 0x1FAD, 0x1FAE, 0x1FAF, 0x1FB0, 0x1FB1, 0x1FB2, 0x1FB3, 0x1FB4, - 0x1FB5, 0x1FB6, 0x1FB7, 0x1FB8, 0x1FB9, 0x1FBA, 0x1FBB, 0x1FBC, - 0x1FBD, 0x1FBE, 0x1FBF, 0xFE00, 0xFE02, 0xFE03, 0xFE04, 0xFE05, - 0xFE06, 0xFE07, 0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, - 0xFE0E, 0xFE0F, 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, - 0xFE16, 0xFE17, 0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, - 0xFE1E, 0xFE1F, 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, - 0xFE26, 0xFE27, 0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, - 0xFE2E, 0xFE2F, 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, - 0xFE36, 0xFE37, 0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, - 0xFE3E, 0xFE3F, 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, - 0xFE46, 0xFE47, 0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, - 0xFE4E, 0xFE4F, 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, - 0xFE56, 0xFE57, 0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, - 0xFE5E, 0xFE5F, 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, - 0xFE66, 0xFE67, 0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, - 0xFE6E, 0xFE6F, 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, - 0xFE76, 0xFE77, 0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, - 0xFE7E, 0xFE7F, 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, - 0xFE86, 0xFE87, 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, - 0xFE8E, 0xFE8F, 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, - 0xFE96, 0xFE97, 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, - 0xFE9E, 0xFE9F, 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, - 0xFEA6, 0xFEA7, 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, - 0xFEAE, 0xFEAF, 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, - 0xFEB6, 0xFEB7, 0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, - 0xFEBE, 0xFEBF, 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, - 0xFEC6, 0xFEC7, 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, - 0xFECE, 0xFECF, 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, - 0xFED6, 0xFED7, 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, - 0xFEDE, 0xFEDF, 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, - 0xFEE6, 0xFEE7, 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, - 0xFEEE, 0xFEEF, 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, - 0xFEF6, 0xFEF7, 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, - 0xFEFE, 0xFEFF, 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, - 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, - 0xFF0E, 0xFF0F, 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, - 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, - 0xFF1E, 0xFF1F, 0xFF20, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, - 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, - 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, - 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0xFF3B, 0xFF3C, 0xFF3D, - 0xFF3E, 0xFF3F, 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, - 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, - 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, - 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, - 0xFF5E, 0xFF5F, 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, - 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, - 0xFF6E, 0xFF6F, 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, - 0xFF76, 0xFF77, 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, - 0xFF7E, 0xFF7F, 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, - 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, - 0xFF8E, 0xFF8F, 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, - 0xFF96, 0xFF97, 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, - 0xFF9E, 0xFF9F, 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, - 0xFFA6, 0xFFA7, 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, - 0xFFAE, 0xFFAF, 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, - 0xFFB6, 0xFFB7, 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, - 0xFFBE, 0xFFBF, 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, - 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, - 0xFFCE, 0xFFCF, 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, - 0xFFD6, 0xFFD7, 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, - 0xFFDE, 0xFFDF, 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, - 0xFFE6, 0xFFE7, 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, - 0xFFEE, 0xFFEF, 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, - 0xFFF6, 0xFFF7, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, - 0xFFFE, 0xFFFF, +static const uint8_t hq_ac_lens[NUM_HQ_AC_ENTRIES] = { + 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, + 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 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, 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, 16, INV,16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, }; -static const uint8_t hq_ac_skips[NUM_HQ_AC_ENTRIES] = { - 0, 0, 0, 0, 64, 1, 1, 0, 0, 0, 0, 2, 2, 1, 1, 0, - 0, 0, 0, 3, 3, 4, 4, 0, 0, 0, 0, 5, 5, 6, 6, 2, - 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 7, 7, 8, 8, 9, - 9, 10, 10, 3, 3, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 12, 12, 13, - 13, 14, 14, 5, 5, 6, 6, 3, 3, 4, 4, 2, 2, 2, 2, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 3, 3, 3, - 3, 2, 2, 1, 1, 1, 1, 1, 1, 0, 1, 6, 6, 4, 4, 3, - 3, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 7, 7, 8, 8, 9, - 9, 10, 10, 7, 7, 8, 8, 4, 4, 3, 3, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 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, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +typedef struct HQProfile { + unsigned tab_offset; + int width, height; + int num_slices; + int tab_w, tab_h; +} HQProfile; + +/* List of profiles, order is important */ +#define HQPROFILES(M, DEF) \ + /* case 0 (default) = case 11*/\ + DEF(11,160, 120, 8, 10, 8) \ + M(1, 720, 480, 8, 25, 54) \ + M(2, 720, 486, 8, 15, 93) \ + M(3, 720, 576, 8, 20, 81) \ + M(4, 960, 720, 12, 25, 108) \ + M(5, 1280, 720, 16, 25, 144) \ + M(6, 1280, 1080, 16, 20, 272) \ + M(7, 1440, 1080, 16, 24, 255) \ + M(8, 1920, 1080, 20, 24, 340) \ + M(9, 640, 480, 8, 25, 48) \ + M(10, 320, 240, 8, 25, 12) \ + M(11, 160, 120, 8, 10, 8) \ + M(12, 800, 600, 8, 25, 76) \ + M(13, 352, 480, 8, 20, 33) \ + M(14, 352, 240, 8, 22, 15) \ + M(15, 352, 288, 8, 18, 22) \ + M(16, 176, 144, 8, 9, 11) \ + M(17, 1280, 1024, 16, 20, 256) \ + M(18, 1280, 960, 16, 25, 192) \ + M(19, 1024, 768, 16, 24, 128) \ + M(20, 704, 480, 8, 20, 66) \ + M(21, 704, 576, 8, 24, 66) \ + +#define OFFSET(PROFILE, W, H, NUM_SLICES, TAB_W, TAB_H) \ + PROFILE_ ## PROFILE ## _OFFSET, \ + PROFILE_ ## PROFILE ## _LAST = PROFILE_ ## PROFILE ## _OFFSET + TAB_W * TAB_H * 2 - 1, +#define NOTHING(PROFILE, W, H, NUM_SLICES, TAB_W, TAB_H) +enum { + HQPROFILES(OFFSET, NOTHING) + NUM_HQ_PERMS }; -static const int16_t hq_ac_syms[NUM_HQ_AC_ENTRIES] = { - 1, -1, 2, -2, 0, 1, -1, 3, - -3, 4, -4, 1, -1, 2, -2, 5, - -5, 6, -6, 1, -1, 1, -1, 7, - -7, 8, -8, 1, -1, 1, -1, 2, - -2, 3, -3, 4, -4, 9, -9, 10, - -10, 11, -11, 1, -1, 1, -1, 1, - -1, 1, -1, 2, -2, 2, -2, 3, - -3, 5, -5, 6, -6, 7, -7, 12, - -12, 13, -13, 14, -14, 15, -15, 16, - -16, 17, -17, 1, -1, 1, -1, 1, - -1, 1, -1, 2, -2, 2, -2, 3, - -3, 3, -3, 4, -4, 5, -5, 8, - -8, 18, -18, 19, -19, 20, -20, 21, - -21, 22, -22, 3, -3, 4, -4, 5, - -5, 6, -6, 9, -9, 10, -10, 11, - -11, 0, 0, 3, -3, 4, -4, 6, - -6, 12, -12, 13, -13, 14, -14, 0, - 0, 0, 0, 2, -2, 2, -2, 2, - -2, 2, -2, 3, -3, 3, -3, 5, - -5, 7, -7, 7, -7, 8, -8, 9, - -9, 10, -10, 11, -11, 15, -15, 16, - -16, 17, -17, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, -1, 2, -2, - 3, -3, 4, -4, 5, -5, 6, -6, - 7, -7, 8, -8, 9, -9, 10, -10, - 11, -11, 12, -12, 13, -13, 14, -14, - 15, -15, 16, -16, 17, -17, 18, -18, - 19, -19, 20, -20, 21, -21, 22, -22, - 23, -23, 24, -24, 25, -25, 26, -26, - 27, -27, 28, -28, 29, -29, 30, -30, - 31, -31, 32, -32, 33, -33, 34, -34, - 35, -35, 36, -36, 37, -37, 38, -38, - 39, -39, 40, -40, 41, -41, 42, -42, - 43, -43, 44, -44, 45, -45, 46, -46, - 47, -47, 48, -48, 49, -49, 50, -50, - 51, -51, 52, -52, 53, -53, 54, -54, - 55, -55, 56, -56, 57, -57, 58, -58, - 59, -59, 60, -60, 61, -61, 62, -62, - 63, -63, 64, -64, 65, -65, 66, -66, - 67, -67, 68, -68, 69, -69, 70, -70, - 71, -71, 72, -72, 73, -73, 74, -74, - 75, -75, 76, -76, 77, -77, 78, -78, - 79, -79, 80, -80, 81, -81, 82, -82, - 83, -83, 84, -84, 85, -85, 86, -86, - 87, -87, 88, -88, 89, -89, 90, -90, - 91, -91, 92, -92, 93, -93, 94, -94, - 95, -95, 96, -96, 97, -97, 98, -98, - 99, -99, 100, -100, 101, -101, 102, -102, - 103, -103, 104, -104, 105, -105, 106, -106, - 107, -107, 108, -108, 109, -109, 110, -110, - 111, -111, 112, -112, 113, -113, 114, -114, - 115, -115, 116, -116, 117, -117, 118, -118, - 119, -119, 120, -120, 121, -121, 122, -122, - 123, -123, 124, -124, 125, -125, 126, -126, - 127, -127, 128, -128, 129, -129, 130, -130, - 131, -131, 132, -132, 133, -133, 134, -134, - 135, -135, 136, -136, 137, -137, 138, -138, - 139, -139, 140, -140, 141, -141, 142, -142, - 143, -143, 144, -144, 145, -145, 146, -146, - 147, -147, 148, -148, 149, -149, 150, -150, - 151, -151, 152, -152, 153, -153, 154, -154, - 155, -155, 156, -156, 157, -157, 158, -158, - 159, -159, 160, -160, 161, -161, 162, -162, - 163, -163, 164, -164, 165, -165, 166, -166, - 167, -167, 168, -168, 169, -169, 170, -170, - 171, -171, 172, -172, 173, -173, 174, -174, - 175, -175, 176, -176, 177, -177, 178, -178, - 179, -179, 180, -180, 181, -181, 182, -182, - 183, -183, 184, -184, 185, -185, 186, -186, - 187, -187, 188, -188, 189, -189, 190, -190, - 191, -191, 192, -192, 193, -193, 194, -194, - 195, -195, 196, -196, 197, -197, 198, -198, - 199, -199, 200, -200, 201, -201, 202, -202, - 203, -203, 204, -204, 205, -205, 206, -206, - 207, -207, 208, -208, 209, -209, 210, -210, - 211, -211, 212, -212, 213, -213, 214, -214, - 215, -215, 216, -216, 217, -217, 218, -218, - 219, -219, 220, -220, 221, -221, 222, -222, - 223, -223, 224, -224, 225, -225, 226, -226, - 227, -227, 228, -228, 229, -229, 230, -230, - 231, -231, 232, -232, 233, -233, 234, -234, - 235, -235, 236, -236, 237, -237, 238, -238, - 239, -239, 240, -240, 241, -241, 242, -242, - 243, -243, 244, -244, 245, -245, 246, -246, - 247, -247, 248, -248, 249, -249, 250, -250, - 251, -251, 252, -252, 253, -253, 254, -254, - 255, -255, +#define HQPROFILE(PROFILE, W, H, NUM_SLICES, TAB_W, TAB_H) \ + { .tab_offset = PROFILE_ ## PROFILE ## _OFFSET, .width = W, .height = H, \ + .num_slices = NUM_SLICES, .tab_w = TAB_W, .tab_h = TAB_H }, + +static const HQProfile hq_profile[NUM_HQ_PROFILES] = { + HQPROFILES(HQPROFILE, HQPROFILE) }; /* tables section - one per supported profile */ -static const uint8_t hq_tab_01[] = { +static const uint8_t hq_perms[] = { + [PROFILE_1_OFFSET] = /* Profile 1 - 2700 elements */ 0, 0, 12, 3, 20, 0, 28, 3, 40, 0, 0, 10, 15, 6, 20, 10, 35, 6, 40, 10, 7, 13, 15, 16, 23, 13, 35, 16, 39, 13, 7, 23, 10, 19, 23, 23, 27, 20, 39, 23, 2, 26, 10, 29, 22, @@ -1632,9 +1595,7 @@ static const uint8_t hq_tab_01[] = { 0, 29, 3, 39, 0, 0, 9, 14, 6, 19, 10, 34, 6, 39, 10, 8, 13, 14, 16, 24, 13, 34, 16, 40, 13, 8, 23, 11, 19, 24, 23, 27, 19, 40, 23, 1, 26, 11, 29, 21, 26, 27, 29, 41, 26, -}; - -static const uint8_t hq_tab_02[] = { + [PROFILE_2_OFFSET] = /* Profile 2 - 2790 elements */ 0, 0, 12, 5, 20, 0, 28, 5, 40, 0, 3, 16, 17, 11, 23, 16, 33, 11, 43, 16, 1, 21, 14, 27, 18, 22, 30, 27, 38, 22, 1, 0, 11, 5, 21, 0, 27, 5, 41, 0, 4, 16, 16, 11, 24, @@ -1821,10 +1782,7 @@ static const uint8_t hq_tab_02[] = { 16, 35, 11, 41, 16, 3, 21, 16, 27, 19, 21, 32, 27, 36, 22, 2, 10, 13, 5, 19, 0, 29, 5, 39, 0, 2, 16, 17, 10, 22, 16, 34, 11, 42, 16, 2, 21, 15, 27, 18, 21, 31, 27, 37, 22, - 0, 0, -}; - -static const uint8_t hq_tab_03[] = { + [PROFILE_3_OFFSET] = /* Profile 3 - 3240 elements */ 0, 0, 14, 4, 20, 0, 34, 4, 40, 0, 8, 14, 15, 9, 24, 14, 35, 9, 40, 14, 7, 19, 11, 23, 23, 19, 27, 23, 39, 19, 1, 33, 10, 28, 21, 33, 27, 29, 41, 33, 1, 0, 15, 4, 21, @@ -2041,9 +1999,7 @@ static const uint8_t hq_tab_03[] = { 33, 28, 28, 39, 33, 8, 8, 13, 4, 19, 0, 33, 4, 39, 0, 8, 13, 14, 9, 25, 14, 34, 9, 41, 14, 8, 19, 12, 23, 24, 19, 28, 23, 40, 19, 0, 33, 11, 28, 20, 33, 27, 28, 40, 33, -}; - -static const uint8_t hq_tab_04[] = { + [PROFILE_4_OFFSET] = /* Profile 4 - 5400 elements */ 0, 0, 19, 4, 26, 0, 45, 4, 52, 0, 11, 13, 18, 9, 34, 14, 44, 9, 56, 14, 10, 18, 18, 23, 35, 19, 40, 23, 57, 19, 2, 32, 19, 28, 24, 32, 41, 28, 49, 33, 3, 37, 15, 42, 25, @@ -2404,9 +2360,7 @@ static const uint8_t hq_tab_04[] = { 0, 44, 4, 51, 0, 10, 13, 17, 9, 35, 14, 43, 9, 57, 14, 9, 18, 19, 23, 35, 18, 41, 23, 58, 19, 3, 32, 20, 28, 25, 32, 42, 28, 48, 33, 4, 37, 14, 42, 26, 37, 40, 42, 48, 37, -}; - -static const uint8_t hq_tab_05[] = { + [PROFILE_5_OFFSET] = /* Profile 5 - 7200 elements */ 0, 0, 25, 4, 34, 0, 59, 4, 68, 0, 13, 13, 22, 9, 47, 13, 56, 9, 78, 14, 10, 18, 28, 23, 44, 18, 58, 23, 78, 18, 8, 32, 31, 28, 38, 32, 61, 28, 68, 32, 11, 37, 18, 41, 41, @@ -2887,9 +2841,7 @@ static const uint8_t hq_tab_05[] = { 0, 58, 4, 67, 0, 12, 13, 21, 9, 46, 13, 55, 9, 79, 14, 9, 18, 29, 23, 43, 18, 59, 23, 77, 18, 9, 32, 31, 27, 39, 32, 62, 28, 69, 32, 12, 37, 19, 41, 42, 37, 49, 41, 72, 37, -}; - -static const uint8_t hq_tab_06[] = { + [PROFILE_6_OFFSET] = /* Profile 6 - 10880 elements */ 0, 0, 25, 8, 34, 0, 59, 8, 68, 0, 13, 25, 22, 17, 47, 25, 56, 17, 78, 26, 10, 34, 28, 43, 44, 34, 58, 43, 78, 34, 8, 60, 31, 52, 38, 60, 61, 52, 68, 60, 1, 0, 26, 8, 35, @@ -3616,9 +3568,7 @@ static const uint8_t hq_tab_06[] = { 0, 58, 8, 67, 0, 12, 25, 21, 17, 46, 25, 55, 17, 79, 26, 9, 34, 29, 43, 43, 34, 59, 43, 77, 34, 9, 60, 31, 51, 39, 60, 62, 52, 69, 60, -}; - -static const uint8_t hq_tab_07[] = { + [PROFILE_7_OFFSET] = /* Profile 7 - 12240 elements */ 0, 0, 23, 8, 32, 0, 55, 8, 64, 0, 87, 8, 13, 25, 22, 17, 44, 26, 54, 17, 72, 26, 86, 17, 12, 34, 24, 43, 44, 34, 52, 43, 73, 35, 80, 43, 4, 60, 25, 52, 32, 60, 53, 52, 60, @@ -4435,9 +4385,7 @@ static const uint8_t hq_tab_07[] = { 8, 31, 0, 54, 8, 63, 0, 86, 8, 12, 25, 21, 17, 44, 25, 53, 17, 73, 26, 85, 17, 11, 34, 25, 43, 43, 34, 53, 43, 74, 35, 81, 43, 5, 60, 26, 52, 33, 60, 54, 52, 61, 60, 82, 52, -}; - -static const uint8_t hq_tab_08[] = { + [PROFILE_8_OFFSET] = /* Profile 8 - 16320 elements */ 0, 0, 31, 8, 42, 0, 73, 8, 84, 0, 115, 8, 16, 25, 27, 17, 58, 25, 69, 17, 99, 26, 111, 17, 12, 34, 36, 43, 54, 34, 74, 43, 96, 34, 112, 43, 11, 60, 39, 51, 49, 60, 78, 52, 87, @@ -5526,10 +5474,7 @@ static const uint8_t hq_tab_08[] = { 8, 41, 0, 72, 8, 83, 0, 114, 8, 15, 25, 26, 17, 57, 25, 68, 17, 99, 25, 110, 17, 11, 34, 37, 43, 53, 34, 75, 43, 95, 34, 113, 43, 12, 60, 38, 51, 50, 60, 79, 52, 88, 60, 117, 52, - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static const uint8_t hq_tab_09[] = { + [PROFILE_9_OFFSET] = /* Profile 9 - 2400 elements */ 0, 0, 10, 3, 18, 0, 24, 3, 36, 0, 1, 10, 14, 6, 19, 10, 31, 7, 37, 10, 5, 13, 15, 16, 19, 13, 30, 17, 33, 13, 4, 23, 8, 20, 18, 23, 26, 20, 32, 23, 4, 26, 9, 24, 22, @@ -5690,9 +5635,7 @@ static const uint8_t hq_tab_09[] = { 0, 25, 3, 35, 0, 0, 10, 13, 6, 18, 10, 31, 6, 36, 10, 6, 13, 14, 16, 20, 13, 31, 17, 34, 13, 5, 23, 8, 19, 19, 23, 25, 20, 33, 23, 3, 26, 8, 24, 21, 26, 26, 24, 39, 26, -}; - -static const uint8_t hq_tab_10[] = { + [PROFILE_10_OFFSET] = /* Profile 10 - 600 elements */ 0, 0, 4, 1, 10, 0, 13, 2, 19, 1, 0, 5, 6, 4, 10, 3, 15, 5, 16, 3, 2, 8, 6, 7, 8, 6, 12, 7, 18, 6, 2, 11, 4, 10, 8, 11, 14, 10, 18, 9, 0, 14, 7, 12, 10, @@ -5733,9 +5676,7 @@ static const uint8_t hq_tab_10[] = { 0, 12, 2, 19, 0, 1, 5, 5, 4, 11, 3, 15, 4, 17, 3, 1, 8, 7, 7, 11, 8, 13, 7, 17, 6, 3, 11, 4, 9, 9, 11, 13, 10, 19, 9, 0, 13, 6, 12, 9, 14, 15, 13, 19, 14, -}; - -static const uint8_t hq_tab_11[] = { + [PROFILE_11_OFFSET] = /* Profile 11 - 160 elements */ 0, 0, 3, 3, 5, 1, 6, 0, 8, 2, 1, 5, 3, 7, 4, 6, 6, 4, 9, 7, 1, 0, 2, 3, 4, 1, 7, 0, 9, 2, 0, 5, 2, 7, 5, 6, 7, 4, 8, 7, 1, 1, 2, 0, 4, @@ -5747,9 +5688,7 @@ static const uint8_t hq_tab_11[] = { 1, 3, 2, 2, 4, 0, 7, 3, 9, 1, 0, 4, 2, 6, 5, 5, 7, 7, 8, 6, 0, 3, 3, 2, 5, 0, 6, 3, 8, 1, 1, 4, 3, 6, 4, 5, 6, 7, 9, 6, -}; - -static const uint8_t hq_tab_12[] = { + [PROFILE_12_OFFSET] = /* Profile 12 - 3800 elements */ 0, 0, 13, 3, 22, 0, 31, 3, 44, 0, 3, 11, 12, 8, 21, 11, 34, 8, 40, 12, 2, 16, 11, 19, 24, 16, 30, 20, 46, 16, 1, 27, 14, 24, 20, 28, 36, 24, 42, 28, 4, 32, 10, 36, 26, @@ -6004,9 +5943,7 @@ static const uint8_t hq_tab_12[] = { 11, 33, 8, 40, 11, 1, 16, 12, 19, 23, 16, 30, 19, 45, 16, 2, 27, 13, 24, 20, 27, 35, 24, 41, 28, 3, 32, 10, 35, 25, 32, 31, 36, 47, 32, -}; - -static const uint8_t hq_tab_13[] = { + [PROFILE_13_OFFSET] = /* Profile 13 - 1320 elements */ 0, 0, 15, 1, 7, 4, 18, 3, 4, 6, 11, 7, 10, 11, 14, 9, 8, 12, 14, 14, 6, 17, 11, 16, 9, 19, 18, 20, 2, 23, 15, 22, 5, 25, 11, 24, 9, 27, 19, 28, 1, 0, 14, 1, 8, @@ -6095,9 +6032,7 @@ static const uint8_t hq_tab_13[] = { 26, 0, 29, 17, 28, 10, 2, 16, 1, 6, 4, 19, 3, 3, 6, 12, 7, 10, 10, 15, 9, 7, 12, 13, 14, 7, 17, 11, 15, 10, 19, 17, 20, 3, 23, 14, 22, 6, 25, 21, 26, 10, 27, 18, 28, -}; - -static const uint8_t hq_tab_14[] = { + [PROFILE_14_OFFSET] = /* Profile 14 - 660 elements */ 0, 0, 17, 0, 0, 2, 14, 1, 9, 3, 14, 3, 9, 5, 19, 4, 2, 6, 19, 6, 9, 6, 12, 7, 7, 9, 16, 8, 0, 9, 15, 9, 10, 11, 15, 11, 10, 13, 18, 12, 1, 14, 18, 14, 1, @@ -6142,9 +6077,7 @@ static const uint8_t hq_tab_14[] = { 14, 7, 1, 16, 0, 0, 1, 15, 1, 10, 3, 15, 3, 10, 5, 18, 4, 1, 6, 18, 6, 1, 8, 13, 7, 8, 9, 15, 8, 1, 9, 20, 10, 10, 10, 16, 11, 10, 12, 17, 12, 0, 14, 17, 14, -}; - -static const uint8_t hq_tab_15[] = { + [PROFILE_15_OFFSET] = /* Profile 15 - 792 elements */ 0, 0, 15, 1, 3, 3, 14, 2, 4, 4, 11, 5, 0, 6, 18, 6, 8, 8, 14, 8, 4, 10, 21, 11, 9, 13, 18, 12, 8, 14, 17, 15, 5, 17, 21, 17, 1, 0, 14, 1, 2, 3, 15, 2, 5, @@ -6198,9 +6131,7 @@ static const uint8_t hq_tab_15[] = { 19, 15, 7, 17, 20, 16, 0, 1, 16, 1, 4, 3, 13, 2, 3, 4, 12, 5, 0, 7, 17, 6, 7, 8, 13, 8, 3, 10, 21, 10, 10, 13, 17, 12, 7, 14, 18, 15, 6, 17, 21, 16, -}; - -static const uint8_t hq_tab_16[] = { + [PROFILE_16_OFFSET] = /* Profile 16 - 198 elements */ 0, 0, 4, 1, 2, 2, 2, 3, 4, 4, 0, 5, 6, 6, 9, 7, 8, 8, 1, 0, 3, 1, 3, 2, 1, 3, 5, 4, 10, 5, 7, 6, 8, 7, 9, 8, 2, 0, 2, 1, 4, 2, 0, 3, 6, @@ -6214,10 +6145,8 @@ static const uint8_t hq_tab_16[] = { 5, 3, 1, 4, 3, 5, 3, 6, 1, 7, 5, 8, 9, 0, 6, 1, 0, 2, 4, 3, 2, 4, 2, 5, 4, 6, 0, 7, 6, 8, 10, 0, 5, 1, 1, 2, 3, 3, 3, 4, 1, 5, 5, 6, 10, - 7, 7, 8, 0, 0, -}; - -static const uint8_t hq_tab_17[] = { + 7, 7, 8, + [PROFILE_17_OFFSET] = /* Profile 17 - 10240 elements */ 0, 0, 25, 8, 34, 0, 59, 8, 68, 0, 13, 24, 22, 16, 47, 24, 56, 16, 78, 25, 10, 32, 28, 41, 44, 32, 58, 41, 78, 32, 8, 57, 31, 49, 38, 57, 61, 49, 68, 57, 1, 0, 26, 8, 35, @@ -6901,9 +6830,7 @@ static const uint8_t hq_tab_17[] = { 0, 15, 24, 8, 33, 0, 58, 8, 67, 0, 12, 24, 21, 16, 46, 24, 55, 16, 79, 25, 9, 32, 29, 41, 43, 32, 59, 41, 77, 32, 9, 57, 31, 48, 39, 57, 62, 49, 69, 57, -}; - -static const uint8_t hq_tab_18[] = { + [PROFILE_18_OFFSET] = /* Profile 18 - 9600 elements */ 0, 0, 25, 6, 34, 0, 59, 6, 68, 0, 13, 18, 22, 12, 47, 18, 56, 12, 78, 19, 10, 24, 28, 31, 44, 24, 58, 31, 78, 24, 8, 43, 31, 37, 38, 43, 61, 37, 68, 43, 11, 49, 18, 55, 41, @@ -7544,9 +7471,7 @@ static const uint8_t hq_tab_18[] = { 0, 58, 6, 67, 0, 12, 18, 21, 12, 46, 18, 55, 12, 79, 19, 9, 24, 29, 31, 43, 24, 59, 31, 77, 24, 9, 43, 31, 36, 39, 43, 62, 37, 69, 43, 12, 49, 19, 55, 42, 49, 49, 55, 72, 49, -}; - -static const uint8_t hq_tab_19[] = { + [PROFILE_19_OFFSET] = /* Profile 19 - 6144 elements */ 0, 0, 25, 4, 34, 0, 59, 4, 12, 12, 21, 8, 46, 12, 55, 8, 8, 16, 30, 21, 42, 16, 60, 21, 11, 29, 29, 24, 41, 29, 63, 24, 15, 33, 22, 37, 45, 33, 52, 37, 3, 45, 26, 41, 33, @@ -7957,9 +7882,7 @@ static const uint8_t hq_tab_19[] = { 12, 20, 8, 45, 12, 54, 8, 7, 16, 31, 21, 41, 16, 61, 21, 12, 29, 28, 24, 42, 29, 62, 24, 15, 32, 23, 37, 46, 33, 53, 37, 4, 45, 27, 41, 34, 45, 57, 41, -}; - -static const uint8_t hq_tab_20[] = { + [PROFILE_20_OFFSET] = /* Profile 20 - 2640 elements */ 0, 0, 15, 3, 24, 0, 35, 3, 1, 9, 16, 6, 22, 10, 40, 6, 8, 12, 14, 16, 32, 12, 38, 16, 6, 22, 19, 19, 30, 22, 39, 19, 5, 25, 21, 29, 25, 25, 41, 29, 1, 0, 14, 3, 25, @@ -8136,9 +8059,7 @@ static const uint8_t hq_tab_20[] = { 28, 27, 25, 43, 29, 0, 5, 16, 3, 23, 0, 36, 3, 2, 9, 15, 6, 22, 9, 39, 6, 7, 12, 13, 16, 31, 12, 37, 16, 5, 22, 20, 19, 29, 22, 40, 19, 6, 25, 21, 28, 26, 25, 42, 29, -}; - -static const uint8_t hq_tab_21[] = { + [PROFILE_21_OFFSET] = /* Profile 21 - 3168 elements */ 0, 0, 15, 3, 24, 0, 35, 3, 1, 9, 16, 6, 22, 10, 40, 6, 8, 12, 14, 16, 32, 12, 38, 16, 6, 22, 19, 19, 30, 22, 39, 19, 5, 25, 21, 29, 25, 25, 41, 29, 7, 35, 11, 31, 27, @@ -8353,30 +8274,6 @@ static const uint8_t hq_tab_21[] = { 35, 33, 32, }; -/* List of profiles, order is important */ -static const HQProfile hq_profile[NUM_HQ_PROFILES] = { - { hq_tab_11, 160, 120, 8, 10, 8 }, // case 0 (default) = case 11 - { hq_tab_01, 720, 480, 8, 25, 54 }, - { hq_tab_02, 720, 486, 8, 15, 93 }, - { hq_tab_03, 720, 576, 8, 20, 81 }, - { hq_tab_04, 960, 720, 12, 25, 108 }, - { hq_tab_05, 1280, 720, 16, 25, 144 }, - { hq_tab_06, 1280, 1080, 16, 20, 272 }, - { hq_tab_07, 1440, 1080, 16, 24, 255 }, - { hq_tab_08, 1920, 1080, 20, 24, 340 }, - { hq_tab_09, 640, 480, 8, 25, 48 }, - { hq_tab_10, 320, 240, 8, 25, 12 }, - { hq_tab_11, 160, 120, 8, 10, 8 }, - { hq_tab_12, 800, 600, 8, 25, 76 }, - { hq_tab_13, 352, 480, 8, 20, 33 }, - { hq_tab_14, 352, 240, 8, 22, 15 }, - { hq_tab_15, 352, 288, 8, 18, 22 }, - { hq_tab_16, 176, 144, 8, 9, 11 }, - { hq_tab_17, 1280, 1024, 16, 20, 256 }, - { hq_tab_18, 1280, 960, 16, 25, 192 }, - { hq_tab_19, 1024, 768, 16, 24, 128 }, - { hq_tab_20, 704, 480, 8, 20, 66 }, - { hq_tab_21, 704, 576, 8, 24, 66 }, -}; +static_assert(sizeof(hq_perms) == NUM_HQ_PERMS, "Inconsistent offsets"); #endif /* AVCODEC_HQ_HQADATA_H */ diff --git a/libavcodec/hqx.c b/libavcodec/hqx.c index ee6c5a662..9ec667258 100644 --- a/libavcodec/hqx.c +++ b/libavcodec/hqx.c @@ -20,17 +20,22 @@ #include +#include "libavutil/frame.h" #include "libavutil/imgutils.h" +#include "libavutil/mem_internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/thread.h" #include "avcodec.h" #include "canopus.h" #include "codec_internal.h" #include "get_bits.h" #include "thread.h" +#include "vlc.h" -#include "hqx.h" #include "hqxdsp.h" +#include "hqxvlc.h" +#include "hq_common.h" /* HQX has four modes - 422, 444, 422alpha and 444alpha - all 12-bit */ enum HQXFormat { @@ -40,23 +45,58 @@ enum HQXFormat { HQX_444A, }; +struct HQXContext; + +typedef int (*mb_decode_func)(struct HQXContext *ctx, + int slice_no, int x, int y); + +typedef struct HQXSlice { + GetBitContext gb; + DECLARE_ALIGNED(16, int16_t, block)[16][64]; +} HQXSlice; + +typedef struct HQXContext { + HQXDSPContext hqxdsp; + HQXSlice slice[16]; + + AVFrame *pic; + mb_decode_func decode_func; + + int format, dcb, width, height; + int interlaced; + + const uint8_t *src; + unsigned int data_size; + uint32_t slice_off[17]; + + const VLCElem *dc_vlc; + + VLC dc11_vlc; +} HQXContext; + #define HQX_HEADER_SIZE 59 +#define AC_IDX(q) ((q) >= 128 ? HQX_AC_Q128 : (q) >= 64 ? HQX_AC_Q64 : \ + (q) >= 32 ? HQX_AC_Q32 : (q) >= 16 ? HQX_AC_Q16 : \ + (q) >= 8 ? HQX_AC_Q8 : HQX_AC_Q0) + /* macroblock selects a group of 4 possible quants and * a block can use any of those four quantisers * one column is powers of 2, the other one is powers of 2 * 3, - * then there is the special one, powers of 2 * 5 */ -static const int hqx_quants[16][4] = { - { 0x1, 0x2, 0x4, 0x8 }, { 0x1, 0x3, 0x6, 0xC }, - { 0x2, 0x4, 0x8, 0x10 }, { 0x3, 0x6, 0xC, 0x18 }, - { 0x4, 0x8, 0x10, 0x20 }, { 0x6, 0xC, 0x18, 0x30 }, - { 0x8, 0x10, 0x20, 0x40 }, - { 0xA, 0x14, 0x28, 0x50 }, - { 0xC, 0x18, 0x30, 0x60 }, - { 0x10, 0x20, 0x40, 0x80 }, { 0x18, 0x30, 0x60, 0xC0 }, - { 0x20, 0x40, 0x80, 0x100 }, { 0x30, 0x60, 0xC0, 0x180 }, - { 0x40, 0x80, 0x100, 0x200 }, { 0x60, 0xC0, 0x180, 0x300 }, - { 0x80, 0x100, 0x200, 0x400 } + * then there is the special one, powers of 2 * 5. + * We also encode the corresponding AC index in these tables in bits 29-31. */ +static const unsigned hqx_quants[16][4] = { +#define Q(q) ((unsigned)AC_IDX(q) << 29 | (q)) + { Q( 0x1), Q( 0x2), Q( 0x4), Q( 0x8) }, { Q( 0x1), Q( 0x3), Q( 0x6), Q( 0xC) }, + { Q( 0x2), Q( 0x4), Q( 0x8), Q( 0x10) }, { Q( 0x3), Q( 0x6), Q( 0xC), Q( 0x18) }, + { Q( 0x4), Q( 0x8), Q( 0x10), Q( 0x20) }, { Q( 0x6), Q( 0xC), Q( 0x18), Q( 0x30) }, + { Q( 0x8), Q( 0x10), Q( 0x20), Q( 0x40) }, + { Q(0xA), Q(0x14), Q(0x28), Q(0x50) }, + { Q( 0xC), Q(0x18), Q( 0x30), Q( 0x60) }, + { Q(0x10), Q( 0x20), Q( 0x40), Q( 0x80) }, { Q(0x18), Q(0x30), Q( 0x60), Q( 0xC0) }, + { Q(0x20), Q( 0x40), Q( 0x80), Q(0x100) }, { Q(0x30), Q(0x60), Q( 0xC0), Q(0x180) }, + { Q(0x40), Q( 0x80), Q(0x100), Q(0x200) }, { Q(0x60), Q(0xC0), Q(0x180), Q(0x300) }, + { Q(0x80), Q(0x100), Q(0x200), Q(0x400) } }; static const uint8_t hqx_quant_luma[64] = { @@ -97,56 +137,43 @@ static inline void put_blocks(HQXContext *ctx, int plane, } static inline void hqx_get_ac(GetBitContext *gb, const HQXAC *ac, - int *run, int *lev) + int *runp, int *lev) { - int val; + int level, run; + OPEN_READER(re, gb); - val = show_bits(gb, ac->lut_bits); - if (ac->lut[val].bits == -1) { - GetBitContext gb2 = *gb; - skip_bits(&gb2, ac->lut_bits); - val = ac->lut[val].lev + show_bits(&gb2, ac->extra_bits); - } - *run = ac->lut[val].run; - *lev = ac->lut[val].lev; - skip_bits(gb, ac->lut[val].bits); + UPDATE_CACHE(re, gb); + GET_RL_VLC(level, run, re, gb, ac->lut, ac->bits, 2, 0); + CLOSE_READER(re, gb); + *runp = run; + *lev = level; } -static int decode_block(GetBitContext *gb, VLC *vlc, - const int *quants, int dcb, +static int decode_block(GetBitContext *gb, const VLCElem vlc[], + const unsigned *quants, int dcb, int16_t block[64], int *last_dc) { - int q, dc; - int ac_idx; - int run, lev, pos = 1; + int run, lev, pos = 0; + unsigned ac_idx, q; + int dc; - memset(block, 0, 64 * sizeof(*block)); - dc = get_vlc2(gb, vlc->table, HQX_DC_VLC_BITS, 2); + dc = get_vlc2(gb, vlc, HQX_DC_VLC_BITS, 2); *last_dc += dc; block[0] = sign_extend(*last_dc << (12 - dcb), 12); q = quants[get_bits(gb, 2)]; - if (q >= 128) - ac_idx = HQX_AC_Q128; - else if (q >= 64) - ac_idx = HQX_AC_Q64; - else if (q >= 32) - ac_idx = HQX_AC_Q32; - else if (q >= 16) - ac_idx = HQX_AC_Q16; - else if (q >= 8) - ac_idx = HQX_AC_Q8; - else - ac_idx = HQX_AC_Q0; + // ac_idx is encoded in the high bits of quants; + // because block is 16 bit, we do not even need to clear said bits. + ac_idx = q >> 29; do { - hqx_get_ac(gb, &ff_hqx_ac[ac_idx], &run, &lev); + hqx_get_ac(gb, &hqx_ac[ac_idx], &run, &lev); pos += run; - if (pos >= 64) + if (pos > 63) break; - block[ff_zigzag_direct[pos++]] = lev * q; - } while (pos < 64); + block[ff_zigzag_direct[pos]] = lev * q; + } while (pos < 63); return 0; } @@ -155,11 +182,13 @@ static int hqx_decode_422(HQXContext *ctx, int slice_no, int x, int y) { HQXSlice *slice = &ctx->slice[slice_no]; GetBitContext *gb = &slice->gb; - const int *quants; + const unsigned *quants; int flag; int last_dc; int i, ret; + memset(slice->block, 0, sizeof(*slice->block) * 8); + if (ctx->interlaced) flag = get_bits1(gb); else @@ -168,10 +197,9 @@ static int hqx_decode_422(HQXContext *ctx, int slice_no, int x, int y) quants = hqx_quants[get_bits(gb, 4)]; for (i = 0; i < 8; i++) { - int vlc_index = ctx->dcb - 9; if (i == 0 || i == 4 || i == 6) last_dc = 0; - ret = decode_block(gb, &ctx->dc_vlc[vlc_index], quants, + ret = decode_block(gb, ctx->dc_vlc, quants, ctx->dcb, slice->block[i], &last_dc); if (ret < 0) return ret; @@ -189,25 +217,23 @@ static int hqx_decode_422a(HQXContext *ctx, int slice_no, int x, int y) { HQXSlice *slice = &ctx->slice[slice_no]; GetBitContext *gb = &slice->gb; - const int *quants; int flag = 0; int last_dc; int i, ret; - int cbp; - cbp = get_vlc2(gb, ctx->cbp_vlc.table, HQX_CBP_VLC_BITS, 1); - - for (i = 0; i < 12; i++) - memset(slice->block[i], 0, sizeof(**slice->block) * 64); + memset(slice->block, 0, sizeof(*slice->block) * 12); for (i = 0; i < 12; i++) slice->block[i][0] = -0x800; + + int cbp = get_vlc2(gb, ff_hq_cbp_vlc, HQ_CBP_VLC_BITS, 1); if (cbp) { + const unsigned *quants; + if (ctx->interlaced) flag = get_bits1(gb); quants = hqx_quants[get_bits(gb, 4)]; - cbp |= cbp << 4; // alpha CBP if (cbp & 0x3) // chroma CBP - top cbp |= 0x500; if (cbp & 0xC) // chroma CBP - bottom @@ -216,8 +242,7 @@ static int hqx_decode_422a(HQXContext *ctx, int slice_no, int x, int y) if (i == 0 || i == 4 || i == 8 || i == 10) last_dc = 0; if (cbp & (1 << i)) { - int vlc_index = ctx->dcb - 9; - ret = decode_block(gb, &ctx->dc_vlc[vlc_index], quants, + ret = decode_block(gb, ctx->dc_vlc, quants, ctx->dcb, slice->block[i], &last_dc); if (ret < 0) return ret; @@ -239,11 +264,13 @@ static int hqx_decode_444(HQXContext *ctx, int slice_no, int x, int y) { HQXSlice *slice = &ctx->slice[slice_no]; GetBitContext *gb = &slice->gb; - const int *quants; + const unsigned *quants; int flag; int last_dc; int i, ret; + memset(slice->block, 0, sizeof(*slice->block) * 12); + if (ctx->interlaced) flag = get_bits1(gb); else @@ -252,10 +279,9 @@ static int hqx_decode_444(HQXContext *ctx, int slice_no, int x, int y) quants = hqx_quants[get_bits(gb, 4)]; for (i = 0; i < 12; i++) { - int vlc_index = ctx->dcb - 9; - if (i == 0 || i == 4 || i == 8) + if (!(i & 3)) last_dc = 0; - ret = decode_block(gb, &ctx->dc_vlc[vlc_index], quants, + ret = decode_block(gb, ctx->dc_vlc, quants, ctx->dcb, slice->block[i], &last_dc); if (ret < 0) return ret; @@ -275,32 +301,29 @@ static int hqx_decode_444a(HQXContext *ctx, int slice_no, int x, int y) { HQXSlice *slice = &ctx->slice[slice_no]; GetBitContext *gb = &slice->gb; - const int *quants; int flag = 0; int last_dc; int i, ret; - int cbp; - cbp = get_vlc2(gb, ctx->cbp_vlc.table, HQX_CBP_VLC_BITS, 1); - - for (i = 0; i < 16; i++) - memset(slice->block[i], 0, sizeof(**slice->block) * 64); + memset(slice->block, 0, sizeof(*slice->block) * 16); for (i = 0; i < 16; i++) slice->block[i][0] = -0x800; + + int cbp = get_vlc2(gb, ff_hq_cbp_vlc, HQ_CBP_VLC_BITS, 1); if (cbp) { + const unsigned *quants; + if (ctx->interlaced) flag = get_bits1(gb); quants = hqx_quants[get_bits(gb, 4)]; - cbp |= cbp << 4; // alpha CBP cbp |= cbp << 8; // chroma CBP for (i = 0; i < 16; i++) { - if (i == 0 || i == 4 || i == 8 || i == 12) + if (!(i & 3)) last_dc = 0; if (cbp & (1 << i)) { - int vlc_index = ctx->dcb - 9; - ret = decode_block(gb, &ctx->dc_vlc[vlc_index], quants, + ret = decode_block(gb, ctx->dc_vlc, quants, ctx->dcb, slice->block[i], &last_dc); if (ret < 0) return ret; @@ -406,7 +429,7 @@ static int hqx_decode_frame(AVCodecContext *avctx, AVFrame *frame, HQXContext *ctx = avctx->priv_data; const uint8_t *src = avpkt->data; uint32_t info_tag; - int data_start; + int data_start, dcb_code; int i, ret; if (avpkt->size < 4 + 4) { @@ -445,16 +468,18 @@ static int hqx_decode_frame(AVCodecContext *avctx, AVFrame *frame, } ctx->interlaced = !(src[2] & 0x80); ctx->format = src[2] & 7; - ctx->dcb = (src[3] & 3) + 8; + dcb_code = src[3] & 3; ctx->width = AV_RB16(src + 4); ctx->height = AV_RB16(src + 6); for (i = 0; i < 17; i++) ctx->slice_off[i] = AV_RB24(src + 8 + i * 3); - if (ctx->dcb == 8) { - av_log(avctx, AV_LOG_ERROR, "Invalid DC precision %d.\n", ctx->dcb); + if (dcb_code == 0) { + av_log(avctx, AV_LOG_ERROR, "Invalid DC precision 8.\n"); return AVERROR_INVALIDDATA; } + ctx->dc_vlc = dcb_code == 3 ? ctx->dc11_vlc.table : dc_vlc[dcb_code - 1]; + ctx->dcb = dcb_code + 8; ret = av_image_check_size(ctx->width, ctx->height, 0, avctx); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Invalid stored dimensions %dx%d.\n", @@ -511,24 +536,28 @@ static int hqx_decode_frame(AVCodecContext *avctx, AVFrame *frame, static av_cold int hqx_decode_close(AVCodecContext *avctx) { - int i; HQXContext *ctx = avctx->priv_data; - ff_vlc_free(&ctx->cbp_vlc); - for (i = 0; i < 3; i++) { - ff_vlc_free(&ctx->dc_vlc[i]); - } + ff_vlc_free(&ctx->dc11_vlc); return 0; } static av_cold int hqx_decode_init(AVCodecContext *avctx) { + static AVOnce init_static_once = AV_ONCE_INIT; HQXContext *ctx = avctx->priv_data; + int ret = vlc_init(&ctx->dc11_vlc, HQX_DC_VLC_BITS, FF_ARRAY_ELEMS(dc11_vlc_lens), + dc11_vlc_lens, 1, 1, dc11_vlc_bits, 2, 2, 0); + + if (ret < 0) + return ret; ff_hqxdsp_init(&ctx->hqxdsp); - return ff_hqx_init_vlcs(ctx); + ff_thread_once(&init_static_once, hqx_init_static); + + return 0; } const FFCodec ff_hqx_decoder = { diff --git a/libavcodec/hqx.h b/libavcodec/hqx.h deleted file mode 100644 index 155ec7f84..000000000 --- a/libavcodec/hqx.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Canopus HQX decoder - * - * 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_HQX_H -#define AVCODEC_HQX_H - -#include - -#include "libavutil/frame.h" -#include "libavutil/mem_internal.h" - -#include "get_bits.h" -#include "hqxdsp.h" - -enum HQXACMode { - HQX_AC_Q0 = 0, - HQX_AC_Q8, - HQX_AC_Q16, - HQX_AC_Q32, - HQX_AC_Q64, - HQX_AC_Q128, - NUM_HQX_AC -}; - -typedef struct HQXLUT { - int16_t lev; - uint8_t run; - int8_t bits; -} HQXLUT; - -typedef struct HQXAC { - int lut_bits, extra_bits; - const HQXLUT *lut; -} HQXAC; - -struct HQXContext; - -typedef int (*mb_decode_func)(struct HQXContext *ctx, - int slice_no, int x, int y); - -typedef struct HQXSlice { - GetBitContext gb; - DECLARE_ALIGNED(16, int16_t, block)[16][64]; -} HQXSlice; - -typedef struct HQXContext { - HQXDSPContext hqxdsp; - HQXSlice slice[16]; - - AVFrame *pic; - mb_decode_func decode_func; - - int format, dcb, width, height; - int interlaced; - - const uint8_t *src; - unsigned int data_size; - uint32_t slice_off[17]; - - VLC cbp_vlc; - VLC dc_vlc[3]; -} HQXContext; - -#define HQX_CBP_VLC_BITS 5 -#define HQX_DC_VLC_BITS 9 - -extern const HQXAC ff_hqx_ac[NUM_HQX_AC]; - -int ff_hqx_init_vlcs(HQXContext *ctx); - -#endif /* AVCODEC_HQX_H */ diff --git a/libavcodec/hqxvlc.c b/libavcodec/hqxvlc.c deleted file mode 100644 index 1eeda4fcc..000000000 --- a/libavcodec/hqxvlc.c +++ /dev/null @@ -1,2163 +0,0 @@ -/* - * Canopus HQX decoder - * - * 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 "hqx.h" - -static const uint8_t cbp_vlc_bits[16] = { - 0x04, 0x1C, 0x1D, 0x09, 0x1E, 0x0B, 0x1B, 0x08, - 0x1F, 0x1A, 0x0C, 0x07, 0x0A, 0x06, 0x05, 0x00, -}; - -static const uint8_t cbp_vlc_lens[16] = { - 4, 5, 5, 4, 5, 4, 5, 4, 5, 5, 4, 4, 4, 4, 4, 2, -}; - -static const uint16_t dc9_vlc_bits[512] = { - 0x0010, 0x0008, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, - 0x002E, 0x0030, 0x0032, 0x0034, 0x0074, 0x0076, 0x0078, 0x007A, - 0x007C, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, - 0x000E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, - 0x005E, 0x0020, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, - 0x002E, 0x0030, 0x0032, 0x0034, 0x0036, 0x0038, 0x003A, 0x003C, - 0x003E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, - 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, - 0x00DE, 0x01C0, 0x01C2, 0x01C4, 0x01C6, 0x01C8, 0x01CA, 0x01CC, - 0x01CE, 0x01D0, 0x01D2, 0x01D4, 0x01D6, 0x01D8, 0x01DA, 0x01DC, - 0x01DE, 0x01E0, 0x01E2, 0x01E4, 0x01E6, 0x01E8, 0x01EA, 0x01EC, - 0x01EE, 0x01F0, 0x01F2, 0x01F4, 0x01F6, 0x01F8, 0x01FA, 0x01FC, - 0x01FE, 0x06C0, 0x06C2, 0x06C4, 0x06C6, 0x06C8, 0x06CA, 0x06CC, - 0x06CE, 0x06D0, 0x06D2, 0x06D4, 0x06D6, 0x06D8, 0x06DA, 0x06DC, - 0x06DE, 0x06E0, 0x06E2, 0x06E4, 0x06E6, 0x06E8, 0x06EA, 0x06EC, - 0x06EE, 0x06F0, 0x06F2, 0x06F4, 0x06F6, 0x06F8, 0x06FA, 0x06FC, - 0x06FE, 0x0E00, 0x0E02, 0x0E04, 0x0E06, 0x0E08, 0x0E0A, 0x0E0C, - 0x0E0E, 0x0E10, 0x0E12, 0x0E14, 0x0E16, 0x0E18, 0x0E1A, 0x0E1C, - 0x0E1E, 0x0E20, 0x0E22, 0x0E24, 0x0E26, 0x0E28, 0x0E2A, 0x0E2C, - 0x0E2E, 0x0E30, 0x0E32, 0x0E34, 0x0E36, 0x0E38, 0x0E3A, 0x0E3C, - 0x0E3E, 0x0E40, 0x0E42, 0x0E44, 0x0E46, 0x0E48, 0x0E4A, 0x0E4C, - 0x0E4E, 0x0E50, 0x0E52, 0x0E54, 0x0E56, 0x0E58, 0x0E5A, 0x0E5C, - 0x0E5E, 0x0E60, 0x0E62, 0x0E64, 0x0E66, 0x0E68, 0x0E6A, 0x0E6C, - 0x0E6E, 0x0E70, 0x0E72, 0x0E74, 0x0E76, 0x0E78, 0x0E7A, 0x0E7C, - 0x0E7E, 0x1F80, 0x1F82, 0x1F84, 0x1F86, 0x1F88, 0x1F8A, 0x1F8C, - 0x1F8E, 0x1F90, 0x1F92, 0x1F94, 0x1F96, 0x1F98, 0x1F9A, 0x1F9C, - 0x1F9E, 0x1FA0, 0x1FA2, 0x1FA4, 0x1FA6, 0x1FA8, 0x1FAA, 0x1FAC, - 0x1FAE, 0x1FB0, 0x1FB2, 0x1FB4, 0x1FB6, 0x1FB8, 0x1FBA, 0x1FBC, - 0x1FBE, 0x1FC0, 0x1FC2, 0x1FC4, 0x1FC6, 0x1FC8, 0x1FCA, 0x1FCC, - 0x1FCE, 0x1FD0, 0x1FD2, 0x1FD4, 0x1FD6, 0x1FD8, 0x1FDA, 0x1FDC, - 0x1FDE, 0x1FE0, 0x1FE2, 0x1FE4, 0x1FE6, 0x1FE8, 0x1FEA, 0x1FEC, - 0x1FEE, 0x1FF0, 0x1FF2, 0x1FF4, 0x1FF6, 0x1FF8, 0x1FFA, 0x1FFC, - 0x0FFF, 0x1FFD, 0x1FFB, 0x1FF9, 0x1FF7, 0x1FF5, 0x1FF3, 0x1FF1, - 0x1FEF, 0x1FED, 0x1FEB, 0x1FE9, 0x1FE7, 0x1FE5, 0x1FE3, 0x1FE1, - 0x1FDF, 0x1FDD, 0x1FDB, 0x1FD9, 0x1FD7, 0x1FD5, 0x1FD3, 0x1FD1, - 0x1FCF, 0x1FCD, 0x1FCB, 0x1FC9, 0x1FC7, 0x1FC5, 0x1FC3, 0x1FC1, - 0x1FBF, 0x1FBD, 0x1FBB, 0x1FB9, 0x1FB7, 0x1FB5, 0x1FB3, 0x1FB1, - 0x1FAF, 0x1FAD, 0x1FAB, 0x1FA9, 0x1FA7, 0x1FA5, 0x1FA3, 0x1FA1, - 0x1F9F, 0x1F9D, 0x1F9B, 0x1F99, 0x1F97, 0x1F95, 0x1F93, 0x1F91, - 0x1F8F, 0x1F8D, 0x1F8B, 0x1F89, 0x1F87, 0x1F85, 0x1F83, 0x1F81, - 0x0E7F, 0x0E7D, 0x0E7B, 0x0E79, 0x0E77, 0x0E75, 0x0E73, 0x0E71, - 0x0E6F, 0x0E6D, 0x0E6B, 0x0E69, 0x0E67, 0x0E65, 0x0E63, 0x0E61, - 0x0E5F, 0x0E5D, 0x0E5B, 0x0E59, 0x0E57, 0x0E55, 0x0E53, 0x0E51, - 0x0E4F, 0x0E4D, 0x0E4B, 0x0E49, 0x0E47, 0x0E45, 0x0E43, 0x0E41, - 0x0E3F, 0x0E3D, 0x0E3B, 0x0E39, 0x0E37, 0x0E35, 0x0E33, 0x0E31, - 0x0E2F, 0x0E2D, 0x0E2B, 0x0E29, 0x0E27, 0x0E25, 0x0E23, 0x0E21, - 0x0E1F, 0x0E1D, 0x0E1B, 0x0E19, 0x0E17, 0x0E15, 0x0E13, 0x0E11, - 0x0E0F, 0x0E0D, 0x0E0B, 0x0E09, 0x0E07, 0x0E05, 0x0E03, 0x0E01, - 0x06FF, 0x06FD, 0x06FB, 0x06F9, 0x06F7, 0x06F5, 0x06F3, 0x06F1, - 0x06EF, 0x06ED, 0x06EB, 0x06E9, 0x06E7, 0x06E5, 0x06E3, 0x06E1, - 0x06DF, 0x06DD, 0x06DB, 0x06D9, 0x06D7, 0x06D5, 0x06D3, 0x06D1, - 0x06CF, 0x06CD, 0x06CB, 0x06C9, 0x06C7, 0x06C5, 0x06C3, 0x06C1, - 0x01FF, 0x01FD, 0x01FB, 0x01F9, 0x01F7, 0x01F5, 0x01F3, 0x01F1, - 0x01EF, 0x01ED, 0x01EB, 0x01E9, 0x01E7, 0x01E5, 0x01E3, 0x01E1, - 0x01DF, 0x01DD, 0x01DB, 0x01D9, 0x01D7, 0x01D5, 0x01D3, 0x01D1, - 0x01CF, 0x01CD, 0x01CB, 0x01C9, 0x01C7, 0x01C5, 0x01C3, 0x01C1, - 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, - 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, - 0x003F, 0x003D, 0x003B, 0x0039, 0x0037, 0x0035, 0x0033, 0x0031, - 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0021, - 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, - 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, - 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0035, 0x0033, 0x0031, - 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0009, -}; - -static const uint8_t dc9_vlc_lens[512] = { - 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 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, - 12, 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, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 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, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, -}; - -static const uint16_t dc10_vlc_bits[1024] = { - 0x0014, 0x002A, 0x002C, 0x002E, 0x0064, 0x0066, 0x0068, 0x006A, - 0x006C, 0x006E, 0x0070, 0x0072, 0x0074, 0x0076, 0x0078, 0x007A, - 0x007C, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, - 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, - 0x005E, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, - 0x000E, 0x0010, 0x0012, 0x0014, 0x0016, 0x0018, 0x001A, 0x001C, - 0x001E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, - 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, - 0x00DE, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, - 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, - 0x005E, 0x0060, 0x0062, 0x0064, 0x0066, 0x0068, 0x006A, 0x006C, - 0x006E, 0x0070, 0x0072, 0x0074, 0x0076, 0x0078, 0x007A, 0x007C, - 0x007E, 0x01C0, 0x01C2, 0x01C4, 0x01C6, 0x01C8, 0x01CA, 0x01CC, - 0x01CE, 0x01D0, 0x01D2, 0x01D4, 0x01D6, 0x01D8, 0x01DA, 0x01DC, - 0x01DE, 0x01E0, 0x01E2, 0x01E4, 0x01E6, 0x01E8, 0x01EA, 0x01EC, - 0x01EE, 0x01F0, 0x01F2, 0x01F4, 0x01F6, 0x01F8, 0x01FA, 0x01FC, - 0x01FE, 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040A, 0x040C, - 0x040E, 0x0410, 0x0412, 0x0414, 0x0416, 0x0418, 0x041A, 0x041C, - 0x041E, 0x0420, 0x0422, 0x0424, 0x0426, 0x0428, 0x042A, 0x042C, - 0x042E, 0x0430, 0x0432, 0x0434, 0x0436, 0x0438, 0x043A, 0x043C, - 0x043E, 0x0440, 0x0442, 0x0444, 0x0446, 0x0448, 0x044A, 0x044C, - 0x044E, 0x0450, 0x0452, 0x0454, 0x0456, 0x0458, 0x045A, 0x045C, - 0x045E, 0x0460, 0x0462, 0x0464, 0x0466, 0x0468, 0x046A, 0x046C, - 0x046E, 0x0470, 0x0472, 0x0474, 0x0476, 0x0478, 0x047A, 0x047C, - 0x047E, 0x0C00, 0x0C02, 0x0C04, 0x0C06, 0x0C08, 0x0C0A, 0x0C0C, - 0x0C0E, 0x0C10, 0x0C12, 0x0C14, 0x0C16, 0x0C18, 0x0C1A, 0x0C1C, - 0x0C1E, 0x0C20, 0x0C22, 0x0C24, 0x0C26, 0x0C28, 0x0C2A, 0x0C2C, - 0x0C2E, 0x0C30, 0x0C32, 0x0C34, 0x0C36, 0x0C38, 0x0C3A, 0x0C3C, - 0x0C3E, 0x0C40, 0x0C42, 0x0C44, 0x0C46, 0x0C48, 0x0C4A, 0x0C4C, - 0x0C4E, 0x0C50, 0x0C52, 0x0C54, 0x0C56, 0x0C58, 0x0C5A, 0x0C5C, - 0x0C5E, 0x0C60, 0x0C62, 0x0C64, 0x0C66, 0x0C68, 0x0C6A, 0x0C6C, - 0x0C6E, 0x0C70, 0x0C72, 0x0C74, 0x0C76, 0x0C78, 0x0C7A, 0x0C7C, - 0x0C7E, 0x0900, 0x0902, 0x0904, 0x0906, 0x0908, 0x090A, 0x090C, - 0x090E, 0x0910, 0x0912, 0x0914, 0x0916, 0x0918, 0x091A, 0x091C, - 0x091E, 0x0920, 0x0922, 0x0924, 0x0926, 0x0928, 0x092A, 0x092C, - 0x092E, 0x0930, 0x0932, 0x0934, 0x0936, 0x0938, 0x093A, 0x093C, - 0x093E, 0x0940, 0x0942, 0x0944, 0x0946, 0x0948, 0x094A, 0x094C, - 0x094E, 0x0950, 0x0952, 0x0954, 0x0956, 0x0958, 0x095A, 0x095C, - 0x095E, 0x0960, 0x0962, 0x0964, 0x0966, 0x0968, 0x096A, 0x096C, - 0x096E, 0x0970, 0x0972, 0x0974, 0x0976, 0x0978, 0x097A, 0x097C, - 0x097E, 0x0980, 0x0982, 0x0984, 0x0986, 0x0988, 0x098A, 0x098C, - 0x098E, 0x0990, 0x0992, 0x0994, 0x0996, 0x0998, 0x099A, 0x099C, - 0x099E, 0x09A0, 0x09A2, 0x09A4, 0x09A6, 0x09A8, 0x09AA, 0x09AC, - 0x09AE, 0x09B0, 0x09B2, 0x09B4, 0x09B6, 0x09B8, 0x09BA, 0x09BC, - 0x09BE, 0x09C0, 0x09C2, 0x09C4, 0x09C6, 0x09C8, 0x09CA, 0x09CC, - 0x09CE, 0x09D0, 0x09D2, 0x09D4, 0x09D6, 0x09D8, 0x09DA, 0x09DC, - 0x09DE, 0x09E0, 0x09E2, 0x09E4, 0x09E6, 0x09E8, 0x09EA, 0x09EC, - 0x09EE, 0x09F0, 0x09F2, 0x09F4, 0x09F6, 0x09F8, 0x09FA, 0x09FC, - 0x09FE, 0x3F00, 0x3F02, 0x3F04, 0x3F06, 0x3F08, 0x3F0A, 0x3F0C, - 0x3F0E, 0x3F10, 0x3F12, 0x3F14, 0x3F16, 0x3F18, 0x3F1A, 0x3F1C, - 0x3F1E, 0x3F20, 0x3F22, 0x3F24, 0x3F26, 0x3F28, 0x3F2A, 0x3F2C, - 0x3F2E, 0x3F30, 0x3F32, 0x3F34, 0x3F36, 0x3F38, 0x3F3A, 0x3F3C, - 0x3F3E, 0x3F40, 0x3F42, 0x3F44, 0x3F46, 0x3F48, 0x3F4A, 0x3F4C, - 0x3F4E, 0x3F50, 0x3F52, 0x3F54, 0x3F56, 0x3F58, 0x3F5A, 0x3F5C, - 0x3F5E, 0x3F60, 0x3F62, 0x3F64, 0x3F66, 0x3F68, 0x3F6A, 0x3F6C, - 0x3F6E, 0x3F70, 0x3F72, 0x3F74, 0x3F76, 0x3F78, 0x3F7A, 0x3F7C, - 0x3F7E, 0x3F80, 0x3F82, 0x3F84, 0x3F86, 0x3F88, 0x3F8A, 0x3F8C, - 0x3F8E, 0x3F90, 0x3F92, 0x3F94, 0x3F96, 0x3F98, 0x3F9A, 0x3F9C, - 0x3F9E, 0x3FA0, 0x3FA2, 0x3FA4, 0x3FA6, 0x3FA8, 0x3FAA, 0x3FAC, - 0x3FAE, 0x3FB0, 0x3FB2, 0x3FB4, 0x3FB6, 0x3FB8, 0x3FBA, 0x3FBC, - 0x3FBE, 0x3FC0, 0x3FC2, 0x3FC4, 0x3FC6, 0x3FC8, 0x3FCA, 0x3FCC, - 0x3FCE, 0x3FD0, 0x3FD2, 0x3FD4, 0x3FD6, 0x3FD8, 0x3FDA, 0x3FDC, - 0x3FDE, 0x3FE0, 0x3FE2, 0x3FE4, 0x3FE6, 0x3FE8, 0x3FEA, 0x3FEC, - 0x3FEE, 0x3FF0, 0x3FF2, 0x3FF4, 0x3FF6, 0x3FF8, 0x3FFA, 0x3FFC, - 0x1FFF, 0x3FFD, 0x3FFB, 0x3FF9, 0x3FF7, 0x3FF5, 0x3FF3, 0x3FF1, - 0x3FEF, 0x3FED, 0x3FEB, 0x3FE9, 0x3FE7, 0x3FE5, 0x3FE3, 0x3FE1, - 0x3FDF, 0x3FDD, 0x3FDB, 0x3FD9, 0x3FD7, 0x3FD5, 0x3FD3, 0x3FD1, - 0x3FCF, 0x3FCD, 0x3FCB, 0x3FC9, 0x3FC7, 0x3FC5, 0x3FC3, 0x3FC1, - 0x3FBF, 0x3FBD, 0x3FBB, 0x3FB9, 0x3FB7, 0x3FB5, 0x3FB3, 0x3FB1, - 0x3FAF, 0x3FAD, 0x3FAB, 0x3FA9, 0x3FA7, 0x3FA5, 0x3FA3, 0x3FA1, - 0x3F9F, 0x3F9D, 0x3F9B, 0x3F99, 0x3F97, 0x3F95, 0x3F93, 0x3F91, - 0x3F8F, 0x3F8D, 0x3F8B, 0x3F89, 0x3F87, 0x3F85, 0x3F83, 0x3F81, - 0x3F7F, 0x3F7D, 0x3F7B, 0x3F79, 0x3F77, 0x3F75, 0x3F73, 0x3F71, - 0x3F6F, 0x3F6D, 0x3F6B, 0x3F69, 0x3F67, 0x3F65, 0x3F63, 0x3F61, - 0x3F5F, 0x3F5D, 0x3F5B, 0x3F59, 0x3F57, 0x3F55, 0x3F53, 0x3F51, - 0x3F4F, 0x3F4D, 0x3F4B, 0x3F49, 0x3F47, 0x3F45, 0x3F43, 0x3F41, - 0x3F3F, 0x3F3D, 0x3F3B, 0x3F39, 0x3F37, 0x3F35, 0x3F33, 0x3F31, - 0x3F2F, 0x3F2D, 0x3F2B, 0x3F29, 0x3F27, 0x3F25, 0x3F23, 0x3F21, - 0x3F1F, 0x3F1D, 0x3F1B, 0x3F19, 0x3F17, 0x3F15, 0x3F13, 0x3F11, - 0x3F0F, 0x3F0D, 0x3F0B, 0x3F09, 0x3F07, 0x3F05, 0x3F03, 0x3F01, - 0x09FF, 0x09FD, 0x09FB, 0x09F9, 0x09F7, 0x09F5, 0x09F3, 0x09F1, - 0x09EF, 0x09ED, 0x09EB, 0x09E9, 0x09E7, 0x09E5, 0x09E3, 0x09E1, - 0x09DF, 0x09DD, 0x09DB, 0x09D9, 0x09D7, 0x09D5, 0x09D3, 0x09D1, - 0x09CF, 0x09CD, 0x09CB, 0x09C9, 0x09C7, 0x09C5, 0x09C3, 0x09C1, - 0x09BF, 0x09BD, 0x09BB, 0x09B9, 0x09B7, 0x09B5, 0x09B3, 0x09B1, - 0x09AF, 0x09AD, 0x09AB, 0x09A9, 0x09A7, 0x09A5, 0x09A3, 0x09A1, - 0x099F, 0x099D, 0x099B, 0x0999, 0x0997, 0x0995, 0x0993, 0x0991, - 0x098F, 0x098D, 0x098B, 0x0989, 0x0987, 0x0985, 0x0983, 0x0981, - 0x097F, 0x097D, 0x097B, 0x0979, 0x0977, 0x0975, 0x0973, 0x0971, - 0x096F, 0x096D, 0x096B, 0x0969, 0x0967, 0x0965, 0x0963, 0x0961, - 0x095F, 0x095D, 0x095B, 0x0959, 0x0957, 0x0955, 0x0953, 0x0951, - 0x094F, 0x094D, 0x094B, 0x0949, 0x0947, 0x0945, 0x0943, 0x0941, - 0x093F, 0x093D, 0x093B, 0x0939, 0x0937, 0x0935, 0x0933, 0x0931, - 0x092F, 0x092D, 0x092B, 0x0929, 0x0927, 0x0925, 0x0923, 0x0921, - 0x091F, 0x091D, 0x091B, 0x0919, 0x0917, 0x0915, 0x0913, 0x0911, - 0x090F, 0x090D, 0x090B, 0x0909, 0x0907, 0x0905, 0x0903, 0x0901, - 0x0C7F, 0x0C7D, 0x0C7B, 0x0C79, 0x0C77, 0x0C75, 0x0C73, 0x0C71, - 0x0C6F, 0x0C6D, 0x0C6B, 0x0C69, 0x0C67, 0x0C65, 0x0C63, 0x0C61, - 0x0C5F, 0x0C5D, 0x0C5B, 0x0C59, 0x0C57, 0x0C55, 0x0C53, 0x0C51, - 0x0C4F, 0x0C4D, 0x0C4B, 0x0C49, 0x0C47, 0x0C45, 0x0C43, 0x0C41, - 0x0C3F, 0x0C3D, 0x0C3B, 0x0C39, 0x0C37, 0x0C35, 0x0C33, 0x0C31, - 0x0C2F, 0x0C2D, 0x0C2B, 0x0C29, 0x0C27, 0x0C25, 0x0C23, 0x0C21, - 0x0C1F, 0x0C1D, 0x0C1B, 0x0C19, 0x0C17, 0x0C15, 0x0C13, 0x0C11, - 0x0C0F, 0x0C0D, 0x0C0B, 0x0C09, 0x0C07, 0x0C05, 0x0C03, 0x0C01, - 0x047F, 0x047D, 0x047B, 0x0479, 0x0477, 0x0475, 0x0473, 0x0471, - 0x046F, 0x046D, 0x046B, 0x0469, 0x0467, 0x0465, 0x0463, 0x0461, - 0x045F, 0x045D, 0x045B, 0x0459, 0x0457, 0x0455, 0x0453, 0x0451, - 0x044F, 0x044D, 0x044B, 0x0449, 0x0447, 0x0445, 0x0443, 0x0441, - 0x043F, 0x043D, 0x043B, 0x0439, 0x0437, 0x0435, 0x0433, 0x0431, - 0x042F, 0x042D, 0x042B, 0x0429, 0x0427, 0x0425, 0x0423, 0x0421, - 0x041F, 0x041D, 0x041B, 0x0419, 0x0417, 0x0415, 0x0413, 0x0411, - 0x040F, 0x040D, 0x040B, 0x0409, 0x0407, 0x0405, 0x0403, 0x0401, - 0x01FF, 0x01FD, 0x01FB, 0x01F9, 0x01F7, 0x01F5, 0x01F3, 0x01F1, - 0x01EF, 0x01ED, 0x01EB, 0x01E9, 0x01E7, 0x01E5, 0x01E3, 0x01E1, - 0x01DF, 0x01DD, 0x01DB, 0x01D9, 0x01D7, 0x01D5, 0x01D3, 0x01D1, - 0x01CF, 0x01CD, 0x01CB, 0x01C9, 0x01C7, 0x01C5, 0x01C3, 0x01C1, - 0x007F, 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0073, 0x0071, - 0x006F, 0x006D, 0x006B, 0x0069, 0x0067, 0x0065, 0x0063, 0x0061, - 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, - 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, - 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, - 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, - 0x001F, 0x001D, 0x001B, 0x0019, 0x0017, 0x0015, 0x0013, 0x0011, - 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, - 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, - 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, - 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0073, 0x0071, 0x006F, - 0x006D, 0x006B, 0x0069, 0x0067, 0x0065, 0x002F, 0x002D, 0x002B, -}; - -static const uint8_t dc10_vlc_lens[1024] = { - 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 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, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 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, - 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, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, -}; - -static const uint16_t dc11_vlc_bits[2048] = { - 0x0032, 0x0066, 0x0068, 0x006A, 0x006C, 0x006E, 0x0070, 0x0072, - 0x0074, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, - 0x00FE, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, - 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, - 0x005E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, - 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, - 0x00DE, 0x00E0, 0x00E2, 0x00E4, 0x00E6, 0x00E8, 0x00EA, 0x00EC, - 0x00EE, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, - 0x00FE, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, - 0x000E, 0x0010, 0x0012, 0x0014, 0x0016, 0x0018, 0x001A, 0x001C, - 0x001E, 0x0020, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, - 0x002E, 0x0030, 0x0032, 0x0034, 0x0036, 0x0038, 0x003A, 0x003C, - 0x003E, 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020A, 0x020C, - 0x020E, 0x0210, 0x0212, 0x0214, 0x0216, 0x0218, 0x021A, 0x021C, - 0x021E, 0x0220, 0x0222, 0x0224, 0x0226, 0x0228, 0x022A, 0x022C, - 0x022E, 0x0230, 0x0232, 0x0234, 0x0236, 0x0238, 0x023A, 0x023C, - 0x023E, 0x0080, 0x0082, 0x0084, 0x0086, 0x0088, 0x008A, 0x008C, - 0x008E, 0x0090, 0x0092, 0x0094, 0x0096, 0x0098, 0x009A, 0x009C, - 0x009E, 0x00A0, 0x00A2, 0x00A4, 0x00A6, 0x00A8, 0x00AA, 0x00AC, - 0x00AE, 0x00B0, 0x00B2, 0x00B4, 0x00B6, 0x00B8, 0x00BA, 0x00BC, - 0x00BE, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, - 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, - 0x00DE, 0x00E0, 0x00E2, 0x00E4, 0x00E6, 0x00E8, 0x00EA, 0x00EC, - 0x00EE, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, - 0x00FE, 0x0480, 0x0482, 0x0484, 0x0486, 0x0488, 0x048A, 0x048C, - 0x048E, 0x0490, 0x0492, 0x0494, 0x0496, 0x0498, 0x049A, 0x049C, - 0x049E, 0x04A0, 0x04A2, 0x04A4, 0x04A6, 0x04A8, 0x04AA, 0x04AC, - 0x04AE, 0x04B0, 0x04B2, 0x04B4, 0x04B6, 0x04B8, 0x04BA, 0x04BC, - 0x04BE, 0x04C0, 0x04C2, 0x04C4, 0x04C6, 0x04C8, 0x04CA, 0x04CC, - 0x04CE, 0x04D0, 0x04D2, 0x04D4, 0x04D6, 0x04D8, 0x04DA, 0x04DC, - 0x04DE, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA, 0x04EC, - 0x04EE, 0x04F0, 0x04F2, 0x04F4, 0x04F6, 0x04F8, 0x04FA, 0x04FC, - 0x04FE, 0x0A00, 0x0A02, 0x0A04, 0x0A06, 0x0A08, 0x0A0A, 0x0A0C, - 0x0A0E, 0x0A10, 0x0A12, 0x0A14, 0x0A16, 0x0A18, 0x0A1A, 0x0A1C, - 0x0A1E, 0x0A20, 0x0A22, 0x0A24, 0x0A26, 0x0A28, 0x0A2A, 0x0A2C, - 0x0A2E, 0x0A30, 0x0A32, 0x0A34, 0x0A36, 0x0A38, 0x0A3A, 0x0A3C, - 0x0A3E, 0x0A40, 0x0A42, 0x0A44, 0x0A46, 0x0A48, 0x0A4A, 0x0A4C, - 0x0A4E, 0x0A50, 0x0A52, 0x0A54, 0x0A56, 0x0A58, 0x0A5A, 0x0A5C, - 0x0A5E, 0x0A60, 0x0A62, 0x0A64, 0x0A66, 0x0A68, 0x0A6A, 0x0A6C, - 0x0A6E, 0x0A70, 0x0A72, 0x0A74, 0x0A76, 0x0A78, 0x0A7A, 0x0A7C, - 0x0A7E, 0x0A80, 0x0A82, 0x0A84, 0x0A86, 0x0A88, 0x0A8A, 0x0A8C, - 0x0A8E, 0x0A90, 0x0A92, 0x0A94, 0x0A96, 0x0A98, 0x0A9A, 0x0A9C, - 0x0A9E, 0x0AA0, 0x0AA2, 0x0AA4, 0x0AA6, 0x0AA8, 0x0AAA, 0x0AAC, - 0x0AAE, 0x0AB0, 0x0AB2, 0x0AB4, 0x0AB6, 0x0AB8, 0x0ABA, 0x0ABC, - 0x0ABE, 0x0AC0, 0x0AC2, 0x0AC4, 0x0AC6, 0x0AC8, 0x0ACA, 0x0ACC, - 0x0ACE, 0x0AD0, 0x0AD2, 0x0AD4, 0x0AD6, 0x0AD8, 0x0ADA, 0x0ADC, - 0x0ADE, 0x0AE0, 0x0AE2, 0x0AE4, 0x0AE6, 0x0AE8, 0x0AEA, 0x0AEC, - 0x0AEE, 0x0AF0, 0x0AF2, 0x0AF4, 0x0AF6, 0x0AF8, 0x0AFA, 0x0AFC, - 0x0AFE, 0x1800, 0x1802, 0x1804, 0x1806, 0x1808, 0x180A, 0x180C, - 0x180E, 0x1810, 0x1812, 0x1814, 0x1816, 0x1818, 0x181A, 0x181C, - 0x181E, 0x1820, 0x1822, 0x1824, 0x1826, 0x1828, 0x182A, 0x182C, - 0x182E, 0x1830, 0x1832, 0x1834, 0x1836, 0x1838, 0x183A, 0x183C, - 0x183E, 0x1840, 0x1842, 0x1844, 0x1846, 0x1848, 0x184A, 0x184C, - 0x184E, 0x1850, 0x1852, 0x1854, 0x1856, 0x1858, 0x185A, 0x185C, - 0x185E, 0x1860, 0x1862, 0x1864, 0x1866, 0x1868, 0x186A, 0x186C, - 0x186E, 0x1870, 0x1872, 0x1874, 0x1876, 0x1878, 0x187A, 0x187C, - 0x187E, 0x1880, 0x1882, 0x1884, 0x1886, 0x1888, 0x188A, 0x188C, - 0x188E, 0x1890, 0x1892, 0x1894, 0x1896, 0x1898, 0x189A, 0x189C, - 0x189E, 0x18A0, 0x18A2, 0x18A4, 0x18A6, 0x18A8, 0x18AA, 0x18AC, - 0x18AE, 0x18B0, 0x18B2, 0x18B4, 0x18B6, 0x18B8, 0x18BA, 0x18BC, - 0x18BE, 0x18C0, 0x18C2, 0x18C4, 0x18C6, 0x18C8, 0x18CA, 0x18CC, - 0x18CE, 0x18D0, 0x18D2, 0x18D4, 0x18D6, 0x18D8, 0x18DA, 0x18DC, - 0x18DE, 0x18E0, 0x18E2, 0x18E4, 0x18E6, 0x18E8, 0x18EA, 0x18EC, - 0x18EE, 0x18F0, 0x18F2, 0x18F4, 0x18F6, 0x18F8, 0x18FA, 0x18FC, - 0x18FE, 0x1600, 0x1602, 0x1604, 0x1606, 0x1608, 0x160A, 0x160C, - 0x160E, 0x1610, 0x1612, 0x1614, 0x1616, 0x1618, 0x161A, 0x161C, - 0x161E, 0x1620, 0x1622, 0x1624, 0x1626, 0x1628, 0x162A, 0x162C, - 0x162E, 0x1630, 0x1632, 0x1634, 0x1636, 0x1638, 0x163A, 0x163C, - 0x163E, 0x1640, 0x1642, 0x1644, 0x1646, 0x1648, 0x164A, 0x164C, - 0x164E, 0x1650, 0x1652, 0x1654, 0x1656, 0x1658, 0x165A, 0x165C, - 0x165E, 0x1660, 0x1662, 0x1664, 0x1666, 0x1668, 0x166A, 0x166C, - 0x166E, 0x1670, 0x1672, 0x1674, 0x1676, 0x1678, 0x167A, 0x167C, - 0x167E, 0x1680, 0x1682, 0x1684, 0x1686, 0x1688, 0x168A, 0x168C, - 0x168E, 0x1690, 0x1692, 0x1694, 0x1696, 0x1698, 0x169A, 0x169C, - 0x169E, 0x16A0, 0x16A2, 0x16A4, 0x16A6, 0x16A8, 0x16AA, 0x16AC, - 0x16AE, 0x16B0, 0x16B2, 0x16B4, 0x16B6, 0x16B8, 0x16BA, 0x16BC, - 0x16BE, 0x16C0, 0x16C2, 0x16C4, 0x16C6, 0x16C8, 0x16CA, 0x16CC, - 0x16CE, 0x16D0, 0x16D2, 0x16D4, 0x16D6, 0x16D8, 0x16DA, 0x16DC, - 0x16DE, 0x16E0, 0x16E2, 0x16E4, 0x16E6, 0x16E8, 0x16EA, 0x16EC, - 0x16EE, 0x16F0, 0x16F2, 0x16F4, 0x16F6, 0x16F8, 0x16FA, 0x16FC, - 0x16FE, 0x1700, 0x1702, 0x1704, 0x1706, 0x1708, 0x170A, 0x170C, - 0x170E, 0x1710, 0x1712, 0x1714, 0x1716, 0x1718, 0x171A, 0x171C, - 0x171E, 0x1720, 0x1722, 0x1724, 0x1726, 0x1728, 0x172A, 0x172C, - 0x172E, 0x1730, 0x1732, 0x1734, 0x1736, 0x1738, 0x173A, 0x173C, - 0x173E, 0x1740, 0x1742, 0x1744, 0x1746, 0x1748, 0x174A, 0x174C, - 0x174E, 0x1750, 0x1752, 0x1754, 0x1756, 0x1758, 0x175A, 0x175C, - 0x175E, 0x1760, 0x1762, 0x1764, 0x1766, 0x1768, 0x176A, 0x176C, - 0x176E, 0x1770, 0x1772, 0x1774, 0x1776, 0x1778, 0x177A, 0x177C, - 0x177E, 0x1780, 0x1782, 0x1784, 0x1786, 0x1788, 0x178A, 0x178C, - 0x178E, 0x1790, 0x1792, 0x1794, 0x1796, 0x1798, 0x179A, 0x179C, - 0x179E, 0x17A0, 0x17A2, 0x17A4, 0x17A6, 0x17A8, 0x17AA, 0x17AC, - 0x17AE, 0x17B0, 0x17B2, 0x17B4, 0x17B6, 0x17B8, 0x17BA, 0x17BC, - 0x17BE, 0x17C0, 0x17C2, 0x17C4, 0x17C6, 0x17C8, 0x17CA, 0x17CC, - 0x17CE, 0x17D0, 0x17D2, 0x17D4, 0x17D6, 0x17D8, 0x17DA, 0x17DC, - 0x17DE, 0x17E0, 0x17E2, 0x17E4, 0x17E6, 0x17E8, 0x17EA, 0x17EC, - 0x17EE, 0x17F0, 0x17F2, 0x17F4, 0x17F6, 0x17F8, 0x17FA, 0x17FC, - 0x17FE, 0x7600, 0x7602, 0x7604, 0x7606, 0x7608, 0x760A, 0x760C, - 0x760E, 0x7610, 0x7612, 0x7614, 0x7616, 0x7618, 0x761A, 0x761C, - 0x761E, 0x7620, 0x7622, 0x7624, 0x7626, 0x7628, 0x762A, 0x762C, - 0x762E, 0x7630, 0x7632, 0x7634, 0x7636, 0x7638, 0x763A, 0x763C, - 0x763E, 0x7640, 0x7642, 0x7644, 0x7646, 0x7648, 0x764A, 0x764C, - 0x764E, 0x7650, 0x7652, 0x7654, 0x7656, 0x7658, 0x765A, 0x765C, - 0x765E, 0x7660, 0x7662, 0x7664, 0x7666, 0x7668, 0x766A, 0x766C, - 0x766E, 0x7670, 0x7672, 0x7674, 0x7676, 0x7678, 0x767A, 0x767C, - 0x767E, 0x7680, 0x7682, 0x7684, 0x7686, 0x7688, 0x768A, 0x768C, - 0x768E, 0x7690, 0x7692, 0x7694, 0x7696, 0x7698, 0x769A, 0x769C, - 0x769E, 0x76A0, 0x76A2, 0x76A4, 0x76A6, 0x76A8, 0x76AA, 0x76AC, - 0x76AE, 0x76B0, 0x76B2, 0x76B4, 0x76B6, 0x76B8, 0x76BA, 0x76BC, - 0x76BE, 0x76C0, 0x76C2, 0x76C4, 0x76C6, 0x76C8, 0x76CA, 0x76CC, - 0x76CE, 0x76D0, 0x76D2, 0x76D4, 0x76D6, 0x76D8, 0x76DA, 0x76DC, - 0x76DE, 0x76E0, 0x76E2, 0x76E4, 0x76E6, 0x76E8, 0x76EA, 0x76EC, - 0x76EE, 0x76F0, 0x76F2, 0x76F4, 0x76F6, 0x76F8, 0x76FA, 0x76FC, - 0x76FE, 0x7700, 0x7702, 0x7704, 0x7706, 0x7708, 0x770A, 0x770C, - 0x770E, 0x7710, 0x7712, 0x7714, 0x7716, 0x7718, 0x771A, 0x771C, - 0x771E, 0x7720, 0x7722, 0x7724, 0x7726, 0x7728, 0x772A, 0x772C, - 0x772E, 0x7730, 0x7732, 0x7734, 0x7736, 0x7738, 0x773A, 0x773C, - 0x773E, 0x7740, 0x7742, 0x7744, 0x7746, 0x7748, 0x774A, 0x774C, - 0x774E, 0x7750, 0x7752, 0x7754, 0x7756, 0x7758, 0x775A, 0x775C, - 0x775E, 0x7760, 0x7762, 0x7764, 0x7766, 0x7768, 0x776A, 0x776C, - 0x776E, 0x7770, 0x7772, 0x7774, 0x7776, 0x7778, 0x777A, 0x777C, - 0x777E, 0x7780, 0x7782, 0x7784, 0x7786, 0x7788, 0x778A, 0x778C, - 0x778E, 0x7790, 0x7792, 0x7794, 0x7796, 0x7798, 0x779A, 0x779C, - 0x779E, 0x77A0, 0x77A2, 0x77A4, 0x77A6, 0x77A8, 0x77AA, 0x77AC, - 0x77AE, 0x77B0, 0x77B2, 0x77B4, 0x77B6, 0x77B8, 0x77BA, 0x77BC, - 0x77BE, 0x77C0, 0x77C2, 0x77C4, 0x77C6, 0x77C8, 0x77CA, 0x77CC, - 0x77CE, 0x77D0, 0x77D2, 0x77D4, 0x77D6, 0x77D8, 0x77DA, 0x77DC, - 0x77DE, 0x77E0, 0x77E2, 0x77E4, 0x77E6, 0x77E8, 0x77EA, 0x77EC, - 0x77EE, 0x77F0, 0x77F2, 0x77F4, 0x77F6, 0x77F8, 0x77FA, 0x77FC, - 0x3BFF, 0x77FD, 0x77FB, 0x77F9, 0x77F7, 0x77F5, 0x77F3, 0x77F1, - 0x77EF, 0x77ED, 0x77EB, 0x77E9, 0x77E7, 0x77E5, 0x77E3, 0x77E1, - 0x77DF, 0x77DD, 0x77DB, 0x77D9, 0x77D7, 0x77D5, 0x77D3, 0x77D1, - 0x77CF, 0x77CD, 0x77CB, 0x77C9, 0x77C7, 0x77C5, 0x77C3, 0x77C1, - 0x77BF, 0x77BD, 0x77BB, 0x77B9, 0x77B7, 0x77B5, 0x77B3, 0x77B1, - 0x77AF, 0x77AD, 0x77AB, 0x77A9, 0x77A7, 0x77A5, 0x77A3, 0x77A1, - 0x779F, 0x779D, 0x779B, 0x7799, 0x7797, 0x7795, 0x7793, 0x7791, - 0x778F, 0x778D, 0x778B, 0x7789, 0x7787, 0x7785, 0x7783, 0x7781, - 0x777F, 0x777D, 0x777B, 0x7779, 0x7777, 0x7775, 0x7773, 0x7771, - 0x776F, 0x776D, 0x776B, 0x7769, 0x7767, 0x7765, 0x7763, 0x7761, - 0x775F, 0x775D, 0x775B, 0x7759, 0x7757, 0x7755, 0x7753, 0x7751, - 0x774F, 0x774D, 0x774B, 0x7749, 0x7747, 0x7745, 0x7743, 0x7741, - 0x773F, 0x773D, 0x773B, 0x7739, 0x7737, 0x7735, 0x7733, 0x7731, - 0x772F, 0x772D, 0x772B, 0x7729, 0x7727, 0x7725, 0x7723, 0x7721, - 0x771F, 0x771D, 0x771B, 0x7719, 0x7717, 0x7715, 0x7713, 0x7711, - 0x770F, 0x770D, 0x770B, 0x7709, 0x7707, 0x7705, 0x7703, 0x7701, - 0x76FF, 0x76FD, 0x76FB, 0x76F9, 0x76F7, 0x76F5, 0x76F3, 0x76F1, - 0x76EF, 0x76ED, 0x76EB, 0x76E9, 0x76E7, 0x76E5, 0x76E3, 0x76E1, - 0x76DF, 0x76DD, 0x76DB, 0x76D9, 0x76D7, 0x76D5, 0x76D3, 0x76D1, - 0x76CF, 0x76CD, 0x76CB, 0x76C9, 0x76C7, 0x76C5, 0x76C3, 0x76C1, - 0x76BF, 0x76BD, 0x76BB, 0x76B9, 0x76B7, 0x76B5, 0x76B3, 0x76B1, - 0x76AF, 0x76AD, 0x76AB, 0x76A9, 0x76A7, 0x76A5, 0x76A3, 0x76A1, - 0x769F, 0x769D, 0x769B, 0x7699, 0x7697, 0x7695, 0x7693, 0x7691, - 0x768F, 0x768D, 0x768B, 0x7689, 0x7687, 0x7685, 0x7683, 0x7681, - 0x767F, 0x767D, 0x767B, 0x7679, 0x7677, 0x7675, 0x7673, 0x7671, - 0x766F, 0x766D, 0x766B, 0x7669, 0x7667, 0x7665, 0x7663, 0x7661, - 0x765F, 0x765D, 0x765B, 0x7659, 0x7657, 0x7655, 0x7653, 0x7651, - 0x764F, 0x764D, 0x764B, 0x7649, 0x7647, 0x7645, 0x7643, 0x7641, - 0x763F, 0x763D, 0x763B, 0x7639, 0x7637, 0x7635, 0x7633, 0x7631, - 0x762F, 0x762D, 0x762B, 0x7629, 0x7627, 0x7625, 0x7623, 0x7621, - 0x761F, 0x761D, 0x761B, 0x7619, 0x7617, 0x7615, 0x7613, 0x7611, - 0x760F, 0x760D, 0x760B, 0x7609, 0x7607, 0x7605, 0x7603, 0x7601, - 0x17FF, 0x17FD, 0x17FB, 0x17F9, 0x17F7, 0x17F5, 0x17F3, 0x17F1, - 0x17EF, 0x17ED, 0x17EB, 0x17E9, 0x17E7, 0x17E5, 0x17E3, 0x17E1, - 0x17DF, 0x17DD, 0x17DB, 0x17D9, 0x17D7, 0x17D5, 0x17D3, 0x17D1, - 0x17CF, 0x17CD, 0x17CB, 0x17C9, 0x17C7, 0x17C5, 0x17C3, 0x17C1, - 0x17BF, 0x17BD, 0x17BB, 0x17B9, 0x17B7, 0x17B5, 0x17B3, 0x17B1, - 0x17AF, 0x17AD, 0x17AB, 0x17A9, 0x17A7, 0x17A5, 0x17A3, 0x17A1, - 0x179F, 0x179D, 0x179B, 0x1799, 0x1797, 0x1795, 0x1793, 0x1791, - 0x178F, 0x178D, 0x178B, 0x1789, 0x1787, 0x1785, 0x1783, 0x1781, - 0x177F, 0x177D, 0x177B, 0x1779, 0x1777, 0x1775, 0x1773, 0x1771, - 0x176F, 0x176D, 0x176B, 0x1769, 0x1767, 0x1765, 0x1763, 0x1761, - 0x175F, 0x175D, 0x175B, 0x1759, 0x1757, 0x1755, 0x1753, 0x1751, - 0x174F, 0x174D, 0x174B, 0x1749, 0x1747, 0x1745, 0x1743, 0x1741, - 0x173F, 0x173D, 0x173B, 0x1739, 0x1737, 0x1735, 0x1733, 0x1731, - 0x172F, 0x172D, 0x172B, 0x1729, 0x1727, 0x1725, 0x1723, 0x1721, - 0x171F, 0x171D, 0x171B, 0x1719, 0x1717, 0x1715, 0x1713, 0x1711, - 0x170F, 0x170D, 0x170B, 0x1709, 0x1707, 0x1705, 0x1703, 0x1701, - 0x16FF, 0x16FD, 0x16FB, 0x16F9, 0x16F7, 0x16F5, 0x16F3, 0x16F1, - 0x16EF, 0x16ED, 0x16EB, 0x16E9, 0x16E7, 0x16E5, 0x16E3, 0x16E1, - 0x16DF, 0x16DD, 0x16DB, 0x16D9, 0x16D7, 0x16D5, 0x16D3, 0x16D1, - 0x16CF, 0x16CD, 0x16CB, 0x16C9, 0x16C7, 0x16C5, 0x16C3, 0x16C1, - 0x16BF, 0x16BD, 0x16BB, 0x16B9, 0x16B7, 0x16B5, 0x16B3, 0x16B1, - 0x16AF, 0x16AD, 0x16AB, 0x16A9, 0x16A7, 0x16A5, 0x16A3, 0x16A1, - 0x169F, 0x169D, 0x169B, 0x1699, 0x1697, 0x1695, 0x1693, 0x1691, - 0x168F, 0x168D, 0x168B, 0x1689, 0x1687, 0x1685, 0x1683, 0x1681, - 0x167F, 0x167D, 0x167B, 0x1679, 0x1677, 0x1675, 0x1673, 0x1671, - 0x166F, 0x166D, 0x166B, 0x1669, 0x1667, 0x1665, 0x1663, 0x1661, - 0x165F, 0x165D, 0x165B, 0x1659, 0x1657, 0x1655, 0x1653, 0x1651, - 0x164F, 0x164D, 0x164B, 0x1649, 0x1647, 0x1645, 0x1643, 0x1641, - 0x163F, 0x163D, 0x163B, 0x1639, 0x1637, 0x1635, 0x1633, 0x1631, - 0x162F, 0x162D, 0x162B, 0x1629, 0x1627, 0x1625, 0x1623, 0x1621, - 0x161F, 0x161D, 0x161B, 0x1619, 0x1617, 0x1615, 0x1613, 0x1611, - 0x160F, 0x160D, 0x160B, 0x1609, 0x1607, 0x1605, 0x1603, 0x1601, - 0x18FF, 0x18FD, 0x18FB, 0x18F9, 0x18F7, 0x18F5, 0x18F3, 0x18F1, - 0x18EF, 0x18ED, 0x18EB, 0x18E9, 0x18E7, 0x18E5, 0x18E3, 0x18E1, - 0x18DF, 0x18DD, 0x18DB, 0x18D9, 0x18D7, 0x18D5, 0x18D3, 0x18D1, - 0x18CF, 0x18CD, 0x18CB, 0x18C9, 0x18C7, 0x18C5, 0x18C3, 0x18C1, - 0x18BF, 0x18BD, 0x18BB, 0x18B9, 0x18B7, 0x18B5, 0x18B3, 0x18B1, - 0x18AF, 0x18AD, 0x18AB, 0x18A9, 0x18A7, 0x18A5, 0x18A3, 0x18A1, - 0x189F, 0x189D, 0x189B, 0x1899, 0x1897, 0x1895, 0x1893, 0x1891, - 0x188F, 0x188D, 0x188B, 0x1889, 0x1887, 0x1885, 0x1883, 0x1881, - 0x187F, 0x187D, 0x187B, 0x1879, 0x1877, 0x1875, 0x1873, 0x1871, - 0x186F, 0x186D, 0x186B, 0x1869, 0x1867, 0x1865, 0x1863, 0x1861, - 0x185F, 0x185D, 0x185B, 0x1859, 0x1857, 0x1855, 0x1853, 0x1851, - 0x184F, 0x184D, 0x184B, 0x1849, 0x1847, 0x1845, 0x1843, 0x1841, - 0x183F, 0x183D, 0x183B, 0x1839, 0x1837, 0x1835, 0x1833, 0x1831, - 0x182F, 0x182D, 0x182B, 0x1829, 0x1827, 0x1825, 0x1823, 0x1821, - 0x181F, 0x181D, 0x181B, 0x1819, 0x1817, 0x1815, 0x1813, 0x1811, - 0x180F, 0x180D, 0x180B, 0x1809, 0x1807, 0x1805, 0x1803, 0x1801, - 0x0AFF, 0x0AFD, 0x0AFB, 0x0AF9, 0x0AF7, 0x0AF5, 0x0AF3, 0x0AF1, - 0x0AEF, 0x0AED, 0x0AEB, 0x0AE9, 0x0AE7, 0x0AE5, 0x0AE3, 0x0AE1, - 0x0ADF, 0x0ADD, 0x0ADB, 0x0AD9, 0x0AD7, 0x0AD5, 0x0AD3, 0x0AD1, - 0x0ACF, 0x0ACD, 0x0ACB, 0x0AC9, 0x0AC7, 0x0AC5, 0x0AC3, 0x0AC1, - 0x0ABF, 0x0ABD, 0x0ABB, 0x0AB9, 0x0AB7, 0x0AB5, 0x0AB3, 0x0AB1, - 0x0AAF, 0x0AAD, 0x0AAB, 0x0AA9, 0x0AA7, 0x0AA5, 0x0AA3, 0x0AA1, - 0x0A9F, 0x0A9D, 0x0A9B, 0x0A99, 0x0A97, 0x0A95, 0x0A93, 0x0A91, - 0x0A8F, 0x0A8D, 0x0A8B, 0x0A89, 0x0A87, 0x0A85, 0x0A83, 0x0A81, - 0x0A7F, 0x0A7D, 0x0A7B, 0x0A79, 0x0A77, 0x0A75, 0x0A73, 0x0A71, - 0x0A6F, 0x0A6D, 0x0A6B, 0x0A69, 0x0A67, 0x0A65, 0x0A63, 0x0A61, - 0x0A5F, 0x0A5D, 0x0A5B, 0x0A59, 0x0A57, 0x0A55, 0x0A53, 0x0A51, - 0x0A4F, 0x0A4D, 0x0A4B, 0x0A49, 0x0A47, 0x0A45, 0x0A43, 0x0A41, - 0x0A3F, 0x0A3D, 0x0A3B, 0x0A39, 0x0A37, 0x0A35, 0x0A33, 0x0A31, - 0x0A2F, 0x0A2D, 0x0A2B, 0x0A29, 0x0A27, 0x0A25, 0x0A23, 0x0A21, - 0x0A1F, 0x0A1D, 0x0A1B, 0x0A19, 0x0A17, 0x0A15, 0x0A13, 0x0A11, - 0x0A0F, 0x0A0D, 0x0A0B, 0x0A09, 0x0A07, 0x0A05, 0x0A03, 0x0A01, - 0x04FF, 0x04FD, 0x04FB, 0x04F9, 0x04F7, 0x04F5, 0x04F3, 0x04F1, - 0x04EF, 0x04ED, 0x04EB, 0x04E9, 0x04E7, 0x04E5, 0x04E3, 0x04E1, - 0x04DF, 0x04DD, 0x04DB, 0x04D9, 0x04D7, 0x04D5, 0x04D3, 0x04D1, - 0x04CF, 0x04CD, 0x04CB, 0x04C9, 0x04C7, 0x04C5, 0x04C3, 0x04C1, - 0x04BF, 0x04BD, 0x04BB, 0x04B9, 0x04B7, 0x04B5, 0x04B3, 0x04B1, - 0x04AF, 0x04AD, 0x04AB, 0x04A9, 0x04A7, 0x04A5, 0x04A3, 0x04A1, - 0x049F, 0x049D, 0x049B, 0x0499, 0x0497, 0x0495, 0x0493, 0x0491, - 0x048F, 0x048D, 0x048B, 0x0489, 0x0487, 0x0485, 0x0483, 0x0481, - 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, - 0x00EF, 0x00ED, 0x00EB, 0x00E9, 0x00E7, 0x00E5, 0x00E3, 0x00E1, - 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, - 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, - 0x00BF, 0x00BD, 0x00BB, 0x00B9, 0x00B7, 0x00B5, 0x00B3, 0x00B1, - 0x00AF, 0x00AD, 0x00AB, 0x00A9, 0x00A7, 0x00A5, 0x00A3, 0x00A1, - 0x009F, 0x009D, 0x009B, 0x0099, 0x0097, 0x0095, 0x0093, 0x0091, - 0x008F, 0x008D, 0x008B, 0x0089, 0x0087, 0x0085, 0x0083, 0x0081, - 0x023F, 0x023D, 0x023B, 0x0239, 0x0237, 0x0235, 0x0233, 0x0231, - 0x022F, 0x022D, 0x022B, 0x0229, 0x0227, 0x0225, 0x0223, 0x0221, - 0x021F, 0x021D, 0x021B, 0x0219, 0x0217, 0x0215, 0x0213, 0x0211, - 0x020F, 0x020D, 0x020B, 0x0209, 0x0207, 0x0205, 0x0203, 0x0201, - 0x003F, 0x003D, 0x003B, 0x0039, 0x0037, 0x0035, 0x0033, 0x0031, - 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0021, - 0x001F, 0x001D, 0x001B, 0x0019, 0x0017, 0x0015, 0x0013, 0x0011, - 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, - 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, - 0x00EF, 0x00ED, 0x00EB, 0x00E9, 0x00E7, 0x00E5, 0x00E3, 0x00E1, - 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, - 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, - 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, - 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, - 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, - 0x0075, 0x0073, 0x0071, 0x006F, 0x006D, 0x006B, 0x0069, 0x0067, -}; - -static const uint8_t dc11_vlc_lens[2048] = { - 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 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, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 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, 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, 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, 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, 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, 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, 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, - 14, 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, 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, - 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, - 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, - 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, - 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, - 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, - 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, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 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, - 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, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, -}; - -#define RPT_2(a, b, c) { a, b, c }, { a, b, c } -#define RPT_4(a, b, c) RPT_2( a, b, c), RPT_2( a, b, c) -#define RPT_8(a, b, c) RPT_4( a, b, c), RPT_4( a, b, c) -#define RPT_16(a, b, c) RPT_8( a, b, c), RPT_8( a, b, c) -#define RPT_32(a, b, c) RPT_16( a, b, c), RPT_16( a, b, c) -#define RPT_64(a, b, c) RPT_32( a, b, c), RPT_32( a, b, c) -#define RPT_128(a, b, c) RPT_64( a, b, c), RPT_64( a, b, c) -#define RPT_256(a, b, c) RPT_128(a, b, c), RPT_128(a, b, c) -#define RPT_512(a, b, c) RPT_256(a, b, c), RPT_256(a, b, c) -#define RPT_1024(a, b, c) RPT_512(a, b, c), RPT_512(a, b, c) - -static const HQXLUT ac0_lut[] = { - RPT_64 ( 1, 0, 4 ), RPT_64 ( -1, 0, 4 ), - RPT_64 ( 2, 0, 4 ), RPT_64 ( -2, 0, 4 ), - RPT_32 ( 3, 0, 5 ), RPT_32 ( -3, 0, 5 ), - RPT_32 ( 4, 0, 5 ), RPT_32 ( -4, 0, 5 ), - RPT_32 ( 1, 1, 5 ), RPT_32 ( -1, 1, 5 ), - RPT_16 ( 5, 0, 6 ), RPT_16 ( -5, 0, 6 ), - RPT_16 ( 6, 0, 6 ), RPT_16 ( -6, 0, 6 ), - RPT_16 ( 7, 0, 6 ), RPT_16 ( -7, 0, 6 ), - RPT_16 ( 8, 0, 6 ), RPT_16 ( -8, 0, 6 ), - { 1024, 0, -1 }, { 1056, 0, -1 }, { 1088, 0, -1 }, { 1120, 0, -1 }, - { 1152, 0, -1 }, { 1184, 0, -1 }, { 1216, 0, -1 }, { 1248, 0, -1 }, - { 1280, 0, -1 }, { 1312, 0, -1 }, { 1344, 0, -1 }, { 1376, 0, -1 }, - { 1408, 0, -1 }, { 1440, 0, -1 }, { 1472, 0, -1 }, { 1504, 0, -1 }, - { 1536, 0, -1 }, { 1568, 0, -1 }, { 1600, 0, -1 }, { 1632, 0, -1 }, - { 1664, 0, -1 }, { 1696, 0, -1 }, { 1728, 0, -1 }, { 1760, 0, -1 }, - { 1792, 0, -1 }, { 1824, 0, -1 }, { 1856, 0, -1 }, { 1888, 0, -1 }, - { 1920, 0, -1 }, { 1952, 0, -1 }, { 1984, 0, -1 }, { 2016, 0, -1 }, - RPT_32 ( 0, 64, 5 ), RPT_8 ( 9, 0, 7 ), - RPT_8 ( -9, 0, 7 ), RPT_8 ( 10, 0, 7 ), - RPT_8 ( -10, 0, 7 ), RPT_8 ( 11, 0, 7 ), - RPT_8 ( -11, 0, 7 ), RPT_8 ( 12, 0, 7 ), - RPT_8 ( -12, 0, 7 ), RPT_8 ( 13, 0, 7 ), - RPT_8 ( -13, 0, 7 ), RPT_8 ( 14, 0, 7 ), - RPT_8 ( -14, 0, 7 ), RPT_8 ( 2, 1, 7 ), - RPT_8 ( -2, 1, 7 ), RPT_8 ( 1, 2, 7 ), - RPT_8 ( -1, 2, 7 ), RPT_4 ( 15, 0, 8 ), - RPT_4 ( -15, 0, 8 ), RPT_4 ( 16, 0, 8 ), - RPT_4 ( -16, 0, 8 ), RPT_4 ( 17, 0, 8 ), - RPT_4 ( -17, 0, 8 ), RPT_4 ( 18, 0, 8 ), - RPT_4 ( -18, 0, 8 ), RPT_4 ( 19, 0, 8 ), - RPT_4 ( -19, 0, 8 ), RPT_4 ( 20, 0, 8 ), - RPT_4 ( -20, 0, 8 ), RPT_4 ( 21, 0, 8 ), - RPT_4 ( -21, 0, 8 ), RPT_4 ( 3, 1, 8 ), - RPT_4 ( -3, 1, 8 ), RPT_4 ( 4, 1, 8 ), - RPT_4 ( -4, 1, 8 ), RPT_4 ( 1, 3, 8 ), - RPT_4 ( -1, 3, 8 ), RPT_4 ( 1, 4, 8 ), - RPT_4 ( -1, 4, 8 ), RPT_4 ( 0, 0, 8 ), - RPT_2 ( 22, 0, 9 ), RPT_2 ( -22, 0, 9 ), - RPT_2 ( 23, 0, 9 ), RPT_2 ( -23, 0, 9 ), - RPT_2 ( 24, 0, 9 ), RPT_2 ( -24, 0, 9 ), - RPT_2 ( 25, 0, 9 ), RPT_2 ( -25, 0, 9 ), - RPT_2 ( 26, 0, 9 ), RPT_2 ( -26, 0, 9 ), - RPT_2 ( 27, 0, 9 ), RPT_2 ( -27, 0, 9 ), - RPT_2 ( 28, 0, 9 ), RPT_2 ( -28, 0, 9 ), - RPT_2 ( 29, 0, 9 ), RPT_2 ( -29, 0, 9 ), - RPT_2 ( 30, 0, 9 ), RPT_2 ( -30, 0, 9 ), - RPT_2 ( 31, 0, 9 ), RPT_2 ( -31, 0, 9 ), - RPT_2 ( 32, 0, 9 ), RPT_2 ( -32, 0, 9 ), - RPT_2 ( 33, 0, 9 ), RPT_2 ( -33, 0, 9 ), - RPT_2 ( 5, 1, 9 ), RPT_2 ( -5, 1, 9 ), - RPT_2 ( 6, 1, 9 ), RPT_2 ( -6, 1, 9 ), - RPT_2 ( 2, 2, 9 ), RPT_2 ( -2, 2, 9 ), - RPT_2 ( 1, 5, 9 ), RPT_2 ( -1, 5, 9 ), - RPT_2 ( 1, 6, 9 ), RPT_2 ( -1, 6, 9 ), - { 34, 0, 10 }, { -34, 0, 10 }, { 35, 0, 10 }, { -35, 0, 10 }, - { 36, 0, 10 }, { -36, 0, 10 }, { 37, 0, 10 }, { -37, 0, 10 }, - { 38, 0, 10 }, { -38, 0, 10 }, { 39, 0, 10 }, { -39, 0, 10 }, - { 40, 0, 10 }, { -40, 0, 10 }, { 41, 0, 10 }, { -41, 0, 10 }, - { 42, 0, 10 }, { -42, 0, 10 }, { 43, 0, 10 }, { -43, 0, 10 }, - { 44, 0, 10 }, { -44, 0, 10 }, { 45, 0, 10 }, { -45, 0, 10 }, - { 46, 0, 10 }, { -46, 0, 10 }, { 47, 0, 10 }, { -47, 0, 10 }, - { 48, 0, 10 }, { -48, 0, 10 }, { 49, 0, 10 }, { -49, 0, 10 }, - { 50, 0, 10 }, { -50, 0, 10 }, RPT_2 ( 0, 1, 9 ), - { 7, 1, 10 }, { -7, 1, 10 }, { 8, 1, 10 }, { -8, 1, 10 }, - { 9, 1, 10 }, { -9, 1, 10 }, { 10, 1, 10 }, { -10, 1, 10 }, - RPT_2 ( 0, 2, 9 ), { 3, 2, 10 }, { -3, 2, 10 }, - RPT_2 ( 0, 3, 9 ), { 2, 3, 10 }, { -2, 3, 10 }, - { 1, 7, 10 }, { -1, 7, 10 }, { 1, 8, 10 }, { -1, 8, 10 }, - { 2048, 0, -1 }, { 2080, 0, -1 }, { 2112, 0, -1 }, { 2144, 0, -1 }, - { 2176, 0, -1 }, { 2208, 0, -1 }, { 2240, 0, -1 }, { 2272, 0, -1 }, - { 2304, 0, -1 }, { 2336, 0, -1 }, { 2368, 0, -1 }, { 2400, 0, -1 }, - { 2432, 0, -1 }, { 2464, 0, -1 }, { 2496, 0, -1 }, { 2528, 0, -1 }, - { 2560, 0, -1 }, { 2592, 0, -1 }, { 2624, 0, -1 }, { 2656, 0, -1 }, - { 2688, 0, -1 }, { 2720, 0, -1 }, { 2752, 0, -1 }, { 0, 4, 10 }, - { 2784, 0, -1 }, { 0, 5, 10 }, { 0, 6, 10 }, { 2816, 0, -1 }, - { 2848, 0, -1 }, { 2880, 0, -1 }, { 2912, 0, -1 }, { 2944, 0, -1 }, - { 2976, 0, -1 }, { 3008, 0, -1 }, { 3040, 0, -1 }, { 3072, 0, -1 }, - { 3104, 0, -1 }, { 3136, 0, -1 }, { 3168, 0, -1 }, { 3200, 0, -1 }, - RPT_4 ( 0, 0, 13 ), RPT_2 ( 1, 0, 14 ), - RPT_2 ( -1, 0, 14 ), RPT_2 ( 2, 0, 14 ), - RPT_2 ( -2, 0, 14 ), RPT_2 ( 3, 0, 14 ), - RPT_2 ( -3, 0, 14 ), RPT_2 ( 4, 0, 14 ), - RPT_2 ( -4, 0, 14 ), RPT_2 ( 5, 0, 14 ), - RPT_2 ( -5, 0, 14 ), RPT_2 ( 6, 0, 14 ), - RPT_2 ( -6, 0, 14 ), RPT_2 ( 7, 0, 14 ), - RPT_2 ( -7, 0, 14 ), RPT_2 ( 8, 0, 14 ), - RPT_2 ( -8, 0, 14 ), RPT_2 ( 9, 0, 14 ), - RPT_2 ( -9, 0, 14 ), RPT_2 ( 10, 0, 14 ), - RPT_2 ( -10, 0, 14 ), RPT_2 ( 11, 0, 14 ), - RPT_2 ( -11, 0, 14 ), RPT_2 ( 12, 0, 14 ), - RPT_2 ( -12, 0, 14 ), RPT_2 ( 13, 0, 14 ), - RPT_2 ( -13, 0, 14 ), RPT_2 ( 14, 0, 14 ), - RPT_2 ( -14, 0, 14 ), RPT_2 ( 15, 0, 14 ), - RPT_2 ( -15, 0, 14 ), RPT_2 ( 16, 0, 14 ), - RPT_2 ( -16, 0, 14 ), RPT_2 ( 17, 0, 14 ), - RPT_2 ( -17, 0, 14 ), RPT_2 ( 18, 0, 14 ), - RPT_2 ( -18, 0, 14 ), RPT_2 ( 19, 0, 14 ), - RPT_2 ( -19, 0, 14 ), RPT_2 ( 20, 0, 14 ), - RPT_2 ( -20, 0, 14 ), RPT_2 ( 21, 0, 14 ), - RPT_2 ( -21, 0, 14 ), RPT_2 ( 22, 0, 14 ), - RPT_2 ( -22, 0, 14 ), RPT_2 ( 23, 0, 14 ), - RPT_2 ( -23, 0, 14 ), RPT_2 ( 24, 0, 14 ), - RPT_2 ( -24, 0, 14 ), RPT_2 ( 25, 0, 14 ), - RPT_2 ( -25, 0, 14 ), RPT_2 ( 26, 0, 14 ), - RPT_2 ( -26, 0, 14 ), RPT_2 ( 27, 0, 14 ), - RPT_2 ( -27, 0, 14 ), RPT_2 ( 28, 0, 14 ), - RPT_2 ( -28, 0, 14 ), RPT_2 ( 29, 0, 14 ), - RPT_2 ( -29, 0, 14 ), RPT_2 ( 30, 0, 14 ), - RPT_2 ( -30, 0, 14 ), RPT_2 ( 31, 0, 14 ), - RPT_2 ( -31, 0, 14 ), RPT_2 ( 32, 0, 14 ), - RPT_2 ( -32, 0, 14 ), RPT_2 ( 33, 0, 14 ), - RPT_2 ( -33, 0, 14 ), RPT_2 ( 34, 0, 14 ), - RPT_2 ( -34, 0, 14 ), RPT_2 ( 35, 0, 14 ), - RPT_2 ( -35, 0, 14 ), RPT_2 ( 36, 0, 14 ), - RPT_2 ( -36, 0, 14 ), RPT_2 ( 37, 0, 14 ), - RPT_2 ( -37, 0, 14 ), RPT_2 ( 38, 0, 14 ), - RPT_2 ( -38, 0, 14 ), RPT_2 ( 39, 0, 14 ), - RPT_2 ( -39, 0, 14 ), RPT_2 ( 40, 0, 14 ), - RPT_2 ( -40, 0, 14 ), RPT_2 ( 41, 0, 14 ), - RPT_2 ( -41, 0, 14 ), RPT_2 ( 42, 0, 14 ), - RPT_2 ( -42, 0, 14 ), RPT_2 ( 43, 0, 14 ), - RPT_2 ( -43, 0, 14 ), RPT_2 ( 44, 0, 14 ), - RPT_2 ( -44, 0, 14 ), RPT_2 ( 45, 0, 14 ), - RPT_2 ( -45, 0, 14 ), RPT_2 ( 46, 0, 14 ), - RPT_2 ( -46, 0, 14 ), RPT_2 ( 47, 0, 14 ), - RPT_2 ( -47, 0, 14 ), RPT_2 ( 48, 0, 14 ), - RPT_2 ( -48, 0, 14 ), RPT_2 ( 49, 0, 14 ), - RPT_2 ( -49, 0, 14 ), RPT_2 ( 50, 0, 14 ), - RPT_2 ( -50, 0, 14 ), RPT_2 ( 51, 0, 14 ), - RPT_2 ( -51, 0, 14 ), RPT_2 ( 52, 0, 14 ), - RPT_2 ( -52, 0, 14 ), RPT_2 ( 53, 0, 14 ), - RPT_2 ( -53, 0, 14 ), RPT_2 ( 54, 0, 14 ), - RPT_2 ( -54, 0, 14 ), RPT_2 ( 55, 0, 14 ), - RPT_2 ( -55, 0, 14 ), RPT_2 ( 56, 0, 14 ), - RPT_2 ( -56, 0, 14 ), RPT_2 ( 57, 0, 14 ), - RPT_2 ( -57, 0, 14 ), RPT_2 ( 58, 0, 14 ), - RPT_2 ( -58, 0, 14 ), RPT_2 ( 59, 0, 14 ), - RPT_2 ( -59, 0, 14 ), RPT_2 ( 60, 0, 14 ), - RPT_2 ( -60, 0, 14 ), RPT_2 ( 61, 0, 14 ), - RPT_2 ( -61, 0, 14 ), RPT_2 ( 62, 0, 14 ), - RPT_2 ( -62, 0, 14 ), RPT_2 ( 63, 0, 14 ), - RPT_2 ( -63, 0, 14 ), RPT_2 ( 64, 0, 14 ), - RPT_2 ( -64, 0, 14 ), RPT_2 ( 65, 0, 14 ), - RPT_2 ( -65, 0, 14 ), RPT_2 ( 66, 0, 14 ), - RPT_2 ( -66, 0, 14 ), RPT_2 ( 67, 0, 14 ), - RPT_2 ( -67, 0, 14 ), RPT_2 ( 68, 0, 14 ), - RPT_2 ( -68, 0, 14 ), RPT_2 ( 69, 0, 14 ), - RPT_2 ( -69, 0, 14 ), RPT_2 ( 70, 0, 14 ), - RPT_2 ( -70, 0, 14 ), RPT_2 ( 71, 0, 14 ), - RPT_2 ( -71, 0, 14 ), RPT_2 ( 72, 0, 14 ), - RPT_2 ( -72, 0, 14 ), RPT_2 ( 73, 0, 14 ), - RPT_2 ( -73, 0, 14 ), RPT_2 ( 74, 0, 14 ), - RPT_2 ( -74, 0, 14 ), RPT_2 ( 75, 0, 14 ), - RPT_2 ( -75, 0, 14 ), RPT_2 ( 76, 0, 14 ), - RPT_2 ( -76, 0, 14 ), RPT_2 ( 77, 0, 14 ), - RPT_2 ( -77, 0, 14 ), RPT_2 ( 78, 0, 14 ), - RPT_2 ( -78, 0, 14 ), RPT_2 ( 79, 0, 14 ), - RPT_2 ( -79, 0, 14 ), RPT_2 ( 80, 0, 14 ), - RPT_2 ( -80, 0, 14 ), RPT_2 ( 81, 0, 14 ), - RPT_2 ( -81, 0, 14 ), RPT_2 ( 82, 0, 14 ), - RPT_2 ( -82, 0, 14 ), RPT_2 ( 83, 0, 14 ), - RPT_2 ( -83, 0, 14 ), RPT_2 ( 84, 0, 14 ), - RPT_2 ( -84, 0, 14 ), RPT_2 ( 85, 0, 14 ), - RPT_2 ( -85, 0, 14 ), RPT_2 ( 86, 0, 14 ), - RPT_2 ( -86, 0, 14 ), RPT_2 ( 87, 0, 14 ), - RPT_2 ( -87, 0, 14 ), RPT_2 ( 88, 0, 14 ), - RPT_2 ( -88, 0, 14 ), RPT_2 ( 89, 0, 14 ), - RPT_2 ( -89, 0, 14 ), RPT_2 ( 90, 0, 14 ), - RPT_2 ( -90, 0, 14 ), RPT_2 ( 91, 0, 14 ), - RPT_2 ( -91, 0, 14 ), RPT_2 ( 92, 0, 14 ), - RPT_2 ( -92, 0, 14 ), RPT_2 ( 93, 0, 14 ), - RPT_2 ( -93, 0, 14 ), RPT_2 ( 94, 0, 14 ), - RPT_2 ( -94, 0, 14 ), RPT_2 ( 95, 0, 14 ), - RPT_2 ( -95, 0, 14 ), RPT_2 ( 96, 0, 14 ), - RPT_2 ( -96, 0, 14 ), RPT_2 ( 97, 0, 14 ), - RPT_2 ( -97, 0, 14 ), RPT_2 ( 98, 0, 14 ), - RPT_2 ( -98, 0, 14 ), RPT_2 ( 99, 0, 14 ), - RPT_2 ( -99, 0, 14 ), RPT_2 ( 100, 0, 14 ), - RPT_2 (-100, 0, 14 ), RPT_2 ( 101, 0, 14 ), - RPT_2 (-101, 0, 14 ), RPT_2 ( 102, 0, 14 ), - RPT_2 (-102, 0, 14 ), RPT_2 ( 103, 0, 14 ), - RPT_2 (-103, 0, 14 ), RPT_2 ( 104, 0, 14 ), - RPT_2 (-104, 0, 14 ), RPT_2 ( 105, 0, 14 ), - RPT_2 (-105, 0, 14 ), RPT_2 ( 106, 0, 14 ), - RPT_2 (-106, 0, 14 ), RPT_2 ( 107, 0, 14 ), - RPT_2 (-107, 0, 14 ), RPT_2 ( 108, 0, 14 ), - RPT_2 (-108, 0, 14 ), RPT_2 ( 109, 0, 14 ), - RPT_2 (-109, 0, 14 ), RPT_2 ( 110, 0, 14 ), - RPT_2 (-110, 0, 14 ), RPT_2 ( 111, 0, 14 ), - RPT_2 (-111, 0, 14 ), RPT_2 ( 112, 0, 14 ), - RPT_2 (-112, 0, 14 ), RPT_2 ( 113, 0, 14 ), - RPT_2 (-113, 0, 14 ), RPT_2 ( 114, 0, 14 ), - RPT_2 (-114, 0, 14 ), RPT_2 ( 115, 0, 14 ), - RPT_2 (-115, 0, 14 ), RPT_2 ( 116, 0, 14 ), - RPT_2 (-116, 0, 14 ), RPT_2 ( 117, 0, 14 ), - RPT_2 (-117, 0, 14 ), RPT_2 ( 118, 0, 14 ), - RPT_2 (-118, 0, 14 ), RPT_2 ( 119, 0, 14 ), - RPT_2 (-119, 0, 14 ), RPT_2 ( 120, 0, 14 ), - RPT_2 (-120, 0, 14 ), RPT_2 ( 121, 0, 14 ), - RPT_2 (-121, 0, 14 ), RPT_2 ( 122, 0, 14 ), - RPT_2 (-122, 0, 14 ), RPT_2 ( 123, 0, 14 ), - RPT_2 (-123, 0, 14 ), RPT_2 ( 124, 0, 14 ), - RPT_2 (-124, 0, 14 ), RPT_2 ( 125, 0, 14 ), - RPT_2 (-125, 0, 14 ), RPT_2 ( 126, 0, 14 ), - RPT_2 (-126, 0, 14 ), RPT_2 ( 127, 0, 14 ), - RPT_2 (-127, 0, 14 ), RPT_2 ( 128, 0, 14 ), - RPT_2 (-128, 0, 14 ), RPT_2 ( 129, 0, 14 ), - RPT_2 (-129, 0, 14 ), RPT_2 ( 130, 0, 14 ), - RPT_2 (-130, 0, 14 ), RPT_2 ( 131, 0, 14 ), - RPT_2 (-131, 0, 14 ), RPT_2 ( 132, 0, 14 ), - RPT_2 (-132, 0, 14 ), RPT_2 ( 133, 0, 14 ), - RPT_2 (-133, 0, 14 ), RPT_2 ( 134, 0, 14 ), - RPT_2 (-134, 0, 14 ), RPT_2 ( 135, 0, 14 ), - RPT_2 (-135, 0, 14 ), RPT_2 ( 136, 0, 14 ), - RPT_2 (-136, 0, 14 ), RPT_2 ( 137, 0, 14 ), - RPT_2 (-137, 0, 14 ), RPT_2 ( 138, 0, 14 ), - RPT_2 (-138, 0, 14 ), RPT_2 ( 139, 0, 14 ), - RPT_2 (-139, 0, 14 ), RPT_2 ( 140, 0, 14 ), - RPT_2 (-140, 0, 14 ), RPT_2 ( 141, 0, 14 ), - RPT_2 (-141, 0, 14 ), RPT_2 ( 142, 0, 14 ), - RPT_2 (-142, 0, 14 ), RPT_2 ( 143, 0, 14 ), - RPT_2 (-143, 0, 14 ), RPT_2 ( 144, 0, 14 ), - RPT_2 (-144, 0, 14 ), RPT_2 ( 145, 0, 14 ), - RPT_2 (-145, 0, 14 ), RPT_2 ( 146, 0, 14 ), - RPT_2 (-146, 0, 14 ), RPT_2 ( 147, 0, 14 ), - RPT_2 (-147, 0, 14 ), RPT_2 ( 148, 0, 14 ), - RPT_2 (-148, 0, 14 ), RPT_2 ( 149, 0, 14 ), - RPT_2 (-149, 0, 14 ), RPT_2 ( 150, 0, 14 ), - RPT_2 (-150, 0, 14 ), RPT_2 ( 151, 0, 14 ), - RPT_2 (-151, 0, 14 ), RPT_2 ( 152, 0, 14 ), - RPT_2 (-152, 0, 14 ), RPT_2 ( 153, 0, 14 ), - RPT_2 (-153, 0, 14 ), RPT_2 ( 154, 0, 14 ), - RPT_2 (-154, 0, 14 ), RPT_2 ( 155, 0, 14 ), - RPT_2 (-155, 0, 14 ), RPT_2 ( 156, 0, 14 ), - RPT_2 (-156, 0, 14 ), RPT_2 ( 157, 0, 14 ), - RPT_2 (-157, 0, 14 ), RPT_2 ( 158, 0, 14 ), - RPT_2 (-158, 0, 14 ), RPT_2 ( 159, 0, 14 ), - RPT_2 (-159, 0, 14 ), RPT_2 ( 160, 0, 14 ), - RPT_2 (-160, 0, 14 ), RPT_2 ( 161, 0, 14 ), - RPT_2 (-161, 0, 14 ), RPT_2 ( 162, 0, 14 ), - RPT_2 (-162, 0, 14 ), RPT_2 ( 163, 0, 14 ), - RPT_2 (-163, 0, 14 ), RPT_2 ( 164, 0, 14 ), - RPT_2 (-164, 0, 14 ), RPT_2 ( 165, 0, 14 ), - RPT_2 (-165, 0, 14 ), RPT_2 ( 166, 0, 14 ), - RPT_2 (-166, 0, 14 ), RPT_2 ( 167, 0, 14 ), - RPT_2 (-167, 0, 14 ), RPT_2 ( 168, 0, 14 ), - RPT_2 (-168, 0, 14 ), RPT_2 ( 169, 0, 14 ), - RPT_2 (-169, 0, 14 ), RPT_2 ( 170, 0, 14 ), - RPT_2 (-170, 0, 14 ), RPT_2 ( 171, 0, 14 ), - RPT_2 (-171, 0, 14 ), RPT_2 ( 172, 0, 14 ), - RPT_2 (-172, 0, 14 ), RPT_2 ( 173, 0, 14 ), - RPT_2 (-173, 0, 14 ), RPT_2 ( 174, 0, 14 ), - RPT_2 (-174, 0, 14 ), RPT_2 ( 175, 0, 14 ), - RPT_2 (-175, 0, 14 ), RPT_2 ( 176, 0, 14 ), - RPT_2 (-176, 0, 14 ), RPT_2 ( 177, 0, 14 ), - RPT_2 (-177, 0, 14 ), RPT_2 ( 178, 0, 14 ), - RPT_2 (-178, 0, 14 ), RPT_2 ( 179, 0, 14 ), - RPT_2 (-179, 0, 14 ), RPT_2 ( 180, 0, 14 ), - RPT_2 (-180, 0, 14 ), RPT_2 ( 181, 0, 14 ), - RPT_2 (-181, 0, 14 ), RPT_2 ( 182, 0, 14 ), - RPT_2 (-182, 0, 14 ), RPT_2 ( 183, 0, 14 ), - RPT_2 (-183, 0, 14 ), RPT_2 ( 184, 0, 14 ), - RPT_2 (-184, 0, 14 ), RPT_2 ( 185, 0, 14 ), - RPT_2 (-185, 0, 14 ), RPT_2 ( 186, 0, 14 ), - RPT_2 (-186, 0, 14 ), RPT_2 ( 187, 0, 14 ), - RPT_2 (-187, 0, 14 ), RPT_2 ( 188, 0, 14 ), - RPT_2 (-188, 0, 14 ), RPT_2 ( 189, 0, 14 ), - RPT_2 (-189, 0, 14 ), RPT_2 ( 190, 0, 14 ), - RPT_2 (-190, 0, 14 ), RPT_2 ( 191, 0, 14 ), - RPT_2 (-191, 0, 14 ), RPT_2 ( 192, 0, 14 ), - RPT_2 (-192, 0, 14 ), RPT_2 ( 193, 0, 14 ), - RPT_2 (-193, 0, 14 ), RPT_2 ( 194, 0, 14 ), - RPT_2 (-194, 0, 14 ), RPT_2 ( 195, 0, 14 ), - RPT_2 (-195, 0, 14 ), RPT_2 ( 196, 0, 14 ), - RPT_2 (-196, 0, 14 ), RPT_2 ( 197, 0, 14 ), - RPT_2 (-197, 0, 14 ), RPT_2 ( 198, 0, 14 ), - RPT_2 (-198, 0, 14 ), RPT_2 ( 199, 0, 14 ), - RPT_2 (-199, 0, 14 ), RPT_2 ( 200, 0, 14 ), - RPT_2 (-200, 0, 14 ), RPT_2 ( 201, 0, 14 ), - RPT_2 (-201, 0, 14 ), RPT_2 ( 202, 0, 14 ), - RPT_2 (-202, 0, 14 ), RPT_2 ( 203, 0, 14 ), - RPT_2 (-203, 0, 14 ), RPT_2 ( 204, 0, 14 ), - RPT_2 (-204, 0, 14 ), RPT_2 ( 205, 0, 14 ), - RPT_2 (-205, 0, 14 ), RPT_2 ( 206, 0, 14 ), - RPT_2 (-206, 0, 14 ), RPT_2 ( 207, 0, 14 ), - RPT_2 (-207, 0, 14 ), RPT_2 ( 208, 0, 14 ), - RPT_2 (-208, 0, 14 ), RPT_2 ( 209, 0, 14 ), - RPT_2 (-209, 0, 14 ), RPT_2 ( 210, 0, 14 ), - RPT_2 (-210, 0, 14 ), RPT_2 ( 211, 0, 14 ), - RPT_2 (-211, 0, 14 ), RPT_2 ( 212, 0, 14 ), - RPT_2 (-212, 0, 14 ), RPT_2 ( 213, 0, 14 ), - RPT_2 (-213, 0, 14 ), RPT_2 ( 214, 0, 14 ), - RPT_2 (-214, 0, 14 ), RPT_2 ( 215, 0, 14 ), - RPT_2 (-215, 0, 14 ), RPT_2 ( 216, 0, 14 ), - RPT_2 (-216, 0, 14 ), RPT_2 ( 217, 0, 14 ), - RPT_2 (-217, 0, 14 ), RPT_2 ( 218, 0, 14 ), - RPT_2 (-218, 0, 14 ), RPT_2 ( 219, 0, 14 ), - RPT_2 (-219, 0, 14 ), RPT_2 ( 220, 0, 14 ), - RPT_2 (-220, 0, 14 ), RPT_2 ( 221, 0, 14 ), - RPT_2 (-221, 0, 14 ), RPT_2 ( 222, 0, 14 ), - RPT_2 (-222, 0, 14 ), RPT_2 ( 223, 0, 14 ), - RPT_2 (-223, 0, 14 ), RPT_2 ( 224, 0, 14 ), - RPT_2 (-224, 0, 14 ), RPT_2 ( 225, 0, 14 ), - RPT_2 (-225, 0, 14 ), RPT_2 ( 226, 0, 14 ), - RPT_2 (-226, 0, 14 ), RPT_2 ( 227, 0, 14 ), - RPT_2 (-227, 0, 14 ), RPT_2 ( 228, 0, 14 ), - RPT_2 (-228, 0, 14 ), RPT_2 ( 229, 0, 14 ), - RPT_2 (-229, 0, 14 ), RPT_2 ( 230, 0, 14 ), - RPT_2 (-230, 0, 14 ), RPT_2 ( 231, 0, 14 ), - RPT_2 (-231, 0, 14 ), RPT_2 ( 232, 0, 14 ), - RPT_2 (-232, 0, 14 ), RPT_2 ( 233, 0, 14 ), - RPT_2 (-233, 0, 14 ), RPT_2 ( 234, 0, 14 ), - RPT_2 (-234, 0, 14 ), RPT_2 ( 235, 0, 14 ), - RPT_2 (-235, 0, 14 ), RPT_2 ( 236, 0, 14 ), - RPT_2 (-236, 0, 14 ), RPT_2 ( 237, 0, 14 ), - RPT_2 (-237, 0, 14 ), RPT_2 ( 238, 0, 14 ), - RPT_2 (-238, 0, 14 ), RPT_2 ( 239, 0, 14 ), - RPT_2 (-239, 0, 14 ), RPT_2 ( 240, 0, 14 ), - RPT_2 (-240, 0, 14 ), RPT_2 ( 241, 0, 14 ), - RPT_2 (-241, 0, 14 ), RPT_2 ( 242, 0, 14 ), - RPT_2 (-242, 0, 14 ), RPT_2 ( 243, 0, 14 ), - RPT_2 (-243, 0, 14 ), RPT_2 ( 244, 0, 14 ), - RPT_2 (-244, 0, 14 ), RPT_2 ( 245, 0, 14 ), - RPT_2 (-245, 0, 14 ), RPT_2 ( 246, 0, 14 ), - RPT_2 (-246, 0, 14 ), RPT_2 ( 247, 0, 14 ), - RPT_2 (-247, 0, 14 ), RPT_2 ( 248, 0, 14 ), - RPT_2 (-248, 0, 14 ), RPT_2 ( 249, 0, 14 ), - RPT_2 (-249, 0, 14 ), RPT_2 ( 250, 0, 14 ), - RPT_2 (-250, 0, 14 ), RPT_2 ( 251, 0, 14 ), - RPT_2 (-251, 0, 14 ), RPT_2 ( 252, 0, 14 ), - RPT_2 (-252, 0, 14 ), RPT_2 ( 253, 0, 14 ), - RPT_2 (-253, 0, 14 ), RPT_2 ( 254, 0, 14 ), - RPT_2 (-254, 0, 14 ), RPT_2 ( 255, 0, 14 ), - RPT_2 (-255, 0, 14 ), { 0, 0, 15 }, { 0, 1, 15 }, - { 0, 2, 15 }, { 0, 3, 15 }, { 0, 4, 15 }, { 0, 5, 15 }, - { 0, 6, 15 }, { 0, 7, 15 }, { 0, 8, 15 }, { 0, 9, 15 }, - { 0, 10, 15 }, { 0, 11, 15 }, { 0, 12, 15 }, { 0, 13, 15 }, - { 0, 14, 15 }, { 0, 15, 15 }, { 0, 16, 15 }, { 0, 17, 15 }, - { 0, 18, 15 }, { 0, 19, 15 }, { 0, 20, 15 }, { 0, 21, 15 }, - { 0, 22, 15 }, { 0, 23, 15 }, { 0, 24, 15 }, { 0, 25, 15 }, - { 0, 26, 15 }, { 0, 27, 15 }, { 0, 28, 15 }, { 0, 29, 15 }, - { 0, 30, 15 }, { 0, 31, 15 }, { 0, 32, 15 }, { 0, 33, 15 }, - { 0, 34, 15 }, { 0, 35, 15 }, { 0, 36, 15 }, { 0, 37, 15 }, - { 0, 38, 15 }, { 0, 39, 15 }, { 0, 40, 15 }, { 0, 41, 15 }, - { 0, 42, 15 }, { 0, 43, 15 }, { 0, 44, 15 }, { 0, 45, 15 }, - { 0, 46, 15 }, { 0, 47, 15 }, { 0, 48, 15 }, { 0, 49, 15 }, - { 0, 50, 15 }, { 0, 51, 15 }, { 0, 52, 15 }, { 0, 53, 15 }, - { 0, 54, 15 }, { 0, 55, 15 }, { 0, 56, 15 }, { 0, 57, 15 }, - { 0, 58, 15 }, { 0, 59, 15 }, { 0, 60, 15 }, { 0, 61, 15 }, - { 0, 62, 15 }, { 0, 63, 15 }, RPT_16 ( 51, 0, 11 ), - RPT_16 ( -51, 0, 11 ), RPT_16 ( 52, 0, 11 ), - RPT_16 ( -52, 0, 11 ), RPT_16 ( 53, 0, 11 ), - RPT_16 ( -53, 0, 11 ), RPT_16 ( 54, 0, 11 ), - RPT_16 ( -54, 0, 11 ), RPT_16 ( 55, 0, 11 ), - RPT_16 ( -55, 0, 11 ), RPT_16 ( 56, 0, 11 ), - RPT_16 ( -56, 0, 11 ), RPT_16 ( 57, 0, 11 ), - RPT_16 ( -57, 0, 11 ), RPT_16 ( 58, 0, 11 ), - RPT_16 ( -58, 0, 11 ), RPT_16 ( 59, 0, 11 ), - RPT_16 ( -59, 0, 11 ), RPT_16 ( 60, 0, 11 ), - RPT_16 ( -60, 0, 11 ), RPT_16 ( 61, 0, 11 ), - RPT_16 ( -61, 0, 11 ), RPT_16 ( 62, 0, 11 ), - RPT_16 ( -62, 0, 11 ), RPT_16 ( 63, 0, 11 ), - RPT_16 ( -63, 0, 11 ), RPT_16 ( 11, 1, 11 ), - RPT_16 ( -11, 1, 11 ), RPT_16 ( 12, 1, 11 ), - RPT_16 ( -12, 1, 11 ), RPT_16 ( 13, 1, 11 ), - RPT_16 ( -13, 1, 11 ), RPT_16 ( 14, 1, 11 ), - RPT_16 ( -14, 1, 11 ), RPT_16 ( 4, 2, 11 ), - RPT_16 ( -4, 2, 11 ), RPT_16 ( 5, 2, 11 ), - RPT_16 ( -5, 2, 11 ), RPT_16 ( 6, 2, 11 ), - RPT_16 ( -6, 2, 11 ), RPT_16 ( 3, 3, 11 ), - RPT_16 ( -3, 3, 11 ), RPT_16 ( 2, 4, 11 ), - RPT_16 ( -2, 4, 11 ), RPT_16 ( 1, 9, 11 ), - RPT_16 ( -1, 9, 11 ), RPT_16 ( 1, 10, 11 ), - RPT_16 ( -1, 10, 11 ), RPT_8 ( 15, 1, 12 ), - RPT_8 ( -15, 1, 12 ), RPT_8 ( 16, 1, 12 ), - RPT_8 ( -16, 1, 12 ), RPT_8 ( 17, 1, 12 ), - RPT_8 ( -17, 1, 12 ), RPT_8 ( 18, 1, 12 ), - RPT_8 ( -18, 1, 12 ), RPT_8 ( 7, 2, 12 ), - RPT_8 ( -7, 2, 12 ), RPT_8 ( 8, 2, 12 ), - RPT_8 ( -8, 2, 12 ), RPT_8 ( 9, 2, 12 ), - RPT_8 ( -9, 2, 12 ), RPT_8 ( 10, 2, 12 ), - RPT_8 ( -10, 2, 12 ), RPT_8 ( 4, 3, 12 ), - RPT_8 ( -4, 3, 12 ), RPT_8 ( 5, 3, 12 ), - RPT_8 ( -5, 3, 12 ), RPT_8 ( 6, 3, 12 ), - RPT_8 ( -6, 3, 12 ), RPT_8 ( 2, 5, 12 ), - RPT_8 ( -2, 5, 12 ), RPT_16 ( 0, 7, 11 ), - RPT_16 ( 0, 8, 11 ), RPT_16 ( 0, 9, 11 ), - RPT_16 ( 0, 10, 11 ), RPT_8 ( 1, 11, 12 ), - RPT_8 ( -1, 11, 12 ), RPT_8 ( 1, 12, 12 ), - RPT_8 ( -1, 12, 12 ), RPT_8 ( 1, 13, 12 ), - RPT_8 ( -1, 13, 12 ), RPT_8 ( 1, 14, 12 ), - RPT_8 ( -1, 14, 12 ), RPT_4 ( 19, 1, 13 ), - RPT_4 ( -19, 1, 13 ), RPT_4 ( 20, 1, 13 ), - RPT_4 ( -20, 1, 13 ), RPT_4 ( 3, 4, 13 ), - RPT_4 ( -3, 4, 13 ), RPT_4 ( 2, 6, 13 ), - RPT_4 ( -2, 6, 13 ), -}; - -static const HQXLUT ac8_lut[] = { - RPT_128 ( 1, 0, 4 ), RPT_128 ( -1, 0, 4 ), - RPT_128 ( 2, 0, 4 ), RPT_128 ( -2, 0, 4 ), - RPT_64 ( 3, 0, 5 ), RPT_64 ( -3, 0, 5 ), - RPT_64 ( 4, 0, 5 ), RPT_64 ( -4, 0, 5 ), - RPT_128 ( 0, 64, 4 ), RPT_32 ( 5, 0, 6 ), - RPT_32 ( -5, 0, 6 ), RPT_32 ( 6, 0, 6 ), - RPT_32 ( -6, 0, 6 ), RPT_32 ( 7, 0, 6 ), - RPT_32 ( -7, 0, 6 ), RPT_32 ( 8, 0, 6 ), - RPT_32 ( -8, 0, 6 ), RPT_32 ( 1, 1, 6 ), - RPT_32 ( -1, 1, 6 ), RPT_32 ( 2, 1, 6 ), - RPT_32 ( -2, 1, 6 ), RPT_16 ( 9, 0, 7 ), - RPT_16 ( -9, 0, 7 ), RPT_16 ( 10, 0, 7 ), - RPT_16 ( -10, 0, 7 ), RPT_16 ( 11, 0, 7 ), - RPT_16 ( -11, 0, 7 ), RPT_16 ( 12, 0, 7 ), - RPT_16 ( -12, 0, 7 ), RPT_16 ( 3, 1, 7 ), - RPT_16 ( -3, 1, 7 ), RPT_16 ( 4, 1, 7 ), - RPT_16 ( -4, 1, 7 ), RPT_16 ( 1, 2, 7 ), - RPT_16 ( -1, 2, 7 ), { 2048, 0, -1 }, { 2112, 0, -1 }, - { 2176, 0, -1 }, { 2240, 0, -1 }, { 2304, 0, -1 }, { 2368, 0, -1 }, - { 2432, 0, -1 }, { 2496, 0, -1 }, { 2560, 0, -1 }, { 2624, 0, -1 }, - { 2688, 0, -1 }, { 2752, 0, -1 }, { 2816, 0, -1 }, { 2880, 0, -1 }, - { 2944, 0, -1 }, { 3008, 0, -1 }, { 3072, 0, -1 }, { 3136, 0, -1 }, - { 3200, 0, -1 }, { 3264, 0, -1 }, { 3328, 0, -1 }, { 3392, 0, -1 }, - { 3456, 0, -1 }, { 3520, 0, -1 }, { 3584, 0, -1 }, { 3648, 0, -1 }, - { 3712, 0, -1 }, { 3776, 0, -1 }, { 3840, 0, -1 }, { 3904, 0, -1 }, - { 3968, 0, -1 }, { 4032, 0, -1 }, RPT_8 ( 13, 0, 8 ), - RPT_8 ( -13, 0, 8 ), RPT_8 ( 14, 0, 8 ), - RPT_8 ( -14, 0, 8 ), RPT_8 ( 15, 0, 8 ), - RPT_8 ( -15, 0, 8 ), RPT_8 ( 16, 0, 8 ), - RPT_8 ( -16, 0, 8 ), RPT_8 ( 17, 0, 8 ), - RPT_8 ( -17, 0, 8 ), RPT_8 ( 18, 0, 8 ), - RPT_8 ( -18, 0, 8 ), RPT_8 ( 5, 1, 8 ), - RPT_8 ( -5, 1, 8 ), RPT_8 ( 6, 1, 8 ), - RPT_8 ( -6, 1, 8 ), RPT_8 ( 2, 2, 8 ), - RPT_8 ( -2, 2, 8 ), RPT_8 ( 1, 3, 8 ), - RPT_8 ( -1, 3, 8 ), RPT_8 ( 0, 0, 8 ), - RPT_4 ( 19, 0, 9 ), RPT_4 ( -19, 0, 9 ), - RPT_4 ( 20, 0, 9 ), RPT_4 ( -20, 0, 9 ), - RPT_4 ( 21, 0, 9 ), RPT_4 ( -21, 0, 9 ), - RPT_4 ( 22, 0, 9 ), RPT_4 ( -22, 0, 9 ), - RPT_4 ( 23, 0, 9 ), RPT_4 ( -23, 0, 9 ), - RPT_4 ( 24, 0, 9 ), RPT_4 ( -24, 0, 9 ), - RPT_4 ( 25, 0, 9 ), RPT_4 ( -25, 0, 9 ), - RPT_4 ( 7, 1, 9 ), RPT_4 ( -7, 1, 9 ), - RPT_4 ( 8, 1, 9 ), RPT_4 ( -8, 1, 9 ), - RPT_4 ( 3, 2, 9 ), RPT_4 ( -3, 2, 9 ), - RPT_4 ( 2, 3, 9 ), RPT_4 ( -2, 3, 9 ), - RPT_4 ( 1, 4, 9 ), RPT_4 ( -1, 4, 9 ), - RPT_4 ( 1, 5, 9 ), RPT_4 ( -1, 5, 9 ), - RPT_2 ( 26, 0, 10 ), RPT_2 ( -26, 0, 10 ), - RPT_2 ( 27, 0, 10 ), RPT_2 ( -27, 0, 10 ), - RPT_2 ( 28, 0, 10 ), RPT_2 ( -28, 0, 10 ), - RPT_2 ( 29, 0, 10 ), RPT_2 ( -29, 0, 10 ), - RPT_2 ( 30, 0, 10 ), RPT_2 ( -30, 0, 10 ), - RPT_2 ( 31, 0, 10 ), RPT_2 ( -31, 0, 10 ), - RPT_2 ( 32, 0, 10 ), RPT_2 ( -32, 0, 10 ), - RPT_2 ( 33, 0, 10 ), RPT_2 ( -33, 0, 10 ), - RPT_2 ( 34, 0, 10 ), RPT_2 ( -34, 0, 10 ), - RPT_2 ( 35, 0, 10 ), RPT_2 ( -35, 0, 10 ), - RPT_2 ( 36, 0, 10 ), RPT_2 ( -36, 0, 10 ), - RPT_4 ( 0, 1, 9 ), RPT_2 ( 9, 1, 10 ), - RPT_2 ( -9, 1, 10 ), RPT_2 ( 10, 1, 10 ), - RPT_2 ( -10, 1, 10 ), RPT_2 ( 11, 1, 10 ), - RPT_2 ( -11, 1, 10 ), RPT_2 ( 12, 1, 10 ), - RPT_2 ( -12, 1, 10 ), RPT_4 ( 0, 2, 9 ), - RPT_2 ( 4, 2, 10 ), RPT_2 ( -4, 2, 10 ), - RPT_2 ( 5, 2, 10 ), RPT_2 ( -5, 2, 10 ), - RPT_2 ( 6, 2, 10 ), RPT_2 ( -6, 2, 10 ), - RPT_4 ( 0, 3, 9 ), RPT_2 ( 3, 3, 10 ), - RPT_2 ( -3, 3, 10 ), RPT_2 ( 4, 3, 10 ), - RPT_2 ( -4, 3, 10 ), RPT_4 ( 0, 4, 9 ), - RPT_2 ( 2, 4, 10 ), RPT_2 ( -2, 4, 10 ), - RPT_4 ( 0, 5, 9 ), RPT_2 ( 1, 6, 10 ), - RPT_2 ( -1, 6, 10 ), RPT_2 ( 1, 7, 10 ), - RPT_2 ( -1, 7, 10 ), RPT_2 ( 1, 8, 10 ), - RPT_2 ( -1, 8, 10 ), { 37, 0, 11 }, { -37, 0, 11 }, - { 38, 0, 11 }, { -38, 0, 11 }, { 39, 0, 11 }, { -39, 0, 11 }, - { 40, 0, 11 }, { -40, 0, 11 }, { 41, 0, 11 }, { -41, 0, 11 }, - { 42, 0, 11 }, { -42, 0, 11 }, { 43, 0, 11 }, { -43, 0, 11 }, - { 44, 0, 11 }, { -44, 0, 11 }, { 45, 0, 11 }, { -45, 0, 11 }, - { 46, 0, 11 }, { -46, 0, 11 }, { 47, 0, 11 }, { -47, 0, 11 }, - { 48, 0, 11 }, { -48, 0, 11 }, { 13, 1, 11 }, { -13, 1, 11 }, - { 14, 1, 11 }, { -14, 1, 11 }, { 15, 1, 11 }, { -15, 1, 11 }, - { 16, 1, 11 }, { -16, 1, 11 }, { 7, 2, 11 }, { -7, 2, 11 }, - { 8, 2, 11 }, { -8, 2, 11 }, { 5, 3, 11 }, { -5, 3, 11 }, - { 6, 3, 11 }, { -6, 3, 11 }, { 3, 4, 11 }, { -3, 4, 11 }, - { 4, 4, 11 }, { -4, 4, 11 }, { 2, 5, 11 }, { -2, 5, 11 }, - RPT_2 ( 0, 6, 10 ), { 2, 6, 11 }, { -2, 6, 11 }, - RPT_2 ( 0, 7, 10 ), RPT_2 ( 0, 8, 10 ), - RPT_2 ( 0, 9, 10 ), { 1, 9, 11 }, { -1, 9, 11 }, - { 1, 10, 11 }, { -1, 10, 11 }, { 1, 11, 11 }, { -1, 11, 11 }, - { 1, 12, 11 }, { -1, 12, 11 }, { 4096, 0, -1 }, { 4160, 0, -1 }, - { 4224, 0, -1 }, { 4288, 0, -1 }, { 4352, 0, -1 }, { 4416, 0, -1 }, - { 4480, 0, -1 }, { 4544, 0, -1 }, { 4608, 0, -1 }, { 4672, 0, -1 }, - { 4736, 0, -1 }, { 4800, 0, -1 }, { 4864, 0, -1 }, { 4928, 0, -1 }, - { 4992, 0, -1 }, { 5056, 0, -1 }, { 5120, 0, -1 }, { 5184, 0, -1 }, - { 5248, 0, -1 }, { 5312, 0, -1 }, { 5376, 0, -1 }, { 5440, 0, -1 }, - { 5504, 0, -1 }, { 5568, 0, -1 }, { 5632, 0, -1 }, { 5696, 0, -1 }, - { 5760, 0, -1 }, { 5824, 0, -1 }, { 5888, 0, -1 }, { 5952, 0, -1 }, - { 6016, 0, -1 }, { 6080, 0, -1 }, { 6144, 0, -1 }, { 6208, 0, -1 }, - { 6272, 0, -1 }, { 6336, 0, -1 }, { 6400, 0, -1 }, { 6464, 0, -1 }, - { 6528, 0, -1 }, { 6592, 0, -1 }, { 0, 10, 11 }, { 6656, 0, -1 }, - { 0, 11, 11 }, { 0, 12, 11 }, { 0, 13, 11 }, { 6720, 0, -1 }, - { 6784, 0, -1 }, { 6848, 0, -1 }, { 6912, 0, -1 }, { 6976, 0, -1 }, - { 7040, 0, -1 }, { 7104, 0, -1 }, { 7168, 0, -1 }, { 7232, 0, -1 }, - { 7296, 0, -1 }, { 7360, 0, -1 }, { 7424, 0, -1 }, { 7488, 0, -1 }, - { 7552, 0, -1 }, { 7616, 0, -1 }, RPT_8 ( 0, 0, 14 ), - RPT_4 ( 1, 0, 15 ), RPT_4 ( -1, 0, 15 ), - RPT_4 ( 2, 0, 15 ), RPT_4 ( -2, 0, 15 ), - RPT_4 ( 3, 0, 15 ), RPT_4 ( -3, 0, 15 ), - RPT_4 ( 4, 0, 15 ), RPT_4 ( -4, 0, 15 ), - RPT_4 ( 5, 0, 15 ), RPT_4 ( -5, 0, 15 ), - RPT_4 ( 6, 0, 15 ), RPT_4 ( -6, 0, 15 ), - RPT_4 ( 7, 0, 15 ), RPT_4 ( -7, 0, 15 ), - RPT_4 ( 8, 0, 15 ), RPT_4 ( -8, 0, 15 ), - RPT_4 ( 9, 0, 15 ), RPT_4 ( -9, 0, 15 ), - RPT_4 ( 10, 0, 15 ), RPT_4 ( -10, 0, 15 ), - RPT_4 ( 11, 0, 15 ), RPT_4 ( -11, 0, 15 ), - RPT_4 ( 12, 0, 15 ), RPT_4 ( -12, 0, 15 ), - RPT_4 ( 13, 0, 15 ), RPT_4 ( -13, 0, 15 ), - RPT_4 ( 14, 0, 15 ), RPT_4 ( -14, 0, 15 ), - RPT_4 ( 15, 0, 15 ), RPT_4 ( -15, 0, 15 ), - RPT_4 ( 16, 0, 15 ), RPT_4 ( -16, 0, 15 ), - RPT_4 ( 17, 0, 15 ), RPT_4 ( -17, 0, 15 ), - RPT_4 ( 18, 0, 15 ), RPT_4 ( -18, 0, 15 ), - RPT_4 ( 19, 0, 15 ), RPT_4 ( -19, 0, 15 ), - RPT_4 ( 20, 0, 15 ), RPT_4 ( -20, 0, 15 ), - RPT_4 ( 21, 0, 15 ), RPT_4 ( -21, 0, 15 ), - RPT_4 ( 22, 0, 15 ), RPT_4 ( -22, 0, 15 ), - RPT_4 ( 23, 0, 15 ), RPT_4 ( -23, 0, 15 ), - RPT_4 ( 24, 0, 15 ), RPT_4 ( -24, 0, 15 ), - RPT_4 ( 25, 0, 15 ), RPT_4 ( -25, 0, 15 ), - RPT_4 ( 26, 0, 15 ), RPT_4 ( -26, 0, 15 ), - RPT_4 ( 27, 0, 15 ), RPT_4 ( -27, 0, 15 ), - RPT_4 ( 28, 0, 15 ), RPT_4 ( -28, 0, 15 ), - RPT_4 ( 29, 0, 15 ), RPT_4 ( -29, 0, 15 ), - RPT_4 ( 30, 0, 15 ), RPT_4 ( -30, 0, 15 ), - RPT_4 ( 31, 0, 15 ), RPT_4 ( -31, 0, 15 ), - RPT_4 ( 32, 0, 15 ), RPT_4 ( -32, 0, 15 ), - RPT_4 ( 33, 0, 15 ), RPT_4 ( -33, 0, 15 ), - RPT_4 ( 34, 0, 15 ), RPT_4 ( -34, 0, 15 ), - RPT_4 ( 35, 0, 15 ), RPT_4 ( -35, 0, 15 ), - RPT_4 ( 36, 0, 15 ), RPT_4 ( -36, 0, 15 ), - RPT_4 ( 37, 0, 15 ), RPT_4 ( -37, 0, 15 ), - RPT_4 ( 38, 0, 15 ), RPT_4 ( -38, 0, 15 ), - RPT_4 ( 39, 0, 15 ), RPT_4 ( -39, 0, 15 ), - RPT_4 ( 40, 0, 15 ), RPT_4 ( -40, 0, 15 ), - RPT_4 ( 41, 0, 15 ), RPT_4 ( -41, 0, 15 ), - RPT_4 ( 42, 0, 15 ), RPT_4 ( -42, 0, 15 ), - RPT_4 ( 43, 0, 15 ), RPT_4 ( -43, 0, 15 ), - RPT_4 ( 44, 0, 15 ), RPT_4 ( -44, 0, 15 ), - RPT_4 ( 45, 0, 15 ), RPT_4 ( -45, 0, 15 ), - RPT_4 ( 46, 0, 15 ), RPT_4 ( -46, 0, 15 ), - RPT_4 ( 47, 0, 15 ), RPT_4 ( -47, 0, 15 ), - RPT_4 ( 48, 0, 15 ), RPT_4 ( -48, 0, 15 ), - RPT_4 ( 49, 0, 15 ), RPT_4 ( -49, 0, 15 ), - RPT_4 ( 50, 0, 15 ), RPT_4 ( -50, 0, 15 ), - RPT_4 ( 51, 0, 15 ), RPT_4 ( -51, 0, 15 ), - RPT_4 ( 52, 0, 15 ), RPT_4 ( -52, 0, 15 ), - RPT_4 ( 53, 0, 15 ), RPT_4 ( -53, 0, 15 ), - RPT_4 ( 54, 0, 15 ), RPT_4 ( -54, 0, 15 ), - RPT_4 ( 55, 0, 15 ), RPT_4 ( -55, 0, 15 ), - RPT_4 ( 56, 0, 15 ), RPT_4 ( -56, 0, 15 ), - RPT_4 ( 57, 0, 15 ), RPT_4 ( -57, 0, 15 ), - RPT_4 ( 58, 0, 15 ), RPT_4 ( -58, 0, 15 ), - RPT_4 ( 59, 0, 15 ), RPT_4 ( -59, 0, 15 ), - RPT_4 ( 60, 0, 15 ), RPT_4 ( -60, 0, 15 ), - RPT_4 ( 61, 0, 15 ), RPT_4 ( -61, 0, 15 ), - RPT_4 ( 62, 0, 15 ), RPT_4 ( -62, 0, 15 ), - RPT_4 ( 63, 0, 15 ), RPT_4 ( -63, 0, 15 ), - RPT_4 ( 64, 0, 15 ), RPT_4 ( -64, 0, 15 ), - RPT_4 ( 65, 0, 15 ), RPT_4 ( -65, 0, 15 ), - RPT_4 ( 66, 0, 15 ), RPT_4 ( -66, 0, 15 ), - RPT_4 ( 67, 0, 15 ), RPT_4 ( -67, 0, 15 ), - RPT_4 ( 68, 0, 15 ), RPT_4 ( -68, 0, 15 ), - RPT_4 ( 69, 0, 15 ), RPT_4 ( -69, 0, 15 ), - RPT_4 ( 70, 0, 15 ), RPT_4 ( -70, 0, 15 ), - RPT_4 ( 71, 0, 15 ), RPT_4 ( -71, 0, 15 ), - RPT_4 ( 72, 0, 15 ), RPT_4 ( -72, 0, 15 ), - RPT_4 ( 73, 0, 15 ), RPT_4 ( -73, 0, 15 ), - RPT_4 ( 74, 0, 15 ), RPT_4 ( -74, 0, 15 ), - RPT_4 ( 75, 0, 15 ), RPT_4 ( -75, 0, 15 ), - RPT_4 ( 76, 0, 15 ), RPT_4 ( -76, 0, 15 ), - RPT_4 ( 77, 0, 15 ), RPT_4 ( -77, 0, 15 ), - RPT_4 ( 78, 0, 15 ), RPT_4 ( -78, 0, 15 ), - RPT_4 ( 79, 0, 15 ), RPT_4 ( -79, 0, 15 ), - RPT_4 ( 80, 0, 15 ), RPT_4 ( -80, 0, 15 ), - RPT_4 ( 81, 0, 15 ), RPT_4 ( -81, 0, 15 ), - RPT_4 ( 82, 0, 15 ), RPT_4 ( -82, 0, 15 ), - RPT_4 ( 83, 0, 15 ), RPT_4 ( -83, 0, 15 ), - RPT_4 ( 84, 0, 15 ), RPT_4 ( -84, 0, 15 ), - RPT_4 ( 85, 0, 15 ), RPT_4 ( -85, 0, 15 ), - RPT_4 ( 86, 0, 15 ), RPT_4 ( -86, 0, 15 ), - RPT_4 ( 87, 0, 15 ), RPT_4 ( -87, 0, 15 ), - RPT_4 ( 88, 0, 15 ), RPT_4 ( -88, 0, 15 ), - RPT_4 ( 89, 0, 15 ), RPT_4 ( -89, 0, 15 ), - RPT_4 ( 90, 0, 15 ), RPT_4 ( -90, 0, 15 ), - RPT_4 ( 91, 0, 15 ), RPT_4 ( -91, 0, 15 ), - RPT_4 ( 92, 0, 15 ), RPT_4 ( -92, 0, 15 ), - RPT_4 ( 93, 0, 15 ), RPT_4 ( -93, 0, 15 ), - RPT_4 ( 94, 0, 15 ), RPT_4 ( -94, 0, 15 ), - RPT_4 ( 95, 0, 15 ), RPT_4 ( -95, 0, 15 ), - RPT_4 ( 96, 0, 15 ), RPT_4 ( -96, 0, 15 ), - RPT_4 ( 97, 0, 15 ), RPT_4 ( -97, 0, 15 ), - RPT_4 ( 98, 0, 15 ), RPT_4 ( -98, 0, 15 ), - RPT_4 ( 99, 0, 15 ), RPT_4 ( -99, 0, 15 ), - RPT_4 ( 100, 0, 15 ), RPT_4 (-100, 0, 15 ), - RPT_4 ( 101, 0, 15 ), RPT_4 (-101, 0, 15 ), - RPT_4 ( 102, 0, 15 ), RPT_4 (-102, 0, 15 ), - RPT_4 ( 103, 0, 15 ), RPT_4 (-103, 0, 15 ), - RPT_4 ( 104, 0, 15 ), RPT_4 (-104, 0, 15 ), - RPT_4 ( 105, 0, 15 ), RPT_4 (-105, 0, 15 ), - RPT_4 ( 106, 0, 15 ), RPT_4 (-106, 0, 15 ), - RPT_4 ( 107, 0, 15 ), RPT_4 (-107, 0, 15 ), - RPT_4 ( 108, 0, 15 ), RPT_4 (-108, 0, 15 ), - RPT_4 ( 109, 0, 15 ), RPT_4 (-109, 0, 15 ), - RPT_4 ( 110, 0, 15 ), RPT_4 (-110, 0, 15 ), - RPT_4 ( 111, 0, 15 ), RPT_4 (-111, 0, 15 ), - RPT_4 ( 112, 0, 15 ), RPT_4 (-112, 0, 15 ), - RPT_4 ( 113, 0, 15 ), RPT_4 (-113, 0, 15 ), - RPT_4 ( 114, 0, 15 ), RPT_4 (-114, 0, 15 ), - RPT_4 ( 115, 0, 15 ), RPT_4 (-115, 0, 15 ), - RPT_4 ( 116, 0, 15 ), RPT_4 (-116, 0, 15 ), - RPT_4 ( 117, 0, 15 ), RPT_4 (-117, 0, 15 ), - RPT_4 ( 118, 0, 15 ), RPT_4 (-118, 0, 15 ), - RPT_4 ( 119, 0, 15 ), RPT_4 (-119, 0, 15 ), - RPT_4 ( 120, 0, 15 ), RPT_4 (-120, 0, 15 ), - RPT_4 ( 121, 0, 15 ), RPT_4 (-121, 0, 15 ), - RPT_4 ( 122, 0, 15 ), RPT_4 (-122, 0, 15 ), - RPT_4 ( 123, 0, 15 ), RPT_4 (-123, 0, 15 ), - RPT_4 ( 124, 0, 15 ), RPT_4 (-124, 0, 15 ), - RPT_4 ( 125, 0, 15 ), RPT_4 (-125, 0, 15 ), - RPT_4 ( 126, 0, 15 ), RPT_4 (-126, 0, 15 ), - RPT_4 ( 127, 0, 15 ), RPT_4 (-127, 0, 15 ), - RPT_4 ( 128, 0, 15 ), RPT_4 (-128, 0, 15 ), - RPT_4 ( 129, 0, 15 ), RPT_4 (-129, 0, 15 ), - RPT_4 ( 130, 0, 15 ), RPT_4 (-130, 0, 15 ), - RPT_4 ( 131, 0, 15 ), RPT_4 (-131, 0, 15 ), - RPT_4 ( 132, 0, 15 ), RPT_4 (-132, 0, 15 ), - RPT_4 ( 133, 0, 15 ), RPT_4 (-133, 0, 15 ), - RPT_4 ( 134, 0, 15 ), RPT_4 (-134, 0, 15 ), - RPT_4 ( 135, 0, 15 ), RPT_4 (-135, 0, 15 ), - RPT_4 ( 136, 0, 15 ), RPT_4 (-136, 0, 15 ), - RPT_4 ( 137, 0, 15 ), RPT_4 (-137, 0, 15 ), - RPT_4 ( 138, 0, 15 ), RPT_4 (-138, 0, 15 ), - RPT_4 ( 139, 0, 15 ), RPT_4 (-139, 0, 15 ), - RPT_4 ( 140, 0, 15 ), RPT_4 (-140, 0, 15 ), - RPT_4 ( 141, 0, 15 ), RPT_4 (-141, 0, 15 ), - RPT_4 ( 142, 0, 15 ), RPT_4 (-142, 0, 15 ), - RPT_4 ( 143, 0, 15 ), RPT_4 (-143, 0, 15 ), - RPT_4 ( 144, 0, 15 ), RPT_4 (-144, 0, 15 ), - RPT_4 ( 145, 0, 15 ), RPT_4 (-145, 0, 15 ), - RPT_4 ( 146, 0, 15 ), RPT_4 (-146, 0, 15 ), - RPT_4 ( 147, 0, 15 ), RPT_4 (-147, 0, 15 ), - RPT_4 ( 148, 0, 15 ), RPT_4 (-148, 0, 15 ), - RPT_4 ( 149, 0, 15 ), RPT_4 (-149, 0, 15 ), - RPT_4 ( 150, 0, 15 ), RPT_4 (-150, 0, 15 ), - RPT_4 ( 151, 0, 15 ), RPT_4 (-151, 0, 15 ), - RPT_4 ( 152, 0, 15 ), RPT_4 (-152, 0, 15 ), - RPT_4 ( 153, 0, 15 ), RPT_4 (-153, 0, 15 ), - RPT_4 ( 154, 0, 15 ), RPT_4 (-154, 0, 15 ), - RPT_4 ( 155, 0, 15 ), RPT_4 (-155, 0, 15 ), - RPT_4 ( 156, 0, 15 ), RPT_4 (-156, 0, 15 ), - RPT_4 ( 157, 0, 15 ), RPT_4 (-157, 0, 15 ), - RPT_4 ( 158, 0, 15 ), RPT_4 (-158, 0, 15 ), - RPT_4 ( 159, 0, 15 ), RPT_4 (-159, 0, 15 ), - RPT_4 ( 160, 0, 15 ), RPT_4 (-160, 0, 15 ), - RPT_4 ( 161, 0, 15 ), RPT_4 (-161, 0, 15 ), - RPT_4 ( 162, 0, 15 ), RPT_4 (-162, 0, 15 ), - RPT_4 ( 163, 0, 15 ), RPT_4 (-163, 0, 15 ), - RPT_4 ( 164, 0, 15 ), RPT_4 (-164, 0, 15 ), - RPT_4 ( 165, 0, 15 ), RPT_4 (-165, 0, 15 ), - RPT_4 ( 166, 0, 15 ), RPT_4 (-166, 0, 15 ), - RPT_4 ( 167, 0, 15 ), RPT_4 (-167, 0, 15 ), - RPT_4 ( 168, 0, 15 ), RPT_4 (-168, 0, 15 ), - RPT_4 ( 169, 0, 15 ), RPT_4 (-169, 0, 15 ), - RPT_4 ( 170, 0, 15 ), RPT_4 (-170, 0, 15 ), - RPT_4 ( 171, 0, 15 ), RPT_4 (-171, 0, 15 ), - RPT_4 ( 172, 0, 15 ), RPT_4 (-172, 0, 15 ), - RPT_4 ( 173, 0, 15 ), RPT_4 (-173, 0, 15 ), - RPT_4 ( 174, 0, 15 ), RPT_4 (-174, 0, 15 ), - RPT_4 ( 175, 0, 15 ), RPT_4 (-175, 0, 15 ), - RPT_4 ( 176, 0, 15 ), RPT_4 (-176, 0, 15 ), - RPT_4 ( 177, 0, 15 ), RPT_4 (-177, 0, 15 ), - RPT_4 ( 178, 0, 15 ), RPT_4 (-178, 0, 15 ), - RPT_4 ( 179, 0, 15 ), RPT_4 (-179, 0, 15 ), - RPT_4 ( 180, 0, 15 ), RPT_4 (-180, 0, 15 ), - RPT_4 ( 181, 0, 15 ), RPT_4 (-181, 0, 15 ), - RPT_4 ( 182, 0, 15 ), RPT_4 (-182, 0, 15 ), - RPT_4 ( 183, 0, 15 ), RPT_4 (-183, 0, 15 ), - RPT_4 ( 184, 0, 15 ), RPT_4 (-184, 0, 15 ), - RPT_4 ( 185, 0, 15 ), RPT_4 (-185, 0, 15 ), - RPT_4 ( 186, 0, 15 ), RPT_4 (-186, 0, 15 ), - RPT_4 ( 187, 0, 15 ), RPT_4 (-187, 0, 15 ), - RPT_4 ( 188, 0, 15 ), RPT_4 (-188, 0, 15 ), - RPT_4 ( 189, 0, 15 ), RPT_4 (-189, 0, 15 ), - RPT_4 ( 190, 0, 15 ), RPT_4 (-190, 0, 15 ), - RPT_4 ( 191, 0, 15 ), RPT_4 (-191, 0, 15 ), - RPT_4 ( 192, 0, 15 ), RPT_4 (-192, 0, 15 ), - RPT_4 ( 193, 0, 15 ), RPT_4 (-193, 0, 15 ), - RPT_4 ( 194, 0, 15 ), RPT_4 (-194, 0, 15 ), - RPT_4 ( 195, 0, 15 ), RPT_4 (-195, 0, 15 ), - RPT_4 ( 196, 0, 15 ), RPT_4 (-196, 0, 15 ), - RPT_4 ( 197, 0, 15 ), RPT_4 (-197, 0, 15 ), - RPT_4 ( 198, 0, 15 ), RPT_4 (-198, 0, 15 ), - RPT_4 ( 199, 0, 15 ), RPT_4 (-199, 0, 15 ), - RPT_4 ( 200, 0, 15 ), RPT_4 (-200, 0, 15 ), - RPT_4 ( 201, 0, 15 ), RPT_4 (-201, 0, 15 ), - RPT_4 ( 202, 0, 15 ), RPT_4 (-202, 0, 15 ), - RPT_4 ( 203, 0, 15 ), RPT_4 (-203, 0, 15 ), - RPT_4 ( 204, 0, 15 ), RPT_4 (-204, 0, 15 ), - RPT_4 ( 205, 0, 15 ), RPT_4 (-205, 0, 15 ), - RPT_4 ( 206, 0, 15 ), RPT_4 (-206, 0, 15 ), - RPT_4 ( 207, 0, 15 ), RPT_4 (-207, 0, 15 ), - RPT_4 ( 208, 0, 15 ), RPT_4 (-208, 0, 15 ), - RPT_4 ( 209, 0, 15 ), RPT_4 (-209, 0, 15 ), - RPT_4 ( 210, 0, 15 ), RPT_4 (-210, 0, 15 ), - RPT_4 ( 211, 0, 15 ), RPT_4 (-211, 0, 15 ), - RPT_4 ( 212, 0, 15 ), RPT_4 (-212, 0, 15 ), - RPT_4 ( 213, 0, 15 ), RPT_4 (-213, 0, 15 ), - RPT_4 ( 214, 0, 15 ), RPT_4 (-214, 0, 15 ), - RPT_4 ( 215, 0, 15 ), RPT_4 (-215, 0, 15 ), - RPT_4 ( 216, 0, 15 ), RPT_4 (-216, 0, 15 ), - RPT_4 ( 217, 0, 15 ), RPT_4 (-217, 0, 15 ), - RPT_4 ( 218, 0, 15 ), RPT_4 (-218, 0, 15 ), - RPT_4 ( 219, 0, 15 ), RPT_4 (-219, 0, 15 ), - RPT_4 ( 220, 0, 15 ), RPT_4 (-220, 0, 15 ), - RPT_4 ( 221, 0, 15 ), RPT_4 (-221, 0, 15 ), - RPT_4 ( 222, 0, 15 ), RPT_4 (-222, 0, 15 ), - RPT_4 ( 223, 0, 15 ), RPT_4 (-223, 0, 15 ), - RPT_4 ( 224, 0, 15 ), RPT_4 (-224, 0, 15 ), - RPT_4 ( 225, 0, 15 ), RPT_4 (-225, 0, 15 ), - RPT_4 ( 226, 0, 15 ), RPT_4 (-226, 0, 15 ), - RPT_4 ( 227, 0, 15 ), RPT_4 (-227, 0, 15 ), - RPT_4 ( 228, 0, 15 ), RPT_4 (-228, 0, 15 ), - RPT_4 ( 229, 0, 15 ), RPT_4 (-229, 0, 15 ), - RPT_4 ( 230, 0, 15 ), RPT_4 (-230, 0, 15 ), - RPT_4 ( 231, 0, 15 ), RPT_4 (-231, 0, 15 ), - RPT_4 ( 232, 0, 15 ), RPT_4 (-232, 0, 15 ), - RPT_4 ( 233, 0, 15 ), RPT_4 (-233, 0, 15 ), - RPT_4 ( 234, 0, 15 ), RPT_4 (-234, 0, 15 ), - RPT_4 ( 235, 0, 15 ), RPT_4 (-235, 0, 15 ), - RPT_4 ( 236, 0, 15 ), RPT_4 (-236, 0, 15 ), - RPT_4 ( 237, 0, 15 ), RPT_4 (-237, 0, 15 ), - RPT_4 ( 238, 0, 15 ), RPT_4 (-238, 0, 15 ), - RPT_4 ( 239, 0, 15 ), RPT_4 (-239, 0, 15 ), - RPT_4 ( 240, 0, 15 ), RPT_4 (-240, 0, 15 ), - RPT_4 ( 241, 0, 15 ), RPT_4 (-241, 0, 15 ), - RPT_4 ( 242, 0, 15 ), RPT_4 (-242, 0, 15 ), - RPT_4 ( 243, 0, 15 ), RPT_4 (-243, 0, 15 ), - RPT_4 ( 244, 0, 15 ), RPT_4 (-244, 0, 15 ), - RPT_4 ( 245, 0, 15 ), RPT_4 (-245, 0, 15 ), - RPT_4 ( 246, 0, 15 ), RPT_4 (-246, 0, 15 ), - RPT_4 ( 247, 0, 15 ), RPT_4 (-247, 0, 15 ), - RPT_4 ( 248, 0, 15 ), RPT_4 (-248, 0, 15 ), - RPT_4 ( 249, 0, 15 ), RPT_4 (-249, 0, 15 ), - RPT_4 ( 250, 0, 15 ), RPT_4 (-250, 0, 15 ), - RPT_4 ( 251, 0, 15 ), RPT_4 (-251, 0, 15 ), - RPT_4 ( 252, 0, 15 ), RPT_4 (-252, 0, 15 ), - RPT_4 ( 253, 0, 15 ), RPT_4 (-253, 0, 15 ), - RPT_4 ( 254, 0, 15 ), RPT_4 (-254, 0, 15 ), - RPT_4 ( 255, 0, 15 ), RPT_4 (-255, 0, 15 ), - RPT_32 ( 49, 0, 12 ), RPT_32 ( -49, 0, 12 ), - RPT_32 ( 50, 0, 12 ), RPT_32 ( -50, 0, 12 ), - RPT_32 ( 51, 0, 12 ), RPT_32 ( -51, 0, 12 ), - RPT_32 ( 52, 0, 12 ), RPT_32 ( -52, 0, 12 ), - RPT_32 ( 53, 0, 12 ), RPT_32 ( -53, 0, 12 ), - RPT_32 ( 54, 0, 12 ), RPT_32 ( -54, 0, 12 ), - RPT_32 ( 55, 0, 12 ), RPT_32 ( -55, 0, 12 ), - RPT_32 ( 56, 0, 12 ), RPT_32 ( -56, 0, 12 ), - RPT_32 ( 57, 0, 12 ), RPT_32 ( -57, 0, 12 ), - RPT_32 ( 58, 0, 12 ), RPT_32 ( -58, 0, 12 ), - RPT_32 ( 59, 0, 12 ), RPT_32 ( -59, 0, 12 ), - RPT_32 ( 60, 0, 12 ), RPT_32 ( -60, 0, 12 ), - RPT_32 ( 61, 0, 12 ), RPT_32 ( -61, 0, 12 ), - RPT_32 ( 62, 0, 12 ), RPT_32 ( -62, 0, 12 ), - RPT_32 ( 63, 0, 12 ), RPT_32 ( -63, 0, 12 ), - RPT_32 ( 17, 1, 12 ), RPT_32 ( -17, 1, 12 ), - RPT_32 ( 18, 1, 12 ), RPT_32 ( -18, 1, 12 ), - RPT_32 ( 19, 1, 12 ), RPT_32 ( -19, 1, 12 ), - RPT_32 ( 20, 1, 12 ), RPT_32 ( -20, 1, 12 ), - RPT_32 ( 21, 1, 12 ), RPT_32 ( -21, 1, 12 ), - RPT_32 ( 22, 1, 12 ), RPT_32 ( -22, 1, 12 ), - RPT_32 ( 23, 1, 12 ), RPT_32 ( -23, 1, 12 ), - RPT_32 ( 24, 1, 12 ), RPT_32 ( -24, 1, 12 ), - RPT_32 ( 9, 2, 12 ), RPT_32 ( -9, 2, 12 ), - RPT_32 ( 10, 2, 12 ), RPT_32 ( -10, 2, 12 ), - RPT_32 ( 11, 2, 12 ), RPT_32 ( -11, 2, 12 ), - RPT_32 ( 12, 2, 12 ), RPT_32 ( -12, 2, 12 ), - RPT_32 ( 7, 3, 12 ), RPT_32 ( -7, 3, 12 ), - RPT_32 ( 8, 3, 12 ), RPT_32 ( -8, 3, 12 ), - RPT_32 ( 5, 4, 12 ), RPT_32 ( -5, 4, 12 ), - RPT_32 ( 6, 4, 12 ), RPT_32 ( -6, 4, 12 ), - RPT_32 ( 3, 5, 12 ), RPT_32 ( -3, 5, 12 ), - RPT_32 ( 4, 5, 12 ), RPT_32 ( -4, 5, 12 ), - RPT_32 ( 5, 5, 12 ), RPT_32 ( -5, 5, 12 ), - RPT_32 ( 6, 5, 12 ), RPT_32 ( -6, 5, 12 ), - RPT_32 ( 3, 6, 12 ), RPT_32 ( -3, 6, 12 ), - RPT_32 ( 4, 6, 12 ), RPT_32 ( -4, 6, 12 ), - RPT_32 ( 2, 7, 12 ), RPT_32 ( -2, 7, 12 ), - RPT_32 ( 2, 8, 12 ), RPT_32 ( -2, 8, 12 ), - RPT_32 ( 2, 9, 12 ), RPT_32 ( -2, 9, 12 ), - RPT_32 ( 2, 10, 12 ), RPT_32 ( -2, 10, 12 ), - RPT_32 ( 1, 13, 12 ), RPT_32 ( -1, 13, 12 ), - RPT_32 ( 1, 14, 12 ), RPT_32 ( -1, 14, 12 ), - { 0, 0, 17 }, { 0, 1, 17 }, { 0, 2, 17 }, { 0, 3, 17 }, - { 0, 4, 17 }, { 0, 5, 17 }, { 0, 6, 17 }, { 0, 7, 17 }, - { 0, 8, 17 }, { 0, 9, 17 }, { 0, 10, 17 }, { 0, 11, 17 }, - { 0, 12, 17 }, { 0, 13, 17 }, { 0, 14, 17 }, { 0, 15, 17 }, - { 0, 16, 17 }, { 0, 17, 17 }, { 0, 18, 17 }, { 0, 19, 17 }, - { 0, 20, 17 }, { 0, 21, 17 }, { 0, 22, 17 }, { 0, 23, 17 }, - { 0, 24, 17 }, { 0, 25, 17 }, { 0, 26, 17 }, { 0, 27, 17 }, - { 0, 28, 17 }, { 0, 29, 17 }, { 0, 30, 17 }, { 0, 31, 17 }, - { 0, 32, 17 }, { 0, 33, 17 }, { 0, 34, 17 }, { 0, 35, 17 }, - { 0, 36, 17 }, { 0, 37, 17 }, { 0, 38, 17 }, { 0, 39, 17 }, - { 0, 40, 17 }, { 0, 41, 17 }, { 0, 42, 17 }, { 0, 43, 17 }, - { 0, 44, 17 }, { 0, 45, 17 }, { 0, 46, 17 }, { 0, 47, 17 }, - { 0, 48, 17 }, { 0, 49, 17 }, { 0, 50, 17 }, { 0, 51, 17 }, - { 0, 52, 17 }, { 0, 53, 17 }, { 0, 54, 17 }, { 0, 55, 17 }, - { 0, 56, 17 }, { 0, 57, 17 }, { 0, 58, 17 }, { 0, 59, 17 }, - { 0, 60, 17 }, { 0, 61, 17 }, { 0, 62, 17 }, { 0, 63, 17 }, - RPT_16 ( 25, 1, 13 ), RPT_16 ( -25, 1, 13 ), - RPT_16 ( 26, 1, 13 ), RPT_16 ( -26, 1, 13 ), - RPT_16 ( 27, 1, 13 ), RPT_16 ( -27, 1, 13 ), - RPT_16 ( 28, 1, 13 ), RPT_16 ( -28, 1, 13 ), - RPT_16 ( 29, 1, 13 ), RPT_16 ( -29, 1, 13 ), - RPT_16 ( 30, 1, 13 ), RPT_16 ( -30, 1, 13 ), - RPT_16 ( 31, 1, 13 ), RPT_16 ( -31, 1, 13 ), - RPT_16 ( 32, 1, 13 ), RPT_16 ( -32, 1, 13 ), - RPT_16 ( 13, 2, 13 ), RPT_16 ( -13, 2, 13 ), - RPT_16 ( 14, 2, 13 ), RPT_16 ( -14, 2, 13 ), - RPT_16 ( 15, 2, 13 ), RPT_16 ( -15, 2, 13 ), - RPT_16 ( 16, 2, 13 ), RPT_16 ( -16, 2, 13 ), - RPT_16 ( 9, 3, 13 ), RPT_16 ( -9, 3, 13 ), - RPT_16 ( 10, 3, 13 ), RPT_16 ( -10, 3, 13 ), - RPT_16 ( 11, 3, 13 ), RPT_16 ( -11, 3, 13 ), - RPT_16 ( 7, 4, 13 ), RPT_16 ( -7, 4, 13 ), - RPT_16 ( 3, 7, 13 ), RPT_16 ( -3, 7, 13 ), - RPT_16 ( 4, 7, 13 ), RPT_16 ( -4, 7, 13 ), - RPT_16 ( 3, 8, 13 ), RPT_16 ( -3, 8, 13 ), - RPT_16 ( 4, 8, 13 ), RPT_16 ( -4, 8, 13 ), - RPT_16 ( 3, 9, 13 ), RPT_16 ( -3, 9, 13 ), - RPT_16 ( 2, 11, 13 ), RPT_16 ( -2, 11, 13 ), - RPT_16 ( 2, 12, 13 ), RPT_16 ( -2, 12, 13 ), - RPT_32 ( 0, 14, 12 ), -}; - -static const HQXLUT ac16_lut[] = { - RPT_256 ( 1, 0, 3 ), RPT_256 ( -1, 0, 3 ), - RPT_128 ( 2, 0, 4 ), RPT_128 ( -2, 0, 4 ), - RPT_64 ( 3, 0, 5 ), RPT_64 ( -3, 0, 5 ), - RPT_64 ( 4, 0, 5 ), RPT_64 ( -4, 0, 5 ), - RPT_64 ( 1, 1, 5 ), RPT_64 ( -1, 1, 5 ), - RPT_128 ( 0, 64, 4 ), RPT_32 ( 5, 0, 6 ), - RPT_32 ( -5, 0, 6 ), RPT_32 ( 6, 0, 6 ), - RPT_32 ( -6, 0, 6 ), RPT_32 ( 2, 1, 6 ), - RPT_32 ( -2, 1, 6 ), RPT_32 ( 1, 2, 6 ), - RPT_32 ( -1, 2, 6 ), RPT_16 ( 7, 0, 7 ), - RPT_16 ( -7, 0, 7 ), RPT_16 ( 8, 0, 7 ), - RPT_16 ( -8, 0, 7 ), RPT_16 ( 9, 0, 7 ), - RPT_16 ( -9, 0, 7 ), RPT_16 ( 3, 1, 7 ), - RPT_16 ( -3, 1, 7 ), RPT_16 ( 1, 3, 7 ), - RPT_16 ( -1, 3, 7 ), RPT_16 ( 1, 4, 7 ), - RPT_16 ( -1, 4, 7 ), RPT_8 ( 10, 0, 8 ), - RPT_8 ( -10, 0, 8 ), RPT_8 ( 11, 0, 8 ), - RPT_8 ( -11, 0, 8 ), RPT_8 ( 12, 0, 8 ), - RPT_8 ( -12, 0, 8 ), RPT_8 ( 4, 1, 8 ), - RPT_8 ( -4, 1, 8 ), RPT_8 ( 2, 2, 8 ), - RPT_8 ( -2, 2, 8 ), RPT_8 ( 1, 5, 8 ), - RPT_8 ( -1, 5, 8 ), RPT_8 ( 1, 6, 8 ), - RPT_8 ( -1, 6, 8 ), RPT_4 ( 13, 0, 9 ), - RPT_4 ( -13, 0, 9 ), RPT_4 ( 14, 0, 9 ), - RPT_4 ( -14, 0, 9 ), RPT_4 ( 15, 0, 9 ), - RPT_4 ( -15, 0, 9 ), RPT_4 ( 16, 0, 9 ), - RPT_4 ( -16, 0, 9 ), RPT_4 ( 17, 0, 9 ), - RPT_4 ( -17, 0, 9 ), RPT_4 ( 5, 1, 9 ), - RPT_4 ( -5, 1, 9 ), RPT_4 ( 2, 3, 9 ), - RPT_4 ( -2, 3, 9 ), RPT_4 ( 1, 7, 9 ), - RPT_4 ( -1, 7, 9 ), RPT_4 ( 1, 8, 9 ), - RPT_4 ( -1, 8, 9 ), RPT_4 ( 1, 9, 9 ), - RPT_4 ( -1, 9, 9 ), RPT_4 ( 1, 10, 9 ), - RPT_4 ( -1, 10, 9 ), RPT_4 ( 0, 0, 9 ), - RPT_2 ( 18, 0, 10 ), RPT_2 ( -18, 0, 10 ), - RPT_2 ( 19, 0, 10 ), RPT_2 ( -19, 0, 10 ), - RPT_2 ( 20, 0, 10 ), RPT_2 ( -20, 0, 10 ), - RPT_2 ( 21, 0, 10 ), RPT_2 ( -21, 0, 10 ), - RPT_2 ( 22, 0, 10 ), RPT_2 ( -22, 0, 10 ), - RPT_2 ( 6, 1, 10 ), RPT_2 ( -6, 1, 10 ), - RPT_2 ( 7, 1, 10 ), RPT_2 ( -7, 1, 10 ), - RPT_2 ( 3, 2, 10 ), RPT_2 ( -3, 2, 10 ), - RPT_2 ( 2, 4, 10 ), RPT_2 ( -2, 4, 10 ), - RPT_2 ( 2, 5, 10 ), RPT_2 ( -2, 5, 10 ), - RPT_2 ( 1, 11, 10 ), RPT_2 ( -1, 11, 10 ), - RPT_2 ( 1, 12, 10 ), RPT_2 ( -1, 12, 10 ), - RPT_2 ( 1, 13, 10 ), RPT_2 ( -1, 13, 10 ), - { 2048, 0, -1 }, { 2112, 0, -1 }, { 2176, 0, -1 }, { 2240, 0, -1 }, - { 2304, 0, -1 }, { 2368, 0, -1 }, { 2432, 0, -1 }, { 2496, 0, -1 }, - { 23, 0, 11 }, { -23, 0, 11 }, { 24, 0, 11 }, { -24, 0, 11 }, - { 25, 0, 11 }, { -25, 0, 11 }, { 26, 0, 11 }, { -26, 0, 11 }, - { 27, 0, 11 }, { -27, 0, 11 }, { 28, 0, 11 }, { -28, 0, 11 }, - { 8, 1, 11 }, { -8, 1, 11 }, { 9, 1, 11 }, { -9, 1, 11 }, - { 4, 2, 11 }, { -4, 2, 11 }, { 3, 3, 11 }, { -3, 3, 11 }, - { 3, 4, 11 }, { -3, 4, 11 }, { 2, 6, 11 }, { -2, 6, 11 }, - { 2, 7, 11 }, { -2, 7, 11 }, { 2560, 0, -1 }, { 2624, 0, -1 }, - { 2688, 0, -1 }, { 2752, 0, -1 }, { 2816, 0, -1 }, { 2880, 0, -1 }, - { 2944, 0, -1 }, { 0, 1, 11 }, { 3008, 0, -1 }, { 3072, 0, -1 }, - { 3136, 0, -1 }, { 0, 2, 11 }, { 3200, 0, -1 }, { 0, 3, 11 }, - { 3264, 0, -1 }, { 3328, 0, -1 }, { 3392, 0, -1 }, { 3456, 0, -1 }, - { 3520, 0, -1 }, { 3584, 0, -1 }, { 3648, 0, -1 }, { 3712, 0, -1 }, - { 3776, 0, -1 }, { 3840, 0, -1 }, { 3904, 0, -1 }, { 3968, 0, -1 }, - { 4032, 0, -1 }, { 4096, 0, -1 }, { 4160, 0, -1 }, { 4224, 0, -1 }, - RPT_4 ( 0, 0, 15 ), RPT_4 ( 0, 1, 15 ), - RPT_4 ( 0, 2, 15 ), RPT_4 ( 0, 3, 15 ), - RPT_4 ( 0, 4, 15 ), RPT_4 ( 0, 5, 15 ), - RPT_4 ( 0, 6, 15 ), RPT_4 ( 0, 7, 15 ), - RPT_4 ( 0, 8, 15 ), RPT_4 ( 0, 9, 15 ), - RPT_4 ( 0, 10, 15 ), RPT_4 ( 0, 11, 15 ), - RPT_4 ( 0, 12, 15 ), RPT_4 ( 0, 13, 15 ), - RPT_4 ( 0, 14, 15 ), RPT_4 ( 0, 15, 15 ), - RPT_4 ( 0, 16, 15 ), RPT_4 ( 0, 17, 15 ), - RPT_4 ( 0, 18, 15 ), RPT_4 ( 0, 19, 15 ), - RPT_4 ( 0, 20, 15 ), RPT_4 ( 0, 21, 15 ), - RPT_4 ( 0, 22, 15 ), RPT_4 ( 0, 23, 15 ), - RPT_4 ( 0, 24, 15 ), RPT_4 ( 0, 25, 15 ), - RPT_4 ( 0, 26, 15 ), RPT_4 ( 0, 27, 15 ), - RPT_4 ( 0, 28, 15 ), RPT_4 ( 0, 29, 15 ), - RPT_4 ( 0, 30, 15 ), RPT_4 ( 0, 31, 15 ), - RPT_4 ( 0, 32, 15 ), RPT_4 ( 0, 33, 15 ), - RPT_4 ( 0, 34, 15 ), RPT_4 ( 0, 35, 15 ), - RPT_4 ( 0, 36, 15 ), RPT_4 ( 0, 37, 15 ), - RPT_4 ( 0, 38, 15 ), RPT_4 ( 0, 39, 15 ), - RPT_4 ( 0, 40, 15 ), RPT_4 ( 0, 41, 15 ), - RPT_4 ( 0, 42, 15 ), RPT_4 ( 0, 43, 15 ), - RPT_4 ( 0, 44, 15 ), RPT_4 ( 0, 45, 15 ), - RPT_4 ( 0, 46, 15 ), RPT_4 ( 0, 47, 15 ), - RPT_4 ( 0, 48, 15 ), RPT_4 ( 0, 49, 15 ), - RPT_4 ( 0, 50, 15 ), RPT_4 ( 0, 51, 15 ), - RPT_4 ( 0, 52, 15 ), RPT_4 ( 0, 53, 15 ), - RPT_4 ( 0, 54, 15 ), RPT_4 ( 0, 55, 15 ), - RPT_4 ( 0, 56, 15 ), RPT_4 ( 0, 57, 15 ), - RPT_4 ( 0, 58, 15 ), RPT_4 ( 0, 59, 15 ), - RPT_4 ( 0, 60, 15 ), RPT_4 ( 0, 61, 15 ), - RPT_4 ( 0, 62, 15 ), RPT_4 ( 0, 63, 15 ), - RPT_2 ( 0, 0, 16 ), { 1, 0, 17 }, { -1, 0, 17 }, - { 2, 0, 17 }, { -2, 0, 17 }, { 3, 0, 17 }, { -3, 0, 17 }, - { 4, 0, 17 }, { -4, 0, 17 }, { 5, 0, 17 }, { -5, 0, 17 }, - { 6, 0, 17 }, { -6, 0, 17 }, { 7, 0, 17 }, { -7, 0, 17 }, - { 8, 0, 17 }, { -8, 0, 17 }, { 9, 0, 17 }, { -9, 0, 17 }, - { 10, 0, 17 }, { -10, 0, 17 }, { 11, 0, 17 }, { -11, 0, 17 }, - { 12, 0, 17 }, { -12, 0, 17 }, { 13, 0, 17 }, { -13, 0, 17 }, - { 14, 0, 17 }, { -14, 0, 17 }, { 15, 0, 17 }, { -15, 0, 17 }, - { 16, 0, 17 }, { -16, 0, 17 }, { 17, 0, 17 }, { -17, 0, 17 }, - { 18, 0, 17 }, { -18, 0, 17 }, { 19, 0, 17 }, { -19, 0, 17 }, - { 20, 0, 17 }, { -20, 0, 17 }, { 21, 0, 17 }, { -21, 0, 17 }, - { 22, 0, 17 }, { -22, 0, 17 }, { 23, 0, 17 }, { -23, 0, 17 }, - { 24, 0, 17 }, { -24, 0, 17 }, { 25, 0, 17 }, { -25, 0, 17 }, - { 26, 0, 17 }, { -26, 0, 17 }, { 27, 0, 17 }, { -27, 0, 17 }, - { 28, 0, 17 }, { -28, 0, 17 }, { 29, 0, 17 }, { -29, 0, 17 }, - { 30, 0, 17 }, { -30, 0, 17 }, { 31, 0, 17 }, { -31, 0, 17 }, - { 32, 0, 17 }, { -32, 0, 17 }, { 33, 0, 17 }, { -33, 0, 17 }, - { 34, 0, 17 }, { -34, 0, 17 }, { 35, 0, 17 }, { -35, 0, 17 }, - { 36, 0, 17 }, { -36, 0, 17 }, { 37, 0, 17 }, { -37, 0, 17 }, - { 38, 0, 17 }, { -38, 0, 17 }, { 39, 0, 17 }, { -39, 0, 17 }, - { 40, 0, 17 }, { -40, 0, 17 }, { 41, 0, 17 }, { -41, 0, 17 }, - { 42, 0, 17 }, { -42, 0, 17 }, { 43, 0, 17 }, { -43, 0, 17 }, - { 44, 0, 17 }, { -44, 0, 17 }, { 45, 0, 17 }, { -45, 0, 17 }, - { 46, 0, 17 }, { -46, 0, 17 }, { 47, 0, 17 }, { -47, 0, 17 }, - { 48, 0, 17 }, { -48, 0, 17 }, { 49, 0, 17 }, { -49, 0, 17 }, - { 50, 0, 17 }, { -50, 0, 17 }, { 51, 0, 17 }, { -51, 0, 17 }, - { 52, 0, 17 }, { -52, 0, 17 }, { 53, 0, 17 }, { -53, 0, 17 }, - { 54, 0, 17 }, { -54, 0, 17 }, { 55, 0, 17 }, { -55, 0, 17 }, - { 56, 0, 17 }, { -56, 0, 17 }, { 57, 0, 17 }, { -57, 0, 17 }, - { 58, 0, 17 }, { -58, 0, 17 }, { 59, 0, 17 }, { -59, 0, 17 }, - { 60, 0, 17 }, { -60, 0, 17 }, { 61, 0, 17 }, { -61, 0, 17 }, - { 62, 0, 17 }, { -62, 0, 17 }, { 63, 0, 17 }, { -63, 0, 17 }, - { 64, 0, 17 }, { -64, 0, 17 }, { 65, 0, 17 }, { -65, 0, 17 }, - { 66, 0, 17 }, { -66, 0, 17 }, { 67, 0, 17 }, { -67, 0, 17 }, - { 68, 0, 17 }, { -68, 0, 17 }, { 69, 0, 17 }, { -69, 0, 17 }, - { 70, 0, 17 }, { -70, 0, 17 }, { 71, 0, 17 }, { -71, 0, 17 }, - { 72, 0, 17 }, { -72, 0, 17 }, { 73, 0, 17 }, { -73, 0, 17 }, - { 74, 0, 17 }, { -74, 0, 17 }, { 75, 0, 17 }, { -75, 0, 17 }, - { 76, 0, 17 }, { -76, 0, 17 }, { 77, 0, 17 }, { -77, 0, 17 }, - { 78, 0, 17 }, { -78, 0, 17 }, { 79, 0, 17 }, { -79, 0, 17 }, - { 80, 0, 17 }, { -80, 0, 17 }, { 81, 0, 17 }, { -81, 0, 17 }, - { 82, 0, 17 }, { -82, 0, 17 }, { 83, 0, 17 }, { -83, 0, 17 }, - { 84, 0, 17 }, { -84, 0, 17 }, { 85, 0, 17 }, { -85, 0, 17 }, - { 86, 0, 17 }, { -86, 0, 17 }, { 87, 0, 17 }, { -87, 0, 17 }, - { 88, 0, 17 }, { -88, 0, 17 }, { 89, 0, 17 }, { -89, 0, 17 }, - { 90, 0, 17 }, { -90, 0, 17 }, { 91, 0, 17 }, { -91, 0, 17 }, - { 92, 0, 17 }, { -92, 0, 17 }, { 93, 0, 17 }, { -93, 0, 17 }, - { 94, 0, 17 }, { -94, 0, 17 }, { 95, 0, 17 }, { -95, 0, 17 }, - { 96, 0, 17 }, { -96, 0, 17 }, { 97, 0, 17 }, { -97, 0, 17 }, - { 98, 0, 17 }, { -98, 0, 17 }, { 99, 0, 17 }, { -99, 0, 17 }, - { 100, 0, 17 }, { -100, 0, 17 }, { 101, 0, 17 }, { -101, 0, 17 }, - { 102, 0, 17 }, { -102, 0, 17 }, { 103, 0, 17 }, { -103, 0, 17 }, - { 104, 0, 17 }, { -104, 0, 17 }, { 105, 0, 17 }, { -105, 0, 17 }, - { 106, 0, 17 }, { -106, 0, 17 }, { 107, 0, 17 }, { -107, 0, 17 }, - { 108, 0, 17 }, { -108, 0, 17 }, { 109, 0, 17 }, { -109, 0, 17 }, - { 110, 0, 17 }, { -110, 0, 17 }, { 111, 0, 17 }, { -111, 0, 17 }, - { 112, 0, 17 }, { -112, 0, 17 }, { 113, 0, 17 }, { -113, 0, 17 }, - { 114, 0, 17 }, { -114, 0, 17 }, { 115, 0, 17 }, { -115, 0, 17 }, - { 116, 0, 17 }, { -116, 0, 17 }, { 117, 0, 17 }, { -117, 0, 17 }, - { 118, 0, 17 }, { -118, 0, 17 }, { 119, 0, 17 }, { -119, 0, 17 }, - { 120, 0, 17 }, { -120, 0, 17 }, { 121, 0, 17 }, { -121, 0, 17 }, - { 122, 0, 17 }, { -122, 0, 17 }, { 123, 0, 17 }, { -123, 0, 17 }, - { 124, 0, 17 }, { -124, 0, 17 }, { 125, 0, 17 }, { -125, 0, 17 }, - { 126, 0, 17 }, { -126, 0, 17 }, { 127, 0, 17 }, { -127, 0, 17 }, - RPT_32 ( 29, 0, 12 ), RPT_32 ( -29, 0, 12 ), - RPT_32 ( 30, 0, 12 ), RPT_32 ( -30, 0, 12 ), - RPT_32 ( 31, 0, 12 ), RPT_32 ( -31, 0, 12 ), - RPT_32 ( 32, 0, 12 ), RPT_32 ( -32, 0, 12 ), - RPT_32 ( 33, 0, 12 ), RPT_32 ( -33, 0, 12 ), - RPT_32 ( 34, 0, 12 ), RPT_32 ( -34, 0, 12 ), - RPT_32 ( 35, 0, 12 ), RPT_32 ( -35, 0, 12 ), - RPT_32 ( 10, 1, 12 ), RPT_32 ( -10, 1, 12 ), - RPT_32 ( 11, 1, 12 ), RPT_32 ( -11, 1, 12 ), - RPT_32 ( 12, 1, 12 ), RPT_32 ( -12, 1, 12 ), - RPT_32 ( 5, 2, 12 ), RPT_32 ( -5, 2, 12 ), - RPT_32 ( 4, 3, 12 ), RPT_32 ( -4, 3, 12 ), - RPT_32 ( 3, 5, 12 ), RPT_32 ( -3, 5, 12 ), - RPT_32 ( 2, 8, 12 ), RPT_32 ( -2, 8, 12 ), - RPT_32 ( 2, 9, 12 ), RPT_32 ( -2, 9, 12 ), - RPT_32 ( 1, 14, 12 ), RPT_32 ( -1, 14, 12 ), - RPT_32 ( 1, 15, 12 ), RPT_32 ( -1, 15, 12 ), - RPT_16 ( 36, 0, 13 ), RPT_16 ( -36, 0, 13 ), - RPT_16 ( 37, 0, 13 ), RPT_16 ( -37, 0, 13 ), - RPT_16 ( 38, 0, 13 ), RPT_16 ( -38, 0, 13 ), - RPT_16 ( 39, 0, 13 ), RPT_16 ( -39, 0, 13 ), - RPT_16 ( 40, 0, 13 ), RPT_16 ( -40, 0, 13 ), - RPT_16 ( 13, 1, 13 ), RPT_16 ( -13, 1, 13 ), - RPT_16 ( 14, 1, 13 ), RPT_16 ( -14, 1, 13 ), - RPT_16 ( 15, 1, 13 ), RPT_16 ( -15, 1, 13 ), - RPT_16 ( 6, 2, 13 ), RPT_16 ( -6, 2, 13 ), - RPT_16 ( 7, 2, 13 ), RPT_16 ( -7, 2, 13 ), - RPT_16 ( 5, 3, 13 ), RPT_16 ( -5, 3, 13 ), - RPT_32 ( 0, 4, 12 ), RPT_16 ( 4, 4, 13 ), - RPT_16 ( -4, 4, 13 ), RPT_32 ( 0, 5, 12 ), - RPT_32 ( 0, 6, 12 ), RPT_16 ( 3, 6, 13 ), - RPT_16 ( -3, 6, 13 ), RPT_32 ( 0, 7, 12 ), - RPT_16 ( 3, 7, 13 ), RPT_16 ( -3, 7, 13 ), - RPT_16 ( 2, 10, 13 ), RPT_16 ( -2, 10, 13 ), - RPT_16 ( 1, 16, 13 ), RPT_16 ( -1, 16, 13 ), -}; - -static const HQXLUT ac32_lut[] = { - RPT_256 ( 1, 0, 3 ), RPT_256 ( -1, 0, 3 ), - RPT_128 ( 2, 0, 4 ), RPT_128 ( -2, 0, 4 ), - RPT_256 ( 0, 64, 3 ), RPT_64 ( 3, 0, 5 ), - RPT_64 ( -3, 0, 5 ), RPT_64 ( 1, 1, 5 ), - RPT_64 ( -1, 1, 5 ), RPT_32 ( 4, 0, 6 ), - RPT_32 ( -4, 0, 6 ), RPT_32 ( 5, 0, 6 ), - RPT_32 ( -5, 0, 6 ), RPT_32 ( 2, 1, 6 ), - RPT_32 ( -2, 1, 6 ), RPT_32 ( 1, 2, 6 ), - RPT_32 ( -1, 2, 6 ), RPT_32 ( 1, 3, 6 ), - RPT_32 ( -1, 3, 6 ), RPT_16 ( 6, 0, 7 ), - RPT_16 ( -6, 0, 7 ), RPT_16 ( 7, 0, 7 ), - RPT_16 ( -7, 0, 7 ), RPT_16 ( 3, 1, 7 ), - RPT_16 ( -3, 1, 7 ), RPT_16 ( 1, 4, 7 ), - RPT_16 ( -1, 4, 7 ), RPT_16 ( 1, 5, 7 ), - RPT_16 ( -1, 5, 7 ), RPT_8 ( 8, 0, 8 ), - RPT_8 ( -8, 0, 8 ), RPT_8 ( 9, 0, 8 ), - RPT_8 ( -9, 0, 8 ), RPT_8 ( 10, 0, 8 ), - RPT_8 ( -10, 0, 8 ), RPT_8 ( 4, 1, 8 ), - RPT_8 ( -4, 1, 8 ), RPT_8 ( 2, 2, 8 ), - RPT_8 ( -2, 2, 8 ), RPT_8 ( 1, 6, 8 ), - RPT_8 ( -1, 6, 8 ), RPT_8 ( 1, 7, 8 ), - RPT_8 ( -1, 7, 8 ), RPT_8 ( 1, 8, 8 ), - RPT_8 ( -1, 8, 8 ), RPT_4 ( 11, 0, 9 ), - RPT_4 ( -11, 0, 9 ), RPT_4 ( 12, 0, 9 ), - RPT_4 ( -12, 0, 9 ), RPT_4 ( 13, 0, 9 ), - RPT_4 ( -13, 0, 9 ), RPT_4 ( 5, 1, 9 ), - RPT_4 ( -5, 1, 9 ), RPT_4 ( 2, 3, 9 ), - RPT_4 ( -2, 3, 9 ), RPT_4 ( 1, 9, 9 ), - RPT_4 ( -1, 9, 9 ), RPT_4 ( 1, 10, 9 ), - RPT_4 ( -1, 10, 9 ), RPT_2 ( 14, 0, 10 ), - RPT_2 ( -14, 0, 10 ), RPT_2 ( 15, 0, 10 ), - RPT_2 ( -15, 0, 10 ), RPT_2 ( 16, 0, 10 ), - RPT_2 ( -16, 0, 10 ), RPT_2 ( 6, 1, 10 ), - RPT_2 ( -6, 1, 10 ), RPT_2 ( 7, 1, 10 ), - RPT_2 ( -7, 1, 10 ), RPT_2 ( 3, 2, 10 ), - RPT_2 ( -3, 2, 10 ), RPT_2 ( 3, 3, 10 ), - RPT_2 ( -3, 3, 10 ), RPT_2 ( 2, 4, 10 ), - RPT_2 ( -2, 4, 10 ), RPT_2 ( 2, 5, 10 ), - RPT_2 ( -2, 5, 10 ), RPT_2 ( 1, 11, 10 ), - RPT_2 ( -1, 11, 10 ), RPT_2 ( 1, 12, 10 ), - RPT_2 ( -1, 12, 10 ), RPT_2 ( 1, 13, 10 ), - RPT_2 ( -1, 13, 10 ), { 2048, 0, -1 }, { 2112, 0, -1 }, - { 2176, 0, -1 }, { 2240, 0, -1 }, RPT_2 ( 0, 0, 10 ), - { 17, 0, 11 }, { -17, 0, 11 }, { 18, 0, 11 }, { -18, 0, 11 }, - { 19, 0, 11 }, { -19, 0, 11 }, { 20, 0, 11 }, { -20, 0, 11 }, - { 8, 1, 11 }, { -8, 1, 11 }, { 9, 1, 11 }, { -9, 1, 11 }, - { 4, 2, 11 }, { -4, 2, 11 }, { 3, 4, 11 }, { -3, 4, 11 }, - { 2, 6, 11 }, { -2, 6, 11 }, { 2, 7, 11 }, { -2, 7, 11 }, - { 2, 8, 11 }, { -2, 8, 11 }, { 1, 14, 11 }, { -1, 14, 11 }, - { 2304, 0, -1 }, { 2368, 0, -1 }, { 2432, 0, -1 }, { 2496, 0, -1 }, - { 2560, 0, -1 }, { 0, 1, 11 }, { 2624, 0, -1 }, { 2688, 0, -1 }, - { 0, 2, 11 }, { 2752, 0, -1 }, { 2816, 0, -1 }, { 0, 3, 11 }, - { 2880, 0, -1 }, { 0, 4, 11 }, { 2944, 0, -1 }, { 3008, 0, -1 }, - { 3072, 0, -1 }, { 3136, 0, -1 }, { 3200, 0, -1 }, { 3264, 0, -1 }, - { 3328, 0, -1 }, { 3392, 0, -1 }, { 3456, 0, -1 }, { 3520, 0, -1 }, - { 3584, 0, -1 }, { 3648, 0, -1 }, RPT_4 ( 0, 0, 15 ), - RPT_4 ( 0, 1, 15 ), RPT_4 ( 0, 2, 15 ), - RPT_4 ( 0, 3, 15 ), RPT_4 ( 0, 4, 15 ), - RPT_4 ( 0, 5, 15 ), RPT_4 ( 0, 6, 15 ), - RPT_4 ( 0, 7, 15 ), RPT_4 ( 0, 8, 15 ), - RPT_4 ( 0, 9, 15 ), RPT_4 ( 0, 10, 15 ), - RPT_4 ( 0, 11, 15 ), RPT_4 ( 0, 12, 15 ), - RPT_4 ( 0, 13, 15 ), RPT_4 ( 0, 14, 15 ), - RPT_4 ( 0, 15, 15 ), RPT_4 ( 0, 16, 15 ), - RPT_4 ( 0, 17, 15 ), RPT_4 ( 0, 18, 15 ), - RPT_4 ( 0, 19, 15 ), RPT_4 ( 0, 20, 15 ), - RPT_4 ( 0, 21, 15 ), RPT_4 ( 0, 22, 15 ), - RPT_4 ( 0, 23, 15 ), RPT_4 ( 0, 24, 15 ), - RPT_4 ( 0, 25, 15 ), RPT_4 ( 0, 26, 15 ), - RPT_4 ( 0, 27, 15 ), RPT_4 ( 0, 28, 15 ), - RPT_4 ( 0, 29, 15 ), RPT_4 ( 0, 30, 15 ), - RPT_4 ( 0, 31, 15 ), RPT_4 ( 0, 32, 15 ), - RPT_4 ( 0, 33, 15 ), RPT_4 ( 0, 34, 15 ), - RPT_4 ( 0, 35, 15 ), RPT_4 ( 0, 36, 15 ), - RPT_4 ( 0, 37, 15 ), RPT_4 ( 0, 38, 15 ), - RPT_4 ( 0, 39, 15 ), RPT_4 ( 0, 40, 15 ), - RPT_4 ( 0, 41, 15 ), RPT_4 ( 0, 42, 15 ), - RPT_4 ( 0, 43, 15 ), RPT_4 ( 0, 44, 15 ), - RPT_4 ( 0, 45, 15 ), RPT_4 ( 0, 46, 15 ), - RPT_4 ( 0, 47, 15 ), RPT_4 ( 0, 48, 15 ), - RPT_4 ( 0, 49, 15 ), RPT_4 ( 0, 50, 15 ), - RPT_4 ( 0, 51, 15 ), RPT_4 ( 0, 52, 15 ), - RPT_4 ( 0, 53, 15 ), RPT_4 ( 0, 54, 15 ), - RPT_4 ( 0, 55, 15 ), RPT_4 ( 0, 56, 15 ), - RPT_4 ( 0, 57, 15 ), RPT_4 ( 0, 58, 15 ), - RPT_4 ( 0, 59, 15 ), RPT_4 ( 0, 60, 15 ), - RPT_4 ( 0, 61, 15 ), RPT_4 ( 0, 62, 15 ), - RPT_4 ( 0, 63, 15 ), RPT_2 ( 0, 0, 16 ), - { 1, 0, 17 }, { -1, 0, 17 }, { 2, 0, 17 }, { -2, 0, 17 }, - { 3, 0, 17 }, { -3, 0, 17 }, { 4, 0, 17 }, { -4, 0, 17 }, - { 5, 0, 17 }, { -5, 0, 17 }, { 6, 0, 17 }, { -6, 0, 17 }, - { 7, 0, 17 }, { -7, 0, 17 }, { 8, 0, 17 }, { -8, 0, 17 }, - { 9, 0, 17 }, { -9, 0, 17 }, { 10, 0, 17 }, { -10, 0, 17 }, - { 11, 0, 17 }, { -11, 0, 17 }, { 12, 0, 17 }, { -12, 0, 17 }, - { 13, 0, 17 }, { -13, 0, 17 }, { 14, 0, 17 }, { -14, 0, 17 }, - { 15, 0, 17 }, { -15, 0, 17 }, { 16, 0, 17 }, { -16, 0, 17 }, - { 17, 0, 17 }, { -17, 0, 17 }, { 18, 0, 17 }, { -18, 0, 17 }, - { 19, 0, 17 }, { -19, 0, 17 }, { 20, 0, 17 }, { -20, 0, 17 }, - { 21, 0, 17 }, { -21, 0, 17 }, { 22, 0, 17 }, { -22, 0, 17 }, - { 23, 0, 17 }, { -23, 0, 17 }, { 24, 0, 17 }, { -24, 0, 17 }, - { 25, 0, 17 }, { -25, 0, 17 }, { 26, 0, 17 }, { -26, 0, 17 }, - { 27, 0, 17 }, { -27, 0, 17 }, { 28, 0, 17 }, { -28, 0, 17 }, - { 29, 0, 17 }, { -29, 0, 17 }, { 30, 0, 17 }, { -30, 0, 17 }, - { 31, 0, 17 }, { -31, 0, 17 }, { 32, 0, 17 }, { -32, 0, 17 }, - { 33, 0, 17 }, { -33, 0, 17 }, { 34, 0, 17 }, { -34, 0, 17 }, - { 35, 0, 17 }, { -35, 0, 17 }, { 36, 0, 17 }, { -36, 0, 17 }, - { 37, 0, 17 }, { -37, 0, 17 }, { 38, 0, 17 }, { -38, 0, 17 }, - { 39, 0, 17 }, { -39, 0, 17 }, { 40, 0, 17 }, { -40, 0, 17 }, - { 41, 0, 17 }, { -41, 0, 17 }, { 42, 0, 17 }, { -42, 0, 17 }, - { 43, 0, 17 }, { -43, 0, 17 }, { 44, 0, 17 }, { -44, 0, 17 }, - { 45, 0, 17 }, { -45, 0, 17 }, { 46, 0, 17 }, { -46, 0, 17 }, - { 47, 0, 17 }, { -47, 0, 17 }, { 48, 0, 17 }, { -48, 0, 17 }, - { 49, 0, 17 }, { -49, 0, 17 }, { 50, 0, 17 }, { -50, 0, 17 }, - { 51, 0, 17 }, { -51, 0, 17 }, { 52, 0, 17 }, { -52, 0, 17 }, - { 53, 0, 17 }, { -53, 0, 17 }, { 54, 0, 17 }, { -54, 0, 17 }, - { 55, 0, 17 }, { -55, 0, 17 }, { 56, 0, 17 }, { -56, 0, 17 }, - { 57, 0, 17 }, { -57, 0, 17 }, { 58, 0, 17 }, { -58, 0, 17 }, - { 59, 0, 17 }, { -59, 0, 17 }, { 60, 0, 17 }, { -60, 0, 17 }, - { 61, 0, 17 }, { -61, 0, 17 }, { 62, 0, 17 }, { -62, 0, 17 }, - { 63, 0, 17 }, { -63, 0, 17 }, RPT_32 ( 21, 0, 12 ), - RPT_32 ( -21, 0, 12 ), RPT_32 ( 22, 0, 12 ), - RPT_32 ( -22, 0, 12 ), RPT_32 ( 23, 0, 12 ), - RPT_32 ( -23, 0, 12 ), RPT_32 ( 10, 1, 12 ), - RPT_32 ( -10, 1, 12 ), RPT_32 ( 11, 1, 12 ), - RPT_32 ( -11, 1, 12 ), RPT_32 ( 5, 2, 12 ), - RPT_32 ( -5, 2, 12 ), RPT_32 ( 6, 2, 12 ), - RPT_32 ( -6, 2, 12 ), RPT_32 ( 4, 3, 12 ), - RPT_32 ( -4, 3, 12 ), RPT_32 ( 3, 5, 12 ), - RPT_32 ( -3, 5, 12 ), RPT_32 ( 3, 6, 12 ), - RPT_32 ( -3, 6, 12 ), RPT_32 ( 2, 9, 12 ), - RPT_32 ( -2, 9, 12 ), RPT_32 ( 1, 15, 12 ), - RPT_32 ( -1, 15, 12 ), RPT_16 ( 24, 0, 13 ), - RPT_16 ( -24, 0, 13 ), RPT_16 ( 25, 0, 13 ), - RPT_16 ( -25, 0, 13 ), RPT_16 ( 26, 0, 13 ), - RPT_16 ( -26, 0, 13 ), RPT_16 ( 12, 1, 13 ), - RPT_16 ( -12, 1, 13 ), RPT_16 ( 13, 1, 13 ), - RPT_16 ( -13, 1, 13 ), RPT_16 ( 5, 3, 13 ), - RPT_16 ( -5, 3, 13 ), RPT_16 ( 4, 4, 13 ), - RPT_16 ( -4, 4, 13 ), RPT_32 ( 0, 5, 12 ), - RPT_16 ( 4, 5, 13 ), RPT_16 ( -4, 5, 13 ), - RPT_32 ( 0, 6, 12 ), RPT_32 ( 0, 7, 12 ), - RPT_16 ( 3, 7, 13 ), RPT_16 ( -3, 7, 13 ), - RPT_32 ( 0, 8, 12 ), RPT_16 ( 3, 8, 13 ), - RPT_16 ( -3, 8, 13 ), RPT_32 ( 0, 9, 12 ), - RPT_16 ( 1, 16, 13 ), RPT_16 ( -1, 16, 13 ), -}; - -static const HQXLUT ac64_lut[] = { - RPT_512 ( 1, 0, 3 ), RPT_512 ( -1, 0, 3 ), - RPT_1024( 0, 64, 2 ), RPT_256 ( 2, 0, 4 ), - RPT_256 ( -2, 0, 4 ), RPT_128 ( 3, 0, 5 ), - RPT_128 ( -3, 0, 5 ), RPT_128 ( 1, 1, 5 ), - RPT_128 ( -1, 1, 5 ), RPT_64 ( 4, 0, 6 ), - RPT_64 ( -4, 0, 6 ), RPT_64 ( 2, 1, 6 ), - RPT_64 ( -2, 1, 6 ), RPT_64 ( 1, 2, 6 ), - RPT_64 ( -1, 2, 6 ), RPT_32 ( 5, 0, 7 ), - RPT_32 ( -5, 0, 7 ), RPT_32 ( 1, 3, 7 ), - RPT_32 ( -1, 3, 7 ), RPT_32 ( 1, 4, 7 ), - RPT_32 ( -1, 4, 7 ), RPT_16 ( 6, 0, 8 ), - RPT_16 ( -6, 0, 8 ), RPT_16 ( 3, 1, 8 ), - RPT_16 ( -3, 1, 8 ), RPT_16 ( 2, 2, 8 ), - RPT_16 ( -2, 2, 8 ), RPT_16 ( 1, 5, 8 ), - RPT_16 ( -1, 5, 8 ), RPT_16 ( 1, 6, 8 ), - RPT_16 ( -1, 6, 8 ), RPT_16 ( 1, 7, 8 ), - RPT_16 ( -1, 7, 8 ), RPT_8 ( 7, 0, 9 ), - RPT_8 ( -7, 0, 9 ), RPT_8 ( 8, 0, 9 ), - RPT_8 ( -8, 0, 9 ), RPT_8 ( 4, 1, 9 ), - RPT_8 ( -4, 1, 9 ), RPT_8 ( 2, 3, 9 ), - RPT_8 ( -2, 3, 9 ), RPT_8 ( 1, 8, 9 ), - RPT_8 ( -1, 8, 9 ), RPT_8 ( 1, 9, 9 ), - RPT_8 ( -1, 9, 9 ), RPT_4 ( 9, 0, 10 ), - RPT_4 ( -9, 0, 10 ), RPT_4 ( 10, 0, 10 ), - RPT_4 ( -10, 0, 10 ), RPT_4 ( 5, 1, 10 ), - RPT_4 ( -5, 1, 10 ), RPT_4 ( 3, 2, 10 ), - RPT_4 ( -3, 2, 10 ), RPT_4 ( 2, 4, 10 ), - RPT_4 ( -2, 4, 10 ), RPT_4 ( 2, 5, 10 ), - RPT_4 ( -2, 5, 10 ), RPT_4 ( 1, 10, 10 ), - RPT_4 ( -1, 10, 10 ), RPT_4 ( 1, 11, 10 ), - RPT_4 ( -1, 11, 10 ), { 4096, 0, -1 }, { 4128, 0, -1 }, - { 4160, 0, -1 }, { 4192, 0, -1 }, { 4224, 0, -1 }, { 4256, 0, -1 }, - { 4288, 0, -1 }, { 4320, 0, -1 }, RPT_4 ( 0, 0, 10 ), - RPT_2 ( 11, 0, 11 ), RPT_2 ( -11, 0, 11 ), - RPT_2 ( 12, 0, 11 ), RPT_2 ( -12, 0, 11 ), - RPT_2 ( 6, 1, 11 ), RPT_2 ( -6, 1, 11 ), - RPT_2 ( 7, 1, 11 ), RPT_2 ( -7, 1, 11 ), - RPT_2 ( 3, 3, 11 ), RPT_2 ( -3, 3, 11 ), - RPT_2 ( 3, 4, 11 ), RPT_2 ( -3, 4, 11 ), - RPT_2 ( 3, 5, 11 ), RPT_2 ( -3, 5, 11 ), - RPT_2 ( 2, 6, 11 ), RPT_2 ( -2, 6, 11 ), - RPT_2 ( 2, 7, 11 ), RPT_2 ( -2, 7, 11 ), - RPT_2 ( 1, 12, 11 ), RPT_2 ( -1, 12, 11 ), - RPT_2 ( 1, 13, 11 ), RPT_2 ( -1, 13, 11 ), - RPT_2 ( 1, 14, 11 ), RPT_2 ( -1, 14, 11 ), - { 13, 0, 12 }, { -13, 0, 12 }, { 14, 0, 12 }, { -14, 0, 12 }, - RPT_2 ( 0, 1, 11 ), { 8, 1, 12 }, { -8, 1, 12 }, - { 4, 2, 12 }, { -4, 2, 12 }, { 4, 3, 12 }, { -4, 3, 12 }, - { 2, 8, 12 }, { -2, 8, 12 }, { 2, 9, 12 }, { -2, 9, 12 }, - { 1, 15, 12 }, { -1, 15, 12 }, { 4352, 0, -1 }, { 4384, 0, -1 }, - { 4416, 0, -1 }, { 4448, 0, -1 }, { 4480, 0, -1 }, { 0, 2, 12 }, - { 4512, 0, -1 }, { 0, 3, 12 }, { 4544, 0, -1 }, { 0, 4, 12 }, - { 4576, 0, -1 }, { 0, 5, 12 }, { 4608, 0, -1 }, { 0, 6, 12 }, - { 4640, 0, -1 }, { 4672, 0, -1 }, { 4704, 0, -1 }, { 4736, 0, -1 }, - RPT_4 ( 0, 0, 15 ), RPT_4 ( 0, 1, 15 ), - RPT_4 ( 0, 2, 15 ), RPT_4 ( 0, 3, 15 ), - RPT_4 ( 0, 4, 15 ), RPT_4 ( 0, 5, 15 ), - RPT_4 ( 0, 6, 15 ), RPT_4 ( 0, 7, 15 ), - RPT_4 ( 0, 8, 15 ), RPT_4 ( 0, 9, 15 ), - RPT_4 ( 0, 10, 15 ), RPT_4 ( 0, 11, 15 ), - RPT_4 ( 0, 12, 15 ), RPT_4 ( 0, 13, 15 ), - RPT_4 ( 0, 14, 15 ), RPT_4 ( 0, 15, 15 ), - RPT_4 ( 0, 16, 15 ), RPT_4 ( 0, 17, 15 ), - RPT_4 ( 0, 18, 15 ), RPT_4 ( 0, 19, 15 ), - RPT_4 ( 0, 20, 15 ), RPT_4 ( 0, 21, 15 ), - RPT_4 ( 0, 22, 15 ), RPT_4 ( 0, 23, 15 ), - RPT_4 ( 0, 24, 15 ), RPT_4 ( 0, 25, 15 ), - RPT_4 ( 0, 26, 15 ), RPT_4 ( 0, 27, 15 ), - RPT_4 ( 0, 28, 15 ), RPT_4 ( 0, 29, 15 ), - RPT_4 ( 0, 30, 15 ), RPT_4 ( 0, 31, 15 ), - RPT_4 ( 0, 32, 15 ), RPT_4 ( 0, 33, 15 ), - RPT_4 ( 0, 34, 15 ), RPT_4 ( 0, 35, 15 ), - RPT_4 ( 0, 36, 15 ), RPT_4 ( 0, 37, 15 ), - RPT_4 ( 0, 38, 15 ), RPT_4 ( 0, 39, 15 ), - RPT_4 ( 0, 40, 15 ), RPT_4 ( 0, 41, 15 ), - RPT_4 ( 0, 42, 15 ), RPT_4 ( 0, 43, 15 ), - RPT_4 ( 0, 44, 15 ), RPT_4 ( 0, 45, 15 ), - RPT_4 ( 0, 46, 15 ), RPT_4 ( 0, 47, 15 ), - RPT_4 ( 0, 48, 15 ), RPT_4 ( 0, 49, 15 ), - RPT_4 ( 0, 50, 15 ), RPT_4 ( 0, 51, 15 ), - RPT_4 ( 0, 52, 15 ), RPT_4 ( 0, 53, 15 ), - RPT_4 ( 0, 54, 15 ), RPT_4 ( 0, 55, 15 ), - RPT_4 ( 0, 56, 15 ), RPT_4 ( 0, 57, 15 ), - RPT_4 ( 0, 58, 15 ), RPT_4 ( 0, 59, 15 ), - RPT_4 ( 0, 60, 15 ), RPT_4 ( 0, 61, 15 ), - RPT_4 ( 0, 62, 15 ), RPT_4 ( 0, 63, 15 ), - RPT_2 ( 0, 0, 16 ), { 1, 0, 17 }, { -1, 0, 17 }, - { 2, 0, 17 }, { -2, 0, 17 }, { 3, 0, 17 }, { -3, 0, 17 }, - { 4, 0, 17 }, { -4, 0, 17 }, { 5, 0, 17 }, { -5, 0, 17 }, - { 6, 0, 17 }, { -6, 0, 17 }, { 7, 0, 17 }, { -7, 0, 17 }, - { 8, 0, 17 }, { -8, 0, 17 }, { 9, 0, 17 }, { -9, 0, 17 }, - { 10, 0, 17 }, { -10, 0, 17 }, { 11, 0, 17 }, { -11, 0, 17 }, - { 12, 0, 17 }, { -12, 0, 17 }, { 13, 0, 17 }, { -13, 0, 17 }, - { 14, 0, 17 }, { -14, 0, 17 }, { 15, 0, 17 }, { -15, 0, 17 }, - { 16, 0, 17 }, { -16, 0, 17 }, { 17, 0, 17 }, { -17, 0, 17 }, - { 18, 0, 17 }, { -18, 0, 17 }, { 19, 0, 17 }, { -19, 0, 17 }, - { 20, 0, 17 }, { -20, 0, 17 }, { 21, 0, 17 }, { -21, 0, 17 }, - { 22, 0, 17 }, { -22, 0, 17 }, { 23, 0, 17 }, { -23, 0, 17 }, - { 24, 0, 17 }, { -24, 0, 17 }, { 25, 0, 17 }, { -25, 0, 17 }, - { 26, 0, 17 }, { -26, 0, 17 }, { 27, 0, 17 }, { -27, 0, 17 }, - { 28, 0, 17 }, { -28, 0, 17 }, { 29, 0, 17 }, { -29, 0, 17 }, - { 30, 0, 17 }, { -30, 0, 17 }, { 31, 0, 17 }, { -31, 0, 17 }, - RPT_16 ( 15, 0, 13 ), RPT_16 ( -15, 0, 13 ), - RPT_16 ( 9, 1, 13 ), RPT_16 ( -9, 1, 13 ), - RPT_16 ( 10, 1, 13 ), RPT_16 ( -10, 1, 13 ), - RPT_16 ( 5, 2, 13 ), RPT_16 ( -5, 2, 13 ), - RPT_16 ( 5, 3, 13 ), RPT_16 ( -5, 3, 13 ), - RPT_16 ( 4, 4, 13 ), RPT_16 ( -4, 4, 13 ), - RPT_16 ( 4, 5, 13 ), RPT_16 ( -4, 5, 13 ), - RPT_16 ( 3, 6, 13 ), RPT_16 ( -3, 6, 13 ), - RPT_16 ( 3, 7, 13 ), RPT_16 ( -3, 7, 13 ), - RPT_16 ( 1, 16, 13 ), RPT_16 ( -1, 16, 13 ), - RPT_16 ( 1, 17, 13 ), RPT_16 ( -1, 17, 13 ), -}; - -static const HQXLUT ac128_lut[] = { - RPT_256 ( 1, 0, 3 ), RPT_256 ( -1, 0, 3 ), - RPT_512 ( 0, 64, 2 ), RPT_128 ( 1, 1, 4 ), - RPT_128 ( -1, 1, 4 ), RPT_64 ( 2, 0, 5 ), - RPT_64 ( -2, 0, 5 ), RPT_32 ( 3, 0, 6 ), - RPT_32 ( -3, 0, 6 ), RPT_32 ( 2, 1, 6 ), - RPT_32 ( -2, 1, 6 ), RPT_32 ( 1, 2, 6 ), - RPT_32 ( -1, 2, 6 ), RPT_32 ( 1, 3, 6 ), - RPT_32 ( -1, 3, 6 ), RPT_32 ( 1, 4, 6 ), - RPT_32 ( -1, 4, 6 ), RPT_16 ( 4, 0, 7 ), - RPT_16 ( -4, 0, 7 ), RPT_16 ( 1, 5, 7 ), - RPT_16 ( -1, 5, 7 ), RPT_16 ( 1, 6, 7 ), - RPT_16 ( -1, 6, 7 ), RPT_16 ( 1, 7, 7 ), - RPT_16 ( -1, 7, 7 ), RPT_8 ( 5, 0, 8 ), - RPT_8 ( -5, 0, 8 ), RPT_8 ( 3, 1, 8 ), - RPT_8 ( -3, 1, 8 ), RPT_8 ( 2, 2, 8 ), - RPT_8 ( -2, 2, 8 ), RPT_8 ( 2, 3, 8 ), - RPT_8 ( -2, 3, 8 ), RPT_8 ( 1, 8, 8 ), - RPT_8 ( -1, 8, 8 ), RPT_8 ( 1, 9, 8 ), - RPT_8 ( -1, 9, 8 ), RPT_4 ( 6, 0, 9 ), - RPT_4 ( -6, 0, 9 ), RPT_4 ( 4, 1, 9 ), - RPT_4 ( -4, 1, 9 ), RPT_4 ( 2, 4, 9 ), - RPT_4 ( -2, 4, 9 ), RPT_4 ( 2, 5, 9 ), - RPT_4 ( -2, 5, 9 ), RPT_4 ( 1, 10, 9 ), - RPT_4 ( -1, 10, 9 ), RPT_2 ( 7, 0, 10 ), - RPT_2 ( -7, 0, 10 ), RPT_2 ( 5, 1, 10 ), - RPT_2 ( -5, 1, 10 ), RPT_2 ( 3, 2, 10 ), - RPT_2 ( -3, 2, 10 ), RPT_2 ( 3, 3, 10 ), - RPT_2 ( -3, 3, 10 ), RPT_2 ( 2, 6, 10 ), - RPT_2 ( -2, 6, 10 ), { 2048, 0, -1 }, { 2112, 0, -1 }, - { 2176, 0, -1 }, { 2240, 0, -1 }, { 6, 1, 11 }, { -6, 1, 11 }, - { 7, 1, 11 }, { -7, 1, 11 }, { 3, 4, 11 }, { -3, 4, 11 }, - { 3, 5, 11 }, { -3, 5, 11 }, { 2, 7, 11 }, { -2, 7, 11 }, - { 2, 8, 11 }, { -2, 8, 11 }, { 2, 9, 11 }, { -2, 9, 11 }, - { 1, 11, 11 }, { -1, 11, 11 }, { 1, 12, 11 }, { -1, 12, 11 }, - { 1, 13, 11 }, { -1, 13, 11 }, { 0, 0, 11 }, { 2304, 0, -1 }, - { 2368, 0, -1 }, { 2432, 0, -1 }, { 2496, 0, -1 }, { 2560, 0, -1 }, - { 2624, 0, -1 }, { 2688, 0, -1 }, { 2752, 0, -1 }, { 2816, 0, -1 }, - { 2880, 0, -1 }, { 2944, 0, -1 }, RPT_4 ( 0, 0, 15 ), - RPT_4 ( 0, 1, 15 ), RPT_4 ( 0, 2, 15 ), - RPT_4 ( 0, 3, 15 ), RPT_4 ( 0, 4, 15 ), - RPT_4 ( 0, 5, 15 ), RPT_4 ( 0, 6, 15 ), - RPT_4 ( 0, 7, 15 ), RPT_4 ( 0, 8, 15 ), - RPT_4 ( 0, 9, 15 ), RPT_4 ( 0, 10, 15 ), - RPT_4 ( 0, 11, 15 ), RPT_4 ( 0, 12, 15 ), - RPT_4 ( 0, 13, 15 ), RPT_4 ( 0, 14, 15 ), - RPT_4 ( 0, 15, 15 ), RPT_4 ( 0, 16, 15 ), - RPT_4 ( 0, 17, 15 ), RPT_4 ( 0, 18, 15 ), - RPT_4 ( 0, 19, 15 ), RPT_4 ( 0, 20, 15 ), - RPT_4 ( 0, 21, 15 ), RPT_4 ( 0, 22, 15 ), - RPT_4 ( 0, 23, 15 ), RPT_4 ( 0, 24, 15 ), - RPT_4 ( 0, 25, 15 ), RPT_4 ( 0, 26, 15 ), - RPT_4 ( 0, 27, 15 ), RPT_4 ( 0, 28, 15 ), - RPT_4 ( 0, 29, 15 ), RPT_4 ( 0, 30, 15 ), - RPT_4 ( 0, 31, 15 ), RPT_4 ( 0, 32, 15 ), - RPT_4 ( 0, 33, 15 ), RPT_4 ( 0, 34, 15 ), - RPT_4 ( 0, 35, 15 ), RPT_4 ( 0, 36, 15 ), - RPT_4 ( 0, 37, 15 ), RPT_4 ( 0, 38, 15 ), - RPT_4 ( 0, 39, 15 ), RPT_4 ( 0, 40, 15 ), - RPT_4 ( 0, 41, 15 ), RPT_4 ( 0, 42, 15 ), - RPT_4 ( 0, 43, 15 ), RPT_4 ( 0, 44, 15 ), - RPT_4 ( 0, 45, 15 ), RPT_4 ( 0, 46, 15 ), - RPT_4 ( 0, 47, 15 ), RPT_4 ( 0, 48, 15 ), - RPT_4 ( 0, 49, 15 ), RPT_4 ( 0, 50, 15 ), - RPT_4 ( 0, 51, 15 ), RPT_4 ( 0, 52, 15 ), - RPT_4 ( 0, 53, 15 ), RPT_4 ( 0, 54, 15 ), - RPT_4 ( 0, 55, 15 ), RPT_4 ( 0, 56, 15 ), - RPT_4 ( 0, 57, 15 ), RPT_4 ( 0, 58, 15 ), - RPT_4 ( 0, 59, 15 ), RPT_4 ( 0, 60, 15 ), - RPT_4 ( 0, 61, 15 ), RPT_4 ( 0, 62, 15 ), - RPT_4 ( 0, 63, 15 ), RPT_32 ( 8, 0, 12 ), - RPT_32 ( -8, 0, 12 ), RPT_32 ( 9, 0, 12 ), - RPT_32 ( -9, 0, 12 ), RPT_32 ( 8, 1, 12 ), - RPT_32 ( -8, 1, 12 ), RPT_32 ( 4, 2, 12 ), - RPT_32 ( -4, 2, 12 ), RPT_32 ( 4, 3, 12 ), - RPT_32 ( -4, 3, 12 ), RPT_32 ( 3, 6, 12 ), - RPT_32 ( -3, 6, 12 ), RPT_32 ( 1, 14, 12 ), - RPT_32 ( -1, 14, 12 ), RPT_32 ( 1, 15, 12 ), - RPT_32 ( -1, 15, 12 ), RPT_32 ( 1, 16, 12 ), - RPT_32 ( -1, 16, 12 ), RPT_32 ( 0, 1, 12 ), - RPT_32 ( 0, 2, 12 ), RPT_32 ( 0, 3, 12 ), - RPT_2 ( 0, 0, 16 ), { 1, 0, 17 }, { -1, 0, 17 }, - { 2, 0, 17 }, { -2, 0, 17 }, { 3, 0, 17 }, { -3, 0, 17 }, - { 4, 0, 17 }, { -4, 0, 17 }, { 5, 0, 17 }, { -5, 0, 17 }, - { 6, 0, 17 }, { -6, 0, 17 }, { 7, 0, 17 }, { -7, 0, 17 }, - { 8, 0, 17 }, { -8, 0, 17 }, { 9, 0, 17 }, { -9, 0, 17 }, - { 10, 0, 17 }, { -10, 0, 17 }, { 11, 0, 17 }, { -11, 0, 17 }, - { 12, 0, 17 }, { -12, 0, 17 }, { 13, 0, 17 }, { -13, 0, 17 }, - { 14, 0, 17 }, { -14, 0, 17 }, { 15, 0, 17 }, { -15, 0, 17 }, -}; - -const HQXAC ff_hqx_ac[NUM_HQX_AC] = { - { 10, 5, ac0_lut }, - { 11, 6, ac8_lut }, - { 11, 6, ac16_lut }, - { 11, 6, ac32_lut }, - { 12, 5, ac64_lut }, - { 11, 6, ac128_lut }, -}; - -#define INIT_DC_TABLE(idx, name) \ - do { \ - ret = vlc_init(&ctx->dc_vlc[idx], HQX_DC_VLC_BITS, \ - FF_ARRAY_ELEMS(name ## _vlc_lens), \ - name ## _vlc_lens, 1, 1, \ - name ## _vlc_bits, 2, 2, 0); \ - if (ret < 0) \ - return ret; \ - } while (0) - -av_cold int ff_hqx_init_vlcs(HQXContext *ctx) -{ - int ret = vlc_init(&ctx->cbp_vlc, HQX_CBP_VLC_BITS, FF_ARRAY_ELEMS(cbp_vlc_lens), - cbp_vlc_lens, 1, 1, cbp_vlc_bits, 1, 1, 0); - if (ret < 0) - return ret; - - INIT_DC_TABLE(0, dc9); - INIT_DC_TABLE(1, dc10); - INIT_DC_TABLE(2, dc11); - - return 0; -} diff --git a/libavcodec/hqxvlc.h b/libavcodec/hqxvlc.h new file mode 100644 index 000000000..864a4b2db --- /dev/null +++ b/libavcodec/hqxvlc.h @@ -0,0 +1,1575 @@ +/* + * Canopus HQX decoder + * + * 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_HQXVLC_H +#define AVCODEC_HQXVLC_H + +#include + +#include "vlc.h" + +#include "libavutil/attributes.h" +#include "libavutil/macros.h" + +#define HQX_DC_VLC_BITS 9 + +enum HQXACMode { + HQX_AC_Q0 = 0, + HQX_AC_Q8, + HQX_AC_Q16, + HQX_AC_Q32, + HQX_AC_Q64, + HQX_AC_Q128, + NUM_HQX_AC +}; + +typedef struct HQXAC { + int bits; + const RL_VLC_ELEM *lut; +} HQXAC; + +static const uint16_t dc9_vlc_bits[512] = { + 0x0010, 0x0008, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, + 0x002E, 0x0030, 0x0032, 0x0034, 0x0074, 0x0076, 0x0078, 0x007A, + 0x007C, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, + 0x000E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, + 0x005E, 0x0020, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, + 0x002E, 0x0030, 0x0032, 0x0034, 0x0036, 0x0038, 0x003A, 0x003C, + 0x003E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, + 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, + 0x00DE, 0x01C0, 0x01C2, 0x01C4, 0x01C6, 0x01C8, 0x01CA, 0x01CC, + 0x01CE, 0x01D0, 0x01D2, 0x01D4, 0x01D6, 0x01D8, 0x01DA, 0x01DC, + 0x01DE, 0x01E0, 0x01E2, 0x01E4, 0x01E6, 0x01E8, 0x01EA, 0x01EC, + 0x01EE, 0x01F0, 0x01F2, 0x01F4, 0x01F6, 0x01F8, 0x01FA, 0x01FC, + 0x01FE, 0x06C0, 0x06C2, 0x06C4, 0x06C6, 0x06C8, 0x06CA, 0x06CC, + 0x06CE, 0x06D0, 0x06D2, 0x06D4, 0x06D6, 0x06D8, 0x06DA, 0x06DC, + 0x06DE, 0x06E0, 0x06E2, 0x06E4, 0x06E6, 0x06E8, 0x06EA, 0x06EC, + 0x06EE, 0x06F0, 0x06F2, 0x06F4, 0x06F6, 0x06F8, 0x06FA, 0x06FC, + 0x06FE, 0x0E00, 0x0E02, 0x0E04, 0x0E06, 0x0E08, 0x0E0A, 0x0E0C, + 0x0E0E, 0x0E10, 0x0E12, 0x0E14, 0x0E16, 0x0E18, 0x0E1A, 0x0E1C, + 0x0E1E, 0x0E20, 0x0E22, 0x0E24, 0x0E26, 0x0E28, 0x0E2A, 0x0E2C, + 0x0E2E, 0x0E30, 0x0E32, 0x0E34, 0x0E36, 0x0E38, 0x0E3A, 0x0E3C, + 0x0E3E, 0x0E40, 0x0E42, 0x0E44, 0x0E46, 0x0E48, 0x0E4A, 0x0E4C, + 0x0E4E, 0x0E50, 0x0E52, 0x0E54, 0x0E56, 0x0E58, 0x0E5A, 0x0E5C, + 0x0E5E, 0x0E60, 0x0E62, 0x0E64, 0x0E66, 0x0E68, 0x0E6A, 0x0E6C, + 0x0E6E, 0x0E70, 0x0E72, 0x0E74, 0x0E76, 0x0E78, 0x0E7A, 0x0E7C, + 0x0E7E, 0x1F80, 0x1F82, 0x1F84, 0x1F86, 0x1F88, 0x1F8A, 0x1F8C, + 0x1F8E, 0x1F90, 0x1F92, 0x1F94, 0x1F96, 0x1F98, 0x1F9A, 0x1F9C, + 0x1F9E, 0x1FA0, 0x1FA2, 0x1FA4, 0x1FA6, 0x1FA8, 0x1FAA, 0x1FAC, + 0x1FAE, 0x1FB0, 0x1FB2, 0x1FB4, 0x1FB6, 0x1FB8, 0x1FBA, 0x1FBC, + 0x1FBE, 0x1FC0, 0x1FC2, 0x1FC4, 0x1FC6, 0x1FC8, 0x1FCA, 0x1FCC, + 0x1FCE, 0x1FD0, 0x1FD2, 0x1FD4, 0x1FD6, 0x1FD8, 0x1FDA, 0x1FDC, + 0x1FDE, 0x1FE0, 0x1FE2, 0x1FE4, 0x1FE6, 0x1FE8, 0x1FEA, 0x1FEC, + 0x1FEE, 0x1FF0, 0x1FF2, 0x1FF4, 0x1FF6, 0x1FF8, 0x1FFA, 0x1FFC, + 0x0FFF, 0x1FFD, 0x1FFB, 0x1FF9, 0x1FF7, 0x1FF5, 0x1FF3, 0x1FF1, + 0x1FEF, 0x1FED, 0x1FEB, 0x1FE9, 0x1FE7, 0x1FE5, 0x1FE3, 0x1FE1, + 0x1FDF, 0x1FDD, 0x1FDB, 0x1FD9, 0x1FD7, 0x1FD5, 0x1FD3, 0x1FD1, + 0x1FCF, 0x1FCD, 0x1FCB, 0x1FC9, 0x1FC7, 0x1FC5, 0x1FC3, 0x1FC1, + 0x1FBF, 0x1FBD, 0x1FBB, 0x1FB9, 0x1FB7, 0x1FB5, 0x1FB3, 0x1FB1, + 0x1FAF, 0x1FAD, 0x1FAB, 0x1FA9, 0x1FA7, 0x1FA5, 0x1FA3, 0x1FA1, + 0x1F9F, 0x1F9D, 0x1F9B, 0x1F99, 0x1F97, 0x1F95, 0x1F93, 0x1F91, + 0x1F8F, 0x1F8D, 0x1F8B, 0x1F89, 0x1F87, 0x1F85, 0x1F83, 0x1F81, + 0x0E7F, 0x0E7D, 0x0E7B, 0x0E79, 0x0E77, 0x0E75, 0x0E73, 0x0E71, + 0x0E6F, 0x0E6D, 0x0E6B, 0x0E69, 0x0E67, 0x0E65, 0x0E63, 0x0E61, + 0x0E5F, 0x0E5D, 0x0E5B, 0x0E59, 0x0E57, 0x0E55, 0x0E53, 0x0E51, + 0x0E4F, 0x0E4D, 0x0E4B, 0x0E49, 0x0E47, 0x0E45, 0x0E43, 0x0E41, + 0x0E3F, 0x0E3D, 0x0E3B, 0x0E39, 0x0E37, 0x0E35, 0x0E33, 0x0E31, + 0x0E2F, 0x0E2D, 0x0E2B, 0x0E29, 0x0E27, 0x0E25, 0x0E23, 0x0E21, + 0x0E1F, 0x0E1D, 0x0E1B, 0x0E19, 0x0E17, 0x0E15, 0x0E13, 0x0E11, + 0x0E0F, 0x0E0D, 0x0E0B, 0x0E09, 0x0E07, 0x0E05, 0x0E03, 0x0E01, + 0x06FF, 0x06FD, 0x06FB, 0x06F9, 0x06F7, 0x06F5, 0x06F3, 0x06F1, + 0x06EF, 0x06ED, 0x06EB, 0x06E9, 0x06E7, 0x06E5, 0x06E3, 0x06E1, + 0x06DF, 0x06DD, 0x06DB, 0x06D9, 0x06D7, 0x06D5, 0x06D3, 0x06D1, + 0x06CF, 0x06CD, 0x06CB, 0x06C9, 0x06C7, 0x06C5, 0x06C3, 0x06C1, + 0x01FF, 0x01FD, 0x01FB, 0x01F9, 0x01F7, 0x01F5, 0x01F3, 0x01F1, + 0x01EF, 0x01ED, 0x01EB, 0x01E9, 0x01E7, 0x01E5, 0x01E3, 0x01E1, + 0x01DF, 0x01DD, 0x01DB, 0x01D9, 0x01D7, 0x01D5, 0x01D3, 0x01D1, + 0x01CF, 0x01CD, 0x01CB, 0x01C9, 0x01C7, 0x01C5, 0x01C3, 0x01C1, + 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, + 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, + 0x003F, 0x003D, 0x003B, 0x0039, 0x0037, 0x0035, 0x0033, 0x0031, + 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0021, + 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, + 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, + 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0035, 0x0033, 0x0031, + 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0009, +}; + +static const uint8_t dc9_vlc_lens[512] = { + 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 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, + 12, 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, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 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, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, +}; + +static const uint16_t dc10_vlc_bits[1024] = { + 0x0014, 0x002A, 0x002C, 0x002E, 0x0064, 0x0066, 0x0068, 0x006A, + 0x006C, 0x006E, 0x0070, 0x0072, 0x0074, 0x0076, 0x0078, 0x007A, + 0x007C, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, + 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, + 0x005E, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, + 0x000E, 0x0010, 0x0012, 0x0014, 0x0016, 0x0018, 0x001A, 0x001C, + 0x001E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, + 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, + 0x00DE, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, + 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, + 0x005E, 0x0060, 0x0062, 0x0064, 0x0066, 0x0068, 0x006A, 0x006C, + 0x006E, 0x0070, 0x0072, 0x0074, 0x0076, 0x0078, 0x007A, 0x007C, + 0x007E, 0x01C0, 0x01C2, 0x01C4, 0x01C6, 0x01C8, 0x01CA, 0x01CC, + 0x01CE, 0x01D0, 0x01D2, 0x01D4, 0x01D6, 0x01D8, 0x01DA, 0x01DC, + 0x01DE, 0x01E0, 0x01E2, 0x01E4, 0x01E6, 0x01E8, 0x01EA, 0x01EC, + 0x01EE, 0x01F0, 0x01F2, 0x01F4, 0x01F6, 0x01F8, 0x01FA, 0x01FC, + 0x01FE, 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040A, 0x040C, + 0x040E, 0x0410, 0x0412, 0x0414, 0x0416, 0x0418, 0x041A, 0x041C, + 0x041E, 0x0420, 0x0422, 0x0424, 0x0426, 0x0428, 0x042A, 0x042C, + 0x042E, 0x0430, 0x0432, 0x0434, 0x0436, 0x0438, 0x043A, 0x043C, + 0x043E, 0x0440, 0x0442, 0x0444, 0x0446, 0x0448, 0x044A, 0x044C, + 0x044E, 0x0450, 0x0452, 0x0454, 0x0456, 0x0458, 0x045A, 0x045C, + 0x045E, 0x0460, 0x0462, 0x0464, 0x0466, 0x0468, 0x046A, 0x046C, + 0x046E, 0x0470, 0x0472, 0x0474, 0x0476, 0x0478, 0x047A, 0x047C, + 0x047E, 0x0C00, 0x0C02, 0x0C04, 0x0C06, 0x0C08, 0x0C0A, 0x0C0C, + 0x0C0E, 0x0C10, 0x0C12, 0x0C14, 0x0C16, 0x0C18, 0x0C1A, 0x0C1C, + 0x0C1E, 0x0C20, 0x0C22, 0x0C24, 0x0C26, 0x0C28, 0x0C2A, 0x0C2C, + 0x0C2E, 0x0C30, 0x0C32, 0x0C34, 0x0C36, 0x0C38, 0x0C3A, 0x0C3C, + 0x0C3E, 0x0C40, 0x0C42, 0x0C44, 0x0C46, 0x0C48, 0x0C4A, 0x0C4C, + 0x0C4E, 0x0C50, 0x0C52, 0x0C54, 0x0C56, 0x0C58, 0x0C5A, 0x0C5C, + 0x0C5E, 0x0C60, 0x0C62, 0x0C64, 0x0C66, 0x0C68, 0x0C6A, 0x0C6C, + 0x0C6E, 0x0C70, 0x0C72, 0x0C74, 0x0C76, 0x0C78, 0x0C7A, 0x0C7C, + 0x0C7E, 0x0900, 0x0902, 0x0904, 0x0906, 0x0908, 0x090A, 0x090C, + 0x090E, 0x0910, 0x0912, 0x0914, 0x0916, 0x0918, 0x091A, 0x091C, + 0x091E, 0x0920, 0x0922, 0x0924, 0x0926, 0x0928, 0x092A, 0x092C, + 0x092E, 0x0930, 0x0932, 0x0934, 0x0936, 0x0938, 0x093A, 0x093C, + 0x093E, 0x0940, 0x0942, 0x0944, 0x0946, 0x0948, 0x094A, 0x094C, + 0x094E, 0x0950, 0x0952, 0x0954, 0x0956, 0x0958, 0x095A, 0x095C, + 0x095E, 0x0960, 0x0962, 0x0964, 0x0966, 0x0968, 0x096A, 0x096C, + 0x096E, 0x0970, 0x0972, 0x0974, 0x0976, 0x0978, 0x097A, 0x097C, + 0x097E, 0x0980, 0x0982, 0x0984, 0x0986, 0x0988, 0x098A, 0x098C, + 0x098E, 0x0990, 0x0992, 0x0994, 0x0996, 0x0998, 0x099A, 0x099C, + 0x099E, 0x09A0, 0x09A2, 0x09A4, 0x09A6, 0x09A8, 0x09AA, 0x09AC, + 0x09AE, 0x09B0, 0x09B2, 0x09B4, 0x09B6, 0x09B8, 0x09BA, 0x09BC, + 0x09BE, 0x09C0, 0x09C2, 0x09C4, 0x09C6, 0x09C8, 0x09CA, 0x09CC, + 0x09CE, 0x09D0, 0x09D2, 0x09D4, 0x09D6, 0x09D8, 0x09DA, 0x09DC, + 0x09DE, 0x09E0, 0x09E2, 0x09E4, 0x09E6, 0x09E8, 0x09EA, 0x09EC, + 0x09EE, 0x09F0, 0x09F2, 0x09F4, 0x09F6, 0x09F8, 0x09FA, 0x09FC, + 0x09FE, 0x3F00, 0x3F02, 0x3F04, 0x3F06, 0x3F08, 0x3F0A, 0x3F0C, + 0x3F0E, 0x3F10, 0x3F12, 0x3F14, 0x3F16, 0x3F18, 0x3F1A, 0x3F1C, + 0x3F1E, 0x3F20, 0x3F22, 0x3F24, 0x3F26, 0x3F28, 0x3F2A, 0x3F2C, + 0x3F2E, 0x3F30, 0x3F32, 0x3F34, 0x3F36, 0x3F38, 0x3F3A, 0x3F3C, + 0x3F3E, 0x3F40, 0x3F42, 0x3F44, 0x3F46, 0x3F48, 0x3F4A, 0x3F4C, + 0x3F4E, 0x3F50, 0x3F52, 0x3F54, 0x3F56, 0x3F58, 0x3F5A, 0x3F5C, + 0x3F5E, 0x3F60, 0x3F62, 0x3F64, 0x3F66, 0x3F68, 0x3F6A, 0x3F6C, + 0x3F6E, 0x3F70, 0x3F72, 0x3F74, 0x3F76, 0x3F78, 0x3F7A, 0x3F7C, + 0x3F7E, 0x3F80, 0x3F82, 0x3F84, 0x3F86, 0x3F88, 0x3F8A, 0x3F8C, + 0x3F8E, 0x3F90, 0x3F92, 0x3F94, 0x3F96, 0x3F98, 0x3F9A, 0x3F9C, + 0x3F9E, 0x3FA0, 0x3FA2, 0x3FA4, 0x3FA6, 0x3FA8, 0x3FAA, 0x3FAC, + 0x3FAE, 0x3FB0, 0x3FB2, 0x3FB4, 0x3FB6, 0x3FB8, 0x3FBA, 0x3FBC, + 0x3FBE, 0x3FC0, 0x3FC2, 0x3FC4, 0x3FC6, 0x3FC8, 0x3FCA, 0x3FCC, + 0x3FCE, 0x3FD0, 0x3FD2, 0x3FD4, 0x3FD6, 0x3FD8, 0x3FDA, 0x3FDC, + 0x3FDE, 0x3FE0, 0x3FE2, 0x3FE4, 0x3FE6, 0x3FE8, 0x3FEA, 0x3FEC, + 0x3FEE, 0x3FF0, 0x3FF2, 0x3FF4, 0x3FF6, 0x3FF8, 0x3FFA, 0x3FFC, + 0x1FFF, 0x3FFD, 0x3FFB, 0x3FF9, 0x3FF7, 0x3FF5, 0x3FF3, 0x3FF1, + 0x3FEF, 0x3FED, 0x3FEB, 0x3FE9, 0x3FE7, 0x3FE5, 0x3FE3, 0x3FE1, + 0x3FDF, 0x3FDD, 0x3FDB, 0x3FD9, 0x3FD7, 0x3FD5, 0x3FD3, 0x3FD1, + 0x3FCF, 0x3FCD, 0x3FCB, 0x3FC9, 0x3FC7, 0x3FC5, 0x3FC3, 0x3FC1, + 0x3FBF, 0x3FBD, 0x3FBB, 0x3FB9, 0x3FB7, 0x3FB5, 0x3FB3, 0x3FB1, + 0x3FAF, 0x3FAD, 0x3FAB, 0x3FA9, 0x3FA7, 0x3FA5, 0x3FA3, 0x3FA1, + 0x3F9F, 0x3F9D, 0x3F9B, 0x3F99, 0x3F97, 0x3F95, 0x3F93, 0x3F91, + 0x3F8F, 0x3F8D, 0x3F8B, 0x3F89, 0x3F87, 0x3F85, 0x3F83, 0x3F81, + 0x3F7F, 0x3F7D, 0x3F7B, 0x3F79, 0x3F77, 0x3F75, 0x3F73, 0x3F71, + 0x3F6F, 0x3F6D, 0x3F6B, 0x3F69, 0x3F67, 0x3F65, 0x3F63, 0x3F61, + 0x3F5F, 0x3F5D, 0x3F5B, 0x3F59, 0x3F57, 0x3F55, 0x3F53, 0x3F51, + 0x3F4F, 0x3F4D, 0x3F4B, 0x3F49, 0x3F47, 0x3F45, 0x3F43, 0x3F41, + 0x3F3F, 0x3F3D, 0x3F3B, 0x3F39, 0x3F37, 0x3F35, 0x3F33, 0x3F31, + 0x3F2F, 0x3F2D, 0x3F2B, 0x3F29, 0x3F27, 0x3F25, 0x3F23, 0x3F21, + 0x3F1F, 0x3F1D, 0x3F1B, 0x3F19, 0x3F17, 0x3F15, 0x3F13, 0x3F11, + 0x3F0F, 0x3F0D, 0x3F0B, 0x3F09, 0x3F07, 0x3F05, 0x3F03, 0x3F01, + 0x09FF, 0x09FD, 0x09FB, 0x09F9, 0x09F7, 0x09F5, 0x09F3, 0x09F1, + 0x09EF, 0x09ED, 0x09EB, 0x09E9, 0x09E7, 0x09E5, 0x09E3, 0x09E1, + 0x09DF, 0x09DD, 0x09DB, 0x09D9, 0x09D7, 0x09D5, 0x09D3, 0x09D1, + 0x09CF, 0x09CD, 0x09CB, 0x09C9, 0x09C7, 0x09C5, 0x09C3, 0x09C1, + 0x09BF, 0x09BD, 0x09BB, 0x09B9, 0x09B7, 0x09B5, 0x09B3, 0x09B1, + 0x09AF, 0x09AD, 0x09AB, 0x09A9, 0x09A7, 0x09A5, 0x09A3, 0x09A1, + 0x099F, 0x099D, 0x099B, 0x0999, 0x0997, 0x0995, 0x0993, 0x0991, + 0x098F, 0x098D, 0x098B, 0x0989, 0x0987, 0x0985, 0x0983, 0x0981, + 0x097F, 0x097D, 0x097B, 0x0979, 0x0977, 0x0975, 0x0973, 0x0971, + 0x096F, 0x096D, 0x096B, 0x0969, 0x0967, 0x0965, 0x0963, 0x0961, + 0x095F, 0x095D, 0x095B, 0x0959, 0x0957, 0x0955, 0x0953, 0x0951, + 0x094F, 0x094D, 0x094B, 0x0949, 0x0947, 0x0945, 0x0943, 0x0941, + 0x093F, 0x093D, 0x093B, 0x0939, 0x0937, 0x0935, 0x0933, 0x0931, + 0x092F, 0x092D, 0x092B, 0x0929, 0x0927, 0x0925, 0x0923, 0x0921, + 0x091F, 0x091D, 0x091B, 0x0919, 0x0917, 0x0915, 0x0913, 0x0911, + 0x090F, 0x090D, 0x090B, 0x0909, 0x0907, 0x0905, 0x0903, 0x0901, + 0x0C7F, 0x0C7D, 0x0C7B, 0x0C79, 0x0C77, 0x0C75, 0x0C73, 0x0C71, + 0x0C6F, 0x0C6D, 0x0C6B, 0x0C69, 0x0C67, 0x0C65, 0x0C63, 0x0C61, + 0x0C5F, 0x0C5D, 0x0C5B, 0x0C59, 0x0C57, 0x0C55, 0x0C53, 0x0C51, + 0x0C4F, 0x0C4D, 0x0C4B, 0x0C49, 0x0C47, 0x0C45, 0x0C43, 0x0C41, + 0x0C3F, 0x0C3D, 0x0C3B, 0x0C39, 0x0C37, 0x0C35, 0x0C33, 0x0C31, + 0x0C2F, 0x0C2D, 0x0C2B, 0x0C29, 0x0C27, 0x0C25, 0x0C23, 0x0C21, + 0x0C1F, 0x0C1D, 0x0C1B, 0x0C19, 0x0C17, 0x0C15, 0x0C13, 0x0C11, + 0x0C0F, 0x0C0D, 0x0C0B, 0x0C09, 0x0C07, 0x0C05, 0x0C03, 0x0C01, + 0x047F, 0x047D, 0x047B, 0x0479, 0x0477, 0x0475, 0x0473, 0x0471, + 0x046F, 0x046D, 0x046B, 0x0469, 0x0467, 0x0465, 0x0463, 0x0461, + 0x045F, 0x045D, 0x045B, 0x0459, 0x0457, 0x0455, 0x0453, 0x0451, + 0x044F, 0x044D, 0x044B, 0x0449, 0x0447, 0x0445, 0x0443, 0x0441, + 0x043F, 0x043D, 0x043B, 0x0439, 0x0437, 0x0435, 0x0433, 0x0431, + 0x042F, 0x042D, 0x042B, 0x0429, 0x0427, 0x0425, 0x0423, 0x0421, + 0x041F, 0x041D, 0x041B, 0x0419, 0x0417, 0x0415, 0x0413, 0x0411, + 0x040F, 0x040D, 0x040B, 0x0409, 0x0407, 0x0405, 0x0403, 0x0401, + 0x01FF, 0x01FD, 0x01FB, 0x01F9, 0x01F7, 0x01F5, 0x01F3, 0x01F1, + 0x01EF, 0x01ED, 0x01EB, 0x01E9, 0x01E7, 0x01E5, 0x01E3, 0x01E1, + 0x01DF, 0x01DD, 0x01DB, 0x01D9, 0x01D7, 0x01D5, 0x01D3, 0x01D1, + 0x01CF, 0x01CD, 0x01CB, 0x01C9, 0x01C7, 0x01C5, 0x01C3, 0x01C1, + 0x007F, 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0073, 0x0071, + 0x006F, 0x006D, 0x006B, 0x0069, 0x0067, 0x0065, 0x0063, 0x0061, + 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, + 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, + 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, + 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, + 0x001F, 0x001D, 0x001B, 0x0019, 0x0017, 0x0015, 0x0013, 0x0011, + 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, + 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, + 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, + 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0073, 0x0071, 0x006F, + 0x006D, 0x006B, 0x0069, 0x0067, 0x0065, 0x002F, 0x002D, 0x002B, +}; + +static const uint8_t dc10_vlc_lens[1024] = { + 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 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, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 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, + 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, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, +}; + +static const uint16_t dc11_vlc_bits[2048] = { + 0x0032, 0x0066, 0x0068, 0x006A, 0x006C, 0x006E, 0x0070, 0x0072, + 0x0074, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, + 0x00FE, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, + 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, + 0x005E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, + 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, + 0x00DE, 0x00E0, 0x00E2, 0x00E4, 0x00E6, 0x00E8, 0x00EA, 0x00EC, + 0x00EE, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, + 0x00FE, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, + 0x000E, 0x0010, 0x0012, 0x0014, 0x0016, 0x0018, 0x001A, 0x001C, + 0x001E, 0x0020, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, + 0x002E, 0x0030, 0x0032, 0x0034, 0x0036, 0x0038, 0x003A, 0x003C, + 0x003E, 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020A, 0x020C, + 0x020E, 0x0210, 0x0212, 0x0214, 0x0216, 0x0218, 0x021A, 0x021C, + 0x021E, 0x0220, 0x0222, 0x0224, 0x0226, 0x0228, 0x022A, 0x022C, + 0x022E, 0x0230, 0x0232, 0x0234, 0x0236, 0x0238, 0x023A, 0x023C, + 0x023E, 0x0080, 0x0082, 0x0084, 0x0086, 0x0088, 0x008A, 0x008C, + 0x008E, 0x0090, 0x0092, 0x0094, 0x0096, 0x0098, 0x009A, 0x009C, + 0x009E, 0x00A0, 0x00A2, 0x00A4, 0x00A6, 0x00A8, 0x00AA, 0x00AC, + 0x00AE, 0x00B0, 0x00B2, 0x00B4, 0x00B6, 0x00B8, 0x00BA, 0x00BC, + 0x00BE, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, + 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, + 0x00DE, 0x00E0, 0x00E2, 0x00E4, 0x00E6, 0x00E8, 0x00EA, 0x00EC, + 0x00EE, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, + 0x00FE, 0x0480, 0x0482, 0x0484, 0x0486, 0x0488, 0x048A, 0x048C, + 0x048E, 0x0490, 0x0492, 0x0494, 0x0496, 0x0498, 0x049A, 0x049C, + 0x049E, 0x04A0, 0x04A2, 0x04A4, 0x04A6, 0x04A8, 0x04AA, 0x04AC, + 0x04AE, 0x04B0, 0x04B2, 0x04B4, 0x04B6, 0x04B8, 0x04BA, 0x04BC, + 0x04BE, 0x04C0, 0x04C2, 0x04C4, 0x04C6, 0x04C8, 0x04CA, 0x04CC, + 0x04CE, 0x04D0, 0x04D2, 0x04D4, 0x04D6, 0x04D8, 0x04DA, 0x04DC, + 0x04DE, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA, 0x04EC, + 0x04EE, 0x04F0, 0x04F2, 0x04F4, 0x04F6, 0x04F8, 0x04FA, 0x04FC, + 0x04FE, 0x0A00, 0x0A02, 0x0A04, 0x0A06, 0x0A08, 0x0A0A, 0x0A0C, + 0x0A0E, 0x0A10, 0x0A12, 0x0A14, 0x0A16, 0x0A18, 0x0A1A, 0x0A1C, + 0x0A1E, 0x0A20, 0x0A22, 0x0A24, 0x0A26, 0x0A28, 0x0A2A, 0x0A2C, + 0x0A2E, 0x0A30, 0x0A32, 0x0A34, 0x0A36, 0x0A38, 0x0A3A, 0x0A3C, + 0x0A3E, 0x0A40, 0x0A42, 0x0A44, 0x0A46, 0x0A48, 0x0A4A, 0x0A4C, + 0x0A4E, 0x0A50, 0x0A52, 0x0A54, 0x0A56, 0x0A58, 0x0A5A, 0x0A5C, + 0x0A5E, 0x0A60, 0x0A62, 0x0A64, 0x0A66, 0x0A68, 0x0A6A, 0x0A6C, + 0x0A6E, 0x0A70, 0x0A72, 0x0A74, 0x0A76, 0x0A78, 0x0A7A, 0x0A7C, + 0x0A7E, 0x0A80, 0x0A82, 0x0A84, 0x0A86, 0x0A88, 0x0A8A, 0x0A8C, + 0x0A8E, 0x0A90, 0x0A92, 0x0A94, 0x0A96, 0x0A98, 0x0A9A, 0x0A9C, + 0x0A9E, 0x0AA0, 0x0AA2, 0x0AA4, 0x0AA6, 0x0AA8, 0x0AAA, 0x0AAC, + 0x0AAE, 0x0AB0, 0x0AB2, 0x0AB4, 0x0AB6, 0x0AB8, 0x0ABA, 0x0ABC, + 0x0ABE, 0x0AC0, 0x0AC2, 0x0AC4, 0x0AC6, 0x0AC8, 0x0ACA, 0x0ACC, + 0x0ACE, 0x0AD0, 0x0AD2, 0x0AD4, 0x0AD6, 0x0AD8, 0x0ADA, 0x0ADC, + 0x0ADE, 0x0AE0, 0x0AE2, 0x0AE4, 0x0AE6, 0x0AE8, 0x0AEA, 0x0AEC, + 0x0AEE, 0x0AF0, 0x0AF2, 0x0AF4, 0x0AF6, 0x0AF8, 0x0AFA, 0x0AFC, + 0x0AFE, 0x1800, 0x1802, 0x1804, 0x1806, 0x1808, 0x180A, 0x180C, + 0x180E, 0x1810, 0x1812, 0x1814, 0x1816, 0x1818, 0x181A, 0x181C, + 0x181E, 0x1820, 0x1822, 0x1824, 0x1826, 0x1828, 0x182A, 0x182C, + 0x182E, 0x1830, 0x1832, 0x1834, 0x1836, 0x1838, 0x183A, 0x183C, + 0x183E, 0x1840, 0x1842, 0x1844, 0x1846, 0x1848, 0x184A, 0x184C, + 0x184E, 0x1850, 0x1852, 0x1854, 0x1856, 0x1858, 0x185A, 0x185C, + 0x185E, 0x1860, 0x1862, 0x1864, 0x1866, 0x1868, 0x186A, 0x186C, + 0x186E, 0x1870, 0x1872, 0x1874, 0x1876, 0x1878, 0x187A, 0x187C, + 0x187E, 0x1880, 0x1882, 0x1884, 0x1886, 0x1888, 0x188A, 0x188C, + 0x188E, 0x1890, 0x1892, 0x1894, 0x1896, 0x1898, 0x189A, 0x189C, + 0x189E, 0x18A0, 0x18A2, 0x18A4, 0x18A6, 0x18A8, 0x18AA, 0x18AC, + 0x18AE, 0x18B0, 0x18B2, 0x18B4, 0x18B6, 0x18B8, 0x18BA, 0x18BC, + 0x18BE, 0x18C0, 0x18C2, 0x18C4, 0x18C6, 0x18C8, 0x18CA, 0x18CC, + 0x18CE, 0x18D0, 0x18D2, 0x18D4, 0x18D6, 0x18D8, 0x18DA, 0x18DC, + 0x18DE, 0x18E0, 0x18E2, 0x18E4, 0x18E6, 0x18E8, 0x18EA, 0x18EC, + 0x18EE, 0x18F0, 0x18F2, 0x18F4, 0x18F6, 0x18F8, 0x18FA, 0x18FC, + 0x18FE, 0x1600, 0x1602, 0x1604, 0x1606, 0x1608, 0x160A, 0x160C, + 0x160E, 0x1610, 0x1612, 0x1614, 0x1616, 0x1618, 0x161A, 0x161C, + 0x161E, 0x1620, 0x1622, 0x1624, 0x1626, 0x1628, 0x162A, 0x162C, + 0x162E, 0x1630, 0x1632, 0x1634, 0x1636, 0x1638, 0x163A, 0x163C, + 0x163E, 0x1640, 0x1642, 0x1644, 0x1646, 0x1648, 0x164A, 0x164C, + 0x164E, 0x1650, 0x1652, 0x1654, 0x1656, 0x1658, 0x165A, 0x165C, + 0x165E, 0x1660, 0x1662, 0x1664, 0x1666, 0x1668, 0x166A, 0x166C, + 0x166E, 0x1670, 0x1672, 0x1674, 0x1676, 0x1678, 0x167A, 0x167C, + 0x167E, 0x1680, 0x1682, 0x1684, 0x1686, 0x1688, 0x168A, 0x168C, + 0x168E, 0x1690, 0x1692, 0x1694, 0x1696, 0x1698, 0x169A, 0x169C, + 0x169E, 0x16A0, 0x16A2, 0x16A4, 0x16A6, 0x16A8, 0x16AA, 0x16AC, + 0x16AE, 0x16B0, 0x16B2, 0x16B4, 0x16B6, 0x16B8, 0x16BA, 0x16BC, + 0x16BE, 0x16C0, 0x16C2, 0x16C4, 0x16C6, 0x16C8, 0x16CA, 0x16CC, + 0x16CE, 0x16D0, 0x16D2, 0x16D4, 0x16D6, 0x16D8, 0x16DA, 0x16DC, + 0x16DE, 0x16E0, 0x16E2, 0x16E4, 0x16E6, 0x16E8, 0x16EA, 0x16EC, + 0x16EE, 0x16F0, 0x16F2, 0x16F4, 0x16F6, 0x16F8, 0x16FA, 0x16FC, + 0x16FE, 0x1700, 0x1702, 0x1704, 0x1706, 0x1708, 0x170A, 0x170C, + 0x170E, 0x1710, 0x1712, 0x1714, 0x1716, 0x1718, 0x171A, 0x171C, + 0x171E, 0x1720, 0x1722, 0x1724, 0x1726, 0x1728, 0x172A, 0x172C, + 0x172E, 0x1730, 0x1732, 0x1734, 0x1736, 0x1738, 0x173A, 0x173C, + 0x173E, 0x1740, 0x1742, 0x1744, 0x1746, 0x1748, 0x174A, 0x174C, + 0x174E, 0x1750, 0x1752, 0x1754, 0x1756, 0x1758, 0x175A, 0x175C, + 0x175E, 0x1760, 0x1762, 0x1764, 0x1766, 0x1768, 0x176A, 0x176C, + 0x176E, 0x1770, 0x1772, 0x1774, 0x1776, 0x1778, 0x177A, 0x177C, + 0x177E, 0x1780, 0x1782, 0x1784, 0x1786, 0x1788, 0x178A, 0x178C, + 0x178E, 0x1790, 0x1792, 0x1794, 0x1796, 0x1798, 0x179A, 0x179C, + 0x179E, 0x17A0, 0x17A2, 0x17A4, 0x17A6, 0x17A8, 0x17AA, 0x17AC, + 0x17AE, 0x17B0, 0x17B2, 0x17B4, 0x17B6, 0x17B8, 0x17BA, 0x17BC, + 0x17BE, 0x17C0, 0x17C2, 0x17C4, 0x17C6, 0x17C8, 0x17CA, 0x17CC, + 0x17CE, 0x17D0, 0x17D2, 0x17D4, 0x17D6, 0x17D8, 0x17DA, 0x17DC, + 0x17DE, 0x17E0, 0x17E2, 0x17E4, 0x17E6, 0x17E8, 0x17EA, 0x17EC, + 0x17EE, 0x17F0, 0x17F2, 0x17F4, 0x17F6, 0x17F8, 0x17FA, 0x17FC, + 0x17FE, 0x7600, 0x7602, 0x7604, 0x7606, 0x7608, 0x760A, 0x760C, + 0x760E, 0x7610, 0x7612, 0x7614, 0x7616, 0x7618, 0x761A, 0x761C, + 0x761E, 0x7620, 0x7622, 0x7624, 0x7626, 0x7628, 0x762A, 0x762C, + 0x762E, 0x7630, 0x7632, 0x7634, 0x7636, 0x7638, 0x763A, 0x763C, + 0x763E, 0x7640, 0x7642, 0x7644, 0x7646, 0x7648, 0x764A, 0x764C, + 0x764E, 0x7650, 0x7652, 0x7654, 0x7656, 0x7658, 0x765A, 0x765C, + 0x765E, 0x7660, 0x7662, 0x7664, 0x7666, 0x7668, 0x766A, 0x766C, + 0x766E, 0x7670, 0x7672, 0x7674, 0x7676, 0x7678, 0x767A, 0x767C, + 0x767E, 0x7680, 0x7682, 0x7684, 0x7686, 0x7688, 0x768A, 0x768C, + 0x768E, 0x7690, 0x7692, 0x7694, 0x7696, 0x7698, 0x769A, 0x769C, + 0x769E, 0x76A0, 0x76A2, 0x76A4, 0x76A6, 0x76A8, 0x76AA, 0x76AC, + 0x76AE, 0x76B0, 0x76B2, 0x76B4, 0x76B6, 0x76B8, 0x76BA, 0x76BC, + 0x76BE, 0x76C0, 0x76C2, 0x76C4, 0x76C6, 0x76C8, 0x76CA, 0x76CC, + 0x76CE, 0x76D0, 0x76D2, 0x76D4, 0x76D6, 0x76D8, 0x76DA, 0x76DC, + 0x76DE, 0x76E0, 0x76E2, 0x76E4, 0x76E6, 0x76E8, 0x76EA, 0x76EC, + 0x76EE, 0x76F0, 0x76F2, 0x76F4, 0x76F6, 0x76F8, 0x76FA, 0x76FC, + 0x76FE, 0x7700, 0x7702, 0x7704, 0x7706, 0x7708, 0x770A, 0x770C, + 0x770E, 0x7710, 0x7712, 0x7714, 0x7716, 0x7718, 0x771A, 0x771C, + 0x771E, 0x7720, 0x7722, 0x7724, 0x7726, 0x7728, 0x772A, 0x772C, + 0x772E, 0x7730, 0x7732, 0x7734, 0x7736, 0x7738, 0x773A, 0x773C, + 0x773E, 0x7740, 0x7742, 0x7744, 0x7746, 0x7748, 0x774A, 0x774C, + 0x774E, 0x7750, 0x7752, 0x7754, 0x7756, 0x7758, 0x775A, 0x775C, + 0x775E, 0x7760, 0x7762, 0x7764, 0x7766, 0x7768, 0x776A, 0x776C, + 0x776E, 0x7770, 0x7772, 0x7774, 0x7776, 0x7778, 0x777A, 0x777C, + 0x777E, 0x7780, 0x7782, 0x7784, 0x7786, 0x7788, 0x778A, 0x778C, + 0x778E, 0x7790, 0x7792, 0x7794, 0x7796, 0x7798, 0x779A, 0x779C, + 0x779E, 0x77A0, 0x77A2, 0x77A4, 0x77A6, 0x77A8, 0x77AA, 0x77AC, + 0x77AE, 0x77B0, 0x77B2, 0x77B4, 0x77B6, 0x77B8, 0x77BA, 0x77BC, + 0x77BE, 0x77C0, 0x77C2, 0x77C4, 0x77C6, 0x77C8, 0x77CA, 0x77CC, + 0x77CE, 0x77D0, 0x77D2, 0x77D4, 0x77D6, 0x77D8, 0x77DA, 0x77DC, + 0x77DE, 0x77E0, 0x77E2, 0x77E4, 0x77E6, 0x77E8, 0x77EA, 0x77EC, + 0x77EE, 0x77F0, 0x77F2, 0x77F4, 0x77F6, 0x77F8, 0x77FA, 0x77FC, + 0x3BFF, 0x77FD, 0x77FB, 0x77F9, 0x77F7, 0x77F5, 0x77F3, 0x77F1, + 0x77EF, 0x77ED, 0x77EB, 0x77E9, 0x77E7, 0x77E5, 0x77E3, 0x77E1, + 0x77DF, 0x77DD, 0x77DB, 0x77D9, 0x77D7, 0x77D5, 0x77D3, 0x77D1, + 0x77CF, 0x77CD, 0x77CB, 0x77C9, 0x77C7, 0x77C5, 0x77C3, 0x77C1, + 0x77BF, 0x77BD, 0x77BB, 0x77B9, 0x77B7, 0x77B5, 0x77B3, 0x77B1, + 0x77AF, 0x77AD, 0x77AB, 0x77A9, 0x77A7, 0x77A5, 0x77A3, 0x77A1, + 0x779F, 0x779D, 0x779B, 0x7799, 0x7797, 0x7795, 0x7793, 0x7791, + 0x778F, 0x778D, 0x778B, 0x7789, 0x7787, 0x7785, 0x7783, 0x7781, + 0x777F, 0x777D, 0x777B, 0x7779, 0x7777, 0x7775, 0x7773, 0x7771, + 0x776F, 0x776D, 0x776B, 0x7769, 0x7767, 0x7765, 0x7763, 0x7761, + 0x775F, 0x775D, 0x775B, 0x7759, 0x7757, 0x7755, 0x7753, 0x7751, + 0x774F, 0x774D, 0x774B, 0x7749, 0x7747, 0x7745, 0x7743, 0x7741, + 0x773F, 0x773D, 0x773B, 0x7739, 0x7737, 0x7735, 0x7733, 0x7731, + 0x772F, 0x772D, 0x772B, 0x7729, 0x7727, 0x7725, 0x7723, 0x7721, + 0x771F, 0x771D, 0x771B, 0x7719, 0x7717, 0x7715, 0x7713, 0x7711, + 0x770F, 0x770D, 0x770B, 0x7709, 0x7707, 0x7705, 0x7703, 0x7701, + 0x76FF, 0x76FD, 0x76FB, 0x76F9, 0x76F7, 0x76F5, 0x76F3, 0x76F1, + 0x76EF, 0x76ED, 0x76EB, 0x76E9, 0x76E7, 0x76E5, 0x76E3, 0x76E1, + 0x76DF, 0x76DD, 0x76DB, 0x76D9, 0x76D7, 0x76D5, 0x76D3, 0x76D1, + 0x76CF, 0x76CD, 0x76CB, 0x76C9, 0x76C7, 0x76C5, 0x76C3, 0x76C1, + 0x76BF, 0x76BD, 0x76BB, 0x76B9, 0x76B7, 0x76B5, 0x76B3, 0x76B1, + 0x76AF, 0x76AD, 0x76AB, 0x76A9, 0x76A7, 0x76A5, 0x76A3, 0x76A1, + 0x769F, 0x769D, 0x769B, 0x7699, 0x7697, 0x7695, 0x7693, 0x7691, + 0x768F, 0x768D, 0x768B, 0x7689, 0x7687, 0x7685, 0x7683, 0x7681, + 0x767F, 0x767D, 0x767B, 0x7679, 0x7677, 0x7675, 0x7673, 0x7671, + 0x766F, 0x766D, 0x766B, 0x7669, 0x7667, 0x7665, 0x7663, 0x7661, + 0x765F, 0x765D, 0x765B, 0x7659, 0x7657, 0x7655, 0x7653, 0x7651, + 0x764F, 0x764D, 0x764B, 0x7649, 0x7647, 0x7645, 0x7643, 0x7641, + 0x763F, 0x763D, 0x763B, 0x7639, 0x7637, 0x7635, 0x7633, 0x7631, + 0x762F, 0x762D, 0x762B, 0x7629, 0x7627, 0x7625, 0x7623, 0x7621, + 0x761F, 0x761D, 0x761B, 0x7619, 0x7617, 0x7615, 0x7613, 0x7611, + 0x760F, 0x760D, 0x760B, 0x7609, 0x7607, 0x7605, 0x7603, 0x7601, + 0x17FF, 0x17FD, 0x17FB, 0x17F9, 0x17F7, 0x17F5, 0x17F3, 0x17F1, + 0x17EF, 0x17ED, 0x17EB, 0x17E9, 0x17E7, 0x17E5, 0x17E3, 0x17E1, + 0x17DF, 0x17DD, 0x17DB, 0x17D9, 0x17D7, 0x17D5, 0x17D3, 0x17D1, + 0x17CF, 0x17CD, 0x17CB, 0x17C9, 0x17C7, 0x17C5, 0x17C3, 0x17C1, + 0x17BF, 0x17BD, 0x17BB, 0x17B9, 0x17B7, 0x17B5, 0x17B3, 0x17B1, + 0x17AF, 0x17AD, 0x17AB, 0x17A9, 0x17A7, 0x17A5, 0x17A3, 0x17A1, + 0x179F, 0x179D, 0x179B, 0x1799, 0x1797, 0x1795, 0x1793, 0x1791, + 0x178F, 0x178D, 0x178B, 0x1789, 0x1787, 0x1785, 0x1783, 0x1781, + 0x177F, 0x177D, 0x177B, 0x1779, 0x1777, 0x1775, 0x1773, 0x1771, + 0x176F, 0x176D, 0x176B, 0x1769, 0x1767, 0x1765, 0x1763, 0x1761, + 0x175F, 0x175D, 0x175B, 0x1759, 0x1757, 0x1755, 0x1753, 0x1751, + 0x174F, 0x174D, 0x174B, 0x1749, 0x1747, 0x1745, 0x1743, 0x1741, + 0x173F, 0x173D, 0x173B, 0x1739, 0x1737, 0x1735, 0x1733, 0x1731, + 0x172F, 0x172D, 0x172B, 0x1729, 0x1727, 0x1725, 0x1723, 0x1721, + 0x171F, 0x171D, 0x171B, 0x1719, 0x1717, 0x1715, 0x1713, 0x1711, + 0x170F, 0x170D, 0x170B, 0x1709, 0x1707, 0x1705, 0x1703, 0x1701, + 0x16FF, 0x16FD, 0x16FB, 0x16F9, 0x16F7, 0x16F5, 0x16F3, 0x16F1, + 0x16EF, 0x16ED, 0x16EB, 0x16E9, 0x16E7, 0x16E5, 0x16E3, 0x16E1, + 0x16DF, 0x16DD, 0x16DB, 0x16D9, 0x16D7, 0x16D5, 0x16D3, 0x16D1, + 0x16CF, 0x16CD, 0x16CB, 0x16C9, 0x16C7, 0x16C5, 0x16C3, 0x16C1, + 0x16BF, 0x16BD, 0x16BB, 0x16B9, 0x16B7, 0x16B5, 0x16B3, 0x16B1, + 0x16AF, 0x16AD, 0x16AB, 0x16A9, 0x16A7, 0x16A5, 0x16A3, 0x16A1, + 0x169F, 0x169D, 0x169B, 0x1699, 0x1697, 0x1695, 0x1693, 0x1691, + 0x168F, 0x168D, 0x168B, 0x1689, 0x1687, 0x1685, 0x1683, 0x1681, + 0x167F, 0x167D, 0x167B, 0x1679, 0x1677, 0x1675, 0x1673, 0x1671, + 0x166F, 0x166D, 0x166B, 0x1669, 0x1667, 0x1665, 0x1663, 0x1661, + 0x165F, 0x165D, 0x165B, 0x1659, 0x1657, 0x1655, 0x1653, 0x1651, + 0x164F, 0x164D, 0x164B, 0x1649, 0x1647, 0x1645, 0x1643, 0x1641, + 0x163F, 0x163D, 0x163B, 0x1639, 0x1637, 0x1635, 0x1633, 0x1631, + 0x162F, 0x162D, 0x162B, 0x1629, 0x1627, 0x1625, 0x1623, 0x1621, + 0x161F, 0x161D, 0x161B, 0x1619, 0x1617, 0x1615, 0x1613, 0x1611, + 0x160F, 0x160D, 0x160B, 0x1609, 0x1607, 0x1605, 0x1603, 0x1601, + 0x18FF, 0x18FD, 0x18FB, 0x18F9, 0x18F7, 0x18F5, 0x18F3, 0x18F1, + 0x18EF, 0x18ED, 0x18EB, 0x18E9, 0x18E7, 0x18E5, 0x18E3, 0x18E1, + 0x18DF, 0x18DD, 0x18DB, 0x18D9, 0x18D7, 0x18D5, 0x18D3, 0x18D1, + 0x18CF, 0x18CD, 0x18CB, 0x18C9, 0x18C7, 0x18C5, 0x18C3, 0x18C1, + 0x18BF, 0x18BD, 0x18BB, 0x18B9, 0x18B7, 0x18B5, 0x18B3, 0x18B1, + 0x18AF, 0x18AD, 0x18AB, 0x18A9, 0x18A7, 0x18A5, 0x18A3, 0x18A1, + 0x189F, 0x189D, 0x189B, 0x1899, 0x1897, 0x1895, 0x1893, 0x1891, + 0x188F, 0x188D, 0x188B, 0x1889, 0x1887, 0x1885, 0x1883, 0x1881, + 0x187F, 0x187D, 0x187B, 0x1879, 0x1877, 0x1875, 0x1873, 0x1871, + 0x186F, 0x186D, 0x186B, 0x1869, 0x1867, 0x1865, 0x1863, 0x1861, + 0x185F, 0x185D, 0x185B, 0x1859, 0x1857, 0x1855, 0x1853, 0x1851, + 0x184F, 0x184D, 0x184B, 0x1849, 0x1847, 0x1845, 0x1843, 0x1841, + 0x183F, 0x183D, 0x183B, 0x1839, 0x1837, 0x1835, 0x1833, 0x1831, + 0x182F, 0x182D, 0x182B, 0x1829, 0x1827, 0x1825, 0x1823, 0x1821, + 0x181F, 0x181D, 0x181B, 0x1819, 0x1817, 0x1815, 0x1813, 0x1811, + 0x180F, 0x180D, 0x180B, 0x1809, 0x1807, 0x1805, 0x1803, 0x1801, + 0x0AFF, 0x0AFD, 0x0AFB, 0x0AF9, 0x0AF7, 0x0AF5, 0x0AF3, 0x0AF1, + 0x0AEF, 0x0AED, 0x0AEB, 0x0AE9, 0x0AE7, 0x0AE5, 0x0AE3, 0x0AE1, + 0x0ADF, 0x0ADD, 0x0ADB, 0x0AD9, 0x0AD7, 0x0AD5, 0x0AD3, 0x0AD1, + 0x0ACF, 0x0ACD, 0x0ACB, 0x0AC9, 0x0AC7, 0x0AC5, 0x0AC3, 0x0AC1, + 0x0ABF, 0x0ABD, 0x0ABB, 0x0AB9, 0x0AB7, 0x0AB5, 0x0AB3, 0x0AB1, + 0x0AAF, 0x0AAD, 0x0AAB, 0x0AA9, 0x0AA7, 0x0AA5, 0x0AA3, 0x0AA1, + 0x0A9F, 0x0A9D, 0x0A9B, 0x0A99, 0x0A97, 0x0A95, 0x0A93, 0x0A91, + 0x0A8F, 0x0A8D, 0x0A8B, 0x0A89, 0x0A87, 0x0A85, 0x0A83, 0x0A81, + 0x0A7F, 0x0A7D, 0x0A7B, 0x0A79, 0x0A77, 0x0A75, 0x0A73, 0x0A71, + 0x0A6F, 0x0A6D, 0x0A6B, 0x0A69, 0x0A67, 0x0A65, 0x0A63, 0x0A61, + 0x0A5F, 0x0A5D, 0x0A5B, 0x0A59, 0x0A57, 0x0A55, 0x0A53, 0x0A51, + 0x0A4F, 0x0A4D, 0x0A4B, 0x0A49, 0x0A47, 0x0A45, 0x0A43, 0x0A41, + 0x0A3F, 0x0A3D, 0x0A3B, 0x0A39, 0x0A37, 0x0A35, 0x0A33, 0x0A31, + 0x0A2F, 0x0A2D, 0x0A2B, 0x0A29, 0x0A27, 0x0A25, 0x0A23, 0x0A21, + 0x0A1F, 0x0A1D, 0x0A1B, 0x0A19, 0x0A17, 0x0A15, 0x0A13, 0x0A11, + 0x0A0F, 0x0A0D, 0x0A0B, 0x0A09, 0x0A07, 0x0A05, 0x0A03, 0x0A01, + 0x04FF, 0x04FD, 0x04FB, 0x04F9, 0x04F7, 0x04F5, 0x04F3, 0x04F1, + 0x04EF, 0x04ED, 0x04EB, 0x04E9, 0x04E7, 0x04E5, 0x04E3, 0x04E1, + 0x04DF, 0x04DD, 0x04DB, 0x04D9, 0x04D7, 0x04D5, 0x04D3, 0x04D1, + 0x04CF, 0x04CD, 0x04CB, 0x04C9, 0x04C7, 0x04C5, 0x04C3, 0x04C1, + 0x04BF, 0x04BD, 0x04BB, 0x04B9, 0x04B7, 0x04B5, 0x04B3, 0x04B1, + 0x04AF, 0x04AD, 0x04AB, 0x04A9, 0x04A7, 0x04A5, 0x04A3, 0x04A1, + 0x049F, 0x049D, 0x049B, 0x0499, 0x0497, 0x0495, 0x0493, 0x0491, + 0x048F, 0x048D, 0x048B, 0x0489, 0x0487, 0x0485, 0x0483, 0x0481, + 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, + 0x00EF, 0x00ED, 0x00EB, 0x00E9, 0x00E7, 0x00E5, 0x00E3, 0x00E1, + 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, + 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, + 0x00BF, 0x00BD, 0x00BB, 0x00B9, 0x00B7, 0x00B5, 0x00B3, 0x00B1, + 0x00AF, 0x00AD, 0x00AB, 0x00A9, 0x00A7, 0x00A5, 0x00A3, 0x00A1, + 0x009F, 0x009D, 0x009B, 0x0099, 0x0097, 0x0095, 0x0093, 0x0091, + 0x008F, 0x008D, 0x008B, 0x0089, 0x0087, 0x0085, 0x0083, 0x0081, + 0x023F, 0x023D, 0x023B, 0x0239, 0x0237, 0x0235, 0x0233, 0x0231, + 0x022F, 0x022D, 0x022B, 0x0229, 0x0227, 0x0225, 0x0223, 0x0221, + 0x021F, 0x021D, 0x021B, 0x0219, 0x0217, 0x0215, 0x0213, 0x0211, + 0x020F, 0x020D, 0x020B, 0x0209, 0x0207, 0x0205, 0x0203, 0x0201, + 0x003F, 0x003D, 0x003B, 0x0039, 0x0037, 0x0035, 0x0033, 0x0031, + 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0021, + 0x001F, 0x001D, 0x001B, 0x0019, 0x0017, 0x0015, 0x0013, 0x0011, + 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, + 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, + 0x00EF, 0x00ED, 0x00EB, 0x00E9, 0x00E7, 0x00E5, 0x00E3, 0x00E1, + 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, + 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, + 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, + 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, + 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, + 0x0075, 0x0073, 0x0071, 0x006F, 0x006D, 0x006B, 0x0069, 0x0067, +}; + +static const uint8_t dc11_vlc_lens[2048] = { + 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 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, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 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, 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, 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, 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, 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, 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, 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, + 14, 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, 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, + 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, + 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, + 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, + 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, + 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, + 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, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 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, + 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, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, +}; + + +static HQXAC hqx_ac[NUM_HQX_AC] = { + { 10 }, { 11 }, { 11 }, { 11 }, { 12 }, { 11 }, +}; + +// level is in -255..255 range, run 0..64, so it fits into 16 bits. +// We offset run by 1 in order to include the implicit run of 1. +#define E(level, run) ((level * 128) | (run + 1)) + +static const int16_t hqx_ac_run_level[] = { + // AC table Q0 - 815 elements + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), + E( -3, 0), E( 4, 0), E( -4, 0), E( 1, 1), E( -1, 1), + E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), E( 7, 0), + E( -7, 0), E( 8, 0), E( -8, 0), E( 0, 0), E( 1, 0), + E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), E( -3, 0), + E( 4, 0), E( -4, 0), E( 5, 0), E( -5, 0), E( 6, 0), + E( -6, 0), E( 7, 0), E( -7, 0), E( 8, 0), E( -8, 0), + E( 9, 0), E( -9, 0), E( 10, 0), E( -10, 0), E( 11, 0), + E( -11, 0), E( 12, 0), E( -12, 0), E( 13, 0), E( -13, 0), + E( 14, 0), E( -14, 0), E( 15, 0), E( -15, 0), E( 16, 0), + E( -16, 0), E( 17, 0), E( -17, 0), E( 18, 0), E( -18, 0), + E( 19, 0), E( -19, 0), E( 20, 0), E( -20, 0), E( 21, 0), + E( -21, 0), E( 22, 0), E( -22, 0), E( 23, 0), E( -23, 0), + E( 24, 0), E( -24, 0), E( 25, 0), E( -25, 0), E( 26, 0), + E( -26, 0), E( 27, 0), E( -27, 0), E( 28, 0), E( -28, 0), + E( 29, 0), E( -29, 0), E( 30, 0), E( -30, 0), E( 31, 0), + E( -31, 0), E( 32, 0), E( -32, 0), E( 33, 0), E( -33, 0), + E( 34, 0), E( -34, 0), E( 35, 0), E( -35, 0), E( 36, 0), + E( -36, 0), E( 37, 0), E( -37, 0), E( 38, 0), E( -38, 0), + E( 39, 0), E( -39, 0), E( 40, 0), E( -40, 0), E( 41, 0), + E( -41, 0), E( 42, 0), E( -42, 0), E( 43, 0), E( -43, 0), + E( 44, 0), E( -44, 0), E( 45, 0), E( -45, 0), E( 46, 0), + E( -46, 0), E( 47, 0), E( -47, 0), E( 48, 0), E( -48, 0), + E( 49, 0), E( -49, 0), E( 50, 0), E( -50, 0), E( 51, 0), + E( -51, 0), E( 52, 0), E( -52, 0), E( 53, 0), E( -53, 0), + E( 54, 0), E( -54, 0), E( 55, 0), E( -55, 0), E( 56, 0), + E( -56, 0), E( 57, 0), E( -57, 0), E( 58, 0), E( -58, 0), + E( 59, 0), E( -59, 0), E( 60, 0), E( -60, 0), E( 61, 0), + E( -61, 0), E( 62, 0), E( -62, 0), E( 63, 0), E( -63, 0), + E( 64, 0), E( -64, 0), E( 65, 0), E( -65, 0), E( 66, 0), + E( -66, 0), E( 67, 0), E( -67, 0), E( 68, 0), E( -68, 0), + E( 69, 0), E( -69, 0), E( 70, 0), E( -70, 0), E( 71, 0), + E( -71, 0), E( 72, 0), E( -72, 0), E( 73, 0), E( -73, 0), + E( 74, 0), E( -74, 0), E( 75, 0), E( -75, 0), E( 76, 0), + E( -76, 0), E( 77, 0), E( -77, 0), E( 78, 0), E( -78, 0), + E( 79, 0), E( -79, 0), E( 80, 0), E( -80, 0), E( 81, 0), + E( -81, 0), E( 82, 0), E( -82, 0), E( 83, 0), E( -83, 0), + E( 84, 0), E( -84, 0), E( 85, 0), E( -85, 0), E( 86, 0), + E( -86, 0), E( 87, 0), E( -87, 0), E( 88, 0), E( -88, 0), + E( 89, 0), E( -89, 0), E( 90, 0), E( -90, 0), E( 91, 0), + E( -91, 0), E( 92, 0), E( -92, 0), E( 93, 0), E( -93, 0), + E( 94, 0), E( -94, 0), E( 95, 0), E( -95, 0), E( 96, 0), + E( -96, 0), E( 97, 0), E( -97, 0), E( 98, 0), E( -98, 0), + E( 99, 0), E( -99, 0), E( 100, 0), E(-100, 0), E( 101, 0), + E(-101, 0), E( 102, 0), E(-102, 0), E( 103, 0), E(-103, 0), + E( 104, 0), E(-104, 0), E( 105, 0), E(-105, 0), E( 106, 0), + E(-106, 0), E( 107, 0), E(-107, 0), E( 108, 0), E(-108, 0), + E( 109, 0), E(-109, 0), E( 110, 0), E(-110, 0), E( 111, 0), + E(-111, 0), E( 112, 0), E(-112, 0), E( 113, 0), E(-113, 0), + E( 114, 0), E(-114, 0), E( 115, 0), E(-115, 0), E( 116, 0), + E(-116, 0), E( 117, 0), E(-117, 0), E( 118, 0), E(-118, 0), + E( 119, 0), E(-119, 0), E( 120, 0), E(-120, 0), E( 121, 0), + E(-121, 0), E( 122, 0), E(-122, 0), E( 123, 0), E(-123, 0), + E( 124, 0), E(-124, 0), E( 125, 0), E(-125, 0), E( 126, 0), + E(-126, 0), E( 127, 0), E(-127, 0), E( 128, 0), E(-128, 0), + E( 129, 0), E(-129, 0), E( 130, 0), E(-130, 0), E( 131, 0), + E(-131, 0), E( 132, 0), E(-132, 0), E( 133, 0), E(-133, 0), + E( 134, 0), E(-134, 0), E( 135, 0), E(-135, 0), E( 136, 0), + E(-136, 0), E( 137, 0), E(-137, 0), E( 138, 0), E(-138, 0), + E( 139, 0), E(-139, 0), E( 140, 0), E(-140, 0), E( 141, 0), + E(-141, 0), E( 142, 0), E(-142, 0), E( 143, 0), E(-143, 0), + E( 144, 0), E(-144, 0), E( 145, 0), E(-145, 0), E( 146, 0), + E(-146, 0), E( 147, 0), E(-147, 0), E( 148, 0), E(-148, 0), + E( 149, 0), E(-149, 0), E( 150, 0), E(-150, 0), E( 151, 0), + E(-151, 0), E( 152, 0), E(-152, 0), E( 153, 0), E(-153, 0), + E( 154, 0), E(-154, 0), E( 155, 0), E(-155, 0), E( 156, 0), + E(-156, 0), E( 157, 0), E(-157, 0), E( 158, 0), E(-158, 0), + E( 159, 0), E(-159, 0), E( 160, 0), E(-160, 0), E( 161, 0), + E(-161, 0), E( 162, 0), E(-162, 0), E( 163, 0), E(-163, 0), + E( 164, 0), E(-164, 0), E( 165, 0), E(-165, 0), E( 166, 0), + E(-166, 0), E( 167, 0), E(-167, 0), E( 168, 0), E(-168, 0), + E( 169, 0), E(-169, 0), E( 170, 0), E(-170, 0), E( 171, 0), + E(-171, 0), E( 172, 0), E(-172, 0), E( 173, 0), E(-173, 0), + E( 174, 0), E(-174, 0), E( 175, 0), E(-175, 0), E( 176, 0), + E(-176, 0), E( 177, 0), E(-177, 0), E( 178, 0), E(-178, 0), + E( 179, 0), E(-179, 0), E( 180, 0), E(-180, 0), E( 181, 0), + E(-181, 0), E( 182, 0), E(-182, 0), E( 183, 0), E(-183, 0), + E( 184, 0), E(-184, 0), E( 185, 0), E(-185, 0), E( 186, 0), + E(-186, 0), E( 187, 0), E(-187, 0), E( 188, 0), E(-188, 0), + E( 189, 0), E(-189, 0), E( 190, 0), E(-190, 0), E( 191, 0), + E(-191, 0), E( 192, 0), E(-192, 0), E( 193, 0), E(-193, 0), + E( 194, 0), E(-194, 0), E( 195, 0), E(-195, 0), E( 196, 0), + E(-196, 0), E( 197, 0), E(-197, 0), E( 198, 0), E(-198, 0), + E( 199, 0), E(-199, 0), E( 200, 0), E(-200, 0), E( 201, 0), + E(-201, 0), E( 202, 0), E(-202, 0), E( 203, 0), E(-203, 0), + E( 204, 0), E(-204, 0), E( 205, 0), E(-205, 0), E( 206, 0), + E(-206, 0), E( 207, 0), E(-207, 0), E( 208, 0), E(-208, 0), + E( 209, 0), E(-209, 0), E( 210, 0), E(-210, 0), E( 211, 0), + E(-211, 0), E( 212, 0), E(-212, 0), E( 213, 0), E(-213, 0), + E( 214, 0), E(-214, 0), E( 215, 0), E(-215, 0), E( 216, 0), + E(-216, 0), E( 217, 0), E(-217, 0), E( 218, 0), E(-218, 0), + E( 219, 0), E(-219, 0), E( 220, 0), E(-220, 0), E( 221, 0), + E(-221, 0), E( 222, 0), E(-222, 0), E( 223, 0), E(-223, 0), + E( 224, 0), E(-224, 0), E( 225, 0), E(-225, 0), E( 226, 0), + E(-226, 0), E( 227, 0), E(-227, 0), E( 228, 0), E(-228, 0), + E( 229, 0), E(-229, 0), E( 230, 0), E(-230, 0), E( 231, 0), + E(-231, 0), E( 232, 0), E(-232, 0), E( 233, 0), E(-233, 0), + E( 234, 0), E(-234, 0), E( 235, 0), E(-235, 0), E( 236, 0), + E(-236, 0), E( 237, 0), E(-237, 0), E( 238, 0), E(-238, 0), + E( 239, 0), E(-239, 0), E( 240, 0), E(-240, 0), E( 241, 0), + E(-241, 0), E( 242, 0), E(-242, 0), E( 243, 0), E(-243, 0), + E( 244, 0), E(-244, 0), E( 245, 0), E(-245, 0), E( 246, 0), + E(-246, 0), E( 247, 0), E(-247, 0), E( 248, 0), E(-248, 0), + E( 249, 0), E(-249, 0), E( 250, 0), E(-250, 0), E( 251, 0), + E(-251, 0), E( 252, 0), E(-252, 0), E( 253, 0), E(-253, 0), + E( 254, 0), E(-254, 0), E( 255, 0), E(-255, 0), E( 0, 64), + E( 9, 0), E( -9, 0), E( 10, 0), E( -10, 0), E( 11, 0), + E( -11, 0), E( 12, 0), E( -12, 0), E( 13, 0), E( -13, 0), + E( 14, 0), E( -14, 0), E( 2, 1), E( -2, 1), E( 1, 2), + E( -1, 2), E( 15, 0), E( -15, 0), E( 16, 0), E( -16, 0), + E( 17, 0), E( -17, 0), E( 18, 0), E( -18, 0), E( 19, 0), + E( -19, 0), E( 20, 0), E( -20, 0), E( 21, 0), E( -21, 0), + E( 3, 1), E( -3, 1), E( 4, 1), E( -4, 1), E( 1, 3), + E( -1, 3), E( 1, 4), E( -1, 4), E( 0, 0), E( 22, 0), + E( -22, 0), E( 23, 0), E( -23, 0), E( 24, 0), E( -24, 0), + E( 25, 0), E( -25, 0), E( 26, 0), E( -26, 0), E( 27, 0), + E( -27, 0), E( 28, 0), E( -28, 0), E( 29, 0), E( -29, 0), + E( 30, 0), E( -30, 0), E( 31, 0), E( -31, 0), E( 32, 0), + E( -32, 0), E( 33, 0), E( -33, 0), E( 5, 1), E( -5, 1), + E( 6, 1), E( -6, 1), E( 2, 2), E( -2, 2), E( 1, 5), + E( -1, 5), E( 1, 6), E( -1, 6), E( 34, 0), E( -34, 0), + E( 35, 0), E( -35, 0), E( 36, 0), E( -36, 0), E( 37, 0), + E( -37, 0), E( 38, 0), E( -38, 0), E( 39, 0), E( -39, 0), + E( 40, 0), E( -40, 0), E( 41, 0), E( -41, 0), E( 42, 0), + E( -42, 0), E( 43, 0), E( -43, 0), E( 44, 0), E( -44, 0), + E( 45, 0), E( -45, 0), E( 46, 0), E( -46, 0), E( 47, 0), + E( -47, 0), E( 48, 0), E( -48, 0), E( 49, 0), E( -49, 0), + E( 50, 0), E( -50, 0), E( 0, 1), E( 7, 1), E( -7, 1), + E( 8, 1), E( -8, 1), E( 9, 1), E( -9, 1), E( 10, 1), + E( -10, 1), E( 0, 2), E( 3, 2), E( -3, 2), E( 0, 3), + E( 2, 3), E( -2, 3), E( 1, 7), E( -1, 7), E( 1, 8), + E( -1, 8), E( 0, 0), E( 0, 1), E( 0, 2), E( 0, 3), + E( 0, 4), E( 0, 5), E( 0, 6), E( 0, 7), E( 0, 8), + E( 0, 9), E( 0, 10), E( 0, 11), E( 0, 12), E( 0, 13), + E( 0, 14), E( 0, 15), E( 0, 16), E( 0, 17), E( 0, 18), + E( 0, 19), E( 0, 20), E( 0, 21), E( 0, 22), E( 0, 23), + E( 0, 24), E( 0, 25), E( 0, 26), E( 0, 27), E( 0, 28), + E( 0, 29), E( 0, 30), E( 0, 31), E( 0, 32), E( 0, 33), + E( 0, 34), E( 0, 35), E( 0, 36), E( 0, 37), E( 0, 38), + E( 0, 39), E( 0, 40), E( 0, 41), E( 0, 42), E( 0, 43), + E( 0, 44), E( 0, 45), E( 0, 46), E( 0, 47), E( 0, 48), + E( 0, 49), E( 0, 50), E( 0, 51), E( 0, 52), E( 0, 53), + E( 0, 54), E( 0, 55), E( 0, 56), E( 0, 57), E( 0, 58), + E( 0, 59), E( 0, 60), E( 0, 61), E( 0, 62), E( 0, 63), + E( 51, 0), E( -51, 0), E( 52, 0), E( -52, 0), E( 53, 0), + E( -53, 0), E( 54, 0), E( -54, 0), E( 55, 0), E( -55, 0), + E( 56, 0), E( -56, 0), E( 57, 0), E( -57, 0), E( 58, 0), + E( -58, 0), E( 59, 0), E( -59, 0), E( 60, 0), E( -60, 0), + E( 61, 0), E( -61, 0), E( 62, 0), E( -62, 0), E( 63, 0), + E( -63, 0), E( 11, 1), E( -11, 1), E( 12, 1), E( -12, 1), + E( 13, 1), E( -13, 1), E( 14, 1), E( -14, 1), E( 4, 2), + E( -4, 2), E( 5, 2), E( -5, 2), E( 6, 2), E( -6, 2), + E( 3, 3), E( -3, 3), E( 0, 4), E( 2, 4), E( -2, 4), + E( 0, 5), E( 0, 6), E( 1, 9), E( -1, 9), E( 1, 10), + E( -1, 10), E( 15, 1), E( -15, 1), E( 16, 1), E( -16, 1), + E( 17, 1), E( -17, 1), E( 18, 1), E( -18, 1), E( 7, 2), + E( -7, 2), E( 8, 2), E( -8, 2), E( 9, 2), E( -9, 2), + E( 10, 2), E( -10, 2), E( 4, 3), E( -4, 3), E( 5, 3), + E( -5, 3), E( 6, 3), E( -6, 3), E( 2, 5), E( -2, 5), + E( 0, 7), E( 0, 8), E( 0, 9), E( 0, 10), E( 1, 11), + E( -1, 11), E( 1, 12), E( -1, 12), E( 1, 13), E( -1, 13), + E( 1, 14), E( -1, 14), E( 19, 1), E( -19, 1), E( 20, 1), + E( -20, 1), E( 3, 4), E( -3, 4), E( 2, 6), E( -2, 6), + // AC table Q8 - 907 elements + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), + E( -3, 0), E( 4, 0), E( -4, 0), E( 0, 64), E( 5, 0), + E( -5, 0), E( 6, 0), E( -6, 0), E( 7, 0), E( -7, 0), + E( 8, 0), E( -8, 0), E( 1, 1), E( -1, 1), E( 2, 1), + E( -2, 1), E( 9, 0), E( -9, 0), E( 10, 0), E( -10, 0), + E( 11, 0), E( -11, 0), E( 12, 0), E( -12, 0), E( 3, 1), + E( -3, 1), E( 4, 1), E( -4, 1), E( 1, 2), E( -1, 2), + E( 0, 0), E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), + E( 3, 0), E( -3, 0), E( 4, 0), E( -4, 0), E( 5, 0), + E( -5, 0), E( 6, 0), E( -6, 0), E( 7, 0), E( -7, 0), + E( 8, 0), E( -8, 0), E( 9, 0), E( -9, 0), E( 10, 0), + E( -10, 0), E( 11, 0), E( -11, 0), E( 12, 0), E( -12, 0), + E( 13, 0), E( -13, 0), E( 14, 0), E( -14, 0), E( 15, 0), + E( -15, 0), E( 16, 0), E( -16, 0), E( 17, 0), E( -17, 0), + E( 18, 0), E( -18, 0), E( 19, 0), E( -19, 0), E( 20, 0), + E( -20, 0), E( 21, 0), E( -21, 0), E( 22, 0), E( -22, 0), + E( 23, 0), E( -23, 0), E( 24, 0), E( -24, 0), E( 25, 0), + E( -25, 0), E( 26, 0), E( -26, 0), E( 27, 0), E( -27, 0), + E( 28, 0), E( -28, 0), E( 29, 0), E( -29, 0), E( 30, 0), + E( -30, 0), E( 31, 0), E( -31, 0), E( 32, 0), E( -32, 0), + E( 33, 0), E( -33, 0), E( 34, 0), E( -34, 0), E( 35, 0), + E( -35, 0), E( 36, 0), E( -36, 0), E( 37, 0), E( -37, 0), + E( 38, 0), E( -38, 0), E( 39, 0), E( -39, 0), E( 40, 0), + E( -40, 0), E( 41, 0), E( -41, 0), E( 42, 0), E( -42, 0), + E( 43, 0), E( -43, 0), E( 44, 0), E( -44, 0), E( 45, 0), + E( -45, 0), E( 46, 0), E( -46, 0), E( 47, 0), E( -47, 0), + E( 48, 0), E( -48, 0), E( 49, 0), E( -49, 0), E( 50, 0), + E( -50, 0), E( 51, 0), E( -51, 0), E( 52, 0), E( -52, 0), + E( 53, 0), E( -53, 0), E( 54, 0), E( -54, 0), E( 55, 0), + E( -55, 0), E( 56, 0), E( -56, 0), E( 57, 0), E( -57, 0), + E( 58, 0), E( -58, 0), E( 59, 0), E( -59, 0), E( 60, 0), + E( -60, 0), E( 61, 0), E( -61, 0), E( 62, 0), E( -62, 0), + E( 63, 0), E( -63, 0), E( 64, 0), E( -64, 0), E( 65, 0), + E( -65, 0), E( 66, 0), E( -66, 0), E( 67, 0), E( -67, 0), + E( 68, 0), E( -68, 0), E( 69, 0), E( -69, 0), E( 70, 0), + E( -70, 0), E( 71, 0), E( -71, 0), E( 72, 0), E( -72, 0), + E( 73, 0), E( -73, 0), E( 74, 0), E( -74, 0), E( 75, 0), + E( -75, 0), E( 76, 0), E( -76, 0), E( 77, 0), E( -77, 0), + E( 78, 0), E( -78, 0), E( 79, 0), E( -79, 0), E( 80, 0), + E( -80, 0), E( 81, 0), E( -81, 0), E( 82, 0), E( -82, 0), + E( 83, 0), E( -83, 0), E( 84, 0), E( -84, 0), E( 85, 0), + E( -85, 0), E( 86, 0), E( -86, 0), E( 87, 0), E( -87, 0), + E( 88, 0), E( -88, 0), E( 89, 0), E( -89, 0), E( 90, 0), + E( -90, 0), E( 91, 0), E( -91, 0), E( 92, 0), E( -92, 0), + E( 93, 0), E( -93, 0), E( 94, 0), E( -94, 0), E( 95, 0), + E( -95, 0), E( 96, 0), E( -96, 0), E( 97, 0), E( -97, 0), + E( 98, 0), E( -98, 0), E( 99, 0), E( -99, 0), E( 100, 0), + E(-100, 0), E( 101, 0), E(-101, 0), E( 102, 0), E(-102, 0), + E( 103, 0), E(-103, 0), E( 104, 0), E(-104, 0), E( 105, 0), + E(-105, 0), E( 106, 0), E(-106, 0), E( 107, 0), E(-107, 0), + E( 108, 0), E(-108, 0), E( 109, 0), E(-109, 0), E( 110, 0), + E(-110, 0), E( 111, 0), E(-111, 0), E( 112, 0), E(-112, 0), + E( 113, 0), E(-113, 0), E( 114, 0), E(-114, 0), E( 115, 0), + E(-115, 0), E( 116, 0), E(-116, 0), E( 117, 0), E(-117, 0), + E( 118, 0), E(-118, 0), E( 119, 0), E(-119, 0), E( 120, 0), + E(-120, 0), E( 121, 0), E(-121, 0), E( 122, 0), E(-122, 0), + E( 123, 0), E(-123, 0), E( 124, 0), E(-124, 0), E( 125, 0), + E(-125, 0), E( 126, 0), E(-126, 0), E( 127, 0), E(-127, 0), + E( 128, 0), E(-128, 0), E( 129, 0), E(-129, 0), E( 130, 0), + E(-130, 0), E( 131, 0), E(-131, 0), E( 132, 0), E(-132, 0), + E( 133, 0), E(-133, 0), E( 134, 0), E(-134, 0), E( 135, 0), + E(-135, 0), E( 136, 0), E(-136, 0), E( 137, 0), E(-137, 0), + E( 138, 0), E(-138, 0), E( 139, 0), E(-139, 0), E( 140, 0), + E(-140, 0), E( 141, 0), E(-141, 0), E( 142, 0), E(-142, 0), + E( 143, 0), E(-143, 0), E( 144, 0), E(-144, 0), E( 145, 0), + E(-145, 0), E( 146, 0), E(-146, 0), E( 147, 0), E(-147, 0), + E( 148, 0), E(-148, 0), E( 149, 0), E(-149, 0), E( 150, 0), + E(-150, 0), E( 151, 0), E(-151, 0), E( 152, 0), E(-152, 0), + E( 153, 0), E(-153, 0), E( 154, 0), E(-154, 0), E( 155, 0), + E(-155, 0), E( 156, 0), E(-156, 0), E( 157, 0), E(-157, 0), + E( 158, 0), E(-158, 0), E( 159, 0), E(-159, 0), E( 160, 0), + E(-160, 0), E( 161, 0), E(-161, 0), E( 162, 0), E(-162, 0), + E( 163, 0), E(-163, 0), E( 164, 0), E(-164, 0), E( 165, 0), + E(-165, 0), E( 166, 0), E(-166, 0), E( 167, 0), E(-167, 0), + E( 168, 0), E(-168, 0), E( 169, 0), E(-169, 0), E( 170, 0), + E(-170, 0), E( 171, 0), E(-171, 0), E( 172, 0), E(-172, 0), + E( 173, 0), E(-173, 0), E( 174, 0), E(-174, 0), E( 175, 0), + E(-175, 0), E( 176, 0), E(-176, 0), E( 177, 0), E(-177, 0), + E( 178, 0), E(-178, 0), E( 179, 0), E(-179, 0), E( 180, 0), + E(-180, 0), E( 181, 0), E(-181, 0), E( 182, 0), E(-182, 0), + E( 183, 0), E(-183, 0), E( 184, 0), E(-184, 0), E( 185, 0), + E(-185, 0), E( 186, 0), E(-186, 0), E( 187, 0), E(-187, 0), + E( 188, 0), E(-188, 0), E( 189, 0), E(-189, 0), E( 190, 0), + E(-190, 0), E( 191, 0), E(-191, 0), E( 192, 0), E(-192, 0), + E( 193, 0), E(-193, 0), E( 194, 0), E(-194, 0), E( 195, 0), + E(-195, 0), E( 196, 0), E(-196, 0), E( 197, 0), E(-197, 0), + E( 198, 0), E(-198, 0), E( 199, 0), E(-199, 0), E( 200, 0), + E(-200, 0), E( 201, 0), E(-201, 0), E( 202, 0), E(-202, 0), + E( 203, 0), E(-203, 0), E( 204, 0), E(-204, 0), E( 205, 0), + E(-205, 0), E( 206, 0), E(-206, 0), E( 207, 0), E(-207, 0), + E( 208, 0), E(-208, 0), E( 209, 0), E(-209, 0), E( 210, 0), + E(-210, 0), E( 211, 0), E(-211, 0), E( 212, 0), E(-212, 0), + E( 213, 0), E(-213, 0), E( 214, 0), E(-214, 0), E( 215, 0), + E(-215, 0), E( 216, 0), E(-216, 0), E( 217, 0), E(-217, 0), + E( 218, 0), E(-218, 0), E( 219, 0), E(-219, 0), E( 220, 0), + E(-220, 0), E( 221, 0), E(-221, 0), E( 222, 0), E(-222, 0), + E( 223, 0), E(-223, 0), E( 224, 0), E(-224, 0), E( 225, 0), + E(-225, 0), E( 226, 0), E(-226, 0), E( 227, 0), E(-227, 0), + E( 228, 0), E(-228, 0), E( 229, 0), E(-229, 0), E( 230, 0), + E(-230, 0), E( 231, 0), E(-231, 0), E( 232, 0), E(-232, 0), + E( 233, 0), E(-233, 0), E( 234, 0), E(-234, 0), E( 235, 0), + E(-235, 0), E( 236, 0), E(-236, 0), E( 237, 0), E(-237, 0), + E( 238, 0), E(-238, 0), E( 239, 0), E(-239, 0), E( 240, 0), + E(-240, 0), E( 241, 0), E(-241, 0), E( 242, 0), E(-242, 0), + E( 243, 0), E(-243, 0), E( 244, 0), E(-244, 0), E( 245, 0), + E(-245, 0), E( 246, 0), E(-246, 0), E( 247, 0), E(-247, 0), + E( 248, 0), E(-248, 0), E( 249, 0), E(-249, 0), E( 250, 0), + E(-250, 0), E( 251, 0), E(-251, 0), E( 252, 0), E(-252, 0), + E( 253, 0), E(-253, 0), E( 254, 0), E(-254, 0), E( 255, 0), + E(-255, 0), E( 13, 0), E( -13, 0), E( 14, 0), E( -14, 0), + E( 15, 0), E( -15, 0), E( 16, 0), E( -16, 0), E( 17, 0), + E( -17, 0), E( 18, 0), E( -18, 0), E( 5, 1), E( -5, 1), + E( 6, 1), E( -6, 1), E( 2, 2), E( -2, 2), E( 1, 3), + E( -1, 3), E( 0, 0), E( 19, 0), E( -19, 0), E( 20, 0), + E( -20, 0), E( 21, 0), E( -21, 0), E( 22, 0), E( -22, 0), + E( 23, 0), E( -23, 0), E( 24, 0), E( -24, 0), E( 25, 0), + E( -25, 0), E( 7, 1), E( -7, 1), E( 8, 1), E( -8, 1), + E( 3, 2), E( -3, 2), E( 2, 3), E( -2, 3), E( 1, 4), + E( -1, 4), E( 1, 5), E( -1, 5), E( 26, 0), E( -26, 0), + E( 27, 0), E( -27, 0), E( 28, 0), E( -28, 0), E( 29, 0), + E( -29, 0), E( 30, 0), E( -30, 0), E( 31, 0), E( -31, 0), + E( 32, 0), E( -32, 0), E( 33, 0), E( -33, 0), E( 34, 0), + E( -34, 0), E( 35, 0), E( -35, 0), E( 36, 0), E( -36, 0), + E( 0, 1), E( 9, 1), E( -9, 1), E( 10, 1), E( -10, 1), + E( 11, 1), E( -11, 1), E( 12, 1), E( -12, 1), E( 0, 2), + E( 4, 2), E( -4, 2), E( 5, 2), E( -5, 2), E( 6, 2), + E( -6, 2), E( 0, 3), E( 3, 3), E( -3, 3), E( 4, 3), + E( -4, 3), E( 0, 4), E( 2, 4), E( -2, 4), E( 0, 5), + E( 1, 6), E( -1, 6), E( 1, 7), E( -1, 7), E( 1, 8), + E( -1, 8), E( 37, 0), E( -37, 0), E( 38, 0), E( -38, 0), + E( 39, 0), E( -39, 0), E( 40, 0), E( -40, 0), E( 41, 0), + E( -41, 0), E( 42, 0), E( -42, 0), E( 43, 0), E( -43, 0), + E( 44, 0), E( -44, 0), E( 45, 0), E( -45, 0), E( 46, 0), + E( -46, 0), E( 47, 0), E( -47, 0), E( 48, 0), E( -48, 0), + E( 13, 1), E( -13, 1), E( 14, 1), E( -14, 1), E( 15, 1), + E( -15, 1), E( 16, 1), E( -16, 1), E( 7, 2), E( -7, 2), + E( 8, 2), E( -8, 2), E( 5, 3), E( -5, 3), E( 6, 3), + E( -6, 3), E( 3, 4), E( -3, 4), E( 4, 4), E( -4, 4), + E( 2, 5), E( -2, 5), E( 0, 6), E( 2, 6), E( -2, 6), + E( 0, 7), E( 0, 8), E( 0, 9), E( 1, 9), E( -1, 9), + E( 1, 10), E( -1, 10), E( 1, 11), E( -1, 11), E( 1, 12), + E( -1, 12), E( 49, 0), E( -49, 0), E( 50, 0), E( -50, 0), + E( 51, 0), E( -51, 0), E( 52, 0), E( -52, 0), E( 53, 0), + E( -53, 0), E( 54, 0), E( -54, 0), E( 55, 0), E( -55, 0), + E( 56, 0), E( -56, 0), E( 57, 0), E( -57, 0), E( 58, 0), + E( -58, 0), E( 59, 0), E( -59, 0), E( 60, 0), E( -60, 0), + E( 61, 0), E( -61, 0), E( 62, 0), E( -62, 0), E( 63, 0), + E( -63, 0), E( 17, 1), E( -17, 1), E( 18, 1), E( -18, 1), + E( 19, 1), E( -19, 1), E( 20, 1), E( -20, 1), E( 21, 1), + E( -21, 1), E( 22, 1), E( -22, 1), E( 23, 1), E( -23, 1), + E( 24, 1), E( -24, 1), E( 9, 2), E( -9, 2), E( 10, 2), + E( -10, 2), E( 11, 2), E( -11, 2), E( 12, 2), E( -12, 2), + E( 7, 3), E( -7, 3), E( 8, 3), E( -8, 3), E( 5, 4), + E( -5, 4), E( 6, 4), E( -6, 4), E( 3, 5), E( -3, 5), + E( 4, 5), E( -4, 5), E( 5, 5), E( -5, 5), E( 6, 5), + E( -6, 5), E( 3, 6), E( -3, 6), E( 4, 6), E( -4, 6), + E( 2, 7), E( -2, 7), E( 2, 8), E( -2, 8), E( 2, 9), + E( -2, 9), E( 0, 10), E( 2, 10), E( -2, 10), E( 0, 11), + E( 0, 12), E( 0, 13), E( 1, 13), E( -1, 13), E( 1, 14), + E( -1, 14), E( 0, 0), E( 0, 1), E( 0, 2), E( 0, 3), + E( 0, 4), E( 0, 5), E( 0, 6), E( 0, 7), E( 0, 8), + E( 0, 9), E( 0, 10), E( 0, 11), E( 0, 12), E( 0, 13), + E( 0, 14), E( 0, 15), E( 0, 16), E( 0, 17), E( 0, 18), + E( 0, 19), E( 0, 20), E( 0, 21), E( 0, 22), E( 0, 23), + E( 0, 24), E( 0, 25), E( 0, 26), E( 0, 27), E( 0, 28), + E( 0, 29), E( 0, 30), E( 0, 31), E( 0, 32), E( 0, 33), + E( 0, 34), E( 0, 35), E( 0, 36), E( 0, 37), E( 0, 38), + E( 0, 39), E( 0, 40), E( 0, 41), E( 0, 42), E( 0, 43), + E( 0, 44), E( 0, 45), E( 0, 46), E( 0, 47), E( 0, 48), + E( 0, 49), E( 0, 50), E( 0, 51), E( 0, 52), E( 0, 53), + E( 0, 54), E( 0, 55), E( 0, 56), E( 0, 57), E( 0, 58), + E( 0, 59), E( 0, 60), E( 0, 61), E( 0, 62), E( 0, 63), + E( 25, 1), E( -25, 1), E( 26, 1), E( -26, 1), E( 27, 1), + E( -27, 1), E( 28, 1), E( -28, 1), E( 29, 1), E( -29, 1), + E( 30, 1), E( -30, 1), E( 31, 1), E( -31, 1), E( 32, 1), + E( -32, 1), E( 13, 2), E( -13, 2), E( 14, 2), E( -14, 2), + E( 15, 2), E( -15, 2), E( 16, 2), E( -16, 2), E( 9, 3), + E( -9, 3), E( 10, 3), E( -10, 3), E( 11, 3), E( -11, 3), + E( 7, 4), E( -7, 4), E( 3, 7), E( -3, 7), E( 4, 7), + E( -4, 7), E( 3, 8), E( -3, 8), E( 4, 8), E( -4, 8), + E( 3, 9), E( -3, 9), E( 2, 11), E( -2, 11), E( 2, 12), + E( -2, 12), E( 0, 14), + // AC table Q16 - 512 elements + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), + E( -3, 0), E( 4, 0), E( -4, 0), E( 1, 1), E( -1, 1), + E( 0, 64), E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), + E( 2, 1), E( -2, 1), E( 1, 2), E( -1, 2), E( 7, 0), + E( -7, 0), E( 8, 0), E( -8, 0), E( 9, 0), E( -9, 0), + E( 3, 1), E( -3, 1), E( 1, 3), E( -1, 3), E( 1, 4), + E( -1, 4), E( 10, 0), E( -10, 0), E( 11, 0), E( -11, 0), + E( 12, 0), E( -12, 0), E( 4, 1), E( -4, 1), E( 2, 2), + E( -2, 2), E( 1, 5), E( -1, 5), E( 1, 6), E( -1, 6), + E( 13, 0), E( -13, 0), E( 14, 0), E( -14, 0), E( 15, 0), + E( -15, 0), E( 16, 0), E( -16, 0), E( 17, 0), E( -17, 0), + E( 5, 1), E( -5, 1), E( 2, 3), E( -2, 3), E( 1, 7), + E( -1, 7), E( 1, 8), E( -1, 8), E( 1, 9), E( -1, 9), + E( 1, 10), E( -1, 10), E( 0, 0), E( 18, 0), E( -18, 0), + E( 19, 0), E( -19, 0), E( 20, 0), E( -20, 0), E( 21, 0), + E( -21, 0), E( 22, 0), E( -22, 0), E( 6, 1), E( -6, 1), + E( 7, 1), E( -7, 1), E( 3, 2), E( -3, 2), E( 2, 4), + E( -2, 4), E( 2, 5), E( -2, 5), E( 1, 11), E( -1, 11), + E( 1, 12), E( -1, 12), E( 1, 13), E( -1, 13), E( 0, 0), + E( 0, 1), E( 0, 2), E( 0, 3), E( 0, 4), E( 0, 5), + E( 0, 6), E( 0, 7), E( 0, 8), E( 0, 9), E( 0, 10), + E( 0, 11), E( 0, 12), E( 0, 13), E( 0, 14), E( 0, 15), + E( 0, 16), E( 0, 17), E( 0, 18), E( 0, 19), E( 0, 20), + E( 0, 21), E( 0, 22), E( 0, 23), E( 0, 24), E( 0, 25), + E( 0, 26), E( 0, 27), E( 0, 28), E( 0, 29), E( 0, 30), + E( 0, 31), E( 0, 32), E( 0, 33), E( 0, 34), E( 0, 35), + E( 0, 36), E( 0, 37), E( 0, 38), E( 0, 39), E( 0, 40), + E( 0, 41), E( 0, 42), E( 0, 43), E( 0, 44), E( 0, 45), + E( 0, 46), E( 0, 47), E( 0, 48), E( 0, 49), E( 0, 50), + E( 0, 51), E( 0, 52), E( 0, 53), E( 0, 54), E( 0, 55), + E( 0, 56), E( 0, 57), E( 0, 58), E( 0, 59), E( 0, 60), + E( 0, 61), E( 0, 62), E( 0, 63), E( 0, 0), E( 1, 0), + E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), E( -3, 0), + E( 4, 0), E( -4, 0), E( 5, 0), E( -5, 0), E( 6, 0), + E( -6, 0), E( 7, 0), E( -7, 0), E( 8, 0), E( -8, 0), + E( 9, 0), E( -9, 0), E( 10, 0), E( -10, 0), E( 11, 0), + E( -11, 0), E( 12, 0), E( -12, 0), E( 13, 0), E( -13, 0), + E( 14, 0), E( -14, 0), E( 15, 0), E( -15, 0), E( 16, 0), + E( -16, 0), E( 17, 0), E( -17, 0), E( 18, 0), E( -18, 0), + E( 19, 0), E( -19, 0), E( 20, 0), E( -20, 0), E( 21, 0), + E( -21, 0), E( 22, 0), E( -22, 0), E( 23, 0), E( -23, 0), + E( 24, 0), E( -24, 0), E( 25, 0), E( -25, 0), E( 26, 0), + E( -26, 0), E( 27, 0), E( -27, 0), E( 28, 0), E( -28, 0), + E( 29, 0), E( -29, 0), E( 30, 0), E( -30, 0), E( 31, 0), + E( -31, 0), E( 32, 0), E( -32, 0), E( 33, 0), E( -33, 0), + E( 34, 0), E( -34, 0), E( 35, 0), E( -35, 0), E( 36, 0), + E( -36, 0), E( 37, 0), E( -37, 0), E( 38, 0), E( -38, 0), + E( 39, 0), E( -39, 0), E( 40, 0), E( -40, 0), E( 41, 0), + E( -41, 0), E( 42, 0), E( -42, 0), E( 43, 0), E( -43, 0), + E( 44, 0), E( -44, 0), E( 45, 0), E( -45, 0), E( 46, 0), + E( -46, 0), E( 47, 0), E( -47, 0), E( 48, 0), E( -48, 0), + E( 49, 0), E( -49, 0), E( 50, 0), E( -50, 0), E( 51, 0), + E( -51, 0), E( 52, 0), E( -52, 0), E( 53, 0), E( -53, 0), + E( 54, 0), E( -54, 0), E( 55, 0), E( -55, 0), E( 56, 0), + E( -56, 0), E( 57, 0), E( -57, 0), E( 58, 0), E( -58, 0), + E( 59, 0), E( -59, 0), E( 60, 0), E( -60, 0), E( 61, 0), + E( -61, 0), E( 62, 0), E( -62, 0), E( 63, 0), E( -63, 0), + E( 64, 0), E( -64, 0), E( 65, 0), E( -65, 0), E( 66, 0), + E( -66, 0), E( 67, 0), E( -67, 0), E( 68, 0), E( -68, 0), + E( 69, 0), E( -69, 0), E( 70, 0), E( -70, 0), E( 71, 0), + E( -71, 0), E( 72, 0), E( -72, 0), E( 73, 0), E( -73, 0), + E( 74, 0), E( -74, 0), E( 75, 0), E( -75, 0), E( 76, 0), + E( -76, 0), E( 77, 0), E( -77, 0), E( 78, 0), E( -78, 0), + E( 79, 0), E( -79, 0), E( 80, 0), E( -80, 0), E( 81, 0), + E( -81, 0), E( 82, 0), E( -82, 0), E( 83, 0), E( -83, 0), + E( 84, 0), E( -84, 0), E( 85, 0), E( -85, 0), E( 86, 0), + E( -86, 0), E( 87, 0), E( -87, 0), E( 88, 0), E( -88, 0), + E( 89, 0), E( -89, 0), E( 90, 0), E( -90, 0), E( 91, 0), + E( -91, 0), E( 92, 0), E( -92, 0), E( 93, 0), E( -93, 0), + E( 94, 0), E( -94, 0), E( 95, 0), E( -95, 0), E( 96, 0), + E( -96, 0), E( 97, 0), E( -97, 0), E( 98, 0), E( -98, 0), + E( 99, 0), E( -99, 0), E( 100, 0), E(-100, 0), E( 101, 0), + E(-101, 0), E( 102, 0), E(-102, 0), E( 103, 0), E(-103, 0), + E( 104, 0), E(-104, 0), E( 105, 0), E(-105, 0), E( 106, 0), + E(-106, 0), E( 107, 0), E(-107, 0), E( 108, 0), E(-108, 0), + E( 109, 0), E(-109, 0), E( 110, 0), E(-110, 0), E( 111, 0), + E(-111, 0), E( 112, 0), E(-112, 0), E( 113, 0), E(-113, 0), + E( 114, 0), E(-114, 0), E( 115, 0), E(-115, 0), E( 116, 0), + E(-116, 0), E( 117, 0), E(-117, 0), E( 118, 0), E(-118, 0), + E( 119, 0), E(-119, 0), E( 120, 0), E(-120, 0), E( 121, 0), + E(-121, 0), E( 122, 0), E(-122, 0), E( 123, 0), E(-123, 0), + E( 124, 0), E(-124, 0), E( 125, 0), E(-125, 0), E( 126, 0), + E(-126, 0), E( 127, 0), E(-127, 0), E( 23, 0), E( -23, 0), + E( 24, 0), E( -24, 0), E( 25, 0), E( -25, 0), E( 26, 0), + E( -26, 0), E( 27, 0), E( -27, 0), E( 28, 0), E( -28, 0), + E( 8, 1), E( -8, 1), E( 9, 1), E( -9, 1), E( 4, 2), + E( -4, 2), E( 3, 3), E( -3, 3), E( 3, 4), E( -3, 4), + E( 2, 6), E( -2, 6), E( 2, 7), E( -2, 7), E( 29, 0), + E( -29, 0), E( 30, 0), E( -30, 0), E( 31, 0), E( -31, 0), + E( 32, 0), E( -32, 0), E( 33, 0), E( -33, 0), E( 34, 0), + E( -34, 0), E( 35, 0), E( -35, 0), E( 0, 1), E( 10, 1), + E( -10, 1), E( 11, 1), E( -11, 1), E( 12, 1), E( -12, 1), + E( 0, 2), E( 5, 2), E( -5, 2), E( 0, 3), E( 4, 3), + E( -4, 3), E( 3, 5), E( -3, 5), E( 2, 8), E( -2, 8), + E( 2, 9), E( -2, 9), E( 1, 14), E( -1, 14), E( 1, 15), + E( -1, 15), E( 36, 0), E( -36, 0), E( 37, 0), E( -37, 0), + E( 38, 0), E( -38, 0), E( 39, 0), E( -39, 0), E( 40, 0), + E( -40, 0), E( 13, 1), E( -13, 1), E( 14, 1), E( -14, 1), + E( 15, 1), E( -15, 1), E( 6, 2), E( -6, 2), E( 7, 2), + E( -7, 2), E( 5, 3), E( -5, 3), E( 0, 4), E( 4, 4), + E( -4, 4), E( 0, 5), E( 0, 6), E( 3, 6), E( -3, 6), + E( 0, 7), E( 3, 7), E( -3, 7), E( 2, 10), E( -2, 10), + E( 1, 16), E( -1, 16), + // AC table Q32 - 354 elements + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 0, 64), E( 3, 0), + E( -3, 0), E( 1, 1), E( -1, 1), E( 4, 0), E( -4, 0), E( 5, 0), + E( -5, 0), E( 2, 1), E( -2, 1), E( 1, 2), E( -1, 2), E( 1, 3), + E( -1, 3), E( 6, 0), E( -6, 0), E( 7, 0), E( -7, 0), E( 3, 1), + E( -3, 1), E( 1, 4), E( -1, 4), E( 1, 5), E( -1, 5), E( 8, 0), + E( -8, 0), E( 9, 0), E( -9, 0), E( 10, 0), E(-10, 0), E( 4, 1), + E( -4, 1), E( 2, 2), E( -2, 2), E( 1, 6), E( -1, 6), E( 1, 7), + E( -1, 7), E( 1, 8), E( -1, 8), E( 11, 0), E(-11, 0), E( 12, 0), + E(-12, 0), E( 13, 0), E(-13, 0), E( 5, 1), E( -5, 1), E( 2, 3), + E( -2, 3), E( 1, 9), E( -1, 9), E( 1, 10), E( -1, 10), E( 14, 0), + E(-14, 0), E( 15, 0), E(-15, 0), E( 16, 0), E(-16, 0), E( 6, 1), + E( -6, 1), E( 7, 1), E( -7, 1), E( 3, 2), E( -3, 2), E( 3, 3), + E( -3, 3), E( 2, 4), E( -2, 4), E( 2, 5), E( -2, 5), E( 1, 11), + E( -1, 11), E( 1, 12), E( -1, 12), E( 1, 13), E( -1, 13), E( 0, 0), + E( 0, 1), E( 0, 2), E( 0, 3), E( 0, 4), E( 0, 5), E( 0, 6), + E( 0, 7), E( 0, 8), E( 0, 9), E( 0, 10), E( 0, 11), E( 0, 12), + E( 0, 13), E( 0, 14), E( 0, 15), E( 0, 16), E( 0, 17), E( 0, 18), + E( 0, 19), E( 0, 20), E( 0, 21), E( 0, 22), E( 0, 23), E( 0, 24), + E( 0, 25), E( 0, 26), E( 0, 27), E( 0, 28), E( 0, 29), E( 0, 30), + E( 0, 31), E( 0, 32), E( 0, 33), E( 0, 34), E( 0, 35), E( 0, 36), + E( 0, 37), E( 0, 38), E( 0, 39), E( 0, 40), E( 0, 41), E( 0, 42), + E( 0, 43), E( 0, 44), E( 0, 45), E( 0, 46), E( 0, 47), E( 0, 48), + E( 0, 49), E( 0, 50), E( 0, 51), E( 0, 52), E( 0, 53), E( 0, 54), + E( 0, 55), E( 0, 56), E( 0, 57), E( 0, 58), E( 0, 59), E( 0, 60), + E( 0, 61), E( 0, 62), E( 0, 63), E( 0, 0), E( 17, 0), E(-17, 0), + E( 18, 0), E(-18, 0), E( 19, 0), E(-19, 0), E( 20, 0), E(-20, 0), + E( 8, 1), E( -8, 1), E( 9, 1), E( -9, 1), E( 4, 2), E( -4, 2), + E( 3, 4), E( -3, 4), E( 2, 6), E( -2, 6), E( 2, 7), E( -2, 7), + E( 2, 8), E( -2, 8), E( 1, 14), E( -1, 14), E( 0, 0), E( 1, 0), + E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), E( -3, 0), E( 4, 0), + E( -4, 0), E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), E( 7, 0), + E( -7, 0), E( 8, 0), E( -8, 0), E( 9, 0), E( -9, 0), E( 10, 0), + E(-10, 0), E( 11, 0), E(-11, 0), E( 12, 0), E(-12, 0), E( 13, 0), + E(-13, 0), E( 14, 0), E(-14, 0), E( 15, 0), E(-15, 0), E( 16, 0), + E(-16, 0), E( 17, 0), E(-17, 0), E( 18, 0), E(-18, 0), E( 19, 0), + E(-19, 0), E( 20, 0), E(-20, 0), E( 21, 0), E(-21, 0), E( 22, 0), + E(-22, 0), E( 23, 0), E(-23, 0), E( 24, 0), E(-24, 0), E( 25, 0), + E(-25, 0), E( 26, 0), E(-26, 0), E( 27, 0), E(-27, 0), E( 28, 0), + E(-28, 0), E( 29, 0), E(-29, 0), E( 30, 0), E(-30, 0), E( 31, 0), + E(-31, 0), E( 32, 0), E(-32, 0), E( 33, 0), E(-33, 0), E( 34, 0), + E(-34, 0), E( 35, 0), E(-35, 0), E( 36, 0), E(-36, 0), E( 37, 0), + E(-37, 0), E( 38, 0), E(-38, 0), E( 39, 0), E(-39, 0), E( 40, 0), + E(-40, 0), E( 41, 0), E(-41, 0), E( 42, 0), E(-42, 0), E( 43, 0), + E(-43, 0), E( 44, 0), E(-44, 0), E( 45, 0), E(-45, 0), E( 46, 0), + E(-46, 0), E( 47, 0), E(-47, 0), E( 48, 0), E(-48, 0), E( 49, 0), + E(-49, 0), E( 50, 0), E(-50, 0), E( 51, 0), E(-51, 0), E( 52, 0), + E(-52, 0), E( 53, 0), E(-53, 0), E( 54, 0), E(-54, 0), E( 55, 0), + E(-55, 0), E( 56, 0), E(-56, 0), E( 57, 0), E(-57, 0), E( 58, 0), + E(-58, 0), E( 59, 0), E(-59, 0), E( 60, 0), E(-60, 0), E( 61, 0), + E(-61, 0), E( 62, 0), E(-62, 0), E( 63, 0), E(-63, 0), E( 21, 0), + E(-21, 0), E( 22, 0), E(-22, 0), E( 23, 0), E(-23, 0), E( 0, 1), + E( 10, 1), E(-10, 1), E( 11, 1), E(-11, 1), E( 0, 2), E( 5, 2), + E( -5, 2), E( 6, 2), E( -6, 2), E( 0, 3), E( 4, 3), E( -4, 3), + E( 0, 4), E( 3, 5), E( -3, 5), E( 3, 6), E( -3, 6), E( 2, 9), + E( -2, 9), E( 1, 15), E( -1, 15), E( 24, 0), E(-24, 0), E( 25, 0), + E(-25, 0), E( 26, 0), E(-26, 0), E( 12, 1), E(-12, 1), E( 13, 1), + E(-13, 1), E( 5, 3), E( -5, 3), E( 4, 4), E( -4, 4), E( 0, 5), + E( 4, 5), E( -4, 5), E( 0, 6), E( 0, 7), E( 3, 7), E( -3, 7), + E( 0, 8), E( 3, 8), E( -3, 8), E( 0, 9), E( 1, 16), E( -1, 16), + // AC table Q64 - 257 elements + E( 1, 0), E( -1, 0), E( 0, 64), E( 2, 0), E( -2, 0), E( 3, 0), + E( -3, 0), E( 1, 1), E( -1, 1), E( 4, 0), E( -4, 0), E( 2, 1), + E( -2, 1), E( 1, 2), E( -1, 2), E( 5, 0), E( -5, 0), E( 1, 3), + E( -1, 3), E( 1, 4), E( -1, 4), E( 6, 0), E( -6, 0), E( 3, 1), + E( -3, 1), E( 2, 2), E( -2, 2), E( 1, 5), E( -1, 5), E( 1, 6), + E( -1, 6), E( 1, 7), E( -1, 7), E( 7, 0), E( -7, 0), E( 8, 0), + E( -8, 0), E( 4, 1), E( -4, 1), E( 2, 3), E( -2, 3), E( 1, 8), + E( -1, 8), E( 1, 9), E( -1, 9), E( 9, 0), E( -9, 0), E( 10, 0), + E(-10, 0), E( 5, 1), E( -5, 1), E( 3, 2), E( -3, 2), E( 2, 4), + E( -2, 4), E( 2, 5), E( -2, 5), E( 1, 10), E( -1, 10), E( 1, 11), + E( -1, 11), E( 0, 0), E( 0, 1), E( 0, 2), E( 0, 3), E( 0, 4), + E( 0, 5), E( 0, 6), E( 0, 7), E( 0, 8), E( 0, 9), E( 0, 10), + E( 0, 11), E( 0, 12), E( 0, 13), E( 0, 14), E( 0, 15), E( 0, 16), + E( 0, 17), E( 0, 18), E( 0, 19), E( 0, 20), E( 0, 21), E( 0, 22), + E( 0, 23), E( 0, 24), E( 0, 25), E( 0, 26), E( 0, 27), E( 0, 28), + E( 0, 29), E( 0, 30), E( 0, 31), E( 0, 32), E( 0, 33), E( 0, 34), + E( 0, 35), E( 0, 36), E( 0, 37), E( 0, 38), E( 0, 39), E( 0, 40), + E( 0, 41), E( 0, 42), E( 0, 43), E( 0, 44), E( 0, 45), E( 0, 46), + E( 0, 47), E( 0, 48), E( 0, 49), E( 0, 50), E( 0, 51), E( 0, 52), + E( 0, 53), E( 0, 54), E( 0, 55), E( 0, 56), E( 0, 57), E( 0, 58), + E( 0, 59), E( 0, 60), E( 0, 61), E( 0, 62), E( 0, 63), E( 0, 0), + E( 11, 0), E(-11, 0), E( 12, 0), E(-12, 0), E( 6, 1), E( -6, 1), + E( 7, 1), E( -7, 1), E( 3, 3), E( -3, 3), E( 3, 4), E( -3, 4), + E( 3, 5), E( -3, 5), E( 2, 6), E( -2, 6), E( 2, 7), E( -2, 7), + E( 1, 12), E( -1, 12), E( 1, 13), E( -1, 13), E( 1, 14), E( -1, 14), + E( 13, 0), E(-13, 0), E( 14, 0), E(-14, 0), E( 0, 1), E( 8, 1), + E( -8, 1), E( 4, 2), E( -4, 2), E( 4, 3), E( -4, 3), E( 2, 8), + E( -2, 8), E( 2, 9), E( -2, 9), E( 1, 15), E( -1, 15), E( 0, 0), + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), E( -3, 0), + E( 4, 0), E( -4, 0), E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), + E( 7, 0), E( -7, 0), E( 8, 0), E( -8, 0), E( 9, 0), E( -9, 0), + E( 10, 0), E(-10, 0), E( 11, 0), E(-11, 0), E( 12, 0), E(-12, 0), + E( 13, 0), E(-13, 0), E( 14, 0), E(-14, 0), E( 15, 0), E(-15, 0), + E( 16, 0), E(-16, 0), E( 17, 0), E(-17, 0), E( 18, 0), E(-18, 0), + E( 19, 0), E(-19, 0), E( 20, 0), E(-20, 0), E( 21, 0), E(-21, 0), + E( 22, 0), E(-22, 0), E( 23, 0), E(-23, 0), E( 24, 0), E(-24, 0), + E( 25, 0), E(-25, 0), E( 26, 0), E(-26, 0), E( 27, 0), E(-27, 0), + E( 28, 0), E(-28, 0), E( 29, 0), E(-29, 0), E( 30, 0), E(-30, 0), + E( 31, 0), E(-31, 0), E( 15, 0), E(-15, 0), E( 9, 1), E( -9, 1), + E( 10, 1), E(-10, 1), E( 0, 2), E( 5, 2), E( -5, 2), E( 0, 3), + E( 5, 3), E( -5, 3), E( 0, 4), E( 4, 4), E( -4, 4), E( 0, 5), + E( 4, 5), E( -4, 5), E( 0, 6), E( 3, 6), E( -3, 6), E( 3, 7), + E( -3, 7), E( 1, 16), E( -1, 16), E( 1, 17), E( -1, 17), + // AC table Q128 - 194 elements + E( 1, 0), E( -1, 0), E( 0, 64), E( 1, 1), E( -1, 1), E( 2, 0), + E( -2, 0), E( 3, 0), E( -3, 0), E( 2, 1), E( -2, 1), E( 1, 2), + E( -1, 2), E( 1, 3), E( -1, 3), E( 1, 4), E( -1, 4), E( 4, 0), + E( -4, 0), E( 1, 5), E( -1, 5), E( 1, 6), E( -1, 6), E( 1, 7), + E( -1, 7), E( 5, 0), E( -5, 0), E( 3, 1), E( -3, 1), E( 2, 2), + E( -2, 2), E( 2, 3), E( -2, 3), E( 1, 8), E( -1, 8), E( 1, 9), + E( -1, 9), E( 6, 0), E( -6, 0), E( 4, 1), E( -4, 1), E( 2, 4), + E( -2, 4), E( 2, 5), E( -2, 5), E( 1, 10), E( -1, 10), E( 7, 0), + E( -7, 0), E( 5, 1), E( -5, 1), E( 3, 2), E( -3, 2), E( 3, 3), + E( -3, 3), E( 2, 6), E( -2, 6), E( 0, 0), E( 0, 1), E( 0, 2), + E( 0, 3), E( 0, 4), E( 0, 5), E( 0, 6), E( 0, 7), E( 0, 8), + E( 0, 9), E( 0, 10), E( 0, 11), E( 0, 12), E( 0, 13), E( 0, 14), + E( 0, 15), E( 0, 16), E( 0, 17), E( 0, 18), E( 0, 19), E( 0, 20), + E( 0, 21), E( 0, 22), E( 0, 23), E( 0, 24), E( 0, 25), E( 0, 26), + E( 0, 27), E( 0, 28), E( 0, 29), E( 0, 30), E( 0, 31), E( 0, 32), + E( 0, 33), E( 0, 34), E( 0, 35), E( 0, 36), E( 0, 37), E( 0, 38), + E( 0, 39), E( 0, 40), E( 0, 41), E( 0, 42), E( 0, 43), E( 0, 44), + E( 0, 45), E( 0, 46), E( 0, 47), E( 0, 48), E( 0, 49), E( 0, 50), + E( 0, 51), E( 0, 52), E( 0, 53), E( 0, 54), E( 0, 55), E( 0, 56), + E( 0, 57), E( 0, 58), E( 0, 59), E( 0, 60), E( 0, 61), E( 0, 62), + E( 0, 63), E( 6, 1), E( -6, 1), E( 7, 1), E( -7, 1), E( 3, 4), + E( -3, 4), E( 3, 5), E( -3, 5), E( 2, 7), E( -2, 7), E( 2, 8), + E( -2, 8), E( 2, 9), E( -2, 9), E( 1, 11), E( -1, 11), E( 1, 12), + E( -1, 12), E( 1, 13), E( -1, 13), E( 0, 0), E( 8, 0), E( -8, 0), + E( 9, 0), E( -9, 0), E( 8, 1), E( -8, 1), E( 4, 2), E( -4, 2), + E( 4, 3), E( -4, 3), E( 3, 6), E( -3, 6), E( 1, 14), E( -1, 14), + E( 1, 15), E( -1, 15), E( 1, 16), E( -1, 16), E( 0, 1), E( 0, 2), + E( 0, 3), E( 0, 0), E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), + E( 3, 0), E( -3, 0), E( 4, 0), E( -4, 0), E( 5, 0), E( -5, 0), + E( 6, 0), E( -6, 0), E( 7, 0), E( -7, 0), E( 8, 0), E( -8, 0), + E( 9, 0), E( -9, 0), E( 10, 0), E(-10, 0), E( 11, 0), E(-11, 0), + E( 12, 0), E(-12, 0), E( 13, 0), E(-13, 0), E( 14, 0), E(-14, 0), + E( 15, 0), E(-15, 0), +}; + +static const uint8_t hqx_ac_lens[] = { + // AC table Q0 - 815 elements + 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, + 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 9, 10, 10, 10, 10, 10, 10, 10, 10, 9, 10, + 10, 9, 10, 10, 10, 10, 10, 10, 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, + 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, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 10, 11, 11, 10, 10, 11, 11, 11, 11, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, + 13, 13, 13, 13, 13, + // AC table Q8 - 907 elements + 4, 4, 4, 4, 5, 5, 5, 5, 4, 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, 14, + 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, 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, 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, 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, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 9, 10, 10, 10, 10, 10, 10, 10, 10, 9, 10, 10, 10, 10, 10, + 10, 9, 10, 10, 10, 10, 9, 10, 10, 9, 10, 10, 10, 10, 10, 10, 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, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 10, 10, 10, 11, 11, 11, 11, + 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 12, 12, 11, 11, 11, + 12, 12, 12, 12, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 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, 12, + // AC table Q16 - 512 elements + 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 4, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 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, 16, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 11, 12, 12, 12, 12, 12, 12, 11, 12, 12, 11, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 13, 13, 12, 12, 13, + 13, 12, 13, 13, 13, 13, 13, 13, + // AC table Q32 - 354 elements + 3, 3, 4, 4, 3, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 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, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 16, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 12, 12, 12, 12, 12, 12, 11, + 12, 12, 12, 12, 11, 12, 12, 12, 12, 11, 12, 12, 11, 12, 12, 12, 12, 12, + 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, + 13, 13, 12, 12, 13, 13, 12, 13, 13, 12, 13, 13, + // AC table Q64 - 257 elements + 3, 3, 2, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 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, 10, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 11, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 13, 13, 13, 13, + 13, 13, 12, 13, 13, 12, 13, 13, 12, 13, 13, 12, 13, 13, 12, 13, 13, 13, + 13, 13, 13, 13, 13, + // AC table Q128 - 194 elements + 3, 3, 2, 4, 4, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, + 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 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, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +}; + +static const uint16_t hqx_ac_nb_elems[] = { 815, 907, 512, 354, 257, 194 }; + +static VLCElem cbp_vlc[896 /* dc9 */ + 1344 /* dc10 */ + + 15630 /* RL_VLC_ELEMS for hqx_ac */]; + +static const VLCElem *dc_vlc[2]; +#define INIT_DC_TABLE(idx, name) \ + do { \ + dc_vlc[idx] = ff_vlc_init_tables(&state, HQX_DC_VLC_BITS, \ + FF_ARRAY_ELEMS(name ## _vlc_lens), \ + name ## _vlc_lens, 1, 1, \ + name ## _vlc_bits, 2, 2, 0); \ + } while (0) + +av_unused av_cold static void hqx_init_static(void) +{ + VLCInitState state = VLC_INIT_STATE(cbp_vlc); + const uint8_t *lens = hqx_ac_lens; + const int16_t *run_level = hqx_ac_run_level; + + INIT_DC_TABLE(0, dc9); + INIT_DC_TABLE(1, dc10); + + for (int i = 0; i < NUM_HQX_AC; ++i) { + RL_VLC_ELEM *lut = state.table; + unsigned nb_codes = state.size; + + hqx_ac[i].lut = + ff_vlc_init_tables_from_lengths(&state, hqx_ac[i].bits, + hqx_ac_nb_elems[i], lens, 1, + run_level, 2, 2, 0, 0); + + nb_codes -= state.size; + + for (unsigned j = 0; j < nb_codes; ++j) { + // lut[j] is in VLC (not RL_VLC) state + int sym = lut[j].sym; + int len = lut[j].len; + int level; + + if (len < 0) { + level = sym; + } else { + level = sym >> 7; + lut[j].run = sym & 0x7f; + } + // lut[j] is now in RL_VLC state + lut[j].len8 = len; + lut[j].level = level; + } + lens += hqx_ac_nb_elems[i]; + run_level += hqx_ac_nb_elems[i]; + } +} + +#endif /* AVCODEC_HQXVLC_H*/ diff --git a/libavcodec/huffman.c b/libavcodec/huffman.c index d47fe1008..0c2d0c27e 100644 --- a/libavcodec/huffman.c +++ b/libavcodec/huffman.c @@ -39,7 +39,10 @@ #define HNODE -1 typedef struct HeapElem { - uint64_t val; + union { + uint64_t val; + uint16_t dummy; // exists solely to ensure alignof(HeapElem) >= alignof(uint16_t) + }; int name; } HeapElem; @@ -59,19 +62,23 @@ static void heap_sift(HeapElem *h, int root, int size) int ff_huff_gen_len_table(uint8_t *dst, const uint64_t *stats, int stats_size, int skip0) { - HeapElem *h = av_malloc_array(sizeof(*h), stats_size); - int *up = av_malloc_array(sizeof(*up) * 2, stats_size); - uint8_t *len = av_malloc_array(sizeof(*len) * 2, stats_size); - uint16_t *map= av_malloc_array(sizeof(*map), stats_size); + int *up; + uint16_t *map; + uint8_t *len; + HeapElem *h = av_malloc_array(stats_size, + sizeof(*h) + 2 * sizeof(up) + 2 * sizeof(len) + sizeof(map)); + if (!h) + return AVERROR(ENOMEM); + up = (int*)(h + stats_size); + // map is suitably aligned because up uses an even number of elements + // and alignof(uint16_t) is either 1 or 2. + map = (uint16_t*)(up + 2 * stats_size); + len = (uint8_t*)(map + stats_size); + int offset, i, next; int size = 0; int ret = 0; - if (!h || !up || !len || !map) { - ret = AVERROR(ENOMEM); - goto end; - } - for (i = 0; iadd_hfyu_median_pred_int16 = add_hfyu_median_pred_int16_c; c->add_hfyu_left_pred_bgr32 = add_hfyu_left_pred_bgr32_c; -#if ARCH_RISCV +#if ARCH_AARCH64 + ff_huffyuvdsp_init_aarch64(c, pix_fmt); +#elif ARCH_RISCV ff_huffyuvdsp_init_riscv(c, pix_fmt); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_huffyuvdsp_init_x86(c, pix_fmt); #endif } diff --git a/libavcodec/huffyuvdsp.h b/libavcodec/huffyuvdsp.h index 34bed58ef..3f319b17c 100644 --- a/libavcodec/huffyuvdsp.h +++ b/libavcodec/huffyuvdsp.h @@ -34,6 +34,8 @@ typedef struct HuffYUVDSPContext { } HuffYUVDSPContext; void ff_huffyuvdsp_init(HuffYUVDSPContext *c, enum AVPixelFormat pix_fmt); +void ff_huffyuvdsp_init_aarch64(HuffYUVDSPContext *c, + enum AVPixelFormat pix_fmt); void ff_huffyuvdsp_init_riscv(HuffYUVDSPContext *c, enum AVPixelFormat pix_fmt); void ff_huffyuvdsp_init_x86(HuffYUVDSPContext *c, enum AVPixelFormat pix_fmt); diff --git a/libavcodec/huffyuvenc.c b/libavcodec/huffyuvenc.c index 5e8b5c0dd..dd3ed9a99 100644 --- a/libavcodec/huffyuvenc.c +++ b/libavcodec/huffyuvenc.c @@ -39,7 +39,6 @@ #include "huffyuvencdsp.h" #include "lossless_videoencdsp.h" #include "put_bits.h" -#include "libavutil/emms.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -48,13 +47,14 @@ typedef struct HYuvEncContext { AVClass *class; AVCodecContext *avctx; PutBitContext pb; - Predictor predictor; + /* Predictor, use int for AVOption */ + int predictor; int interlaced; int decorrelate; int bitstream_bpp; int version; int bps; - int n; // 1<bps <= 8) { s->llvidencdsp.diff_bytes(dst, src0, src1, w); } else { - s->hencdsp.diff_int16((uint16_t *)dst, (const uint16_t *)src0, (const uint16_t *)src1, s->n - 1, w); + s->hencdsp.diff_int16((uint16_t *)dst, (const uint16_t *)src0, (const uint16_t *)src1, s->mask, w); } } @@ -114,7 +114,7 @@ static inline int sub_left_prediction(HYuvEncContext *s, uint8_t *dst, } if (w < 32) return left; - s->hencdsp.diff_int16(dst16 + 32, src16 + 32, src16 + 31, s->n - 1, w - 32); + s->hencdsp.diff_int16(dst16 + 32, src16 + 32, src16 + 31, s->mask, w - 32); return src16[w-1]; } } @@ -190,7 +190,8 @@ static void sub_median_prediction(HYuvEncContext *s, uint8_t *dst, if (s->bps <= 8) { s->llvidencdsp.sub_median_pred(dst, src1, src2, w , left, left_top); } else { - s->hencdsp.sub_hfyu_median_pred_int16((uint16_t *)dst, (const uint16_t *)src1, (const uint16_t *)src2, s->n - 1, w , left, left_top); + s->hencdsp.sub_hfyu_median_pred_int16((uint16_t *)dst, (const uint16_t *)src1, + (const uint16_t *)src2, s->mask, w, left, left_top); } } @@ -252,7 +253,6 @@ static av_cold int encode_init(AVCodecContext *avctx) s->flags = avctx->flags; ff_bswapdsp_init(&s->bdsp); - ff_huffyuvencdsp_init(&s->hencdsp, avctx->pix_fmt); ff_llvidencdsp_init(&s->llvidencdsp); avctx->extradata = av_mallocz(3*MAX_N + 4); @@ -274,6 +274,11 @@ static av_cold int encode_init(AVCodecContext *avctx) s->chroma_h_shift = desc->log2_chroma_w; s->chroma_v_shift = desc->log2_chroma_h; + s->mask = (1 << s->bps) - 1; + s->vlc_n = FFMIN(1 << s->bps, MAX_VLC_N); + + ff_huffyuvencdsp_init(&s->hencdsp, s->bps, avctx->width >> s->chroma_h_shift); + switch (avctx->pix_fmt) { case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUV422P: @@ -332,11 +337,8 @@ static av_cold int encode_init(AVCodecContext *avctx) s->bitstream_bpp = 24; break; default: - av_log(avctx, AV_LOG_ERROR, "format not supported\n"); - return AVERROR(EINVAL); + av_unreachable("Already checked via CODEC_PIXFMTS"); } - s->n = 1<bps; - s->vlc_n = FFMIN(s->n, MAX_VLC_N); avctx->bits_per_coded_sample = s->bitstream_bpp; s->decorrelate = s->bitstream_bpp >= 24 && !s->yuv && !(desc->flags & AV_PIX_FMT_FLAG_PLANAR); @@ -587,7 +589,7 @@ do { \ if (s->bps <= 8) { ENCODE_PLANE(LOAD2, LOADEND, WRITE2, WRITEEND, STAT2, STATEND); } else if (s->bps <= 14) { - int mask = s->n - 1; + unsigned mask = s->mask; ENCODE_PLANE(LOAD2_14, LOADEND_14, WRITE2, WRITEEND, STAT2, STATEND); } else { @@ -937,7 +939,6 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, } else { av_log(avctx, AV_LOG_ERROR, "Format not supported!\n"); } - emms_c(); size += (put_bits_count(&s->pb) + 31) / 8; put_bits(&s->pb, 16, 0); @@ -1022,10 +1023,7 @@ const FFCodec ff_huffyuv_encoder = { FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, .p.priv_class = &normal_class, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB24, - AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB32), .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; @@ -1050,7 +1048,7 @@ const FFCodec ff_ffvhuff_encoder = { FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, .p.priv_class = &ff_class, - .p.pix_fmts = (const enum AVPixelFormat[]){ + CODEC_PIXFMTS( AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_GBRP, @@ -1065,8 +1063,7 @@ const FFCodec ff_ffvhuff_encoder = { AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P16, AV_PIX_FMT_RGB24, - AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE - }, + AV_PIX_FMT_RGB32), .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/huffyuvencdsp.c b/libavcodec/huffyuvencdsp.c index 27428635a..9dd84dbaf 100644 --- a/libavcodec/huffyuvencdsp.c +++ b/libavcodec/huffyuvencdsp.c @@ -84,12 +84,12 @@ static void sub_hfyu_median_pred_int16_c(uint16_t *dst, const uint16_t *src1, co *left_top = lt; } -av_cold void ff_huffyuvencdsp_init(HuffYUVEncDSPContext *c, enum AVPixelFormat pix_fmt) +av_cold void ff_huffyuvencdsp_init(HuffYUVEncDSPContext *c, int bpp, int width) { c->diff_int16 = diff_int16_c; c->sub_hfyu_median_pred_int16 = sub_hfyu_median_pred_int16_c; -#if ARCH_X86 - ff_huffyuvencdsp_init_x86(c, pix_fmt); +#if ARCH_X86 && HAVE_X86ASM + ff_huffyuvencdsp_init_x86(c, bpp, width); #endif } diff --git a/libavcodec/huffyuvencdsp.h b/libavcodec/huffyuvencdsp.h index 779a51ac7..173fbca08 100644 --- a/libavcodec/huffyuvencdsp.h +++ b/libavcodec/huffyuvencdsp.h @@ -21,8 +21,6 @@ #include -#include "libavutil/pixfmt.h" - typedef struct HuffYUVEncDSPContext { void (*diff_int16)(uint16_t *dst /* align 16 */, const uint16_t *src1 /* align 16 */, @@ -34,7 +32,7 @@ typedef struct HuffYUVEncDSPContext { int w, int *left, int *left_top); } HuffYUVEncDSPContext; -void ff_huffyuvencdsp_init(HuffYUVEncDSPContext *c, enum AVPixelFormat pix_fmt); -void ff_huffyuvencdsp_init_x86(HuffYUVEncDSPContext *c, enum AVPixelFormat pix_fmt); +void ff_huffyuvencdsp_init(HuffYUVEncDSPContext *c, int bpp, int width); +void ff_huffyuvencdsp_init_x86(HuffYUVEncDSPContext *c, int bpp, int width); #endif /* AVCODEC_HUFFYUVENCDSP_H */ diff --git a/libavcodec/hw_base_encode.c b/libavcodec/hw_base_encode.c index 7b6ec97d3..927aeb4ba 100644 --- a/libavcodec/hw_base_encode.c +++ b/libavcodec/hw_base_encode.c @@ -18,6 +18,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/error.h" #include "libavutil/internal.h" #include "libavutil/log.h" #include "libavutil/mem.h" @@ -190,12 +191,12 @@ static void hw_base_encode_add_next_prev(FFHWBaseEncodeContext *ctx, return; } - if (ctx->nb_next_prev < MAX_PICTURE_REFERENCES) { + if (ctx->nb_next_prev < ctx->ref_l0) { ctx->next_prev[ctx->nb_next_prev++] = pic; ++pic->ref_count[0]; } else { --ctx->next_prev[0]->ref_count[0]; - for (i = 0; i < MAX_PICTURE_REFERENCES - 1; i++) + for (i = 0; i < ctx->ref_l0 - 1; i++) ctx->next_prev[i] = ctx->next_prev[i + 1]; ctx->next_prev[i] = pic; ++pic->ref_count[0]; @@ -603,7 +604,7 @@ start: av_fifo_can_read(ctx->encode_fifo); err = ctx->op->issue(avctx, pic); if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err); + av_log(avctx, AV_LOG_ERROR, "Encode failed: %s.\n", av_err2str(err)); return err; } pic->encode_issued = 1; @@ -630,7 +631,7 @@ start: err = ctx->op->issue(avctx, pic); if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err); + av_log(avctx, AV_LOG_ERROR, "Encode failed: %s.\n", av_err2str(err)); return err; } @@ -662,6 +663,14 @@ int ff_hw_base_init_gop_structure(FFHWBaseEncodeContext *ctx, AVCodecContext *av uint32_t ref_l0, uint32_t ref_l1, int flags, int prediction_pre_only) { + ctx->ref_l0 = FFMIN(ref_l0, MAX_PICTURE_REFERENCES); + ctx->ref_l1 = FFMIN(ref_l1, MAX_PICTURE_REFERENCES); + + if (avctx->refs > 0) { + ctx->ref_l0 = FFMIN(ctx->ref_l0, avctx->refs); + ctx->ref_l1 = FFMIN(ctx->ref_l1, avctx->refs); + } + if (flags & FF_HW_FLAG_INTRA_ONLY || avctx->gop_size <= 1) { av_log(avctx, AV_LOG_VERBOSE, "Using intra frames only.\n"); ctx->gop_size = 1; @@ -804,6 +813,11 @@ int ff_hw_base_encode_init(AVCodecContext *avctx, FFHWBaseEncodeContext *ctx) int ff_hw_base_encode_close(FFHWBaseEncodeContext *ctx) { + for (FFHWBaseEncodePicture *pic = ctx->pic_start, *next_pic = pic; pic; pic = next_pic) { + next_pic = pic->next; + base_encode_pic_free(pic); + } + av_fifo_freep2(&ctx->encode_fifo); av_frame_free(&ctx->frame); diff --git a/libavcodec/hw_base_encode.h b/libavcodec/hw_base_encode.h index e30b1e60a..e76857972 100644 --- a/libavcodec/hw_base_encode.h +++ b/libavcodec/hw_base_encode.h @@ -193,6 +193,10 @@ typedef struct FFHWBaseEncodeContext { int end_of_stream; int p_to_gpb; + // The number of L0/L1 references supported by the driver. + int ref_l0; + int ref_l1; + // Whether the driver supports ROI at all. int roi_allowed; diff --git a/libavcodec/hwaccel_internal.h b/libavcodec/hwaccel_internal.h index b0cc22bb6..722440681 100644 --- a/libavcodec/hwaccel_internal.h +++ b/libavcodec/hwaccel_internal.h @@ -26,7 +26,7 @@ #include #include "avcodec.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #define HWACCEL_CAP_ASYNC_SAFE (1 << 0) #define HWACCEL_CAP_THREAD_SAFE (1 << 1) @@ -52,11 +52,13 @@ typedef struct FFHWAccel { * Otherwise, this means the whole frame is available at this point. * * @param avctx the codec context + * @param buf_ref the frame data buffer reference (optional) * @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); + int (*start_frame)(AVCodecContext *avctx, const AVBufferRef *buf_ref, + const uint8_t *buf, uint32_t buf_size); /** * Callback for parameter data (SPS/PPS/VPS etc). @@ -155,7 +157,7 @@ typedef struct FFHWAccel { * @param hwctx a pointer to an AVHWDeviceContext. * @param data the per-frame hardware accelerator private data to be freed. */ - void (*free_frame_priv)(FFRefStructOpaque hwctx, void *data); + void (*free_frame_priv)(AVRefStructOpaque hwctx, void *data); /** * Callback to flush the hwaccel state. diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h index 5171e4c7d..3de191288 100644 --- a/libavcodec/hwaccels.h +++ b/libavcodec/hwaccels.h @@ -26,7 +26,10 @@ extern const struct FFHWAccel ff_av1_dxva2_hwaccel; extern const struct FFHWAccel ff_av1_nvdec_hwaccel; extern const struct FFHWAccel ff_av1_vaapi_hwaccel; extern const struct FFHWAccel ff_av1_vdpau_hwaccel; +extern const struct FFHWAccel ff_av1_videotoolbox_hwaccel; extern const struct FFHWAccel ff_av1_vulkan_hwaccel; +extern const struct FFHWAccel ff_dpx_vulkan_hwaccel; +extern const struct FFHWAccel ff_ffv1_vulkan_hwaccel; extern const struct FFHWAccel ff_h263_vaapi_hwaccel; extern const struct FFHWAccel ff_h263_videotoolbox_hwaccel; extern const struct FFHWAccel ff_h264_d3d11va_hwaccel; @@ -65,6 +68,8 @@ extern const struct FFHWAccel ff_mpeg4_vaapi_hwaccel; extern const struct FFHWAccel ff_mpeg4_vdpau_hwaccel; extern const struct FFHWAccel ff_mpeg4_videotoolbox_hwaccel; extern const struct FFHWAccel ff_prores_videotoolbox_hwaccel; +extern const struct FFHWAccel ff_prores_vulkan_hwaccel; +extern const struct FFHWAccel ff_prores_raw_vulkan_hwaccel; extern const struct FFHWAccel ff_vc1_d3d11va_hwaccel; extern const struct FFHWAccel ff_vc1_d3d11va2_hwaccel; extern const struct FFHWAccel ff_vc1_d3d12va_hwaccel; @@ -82,6 +87,8 @@ extern const struct FFHWAccel ff_vp9_nvdec_hwaccel; extern const struct FFHWAccel ff_vp9_vaapi_hwaccel; extern const struct FFHWAccel ff_vp9_vdpau_hwaccel; extern const struct FFHWAccel ff_vp9_videotoolbox_hwaccel; +extern const struct FFHWAccel ff_vp9_vulkan_hwaccel; +extern const struct FFHWAccel ff_vvc_vaapi_hwaccel; extern const struct FFHWAccel ff_wmv3_d3d11va_hwaccel; extern const struct FFHWAccel ff_wmv3_d3d11va2_hwaccel; extern const struct FFHWAccel ff_wmv3_d3d12va_hwaccel; diff --git a/libavcodec/idcinvideo.c b/libavcodec/idcinvideo.c index d9e463354..da17ea35b 100644 --- a/libavcodec/idcinvideo.c +++ b/libavcodec/idcinvideo.c @@ -224,14 +224,7 @@ static int idcin_decode_frame(AVCodecContext *avctx, AVFrame *frame, if (idcin_decode_vlcs(s, frame)) return AVERROR_INVALIDDATA; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* make the palette available on the way out */ memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); diff --git a/libavcodec/idctdsp.c b/libavcodec/idctdsp.c index 4259a117d..e039f900e 100644 --- a/libavcodec/idctdsp.c +++ b/libavcodec/idctdsp.c @@ -41,7 +41,7 @@ av_cold void ff_init_scantable_permutation(uint8_t *idct_permutation, { int i; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM if (ff_init_scantable_permutation_x86(idct_permutation, perm_type)) return; @@ -276,6 +276,10 @@ av_cold void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx) c->idct = ff_faanidct; c->perm_type = FF_IDCT_PERM_NONE; #endif /* CONFIG_FAANIDCT */ +#if CONFIG_MPEG4_DECODER + } else if (avctx->idct_algo == FF_IDCT_XVID) { + ff_xvid_idct_init(c); +#endif } else { // accurate/default c->idct_put = ff_simple_idct_put_int16_8bit; c->idct_add = ff_simple_idct_add_int16_8bit; @@ -289,9 +293,6 @@ av_cold void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx) c->put_signed_pixels_clamped = put_signed_pixels_clamped_c; c->add_pixels_clamped = ff_add_pixels_clamped_c; - if (CONFIG_MPEG4_DECODER && avctx->idct_algo == FF_IDCT_XVID) - ff_xvid_idct_init(c, avctx); - #if ARCH_AARCH64 ff_idctdsp_init_aarch64(c, avctx, high_bit_depth); #elif ARCH_ARM @@ -300,7 +301,7 @@ av_cold void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx) ff_idctdsp_init_ppc(c, avctx, high_bit_depth); #elif ARCH_RISCV ff_idctdsp_init_riscv(c, avctx, high_bit_depth); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_idctdsp_init_x86(c, avctx, high_bit_depth); #elif ARCH_MIPS ff_idctdsp_init_mips(c, avctx, high_bit_depth); diff --git a/libavcodec/idctdsp.h b/libavcodec/idctdsp.h index c08242881..7783d7098 100644 --- a/libavcodec/idctdsp.h +++ b/libavcodec/idctdsp.h @@ -98,8 +98,6 @@ void ff_idctdsp_init(IDCTDSPContext *c, struct AVCodecContext *avctx); void ff_idctdsp_init_aarch64(IDCTDSPContext *c, struct AVCodecContext *avctx, unsigned high_bit_depth); -void ff_idctdsp_init_alpha(IDCTDSPContext *c, struct AVCodecContext *avctx, - unsigned high_bit_depth); void ff_idctdsp_init_arm(IDCTDSPContext *c, struct AVCodecContext *avctx, unsigned high_bit_depth); void ff_idctdsp_init_ppc(IDCTDSPContext *c, struct AVCodecContext *avctx, diff --git a/libavcodec/iirfilter.c b/libavcodec/iirfilter.c deleted file mode 100644 index cefe35ab6..000000000 --- a/libavcodec/iirfilter.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * IIR filter - * Copyright (c) 2008 Konstantin Shishkov - * - * 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 - * different IIR filters implementation - */ - -#include - -#include "config.h" - -#include "libavutil/attributes.h" -#include "libavutil/common.h" -#include "libavutil/log.h" -#include "libavutil/mem.h" - -#include "iirfilter.h" - -/** - * IIR filter global parameters - */ -typedef struct FFIIRFilterCoeffs { - int order; - float gain; - int *cx; - float *cy; -} FFIIRFilterCoeffs; - -/** - * IIR filter state - */ -typedef struct FFIIRFilterState { - float x[1]; -} FFIIRFilterState; - -/// maximum supported filter order -#define MAXORDER 30 - -static av_cold int butterworth_init_coeffs(void *avc, - struct FFIIRFilterCoeffs *c, - enum IIRFilterMode filt_mode, - int order, float cutoff_ratio, - float stopband) -{ - int i, j; - double wa; - double p[MAXORDER + 1][2]; - - if (filt_mode != FF_FILTER_MODE_LOWPASS) { - av_log(avc, AV_LOG_ERROR, "Butterworth filter currently only supports " - "low-pass filter mode\n"); - return -1; - } - if (order & 1) { - av_log(avc, AV_LOG_ERROR, "Butterworth filter currently only supports " - "even filter orders\n"); - return -1; - } - - wa = 2 * tan(M_PI * 0.5 * cutoff_ratio); - - c->cx[0] = 1; - for (i = 1; i < (order >> 1) + 1; i++) - c->cx[i] = c->cx[i - 1] * (order - i + 1LL) / i; - - p[0][0] = 1.0; - p[0][1] = 0.0; - for (i = 1; i <= order; i++) - p[i][0] = p[i][1] = 0.0; - for (i = 0; i < order; i++) { - double zp[2]; - double th = (i + (order >> 1) + 0.5) * M_PI / order; - double a_re, a_im, c_re, c_im; - zp[0] = cos(th) * wa; - zp[1] = sin(th) * wa; - a_re = zp[0] + 2.0; - c_re = zp[0] - 2.0; - a_im = - c_im = zp[1]; - zp[0] = (a_re * c_re + a_im * c_im) / (c_re * c_re + c_im * c_im); - zp[1] = (a_im * c_re - a_re * c_im) / (c_re * c_re + c_im * c_im); - - for (j = order; j >= 1; j--) { - a_re = p[j][0]; - a_im = p[j][1]; - p[j][0] = a_re * zp[0] - a_im * zp[1] + p[j - 1][0]; - p[j][1] = a_re * zp[1] + a_im * zp[0] + p[j - 1][1]; - } - a_re = p[0][0] * zp[0] - p[0][1] * zp[1]; - p[0][1] = p[0][0] * zp[1] + p[0][1] * zp[0]; - p[0][0] = a_re; - } - c->gain = p[order][0]; - for (i = 0; i < order; i++) { - c->gain += p[i][0]; - c->cy[i] = (-p[i][0] * p[order][0] + -p[i][1] * p[order][1]) / - (p[order][0] * p[order][0] + p[order][1] * p[order][1]); - } - c->gain /= 1 << order; - - return 0; -} - -static av_cold int biquad_init_coeffs(void *avc, struct FFIIRFilterCoeffs *c, - enum IIRFilterMode filt_mode, int order, - float cutoff_ratio, float stopband) -{ - double cos_w0, sin_w0; - double a0, x0, x1; - - if (filt_mode != FF_FILTER_MODE_HIGHPASS && - filt_mode != FF_FILTER_MODE_LOWPASS) { - av_log(avc, AV_LOG_ERROR, "Biquad filter currently only supports " - "high-pass and low-pass filter modes\n"); - return -1; - } - if (order != 2) { - av_log(avc, AV_LOG_ERROR, "Biquad filter must have order of 2\n"); - return -1; - } - - cos_w0 = cos(M_PI * cutoff_ratio); - sin_w0 = sin(M_PI * cutoff_ratio); - - a0 = 1.0 + (sin_w0 / 2.0); - - if (filt_mode == FF_FILTER_MODE_HIGHPASS) { - c->gain = ((1.0 + cos_w0) / 2.0) / a0; - x0 = ((1.0 + cos_w0) / 2.0) / a0; - x1 = (-(1.0 + cos_w0)) / a0; - } else { // FF_FILTER_MODE_LOWPASS - c->gain = ((1.0 - cos_w0) / 2.0) / a0; - x0 = ((1.0 - cos_w0) / 2.0) / a0; - x1 = (1.0 - cos_w0) / a0; - } - c->cy[0] = (-1.0 + (sin_w0 / 2.0)) / a0; - c->cy[1] = (2.0 * cos_w0) / a0; - - // divide by gain to make the x coeffs integers. - // during filtering, the delay state will include the gain multiplication - c->cx[0] = lrintf(x0 / c->gain); - c->cx[1] = lrintf(x1 / c->gain); - - return 0; -} - -av_cold struct FFIIRFilterCoeffs *ff_iir_filter_init_coeffs(void *avc, - enum IIRFilterType filt_type, - enum IIRFilterMode filt_mode, - int order, float cutoff_ratio, - float stopband, float ripple) -{ - FFIIRFilterCoeffs *c; - int ret = 0; - - if (order <= 0 || order > MAXORDER || cutoff_ratio >= 1.0) - return NULL; - - if (!(c = av_mallocz(sizeof(*c))) || - !(c->cx = av_malloc (sizeof(c->cx[0]) * ((order >> 1) + 1))) || - !(c->cy = av_malloc (sizeof(c->cy[0]) * order))) - goto free; - c->order = order; - - switch (filt_type) { - case FF_FILTER_TYPE_BUTTERWORTH: - ret = butterworth_init_coeffs(avc, c, filt_mode, order, cutoff_ratio, - stopband); - break; - case FF_FILTER_TYPE_BIQUAD: - ret = biquad_init_coeffs(avc, c, filt_mode, order, cutoff_ratio, - stopband); - break; - default: - av_log(avc, AV_LOG_ERROR, "filter type is not currently implemented\n"); - goto free; - } - - if (!ret) - return c; -free: - ff_iir_filter_free_coeffsp(&c); - return NULL; -} - -av_cold struct FFIIRFilterState *ff_iir_filter_init_state(int order) -{ - FFIIRFilterState *s = av_mallocz(sizeof(FFIIRFilterState) + sizeof(s->x[0]) * (order - 1)); - return s; -} - -#define CONV_S16(dest, source) dest = av_clip_int16(lrintf(source)); - -#define CONV_FLT(dest, source) dest = source; - -#define FILTER_BW_O4_1(i0, i1, i2, i3, fmt) \ - in = *src0 * c->gain + \ - c->cy[0] * s->x[i0] + \ - c->cy[1] * s->x[i1] + \ - c->cy[2] * s->x[i2] + \ - c->cy[3] * s->x[i3]; \ - res = (s->x[i0] + in) * 1 + \ - (s->x[i1] + s->x[i3]) * 4 + \ - s->x[i2] * 6; \ - CONV_ ## fmt(*dst0, res) \ - s->x[i0] = in; \ - src0 += sstep; \ - dst0 += dstep; - -#define FILTER_BW_O4(type, fmt) { \ - int i; \ - const type *src0 = src; \ - type *dst0 = dst; \ - for (i = 0; i < size; i += 4) { \ - float in, res; \ - FILTER_BW_O4_1(0, 1, 2, 3, fmt); \ - FILTER_BW_O4_1(1, 2, 3, 0, fmt); \ - FILTER_BW_O4_1(2, 3, 0, 1, fmt); \ - FILTER_BW_O4_1(3, 0, 1, 2, fmt); \ - } \ -} - -#define FILTER_DIRECT_FORM_II(type, fmt) { \ - int i; \ - const type *src0 = src; \ - type *dst0 = dst; \ - for (i = 0; i < size; i++) { \ - int j; \ - float in, res; \ - in = *src0 * c->gain; \ - for (j = 0; j < c->order; j++) \ - in += c->cy[j] * s->x[j]; \ - res = s->x[0] + in + s->x[c->order >> 1] * c->cx[c->order >> 1]; \ - for (j = 1; j < c->order >> 1; j++) \ - res += (s->x[j] + s->x[c->order - j]) * c->cx[j]; \ - for (j = 0; j < c->order - 1; j++) \ - s->x[j] = s->x[j + 1]; \ - CONV_ ## fmt(*dst0, res) \ - s->x[c->order - 1] = in; \ - src0 += sstep; \ - dst0 += dstep; \ - } \ -} - -#define FILTER_O2(type, fmt) { \ - int i; \ - const type *src0 = src; \ - type *dst0 = dst; \ - for (i = 0; i < size; i++) { \ - float in = *src0 * c->gain + \ - s->x[0] * c->cy[0] + \ - s->x[1] * c->cy[1]; \ - CONV_ ## fmt(*dst0, s->x[0] + in + s->x[1] * c->cx[1]) \ - s->x[0] = s->x[1]; \ - s->x[1] = in; \ - src0 += sstep; \ - dst0 += dstep; \ - } \ -} - -/** - * Perform IIR filtering on floating-point input samples. - * - * @param coeffs pointer to filter coefficients - * @param state pointer to filter state - * @param size input length - * @param src source samples - * @param sstep source stride - * @param dst filtered samples (destination may be the same as input) - * @param dstep destination stride - */ -static void iir_filter_flt(const struct FFIIRFilterCoeffs *c, - struct FFIIRFilterState *s, int size, - const float *src, ptrdiff_t sstep, - float *dst, ptrdiff_t dstep) -{ - if (c->order == 2) { - FILTER_O2(float, FLT) - } else if (c->order == 4) { - FILTER_BW_O4(float, FLT) - } else { - FILTER_DIRECT_FORM_II(float, FLT) - } -} - -av_cold void ff_iir_filter_free_statep(struct FFIIRFilterState **state) -{ - av_freep(state); -} - -av_cold void ff_iir_filter_free_coeffsp(struct FFIIRFilterCoeffs **coeffsp) -{ - struct FFIIRFilterCoeffs *coeffs = *coeffsp; - if (coeffs) { - av_freep(&coeffs->cx); - av_freep(&coeffs->cy); - } - av_freep(coeffsp); -} - -void ff_iir_filter_init(FFIIRFilterContext *f) { - f->filter_flt = iir_filter_flt; - -#if HAVE_MIPSFPU - ff_iir_filter_init_mips(f); -#endif -} diff --git a/libavcodec/iirfilter.h b/libavcodec/iirfilter.h deleted file mode 100644 index 8ab8ae68c..000000000 --- a/libavcodec/iirfilter.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * IIR filter - * Copyright (c) 2008 Konstantin Shishkov - * - * 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 - * IIR filter interface - */ - -#ifndef AVCODEC_IIRFILTER_H -#define AVCODEC_IIRFILTER_H - -#include - -struct FFIIRFilterCoeffs; -struct FFIIRFilterState; - -enum IIRFilterType{ - FF_FILTER_TYPE_BESSEL, - FF_FILTER_TYPE_BIQUAD, - FF_FILTER_TYPE_BUTTERWORTH, - FF_FILTER_TYPE_CHEBYSHEV, - FF_FILTER_TYPE_ELLIPTIC, -}; - -enum IIRFilterMode{ - FF_FILTER_MODE_LOWPASS, - FF_FILTER_MODE_HIGHPASS, - FF_FILTER_MODE_BANDPASS, - FF_FILTER_MODE_BANDSTOP, -}; - -typedef struct FFIIRFilterContext { - /** - * Perform IIR filtering on floating-point input samples. - * - * @param coeffs pointer to filter coefficients - * @param state pointer to filter state - * @param size input length - * @param src source samples - * @param sstep source stride - * @param dst filtered samples (destination may be the same as input) - * @param dstep destination stride - */ - void (*filter_flt)(const struct FFIIRFilterCoeffs *coeffs, - struct FFIIRFilterState *state, int size, - const float *src, ptrdiff_t sstep, float *dst, ptrdiff_t dstep); -} FFIIRFilterContext; - -/** - * Initialize FFIIRFilterContext - */ -void ff_iir_filter_init(FFIIRFilterContext *f); -void ff_iir_filter_init_mips(FFIIRFilterContext *f); - -/** - * Initialize filter coefficients. - * - * @param avc a pointer to an arbitrary struct of which the first - * field is a pointer to an AVClass struct - * @param filt_type filter type (e.g. Butterworth) - * @param filt_mode filter mode (e.g. lowpass) - * @param order filter order - * @param cutoff_ratio cutoff to input frequency ratio - * @param stopband stopband to input frequency ratio (used by bandpass and bandstop filter modes) - * @param ripple ripple factor (used only in Chebyshev filters) - * - * @return pointer to filter coefficients structure or NULL if filter cannot be created - */ -struct FFIIRFilterCoeffs* ff_iir_filter_init_coeffs(void *avc, - enum IIRFilterType filt_type, - enum IIRFilterMode filt_mode, - int order, float cutoff_ratio, - float stopband, float ripple); - -/** - * Create new filter state. - * - * @param order filter order - * - * @return pointer to new filter state or NULL if state creation fails - */ -struct FFIIRFilterState* ff_iir_filter_init_state(int order); - -/** - * Free filter coefficients. - * - * @param coeffs pointer allocated with ff_iir_filter_init_coeffs() - */ -void ff_iir_filter_free_coeffsp(struct FFIIRFilterCoeffs **coeffs); - -/** - * Free and zero filter state. - * - * @param state pointer to pointer allocated with ff_iir_filter_init_state() - */ -void ff_iir_filter_free_statep(struct FFIIRFilterState **state); - -#endif /* AVCODEC_IIRFILTER_H */ diff --git a/libavcodec/ilbcdec.c b/libavcodec/ilbcdec.c index 81b9a49f4..8b495a2f8 100644 --- a/libavcodec/ilbcdec.c +++ b/libavcodec/ilbcdec.c @@ -1099,7 +1099,7 @@ static void do_plc(int16_t *plc_residual, /* (o) concealed residual */ use_gain = 29491; /* 0.9 in Q15 */ } - /* Compute mixing factor of picth repeatition and noise: + /* Compute mixing factor of picth repetition and noise: for max_per>0.7 set periodicity to 1.0 0.4prevResidual[pick]; } - /* pitch repeatition component */ + /* pitch repetition component */ pick = i - use_lag; if (pick < 0) { @@ -1162,7 +1162,7 @@ static void do_plc(int16_t *plc_residual, /* (o) concealed residual */ tot_gain = SPL_MUL_16_16_RSFT(29491, use_gain, 15); /* 0.9*use_gain */ } - /* mix noise and pitch repeatition */ + /* mix noise and pitch repetition */ plc_residual[i] = SPL_MUL_16_16_RSFT(tot_gain, (pitchfact * plc_residual[i] + (32767 - pitchfact) * randvec[i] + 16384) >> 15, 15); /* Shifting down the result one step extra to ensure that no overflow diff --git a/libavcodec/imc.c b/libavcodec/imc.c index 72c4c6ff8..fa02fd5d8 100644 --- a/libavcodec/imc.c +++ b/libavcodec/imc.c @@ -1033,8 +1033,6 @@ const FFCodec ff_imc_decoder = { FF_CODEC_DECODE_CB(imc_decode_frame), .flush = flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif @@ -1050,8 +1048,6 @@ const FFCodec ff_iac_decoder = { FF_CODEC_DECODE_CB(imc_decode_frame), .flush = flush, .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/imm4.c b/libavcodec/imm4.c index 573b61483..d945a440f 100644 --- a/libavcodec/imm4.c +++ b/libavcodec/imm4.c @@ -23,6 +23,7 @@ #include #include +#include "libavutil/attributes.h" #include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" @@ -518,7 +519,7 @@ static av_cold int decode_init(AVCodecContext *avctx) return 0; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { IMM4Context *s = avctx->priv_data; diff --git a/libavcodec/imm5.c b/libavcodec/imm5.c index 793428893..b1cda453c 100644 --- a/libavcodec/imm5.c +++ b/libavcodec/imm5.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" +#include "libavutil/attributes_internal.h" #include "libavutil/intreadwrite.h" #include "avcodec.h" @@ -51,32 +53,27 @@ static const struct IMM5_unit { static av_cold int imm5_init(AVCodecContext *avctx) { IMM5Context *ctx = avctx->priv_data; - const AVCodec *codec; int ret; - codec = avcodec_find_decoder(AV_CODEC_ID_H264); - if (!codec) - return AVERROR_BUG; - ctx->h264_avctx = avcodec_alloc_context3(codec); + EXTERN const FFCodec ff_h264_decoder; + ctx->h264_avctx = avcodec_alloc_context3(&ff_h264_decoder.p); if (!ctx->h264_avctx) return AVERROR(ENOMEM); ctx->h264_avctx->thread_count = 1; ctx->h264_avctx->flags = avctx->flags; ctx->h264_avctx->flags2 = avctx->flags2; - ret = avcodec_open2(ctx->h264_avctx, codec, NULL); + ret = avcodec_open2(ctx->h264_avctx, NULL, NULL); if (ret < 0) return ret; - codec = avcodec_find_decoder(AV_CODEC_ID_HEVC); - if (!codec) - return AVERROR_BUG; - ctx->hevc_avctx = avcodec_alloc_context3(codec); + EXTERN const FFCodec ff_hevc_decoder; + ctx->hevc_avctx = avcodec_alloc_context3(&ff_hevc_decoder.p); if (!ctx->hevc_avctx) return AVERROR(ENOMEM); ctx->hevc_avctx->thread_count = 1; ctx->hevc_avctx->flags = avctx->flags; ctx->hevc_avctx->flags2 = avctx->flags2; - ret = avcodec_open2(ctx->hevc_avctx, codec, NULL); + ret = avcodec_open2(ctx->hevc_avctx, NULL, NULL); if (ret < 0) return ret; @@ -161,7 +158,7 @@ static int imm5_decode_frame(AVCodecContext *avctx, AVFrame *frame, return avpkt->size; } -static void imm5_flush(AVCodecContext *avctx) +static av_cold void imm5_flush(AVCodecContext *avctx) { IMM5Context *ctx = avctx->priv_data; diff --git a/libavcodec/imx.c b/libavcodec/imx.c index 0d9d9b5bb..0f4327ddf 100644 --- a/libavcodec/imx.c +++ b/libavcodec/imx.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "libavutil/common.h" #include "avcodec.h" #include "bytestream.h" @@ -58,19 +59,9 @@ static int imx_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return ret; if (ff_copy_palette(imx->pal, avpkt, avctx)) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif frame->flags |= AV_FRAME_FLAG_KEY; } else { frame->flags &= ~AV_FRAME_FLAG_KEY; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 0; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } bytestream2_init(&gb, avpkt->data, avpkt->size); @@ -168,7 +159,7 @@ FF_ENABLE_DEPRECATION_WARNINGS return avpkt->size; } -static void imx_decode_flush(AVCodecContext *avctx) +static av_cold void imx_decode_flush(AVCodecContext *avctx) { SimbiosisIMXContext *imx = avctx->priv_data; @@ -178,7 +169,7 @@ static void imx_decode_flush(AVCodecContext *avctx) memset(imx->history, 0, sizeof(imx->history)); } -static int imx_decode_close(AVCodecContext *avctx) +static av_cold int imx_decode_close(AVCodecContext *avctx) { SimbiosisIMXContext *imx = avctx->priv_data; diff --git a/libavcodec/indeo3.c b/libavcodec/indeo3.c index fbabd4b6a..ae6fd7290 100644 --- a/libavcodec/indeo3.c +++ b/libavcodec/indeo3.c @@ -324,7 +324,7 @@ static inline uint32_t replicate32(uint32_t a) { /* Fill n lines with 64-bit pixel value pix */ static inline void fill_64(uint8_t *dst, const uint64_t pix, int32_t n, - int32_t row_offset) + ptrdiff_t row_offset) { for (; n > 0; dst += row_offset, n--) AV_WN64A(dst, pix); @@ -429,30 +429,28 @@ if (*data_ptr >= last_ptr) \ static int decode_cell_data(Indeo3DecodeContext *ctx, Cell *cell, - uint8_t *block, uint8_t *ref_block, + uint8_t *block, const uint8_t *ref_block, ptrdiff_t row_offset, int h_zoom, int v_zoom, int mode, const vqEntry *delta[2], int swap_quads[2], const uint8_t **data_ptr, const uint8_t *last_ptr) { int x, y, line, num_lines; int rle_blocks = 0; - uint8_t code, *dst, *ref; const vqEntry *delta_tab; unsigned int dyad1, dyad2; uint64_t pix64; int skip_flag = 0, is_top_of_cell, is_first_row = 1; - int blk_row_offset, line_offset; - blk_row_offset = (row_offset << (2 + v_zoom)) - (cell->width << 2); - line_offset = v_zoom ? row_offset : 0; + const ptrdiff_t blk_row_offset = (row_offset << (2 + v_zoom)) - (cell->width << 2); + const ptrdiff_t line_offset = v_zoom ? row_offset : 0; if (cell->height & v_zoom || cell->width & h_zoom) return IV3_BAD_DATA; for (y = 0; y < cell->height; is_first_row = 0, y += 1 + v_zoom) { for (x = 0; x < cell->width; x += 1 + h_zoom) { - ref = ref_block; - dst = block; + const uint8_t *ref = ref_block; + uint8_t *dst = block; if (rle_blocks > 0) { if (mode <= 4) { @@ -472,7 +470,7 @@ static int decode_cell_data(Indeo3DecodeContext *ctx, Cell *cell, else delta_tab = delta[1]; BUFFER_PRECHECK; - code = bytestream_get_byte(data_ptr); + uint8_t code = bytestream_get_byte(data_ptr); if (code < 248) { if (code < delta_tab->num_dyads) { BUFFER_PRECHECK; @@ -691,9 +689,11 @@ static int decode_cell(Indeo3DecodeContext *ctx, AVCodecContext *avctx, } zoom_fac = mode == 10; - error = decode_cell_data(ctx, cell, block, ref_block, plane->pitch, - zoom_fac, 1, mode, delta, swap_quads, - &data_ptr, last_ptr); + av_assert2(!ref_block); + error = decode_cell_data(ctx, cell, block, + block /* dummy to avoid UB pointer arithmetic */, + plane->pitch, zoom_fac, 1, mode, delta, + swap_quads, &data_ptr, last_ptr); } break; default: diff --git a/libavcodec/intelh263dec.c b/libavcodec/intelh263dec.c index 4efae7938..27a3cadba 100644 --- a/libavcodec/intelh263dec.c +++ b/libavcodec/intelh263dec.c @@ -19,108 +19,109 @@ */ #include "codec_internal.h" +#include "h263.h" #include "mpegvideo.h" #include "mpegvideodec.h" #include "h263data.h" #include "h263dec.h" /* don't understand why they choose a different header ! */ -int ff_intel_h263_decode_picture_header(MpegEncContext *s) +int ff_intel_h263_decode_picture_header(H263DecContext *const h) { int format; - if (get_bits_left(&s->gb) == 64) { /* special dummy frames */ + if (get_bits_left(&h->gb) == 64) { /* special dummy frames */ return FRAME_SKIPPED; } /* picture header */ - if (get_bits(&s->gb, 22) != 0x20) { - av_log(s->avctx, AV_LOG_ERROR, "Bad picture start code\n"); + if (get_bits(&h->gb, 22) != 0x20) { + av_log(h->c.avctx, AV_LOG_ERROR, "Bad picture start code\n"); return -1; } - s->picture_number = get_bits(&s->gb, 8); /* picture timestamp */ + h->picture_number = get_bits(&h->gb, 8); /* picture timestamp */ - if (check_marker(s->avctx, &s->gb, "after picture_number") != 1) { + if (check_marker(h->c.avctx, &h->gb, "after picture_number") != 1) { return -1; /* marker */ } - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Bad H.263 id\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Bad H.263 id\n"); return -1; /* H.263 id */ } - skip_bits1(&s->gb); /* split screen off */ - skip_bits1(&s->gb); /* camera off */ - skip_bits1(&s->gb); /* freeze picture release off */ + skip_bits1(&h->gb); /* split screen off */ + skip_bits1(&h->gb); /* camera off */ + skip_bits1(&h->gb); /* freeze picture release off */ - format = get_bits(&s->gb, 3); + format = get_bits(&h->gb, 3); if (format == 0 || format == 6) { - av_log(s->avctx, AV_LOG_ERROR, "Intel H.263 free format not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Intel H.263 free format not supported\n"); return -1; } - s->h263_plus = 0; - s->pict_type = AV_PICTURE_TYPE_I + get_bits1(&s->gb); + h->c.pict_type = AV_PICTURE_TYPE_I + get_bits1(&h->gb); - s->h263_long_vectors = get_bits1(&s->gb); + h->h263_long_vectors = get_bits1(&h->gb); - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "SAC not supported\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "SAC not supported\n"); return -1; /* SAC: off */ } - s->obmc= get_bits1(&s->gb); - s->pb_frame = get_bits1(&s->gb); + h->c.obmc = get_bits1(&h->gb); + h->pb_frame = get_bits1(&h->gb); if (format < 6) { - s->width = ff_h263_format[format][0]; - s->height = ff_h263_format[format][1]; - s->avctx->sample_aspect_ratio.num = 12; - s->avctx->sample_aspect_ratio.den = 11; + h->c.width = ff_h263_format[format][0]; + h->c.height = ff_h263_format[format][1]; + h->c.avctx->sample_aspect_ratio.num = 12; + h->c.avctx->sample_aspect_ratio.den = 11; } else { - format = get_bits(&s->gb, 3); + format = get_bits(&h->gb, 3); if(format == 0 || format == 7){ - av_log(s->avctx, AV_LOG_ERROR, "Wrong Intel H.263 format\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Wrong Intel H.263 format\n"); return -1; } - if(get_bits(&s->gb, 2)) - av_log(s->avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); - s->loop_filter = get_bits1(&s->gb) * !s->avctx->lowres; - if(get_bits1(&s->gb)) - av_log(s->avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); - if(get_bits1(&s->gb)) - s->pb_frame = 2; - if(get_bits(&s->gb, 5)) - av_log(s->avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); - if(get_bits(&s->gb, 5) != 1) - av_log(s->avctx, AV_LOG_ERROR, "Invalid marker\n"); + if (get_bits(&h->gb, 2)) + av_log(h->c.avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); + h->loop_filter = get_bits1(&h->gb) * !h->c.avctx->lowres; + if (get_bits1(&h->gb)) + av_log(h->c.avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); + if (get_bits1(&h->gb)) + h->pb_frame = 2; + if (get_bits(&h->gb, 5)) + av_log(h->c.avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); + if (get_bits(&h->gb, 5) != 1) + av_log(h->c.avctx, AV_LOG_ERROR, "Invalid marker\n"); } if(format == 6){ - int ar = get_bits(&s->gb, 4); - skip_bits(&s->gb, 9); // display width - check_marker(s->avctx, &s->gb, "in dimensions"); - skip_bits(&s->gb, 9); // display height - if(ar == 15){ - s->avctx->sample_aspect_ratio.num = get_bits(&s->gb, 8); // aspect ratio - width - s->avctx->sample_aspect_ratio.den = get_bits(&s->gb, 8); // aspect ratio - height + int ar = get_bits(&h->gb, 4); + skip_bits(&h->gb, 9); // display width + check_marker(h->c.avctx, &h->gb, "in dimensions"); + skip_bits(&h->gb, 9); // display height + if (ar == 15) { + h->c.avctx->sample_aspect_ratio.num = get_bits(&h->gb, 8); // aspect ratio - width + h->c.avctx->sample_aspect_ratio.den = get_bits(&h->gb, 8); // aspect ratio - height } else { - s->avctx->sample_aspect_ratio = ff_h263_pixel_aspect[ar]; + h->c.avctx->sample_aspect_ratio = ff_h263_pixel_aspect[ar]; } - if (s->avctx->sample_aspect_ratio.num == 0) - av_log(s->avctx, AV_LOG_ERROR, "Invalid aspect ratio.\n"); + if (h->c.avctx->sample_aspect_ratio.num == 0) + av_log(h->c.avctx, AV_LOG_ERROR, "Invalid aspect ratio.\n"); } - s->chroma_qscale= s->qscale = get_bits(&s->gb, 5); - skip_bits1(&s->gb); /* Continuous Presence Multipoint mode: off */ + h->c.chroma_qscale = h->c.qscale = get_bits(&h->gb, 5); + skip_bits1(&h->gb); /* Continuous Presence Multipoint mode: off */ - if(s->pb_frame){ - skip_bits(&s->gb, 3); //temporal reference for B-frame - skip_bits(&s->gb, 2); //dbquant + if (h->pb_frame) { + skip_bits(&h->gb, 3); //temporal reference for B-frame + skip_bits(&h->gb, 2); //dbquant } /* PEI */ - if (skip_1stop_8data_bits(&s->gb) < 0) + if (skip_1stop_8data_bits(&h->gb) < 0) return AVERROR_INVALIDDATA; - s->f_code = 1; - ff_h263_show_pict_info(s); + h->gob_index = H263_GOB_HEIGHT(h->c.height); + + ff_h263_show_pict_info(h, 0); return 0; } @@ -130,7 +131,7 @@ const FFCodec ff_h263i_decoder = { CODEC_LONG_NAME("Intel H.263"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H263I, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(H263DecContext), .init = ff_h263_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, diff --git a/libavcodec/internal.h b/libavcodec/internal.h index 98ab2797c..137fd5274 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -68,7 +68,7 @@ typedef struct AVCodecInternal { struct FramePool *pool; - struct FFRefStructPool *progress_frame_pool; + struct AVRefStructPool *progress_frame_pool; void *thread_ctx; @@ -145,15 +145,6 @@ typedef struct AVCodecInternal { AVFrame *buffer_frame; int draining_done; -#if FF_API_DROPCHANGED - /* used when avctx flag AV_CODEC_FLAG_DROPCHANGED is set */ - int changed_frames_dropped; - int initial_format; - int initial_width, initial_height; - int initial_sample_rate; - AVChannelLayout initial_ch_layout; -#endif - #if CONFIG_LCMS2 FFIccContext icc; /* used to read and write embedded ICC profiles */ #endif diff --git a/libavcodec/interplayacm.c b/libavcodec/interplayacm.c index f39ce36a1..cd2e6faa6 100644 --- a/libavcodec/interplayacm.c +++ b/libavcodec/interplayacm.c @@ -625,6 +625,14 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, return n; } +static void decode_flush(AVCodecContext *avctx) +{ + InterplayACMContext *s = avctx->priv_data; + + s->bitstream_size = 0; + s->bitstream_index = 0; +} + static av_cold int decode_close(AVCodecContext *avctx) { InterplayACMContext *s = avctx->priv_data; @@ -644,6 +652,7 @@ const FFCodec ff_interplay_acm_decoder = { .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_INTERPLAY_ACM, .init = decode_init, + .flush = decode_flush, .close = decode_close, FF_CODEC_DECODE_CB(decode_frame), .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c index 9c13707f8..a3bd93126 100644 --- a/libavcodec/interplayvideo.c +++ b/libavcodec/interplayvideo.c @@ -1315,14 +1315,7 @@ static int ipvideo_decode_frame(AVCodecContext *avctx, AVFrame *frame, return ret; if (!s->is_16bpp) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif } switch (frame_format) { diff --git a/libavcodec/intrax8.c b/libavcodec/intrax8.c index f1dce86a5..ada5fc317 100644 --- a/libavcodec/intrax8.c +++ b/libavcodec/intrax8.c @@ -437,7 +437,7 @@ static void x8_ac_compensation(IntraX8Context *const w, const int direction, const int dc_level) { int t; -#define B(x,y) w->block[0][w->idct_permutation[(x) + (y) * 8]] +#define B(x,y) w->block[w->idsp.idct_permutation[(x) + (y) * 8]] #define T(x) ((x) * dc_level + 0x8000) >> 16; switch (direction) { case 0: @@ -480,24 +480,18 @@ static void x8_ac_compensation(IntraX8Context *const w, const int direction, t = T(1084); // g B(1, 1) += t; - - w->block_last_index[0] = FFMAX(w->block_last_index[0], 7 * 8); break; case 1: B(0, 1) -= T(6269); B(0, 3) -= T(708); B(0, 5) -= T(172); B(0, 7) -= T(73); - - w->block_last_index[0] = FFMAX(w->block_last_index[0], 7 * 8); break; case 2: B(1, 0) -= T(6269); B(3, 0) -= T(708); B(5, 0) -= T(172); B(7, 0) -= T(73); - - w->block_last_index[0] = FFMAX(w->block_last_index[0], 7); break; } #undef B @@ -536,7 +530,7 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma) int sign; av_assert2(w->orient < 12); - w->bdsp.clear_block(w->block[0]); + w->bdsp.clear_block(w->block); if (chroma) dc_mode = 2; @@ -597,12 +591,9 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma) if (use_quant_matrix) level = (level * quant_table[pos]) >> 8; - w->block[0][scantable[pos]] = level; + w->block[scantable[pos]] = level; } while (!final); - - w->block_last_index[0] = pos; } else { // DC only - w->block_last_index[0] = 0; if (w->flat_dc && ((unsigned) (dc_level + 1)) < 3) { // [-1; 1] int32_t divide_quant = !chroma ? w->divide_quant_dc_luma : w->divide_quant_dc_chroma; @@ -622,9 +613,9 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma) zeros_only = dc_level == 0; } if (!chroma) - w->block[0][0] = dc_level * w->quant; + w->block[0] = dc_level * w->quant; else - w->block[0][0] = dc_level * w->quant_dc_chroma; + w->block[0] = dc_level * w->quant_dc_chroma; // there is !zero_only check in the original, but dc_level check is enough if ((unsigned int) (dc_level + 1) >= 3 && (w->edges & 3) != 3) { @@ -633,8 +624,7 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma) * -> 01'10' 10'10' 00'00' 00'01' 01'11' 11'00 => 0x6A017C */ direction = (0x6A017C >> (w->orient * 2)) & 3; if (direction != 3) { - // modify block_last[] - x8_ac_compensation(w, direction, w->block[0][0]); + x8_ac_compensation(w, direction, w->block[0]); } } @@ -647,9 +637,9 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma) w->frame->linesize[!!chroma]); } if (!zeros_only) - w->wdsp.idct_add(w->dest[chroma], + w->idsp.idct_add(w->dest[chroma], w->frame->linesize[!!chroma], - w->block[0]); + w->block); block_placed: if (!chroma) @@ -688,8 +678,7 @@ static void x8_init_block_index(IntraX8Context *w, AVFrame *frame) av_cold int ff_intrax8_common_init(AVCodecContext *avctx, IntraX8Context *w, - int16_t (*block)[64], - int block_last_index[12], + int16_t block[64], int mb_width, int mb_height) { static AVOnce init_static_once = AV_ONCE_INIT; @@ -698,24 +687,20 @@ av_cold int ff_intrax8_common_init(AVCodecContext *avctx, w->mb_width = mb_width; w->mb_height = mb_height; w->block = block; - w->block_last_index = block_last_index; // two rows, 2 blocks per cannon mb w->prediction_table = av_mallocz(w->mb_width * 2 * 2); if (!w->prediction_table) return AVERROR(ENOMEM); - ff_wmv2dsp_init(&w->wdsp); - - ff_init_scantable_permutation(w->idct_permutation, - w->wdsp.idct_perm); + ff_wmv2dsp_init(&w->idsp); ff_permute_scantable(w->permutated_scantable[0], ff_wmv1_scantable[0], - w->idct_permutation); + w->idsp.idct_permutation); ff_permute_scantable(w->permutated_scantable[1], ff_wmv1_scantable[2], - w->idct_permutation); + w->idsp.idct_permutation); ff_permute_scantable(w->permutated_scantable[2], ff_wmv1_scantable[3], - w->idct_permutation); + w->idsp.idct_permutation); ff_intrax8dsp_init(&w->dsp); ff_blockdsp_init(&w->bdsp); diff --git a/libavcodec/intrax8.h b/libavcodec/intrax8.h index b9f8c4250..a936299fb 100644 --- a/libavcodec/intrax8.h +++ b/libavcodec/intrax8.h @@ -21,6 +21,7 @@ #include "blockdsp.h" #include "get_bits.h" +#include "idctdsp.h" #include "intrax8dsp.h" #include "wmv2dsp.h" #include "mpegpicture.h" @@ -35,11 +36,9 @@ typedef struct IntraX8Context { // set by ff_intrax8_common_init uint8_t *prediction_table; // 2 * (mb_w * 2) uint8_t permutated_scantable[3][64]; - WMV2DSPContext wdsp; - uint8_t idct_permutation[64]; + IDCTDSPContext idsp; AVCodecContext *avctx; - int *block_last_index; ///< last nonzero coefficient in block - int16_t (*block)[64]; + int16_t *block; // set by the caller codec IntraX8DSPContext dsp; @@ -77,15 +76,13 @@ typedef struct IntraX8Context { * @param avctx pointer to AVCodecContext * @param w pointer to IntraX8Context * @param block pointer to block array - * @param block_last_index pointer to index array * @param mb_width macroblock width * @param mb_height macroblock height * @return 0 on success, a negative AVERROR value on error */ int ff_intrax8_common_init(AVCodecContext *avctx, IntraX8Context *w, - int16_t (*block)[64], - int block_last_index[12], + int16_t block[64], int mb_width, int mb_height); /** diff --git a/libavcodec/intrax8dsp.c b/libavcodec/intrax8dsp.c index 80c3929f7..267331636 100644 --- a/libavcodec/intrax8dsp.c +++ b/libavcodec/intrax8dsp.c @@ -23,6 +23,7 @@ #include "intrax8dsp.h" #include "libavutil/common.h" +#include "libavutil/intreadwrite.h" /* * area positions, #3 is 1 pixel only, other are 8 pixels @@ -62,11 +63,12 @@ note: 1|2 - mb_x==mb_y==0 - first block, use 0x80 value for all areas; 4 - mb_x>= (mb_width-1) last block in the row, interpolate area #5; -*/ -static void x8_setup_spatial_compensation(uint8_t *src, uint8_t *dst, +static void x8_setup_spatial_compensation(const uint8_t *restrict src, + uint8_t *restrict dst, ptrdiff_t stride, int *range, int *psum, int edges) { - uint8_t *ptr; + const uint8_t *ptr; int sum; int i; int min_pix, max_pix; @@ -160,7 +162,7 @@ static const uint16_t zero_prediction_weights[64 * 2] = { 317, 846, 366, 731, 458, 611, 499, 499, }; -static void spatial_compensation_0(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_0(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int i, j; int x, y; @@ -212,7 +214,7 @@ static void spatial_compensation_0(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_1(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_1(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -223,29 +225,23 @@ static void spatial_compensation_1(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_2(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_2(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { - int x, y; - - for (y = 0; y < 8; y++) { - for (x = 0; x < 8; x++) - dst[x] = src[area4 + 1 + y + x]; + for (int y = 0; y < 8; y++) { + AV_COPY64U(dst, src + area4 + 1 + y); dst += stride; } } -static void spatial_compensation_3(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_3(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { - int x, y; - - for (y = 0; y < 8; y++) { - for (x = 0; x < 8; x++) - dst[x] = src[area4 + ((y + 1) >> 1) + x]; + for (int y = 0; y < 8; y++) { + AV_COPY64U(dst, src + area4 + ((y + 1) >> 1)); dst += stride; } } -static void spatial_compensation_4(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_4(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -256,7 +252,7 @@ static void spatial_compensation_4(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_5(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_5(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -271,18 +267,15 @@ static void spatial_compensation_5(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_6(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_6(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { - int x, y; - - for (y = 0; y < 8; y++) { - for (x = 0; x < 8; x++) - dst[x] = src[area3 + x - y]; + for (int y = 0; y < 8; y++) { + AV_COPY64U(dst, src + area3 - y); dst += stride; } } -static void spatial_compensation_7(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_7(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -297,7 +290,7 @@ static void spatial_compensation_7(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_8(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_8(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -308,7 +301,7 @@ static void spatial_compensation_8(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_9(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_9(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -319,7 +312,7 @@ static void spatial_compensation_9(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_10(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_10(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -330,7 +323,7 @@ static void spatial_compensation_10(uint8_t *src, uint8_t *dst, ptrdiff_t stride } } -static void spatial_compensation_11(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_11(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; diff --git a/libavcodec/intrax8dsp.h b/libavcodec/intrax8dsp.h index bf42698ed..6cf673c36 100644 --- a/libavcodec/intrax8dsp.h +++ b/libavcodec/intrax8dsp.h @@ -26,9 +26,9 @@ typedef struct IntraX8DSPContext { void (*v_loop_filter)(uint8_t *src, ptrdiff_t stride, int qscale); void (*h_loop_filter)(uint8_t *src, ptrdiff_t stride, int qscale); - void (*spatial_compensation[12])(uint8_t *src, uint8_t *dst, + void (*spatial_compensation[12])(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride); - void (*setup_spatial_compensation)(uint8_t *src, uint8_t *dst, + void (*setup_spatial_compensation)(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride, int *range, int *sum, int edges); } IntraX8DSPContext; diff --git a/libavcodec/ipu_parser.c b/libavcodec/ipu_parser.c index 1193a65b1..324f0898e 100644 --- a/libavcodec/ipu_parser.c +++ b/libavcodec/ipu_parser.c @@ -25,6 +25,7 @@ */ #include "parser.h" +#include "parser_internal.h" typedef struct IPUParseContext { ParseContext pc; @@ -69,9 +70,9 @@ static int ipu_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_ipu_parser = { - .codec_ids = { AV_CODEC_ID_IPU }, +const FFCodecParser ff_ipu_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_IPU), .priv_data_size = sizeof(IPUParseContext), - .parser_parse = ipu_parse, - .parser_close = ff_parse_close, + .parse = ipu_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/ituh263dec.c b/libavcodec/ituh263dec.c index e0f3034e5..53ead30c4 100644 --- a/libavcodec/ituh263dec.c +++ b/libavcodec/ituh263dec.c @@ -77,22 +77,22 @@ static const int16_t h263_mb_type_b_map[15]= { MB_TYPE_INTRA4x4 | MB_TYPE_CBP | MB_TYPE_QUANT, }; -void ff_h263_show_pict_info(MpegEncContext *s){ - if(s->avctx->debug&FF_DEBUG_PICT_INFO){ - av_log(s->avctx, AV_LOG_DEBUG, "qp:%d %c size:%d rnd:%d%s%s%s%s%s%s%s%s%s %d/%d\n", - s->qscale, av_get_picture_type_char(s->pict_type), - s->gb.size_in_bits, 1-s->no_rounding, - s->obmc ? " AP" : "", - s->umvplus ? " UMV" : "", - s->h263_long_vectors ? " LONG" : "", - s->h263_plus ? " +" : "", - s->h263_aic ? " AIC" : "", - s->alt_inter_vlc ? " AIV" : "", - s->modified_quant ? " MQ" : "", - s->loop_filter ? " LOOP" : "", - s->h263_slice_structured ? " SS" : "", - s->avctx->framerate.num, s->avctx->framerate.den - ); +void ff_h263_show_pict_info(H263DecContext *const h, int h263_plus) +{ + if (h->c.avctx->debug&FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "qp:%d %c size:%d rnd:%d%s%s%s%s%s%s%s%s%s %d/%d\n", + h->c.qscale, av_get_picture_type_char(h->c.pict_type), + h->gb.size_in_bits, 1-h->c.no_rounding, + h->c.obmc ? " AP" : "", + h->umvplus ? " UMV" : "", + h->h263_long_vectors ? " LONG" : "", + h263_plus ? " +" : "", + h->c.h263_aic ? " AIC" : "", + h->alt_inter_vlc ? " AIV" : "", + h->modified_quant ? " MQ" : "", + h->loop_filter ? " LOOP" : "", + h->h263_slice_structured ? " SS" : "", + h->c.avctx->framerate.num, h->c.avctx->framerate.den); } } @@ -122,7 +122,6 @@ static av_cold void h263_decode_init_vlc(void) VLC_INIT_STATIC_TABLE(ff_h263_mv_vlc, H263_MV_VLC_BITS, 33, &ff_mvtab[0][1], 2, 1, &ff_mvtab[0][0], 2, 1, 0); - ff_h263_init_rl_inter(); VLC_INIT_RL(ff_h263_rl_inter, 554); INIT_FIRST_VLC_RL(ff_rl_intra_aic, 554); VLC_INIT_STATIC_SPARSE_TABLE(h263_mbtype_b_vlc, H263_MBTYPE_B_VLC_BITS, 15, @@ -140,16 +139,16 @@ av_cold void ff_h263_decode_init_vlc(void) ff_thread_once(&init_static_once, h263_decode_init_vlc); } -int ff_h263_decode_mba(MpegEncContext *s) +int ff_h263_decode_mba(H263DecContext *const h) { int i, mb_pos; for (i = 0; i < 6; i++) - if (s->mb_num - 1 <= ff_mba_max[i]) + if (h->c.mb_num - 1 <= ff_mba_max[i]) break; - mb_pos = get_bits(&s->gb, ff_mba_length[i]); - s->mb_x = mb_pos % s->mb_width; - s->mb_y = mb_pos / s->mb_width; + mb_pos = get_bits(&h->gb, ff_mba_length[i]); + h->c.mb_x = mb_pos % h->c.mb_width; + h->c.mb_y = mb_pos / h->c.mb_width; return mb_pos; } @@ -158,53 +157,54 @@ int ff_h263_decode_mba(MpegEncContext *s) * Decode the group of blocks header or slice header. * @return <0 if an error occurred */ -static int h263_decode_gob_header(MpegEncContext *s) +static int h263_decode_gob_header(H263DecContext *const h) { unsigned int val, gob_number; int left; /* Check for GOB Start Code */ - val = show_bits(&s->gb, 16); + val = show_bits(&h->gb, 16); if(val) return -1; /* We have a GBSC probably with GSTUFF */ - skip_bits(&s->gb, 16); /* Drop the zeros */ - left= get_bits_left(&s->gb); + skip_bits(&h->gb, 16); /* Drop the zeros */ + left = get_bits_left(&h->gb); left = FFMIN(left, 32); //MN: we must check the bits left or we might end in an infinite loop (or segfault) for(;left>13; left--){ - if(get_bits1(&s->gb)) break; /* Seek the '1' bit */ + if (get_bits1(&h->gb)) + break; /* Seek the '1' bit */ } if(left<=13) return -1; - if(s->h263_slice_structured){ - if(check_marker(s->avctx, &s->gb, "before MBA")==0) + if (h->h263_slice_structured) { + if (check_marker(h->c.avctx, &h->gb, "before MBA")==0) return -1; - ff_h263_decode_mba(s); + ff_h263_decode_mba(h); - if(s->mb_num > 1583) - if(check_marker(s->avctx, &s->gb, "after MBA")==0) + if (h->c.mb_num > 1583) + if (check_marker(h->c.avctx, &h->gb, "after MBA")==0) return -1; - s->qscale = get_bits(&s->gb, 5); /* SQUANT */ - if(check_marker(s->avctx, &s->gb, "after SQUANT")==0) + h->c.qscale = get_bits(&h->gb, 5); /* SQUANT */ + if (check_marker(h->c.avctx, &h->gb, "after SQUANT")==0) return -1; - skip_bits(&s->gb, 2); /* GFID */ + skip_bits(&h->gb, 2); /* GFID */ }else{ - gob_number = get_bits(&s->gb, 5); /* GN */ - s->mb_x= 0; - s->mb_y= s->gob_index* gob_number; - skip_bits(&s->gb, 2); /* GFID */ - s->qscale = get_bits(&s->gb, 5); /* GQUANT */ + gob_number = get_bits(&h->gb, 5); /* GN */ + h->c.mb_x = 0; + h->c.mb_y = h->gob_index* gob_number; + skip_bits(&h->gb, 2); /* GFID */ + h->c.qscale = get_bits(&h->gb, 5); /* GQUANT */ } - if(s->mb_y >= s->mb_height) + if (h->c.mb_y >= h->c.mb_height) return -1; - if(s->qscale==0) + if (h->c.qscale==0) return -1; return 0; @@ -214,79 +214,84 @@ static int h263_decode_gob_header(MpegEncContext *s) * Decode the group of blocks / video packet header / slice header (MPEG-4 Studio). * @return bit position of the resync_marker, or <0 if none was found */ -int ff_h263_resync(MpegEncContext *s){ +int ff_h263_resync(H263DecContext *const h) +{ int left, pos, ret; /* In MPEG-4 studio mode look for a new slice startcode * and decode slice header */ - if(s->codec_id==AV_CODEC_ID_MPEG4 && s->studio_profile) { - align_get_bits(&s->gb); + if (h->c.codec_id==AV_CODEC_ID_MPEG4 && h->c.studio_profile) { + align_get_bits(&h->gb); - while (get_bits_left(&s->gb) >= 32 && show_bits_long(&s->gb, 32) != SLICE_STARTCODE) { - get_bits(&s->gb, 8); + while (get_bits_left(&h->gb) >= 32 && show_bits_long(&h->gb, 32) != SLICE_STARTCODE) { + get_bits(&h->gb, 8); } - if (get_bits_left(&s->gb) >= 32 && show_bits_long(&s->gb, 32) == SLICE_STARTCODE) - return get_bits_count(&s->gb); + if (get_bits_left(&h->gb) >= 32 && show_bits_long(&h->gb, 32) == SLICE_STARTCODE) + return get_bits_count(&h->gb); else return -1; } - if(s->codec_id==AV_CODEC_ID_MPEG4){ - skip_bits1(&s->gb); - align_get_bits(&s->gb); + if (h->c.codec_id==AV_CODEC_ID_MPEG4){ + skip_bits1(&h->gb); + align_get_bits(&h->gb); } - if(show_bits(&s->gb, 16)==0){ - pos= get_bits_count(&s->gb); - if(CONFIG_MPEG4_DECODER && s->codec_id==AV_CODEC_ID_MPEG4) - ret= ff_mpeg4_decode_video_packet_header(s->avctx->priv_data); + if (show_bits(&h->gb, 16) ==0) { + pos = get_bits_count(&h->gb); +#if CONFIG_MPEG4_DECODER + if (h->c.codec_id == AV_CODEC_ID_MPEG4) + ret = ff_mpeg4_decode_video_packet_header(h); else - ret= h263_decode_gob_header(s); +#endif + ret = h263_decode_gob_header(h); if(ret>=0) return pos; } //OK, it's not where it is supposed to be ... - s->gb= s->last_resync_gb; - align_get_bits(&s->gb); - left= get_bits_left(&s->gb); + h->gb = h->last_resync_gb; + align_get_bits(&h->gb); + left = get_bits_left(&h->gb); for(;left>16+1+5+5; left-=8){ - if(show_bits(&s->gb, 16)==0){ - GetBitContext bak= s->gb; + if (show_bits(&h->gb, 16) == 0){ + GetBitContext bak = h->gb; - pos= get_bits_count(&s->gb); - if(CONFIG_MPEG4_DECODER && s->codec_id==AV_CODEC_ID_MPEG4) - ret= ff_mpeg4_decode_video_packet_header(s->avctx->priv_data); + pos = get_bits_count(&h->gb); +#if CONFIG_MPEG4_DECODER + if (h->c.codec_id == AV_CODEC_ID_MPEG4) + ret = ff_mpeg4_decode_video_packet_header(h); else - ret= h263_decode_gob_header(s); +#endif + ret = h263_decode_gob_header(h); if(ret>=0) return pos; - s->gb= bak; + h->gb = bak; } - skip_bits(&s->gb, 8); + skip_bits(&h->gb, 8); } return -1; } -int ff_h263_decode_motion(MpegEncContext * s, int pred, int f_code) +int ff_h263_decode_motion(H263DecContext *const h, int pred, int f_code) { int code, val, sign, shift; - code = get_vlc2(&s->gb, ff_h263_mv_vlc, H263_MV_VLC_BITS, 2); + code = get_vlc2(&h->gb, ff_h263_mv_vlc, H263_MV_VLC_BITS, 2); if (code == 0) return pred; if (code < 0) return 0xffff; - sign = get_bits1(&s->gb); + sign = get_bits1(&h->gb); shift = f_code - 1; val = code; if (shift) { val = (val - 1) << shift; - val |= get_bits(&s->gb, shift); + val |= get_bits(&h->gb, shift); val++; } if (sign) @@ -294,7 +299,7 @@ int ff_h263_decode_motion(MpegEncContext * s, int pred, int f_code) val += pred; /* modulo decoding */ - if (!s->h263_long_vectors) { + if (!h->h263_long_vectors) { val = sign_extend(val, 5 + f_code); } else { /* horrible H.263 long vector mode */ @@ -309,21 +314,21 @@ int ff_h263_decode_motion(MpegEncContext * s, int pred, int f_code) /* Decode RVLC of H.263+ UMV */ -static int h263p_decode_umotion(MpegEncContext * s, int pred) +static int h263p_decode_umotion(H263DecContext *const h, int pred) { int code = 0, sign; - if (get_bits1(&s->gb)) /* Motion difference = 0 */ + if (get_bits1(&h->gb)) /* Motion difference = 0 */ return pred; - code = 2 + get_bits1(&s->gb); + code = 2 + get_bits1(&h->gb); - while (get_bits1(&s->gb)) + while (get_bits1(&h->gb)) { code <<= 1; - code += get_bits1(&s->gb); + code += get_bits1(&h->gb); if (code >= 32768) { - avpriv_request_sample(s->avctx, "Huge DMV"); + avpriv_request_sample(h->c.avctx, "Huge DMV"); return 0xffff; } } @@ -331,7 +336,7 @@ static int h263p_decode_umotion(MpegEncContext * s, int pred) code >>= 1; code = (sign) ? (pred - code) : (pred + code); - ff_tlog(s->avctx,"H.263+ UMV Motion = %d\n", code); + ff_tlog(h->c.avctx,"H.263+ UMV Motion = %d\n", code); return code; } @@ -339,82 +344,79 @@ static int h263p_decode_umotion(MpegEncContext * s, int pred) /** * read the next MVs for OBMC. yes this is an ugly hack, feel free to send a patch :) */ -static void preview_obmc(MpegEncContext *s){ - GetBitContext gb= s->gb; +static void preview_obmc(H263DecContext *const h) +{ + GetBitContext gb = h->gb; int cbpc, i, pred_x, pred_y, mx, my; int16_t *mot_val; - const int xy= s->mb_x + 1 + s->mb_y * s->mb_stride; - const int stride= s->b8_stride*2; + const int xy = h->c.mb_x + 1 + h->c.mb_y * h->c.mb_stride; + const int stride = h->c.b8_stride * 2; for(i=0; i<4; i++) - s->block_index[i]+= 2; + h->c.block_index[i] += 2; for(i=4; i<6; i++) - s->block_index[i]+= 1; - s->mb_x++; + h->c.block_index[i] += 1; + h->c.mb_x++; - av_assert2(s->pict_type == AV_PICTURE_TYPE_P); + av_assert2(h->c.pict_type == AV_PICTURE_TYPE_P); do{ - if (get_bits1(&s->gb)) { + if (get_bits1(&h->gb)) { /* skip mb */ - mot_val = s->cur_pic.motion_val[0][s->block_index[0]]; + mot_val = h->c.cur_pic.motion_val[0][h->c.block_index[0]]; mot_val[0 ]= mot_val[2 ]= mot_val[0+stride]= mot_val[2+stride]= 0; mot_val[1 ]= mot_val[3 ]= mot_val[1+stride]= mot_val[3+stride]= 0; - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; goto end; } - cbpc = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); }while(cbpc == 20); if(cbpc & 4){ - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA; }else{ - get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpc & 8) { - if(s->modified_quant){ - if(get_bits1(&s->gb)) skip_bits(&s->gb, 1); - else skip_bits(&s->gb, 5); - }else - skip_bits(&s->gb, 2); + skip_bits(&h->gb, h->modified_quant ? (get_bits1(&h->gb) ? 1 : 5) : 2); } if ((cbpc & 16) == 0) { - s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; /* 16x16 motion prediction */ - mot_val= ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + mot_val= ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); + my = ff_h263_decode_motion(h, pred_y, 1); mot_val[0 ]= mot_val[2 ]= mot_val[0+stride]= mot_val[2+stride]= mx; mot_val[1 ]= mot_val[3 ]= mot_val[1+stride]= mot_val[3+stride]= my; } else { - s->cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; + h->c.cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; for(i=0;i<4;i++) { - mot_val = ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + mot_val = ff_h263_pred_motion(&h->c, i, 0, &pred_x, &pred_y); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); - if (s->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) - skip_bits1(&s->gb); /* Bit stuffing to prevent PSC */ + my = ff_h263_decode_motion(h, pred_y, 1); + if (h->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) + skip_bits1(&h->gb); /* Bit stuffing to prevent PSC */ mot_val[0] = mx; mot_val[1] = my; } @@ -423,57 +425,50 @@ static void preview_obmc(MpegEncContext *s){ end: for(i=0; i<4; i++) - s->block_index[i]-= 2; + h->c.block_index[i] -= 2; for(i=4; i<6; i++) - s->block_index[i]-= 1; - s->mb_x--; + h->c.block_index[i] -= 1; + h->c.mb_x--; - s->gb= gb; + h->gb = gb; } -static void h263_decode_dquant(MpegEncContext *s){ +static void h263_decode_dquant(H263DecContext *const h) +{ static const int8_t quant_tab[4] = { -1, -2, 1, 2 }; + int qscale; - if(s->modified_quant){ - if(get_bits1(&s->gb)) - s->qscale= ff_modified_quant_tab[get_bits1(&s->gb)][ s->qscale ]; + if (h->modified_quant) { + if (get_bits1(&h->gb)) + qscale = ff_modified_quant_tab[get_bits1(&h->gb)][h->c.qscale]; else - s->qscale= get_bits(&s->gb, 5); + qscale = get_bits(&h->gb, 5); }else - s->qscale += quant_tab[get_bits(&s->gb, 2)]; - ff_set_qscale(s, s->qscale); + qscale = h->c.qscale + quant_tab[get_bits(&h->gb, 2)]; + ff_set_qscale(&h->c, qscale); } static void h263_pred_acdc(MpegEncContext * s, int16_t *block, int n) { - int x, y, wrap, a, c, pred_dc, scale; - int16_t *dc_val, *ac_val, *ac_val1; + int wrap, a, c, pred_dc, scale; + const int xy = s->block_index[n]; + int16_t *const dc_val = s->dc_val + xy; + int16_t *const ac_val = (s->ac_val + xy)[0]; /* find prediction */ if (n < 4) { - x = 2 * s->mb_x + (n & 1); - y = 2 * s->mb_y + (n>> 1); wrap = s->b8_stride; - dc_val = s->dc_val[0]; - ac_val = s->ac_val[0][0]; scale = s->y_dc_scale; } else { - x = s->mb_x; - y = s->mb_y; wrap = s->mb_stride; - dc_val = s->dc_val[n - 4 + 1]; - ac_val = s->ac_val[n - 4 + 1][0]; scale = s->c_dc_scale; } - ac_val += ((y) * wrap + (x)) * 16; - ac_val1 = ac_val; - /* B C * A X */ - a = dc_val[(x - 1) + (y) * wrap]; - c = dc_val[(x) + (y - 1) * wrap]; + a = dc_val[-1]; + c = dc_val[-wrap]; /* No prediction outside GOB boundary */ if (s->first_slice_line && n != 3) { @@ -486,18 +481,18 @@ static void h263_pred_acdc(MpegEncContext * s, int16_t *block, int n) if (s->h263_aic_dir) { /* left prediction */ if (a != 1024) { - ac_val -= 16; + int16_t *const ac_val2 = ac_val - 16; for (int i = 1; i < 8; i++) { - block[s->idsp.idct_permutation[i << 3]] += ac_val[i]; + block[s->idsp.idct_permutation[i << 3]] += ac_val2[i]; } pred_dc = a; } } else { /* top prediction */ if (c != 1024) { - ac_val -= 16 * wrap; + int16_t *const ac_val2 = ac_val - 16 * wrap; for (int i = 1; i < 8; i++) { - block[s->idsp.idct_permutation[i]] += ac_val[i + 8]; + block[s->idsp.idct_permutation[i]] += ac_val2[i + 8]; } pred_dc = c; } @@ -521,61 +516,63 @@ static void h263_pred_acdc(MpegEncContext * s, int16_t *block, int n) block[0] |= 1; /* Update AC/DC tables */ - dc_val[(x) + (y) * wrap] = block[0]; + *dc_val = block[0]; /* left copy */ for (int i = 1; i < 8; i++) - ac_val1[i] = block[s->idsp.idct_permutation[i << 3]]; + ac_val[i] = block[s->idsp.idct_permutation[i << 3]]; /* top copy */ for (int i = 1; i < 8; i++) - ac_val1[8 + i] = block[s->idsp.idct_permutation[i]]; + ac_val[8 + i] = block[s->idsp.idct_permutation[i]]; } -static int h263_decode_block(MpegEncContext * s, int16_t * block, +static int h263_decode_block(H263DecContext *const h, int16_t block[64], int n, int coded) { int level, i, j, run; const RLTable *rl = &ff_h263_rl_inter; const uint8_t *scan_table; - GetBitContext gb= s->gb; + GetBitContext gb = h->gb; - scan_table = s->intra_scantable.permutated; - if (s->h263_aic && s->mb_intra) { - rl = &ff_rl_intra_aic; + scan_table = h->c.intra_scantable.permutated; + if (h->c.h263_aic && h->c.mb_intra) { i = 0; - if (s->ac_pred) { - if (s->h263_aic_dir) - scan_table = s->permutated_intra_v_scantable; /* left */ + if (!coded) + goto not_coded; + rl = &ff_rl_intra_aic; + if (h->c.ac_pred) { + if (h->c.h263_aic_dir) + scan_table = h->permutated_intra_v_scantable; /* left */ else - scan_table = s->permutated_intra_h_scantable; /* top */ + scan_table = h->permutated_intra_h_scantable; /* top */ } - } else if (s->mb_intra) { + } else if (h->c.mb_intra) { /* DC coef */ - if (CONFIG_RV10_DECODER && s->codec_id == AV_CODEC_ID_RV10) { - if (s->rv10_version == 3 && s->pict_type == AV_PICTURE_TYPE_I) { - int component, diff; - component = (n <= 3 ? 0 : n - 4 + 1); - level = s->last_dc[component]; - if (s->rv10_first_dc_coded[component]) { - diff = ff_rv_decode_dc(s, n); - if (diff < 0) - return -1; - level += diff; - level = level & 0xff; /* handle wrap round */ - s->last_dc[component] = level; + if (CONFIG_RV10_DECODER && h->c.codec_id == AV_CODEC_ID_RV10) { + if (h->rv10_version == 3 && h->c.pict_type == AV_PICTURE_TYPE_I) { + int component = (n <= 3 ? 0 : n - 4 + 1); + level = h->last_dc[component]; + if (h->rv10_first_dc_coded[component]) { + int diff = ff_rv_decode_dc(h, n); + if (diff < 0) + return -1; + level += diff; + level = level & 0xff; /* handle wrap round */ + h->last_dc[component] = level; + } else { + h->rv10_first_dc_coded[component] = 1; + } } else { - s->rv10_first_dc_coded[component] = 1; - } - } else { - level = get_bits(&s->gb, 8); + level = get_bits(&h->gb, 8); if (level == 255) level = 128; - } + } }else{ - level = get_bits(&s->gb, 8); + level = get_bits(&h->gb, 8); if((level&0x7F) == 0){ - av_log(s->avctx, AV_LOG_ERROR, "illegal dc %d at %d %d\n", level, s->mb_x, s->mb_y); - if (s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT)) + av_log(h->c.avctx, AV_LOG_ERROR, "illegal dc %d at %d %d\n", + level, h->c.mb_x, h->c.mb_y); + if (h->c.avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT)) return -1; } if (level == 255) @@ -587,66 +584,65 @@ static int h263_decode_block(MpegEncContext * s, int16_t * block, i = 0; } if (!coded) { - if (s->mb_intra && s->h263_aic) - goto not_coded; - s->block_last_index[n] = i - 1; + h->c.block_last_index[n] = i - 1; return 0; } retry: { - OPEN_READER(re, &s->gb); + OPEN_READER(re, &h->gb); i--; // offset by -1 to allow direct indexing of scan_table for(;;) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, rl->rl_vlc[0], TEX_VLC_BITS, 2, 0); + UPDATE_CACHE(re, &h->gb); + GET_RL_VLC(level, run, re, &h->gb, rl->rl_vlc[0], TEX_VLC_BITS, 2, 0); if (run == 66) { if (level){ - CLOSE_READER(re, &s->gb); - av_log(s->avctx, AV_LOG_ERROR, "illegal ac vlc code at %dx%d\n", s->mb_x, s->mb_y); + CLOSE_READER(re, &h->gb); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal ac vlc code at %dx%d\n", + h->c.mb_x, h->c.mb_y); return -1; } /* escape */ - if (CONFIG_FLV_DECODER && s->h263_flv > 1) { - int is11 = SHOW_UBITS(re, &s->gb, 1); - SKIP_CACHE(re, &s->gb, 1); - run = SHOW_UBITS(re, &s->gb, 7) + 1; + if (CONFIG_FLV_DECODER && h->flv) { + int is11 = SHOW_UBITS(re, &h->gb, 1); + SKIP_CACHE(re, &h->gb, 1); + run = SHOW_UBITS(re, &h->gb, 7) + 1; if (is11) { - SKIP_COUNTER(re, &s->gb, 1 + 7); - UPDATE_CACHE(re, &s->gb); - level = SHOW_SBITS(re, &s->gb, 11); - SKIP_COUNTER(re, &s->gb, 11); + SKIP_COUNTER(re, &h->gb, 1 + 7); + UPDATE_CACHE(re, &h->gb); + level = SHOW_SBITS(re, &h->gb, 11); + SKIP_COUNTER(re, &h->gb, 11); } else { - SKIP_CACHE(re, &s->gb, 7); - level = SHOW_SBITS(re, &s->gb, 7); - SKIP_COUNTER(re, &s->gb, 1 + 7 + 7); + SKIP_CACHE(re, &h->gb, 7); + level = SHOW_SBITS(re, &h->gb, 7); + SKIP_COUNTER(re, &h->gb, 1 + 7 + 7); } } else { - run = SHOW_UBITS(re, &s->gb, 7) + 1; - SKIP_CACHE(re, &s->gb, 7); - level = (int8_t)SHOW_UBITS(re, &s->gb, 8); - SKIP_COUNTER(re, &s->gb, 7 + 8); + run = SHOW_UBITS(re, &h->gb, 7) + 1; + SKIP_CACHE(re, &h->gb, 7); + level = (int8_t)SHOW_UBITS(re, &h->gb, 8); + SKIP_COUNTER(re, &h->gb, 7 + 8); if(level == -128){ - UPDATE_CACHE(re, &s->gb); - if (s->codec_id == AV_CODEC_ID_RV10) { + UPDATE_CACHE(re, &h->gb); + if (h->c.codec_id == AV_CODEC_ID_RV10) { /* XXX: should patch encoder too */ - level = SHOW_SBITS(re, &s->gb, 12); - SKIP_COUNTER(re, &s->gb, 12); + level = SHOW_SBITS(re, &h->gb, 12); + SKIP_COUNTER(re, &h->gb, 12); }else{ - level = SHOW_UBITS(re, &s->gb, 5); - SKIP_CACHE(re, &s->gb, 5); - level |= SHOW_SBITS(re, &s->gb, 6) * (1<<5); - SKIP_COUNTER(re, &s->gb, 5 + 6); + level = SHOW_UBITS(re, &h->gb, 5); + SKIP_CACHE(re, &h->gb, 5); + level |= SHOW_SBITS(re, &h->gb, 6) * (1<<5); + SKIP_COUNTER(re, &h->gb, 5 + 6); } } } } else { - if (SHOW_UBITS(re, &s->gb, 1)) + if (SHOW_UBITS(re, &h->gb, 1)) level = -level; - SKIP_COUNTER(re, &s->gb, 1); + SKIP_COUNTER(re, &h->gb, 1); } i += run; if (i >= 64){ - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); // redo update without last flag, revert -1 offset i = i - run + ((run-1)&63) + 1; if (i < 64) { @@ -654,49 +650,49 @@ retry: block[scan_table[i]] = level; break; } - if(s->alt_inter_vlc && rl == &ff_h263_rl_inter && !s->mb_intra){ + if(h->alt_inter_vlc && rl == &ff_h263_rl_inter && !h->c.mb_intra){ //Looks like a hack but no, it's the way it is supposed to work ... rl = &ff_rl_intra_aic; i = 0; - s->gb= gb; - s->bdsp.clear_block(block); + h->gb = gb; + h->c.bdsp.clear_block(block); goto retry; } - av_log(s->avctx, AV_LOG_ERROR, "run overflow at %dx%d i:%d\n", s->mb_x, s->mb_y, s->mb_intra); + av_log(h->c.avctx, AV_LOG_ERROR, "run overflow at %dx%d i:%d\n", + h->c.mb_x, h->c.mb_y, h->c.mb_intra); return -1; } j = scan_table[i]; block[j] = level; } } + if (h->c.mb_intra && h->c.h263_aic) { not_coded: - if (s->mb_intra && s->h263_aic) { - h263_pred_acdc(s, block, n); - i = 63; + h263_pred_acdc(&h->c, block, n); } - s->block_last_index[n] = i; + h->c.block_last_index[n] = i; return 0; } -static int h263_skip_b_part(MpegEncContext *s, int cbp) +static int h263_skip_b_part(H263DecContext *const h, int cbp) { LOCAL_ALIGNED_32(int16_t, dblock, [64]); int i, mbi; int bli[6]; - /* we have to set s->mb_intra to zero to decode B-part of PB-frame correctly + /* we have to set h->c.mb_intra to zero to decode B-part of PB-frame correctly * but real value should be restored in order to be used later (in OBMC condition) */ - mbi = s->mb_intra; - memcpy(bli, s->block_last_index, sizeof(bli)); - s->mb_intra = 0; + mbi = h->c.mb_intra; + memcpy(bli, h->c.block_last_index, sizeof(bli)); + h->c.mb_intra = 0; for (i = 0; i < 6; i++) { - if (h263_decode_block(s, dblock, i, cbp&32) < 0) + if (h263_decode_block(h, dblock, i, cbp&32) < 0) return -1; cbp+=cbp; } - s->mb_intra = mbi; - memcpy(s->block_last_index, bli, sizeof(bli)); + h->c.mb_intra = mbi; + memcpy(h->c.block_last_index, bli, sizeof(bli)); return 0; } @@ -785,119 +781,121 @@ static int set_direct_mv(MpegEncContext *s) } } -int ff_h263_decode_mb(MpegEncContext *s, - int16_t block[6][64]) +int ff_h263_decode_mb(H263DecContext *const h) { int cbpc, cbpy, i, cbp, pred_x, pred_y, mx, my, dquant; int16_t *mot_val; - const int xy= s->mb_x + s->mb_y * s->mb_stride; + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; int cbpb = 0, pb_mv_count = 0; - av_assert2(!s->h263_pred); + av_assert2(!h->c.h263_pred); - if (s->pict_type == AV_PICTURE_TYPE_P) { + if (h->c.pict_type == AV_PICTURE_TYPE_P) { do{ - if (get_bits1(&s->gb)) { + if (get_bits1(&h->gb)) { /* skip mb */ - s->mb_intra = 0; + h->c.mb_intra = 0; for(i=0;i<6;i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; - s->mb_skipped = !(s->obmc | s->loop_filter); + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + h->c.mv[0][0][0] = 0; + h->c.mv[0][0][1] = 0; + h->c.mb_skipped = !(h->c.obmc | h->loop_filter); goto end; } - cbpc = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); if (cbpc < 0){ - av_log(s->avctx, AV_LOG_ERROR, "cbpc damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpc damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } }while(cbpc == 20); - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); dquant = cbpc & 8; - s->mb_intra = ((cbpc & 4) != 0); - if (s->mb_intra) goto intra; + h->c.mb_intra = ((cbpc & 4) != 0); + if (h->c.mb_intra) + goto intra; - if(s->pb_frame && get_bits1(&s->gb)) - pb_mv_count = h263_get_modb(&s->gb, s->pb_frame, &cbpb); - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + if (h->pb_frame && get_bits1(&h->gb)) + pb_mv_count = h263_get_modb(&h->gb, h->pb_frame, &cbpb); + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, "cbpy damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpy damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } - if(s->alt_inter_vlc==0 || (cbpc & 3)!=3) + if (!h->alt_inter_vlc|| (cbpc & 3)!=3) cbpy ^= 0xF; cbp = (cbpc & 3) | (cbpy << 2); if (dquant) { - h263_decode_dquant(s); + h263_decode_dquant(h); } - s->mv_dir = MV_DIR_FORWARD; + h->c.mv_dir = MV_DIR_FORWARD; if ((cbpc & 16) == 0) { - s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; /* 16x16 motion prediction */ - s->mv_type = MV_TYPE_16X16; - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + h->c.mv_type = MV_TYPE_16X16; + ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); if (mx >= 0xffff) return SLICE_ERROR; - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); + my = ff_h263_decode_motion(h, pred_y, 1); if (my >= 0xffff) return SLICE_ERROR; - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; - if (s->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) - skip_bits1(&s->gb); /* Bit stuffing to prevent PSC */ + if (h->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) + skip_bits1(&h->gb); /* Bit stuffing to prevent PSC */ } else { - s->cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; - s->mv_type = MV_TYPE_8X8; + h->c.cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; + h->c.mv_type = MV_TYPE_8X8; for(i=0;i<4;i++) { - mot_val = ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + mot_val = ff_h263_pred_motion(&h->c, i, 0, &pred_x, &pred_y); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); if (mx >= 0xffff) return SLICE_ERROR; - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); + my = ff_h263_decode_motion(h, pred_y, 1); if (my >= 0xffff) return SLICE_ERROR; - s->mv[0][i][0] = mx; - s->mv[0][i][1] = my; - if (s->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) - skip_bits1(&s->gb); /* Bit stuffing to prevent PSC */ + h->c.mv[0][i][0] = mx; + h->c.mv[0][i][1] = my; + if (h->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) + skip_bits1(&h->gb); /* Bit stuffing to prevent PSC */ mot_val[0] = mx; mot_val[1] = my; } } - } else if(s->pict_type==AV_PICTURE_TYPE_B) { + } else if (h->c.pict_type==AV_PICTURE_TYPE_B) { int mb_type; - const int stride= s->b8_stride; - int16_t *mot_val0 = s->cur_pic.motion_val[0][2 * (s->mb_x + s->mb_y * stride)]; - int16_t *mot_val1 = s->cur_pic.motion_val[1][2 * (s->mb_x + s->mb_y * stride)]; -// const int mv_xy= s->mb_x + 1 + s->mb_y * s->mb_stride; + const int stride = h->c.b8_stride; + int16_t *mot_val0 = h->c.cur_pic.motion_val[0][2 * (h->c.mb_x + h->c.mb_y * stride)]; + int16_t *mot_val1 = h->c.cur_pic.motion_val[1][2 * (h->c.mb_x + h->c.mb_y * stride)]; +// const int mv_xy = h->c.mb_x + 1 + h->c.mb_y * h->c.mb_stride; //FIXME ugly mot_val0[0 ]= mot_val0[2 ]= mot_val0[0+2*stride]= mot_val0[2+2*stride]= @@ -906,176 +904,181 @@ int ff_h263_decode_mb(MpegEncContext *s, mot_val1[1 ]= mot_val1[3 ]= mot_val1[1+2*stride]= mot_val1[3+2*stride]= 0; do{ - mb_type = get_vlc2(&s->gb, h263_mbtype_b_vlc, + mb_type = get_vlc2(&h->gb, h263_mbtype_b_vlc, H263_MBTYPE_B_VLC_BITS, 2); if (mb_type < 0){ - av_log(s->avctx, AV_LOG_ERROR, "b mb_type damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "b mb_type damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } }while(!mb_type); - s->mb_intra = IS_INTRA(mb_type); + h->c.mb_intra = IS_INTRA(mb_type); if(HAS_CBP(mb_type)){ - s->bdsp.clear_blocks(s->block[0]); - cbpc = get_vlc2(&s->gb, cbpc_b_vlc, CBPC_B_VLC_BITS, 1); - if(s->mb_intra){ + h->c.bdsp.clear_blocks(h->block[0]); + cbpc = get_vlc2(&h->gb, cbpc_b_vlc, CBPC_B_VLC_BITS, 1); + if (h->c.mb_intra) { dquant = IS_QUANT(mb_type); goto intra; } - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0){ - av_log(s->avctx, AV_LOG_ERROR, "b cbpy damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "b cbpy damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } - if(s->alt_inter_vlc==0 || (cbpc & 3)!=3) + if (!h->alt_inter_vlc || (cbpc & 3)!=3) cbpy ^= 0xF; cbp = (cbpc & 3) | (cbpy << 2); }else cbp=0; - av_assert2(!s->mb_intra); + av_assert2(!h->c.mb_intra); if(IS_QUANT(mb_type)){ - h263_decode_dquant(s); + h263_decode_dquant(h); } if(IS_DIRECT(mb_type)){ - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; - mb_type |= set_direct_mv(s); + h->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; + mb_type |= set_direct_mv(&h->c); }else{ - s->mv_dir = 0; - s->mv_type= MV_TYPE_16X16; + h->c.mv_dir = 0; + h->c.mv_type = MV_TYPE_16X16; //FIXME UMV if (HAS_FORWARD_MV(mb_type)) { - int16_t *mot_val= ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - s->mv_dir = MV_DIR_FORWARD; + int16_t *mot_val = ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); + h->c.mv_dir = MV_DIR_FORWARD; - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); if (mx >= 0xffff) return SLICE_ERROR; - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); + my = ff_h263_decode_motion(h, pred_y, 1); if (my >= 0xffff) return SLICE_ERROR; - if (s->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) - skip_bits1(&s->gb); /* Bit stuffing to prevent PSC */ + if (h->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) + skip_bits1(&h->gb); /* Bit stuffing to prevent PSC */ - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; mot_val[0 ]= mot_val[2 ]= mot_val[0+2*stride]= mot_val[2+2*stride]= mx; mot_val[1 ]= mot_val[3 ]= mot_val[1+2*stride]= mot_val[3+2*stride]= my; } if (HAS_BACKWARD_MV(mb_type)) { - int16_t *mot_val= ff_h263_pred_motion(s, 0, 1, &pred_x, &pred_y); - s->mv_dir |= MV_DIR_BACKWARD; + int16_t *mot_val = ff_h263_pred_motion(&h->c, 0, 1, &pred_x, &pred_y); + h->c.mv_dir |= MV_DIR_BACKWARD; - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); if (mx >= 0xffff) return SLICE_ERROR; - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); + my = ff_h263_decode_motion(h, pred_y, 1); if (my >= 0xffff) return SLICE_ERROR; - if (s->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) - skip_bits1(&s->gb); /* Bit stuffing to prevent PSC */ + if (h->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) + skip_bits1(&h->gb); /* Bit stuffing to prevent PSC */ - s->mv[1][0][0] = mx; - s->mv[1][0][1] = my; + h->c.mv[1][0][0] = mx; + h->c.mv[1][0][1] = my; mot_val[0 ]= mot_val[2 ]= mot_val[0+2*stride]= mot_val[2+2*stride]= mx; mot_val[1 ]= mot_val[3 ]= mot_val[1+2*stride]= mot_val[3+2*stride]= my; } } - s->cur_pic.mb_type[xy] = mb_type; + h->c.cur_pic.mb_type[xy] = mb_type; } else { /* I-Frame */ do{ - cbpc = get_vlc2(&s->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); if (cbpc < 0){ - av_log(s->avctx, AV_LOG_ERROR, "I cbpc damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "I cbpc damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } }while(cbpc == 8); - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); dquant = cbpc & 4; - s->mb_intra = 1; + h->c.mb_intra = 1; intra: - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; - if (s->h263_aic) { - s->ac_pred = get_bits1(&s->gb); - if(s->ac_pred){ - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA; + if (h->c.h263_aic) { + h->c.ac_pred = get_bits1(&h->gb); + if (h->c.ac_pred) { + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; - s->h263_aic_dir = get_bits1(&s->gb); + h->c.h263_aic_dir = get_bits1(&h->gb); } }else - s->ac_pred = 0; + h->c.ac_pred = 0; - if(s->pb_frame && get_bits1(&s->gb)) - pb_mv_count = h263_get_modb(&s->gb, s->pb_frame, &cbpb); - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + if (h->pb_frame && get_bits1(&h->gb)) + pb_mv_count = h263_get_modb(&h->gb, h->pb_frame, &cbpb); + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if(cbpy<0){ - av_log(s->avctx, AV_LOG_ERROR, "I cbpy damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "I cbpy damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } cbp = (cbpc & 3) | (cbpy << 2); if (dquant) { - h263_decode_dquant(s); + h263_decode_dquant(h); } - pb_mv_count += !!s->pb_frame; + pb_mv_count += !!h->pb_frame; } while(pb_mv_count--){ - ff_h263_decode_motion(s, 0, 1); - ff_h263_decode_motion(s, 0, 1); + ff_h263_decode_motion(h, 0, 1); + ff_h263_decode_motion(h, 0, 1); } /* decode each block */ for (i = 0; i < 6; i++) { - if (h263_decode_block(s, block[i], i, cbp&32) < 0) + if (h263_decode_block(h, h->block[i], i, cbp&32) < 0) return -1; cbp+=cbp; } - if(s->pb_frame && h263_skip_b_part(s, cbpb) < 0) + if (h->pb_frame && h263_skip_b_part(h, cbpb) < 0) return -1; - if(s->obmc && !s->mb_intra){ - if(s->pict_type == AV_PICTURE_TYPE_P && s->mb_x+1mb_width && s->mb_num_left != 1) - preview_obmc(s); + if (h->c.obmc && !h->c.mb_intra) { + if (h->c.pict_type == AV_PICTURE_TYPE_P && + h->c.mb_x + 1 < h->c.mb_width && h->mb_num_left != 1) + preview_obmc(h); } end: - if (get_bits_left(&s->gb) < 0) + if (get_bits_left(&h->gb) < 0) return AVERROR_INVALIDDATA; /* per-MB end of slice check */ { - int v= show_bits(&s->gb, 16); + int v = show_bits(&h->gb, 16); - if (get_bits_left(&s->gb) < 16) { - v >>= 16 - get_bits_left(&s->gb); + if (get_bits_left(&h->gb) < 16) { + v >>= 16 - get_bits_left(&h->gb); } if(v==0) @@ -1086,50 +1089,50 @@ end: } /* Most is hardcoded; should extend to handle all H.263 streams. */ -int ff_h263_decode_picture_header(MpegEncContext *s) +int ff_h263_decode_picture_header(H263DecContext *const h) { - int format, width, height, i, ret; - uint32_t startcode; + int width, height, i, ret; + int h263_plus; - align_get_bits(&s->gb); + align_get_bits(&h->gb); - if (show_bits(&s->gb, 2) == 2 && s->avctx->frame_num == 0) { - av_log(s->avctx, AV_LOG_WARNING, "Header looks like RTP instead of H.263\n"); + if (show_bits(&h->gb, 2) == 2 && h->c.avctx->frame_num == 0) { + av_log(h->c.avctx, AV_LOG_WARNING, "Header looks like RTP instead of H.263\n"); } - startcode= get_bits(&s->gb, 22-8); + uint32_t startcode = get_bits(&h->gb, 22-8); - for(i= get_bits_left(&s->gb); i>24; i-=8) { - startcode = ((startcode << 8) | get_bits(&s->gb, 8)) & 0x003FFFFF; + for (i = get_bits_left(&h->gb); i>24; i -= 8) { + startcode = ((startcode << 8) | get_bits(&h->gb, 8)) & 0x003FFFFF; if(startcode == 0x20) break; } if (startcode != 0x20) { - av_log(s->avctx, AV_LOG_ERROR, "Bad picture start code\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Bad picture start code\n"); return -1; } /* temporal reference */ - i = get_bits(&s->gb, 8); /* picture timestamp */ + i = get_bits(&h->gb, 8); /* picture timestamp */ - i -= (i - (s->picture_number & 0xFF) + 128) & ~0xFF; + i -= (i - (h->picture_number & 0xFF) + 128) & ~0xFF; - s->picture_number= (s->picture_number&~0xFF) + i; + h->picture_number = (h->picture_number&~0xFF) + i; /* PTYPE starts here */ - if (check_marker(s->avctx, &s->gb, "in PTYPE") != 1) { + if (check_marker(h->c.avctx, &h->gb, "in PTYPE") != 1) { return -1; } - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Bad H.263 id\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Bad H.263 id\n"); return -1; /* H.263 id */ } - skip_bits1(&s->gb); /* split screen off */ - skip_bits1(&s->gb); /* camera off */ - skip_bits1(&s->gb); /* freeze picture release off */ + skip_bits1(&h->gb); /* split screen off */ + skip_bits1(&h->gb); /* camera off */ + skip_bits1(&h->gb); /* freeze picture release off */ - format = get_bits(&s->gb, 3); + int format = get_bits(&h->gb, 3); /* 0 forbidden 1 sub-QCIF @@ -1138,95 +1141,95 @@ int ff_h263_decode_picture_header(MpegEncContext *s) */ if (format != 7 && format != 6) { - s->h263_plus = 0; + h263_plus = 0; /* H.263v1 */ width = ff_h263_format[format][0]; height = ff_h263_format[format][1]; if (!width) return -1; - s->pict_type = AV_PICTURE_TYPE_I + get_bits1(&s->gb); + h->c.pict_type = AV_PICTURE_TYPE_I + get_bits1(&h->gb); - s->h263_long_vectors = get_bits1(&s->gb); + h->h263_long_vectors = get_bits1(&h->gb); - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "H.263 SAC not supported\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "H.263 SAC not supported\n"); return -1; /* SAC: off */ } - s->obmc= get_bits1(&s->gb); /* Advanced prediction mode */ + h->c.obmc = get_bits1(&h->gb); /* Advanced prediction mode */ - s->pb_frame = get_bits1(&s->gb); - s->chroma_qscale= s->qscale = get_bits(&s->gb, 5); - skip_bits1(&s->gb); /* Continuous Presence Multipoint mode: off */ + h->pb_frame = get_bits1(&h->gb); + h->c.chroma_qscale = h->c.qscale = get_bits(&h->gb, 5); + skip_bits1(&h->gb); /* Continuous Presence Multipoint mode: off */ - s->width = width; - s->height = height; - s->avctx->sample_aspect_ratio= (AVRational){12,11}; - s->avctx->framerate = (AVRational){ 30000, 1001 }; + h->c.width = width; + h->c.height = height; + h->c.avctx->sample_aspect_ratio= (AVRational){12,11}; + h->c.avctx->framerate = (AVRational){ 30000, 1001 }; } else { int ufep; /* H.263v2 */ - s->h263_plus = 1; - ufep = get_bits(&s->gb, 3); /* Update Full Extended PTYPE */ + h263_plus = 1; + ufep = get_bits(&h->gb, 3); /* Update Full Extended PTYPE */ /* ufep other than 0 and 1 are reserved */ if (ufep == 1) { /* OPPTYPE */ - format = get_bits(&s->gb, 3); - ff_dlog(s->avctx, "ufep=1, format: %d\n", format); - s->custom_pcf= get_bits1(&s->gb); - s->umvplus = get_bits1(&s->gb); /* Unrestricted Motion Vector */ - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Syntax-based Arithmetic Coding (SAC) not supported\n"); + format = get_bits(&h->gb, 3); + ff_dlog(h->c.avctx, "ufep=1, format: %d\n", format); + h->custom_pcf = get_bits1(&h->gb); + h->umvplus = get_bits1(&h->gb); /* Unrestricted Motion Vector */ + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Syntax-based Arithmetic Coding (SAC) not supported\n"); } - s->obmc= get_bits1(&s->gb); /* Advanced prediction mode */ - s->h263_aic = get_bits1(&s->gb); /* Advanced Intra Coding (AIC) */ - s->loop_filter= get_bits1(&s->gb); - if(s->avctx->lowres) - s->loop_filter = 0; + h->c.obmc = get_bits1(&h->gb); /* Advanced prediction mode */ + h->c.h263_aic = get_bits1(&h->gb); /* Advanced Intra Coding (AIC) */ + h->loop_filter = get_bits1(&h->gb); + if (h->c.avctx->lowres) + h->loop_filter = 0; - s->h263_slice_structured= get_bits1(&s->gb); - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Reference Picture Selection not supported\n"); + h->h263_slice_structured = get_bits1(&h->gb); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Reference Picture Selection not supported\n"); } - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Independent Segment Decoding not supported\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Independent Segment Decoding not supported\n"); } - s->alt_inter_vlc= get_bits1(&s->gb); - s->modified_quant= get_bits1(&s->gb); - if(s->modified_quant) - s->chroma_qscale_table= ff_h263_chroma_qscale_table; + h->alt_inter_vlc = get_bits1(&h->gb); + h->modified_quant = get_bits1(&h->gb); + if (h->modified_quant) + h->c.chroma_qscale_table= ff_h263_chroma_qscale_table; - skip_bits(&s->gb, 1); /* Prevent start code emulation */ + skip_bits(&h->gb, 1); /* Prevent start code emulation */ - skip_bits(&s->gb, 3); /* Reserved */ + skip_bits(&h->gb, 3); /* Reserved */ } else if (ufep != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Bad UFEP type (%d)\n", ufep); + av_log(h->c.avctx, AV_LOG_ERROR, "Bad UFEP type (%d)\n", ufep); return -1; } /* MPPTYPE */ - s->pict_type = get_bits(&s->gb, 3); - switch(s->pict_type){ - case 0: s->pict_type= AV_PICTURE_TYPE_I;break; - case 1: s->pict_type= AV_PICTURE_TYPE_P;break; - case 2: s->pict_type= AV_PICTURE_TYPE_P;s->pb_frame = 3;break; - case 3: s->pict_type= AV_PICTURE_TYPE_B;break; - case 7: s->pict_type= AV_PICTURE_TYPE_I;break; //ZYGO + h->c.pict_type = get_bits(&h->gb, 3); + switch (h->c.pict_type) { + case 0: h->c.pict_type = AV_PICTURE_TYPE_I; break; + case 1: h->c.pict_type = AV_PICTURE_TYPE_P; break; + case 2: h->c.pict_type = AV_PICTURE_TYPE_P; h->pb_frame = 3; break; + case 3: h->c.pict_type = AV_PICTURE_TYPE_B; break; + case 7: h->c.pict_type = AV_PICTURE_TYPE_I; break; //ZYGO default: return -1; } - skip_bits(&s->gb, 2); - s->no_rounding = get_bits1(&s->gb); - skip_bits(&s->gb, 4); + skip_bits(&h->gb, 2); + h->c.no_rounding = get_bits1(&h->gb); + skip_bits(&h->gb, 4); /* Get the picture dimensions */ if (ufep) { if (format == 6) { /* Custom Picture Format (CPFMT) */ - int aspect_ratio_info = get_bits(&s->gb, 4); - ff_dlog(s->avctx, "aspect: %d\n", aspect_ratio_info); + int aspect_ratio_info = get_bits(&h->gb, 4); + ff_dlog(h->c.avctx, "aspect: %d\n", aspect_ratio_info); /* aspect ratios: 0 - forbidden 1 - 1:1 @@ -1236,150 +1239,151 @@ int ff_h263_decode_picture_header(MpegEncContext *s) 5 - 40:33 (525-type 16:9) 6-14 - reserved */ - width = (get_bits(&s->gb, 9) + 1) * 4; - check_marker(s->avctx, &s->gb, "in dimensions"); - height = get_bits(&s->gb, 9) * 4; - ff_dlog(s->avctx, "\nH.263+ Custom picture: %dx%d\n",width,height); + width = (get_bits(&h->gb, 9) + 1) * 4; + check_marker(h->c.avctx, &h->gb, "in dimensions"); + height = get_bits(&h->gb, 9) * 4; + ff_dlog(h->c.avctx, "\nH.263+ Custom picture: %dx%d\n",width,height); if (aspect_ratio_info == FF_ASPECT_EXTENDED) { /* expected dimensions */ - s->avctx->sample_aspect_ratio.num= get_bits(&s->gb, 8); - s->avctx->sample_aspect_ratio.den= get_bits(&s->gb, 8); + h->c.avctx->sample_aspect_ratio.num = get_bits(&h->gb, 8); + h->c.avctx->sample_aspect_ratio.den = get_bits(&h->gb, 8); }else{ - s->avctx->sample_aspect_ratio= ff_h263_pixel_aspect[aspect_ratio_info]; + h->c.avctx->sample_aspect_ratio= ff_h263_pixel_aspect[aspect_ratio_info]; } } else { width = ff_h263_format[format][0]; height = ff_h263_format[format][1]; - s->avctx->sample_aspect_ratio= (AVRational){12,11}; + h->c.avctx->sample_aspect_ratio = (AVRational){12,11}; } - s->avctx->sample_aspect_ratio.den <<= s->ehc_mode; + h->c.avctx->sample_aspect_ratio.den <<= h->ehc_mode; if ((width == 0) || (height == 0)) return -1; - s->width = width; - s->height = height; + h->c.width = width; + h->c.height = height; - if(s->custom_pcf){ - int gcd; - s->avctx->framerate.num = 1800000; - s->avctx->framerate.den = 1000 + get_bits1(&s->gb); - s->avctx->framerate.den *= get_bits(&s->gb, 7); - if(s->avctx->framerate.den == 0){ - av_log(s, AV_LOG_ERROR, "zero framerate\n"); + if (h->custom_pcf) { + h->c.avctx->framerate.num = 1800000; + h->c.avctx->framerate.den = 1000 + get_bits1(&h->gb); + h->c.avctx->framerate.den *= get_bits(&h->gb, 7); + if (h->c.avctx->framerate.den == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "zero framerate\n"); return -1; } - gcd= av_gcd(s->avctx->framerate.den, s->avctx->framerate.num); - s->avctx->framerate.den /= gcd; - s->avctx->framerate.num /= gcd; + int gcd = av_gcd(h->c.avctx->framerate.den, h->c.avctx->framerate.num); + h->c.avctx->framerate.den /= gcd; + h->c.avctx->framerate.num /= gcd; }else{ - s->avctx->framerate = (AVRational){ 30000, 1001 }; + h->c.avctx->framerate = (AVRational){ 30000, 1001 }; } } - if(s->custom_pcf){ - skip_bits(&s->gb, 2); //extended Temporal reference - } + if (h->custom_pcf) + skip_bits(&h->gb, 2); //extended Temporal reference if (ufep) { - if (s->umvplus) { - if(get_bits1(&s->gb)==0) /* Unlimited Unrestricted Motion Vectors Indicator (UUI) */ - skip_bits1(&s->gb); + if (h->umvplus) { + if (get_bits1(&h->gb)==0) /* Unlimited Unrestricted Motion Vectors Indicator (UUI) */ + skip_bits1(&h->gb); } - if(s->h263_slice_structured){ - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "rectangular slices not supported\n"); + if (h->h263_slice_structured) { + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "rectangular slices not supported\n"); } - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "unordered slices not supported\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "unordered slices not supported\n"); } } - if (s->pict_type == AV_PICTURE_TYPE_B) { - skip_bits(&s->gb, 4); //ELNUM + if (h->c.pict_type == AV_PICTURE_TYPE_B) { + skip_bits(&h->gb, 4); //ELNUM if (ufep == 1) { - skip_bits(&s->gb, 4); // RLNUM + skip_bits(&h->gb, 4); // RLNUM } } } - s->qscale = get_bits(&s->gb, 5); + h->c.qscale = get_bits(&h->gb, 5); } - if ((ret = av_image_check_size(s->width, s->height, 0, s)) < 0) + ret = av_image_check_size(h->c.width, h->c.height, 0, h->c.avctx); + if (ret < 0) return ret; - if (!(s->avctx->flags2 & AV_CODEC_FLAG2_CHUNKS)) { - if ((s->width * s->height / 256 / 8) > get_bits_left(&s->gb)) + if (!(h->c.avctx->flags2 & AV_CODEC_FLAG2_CHUNKS)) { + if ((h->c.width * h->c.height / 256 / 8) > get_bits_left(&h->gb)) return AVERROR_INVALIDDATA; } - s->mb_width = (s->width + 15) / 16; - s->mb_height = (s->height + 15) / 16; - s->mb_num = s->mb_width * s->mb_height; + h->c.mb_width = (h->c.width + 15U) / 16; + h->c.mb_height = (h->c.height + 15U) / 16; + h->c.mb_num = h->c.mb_width * h->c.mb_height; - if (s->pb_frame) { - skip_bits(&s->gb, 3); /* Temporal reference for B-pictures */ - if (s->custom_pcf) - skip_bits(&s->gb, 2); //extended Temporal reference - skip_bits(&s->gb, 2); /* Quantization information for B-pictures */ + h->gob_index = H263_GOB_HEIGHT(h->c.height); + + if (h->pb_frame) { + skip_bits(&h->gb, 3); /* Temporal reference for B-pictures */ + if (h->custom_pcf) + skip_bits(&h->gb, 2); //extended Temporal reference + skip_bits(&h->gb, 2); /* Quantization information for B-pictures */ } - if (s->pict_type!=AV_PICTURE_TYPE_B) { - s->time = s->picture_number; - s->pp_time = s->time - s->last_non_b_time; - s->last_non_b_time = s->time; + if (h->c.pict_type!=AV_PICTURE_TYPE_B) { + h->c.time = h->picture_number; + h->c.pp_time = h->c.time - h->c.last_non_b_time; + h->c.last_non_b_time = h->c.time; }else{ - s->time = s->picture_number; - s->pb_time = s->pp_time - (s->last_non_b_time - s->time); - if (s->pp_time <=s->pb_time || - s->pp_time <= s->pp_time - s->pb_time || - s->pp_time <= 0){ - s->pp_time = 2; - s->pb_time = 1; + h->c.time = h->picture_number; + h->c.pb_time = h->c.pp_time - (h->c.last_non_b_time - h->c.time); + if (h->c.pp_time <= h->c.pb_time || + h->c.pp_time <= h->c.pp_time - h->c.pb_time || + h->c.pp_time <= 0) { + h->c.pp_time = 2; + h->c.pb_time = 1; } - ff_mpeg4_init_direct_mv(s); + ff_mpeg4_init_direct_mv(&h->c); } /* PEI */ - if (skip_1stop_8data_bits(&s->gb) < 0) + if (skip_1stop_8data_bits(&h->gb) < 0) return AVERROR_INVALIDDATA; - if(s->h263_slice_structured){ - if (check_marker(s->avctx, &s->gb, "SEPB1") != 1) { + if (h->h263_slice_structured) { + if (check_marker(h->c.avctx, &h->gb, "SEPB1") != 1) { return -1; } - ff_h263_decode_mba(s); + ff_h263_decode_mba(h); - if (check_marker(s->avctx, &s->gb, "SEPB2") != 1) { + if (check_marker(h->c.avctx, &h->gb, "SEPB2") != 1) { return -1; } } - s->f_code = 1; - if (s->pict_type == AV_PICTURE_TYPE_B) - s->low_delay = 0; + if (h->c.pict_type == AV_PICTURE_TYPE_B) + h->c.low_delay = 0; - if(s->h263_aic){ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_aic_dc_scale_table; + if (h->c.h263_aic) { + h->c.y_dc_scale_table = + h->c.c_dc_scale_table = ff_aic_dc_scale_table; }else{ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_mpeg1_dc_scale_table; + h->c.y_dc_scale_table = + h->c.c_dc_scale_table = ff_mpeg1_dc_scale_table; } - ff_h263_show_pict_info(s); - if (s->pict_type == AV_PICTURE_TYPE_I && s->codec_tag == AV_RL32("ZYGO") && get_bits_left(&s->gb) >= 85 + 13*3*16 + 50){ + ff_h263_show_pict_info(h, h263_plus); + + if (h->c.pict_type == AV_PICTURE_TYPE_I && h->c.codec_tag == AV_RL32("ZYGO") && get_bits_left(&h->gb) >= 85 + 13*3*16 + 50){ int i,j; - for(i=0; i<85; i++) av_log(s->avctx, AV_LOG_DEBUG, "%d", get_bits1(&s->gb)); - av_log(s->avctx, AV_LOG_DEBUG, "\n"); + for(i=0; i<85; i++) av_log(h->c.avctx, AV_LOG_DEBUG, "%d", get_bits1(&h->gb)); + av_log(h->c.avctx, AV_LOG_DEBUG, "\n"); for(i=0; i<13; i++){ for(j=0; j<3; j++){ - int v= get_bits(&s->gb, 8); - v |= get_sbits(&s->gb, 8) * (1 << 8); - av_log(s->avctx, AV_LOG_DEBUG, " %5d", v); + int v= get_bits(&h->gb, 8); + v |= get_sbits(&h->gb, 8) * (1 << 8); + av_log(h->c.avctx, AV_LOG_DEBUG, " %5d", v); } - av_log(s->avctx, AV_LOG_DEBUG, "\n"); + av_log(h->c.avctx, AV_LOG_DEBUG, "\n"); } - for(i=0; i<50; i++) av_log(s->avctx, AV_LOG_DEBUG, "%d", get_bits1(&s->gb)); + for(i=0; i<50; i++) av_log(h->c.avctx, AV_LOG_DEBUG, "%d", get_bits1(&h->gb)); } return 0; diff --git a/libavcodec/ituh263enc.c b/libavcodec/ituh263enc.c index 8c41e45ab..56259783b 100644 --- a/libavcodec/ituh263enc.c +++ b/libavcodec/ituh263enc.c @@ -30,14 +30,15 @@ #include "config_components.h" #include +#include #include "libavutil/attributes.h" #include "libavutil/thread.h" #include "avcodec.h" #include "codec_internal.h" #include "mpegvideo.h" -#include "mpegvideodata.h" #include "flvenc.h" +#include "mpegvideodata.h" #include "mpegvideoenc.h" #include "h263.h" #include "h263enc.h" @@ -46,17 +47,43 @@ #include "mathops.h" #include "mpegutils.h" #include "internal.h" +#include "put_bits.h" /** * Table of number of bits a motion vector component needs. */ static uint8_t mv_penalty[MAX_FCODE+1][MAX_DMV*2+1]; -/** - * Minimal fcode that a motion vector component would need. - */ -static uint8_t fcode_tab[MAX_MV*2+1]; +static av_cold void init_mv_penalty(void) +{ + for (int f_code = 1; f_code <= MAX_FCODE; f_code++) { + for (int mv = -MAX_DMV; mv <= MAX_DMV; mv++) { + int len; + if (mv == 0) len = 1; // ff_mvtab[0][1] + else { + int val, bit_size, code; + + bit_size = f_code - 1; + + val = mv; + if (val < 0) + val = -val; + val--; + code = (val >> bit_size) + 1; + if (code < 33) { + len = ff_mvtab[code][1] + 1 + bit_size; + } else { + len = 12 /* ff_mvtab[32][1] */ + av_log2(code>>5) + 2 + bit_size; + } + } + + mv_penalty[f_code][mv + MAX_DMV] = len; + } + } +} + +#if CONFIG_H263_ENCODER /** * Minimal fcode that a motion vector component would need in umv. * All entries in this table are 1. @@ -71,6 +98,89 @@ static uint8_t uni_h263_inter_rl_len [64*64*2*2]; //#define UNI_MPEG4_ENC_INDEX(last,run,level) ((last)*128*64 + (run) + (level)*64) #define UNI_MPEG4_ENC_INDEX(last,run,level) ((last)*128*64 + (run)*128 + (level)) +static av_cold void init_uni_h263_rl_tab(const RLTable *rl, uint8_t *len_tab) +{ + const uint16_t (*table_vlc)[2] = rl->table_vlc; + const uint8_t *table_run = rl->table_run; + const uint8_t *table_level = rl->table_level; + + av_assert0(MAX_LEVEL >= 64); + av_assert0(MAX_RUN >= 63); + + // Note: The LUT only covers level values for which the escape value + // is eight bits (not 8 + 5 + 6) + memset(len_tab, H263_ESCAPE_CODE_LENGTH + 1 + 6 + 8, + sizeof(uni_h263_intra_aic_rl_len)); + + len_tab += 64; // simplifies addressing + for (int i = 0; i < H263_RL_NB_ELEMS; ++i) { + int run = table_run[i]; + int level = table_level[i]; + int last = i >= H263_RL_NON_LAST_CODES; + int len = table_vlc[i][1]; + + len_tab[UNI_MPEG4_ENC_INDEX(last, run, level)] = + len_tab[UNI_MPEG4_ENC_INDEX(last, run, -level)] = len + 1 /* sign */; + } + for (int run = 0; run < MAX_RUN; ++run) { + len_tab[UNI_MPEG4_ENC_INDEX(0, run, 0)] = + len_tab[UNI_MPEG4_ENC_INDEX(1, run, 0)] = 0; // is this necessary? + } +} +#endif + +static av_cold void h263_encode_init_static(void) +{ +#if CONFIG_H263_ENCODER + static uint8_t rl_intra_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; + ff_rl_init(&ff_rl_intra_aic, rl_intra_table); + ff_h263_init_rl_inter(); + + init_uni_h263_rl_tab(&ff_rl_intra_aic, uni_h263_intra_aic_rl_len); + init_uni_h263_rl_tab(&ff_h263_rl_inter, uni_h263_inter_rl_len); + + memset(umv_fcode_tab, 1, sizeof(umv_fcode_tab)); +#endif + + init_mv_penalty(); +} + +av_cold const uint8_t (*ff_h263_get_mv_penalty(void))[MAX_DMV*2+1] +{ + static AVOnce init_static_once = AV_ONCE_INIT; + + ff_thread_once(&init_static_once, h263_encode_init_static); + + return mv_penalty; +} + +void ff_h263_encode_motion(PutBitContext *pb, int val, int f_code) +{ + if (val == 0) { + /* zero vector -- corresponds to ff_mvtab[0] */ + put_bits(pb, 1, 1); + } else { + int sign, code, bits; + int bit_size = f_code - 1; + int range = 1 << bit_size; + /* modulo encoding */ + val = sign_extend(val, 6 + bit_size); + sign = val>>31; + val= (val^sign)-sign; + sign&=1; + + val--; + code = (val >> bit_size) + 1; + bits = val & (range - 1); + + put_bits(pb, ff_mvtab[code][1] + 1, (ff_mvtab[code][0] << 1) | sign); + if (bit_size > 0) { + put_bits(pb, bit_size, bits); + } + } +} + +#if CONFIG_H263_ENCODER // Snow and SVQ1 need the above static const uint8_t wrong_run[102] = { 1, 2, 3, 5, 4, 10, 9, 8, 11, 15, 17, 16, 23, 22, 21, 20, @@ -106,20 +216,23 @@ av_const int ff_h263_aspect_to_info(AVRational aspect){ return FF_ASPECT_EXTENDED; } -void ff_h263_encode_picture_header(MpegEncContext * s) +static int h263_encode_picture_header(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int format, coded_frame_rate, coded_frame_rate_base, i, temp_ref; int best_clock_code=1; int best_divisor=60; int best_error= INT_MAX; int custom_pcf; - if(s->h263_plus){ + put_bits_assume_flushed(&s->pb); + + if (s->c.codec_id == AV_CODEC_ID_H263P) { for(i=0; i<2; i++){ int div, error; - div= (s->avctx->time_base.num*1800000LL + 500LL*s->avctx->time_base.den) / ((1000LL+i)*s->avctx->time_base.den); + div= (s->c.avctx->time_base.num*1800000LL + 500LL*s->c.avctx->time_base.den) / ((1000LL+i)*s->c.avctx->time_base.den); div= av_clip(div, 1, 127); - error= FFABS(s->avctx->time_base.num*1800000LL - (1000LL+i)*s->avctx->time_base.den*div); + error= FFABS(s->c.avctx->time_base.num*1800000LL - (1000LL+i)*s->c.avctx->time_base.den*div); if(error < best_error){ best_error= error; best_divisor= div; @@ -131,13 +244,9 @@ void ff_h263_encode_picture_header(MpegEncContext * s) coded_frame_rate= 1800000; coded_frame_rate_base= (1000+best_clock_code)*best_divisor; - align_put_bits(&s->pb); - - /* Update the pointer to last GOB */ - s->ptr_lastgob = put_bits_ptr(&s->pb); put_bits(&s->pb, 22, 0x20); /* PSC */ - temp_ref= s->picture_number * (int64_t)coded_frame_rate * s->avctx->time_base.num / //FIXME use timestamp - (coded_frame_rate_base * (int64_t)s->avctx->time_base.den); + temp_ref = s->picture_number * (int64_t)coded_frame_rate * s->c.avctx->time_base.num / //FIXME use timestamp + (coded_frame_rate_base * (int64_t)s->c.avctx->time_base.den); put_sbits(&s->pb, 8, temp_ref); /* TemporalReference */ put_bits(&s->pb, 1, 1); /* marker */ @@ -146,19 +255,19 @@ void ff_h263_encode_picture_header(MpegEncContext * s) put_bits(&s->pb, 1, 0); /* camera off */ put_bits(&s->pb, 1, 0); /* freeze picture release off */ - format = ff_match_2uint16(ff_h263_format, FF_ARRAY_ELEMS(ff_h263_format), s->width, s->height); - if (!s->h263_plus) { + format = ff_match_2uint16(ff_h263_format, FF_ARRAY_ELEMS(ff_h263_format), s->c.width, s->c.height); + if (s->c.codec_id != AV_CODEC_ID_H263P) { /* H.263v1 */ put_bits(&s->pb, 3, format); - put_bits(&s->pb, 1, (s->pict_type == AV_PICTURE_TYPE_P)); + put_bits(&s->pb, 1, (s->c.pict_type == AV_PICTURE_TYPE_P)); /* By now UMV IS DISABLED ON H.263v1, since the restrictions of H.263v1 UMV implies to check the predicted MV after calculation of the current MB to see if we're on the limits */ put_bits(&s->pb, 1, 0); /* Unrestricted Motion Vector: off */ put_bits(&s->pb, 1, 0); /* SAC: off */ - put_bits(&s->pb, 1, s->obmc); /* Advanced Prediction */ + put_bits(&s->pb, 1, s->c.obmc); /* Advanced Prediction */ put_bits(&s->pb, 1, 0); /* only I/P-frames, no PB-frame */ - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); put_bits(&s->pb, 1, 0); /* Continuous Presence Multipoint mode: off */ } else { int ufep=1; @@ -175,8 +284,8 @@ void ff_h263_encode_picture_header(MpegEncContext * s) put_bits(&s->pb,1, custom_pcf); put_bits(&s->pb,1, s->umvplus); /* Unrestricted Motion Vector */ put_bits(&s->pb,1,0); /* SAC: off */ - put_bits(&s->pb,1,s->obmc); /* Advanced Prediction Mode */ - put_bits(&s->pb,1,s->h263_aic); /* Advanced Intra Coding */ + put_bits(&s->pb,1,s->c.obmc); /* Advanced Prediction Mode */ + put_bits(&s->pb,1,s->c.h263_aic); /* Advanced Intra Coding */ put_bits(&s->pb,1,s->loop_filter); /* Deblocking Filter */ put_bits(&s->pb,1,s->h263_slice_structured); /* Slice Structured */ put_bits(&s->pb,1,0); /* Reference Picture Selection: off */ @@ -186,11 +295,11 @@ void ff_h263_encode_picture_header(MpegEncContext * s) put_bits(&s->pb,1,1); /* "1" to prevent start code emulation */ put_bits(&s->pb,3,0); /* Reserved */ - put_bits(&s->pb, 3, s->pict_type == AV_PICTURE_TYPE_P); + put_bits(&s->pb, 3, s->c.pict_type == AV_PICTURE_TYPE_P); put_bits(&s->pb,1,0); /* Reference Picture Resampling: off */ put_bits(&s->pb,1,0); /* Reduced-Resolution Update: off */ - put_bits(&s->pb,1,s->no_rounding); /* Rounding Type */ + put_bits(&s->pb,1,s->c.no_rounding); /* Rounding Type */ put_bits(&s->pb,2,0); /* Reserved */ put_bits(&s->pb,1,1); /* "1" to prevent start code emulation */ @@ -199,15 +308,15 @@ void ff_h263_encode_picture_header(MpegEncContext * s) if (format == 8) { /* Custom Picture Format (CPFMT) */ - unsigned aspect_ratio_info = ff_h263_aspect_to_info(s->avctx->sample_aspect_ratio); + unsigned aspect_ratio_info = ff_h263_aspect_to_info(s->c.avctx->sample_aspect_ratio); put_bits(&s->pb,4, aspect_ratio_info); - put_bits(&s->pb,9,(s->width >> 2) - 1); + put_bits(&s->pb,9,(s->c.width >> 2) - 1); put_bits(&s->pb,1,1); /* "1" to prevent start code emulation */ - put_bits(&s->pb,9,(s->height >> 2)); + put_bits(&s->pb,9,(s->c.height >> 2)); if (aspect_ratio_info == FF_ASPECT_EXTENDED){ - put_bits(&s->pb, 8, s->avctx->sample_aspect_ratio.num); - put_bits(&s->pb, 8, s->avctx->sample_aspect_ratio.den); + put_bits(&s->pb, 8, s->c.avctx->sample_aspect_ratio.num); + put_bits(&s->pb, 8, s->c.avctx->sample_aspect_ratio.den); } } if (custom_pcf) { @@ -223,71 +332,90 @@ void ff_h263_encode_picture_header(MpegEncContext * s) // put_bits(&s->pb,1,1); /* Limited according tables of Annex D */ //FIXME check actual requested range put_bits(&s->pb,2,1); /* unlimited */ - if(s->h263_slice_structured) + if (s->h263_slice_structured) put_bits(&s->pb,2,0); /* no weird submodes */ - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); } put_bits(&s->pb, 1, 0); /* no PEI */ - if(s->h263_slice_structured){ + if (s->h263_slice_structured) { put_bits(&s->pb, 1, 1); - av_assert1(s->mb_x == 0 && s->mb_y == 0); + av_assert1(s->c.mb_x == 0 && s->c.mb_y == 0); ff_h263_encode_mba(s); put_bits(&s->pb, 1, 1); } + + return 0; +} + +void ff_h263_mpeg4_reset_dc(MPVEncContext *s) +{ + int16_t *dc = s->c.dc_val; + + // The "- 1" is for the top-left entry + const int l_xy = s->c.block_index[2]; + for (int i = l_xy - 2 * s->c.b8_stride - 1; i < l_xy; i += 2) + AV_WN32A(dc + i, 1024 << 16 | 1024); + + const int u_xy = s->c.block_index[4]; + const int v_xy = s->c.block_index[5]; + int16_t *dc2 = dc + v_xy - u_xy; + for (int i = u_xy - s->c.mb_stride - 1; i < u_xy; ++i) + dc[i] = dc2[i] = 1024; } /** * Encode a group of blocks header. */ -void ff_h263_encode_gob_header(MpegEncContext * s, int mb_line) +void ff_h263_encode_gob_header(MPVEncContext *const s, int mb_line) { put_bits(&s->pb, 17, 1); /* GBSC */ - if(s->h263_slice_structured){ + if (s->h263_slice_structured) { put_bits(&s->pb, 1, 1); ff_h263_encode_mba(s); - if(s->mb_num > 1583) + if(s->c.mb_num > 1583) put_bits(&s->pb, 1, 1); - put_bits(&s->pb, 5, s->qscale); /* GQUANT */ + put_bits(&s->pb, 5, s->c.qscale); /* GQUANT */ put_bits(&s->pb, 1, 1); - put_bits(&s->pb, 2, s->pict_type == AV_PICTURE_TYPE_I); /* GFID */ + put_bits(&s->pb, 2, s->c.pict_type == AV_PICTURE_TYPE_I); /* GFID */ }else{ - int gob_number= mb_line / s->gob_index; + int gob_number = mb_line / s->gob_index; put_bits(&s->pb, 5, gob_number); /* GN */ - put_bits(&s->pb, 2, s->pict_type == AV_PICTURE_TYPE_I); /* GFID */ - put_bits(&s->pb, 5, s->qscale); /* GQUANT */ + put_bits(&s->pb, 2, s->c.pict_type == AV_PICTURE_TYPE_I); /* GFID */ + put_bits(&s->pb, 5, s->c.qscale); /* GQUANT */ } } /** * modify qscale so that encoding is actually possible in H.263 (limit difference to -2..2) */ -void ff_clean_h263_qscales(MpegEncContext *s){ - int i; - int8_t * const qscale_table = s->cur_pic.qscale_table; +void ff_clean_h263_qscales(MPVEncContext *const s) +{ + int8_t * const qscale_table = s->c.cur_pic.qscale_table; - for(i=1; imb_num; i++){ - if(qscale_table[ s->mb_index2xy[i] ] - qscale_table[ s->mb_index2xy[i-1] ] >2) - qscale_table[ s->mb_index2xy[i] ]= qscale_table[ s->mb_index2xy[i-1] ]+2; + for (int i = 1; i < s->c.mb_num; i++) { + if (qscale_table[ s->c.mb_index2xy[i] ] - qscale_table[ s->c.mb_index2xy[i-1] ] > 2) + qscale_table[ s->c.mb_index2xy[i] ] = qscale_table[ s->c.mb_index2xy[i-1] ] + 2; } - for(i=s->mb_num-2; i>=0; i--){ - if(qscale_table[ s->mb_index2xy[i] ] - qscale_table[ s->mb_index2xy[i+1] ] >2) - qscale_table[ s->mb_index2xy[i] ]= qscale_table[ s->mb_index2xy[i+1] ]+2; + for(int i = s->c.mb_num - 2; i >= 0; i--) { + if (qscale_table[ s->c.mb_index2xy[i] ] - qscale_table[ s->c.mb_index2xy[i+1] ] > 2) + qscale_table[ s->c.mb_index2xy[i] ] = qscale_table[ s->c.mb_index2xy[i+1] ] + 2; } - if(s->codec_id != AV_CODEC_ID_H263P){ - for(i=1; imb_num; i++){ - int mb_xy= s->mb_index2xy[i]; + if (s->c.codec_id != AV_CODEC_ID_H263P) { + for (int i = 1; i < s->c.mb_num; i++) { + int mb_xy = s->c.mb_index2xy[i]; - if(qscale_table[mb_xy] != qscale_table[s->mb_index2xy[i-1]] && (s->mb_type[mb_xy]&CANDIDATE_MB_TYPE_INTER4V)){ + if (qscale_table[mb_xy] != qscale_table[s->c.mb_index2xy[i - 1]] && + (s->mb_type[mb_xy] & CANDIDATE_MB_TYPE_INTER4V)) { s->mb_type[mb_xy]|= CANDIDATE_MB_TYPE_INTER; } } @@ -296,18 +424,40 @@ void ff_clean_h263_qscales(MpegEncContext *s){ static const int dquant_code[5]= {1,0,9,2,3}; +static void flv2_encode_ac_esc(PutBitContext *pb, int slevel, int level, + int run, int last) +{ + unsigned code; + int bits; + if (level < 64) { // 7-bit level + bits = 1 + 1 + 6 + 7; + code = (0 << (1 + 6 + 7)) | + (last << (6 + 7)) | + (run << 7) | + (slevel & 0x7f); + } else { + /* 11-bit level */ + bits = 1 + 1 + 6 + 11; + code = (1 << (1 + 6 + 11)) | + (last << (6 + 11)) | + (run << 11) | + (slevel & 0x7ff); + } + put_bits(pb, bits, code); +} + /** * Encode an 8x8 block. * @param block the 8x8 block * @param n block index (0-3 are luma, 4-5 are chroma) */ -static void h263_encode_block(MpegEncContext * s, int16_t * block, int n) +static void h263_encode_block(MPVEncContext *const s, int16_t block[], int n) { int level, run, last, i, j, last_index, last_non_zero, sign, slevel, code; const RLTable *rl; rl = &ff_h263_rl_inter; - if (s->mb_intra && !s->h263_aic) { + if (s->c.mb_intra && !s->c.h263_aic) { /* DC coef */ level = block[0]; /* 255 cannot be represented, so we clamp */ @@ -327,19 +477,19 @@ static void h263_encode_block(MpegEncContext * s, int16_t * block, int n) i = 1; } else { i = 0; - if (s->h263_aic && s->mb_intra) + if (s->c.h263_aic && s->c.mb_intra) rl = &ff_rl_intra_aic; - if(s->alt_inter_vlc && !s->mb_intra){ + if (s->alt_inter_vlc && !s->c.mb_intra) { int aic_vlc_bits=0; int inter_vlc_bits=0; int wrong_pos=-1; int aic_code; - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; last_non_zero = i - 1; for (; i <= last_index; i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; level = block[j]; if (level) { run = i - last_non_zero - 1; @@ -370,10 +520,10 @@ static void h263_encode_block(MpegEncContext * s, int16_t * block, int n) } /* AC coefs */ - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; last_non_zero = i - 1; for (; i <= last_index; i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; level = block[j]; if (level) { run = i - last_non_zero - 1; @@ -387,22 +537,22 @@ static void h263_encode_block(MpegEncContext * s, int16_t * block, int n) code = get_rl_index(rl, last, run, level); put_bits(&s->pb, rl->table_vlc[code][1], rl->table_vlc[code][0]); if (code == rl->n) { - if(!CONFIG_FLV_ENCODER || s->h263_flv <= 1){ - put_bits(&s->pb, 1, last); - put_bits(&s->pb, 6, run); + if (!CONFIG_FLV_ENCODER || s->c.codec_id != AV_CODEC_ID_FLV1) { + put_bits(&s->pb, 1, last); + put_bits(&s->pb, 6, run); - av_assert2(slevel != 0); + av_assert2(slevel != 0); - if(level < 128) - put_sbits(&s->pb, 8, slevel); - else{ - put_bits(&s->pb, 8, 128); - put_sbits(&s->pb, 5, slevel); - put_sbits(&s->pb, 6, slevel>>5); + if (level < 128) { + put_sbits(&s->pb, 8, slevel); + } else { + put_bits(&s->pb, 8, 128); + put_sbits(&s->pb, 5, slevel); + put_sbits(&s->pb, 6, slevel>>5); + } + } else { + flv2_encode_ac_esc(&s->pb, slevel, level, run, last); } - }else{ - ff_flv2_encode_ac_esc(&s->pb, slevel, level, run, last); - } } else { put_bits(&s->pb, 1, sign); } @@ -414,69 +564,37 @@ static void h263_encode_block(MpegEncContext * s, int16_t * block, int n) /* Encode MV differences on H.263+ with Unrestricted MV mode */ static void h263p_encode_umotion(PutBitContext *pb, int val) { - short sval = 0; - short i = 0; - short n_bits = 0; - short temp_val; - int code = 0; - int tcode; - if ( val == 0) put_bits(pb, 1, 1); - else if (val == 1) - put_bits(pb, 3, 0); - else if (val == -1) - put_bits(pb, 3, 2); else { + unsigned code = (val < 0) << 1; + unsigned aval = val < 0 ? -val : val; + unsigned n_bits = 2; - sval = ((val < 0) ? (short)(-val):(short)val); - temp_val = sval; - - while (temp_val != 0) { - temp_val = temp_val >> 1; - n_bits++; + while (aval != 1) { // The leading digit is implicitly coded via length + unsigned tmp = (aval & 1) << 1 | 1; + aval >>= 1; + code |= tmp << n_bits; + n_bits += 2; } - - i = n_bits - 1; - while (i > 0) { - tcode = (sval & (1 << (i-1))) >> (i-1); - tcode = (tcode << 1) | 1; - code = (code << 2) | tcode; - i--; - } - code = ((code << 1) | (val < 0)) << 1; - put_bits(pb, (2*n_bits)+1, code); + put_bits(pb, n_bits + 1, code); } } -static int h263_pred_dc(MpegEncContext * s, int n, int16_t **dc_val_ptr) +static int h263_pred_dc(MPVEncContext *const s, int n, int16_t **dc_val_ptr) { - int x, y, wrap, a, c, pred_dc; - int16_t *dc_val; + const int wrap = s->c.block_wrap[n]; + const int xy = s->c.block_index[n]; + int16_t *const dc_val = s->c.dc_val + xy; + int pred_dc; /* find prediction */ - if (n < 4) { - x = 2 * s->mb_x + (n & 1); - y = 2 * s->mb_y + ((n & 2) >> 1); - wrap = s->b8_stride; - dc_val = s->dc_val[0]; - } else { - x = s->mb_x; - y = s->mb_y; - wrap = s->mb_stride; - dc_val = s->dc_val[n - 4 + 1]; - } /* B C * A X */ - a = dc_val[(x - 1) + (y) * wrap]; - c = dc_val[(x) + (y - 1) * wrap]; + int a = dc_val[-1]; + int c = dc_val[-wrap]; - /* No prediction outside GOB boundary */ - if (s->first_slice_line && n != 3) { - if (n != 2) c = 1024; - if (n != 1 && s->mb_x == s->resync_mb_x) a = 1024; - } /* just DC prediction */ if (a != 1024 && c != 1024) pred_dc = (a + c) >> 1; @@ -486,25 +604,24 @@ static int h263_pred_dc(MpegEncContext * s, int n, int16_t **dc_val_ptr) pred_dc = c; /* we assume pred is positive */ - *dc_val_ptr = &dc_val[x + y * wrap]; + *dc_val_ptr = dc_val; return pred_dc; } -void ff_h263_encode_mb(MpegEncContext * s, - int16_t block[6][64], - int motion_x, int motion_y) +static void h263_encode_mb(MPVEncContext *const s, + int16_t block[][64], + int motion_x, int motion_y) { int cbpc, cbpy, i, cbp, pred_x, pred_y; int16_t pred_dc; int16_t rec_intradc[6]; - int16_t *dc_ptr[6]; - const int interleaved_stats = s->avctx->flags & AV_CODEC_FLAG_PASS1; + const int interleaved_stats = s->c.avctx->flags & AV_CODEC_FLAG_PASS1; - if (!s->mb_intra) { + if (!s->c.mb_intra) { /* compute cbp */ cbp= get_p_cbp(s, block, motion_x, motion_y); - if ((cbp | motion_x | motion_y | s->dquant | (s->mv_type - MV_TYPE_16X16)) == 0) { + if ((cbp | motion_x | motion_y | s->dquant | (s->c.mv_type - MV_TYPE_16X16)) == 0) { /* skip macroblock */ put_bits(&s->pb, 1, 1); if(interleaved_stats){ @@ -518,10 +635,10 @@ void ff_h263_encode_mb(MpegEncContext * s, cbpc = cbp & 3; cbpy = cbp >> 2; - if(s->alt_inter_vlc==0 || cbpc!=3) + if (!s->alt_inter_vlc || cbpc!=3) cbpy ^= 0xF; if(s->dquant) cbpc+= 8; - if(s->mv_type==MV_TYPE_16X16){ + if(s->c.mv_type==MV_TYPE_16X16){ put_bits(&s->pb, ff_h263_inter_MCBPC_bits[cbpc], ff_h263_inter_MCBPC_code[cbpc]); @@ -535,7 +652,7 @@ void ff_h263_encode_mb(MpegEncContext * s, } /* motion vectors: 16x16 mode */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); if (!s->umvplus) { ff_h263_encode_motion_vector(s, motion_x - pred_x, @@ -562,10 +679,10 @@ void ff_h263_encode_mb(MpegEncContext * s, for(i=0; i<4; i++){ /* motion vectors: 8x8 mode*/ - ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, i, 0, &pred_x, &pred_y); - motion_x = s->cur_pic.motion_val[0][s->block_index[i]][0]; - motion_y = s->cur_pic.motion_val[0][s->block_index[i]][1]; + motion_x = s->c.cur_pic.motion_val[0][s->c.block_index[i]][0]; + motion_y = s->c.cur_pic.motion_val[0][s->c.block_index[i]][1]; if (!s->umvplus) { ff_h263_encode_motion_vector(s, motion_x - pred_x, motion_y - pred_y, 1); @@ -584,19 +701,17 @@ void ff_h263_encode_mb(MpegEncContext * s, s->mv_bits+= get_bits_diff(s); } } else { - av_assert2(s->mb_intra); + av_assert2(s->c.mb_intra); cbp = 0; - if (s->h263_aic) { + if (s->c.h263_aic) { /* Predict DC */ for(i=0; i<6; i++) { int16_t level = block[i][0]; - int scale; + int16_t *dc_ptr; + int scale = i < 4 ? s->c.y_dc_scale : s->c.c_dc_scale; - if(i<4) scale= s->y_dc_scale; - else scale= s->c_dc_scale; - - pred_dc = h263_pred_dc(s, i, &dc_ptr[i]); + pred_dc = h263_pred_dc(s, i, &dc_ptr); level -= pred_dc; /* Quant */ if (level >= 0) @@ -604,7 +719,7 @@ void ff_h263_encode_mb(MpegEncContext * s, else level = (level - (scale>>1))/scale; - if(!s->modified_quant){ + if (!s->modified_quant) { if (level < -127) level = -127; else if (level > 127) @@ -625,22 +740,22 @@ void ff_h263_encode_mb(MpegEncContext * s, rec_intradc[i] = 2047; /* Update AC/DC tables */ - *dc_ptr[i] = rec_intradc[i]; + *dc_ptr = rec_intradc[i]; /* AIC can change CBP */ - if (s->block_last_index[i] > 0 || - (s->block_last_index[i] == 0 && level !=0)) + if (s->c.block_last_index[i] > 0 || + (s->c.block_last_index[i] == 0 && level !=0)) cbp |= 1 << (5 - i); } }else{ for(i=0; i<6; i++) { /* compute cbp */ - if (s->block_last_index[i] >= 1) + if (s->c.block_last_index[i] >= 1) cbp |= 1 << (5 - i); } } cbpc = cbp & 3; - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { if(s->dquant) cbpc+=4; put_bits(&s->pb, ff_h263_intra_MCBPC_bits[cbpc], @@ -652,7 +767,7 @@ void ff_h263_encode_mb(MpegEncContext * s, ff_h263_inter_MCBPC_bits[cbpc + 4], ff_h263_inter_MCBPC_code[cbpc + 4]); } - if (s->h263_aic) { + if (s->c.h263_aic) { /* XXX: currently, we do not try to use ac prediction */ put_bits(&s->pb, 1, 0); /* no AC prediction */ } @@ -671,14 +786,12 @@ void ff_h263_encode_mb(MpegEncContext * s, h263_encode_block(s, block[i], i); /* Update INTRADC for decoding */ - if (s->h263_aic && s->mb_intra) { + if (s->c.h263_aic && s->c.mb_intra) block[i][0] = rec_intradc[i]; - - } } if(interleaved_stats){ - if (!s->mb_intra) { + if (!s->c.mb_intra) { s->p_tex_bits+= get_bits_diff(s); }else{ s->i_tex_bits+= get_bits_diff(s); @@ -687,169 +800,62 @@ void ff_h263_encode_mb(MpegEncContext * s, } } -void ff_h263_update_mb(MpegEncContext *s) +void ff_h263_update_mb(MPVEncContext *const s) { - const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; + const int mb_xy = s->c.mb_y * s->c.mb_stride + s->c.mb_x; - if (s->cur_pic.mbskip_table) - s->cur_pic.mbskip_table[mb_xy] = s->mb_skipped; + if (s->c.cur_pic.mbskip_table) + s->c.cur_pic.mbskip_table[mb_xy] = s->c.mb_skipped; - if (s->mv_type == MV_TYPE_8X8) - s->cur_pic.mb_type[mb_xy] = MB_TYPE_FORWARD_MV | MB_TYPE_8x8; - else if(s->mb_intra) - s->cur_pic.mb_type[mb_xy] = MB_TYPE_INTRA; + if (s->c.mv_type == MV_TYPE_8X8) + s->c.cur_pic.mb_type[mb_xy] = MB_TYPE_FORWARD_MV | MB_TYPE_8x8; + else if(s->c.mb_intra) + s->c.cur_pic.mb_type[mb_xy] = MB_TYPE_INTRA; else - s->cur_pic.mb_type[mb_xy] = MB_TYPE_FORWARD_MV | MB_TYPE_16x16; + s->c.cur_pic.mb_type[mb_xy] = MB_TYPE_FORWARD_MV | MB_TYPE_16x16; - ff_h263_update_motion_val(s); + ff_h263_update_motion_val(&s->c); } -void ff_h263_encode_motion(PutBitContext *pb, int val, int f_code) +av_cold void ff_h263_encode_init(MPVMainEncContext *const m) { - int range, bit_size, sign, code, bits; + MPVEncContext *const s = &m->s; - if (val == 0) { - /* zero vector -- corresponds to ff_mvtab[0] */ - put_bits(pb, 1, 1); - } else { - bit_size = f_code - 1; - range = 1 << bit_size; - /* modulo encoding */ - val = sign_extend(val, 6 + bit_size); - sign = val>>31; - val= (val^sign)-sign; - sign&=1; + s->me.mv_penalty = ff_h263_get_mv_penalty(); // FIXME exact table for MSMPEG4 & H.263+ - val--; - code = (val >> bit_size) + 1; - bits = val & (range - 1); + ff_h263dsp_init(&s->c.h263dsp); - put_bits(pb, ff_mvtab[code][1] + 1, (ff_mvtab[code][0] << 1) | sign); - if (bit_size > 0) { - put_bits(pb, bit_size, bits); - } - } -} + ff_permute_scantable(s->permutated_intra_h_scantable, ff_alternate_horizontal_scan, + s->c.idsp.idct_permutation); + ff_permute_scantable(s->permutated_intra_v_scantable, ff_alternate_vertical_scan, + s->c.idsp.idct_permutation); -static av_cold void init_mv_penalty_and_fcode(void) -{ - int f_code; - int mv; - - for(f_code=1; f_code<=MAX_FCODE; f_code++){ - for(mv=-MAX_DMV; mv<=MAX_DMV; mv++){ - int len; - - if (mv==0) len = 1; // ff_mvtab[0][1] - else{ - int val, bit_size, code; - - bit_size = f_code - 1; - - val=mv; - if (val < 0) - val = -val; - val--; - code = (val >> bit_size) + 1; - if(code<33){ - len= ff_mvtab[code][1] + 1 + bit_size; - }else{ - len = 12 /* ff_mvtab[32][1] */ + av_log2(code>>5) + 2 + bit_size; - } - } - - mv_penalty[f_code][mv+MAX_DMV]= len; - } - } - - for(f_code=MAX_FCODE; f_code>0; f_code--){ - for(mv=-(16<= 64); - av_assert0(MAX_RUN >= 63); - - for(slevel=-64; slevel<64; slevel++){ - if(slevel==0) continue; - for(run=0; run<64; run++){ - for(last=0; last<=1; last++){ - const int index= UNI_MPEG4_ENC_INDEX(last, run, slevel+64); - int level= slevel < 0 ? -slevel : slevel; - int sign= slevel < 0 ? 1 : 0; - int bits, len, code; - - len_tab[index]= 100; - - /* ESC0 */ - code= get_rl_index(rl, last, run, level); - bits= rl->table_vlc[code][0]; - len= rl->table_vlc[code][1]; - bits=bits*2+sign; len++; - - if (code != rl->n && len < len_tab[index]) - len_tab [index]= len; - - /* ESC */ - bits= rl->table_vlc[rl->n][0]; - len = rl->table_vlc[rl->n][1]; - bits=bits*2+last; len++; - bits=bits*64+run; len+=6; - bits=bits*256+(level&0xff); len+=8; - - if (len < len_tab[index]) - len_tab [index]= len; - } - } - } -} - -static av_cold void h263_encode_init_static(void) -{ - static uint8_t rl_intra_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; - - ff_rl_init(&ff_rl_intra_aic, rl_intra_table); - ff_h263_init_rl_inter(); - - init_uni_h263_rl_tab(&ff_rl_intra_aic, uni_h263_intra_aic_rl_len); - init_uni_h263_rl_tab(&ff_h263_rl_inter, uni_h263_inter_rl_len); - - init_mv_penalty_and_fcode(); -} - -av_cold void ff_h263_encode_init(MpegEncContext *s) -{ - static AVOnce init_static_once = AV_ONCE_INIT; - - s->me.mv_penalty= mv_penalty; // FIXME exact table for MSMPEG4 & H.263+ + if (s->c.codec_id == AV_CODEC_ID_MPEG4) + return; s->intra_ac_vlc_length =s->inter_ac_vlc_length = uni_h263_inter_rl_len; s->intra_ac_vlc_last_length=s->inter_ac_vlc_last_length= uni_h263_inter_rl_len + 128*64; - if(s->h263_aic){ + if (s->c.h263_aic) { s->intra_ac_vlc_length = uni_h263_intra_aic_rl_len; s->intra_ac_vlc_last_length= uni_h263_intra_aic_rl_len + 128*64; + + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_aic_dc_scale_table; } s->ac_esc_length= 7+1+6+8; + if (s->modified_quant) + s->c.chroma_qscale_table = ff_h263_chroma_qscale_table; + + // Only used for H.263 and H.263+ + s->gob_index = H263_GOB_HEIGHT(s->c.height); + // use fcodes >1 only for MPEG-4 & H.263 & H.263+ FIXME - switch(s->codec_id){ - case AV_CODEC_ID_MPEG4: - s->fcode_tab= fcode_tab; - break; + switch(s->c.codec_id){ case AV_CODEC_ID_H263P: - if(s->umvplus) - s->fcode_tab= umv_fcode_tab; - if(s->modified_quant){ + if (s->umvplus) + m->fcode_tab = umv_fcode_tab + MAX_MV; + if (s->modified_quant) { s->min_qcoeff= -2047; s->max_qcoeff= 2047; }else{ @@ -858,42 +864,33 @@ av_cold void ff_h263_encode_init(MpegEncContext *s) } break; // Note for MPEG-4 & H.263 the dc-scale table will be set per frame as needed later +#if CONFIG_FLV_ENCODER case AV_CODEC_ID_FLV1: - if (s->h263_flv > 1) { - s->min_qcoeff= -1023; - s->max_qcoeff= 1023; - } else { - s->min_qcoeff= -127; - s->max_qcoeff= 127; - } + m->encode_picture_header = ff_flv_encode_picture_header; + /* format = 1; 11-bit codes */ + s->min_qcoeff = -1023; + s->max_qcoeff = 1023; break; +#endif default: //nothing needed - default table already set in mpegvideo.c s->min_qcoeff= -127; s->max_qcoeff= 127; } - if(s->h263_aic){ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_aic_dc_scale_table; - }else{ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_mpeg1_dc_scale_table; - } - -#if CONFIG_H263_ENCODER // Snow and SVQ1 call this - ff_h263dsp_init(&s->h263dsp); -#endif - - ff_thread_once(&init_static_once, h263_encode_init_static); + // H.263, H.263+; will be overwritten for MSMPEG-4 later + if (!m->encode_picture_header) + m->encode_picture_header = h263_encode_picture_header; + if (!s->encode_mb) + s->encode_mb = h263_encode_mb; } -void ff_h263_encode_mba(MpegEncContext *s) +void ff_h263_encode_mba(MPVEncContext *const s) { int i, mb_pos; for(i=0; i<6; i++){ - if(s->mb_num-1 <= ff_mba_max[i]) break; + if(s->c.mb_num-1 <= ff_mba_max[i]) break; } - mb_pos= s->mb_x + s->mb_width*s->mb_y; + mb_pos= s->c.mb_x + s->c.mb_width*s->c.mb_y; put_bits(&s->pb, ff_mba_length[i], mb_pos); } @@ -901,7 +898,7 @@ void ff_h263_encode_mba(MpegEncContext *s) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption h263_options[] = { { "obmc", "use overlapped block motion compensation.", OFFSET(obmc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "mb_info", "emit macroblock info for RFC 2190 packetization, the parameter value is the maximum payload size", OFFSET(mb_info), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, + { "mb_info", "emit macroblock info for RFC 2190 packetization, the parameter value is the maximum payload size", FF_MPV_OFFSET(mb_info), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, FF_MPV_COMMON_OPTS FF_MPV_COMMON_MOTION_EST_OPTS { NULL }, @@ -919,22 +916,22 @@ const FFCodec ff_h263_encoder = { CODEC_LONG_NAME("H.263 / H.263-1996"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H263, - .p.pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &h263_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MPVMainEncContext), .init = ff_mpv_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, }; static const AVOption h263p_options[] = { - { "umv", "Use unlimited motion vectors.", OFFSET(umvplus), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "aiv", "Use alternative inter VLC.", OFFSET(alt_inter_vlc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "umv", "Use unlimited motion vectors.", FF_MPV_OFFSET(umvplus), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "aiv", "Use alternative inter VLC.", FF_MPV_OFFSET(alt_inter_vlc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "obmc", "use overlapped block motion compensation.", OFFSET(obmc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "structured_slices", "Write slice start position at every GOB header instead of just GOB number.", OFFSET(h263_slice_structured), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, + { "structured_slices", "Write slice start position at every GOB header instead of just GOB number.", FF_MPV_OFFSET(h263_slice_structured), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, FF_MPV_COMMON_OPTS FF_MPV_COMMON_MOTION_EST_OPTS { NULL }, @@ -951,13 +948,15 @@ const FFCodec ff_h263p_encoder = { CODEC_LONG_NAME("H.263+ / H.263-1998 / H.263 version 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H263P, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &h263p_class, - .p.capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MPVMainEncContext), .init = ff_mpv_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, }; +#endif diff --git a/libavcodec/itut35.h b/libavcodec/itut35.h index a75ef3792..84ea86f3d 100644 --- a/libavcodec/itut35.h +++ b/libavcodec/itut35.h @@ -23,10 +23,19 @@ #define ITU_T_T35_COUNTRY_CODE_UK 0xB4 #define ITU_T_T35_COUNTRY_CODE_US 0xB5 -#define ITU_T_T35_PROVIDER_CODE_ATSC 0x31 -#define ITU_T_T35_PROVIDER_CODE_CUVA 0x04 -#define ITU_T_T35_PROVIDER_CODE_DOLBY 0x3B -#define ITU_T_T35_PROVIDER_CODE_LCEVC 0x50 -#define ITU_T_T35_PROVIDER_CODE_SMTPE 0x3C +// The Terminal Provider Code (or "Manufacturer Code") identifies the +// manufacturer within a country. An Assignment Authority appointed by the +// national body assigns this code nationally. The manufacturer code is always +// used in conjunction with a country code. +// - CN providers +#define ITU_T_T35_PROVIDER_CODE_HDR_VIVID 0x0004 +// - UK providers +// https://www.cix.co.uk/~bpechey/H221/h221code.htm +#define ITU_T_T35_PROVIDER_CODE_VNOVA 0x5000 +// - US providers +#define ITU_T_T35_PROVIDER_CODE_ATSC 0x0031 +#define ITU_T_T35_PROVIDER_CODE_DOLBY 0x003B +#define ITU_T_T35_PROVIDER_CODE_AOM 0x5890 +#define ITU_T_T35_PROVIDER_CODE_SAMSUNG 0x003C #endif /* AVCODEC_ITUT35_H */ diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c index 60cc0f309..cba4d18ad 100644 --- a/libavcodec/j2kenc.c +++ b/libavcodec/j2kenc.c @@ -71,6 +71,7 @@ #include "bytestream.h" #include "jpeg2000.h" #include "version.h" +#include "libavutil/attributes.h" #include "libavutil/common.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" @@ -147,76 +148,6 @@ typedef struct { } Jpeg2000EncoderContext; -/* debug */ -#if 0 -#undef ifprintf -#undef printf - -static void nspaces(FILE *fd, int n) -{ - while(n--) putc(' ', fd); -} - -static void printcomp(Jpeg2000Component *comp) -{ - int i; - for (i = 0; i < comp->y1 - comp->y0; i++) - ff_jpeg2000_printv(comp->i_data + i * (comp->x1 - comp->x0), comp->x1 - comp->x0); -} - -static void dump(Jpeg2000EncoderContext *s, FILE *fd) -{ - int tileno, compno, reslevelno, bandno, precno; - fprintf(fd, "XSiz = %d, YSiz = %d, tile_width = %d, tile_height = %d\n" - "numXtiles = %d, numYtiles = %d, ncomponents = %d\n" - "tiles:\n", - s->width, s->height, s->tile_width, s->tile_height, - s->numXtiles, s->numYtiles, s->ncomponents); - for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){ - Jpeg2000Tile *tile = s->tile + tileno; - nspaces(fd, 2); - fprintf(fd, "tile %d:\n", tileno); - for(compno = 0; compno < s->ncomponents; compno++){ - Jpeg2000Component *comp = tile->comp + compno; - nspaces(fd, 4); - fprintf(fd, "component %d:\n", compno); - nspaces(fd, 4); - fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d\n", - comp->x0, comp->x1, comp->y0, comp->y1); - for(reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){ - Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno; - nspaces(fd, 6); - fprintf(fd, "reslevel %d:\n", reslevelno); - nspaces(fd, 6); - fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d, nbands = %d\n", - reslevel->x0, reslevel->x1, reslevel->y0, - reslevel->y1, reslevel->nbands); - for(bandno = 0; bandno < reslevel->nbands; bandno++){ - Jpeg2000Band *band = reslevel->band + bandno; - nspaces(fd, 8); - fprintf(fd, "band %d:\n", bandno); - nspaces(fd, 8); - fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d," - "codeblock_width = %d, codeblock_height = %d cblknx = %d cblkny = %d\n", - band->x0, band->x1, - band->y0, band->y1, - band->codeblock_width, band->codeblock_height, - band->cblknx, band->cblkny); - for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){ - Jpeg2000Prec *prec = band->prec + precno; - nspaces(fd, 10); - fprintf(fd, "prec %d:\n", precno); - nspaces(fd, 10); - fprintf(fd, "xi0 = %d, xi1 = %d, yi0 = %d, yi1 = %d\n", - prec->xi0, prec->xi1, prec->yi0, prec->yi1); - } - } - } - } - } -} -#endif - /* bitstream routines */ /** put n times val bit */ @@ -580,7 +511,7 @@ static void init_quantization(Jpeg2000EncoderContext *s) } } -static void init_luts(void) +static av_cold void init_luts(void) { int i, a, mask = ~((1<ncomponents; compno++){ Jpeg2000Component *comp = tile->comp + compno; - for (reslevelno = 0, lev = codsty->nreslevels-1; reslevelno < codsty->nreslevels; reslevelno++, lev--){ + for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){ Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno; for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){ @@ -1726,7 +1657,7 @@ static av_cold int j2kenc_init(AVCodecContext *avctx) s->avctx = avctx; av_log(s->avctx, AV_LOG_DEBUG, "init\n"); if (parse_layer_rates(s)) { - av_log(s, AV_LOG_WARNING, "Layer rates invalid. Encoding with 1 layer based on quality metric.\n"); + av_log(avctx, AV_LOG_WARNING, "Layer rates invalid. Encoding with 1 layer based on quality metric.\n"); s->nlayers = 1; s->layer_rates[0] = 0; s->compression_rate_enc = 0; @@ -1802,7 +1733,7 @@ static int j2kenc_destroy(AVCodecContext *avctx) return 0; } -// taken from the libopenjpeg wraper so it matches +// taken from the libopenjpeg wrapper so it matches #define OFFSET(x) offsetof(Jpeg2000EncoderContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM @@ -1845,7 +1776,7 @@ const FFCodec ff_jpeg2000_encoder = { .init = j2kenc_init, FF_CODEC_ENCODE_CB(encode_frame), .close = j2kenc_destroy, - .p.pix_fmts = (const enum AVPixelFormat[]) { + CODEC_PIXFMTS( AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48, AV_PIX_FMT_GBR24P,AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, @@ -1862,9 +1793,7 @@ const FFCodec ff_jpeg2000_encoder = { AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P16, - AV_PIX_FMT_PAL8, - AV_PIX_FMT_NONE - }, + AV_PIX_FMT_PAL8), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &j2k_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/jacosubdec.c b/libavcodec/jacosubdec.c index 08349a9ec..fd90dcc4b 100644 --- a/libavcodec/jacosubdec.c +++ b/libavcodec/jacosubdec.c @@ -32,8 +32,6 @@ #include "libavutil/bprint.h" #include "libavutil/time_internal.h" -#undef time - static int insert_text(AVBPrint *dst, const char *in, const char *arg) { av_bprintf(dst, "%s", arg); diff --git a/libavcodec/jpeg2000.c b/libavcodec/jpeg2000.c index d6ffb0231..6433e1389 100644 --- a/libavcodec/jpeg2000.c +++ b/libavcodec/jpeg2000.c @@ -29,6 +29,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/imgutils.h" +#include "libavutil/intfloat.h" #include "libavutil/mem.h" #include "libavutil/thread.h" #include "avcodec.h" @@ -260,9 +261,7 @@ static void init_band_stepsize(AVCodecContext *avctx, band->f_stepsize *= F_LFTG_X * F_LFTG_X * 4; break; } - if (codsty->transform == FF_DWT97) { - band->f_stepsize *= pow(F_LFTG_K, 2*(codsty->nreslevels2decode - reslevelno) + lband - 2); - } + band->f_stepsize *= pow(F_LFTG_K, 2*(codsty->nreslevels2decode - reslevelno) + lband - 2); } if (band->f_stepsize > (INT_MAX >> 15)) { @@ -270,12 +269,7 @@ static void init_band_stepsize(AVCodecContext *avctx, av_log(avctx, AV_LOG_ERROR, "stepsize out of range\n"); } - band->i_stepsize = band->f_stepsize * (1 << 15); - - /* FIXME: In OpenJPEG code stepsize = stepsize * 0.5. Why? - * If not set output of entropic decoder is not correct. */ - if (!av_codec_is_encoder(avctx->codec)) - band->f_stepsize *= 0.5; + band->i_stepsize = (int)floorf(band->f_stepsize * (1 << 15)); } static int init_prec(AVCodecContext *avctx, diff --git a/libavcodec/jpeg2000_parser.c b/libavcodec/jpeg2000_parser.c index e96efc28e..a5dcc9c9f 100644 --- a/libavcodec/jpeg2000_parser.c +++ b/libavcodec/jpeg2000_parser.c @@ -25,6 +25,7 @@ */ #include "parser.h" +#include "parser_internal.h" /* Whether frame is jp2 file or codestream */ @@ -211,9 +212,9 @@ static int jpeg2000_parse(AVCodecParserContext *s, return next; } -const AVCodecParser ff_jpeg2000_parser = { - .codec_ids = { AV_CODEC_ID_JPEG2000 }, +const FFCodecParser ff_jpeg2000_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_JPEG2000), .priv_data_size = sizeof(JPEG2000ParserContext), - .parser_parse = jpeg2000_parse, - .parser_close = ff_parse_close, + .parse = jpeg2000_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 5a25079da..61ea7e7fa 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -563,9 +563,13 @@ static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) /* set integer 9/7 DWT in case of BITEXACT flag */ if ((s->avctx->flags & AV_CODEC_FLAG_BITEXACT) && (c->transform == FF_DWT97)) c->transform = FF_DWT97_INT; +#if FF_API_CODEC_PROPS else if (c->transform == FF_DWT53) { +FF_DISABLE_DEPRECATION_WARNINGS s->avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; +FF_ENABLE_DEPRECATION_WARNINGS } +#endif if (c->csty & JPEG2000_CSTY_PREC) { int i; @@ -1379,7 +1383,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, } bits_to_read = (uint8_t) (bits_to_read + cblk->lblock); segment_bytes = get_bits(s, bits_to_read); - // Write length information for HT Refinment segment + // Write length information for HT Refinement segment cblk->pass_lengths[1] += segment_bytes; } else if (!(cblk->modes & (JPEG2000_CBLK_TERMALL | JPEG2000_CBLK_BYPASS))) { // Common case for non-HT code-blocks; we have only one segment @@ -1472,7 +1476,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, } if (tmp_length > cblk->data_allocated) { avpriv_request_sample(s->avctx, - "Block with lengthinc greater than %"SIZE_SPECIFIER"", + "Block with lengthinc greater than %zu", cblk->data_allocated); return AVERROR_PATCHWELCOME; } @@ -1539,6 +1543,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, } } av_freep(&cblk->lengthinc); + cblk->nb_lengthinc = 0; } } // Save state of stream @@ -1895,7 +1900,7 @@ static void decode_sigpass(Jpeg2000T1Context *t1, int width, int height, int bpno, int bandno, int vert_causal_ctx_csty_symbol) { - int mask = 3 << (bpno - 1), y0, x, y; + int mask = (3u << bpno)>>1, y0, x, y; for (y0 = 0; y0 < height; y0 += 4) for (x = 0; x < width; x++) @@ -1907,14 +1912,15 @@ static void decode_sigpass(Jpeg2000T1Context *t1, int width, int height, && !(t1->flags[(y+1) * t1->stride + x+1] & (JPEG2000_T1_SIG | JPEG2000_T1_VIS))) { if (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ff_jpeg2000_getsigctxno(t1->flags[(y+1) * t1->stride + x+1] & flags_mask, bandno))) { int xorbit, ctxno = ff_jpeg2000_getsgnctxno(t1->flags[(y+1) * t1->stride + x+1] & flags_mask, &xorbit); - if (t1->mqc.raw) - t1->data[(y) * t1->stride + x] = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ? -mask : mask; - else - t1->data[(y) * t1->stride + x] = (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ^ xorbit) ? - -mask : mask; - + if (t1->mqc.raw) { + t1->data[(y) * t1->stride + x] |= (uint32_t)(ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno)) << 31; + t1->data[(y) * t1->stride + x] |= mask; + } else { + t1->data[(y) * t1->stride + x] |= (uint32_t)(ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ^ xorbit) << 31; + t1->data[(y) * t1->stride + x] |= mask; + } ff_jpeg2000_set_significance(t1, x, y, - t1->data[(y) * t1->stride + x] < 0); + t1->data[(y) * t1->stride + x] & INT32_MIN); } t1->flags[(y + 1) * t1->stride + x + 1] |= JPEG2000_T1_VIS; } @@ -1924,11 +1930,10 @@ static void decode_sigpass(Jpeg2000T1Context *t1, int width, int height, static void decode_refpass(Jpeg2000T1Context *t1, int width, int height, int bpno, int vert_causal_ctx_csty_symbol) { - int phalf, nhalf; + int phalf; int y0, x, y; - phalf = 1 << (bpno - 1); - nhalf = -phalf; + phalf = 1 << bpno; for (y0 = 0; y0 < height; y0 += 4) for (x = 0; x < width; x++) @@ -1937,10 +1942,13 @@ static void decode_refpass(Jpeg2000T1Context *t1, int width, int height, int flags_mask = (vert_causal_ctx_csty_symbol && y == y0 + 3) ? ~(JPEG2000_T1_SIG_S | JPEG2000_T1_SIG_SW | JPEG2000_T1_SIG_SE | JPEG2000_T1_SGN_S) : -1; int ctxno = ff_jpeg2000_getrefctxno(t1->flags[(y + 1) * t1->stride + x + 1] & flags_mask); - int r = ff_mqc_decode(&t1->mqc, - t1->mqc.cx_states + ctxno) - ? phalf : nhalf; - t1->data[(y) * t1->stride + x] += t1->data[(y) * t1->stride + x] < 0 ? -r : r; + t1->data[(y) * t1->stride + x] |= phalf >> 1; + if (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno)) + t1->data[(y) * t1->stride + x] |= phalf; + else { + t1->data[(y) * t1->stride + x] &= ~(phalf); + + } t1->flags[(y + 1) * t1->stride + x + 1] |= JPEG2000_T1_REF; } } @@ -1988,11 +1996,9 @@ static void decode_clnpass(const Jpeg2000DecoderContext *s, Jpeg2000T1Context *t int xorbit; int ctxno = ff_jpeg2000_getsgnctxno(t1->flags[(y + 1) * t1->stride + x + 1] & flags_mask, &xorbit); - t1->data[(y) * t1->stride + x] = (ff_mqc_decode(&t1->mqc, - t1->mqc.cx_states + ctxno) ^ - xorbit) - ? -mask : mask; - ff_jpeg2000_set_significance(t1, x, y, t1->data[(y) * t1->stride + x] < 0); + t1->data[(y) * t1->stride + x] |= (uint32_t)(ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ^ xorbit) << 31; + t1->data[(y) * t1->stride + x] |= mask; + ff_jpeg2000_set_significance(t1, x, y, t1->data[(y) * t1->stride + x] & INT32_MIN); } dec = 0; t1->flags[(y + 1) * t1->stride + x + 1] &= ~JPEG2000_T1_VIS; @@ -2013,9 +2019,9 @@ static void decode_clnpass(const Jpeg2000DecoderContext *s, Jpeg2000T1Context *t static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, - int width, int height, int bandpos, uint8_t roi_shift) + int width, int height, int bandpos, uint8_t roi_shift, const int M_b) { - int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1; + int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1 + 31 - M_b - 1 - roi_shift; int pass_cnt = 0; int vert_causal_ctx_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_VSC; int term_cnt = 0; @@ -2037,7 +2043,7 @@ static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *cod ff_mqc_initdec(&t1->mqc, cblk->data, 0, 1); while (passno--) { - if (bpno < 0 || bpno > 29) { + if (bpno < -1 || bpno > 29) { av_log(s->avctx, AV_LOG_ERROR, "bpno (%d) became invalid\n", bpno); return AVERROR_INVALIDDATA; } @@ -2065,7 +2071,7 @@ static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *cod return AVERROR_INVALIDDATA; } if (FFABS(cblk->data + cblk->data_start[term_cnt + 1] - 2 - t1->mqc.bp) > 0) { - av_log(s->avctx, AV_LOG_WARNING, "Mid mismatch %"PTRDIFF_SPECIFIER" in pass %d of %d\n", + av_log(s->avctx, AV_LOG_WARNING, "Mid mismatch %td in pass %d of %d\n", cblk->data + cblk->data_start[term_cnt + 1] - 2 - t1->mqc.bp, pass_cnt, cblk->npasses); } @@ -2082,7 +2088,7 @@ static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *cod } if (cblk->data + cblk->length - 2 > t1->mqc.bp) { - av_log(s->avctx, AV_LOG_WARNING, "End mismatch %"PTRDIFF_SPECIFIER"\n", + av_log(s->avctx, AV_LOG_WARNING, "End mismatch %td\n", cblk->data + cblk->length - 2 - t1->mqc.bp); } @@ -2090,22 +2096,25 @@ static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *cod av_log(s->avctx, AV_LOG_WARNING, "Synthetic End of Stream Marker Read.\n"); } + /* Reconstruct the sample values */ + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int32_t sign, n, val; + const uint32_t mask = (int64_t)UINT32_MAX >> (M_b + 1); // bit mask for ROI detection + + n = x + (y * t1->stride); + val = t1->data[n]; + sign = val & INT32_MIN; + val &= INT32_MAX; + /* ROI shift, if necessary */ + if (roi_shift && (((uint32_t)val & ~mask) == 0)) + val <<= roi_shift; + t1->data[n] = val | sign; /* NOTE: Binary point for reconstruction value is located in 31 - M_b */ + } + } return 1; } -static inline int roi_shift_param(Jpeg2000Component *comp, - int quan_parameter) -{ - uint8_t roi_shift; - int val; - roi_shift = comp->roi_shift; - val = (quan_parameter < 0)?-quan_parameter:quan_parameter; - - if (val > (1 << roi_shift)) - return (quan_parameter < 0)?-(val >> roi_shift):(val >> roi_shift); - return quan_parameter; -} - /* TODO: Verify dequantization for lossless case * comp->data can be float or int * band->stepsize can be float or int @@ -2115,50 +2124,86 @@ static inline int roi_shift_param(Jpeg2000Component *comp, /* Float dequantization of a codeblock.*/ static void dequantization_float(int x, int y, Jpeg2000Cblk *cblk, Jpeg2000Component *comp, - Jpeg2000T1Context *t1, Jpeg2000Band *band) + Jpeg2000T1Context *t1, Jpeg2000Band *band, const int M_b) { int i, j; int w = cblk->coord[0][1] - cblk->coord[0][0]; + const int downshift = 31 - M_b; + float fscale = band->f_stepsize; + fscale /= (float)(1LL << downshift); for (j = 0; j < (cblk->coord[1][1] - cblk->coord[1][0]); ++j) { float *datap = &comp->f_data[(comp->coord[0][1] - comp->coord[0][0]) * (y + j) + x]; int *src = t1->data + j*t1->stride; - for (i = 0; i < w; ++i) - datap[i] = src[i] * band->f_stepsize; + for (i = 0; i < w; ++i) { + int val = src[i]; + if (val < 0) // Convert sign-magnitude to two's complement + val = -(val & INT32_MAX); + datap[i] = (float)val * fscale; + } } } /* Integer dequantization of a codeblock.*/ static void dequantization_int(int x, int y, Jpeg2000Cblk *cblk, Jpeg2000Component *comp, - Jpeg2000T1Context *t1, Jpeg2000Band *band) + Jpeg2000T1Context *t1, Jpeg2000Band *band, const int M_b) { int i, j; + const int downshift = FFMIN(31 - M_b, 31); int w = cblk->coord[0][1] - cblk->coord[0][0]; for (j = 0; j < (cblk->coord[1][1] - cblk->coord[1][0]); ++j) { int32_t *datap = &comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * (y + j) + x]; int *src = t1->data + j*t1->stride; if (band->i_stepsize == 32768) { - for (i = 0; i < w; ++i) - datap[i] = src[i] / 2; + for (i = 0; i < w; ++i) { + int val = src[i]; + if (val < 0) // Convert sign-magnitude to two's complement + val = -((val & INT32_MAX) >> downshift); + else + val >>= downshift; + datap[i] = val; + } } else { // This should be VERY uncommon - for (i = 0; i < w; ++i) - datap[i] = (src[i] * (int64_t)band->i_stepsize) / 65536; + for (i = 0; i < w; ++i) { + int val = src[i]; + if (val < 0) // Convert sign-magnitude to two's complement + val = -((val & INT32_MAX) >> downshift); + else + val >>= downshift; + datap[i] = (val * (int64_t)band->i_stepsize) / 65536; + } } } } static void dequantization_int_97(int x, int y, Jpeg2000Cblk *cblk, Jpeg2000Component *comp, - Jpeg2000T1Context *t1, Jpeg2000Band *band) + Jpeg2000T1Context *t1, Jpeg2000Band *band, const int M_b) { int i, j; int w = cblk->coord[0][1] - cblk->coord[0][0]; + float fscale = band->f_stepsize; + const int downshift = 31 - M_b; + const int PRESCALE = 6; // At least 6 is required to pass the conformance tests in ISO/IEC 15444-4 + int scale; + + fscale /= (float)(1LL << downshift); + fscale *= (float)(1 << PRESCALE); + fscale *= (float)(1 << (16 + I_PRESHIFT)); + scale = (int)(fscale + 0.5); + band->i_stepsize = scale; for (j = 0; j < (cblk->coord[1][1] - cblk->coord[1][0]); ++j) { int32_t *datap = &comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * (y + j) + x]; int *src = t1->data + j*t1->stride; - for (i = 0; i < w; ++i) - datap[i] = (src[i] * (int64_t)band->i_stepsize + (1<<15)) >> 16; + for (i = 0; i < w; ++i) { + int val = src[i]; + if (val < 0) // Convert sign-magnitude to two's complement + val = -(val & INT32_MAX); + // Shifting down to prevent overflow in dequantization + val = (val + (1LL << (PRESCALE - 1))) >> PRESCALE; + datap[i] = RSHIFT(val * (int64_t)band->i_stepsize, 16); + } } } @@ -2190,18 +2235,6 @@ static inline void mct_decode(const Jpeg2000DecoderContext *s, Jpeg2000Tile *til s->dsp.mct_decode[tile->codsty[0].transform](src[0], src[1], src[2], csize); } -static inline void roi_scale_cblk(Jpeg2000Cblk *cblk, - Jpeg2000Component *comp, - Jpeg2000T1Context *t1) -{ - int i, j; - int w = cblk->coord[0][1] - cblk->coord[0][0]; - for (j = 0; j < (cblk->coord[1][1] - cblk->coord[1][0]); ++j) { - int *src = t1->data + j*t1->stride; - for (i = 0; i < w; ++i) - src[i] = roi_shift_param(comp, src[i]); - } -} static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile *tile) { @@ -2264,7 +2297,7 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile ret = decode_cblk(s, codsty, &t1, cblk, cblk->coord[0][1] - cblk->coord[0][0], cblk->coord[1][1] - cblk->coord[1][0], - bandpos, comp->roi_shift); + bandpos, comp->roi_shift, M_b); if (ret) coded = 1; @@ -2273,14 +2306,12 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile x = cblk->coord[0][0] - band->coord[0][0]; y = cblk->coord[1][0] - band->coord[1][0]; - if (comp->roi_shift) - roi_scale_cblk(cblk, comp, &t1); if (codsty->transform == FF_DWT97) - dequantization_float(x, y, cblk, comp, &t1, band); + dequantization_float(x, y, cblk, comp, &t1, band, M_b); else if (codsty->transform == FF_DWT97_INT) - dequantization_int_97(x, y, cblk, comp, &t1, band); + dequantization_int_97(x, y, cblk, comp, &t1, band, M_b); else - dequantization_int(x, y, cblk, comp, &t1, band); + dequantization_int(x, y, cblk, comp, &t1, band, M_b); } /* end cblk */ } /*end prec */ } /* end band */ @@ -2427,6 +2458,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) Jpeg2000QuantStyle *qntsty = s->qntsty; Jpeg2000POC *poc = &s->poc; uint8_t *properties = s->properties; + uint8_t in_tile_headers = 0; for (;;) { int len, ret = 0; @@ -2509,7 +2541,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_cap(s, codsty); break; case JPEG2000_COC: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "COC marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2517,7 +2549,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_coc(s, codsty, properties); break; case JPEG2000_COD: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "COD marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2525,7 +2557,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_cod(s, codsty, properties); break; case JPEG2000_RGN: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "RGN marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2537,7 +2569,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) } break; case JPEG2000_QCC: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "QCC marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2545,7 +2577,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_qcc(s, len, qntsty, properties); break; case JPEG2000_QCD: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "QCD marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2553,7 +2585,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_qcd(s, len, qntsty, properties); break; case JPEG2000_POC: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "POC marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2561,8 +2593,8 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_poc(s, len, poc); break; case JPEG2000_SOT: - if (!s->in_tile_headers) { - s->in_tile_headers = 1; + if (!in_tile_headers) { + in_tile_headers = 1; if (s->has_ppm) { bytestream2_init(&s->packed_headers_stream, s->packed_headers, s->packed_headers_size); } @@ -2594,7 +2626,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) break; case JPEG2000_PPM: // Packed headers, main header - if (s->in_tile_headers) { + if (in_tile_headers) { av_log(s->avctx, AV_LOG_ERROR, "PPM Marker can only be in Main header\n"); return AVERROR_INVALIDDATA; } @@ -2752,7 +2784,7 @@ static int jp2_find_codestream(Jpeg2000DecoderContext *s) int n = bytestream2_get_be16u(&s->g); for (; n>0; n--) { int cn = bytestream2_get_be16(&s->g); - int av_unused typ = bytestream2_get_be16(&s->g); + av_unused int typ = bytestream2_get_be16(&s->g); int asoc = bytestream2_get_be16(&s->g); if (cn < 4 && asoc < 4) s->cdef[cn] = asoc; @@ -2807,7 +2839,7 @@ static av_cold int jpeg2000_decode_init(AVCodecContext *avctx) Jpeg2000DecoderContext *s = avctx->priv_data; if (avctx->lowres) - av_log(avctx, AV_LOG_WARNING, "lowres is overriden by reduction_factor but set anyway\n"); + av_log(avctx, AV_LOG_WARNING, "lowres is overridden by reduction_factor but set anyway\n"); if (!s->reduction_factor && avctx->lowres < JPEG2000_MAX_RESLEVELS) { s->reduction_factor = avctx->lowres; } @@ -2878,6 +2910,10 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, AVFrame *picture, if (ret = jpeg2000_read_bitstream_packets(s)) goto end; + for (int x = 0; x < s->ncomponents && s->codsty[x].transform == FF_DWT53;) + if (++x == s->ncomponents) + picture->flags |= AV_FRAME_FLAG_LOSSLESS; + avctx->execute2(avctx, jpeg2000_decode_tile, picture, NULL, s->numXtiles * s->numYtiles); jpeg2000_dec_cleanup(s); diff --git a/libavcodec/jpeg2000dec.h b/libavcodec/jpeg2000dec.h index 78eba27ed..fce382316 100644 --- a/libavcodec/jpeg2000dec.h +++ b/libavcodec/jpeg2000dec.h @@ -86,7 +86,6 @@ typedef struct Jpeg2000DecoderContext { uint8_t *packed_headers; // contains packed headers. Used only along with PPM marker int packed_headers_size; GetByteContext packed_headers_stream; - uint8_t in_tile_headers; int cdx[4], cdy[4]; int precision; diff --git a/libavcodec/jpeg2000dsp.c b/libavcodec/jpeg2000dsp.c index 7840fdc35..2931a38ef 100644 --- a/libavcodec/jpeg2000dsp.c +++ b/libavcodec/jpeg2000dsp.c @@ -98,7 +98,7 @@ av_cold void ff_jpeg2000dsp_init(Jpeg2000DSPContext *c) #if ARCH_RISCV ff_jpeg2000dsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_jpeg2000dsp_init_x86(c); #endif } diff --git a/libavcodec/jpeg2000dwt.c b/libavcodec/jpeg2000dwt.c index 34e33553f..9ee812265 100644 --- a/libavcodec/jpeg2000dwt.c +++ b/libavcodec/jpeg2000dwt.c @@ -39,13 +39,12 @@ /* Lifting parameters in integer format. * Computed as param = (float param) * (1 << 16) */ -#define I_LFTG_ALPHA 103949ll -#define I_LFTG_BETA 3472ll -#define I_LFTG_GAMMA 57862ll -#define I_LFTG_DELTA 29066ll -#define I_LFTG_K 80621ll -#define I_LFTG_X 53274ll -#define I_PRESHIFT 8 +#define I_LFTG_ALPHA_PRIME 38413ll // = 103949 - 65536, (= alpha - 1.0) +#define I_LFTG_BETA 3472ll +#define I_LFTG_GAMMA 57862ll +#define I_LFTG_DELTA 29066ll +#define I_LFTG_K 80621ll +#define I_LFTG_X 53274ll static inline void extend53(int *p, int i0, int i1) { @@ -234,8 +233,11 @@ static void sd_1d97_int(int *p, int i0, int i1) extend97_int(p, i0, i1); i0++; i1++; - for (i = (i0>>1) - 2; i < (i1>>1) + 1; i++) - p[2 * i + 1] -= (I_LFTG_ALPHA * (p[2 * i] + p[2 * i + 2]) + (1 << 15)) >> 16; + for (i = (i0>>1) - 2; i < (i1>>1) + 1; i++) { + const int64_t sum = p[2 * i] + p[2 * i + 2]; + p[2 * i + 1] -= sum; + p[2 * i + 1] -= (I_LFTG_ALPHA_PRIME * sum + (1 << 15)) >> 16; + } for (i = (i0>>1) - 1; i < (i1>>1) + 1; i++) p[2 * i] -= (I_LFTG_BETA * (p[2 * i - 1] + p[2 * i + 1]) + (1 << 15)) >> 16; for (i = (i0>>1) - 1; i < (i1>>1); i++) @@ -276,7 +278,7 @@ static void dwt_encode97_int(DWTContext *s, int *t) // copy back and deinterleave for (i = mv; i < lv; i+=2, j++) - t[w*j + lp] = ((l[i] * I_LFTG_X) + (1 << 15)) >> 16; + t[w*j + lp] = l[i]; for (i = 1-mv; i < lv; i+=2, j++) t[w*j + lp] = l[i]; } @@ -293,7 +295,7 @@ static void dwt_encode97_int(DWTContext *s, int *t) // copy back and deinterleave for (i = mh; i < lh; i+=2, j++) - t[w*lp + j] = ((l[i] * I_LFTG_X) + (1 << 15)) >> 16; + t[w*lp + j] = l[i]; for (i = 1-mh; i < lh; i+=2, j++) t[w*lp + j] = l[i]; } @@ -301,7 +303,7 @@ static void dwt_encode97_int(DWTContext *s, int *t) } for (i = 0; i < w * h; i++) - t[i] = (t[i] + ((1<>1)) >> I_PRESHIFT; + t[i] = (t[i] + ((1<<(I_PRESHIFT))>>1)) >> (I_PRESHIFT); } static void sr_1d53(unsigned *p, int i0, int i1) @@ -471,8 +473,11 @@ static void sr_1d97_int(int32_t *p, int i0, int i1) for (i = (i0 >> 1); i < (i1 >> 1) + 1; i++) p[2 * i] += (I_LFTG_BETA * (p[2 * i - 1] + (int64_t)p[2 * i + 1]) + (1 << 15)) >> 16; /* step 6 */ - for (i = (i0 >> 1); i < (i1 >> 1); i++) - p[2 * i + 1] += (I_LFTG_ALPHA * (p[2 * i] + (int64_t)p[2 * i + 2]) + (1 << 15)) >> 16; + for (i = (i0 >> 1); i < (i1 >> 1); i++) { + const int64_t sum = p[2 * i] + (int64_t) p[2 * i + 2]; + p[2 * i + 1] += sum; + p[2 * i + 1] += (I_LFTG_ALPHA_PRIME * sum + (1 << 15)) >> 16; + } } static void dwt_decode97_int(DWTContext *s, int32_t *t) @@ -486,9 +491,6 @@ static void dwt_decode97_int(DWTContext *s, int32_t *t) /* position at index O of line range [0-5,w+5] cf. extend function */ line += 5; - for (i = 0; i < w * h; i++) - data[i] *= 1LL << I_PRESHIFT; - for (lev = 0; lev < s->ndeclevels; lev++) { int lh = s->linelen[lev][0], lv = s->linelen[lev][1], @@ -500,9 +502,9 @@ static void dwt_decode97_int(DWTContext *s, int32_t *t) l = line + mh; for (lp = 0; lp < lv; lp++) { int i, j = 0; - // rescale with interleaving + // interleaving for (i = mh; i < lh; i += 2, j++) - l[i] = ((data[w * lp + j] * I_LFTG_K) + (1 << 15)) >> 16; + l[i] = data[w * lp + j]; for (i = 1 - mh; i < lh; i += 2, j++) l[i] = data[w * lp + j]; @@ -516,9 +518,9 @@ static void dwt_decode97_int(DWTContext *s, int32_t *t) l = line + mv; for (lp = 0; lp < lh; lp++) { int i, j = 0; - // rescale with interleaving + // interleaving for (i = mv; i < lv; i += 2, j++) - l[i] = ((data[w * j + lp] * I_LFTG_K) + (1 << 15)) >> 16; + l[i] = data[w * j + lp]; for (i = 1 - mv; i < lv; i += 2, j++) l[i] = data[w * j + lp]; @@ -530,7 +532,8 @@ static void dwt_decode97_int(DWTContext *s, int32_t *t) } for (i = 0; i < w * h; i++) - data[i] = (data[i] + ((1LL<>1)) >> I_PRESHIFT; + // We shift down by `I_PRESHIFT` because the input coefficients `datap[]` were shifted up by `I_PRESHIFT` to secure the precision + data[i] = (int32_t)(data[i] + ((1LL<<(I_PRESHIFT))>>1)) >> (I_PRESHIFT); } int ff_jpeg2000_dwt_init(DWTContext *s, int border[2][2], diff --git a/libavcodec/jpeg2000dwt.h b/libavcodec/jpeg2000dwt.h index 718d183ac..62f0548ac 100644 --- a/libavcodec/jpeg2000dwt.h +++ b/libavcodec/jpeg2000dwt.h @@ -32,6 +32,7 @@ #define FF_DWT_MAX_DECLVLS 32 ///< max number of decomposition levels #define F_LFTG_K 1.230174104914001f #define F_LFTG_X 0.812893066115961f +#define I_PRESHIFT 8 enum DWTType { FF_DWT97, diff --git a/libavcodec/jpeg2000htdec.c b/libavcodec/jpeg2000htdec.c index 8cedc4146..9fc269306 100644 --- a/libavcodec/jpeg2000htdec.c +++ b/libavcodec/jpeg2000htdec.c @@ -1070,7 +1070,7 @@ static void jpeg2000_process_stripes_block(StateVars *sig_prop, int i_s, int j_s uint8_t *state_p = block_states + (i + 1) * stride + (j + 1); if ((state_p[0] >> HT_SHIFT_REF) & 1) { bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length); - *sp |= (int32_t)bit << 31; + *sp |= (uint32_t)bit << 31; } } } @@ -1160,7 +1160,7 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states); bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length); tmp = 0xFFFFFFFE | (uint32_t)bit; - tmp <<= pLSB; + tmp = (uint32_t)tmp << pLSB; sp[0] &= tmp; sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2) } @@ -1176,7 +1176,7 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states); bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length); tmp = 0xFFFFFFFE | (uint32_t)bit; - tmp <<= pLSB; + tmp = (uint32_t)tmp << pLSB; sp[0] &= tmp; sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2) } @@ -1219,7 +1219,7 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c uint8_t *block_states = NULL; int32_t n, val; // Post-processing - const uint32_t mask = (UINT32_MAX >> M_b) >> 1; // bit mask for ROI detection + const uint32_t mask = (int64_t)UINT32_MAX >> (M_b + 1); // bit mask for ROI detection uint8_t num_rempass; @@ -1324,8 +1324,6 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c jpeg2000_decode_magref_segment(width, height, quad_buf_width, Dref, Lref, pLSB - 1, sample_buf, block_states); - pLSB = 31 - M_b; - /* Reconstruct the sample values */ for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { @@ -1338,12 +1336,7 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c /* ROI shift, if necessary */ if (roi_shift && (((uint32_t)val & ~mask) == 0)) val <<= roi_shift; - /* Convert sign-magnitude to two's complement. */ - if (sign) - val = -val; - /* Shift down to 1 bit upper from decimal point for reconstruction value (= 0.5) */ - val >>= (pLSB - 1); - t1->data[n] = val; + t1->data[n] = val | sign; /* NOTE: Binary point for reconstruction value is located in 31 - M_b */ } } free: diff --git a/libavcodec/jpegls.c b/libavcodec/jpegls.c index 7b4bc30e4..ab8076368 100644 --- a/libavcodec/jpegls.c +++ b/libavcodec/jpegls.c @@ -49,6 +49,10 @@ void ff_jpegls_init_state(JLSState *state) state->A[i] = FFMAX(state->range + 32 >> 6, 2); state->N[i] = 1; } + + memset(state->B, 0, sizeof(state->B)); + memset(state->C, 0, sizeof(state->C)); + memset(state->run_index, 0, sizeof(state->run_index)); } /** diff --git a/libavcodec/jpeglsdec.c b/libavcodec/jpeglsdec.c index 5f463c966..4b07f1f8d 100644 --- a/libavcodec/jpeglsdec.c +++ b/libavcodec/jpeglsdec.c @@ -53,19 +53,19 @@ int ff_jpegls_decode_lse(MJpegDecodeContext *s) int id; int tid, wt, maxtab, i, j; - int len = get_bits(&s->gb, 16); - id = get_bits(&s->gb, 8); + int len = bytestream2_get_be16(&s->gB); + id = bytestream2_get_byte(&s->gB); switch (id) { case 1: if (len < 13) return AVERROR_INVALIDDATA; - s->maxval = get_bits(&s->gb, 16); - s->t1 = get_bits(&s->gb, 16); - s->t2 = get_bits(&s->gb, 16); - s->t3 = get_bits(&s->gb, 16); - s->reset = get_bits(&s->gb, 16); + s->maxval = bytestream2_get_be16u(&s->gB); + s->t1 = bytestream2_get_be16u(&s->gB); + s->t2 = bytestream2_get_be16u(&s->gB); + s->t3 = bytestream2_get_be16u(&s->gB); + s->reset = bytestream2_get_be16u(&s->gB); if (s->avctx->debug & FF_DEBUG_PICT_INFO) { av_log(s->avctx, AV_LOG_DEBUG, "Coding parameters maxval:%d T1:%d T2:%d T3:%d reset:%d\n", @@ -78,8 +78,8 @@ int ff_jpegls_decode_lse(MJpegDecodeContext *s) case 2: s->palette_index = 0; case 3: - tid= get_bits(&s->gb, 8); - wt = get_bits(&s->gb, 8); + tid= bytestream2_get_byte(&s->gB); + wt = bytestream2_get_byte(&s->gB); if (len < 5) return AVERROR_INVALIDDATA; @@ -129,7 +129,7 @@ int ff_jpegls_decode_lse(MJpegDecodeContext *s) uint8_t k = i << shift; pal[k] = wt < 4 ? 0xFF000000 : 0; for (j=0; jgb, 8) << (8*(wt-j-1)); + pal[k] |= bytestream2_get_byte(&s->gB) << (8*(wt-j-1)); } } s->palette_index = i; @@ -352,9 +352,11 @@ static inline int ls_decode_line(JLSState *state, MJpegDecodeContext *s, return 0; } -int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, - int point_transform, int ilv) +int ff_jpegls_decode_picture(MJpegDecodeContext *s) { + int near = s->Ss; + int point_transform = s->Al; + int ilv = s->Se; int i, t = 0; uint8_t *zero, *last, *cur; JLSState *state = s->jls_state; @@ -374,7 +376,6 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, cur = s->picture_ptr->data[0]; /* initialize JPEG-LS state from JPEG parameters */ - memset(state, 0, sizeof(*state)); state->near = near; state->bpp = (s->bits < 2) ? 2 : s->bits; state->maxval = s->maxval; @@ -396,8 +397,6 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, goto end; } - ff_jpegls_init_state(state); - if (s->bits <= 8) shift = point_transform + (8 - s->bits); else @@ -418,10 +417,9 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, av_log(s->avctx, AV_LOG_DEBUG, "JPEG params: ILV=%i Pt=%i BPP=%i, scan = %i\n", ilv, point_transform, s->bits, s->cur_scan); } - if (get_bits_left(&s->gb) < s->height) { - ret = AVERROR_INVALIDDATA; - goto end; - } + + s->restart_count = -1; + if (ilv == 0) { /* separate planes */ if (s->cur_scan > s->nb_components) { ret = AVERROR_INVALIDDATA; @@ -432,7 +430,15 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, width = s->width * stride; cur += off; for (i = 0; i < s->height; i++) { - int ret; + int restart; + ret = ff_mjpeg_handle_restart(s, &restart); + if (ret < 0) + goto end; + if (restart) { + ff_jpegls_init_state(state); + t = 0; + last = zero; + } if (s->bits <= 8) { ret = ls_decode_line(state, s, last, cur, t, width, stride, off, 8); t = last[0]; @@ -444,11 +450,6 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, break; last = cur; cur += s->picture_ptr->linesize[0]; - - if (s->restart_interval && !--s->restart_count) { - align_get_bits(&s->gb); - skip_bits(&s->gb, 16); /* skip RSTn */ - } } decoded_height = i; } else if (ilv == 1) { /* line interleaving */ @@ -458,18 +459,21 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, memset(cur, 0, s->picture_ptr->linesize[0]); width = s->width * stride; for (i = 0; i < s->height; i++) { - int ret; + int restart; + ret = ff_mjpeg_handle_restart(s, &restart); + if (ret < 0) + goto end; + if (restart) { + ff_jpegls_init_state(state); + memset(Rc, 0, sizeof(Rc)); + last = zero; + } for (j = 0; j < stride; j++) { ret = ls_decode_line(state, s, last + j, cur + j, Rc[j], width, stride, j, 8); if (ret < 0) break; Rc[j] = last[j]; - - if (s->restart_interval && !--s->restart_count) { - align_get_bits(&s->gb); - skip_bits(&s->gb, 16); /* skip RSTn */ - } } if (ret < 0) break; diff --git a/libavcodec/jpeglsdec.h b/libavcodec/jpeglsdec.h index 0cafaba7a..0b5ee2d48 100644 --- a/libavcodec/jpeglsdec.h +++ b/libavcodec/jpeglsdec.h @@ -36,7 +36,6 @@ */ int ff_jpegls_decode_lse(MJpegDecodeContext *s); -int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, - int point_transform, int ilv); +int ff_jpegls_decode_picture(MJpegDecodeContext *s); #endif /* AVCODEC_JPEGLSDEC_H */ diff --git a/libavcodec/jpeglsenc.c b/libavcodec/jpeglsenc.c index d2f4a52f2..64440de24 100644 --- a/libavcodec/jpeglsenc.c +++ b/libavcodec/jpeglsenc.c @@ -373,7 +373,7 @@ static int encode_picture_ls(AVCodecContext *avctx, AVPacket *pkt, /* write our own JPEG header, can't use mjpeg_picture_header */ put_marker_byteu(&pb, SOI); - put_marker_byteu(&pb, SOF48); + put_marker_byteu(&pb, SOF55); bytestream2_put_be16u(&pb, 8 + comps * 3); // header size depends on components bytestream2_put_byteu(&pb, (avctx->pix_fmt == AV_PIX_FMT_GRAY16) ? 16 : 8); // bpp bytestream2_put_be16u(&pb, avctx->height); @@ -484,10 +484,7 @@ const FFCodec ff_jpegls_encoder = { .init = encode_jpegls_init, FF_CODEC_ENCODE_CB(encode_picture_ls), .close = encode_jpegls_close, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_BGR24, AV_PIX_FMT_RGB24, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24, AV_PIX_FMT_RGB24, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/jpegxl_parse.c b/libavcodec/jpegxl_parse.c index 7cfdd3e7d..47b831e2b 100644 --- a/libavcodec/jpegxl_parse.c +++ b/libavcodec/jpegxl_parse.c @@ -190,6 +190,7 @@ static void jpegxl_get_bit_depth(GetBitContext *gb, FFJXLMetadata *meta) static int jpegxl_read_extra_channel_info(GetBitContext *gb, FFJXLMetadata *meta, int validate) { int default_alpha = get_bits1(gb); + int alpha_associated = 0; uint32_t type, name_len = 0; if (!default_alpha) { @@ -213,7 +214,7 @@ static int jpegxl_read_extra_channel_info(GetBitContext *gb, FFJXLMetadata *meta skip_bits_long(gb, name_len); if (!default_alpha && type == JPEGXL_CT_ALPHA) - skip_bits1(gb); + alpha_associated = get_bits1(gb); if (type == JPEGXL_CT_SPOT_COLOR) skip_bits_long(gb, 16 * 4); @@ -221,8 +222,10 @@ static int jpegxl_read_extra_channel_info(GetBitContext *gb, FFJXLMetadata *meta if (type == JPEGXL_CT_CFA) jxl_u32(gb, 1, 0, 3, 19, 0, 2, 4, 8); - if (meta && type == JPEGXL_CT_ALPHA) + if (meta && type == JPEGXL_CT_ALPHA) { meta->have_alpha = 1; + meta->alpha_associated = alpha_associated; + } return 0; } @@ -450,7 +453,8 @@ int ff_jpegxl_collect_codestream_header(const uint8_t *input_buffer, int input_l uint8_t *buffer, int buflen, int *copied) { GetByteContext gb; - int pos = 0, last_box = 0; + int64_t pos = 0; + int last_box = 0; bytestream2_init(&gb, input_buffer, input_len); while (1) { @@ -516,5 +520,5 @@ int ff_jpegxl_collect_codestream_header(const uint8_t *input_buffer, int input_l break; } - return pos; + return FFMIN(pos, INT_MAX); } diff --git a/libavcodec/jpegxl_parse.h b/libavcodec/jpegxl_parse.h index 0602f4d40..bb929ccee 100644 --- a/libavcodec/jpegxl_parse.h +++ b/libavcodec/jpegxl_parse.h @@ -35,6 +35,7 @@ typedef struct FFJXLMetadata { uint32_t coded_height; int bit_depth; int have_alpha; + int alpha_associated; /* * offset, in bits, of the animation header * zero if not animated diff --git a/libavcodec/jpegxl_parser.c b/libavcodec/jpegxl_parser.c index a2591ffc0..a16a2733f 100644 --- a/libavcodec/jpegxl_parser.c +++ b/libavcodec/jpegxl_parser.c @@ -32,6 +32,7 @@ #include "bytestream.h" #include "codec_id.h" +#include "parser_internal.h" #define UNCHECKED_BITSTREAM_READER 0 #define BITSTREAM_READER_LE #include "get_bits.h" @@ -155,12 +156,12 @@ typedef struct JXLParseContext { /* using ISOBMFF-based container */ int container; - int skip; + int64_t skip; int copied; - int collected_size; - int codestream_length; + int64_t collected_size; + int64_t codestream_length; int skipped_icc; - int next; + int64_t next; uint8_t cs_buffer[4096 + AV_INPUT_BUFFER_PADDING_SIZE]; } JXLParseContext; @@ -1074,6 +1075,11 @@ static void populate_fields(AVCodecParserContext *s, AVCodecContext *avctx, cons else s->format = meta->have_alpha ? AV_PIX_FMT_RGBAF32 : AV_PIX_FMT_RGBF32; } + + if (meta->have_alpha) { + avctx->alpha_mode = meta->alpha_associated ? AVALPHA_MODE_PREMULTIPLIED + : AVALPHA_MODE_STRAIGHT; + } } static int skip_icc_profile(void *avctx, JXLParseContext *ctx, GetBitContext *gb) @@ -1403,7 +1409,7 @@ static int skip_boxes(JXLParseContext *ctx, const uint8_t *buf, int buf_size) return 0; } -static int try_parse(AVCodecParserContext *s, AVCodecContext *avctx, JXLParseContext *ctx, +static int64_t try_parse(AVCodecParserContext *s, AVCodecContext *avctx, JXLParseContext *ctx, const uint8_t *buf, int buf_size) { int ret, cs_buflen, header_skip; @@ -1496,10 +1502,10 @@ static int jpegxl_parse(AVCodecParserContext *s, AVCodecContext *avctx, } if ((!ctx->container || !ctx->codestream_length) && !ctx->next) { - ret = try_parse(s, avctx, ctx, pbuf, pindex); - if (ret < 0) + int64_t ret64 = try_parse(s, avctx, ctx, pbuf, pindex); + if (ret64 < 0) goto flush; - ctx->next = ret; + ctx->next = ret64; if (ctx->container) ctx->skip += ctx->next; } @@ -1540,9 +1546,9 @@ flush: return next; } -const AVCodecParser ff_jpegxl_parser = { - .codec_ids = { AV_CODEC_ID_JPEGXL }, +const FFCodecParser ff_jpegxl_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_JPEGXL, AV_CODEC_ID_JPEGXL_ANIM), .priv_data_size = sizeof(JXLParseContext), - .parser_parse = jpegxl_parse, - .parser_close = ff_parse_close, + .parse = jpegxl_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/jpegxs.h b/libavcodec/jpegxs.h new file mode 100644 index 000000000..951e2f0d6 --- /dev/null +++ b/libavcodec/jpegxs.h @@ -0,0 +1,37 @@ +/* + * 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_JPEGXS_H +#define AVCODEC_JPEGXS_H + +enum { + JPEGXS_MARKER_SOC = 0xff10, // Start of codestream + JPEGXS_MARKER_EOC = 0xff11, // End of codestream + JPEGXS_MARKER_PIH = 0xff12, // Picture header + JPEGXS_MARKER_CDT = 0xff13, // Component table + JPEGXS_MARKER_WGT = 0xff14, // Weights table + JPEGXS_MARKER_COM = 0xff15, // Extension marker + JPEGXS_MARKER_NLT = 0xff16, // Nonlinearity marker + JPEGXS_MARKER_CWD = 0xff17, // Component-dependent wavelet decomposition marker + JPEGXS_MARKER_CTS = 0xff18, // Colour transformation specification marker + JPEGXS_MARKER_CRG = 0xff19, // Component registration marker + JPEGXS_MARKER_SLH = 0xff20, // Slice header + JPEGXS_MARKER_CAP = 0xff50, // Capabilities Marker +}; + +#endif /* AVCODEC_JPEGXS_H */ diff --git a/libavcodec/jpegxs_parser.c b/libavcodec/jpegxs_parser.c new file mode 100644 index 000000000..a9750b0a0 --- /dev/null +++ b/libavcodec/jpegxs_parser.c @@ -0,0 +1,251 @@ +/* + * 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/mem.h" + +#include "bytestream.h" +#include "get_bits.h" +#include "jpegxs.h" +#include "parser.h" +#include "parser_internal.h" + +typedef struct JPEGXSParseContext { + ParseContext pc; + + int eoc_found; +} JPEGXSParseContext; + +/** + * Find the end of the current frame in the bitstream. + * @return the position of the first byte of the next frame, or -1 + */ +static int jpegxs_find_frame_end(JPEGXSParseContext *jpegxs, const uint8_t *buf, + int buf_size) +{ + ParseContext *pc = &jpegxs->pc; + int pic_found, i = 0; + uint32_t state; + + pic_found = pc->frame_start_found; + state = pc->state; + + if (!pic_found) { + for (i = 0; i < buf_size; i++) { + state = (state << 8) | buf[i]; + if ((uint16_t)state == JPEGXS_MARKER_SOC) { + i++; + pic_found = 1; + break; + } + } + } + + if (buf_size == 0) { + if (jpegxs->eoc_found) { + pc->frame_start_found = jpegxs->eoc_found = 0; + pc->state = -1; + } + return 0; + } + + while (pic_found && i < buf_size) { + if (jpegxs->eoc_found) { + for(; i < buf_size; i++) { + state = (state << 8) | buf[i]; + if ((state >> 16) == JPEGXS_MARKER_EOC) { + if ((uint16_t)state == JPEGXS_MARKER_SOC) { + // New image + pc->frame_start_found = jpegxs->eoc_found = 0; + pc->state = -1; + return i - 1; + } else { + // False positive + i++; + jpegxs->eoc_found = 0; + break; + } + } + } + } + + for(; i < buf_size; i++) { + state = (state << 8) | buf[i]; + if ((uint16_t)state == JPEGXS_MARKER_EOC) { + // EOC candidate + i++; + jpegxs->eoc_found = 1; + break; + } + } + } + + pc->frame_start_found = pic_found; + pc->state = state; + return END_NOT_FOUND; +} + +static int jpegxs_parse_frame(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t *buf, int buf_size) +{ + GetByteContext gbc; + GetBitContext gb; + int8_t bpc[3], log2_chroma_w[3], log2_chroma_h[3]; + int size, marker, components; + + s->key_frame = 1; + s->pict_type = AV_PICTURE_TYPE_I; + + if (buf_size < 4) + return 0; + + bytestream2_init(&gbc, buf, buf_size); + marker = bytestream2_get_be16(&gbc); + if (marker != JPEGXS_MARKER_SOC) + return 0; + + marker = bytestream2_get_be16(&gbc); + if (marker != JPEGXS_MARKER_CAP) + return 0; + size = bytestream2_get_be16(&gbc); + bytestream2_skip(&gbc, FFMAX(size - 2, 0)); + + marker = bytestream2_get_be16(&gbc); + if (marker != JPEGXS_MARKER_PIH) + return 0; + size = bytestream2_get_be16(&gbc); + bytestream2_skip(&gbc, 4); // Lcod + bytestream2_skip(&gbc, 2); // Ppih + bytestream2_skip(&gbc, 2); // Plev + size -= 8; + + s->width = bytestream2_get_be16(&gbc); + s->height = bytestream2_get_be16(&gbc); + size -= 4; + + bytestream2_skip(&gbc, 2); // Cw + bytestream2_skip(&gbc, 2); // Hsl + size -= 4; + + components = bytestream2_get_byte(&gbc); + if (components != 1 && components != 3) + return 0; + size--; + + bytestream2_skip(&gbc, FFMAX(size - 2, 0)); + + while (bytestream2_get_bytes_left(&gbc) > 0) { + marker = bytestream2_get_be16(&gbc); + + switch(marker) { + case JPEGXS_MARKER_CDT: + size = bytestream2_get_be16(&gbc); + init_get_bits8(&gb, gbc.buffer, FFMIN(FFMAX(size - 2, 0), bytestream2_get_bytes_left(&gbc))); + + for (int i = 0; i < components; i++) { + bpc[i] = get_bits(&gb, 8); + if (i && bpc[i] != bpc[i-1]) + return 0; + + log2_chroma_w[i] = get_bits(&gb, 4); + log2_chroma_h[i] = get_bits(&gb, 4); + + if (log2_chroma_h[i] > log2_chroma_w[i]) + return 0; + if (i == 2 && (log2_chroma_h[2] != log2_chroma_h[1] || + log2_chroma_w[2] != log2_chroma_w[1])) + return 0; + } + + switch (bpc[0]) { + case 8: + if (components == 1) s->format = AV_PIX_FMT_GRAY8; + else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P; + else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P; + else s->format = AV_PIX_FMT_YUV420P; + break; + case 10: + if (components == 1) s->format = AV_PIX_FMT_GRAY10; + else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P10; + else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P10; + else s->format = AV_PIX_FMT_YUV420P10; + break; + case 12: + if (components == 1) s->format = AV_PIX_FMT_GRAY12; + else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P12; + else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P12; + else s->format = AV_PIX_FMT_YUV420P12; + break; + case 14: + if (components == 1) s->format = AV_PIX_FMT_GRAY14; + else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P14; + else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P14; + else s->format = AV_PIX_FMT_YUV420P14; + break; + default: + s->format = AV_PIX_FMT_NONE; + break; + } + return 0; + default: + size = bytestream2_get_be16(&gbc); + bytestream2_skip(&gbc, FFMAX(size - 2, 0)); + break; + } + } + + return 0; +} + +static int jpegxsvideo_parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + JPEGXSParseContext *jpegxs = s->priv_data; + ParseContext *pc = &jpegxs->pc; + int next; + + next = jpegxs_find_frame_end(jpegxs, buf, buf_size); + + if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + + jpegxs_parse_frame(s, avctx, buf, buf_size); + + *poutbuf = buf; + *poutbuf_size = buf_size; + return next; +} + +static av_cold void jpegxsparse_close(AVCodecParserContext *s) +{ + JPEGXSParseContext *jpegxs = s->priv_data; + ParseContext *pc = &jpegxs->pc; + + av_freep(&pc->buffer); +} + +const FFCodecParser ff_jpegxs_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_JPEGXS), + .priv_data_size = sizeof(JPEGXSParseContext), + .parse = jpegxsvideo_parse, + .close = jpegxsparse_close, +}; diff --git a/libavcodec/jrevdct.c b/libavcodec/jrevdct.c index 7f1863515..531deee3a 100644 --- a/libavcodec/jrevdct.c +++ b/libavcodec/jrevdct.c @@ -1159,13 +1159,13 @@ void ff_j_rev_dct1(DCTBLOCK data){ #undef FIX #undef CONST_BITS -void ff_jref_idct_put(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +void ff_jref_idct_put(uint8_t *dest, ptrdiff_t line_size, int16_t block[64]) { ff_j_rev_dct(block); ff_put_pixels_clamped_c(block, dest, line_size); } -void ff_jref_idct_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +void ff_jref_idct_add(uint8_t *dest, ptrdiff_t line_size, int16_t block[64]) { ff_j_rev_dct(block); ff_add_pixels_clamped_c(block, dest, line_size); diff --git a/libavcodec/jvdec.c b/libavcodec/jvdec.c index 2b7c9f0d2..d8c78cd18 100644 --- a/libavcodec/jvdec.c +++ b/libavcodec/jvdec.c @@ -37,9 +37,6 @@ typedef struct JvContext { BlockDSPContext bdsp; AVFrame *frame; uint32_t palette[AVPALETTE_COUNT]; -#if FF_API_PALETTE_HAS_CHANGED - int palette_has_changed; -#endif } JvContext; static av_cold int decode_init(AVCodecContext *avctx) @@ -209,18 +206,9 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, s->palette[i] = 0xFFU << 24 | pal << 2 | ((pal >> 4) & 0x30303); buf += 3; } -#if FF_API_PALETTE_HAS_CHANGED - s->palette_has_changed = 1; -#endif } if (video_size) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = s->palette_has_changed; - s->palette_has_changed = 0; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); if ((ret = av_frame_ref(rframe, s->frame)) < 0) diff --git a/libavcodec/kmvc.c b/libavcodec/kmvc.c index 83aba4b25..15a0bc59e 100644 --- a/libavcodec/kmvc.c +++ b/libavcodec/kmvc.c @@ -273,14 +273,7 @@ static int decode_frame(AVCodecContext * avctx, AVFrame *frame, if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = -#endif ff_copy_palette(ctx->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif header = bytestream2_get_byte(&ctx->g); @@ -303,11 +296,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } if (header & KMVC_PALETTE) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif // palette starts from index 1 and has 127 entries for (i = 1; i <= ctx->palsize; i++) { ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&ctx->g); @@ -316,11 +304,6 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->setpal) { ctx->setpal = 0; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } /* make the palette available on the way out */ diff --git a/libavcodec/latm_parser.c b/libavcodec/latm_parser.c index 8cc2024c4..c77bcbaa2 100644 --- a/libavcodec/latm_parser.c +++ b/libavcodec/latm_parser.c @@ -25,6 +25,7 @@ #include #include "parser.h" +#include "parser_internal.h" #define LATM_HEADER 0x56e000 // 0x2b7 (11 bits) #define LATM_MASK 0xFFE000 // top 11 bits @@ -104,9 +105,9 @@ static int latm_parse(AVCodecParserContext *s1, AVCodecContext *avctx, return next; } -const AVCodecParser ff_aac_latm_parser = { - .codec_ids = { AV_CODEC_ID_AAC_LATM }, +const FFCodecParser ff_aac_latm_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_AAC_LATM), .priv_data_size = sizeof(LATMParseContext), - .parser_parse = latm_parse, - .parser_close = ff_parse_close + .parse = latm_parse, + .close = ff_parse_close }; diff --git a/libavcodec/lcevc.h b/libavcodec/lcevc.h new file mode 100644 index 000000000..cfe4c1e6e --- /dev/null +++ b/libavcodec/lcevc.h @@ -0,0 +1,84 @@ +/* + * 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 + * LCEVC common definitions + */ + +#ifndef AVCODEC_LCEVC_H +#define AVCODEC_LCEVC_H + +/* + * Table 17 — NAL unit type codes and NAL unit type classes in + * ISO/IEC 23094-2:2021 + */ +enum { + LCEVC_UNSPEC0_NUT = 0, + LCEVC_UNSPEC1_NUT = 1, + LCEVC_UNSPEC2_NUT = 2, + LCEVC_UNSPEC3_NUT = 3, + LCEVC_UNSPEC4_NUT = 4, + LCEVC_UNSPEC5_NUT = 5, + LCEVC_UNSPEC6_NUT = 6, + LCEVC_UNSPEC7_NUT = 7, + LCEVC_UNSPEC8_NUT = 8, + LCEVC_UNSPEC9_NUT = 9, + LCEVC_UNSPEC10_NUT = 10, + LCEVC_UNSPEC11_NUT = 11, + LCEVC_UNSPEC12_NUT = 12, + LCEVC_UNSPEC13_NUT = 13, + LCEVC_UNSPEC14_NUT = 14, + LCEVC_UNSPEC15_NUT = 15, + LCEVC_UNSPEC16_NUT = 16, + LCEVC_UNSPEC17_NUT = 17, + LCEVC_UNSPEC18_NUT = 18, + LCEVC_UNSPEC19_NUT = 19, + LCEVC_UNSPEC20_NUT = 20, + LCEVC_UNSPEC21_NUT = 21, + LCEVC_UNSPEC22_NUT = 22, + LCEVC_UNSPEC23_NUT = 23, + LCEVC_UNSPEC24_NUT = 24, + LCEVC_UNSPEC25_NUT = 25, + LCEVC_UNSPEC26_NUT = 26, + LCEVC_UNSPEC27_NUT = 27, + LCEVC_NON_IDR_NUT = 28, + LCEVC_IDR_NUT = 29, + LCEVC_RSV_NUT = 30, + LCEVC_UNSPEC31_NUT = 31, +}; + +/* + * Table 19 — Content of payload + */ +enum { + LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG = 0, + LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG = 1, + LCEVC_PAYLOAD_TYPE_PICTURE_CONFIG = 2, + LCEVC_PAYLOAD_TYPE_ENCODED_DATA = 3, + LCEVC_PAYLOAD_TYPE_ENCODED_DATA_TILED = 4, + LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO = 5, + LCEVC_PAYLOAD_TYPE_FILLER = 6, +}; + +enum { + LCEVC_ADDITIONAL_INFO_TYPE_SEI = 0, + LCEVC_ADDITIONAL_INFO_TYPE_VUI = 1, +}; + +#endif /* AVCODEC_LCEVC_H */ diff --git a/libavcodec/lcevc_parse.h b/libavcodec/lcevc_parse.h new file mode 100644 index 000000000..f56758a1a --- /dev/null +++ b/libavcodec/lcevc_parse.h @@ -0,0 +1,42 @@ +/* + * 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_LCEVC_PARSE_H +#define AVCODEC_LCEVC_PARSE_H + +#include + +#include "get_bits.h" + +static inline uint64_t get_mb(GetBitContext *s) { + int more, i = 0; + uint64_t mb = 0; + + do { + int byte = get_bits(s, 8); + unsigned bits = byte & 0x7f; + more = byte & 0x80; + mb = (mb << 7) | bits; + if (++i == 10) + break; + } while (more); + + return mb; +} + +#endif /* AVCODEC_LCEVC_PARSE_H */ diff --git a/libavcodec/lcevc_parser.c b/libavcodec/lcevc_parser.c new file mode 100644 index 000000000..8564fbb52 --- /dev/null +++ b/libavcodec/lcevc_parser.c @@ -0,0 +1,263 @@ +/* + * 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 "libavutil/mem.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "get_bits.h" +#include "h2645_parse.h" +#include "lcevc.h" +#include "lcevc_parse.h" +#include "lcevctab.h" +#include "parser.h" +#include "parser_internal.h" + +#define START_CODE 0x000001 ///< start_code_prefix_one_3bytes + +typedef struct LCEVCParserContext { + ParseContext pc; + + H2645Packet pkt; + + int parsed_extradata; + int is_lvcc; + int nal_length_size; +} LCEVCParserContext; + +static int lcevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf, + int buf_size) +{ + LCEVCParserContext *ctx = s->priv_data; + ParseContext *pc = &ctx->pc; + + for (int i = 0; i < buf_size; i++) { + int nut; + + pc->state = (pc->state << 8) | buf[i]; + + if (((pc->state >> 8) & 0xFFFFFF) != START_CODE) + continue; + + nut = (pc->state >> 1) & 0x1F; + + // Beginning of access unit + if (nut == LCEVC_IDR_NUT || nut == LCEVC_NON_IDR_NUT) { + if (!pc->frame_start_found) + pc->frame_start_found = 1; + else { + pc->frame_start_found = 0; + return i - 3; + } + } + } + + return END_NOT_FOUND; +} + +static const enum AVPixelFormat pix_fmts[4][4] = { + { AV_PIX_FMT_GRAY8, AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, }, + { AV_PIX_FMT_GRAY10, AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, }, + { AV_PIX_FMT_GRAY12, AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, }, + { AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, }, +}; + +static int parse_nal_unit(AVCodecParserContext *s, AVCodecContext *avctx, + const H2645NAL *nal) +{ + GetByteContext gbc; + bytestream2_init(&gbc, nal->data, nal->size); + bytestream2_skip(&gbc, 2); + + while (bytestream2_get_bytes_left(&gbc) > 1) { + GetBitContext gb; + uint64_t payload_size; + int payload_size_type, payload_type; + int block_size; + + int ret = init_get_bits8(&gb, gbc.buffer, bytestream2_get_bytes_left(&gbc)); + if (ret < 0) + return ret; + + payload_size_type = get_bits(&gb, 3); + payload_type = get_bits(&gb, 5); + payload_size = payload_size_type; + if (payload_size_type == 6) + return AVERROR_PATCHWELCOME; + if (payload_size_type == 7) + payload_size = get_mb(&gb); + + if (payload_size > INT_MAX - (get_bits_count(&gb) >> 3)) + return AVERROR_INVALIDDATA; + + block_size = payload_size + (get_bits_count(&gb) >> 3); + if (block_size >= bytestream2_get_bytes_left(&gbc)) + return AVERROR_INVALIDDATA; + + switch (payload_type) { + case LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG: + avctx->profile = get_bits(&gb, 4); + avctx->level = get_bits(&gb, 4); + break; + case LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG: { + int resolution_type, chroma_format_idc, bit_depth; + int processed_planes_type_flag; + + processed_planes_type_flag = get_bits1(&gb); + resolution_type = get_bits(&gb, 6); + skip_bits1(&gb); + chroma_format_idc = get_bits(&gb, 2); + skip_bits(&gb, 2); + bit_depth = get_bits(&gb, 2); // enhancement_depth_type + + s->format = pix_fmts[bit_depth][chroma_format_idc]; + + if (resolution_type < 63) { + s->width = ff_lcevc_resolution_type[resolution_type].width; + s->height = ff_lcevc_resolution_type[resolution_type].height; + } else { + int upsample_type, tile_dimensions_type; + int temporal_step_width_modifier_signalled_flag, level1_filtering_signalled_flag; + // Skip syntax elements until we get to the custom dimension ones + temporal_step_width_modifier_signalled_flag = get_bits1(&gb); + skip_bits(&gb, 3); + upsample_type = get_bits(&gb, 3); + level1_filtering_signalled_flag = get_bits1(&gb); + skip_bits(&gb, 4); + tile_dimensions_type = get_bits(&gb, 2); + skip_bits(&gb, 4); + if (processed_planes_type_flag) + skip_bits(&gb, 4); + if (temporal_step_width_modifier_signalled_flag) + skip_bits(&gb, 8); + if (upsample_type) + skip_bits_long(&gb, 64); + if (level1_filtering_signalled_flag) + skip_bits(&gb, 8); + if (tile_dimensions_type) { + if (tile_dimensions_type == 3) + skip_bits_long(&gb, 32); + skip_bits(&gb, 8); + } + + s->width = get_bits(&gb, 16); + s->height = get_bits(&gb, 16); + } + break; + } + default: + break; + } + + bytestream2_skip(&gbc, block_size); + } + + return 0; +} + +static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, + int buf_size, AVCodecContext *avctx) +{ + LCEVCParserContext *ctx = s->priv_data; + int flags = (H2645_FLAG_IS_NALFF * !!ctx->is_lvcc) | H2645_FLAG_SMALL_PADDING; + int ret, i; + + /* set some sane default values */ + s->pict_type = AV_PICTURE_TYPE_NONE; + s->key_frame = 0; + s->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN; + + ret = ff_h2645_packet_split(&ctx->pkt, buf, buf_size, avctx, + ctx->nal_length_size, AV_CODEC_ID_LCEVC, flags); + if (ret < 0) + return ret; + + for (i = 0; i < ctx->pkt.nb_nals; i++) { + H2645NAL *nal = &ctx->pkt.nals[i]; + + switch (nal->type) { + case LCEVC_IDR_NUT: + s->key_frame = 1; + // fall-through + case LCEVC_NON_IDR_NUT: + parse_nal_unit(s, avctx, nal); + break; + default: + break; + } + } + + return 0; +} + +static int lcevc_parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + LCEVCParserContext *ctx = s->priv_data; + ParseContext *pc = &ctx->pc; + int next; + + if (!ctx->parsed_extradata && avctx->extradata_size > 4) { + ctx->parsed_extradata = 1; + ctx->is_lvcc = !!avctx->extradata[0]; + + if (ctx->is_lvcc) + ctx->nal_length_size = (avctx->extradata[4] >> 6) + 1; + } + + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + } else { + next = lcevc_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, buf, buf_size, avctx); + + *poutbuf = buf; + *poutbuf_size = buf_size; + return next; +} + +static void lcevc_parser_close(AVCodecParserContext *s) +{ + LCEVCParserContext *ctx = s->priv_data; + + ff_h2645_packet_uninit(&ctx->pkt); + + av_freep(&ctx->pc.buffer); +} + +const FFCodecParser ff_lcevc_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_LCEVC), + .priv_data_size = sizeof(LCEVCParserContext), + .parse = lcevc_parse, + .close = lcevc_parser_close, +}; diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c index 1bfb7c78c..69a73866f 100644 --- a/libavcodec/lcevcdec.c +++ b/libavcodec/lcevcdec.c @@ -21,8 +21,14 @@ #include "libavutil/imgutils.h" #include "libavutil/log.h" #include "libavutil/mem.h" +#include "libavutil/refstruct.h" + +#include "cbs.h" +#include "cbs_lcevc.h" #include "decode.h" +#include "lcevc_parse.h" #include "lcevcdec.h" +#include "lcevctab.h" static LCEVC_ColorFormat map_format(int format) { @@ -116,11 +122,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame if (!sd) return 1; -#ifdef LCEVC_DEC_VERSION_MAJOR res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, sd->data, sd->size); -#else - res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size); -#endif if (res != LCEVC_Success) return AVERROR_EXTERNAL; @@ -141,11 +143,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame return AVERROR_EXTERNAL; } -#ifdef LCEVC_DEC_VERSION_MAJOR res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, picture, -1, opaque); -#else - res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, opaque); -#endif if (res != LCEVC_Success) { LCEVC_FreePicture(lcevc->decoder, picture); av_frame_free(&opaque); @@ -197,6 +195,15 @@ static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out) out->width = desc.width + out->crop_left + out->crop_right; out->height = desc.height + out->crop_top + out->crop_bottom; + av_log(logctx, AV_LOG_DEBUG, "out PTS %"PRId64", %dx%d, " + "%zu/%zu/%zu/%zu, " + "SAR %d:%d, " + "hasEnhancement %d, enhanced %d\n", + out->pts, out->width, out->height, + out->crop_top, out->crop_bottom, out->crop_left, out->crop_right, + out->sample_aspect_ratio.num, out->sample_aspect_ratio.den, + info.hasEnhancement, info.enhanced); + res = LCEVC_FreePicture(lcevc->decoder, picture); if (res != LCEVC_Success) return AVERROR_EXTERNAL; @@ -254,7 +261,7 @@ static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event, } } -static void lcevc_free(FFRefStructOpaque unused, void *obj) +static void lcevc_free(AVRefStructOpaque unused, void *obj) { FFLCEVCContext *lcevc = obj; if (lcevc->initialized) { @@ -262,6 +269,10 @@ static void lcevc_free(FFRefStructOpaque unused, void *obj) lcevc_flush_pictures(lcevc); LCEVC_DestroyDecoder(lcevc->decoder); } + if (lcevc->frag) + ff_cbs_fragment_free(lcevc->frag); + av_freep(&lcevc->frag); + ff_cbs_close(&lcevc->cbc); memset(lcevc, 0, sizeof(*lcevc)); } @@ -292,7 +303,7 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx) int ff_lcevc_process(void *logctx, AVFrame *frame) { - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FrameDecodeData *fdd = frame->private_ref; FFLCEVCFrame *frame_ctx = fdd->post_process_opaque; FFLCEVCContext *lcevc = frame_ctx->lcevc; int ret; @@ -319,20 +330,80 @@ int ff_lcevc_process(void *logctx, AVFrame *frame) return 0; } -int ff_lcevc_alloc(FFLCEVCContext **plcevc) +int ff_lcevc_parse_frame(FFLCEVCContext *lcevc, const AVFrame *frame, + int *width, int *height, void *logctx) +{ + LCEVCRawProcessBlock *block = NULL; + LCEVCRawGlobalConfig *gc = NULL; + AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC); + int ret; + + ret = ff_cbs_read(lcevc->cbc, lcevc->frag, sd->buf, sd->data, sd->size); + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, "Failed to parse Access Unit.\n"); + goto end; + } + + ret = ff_cbs_lcevc_find_process_block(lcevc->cbc, lcevc->frag, + LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG, &block); + if (ret < 0) { + ret = 0; + goto end; + } + + gc = block->payload; + if (gc->resolution_type < 63) { + *width = ff_lcevc_resolution_type[gc->resolution_type].width; + *height = ff_lcevc_resolution_type[gc->resolution_type].height; + } else { + *width = gc->custom_resolution_width; + *height = gc->custom_resolution_height; + } + + ret = 0; +end: + ff_cbs_fragment_reset(lcevc->frag); + + return ret; +} + +static const CodedBitstreamUnitType decompose_unit_types[] = { + LCEVC_IDR_NUT, +}; + +int ff_lcevc_alloc(FFLCEVCContext **plcevc, void *logctx) { FFLCEVCContext *lcevc = NULL; - lcevc = ff_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free); + int ret; + + lcevc = av_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free); if (!lcevc) return AVERROR(ENOMEM); + + lcevc->frag = av_mallocz(sizeof(*lcevc->frag)); + if (!lcevc->frag) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = ff_cbs_init(&lcevc->cbc, AV_CODEC_ID_LCEVC, logctx); + if (ret < 0) + goto fail; + + lcevc->cbc->decompose_unit_types = decompose_unit_types; + lcevc->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types); + *plcevc = lcevc; return 0; +fail: + av_refstruct_unref(&lcevc); + return ret; } void ff_lcevc_unref(void *opaque) { FFLCEVCFrame *lcevc = opaque; - ff_refstruct_unref(&lcevc->lcevc); + av_refstruct_unref(&lcevc->lcevc); av_frame_free(&lcevc->frame); av_free(opaque); } diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h index f0d17c041..a65214344 100644 --- a/libavcodec/lcevcdec.h +++ b/libavcodec/lcevcdec.h @@ -19,7 +19,7 @@ #ifndef AVCODEC_LCEVCDEC_H #define AVCODEC_LCEVCDEC_H -#include "config_components.h" +#include "config.h" #include #if CONFIG_LIBLCEVC_DEC @@ -27,10 +27,14 @@ #else typedef uintptr_t LCEVC_DecoderHandle; #endif -#include "refstruct.h" + +struct CodedBitstreamContext; +struct CodedBitstreamFragment; typedef struct FFLCEVCContext { LCEVC_DecoderHandle decoder; + struct CodedBitstreamContext *cbc; + struct CodedBitstreamFragment *frag; int initialized; } FFLCEVCContext; @@ -41,7 +45,9 @@ typedef struct FFLCEVCFrame { struct AVFrame *frame; } FFLCEVCFrame; -int ff_lcevc_alloc(FFLCEVCContext **plcevc); +int ff_lcevc_alloc(FFLCEVCContext **plcevc, void *logctx); int ff_lcevc_process(void *logctx, struct AVFrame *frame); +int ff_lcevc_parse_frame(FFLCEVCContext *lcevc, const struct AVFrame *frame, + int *width, int *height, void *logctx); void ff_lcevc_unref(void *opaque); #endif /* AVCODEC_LCEVCDEC_H */ diff --git a/libavfilter/vulkan.h b/libavcodec/lcevctab.c similarity index 86% rename from libavfilter/vulkan.h rename to libavcodec/lcevctab.c index 928b2e21c..76853b80e 100644 --- a/libavfilter/vulkan.h +++ b/libavcodec/lcevctab.c @@ -16,9 +16,4 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVFILTER_VULKAN_H -#define AVFILTER_VULKAN_H - -#include "libavutil/vulkan.h" - -#endif /* AVFILTER_VULKAN_H */ +#include "lcevctab.h" diff --git a/libavcodec/lcevctab.h b/libavcodec/lcevctab.h new file mode 100644 index 000000000..680358953 --- /dev/null +++ b/libavcodec/lcevctab.h @@ -0,0 +1,41 @@ +/* + * 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_LCEVCTAB_H +#define AVCODEC_LCEVCTAB_H + +static const struct { + int width; + int height; +} ff_lcevc_resolution_type[63] = { + { 0, 0}, + { 360, 200 }, { 400, 240 }, { 480, 320 }, { 640, 360 }, + { 640, 480 }, { 768, 480 }, { 800, 600 }, { 852, 480 }, + { 854, 480 }, { 856, 480 }, { 960, 540 }, { 960, 640 }, + { 1024, 576 }, { 1024, 600 }, { 1024, 768 }, { 1152, 864 }, + { 1280, 720 }, { 1280, 800 }, { 1280, 1024 }, { 1360, 768 }, + { 1366, 768 }, { 1920, 1200 }, { 2048, 1080 }, { 2048, 1152 }, + { 2048, 1536 }, { 2160, 1440 }, { 2560, 1440 }, { 2560, 1600 }, + { 2560, 2048 }, { 3200, 1800 }, { 3200, 2048 }, { 3200, 2400 }, + { 3440, 1440 }, { 3840, 1600 }, { 3840, 2160 }, { 3840, 2400 }, + { 4096, 2160 }, { 4096, 3072 }, { 5120, 2880 }, { 5120, 3200 }, + { 5120, 4096 }, { 6400, 4096 }, { 6400, 4800 }, { 7680, 4320 }, + { 7680, 4800 }, +}; + +#endif /* AVCODEC_LCEVCTAB_H */ diff --git a/libavcodec/lclenc.c b/libavcodec/lclenc.c index dd5eed9d6..f328e1262 100644 --- a/libavcodec/lclenc.c +++ b/libavcodec/lclenc.c @@ -162,6 +162,6 @@ const FFCodec ff_zlib_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/leaddec.c b/libavcodec/leaddec.c index 2f5152c22..e6a91faab 100644 --- a/libavcodec/leaddec.c +++ b/libavcodec/leaddec.c @@ -157,12 +157,17 @@ static int lead_decode_frame(AVCodecContext *avctx, AVFrame * frame, zero = 1; avctx->pix_fmt = AV_PIX_FMT_YUV420P; break; + case 0x6: case 0x8000: yuv20p_half = 1; // fall-through case 0x1000: avctx->pix_fmt = AV_PIX_FMT_YUV420P; break; + case 0x1006: + fields = 2; + avctx->pix_fmt = AV_PIX_FMT_YUV420P; + break; case 0x2000: avctx->pix_fmt = AV_PIX_FMT_YUV444P; break; @@ -236,7 +241,8 @@ static int lead_decode_frame(AVCodecContext *avctx, AVFrame * frame, return ret; } } else if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) { - for (int mb_y = 0; mb_y < (avctx->height + 15) / 16; mb_y++) + for (int f = 0; f < fields; f++) + for (int mb_y = 0; mb_y < (avctx->height + 15) / 16 / fields; mb_y++) for (int mb_x = 0; mb_x < (avctx->width + 15) / 16; mb_x++) for (int b = 0; b < (yuv20p_half ? 4 : 6); b++) { int luma_block = yuv20p_half ? 2 : 4; @@ -257,8 +263,8 @@ static int lead_decode_frame(AVCodecContext *avctx, AVFrame * frame, ret = decode_block(s, &gb, dc_vlc, dc_bits, ac_vlc, ac_bits, dc_pred + plane, dequant[!(b < 4)], - frame->data[plane] + y*frame->linesize[plane] + x, - (yuv20p_half && b < 2 ? 2 : 1) * frame->linesize[plane]); + frame->data[plane] + (f + y*fields)*frame->linesize[plane] + x, + (yuv20p_half && b < 2 ? 2 : 1) * fields * frame->linesize[plane]); if (ret < 0) return ret; diff --git a/libavcodec/libaomdec.c b/libavcodec/libaomdec.c index 69eec8b08..79b299bac 100644 --- a/libavcodec/libaomdec.c +++ b/libavcodec/libaomdec.c @@ -28,11 +28,14 @@ #include "libavutil/common.h" #include "libavutil/cpu.h" +#include "libavutil/hdr_dynamic_metadata.h" #include "libavutil/imgutils.h" #include "avcodec.h" +#include "bytestream.h" #include "codec_internal.h" #include "decode.h" +#include "itut35.h" #include "libaom.h" #include "profiles.h" @@ -68,9 +71,12 @@ static int set_pix_fmt(AVCodecContext *avctx, struct aom_image *img) AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG }; avctx->color_range = color_ranges[img->range]; - avctx->color_primaries = img->cp; - avctx->colorspace = img->mc; - avctx->color_trc = img->tc; + if (img->cp != AOM_CICP_CP_UNSPECIFIED) + avctx->color_primaries = (enum AVColorPrimaries)img->cp; + if (img->mc != AOM_CICP_MC_UNSPECIFIED) + avctx->colorspace = (enum AVColorSpace)img->mc; + if (img->tc != AOM_CICP_TC_UNSPECIFIED) + avctx->color_trc = (enum AVColorTransferCharacteristic)img->tc; switch (img->fmt) { case AOM_IMG_FMT_I420: @@ -137,6 +143,61 @@ static int set_pix_fmt(AVCodecContext *avctx, struct aom_image *img) } } +static int decode_metadata_itu_t_t35(AVFrame *frame, + const uint8_t *buffer, size_t buffer_size) +{ + if (buffer_size < 6) + return AVERROR(EINVAL); + + GetByteContext bc; + bytestream2_init(&bc, buffer, buffer_size); + + const int country_code = bytestream2_get_byteu(&bc); + const int provider_code = bytestream2_get_be16u(&bc); + const int provider_oriented_code = bytestream2_get_be16u(&bc); + const int application_identifier = bytestream2_get_byteu(&bc); + + // See "HDR10+ AV1 Metadata Handling Specification" v1.0.1, Section 2.1. + if (country_code == ITU_T_T35_COUNTRY_CODE_US + && provider_code == ITU_T_T35_PROVIDER_CODE_SAMSUNG + && provider_oriented_code == 0x0001 + && application_identifier == 0x04) { + // HDR10+ + AVDynamicHDRPlus *hdr_plus = av_dynamic_hdr_plus_create_side_data(frame); + if (!hdr_plus) + return AVERROR(ENOMEM); + + int res = av_dynamic_hdr_plus_from_t35(hdr_plus, bc.buffer, + bytestream2_get_bytes_left(&bc)); + if (res < 0) + return res; + } + + return 0; +} + +static int decode_metadata(AVFrame *frame, const struct aom_image *img) +{ + const size_t num_metadata = aom_img_num_metadata(img); + for (size_t i = 0; i < num_metadata; ++i) { + const aom_metadata_t *metadata = aom_img_get_metadata(img, i); + if (!metadata) + continue; + + switch (metadata->type) { + case OBU_METADATA_TYPE_ITUT_T35: { + int res = decode_metadata_itu_t_t35(frame, metadata->payload, metadata->sz); + if (res < 0) + return res; + break; + } + default: + break; + } + } + return 0; +} + static int aom_decode(AVCodecContext *avctx, AVFrame *picture, int *got_frame, AVPacket *avpkt) { @@ -215,6 +276,11 @@ static int aom_decode(AVCodecContext *avctx, AVFrame *picture, av_image_copy(picture->data, picture->linesize, planes, stride, avctx->pix_fmt, img->d_w, img->d_h); } + ret = decode_metadata(picture, img); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to decode metadata\n"); + return ret; + } *got_frame = 1; } return avpkt->size; diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c index 0f7571ee7..20e97e5d4 100644 --- a/libavcodec/libaomenc.c +++ b/libavcodec/libaomenc.c @@ -31,8 +31,8 @@ #include "libavutil/avassert.h" #include "libavutil/base64.h" -#include "libavutil/common.h" #include "libavutil/cpu.h" +#include "libavutil/hdr_dynamic_metadata.h" #include "libavutil/imgutils.h" #include "libavutil/mathematics.h" #include "libavutil/mem.h" @@ -42,12 +42,13 @@ #include "av1.h" #include "avcodec.h" #include "bsf.h" +#include "bytestream.h" #include "codec_internal.h" #include "dovi_rpu.h" #include "encode.h" #include "internal.h" +#include "itut35.h" #include "libaom.h" -#include "packet_internal.h" #include "profiles.h" /* @@ -140,6 +141,8 @@ typedef struct AOMEncoderContext { AVDictionary *aom_params; } AOMContext; +#define OFFSET(x) offsetof(AOMContext, x) + static const char *const ctlidstr[] = { [AOME_SET_CPUUSED] = "AOME_SET_CPUUSED", [AOME_SET_CQ_LEVEL] = "AOME_SET_CQ_LEVEL", @@ -237,7 +240,7 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx, width, "g_pass:", cfg->g_pass, width, "g_lag_in_frames:", cfg->g_lag_in_frames); av_log(avctx, level, "rate control settings\n" - " %*s%u\n %*s%d\n %*s%p(%"SIZE_SPECIFIER")\n %*s%u\n", + " %*s%u\n %*s%d\n %*s%p(%zu)\n %*s%u\n", width, "rc_dropframe_thresh:", cfg->rc_dropframe_thresh, width, "rc_end_usage:", cfg->rc_end_usage, width, "rc_twopass_stats_in:", cfg->rc_twopass_stats_in.buf, cfg->rc_twopass_stats_in.sz, @@ -300,11 +303,7 @@ static av_cold void free_frame_list(struct FrameListData *list) } static av_cold int codecctl_int(AVCodecContext *avctx, -#ifdef UENUM1BYTE - aome_enc_control_id id, -#else - enum aome_enc_control_id id, -#endif + int id, int val) { AOMContext *ctx = avctx->priv_data; @@ -326,15 +325,58 @@ static av_cold int codecctl_int(AVCodecContext *avctx, return 0; } +static int add_hdr_plus(AVCodecContext *avctx, struct aom_image *img, const AVFrame *frame) +{ + // Check for HDR10+ + AVFrameSideData *side_data = + av_frame_get_side_data(frame, AV_FRAME_DATA_DYNAMIC_HDR_PLUS); + if (!side_data) + return 0; + + size_t payload_size; + AVDynamicHDRPlus *hdr_plus = (AVDynamicHDRPlus *)side_data->buf->data; + int res = av_dynamic_hdr_plus_to_t35(hdr_plus, NULL, &payload_size); + if (res < 0) { + log_encoder_error(avctx, "Error finding the size of HDR10+"); + return res; + } + + uint8_t *hdr_plus_buf; + // Extra bytes for the country code, provider code, provider oriented code and app id. + const size_t hdr_plus_buf_size = payload_size + 6; + hdr_plus_buf = av_malloc(hdr_plus_buf_size); + if (!hdr_plus_buf) + return AVERROR(ENOMEM); + + uint8_t *payload = hdr_plus_buf; + // See "HDR10+ AV1 Metadata Handling Specification" v1.0.1, Section 2.1. + bytestream_put_byte(&payload, ITU_T_T35_COUNTRY_CODE_US); + bytestream_put_be16(&payload, ITU_T_T35_PROVIDER_CODE_SAMSUNG); + bytestream_put_be16(&payload, 0x0001); // provider_oriented_code + bytestream_put_byte(&payload, 0x04); // application_identifier + + res = av_dynamic_hdr_plus_to_t35(hdr_plus, &payload, &payload_size); + if (res < 0) { + av_free(hdr_plus_buf); + log_encoder_error(avctx, "Error encoding HDR10+ from side data"); + return res; + } + + res = aom_img_add_metadata(img, OBU_METADATA_TYPE_ITUT_T35, + hdr_plus_buf, hdr_plus_buf_size, AOM_MIF_ANY_FRAME); + av_free(hdr_plus_buf); + if (res < 0) { + log_encoder_error(avctx, "Error adding HDR10+ to aom_img"); + return res; + } + return 0; +} + #if defined(AOM_CTRL_AV1E_GET_NUM_OPERATING_POINTS) && \ defined(AOM_CTRL_AV1E_GET_SEQ_LEVEL_IDX) && \ defined(AOM_CTRL_AV1E_GET_TARGET_SEQ_LEVEL_IDX) static av_cold int codecctl_intp(AVCodecContext *avctx, -#ifdef UENUM1BYTE - aome_enc_control_id id, -#else - enum aome_enc_control_id id, -#endif + int id, int* ptr) { AOMContext *ctx = avctx->priv_data; @@ -342,27 +384,23 @@ static av_cold int codecctl_intp(AVCodecContext *avctx, int width = -30; int res; - snprintf(buf, sizeof(buf), "%s:", ctlidstr[id]); - av_log(avctx, AV_LOG_DEBUG, " %*s%d\n", width, buf, *ptr); - res = aom_codec_control(&ctx->encoder, id, ptr); if (res != AOM_CODEC_OK) { - snprintf(buf, sizeof(buf), "Failed to set %s codec control", + snprintf(buf, sizeof(buf), "Failed to get %s codec control", ctlidstr[id]); log_encoder_error(avctx, buf); return AVERROR(EINVAL); } + snprintf(buf, sizeof(buf), "%s:", ctlidstr[id]); + av_log(avctx, AV_LOG_DEBUG, " %*s%d\n", width, buf, *ptr); + return 0; } #endif static av_cold int codecctl_imgp(AVCodecContext *avctx, -#ifdef UENUM1BYTE - aome_enc_control_id id, -#else - enum aome_enc_control_id id, -#endif + int id, struct aom_image *img) { AOMContext *ctx = avctx->priv_data; @@ -432,7 +470,6 @@ static int set_pix_fmt(AVCodecContext *avctx, aom_codec_caps_t codec_caps, struct aom_codec_enc_cfg *enccfg, aom_codec_flags_t *flags, aom_img_fmt_t *img_fmt) { - AOMContext av_unused *ctx = avctx->priv_data; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); enccfg->g_bit_depth = enccfg->g_input_bit_depth = desc->comp[0].depth; switch (avctx->pix_fmt) { @@ -673,6 +710,46 @@ static int choose_tiling(AVCodecContext *avctx, return 0; } + +static const struct { + int aom_enum; + unsigned offset; +} option_map[] = { + { AOME_SET_ENABLEAUTOALTREF, OFFSET(auto_alt_ref) }, + { AOME_SET_ARNR_MAXFRAMES, OFFSET(arnr_max_frames) }, + { AOME_SET_ARNR_STRENGTH, OFFSET(arnr_strength) }, + { AV1E_SET_ENABLE_CDEF, OFFSET(enable_cdef) }, + { AV1E_SET_ENABLE_RESTORATION, OFFSET(enable_restoration) }, + { AV1E_SET_ENABLE_RECT_PARTITIONS, OFFSET(enable_rect_partitions) }, + { AV1E_SET_ENABLE_1TO4_PARTITIONS, OFFSET(enable_1to4_partitions) }, + { AV1E_SET_ENABLE_AB_PARTITIONS, OFFSET(enable_ab_partitions) }, + { AV1E_SET_ENABLE_ANGLE_DELTA, OFFSET(enable_angle_delta) }, + { AV1E_SET_ENABLE_CFL_INTRA, OFFSET(enable_cfl_intra) }, + { AV1E_SET_ENABLE_FILTER_INTRA, OFFSET(enable_filter_intra) }, + { AV1E_SET_ENABLE_INTRA_EDGE_FILTER, OFFSET(enable_intra_edge_filter) }, + { AV1E_SET_ENABLE_PAETH_INTRA, OFFSET(enable_paeth_intra) }, + { AV1E_SET_ENABLE_SMOOTH_INTRA, OFFSET(enable_smooth_intra) }, + { AV1E_SET_ENABLE_PALETTE, OFFSET(enable_palette) }, + { AV1E_SET_ENABLE_TX64, OFFSET(enable_tx64) }, + { AV1E_SET_ENABLE_FLIP_IDTX, OFFSET(enable_flip_idtx) }, + { AV1E_SET_INTRA_DCT_ONLY, OFFSET(use_intra_dct_only) }, + { AV1E_SET_INTER_DCT_ONLY, OFFSET(use_inter_dct_only) }, + { AV1E_SET_INTRA_DEFAULT_TX_ONLY, OFFSET(use_intra_default_tx_only) }, + { AV1E_SET_REDUCED_TX_TYPE_SET, OFFSET(reduced_tx_type_set) }, + { AV1E_SET_ENABLE_REF_FRAME_MVS, OFFSET(enable_ref_frame_mvs) }, + { AV1E_SET_REDUCED_REFERENCE_SET, OFFSET(enable_reduced_reference_set) }, + { AV1E_SET_ENABLE_DIFF_WTD_COMP, OFFSET(enable_diff_wtd_comp) }, + { AV1E_SET_ENABLE_DIST_WTD_COMP, OFFSET(enable_dist_wtd_comp) }, + { AV1E_SET_ENABLE_DUAL_FILTER, OFFSET(enable_dual_filter) }, + { AV1E_SET_ENABLE_INTERINTER_WEDGE, OFFSET(enable_interinter_wedge) }, + { AV1E_SET_ENABLE_MASKED_COMP, OFFSET(enable_masked_comp) }, + { AV1E_SET_ENABLE_INTERINTRA_COMP, OFFSET(enable_interintra_comp) }, + { AV1E_SET_ENABLE_INTERINTRA_WEDGE, OFFSET(enable_interintra_wedge) }, + { AV1E_SET_ENABLE_OBMC, OFFSET(enable_obmc) }, + { AV1E_SET_ENABLE_ONESIDED_COMP, OFFSET(enable_onesided_comp) }, + { AV1E_SET_ENABLE_SMOOTH_INTERINTRA, OFFSET(enable_smooth_interintra) }, +}; + static av_cold int aom_init(AVCodecContext *avctx, const struct aom_codec_iface *iface) { @@ -681,7 +758,6 @@ static av_cold int aom_init(AVCodecContext *avctx, struct aom_codec_enc_cfg enccfg = { 0 }; aom_codec_flags_t flags = (avctx->flags & AV_CODEC_FLAG_PSNR) ? AOM_CODEC_USE_PSNR : 0; - AVCPBProperties *cpb_props; int res; aom_img_fmt_t img_fmt; aom_codec_caps_t codec_caps = aom_codec_get_caps(iface); @@ -808,7 +884,7 @@ static av_cold int aom_init(AVCodecContext *avctx, ret = av_reallocp(&ctx->twopass_stats.buf, ctx->twopass_stats.sz); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, - "Stat buffer alloc (%"SIZE_SPECIFIER" bytes) failed\n", + "Stat buffer alloc (%zu bytes) failed\n", ctx->twopass_stats.sz); ctx->twopass_stats.sz = 0; return ret; @@ -860,73 +936,12 @@ static av_cold int aom_init(AVCodecContext *avctx, // codec control failures are currently treated only as warnings av_log(avctx, AV_LOG_DEBUG, "aom_codec_control\n"); codecctl_int(avctx, AOME_SET_CPUUSED, ctx->cpu_used); - if (ctx->auto_alt_ref >= 0) - codecctl_int(avctx, AOME_SET_ENABLEAUTOALTREF, ctx->auto_alt_ref); - if (ctx->arnr_max_frames >= 0) - codecctl_int(avctx, AOME_SET_ARNR_MAXFRAMES, ctx->arnr_max_frames); - if (ctx->arnr_strength >= 0) - codecctl_int(avctx, AOME_SET_ARNR_STRENGTH, ctx->arnr_strength); - if (ctx->enable_cdef >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_CDEF, ctx->enable_cdef); - if (ctx->enable_restoration >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_RESTORATION, ctx->enable_restoration); - if (ctx->enable_rect_partitions >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_RECT_PARTITIONS, ctx->enable_rect_partitions); - if (ctx->enable_1to4_partitions >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_1TO4_PARTITIONS, ctx->enable_1to4_partitions); - if (ctx->enable_ab_partitions >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_AB_PARTITIONS, ctx->enable_ab_partitions); - if (ctx->enable_angle_delta >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_ANGLE_DELTA, ctx->enable_angle_delta); - if (ctx->enable_cfl_intra >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_CFL_INTRA, ctx->enable_cfl_intra); - if (ctx->enable_filter_intra >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_FILTER_INTRA, ctx->enable_filter_intra); - if (ctx->enable_intra_edge_filter >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_INTRA_EDGE_FILTER, ctx->enable_intra_edge_filter); - if (ctx->enable_paeth_intra >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_PAETH_INTRA, ctx->enable_paeth_intra); - if (ctx->enable_smooth_intra >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_SMOOTH_INTRA, ctx->enable_smooth_intra); - if (ctx->enable_palette >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_PALETTE, ctx->enable_palette); - if (ctx->enable_tx64 >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_TX64, ctx->enable_tx64); - if (ctx->enable_flip_idtx >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_FLIP_IDTX, ctx->enable_flip_idtx); - if (ctx->use_intra_dct_only >= 0) - codecctl_int(avctx, AV1E_SET_INTRA_DCT_ONLY, ctx->use_intra_dct_only); - if (ctx->use_inter_dct_only >= 0) - codecctl_int(avctx, AV1E_SET_INTER_DCT_ONLY, ctx->use_inter_dct_only); - if (ctx->use_intra_default_tx_only >= 0) - codecctl_int(avctx, AV1E_SET_INTRA_DEFAULT_TX_ONLY, ctx->use_intra_default_tx_only); - if (ctx->reduced_tx_type_set >= 0) - codecctl_int(avctx, AV1E_SET_REDUCED_TX_TYPE_SET, ctx->reduced_tx_type_set); - if (ctx->enable_ref_frame_mvs >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_REF_FRAME_MVS, ctx->enable_ref_frame_mvs); - if (ctx->enable_reduced_reference_set >= 0) - codecctl_int(avctx, AV1E_SET_REDUCED_REFERENCE_SET, ctx->enable_reduced_reference_set); - if (ctx->enable_diff_wtd_comp >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_DIFF_WTD_COMP, ctx->enable_diff_wtd_comp); - if (ctx->enable_dist_wtd_comp >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_DIST_WTD_COMP, ctx->enable_dist_wtd_comp); - if (ctx->enable_dual_filter >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_DUAL_FILTER, ctx->enable_dual_filter); - if (ctx->enable_interinter_wedge >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_INTERINTER_WEDGE, ctx->enable_interinter_wedge); - if (ctx->enable_masked_comp >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_MASKED_COMP, ctx->enable_masked_comp); - if (ctx->enable_interintra_comp >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_INTERINTRA_COMP, ctx->enable_interintra_comp); - if (ctx->enable_interintra_wedge >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_INTERINTRA_WEDGE, ctx->enable_interintra_wedge); - if (ctx->enable_obmc >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_OBMC, ctx->enable_obmc); - if (ctx->enable_onesided_comp >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_ONESIDED_COMP, ctx->enable_onesided_comp); - if (ctx->enable_smooth_interintra >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_SMOOTH_INTERINTRA, ctx->enable_smooth_interintra); + for (size_t i = 0; i < FF_ARRAY_ELEMS(option_map); ++i) { + int val = *(int*)((char*)ctx + option_map[i].offset); + if (val >= 0) + codecctl_int(avctx, option_map[i].aom_enum, val); + } codecctl_int(avctx, AOME_SET_STATIC_THRESHOLD, ctx->static_thresh); if (ctx->crf >= 0) codecctl_int(avctx, AOME_SET_CQ_LEVEL, ctx->crf); @@ -989,10 +1004,6 @@ static av_cold int aom_init(AVCodecContext *avctx, if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) ctx->rawimg.bit_depth = enccfg.g_bit_depth; - cpb_props = ff_encode_add_cpb_side_data(avctx); - if (!cpb_props) - return AVERROR(ENOMEM); - ctx->dovi.logctx = avctx; if ((res = ff_dovi_configure(&ctx->dovi, avctx)) < 0) return res; @@ -1019,6 +1030,10 @@ static av_cold int aom_init(AVCodecContext *avctx, return ret; } + AVCPBProperties *cpb_props = ff_encode_add_cpb_side_data(avctx); + if (!cpb_props) + return AVERROR(ENOMEM); + if (enccfg.rc_end_usage == AOM_CBR || enccfg.g_pass != AOM_RC_ONE_PASS) { cpb_props->max_bitrate = avctx->rc_max_rate; @@ -1060,11 +1075,11 @@ static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, AVPacket *pkt) { AOMContext *ctx = avctx->priv_data; - int av_unused pict_type; + enum AVPictureType pict_type; int ret = ff_get_encode_buffer(avctx, pkt, cx_frame->sz, 0); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, - "Error getting output packet of size %"SIZE_SPECIFIER".\n", cx_frame->sz); + "Error getting output packet of size %zu.\n", cx_frame->sz); return ret; } memcpy(pkt->data, cx_frame->buf, pkt->size); @@ -1080,8 +1095,8 @@ static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, pict_type = AV_PICTURE_TYPE_P; } - ff_side_data_set_encoder_stats(pkt, 0, cx_frame->sse + 1, - cx_frame->have_sse ? 3 : 0, pict_type); + ff_encode_add_stats_side_data(pkt, 0, cx_frame->sse + 1, + cx_frame->have_sse ? 3 : 0, pict_type); if (cx_frame->have_sse) { int i; @@ -1163,7 +1178,7 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out) if (!cx_frame->buf) { av_log(avctx, AV_LOG_ERROR, - "Data buffer alloc (%"SIZE_SPECIFIER" bytes) failed\n", + "Data buffer alloc (%zu bytes) failed\n", cx_frame->sz); av_freep(&cx_frame); return AVERROR(ENOMEM); @@ -1254,6 +1269,7 @@ static int aom_encode(AVCodecContext *avctx, AVPacket *pkt, if (frame) { rawimg = &ctx->rawimg; + aom_img_remove_metadata(rawimg); rawimg->planes[AOM_PLANE_Y] = frame->data[0]; rawimg->planes[AOM_PLANE_U] = frame->data[1]; rawimg->planes[AOM_PLANE_V] = frame->data[2]; @@ -1270,13 +1286,7 @@ static int aom_encode(AVCodecContext *avctx, AVPacket *pkt, else if (avctx->framerate.num > 0 && avctx->framerate.den > 0) duration = av_rescale_q(1, av_inv_q(avctx->framerate), avctx->time_base); else { -FF_DISABLE_DEPRECATION_WARNINGS - duration = -#if FF_API_TICKS_PER_FRAME - avctx->ticks_per_frame ? avctx->ticks_per_frame : -#endif - 1; -FF_ENABLE_DEPRECATION_WARNINGS + duration = 1; } switch (frame->color_range) { @@ -1310,6 +1320,10 @@ FF_ENABLE_DEPRECATION_WARNINGS if (frame->pict_type == AV_PICTURE_TYPE_I) flags |= AOM_EFLAG_FORCE_KF; + + res = add_hdr_plus(avctx, rawimg, frame); + if (res < 0) + return res; } res = aom_codec_encode(&ctx->encoder, rawimg, timestamp, duration, flags); @@ -1326,7 +1340,7 @@ FF_ENABLE_DEPRECATION_WARNINGS avctx->stats_out = av_malloc(b64_size); if (!avctx->stats_out) { - av_log(avctx, AV_LOG_ERROR, "Stat buffer alloc (%"SIZE_SPECIFIER" bytes) failed\n", + av_log(avctx, AV_LOG_ERROR, "Stat buffer alloc (%zu bytes) failed\n", b64_size); return AVERROR(ENOMEM); } @@ -1464,7 +1478,6 @@ static av_cold int av1_init(AVCodecContext *avctx) return aom_init(avctx, aom_codec_av1_cx()); } -#define OFFSET(x) offsetof(AOMContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 8, VE}, diff --git a/libavcodec/libaribb24.c b/libavcodec/libaribb24.c index 009c995de..a26e45629 100644 --- a/libavcodec/libaribb24.c +++ b/libavcodec/libaribb24.c @@ -96,13 +96,13 @@ static int libaribb24_generate_ass_header(AVCodecContext *avctx) font_size = get_profile_font_size(avctx); avctx->subtitle_header = av_asprintf( - "[Script Info]\r\n" - "; Script generated by FFmpeg/Lavc%s\r\n" - "ScriptType: v4.00+\r\n" - "PlayResX: %d\r\n" - "PlayResY: %d\r\n" - "\r\n" - "[V4+ Styles]\r\n" + "[Script Info]\n" + "; Script generated by FFmpeg/Lavc%s\n" + "ScriptType: v4.00+\n" + "PlayResX: %d\n" + "PlayResY: %d\n" + "\n" + "[V4+ Styles]\n" /* ASSv4 header */ "Format: Name, " @@ -113,7 +113,7 @@ static int libaribb24_generate_ass_header(AVCodecContext *avctx) "Spacing, Angle, " "BorderStyle, Outline, Shadow, " "Alignment, MarginL, MarginR, MarginV, " - "Encoding\r\n" + "Encoding\n" "Style: " "Default," /* Name */ @@ -124,11 +124,11 @@ static int libaribb24_generate_ass_header(AVCodecContext *avctx) "0,0," /* Spacing, Angle */ "%d,1,0," /* BorderStyle, Outline, Shadow */ "%d,10,10,10," /* Alignment, Margin[LRV] */ - "0\r\n" /* Encoding */ + "0\n" /* Encoding */ - "\r\n" - "[Events]\r\n" - "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n", + "\n" + "[Events]\n" + "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n", !(avctx->flags & AV_CODEC_FLAG_BITEXACT) ? AV_STRINGIFY(LIBAVCODEC_VERSION) : "", plane_width, plane_height, ASS_DEFAULT_FONT, font_size, ASS_DEFAULT_COLOR, @@ -144,7 +144,7 @@ static int libaribb24_generate_ass_header(AVCodecContext *avctx) return 0; } -static int libaribb24_init(AVCodecContext *avctx) +static av_cold int libaribb24_init(AVCodecContext *avctx) { Libaribb24Context *b24 = avctx->priv_data; void(* arib_dec_init)(arib_decoder_t* decoder) = NULL; @@ -197,7 +197,7 @@ static int libaribb24_init(AVCodecContext *avctx) return 0; } -static int libaribb24_close(AVCodecContext *avctx) +static av_cold int libaribb24_close(AVCodecContext *avctx) { Libaribb24Context *b24 = avctx->priv_data; diff --git a/libavcodec/libaribcaption.c b/libavcodec/libaribcaption.c index 0b67d4177..66d18b9d3 100644 --- a/libavcodec/libaribcaption.c +++ b/libavcodec/libaribcaption.c @@ -250,7 +250,7 @@ static uint8_t clut_pick_or_set(ARIBCaptionContext *ctx, int r, int g, int b, in return c; } -/* initialiaze CLUT with each character colors */ +/* initialize CLUT with each character colors */ static void clut_init(ARIBCaptionContext *ctx, aribcc_caption_region_t *region) { aribcc_color_t text_color, back_color, stroke_color; @@ -522,14 +522,14 @@ static int set_ass_header(ARIBCaptionContext *ctx) av_freep(&avctx->subtitle_header); avctx->subtitle_header = av_asprintf( - "[Script Info]\r\n" - "ScriptType: v4.00+\r\n" - "PlayResX: %d\r\n" - "PlayResY: %d\r\n" - "WrapStyle: 2\r\n" /* 2: no word wrapping */ - "\r\n" + "[Script Info]\n" + "ScriptType: v4.00+\n" + "PlayResX: %d\n" + "PlayResY: %d\n" + "WrapStyle: 2\n" /* 2: no word wrapping */ + "\n" - "[V4+ Styles]\r\n" + "[V4+ Styles]\n" "Format: Name, " "Fontname, Fontsize, " "PrimaryColour, SecondaryColour, OutlineColour, BackColour, " @@ -538,7 +538,7 @@ static int set_ass_header(ARIBCaptionContext *ctx) "Spacing, Angle, " "BorderStyle, Outline, Shadow, " "Alignment, MarginL, MarginR, MarginV, " - "Encoding\r\n" + "Encoding\n" "Style: " "Default," /* Name */ @@ -549,11 +549,11 @@ static int set_ass_header(ARIBCaptionContext *ctx) "0,0," /* Spacing, Angle */ "%d,%d,%d," /* BorderStyle, Outline, Shadow */ "%d,10,10,10," /* Alignment, Margin[LRV] */ - "0\r\n" /* Encoding */ - "\r\n" + "0\n" /* Encoding */ + "\n" - "[Events]\r\n" - "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n", + "[Events]\n" + "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n", ctx->plane_width, ctx->plane_height, font_name, ctx->font_size, ASS_DEFAULT_COLOR, ASS_DEFAULT_COLOR, @@ -939,7 +939,7 @@ static void aribcaption_flush(AVCodecContext *avctx) ctx->readorder = 0; } -static int aribcaption_close(AVCodecContext *avctx) +static av_cold int aribcaption_close(AVCodecContext *avctx) { ARIBCaptionContext *ctx = avctx->priv_data; @@ -954,7 +954,7 @@ static int aribcaption_close(AVCodecContext *avctx) return 0; } -static int aribcaption_init(AVCodecContext *avctx) +static av_cold int aribcaption_init(AVCodecContext *avctx) { ARIBCaptionContext *ctx = avctx->priv_data; aribcc_profile_t profile; diff --git a/libavcodec/libcodec2.c b/libavcodec/libcodec2.c index ebcd20c44..889586572 100644 --- a/libavcodec/libcodec2.c +++ b/libavcodec/libcodec2.c @@ -104,13 +104,6 @@ static av_cold int libcodec2_init_encoder(AVCodecContext *avctx) { LibCodec2Context *c2 = avctx->priv_data; - //will need to be smarter once we get wideband support - if (avctx->sample_rate != 8000 || - avctx->sample_fmt != AV_SAMPLE_FMT_S16) { - av_log(avctx, AV_LOG_ERROR, "only 8 kHz 16-bit mono allowed\n"); - return AVERROR(EINVAL); - } - avctx->extradata = av_mallocz(CODEC2_EXTRADATA_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); if (!avctx->extradata) { return AVERROR(ENOMEM); @@ -182,9 +175,6 @@ const FFCodec ff_libcodec2_decoder = { .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_CODEC2, .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF, - .p.supported_samplerates = (const int[]){ 8000, 0 }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, { 0 } }, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, .priv_data_size = sizeof(LibCodec2Context), .init = libcodec2_init_decoder, @@ -199,9 +189,9 @@ const FFCodec ff_libcodec2_encoder = { .p.id = AV_CODEC_ID_CODEC2, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.supported_samplerates = (const int[]){ 8000, 0 }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, { 0 } }, + CODEC_SAMPLERATES(8000), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), .p.priv_class = &libcodec2_enc_class, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, .priv_data_size = sizeof(LibCodec2Context), diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c index ff67f44bd..14ec9842a 100644 --- a/libavcodec/libdav1d.c +++ b/libavcodec/libdav1d.c @@ -50,8 +50,6 @@ typedef struct Libdav1dContext { int pool_size; Dav1dData data; - int tile_threads; - int frame_threads; int max_frame_delay; int apply_grain; int operating_point; @@ -145,15 +143,14 @@ static void libdav1d_init_params(AVCodecContext *c, const Dav1dSequenceHeader *s c->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; break; } - c->colorspace = (enum AVColorSpace) seq->mtrx; - c->color_primaries = (enum AVColorPrimaries) seq->pri; - c->color_trc = (enum AVColorTransferCharacteristic) seq->trc; + if (seq->color_description_present) { + c->colorspace = (enum AVColorSpace) seq->mtrx; + c->color_primaries = (enum AVColorPrimaries) seq->pri; + c->color_trc = (enum AVColorTransferCharacteristic) seq->trc; + } c->color_range = seq->color_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; - if (seq->layout == DAV1D_PIXEL_LAYOUT_I444 && - seq->mtrx == DAV1D_MC_IDENTITY && - seq->pri == DAV1D_COLOR_PRI_BT709 && - seq->trc == DAV1D_TRC_SRGB) + if (seq->layout == DAV1D_PIXEL_LAYOUT_I444 && c->colorspace == AVCOL_SPC_RGB) c->pix_fmt = pix_fmt_rgb[seq->hbd]; else c->pix_fmt = pix_fmt[seq->layout][seq->hbd]; @@ -162,10 +159,14 @@ static void libdav1d_init_params(AVCodecContext *c, const Dav1dSequenceHeader *s (unsigned)seq->num_units_in_tick, (unsigned)seq->time_scale); +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS if (seq->film_grain_present) c->properties |= FF_CODEC_PROPERTY_FILM_GRAIN; else c->properties &= ~FF_CODEC_PROPERTY_FILM_GRAIN; +FF_ENABLE_DEPRECATION_WARNINGS +#endif } static av_cold int libdav1d_parse_extradata(AVCodecContext *c) @@ -211,11 +212,7 @@ static av_cold int libdav1d_init(AVCodecContext *c) { Libdav1dContext *dav1d = c->priv_data; Dav1dSettings s; -#if FF_DAV1D_VERSION_AT_LEAST(6,0) int threads = c->thread_count; -#else - int threads = (c->thread_count ? c->thread_count : av_cpu_count()) * 3 / 2; -#endif const AVPacketSideData *sd; int res; @@ -236,32 +233,14 @@ static av_cold int libdav1d_init(AVCodecContext *c) s.all_layers = dav1d->all_layers; if (dav1d->operating_point >= 0) s.operating_point = dav1d->operating_point; -#if FF_DAV1D_VERSION_AT_LEAST(6,2) s.strict_std_compliance = c->strict_std_compliance > 0; -#endif -#if FF_DAV1D_VERSION_AT_LEAST(6,0) - if (dav1d->frame_threads || dav1d->tile_threads) - s.n_threads = FFMAX(dav1d->frame_threads, dav1d->tile_threads); - else - s.n_threads = FFMIN(threads, DAV1D_MAX_THREADS); + s.n_threads = FFMIN(threads, DAV1D_MAX_THREADS); if (dav1d->max_frame_delay > 0 && (c->flags & AV_CODEC_FLAG_LOW_DELAY)) av_log(c, AV_LOG_WARNING, "Low delay mode requested, forcing max_frame_delay 1\n"); s.max_frame_delay = (c->flags & AV_CODEC_FLAG_LOW_DELAY) ? 1 : dav1d->max_frame_delay; av_log(c, AV_LOG_DEBUG, "Using %d threads, %d max_frame_delay\n", s.n_threads, s.max_frame_delay); -#else - s.n_tile_threads = dav1d->tile_threads - ? dav1d->tile_threads - : FFMIN(floor(sqrt(threads)), DAV1D_MAX_TILE_THREADS); - s.n_frame_threads = dav1d->frame_threads - ? dav1d->frame_threads - : FFMIN(ceil(threads / s.n_tile_threads), DAV1D_MAX_FRAME_THREADS); - if (dav1d->max_frame_delay > 0) - s.n_frame_threads = FFMIN(s.n_frame_threads, dav1d->max_frame_delay); - av_log(c, AV_LOG_DEBUG, "Using %d frame threads, %d tile threads\n", - s.n_frame_threads, s.n_tile_threads); -#endif #if FF_DAV1D_VERSION_AT_LEAST(6,8) if (c->skip_frame >= AVDISCARD_NONKEY) @@ -382,14 +361,86 @@ static int libdav1d_receive_frame_internal(AVCodecContext *c, Dav1dPicture *p) return res; } +static int parse_itut_t35_metadata(Libdav1dContext *dav1d, Dav1dPicture *p, + const Dav1dITUTT35 *itut_t35, AVCodecContext *c, + AVFrame *frame) { + GetByteContext gb; + int provider_code, country_code; + int res; + + bytestream2_init(&gb, itut_t35->payload, itut_t35->payload_size); + + provider_code = bytestream2_get_be16(&gb); + country_code = itut_t35->country_code; + if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_ATSC) { + uint32_t user_identifier = bytestream2_get_be32(&gb); + switch (user_identifier) { + case MKBETAG('G', 'A', '9', '4'): { // closed captions + AVBufferRef *buf = NULL; + + res = ff_parse_a53_cc(&buf, gb.buffer, bytestream2_get_bytes_left(&gb)); + if (res < 0) + return res; + if (!res) + return 0; // no cc found, ignore + + res = ff_frame_new_side_data_from_buf(c, frame, AV_FRAME_DATA_A53_CC, &buf); + if (res < 0) + return res; + +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS + c->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + break; + } + default: // ignore unsupported identifiers + break; + } + } else if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_SAMSUNG) { + AVDynamicHDRPlus *hdrplus; + int provider_oriented_code = bytestream2_get_be16(&gb); + int application_identifier = bytestream2_get_byte(&gb); + + if (provider_oriented_code != 1 || application_identifier != 4) + return 0; // ignore + + hdrplus = av_dynamic_hdr_plus_create_side_data(frame); + if (!hdrplus) + return AVERROR(ENOMEM); + + res = av_dynamic_hdr_plus_from_t35(hdrplus, gb.buffer, + bytestream2_get_bytes_left(&gb)); + if (res < 0) + return res; + } else if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_DOLBY) { + int provider_oriented_code = bytestream2_get_be32(&gb); + if (provider_oriented_code != 0x800) + return 0; // ignore + + res = ff_dovi_rpu_parse(&dav1d->dovi, gb.buffer, bytestream2_get_bytes_left(&gb), + c->err_recognition); + if (res < 0) { + av_log(c, AV_LOG_WARNING, "Error parsing DOVI OBU.\n"); + return 0; // ignore + } + + res = ff_dovi_attach_side_data(&dav1d->dovi, frame); + if (res < 0) + return res; + } else { + // ignore unsupported provider codes + } + return 0; +} + static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) { Libdav1dContext *dav1d = c->priv_data; Dav1dPicture pic = { 0 }, *p = &pic; const AVPacket *pkt; -#if FF_DAV1D_VERSION_AT_LEAST(5,1) enum Dav1dEventFlags event_flags = 0; -#endif int res; do { @@ -415,12 +466,10 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) frame->linesize[1] = p->stride[1]; frame->linesize[2] = p->stride[1]; -#if FF_DAV1D_VERSION_AT_LEAST(5,1) dav1d_get_event_flags(dav1d->c, &event_flags); - if (c->pix_fmt == AV_PIX_FMT_NONE || - event_flags & DAV1D_EVENT_FLAG_NEW_SEQUENCE) -#endif - libdav1d_init_params(c, p->seq_hdr); + if (c->pix_fmt == AV_PIX_FMT_NONE || event_flags & DAV1D_EVENT_FLAG_NEW_SEQUENCE) + libdav1d_init_params(c, p->seq_hdr); + res = ff_decode_frame_props(c, frame); if (res < 0) goto fail; @@ -510,79 +559,9 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) #else const Dav1dITUTT35 *itut_t35 = p->itut_t35; #endif - GetByteContext gb; - int provider_code; - - bytestream2_init(&gb, itut_t35->payload, itut_t35->payload_size); - - provider_code = bytestream2_get_be16(&gb); - switch (provider_code) { - case ITU_T_T35_PROVIDER_CODE_ATSC: { - uint32_t user_identifier = bytestream2_get_be32(&gb); - switch (user_identifier) { - case MKBETAG('G', 'A', '9', '4'): { // closed captions - AVBufferRef *buf = NULL; - - res = ff_parse_a53_cc(&buf, gb.buffer, bytestream2_get_bytes_left(&gb)); - if (res < 0) - goto fail; - if (!res) - break; - - res = ff_frame_new_side_data_from_buf(c, frame, AV_FRAME_DATA_A53_CC, &buf); - if (res < 0) - goto fail; - - c->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; - break; - } - default: // ignore unsupported identifiers - break; - } - break; - } - case ITU_T_T35_PROVIDER_CODE_SMTPE: { - AVDynamicHDRPlus *hdrplus; - int provider_oriented_code = bytestream2_get_be16(&gb); - int application_identifier = bytestream2_get_byte(&gb); - - if (itut_t35->country_code != ITU_T_T35_COUNTRY_CODE_US || - provider_oriented_code != 1 || application_identifier != 4) - break; - - hdrplus = av_dynamic_hdr_plus_create_side_data(frame); - if (!hdrplus) { - res = AVERROR(ENOMEM); - goto fail; - } - - res = av_dynamic_hdr_plus_from_t35(hdrplus, gb.buffer, - bytestream2_get_bytes_left(&gb)); - if (res < 0) - goto fail; - break; - } - case ITU_T_T35_PROVIDER_CODE_DOLBY: { - int provider_oriented_code = bytestream2_get_be32(&gb); - if (itut_t35->country_code != ITU_T_T35_COUNTRY_CODE_US || - provider_oriented_code != 0x800) - break; - - res = ff_dovi_rpu_parse(&dav1d->dovi, gb.buffer, gb.buffer_end - gb.buffer, - c->err_recognition); - if (res < 0) { - av_log(c, AV_LOG_WARNING, "Error parsing DOVI OBU.\n"); - break; // ignore - } - - res = ff_dovi_attach_side_data(&dav1d->dovi, frame); - if (res < 0) - goto fail; - break; - } - default: // ignore unsupported provider codes - break; - } + res = parse_itut_t35_metadata(dav1d, p, itut_t35, c, frame); + if (res < 0) + goto fail; #if FF_DAV1D_VERSION_AT_LEAST(6,9) } #endif @@ -669,8 +648,6 @@ static av_cold int libdav1d_close(AVCodecContext *c) #define OFFSET(x) offsetof(Libdav1dContext, x) #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM static const AVOption libdav1d_options[] = { - { "tilethreads", "Tile threads", OFFSET(tile_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_TILE_THREADS, VD | AV_OPT_FLAG_DEPRECATED }, - { "framethreads", "Frame threads", OFFSET(frame_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_FRAME_THREADS, VD | AV_OPT_FLAG_DEPRECATED }, { "max_frame_delay", "Max frame delay", OFFSET(max_frame_delay), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_FRAME_DELAY, VD }, { "filmgrain", "Apply Film Grain", OFFSET(apply_grain), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VD | AV_OPT_FLAG_DEPRECATED }, { "oppoint", "Select an operating point of the scalable bitstream", OFFSET(operating_point), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 31, VD }, diff --git a/libavcodec/libfdk-aacenc.c b/libavcodec/libfdk-aacenc.c index 4dcfb25db..6c28633fb 100644 --- a/libavcodec/libfdk-aacenc.c +++ b/libavcodec/libfdk-aacenc.c @@ -530,7 +530,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts, &avpkt->duration); - discard_padding = avctx->frame_size - avpkt->duration; + discard_padding = avctx->frame_size - ff_samples_from_time_base(avctx, avpkt->duration); // Check if subtraction resulted in an overflow if ((discard_padding < avctx->frame_size) != (avpkt->duration > 0)) { av_log(avctx, AV_LOG_ERROR, "discard padding overflow\n"); @@ -607,12 +607,11 @@ const FFCodec ff_libfdk_aac_encoder = { FF_CODEC_ENCODE_CB(aac_encode_frame), .flush = aac_encode_flush, .close = aac_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.priv_class = &aac_enc_class, .defaults = aac_encode_defaults, .p.profiles = profiles, - .p.supported_samplerates = aac_sample_rates, + CODEC_SAMPLERATES_ARRAY(aac_sample_rates), .p.wrapper_name = "libfdk", - .p.ch_layouts = aac_ch_layouts, + CODEC_CH_LAYOUTS_ARRAY(aac_ch_layouts), }; diff --git a/libavcodec/libgsmenc.c b/libavcodec/libgsmenc.c index 505b6afb0..6b4786a8a 100644 --- a/libavcodec/libgsmenc.c +++ b/libavcodec/libgsmenc.c @@ -127,9 +127,8 @@ const FFCodec ff_libgsm_encoder = { FF_CODEC_ENCODE_CB(libgsm_encode_frame), .close = libgsm_encode_close, .defaults = libgsm_defaults, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.wrapper_name = "libgsm", .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, }; @@ -145,9 +144,8 @@ const FFCodec ff_libgsm_ms_encoder = { FF_CODEC_ENCODE_CB(libgsm_encode_frame), .close = libgsm_encode_close, .defaults = libgsm_defaults, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.wrapper_name = "libgsm", .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, }; diff --git a/libavcodec/libilbc.c b/libavcodec/libilbc.c index 9ca90bf0c..9a43e566f 100644 --- a/libavcodec/libilbc.c +++ b/libavcodec/libilbc.c @@ -99,8 +99,7 @@ static int ilbc_decode_frame(AVCodecContext *avctx, AVFrame *frame, #if LIBILBC_VERSION_MAJOR < 3 av_log(avctx, AV_LOG_ERROR, "iLBC frame too short (%u, should be %u)\n", #else - av_log(avctx, AV_LOG_ERROR, "iLBC frame too short (%u, should be " - "%"SIZE_SPECIFIER")\n", + av_log(avctx, AV_LOG_ERROR, "iLBC frame too short (%u, should be %zu)\n", #endif buf_size, s->decoder.no_of_bytes); return AVERROR_INVALIDDATA; @@ -210,8 +209,7 @@ const FFCodec ff_libilbc_encoder = { .priv_data_size = sizeof(ILBCEncContext), .init = ilbc_encode_init, FF_CODEC_ENCODE_CB(ilbc_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .defaults = ilbc_encode_defaults, .p.priv_class = &ilbc_enc_class, .p.wrapper_name = "libbilbc", diff --git a/libavcodec/libjxldec.c b/libavcodec/libjxldec.c index 9dfc261e3..a2f125998 100644 --- a/libavcodec/libjxldec.c +++ b/libavcodec/libjxldec.c @@ -29,6 +29,7 @@ #include "libavutil/common.h" #include "libavutil/csp.h" #include "libavutil/error.h" +#include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" @@ -37,6 +38,7 @@ #include "avcodec.h" #include "codec_internal.h" #include "decode.h" +#include "exif_internal.h" #include "internal.h" #include @@ -59,6 +61,11 @@ typedef struct LibJxlDecodeContext { int prev_is_last; AVRational anim_timebase; AVFrame *frame; + int frame_complete; + JxlDecoderStatus jret; + AVBufferRef *exif; + size_t exif_pos; + int exif_box; } LibJxlDecodeContext; static int libjxl_init_jxl_decoder(AVCodecContext *avctx) @@ -66,17 +73,24 @@ static int libjxl_init_jxl_decoder(AVCodecContext *avctx) LibJxlDecodeContext *ctx = avctx->priv_data; ctx->events = JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE - | JXL_DEC_COLOR_ENCODING | JXL_DEC_FRAME; + | JXL_DEC_COLOR_ENCODING | JXL_DEC_FRAME + | JXL_DEC_BOX; if (JxlDecoderSubscribeEvents(ctx->decoder, ctx->events) != JXL_DEC_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Error subscribing to JXL events\n"); return AVERROR_EXTERNAL; } + if (JxlDecoderSetDecompressBoxes(ctx->decoder, JXL_TRUE) != JXL_DEC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Error setting compress box mode\n"); + return AVERROR_EXTERNAL; + } + if (JxlDecoderSetParallelRunner(ctx->decoder, JxlThreadParallelRunner, ctx->runner) != JXL_DEC_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to set JxlThreadParallelRunner\n"); return AVERROR_EXTERNAL; } + av_buffer_unref(&ctx->exif); memset(&ctx->basic_info, 0, sizeof(JxlBasicInfo)); memset(&ctx->jxl_pixfmt, 0, sizeof(JxlPixelFormat)); ctx->prev_is_last = 1; @@ -360,10 +374,62 @@ static int libjxl_color_encoding_event(AVCodecContext *avctx, AVFrame *frame) return 0; } +static int libjxl_attach_sidedata(AVCodecContext *avctx) +{ + LibJxlDecodeContext *ctx = avctx->priv_data; + int ret = 0; + + if (ctx->iccp) { + ret = ff_frame_new_side_data_from_buf(avctx, ctx->frame, AV_FRAME_DATA_ICC_PROFILE, &ctx->iccp); + if (ret < 0) + return ret; + } + + if (ctx->exif) { + AVExifMetadata ifd = { 0 }; + /* size may be larger than exif_pos due to the realloc loop */ + ret = av_exif_parse_buffer(avctx, ctx->exif->data, ctx->exif_pos, &ifd, AV_EXIF_T_OFF); + av_buffer_unref(&ctx->exif); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to parse EXIF buffer: %s\n", av_err2str(ret)); + return ret; + } + /* + * JPEG XL Codestream orientation overrides EXIF orientation in all cases. + * As a result, we remove the EXIF Orientation tag rather than just zeroing it + * in order to prevent any ambiguity. libjxl autorotates the image for us so we + * do not need to worry about that. + */ + ret = av_exif_remove_entry(avctx, &ifd, av_exif_get_tag_id("Orientation"), 0); + if (ret < 0) + av_log(avctx, AV_LOG_WARNING, "Unable to remove orientation from EXIF buffer: %s\n", av_err2str(ret)); + ret = ff_decode_exif_attach_ifd(avctx, ctx->frame, &ifd); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "Unable to attach EXIF ifd: %s\n", av_err2str(ret)); + av_exif_free(&ifd); + } + + return ret; +} + +static int libjxl_finalize_frame(AVCodecContext *avctx, AVFrame *dst, AVFrame *src) +{ + LibJxlDecodeContext *ctx = avctx->priv_data; + if (ctx->exif_box) { + /* last box was Exif */ + size_t remainder = JxlDecoderReleaseBoxBuffer(ctx->decoder); + ctx->exif_pos = ctx->exif->size - remainder; + ctx->exif_box = 0; + } + int ret = libjxl_attach_sidedata(avctx); + av_frame_move_ref(dst, src); + ctx->frame_complete = 0; + return ret; +} + static int libjxl_receive_frame(AVCodecContext *avctx, AVFrame *frame) { LibJxlDecodeContext *ctx = avctx->priv_data; - JxlDecoderStatus jret = JXL_DEC_SUCCESS; int ret; AVPacket *pkt = ctx->avpkt; @@ -380,35 +446,45 @@ static int libjxl_receive_frame(AVCodecContext *avctx, AVFrame *frame) ctx->frame_duration = 0; if (!pkt->size) { /* jret set by the last iteration of the loop */ - if (jret == JXL_DEC_NEED_MORE_INPUT) { + if (ctx->jret == JXL_DEC_NEED_MORE_INPUT && !ctx->frame_complete) { av_log(avctx, AV_LOG_ERROR, "Unexpected end of JXL codestream\n"); return AVERROR_INVALIDDATA; - } else { - return AVERROR_EOF; + } else if (ctx->frame_complete) { + ctx->jret = JXL_DEC_SUCCESS; + goto success; } + return AVERROR_EOF; } } - jret = JxlDecoderSetInput(ctx->decoder, pkt->data, pkt->size); - if (jret == JXL_DEC_ERROR) { + ctx->jret = JxlDecoderSetInput(ctx->decoder, pkt->data, pkt->size); + if (ctx->jret == JXL_DEC_ERROR) { /* this should never happen here unless there's a bug in libjxl */ av_log(avctx, AV_LOG_ERROR, "Unknown libjxl decode error\n"); return AVERROR_EXTERNAL; } - jret = JxlDecoderProcessInput(ctx->decoder); + ctx->jret = JxlDecoderProcessInput(ctx->decoder); /* * JxlDecoderReleaseInput returns the number * of bytes remaining to be read, rather than * the number of bytes that it did read */ remaining = JxlDecoderReleaseInput(ctx->decoder); - pkt->data += pkt->size - remaining; + size_t consumed = pkt->size - remaining; + pkt->data += consumed; pkt->size = remaining; - switch(jret) { + switch(ctx->jret) { case JXL_DEC_ERROR: av_log(avctx, AV_LOG_ERROR, "Unknown libjxl decode error\n"); + /* + * we consume all remaining input on error, if nothing was consumed + * this prevents libjxl from consuming nothing forever + * and just dumping the last error over and over + */ + if (!consumed) + av_packet_unref(pkt); return AVERROR_INVALIDDATA; case JXL_DEC_NEED_MORE_INPUT: av_log(avctx, AV_LOG_DEBUG, "NEED_MORE_INPUT event emitted\n"); @@ -433,6 +509,12 @@ static int libjxl_receive_frame(AVCodecContext *avctx, AVFrame *frame) if (ctx->basic_info.have_animation) ctx->anim_timebase = av_make_q(ctx->basic_info.animation.tps_denominator, ctx->basic_info.animation.tps_numerator); + if (ctx->basic_info.alpha_bits) { + if (ctx->basic_info.alpha_premultiplied) + avctx->alpha_mode = AVALPHA_MODE_PREMULTIPLIED; + else + avctx->alpha_mode = AVALPHA_MODE_STRAIGHT; + } continue; case JXL_DEC_COLOR_ENCODING: av_log(avctx, AV_LOG_DEBUG, "COLOR_ENCODING event emitted\n"); @@ -482,11 +564,6 @@ static int libjxl_receive_frame(AVCodecContext *avctx, AVFrame *frame) case JXL_DEC_FULL_IMAGE: /* full image is one frame, even if animated */ av_log(avctx, AV_LOG_DEBUG, "FULL_IMAGE event emitted\n"); - if (ctx->iccp) { - ret = ff_frame_new_side_data_from_buf(avctx, ctx->frame, AV_FRAME_DATA_ICC_PROFILE, &ctx->iccp); - if (ret < 0) - return ret; - } if (ctx->basic_info.have_animation) { ctx->frame->pts = av_rescale_q(ctx->accumulated_pts, ctx->anim_timebase, avctx->pkt_timebase); ctx->frame->duration = av_rescale_q(ctx->frame_duration, ctx->anim_timebase, avctx->pkt_timebase); @@ -498,8 +575,13 @@ static int libjxl_receive_frame(AVCodecContext *avctx, AVFrame *frame) ctx->frame->pts += pkt->pts; ctx->accumulated_pts += ctx->frame_duration; ctx->frame->pkt_dts = pkt->dts; - av_frame_move_ref(frame, ctx->frame); - return 0; + if (ctx->basic_info.have_animation && !ctx->prev_is_last) { + libjxl_finalize_frame(avctx, frame, ctx->frame); + return 0; + } else { + ctx->frame_complete = 1; + continue; + } case JXL_DEC_SUCCESS: av_log(avctx, AV_LOG_DEBUG, "SUCCESS event emitted\n"); /* @@ -508,11 +590,57 @@ static int libjxl_receive_frame(AVCodecContext *avctx, AVFrame *frame) * but it will also be fired when the next image of * an image2pipe sequence is loaded up */ +success: + libjxl_finalize_frame(avctx, frame, ctx->frame); JxlDecoderReset(ctx->decoder); libjxl_init_jxl_decoder(avctx); + return 0; + case JXL_DEC_BOX: { + char type[4]; + av_log(avctx, AV_LOG_DEBUG, "BOX event emitted\n"); + if (ctx->exif_box) { + /* last box was Exif */ + size_t remainder = JxlDecoderReleaseBoxBuffer(ctx->decoder); + ctx->exif_pos = ctx->exif->size - remainder; + } + if (JxlDecoderGetBoxType(ctx->decoder, type, JXL_TRUE) != JXL_DEC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Error getting box type\n"); + return AVERROR_EXTERNAL; + } + if (AV_RL32(type) != MKTAG('E','x','i','f')) { + ctx->exif_box = 0; + continue; + } + ctx->exif_box = 1; + av_buffer_unref(&ctx->exif); + ctx->exif_pos = 0; + // 4k buffer should usually be enough + ret = av_buffer_realloc(&ctx->exif, 4096); + if (ret < 0) + return AVERROR(ENOMEM); + if (JxlDecoderSetBoxBuffer(ctx->decoder, ctx->exif->data, ctx->exif->size) != JXL_DEC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Error setting box buffer\n"); + return AVERROR_EXTERNAL; + } continue; + } + case JXL_DEC_BOX_NEED_MORE_OUTPUT: { + av_log(avctx, AV_LOG_DEBUG, "BOX_NEED_MORE_OUTPUT event emitted\n"); + size_t remainder = JxlDecoderReleaseBoxBuffer(ctx->decoder); + ctx->exif_pos = ctx->exif->size - remainder; + size_t new_size = ctx->exif->size << 1; + ret = av_buffer_realloc(&ctx->exif, new_size); + if (ret < 0) + return AVERROR(ENOMEM); + if (JxlDecoderSetBoxBuffer(ctx->decoder, ctx->exif->data + ctx->exif_pos, + ctx->exif->size - ctx->exif_pos) != JXL_DEC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Error setting box buffer\n"); + return AVERROR_EXTERNAL; + } + continue; + } default: - av_log(avctx, AV_LOG_ERROR, "Bad libjxl event: %d\n", jret); + av_log(avctx, AV_LOG_ERROR, "Bad libjxl event: %d\n", ctx->jret); return AVERROR_EXTERNAL; } } @@ -528,6 +656,7 @@ static av_cold int libjxl_decode_close(AVCodecContext *avctx) if (ctx->decoder) JxlDecoderDestroy(ctx->decoder); ctx->decoder = NULL; + av_buffer_unref(&ctx->exif); av_buffer_unref(&ctx->iccp); av_frame_free(&ctx->frame); @@ -549,3 +678,19 @@ const FFCodec ff_libjxl_decoder = { FF_CODEC_CAP_ICC_PROFILES, .p.wrapper_name = "libjxl", }; + +const FFCodec ff_libjxl_anim_decoder = { + .p.name = "libjxl_anim", + CODEC_LONG_NAME("libjxl JPEG XL animated"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_JPEGXL_ANIM, + .priv_data_size = sizeof(LibJxlDecodeContext), + .init = libjxl_decode_init, + FF_CODEC_RECEIVE_FRAME_CB(libjxl_receive_frame), + .close = libjxl_decode_close, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_OTHER_THREADS, + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | + FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_ICC_PROFILES, + .p.wrapper_name = "libjxl", +}; diff --git a/libavcodec/libjxlenc.c b/libavcodec/libjxlenc.c index 8b0e60df6..ca4606154 100644 --- a/libavcodec/libjxlenc.c +++ b/libavcodec/libjxlenc.c @@ -28,6 +28,7 @@ #include "libavutil/avutil.h" #include "libavutil/csp.h" +#include "libavutil/display.h" #include "libavutil/error.h" #include "libavutil/frame.h" #include "libavutil/libm.h" @@ -40,6 +41,7 @@ #include "avcodec.h" #include "encode.h" #include "codec_internal.h" +#include "exif_internal.h" #include #include @@ -56,6 +58,13 @@ typedef struct LibJxlEncodeContext { int xyb; uint8_t *buffer; size_t buffer_size; + JxlPixelFormat jxl_fmt; + AVBufferRef *exif_buffer; + + /* animation stuff */ + AVFrame *frame; + AVFrame *prev; + int64_t duration; } LibJxlEncodeContext; /** @@ -87,9 +96,9 @@ static float quality_to_distance(float quality) } /** - * Initalize the encoder on a per-frame basis. All of these need to be set - * once each time the encoder is reset, which it must be each frame to make - * the image2 muxer work. + * Initialize the encoder on a per-file basis. All of these need to be set + * once each time the encoder is reset, which is each frame for still + * images, to make the image2 muxer work. For animation this is run once. * * @return 0 upon success, negative on failure. */ @@ -100,12 +109,6 @@ static int libjxl_init_jxl_encoder(AVCodecContext *avctx) /* reset the encoder every frame for image2 muxer */ JxlEncoderReset(ctx->encoder); - ctx->options = JxlEncoderFrameSettingsCreate(ctx->encoder, NULL); - if (!ctx->options) { - av_log(avctx, AV_LOG_ERROR, "Failed to create JxlEncoderOptions\n"); - return AVERROR_EXTERNAL; - } - /* This needs to be set each time the encoder is reset */ if (JxlEncoderSetParallelRunner(ctx->encoder, JxlThreadParallelRunner, ctx->runner) != JXL_ENC_SUCCESS) { @@ -113,42 +116,9 @@ static int libjxl_init_jxl_encoder(AVCodecContext *avctx) return AVERROR_EXTERNAL; } - /* these shouldn't fail, libjxl bug notwithstanding */ - if (JxlEncoderFrameSettingsSetOption(ctx->options, JXL_ENC_FRAME_SETTING_EFFORT, ctx->effort) - != JXL_ENC_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set effort to: %d\n", ctx->effort); - return AVERROR_EXTERNAL; - } - - /* check for negative, our default */ - if (ctx->distance < 0.0) { - /* use ffmpeg.c -q option if passed */ - if (avctx->flags & AV_CODEC_FLAG_QSCALE) - ctx->distance = quality_to_distance((float)avctx->global_quality / FF_QP2LAMBDA); - else - /* default 1.0 matches cjxl */ - ctx->distance = 1.0; - } - - /* - * 0.01 is the minimum distance accepted for lossy - * interpreting any positive value less than this as minimum - */ - if (ctx->distance > 0.0 && ctx->distance < 0.01) - ctx->distance = 0.01; - if (JxlEncoderSetFrameDistance(ctx->options, ctx->distance) != JXL_ENC_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set distance: %f\n", ctx->distance); - return AVERROR_EXTERNAL; - } - - /* - * In theory the library should automatically enable modular if necessary, - * but it appears it won't at the moment due to a bug. This will still - * work even if that is patched. - */ - if (JxlEncoderFrameSettingsSetOption(ctx->options, JXL_ENC_FRAME_SETTING_MODULAR, - ctx->modular || ctx->distance <= 0.0 ? 1 : -1) != JXL_ENC_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set modular\n"); + ctx->options = JxlEncoderFrameSettingsCreate(ctx->encoder, NULL); + if (!ctx->options) { + av_log(avctx, AV_LOG_ERROR, "Failed to create JxlEncoderOptions\n"); return AVERROR_EXTERNAL; } @@ -185,6 +155,47 @@ static av_cold int libjxl_encode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); } + /* check for negative, our default */ + if (ctx->distance < 0.0) { + /* use ffmpeg.c -q option if passed */ + if (avctx->flags & AV_CODEC_FLAG_QSCALE) + ctx->distance = quality_to_distance((float)avctx->global_quality / FF_QP2LAMBDA); + else + /* default 1.0 matches cjxl */ + ctx->distance = 1.0; + } + /* + * 0.01 is the minimum distance accepted for lossy + * interpreting any positive value less than this as minimum + */ + if (ctx->distance > 0.0 && ctx->distance < 0.01) + ctx->distance = 0.01; + + return 0; +} + +/** + * Initializer for the animation encoder. This calls the other initializers + * to prevent code duplication and also allocates the prev-frame used in the + * encoder. + */ +static av_cold int libjxl_anim_encode_init(AVCodecContext *avctx) +{ + int ret; + LibJxlEncodeContext *ctx = avctx->priv_data; + + ret = libjxl_encode_init(avctx); + if (ret < 0) + return ret; + + ret = libjxl_init_jxl_encoder(avctx); + if (ret < 0) + return ret; + + ctx->frame = av_frame_alloc(); + if (!ctx->frame) + return AVERROR(ENOMEM); + return 0; } @@ -239,83 +250,12 @@ static int libjxl_populate_primaries(void *avctx, JxlColorEncoding *jxl_color, e return 0; } -/** - * Encode an entire frame. Currently animation, is not supported by - * this encoder, so this will always reinitialize a new still image - * and encode a one-frame image (for image2 and image2pipe). - */ -static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet) +static int libjxl_populate_colorspace(AVCodecContext *avctx, const AVFrame *frame, + const AVPixFmtDescriptor *pix_desc, const JxlBasicInfo *info) { - LibJxlEncodeContext *ctx = avctx->priv_data; - AVFrameSideData *sd; - const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(frame->format); - JxlBasicInfo info; JxlColorEncoding jxl_color; - JxlPixelFormat jxl_fmt; - int bits_per_sample; -#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0) - JxlBitDepth jxl_bit_depth; -#endif - JxlEncoderStatus jret; + LibJxlEncodeContext *ctx = avctx->priv_data; int ret; - size_t available = ctx->buffer_size; - size_t bytes_written = 0; - uint8_t *next_out = ctx->buffer; - const uint8_t *data; - - ret = libjxl_init_jxl_encoder(avctx); - if (ret) { - av_log(avctx, AV_LOG_ERROR, "Error frame-initializing JxlEncoder\n"); - return ret; - } - - /* populate the basic info settings */ - JxlEncoderInitBasicInfo(&info); - jxl_fmt.num_channels = pix_desc->nb_components; - info.xsize = frame->width; - info.ysize = frame->height; - info.num_extra_channels = (jxl_fmt.num_channels + 1) % 2; - info.num_color_channels = jxl_fmt.num_channels - info.num_extra_channels; - bits_per_sample = av_get_bits_per_pixel(pix_desc) / jxl_fmt.num_channels; - info.bits_per_sample = avctx->bits_per_raw_sample > 0 && !(pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT) - ? avctx->bits_per_raw_sample : bits_per_sample; - info.alpha_bits = (info.num_extra_channels > 0) * info.bits_per_sample; - if (pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT) { - info.exponent_bits_per_sample = info.bits_per_sample > 16 ? 8 : 5; - info.alpha_exponent_bits = info.alpha_bits ? info.exponent_bits_per_sample : 0; - jxl_fmt.data_type = info.bits_per_sample > 16 ? JXL_TYPE_FLOAT : JXL_TYPE_FLOAT16; - } else { - info.exponent_bits_per_sample = 0; - info.alpha_exponent_bits = 0; - jxl_fmt.data_type = info.bits_per_sample <= 8 ? JXL_TYPE_UINT8 : JXL_TYPE_UINT16; - } - -#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0) - jxl_bit_depth.bits_per_sample = bits_per_sample; - jxl_bit_depth.type = JXL_BIT_DEPTH_FROM_PIXEL_FORMAT; - jxl_bit_depth.exponent_bits_per_sample = pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT ? - info.exponent_bits_per_sample : 0; -#endif - - /* JPEG XL format itself does not support limited range */ - if (avctx->color_range == AVCOL_RANGE_MPEG || - avctx->color_range == AVCOL_RANGE_UNSPECIFIED && frame->color_range == AVCOL_RANGE_MPEG) - av_log(avctx, AV_LOG_WARNING, "This encoder does not support limited (tv) range, colors will be wrong!\n"); - else if (avctx->color_range != AVCOL_RANGE_JPEG && frame->color_range != AVCOL_RANGE_JPEG) - av_log(avctx, AV_LOG_WARNING, "Unknown color range, assuming full (pc)\n"); - - /* bitexact lossless requires there to be no XYB transform */ - info.uses_original_profile = ctx->distance == 0.0 || !ctx->xyb; - info.orientation = frame->linesize[0] >= 0 ? JXL_ORIENT_IDENTITY : JXL_ORIENT_FLIP_VERTICAL; - - if (JxlEncoderSetBasicInfo(ctx->encoder, &info) != JXL_ENC_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set JxlBasicInfo\n"); - return AVERROR_EXTERNAL; - } - - /* rendering intent doesn't matter here - * but libjxl will whine if we don't set it */ - jxl_color.rendering_intent = JXL_RENDERING_INTENT_RELATIVE; switch (frame->color_trc && frame->color_trc != AVCOL_TRC_UNSPECIFIED ? frame->color_trc : avctx->color_trc) { @@ -347,64 +287,313 @@ static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFra break; default: if (pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT) { - av_log(avctx, AV_LOG_WARNING, "Unknown transfer function, assuming Linear Light. Colors may be wrong.\n"); + av_log(avctx, AV_LOG_WARNING, + "Unknown transfer function, assuming Linear Light. Colors may be wrong.\n"); jxl_color.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR; } else { - av_log(avctx, AV_LOG_WARNING, "Unknown transfer function, assuming IEC61966-2-1/sRGB. Colors may be wrong.\n"); + av_log(avctx, AV_LOG_WARNING, + "Unknown transfer function, assuming IEC61966-2-1/sRGB. Colors may be wrong.\n"); jxl_color.transfer_function = JXL_TRANSFER_FUNCTION_SRGB; } } - /* This should be implied to be honest - * but a libjxl bug makes it fail otherwise */ - if (info.num_color_channels == 1) + jxl_color.rendering_intent = JXL_RENDERING_INTENT_RELATIVE; + if (info->num_color_channels == 1) jxl_color.color_space = JXL_COLOR_SPACE_GRAY; else jxl_color.color_space = JXL_COLOR_SPACE_RGB; ret = libjxl_populate_primaries(avctx, &jxl_color, - frame->color_primaries && frame->color_primaries != AVCOL_PRI_UNSPECIFIED - ? frame->color_primaries : avctx->color_primaries); + frame->color_primaries && frame->color_primaries != AVCOL_PRI_UNSPECIFIED + ? frame->color_primaries : avctx->color_primaries); if (ret < 0) return ret; - sd = av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE); - if (sd && sd->size && JxlEncoderSetICCProfile(ctx->encoder, sd->data, sd->size) != JXL_ENC_SUCCESS) - av_log(avctx, AV_LOG_WARNING, "Could not set ICC Profile\n"); - if (JxlEncoderSetColorEncoding(ctx->encoder, &jxl_color) != JXL_ENC_SUCCESS) + if (JxlEncoderSetColorEncoding(ctx->encoder, &jxl_color) != JXL_ENC_SUCCESS) { av_log(avctx, AV_LOG_WARNING, "Failed to set JxlColorEncoding\n"); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int libjxl_add_boxes(AVCodecContext *avctx) +{ + LibJxlEncodeContext *ctx = avctx->priv_data; + JxlEncoderStatus jret = JXL_ENC_SUCCESS; + int ret = 0, opened = 0; + + /* no boxes need to be added */ + if (!ctx->exif_buffer) + goto end; + + jret = JxlEncoderUseBoxes(ctx->encoder); + if (jret != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_WARNING, "Could not enable UseBoxes\n"); + ret = AVERROR_EXTERNAL; + goto end; + } + opened = 1; + + jret = JxlEncoderAddBox(ctx->encoder, "Exif", ctx->exif_buffer->data, ctx->exif_buffer->size, JXL_TRUE); + if (jret != JXL_ENC_SUCCESS) + jret = JxlEncoderAddBox(ctx->encoder, "Exif", ctx->exif_buffer->data, ctx->exif_buffer->size, JXL_FALSE); + if (jret != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_WARNING, "Failed to add Exif box\n"); + ret = AVERROR_EXTERNAL; + goto end; + } + +end: + if (opened) + JxlEncoderCloseBoxes(ctx->encoder); + + return ret; +} + +/** + * Sends metadata to libjxl based on the first frame of the stream, such as pixel format, + * orientation, bit depth, and that sort of thing. + */ +static int libjxl_preprocess_stream(AVCodecContext *avctx, const AVFrame *frame, int animated) +{ + LibJxlEncodeContext *ctx = avctx->priv_data; + AVFrameSideData *sd; + int32_t *matrix = (int32_t[9]){ 0 }; + int ret = 0, have_matrix = 0; + JxlEncoderStatus jret = JXL_ENC_SUCCESS; + const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(frame->format); + JxlBasicInfo info; + JxlPixelFormat *jxl_fmt = &ctx->jxl_fmt; + int bits_per_sample; + int orientation; +#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0) + JxlBitDepth jxl_bit_depth; +#endif + + /* populate the basic info settings */ + JxlEncoderInitBasicInfo(&info); + jxl_fmt->num_channels = pix_desc->nb_components; + info.xsize = frame->width; + info.ysize = frame->height; + info.num_extra_channels = (jxl_fmt->num_channels + 1) & 0x1; + info.num_color_channels = jxl_fmt->num_channels - info.num_extra_channels; + bits_per_sample = av_get_bits_per_pixel(pix_desc) / jxl_fmt->num_channels; + info.bits_per_sample = avctx->bits_per_raw_sample > 0 && !(pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT) + ? avctx->bits_per_raw_sample : bits_per_sample; + info.alpha_bits = (info.num_extra_channels > 0) * info.bits_per_sample; + if (pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT) { + info.exponent_bits_per_sample = info.bits_per_sample > 16 ? 8 : 5; + info.alpha_exponent_bits = info.alpha_bits ? info.exponent_bits_per_sample : 0; + jxl_fmt->data_type = info.bits_per_sample > 16 ? JXL_TYPE_FLOAT : JXL_TYPE_FLOAT16; + } else { + info.exponent_bits_per_sample = 0; + info.alpha_exponent_bits = 0; + jxl_fmt->data_type = info.bits_per_sample <= 8 ? JXL_TYPE_UINT8 : JXL_TYPE_UINT16; + } + + if (info.alpha_bits) { + if (avctx->alpha_mode == AVALPHA_MODE_PREMULTIPLIED || + avctx->alpha_mode == AVALPHA_MODE_UNSPECIFIED && frame->alpha_mode == AVALPHA_MODE_PREMULTIPLIED) { + info.alpha_premultiplied = 1; + } else if (avctx->alpha_mode != AVALPHA_MODE_STRAIGHT && frame->alpha_mode != AVALPHA_MODE_STRAIGHT) { + av_log(avctx, AV_LOG_WARNING, "Unknown alpha mode, assuming straight (independent)\n"); + } + } #if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0) - if (JxlEncoderSetFrameBitDepth(ctx->options, &jxl_bit_depth) != JXL_ENC_SUCCESS) + jxl_bit_depth.bits_per_sample = bits_per_sample; + jxl_bit_depth.type = JXL_BIT_DEPTH_FROM_PIXEL_FORMAT; + jxl_bit_depth.exponent_bits_per_sample = pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT ? + info.exponent_bits_per_sample : 0; +#endif + + /* JPEG XL format itself does not support limited range */ + if (avctx->color_range == AVCOL_RANGE_MPEG || + avctx->color_range == AVCOL_RANGE_UNSPECIFIED && frame->color_range == AVCOL_RANGE_MPEG) + av_log(avctx, AV_LOG_WARNING, "This encoder does not support limited (tv) range, colors will be wrong!\n"); + else if (avctx->color_range != AVCOL_RANGE_JPEG && frame->color_range != AVCOL_RANGE_JPEG) + av_log(avctx, AV_LOG_WARNING, "Unknown color range, assuming full (pc)\n"); + + /* bitexact lossless requires there to be no XYB transform */ + info.uses_original_profile = ctx->distance == 0.0 || !ctx->xyb; + + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX); + if (sd) { + matrix = (int32_t *) sd->data; + have_matrix = 1; + } + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_EXIF); + if (sd) { + AVExifMetadata ifd = { 0 }; + AVExifEntry *orient = NULL; + uint16_t tag = av_exif_get_tag_id("Orientation"); + ret = av_exif_parse_buffer(avctx, sd->data, sd->size, &ifd, AV_EXIF_TIFF_HEADER); + if (ret >= 0) + ret = ff_exif_sanitize_ifd(avctx, frame, &ifd); + if (ret >= 0) + ret = av_exif_get_entry(avctx, &ifd, tag, 0, &orient); + if (ret >= 0 && orient) { + if (!have_matrix && orient->value.uint[0] >= 1 && orient->value.uint[0] <= 8) { + av_exif_orientation_to_matrix(matrix, orient->value.uint[0]); + have_matrix = 1; + } + /* pop the orientation tag anyway, because it only creates */ + /* ambiguity with the codestream orientation taking precdence */ + ret = av_exif_remove_entry(avctx, &ifd, tag, 0); + } + if (ret >= 0) + ret = av_exif_write(avctx, &ifd, &ctx->exif_buffer, AV_EXIF_T_OFF); + if (ret < 0) + av_log(avctx, AV_LOG_WARNING, "unable to process EXIF frame data\n"); + av_exif_free(&ifd); + } + + /* use identity matrix as default */ + if (!have_matrix) + av_exif_orientation_to_matrix(matrix, 1); + + /* av_display_matrix_flip is a right-multipilcation */ + /* i.e. flip is applied before the previous matrix */ + if (frame->linesize < 0) + av_display_matrix_flip(matrix, 0, 1); + + orientation = av_exif_matrix_to_orientation(matrix); + /* JPEG XL orientation flag agrees with EXIF for values 1-8 */ + if (orientation) { + info.orientation = orientation; + } else { + av_log(avctx, AV_LOG_WARNING, "singular displaymatrix data\n"); + info.orientation = frame->linesize[0] >= 0 ? JXL_ORIENT_IDENTITY : JXL_ORIENT_FLIP_VERTICAL; + } + + /* restore the previous value */ + if (frame->linesize < 0) + av_display_matrix_flip(matrix, 0, 1); + + if (animated) { + info.have_animation = 1; + info.animation.have_timecodes = 0; + info.animation.num_loops = 0; + /* avctx->timebase is in seconds per tick, so we take the reciprocol */ + info.animation.tps_numerator = avctx->time_base.den; + info.animation.tps_denominator = avctx->time_base.num; + } + + jret = JxlEncoderSetBasicInfo(ctx->encoder, &info); + if (jret != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set JxlBasicInfo\n"); + ret = AVERROR_EXTERNAL; + goto end; + } + + if (info.alpha_bits) { + JxlExtraChannelInfo extra_info; + JxlEncoderInitExtraChannelInfo(JXL_CHANNEL_ALPHA, &extra_info); + extra_info.bits_per_sample = info.alpha_bits; + extra_info.exponent_bits_per_sample = info.alpha_exponent_bits; + extra_info.alpha_premultiplied = info.alpha_premultiplied; + jret = JxlEncoderSetExtraChannelInfo(ctx->encoder, 0, &extra_info); + if (jret != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set JxlExtraChannelInfo for alpha!\n"); + ret = AVERROR_EXTERNAL; + goto end; + } + } + + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE); + if (sd && sd->size) { + jret = JxlEncoderSetICCProfile(ctx->encoder, sd->data, sd->size); + if (jret != JXL_ENC_SUCCESS) + av_log(avctx, AV_LOG_WARNING, "Could not set ICC Profile\n"); + } + + /* jret != JXL_ENC_SUCCESS means fallthrough from above */ + if (!sd || !sd->size || jret != JXL_ENC_SUCCESS) + libjxl_populate_colorspace(avctx, frame, pix_desc, &info); + +#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0) + jret = JxlEncoderSetFrameBitDepth(ctx->options, &jxl_bit_depth); + if (jret != JXL_ENC_SUCCESS) av_log(avctx, AV_LOG_WARNING, "Failed to set JxlBitDepth\n"); #endif /* depending on basic info, level 10 might * be required instead of level 5 */ if (JxlEncoderGetRequiredCodestreamLevel(ctx->encoder) > 5) { - if (JxlEncoderSetCodestreamLevel(ctx->encoder, 10) != JXL_ENC_SUCCESS) + jret = JxlEncoderSetCodestreamLevel(ctx->encoder, 10); + if (jret != JXL_ENC_SUCCESS) av_log(avctx, AV_LOG_WARNING, "Could not increase codestream level\n"); } - jxl_fmt.endianness = JXL_NATIVE_ENDIAN; - if (frame->linesize[0] >= 0) { - jxl_fmt.align = frame->linesize[0]; - data = frame->data[0]; - } else { - jxl_fmt.align = -frame->linesize[0]; - data = frame->data[0] + frame->linesize[0] * (info.ysize - 1); + libjxl_add_boxes(avctx); + +end: + av_buffer_unref(&ctx->exif_buffer); + return ret; +} + +/** + * Sends frame information to libjxl on a per-frame basis. If this is a still image, + * this is evaluated once per output file. If this is an animated JPEG XL encode, it + * is called once per frame. + * + * This returns a buffer to the data that should be passed to libjxl (via the + * argument **data). If the linesize is nonnegative, this will be frame->data[0], + * although if the linesize is negative, it will be the start of the buffer + * instead. *data is just a pointer to a location in frame->data so it should not be + * freed directly. + */ +static int libjxl_preprocess_frame(AVCodecContext *avctx, const AVFrame *frame, const uint8_t **data) +{ + LibJxlEncodeContext *ctx = avctx->priv_data; + JxlPixelFormat *jxl_fmt = &ctx->jxl_fmt; + + /* these shouldn't fail, libjxl bug notwithstanding */ + if (JxlEncoderFrameSettingsSetOption(ctx->options, JXL_ENC_FRAME_SETTING_EFFORT, ctx->effort) + != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set effort to: %d\n", ctx->effort); + return AVERROR_EXTERNAL; } - if (JxlEncoderAddImageFrame(ctx->options, &jxl_fmt, data, jxl_fmt.align * info.ysize) != JXL_ENC_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to add Image Frame\n"); + if (JxlEncoderSetFrameDistance(ctx->options, ctx->distance) != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set distance: %f\n", ctx->distance); return AVERROR_EXTERNAL; } /* - * Run this after the last frame in the image has been passed. - * TODO support animation + * In theory the library should automatically enable modular if necessary, + * but it appears it won't at the moment due to a bug. This will still + * work even if that is patched. */ - JxlEncoderCloseInput(ctx->encoder); + if (JxlEncoderFrameSettingsSetOption(ctx->options, JXL_ENC_FRAME_SETTING_MODULAR, + ctx->modular || ctx->distance <= 0.0 ? 1 : -1) != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set modular\n"); + return AVERROR_EXTERNAL; + } + + jxl_fmt->endianness = JXL_NATIVE_ENDIAN; + if (frame->linesize[0] >= 0) { + jxl_fmt->align = frame->linesize[0]; + *data = frame->data[0]; + } else { + jxl_fmt->align = -frame->linesize[0]; + *data = frame->data[0] + frame->linesize[0] * (frame->height - 1); + } + + return 0; +} + +/** + * Run libjxl's output processing loop, reallocating the packet as necessary + * if libjxl needs more space to work with. + */ +static int libjxl_process_output(AVCodecContext *avctx, size_t *bytes_written) +{ + LibJxlEncodeContext *ctx = avctx->priv_data; + JxlEncoderStatus jret; + size_t available = ctx->buffer_size; + uint8_t *next_out = ctx->buffer; while (1) { jret = JxlEncoderProcessOutput(ctx->encoder, &next_out, &available); @@ -412,7 +601,7 @@ static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFra av_log(avctx, AV_LOG_ERROR, "Unspecified libjxl error occurred\n"); return AVERROR_EXTERNAL; } - bytes_written = ctx->buffer_size - available; + *bytes_written = ctx->buffer_size - available; /* all data passed has been encoded */ if (jret == JXL_ENC_SUCCESS) break; @@ -429,14 +618,58 @@ static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFra return AVERROR(ENOMEM); ctx->buffer = temp; ctx->buffer_size = new_size; - next_out = ctx->buffer + bytes_written; - available = new_size - bytes_written; + next_out = ctx->buffer + *bytes_written; + available = new_size - *bytes_written; continue; } av_log(avctx, AV_LOG_ERROR, "Bad libjxl event: %d\n", jret); return AVERROR_EXTERNAL; } + return 0; +} + +/** + * Encode an entire frame. This will always reinitialize a new still image + * and encode a one-frame image (for image2 and image2pipe). + */ +static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet) +{ + + LibJxlEncodeContext *ctx = avctx->priv_data; + int ret; + size_t bytes_written = 0; + const uint8_t *data; + + ret = libjxl_init_jxl_encoder(avctx); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error frame-initializing JxlEncoder\n"); + return ret; + } + + ret = libjxl_preprocess_stream(avctx, frame, 0); + if (ret < 0) + return ret; + + ret = libjxl_preprocess_frame(avctx, frame, &data); + if (ret < 0) + return ret; + + if (JxlEncoderAddImageFrame(ctx->options, &ctx->jxl_fmt, data, ctx->jxl_fmt.align * frame->height) + != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to add Image Frame\n"); + return AVERROR_EXTERNAL; + } + + /* + * Run this after the last frame in the image has been passed. + */ + JxlEncoderCloseInput(ctx->encoder); + + ret = libjxl_process_output(avctx, &bytes_written); + if (ret < 0) + return ret; + ret = ff_get_encode_buffer(avctx, pkt, bytes_written, 0); if (ret < 0) return ret; @@ -447,6 +680,94 @@ static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFra return 0; } +/** + * Encode one frame of the animation. libjxl requires us to set duration of the frame + * but we're only promised the PTS, not the duration. As a result we have to buffer + * a frame and subtract the PTS from the last PTS. The last frame uses the previous + * frame's calculated duration as a fallback if its duration field is unset. + * + * We also need to tell libjxl if our frame is the last one, which we won't know upon + * receiving a single frame, so we have to buffer a frame as well and send the "last frame" + * upon receiving the special EOF frame. + */ +static int libjxl_anim_encode_frame(AVCodecContext *avctx, AVPacket *pkt) +{ + LibJxlEncodeContext *ctx = avctx->priv_data; + int ret = 0; + JxlFrameHeader frame_header; + size_t bytes_written = 0; + const uint8_t *data; + + if (!ctx->prev) { + ctx->prev = av_frame_alloc(); + if (!ctx->prev) + return AVERROR(ENOMEM); + ret = ff_encode_get_frame(avctx, ctx->prev); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + return ret; + ret = libjxl_preprocess_stream(avctx, ctx->prev, 1); + if (ret < 0) + return ret; + } + + ret = ff_encode_get_frame(avctx, ctx->frame); + if (ret == AVERROR_EOF) { + av_frame_free(&ctx->frame); + ret = 0; + } + if (ret == AVERROR(EAGAIN)) + return ret; + + JxlEncoderInitFrameHeader(&frame_header); + + ctx->duration = ctx->prev->duration ? ctx->prev->duration : + ctx->frame ? ctx->frame->pts - ctx->prev->pts : + ctx->duration ? ctx->duration : + 1; + + frame_header.duration = ctx->duration; + pkt->duration = ctx->duration; + pkt->pts = ctx->prev->pts; + pkt->dts = pkt->pts; + + if (JxlEncoderSetFrameHeader(ctx->options, &frame_header) != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set JxlFrameHeader\n"); + return AVERROR_EXTERNAL; + } + + ret = libjxl_preprocess_frame(avctx, ctx->prev, &data); + if (ret < 0) + return ret; + + if (JxlEncoderAddImageFrame(ctx->options, &ctx->jxl_fmt, data, ctx->jxl_fmt.align * ctx->prev->height) + != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to add Image Frame\n"); + return AVERROR_EXTERNAL; + } + + if (!ctx->frame) + JxlEncoderCloseInput(ctx->encoder); + + ret = libjxl_process_output(avctx, &bytes_written); + if (ret < 0) + return ret; + + ret = ff_get_encode_buffer(avctx, pkt, bytes_written, 0); + if (ret < 0) + return ret; + + memcpy(pkt->data, ctx->buffer, bytes_written); + + if (ctx->frame) { + av_frame_unref(ctx->prev); + av_frame_move_ref(ctx->prev, ctx->frame); + } else { + av_frame_free(&ctx->prev); + } + + return ret; +} + static av_cold int libjxl_encode_close(AVCodecContext *avctx) { LibJxlEncodeContext *ctx = avctx->priv_data; @@ -464,6 +785,8 @@ static av_cold int libjxl_encode_close(AVCodecContext *avctx) ctx->encoder = NULL; av_freep(&ctx->buffer); + av_frame_free(&ctx->prev); + av_frame_free(&ctx->frame); return 0; } @@ -488,6 +811,16 @@ static const AVClass libjxl_encode_class = { .version = LIBAVUTIL_VERSION_INT, }; +static const enum AVPixelFormat libjxl_supported_pixfmts[] = { + AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64, + AV_PIX_FMT_RGBF32, AV_PIX_FMT_RGBAF32, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_YA8, + AV_PIX_FMT_GRAY16, AV_PIX_FMT_YA16, + AV_PIX_FMT_GRAYF32, + AV_PIX_FMT_NONE, +}; + const FFCodec ff_libjxl_encoder = { .p.name = "libjxl", CODEC_LONG_NAME("libjxl JPEG XL"), @@ -503,15 +836,29 @@ const FFCodec ff_libjxl_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_ICC_PROFILES, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64, - AV_PIX_FMT_RGBF32, AV_PIX_FMT_RGBAF32, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_YA8, - AV_PIX_FMT_GRAY16, AV_PIX_FMT_YA16, - AV_PIX_FMT_GRAYF32, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS_ARRAY(libjxl_supported_pixfmts), + .alpha_modes = AVALPHA_MODE_STRAIGHT | AVALPHA_MODE_PREMULTIPLIED, + .p.priv_class = &libjxl_encode_class, + .p.wrapper_name = "libjxl", +}; + +const FFCodec ff_libjxl_anim_encoder = { + .p.name = "libjxl_anim", + CODEC_LONG_NAME("libjxl JPEG XL animated"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_JPEGXL_ANIM, + .priv_data_size = sizeof(LibJxlEncodeContext), + .init = libjxl_anim_encode_init, + FF_CODEC_RECEIVE_PACKET_CB(libjxl_anim_encode_frame), + .close = libjxl_encode_close, + .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | + AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | + FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_ICC_PROFILES, + CODEC_PIXFMTS_ARRAY(libjxl_supported_pixfmts), + .alpha_modes = AVALPHA_MODE_STRAIGHT | AVALPHA_MODE_PREMULTIPLIED, .p.priv_class = &libjxl_encode_class, .p.wrapper_name = "libjxl", }; diff --git a/libavcodec/libkvazaar.c b/libavcodec/libkvazaar.c index e82be2a35..908c7a038 100644 --- a/libavcodec/libkvazaar.c +++ b/libavcodec/libkvazaar.c @@ -29,7 +29,6 @@ #include "libavutil/dict.h" #include "libavutil/error.h" #include "libavutil/imgutils.h" -#include "libavutil/internal.h" #include "libavutil/log.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" @@ -38,7 +37,6 @@ #include "avcodec.h" #include "codec_internal.h" #include "encode.h" -#include "packet_internal.h" typedef struct LibkvazaarContext { const AVClass *class; @@ -86,13 +84,7 @@ static av_cold int libkvazaar_init(AVCodecContext *avctx) cfg->framerate_denom = avctx->framerate.den; } else { cfg->framerate_num = avctx->time_base.den; -FF_DISABLE_DEPRECATION_WARNINGS - cfg->framerate_denom = avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + cfg->framerate_denom = avctx->time_base.num; } cfg->target_bitrate = avctx->bit_rate; cfg->vui.sar_width = avctx->sample_aspect_ratio.num; @@ -180,7 +172,6 @@ static int libkvazaar_encode(AVCodecContext *avctx, kvz_data_chunk *data_out = NULL; uint32_t len_out = 0; int retval = 0; - int pict_type; *got_packet_ptr = 0; @@ -274,6 +265,7 @@ static int libkvazaar_encode(AVCodecContext *avctx, avpkt->flags |= AV_PKT_FLAG_KEY; } + enum AVPictureType pict_type; switch (frame_info.slice_type) { case KVZ_SLICE_I: pict_type = AV_PICTURE_TYPE_I; @@ -289,7 +281,7 @@ static int libkvazaar_encode(AVCodecContext *avctx, return AVERROR_EXTERNAL; } - ff_side_data_set_encoder_stats(avpkt, frame_info.qp * FF_QP2LAMBDA, NULL, 0, pict_type); + ff_encode_add_stats_side_data(avpkt, frame_info.qp * FF_QP2LAMBDA, NULL, 0, pict_type); *got_packet_ptr = 1; } @@ -333,7 +325,7 @@ const FFCodec ff_libkvazaar_encoder = { .p.id = AV_CODEC_ID_HEVC, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS, - .p.pix_fmts = pix_fmts, + CODEC_PIXFMTS_ARRAY(pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, diff --git a/libavcodec/liblc3dec.c b/libavcodec/liblc3dec.c index d250ace38..b27c2ee90 100644 --- a/libavcodec/liblc3dec.c +++ b/libavcodec/liblc3dec.c @@ -82,10 +82,11 @@ static av_cold int liblc3_decode_init(AVCodecContext *avctx) (char *)liblc3->decoder_mem + ch * decoder_size); } - avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; + avctx->sample_fmt = avctx->request_sample_fmt == AV_SAMPLE_FMT_FLT ? + AV_SAMPLE_FMT_FLT : AV_SAMPLE_FMT_FLTP; + avctx->delay = lc3_hr_delay_samples( liblc3->hr_mode, liblc3->frame_us, liblc3->srate_hz); - avctx->internal->skip_samples = avctx->delay; return 0; } @@ -113,11 +114,16 @@ static int liblc3_decode(AVCodecContext *avctx, AVFrame *frame, return ret; block_bytes = avpkt->size; + int is_planar = avctx->sample_fmt == AV_SAMPLE_FMT_FLTP; + for (int ch = 0; ch < channels; ch++) { int nbytes = block_bytes / channels + (ch < block_bytes % channels); + float *pcm_data = is_planar ? (float*)frame->extended_data[ch] : + (float*)frame->extended_data[0] + ch; + int stride = is_planar ? 1 : channels; ret = lc3_decode(liblc3->decoder[ch], in, nbytes, - LC3_PCM_FORMAT_FLOAT, frame->data[ch], 1); + LC3_PCM_FORMAT_FLOAT, pcm_data, stride); if (ret < 0) return AVERROR_INVALIDDATA; diff --git a/libavcodec/liblc3enc.c b/libavcodec/liblc3enc.c index 3c0bcc684..e64963b45 100644 --- a/libavcodec/liblc3enc.c +++ b/libavcodec/liblc3enc.c @@ -137,7 +137,6 @@ static int liblc3_encode(AVCodecContext *avctx, AVPacket *pkt, LibLC3EncContext *liblc3 = avctx->priv_data; int block_bytes = liblc3->block_bytes; int channels = avctx->ch_layout.nb_channels; - void *zero_frame = NULL; uint8_t *data_ptr; int ret; @@ -152,25 +151,27 @@ static int liblc3_encode(AVCodecContext *avctx, AVPacket *pkt, return 0; liblc3->remaining_samples = 0; - zero_frame = av_mallocz(avctx->frame_size * sizeof(float)); - if (!zero_frame) - return AVERROR(ENOMEM); } + int is_planar = avctx->sample_fmt == AV_SAMPLE_FMT_FLTP; + data_ptr = pkt->data; for (int ch = 0; ch < channels; ch++) { - const float *pcm = zero_frame ? zero_frame : frame->data[ch]; int nbytes = block_bytes / channels + (ch < block_bytes % channels); + const float *pcm = frame ? + (is_planar ? (const float*)frame->data[ch] : + (const float*)frame->data[0] + ch) : + (const float[]){ 0 }; + + int stride = frame ? (is_planar ? 1 : channels) : 0; + lc3_encode(liblc3->encoder[ch], - LC3_PCM_FORMAT_FLOAT, pcm, 1, nbytes, data_ptr); + LC3_PCM_FORMAT_FLOAT, pcm, stride, nbytes, data_ptr); data_ptr += nbytes; } - if (zero_frame) - av_free(zero_frame); - *got_packet_ptr = 1; return 0; @@ -201,12 +202,10 @@ const FFCodec ff_liblc3_encoder = { .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_LC3, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .p.supported_samplerates = (const int []) - { 96000, 48000, 32000, 24000, 16000, 8000, 0 }, - .p.sample_fmts = (const enum AVSampleFormat[]) - { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, .p.priv_class = &class, .p.wrapper_name = "liblc3", + CODEC_SAMPLERATES(96000, 48000, 32000, 24000, 16000, 8000), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), .priv_data_size = sizeof(LibLC3EncContext), .init = liblc3_encode_init, .close = liblc3_encode_close, diff --git a/libavcodec/libmp3lame.c b/libavcodec/libmp3lame.c index 42558178e..339505ccf 100644 --- a/libavcodec/libmp3lame.c +++ b/libavcodec/libmp3lame.c @@ -285,7 +285,7 @@ static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts, &avpkt->duration); - discard_padding = avctx->frame_size - avpkt->duration; + discard_padding = avctx->frame_size - ff_samples_from_time_base(avctx, avpkt->duration); // Check if subtraction resulted in an overflow if ((discard_padding < avctx->frame_size) != (avpkt->duration > 0)) { av_log(avctx, AV_LOG_ERROR, "discard padding overflow\n"); @@ -348,15 +348,9 @@ const FFCodec ff_libmp3lame_encoder = { .init = mp3lame_encode_init, FF_CODEC_ENCODE_CB(mp3lame_encode_frame), .close = mp3lame_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = libmp3lame_sample_rates, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 }, - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16P), + CODEC_SAMPLERATES_ARRAY(libmp3lame_sample_rates), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), .p.priv_class = &libmp3lame_class, .defaults = libmp3lame_defaults, .p.wrapper_name = "libmp3lame", diff --git a/libavcodec/libmpeghdec.c b/libavcodec/libmpeghdec.c new file mode 100644 index 000000000..ecc3a2dc0 --- /dev/null +++ b/libavcodec/libmpeghdec.c @@ -0,0 +1,231 @@ +/* + * MPEG-H 3D Audio Decoder Wrapper + * Copyright (C) 2025 Fraunhofer Institute for Integrated Circuits IIS + * + * 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 + */ + +/* + * Please note that this FFmpeg Software is licensed under the LGPL-2.1 + * but is combined with software that is licensed under different terms, namely + * the "Software License for The Fraunhofer FDK MPEG-H Software". Fraunhofer + * as the initial licensor does not interpret the LGPL-2.1 as requiring + * distribution of the MPEG-H Software under the LGPL-2.1 if being distributed + * together with this FFmpeg Software. Therefore, downstream distribution of + * FFmpeg Software does not imply any right to redistribute the MPEG-H Software + * under the LGPL-2.1. + */ +#include +#include + +#include "libavutil/channel_layout.h" +#include "libavutil/frame.h" +#include "libavutil/mem.h" + +#include "codec_internal.h" +#include "decode.h" + +#define MAX_LOST_FRAMES 2 +// max framesize * (max delay frames + 1) +#define PER_CHANNEL_OUTBUF_SIZE (3072 * (MAX_LOST_FRAMES + 1)) + +typedef struct MPEGH3DADecContext { + // pointer to the decoder + HANDLE_MPEGH_DECODER_CONTEXT decoder; + + // Internal values + int32_t *decoder_buffer; + int decoder_buffer_size; ///< in samples +} MPEGH3DADecContext; + +static av_cold int mpegh3dadec_close(AVCodecContext *avctx) +{ + MPEGH3DADecContext *s = avctx->priv_data; + + if (s->decoder) + mpeghdecoder_destroy(s->decoder); + s->decoder = NULL; + av_freep(&s->decoder_buffer); + + return 0; +} + +// Lookup CICP for FFmpeg channel layout, see: +// https://github.com/Fraunhofer-IIS/mpeghdec/wiki/MPEG-H-decoder-target-layouts +static av_cold int channel_layout_to_cicp(const AVChannelLayout *layout) +{ +// different from AV_CH_LAYOUT_7POINT2POINT3 +#define CH_LAYOUT_7POINT2POINT3 AV_CH_LAYOUT_5POINT1POINT2 | AV_CH_SIDE_SURROUND_LEFT | \ + AV_CH_SIDE_SURROUND_RIGHT | AV_CH_TOP_BACK_CENTER | \ + AV_CH_LOW_FREQUENCY_2 +#define CH_LAYOUT_5POINT1POINT6 AV_CH_LAYOUT_5POINT1POINT4_BACK | \ + AV_CH_TOP_FRONT_CENTER | AV_CH_TOP_CENTER +#define CH_LAYOUT_7POINT1POINT6 AV_CH_LAYOUT_7POINT1POINT4_BACK | \ + AV_CH_TOP_FRONT_CENTER | AV_CH_TOP_CENTER + static const uint64_t channel_layout_masks[] = { + 0, + AV_CH_LAYOUT_MONO, AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_SURROUND, AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT0, AV_CH_LAYOUT_5POINT1, + AV_CH_LAYOUT_7POINT1_WIDE, 0, + AV_CH_LAYOUT_2_1, AV_CH_LAYOUT_2_2, + AV_CH_LAYOUT_6POINT1, AV_CH_LAYOUT_7POINT1, + AV_CH_LAYOUT_22POINT2, AV_CH_LAYOUT_5POINT1POINT2, + CH_LAYOUT_7POINT2POINT3, AV_CH_LAYOUT_5POINT1POINT4_BACK, + CH_LAYOUT_5POINT1POINT6, CH_LAYOUT_7POINT1POINT6, + AV_CH_LAYOUT_7POINT1POINT4_BACK, + }; + for (size_t i = 0; i < FF_ARRAY_ELEMS(channel_layout_masks); ++i) { + if (channel_layout_masks[i]) { + AVChannelLayout ch_layout; + av_channel_layout_from_mask(&ch_layout, channel_layout_masks[i]); + if (!av_channel_layout_compare(layout, &ch_layout)) + return i; + } + } + + return 0; +} + +static av_cold int mpegh3dadec_init(AVCodecContext *avctx) +{ + int cicp; + + MPEGH3DADecContext *s = avctx->priv_data; + + if (avctx->ch_layout.nb_channels == 0) { + av_log(avctx, AV_LOG_ERROR, "Channel layout needs to be specified\n"); + return AVERROR(EINVAL); + } else if ((cicp = channel_layout_to_cicp(&avctx->ch_layout)) <= 0) { + av_log(avctx, AV_LOG_ERROR, "Unsupported channel layout\n"); + return AVERROR(EINVAL); + } + + s->decoder = NULL; + + avctx->delay = 0; + avctx->sample_fmt = AV_SAMPLE_FMT_S32; + avctx->sample_rate = 48000; + + s->decoder_buffer_size = PER_CHANNEL_OUTBUF_SIZE * avctx->ch_layout.nb_channels; + s->decoder_buffer = av_malloc_array(s->decoder_buffer_size, sizeof(*s->decoder_buffer)); + if (!s->decoder_buffer) + return AVERROR(ENOMEM); + + // initialize the decoder + s->decoder = mpeghdecoder_init(cicp); + if (s->decoder == NULL) { + av_log(avctx, AV_LOG_ERROR, "MPEG-H decoder library init failed.\n"); + return AVERROR_EXTERNAL; + } + + if (avctx->extradata_size) { + if (mpeghdecoder_setMhaConfig(s->decoder, avctx->extradata, + avctx->extradata_size)) { + av_log(avctx, AV_LOG_ERROR, "Unable to set MHA configuration\n"); + return AVERROR_INVALIDDATA; + } + } + + return 0; +} + +static int mpegh3dadec_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, AVPacket *avpkt) +{ + MPEGH3DADecContext *s = avctx->priv_data; + int ret; + MPEGH_DECODER_ERROR err; + MPEGH_DECODER_OUTPUT_INFO out_info; + + if (!avctx->sample_rate) { + av_log(avctx, AV_LOG_ERROR, "Audio sample rate is not set"); + return AVERROR_INVALIDDATA; + } + + if (avpkt->data != NULL && avpkt->size > 0) { + if ((err = mpeghdecoder_processTimescale(s->decoder, avpkt->data, + avpkt->size, avpkt->pts, + avctx->sample_rate))) { + av_log(avctx, AV_LOG_ERROR, "mpeghdecoder_process() failed: %x\n", + err); + return AVERROR_INVALIDDATA; + } + } else { + // we are flushing + err = mpeghdecoder_flushAndGet(s->decoder); + + if (err != MPEGH_DEC_OK && err != MPEGH_DEC_FEED_DATA) + av_log(avctx, AV_LOG_WARNING, + "mpeghdecoder_flushAndGet() failed: %d\n", err); + } + + err = mpeghdecoder_getSamples(s->decoder, s->decoder_buffer, + s->decoder_buffer_size, + &out_info); + if (err == MPEGH_DEC_FEED_DATA) { + // no frames to produce at the moment + return avpkt->size; + } else if (err) { + av_log(avctx, AV_LOG_ERROR, "mpeghdecoder_getSamples() failed: %x\n", + err); + return AVERROR_UNKNOWN; + } + + frame->nb_samples = out_info.numSamplesPerChannel; + frame->sample_rate = avctx->sample_rate = out_info.sampleRate; + frame->pts = out_info.ticks; + frame->time_base.num = 1; + frame->time_base.den = out_info.sampleRate; + + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + memcpy(frame->extended_data[0], s->decoder_buffer, + avctx->ch_layout.nb_channels * frame->nb_samples * + sizeof(*s->decoder_buffer) /* only AV_SAMPLE_FMT_S32 is supported */); + + *got_frame_ptr = 1; + return ret = avpkt->size; +} + +static av_cold void mpegh3dadec_flush(AVCodecContext *avctx) +{ + MPEGH_DECODER_ERROR err; + MPEGH3DADecContext *s = avctx->priv_data; + + err = mpeghdecoder_flush(s->decoder); + + if (err != MPEGH_DEC_OK && err != MPEGH_DEC_FEED_DATA) + av_log(avctx, AV_LOG_WARNING, "mpeghdecoder_flush failed: %d\n", err); +} + +const FFCodec ff_libmpeghdec_decoder = { + .p.name = "libmpeghdec", + CODEC_LONG_NAME("libmpeghdec (MPEG-H 3D Audio)"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_MPEGH_3D_AUDIO, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_CHANNEL_CONF, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .priv_data_size = sizeof(MPEGH3DADecContext), + .init = mpegh3dadec_init, + FF_CODEC_DECODE_CB(mpegh3dadec_decode_frame), + .flush = mpegh3dadec_flush, + .close = mpegh3dadec_close, + .p.wrapper_name = "libmpeghdec", +}; diff --git a/libavcodec/liboapvenc.c b/libavcodec/liboapvenc.c new file mode 100644 index 000000000..84bd175ef --- /dev/null +++ b/libavcodec/liboapvenc.c @@ -0,0 +1,510 @@ +/* + * liboapv encoder + * Advanced Professional Video codec library + * + * Copyright (C) 2025 Dawid Kozinski + * + * 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 + +#include "libavutil/avassert.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/pixfmt.h" + +#include "avcodec.h" +#include "apv.h" +#include "codec_internal.h" +#include "encode.h" +#include "profiles.h" + +#define MAX_BS_BUF (128 * 1024 * 1024) +#define MAX_NUM_FRMS (1) // supports only 1-frame in an access unit +#define FRM_IDX (0) // supports only 1-frame in an access unit +#define MAX_NUM_CC (OAPV_MAX_CC) // Max number of color components (upto 4:4:4:4) + +/** + * The structure stores all the states associated with the instance of APV encoder + */ +typedef struct ApvEncContext { + const AVClass *class; + + oapve_t id; // APV instance identifier + oapvm_t mid; + oapve_cdesc_t cdsc; // coding parameters i.e profile, width & height of input frame, num of therads, frame rate ... + oapv_bitb_t bitb; // bitstream buffer (output) + oapve_stat_t stat; // encoding status (output) + + oapv_frms_t ifrms; // frames for input + + int num_frames; // number of frames in an access unit + + int preset_id; // preset of apv ( fastest, fast, medium, slow, placebo) + + int qp; // quantization parameter (QP) [0,63] + + AVDictionary *oapv_params; +} ApvEncContext; + +static int apv_imgb_release(oapv_imgb_t *imgb) +{ + int refcnt = --imgb->refcnt; + if (refcnt == 0) { + for (int i = 0; i < imgb->np; i++) + av_freep(&imgb->baddr[i]); + av_free(imgb); + } + + return refcnt; +} + +static int apv_imgb_addref(oapv_imgb_t * imgb) +{ + int refcnt = ++imgb->refcnt; + return refcnt; +} + +static int apv_imgb_getref(oapv_imgb_t * imgb) +{ + return imgb->refcnt; +} + +/** + * Convert FFmpeg pixel format (AVPixelFormat) into APV pre-defined color format + * + * @return APV pre-defined color format (@see oapv.h) on success, OAPV_CF_UNKNOWN on failure + */ +static inline int get_color_format(enum AVPixelFormat pix_fmt) +{ + int cf = OAPV_CF_UNKNOWN; + + switch (pix_fmt) { + case AV_PIX_FMT_GRAY10: + cf = OAPV_CF_YCBCR400; + break; + case AV_PIX_FMT_YUV422P10: + cf = OAPV_CF_YCBCR422; + break; + case AV_PIX_FMT_YUV422P12: + cf = OAPV_CF_YCBCR422; + break; + case AV_PIX_FMT_YUV444P10: + cf = OAPV_CF_YCBCR444; + break; + case AV_PIX_FMT_YUV444P12: + cf = OAPV_CF_YCBCR444; + break; + case AV_PIX_FMT_YUVA444P10: + cf = OAPV_CF_YCBCR4444; + break; + case AV_PIX_FMT_YUVA444P12: + cf = OAPV_CF_YCBCR4444; + break; + default: + av_assert0(cf != OAPV_CF_UNKNOWN); + } + + return cf; +} + +static oapv_imgb_t *apv_imgb_create(AVCodecContext *avctx) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); + oapv_imgb_t *imgb; + int input_depth; + int cfmt; // color format + int cs; + + av_assert0(desc); + + imgb = av_mallocz(sizeof(oapv_imgb_t)); + if (!imgb) + goto fail; + + input_depth = desc->comp[0].depth; + cfmt = get_color_format(avctx->pix_fmt); + cs = OAPV_CS_SET(cfmt, input_depth, AV_HAVE_BIGENDIAN); + + imgb->np = desc->nb_components; + + for (int i = 0; i < imgb->np; i++) { + imgb->w[i] = avctx->width >> ((i == 1 || i == 2) ? desc->log2_chroma_w : 0); + imgb->h[i] = avctx->height; + imgb->aw[i] = FFALIGN(imgb->w[i], OAPV_MB_W); + imgb->ah[i] = FFALIGN(imgb->h[i], OAPV_MB_H); + imgb->s[i] = imgb->aw[i] * OAPV_CS_GET_BYTE_DEPTH(cs); + + imgb->bsize[i] = imgb->e[i] = imgb->s[i] * imgb->ah[i]; + imgb->a[i] = imgb->baddr[i] = av_mallocz(imgb->bsize[i]); + if (imgb->a[i] == NULL) + goto fail; + } + + imgb->cs = cs; + imgb->addref = apv_imgb_addref; + imgb->getref = apv_imgb_getref; + imgb->release = apv_imgb_release; + imgb->refcnt = 1; + + return imgb; +fail: + av_log(avctx, AV_LOG_ERROR, "cannot create image buffer\n"); + if (imgb) { + for (int i = 0; i < imgb->np; i++) + av_freep(&imgb->a[i]); + av_freep(&imgb); + } + return NULL; +} + +/** + * The function returns a pointer to the object of the oapve_cdesc_t type. + * oapve_cdesc_t contains all encoder parameters that should be initialized before the encoder is used. + * + * The field values of the oapve_cdesc_t structure are populated based on: + * - the corresponding field values of the AvCodecConetxt structure, + * - the apv encoder specific option values, + * + * The order of processing input data and populating the apve_cdsc structure + * 1) first, the fields of the AVCodecContext structure corresponding to the provided input options are processed, + * (i.e -pix_fmt yuv422p -s:v 1920x1080 -r 30 -profile:v 0) + * 2) then apve-specific options added as AVOption to the apv AVCodec implementation + * (i.e -preset 0) + * + * Keep in mind that, there are options that can be set in different ways. + * In this case, please follow the above-mentioned order of processing. + * The most recent assignments overwrite the previous values. + * + * @param[in] avctx codec context (AVCodecContext) + * @param[out] cdsc contains all APV encoder encoder parameters that should be initialized before the encoder is use + * + * @return 0 on success, negative error code on failure + */ +static int get_conf(AVCodecContext *avctx, oapve_cdesc_t *cdsc) +{ + ApvEncContext *apv = avctx->priv_data; + + /* initialize apv_param struct with default values */ + int ret = oapve_param_default(&cdsc->param[FRM_IDX]); + if (OAPV_FAILED(ret)) { + av_log(avctx, AV_LOG_ERROR, "Cannot set default parameter\n"); + return AVERROR_EXTERNAL; + } + + /* read options from AVCodecContext */ + if (avctx->width > 0) + cdsc->param[FRM_IDX].w = avctx->width; + + if (avctx->height > 0) + cdsc->param[FRM_IDX].h = avctx->height; + + if (avctx->framerate.num > 0) { + cdsc->param[FRM_IDX].fps_num = avctx->framerate.num; + cdsc->param[FRM_IDX].fps_den = avctx->framerate.den; + } else if (avctx->time_base.num > 0) { + cdsc->param[FRM_IDX].fps_num = avctx->time_base.den; + cdsc->param[FRM_IDX].fps_den = avctx->time_base.num; + } + + cdsc->param[FRM_IDX].preset = apv->preset_id; + cdsc->param[FRM_IDX].qp = apv->qp; + if (avctx->bit_rate / 1000 > INT_MAX || avctx->rc_max_rate / 1000 > INT_MAX) { + av_log(avctx, AV_LOG_ERROR, "bit_rate and rc_max_rate > %d000 is not supported\n", INT_MAX); + return AVERROR(EINVAL); + } + cdsc->param[FRM_IDX].bitrate = (int)(avctx->bit_rate / 1000); + if (cdsc->param[FRM_IDX].bitrate) { + if (cdsc->param[FRM_IDX].qp) { + av_log(avctx, AV_LOG_WARNING, "You cannot set both the bitrate and the QP parameter at the same time.\n" + "If the bitrate is set, the rate control type is set to ABR, which means that the QP value is ignored.\n"); + } + cdsc->param[FRM_IDX].rc_type = OAPV_RC_ABR; + } + + cdsc->threads = avctx->thread_count; + + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) { + cdsc->param[FRM_IDX].color_primaries = avctx->color_primaries; + cdsc->param[FRM_IDX].color_description_present_flag = 1; + } + + if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED) { + cdsc->param[FRM_IDX].transfer_characteristics = avctx->color_trc; + cdsc->param[FRM_IDX].color_description_present_flag = 1; + } + + if (avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + cdsc->param[FRM_IDX].matrix_coefficients = avctx->colorspace; + cdsc->param[FRM_IDX].color_description_present_flag = 1; + } + + if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED) { + cdsc->param[FRM_IDX].full_range_flag = (avctx->color_range == AVCOL_RANGE_JPEG); + cdsc->param[FRM_IDX].color_description_present_flag = 1; + } + + cdsc->max_bs_buf_size = MAX_BS_BUF; /* maximum bitstream buffer size */ + cdsc->max_num_frms = MAX_NUM_FRMS; + + const AVDictionaryEntry *en = NULL; + while (en = av_dict_iterate(apv->oapv_params, en)) { + ret = oapve_param_parse(&cdsc->param[FRM_IDX], en->key, en->value); + if (ret < 0) + av_log(avctx, AV_LOG_WARNING, "Error parsing option '%s = %s'.\n", en->key, en->value); + } + + return 0; +} + +/** + * @brief Initialize APV codec + * Create an encoder instance and allocate all the needed resources + * + * @param avctx codec context + * @return 0 on success, negative error code on failure + */ +static av_cold int liboapve_init(AVCodecContext *avctx) +{ + ApvEncContext *apv = avctx->priv_data; + oapve_cdesc_t *cdsc = &apv->cdsc; + unsigned char *bs_buf; + int ret; + + /* allocate bitstream buffer */ + bs_buf = (unsigned char *)av_malloc(MAX_BS_BUF); + if (bs_buf == NULL) { + av_log(avctx, AV_LOG_ERROR, "Cannot allocate bitstream buffer, size=%d\n", MAX_BS_BUF); + return AVERROR(ENOMEM); + } + apv->bitb.addr = bs_buf; + apv->bitb.bsize = MAX_BS_BUF; + + /* read configurations and set values for created descriptor (APV_CDSC) */ + ret = get_conf(avctx, cdsc); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Cannot get OAPV configuration\n"); + return ret; + } + + /* create encoder */ + apv->id = oapve_create(cdsc, &ret); + if (apv->id == NULL) { + av_log(avctx, AV_LOG_ERROR, "Cannot create OAPV encoder\n"); + if (ret == OAPV_ERR_INVALID_LEVEL) + av_log(avctx, AV_LOG_ERROR, "Invalid level idc: %d\n", cdsc->param[0].level_idc); + return AVERROR_EXTERNAL; + } + + /* create metadata handler */ + apv->mid = oapvm_create(&ret); + if (apv->mid == NULL || OAPV_FAILED(ret)) { + av_log(avctx, AV_LOG_ERROR, "cannot create OAPV metadata handler\n"); + return AVERROR_EXTERNAL; + } + + int value = OAPV_CFG_VAL_AU_BS_FMT_NONE; + int size = 4; + ret = oapve_config(apv->id, OAPV_CFG_SET_AU_BS_FMT, &value, &size); + if (OAPV_FAILED(ret)) { + av_log(avctx, AV_LOG_ERROR, "Failed to set config for using encoder output format\n"); + return AVERROR_EXTERNAL; + } + + apv->ifrms.frm[FRM_IDX].imgb = apv_imgb_create(avctx); + if (apv->ifrms.frm[FRM_IDX].imgb == NULL) + return AVERROR(ENOMEM); + apv->ifrms.num_frms++; + + /* color description values */ + if (cdsc->param[FRM_IDX].color_description_present_flag) { + avctx->color_primaries = cdsc->param[FRM_IDX].color_primaries; + avctx->color_trc = cdsc->param[FRM_IDX].transfer_characteristics; + avctx->colorspace = cdsc->param[FRM_IDX].matrix_coefficients; + avctx->color_range = (cdsc->param[FRM_IDX].full_range_flag) ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + } + + return 0; +} + +/** + * Encode raw data frame into APV packet + * + * @param[in] avctx codec context + * @param[out] avpkt output AVPacket containing encoded data + * @param[in] frame AVFrame containing the raw data to be encoded + * @param[out] got_packet encoder sets to 0 or 1 to indicate that a + * non-empty packet was returned in pkt + * + * @return 0 on success, negative error code on failure + */ +static int liboapve_encode(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet) +{ + ApvEncContext *apv = avctx->priv_data; + const oapve_cdesc_t *cdsc = &apv->cdsc; + oapv_frm_t *frm = &apv->ifrms.frm[FRM_IDX]; + oapv_imgb_t *imgb = frm->imgb; + int ret; + + if (avctx->width != frame->width || avctx->height != frame->height || avctx->pix_fmt != frame->format) { + av_log(avctx, AV_LOG_ERROR, "Dimension changes are not supported\n"); + return AVERROR(EINVAL); + } + + av_image_copy((uint8_t **)imgb->a, imgb->s, (const uint8_t **)frame->data, frame->linesize, + frame->format, frame->width, frame->height); + + imgb->ts[0] = frame->pts; + + frm->group_id = 1; // @todo FIX-ME : need to set properly in case of multi-frame + frm->pbu_type = OAPV_PBU_TYPE_PRIMARY_FRAME; + + ret = oapve_encode(apv->id, &apv->ifrms, apv->mid, &apv->bitb, &apv->stat, NULL); + if (OAPV_FAILED(ret)) { + av_log(avctx, AV_LOG_ERROR, "oapve_encode() failed\n"); + return AVERROR_EXTERNAL; + } + + /* store bitstream */ + if (OAPV_SUCCEEDED(ret) && apv->stat.write > 0) { + uint8_t *data = apv->bitb.addr; + int size = apv->stat.write; + + // The encoder may return a "Raw bitstream" formatted AU, including au_size. + // Discard it as we only need the access_unit() structure. + if (size > 4 && AV_RB32(data) != APV_SIGNATURE) { + data += 4; + size -= 4; + } + + ret = ff_get_encode_buffer(avctx, avpkt, size, 0); + if (ret < 0) + return ret; + + memcpy(avpkt->data, data, size); + avpkt->pts = avpkt->dts = frame->pts; + avpkt->flags |= AV_PKT_FLAG_KEY; + + if (cdsc->param[FRM_IDX].qp) + ff_encode_add_stats_side_data(avpkt, cdsc->param[FRM_IDX].qp * FF_QP2LAMBDA, NULL, 0, AV_PICTURE_TYPE_I); + + *got_packet = 1; + } + + return 0; +} + +/** + * Destroy the encoder and release all the allocated resources + * + * @param avctx codec context + * @return 0 on success, negative error code on failure + */ +static av_cold int liboapve_close(AVCodecContext *avctx) +{ + ApvEncContext *apv = avctx->priv_data; + + for (int i = 0; i < apv->num_frames; i++) { + if (apv->ifrms.frm[i].imgb != NULL) + apv->ifrms.frm[i].imgb->release(apv->ifrms.frm[i].imgb); + apv->ifrms.frm[i].imgb = NULL; + } + + if (apv->mid) { + oapvm_rem_all(apv->mid); + } + + if (apv->id) { + oapve_delete(apv->id); + apv->id = NULL; + } + + if (apv->mid) { + oapvm_delete(apv->mid); + apv->mid = NULL; + } + + av_freep(&apv->bitb.addr); /* release bitstream buffer */ + + return 0; +} + +#define OFFSET(x) offsetof(ApvEncContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM + +static const enum AVPixelFormat supported_pixel_formats[] = { + AV_PIX_FMT_GRAY10, + AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUV422P12, + AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV444P12, + AV_PIX_FMT_YUVA444P10, + AV_PIX_FMT_YUVA444P12, + AV_PIX_FMT_NONE +}; + +static const AVOption liboapv_options[] = { + { "preset", "Encoding preset for setting encoding speed (optimization level control)", OFFSET(preset_id), AV_OPT_TYPE_INT, { .i64 = OAPV_PRESET_DEFAULT }, OAPV_PRESET_FASTEST, OAPV_PRESET_PLACEBO, VE, .unit = "preset" }, + { "fastest", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_FASTEST }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + { "fast", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_FAST }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + { "medium", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_MEDIUM }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + { "slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_SLOW }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + { "placebo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_PLACEBO }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_DEFAULT }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + + { "qp", "Quantization parameter value for CQP rate control mode", OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 63, VE }, + { "oapv-params", "Override the apv configuration using a :-separated list of key=value parameters", OFFSET(oapv_params), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, + { NULL } +}; + +static const AVClass liboapve_class = { + .class_name = "liboapv", + .item_name = av_default_item_name, + .option = liboapv_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const FFCodecDefault liboapve_defaults[] = { + { "b", "0" }, // bitrate in terms of kilo-bits per second (support for bit-rates from a few hundred Mbps to a few Gbps for 2K, 4K and 8K resolution content) + { NULL }, +}; + +const FFCodec ff_liboapv_encoder = { + .p.name = "liboapv", + .p.long_name = NULL_IF_CONFIG_SMALL("liboapv APV"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_APV, + .init = liboapve_init, + FF_CODEC_ENCODE_CB(liboapve_encode), + .close = liboapve_close, + .priv_data_size = sizeof(ApvEncContext), + .p.priv_class = &liboapve_class, + .defaults = liboapve_defaults, + .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1, + .p.wrapper_name = "liboapv", + .p.pix_fmts = supported_pixel_formats, + .p.profiles = NULL_IF_CONFIG_SMALL(ff_apv_profiles), + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_NOT_INIT_THREADSAFE, +}; diff --git a/libavcodec/libopencore-amr.c b/libavcodec/libopencore-amr.c index b127b3310..95c7b9b13 100644 --- a/libavcodec/libopencore-amr.c +++ b/libavcodec/libopencore-amr.c @@ -302,8 +302,7 @@ const FFCodec ff_libopencore_amrnb_encoder = { .init = amr_nb_encode_init, FF_CODEC_ENCODE_CB(amr_nb_encode_frame), .close = amr_nb_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.priv_class = &amrnb_class, }; #endif /* CONFIG_LIBOPENCORE_AMRNB_ENCODER */ diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c index 7107c1a67..6f6f26463 100644 --- a/libavcodec/libopenh264enc.c +++ b/libavcodec/libopenh264enc.c @@ -135,13 +135,7 @@ static av_cold int svc_encode_init(AVCodecContext *avctx) if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { param.fMaxFrameRate = av_q2d(avctx->framerate); } else { -FF_DISABLE_DEPRECATION_WARNINGS - param.fMaxFrameRate = 1.0 / av_q2d(avctx->time_base) -#if FF_API_TICKS_PER_FRAME - / FFMAX(avctx->ticks_per_frame, 1) -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + param.fMaxFrameRate = 1.0 / av_q2d(avctx->time_base); } param.iPicWidth = avctx->width; param.iPicHeight = avctx->height; @@ -442,9 +436,7 @@ const FFCodec ff_libopenh264_encoder = { .close = svc_encode_close, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, - AV_PIX_FMT_YUVJ420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .defaults = svc_enc_defaults, .p.priv_class = &class, diff --git a/libavcodec/libopenjpegenc.c b/libavcodec/libopenjpegenc.c index 01b67dffd..b797d34e1 100644 --- a/libavcodec/libopenjpegenc.c +++ b/libavcodec/libopenjpegenc.c @@ -765,7 +765,7 @@ const FFCodec ff_libopenjpeg_encoder = { FF_CODEC_ENCODE_CB(libopenjpeg_encode_frame), .p.capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = (const enum AVPixelFormat[]) { + CODEC_PIXFMTS( AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64, AV_PIX_FMT_GBR24P, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, @@ -782,9 +782,7 @@ const FFCodec ff_libopenjpeg_encoder = { AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, - AV_PIX_FMT_XYZ12, - AV_PIX_FMT_NONE - }, + AV_PIX_FMT_XYZ12), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &openjpeg_class, .p.wrapper_name = "libopenjpeg", diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c index 9b9a61034..fc2119baf 100644 --- a/libavcodec/libopusdec.c +++ b/libavcodec/libopusdec.c @@ -139,7 +139,7 @@ static av_cold int libopus_decode_init(AVCodecContext *avc) #endif /* Decoder delay (in samples) at 48kHz */ - avc->delay = avc->internal->skip_samples = opus->pre_skip; + avc->delay = opus->pre_skip; return 0; } @@ -244,9 +244,7 @@ const FFCodec ff_libopus_decoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), .p.priv_class = &libopusdec_class, .p.wrapper_name = "libopus", }; diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c index 6b8b2cda0..927776bbc 100644 --- a/libavcodec/libopusenc.c +++ b/libavcodec/libopusenc.c @@ -511,7 +511,7 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt, ff_af_queue_remove(&opus->afq, opus->opts.packet_size, &avpkt->pts, &avpkt->duration); - discard_padding = opus->opts.packet_size - avpkt->duration; + discard_padding = opus->opts.packet_size - ff_samples_from_time_base(avctx, avpkt->duration); // Check if subtraction resulted in an overflow if ((discard_padding < opus->opts.packet_size) != (avpkt->duration > 0)) return AVERROR(EINVAL); @@ -592,10 +592,8 @@ const FFCodec ff_libopus_encoder = { .init = libopus_encode_init, FF_CODEC_ENCODE_CB(libopus_encode), .close = libopus_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = libopus_sample_rates, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), + CODEC_SAMPLERATES_ARRAY(libopus_sample_rates), .p.priv_class = &libopus_class, .defaults = libopus_defaults, .p.wrapper_name = "libopus", diff --git a/libavcodec/librav1e.c b/libavcodec/librav1e.c index 546d00297..0db80830d 100644 --- a/libavcodec/librav1e.c +++ b/libavcodec/librav1e.c @@ -217,15 +217,9 @@ static av_cold int librav1e_encode_init(AVCodecContext *avctx) avctx->framerate.den, avctx->framerate.num }); } else { -FF_DISABLE_DEPRECATION_WARNINGS rav1e_config_set_time_base(cfg, (RaRational) { - avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - , avctx->time_base.den + avctx->time_base.num, avctx->time_base.den }); -FF_ENABLE_DEPRECATION_WARNINGS } if ((avctx->flags & AV_CODEC_FLAG_PASS1 || avctx->flags & AV_CODEC_FLAG_PASS2) && !avctx->bit_rate) { @@ -667,7 +661,7 @@ const FFCodec ff_librav1e_encoder = { .priv_data_size = sizeof(librav1eContext), .p.priv_class = &class, .defaults = librav1e_defaults, - .p.pix_fmts = librav1e_pix_fmts, + CODEC_PIXFMTS_ARRAY(librav1e_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_RECON_FRAME | diff --git a/libavcodec/libshine.c b/libavcodec/libshine.c index 333d86f77..aa71383bf 100644 --- a/libavcodec/libshine.c +++ b/libavcodec/libshine.c @@ -137,12 +137,8 @@ const FFCodec ff_libshine_encoder = { .init = libshine_encode_init, FF_CODEC_ENCODE_CB(libshine_encode_frame), .close = libshine_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = libshine_sample_rates, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 }, - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), + CODEC_SAMPLERATES_ARRAY(libshine_sample_rates), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), .p.wrapper_name = "libshine", }; diff --git a/libavcodec/libspeexdec.c b/libavcodec/libspeexdec.c index 84b308490..46f65ab07 100644 --- a/libavcodec/libspeexdec.c +++ b/libavcodec/libspeexdec.c @@ -195,11 +195,7 @@ const FFCodec ff_libspeex_decoder = { CODEC_LONG_NAME("libspeex Speex"), .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_SPEEX, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, + .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, .p.wrapper_name = "libspeex", .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, .priv_data_size = sizeof(LibSpeexContext), diff --git a/libavcodec/libspeexenc.c b/libavcodec/libspeexenc.c index 7b19db5a2..6f2d1ac7e 100644 --- a/libavcodec/libspeexenc.c +++ b/libavcodec/libspeexenc.c @@ -353,13 +353,9 @@ const FFCodec ff_libspeex_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 }, - }, - .p.supported_samplerates = (const int[]){ 8000, 16000, 32000, 0 }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLERATES(8000, 16000, 32000), .p.priv_class = &speex_class, .defaults = defaults, .p.wrapper_name = "libspeex", diff --git a/libavcodec/libsvtav1.c b/libavcodec/libsvtav1.c index 7a3048411..fec2ed596 100644 --- a/libavcodec/libsvtav1.c +++ b/libavcodec/libsvtav1.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -28,6 +29,7 @@ #include "libavutil/common.h" #include "libavutil/frame.h" #include "libavutil/imgutils.h" +#include "libavutil/base64.h" #include "libavutil/intreadwrite.h" #include "libavutil/mastering_display_metadata.h" #include "libavutil/mem.h" @@ -38,7 +40,6 @@ #include "codec_internal.h" #include "dovi_rpu.h" #include "encode.h" -#include "packet_internal.h" #include "avcodec.h" #include "profiles.h" @@ -66,6 +67,8 @@ typedef struct SvtContext { DOVIContext dovi; + uint8_t *stats_buf; + // User options. AVDictionary *svtav1_opts; int enc_mode; @@ -210,7 +213,7 @@ static int config_enc_params(EbSvtAv1EncConfiguration *param, { SvtContext *svt_enc = avctx->priv_data; const AVPixFmtDescriptor *desc; - const AVDictionaryEntry av_unused *en = NULL; + av_unused const AVDictionaryEntry *en = NULL; // Update param from options if (svt_enc->enc_mode >= -1) @@ -246,10 +249,10 @@ static int config_enc_params(EbSvtAv1EncConfiguration *param, } desc = av_pix_fmt_desc_get(avctx->pix_fmt); - param->color_primaries = avctx->color_primaries; - param->matrix_coefficients = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? - AVCOL_SPC_RGB : avctx->colorspace; - param->transfer_characteristics = avctx->color_trc; + param->color_primaries = (enum EbColorPrimaries)avctx->color_primaries; + param->matrix_coefficients = (enum EbMatrixCoefficients)((desc->flags & AV_PIX_FMT_FLAG_RGB) ? + AVCOL_SPC_RGB : avctx->colorspace); + param->transfer_characteristics = (enum EbTransferCharacteristics)avctx->color_trc; if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED) param->color_range = avctx->color_range == AVCOL_RANGE_JPEG; @@ -315,13 +318,7 @@ static int config_enc_params(EbSvtAv1EncConfiguration *param, param->frame_rate_denominator = avctx->framerate.den; } else { param->frame_rate_numerator = avctx->time_base.den; -FF_DISABLE_DEPRECATION_WARNINGS - param->frame_rate_denominator = avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + param->frame_rate_denominator = avctx->time_base.num; } /* 2 = IDR, closed GOP, 1 = CRA, open GOP */ @@ -348,6 +345,42 @@ FF_ENABLE_DEPRECATION_WARNINGS return AVERROR(ENOSYS); } #endif + if (avctx->flags & AV_CODEC_FLAG_PASS2) { + int stats_sz; + + if (!avctx->stats_in) { + av_log(avctx, AV_LOG_ERROR, "No stats file for second pass\n"); + return AVERROR(EINVAL); + } + + stats_sz = AV_BASE64_DECODE_SIZE(strlen(avctx->stats_in)); + if (stats_sz <= 0) { + av_log(avctx, AV_LOG_ERROR, "Invalid stats file size\n"); + return AVERROR(EINVAL); + } + + svt_enc->stats_buf = av_malloc(stats_sz); + if (!svt_enc->stats_buf) { + av_log(avctx, AV_LOG_ERROR, "Failed to allocate stats buffer\n"); + return AVERROR(ENOMEM); + } + + stats_sz = av_base64_decode(svt_enc->stats_buf, avctx->stats_in, stats_sz); + if (stats_sz < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to decode stats file\n"); + av_freep(&svt_enc->stats_buf); + return AVERROR(EINVAL); + } + + param->rc_stats_buffer.buf = svt_enc->stats_buf; + param->rc_stats_buffer.sz = stats_sz; + param->pass = 2; + + av_log(avctx, AV_LOG_VERBOSE, "Using %d bytes of 2-pass stats\n", stats_sz); + } else if (avctx->flags & AV_CODEC_FLAG_PASS1) { + param->pass = 1; + av_log(avctx, AV_LOG_VERBOSE, "Starting first pass\n"); + } param->source_width = avctx->width; param->source_height = avctx->height; @@ -601,7 +634,7 @@ static int eb_receive_packet(AVCodecContext *avctx, AVPacket *pkt) AVFrame *frame = svt_enc->frame; EbErrorType svt_ret; AVBufferRef *ref; - int ret = 0, pict_type; + int ret = 0; if (svt_enc->eos_flag == EOS_RECEIVED) return AVERROR_EOF; @@ -625,9 +658,45 @@ static int eb_receive_packet(AVCodecContext *avctx, AVPacket *pkt) #if SVT_AV1_CHECK_VERSION(2, 0, 0) if (headerPtr->flags & EB_BUFFERFLAG_EOS) { - svt_enc->eos_flag = EOS_RECEIVED; - svt_av1_enc_release_out_buffer(&headerPtr); - return AVERROR_EOF; + if (avctx->flags & AV_CODEC_FLAG_PASS1) { + SvtAv1FixedBuf first_pass_stats = { 0 }; + EbErrorType svt_ret_stats; + int b64_size; + + svt_ret_stats = svt_av1_enc_get_stream_info( + svt_enc->svt_handle, + SVT_AV1_STREAM_INFO_FIRST_PASS_STATS_OUT, + &first_pass_stats); + + if (svt_ret_stats != EB_ErrorNone) { + av_log(avctx, AV_LOG_ERROR, + "Failed to get first pass stats\n"); + svt_av1_enc_release_out_buffer(&headerPtr); + return AVERROR_EXTERNAL; + } + + if (first_pass_stats.sz > 0 && first_pass_stats.buf) { + b64_size = AV_BASE64_SIZE(first_pass_stats.sz); + avctx->stats_out = av_malloc(b64_size); + if (!avctx->stats_out) { + av_log(avctx, AV_LOG_ERROR, + "Failed to allocate stats output buffer\n"); + svt_av1_enc_release_out_buffer(&headerPtr); + return AVERROR(ENOMEM); + } + + av_base64_encode(avctx->stats_out, b64_size, + first_pass_stats.buf, first_pass_stats.sz); + + av_log(avctx, AV_LOG_VERBOSE, + "First pass stats: %"PRIu64" bytes, encoded to %d bytes\n", + first_pass_stats.sz, b64_size); + } + } + + svt_enc->eos_flag = EOS_RECEIVED; + svt_av1_enc_release_out_buffer(&headerPtr); + return AVERROR_EOF; } #endif @@ -647,6 +716,7 @@ static int eb_receive_packet(AVCodecContext *avctx, AVPacket *pkt) pkt->pts = headerPtr->pts; pkt->dts = headerPtr->dts; + enum AVPictureType pict_type; switch (headerPtr->pic_type) { case EB_AV1_KEY_PICTURE: pkt->flags |= AV_PKT_FLAG_KEY; @@ -670,7 +740,7 @@ static int eb_receive_packet(AVCodecContext *avctx, AVPacket *pkt) svt_enc->eos_flag = EOS_RECEIVED; #endif - ff_side_data_set_encoder_stats(pkt, headerPtr->qp * FF_QP2LAMBDA, NULL, 0, pict_type); + ff_encode_add_stats_side_data(pkt, headerPtr->qp * FF_QP2LAMBDA, NULL, 0, pict_type); svt_av1_enc_release_out_buffer(&headerPtr); @@ -694,6 +764,7 @@ static av_cold int eb_enc_close(AVCodecContext *avctx) av_buffer_pool_uninit(&svt_enc->pool); av_frame_free(&svt_enc->frame); ff_dovi_ctx_unref(&svt_enc->dovi); + av_freep(&svt_enc->stats_buf); return 0; } @@ -774,9 +845,7 @@ const FFCodec ff_libsvtav1_encoder = { .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, - AV_PIX_FMT_YUV420P10, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = eb_enc_defaults, diff --git a/libavcodec/libsvtjpegxsdec.c b/libavcodec/libsvtjpegxsdec.c new file mode 100644 index 000000000..7a325c444 --- /dev/null +++ b/libavcodec/libsvtjpegxsdec.c @@ -0,0 +1,228 @@ +/* + * Copyright(c) 2024 Intel Corporation + * + * 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 + */ + +/* +* Copyright(c) 2024 Intel Corporation +* SPDX - License - Identifier: BSD - 2 - Clause - Patent +*/ + +#include + +#include "libavutil/mem.h" +#include "libavutil/common.h" +#include "libavutil/cpu.h" +#include "libavutil/imgutils.h" +#include "libavutil/avassert.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "decode.h" +#include "profiles.h" + +typedef struct SvtJpegXsDecodeContext { + svt_jpeg_xs_image_config_t config; + svt_jpeg_xs_decoder_api_t decoder; + svt_jpeg_xs_frame_t input; + svt_jpeg_xs_frame_t output; + uint32_t decoder_initialized; + + int proxy_mode; +} SvtJpegXsDecodeContext; + +static int set_pix_fmt(void *logctx, const svt_jpeg_xs_image_config_t *config) +{ + int ret = AVERROR_BUG; + + switch (config->format) { + case COLOUR_FORMAT_PLANAR_YUV420: + if (config->bit_depth == 8) + return AV_PIX_FMT_YUV420P; + else if (config->bit_depth == 10) + return AV_PIX_FMT_YUV420P10LE; + else if (config->bit_depth == 12) + return AV_PIX_FMT_YUV420P12LE; + else + return AV_PIX_FMT_YUV420P14LE; + break; + case COLOUR_FORMAT_PLANAR_YUV422: + if (config->bit_depth == 8) + return AV_PIX_FMT_YUV422P; + else if (config->bit_depth == 10) + return AV_PIX_FMT_YUV422P10LE; + else if (config->bit_depth == 12) + return AV_PIX_FMT_YUV422P12LE; + else + return AV_PIX_FMT_YUV422P14LE; + break; + case COLOUR_FORMAT_PLANAR_YUV444_OR_RGB: + if (config->bit_depth == 8) + return AV_PIX_FMT_YUV444P; + else if (config->bit_depth == 10) + return AV_PIX_FMT_YUV444P10LE; + else if (config->bit_depth == 12) + return AV_PIX_FMT_YUV444P12LE; + else + return AV_PIX_FMT_YUV444P14LE; + break; + default: + av_log(logctx, AV_LOG_ERROR, "Unsupported pixel format.\n"); + ret = AVERROR_INVALIDDATA; + break; + } + + return ret; +} + +static int svt_jpegxs_dec_decode(AVCodecContext* avctx, AVFrame* picture, int* got_frame, AVPacket* avpkt) +{ + SvtJpegXsDecodeContext* svt_dec = avctx->priv_data; + SvtJxsErrorType_t err = SvtJxsErrorNone; + uint32_t frame_size; + int ret; + + err = svt_jpeg_xs_decoder_get_single_frame_size_with_proxy( + avpkt->data, avpkt->size, &svt_dec->config, &frame_size, 1 /*quick search*/, svt_dec->decoder.proxy_mode); + if (err) { + av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_get_single_frame_size_with_proxy failed, err=%d\n", err); + return AVERROR_EXTERNAL; + } + if (avpkt->size < frame_size) { + av_log(avctx, AV_LOG_ERROR, "Not enough data in a packet.\n"); + return AVERROR(EINVAL); + } + if (avpkt->size > frame_size) { + av_log(avctx, AV_LOG_ERROR, "Single packet have data for more than one frame.\n"); + return AVERROR(EINVAL); + } + + ret = set_pix_fmt(avctx, &svt_dec->config); + if (ret < 0) + return ret; + + if (!svt_dec->decoder_initialized || ret != avctx->pix_fmt || + avctx->width != svt_dec->config.width || avctx->height != svt_dec->config.height) { + if (svt_dec->decoder_initialized) + svt_jpeg_xs_decoder_close(&svt_dec->decoder); + err = svt_jpeg_xs_decoder_init(SVT_JPEGXS_API_VER_MAJOR, SVT_JPEGXS_API_VER_MINOR, + &svt_dec->decoder, avpkt->data, avpkt->size, &svt_dec->config); + if (err) { + av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_init failed, err=%d\n", err); + return AVERROR_EXTERNAL; + } + + avctx->pix_fmt = ret; + + ret = ff_set_dimensions(avctx, svt_dec->config.width, svt_dec->config.height); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "ff_set_dimensions failed, err=%d\n", ret); + return ret; + } + + svt_dec->decoder_initialized = 1; + } + + if (avctx->skip_frame == AVDISCARD_ALL) + return 0; + + svt_dec->input.bitstream.buffer = avpkt->data; + svt_dec->input.bitstream.allocation_size = avpkt->size; + svt_dec->input.bitstream.used_size = avpkt->size; + svt_dec->input.user_prv_ctx_ptr = avpkt; + + ret = ff_get_buffer(avctx, picture, 0); + if (ret < 0) + return ret; + + unsigned pixel_shift = svt_dec->config.bit_depth <= 8 ? 0 : 1; + for (int comp = 0; comp < svt_dec->config.components_num; comp++) { + svt_dec->input.image.data_yuv[comp] = picture->data[comp]; + svt_dec->input.image.stride[comp] = picture->linesize[comp] >> pixel_shift; + svt_dec->input.image.alloc_size[comp] = picture->linesize[comp] * svt_dec->config.components[comp].height; + } + + err = svt_jpeg_xs_decoder_send_frame(&svt_dec->decoder, &svt_dec->input, 1 /*blocking*/); + if (err) { + av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_send_frame failed, err=%d\n", err); + return AVERROR_EXTERNAL; + } + + err = svt_jpeg_xs_decoder_get_frame(&svt_dec->decoder, &svt_dec->output, 1 /*blocking*/); + if (err) { + av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_get_frame failed, err=%d\n", err); + return AVERROR_EXTERNAL; + } + + if (svt_dec->output.user_prv_ctx_ptr != avpkt) { + av_log(avctx, AV_LOG_ERROR, "Returned different user_prv_ctx_ptr than expected\n"); + return AVERROR_EXTERNAL; + } + + *got_frame = 1; + + return avpkt->size; +} + +static av_cold int svt_jpegxs_dec_free(AVCodecContext* avctx) +{ + SvtJpegXsDecodeContext* svt_dec = avctx->priv_data; + + svt_jpeg_xs_decoder_close(&svt_dec->decoder); + + return 0; +} + +static av_cold int svt_jpegxs_dec_init(AVCodecContext* avctx) +{ + SvtJpegXsDecodeContext* svt_dec = avctx->priv_data; + + int log_level = av_log_get_level(); + svt_dec->decoder.verbose = log_level < AV_LOG_DEBUG ? VERBOSE_ERRORS : + log_level == AV_LOG_DEBUG ? VERBOSE_SYSTEM_INFO : VERBOSE_WARNINGS; + + if (avctx->lowres == 1) + svt_dec->decoder.proxy_mode = proxy_mode_half; + else if (avctx->lowres == 2) + svt_dec->decoder.proxy_mode = proxy_mode_quarter; + else + svt_dec->decoder.proxy_mode = proxy_mode_full; + + int thread_count = avctx->thread_count ? avctx->thread_count : av_cpu_count(); + svt_dec->decoder.threads_num = FFMIN(thread_count, 64); + svt_dec->decoder.use_cpu_flags = CPU_FLAGS_ALL; + + return 0; +} + +const FFCodec ff_libsvtjpegxs_decoder = { + .p.name = "libsvtjpegxs", + CODEC_LONG_NAME("SVT JPEG XS(Scalable Video Technology for JPEG XS) decoder"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_JPEGXS, + .priv_data_size = sizeof(SvtJpegXsDecodeContext), + .init = svt_jpegxs_dec_init, + .close = svt_jpegxs_dec_free, + FF_CODEC_DECODE_CB(svt_jpegxs_dec_decode), + .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | + FF_CODEC_CAP_AUTO_THREADS, + .p.max_lowres = 2, + .p.wrapper_name = "libsvtjpegxs", +}; diff --git a/libavcodec/libsvtjpegxsenc.c b/libavcodec/libsvtjpegxsenc.c new file mode 100644 index 000000000..d8dbc9307 --- /dev/null +++ b/libavcodec/libsvtjpegxsenc.c @@ -0,0 +1,303 @@ +/* + * Copyright(c) 2024 Intel Corporation + * + * 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 + */ + +/* +* Copyright(c) 2024 Intel Corporation +* SPDX - License - Identifier: BSD - 2 - Clause - Patent +*/ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/cpu.h" +#include "libavutil/imgutils.h" +#include "libavutil/rational.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "encode.h" +#include "profiles.h" + +typedef struct SvtJpegXsEncodeContext { + AVClass* class; + + int decomp_v; + int decomp_h; + int quant; + int coding_signs_handling; + int coding_significance; + int coding_vpred; + + svt_jpeg_xs_encoder_api_t encoder; + int bitstream_frame_size; +} SvtJpegXsEncodeContext; + +static int svt_jpegxs_enc_encode(AVCodecContext* avctx, AVPacket* pkt, + const AVFrame* frame, int* got_packet) +{ + SvtJpegXsEncodeContext* svt_enc = avctx->priv_data; + + svt_jpeg_xs_frame_t enc_input; + svt_jpeg_xs_bitstream_buffer_t *const out_buf = &enc_input.bitstream; + svt_jpeg_xs_image_buffer_t *const in_buf = &enc_input.image; + svt_jpeg_xs_frame_t enc_output; + + SvtJxsErrorType_t err = SvtJxsErrorNone; + + int ret = ff_get_encode_buffer(avctx, pkt, svt_enc->bitstream_frame_size, 0); + if (ret < 0) + return ret; + + out_buf->buffer = pkt->data;// output bitstream ptr + out_buf->allocation_size = pkt->size;// output bitstream size + out_buf->used_size = 0; + + unsigned pixel_shift = svt_enc->encoder.input_bit_depth <= 8 ? 0 : 1; + for (int comp = 0; comp < 3; comp++) { + // svt-jpegxs require stride in pixel's not in bytes, this means that for 10 bit-depth, stride is half the linesize + in_buf->stride[comp] = frame->linesize[comp] >> pixel_shift; + in_buf->data_yuv[comp] = frame->data[comp]; + in_buf->alloc_size[comp] = frame->linesize[comp] * svt_enc->encoder.source_height; + } + + enc_input.user_prv_ctx_ptr = pkt; + + err = svt_jpeg_xs_encoder_send_picture(&svt_enc->encoder, &enc_input, 1 /*blocking*/); + if (err != SvtJxsErrorNone) { + av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_encoder_send_picture failed\n"); + return AVERROR_EXTERNAL; + } + + err = svt_jpeg_xs_encoder_get_packet(&svt_enc->encoder, &enc_output, 1 /*blocking*/); + if (err != SvtJxsErrorNone) { + av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_encoder_get_packet failed\n"); + return AVERROR_EXTERNAL; + } + + if (enc_output.user_prv_ctx_ptr != pkt) { + av_log(avctx, AV_LOG_ERROR, "Returned different user_prv_ctx_ptr than expected\n"); + return AVERROR_EXTERNAL; + } + + pkt->size = enc_output.bitstream.used_size; + + *got_packet = 1; + + return 0; +} + +static av_cold int svt_jpegxs_enc_free(AVCodecContext* avctx) { + SvtJpegXsEncodeContext* svt_enc = avctx->priv_data; + + svt_jpeg_xs_encoder_close(&svt_enc->encoder); + + return 0; +} + +static void set_pix_fmt(AVCodecContext *avctx, svt_jpeg_xs_encoder_api_t *encoder) +{ + switch (avctx->pix_fmt) { + case AV_PIX_FMT_YUV420P: + encoder->input_bit_depth = 8; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV420; + return; + case AV_PIX_FMT_YUV422P: + encoder->input_bit_depth = 8; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV422; + return; + case AV_PIX_FMT_YUV444P: + encoder->input_bit_depth = 8; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV444_OR_RGB; + return; + case AV_PIX_FMT_YUV420P10LE: + encoder->input_bit_depth = 10; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV420; + return; + case AV_PIX_FMT_YUV422P10LE: + encoder->input_bit_depth = 10; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV422; + return; + case AV_PIX_FMT_YUV444P10LE: + encoder->input_bit_depth = 10; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV444_OR_RGB; + return; + case AV_PIX_FMT_YUV420P12LE: + encoder->input_bit_depth = 12; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV420; + return; + case AV_PIX_FMT_YUV422P12LE: + encoder->input_bit_depth = 12; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV422; + return; + case AV_PIX_FMT_YUV444P12LE: + encoder->input_bit_depth = 12; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV444_OR_RGB; + return; + case AV_PIX_FMT_YUV420P14LE: + encoder->input_bit_depth = 14; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV420; + return; + case AV_PIX_FMT_YUV422P14LE: + encoder->input_bit_depth = 14; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV422; + return; + case AV_PIX_FMT_YUV444P14LE: + encoder->input_bit_depth = 14; + encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV444_OR_RGB; + return; + default: + av_unreachable("Already checked via CODEC_PIXFMTS_ARRAY"); + break; + } +} + +static av_cold int svt_jpegxs_enc_init(AVCodecContext* avctx) { + SvtJpegXsEncodeContext* svt_enc = avctx->priv_data; + AVRational bpp; + SvtJxsErrorType_t err; + + err = svt_jpeg_xs_encoder_load_default_parameters(SVT_JPEGXS_API_VER_MAJOR, SVT_JPEGXS_API_VER_MINOR, &(svt_enc->encoder)); + if (err != SvtJxsErrorNone) { + av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_encoder_load_default_parameters failed\n"); + return AVERROR_EXTERNAL; + } + + svt_enc->encoder.source_width = avctx->width; + svt_enc->encoder.source_height = avctx->height; + + set_pix_fmt(avctx, &svt_enc->encoder); + + int thread_count = avctx->thread_count ? avctx->thread_count : av_cpu_count(); + svt_enc->encoder.threads_num = FFMIN(thread_count, 64); + + int log_level = av_log_get_level(); + svt_enc->encoder.verbose = log_level < AV_LOG_DEBUG ? VERBOSE_ERRORS : + log_level == AV_LOG_DEBUG ? VERBOSE_SYSTEM_INFO : VERBOSE_WARNINGS; + + if (avctx->framerate.num <= 0 || avctx->framerate.den <= 0) { + av_log(avctx, AV_LOG_ERROR, "framerate must be set\n"); + return AVERROR(EINVAL); + } + if (avctx->bit_rate == 0) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); + // default to a 1.5 compression ratio + avctx->bit_rate = (int64_t)avctx->width * avctx->height * + (av_get_bits_per_pixel(desc) * 2 / 3) * av_q2d(avctx->framerate); + av_log(avctx, AV_LOG_WARNING, "No bitrate set, defaulting to %"PRId64"\n", avctx->bit_rate); + } + + av_reduce(&bpp.num, &bpp.den, avctx->bit_rate, (int64_t)avctx->width * avctx->height, INT_MAX); + bpp = av_div_q(bpp, avctx->framerate); + svt_enc->encoder.bpp_numerator = bpp.num; + svt_enc->encoder.bpp_denominator = bpp.den; + + if (svt_enc->decomp_v >= 0) + svt_enc->encoder.ndecomp_v = svt_enc->decomp_v; + if (svt_enc->decomp_h >= 0) + svt_enc->encoder.ndecomp_h = svt_enc->decomp_h; + if (svt_enc->quant >= 0) + svt_enc->encoder.quantization = svt_enc->quant; + if (svt_enc->coding_signs_handling >= 0) + svt_enc->encoder.coding_signs_handling = svt_enc->coding_signs_handling; + if (svt_enc->coding_significance >= 0) + svt_enc->encoder.coding_significance = svt_enc->coding_significance; + if (svt_enc->coding_vpred >= 0) + svt_enc->encoder.coding_vertical_prediction_mode = svt_enc->coding_vpred; + if (avctx->slices > 0) + svt_enc->encoder.slice_height = avctx->height / avctx->slices; + + err = svt_jpeg_xs_encoder_init(SVT_JPEGXS_API_VER_MAJOR, SVT_JPEGXS_API_VER_MINOR, &svt_enc->encoder); + if (err != SvtJxsErrorNone) { + av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_encoder_init failed\n"); + return AVERROR_EXTERNAL; + } + + svt_enc->bitstream_frame_size = (((int64_t)avctx->width * avctx->height * + svt_enc->encoder.bpp_numerator / svt_enc->encoder.bpp_denominator + 7) / 8); + + return 0; +} + +static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUV420P10LE, + AV_PIX_FMT_YUV422P10LE, + AV_PIX_FMT_YUV444P10LE, + AV_PIX_FMT_YUV420P12LE, + AV_PIX_FMT_YUV422P12LE, + AV_PIX_FMT_YUV444P12LE, + AV_PIX_FMT_YUV420P14LE, + AV_PIX_FMT_YUV422P14LE, + AV_PIX_FMT_YUV444P14LE, + AV_PIX_FMT_NONE +}; + +static const FFCodecDefault svt_jpegxs_defaults[] = { + { "b", "0" }, + { NULL }, +}; + +#define OFFSET(x) offsetof(SvtJpegXsEncodeContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption svtjpegxs_enc_options[] = { + { "decomp_v", "vertical decomposition level", OFFSET(decomp_v), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 2, VE }, + { "decomp_h", "horizontal decomposition level", OFFSET(decomp_h), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 5, VE }, + { "quantization", "Quantization algorithm", OFFSET(quant), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 1, VE, .unit = "quantization" }, + { "deadzone", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, VE, .unit = "quantization" }, + { "uniform", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, VE, .unit = "quantization" }, + { "coding-signs", "Enable Signs handling strategy", OFFSET(coding_signs_handling), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 2, VE, .unit = "coding-signs" }, + { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, VE, .unit = "coding-signs" }, + { "fast", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, VE, .unit = "coding-signs" }, + { "full", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2}, INT_MIN, INT_MAX, VE, .unit = "coding-signs" }, + { "coding-sigf", "Enable Significance coding", OFFSET(coding_significance), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, + { "coding-vpred", "Enable Vertical Prediction coding", OFFSET(coding_vpred), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 2, VE, .unit = "coding-vpred" }, + { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, VE, .unit = "coding-vpred" }, + { "no_residuals", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, VE, .unit = "coding-vpred" }, + { "no_coeffs", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2}, INT_MIN, INT_MAX, VE, .unit = "coding-vpred" }, + { NULL }, +}; + +static const AVClass svtjpegxs_enc_class = { + .class_name = "libsvtjpegxs", + .item_name = av_default_item_name, + .option = svtjpegxs_enc_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_libsvtjpegxs_encoder = { + .p.name = "libsvtjpegxs", + CODEC_LONG_NAME("SVT JPEG XS(Scalable Video Technology for JPEG XS) encoder"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_JPEGXS, + .priv_data_size = sizeof(SvtJpegXsEncodeContext), + .init = svt_jpegxs_enc_init, + .close = svt_jpegxs_enc_free, + .defaults = svt_jpegxs_defaults, + FF_CODEC_ENCODE_CB(svt_jpegxs_enc_encode), + .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | + FF_CODEC_CAP_AUTO_THREADS, + CODEC_PIXFMTS_ARRAY(pix_fmts), + .p.wrapper_name = "libsvtjpegxs", + .p.priv_class = &svtjpegxs_enc_class, +}; diff --git a/libavcodec/libtheoraenc.c b/libavcodec/libtheoraenc.c index 761cd45d4..e089fe8f5 100644 --- a/libavcodec/libtheoraenc.c +++ b/libavcodec/libtheoraenc.c @@ -37,6 +37,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/log.h" #include "libavutil/base64.h" +#include "libavutil/opt.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" @@ -45,15 +46,29 @@ #include typedef struct TheoraContext { + AVClass *av_class; /**< class for AVOptions */ th_enc_ctx *t_state; uint8_t *stats; int stats_size; int stats_offset; int uv_hshift; int uv_vshift; - int keyframe_mask; + unsigned keyframe_mask; + int speed_level; } TheoraContext; +static const AVOption options[] = { + { "speed_level", "Sets the encoding speed level", offsetof(TheoraContext, speed_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, + { NULL } +}; + +static const AVClass theora_class = { + .class_name = "libtheora", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + /** Concatenate an ogg_packet into the extradata. */ static int concatenate_packet(unsigned int* offset, AVCodecContext* avc_context, @@ -234,7 +249,7 @@ static av_cold int encode_init(AVCodecContext* avc_context) return AVERROR_EXTERNAL; } - h->keyframe_mask = (1 << av_ceil_log2(avc_context->gop_size)) - 1; + h->keyframe_mask = (1U << av_ceil_log2(avc_context->gop_size)) - 1; /* Clear up theora_info struct */ th_info_clear(&t_info); @@ -244,6 +259,15 @@ static av_cold int encode_init(AVCodecContext* avc_context) return AVERROR_EXTERNAL; } + // Set encoding speed level + if (h->speed_level != -1) { + int max_speed_level; + int speed_level = h->speed_level; + th_encode_ctl(h->t_state, TH_ENCCTL_GET_SPLEVEL_MAX, &max_speed_level, sizeof(max_speed_level)); + speed_level = FFMIN(speed_level, max_speed_level); + th_encode_ctl(h->t_state, TH_ENCCTL_SET_SPLEVEL, &speed_level, sizeof(speed_level)); + } + // need to enable 2 pass (via TH_ENCCTL_2PASS_) before encoding headers if (avc_context->flags & AV_CODEC_FLAG_PASS1) { if ((ret = get_stats(avc_context, 0)) < 0) @@ -388,9 +412,8 @@ const FFCodec ff_libtheora_encoder = { .init = encode_init, .close = encode_close, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P), + .p.priv_class = &theora_class, .color_ranges = AVCOL_RANGE_MPEG, .p.wrapper_name = "libtheora", }; diff --git a/libavcodec/libtwolame.c b/libavcodec/libtwolame.c index f3bd4771d..18b40dafc 100644 --- a/libavcodec/libtwolame.c +++ b/libavcodec/libtwolame.c @@ -221,18 +221,9 @@ const FFCodec ff_libtwolame_encoder = { .close = twolame_encode_close, .defaults = twolame_defaults, .p.priv_class = &twolame_class, - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE - }, - .p.ch_layouts = (const AVChannelLayout[]) { - AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 }, - }, - .p.supported_samplerates = twolame_samplerates, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLERATES_ARRAY(twolame_samplerates), .p.wrapper_name = "libtwolame", }; diff --git a/libavcodec/libuavs3d.c b/libavcodec/libuavs3d.c index 53b5faafc..3eea2051b 100644 --- a/libavcodec/libuavs3d.c +++ b/libavcodec/libuavs3d.c @@ -79,12 +79,6 @@ static void uavs3d_output_callback(uavs3d_io_frm_t *dec_frame) { frm->pts = dec_frame->pts; frm->pkt_dts = dec_frame->dts; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frm->pkt_pos = dec_frame->pkt_pos; - frm->pkt_size = dec_frame->pkt_size; -FF_ENABLE_DEPRECATION_WARNINGS -#endif if (dec_frame->type < 0 || dec_frame->type >= FF_ARRAY_ELEMS(ff_avs3_image_type)) { av_log(NULL, AV_LOG_WARNING, "Error frame type in uavs3d: %d.\n", dec_frame->type); @@ -106,6 +100,91 @@ FF_ENABLE_DEPRECATION_WARNINGS uavs3d_img_cpy_cvt(&frm_out, dec_frame, dec_frame->bit_depth); } +#define UAVS3D_CHECK_INVALID_RANGE(v, l, r) ((v)<(l)||(v)>(r)) + +static int libuavs3d_on_seq_header(AVCodecContext *avctx) +{ + uavs3d_context *h = avctx->priv_data; + uavs3d_io_frm_t *frm_dec = &h->dec_frame; + struct uavs3d_com_seqh_t *seqh = frm_dec->seqhdr; + int ret; + + if (UAVS3D_CHECK_INVALID_RANGE(seqh->frame_rate_code, 0, 15)) { + av_log(avctx, AV_LOG_ERROR, "Invalid frame rate code: %d.\n", seqh->frame_rate_code); + seqh->frame_rate_code = 3; // default 25 fps + } else { + avctx->framerate.num = ff_avs3_frame_rate_tab[seqh->frame_rate_code].num; + avctx->framerate.den = ff_avs3_frame_rate_tab[seqh->frame_rate_code].den; + } + avctx->has_b_frames = seqh->output_reorder_delay; + avctx->pix_fmt = seqh->bit_depth_internal == 8 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUV420P10; + ret = ff_set_dimensions(avctx, seqh->horizontal_size, seqh->vertical_size); + if (ret < 0) + return ret; + h->got_seqhdr = 1; + + if (seqh->colour_description) { + if (UAVS3D_CHECK_INVALID_RANGE(seqh->colour_primaries, 0, 9) || + UAVS3D_CHECK_INVALID_RANGE(seqh->transfer_characteristics, 0, 14) || + UAVS3D_CHECK_INVALID_RANGE(seqh->matrix_coefficients, 0, 11)) { + av_log(avctx, AV_LOG_ERROR, + "Invalid colour description: primaries: %d" + "transfer characteristics: %d" + "matrix coefficients: %d.\n", + seqh->colour_primaries, + seqh->transfer_characteristics, + seqh->matrix_coefficients); + } else { + avctx->color_primaries = ff_avs3_color_primaries_tab[seqh->colour_primaries]; + avctx->color_trc = ff_avs3_color_transfer_tab [seqh->transfer_characteristics]; + avctx->colorspace = ff_avs3_color_matrix_tab [seqh->matrix_coefficients]; + } + } + + return 0; +} + +static int libuavs3d_decode_extradata(AVCodecContext *avctx) +{ + uavs3d_context *h = avctx->priv_data; + uint8_t *header = avctx->extradata; + int header_size = avctx->extradata_size; + uavs3d_io_frm_t *frm_dec = &h->dec_frame; + + if (avctx->extradata_size < 4) { + av_log(avctx, AV_LOG_WARNING, "Invalid extradata size %d\n", + avctx->extradata_size); + return 0; + } + + if (header[0] == 1) { + // Skip configurationVersion and sequence_header_length + header += 3; + // Also remove library_dependency_idc at the end + header_size -= 4; + } + + frm_dec->nal_type = 0; + frm_dec->pkt_pos = 0; + frm_dec->pkt_size = header_size; + frm_dec->bs = header; + frm_dec->bs_len = header_size; + frm_dec->pts = 0; + frm_dec->dts = 0; + uavs3d_decode(h->dec_handle, frm_dec); + if (frm_dec->nal_type == NAL_SEQ_HEADER) { + int ret = libuavs3d_on_seq_header(avctx); + if (ret < 0) + av_log(avctx, AV_LOG_WARNING, + "Process sequence header failed, %s\n", av_err2str(ret)); + } else { + av_log(avctx, AV_LOG_WARNING, + "Missing sequence header in extradata\n"); + } + + return 0; +} + static av_cold int libuavs3d_init(AVCodecContext *avctx) { uavs3d_context *h = avctx->priv_data; @@ -120,6 +199,9 @@ static av_cold int libuavs3d_init(AVCodecContext *avctx) return AVERROR(ENOMEM); } + if (avctx->extradata) + return libuavs3d_decode_extradata(avctx); + return 0; } @@ -146,7 +228,6 @@ static void libuavs3d_flush(AVCodecContext * avctx) } } -#define UAVS3D_CHECK_INVALID_RANGE(v, l, r) ((v)<(l)||(v)>(r)) static int libuavs3d_decode_frame(AVCodecContext *avctx, AVFrame *frm, int *got_frame, AVPacket *avpkt) { @@ -176,12 +257,6 @@ static int libuavs3d_decode_frame(AVCodecContext *avctx, AVFrame *frm, uavs3d_io_frm_t *frm_dec = &h->dec_frame; buf_end = buf + buf_size; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frm_dec->pkt_pos = avpkt->pos; - frm_dec->pkt_size = avpkt->size; -FF_ENABLE_DEPRECATION_WARNINGS -#endif while (!finish) { int bs_len; @@ -207,38 +282,9 @@ FF_ENABLE_DEPRECATION_WARNINGS buf_ptr += bs_len; if (frm_dec->nal_type == NAL_SEQ_HEADER) { - struct uavs3d_com_seqh_t *seqh = frm_dec->seqhdr; - if (UAVS3D_CHECK_INVALID_RANGE(seqh->frame_rate_code, 0, 15)) { - av_log(avctx, AV_LOG_ERROR, "Invalid frame rate code: %d.\n", seqh->frame_rate_code); - seqh->frame_rate_code = 3; // default 25 fps - } else { - avctx->framerate.num = ff_avs3_frame_rate_tab[seqh->frame_rate_code].num; - avctx->framerate.den = ff_avs3_frame_rate_tab[seqh->frame_rate_code].den; - } - avctx->has_b_frames = seqh->output_reorder_delay; - avctx->pix_fmt = seqh->bit_depth_internal == 8 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUV420P10LE; - ret = ff_set_dimensions(avctx, seqh->horizontal_size, seqh->vertical_size); + ret = libuavs3d_on_seq_header(avctx); if (ret < 0) return ret; - h->got_seqhdr = 1; - - if (seqh->colour_description) { - if (UAVS3D_CHECK_INVALID_RANGE(seqh->colour_primaries, 0, 9) || - UAVS3D_CHECK_INVALID_RANGE(seqh->transfer_characteristics, 0, 14) || - UAVS3D_CHECK_INVALID_RANGE(seqh->matrix_coefficients, 0, 11)) { - av_log(avctx, AV_LOG_ERROR, - "Invalid colour description: primaries: %d" - "transfer characteristics: %d" - "matrix coefficients: %d.\n", - seqh->colour_primaries, - seqh->transfer_characteristics, - seqh->matrix_coefficients); - } else { - avctx->color_primaries = ff_avs3_color_primaries_tab[seqh->colour_primaries]; - avctx->color_trc = ff_avs3_color_transfer_tab [seqh->transfer_characteristics]; - avctx->colorspace = ff_avs3_color_matrix_tab [seqh->matrix_coefficients]; - } - } } if (frm_dec->got_pic) { break; diff --git a/libavcodec/libvo-amrwbenc.c b/libavcodec/libvo-amrwbenc.c index 02b8941a6..c68b66fc4 100644 --- a/libavcodec/libvo-amrwbenc.c +++ b/libavcodec/libvo-amrwbenc.c @@ -153,6 +153,5 @@ const FFCodec ff_libvo_amrwbenc_encoder = { .init = amr_wb_encode_init, FF_CODEC_ENCODE_CB(amr_wb_encode_frame), .close = amr_wb_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), }; diff --git a/libavcodec/libvorbisdec.c b/libavcodec/libvorbisdec.c index eb80ecf67..b38f423b9 100644 --- a/libavcodec/libvorbisdec.c +++ b/libavcodec/libvorbisdec.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include "avcodec.h" @@ -35,7 +36,8 @@ typedef struct OggVorbisDecContext { static int oggvorbis_decode_close(AVCodecContext *avccontext); -static int oggvorbis_decode_init(AVCodecContext *avccontext) { +static av_cold int oggvorbis_decode_init(AVCodecContext *avccontext) +{ OggVorbisDecContext *context = avccontext->priv_data ; uint8_t *p= avccontext->extradata; int i, hsizes[3], ret; @@ -123,7 +125,7 @@ static int oggvorbis_decode_init(AVCodecContext *avccontext) { avccontext->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; avccontext->ch_layout.nb_channels = context->vi.channels; avccontext->sample_rate = context->vi.rate; - avccontext->sample_fmt = AV_SAMPLE_FMT_S16; + avccontext->sample_fmt = AV_SAMPLE_FMT_FLTP; avccontext->time_base= (AVRational){1, avccontext->sample_rate}; vorbis_synthesis_init(&context->vd, &context->vi); @@ -137,33 +139,14 @@ static int oggvorbis_decode_init(AVCodecContext *avccontext) { } -static inline int conv(int samples, float **pcm, char *buf, int channels) { - int i, j; - ogg_int16_t *ptr, *data = (ogg_int16_t*)buf ; - float *mono ; - - for(i = 0 ; i < channels ; i++){ - ptr = &data[i]; - mono = pcm[i] ; - - for(j = 0 ; j < samples ; j++) { - *ptr = av_clip_int16(mono[j] * 32767.f); - ptr += channels; - } - } - - return 0 ; -} - static int oggvorbis_decode_frame(AVCodecContext *avccontext, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt) { OggVorbisDecContext *context = avccontext->priv_data ; float **pcm ; ogg_packet *op= &context->op; - int samples, total_samples, total_bytes; + int samples, total_samples; int ret; - int16_t *output; if(!avpkt->size){ //FIXME flush @@ -173,8 +156,6 @@ static int oggvorbis_decode_frame(AVCodecContext *avccontext, AVFrame *frame, frame->nb_samples = 8192*4; if ((ret = ff_get_buffer(avccontext, frame, 0)) < 0) return ret; - output = (int16_t *)frame->data[0]; - op->packet = avpkt->data; op->bytes = avpkt->size; @@ -189,11 +170,10 @@ static int oggvorbis_decode_frame(AVCodecContext *avccontext, AVFrame *frame, vorbis_synthesis_blockin(&context->vd, &context->vb) ; total_samples = 0 ; - total_bytes = 0 ; while((samples = vorbis_synthesis_pcmout(&context->vd, &pcm)) > 0) { - conv(samples, pcm, (char*)output + total_bytes, context->vi.channels) ; - total_bytes += samples * 2 * context->vi.channels ; + for (int ch = 0; ch < context->vi.channels; ch++) + memcpy((float *)frame->extended_data[ch] + total_samples, pcm[ch], samples * sizeof(float)); total_samples += samples ; vorbis_synthesis_read(&context->vd, samples) ; } @@ -204,7 +184,8 @@ static int oggvorbis_decode_frame(AVCodecContext *avccontext, AVFrame *frame, } -static int oggvorbis_decode_close(AVCodecContext *avccontext) { +static av_cold int oggvorbis_decode_close(AVCodecContext *avccontext) +{ OggVorbisDecContext *context = avccontext->priv_data ; vorbis_block_clear(&context->vb); diff --git a/libavcodec/libvorbisenc.c b/libavcodec/libvorbisenc.c index e4f8cb67e..c54ebebae 100644 --- a/libavcodec/libvorbisenc.c +++ b/libavcodec/libvorbisenc.c @@ -23,6 +23,7 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/fifo.h" +#include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" @@ -179,6 +180,62 @@ error: return vorbis_error_to_averror(ret); } +static av_cold int libvorbis_get_priming_samples(vorbis_info *vi, AVCodecContext *avctx) +{ + LibvorbisEncContext *s = avctx->priv_data; + vorbis_dsp_state vd; + vorbis_block vb; + ogg_packet op; + int ret; + + if ((ret = vorbis_analysis_init(&vd, vi))) { + av_log(avctx, AV_LOG_ERROR, "analysis init failed\n"); + return vorbis_error_to_averror(ret); + } + if ((ret = vorbis_block_init(&vd, &vb))) { + av_log(avctx, AV_LOG_ERROR, "dsp init failed\n"); + vorbis_dsp_clear(&vd); + return vorbis_error_to_averror(ret); + } + + if ((ret = vorbis_analysis_wrote(&vd, 0)) < 0) { + av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote() during init\n"); + ret = vorbis_error_to_averror(ret); + goto error; + } + + /* retrieve available packets from libvorbis */ + if ((ret = vorbis_analysis_blockout(&vd, &vb)) == 1) { + if ((ret = vorbis_analysis(&vb, NULL)) < 0) { + av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_blockout() during init\n"); + ret = vorbis_error_to_averror(ret); + goto error; + } + if ((ret = vorbis_bitrate_addblock(&vb)) < 0) { + av_log(avctx, AV_LOG_ERROR, "error in vorbis_bitrate_addblock() during init\n"); + ret = vorbis_error_to_averror(ret); + goto error; + } + + /* add any available packets to the output packet buffer */ + ret = vorbis_bitrate_flushpacket(&vd, &op); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "error in vorbis_bitrate_flushpacket() during init\n"); + ret = vorbis_error_to_averror(ret); + goto error; + } + } + + avctx->initial_padding = av_vorbis_parse_frame(s->vp, op.packet, op.bytes); + + ret = 0; +error: + vorbis_block_clear(&vb); + vorbis_dsp_clear(&vd); + + return ret; +} + /* How many bytes are needed for a buffer of length 'l' */ static int xiph_len(int l) { @@ -269,6 +326,9 @@ static av_cold int libvorbis_encode_init(AVCodecContext *avctx) vorbis_comment_clear(&s->vc); + if ((ret = libvorbis_get_priming_samples(&s->vi, avctx))) + return ret; + avctx->frame_size = LIBVORBIS_FRAME_SIZE; ff_af_queue_init(avctx, &s->afq); @@ -357,17 +417,19 @@ static int libvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, duration = av_vorbis_parse_frame(s->vp, avpkt->data, avpkt->size); if (duration > 0) { - /* we do not know encoder delay until we get the first packet from - * libvorbis, so we have to update the AudioFrameQueue counts */ - if (!avctx->initial_padding && s->afq.frames) { - avctx->initial_padding = duration; - av_assert0(!s->afq.remaining_delay); - s->afq.frames->duration += duration; - if (s->afq.frames->pts != AV_NOPTS_VALUE) - s->afq.frames->pts -= duration; - s->afq.remaining_samples += duration; - } + int discard_padding; + ff_af_queue_remove(&s->afq, duration, &avpkt->pts, &avpkt->duration); + + discard_padding = duration - ff_samples_from_time_base(avctx, avpkt->duration); + if (discard_padding > 0) { + uint8_t *side_data = av_packet_new_side_data(avpkt, + AV_PKT_DATA_SKIP_SAMPLES, + 10); + if (!side_data) + return AVERROR(ENOMEM); + AV_WL32(side_data + 4, discard_padding); + } } *got_packet_ptr = 1; @@ -386,8 +448,7 @@ const FFCodec ff_libvorbis_encoder = { .init = libvorbis_encode_init, FF_CODEC_ENCODE_CB(libvorbis_encode_frame), .close = libvorbis_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &vorbis_class, .defaults = defaults, .p.wrapper_name = "libvorbis", diff --git a/libavcodec/libvpxdec.c b/libavcodec/libvpxdec.c index c6187fd5a..317725bf3 100644 --- a/libavcodec/libvpxdec.c +++ b/libavcodec/libvpxdec.c @@ -41,6 +41,7 @@ #include "profiles.h" typedef struct VPxDecoderContext { + const struct vpx_codec_iface *iface; struct vpx_codec_ctx decoder; struct vpx_codec_ctx decoder_alpha; AVBufferPool *pool; @@ -84,9 +85,9 @@ static int release_frame_buffer(void *priv, vpx_codec_frame_buffer_t *fb) } static av_cold int vpx_init(AVCodecContext *avctx, - struct vpx_codec_ctx* decoder, - const struct vpx_codec_iface *iface) + struct vpx_codec_ctx* decoder) { + VPxContext *ctx = avctx->priv_data; struct vpx_codec_dec_cfg deccfg = { .threads = FFMIN(avctx->thread_count ? avctx->thread_count : av_cpu_count(), MAX_VPX_THREADS) }; @@ -94,15 +95,20 @@ static av_cold int vpx_init(AVCodecContext *avctx, av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str()); av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config()); - if (vpx_codec_dec_init(decoder, iface, &deccfg, 0) != VPX_CODEC_OK) { + if (vpx_codec_dec_init(decoder, ctx->iface, &deccfg, 0) != VPX_CODEC_OK) { const char *error = vpx_codec_error(decoder); av_log(avctx, AV_LOG_ERROR, "Failed to initialize decoder: %s\n", error); return AVERROR(EINVAL); } - if (avctx->codec_id == AV_CODEC_ID_VP9) - vpx_codec_set_frame_buffer_functions(decoder, get_frame_buffer, release_frame_buffer, avctx->priv_data); + if (vpx_codec_get_caps(ctx->iface) & VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER) { + if (vpx_codec_set_frame_buffer_functions(decoder, get_frame_buffer, release_frame_buffer, avctx->priv_data)) { + vpx_codec_destroy(decoder); + av_log(avctx, AV_LOG_ERROR, "Failed to set frame buffer.\n"); + return AVERROR_EXTERNAL; + } + } return 0; } @@ -134,23 +140,28 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, #if CONFIG_LIBVPX_VP9_DECODER case VPX_IMG_FMT_I422: avctx->profile = AV_PROFILE_VP9_1; - avctx->pix_fmt = AV_PIX_FMT_YUV422P; + avctx->pix_fmt = + has_alpha_channel ? AV_PIX_FMT_YUVA422P : AV_PIX_FMT_YUV422P; return 0; case VPX_IMG_FMT_I440: + //TODO: Add alpha support once the pixel format becomes available avctx->profile = AV_PROFILE_VP9_1; avctx->pix_fmt = AV_PIX_FMT_YUV440P; return 0; case VPX_IMG_FMT_I444: avctx->profile = AV_PROFILE_VP9_1; avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ? - AV_PIX_FMT_GBRP : AV_PIX_FMT_YUV444P; + (has_alpha_channel ? AV_PIX_FMT_GBRAP : AV_PIX_FMT_GBRP) : + (has_alpha_channel ? AV_PIX_FMT_YUVA444P : AV_PIX_FMT_YUV444P); return 0; case VPX_IMG_FMT_I42016: avctx->profile = AV_PROFILE_VP9_2; if (img->bit_depth == 10) { - avctx->pix_fmt = AV_PIX_FMT_YUV420P10; + avctx->pix_fmt = + has_alpha_channel ? AV_PIX_FMT_YUVA420P10 : AV_PIX_FMT_YUV420P10; return 0; } else if (img->bit_depth == 12) { + //TODO: Add alpha support once the pixel format becomes available avctx->pix_fmt = AV_PIX_FMT_YUV420P12; return 0; } else { @@ -159,15 +170,18 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, case VPX_IMG_FMT_I42216: avctx->profile = AV_PROFILE_VP9_3; if (img->bit_depth == 10) { - avctx->pix_fmt = AV_PIX_FMT_YUV422P10; + avctx->pix_fmt = + has_alpha_channel ? AV_PIX_FMT_YUVA422P10 : AV_PIX_FMT_YUV422P10; return 0; } else if (img->bit_depth == 12) { + //TODO: Add alpha support once the pixel format becomes available avctx->pix_fmt = AV_PIX_FMT_YUV422P12; return 0; } else { return AVERROR_INVALIDDATA; } case VPX_IMG_FMT_I44016: + //TODO: Add alpha support once the pixel format becomes available avctx->profile = AV_PROFILE_VP9_3; if (img->bit_depth == 10) { avctx->pix_fmt = AV_PIX_FMT_YUV440P10; @@ -182,11 +196,13 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, avctx->profile = AV_PROFILE_VP9_3; if (img->bit_depth == 10) { avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ? - AV_PIX_FMT_GBRP10 : AV_PIX_FMT_YUV444P10; + (has_alpha_channel ? AV_PIX_FMT_GBRAP10 : AV_PIX_FMT_GBRP10) : + (has_alpha_channel ? AV_PIX_FMT_YUVA444P10 : AV_PIX_FMT_YUV444P10); return 0; } else if (img->bit_depth == 12) { avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ? - AV_PIX_FMT_GBRP12 : AV_PIX_FMT_YUV444P12; + (has_alpha_channel ? AV_PIX_FMT_GBRAP12 : AV_PIX_FMT_GBRP12) : + (has_alpha_channel ? AV_PIX_FMT_YUVA444P12 : AV_PIX_FMT_YUV444P12); return 0; } else { return AVERROR_INVALIDDATA; @@ -239,17 +255,7 @@ static int vpx_decode(AVCodecContext *avctx, AVFrame *picture, if (additional_id == 1) { // 1 stands for alpha channel data. if (!ctx->has_alpha_channel) { ctx->has_alpha_channel = 1; - ret = vpx_init(avctx, - &ctx->decoder_alpha, -#if CONFIG_LIBVPX_VP8_DECODER && CONFIG_LIBVPX_VP9_DECODER - (avctx->codec_id == AV_CODEC_ID_VP8) ? - vpx_codec_vp8_dx() : vpx_codec_vp9_dx() -#elif CONFIG_LIBVPX_VP8_DECODER - vpx_codec_vp8_dx() -#else - vpx_codec_vp9_dx() -#endif - ); + ret = vpx_init(avctx, &ctx->decoder_alpha); if (ret) return ret; } @@ -308,7 +314,7 @@ static int vpx_decode(AVCodecContext *avctx, AVFrame *picture, linesizes[3] = ctx->has_alpha_channel ? img_alpha->stride[VPX_PLANE_Y] : 0; - if (img->fb_priv && (!ctx->has_alpha_channel || img_alpha->fb_priv)) { + if (vpx_codec_get_caps(ctx->iface) & VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER) { ret = ff_decode_frame_props(avctx, picture); if (ret < 0) return ret; @@ -349,7 +355,8 @@ static av_cold int vpx_free(AVCodecContext *avctx) static av_cold int vp8_init(AVCodecContext *avctx) { VPxContext *ctx = avctx->priv_data; - return vpx_init(avctx, &ctx->decoder, vpx_codec_vp8_dx()); + ctx->iface = vpx_codec_vp8_dx(); + return vpx_init(avctx, &ctx->decoder); } const FFCodec ff_libvpx_vp8_decoder = { @@ -372,7 +379,8 @@ const FFCodec ff_libvpx_vp8_decoder = { static av_cold int vp9_init(AVCodecContext *avctx) { VPxContext *ctx = avctx->priv_data; - return vpx_init(avctx, &ctx->decoder, vpx_codec_vp9_dx()); + ctx->iface = vpx_codec_vp9_dx(); + return vpx_init(avctx, &ctx->decoder); } const FFCodec ff_libvpx_vp9_decoder = { diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c index 228ede7c8..88c058c40 100644 --- a/libavcodec/libvpxenc.c +++ b/libavcodec/libvpxenc.c @@ -36,7 +36,6 @@ #include "libavutil/avassert.h" #include "libavutil/mem.h" #include "libvpx.h" -#include "packet_internal.h" #include "profiles.h" #include "libavutil/avstring.h" #include "libavutil/base64.h" @@ -203,15 +202,14 @@ static const char *const ctlidstr[] = { #endif }; -static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc) +static av_cold void log_encoder_error(void *logctx, struct vpx_codec_ctx *encoder, const char *desc) { - VPxContext *ctx = avctx->priv_data; - const char *error = vpx_codec_error(&ctx->encoder); - const char *detail = vpx_codec_error_detail(&ctx->encoder); + const char *error = vpx_codec_error(encoder); + const char *detail = vpx_codec_error_detail(encoder); - av_log(avctx, AV_LOG_ERROR, "%s: %s\n", desc, error); + av_log(logctx, AV_LOG_ERROR, "%s: %s\n", desc, error); if (detail) - av_log(avctx, AV_LOG_ERROR, " Additional information: %s\n", detail); + av_log(logctx, AV_LOG_ERROR, " Additional information: %s\n", detail); } static av_cold void dump_enc_cfg(AVCodecContext *avctx, @@ -243,7 +241,7 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx, width, "g_lag_in_frames:", cfg->g_lag_in_frames); av_log(avctx, level, "rate control settings\n" " %*s%u\n %*s%u\n %*s%u\n %*s%u\n" - " %*s%d\n %*s%p(%"SIZE_SPECIFIER")\n %*s%u\n", + " %*s%d\n %*s%p(%zu)\n %*s%u\n", width, "rc_dropframe_thresh:", cfg->rc_dropframe_thresh, width, "rc_resize_allowed:", cfg->rc_resize_allowed, width, "rc_resize_up_thresh:", cfg->rc_resize_up_thresh, @@ -353,6 +351,13 @@ static av_cold void fifo_free(AVFifo **fifo) av_fifo_freep2(fifo); } +static int encoder_can_drop_frames(AVCodecContext *avctx) +{ + VPxContext *ctx = avctx->priv_data; + + return (ctx->drop_threshold > 0) || (ctx->screen_content_mode == 2); +} + static int frame_data_submit(AVCodecContext *avctx, AVFifo *fifo, const AVFrame *frame) { @@ -384,6 +389,18 @@ static int frame_data_submit(AVCodecContext *avctx, AVFifo *fifo, } ret = av_fifo_write(fifo, &fd, 1); + if (ret == AVERROR(ENOSPC)) { + FrameData fd2; + + av_log(avctx, AV_LOG_WARNING, "FIFO full, will drop a front element\n"); + + ret = av_fifo_read(fifo, &fd2, 1); + if (ret >= 0) { + frame_data_uninit(&fd2); + ret = av_fifo_write(fifo, &fd, 1); + } + } + if (ret < 0) goto fail; @@ -399,13 +416,25 @@ static int frame_data_apply(AVCodecContext *avctx, AVFifo *fifo, AVPacket *pkt) uint8_t *data; int ret = 0; - if (av_fifo_peek(fifo, &fd, 1, 0) < 0) - return 0; - if (fd.pts != pkt->pts) { - av_log(avctx, AV_LOG_WARNING, - "Mismatching timestamps: libvpx %"PRId64" queued %"PRId64"; " - "this is a bug, please report it\n", pkt->pts, fd.pts); - goto skip; + while (1) { + if (av_fifo_peek(fifo, &fd, 1, 0) < 0) + return 0; + + if (fd.pts == pkt->pts) { + break; + } + + if (!encoder_can_drop_frames(avctx)) { + av_log(avctx, AV_LOG_WARNING, + "Mismatching timestamps: libvpx %"PRId64" queued %"PRId64"; " + "this is a bug, please report it\n", pkt->pts, fd.pts); + goto skip; + } + + av_log(avctx, AV_LOG_DEBUG, "Dropped frame with pts %"PRId64"\n", + fd.pts); + av_fifo_drain2(fifo, 1); + frame_data_uninit(&fd); } pkt->duration = fd.duration; @@ -447,16 +476,16 @@ static av_cold int codecctl_int(AVCodecContext *avctx, if (res != VPX_CODEC_OK) { snprintf(buf, sizeof(buf), "Failed to set %s codec control", ctlidstr[id]); - log_encoder_error(avctx, buf); + log_encoder_error(avctx, &ctx->encoder, buf); return AVERROR(EINVAL); } - if (ctx->is_alpha) { + if (ctx->is_alpha && id != VP9E_SET_COLOR_SPACE) { int res_alpha = vpx_codec_control(&ctx->encoder_alpha, id, val); if (res_alpha != VPX_CODEC_OK) { snprintf(buf, sizeof(buf), "Failed to set %s alpha codec control", ctlidstr[id]); - log_encoder_error(avctx, buf); + log_encoder_error(avctx, &ctx->encoder_alpha, buf); return AVERROR(EINVAL); } } @@ -480,7 +509,7 @@ static av_cold int codecctl_intp(AVCodecContext *avctx, if (res != VPX_CODEC_OK) { snprintf(buf, sizeof(buf), "Failed to set %s codec control", ctlidstr[id]); - log_encoder_error(avctx, buf); + log_encoder_error(avctx, &ctx->encoder, buf); return AVERROR(EINVAL); } @@ -489,7 +518,7 @@ static av_cold int codecctl_intp(AVCodecContext *avctx, if (res_alpha != VPX_CODEC_OK) { snprintf(buf, sizeof(buf), "Failed to set %s alpha codec control", ctlidstr[id]); - log_encoder_error(avctx, buf); + log_encoder_error(avctx, &ctx->encoder_alpha, buf); return AVERROR(EINVAL); } } @@ -796,6 +825,7 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, *img_fmt = VPX_IMG_FMT_I420; return 0; case AV_PIX_FMT_YUV422P: + case AV_PIX_FMT_YUVA422P: enccfg->g_profile = 1; *img_fmt = VPX_IMG_FMT_I422; return 0; @@ -804,12 +834,15 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, *img_fmt = VPX_IMG_FMT_I440; return 0; case AV_PIX_FMT_GBRP: + case AV_PIX_FMT_GBRAP: ctx->vpx_cs = VPX_CS_SRGB; case AV_PIX_FMT_YUV444P: + case AV_PIX_FMT_YUVA444P: enccfg->g_profile = 1; *img_fmt = VPX_IMG_FMT_I444; return 0; case AV_PIX_FMT_YUV420P10: + case AV_PIX_FMT_YUVA420P10: case AV_PIX_FMT_YUV420P12: if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) { enccfg->g_profile = 2; @@ -819,6 +852,7 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, } break; case AV_PIX_FMT_YUV422P10: + case AV_PIX_FMT_YUVA422P10: case AV_PIX_FMT_YUV422P12: if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) { enccfg->g_profile = 3; @@ -837,10 +871,14 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, } break; case AV_PIX_FMT_GBRP10: + case AV_PIX_FMT_GBRAP10: case AV_PIX_FMT_GBRP12: + case AV_PIX_FMT_GBRAP12: ctx->vpx_cs = VPX_CS_SRGB; case AV_PIX_FMT_YUV444P10: + case AV_PIX_FMT_YUVA444P10: case AV_PIX_FMT_YUV444P12: + case AV_PIX_FMT_YUVA444P12: if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) { enccfg->g_profile = 3; *img_fmt = VPX_IMG_FMT_I44416; @@ -975,12 +1013,21 @@ static av_cold int vpx_init(AVCodecContext *avctx, vpx_svc_extra_cfg_t svc_params; #endif const AVDictionaryEntry* en = NULL; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str()); av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config()); - if (avctx->pix_fmt == AV_PIX_FMT_YUVA420P) + if (desc && (desc->flags & AV_PIX_FMT_FLAG_ALPHA)) { ctx->is_alpha = 1; + if (avctx->pix_fmt != AV_PIX_FMT_YUVA420P && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { + av_log(avctx, AV_LOG_ERROR, + "Pixel format '%s' is not widely supported. " + "Use -strict experimental to use it anyway, or use 'yuva420p' pixel format instead.\n", + av_get_pix_fmt_name(avctx->pix_fmt)); + return AVERROR(EINVAL); + } + } if ((res = vpx_codec_enc_config_default(iface, &enccfg, 0)) != VPX_CODEC_OK) { av_log(avctx, AV_LOG_ERROR, "Failed to get config: %s\n", @@ -1118,7 +1165,7 @@ static av_cold int vpx_init(AVCodecContext *avctx, ret = av_reallocp(&ctx->twopass_stats.buf, ctx->twopass_stats.sz); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, - "Stat buffer alloc (%"SIZE_SPECIFIER" bytes) failed\n", + "Stat buffer alloc (%zu bytes) failed\n", ctx->twopass_stats.sz); ctx->twopass_stats.sz = 0; return ret; @@ -1153,7 +1200,7 @@ static av_cold int vpx_init(AVCodecContext *avctx, res = vpx_codec_enc_init(&ctx->encoder, iface, &enccfg, flags); if (res != VPX_CODEC_OK) { dump_enc_cfg(avctx, &enccfg, AV_LOG_WARNING); - log_encoder_error(avctx, "Failed to initialize encoder"); + log_encoder_error(avctx, &ctx->encoder, "Failed to initialize encoder"); return AVERROR(EINVAL); } dump_enc_cfg(avctx, &enccfg, AV_LOG_DEBUG); @@ -1175,9 +1222,10 @@ static av_cold int vpx_init(AVCodecContext *avctx, #endif if (ctx->is_alpha) { enccfg_alpha = enccfg; + enccfg_alpha.g_profile = (flags & VPX_CODEC_USE_HIGHBITDEPTH) ? 2 : 0; res = vpx_codec_enc_init(&ctx->encoder_alpha, iface, &enccfg_alpha, flags); if (res != VPX_CODEC_OK) { - log_encoder_error(avctx, "Failed to initialize alpha encoder"); + log_encoder_error(avctx, &ctx->encoder_alpha, "Failed to initialize alpha encoder"); return AVERROR(EINVAL); } } @@ -1324,7 +1372,7 @@ static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, VPxContext *ctx = avctx->priv_data; int ret = ff_get_encode_buffer(avctx, pkt, cx_frame->sz, 0); uint8_t *side_data; - int pict_type; + enum AVPictureType pict_type; int quality; if (ret < 0) @@ -1343,8 +1391,8 @@ static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, ret = vpx_codec_control(&ctx->encoder, VP8E_GET_LAST_QUANTIZER_64, &quality); if (ret != VPX_CODEC_OK) quality = 0; - ff_side_data_set_encoder_stats(pkt, quality * FF_QP2LAMBDA, cx_frame->sse + 1, - cx_frame->have_sse ? 3 : 0, pict_type); + ff_encode_add_stats_side_data(pkt, quality * FF_QP2LAMBDA, cx_frame->sse + 1, + cx_frame->have_sse ? 3 : 0, pict_type); if (cx_frame->have_sse) { /* Beware of the Y/U/V/all order! */ @@ -1424,7 +1472,7 @@ static int queue_frames(AVCodecContext *avctx, struct vpx_codec_ctx *encoder, if (!cx_frame->buf) { av_log(avctx, AV_LOG_ERROR, - "Data buffer alloc (%"SIZE_SPECIFIER" bytes) failed\n", + "Data buffer alloc (%zu bytes) failed\n", cx_frame->sz); av_freep(&cx_frame); return AVERROR(ENOMEM); @@ -1607,14 +1655,14 @@ static int vp9_encode_set_roi(AVCodecContext *avctx, int frame_width, int frame_ ret = set_roi_map(avctx, sd, frame_width, frame_height, &roi_map, block_size, segment_cnt); if (ret) { - log_encoder_error(avctx, "Failed to set_roi_map.\n"); + log_encoder_error(avctx, &ctx->encoder, "Failed to set_roi_map.\n"); return ret; } memset(roi_map.ref_frame, -1, sizeof(roi_map.ref_frame)); if (vpx_codec_control(&ctx->encoder, VP9E_SET_ROI_MAP, &roi_map)) { - log_encoder_error(avctx, "Failed to set VP9E_SET_ROI_MAP codec control.\n"); + log_encoder_error(avctx, &ctx->encoder, "Failed to set VP9E_SET_ROI_MAP codec control.\n"); ret = AVERROR_INVALIDDATA; } av_freep(&roi_map.roi_map); @@ -1639,12 +1687,12 @@ static int vp8_encode_set_roi(AVCodecContext *avctx, int frame_width, int frame_ int ret = set_roi_map(avctx, sd, frame_width, frame_height, &roi_map, block_size, segment_cnt); if (ret) { - log_encoder_error(avctx, "Failed to set_roi_map.\n"); + log_encoder_error(avctx, &ctx->encoder, "Failed to set_roi_map.\n"); return ret; } if (vpx_codec_control(&ctx->encoder, VP8E_SET_ROI_MAP, &roi_map)) { - log_encoder_error(avctx, "Failed to set VP8E_SET_ROI_MAP codec control.\n"); + log_encoder_error(avctx, &ctx->encoder, "Failed to set VP8E_SET_ROI_MAP codec control.\n"); ret = AVERROR_INVALIDDATA; } @@ -1663,18 +1711,28 @@ static int realloc_alpha_uv(AVCodecContext *avctx, int width, int height) !planes[VPX_PLANE_V] || width != (int)rawimg_alpha->d_w || height != (int)rawimg_alpha->d_h) { + vpx_img_fmt_t alpha_fmt = ctx->rawimg.bit_depth > 8 ? + VPX_IMG_FMT_I42016 : VPX_IMG_FMT_I420; av_freep(&planes[VPX_PLANE_U]); av_freep(&planes[VPX_PLANE_V]); - vpx_img_wrap(rawimg_alpha, VPX_IMG_FMT_I420, width, height, 1, + vpx_img_wrap(rawimg_alpha, alpha_fmt, width, height, 1, (unsigned char*)1); planes[VPX_PLANE_U] = av_malloc_array(stride[VPX_PLANE_U], height); planes[VPX_PLANE_V] = av_malloc_array(stride[VPX_PLANE_V], height); if (!planes[VPX_PLANE_U] || !planes[VPX_PLANE_V]) return AVERROR(ENOMEM); - memset(planes[VPX_PLANE_U], 0x80, stride[VPX_PLANE_U] * height); - memset(planes[VPX_PLANE_V], 0x80, stride[VPX_PLANE_V] * height); + if (ctx->rawimg.bit_depth > 8) { + int val = 0x80 << (ctx->rawimg.bit_depth - 8); + AV_WN16(planes[VPX_PLANE_U], val); + AV_WN16(planes[VPX_PLANE_V], val); + av_memcpy_backptr(planes[VPX_PLANE_U] + 2, 2, stride[VPX_PLANE_U] * height - 2); + av_memcpy_backptr(planes[VPX_PLANE_V] + 2, 2, stride[VPX_PLANE_V] * height - 2); + } else { + memset(planes[VPX_PLANE_U], 0x80, stride[VPX_PLANE_U] * height); + memset(planes[VPX_PLANE_V], 0x80, stride[VPX_PLANE_V] * height); + } } return 0; @@ -1699,7 +1757,7 @@ static int vpx_encode(AVCodecContext *avctx, AVPacket *pkt, cfg.rc_max_quantizer = avctx->qmax; res = vpx_codec_enc_config_set(&ctx->encoder, &cfg); if (res != VPX_CODEC_OK) { - log_encoder_error(avctx, "Error reconfiguring encoder"); + log_encoder_error(avctx, &ctx->encoder, "Error reconfiguring encoder"); return AVERROR_INVALIDDATA; } } @@ -1831,19 +1889,13 @@ static int vpx_encode(AVCodecContext *avctx, AVPacket *pkt, else if (avctx->framerate.num > 0 && avctx->framerate.den > 0) duration = av_rescale_q(1, av_inv_q(avctx->framerate), avctx->time_base); else { -FF_DISABLE_DEPRECATION_WARNINGS - duration = -#if FF_API_TICKS_PER_FRAME - avctx->ticks_per_frame ? avctx->ticks_per_frame : -#endif - 1; -FF_ENABLE_DEPRECATION_WARNINGS + duration = 1; } res = vpx_codec_encode(&ctx->encoder, rawimg, timestamp, duration, flags, ctx->deadline); if (res != VPX_CODEC_OK) { - log_encoder_error(avctx, "Error encoding frame"); + log_encoder_error(avctx, &ctx->encoder, "Error encoding frame"); return AVERROR_INVALIDDATA; } @@ -1851,7 +1903,7 @@ FF_ENABLE_DEPRECATION_WARNINGS res = vpx_codec_encode(&ctx->encoder_alpha, rawimg_alpha, timestamp, duration, flags, ctx->deadline); if (res != VPX_CODEC_OK) { - log_encoder_error(avctx, "Error encoding alpha frame"); + log_encoder_error(avctx, &ctx->encoder_alpha, "Error encoding alpha frame"); return AVERROR_INVALIDDATA; } } @@ -2044,7 +2096,7 @@ const FFCodec ff_libvpx_vp8_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class_vp8, .defaults = defaults, @@ -2062,9 +2114,12 @@ static const enum AVPixelFormat vp9_pix_fmts_highcol[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_GBRP, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_NONE }; @@ -2072,19 +2127,28 @@ static const enum AVPixelFormat vp9_pix_fmts_highbd[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUV440P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV440P12, AV_PIX_FMT_YUV444P12, + AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_GBRP, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRP12, + AV_PIX_FMT_GBRAP12, AV_PIX_FMT_NONE }; diff --git a/libavcodec/libvvenc.c b/libavcodec/libvvenc.c index ece9badb1..29a49ba09 100644 --- a/libavcodec/libvvenc.c +++ b/libavcodec/libvvenc.c @@ -128,20 +128,7 @@ static void vvenc_set_framerate(AVCodecContext *avctx, vvenc_config *params) params->m_FrameScale = avctx->time_base.num; } -FF_DISABLE_DEPRECATION_WARNINGS - -#if FF_API_TICKS_PER_FRAME - if (avctx->ticks_per_frame == 1) { -#endif - params->m_TicksPerSecond = -1; /* auto mode for ticks per frame = 1 */ -#if FF_API_TICKS_PER_FRAME - } else { - params->m_TicksPerSecond = - ceil((avctx->time_base.den / (double) avctx->time_base.num) * - (double) avctx->ticks_per_frame); - } -#endif -FF_ENABLE_DEPRECATION_WARNINGS + params->m_TicksPerSecond = -1; /* auto mode for ticks per frame = 1 */ } static int vvenc_parse_vvenc_params(AVCodecContext *avctx, vvenc_config *params) @@ -482,7 +469,7 @@ const FFCodec ff_libvvenc_encoder = { .p.priv_class = &class, .p.wrapper_name = "libvvenc", .priv_data_size = sizeof(VVenCContext), - .p.pix_fmts = pix_fmts_vvenc, + CODEC_PIXFMTS_ARRAY(pix_fmts_vvenc), .init = vvenc_init, FF_CODEC_ENCODE_CB(vvenc_frame), .close = vvenc_close, diff --git a/libavcodec/libwebpenc.c b/libavcodec/libwebpenc.c index 670412cc6..8ea1bc880 100644 --- a/libavcodec/libwebpenc.c +++ b/libavcodec/libwebpenc.c @@ -94,7 +94,7 @@ const FFCodec ff_libwebp_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_WEBP, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = ff_libwebpenc_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_libwebpenc_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_libwebpenc_class, .p.wrapper_name = "libwebp", diff --git a/libavcodec/libwebpenc_animencoder.c b/libavcodec/libwebpenc_animencoder.c index c5361d7f9..15592fbd1 100644 --- a/libavcodec/libwebpenc_animencoder.c +++ b/libavcodec/libwebpenc_animencoder.c @@ -167,7 +167,7 @@ const FFCodec ff_libwebp_anim_encoder = { .p.id = AV_CODEC_ID_WEBP, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = ff_libwebpenc_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_libwebpenc_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_libwebpenc_class, .p.wrapper_name = "libwebp", diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c index 409f45fc7..b688d4f32 100644 --- a/libavcodec/libx264.c +++ b/libavcodec/libx264.c @@ -22,7 +22,6 @@ #include "config_components.h" #include "libavutil/buffer.h" -#include "libavutil/eval.h" #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/mastering_display_metadata.h" @@ -30,7 +29,6 @@ #include "libavutil/pixdesc.h" #include "libavutil/stereo3d.h" #include "libavutil/time.h" -#include "libavutil/intreadwrite.h" #include "libavutil/video_hint.h" #include "avcodec.h" #include "codec_internal.h" @@ -615,7 +613,7 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, x264_nal_t *nal; int nnal, ret; x264_picture_t pic_out = {0}, *pic_in; - int pict_type; + enum AVPictureType pict_type; int64_t wallclock = 0; X264Opaque *out_opaque; @@ -730,8 +728,8 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, errors = sse; } - ff_side_data_set_encoder_stats(pkt, (pic_out.i_qpplus1 - 1) * FF_QP2LAMBDA, - errors, error_count, pict_type); + ff_encode_add_stats_side_data(pkt, (pic_out.i_qpplus1 - 1) * FF_QP2LAMBDA, + errors, error_count, pict_type); if (wallclock) ff_side_data_set_prft(pkt, wallclock); @@ -1317,13 +1315,7 @@ static av_cold int X264_init(AVCodecContext *avctx) x4->params.i_fps_den = avctx->framerate.den; } else { x4->params.i_fps_num = avctx->time_base.den; -FF_DISABLE_DEPRECATION_WARNINGS - x4->params.i_fps_den = avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + x4->params.i_fps_den = avctx->time_base.num; } x4->params.analyse.b_psnr = avctx->flags & AV_CODEC_FLAG_PSNR; @@ -1633,7 +1625,7 @@ const FFCodec ff_libx264_encoder = { .flush = X264_flush, .close = X264_close, .defaults = x264_defaults, - .p.pix_fmts = pix_fmts_all, + CODEC_PIXFMTS_ARRAY(pix_fmts_all), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS #if X264_BUILD < 158 @@ -1659,7 +1651,7 @@ const FFCodec ff_libx264rgb_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = pix_fmts_8bit_rgb, + CODEC_PIXFMTS_ARRAY(pix_fmts_8bit_rgb), .p.priv_class = &rgbclass, .p.wrapper_name = "libx264", .priv_data_size = sizeof(X264Context), @@ -1691,7 +1683,7 @@ const FFCodec ff_libx262_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = pix_fmts_8bit, + CODEC_PIXFMTS_ARRAY(pix_fmts_8bit), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &X262_class, .p.wrapper_name = "libx264", diff --git a/libavcodec/libx265.c b/libavcodec/libx265.c index 63cc497f8..7d488c0f4 100644 --- a/libavcodec/libx265.c +++ b/libavcodec/libx265.c @@ -38,10 +38,17 @@ #include "codec_internal.h" #include "dovi_rpu.h" #include "encode.h" -#include "packet_internal.h" #include "atsc_a53.h" #include "sei.h" +#if defined(X265_ENABLE_ALPHA) && MAX_LAYERS > 2 +#define FF_X265_MAX_LAYERS MAX_LAYERS +#elif X265_BUILD >= 210 +#define FF_X265_MAX_LAYERS 2 +#else +#define FF_X265_MAX_LAYERS 1 +#endif + typedef struct ReorderedData { int64_t duration; @@ -64,6 +71,7 @@ typedef struct libx265Context { char *preset; char *tune; char *profile; + char *stats; AVDictionary *x265_opts; void *sei_data; @@ -243,6 +251,24 @@ static int handle_side_data(AVCodecContext *avctx, const x265_api *api, return 0; } +static int get_x265_log_level(AVCodecContext *avctx) +{ + int level = av_log_get_level() + avctx->log_level_offset; + + if (level <= AV_LOG_QUIET) + return X265_LOG_NONE; + if (level <= AV_LOG_ERROR) + return X265_LOG_ERROR; + if (level <= AV_LOG_WARNING) + return X265_LOG_WARNING; + if (level <= AV_LOG_INFO) + return X265_LOG_INFO; + if (level <= AV_LOG_DEBUG) + return X265_LOG_DEBUG; + + return X265_LOG_FULL; +} + static av_cold int libx265_encode_init(AVCodecContext *avctx) { libx265Context *ctx = avctx->priv_data; @@ -278,19 +304,14 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } + ctx->params->logLevel = get_x265_log_level(avctx); ctx->params->frameNumThreads = avctx->thread_count; if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { ctx->params->fpsNum = avctx->framerate.num; ctx->params->fpsDenom = avctx->framerate.den; } else { ctx->params->fpsNum = avctx->time_base.den; -FF_DISABLE_DEPRECATION_WARNINGS - ctx->params->fpsDenom = avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + ctx->params->fpsDenom = avctx->time_base.num; } ctx->params->sourceWidth = avctx->width; ctx->params->sourceHeight = avctx->height; @@ -497,8 +518,22 @@ FF_ENABLE_DEPRECATION_WARNINGS { const AVDictionaryEntry *en = NULL; while ((en = av_dict_iterate(ctx->x265_opts, en))) { - int parse_ret = ctx->api->param_parse(ctx->params, en->key, en->value); + int parse_ret; + // ignore forced alpha option. The pixel format is all we need. + if (!strncmp(en->key, "alpha", 5)) { + if (desc->nb_components == 4) { + av_log(avctx, AV_LOG_WARNING, + "Ignoring redundant \"alpha\" option.\n"); + continue; + } + av_log(avctx, AV_LOG_ERROR, + "Alpha encoding was requested through an unsupported " + "option when no alpha plane is present\n"); + return AVERROR(EINVAL); + } + + parse_ret = ctx->api->param_parse(ctx->params, en->key, en->value); switch (parse_ret) { case X265_PARAM_BAD_NAME: av_log(avctx, AV_LOG_WARNING, @@ -514,6 +549,24 @@ FF_ENABLE_DEPRECATION_WARNINGS } } + if (avctx->flags & AV_CODEC_FLAG_PASS1) { + if (ctx->api->param_parse(ctx->params, "pass", "1") == X265_PARAM_BAD_VALUE) { + av_log(avctx, AV_LOG_ERROR, "Invalid value for param \"pass\".\n"); + return AVERROR(EINVAL); + } + } else if (avctx->flags & AV_CODEC_FLAG_PASS2) { + if (ctx->api->param_parse(ctx->params, "pass", "2") == X265_PARAM_BAD_VALUE) { + av_log(avctx, AV_LOG_ERROR, "Invalid value for param \"pass\".\n"); + return AVERROR(EINVAL); + } + } + if (ctx->stats) { + if (ctx->api->param_parse(ctx->params, "stats", ctx->stats) == X265_PARAM_BAD_VALUE) { + av_log(avctx, AV_LOG_ERROR, "Invalid value \"%s\" for param \"stats\".\n", ctx->stats); + return AVERROR(EINVAL); + } + } + if (ctx->params->rc.vbvBufferSize && avctx->rc_initial_buffer_occupancy > 1000 && ctx->params->rc.vbvBufferInit == 0.9) { ctx->params->rc.vbvBufferInit = (float)avctx->rc_initial_buffer_occupancy / 1000; @@ -539,6 +592,15 @@ FF_ENABLE_DEPRECATION_WARNINGS ctx->dovi.cfg.dv_bl_signal_compatibility_id; #endif +#if X265_BUILD >= 210 && FF_X265_MAX_LAYERS > 1 + if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) { + if (ctx->api->param_parse(ctx->params, "alpha", "1") < 0) { + av_log(avctx, AV_LOG_ERROR, "Loaded libx265 does not support alpha layer encoding.\n"); + return AVERROR(ENOTSUP); + } + } +#endif + ctx->encoder = ctx->api->encoder_open(ctx->params); if (!ctx->encoder) { av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n"); @@ -659,19 +721,16 @@ static void free_picture(libx265Context *ctx, x265_picture *pic) static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pic, int *got_packet) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); libx265Context *ctx = avctx->priv_data; x265_picture x265pic; + x265_picture x265pic_out[FF_X265_MAX_LAYERS] = { 0 }; #if (X265_BUILD >= 210) && (X265_BUILD < 213) - x265_picture x265pic_layers_out[MAX_SCALABLE_LAYERS]; - x265_picture* x265pic_lyrptr_out[MAX_SCALABLE_LAYERS]; -#else - x265_picture x265pic_solo_out = { 0 }; + x265_picture *x265pic_lyrptr_out[FF_X265_MAX_LAYERS]; #endif - x265_picture* x265pic_out; x265_nal *nal; x265_sei *sei; uint8_t *dst; - int pict_type; int payload = 0; int nnal; int ret; @@ -687,7 +746,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, ReorderedData *rd; int rd_idx; - for (i = 0; i < 3; i++) { + for (i = 0; i < desc->nb_components; i++) { x265pic.planes[i] = pic->data[i]; x265pic.stride[i] = pic->linesize[i]; } @@ -749,7 +808,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, sei_payload = &sei->payloads[sei->numPayloads]; sei_payload->payload = sei_data; sei_payload->payloadSize = sei_size; - sei_payload->payloadType = SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35; + sei_payload->payloadType = (SEIPayloadType)SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35; sei->numPayloads++; } } @@ -780,7 +839,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } sei_payload->payloadSize = side_data->size; /* Equal to libx265 USER_DATA_UNREGISTERED */ - sei_payload->payloadType = SEI_TYPE_USER_DATA_UNREGISTERED; + sei_payload->payloadType = (SEIPayloadType)SEI_TYPE_USER_DATA_UNREGISTERED; sei->numPayloads++; } } @@ -806,14 +865,14 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } #if (X265_BUILD >= 210) && (X265_BUILD < 213) - for (i = 0; i < MAX_SCALABLE_LAYERS; i++) - x265pic_lyrptr_out[i] = &x265pic_layers_out[i]; + for (i = 0; i < FF_ARRAY_ELEMS(x265pic_out); i++) + x265pic_lyrptr_out[i] = &x265pic_out[i]; ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal, pic ? &x265pic : NULL, x265pic_lyrptr_out); #else ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal, - pic ? &x265pic : NULL, &x265pic_solo_out); + pic ? &x265pic : NULL, x265pic_out); #endif for (i = 0; i < sei->numPayloads; i++) @@ -844,15 +903,10 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, pkt->flags |= AV_PKT_FLAG_KEY; } -#if (X265_BUILD >= 210) && (X265_BUILD < 213) - x265pic_out = x265pic_lyrptr_out[0]; -#else - x265pic_out = &x265pic_solo_out; -#endif - pkt->pts = x265pic_out->pts; pkt->dts = x265pic_out->dts; + enum AVPictureType pict_type; switch (x265pic_out->sliceType) { case X265_TYPE_IDR: case X265_TYPE_I: @@ -877,7 +931,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, #endif pkt->flags |= AV_PKT_FLAG_DISPOSABLE; - ff_side_data_set_encoder_stats(pkt, x265pic_out->frameData.qp * FF_QP2LAMBDA, NULL, 0, pict_type); + ff_encode_add_stats_side_data(pkt, x265pic_out->frameData.qp * FF_QP2LAMBDA, NULL, 0, pict_type); if (x265pic_out->userData) { int idx = (int)(intptr_t)x265pic_out->userData - 1; @@ -907,6 +961,9 @@ static const enum AVPixelFormat x265_csp_eight[] = { AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_GBRP, AV_PIX_FMT_GRAY8, +#if X265_BUILD >= 210 && FF_X265_MAX_LAYERS > 1 + AV_PIX_FMT_YUVA420P, +#endif AV_PIX_FMT_NONE }; @@ -924,6 +981,10 @@ static const enum AVPixelFormat x265_csp_ten[] = { AV_PIX_FMT_GBRP10, AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, +#if X265_BUILD >= 210 && FF_X265_MAX_LAYERS > 1 + AV_PIX_FMT_YUVA420P, + AV_PIX_FMT_YUVA420P10, +#endif AV_PIX_FMT_NONE }; @@ -946,6 +1007,10 @@ static const enum AVPixelFormat x265_csp_twelve[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, +#if X265_BUILD >= 210 && FF_X265_MAX_LAYERS > 1 + AV_PIX_FMT_YUVA420P, + AV_PIX_FMT_YUVA420P10, +#endif AV_PIX_FMT_NONE }; @@ -982,6 +1047,7 @@ static const AVOption options[] = { { "preset", "set the x265 preset", OFFSET(preset), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { "tune", "set the x265 tune parameter", OFFSET(tune), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { "profile", "set the x265 profile", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, + { "x265-stats", "Filename for 2 pass stats", OFFSET(stats), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { "udu_sei", "Use user data unregistered SEI if available", OFFSET(udu_sei), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "x265-params", "set the x265 configuration using a :-separated list of key=value parameters", OFFSET(x265_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, diff --git a/libavcodec/libxavs.c b/libavcodec/libxavs.c index d0f6e141c..e4db12a69 100644 --- a/libavcodec/libxavs.c +++ b/libavcodec/libxavs.c @@ -20,7 +20,6 @@ */ #include -#include #include #include #include @@ -29,7 +28,6 @@ #include "avcodec.h" #include "codec_internal.h" #include "encode.h" -#include "packet_internal.h" #include "libavutil/internal.h" #include "libavutil/mem.h" #include "libavutil/opt.h" @@ -128,7 +126,6 @@ static int XAVS_frame(AVCodecContext *avctx, AVPacket *pkt, xavs_nal_t *nal; int nnal, i, ret; xavs_picture_t pic_out; - int pict_type; x4->pic.img.i_csp = XAVS_CSP_I420; x4->pic.img.i_plane = 3; @@ -179,6 +176,7 @@ static int XAVS_frame(AVCodecContext *avctx, AVPacket *pkt, } else pkt->dts = pkt->pts; + enum AVPictureType pict_type; switch (pic_out.i_type) { case XAVS_TYPE_IDR: case XAVS_TYPE_I: @@ -201,7 +199,7 @@ static int XAVS_frame(AVCodecContext *avctx, AVPacket *pkt, pkt->flags |= AV_PKT_FLAG_KEY; } - ff_side_data_set_encoder_stats(pkt, (pic_out.i_qpplus1 - 1) * FF_QP2LAMBDA, NULL, 0, pict_type); + ff_encode_add_stats_side_data(pkt, (pic_out.i_qpplus1 - 1) * FF_QP2LAMBDA, NULL, 0, pict_type); x4->out_frame_count++; *got_packet = ret; @@ -434,7 +432,7 @@ const FFCodec ff_libxavs_encoder = { .close = XAVS_close, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_AUTO_THREADS, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &xavs_class, .defaults = xavs_defaults, diff --git a/libavcodec/libxavs2.c b/libavcodec/libxavs2.c index 1021d2ae2..d7583e8b6 100644 --- a/libavcodec/libxavs2.c +++ b/libavcodec/libxavs2.c @@ -299,8 +299,7 @@ const FFCodec ff_libxavs2_encoder = { .close = xavs2_close, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_AUTO_THREADS, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &libxavs2, .defaults = xavs2_defaults, diff --git a/libavcodec/libxeve.c b/libavcodec/libxeve.c index 61376f3e6..e87aa25f2 100644 --- a/libavcodec/libxeve.c +++ b/libavcodec/libxeve.c @@ -22,7 +22,6 @@ */ #include -#include #include @@ -32,13 +31,9 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" -#include "libavutil/time.h" #include "libavutil/cpu.h" -#include "libavutil/avstring.h" #include "avcodec.h" -#include "internal.h" -#include "packet_internal.h" #include "codec_internal.h" #include "profiles.h" #include "encode.h" @@ -472,8 +467,6 @@ static int libxeve_encode(AVCodecContext *avctx, AVPacket *avpkt, *got_packet = 0; return 0; } else if (ret == XEVE_OK) { - int av_pic_type; - if (xectx->stat.write > 0) { ret = ff_get_encode_buffer(avctx, avpkt, xectx->stat.write, 0); @@ -488,6 +481,7 @@ static int libxeve_encode(AVCodecContext *avctx, AVPacket *avpkt, avpkt->pts = xectx->bitb.ts[XEVE_TS_PTS]; avpkt->dts = xectx->bitb.ts[XEVE_TS_DTS]; + enum AVPictureType av_pic_type; switch(xectx->stat.stype) { case XEVE_ST_I: av_pic_type = AV_PICTURE_TYPE_I; @@ -504,7 +498,7 @@ static int libxeve_encode(AVCodecContext *avctx, AVPacket *avpkt, return AVERROR_INVALIDDATA; } - ff_side_data_set_encoder_stats(avpkt, xectx->stat.qp * FF_QP2LAMBDA, NULL, 0, av_pic_type); + ff_encode_add_stats_side_data(avpkt, xectx->stat.qp * FF_QP2LAMBDA, NULL, 0, av_pic_type); *got_packet = 1; } @@ -613,7 +607,7 @@ const FFCodec ff_libxeve_encoder = { .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1, .p.profiles = NULL_IF_CONFIG_SMALL(ff_evc_profiles), .p.wrapper_name = "libxeve", - .p.pix_fmts = supported_pixel_formats, + CODEC_PIXFMTS_ARRAY(supported_pixel_formats), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_NOT_INIT_THREADSAFE, }; diff --git a/libavcodec/libxvid.c b/libavcodec/libxvid.c index fbd33b706..94c521313 100644 --- a/libavcodec/libxvid.c +++ b/libavcodec/libxvid.c @@ -41,7 +41,6 @@ #include "codec_internal.h" #include "encode.h" #include "mpegutils.h" -#include "packet_internal.h" #if HAVE_UNISTD_H #include @@ -617,6 +616,10 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) x->intra_matrix = x->inter_matrix = NULL; + ret = ff_check_codec_matrices(avctx, FF_MATRIX_TYPE_INTRA | FF_MATRIX_TYPE_INTER, 1, 255); + if (ret < 0) + return ret; + if (x->mpeg_quant) x->vol_flags |= XVID_VOL_MPEGQUANT; if ((avctx->intra_matrix || avctx->inter_matrix)) { @@ -814,7 +817,7 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } if (xerr > 0) { - int pict_type; + enum AVPictureType pict_type; *got_packet = 1; @@ -827,7 +830,7 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt, else pict_type = AV_PICTURE_TYPE_I; - ff_side_data_set_encoder_stats(pkt, xvid_enc_stats.quant * FF_QP2LAMBDA, NULL, 0, pict_type); + ff_encode_add_stats_side_data(pkt, xvid_enc_stats.quant * FF_QP2LAMBDA, NULL, 0, pict_type); if (xvid_enc_frame.out_flags & XVID_KEYFRAME) { pkt->flags |= AV_PKT_FLAG_KEY; @@ -907,7 +910,7 @@ const FFCodec ff_libxvid_encoder = { .init = xvid_encode_init, FF_CODEC_ENCODE_CB(xvid_encode_frame), .close = xvid_encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &xvid_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/ljpegenc.c b/libavcodec/ljpegenc.c index 927420c2d..ab37ab0d5 100644 --- a/libavcodec/ljpegenc.c +++ b/libavcodec/ljpegenc.c @@ -252,7 +252,7 @@ static int ljpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, ff_mjpeg_encode_picture_trailer(&pb, header_bits); flush_put_bits(&pb); - pkt->size = put_bits_ptr(&pb) - pb.buf; + pkt->size = put_bytes_output(&pb); *got_packet = 1; return 0; @@ -323,10 +323,8 @@ const FFCodec ff_ljpeg_encoder = { .init = ljpeg_encode_init, FF_CODEC_ENCODE_CB(ljpeg_encode_frame), .close = ljpeg_encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_BGR24 , AV_PIX_FMT_BGRA , AV_PIX_FMT_BGR0, - AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, - AV_PIX_FMT_YUV420P , AV_PIX_FMT_YUV444P , AV_PIX_FMT_YUV422P, - AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR0, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, }; diff --git a/libavcodec/loongarch/h264dsp_init_loongarch.c b/libavcodec/loongarch/h264dsp_init_loongarch.c index b70fe696d..745915d5c 100644 --- a/libavcodec/loongarch/h264dsp_init_loongarch.c +++ b/libavcodec/loongarch/h264dsp_init_loongarch.c @@ -30,67 +30,67 @@ av_cold void ff_h264dsp_init_loongarch(H264DSPContext *c, const int bit_depth, if (have_lsx(cpu_flags)) { if (chroma_format_idc <= 1) - c->h264_loop_filter_strength = ff_h264_loop_filter_strength_lsx; + c->loop_filter_strength = ff_h264_loop_filter_strength_lsx; if (bit_depth == 8) { - c->h264_idct_add = ff_h264_idct_add_8_lsx; - c->h264_idct8_add = ff_h264_idct8_add_8_lsx; - c->h264_idct_dc_add = ff_h264_idct_dc_add_8_lsx; - c->h264_idct8_dc_add = ff_h264_idct8_dc_add_8_lsx; + c->idct_add = ff_h264_idct_add_8_lsx; + c->idct8_add = ff_h264_idct8_add_8_lsx; + c->idct_dc_add = ff_h264_idct_dc_add_8_lsx; + c->idct8_dc_add = ff_h264_idct8_dc_add_8_lsx; if (chroma_format_idc <= 1) { - c->h264_idct_add8 = ff_h264_idct_add8_8_lsx; - c->h264_h_loop_filter_chroma = ff_h264_h_lpf_chroma_8_lsx; - c->h264_h_loop_filter_chroma_intra = ff_h264_h_lpf_chroma_intra_8_lsx; + c->idct_add8 = ff_h264_idct_add8_8_lsx; + c->h_loop_filter_chroma = ff_h264_h_lpf_chroma_8_lsx; + c->h_loop_filter_chroma_intra = ff_h264_h_lpf_chroma_intra_8_lsx; } else - c->h264_idct_add8 = ff_h264_idct_add8_422_8_lsx; + c->idct_add8 = ff_h264_idct_add8_422_8_lsx; - c->h264_idct_add16 = ff_h264_idct_add16_8_lsx; - c->h264_idct8_add4 = ff_h264_idct8_add4_8_lsx; - c->h264_luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_8_lsx; - c->h264_idct_add16intra = ff_h264_idct_add16_intra_8_lsx; + c->idct_add16 = ff_h264_idct_add16_8_lsx; + c->idct8_add4 = ff_h264_idct8_add4_8_lsx; + c->luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_8_lsx; + c->idct_add16intra = ff_h264_idct_add16_intra_8_lsx; - c->h264_add_pixels4_clear = ff_h264_add_pixels4_8_lsx; - c->h264_add_pixels8_clear = ff_h264_add_pixels8_8_lsx; - c->h264_v_loop_filter_luma = ff_h264_v_lpf_luma_8_lsx; - c->h264_h_loop_filter_luma = ff_h264_h_lpf_luma_8_lsx; - c->h264_v_loop_filter_luma_intra = ff_h264_v_lpf_luma_intra_8_lsx; - c->h264_h_loop_filter_luma_intra = ff_h264_h_lpf_luma_intra_8_lsx; - c->h264_v_loop_filter_chroma = ff_h264_v_lpf_chroma_8_lsx; + c->add_pixels4_clear = ff_h264_add_pixels4_8_lsx; + c->add_pixels8_clear = ff_h264_add_pixels8_8_lsx; + c->v_loop_filter_luma = ff_h264_v_lpf_luma_8_lsx; + c->h_loop_filter_luma = ff_h264_h_lpf_luma_8_lsx; + c->v_loop_filter_luma_intra = ff_h264_v_lpf_luma_intra_8_lsx; + c->h_loop_filter_luma_intra = ff_h264_h_lpf_luma_intra_8_lsx; + c->v_loop_filter_chroma = ff_h264_v_lpf_chroma_8_lsx; - c->h264_v_loop_filter_chroma_intra = ff_h264_v_lpf_chroma_intra_8_lsx; + c->v_loop_filter_chroma_intra = ff_h264_v_lpf_chroma_intra_8_lsx; - c->biweight_h264_pixels_tab[0] = ff_biweight_h264_pixels16_8_lsx; - c->biweight_h264_pixels_tab[1] = ff_biweight_h264_pixels8_8_lsx; - c->biweight_h264_pixels_tab[2] = ff_biweight_h264_pixels4_8_lsx; - c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels16_8_lsx; - c->weight_h264_pixels_tab[1] = ff_weight_h264_pixels8_8_lsx; - c->weight_h264_pixels_tab[2] = ff_weight_h264_pixels4_8_lsx; - c->h264_idct8_add = ff_h264_idct8_add_8_lsx; - c->h264_idct8_dc_add = ff_h264_idct8_dc_add_8_lsx; + c->biweight_pixels_tab[0] = ff_biweight_h264_pixels16_8_lsx; + c->biweight_pixels_tab[1] = ff_biweight_h264_pixels8_8_lsx; + c->biweight_pixels_tab[2] = ff_biweight_h264_pixels4_8_lsx; + c->weight_pixels_tab[0] = ff_weight_h264_pixels16_8_lsx; + c->weight_pixels_tab[1] = ff_weight_h264_pixels8_8_lsx; + c->weight_pixels_tab[2] = ff_weight_h264_pixels4_8_lsx; + c->idct8_add = ff_h264_idct8_add_8_lsx; + c->idct8_dc_add = ff_h264_idct8_dc_add_8_lsx; } } #if HAVE_LASX if (have_lasx(cpu_flags)) { if (chroma_format_idc <= 1) - c->h264_loop_filter_strength = ff_h264_loop_filter_strength_lasx; + c->loop_filter_strength = ff_h264_loop_filter_strength_lasx; if (bit_depth == 8) { - c->h264_add_pixels4_clear = ff_h264_add_pixels4_8_lasx; - c->h264_add_pixels8_clear = ff_h264_add_pixels8_8_lasx; - c->h264_v_loop_filter_luma = ff_h264_v_lpf_luma_8_lasx; - c->h264_h_loop_filter_luma = ff_h264_h_lpf_luma_8_lasx; - c->h264_v_loop_filter_luma_intra = ff_h264_v_lpf_luma_intra_8_lasx; - c->h264_h_loop_filter_luma_intra = ff_h264_h_lpf_luma_intra_8_lasx; + c->add_pixels4_clear = ff_h264_add_pixels4_8_lasx; + c->add_pixels8_clear = ff_h264_add_pixels8_8_lasx; + c->v_loop_filter_luma = ff_h264_v_lpf_luma_8_lasx; + c->h_loop_filter_luma = ff_h264_h_lpf_luma_8_lasx; + c->v_loop_filter_luma_intra = ff_h264_v_lpf_luma_intra_8_lasx; + c->h_loop_filter_luma_intra = ff_h264_h_lpf_luma_intra_8_lasx; /* Weighted MC */ - c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels16_8_lasx; - c->weight_h264_pixels_tab[1] = ff_weight_h264_pixels8_8_lasx; + c->weight_pixels_tab[0] = ff_weight_h264_pixels16_8_lasx; + c->weight_pixels_tab[1] = ff_weight_h264_pixels8_8_lasx; - c->biweight_h264_pixels_tab[0] = ff_biweight_h264_pixels16_8_lasx; - c->biweight_h264_pixels_tab[1] = ff_biweight_h264_pixels8_8_lasx; + c->biweight_pixels_tab[0] = ff_biweight_h264_pixels16_8_lasx; + c->biweight_pixels_tab[1] = ff_biweight_h264_pixels8_8_lasx; - c->h264_idct8_add = ff_h264_idct8_add_8_lasx; - c->h264_idct8_dc_add = ff_h264_idct8_dc_add_8_lasx; - c->h264_idct8_add4 = ff_h264_idct8_add4_8_lasx; + c->idct8_add = ff_h264_idct8_add_8_lasx; + c->idct8_dc_add = ff_h264_idct8_dc_add_8_lasx; + c->idct8_add4 = ff_h264_idct8_add4_8_lasx; } } #endif // #if HAVE_LASX diff --git a/libavcodec/loongarch/hevc_mc.S b/libavcodec/loongarch/hevc_mc.S index 12d92e32e..b0eca55e6 100644 --- a/libavcodec/loongarch/hevc_mc.S +++ b/libavcodec/loongarch/hevc_mc.S @@ -674,7 +674,7 @@ endfunc vdp2.h.bu.b \out1, \in1, vr5 vdp2.h.bu.b vr12, \in2, vr5 vdp2.h.bu.b vr20, \in3, vr5 - vbsrl.v \in0, \in0, 1 //Back up previous 7 loaded datas, + vbsrl.v \in0, \in0, 1 //Back up previous 7 loaded data, vbsrl.v \in1, \in1, 1 //so just need to insert the 8th vbsrl.v \in2, \in2, 1 //load in the next loop. vbsrl.v \in3, \in3, 1 @@ -903,7 +903,7 @@ endfunc xvhaddw.d.h xr7 xvhaddw.d.h xr8 xvhaddw.d.h xr9 - xvbsrl.v xr14, xr14, 1 //Back up previous 7 loaded datas, + xvbsrl.v xr14, xr14, 1 //Back up previous 7 loaded data, xvbsrl.v xr15, xr15, 1 //so just need to insert the 8th xvbsrl.v xr16, xr16, 1 //load in next loop. xvbsrl.v xr17, xr17, 1 diff --git a/libavcodec/loongarch/hevc_mc_bi_lsx.c b/libavcodec/loongarch/hevc_mc_bi_lsx.c index d7ddd1c24..feb85956a 100644 --- a/libavcodec/loongarch/hevc_mc_bi_lsx.c +++ b/libavcodec/loongarch/hevc_mc_bi_lsx.c @@ -227,7 +227,7 @@ void hevc_bi_copy_8w_lsx(const uint8_t *src0_ptr, int32_t src_stride, const int16_t *src1_ptr, int32_t src2_stride, uint8_t *dst, int32_t dst_stride, int32_t height) { - int32_t loop_cnt = height >> 3; + uint32_t loop_cnt; int32_t res = (height & 7) >> 1; int32_t src_stride_2x = (src_stride << 1); int32_t dst_stride_2x = (dst_stride << 1); @@ -312,7 +312,8 @@ void hevc_bi_copy_12w_lsx(const uint8_t *src0_ptr, int32_t src_stride, const int16_t *src1_ptr, int32_t src2_stride, uint8_t *dst, int32_t dst_stride, int32_t height) { - uint32_t loop_cnt; + uint32_t loop_cnt = height >> 2; + uint32_t res = (height & 3) >> 1; int32_t src_stride_2x = (src_stride << 1); int32_t dst_stride_2x = (dst_stride << 1); int32_t src_stride_4x = (src_stride << 2); @@ -328,10 +329,9 @@ void hevc_bi_copy_12w_lsx(const uint8_t *src0_ptr, int32_t src_stride, __m128i in0, in1, in2, in3, in4, in5, in6, in7; __m128i dst0, dst1, dst2, dst3, dst4, dst5; - for (loop_cnt = 4; loop_cnt--;) { + for (; loop_cnt--;) { src0 = __lsx_vld(src0_ptr, 0); - DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, - src1, src2); + DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, src1, src2); src3 = __lsx_vldx(src0_ptr, src_stride_3x); src0_ptr += src_stride_4x; in0 = __lsx_vld(src1_ptr, 0); @@ -340,8 +340,7 @@ void hevc_bi_copy_12w_lsx(const uint8_t *src0_ptr, int32_t src_stride, in3 = __lsx_vldx(src1_ptr, src2_stride_3x); src1_ptr += src2_stride_2x; in4 = __lsx_vld(_src1, 0); - DUP2_ARG2(__lsx_vldx, _src1, src2_stride_x, _src1, src2_stride_2x, - in5, in6); + DUP2_ARG2(__lsx_vldx, _src1, src2_stride_x, _src1, src2_stride_2x, in5, in6); in7 = __lsx_vldx(_src1, src2_stride_3x); _src1 += src2_stride_2x; @@ -363,6 +362,31 @@ void hevc_bi_copy_12w_lsx(const uint8_t *src0_ptr, int32_t src_stride, __lsx_vstelm_w(out2, dst + dst_stride_3x, 8, 3); dst += dst_stride_4x; } + for (;res--;) { + src0 = __lsx_vld(src0_ptr, 0); + src1 = __lsx_vld(src0_ptr + src_stride, 0); + in0 = __lsx_vld(src1_ptr, 0); + in1 = __lsx_vldx(src1_ptr, src2_stride_x); + dst0 = __lsx_vsllwil_hu_bu(src0, 6); + dst1 = __lsx_vsllwil_hu_bu(src1, 6); + out0 = hevc_bi_rnd_clip(in0, dst0, in1, dst1); + __lsx_vstelm_d(out0, dst, 0, 0); + __lsx_vstelm_d(out0, dst + dst_stride, 0, 1); + + in0 = __lsx_vldrepl_d(_src1, 0); + in1 = __lsx_vldrepl_d(_src1 + src2_stride, 0); + src0 = __lsx_vilvh_w(src1, src0); + in0 = __lsx_vilvl_d(in1, in0); + dst0 = __lsx_vsllwil_hu_bu(src0, 6); + dst0 = __lsx_vsadd_h(dst0, in0); + dst0 = __lsx_vssrarni_bu_h(dst0, dst0, 7); + __lsx_vstelm_w(dst0, dst, 8, 0); + __lsx_vstelm_w(dst0, dst + dst_stride, 8, 1); + src0_ptr += src_stride_2x; + _src1 += src2_stride_x; + src1_ptr += src2_stride_x; + dst += dst_stride_2x; + } } static @@ -370,7 +394,8 @@ void hevc_bi_copy_16w_lsx(const uint8_t *src0_ptr, int32_t src_stride, const int16_t *src1_ptr, int32_t src2_stride, uint8_t *dst, int32_t dst_stride, int32_t height) { - uint32_t loop_cnt; + uint32_t loop_cnt = height >> 2; + uint32_t res = (height & 3) >> 1; int32_t src_stride_2x = (src_stride << 1); int32_t dst_stride_2x = (dst_stride << 1); int32_t src_stride_4x = (src_stride << 2); @@ -387,7 +412,7 @@ void hevc_bi_copy_16w_lsx(const uint8_t *src0_ptr, int32_t src_stride, __m128i dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; __m128i zero = {0}; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (; loop_cnt--;) { src0 = __lsx_vld(src0_ptr, 0); DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, src1, src2); @@ -420,6 +445,27 @@ void hevc_bi_copy_16w_lsx(const uint8_t *src0_ptr, int32_t src_stride, __lsx_vstx(out3, dst, dst_stride_3x); dst += dst_stride_4x; } + for (;res--;) { + src0 = __lsx_vld(src0_ptr, 0); + src1 = __lsx_vldx(src0_ptr, src_stride); + in0 = __lsx_vld(src1_ptr, 0); + in1 = __lsx_vldx(src1_ptr, src2_stride_x); + in4 = __lsx_vld(_src1, 0); + in5 = __lsx_vldx(_src1, src2_stride_x); + + DUP2_ARG2(__lsx_vsllwil_hu_bu, src0, 6, src1, 6, dst0_r, dst1_r); + DUP2_ARG2(__lsx_vilvh_b, zero, src0, zero, src1, dst0_l, dst1_l); + DUP2_ARG2(__lsx_vslli_h, dst0_l, 6, dst1_l, 6, dst0_l, dst1_l); + out0 = hevc_bi_rnd_clip(in0, dst0_r, in4, dst0_l); + out1 = hevc_bi_rnd_clip(in1, dst1_r, in5, dst1_l); + __lsx_vst(out0, dst, 0); + __lsx_vstx(out1, dst, dst_stride); + + src0_ptr += src_stride_2x; + _src1 += src2_stride_x; + src1_ptr += src2_stride_x; + dst += dst_stride_2x; + } } static @@ -1061,7 +1107,8 @@ static void hevc_hz_4t_24w_lsx(const uint8_t *src0_ptr, int32_t src_stride, { const int16_t *src1_ptr_tmp; uint8_t *dst_tmp; - uint32_t loop_cnt; + uint32_t loop_cnt = height >> 2; + uint32_t res = (height & 3) >> 1; int32_t dst_stride_2x = (dst_stride << 1); int32_t dst_stride_4x = (dst_stride << 2); int32_t dst_stride_3x = dst_stride_2x + dst_stride; @@ -1086,7 +1133,7 @@ static void hevc_hz_4t_24w_lsx(const uint8_t *src0_ptr, int32_t src_stride, dst_tmp = dst + 16; src1_ptr_tmp = src1_ptr + 16; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (; loop_cnt--;) { DUP2_ARG2(__lsx_vld, src0_ptr, 0, src0_ptr, 16, src0, src1); src0_ptr += src_stride; DUP2_ARG2(__lsx_vld, src0_ptr, 0, src0_ptr, 16, src2, src3); @@ -1155,6 +1202,42 @@ static void hevc_hz_4t_24w_lsx(const uint8_t *src0_ptr, int32_t src_stride, __lsx_vstelm_d(dst1, dst_tmp + dst_stride_3x, 0, 1); dst_tmp += dst_stride_4x; } + for (; res--;) { + DUP2_ARG2(__lsx_vld, src0_ptr, 0, src0_ptr, 16, src0, src1); + src0_ptr += src_stride; + DUP2_ARG2(__lsx_vld, src0_ptr, 0, src0_ptr, 16, src2, src3); + src0_ptr += src_stride; + DUP2_ARG2(__lsx_vld, src1_ptr, 0, src1_ptr, 16, in0, in1); + src1_ptr += src2_stride; + DUP2_ARG2(__lsx_vld, src1_ptr, 0, src1_ptr, 16, in2, in3); + src1_ptr += src2_stride; + + DUP4_ARG3(__lsx_vshuf_b, src0, src0, mask0, src1, src0, mask2, src2, + src2, mask0, src3, src2, mask2, vec0, vec1, vec2, vec3); + DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec1, filt0, vec2, filt0, + vec3, filt0, dst0, dst1, dst2, dst3); + DUP4_ARG3(__lsx_vshuf_b, src0, src0, mask1, src1, src0, mask3, src2, + src2, mask1, src3, src2, mask3, vec0, vec1, vec2, vec3); + DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec0, filt1, dst1, vec1, filt1, + dst2, vec2, filt1, dst3, vec3, filt1, dst0, dst1, dst2, dst3); + dst0 = hevc_bi_rnd_clip(in0, dst0, in1, dst1); + dst1 = hevc_bi_rnd_clip(in2, dst2, in3, dst3); + __lsx_vst(dst0, dst, 0); + __lsx_vstx(dst1, dst, dst_stride); + dst += dst_stride_2x; + + in0 = __lsx_vld(src1_ptr_tmp, 0); + in1 = __lsx_vldx(src1_ptr_tmp, src2_stride_x); + src1_ptr_tmp += src2_stride_x; + DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask0, src3, src3, mask0, vec0, vec1); + DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec1, filt0, dst0, dst1); + DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask1, src3, src3, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec0, filt1, dst1, vec1, filt1, dst0, dst1); + dst0 = hevc_bi_rnd_clip(in0, dst0, in1, dst1); + __lsx_vstelm_d(dst0, dst_tmp, 0, 0); + __lsx_vstelm_d(dst0, dst_tmp + dst_stride, 0, 1); + dst_tmp += dst_stride_2x; + } } static void hevc_hz_4t_32w_lsx(const uint8_t *src0_ptr, int32_t src_stride, @@ -1206,7 +1289,7 @@ static void hevc_vt_4t_12w_lsx(const uint8_t *src0_ptr, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - int32_t loop_cnt; + uint32_t loop_cnt; int32_t src_stride_2x = (src_stride << 1); int32_t dst_stride_2x = (dst_stride << 1); int32_t dst_stride_4x = (dst_stride << 2); @@ -1295,7 +1378,7 @@ static void hevc_vt_4t_16w_lsx(const uint8_t *src0_ptr, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - int32_t loop_cnt; + uint32_t loop_cnt = height >> 2; const int32_t src_stride_2x = (src_stride << 1); const int32_t dst_stride_2x = (dst_stride << 1); const int32_t src_stride_3x = src_stride_2x + src_stride; @@ -1316,7 +1399,7 @@ static void hevc_vt_4t_16w_lsx(const uint8_t *src0_ptr, int32_t src_stride, DUP2_ARG2(__lsx_vilvl_b, src1, src0, src2, src1, src10_r, src21_r); DUP2_ARG2(__lsx_vilvh_b, src1, src0, src2, src1, src10_l, src21_l); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (; loop_cnt--;) { src3 = __lsx_vld(src0_ptr, 0); src4 = __lsx_vldx(src0_ptr, src_stride); src0_ptr += src_stride_2x; @@ -1480,193 +1563,6 @@ static void hevc_vt_4t_32w_lsx(const uint8_t *src0_ptr, int32_t src_stride, dst + 16, dst_stride, filter, height); } -static void hevc_hv_4t_6w_lsx(const uint8_t *src0_ptr, int32_t src_stride, - const int16_t *src1_ptr, int32_t src2_stride, - uint8_t *dst, int32_t dst_stride, - const int8_t *filter_x, const int8_t *filter_y, - int32_t height) -{ - int32_t src_stride_2x = (src_stride << 1); - int32_t dst_stride_2x = (dst_stride << 1); - int32_t src_stride_4x = (src_stride << 2); - int32_t dst_stride_4x = (dst_stride << 2); - int32_t src2_stride_2x = (src2_stride << 1); - int32_t src2_stride_4x = (src2_stride << 2); - int32_t src_stride_3x = src_stride_2x + src_stride; - int32_t dst_stride_3x = dst_stride_2x + dst_stride; - int32_t src2_stride_3x = src2_stride_2x + src2_stride; - __m128i out0, out1; - __m128i src0, src1, src2, src3, src4, src5, src6; - __m128i vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, mask1; - __m128i filt0, filt1, filt_h0, filt_h1; - __m128i dsth0, dsth1, dsth2, dsth3, dsth4, dsth5; - __m128i dsth6, dsth7, dsth8, dsth9, dsth10; - __m128i dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - __m128i dst4_r, dst5_r, dst6_r, dst7_r; - __m128i tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; - __m128i reg0, reg1, reg2, reg3; - __m128i mask0 = __lsx_vld(ff_hevc_mask_arr, 0); - - src0_ptr -= (src_stride + 1); - DUP2_ARG2(__lsx_vldrepl_h, filter_x, 0, filter_x, 2, filt0, filt1); - - filt_h1 = __lsx_vld(filter_y, 0); - filt_h1 = __lsx_vsllwil_h_b(filt_h1, 0); - DUP2_ARG2(__lsx_vreplvei_w, filt_h1, 0, filt_h1, 1, filt_h0, filt_h1); - - mask1 = __lsx_vaddi_bu(mask0, 2); - - src0 = __lsx_vld(src0_ptr, 0); - DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, - src1, src2); - src0_ptr += src_stride_3x; - - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask0, src1, src1, mask1, vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src2, src2, mask1, vec4, vec5); - - DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dsth0, dsth1); - dsth2 = __lsx_vdp2_h_bu_b(vec4, filt0); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dsth0, vec1, filt1, dsth1, vec3, filt1, - dsth0, dsth1); - dsth2 = __lsx_vdp2add_h_bu_b(dsth2, vec5, filt1); - - DUP2_ARG2(__lsx_vilvl_h, dsth1, dsth0, dsth2, dsth1, tmp0, tmp2); - DUP2_ARG2(__lsx_vilvh_h, dsth1, dsth0, dsth2, dsth1, tmp1, tmp3); - - src3 = __lsx_vld(src0_ptr, 0); - DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, - src4, src5); - src6 = __lsx_vldx(src0_ptr, src_stride_3x); - src0_ptr += src_stride_4x; - DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, vec4, vec5); - DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, vec6, vec7); - - DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, vec6, - filt0, dsth3, dsth4, dsth5, dsth6); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dsth3, vec1, filt1, dsth4, vec3, filt1, dsth5, - vec5, filt1, dsth6, vec7, filt1, dsth3, dsth4, dsth5, dsth6); - - src3 = __lsx_vld(src0_ptr, 0); - DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, - src4, src5); - src6 = __lsx_vldx(src0_ptr, src_stride_3x); - - DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, vec4, vec5); - DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, vec6, vec7); - - DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, vec6, - filt0, dsth7, dsth8, dsth9, dsth10); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dsth7, vec1, filt1, dsth8, vec3, filt1, dsth9, - vec5, filt1, dsth10, vec7, filt1, dsth7, dsth8, dsth9, dsth10); - - DUP2_ARG2(__lsx_vilvl_h, dsth3, dsth2, dsth4, dsth3, tmp4, tmp6); - DUP2_ARG2(__lsx_vilvh_h, dsth3, dsth2, dsth4, dsth3, tmp5, tmp7); - DUP2_ARG2(__lsx_vilvl_h, dsth5, dsth4, dsth6, dsth5, dsth0, dsth2); - DUP2_ARG2(__lsx_vilvh_h, dsth5, dsth4, dsth6, dsth5, dsth1, dsth3); - DUP4_ARG2(__lsx_vdp2_w_h, tmp0, filt_h0, tmp2, filt_h0, tmp4, filt_h0, - tmp6, filt_h0, dst0_r, dst1_r, dst2_r, dst3_r); - DUP4_ARG3(__lsx_vdp2add_w_h, dst0_r, tmp4, filt_h1, dst1_r, tmp6, - filt_h1, dst2_r, dsth0, filt_h1, dst3_r, dsth2, filt_h1, - dst0_r, dst1_r, dst2_r, dst3_r); - DUP2_ARG2(__lsx_vpickev_d, tmp3, tmp1, tmp7, tmp5, tmp0, tmp8); - dst0_l = __lsx_vdp2_w_h(tmp0, filt_h0); - dst0_l = __lsx_vdp2add_w_h(dst0_l, tmp8, filt_h1); - - DUP2_ARG2(__lsx_vilvl_h, dsth7, dsth6, dsth8, dsth7, tmp0, tmp2); - DUP2_ARG2(__lsx_vilvh_h, dsth7, dsth6, dsth8, dsth7, tmp1, tmp3); - DUP2_ARG2(__lsx_vilvl_h, dsth9, dsth8, dsth10, dsth9, tmp4, tmp6); - DUP2_ARG2(__lsx_vilvh_h, dsth9, dsth8, dsth10, dsth9, tmp5, tmp7); - DUP4_ARG2(__lsx_vdp2_w_h, dsth0, filt_h0, dsth2, filt_h0, tmp0, filt_h0, - tmp2, filt_h0, dst4_r, dst5_r, dst6_r, dst7_r); - DUP4_ARG3(__lsx_vdp2add_w_h, dst4_r, tmp0, filt_h1, dst5_r, tmp2, - filt_h1, dst6_r, tmp4, filt_h1, dst7_r, tmp6, filt_h1, - dst4_r, dst5_r, dst6_r, dst7_r); - DUP2_ARG2(__lsx_vpickev_d, dsth3, dsth1, tmp3, tmp1, tmp0, tmp1); - tmp2 = __lsx_vpickev_d(tmp7, tmp5); - - DUP2_ARG2(__lsx_vdp2_w_h, tmp8, filt_h0, tmp0, filt_h0, dst1_l, dst2_l); - dst3_l = __lsx_vdp2_w_h(tmp1, filt_h0); - DUP2_ARG3(__lsx_vdp2add_w_h, dst1_l, tmp0, filt_h1, dst2_l, tmp1, filt_h1, - dst1_l, dst2_l); - dst3_l = __lsx_vdp2add_w_h(dst3_l, tmp2, filt_h1); - - DUP4_ARG2(__lsx_vsrai_d, dst0_r, 6, dst1_r, 6, dst2_r, 6, dst3_r, 6, - dst0_r, dst1_r, dst2_r, dst3_r); - DUP4_ARG2(__lsx_vsrai_d, dst4_r, 6, dst5_r, 6, dst6_r, 6, dst7_r, 6, - dst4_r, dst5_r, dst6_r, dst7_r); - DUP4_ARG2(__lsx_vsrai_d, dst0_l, 6, dst1_l, 6, dst2_l, 6, dst3_l, 6, - dst0_l, dst1_l, dst2_l, dst3_l); - DUP2_ARG2(__lsx_vpickev_h, dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); - DUP2_ARG2(__lsx_vpickev_h, dst5_r, dst4_r, dst7_r, dst6_r, tmp2, tmp3); - DUP2_ARG2(__lsx_vpickev_h, dst1_l, dst0_l, dst3_l, dst2_l, tmp4, tmp5); - - reg0 = __lsx_vldrepl_d(src1_ptr, 0); - reg1 = __lsx_vldrepl_d(src1_ptr + src2_stride, 0); - dsth0 = __lsx_vilvl_d(reg1, reg0); - reg0 = __lsx_vldrepl_d(src1_ptr + src2_stride_2x, 0); - reg1 = __lsx_vldrepl_d(src1_ptr + src2_stride_3x, 0); - dsth1 = __lsx_vilvl_d(reg1, reg0); - src1_ptr += src2_stride_4x; - reg0 = __lsx_vldrepl_d(src1_ptr, 0); - reg1 = __lsx_vldrepl_d(src1_ptr + src2_stride, 0); - dsth2 = __lsx_vilvl_d(reg1, reg0); - reg0 = __lsx_vldrepl_d(src1_ptr + src2_stride_2x, 0); - reg1 = __lsx_vldrepl_d(src1_ptr + src2_stride_3x, 0); - dsth3 = __lsx_vilvl_d(reg1, reg0); - - DUP4_ARG2(__lsx_vsadd_h, dsth0, tmp0, dsth1, tmp1, dsth2, tmp2, dsth3, - tmp3, tmp0, tmp1, tmp2, tmp3); - DUP4_ARG2(__lsx_vmaxi_h, tmp0, 0, tmp1, 0, tmp2, 0, tmp3, 0, - tmp0, tmp1, tmp2, tmp3); - DUP2_ARG3(__lsx_vssrlrni_bu_h, tmp1, tmp0, 7, tmp3, tmp2, 7, out0, out1); - - __lsx_vstelm_w(out0, dst, 0, 0); - __lsx_vstelm_w(out0, dst + dst_stride, 0, 1); - __lsx_vstelm_w(out0, dst + dst_stride_2x, 0, 2); - __lsx_vstelm_w(out0, dst + dst_stride_3x, 0, 3); - dst += dst_stride_4x; - __lsx_vstelm_w(out1, dst, 0, 0); - __lsx_vstelm_w(out1, dst + dst_stride, 0, 1); - __lsx_vstelm_w(out1, dst + dst_stride_2x, 0, 2); - __lsx_vstelm_w(out1, dst + dst_stride_3x, 0, 3); - dst -= dst_stride_4x; - - src1_ptr -= src2_stride_4x; - - reg0 = __lsx_vldrepl_w(src1_ptr, 8); - reg1 = __lsx_vldrepl_w(src1_ptr + src2_stride, 8); - reg2 = __lsx_vldrepl_w(src1_ptr + src2_stride_2x, 8); - reg3 = __lsx_vldrepl_w(src1_ptr + src2_stride_3x, 8); - DUP2_ARG2(__lsx_vilvl_w, reg1, reg0, reg3, reg2, tmp0, tmp1); - dsth4 = __lsx_vilvl_d(tmp1, tmp0); - src1_ptr += src2_stride_4x; - - reg0 = __lsx_vldrepl_w(src1_ptr, 8); - reg1 = __lsx_vldrepl_w(src1_ptr + src2_stride, 8); - reg2 = __lsx_vldrepl_w(src1_ptr + src2_stride_2x, 8); - reg3 = __lsx_vldrepl_w(src1_ptr + src2_stride_3x, 8); - DUP2_ARG2(__lsx_vilvl_w, reg1, reg0, reg3, reg2, tmp0, tmp1); - dsth5 = __lsx_vilvl_d(tmp1, tmp0); - DUP2_ARG2(__lsx_vsadd_h, dsth4, tmp4, dsth5, tmp5, tmp4, tmp5); - DUP2_ARG2(__lsx_vmaxi_h, tmp4, 0, tmp5, 7, tmp4, tmp5); - out0 = __lsx_vssrlrni_bu_h(tmp5, tmp4, 7); - - __lsx_vstelm_h(out0, dst, 4, 0); - __lsx_vstelm_h(out0, dst + dst_stride, 4, 1); - __lsx_vstelm_h(out0, dst + dst_stride_2x, 4, 2); - __lsx_vstelm_h(out0, dst + dst_stride_3x, 4, 3); - dst += dst_stride_4x; - __lsx_vstelm_h(out0, dst, 4, 4); - __lsx_vstelm_h(out0, dst + dst_stride, 4, 5); - __lsx_vstelm_h(out0, dst + dst_stride_2x, 4, 6); - __lsx_vstelm_h(out0, dst + dst_stride_3x, 4, 7); -} - static av_always_inline void hevc_hv_4t_8x2_lsx(const uint8_t *src0_ptr, int32_t src_stride, const int16_t *src1_ptr, int32_t src2_stride, uint8_t *dst, int32_t dst_stride, @@ -2281,7 +2177,6 @@ BI_MC_HV(qpel, 48, 8); BI_MC_HV(qpel, 64, 8); BI_MC_HV(epel, 8, 4); -BI_MC_HV(epel, 6, 4); BI_MC_HV(epel, 16, 4); BI_MC_HV(epel, 24, 4); BI_MC_HV(epel, 32, 4); diff --git a/libavcodec/loongarch/hevc_mc_uni_lsx.c b/libavcodec/loongarch/hevc_mc_uni_lsx.c index 6bdc27a82..5ec115bab 100644 --- a/libavcodec/loongarch/hevc_mc_uni_lsx.c +++ b/libavcodec/loongarch/hevc_mc_uni_lsx.c @@ -545,7 +545,7 @@ static void hevc_hv_8t_64w_lsx(const uint8_t *src, int32_t src_stride, uint8_t * } static av_always_inline -void common_vt_4t_24w_lsx(const uint8_t *src, int32_t src_stride, +void common_vt_2t_24w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { @@ -554,8 +554,8 @@ void common_vt_4t_24w_lsx(const uint8_t *src, int32_t src_stride, int32_t src_stride_3x = src_stride_2x + src_stride; const uint8_t *_src; - __m128i src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; - __m128i src11, filt0, filt1; + __m128i src0, src1, src2, src3, src4, src6, src7, src8, src9, src10; + __m128i filt0, filt1; __m128i src10_r, src32_r, src76_r, src98_r, src21_r, src43_r, src87_r; __m128i src109_r, src10_l, src32_l, src21_l, src43_l; __m128i out0_r, out1_r, out2_r, out3_r, out0_l, out1_l; @@ -578,7 +578,7 @@ void common_vt_4t_24w_lsx(const uint8_t *src, int32_t src_stride, _src += src_stride_3x; DUP2_ARG2(__lsx_vilvl_b, src7, src6, src8, src7, src76_r, src87_r); - for (loop_cnt = 8; loop_cnt--;) { + for (loop_cnt = height >> 1; loop_cnt--;) { /* 16 width */ DUP2_ARG2(__lsx_vld, src, 0, _src, 0, src3, src9); DUP2_ARG2(__lsx_vldx, src, src_stride, _src, src_stride, src4, src10); @@ -605,53 +605,27 @@ void common_vt_4t_24w_lsx(const uint8_t *src, int32_t src_stride, /* 16 + 8 width */ DUP4_ARG3(__lsx_vssrarni_bu_h, out0_l, out0_r, 6, out2_r, out2_r, 6, - out3_r, out3_r, 6, out1_l, out1_r, 6, out1, out2, out3, out4); - __lsx_vst(out1, dst, 0); - __lsx_vstelm_d(out2, dst, 16, 0); - dst += dst_stride; - __lsx_vst(out4, dst, 0); - __lsx_vstelm_d(out3, dst, 16, 0); - dst += dst_stride; - - /* 16 width */ - DUP2_ARG2(__lsx_vld, src, 0, _src, 0, src5, src11); - DUP2_ARG2(__lsx_vldx, src, src_stride, _src, src_stride, src2, src8); - DUP2_ARG2(__lsx_vilvl_b, src5, src4, src2, src5, src10_r, src21_r); - DUP2_ARG2(__lsx_vilvh_b, src5, src4, src2, src5, src10_l, src21_l); - - /* 8 width */ - src += src_stride_2x; - _src += src_stride_2x; - DUP2_ARG2(__lsx_vilvl_b, src11, src10, src8, src11, src76_r, src87_r); - - /* 16 width */ - DUP4_ARG2(__lsx_vdp2_h_bu_b, src32_r, filt0, src32_l, filt0, src43_r, - filt0, src43_l, filt0, out0_r, out0_l, out1_r, out1_l); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, out0_r, src10_r, filt1, out0_l, src10_l, - filt1, out1_r, src21_r, filt1, out1_l, src21_l, filt1, - out0_r, out0_l, out1_r, out1_l); - - /* 8 width */ - DUP2_ARG2(__lsx_vdp2_h_bu_b, src98_r, filt0, src109_r, filt0, - out2_r, out3_r); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, out2_r, src76_r, filt1, out3_r, - src87_r, filt1, out2_r, out3_r); - - /* 16 + 8 width */ - DUP4_ARG3(__lsx_vssrarni_bu_h, out0_l, out0_r, 6, out2_r, out2_r, 6, - out1_l, out1_r, 6, out3_r, out3_r, 6, out1, out2, out3, out4); - + out1_l, out1_r, 6, out3_r, out3_r, 6, out1, out2, out3, out4); __lsx_vst(out1, dst, 0); __lsx_vstelm_d(out2, dst, 16, 0); dst += dst_stride; __lsx_vst(out3, dst, 0); __lsx_vstelm_d(out4, dst, 16, 0); dst += dst_stride; + + src10_r = src32_r; + src21_r = src43_r; + src10_l = src32_l; + src21_l = src43_l; + src2 = src4; + src76_r = src98_r; + src87_r = src109_r; + src8 = src10; } } static av_always_inline -void common_vt_4t_32w_lsx(const uint8_t *src, int32_t src_stride, +void common_vt_2t_32w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { @@ -805,102 +779,6 @@ void hevc_hv_4t_8x2_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, __lsx_vstelm_d(out, dst + dst_stride, 0, 1); } -static av_always_inline -void hevc_hv_4t_8multx4_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, - int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, int32_t width8mult) -{ - uint32_t cnt; - const int32_t src_stride_2x = (src_stride << 1); - const int32_t dst_stride_2x = (dst_stride << 1); - const int32_t src_stride_4x = (src_stride << 2); - const int32_t src_stride_3x = src_stride_2x + src_stride; - const int32_t dst_stride_3x = dst_stride_2x + dst_stride; - - __m128i out0, out1; - __m128i src0, src1, src2, src3, src4, src5, src6, mask0, mask1; - __m128i vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; - __m128i filt0, filt1, filt_h0, filt_h1, filter_vec; - __m128i dst0, dst1, dst2, dst3, dst4, dst5, dst6, tmp0, tmp1, tmp2, tmp3; - __m128i dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - __m128i dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; - __m128i dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; - - src -= (src_stride + 1); - DUP2_ARG2(__lsx_vldrepl_h, filter_x, 0, filter_x, 2, filt0, filt1); - - filter_vec = __lsx_vld(filter_y, 0); - filter_vec = __lsx_vsllwil_h_b(filter_vec, 0); - DUP2_ARG2(__lsx_vreplvei_w, filter_vec, 0, filter_vec, 1, filt_h0, filt_h1); - - mask0 = __lsx_vld(ff_hevc_mask_arr, 0); - mask1 = __lsx_vaddi_bu(mask0, 2); - - for (cnt = width8mult; cnt--;) { - src0 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src1, src2); - src3 = __lsx_vldx(src, src_stride_3x); - src += src_stride_4x; - src4 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src5, src6); - src += (8 - src_stride_4x); - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask0, src1, src1, mask1, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src2, src2, mask1, - vec4, vec5); - - DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dst0, dst1); - dst2 = __lsx_vdp2_h_bu_b(vec4, filt0); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec1, filt1, dst1, vec3, filt1, - dst0, dst1); - dst2 = __lsx_vdp2add_h_bu_b(dst2, vec5, filt1); - - DUP2_ARG2(__lsx_vilvl_h, dst1, dst0, dst2, dst1, dst10_r, dst21_r); - DUP2_ARG2(__lsx_vilvh_h, dst1, dst0, dst2, dst1, dst10_l, dst21_l); - - DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, - vec4, vec5); - DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, - vec6, vec7); - - DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, - vec6, filt0, dst3, dst4, dst5, dst6); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst3, vec1, filt1, dst4, vec3, filt1, - dst5, vec5, filt1, dst6, vec7, filt1, dst3, dst4, dst5, dst6); - - DUP4_ARG2(__lsx_vilvl_h, dst3, dst2, dst4, dst3, dst5, dst4, dst6, - dst5, dst32_r, dst43_r, dst54_r, dst65_r); - DUP4_ARG2(__lsx_vilvh_h, dst3, dst2, dst4, dst3, dst5, dst4, dst6, - dst5, dst32_l, dst43_l, dst54_l, dst65_l); - - DUP4_ARG2(__lsx_vdp2_w_h, dst10_r, filt_h0, dst10_l, filt_h0, dst21_r, - filt_h0, dst21_l, filt_h0, dst0_r, dst0_l, dst1_r, dst1_l); - DUP4_ARG2(__lsx_vdp2_w_h, dst32_r, filt_h0, dst32_l, filt_h0, dst43_r, - filt_h0, dst43_l, filt_h0, dst2_r, dst2_l, dst3_r, dst3_l); - DUP4_ARG3(__lsx_vdp2add_w_h, dst0_r, dst32_r, filt_h1, dst0_l, dst32_l, - filt_h1, dst1_r, dst43_r, filt_h1, dst1_l, dst43_l, filt_h1, - dst0_r, dst0_l, dst1_r, dst1_l); - DUP4_ARG3(__lsx_vdp2add_w_h, dst2_r, dst54_r, filt_h1, dst2_l, dst54_l, - filt_h1, dst3_r, dst65_r, filt_h1, dst3_l, dst65_l, filt_h1, - dst2_r, dst2_l, dst3_r, dst3_l); - - DUP4_ARG3(__lsx_vsrani_h_w, dst0_l, dst0_r, 6, dst1_l, dst1_r, 6, - dst2_l, dst2_r, 6, dst3_l, dst3_r, 6, tmp0, tmp1, tmp2, tmp3); - DUP2_ARG3(__lsx_vssrarni_bu_h, tmp1, tmp0, 6, tmp3, tmp2, 6, out0, out1); - __lsx_vstelm_d(out0, dst, 0, 0); - __lsx_vstelm_d(out0, dst + dst_stride, 0, 1); - __lsx_vstelm_d(out1, dst + dst_stride_2x, 0, 0); - __lsx_vstelm_d(out1, dst + dst_stride_3x, 0, 1); - dst += 8; - } -} - static av_always_inline void hevc_hv_4t_8x6_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, @@ -1009,10 +887,9 @@ void hevc_hv_4t_8x6_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, } static av_always_inline -void hevc_hv_4t_8multx4mult_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, - int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, int32_t height, - int32_t width8mult) +void hevc_hv_4t_8mult_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, + int32_t dst_stride, const int8_t *filter_x, + const int8_t *filter_y, int32_t height, int32_t width8mult) { uint32_t loop_cnt, cnt; const uint8_t *src_tmp; @@ -1134,14 +1011,10 @@ void hevc_hv_4t_8w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, { if (2 == height) { hevc_hv_4t_8x2_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y); - } else if (4 == height) { - hevc_hv_4t_8multx4_lsx(src, src_stride, dst, dst_stride, - filter_x, filter_y, 1); } else if (6 == height) { hevc_hv_4t_8x6_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y); } else if (0 == (height & 0x03)) { - hevc_hv_4t_8multx4mult_lsx(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 1); + hevc_hv_4t_8mult_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 1); } } @@ -1160,17 +1033,14 @@ void hevc_hv_4t_12w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, const int32_t src_stride_3x = src_stride_2x + src_stride; const int32_t dst_stride_3x = dst_stride_2x + dst_stride; __m128i out0, out1; - __m128i src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + __m128i src0, src1, src2, src3, src4, src5, src6; __m128i vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; - __m128i mask0, mask1, mask2, mask3; + __m128i mask0, mask1; __m128i filt0, filt1, filt_h0, filt_h1, filter_vec, tmp0, tmp1, tmp2, tmp3; __m128i dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6; - __m128i dst10, dst21, dst22, dst73, dst84, dst95, dst106; - __m128i dst76_r, dst98_r, dst87_r, dst109_r; __m128i dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; __m128i dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; __m128i dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - __m128i dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; src -= (src_stride + 1); DUP2_ARG2(__lsx_vldrepl_h, filter_x, 0, filter_x, 2, filt0, filt1); @@ -1186,8 +1056,7 @@ void hevc_hv_4t_12w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, dst_tmp = dst; src0 = __lsx_vld(src_tmp, 0); - DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, - src1, src2); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src1, src2); src_tmp += src_stride_3x; DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, vec0, vec1); @@ -1196,17 +1065,15 @@ void hevc_hv_4t_12w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dsth0, dsth1); dsth2 = __lsx_vdp2_h_bu_b(vec4, filt0); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dsth0, vec1, filt1, dsth1, vec3, filt1, - dsth0, dsth1); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dsth0, vec1, filt1, dsth1, vec3, filt1, dsth0, dsth1); dsth2 = __lsx_vdp2add_h_bu_b(dsth2, vec5, filt1); DUP2_ARG2(__lsx_vilvl_h, dsth1, dsth0, dsth2, dsth1, dst10_r, dst21_r); DUP2_ARG2(__lsx_vilvh_h, dsth1, dsth0, dsth2, dsth1, dst10_l, dst21_l); - for (loop_cnt = 4; loop_cnt--;) { + for (loop_cnt = height >> 2; loop_cnt--;) { src3 = __lsx_vld(src_tmp, 0); - DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, - src4, src5); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src4, src5); src6 = __lsx_vldx(src_tmp, src_stride_3x); src_tmp += src_stride_4x; @@ -1254,83 +1121,73 @@ void hevc_hv_4t_12w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, dsth2 = dsth6; } - src += 8; - dst += 8; + src_tmp = src + 8; + dst_tmp = dst + 8; - mask2 = __lsx_vld(ff_hevc_mask_arr, 16); - mask3 = __lsx_vaddi_bu(mask2, 2); + src0 = __lsx_vld(src_tmp, 0); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src1, src2); + src_tmp += src_stride_3x; - src0 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src1, src2); - src += src_stride_3x; - DUP2_ARG3(__lsx_vshuf_b, src1, src0, mask2, src1, src0, mask3, vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src1, mask2, src2, src1, mask3, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask0, src1, src1, mask1, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src2, src2, mask1, vec4, vec5); - DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dst10, dst21); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst10, vec1, filt1, dst21, vec3, filt1, - dst10, dst21); + DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dsth0, dsth1); + dsth2 = __lsx_vdp2_h_bu_b(vec4, filt0); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dsth0, vec1, filt1, dsth1, vec3, filt1, dsth0, dsth1); + dsth2 = __lsx_vdp2add_h_bu_b(dsth2, vec5, filt1); - dst10_r = __lsx_vilvl_h(dst21, dst10); - dst21_r = __lsx_vilvh_h(dst21, dst10); - dst22 = __lsx_vreplvei_d(dst21, 1); + DUP2_ARG2(__lsx_vilvl_h, dsth1, dsth0, dsth2, dsth1, dst10_r, dst21_r); + DUP2_ARG2(__lsx_vilvh_h, dsth1, dsth0, dsth2, dsth1, dst10_l, dst21_l); - for (loop_cnt = 2; loop_cnt--;) { - src3 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src4, src5); - src6 = __lsx_vldx(src, src_stride_3x); - src += src_stride_4x; - src7 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src8, src9); - src10 = __lsx_vldx(src, src_stride_3x); - src += src_stride_4x; - DUP4_ARG3(__lsx_vshuf_b, src7, src3, mask2, src7, src3, mask3, src8, - src4, mask2, src8, src4, mask3, vec0, vec1, vec2, vec3); - DUP4_ARG3(__lsx_vshuf_b, src9, src5, mask2, src9, src5, mask3, src10, - src6, mask2, src10, src6, mask3, vec4, vec5, vec6, vec7); + for (loop_cnt = height >> 2; loop_cnt--;) { + src3 = __lsx_vld(src_tmp, 0); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src4, src5); + src6 = __lsx_vldx(src_tmp, src_stride_3x); + src_tmp += src_stride_4x; + + DUP4_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, src4, + src4, mask0, src4, src4, mask1, vec0, vec1, vec2, vec3); + DUP4_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, src6, + src6, mask0, src6, src6, mask1, vec4, vec5, vec6, vec7); DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, - vec6, filt0, dst73, dst84, dst95, dst106); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst73, vec1, filt1, dst84, vec3, - filt1, dst95, vec5, filt1, dst106, vec7, filt1, - dst73, dst84, dst95, dst106); + vec6, filt0, dsth3, dsth4, dsth5, dsth6); + DUP4_ARG3(__lsx_vdp2add_h_bu_b, dsth3, vec1, filt1, dsth4, + vec3, filt1, dsth5, vec5, filt1, dsth6, vec7, filt1, + dsth3, dsth4, dsth5, dsth6); - dst32_r = __lsx_vilvl_h(dst73, dst22); - DUP2_ARG2(__lsx_vilvl_h, dst84, dst73, dst95, dst84, dst43_r, dst54_r); - DUP2_ARG2(__lsx_vilvh_h, dst84, dst73, dst95, dst84, dst87_r, dst98_r); - dst65_r = __lsx_vilvl_h(dst106, dst95); - dst109_r = __lsx_vilvh_h(dst106, dst95); - dst22 = __lsx_vreplvei_d(dst73, 1); - dst76_r = __lsx_vilvl_h(dst22, dst106); + DUP4_ARG2(__lsx_vilvl_h, dsth3, dsth2, dsth4, dsth3, dsth5, dsth4, + dsth6, dsth5, dst32_r, dst43_r, dst54_r, dst65_r); + DUP4_ARG2(__lsx_vilvh_h, dsth3, dsth2, dsth4, dsth3, dsth5, dsth4, + dsth6, dsth5, dst32_l, dst43_l, dst54_l, dst65_l); - DUP4_ARG2(__lsx_vdp2_w_h, dst10_r, filt_h0, dst21_r, filt_h0, dst32_r, - filt_h0, dst43_r, filt_h0, dst0, dst1, dst2, dst3); - DUP4_ARG2(__lsx_vdp2_w_h, dst54_r, filt_h0, dst65_r, filt_h0, dst76_r, - filt_h0, dst87_r, filt_h0, dst4, dst5, dst6, dst7); - DUP4_ARG3(__lsx_vdp2add_w_h, dst0, dst32_r, filt_h1, dst1, dst43_r, - filt_h1, dst2, dst54_r, filt_h1, dst3, dst65_r, filt_h1, - dst0, dst1, dst2, dst3); - DUP4_ARG3(__lsx_vdp2add_w_h, dst4, dst76_r, filt_h1, dst5, dst87_r, - filt_h1, dst6, dst98_r, filt_h1, dst7, dst109_r, filt_h1, - dst4, dst5, dst6, dst7); + DUP4_ARG2(__lsx_vdp2_w_h, dst10_r, filt_h0, dst10_l, filt_h0, dst21_r, + filt_h0, dst21_l, filt_h0, dst0_r, dst0_l, dst1_r, dst1_l); + DUP4_ARG2(__lsx_vdp2_w_h, dst32_r, filt_h0, dst32_l, filt_h0, dst43_r, + filt_h0, dst43_l, filt_h0, dst2_r, dst2_l, dst3_r, dst3_l); + DUP4_ARG3(__lsx_vdp2add_w_h, dst0_r, dst32_r, filt_h1, dst0_l, dst32_l, + filt_h1, dst1_r, dst43_r, filt_h1, dst1_l, dst43_l, filt_h1, + dst0_r, dst0_l, dst1_r, dst1_l); + DUP4_ARG3(__lsx_vdp2add_w_h, dst2_r, dst54_r, filt_h1, dst2_l, dst54_l, + filt_h1, dst3_r, dst65_r, filt_h1, dst3_l, dst65_l, filt_h1, + dst2_r, dst2_l, dst3_r, dst3_l); - DUP4_ARG3(__lsx_vsrani_h_w, dst1, dst0, 6, dst3, dst2, 6, dst5, dst4, - 6, dst7, dst6, 6, tmp0, tmp1, tmp2, tmp3); + DUP4_ARG3(__lsx_vsrani_h_w, dst0_l, dst0_r, 6, dst1_l, dst1_r, 6, dst2_l, + dst2_r, 6, dst3_l, dst3_r, 6, tmp0, tmp1, tmp2, tmp3); DUP2_ARG3(__lsx_vssrarni_bu_h, tmp1, tmp0, 6, tmp3, tmp2, 6, out0, out1); - __lsx_vstelm_w(out0, dst, 0, 0); - __lsx_vstelm_w(out0, dst + dst_stride, 0, 1); - __lsx_vstelm_w(out0, dst + dst_stride_2x, 0, 2); - __lsx_vstelm_w(out0, dst + dst_stride_3x, 0, 3); - dst += dst_stride_4x; - __lsx_vstelm_w(out1, dst, 0, 0); - __lsx_vstelm_w(out1, dst + dst_stride, 0, 1); - __lsx_vstelm_w(out1, dst + dst_stride_2x, 0, 2); - __lsx_vstelm_w(out1, dst + dst_stride_3x, 0, 3); - dst += dst_stride_4x; + __lsx_vstelm_w(out0, dst_tmp, 0, 0); + __lsx_vstelm_w(out0, dst_tmp + dst_stride, 0, 2); + __lsx_vstelm_w(out1, dst_tmp + dst_stride_2x, 0, 0); + __lsx_vstelm_w(out1, dst_tmp + dst_stride_3x, 0, 2); + dst_tmp += dst_stride_4x; - dst10_r = dst98_r; - dst21_r = dst109_r; - dst22 = __lsx_vreplvei_d(dst106, 1); + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; } } @@ -1338,29 +1195,21 @@ static void hevc_hv_4t_16w_lsx(const uint8_t *src, int32_t src_stride, uint8_t * int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - if (4 == height) { - hevc_hv_4t_8multx4_lsx(src, src_stride, dst, dst_stride, filter_x, - filter_y, 2); - } else { - hevc_hv_4t_8multx4mult_lsx(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 2); - } + hevc_hv_4t_8mult_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 2); } static void hevc_hv_4t_24w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_4t_8multx4mult_lsx(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 3); + hevc_hv_4t_8mult_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 3); } static void hevc_hv_4t_32w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_4t_8multx4mult_lsx(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 4); + hevc_hv_4t_8mult_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 4); } #define UNI_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ @@ -1386,8 +1235,8 @@ UNI_MC(qpel, v, 32, 8, vt, my); UNI_MC(qpel, v, 48, 8, vt, my); UNI_MC(qpel, v, 64, 8, vt, my); -UNI_MC(epel, v, 24, 4, vt, my); -UNI_MC(epel, v, 32, 4, vt, my); +UNI_MC(epel, v, 24, 2, vt, my); +UNI_MC(epel, v, 32, 2, vt, my); #undef UNI_MC diff --git a/libavcodec/loongarch/hevcdsp_init_loongarch.c b/libavcodec/loongarch/hevcdsp_init_loongarch.c index 1585bda27..55fe6b15a 100644 --- a/libavcodec/loongarch/hevcdsp_init_loongarch.c +++ b/libavcodec/loongarch/hevcdsp_init_loongarch.c @@ -139,7 +139,6 @@ void ff_hevc_dsp_init_loongarch(HEVCDSPContext *c, const int bit_depth) c->put_hevc_epel_bi[6][1][0] = ff_hevc_put_hevc_bi_epel_v24_8_lsx; c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_hevc_bi_epel_v32_8_lsx; - c->put_hevc_epel_bi[2][1][1] = ff_hevc_put_hevc_bi_epel_hv6_8_lsx; c->put_hevc_epel_bi[3][1][1] = ff_hevc_put_hevc_bi_epel_hv8_8_lsx; c->put_hevc_epel_bi[5][1][1] = ff_hevc_put_hevc_bi_epel_hv16_8_lsx; c->put_hevc_epel_bi[6][1][1] = ff_hevc_put_hevc_bi_epel_hv24_8_lsx; diff --git a/libavcodec/loongarch/hevcdsp_lsx.c b/libavcodec/loongarch/hevcdsp_lsx.c index 574792552..993944164 100644 --- a/libavcodec/loongarch/hevcdsp_lsx.c +++ b/libavcodec/loongarch/hevcdsp_lsx.c @@ -772,56 +772,40 @@ static void hevc_hz_8t_12w_lsx(const uint8_t *src, int32_t src_stride, DUP2_ARG2(__lsx_vaddi_bu, mask4, 2, mask4, 4, mask5, mask6); mask7 = __lsx_vaddi_bu(mask4, 6); - for (loop_cnt = 4; loop_cnt--;) { + for (loop_cnt = height >> 2; loop_cnt--;) { src0 = __lsx_vld(src, 0); DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src1, src2); src3 = __lsx_vldx(src, src_stride_3x); src4 = __lsx_vld(_src, 0); - DUP2_ARG2(__lsx_vldx, _src, src_stride, _src, src_stride_2x, - src5, src6); + DUP2_ARG2(__lsx_vldx, _src, src_stride, _src, src_stride_2x, src5, src6); src7 = __lsx_vldx(_src, src_stride_3x); src += src_stride_4x; _src += src_stride_4x; - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src1, src1, mask0, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src3, src3, mask0, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask4, src7, src6, mask4, - vec4, vec5); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src1, src1, mask0, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src3, src3, mask0, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask4, src7, src6, mask4, vec4, vec5); DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec1, filt0, vec2, filt0, vec3, filt0, dst0, dst1, dst2, dst3); DUP2_ARG2(__lsx_vdp2_h_bu_b, vec4, filt0, vec5, filt0, dst4, dst5); - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask1, src1, src1, mask1, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask1, src3, src3, mask1, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask5, src7, src6, mask5, - vec4, vec5); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask1, src1, src1, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask1, src3, src3, mask1, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask5, src7, src6, mask5, vec4, vec5); DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec0, filt1, dst1, vec1, filt1, dst2, vec2, filt1, dst3, vec3, filt1, dst0, dst1, dst2, dst3); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt1, dst5, vec5, filt1, - dst4, dst5); - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask2, src1, src1, mask2, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask2, src3, src3, mask2, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask6, src7, src6, mask6, - vec4, vec5); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt1, dst5, vec5, filt1, dst4, dst5); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask2, src1, src1, mask2, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask2, src3, src3, mask2, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask6, src7, src6, mask6, vec4, vec5); DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec0, filt2, dst1, vec1, filt2, dst2, vec2, filt2, dst3, vec3, filt2, dst0, dst1, dst2, dst3); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt2, dst5, vec5, filt2, - dst4, dst5); - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask3, src1, src1, mask3, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask3, src3, src3, mask3, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask7, src7, src6, mask7, - vec4, vec5); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt2, dst5, vec5, filt2, dst4, dst5); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask3, src1, src1, mask3, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask3, src3, src3, mask3, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask7, src7, src6, mask7, vec4, vec5); DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec0, filt3, dst1, vec1, filt3, dst2, vec2, filt3, dst3, vec3, filt3, dst0, dst1, dst2, dst3); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt3, dst5, vec5, filt3, - dst4, dst5); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt3, dst5, vec5, filt3, dst4, dst5); __lsx_vst(dst0, dst, 0); __lsx_vstelm_d(dst4, dst, 16, 0); @@ -2972,16 +2956,14 @@ static void hevc_hv_4t_12w_lsx(const uint8_t *src, int32_t src_stride_3x = src_stride_2x + src_stride; int32_t dst_stride_3x = dst_stride_2x + dst_stride_x; - __m128i src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + __m128i src0, src1, src2, src3, src4, src5, src6; __m128i vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; - __m128i mask0, mask1, mask2, mask3; + __m128i mask0, mask1; __m128i filt0, filt1, filt_h0, filt_h1, filter_vec, dst0; - __m128i dst1, dst2, dst3, dst4, dst5, dst6, dst10, dst21, dst22, dst73; - __m128i dst84, dst95, dst106, dst76_r, dst98_r, dst87_r, dst109_r; + __m128i dst1, dst2, dst3, dst4, dst5, dst6; __m128i dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; __m128i dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; __m128i dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - __m128i tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; src -= (src_stride + 1); DUP2_ARG2(__lsx_vldrepl_h, filter_x, 0, filter_x, 2, filt0, filt1); @@ -2997,8 +2979,7 @@ static void hevc_hv_4t_12w_lsx(const uint8_t *src, dst_tmp = dst; src0 = __lsx_vld(src_tmp, 0); - DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, - src1, src2); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src1, src2); src_tmp += src_stride_3x; DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, vec0, vec1); @@ -3007,34 +2988,27 @@ static void hevc_hv_4t_12w_lsx(const uint8_t *src, DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dst0, dst1); dst2 = __lsx_vdp2_h_bu_b(vec4, filt0); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec1, filt1, dst1, vec3, filt1, - dst0, dst1); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec1, filt1, dst1, vec3, filt1, dst0, dst1); dst2 = __lsx_vdp2add_h_bu_b(dst2, vec5, filt1); DUP2_ARG2(__lsx_vilvl_h, dst1, dst0, dst2, dst1, dst10_r, dst21_r); DUP2_ARG2(__lsx_vilvh_h, dst1, dst0, dst2, dst1, dst10_l, dst21_l); - for (loop_cnt = 4; loop_cnt--;) { + for (loop_cnt = height >> 2; loop_cnt--;) { src3 = __lsx_vld(src_tmp, 0); - DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, - src4, src5); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src4, src5); src6 = __lsx_vldx(src_tmp, src_stride_3x); src_tmp += src_stride_4x; - DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, - vec4, vec5); - DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, - vec6, vec7); + DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, vec4, vec5); + DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, vec6, vec7); DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, vec6, filt0, dst3, dst4, dst5, dst6); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst3, vec1, filt1, dst4, vec3, - filt1, dst5, vec5, filt1, dst6, vec7, filt1, dst3, - dst4, dst5, dst6); + DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst3, vec1, filt1, dst4, vec3, filt1, + dst5, vec5, filt1, dst6, vec7, filt1, dst3, dst4, dst5, dst6); DUP2_ARG2(__lsx_vilvl_h, dst3, dst2, dst4, dst3, dst32_r, dst43_r); DUP2_ARG2(__lsx_vilvh_h, dst3, dst2, dst4, dst3, dst32_l, dst43_l); @@ -3051,12 +3025,8 @@ static void hevc_hv_4t_12w_lsx(const uint8_t *src, DUP4_ARG3(__lsx_vdp2add_w_h, dst2_r, dst54_r, filt_h1, dst2_l, dst54_l, filt_h1, dst3_r, dst65_r, filt_h1, dst3_l, dst65_l, filt_h1, dst2_r, dst2_l, dst3_r, dst3_l); - DUP4_ARG2(__lsx_vsrai_w, dst0_r, 6, dst0_l, 6, dst1_r, 6, dst1_l, 6, - dst0_r, dst0_l, dst1_r, dst1_l); - DUP4_ARG2(__lsx_vsrai_w, dst2_r, 6, dst2_l, 6, dst3_r, 6, dst3_l, 6, - dst2_r, dst2_l, dst3_r, dst3_l); - DUP4_ARG2(__lsx_vpickev_h, dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, - dst3_l, dst3_r, dst0_r, dst1_r, dst2_r, dst3_r); + DUP2_ARG3(__lsx_vsrani_h_w, dst0_l, dst0_r, 6, dst1_l, dst1_r, 6, dst0_r, dst1_r); + DUP2_ARG3(__lsx_vsrani_h_w, dst2_l, dst2_r, 6, dst3_l, dst3_r, 6, dst2_r, dst3_r); __lsx_vst(dst0_r, dst_tmp, 0); __lsx_vstx(dst1_r, dst_tmp, dst_stride_x); __lsx_vstx(dst2_r, dst_tmp, dst_stride_2x); @@ -3070,93 +3040,74 @@ static void hevc_hv_4t_12w_lsx(const uint8_t *src, dst2 = dst6; } - src += 8; - dst += 8; + src_tmp = src + 8; + dst_tmp = dst + 8; - mask2 = __lsx_vld(ff_hevc_mask_arr, 16); - mask3 = __lsx_vaddi_bu(mask2, 2); + src0 = __lsx_vld(src_tmp, 0); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src1, src2); + src_tmp += src_stride_3x; - src0 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src1, src2); - src += src_stride_3x; - DUP2_ARG3(__lsx_vshuf_b, src1, src0, mask2, src1, src0, mask3, vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src1, mask2, src2, src1, mask3, vec2, vec3); - DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dst10, dst21); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst10, vec1, filt1, dst21, vec3, filt1, - dst10, dst21); - dst10_r = __lsx_vilvl_h(dst21, dst10); - dst21_r = __lsx_vilvh_h(dst21, dst10); - dst22 = __lsx_vreplvei_d(dst21, 1); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask0, src1, src1, mask1, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src2, src2, mask1, vec4, vec5); - for (loop_cnt = 2; loop_cnt--;) { - src3 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src4, src5); - src6 = __lsx_vldx(src, src_stride_3x); - src += src_stride_4x; - src7 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src8, src9); - src10 = __lsx_vldx(src, src_stride_3x); - src += src_stride_4x; - DUP2_ARG3(__lsx_vshuf_b, src7, src3, mask2, src7, src3, mask3, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src8, src4, mask2, src8, src4, mask3, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src9, src5, mask2, src9, src5, mask3, - vec4, vec5); - DUP2_ARG3(__lsx_vshuf_b, src10, src6, mask2, src10, src6, mask3, - vec6, vec7); + DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dst0, dst1); + dst2 = __lsx_vdp2_h_bu_b(vec4, filt0); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec1, filt1, dst1, vec3, filt1, dst0, dst1); + dst2 = __lsx_vdp2add_h_bu_b(dst2, vec5, filt1); + + DUP2_ARG2(__lsx_vilvl_h, dst1, dst0, dst2, dst1, dst10_r, dst21_r); + DUP2_ARG2(__lsx_vilvh_h, dst1, dst0, dst2, dst1, dst10_l, dst21_l); + + for (loop_cnt = height >> 2; loop_cnt--;) { + src3 = __lsx_vld(src_tmp, 0); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src4, src5); + src6 = __lsx_vldx(src_tmp, src_stride_3x); + src_tmp += src_stride_4x; + + DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, vec4, vec5); + DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, vec6, vec7); DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, - vec6, filt0, dst73, dst84, dst95, dst106); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst73, vec1, filt1, dst84, vec3, - filt1, dst95, vec5, filt1, dst106, vec7, filt1, dst73, - dst84, dst95, dst106); + vec6, filt0, dst3, dst4, dst5, dst6); + DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst3, vec1, filt1, dst4, vec3, filt1, + dst5, vec5, filt1, dst6, vec7, filt1, dst3, dst4, dst5, dst6); - DUP2_ARG2(__lsx_vilvl_h, dst73, dst22, dst84, dst73, dst32_r, dst43_r); - DUP2_ARG2(__lsx_vilvh_h, dst84, dst73, dst95, dst84, dst87_r, dst98_r); - DUP2_ARG2(__lsx_vilvl_h, dst95, dst84, dst106, dst95, dst54_r, dst65_r); - dst109_r = __lsx_vilvh_h(dst106, dst95); - dst22 = __lsx_vreplvei_d(dst73, 1); - dst76_r = __lsx_vilvl_h(dst22, dst106); + DUP2_ARG2(__lsx_vilvl_h, dst3, dst2, dst4, dst3, dst32_r, dst43_r); + DUP2_ARG2(__lsx_vilvh_h, dst3, dst2, dst4, dst3, dst32_l, dst43_l); + DUP2_ARG2(__lsx_vilvl_h, dst5, dst4, dst6, dst5, dst54_r, dst65_r); + DUP2_ARG2(__lsx_vilvh_h, dst5, dst4, dst6, dst5, dst54_l, dst65_l); - DUP4_ARG2(__lsx_vdp2_w_h, dst10_r, filt_h0, dst21_r, filt_h0, dst32_r, - filt_h0, dst43_r, filt_h0, tmp0, tmp1, tmp2, tmp3); - DUP4_ARG2(__lsx_vdp2_w_h, dst54_r, filt_h0, dst65_r, filt_h0, dst76_r, - filt_h0, dst87_r, filt_h0, tmp4, tmp5, tmp6, tmp7); - DUP4_ARG3(__lsx_vdp2add_w_h, tmp0, dst32_r, filt_h1, tmp1, dst43_r, - filt_h1, tmp2, dst54_r, filt_h1, tmp3, dst65_r, filt_h1, - tmp0, tmp1, tmp2, tmp3); - DUP4_ARG3(__lsx_vdp2add_w_h, tmp4, dst76_r, filt_h1, tmp5, dst87_r, - filt_h1, tmp6, dst98_r, filt_h1, tmp7, dst109_r, filt_h1, - tmp4, tmp5, tmp6, tmp7); - DUP4_ARG2(__lsx_vsrai_w, tmp0, 6, tmp1, 6, tmp2, 6, tmp3, 6, - tmp0, tmp1, tmp2, tmp3); - DUP4_ARG2(__lsx_vsrai_w, tmp4, 6, tmp5, 6, tmp6, 6, tmp7, 6, - tmp4, tmp5, tmp6, tmp7); - DUP4_ARG2(__lsx_vpickev_h, tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, - tmp7, tmp6, tmp0, tmp1, tmp2, tmp3); + DUP4_ARG2(__lsx_vdp2_w_h, dst10_r, filt_h0, dst10_l, filt_h0, dst21_r, + filt_h0, dst21_l, filt_h0, dst0_r, dst0_l, dst1_r, dst1_l); + DUP4_ARG2(__lsx_vdp2_w_h, dst32_r, filt_h0, dst32_l, filt_h0, dst43_r, + filt_h0, dst43_l, filt_h0, dst2_r, dst2_l, dst3_r, dst3_l); + DUP4_ARG3(__lsx_vdp2add_w_h, dst0_r, dst32_r, filt_h1, dst0_l, dst32_l, + filt_h1, dst1_r, dst43_r, filt_h1, dst1_l, dst43_l, filt_h1, + dst0_r, dst0_l, dst1_r, dst1_l); + DUP4_ARG3(__lsx_vdp2add_w_h, dst2_r, dst54_r, filt_h1, dst2_l, dst54_l, + filt_h1, dst3_r, dst65_r, filt_h1, dst3_l, dst65_l, filt_h1, + dst2_r, dst2_l, dst3_r, dst3_l); + DUP2_ARG3(__lsx_vsrani_h_w, dst0_l, dst0_r, 6, dst1_l, dst1_r, 6, dst0_r, dst1_r); + DUP2_ARG3(__lsx_vsrani_h_w, dst2_l, dst2_r, 6, dst3_l, dst3_r, 6, dst2_r, dst3_r); + __lsx_vstelm_d(dst0_r, dst_tmp, 0, 0); + dst_tmp += dst_stride; + __lsx_vstelm_d(dst1_r, dst_tmp, 0, 0); + dst_tmp += dst_stride; + __lsx_vstelm_d(dst2_r, dst_tmp, 0, 0); + dst_tmp += dst_stride; + __lsx_vstelm_d(dst3_r, dst_tmp, 0, 0); + dst_tmp += dst_stride; - __lsx_vstelm_d(tmp0, dst, 0, 0); - dst += dst_stride; - __lsx_vstelm_d(tmp0, dst, 0, 1); - dst += dst_stride; - __lsx_vstelm_d(tmp1, dst, 0, 0); - dst += dst_stride; - __lsx_vstelm_d(tmp1, dst, 0, 1); - dst += dst_stride; - __lsx_vstelm_d(tmp2, dst, 0, 0); - dst += dst_stride; - __lsx_vstelm_d(tmp2, dst, 0, 1); - dst += dst_stride; - __lsx_vstelm_d(tmp3, dst, 0, 0); - dst += dst_stride; - __lsx_vstelm_d(tmp3, dst, 0, 1); - dst += dst_stride; - - dst10_r = dst98_r; - dst21_r = dst109_r; - dst22 = __lsx_vreplvei_d(dst106, 1); + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; } + } static void hevc_hv_4t_16w_lsx(const uint8_t *src, diff --git a/libavcodec/loongarch/hevcdsp_lsx.h b/libavcodec/loongarch/hevcdsp_lsx.h index cf2a519e9..8562a0d68 100644 --- a/libavcodec/loongarch/hevcdsp_lsx.h +++ b/libavcodec/loongarch/hevcdsp_lsx.h @@ -141,7 +141,6 @@ BI_MC(epel, v, 16); BI_MC(epel, v, 24); BI_MC(epel, v, 32); -BI_MC(epel, hv, 6); BI_MC(epel, hv, 8); BI_MC(epel, hv, 16); BI_MC(epel, hv, 24); diff --git a/libavcodec/loongarch/hpeldsp_init_loongarch.c b/libavcodec/loongarch/hpeldsp_init_loongarch.c index 1690be543..ffdfb69bb 100644 --- a/libavcodec/loongarch/hpeldsp_init_loongarch.c +++ b/libavcodec/loongarch/hpeldsp_init_loongarch.c @@ -45,6 +45,6 @@ void ff_hpeldsp_init_loongarch(HpelDSPContext *c, int flags) c->put_no_rnd_pixels_tab[1][0] = ff_put_pixels8_8_lasx; c->put_no_rnd_pixels_tab[1][1] = ff_put_no_rnd_pixels8_x2_8_lasx; c->put_no_rnd_pixels_tab[1][2] = ff_put_no_rnd_pixels8_y2_8_lasx; - c->put_no_rnd_pixels_tab[1][3] = ff_put_no_rnd_pixels8_xy2_8_lasx; + c->put_no_rnd_pixels_tab[1][3] = ff_put_no_rnd_pixels8_xy2_8_lsx; } } diff --git a/libavcodec/loongarch/hpeldsp_lasx.c b/libavcodec/loongarch/hpeldsp_lasx.c index dd2ae173d..68cab715b 100644 --- a/libavcodec/loongarch/hpeldsp_lasx.c +++ b/libavcodec/loongarch/hpeldsp_lasx.c @@ -192,61 +192,33 @@ void ff_put_pixels8_8_lasx(uint8_t *block, const uint8_t *pixels, ); } +/** + * For widths 16, h is always a positive multiple of 4. + * The function processes 4 rows per iteration. + */ void ff_put_pixels16_8_lsx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { - int h_8 = h >> 3; - int res = h & 7; - ptrdiff_t stride2, stride3, stride4; + int h_4 = h >> 2; + ptrdiff_t stride2 = line_size << 1; + ptrdiff_t stride3 = stride2 + line_size; + ptrdiff_t stride4 = line_size << 2; + __m128i src0, src1, src2, src3; - __asm__ volatile ( - "beqz %[h_8], 2f \n\t" - "slli.d %[stride2], %[stride], 1 \n\t" - "add.d %[stride3], %[stride2], %[stride] \n\t" - "slli.d %[stride4], %[stride2], 1 \n\t" - "1: \n\t" - "vld $vr0, %[src], 0x0 \n\t" - "vldx $vr1, %[src], %[stride] \n\t" - "vldx $vr2, %[src], %[stride2] \n\t" - "vldx $vr3, %[src], %[stride3] \n\t" - "add.d %[src], %[src], %[stride4] \n\t" - "vld $vr4, %[src], 0x0 \n\t" - "vldx $vr5, %[src], %[stride] \n\t" - "vldx $vr6, %[src], %[stride2] \n\t" - "vldx $vr7, %[src], %[stride3] \n\t" - "add.d %[src], %[src], %[stride4] \n\t" + for (int i = 0; i < h_4; i++) { + src0 = __lsx_vld(pixels, 0); + src1 = __lsx_vldx(pixels, line_size); + src2 = __lsx_vldx(pixels, stride2); + src3 = __lsx_vldx(pixels, stride3); - "addi.d %[h_8], %[h_8], -1 \n\t" + __lsx_vst(src0, block, 0); + __lsx_vstx(src1, block, line_size); + __lsx_vstx(src2, block, stride2); + __lsx_vstx(src3, block, stride3); - "vst $vr0, %[dst], 0x0 \n\t" - "vstx $vr1, %[dst], %[stride] \n\t" - "vstx $vr2, %[dst], %[stride2] \n\t" - "vstx $vr3, %[dst], %[stride3] \n\t" - "add.d %[dst], %[dst], %[stride4] \n\t" - "vst $vr4, %[dst], 0x0 \n\t" - "vstx $vr5, %[dst], %[stride] \n\t" - "vstx $vr6, %[dst], %[stride2] \n\t" - "vstx $vr7, %[dst], %[stride3] \n\t" - "add.d %[dst], %[dst], %[stride4] \n\t" - "bnez %[h_8], 1b \n\t" - - "2: \n\t" - "beqz %[res], 4f \n\t" - "3: \n\t" - "vld $vr0, %[src], 0x0 \n\t" - "add.d %[src], %[src], %[stride] \n\t" - "addi.d %[res], %[res], -1 \n\t" - "vst $vr0, %[dst], 0x0 \n\t" - "add.d %[dst], %[dst], %[stride] \n\t" - "bnez %[res], 3b \n\t" - "4: \n\t" - : [dst]"+&r"(block), [src]"+&r"(pixels), - [h_8]"+&r"(h_8), [res]"+&r"(res), - [stride2]"=&r"(stride2), [stride3]"=&r"(stride3), - [stride4]"=&r"(stride4) - : [stride]"r"(line_size) - : "memory" - ); + pixels += stride4; + block += stride4; + } } void ff_put_pixels8_x2_8_lasx(uint8_t *block, const uint8_t *pixels, @@ -277,961 +249,253 @@ void ff_put_pixels16_y2_8_lasx(uint8_t *block, const uint8_t *pixels, line_size, line_size, h); } -static void common_hz_bil_no_rnd_16x16_lasx(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t *_src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += 1; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += (src_stride_4x -1); - DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src5, - src4, 0x20, src7, src6, 0x20, src0, src1, src2, src3); - src0 = __lasx_xvavg_bu(src0, src2); - src1 = __lasx_xvavg_bu(src1, src3); - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src0, dst, 0, 2); - __lasx_xvstelm_d(src0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 0); - __lasx_xvstelm_d(src1, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 2); - __lasx_xvstelm_d(src1, dst, 8, 3); - dst += dst_stride; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += 1; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += (src_stride_4x - 1); - DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src5, src4, - 0x20, src7, src6, 0x20, src0, src1, src2, src3); - src0 = __lasx_xvavg_bu(src0, src2); - src1 = __lasx_xvavg_bu(src1, src3); - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src0, dst, 0, 2); - __lasx_xvstelm_d(src0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 0); - __lasx_xvstelm_d(src1, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 2); - __lasx_xvstelm_d(src1, dst, 8, 3); - dst += dst_stride; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += 1; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += (src_stride_4x - 1); - DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src5, src4, - 0x20, src7, src6, 0x20, src0, src1, src2, src3); - src0 = __lasx_xvavg_bu(src0, src2); - src1 = __lasx_xvavg_bu(src1, src3); - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src0, dst, 0, 2); - __lasx_xvstelm_d(src0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 0); - __lasx_xvstelm_d(src1, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 2); - __lasx_xvstelm_d(src1, dst, 8, 3); - dst += dst_stride; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += 1; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src5, src4, - 0x20, src7, src6, 0x20, src0, src1, src2, src3); - src0 = __lasx_xvavg_bu(src0, src2); - src1 = __lasx_xvavg_bu(src1, src3); - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src0, dst, 0, 2); - __lasx_xvstelm_d(src0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 0); - __lasx_xvstelm_d(src1, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 2); - __lasx_xvstelm_d(src1, dst, 8, 3); -} - -static void common_hz_bil_no_rnd_8x16_lasx(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t* _src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += 1; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += (src_stride_4x - 1); - DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src5, src4, - 0x20, src7, src6, 0x20, src0, src1, src2, src3); - src0 = __lasx_xvavg_bu(src0, src2); - src1 = __lasx_xvavg_bu(src1, src3); - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src0, dst, 0, 2); - __lasx_xvstelm_d(src0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 0); - __lasx_xvstelm_d(src1, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 2); - __lasx_xvstelm_d(src1, dst, 8, 3); - dst += dst_stride; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += 1; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src5, src4, - 0x20, src7, src6, 0x20, src0, src1, src2, src3); - src0 = __lasx_xvavg_bu(src0, src2); - src1 = __lasx_xvavg_bu(src1, src3); - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src0, dst, 0, 2); - __lasx_xvstelm_d(src0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 0); - __lasx_xvstelm_d(src1, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src1, dst, 0, 2); - __lasx_xvstelm_d(src1, dst, 8, 3); -} - +/** + * For widths 16, h is always a positive multiple of 4. + * The function processes 4 rows per iteration. + */ void ff_put_no_rnd_pixels16_x2_8_lasx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { - if (h == 16) { - common_hz_bil_no_rnd_16x16_lasx(pixels, line_size, block, line_size); - } else if (h == 8) { - common_hz_bil_no_rnd_8x16_lasx(pixels, line_size, block, line_size); + __m256i src0, src1, src2, src3, src4, src5, src6, src7; + int32_t h_4 = h >> 2; + int32_t stride2x = line_size << 1; + int32_t stride4x = line_size << 2; + int32_t stride3x = stride2x + line_size; + uint8_t* _src = (uint8_t*)pixels + 1; + + for (int i = 0; i < h_4; i++) { + src0 = __lasx_xvld(pixels, 0); + DUP2_ARG2(__lasx_xvldx, pixels, line_size, pixels, stride2x, src1, src2); + src3 = __lasx_xvldx(pixels, stride3x); + src4 = __lasx_xvld(_src, 0); + DUP2_ARG2(__lasx_xvldx, _src, line_size, _src, stride2x, src5, src6); + src7 = __lasx_xvldx(_src, stride3x); + DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src5, src4, + 0x20, src7, src6, 0x20, src0, src1, src2, src3); + src0 = __lasx_xvavg_bu(src0, src2); + src1 = __lasx_xvavg_bu(src1, src3); + __lasx_xvstelm_d(src0, block, 0, 0); + __lasx_xvstelm_d(src0, block, 8, 1); + block += line_size; + __lasx_xvstelm_d(src0, block, 0, 2); + __lasx_xvstelm_d(src0, block, 8, 3); + block += line_size; + __lasx_xvstelm_d(src1, block, 0, 0); + __lasx_xvstelm_d(src1, block, 8, 1); + block += line_size; + __lasx_xvstelm_d(src1, block, 0, 2); + __lasx_xvstelm_d(src1, block, 8, 3); + block += line_size; + + _src += stride4x; + pixels += stride4x; } } -static void common_vt_bil_no_rnd_16x16_lasx(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7, src8; - __m256i src9, src10, src11, src12, src13, src14, src15, src16; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t* _src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src8 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src9, src10); - src11 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src12 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src13, src14); - src15 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src16 = __lasx_xvld(_src, 0); - - DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src2, src1, 0x20, src3, src2, - 0x20, src4, src3, 0x20, src0, src1, src2, src3); - DUP4_ARG3(__lasx_xvpermi_q, src5, src4, 0x20, src6, src5, 0x20, src7, src6, - 0x20, src8, src7, 0x20, src4, src5, src6, src7); - DUP4_ARG3(__lasx_xvpermi_q, src9, src8, 0x20, src10, src9, 0x20, src11, - src10, 0x20, src12, src11, 0x20, src8, src9, src10, src11); - DUP4_ARG3(__lasx_xvpermi_q, src13, src12, 0x20, src14, src13, 0x20, src15, - src14, 0x20, src16, src15, 0x20, src12, src13, src14, src15); - DUP4_ARG2(__lasx_xvavg_bu, src0, src1, src2, src3, src4, src5, src6, src7, - src0, src2, src4, src6); - DUP4_ARG2(__lasx_xvavg_bu, src8, src9, src10, src11, src12, src13, src14, - src15, src8, src10, src12, src14); - - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src0, dst, 0, 2); - __lasx_xvstelm_d(src0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src2, dst, 0, 0); - __lasx_xvstelm_d(src2, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src2, dst, 0, 2); - __lasx_xvstelm_d(src2, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src4, dst, 0, 0); - __lasx_xvstelm_d(src4, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src4, dst, 0, 2); - __lasx_xvstelm_d(src4, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src6, dst, 0, 0); - __lasx_xvstelm_d(src6, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src6, dst, 0, 2); - __lasx_xvstelm_d(src6, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src8, dst, 0, 0); - __lasx_xvstelm_d(src8, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src8, dst, 0, 2); - __lasx_xvstelm_d(src8, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src10, dst, 0, 0); - __lasx_xvstelm_d(src10, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src10, dst, 0, 2); - __lasx_xvstelm_d(src10, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src12, dst, 0, 0); - __lasx_xvstelm_d(src12, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src12, dst, 0, 2); - __lasx_xvstelm_d(src12, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src14, dst, 0, 0); - __lasx_xvstelm_d(src14, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src14, dst, 0, 2); - __lasx_xvstelm_d(src14, dst, 8, 3); -} - -static void common_vt_bil_no_rnd_8x16_lasx(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7, src8; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t* _src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src8 = __lasx_xvld(_src, 0); - - DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src2, src1, 0x20, src3, src2, - 0x20, src4, src3, 0x20, src0, src1, src2, src3); - DUP4_ARG3(__lasx_xvpermi_q, src5, src4, 0x20, src6, src5, 0x20, src7, src6, - 0x20, src8, src7, 0x20, src4, src5, src6, src7); - DUP4_ARG2(__lasx_xvavg_bu, src0, src1, src2, src3, src4, src5, src6, src7, - src0, src2, src4, src6); - - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src0, dst, 0, 2); - __lasx_xvstelm_d(src0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src2, dst, 0, 0); - __lasx_xvstelm_d(src2, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src2, dst, 0, 2); - __lasx_xvstelm_d(src2, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src4, dst, 0, 0); - __lasx_xvstelm_d(src4, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src4, dst, 0, 2); - __lasx_xvstelm_d(src4, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(src6, dst, 0, 0); - __lasx_xvstelm_d(src6, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(src6, dst, 0, 2); - __lasx_xvstelm_d(src6, dst, 8, 3); -} - +/** + * For widths 16, h is always a positive multiple of 4. + * The function processes 4 rows per iteration. + */ void ff_put_no_rnd_pixels16_y2_8_lasx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { - if (h == 16) { - common_vt_bil_no_rnd_16x16_lasx(pixels, line_size, block, line_size); - } else if (h == 8) { - common_vt_bil_no_rnd_8x16_lasx(pixels, line_size, block, line_size); + __m256i src0, src1, src2, src3, src4; + int32_t stride2x = line_size << 1; + int32_t stride4x = line_size << 2; + int32_t stride3x = stride2x + line_size; + uint8_t* _src = (uint8_t*)pixels; + int32_t h_4 = h >> 2; + + for (int i = 0; i < h_4; i++) { + src0 = __lasx_xvld(_src, 0); + DUP2_ARG2(__lasx_xvldx, _src, line_size, _src, stride2x, src1, src2); + src3 = __lasx_xvldx(_src, stride3x); + _src += stride4x; + src4 = __lasx_xvld(_src, 0); + + DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src2, src1, 0x20, src3, src2, + 0x20, src4, src3, 0x20, src0, src1, src2, src3); + DUP2_ARG2(__lasx_xvavg_bu, src0, src1, src2, src3, src0, src2); + + __lasx_xvstelm_d(src0, block, 0, 0); + __lasx_xvstelm_d(src0, block, 8, 1); + block += line_size; + __lasx_xvstelm_d(src0, block, 0, 2); + __lasx_xvstelm_d(src0, block, 8, 3); + block += line_size; + __lasx_xvstelm_d(src2, block, 0, 0); + __lasx_xvstelm_d(src2, block, 8, 1); + block += line_size; + __lasx_xvstelm_d(src2, block, 0, 2); + __lasx_xvstelm_d(src2, block, 8, 3); + block += line_size; } } -static void common_hv_bil_no_rnd_16x16_lasx(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7, src8, src9; - __m256i src10, src11, src12, src13, src14, src15, src16, src17; - __m256i sum0, sum1, sum2, sum3, sum4, sum5, sum6, sum7; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t* _src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += (1 - src_stride_4x); - src9 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src10, src11); - src12 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src13 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src14, src15); - src16 = __lasx_xvldx(_src, src_stride_3x); - _src += (src_stride_4x - 1); - DUP2_ARG2(__lasx_xvld, _src, 0, _src, 1, src8, src17); - - DUP4_ARG3(__lasx_xvpermi_q, src0, src4, 0x02, src1, src5, 0x02, src2, - src6, 0x02, src3, src7, 0x02, src0, src1, src2, src3); - DUP4_ARG3(__lasx_xvpermi_q, src4, src8, 0x02, src9, src13, 0x02, src10, - src14, 0x02, src11, src15, 0x02, src4, src5, src6, src7); - DUP2_ARG3(__lasx_xvpermi_q, src12, src16, 0x02, src13, src17, 0x02, - src8, src9); - DUP4_ARG2(__lasx_xvilvl_h, src5, src0, src6, src1, src7, src2, src8, src3, - sum0, sum2, sum4, sum6); - DUP4_ARG2(__lasx_xvilvh_h, src5, src0, src6, src1, src7, src2, src8, src3, - sum1, sum3, sum5, sum7); - src8 = __lasx_xvilvl_h(src9, src4); - src9 = __lasx_xvilvh_h(src9, src4); - - DUP4_ARG2(__lasx_xvhaddw_hu_bu, sum0, sum0, sum1, sum1, sum2, sum2, - sum3, sum3, src0, src1, src2, src3); - DUP4_ARG2(__lasx_xvhaddw_hu_bu, sum4, sum4, sum5, sum5, sum6, sum6, - sum7, sum7, src4, src5, src6, src7); - DUP2_ARG2(__lasx_xvhaddw_hu_bu, src8, src8, src9, src9, src8, src9); - - DUP4_ARG2(__lasx_xvadd_h, src0, src2, src1, src3, src2, src4, src3, src5, - sum0, sum1, sum2, sum3); - DUP4_ARG2(__lasx_xvadd_h, src4, src6, src5, src7, src6, src8, src7, src9, - sum4, sum5, sum6, sum7); - DUP4_ARG2(__lasx_xvaddi_hu, sum0, 1, sum1, 1, sum2, 1, sum3, 1, - sum0, sum1, sum2, sum3); - DUP4_ARG2(__lasx_xvaddi_hu, sum4, 1, sum5, 1, sum6, 1, sum7, 1, - sum4, sum5, sum6, sum7); - DUP4_ARG3(__lasx_xvsrani_b_h, sum1, sum0, 2, sum3, sum2, 2, sum5, sum4, 2, - sum7, sum6, 2, sum0, sum1, sum2, sum3); - __lasx_xvstelm_d(sum0, dst, 0, 0); - __lasx_xvstelm_d(sum0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum1, dst, 0, 0); - __lasx_xvstelm_d(sum1, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum2, dst, 0, 0); - __lasx_xvstelm_d(sum2, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum3, dst, 0, 0); - __lasx_xvstelm_d(sum3, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum0, dst, 0, 2); - __lasx_xvstelm_d(sum0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum1, dst, 0, 2); - __lasx_xvstelm_d(sum1, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum2, dst, 0, 2); - __lasx_xvstelm_d(sum2, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum3, dst, 0, 2); - __lasx_xvstelm_d(sum3, dst, 8, 3); - dst += dst_stride; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += (1 - src_stride_4x); - src9 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src10, src11); - src12 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src13 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src14, src15); - src16 = __lasx_xvldx(_src, src_stride_3x); - _src += (src_stride_4x - 1); - DUP2_ARG2(__lasx_xvld, _src, 0, _src, 1, src8, src17); - - DUP4_ARG3(__lasx_xvpermi_q, src0, src4, 0x02, src1, src5, 0x02, src2, src6, 0x02, - src3, src7, 0x02, src0, src1, src2, src3); - DUP4_ARG3(__lasx_xvpermi_q, src4, src8, 0x02, src9, src13, 0x02, src10, src14, 0x02, - src11, src15, 0x02, src4, src5, src6, src7); - DUP2_ARG3(__lasx_xvpermi_q, src12, src16, 0x02, src13, src17, 0x02, src8, src9); - - DUP4_ARG2(__lasx_xvilvl_h, src5, src0, src6, src1, src7, src2, src8, src3, - sum0, sum2, sum4, sum6); - DUP4_ARG2(__lasx_xvilvh_h, src5, src0, src6, src1, src7, src2, src8, src3, - sum1, sum3, sum5, sum7); - src8 = __lasx_xvilvl_h(src9, src4); - src9 = __lasx_xvilvh_h(src9, src4); - - DUP4_ARG2(__lasx_xvhaddw_hu_bu, sum0, sum0, sum1, sum1, sum2, sum2, - sum3, sum3, src0, src1, src2, src3); - DUP4_ARG2(__lasx_xvhaddw_hu_bu, sum4, sum4, sum5, sum5, sum6, sum6, - sum7, sum7, src4, src5, src6, src7); - DUP2_ARG2(__lasx_xvhaddw_hu_bu, src8, src8, src9, src9, src8, src9); - - DUP4_ARG2(__lasx_xvadd_h, src0, src2, src1, src3, src2, src4, src3, src5, - sum0, sum1, sum2, sum3); - DUP4_ARG2(__lasx_xvadd_h, src4, src6, src5, src7, src6, src8, src7, src9, - sum4, sum5, sum6, sum7); - DUP4_ARG2(__lasx_xvaddi_hu, sum0, 1, sum1, 1, sum2, 1, sum3, 1, - sum0, sum1, sum2, sum3); - DUP4_ARG2(__lasx_xvaddi_hu, sum4, 1, sum5, 1, sum6, 1, sum7, 1, - sum4, sum5, sum6, sum7); - DUP4_ARG3(__lasx_xvsrani_b_h, sum1, sum0, 2, sum3, sum2, 2, sum5, sum4, 2, - sum7, sum6, 2, sum0, sum1, sum2, sum3); - __lasx_xvstelm_d(sum0, dst, 0, 0); - __lasx_xvstelm_d(sum0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum1, dst, 0, 0); - __lasx_xvstelm_d(sum1, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum2, dst, 0, 0); - __lasx_xvstelm_d(sum2, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum3, dst, 0, 0); - __lasx_xvstelm_d(sum3, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum0, dst, 0, 2); - __lasx_xvstelm_d(sum0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum1, dst, 0, 2); - __lasx_xvstelm_d(sum1, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum2, dst, 0, 2); - __lasx_xvstelm_d(sum2, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum3, dst, 0, 2); - __lasx_xvstelm_d(sum3, dst, 8, 3); -} - -static void common_hv_bil_no_rnd_8x16_lasx(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7, src8, src9; - __m256i src10, src11, src12, src13, src14, src15, src16, src17; - __m256i sum0, sum1, sum2, sum3, sum4, sum5, sum6, sum7; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t* _src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += (1 - src_stride_4x); - src9 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src10, src11); - src12 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src13 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src14, src15); - src16 = __lasx_xvldx(_src, src_stride_3x); - _src += (src_stride_4x - 1); - DUP2_ARG2(__lasx_xvld, _src, 0, _src, 1, src8, src17); - - DUP4_ARG3(__lasx_xvpermi_q, src0, src4, 0x02, src1, src5, 0x02, src2, - src6, 0x02, src3, src7, 0x02, src0, src1, src2, src3); - DUP4_ARG3(__lasx_xvpermi_q, src4, src8, 0x02, src9, src13, 0x02, src10, - src14, 0x02, src11, src15, 0x02, src4, src5, src6, src7); - DUP2_ARG3(__lasx_xvpermi_q, src12, src16, 0x02, src13, src17, 0x02, src8, src9); - - DUP4_ARG2(__lasx_xvilvl_h, src5, src0, src6, src1, src7, src2, src8, src3, - sum0, sum2, sum4, sum6); - DUP4_ARG2(__lasx_xvilvh_h, src5, src0, src6, src1, src7, src2, src8, src3, - sum1, sum3, sum5, sum7); - src8 = __lasx_xvilvl_h(src9, src4); - src9 = __lasx_xvilvh_h(src9, src4); - - DUP4_ARG2(__lasx_xvhaddw_hu_bu, sum0, sum0, sum1, sum1, sum2, sum2, - sum3, sum3, src0, src1, src2, src3); - DUP4_ARG2(__lasx_xvhaddw_hu_bu, sum4, sum4, sum5, sum5, sum6, sum6, - sum7, sum7, src4, src5, src6, src7); - DUP2_ARG2(__lasx_xvhaddw_hu_bu, src8, src8, src9, src9, src8, src9); - - DUP4_ARG2(__lasx_xvadd_h, src0, src2, src1, src3, src2, src4, src3, src5, - sum0, sum1, sum2, sum3); - DUP4_ARG2(__lasx_xvadd_h, src4, src6, src5, src7, src6, src8, src7, src9, - sum4, sum5, sum6, sum7); - DUP4_ARG2(__lasx_xvaddi_hu, sum0, 1, sum1, 1, sum2, 1, sum3, 1, - sum0, sum1, sum2, sum3); - DUP4_ARG2(__lasx_xvaddi_hu, sum4, 1, sum5, 1, sum6, 1, sum7, 1, - sum4, sum5, sum6, sum7); - DUP4_ARG3(__lasx_xvsrani_b_h, sum1, sum0, 2, sum3, sum2, 2, sum5, sum4, 2, - sum7, sum6, 2, sum0, sum1, sum2, sum3); - __lasx_xvstelm_d(sum0, dst, 0, 0); - __lasx_xvstelm_d(sum0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum1, dst, 0, 0); - __lasx_xvstelm_d(sum1, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum2, dst, 0, 0); - __lasx_xvstelm_d(sum2, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum3, dst, 0, 0); - __lasx_xvstelm_d(sum3, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum0, dst, 0, 2); - __lasx_xvstelm_d(sum0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum1, dst, 0, 2); - __lasx_xvstelm_d(sum1, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum2, dst, 0, 2); - __lasx_xvstelm_d(sum2, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum3, dst, 0, 2); - __lasx_xvstelm_d(sum3, dst, 8, 3); -} - void ff_put_no_rnd_pixels16_xy2_8_lasx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { - if (h == 16) { - common_hv_bil_no_rnd_16x16_lasx(pixels, line_size, block, line_size); - } else if (h == 8) { - common_hv_bil_no_rnd_8x16_lasx(pixels, line_size, block, line_size); + __m256i src0, src1, src2, src3; + __m256i sum0, sum1, sum2; + src0 = __lasx_xvld(pixels, 0); + src1 = __lasx_xvld(pixels, 1); + src2 = __lasx_vext2xv_hu_bu(src0); + src3 = __lasx_vext2xv_hu_bu(src1); + sum0 = __lasx_xvadd_h(src2, src3); + sum0 = __lasx_xvaddi_hu(sum0, 1); + + for (int i= 0; i < h; i++) { + pixels += line_size; + src0 = __lasx_xvld(pixels, 0); + src1 = __lasx_xvld(pixels, 1); + + src2 = __lasx_vext2xv_hu_bu(src0); + src3 = __lasx_vext2xv_hu_bu(src1); + sum1 = __lasx_xvadd_h(src2, src3); + sum2 = __lasx_xvadd_h(sum0, sum1); + sum2 = __lasx_xvsrani_b_h(sum2, sum2, 2); + + sum0 = __lasx_xvaddi_hu(sum1, 1); + __lasx_xvstelm_d(sum2, block, 0, 0); + __lasx_xvstelm_d(sum2, block, 8, 3); + + block += line_size; } } -static void common_hz_bil_no_rnd_8x8_lasx(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7; - __m256i src8, src9, src10, src11, src12, src13, src14, src15; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t dst_stride_2x = dst_stride << 1; - int32_t dst_stride_4x = dst_stride << 2; - int32_t dst_stride_3x = dst_stride_2x + dst_stride; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t* _src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += (1 - src_stride_4x); - src8 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src9, src10); - src11 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src12 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src13, src14); - src15 = __lasx_xvldx(_src, src_stride_3x); - - DUP4_ARG2(__lasx_xvpickev_d, src1, src0, src3, src2, src5, src4, src7, - src6, src0, src1, src2, src3); - DUP4_ARG2(__lasx_xvpickev_d, src9, src8, src11, src10, src13, src12, src15, - src14, src4, src5, src6, src7); - DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src5, src4, - 0x20, src7, src6, 0x20, src0, src1, src2, src3); - src0 = __lasx_xvavg_bu(src0, src2); - src1 = __lasx_xvavg_bu(src1, src3); - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst + dst_stride, 0, 1); - __lasx_xvstelm_d(src0, dst + dst_stride_2x, 0, 2); - __lasx_xvstelm_d(src0, dst + dst_stride_3x, 0, 3); - dst += dst_stride_4x; - __lasx_xvstelm_d(src1, dst, 0, 0); - __lasx_xvstelm_d(src1, dst + dst_stride, 0, 1); - __lasx_xvstelm_d(src1, dst + dst_stride_2x, 0, 2); - __lasx_xvstelm_d(src1, dst + dst_stride_3x, 0, 3); -} - -static void common_hz_bil_no_rnd_4x8_lasx(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_3x = src_stride_2x + src_stride; - int32_t dst_stride_2x = dst_stride << 1; - int32_t dst_stride_3x = dst_stride_2x + dst_stride; - uint8_t *_src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += 1; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - DUP4_ARG2(__lasx_xvpickev_d, src1, src0, src3, src2, src5, src4, src7, src6, - src0, src1, src2, src3); - DUP2_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src0, src1); - src0 = __lasx_xvavg_bu(src0, src1); - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst + dst_stride, 0, 1); - __lasx_xvstelm_d(src0, dst + dst_stride_2x, 0, 2); - __lasx_xvstelm_d(src0, dst + dst_stride_3x, 0, 3); -} - +/** + * For widths 8, h is always a positive multiple of 4. + * The function processes 4 rows per iteration. + */ void ff_put_no_rnd_pixels8_x2_8_lasx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { - if (h == 8) { - common_hz_bil_no_rnd_8x8_lasx(pixels, line_size, block, line_size); - } else if (h == 4) { - common_hz_bil_no_rnd_4x8_lasx(pixels, line_size, block, line_size); + __m256i src0, src1, src2, src3, src4, src5, src6, src7; + int32_t stride2x = line_size << 1; + int32_t stride3x = stride2x + line_size; + int32_t stride4x = line_size << 2; + uint8_t *_src = (uint8_t*)pixels + 1; + int32_t h_4 = h >> 2; + + for (int i = 0; i < h_4; i++) { + src0 = __lasx_xvld(pixels, 0); + DUP2_ARG2(__lasx_xvldx, pixels, line_size, pixels, stride2x, src1, src2); + src3 = __lasx_xvldx(pixels, stride3x); + src4 = __lasx_xvld(_src, 0); + DUP2_ARG2(__lasx_xvldx, _src, line_size, _src, stride2x, src5, src6); + src7 = __lasx_xvldx(_src, stride3x); + DUP4_ARG2(__lasx_xvpickev_d, src1, src0, src3, src2, src5, src4, src7, src6, + src0, src1, src2, src3); + DUP2_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src0, src1); + src0 = __lasx_xvavg_bu(src0, src1); + __lasx_xvstelm_d(src0, block, 0, 0); + block += line_size; + __lasx_xvstelm_d(src0, block, 0, 1); + block += line_size; + __lasx_xvstelm_d(src0, block, 0, 2); + block += line_size; + __lasx_xvstelm_d(src0, block, 0, 3); + block += line_size; + + pixels += stride4x; + _src += stride4x; } } -static void common_vt_bil_no_rnd_8x8_lasx(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7, src8; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t dst_stride_2x = dst_stride << 1; - int32_t dst_stride_4x = dst_stride << 2; - int32_t dst_stride_3x = dst_stride_2x + dst_stride; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t* _src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src8 = __lasx_xvld(_src, 0); - - DUP4_ARG2(__lasx_xvpickev_d, src1, src0, src2, src1, src3, src2, src4, src3, - src0, src1, src2, src3); - DUP4_ARG2(__lasx_xvpickev_d, src5, src4, src6, src5, src7, src6, src8, src7, - src4, src5, src6, src7); - DUP4_ARG3(__lasx_xvpermi_q, src2, src0, 0x20, src3, src1, 0x20, src6, src4, - 0x20, src7, src5, 0x20, src0, src1, src2, src3); - src0 = __lasx_xvavg_bu(src0, src1); - src1 = __lasx_xvavg_bu(src2, src3); - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst + dst_stride, 0, 1); - __lasx_xvstelm_d(src0, dst + dst_stride_2x, 0, 2); - __lasx_xvstelm_d(src0, dst + dst_stride_3x, 0, 3); - dst += dst_stride_4x; - __lasx_xvstelm_d(src1, dst, 0, 0); - __lasx_xvstelm_d(src1, dst + dst_stride, 0, 1); - __lasx_xvstelm_d(src1, dst + dst_stride_2x, 0, 2); - __lasx_xvstelm_d(src1, dst + dst_stride_3x, 0, 3); -} - -static void common_vt_bil_no_rnd_4x8_lasx(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t dst_stride_2x = dst_stride << 1; - int32_t dst_stride_3x = dst_stride_2x + dst_stride; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t* _src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP4_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, _src, - src_stride_3x, _src, src_stride_4x, src1, src2, src3, src4); - DUP4_ARG2(__lasx_xvpickev_d, src1, src0, src2, src1, src3, src2, src4, src3, - src0, src1, src2, src3); - DUP2_ARG3(__lasx_xvpermi_q, src2, src0, 0x20, src3, src1, 0x20, src0, src1); - src0 = __lasx_xvavg_bu(src0, src1); - __lasx_xvstelm_d(src0, dst, 0, 0); - __lasx_xvstelm_d(src0, dst + dst_stride, 0, 1); - __lasx_xvstelm_d(src0, dst + dst_stride_2x, 0, 2); - __lasx_xvstelm_d(src0, dst + dst_stride_3x, 0, 3); -} - +/** + * For widths 8, h is always a positive multiple of 4. + * The function processes 4 rows per iteration. + */ void ff_put_no_rnd_pixels8_y2_8_lasx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { - if (h == 8) { - common_vt_bil_no_rnd_8x8_lasx(pixels, line_size, block, line_size); - } else if (h == 4) { - common_vt_bil_no_rnd_4x8_lasx(pixels, line_size, block, line_size); - } -} + __m256i src0, src1, src2, src3, src4; + int32_t stride2x = line_size << 1; + int32_t stride4x = line_size << 2; + int32_t stride3x = stride2x + line_size; + uint8_t* _src = (uint8_t*)pixels; + int32_t h_4 = h >> 2; -static void common_hv_bil_no_rnd_8x8_lasx(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7; - __m256i src8, src9, src10, src11, src12, src13, src14, src15, src16, src17; - __m256i sum0, sum1, sum2, sum3; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t dst_stride_2x = dst_stride << 1; - int32_t dst_stride_4x = dst_stride << 2; - int32_t dst_stride_3x = dst_stride_2x + dst_stride; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t* _src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += (1 - src_stride_4x); - src9 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src10, src11); - src12 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src13 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src14, src15); - src16 = __lasx_xvldx(_src, src_stride_3x); - _src += (src_stride_4x - 1); - DUP2_ARG2(__lasx_xvld, _src, 0, _src, 1, src8, src17); - - DUP4_ARG2(__lasx_xvilvl_b, src9, src0, src10, src1, src11, src2, src12, src3, - src0, src1, src2, src3); - DUP4_ARG2(__lasx_xvilvl_b, src13, src4, src14, src5, src15, src6, src16, src7, - src4, src5, src6, src7); - src8 = __lasx_xvilvl_b(src17, src8); - DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src2, src1, 0x20, src3, src2, - 0x20, src4, src3, 0x20, src0, src1, src2, src3); - DUP4_ARG3(__lasx_xvpermi_q, src5, src4, 0x20, src6, src5, 0x20, src7, src6, - 0x20, src8, src7, 0x20, src4, src5, src6, src7); - DUP4_ARG2(__lasx_xvhaddw_hu_bu, src0, src0, src1, src1, src2, src2, - src3, src3, src0, src1, src2, src3); - DUP4_ARG2(__lasx_xvhaddw_hu_bu, src4, src4, src5, src5, src6, src6, - src7, src7, src4, src5, src6, src7); - DUP4_ARG2(__lasx_xvadd_h, src0, src1, src2, src3, src4, src5, src6, src7, - sum0, sum1, sum2, sum3); - DUP4_ARG2(__lasx_xvaddi_hu, sum0, 1, sum1, 1, sum2, 1, sum3, 1, - sum0, sum1, sum2, sum3); - DUP2_ARG3(__lasx_xvsrani_b_h, sum1, sum0, 2, sum3, sum2, 2, sum0, sum1); - __lasx_xvstelm_d(sum0, dst, 0, 0); - __lasx_xvstelm_d(sum0, dst + dst_stride, 0, 2); - __lasx_xvstelm_d(sum0, dst + dst_stride_2x, 0, 1); - __lasx_xvstelm_d(sum0, dst + dst_stride_3x, 0, 3); - dst += dst_stride_4x; - __lasx_xvstelm_d(sum1, dst, 0, 0); - __lasx_xvstelm_d(sum1, dst + dst_stride, 0, 2); - __lasx_xvstelm_d(sum1, dst + dst_stride_2x, 0, 1); - __lasx_xvstelm_d(sum1, dst + dst_stride_3x, 0, 3); -} - -static void common_hv_bil_no_rnd_4x8_lasx(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7; - __m256i src8, src9, sum0, sum1; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t dst_stride_2x = dst_stride << 1; - int32_t dst_stride_3x = dst_stride_2x + dst_stride; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t *_src = (uint8_t*)src; - - src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += 1; - src5 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src6, src7); - src8 = __lasx_xvldx(_src, src_stride_3x); - _src += (src_stride_4x - 1); - DUP2_ARG2(__lasx_xvld, _src, 0, _src, 1, src4, src9); - - DUP4_ARG2(__lasx_xvilvl_b, src5, src0, src6, src1, src7, src2, src8, src3, - src0, src1, src2, src3); - src4 = __lasx_xvilvl_b(src9, src4); - DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src2, src1, 0x20, src3, src2, - 0x20, src4, src3, 0x20, src0, src1, src2, src3); - DUP4_ARG2(__lasx_xvhaddw_hu_bu, src0, src0, src1, src1, src2, src2, - src3, src3, src0, src1, src2, src3); - DUP2_ARG2(__lasx_xvadd_h, src0, src1, src2, src3, sum0, sum1); - sum0 = __lasx_xvaddi_hu(sum0, 1); - sum1 = __lasx_xvaddi_hu(sum1, 1); - sum0 = __lasx_xvsrani_b_h(sum1, sum0, 2); - __lasx_xvstelm_d(sum0, dst, 0, 0); - __lasx_xvstelm_d(sum0, dst + dst_stride, 0, 2); - __lasx_xvstelm_d(sum0, dst + dst_stride_2x, 0, 1); - __lasx_xvstelm_d(sum0, dst + dst_stride_3x, 0, 3); -} - -void ff_put_no_rnd_pixels8_xy2_8_lasx(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h) -{ - if (h == 8) { - common_hv_bil_no_rnd_8x8_lasx(pixels, line_size, block, line_size); - } else if (h == 4) { - common_hv_bil_no_rnd_4x8_lasx(pixels, line_size, block, line_size); - } -} - -static void common_hv_bil_16w_lasx(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint8_t height) -{ - __m256i src0, src1, src2, src3, src4, src5, src6, src7, src8, src9; - __m256i src10, src11, src12, src13, src14, src15, src16, src17; - __m256i sum0, sum1, sum2, sum3, sum4, sum5, sum6, sum7; - uint8_t loop_cnt; - int32_t src_stride_2x = src_stride << 1; - int32_t src_stride_4x = src_stride << 2; - int32_t src_stride_3x = src_stride_2x + src_stride; - uint8_t* _src = (uint8_t*)src; - - for (loop_cnt = (height >> 3); loop_cnt--;) { + for (int i = 0; i < h_4; i++) { src0 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src1, src2); - src3 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src4 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, src5, src6); - src7 = __lasx_xvldx(_src, src_stride_3x); - _src += (1 - src_stride_4x); - src9 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src10, src11); - src12 = __lasx_xvldx(_src, src_stride_3x); - _src += src_stride_4x; - src13 = __lasx_xvld(_src, 0); - DUP2_ARG2(__lasx_xvldx, _src, src_stride, _src, src_stride_2x, - src14, src15); - src16 = __lasx_xvldx(_src, src_stride_3x); - _src += (src_stride_4x - 1); - DUP2_ARG2(__lasx_xvld, _src, 0, _src, 1, src8, src17); + DUP4_ARG2(__lasx_xvldx, _src, line_size, _src, stride2x, _src, + stride3x, _src, stride4x, src1, src2, src3, src4); + DUP4_ARG2(__lasx_xvpickev_d, src1, src0, src2, src1, src3, src2, src4, src3, + src0, src1, src2, src3); + DUP2_ARG3(__lasx_xvpermi_q, src2, src0, 0x20, src3, src1, 0x20, src0, src1); + src0 = __lasx_xvavg_bu(src0, src1); + __lasx_xvstelm_d(src0, block, 0, 0); + block += line_size; + __lasx_xvstelm_d(src0, block, 0, 1); + block += line_size; + __lasx_xvstelm_d(src0, block, 0, 2); + block += line_size; + __lasx_xvstelm_d(src0, block, 0, 3); + block += line_size; - DUP4_ARG3(__lasx_xvpermi_q, src0, src4, 0x02, src1, src5, 0x02, src2, - src6, 0x02, src3, src7, 0x02, src0, src1, src2, src3); - DUP4_ARG3(__lasx_xvpermi_q, src4, src8, 0x02, src9, src13, 0x02, src10, - src14, 0x02, src11, src15, 0x02, src4, src5, src6, src7); - DUP2_ARG3(__lasx_xvpermi_q, src12, src16, 0x02, src13, src17, 0x02, - src8, src9); + _src += stride4x; + } +} - DUP4_ARG2(__lasx_xvilvl_h, src5, src0, src6, src1, src7, src2, src8, - src3, sum0, sum2, sum4, sum6); - DUP4_ARG2(__lasx_xvilvh_h, src5, src0, src6, src1, src7, src2, src8, - src3, sum1, sum3, sum5, sum7); - src8 = __lasx_xvilvl_h(src9, src4); - src9 = __lasx_xvilvh_h(src9, src4); +void ff_put_no_rnd_pixels8_xy2_8_lsx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h) +{ + __m128i src0, src1, src2, src3; + __m128i sum0, sum1, sum2; - DUP4_ARG2(__lasx_xvhaddw_hu_bu, sum0, sum0, sum1, sum1, sum2, sum2, - sum3, sum3, src0, src1, src2, src3); - DUP4_ARG2(__lasx_xvhaddw_hu_bu, sum4, sum4, sum5, sum5, sum6, sum6, - sum7, sum7, src4, src5, src6, src7); - DUP2_ARG2(__lasx_xvhaddw_hu_bu, src8, src8, src9, src9, src8, src9); + src0 = __lsx_vld(pixels, 0); + src1 = __lsx_vld(pixels, 1); + src2 = __lsx_vsllwil_hu_bu(src0, 0); + src3 = __lsx_vsllwil_hu_bu(src1, 0); + sum0 = __lsx_vadd_h(src2, src3); + sum0 = __lsx_vaddi_hu(sum0, 1); - DUP4_ARG2(__lasx_xvadd_h, src0, src2, src1, src3, src2, src4, src3, - src5, sum0, sum1, sum2, sum3); - DUP4_ARG2(__lasx_xvadd_h, src4, src6, src5, src7, src6, src8, src7, - src9, sum4, sum5, sum6, sum7); - DUP4_ARG3(__lasx_xvsrarni_b_h, sum1, sum0, 2, sum3, sum2, 2, sum5, - sum4, 2, sum7, sum6, 2, sum0, sum1, sum2, sum3); - __lasx_xvstelm_d(sum0, dst, 0, 0); - __lasx_xvstelm_d(sum0, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum1, dst, 0, 0); - __lasx_xvstelm_d(sum1, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum2, dst, 0, 0); - __lasx_xvstelm_d(sum2, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum3, dst, 0, 0); - __lasx_xvstelm_d(sum3, dst, 8, 1); - dst += dst_stride; - __lasx_xvstelm_d(sum0, dst, 0, 2); - __lasx_xvstelm_d(sum0, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum1, dst, 0, 2); - __lasx_xvstelm_d(sum1, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum2, dst, 0, 2); - __lasx_xvstelm_d(sum2, dst, 8, 3); - dst += dst_stride; - __lasx_xvstelm_d(sum3, dst, 0, 2); - __lasx_xvstelm_d(sum3, dst, 8, 3); - dst += dst_stride; + for (int i = 0; i < h; i++) { + pixels += line_size; + src0 = __lsx_vld(pixels, 0); + src1 = __lsx_vld(pixels, 1); + src2 = __lsx_vsllwil_hu_bu(src0, 0); + src3 = __lsx_vsllwil_hu_bu(src1, 0); + sum1 = __lsx_vadd_h(src2, src3); + sum2 = __lsx_vadd_h(sum0, sum1); + sum2 = __lsx_vsrani_b_h(sum2, sum2, 2); + + sum0 = __lsx_vaddi_hu(sum1, 1); + __lsx_vstelm_d(sum2, block, 0, 0); + + block += line_size; } } void ff_put_pixels16_xy2_8_lasx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { - common_hv_bil_16w_lasx(pixels, line_size, block, line_size, h); + __m256i src0, src1, src2, src3; + __m256i sum0, sum1, sum2; + + src0 = __lasx_xvld(pixels, 0); + src1 = __lasx_xvld(pixels, 1); + src2 = __lasx_vext2xv_hu_bu(src0); + src3 = __lasx_vext2xv_hu_bu(src1); + sum0 = __lasx_xvadd_h(src2, src3); + sum0 = __lasx_xvaddi_hu(sum0, 2); + + for (int i = 0; i < h; i++) { + pixels += line_size; + src0 = __lasx_xvld(pixels, 0); + src1 = __lasx_xvld(pixels, 1); + + src2 = __lasx_vext2xv_hu_bu(src0); + src3 = __lasx_vext2xv_hu_bu(src1); + sum1 = __lasx_xvadd_h(src2, src3); + sum2 = __lasx_xvadd_h(sum0, sum1); + sum2 = __lasx_xvsrani_b_h(sum2, sum2, 2); + sum0 = __lasx_xvaddi_hu(sum1, 2); + __lasx_xvstelm_d(sum2, block, 0, 0); + __lasx_xvstelm_d(sum2, block, 8, 3); + block += line_size; + } } static void common_hv_bil_8w_lasx(const uint8_t *src, int32_t src_stride, diff --git a/libavcodec/loongarch/hpeldsp_lasx.h b/libavcodec/loongarch/hpeldsp_lasx.h index 2e035eade..df3987d30 100644 --- a/libavcodec/loongarch/hpeldsp_lasx.h +++ b/libavcodec/loongarch/hpeldsp_lasx.h @@ -49,8 +49,8 @@ void ff_put_no_rnd_pixels8_x2_8_lasx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); void ff_put_no_rnd_pixels8_y2_8_lasx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); -void ff_put_no_rnd_pixels8_xy2_8_lasx(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels8_xy2_8_lsx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); void ff_put_pixels8_xy2_8_lasx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); void ff_put_pixels16_xy2_8_lasx(uint8_t *block, const uint8_t *pixels, diff --git a/libavcodec/loongarch/loongson_asm.S b/libavcodec/loongarch/loongson_asm.S index 0a649f51c..5edec9b82 100644 --- a/libavcodec/loongarch/loongson_asm.S +++ b/libavcodec/loongarch/loongson_asm.S @@ -332,7 +332,7 @@ ASM_PREF\name: ; /* * Description : Store elements of vector - * vd : Data vector to be stroed + * vd : Data vector to be stored * rk : Address of data storage * ra : Offset of address * si : Index of data in vd diff --git a/libavcodec/loongarch/vc1dsp_loongarch.h b/libavcodec/loongarch/vc1dsp_loongarch.h index e5ccbcb76..30589e248 100644 --- a/libavcodec/loongarch/vc1dsp_loongarch.h +++ b/libavcodec/loongarch/vc1dsp_loongarch.h @@ -30,7 +30,7 @@ void ff_vc1_inv_trans_8x8_dc_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *bloc void ff_vc1_inv_trans_8x4_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_8x4_dc_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_4x8_dc_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); -void ff_vc1_inv_trans_4x8_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *blokc); +void ff_vc1_inv_trans_4x8_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_4x4_dc_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_4x4_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); diff --git a/libavcodec/lossless_audiodsp.c b/libavcodec/lossless_audiodsp.c index b0d64cf5b..2d57857da 100644 --- a/libavcodec/lossless_audiodsp.c +++ b/libavcodec/lossless_audiodsp.c @@ -61,11 +61,9 @@ av_cold void ff_llauddsp_init(LLAudDSPContext *c) #if ARCH_ARM ff_llauddsp_init_arm(c); -#elif ARCH_PPC - ff_llauddsp_init_ppc(c); #elif ARCH_RISCV ff_llauddsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_llauddsp_init_x86(c); #endif } diff --git a/libavcodec/lossless_audiodsp.h b/libavcodec/lossless_audiodsp.h index cf2d43d7c..e89e27fef 100644 --- a/libavcodec/lossless_audiodsp.h +++ b/libavcodec/lossless_audiodsp.h @@ -45,7 +45,6 @@ typedef struct LLAudDSPContext { void ff_llauddsp_init(LLAudDSPContext *c); void ff_llauddsp_init_arm(LLAudDSPContext *c); -void ff_llauddsp_init_ppc(LLAudDSPContext *c); void ff_llauddsp_init_riscv(LLAudDSPContext *c); void ff_llauddsp_init_x86(LLAudDSPContext *c); diff --git a/libavcodec/lossless_videodsp.c b/libavcodec/lossless_videodsp.c index 876decb1e..bf3a3da90 100644 --- a/libavcodec/lossless_videodsp.c +++ b/libavcodec/lossless_videodsp.c @@ -21,6 +21,7 @@ #include "config.h" #include "lossless_videodsp.h" #include "libavcodec/mathops.h" +#include "libavutil/attributes.h" // 0x7f7f7f7f or 0x7f7f7f7f7f7f7f7f or whatever, depending on the cpu's native arithmetic size #define pb_7f (~0UL / 255 * 0x7f) @@ -110,7 +111,7 @@ static void add_gradient_pred_c(uint8_t *src, const ptrdiff_t stride, const ptrd } } -void ff_llviddsp_init(LLVidDSPContext *c) +av_cold void ff_llviddsp_init(LLVidDSPContext *c) { c->add_bytes = add_bytes_c; c->add_median_pred = add_median_pred_c; @@ -123,7 +124,7 @@ void ff_llviddsp_init(LLVidDSPContext *c) ff_llviddsp_init_ppc(c); #elif ARCH_RISCV ff_llviddsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_llviddsp_init_x86(c); #endif } diff --git a/libavcodec/lossless_videoencdsp.h b/libavcodec/lossless_videoencdsp.h index 7fd0ad32c..44b33e7ed 100644 --- a/libavcodec/lossless_videoencdsp.h +++ b/libavcodec/lossless_videoencdsp.h @@ -29,7 +29,6 @@ typedef struct LLVidEncDSPContext { intptr_t w); /** * Subtract HuffYUV's variant of median prediction. - * Note, this might read from src1[-1], src2[-1]. */ void (*sub_median_pred)(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, intptr_t w, diff --git a/libavcodec/lpc.c b/libavcodec/lpc.c index e793e5403..38c78d952 100644 --- a/libavcodec/lpc.c +++ b/libavcodec/lpc.c @@ -267,7 +267,7 @@ int ff_lpc_calc_coefs(LPCContext *s, s->lpc_compute_autocorr(s->windowed_samples, blocksize, max_order, autoc); - compute_lpc_coefs(autoc, max_order, &lpc[0][0], MAX_LPC_ORDER, 0, 1); + compute_lpc_coefs(autoc, 0, max_order, &lpc[0][0], MAX_LPC_ORDER, 0, 1, NULL); for(i=0; isize; } -static int lscr_decode_close(AVCodecContext *avctx) +static av_cold int lscr_decode_close(AVCodecContext *avctx) { LSCRContext *s = avctx->priv_data; @@ -225,7 +225,7 @@ static int lscr_decode_close(AVCodecContext *avctx) return 0; } -static int lscr_decode_init(AVCodecContext *avctx) +static av_cold int lscr_decode_init(AVCodecContext *avctx) { LSCRContext *s = avctx->priv_data; @@ -242,7 +242,7 @@ static int lscr_decode_init(AVCodecContext *avctx) return ff_inflate_init(&s->zstream, avctx); } -static void lscr_decode_flush(AVCodecContext *avctx) +static av_cold void lscr_decode_flush(AVCodecContext *avctx) { LSCRContext *s = avctx->priv_data; av_frame_unref(s->last_picture); diff --git a/libavcodec/lsp.c b/libavcodec/lsp.c index 275984097..4eaeb2bfc 100644 --- a/libavcodec/lsp.c +++ b/libavcodec/lsp.c @@ -150,7 +150,13 @@ static void lsp2polyf(const double *lsp, double *f, int lp_half_order) } #endif /* lsp2polyf */ -void ff_acelp_lsp2lpc(int16_t* lp, const int16_t* lsp, int lp_half_order) +/** + * @brief LSP to LP conversion (3.2.6 of G.729) + * @param[out] lp decoded LP coefficients (-0x8000 <= (3.12) < 0x8000) + * @param lsp LSP coefficients (-0x8000 <= (0.15) < 0x8000) + * @param lp_half_order LP filter order, divided by 2 + */ +static void acelp_lsp2lpc(int16_t lp[], const int16_t lsp[], int lp_half_order) { int i; int f1[MAX_LP_HALF_ORDER+1]; // (3.22) @@ -211,10 +217,10 @@ void ff_acelp_lp_decode(int16_t* lp_1st, int16_t* lp_2nd, const int16_t* lsp_2nd lsp_1st[i] = (lsp_2nd[i] + lsp_prev[i]) >> 1; #endif - ff_acelp_lsp2lpc(lp_1st, lsp_1st, lp_order >> 1); + acelp_lsp2lpc(lp_1st, lsp_1st, lp_order >> 1); /* LSP values for second subframe (3.2.5 of G.729)*/ - ff_acelp_lsp2lpc(lp_2nd, lsp_2nd, lp_order >> 1); + acelp_lsp2lpc(lp_2nd, lsp_2nd, lp_order >> 1); } void ff_acelp_lspd2lpc(const double *lsp, float *lpc, int lp_half_order) diff --git a/libavcodec/lsp.h b/libavcodec/lsp.h index 26b1382ed..17126a43c 100644 --- a/libavcodec/lsp.h +++ b/libavcodec/lsp.h @@ -67,14 +67,6 @@ void ff_acelp_lsf2lsp(int16_t *lsp, const int16_t *lsf, int lp_order); */ void ff_acelp_lsf2lspd(double *lsp, const float *lsf, int lp_order); -/** - * @brief LSP to LP conversion (3.2.6 of G.729) - * @param[out] lp decoded LP coefficients (-0x8000 <= (3.12) < 0x8000) - * @param lsp LSP coefficients (-0x8000 <= (0.15) < 0x8000) - * @param lp_half_order LP filter order, divided by 2 - */ -void ff_acelp_lsp2lpc(int16_t* lp, const int16_t* lsp, int lp_half_order); - /** * LSP to LP conversion (5.2.4 of AMR-WB) */ diff --git a/libavcodec/mace.c b/libavcodec/mace.c index a35291330..299e5f5cf 100644 --- a/libavcodec/mace.c +++ b/libavcodec/mace.c @@ -293,8 +293,6 @@ const FFCodec ff_mace3_decoder = { .init = mace_decode_init, FF_CODEC_DECODE_CB(mace_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, }; const FFCodec ff_mace6_decoder = { @@ -306,6 +304,4 @@ const FFCodec ff_mace6_decoder = { .init = mace_decode_init, FF_CODEC_DECODE_CB(mace_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/magicyuv.c b/libavcodec/magicyuv.c index 27095797f..46d474a24 100644 --- a/libavcodec/magicyuv.c +++ b/libavcodec/magicyuv.c @@ -463,37 +463,22 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p, return AVERROR_PATCHWELCOME; } - s->hshift[1] = - s->vshift[1] = - s->hshift[2] = - s->vshift[2] = 0; - s->decorrelate = 0; - s->bps = 8; - format = bytestream2_get_byteu(&gb); switch (format) { case 0x65: avctx->pix_fmt = AV_PIX_FMT_GBRP; - s->decorrelate = 1; break; case 0x66: avctx->pix_fmt = AV_PIX_FMT_GBRAP; - s->decorrelate = 1; break; case 0x67: avctx->pix_fmt = AV_PIX_FMT_YUV444P; break; case 0x68: avctx->pix_fmt = AV_PIX_FMT_YUV422P; - s->hshift[1] = - s->hshift[2] = 1; break; case 0x69: avctx->pix_fmt = AV_PIX_FMT_YUV420P; - s->hshift[1] = - s->vshift[1] = - s->hshift[2] = - s->vshift[2] = 1; break; case 0x6a: avctx->pix_fmt = AV_PIX_FMT_YUVA444P; @@ -503,60 +488,44 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p, break; case 0x6c: avctx->pix_fmt = AV_PIX_FMT_YUV422P10; - s->hshift[1] = - s->hshift[2] = 1; - s->bps = 10; break; case 0x76: avctx->pix_fmt = AV_PIX_FMT_YUV444P10; - s->bps = 10; break; case 0x6d: avctx->pix_fmt = AV_PIX_FMT_GBRP10; - s->decorrelate = 1; - s->bps = 10; break; case 0x6e: avctx->pix_fmt = AV_PIX_FMT_GBRAP10; - s->decorrelate = 1; - s->bps = 10; break; case 0x6f: avctx->pix_fmt = AV_PIX_FMT_GBRP12; - s->decorrelate = 1; - s->bps = 12; break; case 0x70: avctx->pix_fmt = AV_PIX_FMT_GBRAP12; - s->decorrelate = 1; - s->bps = 12; break; case 0x71: avctx->pix_fmt = AV_PIX_FMT_GBRP14; - s->decorrelate = 1; - s->bps = 14; break; case 0x72: avctx->pix_fmt = AV_PIX_FMT_GBRAP14; - s->decorrelate = 1; - s->bps = 14; break; case 0x73: avctx->pix_fmt = AV_PIX_FMT_GRAY10; - s->bps = 10; break; case 0x7b: avctx->pix_fmt = AV_PIX_FMT_YUV420P10; - s->hshift[1] = - s->vshift[1] = - s->hshift[2] = - s->vshift[2] = 1; - s->bps = 10; break; default: avpriv_request_sample(avctx, "Format 0x%X", format); return AVERROR_PATCHWELCOME; } + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); + av_assert1(desc); + int is_rgb = s->decorrelate = !!(desc->flags & AV_PIX_FMT_FLAG_RGB); + s->hshift[1] = s->hshift[2] = desc->log2_chroma_w; + s->vshift[1] = s->vshift[2] = desc->log2_chroma_h; + s->bps = desc->comp[0].depth; s->max = 1 << s->bps; s->magy_decode_slice = s->bps == 8 ? magy_decode_slice : magy_decode_slice10; s->planes = av_pix_fmt_count_planes(avctx->pix_fmt); @@ -660,14 +629,7 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p, s->p = p; avctx->execute2(avctx, s->magy_decode_slice, NULL, NULL, s->nb_slices); - if (avctx->pix_fmt == AV_PIX_FMT_GBRP || - avctx->pix_fmt == AV_PIX_FMT_GBRAP || - avctx->pix_fmt == AV_PIX_FMT_GBRP10 || - avctx->pix_fmt == AV_PIX_FMT_GBRAP10|| - avctx->pix_fmt == AV_PIX_FMT_GBRAP12|| - avctx->pix_fmt == AV_PIX_FMT_GBRAP14|| - avctx->pix_fmt == AV_PIX_FMT_GBRP12|| - avctx->pix_fmt == AV_PIX_FMT_GBRP14) { + if (is_rgb) { FFSWAP(uint8_t*, p->data[0], p->data[1]); FFSWAP(int, p->linesize[0], p->linesize[1]); } else { diff --git a/libavcodec/magicyuvenc.c b/libavcodec/magicyuvenc.c index 3364207f8..80a54638b 100644 --- a/libavcodec/magicyuvenc.c +++ b/libavcodec/magicyuvenc.c @@ -50,15 +50,18 @@ typedef struct HuffEntry { typedef struct PTable { int value; ///< input value - int64_t prob; ///< number of occurences of this value in input + int64_t prob; ///< number of occurrences of this value in input } PTable; typedef struct Slice { + int width; + int height; + int encode_raw; unsigned pos; unsigned size; uint8_t *slice; - uint8_t *bitslice; - PTable counts[256]; + uint8_t *dst; + int64_t counts[256]; } Slice; typedef struct MagicYUVContext { @@ -71,7 +74,6 @@ typedef struct MagicYUVContext { int correlate; int hshift[4]; int vshift[4]; - unsigned bitslice_size; uint8_t *decorrelate_buf[2]; Slice *slices; HuffEntry he[4][256]; @@ -201,11 +203,12 @@ static av_cold int magy_encode_init(AVCodecContext *avctx) s->planes = av_pix_fmt_count_planes(avctx->pix_fmt); - s->nb_slices = (avctx->slices <= 0) ? av_cpu_count() : avctx->slices; + s->nb_slices = avctx->slices > 0 ? avctx->slices : avctx->thread_count; s->nb_slices = FFMIN(s->nb_slices, avctx->height >> s->vshift[1]); s->nb_slices = FFMAX(1, s->nb_slices); s->slice_height = FFALIGN((avctx->height + s->nb_slices - 1) / s->nb_slices, 1 << s->vshift[1]); s->nb_slices = (avctx->height + s->slice_height - 1) / s->slice_height; + s->nb_slices = FFMIN(256U / s->planes, s->nb_slices); s->slices = av_calloc(s->nb_slices * s->planes, sizeof(*s->slices)); if (!s->slices) return AVERROR(ENOMEM); @@ -220,18 +223,18 @@ static av_cold int magy_encode_init(AVCodecContext *avctx) s->decorrelate_buf[1] = s->decorrelate_buf[0] + (s->nb_slices * s->slice_height) * aligned_width; } - s->bitslice_size = avctx->width * s->slice_height + 2; for (int n = 0; n < s->nb_slices; n++) { for (int i = 0; i < s->planes; i++) { Slice *sl = &s->slices[n * s->planes + i]; - sl->bitslice = av_malloc(s->bitslice_size + AV_INPUT_BUFFER_PADDING_SIZE); + sl->height = n == s->nb_slices - 1 ? avctx->height - n * s->slice_height : s->slice_height; + sl->height = AV_CEIL_RSHIFT(sl->height, s->vshift[i]); + sl->width = AV_CEIL_RSHIFT(avctx->width, s->hshift[i]); + sl->slice = av_malloc(avctx->width * (s->slice_height + 2) + AV_INPUT_BUFFER_PADDING_SIZE); - if (!sl->slice || !sl->bitslice) { - av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer.\n"); + if (!sl->slice) return AVERROR(ENOMEM); - } } } @@ -245,29 +248,26 @@ static av_cold int magy_encode_init(AVCodecContext *avctx) avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); - - if (!avctx->extradata) { - av_log(avctx, AV_LOG_ERROR, "Could not allocate extradata.\n"); + if (!avctx->extradata) return AVERROR(ENOMEM); - } bytestream2_init_writer(&pb, avctx->extradata, MAGICYUV_EXTRADATA_SIZE); - bytestream2_put_le32(&pb, MKTAG('M', 'A', 'G', 'Y')); - bytestream2_put_le32(&pb, 32); - bytestream2_put_byte(&pb, 7); - bytestream2_put_byte(&pb, s->format); - bytestream2_put_byte(&pb, 12); - bytestream2_put_byte(&pb, 0); + bytestream2_put_le32u(&pb, MKTAG('M', 'A', 'G', 'Y')); + bytestream2_put_le32u(&pb, 32); + bytestream2_put_byteu(&pb, 7); + bytestream2_put_byteu(&pb, s->format); + bytestream2_put_byteu(&pb, 12); + bytestream2_put_byteu(&pb, 0); - bytestream2_put_byte(&pb, 0); - bytestream2_put_byte(&pb, 0); - bytestream2_put_byte(&pb, 32); - bytestream2_put_byte(&pb, 0); + bytestream2_put_byteu(&pb, 0); + bytestream2_put_byteu(&pb, 0); + bytestream2_put_byteu(&pb, 32); + bytestream2_put_byteu(&pb, 0); - bytestream2_put_le32(&pb, avctx->width); - bytestream2_put_le32(&pb, avctx->height); - bytestream2_put_le32(&pb, avctx->width); - bytestream2_put_le32(&pb, avctx->height); + bytestream2_put_le32u(&pb, avctx->width); + bytestream2_put_le32u(&pb, avctx->height); + bytestream2_put_le32u(&pb, avctx->width); + bytestream2_put_le32u(&pb, avctx->height); return 0; } @@ -287,11 +287,11 @@ static void calculate_codes(HuffEntry *he, uint16_t codes_count[33]) } static void count_usage(const uint8_t *src, int width, - int height, PTable *counts) + int height, int64_t *counts) { for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) - counts[src[i]].prob++; + counts[src[i]]++; src += width; } } @@ -377,53 +377,51 @@ static int count_plane_slice(AVCodecContext *avctx, int n, int plane) MagicYUVContext *s = avctx->priv_data; Slice *sl = &s->slices[n * s->planes + plane]; const uint8_t *dst = sl->slice; - PTable *counts = sl->counts; - const int slice_height = s->slice_height; - const int last_height = FFMIN(slice_height, avctx->height - n * slice_height); - const int height = (n < (s->nb_slices - 1)) ? slice_height : last_height; + int64_t *counts = sl->counts; memset(counts, 0, sizeof(sl->counts)); - count_usage(dst, AV_CEIL_RSHIFT(avctx->width, s->hshift[plane]), - AV_CEIL_RSHIFT(height, s->vshift[plane]), counts); + count_usage(dst, sl->width, sl->height, counts); return 0; } -static int encode_table(AVCodecContext *avctx, - PutBitContext *pb, HuffEntry *he, int plane) +static void generate_codes(AVCodecContext *avctx, + HuffEntry *he, int plane) { MagicYUVContext *s = avctx->priv_data; - PTable counts[256] = { {0} }; + PTable counts[256]; uint16_t codes_counts[33] = { 0 }; + for (size_t i = 0; i < FF_ARRAY_ELEMS(counts); i++) { + counts[i].prob = 1; + counts[i].value = i; + } + for (int n = 0; n < s->nb_slices; n++) { Slice *sl = &s->slices[n * s->planes + plane]; - PTable *slice_counts = sl->counts; + int64_t *slice_counts = sl->counts; for (int i = 0; i < 256; i++) - counts[i].prob = slice_counts[i].prob; - } - - for (int i = 0; i < 256; i++) { - counts[i].prob++; - counts[i].value = i; + counts[i].prob += slice_counts[i]; } magy_huffman_compute_bits(counts, he, codes_counts, 256, 12); calculate_codes(he, codes_counts); - - for (int i = 0; i < 256; i++) { - put_bits(pb, 1, 0); - put_bits(pb, 7, he[i].len); - } - - return 0; } -static int encode_plane_slice_raw(const uint8_t *src, uint8_t *dst, unsigned dst_size, - int width, int height, int prediction) +static void output_codes(PutByteContext *pb, const HuffEntry he[256]) +{ + for (int i = 0; i < 256; i++) { + // The seven low bits are len; the top bit means the run of + // codes of this length has length one. + bytestream2_put_byteu(pb, he[i].len); + } +} + +static void encode_plane_slice_raw(const uint8_t *src, uint8_t *dst, + int width, int height, int prediction) { unsigned count = width * height; @@ -431,20 +429,12 @@ static int encode_plane_slice_raw(const uint8_t *src, uint8_t *dst, unsigned dst dst[1] = prediction; memcpy(dst + 2, src, count); - count += 2; - AV_WN32(dst + count, 0); - if (count & 3) - count += 4 - (count & 3); - - return count; } -static int encode_plane_slice(const uint8_t *src, uint8_t *dst, unsigned dst_size, - int width, int height, HuffEntry *he, int prediction) +static void encode_plane_slice(const uint8_t *src, uint8_t *dst, unsigned dst_size, + int width, int height, HuffEntry *he, int prediction) { - const uint8_t *osrc = src; PutBitContext pb; - int count; init_put_bits(&pb, dst, dst_size); @@ -455,41 +445,35 @@ static int encode_plane_slice(const uint8_t *src, uint8_t *dst, unsigned dst_siz for (int i = 0; i < width; i++) { const int idx = src[i]; const int len = he[idx].len; - if (put_bits_left(&pb) < len + 32) - return encode_plane_slice_raw(osrc, dst, dst_size, width, height, prediction); put_bits(&pb, len, he[idx].code); } src += width; } - count = put_bits_count(&pb) & 0x1F; - - if (count) - put_bits(&pb, 32 - count, 0); - flush_put_bits(&pb); - - return put_bytes_output(&pb); + av_assert1(put_bytes_left(&pb, 0) <= 3); } static int encode_slice(AVCodecContext *avctx, void *tdata, int n, int threadnr) { MagicYUVContext *s = avctx->priv_data; - const int slice_height = s->slice_height; - const int last_height = FFMIN(slice_height, avctx->height - n * slice_height); - const int height = (n < (s->nb_slices - 1)) ? slice_height : last_height; for (int i = 0; i < s->planes; i++) { Slice *sl = &s->slices[n * s->planes + i]; - sl->size = + // Zero the padding now + AV_WN32(sl->dst + sl->size - 4, 0); + + if (sl->encode_raw) + encode_plane_slice_raw(sl->slice, sl->dst, + sl->width, sl->height, s->frame_pred); + else encode_plane_slice(sl->slice, - sl->bitslice, - s->bitslice_size, - AV_CEIL_RSHIFT(avctx->width, s->hshift[i]), - AV_CEIL_RSHIFT(height, s->vshift[i]), + sl->dst, + sl->size, + sl->width, sl->height, s->he[i], s->frame_pred); } @@ -545,8 +529,7 @@ static int predict_slice(AVCodecContext *avctx, void *tdata, s->predict(s, frame->data[i] + n * (slice_height >> s->vshift[i]) * frame->linesize[i], sl->slice, frame->linesize[i], - AV_CEIL_RSHIFT(frame->width, s->hshift[i]), - AV_CEIL_RSHIFT(height, s->vshift[i])); + sl->width, sl->height); } } @@ -560,86 +543,79 @@ static int magy_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet) { MagicYUVContext *s = avctx->priv_data; - const int width = avctx->width, height = avctx->height; - const int slice_height = s->slice_height; - unsigned tables_size; - PutBitContext pbit; PutByteContext pb; - int pos, ret = 0; + int header_size = 32 + (4 + 1) * (s->planes * s->nb_slices + 1) + + 256 * s->planes /* Hufftables */; + int64_t pkt_size = header_size; + int ret; - ret = ff_alloc_packet(avctx, pkt, (256 + 4 * s->nb_slices + width * height) * - s->planes + 256); + avctx->execute2(avctx, predict_slice, (void *)frame, NULL, s->nb_slices); + + for (int i = 0; i < s->planes; i++) + generate_codes(avctx, s->he[i], i); + + for (int i = 0; i < s->nb_slices; ++i) { + for (int j = 0; j < s->planes; ++j) { + Slice *const sl = &s->slices[i * s->planes + j]; + int64_t size = 0; + + for (size_t k = 0; k < FF_ARRAY_ELEMS(sl->counts); ++k) + size += sl->counts[k] * s->he[j][k].len; + size = AV_CEIL_RSHIFT(size, 3); + sl->encode_raw = size >= sl->width * sl->height; + if (sl->encode_raw) + size = sl->width * sl->height; + sl->size = FFALIGN(size + 2, 4); + sl->pos = pkt_size; + pkt_size += sl->size; + } + } + + ret = ff_get_encode_buffer(avctx, pkt, pkt_size, 0); if (ret < 0) return ret; bytestream2_init_writer(&pb, pkt->data, pkt->size); - bytestream2_put_le32(&pb, MKTAG('M', 'A', 'G', 'Y')); - bytestream2_put_le32(&pb, 32); // header size - bytestream2_put_byte(&pb, 7); // version - bytestream2_put_byte(&pb, s->format); - bytestream2_put_byte(&pb, 12); // max huffman length - bytestream2_put_byte(&pb, 0); + bytestream2_put_le32u(&pb, MKTAG('M', 'A', 'G', 'Y')); + bytestream2_put_le32u(&pb, 32); // header size + bytestream2_put_byteu(&pb, 7); // version + bytestream2_put_byteu(&pb, s->format); + bytestream2_put_byteu(&pb, 12); // max huffman length + bytestream2_put_byteu(&pb, 0); - bytestream2_put_byte(&pb, 0); - bytestream2_put_byte(&pb, 0); - bytestream2_put_byte(&pb, 32); // coder type - bytestream2_put_byte(&pb, 0); + bytestream2_put_byteu(&pb, 0); + bytestream2_put_byteu(&pb, 0); + bytestream2_put_byteu(&pb, 32); // coder type + bytestream2_put_byteu(&pb, 0); - bytestream2_put_le32(&pb, avctx->width); - bytestream2_put_le32(&pb, avctx->height); - bytestream2_put_le32(&pb, avctx->width); - bytestream2_put_le32(&pb, slice_height); - bytestream2_put_le32(&pb, 0); + bytestream2_put_le32u(&pb, avctx->width); + bytestream2_put_le32u(&pb, avctx->height); + bytestream2_put_le32u(&pb, avctx->width); + bytestream2_put_le32u(&pb, s->slice_height); - for (int i = 0; i < s->planes; i++) { - bytestream2_put_le32(&pb, 0); - for (int j = 1; j < s->nb_slices; j++) - bytestream2_put_le32(&pb, 0); + // Slice position is relative to the current position (i.e. 32) + bytestream2_put_le32u(&pb, header_size - 32); + + for (int i = 0; i < s->planes; ++i) { + for (int j = 0; j < s->nb_slices; ++j) { + Slice *const sl = &s->slices[j * s->planes + i]; + bytestream2_put_le32u(&pb, sl->pos - 32); + sl->dst = pkt->data + sl->pos; + } } - bytestream2_put_byte(&pb, s->planes); + bytestream2_put_byteu(&pb, s->planes); for (int i = 0; i < s->planes; i++) { for (int n = 0; n < s->nb_slices; n++) - bytestream2_put_byte(&pb, n * s->planes + i); + bytestream2_put_byteu(&pb, n * s->planes + i); } - avctx->execute2(avctx, predict_slice, (void *)frame, NULL, s->nb_slices); - - init_put_bits(&pbit, pkt->data + bytestream2_tell_p(&pb), bytestream2_get_bytes_left_p(&pb)); - - for (int i = 0; i < s->planes; i++) - encode_table(avctx, &pbit, s->he[i], i); - - tables_size = put_bytes_count(&pbit, 1); - bytestream2_skip_p(&pb, tables_size); + for (int i = 0; i < s->planes; ++i) + output_codes(&pb, s->he[i]); avctx->execute2(avctx, encode_slice, NULL, NULL, s->nb_slices); - for (int n = 0; n < s->nb_slices; n++) { - for (int i = 0; i < s->planes; i++) { - Slice *sl = &s->slices[n * s->planes + i]; - - sl->pos = bytestream2_tell_p(&pb); - - bytestream2_put_buffer(&pb, sl->bitslice, sl->size); - } - } - - pos = bytestream2_tell_p(&pb); - bytestream2_seek_p(&pb, 32, SEEK_SET); - bytestream2_put_le32(&pb, s->slices[0].pos - 32); - for (int i = 0; i < s->planes; i++) { - for (int n = 0; n < s->nb_slices; n++) { - Slice *sl = &s->slices[n * s->planes + i]; - - bytestream2_put_le32(&pb, sl->pos - 32); - } - } - bytestream2_seek_p(&pb, pos, SEEK_SET); - - pkt->size = bytestream2_tell_p(&pb); - *got_packet = 1; return 0; @@ -649,13 +625,14 @@ static av_cold int magy_encode_close(AVCodecContext *avctx) { MagicYUVContext *s = avctx->priv_data; - for (int i = 0; i < s->planes * s->nb_slices && s->slices; i++) { - Slice *sl = &s->slices[i]; + if (s->slices) { + for (int i = 0; i < s->planes * s->nb_slices; i++) { + Slice *sl = &s->slices[i]; - av_freep(&sl->slice); - av_freep(&sl->bitslice); + av_freep(&sl->slice); + } + av_freep(&s->slices); } - av_freep(&s->slices); av_freep(&s->decorrelate_buf); return 0; @@ -691,11 +668,9 @@ const FFCodec ff_magicyuv_encoder = { .init = magy_encode_init, .close = magy_encode_close, FF_CODEC_ENCODE_CB(magy_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_YUV422P, - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_GRAY8, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, + AV_PIX_FMT_GRAY8), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/mathops.h b/libavcodec/mathops.h index 84a924f31..64431b8a1 100644 --- a/libavcodec/mathops.h +++ b/libavcodec/mathops.h @@ -32,8 +32,9 @@ extern const uint32_t ff_inverse[257]; extern const uint8_t ff_log2_run[41]; +EXTERN const uint32_t ff_square_tab[512]; extern const uint8_t ff_sqrt_tab[256]; -extern const uint8_t attribute_visibility_hidden ff_crop_tab[256 + 2 * MAX_NEG_CROP]; +EXTERN const uint8_t ff_crop_tab[256 + 2 * MAX_NEG_CROP]; extern const uint8_t ff_zigzag_direct[64]; extern const uint8_t ff_zigzag_scan[16+1]; @@ -43,6 +44,8 @@ extern const uint8_t ff_zigzag_scan[16+1]; # include "mips/mathops.h" #elif ARCH_PPC # include "ppc/mathops.h" +#elif ARCH_RISCV +# include "riscv/mathops.h" #elif ARCH_X86 # include "x86/mathops.h" #endif @@ -92,23 +95,24 @@ static av_always_inline unsigned UMULH(unsigned a, unsigned b){ #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) +static inline av_const int median3_c(int a, int b, int c) { - 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; - } + int max2, min2, m; + + if (a >= b) { + max2 = a; + min2 = b; + } else { + max2 = b; + min2 = a; } - return b; + m = (c >= max2) ? max2 : c; + + return (m >= min2) ? m : min2; } + +#ifndef mid_pred +#define mid_pred median3_c #endif #ifndef median4 diff --git a/libavcodec/mathtables.c b/libavcodec/mathtables.c index 8b0031eb0..9a25da496 100644 --- a/libavcodec/mathtables.c +++ b/libavcodec/mathtables.c @@ -20,8 +20,47 @@ #include +#include "config.h" #include "mathops.h" +#if CONFIG_ME_CMP || CONFIG_MPEGVIDEOENCDSP +/* (i - 256) * (i - 256) */ +const uint32_t ff_square_tab[512] = { + 65536, 65025, 64516, 64009, 63504, 63001, 62500, 62001, 61504, 61009, 60516, 60025, 59536, 59049, 58564, 58081, + 57600, 57121, 56644, 56169, 55696, 55225, 54756, 54289, 53824, 53361, 52900, 52441, 51984, 51529, 51076, 50625, + 50176, 49729, 49284, 48841, 48400, 47961, 47524, 47089, 46656, 46225, 45796, 45369, 44944, 44521, 44100, 43681, + 43264, 42849, 42436, 42025, 41616, 41209, 40804, 40401, 40000, 39601, 39204, 38809, 38416, 38025, 37636, 37249, + 36864, 36481, 36100, 35721, 35344, 34969, 34596, 34225, 33856, 33489, 33124, 32761, 32400, 32041, 31684, 31329, + 30976, 30625, 30276, 29929, 29584, 29241, 28900, 28561, 28224, 27889, 27556, 27225, 26896, 26569, 26244, 25921, + 25600, 25281, 24964, 24649, 24336, 24025, 23716, 23409, 23104, 22801, 22500, 22201, 21904, 21609, 21316, 21025, + 20736, 20449, 20164, 19881, 19600, 19321, 19044, 18769, 18496, 18225, 17956, 17689, 17424, 17161, 16900, 16641, + 16384, 16129, 15876, 15625, 15376, 15129, 14884, 14641, 14400, 14161, 13924, 13689, 13456, 13225, 12996, 12769, + 12544, 12321, 12100, 11881, 11664, 11449, 11236, 11025, 10816, 10609, 10404, 10201, 10000, 9801, 9604, 9409, + 9216, 9025, 8836, 8649, 8464, 8281, 8100, 7921, 7744, 7569, 7396, 7225, 7056, 6889, 6724, 6561, + 6400, 6241, 6084, 5929, 5776, 5625, 5476, 5329, 5184, 5041, 4900, 4761, 4624, 4489, 4356, 4225, + 4096, 3969, 3844, 3721, 3600, 3481, 3364, 3249, 3136, 3025, 2916, 2809, 2704, 2601, 2500, 2401, + 2304, 2209, 2116, 2025, 1936, 1849, 1764, 1681, 1600, 1521, 1444, 1369, 1296, 1225, 1156, 1089, + 1024, 961, 900, 841, 784, 729, 676, 625, 576, 529, 484, 441, 400, 361, 324, 289, + 256, 225, 196, 169, 144, 121, 100, 81, 64, 49, 36, 25, 16, 9, 4, 1, + 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, + 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, + 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, + 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, + 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, + 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, + 9216, 9409, 9604, 9801, 10000, 10201, 10404, 10609, 10816, 11025, 11236, 11449, 11664, 11881, 12100, 12321, + 12544, 12769, 12996, 13225, 13456, 13689, 13924, 14161, 14400, 14641, 14884, 15129, 15376, 15625, 15876, 16129, + 16384, 16641, 16900, 17161, 17424, 17689, 17956, 18225, 18496, 18769, 19044, 19321, 19600, 19881, 20164, 20449, + 20736, 21025, 21316, 21609, 21904, 22201, 22500, 22801, 23104, 23409, 23716, 24025, 24336, 24649, 24964, 25281, + 25600, 25921, 26244, 26569, 26896, 27225, 27556, 27889, 28224, 28561, 28900, 29241, 29584, 29929, 30276, 30625, + 30976, 31329, 31684, 32041, 32400, 32761, 33124, 33489, 33856, 34225, 34596, 34969, 35344, 35721, 36100, 36481, + 36864, 37249, 37636, 38025, 38416, 38809, 39204, 39601, 40000, 40401, 40804, 41209, 41616, 42025, 42436, 42849, + 43264, 43681, 44100, 44521, 44944, 45369, 45796, 46225, 46656, 47089, 47524, 47961, 48400, 48841, 49284, 49729, + 50176, 50625, 51076, 51529, 51984, 52441, 52900, 53361, 53824, 54289, 54756, 55225, 55696, 56169, 56644, 57121, + 57600, 58081, 58564, 59049, 59536, 60025, 60516, 61009, 61504, 62001, 62500, 63001, 63504, 64009, 64516, 65025, +}; +#endif + /* a*inverse[b]>>32 == a/b for all 0<=a<=16909558 && 2<=b<=256 * for a>16909558, is an overestimate by less than 1 part in 1<<24 */ const uint32_t ff_inverse[257]={ @@ -72,10 +111,10 @@ const uint8_t ff_sqrt_tab[256]={ }; #define times4(x) x, x, x, x -#define times256(x) times4(times4(times4(times4(times4(x))))) +#define times1024(x) times4(times4(times4(times4(times4(x))))) const uint8_t ff_crop_tab[256 + 2 * MAX_NEG_CROP] = { -times256(0x00), +times1024(0x00), 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, @@ -92,7 +131,7 @@ times256(0x00), 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, -times256(0xFF) +times1024(0xFF) }; const uint8_t ff_zigzag_direct[64] = { diff --git a/libavcodec/mdec.c b/libavcodec/mdec.c index e25af404b..6ea64a8a3 100644 --- a/libavcodec/mdec.c +++ b/libavcodec/mdec.c @@ -56,7 +56,6 @@ typedef struct MDECContext { DECLARE_ALIGNED(16, uint16_t, quant_matrix)[64]; uint8_t *bitstream_buffer; unsigned int bitstream_buffer_size; - int block_last_index[6]; } MDECContext; //very similar to MPEG-1 @@ -101,9 +100,10 @@ static inline int mdec_decode_block_intra(MDECContext *a, int16_t *block, int n) LAST_SKIP_BITS(re, &a->gb, 1); } else { /* escape */ - run = SHOW_UBITS(re, &a->gb, 6)+1; LAST_SKIP_BITS(re, &a->gb, 6); - UPDATE_CACHE(re, &a->gb); - level = SHOW_SBITS(re, &a->gb, 10); SKIP_BITS(re, &a->gb, 10); + run = SHOW_UBITS(re, &a->gb, 6) + 1; + SKIP_BITS(re, &a->gb, 6); + level = SHOW_SBITS(re, &a->gb, 10); + LAST_SKIP_BITS(re, &a->gb, 10); i += run; if (i > 63) { av_log(a->avctx, AV_LOG_ERROR, @@ -126,7 +126,6 @@ static inline int mdec_decode_block_intra(MDECContext *a, int16_t *block, int n) } CLOSE_READER(re, &a->gb); } - a->block_last_index[n] = i; return 0; } diff --git a/libavcodec/me_cmp.c b/libavcodec/me_cmp.c index f3e2f2482..09861e207 100644 --- a/libavcodec/me_cmp.c +++ b/libavcodec/me_cmp.c @@ -27,49 +27,14 @@ #include "libavutil/mem_internal.h" #include "avcodec.h" #include "copy_block.h" +#include "mathops.h" #include "simple_idct.h" #include "me_cmp.h" #include "mpegvideoenc.h" #include "config.h" #include "config_components.h" -/* (i - 256) * (i - 256) */ -const uint32_t ff_square_tab[512] = { - 65536, 65025, 64516, 64009, 63504, 63001, 62500, 62001, 61504, 61009, 60516, 60025, 59536, 59049, 58564, 58081, - 57600, 57121, 56644, 56169, 55696, 55225, 54756, 54289, 53824, 53361, 52900, 52441, 51984, 51529, 51076, 50625, - 50176, 49729, 49284, 48841, 48400, 47961, 47524, 47089, 46656, 46225, 45796, 45369, 44944, 44521, 44100, 43681, - 43264, 42849, 42436, 42025, 41616, 41209, 40804, 40401, 40000, 39601, 39204, 38809, 38416, 38025, 37636, 37249, - 36864, 36481, 36100, 35721, 35344, 34969, 34596, 34225, 33856, 33489, 33124, 32761, 32400, 32041, 31684, 31329, - 30976, 30625, 30276, 29929, 29584, 29241, 28900, 28561, 28224, 27889, 27556, 27225, 26896, 26569, 26244, 25921, - 25600, 25281, 24964, 24649, 24336, 24025, 23716, 23409, 23104, 22801, 22500, 22201, 21904, 21609, 21316, 21025, - 20736, 20449, 20164, 19881, 19600, 19321, 19044, 18769, 18496, 18225, 17956, 17689, 17424, 17161, 16900, 16641, - 16384, 16129, 15876, 15625, 15376, 15129, 14884, 14641, 14400, 14161, 13924, 13689, 13456, 13225, 12996, 12769, - 12544, 12321, 12100, 11881, 11664, 11449, 11236, 11025, 10816, 10609, 10404, 10201, 10000, 9801, 9604, 9409, - 9216, 9025, 8836, 8649, 8464, 8281, 8100, 7921, 7744, 7569, 7396, 7225, 7056, 6889, 6724, 6561, - 6400, 6241, 6084, 5929, 5776, 5625, 5476, 5329, 5184, 5041, 4900, 4761, 4624, 4489, 4356, 4225, - 4096, 3969, 3844, 3721, 3600, 3481, 3364, 3249, 3136, 3025, 2916, 2809, 2704, 2601, 2500, 2401, - 2304, 2209, 2116, 2025, 1936, 1849, 1764, 1681, 1600, 1521, 1444, 1369, 1296, 1225, 1156, 1089, - 1024, 961, 900, 841, 784, 729, 676, 625, 576, 529, 484, 441, 400, 361, 324, 289, - 256, 225, 196, 169, 144, 121, 100, 81, 64, 49, 36, 25, 16, 9, 4, 1, - 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, - 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, - 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, - 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, - 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, - 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, - 9216, 9409, 9604, 9801, 10000, 10201, 10404, 10609, 10816, 11025, 11236, 11449, 11664, 11881, 12100, 12321, - 12544, 12769, 12996, 13225, 13456, 13689, 13924, 14161, 14400, 14641, 14884, 15129, 15376, 15625, 15876, 16129, - 16384, 16641, 16900, 17161, 17424, 17689, 17956, 18225, 18496, 18769, 19044, 19321, 19600, 19881, 20164, 20449, - 20736, 21025, 21316, 21609, 21904, 22201, 22500, 22801, 23104, 23409, 23716, 24025, 24336, 24649, 24964, 25281, - 25600, 25921, 26244, 26569, 26896, 27225, 27556, 27889, 28224, 28561, 28900, 29241, 29584, 29929, 30276, 30625, - 30976, 31329, 31684, 32041, 32400, 32761, 33124, 33489, 33856, 34225, 34596, 34969, 35344, 35721, 36100, 36481, - 36864, 37249, 37636, 38025, 38416, 38809, 39204, 39601, 40000, 40401, 40804, 41209, 41616, 42025, 42436, 42849, - 43264, 43681, 44100, 44521, 44944, 45369, 45796, 46225, 46656, 47089, 47524, 47961, 48400, 48841, 49284, 49729, - 50176, 50625, 51076, 51529, 51984, 52441, 52900, 53361, 53824, 54289, 54756, 55225, 55696, 56169, 56644, 57121, - 57600, 58081, 58564, 59049, 59536, 60025, 60516, 61009, 61504, 62001, 62500, 63001, 63504, 64009, 64516, 65025, -}; - -static int sse4_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sse4_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -86,7 +51,7 @@ static int sse4_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, return s; } -static int sse8_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sse8_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -107,7 +72,7 @@ static int sse8_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, return s; } -static int sse16_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sse16_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -149,7 +114,7 @@ static int sum_abs_dctelem_c(const int16_t *block) #define avg2(a, b) (((a) + (b) + 1) >> 1) #define avg4(a, b, c, d) (((a) + (b) + (c) + (d) + 2) >> 2) -static inline int pix_abs16_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static inline int pix_abs16_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -177,7 +142,7 @@ static inline int pix_abs16_c(MpegEncContext *v, const uint8_t *pix1, const uint return s; } -static inline int pix_median_abs16_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static inline int pix_median_abs16_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i, j; @@ -216,7 +181,7 @@ static inline int pix_median_abs16_c(MpegEncContext *v, const uint8_t *pix1, con return s; } -static int pix_abs16_x2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs16_x2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -244,7 +209,7 @@ static int pix_abs16_x2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t return s; } -static int pix_abs16_y2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs16_y2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -274,7 +239,7 @@ static int pix_abs16_y2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t return s; } -static int pix_abs16_xy2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs16_xy2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -304,7 +269,7 @@ static int pix_abs16_xy2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t return s; } -static inline int pix_abs8_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static inline int pix_abs8_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -324,7 +289,7 @@ static inline int pix_abs8_c(MpegEncContext *v, const uint8_t *pix1, const uint8 return s; } -static inline int pix_median_abs8_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static inline int pix_median_abs8_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i, j; @@ -355,7 +320,7 @@ static inline int pix_median_abs8_c(MpegEncContext *v, const uint8_t *pix1, cons return s; } -static int pix_abs8_x2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs8_x2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -375,7 +340,7 @@ static int pix_abs8_x2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t * return s; } -static int pix_abs8_y2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs8_y2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -397,7 +362,7 @@ static int pix_abs8_y2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t * return s; } -static int pix_abs8_xy2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs8_xy2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -419,7 +384,7 @@ static int pix_abs8_xy2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t return s; } -static int nsse16_c(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +static int nsse16_c(MPVEncContext *const c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { int score1 = 0, score2 = 0, x, y; @@ -439,12 +404,12 @@ static int nsse16_c(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, } if (c) - return score1 + FFABS(score2) * c->avctx->nsse_weight; + return score1 + FFABS(score2) * c->c.avctx->nsse_weight; else return score1 + FFABS(score2) * 8; } -static int nsse8_c(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +static int nsse8_c(MPVEncContext *const c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { int score1 = 0, score2 = 0, x, y; @@ -464,12 +429,12 @@ static int nsse8_c(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, } if (c) - return score1 + FFABS(score2) * c->avctx->nsse_weight; + return score1 + FFABS(score2) * c->c.avctx->nsse_weight; else return score1 + FFABS(score2) * 8; } -static int zero_cmp(MpegEncContext *s, const uint8_t *a, const uint8_t *b, +static int zero_cmp(MPVEncContext *s, const uint8_t *a, const uint8_t *b, ptrdiff_t stride, int h) { return 0; @@ -546,7 +511,7 @@ av_cold int ff_set_cmp(const MECmpContext *c, me_cmp_func *cmp, int type, int mp #define BUTTERFLYA(x, y) (FFABS((x) + (y)) + FFABS((x) - (y))) -static int hadamard8_diff8x8_c(MpegEncContext *s, const uint8_t *dst, +static int hadamard8_diff8x8_c(MPVEncContext *unused, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) { int i, temp[64], sum = 0; @@ -596,7 +561,7 @@ static int hadamard8_diff8x8_c(MpegEncContext *s, const uint8_t *dst, return sum; } -static int hadamard8_intra8x8_c(MpegEncContext *s, const uint8_t *src, +static int hadamard8_intra8x8_c(MPVEncContext *unused, const uint8_t *src, const uint8_t *dummy, ptrdiff_t stride, int h) { int i, temp[64], sum = 0; @@ -646,7 +611,7 @@ static int hadamard8_intra8x8_c(MpegEncContext *s, const uint8_t *src, return sum; } -static int dct_sad8x8_c(MpegEncContext *s, const uint8_t *src1, +static int dct_sad8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { LOCAL_ALIGNED_16(int16_t, temp, [64]); @@ -685,7 +650,7 @@ static int dct_sad8x8_c(MpegEncContext *s, const uint8_t *src1, DST(7, (a4 >> 2) - a7); \ } -static int dct264_sad8x8_c(MpegEncContext *s, const uint8_t *src1, +static int dct264_sad8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { int16_t dct[8][8]; @@ -710,7 +675,7 @@ static int dct264_sad8x8_c(MpegEncContext *s, const uint8_t *src1, } #endif -static int dct_max8x8_c(MpegEncContext *s, const uint8_t *src1, +static int dct_max8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { LOCAL_ALIGNED_16(int16_t, temp, [64]); @@ -725,22 +690,22 @@ static int dct_max8x8_c(MpegEncContext *s, const uint8_t *src1, return sum; } -static int quant_psnr8x8_c(MpegEncContext *s, const uint8_t *src1, +static int quant_psnr8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { LOCAL_ALIGNED_16(int16_t, temp, [64 * 2]); int16_t *const bak = temp + 64; int sum = 0, i; - s->mb_intra = 0; + s->c.mb_intra = 0; s->pdsp.diff_pixels_unaligned(temp, src1, src2, stride); memcpy(bak, temp, 64 * sizeof(int16_t)); - s->block_last_index[0 /* FIXME */] = - s->dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); - s->dct_unquantize_inter(s, temp, 0, s->qscale); + s->c.block_last_index[0 /* FIXME */] = + s->dct_quantize(s, temp, 0 /* FIXME */, s->c.qscale, &i); + s->c.dct_unquantize_inter(&s->c, temp, 0, s->c.qscale); ff_simple_idct_int16_8bit(temp); // FIXME for (i = 0; i < 64; i++) @@ -749,29 +714,29 @@ static int quant_psnr8x8_c(MpegEncContext *s, const uint8_t *src1, return sum; } -static int rd8x8_c(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, +static int rd8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { - const uint8_t *scantable = s->intra_scantable.permutated; + const uint8_t *scantable = s->c.intra_scantable.permutated; LOCAL_ALIGNED_16(int16_t, temp, [64]); LOCAL_ALIGNED_16(uint8_t, lsrc1, [64]); LOCAL_ALIGNED_16(uint8_t, lsrc2, [64]); int i, last, run, bits, level, distortion, start_i; const int esc_length = s->ac_esc_length; - uint8_t *length, *last_length; + const uint8_t *length, *last_length; copy_block8(lsrc1, src1, 8, stride, 8); copy_block8(lsrc2, src2, 8, stride, 8); s->pdsp.diff_pixels(temp, lsrc1, lsrc2, 8); - s->block_last_index[0 /* FIXME */] = + s->c.block_last_index[0 /* FIXME */] = last = - s->dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); + s->dct_quantize(s, temp, 0 /* FIXME */, s->c.qscale, &i); bits = 0; - if (s->mb_intra) { + if (s->c.mb_intra) { start_i = 1; length = s->intra_ac_vlc_length; last_length = s->intra_ac_vlc_last_length; @@ -811,37 +776,37 @@ static int rd8x8_c(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, } if (last >= 0) { - if (s->mb_intra) - s->dct_unquantize_intra(s, temp, 0, s->qscale); + if (s->c.mb_intra) + s->c.dct_unquantize_intra(&s->c, temp, 0, s->c.qscale); else - s->dct_unquantize_inter(s, temp, 0, s->qscale); + s->c.dct_unquantize_inter(&s->c, temp, 0, s->c.qscale); } - s->idsp.idct_add(lsrc2, 8, temp); + s->c.idsp.idct_add(lsrc2, 8, temp); distortion = s->sse_cmp[1](NULL, lsrc2, lsrc1, 8, 8); - return distortion + ((bits * s->qscale * s->qscale * 109 + 64) >> 7); + return distortion + ((bits * s->c.qscale * s->c.qscale * 109 + 64) >> 7); } -static int bit8x8_c(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, +static int bit8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { - const uint8_t *scantable = s->intra_scantable.permutated; + const uint8_t *scantable = s->c.intra_scantable.permutated; LOCAL_ALIGNED_16(int16_t, temp, [64]); int i, last, run, bits, level, start_i; const int esc_length = s->ac_esc_length; - uint8_t *length, *last_length; + const uint8_t *length, *last_length; s->pdsp.diff_pixels_unaligned(temp, src1, src2, stride); - s->block_last_index[0 /* FIXME */] = + s->c.block_last_index[0 /* FIXME */] = last = - s->dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); + s->dct_quantize(s, temp, 0 /* FIXME */, s->c.qscale, &i); bits = 0; - if (s->mb_intra) { + if (s->c.mb_intra) { start_i = 1; length = s->intra_ac_vlc_length; last_length = s->intra_ac_vlc_last_length; @@ -884,7 +849,7 @@ static int bit8x8_c(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, } #define VSAD_INTRA(size) \ -static int vsad_intra ## size ## _c(MpegEncContext *c, \ +static int vsad_intra ## size ## _c(MPVEncContext *unused, \ const uint8_t *s, const uint8_t *dummy, \ ptrdiff_t stride, int h) \ { \ @@ -906,7 +871,7 @@ VSAD_INTRA(8) VSAD_INTRA(16) #define VSAD(size) \ -static int vsad ## size ## _c(MpegEncContext *c, \ +static int vsad ## size ## _c(MPVEncContext *unused, \ const uint8_t *s1, const uint8_t *s2, \ ptrdiff_t stride, int h) \ { \ @@ -926,7 +891,7 @@ VSAD(16) #define SQ(a) ((a) * (a)) #define VSSE_INTRA(size) \ -static int vsse_intra ## size ## _c(MpegEncContext *c, \ +static int vsse_intra ## size ## _c(MPVEncContext *unused, \ const uint8_t *s, const uint8_t *dummy, \ ptrdiff_t stride, int h) \ { \ @@ -948,8 +913,8 @@ VSSE_INTRA(8) VSSE_INTRA(16) #define VSSE(size) \ -static int vsse ## size ## _c(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, \ - ptrdiff_t stride, int h) \ +static int vsse ## size ## _c(MPVEncContext *unused, const uint8_t *s1, \ + const uint8_t *s2, ptrdiff_t stride, int h) \ { \ int score = 0, x, y; \ \ @@ -966,8 +931,8 @@ VSSE(8) VSSE(16) #define WRAPPER8_16_SQ(name8, name16) \ -static int name16(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, \ - ptrdiff_t stride, int h) \ +static int name16(MPVEncContext *const s, const uint8_t *dst, \ + const uint8_t *src, ptrdiff_t stride, int h) \ { \ int score = 0; \ \ @@ -1054,7 +1019,7 @@ av_cold void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx) ff_me_cmp_init_ppc(c, avctx); #elif ARCH_RISCV ff_me_cmp_init_riscv(c, avctx); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_me_cmp_init_x86(c, avctx); #elif ARCH_MIPS ff_me_cmp_init_mips(c, avctx); diff --git a/libavcodec/me_cmp.h b/libavcodec/me_cmp.h index 9053327c4..49f81e190 100644 --- a/libavcodec/me_cmp.h +++ b/libavcodec/me_cmp.h @@ -21,13 +21,8 @@ #include -#include "libavutil/attributes_internal.h" - #include "avcodec.h" -extern const uint32_t attribute_visibility_hidden ff_square_tab[512]; - - /* minimum alignment rules ;) * If you notice errors in the align stuff, need more alignment for some ASM code * for some CPU or need to use a function with less aligned data then send a mail @@ -41,13 +36,13 @@ extern const uint32_t attribute_visibility_hidden ff_square_tab[512]; * !future video codecs might need functions with less strict alignment */ -struct MpegEncContext; +typedef struct MPVEncContext MPVEncContext; /* Motion estimation: * h is limited to { width / 2, width, 2 * width }, * but never larger than 16 and never smaller than 2. * Although currently h < 4 is not used as functions with * width < 8 are neither used nor implemented. */ -typedef int (*me_cmp_func)(struct MpegEncContext *c, +typedef int (*me_cmp_func)(MPVEncContext *c, const uint8_t *blk1 /* align width (8 or 16) */, const uint8_t *blk2 /* align 1 */, ptrdiff_t stride, int h); @@ -76,7 +71,6 @@ typedef struct MECmpContext { void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx); void ff_me_cmp_init_aarch64(MECmpContext *c, AVCodecContext *avctx); -void ff_me_cmp_init_alpha(MECmpContext *c, AVCodecContext *avctx); void ff_me_cmp_init_arm(MECmpContext *c, AVCodecContext *avctx); void ff_me_cmp_init_ppc(MECmpContext *c, AVCodecContext *avctx); void ff_me_cmp_init_riscv(MECmpContext *c, AVCodecContext *avctx); @@ -87,7 +81,7 @@ void ff_me_cmp_init_mips(MECmpContext *c, AVCodecContext *avctx); * Fill the function pointer array cmp[6] with me_cmp_funcs from * c based upon type. If mpvenc is not set, an error is returned * if the type of comparison functions requires an initialized - * MpegEncContext. + * MPVEncContext. */ int ff_set_cmp(const MECmpContext *c, me_cmp_func *cmp, int type, int mpvenc); diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c index 96c886666..283bbe72d 100644 --- a/libavcodec/mediacodec_wrapper.c +++ b/libavcodec/mediacodec_wrapper.c @@ -1762,6 +1762,14 @@ static int mediacodec_jni_signalEndOfInputStream(FFAMediaCodec *ctx) return 0; } +static int mediacodec_jni_setAsyncNotifyCallback(FFAMediaCodec *codec, + const FFAMediaCodecOnAsyncNotifyCallback *callback, + void *userdata) +{ + av_log(codec, AV_LOG_ERROR, "Doesn't support aync mode with JNI, please try ndk_codec=1\n"); + return AVERROR(ENOSYS); +} + static const FFAMediaFormat media_format_jni = { .class = &amediaformat_class, @@ -1821,6 +1829,7 @@ static const FFAMediaCodec media_codec_jni = { .getConfigureFlagEncode = mediacodec_jni_getConfigureFlagEncode, .cleanOutputBuffers = mediacodec_jni_cleanOutputBuffers, .signalEndOfInputStream = mediacodec_jni_signalEndOfInputStream, + .setAsyncNotifyCallback = mediacodec_jni_setAsyncNotifyCallback, }; typedef struct FFAMediaFormatNdk { @@ -1842,6 +1851,9 @@ typedef struct FFAMediaCodecNdk { AMediaCodec *impl; ANativeWindow *window; + FFAMediaCodecOnAsyncNotifyCallback async_cb; + void *async_userdata; + // Available since API level 28. media_status_t (*getName)(AMediaCodec*, char** out_name); void (*releaseName)(AMediaCodec*, char* name); @@ -1849,6 +1861,8 @@ typedef struct FFAMediaCodecNdk { // Available since API level 26. media_status_t (*setInputSurface)(AMediaCodec*, ANativeWindow *); media_status_t (*signalEndOfInputStream)(AMediaCodec *); + media_status_t (*setAsyncNotifyCallback)(AMediaCodec *, + struct AMediaCodecOnAsyncNotifyCallback callback, void *userdata); } FFAMediaCodecNdk; static const FFAMediaFormat media_format_ndk; @@ -1866,6 +1880,32 @@ static const AVClass amediacodec_ndk_class = { .version = LIBAVUTIL_VERSION_INT, }; +static int media_status_to_error(media_status_t status) +{ + switch (status) { + case AMEDIA_OK: + return 0; + case AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE: + return AVERROR(ENOMEM); + case AMEDIA_ERROR_MALFORMED: + return AVERROR_INVALIDDATA; + case AMEDIA_ERROR_UNSUPPORTED: + return AVERROR(ENOTSUP); + case AMEDIA_ERROR_INVALID_PARAMETER: + return AVERROR(EINVAL); + case AMEDIA_ERROR_INVALID_OPERATION: + return AVERROR(EOPNOTSUPP); + case AMEDIA_ERROR_END_OF_STREAM: + return AVERROR_EOF; + case AMEDIA_ERROR_IO: + return AVERROR(EIO); + case AMEDIA_ERROR_WOULD_BLOCK: + return AVERROR(EWOULDBLOCK); + default: + return AVERROR_EXTERNAL; + } +} + static FFAMediaFormat *mediaformat_ndk_create(AMediaFormat *impl) { FFAMediaFormatNdk *format = av_mallocz(sizeof(*format)); @@ -2060,6 +2100,7 @@ static inline FFAMediaCodec *ndk_codec_create(int method, const char *arg) { GET_SYMBOL(setInputSurface) GET_SYMBOL(signalEndOfInputStream) + GET_SYMBOL(setAsyncNotifyCallback) #undef GET_SYMBOL @@ -2335,6 +2376,94 @@ static int mediacodec_ndk_signalEndOfInputStream(FFAMediaCodec *ctx) return 0; } +static void mediacodec_ndk_onInputAvailable(AMediaCodec *impl, void *userdata, + int32_t index) +{ + FFAMediaCodecNdk *codec = userdata; + codec->async_cb.onAsyncInputAvailable((FFAMediaCodec *) codec, + codec->async_userdata, index); +} + +static void mediacodec_ndk_onOutputAvailable(AMediaCodec *impl, + void *userdata, + int32_t index, + AMediaCodecBufferInfo *buffer_info) +{ + FFAMediaCodecNdk *codec = userdata; + FFAMediaCodecBufferInfo info = { + .offset = buffer_info->offset, + .size = buffer_info->size, + .presentationTimeUs = buffer_info->presentationTimeUs, + .flags = buffer_info->flags, + }; + + codec->async_cb.onAsyncOutputAvailable(&codec->api, codec->async_userdata, + index, &info); +} + +static void mediacodec_ndk_onFormatChanged(AMediaCodec *impl, void *userdata, + AMediaFormat *format) +{ + FFAMediaCodecNdk *codec = userdata; + FFAMediaFormat *media_format = mediaformat_ndk_create(format); + if (!media_format) + return; + + codec->async_cb.onAsyncFormatChanged(&codec->api, codec->async_userdata, + media_format); + ff_AMediaFormat_delete(media_format); +} + +static void mediacodec_ndk_onError(AMediaCodec *impl, void *userdata, + media_status_t status, + int32_t actionCode, + const char *detail) +{ + FFAMediaCodecNdk *codec = userdata; + int error = media_status_to_error(status); + + codec->async_cb.onAsyncError(&codec->api, codec->async_userdata, error, + detail); +} + +static int mediacodec_ndk_setAsyncNotifyCallback(FFAMediaCodec *ctx, + const FFAMediaCodecOnAsyncNotifyCallback *callback, + void *userdata) +{ + FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx; + struct AMediaCodecOnAsyncNotifyCallback cb = { + .onAsyncInputAvailable = mediacodec_ndk_onInputAvailable, + .onAsyncOutputAvailable = mediacodec_ndk_onOutputAvailable, + .onAsyncFormatChanged = mediacodec_ndk_onFormatChanged, + .onAsyncError = mediacodec_ndk_onError, + }; + media_status_t status; + + if (!codec->setAsyncNotifyCallback) { + av_log(codec, AV_LOG_ERROR, "setAsyncNotifyCallback unavailable\n"); + return AVERROR(ENOSYS); + } + + if (!callback || + !callback->onAsyncInputAvailable || + !callback->onAsyncOutputAvailable || + !callback->onAsyncFormatChanged || + !callback->onAsyncError) + return AVERROR(EINVAL); + + codec->async_cb = *callback; + codec->async_userdata = userdata; + + status = codec->setAsyncNotifyCallback(codec->impl, cb, codec); + if (status != AMEDIA_OK) { + av_log(codec, AV_LOG_ERROR, "setAsyncNotifyCallback failed, %d\n", + status); + return AVERROR_EXTERNAL; + } + + return 0; +} + static const FFAMediaFormat media_format_ndk = { .class = &amediaformat_ndk_class, @@ -2396,6 +2525,7 @@ static const FFAMediaCodec media_codec_ndk = { .getConfigureFlagEncode = mediacodec_ndk_getConfigureFlagEncode, .cleanOutputBuffers = mediacodec_ndk_cleanOutputBuffers, .signalEndOfInputStream = mediacodec_ndk_signalEndOfInputStream, + .setAsyncNotifyCallback = mediacodec_ndk_setAsyncNotifyCallback, }; FFAMediaFormat *ff_AMediaFormat_new(int ndk) diff --git a/libavcodec/mediacodec_wrapper.h b/libavcodec/mediacodec_wrapper.h index 11a426049..18d079644 100644 --- a/libavcodec/mediacodec_wrapper.h +++ b/libavcodec/mediacodec_wrapper.h @@ -178,6 +178,22 @@ struct FFAMediaCodecBufferInfo { typedef struct FFAMediaCodecBufferInfo FFAMediaCodecBufferInfo; typedef struct FFAMediaCodec FFAMediaCodec; + +typedef struct FFAMediaCodecOnAsyncNotifyCallback { + void (*onAsyncInputAvailable)(FFAMediaCodec *codec, void *userdata, + int32_t index); + + void (*onAsyncOutputAvailable)(FFAMediaCodec *codec, void *userdata, + int32_t index, + FFAMediaCodecBufferInfo *buffer_info); + + void (*onAsyncFormatChanged)(FFAMediaCodec *codec, void *userdata, + FFAMediaFormat *format); + + void (*onAsyncError)(FFAMediaCodec *codec, void *userdata, int error, + const char *detail); +} FFAMediaCodecOnAsyncNotifyCallback; + struct FFAMediaCodec { const AVClass *class; @@ -219,6 +235,11 @@ struct FFAMediaCodec { // For encoder with FFANativeWindow as input. int (*signalEndOfInputStream)(FFAMediaCodec *); + + // Introduced in Android API 28 + int (*setAsyncNotifyCallback)(FFAMediaCodec *codec, + const FFAMediaCodecOnAsyncNotifyCallback *callback, + void *userdata); }; static inline char *ff_AMediaCodec_getName(FFAMediaCodec *codec) @@ -343,6 +364,13 @@ static inline int ff_AMediaCodec_signalEndOfInputStream(FFAMediaCodec *codec) return codec->signalEndOfInputStream(codec); } +static inline int ff_AMediaCodec_setAsyncNotifyCallback(FFAMediaCodec *codec, + const FFAMediaCodecOnAsyncNotifyCallback *callback, + void *userdata) +{ + return codec->setAsyncNotifyCallback(codec, callback, userdata); +} + int ff_Build_SDK_INT(AVCodecContext *avctx); enum FFAMediaFormatColorRange { diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c index cc55b306b..ea9362ba8 100644 --- a/libavcodec/mediacodecdec.c +++ b/libavcodec/mediacodecdec.c @@ -57,6 +57,8 @@ typedef struct MediaCodecH264DecContext { int amlogic_mpeg2_api23_workaround; int use_ndk_codec; + // Ref. MediaFormat KEY_OPERATING_RATE + int operating_rate; } MediaCodecH264DecContext; static av_cold int mediacodec_decode_close(AVCodecContext *avctx) @@ -131,14 +133,12 @@ static int h264_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) int i; int ret; - H264ParamSets ps; + H264ParamSets ps = {0}; const PPS *pps = NULL; const SPS *sps = NULL; int is_avc = 0; int nal_length_size = 0; - memset(&ps, 0, sizeof(ps)); - ret = ff_h264_decode_extradata(avctx->extradata, avctx->extradata_size, &ps, &is_avc, &nal_length_size, 0, avctx); if (ret < 0) { @@ -197,8 +197,8 @@ static int hevc_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) int i; int ret; - HEVCParamSets ps; - HEVCSEI sei; + HEVCParamSets ps = {0}; + HEVCSEI sei = {0}; const HEVCVPS *vps = NULL; const HEVCPPS *pps = NULL; @@ -213,9 +213,6 @@ static int hevc_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) int sps_data_size = 0; int pps_data_size = 0; - memset(&ps, 0, sizeof(ps)); - memset(&sei, 0, sizeof(sei)); - ret = ff_hevc_decode_extradata(avctx->extradata, avctx->extradata_size, &ps, &sei, &is_nalff, &nal_length_size, 0, 1, avctx); if (ret < 0) { @@ -441,6 +438,8 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) ff_AMediaFormat_setInt32(format, "channel-count", avctx->ch_layout.nb_channels); ff_AMediaFormat_setInt32(format, "sample-rate", avctx->sample_rate); } + if (s->operating_rate > 0) + ff_AMediaFormat_setInt32(format, "operating-rate", s->operating_rate); s->ctx = av_mallocz(sizeof(*s->ctx)); if (!s->ctx) { @@ -599,6 +598,8 @@ static const AVOption ff_mediacodec_vdec_options[] = { OFFSET(delay_flush), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VD }, { "ndk_codec", "Use MediaCodec from NDK", OFFSET(use_ndk_codec), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VD }, + { "operating_rate", "The desired operating rate that the codec will need to operate at, zero for unspecified", + OFFSET(operating_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, VD }, { NULL } }; @@ -662,6 +663,8 @@ DECLARE_MEDIACODEC_VDEC(av1, "AV1", AV_CODEC_ID_AV1, NULL) static const AVOption ff_mediacodec_adec_options[] = { { "ndk_codec", "Use MediaCodec from NDK", OFFSET(use_ndk_codec), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AD }, + { "operating_rate", "The desired operating rate that the codec will need to operate at, zero for unspecified", + OFFSET(operating_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AD }, { NULL } }; diff --git a/libavcodec/mediacodecdec_common.c b/libavcodec/mediacodecdec_common.c index 842a7d2bb..9b91c8edf 100644 --- a/libavcodec/mediacodecdec_common.c +++ b/libavcodec/mediacodecdec_common.c @@ -543,6 +543,8 @@ static int mediacodec_wrap_sw_buffer(AVCodecContext *avctx, av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", key, format); \ ret = AVERROR_EXTERNAL; \ goto fail; \ + } else { \ + (name) = 0; \ } \ } while (0) \ diff --git a/libavcodec/mediacodecenc.c b/libavcodec/mediacodecenc.c index e76ea8123..507c48df9 100644 --- a/libavcodec/mediacodecenc.c +++ b/libavcodec/mediacodecenc.c @@ -23,11 +23,13 @@ #include "config_components.h" #include "libavutil/avassert.h" +#include "libavutil/fifo.h" #include "libavutil/avstring.h" #include "libavutil/hwcontext_mediacodec.h" #include "libavutil/imgutils.h" #include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavutil/thread.h" #include "avcodec.h" #include "bsf.h" @@ -54,6 +56,11 @@ enum BitrateMode { BITRATE_MODE_CBR_FD = 3, }; +typedef struct MediaCodecAsyncOutput { + int32_t index; + FFAMediaCodecBufferInfo buf_info; +} MediaCodecAsyncOutput; + typedef struct MediaCodecEncContext { AVClass *avclass; FFAMediaCodec *codec; @@ -76,6 +83,25 @@ typedef struct MediaCodecEncContext { int level; int pts_as_dts; int extract_extradata; + // Ref. MediaFormat KEY_OPERATING_RATE + int operating_rate; + int async_mode; + + AVMutex input_mutex; + AVCond input_cond; + AVFifo *input_index; + + AVMutex output_mutex; + AVCond output_cond; + int encode_status; + AVFifo *async_output; + + int qp_i_min; + int qp_p_min; + int qp_b_min; + int qp_i_max; + int qp_p_max; + int qp_b_max; } MediaCodecEncContext; enum { @@ -100,17 +126,26 @@ static const enum AVPixelFormat avc_pix_fmts[] = { AV_PIX_FMT_NONE }; -static void mediacodec_output_format(AVCodecContext *avctx) +static void mediacodec_dump_format(AVCodecContext *avctx, + FFAMediaFormat *out_format) { MediaCodecEncContext *s = avctx->priv_data; - char *name = ff_AMediaCodec_getName(s->codec); - FFAMediaFormat *out_format = ff_AMediaCodec_getOutputFormat(s->codec); + const char *name = s->name; char *str = ff_AMediaFormat_toString(out_format); av_log(avctx, AV_LOG_DEBUG, "MediaCodec encoder %s output format %s\n", name ? name : "unknown", str); - av_free(name); av_free(str); +} + +static void mediacodec_output_format(AVCodecContext *avctx) +{ + MediaCodecEncContext *s = avctx->priv_data; + FFAMediaFormat *out_format = ff_AMediaCodec_getOutputFormat(s->codec); + + if (!s->name) + s->name = ff_AMediaCodec_getName(s->codec); + mediacodec_dump_format(avctx, out_format); ff_AMediaFormat_delete(out_format); } @@ -183,8 +218,179 @@ static int mediacodec_init_bsf(AVCodecContext *avctx) return ret; } +static void copy_frame_to_buffer(AVCodecContext *avctx, const AVFrame *frame, + uint8_t *dst, size_t size) +{ + MediaCodecEncContext *s = avctx->priv_data; + uint8_t *dst_data[4] = {}; + int dst_linesize[4] = {}; + + if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) { + dst_data[0] = dst; + dst_data[1] = dst + s->width * s->height; + dst_data[2] = dst_data[1] + s->width * s->height / 4; + + dst_linesize[0] = s->width; + dst_linesize[1] = dst_linesize[2] = s->width / 2; + } else if (avctx->pix_fmt == AV_PIX_FMT_NV12) { + dst_data[0] = dst; + dst_data[1] = dst + s->width * s->height; + + dst_linesize[0] = s->width; + dst_linesize[1] = s->width; + } else { + av_assert0(0); + } + + av_image_copy2(dst_data, dst_linesize, frame->data, frame->linesize, + avctx->pix_fmt, avctx->width, avctx->height); +} + + +static void on_error(FFAMediaCodec *codec, void *userdata, int error, + const char *detail) +{ + AVCodecContext *avctx = userdata; + MediaCodecEncContext *s = avctx->priv_data; + + if (error == AVERROR(EAGAIN)) + return; + + av_log(avctx, AV_LOG_ERROR, "On error, %s, %s\n", av_err2str(error), detail); + + ff_mutex_lock(&s->input_mutex); + ff_mutex_lock(&s->output_mutex); + s->encode_status = error; + ff_mutex_unlock(&s->output_mutex); + ff_mutex_unlock(&s->input_mutex); + + ff_cond_signal(&s->output_cond); + ff_cond_signal(&s->input_cond); +} + +static void on_input_available(FFAMediaCodec *codec, void *userdata, + int32_t index) +{ + AVCodecContext *avctx = userdata; + MediaCodecEncContext *s = avctx->priv_data; + int ret; + + ff_mutex_lock(&s->input_mutex); + ret = av_fifo_write(s->input_index, &index, 1); + if (ret >= 0) + ff_cond_signal(&s->input_cond); + ff_mutex_unlock(&s->input_mutex); + + if (ret < 0) + on_error(codec, userdata, ret, "av_fifo_write failed"); +} + +static void on_output_available(FFAMediaCodec *codec, void *userdata, + int32_t index, + FFAMediaCodecBufferInfo *out_info) +{ + AVCodecContext *avctx = userdata; + MediaCodecEncContext *s = avctx->priv_data; + MediaCodecAsyncOutput output = { + .index = index, + .buf_info = *out_info, + }; + int ret; + + ff_mutex_lock(&s->output_mutex); + ret = av_fifo_write(s->async_output, &output, 1); + if (ret >= 0) + ff_cond_signal(&s->output_cond); + ff_mutex_unlock(&s->output_mutex); + + if (ret < 0) + on_error(codec, userdata, ret, "av_fifo_write failed"); +} + +static void on_format_changed(FFAMediaCodec *codec, void *userdata, + FFAMediaFormat *format) +{ + mediacodec_dump_format(userdata, format); +} + +static int mediacodec_init_async_state(AVCodecContext *avctx) +{ + MediaCodecEncContext *s = avctx->priv_data; + size_t fifo_size = 16; + + if (!s->async_mode) + return 0; + + ff_mutex_init(&s->input_mutex, NULL); + ff_cond_init(&s->input_cond, NULL); + + ff_mutex_init(&s->output_mutex, NULL); + ff_cond_init(&s->output_cond, NULL); + + s->input_index = av_fifo_alloc2(fifo_size, sizeof(int32_t), AV_FIFO_FLAG_AUTO_GROW); + s->async_output = av_fifo_alloc2(fifo_size, sizeof(MediaCodecAsyncOutput), + AV_FIFO_FLAG_AUTO_GROW); + + if (!s->input_index || !s->async_output) + return AVERROR(ENOMEM); + + return 0; +} + +static void mediacodec_uninit_async_state(AVCodecContext *avctx) +{ + MediaCodecEncContext *s = avctx->priv_data; + + if (!s->async_mode) + return; + + ff_mutex_destroy(&s->input_mutex); + ff_cond_destroy(&s->input_cond); + + ff_mutex_destroy(&s->output_mutex); + ff_cond_destroy(&s->output_cond); + + av_fifo_freep2(&s->input_index); + av_fifo_freep2(&s->async_output); + + s->async_mode = 0; +} + static int mediacodec_generate_extradata(AVCodecContext *avctx); +static void mediacodec_set_qp_range(AVCodecContext *avctx, + FFAMediaFormat *format) +{ + MediaCodecEncContext *s = avctx->priv_data; + + // Handle common options in AVCodecContext first. + if (avctx->qmin >= 0) { + ff_AMediaFormat_setInt32(format, "video-qp-i-min", avctx->qmin); + ff_AMediaFormat_setInt32(format, "video-qp-p-min", avctx->qmin); + ff_AMediaFormat_setInt32(format, "video-qp-b-min", avctx->qmin); + } + + if (avctx->qmax >= 0) { + ff_AMediaFormat_setInt32(format, "video-qp-i-max", avctx->qmax); + ff_AMediaFormat_setInt32(format, "video-qp-p-max", avctx->qmax); + ff_AMediaFormat_setInt32(format, "video-qp-b-max", avctx->qmax); + } + + if (s->qp_i_min >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-i-min", s->qp_i_min); + if (s->qp_p_min >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-p-min", s->qp_p_min); + if (s->qp_b_min >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-b-min", s->qp_b_min); + + if (s->qp_i_max >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-i-max", s->qp_i_max); + if (s->qp_p_max >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-p-max", s->qp_p_max); + if (s->qp_b_max >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-b-max", s->qp_b_max); +} + static av_cold int mediacodec_init(AVCodecContext *avctx) { const char *codec_mime = NULL; @@ -193,6 +399,11 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) int ret; int gop; + // Init async state first, so we can do cleanup safely on error path. + ret = mediacodec_init_async_state(avctx); + if (ret < 0) + return ret; + if (s->use_ndk_codec < 0) s->use_ndk_codec = !av_jni_get_java_vm(avctx); @@ -313,6 +524,8 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) if (s->bitrate_mode == BITRATE_MODE_CQ && avctx->global_quality > 0) ff_AMediaFormat_setInt32(format, "quality", avctx->global_quality); } + mediacodec_set_qp_range(avctx, format); + // frame-rate and i-frame-interval are required to configure codec if (avctx->framerate.num >= avctx->framerate.den && avctx->framerate.den > 0) { s->fps = avctx->framerate.num / avctx->framerate.den; @@ -354,6 +567,8 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) } if (s->pts_as_dts == -1) s->pts_as_dts = avctx->max_b_frames <= 0; + if (s->operating_rate > 0) + ff_AMediaFormat_setInt32(format, "operating-rate", s->operating_rate); ret = ff_AMediaCodec_getConfigureFlagEncode(s->codec); ret = ff_AMediaCodec_configure(s->codec, format, s->window, NULL, ret); @@ -365,10 +580,21 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) goto bailout; } - ret = ff_AMediaCodec_start(s->codec); - if (ret) { - av_log(avctx, AV_LOG_ERROR, "MediaCodec failed to start, %s\n", av_err2str(ret)); - goto bailout; + if (s->async_mode) { + FFAMediaCodecOnAsyncNotifyCallback cb = { + .onAsyncInputAvailable = on_input_available, + .onAsyncOutputAvailable = on_output_available, + .onAsyncFormatChanged = on_format_changed, + .onAsyncError = on_error, + }; + + ret = ff_AMediaCodec_setAsyncNotifyCallback(s->codec, &cb, avctx); + if (ret < 0) { + av_log(avctx, AV_LOG_WARNING, + "Try MediaCodec async mode failed, %s, switch to sync mode\n", + av_err2str(ret)); + mediacodec_uninit_async_state(avctx); + } } ret = mediacodec_init_bsf(avctx); @@ -383,6 +609,13 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) goto bailout; } + ret = ff_AMediaCodec_start(s->codec); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "MediaCodec failed to start, %s\n", + av_err2str(ret)); + goto bailout; + } + ret = mediacodec_generate_extradata(avctx); bailout: @@ -391,17 +624,60 @@ bailout: return ret; } +static int mediacodec_get_output_index(AVCodecContext *avctx, ssize_t *index, + FFAMediaCodecBufferInfo *out_info) +{ + MediaCodecEncContext *s = avctx->priv_data; + FFAMediaCodec *codec = s->codec; + int64_t timeout_us = s->eof_sent ? OUTPUT_DEQUEUE_TIMEOUT_US : 0; + MediaCodecAsyncOutput output = { .index = -1 }; + int ret; + + if (!s->async_mode) { + *index = ff_AMediaCodec_dequeueOutputBuffer(codec, out_info, timeout_us); + return 0; + } + + ff_mutex_lock(&s->output_mutex); + + while (!s->encode_status) { + if (av_fifo_read(s->async_output, &output, 1) >= 0) + break; + + // Only wait after signalEndOfInputStream + if (s->eof_sent && !s->encode_status) + ff_cond_wait(&s->output_cond, &s->output_mutex); + else + break; + } + + ret = s->encode_status; + ff_mutex_unlock(&s->output_mutex); + + // Get output index success + if (output.index >= 0) { + *index = output.index; + *out_info = output.buf_info; + return 0; + } + + return ret ? ret : AVERROR(EAGAIN); +} + static int mediacodec_receive(AVCodecContext *avctx, AVPacket *pkt) { MediaCodecEncContext *s = avctx->priv_data; FFAMediaCodec *codec = s->codec; + ssize_t index; FFAMediaCodecBufferInfo out_info = {0}; uint8_t *out_buf; size_t out_size = 0; int ret; int extradata_size = 0; - int64_t timeout_us = s->eof_sent ? OUTPUT_DEQUEUE_TIMEOUT_US : 0; - ssize_t index = ff_AMediaCodec_dequeueOutputBuffer(codec, &out_info, timeout_us); + + ret = mediacodec_get_output_index(avctx, &index, &out_info); + if (ret < 0) + return ret; if (ff_AMediaCodec_infoTryAgainLater(codec, index)) return AVERROR(EAGAIN); @@ -429,6 +705,16 @@ static int mediacodec_receive(AVCodecContext *avctx, AVPacket *pkt) } if (out_info.flags & ff_AMediaCodec_getBufferFlagCodecConfig(codec)) { + if (avctx->codec_id == AV_CODEC_ID_AV1) { + // Skip AV1CodecConfigurationRecord without configOBUs + if (out_info.size <= 4) { + ff_AMediaCodec_releaseOutputBuffer(codec, index, false); + return mediacodec_receive(avctx, pkt); + } + out_info.size -= 4; + out_info.offset += 4; + } + ret = av_reallocp(&s->extradata, out_info.size); if (ret) goto bailout; @@ -466,33 +752,39 @@ bailout: return ret; } -static void copy_frame_to_buffer(AVCodecContext *avctx, const AVFrame *frame, uint8_t *dst, size_t size) +static int mediacodec_get_input_index(AVCodecContext *avctx, ssize_t *index) { MediaCodecEncContext *s = avctx->priv_data; - uint8_t *dst_data[4] = {}; - int dst_linesize[4] = {}; + FFAMediaCodec *codec = s->codec; + int ret = 0; + int32_t n; - if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) { - dst_data[0] = dst; - dst_data[1] = dst + s->width * s->height; - dst_data[2] = dst_data[1] + s->width * s->height / 4; - - dst_linesize[0] = s->width; - dst_linesize[1] = dst_linesize[2] = s->width / 2; - } else if (avctx->pix_fmt == AV_PIX_FMT_NV12) { - dst_data[0] = dst; - dst_data[1] = dst + s->width * s->height; - - dst_linesize[0] = s->width; - dst_linesize[1] = s->width; - } else { - av_assert0(0); + if (!s->async_mode) { + *index = ff_AMediaCodec_dequeueInputBuffer(codec, INPUT_DEQUEUE_TIMEOUT_US); + return 0; } - av_image_copy2(dst_data, dst_linesize, frame->data, frame->linesize, - avctx->pix_fmt, avctx->width, avctx->height); + ff_mutex_lock(&s->input_mutex); + + n = -1; + while (n < 0 && !s->encode_status) { + if (av_fifo_can_read(s->input_index) > 0) { + av_fifo_read(s->input_index, &n, 1); + break; + } + + if (n < 0 && !s->encode_status) + ff_cond_wait(&s->input_cond, &s->input_mutex); + } + + ret = s->encode_status; + *index = n; + ff_mutex_unlock(&s->input_mutex); + + return ret; } + static int mediacodec_send(AVCodecContext *avctx, const AVFrame *frame) { MediaCodecEncContext *s = avctx->priv_data; @@ -502,7 +794,7 @@ static int mediacodec_send(AVCodecContext *avctx, size_t input_size = 0; int64_t pts = 0; uint32_t flags = 0; - int64_t timeout_us; + int ret; if (s->eof_sent) return 0; @@ -518,8 +810,10 @@ static int mediacodec_send(AVCodecContext *avctx, return 0; } - timeout_us = INPUT_DEQUEUE_TIMEOUT_US; - index = ff_AMediaCodec_dequeueInputBuffer(codec, timeout_us); + ret = mediacodec_get_input_index(avctx, &index); + if (ret < 0) + return ret; + if (ff_AMediaCodec_infoTryAgainLater(codec, index)) return AVERROR(EAGAIN); @@ -652,7 +946,8 @@ static int mediacodec_generate_extradata(AVCodecContext *avctx) if (!(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) return 0; - if (!s->extract_extradata) { + // Send dummy frame and receive a packet doesn't work in async mode + if (s->async_mode || !s->extract_extradata) { av_log(avctx, AV_LOG_WARNING, "Mediacodec encoder doesn't support AV_CODEC_FLAG_GLOBAL_HEADER. " "Use extract_extradata bsf when necessary.\n"); @@ -709,6 +1004,8 @@ static av_cold int mediacodec_close(AVCodecContext *avctx) av_bsf_free(&s->bsf); av_frame_free(&s->frame); + mediacodec_uninit_async_state(avctx); + return 0; } @@ -734,11 +1031,19 @@ static const AVCodecHWConfigInternal *const mediacodec_hw_configs[] = { NULL }; +static const FFCodecDefault mediacodec_defaults[] = { + {"qmin", "-1"}, + {"qmax", "-1"}, + {NULL}, +}; + #define OFFSET(x) offsetof(MediaCodecEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM #define COMMON_OPTION \ { "ndk_codec", "Use MediaCodec from NDK", \ OFFSET(use_ndk_codec), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE }, \ + { "ndk_async", "Try NDK MediaCodec in async mode", \ + OFFSET(async_mode), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VE }, \ { "codec_name", "Select codec by name", \ OFFSET(name), AV_OPT_TYPE_STRING, {0}, 0, 0, VE }, \ { "bitrate_mode", "Bitrate control method", \ @@ -754,6 +1059,20 @@ static const AVCodecHWConfigInternal *const mediacodec_hw_configs[] = { { "pts_as_dts", "Use PTS as DTS. It is enabled automatically if avctx max_b_frames <= 0, " \ "since most of Android devices don't output B frames by default.", \ OFFSET(pts_as_dts), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE }, \ + { "operating_rate", "The desired operating rate that the codec will need to operate at, zero for unspecified", \ + OFFSET(operating_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, VE }, \ + { "qp_i_min", "minimum quantization parameter for I frame", \ + OFFSET(qp_i_min), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ + { "qp_p_min", "minimum quantization parameter for P frame", \ + OFFSET(qp_p_min), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ + { "qp_b_min", "minimum quantization parameter for B frame", \ + OFFSET(qp_b_min), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ + { "qp_i_max", "maximum quantization parameter for I frame", \ + OFFSET(qp_i_max), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ + { "qp_p_max", "maximum quantization parameter for P frame", \ + OFFSET(qp_p_max), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ + { "qp_b_max", "maximum quantization parameter for B frame", \ + OFFSET(qp_b_max), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ #define MEDIACODEC_ENCODER_CLASS(name) \ @@ -775,8 +1094,9 @@ const FFCodec ff_ ## short_name ## _mediacodec_encoder = { \ AV_CODEC_CAP_HARDWARE | \ AV_CODEC_CAP_ENCODER_FLUSH, \ .priv_data_size = sizeof(MediaCodecEncContext), \ - .p.pix_fmts = avc_pix_fmts, \ + CODEC_PIXFMTS_ARRAY(avc_pix_fmts), \ .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, \ + .defaults = mediacodec_defaults, \ .init = mediacodec_init, \ FF_CODEC_RECEIVE_PACKET_CB(mediacodec_encode), \ .close = mediacodec_close, \ @@ -1032,7 +1352,7 @@ static const AVOption vp9_options[] = { 0, AV_OPT_TYPE_CONST, { .i64 = VP9Level52 }, 0, 0, VE, .unit = "level" }, { "6", "Level 6", 0, AV_OPT_TYPE_CONST, { .i64 = VP9Level6 }, 0, 0, VE, .unit = "level" }, - { "6.1", "Level 4.1", + { "6.1", "Level 6.1", 0, AV_OPT_TYPE_CONST, { .i64 = VP9Level61 }, 0, 0, VE, .unit = "level" }, { "6.2", "Level 6.2", 0, AV_OPT_TYPE_CONST, { .i64 = VP9Level62 }, 0, 0, VE, .unit = "level" }, diff --git a/libavcodec/metasound.c b/libavcodec/metasound.c index f33231683..0cca237c1 100644 --- a/libavcodec/metasound.c +++ b/libavcodec/metasound.c @@ -374,7 +374,5 @@ const FFCodec ff_metasound_decoder = { .close = ff_twinvq_decode_close, FF_CODEC_DECODE_CB(ff_twinvq_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/mf_utils.c b/libavcodec/mf_utils.c index 48e3a63ef..ff44130ca 100644 --- a/libavcodec/mf_utils.c +++ b/libavcodec/mf_utils.c @@ -240,6 +240,7 @@ static struct GUID_Entry guid_names[] = { GUID_ENTRY(MFMediaType_Video), GUID_ENTRY(MFAudioFormat_PCM), GUID_ENTRY(MFAudioFormat_Float), + GUID_ENTRY(ff_MFVideoFormat_AV1), GUID_ENTRY(MFVideoFormat_H264), GUID_ENTRY(MFVideoFormat_H264_ES), GUID_ENTRY(ff_MFVideoFormat_HEVC), @@ -507,6 +508,7 @@ void ff_media_type_dump(void *log, IMFMediaType *type) const CLSID *ff_codec_to_mf_subtype(enum AVCodecID codec) { switch (codec) { + case AV_CODEC_ID_AV1: return &ff_MFVideoFormat_AV1; case AV_CODEC_ID_H264: return &MFVideoFormat_H264; case AV_CODEC_ID_HEVC: return &ff_MFVideoFormat_HEVC; case AV_CODEC_ID_AC3: return &MFAudioFormat_Dolby_AC3; diff --git a/libavcodec/mf_utils.h b/libavcodec/mf_utils.h index 387c005f3..ecebb6fcd 100644 --- a/libavcodec/mf_utils.h +++ b/libavcodec/mf_utils.h @@ -53,6 +53,13 @@ typedef struct MFFunctions { IMFMediaBuffer **ppBuffer); HRESULT (WINAPI *MFCreateSample) (IMFSample **ppIMFSample); HRESULT (WINAPI *MFCreateMediaType) (IMFMediaType **ppMFType); + HRESULT (WINAPI *MFCreateDXGISurfaceBuffer) (REFIID riid, + IUnknown* punkSurface, + UINT uSubresourceIndex, + BOOL fBottomUpWhenLinear, + IMFMediaBuffer** ppBuffer); + HRESULT (WINAPI *MFCreateDXGIDeviceManager) (UINT* resetToken, + IMFDXGIDeviceManager** ppDeviceManager); // MFTEnumEx is missing in Windows Vista's mfplat.dll. HRESULT (WINAPI *MFTEnumEx)(GUID guidCategory, UINT32 Flags, const MFT_REGISTER_TYPE_INFO *pInputType, @@ -113,6 +120,7 @@ DEFINE_GUID(ff_MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT_PROGRESSIVE, 0xf5523a5, 0x1cb2, DEFINE_MEDIATYPE_GUID(ff_MFVideoFormat_HEVC, 0x43564548); // FCC('HEVC') DEFINE_MEDIATYPE_GUID(ff_MFVideoFormat_HEVC_ES, 0x53564548); // FCC('HEVS') +DEFINE_MEDIATYPE_GUID(ff_MFVideoFormat_AV1, 0x31305641); // FCC('AV01') // This enum is missing from mingw-w64's codecapi.h by v7.0.0. diff --git a/libavcodec/mfenc.c b/libavcodec/mfenc.c index b8f8a25f4..541f7fb96 100644 --- a/libavcodec/mfenc.c +++ b/libavcodec/mfenc.c @@ -31,10 +31,18 @@ #include "codec_internal.h" #include "internal.h" #include "compat/w32dlfcn.h" +#if CONFIG_D3D11VA +#include "libavutil/hwcontext_d3d11va.h" +#endif typedef struct MFContext { AVClass *av_class; HMODULE library; + HMODULE d3d_dll; + ID3D11DeviceContext* d3d_context; + IMFDXGIDeviceManager *dxgiManager; + int resetToken; + MFFunctions functions; AVFrame *frame; int is_video, is_audio; @@ -47,6 +55,7 @@ typedef struct MFContext { int out_stream_provides_samples; int draining, draining_done; int sample_sent; + int stream_started; int async_need_input, async_have_output, async_marker; int64_t reorder_delay; ICodecAPI *codec_api; @@ -55,6 +64,7 @@ typedef struct MFContext { int opt_enc_quality; int opt_enc_scenario; int opt_enc_hw; + AVD3D11VADeviceContext* device_hwctx; } MFContext; static int mf_choose_output_type(AVCodecContext *avctx); @@ -138,6 +148,15 @@ static int64_t mf_sample_get_pts(AVCodecContext *avctx, IMFSample *sample) return mf_from_mf_time(avctx, pts); } +static int64_t mf_sample_get_duration(AVCodecContext *avctx, IMFSample *sample) +{ + LONGLONG duration; + HRESULT hr = IMFSample_GetSampleDuration(sample, &duration); + if (FAILED(hr)) + return 0; + return mf_from_mf_time(avctx, duration); +} + static int mf_enca_output_type_get(AVCodecContext *avctx, IMFMediaType *type) { MFContext *c = avctx->priv_data; @@ -265,6 +284,7 @@ static int mf_sample_to_avpacket(AVCodecContext *avctx, IMFSample *sample, AVPac IMFMediaBuffer_Release(buffer); avpkt->pts = avpkt->dts = mf_sample_get_pts(avctx, sample); + avpkt->duration = mf_sample_get_duration(avctx, sample); hr = IMFAttributes_GetUINT32(sample, &MFSampleExtension_CleanPoint, &t32); if (c->is_audio || (!FAILED(hr) && t32 != 0)) @@ -286,7 +306,7 @@ static int mf_sample_to_avpacket(AVCodecContext *avctx, IMFSample *sample, AVPac return 0; } -static IMFSample *mf_a_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame) +static int mf_a_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame, IMFSample **out_sample) { MFContext *c = avctx->priv_data; size_t len; @@ -298,41 +318,127 @@ static IMFSample *mf_a_avframe_to_sample(AVCodecContext *avctx, const AVFrame *f sample = ff_create_memory_sample(&c->functions, frame->data[0], len, c->in_info.cbAlignment); - if (sample) - IMFSample_SetSampleDuration(sample, mf_to_mf_time(avctx, frame->nb_samples)); - return sample; + if (!sample) + return AVERROR(ENOMEM); + + IMFSample_SetSampleDuration(sample, mf_to_mf_time(avctx, frame->nb_samples)); + + *out_sample = sample; + return 0; } -static IMFSample *mf_v_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame) +static int initialize_dxgi_manager(AVCodecContext *avctx) { MFContext *c = avctx->priv_data; - IMFSample *sample; - IMFMediaBuffer *buffer; - BYTE *data; + MFFunctions *func = &c->functions; HRESULT hr; - int ret; - int size; + + hr = func->MFCreateDXGIDeviceManager(&c->resetToken, &c->dxgiManager); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create DXGI device manager: %s\n", ff_hr_str(hr)); + return AVERROR_EXTERNAL; + } + + hr = IMFDXGIDeviceManager_ResetDevice(c->dxgiManager, (IUnknown*)c->device_hwctx->device, c->resetToken); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to reset device: %s\n", ff_hr_str(hr)); + return AVERROR_EXTERNAL; + } + + hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)c->dxgiManager); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to set D3D manager: %s\n", ff_hr_str(hr)); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int process_d3d11_frame(AVCodecContext *avctx, const AVFrame *frame, IMFSample **out_sample) +{ + MFContext *c = avctx->priv_data; + MFFunctions *func = &c->functions; + AVHWFramesContext *frames_ctx = NULL; + ID3D11Texture2D *d3d11_texture = NULL; + IMFSample *sample = NULL; + IMFMediaBuffer *buffer = NULL; + int subIdx = 0; + HRESULT hr; + + frames_ctx = (AVHWFramesContext*)frame->hw_frames_ctx->data; + c->device_hwctx = (AVD3D11VADeviceContext*)frames_ctx->device_ctx->hwctx; + + if (!c->dxgiManager) { + hr = initialize_dxgi_manager(avctx); + if (FAILED(hr)) { + return AVERROR_EXTERNAL; + } + } + + d3d11_texture = (ID3D11Texture2D*)frame->data[0]; + subIdx = (int)(intptr_t)frame->data[1]; + + if (!d3d11_texture) { + av_log(avctx, AV_LOG_ERROR, "D3D11 texture not found\n"); + return AVERROR(EINVAL); + } + + hr = func->MFCreateSample(&sample); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create MF sample: %s\n", ff_hr_str(hr)); + return AVERROR_EXTERNAL; + } + + hr = func->MFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown*)d3d11_texture, subIdx, 0, &buffer); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create DXGI surface buffer: %s\n", ff_hr_str(hr)); + IMFSample_Release(sample); + return AVERROR_EXTERNAL; + } + + hr = IMFSample_AddBuffer(sample, buffer); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to add buffer to sample: %s\n", ff_hr_str(hr)); + IMFMediaBuffer_Release(buffer); + IMFSample_Release(sample); + return AVERROR_EXTERNAL; + } + + IMFMediaBuffer_Release(buffer); + + *out_sample = sample; + return 0; +} + +static int process_software_frame(AVCodecContext *avctx, const AVFrame *frame, IMFSample **out_sample) +{ + MFContext *c = avctx->priv_data; + IMFSample *sample = NULL; + IMFMediaBuffer *buffer = NULL; + BYTE *data = NULL; + HRESULT hr; + int size, ret; size = av_image_get_buffer_size(avctx->pix_fmt, avctx->width, avctx->height, 1); if (size < 0) - return NULL; + return size; sample = ff_create_memory_sample(&c->functions, NULL, size, c->in_info.cbAlignment); if (!sample) - return NULL; + return AVERROR_EXTERNAL; hr = IMFSample_GetBufferByIndex(sample, 0, &buffer); if (FAILED(hr)) { IMFSample_Release(sample); - return NULL; + return AVERROR_EXTERNAL; } hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); if (FAILED(hr)) { IMFMediaBuffer_Release(buffer); IMFSample_Release(sample); - return NULL; + return AVERROR_EXTERNAL; } ret = av_image_copy_to_buffer((uint8_t *)data, size, (void *)frame->data, frame->linesize, @@ -342,29 +448,63 @@ static IMFSample *mf_v_avframe_to_sample(AVCodecContext *avctx, const AVFrame *f IMFMediaBuffer_Release(buffer); if (ret < 0) { IMFSample_Release(sample); - return NULL; + return ret; } IMFSample_SetSampleDuration(sample, mf_to_mf_time(avctx, frame->duration)); + *out_sample = sample; - return sample; + return 0; } -static IMFSample *mf_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame) +static int mf_v_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame, IMFSample **out_sample) +{ + IMFSample *sample = NULL; + HRESULT hr; + int ret; + + if (frame->format == AV_PIX_FMT_D3D11) { + // Handle D3D11 hardware frames + ret = process_d3d11_frame(avctx, frame, &sample); + if (ret < 0) { + return ret; + } + } else { + // Handle software frames + ret = process_software_frame(avctx, frame, &sample); + if (ret < 0) { + return ret; + } + } + + // Set sample duration + hr = IMFSample_SetSampleDuration(sample, mf_to_mf_time(avctx, frame->duration)); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_WARNING, "Failed to set sample duration: %s\n", ff_hr_str(hr)); + } + + *out_sample = sample; + return 0; +} + +static int mf_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame, IMFSample **out_sample) { MFContext *c = avctx->priv_data; IMFSample *sample; + int ret; if (c->is_audio) { - sample = mf_a_avframe_to_sample(avctx, frame); + ret = mf_a_avframe_to_sample(avctx, frame, &sample); } else { - sample = mf_v_avframe_to_sample(avctx, frame); + ret = mf_v_avframe_to_sample(avctx, frame, &sample); } - if (sample) - mf_sample_set_pts(avctx, sample, frame->pts); + if (ret < 0) + return ret; - return sample; + mf_sample_set_pts(avctx, sample, frame->pts); + *out_sample = sample; + return 0; } static int mf_send_sample(AVCodecContext *avctx, IMFSample *sample) @@ -500,10 +640,10 @@ static int mf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) } if (c->frame->buf[0]) { - sample = mf_avframe_to_sample(avctx, c->frame); - if (!sample) { + ret = mf_avframe_to_sample(avctx, c->frame, &sample); + if (ret < 0) { av_frame_unref(c->frame); - return AVERROR(ENOMEM); + return ret; } if (c->is_video && c->codec_api) { if (c->frame->pict_type == AV_PICTURE_TYPE_I || !c->sample_sent) @@ -511,6 +651,23 @@ static int mf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) } } + if(!c->stream_started) + { + HRESULT hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "could not start streaming (%s)\n", ff_hr_str(hr)); + return AVERROR(EBADMSG); + } + + hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "could not start stream (%s)\n", ff_hr_str(hr)); + return AVERROR(EBADMSG); + } + + c->stream_started = 1; + } + ret = mf_send_sample(avctx, sample); if (sample) IMFSample_Release(sample); @@ -660,11 +817,6 @@ static int mf_encv_output_adjust(AVCodecContext *avctx, IMFMediaType *type) framerate = avctx->framerate; } else { framerate = av_inv_q(avctx->time_base); -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - framerate.den *= avctx->ticks_per_frame; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } ff_MFSetAttributeRatio((IMFAttributes *)type, &MF_MT_FRAME_RATE, framerate.num, framerate.den); @@ -724,6 +876,9 @@ FF_ENABLE_DEPRECATION_WARNINGS if (c->opt_enc_scenario >= 0) ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVScenarioInfo, FF_VAL_VT_UI4(c->opt_enc_scenario)); + + if (avctx->flags & AV_CODEC_FLAG_LOW_DELAY) + ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVLowLatencyMode, FF_VAL_VT_UI4(1)); } return 0; @@ -732,8 +887,16 @@ FF_ENABLE_DEPRECATION_WARNINGS static int64_t mf_encv_input_score(AVCodecContext *avctx, IMFMediaType *type) { enum AVPixelFormat pix_fmt = ff_media_type_to_pix_fmt((IMFAttributes *)type); - if (pix_fmt != avctx->pix_fmt) - return -1; // can not use + + if (avctx->pix_fmt == AV_PIX_FMT_D3D11) { + if (pix_fmt != AV_PIX_FMT_NV12) { + return -1; // can not use + } + } + else { + if (pix_fmt != avctx->pix_fmt) + return -1; // can not use + } return 0; } @@ -741,9 +904,16 @@ static int64_t mf_encv_input_score(AVCodecContext *avctx, IMFMediaType *type) static int mf_encv_input_adjust(AVCodecContext *avctx, IMFMediaType *type) { enum AVPixelFormat pix_fmt = ff_media_type_to_pix_fmt((IMFAttributes *)type); - if (pix_fmt != avctx->pix_fmt) { - av_log(avctx, AV_LOG_ERROR, "unsupported input pixel format set\n"); - return AVERROR(EINVAL); + if (avctx->pix_fmt == AV_PIX_FMT_D3D11) { + if (pix_fmt != AV_PIX_FMT_NV12 && pix_fmt != AV_PIX_FMT_D3D11) { + av_log(avctx, AV_LOG_ERROR, "unsupported input pixel format set\n"); + return AVERROR(EINVAL); + } + } else { + if (pix_fmt != avctx->pix_fmt) { + av_log(avctx, AV_LOG_ERROR, "unsupported input pixel format set\n"); + return AVERROR(EINVAL); + } } //ff_MFSetAttributeSize((IMFAttributes *)type, &MF_MT_FRAME_SIZE, avctx->width, avctx->height); @@ -1111,18 +1281,6 @@ static int mf_init_encoder(AVCodecContext *avctx) if ((ret = mf_setup_context(avctx)) < 0) return ret; - hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); - if (FAILED(hr)) { - av_log(avctx, AV_LOG_ERROR, "could not start streaming (%s)\n", ff_hr_str(hr)); - return AVERROR_EXTERNAL; - } - - hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); - if (FAILED(hr)) { - av_log(avctx, AV_LOG_ERROR, "could not start stream (%s)\n", ff_hr_str(hr)); - return AVERROR_EXTERNAL; - } - if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER && c->async_events && c->is_video && !avctx->extradata) { int sleep = 10000, total = 0; @@ -1180,6 +1338,7 @@ static int mf_load_library(AVCodecContext *avctx) #if !HAVE_UWP c->library = dlopen("mfplat.dll", 0); + c->d3d_dll = dlopen("D3D11.dll", 0); if (!c->library) { av_log(c, AV_LOG_ERROR, "DLL mfplat.dll failed to open\n"); @@ -1192,6 +1351,8 @@ static int mf_load_library(AVCodecContext *avctx) LOAD_MF_FUNCTION(c, MFCreateAlignedMemoryBuffer); LOAD_MF_FUNCTION(c, MFCreateSample); LOAD_MF_FUNCTION(c, MFCreateMediaType); + LOAD_MF_FUNCTION(c, MFCreateDXGISurfaceBuffer); + LOAD_MF_FUNCTION(c, MFCreateDXGIDeviceManager); // MFTEnumEx is missing in Windows Vista's mfplat.dll. LOAD_MF_FUNCTION(c, MFTEnumEx); @@ -1208,11 +1369,15 @@ static int mf_close(AVCodecContext *avctx) if (c->async_events) IMFMediaEventGenerator_Release(c->async_events); + if (c->dxgiManager) + IMFDXGIDeviceManager_Release(c->dxgiManager); + #if !HAVE_UWP if (c->library) ff_free_mf(&c->functions, &c->mft); dlclose(c->library); + dlclose(c->d3d_dll); c->library = NULL; #else ff_free_mf(&c->functions, &c->mft); @@ -1226,7 +1391,7 @@ static int mf_close(AVCodecContext *avctx) return 0; } -static int mf_init(AVCodecContext *avctx) +static av_cold int mf_init(AVCodecContext *avctx) { int ret; if ((ret = mf_load_library(avctx)) == 0) { @@ -1263,8 +1428,7 @@ static int mf_init(AVCodecContext *avctx) }; #define AFMTS \ - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, \ - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), #define ACAPS \ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID | \ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_VARIABLE_FRAME_SIZE, @@ -1306,12 +1470,11 @@ static const FFCodecDefault defaults[] = { }; #define VFMTS \ - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, \ - AV_PIX_FMT_YUV420P, \ - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, AV_PIX_FMT_D3D11), #define VCAPS \ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID | \ AV_CODEC_CAP_DR1, MF_ENCODER(VIDEO, h264, H264, venc_opts, VFMTS, VCAPS, defaults); MF_ENCODER(VIDEO, hevc, HEVC, venc_opts, VFMTS, VCAPS, defaults); +MF_ENCODER(VIDEO, av1, AV1, venc_opts, VFMTS, VCAPS, defaults); diff --git a/libavcodec/microdvddec.c b/libavcodec/microdvddec.c index 786a3845f..a46a62e45 100644 --- a/libavcodec/microdvddec.c +++ b/libavcodec/microdvddec.c @@ -319,7 +319,7 @@ static int microdvd_decode_frame(AVCodecContext *avctx, AVSubtitle *sub, return avpkt->size; } -static int microdvd_init(AVCodecContext *avctx) +static av_cold int microdvd_init(AVCodecContext *avctx) { int i, sidx; AVBPrint font_buf; diff --git a/libavcodec/midivid.c b/libavcodec/midivid.c index 70730231b..a4f90c2cf 100644 --- a/libavcodec/midivid.c +++ b/libavcodec/midivid.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/mem.h" @@ -257,7 +258,7 @@ static av_cold int decode_init(AVCodecContext *avctx) return 0; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { MidiVidContext *s = avctx->priv_data; diff --git a/libavcodec/mimic.c b/libavcodec/mimic.c index 2925aa50f..08e250961 100644 --- a/libavcodec/mimic.c +++ b/libavcodec/mimic.c @@ -399,7 +399,9 @@ static int mimic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, ctx->bbdsp.bswap_buf(ctx->swap_buf, (const uint32_t *) (buf + MIMIC_HEADER_SIZE), swap_buf_size >> 2); - init_get_bits(&ctx->gb, ctx->swap_buf, swap_buf_size << 3); + res = init_get_bits8(&ctx->gb, ctx->swap_buf, swap_buf_size); + if (res < 0) + return res; res = decode(ctx, quality, num_coeffs, !is_pframe); ff_progress_frame_report(&ctx->frames[ctx->cur_index], INT_MAX); diff --git a/libavcodec/mips/Makefile b/libavcodec/mips/Makefile index fc1bc6b03..1d777293d 100644 --- a/libavcodec/mips/Makefile +++ b/libavcodec/mips/Makefile @@ -1,20 +1,43 @@ ARCH_HEADERS = cabac.h compute_antialias_fixed.h \ compute_antialias_float.h \ +MIPSFPU-OBJS-$(CONFIG_ACELP_KELVIN_DECODER) += mips/acelp_filters_mips.o \ + mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o MIPSFPU-OBJS-$(CONFIG_AMRNB_DECODER) += mips/acelp_filters_mips.o \ mips/celp_filters_mips.o \ - mips/celp_math_mips.o \ mips/acelp_vectors_mips.o MIPSFPU-OBJS-$(CONFIG_AMRWB_DECODER) += mips/acelp_filters_mips.o \ mips/celp_filters_mips.o \ mips/amrwbdec_mips.o \ - mips/celp_math_mips.o \ mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_COMFORTNOISE_DECODER) += mips/celp_filters_mips.o +MIPSFPU-OBJS-$(CONFIG_EVRC_DECODER) += mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_G723_1_DECODER) += mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_G723_1_ENCODER) += mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_G728_DECODER) += mips/celp_filters_mips.o +MIPSFPU-OBJS-$(CONFIG_G729_DECODER) += mips/acelp_filters_mips.o \ + mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_QCELP_DECODER) += mips/acelp_filters_mips.o \ + mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_RA_144_DECODER) += mips/celp_filters_mips.o +MIPSFPU-OBJS-$(CONFIG_RA_144_ENCODER) += mips/celp_filters_mips.o +MIPSFPU-OBJS-$(CONFIG_RA_288_DECODER) += mips/celp_filters_mips.o +MIPSFPU-OBJS-$(CONFIG_SIPR_DECODER) += mips/acelp_filters_mips.o \ + mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_WMAVOICE_DECODER) += mips/acelp_filters_mips.o \ + mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_CELP_MATH) += mips/celp_math_mips.o MIPSFPU-OBJS-$(CONFIG_MPEGAUDIODSP) += mips/mpegaudiodsp_mips_float.o MIPSDSP-OBJS-$(CONFIG_MPEGAUDIODSP) += mips/mpegaudiodsp_mips_fixed.o MIPSFPU-OBJS-$(CONFIG_FMTCONVERT) += mips/fmtconvert_mips.o OBJS-$(CONFIG_AC3DSP) += mips/ac3dsp_mips.o -MIPSFPU-OBJS-$(CONFIG_AAC_ENCODER) += mips/iirfilter_mips.o OBJS-$(CONFIG_HEVC_DECODER) += mips/hevcdsp_init_mips.o \ mips/hevcpred_init_mips.o OBJS-$(CONFIG_VP9_DECODER) += mips/vp9dsp_init_mips.o @@ -31,8 +54,7 @@ OBJS-$(CONFIG_BLOCKDSP) += mips/blockdsp_init_mips.o OBJS-$(CONFIG_PIXBLOCKDSP) += mips/pixblockdsp_init_mips.o OBJS-$(CONFIG_IDCTDSP) += mips/idctdsp_init_mips.o OBJS-$(CONFIG_MPEGVIDEO) += mips/mpegvideo_init_mips.o -OBJS-$(CONFIG_MPEGVIDEOENC) += mips/mpegvideoenc_init_mips.o \ - mips/mpegvideoencdsp_init_mips.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += mips/mpegvideoencdsp_init_mips.o OBJS-$(CONFIG_ME_CMP) += mips/me_cmp_init_mips.o OBJS-$(CONFIG_MPEG4_DECODER) += mips/xvididct_init_mips.o OBJS-$(CONFIG_VC1DSP) += mips/vc1dsp_init_mips.o @@ -68,16 +90,16 @@ MSA-OBJS-$(CONFIG_PIXBLOCKDSP) += mips/pixblockdsp_msa.o MSA-OBJS-$(CONFIG_IDCTDSP) += mips/idctdsp_msa.o \ mips/simple_idct_msa.o MSA-OBJS-$(CONFIG_MPEGVIDEO) += mips/mpegvideo_msa.o -MSA-OBJS-$(CONFIG_MPEGVIDEOENC) += mips/mpegvideoencdsp_msa.o +MSA-OBJS-$(CONFIG_MPEGVIDEOENCDSP) += mips/mpegvideoencdsp_msa.o MSA-OBJS-$(CONFIG_ME_CMP) += mips/me_cmp_msa.o -MSA-OBJS-$(CONFIG_VC1_DECODER) += mips/vc1dsp_msa.o +MSA-OBJS-$(CONFIG_VC1DSP) += mips/vc1dsp_msa.o MMI-OBJS += mips/constants.o MMI-OBJS-$(CONFIG_H264DSP) += mips/h264dsp_mmi.o MMI-OBJS-$(CONFIG_H264CHROMA) += mips/h264chroma_mmi.o MMI-OBJS-$(CONFIG_H264PRED) += mips/h264pred_mmi.o MMI-OBJS-$(CONFIG_MPEGVIDEO) += mips/mpegvideo_mmi.o -MMI-OBJS-$(CONFIG_MPEGVIDEOENC) += mips/mpegvideoenc_mmi.o +MMI-OBJS-$(CONFIG_MPEGVIDEOENCDSP) += mips/mpegvideoenc_mmi.o MMI-OBJS-$(CONFIG_IDCTDSP) += mips/idctdsp_mmi.o \ mips/simple_idct_mmi.o MMI-OBJS-$(CONFIG_MPEG4_DECODER) += mips/xvid_idct_mmi.o @@ -86,7 +108,7 @@ MMI-OBJS-$(CONFIG_PIXBLOCKDSP) += mips/pixblockdsp_mmi.o MMI-OBJS-$(CONFIG_H264QPEL) += mips/h264qpel_mmi.o MMI-OBJS-$(CONFIG_VP8_DECODER) += mips/vp8dsp_mmi.o MMI-OBJS-$(CONFIG_HPELDSP) += mips/hpeldsp_mmi.o -MMI-OBJS-$(CONFIG_VC1_DECODER) += mips/vc1dsp_mmi.o +MMI-OBJS-$(CONFIG_VC1DSP) += mips/vc1dsp_mmi.o MMI-OBJS-$(CONFIG_WMV2DSP) += mips/wmv2dsp_mmi.o MMI-OBJS-$(CONFIG_HEVC_DECODER) += mips/hevcdsp_mmi.o MMI-OBJS-$(CONFIG_VP3DSP) += mips/vp3dsp_idct_mmi.o diff --git a/libavcodec/mips/celp_math_mips.c b/libavcodec/mips/celp_math_mips.c index ce711bd63..1c41ce56d 100644 --- a/libavcodec/mips/celp_math_mips.c +++ b/libavcodec/mips/celp_math_mips.c @@ -53,6 +53,7 @@ */ #include "config.h" #include "libavcodec/celp_math.h" +#include "libavutil/attributes.h" #include "libavutil/mips/asmdefs.h" #if HAVE_INLINE_ASM @@ -84,7 +85,7 @@ static float ff_dot_productf_mips(const float* a, const float* b, #endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ #endif /* HAVE_INLINE_ASM */ -void ff_celp_math_init_mips(CELPMContext *c) +av_cold void ff_celp_math_init_mips(CELPMContext *c) { #if HAVE_INLINE_ASM #if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 diff --git a/libavcodec/mips/h263dsp_mips.h b/libavcodec/mips/h263dsp_mips.h index d4de2233a..5ea9fcbb8 100644 --- a/libavcodec/mips/h263dsp_mips.h +++ b/libavcodec/mips/h263dsp_mips.h @@ -25,11 +25,11 @@ void ff_h263_h_loop_filter_msa(uint8_t *src, int stride, int q_scale); void ff_h263_v_loop_filter_msa(uint8_t *src, int stride, int q_scale); -void ff_dct_unquantize_mpeg2_inter_msa(MpegEncContext *s, int16_t *block, +void ff_dct_unquantize_mpeg2_inter_msa(const MPVContext *s, int16_t *block, int32_t index, int32_t q_scale); -void ff_dct_unquantize_h263_inter_msa(MpegEncContext *s, int16_t *block, +void ff_dct_unquantize_h263_inter_msa(const MPVContext *s, int16_t *block, int32_t index, int32_t q_scale); -void ff_dct_unquantize_h263_intra_msa(MpegEncContext *s, int16_t *block, +void ff_dct_unquantize_h263_intra_msa(const MPVContext *s, int16_t *block, int32_t index, int32_t q_scale); int ff_pix_sum_msa(const uint8_t *pix, ptrdiff_t line_size); diff --git a/libavcodec/mips/h264dsp_init_mips.c b/libavcodec/mips/h264dsp_init_mips.c index 72f42895e..4d8c3a7a5 100644 --- a/libavcodec/mips/h264dsp_init_mips.c +++ b/libavcodec/mips/h264dsp_init_mips.c @@ -30,101 +30,101 @@ av_cold void ff_h264dsp_init_mips(H264DSPContext *c, const int bit_depth, if (have_mmi(cpu_flags)) { if (bit_depth == 8) { - c->h264_add_pixels4_clear = ff_h264_add_pixels4_8_mmi; - c->h264_idct_add = ff_h264_idct_add_8_mmi; - c->h264_idct8_add = ff_h264_idct8_add_8_mmi; - c->h264_idct_dc_add = ff_h264_idct_dc_add_8_mmi; - c->h264_idct8_dc_add = ff_h264_idct8_dc_add_8_mmi; - c->h264_idct_add16 = ff_h264_idct_add16_8_mmi; - c->h264_idct_add16intra = ff_h264_idct_add16intra_8_mmi; - c->h264_idct8_add4 = ff_h264_idct8_add4_8_mmi; + c->add_pixels4_clear = ff_h264_add_pixels4_8_mmi; + c->idct_add = ff_h264_idct_add_8_mmi; + c->idct8_add = ff_h264_idct8_add_8_mmi; + c->idct_dc_add = ff_h264_idct_dc_add_8_mmi; + c->idct8_dc_add = ff_h264_idct8_dc_add_8_mmi; + c->idct_add16 = ff_h264_idct_add16_8_mmi; + c->idct_add16intra = ff_h264_idct_add16intra_8_mmi; + c->idct8_add4 = ff_h264_idct8_add4_8_mmi; if (chroma_format_idc <= 1) - c->h264_idct_add8 = ff_h264_idct_add8_8_mmi; + c->idct_add8 = ff_h264_idct_add8_8_mmi; else - c->h264_idct_add8 = ff_h264_idct_add8_422_8_mmi; + c->idct_add8 = ff_h264_idct_add8_422_8_mmi; - c->h264_luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_8_mmi; + c->luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_8_mmi; - c->weight_h264_pixels_tab[0] = ff_h264_weight_pixels16_8_mmi; - c->weight_h264_pixels_tab[1] = ff_h264_weight_pixels8_8_mmi; - c->weight_h264_pixels_tab[2] = ff_h264_weight_pixels4_8_mmi; + c->weight_pixels_tab[0] = ff_h264_weight_pixels16_8_mmi; + c->weight_pixels_tab[1] = ff_h264_weight_pixels8_8_mmi; + c->weight_pixels_tab[2] = ff_h264_weight_pixels4_8_mmi; - c->biweight_h264_pixels_tab[0] = ff_h264_biweight_pixels16_8_mmi; - c->biweight_h264_pixels_tab[1] = ff_h264_biweight_pixels8_8_mmi; - c->biweight_h264_pixels_tab[2] = ff_h264_biweight_pixels4_8_mmi; + c->biweight_pixels_tab[0] = ff_h264_biweight_pixels16_8_mmi; + c->biweight_pixels_tab[1] = ff_h264_biweight_pixels8_8_mmi; + c->biweight_pixels_tab[2] = ff_h264_biweight_pixels4_8_mmi; - c->h264_v_loop_filter_chroma = ff_deblock_v_chroma_8_mmi; - c->h264_v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_8_mmi; + c->v_loop_filter_chroma = ff_deblock_v_chroma_8_mmi; + c->v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_8_mmi; if (chroma_format_idc <= 1) { - c->h264_h_loop_filter_chroma = + c->h_loop_filter_chroma = ff_deblock_h_chroma_8_mmi; - c->h264_h_loop_filter_chroma_intra = + c->h_loop_filter_chroma_intra = ff_deblock_h_chroma_intra_8_mmi; } - c->h264_v_loop_filter_luma = ff_deblock_v_luma_8_mmi; - c->h264_v_loop_filter_luma_intra = ff_deblock_v_luma_intra_8_mmi; - c->h264_h_loop_filter_luma = ff_deblock_h_luma_8_mmi; - c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_8_mmi; + c->v_loop_filter_luma = ff_deblock_v_luma_8_mmi; + c->v_loop_filter_luma_intra = ff_deblock_v_luma_intra_8_mmi; + c->h_loop_filter_luma = ff_deblock_h_luma_8_mmi; + c->h_loop_filter_luma_intra = ff_deblock_h_luma_intra_8_mmi; } } if (have_msa(cpu_flags)) { if (chroma_format_idc <= 1) - c->h264_loop_filter_strength = ff_h264_loop_filter_strength_msa; + c->loop_filter_strength = ff_h264_loop_filter_strength_msa; if (bit_depth == 8) { - c->h264_v_loop_filter_luma = ff_h264_v_lpf_luma_inter_msa; - c->h264_h_loop_filter_luma = ff_h264_h_lpf_luma_inter_msa; - c->h264_h_loop_filter_luma_mbaff = + c->v_loop_filter_luma = ff_h264_v_lpf_luma_inter_msa; + c->h_loop_filter_luma = ff_h264_h_lpf_luma_inter_msa; + c->h_loop_filter_luma_mbaff = ff_h264_h_loop_filter_luma_mbaff_msa; - c->h264_v_loop_filter_luma_intra = ff_h264_v_lpf_luma_intra_msa; - c->h264_h_loop_filter_luma_intra = ff_h264_h_lpf_luma_intra_msa; - c->h264_h_loop_filter_luma_mbaff_intra = + c->v_loop_filter_luma_intra = ff_h264_v_lpf_luma_intra_msa; + c->h_loop_filter_luma_intra = ff_h264_h_lpf_luma_intra_msa; + c->h_loop_filter_luma_mbaff_intra = ff_h264_h_loop_filter_luma_mbaff_intra_msa; - c->h264_v_loop_filter_chroma = ff_h264_v_lpf_chroma_inter_msa; + c->v_loop_filter_chroma = ff_h264_v_lpf_chroma_inter_msa; if (chroma_format_idc <= 1) - c->h264_h_loop_filter_chroma = ff_h264_h_lpf_chroma_inter_msa; + c->h_loop_filter_chroma = ff_h264_h_lpf_chroma_inter_msa; else - c->h264_h_loop_filter_chroma = + c->h_loop_filter_chroma = ff_h264_h_loop_filter_chroma422_msa; if (chroma_format_idc > 1) - c->h264_h_loop_filter_chroma_mbaff = + c->h_loop_filter_chroma_mbaff = ff_h264_h_loop_filter_chroma422_mbaff_msa; - c->h264_v_loop_filter_chroma_intra = + c->v_loop_filter_chroma_intra = ff_h264_v_lpf_chroma_intra_msa; if (chroma_format_idc <= 1) - c->h264_h_loop_filter_chroma_intra = + c->h_loop_filter_chroma_intra = ff_h264_h_lpf_chroma_intra_msa; /* Weighted MC */ - c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels16_8_msa; - c->weight_h264_pixels_tab[1] = ff_weight_h264_pixels8_8_msa; - c->weight_h264_pixels_tab[2] = ff_weight_h264_pixels4_8_msa; + c->weight_pixels_tab[0] = ff_weight_h264_pixels16_8_msa; + c->weight_pixels_tab[1] = ff_weight_h264_pixels8_8_msa; + c->weight_pixels_tab[2] = ff_weight_h264_pixels4_8_msa; - c->biweight_h264_pixels_tab[0] = ff_biweight_h264_pixels16_8_msa; - c->biweight_h264_pixels_tab[1] = ff_biweight_h264_pixels8_8_msa; - c->biweight_h264_pixels_tab[2] = ff_biweight_h264_pixels4_8_msa; + c->biweight_pixels_tab[0] = ff_biweight_h264_pixels16_8_msa; + c->biweight_pixels_tab[1] = ff_biweight_h264_pixels8_8_msa; + c->biweight_pixels_tab[2] = ff_biweight_h264_pixels4_8_msa; - c->h264_idct_add = ff_h264_idct_add_msa; - c->h264_idct8_add = ff_h264_idct8_addblk_msa; - c->h264_idct_dc_add = ff_h264_idct4x4_addblk_dc_msa; - c->h264_idct8_dc_add = ff_h264_idct8_dc_addblk_msa; - c->h264_idct_add16 = ff_h264_idct_add16_msa; - c->h264_idct8_add4 = ff_h264_idct8_add4_msa; + c->idct_add = ff_h264_idct_add_msa; + c->idct8_add = ff_h264_idct8_addblk_msa; + c->idct_dc_add = ff_h264_idct4x4_addblk_dc_msa; + c->idct8_dc_add = ff_h264_idct8_dc_addblk_msa; + c->idct_add16 = ff_h264_idct_add16_msa; + c->idct8_add4 = ff_h264_idct8_add4_msa; if (chroma_format_idc <= 1) - c->h264_idct_add8 = ff_h264_idct_add8_msa; + c->idct_add8 = ff_h264_idct_add8_msa; else - c->h264_idct_add8 = ff_h264_idct_add8_422_msa; + c->idct_add8 = ff_h264_idct_add8_422_msa; - c->h264_idct_add16intra = ff_h264_idct_add16_intra_msa; - c->h264_luma_dc_dequant_idct = ff_h264_deq_idct_luma_dc_msa; + c->idct_add16intra = ff_h264_idct_add16_intra_msa; + c->luma_dc_dequant_idct = ff_h264_deq_idct_luma_dc_msa; } } } diff --git a/libavcodec/mips/h264pred_mmi.c b/libavcodec/mips/h264pred_mmi.c index 480411f5b..09d4ac169 100644 --- a/libavcodec/mips/h264pred_mmi.c +++ b/libavcodec/mips/h264pred_mmi.c @@ -24,6 +24,7 @@ #include "h264pred_mips.h" #include "libavcodec/bit_depth_template.c" +#include "libavutil/intfloat.h" #include "libavutil/mips/mmiutils.h" #include "constants.h" diff --git a/libavcodec/mips/h264qpel_mmi.c b/libavcodec/mips/h264qpel_mmi.c index 3482956e1..37ab29a44 100644 --- a/libavcodec/mips/h264qpel_mmi.c +++ b/libavcodec/mips/h264qpel_mmi.c @@ -1258,7 +1258,6 @@ static void avg_h264_qpel16_v_lowpass_mmi(uint8_t *dst, const uint8_t *src, static void put_h264_qpel4_hv_lowpass_mmi(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride) { - INIT_CLIP int i; int16_t _tmp[36]; int16_t *tmp = _tmp; @@ -1822,7 +1821,6 @@ static void put_pixels16_l2_shift5_mmi(uint8_t *dst, int16_t *src16, static void avg_h264_qpel4_hv_lowpass_mmi(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride) { - INIT_CLIP int i; int16_t _tmp[36]; int16_t *tmp = _tmp; diff --git a/libavcodec/mips/hevcdsp_mmi.c b/libavcodec/mips/hevcdsp_mmi.c index 6ff52187e..30a3030d0 100644 --- a/libavcodec/mips/hevcdsp_mmi.c +++ b/libavcodec/mips/hevcdsp_mmi.c @@ -21,6 +21,7 @@ #include "libavcodec/hevc/hevcdec.h" #include "libavcodec/bit_depth_template.c" #include "libavcodec/mips/hevcdsp_mips.h" +#include "libavutil/intfloat.h" #include "libavutil/mips/mmiutils.h" #define PUT_HEVC_QPEL_H(w, x_step, src_step, dst_step) \ diff --git a/libavcodec/mips/iirfilter_mips.c b/libavcodec/mips/iirfilter_mips.c deleted file mode 100644 index 3a1352a7e..000000000 --- a/libavcodec/mips/iirfilter_mips.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * 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: Bojan Zivkovic (bojan@mips.com) - * - * IIR filter optimized for MIPS floating-point architecture - * - * 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 - * Reference: libavcodec/iirfilter.c - */ - -#include "config.h" -#include "libavcodec/iirfilter.h" - -#if HAVE_INLINE_ASM -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 -typedef struct FFIIRFilterCoeffs { - int order; - float gain; - int *cx; - float *cy; -} FFIIRFilterCoeffs; - -typedef struct FFIIRFilterState { - float x[1]; -} FFIIRFilterState; - -static void iir_filter_flt_mips(const struct FFIIRFilterCoeffs *c, - struct FFIIRFilterState *s, int size, - const float *src, ptrdiff_t sstep, float *dst, ptrdiff_t dstep) -{ - if (c->order == 2) { - int i; - const float *src0 = src; - float *dst0 = dst; - for (i = 0; i < size; i++) { - float in = *src0 * c->gain + s->x[0] * c->cy[0] + s->x[1] * c->cy[1]; - *dst0 = s->x[0] + in + s->x[1] * c->cx[1]; - s->x[0] = s->x[1]; - s->x[1] = in; - src0 += sstep; - dst0 += dstep; - } - } else if (c->order == 4) { - int i; - const float *src0 = src; - float *dst0 = dst; - float four = 4.0; - float six = 6.0; - for (i = 0; i < size; i += 4) { - float in1, in2, in3, in4; - float res1, res2, res3, res4; - float *x = s->x; - float *cy = c->cy; - float gain = c->gain; - float src0_0 = src0[0 ]; - float src0_1 = src0[sstep ]; - float src0_2 = src0[2*sstep]; - float src0_3 = src0[3*sstep]; - - __asm__ volatile ( - "lwc1 $f0, 0(%[cy]) \n\t" - "lwc1 $f4, 0(%[x]) \n\t" - "lwc1 $f5, 4(%[x]) \n\t" - "lwc1 $f6, 8(%[x]) \n\t" - "lwc1 $f7, 12(%[x]) \n\t" - "mul.s %[in1], %[src0_0], %[gain] \n\t" - "mul.s %[in2], %[src0_1], %[gain] \n\t" - "mul.s %[in3], %[src0_2], %[gain] \n\t" - "mul.s %[in4], %[src0_3], %[gain] \n\t" - "lwc1 $f1, 4(%[cy]) \n\t" - "madd.s %[in1], %[in1], $f0, $f4 \n\t" - "madd.s %[in2], %[in2], $f0, $f5 \n\t" - "madd.s %[in3], %[in3], $f0, $f6 \n\t" - "madd.s %[in4], %[in4], $f0, $f7 \n\t" - "lwc1 $f2, 8(%[cy]) \n\t" - "madd.s %[in1], %[in1], $f1, $f5 \n\t" - "madd.s %[in2], %[in2], $f1, $f6 \n\t" - "madd.s %[in3], %[in3], $f1, $f7 \n\t" - "lwc1 $f3, 12(%[cy]) \n\t" - "add.s $f8, $f5, $f7 \n\t" - "madd.s %[in1], %[in1], $f2, $f6 \n\t" - "madd.s %[in2], %[in2], $f2, $f7 \n\t" - "mul.s $f9, $f6, %[six] \n\t" - "mul.s $f10, $f7, %[six] \n\t" - "madd.s %[in1], %[in1], $f3, $f7 \n\t" - "madd.s %[in2], %[in2], $f3, %[in1] \n\t" - "madd.s %[in3], %[in3], $f2, %[in1] \n\t" - "madd.s %[in4], %[in4], $f1, %[in1] \n\t" - "add.s %[res1], $f4, %[in1] \n\t" - "swc1 %[in1], 0(%[x]) \n\t" - "add.s $f0, $f6, %[in1] \n\t" - "madd.s %[in3], %[in3], $f3, %[in2] \n\t" - "madd.s %[in4], %[in4], $f2, %[in2] \n\t" - "add.s %[res2], $f5, %[in2] \n\t" - "madd.s %[res1], %[res1], $f8, %[four] \n\t" - "add.s $f8, $f7, %[in2] \n\t" - "swc1 %[in2], 4(%[x]) \n\t" - "madd.s %[in4], %[in4], $f3, %[in3] \n\t" - "add.s %[res3], $f6, %[in3] \n\t" - "add.s %[res1], %[res1], $f9 \n\t" - "madd.s %[res2], %[res2], $f0, %[four] \n\t" - "swc1 %[in3], 8(%[x]) \n\t" - "add.s %[res4], $f7, %[in4] \n\t" - "madd.s %[res3], %[res3], $f8, %[four] \n\t" - "swc1 %[in4], 12(%[x]) \n\t" - "add.s %[res2], %[res2], $f10 \n\t" - "add.s $f8, %[in1], %[in3] \n\t" - "madd.s %[res3], %[res3], %[in1], %[six] \n\t" - "madd.s %[res4], %[res4], $f8, %[four] \n\t" - "madd.s %[res4], %[res4], %[in2], %[six] \n\t" - - : [in1]"=&f"(in1), [in2]"=&f"(in2), - [in3]"=&f"(in3), [in4]"=&f"(in4), - [res1]"=&f"(res1), [res2]"=&f"(res2), - [res3]"=&f"(res3), [res4]"=&f"(res4) - : [src0_0]"f"(src0_0), [src0_1]"f"(src0_1), - [src0_2]"f"(src0_2), [src0_3]"f"(src0_3), - [gain]"f"(gain), [x]"r"(x), [cy]"r"(cy), - [four]"f"(four), [six]"f"(six) - : "$f0", "$f1", "$f2", "$f3", - "$f4", "$f5", "$f6", "$f7", - "$f8", "$f9", "$f10", - "memory" - ); - - dst0[0 ] = res1; - dst0[sstep ] = res2; - dst0[2*sstep] = res3; - dst0[3*sstep] = res4; - - src0 += 4*sstep; - dst0 += 4*dstep; - } - } else { - int i; - const float *src0 = src; - float *dst0 = dst; - for (i = 0; i < size; i++) { - int j; - float in, res; - in = *src0 * c->gain; - for(j = 0; j < c->order; j++) - in += c->cy[j] * s->x[j]; - res = s->x[0] + in + s->x[c->order >> 1] * c->cx[c->order >> 1]; - for(j = 1; j < c->order >> 1; j++) - res += (s->x[j] + s->x[c->order - j]) * c->cx[j]; - for(j = 0; j < c->order - 1; j++) - s->x[j] = s->x[j + 1]; - *dst0 = res; - s->x[c->order - 1] = in; - src0 += sstep; - dst0 += dstep; - } - } -} -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_INLINE_ASM */ - -void ff_iir_filter_init_mips(FFIIRFilterContext *f) { -#if HAVE_INLINE_ASM -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 - f->filter_flt = iir_filter_flt_mips; -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_INLINE_ASM */ -} diff --git a/libavcodec/mips/me_cmp_mips.h b/libavcodec/mips/me_cmp_mips.h index 72b7de70b..7e2c926d3 100644 --- a/libavcodec/mips/me_cmp_mips.h +++ b/libavcodec/mips/me_cmp_mips.h @@ -21,38 +21,38 @@ #ifndef AVCODEC_MIPS_ME_CMP_MIPS_H #define AVCODEC_MIPS_ME_CMP_MIPS_H -#include "../mpegvideo.h" +#include "../mpegvideoenc.h" #include "libavcodec/bit_depth_template.c" -int ff_hadamard8_diff8x8_msa(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, +int ff_hadamard8_diff8x8_msa(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h); -int ff_hadamard8_intra8x8_msa(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, +int ff_hadamard8_intra8x8_msa(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h); -int ff_hadamard8_diff16_msa(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, +int ff_hadamard8_diff16_msa(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h); -int ff_hadamard8_intra16_msa(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, +int ff_hadamard8_intra16_msa(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h); -int ff_pix_abs16_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_x2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_x2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_y2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_y2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_xy2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_xy2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_x2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_x2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_y2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_y2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_xy2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_xy2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sse16_msa(MpegEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, +int ff_sse16_msa(MPVEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, ptrdiff_t stride, int i32Height); -int ff_sse8_msa(MpegEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, +int ff_sse8_msa(MPVEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, ptrdiff_t stride, int i32Height); -int ff_sse4_msa(MpegEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, +int ff_sse4_msa(MPVEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, ptrdiff_t stride, int i32Height); void ff_add_pixels8_msa(const uint8_t *restrict pixels, int16_t *block, ptrdiff_t stride); diff --git a/libavcodec/mips/me_cmp_msa.c b/libavcodec/mips/me_cmp_msa.c index 351494161..8ecc6352e 100644 --- a/libavcodec/mips/me_cmp_msa.c +++ b/libavcodec/mips/me_cmp_msa.c @@ -732,79 +732,79 @@ static int32_t hadamard_intra_8x8_msa(const uint8_t *src, int32_t src_stride, return sum_res; } -int ff_pix_abs16_msa(MpegEncContext *v, const uint8_t *src, const uint8_t *ref, +int ff_pix_abs16_msa(MPVEncContext *v, const uint8_t *src, const uint8_t *ref, ptrdiff_t stride, int height) { return sad_16width_msa(src, stride, ref, stride, height); } -int ff_pix_abs8_msa(MpegEncContext *v, const uint8_t *src, const uint8_t *ref, +int ff_pix_abs8_msa(MPVEncContext *v, const uint8_t *src, const uint8_t *ref, ptrdiff_t stride, int height) { return sad_8width_msa(src, stride, ref, stride, height); } -int ff_pix_abs16_x2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_x2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_horiz_bilinear_filter_16width_msa(pix1, stride, pix2, stride, h); } -int ff_pix_abs16_y2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_y2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_vert_bilinear_filter_16width_msa(pix1, stride, pix2, stride, h); } -int ff_pix_abs16_xy2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_xy2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_hv_bilinear_filter_16width_msa(pix1, stride, pix2, stride, h); } -int ff_pix_abs8_x2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_x2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_horiz_bilinear_filter_8width_msa(pix1, stride, pix2, stride, h); } -int ff_pix_abs8_y2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_y2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_vert_bilinear_filter_8width_msa(pix1, stride, pix2, stride, h); } -int ff_pix_abs8_xy2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_xy2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_hv_bilinear_filter_8width_msa(pix1, stride, pix2, stride, h); } -int ff_sse16_msa(MpegEncContext *v, const uint8_t *src, const uint8_t *ref, +int ff_sse16_msa(MPVEncContext *v, const uint8_t *src, const uint8_t *ref, ptrdiff_t stride, int height) { return sse_16width_msa(src, stride, ref, stride, height); } -int ff_sse8_msa(MpegEncContext *v, const uint8_t *src, const uint8_t *ref, +int ff_sse8_msa(MPVEncContext *v, const uint8_t *src, const uint8_t *ref, ptrdiff_t stride, int height) { return sse_8width_msa(src, stride, ref, stride, height); } -int ff_sse4_msa(MpegEncContext *v, const uint8_t *src, const uint8_t *ref, +int ff_sse4_msa(MPVEncContext *v, const uint8_t *src, const uint8_t *ref, ptrdiff_t stride, int height) { return sse_4width_msa(src, stride, ref, stride, height); } -int ff_hadamard8_diff8x8_msa(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, +int ff_hadamard8_diff8x8_msa(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) { return hadamard_diff_8x8_msa(src, stride, dst, stride); } -int ff_hadamard8_intra8x8_msa(MpegEncContext *s, const uint8_t *src, const uint8_t *dummy, +int ff_hadamard8_intra8x8_msa(MPVEncContext *s, const uint8_t *src, const uint8_t *dummy, ptrdiff_t stride, int h) { return hadamard_intra_8x8_msa(src, stride, dummy, stride); @@ -812,7 +812,7 @@ int ff_hadamard8_intra8x8_msa(MpegEncContext *s, const uint8_t *src, const uint8 /* Hadamard Transform functions */ #define WRAPPER8_16_SQ(name8, name16) \ -int name16(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, \ +int name16(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, \ ptrdiff_t stride, int h) \ { \ int score = 0; \ diff --git a/libavcodec/mips/mpegvideo_init_mips.c b/libavcodec/mips/mpegvideo_init_mips.c index 1d02b0c93..75c88a131 100644 --- a/libavcodec/mips/mpegvideo_init_mips.c +++ b/libavcodec/mips/mpegvideo_init_mips.c @@ -20,10 +20,12 @@ #include "libavutil/attributes.h" #include "libavutil/mips/cpu.h" +#include "libavcodec/mpegvideo_unquantize.h" #include "h263dsp_mips.h" #include "mpegvideo_mips.h" -av_cold void ff_mpv_common_init_mips(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_mips(MPVUnquantDSPContext *s, + int bitexact, int q_scale_type) { int cpu_flags = av_get_cpu_flags(); @@ -33,15 +35,15 @@ av_cold void ff_mpv_common_init_mips(MpegEncContext *s) s->dct_unquantize_mpeg1_intra = ff_dct_unquantize_mpeg1_intra_mmi; s->dct_unquantize_mpeg1_inter = ff_dct_unquantize_mpeg1_inter_mmi; - if (!(s->avctx->flags & AV_CODEC_FLAG_BITEXACT)) - if (!s->q_scale_type) + if (!bitexact) + if (!q_scale_type) s->dct_unquantize_mpeg2_intra = ff_dct_unquantize_mpeg2_intra_mmi; } if (have_msa(cpu_flags)) { s->dct_unquantize_h263_intra = ff_dct_unquantize_h263_intra_msa; s->dct_unquantize_h263_inter = ff_dct_unquantize_h263_inter_msa; - if (!s->q_scale_type) + if (!q_scale_type) s->dct_unquantize_mpeg2_inter = ff_dct_unquantize_mpeg2_inter_msa; } } diff --git a/libavcodec/mips/mpegvideo_mips.h b/libavcodec/mips/mpegvideo_mips.h index 760d7b329..2544279ac 100644 --- a/libavcodec/mips/mpegvideo_mips.h +++ b/libavcodec/mips/mpegvideo_mips.h @@ -23,16 +23,16 @@ #include "libavcodec/mpegvideo.h" -void ff_dct_unquantize_h263_intra_mmi(MpegEncContext *s, int16_t *block, - int n, int qscale); -void ff_dct_unquantize_h263_inter_mmi(MpegEncContext *s, int16_t *block, - int n, int qscale); -void ff_dct_unquantize_mpeg1_intra_mmi(MpegEncContext *s, int16_t *block, - int n, int qscale); -void ff_dct_unquantize_mpeg1_inter_mmi(MpegEncContext *s, int16_t *block, - int n, int qscale); -void ff_dct_unquantize_mpeg2_intra_mmi(MpegEncContext *s, int16_t *block, - int n, int qscale); -void ff_denoise_dct_mmi(MpegEncContext *s, int16_t *block); +void ff_dct_unquantize_h263_intra_mmi(const MPVContext *s, int16_t *block, + int n, int qscale); +void ff_dct_unquantize_h263_inter_mmi(const MPVContext *s, int16_t *block, + int n, int qscale); +void ff_dct_unquantize_mpeg1_intra_mmi(const MPVContext *s, int16_t *block, + int n, int qscale); +void ff_dct_unquantize_mpeg1_inter_mmi(const MPVContext *s, int16_t *block, + int n, int qscale); +void ff_dct_unquantize_mpeg2_intra_mmi(const MPVContext *s, int16_t *block, + int n, int qscale); +void ff_denoise_dct_mmi(int16_t block[64], int sum[64], const uint16_t offset[64]); #endif /* AVCODEC_MIPS_MPEGVIDEO_MIPS_H */ diff --git a/libavcodec/mips/mpegvideo_mmi.c b/libavcodec/mips/mpegvideo_mmi.c index 7af421db6..90bd90c14 100644 --- a/libavcodec/mips/mpegvideo_mmi.c +++ b/libavcodec/mips/mpegvideo_mmi.c @@ -25,8 +25,8 @@ #include "mpegvideo_mips.h" #include "libavutil/mips/mmiutils.h" -void ff_dct_unquantize_h263_intra_mmi(MpegEncContext *s, int16_t *block, - int n, int qscale) +void ff_dct_unquantize_h263_intra_mmi(const MPVContext *s, int16_t *block, + int n, int qscale) { int64_t level, nCoeffs; double ftmp[6]; @@ -101,8 +101,8 @@ void ff_dct_unquantize_h263_intra_mmi(MpegEncContext *s, int16_t *block, block[0] = level; } -void ff_dct_unquantize_h263_inter_mmi(MpegEncContext *s, int16_t *block, - int n, int qscale) +void ff_dct_unquantize_h263_inter_mmi(const MPVContext *s, int16_t *block, + int n, int qscale) { int64_t nCoeffs; double ftmp[6]; @@ -160,8 +160,8 @@ void ff_dct_unquantize_h263_inter_mmi(MpegEncContext *s, int16_t *block, ); } -void ff_dct_unquantize_mpeg1_intra_mmi(MpegEncContext *s, int16_t *block, - int n, int qscale) +void ff_dct_unquantize_mpeg1_intra_mmi(const MPVContext *s, int16_t *block, + int n, int qscale) { int64_t nCoeffs; const uint16_t *quant_matrix; @@ -254,8 +254,8 @@ void ff_dct_unquantize_mpeg1_intra_mmi(MpegEncContext *s, int16_t *block, block[0] = block0; } -void ff_dct_unquantize_mpeg1_inter_mmi(MpegEncContext *s, int16_t *block, - int n, int qscale) +void ff_dct_unquantize_mpeg1_inter_mmi(const MPVContext *s, int16_t *block, + int n, int qscale) { int64_t nCoeffs; const uint16_t *quant_matrix; @@ -342,8 +342,8 @@ void ff_dct_unquantize_mpeg1_inter_mmi(MpegEncContext *s, int16_t *block, ); } -void ff_dct_unquantize_mpeg2_intra_mmi(MpegEncContext *s, int16_t *block, - int n, int qscale) +void ff_dct_unquantize_mpeg2_intra_mmi(const MPVContext *s, int16_t *block, + int n, int qscale) { uint64_t nCoeffs; const uint16_t *quant_matrix; @@ -356,10 +356,7 @@ void ff_dct_unquantize_mpeg2_intra_mmi(MpegEncContext *s, int16_t *block, assert(s->block_last_index[n]>=0); - if (s->alternate_scan) - nCoeffs = 63; - else - nCoeffs = s->intra_scantable.raster_end[s->block_last_index[n]]; + nCoeffs = s->intra_scantable.raster_end[s->block_last_index[n]]; if (n < 4) block0 = block[0] * s->y_dc_scale; diff --git a/libavcodec/mips/mpegvideo_msa.c b/libavcodec/mips/mpegvideo_msa.c index aa9ef770e..a870a2cd7 100644 --- a/libavcodec/mips/mpegvideo_msa.c +++ b/libavcodec/mips/mpegvideo_msa.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/mips/generic_macros_msa.h" #include "h263dsp_mips.h" @@ -193,7 +194,7 @@ static int32_t mpeg2_dct_unquantize_inter_msa(int16_t *block, return sum_res; } -void ff_dct_unquantize_h263_intra_msa(MpegEncContext *s, +void ff_dct_unquantize_h263_intra_msa(const MPVContext *s, int16_t *block, int32_t index, int32_t qscale) { @@ -218,7 +219,7 @@ void ff_dct_unquantize_h263_intra_msa(MpegEncContext *s, h263_dct_unquantize_msa(block, qmul, qadd, nCoeffs, 1); } -void ff_dct_unquantize_h263_inter_msa(MpegEncContext *s, +void ff_dct_unquantize_h263_inter_msa(const MPVContext *s, int16_t *block, int32_t index, int32_t qscale) { @@ -235,7 +236,7 @@ void ff_dct_unquantize_h263_inter_msa(MpegEncContext *s, h263_dct_unquantize_msa(block, qmul, qadd, nCoeffs, 0); } -void ff_dct_unquantize_mpeg2_inter_msa(MpegEncContext *s, +void ff_dct_unquantize_mpeg2_inter_msa(const MPVContext *s, int16_t *block, int32_t index, int32_t qscale) { diff --git a/libavcodec/mips/mpegvideoencdsp_init_mips.c b/libavcodec/mips/mpegvideoencdsp_init_mips.c index 3efbeec34..df916282a 100644 --- a/libavcodec/mips/mpegvideoencdsp_init_mips.c +++ b/libavcodec/mips/mpegvideoencdsp_init_mips.c @@ -21,13 +21,19 @@ #include "libavutil/attributes.h" #include "libavutil/mips/cpu.h" #include "libavcodec/bit_depth_template.c" +#include "libavcodec/mpegvideoencdsp.h" #include "h263dsp_mips.h" +#include "mpegvideo_mips.h" av_cold void ff_mpegvideoencdsp_init_mips(MpegvideoEncDSPContext *c, AVCodecContext *avctx) { int cpu_flags = av_get_cpu_flags(); + if (have_mmi(cpu_flags)) { + c->denoise_dct = ff_denoise_dct_mmi; + } + if (have_msa(cpu_flags)) { #if BIT_DEPTH == 8 c->pix_sum = ff_pix_sum_msa; diff --git a/libavcodec/mips/mpegvideoenc_mmi.c b/libavcodec/mips/mpegvideoencdsp_mmi.c similarity index 95% rename from libavcodec/mips/mpegvideoenc_mmi.c rename to libavcodec/mips/mpegvideoencdsp_mmi.c index 65da155e9..2239a0597 100644 --- a/libavcodec/mips/mpegvideoenc_mmi.c +++ b/libavcodec/mips/mpegvideoencdsp_mmi.c @@ -25,17 +25,12 @@ #include "mpegvideo_mips.h" #include "libavutil/mips/mmiutils.h" -void ff_denoise_dct_mmi(MpegEncContext *s, int16_t *block) +void ff_denoise_dct_mmi(int16_t block[64], int sum[64], const uint16_t offset[64]) { - const int intra = s->mb_intra; - int *sum = s->dct_error_sum[intra]; - uint16_t *offset = s->dct_offset[intra]; double ftmp[8]; mips_reg addr[1]; DECLARE_VAR_ALL64; - s->dct_count[intra]++; - __asm__ volatile( "pxor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" "1: \n\t" diff --git a/libavcodec/mips/pixblockdsp_init_mips.c b/libavcodec/mips/pixblockdsp_init_mips.c index 2e2d70953..acea95d36 100644 --- a/libavcodec/mips/pixblockdsp_init_mips.c +++ b/libavcodec/mips/pixblockdsp_init_mips.c @@ -20,9 +20,10 @@ */ #include "libavutil/mips/cpu.h" +#include "libavcodec/pixblockdsp.h" #include "pixblockdsp_mips.h" -void ff_pixblockdsp_init_mips(PixblockDSPContext *c, AVCodecContext *avctx, +void ff_pixblockdsp_init_mips(PixblockDSPContext *c, unsigned high_bit_depth) { int cpu_flags = av_get_cpu_flags(); @@ -30,27 +31,13 @@ void ff_pixblockdsp_init_mips(PixblockDSPContext *c, AVCodecContext *avctx, if (have_mmi(cpu_flags)) { c->diff_pixels = ff_diff_pixels_mmi; - if (!high_bit_depth || avctx->codec_type != AVMEDIA_TYPE_VIDEO) { + if (!high_bit_depth) c->get_pixels = ff_get_pixels_8_mmi; - } } if (have_msa(cpu_flags)) { c->diff_pixels = ff_diff_pixels_msa; - switch (avctx->bits_per_raw_sample) { - case 9: - case 10: - case 12: - case 14: - c->get_pixels = ff_get_pixels_16_msa; - break; - default: - if (avctx->bits_per_raw_sample <= 8 || avctx->codec_type != - AVMEDIA_TYPE_VIDEO) { - c->get_pixels = ff_get_pixels_8_msa; - } - break; - } + c->get_pixels = high_bit_depth ? ff_get_pixels_16_msa : ff_get_pixels_8_msa; } } diff --git a/libavcodec/mips/pixblockdsp_mips.h b/libavcodec/mips/pixblockdsp_mips.h index 7fd137cd0..fc387ea42 100644 --- a/libavcodec/mips/pixblockdsp_mips.h +++ b/libavcodec/mips/pixblockdsp_mips.h @@ -22,7 +22,8 @@ #ifndef AVCODEC_MIPS_PIXBLOCKDSP_MIPS_H #define AVCODEC_MIPS_PIXBLOCKDSP_MIPS_H -#include "../mpegvideo.h" +#include +#include void ff_diff_pixels_msa(int16_t *restrict block, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride); diff --git a/libavcodec/mips/vp3dsp_init_mips.c b/libavcodec/mips/vp3dsp_init_mips.c index 4252ff790..7388386d2 100644 --- a/libavcodec/mips/vp3dsp_init_mips.c +++ b/libavcodec/mips/vp3dsp_init_mips.c @@ -26,7 +26,7 @@ #include "libavcodec/vp3dsp.h" #include "vp3dsp_mips.h" -av_cold void ff_vp3dsp_init_mips(VP3DSPContext *c, int flags) +av_cold void ff_vp3dsp_init_mips(VP3DSPContext *c) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/mips/vp8dsp_mmi.c b/libavcodec/mips/vp8dsp_mmi.c index bc774aa36..6de405bfb 100644 --- a/libavcodec/mips/vp8dsp_mmi.c +++ b/libavcodec/mips/vp8dsp_mmi.c @@ -24,6 +24,7 @@ #include "vp8dsp_mips.h" #include "constants.h" #include "libavutil/attributes.h" +#include "libavutil/intfloat.h" #include "libavutil/mips/mmiutils.h" #include "libavutil/mem_internal.h" @@ -668,10 +669,10 @@ static const uint8_t subpel_filters[7][6] = { static av_always_inline void vp8_filter_common_is4tap(uint8_t *p, ptrdiff_t stride) { - int av_unused p1 = p[-2 * stride]; - int av_unused p0 = p[-1 * stride]; - int av_unused q0 = p[ 0 * stride]; - int av_unused q1 = p[ 1 * stride]; + av_unused int p1 = p[-2 * stride]; + av_unused int p0 = p[-1 * stride]; + av_unused int q0 = p[ 0 * stride]; + av_unused int q1 = p[ 1 * stride]; int a, f1, f2; const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; @@ -693,10 +694,10 @@ static av_always_inline void vp8_filter_common_is4tap(uint8_t *p, static av_always_inline void vp8_filter_common_isnot4tap(uint8_t *p, ptrdiff_t stride) { - int av_unused p1 = p[-2 * stride]; - int av_unused p0 = p[-1 * stride]; - int av_unused q0 = p[ 0 * stride]; - int av_unused q1 = p[ 1 * stride]; + av_unused int p1 = p[-2 * stride]; + av_unused int p0 = p[-1 * stride]; + av_unused int q0 = p[ 0 * stride]; + av_unused int q1 = p[ 1 * stride]; int a, f1, f2; const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; @@ -720,20 +721,20 @@ static av_always_inline void vp8_filter_common_isnot4tap(uint8_t *p, static av_always_inline int vp8_simple_limit(uint8_t *p, ptrdiff_t stride, int flim) { - int av_unused p1 = p[-2 * stride]; - int av_unused p0 = p[-1 * stride]; - int av_unused q0 = p[ 0 * stride]; - int av_unused q1 = p[ 1 * stride]; + av_unused int p1 = p[-2 * stride]; + av_unused int p0 = p[-1 * stride]; + av_unused int q0 = p[ 0 * stride]; + av_unused int q1 = p[ 1 * stride]; return 2 * FFABS(p0 - q0) + (FFABS(p1 - q1) >> 1) <= flim; } static av_always_inline int hev(uint8_t *p, ptrdiff_t stride, int thresh) { - int av_unused p1 = p[-2 * stride]; - int av_unused p0 = p[-1 * stride]; - int av_unused q0 = p[ 0 * stride]; - int av_unused q1 = p[ 1 * stride]; + av_unused int p1 = p[-2 * stride]; + av_unused int p0 = p[-1 * stride]; + av_unused int q0 = p[ 0 * stride]; + av_unused int q1 = p[ 1 * stride]; return FFABS(p1 - p0) > thresh || FFABS(q1 - q0) > thresh; } @@ -743,12 +744,12 @@ static av_always_inline void filter_mbedge(uint8_t *p, ptrdiff_t stride) int a0, a1, a2, w; const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; - int av_unused p2 = p[-3 * stride]; - int av_unused p1 = p[-2 * stride]; - int av_unused p0 = p[-1 * stride]; - int av_unused q0 = p[ 0 * stride]; - int av_unused q1 = p[ 1 * stride]; - int av_unused q2 = p[ 2 * stride]; + av_unused int p2 = p[-3 * stride]; + av_unused int p1 = p[-2 * stride]; + av_unused int p0 = p[-1 * stride]; + av_unused int q0 = p[ 0 * stride]; + av_unused int q1 = p[ 1 * stride]; + av_unused int q2 = p[ 2 * stride]; w = clip_int8(p1 - q1); w = clip_int8(w + 3 * (q0 - p0)); @@ -768,14 +769,14 @@ static av_always_inline void filter_mbedge(uint8_t *p, ptrdiff_t stride) static av_always_inline int vp8_normal_limit(uint8_t *p, ptrdiff_t stride, int E, int I) { - int av_unused p3 = p[-4 * stride]; - int av_unused p2 = p[-3 * stride]; - int av_unused p1 = p[-2 * stride]; - int av_unused p0 = p[-1 * stride]; - int av_unused q0 = p[ 0 * stride]; - int av_unused q1 = p[ 1 * stride]; - int av_unused q2 = p[ 2 * stride]; - int av_unused q3 = p[ 3 * stride]; + av_unused int p3 = p[-4 * stride]; + av_unused int p2 = p[-3 * stride]; + av_unused int p1 = p[-2 * stride]; + av_unused int p0 = p[-1 * stride]; + av_unused int q0 = p[ 0 * stride]; + av_unused int q1 = p[ 1 * stride]; + av_unused int q2 = p[ 2 * stride]; + av_unused int q3 = p[ 3 * stride]; return vp8_simple_limit(p, stride, E) && FFABS(p3 - p2) <= I && FFABS(p2 - p1) <= I && diff --git a/libavcodec/mips/wmv2dsp_init_mips.c b/libavcodec/mips/wmv2dsp_init_mips.c index af1400731..e48413b9a 100644 --- a/libavcodec/mips/wmv2dsp_init_mips.c +++ b/libavcodec/mips/wmv2dsp_init_mips.c @@ -21,9 +21,11 @@ #include "libavutil/mips/cpu.h" #include "config.h" #include "libavutil/attributes.h" +#include "libavcodec/idctdsp.h" +#include "libavcodec/wmv2dsp.h" #include "wmv2dsp_mips.h" -av_cold void ff_wmv2dsp_init_mips(WMV2DSPContext *c) +av_cold void ff_wmv2dsp_init_mips(IDCTDSPContext *c) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/mips/wmv2dsp_mips.h b/libavcodec/mips/wmv2dsp_mips.h index c96b3d94c..94fbd8f6b 100644 --- a/libavcodec/mips/wmv2dsp_mips.h +++ b/libavcodec/mips/wmv2dsp_mips.h @@ -21,7 +21,8 @@ #ifndef AVCODEC_MIPS_WMV2DSP_MIPS_H #define AVCODEC_MIPS_WMV2DSP_MIPS_H -#include "libavcodec/wmv2dsp.h" +#include +#include void ff_wmv2_idct_add_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block); void ff_wmv2_idct_put_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block); diff --git a/libavcodec/mips/xvididct_init_mips.c b/libavcodec/mips/xvididct_init_mips.c index 658a5792e..524cf8dcd 100644 --- a/libavcodec/mips/xvididct_init_mips.c +++ b/libavcodec/mips/xvididct_init_mips.c @@ -22,20 +22,14 @@ #include "libavutil/mips/cpu.h" #include "xvididct_mips.h" -av_cold void ff_xvid_idct_init_mips(IDCTDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth) +av_cold void ff_xvid_idct_init_mips(IDCTDSPContext *c) { int cpu_flags = av_get_cpu_flags(); if (have_mmi(cpu_flags)) { - if (!high_bit_depth) { - if (avctx->idct_algo == FF_IDCT_AUTO || - avctx->idct_algo == FF_IDCT_XVID) { - c->idct_put = ff_xvid_idct_put_mmi; - c->idct_add = ff_xvid_idct_add_mmi; - c->idct = ff_xvid_idct_mmi; - c->perm_type = FF_IDCT_PERM_NONE; - } - } + c->idct_put = ff_xvid_idct_put_mmi; + c->idct_add = ff_xvid_idct_add_mmi; + c->idct = ff_xvid_idct_mmi; + c->perm_type = FF_IDCT_PERM_NONE; } } diff --git a/libavcodec/misc4.c b/libavcodec/misc4.c index 72ac944e5..d92c671d1 100644 --- a/libavcodec/misc4.c +++ b/libavcodec/misc4.c @@ -180,10 +180,5 @@ const FFCodec ff_misc4_decoder = { .init = misc4_init, FF_CODEC_DECODE_CB(misc4_decode), .p.capabilities = AV_CODEC_CAP_DR1 | -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/misc4_parser.c b/libavcodec/misc4_parser.c index d234dbb62..df1bbd07b 100644 --- a/libavcodec/misc4_parser.c +++ b/libavcodec/misc4_parser.c @@ -19,6 +19,7 @@ */ #include "parser.h" +#include "parser_internal.h" typedef struct MISC4Context { ParseContext pc; @@ -73,9 +74,9 @@ static int misc4_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_misc4_parser = { - .codec_ids = { AV_CODEC_ID_MISC4 }, +const FFCodecParser ff_misc4_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_MISC4), .priv_data_size = sizeof(MISC4Context), - .parser_parse = misc4_parse, - .parser_close = ff_parse_close, + .parse = misc4_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/mjpeg.h b/libavcodec/mjpeg.h index cd5d0af2a..e66e39714 100644 --- a/libavcodec/mjpeg.h +++ b/libavcodec/mjpeg.h @@ -100,7 +100,7 @@ enum JpegMarker { JPG4 = 0xf4, JPG5 = 0xf5, JPG6 = 0xf6, - SOF48 = 0xf7, ///< JPEG-LS + SOF55 = 0xf7, ///< JPEG-LS LSE = 0xf8, ///< JPEG-LS extension parameters JPG9 = 0xf9, JPG10 = 0xfa, diff --git a/libavcodec/mjpeg_parser.c b/libavcodec/mjpeg_parser.c index 62b923b62..66f364d8f 100644 --- a/libavcodec/mjpeg_parser.c +++ b/libavcodec/mjpeg_parser.c @@ -27,6 +27,7 @@ */ #include "parser.h" +#include "parser_internal.h" typedef struct MJPEGParserContext{ ParseContext pc; @@ -128,9 +129,9 @@ static int jpeg_parse(AVCodecParserContext *s, } -const AVCodecParser ff_mjpeg_parser = { - .codec_ids = { AV_CODEC_ID_MJPEG, AV_CODEC_ID_JPEGLS }, +const FFCodecParser ff_mjpeg_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_MJPEG, AV_CODEC_ID_JPEGLS), .priv_data_size = sizeof(MJPEGParserContext), - .parser_parse = jpeg_parse, - .parser_close = ff_parse_close, + .parse = jpeg_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/mjpegbdec.c b/libavcodec/mjpegbdec.c index 4db1d9a89..e627ab810 100644 --- a/libavcodec/mjpegbdec.c +++ b/libavcodec/mjpegbdec.c @@ -61,7 +61,6 @@ static int mjpegb_decode_frame(AVCodecContext *avctx, AVFrame *rframe, read_header: /* reset on every SOI */ s->restart_interval = 0; - s->restart_count = 0; s->mjpb_skiptosod = 0; if ((ret = init_get_bits8(&hgb, buf_ptr, /*buf_size*/(buf_end - buf_ptr))) < 0) @@ -84,8 +83,7 @@ read_header: dqt_offs = read_offs(avctx, &hgb, buf_end - buf_ptr, "dqt is %d and size is %d\n"); av_log(avctx, AV_LOG_DEBUG, "dqt offs: 0x%"PRIx32"\n", dqt_offs); if (dqt_offs) { - init_get_bits(&s->gb, buf_ptr+dqt_offs, (buf_end - (buf_ptr+dqt_offs))*8); - s->start_code = DQT; + bytestream2_init(&s->gB, buf_ptr+dqt_offs, buf_end - (buf_ptr+dqt_offs)); ret = ff_mjpeg_decode_dqt(s); if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) return ret; @@ -94,16 +92,14 @@ read_header: dht_offs = read_offs(avctx, &hgb, buf_end - buf_ptr, "dht is %d and size is %d\n"); av_log(avctx, AV_LOG_DEBUG, "dht offs: 0x%"PRIx32"\n", dht_offs); if (dht_offs) { - init_get_bits(&s->gb, buf_ptr+dht_offs, (buf_end - (buf_ptr+dht_offs))*8); - s->start_code = DHT; + bytestream2_init(&s->gB, buf_ptr+dht_offs, buf_end - (buf_ptr+dht_offs)); ff_mjpeg_decode_dht(s); } sof_offs = read_offs(avctx, &hgb, buf_end - buf_ptr, "sof is %d and size is %d\n"); av_log(avctx, AV_LOG_DEBUG, "sof offs: 0x%"PRIx32"\n", sof_offs); if (sof_offs) { - init_get_bits(&s->gb, buf_ptr+sof_offs, (buf_end - (buf_ptr+sof_offs))*8); - s->start_code = SOF0; + bytestream2_init(&s->gB, buf_ptr+sof_offs, buf_end - (buf_ptr+sof_offs)); if ((ret = ff_mjpeg_decode_sof(s)) < 0) return ret; } @@ -113,14 +109,13 @@ read_header: sod_offs = read_offs(avctx, &hgb, buf_end - buf_ptr, "sof is %d and size is %d\n"); av_log(avctx, AV_LOG_DEBUG, "sod offs: 0x%"PRIx32"\n", sod_offs); if (sos_offs) { - init_get_bits(&s->gb, buf_ptr + sos_offs, - 8 * FFMIN(field_size, buf_end - buf_ptr - sos_offs)); - s->mjpb_skiptosod = (sod_offs - sos_offs - show_bits(&s->gb, 16)); - s->start_code = SOS; + bytestream2_init(&s->gB, buf_ptr+sos_offs, + FFMIN(field_size, buf_end - buf_ptr - sos_offs)); + s->mjpb_skiptosod = (sod_offs - sos_offs - bytestream2_peek_be16(&s->gB)); if (avctx->skip_frame == AVDISCARD_ALL) { - skip_bits(&s->gb, get_bits_left(&s->gb)); + bytestream2_skipu(&s->gB, bytestream2_get_bytes_left(&s->gB)); } else { - ret = ff_mjpeg_decode_sos(s, NULL, 0, NULL); + ret = ff_mjpeg_decode_sos(s); if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) return ret; } diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index 66c98b60b..9c8b846a7 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -32,8 +32,7 @@ #include "config_components.h" -#include "libavutil/display.h" -#include "libavutil/emms.h" +#include "libavutil/attributes.h" #include "libavutil/imgutils.h" #include "libavutil/avassert.h" #include "libavutil/mem.h" @@ -43,6 +42,7 @@ #include "codec_internal.h" #include "copy_block.h" #include "decode.h" +#include "exif.h" #include "hwaccel_internal.h" #include "hwconfig.h" #include "idctdsp.h" @@ -53,11 +53,11 @@ #include "jpeglsdec.h" #include "profiles.h" #include "put_bits.h" -#include "exif.h" -#include "bytestream.h" -#include "tiff_common.h" +static void mjpeg_find_raw_scan_data(MJpegDecodeContext *s, + const uint8_t **pbuf_ptr, size_t *pbuf_size); + static int init_default_huffman_tables(MJpegDecodeContext *s) { static const struct { @@ -103,13 +103,12 @@ static int init_default_huffman_tables(MJpegDecodeContext *s) static void parse_avid(MJpegDecodeContext *s, uint8_t *buf, int len) { - s->buggy_avid = 1; - if (len > 14 && buf[12] == 1) /* 1 - NTSC */ + if (len > 12 && buf[12] == 1) /* 1 - NTSC */ s->interlace_polarity = 1; - if (len > 14 && buf[12] == 2) /* 2 - PAL */ + if (len > 12 && buf[12] == 2) /* 2 - PAL */ s->interlace_polarity = 0; if (s->avctx->debug & FF_DEBUG_PICT_INFO) - av_log(s->avctx, AV_LOG_INFO, "AVID: len:%d %d\n", len, len > 14 ? buf[12] : -1); + av_log(s->avctx, AV_LOG_INFO, "AVID: len:%d %d\n", len, len > 12 ? buf[12] : -1); } static void init_idct(AVCodecContext *avctx) @@ -135,11 +134,9 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx) s->avctx = avctx; ff_blockdsp_init(&s->bdsp); - ff_hpeldsp_init(&s->hdsp, avctx->flags); init_idct(avctx); s->buffer_size = 0; s->buffer = NULL; - s->start_code = -1; s->first_picture = 1; s->got_picture = 0; s->orig_height = avctx->coded_height; @@ -152,8 +149,7 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx) if (s->extern_huff && avctx->extradata) { av_log(avctx, AV_LOG_INFO, "using external huffman table\n"); - if ((ret = init_get_bits(&s->gb, avctx->extradata, avctx->extradata_size * 8)) < 0) - return ret; + bytestream2_init(&s->gB, avctx->extradata, avctx->extradata_size); if (ff_mjpeg_decode_dht(s)) { av_log(avctx, AV_LOG_ERROR, "error using external huffman table, switching back to internal\n"); @@ -183,7 +179,7 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); } else if (avctx->extradata_size > 8 && AV_RL32(avctx->extradata) == 0x2C - && AV_RL32(avctx->extradata+4) == 0x18) { + && AV_RL32(avctx->extradata + 4) == 0x18) { parse_avid(s, avctx->extradata, avctx->extradata_size); } @@ -194,31 +190,42 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx) } +static int mjpeg_parse_len(MJpegDecodeContext *s, int *plen, const char *name) +{ + int len = bytestream2_get_be16u(&s->gB); + if (len < 2 || bytestream2_get_bytes_left(&s->gB) < (len - 2)) { + av_log(s->avctx, AV_LOG_ERROR, "%s: invalid len %d\n", name, len); + return AVERROR_INVALIDDATA; + } + *plen = len - 2; + return 0; +} + /* quantize tables */ int ff_mjpeg_decode_dqt(MJpegDecodeContext *s) { int len, index, i; - len = get_bits(&s->gb, 16) - 2; - - if (8*len > get_bits_left(&s->gb)) { - av_log(s->avctx, AV_LOG_ERROR, "dqt: len %d is too large\n", len); - return AVERROR_INVALIDDATA; - } + int ret = mjpeg_parse_len(s, &len, "dqt"); + if (ret < 0) + return ret; while (len >= 65) { - int pr = get_bits(&s->gb, 4); + uint8_t b = bytestream2_get_byteu(&s->gB); + int pr = b >> 4; if (pr > 1) { av_log(s->avctx, AV_LOG_ERROR, "dqt: invalid precision\n"); return AVERROR_INVALIDDATA; } - index = get_bits(&s->gb, 4); + if (len < (1 + 64 * (1 + pr))) + return AVERROR_INVALIDDATA; + index = b & 0x0F; if (index >= 4) - return -1; + return AVERROR_INVALIDDATA; av_log(s->avctx, AV_LOG_DEBUG, "index=%d\n", index); /* read quant table */ for (i = 0; i < 64; i++) { - s->quant_matrixes[index][i] = get_bits(&s->gb, pr ? 16 : 8); + s->quant_matrixes[index][i] = pr ? bytestream2_get_be16u(&s->gB) : bytestream2_get_byteu(&s->gB); if (s->quant_matrixes[index][i] == 0) { int log_level = s->avctx->err_recognition & AV_EF_EXPLODE ? AV_LOG_ERROR : AV_LOG_WARNING; av_log(s->avctx, log_level, "dqt: 0 quant value\n"); @@ -232,7 +239,7 @@ int ff_mjpeg_decode_dqt(MJpegDecodeContext *s) s->quant_matrixes[index][8]) >> 1; av_log(s->avctx, AV_LOG_DEBUG, "qscale[%d]: %d\n", index, s->qscale[index]); - len -= 1 + 64 * (1+pr); + len -= 1 + 64 * (1 + pr); } return 0; } @@ -245,25 +252,23 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s) uint8_t val_table[256]; int ret = 0; - len = get_bits(&s->gb, 16) - 2; - - if (8*len > get_bits_left(&s->gb)) { - av_log(s->avctx, AV_LOG_ERROR, "dht: len %d is too large\n", len); - return AVERROR_INVALIDDATA; - } + ret = mjpeg_parse_len(s, &len, "dht"); + if (ret < 0) + return ret; while (len > 0) { if (len < 17) return AVERROR_INVALIDDATA; - class = get_bits(&s->gb, 4); + uint8_t b = bytestream2_get_byteu(&s->gB); + class = b >> 4; if (class >= 2) return AVERROR_INVALIDDATA; - index = get_bits(&s->gb, 4); + index = b & 0x0F; if (index >= 4) return AVERROR_INVALIDDATA; n = 0; for (i = 1; i <= 16; i++) { - bits_table[i] = get_bits(&s->gb, 8); + bits_table[i] = bytestream2_get_byteu(&s->gB); n += bits_table[i]; } len -= 17; @@ -271,7 +276,7 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s) return AVERROR_INVALIDDATA; for (i = 0; i < n; i++) { - v = get_bits(&s->gb, 8); + v = bytestream2_get_byteu(&s->gB); val_table[i] = v; } len -= n; @@ -310,8 +315,12 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) memset(s->upscale_h, 0, sizeof(s->upscale_h)); memset(s->upscale_v, 0, sizeof(s->upscale_v)); - len = get_bits(&s->gb, 16); - bits = get_bits(&s->gb, 8); + ret = mjpeg_parse_len(s, &len, "sof"); + if (ret < 0) + return ret; + if (len < 6) + return AVERROR_INVALIDDATA; + bits = bytestream2_get_byteu(&s->gB); if (bits > 16 || bits < 1) { av_log(s->avctx, AV_LOG_ERROR, "bits %d is invalid\n", bits); @@ -328,17 +337,17 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) if (bits == 9 && !s->pegasus_rct) s->rct = 1; // FIXME ugly - if(s->lossless && s->avctx->lowres){ + if (s->lossless && s->avctx->lowres) { av_log(s->avctx, AV_LOG_ERROR, "lowres is not possible with lossless jpeg\n"); - return -1; + return AVERROR(ENOSYS); } - height = get_bits(&s->gb, 16); - width = get_bits(&s->gb, 16); + height = bytestream2_get_be16u(&s->gB); + width = bytestream2_get_be16u(&s->gB); // HACK for odd_height.mov if (s->interlaced && s->width == width && s->height == height + 1) - height= s->height; + height = s->height; av_log(s->avctx, AV_LOG_DEBUG, "sof0: picture: %dx%d\n", width, height); if (av_image_check_size(width, height, 0, s->avctx) < 0) @@ -350,10 +359,10 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) return AVERROR_INVALIDDATA; } - nb_components = get_bits(&s->gb, 8); + nb_components = bytestream2_get_byteu(&s->gB); if (nb_components <= 0 || nb_components > MAX_COMPONENTS) - return -1; + return AVERROR_INVALIDDATA; if (s->interlaced && (s->bottom_field == !s->interlace_polarity)) { if (nb_components != s->nb_components) { av_log(s->avctx, AV_LOG_ERROR, @@ -367,7 +376,8 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) "bits/component or 16-bit gray"); return AVERROR_PATCHWELCOME; } - if (len != 8 + 3 * nb_components) { + len -= 6; + if (len != 3 * nb_components) { av_log(s->avctx, AV_LOG_ERROR, "decode_sof0: error, len(%d) mismatch %d components\n", len, nb_components); return AVERROR_INVALIDDATA; } @@ -377,15 +387,16 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) s->v_max = 1; for (i = 0; i < nb_components; i++) { /* component id */ - s->component_id[i] = get_bits(&s->gb, 8); - h_count[i] = get_bits(&s->gb, 4); - v_count[i] = get_bits(&s->gb, 4); + s->component_id[i] = bytestream2_get_byteu(&s->gB); + uint8_t b = bytestream2_get_byteu(&s->gB); + h_count[i] = b >> 4; + v_count[i] = b & 0x0F; /* compute hmax and vmax (only used in interleaved case) */ if (h_count[i] > s->h_max) s->h_max = h_count[i]; if (v_count[i] > s->v_max) s->v_max = v_count[i]; - s->quant_index[i] = get_bits(&s->gb, 8); + s->quant_index[i] = bytestream2_get_byteu(&s->gB); if (s->quant_index[i] >= 4) { av_log(s->avctx, AV_LOG_ERROR, "quant_index is invalid\n"); return AVERROR_INVALIDDATA; @@ -483,7 +494,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) return AVERROR_INVALIDDATA; } } else { - if (s->v_max == 1 && s->h_max == 1 && s->lossless==1 && (nb_components==3 || nb_components==4)) + if (s->v_max == 1 && s->h_max == 1 && s->lossless == 1 && (nb_components == 3 || nb_components == 4)) s->rgb = 1; else if (!s->lossless) s->rgb = 0; @@ -501,18 +512,18 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) pix_fmt_id -= (pix_fmt_id & 0x0F0F0F0F) >> 1; for (i = 0; i < 8; i++) { - int j = 6 + (i&1) - (i&6); - int is = (pix_fmt_id >> (4*i)) & 0xF; - int js = (pix_fmt_id >> (4*j)) & 0xF; + int j = 6 + (i & 1) - (i & 6); + int is = (pix_fmt_id >> (4 * i)) & 0xF; + int js = (pix_fmt_id >> (4 * j)) & 0xF; if (is == 1 && js != 2 && (i < 2 || i > 5)) - js = (pix_fmt_id >> ( 8 + 4*(i&1))) & 0xF; + js = (pix_fmt_id >> ( 8 + 4 * (i & 1))) & 0xF; if (is == 1 && js != 2 && (i < 2 || i > 5)) - js = (pix_fmt_id >> (16 + 4*(i&1))) & 0xF; + js = (pix_fmt_id >> (16 + 4 * (i & 1))) & 0xF; if (is == 1 && js == 2) { - if (i & 1) s->upscale_h[j/2] = 1; - else s->upscale_v[j/2] = 1; + if (i & 1) s->upscale_h[j / 2] = 1; + else s->upscale_v[j / 2] = 1; } } @@ -537,7 +548,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) } else { if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; else s->avctx->pix_fmt = AV_PIX_FMT_YUV444P16; - s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; + s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; } } av_assert0(s->nb_components == 3); @@ -596,7 +607,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) if (s->bits > 8) goto unk_pixfmt; if (s->adobe_transform == 0 || s->component_id[0] == 'R' && - s->component_id[1] == 'G' && s->component_id[2] == 'B') { + s->component_id[1] == 'G' && s->component_id[2] == 'B') { s->avctx->pix_fmt = AV_PIX_FMT_GBRP; } else { s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; @@ -612,7 +623,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) case 0x41000000: case 0x43000000: case 0x44000000: - if(s->bits <= 8) + if (s->bits <= 8) s->avctx->pix_fmt = s->force_pal8 ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_GRAY8; else s->avctx->pix_fmt = AV_PIX_FMT_GRAY16; @@ -761,8 +772,9 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) } av_frame_unref(s->picture_ptr); - if (ff_get_buffer(s->avctx, s->picture_ptr, AV_GET_BUFFER_FLAG_REF) < 0) - return -1; + ret = ff_get_buffer(s->avctx, s->picture_ptr, AV_GET_BUFFER_FLAG_REF); + if (ret < 0) + return ret; s->picture_ptr->pict_type = AV_PICTURE_TYPE_I; s->picture_ptr->flags |= AV_FRAME_FLAG_KEY; s->got_picture = 1; @@ -812,7 +824,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) if (!s->hwaccel_picture_private) return AVERROR(ENOMEM); - ret = hwaccel->start_frame(s->avctx, s->raw_image_buffer, + ret = hwaccel->start_frame(s->avctx, NULL, s->raw_image_buffer, s->raw_image_buffer_size); if (ret < 0) return ret; @@ -821,21 +833,18 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) return 0; } -static inline int mjpeg_decode_dc(MJpegDecodeContext *s, int dc_index) +static inline int mjpeg_decode_dc(MJpegDecodeContext *s, int dc_index, int *val) { int code; code = get_vlc2(&s->gb, s->vlcs[0][dc_index].table, 9, 2); if (code < 0 || code > 16) { - av_log(s->avctx, AV_LOG_WARNING, - "mjpeg_decode_dc: bad vlc: %d:%d (%p)\n", - 0, dc_index, &s->vlcs[0][dc_index]); - return 0xfffff; + av_log(s->avctx, AV_LOG_ERROR, + "mjpeg_decode_dc: bad vlc: %d\n", dc_index); + return AVERROR_INVALIDDATA; } - if (code) - return get_xbits(&s->gb, code); - else - return 0; + *val = code ? get_xbits(&s->gb, code) : 0; + return 0; } /* decode block and dequantize */ @@ -845,44 +854,45 @@ static int decode_block(MJpegDecodeContext *s, int16_t *block, int component, int code, i, j, level, val; /* DC coef */ - val = mjpeg_decode_dc(s, dc_index); - if (val == 0xfffff) { - av_log(s->avctx, AV_LOG_ERROR, "error dc\n"); - return AVERROR_INVALIDDATA; - } + int ret = mjpeg_decode_dc(s, dc_index, &val); + if (ret < 0) + return ret; + val = val * (unsigned)quant_matrix[0] + s->last_dc[component]; s->last_dc[component] = val; block[0] = av_clip_int16(val); /* AC coefs */ i = 0; - {OPEN_READER(re, &s->gb); - do { - UPDATE_CACHE(re, &s->gb); - GET_VLC(code, re, &s->gb, s->vlcs[1][ac_index].table, 9, 2); + { + OPEN_READER(re, &s->gb); + do { + UPDATE_CACHE(re, &s->gb); + GET_VLC(code, re, &s->gb, s->vlcs[1][ac_index].table, 9, 2); - i += ((unsigned)code) >> 4; + i += ((unsigned)code) >> 4; code &= 0xf; - if (code) { - if (code > MIN_CACHE_BITS - 16) - UPDATE_CACHE(re, &s->gb); + if (code) { + // GET_VLC updates the cache if parsing reaches the second stage. + // So we have at least MIN_CACHE_BITS - 9 > 15 bits left here + // and don't need to refill the cache. + { + int cache = GET_CACHE(re, &s->gb); + int sign = (~cache) >> 31; + level = (NEG_USR32(sign ^ cache,code) ^ sign) - sign; + } - { - int cache = GET_CACHE(re, &s->gb); - int sign = (~cache) >> 31; - level = (NEG_USR32(sign ^ cache,code) ^ sign) - sign; + LAST_SKIP_BITS(re, &s->gb, code); + + if (i > 63) { + av_log(s->avctx, AV_LOG_ERROR, "error count: %d\n", i); + return AVERROR_INVALIDDATA; + } + j = s->permutated_scantable[i]; + block[j] = level * quant_matrix[i]; } - - LAST_SKIP_BITS(re, &s->gb, code); - - if (i > 63) { - av_log(s->avctx, AV_LOG_ERROR, "error count: %d\n", i); - return AVERROR_INVALIDDATA; - } - j = s->permutated_scantable[i]; - block[j] = level * quant_matrix[i]; - } - } while (i < 63); - CLOSE_READER(re, &s->gb);} + } while (i < 63); + CLOSE_READER(re, &s->gb); + } return 0; } @@ -893,11 +903,10 @@ static int decode_dc_progressive(MJpegDecodeContext *s, int16_t *block, { unsigned val; s->bdsp.clear_block(block); - val = mjpeg_decode_dc(s, dc_index); - if (val == 0xfffff) { - av_log(s->avctx, AV_LOG_ERROR, "error dc\n"); - return AVERROR_INVALIDDATA; - } + int ret = mjpeg_decode_dc(s, dc_index, &val); + if (ret < 0) + return ret; + val = (val * (quant_matrix[0] << Al)) + s->last_dc[component]; s->last_dc[component] = val; block[0] = val; @@ -908,7 +917,7 @@ static int decode_dc_progressive(MJpegDecodeContext *s, int16_t *block, static int decode_block_progressive(MJpegDecodeContext *s, int16_t *block, uint8_t *last_nnz, int ac_index, uint16_t *quant_matrix, - int ss, int se, int Al, int *EOBRUN) + int Ss, int Se, int Al, int *EOBRUN) { int code, i, j, val, run; unsigned level; @@ -920,7 +929,7 @@ static int decode_block_progressive(MJpegDecodeContext *s, int16_t *block, { OPEN_READER(re, &s->gb); - for (i = ss; ; i++) { + for (i = Ss; ; i++) { UPDATE_CACHE(re, &s->gb); GET_VLC(code, re, &s->gb, s->vlcs[2][ac_index].table, 9, 2); @@ -928,8 +937,6 @@ static int decode_block_progressive(MJpegDecodeContext *s, int16_t *block, code &= 0xF; if (code) { i += run; - if (code > MIN_CACHE_BITS - 16) - UPDATE_CACHE(re, &s->gb); { int cache = GET_CACHE(re, &s->gb); @@ -939,10 +946,10 @@ static int decode_block_progressive(MJpegDecodeContext *s, int16_t *block, LAST_SKIP_BITS(re, &s->gb, code); - if (i >= se) { - if (i == se) { - j = s->permutated_scantable[se]; - block[j] = level * (quant_matrix[se] << Al); + if (i >= Se) { + if (i == Se) { + j = s->permutated_scantable[Se]; + block[j] = level * (quant_matrix[Se] << Al); break; } av_log(s->avctx, AV_LOG_ERROR, "error count: %d\n", i); @@ -951,16 +958,17 @@ static int decode_block_progressive(MJpegDecodeContext *s, int16_t *block, j = s->permutated_scantable[i]; block[j] = level * (quant_matrix[i] << Al); } else { - if (run == 0xF) {// ZRL - skip 15 coefficients + if (run == 0xF) { // ZRL - skip 15 coefficients i += 15; - if (i >= se) { + if (i >= Se) { av_log(s->avctx, AV_LOG_ERROR, "ZRL overflow: %d\n", i); return AVERROR_INVALIDDATA; } } else { val = (1 << run); if (run) { - UPDATE_CACHE(re, &s->gb); + // Given that GET_VLC reloads internally, we always + // have at least 16 bits in the cache here. val += NEG_USR32(GET_CACHE(re, &s->gb), run); LAST_SKIP_BITS(re, &s->gb, run); } @@ -990,7 +998,7 @@ static int decode_block_progressive(MJpegDecodeContext *s, int16_t *block, for (; ; i++) { \ if (i > last) { \ i += run; \ - if (i > se) { \ + if (i > Se) { \ av_log(s->avctx, AV_LOG_ERROR, "error count: %d\n", i); \ return -1; \ } \ @@ -1007,10 +1015,10 @@ for (; ; i++) { \ static int decode_block_refinement(MJpegDecodeContext *s, int16_t *block, uint8_t *last_nnz, int ac_index, uint16_t *quant_matrix, - int ss, int se, int Al, int *EOBRUN) + int Ss, int Se, int Al, int *EOBRUN) { - int code, i = ss, j, sign, val, run; - int last = FFMIN(se, *last_nnz); + int code, i = Ss, j, sign, val, run; + int last = FFMIN(Se, *last_nnz); OPEN_READER(re, &s->gb); if (*EOBRUN) { @@ -1022,14 +1030,13 @@ static int decode_block_refinement(MJpegDecodeContext *s, int16_t *block, if (code & 0xF) { run = ((unsigned) code) >> 4; - UPDATE_CACHE(re, &s->gb); val = SHOW_UBITS(re, &s->gb, 1); LAST_SKIP_BITS(re, &s->gb, 1); ZERO_RUN; j = s->permutated_scantable[i]; val--; block[j] = ((quant_matrix[i] << Al) ^ val) - val; - if (i == se) { + if (i == Se) { if (i > *last_nnz) *last_nnz = i; CLOSE_READER(re, &s->gb); @@ -1043,7 +1050,8 @@ static int decode_block_refinement(MJpegDecodeContext *s, int16_t *block, val = run; run = (1 << run); if (val) { - UPDATE_CACHE(re, &s->gb); + // Given that GET_VLC reloads internally, we always + // have at least 16 bits in the cache here. run += SHOW_UBITS(re, &s->gb, val); LAST_SKIP_BITS(re, &s->gb, val); } @@ -1069,43 +1077,12 @@ static int decode_block_refinement(MJpegDecodeContext *s, int16_t *block, #undef REFINE_BIT #undef ZERO_RUN -static int handle_rstn(MJpegDecodeContext *s, int nb_components) -{ - int i; - int reset = 0; - - if (s->restart_interval) { - s->restart_count--; - if(s->restart_count == 0 && s->avctx->codec_id == AV_CODEC_ID_THP){ - align_get_bits(&s->gb); - for (i = 0; i < nb_components; i++) /* reset dc */ - s->last_dc[i] = (4 << s->bits); - } - - i = 8 + ((-get_bits_count(&s->gb)) & 7); - /* skip RSTn */ - if (s->restart_count == 0) { - if( show_bits(&s->gb, i) == (1 << i) - 1 - || show_bits(&s->gb, i) == 0xFF) { - int pos = get_bits_count(&s->gb); - align_get_bits(&s->gb); - while (get_bits_left(&s->gb) >= 8 && show_bits(&s->gb, 8) == 0xFF) - skip_bits(&s->gb, 8); - if (get_bits_left(&s->gb) >= 8 && (get_bits(&s->gb, 8) & 0xF8) == 0xD0) { - for (i = 0; i < nb_components; i++) /* reset dc */ - s->last_dc[i] = (4 << s->bits); - reset = 1; - } else - skip_bits_long(&s->gb, pos - get_bits_count(&s->gb)); - } - } - } - return reset; -} - /* Handles 1 to 4 components */ -static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int nb_components, int predictor, int point_transform) +static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s) { + int nb_components = s->nb_components_sos; + int predictor = s->Ss; + int point_transform = s->Al; int i, mb_x, mb_y; unsigned width; uint16_t (*buffer)[4]; @@ -1115,6 +1092,7 @@ static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int nb_components, int p int resync_mb_y = 0; int resync_mb_x = 0; int vpred[6]; + int ret; if (!s->bayer && s->nb_components < 3) return AVERROR_INVALIDDATA; @@ -1130,10 +1108,8 @@ static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int nb_components, int p } - s->restart_count = s->restart_interval; - - if (s->restart_interval == 0) - s->restart_interval = INT_MAX; + for (i = 0; i < 6; i++) + vpred[i] = 1 << (s->bits - 1); if (s->bayer) width = s->mb_width / nb_components; /* Interleaved, width stored is the total so need to divide */ @@ -1149,6 +1125,8 @@ static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int nb_components, int p for (i = 0; i < 4; i++) buffer[0][i] = 1 << (s->bits - 1); + s->restart_count = -1; + for (mb_y = 0; mb_y < s->mb_height; mb_y++) { uint8_t *ptr = s->picture_ptr->data[0] + (linesize * mb_y); @@ -1158,38 +1136,37 @@ static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int nb_components, int p for (i = 0; i < 4; i++) top[i] = left[i] = topleft[i] = buffer[0][i]; - if ((mb_y * s->width) % s->restart_interval == 0) { - for (i = 0; i < 6; i++) - vpred[i] = 1 << (s->bits-1); - } - for (mb_x = 0; mb_x < width; mb_x++) { int modified_predictor = predictor; + int restart; + + ret = ff_mjpeg_handle_restart(s, &restart); + if (ret < 0) + return ret; + if (restart) { + resync_mb_x = mb_x; + resync_mb_y = mb_y; + for (i = 0; i < 4; i++) + top[i] = left[i] = topleft[i] = 1 << (s->bits - 1); + } if (get_bits_left(&s->gb) < 1) { av_log(s->avctx, AV_LOG_ERROR, "bitstream end in rgb_scan\n"); return AVERROR_INVALIDDATA; } - if (s->restart_interval && !s->restart_count){ - s->restart_count = s->restart_interval; - resync_mb_x = mb_x; - resync_mb_y = mb_y; - for(i=0; i<4; i++) - top[i] = left[i]= topleft[i]= 1 << (s->bits - 1); - } - if (mb_y == resync_mb_y || mb_y == resync_mb_y+1 && mb_x < resync_mb_x || !mb_x) + if (mb_y == resync_mb_y || mb_y == resync_mb_y + 1 && mb_x < resync_mb_x || !mb_x) modified_predictor = 1; - for (i=0;idc_index[i]); - if(dc == 0xFFFFF) - return -1; + ret = mjpeg_decode_dc(s, s->dc_index[i], &dc); + if (ret < 0) + return ret; if (!s->bayer || mb_x) { pred = left[i]; @@ -1203,45 +1180,40 @@ static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int nb_components, int p left[i] = buffer[mb_x][i] = mask & (pred + (unsigned)(dc * (1 << point_transform))); } - - if (s->restart_interval && !--s->restart_count) { - align_get_bits(&s->gb); - skip_bits(&s->gb, 16); /* skip RSTn */ - } } if (s->rct && s->nb_components == 4) { for (mb_x = 0; mb_x < s->mb_width; mb_x++) { - ptr[4*mb_x + 2] = buffer[mb_x][0] - ((buffer[mb_x][1] + buffer[mb_x][2] - 0x200) >> 2); - ptr[4*mb_x + 1] = buffer[mb_x][1] + ptr[4*mb_x + 2]; - ptr[4*mb_x + 3] = buffer[mb_x][2] + ptr[4*mb_x + 2]; - ptr[4*mb_x + 0] = buffer[mb_x][3]; + ptr[4 * mb_x + 2] = buffer[mb_x][0] - ((buffer[mb_x][1] + buffer[mb_x][2] - 0x200) >> 2); + ptr[4 * mb_x + 1] = buffer[mb_x][1] + ptr[4 * mb_x + 2]; + ptr[4 * mb_x + 3] = buffer[mb_x][2] + ptr[4 * mb_x + 2]; + ptr[4 * mb_x + 0] = buffer[mb_x][3]; } } else if (s->nb_components == 4) { - for(i=0; icomp_index[i]; + for (i = 0; i < nb_components; i++) { + int c = s->comp_index[i]; if (s->bits <= 8) { - for(mb_x = 0; mb_x < s->mb_width; mb_x++) { - ptr[4*mb_x+3-c] = buffer[mb_x][i]; + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + ptr[4 * mb_x + 3 - c] = buffer[mb_x][i]; } - } else if(s->bits == 9) { + } else if (s->bits == 9) { return AVERROR_PATCHWELCOME; } else { - for(mb_x = 0; mb_x < s->mb_width; mb_x++) { - ((uint16_t*)ptr)[4*mb_x+c] = buffer[mb_x][i]; + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + ((uint16_t*)ptr)[4 * mb_x + c] = buffer[mb_x][i]; } } } } else if (s->rct) { for (mb_x = 0; mb_x < s->mb_width; mb_x++) { - ptr[3*mb_x + 1] = buffer[mb_x][0] - ((buffer[mb_x][1] + buffer[mb_x][2] - 0x200) >> 2); - ptr[3*mb_x + 0] = buffer[mb_x][1] + ptr[3*mb_x + 1]; - ptr[3*mb_x + 2] = buffer[mb_x][2] + ptr[3*mb_x + 1]; + ptr[3 * mb_x + 1] = buffer[mb_x][0] - ((buffer[mb_x][1] + buffer[mb_x][2] - 0x200) >> 2); + ptr[3 * mb_x + 0] = buffer[mb_x][1] + ptr[3 * mb_x + 1]; + ptr[3 * mb_x + 2] = buffer[mb_x][2] + ptr[3 * mb_x + 1]; } } else if (s->pegasus_rct) { for (mb_x = 0; mb_x < s->mb_width; mb_x++) { - ptr[3*mb_x + 1] = buffer[mb_x][0] - ((buffer[mb_x][1] + buffer[mb_x][2]) >> 2); - ptr[3*mb_x + 0] = buffer[mb_x][1] + ptr[3*mb_x + 1]; - ptr[3*mb_x + 2] = buffer[mb_x][2] + ptr[3*mb_x + 1]; + ptr[3 * mb_x + 1] = buffer[mb_x][0] - ((buffer[mb_x][1] + buffer[mb_x][2]) >> 2); + ptr[3 * mb_x + 0] = buffer[mb_x][1] + ptr[3 * mb_x + 1]; + ptr[3 * mb_x + 2] = buffer[mb_x][2] + ptr[3 * mb_x + 1]; } } else if (s->bayer) { if (s->bits <= 8) @@ -1252,22 +1224,22 @@ static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int nb_components, int p ((uint16_t*)ptr)[mb_x] = buffer[mb_x][0]; } else if (nb_components == 2) { for (mb_x = 0; mb_x < width; mb_x++) { - ((uint16_t*)ptr)[2*mb_x + 0] = buffer[mb_x][0]; - ((uint16_t*)ptr)[2*mb_x + 1] = buffer[mb_x][1]; + ((uint16_t*)ptr)[2 * mb_x + 0] = buffer[mb_x][0]; + ((uint16_t*)ptr)[2 * mb_x + 1] = buffer[mb_x][1]; } } } else { - for(i=0; icomp_index[i]; + for (i = 0; i < nb_components; i++) { + int c = s->comp_index[i]; if (s->bits <= 8) { - for(mb_x = 0; mb_x < s->mb_width; mb_x++) { - ptr[3*mb_x+2-c] = buffer[mb_x][i]; + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + ptr[3 * mb_x + 2 - c] = buffer[mb_x][i]; } - } else if(s->bits == 9) { + } else if (s->bits == 9) { return AVERROR_PATCHWELCOME; } else { - for(mb_x = 0; mb_x < s->mb_width; mb_x++) { - ((uint16_t*)ptr)[3*mb_x+2-c] = buffer[mb_x][i]; + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + ((uint16_t*)ptr)[3 * mb_x + 2 - c] = buffer[mb_x][i]; } } } @@ -1276,33 +1248,42 @@ static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int nb_components, int p return 0; } -static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s, int predictor, - int point_transform, int nb_components) +static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s) { + int predictor = s->Ss; + int point_transform = s->Al; + int nb_components = s->nb_components_sos; int i, mb_x, mb_y, mask; - int bits= (s->bits+7)&~7; + int bits = (s->bits + 7) & ~7; int resync_mb_y = 0; int resync_mb_x = 0; + int ret; point_transform += bits - s->bits; mask = ((1 << s->bits) - 1) << point_transform; - av_assert0(nb_components>=1 && nb_components<=4); + av_assert0(nb_components >= 1 && nb_components <= 4); + + s->restart_count = -1; for (mb_y = 0; mb_y < s->mb_height; mb_y++) { for (mb_x = 0; mb_x < s->mb_width; mb_x++) { - if (get_bits_left(&s->gb) < 1) { - av_log(s->avctx, AV_LOG_ERROR, "bitstream end in yuv_scan\n"); - return AVERROR_INVALIDDATA; - } - if (s->restart_interval && !s->restart_count){ - s->restart_count = s->restart_interval; + int restart; + ret = ff_mjpeg_handle_restart(s, &restart); + if (ret < 0) + return ret; + if (restart) { resync_mb_x = mb_x; resync_mb_y = mb_y; } - if(!mb_x || mb_y == resync_mb_y || mb_y == resync_mb_y+1 && mb_x < resync_mb_x || s->interlaced){ - int toprow = mb_y == resync_mb_y || mb_y == resync_mb_y+1 && mb_x < resync_mb_x; + if (get_bits_left(&s->gb) < 1) { + av_log(s->avctx, AV_LOG_ERROR, "bitstream end in yuv_scan\n"); + return AVERROR_INVALIDDATA; + } + + if (!mb_x || mb_y == resync_mb_y || mb_y == resync_mb_y + 1 && mb_x < resync_mb_x || s->interlaced) { + int toprow = mb_y == resync_mb_y || mb_y == resync_mb_y + 1 && mb_x < resync_mb_x; int leftcol = !mb_x || mb_y == resync_mb_y && mb_x == resync_mb_x; for (i = 0; i < nb_components; i++) { uint8_t *ptr; @@ -1314,59 +1295,60 @@ static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s, int predictor, v = s->v_scount[i]; x = 0; y = 0; - linesize= s->linesize[c]; + linesize = s->linesize[c]; - if(bits>8) linesize /= 2; + if (bits > 8) linesize /= 2; - for(j=0; jdc_index[i]); - if(dc == 0xFFFFF) - return -1; + ret = mjpeg_decode_dc(s, s->dc_index[i], &dc); + if (ret < 0) + return ret; + if ( h * mb_x + x >= s->width || v * mb_y + y >= s->height) { // Nothing to do - } else if (bits<=8) { - ptr = s->picture_ptr->data[c] + (linesize * (v * mb_y + y)) + (h * mb_x + x); //FIXME optimize this crap - if(y==0 && toprow){ - if(x==0 && leftcol){ - pred= 1 << (bits - 1); - }else{ - pred= ptr[-1]; + } else if (bits <= 8) { + ptr = s->picture_ptr->data[c] + (linesize * (v * mb_y + y)) + (h * mb_x + x); // FIXME optimize this crap + if (y == 0 && toprow) { + if (x == 0 && leftcol) { + pred = 1 << (bits - 1); + } else { + pred = ptr[-1]; } - }else{ - if(x==0 && leftcol){ - pred= ptr[-linesize]; - }else{ - PREDICT(pred, ptr[-linesize-1], ptr[-linesize], ptr[-1], predictor); + } else { + if (x == 0 && leftcol) { + pred = ptr[-linesize]; + } else { + PREDICT(pred, ptr[-linesize - 1], ptr[-linesize], ptr[-1], predictor); } } if (s->interlaced && s->bottom_field) ptr += linesize >> 1; pred &= mask; - *ptr= pred + ((unsigned)dc << point_transform); - }else{ - ptr16 = (uint16_t*)(s->picture_ptr->data[c] + 2*(linesize * (v * mb_y + y)) + 2*(h * mb_x + x)); //FIXME optimize this crap - if(y==0 && toprow){ - if(x==0 && leftcol){ - pred= 1 << (bits - 1); - }else{ - pred= ptr16[-1]; + *ptr = pred + ((unsigned)dc << point_transform); + } else { + ptr16 = (uint16_t*)(s->picture_ptr->data[c] + 2 * (linesize * (v * mb_y + y)) + 2 * (h * mb_x + x)); // FIXME optimize this crap + if (y == 0 && toprow) { + if (x == 0 && leftcol) { + pred = 1 << (bits - 1); + } else { + pred = ptr16[-1]; } - }else{ - if(x==0 && leftcol){ - pred= ptr16[-linesize]; - }else{ - PREDICT(pred, ptr16[-linesize-1], ptr16[-linesize], ptr16[-1], predictor); + } else { + if (x == 0 && leftcol) { + pred = ptr16[-linesize]; + } else { + PREDICT(pred, ptr16[-linesize - 1], ptr16[-linesize], ptr16[-1], predictor); } } if (s->interlaced && s->bottom_field) ptr16 += linesize >> 1; pred &= mask; - *ptr16= pred + ((unsigned)dc << point_transform); + *ptr16 = pred + ((unsigned)dc << point_transform); } if (++x == h) { x = 0; @@ -1387,31 +1369,32 @@ static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s, int predictor, y = 0; linesize = s->linesize[c]; - if(bits>8) linesize /= 2; + if (bits > 8) linesize /= 2; for (j = 0; j < n; j++) { int pred; - dc = mjpeg_decode_dc(s, s->dc_index[i]); - if(dc == 0xFFFFF) - return -1; + ret = mjpeg_decode_dc(s, s->dc_index[i], &dc); + if (ret < 0) + return ret; + if ( h * mb_x + x >= s->width || v * mb_y + y >= s->height) { // Nothing to do - } else if (bits<=8) { + } else if (bits <= 8) { ptr = s->picture_ptr->data[c] + (linesize * (v * mb_y + y)) + - (h * mb_x + x); //FIXME optimize this crap - PREDICT(pred, ptr[-linesize-1], ptr[-linesize], ptr[-1], predictor); + (h * mb_x + x); // FIXME optimize this crap + PREDICT(pred, ptr[-linesize - 1], ptr[-linesize], ptr[-1], predictor); pred &= mask; *ptr = pred + ((unsigned)dc << point_transform); - }else{ - ptr16 = (uint16_t*)(s->picture_ptr->data[c] + 2*(linesize * (v * mb_y + y)) + 2*(h * mb_x + x)); //FIXME optimize this crap - PREDICT(pred, ptr16[-linesize-1], ptr16[-linesize], ptr16[-1], predictor); + } else { + ptr16 = (uint16_t*)(s->picture_ptr->data[c] + 2 * (linesize * (v * mb_y + y)) + 2 * (h * mb_x + x)); // FIXME optimize this crap + PREDICT(pred, ptr16[-linesize - 1], ptr16[-linesize], ptr16[-1], predictor); pred &= mask; - *ptr16= pred + ((unsigned)dc << point_transform); + *ptr16 = pred + ((unsigned)dc << point_transform); } if (++x == h) { @@ -1421,10 +1404,6 @@ static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s, int predictor, } } } - if (s->restart_interval && !--s->restart_count) { - align_get_bits(&s->gb); - skip_bits(&s->gb, 16); /* skip RSTn */ - } } } return 0; @@ -1435,7 +1414,7 @@ static av_always_inline void mjpeg_copy_block(MJpegDecodeContext *s, int linesize, int lowres) { switch (lowres) { - case 0: s->hdsp.put_pixels_tab[1][0](dst, src, linesize, 8); + case 0: s->copy_block(dst, src, linesize, 8); break; case 1: copy_block4(dst, src, linesize, linesize, 4); break; @@ -1451,38 +1430,44 @@ static void shift_output(MJpegDecodeContext *s, uint8_t *ptr, int linesize) int block_x, block_y; int size = 8 >> s->avctx->lowres; if (s->bits > 8) { - for (block_y=0; block_ybits; + for (block_y = 0; block_y < size; block_y++) + for (block_x = 0; block_x < size; block_x++) + *(uint16_t*)(ptr + 2 * block_x + block_y * linesize) <<= 16 - s->bits; } else { - for (block_y=0; block_ybits; + for (block_y = 0; block_y < size; block_y++) + for (block_x = 0; block_x < size; block_x++) + *(ptr + block_x + block_y * linesize) <<= 8 - s->bits; } } -static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah, - int Al, const uint8_t *mb_bitmask, - int mb_bitmask_size, - const AVFrame *reference) +static int mjpeg_decode_scan(MJpegDecodeContext *s) { + int nb_components = s->nb_components_sos; + int Ah = s->Ah; + int Al = s->Al; + const uint8_t *mb_bitmask = NULL; + const AVFrame *reference = NULL; int i, mb_x, mb_y, chroma_h_shift, chroma_v_shift, chroma_width, chroma_height; uint8_t *data[MAX_COMPONENTS]; const uint8_t *reference_data[MAX_COMPONENTS]; int linesize[MAX_COMPONENTS]; GetBitContext mb_bitmask_gb = {0}; // initialize to silence gcc warning int bytes_per_pixel = 1 + (s->bits > 8); + int ret; + + if (s->avctx->codec_id == AV_CODEC_ID_MXPEG) { + mb_bitmask = s->mb_bitmask; + reference = s->reference; + } if (mb_bitmask) { - if (mb_bitmask_size != (s->mb_width * s->mb_height + 7)>>3) { + if (s->mb_bitmask_size != (s->mb_width * s->mb_height + 7) >> 3) { av_log(s->avctx, AV_LOG_ERROR, "mb_bitmask_size mismatches\n"); return AVERROR_INVALIDDATA; } init_get_bits(&mb_bitmask_gb, mb_bitmask, s->mb_width * s->mb_height); } - s->restart_count = 0; - av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, &chroma_h_shift, &chroma_v_shift); chroma_width = AV_CEIL_RSHIFT(s->width, chroma_h_shift); @@ -1496,12 +1481,32 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah, s->coefs_finished[c] |= 1; } +next_field: + s->restart_count = -1; + for (mb_y = 0; mb_y < s->mb_height; mb_y++) { for (mb_x = 0; mb_x < s->mb_width; mb_x++) { const int copy_mb = mb_bitmask && !get_bits1(&mb_bitmask_gb); + int restart; - if (s->restart_interval && !s->restart_count) - s->restart_count = s->restart_interval; + if (s->avctx->codec_id == AV_CODEC_ID_THP) { + if (s->restart_count < 0) { + ret = ff_mjpeg_unescape_sos(s); + if (ret < 0) + return ret; + } + restart = ff_mjpeg_should_restart(s); + if (restart) + align_get_bits(&s->gb); + } else { + ret = ff_mjpeg_handle_restart(s, &restart); + if (ret < 0) + return ret; + } + if (restart) { + for (i = 0; i < nb_components; i++) + s->last_dc[i] = (4 << s->bits); + } if (get_bits_left(&s->gb) < 0) { av_log(s->avctx, AV_LOG_ERROR, "overread %d\n", @@ -1524,8 +1529,8 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah, if (s->interlaced && s->bottom_field) block_offset += linesize[c] >> 1; - if ( 8*(h * mb_x + x) < ((c == 1) || (c == 2) ? chroma_width : s->width) - && 8*(v * mb_y + y) < ((c == 1) || (c == 2) ? chroma_height : s->height)) { + if ( 8 * (h * mb_x + x) < ((c == 1) || (c == 2) ? chroma_width : s->width) + && 8 * (v * mb_y + y) < ((c == 1) || (c == 2) ? chroma_height : s->height)) { ptr = data[c] + block_offset; } else ptr = NULL; @@ -1533,7 +1538,7 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah, if (copy_mb) { if (ptr) mjpeg_copy_block(s, ptr, reference_data[c] + block_offset, - linesize[c], s->avctx->lowres); + linesize[c], s->avctx->lowres); } else { s->bdsp.clear_block(s->block); @@ -1575,63 +1580,73 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah, } } } - - handle_rstn(s, nb_components); } } + + if (s->interlaced && + bytestream2_get_bytes_left(&s->gB) > 2 && + bytestream2_tell(&s->gB) > 2 && + s->gB.buffer[-2] == 0xFF && + s->gB.buffer[-1] == 0xD1) { + av_log(s->avctx, AV_LOG_DEBUG, "AVRn interlaced picture marker found\n"); + s->bottom_field ^= 1; + + goto next_field; + } + return 0; } -static int mjpeg_decode_scan_progressive_ac(MJpegDecodeContext *s, int ss, - int se, int Ah, int Al) +static int mjpeg_decode_scan_progressive_ac(MJpegDecodeContext *s) { + int Ss = s->Ss; + int Se = s->Se; + int Ah = s->Ah; + int Al = s->Al; int mb_x, mb_y; int EOBRUN = 0; int c = s->comp_index[0]; uint16_t *quant_matrix = s->quant_matrixes[s->quant_sindex[0]]; - av_assert0(ss>=0 && Ah>=0 && Al>=0); - if (se < ss || se > 63) { - av_log(s->avctx, AV_LOG_ERROR, "SS/SE %d/%d is invalid\n", ss, se); + av_assert0(Ss >= 0 && Ah >= 0 && Al >= 0); + if (Se < Ss || Se > 63) { + av_log(s->avctx, AV_LOG_ERROR, "SS/SE %d/%d is invalid\n", Ss, Se); return AVERROR_INVALIDDATA; } // s->coefs_finished is a bitmask for coefficients coded - // ss and se are parameters telling start and end coefficients - s->coefs_finished[c] |= (2ULL << se) - (1ULL << ss); + // Ss and Se are parameters telling start and end coefficients + s->coefs_finished[c] |= (2ULL << Se) - (1ULL << Ss); - s->restart_count = 0; + s->restart_count = -1; for (mb_y = 0; mb_y < s->mb_height; mb_y++) { int block_idx = mb_y * s->block_stride[c]; int16_t (*block)[64] = &s->blocks[c][block_idx]; uint8_t *last_nnz = &s->last_nnz[c][block_idx]; - if (get_bits_left(&s->gb) <= 0) { - av_log(s->avctx, AV_LOG_ERROR, "bitstream truncated in mjpeg_decode_scan_progressive_ac\n"); - return AVERROR_INVALIDDATA; - } for (mb_x = 0; mb_x < s->mb_width; mb_x++, block++, last_nnz++) { - int ret; - if (s->restart_interval && !s->restart_count) - s->restart_count = s->restart_interval; - - if (Ah) - ret = decode_block_refinement(s, *block, last_nnz, s->ac_index[0], - quant_matrix, ss, se, Al, &EOBRUN); - else - ret = decode_block_progressive(s, *block, last_nnz, s->ac_index[0], - quant_matrix, ss, se, Al, &EOBRUN); - - if (ret >= 0 && get_bits_left(&s->gb) < 0) - ret = AVERROR_INVALIDDATA; - if (ret < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "error y=%d x=%d\n", mb_y, mb_x); - return AVERROR_INVALIDDATA; - } - - if (handle_rstn(s, 0)) + int ret; + int restart; + ret = ff_mjpeg_handle_restart(s, &restart); + if (ret < 0) + return ret; + if (restart) EOBRUN = 0; + + if (Ah) + ret = decode_block_refinement(s, *block, last_nnz, s->ac_index[0], + quant_matrix, Ss, Se, Al, &EOBRUN); + else + ret = decode_block_progressive(s, *block, last_nnz, s->ac_index[0], + quant_matrix, Ss, Se, Al, &EOBRUN); + + if (ret >= 0 && get_bits_left(&s->gb) < 0) + ret = AVERROR_INVALIDDATA; + if (ret < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "error y=%d x=%d\n", mb_y, mb_x); + return AVERROR_INVALIDDATA; + } } } return 0; @@ -1666,50 +1681,42 @@ static void mjpeg_idct_scan_progressive_ac(MJpegDecodeContext *s) s->idsp.idct_put(ptr, linesize, *block); if (s->bits & 7) shift_output(s, ptr, linesize); - ptr += bytes_per_pixel*8 >> s->avctx->lowres; + ptr += bytes_per_pixel * 8 >> s->avctx->lowres; } } } } -int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, - int mb_bitmask_size, const AVFrame *reference) +int ff_mjpeg_decode_sos(MJpegDecodeContext *s) { - int len, nb_components, i, h, v, predictor, point_transform; + int len, i, h, v; int index, id, ret; const int block_size = s->lossless ? 1 : 8; - int ilv, prev_shift; if (!s->got_picture) { av_log(s->avctx, AV_LOG_WARNING, "Can not process SOS before SOF, skipping\n"); - return -1; - } - - if (reference) { - if (reference->width != s->picture_ptr->width || - reference->height != s->picture_ptr->height || - reference->format != s->picture_ptr->format) { - av_log(s->avctx, AV_LOG_ERROR, "Reference mismatching\n"); - return AVERROR_INVALIDDATA; - } - } - - /* XXX: verify len field validity */ - len = get_bits(&s->gb, 16); - nb_components = get_bits(&s->gb, 8); - if (nb_components == 0 || nb_components > MAX_COMPONENTS) { - avpriv_report_missing_feature(s->avctx, - "decode_sos: nb_components (%d)", - nb_components); - return AVERROR_PATCHWELCOME; - } - if (len != 6 + 2 * nb_components) { - av_log(s->avctx, AV_LOG_ERROR, "decode_sos: invalid len (%d)\n", len); return AVERROR_INVALIDDATA; } - for (i = 0; i < nb_components; i++) { - id = get_bits(&s->gb, 8); + + ret = mjpeg_parse_len(s, &len, "sos"); + if (ret < 0) + return ret; + if (len < 1) + return AVERROR_INVALIDDATA; + s->nb_components_sos = bytestream2_get_byteu(&s->gB); + if (s->nb_components_sos == 0 || s->nb_components_sos > MAX_COMPONENTS) { + avpriv_report_missing_feature(s->avctx, + "decode_sos: nb_components (%d)", + s->nb_components_sos); + return AVERROR_PATCHWELCOME; + } + if (len != 4 + 2 * s->nb_components_sos) { + av_log(s->avctx, AV_LOG_ERROR, "decode_sos: len(%d) mismatch %d components\n", len, s->nb_components_sos); + return AVERROR_INVALIDDATA; + } + for (i = 0; i < s->nb_components_sos; i++) { + id = bytestream2_get_byteu(&s->gB); av_log(s->avctx, AV_LOG_DEBUG, "component: %d\n", id); /* find component index */ for (index = 0; index < s->nb_components; index++) @@ -1722,7 +1729,7 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, } /* Metasoft MJPEG codec has Cb and Cr swapped */ if (s->avctx->codec_tag == MKTAG('M', 'T', 'S', 'J') - && nb_components == 3 && s->nb_components == 3 && i) + && s->nb_components_sos == 3 && s->nb_components == 3 && i) index = 3 - i; s->quant_sindex[i] = s->quant_index[index]; @@ -1732,8 +1739,9 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, s->comp_index[i] = index; - s->dc_index[i] = get_bits(&s->gb, 4); - s->ac_index[i] = get_bits(&s->gb, 4); + uint8_t b = bytestream2_get_byteu(&s->gB); + s->dc_index[i] = b >> 4; + s->ac_index[i] = b & 0x0F; if (s->dc_index[i] < 0 || s->ac_index[i] < 0 || s->dc_index[i] >= 4 || s->ac_index[i] >= 4) @@ -1742,15 +1750,13 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, goto out_of_range; } - predictor = get_bits(&s->gb, 8); /* JPEG Ss / lossless JPEG predictor /JPEG-LS NEAR */ - ilv = get_bits(&s->gb, 8); /* JPEG Se / JPEG-LS ILV */ - if(s->avctx->codec_tag != AV_RL32("CJPG")){ - prev_shift = get_bits(&s->gb, 4); /* Ah */ - point_transform = get_bits(&s->gb, 4); /* Al */ - }else - prev_shift = point_transform = 0; + s->Ss = bytestream2_get_byteu(&s->gB); /* JPEG Ss / lossless JPEG predictor / JPEG-LS NEAR */ + s->Se = bytestream2_get_byteu(&s->gB); /* JPEG Se / JPEG-LS ILV */ + uint8_t b = bytestream2_get_byteu(&s->gB); + s->Ah = b >> 4; /* Ah */ + s->Al = b & 0x0F; /* Al */ - if (nb_components > 1) { + if (s->nb_components_sos > 1) { /* interleaved stream */ s->mb_width = (s->width + s->h_max * block_size - 1) / (s->h_max * block_size); s->mb_height = (s->height + s->v_max * block_size - 1) / (s->v_max * block_size); @@ -1767,80 +1773,59 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, if (s->avctx->debug & FF_DEBUG_PICT_INFO) av_log(s->avctx, AV_LOG_DEBUG, "%s %s p:%d >>:%d ilv:%d bits:%d skip:%d %s comp:%d\n", s->lossless ? "lossless" : "sequential DCT", s->rgb ? "RGB" : "", - predictor, point_transform, ilv, s->bits, s->mjpb_skiptosod, - s->pegasus_rct ? "PRCT" : (s->rct ? "RCT" : ""), nb_components); + s->Ss, s->Al, s->Se, s->bits, s->mjpb_skiptosod, + s->pegasus_rct ? "PRCT" : (s->rct ? "RCT" : ""), s->nb_components_sos); /* mjpeg-b can have padding bytes between sos and image data, skip them */ - for (i = s->mjpb_skiptosod; i > 0; i--) - skip_bits(&s->gb, 8); - -next_field: - for (i = 0; i < nb_components; i++) - s->last_dc[i] = (4 << s->bits); + if (s->mjpb_skiptosod) + bytestream2_skip(&s->gB, s->mjpb_skiptosod); if (s->avctx->hwaccel) { - int bytes_to_start = get_bits_count(&s->gb) / 8; - av_assert0(bytes_to_start >= 0 && - s->raw_scan_buffer_size >= bytes_to_start); + const uint8_t *buf_ptr; + size_t buf_size; - ret = FF_HW_CALL(s->avctx, decode_slice, - s->raw_scan_buffer + bytes_to_start, - s->raw_scan_buffer_size - bytes_to_start); + mjpeg_find_raw_scan_data(s, &buf_ptr, &buf_size); + + ret = FF_HW_CALL(s->avctx, decode_slice, buf_ptr, buf_size); if (ret < 0) return ret; - } else if (s->lossless) { - av_assert0(s->picture_ptr == s->picture); - if (CONFIG_JPEGLS_DECODER && s->ls) { -// for () { -// reset_ls_coding_parameters(s, 0); - - if ((ret = ff_jpegls_decode_picture(s, predictor, - point_transform, ilv)) < 0) - return ret; - } else { - if (s->rgb || s->bayer) { - if ((ret = ljpeg_decode_rgb_scan(s, nb_components, predictor, point_transform)) < 0) + } else { + if (s->lossless) { + av_assert0(s->picture_ptr == s->picture); + if (CONFIG_JPEGLS_DECODER && s->ls) { + if ((ret = ff_jpegls_decode_picture(s)) < 0) return ret; } else { - if ((ret = ljpeg_decode_yuv_scan(s, predictor, - point_transform, - nb_components)) < 0) + if (s->rgb || s->bayer) { + if ((ret = ljpeg_decode_rgb_scan(s)) < 0) + return ret; + } else { + if ((ret = ljpeg_decode_yuv_scan(s)) < 0) + return ret; + } + } + } else { + if (s->progressive && s->Ss) { + av_assert0(s->picture_ptr == s->picture); + if ((ret = mjpeg_decode_scan_progressive_ac(s)) < 0) + return ret; + } else { + if ((ret = mjpeg_decode_scan(s)) < 0) return ret; } } - } else { - if (s->progressive && predictor) { - av_assert0(s->picture_ptr == s->picture); - if ((ret = mjpeg_decode_scan_progressive_ac(s, predictor, - ilv, prev_shift, - point_transform)) < 0) - return ret; - } else { - if ((ret = mjpeg_decode_scan(s, nb_components, - prev_shift, point_transform, - mb_bitmask, mb_bitmask_size, reference)) < 0) - return ret; - } } - if (s->interlaced && - get_bits_left(&s->gb) > 32 && - show_bits(&s->gb, 8) == 0xFF) { - GetBitContext bak = s->gb; - align_get_bits(&bak); - if (show_bits(&bak, 16) == 0xFFD1) { - av_log(s->avctx, AV_LOG_DEBUG, "AVRn interlaced picture marker found\n"); - s->gb = bak; - skip_bits(&s->gb, 16); - s->bottom_field ^= 1; - - goto next_field; - } + if (s->avctx->codec_id == AV_CODEC_ID_MEDIA100 || + s->avctx->codec_id == AV_CODEC_ID_MJPEGB || + s->avctx->codec_id == AV_CODEC_ID_THP) { + /* Add the amount of bits read from the unescaped image data buffer + * into the GetByteContext. */ + bytestream2_skipu(&s->gB, (get_bits_count(&s->gb) + 7) / 8); } - emms_c(); return 0; out_of_range: av_log(s->avctx, AV_LOG_ERROR, "decode_sos: ac/dc index out of range\n"); @@ -1849,42 +1834,38 @@ next_field: static int mjpeg_decode_dri(MJpegDecodeContext *s) { - if (get_bits(&s->gb, 16) != 4) + if (bytestream2_get_be16u(&s->gB) != 4) return AVERROR_INVALIDDATA; - s->restart_interval = get_bits(&s->gb, 16); - s->restart_count = 0; + s->restart_interval = bytestream2_get_be16u(&s->gB); av_log(s->avctx, AV_LOG_DEBUG, "restart interval: %d\n", s->restart_interval); return 0; } -static int mjpeg_decode_app(MJpegDecodeContext *s) +static int mjpeg_decode_app(MJpegDecodeContext *s, int start_code) { int len, id, i; - len = get_bits(&s->gb, 16); - if (len < 6) { - if (s->bayer) { - // Pentax K-1 (digital camera) JPEG images embedded in DNG images contain unknown APP0 markers - av_log(s->avctx, AV_LOG_WARNING, "skipping APPx (len=%"PRId32") for bayer-encoded image\n", len); - skip_bits(&s->gb, len); - return 0; - } else - return AVERROR_INVALIDDATA; - } - if (8 * len > get_bits_left(&s->gb)) + int ret = mjpeg_parse_len(s, &len, "app"); + if (ret < 0) return AVERROR_INVALIDDATA; - id = get_bits_long(&s->gb, 32); - len -= 6; + if (len < 4) { + if (s->avctx->err_recognition & AV_EF_EXPLODE) + return AVERROR_INVALIDDATA; + av_log(s->avctx, AV_LOG_VERBOSE, "skipping APPx stub (len=%" PRId32 ")\n", len); + goto out; + } + + id = bytestream2_get_be32u(&s->gB); + len -= 4; if (s->avctx->debug & FF_DEBUG_STARTCODE) av_log(s->avctx, AV_LOG_DEBUG, "APPx (%s / %8X) len=%d\n", av_fourcc2str(av_bswap32(id)), id, len); - /* Buggy AVID, it puts EOI only at every 10th frame. */ - /* Also, this fourcc is used by non-avid files too, it holds some + /* This fourcc is used by non-avid files too, it holds some information, but it's always present in AVID-created files. */ if (id == AV_RB32("AVI1")) { /* structure: @@ -1894,8 +1875,9 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) 4bytes field_size 4bytes field_size_less_padding */ - s->buggy_avid = 1; - i = get_bits(&s->gb, 8); len--; + if (len < 1) + goto out; + i = bytestream2_get_byteu(&s->gB); len--; av_log(s->avctx, AV_LOG_DEBUG, "polarity %d\n", i); goto out; } @@ -1904,13 +1886,13 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) int t_w, t_h, v1, v2; if (len < 8) goto out; - skip_bits(&s->gb, 8); /* the trailing zero-byte */ - v1 = get_bits(&s->gb, 8); - v2 = get_bits(&s->gb, 8); - skip_bits(&s->gb, 8); + bytestream2_skipu(&s->gB, 1); /* the trailing zero-byte */ + v1 = bytestream2_get_byteu(&s->gB); + v2 = bytestream2_get_byteu(&s->gB); + bytestream2_skipu(&s->gB, 1); - s->avctx->sample_aspect_ratio.num = get_bits(&s->gb, 16); - s->avctx->sample_aspect_ratio.den = get_bits(&s->gb, 16); + s->avctx->sample_aspect_ratio.num = bytestream2_get_be16u(&s->gB); + s->avctx->sample_aspect_ratio.den = bytestream2_get_be16u(&s->gB); if ( s->avctx->sample_aspect_ratio.num <= 0 || s->avctx->sample_aspect_ratio.den <= 0) { s->avctx->sample_aspect_ratio.num = 0; @@ -1926,11 +1908,11 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) len -= 8; if (len >= 2) { - t_w = get_bits(&s->gb, 8); - t_h = get_bits(&s->gb, 8); + t_w = bytestream2_get_byteu(&s->gB); + t_h = bytestream2_get_byteu(&s->gB); if (t_w && t_h) { /* skip thumbnail */ - if (len -10 - (t_w * t_h * 3) > 0) + if (len - 10 - (t_w * t_h * 3) > 0) len -= t_w * t_h * 3; } len -= 2; @@ -1939,17 +1921,17 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) } if ( id == AV_RB32("Adob") - && len >= 7 - && show_bits(&s->gb, 8) == 'e' - && show_bits_long(&s->gb, 32) != AV_RB32("e_CM")) { - skip_bits(&s->gb, 8); /* 'e' */ - skip_bits(&s->gb, 16); /* version */ - skip_bits(&s->gb, 16); /* flags0 */ - skip_bits(&s->gb, 16); /* flags1 */ - s->adobe_transform = get_bits(&s->gb, 8); + && len >= 8 + && bytestream2_peek_byteu(&s->gB) == 'e' + && bytestream2_peek_be32u(&s->gB) != AV_RB32("e_CM")) { + bytestream2_skipu(&s->gB, 1); /* 'e' */ + bytestream2_skipu(&s->gB, 2); /* version */ + bytestream2_skipu(&s->gB, 2); /* flags0 */ + bytestream2_skipu(&s->gB, 2); /* flags1 */ + s->adobe_transform = bytestream2_get_byteu(&s->gB); if (s->avctx->debug & FF_DEBUG_PICT_INFO) av_log(s->avctx, AV_LOG_INFO, "mjpeg: Adobe header found, transform=%d\n", s->adobe_transform); - len -= 7; + len -= 8; goto out; } @@ -1959,11 +1941,13 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) if (s->avctx->debug & FF_DEBUG_PICT_INFO) av_log(s->avctx, AV_LOG_INFO, "Pegasus lossless jpeg header found\n"); - skip_bits(&s->gb, 16); /* version ? */ - skip_bits(&s->gb, 16); /* unknown always 0? */ - skip_bits(&s->gb, 16); /* unknown always 0? */ - skip_bits(&s->gb, 16); /* unknown always 0? */ - switch (i=get_bits(&s->gb, 8)) { + if (len < 9) + goto out; + bytestream2_skipu(&s->gB, 2); /* version ? */ + bytestream2_skipu(&s->gB, 2); /* unknown always 0? */ + bytestream2_skipu(&s->gB, 2); /* unknown always 0? */ + bytestream2_skipu(&s->gB, 2); /* unknown always 0? */ + switch (i = bytestream2_get_byteu(&s->gB)) { case 1: rgb = 1; pegasus_rct = 0; @@ -1991,32 +1975,32 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) goto out; } if (id == AV_RL32("colr") && len > 0) { - s->colr = get_bits(&s->gb, 8); + s->colr = bytestream2_get_byteu(&s->gB); if (s->avctx->debug & FF_DEBUG_PICT_INFO) av_log(s->avctx, AV_LOG_INFO, "COLR %d\n", s->colr); - len --; + len--; goto out; } if (id == AV_RL32("xfrm") && len > 0) { - s->xfrm = get_bits(&s->gb, 8); + s->xfrm = bytestream2_get_byteu(&s->gB); if (s->avctx->debug & FF_DEBUG_PICT_INFO) av_log(s->avctx, AV_LOG_INFO, "XFRM %d\n", s->xfrm); - len --; + len--; goto out; } /* JPS extension by VRex */ - if (s->start_code == APP3 && id == AV_RB32("_JPS") && len >= 10) { + if (start_code == APP3 && id == AV_RB32("_JPS") && len >= 10) { int flags, layout, type; if (s->avctx->debug & FF_DEBUG_PICT_INFO) av_log(s->avctx, AV_LOG_INFO, "_JPSJPS_\n"); - skip_bits(&s->gb, 32); len -= 4; /* JPS_ */ - skip_bits(&s->gb, 16); len -= 2; /* block length */ - skip_bits(&s->gb, 8); /* reserved */ - flags = get_bits(&s->gb, 8); - layout = get_bits(&s->gb, 8); - type = get_bits(&s->gb, 8); + bytestream2_skipu(&s->gB, 4); len -= 4; /* JPS_ */ + bytestream2_skipu(&s->gB, 2); len -= 2; /* block length */ + bytestream2_skipu(&s->gB, 1); /* reserved */ + flags = bytestream2_get_byteu(&s->gB); + layout = bytestream2_get_byteu(&s->gB); + type = bytestream2_get_byteu(&s->gB); len -= 4; av_freep(&s->stereo3d); @@ -2046,43 +2030,32 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) } /* EXIF metadata */ - if (s->start_code == APP1 && id == AV_RB32("Exif") && len >= 2) { - GetByteContext gbytes; - int ret, le, ifd_offset, bytes_read; - const uint8_t *aligned; + if (start_code == APP1 && id == AV_RB32("Exif") && len >= 2) { + int ret; - skip_bits(&s->gb, 16); // skip padding + bytestream2_skipu(&s->gB, 2); // skip padding len -= 2; - // init byte wise reading - aligned = align_get_bits(&s->gb); - bytestream2_init(&gbytes, aligned, len); - - // read TIFF header - ret = ff_tdecode_header(&gbytes, &le, &ifd_offset); - if (ret) { - av_log(s->avctx, AV_LOG_ERROR, "mjpeg: invalid TIFF header in EXIF data\n"); - } else { - bytestream2_seek(&gbytes, ifd_offset, SEEK_SET); - - // read 0th IFD and store the metadata - // (return values > 0 indicate the presence of subimage metadata) - ret = ff_exif_decode_ifd(s->avctx, &gbytes, le, 0, &s->exif_metadata); - if (ret < 0) { - av_log(s->avctx, AV_LOG_ERROR, "mjpeg: error decoding EXIF data\n"); - } + if (s->exif_metadata.entries) { + av_log(s->avctx, AV_LOG_WARNING, "multiple EXIF\n"); + goto out; } - bytes_read = bytestream2_tell(&gbytes); - skip_bits(&s->gb, bytes_read << 3); - len -= bytes_read; + ret = av_exif_parse_buffer(s->avctx, s->gB.buffer, len, &s->exif_metadata, AV_EXIF_TIFF_HEADER); + if (ret < 0) { + av_log(s->avctx, AV_LOG_WARNING, "unable to parse EXIF buffer\n"); + goto out; + } + + bytestream2_skipu(&s->gB, ret); + len -= ret; goto out; } /* Apple MJPEG-A */ - if ((s->start_code == APP1) && (len > (0x28 - 8))) { - id = get_bits_long(&s->gb, 32); + if ((start_code == APP1) && (len > (0x28 - 8))) { + id = bytestream2_get_be32u(&s->gB); len -= 4; /* Apple MJPEG-A */ if (id == AV_RB32("mjpg")) { @@ -2101,34 +2074,34 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) } } - if (s->start_code == APP2 && id == AV_RB32("ICC_") && len >= 10) { + if (start_code == APP2 && id == AV_RB32("ICC_") && len >= 10) { int id2; unsigned seqno; unsigned nummarkers; - id = get_bits_long(&s->gb, 32); - id2 = get_bits(&s->gb, 24); + id = bytestream2_get_be32u(&s->gB); + id2 = bytestream2_get_be24u(&s->gB); len -= 7; if (id != AV_RB32("PROF") || id2 != AV_RB24("ILE")) { av_log(s->avctx, AV_LOG_WARNING, "Invalid ICC_PROFILE header in APP2\n"); goto out; } - skip_bits(&s->gb, 8); - seqno = get_bits(&s->gb, 8); + bytestream2_skipu(&s->gB, 1); + seqno = bytestream2_get_byteu(&s->gB); len -= 2; if (seqno == 0) { av_log(s->avctx, AV_LOG_WARNING, "Invalid sequence number in APP2\n"); goto out; } - nummarkers = get_bits(&s->gb, 8); + nummarkers = bytestream2_get_byteu(&s->gB); len -= 1; if (nummarkers == 0) { av_log(s->avctx, AV_LOG_WARNING, "Invalid number of markers coded in APP2\n"); goto out; } else if (s->iccnum != 0 && nummarkers != s->iccnum) { - av_log(s->avctx, AV_LOG_WARNING, "Mistmatch in coded number of ICC markers between markers\n"); + av_log(s->avctx, AV_LOG_WARNING, "Mismatch in coded number of ICC markers between markers\n"); goto out; } else if (seqno > nummarkers) { av_log(s->avctx, AV_LOG_WARNING, "Mismatching sequence number and coded number of ICC markers\n"); @@ -2156,8 +2129,7 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) return AVERROR(ENOMEM); } - memcpy(s->iccentries[seqno - 1].data, align_get_bits(&s->gb), len); - skip_bits(&s->gb, len << 3); + bytestream2_get_bufferu(&s->gB, s->iccentries[seqno - 1].data, len); len = 0; s->iccread++; @@ -2170,195 +2142,239 @@ out: if (len < 0) av_log(s->avctx, AV_LOG_ERROR, "mjpeg: error, decode_app parser read over the end\n"); - while (--len > 0) - skip_bits(&s->gb, 8); + if (len > 0) + bytestream2_skipu(&s->gB, len); return 0; } static int mjpeg_decode_com(MJpegDecodeContext *s) { - int len = get_bits(&s->gb, 16); - if (len >= 2 && 8 * len - 16 <= get_bits_left(&s->gb)) { - int i; - char *cbuf = av_malloc(len - 1); - if (!cbuf) - return AVERROR(ENOMEM); + int len; + int ret = mjpeg_parse_len(s, &len, "com"); + if (ret < 0) + return ret; + if (!len) + return 0; - for (i = 0; i < len - 2; i++) - cbuf[i] = get_bits(&s->gb, 8); - if (i > 0 && cbuf[i - 1] == '\n') - cbuf[i - 1] = 0; - else - cbuf[i] = 0; + int i; + char *cbuf = av_malloc(len + 1); + if (!cbuf) + return AVERROR(ENOMEM); - if (s->avctx->debug & FF_DEBUG_PICT_INFO) - av_log(s->avctx, AV_LOG_INFO, "comment: '%s'\n", cbuf); + for (i = 0; i < len; i++) + cbuf[i] = bytestream2_get_byteu(&s->gB); + if (cbuf[i - 1] == '\n') + cbuf[i - 1] = 0; + else + cbuf[i] = 0; - /* buggy avid, it puts EOI only at every 10th frame */ - if (!strncmp(cbuf, "AVID", 4)) { - parse_avid(s, cbuf, len); - } else if (!strcmp(cbuf, "CS=ITU601")) - s->cs_itu601 = 1; - else if ((!strncmp(cbuf, "Intel(R) JPEG Library, version 1", 32) && s->avctx->codec_tag) || - (!strncmp(cbuf, "Metasoft MJPEG Codec", 20))) - s->flipped = 1; - else if (!strcmp(cbuf, "MULTISCOPE II")) { - s->avctx->sample_aspect_ratio = (AVRational) { 1, 2 }; - s->multiscope = 2; - } + if (s->avctx->debug & FF_DEBUG_PICT_INFO) + av_log(s->avctx, AV_LOG_INFO, "comment: '%s'\n", cbuf); - av_free(cbuf); + /* buggy avid, it puts EOI only at every 10th frame */ + if (!strncmp(cbuf, "AVID", 4)) { + parse_avid(s, cbuf, len); + } else if (!strcmp(cbuf, "CS=ITU601")) + s->cs_itu601 = 1; + else if ((!strncmp(cbuf, "Intel(R) JPEG Library, version 1", 32) && s->avctx->codec_tag) || + (!strncmp(cbuf, "Metasoft MJPEG Codec", 20))) + s->flipped = 1; + else if (!strcmp(cbuf, "MULTISCOPE II")) { + s->avctx->sample_aspect_ratio = (AVRational) { 1, 2 }; + s->multiscope = 2; } + av_free(cbuf); + return 0; } /* return the 8 bit start code value and update the search state. Return -1 if no start code found */ -static int find_marker(const uint8_t **pbuf_ptr, const uint8_t *buf_end) +int ff_mjpeg_find_marker(const uint8_t **pbuf_ptr, const uint8_t *buf_end) { const uint8_t *buf_ptr; - unsigned int v, v2; int val; - int skipped = 0; buf_ptr = *pbuf_ptr; - while (buf_end - buf_ptr > 1) { - v = *buf_ptr++; - v2 = *buf_ptr; - if ((v == 0xff) && (v2 >= SOF0) && (v2 <= COM) && buf_ptr < buf_end) { + while ((buf_ptr = memchr(buf_ptr, 0xff, buf_end - buf_ptr))) { + buf_ptr++; + while (buf_ptr < buf_end) { val = *buf_ptr++; - goto found; + if (val != 0xff) { + if ((val >= SOF0) && (val <= COM)) + goto found; + break; + } } - skipped++; } buf_ptr = buf_end; val = -1; found: - ff_dlog(NULL, "find_marker skipped %d bytes\n", skipped); + ff_dlog(NULL, "find_marker skipped %td bytes\n", + (buf_ptr - *pbuf_ptr) - (val < 0 ? 0 : 2)); *pbuf_ptr = buf_ptr; return val; } -int ff_mjpeg_find_marker(MJpegDecodeContext *s, - const uint8_t **buf_ptr, const uint8_t *buf_end, - const uint8_t **unescaped_buf_ptr, - int *unescaped_buf_size) +static void mjpeg_find_raw_scan_data(MJpegDecodeContext *s, + const uint8_t **pbuf_ptr, size_t *pbuf_size) { - int start_code; - start_code = find_marker(buf_ptr, buf_end); + const uint8_t *buf_ptr = s->gB.buffer; + const uint8_t *buf_end = buf_ptr + bytestream2_get_bytes_left(&s->gB); - av_fast_padded_malloc(&s->buffer, &s->buffer_size, buf_end - *buf_ptr); + /* Find size of image data buffer (including restart markers). + * No unescaping is performed. */ + const uint8_t *ptr = buf_ptr; + while ((ptr = memchr(ptr, 0xff, buf_end - ptr))) { + ptr++; + if (ptr < buf_end) { + uint8_t x = *ptr++; + /* Discard multiple optional 0xFF fill bytes. */ + while (x == 0xff && ptr < buf_end) + x = *ptr++; + if (x && (x < RST0 || x > RST7)) { + /* Non-restart marker */ + ptr -= 2; + goto found_hw; + } + } + } + ptr = buf_end; +found_hw: + *pbuf_ptr = buf_ptr; + *pbuf_size = ptr - buf_ptr; + bytestream2_skipu(&s->gB, *pbuf_size); +} + +int ff_mjpeg_unescape_sos(MJpegDecodeContext *s) +{ + const uint8_t *buf_ptr = s->gB.buffer; + const uint8_t *buf_end = buf_ptr + bytestream2_get_bytes_left(&s->gB); + const uint8_t *unescaped_buf_ptr; + size_t unescaped_buf_size; + + if (s->avctx->codec_id == AV_CODEC_ID_MEDIA100 || + s->avctx->codec_id == AV_CODEC_ID_MJPEGB || + s->avctx->codec_id == AV_CODEC_ID_THP) { + /* The image data buffer is already unescaped. The only way to + * find the size of the buffer is by fully decoding it. */ + unescaped_buf_ptr = buf_ptr; + unescaped_buf_size = buf_end - buf_ptr; + goto the_end; + } + + av_fast_padded_malloc(&s->buffer, &s->buffer_size, buf_end - buf_ptr); if (!s->buffer) return AVERROR(ENOMEM); /* unescape buffer of SOS, use special treatment for JPEG-LS */ - if (start_code == SOS && !s->ls) { - const uint8_t *src = *buf_ptr; + if (!s->ls) { + const uint8_t *src = buf_ptr; const uint8_t *ptr = src; uint8_t *dst = s->buffer; + PutByteContext pb; - #define copy_data_segment(skip) do { \ - ptrdiff_t length = (ptr - src) - (skip); \ - if (length > 0) { \ - memcpy(dst, src, length); \ - dst += length; \ - src = ptr; \ - } \ - } while (0) + bytestream2_init_writer(&pb, dst, buf_end - src); - if (s->avctx->codec_id == AV_CODEC_ID_THP) { - ptr = buf_end; - copy_data_segment(0); - } else { - while (ptr < buf_end) { - uint8_t x = *(ptr++); + while ((ptr = memchr(ptr, 0xff, buf_end - ptr))) { + ptr++; + if (ptr < buf_end) { + /* Copy verbatim data. */ + ptrdiff_t length = (ptr - 1) - src; + if (length > 0) + bytestream2_put_bufferu(&pb, src, length); - if (x == 0xff) { - ptrdiff_t skip = 0; - while (ptr < buf_end && x == 0xff) { - x = *(ptr++); - skip++; - } + uint8_t x = *ptr++; + /* Discard multiple optional 0xFF fill bytes. */ + while (x == 0xff && ptr < buf_end) + x = *ptr++; - /* 0xFF, 0xFF, ... */ - if (skip > 1) { - copy_data_segment(skip); - - /* decrement src as it is equal to ptr after the - * copy_data_segment macro and we might want to - * copy the current value of x later on */ - src--; - } - - if (x < RST0 || x > RST7) { - copy_data_segment(1); - if (x) - break; - } + src = ptr; + if (x == 0) { + /* Stuffed zero byte */ + bytestream2_put_byteu(&pb, 0xff); + } else if (x >= RST0 && x <= RST7) { + /* Restart marker */ + goto found; + } else { + /* Non-restart marker */ + ptr -= 2; + goto found; } } - if (src < ptr) - copy_data_segment(0); } - #undef copy_data_segment + /* Copy remaining verbatim data. */ + ptr = buf_end; + ptrdiff_t length = ptr - src; + if (length > 0) + bytestream2_put_bufferu(&pb, src, length); - *unescaped_buf_ptr = s->buffer; - *unescaped_buf_size = dst - s->buffer; - memset(s->buffer + *unescaped_buf_size, 0, +found: + unescaped_buf_ptr = s->buffer; + unescaped_buf_size = bytestream2_tell_p(&pb); + memset(s->buffer + unescaped_buf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); - av_log(s->avctx, AV_LOG_DEBUG, "escaping removed %"PTRDIFF_SPECIFIER" bytes\n", - (buf_end - *buf_ptr) - (dst - s->buffer)); - } else if (start_code == SOS && s->ls) { - const uint8_t *src = *buf_ptr; + bytestream2_skipu(&s->gB, ptr - buf_ptr); + + av_log(s->avctx, AV_LOG_DEBUG, "escaping removed %td bytes\n", + (buf_end - buf_ptr) - (unescaped_buf_size)); + } else { + const uint8_t *src = buf_ptr; + const uint8_t *ptr = src; uint8_t *dst = s->buffer; - int bit_count = 0; - int t = 0, b = 0; PutBitContext pb; - /* find marker */ - while (src + t < buf_end) { - uint8_t x = src[t++]; - if (x == 0xff) { - while ((src + t < buf_end) && x == 0xff) - x = src[t++]; - if (x & 0x80) { - t -= FFMIN(2, t); - break; - } - } - } - bit_count = t * 8; - init_put_bits(&pb, dst, t); + init_put_bits(&pb, dst, buf_end - src); - /* unescape bitstream */ - while (b < t) { - uint8_t x = src[b++]; - put_bits(&pb, 8, x); - if (x == 0xFF && b < t) { - x = src[b++]; - if (x & 0x80) { - av_log(s->avctx, AV_LOG_WARNING, "Invalid escape sequence\n"); - x &= 0x7f; + while ((ptr = memchr(ptr, 0xff, buf_end - ptr))) { + ptr++; + if (ptr < buf_end) { + /* Copy verbatim data. */ + ptrdiff_t length = (ptr - 1) - src; + if (length > 0) + ff_copy_bits(&pb, src, length * 8); + + uint8_t x = *ptr++; + /* Discard multiple optional 0xFF fill bytes. */ + while (x == 0xff && ptr < buf_end) + x = *ptr++; + + src = ptr; + if (!(x & 0x80)) { + /* Stuffed zero bit */ + put_bits(&pb, 15, 0x7f80 | x); + } else if (x >= RST0 && x <= RST7) { + /* Restart marker */ + goto found_ls; + } else { + /* Non-restart marker */ + ptr -= 2; + goto found_ls; } - put_bits(&pb, 7, x); - bit_count--; } } + /* Copy remaining verbatim data. */ + ptr = buf_end; + ptrdiff_t length = ptr - src; + if (length > 0) + ff_copy_bits(&pb, src, length * 8); + +found_ls: flush_put_bits(&pb); - *unescaped_buf_ptr = dst; - *unescaped_buf_size = (bit_count + 7) >> 3; - memset(s->buffer + *unescaped_buf_size, 0, + unescaped_buf_ptr = dst; + unescaped_buf_size = put_bytes_output(&pb); + memset(s->buffer + unescaped_buf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); - } else { - *unescaped_buf_ptr = *buf_ptr; - *unescaped_buf_size = buf_end - *buf_ptr; + + bytestream2_skipu(&s->gB, ptr - buf_ptr); } - return start_code; +the_end: + return init_get_bits8(&s->gb, unescaped_buf_ptr, unescaped_buf_size); } static void reset_icc_profile(MJpegDecodeContext *s) @@ -2381,20 +2397,17 @@ int ff_mjpeg_decode_frame_from_buf(AVCodecContext *avctx, AVFrame *frame, { MJpegDecodeContext *s = avctx->priv_data; const uint8_t *buf_end, *buf_ptr; - const uint8_t *unescaped_buf_ptr; int hshift, vshift; - int unescaped_buf_size; int start_code; int index; int ret = 0; int is16bit; - AVDictionaryEntry *e = NULL; s->force_pal8 = 0; s->buf_size = buf_size; - av_dict_free(&s->exif_metadata); + av_exif_free(&s->exif_metadata); av_freep(&s->stereo3d); s->adobe_transform = -1; @@ -2406,29 +2419,23 @@ redo_for_pal8: buf_end = buf + buf_size; while (buf_ptr < buf_end) { /* find start next marker */ - start_code = ff_mjpeg_find_marker(s, &buf_ptr, buf_end, - &unescaped_buf_ptr, - &unescaped_buf_size); + start_code = ff_mjpeg_find_marker(&buf_ptr, buf_end); /* EOF */ - if (start_code < 0) { + if (start_code < 0) break; - } else if (unescaped_buf_size > INT_MAX / 8) { + + ptrdiff_t bytes_left = buf_end - buf_ptr; + if (bytes_left > INT_MAX / 8) { av_log(avctx, AV_LOG_ERROR, - "MJPEG packet 0x%x too big (%d/%d), corrupt data?\n", - start_code, unescaped_buf_size, buf_size); + "MJPEG packet 0x%x too big (%td/%d), corrupt data?\n", + start_code, bytes_left, buf_size); return AVERROR_INVALIDDATA; } - av_log(avctx, AV_LOG_DEBUG, "marker=%x avail_size_in_buf=%"PTRDIFF_SPECIFIER"\n", + av_log(avctx, AV_LOG_DEBUG, "marker=%x avail_size_in_buf=%td\n", start_code, buf_end - buf_ptr); - ret = init_get_bits8(&s->gb, unescaped_buf_ptr, unescaped_buf_size); + bytestream2_init(&s->gB, buf_ptr, bytes_left); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "invalid buffer\n"); - goto fail; - } - - s->start_code = start_code; if (avctx->debug & FF_DEBUG_STARTCODE) av_log(avctx, AV_LOG_DEBUG, "startcode: %X\n", start_code); @@ -2438,7 +2445,7 @@ redo_for_pal8: "restart marker: %d\n", start_code & 0x0f); /* APP fields */ } else if (start_code >= APP0 && start_code <= APP15) { - if ((ret = mjpeg_decode_app(s)) < 0) + if ((ret = mjpeg_decode_app(s, start_code)) < 0) av_log(avctx, AV_LOG_ERROR, "unable to decode APP fields: %s\n", av_err2str(ret)); /* Comment */ @@ -2455,21 +2462,18 @@ redo_for_pal8: ret = -1; if (!CONFIG_JPEGLS_DECODER && - (start_code == SOF48 || start_code == LSE)) { + (start_code == SOF55 || start_code == LSE)) { av_log(avctx, AV_LOG_ERROR, "JPEG-LS support not enabled.\n"); return AVERROR(ENOSYS); } if (avctx->skip_frame == AVDISCARD_ALL) { - switch(start_code) { + switch (start_code) { case SOF0: case SOF1: case SOF2: case SOF3: - case SOF48: - case SOI: - case SOS: - case EOI: + case SOF55: break; default: goto skip; @@ -2479,7 +2483,6 @@ redo_for_pal8: switch (start_code) { case SOI: s->restart_interval = 0; - s->restart_count = 0; s->raw_image_buffer = buf_ptr; s->raw_image_buffer_size = buf_end - buf_ptr; /* nothing to do on SOI */ @@ -2512,16 +2515,24 @@ redo_for_pal8: break; case SOF3: avctx->profile = AV_PROFILE_MJPEG_HUFFMAN_LOSSLESS; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif s->lossless = 1; s->ls = 0; s->progressive = 0; if ((ret = ff_mjpeg_decode_sof(s)) < 0) goto fail; break; - case SOF48: + case SOF55: avctx->profile = AV_PROFILE_MJPEG_JPEG_LS; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif s->lossless = 1; s->ls = 1; s->progressive = 0; @@ -2537,7 +2548,7 @@ redo_for_pal8: break; case EOI: eoi_parser: - if (!avctx->hwaccel && avctx->skip_frame != AVDISCARD_ALL && + if (!avctx->hwaccel && s->progressive && s->cur_scan && s->got_picture) mjpeg_idct_scan_progressive_ac(s); s->cur_scan = 0; @@ -2552,10 +2563,6 @@ eoi_parser: if (s->bottom_field == !s->interlace_polarity) break; } - if (avctx->skip_frame == AVDISCARD_ALL) { - s->got_picture = 0; - goto the_end_no_picture; - } if (avctx->hwaccel) { ret = FF_HW_SIMPLE_CALL(avctx, end_frame); if (ret < 0) @@ -2565,6 +2572,8 @@ eoi_parser: } if ((ret = av_frame_ref(frame, s->picture_ptr)) < 0) return ret; + if (s->lossless) + frame->flags |= AV_FRAME_FLAG_LOSSLESS; *got_frame = 1; s->got_picture = 0; @@ -2578,16 +2587,9 @@ eoi_parser: goto the_end; case SOS: - s->raw_scan_buffer = buf_ptr; - s->raw_scan_buffer_size = buf_end - buf_ptr; - s->cur_scan++; - if (avctx->skip_frame == AVDISCARD_ALL) { - skip_bits(&s->gb, get_bits_left(&s->gb)); - break; - } - if ((ret = ff_mjpeg_decode_sos(s, NULL, 0, NULL)) < 0 && + if ((ret = ff_mjpeg_decode_sos(s)) < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) goto fail; break; @@ -2610,12 +2612,24 @@ eoi_parser: break; } + if (avctx->skip_frame == AVDISCARD_ALL) { + switch (start_code) { + case SOF0: + case SOF1: + case SOF2: + case SOF3: + case SOF55: + s->got_picture = 0; + goto the_end_no_picture; + } + } + skip: /* eof process start code */ - buf_ptr += (get_bits_count(&s->gb) + 7) / 8; + buf_ptr += bytestream2_tell(&s->gB); av_log(avctx, AV_LOG_DEBUG, - "marker parser used %d bytes (%d bits)\n", - (get_bits_count(&s->gb) + 7) / 8, get_bits_count(&s->gb)); + "marker parser used %d bytes\n", + bytestream2_tell(&s->gB)); } if (s->got_picture && s->cur_scan) { av_log(avctx, AV_LOG_WARNING, "EOI missing, emulating\n"); @@ -2652,18 +2666,18 @@ the_end: return ret; av_assert0(s->nb_components == av_pix_fmt_count_planes(s->picture_ptr->format)); - for (p = 0; pnb_components; p++) { + for (p = 0; p < s->nb_components; p++) { uint8_t *line = s->picture_ptr->data[p]; int w = s->width; int h = s->height; if (!s->upscale_h[p]) continue; - if (p==1 || p==2) { + if (p == 1 || p == 2) { w = AV_CEIL_RSHIFT(w, hshift); h = AV_CEIL_RSHIFT(h, vshift); } if (s->upscale_v[p] == 1) - h = (h+1)>>1; + h = (h + 1) >> 1; av_assert0(w > 0); for (int i = 0; i < h; i++) { if (s->upscale_h[p] == 1) { @@ -2688,7 +2702,7 @@ the_end: for (index = w - 3; index > 0; index--) { line[index] = (line[index / 3] + line[(index + 1) / 3] + line[(index + 2) / 3] + 1) / 3; } - } else if (s->upscale_h[p] == 4){ + } else if (s->upscale_h[p] == 4) { if (is16bit) { uint16_t *line16 = (uint16_t *) line; line16[w - 1] = line16[(w - 1) >> 2]; @@ -2738,7 +2752,7 @@ the_end: int h = s->height; if (!s->upscale_v[p]) continue; - if (p==1 || p==2) { + if (p == 1 || p == 2) { w = AV_CEIL_RSHIFT(w, hshift); h = AV_CEIL_RSHIFT(h, vshift); } @@ -2762,7 +2776,7 @@ the_end: return ret; av_assert0(s->nb_components == av_pix_fmt_count_planes(frame->format)); - for (index=0; indexnb_components; index++) { + for (index = 0; index < s->nb_components; index++) { int h = frame->height; if (index && index < 3) h = AV_CEIL_RSHIFT(h, vshift); @@ -2788,18 +2802,18 @@ the_end: for (int i = 0; i < h; i++) { int j; uint8_t *dst[4]; - for (index=0; index<4; index++) { + for (index = 0; index < 4; index++) { dst[index] = s->picture_ptr->data[index] + s->picture_ptr->linesize[index]*i; } - for (j=0; j> 16; - dst[1][j] = b*257 >> 16; - dst[2][j] = r*257 >> 16; + dst[0][j] = g * 257 >> 16; + dst[1][j] = b * 257 >> 16; + dst[2][j] = r * 257 >> 16; } memset(dst[3], 255, w); } @@ -2811,18 +2825,18 @@ the_end: for (int i = 0; i < h; i++) { int j; uint8_t *dst[4]; - for (index=0; index<4; index++) { + for (index = 0; index < 4; index++) { dst[index] = s->picture_ptr->data[index] + s->picture_ptr->linesize[index]*i; } - for (j=0; j> 16; - dst[1][j] = (g*257 >> 16) + 128; - dst[2][j] = (b*257 >> 16) + 128; + dst[0][j] = r * 257 >> 16; + dst[1][j] = (g * 257 >> 16) + 128; + dst[2][j] = (b * 257 >> 16) + 128; } memset(dst[3], 255, w); } @@ -2861,60 +2875,13 @@ the_end: } } - if (e = av_dict_get(s->exif_metadata, "Orientation", e, AV_DICT_IGNORE_SUFFIX)) { - char *value = e->value + strspn(e->value, " \n\t\r"), *endptr; - int orientation = strtol(value, &endptr, 0); - - if (!*endptr) { - AVFrameSideData *sd = NULL; - - if (orientation >= 2 && orientation <= 8) { - ret = ff_frame_new_side_data(avctx, frame, AV_FRAME_DATA_DISPLAYMATRIX, sizeof(int32_t) * 9, &sd); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Could not allocate frame side data\n"); - return ret; - } - } - - if (sd) { - int32_t *matrix = (int32_t *)sd->data; - - switch (orientation) { - case 2: - av_display_rotation_set(matrix, 0.0); - av_display_matrix_flip(matrix, 1, 0); - break; - case 3: - av_display_rotation_set(matrix, 180.0); - break; - case 4: - av_display_rotation_set(matrix, 180.0); - av_display_matrix_flip(matrix, 1, 0); - break; - case 5: - av_display_rotation_set(matrix, 90.0); - av_display_matrix_flip(matrix, 1, 0); - break; - case 6: - av_display_rotation_set(matrix, 90.0); - break; - case 7: - av_display_rotation_set(matrix, -90.0); - av_display_matrix_flip(matrix, 1, 0); - break; - case 8: - av_display_rotation_set(matrix, -90.0); - break; - default: - av_assert0(0); - } - } - } + if (s->exif_metadata.entries) { + ret = ff_decode_exif_attach_ifd(avctx, frame, &s->exif_metadata); + av_exif_free(&s->exif_metadata); + if (ret < 0) + av_log(avctx, AV_LOG_WARNING, "couldn't attach EXIF metadata\n"); } - av_dict_copy(&frame->metadata, s->exif_metadata, 0); - av_dict_free(&s->exif_metadata); - if (avctx->codec_id != AV_CODEC_ID_SMVJPEG && (avctx->codec_tag == MKTAG('A', 'V', 'R', 'n') || avctx->codec_tag == MKTAG('A', 'V', 'D', 'J')) && @@ -2924,7 +2891,7 @@ the_end: } the_end_no_picture: - av_log(avctx, AV_LOG_DEBUG, "decode frame unused %"PTRDIFF_SPECIFIER" bytes\n", + av_log(avctx, AV_LOG_DEBUG, "decode frame unused %td bytes\n", buf_end - buf_ptr); return buf_ptr - buf; } @@ -2948,11 +2915,8 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx) av_log(avctx, AV_LOG_INFO, "Single field\n"); } - if (s->picture) { - av_frame_free(&s->picture); - s->picture_ptr = NULL; - } else if (s->picture_ptr) - av_frame_unref(s->picture_ptr); + av_frame_free(&s->picture); + s->picture_ptr = NULL; av_frame_free(&s->smv_frame); @@ -2969,7 +2933,7 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx) av_freep(&s->blocks[i]); av_freep(&s->last_nnz[i]); } - av_dict_free(&s->exif_metadata); + av_exif_free(&s->exif_metadata); reset_icc_profile(s); @@ -2979,7 +2943,7 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx) return 0; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { MJpegDecodeContext *s = avctx->priv_data; s->got_picture = 0; diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h index 13c524d59..29fe5db03 100644 --- a/libavcodec/mjpegdec.h +++ b/libavcodec/mjpegdec.h @@ -36,6 +36,8 @@ #include "avcodec.h" #include "blockdsp.h" +#include "bytestream.h" +#include "exif.h" #include "get_bits.h" #include "hpeldsp.h" #include "idctdsp.h" @@ -55,9 +57,9 @@ typedef struct MJpegDecodeContext { AVClass *class; AVCodecContext *avctx; GetBitContext gb; + GetByteContext gB; int buf_size; - int start_code; /* current start code */ int buffer_size; uint8_t *buffer; @@ -83,6 +85,13 @@ typedef struct MJpegDecodeContext { int xfrm; int adobe_transform; + /* SOS fields */ + int nb_components_sos; + int Ss; + int Se; + int Ah; + int Al; + int maxval; int near; ///< near lossless bound (si 0 for lossless) int t1,t2,t3; @@ -109,7 +118,6 @@ typedef struct MJpegDecodeContext { AVFrame *picture_ptr; /* pointer to picture structure */ int got_picture; ///< we found a SOF and picture is valid, too. int linesize[MAX_COMPONENTS]; ///< linesize << interlaced - int8_t *qscale_table; DECLARE_ALIGNED(32, int16_t, block)[64]; int16_t (*blocks[MAX_COMPONENTS])[64]; ///< intermediate sums (progressive mode) uint8_t *last_nnz[MAX_COMPONENTS]; @@ -118,13 +126,12 @@ typedef struct MJpegDecodeContext { int force_pal8; uint8_t permutated_scantable[64]; BlockDSPContext bdsp; - HpelDSPContext hdsp; IDCTDSPContext idsp; + op_pixels_func copy_block; ///< only set and used by mxpeg int restart_interval; int restart_count; - int buggy_avid; int cs_itu601; int interlace_polarity; int multiscope; @@ -138,7 +145,7 @@ typedef struct MJpegDecodeContext { unsigned int ljpeg_buffer_size; int extern_huff; - AVDictionary *exif_metadata; + AVExifMetadata exif_metadata; AVStereo3D *stereo3d; ///!< stereoscopic information (cached, since it is read before frame allocation) @@ -155,8 +162,6 @@ typedef struct MJpegDecodeContext { // Raw stream data for hwaccel use. const uint8_t *raw_image_buffer; size_t raw_image_buffer_size; - const uint8_t *raw_scan_buffer; - size_t raw_scan_buffer_size; uint8_t raw_huffman_lengths[2][4][16]; uint8_t raw_huffman_values[2][4][256]; @@ -165,6 +170,10 @@ typedef struct MJpegDecodeContext { enum AVPixelFormat hwaccel_pix_fmt; void *hwaccel_picture_private; struct JLSState *jls_state; + + const uint8_t *mb_bitmask; + size_t mb_bitmask_size; + const AVFrame *reference; } MJpegDecodeContext; int ff_mjpeg_build_vlc(VLC *vlc, const uint8_t *bits_table, @@ -180,11 +189,37 @@ int ff_mjpeg_decode_frame_from_buf(AVCodecContext *avctx, int ff_mjpeg_decode_dqt(MJpegDecodeContext *s); int ff_mjpeg_decode_dht(MJpegDecodeContext *s); int ff_mjpeg_decode_sof(MJpegDecodeContext *s); -int ff_mjpeg_decode_sos(MJpegDecodeContext *s, - const uint8_t *mb_bitmask,int mb_bitmask_size, - const AVFrame *reference); -int ff_mjpeg_find_marker(MJpegDecodeContext *s, - const uint8_t **buf_ptr, const uint8_t *buf_end, - const uint8_t **unescaped_buf_ptr, int *unescaped_buf_size); +int ff_mjpeg_decode_sos(MJpegDecodeContext *s); +int ff_mjpeg_find_marker(const uint8_t **buf_ptr, const uint8_t *buf_end); +int ff_mjpeg_unescape_sos(MJpegDecodeContext *s); + +static inline int ff_mjpeg_should_restart(MJpegDecodeContext *s) +{ + int restart = 0; + if (s->restart_interval) { + if (s->restart_count <= 0) { + s->restart_count = s->restart_interval; + restart = 1; + } + s->restart_count--; + } else { + if (s->restart_count < 0) { + s->restart_count = 0; + restart = 1; + } + } + return restart; +} + +static inline int ff_mjpeg_handle_restart(MJpegDecodeContext *s, int *restart) +{ + *restart = ff_mjpeg_should_restart(s); + if (*restart) { + int ret = ff_mjpeg_unescape_sos(s); + if (ret < 0) + return ret; + } + return 0; +} #endif /* AVCODEC_MJPEGDEC_H */ diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c index 40da602a6..ee70e17bc 100644 --- a/libavcodec/mjpegenc.c +++ b/libavcodec/mjpegenc.c @@ -45,12 +45,26 @@ #include "mpegvideoenc.h" #include "profiles.h" +/** + * Buffer of JPEG frame data. + * + * Optimal Huffman table generation requires the frame data to be loaded into + * a buffer so that the tables can be computed. + * There are at most mb_width*mb_height*12*64 of these per frame. + */ +typedef struct MJpegHuffmanCode { + // 0=DC lum, 1=DC chrom, 2=AC lum, 3=AC chrom + uint8_t table_id; ///< The Huffman table id associated with the data. + uint8_t code; ///< The exponent. + uint16_t mant; ///< The mantissa. +} MJpegHuffmanCode; + /* The following is the private context of MJPEG/AMV decoder. * Note that when using slice threading only the main thread's - * MpegEncContext is followed by a MjpegContext; the other threads - * can access this shared context via MpegEncContext.mjpeg. */ + * MPVEncContext is followed by a MjpegContext; the other threads + * can access this shared context via MPVEncContext.mjpeg. */ typedef struct MJPEGEncContext { - MpegEncContext mpeg; + MPVMainEncContext mpeg; MJpegContext mjpeg; } MJPEGEncContext; @@ -78,35 +92,39 @@ static av_cold void init_uni_ac_vlc(const uint8_t huff_size_ac[256], } } -static void mjpeg_encode_picture_header(MpegEncContext *s) +static void mjpeg_encode_picture_header(MPVEncContext *const s) { - ff_mjpeg_encode_picture_header(s->avctx, &s->pb, s->cur_pic.ptr->f, s->mjpeg_ctx, - s->intra_scantable.permutated, 0, - s->intra_matrix, s->chroma_intra_matrix, - s->slice_context_count > 1); + ff_mjpeg_encode_picture_header(s->c.avctx, &s->pb, s->c.cur_pic.ptr->f, s->mjpeg_ctx, + s->c.intra_scantable.permutated, 0, + s->c.intra_matrix, s->c.chroma_intra_matrix, + s->c.slice_context_count > 1); s->esc_pos = put_bytes_count(&s->pb, 0); - for (int i = 1; i < s->slice_context_count; i++) - s->thread_context[i]->esc_pos = 0; + for (int i = 1; i < s->c.slice_context_count; i++) + s->c.enc_contexts[i]->esc_pos = 0; } -void ff_mjpeg_amv_encode_picture_header(MpegEncContext *s) +static int mjpeg_amv_encode_picture_header(MPVMainEncContext *const m) { - MJPEGEncContext *const m = (MJPEGEncContext*)s; - av_assert2(s->mjpeg_ctx == &m->mjpeg); + MJPEGEncContext *const m2 = (MJPEGEncContext*)m; + MPVEncContext *const s = &m->s; + av_assert2(s->mjpeg_ctx == &m2->mjpeg); /* s->huffman == HUFFMAN_TABLE_OPTIMAL can only be true for MJPEG. */ - if (!CONFIG_MJPEG_ENCODER || m->mjpeg.huffman != HUFFMAN_TABLE_OPTIMAL) + if (!CONFIG_MJPEG_ENCODER || m2->mjpeg.huffman != HUFFMAN_TABLE_OPTIMAL) mjpeg_encode_picture_header(s); + + return 0; } #if CONFIG_MJPEG_ENCODER /** * Encodes and outputs the entire frame in the JPEG format. * - * @param s The MpegEncContext. + * @param main The MPVMainEncContext. */ -static void mjpeg_encode_picture_frame(MpegEncContext *s) +static void mjpeg_encode_picture_frame(MPVMainEncContext *const main) { + MPVEncContext *const s = &main->s; int nbits, code, table_id; MJpegContext *m = s->mjpeg_ctx; uint8_t *huff_size[4] = { m->huff_size_dc_luminance, @@ -120,7 +138,7 @@ static void mjpeg_encode_picture_frame(MpegEncContext *s) size_t total_bits = 0; size_t bytes_needed; - s->header_bits = get_bits_diff(s); + main->header_bits = get_bits_diff(s); // Estimate the total size first for (int i = 0; i < m->huff_ncode; i++) { table_id = m->huff_buffer[i].table_id; @@ -214,18 +232,21 @@ static void mjpeg_build_optimal_huffman(MJpegContext *m) * * Header + values + stuffing. * - * @param s The MpegEncContext. + * @param s The MPVEncContext. * @return int Error code, 0 if successful. */ -int ff_mjpeg_encode_stuffing(MpegEncContext *s) +int ff_mjpeg_encode_stuffing(MPVEncContext *const s) { MJpegContext *const m = s->mjpeg_ctx; PutBitContext *pbc = &s->pb; - int mb_y = s->mb_y - !s->mb_x; + int mb_y = s->c.mb_y - !s->c.mb_x; int ret; #if CONFIG_MJPEG_ENCODER if (m->huffman == HUFFMAN_TABLE_OPTIMAL) { + /* HUFFMAN_TABLE_OPTIMAL is incompatible with slice threading, + * therefore the following cast is allowed. */ + MPVMainEncContext *const main = (MPVMainEncContext*)s; mjpeg_build_optimal_huffman(m); @@ -239,128 +260,49 @@ int ff_mjpeg_encode_stuffing(MpegEncContext *s) s->intra_chroma_ac_vlc_last_length = m->uni_chroma_ac_vlc_len; mjpeg_encode_picture_header(s); - mjpeg_encode_picture_frame(s); + mjpeg_encode_picture_frame(main); } #endif ret = ff_mpv_reallocate_putbitbuffer(s, put_bits_count(&s->pb) / 8 + 100, put_bits_count(&s->pb) / 4 + 1000); if (ret < 0) { - av_log(s->avctx, AV_LOG_ERROR, "Buffer reallocation failed\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "Buffer reallocation failed\n"); goto fail; } ff_mjpeg_escape_FF(pbc, s->esc_pos); - if (s->slice_context_count > 1 && mb_y < s->mb_height - 1) + if (s->c.slice_context_count > 1 && mb_y < s->c.mb_height - 1) put_marker(pbc, RST0 + (mb_y&7)); s->esc_pos = put_bytes_count(pbc, 0); fail: for (int i = 0; i < 3; i++) - s->last_dc[i] = 128 << s->intra_dc_precision; + s->last_dc[i] = 128; return ret; } -static int alloc_huffman(MpegEncContext *s) +static int alloc_huffman(MJPEGEncContext *const m2) { - MJpegContext *m = s->mjpeg_ctx; - size_t num_mbs, num_blocks, num_codes; - int blocks_per_mb; - - // We need to init this here as the mjpeg init is called before the common init, - s->mb_width = (s->width + 15) / 16; - s->mb_height = (s->height + 15) / 16; - - switch (s->chroma_format) { - case CHROMA_420: blocks_per_mb = 6; break; - case CHROMA_422: blocks_per_mb = 8; break; - case CHROMA_444: blocks_per_mb = 12; break; - default: av_assert0(0); + MJpegContext *const m = &m2->mjpeg; + MPVEncContext *const s = &m2->mpeg.s; + static const char blocks_per_mb[] = { + [CHROMA_420] = 6, [CHROMA_422] = 8, [CHROMA_444] = 12 }; + size_t num_blocks; // Make sure we have enough space to hold this frame. - num_mbs = s->mb_width * s->mb_height; - num_blocks = num_mbs * blocks_per_mb; - num_codes = num_blocks * 64; + num_blocks = s->c.mb_num * blocks_per_mb[s->c.chroma_format]; - m->huff_buffer = av_malloc_array(num_codes, sizeof(MJpegHuffmanCode)); + m->huff_buffer = av_malloc_array(num_blocks, + 64 /* codes per MB */ * sizeof(MJpegHuffmanCode)); if (!m->huff_buffer) return AVERROR(ENOMEM); return 0; } -av_cold int ff_mjpeg_encode_init(MpegEncContext *s) -{ - MJpegContext *const m = &((MJPEGEncContext*)s)->mjpeg; - int ret, use_slices; - - s->mjpeg_ctx = m; - use_slices = s->avctx->slices > 0 ? s->avctx->slices > 1 : - (s->avctx->active_thread_type & FF_THREAD_SLICE) && - s->avctx->thread_count > 1; - - if (s->codec_id == AV_CODEC_ID_AMV || use_slices) - m->huffman = HUFFMAN_TABLE_DEFAULT; - - if (s->mpv_flags & FF_MPV_FLAG_QP_RD) { - // Used to produce garbage with MJPEG. - av_log(s->avctx, AV_LOG_ERROR, - "QP RD is no longer compatible with MJPEG or AMV\n"); - return AVERROR(EINVAL); - } - - /* The following check is automatically true for AMV, - * but it doesn't hurt either. */ - ret = ff_mjpeg_encode_check_pix_fmt(s->avctx); - if (ret < 0) - return ret; - - if (s->width > 65500 || s->height > 65500) { - av_log(s, AV_LOG_ERROR, "JPEG does not support resolutions above 65500x65500\n"); - return AVERROR(EINVAL); - } - - s->min_qcoeff=-1023; - s->max_qcoeff= 1023; - - // Build default Huffman tables. - // These may be overwritten later with more optimal Huffman tables, but - // they are needed at least right now for some processes like trellis. - ff_mjpeg_build_huffman_codes(m->huff_size_dc_luminance, - m->huff_code_dc_luminance, - ff_mjpeg_bits_dc_luminance, - ff_mjpeg_val_dc); - ff_mjpeg_build_huffman_codes(m->huff_size_dc_chrominance, - m->huff_code_dc_chrominance, - ff_mjpeg_bits_dc_chrominance, - ff_mjpeg_val_dc); - ff_mjpeg_build_huffman_codes(m->huff_size_ac_luminance, - m->huff_code_ac_luminance, - ff_mjpeg_bits_ac_luminance, - ff_mjpeg_val_ac_luminance); - ff_mjpeg_build_huffman_codes(m->huff_size_ac_chrominance, - m->huff_code_ac_chrominance, - ff_mjpeg_bits_ac_chrominance, - ff_mjpeg_val_ac_chrominance); - - init_uni_ac_vlc(m->huff_size_ac_luminance, m->uni_ac_vlc_len); - init_uni_ac_vlc(m->huff_size_ac_chrominance, m->uni_chroma_ac_vlc_len); - s->intra_ac_vlc_length = - s->intra_ac_vlc_last_length = m->uni_ac_vlc_len; - s->intra_chroma_ac_vlc_length = - s->intra_chroma_ac_vlc_last_length = m->uni_chroma_ac_vlc_len; - - // Buffers start out empty. - m->huff_ncode = 0; - - if (m->huffman == HUFFMAN_TABLE_OPTIMAL) - return alloc_huffman(s); - - return 0; -} - static av_cold int mjpeg_encode_close(AVCodecContext *avctx) { MJPEGEncContext *const mjpeg = avctx->priv_data; @@ -376,7 +318,7 @@ static av_cold int mjpeg_encode_close(AVCodecContext *avctx) * @param table_id Which Huffman table the code belongs to. * @param code The encoded exponent of the coefficients and the run-bits. */ -static inline void ff_mjpeg_encode_code(MJpegContext *s, uint8_t table_id, int code) +static inline void mjpeg_encode_code(MJpegContext *s, uint8_t table_id, int code) { MJpegHuffmanCode *c = &s->huff_buffer[s->huff_ncode++]; c->table_id = table_id; @@ -391,13 +333,13 @@ static inline void ff_mjpeg_encode_code(MJpegContext *s, uint8_t table_id, int c * @param val The coefficient. * @param run The run-bits. */ -static void ff_mjpeg_encode_coef(MJpegContext *s, uint8_t table_id, int val, int run) +static void mjpeg_encode_coef(MJpegContext *s, uint8_t table_id, int val, int run) { int mant, code; if (val == 0) { av_assert0(run == 0); - ff_mjpeg_encode_code(s, table_id, 0); + mjpeg_encode_code(s, table_id, 0); } else { mant = val; if (val < 0) { @@ -408,18 +350,18 @@ static void ff_mjpeg_encode_coef(MJpegContext *s, uint8_t table_id, int val, int code = (run << 4) | (av_log2_16bit(val) + 1); s->huff_buffer[s->huff_ncode].mant = mant; - ff_mjpeg_encode_code(s, table_id, code); + mjpeg_encode_code(s, table_id, code); } } /** * Add the block's data into the JPEG buffer. * - * @param s The MpegEncContext that contains the JPEG buffer. + * @param s The MPVEncContext that contains the JPEG buffer. * @param block The block. * @param n The block's index or number. */ -static void record_block(MpegEncContext *s, int16_t *block, int n) +static void record_block(MPVEncContext *const s, int16_t block[], int n) { int i, j, table_id; int component, dc, last_index, val, run; @@ -431,44 +373,44 @@ static void record_block(MpegEncContext *s, int16_t *block, int n) dc = block[0]; /* overflow is impossible */ val = dc - s->last_dc[component]; - ff_mjpeg_encode_coef(m, table_id, val, 0); + mjpeg_encode_coef(m, table_id, val, 0); s->last_dc[component] = dc; /* AC coefs */ run = 0; - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; table_id |= 2; for(i=1;i<=last_index;i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; val = block[j]; if (val == 0) { run++; } else { while (run >= 16) { - ff_mjpeg_encode_code(m, table_id, 0xf0); + mjpeg_encode_code(m, table_id, 0xf0); run -= 16; } - ff_mjpeg_encode_coef(m, table_id, val, run); + mjpeg_encode_coef(m, table_id, val, run); run = 0; } } /* output EOB only if not already 64 values */ if (last_index < 63 || run != 0) - ff_mjpeg_encode_code(m, table_id, 0); + mjpeg_encode_code(m, table_id, 0); } -static void encode_block(MpegEncContext *s, int16_t *block, int n) +static void encode_block(MPVEncContext *const s, int16_t block[], int n) { int mant, nbits, code, i, j; int component, dc, run, last_index, val; - MJpegContext *m = s->mjpeg_ctx; - uint8_t *huff_size_ac; - uint16_t *huff_code_ac; + const MJpegContext *const m = s->mjpeg_ctx; + const uint16_t *huff_code_ac; + const uint8_t *huff_size_ac; /* DC coef */ component = (n <= 3 ? 0 : (n&1) + 1); @@ -488,9 +430,9 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n) /* AC coefs */ run = 0; - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; for(i=1;i<=last_index;i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; val = block[j]; if (val == 0) { run++; @@ -520,79 +462,159 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n) put_bits(&s->pb, huff_size_ac[0], huff_code_ac[0]); } -void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[12][64]) +static void mjpeg_record_mb(MPVEncContext *const s, int16_t block[][64], + int unused_x, int unused_y) { - int i; - if (s->mjpeg_ctx->huffman == HUFFMAN_TABLE_OPTIMAL) { - if (s->chroma_format == CHROMA_444) { - record_block(s, block[0], 0); - record_block(s, block[2], 2); - record_block(s, block[4], 4); - record_block(s, block[8], 8); - record_block(s, block[5], 5); - record_block(s, block[9], 9); + if (s->c.chroma_format == CHROMA_444) { + record_block(s, block[0], 0); + record_block(s, block[2], 2); + record_block(s, block[4], 4); + record_block(s, block[8], 8); + record_block(s, block[5], 5); + record_block(s, block[9], 9); - if (16*s->mb_x+8 < s->width) { - record_block(s, block[1], 1); - record_block(s, block[3], 3); - record_block(s, block[6], 6); - record_block(s, block[10], 10); - record_block(s, block[7], 7); - record_block(s, block[11], 11); - } - } else { - for(i=0;i<5;i++) { - record_block(s, block[i], i); - } - if (s->chroma_format == CHROMA_420) { - record_block(s, block[5], 5); - } else { - record_block(s, block[6], 6); - record_block(s, block[5], 5); - record_block(s, block[7], 7); - } + if (16*s->c.mb_x+8 < s->c.width) { + record_block(s, block[1], 1); + record_block(s, block[3], 3); + record_block(s, block[6], 6); + record_block(s, block[10], 10); + record_block(s, block[7], 7); + record_block(s, block[11], 11); } } else { - if (s->chroma_format == CHROMA_444) { - encode_block(s, block[0], 0); - encode_block(s, block[2], 2); - encode_block(s, block[4], 4); - encode_block(s, block[8], 8); - encode_block(s, block[5], 5); - encode_block(s, block[9], 9); - - if (16*s->mb_x+8 < s->width) { - encode_block(s, block[1], 1); - encode_block(s, block[3], 3); - encode_block(s, block[6], 6); - encode_block(s, block[10], 10); - encode_block(s, block[7], 7); - encode_block(s, block[11], 11); - } + for (int i = 0; i < 5; i++) + record_block(s, block[i], i); + if (s->c.chroma_format == CHROMA_420) { + record_block(s, block[5], 5); } else { - for(i=0;i<5;i++) { - encode_block(s, block[i], i); - } - if (s->chroma_format == CHROMA_420) { - encode_block(s, block[5], 5); - } else { - encode_block(s, block[6], 6); - encode_block(s, block[5], 5); - encode_block(s, block[7], 7); - } + record_block(s, block[6], 6); + record_block(s, block[5], 5); + record_block(s, block[7], 7); } - - s->i_tex_bits += get_bits_diff(s); } } +static void mjpeg_encode_mb(MPVEncContext *const s, int16_t block[][64], + int unused_x, int unused_y) +{ + if (s->c.chroma_format == CHROMA_444) { + encode_block(s, block[0], 0); + encode_block(s, block[2], 2); + encode_block(s, block[4], 4); + encode_block(s, block[8], 8); + encode_block(s, block[5], 5); + encode_block(s, block[9], 9); + + if (16 * s->c.mb_x + 8 < s->c.width) { + encode_block(s, block[1], 1); + encode_block(s, block[3], 3); + encode_block(s, block[6], 6); + encode_block(s, block[10], 10); + encode_block(s, block[7], 7); + encode_block(s, block[11], 11); + } + } else { + for (int i = 0; i < 5; i++) + encode_block(s, block[i], i); + if (s->c.chroma_format == CHROMA_420) { + encode_block(s, block[5], 5); + } else { + encode_block(s, block[6], 6); + encode_block(s, block[5], 5); + encode_block(s, block[7], 7); + } + } + + s->i_tex_bits += get_bits_diff(s); +} + +static av_cold int mjpeg_encode_init(AVCodecContext *avctx) +{ + MJPEGEncContext *const m2 = avctx->priv_data; + MJpegContext *const m = &m2->mjpeg; + MPVEncContext *const s = &m2->mpeg.s; + int ret; + + s->mjpeg_ctx = m; + m2->mpeg.encode_picture_header = mjpeg_amv_encode_picture_header; + // May be overridden below + s->encode_mb = mjpeg_encode_mb; + + if (s->mpv_flags & FF_MPV_FLAG_QP_RD) { + // Used to produce garbage with MJPEG. + av_log(avctx, AV_LOG_ERROR, + "QP RD is no longer compatible with MJPEG or AMV\n"); + return AVERROR(EINVAL); + } + + /* The following check is automatically true for AMV, + * but it doesn't hurt either. */ + ret = ff_mjpeg_encode_check_pix_fmt(avctx); + if (ret < 0) + return ret; + + if (avctx->width > 65500 || avctx->height > 65500) { + av_log(avctx, AV_LOG_ERROR, "JPEG does not support resolutions above 65500x65500\n"); + return AVERROR(EINVAL); + } + + // Build default Huffman tables. + // These may be overwritten later with more optimal Huffman tables, but + // they are needed at least right now for some processes like trellis. + ff_mjpeg_build_huffman_codes(m->huff_size_dc_luminance, + m->huff_code_dc_luminance, + ff_mjpeg_bits_dc_luminance, + ff_mjpeg_val_dc); + ff_mjpeg_build_huffman_codes(m->huff_size_dc_chrominance, + m->huff_code_dc_chrominance, + ff_mjpeg_bits_dc_chrominance, + ff_mjpeg_val_dc); + ff_mjpeg_build_huffman_codes(m->huff_size_ac_luminance, + m->huff_code_ac_luminance, + ff_mjpeg_bits_ac_luminance, + ff_mjpeg_val_ac_luminance); + ff_mjpeg_build_huffman_codes(m->huff_size_ac_chrominance, + m->huff_code_ac_chrominance, + ff_mjpeg_bits_ac_chrominance, + ff_mjpeg_val_ac_chrominance); + + init_uni_ac_vlc(m->huff_size_ac_luminance, m->uni_ac_vlc_len); + init_uni_ac_vlc(m->huff_size_ac_chrominance, m->uni_chroma_ac_vlc_len); + + s->min_qcoeff = -1023; + s->max_qcoeff = 1023; + + s->intra_ac_vlc_length = + s->intra_ac_vlc_last_length = m->uni_ac_vlc_len; + s->intra_chroma_ac_vlc_length = + s->intra_chroma_ac_vlc_last_length = m->uni_chroma_ac_vlc_len; + + ret = ff_mpv_encode_init(avctx); + if (ret < 0) + return ret; + + // Buffers start out empty. + m->huff_ncode = 0; + + if (s->c.slice_context_count > 1) + m->huffman = HUFFMAN_TABLE_DEFAULT; + + if (m->huffman == HUFFMAN_TABLE_OPTIMAL) { + // If we are here, we have only one slice_context. So no loop necessary. + s->encode_mb = mjpeg_record_mb; + return alloc_huffman(m2); + } + + return 0; +} + #if CONFIG_AMV_ENCODER // maximum over s->mjpeg_vsample[i] #define V_MAX 2 static int amv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pic_arg, int *got_packet) { - MpegEncContext *s = avctx->priv_data; + MPVEncContext *const s = avctx->priv_data; AVFrame *pic; int i, ret; int chroma_v_shift = 1; /* AMV is 420-only */ @@ -612,7 +634,7 @@ static int amv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, //picture should be flipped upside-down for(i=0; i < 3; i++) { int vsample = i ? 2 >> chroma_v_shift : 2; - pic->data[i] += pic->linesize[i] * (vsample * s->height / V_MAX - 1); + pic->data[i] += pic->linesize[i] * (vsample * s->c.height / V_MAX - 1); pic->linesize[i] *= -1; } ret = ff_mpv_encode_picture(avctx, pkt, pic, got_packet); @@ -624,11 +646,12 @@ static int amv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, #define OFFSET(x) offsetof(MJPEGEncContext, mjpeg.x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { -FF_MPV_COMMON_OPTS +#define AMV_OPTIONS_OFFSET 4 { "huffman", "Huffman table strategy", OFFSET(huffman), AV_OPT_TYPE_INT, { .i64 = HUFFMAN_TABLE_OPTIMAL }, 0, NB_HUFFMAN_TABLE_OPTION - 1, VE, .unit = "huffman" }, { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = HUFFMAN_TABLE_DEFAULT }, INT_MIN, INT_MAX, VE, .unit = "huffman" }, { "optimal", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = HUFFMAN_TABLE_OPTIMAL }, INT_MIN, INT_MAX, VE, .unit = "huffman" }, { "force_duplicated_matrix", "Always write luma and chroma matrix for mjpeg, useful for rtp streaming.", OFFSET(force_duplicated_matrix), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, VE }, +FF_MPV_COMMON_OPTS { NULL}, }; @@ -660,23 +683,21 @@ static int mjpeg_get_supported_config(const AVCodecContext *avctx, return ff_default_get_supported_config(avctx, codec, config, flags, out, out_num); } -FFCodec ff_mjpeg_encoder = { +const FFCodec ff_mjpeg_encoder = { .p.name = "mjpeg", CODEC_LONG_NAME("MJPEG (Motion JPEG)"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MJPEG, .priv_data_size = sizeof(MJPEGEncContext), - .init = ff_mpv_encode_init, + .init = mjpeg_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = mjpeg_encode_close, - .p.capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | + .p.capabilities = AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_ICC_PROFILES, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P), .p.priv_class = &mjpeg_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_mjpeg_profiles), .get_supported_config = mjpeg_get_supported_config, @@ -687,7 +708,7 @@ FFCodec ff_mjpeg_encoder = { static const AVClass amv_class = { .class_name = "amv encoder", .item_name = av_default_item_name, - .option = options, + .option = options + AMV_OPTIONS_OFFSET, .version = LIBAVUTIL_VERSION_INT, }; @@ -696,16 +717,14 @@ const FFCodec ff_amv_encoder = { CODEC_LONG_NAME("AMV Video"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_AMV, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(MJPEGEncContext), - .init = ff_mpv_encode_init, + .init = mjpeg_encode_init, FF_CODEC_ENCODE_CB(amv_encode_picture), .close = mjpeg_encode_close, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUVJ420P), .color_ranges = AVCOL_RANGE_JPEG, .p.priv_class = &amv_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, }; #endif diff --git a/libavcodec/mjpegenc.h b/libavcodec/mjpegenc.h index a593b67e9..92feed28b 100644 --- a/libavcodec/mjpegenc.h +++ b/libavcodec/mjpegenc.h @@ -36,23 +36,8 @@ #include #include "mjpeg.h" -#include "mpegvideo.h" #include "put_bits.h" -/** - * Buffer of JPEG frame data. - * - * Optimal Huffman table generation requires the frame data to be loaded into - * a buffer so that the tables can be computed. - * There are at most mb_width*mb_height*12*64 of these per frame. - */ -typedef struct MJpegHuffmanCode { - // 0=DC lum, 1=DC chrom, 2=AC lum, 3=AC chrom - uint8_t table_id; ///< The Huffman table id associated with the data. - uint8_t code; ///< The exponent. - uint16_t mant; ///< The mantissa. -} MJpegHuffmanCode; - /** * Holds JPEG frame data and Huffman table data. */ @@ -71,9 +56,9 @@ typedef struct MJpegContext { uint8_t huff_size_ac_chrominance[256]; ///< AC chrominance Huffman table size. uint16_t huff_code_ac_chrominance[256]; ///< AC chrominance Huffman table codes. - /** Storage for AC luminance VLC (in MpegEncContext) */ + /** Storage for AC luminance VLC */ uint8_t uni_ac_vlc_len[64 * 64 * 2]; - /** Storage for AC chrominance VLC (in MpegEncContext) */ + /** Storage for AC chrominance VLC */ uint8_t uni_chroma_ac_vlc_len[64 * 64 * 2]; // Default DC tables have exactly 12 values @@ -89,7 +74,7 @@ typedef struct MJpegContext { uint8_t val_ac_chrominance[256]; ///< AC chrominance Huffman values. size_t huff_ncode; ///< Number of current entries in the buffer. - MJpegHuffmanCode *huff_buffer; ///< Buffer for Huffman code values. + struct MJpegHuffmanCode *huff_buffer; ///< Buffer for Huffman code values. } MJpegContext; /** @@ -107,9 +92,8 @@ static inline void put_marker(PutBitContext *p, enum JpegMarker code) put_bits(p, 8, code); } -int ff_mjpeg_encode_init(MpegEncContext *s); -void ff_mjpeg_amv_encode_picture_header(MpegEncContext *s); -void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[12][64]); -int ff_mjpeg_encode_stuffing(MpegEncContext *s); +typedef struct MPVEncContext MPVEncContext; + +int ff_mjpeg_encode_stuffing(MPVEncContext *s); #endif /* AVCODEC_MJPEGENC_H */ diff --git a/libavcodec/mjpegenc_common.c b/libavcodec/mjpegenc_common.c index 751e43fd3..5effbdbc3 100644 --- a/libavcodec/mjpegenc_common.c +++ b/libavcodec/mjpegenc_common.c @@ -56,10 +56,10 @@ static int put_huffman_table(PutBitContext *p, int table_class, int table_id, } static void jpeg_table_header(AVCodecContext *avctx, PutBitContext *p, - MJpegContext *m, + const MJpegContext *m, const uint8_t intra_matrix_permutation[64], - uint16_t luma_intra_matrix[64], - uint16_t chroma_intra_matrix[64], + const uint16_t luma_intra_matrix[64], + const uint16_t chroma_intra_matrix[64], int hsample[3], int use_slices, int matrices_differ) { int size; @@ -145,7 +145,7 @@ int ff_mjpeg_add_icc_profile_size(AVCodecContext *avctx, const AVFrame *frame, return 0; if (sd->size > ICC_MAX_CHUNKS * ICC_CHUNK_SIZE) { - av_log(avctx, AV_LOG_ERROR, "Cannot store %"SIZE_SPECIFIER" byte ICC " + av_log(avctx, AV_LOG_ERROR, "Cannot store %zu byte ICC " "profile: too large for JPEG\n", sd->size); return AVERROR_INVALIDDATA; @@ -246,7 +246,7 @@ static void jpeg_put_comments(AVCodecContext *avctx, PutBitContext *p, } } -void ff_mjpeg_init_hvsample(AVCodecContext *avctx, int hsample[4], int vsample[4]) +void ff_mjpeg_init_hvsample(const AVCodecContext *avctx, int hsample[4], int vsample[4]) { if (avctx->codec_id == AV_CODEC_ID_LJPEG && ( avctx->pix_fmt == AV_PIX_FMT_BGR0 @@ -273,10 +273,10 @@ void ff_mjpeg_init_hvsample(AVCodecContext *avctx, int hsample[4], int vsample[4 } void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, - const AVFrame *frame, struct MJpegContext *m, + const AVFrame *frame, const struct MJpegContext *m, const uint8_t intra_matrix_permutation[64], int pred, - uint16_t luma_intra_matrix[64], - uint16_t chroma_intra_matrix[64], + const uint16_t luma_intra_matrix[64], + const uint16_t chroma_intra_matrix[64], int use_slices) { const int lossless = !m; @@ -304,7 +304,8 @@ void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, switch (avctx->codec_id) { case AV_CODEC_ID_MJPEG: put_marker(pb, SOF0 ); break; case AV_CODEC_ID_LJPEG: put_marker(pb, SOF3 ); break; - default: av_assert0(0); + default: av_unreachable("ff_mjpeg_encode_picture_header only called by " + "AMV, LJPEG, MJPEG and the former has been ruled out"); } put_bits(pb, 16, 8 + 3 * components); @@ -375,7 +376,7 @@ void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, switch (avctx->codec_id) { case AV_CODEC_ID_MJPEG: put_bits(pb, 8, 63); break; /* Se (not used) */ case AV_CODEC_ID_LJPEG: put_bits(pb, 8, 0); break; /* not used */ - default: av_assert0(0); + default: av_unreachable("Only LJPEG, MJPEG possible here"); } put_bits(pb, 8, 0); /* Ah/Al (not used) */ @@ -465,7 +466,7 @@ void ff_mjpeg_encode_picture_trailer(PutBitContext *pb, int header_bits) } void ff_mjpeg_encode_dc(PutBitContext *pb, int val, - uint8_t *huff_size, uint16_t *huff_code) + const uint8_t huff_size[], const uint16_t huff_code[]) { int mant, nbits; diff --git a/libavcodec/mjpegenc_common.h b/libavcodec/mjpegenc_common.h index e9f0ea44a..0cf5a7270 100644 --- a/libavcodec/mjpegenc_common.h +++ b/libavcodec/mjpegenc_common.h @@ -31,21 +31,21 @@ struct MJpegContext; int ff_mjpeg_add_icc_profile_size(AVCodecContext *avctx, const AVFrame *frame, size_t *max_pkt_size); void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, - const AVFrame *frame, struct MJpegContext *m, + const AVFrame *frame, const struct MJpegContext *m, const uint8_t intra_matrix_permutation[64], int pred, - uint16_t luma_intra_matrix[64], - uint16_t chroma_intra_matrix[64], + const uint16_t luma_intra_matrix[64], + const uint16_t chroma_intra_matrix[64], int use_slices); void ff_mjpeg_encode_picture_trailer(PutBitContext *pb, int header_bits); void ff_mjpeg_escape_FF(PutBitContext *pb, int start); void ff_mjpeg_build_huffman_codes(uint8_t *huff_size, uint16_t *huff_code, const uint8_t *bits_table, const uint8_t *val_table); -void ff_mjpeg_init_hvsample(AVCodecContext *avctx, int hsample[4], int vsample[4]); +void ff_mjpeg_init_hvsample(const AVCodecContext *avctx, int hsample[4], int vsample[4]); void ff_mjpeg_encode_dc(PutBitContext *pb, int val, - uint8_t *huff_size, uint16_t *huff_code); + const uint8_t huff_size[], const uint16_t huff_code[]); int ff_mjpeg_encode_check_pix_fmt(AVCodecContext *avctx); diff --git a/libavcodec/mjpegenc_huffman.c b/libavcodec/mjpegenc_huffman.c index 9bfcb7e78..5a0d8b0b4 100644 --- a/libavcodec/mjpegenc_huffman.c +++ b/libavcodec/mjpegenc_huffman.c @@ -25,6 +25,24 @@ #include "libavutil/qsort.h" #include "mjpegenc_huffman.h" +/** + * Used to assign a occurrence count or "probability" to an input value + */ +typedef struct PTable { + int value; ///< input value + int prob; ///< number of occurrences of this value in input +} PTable; + +/** + * Used to store intermediate lists in the package merge algorithm + */ +typedef struct PackageMergerList { + int nitems; ///< number of items in the list and probability ex. 4 + int item_idx[515]; ///< index range for each item in items 0, 2, 5, 9, 13 + int probability[514]; ///< probability of each item 3, 8, 18, 46 + int items[257 * 16]; ///< chain of all individual values that make up items A, B, A, B, C, A, B, C, D, C, D, D, E +} PackageMergerList; + /** * Comparison function for two PTables by prob * @@ -39,20 +57,6 @@ static int compare_by_prob(const void *a, const void *b) return a_val.prob - b_val.prob; } -/** - * Comparison function for two HuffTables by length - * - * @param a First HuffTable to compare - * @param b Second HuffTable to compare - * @return < 0 for less than, 0 for equals, > 0 for greater than - */ -static int compare_by_length(const void *a, const void *b) -{ - HuffTable a_val = *(HuffTable *) a; - HuffTable b_val = *(HuffTable *) b; - return a_val.length - b_val.length; -} - /** * Computes the length of the Huffman encoding for each distinct input value. * Uses package merge algorithm as follows: @@ -66,15 +70,17 @@ static int compare_by_length(const void *a, const void *b) * 8. the length of the huffman code for symbol s will be equal to the number of times the symbol occurs in the select elements * Go to guru.multimedia.cx/small-tasks-for-ffmpeg/ for more details * - * All probabilities should be positive integers. The output is sorted by code, - * not by length. + * All probabilities should be nonnegative integers. * - * @param prob_table input array of a PTable for each distinct input value - * @param distincts output array of a HuffTable that will be populated by this function - * @param size size of the prob_table array - * @param max_length max length of an encoding + * @param prob_table[in,out] array of a PTable for each distinct input value, + * will be sorted according to ascending probability + * @param counts[out] the number of values of a given length + * @param size number of elements of the prob_table array + * @param max_length max length of a code */ -void ff_mjpegenc_huffman_compute_bits(PTable *prob_table, HuffTable *distincts, int size, int max_length) +static void mjpegenc_huffman_compute_bits(PTable *prob_table, + uint8_t counts[/* max_length + 1 */], + int size, int max_length) { PackageMergerList list_a, list_b, *to = &list_a, *from = &list_b, *temp; @@ -132,14 +138,9 @@ void ff_mjpegenc_huffman_compute_bits(PTable *prob_table, HuffTable *distincts, } // we don't want to return the 256 bit count (it was just in here to prevent // all 1s encoding) - j = 0; - for (i = 0; i < 256; i++) { - if (nbits[i] > 0) { - distincts[j].code = i; - distincts[j].length = nbits[i]; - j++; - } - } + memset(counts, 0, sizeof(counts[0]) * (max_length + 1)); + for (int i = 0; i < 256; ++i) + counts[nbits[i]]++; } void ff_mjpeg_encode_huffman_init(MJpegEncHuffmanContext *s) @@ -158,32 +159,28 @@ void ff_mjpeg_encode_huffman_init(MJpegEncHuffmanContext *s) void ff_mjpeg_encode_huffman_close(MJpegEncHuffmanContext *s, uint8_t bits[17], uint8_t val[], int max_nval) { - int i, j; - int nval = 0; PTable val_counts[257]; - HuffTable distincts[256]; - for (i = 0; i < 256; i++) { - if (s->val_count[i]) nval++; - } - av_assert0 (nval <= max_nval); + av_assert1(max_nval <= FF_ARRAY_ELEMS(val_counts) - 1); - j = 0; - for (i = 0; i < 256; i++) { + int nval = 0; + for (int i = 0; i < 256; i++) { if (s->val_count[i]) { - val_counts[j].value = i; - val_counts[j].prob = s->val_count[i]; - j++; + val_counts[nval].value = i; + val_counts[nval].prob = s->val_count[i]; + nval++; + av_assert2(nval <= max_nval); } } - val_counts[j].value = 256; - val_counts[j].prob = 0; - ff_mjpegenc_huffman_compute_bits(val_counts, distincts, nval + 1, 16); - AV_QSORT(distincts, nval, HuffTable, compare_by_length); + val_counts[nval].value = 256; + val_counts[nval].prob = 0; - memset(bits, 0, sizeof(bits[0]) * 17); - for (i = 0; i < nval; i++) { - val[i] = distincts[i].code; - bits[distincts[i].length]++; - } + mjpegenc_huffman_compute_bits(val_counts, bits, nval + 1, 16); + + // val_counts[0] is the fake element we added earlier. + av_assert1(val_counts[0].prob == 0 && val_counts[0].value == 256); + // The following loop puts the values with higher occurrence first, + // ensuring that they get the shorter codes. + for (int i = 0; i < nval; ++i) + val[i] = val_counts[nval - i].value; } diff --git a/libavcodec/mjpegenc_huffman.h b/libavcodec/mjpegenc_huffman.h index 5fe65504e..8822e468a 100644 --- a/libavcodec/mjpegenc_huffman.h +++ b/libavcodec/mjpegenc_huffman.h @@ -44,33 +44,4 @@ void ff_mjpeg_encode_huffman_close(MJpegEncHuffmanContext *s, uint8_t bits[17], uint8_t val[], int max_nval); - -/** - * Used to assign a occurrence count or "probability" to an input value - */ -typedef struct PTable { - int value; ///< input value - int prob; ///< number of occurences of this value in input -} PTable; - -/** - * Used to store intermediate lists in the package merge algorithm - */ -typedef struct PackageMergerList { - int nitems; ///< number of items in the list and probability ex. 4 - int item_idx[515]; ///< index range for each item in items 0, 2, 5, 9, 13 - int probability[514]; ///< probability of each item 3, 8, 18, 46 - int items[257 * 16]; ///< chain of all individual values that make up items A, B, A, B, C, A, B, C, D, C, D, D, E -} PackageMergerList; - -/** - * Used to store optimal huffman encoding results - */ -typedef struct HuffTable { - int code; ///< code is the input value - int length; ///< length of the encoding -} HuffTable; - -void ff_mjpegenc_huffman_compute_bits(PTable *prob_table, HuffTable *distincts, - int size, int max_length); #endif /* AVCODEC_MJPEGENC_HUFFMAN_H */ diff --git a/libavcodec/mlp.c b/libavcodec/mlp.c index 33045c08c..6a545d45d 100644 --- a/libavcodec/mlp.c +++ b/libavcodec/mlp.c @@ -70,13 +70,11 @@ const AVChannelLayout ff_mlp_ch_layouts[12] = { #define CRC_TABLE_SIZE 1024 #endif static AVCRC crc_63[CRC_TABLE_SIZE]; -static AVCRC crc_1D[CRC_TABLE_SIZE]; static AVCRC crc_2D[CRC_TABLE_SIZE]; static av_cold void mlp_init_crc(void) { av_crc_init(crc_63, 0, 8, 0x63, sizeof(crc_63)); - av_crc_init(crc_1D, 0, 8, 0x1D, sizeof(crc_1D)); av_crc_init(crc_2D, 0, 16, 0x002D, sizeof(crc_2D)); } @@ -104,11 +102,15 @@ uint8_t ff_mlp_checksum8(const uint8_t *buf, unsigned int buf_size) uint8_t ff_mlp_restart_checksum(const uint8_t *buf, unsigned int bit_size) { + const AVCRC *crc_1D = av_crc_get_table(AV_CRC_8_EBU); int i; int num_bytes = (bit_size + 2) / 8; - int crc = crc_1D[buf[0] & 0x3f]; - crc = av_crc(crc_1D, crc, buf + 1, num_bytes - 2); + // The two most significant bits of buf[0] are not supposed + // to be contained in the checksum; using buf[0] & 0xC0 as start value + // achieves this. + int crc = av_crc(crc_1D, buf[0] & 0xC0, buf, num_bytes - 1); + crc ^= buf[num_bytes - 1]; for (i = 0; i < ((bit_size + 2) & 7); i++) { diff --git a/libavcodec/mlp_parser.c b/libavcodec/mlp_parser.c index d391390dd..4f348c5d4 100644 --- a/libavcodec/mlp_parser.c +++ b/libavcodec/mlp_parser.c @@ -31,6 +31,7 @@ #include "parser.h" #include "mlp_parse.h" #include "mlp.h" +#include "parser_internal.h" typedef struct MLPParseContext { @@ -204,10 +205,10 @@ lost_sync: return 1; } -const AVCodecParser ff_mlp_parser = { - .codec_ids = { AV_CODEC_ID_MLP, AV_CODEC_ID_TRUEHD }, +const FFCodecParser ff_mlp_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_MLP, AV_CODEC_ID_TRUEHD), .priv_data_size = sizeof(MLPParseContext), - .parser_init = mlp_init, - .parser_parse = mlp_parse, - .parser_close = ff_parse_close, + .init = mlp_init, + .parse = mlp_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c index e69e4442d..580efc3cf 100644 --- a/libavcodec/mlpdec.c +++ b/libavcodec/mlpdec.c @@ -29,6 +29,7 @@ #include #include "avcodec.h" +#include "libavutil/attributes.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/channel_layout.h" @@ -1411,7 +1412,7 @@ error: return AVERROR_INVALIDDATA; } -static void mlp_decode_flush(AVCodecContext *avctx) +static av_cold void mlp_decode_flush(AVCodecContext *avctx) { MLPDecodeContext *m = avctx->priv_data; diff --git a/libavcodec/mlpenc.c b/libavcodec/mlpenc.c index 06670de45..4d4c33f48 100644 --- a/libavcodec/mlpenc.c +++ b/libavcodec/mlpenc.c @@ -521,10 +521,7 @@ static av_cold int mlp_encode_init(AVCodecContext *avctx) ctx->fs = 0x10 + 2; break; default: - av_log(avctx, AV_LOG_ERROR, "Unsupported sample rate %d. Supported " - "sample rates are 44100, 88200, 176400, 48000, " - "96000, and 192000.\n", avctx->sample_rate); - return AVERROR(EINVAL); + av_unreachable("Checked via CODEC_SAMPLERATES"); } ctx->coded_sample_rate[1] = -1 & 0xf; @@ -547,9 +544,7 @@ static av_cold int mlp_encode_init(AVCodecContext *avctx) avctx->bits_per_raw_sample = 24; break; default: - av_log(avctx, AV_LOG_ERROR, "Sample format not supported. " - "Only 16- and 24-bit samples are supported.\n"); - return AVERROR(EINVAL); + av_unreachable("Checked via CODEC_SAMPLEFMTS"); } ctx->coded_sample_fmt[1] = -1 & 0xf; @@ -613,7 +608,7 @@ static av_cold int mlp_encode_init(AVCodecContext *avctx) ctx->thd_substream_info = 0x3C; break; default: - av_assert1(!"AVCodec.ch_layouts needs to be updated"); + av_unreachable("Checked via CODEC_CH_LAYOUTS"); } ctx->flags = 0; ctx->channel_occupancy = 0; @@ -2308,9 +2303,9 @@ const FFCodec ff_mlp_encoder = { FF_CODEC_ENCODE_CB(mlp_encode_frame), .close = mlp_encode_close, .p.priv_class = &mlp_class, - .p.sample_fmts = (const enum AVSampleFormat[]) {AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE}, - .p.supported_samplerates = (const int[]) {44100, 48000, 88200, 96000, 176400, 192000, 0}, - .p.ch_layouts = ff_mlp_ch_layouts, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P), + CODEC_SAMPLERATES(44100, 48000, 88200, 96000, 176400, 192000), + CODEC_CH_LAYOUTS_ARRAY(ff_mlp_ch_layouts), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif @@ -2328,20 +2323,13 @@ const FFCodec ff_truehd_encoder = { FF_CODEC_ENCODE_CB(mlp_encode_frame), .close = mlp_encode_close, .p.priv_class = &mlp_class, - .p.sample_fmts = (const enum AVSampleFormat[]) {AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE}, - .p.supported_samplerates = (const int[]) {44100, 48000, 88200, 96000, 176400, 192000, 0}, - .p.ch_layouts = (const AVChannelLayout[]) { - AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - AV_CHANNEL_LAYOUT_2POINT1, - AV_CHANNEL_LAYOUT_SURROUND, - AV_CHANNEL_LAYOUT_3POINT1, - AV_CHANNEL_LAYOUT_4POINT0, - AV_CHANNEL_LAYOUT_4POINT1, - AV_CHANNEL_LAYOUT_5POINT0, - AV_CHANNEL_LAYOUT_5POINT1, - { 0 } - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P), + CODEC_SAMPLERATES(44100, 48000, 88200, 96000, 176400, 192000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO, + AV_CHANNEL_LAYOUT_2POINT1, AV_CHANNEL_LAYOUT_SURROUND, + AV_CHANNEL_LAYOUT_3POINT1, AV_CHANNEL_LAYOUT_4POINT0, + AV_CHANNEL_LAYOUT_4POINT1, AV_CHANNEL_LAYOUT_5POINT0, + AV_CHANNEL_LAYOUT_5POINT1), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/mlz.h b/libavcodec/mlz.h index 24993126c..666a8d0b2 100644 --- a/libavcodec/mlz.h +++ b/libavcodec/mlz.h @@ -42,7 +42,7 @@ typedef struct MLZDict { int match_len; } MLZDict; -/** MLZ data strucure +/** MLZ data structure */ typedef struct MLZ { int dic_code_bit; diff --git a/libavcodec/mmvideo.c b/libavcodec/mmvideo.c index 3038d9ea9..2a0c85599 100644 --- a/libavcodec/mmvideo.c +++ b/libavcodec/mmvideo.c @@ -39,6 +39,7 @@ #define MM_PREAMBLE_SIZE 6 +#define MM_TYPE_RAW 0x2 #define MM_TYPE_INTER 0x5 #define MM_TYPE_INTRA 0x8 #define MM_TYPE_INTRA_HH 0xc @@ -76,15 +77,21 @@ static av_cold int mm_decode_init(AVCodecContext *avctx) return 0; } +static int mm_decode_raw(MmContext * s) +{ + if (bytestream2_get_bytes_left(&s->gb) < s->avctx->width * s->avctx->height) + return AVERROR_INVALIDDATA; + for (int y = 0; y < s->avctx->height; y++) + bytestream2_get_buffer(&s->gb, s->frame->data[0] + y*s->frame->linesize[0], s->avctx->width); + return 0; +} + static void mm_decode_pal(MmContext *s) { - int i; - - bytestream2_skip(&s->gb, 4); - for (i = 0; i < 128; i++) { - s->palette[i] = 0xFFU << 24 | bytestream2_get_be24(&s->gb); - s->palette[i+128] = s->palette[i]<<2; - } + int start = bytestream2_get_le16(&s->gb); + int count = bytestream2_get_le16(&s->gb); + for (int i = 0; i < count; i++) + s->palette[(start+i)&0xFF] = 0xFFU << 24 | (bytestream2_get_be24(&s->gb) << 2); } /** @@ -164,7 +171,7 @@ static int mm_decode_inter(MmContext * s, int half_horiz, int half_vert) for(j=0; j<8; j++) { int replace = (replace_array >> (7-j)) & 1; if (x + half_horiz >= s->avctx->width) - return AVERROR_INVALIDDATA; + break; if (replace) { int color = bytestream2_get_byte(&data_ptr); s->frame->data[0][y*s->frame->linesize[0] + x] = color; @@ -205,6 +212,7 @@ static int mm_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return res; switch(type) { + case MM_TYPE_RAW : res = mm_decode_raw(s); break; case MM_TYPE_PALETTE : mm_decode_pal(s); return avpkt->size; case MM_TYPE_INTRA : res = mm_decode_intra(s, 0, 0); break; case MM_TYPE_INTRA_HH : res = mm_decode_intra(s, 1, 0); break; diff --git a/libavcodec/mobiclip.c b/libavcodec/mobiclip.c index 133a835ad..8e8fe4480 100644 --- a/libavcodec/mobiclip.c +++ b/libavcodec/mobiclip.c @@ -23,6 +23,7 @@ #include +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/mem.h" #include "libavutil/thread.h" @@ -1315,7 +1316,7 @@ static int mobiclip_decode(AVCodecContext *avctx, AVFrame *rframe, return 0; } -static void mobiclip_flush(AVCodecContext *avctx) +static av_cold void mobiclip_flush(AVCodecContext *avctx) { MobiClipContext *s = avctx->priv_data; diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c index c0c2f315f..8ca6f16a7 100644 --- a/libavcodec/motion_est.c +++ b/libavcodec/motion_est.c @@ -32,6 +32,7 @@ #include #include "avcodec.h" +#include "h263.h" #include "mathops.h" #include "motion_est.h" #include "mpegutils.h" @@ -46,7 +47,7 @@ #define ME_MAP_SHIFT 3 #define ME_MAP_MV_BITS 11 -static int sad_hpel_motion_search(MpegEncContext * s, +static int sad_hpel_motion_search(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h); @@ -90,12 +91,12 @@ static inline void init_ref(MotionEstContext *c, uint8_t *const src[3], }; int i; for(i=0; i<3; i++){ - c->src[0][i]= src[i] ? FF_PTR_ADD(src[i], offset[i]) : NULL; - c->ref[0][i]= ref[i] ? FF_PTR_ADD(ref[i], offset[i]) : NULL; + c->src[0][i]= src[i] ? src[i] + offset[i] : NULL; + c->ref[0][i]= ref[i] ? ref[i] + offset[i] : NULL; } if(ref_index){ for(i=0; i<3; i++){ - c->ref[ref_index][i]= ref2[i] ? FF_PTR_ADD(ref2[i], offset[i]) : NULL; + c->ref[ref_index][i]= ref2[i] ? ref2[i] + offset[i] : NULL; } } } @@ -106,10 +107,10 @@ static int get_flags(MotionEstContext *c, int direct, int chroma){ + (chroma ? FLAG_CHROMA : 0); } -static av_always_inline int cmp_direct_inline(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static av_always_inline int cmp_direct_inline(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, int qpel){ - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int stride= c->stride; const int hx = subx + x * (1 << (1 + qpel)); const int hy = suby + y * (1 << (1 + qpel)); @@ -117,71 +118,71 @@ static av_always_inline int cmp_direct_inline(MpegEncContext *s, const int x, co const uint8_t * const * const src = c->src[src_index]; int d; //FIXME check chroma 4mv, (no crashes ...) - av_assert2(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1)); - if(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1)){ - const int time_pp= s->pp_time; - const int time_pb= s->pb_time; - const int mask= 2*qpel+1; - if(s->mv_type==MV_TYPE_8X8){ - int i; - for(i=0; i<4; i++){ - int fx = c->direct_basis_mv[i][0] + hx; - int fy = c->direct_basis_mv[i][1] + hy; - int bx = hx ? fx - c->co_located_mv[i][0] : c->co_located_mv[i][0]*(time_pb - time_pp)/time_pp + ((i &1)<<(qpel+4)); - int by = hy ? fy - c->co_located_mv[i][1] : c->co_located_mv[i][1]*(time_pb - time_pp)/time_pp + ((i>>1)<<(qpel+4)); - int fxy= (fx&mask) + ((fy&mask)<<(qpel+1)); - int bxy= (bx&mask) + ((by&mask)<<(qpel+1)); + av_assert2(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1)); + if (x >= c->xmin && hx <= c->xmax << (qpel + 1) && + y >= c->ymin && hy <= c->ymax << (qpel + 1)) { + const int time_pp = s->c.pp_time; + const int time_pb = s->c.pb_time; + const int mask = 2 * qpel + 1; + if (s->c.mv_type == MV_TYPE_8X8) { + for(int i = 0; i < 4; ++i) { + int fx = c->direct_basis_mv[i][0] + hx; + int fy = c->direct_basis_mv[i][1] + hy; + int bx = hx ? fx - c->co_located_mv[i][0] : c->co_located_mv[i][0] * (time_pb - time_pp)/time_pp + ((i &1)<<(qpel+4)); + int by = hy ? fy - c->co_located_mv[i][1] : c->co_located_mv[i][1] * (time_pb - time_pp)/time_pp + ((i>>1)<<(qpel+4)); + int fxy = (fx & mask) + ((fy & mask) << (qpel + 1)); + int bxy = (bx & mask) + ((by & mask) << (qpel + 1)); - uint8_t *dst= c->temp + 8*(i&1) + 8*stride*(i>>1); - if(qpel){ - c->qpel_put[1][fxy](dst, ref[0] + (fx>>2) + (fy>>2)*stride, stride); - c->qpel_avg[1][bxy](dst, ref[8] + (bx>>2) + (by>>2)*stride, stride); - }else{ - c->hpel_put[1][fxy](dst, ref[0] + (fx>>1) + (fy>>1)*stride, stride, 8); - c->hpel_avg[1][bxy](dst, ref[8] + (bx>>1) + (by>>1)*stride, stride, 8); - } - } - }else{ - int fx = c->direct_basis_mv[0][0] + hx; - int fy = c->direct_basis_mv[0][1] + hy; - int bx = hx ? fx - c->co_located_mv[0][0] : (c->co_located_mv[0][0]*(time_pb - time_pp)/time_pp); - int by = hy ? fy - c->co_located_mv[0][1] : (c->co_located_mv[0][1]*(time_pb - time_pp)/time_pp); - int fxy= (fx&mask) + ((fy&mask)<<(qpel+1)); - int bxy= (bx&mask) + ((by&mask)<<(qpel+1)); - - if(qpel){ - c->qpel_put[1][fxy](c->temp , ref[0] + (fx>>2) + (fy>>2)*stride , stride); - c->qpel_put[1][fxy](c->temp + 8 , ref[0] + (fx>>2) + (fy>>2)*stride + 8 , stride); - c->qpel_put[1][fxy](c->temp + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8*stride, stride); - c->qpel_put[1][fxy](c->temp + 8 + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8 + 8*stride, stride); - c->qpel_avg[1][bxy](c->temp , ref[8] + (bx>>2) + (by>>2)*stride , stride); - c->qpel_avg[1][bxy](c->temp + 8 , ref[8] + (bx>>2) + (by>>2)*stride + 8 , stride); - c->qpel_avg[1][bxy](c->temp + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8*stride, stride); - c->qpel_avg[1][bxy](c->temp + 8 + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8 + 8*stride, stride); - }else{ - av_assert2((fx>>1) + 16*s->mb_x >= -16); - av_assert2((fy>>1) + 16*s->mb_y >= -16); - av_assert2((fx>>1) + 16*s->mb_x <= s->width); - av_assert2((fy>>1) + 16*s->mb_y <= s->height); - av_assert2((bx>>1) + 16*s->mb_x >= -16); - av_assert2((by>>1) + 16*s->mb_y >= -16); - av_assert2((bx>>1) + 16*s->mb_x <= s->width); - av_assert2((by>>1) + 16*s->mb_y <= s->height); - - c->hpel_put[0][fxy](c->temp, ref[0] + (fx>>1) + (fy>>1)*stride, stride, 16); - c->hpel_avg[0][bxy](c->temp, ref[8] + (bx>>1) + (by>>1)*stride, stride, 16); + uint8_t *dst = c->temp + 8 * (i & 1) + 8 * stride * (i >> 1); + if (qpel) { + c->qpel_put[1][fxy](dst, ref[0] + (fx >> 2) + (fy >> 2) * stride, stride); + c->qpel_avg[1][bxy](dst, ref[8] + (bx >> 2) + (by >> 2) * stride, stride); + } else { + c->hpel_put[1][fxy](dst, ref[0] + (fx >> 1) + (fy >> 1) * stride, stride, 8); + c->hpel_avg[1][bxy](dst, ref[8] + (bx >> 1) + (by >> 1) * stride, stride, 8); } } - d = cmp_func(s, c->temp, src[0], stride, 16); - }else - d= 256*256*256*32; + } else { + int fx = c->direct_basis_mv[0][0] + hx; + int fy = c->direct_basis_mv[0][1] + hy; + int bx = hx ? fx - c->co_located_mv[0][0] : (c->co_located_mv[0][0] * (time_pb - time_pp)/time_pp); + int by = hy ? fy - c->co_located_mv[0][1] : (c->co_located_mv[0][1] * (time_pb - time_pp)/time_pp); + int fxy = (fx & mask) + ((fy & mask) << (qpel + 1)); + int bxy = (bx & mask) + ((by & mask) << (qpel + 1)); + + if (qpel) { + c->qpel_put[1][fxy](c->temp , ref[0] + (fx>>2) + (fy>>2)*stride , stride); + c->qpel_put[1][fxy](c->temp + 8 , ref[0] + (fx>>2) + (fy>>2)*stride + 8 , stride); + c->qpel_put[1][fxy](c->temp + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8*stride, stride); + c->qpel_put[1][fxy](c->temp + 8 + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8 + 8*stride, stride); + c->qpel_avg[1][bxy](c->temp , ref[8] + (bx>>2) + (by>>2)*stride , stride); + c->qpel_avg[1][bxy](c->temp + 8 , ref[8] + (bx>>2) + (by>>2)*stride + 8 , stride); + c->qpel_avg[1][bxy](c->temp + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8*stride, stride); + c->qpel_avg[1][bxy](c->temp + 8 + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8 + 8*stride, stride); + } else { + av_assert2((fx >> 1) + 16 * s->c.mb_x >= -16); + av_assert2((fy >> 1) + 16 * s->c.mb_y >= -16); + av_assert2((fx >> 1) + 16 * s->c.mb_x <= s->c.width); + av_assert2((fy >> 1) + 16 * s->c.mb_y <= s->c.height); + av_assert2((bx >> 1) + 16 * s->c.mb_x >= -16); + av_assert2((by >> 1) + 16 * s->c.mb_y >= -16); + av_assert2((bx >> 1) + 16 * s->c.mb_x <= s->c.width); + av_assert2((by >> 1) + 16 * s->c.mb_y <= s->c.height); + + c->hpel_put[0][fxy](c->temp, ref[0] + (fx >> 1) + (fy >> 1) * stride, stride, 16); + c->hpel_avg[0][bxy](c->temp, ref[8] + (bx >> 1) + (by >> 1) * stride, stride, 16); + } + } + d = cmp_func(s, c->temp, src[0], stride, 16); + } else + d = 256 * 256 * 256 * 32; return d; } -static av_always_inline int cmp_inline(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static av_always_inline int cmp_inline(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, int qpel, int chroma){ - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int stride= c->stride; const int uvstride= c->uvstride; const int dxy= subx + (suby<<(1+qpel)); //FIXME log2_subpel? @@ -191,52 +192,52 @@ static av_always_inline int cmp_inline(MpegEncContext *s, const int x, const int const uint8_t * const * const src = c->src[src_index]; int d; //FIXME check chroma 4mv, (no crashes ...) - int uvdxy; /* no, it might not be used uninitialized */ - if(dxy){ - if(qpel){ - if (h << size == 16) { - c->qpel_put[size][dxy](c->temp, ref[0] + x + y*stride, stride); //FIXME prototype (add h) - } else if (size == 0 && h == 8) { - c->qpel_put[1][dxy](c->temp , ref[0] + x + y*stride , stride); - c->qpel_put[1][dxy](c->temp + 8, ref[0] + x + y*stride + 8, stride); - } else - av_assert2(0); - if(chroma){ - int cx= hx/2; - int cy= hy/2; - cx= (cx>>1)|(cx&1); - cy= (cy>>1)|(cy&1); - uvdxy= (cx&1) + 2*(cy&1); - // FIXME x/y wrong, but MPEG-4 qpel is sick anyway, we should drop as much of it as possible in favor for H.264 - } - }else{ - c->hpel_put[size][dxy](c->temp, ref[0] + x + y*stride, stride, h); - if(chroma) - uvdxy= dxy | (x&1) | (2*(y&1)); + int uvdxy; /* no, it might not be used uninitialized */ + if (dxy) { + if (qpel) { + if (h << size == 16) { + c->qpel_put[size][dxy](c->temp, ref[0] + x + y * stride, stride); //FIXME prototype (add h) + } else if (size == 0 && h == 8) { + c->qpel_put[1][dxy](c->temp , ref[0] + x + y * stride , stride); + c->qpel_put[1][dxy](c->temp + 8, ref[0] + x + y * stride + 8, stride); + } else + av_assert2(0); + if (chroma) { + int cx = hx / 2; + int cy = hy / 2; + cx = (cx >> 1) | (cx & 1); + cy = (cy >> 1) | (cy & 1); + uvdxy = (cx & 1) + 2 * (cy & 1); + // FIXME x/y wrong, but MPEG-4 qpel is sick anyway, we should drop as much of it as possible in favor for H.264 } - d = cmp_func(s, c->temp, src[0], stride, h); - }else{ - d = cmp_func(s, src[0], ref[0] + x + y*stride, stride, h); - if(chroma) - uvdxy= (x&1) + 2*(y&1); - } - if(chroma){ - uint8_t * const uvtemp= c->temp + 16*stride; - c->hpel_put[size+1][uvdxy](uvtemp , ref[1] + (x>>1) + (y>>1)*uvstride, uvstride, h>>1); - c->hpel_put[size+1][uvdxy](uvtemp+8, ref[2] + (x>>1) + (y>>1)*uvstride, uvstride, h>>1); - d += chroma_cmp_func(s, uvtemp , src[1], uvstride, h>>1); - d += chroma_cmp_func(s, uvtemp+8, src[2], uvstride, h>>1); + } else { + c->hpel_put[size][dxy](c->temp, ref[0] + x + y * stride, stride, h); + if (chroma) + uvdxy = dxy | (x & 1) | (2 * (y & 1)); } + d = cmp_func(s, c->temp, src[0], stride, h); + } else { + d = cmp_func(s, src[0], ref[0] + x + y * stride, stride, h); + if (chroma) + uvdxy = (x & 1) + 2 * (y & 1); + } + if (chroma) { + uint8_t *const uvtemp = c->temp + 16 * stride; + c->hpel_put[size + 1][uvdxy](uvtemp , ref[1] + (x >> 1) + (y >> 1) * uvstride, uvstride, h >> 1); + c->hpel_put[size + 1][uvdxy](uvtemp + 8, ref[2] + (x >> 1) + (y >> 1) * uvstride, uvstride, h >> 1); + d += chroma_cmp_func(s, uvtemp , src[1], uvstride, h >> 1); + d += chroma_cmp_func(s, uvtemp + 8, src[2], uvstride, h >> 1); + } return d; } -static int cmp_simple(MpegEncContext *s, const int x, const int y, +static int cmp_simple(MPVEncContext *const s, const int x, const int y, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func){ return cmp_inline(s,x,y,0,0,0,16,ref_index,src_index, cmp_func, chroma_cmp_func, 0, 0); } -static int cmp_fpel_internal(MpegEncContext *s, const int x, const int y, +static int cmp_fpel_internal(MPVEncContext *const s, const int x, const int y, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ if(flags&FLAG_DIRECT){ @@ -246,7 +247,7 @@ static int cmp_fpel_internal(MpegEncContext *s, const int x, const int y, } } -static int cmp_internal(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static int cmp_internal(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ if(flags&FLAG_DIRECT){ @@ -259,7 +260,7 @@ static int cmp_internal(MpegEncContext *s, const int x, const int y, const int s /** @brief compares a block (either a full macroblock or a partition thereof) against a proposed motion-compensated prediction of that block */ -static av_always_inline int cmp(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static av_always_inline int cmp(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ if(av_builtin_constant_p(flags) && av_builtin_constant_p(h) && av_builtin_constant_p(size) @@ -274,7 +275,7 @@ static av_always_inline int cmp(MpegEncContext *s, const int x, const int y, con } } -static int cmp_hpel(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static int cmp_hpel(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ if(flags&FLAG_DIRECT){ @@ -284,7 +285,7 @@ static int cmp_hpel(MpegEncContext *s, const int x, const int y, const int subx, } } -static int cmp_qpel(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static int cmp_qpel(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ if(flags&FLAG_DIRECT){ @@ -296,7 +297,7 @@ static int cmp_qpel(MpegEncContext *s, const int x, const int y, const int subx, #include "motion_est_template.c" -static int zero_cmp(MpegEncContext *s, const uint8_t *a, const uint8_t *b, +static int zero_cmp(MPVEncContext *const s, const uint8_t *a, const uint8_t *b, ptrdiff_t stride, int h) { return 0; @@ -367,35 +368,39 @@ av_cold int ff_me_init(MotionEstContext *c, AVCodecContext *avctx, return 0; } -void ff_me_init_pic(MpegEncContext *s) +void ff_me_init_pic(MPVEncContext *const s) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; -/*FIXME s->no_rounding b_type*/ - if (s->avctx->flags & AV_CODEC_FLAG_QPEL) { - c->qpel_avg = s->qdsp.avg_qpel_pixels_tab; - if (s->no_rounding) - c->qpel_put = s->qdsp.put_no_rnd_qpel_pixels_tab; +/*FIXME s->c.no_rounding b_type*/ + if (c->avctx->flags & AV_CODEC_FLAG_QPEL) { + c->qpel_avg = s->c.qdsp.avg_qpel_pixels_tab; + if (s->c.no_rounding) + c->qpel_put = s->c.qdsp.put_no_rnd_qpel_pixels_tab; else - c->qpel_put = s->qdsp.put_qpel_pixels_tab; + c->qpel_put = s->c.qdsp.put_qpel_pixels_tab; } - c->hpel_avg = s->hdsp.avg_pixels_tab; - if (s->no_rounding) - c->hpel_put = s->hdsp.put_no_rnd_pixels_tab; + c->hpel_avg = s->c.hdsp.avg_pixels_tab; + if (s->c.no_rounding) + c->hpel_put = s->c.hdsp.put_no_rnd_pixels_tab; else - c->hpel_put = s->hdsp.put_pixels_tab; + c->hpel_put = s->c.hdsp.put_pixels_tab; - if(s->linesize){ - c->stride = s->linesize; - c->uvstride= s->uvlinesize; + if (s->c.linesize) { + c->stride = s->c.linesize; + c->uvstride = s->c.uvlinesize; }else{ - c->stride = 16*s->mb_width + 32; - c->uvstride= 8*s->mb_width + 16; + c->stride = 16*s->c.mb_width + 32; + c->uvstride = 8*s->c.mb_width + 16; } - if (s->codec_id != AV_CODEC_ID_SNOW) { + if (s->c.codec_id != AV_CODEC_ID_SNOW) { c->hpel_put[2][0]= c->hpel_put[2][1]= c->hpel_put[2][2]= c->hpel_put[2][3]= zero_hpel; } + /* Reset the average MB variance and scene change stats */ + c->scene_change_score = 0; + c->mb_var_sum_temp = + c->mc_mb_var_sum_temp = 0; } #define CHECK_SAD_HALF_MV(suffix, x, y) \ @@ -405,12 +410,12 @@ void ff_me_init_pic(MpegEncContext *s) COPY3_IF_LT(dminh, d, dx, x, dy, y)\ } -static int sad_hpel_motion_search(MpegEncContext * s, +static int sad_hpel_motion_search(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int penalty_factor= c->sub_penalty_factor; int mx, my, dminh; const uint8_t *pix, *ptr; @@ -510,58 +515,58 @@ static int sad_hpel_motion_search(MpegEncContext * s, return dminh; } -static inline void set_p_mv_tables(MpegEncContext * s, int mx, int my, int mv4) +static inline void set_p_mv_tables(MPVEncContext *const s, int mx, int my, int mv4) { - const int xy= s->mb_x + s->mb_y*s->mb_stride; + const int xy = s->c.mb_x + s->c.mb_y * s->c.mb_stride; s->p_mv_table[xy][0] = mx; s->p_mv_table[xy][1] = my; /* has already been set to the 4 MV if 4MV is done */ if(mv4){ - int mot_xy= s->block_index[0]; + int mot_xy = s->c.block_index[0]; - s->cur_pic.motion_val[0][mot_xy ][0] = mx; - s->cur_pic.motion_val[0][mot_xy ][1] = my; - s->cur_pic.motion_val[0][mot_xy + 1][0] = mx; - s->cur_pic.motion_val[0][mot_xy + 1][1] = my; + s->c.cur_pic.motion_val[0][mot_xy ][0] = mx; + s->c.cur_pic.motion_val[0][mot_xy ][1] = my; + s->c.cur_pic.motion_val[0][mot_xy + 1][0] = mx; + s->c.cur_pic.motion_val[0][mot_xy + 1][1] = my; - mot_xy += s->b8_stride; - s->cur_pic.motion_val[0][mot_xy ][0] = mx; - s->cur_pic.motion_val[0][mot_xy ][1] = my; - s->cur_pic.motion_val[0][mot_xy + 1][0] = mx; - s->cur_pic.motion_val[0][mot_xy + 1][1] = my; + mot_xy += s->c.b8_stride; + s->c.cur_pic.motion_val[0][mot_xy ][0] = mx; + s->c.cur_pic.motion_val[0][mot_xy ][1] = my; + s->c.cur_pic.motion_val[0][mot_xy + 1][0] = mx; + s->c.cur_pic.motion_val[0][mot_xy + 1][1] = my; } } /** * get fullpel ME search limits. */ -static inline void get_limits(MpegEncContext *s, int x, int y, int bframe) +static inline void get_limits(MPVEncContext *const s, int x, int y, int bframe) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int range= c->avctx->me_range >> (1 + !!(c->flags&FLAG_QPEL)); int max_range = MAX_MV >> (1 + !!(c->flags&FLAG_QPEL)); /* if(c->avctx->me_range) c->range= c->avctx->me_range >> 1; else c->range= 16; */ - if (s->unrestricted_mv) { + if (c->unrestricted_mv) { c->xmin = - x - 16; c->ymin = - y - 16; - c->xmax = - x + s->width; - c->ymax = - y + s->height; - } else if (!(av_builtin_constant_p(bframe) && bframe) && s->out_format == FMT_H261){ + c->xmax = - x + s->c.width; + c->ymax = - y + s->c.height; + } else if (!(av_builtin_constant_p(bframe) && bframe) && s->c.out_format == FMT_H261){ // Search range of H.261 is different from other codec standards c->xmin = (x > 15) ? - 15 : 0; c->ymin = (y > 15) ? - 15 : 0; - c->xmax = (x < s->mb_width * 16 - 16) ? 15 : 0; - c->ymax = (y < s->mb_height * 16 - 16) ? 15 : 0; + c->xmax = (x < s->c.mb_width * 16 - 16) ? 15 : 0; + c->ymax = (y < s->c.mb_height * 16 - 16) ? 15 : 0; } else { c->xmin = - x; c->ymin = - y; - c->xmax = - x + s->mb_width *16 - 16; - c->ymax = - y + s->mb_height*16 - 16; + c->xmax = - x + s->c.mb_width *16 - 16; + c->ymax = - y + s->c.mb_height*16 - 16; } if(!range || range > max_range) range = max_range; @@ -584,9 +589,9 @@ static inline void init_mv4_ref(MotionEstContext *c){ c->src[3][0] = c->src[2][0] + 8; } -static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) +static inline int h263_mv4_search(MPVEncContext *const s, int mx, int my, int shift) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int size= 1; const int h=8; int block; @@ -595,7 +600,7 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) int same=1; const int stride= c->stride; const uint8_t *mv_penalty = c->current_mv_penalty; - int safety_clipping= s->unrestricted_mv && (s->width&15) && (s->height&15); + int safety_clipping = c->unrestricted_mv && (s->c.width&15) && (s->c.height&15); init_mv4_ref(c); @@ -604,28 +609,28 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) int pred_x4, pred_y4; int dmin4; static const int off[4]= {2, 1, 1, -1}; - const int mot_stride = s->b8_stride; - const int mot_xy = s->block_index[block]; + const int mot_stride = s->c.b8_stride; + const int mot_xy = s->c.block_index[block]; if(safety_clipping){ - c->xmax = - 16*s->mb_x + s->width - 8*(block &1); - c->ymax = - 16*s->mb_y + s->height - 8*(block>>1); + c->xmax = - 16*s->c.mb_x + s->c.width - 8*(block &1); + c->ymax = - 16*s->c.mb_y + s->c.height - 8*(block>>1); } - P_LEFT[0] = s->cur_pic.motion_val[0][mot_xy - 1][0]; - P_LEFT[1] = s->cur_pic.motion_val[0][mot_xy - 1][1]; + P_LEFT[0] = s->c.cur_pic.motion_val[0][mot_xy - 1][0]; + P_LEFT[1] = s->c.cur_pic.motion_val[0][mot_xy - 1][1]; if (P_LEFT[0] > c->xmax * (1 << shift)) P_LEFT[0] = c->xmax * (1 << shift); /* special case for first line */ - if (s->first_slice_line && block<2) { + if (s->c.first_slice_line && block < 2) { c->pred_x= pred_x4= P_LEFT[0]; c->pred_y= pred_y4= P_LEFT[1]; } else { - P_TOP[0] = s->cur_pic.motion_val[0][mot_xy - mot_stride ][0]; - P_TOP[1] = s->cur_pic.motion_val[0][mot_xy - mot_stride ][1]; - P_TOPRIGHT[0] = s->cur_pic.motion_val[0][mot_xy - mot_stride + off[block]][0]; - P_TOPRIGHT[1] = s->cur_pic.motion_val[0][mot_xy - mot_stride + off[block]][1]; + P_TOP[0] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride ][0]; + P_TOP[1] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride ][1]; + P_TOPRIGHT[0] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride + off[block]][0]; + P_TOPRIGHT[1] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride + off[block]][1]; if (P_TOP[1] > c->ymax * (1 << shift)) P_TOP[1] = c->ymax * (1 << shift); if (P_TOPRIGHT[0] < c->xmin * (1 << shift)) P_TOPRIGHT[0] = c->xmin * (1 << shift); if (P_TOPRIGHT[0] > c->xmax * (1 << shift)) P_TOPRIGHT[0] = c->xmax * (1 << shift); @@ -641,7 +646,7 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) P_MV1[1]= my; if(safety_clipping) for(i=1; i<10; i++){ - if (s->first_slice_line && block<2 && i>1 && i<9) + if (s->c.first_slice_line && block < 2 && i > 1 && i < 9) continue; if (i>4 && i<9) continue; @@ -657,28 +662,22 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) int dxy; const int offset= ((block&1) + (block>>1)*stride)*8; uint8_t *dest_y = c->scratchpad + offset; - if(s->quarter_sample){ + if (s->c.quarter_sample) { const uint8_t *ref = c->ref[block][0] + (mx4>>2) + (my4>>2)*stride; dxy = ((my4 & 3) << 2) | (mx4 & 3); - if(s->no_rounding) - s->qdsp.put_no_rnd_qpel_pixels_tab[1][dxy](dest_y, ref, stride); - else - s->qdsp.put_qpel_pixels_tab[1][dxy](dest_y, ref, stride); + c->qpel_put[1][dxy](dest_y, ref, stride); }else{ const uint8_t *ref = c->ref[block][0] + (mx4>>1) + (my4>>1)*stride; dxy = ((my4 & 1) << 1) | (mx4 & 1); - if(s->no_rounding) - s->hdsp.put_no_rnd_pixels_tab[1][dxy](dest_y , ref , stride, h); - else - s->hdsp.put_pixels_tab [1][dxy](dest_y , ref , stride, h); + c->hpel_put[1][dxy](dest_y, ref, stride, h); } dmin_sum+= (mv_penalty[mx4-pred_x4] + mv_penalty[my4-pred_y4])*c->mb_penalty_factor; }else dmin_sum+= dmin4; - if(s->quarter_sample){ + if (s->c.quarter_sample) { mx4_sum+= mx4/2; my4_sum+= my4/2; }else{ @@ -686,8 +685,8 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) my4_sum+= my4; } - s->cur_pic.motion_val[0][s->block_index[block]][0] = mx4; - s->cur_pic.motion_val[0][s->block_index[block]][1] = my4; + s->c.cur_pic.motion_val[0][s->c.block_index[block]][0] = mx4; + s->c.cur_pic.motion_val[0][s->c.block_index[block]][1] = my4; if(mx4 != mx || my4 != my) same=0; } @@ -698,7 +697,7 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) if (c->me_sub_cmp[0] != c->mb_cmp[0]) { dmin_sum += c->mb_cmp[0](s, s->new_pic->data[0] + - s->mb_x * 16 + s->mb_y * 16 * stride, + s->c.mb_x * 16 + s->c.mb_y * 16 * stride, c->scratchpad, stride, 16); } @@ -711,18 +710,13 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) my= ff_h263_round_chroma(my4_sum); dxy = ((my & 1) << 1) | (mx & 1); - offset= (s->mb_x*8 + (mx>>1)) + (s->mb_y*8 + (my>>1))*s->uvlinesize; + offset = (s->c.mb_x*8 + (mx>>1)) + (s->c.mb_y*8 + (my>>1))*s->c.uvlinesize; - if(s->no_rounding){ - s->hdsp.put_no_rnd_pixels_tab[1][dxy](c->scratchpad , s->last_pic.data[1] + offset, s->uvlinesize, 8); - s->hdsp.put_no_rnd_pixels_tab[1][dxy](c->scratchpad + 8, s->last_pic.data[2] + offset, s->uvlinesize, 8); - }else{ - s->hdsp.put_pixels_tab [1][dxy](c->scratchpad , s->last_pic.data[1] + offset, s->uvlinesize, 8); - s->hdsp.put_pixels_tab [1][dxy](c->scratchpad + 8, s->last_pic.data[2] + offset, s->uvlinesize, 8); - } + c->hpel_put[1][dxy](c->scratchpad , s->c.last_pic.data[1] + offset, s->c.uvlinesize, 8); + c->hpel_put[1][dxy](c->scratchpad + 8, s->c.last_pic.data[2] + offset, s->c.uvlinesize, 8); - dmin_sum += c->mb_cmp[1](s, s->new_pic->data[1] + s->mb_x * 8 + s->mb_y * 8 * s->uvlinesize, c->scratchpad, s->uvlinesize, 8); - dmin_sum += c->mb_cmp[1](s, s->new_pic->data[2] + s->mb_x * 8 + s->mb_y * 8 * s->uvlinesize, c->scratchpad + 8, s->uvlinesize, 8); + dmin_sum += c->mb_cmp[1](s, s->new_pic->data[1] + s->c.mb_x * 8 + s->c.mb_y * 8 * s->c.uvlinesize, c->scratchpad, s->c.uvlinesize, 8); + dmin_sum += c->mb_cmp[1](s, s->new_pic->data[2] + s->c.mb_x * 8 + s->c.mb_y * 8 * s->c.uvlinesize, c->scratchpad + 8, s->c.uvlinesize, 8); } c->pred_x= mx; @@ -730,7 +724,7 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) switch(c->avctx->mb_cmp&0xFF){ /*case FF_CMP_SSE: - return dmin_sum+ 32*s->qscale*s->qscale;*/ + return dmin_sum+ 32*s->c.qscale*s->c.qscale;*/ case FF_CMP_RD: return dmin_sum; default: @@ -738,33 +732,34 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) } } -static inline void init_interlaced_ref(MpegEncContext *s, int ref_index){ - MotionEstContext * const c= &s->me; +static inline void init_interlaced_ref(MPVEncContext *const s, int ref_index) +{ + MotionEstContext *const c = &s->me; - c->ref[1+ref_index][0] = c->ref[0+ref_index][0] + s->linesize; - c->src[1][0] = c->src[0][0] + s->linesize; + c->ref[1+ref_index][0] = c->ref[0+ref_index][0] + s->c.linesize; + c->src[1][0] = c->src[0][0] + s->c.linesize; if(c->flags & FLAG_CHROMA){ - c->ref[1+ref_index][1] = c->ref[0+ref_index][1] + s->uvlinesize; - c->ref[1+ref_index][2] = c->ref[0+ref_index][2] + s->uvlinesize; - c->src[1][1] = c->src[0][1] + s->uvlinesize; - c->src[1][2] = c->src[0][2] + s->uvlinesize; + c->ref[1+ref_index][1] = c->ref[0+ref_index][1] + s->c.uvlinesize; + c->ref[1+ref_index][2] = c->ref[0+ref_index][2] + s->c.uvlinesize; + c->src[1][1] = c->src[0][1] + s->c.uvlinesize; + c->src[1][2] = c->src[0][2] + s->c.uvlinesize; } } -static int interlaced_search(MpegEncContext *s, int ref_index, +static int interlaced_search(MPVEncContext *const s, int ref_index, int16_t (*mv_tables[2][2])[2], uint8_t *field_select_tables[2], int mx, int my, int user_field_select) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int size=0; const int h=8; int block; int P[10][2]; const uint8_t * const mv_penalty = c->current_mv_penalty; int same=1; - const int stride= 2*s->linesize; + const int stride = 2*s->c.linesize; int dmin_sum= 0; - const int mot_stride= s->mb_stride; - const int xy= s->mb_x + s->mb_y*mot_stride; + const int mot_stride = s->c.mb_stride; + const int xy = s->c.mb_x + s->c.mb_y*mot_stride; c->ymin>>=1; c->ymax>>=1; @@ -795,7 +790,7 @@ static int interlaced_search(MpegEncContext *s, int ref_index, c->pred_x= P_LEFT[0]; c->pred_y= P_LEFT[1]; - if(!s->first_slice_line){ + if (!s->c.first_slice_line) { P_TOP[0] = mv_table[xy - mot_stride][0]; P_TOP[1] = mv_table[xy - mot_stride][1]; P_TOPRIGHT[0] = mv_table[xy - mot_stride + 1][0]; @@ -825,11 +820,7 @@ static int interlaced_search(MpegEncContext *s, int ref_index, const uint8_t *ref = c->ref[field_select+ref_index][0] + (mx_i>>1) + (my_i>>1)*stride; dxy = ((my_i & 1) << 1) | (mx_i & 1); - if(s->no_rounding){ - s->hdsp.put_no_rnd_pixels_tab[size][dxy](c->scratchpad, ref , stride, h); - }else{ - s->hdsp.put_pixels_tab [size][dxy](c->scratchpad, ref , stride, h); - } + c->hpel_put[size][dxy](c->scratchpad, ref, stride, h); dmin = c->mb_cmp[size](s, c->src[block][0], c->scratchpad, stride, h); dmin+= (mv_penalty[mx_i-c->pred_x] + mv_penalty[my_i-c->pred_y] + 1)*c->mb_penalty_factor; }else @@ -865,7 +856,7 @@ static int interlaced_search(MpegEncContext *s, int ref_index, switch(c->avctx->mb_cmp&0xFF){ /*case FF_CMP_SSE: - return dmin_sum+ 32*s->qscale*s->qscale;*/ + return dmin_sum+ 32*s->c.qscale*s->c.qscale;*/ case FF_CMP_RD: return dmin_sum; default: @@ -898,57 +889,57 @@ static inline int get_penalty_factor(int lambda, int lambda2, int type){ } } -void ff_estimate_p_frame_motion(MpegEncContext * s, +void ff_estimate_p_frame_motion(MPVEncContext *const s, int mb_x, int mb_y) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const uint8_t *pix, *ppix; int sum, mx = 0, my = 0, dmin = 0; int varc; ///< the variance of the block (sum of squared (p[y][x]-average)) int vard; ///< sum of squared differences with the estimated motion vector int P[10][2]; - const int shift= 1+s->quarter_sample; + const int shift = 1 + s->c.quarter_sample; int mb_type=0; - init_ref(c, s->new_pic->data, s->last_pic.data, NULL, 16*mb_x, 16*mb_y, 0); + init_ref(c, s->new_pic->data, s->c.last_pic.data, NULL, 16*mb_x, 16*mb_y, 0); - av_assert0(s->quarter_sample==0 || s->quarter_sample==1); - av_assert0(s->linesize == c->stride); - av_assert0(s->uvlinesize == c->uvstride); + av_assert0(s->c.quarter_sample == 0 || s->c.quarter_sample == 1); + av_assert0(s->c.linesize == c->stride); + av_assert0(s->c.uvlinesize == c->uvstride); - c->penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_cmp); - c->sub_penalty_factor= get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp); - c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp); - c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_DMV; + c->penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_cmp); + c->sub_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp); + c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp); + c->current_mv_penalty = c->mv_penalty[s->f_code] + MAX_DMV; get_limits(s, 16*mb_x, 16*mb_y, 0); c->skip=0; /* intra / predictive decision */ pix = c->src[0][0]; - sum = s->mpvencdsp.pix_sum(pix, s->linesize); - varc = s->mpvencdsp.pix_norm1(pix, s->linesize) - + sum = s->mpvencdsp.pix_sum(pix, s->c.linesize); + varc = s->mpvencdsp.pix_norm1(pix, s->c.linesize) - (((unsigned) sum * sum) >> 8) + 500; - s->mb_mean[s->mb_stride * mb_y + mb_x] = (sum+128)>>8; - s->mb_var [s->mb_stride * mb_y + mb_x] = (varc+128)>>8; + s->mb_mean[s->c.mb_stride * mb_y + mb_x] = (sum + 128) >> 8; + s->mb_var [s->c.mb_stride * mb_y + mb_x] = (varc + 128) >> 8; c->mb_var_sum_temp += (varc+128)>>8; - if (s->motion_est != FF_ME_ZERO) { - const int mot_stride = s->b8_stride; - const int mot_xy = s->block_index[0]; + if (c->motion_est != FF_ME_ZERO) { + const int mot_stride = s->c.b8_stride; + const int mot_xy = s->c.block_index[0]; - P_LEFT[0] = s->cur_pic.motion_val[0][mot_xy - 1][0]; - P_LEFT[1] = s->cur_pic.motion_val[0][mot_xy - 1][1]; + P_LEFT[0] = s->c.cur_pic.motion_val[0][mot_xy - 1][0]; + P_LEFT[1] = s->c.cur_pic.motion_val[0][mot_xy - 1][1]; if (P_LEFT[0] > (c->xmax << shift)) P_LEFT[0] = c->xmax << shift; - if (!s->first_slice_line) { - P_TOP[0] = s->cur_pic.motion_val[0][mot_xy - mot_stride ][0]; - P_TOP[1] = s->cur_pic.motion_val[0][mot_xy - mot_stride ][1]; - P_TOPRIGHT[0] = s->cur_pic.motion_val[0][mot_xy - mot_stride + 2][0]; - P_TOPRIGHT[1] = s->cur_pic.motion_val[0][mot_xy - mot_stride + 2][1]; + if (!s->c.first_slice_line) { + P_TOP[0] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride ][0]; + P_TOP[1] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride ][1]; + P_TOPRIGHT[0] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride + 2][0]; + P_TOPRIGHT[1] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride + 2][1]; if (P_TOP[1] > (c->ymax << shift)) P_TOP[1] = c->ymax << shift; if (P_TOPRIGHT[0] < (c->xmin * (1 << shift))) @@ -959,7 +950,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, P_MEDIAN[0] = mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]); P_MEDIAN[1] = mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]); - if (s->out_format == FMT_H263) { + if (s->c.out_format == FMT_H263) { c->pred_x = P_MEDIAN[0]; c->pred_y = P_MEDIAN[1]; } else { /* MPEG-1 at least */ @@ -974,21 +965,21 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, } /* At this point (mx,my) are full-pell and the relative displacement */ - ppix = c->ref[0][0] + (my * s->linesize) + mx; + ppix = c->ref[0][0] + (my * s->c.linesize) + mx; - vard = c->sse(NULL, pix, ppix, s->linesize, 16); + vard = c->sse(NULL, pix, ppix, s->c.linesize, 16); - s->mc_mb_var[s->mb_stride * mb_y + mb_x] = (vard+128)>>8; + s->mc_mb_var[s->c.mb_stride * mb_y + mb_x] = (vard+128)>>8; c->mc_mb_var_sum_temp += (vard+128)>>8; if (c->avctx->mb_decision > FF_MB_DECISION_SIMPLE) { - int p_score= FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); - int i_score= varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; + int p_score = FFMIN(vard, varc - 500 + (s->lambda2 >> FF_LAMBDA_SHIFT)*100); + int i_score = varc - 500 + (s->lambda2 >> FF_LAMBDA_SHIFT)*20; c->scene_change_score+= ff_sqrt(p_score) - ff_sqrt(i_score); if (vard*2 + 200*256 > varc && !s->intra_penalty) mb_type|= CANDIDATE_MB_TYPE_INTRA; - if (varc*2 + 200*256 > vard || s->qscale > 24){ + if (varc*2 + 200*256 > vard || s->c.qscale > 24){ // if (varc*2 + 200*256 + 50*(s->lambda2>>FF_LAMBDA_SHIFT) > vard){ mb_type|= CANDIDATE_MB_TYPE_INTER; c->sub_motion_search(s, &mx, &my, dmin, 0, 0, 0, 16); @@ -999,7 +990,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, mx *= 1 << shift; my *= 1 << shift; } - if ((s->avctx->flags & AV_CODEC_FLAG_4MV) + if ((c->avctx->flags & AV_CODEC_FLAG_4MV) && !c->skip && varc>50<<8 && vard>10<<8){ if(h263_mv4_search(s, mx, my, shift) < INT_MAX) mb_type|=CANDIDATE_MB_TYPE_INTER4V; @@ -1007,9 +998,9 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, set_p_mv_tables(s, mx, my, 0); }else set_p_mv_tables(s, mx, my, 1); - if ((s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) + if ((c->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) && !c->skip){ //FIXME varc/d checks - if(interlaced_search(s, 0, s->p_field_mv_table, s->p_field_select_table, mx, my, 0) < INT_MAX) + if(interlaced_search(s, 0, s->c.p_field_mv_table, s->p_field_select_table, mx, my, 0) < INT_MAX) mb_type |= CANDIDATE_MB_TYPE_INTER_I; } }else{ @@ -1020,7 +1011,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, if(c->avctx->me_sub_cmp != c->avctx->mb_cmp && !c->skip) dmin= get_mb_score(s, mx, my, 0, 0, 0, 16, 1); - if ((s->avctx->flags & AV_CODEC_FLAG_4MV) + if ((c->avctx->flags & AV_CODEC_FLAG_4MV) && !c->skip && varc>50<<8 && vard>10<<8){ int dmin4= h263_mv4_search(s, mx, my, shift); if(dmin4 < dmin){ @@ -1028,9 +1019,9 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, dmin=dmin4; } } - if ((s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) + if ((c->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) && !c->skip){ //FIXME varc/d checks - int dmin_i= interlaced_search(s, 0, s->p_field_mv_table, s->p_field_select_table, mx, my, 0); + int dmin_i= interlaced_search(s, 0, s->c.p_field_mv_table, s->p_field_select_table, mx, my, 0); if(dmin_i < dmin){ mb_type = CANDIDATE_MB_TYPE_INTER_I; dmin= dmin_i; @@ -1047,66 +1038,64 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, mean*= 0x01010101; for(i=0; i<16; i++){ - *(uint32_t*)(&c->scratchpad[i*s->linesize+ 0]) = mean; - *(uint32_t*)(&c->scratchpad[i*s->linesize+ 4]) = mean; - *(uint32_t*)(&c->scratchpad[i*s->linesize+ 8]) = mean; - *(uint32_t*)(&c->scratchpad[i*s->linesize+12]) = mean; + *(uint32_t*)(&c->scratchpad[i*s->c.linesize+ 0]) = mean; + *(uint32_t*)(&c->scratchpad[i*s->c.linesize+ 4]) = mean; + *(uint32_t*)(&c->scratchpad[i*s->c.linesize+ 8]) = mean; + *(uint32_t*)(&c->scratchpad[i*s->c.linesize+12]) = mean; } - intra_score= c->mb_cmp[0](s, c->scratchpad, pix, s->linesize, 16); + intra_score= c->mb_cmp[0](s, c->scratchpad, pix, s->c.linesize, 16); } intra_score += c->mb_penalty_factor*16 + s->intra_penalty; if(intra_score < dmin){ mb_type= CANDIDATE_MB_TYPE_INTRA; - s->cur_pic.mb_type[mb_y*s->mb_stride + mb_x] = CANDIDATE_MB_TYPE_INTRA; //FIXME cleanup + s->c.cur_pic.mb_type[mb_y*s->c.mb_stride + mb_x] = CANDIDATE_MB_TYPE_INTRA; //FIXME cleanup }else - s->cur_pic.mb_type[mb_y*s->mb_stride + mb_x] = 0; + s->c.cur_pic.mb_type[mb_y*s->c.mb_stride + mb_x] = 0; { - int p_score= FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); - int i_score= varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; + int p_score = FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); + int i_score = varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; c->scene_change_score+= ff_sqrt(p_score) - ff_sqrt(i_score); } } - s->mb_type[mb_y*s->mb_stride + mb_x]= mb_type; + s->mb_type[mb_y*s->c.mb_stride + mb_x] = mb_type; } -int ff_pre_estimate_p_frame_motion(MpegEncContext * s, +int ff_pre_estimate_p_frame_motion(MPVEncContext *const s, int mb_x, int mb_y) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int mx, my, dmin; int P[10][2]; - const int shift= 1+s->quarter_sample; - const int xy= mb_x + mb_y*s->mb_stride; - init_ref(c, s->new_pic->data, s->last_pic.data, NULL, 16*mb_x, 16*mb_y, 0); + const int shift = 1 + s->c.quarter_sample; + const int xy = mb_x + mb_y*s->c.mb_stride; + init_ref(c, s->new_pic->data, s->c.last_pic.data, NULL, 16*mb_x, 16*mb_y, 0); - av_assert0(s->quarter_sample==0 || s->quarter_sample==1); + av_assert0(s->c.quarter_sample == 0 || s->c.quarter_sample == 1); - c->pre_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_pre_cmp); - c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_DMV; + c->pre_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_pre_cmp); + c->current_mv_penalty = c->mv_penalty[s->f_code] + MAX_DMV; get_limits(s, 16*mb_x, 16*mb_y, 0); c->skip=0; - P_LEFT[0] = s->p_mv_table[xy + 1][0]; + P_LEFT[0] = FFMAX(s->p_mv_table[xy + 1][0], c->xmin * (1 << shift)); P_LEFT[1] = s->p_mv_table[xy + 1][1]; - if(P_LEFT[0] < (c->xmin<xmin<first_slice_line) { + if (s->c.first_slice_line) { c->pred_x= P_LEFT[0]; c->pred_y= P_LEFT[1]; P_TOP[0]= P_TOPRIGHT[0]= P_MEDIAN[0]= P_TOP[1]= P_TOPRIGHT[1]= P_MEDIAN[1]= 0; //FIXME } else { - P_TOP[0] = s->p_mv_table[xy + s->mb_stride ][0]; - P_TOP[1] = s->p_mv_table[xy + s->mb_stride ][1]; - P_TOPRIGHT[0] = s->p_mv_table[xy + s->mb_stride - 1][0]; - P_TOPRIGHT[1] = s->p_mv_table[xy + s->mb_stride - 1][1]; + P_TOP[0] = s->p_mv_table[xy + s->c.mb_stride ][0]; + P_TOP[1] = s->p_mv_table[xy + s->c.mb_stride ][1]; + P_TOPRIGHT[0] = s->p_mv_table[xy + s->c.mb_stride - 1][0]; + P_TOPRIGHT[1] = s->p_mv_table[xy + s->c.mb_stride - 1][1]; if(P_TOP[1] < (c->ymin<ymin< (c->xmax<xmax<ymin<ymin<me; + MotionEstContext *const c = &s->me; int mx = 0, my = 0, dmin = 0; int P[10][2]; - const int shift= 1+s->quarter_sample; - const int mot_stride = s->mb_stride; + const int shift= 1+s->c.quarter_sample; + const int mot_stride = s->c.mb_stride; const int mot_xy = mb_y*mot_stride + mb_x; const uint8_t * const mv_penalty = c->mv_penalty[f_code] + MAX_DMV; int mv_scale; @@ -1142,14 +1131,14 @@ static int estimate_motion_b(MpegEncContext *s, int mb_x, int mb_y, get_limits(s, 16*mb_x, 16*mb_y, 1); - if (s->motion_est != FF_ME_ZERO) { + if (c->motion_est != FF_ME_ZERO) { P_LEFT[0] = mv_table[mot_xy - 1][0]; P_LEFT[1] = mv_table[mot_xy - 1][1]; if (P_LEFT[0] > (c->xmax << shift)) P_LEFT[0] = (c->xmax << shift); /* special case for first line */ - if (!s->first_slice_line) { + if (!s->c.first_slice_line) { P_TOP[0] = mv_table[mot_xy - mot_stride ][0]; P_TOP[1] = mv_table[mot_xy - mot_stride ][1]; P_TOPRIGHT[0] = mv_table[mot_xy - mot_stride + 1][0]; @@ -1165,9 +1154,9 @@ static int estimate_motion_b(MpegEncContext *s, int mb_x, int mb_y, c->pred_y = P_LEFT[1]; if(mv_table == s->b_forw_mv_table){ - mv_scale= (s->pb_time<<16) / (s->pp_time<c.pb_time<<16) / (s->c.pp_time<pb_time - s->pp_time) * (1 << 16)) / (s->pp_time<c.pb_time - s->c.pp_time) * (1 << 16)) / (s->c.pp_time<p_mv_table, mv_scale, 0, 16); @@ -1178,14 +1167,14 @@ static int estimate_motion_b(MpegEncContext *s, int mb_x, int mb_y, if(c->avctx->me_sub_cmp != c->avctx->mb_cmp && !c->skip) dmin= get_mb_score(s, mx, my, 0, ref_index, 0, 16, 1); -// s->mb_type[mb_y*s->mb_width + mb_x]= mb_type; +// s->mb_type[mb_y*s->c.mb_width + mb_x]= mb_type; mv_table[mot_xy][0]= mx; mv_table[mot_xy][1]= my; return dmin; } -static inline int check_bidir_mv(MpegEncContext * s, +static inline int check_bidir_mv(MPVEncContext *const s, int motion_fx, int motion_fy, int motion_bx, int motion_by, int pred_fx, int pred_fy, @@ -1195,7 +1184,7 @@ static inline int check_bidir_mv(MpegEncContext * s, //FIXME optimize? //FIXME better f_code prediction (max mv & distance) //FIXME pointers - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const uint8_t * const mv_penalty_f = c->mv_penalty[s->f_code] + MAX_DMV; // f_code of the prev frame const uint8_t * const mv_penalty_b = c->mv_penalty[s->b_code] + MAX_DMV; // f_code of the prev frame int stride= c->stride; @@ -1208,34 +1197,34 @@ static inline int check_bidir_mv(MpegEncContext * s, const uint8_t *const *ref_data = c->ref[0]; const uint8_t *const *ref2_data = c->ref[2]; - if(s->quarter_sample){ + if(s->c.quarter_sample){ dxy = ((motion_fy & 3) << 2) | (motion_fx & 3); src_x = motion_fx >> 2; src_y = motion_fy >> 2; ptr = ref_data[0] + (src_y * stride) + src_x; - s->qdsp.put_qpel_pixels_tab[0][dxy](dest_y, ptr, stride); + s->c.qdsp.put_qpel_pixels_tab[0][dxy](dest_y, ptr, stride); dxy = ((motion_by & 3) << 2) | (motion_bx & 3); src_x = motion_bx >> 2; src_y = motion_by >> 2; ptr = ref2_data[0] + (src_y * stride) + src_x; - s->qdsp.avg_qpel_pixels_tab[size][dxy](dest_y, ptr, stride); + s->c.qdsp.avg_qpel_pixels_tab[size][dxy](dest_y, ptr, stride); }else{ dxy = ((motion_fy & 1) << 1) | (motion_fx & 1); src_x = motion_fx >> 1; src_y = motion_fy >> 1; ptr = ref_data[0] + (src_y * stride) + src_x; - s->hdsp.put_pixels_tab[size][dxy](dest_y , ptr , stride, h); + s->c.hdsp.put_pixels_tab[size][dxy](dest_y , ptr , stride, h); dxy = ((motion_by & 1) << 1) | (motion_bx & 1); src_x = motion_bx >> 1; src_y = motion_by >> 1; ptr = ref2_data[0] + (src_y * stride) + src_x; - s->hdsp.avg_pixels_tab[size][dxy](dest_y , ptr , stride, h); + s->c.hdsp.avg_pixels_tab[size][dxy](dest_y , ptr , stride, h); } fbmin = (mv_penalty_f[motion_fx-pred_fx] + mv_penalty_f[motion_fy-pred_fy])*c->mb_penalty_factor @@ -1250,10 +1239,10 @@ static inline int check_bidir_mv(MpegEncContext * s, } /* refine the bidir vectors in hq mode and return the score in both lq & hq mode*/ -static inline int bidir_refine(MpegEncContext * s, int mb_x, int mb_y) +static inline int bidir_refine(MPVEncContext *const s, int mb_x, int mb_y) { - MotionEstContext * const c= &s->me; - const int mot_stride = s->mb_stride; + MotionEstContext *const c = &s->me; + const int mot_stride = s->c.mb_stride; const int xy = mb_y *mot_stride + mb_x; int fbmin; int pred_fx= s->b_bidir_forw_mv_table[xy-1][0]; @@ -1284,10 +1273,10 @@ static inline int bidir_refine(MpegEncContext * s, int mb_x, int mb_y) pred_bx, pred_by, 0, 16); - if(s->avctx->bidir_refine){ + if (c->avctx->bidir_refine) { int end; static const uint8_t limittab[5]={0,8,32,64,80}; - const int limit= limittab[s->avctx->bidir_refine]; + const int limit = limittab[c->avctx->bidir_refine]; static const int8_t vect[][4]={ { 0, 0, 0, 1}, { 0, 0, 0,-1}, { 0, 0, 1, 0}, { 0, 0,-1, 0}, { 0, 1, 0, 0}, { 0,-1, 0, 0}, { 1, 0, 0, 0}, {-1, 0, 0, 0}, @@ -1397,16 +1386,16 @@ CHECK_BIDIR(-(a),-(b),-(c),-(d)) return fbmin; } -static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) +static inline int direct_search(MPVEncContext *const s, int mb_x, int mb_y) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int P[10][2]; - const int mot_stride = s->mb_stride; + const int mot_stride = s->c.mb_stride; const int mot_xy = mb_y*mot_stride + mb_x; - const int shift= 1+s->quarter_sample; + const int shift= 1+s->c.quarter_sample; int dmin, i; - const int time_pp= s->pp_time; - const int time_pb= s->pb_time; + const int time_pp= s->c.pp_time; + const int time_pb= s->c.pb_time; int mx, my, xmin, xmax, ymin, ymax; int16_t (*mv_table)[2]= s->b_direct_mv_table; @@ -1414,18 +1403,18 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) ymin= xmin=(-32)>>shift; ymax= xmax= 31>>shift; - if (IS_8X8(s->next_pic.mb_type[mot_xy])) { - s->mv_type= MV_TYPE_8X8; + if (IS_8X8(s->c.next_pic.mb_type[mot_xy])) { + s->c.mv_type = MV_TYPE_8X8; }else{ - s->mv_type= MV_TYPE_16X16; + s->c.mv_type = MV_TYPE_16X16; } for(i=0; i<4; i++){ - int index= s->block_index[i]; + int index= s->c.block_index[i]; int min, max; - c->co_located_mv[i][0] = s->next_pic.motion_val[0][index][0]; - c->co_located_mv[i][1] = s->next_pic.motion_val[0][index][1]; + c->co_located_mv[i][0] = s->c.next_pic.motion_val[0][index][0]; + c->co_located_mv[i][1] = s->c.next_pic.motion_val[0][index][1]; c->direct_basis_mv[i][0]= c->co_located_mv[i][0]*time_pb/time_pp + ((i& 1)<<(shift+3)); c->direct_basis_mv[i][1]= c->co_located_mv[i][1]*time_pb/time_pp + ((i>>1)<<(shift+3)); // c->direct_basis_mv[1][i][0]= c->co_located_mv[i][0]*(time_pb - time_pp)/time_pp + ((i &1)<<(shift+3); @@ -1435,17 +1424,17 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) min= FFMIN(c->direct_basis_mv[i][0], c->direct_basis_mv[i][0] - c->co_located_mv[i][0])>>shift; max+= 16*mb_x + 1; // +-1 is for the simpler rounding min+= 16*mb_x - 1; - xmax= FFMIN(xmax, s->width - max); + xmax= FFMIN(xmax, s->c.width - max); xmin= FFMAX(xmin, - 16 - min); max= FFMAX(c->direct_basis_mv[i][1], c->direct_basis_mv[i][1] - c->co_located_mv[i][1])>>shift; min= FFMIN(c->direct_basis_mv[i][1], c->direct_basis_mv[i][1] - c->co_located_mv[i][1])>>shift; max+= 16*mb_y + 1; // +-1 is for the simpler rounding min+= 16*mb_y - 1; - ymax= FFMIN(ymax, s->height - max); + ymax= FFMIN(ymax, s->c.height - max); ymin= FFMAX(ymin, - 16 - min); - if(s->mv_type == MV_TYPE_16X16) break; + if(s->c.mv_type == MV_TYPE_16X16) break; } av_assert2(xmax <= 15 && ymax <= 15 && xmin >= -16 && ymin >= -16); @@ -1470,7 +1459,7 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) P_LEFT[1] = av_clip(mv_table[mot_xy - 1][1], ymin * (1 << shift), ymax << shift); /* special case for first line */ - if (!s->first_slice_line) { //FIXME maybe allow this over thread boundary as it is clipped + if (!s->c.first_slice_line) { //FIXME maybe allow this over thread boundary as it is clipped P_TOP[0] = av_clip(mv_table[mot_xy - mot_stride ][0], xmin * (1 << shift), xmax << shift); P_TOP[1] = av_clip(mv_table[mot_xy - mot_stride ][1], ymin * (1 << shift), ymax << shift); P_TOPRIGHT[0] = av_clip(mv_table[mot_xy - mot_stride + 1][0], xmin * (1 << shift), xmax << shift); @@ -1499,27 +1488,27 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) return dmin; } -void ff_estimate_b_frame_motion(MpegEncContext * s, +void ff_estimate_b_frame_motion(MPVEncContext *const s, int mb_x, int mb_y) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int fmin, bmin, dmin, fbmin, bimin, fimin; int type=0; - const int xy = mb_y*s->mb_stride + mb_x; - init_ref(c, s->new_pic->data, s->last_pic.data, - s->next_pic.data, 16 * mb_x, 16 * mb_y, 2); + const int xy = mb_y*s->c.mb_stride + mb_x; + init_ref(c, s->new_pic->data, s->c.last_pic.data, + s->c.next_pic.data, 16 * mb_x, 16 * mb_y, 2); get_limits(s, 16*mb_x, 16*mb_y, 1); c->skip=0; - if (s->codec_id == AV_CODEC_ID_MPEG4 && s->next_pic.mbskip_table[xy]) { + if (s->c.codec_id == AV_CODEC_ID_MPEG4 && s->c.next_pic.mbskip_table[xy]) { int score= direct_search(s, mb_x, mb_y); //FIXME just check 0,0 score= ((unsigned)(score*score + 128*256))>>16; c->mc_mb_var_sum_temp += score; - s->mc_mb_var[mb_y*s->mb_stride + mb_x] = score; //FIXME use SSE - s->mb_type[mb_y*s->mb_stride + mb_x]= CANDIDATE_MB_TYPE_DIRECT0; + s->mc_mb_var[mb_y*s->c.mb_stride + mb_x] = score; //FIXME use SSE + s->mb_type[mb_y*s->c.mb_stride + mb_x]= CANDIDATE_MB_TYPE_DIRECT0; return; } @@ -1528,7 +1517,7 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, c->sub_penalty_factor= get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp); c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp); - if (s->codec_id == AV_CODEC_ID_MPEG4) + if (s->c.codec_id == AV_CODEC_ID_MPEG4) dmin= direct_search(s, mb_x, mb_y); else dmin= INT_MAX; @@ -1541,20 +1530,20 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, c->skip=0; bmin = estimate_motion_b(s, mb_x, mb_y, s->b_back_mv_table, 2, s->b_code) + 2 * c->mb_penalty_factor; - ff_dlog(s, " %d %d ", s->b_forw_mv_table[xy][0], s->b_forw_mv_table[xy][1]); + ff_dlog(c->avctx, " %d %d ", s->b_forw_mv_table[xy][0], s->b_forw_mv_table[xy][1]); c->skip=0; fbmin= bidir_refine(s, mb_x, mb_y) + c->mb_penalty_factor; - ff_dlog(s, "%d %d %d %d\n", dmin, fmin, bmin, fbmin); + ff_dlog(c->avctx, "%d %d %d %d\n", dmin, fmin, bmin, fbmin); - if (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { + if (c->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { //FIXME mb type penalty c->skip=0; - c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_DMV; + c->current_mv_penalty = c->mv_penalty[s->f_code] + MAX_DMV; fimin= interlaced_search(s, 0, s->b_field_mv_table[0], s->b_field_select_table[0], s->b_forw_mv_table[xy][0], s->b_forw_mv_table[xy][1], 0); - c->current_mv_penalty= c->mv_penalty[s->b_code] + MAX_DMV; + c->current_mv_penalty = c->mv_penalty[s->b_code] + MAX_DMV; bimin= interlaced_search(s, 2, s->b_field_mv_table[1], s->b_field_select_table[1], s->b_back_mv_table[xy][0], s->b_back_mv_table[xy][1], 0); @@ -1588,7 +1577,7 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, score= ((unsigned)(score*score + 128*256))>>16; c->mc_mb_var_sum_temp += score; - s->mc_mb_var[mb_y*s->mb_stride + mb_x] = score; //FIXME use SSE + s->mc_mb_var[mb_y*s->c.mb_stride + mb_x] = score; //FIXME use SSE } if(c->avctx->mb_decision > FF_MB_DECISION_SIMPLE){ @@ -1602,40 +1591,43 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, } //FIXME something smarter if(dmin>256*256*16) type&= ~CANDIDATE_MB_TYPE_DIRECT; //do not try direct mode if it is invalid for this MB - if (s->codec_id == AV_CODEC_ID_MPEG4 && type&CANDIDATE_MB_TYPE_DIRECT && + if (s->c.codec_id == AV_CODEC_ID_MPEG4 && type&CANDIDATE_MB_TYPE_DIRECT && s->mpv_flags & FF_MPV_FLAG_MV0 && *(uint32_t*)s->b_direct_mv_table[xy]) type |= CANDIDATE_MB_TYPE_DIRECT0; } - s->mb_type[mb_y*s->mb_stride + mb_x]= type; + s->mb_type[mb_y*s->c.mb_stride + mb_x]= type; } /* find best f_code for ME which do unlimited searches */ -int ff_get_best_fcode(MpegEncContext * s, const int16_t (*mv_table)[2], int type) +int ff_get_best_fcode(MPVMainEncContext *const m, const int16_t (*mv_table)[2], int type) { - if (s->motion_est != FF_ME_ZERO) { + MPVEncContext *const s = &m->s; + MotionEstContext *const c = &s->me; + + if (c->motion_est != FF_ME_ZERO) { int score[8]; - int i, y, range= s->avctx->me_range ? s->avctx->me_range : (INT_MAX/2); - const uint8_t * fcode_tab = s->fcode_tab; + int i, range = c->avctx->me_range ? c->avctx->me_range : (INT_MAX/2); + const uint8_t * fcode_tab = m->fcode_tab; int best_fcode=-1; int best_score=-10000000; - if (s->msmpeg4_version != MSMP4_UNUSED) + if (s->c.msmpeg4_version != MSMP4_UNUSED) range= FFMIN(range, 16); - else if(s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL) + else if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO && + c->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL) range= FFMIN(range, 256); - for(i=0; i<8; i++) score[i]= s->mb_num*(8-i); + for(i=0; i<8; i++) score[i]= s->c.mb_num*(8-i); - for(y=0; ymb_height; y++){ + for (int y = 0; y < s->c.mb_height; y++) { int x; - int xy= y*s->mb_stride; - for(x=0; xmb_width; x++, xy++){ + int xy= y*s->c.mb_stride; + for(x=0; xc.mb_width; x++, xy++){ if(s->mb_type[xy] & type){ int mx= mv_table[xy][0]; int my= mv_table[xy][1]; - int fcode= FFMAX(fcode_tab[mx + MAX_MV], - fcode_tab[my + MAX_MV]); + int fcode = FFMAX(fcode_tab[mx], fcode_tab[my]); int j; if (mx >= range || mx < -range || @@ -1643,7 +1635,7 @@ int ff_get_best_fcode(MpegEncContext * s, const int16_t (*mv_table)[2], int type continue; for(j=0; jpict_type == AV_PICTURE_TYPE_B || + if (s->c.pict_type == AV_PICTURE_TYPE_B || s->mc_mb_var[xy] < s->mb_var[xy]) score[j]-= 170; } @@ -1664,42 +1656,42 @@ int ff_get_best_fcode(MpegEncContext * s, const int16_t (*mv_table)[2], int type } } -void ff_fix_long_p_mvs(MpegEncContext * s, int type) +void ff_fix_long_p_mvs(MPVEncContext *const s, int type) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int f_code= s->f_code; int y, range; - av_assert0(s->pict_type==AV_PICTURE_TYPE_P); + av_assert0(s->c.pict_type == AV_PICTURE_TYPE_P); - range = (((s->out_format == FMT_MPEG1 || s->msmpeg4_version != MSMP4_UNUSED) ? 8 : 16) << f_code); + range = (((s->c.out_format == FMT_MPEG1 || s->c.msmpeg4_version != MSMP4_UNUSED) ? 8 : 16) << f_code); - av_assert0(range <= 16 || s->msmpeg4_version == MSMP4_UNUSED); - av_assert0(range <=256 || !(s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL)); + av_assert0(range <= 16 || s->c.msmpeg4_version == MSMP4_UNUSED); + av_assert0(range <=256 || !(s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO && c->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL)); if(c->avctx->me_range && range > c->avctx->me_range) range= c->avctx->me_range; - if (s->avctx->flags & AV_CODEC_FLAG_4MV) { - const int wrap= s->b8_stride; + if (c->avctx->flags & AV_CODEC_FLAG_4MV) { + const int wrap= s->c.b8_stride; /* clip / convert to intra 8x8 type MVs */ - for(y=0; ymb_height; y++){ + for(y=0; yc.mb_height; y++){ int xy= y*2*wrap; - int i= y*s->mb_stride; + int i= y*s->c.mb_stride; int x; - for(x=0; xmb_width; x++){ + for(x=0; xc.mb_width; x++){ if(s->mb_type[i]&CANDIDATE_MB_TYPE_INTER4V){ int block; for(block=0; block<4; block++){ int off= (block& 1) + (block>>1)*wrap; - int mx = s->cur_pic.motion_val[0][ xy + off ][0]; - int my = s->cur_pic.motion_val[0][ xy + off ][1]; + int mx = s->c.cur_pic.motion_val[0][ xy + off ][0]; + int my = s->c.cur_pic.motion_val[0][ xy + off ][1]; if( mx >=range || mx <-range || my >=range || my <-range){ s->mb_type[i] &= ~CANDIDATE_MB_TYPE_INTER4V; s->mb_type[i] |= type; - s->cur_pic.mb_type[i] = type; + s->c.cur_pic.mb_type[i] = type; } } } @@ -1713,14 +1705,14 @@ void ff_fix_long_p_mvs(MpegEncContext * s, int type) /** * @param truncate 1 for truncation, 0 for using intra */ -void ff_fix_long_mvs(MpegEncContext * s, uint8_t *field_select_table, int field_select, +void ff_fix_long_mvs(MPVEncContext *const s, uint8_t *field_select_table, int field_select, int16_t (*mv_table)[2], int f_code, int type, int truncate) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int y, h_range, v_range; // RAL: 8 in MPEG-1, 16 in MPEG-4 - int range = (((s->out_format == FMT_MPEG1 || s->msmpeg4_version != MSMP4_UNUSED) ? 8 : 16) << f_code); + int range = (((s->c.out_format == FMT_MPEG1 || s->c.msmpeg4_version != MSMP4_UNUSED) ? 8 : 16) << f_code); if(c->avctx->me_range && range > c->avctx->me_range) range= c->avctx->me_range; @@ -1728,10 +1720,10 @@ void ff_fix_long_mvs(MpegEncContext * s, uint8_t *field_select_table, int field_ v_range= field_select_table ? range>>1 : range; /* clip / convert to intra 16x16 type MVs */ - for(y=0; ymb_height; y++){ + for(y=0; yc.mb_height; y++){ int x; - int xy= y*s->mb_stride; - for(x=0; xmb_width; x++){ + int xy= y*s->c.mb_stride; + for(x=0; xc.mb_width; x++){ if (s->mb_type[xy] & type){ // RAL: "type" test added... if (!field_select_table || field_select_table[xy] == field_select) { if( mv_table[xy][0] >=h_range || mv_table[xy][0] <-h_range diff --git a/libavcodec/motion_est.h b/libavcodec/motion_est.h index 12f7cd43a..7e57a3a79 100644 --- a/libavcodec/motion_est.h +++ b/libavcodec/motion_est.h @@ -28,7 +28,8 @@ #include "me_cmp.h" #include "qpeldsp.h" -struct MpegEncContext; +typedef struct MPVEncContext MPVEncContext; +typedef struct MPVMainEncContext MPVMainEncContext; #if ARCH_IA64 // Limit static arrays to avoid gcc failing "short data segment overflowed" #define MAX_MV 1024 @@ -47,14 +48,13 @@ struct MpegEncContext; */ typedef struct MotionEstContext { AVCodecContext *avctx; + int motion_est; ///< ME algorithm int skip; ///< set if ME is skipped for the current MB int co_located_mv[4][2]; ///< mv from last P-frame for direct mode ME int direct_basis_mv[4][2]; uint8_t *scratchpad; /**< data area for the ME algo, so that * the ME does not need to malloc/free. */ uint8_t *temp; - uint32_t *map; ///< map to avoid duplicate evaluations - uint32_t *score_map; ///< map to store the scores unsigned map_generation; int pre_penalty_factor; int penalty_factor; /**< an estimate of the bits required to @@ -69,6 +69,7 @@ typedef struct MotionEstContext { int mb_flags; int pre_pass; ///< = 1 for the pre pass int dia_size; + int unrestricted_mv; ///< mv can point outside of the coded picture int xmin; int xmax; int ymin; @@ -98,21 +99,14 @@ typedef struct MotionEstContext { qpel_mc_func(*qpel_avg)[16]; const uint8_t (*mv_penalty)[MAX_DMV * 2 + 1]; ///< bit amount needed to encode a MV const uint8_t *current_mv_penalty; - int (*sub_motion_search)(struct MpegEncContext *s, + int (*sub_motion_search)(MPVEncContext *s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h); -} MotionEstContext; -static inline int ff_h263_round_chroma(int x) -{ - //FIXME static or not? - static const uint8_t h263_chroma_roundtab[16] = { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, - }; - return h263_chroma_roundtab[x & 0xf] + (x >> 3); -} + uint32_t map[ME_MAP_SIZE]; ///< map to avoid duplicate evaluations + uint32_t score_map[ME_MAP_SIZE];///< map to store the scores +} MotionEstContext; /** * Performs one-time initialization of the MotionEstContext. @@ -120,27 +114,27 @@ static inline int ff_h263_round_chroma(int x) int ff_me_init(MotionEstContext *c, struct AVCodecContext *avctx, const struct MECmpContext *mecc, int mpvenc); -void ff_me_init_pic(struct MpegEncContext *s); +void ff_me_init_pic(MPVEncContext *s); -void ff_estimate_p_frame_motion(struct MpegEncContext *s, int mb_x, int mb_y); -void ff_estimate_b_frame_motion(struct MpegEncContext *s, int mb_x, int mb_y); +void ff_estimate_p_frame_motion(MPVEncContext *s, int mb_x, int mb_y); +void ff_estimate_b_frame_motion(MPVEncContext *s, int mb_x, int mb_y); -int ff_pre_estimate_p_frame_motion(struct MpegEncContext *s, +int ff_pre_estimate_p_frame_motion(MPVEncContext *s, int mb_x, int mb_y); -int ff_epzs_motion_search(struct MpegEncContext *s, int *mx_ptr, int *my_ptr, +int ff_epzs_motion_search(MPVEncContext *s, int *mx_ptr, int *my_ptr, int P[10][2], int src_index, int ref_index, const int16_t (*last_mv)[2], int ref_mv_scale, int size, int h); -int ff_get_mb_score(struct MpegEncContext *s, int mx, int my, int src_index, +int ff_get_mb_score(MPVEncContext *s, int mx, int my, int src_index, int ref_index, int size, int h, int add_rate); -int ff_get_best_fcode(struct MpegEncContext *s, +int ff_get_best_fcode(MPVMainEncContext *m, const int16_t (*mv_table)[2], int type); -void ff_fix_long_p_mvs(struct MpegEncContext *s, int type); -void ff_fix_long_mvs(struct MpegEncContext *s, uint8_t *field_select_table, +void ff_fix_long_p_mvs(MPVEncContext *s, int type); +void ff_fix_long_mvs(MPVEncContext *s, uint8_t *field_select_table, int field_select, int16_t (*mv_table)[2], int f_code, int type, int truncate); diff --git a/libavcodec/motion_est_template.c b/libavcodec/motion_est_template.c index b2701aa32..cf481e2c6 100644 --- a/libavcodec/motion_est_template.c +++ b/libavcodec/motion_est_template.c @@ -25,15 +25,15 @@ */ #include "libavutil/qsort.h" -#include "mpegvideo.h" +#include "mpegvideoenc.h" //Let us hope gcc will remove the unused vars ...(gcc 3.2.2 seems to do it ...) #define LOAD_COMMON\ - uint32_t av_unused * const score_map= c->score_map;\ - const int av_unused xmin= c->xmin;\ - const int av_unused ymin= c->ymin;\ - const int av_unused xmax= c->xmax;\ - const int av_unused ymax= c->ymax;\ + av_unused uint32_t * const score_map= c->score_map;\ + av_unused const int xmin= c->xmin;\ + av_unused const int ymin= c->ymin;\ + av_unused const int xmax= c->xmax;\ + av_unused const int ymax= c->ymax;\ const uint8_t *mv_penalty = c->current_mv_penalty; \ const int pred_x= c->pred_x;\ const int pred_y= c->pred_y;\ @@ -47,12 +47,12 @@ COPY3_IF_LT(dmin, d, bx, hx, by, hy)\ } -static int hpel_motion_search(MpegEncContext * s, +static int hpel_motion_search(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int mx = *mx_ptr; const int my = *my_ptr; const int penalty_factor= c->sub_penalty_factor; @@ -152,7 +152,7 @@ static int hpel_motion_search(MpegEncContext * s, return dmin; } -static int no_sub_motion_search(MpegEncContext * s, +static int no_sub_motion_search(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h) @@ -162,11 +162,11 @@ static int no_sub_motion_search(MpegEncContext * s, return dmin; } -static inline int get_mb_score(MpegEncContext *s, int mx, int my, +static inline int get_mb_score(MPVEncContext *const s, int mx, int my, int src_index, int ref_index, int size, int h, int add_rate) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int penalty_factor= c->mb_penalty_factor; const int flags= c->mb_flags; const int qpel= flags & FLAG_QPEL; @@ -189,7 +189,7 @@ static inline int get_mb_score(MpegEncContext *s, int mx, int my, return d; } -int ff_get_mb_score(MpegEncContext *s, int mx, int my, int src_index, +int ff_get_mb_score(MPVEncContext *const s, int mx, int my, int src_index, int ref_index, int size, int h, int add_rate) { return get_mb_score(s, mx, my, src_index, ref_index, size, h, add_rate); @@ -204,12 +204,12 @@ int ff_get_mb_score(MpegEncContext *s, int mx, int my, int src_index, COPY3_IF_LT(dmin, d, bx, hx, by, hy)\ } -static int qpel_motion_search(MpegEncContext * s, +static int qpel_motion_search(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int mx = *mx_ptr; const int my = *my_ptr; const int penalty_factor= c->sub_penalty_factor; @@ -403,21 +403,21 @@ static int qpel_motion_search(MpegEncContext * s, } #define check(x,y,S,v)\ -if( (x)<(xmin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmin" #v, xmin, (x), (y), s->mb_x, s->mb_y);\ -if( (x)>(xmax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmax" #v, xmax, (x), (y), s->mb_x, s->mb_y);\ -if( (y)<(ymin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymin" #v, ymin, (x), (y), s->mb_x, s->mb_y);\ -if( (y)>(ymax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymax" #v, ymax, (x), (y), s->mb_x, s->mb_y);\ +if( (x)<(xmin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmin" #v, xmin, (x), (y), s->c.mb_x, s->c.mb_y);\ +if( (x)>(xmax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmax" #v, xmax, (x), (y), s->c.mb_x, s->c.mb_y);\ +if( (y)<(ymin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymin" #v, ymin, (x), (y), s->c.mb_x, s->c.mb_y);\ +if( (y)>(ymax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymax" #v, ymax, (x), (y), s->c.mb_x, s->c.mb_y);\ #define LOAD_COMMON2\ uint32_t *map= c->map;\ const int qpel= flags&FLAG_QPEL;\ const int shift= 1+qpel;\ -static av_always_inline int small_diamond_search(MpegEncContext * s, int *best, int dmin, +static av_always_inline int small_diamond_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; int next_dir=-1; LOAD_COMMON @@ -454,11 +454,11 @@ static av_always_inline int small_diamond_search(MpegEncContext * s, int *best, } } -static int funny_diamond_search(MpegEncContext * s, int *best, int dmin, +static int funny_diamond_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; int dia_size; LOAD_COMMON @@ -496,11 +496,11 @@ static int funny_diamond_search(MpegEncContext * s, int *best, int dmin, return dmin; } -static int hex_search(MpegEncContext * s, int *best, int dmin, +static int hex_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags, int dia_size) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON LOAD_COMMON2 @@ -530,11 +530,11 @@ static int hex_search(MpegEncContext * s, int *best, int dmin, return dmin; } -static int l2s_dia_search(MpegEncContext * s, int *best, int dmin, +static int l2s_dia_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON LOAD_COMMON2 @@ -568,11 +568,11 @@ static int l2s_dia_search(MpegEncContext * s, int *best, int dmin, return dmin; } -static int umh_search(MpegEncContext * s, int *best, int dmin, +static int umh_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON LOAD_COMMON2 @@ -615,11 +615,11 @@ static int umh_search(MpegEncContext * s, int *best, int dmin, return hex_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags, 2); } -static int full_search(MpegEncContext * s, int *best, int dmin, +static int full_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON LOAD_COMMON2 @@ -678,11 +678,11 @@ static int full_search(MpegEncContext * s, int *best, int dmin, } #define MAX_SAB_SIZE ME_MAP_SIZE -static int sab_diamond_search(MpegEncContext * s, int *best, int dmin, +static int sab_diamond_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; Minima minima[MAX_SAB_SIZE]; const int minima_count= FFABS(c->dia_size); @@ -768,11 +768,11 @@ static int sab_diamond_search(MpegEncContext * s, int *best, int dmin, return dmin; } -static int var_diamond_search(MpegEncContext * s, int *best, int dmin, +static int var_diamond_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; int dia_size; LOAD_COMMON @@ -829,10 +829,10 @@ static int var_diamond_search(MpegEncContext * s, int *best, int dmin, return dmin; } -static av_always_inline int diamond_search(MpegEncContext * s, int *best, int dmin, +static av_always_inline int diamond_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags){ - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; if(c->dia_size==-1) return funny_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags); else if(c->dia_size<-1) @@ -857,11 +857,11 @@ static av_always_inline int diamond_search(MpegEncContext * s, int *best, int dm it takes fewer iterations. And it increases the chance that we find the optimal mv. */ -static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int *mx_ptr, int *my_ptr, +static av_always_inline int epzs_motion_search_internal(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int P[10][2], int src_index, int ref_index, const int16_t (*last_mv)[2], int ref_mv_scale, int flags, int size, int h) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int best[2]={0, 0}; /**< x and y coordinates of the best motion vector. i.e. the difference between the position of the block currently being encoded and the position of @@ -871,8 +871,8 @@ static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int corresponding to the mv stored in best[]. */ unsigned map_generation; int penalty_factor; - const int ref_mv_stride= s->mb_stride; //pass as arg FIXME - const int ref_mv_xy = s->mb_x + s->mb_y * ref_mv_stride; // add to last_mv before passing FIXME + const int ref_mv_stride= s->c.mb_stride; //pass as arg FIXME + const int ref_mv_xy = s->c.mb_x + s->c.mb_y * ref_mv_stride; // add to last_mv before passing FIXME me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON @@ -896,17 +896,17 @@ static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int score_map[0]= dmin; //FIXME precalc first term below? - if ((s->pict_type == AV_PICTURE_TYPE_B && !(c->flags & FLAG_DIRECT)) || + if ((s->c.pict_type == AV_PICTURE_TYPE_B && !(c->flags & FLAG_DIRECT)) || s->mpv_flags & FF_MPV_FLAG_MV0) dmin += (mv_penalty[pred_x] + mv_penalty[pred_y])*penalty_factor; /* first line */ - if (s->first_slice_line) { + if (s->c.first_slice_line) { CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift) CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16) }else{ - if(dmin<((h*h*s->avctx->mv0_threshold)>>8) + if (dmin < ((h * h * c->avctx->mv0_threshold) >> 8) && ( P_LEFT[0] |P_LEFT[1] |P_TOP[0] |P_TOP[1] |P_TOPRIGHT[0]|P_TOPRIGHT[1])==0){ @@ -930,13 +930,13 @@ static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int if(c->pre_pass){ CHECK_CLIPPED_MV((last_mv[ref_mv_xy-1][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy-1][1]*ref_mv_scale + (1<<15))>>16) - if(!s->first_slice_line) + if(!s->c.first_slice_line) CHECK_CLIPPED_MV((last_mv[ref_mv_xy-ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy-ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16) }else{ CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16) - if(s->mb_y+1end_mb_y) //FIXME replace at least with last_slice_line + if(s->c.mb_y+1c.end_mb_y) //FIXME replace at least with last_slice_line CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16) } @@ -944,10 +944,10 @@ static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int if(c->avctx->last_predictor_count){ const int count= c->avctx->last_predictor_count; - const int xstart= FFMAX(0, s->mb_x - count); - const int ystart= FFMAX(0, s->mb_y - count); - const int xend= FFMIN(s->mb_width , s->mb_x + count + 1); - const int yend= FFMIN(s->mb_height, s->mb_y + count + 1); + const int xstart= FFMAX(0, s->c.mb_x - count); + const int ystart= FFMAX(0, s->c.mb_y - count); + const int xend= FFMIN(s->c.mb_width , s->c.mb_x + count + 1); + const int yend= FFMIN(s->c.mb_height, s->c.mb_y + count + 1); int mb_y; for(mb_y=ystart; mb_yme; + MotionEstContext *const c = &s->me; //FIXME convert other functions in the same way if faster if(c->flags==0 && h==16 && size==0){ return epzs_motion_search_internal(s, mx_ptr, my_ptr, P, src_index, ref_index, last_mv, ref_mv_scale, 0, 0, 16); @@ -990,19 +990,19 @@ int ff_epzs_motion_search(MpegEncContext *s, int *mx_ptr, int *my_ptr, } } -static int epzs_motion_search2(MpegEncContext * s, +static int epzs_motion_search2(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int P[10][2], int src_index, int ref_index, const int16_t (*last_mv)[2], int ref_mv_scale, const int size) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int best[2]={0, 0}; int d, dmin; unsigned map_generation; const int penalty_factor= c->penalty_factor; const int h=8; - const int ref_mv_stride= s->mb_stride; - const int ref_mv_xy= s->mb_x + s->mb_y *ref_mv_stride; + const int ref_mv_stride= s->c.mb_stride; + const int ref_mv_xy= s->c.mb_x + s->c.mb_y *ref_mv_stride; me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON int flags= c->flags; @@ -1016,7 +1016,7 @@ static int epzs_motion_search2(MpegEncContext * s, dmin = 1000000; /* first line */ - if (s->first_slice_line) { + if (s->c.first_slice_line) { CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift) CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16) @@ -1034,7 +1034,7 @@ static int epzs_motion_search2(MpegEncContext * s, if(dmin>64*4){ CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16) - if(s->mb_y+1end_mb_y) //FIXME replace at least with last_slice_line + if(s->c.mb_y+1c.end_mb_y) //FIXME replace at least with last_slice_line CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16) } diff --git a/libavcodec/motionpixels.c b/libavcodec/motionpixels.c index 287f35f30..e5c3daece 100644 --- a/libavcodec/motionpixels.c +++ b/libavcodec/motionpixels.c @@ -70,7 +70,6 @@ static av_cold int mp_decode_end(AVCodecContext *avctx) static av_cold int mp_decode_init(AVCodecContext *avctx) { - av_unused static AVOnce init_static_once = AV_ONCE_INIT; MotionPixelsContext *mp = avctx->priv_data; int w4 = (avctx->width + 3) & ~3; int h4 = (avctx->height + 3) & ~3; @@ -95,6 +94,7 @@ static av_cold int mp_decode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); #if !CONFIG_HARDCODED_TABLES + static AVOnce init_static_once = AV_ONCE_INIT; ff_thread_once(&init_static_once, motionpixels_tableinit); #endif diff --git a/libavcodec/movtextdec.c b/libavcodec/movtextdec.c index f799252bf..fe04514e1 100644 --- a/libavcodec/movtextdec.c +++ b/libavcodec/movtextdec.c @@ -443,7 +443,7 @@ static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end, return 0; } -static int mov_text_init(AVCodecContext *avctx) { +static av_cold int mov_text_init(AVCodecContext *avctx) { /* * TODO: Handle the default text style. * NB: Most players ignore styles completely, with the result that @@ -561,7 +561,7 @@ static int mov_text_decode_frame(AVCodecContext *avctx, AVSubtitle *sub, return avpkt->size; } -static int mov_text_decode_close(AVCodecContext *avctx) +static av_cold int mov_text_decode_close(AVCodecContext *avctx) { MovTextContext *m = avctx->priv_data; mov_text_cleanup_ftab(m); @@ -569,7 +569,7 @@ static int mov_text_decode_close(AVCodecContext *avctx) return 0; } -static void mov_text_flush(AVCodecContext *avctx) +static av_cold void mov_text_flush(AVCodecContext *avctx) { MovTextContext *m = avctx->priv_data; if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP)) diff --git a/libavcodec/movtextenc.c b/libavcodec/movtextenc.c index fd8c7dc9f..a5f032559 100644 --- a/libavcodec/movtextenc.c +++ b/libavcodec/movtextenc.c @@ -21,6 +21,7 @@ #include #include "avcodec.h" +#include "libavutil/attributes.h" #include "libavutil/opt.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" @@ -162,7 +163,7 @@ static const Box box_types[] = { const static size_t box_count = FF_ARRAY_ELEMS(box_types); -static int mov_text_encode_close(AVCodecContext *avctx) +static av_cold int mov_text_encode_close(AVCodecContext *avctx) { MovTextContext *s = avctx->priv_data; @@ -259,7 +260,7 @@ static int encode_sample_description(AVCodecContext *avctx) // Build font table // We can't build a complete font table since that would require // scanning all dialogs first. But we can at least fill in what - // is avaiable in the ASS header + // is available in the ASS header if (style && ass->styles_count) { // Find unique font names if (style->font_name) { diff --git a/libavcodec/mpc7.c b/libavcodec/mpc7.c index f1ce4075c..b95cec1f0 100644 --- a/libavcodec/mpc7.c +++ b/libavcodec/mpc7.c @@ -25,6 +25,7 @@ * divided into 32 subbands. */ +#include "libavutil/attributes.h" #include "libavutil/channel_layout.h" #include "libavutil/internal.h" #include "libavutil/lfg.h" @@ -296,7 +297,7 @@ static int mpc7_decode_frame(AVCodecContext *avctx, AVFrame *frame, return avpkt->size; } -static void mpc7_decode_flush(AVCodecContext *avctx) +static av_cold void mpc7_decode_flush(AVCodecContext *avctx) { MPCContext *c = avctx->priv_data; @@ -323,6 +324,4 @@ const FFCodec ff_mpc7_decoder = { FF_CODEC_DECODE_CB(mpc7_decode_frame), .flush = mpc7_decode_flush, .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/mpc8.c b/libavcodec/mpc8.c index ae145927e..aad9f9f17 100644 --- a/libavcodec/mpc8.c +++ b/libavcodec/mpc8.c @@ -399,6 +399,4 @@ const FFCodec ff_mpc8_decoder = { FF_CODEC_DECODE_CB(mpc8_decode_frame), .flush = mpc8_decode_flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 444ea83f3..61723f3a2 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -28,11 +28,8 @@ #define UNCHECKED_BITSTREAM_READER 1 #include "libavutil/attributes.h" -#include "libavutil/avassert.h" #include "libavutil/thread.h" -#include "mpegvideo.h" -#include "mpeg12codecs.h" #include "mpeg12data.h" #include "mpeg12dec.h" #include "mpegutils.h" @@ -90,15 +87,13 @@ av_cold void ff_init_2d_vlc_rl(const uint16_t table_vlc[][2], RL_VLC_ELEM rl_vlc const int8_t table_run[], const uint8_t table_level[], int n, unsigned static_size, int flags) { - int i; - VLCElem table[680] = { 0 }; - VLC vlc = { .table = table, .table_allocated = static_size }; - av_assert0(static_size <= FF_ARRAY_ELEMS(table)); - vlc_init(&vlc, TEX_VLC_BITS, n + 2, &table_vlc[0][1], 4, 2, &table_vlc[0][0], 4, 2, VLC_INIT_USE_STATIC | flags); + ff_vlc_init_table_sparse(rl_vlc, static_size, TEX_VLC_BITS, n + 2, + &table_vlc[0][1], 4, 2, &table_vlc[0][0], 4, 2, + NULL, 0, 0, flags); - for (i = 0; i < vlc.table_size; i++) { - int code = vlc.table[i].sym; - int len = vlc.table[i].len; + for (unsigned i = 0; i < static_size; i++) { + int idx = rl_vlc[i].sym; + int len = rl_vlc[i].len; int level, run; if (len == 0) { // illegal code @@ -106,33 +101,25 @@ av_cold void ff_init_2d_vlc_rl(const uint16_t table_vlc[][2], RL_VLC_ELEM rl_vlc level = MAX_LEVEL; } else if (len<0) { //more bits needed run = 0; - level = code; + level = idx; } else { - if (code == n) { //esc + if (idx == n) { //esc run = 65; level = 0; - } else if (code == n + 1) { //eob + } else if (idx == n + 1) { //eob run = 0; level = 127; } else { - run = table_run [code] + 1; - level = table_level[code]; + run = table_run [idx] + 1; + level = table_level[idx]; } } - rl_vlc[i].len = len; + rl_vlc[i].len8 = len; rl_vlc[i].level = level; rl_vlc[i].run = run; } } -void ff_mpeg1_clean_buffers(MpegEncContext *s) -{ - s->last_dc[0] = 1 << (7 + s->intra_dc_precision); - s->last_dc[1] = s->last_dc[0]; - s->last_dc[2] = s->last_dc[0]; - memset(s->last_mv, 0, sizeof(s->last_mv)); -} - /******************************************/ /* decoding */ @@ -279,7 +266,7 @@ end: } if (i > MAX_INDEX) - i = AVERROR_INVALIDDATA; + return AVERROR_INVALIDDATA; - return i; + return 0; } diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c index 4f784611d..4c83bcfa9 100644 --- a/libavcodec/mpeg12dec.c +++ b/libavcodec/mpeg12dec.c @@ -29,6 +29,7 @@ #define UNCHECKED_BITSTREAM_READER 1 #include +#include #include "libavutil/attributes.h" #include "libavutil/emms.h" @@ -43,13 +44,12 @@ #include "codec_internal.h" #include "decode.h" #include "error_resilience.h" +#include "get_bits.h" #include "hwaccel_internal.h" #include "hwconfig.h" #include "idctdsp.h" -#include "internal.h" #include "mpeg_er.h" #include "mpeg12.h" -#include "mpeg12codecs.h" #include "mpeg12data.h" #include "mpeg12dec.h" #include "mpegutils.h" @@ -58,7 +58,6 @@ #include "mpegvideodec.h" #include "profiles.h" #include "startcode.h" -#include "thread.h" #define A53_MAX_CC_COUNT 2000 @@ -66,12 +65,21 @@ enum Mpeg2ClosedCaptionsFormat { CC_FORMAT_AUTO, CC_FORMAT_A53_PART4, CC_FORMAT_SCTE20, - CC_FORMAT_DVD + CC_FORMAT_DVD, + CC_FORMAT_DISH }; +typedef struct Mpeg12SliceContext { + MPVContext c; + GetBitContext gb; + + int last_dc[3]; ///< last DC values + + DECLARE_ALIGNED_32(int16_t, block)[12][64]; +} Mpeg12SliceContext; + typedef struct Mpeg1Context { - MpegEncContext mpeg_enc_ctx; - int repeat_field; /* true if we must repeat the field */ + Mpeg12SliceContext slice; AVPanScan pan_scan; /* some temporary storage for the panscan */ enum AVStereo3DType stereo3d_type; int has_stereo3d; @@ -81,8 +89,7 @@ typedef struct Mpeg1Context { int has_afd; int slice_count; unsigned aspect_ratio_info; - AVRational save_aspect; - int save_width, save_height, save_progressive_seq; + int save_progressive_seq, save_chroma_format; AVRational frame_rate_ext; /* MPEG-2 specific framerate modificator */ unsigned frame_rate_index; int sync; /* Did we reach a sync point like a GOP/SEQ/KEYFrame? */ @@ -90,11 +97,13 @@ typedef struct Mpeg1Context { int tmpgexs; int first_slice; int extradata_decoded; + int vbv_delay; + int64_t bit_rate; int64_t timecode_frame_start; /*< GOP timecode frame start number, in non drop frame format */ } Mpeg1Context; /* as H.263, but only 17 codes */ -static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred) +static int mpeg_decode_motion(Mpeg12SliceContext *const s, int fcode, int pred) { int code, sign, val, shift; @@ -124,19 +133,19 @@ static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred) #define check_scantable_index(ctx, x) \ do { \ if ((x) > MAX_INDEX) { \ - av_log(ctx->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", \ - ctx->mb_x, ctx->mb_y); \ + av_log(ctx->c.avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", \ + ctx->c.mb_x, ctx->c.mb_y); \ return AVERROR_INVALIDDATA; \ } \ } while (0) -static inline int mpeg1_decode_block_inter(MpegEncContext *s, +static inline int mpeg1_decode_block_inter(Mpeg12SliceContext *const s, int16_t *block, int n) { int level, i, j, run; - const uint8_t *const scantable = s->intra_scantable.permutated; - const uint16_t *quant_matrix = s->inter_matrix; - const int qscale = s->qscale; + const uint8_t *const scantable = s->c.intra_scantable.permutated; + const uint16_t *quant_matrix = s->c.inter_matrix; + const int qscale = s->c.qscale; { OPEN_READER(re, &s->gb); @@ -210,17 +219,17 @@ end: check_scantable_index(s, i); - s->block_last_index[n] = i; + s->c.block_last_index[n] = i; return 0; } -static inline int mpeg2_decode_block_non_intra(MpegEncContext *s, +static inline int mpeg2_decode_block_non_intra(Mpeg12SliceContext *const s, int16_t *block, int n) { int level, i, j, run; - const uint8_t *const scantable = s->intra_scantable.permutated; + const uint8_t *const scantable = s->c.intra_scantable.permutated; const uint16_t *quant_matrix; - const int qscale = s->qscale; + const int qscale = s->c.qscale; int mismatch; mismatch = 1; @@ -229,9 +238,9 @@ static inline int mpeg2_decode_block_non_intra(MpegEncContext *s, OPEN_READER(re, &s->gb); i = -1; if (n < 4) - quant_matrix = s->inter_matrix; + quant_matrix = s->c.inter_matrix; else - quant_matrix = s->chroma_inter_matrix; + quant_matrix = s->c.chroma_inter_matrix; // Special case for first coefficient, no need to add second VLC table. UPDATE_CACHE(re, &s->gb); @@ -295,38 +304,38 @@ end: check_scantable_index(s, i); - s->block_last_index[n] = i; + s->c.block_last_index[n] = i; return 0; } -static inline int mpeg2_decode_block_intra(MpegEncContext *s, +static inline int mpeg2_decode_block_intra(Mpeg12SliceContext *const s, int16_t *block, int n) { int level, dc, diff, i, j, run; int component; const RL_VLC_ELEM *rl_vlc; - const uint8_t *const scantable = s->intra_scantable.permutated; + const uint8_t *const scantable = s->c.intra_scantable.permutated; const uint16_t *quant_matrix; - const int qscale = s->qscale; + const int qscale = s->c.qscale; int mismatch; /* DC coefficient */ if (n < 4) { - quant_matrix = s->intra_matrix; + quant_matrix = s->c.intra_matrix; component = 0; } else { - quant_matrix = s->chroma_intra_matrix; + quant_matrix = s->c.chroma_intra_matrix; component = (n & 1) + 1; } diff = decode_dc(&s->gb, component); dc = s->last_dc[component]; dc += diff; s->last_dc[component] = dc; - block[0] = dc * (1 << (3 - s->intra_dc_precision)); - ff_tlog(s->avctx, "dc=%d\n", block[0]); + block[0] = dc * (1 << (3 - s->c.intra_dc_precision)); + ff_tlog(s->c.avctx, "dc=%d\n", block[0]); mismatch = block[0] ^ 1; i = 0; - if (s->intra_vlc_format) + if (s->c.intra_vlc_format) rl_vlc = ff_mpeg2_rl_vlc; else rl_vlc = ff_mpeg1_rl_vlc; @@ -377,14 +386,10 @@ static inline int mpeg2_decode_block_intra(MpegEncContext *s, check_scantable_index(s, i); - s->block_last_index[n] = i; return 0; } -/******************************************/ -/* decoding */ - -static inline int get_dmv(MpegEncContext *s) +static inline int get_dmv(Mpeg12SliceContext *const s) { if (get_bits1(&s->gb)) return 1 - (get_bits1(&s->gb) << 1); @@ -398,51 +403,51 @@ static inline int get_dmv(MpegEncContext *s) #define MT_16X8 2 #define MT_DMV 3 -static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) +static int mpeg_decode_mb(Mpeg12SliceContext *const s, int *mb_skip_run) { int i, j, k, cbp, val, mb_type, motion_type; - const int mb_block_count = 4 + (1 << s->chroma_format); + const int mb_block_count = 4 + (1 << s->c.chroma_format); int ret; - ff_tlog(s->avctx, "decode_mb: x=%d y=%d\n", s->mb_x, s->mb_y); + ff_tlog(s->c.avctx, "decode_mb: x=%d y=%d\n", s->c.mb_x, s->c.mb_y); - av_assert2(s->mb_skipped == 0); + av_assert2(s->c.mb_skipped == 0); - if (s->mb_skip_run-- != 0) { - if (s->pict_type == AV_PICTURE_TYPE_P) { - s->mb_skipped = 1; - s->cur_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride] = + if ((*mb_skip_run)-- != 0) { + if (s->c.pict_type == AV_PICTURE_TYPE_P) { + s->c.mb_skipped = 1; + s->c.cur_pic.mb_type[s->c.mb_x + s->c.mb_y * s->c.mb_stride] = MB_TYPE_SKIP | MB_TYPE_FORWARD_MV | MB_TYPE_16x16; } else { int mb_type; - if (s->mb_x) - mb_type = s->cur_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride - 1]; + if (s->c.mb_x) + mb_type = s->c.cur_pic.mb_type[s->c.mb_x + s->c.mb_y * s->c.mb_stride - 1]; else // FIXME not sure if this is allowed in MPEG at all - mb_type = s->cur_pic.mb_type[s->mb_width + (s->mb_y - 1) * s->mb_stride - 1]; + mb_type = s->c.cur_pic.mb_type[s->c.mb_width + (s->c.mb_y - 1) * s->c.mb_stride - 1]; if (IS_INTRA(mb_type)) { - av_log(s->avctx, AV_LOG_ERROR, "skip with previntra\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "skip with previntra\n"); return AVERROR_INVALIDDATA; } - s->cur_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride] = + s->c.cur_pic.mb_type[s->c.mb_x + s->c.mb_y * s->c.mb_stride] = mb_type | MB_TYPE_SKIP; - if ((s->mv[0][0][0] | s->mv[0][0][1] | s->mv[1][0][0] | s->mv[1][0][1]) == 0) - s->mb_skipped = 1; + if ((s->c.mv[0][0][0] | s->c.mv[0][0][1] | s->c.mv[1][0][0] | s->c.mv[1][0][1]) == 0) + s->c.mb_skipped = 1; } return 0; } - switch (s->pict_type) { + switch (s->c.pict_type) { default: case AV_PICTURE_TYPE_I: if (get_bits1(&s->gb) == 0) { if (get_bits1(&s->gb) == 0) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(s->c.avctx, AV_LOG_ERROR, "Invalid mb type in I-frame at %d %d\n", - s->mb_x, s->mb_y); + s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } mb_type = MB_TYPE_QUANT | MB_TYPE_INTRA; @@ -453,159 +458,157 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) case AV_PICTURE_TYPE_P: mb_type = get_vlc2(&s->gb, ff_mb_ptype_vlc, MB_PTYPE_VLC_BITS, 1); if (mb_type < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "Invalid mb type in P-frame at %d %d\n", s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_ERROR, + "Invalid mb type in P-frame at %d %d\n", s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } break; case AV_PICTURE_TYPE_B: mb_type = get_vlc2(&s->gb, ff_mb_btype_vlc, MB_BTYPE_VLC_BITS, 1); if (mb_type < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "Invalid mb type in B-frame at %d %d\n", s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_ERROR, + "Invalid mb type in B-frame at %d %d\n", s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } break; } - ff_tlog(s->avctx, "mb_type=%x\n", mb_type); + ff_tlog(s->c.avctx, "mb_type=%x\n", mb_type); // motion_type = 0; /* avoid warning */ if (IS_INTRA(mb_type)) { - s->bdsp.clear_blocks(s->block[0]); + s->c.bdsp.clear_blocks(s->block[0]); - if (!s->chroma_y_shift) - s->bdsp.clear_blocks(s->block[6]); + if (!s->c.chroma_y_shift) + s->c.bdsp.clear_blocks(s->block[6]); /* compute DCT type */ // FIXME: add an interlaced_dct coded var? - if (s->picture_structure == PICT_FRAME && - !s->frame_pred_frame_dct) - s->interlaced_dct = get_bits1(&s->gb); + if (s->c.picture_structure == PICT_FRAME && + !s->c.frame_pred_frame_dct) + s->c.interlaced_dct = get_bits1(&s->gb); if (IS_QUANT(mb_type)) - s->qscale = mpeg_get_qscale(s); + s->c.qscale = mpeg_get_qscale(&s->gb, s->c.q_scale_type); - if (s->concealment_motion_vectors) { + if (s->c.concealment_motion_vectors) { /* just parse them */ - if (s->picture_structure != PICT_FRAME) + if (s->c.picture_structure != PICT_FRAME) skip_bits1(&s->gb); /* field select */ - s->mv[0][0][0] = - s->last_mv[0][0][0] = - s->last_mv[0][1][0] = mpeg_decode_motion(s, s->mpeg_f_code[0][0], - s->last_mv[0][0][0]); - s->mv[0][0][1] = - s->last_mv[0][0][1] = - s->last_mv[0][1][1] = mpeg_decode_motion(s, s->mpeg_f_code[0][1], - s->last_mv[0][0][1]); + s->c.mv[0][0][0] = + s->c.last_mv[0][0][0] = + s->c.last_mv[0][1][0] = mpeg_decode_motion(s, s->c.mpeg_f_code[0][0], + s->c.last_mv[0][0][0]); + s->c.mv[0][0][1] = + s->c.last_mv[0][0][1] = + s->c.last_mv[0][1][1] = mpeg_decode_motion(s, s->c.mpeg_f_code[0][1], + s->c.last_mv[0][0][1]); - check_marker(s->avctx, &s->gb, "after concealment_motion_vectors"); + check_marker(s->c.avctx, &s->gb, "after concealment_motion_vectors"); } else { /* reset mv prediction */ - memset(s->last_mv, 0, sizeof(s->last_mv)); + memset(s->c.last_mv, 0, sizeof(s->c.last_mv)); } - s->mb_intra = 1; + s->c.mb_intra = 1; - if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO) { for (i = 0; i < mb_block_count; i++) if ((ret = mpeg2_decode_block_intra(s, s->block[i], i)) < 0) return ret; } else { for (i = 0; i < 6; i++) { ret = ff_mpeg1_decode_block_intra(&s->gb, - s->intra_matrix, - s->intra_scantable.permutated, + s->c.intra_matrix, + s->c.intra_scantable.permutated, s->last_dc, s->block[i], - i, s->qscale); + i, s->c.qscale); if (ret < 0) { - av_log(s->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", - s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", + s->c.mb_x, s->c.mb_y); return ret; } - - s->block_last_index[i] = ret; } } } else { if (mb_type & MB_TYPE_ZERO_MV) { av_assert2(mb_type & MB_TYPE_CBP); - s->mv_dir = MV_DIR_FORWARD; - if (s->picture_structure == PICT_FRAME) { - if (s->picture_structure == PICT_FRAME - && !s->frame_pred_frame_dct) - s->interlaced_dct = get_bits1(&s->gb); - s->mv_type = MV_TYPE_16X16; + s->c.mv_dir = MV_DIR_FORWARD; + if (s->c.picture_structure == PICT_FRAME) { + if (s->c.picture_structure == PICT_FRAME + && !s->c.frame_pred_frame_dct) + s->c.interlaced_dct = get_bits1(&s->gb); + s->c.mv_type = MV_TYPE_16X16; } else { - s->mv_type = MV_TYPE_FIELD; + s->c.mv_type = MV_TYPE_FIELD; mb_type |= MB_TYPE_INTERLACED; - s->field_select[0][0] = s->picture_structure - 1; + s->c.field_select[0][0] = s->c.picture_structure - 1; } if (IS_QUANT(mb_type)) - s->qscale = mpeg_get_qscale(s); + s->c.qscale = mpeg_get_qscale(&s->gb, s->c.q_scale_type); - s->last_mv[0][0][0] = 0; - s->last_mv[0][0][1] = 0; - s->last_mv[0][1][0] = 0; - s->last_mv[0][1][1] = 0; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; + s->c.last_mv[0][0][0] = 0; + s->c.last_mv[0][0][1] = 0; + s->c.last_mv[0][1][0] = 0; + s->c.last_mv[0][1][1] = 0; + s->c.mv[0][0][0] = 0; + s->c.mv[0][0][1] = 0; } else { av_assert2(mb_type & MB_TYPE_BIDIR_MV); // FIXME decide if MBs in field pictures are MB_TYPE_INTERLACED /* get additional motion vector type */ - if (s->picture_structure == PICT_FRAME && s->frame_pred_frame_dct) { + if (s->c.picture_structure == PICT_FRAME && s->c.frame_pred_frame_dct) { motion_type = MT_FRAME; } else { motion_type = get_bits(&s->gb, 2); - if (s->picture_structure == PICT_FRAME && HAS_CBP(mb_type)) - s->interlaced_dct = get_bits1(&s->gb); + if (s->c.picture_structure == PICT_FRAME && HAS_CBP(mb_type)) + s->c.interlaced_dct = get_bits1(&s->gb); } if (IS_QUANT(mb_type)) - s->qscale = mpeg_get_qscale(s); + s->c.qscale = mpeg_get_qscale(&s->gb, s->c.q_scale_type); /* motion vectors */ - s->mv_dir = MB_TYPE_MV_2_MV_DIR(mb_type); - ff_tlog(s->avctx, "motion_type=%d\n", motion_type); + s->c.mv_dir = MB_TYPE_MV_2_MV_DIR(mb_type); + ff_tlog(s->c.avctx, "motion_type=%d\n", motion_type); switch (motion_type) { case MT_FRAME: /* or MT_16X8 */ - if (s->picture_structure == PICT_FRAME) { + if (s->c.picture_structure == PICT_FRAME) { mb_type |= MB_TYPE_16x16; - s->mv_type = MV_TYPE_16X16; + s->c.mv_type = MV_TYPE_16X16; for (i = 0; i < 2; i++) { if (HAS_MV(mb_type, i)) { /* MT_FRAME */ - s->mv[i][0][0] = - s->last_mv[i][0][0] = - s->last_mv[i][1][0] = - mpeg_decode_motion(s, s->mpeg_f_code[i][0], - s->last_mv[i][0][0]); - s->mv[i][0][1] = - s->last_mv[i][0][1] = - s->last_mv[i][1][1] = - mpeg_decode_motion(s, s->mpeg_f_code[i][1], - s->last_mv[i][0][1]); + s->c.mv[i][0][0] = + s->c.last_mv[i][0][0] = + s->c.last_mv[i][1][0] = + mpeg_decode_motion(s, s->c.mpeg_f_code[i][0], + s->c.last_mv[i][0][0]); + s->c.mv[i][0][1] = + s->c.last_mv[i][0][1] = + s->c.last_mv[i][1][1] = + mpeg_decode_motion(s, s->c.mpeg_f_code[i][1], + s->c.last_mv[i][0][1]); /* full_pel: only for MPEG-1 */ - if (s->full_pel[i]) { - s->mv[i][0][0] *= 2; - s->mv[i][0][1] *= 2; + if (s->c.full_pel[i]) { + s->c.mv[i][0][0] *= 2; + s->c.mv[i][0][1] *= 2; } } } } else { mb_type |= MB_TYPE_16x8 | MB_TYPE_INTERLACED; - s->mv_type = MV_TYPE_16X8; + s->c.mv_type = MV_TYPE_16X8; for (i = 0; i < 2; i++) { if (HAS_MV(mb_type, i)) { /* MT_16X8 */ for (j = 0; j < 2; j++) { - s->field_select[i][j] = get_bits1(&s->gb); + s->c.field_select[i][j] = get_bits1(&s->gb); for (k = 0; k < 2; k++) { - val = mpeg_decode_motion(s, s->mpeg_f_code[i][k], - s->last_mv[i][j][k]); - s->last_mv[i][j][k] = val; - s->mv[i][j][k] = val; + val = mpeg_decode_motion(s, s->c.mpeg_f_code[i][k], + s->c.last_mv[i][j][k]); + s->c.last_mv[i][j][k] = val; + s->c.mv[i][j][k] = val; } } } @@ -613,121 +616,122 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) } break; case MT_FIELD: - s->mv_type = MV_TYPE_FIELD; - if (s->picture_structure == PICT_FRAME) { + s->c.mv_type = MV_TYPE_FIELD; + if (s->c.picture_structure == PICT_FRAME) { mb_type |= MB_TYPE_16x8 | MB_TYPE_INTERLACED; for (i = 0; i < 2; i++) { if (HAS_MV(mb_type, i)) { for (j = 0; j < 2; j++) { - s->field_select[i][j] = get_bits1(&s->gb); - val = mpeg_decode_motion(s, s->mpeg_f_code[i][0], - s->last_mv[i][j][0]); - s->last_mv[i][j][0] = val; - s->mv[i][j][0] = val; - ff_tlog(s->avctx, "fmx=%d\n", val); - val = mpeg_decode_motion(s, s->mpeg_f_code[i][1], - s->last_mv[i][j][1] >> 1); - s->last_mv[i][j][1] = 2 * val; - s->mv[i][j][1] = val; - ff_tlog(s->avctx, "fmy=%d\n", val); + s->c.field_select[i][j] = get_bits1(&s->gb); + val = mpeg_decode_motion(s, s->c.mpeg_f_code[i][0], + s->c.last_mv[i][j][0]); + s->c.last_mv[i][j][0] = val; + s->c.mv[i][j][0] = val; + ff_tlog(s->c.avctx, "fmx=%d\n", val); + val = mpeg_decode_motion(s, s->c.mpeg_f_code[i][1], + s->c.last_mv[i][j][1] >> 1); + s->c.last_mv[i][j][1] = 2 * val; + s->c.mv[i][j][1] = val; + ff_tlog(s->c.avctx, "fmy=%d\n", val); } } } } else { - av_assert0(!s->progressive_sequence); + av_assert0(!s->c.progressive_sequence); mb_type |= MB_TYPE_16x16 | MB_TYPE_INTERLACED; for (i = 0; i < 2; i++) { if (HAS_MV(mb_type, i)) { - s->field_select[i][0] = get_bits1(&s->gb); + s->c.field_select[i][0] = get_bits1(&s->gb); for (k = 0; k < 2; k++) { - val = mpeg_decode_motion(s, s->mpeg_f_code[i][k], - s->last_mv[i][0][k]); - s->last_mv[i][0][k] = val; - s->last_mv[i][1][k] = val; - s->mv[i][0][k] = val; + val = mpeg_decode_motion(s, s->c.mpeg_f_code[i][k], + s->c.last_mv[i][0][k]); + s->c.last_mv[i][0][k] = val; + s->c.last_mv[i][1][k] = val; + s->c.mv[i][0][k] = val; } } } } break; case MT_DMV: - if (s->progressive_sequence){ - av_log(s->avctx, AV_LOG_ERROR, "MT_DMV in progressive_sequence\n"); + if (s->c.progressive_sequence){ + av_log(s->c.avctx, AV_LOG_ERROR, "MT_DMV in progressive_sequence\n"); return AVERROR_INVALIDDATA; } - s->mv_type = MV_TYPE_DMV; + s->c.mv_type = MV_TYPE_DMV; for (i = 0; i < 2; i++) { if (HAS_MV(mb_type, i)) { int dmx, dmy, mx, my, m; - const int my_shift = s->picture_structure == PICT_FRAME; + const int my_shift = s->c.picture_structure == PICT_FRAME; - mx = mpeg_decode_motion(s, s->mpeg_f_code[i][0], - s->last_mv[i][0][0]); - s->last_mv[i][0][0] = mx; - s->last_mv[i][1][0] = mx; + mx = mpeg_decode_motion(s, s->c.mpeg_f_code[i][0], + s->c.last_mv[i][0][0]); + s->c.last_mv[i][0][0] = mx; + s->c.last_mv[i][1][0] = mx; dmx = get_dmv(s); - my = mpeg_decode_motion(s, s->mpeg_f_code[i][1], - s->last_mv[i][0][1] >> my_shift); + my = mpeg_decode_motion(s, s->c.mpeg_f_code[i][1], + s->c.last_mv[i][0][1] >> my_shift); dmy = get_dmv(s); - s->last_mv[i][0][1] = my * (1 << my_shift); - s->last_mv[i][1][1] = my * (1 << my_shift); + s->c.last_mv[i][0][1] = my * (1 << my_shift); + s->c.last_mv[i][1][1] = my * (1 << my_shift); - s->mv[i][0][0] = mx; - s->mv[i][0][1] = my; - s->mv[i][1][0] = mx; // not used - s->mv[i][1][1] = my; // not used + s->c.mv[i][0][0] = mx; + s->c.mv[i][0][1] = my; + s->c.mv[i][1][0] = mx; // not used + s->c.mv[i][1][1] = my; // not used - if (s->picture_structure == PICT_FRAME) { + if (s->c.picture_structure == PICT_FRAME) { mb_type |= MB_TYPE_16x16 | MB_TYPE_INTERLACED; - // m = 1 + 2 * s->top_field_first; - m = s->top_field_first ? 1 : 3; + // m = 1 + 2 * s->c.top_field_first; + m = s->c.top_field_first ? 1 : 3; /* top -> top pred */ - s->mv[i][2][0] = ((mx * m + (mx > 0)) >> 1) + dmx; - s->mv[i][2][1] = ((my * m + (my > 0)) >> 1) + dmy - 1; + s->c.mv[i][2][0] = ((mx * m + (mx > 0)) >> 1) + dmx; + s->c.mv[i][2][1] = ((my * m + (my > 0)) >> 1) + dmy - 1; m = 4 - m; - s->mv[i][3][0] = ((mx * m + (mx > 0)) >> 1) + dmx; - s->mv[i][3][1] = ((my * m + (my > 0)) >> 1) + dmy + 1; + s->c.mv[i][3][0] = ((mx * m + (mx > 0)) >> 1) + dmx; + s->c.mv[i][3][1] = ((my * m + (my > 0)) >> 1) + dmy + 1; } else { mb_type |= MB_TYPE_16x16; - s->mv[i][2][0] = ((mx + (mx > 0)) >> 1) + dmx; - s->mv[i][2][1] = ((my + (my > 0)) >> 1) + dmy; - if (s->picture_structure == PICT_TOP_FIELD) - s->mv[i][2][1]--; + s->c.mv[i][2][0] = ((mx + (mx > 0)) >> 1) + dmx; + s->c.mv[i][2][1] = ((my + (my > 0)) >> 1) + dmy; + if (s->c.picture_structure == PICT_TOP_FIELD) + s->c.mv[i][2][1]--; else - s->mv[i][2][1]++; + s->c.mv[i][2][1]++; } } } break; default: - av_log(s->avctx, AV_LOG_ERROR, - "00 motion_type at %d %d\n", s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_ERROR, + "00 motion_type at %d %d\n", s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } } - s->mb_intra = 0; + s->c.mb_intra = 0; + s->last_dc[0] = s->last_dc[1] = s->last_dc[2] = 128 << s->c.intra_dc_precision; if (HAS_CBP(mb_type)) { - s->bdsp.clear_blocks(s->block[0]); + s->c.bdsp.clear_blocks(s->block[0]); cbp = get_vlc2(&s->gb, ff_mb_pat_vlc, MB_PAT_VLC_BITS, 1); if (mb_block_count > 6) { cbp *= 1 << mb_block_count - 6; - cbp |= get_bits(&s->gb, mb_block_count - 6); - s->bdsp.clear_blocks(s->block[6]); + cbp |= get_bits(&s->gb, mb_block_count - 6); + s->c.bdsp.clear_blocks(s->block[6]); } if (cbp <= 0) { - av_log(s->avctx, AV_LOG_ERROR, - "invalid cbp %d at %d %d\n", cbp, s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_ERROR, + "invalid cbp %d at %d %d\n", cbp, s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } - if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO) { cbp <<= 12 - mb_block_count; for (i = 0; i < mb_block_count; i++) { @@ -735,7 +739,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) if ((ret = mpeg2_decode_block_non_intra(s, s->block[i], i)) < 0) return ret; } else { - s->block_last_index[i] = -1; + s->c.block_last_index[i] = -1; } cbp += cbp; } @@ -745,18 +749,18 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) if ((ret = mpeg1_decode_block_inter(s, s->block[i], i)) < 0) return ret; } else { - s->block_last_index[i] = -1; + s->c.block_last_index[i] = -1; } cbp += cbp; } } } else { for (i = 0; i < 12; i++) - s->block_last_index[i] = -1; + s->c.block_last_index[i] = -1; } } - s->cur_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride] = mb_type; + s->c.cur_pic.mb_type[s->c.mb_x + s->c.mb_y * s->c.mb_stride] = mb_type; return 0; } @@ -764,9 +768,10 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) static av_cold int mpeg_decode_init(AVCodecContext *avctx) { Mpeg1Context *s = avctx->priv_data; - MpegEncContext *s2 = &s->mpeg_enc_ctx; + MPVContext *const s2 = &s->slice.c; int ret; + s2->slice_ctx_size = sizeof(s->slice); s2->out_format = FMT_MPEG1; if ( avctx->codec_tag != AV_RL32("VCR2") @@ -778,34 +783,11 @@ static av_cold int mpeg_decode_init(AVCodecContext *avctx) ff_mpeg12_init_vlcs(); - s2->chroma_format = 1; - s->repeat_field = 0; + s2->chroma_format = CHROMA_420; avctx->color_range = AVCOL_RANGE_MPEG; return 0; } -#if HAVE_THREADS -static int mpeg_decode_update_thread_context(AVCodecContext *avctx, - const AVCodecContext *avctx_from) -{ - Mpeg1Context *ctx = avctx->priv_data, *ctx_from = avctx_from->priv_data; - MpegEncContext *s = &ctx->mpeg_enc_ctx, *s1 = &ctx_from->mpeg_enc_ctx; - int err; - - if (avctx == avctx_from || !s1->context_initialized) - return 0; - - err = ff_mpeg_update_thread_context(avctx, avctx_from); - if (err) - return err; - - if (!s->context_initialized) - memcpy(s + 1, s1 + 1, sizeof(Mpeg1Context) - sizeof(MpegEncContext)); - - return 0; -} -#endif - static const enum AVPixelFormat mpeg1_hwaccel_pixfmt_list_420[] = { #if CONFIG_MPEG1_NVDEC_HWACCEL AV_PIX_FMT_CUDA, @@ -857,17 +839,17 @@ static const enum AVPixelFormat mpeg12_pixfmt_list_444[] = { static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; const enum AVPixelFormat *pix_fmts; if (CONFIG_GRAY && (avctx->flags & AV_CODEC_FLAG_GRAY)) return AV_PIX_FMT_GRAY8; - if (s->chroma_format < 2) + if (s->chroma_format < CHROMA_422) pix_fmts = avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO ? mpeg1_hwaccel_pixfmt_list_420 : mpeg2_hwaccel_pixfmt_list_420; - else if (s->chroma_format == 2) + else if (s->chroma_format == CHROMA_422) pix_fmts = mpeg12_pixfmt_list_422; else pix_fmts = mpeg12_pixfmt_list_444; @@ -880,7 +862,7 @@ static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx) static int mpeg_decode_postinit(AVCodecContext *avctx) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; int ret; if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) { @@ -937,9 +919,7 @@ static int mpeg_decode_postinit(AVCodecContext *avctx) if (!s->context_initialized || avctx->coded_width != s->width || avctx->coded_height != s->height || - s1->save_width != s->width || - s1->save_height != s->height || - av_cmp_q(s1->save_aspect, s->avctx->sample_aspect_ratio) || + s1->save_chroma_format != s->chroma_format || (s1->save_progressive_seq != s->progressive_sequence && FFALIGN(s->height, 16) != FFALIGN(s->height, 32)) || 0) { if (s->context_initialized) @@ -949,17 +929,15 @@ static int mpeg_decode_postinit(AVCodecContext *avctx) if (ret < 0) return ret; - if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->bit_rate && - (s->bit_rate != 0x3FFFF*400)) { - avctx->rc_max_rate = s->bit_rate; - } else if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && s->bit_rate && - (s->bit_rate != 0x3FFFF*400 || s->vbv_delay != 0xFFFF)) { - avctx->bit_rate = s->bit_rate; + if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO && s1->bit_rate && + (s1->bit_rate != 0x3FFFF*400)) { + avctx->rc_max_rate = s1->bit_rate; + } else if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && s1->bit_rate && + (s1->bit_rate != 0x3FFFF*400 || s1->vbv_delay != 0xFFFF)) { + avctx->bit_rate = s1->bit_rate; } - s1->save_aspect = s->avctx->sample_aspect_ratio; - s1->save_width = s->width; - s1->save_height = s->height; s1->save_progressive_seq = s->progressive_sequence; + s1->save_chroma_format = s->chroma_format; /* low_delay may be forced, in this case we will have B-frames * that behave like P-frames. */ @@ -968,12 +946,6 @@ static int mpeg_decode_postinit(AVCodecContext *avctx) if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) { // MPEG-1 fps avctx->framerate = ff_mpeg12_frame_rate_tab[s1->frame_rate_index]; -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - avctx->ticks_per_frame = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - avctx->chroma_sample_location = AVCHROMA_LOC_CENTER; } else { // MPEG-2 // MPEG-2 fps @@ -982,16 +954,11 @@ FF_ENABLE_DEPRECATION_WARNINGS ff_mpeg12_frame_rate_tab[s1->frame_rate_index].num * s1->frame_rate_ext.num, ff_mpeg12_frame_rate_tab[s1->frame_rate_index].den * s1->frame_rate_ext.den, 1 << 30); -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - avctx->ticks_per_frame = 2; -FF_ENABLE_DEPRECATION_WARNINGS -#endif switch (s->chroma_format) { - case 1: avctx->chroma_sample_location = AVCHROMA_LOC_LEFT; break; - case 2: - case 3: avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; break; + case CHROMA_420: avctx->chroma_sample_location = AVCHROMA_LOC_LEFT; break; + case CHROMA_422: + case CHROMA_444: avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; break; default: av_assert0(0); } } // MPEG-2 @@ -1001,7 +968,8 @@ FF_ENABLE_DEPRECATION_WARNINGS if ((ret = ff_mpv_common_init(s)) < 0) return ret; if (!s->avctx->lowres) - ff_mpv_framesize_disable(&s->sc); + for (int i = 0; i < s->slice_context_count; i++) + ff_mpv_framesize_disable(&s->thread_context[i]->sc); } return 0; } @@ -1010,24 +978,25 @@ static int mpeg1_decode_picture(AVCodecContext *avctx, const uint8_t *buf, int buf_size) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; + GetBitContext gb0, *const gb = &gb0; int ref, f_code, vbv_delay, ret; - ret = init_get_bits8(&s->gb, buf, buf_size); + ret = init_get_bits8(gb, buf, buf_size); if (ret < 0) return ret; - ref = get_bits(&s->gb, 10); /* temporal ref */ - s->pict_type = get_bits(&s->gb, 3); + ref = get_bits(gb, 10); /* temporal ref */ + s->pict_type = get_bits(gb, 3); if (s->pict_type == 0 || s->pict_type > 3) return AVERROR_INVALIDDATA; - vbv_delay = get_bits(&s->gb, 16); - s->vbv_delay = vbv_delay; + vbv_delay = get_bits(gb, 16); + s1->vbv_delay = vbv_delay; if (s->pict_type == AV_PICTURE_TYPE_P || s->pict_type == AV_PICTURE_TYPE_B) { - s->full_pel[0] = get_bits1(&s->gb); - f_code = get_bits(&s->gb, 3); + s->full_pel[0] = get_bits1(gb); + f_code = get_bits(gb, 3); if (f_code == 0 && (avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))) return AVERROR_INVALIDDATA; f_code += !f_code; @@ -1035,8 +1004,8 @@ static int mpeg1_decode_picture(AVCodecContext *avctx, const uint8_t *buf, s->mpeg_f_code[0][1] = f_code; } if (s->pict_type == AV_PICTURE_TYPE_B) { - s->full_pel[1] = get_bits1(&s->gb); - f_code = get_bits(&s->gb, 3); + s->full_pel[1] = get_bits1(gb); + f_code = get_bits(gb, 3); if (f_code == 0 && (avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))) return AVERROR_INVALIDDATA; f_code += !f_code; @@ -1048,43 +1017,42 @@ static int mpeg1_decode_picture(AVCodecContext *avctx, const uint8_t *buf, av_log(avctx, AV_LOG_DEBUG, "vbv_delay %d, ref %d type:%d\n", vbv_delay, ref, s->pict_type); - s->y_dc_scale = 8; - s->c_dc_scale = 8; return 0; } -static void mpeg_decode_sequence_extension(Mpeg1Context *s1) +static void mpeg_decode_sequence_extension(Mpeg1Context *const s1, + GetBitContext *const gb) { - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; int horiz_size_ext, vert_size_ext; int bit_rate_ext; - skip_bits(&s->gb, 1); /* profile and level esc*/ - s->avctx->profile = get_bits(&s->gb, 3); - s->avctx->level = get_bits(&s->gb, 4); - s->progressive_sequence = get_bits1(&s->gb); /* progressive_sequence */ - s->chroma_format = get_bits(&s->gb, 2); /* chroma_format 1=420, 2=422, 3=444 */ + skip_bits(gb, 1); /* profile and level esc*/ + s->avctx->profile = get_bits(gb, 3); + s->avctx->level = get_bits(gb, 4); + s->progressive_sequence = get_bits1(gb); /* progressive_sequence */ + s->chroma_format = get_bits(gb, 2); /* chroma_format 1=420, 2=422, 3=444 */ if (!s->chroma_format) { - s->chroma_format = 1; + s->chroma_format = CHROMA_420; av_log(s->avctx, AV_LOG_WARNING, "Chroma format invalid\n"); } - horiz_size_ext = get_bits(&s->gb, 2); - vert_size_ext = get_bits(&s->gb, 2); + horiz_size_ext = get_bits(gb, 2); + vert_size_ext = get_bits(gb, 2); s->width |= (horiz_size_ext << 12); s->height |= (vert_size_ext << 12); - bit_rate_ext = get_bits(&s->gb, 12); /* XXX: handle it */ - s->bit_rate += (bit_rate_ext << 18) * 400LL; - check_marker(s->avctx, &s->gb, "after bit rate extension"); - s->avctx->rc_buffer_size += get_bits(&s->gb, 8) * 1024 * 16 << 10; + bit_rate_ext = get_bits(gb, 12); /* XXX: handle it */ + s1->bit_rate += (bit_rate_ext << 18) * 400LL; + check_marker(s->avctx, gb, "after bit rate extension"); + s->avctx->rc_buffer_size += get_bits(gb, 8) * 1024 * 16 << 10; - s->low_delay = get_bits1(&s->gb); + s->low_delay = get_bits1(gb); if (s->avctx->flags & AV_CODEC_FLAG_LOW_DELAY) s->low_delay = 1; - s1->frame_rate_ext.num = get_bits(&s->gb, 2) + 1; - s1->frame_rate_ext.den = get_bits(&s->gb, 5) + 1; + s1->frame_rate_ext.num = get_bits(gb, 2) + 1; + s1->frame_rate_ext.den = get_bits(gb, 5) + 1; ff_dlog(s->avctx, "sequence extension\n"); s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG2VIDEO; @@ -1093,24 +1061,25 @@ static void mpeg_decode_sequence_extension(Mpeg1Context *s1) av_log(s->avctx, AV_LOG_DEBUG, "profile: %d, level: %d ps: %d cf:%d vbv buffer: %d, bitrate:%"PRId64"\n", s->avctx->profile, s->avctx->level, s->progressive_sequence, s->chroma_format, - s->avctx->rc_buffer_size, s->bit_rate); + s->avctx->rc_buffer_size, s1->bit_rate); } -static void mpeg_decode_sequence_display_extension(Mpeg1Context *s1) +static void mpeg_decode_sequence_display_extension(Mpeg1Context *const s1, + GetBitContext *const gb) { - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; int color_description, w, h; - skip_bits(&s->gb, 3); /* video format */ - color_description = get_bits1(&s->gb); + skip_bits(gb, 3); /* video format */ + color_description = get_bits1(gb); if (color_description) { - s->avctx->color_primaries = get_bits(&s->gb, 8); - s->avctx->color_trc = get_bits(&s->gb, 8); - s->avctx->colorspace = get_bits(&s->gb, 8); + s->avctx->color_primaries = get_bits(gb, 8); + s->avctx->color_trc = get_bits(gb, 8); + s->avctx->colorspace = get_bits(gb, 8); } - w = get_bits(&s->gb, 14); - skip_bits(&s->gb, 1); // marker - h = get_bits(&s->gb, 14); + w = get_bits(gb, 14); + skip_bits(gb, 1); // marker + h = get_bits(gb, 14); // remaining 3 bits are zero padding s1->pan_scan.width = 16 * w; @@ -1120,9 +1089,10 @@ static void mpeg_decode_sequence_display_extension(Mpeg1Context *s1) av_log(s->avctx, AV_LOG_DEBUG, "sde w:%d, h:%d\n", w, h); } -static void mpeg_decode_picture_display_extension(Mpeg1Context *s1) +static void mpeg_decode_picture_display_extension(Mpeg1Context *const s1, + GetBitContext *const gb) { - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; int i, nofco; nofco = 1; @@ -1140,10 +1110,10 @@ static void mpeg_decode_picture_display_extension(Mpeg1Context *s1) } } for (i = 0; i < nofco; i++) { - s1->pan_scan.position[i][0] = get_sbits(&s->gb, 16); - skip_bits(&s->gb, 1); // marker - s1->pan_scan.position[i][1] = get_sbits(&s->gb, 16); - skip_bits(&s->gb, 1); // marker + s1->pan_scan.position[i][0] = get_sbits(gb, 16); + skip_bits(gb, 1); // marker + s1->pan_scan.position[i][1] = get_sbits(gb, 16); + skip_bits(gb, 1); // marker } if (s->avctx->debug & FF_DEBUG_PICT_INFO) @@ -1154,14 +1124,14 @@ static void mpeg_decode_picture_display_extension(Mpeg1Context *s1) s1->pan_scan.position[2][0], s1->pan_scan.position[2][1]); } -static int load_matrix(MpegEncContext *s, uint16_t matrix0[64], - uint16_t matrix1[64], int intra) +static int load_matrix(MPVContext *const s, GetBitContext *const gb, + uint16_t matrix0[64], uint16_t matrix1[64], int intra) { int i; for (i = 0; i < 64; i++) { int j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; - int v = get_bits(&s->gb, 8); + int v = get_bits(gb, 8); if (v == 0) { av_log(s->avctx, AV_LOG_ERROR, "matrix damaged\n"); return AVERROR_INVALIDDATA; @@ -1177,29 +1147,31 @@ static int load_matrix(MpegEncContext *s, uint16_t matrix0[64], return 0; } -static void mpeg_decode_quant_matrix_extension(MpegEncContext *s) +static void mpeg_decode_quant_matrix_extension(MPVContext *const s, + GetBitContext *const gb) { ff_dlog(s->avctx, "matrix extension\n"); - if (get_bits1(&s->gb)) - load_matrix(s, s->chroma_intra_matrix, s->intra_matrix, 1); - if (get_bits1(&s->gb)) - load_matrix(s, s->chroma_inter_matrix, s->inter_matrix, 0); - if (get_bits1(&s->gb)) - load_matrix(s, s->chroma_intra_matrix, NULL, 1); - if (get_bits1(&s->gb)) - load_matrix(s, s->chroma_inter_matrix, NULL, 0); + if (get_bits1(gb)) + load_matrix(s, gb, s->chroma_intra_matrix, s->intra_matrix, 1); + if (get_bits1(gb)) + load_matrix(s, gb, s->chroma_inter_matrix, s->inter_matrix, 0); + if (get_bits1(gb)) + load_matrix(s, gb, s->chroma_intra_matrix, NULL, 1); + if (get_bits1(gb)) + load_matrix(s, gb, s->chroma_inter_matrix, NULL, 0); } -static int mpeg_decode_picture_coding_extension(Mpeg1Context *s1) +static int mpeg_decode_picture_coding_extension(Mpeg1Context *const s1, + GetBitContext *const gb) { - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; s->full_pel[0] = s->full_pel[1] = 0; - s->mpeg_f_code[0][0] = get_bits(&s->gb, 4); - s->mpeg_f_code[0][1] = get_bits(&s->gb, 4); - s->mpeg_f_code[1][0] = get_bits(&s->gb, 4); - s->mpeg_f_code[1][1] = get_bits(&s->gb, 4); + s->mpeg_f_code[0][0] = get_bits(gb, 4); + s->mpeg_f_code[0][1] = get_bits(gb, 4); + s->mpeg_f_code[1][0] = get_bits(gb, 4); + s->mpeg_f_code[1][1] = get_bits(gb, 4); s->mpeg_f_code[0][0] += !s->mpeg_f_code[0][0]; s->mpeg_f_code[0][1] += !s->mpeg_f_code[0][1]; s->mpeg_f_code[1][0] += !s->mpeg_f_code[1][0]; @@ -1218,22 +1190,22 @@ static int mpeg_decode_picture_coding_extension(Mpeg1Context *s1) s->pict_type = AV_PICTURE_TYPE_B; } - s->intra_dc_precision = get_bits(&s->gb, 2); - s->picture_structure = get_bits(&s->gb, 2); - s->top_field_first = get_bits1(&s->gb); - s->frame_pred_frame_dct = get_bits1(&s->gb); - s->concealment_motion_vectors = get_bits1(&s->gb); - s->q_scale_type = get_bits1(&s->gb); - s->intra_vlc_format = get_bits1(&s->gb); - s->alternate_scan = get_bits1(&s->gb); - s->repeat_first_field = get_bits1(&s->gb); - s->chroma_420_type = get_bits1(&s->gb); - s->progressive_frame = get_bits1(&s->gb); + s->intra_dc_precision = get_bits(gb, 2); + s->picture_structure = get_bits(gb, 2); + s->top_field_first = get_bits1(gb); + s->frame_pred_frame_dct = get_bits1(gb); + s->concealment_motion_vectors = get_bits1(gb); + s->q_scale_type = get_bits1(gb); + s->intra_vlc_format = get_bits1(gb); + s->alternate_scan = get_bits1(gb); + s->repeat_first_field = get_bits1(gb); + s->chroma_420_type = get_bits1(gb); + s->progressive_frame = get_bits1(gb); - // We only initialize intra_scantable, as both scantables always coincide - // and all code therefore only uses the intra one. - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, - s->alternate_scan ? ff_alternate_vertical_scan : ff_zigzag_direct); + // We only initialize intra_scantable.permutated, as this is all we use. + ff_permute_scantable(s->intra_scantable.permutated, + s->alternate_scan ? ff_alternate_vertical_scan : ff_zigzag_direct, + s->idsp.idct_permutation); /* composite display not parsed */ ff_dlog(s->avctx, "intra_dc_precision=%d\n", s->intra_dc_precision); @@ -1251,7 +1223,7 @@ static int mpeg_decode_picture_coding_extension(Mpeg1Context *s1) static int mpeg_field_start(Mpeg1Context *s1, const uint8_t *buf, int buf_size) { - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; AVCodecContext *avctx = s->avctx; int second_field = 0; int ret; @@ -1331,9 +1303,6 @@ static int mpeg_field_start(Mpeg1Context *s1, const uint8_t *buf, int buf_size) *sd->data = s1->afd; s1->has_afd = 0; } - - if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_FRAME)) - ff_thread_finish_setup(avctx); } else { // second field second_field = 1; if (!s->cur_pic.ptr) { @@ -1361,7 +1330,7 @@ static int mpeg_field_start(Mpeg1Context *s1, const uint8_t *buf, int buf_size) } if (avctx->hwaccel) { - if ((ret = FF_HW_CALL(avctx, start_frame, buf, buf_size)) < 0) + if ((ret = FF_HW_CALL(avctx, start_frame, NULL, buf, buf_size)) < 0) return ret; } else if (s->codec_tag == MKTAG('V', 'C', 'R', '2')) { // Exchange UV @@ -1383,37 +1352,36 @@ static int mpeg_field_start(Mpeg1Context *s1, const uint8_t *buf, int buf_size) /** * Decode a slice. - * MpegEncContext.mb_y must be set to the MB row from the startcode. + * Mpeg12SliceContext.c.mb_y must be set to the MB row from the startcode. * @return DECODE_SLICE_ERROR if the slice is damaged, * DECODE_SLICE_OK if this slice is OK */ -static int mpeg_decode_slice(MpegEncContext *s, int mb_y, +static int mpeg_decode_slice(Mpeg12SliceContext *const s, int mb_y, const uint8_t **buf, int buf_size) { - AVCodecContext *avctx = s->avctx; - const int lowres = s->avctx->lowres; - const int field_pic = s->picture_structure != PICT_FRAME; + AVCodecContext *avctx = s->c.avctx; + const int lowres = s->c.avctx->lowres; + const int field_pic = s->c.picture_structure != PICT_FRAME; int ret; - s->resync_mb_x = - s->resync_mb_y = -1; + s->c.resync_mb_x = + s->c.resync_mb_y = -1; - av_assert0(mb_y < s->mb_height); + av_assert0(mb_y < s->c.mb_height); ret = init_get_bits8(&s->gb, *buf, buf_size); if (ret < 0) return ret; - if (s->codec_id != AV_CODEC_ID_MPEG1VIDEO && s->mb_height > 2800/16) + if (s->c.codec_id != AV_CODEC_ID_MPEG1VIDEO && s->c.mb_height > 2800/16) skip_bits(&s->gb, 3); - ff_mpeg1_clean_buffers(s); - s->interlaced_dct = 0; + s->c.interlaced_dct = 0; - s->qscale = mpeg_get_qscale(s); + s->c.qscale = mpeg_get_qscale(&s->gb, s->c.q_scale_type); - if (s->qscale == 0) { - av_log(s->avctx, AV_LOG_ERROR, "qscale == 0\n"); + if (s->c.qscale == 0) { + av_log(s->c.avctx, AV_LOG_ERROR, "qscale == 0\n"); return AVERROR_INVALIDDATA; } @@ -1421,31 +1389,31 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, if (skip_1stop_8data_bits(&s->gb) < 0) return AVERROR_INVALIDDATA; - s->mb_x = 0; + s->c.mb_x = 0; - if (mb_y == 0 && s->codec_tag == AV_RL32("SLIF")) { + if (mb_y == 0 && s->c.codec_tag == AV_RL32("SLIF")) { skip_bits1(&s->gb); } else { while (get_bits_left(&s->gb) > 0) { int code = get_vlc2(&s->gb, ff_mbincr_vlc, MBINCR_VLC_BITS, 2); if (code < 0) { - av_log(s->avctx, AV_LOG_ERROR, "first mb_incr damaged\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "first mb_incr damaged\n"); return AVERROR_INVALIDDATA; } if (code >= 33) { if (code == 33) - s->mb_x += 33; + s->c.mb_x += 33; /* otherwise, stuffing, nothing to do */ } else { - s->mb_x += code; + s->c.mb_x += code; break; } } } - if (s->mb_x >= (unsigned) s->mb_width) { - av_log(s->avctx, AV_LOG_ERROR, "initial skip overflow\n"); + if (s->c.mb_x >= (unsigned) s->c.mb_width) { + av_log(s->c.avctx, AV_LOG_ERROR, "initial skip overflow\n"); return AVERROR_INVALIDDATA; } @@ -1455,102 +1423,106 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, buf_end = avpriv_find_start_code(buf_start + 2, *buf + buf_size, &start_code); if (buf_end < *buf + buf_size) buf_end -= 4; - s->mb_y = mb_y; + s->c.mb_y = mb_y; if (FF_HW_CALL(avctx, decode_slice, buf_start, buf_end - buf_start) < 0) return DECODE_SLICE_ERROR; *buf = buf_end; return DECODE_SLICE_OK; } - s->resync_mb_x = s->mb_x; - s->resync_mb_y = s->mb_y = mb_y; - s->mb_skip_run = 0; - ff_init_block_index(s); + s->c.resync_mb_x = s->c.mb_x; + s->c.resync_mb_y = s->c.mb_y = mb_y; + ff_init_block_index(&s->c); - if (s->mb_y == 0 && s->mb_x == 0 && (s->first_field || s->picture_structure == PICT_FRAME)) { - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, + if (s->c.mb_y == 0 && s->c.mb_x == 0 && (s->c.first_field || s->c.picture_structure == PICT_FRAME)) { + if (s->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(s->c.avctx, AV_LOG_DEBUG, "qp:%d fc:%2d%2d%2d%2d %c %s %s %s %s dc:%d pstruct:%d fdct:%d cmv:%d qtype:%d ivlc:%d rff:%d %s\n", - s->qscale, - s->mpeg_f_code[0][0], s->mpeg_f_code[0][1], - s->mpeg_f_code[1][0], s->mpeg_f_code[1][1], - s->pict_type == AV_PICTURE_TYPE_I ? 'I' : - (s->pict_type == AV_PICTURE_TYPE_P ? 'P' : - (s->pict_type == AV_PICTURE_TYPE_B ? 'B' : 'S')), - s->progressive_sequence ? "ps" : "", - s->progressive_frame ? "pf" : "", - s->alternate_scan ? "alt" : "", - s->top_field_first ? "top" : "", - s->intra_dc_precision, s->picture_structure, - s->frame_pred_frame_dct, s->concealment_motion_vectors, - s->q_scale_type, s->intra_vlc_format, - s->repeat_first_field, s->chroma_420_type ? "420" : ""); + s->c.qscale, + s->c.mpeg_f_code[0][0], s->c.mpeg_f_code[0][1], + s->c.mpeg_f_code[1][0], s->c.mpeg_f_code[1][1], + s->c.pict_type == AV_PICTURE_TYPE_I ? 'I' : + (s->c.pict_type == AV_PICTURE_TYPE_P ? 'P' : + (s->c.pict_type == AV_PICTURE_TYPE_B ? 'B' : 'S')), + s->c.progressive_sequence ? "ps" : "", + s->c.progressive_frame ? "pf" : "", + s->c.alternate_scan ? "alt" : "", + s->c.top_field_first ? "top" : "", + s->c.intra_dc_precision, s->c.picture_structure, + s->c.frame_pred_frame_dct, s->c.concealment_motion_vectors, + s->c.q_scale_type, s->c.intra_vlc_format, + s->c.repeat_first_field, s->c.chroma_420_type ? "420" : ""); } } - for (;;) { - if ((ret = mpeg_decode_mb(s, s->block)) < 0) + s->last_dc[0] = 128 << s->c.intra_dc_precision; + s->last_dc[1] = s->last_dc[0]; + s->last_dc[2] = s->last_dc[0]; + memset(s->c.last_mv, 0, sizeof(s->c.last_mv)); + + for (int mb_skip_run = 0;;) { + ret = mpeg_decode_mb(s, &mb_skip_run); + if (ret < 0) return ret; // Note motion_val is normally NULL unless we want to extract the MVs. - if (s->cur_pic.motion_val[0]) { - const int wrap = s->b8_stride; - int xy = s->mb_x * 2 + s->mb_y * 2 * wrap; - int b8_xy = 4 * (s->mb_x + s->mb_y * s->mb_stride); + if (s->c.cur_pic.motion_val[0]) { + const int wrap = s->c.b8_stride; + int xy = s->c.mb_x * 2 + s->c.mb_y * 2 * wrap; + int b8_xy = 4 * (s->c.mb_x + s->c.mb_y * s->c.mb_stride); int motion_x, motion_y, dir, i; for (i = 0; i < 2; i++) { for (dir = 0; dir < 2; dir++) { - if (s->mb_intra || - (dir == 1 && s->pict_type != AV_PICTURE_TYPE_B)) { + if (s->c.mb_intra || + (dir == 1 && s->c.pict_type != AV_PICTURE_TYPE_B)) { motion_x = motion_y = 0; - } else if (s->mv_type == MV_TYPE_16X16 || - (s->mv_type == MV_TYPE_FIELD && field_pic)) { - motion_x = s->mv[dir][0][0]; - motion_y = s->mv[dir][0][1]; - } else { /* if ((s->mv_type == MV_TYPE_FIELD) || (s->mv_type == MV_TYPE_16X8)) */ - motion_x = s->mv[dir][i][0]; - motion_y = s->mv[dir][i][1]; + } else if (s->c.mv_type == MV_TYPE_16X16 || + (s->c.mv_type == MV_TYPE_FIELD && field_pic)) { + motion_x = s->c.mv[dir][0][0]; + motion_y = s->c.mv[dir][0][1]; + } else { /* if ((s->c.mv_type == MV_TYPE_FIELD) || (s->c.mv_type == MV_TYPE_16X8)) */ + motion_x = s->c.mv[dir][i][0]; + motion_y = s->c.mv[dir][i][1]; } - s->cur_pic.motion_val[dir][xy][0] = motion_x; - s->cur_pic.motion_val[dir][xy][1] = motion_y; - s->cur_pic.motion_val[dir][xy + 1][0] = motion_x; - s->cur_pic.motion_val[dir][xy + 1][1] = motion_y; - s->cur_pic.ref_index [dir][b8_xy] = - s->cur_pic.ref_index [dir][b8_xy + 1] = s->field_select[dir][i]; - av_assert2(s->field_select[dir][i] == 0 || - s->field_select[dir][i] == 1); + s->c.cur_pic.motion_val[dir][xy][0] = motion_x; + s->c.cur_pic.motion_val[dir][xy][1] = motion_y; + s->c.cur_pic.motion_val[dir][xy + 1][0] = motion_x; + s->c.cur_pic.motion_val[dir][xy + 1][1] = motion_y; + s->c.cur_pic.ref_index [dir][b8_xy] = + s->c.cur_pic.ref_index [dir][b8_xy + 1] = s->c.field_select[dir][i]; + av_assert2(s->c.field_select[dir][i] == 0 || + s->c.field_select[dir][i] == 1); } xy += wrap; b8_xy += 2; } } - s->dest[0] += 16 >> lowres; - s->dest[1] +=(16 >> lowres) >> s->chroma_x_shift; - s->dest[2] +=(16 >> lowres) >> s->chroma_x_shift; + s->c.dest[0] += 16 >> lowres; + s->c.dest[1] +=(16 >> lowres) >> s->c.chroma_x_shift; + s->c.dest[2] +=(16 >> lowres) >> s->c.chroma_x_shift; - ff_mpv_reconstruct_mb(s, s->block); + ff_mpv_reconstruct_mb(&s->c, s->block); - if (++s->mb_x >= s->mb_width) { - const int mb_size = 16 >> s->avctx->lowres; + if (++s->c.mb_x >= s->c.mb_width) { + const int mb_size = 16 >> s->c.avctx->lowres; int left; - ff_mpeg_draw_horiz_band(s, mb_size * (s->mb_y >> field_pic), mb_size); - ff_mpv_report_decode_progress(s); + ff_mpeg_draw_horiz_band(&s->c, mb_size * (s->c.mb_y >> field_pic), mb_size); - s->mb_x = 0; - s->mb_y += 1 << field_pic; + s->c.mb_x = 0; + s->c.mb_y += 1 << field_pic; - if (s->mb_y >= s->mb_height) { + if (s->c.mb_y >= s->c.mb_height) { int left = get_bits_left(&s->gb); - int is_d10 = s->chroma_format == 2 && - s->pict_type == AV_PICTURE_TYPE_I && + int is_d10 = s->c.chroma_format == CHROMA_422 && + s->c.pict_type == AV_PICTURE_TYPE_I && avctx->profile == 0 && avctx->level == 5 && - s->intra_dc_precision == 2 && - s->q_scale_type == 1 && s->alternate_scan == 0 && - s->progressive_frame == 0 + s->c.intra_dc_precision == 2 && + s->c.q_scale_type == 1 && s->c.alternate_scan == 0 && + s->c.progressive_frame == 0 /* vbv_delay == 0xBBB || 0xE10 */; if (left >= 32 && !is_d10) { @@ -1570,7 +1542,7 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, (left && show_bits(&s->gb, FFMIN(left, 23)) && !is_d10) || ((avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_AGGRESSIVE)) && left > 8)) { av_log(avctx, AV_LOG_ERROR, "end mismatch left=%d %0X at %d %d\n", - left, left>0 ? show_bits(&s->gb, FFMIN(left, 23)) : 0, s->mb_x, s->mb_y); + left, left>0 ? show_bits(&s->gb, FFMIN(left, 23)) : 0, s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } else goto eos; @@ -1580,134 +1552,136 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, // area, we detect this here instead of running into the end expecting // more data left = get_bits_left(&s->gb); - if (s->mb_y >= ((s->height + 15) >> 4) && - !s->progressive_sequence && + if (s->c.mb_y >= ((s->c.height + 15) >> 4) && + !s->c.progressive_sequence && left <= 25 && left >= 0 && - s->mb_skip_run == -1 && + mb_skip_run == -1 && (!left || show_bits(&s->gb, left) == 0)) goto eos; - ff_init_block_index(s); + ff_init_block_index(&s->c); } /* skip mb handling */ - if (s->mb_skip_run == -1) { + if (mb_skip_run == -1) { /* read increment again */ - s->mb_skip_run = 0; + mb_skip_run = 0; for (;;) { int code = get_vlc2(&s->gb, ff_mbincr_vlc, MBINCR_VLC_BITS, 2); if (code < 0) { - av_log(s->avctx, AV_LOG_ERROR, "mb incr damaged\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "mb incr damaged\n"); return AVERROR_INVALIDDATA; } if (code >= 33) { if (code == 33) { - s->mb_skip_run += 33; + mb_skip_run += 33; } else if (code == 35) { - if (s->mb_skip_run != 0 || show_bits(&s->gb, 15) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "slice mismatch\n"); + if (mb_skip_run != 0 || show_bits(&s->gb, 15) != 0) { + av_log(s->c.avctx, AV_LOG_ERROR, "slice mismatch\n"); return AVERROR_INVALIDDATA; } goto eos; /* end of slice */ } /* otherwise, stuffing, nothing to do */ } else { - s->mb_skip_run += code; + mb_skip_run += code; break; } } - if (s->mb_skip_run) { + if (mb_skip_run) { int i; - if (s->pict_type == AV_PICTURE_TYPE_I) { - av_log(s->avctx, AV_LOG_ERROR, - "skipped MB in I-frame at %d %d\n", s->mb_x, s->mb_y); + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + av_log(s->c.avctx, AV_LOG_ERROR, + "skipped MB in I-frame at %d %d\n", s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } /* skip mb */ - s->mb_intra = 0; + s->c.mb_intra = 0; for (i = 0; i < 12; i++) - s->block_last_index[i] = -1; - if (s->picture_structure == PICT_FRAME) - s->mv_type = MV_TYPE_16X16; + s->c.block_last_index[i] = -1; + s->last_dc[0] = s->last_dc[1] = s->last_dc[2] = 128 << s->c.intra_dc_precision; + if (s->c.picture_structure == PICT_FRAME) + s->c.mv_type = MV_TYPE_16X16; else - s->mv_type = MV_TYPE_FIELD; - if (s->pict_type == AV_PICTURE_TYPE_P) { + s->c.mv_type = MV_TYPE_FIELD; + if (s->c.pict_type == AV_PICTURE_TYPE_P) { /* if P type, zero motion vector is implied */ - s->mv_dir = MV_DIR_FORWARD; - s->mv[0][0][0] = s->mv[0][0][1] = 0; - s->last_mv[0][0][0] = s->last_mv[0][0][1] = 0; - s->last_mv[0][1][0] = s->last_mv[0][1][1] = 0; - s->field_select[0][0] = (s->picture_structure - 1) & 1; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv[0][0][0] = s->c.mv[0][0][1] = 0; + s->c.last_mv[0][0][0] = s->c.last_mv[0][0][1] = 0; + s->c.last_mv[0][1][0] = s->c.last_mv[0][1][1] = 0; + s->c.field_select[0][0] = (s->c.picture_structure - 1) & 1; } else { /* if B type, reuse previous vectors and directions */ - s->mv[0][0][0] = s->last_mv[0][0][0]; - s->mv[0][0][1] = s->last_mv[0][0][1]; - s->mv[1][0][0] = s->last_mv[1][0][0]; - s->mv[1][0][1] = s->last_mv[1][0][1]; - s->field_select[0][0] = (s->picture_structure - 1) & 1; - s->field_select[1][0] = (s->picture_structure - 1) & 1; + s->c.mv[0][0][0] = s->c.last_mv[0][0][0]; + s->c.mv[0][0][1] = s->c.last_mv[0][0][1]; + s->c.mv[1][0][0] = s->c.last_mv[1][0][0]; + s->c.mv[1][0][1] = s->c.last_mv[1][0][1]; + s->c.field_select[0][0] = (s->c.picture_structure - 1) & 1; + s->c.field_select[1][0] = (s->c.picture_structure - 1) & 1; } } } } eos: // end of slice if (get_bits_left(&s->gb) < 0) { - av_log(s, AV_LOG_ERROR, "overread %d\n", -get_bits_left(&s->gb)); + av_log(s->c.avctx, AV_LOG_ERROR, "overread %d\n", -get_bits_left(&s->gb)); return AVERROR_INVALIDDATA; } *buf += (get_bits_count(&s->gb) - 1) / 8; - ff_dlog(s, "Slice start:%d %d end:%d %d\n", s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y); + ff_dlog(s->c.avctx, "Slice start:%d %d end:%d %d\n", s->c.resync_mb_x, s->c.resync_mb_y, s->c.mb_x, s->c.mb_y); return 0; } static int slice_decode_thread(AVCodecContext *c, void *arg) { - MpegEncContext *s = *(void **) arg; + Mpeg12SliceContext *const s = *(void **) arg; const uint8_t *buf = s->gb.buffer; - int mb_y = s->start_mb_y; - const int field_pic = s->picture_structure != PICT_FRAME; + const uint8_t *end = buf + get_bits_bytesize(&s->gb, 0); + int mb_y = s->c.start_mb_y; + const int field_pic = s->c.picture_structure != PICT_FRAME; - s->er.error_count = (3 * (s->end_mb_y - s->start_mb_y) * s->mb_width) >> field_pic; + s->c.er.error_count = (3 * (s->c.end_mb_y - s->c.start_mb_y) * s->c.mb_width) >> field_pic; for (;;) { uint32_t start_code; int ret; - ret = mpeg_decode_slice(s, mb_y, &buf, s->gb.buffer_end - buf); + ret = mpeg_decode_slice(s, mb_y, &buf, end - buf); emms_c(); ff_dlog(c, "ret:%d resync:%d/%d mb:%d/%d ts:%d/%d ec:%d\n", - ret, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, - s->start_mb_y, s->end_mb_y, s->er.error_count); + ret, s->c.resync_mb_x, s->c.resync_mb_y, s->c.mb_x, s->c.mb_y, + s->c.start_mb_y, s->c.end_mb_y, s->c.er.error_count); if (ret < 0) { if (c->err_recognition & AV_EF_EXPLODE) return ret; - if (s->resync_mb_x >= 0 && s->resync_mb_y >= 0) - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x, s->mb_y, + if (s->c.resync_mb_x >= 0 && s->c.resync_mb_y >= 0) + ff_er_add_slice(&s->c.er, s->c.resync_mb_x, s->c.resync_mb_y, + s->c.mb_x, s->c.mb_y, ER_AC_ERROR | ER_DC_ERROR | ER_MV_ERROR); } else { - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x - 1, s->mb_y, + ff_er_add_slice(&s->c.er, s->c.resync_mb_x, s->c.resync_mb_y, + s->c.mb_x - 1, s->c.mb_y, ER_AC_END | ER_DC_END | ER_MV_END); } - if (s->mb_y == s->end_mb_y) + if (s->c.mb_y == s->c.end_mb_y) return 0; start_code = -1; - buf = avpriv_find_start_code(buf, s->gb.buffer_end, &start_code); + buf = avpriv_find_start_code(buf, end, &start_code); if (start_code < SLICE_MIN_START_CODE || start_code > SLICE_MAX_START_CODE) return AVERROR_INVALIDDATA; mb_y = start_code - SLICE_MIN_START_CODE; - if (s->codec_id != AV_CODEC_ID_MPEG1VIDEO && s->mb_height > 2800/16) + if (s->c.codec_id != AV_CODEC_ID_MPEG1VIDEO && s->c.mb_height > 2800/16) mb_y += (*buf&0xE0)<<2; mb_y <<= field_pic; - if (s->picture_structure == PICT_BOTTOM_FIELD) + if (s->c.picture_structure == PICT_BOTTOM_FIELD) mb_y++; - if (mb_y >= s->end_mb_y) + if (mb_y >= s->c.end_mb_y) return AVERROR_INVALIDDATA; } } @@ -1719,7 +1693,7 @@ static int slice_decode_thread(AVCodecContext *c, void *arg) static int slice_end(AVCodecContext *avctx, AVFrame *pict, int *got_output) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; if (!s->context_initialized || !s->cur_pic.ptr) return 0; @@ -1770,45 +1744,46 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, const uint8_t *buf, int buf_size) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; + GetBitContext gb0, *const gb = &gb0; int width, height; int i, v, j; - int ret = init_get_bits8(&s->gb, buf, buf_size); + int ret = init_get_bits8(gb, buf, buf_size); if (ret < 0) return ret; - width = get_bits(&s->gb, 12); - height = get_bits(&s->gb, 12); + width = get_bits(gb, 12); + height = get_bits(gb, 12); if (width == 0 || height == 0) { av_log(avctx, AV_LOG_WARNING, "Invalid horizontal or vertical size value.\n"); if (avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_COMPLIANT)) return AVERROR_INVALIDDATA; } - s1->aspect_ratio_info = get_bits(&s->gb, 4); + s1->aspect_ratio_info = get_bits(gb, 4); if (s1->aspect_ratio_info == 0) { av_log(avctx, AV_LOG_ERROR, "aspect ratio has forbidden 0 value\n"); if (avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_COMPLIANT)) return AVERROR_INVALIDDATA; } - s1->frame_rate_index = get_bits(&s->gb, 4); + s1->frame_rate_index = get_bits(gb, 4); if (s1->frame_rate_index == 0 || s1->frame_rate_index > 13) { av_log(avctx, AV_LOG_WARNING, "frame_rate_index %d is invalid\n", s1->frame_rate_index); s1->frame_rate_index = 1; } - s->bit_rate = get_bits(&s->gb, 18) * 400LL; - if (check_marker(s->avctx, &s->gb, "in sequence header") == 0) { + s1->bit_rate = get_bits(gb, 18) * 400; + if (check_marker(s->avctx, gb, "in sequence header") == 0) { return AVERROR_INVALIDDATA; } - s->avctx->rc_buffer_size = get_bits(&s->gb, 10) * 1024 * 16; - skip_bits(&s->gb, 1); + s->avctx->rc_buffer_size = get_bits(gb, 10) * 1024 * 16; + skip_bits(gb, 1); /* get matrix */ - if (get_bits1(&s->gb)) { - load_matrix(s, s->chroma_intra_matrix, s->intra_matrix, 1); + if (get_bits1(gb)) { + load_matrix(s, gb, s->chroma_intra_matrix, s->intra_matrix, 1); } else { for (i = 0; i < 64; i++) { j = s->idsp.idct_permutation[i]; @@ -1817,8 +1792,8 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, s->chroma_intra_matrix[j] = v; } } - if (get_bits1(&s->gb)) { - load_matrix(s, s->chroma_inter_matrix, s->inter_matrix, 0); + if (get_bits1(gb)) { + load_matrix(s, gb, s->chroma_inter_matrix, s->inter_matrix, 0); } else { for (i = 0; i < 64; i++) { int j = s->idsp.idct_permutation[i]; @@ -1828,7 +1803,7 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, } } - if (show_bits(&s->gb, 23) != 0) { + if (show_bits(gb, 23) != 0) { av_log(s->avctx, AV_LOG_ERROR, "sequence header damaged\n"); return AVERROR_INVALIDDATA; } @@ -1842,7 +1817,7 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, s->picture_structure = PICT_FRAME; s->first_field = 0; s->frame_pred_frame_dct = 1; - s->chroma_format = 1; + s->chroma_format = CHROMA_420; s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG1VIDEO; if (s->avctx->flags & AV_CODEC_FLAG_LOW_DELAY) @@ -1850,7 +1825,7 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, if (s->avctx->debug & FF_DEBUG_PICT_INFO) av_log(s->avctx, AV_LOG_DEBUG, "vbv buffer: %d, bitrate:%"PRId64", aspect_ratio_info: %d \n", - s->avctx->rc_buffer_size, s->bit_rate, s1->aspect_ratio_info); + s->avctx->rc_buffer_size, s1->bit_rate, s1->aspect_ratio_info); return 0; } @@ -1858,7 +1833,7 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, static int vcr2_init_sequence(AVCodecContext *avctx) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; int i, v, ret; /* start new MPEG-1 context decoding */ @@ -1875,7 +1850,8 @@ static int vcr2_init_sequence(AVCodecContext *avctx) if ((ret = ff_mpv_common_init(s)) < 0) return ret; if (!s->avctx->lowres) - ff_mpv_framesize_disable(&s->sc); + for (int i = 0; i < s->slice_context_count; i++) + ff_mpv_framesize_disable(&s->thread_context[i]->sc); for (i = 0; i < 64; i++) { int j = s->idsp.idct_permutation[i]; @@ -1893,15 +1869,14 @@ static int vcr2_init_sequence(AVCodecContext *avctx) s->picture_structure = PICT_FRAME; s->first_field = 0; s->frame_pred_frame_dct = 1; - s->chroma_format = 1; + s->chroma_format = CHROMA_420; if (s->codec_tag == AV_RL32("BW10")) { s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG1VIDEO; } else { s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG2VIDEO; } - s1->save_width = s->width; - s1->save_height = s->height; s1->save_progressive_seq = s->progressive_sequence; + s1->save_chroma_format = s->chroma_format; return 0; } @@ -1917,6 +1892,12 @@ static void mpeg_set_cc_format(AVCodecContext *avctx, enum Mpeg2ClosedCaptionsFo av_log(avctx, AV_LOG_DEBUG, "CC: first seen substream is %s format\n", label); } + +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS + avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif } static int mpeg_decode_a53_cc(AVCodecContext *avctx, @@ -1943,7 +1924,6 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, if (ret >= 0) memcpy(s1->a53_buf_ref->data + old_size, p + 7, cc_count * UINT64_C(3)); - avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; mpeg_set_cc_format(avctx, CC_FORMAT_A53_PART4, "A/53 Part 4"); } return 1; @@ -1969,9 +1949,9 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, ret = av_buffer_realloc(&s1->a53_buf_ref, new_size); if (ret >= 0) { uint8_t field, cc1, cc2; - uint8_t *cap = s1->a53_buf_ref->data; + uint8_t *cap = s1->a53_buf_ref->data + old_size; - memset(s1->a53_buf_ref->data + old_size, 0, cc_count * 3); + memset(cap, 0, cc_count * 3); for (i = 0; i < cc_count && get_bits_left(&gb) >= 26; i++) { skip_bits(&gb, 2); // priority field = get_bits(&gb, 2); @@ -1984,7 +1964,7 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, cap[0] = cap[1] = cap[2] = 0x00; } else { field = (field == 2 ? 1 : 0); - if (!s1->mpeg_enc_ctx.top_field_first) field = !field; + if (!s1->slice.c.top_field_first) field = !field; cap[0] = 0x04 | field; cap[1] = ff_reverse[cc1]; cap[2] = ff_reverse[cc2]; @@ -1993,7 +1973,6 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, } } - avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; mpeg_set_cc_format(avctx, CC_FORMAT_SCTE20, "SCTE-20"); } return 1; @@ -2042,7 +2021,7 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, ret = av_buffer_realloc(&s1->a53_buf_ref, new_size); if (ret >= 0) { uint8_t field1 = !!(p[4] & 0x80); - uint8_t *cap = s1->a53_buf_ref->data; + uint8_t *cap = s1->a53_buf_ref->data + old_size; p += 5; for (i = 0; i < cc_count; i++) { cap[0] = (p[0] == 0xff && field1) ? 0xfc : 0xfd; @@ -2056,10 +2035,72 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, } } - avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; mpeg_set_cc_format(avctx, CC_FORMAT_DVD, "DVD"); } return 1; + } else if ((!s1->cc_format || s1->cc_format == CC_FORMAT_DISH) && + buf_size >= 12 && + p[0] == 0x05 && p[1] == 0x02) { + /* extract Dish Network CC data */ + const uint8_t cc_header = 0xf8 | 0x04 /* valid */ | 0x00 /* line 21 field 1 */; + uint8_t cc_data[4] = {0}; + int cc_count = 0; + uint8_t cc_type = p[7]; + p += 8; + buf_size -= 8; + + if (cc_type == 0x05 && buf_size >= 7) { + cc_type = p[6]; + p += 7; + buf_size -= 7; + } + + if (cc_type == 0x02 && buf_size >= 4) { /* 2-byte caption, can be repeated */ + cc_count = 1; + cc_data[0] = p[1]; + cc_data[1] = p[2]; + cc_type = p[3]; + + /* Only repeat characters when the next type flag + * is 0x04 and the characters are repeatable (i.e., less than + * 32 with the parity stripped). + */ + if (cc_type == 0x04 && (cc_data[0] & 0x7f) < 32) { + cc_count = 2; + cc_data[2] = cc_data[0]; + cc_data[3] = cc_data[1]; + } + } else if (cc_type == 0x04 && buf_size >= 5) { /* 4-byte caption, not repeated */ + cc_count = 2; + cc_data[0] = p[1]; + cc_data[1] = p[2]; + cc_data[2] = p[3]; + cc_data[3] = p[4]; + } + + if (cc_count > 0) { + int ret; + int old_size = s1->a53_buf_ref ? s1->a53_buf_ref->size : 0; + const uint64_t new_size = (old_size + cc_count * UINT64_C(3)); + if (new_size > 3 * A53_MAX_CC_COUNT) + return AVERROR(EINVAL); + + ret = av_buffer_realloc(&s1->a53_buf_ref, new_size); + if (ret >= 0) { + uint8_t *cap = s1->a53_buf_ref->data + old_size; + cap[0] = cc_header; + cap[1] = cc_data[0]; + cap[2] = cc_data[1]; + if (cc_count == 2) { + cap[3] = cc_header; + cap[4] = cc_data[2]; + cap[5] = cc_data[3]; + } + } + + mpeg_set_cc_format(avctx, CC_FORMAT_DISH, "Dish Network"); + } + return 1; } return 0; } @@ -2067,7 +2108,6 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, static void mpeg_decode_user_data(AVCodecContext *avctx, const uint8_t *p, int buf_size) { - Mpeg1Context *s = avctx->priv_data; const uint8_t *buf_end = p + buf_size; Mpeg1Context *s1 = avctx->priv_data; @@ -2083,7 +2123,7 @@ static void mpeg_decode_user_data(AVCodecContext *avctx, int i; for(i=0; i<20; i++) if (!memcmp(p+i, "\0TMPGEXS\0", 9)){ - s->tmpgexs= 1; + s1->tmpgexs = 1; } } /* we parse the DTG active format information */ @@ -2138,21 +2178,22 @@ static int mpeg_decode_gop(AVCodecContext *avctx, const uint8_t *buf, int buf_size) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; + GetBitContext gb0, *const gb = &gb0; int broken_link; int64_t tc; - int ret = init_get_bits8(&s->gb, buf, buf_size); + int ret = init_get_bits8(gb, buf, buf_size); if (ret < 0) return ret; - tc = s1->timecode_frame_start = get_bits(&s->gb, 25); + tc = s1->timecode_frame_start = get_bits(gb, 25); - s1->closed_gop = get_bits1(&s->gb); + s1->closed_gop = get_bits1(gb); /* broken_link indicates that after editing the * reference frames of the first B-Frames after GOP I-Frame * are missing (open gop) */ - broken_link = get_bits1(&s->gb); + broken_link = get_bits1(gb); if (s->avctx->debug & FF_DEBUG_PICT_INFO) { char tcbuf[AV_TIMECODE_STR_SIZE]; @@ -2165,11 +2206,40 @@ static int mpeg_decode_gop(AVCodecContext *avctx, return 0; } +static void mpeg12_execute_slice_threads(AVCodecContext *avctx, + Mpeg1Context *const s) +{ + if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_SLICE) && + !avctx->hwaccel) { + MPVContext *const s2 = &s->slice.c; + int error_count = 0; + + avctx->execute(avctx, slice_decode_thread, + s2->mpeg12_contexts, NULL, + s->slice_count, sizeof(s2->mpeg12_contexts[0])); + + for (int i = 0; i < s->slice_count; i++) { + MpegEncContext *const slice = s2->thread_context[i]; + int slice_err = atomic_load_explicit(&slice->er.error_count, + memory_order_relaxed); + // error_count can get set to INT_MAX on serious errors. + // So use saturated addition. + if ((unsigned)slice_err > INT_MAX - error_count) { + error_count = INT_MAX; + break; + } + error_count += slice_err; + } + atomic_store_explicit(&s2->er.error_count, error_count, + memory_order_relaxed); + } +} + static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, int *got_output, const uint8_t *buf, int buf_size) { Mpeg1Context *s = avctx->priv_data; - MpegEncContext *s2 = &s->mpeg_enc_ctx; + MPVContext *const s2 = &s->slice.c; const uint8_t *buf_ptr = buf; const uint8_t *buf_end = buf + buf_size; int ret, input_size; @@ -2182,18 +2252,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, buf_ptr = avpriv_find_start_code(buf_ptr, buf_end, &start_code); if (start_code > 0x1ff) { if (!skip_frame) { - if (HAVE_THREADS && - (avctx->active_thread_type & FF_THREAD_SLICE) && - !avctx->hwaccel) { - int i; - av_assert0(avctx->thread_count > 1); - - avctx->execute(avctx, slice_decode_thread, - &s2->thread_context[0], NULL, - s->slice_count, sizeof(void *)); - for (i = 0; i < s->slice_count; i++) - s2->er.error_count += s2->thread_context[i]->er.error_count; - } + mpeg12_execute_slice_threads(avctx, s); ret = slice_end(avctx, picture, got_output); if (ret < 0) @@ -2210,7 +2269,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, input_size = buf_end - buf_ptr; if (avctx->debug & FF_DEBUG_STARTCODE) - av_log(avctx, AV_LOG_DEBUG, "%3"PRIX32" at %"PTRDIFF_SPECIFIER" left %d\n", + av_log(avctx, AV_LOG_DEBUG, "%3"PRIX32" at %td left %d\n", start_code, buf_ptr - buf, input_size); /* prepare data for next start code */ @@ -2252,15 +2311,8 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, s2->intra_dc_precision= 3; s2->intra_matrix[0]= 1; } - if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_SLICE) && - !avctx->hwaccel && s->slice_count) { - int i; - - avctx->execute(avctx, slice_decode_thread, - s2->thread_context, NULL, - s->slice_count, sizeof(void *)); - for (i = 0; i < s->slice_count; i++) - s2->er.error_count += s2->thread_context[i]->er.error_count; + if (s->slice_count) { + mpeg12_execute_slice_threads(avctx, s); s->slice_count = 0; } if (last_code == 0 || last_code == SLICE_MIN_START_CODE) { @@ -2283,15 +2335,17 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, return AVERROR_INVALIDDATA; } break; - case EXT_START_CODE: - ret = init_get_bits8(&s2->gb, buf_ptr, input_size); + case EXT_START_CODE: { + GetBitContext gb0, *const gb = &gb0; + + ret = init_get_bits8(gb, buf_ptr, input_size); if (ret < 0) return ret; - switch (get_bits(&s2->gb, 4)) { + switch (get_bits(gb, 4)) { case 0x1: if (last_code == 0) { - mpeg_decode_sequence_extension(s); + mpeg_decode_sequence_extension(s, gb); } else { av_log(avctx, AV_LOG_ERROR, "ignoring seq ext after %X\n", last_code); @@ -2300,17 +2354,17 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, } break; case 0x2: - mpeg_decode_sequence_display_extension(s); + mpeg_decode_sequence_display_extension(s, gb); break; case 0x3: - mpeg_decode_quant_matrix_extension(s2); + mpeg_decode_quant_matrix_extension(s2, gb); break; case 0x7: - mpeg_decode_picture_display_extension(s); + mpeg_decode_picture_display_extension(s, gb); break; case 0x8: if (last_code == PICTURE_START_CODE) { - int ret = mpeg_decode_picture_coding_extension(s); + int ret = mpeg_decode_picture_coding_extension(s, gb); if (ret < 0) return ret; } else { @@ -2322,6 +2376,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, break; } break; + } case USER_START_CODE: mpeg_decode_user_data(avctx, buf_ptr, input_size); break; @@ -2458,15 +2513,14 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, int threshold = (s2->mb_height * s->slice_count + s2->slice_context_count / 2) / s2->slice_context_count; - av_assert0(avctx->thread_count > 1); if (threshold <= mb_y) { - MpegEncContext *thread_context = s2->thread_context[s->slice_count]; + Mpeg12SliceContext *const thread_context = s2->mpeg12_contexts[s->slice_count]; - thread_context->start_mb_y = mb_y; - thread_context->end_mb_y = s2->mb_height; + thread_context->c.start_mb_y = mb_y; + thread_context->c.end_mb_y = s2->mb_height; if (s->slice_count) { s2->thread_context[s->slice_count - 1]->end_mb_y = mb_y; - ret = ff_update_duplicate_context(thread_context, s2); + ret = ff_update_duplicate_context(&thread_context->c, s2); if (ret < 0) return ret; } @@ -2477,7 +2531,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, } buf_ptr += 2; // FIXME add minimum number of bytes per slice } else { - ret = mpeg_decode_slice(s2, mb_y, &buf_ptr, input_size); + ret = mpeg_decode_slice(&s->slice, mb_y, &buf_ptr, input_size); emms_c(); if (ret < 0) { @@ -2506,7 +2560,7 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture, int ret; int buf_size = avpkt->size; Mpeg1Context *s = avctx->priv_data; - MpegEncContext *s2 = &s->mpeg_enc_ctx; + MPVContext *const s2 = &s->slice.c; if (buf_size == 0 || (buf_size == 4 && AV_RB32(buf) == SEQ_END_CODE)) { /* special case for last picture */ @@ -2566,7 +2620,7 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture, return ret; } -static void flush(AVCodecContext *avctx) +static av_cold void flush(AVCodecContext *avctx) { Mpeg1Context *s = avctx->priv_data; @@ -2599,7 +2653,6 @@ const FFCodec ff_mpeg1video_decoder = { .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .flush = flush, .p.max_lowres = 3, - UPDATE_THREAD_CONTEXT(mpeg_decode_update_thread_context), .hw_configs = (const AVCodecHWConfigInternal *const []) { #if CONFIG_MPEG1_NVDEC_HWACCEL HWACCEL_NVDEC(mpeg1), @@ -2620,7 +2673,7 @@ const FFCodec ff_mpeg1video_decoder = { static const AVOption mpeg2video_options[] = { { "cc_format", "extract a specific Closed Captions format", M2V_OFFSET(cc_format), AV_OPT_TYPE_INT, { .i64 = CC_FORMAT_AUTO }, - CC_FORMAT_AUTO, CC_FORMAT_DVD, M2V_PARAM, .unit = "cc_format" }, + CC_FORMAT_AUTO, CC_FORMAT_DISH, M2V_PARAM, .unit = "cc_format" }, { "auto", "pick first seen CC substream", 0, AV_OPT_TYPE_CONST, { .i64 = CC_FORMAT_AUTO }, .flags = M2V_PARAM, .unit = "cc_format" }, @@ -2630,6 +2683,8 @@ static const AVOption mpeg2video_options[] = { { .i64 = CC_FORMAT_SCTE20 }, .flags = M2V_PARAM, .unit = "cc_format" }, { "dvd", "pick DVD CC substream", 0, AV_OPT_TYPE_CONST, { .i64 = CC_FORMAT_DVD }, .flags = M2V_PARAM, .unit = "cc_format" }, + { "dish", "pick Dish Network CC substream", 0, AV_OPT_TYPE_CONST, + { .i64 = CC_FORMAT_DISH }, .flags = M2V_PARAM, .unit = "cc_format" }, { NULL } }; @@ -2704,18 +2759,18 @@ const FFCodec ff_mpegvideo_decoder = { }; typedef struct IPUContext { - MpegEncContext m; + Mpeg12SliceContext m; int flags; - DECLARE_ALIGNED(32, int16_t, block)[6][64]; } IPUContext; static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt) { IPUContext *s = avctx->priv_data; - MpegEncContext *m = &s->m; - GetBitContext *gb = &m->gb; + MPVContext *const m = &s->m.c; + GetBitContext *const gb = &s->m.gb; + int16_t (*const block)[64] = s->m.block; int ret; // Check for minimal intra MB size (considering mb header, luma & chroma dc VLC, ac EOB VLC) @@ -2736,10 +2791,11 @@ static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, m->intra_vlc_format = !!(s->flags & 0x20); m->alternate_scan = !!(s->flags & 0x10); - ff_init_scantable(m->idsp.idct_permutation, &m->intra_scantable, - s->flags & 0x10 ? ff_alternate_vertical_scan : ff_zigzag_direct); + ff_permute_scantable(m->intra_scantable.permutated, + s->flags & 0x10 ? ff_alternate_vertical_scan : ff_zigzag_direct, + m->idsp.idct_permutation); - m->last_dc[0] = m->last_dc[1] = m->last_dc[2] = 1 << (7 + (s->flags & 3)); + s->m.last_dc[0] = s->m.last_dc[1] = s->m.last_dc[2] = 128 << (s->flags & 3); m->qscale = 1; for (int y = 0; y < avctx->height; y += 16) { @@ -2762,19 +2818,19 @@ static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, skip_bits1(gb); if (intraquant) - m->qscale = mpeg_get_qscale(m); + m->qscale = mpeg_get_qscale(gb, m->q_scale_type); - memset(s->block, 0, sizeof(s->block)); + memset(block, 0, 6 * sizeof(*block)); for (int n = 0; n < 6; n++) { if (s->flags & 0x80) { - ret = ff_mpeg1_decode_block_intra(&m->gb, + ret = ff_mpeg1_decode_block_intra(gb, m->intra_matrix, m->intra_scantable.permutated, - m->last_dc, s->block[n], + s->m.last_dc, block[n], n, m->qscale); } else { - ret = mpeg2_decode_block_intra(m, s->block[n], n); + ret = mpeg2_decode_block_intra(&s->m, block[n], n); } if (ret < 0) @@ -2782,17 +2838,17 @@ static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, } m->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x, - frame->linesize[0], s->block[0]); + frame->linesize[0], block[0]); m->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x + 8, - frame->linesize[0], s->block[1]); + frame->linesize[0], block[1]); m->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x, - frame->linesize[0], s->block[2]); + frame->linesize[0], block[2]); m->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x + 8, - frame->linesize[0], s->block[3]); + frame->linesize[0], block[3]); m->idsp.idct_put(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1), - frame->linesize[1], s->block[4]); + frame->linesize[1], block[4]); m->idsp.idct_put(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1), - frame->linesize[2], s->block[5]); + frame->linesize[2], block[5]); } } @@ -2808,7 +2864,7 @@ static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, static av_cold int ipu_decode_init(AVCodecContext *avctx) { IPUContext *s = avctx->priv_data; - MpegEncContext *m = &s->m; + MPVContext *const m = &s->m.c; avctx->pix_fmt = AV_PIX_FMT_YUV420P; m->avctx = avctx; diff --git a/libavcodec/mpeg12enc.c b/libavcodec/mpeg12enc.c index e56571da0..753732714 100644 --- a/libavcodec/mpeg12enc.c +++ b/libavcodec/mpeg12enc.c @@ -25,6 +25,7 @@ * MPEG-1/2 encoder */ +#include #include #include "config.h" @@ -49,6 +50,7 @@ #include "mpegvideodata.h" #include "mpegvideoenc.h" #include "profiles.h" +#include "put_bits.h" #include "rl.h" #if CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER @@ -72,7 +74,7 @@ static uint32_t mpeg1_lum_dc_uni[512]; static uint32_t mpeg1_chr_dc_uni[512]; typedef struct MPEG12EncContext { - MpegEncContext mpeg; + MPVMainEncContext mpeg; AVRational frame_rate_ext; unsigned frame_rate_index; @@ -137,157 +139,27 @@ av_cold void ff_mpeg1_init_uni_ac_vlc(const int8_t max_level[], } #if CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER -static int find_frame_rate_index(AVCodecContext *avctx, MPEG12EncContext *mpeg12) -{ - int i; - AVRational bestq = (AVRational) {0, 0}; - AVRational ext; - AVRational target = av_inv_q(avctx->time_base); - - for (i = 1; i < 14; i++) { - if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL && - i >= 9) - break; - - for (ext.num=1; ext.num <= 4; ext.num++) { - for (ext.den=1; ext.den <= 32; ext.den++) { - AVRational q = av_mul_q(ext, ff_mpeg12_frame_rate_tab[i]); - - if (avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO && (ext.den!=1 || ext.num!=1)) - continue; - if (av_gcd(ext.den, ext.num) != 1) - continue; - - if ( bestq.num==0 - || av_nearer_q(target, bestq, q) < 0 - || ext.num==1 && ext.den==1 && av_nearer_q(target, bestq, q) == 0) { - bestq = q; - mpeg12->frame_rate_index = i; - mpeg12->frame_rate_ext.num = ext.num; - mpeg12->frame_rate_ext.den = ext.den; - } - } - } - } - - if (av_cmp_q(target, bestq)) - return -1; - else - return 0; -} - -static av_cold int encode_init(AVCodecContext *avctx) -{ - MPEG12EncContext *const mpeg12 = avctx->priv_data; - int ret; - int max_size = avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ? 16383 : 4095; - - if (avctx->width > max_size || avctx->height > max_size) { - av_log(avctx, AV_LOG_ERROR, "%s does not support resolutions above %dx%d\n", - CONFIG_SMALL ? avctx->codec->name : avctx->codec->long_name, - max_size, max_size); - return AVERROR(EINVAL); - } - if ((avctx->width & 0xFFF) == 0 && (avctx->height & 0xFFF) == 1) { - av_log(avctx, AV_LOG_ERROR, "Width / Height is invalid for MPEG2\n"); - return AVERROR(EINVAL); - } - - if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { - if ((avctx->width & 0xFFF) == 0 || (avctx->height & 0xFFF) == 0) { - av_log(avctx, AV_LOG_ERROR, "Width or Height are not allowed to be multiples of 4096\n" - "add '-strict %d' if you want to use them anyway.\n", FF_COMPLIANCE_UNOFFICIAL); - return AVERROR(EINVAL); - } - } - - if (avctx->profile == AV_PROFILE_UNKNOWN) { - if (avctx->level != AV_LEVEL_UNKNOWN) { - av_log(avctx, AV_LOG_ERROR, "Set profile and level\n"); - return AVERROR(EINVAL); - } - /* Main or 4:2:2 */ - avctx->profile = avctx->pix_fmt == AV_PIX_FMT_YUV420P ? AV_PROFILE_MPEG2_MAIN - : AV_PROFILE_MPEG2_422; - } - if (avctx->level == AV_LEVEL_UNKNOWN) { - if (avctx->profile == AV_PROFILE_MPEG2_422) { /* 4:2:2 */ - if (avctx->width <= 720 && avctx->height <= 608) - avctx->level = 5; /* Main */ - else - avctx->level = 2; /* High */ - } else { - if (avctx->profile != AV_PROFILE_MPEG2_HIGH && - avctx->pix_fmt != AV_PIX_FMT_YUV420P) { - av_log(avctx, AV_LOG_ERROR, - "Only High(1) and 4:2:2(0) profiles support 4:2:2 color sampling\n"); - return AVERROR(EINVAL); - } - if (avctx->width <= 720 && avctx->height <= 576) - avctx->level = 8; /* Main */ - else if (avctx->width <= 1440) - avctx->level = 6; /* High 1440 */ - else - avctx->level = 4; /* High */ - } - } - - if ((ret = ff_mpv_encode_init(avctx)) < 0) - return ret; - - if (find_frame_rate_index(avctx, mpeg12) < 0) { - if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { - av_log(avctx, AV_LOG_ERROR, "MPEG-1/2 does not support %d/%d fps\n", - avctx->time_base.den, avctx->time_base.num); - return AVERROR(EINVAL); - } else { - av_log(avctx, AV_LOG_INFO, - "MPEG-1/2 does not support %d/%d fps, there may be AV sync issues\n", - avctx->time_base.den, avctx->time_base.num); - } - } - - if (mpeg12->drop_frame_timecode) - mpeg12->tc.flags |= AV_TIMECODE_FLAG_DROPFRAME; - if (mpeg12->drop_frame_timecode && mpeg12->frame_rate_index != 4) { - av_log(avctx, AV_LOG_ERROR, - "Drop frame time code only allowed with 1001/30000 fps\n"); - return AVERROR(EINVAL); - } - - if (mpeg12->tc_opt_str) { - AVRational rate = ff_mpeg12_frame_rate_tab[mpeg12->frame_rate_index]; - int ret = av_timecode_init_from_string(&mpeg12->tc, rate, mpeg12->tc_opt_str, avctx); - if (ret < 0) - return ret; - mpeg12->drop_frame_timecode = !!(mpeg12->tc.flags & AV_TIMECODE_FLAG_DROPFRAME); - mpeg12->timecode_frame_start = mpeg12->tc.start; - } else { - mpeg12->timecode_frame_start = 0; // default is -1 - } - - return 0; -} - -static void put_header(MpegEncContext *s, uint32_t header) +static void put_header(MPVEncContext *const s, uint32_t header) { align_put_bits(&s->pb); put_bits32(&s->pb, header); } /* put sequence header if needed */ -static void mpeg1_encode_sequence_header(MpegEncContext *s) +static void mpeg1_encode_sequence_header(MPEG12EncContext *mpeg12) { - MPEG12EncContext *const mpeg12 = (MPEG12EncContext*)s; + MPVEncContext *const s = &mpeg12->mpeg.s; unsigned int vbv_buffer_size, fps, v; int constraint_parameter_flag; AVRational framerate = ff_mpeg12_frame_rate_tab[mpeg12->frame_rate_index]; uint64_t time_code; int64_t best_aspect_error = INT64_MAX; - AVRational aspect_ratio = s->avctx->sample_aspect_ratio; + AVRational aspect_ratio = s->c.avctx->sample_aspect_ratio; int aspect_ratio_info; - if (!(s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY)) + put_bits_assume_flushed(&s->pb); + + if (!(s->c.cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY)) return; if (aspect_ratio.num == 0 || aspect_ratio.den == 0) @@ -296,15 +168,15 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) /* MPEG-1 header repeated every GOP */ put_header(s, SEQ_START_CODE); - put_sbits(&s->pb, 12, s->width & 0xFFF); - put_sbits(&s->pb, 12, s->height & 0xFFF); + put_sbits(&s->pb, 12, s->c.width & 0xFFF); + put_sbits(&s->pb, 12, s->c.height & 0xFFF); for (int i = 1; i < 15; i++) { int64_t error = aspect_ratio.num * (1LL<<32) / aspect_ratio.den; - if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO || i <= 1) + if (s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO || i <= 1) error -= (1LL<<32) / ff_mpeg1_aspect[i]; else - error -= (1LL<<32)*ff_mpeg2_aspect[i].num * s->height / s->width / ff_mpeg2_aspect[i].den; + error -= (1LL<<32)*ff_mpeg2_aspect[i].num * s->c.height / s->c.width / ff_mpeg2_aspect[i].den; error = FFABS(error); @@ -317,20 +189,20 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) put_bits(&s->pb, 4, aspect_ratio_info); put_bits(&s->pb, 4, mpeg12->frame_rate_index); - if (s->avctx->rc_max_rate) { - v = (s->avctx->rc_max_rate + 399) / 400; - if (v > 0x3ffff && s->codec_id == AV_CODEC_ID_MPEG1VIDEO) + if (s->c.avctx->rc_max_rate) { + v = (s->c.avctx->rc_max_rate + 399) / 400; + if (v > 0x3ffff && s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO) v = 0x3ffff; } else { v = 0x3FFFF; } - if (s->avctx->rc_buffer_size) - vbv_buffer_size = s->avctx->rc_buffer_size; + if (s->c.avctx->rc_buffer_size) + vbv_buffer_size = s->c.avctx->rc_buffer_size; else /* VBV calculation: Scaled so that a VCD has the proper * VBV size of 40 kilobytes */ - vbv_buffer_size = av_rescale_rnd(s->bit_rate, 20, 1151929 / 2, AV_ROUND_ZERO) * 8 * 1024; + vbv_buffer_size = av_rescale_rnd(mpeg12->mpeg.bit_rate, 20, 1151929 / 2, AV_ROUND_ZERO) * 8 * 1024; vbv_buffer_size = (vbv_buffer_size + 16383) / 16384; put_sbits(&s->pb, 18, v); @@ -338,48 +210,48 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) put_sbits(&s->pb, 10, vbv_buffer_size); constraint_parameter_flag = - s->width <= 768 && - s->height <= 576 && - s->mb_width * s->mb_height <= 396 && - s->mb_width * s->mb_height * framerate.num <= 396 * 25 * framerate.den && + s->c.width <= 768 && + s->c.height <= 576 && + s->c.mb_width * s->c.mb_height <= 396 && + s->c.mb_width * s->c.mb_height * framerate.num <= 396 * 25 * framerate.den && framerate.num <= framerate.den * 30 && - s->avctx->me_range && - s->avctx->me_range < 128 && + s->c.avctx->me_range && + s->c.avctx->me_range < 128 && vbv_buffer_size <= 20 && v <= 1856000 / 400 && - s->codec_id == AV_CODEC_ID_MPEG1VIDEO; + s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO; put_bits(&s->pb, 1, constraint_parameter_flag); - ff_write_quant_matrix(&s->pb, s->avctx->intra_matrix); - ff_write_quant_matrix(&s->pb, s->avctx->inter_matrix); + ff_write_quant_matrix(&s->pb, s->c.avctx->intra_matrix); + ff_write_quant_matrix(&s->pb, s->c.avctx->inter_matrix); - if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO) { const AVFrameSideData *side_data; - int width = s->width; - int height = s->height; + int width = s->c.width; + int height = s->c.height; int use_seq_disp_ext; put_header(s, EXT_START_CODE); put_bits(&s->pb, 4, 1); // seq ext - put_bits(&s->pb, 1, s->avctx->profile == AV_PROFILE_MPEG2_422); // escx 1 for 4:2:2 profile + put_bits(&s->pb, 1, s->c.avctx->profile == AV_PROFILE_MPEG2_422); // escx 1 for 4:2:2 profile - put_bits(&s->pb, 3, s->avctx->profile); // profile - put_bits(&s->pb, 4, s->avctx->level); // level + put_bits(&s->pb, 3, s->c.avctx->profile); // profile + put_bits(&s->pb, 4, s->c.avctx->level); // level - put_bits(&s->pb, 1, s->progressive_sequence); - put_bits(&s->pb, 2, s->chroma_format); - put_bits(&s->pb, 2, s->width >> 12); - put_bits(&s->pb, 2, s->height >> 12); + put_bits(&s->pb, 1, s->c.progressive_sequence); + put_bits(&s->pb, 2, s->c.chroma_format); + put_bits(&s->pb, 2, s->c.width >> 12); + put_bits(&s->pb, 2, s->c.height >> 12); put_bits(&s->pb, 12, v >> 18); // bitrate ext put_bits(&s->pb, 1, 1); // marker put_bits(&s->pb, 8, vbv_buffer_size >> 10); // vbv buffer ext - put_bits(&s->pb, 1, s->low_delay); + put_bits(&s->pb, 1, s->c.low_delay); put_bits(&s->pb, 2, mpeg12->frame_rate_ext.num-1); // frame_rate_ext_n put_bits(&s->pb, 5, mpeg12->frame_rate_ext.den-1); // frame_rate_ext_d - side_data = av_frame_get_side_data(s->cur_pic.ptr->f, AV_FRAME_DATA_PANSCAN); + side_data = av_frame_get_side_data(s->c.cur_pic.ptr->f, AV_FRAME_DATA_PANSCAN); if (side_data) { const AVPanScan *pan_scan = (AVPanScan *)side_data->data; if (pan_scan->width && pan_scan->height) { @@ -388,11 +260,11 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) } } - use_seq_disp_ext = (width != s->width || - height != s->height || - s->avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || - s->avctx->color_trc != AVCOL_TRC_UNSPECIFIED || - s->avctx->colorspace != AVCOL_SPC_UNSPECIFIED || + use_seq_disp_ext = (width != s->c.width || + height != s->c.height || + s->c.avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + s->c.avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + s->c.avctx->colorspace != AVCOL_SPC_UNSPECIFIED || mpeg12->video_format != VIDEO_FORMAT_UNSPECIFIED); if (mpeg12->seq_disp_ext == 1 || @@ -401,9 +273,9 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) put_bits(&s->pb, 4, 2); // sequence display extension put_bits(&s->pb, 3, mpeg12->video_format); // video_format put_bits(&s->pb, 1, 1); // colour_description - put_bits(&s->pb, 8, s->avctx->color_primaries); // colour_primaries - put_bits(&s->pb, 8, s->avctx->color_trc); // transfer_characteristics - put_bits(&s->pb, 8, s->avctx->colorspace); // matrix_coefficients + put_bits(&s->pb, 8, s->c.avctx->color_primaries); // colour_primaries + put_bits(&s->pb, 8, s->c.avctx->color_trc); // transfer_characteristics + put_bits(&s->pb, 8, s->c.avctx->colorspace); // matrix_coefficients put_bits(&s->pb, 14, width); // display_horizontal_size put_bits(&s->pb, 1, 1); // marker_bit put_bits(&s->pb, 14, height); // display_vertical_size @@ -416,10 +288,10 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) /* time code: we must convert from the real frame rate to a * fake MPEG frame rate in case of low frame rate */ fps = (framerate.num + framerate.den / 2) / framerate.den; - time_code = s->cur_pic.ptr->coded_picture_number + + time_code = s->c.cur_pic.ptr->coded_picture_number + mpeg12->timecode_frame_start; - mpeg12->gop_picture_number = s->cur_pic.ptr->coded_picture_number; + mpeg12->gop_picture_number = s->c.cur_pic.ptr->coded_picture_number; av_assert0(mpeg12->drop_frame_timecode == !!(mpeg12->tc.flags & AV_TIMECODE_FLAG_DROPFRAME)); if (mpeg12->drop_frame_timecode) @@ -430,12 +302,12 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) put_bits(&s->pb, 1, 1); put_bits(&s->pb, 6, (uint32_t)((time_code / fps) % 60)); put_bits(&s->pb, 6, (uint32_t)((time_code % fps))); - put_bits(&s->pb, 1, !!(s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) || - s->intra_only || !mpeg12->gop_picture_number); + put_bits(&s->pb, 1, !!(s->c.avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) || + mpeg12->mpeg.intra_only || !mpeg12->gop_picture_number); put_bits(&s->pb, 1, 0); // broken link } -static inline void encode_mb_skip_run(MpegEncContext *s, int run) +static inline void encode_mb_skip_run(MPVEncContext *const s, int run) { while (run >= 33) { put_bits(&s->pb, 11, 0x008); @@ -445,57 +317,61 @@ static inline void encode_mb_skip_run(MpegEncContext *s, int run) ff_mpeg12_mbAddrIncrTable[run][0]); } -static av_always_inline void put_qscale(MpegEncContext *s) +static av_always_inline void put_qscale(MPVEncContext *const s) { - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); } -void ff_mpeg1_encode_slice_header(MpegEncContext *s) +void ff_mpeg1_encode_slice_header(MPVEncContext *const s) { - if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->height > 2800) { - put_header(s, SLICE_MIN_START_CODE + (s->mb_y & 127)); + if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO && s->c.height > 2800) { + put_header(s, SLICE_MIN_START_CODE + (s->c.mb_y & 127)); /* slice_vertical_position_extension */ - put_bits(&s->pb, 3, s->mb_y >> 7); + put_bits(&s->pb, 3, s->c.mb_y >> 7); } else { - put_header(s, SLICE_MIN_START_CODE + s->mb_y); + av_assert1(s->c.mb_y <= SLICE_MAX_START_CODE - SLICE_MIN_START_CODE); + put_header(s, SLICE_MIN_START_CODE + s->c.mb_y); } put_qscale(s); /* slice extra information */ put_bits(&s->pb, 1, 0); } -void ff_mpeg1_encode_picture_header(MpegEncContext *s) +static int mpeg1_encode_picture_header(MPVMainEncContext *const m) { - MPEG12EncContext *const mpeg12 = (MPEG12EncContext*)s; + MPEG12EncContext *const mpeg12 = (MPEG12EncContext*)m; + MPVEncContext *const s = &m->s; const AVFrameSideData *side_data; - mpeg1_encode_sequence_header(s); + + put_bits_assume_flushed(&s->pb); + + mpeg1_encode_sequence_header(mpeg12); /* MPEG-1 picture header */ put_header(s, PICTURE_START_CODE); /* temporal reference */ - // RAL: s->picture_number instead of s->fake_picture_number put_bits(&s->pb, 10, (s->picture_number - mpeg12->gop_picture_number) & 0x3ff); - put_bits(&s->pb, 3, s->pict_type); + put_bits(&s->pb, 3, s->c.pict_type); - s->vbv_delay_pos = put_bytes_count(&s->pb, 0); + m->vbv_delay_pos = put_bytes_count(&s->pb, 0); put_bits(&s->pb, 16, 0xFFFF); /* vbv_delay */ // RAL: Forward f_code also needed for B-frames - if (s->pict_type == AV_PICTURE_TYPE_P || - s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_P || + s->c.pict_type == AV_PICTURE_TYPE_B) { put_bits(&s->pb, 1, 0); /* half pel coordinates */ - if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO) + if (s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO) put_bits(&s->pb, 3, s->f_code); /* forward_f_code */ else put_bits(&s->pb, 3, 7); /* forward_f_code */ } // RAL: Backward f_code necessary for B-frames - if (s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) { put_bits(&s->pb, 1, 0); /* half pel coordinates */ - if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO) + if (s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO) put_bits(&s->pb, 3, s->b_code); /* backward_f_code */ else put_bits(&s->pb, 3, 7); /* backward_f_code */ @@ -503,45 +379,45 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s) put_bits(&s->pb, 1, 0); /* extra bit picture */ - s->frame_pred_frame_dct = 1; - if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + s->c.frame_pred_frame_dct = 1; + if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO) { put_header(s, EXT_START_CODE); put_bits(&s->pb, 4, 8); /* pic ext */ - if (s->pict_type == AV_PICTURE_TYPE_P || - s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_P || + s->c.pict_type == AV_PICTURE_TYPE_B) { put_bits(&s->pb, 4, s->f_code); put_bits(&s->pb, 4, s->f_code); } else { put_bits(&s->pb, 8, 255); } - if (s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) { put_bits(&s->pb, 4, s->b_code); put_bits(&s->pb, 4, s->b_code); } else { put_bits(&s->pb, 8, 255); } - put_bits(&s->pb, 2, s->intra_dc_precision); + put_bits(&s->pb, 2, s->c.intra_dc_precision); - av_assert0(s->picture_structure == PICT_FRAME); - put_bits(&s->pb, 2, s->picture_structure); - if (s->progressive_sequence) + av_assert0(s->c.picture_structure == PICT_FRAME); + put_bits(&s->pb, 2, s->c.picture_structure); + if (s->c.progressive_sequence) put_bits(&s->pb, 1, 0); /* no repeat */ else - put_bits(&s->pb, 1, !!(s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); + put_bits(&s->pb, 1, !!(s->c.cur_pic.ptr->f->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); /* XXX: optimize the generation of this flag with entropy measures */ - s->frame_pred_frame_dct = s->progressive_sequence; + s->c.frame_pred_frame_dct = s->c.progressive_sequence; - put_bits(&s->pb, 1, s->frame_pred_frame_dct); - put_bits(&s->pb, 1, s->concealment_motion_vectors); - put_bits(&s->pb, 1, s->q_scale_type); - put_bits(&s->pb, 1, s->intra_vlc_format); - put_bits(&s->pb, 1, s->alternate_scan); - put_bits(&s->pb, 1, s->repeat_first_field); - s->progressive_frame = s->progressive_sequence; + put_bits(&s->pb, 1, s->c.frame_pred_frame_dct); + put_bits(&s->pb, 1, s->c.concealment_motion_vectors); + put_bits(&s->pb, 1, s->c.q_scale_type); + put_bits(&s->pb, 1, s->c.intra_vlc_format); + put_bits(&s->pb, 1, s->c.alternate_scan); + put_bits(&s->pb, 1, s->c.repeat_first_field); + s->c.progressive_frame = s->c.progressive_sequence; /* chroma_420_type */ - put_bits(&s->pb, 1, s->chroma_format == - CHROMA_420 ? s->progressive_frame : 0); - put_bits(&s->pb, 1, s->progressive_frame); + put_bits(&s->pb, 1, s->c.chroma_format == + CHROMA_420 ? s->c.progressive_frame : 0); + put_bits(&s->pb, 1, s->c.progressive_frame); put_bits(&s->pb, 1, 0); /* composite_display_flag */ } if (mpeg12->scan_offset) { @@ -551,7 +427,7 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s) for (i = 0; i < sizeof(svcd_scan_offset_placeholder); i++) put_bits(&s->pb, 8, svcd_scan_offset_placeholder[i]); } - side_data = av_frame_get_side_data(s->cur_pic.ptr->f, + side_data = av_frame_get_side_data(s->c.cur_pic.ptr->f, AV_FRAME_DATA_STEREO3D); if (side_data) { const AVStereo3D *stereo = (AVStereo3D *)side_data->data; @@ -577,67 +453,61 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s) if (fpa_type != 0) { put_header(s, USER_START_CODE); - put_bits(&s->pb, 8, 'J'); // S3D_video_format_signaling_identifier - put_bits(&s->pb, 8, 'P'); - put_bits(&s->pb, 8, '3'); - put_bits(&s->pb, 8, 'D'); + // S3D_video_format_signaling_identifier + put_bits32(&s->pb, MKBETAG('J','P','3','D')); put_bits(&s->pb, 8, 0x03); // S3D_video_format_length put_bits(&s->pb, 1, 1); // reserved_bit put_bits(&s->pb, 7, fpa_type); // S3D_video_format_type - put_bits(&s->pb, 8, 0x04); // reserved_data[0] - put_bits(&s->pb, 8, 0xFF); // reserved_data[1] + put_bits(&s->pb, 16, 0x04FF); // reserved_data } } if (CONFIG_MPEG2VIDEO_ENCODER && mpeg12->a53_cc) { - side_data = av_frame_get_side_data(s->cur_pic.ptr->f, + side_data = av_frame_get_side_data(s->c.cur_pic.ptr->f, AV_FRAME_DATA_A53_CC); if (side_data) { if (side_data->size <= A53_MAX_CC_COUNT * 3 && side_data->size % 3 == 0) { - int i = 0; - put_header (s, USER_START_CODE); - put_bits(&s->pb, 8, 'G'); // user_identifier - put_bits(&s->pb, 8, 'A'); - put_bits(&s->pb, 8, '9'); - put_bits(&s->pb, 8, '4'); + put_bits32(&s->pb, MKBETAG('G','A','9','4')); // user_identifier put_bits(&s->pb, 8, 3); // user_data_type_code put_bits(&s->pb, 8, (side_data->size / 3 & A53_MAX_CC_COUNT) | 0x40); // flags, cc_count put_bits(&s->pb, 8, 0xff); // em_data - for (i = 0; i < side_data->size; i++) + for (int i = 0; i < side_data->size; i++) put_bits(&s->pb, 8, side_data->data[i]); put_bits(&s->pb, 8, 0xff); // marker_bits } else { - av_log(s->avctx, AV_LOG_WARNING, - "Closed Caption size (%"SIZE_SPECIFIER") can not exceed " + av_log(s->c.avctx, AV_LOG_WARNING, + "Closed Caption size (%zu) can not exceed " "93 bytes and must be a multiple of 3\n", side_data->size); } } } - s->mb_y = 0; + s->c.mb_y = 0; ff_mpeg1_encode_slice_header(s); + + return 0; } -static inline void put_mb_modes(MpegEncContext *s, int n, int bits, +static inline void put_mb_modes(MPVEncContext *const s, int n, int bits, int has_mv, int field_motion) { put_bits(&s->pb, n, bits); - if (!s->frame_pred_frame_dct) { + if (!s->c.frame_pred_frame_dct) { if (has_mv) /* motion_type: frame/field */ put_bits(&s->pb, 2, 2 - field_motion); - put_bits(&s->pb, 1, s->interlaced_dct); + put_bits(&s->pb, 1, s->c.interlaced_dct); } } // RAL: Parameter added: f_or_b_code -static void mpeg1_encode_motion(MpegEncContext *s, int val, int f_or_b_code) +static void mpeg1_encode_motion(MPVEncContext *const s, int val, int f_or_b_code) { if (val == 0) { /* zero vector, corresponds to ff_mpeg12_mbMotionVectorTable[0] */ @@ -674,7 +544,7 @@ static void mpeg1_encode_motion(MpegEncContext *s, int val, int f_or_b_code) } } -static inline void encode_dc(MpegEncContext *s, int diff, int component) +static inline void encode_dc(MPVEncContext *const s, int diff, int component) { unsigned int diff_u = diff + 255; if (diff_u >= 511) { @@ -708,23 +578,23 @@ static inline void encode_dc(MpegEncContext *s, int diff, int component) } } -static void mpeg1_encode_block(MpegEncContext *s, const int16_t *block, int n) +static void mpeg1_encode_block(MPVEncContext *const s, const int16_t block[], int n) { int alevel, level, last_non_zero, dc, diff, i, j, run, last_index, sign; int code, component; const uint16_t (*table_vlc)[2] = ff_mpeg1_vlc_table; - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; /* DC coef */ - if (s->mb_intra) { + if (s->c.mb_intra) { component = (n <= 3 ? 0 : (n & 1) + 1); dc = block[0]; /* overflow is impossible */ diff = dc - s->last_dc[component]; encode_dc(s, diff, component); s->last_dc[component] = dc; i = 1; - if (s->intra_vlc_format) + if (s->c.intra_vlc_format) table_vlc = ff_mpeg2_vlc_table; } else { /* encode the first coefficient: needs to be done here because @@ -745,7 +615,7 @@ static void mpeg1_encode_block(MpegEncContext *s, const int16_t *block, int n) last_non_zero = i - 1; for (; i <= last_index; i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; level = block[j]; next_coef: @@ -763,13 +633,12 @@ next_coef: put_bits(&s->pb, table_vlc[code][1] + 1, (table_vlc[code][0] << 1) + sign); } else { - /* Escape seems to be pretty rare <5% so I do not optimize it; - * the following value is the common escape value for both - * possible tables (i.e. table_vlc[111]). */ - put_bits(&s->pb, 6, 0x01); + /* Escape seems to be pretty rare <5% so I do not optimize it. + * The following encodes run together with the common escape + * value of both tables 000001b. */ + put_bits(&s->pb, 6 + 6, 0x01 << 6 | run); /* escape: only clip in this case */ - put_bits(&s->pb, 6, run); - if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO) { + if (s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO) { if (alevel < 128) { put_sbits(&s->pb, 8, level); } else { @@ -789,55 +658,55 @@ next_coef: put_bits(&s->pb, table_vlc[112][1], table_vlc[112][0]); } -static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, +static av_always_inline void mpeg1_encode_mb_internal(MPVEncContext *const s, const int16_t block[8][64], int motion_x, int motion_y, int mb_block_count, int chroma_y_shift) { /* MPEG-1 is always 420. */ -#define IS_MPEG1(s) (chroma_y_shift == 1 && (s)->codec_id == AV_CODEC_ID_MPEG1VIDEO) +#define IS_MPEG1(s) (chroma_y_shift == 1 && (s)->c.codec_id == AV_CODEC_ID_MPEG1VIDEO) int i, cbp; - const int mb_x = s->mb_x; - const int mb_y = s->mb_y; - const int first_mb = mb_x == s->resync_mb_x && mb_y == s->resync_mb_y; + const int mb_x = s->c.mb_x; + const int mb_y = s->c.mb_y; + const int first_mb = mb_x == s->c.resync_mb_x && mb_y == s->c.resync_mb_y; /* compute cbp */ cbp = 0; for (i = 0; i < mb_block_count; i++) - if (s->block_last_index[i] >= 0) + if (s->c.block_last_index[i] >= 0) cbp |= 1 << (mb_block_count - 1 - i); - if (cbp == 0 && !first_mb && s->mv_type == MV_TYPE_16X16 && - (mb_x != s->mb_width - 1 || - (mb_y != s->end_mb_y - 1 && IS_MPEG1(s))) && - ((s->pict_type == AV_PICTURE_TYPE_P && (motion_x | motion_y) == 0) || - (s->pict_type == AV_PICTURE_TYPE_B && s->mv_dir == s->last_mv_dir && - (((s->mv_dir & MV_DIR_FORWARD) - ? ((s->mv[0][0][0] - s->last_mv[0][0][0]) | - (s->mv[0][0][1] - s->last_mv[0][0][1])) : 0) | - ((s->mv_dir & MV_DIR_BACKWARD) - ? ((s->mv[1][0][0] - s->last_mv[1][0][0]) | - (s->mv[1][0][1] - s->last_mv[1][0][1])) : 0)) == 0))) { + if (cbp == 0 && !first_mb && s->c.mv_type == MV_TYPE_16X16 && + (mb_x != s->c.mb_width - 1 || + (mb_y != s->c.end_mb_y - 1 && IS_MPEG1(s))) && + ((s->c.pict_type == AV_PICTURE_TYPE_P && (motion_x | motion_y) == 0) || + (s->c.pict_type == AV_PICTURE_TYPE_B && s->c.mv_dir == s->last_mv_dir && + (((s->c.mv_dir & MV_DIR_FORWARD) + ? ((s->c.mv[0][0][0] - s->c.last_mv[0][0][0]) | + (s->c.mv[0][0][1] - s->c.last_mv[0][0][1])) : 0) | + ((s->c.mv_dir & MV_DIR_BACKWARD) + ? ((s->c.mv[1][0][0] - s->c.last_mv[1][0][0]) | + (s->c.mv[1][0][1] - s->c.last_mv[1][0][1])) : 0)) == 0))) { s->mb_skip_run++; - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; s->misc_bits++; s->last_bits++; - if (s->pict_type == AV_PICTURE_TYPE_P) { - s->last_mv[0][0][0] = - s->last_mv[0][0][1] = - s->last_mv[0][1][0] = - s->last_mv[0][1][1] = 0; + if (s->c.pict_type == AV_PICTURE_TYPE_P) { + s->c.last_mv[0][0][0] = + s->c.last_mv[0][0][1] = + s->c.last_mv[0][1][0] = + s->c.last_mv[0][1][1] = 0; } } else { if (first_mb) { av_assert0(s->mb_skip_run == 0); - encode_mb_skip_run(s, s->mb_x); + encode_mb_skip_run(s, s->c.mb_x); } else { encode_mb_skip_run(s, s->mb_skip_run); } - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { if (s->dquant && cbp) { /* macroblock_type: macroblock_quant = 1 */ put_mb_modes(s, 2, 1, 0, 0); @@ -845,23 +714,23 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, } else { /* macroblock_type: macroblock_quant = 0 */ put_mb_modes(s, 1, 1, 0, 0); - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; } s->misc_bits += get_bits_diff(s); s->i_count++; - } else if (s->mb_intra) { + } else if (s->c.mb_intra) { if (s->dquant && cbp) { put_mb_modes(s, 6, 0x01, 0, 0); put_qscale(s); } else { put_mb_modes(s, 5, 0x03, 0, 0); - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; } s->misc_bits += get_bits_diff(s); s->i_count++; - memset(s->last_mv, 0, sizeof(s->last_mv)); - } else if (s->pict_type == AV_PICTURE_TYPE_P) { - if (s->mv_type == MV_TYPE_16X16) { + memset(s->c.last_mv, 0, sizeof(s->c.last_mv)); + } else if (s->c.pict_type == AV_PICTURE_TYPE_P) { + if (s->c.mv_type == MV_TYPE_16X16) { if (cbp != 0) { if ((motion_x | motion_y) == 0) { if (s->dquant) { @@ -883,34 +752,34 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, s->misc_bits += get_bits_diff(s); // RAL: f_code parameter added mpeg1_encode_motion(s, - motion_x - s->last_mv[0][0][0], + motion_x - s->c.last_mv[0][0][0], s->f_code); // RAL: f_code parameter added mpeg1_encode_motion(s, - motion_y - s->last_mv[0][0][1], + motion_y - s->c.last_mv[0][0][1], s->f_code); s->mv_bits += get_bits_diff(s); } } else { put_bits(&s->pb, 3, 1); /* motion only */ - if (!s->frame_pred_frame_dct) + if (!s->c.frame_pred_frame_dct) put_bits(&s->pb, 2, 2); /* motion_type: frame */ s->misc_bits += get_bits_diff(s); // RAL: f_code parameter added mpeg1_encode_motion(s, - motion_x - s->last_mv[0][0][0], + motion_x - s->c.last_mv[0][0][0], s->f_code); // RAL: f_code parameter added mpeg1_encode_motion(s, - motion_y - s->last_mv[0][0][1], + motion_y - s->c.last_mv[0][0][1], s->f_code); - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; s->mv_bits += get_bits_diff(s); } - s->last_mv[0][1][0] = s->last_mv[0][0][0] = motion_x; - s->last_mv[0][1][1] = s->last_mv[0][0][1] = motion_y; + s->c.last_mv[0][1][0] = s->c.last_mv[0][0][0] = motion_x; + s->c.last_mv[0][1][1] = s->c.last_mv[0][0][1] = motion_y; } else { - av_assert2(!s->frame_pred_frame_dct && s->mv_type == MV_TYPE_FIELD); + av_assert2(!s->c.frame_pred_frame_dct && s->c.mv_type == MV_TYPE_FIELD); if (cbp) { if (s->dquant) { @@ -922,19 +791,19 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, } else { put_bits(&s->pb, 3, 1); /* motion only */ put_bits(&s->pb, 2, 1); /* motion_type: field */ - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; } s->misc_bits += get_bits_diff(s); for (i = 0; i < 2; i++) { - put_bits(&s->pb, 1, s->field_select[0][i]); + put_bits(&s->pb, 1, s->c.field_select[0][i]); mpeg1_encode_motion(s, - s->mv[0][i][0] - s->last_mv[0][i][0], + s->c.mv[0][i][0] - s->c.last_mv[0][i][0], s->f_code); mpeg1_encode_motion(s, - s->mv[0][i][1] - (s->last_mv[0][i][1] >> 1), + s->c.mv[0][i][1] - (s->c.last_mv[0][i][1] >> 1), s->f_code); - s->last_mv[0][i][0] = s->mv[0][i][0]; - s->last_mv[0][i][1] = 2 * s->mv[0][i][1]; + s->c.last_mv[0][i][0] = s->c.mv[0][i][0]; + s->c.last_mv[0][i][1] = 2 * s->c.mv[0][i][1]; } s->mv_bits += get_bits_diff(s); } @@ -951,91 +820,91 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, } } } else { - if (s->mv_type == MV_TYPE_16X16) { + if (s->c.mv_type == MV_TYPE_16X16) { if (cbp) { // With coded bloc pattern if (s->dquant) { - if (s->mv_dir == MV_DIR_FORWARD) + if (s->c.mv_dir == MV_DIR_FORWARD) put_mb_modes(s, 6, 3, 1, 0); else - put_mb_modes(s, 8 - s->mv_dir, 2, 1, 0); + put_mb_modes(s, 8 - s->c.mv_dir, 2, 1, 0); put_qscale(s); } else { - put_mb_modes(s, 5 - s->mv_dir, 3, 1, 0); + put_mb_modes(s, 5 - s->c.mv_dir, 3, 1, 0); } } else { // No coded bloc pattern - put_bits(&s->pb, 5 - s->mv_dir, 2); - if (!s->frame_pred_frame_dct) + put_bits(&s->pb, 5 - s->c.mv_dir, 2); + if (!s->c.frame_pred_frame_dct) put_bits(&s->pb, 2, 2); /* motion_type: frame */ - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; } s->misc_bits += get_bits_diff(s); - if (s->mv_dir & MV_DIR_FORWARD) { + if (s->c.mv_dir & MV_DIR_FORWARD) { mpeg1_encode_motion(s, - s->mv[0][0][0] - s->last_mv[0][0][0], + s->c.mv[0][0][0] - s->c.last_mv[0][0][0], s->f_code); mpeg1_encode_motion(s, - s->mv[0][0][1] - s->last_mv[0][0][1], + s->c.mv[0][0][1] - s->c.last_mv[0][0][1], s->f_code); - s->last_mv[0][0][0] = - s->last_mv[0][1][0] = s->mv[0][0][0]; - s->last_mv[0][0][1] = - s->last_mv[0][1][1] = s->mv[0][0][1]; + s->c.last_mv[0][0][0] = + s->c.last_mv[0][1][0] = s->c.mv[0][0][0]; + s->c.last_mv[0][0][1] = + s->c.last_mv[0][1][1] = s->c.mv[0][0][1]; } - if (s->mv_dir & MV_DIR_BACKWARD) { + if (s->c.mv_dir & MV_DIR_BACKWARD) { mpeg1_encode_motion(s, - s->mv[1][0][0] - s->last_mv[1][0][0], + s->c.mv[1][0][0] - s->c.last_mv[1][0][0], s->b_code); mpeg1_encode_motion(s, - s->mv[1][0][1] - s->last_mv[1][0][1], + s->c.mv[1][0][1] - s->c.last_mv[1][0][1], s->b_code); - s->last_mv[1][0][0] = - s->last_mv[1][1][0] = s->mv[1][0][0]; - s->last_mv[1][0][1] = - s->last_mv[1][1][1] = s->mv[1][0][1]; + s->c.last_mv[1][0][0] = + s->c.last_mv[1][1][0] = s->c.mv[1][0][0]; + s->c.last_mv[1][0][1] = + s->c.last_mv[1][1][1] = s->c.mv[1][0][1]; } } else { - av_assert2(s->mv_type == MV_TYPE_FIELD); - av_assert2(!s->frame_pred_frame_dct); + av_assert2(s->c.mv_type == MV_TYPE_FIELD); + av_assert2(!s->c.frame_pred_frame_dct); if (cbp) { // With coded bloc pattern if (s->dquant) { - if (s->mv_dir == MV_DIR_FORWARD) + if (s->c.mv_dir == MV_DIR_FORWARD) put_mb_modes(s, 6, 3, 1, 1); else - put_mb_modes(s, 8 - s->mv_dir, 2, 1, 1); + put_mb_modes(s, 8 - s->c.mv_dir, 2, 1, 1); put_qscale(s); } else { - put_mb_modes(s, 5 - s->mv_dir, 3, 1, 1); + put_mb_modes(s, 5 - s->c.mv_dir, 3, 1, 1); } } else { // No coded bloc pattern - put_bits(&s->pb, 5 - s->mv_dir, 2); + put_bits(&s->pb, 5 - s->c.mv_dir, 2); put_bits(&s->pb, 2, 1); /* motion_type: field */ - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; } s->misc_bits += get_bits_diff(s); - if (s->mv_dir & MV_DIR_FORWARD) { + if (s->c.mv_dir & MV_DIR_FORWARD) { for (i = 0; i < 2; i++) { - put_bits(&s->pb, 1, s->field_select[0][i]); + put_bits(&s->pb, 1, s->c.field_select[0][i]); mpeg1_encode_motion(s, - s->mv[0][i][0] - s->last_mv[0][i][0], + s->c.mv[0][i][0] - s->c.last_mv[0][i][0], s->f_code); mpeg1_encode_motion(s, - s->mv[0][i][1] - (s->last_mv[0][i][1] >> 1), + s->c.mv[0][i][1] - (s->c.last_mv[0][i][1] >> 1), s->f_code); - s->last_mv[0][i][0] = s->mv[0][i][0]; - s->last_mv[0][i][1] = s->mv[0][i][1] * 2; + s->c.last_mv[0][i][0] = s->c.mv[0][i][0]; + s->c.last_mv[0][i][1] = s->c.mv[0][i][1] * 2; } } - if (s->mv_dir & MV_DIR_BACKWARD) { + if (s->c.mv_dir & MV_DIR_BACKWARD) { for (i = 0; i < 2; i++) { - put_bits(&s->pb, 1, s->field_select[1][i]); + put_bits(&s->pb, 1, s->c.field_select[1][i]); mpeg1_encode_motion(s, - s->mv[1][i][0] - s->last_mv[1][i][0], + s->c.mv[1][i][0] - s->c.last_mv[1][i][0], s->b_code); mpeg1_encode_motion(s, - s->mv[1][i][1] - (s->last_mv[1][i][1] >> 1), + s->c.mv[1][i][1] - (s->c.last_mv[1][i][1] >> 1), s->b_code); - s->last_mv[1][i][0] = s->mv[1][i][0]; - s->last_mv[1][i][1] = s->mv[1][i][1] * 2; + s->c.last_mv[1][i][0] = s->c.mv[1][i][0]; + s->c.last_mv[1][i][1] = s->c.mv[1][i][1] * 2; } } } @@ -1057,17 +926,19 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, if (cbp & (1 << (mb_block_count - 1 - i))) mpeg1_encode_block(s, block[i], i); s->mb_skip_run = 0; - if (s->mb_intra) + if (s->c.mb_intra) s->i_tex_bits += get_bits_diff(s); else s->p_tex_bits += get_bits_diff(s); } } -void ff_mpeg1_encode_mb(MpegEncContext *s, int16_t block[8][64], - int motion_x, int motion_y) +static void mpeg12_encode_mb(MPVEncContext *const s, int16_t block[][64], + int motion_x, int motion_y) { - if (s->chroma_format == CHROMA_420) + if (!s->c.mb_intra) + s->last_dc[0] = s->last_dc[1] = s->last_dc[2] = 128 << s->c.intra_dc_precision; + if (s->c.chroma_format == CHROMA_420) mpeg1_encode_mb_internal(s, block, motion_x, motion_y, 6, 1); else mpeg1_encode_mb_internal(s, block, motion_x, motion_y, 8, 0); @@ -1138,24 +1009,152 @@ static av_cold void mpeg12_encode_init_static(void) fcode_tab[mv + MAX_MV] = f_code; } -av_cold void ff_mpeg1_encode_init(MpegEncContext *s) +static av_cold int find_frame_rate_index(AVCodecContext *avctx, MPEG12EncContext *mpeg12) +{ + AVRational bestq = (AVRational) {0, 0}; + AVRational ext; + AVRational target = av_inv_q(avctx->time_base); + + for (int i = 1; i < 14; i++) { + if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL && + i >= 9) + break; + + for (ext.num = 1; ext.num <= 4; ext.num++) { + for (ext.den = 1; ext.den <= 32; ext.den++) { + AVRational q = av_mul_q(ext, ff_mpeg12_frame_rate_tab[i]); + + if (avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO && (ext.den!=1 || ext.num!=1)) + continue; + if (av_gcd(ext.den, ext.num) != 1) + continue; + + if ( bestq.num==0 + || av_nearer_q(target, bestq, q) < 0 + || ext.num==1 && ext.den==1 && av_nearer_q(target, bestq, q) == 0) { + bestq = q; + mpeg12->frame_rate_index = i; + mpeg12->frame_rate_ext.num = ext.num; + mpeg12->frame_rate_ext.den = ext.den; + } + } + } + } + + if (av_cmp_q(target, bestq)) + return -1; + else + return 0; +} + +static av_cold int encode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; + MPEG12EncContext *const mpeg12 = avctx->priv_data; + MPVMainEncContext *const m = &mpeg12->mpeg; + MPVEncContext *const s = &m->s; + int ret; + int max_size = avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ? 16383 : 4095; - s->y_dc_scale_table = - s->c_dc_scale_table = ff_mpeg12_dc_scale_table[s->intra_dc_precision]; + if (avctx->width > max_size || avctx->height > max_size) { + av_log(avctx, AV_LOG_ERROR, "%s does not support resolutions above %dx%d\n", + CONFIG_SMALL ? avctx->codec->name : avctx->codec->long_name, + max_size, max_size); + return AVERROR(EINVAL); + } + if ((avctx->width & 0xFFF) == 0 && (avctx->height & 0xFFF) == 1) { + av_log(avctx, AV_LOG_ERROR, "Width / Height is invalid for MPEG2\n"); + return AVERROR(EINVAL); + } + + if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { + if ((avctx->width & 0xFFF) == 0 || (avctx->height & 0xFFF) == 0) { + av_log(avctx, AV_LOG_ERROR, "Width or Height are not allowed to be multiples of 4096\n" + "add '-strict %d' if you want to use them anyway.\n", FF_COMPLIANCE_UNOFFICIAL); + return AVERROR(EINVAL); + } + } + + if (s->c.q_scale_type == 1) { + if (avctx->qmax > 28) { + av_log(avctx, AV_LOG_ERROR, + "non linear quant only supports qmax <= 28 currently\n"); + return AVERROR_PATCHWELCOME; + } + } + + if (avctx->profile == AV_PROFILE_UNKNOWN) { + if (avctx->level != AV_LEVEL_UNKNOWN) { + av_log(avctx, AV_LOG_ERROR, "Set profile and level\n"); + return AVERROR(EINVAL); + } + /* Main or 4:2:2 */ + avctx->profile = avctx->pix_fmt == AV_PIX_FMT_YUV420P ? AV_PROFILE_MPEG2_MAIN + : AV_PROFILE_MPEG2_422; + } + if (avctx->level == AV_LEVEL_UNKNOWN) { + if (avctx->profile == AV_PROFILE_MPEG2_422) { /* 4:2:2 */ + if (avctx->width <= 720 && avctx->height <= 608) + avctx->level = 5; /* Main */ + else + avctx->level = 2; /* High */ + } else { + if (avctx->profile != AV_PROFILE_MPEG2_HIGH && + avctx->pix_fmt != AV_PIX_FMT_YUV420P) { + av_log(avctx, AV_LOG_ERROR, + "Only High(1) and 4:2:2(0) profiles support 4:2:2 color sampling\n"); + return AVERROR(EINVAL); + } + if (avctx->width <= 720 && avctx->height <= 576) + avctx->level = 8; /* Main */ + else if (avctx->width <= 1440) + avctx->level = 6; /* High 1440 */ + else + avctx->level = 4; /* High */ + } + } + + m->encode_picture_header = mpeg1_encode_picture_header; + s->encode_mb = mpeg12_encode_mb; s->me.mv_penalty = mv_penalty; - s->fcode_tab = fcode_tab; - if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO) { + m->fcode_tab = fcode_tab + MAX_MV; + if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) { s->min_qcoeff = -255; s->max_qcoeff = 255; } else { s->min_qcoeff = -2047; s->max_qcoeff = 2047; s->mpeg_quant = 1; +#if FF_API_INTRA_DC_PRECISION + if (s->c.intra_dc_precision < 0) { +FF_DISABLE_DEPRECATION_WARNINGS + s->c.intra_dc_precision = avctx->intra_dc_precision; +FF_ENABLE_DEPRECATION_WARNINGS + // workaround some differences between how applications specify dc precision + if (s->c.intra_dc_precision < 0) { + s->c.intra_dc_precision += 8; + } else if (s->c.intra_dc_precision >= 8) + s->c.intra_dc_precision -= 8; + + if (s->c.intra_dc_precision < 0) { + av_log(avctx, AV_LOG_ERROR, + "intra dc precision must be positive, note some applications use" + " 0 and some 8 as base meaning 8bit, the value must not be smaller than that\n"); + return AVERROR(EINVAL); + } + + if (s->c.intra_dc_precision > 3) { + av_log(avctx, AV_LOG_ERROR, "intra dc precision too large\n"); + return AVERROR(EINVAL); + } + } +#endif } - if (s->intra_vlc_format) { + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_mpeg12_dc_scale_table[s->c.intra_dc_precision]; + + if (s->c.intra_vlc_format) { s->intra_ac_vlc_length = s->intra_ac_vlc_last_length = uni_mpeg2_ac_vlc_len; } else { @@ -1165,7 +1164,77 @@ av_cold void ff_mpeg1_encode_init(MpegEncContext *s) s->inter_ac_vlc_length = s->inter_ac_vlc_last_length = uni_mpeg1_ac_vlc_len; + ret = ff_mpv_encode_init(avctx); + if (ret < 0) + return ret; + + if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && + s->c.thread_context[s->c.slice_context_count - 1]->start_mb_y > + SLICE_MAX_START_CODE - SLICE_MIN_START_CODE) { + // MPEG-1 slices must not start at a MB row number that would make + // their start code > SLICE_MAX_START_CODE. So make the last slice + // bigger if needed and evenly distribute the first 174 rows. + static_assert(MAX_THREADS <= 1 + SLICE_MAX_START_CODE - SLICE_MIN_START_CODE, + "With more than 175 slice contexts, we have to handle " + "the case in which there is no work to do for some " + "slice contexts."); + const int mb_height = SLICE_MAX_START_CODE - SLICE_MIN_START_CODE; + const int nb_slices = s->c.slice_context_count - 1; + + s->c.thread_context[nb_slices]->start_mb_y = mb_height; + + av_assert1(nb_slices >= 1); + for (int i = 0; i < nb_slices; i++) { + s->c.thread_context[i]->start_mb_y = + (mb_height * (i ) + nb_slices / 2) / nb_slices; + s->c.thread_context[i]->end_mb_y = + (mb_height * (i + 1) + nb_slices / 2) / nb_slices; + } + } + + if (find_frame_rate_index(avctx, mpeg12) < 0) { + if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { + av_log(avctx, AV_LOG_ERROR, "MPEG-1/2 does not support %d/%d fps\n", + avctx->time_base.den, avctx->time_base.num); + return AVERROR(EINVAL); + } else { + av_log(avctx, AV_LOG_INFO, + "MPEG-1/2 does not support %d/%d fps, there may be AV sync issues\n", + avctx->time_base.den, avctx->time_base.num); + } + } + + if (avctx->rc_max_rate && + avctx->rc_min_rate == avctx->rc_max_rate && + 90000LL * (avctx->rc_buffer_size - 1) > + avctx->rc_max_rate * 0xFFFFLL) { + av_log(avctx, AV_LOG_INFO, + "Warning vbv_delay will be set to 0xFFFF (=VBR) as the " + "specified vbv buffer is too large for the given bitrate!\n"); + } + + if (mpeg12->drop_frame_timecode) + mpeg12->tc.flags |= AV_TIMECODE_FLAG_DROPFRAME; + if (mpeg12->drop_frame_timecode && mpeg12->frame_rate_index != 4) { + av_log(avctx, AV_LOG_ERROR, + "Drop frame time code only allowed with 1001/30000 fps\n"); + return AVERROR(EINVAL); + } + + if (mpeg12->tc_opt_str) { + AVRational rate = ff_mpeg12_frame_rate_tab[mpeg12->frame_rate_index]; + int ret = av_timecode_init_from_string(&mpeg12->tc, rate, mpeg12->tc_opt_str, avctx); + if (ret < 0) + return ret; + mpeg12->drop_frame_timecode = !!(mpeg12->tc.flags & AV_TIMECODE_FLAG_DROPFRAME); + mpeg12->timecode_frame_start = mpeg12->tc.start; + } else { + mpeg12->timecode_frame_start = 0; // default is -1 + } + ff_thread_once(&init_static_once, mpeg12_encode_init_static); + + return 0; } #define OFFSET(x) offsetof(MPEG12EncContext, x) @@ -1190,10 +1259,15 @@ static const AVOption mpeg1_options[] = { static const AVOption mpeg2_options[] = { COMMON_OPTS +#if FF_API_INTRA_DC_PRECISION + { "intra_dc_precision", "Precision of the DC coefficient - 8", FF_MPV_OFFSET(c.intra_dc_precision), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 3, VE }, +#else + { "intra_dc_precision", "Precision of the DC coefficient - 8", FF_MPV_OFFSET(c.intra_dc_precision), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 3, VE }, +#endif { "intra_vlc", "Use MPEG-2 intra VLC table.", - FF_MPV_OFFSET(intra_vlc_format), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "non_linear_quant", "Use nonlinear quantizer.", FF_MPV_OFFSET(q_scale_type), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "alternate_scan", "Enable alternate scantable.", FF_MPV_OFFSET(alternate_scan), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + FF_MPV_OFFSET(c.intra_vlc_format), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "non_linear_quant", "Use nonlinear quantizer.", FF_MPV_OFFSET(c.q_scale_type), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "alternate_scan", "Enable alternate scantable.", FF_MPV_OFFSET(c.alternate_scan), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, { "seq_disp_ext", "Write sequence_display_extension blocks.", OFFSET(seq_disp_ext), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE, .unit = "seq_disp_ext" }, { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, VE, .unit = "seq_disp_ext" }, @@ -1238,11 +1312,11 @@ const FFCodec ff_mpeg1video_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, - .p.supported_framerates = ff_mpeg12_frame_rate_tab + 1, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_FRAMERATES_ARRAY(ff_mpeg12_frame_rate_tab + 1), + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, - .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .p.priv_class = &mpeg1_class, @@ -1257,12 +1331,11 @@ const FFCodec ff_mpeg2video_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, - .p.supported_framerates = ff_mpeg2_frame_rate_tab, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_YUV422P, - AV_PIX_FMT_NONE }, + CODEC_FRAMERATES_ARRAY(ff_mpeg2_frame_rate_tab), + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P), .color_ranges = AVCOL_RANGE_MPEG, - .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .p.priv_class = &mpeg2_class, diff --git a/libavcodec/mpeg12enc.h b/libavcodec/mpeg12enc.h index 0b35af8a3..89ac6a064 100644 --- a/libavcodec/mpeg12enc.h +++ b/libavcodec/mpeg12enc.h @@ -22,14 +22,16 @@ #ifndef AVCODEC_MPEG12ENC_H #define AVCODEC_MPEG12ENC_H -#include +#include "mpegvideoenc.h" -#include "mpegvideo.h" +void ff_mpeg1_encode_slice_header(MPVEncContext *s); -void ff_mpeg1_encode_picture_header(MpegEncContext *s); -void ff_mpeg1_encode_mb(MpegEncContext *s, int16_t block[8][64], - int motion_x, int motion_y); -void ff_mpeg1_encode_init(MpegEncContext *s); -void ff_mpeg1_encode_slice_header(MpegEncContext *s); +static inline void ff_mpeg1_clean_buffers(MPVEncContext *s) +{ + s->last_dc[0] = 128 << s->c.intra_dc_precision; + s->last_dc[1] = s->last_dc[0]; + s->last_dc[2] = s->last_dc[0]; + memset(s->c.last_mv, 0, sizeof(s->c.last_mv)); +} #endif /* AVCODEC_MPEG12ENC_H */ diff --git a/libavcodec/mpeg4audio_sample_rates.h b/libavcodec/mpeg4audio_sample_rates.h index 0b8caa6d7..a847a9799 100644 --- a/libavcodec/mpeg4audio_sample_rates.h +++ b/libavcodec/mpeg4audio_sample_rates.h @@ -23,6 +23,10 @@ #ifndef AVCODEC_MPEG4AUDIO_SAMPLE_RATES_H #define AVCODEC_MPEG4AUDIO_SAMPLE_RATES_H +// This table contains only 13 real elements and is padded with zeroes. +// It is used by the AAC encoder as sample rate table, so the encoder +// needs to actually support all of these rates and it needs to have +// a trailing zero. const int ff_mpeg4audio_sample_rates[16] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 diff --git a/libavcodec/mpeg4video.c b/libavcodec/mpeg4video.c index 3133cc22c..a53ce72df 100644 --- a/libavcodec/mpeg4video.c +++ b/libavcodec/mpeg4video.c @@ -20,35 +20,22 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/thread.h" - #include "mpegutils.h" #include "mpegvideo.h" #include "mpeg4video.h" #include "mpeg4data.h" -static av_cold void mpeg4_init_rl_intra(void) +int ff_mpeg4_get_video_packet_prefix_length(enum AVPictureType pict_type, + int f_code, int b_code) { - static uint8_t mpeg4_rl_intra_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; - ff_rl_init(&ff_mpeg4_rl_intra, mpeg4_rl_intra_table); -} - -av_cold void ff_mpeg4_init_rl_intra(void) -{ - static AVOnce init_static_once = AV_ONCE_INIT; - ff_thread_once(&init_static_once, mpeg4_init_rl_intra); -} - -int ff_mpeg4_get_video_packet_prefix_length(MpegEncContext *s) -{ - switch (s->pict_type) { + switch (pict_type) { case AV_PICTURE_TYPE_I: return 16; case AV_PICTURE_TYPE_P: case AV_PICTURE_TYPE_S: - return s->f_code + 15; + return f_code + 15; case AV_PICTURE_TYPE_B: - return FFMAX3(s->f_code, s->b_code, 2) + 15; + return FFMAX3(f_code, b_code, 2) + 15; default: return -1; } @@ -56,17 +43,20 @@ int ff_mpeg4_get_video_packet_prefix_length(MpegEncContext *s) void ff_mpeg4_clean_buffers(MpegEncContext *s) { - int c_wrap, c_xy, l_wrap, l_xy; + const int mb_height = s->mb_height; + int c_wrap, l_wrap, l_xy; l_wrap = s->b8_stride; l_xy = (2 * s->mb_y - 1) * l_wrap + s->mb_x * 2 - 1; c_wrap = s->mb_stride; - c_xy = (s->mb_y - 1) * c_wrap + s->mb_x - 1; + int u_xy = 2 * mb_height * l_wrap + s->mb_y * c_wrap + s->mb_x - 1; + int v_xy = u_xy + c_wrap * (mb_height + 1); + int16_t (*ac_val)[16] = s->ac_val; /* clean AC */ - memset(s->ac_val[0] + l_xy, 0, (l_wrap * 2 + 1) * 16 * sizeof(int16_t)); - memset(s->ac_val[1] + c_xy, 0, (c_wrap + 1) * 16 * sizeof(int16_t)); - memset(s->ac_val[2] + c_xy, 0, (c_wrap + 1) * 16 * sizeof(int16_t)); + memset(ac_val + l_xy, 0, (l_wrap * 2 + 1) * sizeof(*ac_val)); + memset(ac_val + u_xy, 0, (c_wrap + 1) * sizeof(*ac_val)); + memset(ac_val + v_xy, 0, (c_wrap + 1) * sizeof(*ac_val)); /* clean MV */ // we can't clear the MVs as they might be needed by a B-frame diff --git a/libavcodec/mpeg4video.h b/libavcodec/mpeg4video.h index 29b11eb92..274b21a06 100644 --- a/libavcodec/mpeg4video.h +++ b/libavcodec/mpeg4video.h @@ -28,7 +28,8 @@ #include "mpegvideo.h" void ff_mpeg4_clean_buffers(MpegEncContext *s); -int ff_mpeg4_get_video_packet_prefix_length(MpegEncContext *s); +int ff_mpeg4_get_video_packet_prefix_length(enum AVPictureType pict_type, + int f_code, int b_code); void ff_mpeg4_init_direct_mv(MpegEncContext *s); /** @@ -36,94 +37,4 @@ void ff_mpeg4_init_direct_mv(MpegEncContext *s); */ int ff_mpeg4_set_direct_mv(MpegEncContext *s, int mx, int my); -#if 0 //3IV1 is quite rare and it slows things down a tiny bit -#define IS_3IV1 s->codec_tag == AV_RL32("3IV1") -#else -#define IS_3IV1 0 -#endif - -/** - * Predict the dc. - * encoding quantized level -> quantized diff - * decoding quantized diff -> quantized level - * @param n block index (0-3 are luma, 4-5 are chroma) - * @param dir_ptr pointer to an integer where the prediction direction will be stored - */ -static inline int ff_mpeg4_pred_dc(MpegEncContext *s, int n, int level, - int *dir_ptr, int encoding) -{ - int a, b, c, wrap, pred, scale, ret; - int16_t *dc_val; - - /* find prediction */ - if (n < 4) - scale = s->y_dc_scale; - else - scale = s->c_dc_scale; - if (IS_3IV1) - scale = 8; - - wrap = s->block_wrap[n]; - dc_val = s->dc_val[0] + s->block_index[n]; - - /* B C - * A X - */ - a = dc_val[-1]; - b = dc_val[-1 - wrap]; - c = dc_val[-wrap]; - - /* outside slice handling (we can't do that by memset as we need the - * dc for error resilience) */ - if (s->first_slice_line && n != 3) { - if (n != 2) - b = c = 1024; - if (n != 1 && s->mb_x == s->resync_mb_x) - b = a = 1024; - } - if (s->mb_x == s->resync_mb_x && s->mb_y == s->resync_mb_y + 1) { - if (n == 0 || n == 4 || n == 5) - b = 1024; - } - - if (abs(a - b) < abs(b - c)) { - pred = c; - *dir_ptr = 1; /* top */ - } else { - pred = a; - *dir_ptr = 0; /* left */ - } - /* we assume pred is positive */ - pred = FASTDIV((pred + (scale >> 1)), scale); - - if (encoding) { - ret = level - pred; - } else { - level += pred; - ret = level; - } - level *= scale; - if (level & (~2047)) { - if (!s->encoding && (s->avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_AGGRESSIVE))) { - if (level < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "dc<0 at %dx%d\n", s->mb_x, s->mb_y); - return AVERROR_INVALIDDATA; - } - if (level > 2048 + scale) { - av_log(s->avctx, AV_LOG_ERROR, - "dc overflow at %dx%d\n", s->mb_x, s->mb_y); - return AVERROR_INVALIDDATA; - } - } - if (level < 0) - level = 0; - else if (!(s->workaround_bugs & FF_BUG_DC_CLIP)) - level = 2047; - } - dc_val[0] = level; - - return ret; -} - #endif /* AVCODEC_MPEG4VIDEO_H */ diff --git a/libavcodec/mpeg4video_parser.c b/libavcodec/mpeg4video_parser.c index b00b523bd..fe6d333fc 100644 --- a/libavcodec/mpeg4video_parser.c +++ b/libavcodec/mpeg4video_parser.c @@ -27,6 +27,7 @@ #include "mpegvideo.h" #include "mpeg4videodec.h" #include "mpeg4videodefs.h" +#include "parser_internal.h" struct Mp4vParseContext { ParseContext pc; @@ -84,7 +85,7 @@ static int mpeg4_decode_header(AVCodecParserContext *s1, AVCodecContext *avctx, { struct Mp4vParseContext *pc = s1->priv_data; Mpeg4DecContext *dec_ctx = &pc->dec_ctx; - MpegEncContext *s = &dec_ctx->m; + MPVContext *const s = &dec_ctx->h.c; GetBitContext gb1, *gb = &gb1; int ret; @@ -92,13 +93,14 @@ static int mpeg4_decode_header(AVCodecParserContext *s1, AVCodecContext *avctx, if (avctx->extradata_size && pc->first_picture) { init_get_bits(gb, avctx->extradata, avctx->extradata_size * 8); - ret = ff_mpeg4_decode_picture_header(dec_ctx, gb, 1, 1); + ret = ff_mpeg4_parse_picture_header(dec_ctx, gb, 1, 1); if (ret < 0) av_log(avctx, AV_LOG_WARNING, "Failed to parse extradata\n"); } init_get_bits(gb, buf, 8 * buf_size); - ret = ff_mpeg4_decode_picture_header(dec_ctx, gb, 0, 1); + ret = ff_mpeg4_parse_picture_header(dec_ctx, gb, 0, 1); + avctx->has_b_frames = !s->low_delay; if (s->width && (!avctx->width || !avctx->height || !avctx->coded_width || !avctx->coded_height)) { ret = ff_set_dimensions(avctx, s->width, s->height); @@ -123,7 +125,7 @@ static av_cold int mpeg4video_parse_init(AVCodecParserContext *s) pc->first_picture = 1; pc->dec_ctx.quant_precision = 5; - pc->dec_ctx.m.slice_context_count = 1; + pc->dec_ctx.h.c.slice_context_count = 1; pc->dec_ctx.showed_packed_warning = 1; return 0; } @@ -154,10 +156,10 @@ static int mpeg4video_parse(AVCodecParserContext *s, return next; } -const AVCodecParser ff_mpeg4video_parser = { - .codec_ids = { AV_CODEC_ID_MPEG4 }, +const FFCodecParser ff_mpeg4video_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_MPEG4), .priv_data_size = sizeof(struct Mp4vParseContext), - .parser_init = mpeg4video_parse_init, - .parser_parse = mpeg4video_parse, - .parser_close = ff_parse_close, + .init = mpeg4video_parse_init, + .parse = mpeg4video_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/mpeg4videodata.h b/libavcodec/mpeg4videodata.h index 8aac8a225..baca8a0b9 100644 --- a/libavcodec/mpeg4videodata.h +++ b/libavcodec/mpeg4videodata.h @@ -35,7 +35,6 @@ extern const int8_t ff_mpeg4_intra_level[102]; extern const int8_t ff_mpeg4_intra_run[102]; extern RLTable ff_mpeg4_rl_intra; -void ff_mpeg4_init_rl_intra(void); /* Note this is identical to the intra rvlc except that it is reordered. */ extern RLTable ff_rvlc_rl_inter; diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c index debcafc4c..3d20f7c38 100644 --- a/libavcodec/mpeg4videodec.c +++ b/libavcodec/mpeg4videodec.c @@ -24,6 +24,7 @@ #include "config_components.h" +#include "libavutil/avassert.h" #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/thread.h" @@ -35,6 +36,7 @@ #include "mpegvideo.h" #include "mpegvideodata.h" #include "mpegvideodec.h" +#include "mpegvideo_unquantize.h" #include "mpeg4video.h" #include "mpeg4videodata.h" #include "mpeg4videodec.h" @@ -46,9 +48,14 @@ #include "profiles.h" #include "qpeldsp.h" #include "threadprogress.h" -#include "xvididct.h" #include "unary.h" +#if 0 //3IV1 is quite rare and it slows things down a tiny bit +#define IS_3IV1 (s->codec_tag == AV_RL32("3IV1")) +#else +#define IS_3IV1 0 +#endif + /* The defines below define the number of bits that are read at once for * reading vlc values. Changing these may improve speed and data cache needs * be aware though that decreasing them may need the number of stages that is @@ -74,6 +81,12 @@ static const int16_t mb_type_b_map[4] = { MB_TYPE_FORWARD_MV | MB_TYPE_16x16, }; +static inline Mpeg4DecContext *h263_to_mpeg4(H263DecContext *h) +{ + av_assert2(h->c.codec_id == AV_CODEC_ID_MPEG4 && h->c.avctx->priv_data == h); + return (Mpeg4DecContext*)h; +} + static void gmc1_motion(MpegEncContext *s, const Mpeg4DecContext *ctx, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, uint8_t *const *ref_picture) @@ -312,55 +325,55 @@ void ff_mpeg4_decode_studio(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb * @param n block index (0-3 are luma, 4-5 are chroma) * @param dir the ac prediction direction */ -void ff_mpeg4_pred_ac(MpegEncContext *s, int16_t *block, int n, int dir) +void ff_mpeg4_pred_ac(H263DecContext *const h, int16_t *block, int n, int dir) { int i; int16_t *ac_val, *ac_val1; - int8_t *const qscale_table = s->cur_pic.qscale_table; + int8_t *const qscale_table = h->c.cur_pic.qscale_table; /* find prediction */ - ac_val = &s->ac_val[0][0][0] + s->block_index[n] * 16; + ac_val = &h->c.ac_val[0][0] + h->c.block_index[n] * 16; ac_val1 = ac_val; - if (s->ac_pred) { + if (h->c.ac_pred) { if (dir == 0) { - const int xy = s->mb_x - 1 + s->mb_y * s->mb_stride; + const int xy = h->c.mb_x - 1 + h->c.mb_y * h->c.mb_stride; /* left prediction */ ac_val -= 16; - if (s->mb_x == 0 || s->qscale == qscale_table[xy] || + if (h->c.mb_x == 0 || h->c.qscale == qscale_table[xy] || n == 1 || n == 3) { /* same qscale */ for (i = 1; i < 8; i++) - block[s->idsp.idct_permutation[i << 3]] += ac_val[i]; + block[h->c.idsp.idct_permutation[i << 3]] += ac_val[i]; } else { /* different qscale, we must rescale */ for (i = 1; i < 8; i++) - block[s->idsp.idct_permutation[i << 3]] += ROUNDED_DIV(ac_val[i] * qscale_table[xy], s->qscale); + block[h->c.idsp.idct_permutation[i << 3]] += ROUNDED_DIV(ac_val[i] * qscale_table[xy], h->c.qscale); } } else { - const int xy = s->mb_x + s->mb_y * s->mb_stride - s->mb_stride; + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride - h->c.mb_stride; /* top prediction */ - ac_val -= 16 * s->block_wrap[n]; + ac_val -= 16 * h->c.block_wrap[n]; - if (s->mb_y == 0 || s->qscale == qscale_table[xy] || + if (h->c.mb_y == 0 || h->c.qscale == qscale_table[xy] || n == 2 || n == 3) { /* same qscale */ for (i = 1; i < 8; i++) - block[s->idsp.idct_permutation[i]] += ac_val[i + 8]; + block[h->c.idsp.idct_permutation[i]] += ac_val[i + 8]; } else { /* different qscale, we must rescale */ for (i = 1; i < 8; i++) - block[s->idsp.idct_permutation[i]] += ROUNDED_DIV(ac_val[i + 8] * qscale_table[xy], s->qscale); + block[h->c.idsp.idct_permutation[i]] += ROUNDED_DIV(ac_val[i + 8] * qscale_table[xy], h->c.qscale); } } } /* left copy */ for (i = 1; i < 8; i++) - ac_val1[i] = block[s->idsp.idct_permutation[i << 3]]; + ac_val1[i] = block[h->c.idsp.idct_permutation[i << 3]]; /* top copy */ for (i = 1; i < 8; i++) - ac_val1[8 + i] = block[s->idsp.idct_permutation[i]]; + ac_val1[8 + i] = block[h->c.idsp.idct_permutation[i]]; } /** @@ -369,28 +382,28 @@ void ff_mpeg4_pred_ac(MpegEncContext *s, int16_t *block, int n, int dir) */ static inline int mpeg4_is_resync(Mpeg4DecContext *ctx) { - MpegEncContext *s = &ctx->m; - int bits_count = get_bits_count(&s->gb); - int v = show_bits(&s->gb, 16); + H263DecContext *const h = &ctx->h; + int bits_count = get_bits_count(&h->gb); + int v = show_bits(&h->gb, 16); - if (s->workaround_bugs & FF_BUG_NO_PADDING && !ctx->resync_marker) + if (h->c.workaround_bugs & FF_BUG_NO_PADDING && !ctx->resync_marker) return 0; while (v <= 0xFF) { - if (s->pict_type == AV_PICTURE_TYPE_B || - (v >> (8 - s->pict_type) != 1) || s->partitioned_frame) + if (h->c.pict_type == AV_PICTURE_TYPE_B || + (v >> (8 - h->c.pict_type) != 1) || h->partitioned_frame) break; - skip_bits(&s->gb, 8 + s->pict_type); - bits_count += 8 + s->pict_type; - v = show_bits(&s->gb, 16); + skip_bits(&h->gb, 8 + h->c.pict_type); + bits_count += 8 + h->c.pict_type; + v = show_bits(&h->gb, 16); } - if (bits_count + 8 >= s->gb.size_in_bits) { + if (bits_count + 8 >= h->gb.size_in_bits) { v >>= 8; v |= 0x7F >> (7 - (bits_count & 7)); if (v == 0x7F) - return s->mb_num; + return h->c.mb_num; } else { static const uint16_t mpeg4_resync_prefix[8] = { 0x7F00, 0x7E00, 0x7C00, 0x7800, 0x7000, 0x6000, 0x4000, 0x0000 @@ -398,23 +411,23 @@ static inline int mpeg4_is_resync(Mpeg4DecContext *ctx) if (v == mpeg4_resync_prefix[bits_count & 7]) { int len, mb_num; - int mb_num_bits = av_log2(s->mb_num - 1) + 1; - GetBitContext gb = s->gb; + int mb_num_bits = av_log2(h->c.mb_num - 1) + 1; + GetBitContext gb = h->gb; - skip_bits(&s->gb, 1); - align_get_bits(&s->gb); + skip_bits(&h->gb, 1); + align_get_bits(&h->gb); for (len = 0; len < 32; len++) - if (get_bits1(&s->gb)) + if (get_bits1(&h->gb)) break; - mb_num = get_bits(&s->gb, mb_num_bits); - if (!mb_num || mb_num > s->mb_num || get_bits_count(&s->gb)+6 > s->gb.size_in_bits) + mb_num = get_bits(&h->gb, mb_num_bits); + if (!mb_num || mb_num > h->c.mb_num || get_bits_count(&h->gb) + 6 > h->gb.size_in_bits) mb_num= -1; - s->gb = gb; + h->gb = gb; - if (len >= ff_mpeg4_get_video_packet_prefix_length(s)) + if (len >= ff_mpeg4_get_video_packet_prefix_length(h->c.pict_type, ctx->f_code, ctx->b_code)) return mb_num; } } @@ -423,7 +436,7 @@ static inline int mpeg4_is_resync(Mpeg4DecContext *ctx) static int mpeg4_decode_sprite_trajectory(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + MpegEncContext *s = &ctx->h.c; int a = 2 << ctx->sprite_warping_accuracy; int rho = 3 - ctx->sprite_warping_accuracy; int r = 16 / a; @@ -598,7 +611,8 @@ static int mpeg4_decode_sprite_trajectory(Mpeg4DecContext *ctx, GetBitContext *g ctx->sprite_shift[1] = alpha + beta + rho - min_ab + 2; break; default: - av_assert0(0); + av_unreachable("num_sprite_warping_points outside of 0..3 results in an error" + "in which num_sprite_warping_points is reset to zero"); } /* try to simplify the situation */ if (sprite_delta[0][0] == a << ctx->sprite_shift[0] && @@ -677,13 +691,12 @@ overflow: } static int decode_new_pred(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; int len = FFMIN(ctx->time_increment_bits + 3, 15); get_bits(gb, len); if (get_bits1(gb)) get_bits(gb, len); - check_marker(s->avctx, gb, "after new_pred"); + check_marker(ctx->h.c.avctx, gb, "after new_pred"); return 0; } @@ -692,124 +705,125 @@ static int decode_new_pred(Mpeg4DecContext *ctx, GetBitContext *gb) { * Decode the next video packet. * @return <0 if something went wrong */ -int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx) +int ff_mpeg4_decode_video_packet_header(H263DecContext *const h) { - MpegEncContext *s = &ctx->m; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); - int mb_num_bits = av_log2(s->mb_num - 1) + 1; + int mb_num_bits = av_log2(h->c.mb_num - 1) + 1; int header_extension = 0, mb_num, len; /* is there enough space left for a video packet + header */ - if (get_bits_count(&s->gb) > s->gb.size_in_bits - 20) + if (get_bits_count(&h->gb) > h->gb.size_in_bits - 20) return AVERROR_INVALIDDATA; for (len = 0; len < 32; len++) - if (get_bits1(&s->gb)) + if (get_bits1(&h->gb)) break; - if (len != ff_mpeg4_get_video_packet_prefix_length(s)) { - av_log(s->avctx, AV_LOG_ERROR, "marker does not match f_code\n"); + if (len != ff_mpeg4_get_video_packet_prefix_length(h->c.pict_type, ctx->f_code, ctx->b_code)) { + av_log(h->c.avctx, AV_LOG_ERROR, "marker does not match f_code\n"); return AVERROR_INVALIDDATA; } if (ctx->shape != RECT_SHAPE) { - header_extension = get_bits1(&s->gb); + header_extension = get_bits1(&h->gb); // FIXME more stuff here } - mb_num = get_bits(&s->gb, mb_num_bits); - if (mb_num >= s->mb_num || !mb_num) { - av_log(s->avctx, AV_LOG_ERROR, - "illegal mb_num in video packet (%d %d) \n", mb_num, s->mb_num); + mb_num = get_bits(&h->gb, mb_num_bits); + if (mb_num >= h->c.mb_num || !mb_num) { + av_log(h->c.avctx, AV_LOG_ERROR, + "illegal mb_num in video packet (%d %d) \n", mb_num, h->c.mb_num); return AVERROR_INVALIDDATA; } - s->mb_x = mb_num % s->mb_width; - s->mb_y = mb_num / s->mb_width; + h->c.mb_x = mb_num % h->c.mb_width; + h->c.mb_y = mb_num / h->c.mb_width; if (ctx->shape != BIN_ONLY_SHAPE) { - int qscale = get_bits(&s->gb, ctx->quant_precision); + int qscale = get_bits(&h->gb, ctx->quant_precision); if (qscale) - s->chroma_qscale = s->qscale = qscale; + h->c.chroma_qscale = h->c.qscale = qscale; } if (ctx->shape == RECT_SHAPE) - header_extension = get_bits1(&s->gb); + header_extension = get_bits1(&h->gb); if (header_extension) { - while (get_bits1(&s->gb) != 0) + while (get_bits1(&h->gb) != 0) ; - check_marker(s->avctx, &s->gb, "before time_increment in video packed header"); - skip_bits(&s->gb, ctx->time_increment_bits); /* time_increment */ - check_marker(s->avctx, &s->gb, "before vop_coding_type in video packed header"); + check_marker(h->c.avctx, &h->gb, "before time_increment in video packed header"); + skip_bits(&h->gb, ctx->time_increment_bits); /* time_increment */ + check_marker(h->c.avctx, &h->gb, "before vop_coding_type in video packed header"); - skip_bits(&s->gb, 2); /* vop coding type */ + skip_bits(&h->gb, 2); /* vop coding type */ // FIXME not rect stuff here if (ctx->shape != BIN_ONLY_SHAPE) { - skip_bits(&s->gb, 3); /* intra dc vlc threshold */ + skip_bits(&h->gb, 3); /* intra dc vlc threshold */ // FIXME don't just ignore everything - if (s->pict_type == AV_PICTURE_TYPE_S && + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE) { - if (mpeg4_decode_sprite_trajectory(ctx, &s->gb) < 0) + if (mpeg4_decode_sprite_trajectory(ctx, &h->gb) < 0) return AVERROR_INVALIDDATA; - av_log(s->avctx, AV_LOG_ERROR, "untested\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "untested\n"); } // FIXME reduced res stuff here - if (s->pict_type != AV_PICTURE_TYPE_I) { - int f_code = get_bits(&s->gb, 3); /* fcode_for */ + if (h->c.pict_type != AV_PICTURE_TYPE_I) { + int f_code = get_bits(&h->gb, 3); /* fcode_for */ if (f_code == 0) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "Error, video packet header damaged (f_code=0)\n"); } - if (s->pict_type == AV_PICTURE_TYPE_B) { - int b_code = get_bits(&s->gb, 3); + if (h->c.pict_type == AV_PICTURE_TYPE_B) { + int b_code = get_bits(&h->gb, 3); if (b_code == 0) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "Error, video packet header damaged (b_code=0)\n"); } } } if (ctx->new_pred) - decode_new_pred(ctx, &s->gb); + decode_new_pred(ctx, &h->gb); return 0; } -static void reset_studio_dc_predictors(MpegEncContext *s) +static void reset_studio_dc_predictors(Mpeg4DecContext *const ctx) { + H263DecContext *const h = &ctx->h; /* Reset DC Predictors */ - s->last_dc[0] = - s->last_dc[1] = - s->last_dc[2] = 1 << (s->avctx->bits_per_raw_sample + s->dct_precision + s->intra_dc_precision - 1); + h->last_dc[0] = + h->last_dc[1] = + h->last_dc[2] = 1 << (h->c.avctx->bits_per_raw_sample + ctx->dct_precision + h->c.intra_dc_precision - 1); } /** * Decode the next video packet. * @return <0 if something went wrong */ -int ff_mpeg4_decode_studio_slice_header(Mpeg4DecContext *ctx) +int ff_mpeg4_decode_studio_slice_header(H263DecContext *const h) { - MpegEncContext *s = &ctx->m; - GetBitContext *gb = &s->gb; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); + GetBitContext *gb = &h->gb; unsigned vlc_len; uint16_t mb_num; if (get_bits_left(gb) >= 32 && get_bits_long(gb, 32) == SLICE_STARTCODE) { - vlc_len = av_log2(s->mb_width * s->mb_height) + 1; + vlc_len = av_log2(h->c.mb_width * h->c.mb_height) + 1; mb_num = get_bits(gb, vlc_len); - if (mb_num >= s->mb_num) + if (mb_num >= h->c.mb_num) return AVERROR_INVALIDDATA; - s->mb_x = mb_num % s->mb_width; - s->mb_y = mb_num / s->mb_width; + h->c.mb_x = mb_num % h->c.mb_width; + h->c.mb_y = mb_num / h->c.mb_width; if (ctx->shape != BIN_ONLY_SHAPE) - s->qscale = mpeg_get_qscale(s); + h->c.qscale = mpeg_get_qscale(&h->gb, h->c.q_scale_type); if (get_bits1(gb)) { /* slice_extension_flag */ skip_bits1(gb); /* intra_slice */ @@ -819,7 +833,7 @@ int ff_mpeg4_decode_studio_slice_header(Mpeg4DecContext *ctx) skip_bits(gb, 8); /* extra_information_slice */ } - reset_studio_dc_predictors(s); + reset_studio_dc_predictors(ctx); } else { return AVERROR_INVALIDDATA; @@ -835,9 +849,9 @@ int ff_mpeg4_decode_studio_slice_header(Mpeg4DecContext *ctx) */ static inline int get_amv(Mpeg4DecContext *ctx, int n) { - MpegEncContext *s = &ctx->m; + MPVContext *const s = &ctx->h.c; int x, y, mb_v, sum, dx, dy, shift; - int len = 1 << (s->f_code + 4); + int len = 1 << (ctx->f_code + 4); const int a = ctx->sprite_warping_accuracy; if (s->workaround_bugs & FF_BUG_AMV) @@ -880,23 +894,103 @@ static inline int get_amv(Mpeg4DecContext *ctx, int n) return sum; } +/** + * Predict the dc. + * @param n block index (0-3 are luma, 4-5 are chroma) + * @param dir_ptr pointer to an integer where the prediction direction will be stored + */ +static inline int mpeg4_pred_dc(MpegEncContext *s, int n, int *dir_ptr) +{ + const int16_t *const dc_val = s->dc_val + s->block_index[n]; + const int wrap = s->block_wrap[n]; + int pred; + + /* find prediction */ + + /* B C + * A X + */ + int a = dc_val[-1]; + int b = dc_val[-1 - wrap]; + int c = dc_val[-wrap]; + + /* outside slice handling (we can't do that by memset as we need the + * dc for error resilience) */ + if (s->first_slice_line && n != 3) { + if (n != 2) + b = c = 1024; + if (n != 1 && s->mb_x == s->resync_mb_x) + b = a = 1024; + } + if (s->mb_x == s->resync_mb_x && s->mb_y == s->resync_mb_y + 1) { + if (n == 0 || n == 4 || n == 5) + b = 1024; + } + + if (abs(a - b) < abs(b - c)) { + pred = c; + *dir_ptr = 1; /* top */ + } else { + pred = a; + *dir_ptr = 0; /* left */ + } + return pred; +} + +static inline int mpeg4_get_level_dc(MpegEncContext *s, int n, int pred, int level) +{ + int scale = n < 4 ? s->y_dc_scale : s->c_dc_scale; + int ret; + + if (IS_3IV1) + scale = 8; + + /* we assume pred is positive */ + pred = FASTDIV((pred + (scale >> 1)), scale); + + level += pred; + ret = level; + level *= scale; + if (level & (~2047)) { + if (s->avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_AGGRESSIVE)) { + if (level < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "dc<0 at %dx%d\n", s->mb_x, s->mb_y); + return AVERROR_INVALIDDATA; + } + if (level > 2048 + scale) { + av_log(s->avctx, AV_LOG_ERROR, + "dc overflow at %dx%d\n", s->mb_x, s->mb_y); + return AVERROR_INVALIDDATA; + } + } + if (level < 0) + level = 0; + else if (!(s->workaround_bugs & FF_BUG_DC_CLIP)) + level = 2047; + } + s->dc_val[s->block_index[n]] = level; + + return ret; +} + /** * Decode the dc value. * @param n block index (0-3 are luma, 4-5 are chroma) * @param dir_ptr the prediction direction will be stored here * @return the quantized dc */ -static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr) +static inline int mpeg4_decode_dc(H263DecContext *const h, int n, int *dir_ptr) { - int level, code; + int level, code, pred; if (n < 4) - code = get_vlc2(&s->gb, dc_lum, DC_VLC_BITS, 1); + code = get_vlc2(&h->gb, dc_lum, DC_VLC_BITS, 1); else - code = get_vlc2(&s->gb, dc_chrom, DC_VLC_BITS, 1); + code = get_vlc2(&h->gb, dc_chrom, DC_VLC_BITS, 1); if (code < 0) { - av_log(s->avctx, AV_LOG_ERROR, "illegal dc vlc\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal dc vlc\n"); return AVERROR_INVALIDDATA; } @@ -905,28 +999,29 @@ static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr) } else { if (IS_3IV1) { if (code == 1) - level = 2 * get_bits1(&s->gb) - 1; + level = 2 * get_bits1(&h->gb) - 1; else { - if (get_bits1(&s->gb)) - level = get_bits(&s->gb, code - 1) + (1 << (code - 1)); + if (get_bits1(&h->gb)) + level = get_bits(&h->gb, code - 1) + (1 << (code - 1)); else - level = -get_bits(&s->gb, code - 1) - (1 << (code - 1)); + level = -get_bits(&h->gb, code - 1) - (1 << (code - 1)); } } else { - level = get_xbits(&s->gb, code); + level = get_xbits(&h->gb, code); } if (code > 8) { - if (get_bits1(&s->gb) == 0) { /* marker */ - if (s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT)) { - av_log(s->avctx, AV_LOG_ERROR, "dc marker bit missing\n"); + if (get_bits1(&h->gb) == 0) { /* marker */ + if (h->c.avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT)) { + av_log(h->c.avctx, AV_LOG_ERROR, "dc marker bit missing\n"); return AVERROR_INVALIDDATA; } } } } - return ff_mpeg4_pred_dc(s, n, level, dir_ptr, 0); + pred = mpeg4_pred_dc(&h->c, n, dir_ptr); + return mpeg4_get_level_dc(&h->c, n, pred, level); } /** @@ -935,85 +1030,85 @@ static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr) */ static int mpeg4_decode_partition_a(Mpeg4DecContext *ctx) { - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; int mb_num = 0; static const int8_t quant_tab[4] = { -1, -2, 1, 2 }; /* decode first partition */ - s->first_slice_line = 1; - for (; s->mb_y < s->mb_height; s->mb_y++) { - ff_init_block_index(s); - for (; s->mb_x < s->mb_width; s->mb_x++) { - const int xy = s->mb_x + s->mb_y * s->mb_stride; + h->c.first_slice_line = 1; + for (; h->c.mb_y < h->c.mb_height; h->c.mb_y++) { + ff_init_block_index(&h->c); + for (; h->c.mb_x < h->c.mb_width; h->c.mb_x++) { + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; int cbpc; int dir = 0; mb_num++; - ff_update_block_index(s, 8, s->avctx->lowres, 1); - if (s->mb_x == s->resync_mb_x && s->mb_y == s->resync_mb_y + 1) - s->first_slice_line = 0; + ff_update_block_index(&h->c, 8, h->c.avctx->lowres, 1); + if (h->c.mb_x == h->c.resync_mb_x && h->c.mb_y == h->c.resync_mb_y + 1) + h->c.first_slice_line = 0; - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (h->c.pict_type == AV_PICTURE_TYPE_I) { int i; do { - if (show_bits(&s->gb, 19) == DC_MARKER) + if (show_bits(&h->gb, 19) == DC_MARKER) return mb_num - 1; - cbpc = get_vlc2(&s->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); if (cbpc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "mcbpc corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "mcbpc corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } } while (cbpc == 8); - s->cbp_table[xy] = cbpc & 3; - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; - s->mb_intra = 1; + h->c.cbp_table[xy] = cbpc & 3; + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA; + h->c.mb_intra = 1; if (cbpc & 4) - ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); + ff_set_qscale(&h->c, h->c.qscale + quant_tab[get_bits(&h->gb, 2)]); - s->cur_pic.qscale_table[xy] = s->qscale; + h->c.cur_pic.qscale_table[xy] = h->c.qscale; - s->mbintra_table[xy] = 1; + h->c.mbintra_table[xy] = 1; for (i = 0; i < 6; i++) { int dc_pred_dir; - int dc = mpeg4_decode_dc(s, i, &dc_pred_dir); + int dc = mpeg4_decode_dc(h, i, &dc_pred_dir); if (dc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "DC corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "DC corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return dc; } dir <<= 1; if (dc_pred_dir) dir |= 1; } - s->pred_dir_table[xy] = dir; + h->c.pred_dir_table[xy] = dir; } else { /* P/S_TYPE */ int mx, my, pred_x, pred_y, bits; - int16_t *const mot_val = s->cur_pic.motion_val[0][s->block_index[0]]; - const int stride = s->b8_stride * 2; + int16_t *const mot_val = h->c.cur_pic.motion_val[0][h->c.block_index[0]]; + const int stride = h->c.b8_stride * 2; try_again: - bits = show_bits(&s->gb, 17); + bits = show_bits(&h->gb, 17); if (bits == MOTION_MARKER) return mb_num - 1; - skip_bits1(&s->gb); + skip_bits1(&h->gb); if (bits & 0x10000) { /* skip mb */ - if (s->pict_type == AV_PICTURE_TYPE_S && + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE) { - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_GMC | MB_TYPE_FORWARD_MV; mx = get_amv(ctx, 0); my = get_amv(ctx, 1); } else { - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; mx = my = 0; @@ -1027,27 +1122,26 @@ try_again: mot_val[1 + stride] = mot_val[3 + stride] = my; - if (s->mbintra_table[xy]) - ff_clean_intra_table_entries(s); + ff_h263_clean_intra_table_entries(&h->c, xy); continue; } - cbpc = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); if (cbpc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "mcbpc corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "mcbpc corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } if (cbpc == 20) goto try_again; - s->cbp_table[xy] = cbpc & (8 + 3); // 8 is dquant + h->c.cbp_table[xy] = cbpc & (8 + 3); // 8 is dquant - s->mb_intra = ((cbpc & 4) != 0); + h->c.mb_intra = ((cbpc & 4) != 0); - if (s->mb_intra) { - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; - s->mbintra_table[xy] = 1; + if (h->c.mb_intra) { + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA; + h->c.mbintra_table[xy] = 1; mot_val[0] = mot_val[2] = mot_val[0 + stride] = @@ -1057,34 +1151,33 @@ try_again: mot_val[1 + stride] = mot_val[3 + stride] = 0; } else { - if (s->mbintra_table[xy]) - ff_clean_intra_table_entries(s); + ff_h263_clean_intra_table_entries(&h->c, xy); - if (s->pict_type == AV_PICTURE_TYPE_S && + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE && (cbpc & 16) == 0) - s->mcsel = get_bits1(&s->gb); + h->c.mcsel = get_bits1(&h->gb); else - s->mcsel = 0; + h->c.mcsel = 0; if ((cbpc & 16) == 0) { /* 16x16 motion prediction */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - if (!s->mcsel) { - mx = ff_h263_decode_motion(s, pred_x, s->f_code); + ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); + if (!h->c.mcsel) { + mx = ff_h263_decode_motion(h, pred_x, ctx->f_code); if (mx >= 0xffff) return AVERROR_INVALIDDATA; - my = ff_h263_decode_motion(s, pred_y, s->f_code); + my = ff_h263_decode_motion(h, pred_y, ctx->f_code); if (my >= 0xffff) return AVERROR_INVALIDDATA; - s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } else { mx = get_amv(ctx, 0); my = get_amv(ctx, 1); - s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_GMC | MB_TYPE_FORWARD_MV; } @@ -1099,15 +1192,15 @@ try_again: mot_val[3 + stride] = my; } else { int i; - s->cur_pic.mb_type[xy] = MB_TYPE_8x8 | + h->c.cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; for (i = 0; i < 4; i++) { - int16_t *mot_val = ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); - mx = ff_h263_decode_motion(s, pred_x, s->f_code); + int16_t *mot_val = ff_h263_pred_motion(&h->c, i, 0, &pred_x, &pred_y); + mx = ff_h263_decode_motion(h, pred_x, ctx->f_code); if (mx >= 0xffff) return AVERROR_INVALIDDATA; - my = ff_h263_decode_motion(s, pred_y, s->f_code); + my = ff_h263_decode_motion(h, pred_y, ctx->f_code); if (my >= 0xffff) return AVERROR_INVALIDDATA; mot_val[0] = mx; @@ -1117,7 +1210,7 @@ try_again: } } } - s->mb_x = 0; + h->c.mb_x = 0; } return mb_num; @@ -1127,91 +1220,91 @@ try_again: * decode second partition. * @return <0 if an error occurred */ -static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) +static int mpeg4_decode_partition_b(H263DecContext *const h, int mb_count) { int mb_num = 0; static const int8_t quant_tab[4] = { -1, -2, 1, 2 }; - s->mb_x = s->resync_mb_x; - s->first_slice_line = 1; - for (s->mb_y = s->resync_mb_y; mb_num < mb_count; s->mb_y++) { - ff_init_block_index(s); - for (; mb_num < mb_count && s->mb_x < s->mb_width; s->mb_x++) { - const int xy = s->mb_x + s->mb_y * s->mb_stride; + h->c.mb_x = h->c.resync_mb_x; + h->c.first_slice_line = 1; + for (h->c.mb_y = h->c.resync_mb_y; mb_num < mb_count; h->c.mb_y++) { + ff_init_block_index(&h->c); + for (; mb_num < mb_count && h->c.mb_x < h->c.mb_width; h->c.mb_x++) { + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; mb_num++; - ff_update_block_index(s, 8, s->avctx->lowres, 1); - if (s->mb_x == s->resync_mb_x && s->mb_y == s->resync_mb_y + 1) - s->first_slice_line = 0; + ff_update_block_index(&h->c, 8, h->c.avctx->lowres, 1); + if (h->c.mb_x == h->c.resync_mb_x && h->c.mb_y == h->c.resync_mb_y + 1) + h->c.first_slice_line = 0; - if (s->pict_type == AV_PICTURE_TYPE_I) { - int ac_pred = get_bits1(&s->gb); - int cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + if (h->c.pict_type == AV_PICTURE_TYPE_I) { + int ac_pred = get_bits1(&h->gb); + int cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "cbpy corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "cbpy corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } - s->cbp_table[xy] |= cbpy << 2; - s->cur_pic.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; + h->c.cbp_table[xy] |= cbpy << 2; + h->c.cur_pic.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; } else { /* P || S_TYPE */ - if (IS_INTRA(s->cur_pic.mb_type[xy])) { + if (IS_INTRA(h->c.cur_pic.mb_type[xy])) { int i; int dir = 0; - int ac_pred = get_bits1(&s->gb); - int cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + int ac_pred = get_bits1(&h->gb); + int cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "I cbpy corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "I cbpy corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } - if (s->cbp_table[xy] & 8) - ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); - s->cur_pic.qscale_table[xy] = s->qscale; + if (h->c.cbp_table[xy] & 8) + ff_set_qscale(&h->c, h->c.qscale + quant_tab[get_bits(&h->gb, 2)]); + h->c.cur_pic.qscale_table[xy] = h->c.qscale; for (i = 0; i < 6; i++) { int dc_pred_dir; - int dc = mpeg4_decode_dc(s, i, &dc_pred_dir); + int dc = mpeg4_decode_dc(h, i, &dc_pred_dir); if (dc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "DC corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "DC corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return dc; } dir <<= 1; if (dc_pred_dir) dir |= 1; } - s->cbp_table[xy] &= 3; // remove dquant - s->cbp_table[xy] |= cbpy << 2; - s->cur_pic.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; - s->pred_dir_table[xy] = dir; - } else if (IS_SKIP(s->cur_pic.mb_type[xy])) { - s->cur_pic.qscale_table[xy] = s->qscale; - s->cbp_table[xy] = 0; + h->c.cbp_table[xy] &= 3; // remove dquant + h->c.cbp_table[xy] |= cbpy << 2; + h->c.cur_pic.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; + h->c.pred_dir_table[xy] = dir; + } else if (IS_SKIP(h->c.cur_pic.mb_type[xy])) { + h->c.cur_pic.qscale_table[xy] = h->c.qscale; + h->c.cbp_table[xy] = 0; } else { - int cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + int cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "P cbpy corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "P cbpy corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } - if (s->cbp_table[xy] & 8) - ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); - s->cur_pic.qscale_table[xy] = s->qscale; + if (h->c.cbp_table[xy] & 8) + ff_set_qscale(&h->c, h->c.qscale + quant_tab[get_bits(&h->gb, 2)]); + h->c.cur_pic.qscale_table[xy] = h->c.qscale; - s->cbp_table[xy] &= 3; // remove dquant - s->cbp_table[xy] |= (cbpy ^ 0xf) << 2; + h->c.cbp_table[xy] &= 3; // remove dquant + h->c.cbp_table[xy] |= (cbpy ^ 0xf) << 2; } } } if (mb_num >= mb_count) return 0; - s->mb_x = 0; + h->c.mb_x = 0; } return 0; } @@ -1220,62 +1313,62 @@ static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) * Decode the first and second partition. * @return <0 if error (and sets error type in the error_status_table) */ -int ff_mpeg4_decode_partitions(Mpeg4DecContext *ctx) +int ff_mpeg4_decode_partitions(H263DecContext *const h) { - MpegEncContext *s = &ctx->m; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); int mb_num; int ret; - const int part_a_error = s->pict_type == AV_PICTURE_TYPE_I ? (ER_DC_ERROR | ER_MV_ERROR) : ER_MV_ERROR; - const int part_a_end = s->pict_type == AV_PICTURE_TYPE_I ? (ER_DC_END | ER_MV_END) : ER_MV_END; + const int part_a_error = h->c.pict_type == AV_PICTURE_TYPE_I ? (ER_DC_ERROR | ER_MV_ERROR) : ER_MV_ERROR; + const int part_a_end = h->c.pict_type == AV_PICTURE_TYPE_I ? (ER_DC_END | ER_MV_END) : ER_MV_END; mb_num = mpeg4_decode_partition_a(ctx); if (mb_num <= 0) { - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x, s->mb_y, part_a_error); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x, h->c.mb_y, part_a_error); return mb_num ? mb_num : AVERROR_INVALIDDATA; } - if (s->resync_mb_x + s->resync_mb_y * s->mb_width + mb_num > s->mb_num) { - av_log(s->avctx, AV_LOG_ERROR, "slice below monitor ...\n"); - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x, s->mb_y, part_a_error); + if (h->c.resync_mb_x + h->c.resync_mb_y * h->c.mb_width + mb_num > h->c.mb_num) { + av_log(h->c.avctx, AV_LOG_ERROR, "slice below monitor ...\n"); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x, h->c.mb_y, part_a_error); return AVERROR_INVALIDDATA; } - s->mb_num_left = mb_num; + h->mb_num_left = mb_num; - if (s->pict_type == AV_PICTURE_TYPE_I) { - while (show_bits(&s->gb, 9) == 1) - skip_bits(&s->gb, 9); - if (get_bits(&s->gb, 19) != DC_MARKER) { - av_log(s->avctx, AV_LOG_ERROR, + if (h->c.pict_type == AV_PICTURE_TYPE_I) { + while (show_bits(&h->gb, 9) == 1) + skip_bits(&h->gb, 9); + if (get_bits(&h->gb, 19) != DC_MARKER) { + av_log(h->c.avctx, AV_LOG_ERROR, "marker missing after first I partition at %d %d\n", - s->mb_x, s->mb_y); + h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } } else { - while (show_bits(&s->gb, 10) == 1) - skip_bits(&s->gb, 10); - if (get_bits(&s->gb, 17) != MOTION_MARKER) { - av_log(s->avctx, AV_LOG_ERROR, + while (show_bits(&h->gb, 10) == 1) + skip_bits(&h->gb, 10); + if (get_bits(&h->gb, 17) != MOTION_MARKER) { + av_log(h->c.avctx, AV_LOG_ERROR, "marker missing after first P partition at %d %d\n", - s->mb_x, s->mb_y); + h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } } - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x - 1, s->mb_y, part_a_end); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x - 1, h->c.mb_y, part_a_end); - ret = mpeg4_decode_partition_b(s, mb_num); + ret = mpeg4_decode_partition_b(h, mb_num); if (ret < 0) { - if (s->pict_type == AV_PICTURE_TYPE_P) - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x, s->mb_y, ER_DC_ERROR); + if (h->c.pict_type == AV_PICTURE_TYPE_P) + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x, h->c.mb_y, ER_DC_ERROR); return ret; } else { - if (s->pict_type == AV_PICTURE_TYPE_P) - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x - 1, s->mb_y, ER_DC_END); + if (h->c.pict_type == AV_PICTURE_TYPE_P) + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x - 1, h->c.mb_y, ER_DC_END); } return 0; @@ -1289,8 +1382,8 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, int n, int coded, int intra, int use_intra_dc_vlc, int rvlc) { - MpegEncContext *s = &ctx->m; - int level, i, last, run, qmul, qadd; + H263DecContext *const h = &ctx->h; + int level, i, last, run, qmul, qadd, pred; int av_uninit(dc_pred_dir); const RLTable *rl; const RL_VLC_ELEM *rl_vlc; @@ -1299,17 +1392,18 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, // Note intra & rvlc should be optimized away if this is inlined if (intra) { + // FIXME add short header support if (use_intra_dc_vlc) { /* DC coef */ - if (s->partitioned_frame) { - level = s->dc_val[0][s->block_index[n]]; + if (h->partitioned_frame) { + level = h->c.dc_val[h->c.block_index[n]]; if (n < 4) - level = FASTDIV((level + (s->y_dc_scale >> 1)), s->y_dc_scale); + level = FASTDIV((level + (h->c.y_dc_scale >> 1)), h->c.y_dc_scale); else - level = FASTDIV((level + (s->c_dc_scale >> 1)), s->c_dc_scale); - dc_pred_dir = (s->pred_dir_table[s->mb_x + s->mb_y * s->mb_stride] << n) & 32; + level = FASTDIV((level + (h->c.c_dc_scale >> 1)), h->c.c_dc_scale); + dc_pred_dir = (h->c.pred_dir_table[h->c.mb_x + h->c.mb_y * h->c.mb_stride] << n) & 32; } else { - level = mpeg4_decode_dc(s, n, &dc_pred_dir); + level = mpeg4_decode_dc(h, n, &dc_pred_dir); if (level < 0) return level; } @@ -1317,7 +1411,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, i = 0; } else { i = -1; - ff_mpeg4_pred_dc(s, n, 0, &dc_pred_dir, 0); + pred = mpeg4_pred_dc(&h->c, n, &dc_pred_dir); } if (!coded) goto not_coded; @@ -1329,20 +1423,20 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, rl = &ff_mpeg4_rl_intra; rl_vlc = ff_mpeg4_rl_intra.rl_vlc[0]; } - if (s->ac_pred) { + if (h->c.ac_pred) { if (dc_pred_dir == 0) - scan_table = s->permutated_intra_v_scantable; /* left */ + scan_table = h->permutated_intra_v_scantable; /* left */ else - scan_table = s->permutated_intra_h_scantable; /* top */ + scan_table = h->permutated_intra_h_scantable; /* top */ } else { - scan_table = s->intra_scantable.permutated; + scan_table = h->c.intra_scantable.permutated; } qmul = 1; qadd = 0; } else { i = -1; if (!coded) { - s->block_last_index[n] = i; + h->c.block_last_index[n] = i; return 0; } if (rvlc) @@ -1350,9 +1444,9 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, else rl = &ff_h263_rl_inter; - scan_table = s->intra_scantable.permutated; + scan_table = h->c.intra_scantable.permutated; - if (s->mpeg_quant) { + if (ctx->mpeg_quant) { qmul = 1; qadd = 0; if (rvlc) @@ -1360,61 +1454,61 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, else rl_vlc = ff_h263_rl_inter.rl_vlc[0]; } else { - qmul = s->qscale << 1; - qadd = (s->qscale - 1) | 1; + qmul = h->c.qscale << 1; + qadd = (h->c.qscale - 1) | 1; if (rvlc) - rl_vlc = ff_rvlc_rl_inter.rl_vlc[s->qscale]; + rl_vlc = ff_rvlc_rl_inter.rl_vlc[h->c.qscale]; else - rl_vlc = ff_h263_rl_inter.rl_vlc[s->qscale]; + rl_vlc = ff_h263_rl_inter.rl_vlc[h->c.qscale]; } } { - OPEN_READER(re, &s->gb); + OPEN_READER(re, &h->gb); for (;;) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 0); + UPDATE_CACHE(re, &h->gb); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 0); if (level == 0) { /* escape */ if (rvlc) { - if (SHOW_UBITS(re, &s->gb, 1) == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (SHOW_UBITS(re, &h->gb, 1) == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "1. marker bit missing in rvlc esc\n"); return AVERROR_INVALIDDATA; } - SKIP_CACHE(re, &s->gb, 1); + SKIP_CACHE(re, &h->gb, 1); - last = SHOW_UBITS(re, &s->gb, 1); - SKIP_CACHE(re, &s->gb, 1); - run = SHOW_UBITS(re, &s->gb, 6); - SKIP_COUNTER(re, &s->gb, 1 + 1 + 6); - UPDATE_CACHE(re, &s->gb); + last = SHOW_UBITS(re, &h->gb, 1); + SKIP_CACHE(re, &h->gb, 1); + run = SHOW_UBITS(re, &h->gb, 6); + SKIP_COUNTER(re, &h->gb, 1 + 1 + 6); + UPDATE_CACHE(re, &h->gb); - if (SHOW_UBITS(re, &s->gb, 1) == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (SHOW_UBITS(re, &h->gb, 1) == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "2. marker bit missing in rvlc esc\n"); return AVERROR_INVALIDDATA; } - SKIP_CACHE(re, &s->gb, 1); + SKIP_CACHE(re, &h->gb, 1); - level = SHOW_UBITS(re, &s->gb, 11); - SKIP_CACHE(re, &s->gb, 11); + level = SHOW_UBITS(re, &h->gb, 11); + SKIP_CACHE(re, &h->gb, 11); - if (SHOW_UBITS(re, &s->gb, 5) != 0x10) { - av_log(s->avctx, AV_LOG_ERROR, "reverse esc missing\n"); + if (SHOW_UBITS(re, &h->gb, 5) != 0x10) { + av_log(h->c.avctx, AV_LOG_ERROR, "reverse esc missing\n"); return AVERROR_INVALIDDATA; } - SKIP_CACHE(re, &s->gb, 5); + SKIP_CACHE(re, &h->gb, 5); level = level * qmul + qadd; - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - SKIP_COUNTER(re, &s->gb, 1 + 11 + 5 + 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + SKIP_COUNTER(re, &h->gb, 1 + 11 + 5 + 1); i += run + 1; if (last) i += 192; } else { int cache; - cache = GET_CACHE(re, &s->gb); + cache = GET_CACHE(re, &h->gb); if (IS_3IV1) cache ^= 0xC0000000; @@ -1422,54 +1516,54 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, if (cache & 0x80000000) { if (cache & 0x40000000) { /* third escape */ - SKIP_CACHE(re, &s->gb, 2); - last = SHOW_UBITS(re, &s->gb, 1); - SKIP_CACHE(re, &s->gb, 1); - run = SHOW_UBITS(re, &s->gb, 6); - SKIP_COUNTER(re, &s->gb, 2 + 1 + 6); - UPDATE_CACHE(re, &s->gb); + SKIP_CACHE(re, &h->gb, 2); + last = SHOW_UBITS(re, &h->gb, 1); + SKIP_CACHE(re, &h->gb, 1); + run = SHOW_UBITS(re, &h->gb, 6); + SKIP_COUNTER(re, &h->gb, 2 + 1 + 6); + UPDATE_CACHE(re, &h->gb); if (IS_3IV1) { - level = SHOW_SBITS(re, &s->gb, 12); - LAST_SKIP_BITS(re, &s->gb, 12); + level = SHOW_SBITS(re, &h->gb, 12); + LAST_SKIP_BITS(re, &h->gb, 12); } else { - if (SHOW_UBITS(re, &s->gb, 1) == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (SHOW_UBITS(re, &h->gb, 1) == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "1. marker bit missing in 3. esc\n"); - if (!(s->avctx->err_recognition & AV_EF_IGNORE_ERR) || get_bits_left(&s->gb) <= 0) + if (!(h->c.avctx->err_recognition & AV_EF_IGNORE_ERR) || get_bits_left(&h->gb) <= 0) return AVERROR_INVALIDDATA; } - SKIP_CACHE(re, &s->gb, 1); + SKIP_CACHE(re, &h->gb, 1); - level = SHOW_SBITS(re, &s->gb, 12); - SKIP_CACHE(re, &s->gb, 12); + level = SHOW_SBITS(re, &h->gb, 12); + SKIP_CACHE(re, &h->gb, 12); - if (SHOW_UBITS(re, &s->gb, 1) == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (SHOW_UBITS(re, &h->gb, 1) == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "2. marker bit missing in 3. esc\n"); - if (!(s->avctx->err_recognition & AV_EF_IGNORE_ERR) || get_bits_left(&s->gb) <= 0) + if (!(h->c.avctx->err_recognition & AV_EF_IGNORE_ERR) || get_bits_left(&h->gb) <= 0) return AVERROR_INVALIDDATA; } - SKIP_COUNTER(re, &s->gb, 1 + 12 + 1); + SKIP_COUNTER(re, &h->gb, 1 + 12 + 1); } #if 0 - if (s->error_recognition >= FF_ER_COMPLIANT) { + if (h->c.error_recognition >= FF_ER_COMPLIANT) { const int abs_level= FFABS(level); if (abs_level<=MAX_LEVEL && run<=MAX_RUN) { const int run1= run - rl->max_run[last][abs_level] - 1; if (abs_level <= rl->max_level[last][run]) { - av_log(s->avctx, AV_LOG_ERROR, "illegal 3. esc, vlc encoding possible\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal 3. esc, vlc encoding possible\n"); return AVERROR_INVALIDDATA; } - if (s->error_recognition > FF_ER_COMPLIANT) { + if (h->c.error_recognition > FF_ER_COMPLIANT) { if (abs_level <= rl->max_level[last][run]*2) { - av_log(s->avctx, AV_LOG_ERROR, "illegal 3. esc, esc 1 encoding possible\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal 3. esc, esc 1 encoding possible\n"); return AVERROR_INVALIDDATA; } if (run1 >= 0 && abs_level <= rl->max_level[last][run1]) { - av_log(s->avctx, AV_LOG_ERROR, "illegal 3. esc, esc 2 encoding possible\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal 3. esc, esc 2 encoding possible\n"); return AVERROR_INVALIDDATA; } } @@ -1482,11 +1576,11 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, level = level * qmul - qadd; if ((unsigned)(level + 2048) > 4095) { - if (s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_AGGRESSIVE)) { + if (h->c.avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_AGGRESSIVE)) { if (level > 2560 || level < -2560) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "|level| overflow in 3. esc, qp=%d\n", - s->qscale); + h->c.qscale); return AVERROR_INVALIDDATA; } } @@ -1498,33 +1592,33 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, i += 192; } else { /* second escape */ - SKIP_BITS(re, &s->gb, 2); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 1); + SKIP_BITS(re, &h->gb, 2); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 1); i += run + rl->max_run[run >> 7][level / qmul] + 1; // FIXME opt indexing - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } } else { /* first escape */ - SKIP_BITS(re, &s->gb, 1); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 1); + SKIP_BITS(re, &h->gb, 1); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 1); i += run; level = level + rl->max_level[run >> 7][(run - 1) & 63] * qmul; // FIXME opt indexing - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } } } else { i += run; - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } - ff_tlog(s->avctx, "dct[%d][%d] = %- 4d end?:%d\n", scan_table[i&63]&7, scan_table[i&63] >> 3, level, i>62); + ff_tlog(h->c.avctx, "dct[%d][%d] = %- 4d end?:%d\n", scan_table[i&63]&7, scan_table[i&63] >> 3, level, i>62); if (i > 62) { i -= 192; if (i & (~63)) { - av_log(s->avctx, AV_LOG_ERROR, - "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "ac-tex damaged at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } @@ -1534,22 +1628,22 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, block[scan_table[i]] = level; } - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); } not_coded: if (intra) { if (!use_intra_dc_vlc) { - block[0] = ff_mpeg4_pred_dc(s, n, block[0], &dc_pred_dir, 0); + block[0] = mpeg4_get_level_dc(&h->c, n, pred, block[0]); i -= i >> 31; // if (i == -1) i = 0; } - ff_mpeg4_pred_ac(s, block, n, dc_pred_dir); - if (s->ac_pred) + ff_mpeg4_pred_ac(h, block, n, dc_pred_dir); + if (h->c.ac_pred) i = 63; // FIXME not optimal } - s->block_last_index[n] = i; + h->c.block_last_index[n] = i; return 0; } @@ -1557,74 +1651,71 @@ not_coded: * decode partition C of one MB. * @return <0 if an error occurred */ -static int mpeg4_decode_partitioned_mb(MpegEncContext *s, int16_t block[6][64]) +static int mpeg4_decode_partitioned_mb(H263DecContext *const h) { - Mpeg4DecContext *ctx = s->avctx->priv_data; - int cbp, mb_type, use_intra_dc_vlc; - const int xy = s->mb_x + s->mb_y * s->mb_stride; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; - av_assert2(s == (void*)ctx); + const int mb_type = h->c.cur_pic.mb_type[xy]; + int cbp = h->c.cbp_table[xy]; - mb_type = s->cur_pic.mb_type[xy]; - cbp = s->cbp_table[xy]; + const int use_intra_dc_vlc = h->c.qscale < ctx->intra_dc_threshold; - use_intra_dc_vlc = s->qscale < ctx->intra_dc_threshold; + if (h->c.cur_pic.qscale_table[xy] != h->c.qscale) + ff_set_qscale(&h->c, h->c.cur_pic.qscale_table[xy]); - if (s->cur_pic.qscale_table[xy] != s->qscale) - ff_set_qscale(s, s->cur_pic.qscale_table[xy]); - - if (s->pict_type == AV_PICTURE_TYPE_P || - s->pict_type == AV_PICTURE_TYPE_S) { + if (h->c.pict_type == AV_PICTURE_TYPE_P || + h->c.pict_type == AV_PICTURE_TYPE_S) { int i; for (i = 0; i < 4; i++) { - s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0]; - s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1]; + h->c.mv[0][i][0] = h->c.cur_pic.motion_val[0][h->c.block_index[i]][0]; + h->c.mv[0][i][1] = h->c.cur_pic.motion_val[0][h->c.block_index[i]][1]; } - s->mb_intra = IS_INTRA(mb_type); + h->c.mb_intra = IS_INTRA(mb_type); if (IS_SKIP(mb_type)) { /* skip mb */ for (i = 0; i < 6; i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - if (s->pict_type == AV_PICTURE_TYPE_S + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE) { - s->mcsel = 1; - s->mb_skipped = 0; - s->cur_pic.mbskip_table[xy] = 0; + h->c.mcsel = 1; + h->c.mb_skipped = 0; + h->c.cur_pic.mbskip_table[xy] = 0; } else { - s->mcsel = 0; - s->mb_skipped = 1; - s->cur_pic.mbskip_table[xy] = 1; + h->c.mcsel = 0; + h->c.mb_skipped = 1; + h->c.cur_pic.mbskip_table[xy] = 1; } - } else if (s->mb_intra) { - s->ac_pred = IS_ACPRED(s->cur_pic.mb_type[xy]); - } else if (!s->mb_intra) { - // s->mcsel = 0; // FIXME do we need to init that? + } else if (h->c.mb_intra) { + h->c.ac_pred = IS_ACPRED(h->c.cur_pic.mb_type[xy]); + } else if (!h->c.mb_intra) { + // h->c.mcsel = 0; // FIXME do we need to init that? - s->mv_dir = MV_DIR_FORWARD; + h->c.mv_dir = MV_DIR_FORWARD; if (IS_8X8(mb_type)) { - s->mv_type = MV_TYPE_8X8; + h->c.mv_type = MV_TYPE_8X8; } else { - s->mv_type = MV_TYPE_16X16; + h->c.mv_type = MV_TYPE_16X16; } } } else { /* I-Frame */ - s->mb_intra = 1; - s->ac_pred = IS_ACPRED(s->cur_pic.mb_type[xy]); + h->c.mb_intra = 1; + h->c.ac_pred = IS_ACPRED(h->c.cur_pic.mb_type[xy]); } if (!IS_SKIP(mb_type)) { int i; - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); /* decode each block */ for (i = 0; i < 6; i++) { - if (mpeg4_decode_block(ctx, block[i], i, cbp & 32, s->mb_intra, + if (mpeg4_decode_block(ctx, h->block[i], i, cbp & 32, h->c.mb_intra, use_intra_dc_vlc, ctx->rvlc) < 0) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "texture corrupted at %d %d %d\n", - s->mb_x, s->mb_y, s->mb_intra); + h->c.mb_x, h->c.mb_y, h->c.mb_intra); return AVERROR_INVALIDDATA; } cbp += cbp; @@ -1632,301 +1723,300 @@ static int mpeg4_decode_partitioned_mb(MpegEncContext *s, int16_t block[6][64]) } /* per-MB end of slice check */ - if (--s->mb_num_left <= 0) { + if (--h->mb_num_left <= 0) { if (mpeg4_is_resync(ctx)) return SLICE_END; else return SLICE_NOEND; } else { if (mpeg4_is_resync(ctx)) { - const int delta = s->mb_x + 1 == s->mb_width ? 2 : 1; - if (s->cbp_table[xy + delta]) + const int delta = h->c.mb_x + 1 == h->c.mb_width ? 2 : 1; + if (h->c.cbp_table[xy + delta]) return SLICE_END; } return SLICE_OK; } } -static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) +static int mpeg4_decode_mb(H263DecContext *const h) { - Mpeg4DecContext *ctx = s->avctx->priv_data; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); int cbpc, cbpy, i, cbp, pred_x, pred_y, mx, my, dquant; static const int8_t quant_tab[4] = { -1, -2, 1, 2 }; - const int xy = s->mb_x + s->mb_y * s->mb_stride; + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; int next; - av_assert2(s == (void*)ctx); - av_assert2(s->h263_pred); + av_assert2(h->c.h263_pred); - if (s->pict_type == AV_PICTURE_TYPE_P || - s->pict_type == AV_PICTURE_TYPE_S) { + if (h->c.pict_type == AV_PICTURE_TYPE_P || + h->c.pict_type == AV_PICTURE_TYPE_S) { do { - if (get_bits1(&s->gb)) { + if (get_bits1(&h->gb)) { /* skip mb */ - s->mb_intra = 0; + h->c.mb_intra = 0; for (i = 0; i < 6; i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - if (s->pict_type == AV_PICTURE_TYPE_S && + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE) { - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_GMC | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; - s->mcsel = 1; - s->mv[0][0][0] = get_amv(ctx, 0); - s->mv[0][0][1] = get_amv(ctx, 1); - s->cur_pic.mbskip_table[xy] = 0; - s->mb_skipped = 0; + h->c.mcsel = 1; + h->c.mv[0][0][0] = get_amv(ctx, 0); + h->c.mv[0][0][1] = get_amv(ctx, 1); + h->c.cur_pic.mbskip_table[xy] = 0; + h->c.mb_skipped = 0; } else { - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; - s->mcsel = 0; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; - s->cur_pic.mbskip_table[xy] = 1; - s->mb_skipped = 1; + h->c.mcsel = 0; + h->c.mv[0][0][0] = 0; + h->c.mv[0][0][1] = 0; + h->c.cur_pic.mbskip_table[xy] = 1; + h->c.mb_skipped = 1; } goto end; } - cbpc = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); if (cbpc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "mcbpc damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "mcbpc damaged at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } } while (cbpc == 20); - s->bdsp.clear_blocks(s->block[0]); dquant = cbpc & 8; - s->mb_intra = ((cbpc & 4) != 0); - if (s->mb_intra) + h->c.mb_intra = ((cbpc & 4) != 0); + if (h->c.mb_intra) goto intra; + h->c.bdsp.clear_blocks(h->block[0]); - if (s->pict_type == AV_PICTURE_TYPE_S && + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE && (cbpc & 16) == 0) - s->mcsel = get_bits1(&s->gb); + h->c.mcsel = get_bits1(&h->gb); else - s->mcsel = 0; - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1) ^ 0x0F; + h->c.mcsel = 0; + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1) ^ 0x0F; if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "P cbpy damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "P cbpy damaged at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } cbp = (cbpc & 3) | (cbpy << 2); if (dquant) - ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); - if ((!s->progressive_sequence) && - (cbp || (s->workaround_bugs & FF_BUG_XVID_ILACE))) - s->interlaced_dct = get_bits1(&s->gb); + ff_set_qscale(&h->c, h->c.qscale + quant_tab[get_bits(&h->gb, 2)]); + if ((!h->c.progressive_sequence) && + (cbp || (h->c.workaround_bugs & FF_BUG_XVID_ILACE))) + h->c.interlaced_dct = get_bits1(&h->gb); - s->mv_dir = MV_DIR_FORWARD; + h->c.mv_dir = MV_DIR_FORWARD; if ((cbpc & 16) == 0) { - if (s->mcsel) { - s->cur_pic.mb_type[xy] = MB_TYPE_GMC | MB_TYPE_16x16 | + if (h->c.mcsel) { + h->c.cur_pic.mb_type[xy] = MB_TYPE_GMC | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; /* 16x16 global motion prediction */ - s->mv_type = MV_TYPE_16X16; + h->c.mv_type = MV_TYPE_16X16; mx = get_amv(ctx, 0); my = get_amv(ctx, 1); - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; - } else if ((!s->progressive_sequence) && get_bits1(&s->gb)) { - s->cur_pic.mb_type[xy] = MB_TYPE_16x8 | MB_TYPE_FORWARD_MV | + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; + } else if ((!h->c.progressive_sequence) && get_bits1(&h->gb)) { + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x8 | MB_TYPE_FORWARD_MV | MB_TYPE_INTERLACED; /* 16x8 field motion prediction */ - s->mv_type = MV_TYPE_FIELD; + h->c.mv_type = MV_TYPE_FIELD; - s->field_select[0][0] = get_bits1(&s->gb); - s->field_select[0][1] = get_bits1(&s->gb); + h->c.field_select[0][0] = get_bits1(&h->gb); + h->c.field_select[0][1] = get_bits1(&h->gb); - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); for (i = 0; i < 2; i++) { - mx = ff_h263_decode_motion(s, pred_x, s->f_code); + mx = ff_h263_decode_motion(h, pred_x, ctx->f_code); if (mx >= 0xffff) return AVERROR_INVALIDDATA; - my = ff_h263_decode_motion(s, pred_y / 2, s->f_code); + my = ff_h263_decode_motion(h, pred_y / 2, ctx->f_code); if (my >= 0xffff) return AVERROR_INVALIDDATA; - s->mv[0][i][0] = mx; - s->mv[0][i][1] = my; + h->c.mv[0][i][0] = mx; + h->c.mv[0][i][1] = my; } } else { - s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; /* 16x16 motion prediction */ - s->mv_type = MV_TYPE_16X16; - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - mx = ff_h263_decode_motion(s, pred_x, s->f_code); + h->c.mv_type = MV_TYPE_16X16; + ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); + mx = ff_h263_decode_motion(h, pred_x, ctx->f_code); if (mx >= 0xffff) return AVERROR_INVALIDDATA; - my = ff_h263_decode_motion(s, pred_y, s->f_code); + my = ff_h263_decode_motion(h, pred_y, ctx->f_code); if (my >= 0xffff) return AVERROR_INVALIDDATA; - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; } } else { - s->cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; - s->mv_type = MV_TYPE_8X8; + h->c.cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; + h->c.mv_type = MV_TYPE_8X8; for (i = 0; i < 4; i++) { - int16_t *mot_val = ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); - mx = ff_h263_decode_motion(s, pred_x, s->f_code); + int16_t *mot_val = ff_h263_pred_motion(&h->c, i, 0, &pred_x, &pred_y); + mx = ff_h263_decode_motion(h, pred_x, ctx->f_code); if (mx >= 0xffff) return AVERROR_INVALIDDATA; - my = ff_h263_decode_motion(s, pred_y, s->f_code); + my = ff_h263_decode_motion(h, pred_y, ctx->f_code); if (my >= 0xffff) return AVERROR_INVALIDDATA; - s->mv[0][i][0] = mx; - s->mv[0][i][1] = my; + h->c.mv[0][i][0] = mx; + h->c.mv[0][i][1] = my; mot_val[0] = mx; mot_val[1] = my; } } - } else if (s->pict_type == AV_PICTURE_TYPE_B) { + } else if (h->c.pict_type == AV_PICTURE_TYPE_B) { int modb1; // first bit of modb int modb2; // second bit of modb int mb_type; - s->mb_intra = 0; // B-frames never contain intra blocks - s->mcsel = 0; // ... true gmc blocks + h->c.mb_intra = 0; // B-frames never contain intra blocks + h->c.mcsel = 0; // ... true gmc blocks - if (s->mb_x == 0) { + if (h->c.mb_x == 0) { for (i = 0; i < 2; i++) { - s->last_mv[i][0][0] = - s->last_mv[i][0][1] = - s->last_mv[i][1][0] = - s->last_mv[i][1][1] = 0; + h->c.last_mv[i][0][0] = + h->c.last_mv[i][0][1] = + h->c.last_mv[i][1][0] = + h->c.last_mv[i][1][1] = 0; } - ff_thread_progress_await(&s->next_pic.ptr->progress, s->mb_y); + ff_thread_progress_await(&h->c.next_pic.ptr->progress, h->c.mb_y); } /* if we skipped it in the future P-frame than skip it now too */ - s->mb_skipped = s->next_pic.mbskip_table[s->mb_y * s->mb_stride + s->mb_x]; // Note, skiptab=0 if last was GMC + h->c.mb_skipped = h->c.next_pic.mbskip_table[h->c.mb_y * h->c.mb_stride + h->c.mb_x]; // Note, skiptab=0 if last was GMC - if (s->mb_skipped) { + if (h->c.mb_skipped) { /* skip mb */ for (i = 0; i < 6; i++) - s->block_last_index[i] = -1; + h->c.block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = - s->mv[0][0][1] = - s->mv[1][0][0] = - s->mv[1][0][1] = 0; - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = + h->c.mv[0][0][1] = + h->c.mv[1][0][0] = + h->c.mv[1][0][1] = 0; + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; goto end; } - modb1 = get_bits1(&s->gb); + modb1 = get_bits1(&h->gb); if (modb1) { // like MB_TYPE_B_DIRECT but no vectors coded mb_type = MB_TYPE_DIRECT2 | MB_TYPE_SKIP | MB_TYPE_BIDIR_MV; cbp = 0; } else { - modb2 = get_bits1(&s->gb); - mb_type = get_vlc2(&s->gb, mb_type_b_vlc, MB_TYPE_B_VLC_BITS, 1); + modb2 = get_bits1(&h->gb); + mb_type = get_vlc2(&h->gb, mb_type_b_vlc, MB_TYPE_B_VLC_BITS, 1); if (mb_type < 0) { - av_log(s->avctx, AV_LOG_ERROR, "illegal MB_type\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal MB_type\n"); return AVERROR_INVALIDDATA; } if (modb2) { cbp = 0; } else { - s->bdsp.clear_blocks(s->block[0]); - cbp = get_bits(&s->gb, 6); + h->c.bdsp.clear_blocks(h->block[0]); + cbp = get_bits(&h->gb, 6); } if ((!IS_DIRECT(mb_type)) && cbp) { - if (get_bits1(&s->gb)) - ff_set_qscale(s, s->qscale + get_bits1(&s->gb) * 4 - 2); + if (get_bits1(&h->gb)) + ff_set_qscale(&h->c, h->c.qscale + get_bits1(&h->gb) * 4 - 2); } - if (!s->progressive_sequence) { + if (!h->c.progressive_sequence) { if (cbp) - s->interlaced_dct = get_bits1(&s->gb); + h->c.interlaced_dct = get_bits1(&h->gb); - if (!IS_DIRECT(mb_type) && get_bits1(&s->gb)) { + if (!IS_DIRECT(mb_type) && get_bits1(&h->gb)) { mb_type |= MB_TYPE_16x8 | MB_TYPE_INTERLACED; mb_type &= ~MB_TYPE_16x16; if (HAS_FORWARD_MV(mb_type)) { - s->field_select[0][0] = get_bits1(&s->gb); - s->field_select[0][1] = get_bits1(&s->gb); + h->c.field_select[0][0] = get_bits1(&h->gb); + h->c.field_select[0][1] = get_bits1(&h->gb); } if (HAS_BACKWARD_MV(mb_type)) { - s->field_select[1][0] = get_bits1(&s->gb); - s->field_select[1][1] = get_bits1(&s->gb); + h->c.field_select[1][0] = get_bits1(&h->gb); + h->c.field_select[1][1] = get_bits1(&h->gb); } } } - s->mv_dir = 0; + h->c.mv_dir = 0; if ((mb_type & (MB_TYPE_DIRECT2 | MB_TYPE_INTERLACED)) == 0) { - s->mv_type = MV_TYPE_16X16; + h->c.mv_type = MV_TYPE_16X16; if (HAS_FORWARD_MV(mb_type)) { - s->mv_dir = MV_DIR_FORWARD; + h->c.mv_dir = MV_DIR_FORWARD; - mx = ff_h263_decode_motion(s, s->last_mv[0][0][0], s->f_code); - my = ff_h263_decode_motion(s, s->last_mv[0][0][1], s->f_code); - s->last_mv[0][1][0] = - s->last_mv[0][0][0] = - s->mv[0][0][0] = mx; - s->last_mv[0][1][1] = - s->last_mv[0][0][1] = - s->mv[0][0][1] = my; + mx = ff_h263_decode_motion(h, h->c.last_mv[0][0][0], ctx->f_code); + my = ff_h263_decode_motion(h, h->c.last_mv[0][0][1], ctx->f_code); + h->c.last_mv[0][1][0] = + h->c.last_mv[0][0][0] = + h->c.mv[0][0][0] = mx; + h->c.last_mv[0][1][1] = + h->c.last_mv[0][0][1] = + h->c.mv[0][0][1] = my; } if (HAS_BACKWARD_MV(mb_type)) { - s->mv_dir |= MV_DIR_BACKWARD; + h->c.mv_dir |= MV_DIR_BACKWARD; - mx = ff_h263_decode_motion(s, s->last_mv[1][0][0], s->b_code); - my = ff_h263_decode_motion(s, s->last_mv[1][0][1], s->b_code); - s->last_mv[1][1][0] = - s->last_mv[1][0][0] = - s->mv[1][0][0] = mx; - s->last_mv[1][1][1] = - s->last_mv[1][0][1] = - s->mv[1][0][1] = my; + mx = ff_h263_decode_motion(h, h->c.last_mv[1][0][0], ctx->b_code); + my = ff_h263_decode_motion(h, h->c.last_mv[1][0][1], ctx->b_code); + h->c.last_mv[1][1][0] = + h->c.last_mv[1][0][0] = + h->c.mv[1][0][0] = mx; + h->c.last_mv[1][1][1] = + h->c.last_mv[1][0][1] = + h->c.mv[1][0][1] = my; } } else if (!IS_DIRECT(mb_type)) { - s->mv_type = MV_TYPE_FIELD; + h->c.mv_type = MV_TYPE_FIELD; if (HAS_FORWARD_MV(mb_type)) { - s->mv_dir = MV_DIR_FORWARD; + h->c.mv_dir = MV_DIR_FORWARD; for (i = 0; i < 2; i++) { - mx = ff_h263_decode_motion(s, s->last_mv[0][i][0], s->f_code); - my = ff_h263_decode_motion(s, s->last_mv[0][i][1] / 2, s->f_code); - s->last_mv[0][i][0] = - s->mv[0][i][0] = mx; - s->last_mv[0][i][1] = (s->mv[0][i][1] = my) * 2; + mx = ff_h263_decode_motion(h, h->c.last_mv[0][i][0], ctx->f_code); + my = ff_h263_decode_motion(h, h->c.last_mv[0][i][1] / 2, ctx->f_code); + h->c.last_mv[0][i][0] = + h->c.mv[0][i][0] = mx; + h->c.last_mv[0][i][1] = (h->c.mv[0][i][1] = my) * 2; } } if (HAS_BACKWARD_MV(mb_type)) { - s->mv_dir |= MV_DIR_BACKWARD; + h->c.mv_dir |= MV_DIR_BACKWARD; for (i = 0; i < 2; i++) { - mx = ff_h263_decode_motion(s, s->last_mv[1][i][0], s->b_code); - my = ff_h263_decode_motion(s, s->last_mv[1][i][1] / 2, s->b_code); - s->last_mv[1][i][0] = - s->mv[1][i][0] = mx; - s->last_mv[1][i][1] = (s->mv[1][i][1] = my) * 2; + mx = ff_h263_decode_motion(h, h->c.last_mv[1][i][0], ctx->b_code); + my = ff_h263_decode_motion(h, h->c.last_mv[1][i][1] / 2, ctx->b_code); + h->c.last_mv[1][i][0] = + h->c.mv[1][i][0] = mx; + h->c.last_mv[1][i][1] = (h->c.mv[1][i][1] = my) * 2; } } } @@ -1937,56 +2027,56 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) mx = my = 0; } else { - mx = ff_h263_decode_motion(s, 0, 1); - my = ff_h263_decode_motion(s, 0, 1); + mx = ff_h263_decode_motion(h, 0, 1); + my = ff_h263_decode_motion(h, 0, 1); } - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; - mb_type |= ff_mpeg4_set_direct_mv(s, mx, my); + h->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; + mb_type |= ff_mpeg4_set_direct_mv(&h->c, mx, my); } - s->cur_pic.mb_type[xy] = mb_type; + h->c.cur_pic.mb_type[xy] = mb_type; } else { /* I-Frame */ int use_intra_dc_vlc; do { - cbpc = get_vlc2(&s->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); if (cbpc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "I cbpc damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "I cbpc damaged at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } } while (cbpc == 8); dquant = cbpc & 4; - s->mb_intra = 1; + h->c.mb_intra = 1; intra: - s->ac_pred = get_bits1(&s->gb); - if (s->ac_pred) - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; + h->c.ac_pred = get_bits1(&h->gb); + if (h->c.ac_pred) + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; else - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA; - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "I cbpy damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "I cbpy damaged at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } cbp = (cbpc & 3) | (cbpy << 2); - use_intra_dc_vlc = s->qscale < ctx->intra_dc_threshold; + use_intra_dc_vlc = h->c.qscale < ctx->intra_dc_threshold; if (dquant) - ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); + ff_set_qscale(&h->c, h->c.qscale + quant_tab[get_bits(&h->gb, 2)]); - if (!s->progressive_sequence) - s->interlaced_dct = get_bits1(&s->gb); + if (!h->c.progressive_sequence) + h->c.interlaced_dct = get_bits1(&h->gb); - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); /* decode each block */ for (i = 0; i < 6; i++) { - if (mpeg4_decode_block(ctx, block[i], i, cbp & 32, + if (mpeg4_decode_block(ctx, h->block[i], i, cbp & 32, 1, use_intra_dc_vlc, 0) < 0) return AVERROR_INVALIDDATA; cbp += cbp; @@ -1996,7 +2086,7 @@ intra: /* decode each block */ for (i = 0; i < 6; i++) { - if (mpeg4_decode_block(ctx, block[i], i, cbp & 32, 0, 0, 0) < 0) + if (mpeg4_decode_block(ctx, h->block[i], i, cbp & 32, 0, 0, 0) < 0) return AVERROR_INVALIDDATA; cbp += cbp; } @@ -2005,18 +2095,18 @@ end: /* per-MB end of slice check */ next = mpeg4_is_resync(ctx); if (next) { - if (s->mb_x + s->mb_y*s->mb_width + 1 > next && (s->avctx->err_recognition & AV_EF_AGGRESSIVE)) { + if (h->c.mb_x + h->c.mb_y*h->c.mb_width + 1 > next && (h->c.avctx->err_recognition & AV_EF_AGGRESSIVE)) { return AVERROR_INVALIDDATA; - } else if (s->mb_x + s->mb_y*s->mb_width + 1 >= next) + } else if (h->c.mb_x + h->c.mb_y*h->c.mb_width + 1 >= next) return SLICE_END; - if (s->pict_type == AV_PICTURE_TYPE_B) { - const int delta = s->mb_x + 1 == s->mb_width ? 2 : 1; - ff_thread_progress_await(&s->next_pic.ptr->progress, - (s->mb_x + delta >= s->mb_width) - ? FFMIN(s->mb_y + 1, s->mb_height - 1) - : s->mb_y); - if (s->next_pic.mbskip_table[xy + delta]) + if (h->c.pict_type == AV_PICTURE_TYPE_B) { + const int delta = h->c.mb_x + 1 == h->c.mb_width ? 2 : 1; + ff_thread_progress_await(&h->c.next_pic.ptr->progress, + (h->c.mb_x + delta >= h->c.mb_width) + ? FFMIN(h->c.mb_y + 1, h->c.mb_height - 1) + : h->c.mb_y); + if (h->c.next_pic.mbskip_table[xy + delta]) return SLICE_OK; } @@ -2063,19 +2153,19 @@ static const uint8_t ac_state_tab[22][2] = {0, 11} }; -static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n) +static int mpeg4_decode_studio_block(Mpeg4DecContext *const ctx, int32_t block[64], int n) { - Mpeg4DecContext *ctx = s->avctx->priv_data; + H263DecContext *const h = &ctx->h; int cc, dct_dc_size, dct_diff, code, j, idx = 1, group = 0, run = 0, additional_code_len, sign, mismatch; const VLCElem *cur_vlc = studio_intra_tab[0]; - const uint8_t *const scantable = s->intra_scantable.permutated; + const uint8_t *const scantable = h->c.intra_scantable.permutated; const uint16_t *quant_matrix; uint32_t flc; - const int min = -1 * (1 << (s->avctx->bits_per_raw_sample + 6)); - const int max = ((1 << (s->avctx->bits_per_raw_sample + 6)) - 1); - int shift = 3 - s->dct_precision; + const int min = -1 * (1 << (h->c.avctx->bits_per_raw_sample + 6)); + const int max = ((1 << (h->c.avctx->bits_per_raw_sample + 6)) - 1); + int shift = 3 - ctx->dct_precision; mismatch = 1; @@ -2083,35 +2173,35 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n if (n < 4) { cc = 0; - dct_dc_size = get_vlc2(&s->gb, studio_luma_dc, STUDIO_INTRA_BITS, 2); - quant_matrix = s->intra_matrix; + dct_dc_size = get_vlc2(&h->gb, studio_luma_dc, STUDIO_INTRA_BITS, 2); + quant_matrix = h->c.intra_matrix; } else { cc = (n & 1) + 1; if (ctx->rgb) - dct_dc_size = get_vlc2(&s->gb, studio_luma_dc, STUDIO_INTRA_BITS, 2); + dct_dc_size = get_vlc2(&h->gb, studio_luma_dc, STUDIO_INTRA_BITS, 2); else - dct_dc_size = get_vlc2(&s->gb, studio_chroma_dc, STUDIO_INTRA_BITS, 2); - quant_matrix = s->chroma_intra_matrix; + dct_dc_size = get_vlc2(&h->gb, studio_chroma_dc, STUDIO_INTRA_BITS, 2); + quant_matrix = h->c.chroma_intra_matrix; } if (dct_dc_size == 0) { dct_diff = 0; } else { - dct_diff = get_xbits(&s->gb, dct_dc_size); + dct_diff = get_xbits(&h->gb, dct_dc_size); if (dct_dc_size > 8) { - if(!check_marker(s->avctx, &s->gb, "dct_dc_size > 8")) + if(!check_marker(h->c.avctx, &h->gb, "dct_dc_size > 8")) return AVERROR_INVALIDDATA; } } - s->last_dc[cc] += dct_diff; + h->last_dc[cc] += dct_diff; - if (s->mpeg_quant) - block[0] = s->last_dc[cc] * (8 >> s->intra_dc_precision); + if (ctx->mpeg_quant) + block[0] = h->last_dc[cc] * (8 >> h->c.intra_dc_precision); else - block[0] = s->last_dc[cc] * (8 >> s->intra_dc_precision) * (8 >> s->dct_precision); + block[0] = h->last_dc[cc] * (8 >> h->c.intra_dc_precision) * (8 >> ctx->dct_precision); /* TODO: support mpeg_quant for AC coefficients */ block[0] = av_clip(block[0], min, max); @@ -2119,10 +2209,10 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n /* AC Coefficients */ while (1) { - group = get_vlc2(&s->gb, cur_vlc, STUDIO_INTRA_BITS, 2); + group = get_vlc2(&h->gb, cur_vlc, STUDIO_INTRA_BITS, 2); if (group < 0) { - av_log(s->avctx, AV_LOG_ERROR, "illegal ac coefficient group vlc\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal ac coefficient group vlc\n"); return AVERROR_INVALIDDATA; } @@ -2136,12 +2226,12 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n /* Zero run length (Table B.47) */ run = 1 << additional_code_len; if (additional_code_len) - run += get_bits(&s->gb, additional_code_len); + run += get_bits(&h->gb, additional_code_len); idx += run; continue; } else if (group >= 7 && group <= 12) { /* Zero run length and +/-1 level (Table B.48) */ - code = get_bits(&s->gb, additional_code_len); + code = get_bits(&h->gb, additional_code_len); sign = code & 1; code >>= 1; run = (1 << (additional_code_len - 1)) + code; @@ -2155,20 +2245,20 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n if (idx > 63) return AVERROR_INVALIDDATA; j = scantable[idx++]; - block[j] = get_xbits(&s->gb, additional_code_len); + block[j] = get_xbits(&h->gb, additional_code_len); } else if (group == 21) { /* Escape */ if (idx > 63) return AVERROR_INVALIDDATA; j = scantable[idx++]; - additional_code_len = s->avctx->bits_per_raw_sample + s->dct_precision + 4; - flc = get_bits(&s->gb, additional_code_len); + additional_code_len = h->c.avctx->bits_per_raw_sample + ctx->dct_precision + 4; + flc = get_bits(&h->gb, additional_code_len); if (flc >> (additional_code_len-1)) block[j] = -1 * (( flc ^ ((1 << additional_code_len) -1)) + 1); else block[j] = flc; } - block[j] = ((block[j] * quant_matrix[j] * s->qscale) * (1 << shift)) / 16; + block[j] = ((block[j] * quant_matrix[j] * h->c.qscale) * (1 << shift)) / 16; block[j] = av_clip(block[j], min, max); mismatch ^= block[j]; } @@ -2178,24 +2268,26 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n return 0; } -static int mpeg4_decode_dpcm_macroblock(MpegEncContext *s, int16_t macroblock[256], int n) +static int mpeg4_decode_dpcm_macroblock(Mpeg4DecContext *const ctx, + int16_t macroblock[256], int n) { - int i, j, w, h, idx = 0; + H263DecContext *const h = &ctx->h; + int j, w, height, idx = 0; int block_mean, rice_parameter, rice_prefix_code, rice_suffix_code, dpcm_residual, left, top, topleft, min_left_top, max_left_top, p, p2, output; - h = 16 >> (n ? s->chroma_y_shift : 0); - w = 16 >> (n ? s->chroma_x_shift : 0); + height = 16 >> (n ? h->c.chroma_y_shift : 0); + w = 16 >> (n ? h->c.chroma_x_shift : 0); - block_mean = get_bits(&s->gb, s->avctx->bits_per_raw_sample); + block_mean = get_bits(&h->gb, h->c.avctx->bits_per_raw_sample); if (block_mean == 0){ - av_log(s->avctx, AV_LOG_ERROR, "Forbidden block_mean\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Forbidden block_mean\n"); return AVERROR_INVALIDDATA; } - s->last_dc[n] = block_mean * (1 << (s->dct_precision + s->intra_dc_precision)); + h->last_dc[n] = block_mean * (1 << (ctx->dct_precision + h->c.intra_dc_precision)); - rice_parameter = get_bits(&s->gb, 4); + rice_parameter = get_bits(&h->gb, 4); if (rice_parameter == 0) { - av_log(s->avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); return AVERROR_INVALIDDATA; } @@ -2203,29 +2295,29 @@ static int mpeg4_decode_dpcm_macroblock(MpegEncContext *s, int16_t macroblock[25 rice_parameter = 0; if (rice_parameter > 11) { - av_log(s->avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); return AVERROR_INVALIDDATA; } - for (i = 0; i < h; i++) { - output = 1 << (s->avctx->bits_per_raw_sample - 1); - top = 1 << (s->avctx->bits_per_raw_sample - 1); + for (int i = 0; i < height; i++) { + output = 1 << (h->c.avctx->bits_per_raw_sample - 1); + top = 1 << (h->c.avctx->bits_per_raw_sample - 1); for (j = 0; j < w; j++) { left = output; topleft = top; - rice_prefix_code = get_unary(&s->gb, 1, 12); + rice_prefix_code = get_unary(&h->gb, 1, 12); /* Escape */ if (rice_prefix_code == 11) - dpcm_residual = get_bits(&s->gb, s->avctx->bits_per_raw_sample); + dpcm_residual = get_bits(&h->gb, h->c.avctx->bits_per_raw_sample); else { if (rice_prefix_code == 12) { - av_log(s->avctx, AV_LOG_ERROR, "Forbidden rice_prefix_code\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Forbidden rice_prefix_code\n"); return AVERROR_INVALIDDATA; } - rice_suffix_code = get_bitsz(&s->gb, rice_parameter); + rice_suffix_code = get_bitsz(&h->gb, rice_parameter); dpcm_residual = (rice_prefix_code << rice_parameter) + rice_suffix_code; } @@ -2254,56 +2346,56 @@ static int mpeg4_decode_dpcm_macroblock(MpegEncContext *s, int16_t macroblock[25 if (p2 > p) dpcm_residual *= -1; - macroblock[idx++] = output = (dpcm_residual + p) & ((1 << s->avctx->bits_per_raw_sample) - 1); + macroblock[idx++] = output = (dpcm_residual + p) & ((1 << h->c.avctx->bits_per_raw_sample) - 1); } } return 0; } -static int mpeg4_decode_studio_mb(MpegEncContext *s, int16_t block_[12][64]) +static int mpeg4_decode_studio_mb(H263DecContext *const h) { - Mpeg4DecContext *const ctx = (Mpeg4DecContext*)s; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); int i; ctx->dpcm_direction = 0; /* StudioMacroblock */ /* Assumes I-VOP */ - s->mb_intra = 1; - if (get_bits1(&s->gb)) { /* compression_mode */ + h->c.mb_intra = 1; + if (get_bits1(&h->gb)) { /* compression_mode */ /* DCT */ /* macroblock_type, 1 or 2-bit VLC */ - if (!get_bits1(&s->gb)) { - skip_bits1(&s->gb); - s->qscale = mpeg_get_qscale(s); + if (!get_bits1(&h->gb)) { + skip_bits1(&h->gb); + h->c.qscale = mpeg_get_qscale(&h->gb, h->c.q_scale_type); } - for (i = 0; i < mpeg4_block_count[s->chroma_format]; i++) { - if (mpeg4_decode_studio_block(s, ctx->block32[i], i) < 0) + for (i = 0; i < mpeg4_block_count[h->c.chroma_format]; i++) { + if (mpeg4_decode_studio_block(ctx, ctx->block32[i], i) < 0) return AVERROR_INVALIDDATA; } } else { /* DPCM */ - check_marker(s->avctx, &s->gb, "DPCM block start"); - ctx->dpcm_direction = get_bits1(&s->gb) ? -1 : 1; + check_marker(h->c.avctx, &h->gb, "DPCM block start"); + ctx->dpcm_direction = get_bits1(&h->gb) ? -1 : 1; for (i = 0; i < 3; i++) { - if (mpeg4_decode_dpcm_macroblock(s, ctx->dpcm_macroblock[i], i) < 0) + if (mpeg4_decode_dpcm_macroblock(ctx, ctx->dpcm_macroblock[i], i) < 0) return AVERROR_INVALIDDATA; } } - if (get_bits_left(&s->gb) >= 24 && show_bits(&s->gb, 23) == 0) { - next_start_code_studio(&s->gb); + if (get_bits_left(&h->gb) >= 24 && show_bits(&h->gb, 23) == 0) { + next_start_code_studio(&h->gb); return SLICE_END; } //vcon-stp9L1.bits (first frame) - if (get_bits_left(&s->gb) == 0) + if (get_bits_left(&h->gb) == 0) return SLICE_END; //vcon-stp2L1.bits, vcon-stp3L1.bits, vcon-stp6L1.bits, vcon-stp7L1.bits, vcon-stp8L1.bits, vcon-stp10L1.bits (first frame) - if (get_bits_left(&s->gb) < 8U && show_bits(&s->gb, get_bits_left(&s->gb)) == 0) + if (get_bits_left(&h->gb) < 8U && show_bits(&h->gb, get_bits_left(&h->gb)) == 0) return SLICE_END; return SLICE_OK; @@ -2462,7 +2554,7 @@ static void extension_and_user_data(MpegEncContext *s, GetBitContext *gb, int id static int decode_studio_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + MPVContext *const s = &ctx->h.c; int width, height, aspect_ratio_info; int bits_per_raw_sample; int rgb, chroma_format; @@ -2538,7 +2630,7 @@ static int decode_studio_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) skip_bits(gb, 15); /* latter_half_vbv_occupancy */ check_marker(s->avctx, gb, "after latter_half_vbv_occupancy"); s->low_delay = get_bits1(gb); - s->mpeg_quant = get_bits1(gb); /* mpeg2_stream */ + ctx->mpeg_quant = get_bits1(gb); /* mpeg2_stream */ next_start_code_studio(gb); extension_and_user_data(s, gb, 2); @@ -2548,7 +2640,7 @@ static int decode_studio_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; int width, height, vo_ver_id, aspect_ratio_info; /* vol header */ @@ -2562,12 +2654,12 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) */ if (ctx->vo_type == CORE_STUDIO_VO_TYPE || ctx->vo_type == SIMPLE_STUDIO_VO_TYPE) { - if (s->avctx->profile != AV_PROFILE_UNKNOWN && s->avctx->profile != AV_PROFILE_MPEG4_SIMPLE_STUDIO) + if (h->c.avctx->profile != AV_PROFILE_UNKNOWN && h->c.avctx->profile != AV_PROFILE_MPEG4_SIMPLE_STUDIO) return AVERROR_INVALIDDATA; - s->studio_profile = 1; - s->avctx->profile = AV_PROFILE_MPEG4_SIMPLE_STUDIO; + h->c.studio_profile = 1; + h->c.avctx->profile = AV_PROFILE_MPEG4_SIMPLE_STUDIO; return decode_studio_vol_header(ctx, gb); - } else if (s->studio_profile) { + } else if (h->c.studio_profile) { return AVERROR_PATCHWELCOME; } @@ -2579,97 +2671,97 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) } aspect_ratio_info = get_bits(gb, 4); if (aspect_ratio_info == FF_ASPECT_EXTENDED) { - s->avctx->sample_aspect_ratio.num = get_bits(gb, 8); // par_width - s->avctx->sample_aspect_ratio.den = get_bits(gb, 8); // par_height + h->c.avctx->sample_aspect_ratio.num = get_bits(gb, 8); // par_width + h->c.avctx->sample_aspect_ratio.den = get_bits(gb, 8); // par_height } else { - s->avctx->sample_aspect_ratio = ff_h263_pixel_aspect[aspect_ratio_info]; + h->c.avctx->sample_aspect_ratio = ff_h263_pixel_aspect[aspect_ratio_info]; } if ((ctx->vol_control_parameters = get_bits1(gb))) { /* vol control parameter */ int chroma_format = get_bits(gb, 2); if (chroma_format != CHROMA_420) - av_log(s->avctx, AV_LOG_ERROR, "illegal chroma format\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal chroma format\n"); - s->low_delay = get_bits1(gb); + h->c.low_delay = get_bits1(gb); if (get_bits1(gb)) { /* vbv parameters */ get_bits(gb, 15); /* first_half_bitrate */ - check_marker(s->avctx, gb, "after first_half_bitrate"); + check_marker(h->c.avctx, gb, "after first_half_bitrate"); get_bits(gb, 15); /* latter_half_bitrate */ - check_marker(s->avctx, gb, "after latter_half_bitrate"); + check_marker(h->c.avctx, gb, "after latter_half_bitrate"); get_bits(gb, 15); /* first_half_vbv_buffer_size */ - check_marker(s->avctx, gb, "after first_half_vbv_buffer_size"); + check_marker(h->c.avctx, gb, "after first_half_vbv_buffer_size"); get_bits(gb, 3); /* latter_half_vbv_buffer_size */ get_bits(gb, 11); /* first_half_vbv_occupancy */ - check_marker(s->avctx, gb, "after first_half_vbv_occupancy"); + check_marker(h->c.avctx, gb, "after first_half_vbv_occupancy"); get_bits(gb, 15); /* latter_half_vbv_occupancy */ - check_marker(s->avctx, gb, "after latter_half_vbv_occupancy"); + check_marker(h->c.avctx, gb, "after latter_half_vbv_occupancy"); } } else { /* is setting low delay flag only once the smartest thing to do? * low delay detection will not be overridden. */ - if (s->picture_number == 0) { + if (h->picture_number == 0) { switch (ctx->vo_type) { case SIMPLE_VO_TYPE: case ADV_SIMPLE_VO_TYPE: - s->low_delay = 1; + h->c.low_delay = 1; break; default: - s->low_delay = 0; + h->c.low_delay = 0; } } } ctx->shape = get_bits(gb, 2); /* vol shape */ if (ctx->shape != RECT_SHAPE) - av_log(s->avctx, AV_LOG_ERROR, "only rectangular vol supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "only rectangular vol supported\n"); if (ctx->shape == GRAY_SHAPE && vo_ver_id != 1) { - av_log(s->avctx, AV_LOG_ERROR, "Gray shape not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Gray shape not supported\n"); skip_bits(gb, 4); /* video_object_layer_shape_extension */ } - check_marker(s->avctx, gb, "before time_increment_resolution"); + check_marker(h->c.avctx, gb, "before time_increment_resolution"); - s->avctx->framerate.num = get_bits(gb, 16); - if (!s->avctx->framerate.num) { - av_log(s->avctx, AV_LOG_ERROR, "framerate==0\n"); + h->c.avctx->framerate.num = get_bits(gb, 16); + if (!h->c.avctx->framerate.num) { + av_log(h->c.avctx, AV_LOG_ERROR, "framerate==0\n"); return AVERROR_INVALIDDATA; } - ctx->time_increment_bits = av_log2(s->avctx->framerate.num - 1) + 1; + ctx->time_increment_bits = av_log2(h->c.avctx->framerate.num - 1) + 1; if (ctx->time_increment_bits < 1) ctx->time_increment_bits = 1; - check_marker(s->avctx, gb, "before fixed_vop_rate"); + check_marker(h->c.avctx, gb, "before fixed_vop_rate"); if (get_bits1(gb) != 0) /* fixed_vop_rate */ - s->avctx->framerate.den = get_bits(gb, ctx->time_increment_bits); + h->c.avctx->framerate.den = get_bits(gb, ctx->time_increment_bits); else - s->avctx->framerate.den = 1; + h->c.avctx->framerate.den = 1; ctx->t_frame = 0; if (ctx->shape != BIN_ONLY_SHAPE) { if (ctx->shape == RECT_SHAPE) { - check_marker(s->avctx, gb, "before width"); + check_marker(h->c.avctx, gb, "before width"); width = get_bits(gb, 13); - check_marker(s->avctx, gb, "before height"); + check_marker(h->c.avctx, gb, "before height"); height = get_bits(gb, 13); - check_marker(s->avctx, gb, "after height"); + check_marker(h->c.avctx, gb, "after height"); if (width && height && /* they should be non zero but who knows */ - !(s->width && s->codec_tag == AV_RL32("MP4S"))) { - if (s->width && s->height && - (s->width != width || s->height != height)) - s->context_reinit = 1; - s->width = width; - s->height = height; + !(h->c.width && h->c.codec_tag == AV_RL32("MP4S"))) { + if (h->c.width && h->c.height && + (h->c.width != width || h->c.height != height)) + h->c.context_reinit = 1; + h->c.width = width; + h->c.height = height; } } - s->progressive_sequence = - s->progressive_frame = get_bits1(gb) ^ 1; - s->interlaced_dct = 0; - if (!get_bits1(gb) && (s->avctx->debug & FF_DEBUG_PICT_INFO)) - av_log(s->avctx, AV_LOG_INFO, /* OBMC Disable */ + h->c.progressive_sequence = + h->c.progressive_frame = get_bits1(gb) ^ 1; + h->c.interlaced_dct = 0; + if (!get_bits1(gb) && (h->c.avctx->debug & FF_DEBUG_PICT_INFO)) + av_log(h->c.avctx, AV_LOG_INFO, /* OBMC Disable */ "MPEG-4 OBMC not supported (very likely buggy encoder)\n"); if (vo_ver_id == 1) ctx->vol_sprite_usage = get_bits1(gb); /* vol_sprite_usage */ @@ -2677,22 +2769,22 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) ctx->vol_sprite_usage = get_bits(gb, 2); /* vol_sprite_usage */ if (ctx->vol_sprite_usage == STATIC_SPRITE) - av_log(s->avctx, AV_LOG_ERROR, "Static Sprites not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Static Sprites not supported\n"); if (ctx->vol_sprite_usage == STATIC_SPRITE || ctx->vol_sprite_usage == GMC_SPRITE) { if (ctx->vol_sprite_usage == STATIC_SPRITE) { skip_bits(gb, 13); // sprite_width - check_marker(s->avctx, gb, "after sprite_width"); + check_marker(h->c.avctx, gb, "after sprite_width"); skip_bits(gb, 13); // sprite_height - check_marker(s->avctx, gb, "after sprite_height"); + check_marker(h->c.avctx, gb, "after sprite_height"); skip_bits(gb, 13); // sprite_left - check_marker(s->avctx, gb, "after sprite_left"); + check_marker(h->c.avctx, gb, "after sprite_left"); skip_bits(gb, 13); // sprite_top - check_marker(s->avctx, gb, "after sprite_top"); + check_marker(h->c.avctx, gb, "after sprite_top"); } ctx->num_sprite_warping_points = get_bits(gb, 6); if (ctx->num_sprite_warping_points > 3) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "%d sprite_warping_points\n", ctx->num_sprite_warping_points); ctx->num_sprite_warping_points = 0; @@ -2708,9 +2800,9 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) if (get_bits1(gb) == 1) { /* not_8_bit */ ctx->quant_precision = get_bits(gb, 4); /* quant_precision */ if (get_bits(gb, 4) != 8) /* bits_per_pixel */ - av_log(s->avctx, AV_LOG_ERROR, "N-bit not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "N-bit not supported\n"); if (ctx->quant_precision != 5) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "quant precision %d\n", ctx->quant_precision); if (ctx->quant_precision < 3 || ctx->quant_precision > 9) ctx->quant_precision = 5; @@ -2720,10 +2812,10 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) // FIXME a bunch of grayscale shape things - if ((s->mpeg_quant = get_bits1(gb))) { /* vol_quant_type */ + if ((ctx->mpeg_quant = get_bits1(gb))) { /* vol_quant_type */ int i, v; - mpeg4_load_default_matrices(s); + mpeg4_load_default_matrices(&h->c); /* load custom intra matrix */ if (get_bits1(gb)) { @@ -2731,7 +2823,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) for (i = 0; i < 64; i++) { int j; if (get_bits_left(gb) < 8) { - av_log(s->avctx, AV_LOG_ERROR, "insufficient data for custom matrix\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "insufficient data for custom matrix\n"); return AVERROR_INVALIDDATA; } v = get_bits(gb, 8); @@ -2739,16 +2831,14 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) break; last = v; - j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; - s->intra_matrix[j] = last; - s->chroma_intra_matrix[j] = last; + j = h->c.idsp.idct_permutation[ff_zigzag_direct[i]]; + h->c.intra_matrix[j] = last; } /* replicate last value */ for (; i < 64; i++) { - int j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; - s->intra_matrix[j] = last; - s->chroma_intra_matrix[j] = last; + int j = h->c.idsp.idct_permutation[ff_zigzag_direct[i]]; + h->c.intra_matrix[j] = last; } } @@ -2758,7 +2848,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) for (i = 0; i < 64; i++) { int j; if (get_bits_left(gb) < 8) { - av_log(s->avctx, AV_LOG_ERROR, "insufficient data for custom matrix\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "insufficient data for custom matrix\n"); return AVERROR_INVALIDDATA; } v = get_bits(gb, 8); @@ -2766,16 +2856,14 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) break; last = v; - j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; - s->inter_matrix[j] = v; - s->chroma_inter_matrix[j] = v; + j = h->c.idsp.idct_permutation[ff_zigzag_direct[i]]; + h->c.inter_matrix[j] = v; } /* replicate last value */ for (; i < 64; i++) { - int j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; - s->inter_matrix[j] = last; - s->chroma_inter_matrix[j] = last; + int j = h->c.idsp.idct_permutation[ff_zigzag_direct[i]]; + h->c.inter_matrix[j] = last; } } @@ -2783,12 +2871,12 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) } if (vo_ver_id != 1) - s->quarter_sample = get_bits1(gb); + h->c.quarter_sample = get_bits1(gb); else - s->quarter_sample = 0; + h->c.quarter_sample = 0; if (get_bits_left(gb) < 4) { - av_log(s->avctx, AV_LOG_ERROR, "VOL Header truncated\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "VOL Header truncated\n"); return AVERROR_INVALIDDATA; } @@ -2810,7 +2898,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* inter4v_blocks */ ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* not coded blocks */ } - if (!check_marker(s->avctx, gb, "in complexity estimation part 1")) { + if (!check_marker(h->c.avctx, gb, "in complexity estimation part 1")) { skip_bits_long(gb, pos - get_bits_count(gb)); goto no_cplx_est; } @@ -2828,7 +2916,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* halfpel2 */ ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* halfpel4 */ } - if (!check_marker(s->avctx, gb, "in complexity estimation part 2")) { + if (!check_marker(h->c.avctx, gb, "in complexity estimation part 2")) { skip_bits_long(gb, pos - get_bits_count(gb)); goto no_cplx_est; } @@ -2837,7 +2925,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* qpel */ } } else - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "Invalid Complexity estimation method %d\n", estimation_method); } else { @@ -2850,19 +2938,19 @@ no_cplx_est: ctx->resync_marker = !get_bits1(gb); /* resync_marker_disabled */ - s->data_partitioning = get_bits1(gb); - if (s->data_partitioning) + h->data_partitioning = get_bits1(gb); + if (h->data_partitioning) ctx->rvlc = get_bits1(gb); if (vo_ver_id != 1) { ctx->new_pred = get_bits1(gb); if (ctx->new_pred) { - av_log(s->avctx, AV_LOG_ERROR, "new pred not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "new pred not supported\n"); skip_bits(gb, 2); /* requested upstream message type */ skip_bits1(gb); /* newpred segment type */ } if (get_bits1(gb)) // reduced_res_vop - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "reduced resolution VOP not supported\n"); } else { ctx->new_pred = 0; @@ -2893,21 +2981,23 @@ no_cplx_est: ctx->scalability = 0; *gb = bak; } else - av_log(s->avctx, AV_LOG_ERROR, "scalability not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "scalability not supported\n"); // bin shape stuff FIXME } } - if (s->avctx->debug&FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, "tb %d/%d, tincrbits:%d, qp_prec:%d, ps:%d, low_delay:%d %s%s%s%s\n", - s->avctx->framerate.den, s->avctx->framerate.num, + if (h->c.avctx->debug&FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "tb %d/%d, tincrbits:%d, qp_prec:%d, ps:%d, low_delay:%d %s%s%s%s\n", + h->c.avctx->framerate.den, h->c.avctx->framerate.num, ctx->time_increment_bits, ctx->quant_precision, - s->progressive_sequence, - s->low_delay, - ctx->scalability ? "scalability " :"" , s->quarter_sample ? "qpel " : "", - s->data_partitioning ? "partition " : "", ctx->rvlc ? "rvlc " : "" + h->c.progressive_sequence, + h->c.low_delay, + ctx->scalability ? "scalability " :"" , + h->c.quarter_sample ? "qpel " : "", + h->data_partitioning ? "partition " : "", + ctx->rvlc ? "rvlc " : "" ); } @@ -2920,7 +3010,7 @@ no_cplx_est: */ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; char buf[256]; int i; int e; @@ -2941,7 +3031,7 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb) if (e >= 2) { ctx->divx_version = ver; ctx->divx_build = build; - s->divx_packed = e == 3 && last == 'p'; + h->divx_packed = e == 3 && last == 'p'; } /* libavcodec detection */ @@ -2952,7 +3042,7 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb) e = sscanf(buf, "Lavc%d.%d.%d", &ver, &ver2, &ver3) + 1; if (e > 1) { if (ver > 0xFFU || ver2 > 0xFFU || ver3 > 0xFFU) { - av_log(s->avctx, AV_LOG_WARNING, + av_log(h->c.avctx, AV_LOG_WARNING, "Unknown Lavc version string encountered, %d.%d.%d; " "clamping sub-version values to 8-bits.\n", ver, ver2, ver3); @@ -2975,160 +3065,43 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb) return 0; } -int ff_mpeg4_workaround_bugs(AVCodecContext *avctx) -{ - Mpeg4DecContext *ctx = avctx->priv_data; - MpegEncContext *s = &ctx->m; - - if (ctx->xvid_build == -1 && ctx->divx_version == -1 && ctx->lavc_build == -1) { - if (s->codec_tag == AV_RL32("XVID") || - s->codec_tag == AV_RL32("XVIX") || - s->codec_tag == AV_RL32("RMP4") || - s->codec_tag == AV_RL32("ZMP4") || - s->codec_tag == AV_RL32("SIPP")) - ctx->xvid_build = 0; - } - - if (ctx->xvid_build == -1 && ctx->divx_version == -1 && ctx->lavc_build == -1) - if (s->codec_tag == AV_RL32("DIVX") && ctx->vo_type == 0 && - ctx->vol_control_parameters == 0) - ctx->divx_version = 400; // divx 4 - - if (ctx->xvid_build >= 0 && ctx->divx_version >= 0) { - ctx->divx_version = - ctx->divx_build = -1; - } - - if (s->workaround_bugs & FF_BUG_AUTODETECT) { - if (s->codec_tag == AV_RL32("XVIX")) - s->workaround_bugs |= FF_BUG_XVID_ILACE; - - if (s->codec_tag == AV_RL32("UMP4")) - s->workaround_bugs |= FF_BUG_UMP4; - - if (ctx->divx_version >= 500 && ctx->divx_build < 1814) - s->workaround_bugs |= FF_BUG_QPEL_CHROMA; - - if (ctx->divx_version > 502 && ctx->divx_build < 1814) - s->workaround_bugs |= FF_BUG_QPEL_CHROMA2; - - if (ctx->xvid_build <= 3U) - s->padding_bug_score = 256 * 256 * 256 * 64; - - if (ctx->xvid_build <= 1U) - s->workaround_bugs |= FF_BUG_QPEL_CHROMA; - - if (ctx->xvid_build <= 12U) - s->workaround_bugs |= FF_BUG_EDGE; - - if (ctx->xvid_build <= 32U) - s->workaround_bugs |= FF_BUG_DC_CLIP; - -#define SET_QPEL_FUNC(postfix1, postfix2) \ - s->qdsp.put_ ## postfix1 = ff_put_ ## postfix2; \ - s->qdsp.put_no_rnd_ ## postfix1 = ff_put_no_rnd_ ## postfix2; \ - s->qdsp.avg_ ## postfix1 = ff_avg_ ## postfix2; - - if (ctx->lavc_build < 4653U) - s->workaround_bugs |= FF_BUG_STD_QPEL; - - if (ctx->lavc_build < 4655U) - s->workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE; - - if (ctx->lavc_build < 4670U) - s->workaround_bugs |= FF_BUG_EDGE; - - if (ctx->lavc_build <= 4712U) - s->workaround_bugs |= FF_BUG_DC_CLIP; - - if ((ctx->lavc_build&0xFF) >= 100) { - if (ctx->lavc_build > 3621476 && ctx->lavc_build < 3752552 && - (ctx->lavc_build < 3752037 || ctx->lavc_build > 3752191) // 3.2.1+ - ) - s->workaround_bugs |= FF_BUG_IEDGE; - } - - if (ctx->divx_version >= 0) - s->workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE; - if (ctx->divx_version == 501 && ctx->divx_build == 20020416) - s->padding_bug_score = 256 * 256 * 256 * 64; - - if (ctx->divx_version < 500U) - s->workaround_bugs |= FF_BUG_EDGE; - - if (ctx->divx_version >= 0) - s->workaround_bugs |= FF_BUG_HPEL_CHROMA; - } - - if (s->workaround_bugs & FF_BUG_STD_QPEL) { - SET_QPEL_FUNC(qpel_pixels_tab[0][5], qpel16_mc11_old_c) - SET_QPEL_FUNC(qpel_pixels_tab[0][7], qpel16_mc31_old_c) - SET_QPEL_FUNC(qpel_pixels_tab[0][9], qpel16_mc12_old_c) - SET_QPEL_FUNC(qpel_pixels_tab[0][11], qpel16_mc32_old_c) - SET_QPEL_FUNC(qpel_pixels_tab[0][13], qpel16_mc13_old_c) - SET_QPEL_FUNC(qpel_pixels_tab[0][15], qpel16_mc33_old_c) - - SET_QPEL_FUNC(qpel_pixels_tab[1][5], qpel8_mc11_old_c) - SET_QPEL_FUNC(qpel_pixels_tab[1][7], qpel8_mc31_old_c) - SET_QPEL_FUNC(qpel_pixels_tab[1][9], qpel8_mc12_old_c) - SET_QPEL_FUNC(qpel_pixels_tab[1][11], qpel8_mc32_old_c) - SET_QPEL_FUNC(qpel_pixels_tab[1][13], qpel8_mc13_old_c) - SET_QPEL_FUNC(qpel_pixels_tab[1][15], qpel8_mc33_old_c) - } - - if (avctx->debug & FF_DEBUG_BUGS) - av_log(s->avctx, AV_LOG_DEBUG, - "bugs: %X lavc_build:%d xvid_build:%d divx_version:%d divx_build:%d %s\n", - s->workaround_bugs, ctx->lavc_build, ctx->xvid_build, - ctx->divx_version, ctx->divx_build, s->divx_packed ? "p" : ""); - - if (CONFIG_MPEG4_DECODER && ctx->xvid_build >= 0 && - avctx->idct_algo == FF_IDCT_AUTO) { - avctx->idct_algo = FF_IDCT_XVID; - ff_mpv_idct_init(s); - return 1; - } - - return 0; -} - static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb, int parse_only) { - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; int time_incr, time_increment; int64_t pts; - s->mcsel = 0; - s->pict_type = get_bits(gb, 2) + AV_PICTURE_TYPE_I; /* pict type: I = 0 , P = 1 */ - if (s->pict_type == AV_PICTURE_TYPE_B && s->low_delay && - ctx->vol_control_parameters == 0 && !(s->avctx->flags & AV_CODEC_FLAG_LOW_DELAY)) { - av_log(s->avctx, AV_LOG_ERROR, "low_delay flag set incorrectly, clearing it\n"); - s->low_delay = 0; + h->c.mcsel = 0; + h->c.pict_type = get_bits(gb, 2) + AV_PICTURE_TYPE_I; /* pict type: I = 0 , P = 1 */ + if (h->c.pict_type == AV_PICTURE_TYPE_B && h->c.low_delay && + ctx->vol_control_parameters == 0 && !(h->c.avctx->flags & AV_CODEC_FLAG_LOW_DELAY)) { + av_log(h->c.avctx, AV_LOG_ERROR, "low_delay flag set incorrectly, clearing it\n"); + h->c.low_delay = 0; } - s->partitioned_frame = s->data_partitioning && s->pict_type != AV_PICTURE_TYPE_B; - if (s->partitioned_frame) - s->decode_mb = mpeg4_decode_partitioned_mb; + h->partitioned_frame = h->data_partitioning && h->c.pict_type != AV_PICTURE_TYPE_B; + if (h->partitioned_frame) + h->decode_mb = mpeg4_decode_partitioned_mb; else - s->decode_mb = mpeg4_decode_mb; + h->decode_mb = mpeg4_decode_mb; time_incr = 0; while (get_bits1(gb) != 0) time_incr++; - check_marker(s->avctx, gb, "before time_increment"); + check_marker(h->c.avctx, gb, "before time_increment"); if (ctx->time_increment_bits == 0 || !(show_bits(gb, ctx->time_increment_bits + 1) & 1)) { - av_log(s->avctx, AV_LOG_WARNING, + av_log(h->c.avctx, AV_LOG_WARNING, "time_increment_bits %d is invalid in relation to the current bitstream, this is likely caused by a missing VOL header\n", ctx->time_increment_bits); for (ctx->time_increment_bits = 1; ctx->time_increment_bits < 16; ctx->time_increment_bits++) { - if (s->pict_type == AV_PICTURE_TYPE_P || - (s->pict_type == AV_PICTURE_TYPE_S && + if (h->c.pict_type == AV_PICTURE_TYPE_P || + (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE)) { if ((show_bits(gb, ctx->time_increment_bits + 6) & 0x37) == 0x30) break; @@ -3136,7 +3109,7 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb, break; } - av_log(s->avctx, AV_LOG_WARNING, + av_log(h->c.avctx, AV_LOG_WARNING, "time_increment_bits set to %d bits, based on bitstream analysis\n", ctx->time_increment_bits); } @@ -3145,83 +3118,84 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb, else time_increment = get_bits(gb, ctx->time_increment_bits); - if (s->pict_type != AV_PICTURE_TYPE_B) { - s->last_time_base = s->time_base; - s->time_base += time_incr; - s->time = s->time_base * (int64_t)s->avctx->framerate.num + time_increment; - if (s->workaround_bugs & FF_BUG_UMP4) { - if (s->time < s->last_non_b_time) { + if (h->c.pict_type != AV_PICTURE_TYPE_B) { + h->c.last_time_base = h->c.time_base; + h->c.time_base += time_incr; + h->c.time = h->c.time_base * (int64_t)h->c.avctx->framerate.num + time_increment; + if (h->c.workaround_bugs & FF_BUG_UMP4) { + if (h->c.time < h->c.last_non_b_time) { /* header is not mpeg-4-compatible, broken encoder, * trying to workaround */ - s->time_base++; - s->time += s->avctx->framerate.num; + h->c.time_base++; + h->c.time += h->c.avctx->framerate.num; } } - s->pp_time = s->time - s->last_non_b_time; - s->last_non_b_time = s->time; + h->c.pp_time = h->c.time - h->c.last_non_b_time; + h->c.last_non_b_time = h->c.time; } else { - s->time = (s->last_time_base + time_incr) * (int64_t)s->avctx->framerate.num + time_increment; - s->pb_time = s->pp_time - (s->last_non_b_time - s->time); - if (s->pp_time <= s->pb_time || - s->pp_time <= s->pp_time - s->pb_time || - s->pp_time <= 0) { + h->c.time = (h->c.last_time_base + time_incr) * (int64_t)h->c.avctx->framerate.num + time_increment; + h->c.pb_time = h->c.pp_time - (h->c.last_non_b_time - h->c.time); + if (h->c.pp_time <= h->c.pb_time || + h->c.pp_time <= h->c.pp_time - h->c.pb_time || + h->c.pp_time <= 0) { /* messed up order, maybe after seeking? skipping current B-frame */ return FRAME_SKIPPED; } - ff_mpeg4_init_direct_mv(s); + ff_mpeg4_init_direct_mv(&h->c); if (ctx->t_frame == 0) - ctx->t_frame = s->pb_time; + ctx->t_frame = h->c.pb_time; if (ctx->t_frame == 0) ctx->t_frame = 1; // 1/0 protection - s->pp_field_time = (ROUNDED_DIV(s->last_non_b_time, ctx->t_frame) - - ROUNDED_DIV(s->last_non_b_time - s->pp_time, ctx->t_frame)) * 2; - s->pb_field_time = (ROUNDED_DIV(s->time, ctx->t_frame) - - ROUNDED_DIV(s->last_non_b_time - s->pp_time, ctx->t_frame)) * 2; - if (s->pp_field_time <= s->pb_field_time || s->pb_field_time <= 1) { - s->pb_field_time = 2; - s->pp_field_time = 4; - if (!s->progressive_sequence) + h->c.pp_field_time = (ROUNDED_DIV(h->c.last_non_b_time, ctx->t_frame) - + ROUNDED_DIV(h->c.last_non_b_time - h->c.pp_time, ctx->t_frame)) * 2; + h->c.pb_field_time = (ROUNDED_DIV(h->c.time, ctx->t_frame) - + ROUNDED_DIV(h->c.last_non_b_time - h->c.pp_time, ctx->t_frame)) * 2; + if (h->c.pp_field_time <= h->c.pb_field_time || h->c.pb_field_time <= 1) { + h->c.pb_field_time = 2; + h->c.pp_field_time = 4; + if (!h->c.progressive_sequence) return FRAME_SKIPPED; } } - if (s->avctx->framerate.den) - pts = ROUNDED_DIV(s->time, s->avctx->framerate.den); + if (h->c.avctx->framerate.den) + pts = ROUNDED_DIV(h->c.time, h->c.avctx->framerate.den); else pts = AV_NOPTS_VALUE; - ff_dlog(s->avctx, "MPEG4 PTS: %"PRId64"\n", pts); + ff_dlog(h->c.avctx, "MPEG4 PTS: %"PRId64"\n", pts); - check_marker(s->avctx, gb, "before vop_coded"); + check_marker(h->c.avctx, gb, "before vop_coded"); /* vop coded */ if (get_bits1(gb) != 1) { - if (s->avctx->debug & FF_DEBUG_PICT_INFO) - av_log(s->avctx, AV_LOG_ERROR, "vop not coded\n"); + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) + av_log(h->c.avctx, AV_LOG_ERROR, "vop not coded\n"); + h->skipped_last_frame = 1; return FRAME_SKIPPED; } if (ctx->new_pred) decode_new_pred(ctx, gb); if (ctx->shape != BIN_ONLY_SHAPE && - (s->pict_type == AV_PICTURE_TYPE_P || - (s->pict_type == AV_PICTURE_TYPE_S && + (h->c.pict_type == AV_PICTURE_TYPE_P || + (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE))) { /* rounding type for motion estimation */ - s->no_rounding = get_bits1(gb); + h->c.no_rounding = get_bits1(gb); } else { - s->no_rounding = 0; + h->c.no_rounding = 0; } // FIXME reduced res stuff if (ctx->shape != RECT_SHAPE) { - if (ctx->vol_sprite_usage != 1 || s->pict_type != AV_PICTURE_TYPE_I) { + if (ctx->vol_sprite_usage != 1 || h->c.pict_type != AV_PICTURE_TYPE_I) { skip_bits(gb, 13); /* width */ - check_marker(s->avctx, gb, "after width"); + check_marker(h->c.avctx, gb, "after width"); skip_bits(gb, 13); /* height */ - check_marker(s->avctx, gb, "after height"); + check_marker(h->c.avctx, gb, "after height"); skip_bits(gb, 13); /* hor_spat_ref */ - check_marker(s->avctx, gb, "after hor_spat_ref"); + check_marker(h->c.avctx, gb, "after hor_spat_ref"); skip_bits(gb, 13); /* ver_spat_ref */ } skip_bits1(gb); /* change_CR_disable */ @@ -3234,154 +3208,155 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb, if (ctx->shape != BIN_ONLY_SHAPE) { skip_bits_long(gb, ctx->cplx_estimation_trash_i); - if (s->pict_type != AV_PICTURE_TYPE_I) + if (h->c.pict_type != AV_PICTURE_TYPE_I) skip_bits_long(gb, ctx->cplx_estimation_trash_p); - if (s->pict_type == AV_PICTURE_TYPE_B) + if (h->c.pict_type == AV_PICTURE_TYPE_B) skip_bits_long(gb, ctx->cplx_estimation_trash_b); if (get_bits_left(gb) < 3) { - av_log(s->avctx, AV_LOG_ERROR, "Header truncated\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Header truncated\n"); return AVERROR_INVALIDDATA; } ctx->intra_dc_threshold = ff_mpeg4_dc_threshold[get_bits(gb, 3)]; - if (!s->progressive_sequence) { - s->top_field_first = get_bits1(gb); - s->alternate_scan = get_bits1(gb); + if (!h->c.progressive_sequence) { + h->c.top_field_first = get_bits1(gb); + h->c.alternate_scan = get_bits1(gb); } else - s->alternate_scan = 0; + h->c.alternate_scan = 0; } - if (s->alternate_scan) { - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_alternate_vertical_scan); - ff_permute_scantable(s->permutated_intra_h_scantable, ff_alternate_vertical_scan, - s->idsp.idct_permutation); - } else { - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_zigzag_direct); - ff_permute_scantable(s->permutated_intra_h_scantable, ff_alternate_horizontal_scan, - s->idsp.idct_permutation); - } - ff_permute_scantable(s->permutated_intra_v_scantable, ff_alternate_vertical_scan, - s->idsp.idct_permutation); - /* Skip at this point when only parsing since the remaining * data is not useful for a parser and requires the * sprite_trajectory VLC to be initialized. */ if (parse_only) goto end; - if (s->pict_type == AV_PICTURE_TYPE_S) { + if (h->c.alternate_scan) { + ff_init_scantable(h->c.idsp.idct_permutation, &h->c.intra_scantable, ff_alternate_vertical_scan); + ff_permute_scantable(h->permutated_intra_h_scantable, ff_alternate_vertical_scan, + h->c.idsp.idct_permutation); + } else { + ff_init_scantable(h->c.idsp.idct_permutation, &h->c.intra_scantable, ff_zigzag_direct); + ff_permute_scantable(h->permutated_intra_h_scantable, ff_alternate_horizontal_scan, + h->c.idsp.idct_permutation); + } + ff_permute_scantable(h->permutated_intra_v_scantable, ff_alternate_vertical_scan, + h->c.idsp.idct_permutation); + + if (h->c.pict_type == AV_PICTURE_TYPE_S) { if((ctx->vol_sprite_usage == STATIC_SPRITE || ctx->vol_sprite_usage == GMC_SPRITE)) { if (mpeg4_decode_sprite_trajectory(ctx, gb) < 0) return AVERROR_INVALIDDATA; if (ctx->sprite_brightness_change) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "sprite_brightness_change not supported\n"); if (ctx->vol_sprite_usage == STATIC_SPRITE) - av_log(s->avctx, AV_LOG_ERROR, "static sprite not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "static sprite not supported\n"); } else { memset(ctx->sprite_offset, 0, sizeof(ctx->sprite_offset)); memset(ctx->sprite_delta, 0, sizeof(ctx->sprite_delta)); } } + ctx->f_code = 1; + ctx->b_code = 1; if (ctx->shape != BIN_ONLY_SHAPE) { - s->chroma_qscale = s->qscale = get_bits(gb, ctx->quant_precision); - if (s->qscale == 0) { - av_log(s->avctx, AV_LOG_ERROR, + h->c.chroma_qscale = h->c.qscale = get_bits(gb, ctx->quant_precision); + if (h->c.qscale == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Error, header damaged or not MPEG-4 header (qscale=0)\n"); return AVERROR_INVALIDDATA; // makes no sense to continue, as there is nothing left from the image then } - if (s->pict_type != AV_PICTURE_TYPE_I) { - s->f_code = get_bits(gb, 3); /* fcode_for */ - if (s->f_code == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (h->c.pict_type != AV_PICTURE_TYPE_I) { + ctx->f_code = get_bits(gb, 3); /* fcode_for */ + if (ctx->f_code == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Error, header damaged or not MPEG-4 header (f_code=0)\n"); - s->f_code = 1; + ctx->f_code = 1; return AVERROR_INVALIDDATA; // makes no sense to continue, as there is nothing left from the image then } - } else - s->f_code = 1; + } - if (s->pict_type == AV_PICTURE_TYPE_B) { - s->b_code = get_bits(gb, 3); - if (s->b_code == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (h->c.pict_type == AV_PICTURE_TYPE_B) { + ctx->b_code = get_bits(gb, 3); + if (ctx->b_code == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Error, header damaged or not MPEG4 header (b_code=0)\n"); - s->b_code=1; + ctx->b_code=1; return AVERROR_INVALIDDATA; // makes no sense to continue, as the MV decoding will break very quickly } - } else - s->b_code = 1; + } - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "qp:%d fc:%d,%d %c size:%d pro:%d alt:%d top:%d %cpel part:%d resync:%d w:%d a:%d rnd:%d vot:%d%s dc:%d ce:%d/%d/%d time:%"PRId64" tincr:%d\n", - s->qscale, s->f_code, s->b_code, - s->pict_type == AV_PICTURE_TYPE_I ? 'I' : (s->pict_type == AV_PICTURE_TYPE_P ? 'P' : (s->pict_type == AV_PICTURE_TYPE_B ? 'B' : 'S')), - gb->size_in_bits,s->progressive_sequence, s->alternate_scan, - s->top_field_first, s->quarter_sample ? 'q' : 'h', - s->data_partitioning, ctx->resync_marker, + h->c.qscale, ctx->f_code, ctx->b_code, + h->c.pict_type == AV_PICTURE_TYPE_I ? 'I' : (h->c.pict_type == AV_PICTURE_TYPE_P ? 'P' : (h->c.pict_type == AV_PICTURE_TYPE_B ? 'B' : 'S')), + gb->size_in_bits,h->c.progressive_sequence, h->c.alternate_scan, + h->c.top_field_first, h->c.quarter_sample ? 'q' : 'h', + h->data_partitioning, ctx->resync_marker, ctx->num_sprite_warping_points, ctx->sprite_warping_accuracy, - 1 - s->no_rounding, ctx->vo_type, + 1 - h->c.no_rounding, ctx->vo_type, ctx->vol_control_parameters ? " VOLC" : " ", ctx->intra_dc_threshold, ctx->cplx_estimation_trash_i, ctx->cplx_estimation_trash_p, ctx->cplx_estimation_trash_b, - s->time, + h->c.time, time_increment ); } if (!ctx->scalability) { - if (ctx->shape != RECT_SHAPE && s->pict_type != AV_PICTURE_TYPE_I) + if (ctx->shape != RECT_SHAPE && h->c.pict_type != AV_PICTURE_TYPE_I) skip_bits1(gb); // vop shape coding type } else { if (ctx->enhancement_type) { int load_backward_shape = get_bits1(gb); if (load_backward_shape) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "load backward shape isn't supported\n"); } skip_bits(gb, 2); // ref_select_code } } + h->c.dct_unquantize_intra = ctx->mpeg_quant ? ctx->dct_unquantize_mpeg2_intra + : ctx->dct_unquantize_h263_intra; + // The following tells ff_mpv_reconstruct_mb() to unquantize iff mpeg_quant + h->c.dct_unquantize_inter = ctx->mpeg_quant ? ctx->dct_unquantize_mpeg2_inter : NULL; + end: /* detect buggy encoders which don't set the low_delay flag * (divx4/xvid/opendivx). Note we cannot detect divx5 without B-frames * easily (although it's buggy too) */ if (ctx->vo_type == 0 && ctx->vol_control_parameters == 0 && - ctx->divx_version == -1 && s->picture_number == 0) { - av_log(s->avctx, AV_LOG_WARNING, + ctx->divx_version == -1 && h->picture_number == 0) { + av_log(h->c.avctx, AV_LOG_WARNING, "looks like this file was encoded with (divx4/(old)xvid/opendivx) -> forcing low_delay flag\n"); - s->low_delay = 1; + h->c.low_delay = 1; } - s->picture_number++; // better than pic number==0 always ;) + h->picture_number++; // better than pic number==0 always ;) - // FIXME add short header support - s->y_dc_scale_table = ff_mpeg4_y_dc_scale_table; - s->c_dc_scale_table = ff_mpeg4_c_dc_scale_table; - - if (s->workaround_bugs & FF_BUG_EDGE) { - s->h_edge_pos = s->width; - s->v_edge_pos = s->height; + if (h->c.workaround_bugs & FF_BUG_EDGE) { + h->c.h_edge_pos = h->c.width; + h->c.v_edge_pos = h->c.height; } return 0; } static void decode_smpte_tc(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + AVCodecContext *const avctx = ctx->h.c.avctx; skip_bits(gb, 16); /* Time_code[63..48] */ - check_marker(s->avctx, gb, "after Time_code[63..48]"); + check_marker(avctx, gb, "after Time_code[63..48]"); skip_bits(gb, 16); /* Time_code[47..32] */ - check_marker(s->avctx, gb, "after Time_code[47..32]"); + check_marker(avctx, gb, "after Time_code[47..32]"); skip_bits(gb, 16); /* Time_code[31..16] */ - check_marker(s->avctx, gb, "after Time_code[31..16]"); + check_marker(avctx, gb, "after Time_code[31..16]"); skip_bits(gb, 16); /* Time_code[15..0] */ - check_marker(s->avctx, gb, "after Time_code[15..0]"); + check_marker(avctx, gb, "after Time_code[15..0]"); skip_bits(gb, 4); /* reserved_bits */ } @@ -3391,64 +3366,63 @@ static void decode_smpte_tc(Mpeg4DecContext *ctx, GetBitContext *gb) */ static int decode_studio_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; if (get_bits_left(gb) <= 32) return 0; - s->partitioned_frame = 0; - s->interlaced_dct = 0; - s->decode_mb = mpeg4_decode_studio_mb; + h->partitioned_frame = 0; + h->c.interlaced_dct = 0; + h->decode_mb = mpeg4_decode_studio_mb; decode_smpte_tc(ctx, gb); skip_bits(gb, 10); /* temporal_reference */ skip_bits(gb, 2); /* vop_structure */ - s->pict_type = get_bits(gb, 2) + AV_PICTURE_TYPE_I; /* vop_coding_type */ + h->c.pict_type = get_bits(gb, 2) + AV_PICTURE_TYPE_I; /* vop_coding_type */ if (get_bits1(gb)) { /* vop_coded */ skip_bits1(gb); /* top_field_first */ skip_bits1(gb); /* repeat_first_field */ - s->progressive_frame = get_bits1(gb) ^ 1; /* progressive_frame */ + h->c.progressive_frame = get_bits1(gb) ^ 1; /* progressive_frame */ } - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (h->c.pict_type == AV_PICTURE_TYPE_I) { if (get_bits1(gb)) - reset_studio_dc_predictors(s); + reset_studio_dc_predictors(ctx); } if (ctx->shape != BIN_ONLY_SHAPE) { - s->alternate_scan = get_bits1(gb); - s->frame_pred_frame_dct = get_bits1(gb); - s->dct_precision = get_bits(gb, 2); - s->intra_dc_precision = get_bits(gb, 2); - s->q_scale_type = get_bits1(gb); + h->c.alternate_scan = get_bits1(gb); + h->c.frame_pred_frame_dct = get_bits1(gb); + ctx->dct_precision = get_bits(gb, 2); + h->c.intra_dc_precision = get_bits(gb, 2); + h->c.q_scale_type = get_bits1(gb); } - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, - s->alternate_scan ? ff_alternate_vertical_scan : ff_zigzag_direct); + ff_init_scantable(h->c.idsp.idct_permutation, &h->c.intra_scantable, + h->c.alternate_scan ? ff_alternate_vertical_scan : ff_zigzag_direct); - mpeg4_load_default_matrices(s); + mpeg4_load_default_matrices(&h->c); next_start_code_studio(gb); - extension_and_user_data(s, gb, 4); + extension_and_user_data(&h->c, gb, 4); return 0; } static int decode_studiovisualobject(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; int visual_object_type; skip_bits(gb, 4); /* visual_object_verid */ visual_object_type = get_bits(gb, 4); if (visual_object_type != VOT_VIDEO_ID) { - avpriv_request_sample(s->avctx, "VO type %u", visual_object_type); + avpriv_request_sample(ctx->h.c.avctx, "VO type %u", visual_object_type); return AVERROR_PATCHWELCOME; } next_start_code_studio(gb); - extension_and_user_data(s, gb, 1); + extension_and_user_data(&ctx->h.c, gb, 1); return 0; } @@ -3463,10 +3437,10 @@ static int decode_studiovisualobject(Mpeg4DecContext *ctx, GetBitContext *gb) * FRAME_SKIPPED if a not coded VOP is found * 0 else */ -int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, - int header, int parse_only) +int ff_mpeg4_parse_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, + int header, int parse_only) { - MpegEncContext *s = &ctx->m; + MPVContext *const s = &ctx->h.c; unsigned startcode, v; int ret; int vol = 0; @@ -3476,7 +3450,7 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, // If we have not switched to studio profile than we also did not switch bps // that means something else (like a previous instance) outside set bps which - // would be inconsistant with the currect state, thus reset it + // would be inconsistent with the correct state, thus reset it if (!s->studio_profile && s->avctx->bits_per_raw_sample != 8) s->avctx->bits_per_raw_sample = 0; @@ -3562,6 +3536,8 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, name = "Reserved"; else if (startcode <= 0x1FF) name = "System start"; + else + av_unreachable("Unexpected startcode"); av_log(s->avctx, AV_LOG_DEBUG, "startcode: %3X %s at %d\n", startcode, name, get_bits_count(gb)); } @@ -3609,7 +3585,6 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, end: if (s->avctx->flags & AV_CODEC_FLAG_LOW_DELAY) s->low_delay = 1; - s->avctx->has_b_frames = !s->low_delay; if (s->studio_profile) { if (!s->avctx->bits_per_raw_sample) { @@ -3621,17 +3596,200 @@ end: return decode_vop_header(ctx, gb, parse_only); } -int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size) +#if CONFIG_MPEG4_DECODER +static av_cold void permute_quant_matrix(uint16_t matrix[64], + const uint8_t new_perm[64], + const uint8_t old_perm[64]) +{ + uint16_t tmp[64]; + + memcpy(tmp, matrix, sizeof(tmp)); + for (int i = 0; i < 64; ++i) + matrix[new_perm[i]] = tmp[old_perm[i]]; +} + +static av_cold void switch_to_xvid_idct(AVCodecContext *const avctx, + H263DecContext *const h) +{ + uint8_t old_permutation[64]; + + memcpy(old_permutation, h->c.idsp.idct_permutation, sizeof(old_permutation)); + + avctx->idct_algo = FF_IDCT_XVID; + ff_mpv_idct_init(&h->c); + ff_permute_scantable(h->permutated_intra_h_scantable, + h->c.alternate_scan ? ff_alternate_vertical_scan : ff_alternate_horizontal_scan, + h->c.idsp.idct_permutation); + ff_permute_scantable(h->permutated_intra_v_scantable, ff_alternate_vertical_scan, + h->c.idsp.idct_permutation); + + // Normal (i.e. non-studio) MPEG-4 does not use the chroma matrices. + permute_quant_matrix(h->c.inter_matrix, h->c.idsp.idct_permutation, old_permutation); + permute_quant_matrix(h->c.intra_matrix, h->c.idsp.idct_permutation, old_permutation); +} + +void ff_mpeg4_workaround_bugs(AVCodecContext *avctx) { Mpeg4DecContext *ctx = avctx->priv_data; - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; + + if (ctx->xvid_build == -1 && ctx->divx_version == -1 && ctx->lavc_build == -1) { + if (h->c.codec_tag == AV_RL32("XVID") || + h->c.codec_tag == AV_RL32("XVIX") || + h->c.codec_tag == AV_RL32("RMP4") || + h->c.codec_tag == AV_RL32("ZMP4") || + h->c.codec_tag == AV_RL32("SIPP")) + ctx->xvid_build = 0; + } + + if (ctx->xvid_build == -1 && ctx->divx_version == -1 && ctx->lavc_build == -1) + if (h->c.codec_tag == AV_RL32("DIVX") && ctx->vo_type == 0 && + ctx->vol_control_parameters == 0) + ctx->divx_version = 400; // divx 4 + + if (ctx->xvid_build >= 0 && ctx->divx_version >= 0) { + ctx->divx_version = + ctx->divx_build = -1; + } + + if (h->c.workaround_bugs & FF_BUG_AUTODETECT) { + if (h->c.codec_tag == AV_RL32("XVIX")) + h->c.workaround_bugs |= FF_BUG_XVID_ILACE; + + if (h->c.codec_tag == AV_RL32("UMP4")) + h->c.workaround_bugs |= FF_BUG_UMP4; + + if (ctx->divx_version >= 500 && ctx->divx_build < 1814) + h->c.workaround_bugs |= FF_BUG_QPEL_CHROMA; + + if (ctx->divx_version > 502 && ctx->divx_build < 1814) + h->c.workaround_bugs |= FF_BUG_QPEL_CHROMA2; + + if (ctx->xvid_build <= 3U) + h->padding_bug_score = 256 * 256 * 256 * 64; + + if (ctx->xvid_build <= 1U) + h->c.workaround_bugs |= FF_BUG_QPEL_CHROMA; + + if (ctx->xvid_build <= 12U) + h->c.workaround_bugs |= FF_BUG_EDGE; + + if (ctx->xvid_build <= 32U) + h->c.workaround_bugs |= FF_BUG_DC_CLIP; + +#define SET_QPEL_FUNC(postfix1, postfix2) \ + h->c.qdsp.put_ ## postfix1 = ff_put_ ## postfix2; \ + h->c.qdsp.put_no_rnd_ ## postfix1 = ff_put_no_rnd_ ## postfix2; \ + h->c.qdsp.avg_ ## postfix1 = ff_avg_ ## postfix2; + + if (ctx->lavc_build < 4653U) + h->c.workaround_bugs |= FF_BUG_STD_QPEL; + + if (ctx->lavc_build < 4655U) + h->c.workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE; + + if (ctx->lavc_build < 4670U) + h->c.workaround_bugs |= FF_BUG_EDGE; + + if (ctx->lavc_build <= 4712U) + h->c.workaround_bugs |= FF_BUG_DC_CLIP; + + if ((ctx->lavc_build&0xFF) >= 100) { + if (ctx->lavc_build > 3621476 && ctx->lavc_build < 3752552 && + (ctx->lavc_build < 3752037 || ctx->lavc_build > 3752191) // 3.2.1+ + ) + h->c.workaround_bugs |= FF_BUG_IEDGE; + } + + if (ctx->divx_version >= 0) + h->c.workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE; + if (ctx->divx_version == 501 && ctx->divx_build == 20020416) + h->padding_bug_score = 256 * 256 * 256 * 64; + + if (ctx->divx_version < 500U) + h->c.workaround_bugs |= FF_BUG_EDGE; + + if (ctx->divx_version >= 0) + h->c.workaround_bugs |= FF_BUG_HPEL_CHROMA; + } + + if (h->c.workaround_bugs & FF_BUG_STD_QPEL) { + SET_QPEL_FUNC(qpel_pixels_tab[0][5], qpel16_mc11_old_c) + SET_QPEL_FUNC(qpel_pixels_tab[0][7], qpel16_mc31_old_c) + SET_QPEL_FUNC(qpel_pixels_tab[0][9], qpel16_mc12_old_c) + SET_QPEL_FUNC(qpel_pixels_tab[0][11], qpel16_mc32_old_c) + SET_QPEL_FUNC(qpel_pixels_tab[0][13], qpel16_mc13_old_c) + SET_QPEL_FUNC(qpel_pixels_tab[0][15], qpel16_mc33_old_c) + + SET_QPEL_FUNC(qpel_pixels_tab[1][5], qpel8_mc11_old_c) + SET_QPEL_FUNC(qpel_pixels_tab[1][7], qpel8_mc31_old_c) + SET_QPEL_FUNC(qpel_pixels_tab[1][9], qpel8_mc12_old_c) + SET_QPEL_FUNC(qpel_pixels_tab[1][11], qpel8_mc32_old_c) + SET_QPEL_FUNC(qpel_pixels_tab[1][13], qpel8_mc13_old_c) + SET_QPEL_FUNC(qpel_pixels_tab[1][15], qpel8_mc33_old_c) + } + + if (avctx->debug & FF_DEBUG_BUGS) + av_log(h->c.avctx, AV_LOG_DEBUG, + "bugs: %X lavc_build:%d xvid_build:%d divx_version:%d divx_build:%d %s\n", + h->c.workaround_bugs, ctx->lavc_build, ctx->xvid_build, + ctx->divx_version, ctx->divx_build, h->divx_packed ? "p" : ""); + + if (ctx->xvid_build >= 0 && + avctx->idct_algo == FF_IDCT_AUTO && !h->c.studio_profile) { + switch_to_xvid_idct(avctx, h); + } +} + +static int mpeg4_decode_picture_header(H263DecContext *const h) +{ + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); + + h->skipped_last_frame = 0; + + if (ctx->bitstream_buffer) { + int buf_size = get_bits_left(&h->gb) / 8U; + int bitstream_buffer_size = ctx->bitstream_buffer->size; + const uint8_t *buf = h->gb.buffer; + + if (h->divx_packed) { + for (int i = 0; i < buf_size - 3; i++) { + if (buf[i] == 0 && buf[i+1] == 0 && buf[i+2] == 1) { + if (buf[i+3] == 0xB0) { + av_log(h->c.avctx, AV_LOG_WARNING, "Discarding excessive bitstream in packed xvid\n"); + bitstream_buffer_size = 0; + } + break; + } + } + } + ctx->bitstream_buffer->size = 0; + if (bitstream_buffer_size && (h->divx_packed || buf_size <= MAX_NVOP_SIZE)) {// divx 5.01+/xvid frame reorder + int ret = init_get_bits8(&h->gb, ctx->bitstream_buffer->data, + bitstream_buffer_size); + if (ret < 0) + return ret; + } else + av_buffer_unref(&ctx->bitstream_buffer); + } + + return ff_mpeg4_parse_picture_header(ctx, &h->gb, 0, 0); +} + +int ff_mpeg4_frame_end(AVCodecContext *avctx, const AVPacket *pkt) +{ + Mpeg4DecContext *ctx = avctx->priv_data; + H263DecContext *const h = &ctx->h; + int ret; + + av_assert1(!ctx->bitstream_buffer || !ctx->bitstream_buffer->size); /* divx 5.01+ bitstream reorder stuff */ - /* Since this clobbers the input buffer and hwaccel codecs still need the - * data during hwaccel->end_frame we should not do this any earlier */ - if (s->divx_packed) { - int current_pos = s->gb.buffer == s->bitstream_buffer ? 0 : (get_bits_count(&s->gb) >> 3); + if (h->divx_packed) { + int current_pos = ctx->bitstream_buffer && h->gb.buffer == ctx->bitstream_buffer->data ? 0 : (get_bits_count(&h->gb) >> 3); int startcode_found = 0; + uint8_t *buf = pkt->data; + int buf_size = pkt->size; if (buf_size - current_pos > 7) { @@ -3649,38 +3807,91 @@ int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size) if (startcode_found) { if (!ctx->showed_packed_warning) { - av_log(s->avctx, AV_LOG_INFO, "Video uses a non-standard and " + av_log(h->c.avctx, AV_LOG_INFO, "Video uses a non-standard and " "wasteful way to store B-frames ('packed B-frames'). " "Consider using the mpeg4_unpack_bframes bitstream filter without encoding but stream copy to fix it.\n"); ctx->showed_packed_warning = 1; } - av_fast_padded_malloc(&s->bitstream_buffer, - &s->allocated_bitstream_buffer_size, - buf_size - current_pos); - if (!s->bitstream_buffer) { - s->bitstream_buffer_size = 0; - return AVERROR(ENOMEM); - } - memcpy(s->bitstream_buffer, buf + current_pos, - buf_size - current_pos); - s->bitstream_buffer_size = buf_size - current_pos; + ret = av_buffer_replace(&ctx->bitstream_buffer, pkt->buf); + if (ret < 0) + return ret; + + ctx->bitstream_buffer->data = buf + current_pos; + ctx->bitstream_buffer->size = buf_size - current_pos; } } return 0; } -#if CONFIG_MPEG4_DECODER #if HAVE_THREADS +static av_cold void clear_context(MpegEncContext *s) +{ + memset(&s->buffer_pools, 0, sizeof(s->buffer_pools)); + memset(&s->next_pic, 0, sizeof(s->next_pic)); + memset(&s->last_pic, 0, sizeof(s->last_pic)); + memset(&s->cur_pic, 0, sizeof(s->cur_pic)); + + memset(s->thread_context, 0, sizeof(s->thread_context)); + + s->ac_val_base = NULL; + s->ac_val = NULL; + memset(&s->sc, 0, sizeof(s->sc)); + + s->p_field_mv_table_base = NULL; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + s->p_field_mv_table[i][j] = NULL; + + s->dc_val_base = NULL; + s->coded_block_base = NULL; + s->mbintra_table = NULL; + s->cbp_table = NULL; + s->pred_dir_table = NULL; + + s->mbskip_table = NULL; + + s->er.error_status_table = NULL; + s->er.er_temp_buffer = NULL; + s->mb_index2xy = NULL; + + s->context_initialized = 0; + s->context_reinit = 0; +} + +static av_cold int update_mpvctx(MpegEncContext *s, const MpegEncContext *s1) +{ + AVCodecContext *avctx = s->avctx; + // FIXME the following leads to a data race; instead copy only + // the necessary fields. + memcpy(s, s1, sizeof(*s)); + clear_context(s); + + s->avctx = avctx; + + if (s1->context_initialized) { + int err = ff_mpv_common_init(s); + if (err < 0) + return err; + } + return 0; +} + static int mpeg4_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { Mpeg4DecContext *s = dst->priv_data; const Mpeg4DecContext *s1 = src->priv_data; - int init = s->m.context_initialized; + int init = s->h.c.context_initialized; + int ret; - int ret = ff_mpeg_update_thread_context(dst, src); + if (!init) { + ret = update_mpvctx(&s->h.c, &s1->h.c); + if (ret < 0) + return ret; + } + ret = ff_mpeg_update_thread_context(dst, src); if (ret < 0) return ret; @@ -3691,7 +3902,8 @@ static int mpeg4_update_thread_context(AVCodecContext *dst, s->sprite_brightness_change = s1->sprite_brightness_change; s->sprite_warping_accuracy = s1->sprite_warping_accuracy; s->num_sprite_warping_points = s1->num_sprite_warping_points; - s->m.data_partitioning = s1->m.data_partitioning; + s->h.data_partitioning = s1->h.data_partitioning; + s->mpeg_quant = s1->mpeg_quant; s->rvlc = s1->rvlc; s->resync_marker = s1->resync_marker; s->t_frame = s1->t_frame; @@ -3699,6 +3911,7 @@ static int mpeg4_update_thread_context(AVCodecContext *dst, s->enhancement_type = s1->enhancement_type; s->scalability = s1->scalability; s->intra_dc_threshold = s1->intra_dc_threshold; + s->h.divx_packed = s1->h.divx_packed; s->divx_version = s1->divx_version; s->divx_build = s1->divx_build; s->xvid_build = s1->xvid_build; @@ -3711,23 +3924,25 @@ static int mpeg4_update_thread_context(AVCodecContext *dst, s->cplx_estimation_trash_b = s1->cplx_estimation_trash_b; s->rgb = s1->rgb; + s->h.skipped_last_frame = s1->h.skipped_last_frame; + s->h.padding_bug_score = s1->h.padding_bug_score; // FIXME: racy + + s->h.picture_number = s1->h.picture_number; + memcpy(s->sprite_shift, s1->sprite_shift, sizeof(s1->sprite_shift)); memcpy(s->sprite_traj, s1->sprite_traj, sizeof(s1->sprite_traj)); - if (!init && s1->xvid_build >= 0) - ff_xvid_idct_init(&s->m.idsp, dst); - - return 0; + return av_buffer_replace(&s->bitstream_buffer, s1->bitstream_buffer); } static int mpeg4_update_thread_context_for_user(AVCodecContext *dst, const AVCodecContext *src) { - MpegEncContext *m = dst->priv_data; - const MpegEncContext *m1 = src->priv_data; + H263DecContext *const h = dst->priv_data; + const H263DecContext *const h1 = src->priv_data; - m->quarter_sample = m1->quarter_sample; - m->divx_packed = m1->divx_packed; + h->c.quarter_sample = h1->c.quarter_sample; + h->divx_packed = h1->divx_packed; return 0; } @@ -3735,7 +3950,6 @@ static int mpeg4_update_thread_context_for_user(AVCodecContext *dst, static av_cold void mpeg4_init_static(void) { - static uint8_t mpeg4_rvlc_rl_tables[2][2][2 * MAX_RUN + MAX_LEVEL + 3]; static VLCElem vlc_buf[6498]; VLCInitState state = VLC_INIT_STATE(vlc_buf); @@ -3757,9 +3971,10 @@ static av_cold void mpeg4_init_static(void) 0, 0); } - ff_mpeg4_init_rl_intra(); - ff_rl_init(&ff_rvlc_rl_inter, mpeg4_rvlc_rl_tables[0]); - ff_rl_init(&ff_rvlc_rl_intra, mpeg4_rvlc_rl_tables[1]); + static uint8_t mpeg4_rl_intra_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; + ff_rl_init(&ff_mpeg4_rl_intra, mpeg4_rl_intra_table); + ff_h263_init_rl_inter(); + INIT_FIRST_VLC_RL(ff_mpeg4_rl_intra, 554); VLC_INIT_RL(ff_rvlc_rl_inter, 1072); INIT_FIRST_VLC_RL(ff_rvlc_rl_intra, 1072); @@ -3782,7 +3997,8 @@ static av_cold int decode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; Mpeg4DecContext *ctx = avctx->priv_data; - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; + MPVUnquantDSPContext unquant_dsp_ctx; int ret; ctx->divx_version = @@ -3793,15 +4009,28 @@ static av_cold int decode_init(AVCodecContext *avctx) if ((ret = ff_h263_decode_init(avctx)) < 0) return ret; - s->h263_pred = 1; - s->low_delay = 0; /* default, might be overridden in the vol header during header parsing */ - s->decode_mb = mpeg4_decode_mb; + ff_mpv_unquantize_init(&unquant_dsp_ctx, + avctx->flags & AV_CODEC_FLAG_BITEXACT, 0); + + ctx->dct_unquantize_h263_intra = unquant_dsp_ctx.dct_unquantize_h263_intra; + ctx->dct_unquantize_mpeg2_intra = unquant_dsp_ctx.dct_unquantize_mpeg2_intra; + // dct_unquantize_inter is only used with MPEG-2 quantizers, + // so that is all we keep. + ctx->dct_unquantize_mpeg2_inter = unquant_dsp_ctx.dct_unquantize_mpeg2_inter; + + h->c.y_dc_scale_table = ff_mpeg4_y_dc_scale_table; + h->c.c_dc_scale_table = ff_mpeg4_c_dc_scale_table; + + h->c.h263_pred = 1; + h->c.low_delay = 0; /* default, might be overridden in the vol header during header parsing */ + h->decode_header = mpeg4_decode_picture_header; + h->decode_mb = mpeg4_decode_mb; ctx->time_increment_bits = 4; /* default value for broken headers */ ctx->quant_precision = 5; avctx->chroma_sample_location = AVCHROMA_LOC_LEFT; - ff_qpeldsp_init(&s->qdsp); + ff_qpeldsp_init(&h->c.qdsp); ff_mpeg4videodsp_init(&ctx->mdsp); ff_thread_once(&init_static_once, mpeg4_init_static); @@ -3811,16 +4040,33 @@ static av_cold int decode_init(AVCodecContext *avctx) GetBitContext gb; if (init_get_bits8(&gb, avctx->extradata, avctx->extradata_size) >= 0) - ff_mpeg4_decode_picture_header(ctx, &gb, 1, 0); + ff_mpeg4_parse_picture_header(ctx, &gb, 1, 0); } return 0; } -#define OFFSET(x) offsetof(MpegEncContext, x) +static av_cold void mpeg4_flush(AVCodecContext *avctx) +{ + Mpeg4DecContext *const ctx = avctx->priv_data; + + av_buffer_unref(&ctx->bitstream_buffer); + ff_mpeg_flush(avctx); +} + +static av_cold int mpeg4_close(AVCodecContext *avctx) +{ + Mpeg4DecContext *const ctx = avctx->priv_data; + + av_buffer_unref(&ctx->bitstream_buffer); + + return ff_mpv_decode_close(avctx); +} + +#define OFFSET(x) offsetof(H263DecContext, x) #define FLAGS AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY static const AVOption mpeg4_options[] = { - {"quarter_sample", "1/4 subpel MC", OFFSET(quarter_sample), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS}, + {"quarter_sample", "1/4 subpel MC", OFFSET(c.quarter_sample), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS}, {"divx_packed", "divx style packed b frames", OFFSET(divx_packed), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS}, {NULL} }; @@ -3840,12 +4086,12 @@ const FFCodec ff_mpeg4_decoder = { .priv_data_size = sizeof(Mpeg4DecContext), .init = decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), - .close = ff_mpv_decode_close, + .close = mpeg4_close, .p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_FRAME_THREADS, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, - .flush = ff_mpeg_flush, + .flush = mpeg4_flush, .p.max_lowres = 3, .p.profiles = NULL_IF_CONFIG_SMALL(ff_mpeg4_video_profiles), UPDATE_THREAD_CONTEXT(mpeg4_update_thread_context), diff --git a/libavcodec/mpeg4videodec.h b/libavcodec/mpeg4videodec.h index 734237b16..2eafa1ef8 100644 --- a/libavcodec/mpeg4videodec.h +++ b/libavcodec/mpeg4videodec.h @@ -26,13 +26,17 @@ #include #include "get_bits.h" +#include "h263dec.h" #include "mpegvideo.h" #include "mpeg4videodsp.h" #include "libavutil/mem_internal.h" typedef struct Mpeg4DecContext { - MpegEncContext m; + H263DecContext h; + + int f_code; ///< forward MV resolution + int b_code; ///< backward MV resolution for B-frames /// number of bits to represent the fractional part of time int time_increment_bits; @@ -49,6 +53,7 @@ typedef struct Mpeg4DecContext { /// sprite shift [isChroma] int sprite_shift[2]; + int mpeg_quant; // reversible vlc int rvlc; /// could this stream contain resync markers @@ -70,6 +75,8 @@ typedef struct Mpeg4DecContext { int divx_build; int xvid_build; int lavc_build; + /// Divx 5.01 puts several frames in a single one, this is used to reorder them + AVBufferRef *bitstream_buffer; int vo_type; @@ -86,27 +93,37 @@ typedef struct Mpeg4DecContext { Mpeg4VideoDSPContext mdsp; - DECLARE_ALIGNED(8, int32_t, block32)[12][64]; + void (*dct_unquantize_mpeg2_inter)(const MPVContext *s, + int16_t *block, int n, int qscale); + void (*dct_unquantize_mpeg2_intra)(const MPVContext *s, + int16_t *block, int n, int qscale); + void (*dct_unquantize_h263_intra)(const MPVContext *s, + int16_t *block, int n, int qscale); + + union { + DECLARE_ALIGNED(8, int32_t, block32)[12][64]; + int16_t dpcm_macroblock[3][256]; + }; // 0 = DCT, 1 = DPCM top to bottom scan, -1 = DPCM bottom to top scan int dpcm_direction; - int16_t dpcm_macroblock[3][256]; + int dct_precision; } Mpeg4DecContext; -int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, - int header, int parse_only); +int ff_mpeg4_parse_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, + int header, int parse_only); void ff_mpeg4_decode_studio(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int block_size, int uvlinesize, int dct_linesize, int dct_offset); void ff_mpeg4_mcsel_motion(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, uint8_t *const *ref_picture); -int ff_mpeg4_decode_partitions(Mpeg4DecContext *ctx); -int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx); -int ff_mpeg4_decode_studio_slice_header(Mpeg4DecContext *ctx); -int ff_mpeg4_workaround_bugs(AVCodecContext *avctx); -void ff_mpeg4_pred_ac(MpegEncContext *s, int16_t *block, int n, +int ff_mpeg4_decode_partitions(H263DecContext *const h); +int ff_mpeg4_decode_video_packet_header(H263DecContext *const h); +int ff_mpeg4_decode_studio_slice_header(H263DecContext *const h); +void ff_mpeg4_workaround_bugs(AVCodecContext *avctx); +void ff_mpeg4_pred_ac(H263DecContext *const h, int16_t *block, int n, int dir); -int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size); +int ff_mpeg4_frame_end(AVCodecContext *avctx, const AVPacket *pkt); #endif diff --git a/libavcodec/mpeg4videoenc.c b/libavcodec/mpeg4videoenc.c index 98254c2c6..a10da6af8 100644 --- a/libavcodec/mpeg4videoenc.c +++ b/libavcodec/mpeg4videoenc.c @@ -29,14 +29,21 @@ #include "mpegvideo.h" #include "h263.h" #include "h263enc.h" +#include "mathops.h" #include "mpeg4video.h" #include "mpeg4videodata.h" #include "mpeg4videodefs.h" #include "mpeg4videoenc.h" #include "mpegvideoenc.h" #include "profiles.h" +#include "put_bits.h" #include "version.h" +/** + * Minimal fcode that a motion vector component would need. + */ +static uint8_t fcode_tab[MAX_MV*2+1]; + /* The uni_DCtab_* tables below contain unified bits+length tables to encode DC * differences in MPEG-4. Unified in the sense that the specification specifies * this encoding in several steps. */ @@ -66,11 +73,22 @@ static uint8_t uni_mpeg4_inter_rl_len[64 * 64 * 2 * 2]; * max run: 29/41 */ +typedef struct Mpeg4EncContext { + MPVMainEncContext m; + /// number of bits to represent the fractional part of time + int time_increment_bits; +} Mpeg4EncContext; + +static inline Mpeg4EncContext *mainctx_to_mpeg4(MPVMainEncContext *m) +{ + return (Mpeg4EncContext*)m; +} + /** * Return the number of bits that encoding the 8x8 block in block would need. * @param[in] block_last_index last index in scantable order that refers to a non zero element in block. */ -static inline int get_block_rate(MpegEncContext *s, int16_t block[64], +static inline int get_block_rate(MPVEncContext *const s, int16_t block[64], int block_last_index, const uint8_t scantable[64]) { int last = 0; @@ -99,102 +117,132 @@ static inline int get_block_rate(MpegEncContext *s, int16_t block[64], /** * Restore the ac coefficients in block that have been changed by decide_ac_pred(). - * This function also restores s->block_last_index. + * This function also restores s->c.block_last_index. * @param[in,out] block MB coefficients, these will be restored * @param[in] dir ac prediction direction for each 8x8 block * @param[out] st scantable for each 8x8 block * @param[in] zigzag_last_index index referring to the last non zero coefficient in zigzag order */ -static inline void restore_ac_coeffs(MpegEncContext *s, int16_t block[6][64], +static inline void restore_ac_coeffs(MPVEncContext *const s, int16_t block[6][64], const int dir[6], const uint8_t *st[6], const int zigzag_last_index[6]) { int i, n; - memcpy(s->block_last_index, zigzag_last_index, sizeof(int) * 6); + memcpy(s->c.block_last_index, zigzag_last_index, sizeof(int) * 6); for (n = 0; n < 6; n++) { - int16_t *ac_val = &s->ac_val[0][0][0] + s->block_index[n] * 16; + int16_t *ac_val = &s->c.ac_val[0][0] + s->c.block_index[n] * 16; - st[n] = s->intra_scantable.permutated; + st[n] = s->c.intra_scantable.permutated; if (dir[n]) { /* top prediction */ for (i = 1; i < 8; i++) - block[n][s->idsp.idct_permutation[i]] = ac_val[i + 8]; + block[n][s->c.idsp.idct_permutation[i]] = ac_val[i + 8]; } else { /* left prediction */ for (i = 1; i < 8; i++) - block[n][s->idsp.idct_permutation[i << 3]] = ac_val[i]; + block[n][s->c.idsp.idct_permutation[i << 3]] = ac_val[i]; } } } +/** + * Predict the dc. + * @param n block index (0-3 are luma, 4-5 are chroma) + * @param dir_ptr pointer to an integer where the prediction direction will be stored + */ +static int mpeg4_pred_dc(MpegEncContext *s, int n, int *dir_ptr) +{ + const int16_t *const dc_val = s->dc_val + s->block_index[n]; + const int wrap = s->block_wrap[n]; + + /* B C + * A X + */ + const int a = dc_val[-1]; + const int b = dc_val[-1 - wrap]; + const int c = dc_val[-wrap]; + int pred; + + // There is no need for out-of-slice handling here, as all values are set + // appropriately when a new slice is opened. + if (abs(a - b) < abs(b - c)) { + pred = c; + *dir_ptr = 1; /* top */ + } else { + pred = a; + *dir_ptr = 0; /* left */ + } + return pred; +} + /** * Return the optimal value (0 or 1) for the ac_pred element for the given MB in MPEG-4. - * This function will also update s->block_last_index and s->ac_val. + * This function will also update s->c.block_last_index and s->c.ac_val. * @param[in,out] block MB coefficients, these will be updated if 1 is returned * @param[in] dir ac prediction direction for each 8x8 block * @param[out] st scantable for each 8x8 block * @param[out] zigzag_last_index index referring to the last non zero coefficient in zigzag order */ -static inline int decide_ac_pred(MpegEncContext *s, int16_t block[6][64], +static inline int decide_ac_pred(MPVEncContext *const s, int16_t block[6][64], const int dir[6], const uint8_t *st[6], int zigzag_last_index[6]) { int score = 0; int i, n; - const int8_t *const qscale_table = s->cur_pic.qscale_table; + const int8_t *const qscale_table = s->c.cur_pic.qscale_table; - memcpy(zigzag_last_index, s->block_last_index, sizeof(int) * 6); + memcpy(zigzag_last_index, s->c.block_last_index, sizeof(int) * 6); for (n = 0; n < 6; n++) { int16_t *ac_val, *ac_val1; - score -= get_block_rate(s, block[n], s->block_last_index[n], - s->intra_scantable.permutated); + score -= get_block_rate(s, block[n], s->c.block_last_index[n], + s->c.intra_scantable.permutated); - ac_val = &s->ac_val[0][0][0] + s->block_index[n] * 16; + ac_val = &s->c.ac_val[0][0] + s->c.block_index[n] * 16; ac_val1 = ac_val; if (dir[n]) { - const int xy = s->mb_x + s->mb_y * s->mb_stride - s->mb_stride; + const int xy = s->c.mb_x + s->c.mb_y * s->c.mb_stride - s->c.mb_stride; /* top prediction */ - ac_val -= s->block_wrap[n] * 16; - if (s->mb_y == 0 || s->qscale == qscale_table[xy] || n == 2 || n == 3) { + ac_val -= s->c.block_wrap[n] * 16; + if (s->c.first_slice_line || s->c.qscale == qscale_table[xy] || n == 2 || n == 3) { /* same qscale */ for (i = 1; i < 8; i++) { - const int level = block[n][s->idsp.idct_permutation[i]]; - block[n][s->idsp.idct_permutation[i]] = level - ac_val[i + 8]; - ac_val1[i] = block[n][s->idsp.idct_permutation[i << 3]]; + const int level = block[n][s->c.idsp.idct_permutation[i]]; + block[n][s->c.idsp.idct_permutation[i]] = level - ac_val[i + 8]; + ac_val1[i] = block[n][s->c.idsp.idct_permutation[i << 3]]; ac_val1[i + 8] = level; } } else { /* different qscale, we must rescale */ for (i = 1; i < 8; i++) { - const int level = block[n][s->idsp.idct_permutation[i]]; - block[n][s->idsp.idct_permutation[i]] = level - ROUNDED_DIV(ac_val[i + 8] * qscale_table[xy], s->qscale); - ac_val1[i] = block[n][s->idsp.idct_permutation[i << 3]]; + const int level = block[n][s->c.idsp.idct_permutation[i]]; + block[n][s->c.idsp.idct_permutation[i]] = level - ROUNDED_DIV(ac_val[i + 8] * qscale_table[xy], s->c.qscale); + ac_val1[i] = block[n][s->c.idsp.idct_permutation[i << 3]]; ac_val1[i + 8] = level; } } st[n] = s->permutated_intra_h_scantable; } else { - const int xy = s->mb_x - 1 + s->mb_y * s->mb_stride; + const int xy = s->c.mb_x - 1 + s->c.mb_y * s->c.mb_stride; /* left prediction */ ac_val -= 16; - if (s->mb_x == 0 || s->qscale == qscale_table[xy] || n == 1 || n == 3) { + if (s->c.mb_x == 0 || s->c.qscale == qscale_table[xy] || n == 1 || n == 3) { /* same qscale */ for (i = 1; i < 8; i++) { - const int level = block[n][s->idsp.idct_permutation[i << 3]]; - block[n][s->idsp.idct_permutation[i << 3]] = level - ac_val[i]; + const int level = block[n][s->c.idsp.idct_permutation[i << 3]]; + block[n][s->c.idsp.idct_permutation[i << 3]] = level - ac_val[i]; ac_val1[i] = level; - ac_val1[i + 8] = block[n][s->idsp.idct_permutation[i]]; + ac_val1[i + 8] = block[n][s->c.idsp.idct_permutation[i]]; } } else { /* different qscale, we must rescale */ for (i = 1; i < 8; i++) { - const int level = block[n][s->idsp.idct_permutation[i << 3]]; - block[n][s->idsp.idct_permutation[i << 3]] = level - ROUNDED_DIV(ac_val[i] * qscale_table[xy], s->qscale); + const int level = block[n][s->c.idsp.idct_permutation[i << 3]]; + block[n][s->c.idsp.idct_permutation[i << 3]] = level - ROUNDED_DIV(ac_val[i] * qscale_table[xy], s->c.qscale); ac_val1[i] = level; - ac_val1[i + 8] = block[n][s->idsp.idct_permutation[i]]; + ac_val1[i + 8] = block[n][s->c.idsp.idct_permutation[i]]; } } st[n] = s->permutated_intra_v_scantable; @@ -203,9 +251,9 @@ static inline int decide_ac_pred(MpegEncContext *s, int16_t block[6][64], for (i = 63; i > 0; i--) // FIXME optimize if (block[n][st[n][i]]) break; - s->block_last_index[n] = i; + s->c.block_last_index[n] = i; - score += get_block_rate(s, block[n], s->block_last_index[n], st[n]); + score += get_block_rate(s, block[n], s->c.block_last_index[n], st[n]); } if (score < 0) { @@ -219,39 +267,37 @@ static inline int decide_ac_pred(MpegEncContext *s, int16_t block[6][64], /** * modify mb_type & qscale so that encoding is actually possible in MPEG-4 */ -void ff_clean_mpeg4_qscales(MpegEncContext *s) +void ff_clean_mpeg4_qscales(MPVEncContext *const s) { - int i; - int8_t *const qscale_table = s->cur_pic.qscale_table; - ff_clean_h263_qscales(s); - if (s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) { + int8_t *const qscale_table = s->c.cur_pic.qscale_table; int odd = 0; /* ok, come on, this isn't funny anymore, there's more code for * handling this MPEG-4 mess than for the actual adaptive quantization */ - for (i = 0; i < s->mb_num; i++) { - int mb_xy = s->mb_index2xy[i]; + for (int i = 0; i < s->c.mb_num; i++) { + int mb_xy = s->c.mb_index2xy[i]; odd += qscale_table[mb_xy] & 1; } - if (2 * odd > s->mb_num) + if (2 * odd > s->c.mb_num) odd = 1; else odd = 0; - for (i = 0; i < s->mb_num; i++) { - int mb_xy = s->mb_index2xy[i]; + for (int i = 0; i < s->c.mb_num; i++) { + int mb_xy = s->c.mb_index2xy[i]; if ((qscale_table[mb_xy] & 1) != odd) qscale_table[mb_xy]++; if (qscale_table[mb_xy] > 31) qscale_table[mb_xy] = 31; } - for (i = 1; i < s->mb_num; i++) { - int mb_xy = s->mb_index2xy[i]; - if (qscale_table[mb_xy] != qscale_table[s->mb_index2xy[i - 1]] && + for (int i = 1; i < s->c.mb_num; i++) { + int mb_xy = s->c.mb_index2xy[i]; + if (qscale_table[mb_xy] != qscale_table[s->c.mb_index2xy[i - 1]] && (s->mb_type[mb_xy] & CANDIDATE_MB_TYPE_DIRECT)) { s->mb_type[mb_xy] |= CANDIDATE_MB_TYPE_BIDIR; } @@ -276,46 +322,19 @@ static inline void mpeg4_encode_dc(PutBitContext *s, int level, int n) } } -static inline int mpeg4_get_dc_length(int level, int n) -{ - if (n < 4) - return uni_DCtab_lum_len[level + 256]; - else - return uni_DCtab_chrom_len[level + 256]; -} - /** - * Encode an 8x8 block. - * @param n block index (0-3 are luma, 4-5 are chroma) + * Encode the AC coefficients of an 8x8 block. */ -static inline void mpeg4_encode_block(const MpegEncContext *s, - const int16_t *block, int n, int intra_dc, - const uint8_t *scan_table, PutBitContext *dc_pb, - PutBitContext *ac_pb) +static inline void mpeg4_encode_ac_coeffs(const int16_t block[64], + const int last_index, int i, + const uint8_t *const scan_table, + PutBitContext *const ac_pb, + const uint32_t *const bits_tab, + const uint8_t *const len_tab) { - int i, last_non_zero; - const uint32_t *bits_tab; - const uint8_t *len_tab; - const int last_index = s->block_last_index[n]; - - if (s->mb_intra) { // Note gcc (3.2.1 at least) will optimize this away - /* MPEG-4 based DC predictor */ - mpeg4_encode_dc(dc_pb, intra_dc, n); - if (last_index < 1) - return; - i = 1; - bits_tab = uni_mpeg4_intra_rl_bits; - len_tab = uni_mpeg4_intra_rl_len; - } else { - if (last_index < 0) - return; - i = 0; - bits_tab = uni_mpeg4_inter_rl_bits; - len_tab = uni_mpeg4_inter_rl_len; - } + int last_non_zero = i - 1; /* AC coefs */ - last_non_zero = i - 1; for (; i < last_index; i++) { int level = block[scan_table[i]]; if (level) { @@ -349,97 +368,44 @@ static inline void mpeg4_encode_block(const MpegEncContext *s, } } -static int mpeg4_get_block_length(MpegEncContext *s, - const int16_t *block, int n, - int intra_dc, const uint8_t *scan_table) +static void mpeg4_encode_blocks_inter(MPVEncContext *const s, + const int16_t block[6][64], + PutBitContext *ac_pb) { - int i, last_non_zero; - const uint8_t *len_tab; - const int last_index = s->block_last_index[n]; - int len = 0; - - if (s->mb_intra) { // Note gcc (3.2.1 at least) will optimize this away - /* MPEG-4 based DC predictor */ - len += mpeg4_get_dc_length(intra_dc, n); - if (last_index < 1) - return len; - i = 1; - len_tab = uni_mpeg4_intra_rl_len; - } else { + /* encode each block */ + for (int n = 0; n < 6; ++n) { + const int last_index = s->c.block_last_index[n]; if (last_index < 0) - return 0; - i = 0; - len_tab = uni_mpeg4_inter_rl_len; - } + continue; - /* AC coefs */ - last_non_zero = i - 1; - for (; i < last_index; i++) { - int level = block[scan_table[i]]; - if (level) { - int run = i - last_non_zero - 1; - level += 64; - if ((level & (~127)) == 0) { - const int index = UNI_MPEG4_ENC_INDEX(0, run, level); - len += len_tab[index]; - } else { // ESC3 - len += 7 + 2 + 1 + 6 + 1 + 12 + 1; - } - last_non_zero = i; - } + mpeg4_encode_ac_coeffs(block[n], last_index, 0, + s->c.intra_scantable.permutated, ac_pb, + uni_mpeg4_inter_rl_bits, uni_mpeg4_inter_rl_len); } - /* if (i <= last_index) */ { - int level = block[scan_table[i]]; - int run = i - last_non_zero - 1; - level += 64; - if ((level & (~127)) == 0) { - const int index = UNI_MPEG4_ENC_INDEX(1, run, level); - len += len_tab[index]; - } else { // ESC3 - len += 7 + 2 + 1 + 6 + 1 + 12 + 1; - } - } - - return len; } -static inline void mpeg4_encode_blocks(MpegEncContext *s, - const int16_t block[6][64], - const int intra_dc[6], - const uint8_t * const *scan_table, - PutBitContext *dc_pb, - PutBitContext *ac_pb) +static void mpeg4_encode_blocks_intra(MPVEncContext *const s, + const int16_t block[6][64], + const int intra_dc[6], + const uint8_t * const *scan_table, + PutBitContext *dc_pb, + PutBitContext *ac_pb) { - int i; + /* encode each block */ + for (int n = 0; n < 6; ++n) { + mpeg4_encode_dc(dc_pb, intra_dc[n], n); - if (scan_table) { - if (s->avctx->flags2 & AV_CODEC_FLAG2_NO_OUTPUT) { - for (i = 0; i < 6; i++) - skip_put_bits(&s->pb, - mpeg4_get_block_length(s, block[i], i, - intra_dc[i], scan_table[i])); - } else { - /* encode each block */ - for (i = 0; i < 6; i++) - mpeg4_encode_block(s, block[i], i, - intra_dc[i], scan_table[i], dc_pb, ac_pb); - } - } else { - if (s->avctx->flags2 & AV_CODEC_FLAG2_NO_OUTPUT) { - for (i = 0; i < 6; i++) - skip_put_bits(&s->pb, - mpeg4_get_block_length(s, block[i], i, 0, - s->intra_scantable.permutated)); - } else { - /* encode each block */ - for (i = 0; i < 6; i++) - mpeg4_encode_block(s, block[i], i, 0, - s->intra_scantable.permutated, dc_pb, ac_pb); - } + const int last_index = s->c.block_last_index[n]; + if (last_index <= 0) + continue; + + mpeg4_encode_ac_coeffs(block[n], last_index, 1, + scan_table[n], ac_pb, + uni_mpeg4_intra_rl_bits, uni_mpeg4_intra_rl_len); } } -static inline int get_b_cbp(MpegEncContext *s, int16_t block[6][64], +static inline int get_b_cbp(MPVEncContext *const s, int16_t block[6][64], int motion_x, int motion_y, int mb_type) { int cbp = 0, i; @@ -466,14 +432,14 @@ static inline int get_b_cbp(MpegEncContext *s, int16_t block[6][64], } for (i = 0; i < 6; i++) { - if (s->block_last_index[i] >= 0 && ((cbp >> (5 - i)) & 1) == 0) { - s->block_last_index[i] = -1; - s->bdsp.clear_block(s->block[i]); + if (s->c.block_last_index[i] >= 0 && ((cbp >> (5 - i)) & 1) == 0) { + s->c.block_last_index[i] = -1; + s->c.bdsp.clear_block(s->block[i]); } } } else { for (i = 0; i < 6; i++) { - if (s->block_last_index[i] >= 0) + if (s->c.block_last_index[i] >= 0) cbp |= 1 << (5 - i); } } @@ -483,29 +449,29 @@ static inline int get_b_cbp(MpegEncContext *s, int16_t block[6][64], // FIXME this is duplicated to h263.c static const int dquant_code[5] = { 1, 0, 9, 2, 3 }; -void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], - int motion_x, int motion_y) +static void mpeg4_encode_mb(MPVEncContext *const s, int16_t block[][64], + int motion_x, int motion_y) { int cbpc, cbpy, pred_x, pred_y; PutBitContext *const pb2 = s->data_partitioning ? &s->pb2 : &s->pb; - PutBitContext *const tex_pb = s->data_partitioning && s->pict_type != AV_PICTURE_TYPE_B ? &s->tex_pb : &s->pb; - PutBitContext *const dc_pb = s->data_partitioning && s->pict_type != AV_PICTURE_TYPE_I ? &s->pb2 : &s->pb; - const int interleaved_stats = (s->avctx->flags & AV_CODEC_FLAG_PASS1) && !s->data_partitioning ? 1 : 0; + PutBitContext *const tex_pb = s->data_partitioning && s->c.pict_type != AV_PICTURE_TYPE_B ? &s->tex_pb : &s->pb; + PutBitContext *const dc_pb = s->data_partitioning && s->c.pict_type != AV_PICTURE_TYPE_I ? &s->pb2 : &s->pb; + const int interleaved_stats = (s->c.avctx->flags & AV_CODEC_FLAG_PASS1) && !s->data_partitioning; - if (!s->mb_intra) { + if (!s->c.mb_intra) { int i, cbp; - if (s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) { /* convert from mv_dir to type */ static const int mb_type_table[8] = { -1, 3, 2, 1, -1, -1, -1, 0 }; - int mb_type = mb_type_table[s->mv_dir]; + int mb_type = mb_type_table[s->c.mv_dir]; - if (s->mb_x == 0) { + if (s->c.mb_x == 0) { for (i = 0; i < 2; i++) - s->last_mv[i][0][0] = - s->last_mv[i][0][1] = - s->last_mv[i][1][0] = - s->last_mv[i][1][1] = 0; + s->c.last_mv[i][0][0] = + s->c.last_mv[i][0][1] = + s->c.last_mv[i][1][0] = + s->c.last_mv[i][1][1] = 0; } av_assert2(s->dquant >= -2 && s->dquant <= 2); @@ -513,14 +479,14 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], av_assert2(mb_type >= 0); /* nothing to do if this MB was skipped in the next P-frame */ - if (s->next_pic.mbskip_table[s->mb_y * s->mb_stride + s->mb_x]) { // FIXME avoid DCT & ... - s->mv[0][0][0] = - s->mv[0][0][1] = - s->mv[1][0][0] = - s->mv[1][0][1] = 0; - s->mv_dir = MV_DIR_FORWARD; // doesn't matter - s->qscale -= s->dquant; -// s->mb_skipped = 1; + if (s->c.next_pic.mbskip_table[s->c.mb_y * s->c.mb_stride + s->c.mb_x]) { // FIXME avoid DCT & ... + s->c.mv[0][0][0] = + s->c.mv[0][0][1] = + s->c.mv[1][0][0] = + s->c.mv[1][0][1] = 0; + s->c.mv_dir = MV_DIR_FORWARD; // doesn't matter + s->c.qscale -= s->dquant; +// s->c.mb_skipped = 1; return; } @@ -552,71 +518,71 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], else put_bits(&s->pb, 1, 0); } else - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; - if (!s->progressive_sequence) { + if (!s->c.progressive_sequence) { if (cbp) - put_bits(&s->pb, 1, s->interlaced_dct); + put_bits(&s->pb, 1, s->c.interlaced_dct); if (mb_type) // not direct mode - put_bits(&s->pb, 1, s->mv_type == MV_TYPE_FIELD); + put_bits(&s->pb, 1, s->c.mv_type == MV_TYPE_FIELD); } if (interleaved_stats) s->misc_bits += get_bits_diff(s); if (!mb_type) { - av_assert2(s->mv_dir & MV_DIRECT); + av_assert2(s->c.mv_dir & MV_DIRECT); ff_h263_encode_motion_vector(s, motion_x, motion_y, 1); } else { av_assert2(mb_type > 0 && mb_type < 4); - if (s->mv_type != MV_TYPE_FIELD) { - if (s->mv_dir & MV_DIR_FORWARD) { + if (s->c.mv_type != MV_TYPE_FIELD) { + if (s->c.mv_dir & MV_DIR_FORWARD) { ff_h263_encode_motion_vector(s, - s->mv[0][0][0] - s->last_mv[0][0][0], - s->mv[0][0][1] - s->last_mv[0][0][1], + s->c.mv[0][0][0] - s->c.last_mv[0][0][0], + s->c.mv[0][0][1] - s->c.last_mv[0][0][1], s->f_code); - s->last_mv[0][0][0] = - s->last_mv[0][1][0] = s->mv[0][0][0]; - s->last_mv[0][0][1] = - s->last_mv[0][1][1] = s->mv[0][0][1]; + s->c.last_mv[0][0][0] = + s->c.last_mv[0][1][0] = s->c.mv[0][0][0]; + s->c.last_mv[0][0][1] = + s->c.last_mv[0][1][1] = s->c.mv[0][0][1]; } - if (s->mv_dir & MV_DIR_BACKWARD) { + if (s->c.mv_dir & MV_DIR_BACKWARD) { ff_h263_encode_motion_vector(s, - s->mv[1][0][0] - s->last_mv[1][0][0], - s->mv[1][0][1] - s->last_mv[1][0][1], + s->c.mv[1][0][0] - s->c.last_mv[1][0][0], + s->c.mv[1][0][1] - s->c.last_mv[1][0][1], s->b_code); - s->last_mv[1][0][0] = - s->last_mv[1][1][0] = s->mv[1][0][0]; - s->last_mv[1][0][1] = - s->last_mv[1][1][1] = s->mv[1][0][1]; + s->c.last_mv[1][0][0] = + s->c.last_mv[1][1][0] = s->c.mv[1][0][0]; + s->c.last_mv[1][0][1] = + s->c.last_mv[1][1][1] = s->c.mv[1][0][1]; } } else { - if (s->mv_dir & MV_DIR_FORWARD) { - put_bits(&s->pb, 1, s->field_select[0][0]); - put_bits(&s->pb, 1, s->field_select[0][1]); + if (s->c.mv_dir & MV_DIR_FORWARD) { + put_bits(&s->pb, 1, s->c.field_select[0][0]); + put_bits(&s->pb, 1, s->c.field_select[0][1]); } - if (s->mv_dir & MV_DIR_BACKWARD) { - put_bits(&s->pb, 1, s->field_select[1][0]); - put_bits(&s->pb, 1, s->field_select[1][1]); + if (s->c.mv_dir & MV_DIR_BACKWARD) { + put_bits(&s->pb, 1, s->c.field_select[1][0]); + put_bits(&s->pb, 1, s->c.field_select[1][1]); } - if (s->mv_dir & MV_DIR_FORWARD) { + if (s->c.mv_dir & MV_DIR_FORWARD) { for (i = 0; i < 2; i++) { ff_h263_encode_motion_vector(s, - s->mv[0][i][0] - s->last_mv[0][i][0], - s->mv[0][i][1] - s->last_mv[0][i][1] / 2, + s->c.mv[0][i][0] - s->c.last_mv[0][i][0], + s->c.mv[0][i][1] - s->c.last_mv[0][i][1] / 2, s->f_code); - s->last_mv[0][i][0] = s->mv[0][i][0]; - s->last_mv[0][i][1] = s->mv[0][i][1] * 2; + s->c.last_mv[0][i][0] = s->c.mv[0][i][0]; + s->c.last_mv[0][i][1] = s->c.mv[0][i][1] * 2; } } - if (s->mv_dir & MV_DIR_BACKWARD) { + if (s->c.mv_dir & MV_DIR_BACKWARD) { for (i = 0; i < 2; i++) { ff_h263_encode_motion_vector(s, - s->mv[1][i][0] - s->last_mv[1][i][0], - s->mv[1][i][1] - s->last_mv[1][i][1] / 2, + s->c.mv[1][i][0] - s->c.last_mv[1][i][0], + s->c.mv[1][i][1] - s->c.last_mv[1][i][1] / 2, s->b_code); - s->last_mv[1][i][0] = s->mv[1][i][0]; - s->last_mv[1][i][1] = s->mv[1][i][1] * 2; + s->c.last_mv[1][i][0] = s->c.mv[1][i][0]; + s->c.last_mv[1][i][1] = s->c.mv[1][i][1] * 2; } } } @@ -625,34 +591,34 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], if (interleaved_stats) s->mv_bits += get_bits_diff(s); - mpeg4_encode_blocks(s, block, NULL, NULL, NULL, &s->pb); + mpeg4_encode_blocks_inter(s, block, &s->pb); if (interleaved_stats) s->p_tex_bits += get_bits_diff(s); - } else { /* s->pict_type==AV_PICTURE_TYPE_B */ + } else { /* s->c.pict_type == AV_PICTURE_TYPE_B */ cbp = get_p_cbp(s, block, motion_x, motion_y); if ((cbp | motion_x | motion_y | s->dquant) == 0 && - s->mv_type == MV_TYPE_16X16) { + s->c.mv_type == MV_TYPE_16X16) { + const MPVMainEncContext *const m = slice_to_mainenc(s); /* Check if the B-frames can skip it too, as we must skip it * if we skip here why didn't they just compress * the skip-mb bits instead of reusing them ?! */ - if (s->max_b_frames > 0) { - int i; + if (m->max_b_frames > 0) { int x, y, offset; const uint8_t *p_pic; - x = s->mb_x * 16; - y = s->mb_y * 16; + x = s->c.mb_x * 16; + y = s->c.mb_y * 16; - offset = x + y * s->linesize; + offset = x + y * s->c.linesize; p_pic = s->new_pic->data[0] + offset; - s->mb_skipped = 1; - for (i = 0; i < s->max_b_frames; i++) { + s->c.mb_skipped = 1; + for (int i = 0; i < m->max_b_frames; i++) { const uint8_t *b_pic; int diff; - const MPVPicture *pic = s->reordered_input_picture[i + 1]; + const MPVPicture *pic = m->reordered_input_picture[i + 1]; if (!pic || pic->f->pict_type != AV_PICTURE_TYPE_B) break; @@ -661,29 +627,29 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], if (!pic->shared) b_pic += INPLACE_OFFSET; - if (x + 16 > s->width || y + 16 > s->height) { + if (x + 16 > s->c.width || y + 16 > s->c.height) { int x1, y1; - int xe = FFMIN(16, s->width - x); - int ye = FFMIN(16, s->height - y); + int xe = FFMIN(16, s->c.width - x); + int ye = FFMIN(16, s->c.height - y); diff = 0; for (y1 = 0; y1 < ye; y1++) { for (x1 = 0; x1 < xe; x1++) { - diff += FFABS(p_pic[x1 + y1 * s->linesize] - b_pic[x1 + y1 * s->linesize]); + diff += FFABS(p_pic[x1 + y1 * s->c.linesize] - b_pic[x1 + y1 * s->c.linesize]); } } diff = diff * 256 / (xe * ye); } else { - diff = s->sad_cmp[0](NULL, p_pic, b_pic, s->linesize, 16); + diff = s->sad_cmp[0](NULL, p_pic, b_pic, s->c.linesize, 16); } - if (diff > s->qscale * 70) { // FIXME check that 70 is optimal - s->mb_skipped = 0; + if (diff > s->c.qscale * 70) { // FIXME check that 70 is optimal + s->c.mb_skipped = 0; break; } } } else - s->mb_skipped = 1; + s->c.mb_skipped = 1; - if (s->mb_skipped == 1) { + if (s->c.mb_skipped == 1) { /* skip macroblock */ put_bits(&s->pb, 1, 1); @@ -700,7 +666,7 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], cbpc = cbp & 3; cbpy = cbp >> 2; cbpy ^= 0xf; - if (s->mv_type == MV_TYPE_16X16) { + if (s->c.mv_type == MV_TYPE_16X16) { if (s->dquant) cbpc += 8; put_bits(&s->pb, @@ -711,9 +677,9 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], if (s->dquant) put_bits(pb2, 2, dquant_code[s->dquant + 2]); - if (!s->progressive_sequence) { + if (!s->c.progressive_sequence) { if (cbp) - put_bits(pb2, 1, s->interlaced_dct); + put_bits(pb2, 1, s->c.interlaced_dct); put_bits(pb2, 1, 0); } @@ -721,13 +687,13 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], s->misc_bits += get_bits_diff(s); /* motion vectors: 16x16 mode */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); ff_h263_encode_motion_vector(s, motion_x - pred_x, motion_y - pred_y, s->f_code); - } else if (s->mv_type == MV_TYPE_FIELD) { + } else if (s->c.mv_type == MV_TYPE_FIELD) { if (s->dquant) cbpc += 8; put_bits(&s->pb, @@ -738,49 +704,49 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], if (s->dquant) put_bits(pb2, 2, dquant_code[s->dquant + 2]); - av_assert2(!s->progressive_sequence); + av_assert2(!s->c.progressive_sequence); if (cbp) - put_bits(pb2, 1, s->interlaced_dct); + put_bits(pb2, 1, s->c.interlaced_dct); put_bits(pb2, 1, 1); if (interleaved_stats) s->misc_bits += get_bits_diff(s); /* motion vectors: 16x8 interlaced mode */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); pred_y /= 2; - put_bits(&s->pb, 1, s->field_select[0][0]); - put_bits(&s->pb, 1, s->field_select[0][1]); + put_bits(&s->pb, 1, s->c.field_select[0][0]); + put_bits(&s->pb, 1, s->c.field_select[0][1]); ff_h263_encode_motion_vector(s, - s->mv[0][0][0] - pred_x, - s->mv[0][0][1] - pred_y, + s->c.mv[0][0][0] - pred_x, + s->c.mv[0][0][1] - pred_y, s->f_code); ff_h263_encode_motion_vector(s, - s->mv[0][1][0] - pred_x, - s->mv[0][1][1] - pred_y, + s->c.mv[0][1][0] - pred_x, + s->c.mv[0][1][1] - pred_y, s->f_code); } else { - av_assert2(s->mv_type == MV_TYPE_8X8); + av_assert2(s->c.mv_type == MV_TYPE_8X8); put_bits(&s->pb, ff_h263_inter_MCBPC_bits[cbpc + 16], ff_h263_inter_MCBPC_code[cbpc + 16]); put_bits(pb2, ff_h263_cbpy_tab[cbpy][1], ff_h263_cbpy_tab[cbpy][0]); - if (!s->progressive_sequence && cbp) - put_bits(pb2, 1, s->interlaced_dct); + if (!s->c.progressive_sequence && cbp) + put_bits(pb2, 1, s->c.interlaced_dct); if (interleaved_stats) s->misc_bits += get_bits_diff(s); for (i = 0; i < 4; i++) { /* motion vectors: 8x8 mode*/ - ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, i, 0, &pred_x, &pred_y); ff_h263_encode_motion_vector(s, - s->cur_pic.motion_val[0][s->block_index[i]][0] - pred_x, - s->cur_pic.motion_val[0][s->block_index[i]][1] - pred_y, + s->c.cur_pic.motion_val[0][s->c.block_index[i]][0] - pred_x, + s->c.cur_pic.motion_val[0][s->c.block_index[i]][1] - pred_y, s->f_code); } } @@ -788,7 +754,7 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], if (interleaved_stats) s->mv_bits += get_bits_diff(s); - mpeg4_encode_blocks(s, block, NULL, NULL, NULL, tex_pb); + mpeg4_encode_blocks_inter(s, block, tex_pb); if (interleaved_stats) s->p_tex_bits += get_bits_diff(s); @@ -801,24 +767,30 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], const uint8_t *scan_table[6]; int i; - for (i = 0; i < 6; i++) - dc_diff[i] = ff_mpeg4_pred_dc(s, i, block[i][0], &dir[i], 1); + for (int i = 0; i < 6; i++) { + int pred = mpeg4_pred_dc(&s->c, i, &dir[i]); + int scale = i < 4 ? s->c.y_dc_scale : s->c.c_dc_scale; - if (s->avctx->flags & AV_CODEC_FLAG_AC_PRED) { - s->ac_pred = decide_ac_pred(s, block, dir, scan_table, zigzag_last_index); + pred = FASTDIV((pred + (scale >> 1)), scale); + dc_diff[i] = block[i][0] - pred; + s->c.dc_val[s->c.block_index[i]] = av_clip_uintp2(block[i][0] * scale, 11); + } + + if (s->c.avctx->flags & AV_CODEC_FLAG_AC_PRED) { + s->c.ac_pred = decide_ac_pred(s, block, dir, scan_table, zigzag_last_index); } else { for (i = 0; i < 6; i++) - scan_table[i] = s->intra_scantable.permutated; + scan_table[i] = s->c.intra_scantable.permutated; } /* compute cbp */ cbp = 0; for (i = 0; i < 6; i++) - if (s->block_last_index[i] >= 1) + if (s->c.block_last_index[i] >= 1) cbp |= 1 << (5 - i); cbpc = cbp & 3; - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { if (s->dquant) cbpc += 4; put_bits(&s->pb, @@ -832,19 +804,19 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], ff_h263_inter_MCBPC_bits[cbpc + 4], ff_h263_inter_MCBPC_code[cbpc + 4]); } - put_bits(pb2, 1, s->ac_pred); + put_bits(pb2, 1, s->c.ac_pred); cbpy = cbp >> 2; put_bits(pb2, ff_h263_cbpy_tab[cbpy][1], ff_h263_cbpy_tab[cbpy][0]); if (s->dquant) put_bits(dc_pb, 2, dquant_code[s->dquant + 2]); - if (!s->progressive_sequence) - put_bits(dc_pb, 1, s->interlaced_dct); + if (!s->c.progressive_sequence) + put_bits(dc_pb, 1, s->c.interlaced_dct); if (interleaved_stats) s->misc_bits += get_bits_diff(s); - mpeg4_encode_blocks(s, block, dc_diff, scan_table, dc_pb, tex_pb); + mpeg4_encode_blocks_intra(s, block, dc_diff, scan_table, dc_pb, tex_pb); if (interleaved_stats) s->i_tex_bits += get_bits_diff(s); @@ -852,7 +824,7 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], /* restore ac coeffs & last_index stuff * if we messed them up with the prediction */ - if (s->ac_pred) + if (s->c.ac_pred) restore_ac_coeffs(s, block, dir, scan_table, zigzag_last_index); } } @@ -868,30 +840,31 @@ void ff_mpeg4_stuffing(PutBitContext *pbc) } /* must be called before writing the header */ -void ff_set_mpeg4_time(MpegEncContext *s) +void ff_set_mpeg4_time(MPVEncContext *const s) { - if (s->pict_type == AV_PICTURE_TYPE_B) { - ff_mpeg4_init_direct_mv(s); + if (s->c.pict_type == AV_PICTURE_TYPE_B) { + ff_mpeg4_init_direct_mv(&s->c); } else { - s->last_time_base = s->time_base; - s->time_base = FFUDIV(s->time, s->avctx->time_base.den); + s->c.last_time_base = s->c.time_base; + s->c.time_base = FFUDIV(s->c.time, s->c.avctx->time_base.den); } } -static void mpeg4_encode_gop_header(MpegEncContext *s) +static void mpeg4_encode_gop_header(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int64_t hours, minutes, seconds; int64_t time; put_bits32(&s->pb, GOP_STARTCODE); - time = s->cur_pic.ptr->f->pts; - if (s->reordered_input_picture[1]) - time = FFMIN(time, s->reordered_input_picture[1]->f->pts); - time = time * s->avctx->time_base.num; - s->last_time_base = FFUDIV(time, s->avctx->time_base.den); + time = s->c.cur_pic.ptr->f->pts; + if (m->reordered_input_picture[1]) + time = FFMIN(time, m->reordered_input_picture[1]->f->pts); + time = time * s->c.avctx->time_base.num; + s->c.last_time_base = FFUDIV(time, s->c.avctx->time_base.den); - seconds = FFUDIV(time, s->avctx->time_base.den); + seconds = FFUDIV(time, s->c.avctx->time_base.den); minutes = FFUDIV(seconds, 60); seconds = FFUMOD(seconds, 60); hours = FFUDIV(minutes, 60); minutes = FFUMOD(minutes, 60); hours = FFUMOD(hours , 24); @@ -901,27 +874,28 @@ static void mpeg4_encode_gop_header(MpegEncContext *s) put_bits(&s->pb, 1, 1); put_bits(&s->pb, 6, seconds); - put_bits(&s->pb, 1, !!(s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP)); + put_bits(&s->pb, 1, !!(s->c.avctx->flags & AV_CODEC_FLAG_CLOSED_GOP)); put_bits(&s->pb, 1, 0); // broken link == NO ff_mpeg4_stuffing(&s->pb); } -static void mpeg4_encode_visual_object_header(MpegEncContext *s) +static void mpeg4_encode_visual_object_header(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int profile_and_level_indication; int vo_ver_id; - if (s->avctx->profile != AV_PROFILE_UNKNOWN) { - profile_and_level_indication = s->avctx->profile << 4; - } else if (s->max_b_frames || s->quarter_sample) { + if (s->c.avctx->profile != AV_PROFILE_UNKNOWN) { + profile_and_level_indication = s->c.avctx->profile << 4; + } else if (m->max_b_frames || s->c.quarter_sample) { profile_and_level_indication = 0xF0; // adv simple } else { profile_and_level_indication = 0x00; // simple } - if (s->avctx->level != AV_LEVEL_UNKNOWN) - profile_and_level_indication |= s->avctx->level; + if (s->c.avctx->level != AV_LEVEL_UNKNOWN) + profile_and_level_indication |= s->c.avctx->level; else profile_and_level_indication |= 1; // level 1 @@ -949,13 +923,14 @@ static void mpeg4_encode_visual_object_header(MpegEncContext *s) ff_mpeg4_stuffing(&s->pb); } -static void mpeg4_encode_vol_header(MpegEncContext *s, +static void mpeg4_encode_vol_header(Mpeg4EncContext *const m4, int vo_number, int vol_number) { + MPVEncContext *const s = &m4->m.s; int vo_ver_id, vo_type, aspect_ratio_info; - if (s->max_b_frames || s->quarter_sample) { + if (m4->m.max_b_frames || s->c.quarter_sample) { vo_ver_id = 5; vo_type = ADV_SIMPLE_VO_TYPE; } else { @@ -968,47 +943,39 @@ static void mpeg4_encode_vol_header(MpegEncContext *s, put_bits(&s->pb, 1, 0); /* random access vol */ put_bits(&s->pb, 8, vo_type); /* video obj type indication */ - if (s->workaround_bugs & FF_BUG_MS) { - put_bits(&s->pb, 1, 0); /* is obj layer id= no */ - } else { - put_bits(&s->pb, 1, 1); /* is obj layer id= yes */ - put_bits(&s->pb, 4, vo_ver_id); /* is obj layer ver id */ - put_bits(&s->pb, 3, 1); /* is obj layer priority */ - } + put_bits(&s->pb, 1, 1); /* is obj layer id= yes */ + put_bits(&s->pb, 4, vo_ver_id); /* is obj layer ver id */ + put_bits(&s->pb, 3, 1); /* is obj layer priority */ - aspect_ratio_info = ff_h263_aspect_to_info(s->avctx->sample_aspect_ratio); + aspect_ratio_info = ff_h263_aspect_to_info(s->c.avctx->sample_aspect_ratio); put_bits(&s->pb, 4, aspect_ratio_info); /* aspect ratio info */ if (aspect_ratio_info == FF_ASPECT_EXTENDED) { - av_reduce(&s->avctx->sample_aspect_ratio.num, &s->avctx->sample_aspect_ratio.den, - s->avctx->sample_aspect_ratio.num, s->avctx->sample_aspect_ratio.den, 255); - put_bits(&s->pb, 8, s->avctx->sample_aspect_ratio.num); - put_bits(&s->pb, 8, s->avctx->sample_aspect_ratio.den); + av_reduce(&s->c.avctx->sample_aspect_ratio.num, &s->c.avctx->sample_aspect_ratio.den, + s->c.avctx->sample_aspect_ratio.num, s->c.avctx->sample_aspect_ratio.den, 255); + put_bits(&s->pb, 8, s->c.avctx->sample_aspect_ratio.num); + put_bits(&s->pb, 8, s->c.avctx->sample_aspect_ratio.den); } - if (s->workaround_bugs & FF_BUG_MS) { - put_bits(&s->pb, 1, 0); /* vol control parameters= no @@@ */ - } else { - put_bits(&s->pb, 1, 1); /* vol control parameters= yes */ - put_bits(&s->pb, 2, 1); /* chroma format YUV 420/YV12 */ - put_bits(&s->pb, 1, s->low_delay); - put_bits(&s->pb, 1, 0); /* vbv parameters= no */ - } + put_bits(&s->pb, 1, 1); /* vol control parameters= yes */ + put_bits(&s->pb, 2, 1); /* chroma format YUV 420/YV12 */ + put_bits(&s->pb, 1, s->c.low_delay); + put_bits(&s->pb, 1, 0); /* vbv parameters= no */ put_bits(&s->pb, 2, RECT_SHAPE); /* vol shape= rectangle */ put_bits(&s->pb, 1, 1); /* marker bit */ - put_bits(&s->pb, 16, s->avctx->time_base.den); - if (s->time_increment_bits < 1) - s->time_increment_bits = 1; + put_bits(&s->pb, 16, s->c.avctx->time_base.den); + if (m4->time_increment_bits < 1) + m4->time_increment_bits = 1; put_bits(&s->pb, 1, 1); /* marker bit */ put_bits(&s->pb, 1, 0); /* fixed vop rate=no */ put_bits(&s->pb, 1, 1); /* marker bit */ - put_bits(&s->pb, 13, s->width); /* vol width */ + put_bits(&s->pb, 13, s->c.width); /* vol width */ put_bits(&s->pb, 1, 1); /* marker bit */ - put_bits(&s->pb, 13, s->height); /* vol height */ + put_bits(&s->pb, 13, s->c.height); /* vol height */ put_bits(&s->pb, 1, 1); /* marker bit */ - put_bits(&s->pb, 1, s->progressive_sequence ? 0 : 1); + put_bits(&s->pb, 1, s->c.progressive_sequence ? 0 : 1); put_bits(&s->pb, 1, 1); /* obmc disable */ if (vo_ver_id == 1) put_bits(&s->pb, 1, 0); /* sprite enable */ @@ -1019,15 +986,15 @@ static void mpeg4_encode_vol_header(MpegEncContext *s, put_bits(&s->pb, 1, s->mpeg_quant); /* quant type = (0 = H.263 style) */ if (s->mpeg_quant) { - ff_write_quant_matrix(&s->pb, s->avctx->intra_matrix); - ff_write_quant_matrix(&s->pb, s->avctx->inter_matrix); + ff_write_quant_matrix(&s->pb, s->c.avctx->intra_matrix); + ff_write_quant_matrix(&s->pb, s->c.avctx->inter_matrix); } if (vo_ver_id != 1) - put_bits(&s->pb, 1, s->quarter_sample); + put_bits(&s->pb, 1, s->c.quarter_sample); put_bits(&s->pb, 1, 1); /* complexity estimation disable */ put_bits(&s->pb, 1, s->rtp_mode ? 0 : 1); /* resync marker disable */ - put_bits(&s->pb, 1, s->data_partitioning ? 1 : 0); + put_bits(&s->pb, 1, s->data_partitioning); if (s->data_partitioning) put_bits(&s->pb, 1, 0); /* no rvlc */ @@ -1040,41 +1007,44 @@ static void mpeg4_encode_vol_header(MpegEncContext *s, ff_mpeg4_stuffing(&s->pb); /* user data */ - if (!(s->avctx->flags & AV_CODEC_FLAG_BITEXACT)) { + if (!(s->c.avctx->flags & AV_CODEC_FLAG_BITEXACT)) { put_bits32(&s->pb, USER_DATA_STARTCODE); ff_put_string(&s->pb, LIBAVCODEC_IDENT, 0); } } /* write MPEG-4 VOP header */ -int ff_mpeg4_encode_picture_header(MpegEncContext *s) +static int mpeg4_encode_picture_header(MPVMainEncContext *const m) { + Mpeg4EncContext *const m4 = mainctx_to_mpeg4(m); + MPVEncContext *const s = &m->s; uint64_t time_incr; int64_t time_div, time_mod; - if (s->pict_type == AV_PICTURE_TYPE_I) { - if (!(s->avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) { - if (s->avctx->strict_std_compliance < FF_COMPLIANCE_VERY_STRICT) // HACK, the reference sw is buggy - mpeg4_encode_visual_object_header(s); - if (s->avctx->strict_std_compliance < FF_COMPLIANCE_VERY_STRICT || s->picture_number == 0) // HACK, the reference sw is buggy - mpeg4_encode_vol_header(s, 0, 0); + put_bits_assume_flushed(&s->pb); + + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + if (!(s->c.avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) { + if (s->c.avctx->strict_std_compliance < FF_COMPLIANCE_VERY_STRICT) // HACK, the reference sw is buggy + mpeg4_encode_visual_object_header(m); + if (s->c.avctx->strict_std_compliance < FF_COMPLIANCE_VERY_STRICT || s->picture_number == 0) // HACK, the reference sw is buggy + mpeg4_encode_vol_header(m4, 0, 0); } - if (!(s->workaround_bugs & FF_BUG_MS)) - mpeg4_encode_gop_header(s); + mpeg4_encode_gop_header(m); } - s->partitioned_frame = s->data_partitioning && s->pict_type != AV_PICTURE_TYPE_B; + s->partitioned_frame = s->data_partitioning && s->c.pict_type != AV_PICTURE_TYPE_B; put_bits32(&s->pb, VOP_STARTCODE); /* vop header */ - put_bits(&s->pb, 2, s->pict_type - 1); /* pict type: I = 0 , P = 1 */ + put_bits(&s->pb, 2, s->c.pict_type - 1); /* pict type: I = 0 , P = 1 */ - time_div = FFUDIV(s->time, s->avctx->time_base.den); - time_mod = FFUMOD(s->time, s->avctx->time_base.den); - time_incr = time_div - s->last_time_base; + time_div = FFUDIV(s->c.time, s->c.avctx->time_base.den); + time_mod = FFUMOD(s->c.time, s->c.avctx->time_base.den); + time_incr = time_div - s->c.last_time_base; // This limits the frame duration to max 1 day if (time_incr > 3600*24) { - av_log(s->avctx, AV_LOG_ERROR, "time_incr %"PRIu64" too large\n", time_incr); + av_log(s->c.avctx, AV_LOG_ERROR, "time_incr %"PRIu64" too large\n", time_incr); return AVERROR(EINVAL); } while (time_incr--) @@ -1083,24 +1053,24 @@ int ff_mpeg4_encode_picture_header(MpegEncContext *s) put_bits(&s->pb, 1, 0); put_bits(&s->pb, 1, 1); /* marker */ - put_bits(&s->pb, s->time_increment_bits, time_mod); /* time increment */ + put_bits(&s->pb, m4->time_increment_bits, time_mod); /* time increment */ put_bits(&s->pb, 1, 1); /* marker */ put_bits(&s->pb, 1, 1); /* vop coded */ - if (s->pict_type == AV_PICTURE_TYPE_P) { - put_bits(&s->pb, 1, s->no_rounding); /* rounding type */ + if (s->c.pict_type == AV_PICTURE_TYPE_P) { + put_bits(&s->pb, 1, s->c.no_rounding); /* rounding type */ } put_bits(&s->pb, 3, 0); /* intra dc VLC threshold */ - if (!s->progressive_sequence) { - put_bits(&s->pb, 1, !!(s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); - put_bits(&s->pb, 1, s->alternate_scan); + if (!s->c.progressive_sequence) { + put_bits(&s->pb, 1, !!(s->c.cur_pic.ptr->f->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); + put_bits(&s->pb, 1, s->c.alternate_scan); } // FIXME sprite stuff - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); - if (s->pict_type != AV_PICTURE_TYPE_I) + if (s->c.pict_type != AV_PICTURE_TYPE_I) put_bits(&s->pb, 3, s->f_code); /* fcode_for */ - if (s->pict_type == AV_PICTURE_TYPE_B) + if (s->c.pict_type == AV_PICTURE_TYPE_B) put_bits(&s->pb, 3, s->b_code); /* fcode_back */ return 0; @@ -1164,95 +1134,78 @@ static av_cold void init_uni_dc_tab(void) static av_cold void init_uni_mpeg4_rl_tab(RLTable *rl, uint32_t *bits_tab, uint8_t *len_tab) { - int slevel, run, last; + // Type 3 escape method. The escape code is the same for both VLCs + // (0x3, seven bits), so it is hardcoded. + memset(len_tab, 30, 2 * 2 * 64 * 64); + len_tab += 64; + bits_tab += 64; + for (int run = 0; run < 64; ++run) { + for (int level = 1;; ++level) { + // Escape code type 3 not last run (6 bits) marker marker + unsigned code = (3 << 23) | (3 << 21) | (0 << 20) | (run << 14) | (1 << 13) | 1; + // first the negative levels + bits_tab[UNI_MPEG4_ENC_INDEX(0, run, -level)] = code | (-level & 0xfff) << 1; + bits_tab[UNI_MPEG4_ENC_INDEX(1, run, -level)] = + bits_tab[UNI_MPEG4_ENC_INDEX(0, run, -level)] | (1 << 20) /* last */; - av_assert0(MAX_LEVEL >= 64); - av_assert0(MAX_RUN >= 63); - - for (slevel = -64; slevel < 64; slevel++) { - if (slevel == 0) - continue; - for (run = 0; run < 64; run++) { - for (last = 0; last <= 1; last++) { - const int index = UNI_MPEG4_ENC_INDEX(last, run, slevel + 64); - int level = slevel < 0 ? -slevel : slevel; - int sign = slevel < 0 ? 1 : 0; - int bits, len, code; - int level1, run1; - - len_tab[index] = 100; - - /* ESC0 */ - code = get_rl_index(rl, last, run, level); - bits = rl->table_vlc[code][0]; - len = rl->table_vlc[code][1]; - bits = bits * 2 + sign; - len++; - - if (code != rl->n && len < len_tab[index]) { - bits_tab[index] = bits; - len_tab[index] = len; - } - /* ESC1 */ - bits = rl->table_vlc[rl->n][0]; - len = rl->table_vlc[rl->n][1]; - bits = bits * 2; - len++; // esc1 - level1 = level - rl->max_level[last][run]; - if (level1 > 0) { - code = get_rl_index(rl, last, run, level1); - bits <<= rl->table_vlc[code][1]; - len += rl->table_vlc[code][1]; - bits += rl->table_vlc[code][0]; - bits = bits * 2 + sign; - len++; - - if (code != rl->n && len < len_tab[index]) { - bits_tab[index] = bits; - len_tab[index] = len; - } - } - /* ESC2 */ - bits = rl->table_vlc[rl->n][0]; - len = rl->table_vlc[rl->n][1]; - bits = bits * 4 + 2; - len += 2; // esc2 - run1 = run - rl->max_run[last][level] - 1; - if (run1 >= 0) { - code = get_rl_index(rl, last, run1, level); - bits <<= rl->table_vlc[code][1]; - len += rl->table_vlc[code][1]; - bits += rl->table_vlc[code][0]; - bits = bits * 2 + sign; - len++; - - if (code != rl->n && len < len_tab[index]) { - bits_tab[index] = bits; - len_tab[index] = len; - } - } - /* ESC3 */ - bits = rl->table_vlc[rl->n][0]; - len = rl->table_vlc[rl->n][1]; - bits = bits * 4 + 3; - len += 2; // esc3 - bits = bits * 2 + last; - len++; - bits = bits * 64 + run; - len += 6; - bits = bits * 2 + 1; - len++; // marker - bits = bits * 4096 + (slevel & 0xfff); - len += 12; - bits = bits * 2 + 1; - len++; // marker - - if (len < len_tab[index]) { - bits_tab[index] = bits; - len_tab[index] = len; - } - } + if (level == 64) // positive levels have a range of 1..63 + break; + bits_tab[UNI_MPEG4_ENC_INDEX(0, run, level)] = code | level << 1; + bits_tab[UNI_MPEG4_ENC_INDEX(1, run, level)] = + bits_tab[UNI_MPEG4_ENC_INDEX(0, run, level)] | (1 << 20) /* last */; } + // Is this needed at all? + len_tab[UNI_MPEG4_ENC_INDEX(0, run, 0)] = + len_tab[UNI_MPEG4_ENC_INDEX(1, run, 0)] = 0; + } + + uint8_t max_run[2][32] = { 0 }; + +#define VLC_NUM_CODES 102 // excluding the escape + av_assert2(rl->n == VLC_NUM_CODES); + for (int i = VLC_NUM_CODES - 1, max_level, cur_run = 0; i >= 0; --i) { + int run = rl->table_run[i], level = rl->table_level[i]; + int last = i >= rl->last; + unsigned code = rl->table_vlc[i][0] << 1; + int len = rl->table_vlc[i][1] + 1; + + bits_tab[UNI_MPEG4_ENC_INDEX(last, run, level)] = code; + len_tab [UNI_MPEG4_ENC_INDEX(last, run, level)] = len; + bits_tab[UNI_MPEG4_ENC_INDEX(last, run, -level)] = code | 1; + len_tab [UNI_MPEG4_ENC_INDEX(last, run, -level)] = len; + + if (!max_run[last][level]) + max_run[last][level] = run + 1; + av_assert2(run + 1 <= max_run[last][level]); + + int run3 = run + max_run[last][level]; + int len3 = len + 7 + 2; + + if (run3 < 64 && len3 < len_tab[UNI_MPEG4_ENC_INDEX(last, run3, level)]) { + unsigned code3 = code | (0x3 << 2 | 0x2) << len; + bits_tab[UNI_MPEG4_ENC_INDEX(last, run3, level)] = code3; + len_tab [UNI_MPEG4_ENC_INDEX(last, run3, level)] = len3; + bits_tab[UNI_MPEG4_ENC_INDEX(last, run3, -level)] = code3 | 1; + len_tab [UNI_MPEG4_ENC_INDEX(last, run3, -level)] = len3; + } + // table_run and table_level are ordered so that all the entries + // with the same last and run are consecutive and level is ascending + // among these entries. By traversing downwards we therefore automatically + // encounter max_level of a given run first, needed for escape method 1. + if (run != cur_run) { + max_level = level; + cur_run = run; + } else + av_assert2(max_level > level); + + code |= 0x3 << (len + 1); + len += 7 + 1; + level += max_level; + av_assert2(len_tab [UNI_MPEG4_ENC_INDEX(last, run, level)] >= len); + bits_tab[UNI_MPEG4_ENC_INDEX(last, run, level)] = code; + len_tab [UNI_MPEG4_ENC_INDEX(last, run, level)] = len; + bits_tab[UNI_MPEG4_ENC_INDEX(last, run, -level)] = code | 1; + len_tab [UNI_MPEG4_ENC_INDEX(last, run, -level)] = len; } } @@ -1260,16 +1213,21 @@ static av_cold void mpeg4_encode_init_static(void) { init_uni_dc_tab(); - ff_mpeg4_init_rl_intra(); - init_uni_mpeg4_rl_tab(&ff_mpeg4_rl_intra, uni_mpeg4_intra_rl_bits, uni_mpeg4_intra_rl_len); init_uni_mpeg4_rl_tab(&ff_h263_rl_inter, uni_mpeg4_inter_rl_bits, uni_mpeg4_inter_rl_len); + + for (int f_code = MAX_FCODE; f_code > 0; f_code--) { + for (int mv = -(16 << f_code); mv < (16 << f_code); mv++) + fcode_tab[mv + MAX_MV] = f_code; + } } static av_cold int encode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; - MpegEncContext *s = avctx->priv_data; + Mpeg4EncContext *const m4 = avctx->priv_data; + MPVMainEncContext *const m = &m4->m; + MPVEncContext *const s = &m->s; int ret; if (avctx->width >= (1<<13) || avctx->height >= (1<<13)) { @@ -1277,11 +1235,10 @@ static av_cold int encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - ff_qpeldsp_init(&s->qdsp); - if ((ret = ff_mpv_encode_init(avctx)) < 0) - return ret; + m->encode_picture_header = mpeg4_encode_picture_header; + s->encode_mb = mpeg4_encode_mb; - ff_thread_once(&init_static_once, mpeg4_encode_init_static); + m->fcode_tab = fcode_tab + MAX_MV; s->min_qcoeff = -2048; s->max_qcoeff = 2047; @@ -1291,27 +1248,43 @@ static av_cold int encode_init(AVCodecContext *avctx) s->inter_ac_vlc_last_length = uni_mpeg4_inter_rl_len + 128 * 64; s->luma_dc_vlc_length = uni_DCtab_lum_len; s->ac_esc_length = 7 + 2 + 1 + 6 + 1 + 12 + 1; - s->y_dc_scale_table = ff_mpeg4_y_dc_scale_table; - s->c_dc_scale_table = ff_mpeg4_c_dc_scale_table; + s->c.y_dc_scale_table = ff_mpeg4_y_dc_scale_table; + s->c.c_dc_scale_table = ff_mpeg4_c_dc_scale_table; - if (s->avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { - s->avctx->extradata = av_malloc(1024); - if (!s->avctx->extradata) + ff_qpeldsp_init(&s->c.qdsp); + if ((ret = ff_mpv_encode_init(avctx)) < 0) + return ret; + + ff_thread_once(&init_static_once, mpeg4_encode_init_static); + + if (avctx->time_base.den > (1 << 16) - 1) { + av_log(avctx, AV_LOG_ERROR, + "timebase %d/%d not supported by MPEG 4 standard, " + "the maximum admitted value for the timebase denominator " + "is %d\n", avctx->time_base.num, avctx->time_base.den, + (1 << 16) - 1); + return AVERROR(EINVAL); + } + + m4->time_increment_bits = av_log2(avctx->time_base.den - 1) + 1; + + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { + avctx->extradata = av_malloc(1024); + if (!avctx->extradata) return AVERROR(ENOMEM); - init_put_bits(&s->pb, s->avctx->extradata, 1024); + init_put_bits(&s->pb, avctx->extradata, 1024); - if (!(s->workaround_bugs & FF_BUG_MS)) - mpeg4_encode_visual_object_header(s); - mpeg4_encode_vol_header(s, 0, 0); + mpeg4_encode_visual_object_header(m); + mpeg4_encode_vol_header(m4, 0, 0); // ff_mpeg4_stuffing(&s->pb); ? flush_put_bits(&s->pb); - s->avctx->extradata_size = put_bytes_output(&s->pb); + avctx->extradata_size = put_bytes_output(&s->pb); } return 0; } -void ff_mpeg4_init_partitions(MpegEncContext *s) +void ff_mpeg4_init_partitions(MPVEncContext *const s) { uint8_t *start = put_bits_ptr(&s->pb); uint8_t *end = s->pb.buf_end; @@ -1324,13 +1297,13 @@ void ff_mpeg4_init_partitions(MpegEncContext *s) init_put_bits(&s->pb2, start + pb_size + tex_size, pb_size); } -void ff_mpeg4_merge_partitions(MpegEncContext *s) +void ff_mpeg4_merge_partitions(MPVEncContext *const s) { const int pb2_len = put_bits_count(&s->pb2); const int tex_pb_len = put_bits_count(&s->tex_pb); const int bits = put_bits_count(&s->pb); - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { put_bits(&s->pb, 19, DC_MARKER); s->misc_bits += 19 + pb2_len + bits - s->last_bits; s->i_tex_bits += tex_pb_len; @@ -1350,23 +1323,23 @@ void ff_mpeg4_merge_partitions(MpegEncContext *s) s->last_bits = put_bits_count(&s->pb); } -void ff_mpeg4_encode_video_packet_header(MpegEncContext *s) +void ff_mpeg4_encode_video_packet_header(MPVEncContext *const s) { - int mb_num_bits = av_log2(s->mb_num - 1) + 1; + int mb_num_bits = av_log2(s->c.mb_num - 1) + 1; - put_bits(&s->pb, ff_mpeg4_get_video_packet_prefix_length(s), 0); + put_bits(&s->pb, ff_mpeg4_get_video_packet_prefix_length(s->c.pict_type, s->f_code, s->b_code), 0); put_bits(&s->pb, 1, 1); - put_bits(&s->pb, mb_num_bits, s->mb_x + s->mb_y * s->mb_width); - put_bits(&s->pb, 5 /* quant_precision */, s->qscale); + put_bits(&s->pb, mb_num_bits, s->c.mb_x + s->c.mb_y * s->c.mb_width); + put_bits(&s->pb, 5 /* quant_precision */, s->c.qscale); put_bits(&s->pb, 1, 0); /* no HEC */ } -#define OFFSET(x) offsetof(MpegEncContext, x) +#define OFFSET(x) offsetof(MPVEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "data_partitioning", "Use data partitioning.", OFFSET(data_partitioning), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "alternate_scan", "Enable alternate scantable.", OFFSET(alternate_scan), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "data_partitioning", "Use data partitioning.", FF_MPV_OFFSET(data_partitioning), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "alternate_scan", "Enable alternate scantable.", OFFSET(c.alternate_scan), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "mpeg_quant", "Use MPEG quantizers instead of H.263", OFFSET(mpeg_quant), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, VE }, FF_MPV_COMMON_BFRAME_OPTS @@ -1388,13 +1361,14 @@ const FFCodec ff_mpeg4_encoder = { CODEC_LONG_NAME("MPEG-4 part 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MPEG4, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(Mpeg4EncContext), .init = encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, - .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .p.priv_class = &mpeg4enc_class, diff --git a/libavcodec/mpeg4videoenc.h b/libavcodec/mpeg4videoenc.h index f0d5c3d07..4e20b8aaa 100644 --- a/libavcodec/mpeg4videoenc.h +++ b/libavcodec/mpeg4videoenc.h @@ -25,19 +25,28 @@ #include -#include "mpegvideo.h" #include "put_bits.h" -void ff_mpeg4_encode_mb(MpegEncContext *s, - int16_t block[6][64], - int motion_x, int motion_y); -void ff_set_mpeg4_time(MpegEncContext *s); -int ff_mpeg4_encode_picture_header(MpegEncContext *s); +enum { + MAX_PB2_INTRA_SIZE = 1 /* ac_pred */ + 5 /* max cbpy len */ + + 2 /* dquant */ + 1 /* interlaced dct */ + + 4 * (8 /* longest luma dct_dc_size */ + + 9 /* longest dc diff */ + 1 /* marker */) + + 2 * (9 + 9 + 1), + MAX_PB2_INTER_SIZE = 5 /* max cbpy len */ + + 2 /* dquant */ + 1 /* interlaced_dct */ + 1, + MAX_PB2_MB_SIZE = (FFMAX(MAX_PB2_INTER_SIZE, MAX_PB2_INTRA_SIZE) + 7) / 8, + MAX_AC_TEX_MB_SIZE = 64 * 6 * 30 /* longest escape code */ / 8, +}; -void ff_mpeg4_encode_video_packet_header(MpegEncContext *s); +typedef struct MPVEncContext MPVEncContext; + +void ff_set_mpeg4_time(MPVEncContext *s); + +void ff_mpeg4_encode_video_packet_header(MPVEncContext *s); void ff_mpeg4_stuffing(PutBitContext *pbc); -void ff_mpeg4_init_partitions(MpegEncContext *s); -void ff_mpeg4_merge_partitions(MpegEncContext *s); -void ff_clean_mpeg4_qscales(MpegEncContext *s); +void ff_mpeg4_init_partitions(MPVEncContext *s); +void ff_mpeg4_merge_partitions(MPVEncContext *s); +void ff_clean_mpeg4_qscales(MPVEncContext *s); #endif diff --git a/libavcodec/mpeg_er.c b/libavcodec/mpeg_er.c index 3cbdeeebe..5bb5ed844 100644 --- a/libavcodec/mpeg_er.c +++ b/libavcodec/mpeg_er.c @@ -28,11 +28,8 @@ static void set_erpic(ERPicture *dst, const MPVPicture *src) int i; memset(dst, 0, sizeof(*dst)); - if (!src) { - dst->f = NULL; - dst->tf = NULL; + if (!src) return; - } dst->f = src->f; dst->progress = &src->progress; @@ -54,10 +51,7 @@ void ff_mpeg_er_frame_start(MpegEncContext *s) set_erpic(&er->next_pic, s->next_pic.ptr); set_erpic(&er->last_pic, s->last_pic.ptr); - er->pp_time = s->pp_time; - er->pb_time = s->pb_time; er->quarter_sample = s->quarter_sample; - er->partitioned_frame = s->partitioned_frame; ff_er_frame_start(er); } @@ -79,7 +73,7 @@ static void mpeg_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type, s->mcsel = 0; memcpy(s->mv, mv, sizeof(*mv)); - // The following disables the IDCT. + // The following disables unquantizing and the IDCT. for (size_t i = 0; i < FF_ARRAY_ELEMS(s->block_last_index); i++) s->block_last_index[i] = -1; @@ -96,14 +90,12 @@ static void mpeg_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type, if (ref) av_log(s->avctx, AV_LOG_DEBUG, "Interlaced error concealment is not fully implemented\n"); - ff_mpv_reconstruct_mb(s, s->block); + ff_mpv_reconstruct_mb(s, NULL); } -int ff_mpeg_er_init(MpegEncContext *s) +av_cold int ff_mpeg_er_init(MpegEncContext *s) { ERContext *er = &s->er; - int mb_array_size = s->mb_height * s->mb_stride; - int i; er->avctx = s->avctx; @@ -114,23 +106,15 @@ int ff_mpeg_er_init(MpegEncContext *s) er->mb_stride = s->mb_stride; er->b8_stride = s->b8_stride; - er->er_temp_buffer = av_malloc(s->mb_height * s->mb_stride * (4*sizeof(int) + 1)); - er->error_status_table = av_mallocz(mb_array_size); - if (!er->er_temp_buffer || !er->error_status_table) - goto fail; + er->dc_val[0] = s->dc_val; + er->dc_val[1] = er->dc_val[0] + s->b8_stride * 2 * s->buffer_pools.alloc_mb_height + s->mb_stride; + er->dc_val[2] = er->dc_val[1] + s->mb_stride * (s->buffer_pools.alloc_mb_height + 1); er->mbskip_table = s->mbskip_table; er->mbintra_table = s->mbintra_table; - for (i = 0; i < FF_ARRAY_ELEMS(s->dc_val); i++) - er->dc_val[i] = s->dc_val[i]; - er->decode_mb = mpeg_er_decode_mb; er->opaque = s; - return 0; -fail: - av_freep(&er->er_temp_buffer); - av_freep(&er->error_status_table); - return AVERROR(ENOMEM); + return ff_er_init(er); } diff --git a/libavcodec/mpeg_er.h b/libavcodec/mpeg_er.h index bb627a4d0..145d1866e 100644 --- a/libavcodec/mpeg_er.h +++ b/libavcodec/mpeg_er.h @@ -24,4 +24,13 @@ int ff_mpeg_er_init(MpegEncContext *s); void ff_mpeg_er_frame_start(MpegEncContext *s); +static inline void ff_mpv_er_frame_start_ext(MPVContext *const s, int partitioned_frame, + uint16_t pp_time, uint16_t pb_time) +{ + s->er.partitioned_frame = partitioned_frame; + s->er.pp_time = pp_time; + s->er.pb_time = pb_time; + ff_mpeg_er_frame_start(s); +} + #endif /* AVCODEC_MPEG_ER_H */ diff --git a/libavcodec/mpegaudio_parser.c b/libavcodec/mpegaudio_parser.c index d54366f10..8c33d36df 100644 --- a/libavcodec/mpegaudio_parser.c +++ b/libavcodec/mpegaudio_parser.c @@ -22,6 +22,7 @@ #include "parser.h" #include "mpegaudiodecheader.h" +#include "parser_internal.h" #include "libavutil/common.h" #include "libavformat/apetag.h" // for APE tag. #include "libavformat/id3v1.h" // for ID3v1_TAG_SIZE @@ -136,9 +137,10 @@ static int mpegaudio_parse(AVCodecParserContext *s1, } -const AVCodecParser ff_mpegaudio_parser = { - .codec_ids = { AV_CODEC_ID_MP1, AV_CODEC_ID_MP2, AV_CODEC_ID_MP3, AV_CODEC_ID_MP3ADU }, +const FFCodecParser ff_mpegaudio_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_MP1, AV_CODEC_ID_MP2, + AV_CODEC_ID_MP3, AV_CODEC_ID_MP3ADU), .priv_data_size = sizeof(MpegAudioParseContext), - .parser_parse = mpegaudio_parse, - .parser_close = ff_parse_close, + .parse = mpegaudio_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/mpegaudiodec_fixed.c b/libavcodec/mpegaudiodec_fixed.c index b5b6822a1..055e3c64e 100644 --- a/libavcodec/mpegaudiodec_fixed.c +++ b/libavcodec/mpegaudiodec_fixed.c @@ -72,9 +72,7 @@ const FFCodec ff_mp1_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16), }; #endif #if CONFIG_MP2_DECODER @@ -89,9 +87,7 @@ const FFCodec ff_mp2_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16), }; #endif #if CONFIG_MP3_DECODER @@ -106,9 +102,7 @@ const FFCodec ff_mp3_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16), }; #endif #if CONFIG_MP3ADU_DECODER @@ -123,9 +117,7 @@ const FFCodec ff_mp3adu_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16), }; #endif #if CONFIG_MP3ON4_DECODER @@ -141,8 +133,7 @@ const FFCodec ff_mp3on4_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush_mp3on4, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/mpegaudiodec_float.c b/libavcodec/mpegaudiodec_float.c index ba8c49a3b..e713e9e25 100644 --- a/libavcodec/mpegaudiodec_float.c +++ b/libavcodec/mpegaudiodec_float.c @@ -85,9 +85,7 @@ const FFCodec ff_mp1float_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), }; #endif #if CONFIG_MP2FLOAT_DECODER @@ -102,9 +100,23 @@ const FFCodec ff_mp2float_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), +}; +#endif +#if CONFIG_AHX_DECODER +const FFCodec ff_ahx_decoder = { + .p.name = "ahx", + CODEC_LONG_NAME("CRI AHX"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_AHX, + .priv_data_size = sizeof(MPADecodeContext), + .init = decode_init, + FF_CODEC_DECODE_CB(decode_frame), + .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | + AV_CODEC_CAP_DR1, + .flush = flush, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), + .bsfs = "ahx_to_mp2", }; #endif #if CONFIG_MP3FLOAT_DECODER @@ -119,9 +131,7 @@ const FFCodec ff_mp3float_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), }; #endif #if CONFIG_MP3ADUFLOAT_DECODER @@ -136,9 +146,7 @@ const FFCodec ff_mp3adufloat_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), }; #endif #if CONFIG_MP3ON4FLOAT_DECODER @@ -154,8 +162,7 @@ const FFCodec ff_mp3on4float_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush_mp3on4, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/mpegaudiodec_template.c b/libavcodec/mpegaudiodec_template.c index c73b1e005..08b79312c 100644 --- a/libavcodec/mpegaudiodec_template.c +++ b/libavcodec/mpegaudiodec_template.c @@ -280,10 +280,9 @@ static av_cold void decode_init_static(void) ff_mpegaudiodec_common_init_static(); } -static av_cold int decode_init(AVCodecContext * avctx) +static av_cold int decode_ctx_init(AVCodecContext *avctx, MPADecodeContext *s) { static AVOnce init_static_once = AV_ONCE_INIT; - MPADecodeContext *s = avctx->priv_data; s->avctx = avctx; @@ -315,6 +314,11 @@ static av_cold int decode_init(AVCodecContext * avctx) return 0; } +static av_cold int decode_init(AVCodecContext *avctx) +{ + return decode_ctx_init(avctx, avctx->priv_data); +} + #define C3 FIXHR(0.86602540378443864676/2) #define C4 FIXHR(0.70710678118654752439/2) //0.5 / cos(pi*(9)/36) #define C5 FIXHR(0.51763809020504152469/2) //0.5 / cos(pi*(5)/36) @@ -381,7 +385,7 @@ static int handle_crc(MPADecodeContext *s, int sec_len) crc_val = av_crc(crc_tab, crc_val, tmp_buf, 3); if (crc_val) { - av_log(s->avctx, AV_LOG_ERROR, "CRC mismatch %X!\n", crc_val); + av_log(s->avctx, AV_LOG_ERROR, "CRC mismatch %"PRIX32"!\n", crc_val); if (s->err_recognition & AV_EF_EXPLODE) return AVERROR_INVALIDDATA; } @@ -1604,7 +1608,8 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if (ret >= 0) { s->frame->nb_samples = avctx->frame_size; *got_frame_ptr = 1; - avctx->sample_rate = s->sample_rate; + if (avctx->codec_id != AV_CODEC_ID_AHX) + avctx->sample_rate = s->sample_rate; //FIXME maybe move the other codec info stuff from above here too } else { av_log(avctx, AV_LOG_ERROR, "Error while decoding MPEG audio frame.\n"); @@ -1621,7 +1626,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, return buf_size + skipped; } -static void mp_flush(MPADecodeContext *ctx) +static av_cold void mp_flush(MPADecodeContext *ctx) { memset(ctx->synth_buf, 0, sizeof(ctx->synth_buf)); memset(ctx->mdct_buf, 0, sizeof(ctx->mdct_buf)); @@ -1629,7 +1634,7 @@ static void mp_flush(MPADecodeContext *ctx) ctx->dither_state = 0; } -static void flush(AVCodecContext *avctx) +static av_cold void flush(AVCodecContext *avctx) { mp_flush(avctx->priv_data); } @@ -1734,10 +1739,8 @@ static const int16_t chan_layout[8] = { static av_cold int decode_close_mp3on4(AVCodecContext * avctx) { MP3On4DecodeContext *s = avctx->priv_data; - int i; - for (i = 0; i < s->frames; i++) - av_freep(&s->mp3decctx[i]); + av_freep(&s->mp3decctx[0]); return 0; } @@ -1770,20 +1773,14 @@ static av_cold int decode_init_mp3on4(AVCodecContext * avctx) else s->syncword = 0xfff00000; - /* Init the first mp3 decoder in standard way, so that all tables get builded - * We replace avctx->priv_data with the context of the first decoder so that - * decode_init() does not have to be changed. + /* Init the first mp3 decoder in standard way, so that all tables get built * Other decoders will be initialized here copying data from the first context */ - // Allocate zeroed memory for the first decoder context - s->mp3decctx[0] = av_mallocz(sizeof(MPADecodeContext)); + // Allocate zeroed memory for the decoder contexts + s->mp3decctx[0] = av_calloc(s->frames, sizeof(*s->mp3decctx[0])); if (!s->mp3decctx[0]) return AVERROR(ENOMEM); - // Put decoder context in place to make init_decode() happy - avctx->priv_data = s->mp3decctx[0]; - ret = decode_init(avctx); - // Restore mp3on4 context pointer - avctx->priv_data = s; + ret = decode_ctx_init(avctx, s->mp3decctx[0]); if (ret < 0) return ret; s->mp3decctx[0]->adu_mode = 1; // Set adu mode @@ -1792,20 +1789,20 @@ static av_cold int decode_init_mp3on4(AVCodecContext * avctx) * Each frame is 1 or 2 channels - up to 5 frames allowed */ for (i = 1; i < s->frames; i++) { - s->mp3decctx[i] = av_mallocz(sizeof(MPADecodeContext)); - if (!s->mp3decctx[i]) - return AVERROR(ENOMEM); + s->mp3decctx[i] = s->mp3decctx[0] + i; s->mp3decctx[i]->adu_mode = 1; s->mp3decctx[i]->avctx = avctx; s->mp3decctx[i]->mpadsp = s->mp3decctx[0]->mpadsp; +#if USE_FLOATS s->mp3decctx[i]->butterflies_float = s->mp3decctx[0]->butterflies_float; +#endif } return 0; } -static void flush_mp3on4(AVCodecContext *avctx) +static av_cold void flush_mp3on4(AVCodecContext *avctx) { int i; MP3On4DecodeContext *s = avctx->priv_data; diff --git a/libavcodec/mpegaudioenc_template.c b/libavcodec/mpegaudioenc.c similarity index 81% rename from libavcodec/mpegaudioenc_template.c rename to libavcodec/mpegaudioenc.c index adb88cd68..9727c3819 100644 --- a/libavcodec/mpegaudioenc_template.c +++ b/libavcodec/mpegaudioenc.c @@ -24,9 +24,14 @@ * The simplest mpeg audio layer 2 encoder. */ +#include "config.h" +#include "config_components.h" + +#include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "avcodec.h" +#include "codec_internal.h" #include "encode.h" #include "put_bits.h" @@ -45,12 +50,12 @@ #define SAMPLES_BUF_SIZE 4096 typedef struct MpegAudioContext { - PutBitContext pb; int nb_channels; int lsf; /* 1 if mpeg2 low bitrate selected */ int bitrate_index; /* bit rate */ int freq_index; int frame_size; /* frame size, in bits, without padding */ + int is_fixed; /* padding computation */ int frame_frac, frame_frac_incr, do_padding; short samples_buf[MPA_MAX_CHANNELS][SAMPLES_BUF_SIZE]; /* buffer for filter */ @@ -64,16 +69,19 @@ typedef struct MpegAudioContext { int16_t filter_bank[512]; int scale_factor_table[64]; unsigned char scale_diff_table[128]; -#if USE_FLOATS - float scale_factor_inv_table[64]; -#else - int8_t scale_factor_shift[64]; - unsigned short scale_factor_mult[64]; -#endif + union { + float scale_factor_inv_table[64]; + struct { + int8_t scale_factor_shift[64]; + unsigned short scale_factor_mult[64]; + }; + }; unsigned short total_quant_bits[17]; /* total number of bits per allocation group */ } MpegAudioContext; -static av_cold int MPA_encode_init(AVCodecContext *avctx) +#define IS_FIXED(s) (CONFIG_MP2_ENCODER && CONFIG_MP2FIXED_ENCODER ? (s)->is_fixed : CONFIG_MP2FIXED_ENCODER) + +static av_cold int mpa_encode_init(AVCodecContext *avctx) { MpegAudioContext *s = avctx->priv_data; int freq = avctx->sample_rate; @@ -89,7 +97,8 @@ static av_cold int MPA_encode_init(AVCodecContext *avctx) /* encoding freq */ s->lsf = 0; - for(i=0;i<3;i++) { + for (i = 0;; i++) { + av_assert1(i < 3); if (ff_mpa_freq_tab[i] == freq) break; if ((ff_mpa_freq_tab[i] / 2) == freq) { @@ -97,10 +106,6 @@ static av_cold int MPA_encode_init(AVCodecContext *avctx) break; } } - if (i == 3){ - av_log(avctx, AV_LOG_ERROR, "Sampling rate %d is not allowed in mp2\n", freq); - return AVERROR(EINVAL); - } s->freq_index = i; /* encoding bitrate & frequency */ @@ -159,13 +164,13 @@ static av_cold int MPA_encode_init(AVCodecContext *avctx) if (v <= 0) v = 1; s->scale_factor_table[i] = v; -#if USE_FLOATS - s->scale_factor_inv_table[i] = exp2(-(3 - i) / 3.0) / (float)(1 << 20); -#else + if (IS_FIXED(s)) { #define P 15 - s->scale_factor_shift[i] = 21 - P - (i / 3); - s->scale_factor_mult[i] = (1 << P) * exp2((i % 3) / 3.0); -#endif + s->scale_factor_shift[i] = 21 - P - (i / 3); + s->scale_factor_mult[i] = (1 << P) * exp2((i % 3) / 3.0); + } else { + s->scale_factor_inv_table[i] = exp2(-(3 - i) / 3.0) / (float)(1 << 20); + } } for(i=0;i<128;i++) { v = i - 64; @@ -502,7 +507,7 @@ static void psycho_acoustic_model(MpegAudioContext *s, short smr[SBLIMIT]) /* Try to maximize the smr while using a number of bits inferior to the frame size. I tried to make the code simpler, faster and smaller than other encoders :-) */ -static void compute_bit_allocation(MpegAudioContext *s, +static unsigned compute_bit_allocation(MpegAudioContext *s, short smr1[MPA_MAX_CHANNELS][SBLIMIT], unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT], int *padding) @@ -592,20 +597,86 @@ static void compute_bit_allocation(MpegAudioContext *s, } *padding = max_frame_size - current_frame_size; av_assert0(*padding >= 0); + return max_frame_size / 8U; +} + +/// Quantization & write sub band samples +static av_always_inline void encode_subbands(MpegAudioContext *const s, + PutBitContext *const p, + const uint8_t bit_alloc[MPA_MAX_CHANNELS][SBLIMIT], + int is_fixed) +{ + for (int k = 0; k < 3; ++k) { + for (int l = 0; l < 12; l += 3) { + for (int i = 0, j = 0; i < s->sblimit; ++i) { + const int bit_alloc_bits = s->alloc_table[j]; + for (int ch = 0; ch < s->nb_channels; ++ch) { + const int b = bit_alloc[ch][i]; + if (b) { + /* we encode 3 sub band samples of the same sub band at a time */ + const int qindex = s->alloc_table[j + b]; + const int steps = ff_mpa_quant_steps[qindex]; + int q[3]; + + for (int m = 0; m < 3; ++m) { + const int sample = s->sb_samples[ch][k][l + m][i]; + /* divide by scale factor */ + if (!is_fixed) { + float a = (float)sample * s->scale_factor_inv_table[s->scale_factors[ch][i][k]]; + q[m] = (int)((a + 1.0) * steps * 0.5); + } else { + const int e = s->scale_factors[ch][i][k]; + const int shift = s->scale_factor_shift[e]; + const int mult = s->scale_factor_mult[e]; + int q1; + + /* normalize to P bits */ + if (shift < 0) + q1 = sample * (1 << -shift); + else + q1 = sample >> shift; + q1 = (q1 * mult) >> P; + q1 += 1 << P; + if (q1 < 0) + q1 = 0; + q[m] = (q1 * (unsigned)steps) >> (P + 1); + } + if (q[m] >= steps) + q[m] = steps - 1; + av_assert2(q[m] >= 0 && q[m] < steps); + } + const int bits = ff_mpa_quant_bits[qindex]; + if (bits < 0) { + /* group the 3 values to save bits */ + put_bits(p, -bits, + q[0] + steps * (q[1] + steps * q[2])); + } else { + put_bits(p, bits, q[0]); + put_bits(p, bits, q[1]); + put_bits(p, bits, q[2]); + } + } + } + /* next subband in alloc table */ + j += 1 << bit_alloc_bits; + } + } + } } /* * Output the MPEG audio layer 2 frame. Note how the code is small * compared to other encoders :-) */ -static void encode_frame(MpegAudioContext *s, +static void encode_frame(MpegAudioContext *s, uint8_t *buf, unsigned buf_size, unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT], int padding) { - int i, j, k, l, bit_alloc_bits, b, ch; + int i, j, bit_alloc_bits, ch; unsigned char *sf; - int q[3]; - PutBitContext *p = &s->pb; + PutBitContext p0, *p = &p0; + + init_put_bits(p, buf, buf_size); /* header */ @@ -648,14 +719,11 @@ static void encode_frame(MpegAudioContext *s, sf = &s->scale_factors[ch][i][0]; switch(s->scale_code[ch][i]) { case 0: - put_bits(p, 6, sf[0]); - put_bits(p, 6, sf[1]); - put_bits(p, 6, sf[2]); + put_bits(p, 18, sf[0] << 12 | sf[1] << 6 | sf[2]); break; case 3: case 1: - put_bits(p, 6, sf[0]); - put_bits(p, 6, sf[2]); + put_bits(p, 12, sf[0] << 6 | sf[2]); break; case 2: put_bits(p, 6, sf[0]); @@ -665,76 +733,26 @@ static void encode_frame(MpegAudioContext *s, } } - /* quantization & write sub band samples */ - - for(k=0;k<3;k++) { - for(l=0;l<12;l+=3) { - j = 0; - for(i=0;isblimit;i++) { - bit_alloc_bits = s->alloc_table[j]; - for(ch=0;chnb_channels;ch++) { - b = bit_alloc[ch][i]; - if (b) { - int qindex, steps, m, sample, bits; - /* we encode 3 sub band samples of the same sub band at a time */ - qindex = s->alloc_table[j+b]; - steps = ff_mpa_quant_steps[qindex]; - for(m=0;m<3;m++) { - sample = s->sb_samples[ch][k][l + m][i]; - /* divide by scale factor */ -#if USE_FLOATS - { - float a; - a = (float)sample * s->scale_factor_inv_table[s->scale_factors[ch][i][k]]; - q[m] = (int)((a + 1.0) * steps * 0.5); - } +#if CONFIG_SMALL + encode_subbands(s, p, bit_alloc, IS_FIXED(s)); #else - { - int q1, e, shift, mult; - e = s->scale_factors[ch][i][k]; - shift = s->scale_factor_shift[e]; - mult = s->scale_factor_mult[e]; - - /* normalize to P bits */ - if (shift < 0) - q1 = sample * (1 << -shift); - else - q1 = sample >> shift; - q1 = (q1 * mult) >> P; - q1 += 1 << P; - if (q1 < 0) - q1 = 0; - q[m] = (q1 * (unsigned)steps) >> (P + 1); - } + if (IS_FIXED(s)) + encode_subbands(s, p, bit_alloc, 1); + else + encode_subbands(s, p, bit_alloc, 0); #endif - if (q[m] >= steps) - q[m] = steps - 1; - av_assert2(q[m] >= 0 && q[m] < steps); - } - bits = ff_mpa_quant_bits[qindex]; - if (bits < 0) { - /* group the 3 values to save bits */ - put_bits(p, -bits, - q[0] + steps * (q[1] + steps * q[2])); - } else { - put_bits(p, bits, q[0]); - put_bits(p, bits, q[1]); - put_bits(p, bits, q[2]); - } - } - } - /* next subband in alloc table */ - j += 1 << bit_alloc_bits; - } - } - } + + av_assert1(put_bits_left(p) == padding); + + /* flush */ + flush_put_bits(p); /* padding */ - for(i=0;ipriv_data; @@ -754,18 +772,13 @@ static int MPA_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, for(i=0;inb_channels;i++) { psycho_acoustic_model(s, smr[i]); } - compute_bit_allocation(s, smr, bit_alloc, &padding); + unsigned frame_size = compute_bit_allocation(s, smr, bit_alloc, &padding); - if ((ret = ff_alloc_packet(avctx, avpkt, MPA_MAX_CODED_FRAME_SIZE)) < 0) + ret = ff_get_encode_buffer(avctx, avpkt, frame_size, 0); + if (ret < 0) return ret; - init_put_bits(&s->pb, avpkt->data, avpkt->size); - - encode_frame(s, bit_alloc, padding); - - /* flush */ - flush_put_bits(&s->pb); - avpkt->size = put_bytes_output(&s->pb); + encode_frame(s, avpkt->data, frame_size, bit_alloc, padding); if (frame->pts != AV_NOPTS_VALUE) avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding); @@ -778,3 +791,45 @@ static const FFCodecDefault mp2_defaults[] = { { "b", "0" }, { NULL }, }; + +#if CONFIG_MP2_ENCODER +const FFCodec ff_mp2_encoder = { + .p.name = "mp2", + CODEC_LONG_NAME("MP2 (MPEG audio layer 2)"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_MP2, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .priv_data_size = sizeof(MpegAudioContext), + .init = mpa_encode_init, + FF_CODEC_ENCODE_CB(mpa_encode_frame), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_SAMPLERATES(44100, 48000, 32000, 22050, 24000, 16000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + .defaults = mp2_defaults, +}; +#endif + +#if CONFIG_MP2FIXED_ENCODER +static av_cold int mpa_fixed_encode_init(AVCodecContext *avctx) +{ + MpegAudioContext *s = avctx->priv_data; + + s->is_fixed = 1; + return mpa_encode_init(avctx); +} + +const FFCodec ff_mp2fixed_encoder = { + .p.name = "mp2fixed", + CODEC_LONG_NAME("MP2 fixed point (MPEG audio layer 2)"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_MP2, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .priv_data_size = sizeof(MpegAudioContext), + .init = mpa_fixed_encode_init, + FF_CODEC_ENCODE_CB(mpa_encode_frame), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_SAMPLERATES(44100, 48000, 32000, 22050, 24000, 16000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + .defaults = mp2_defaults, +}; +#endif diff --git a/libavcodec/mpegaudioenc_fixed.c b/libavcodec/mpegaudioenc_fixed.c deleted file mode 100644 index cdfc0b995..000000000 --- a/libavcodec/mpegaudioenc_fixed.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * The simplest mpeg audio layer 2 encoder - * Copyright (c) 2000, 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 - */ - -#include "libavutil/channel_layout.h" -#include "codec_internal.h" -#include "mpegaudioenc_template.c" - -const FFCodec ff_mp2fixed_encoder = { - .p.name = "mp2fixed", - CODEC_LONG_NAME("MP2 fixed point (MPEG audio layer 2)"), - .p.type = AVMEDIA_TYPE_AUDIO, - .p.id = AV_CODEC_ID_MP2, - .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .priv_data_size = sizeof(MpegAudioContext), - .init = MPA_encode_init, - FF_CODEC_ENCODE_CB(MPA_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]){ - 44100, 48000, 32000, 22050, 24000, 16000, 0 - }, - .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 } }, - .defaults = mp2_defaults, -}; diff --git a/libavcodec/mpegaudioenc_float.c b/libavcodec/mpegaudioenc_float.c deleted file mode 100644 index f94ab54e8..000000000 --- a/libavcodec/mpegaudioenc_float.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * The simplest mpeg audio layer 2 encoder - * Copyright (c) 2000, 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 - */ - -#include "libavutil/channel_layout.h" -#define USE_FLOATS 1 -#include "codec_internal.h" -#include "mpegaudioenc_template.c" - -const FFCodec ff_mp2_encoder = { - .p.name = "mp2", - CODEC_LONG_NAME("MP2 (MPEG audio layer 2)"), - .p.type = AVMEDIA_TYPE_AUDIO, - .p.id = AV_CODEC_ID_MP2, - .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .priv_data_size = sizeof(MpegAudioContext), - .init = MPA_encode_init, - FF_CODEC_ENCODE_CB(MPA_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]){ - 44100, 48000, 32000, 22050, 24000, 16000, 0 - }, - .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 } }, - .defaults = mp2_defaults, -}; diff --git a/libavcodec/mpegpicture.c b/libavcodec/mpegpicture.c index cde060aa1..3f32fe877 100644 --- a/libavcodec/mpegpicture.c +++ b/libavcodec/mpegpicture.c @@ -26,24 +26,24 @@ #include "avcodec.h" #include "mpegpicture.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" -static void mpv_pic_reset(FFRefStructOpaque unused, void *obj) +static void mpv_pic_reset(AVRefStructOpaque unused, void *obj) { MPVPicture *pic = obj; av_frame_unref(pic->f); ff_thread_progress_reset(&pic->progress); - ff_refstruct_unref(&pic->hwaccel_picture_private); + av_refstruct_unref(&pic->hwaccel_picture_private); - ff_refstruct_unref(&pic->mbskip_table); - ff_refstruct_unref(&pic->qscale_table_base); - ff_refstruct_unref(&pic->mb_type_base); + av_refstruct_unref(&pic->mbskip_table); + av_refstruct_unref(&pic->qscale_table_base); + av_refstruct_unref(&pic->mb_type_base); for (int i = 0; i < 2; i++) { - ff_refstruct_unref(&pic->motion_val_base[i]); - ff_refstruct_unref(&pic->ref_index[i]); + av_refstruct_unref(&pic->motion_val_base[i]); + av_refstruct_unref(&pic->ref_index[i]); pic->motion_val[i] = NULL; } @@ -64,7 +64,7 @@ static void mpv_pic_reset(FFRefStructOpaque unused, void *obj) pic->coded_picture_number = 0; } -static int av_cold mpv_pic_init(FFRefStructOpaque opaque, void *obj) +static int av_cold mpv_pic_init(AVRefStructOpaque opaque, void *obj) { MPVPicture *pic = obj; int ret, init_progress = (uintptr_t)opaque.nc; @@ -79,7 +79,7 @@ static int av_cold mpv_pic_init(FFRefStructOpaque opaque, void *obj) return 0; } -static void av_cold mpv_pic_free(FFRefStructOpaque unused, void *obj) +static void av_cold mpv_pic_free(AVRefStructOpaque unused, void *obj) { MPVPicture *pic = obj; @@ -87,17 +87,17 @@ static void av_cold mpv_pic_free(FFRefStructOpaque unused, void *obj) av_frame_free(&pic->f); } -av_cold FFRefStructPool *ff_mpv_alloc_pic_pool(int init_progress) +av_cold AVRefStructPool *ff_mpv_alloc_pic_pool(int init_progress) { - return ff_refstruct_pool_alloc_ext(sizeof(MPVPicture), - FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, + return av_refstruct_pool_alloc_ext(sizeof(MPVPicture), + AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, (void*)(uintptr_t)init_progress, mpv_pic_init, mpv_pic_reset, mpv_pic_free, NULL); } void ff_mpv_unref_picture(MPVWorkPicture *pic) { - ff_refstruct_unref(&pic->ptr); + av_refstruct_unref(&pic->ptr); memset(pic, 0, sizeof(*pic)); } @@ -121,13 +121,13 @@ static void set_workpic_from_pic(MPVWorkPicture *wpic, const MPVPicture *pic) void ff_mpv_replace_picture(MPVWorkPicture *dst, const MPVWorkPicture *src) { av_assert1(dst != src); - ff_refstruct_replace(&dst->ptr, src->ptr); + av_refstruct_replace(&dst->ptr, src->ptr); memcpy(dst, src, sizeof(*dst)); } void ff_mpv_workpic_from_pic(MPVWorkPicture *wpic, MPVPicture *pic) { - ff_refstruct_replace(&wpic->ptr, pic); + av_refstruct_replace(&wpic->ptr, pic); if (!pic) { memset(wpic, 0, sizeof(*wpic)); return; @@ -186,7 +186,7 @@ int ff_mpv_pic_check_linesize(void *logctx, const AVFrame *f, if ((linesize && linesize != f->linesize[0]) || (uvlinesize && uvlinesize != f->linesize[1])) { av_log(logctx, AV_LOG_ERROR, "Stride change unsupported: " - "linesize=%"PTRDIFF_SPECIFIER"/%d uvlinesize=%"PTRDIFF_SPECIFIER"/%d)\n", + "linesize=%td/%d uvlinesize=%td/%d)\n", linesize, f->linesize[0], uvlinesize, f->linesize[1]); return AVERROR_PATCHWELCOME; @@ -207,7 +207,7 @@ static int alloc_picture_tables(BufferPoolContext *pools, MPVPicture *pic, int mb_height) { #define GET_BUFFER(name, buf_suffix, idx_suffix) do { \ - pic->name ## buf_suffix idx_suffix = ff_refstruct_pool_get(pools->name ## _pool); \ + pic->name ## buf_suffix idx_suffix = av_refstruct_pool_get(pools->name ## _pool); \ if (!pic->name ## buf_suffix idx_suffix) \ return AVERROR(ENOMEM); \ } while (0) diff --git a/libavcodec/mpegpicture.h b/libavcodec/mpegpicture.h index 196aa9b74..d24093656 100644 --- a/libavcodec/mpegpicture.h +++ b/libavcodec/mpegpicture.h @@ -42,11 +42,11 @@ typedef struct ScratchpadContext { } ScratchpadContext; typedef struct BufferPoolContext { - struct FFRefStructPool *mbskip_table_pool; - struct FFRefStructPool *qscale_table_pool; - struct FFRefStructPool *mb_type_pool; - struct FFRefStructPool *motion_val_pool; - struct FFRefStructPool *ref_index_pool; + struct AVRefStructPool *mbskip_table_pool; + struct AVRefStructPool *qscale_table_pool; + struct AVRefStructPool *mb_type_pool; + struct AVRefStructPool *motion_val_pool; + struct AVRefStructPool *ref_index_pool; int alloc_mb_width; ///< mb_width used to allocate tables int alloc_mb_height; ///< mb_height used to allocate tables int alloc_mb_stride; ///< mb_stride used to allocate tables @@ -114,7 +114,7 @@ typedef struct MPVWorkPicture { /** * Allocate a pool of MPVPictures. */ -struct FFRefStructPool *ff_mpv_alloc_pic_pool(int init_progress); +struct AVRefStructPool *ff_mpv_alloc_pic_pool(int init_progress); /** * Allocate an MPVPicture's accessories (but not the AVFrame's buffer itself) diff --git a/libavcodec/mpegutils.h b/libavcodec/mpegutils.h index e4ce26d29..9967762a7 100644 --- a/libavcodec/mpegutils.h +++ b/libavcodec/mpegutils.h @@ -33,7 +33,6 @@ #define PICT_FRAME 3 #define MAX_MB_BYTES (30 * 16 * 16 * 3 / 8 + 120) -#define MAX_FCODE 7 /* MB types */ #define MB_TYPE_INTRA4x4 (1 << 0) diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 01e310e48..09e5a9623 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -31,6 +31,7 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/internal.h" +#include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "avcodec.h" @@ -41,220 +42,7 @@ #include "mpegutils.h" #include "mpegvideo.h" #include "mpegvideodata.h" -#include "refstruct.h" - -static void dct_unquantize_mpeg1_intra_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, nCoeffs; - const uint16_t *quant_matrix; - - nCoeffs= s->block_last_index[n]; - - block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; - /* XXX: only MPEG-1 */ - quant_matrix = s->intra_matrix; - for(i=1;i<=nCoeffs;i++) { - int j= s->intra_scantable.permutated[i]; - level = block[j]; - if (level) { - if (level < 0) { - level = -level; - level = (int)(level * qscale * quant_matrix[j]) >> 3; - level = (level - 1) | 1; - level = -level; - } else { - level = (int)(level * qscale * quant_matrix[j]) >> 3; - level = (level - 1) | 1; - } - block[j] = level; - } - } -} - -static void dct_unquantize_mpeg1_inter_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, nCoeffs; - const uint16_t *quant_matrix; - - nCoeffs= s->block_last_index[n]; - - quant_matrix = s->inter_matrix; - for(i=0; i<=nCoeffs; i++) { - int j= s->intra_scantable.permutated[i]; - level = block[j]; - if (level) { - if (level < 0) { - level = -level; - level = (((level << 1) + 1) * qscale * - ((int) (quant_matrix[j]))) >> 4; - level = (level - 1) | 1; - level = -level; - } else { - level = (((level << 1) + 1) * qscale * - ((int) (quant_matrix[j]))) >> 4; - level = (level - 1) | 1; - } - block[j] = level; - } - } -} - -static void dct_unquantize_mpeg2_intra_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, nCoeffs; - const uint16_t *quant_matrix; - - if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; - else qscale <<= 1; - - nCoeffs= s->block_last_index[n]; - - block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; - quant_matrix = s->intra_matrix; - for(i=1;i<=nCoeffs;i++) { - int j= s->intra_scantable.permutated[i]; - level = block[j]; - if (level) { - if (level < 0) { - level = -level; - level = (int)(level * qscale * quant_matrix[j]) >> 4; - level = -level; - } else { - level = (int)(level * qscale * quant_matrix[j]) >> 4; - } - block[j] = level; - } - } -} - -static void dct_unquantize_mpeg2_intra_bitexact(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, nCoeffs; - const uint16_t *quant_matrix; - int sum=-1; - - if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; - else qscale <<= 1; - - nCoeffs= s->block_last_index[n]; - - block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; - sum += block[0]; - quant_matrix = s->intra_matrix; - for(i=1;i<=nCoeffs;i++) { - int j= s->intra_scantable.permutated[i]; - level = block[j]; - if (level) { - if (level < 0) { - level = -level; - level = (int)(level * qscale * quant_matrix[j]) >> 4; - level = -level; - } else { - level = (int)(level * qscale * quant_matrix[j]) >> 4; - } - block[j] = level; - sum+=level; - } - } - block[63]^=sum&1; -} - -static void dct_unquantize_mpeg2_inter_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, nCoeffs; - const uint16_t *quant_matrix; - int sum=-1; - - if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; - else qscale <<= 1; - - nCoeffs= s->block_last_index[n]; - - quant_matrix = s->inter_matrix; - for(i=0; i<=nCoeffs; i++) { - int j= s->intra_scantable.permutated[i]; - level = block[j]; - if (level) { - if (level < 0) { - level = -level; - level = (((level << 1) + 1) * qscale * - ((int) (quant_matrix[j]))) >> 5; - level = -level; - } else { - level = (((level << 1) + 1) * qscale * - ((int) (quant_matrix[j]))) >> 5; - } - block[j] = level; - sum+=level; - } - } - block[63]^=sum&1; -} - -static void dct_unquantize_h263_intra_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, qmul, qadd; - int nCoeffs; - - av_assert2(s->block_last_index[n]>=0 || s->h263_aic); - - qmul = qscale << 1; - - if (!s->h263_aic) { - block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; - qadd = (qscale - 1) | 1; - }else{ - qadd = 0; - } - if(s->ac_pred) - nCoeffs=63; - else - nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; - - for(i=1; i<=nCoeffs; i++) { - level = block[i]; - if (level) { - if (level < 0) { - level = level * qmul - qadd; - } else { - level = level * qmul + qadd; - } - block[i] = level; - } - } -} - -static void dct_unquantize_h263_inter_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, qmul, qadd; - int nCoeffs; - - av_assert2(s->block_last_index[n]>=0); - - qadd = (qscale - 1) | 1; - qmul = qscale << 1; - - nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ]; - - for(i=0; i<=nCoeffs; i++) { - level = block[i]; - if (level) { - if (level < 0) { - level = level * qmul - qadd; - } else { - level = level * qmul + qadd; - } - block[i] = level; - } - } -} +#include "libavutil/refstruct.h" static void gray16(uint8_t *dst, const uint8_t *src, ptrdiff_t linesize, int h) @@ -290,20 +78,6 @@ static av_cold void dsp_init(MpegEncContext *s) } } -av_cold void ff_init_scantable(const uint8_t *permutation, ScanTable *st, - const uint8_t *src_scantable) -{ - st->scantable = src_scantable; - - for (int i = 0, end = -1; i < 64; i++) { - int j = src_scantable[i]; - st->permutated[i] = permutation[j]; - if (permutation[j] > end) - end = permutation[j]; - st->raster_end[i] = end; - } -} - av_cold void ff_mpv_idct_init(MpegEncContext *s) { if (s->codec_id == AV_CODEC_ID_MPEG4) @@ -320,82 +94,17 @@ av_cold void ff_mpv_idct_init(MpegEncContext *s) ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, ff_zigzag_direct); ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_zigzag_direct); } - ff_permute_scantable(s->permutated_intra_h_scantable, ff_alternate_horizontal_scan, - s->idsp.idct_permutation); - ff_permute_scantable(s->permutated_intra_v_scantable, ff_alternate_vertical_scan, - s->idsp.idct_permutation); - - s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_c; - s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_c; - s->dct_unquantize_mpeg1_intra = dct_unquantize_mpeg1_intra_c; - s->dct_unquantize_mpeg1_inter = dct_unquantize_mpeg1_inter_c; - s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_c; - if (s->avctx->flags & AV_CODEC_FLAG_BITEXACT) - s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_bitexact; - s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_c; - -#if HAVE_INTRINSICS_NEON - ff_mpv_common_init_neon(s); -#endif - -#if ARCH_ARM - ff_mpv_common_init_arm(s); -#elif ARCH_PPC - ff_mpv_common_init_ppc(s); -#elif ARCH_X86 - ff_mpv_common_init_x86(s); -#elif ARCH_MIPS - ff_mpv_common_init_mips(s); -#endif } -static int init_duplicate_context(MpegEncContext *s) +av_cold int ff_mpv_init_duplicate_contexts(MpegEncContext *s) { - if (s->encoding) { - s->me.map = av_mallocz(2 * ME_MAP_SIZE * sizeof(*s->me.map)); - if (!s->me.map) - return AVERROR(ENOMEM); - s->me.score_map = s->me.map + ME_MAP_SIZE; + const int nb_slices = s->slice_context_count; + const size_t slice_size = s->slice_ctx_size; - if (s->noise_reduction) { - if (!FF_ALLOCZ_TYPED_ARRAY(s->dct_error_sum, 2)) - return AVERROR(ENOMEM); - } - } - if (!FF_ALLOCZ_TYPED_ARRAY(s->blocks, 1 + s->encoding)) - return AVERROR(ENOMEM); - s->block = s->blocks[0]; - - if (s->out_format == FMT_H263) { - int mb_height = s->msmpeg4_version == MSMP4_VC1 ? - FFALIGN(s->mb_height, 2) : s->mb_height; - int y_size = s->b8_stride * (2 * mb_height + 1); - int c_size = s->mb_stride * (mb_height + 1); - int yc_size = y_size + 2 * c_size; - /* ac values */ - if (!FF_ALLOCZ_TYPED_ARRAY(s->ac_val_base, yc_size)) - return AVERROR(ENOMEM); - s->ac_val[0] = s->ac_val_base + s->b8_stride + 1; - s->ac_val[1] = s->ac_val_base + y_size + s->mb_stride + 1; - s->ac_val[2] = s->ac_val[1] + c_size; - } - - return 0; -} - -int ff_mpv_init_duplicate_contexts(MpegEncContext *s) -{ - int nb_slices = s->slice_context_count, ret; - - /* We initialize the copies before the original so that - * fields allocated in init_duplicate_context are NULL after - * copying. This prevents double-frees upon allocation error. */ for (int i = 1; i < nb_slices; i++) { - s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext)); + s->thread_context[i] = av_memdup(s, slice_size); if (!s->thread_context[i]) return AVERROR(ENOMEM); - if ((ret = init_duplicate_context(s->thread_context[i])) < 0) - return ret; s->thread_context[i]->start_mb_y = (s->mb_height * (i ) + nb_slices / 2) / nb_slices; s->thread_context[i]->end_mb_y = @@ -404,29 +113,21 @@ int ff_mpv_init_duplicate_contexts(MpegEncContext *s) s->start_mb_y = 0; s->end_mb_y = nb_slices > 1 ? (s->mb_height + nb_slices / 2) / nb_slices : s->mb_height; - return init_duplicate_context(s); + return 0; } -static void free_duplicate_context(MpegEncContext *s) +static av_cold void free_duplicate_context(MpegEncContext *s) { if (!s) return; av_freep(&s->sc.edge_emu_buffer); av_freep(&s->sc.scratchpad_buf); - s->me.temp = s->me.scratchpad = s->sc.obmc_scratchpad = NULL; s->sc.linesize = 0; - - av_freep(&s->dct_error_sum); - av_freep(&s->me.map); - s->me.score_map = NULL; - av_freep(&s->blocks); - av_freep(&s->ac_val_base); - s->block = NULL; } -static void free_duplicate_contexts(MpegEncContext *s) +static av_cold void free_duplicate_contexts(MpegEncContext *s) { for (int i = 1; i < s->slice_context_count; i++) { free_duplicate_context(s->thread_context[i]); @@ -435,35 +136,22 @@ static void free_duplicate_contexts(MpegEncContext *s) free_duplicate_context(s); } -static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src) -{ -#define COPY(a) bak->a = src->a - COPY(sc); - COPY(me.map); - COPY(me.score_map); - COPY(blocks); - COPY(block); - COPY(start_mb_y); - COPY(end_mb_y); - COPY(me.map_generation); - COPY(dct_error_sum); - COPY(dct_count[0]); - COPY(dct_count[1]); - COPY(ac_val_base); - COPY(ac_val[0]); - COPY(ac_val[1]); - COPY(ac_val[2]); -#undef COPY -} - int ff_update_duplicate_context(MpegEncContext *dst, const MpegEncContext *src) { - MpegEncContext bak; +#define COPY(M) \ + M(ScratchpadContext, sc) \ + M(int, start_mb_y) \ + M(int, end_mb_y) \ + M(int16_t*, dc_val) \ + M(void*, ac_val) + int ret; // FIXME copy only needed parts - backup_duplicate_context(&bak, dst); +#define BACKUP(T, member) T member = dst->member; + COPY(BACKUP) memcpy(dst, src, sizeof(MpegEncContext)); - backup_duplicate_context(dst, &bak); +#define RESTORE(T, member) dst->member = member; + COPY(RESTORE) ret = ff_mpv_framesize_alloc(dst->avctx, &dst->sc, dst->linesize); if (ret < 0) { @@ -480,44 +168,56 @@ int ff_update_duplicate_context(MpegEncContext *dst, const MpegEncContext *src) * The changed fields will not depend upon the * prior state of the MpegEncContext. */ -void ff_mpv_common_defaults(MpegEncContext *s) +av_cold void ff_mpv_common_defaults(MpegEncContext *s) { - s->y_dc_scale_table = - s->c_dc_scale_table = ff_mpeg1_dc_scale_table; s->chroma_qscale_table = ff_default_chroma_qscale_table; s->progressive_frame = 1; s->progressive_sequence = 1; s->picture_structure = PICT_FRAME; - s->picture_number = 0; - - s->f_code = 1; - s->b_code = 1; - s->slice_context_count = 1; } -static void free_buffer_pools(BufferPoolContext *pools) +static av_cold void free_buffer_pools(BufferPoolContext *pools) { - ff_refstruct_pool_uninit(&pools->mbskip_table_pool); - ff_refstruct_pool_uninit(&pools->qscale_table_pool); - ff_refstruct_pool_uninit(&pools->mb_type_pool); - ff_refstruct_pool_uninit(&pools->motion_val_pool); - ff_refstruct_pool_uninit(&pools->ref_index_pool); + av_refstruct_pool_uninit(&pools->mbskip_table_pool); + av_refstruct_pool_uninit(&pools->qscale_table_pool); + av_refstruct_pool_uninit(&pools->mb_type_pool); + av_refstruct_pool_uninit(&pools->motion_val_pool); + av_refstruct_pool_uninit(&pools->ref_index_pool); pools->alloc_mb_height = pools->alloc_mb_width = pools->alloc_mb_stride = 0; } -int ff_mpv_init_context_frame(MpegEncContext *s) +av_cold int ff_mpv_init_context_frame(MpegEncContext *s) { + int nb_slices = (HAVE_THREADS && + s->avctx->active_thread_type & FF_THREAD_SLICE) ? + s->avctx->thread_count : 1; BufferPoolContext *const pools = &s->buffer_pools; - int y_size, c_size, yc_size, i, mb_array_size, mv_table_size, x, y; + int y_size, c_size, yc_size, mb_array_size, mv_table_size, x, y; int mb_height; + if (s->encoding && s->avctx->slices) + nb_slices = s->avctx->slices; + if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO && !s->progressive_sequence) s->mb_height = (s->height + 31) / 32 * 2; else s->mb_height = (s->height + 15) / 16; + if (nb_slices > MAX_THREADS || (nb_slices > s->mb_height && s->mb_height)) { + int max_slices; + if (s->mb_height) + max_slices = FFMIN(MAX_THREADS, s->mb_height); + else + max_slices = MAX_THREADS; + av_log(s->avctx, AV_LOG_WARNING, "too many threads/slices (%d)," + " reducing to %d\n", nb_slices, max_slices); + nb_slices = max_slices; + } + + s->slice_context_count = nb_slices; + /* VC-1 can change from being progressive to interlaced on a per-frame * basis. We therefore allocate certain buffers so big that they work * in both instances. */ @@ -557,7 +257,7 @@ int ff_mpv_init_context_frame(MpegEncContext *s) s->mb_index2xy[s->mb_height * s->mb_width] = (s->mb_height - 1) * s->mb_stride + s->mb_width; // FIXME really needed? #define ALLOC_POOL(name, size, flags) do { \ - pools->name ##_pool = ff_refstruct_pool_alloc((size), (flags)); \ + pools->name ##_pool = av_refstruct_pool_alloc((size), (flags)); \ if (!pools->name ##_pool) \ return AVERROR(ENOMEM); \ } while (0) @@ -578,7 +278,7 @@ int ff_mpv_init_context_frame(MpegEncContext *s) } if (s->codec_id == AV_CODEC_ID_MPEG4) { ALLOC_POOL(mbskip_table, mb_array_size + 2, - !s->encoding ? FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME : 0); + !s->encoding ? AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME : 0); if (!s->encoding) { /* cbp, pred_dir */ if (!(s->cbp_table = av_mallocz(mb_array_size)) || @@ -595,24 +295,39 @@ int ff_mpv_init_context_frame(MpegEncContext *s) s->coded_block = s->coded_block_base + s->b8_stride + 1; } - if (s->h263_pred || s->h263_plus || !s->encoding) { + if (s->h263_pred || s->h263_aic || !s->encoding) { + // When encoding, each slice (and therefore each thread) + // gets its own ac_val and dc_val buffers in order to avoid + // races. + size_t allslice_yc_size = yc_size * (s->encoding ? nb_slices : 1); + if (s->out_format == FMT_H263) { + /* ac values */ + if (!FF_ALLOCZ_TYPED_ARRAY(s->ac_val_base, allslice_yc_size)) + return AVERROR(ENOMEM); + s->ac_val = s->ac_val_base + s->b8_stride + 1; + } + /* dc values */ // MN: we need these for error resilience of intra-frames - if (!FF_ALLOCZ_TYPED_ARRAY(s->dc_val_base, yc_size)) + // Allocating them unconditionally for decoders also means + // that we don't need to reinitialize when e.g. h263_aic changes. + + // y_size and therefore yc_size is always odd; allocate one element + // more for each encoder slice in order to be able to align each slice's + // dc_val to four in order to use aligned stores when cleaning dc_val. + allslice_yc_size += s->encoding * nb_slices; + if (!FF_ALLOC_TYPED_ARRAY(s->dc_val_base, allslice_yc_size)) return AVERROR(ENOMEM); - s->dc_val[0] = s->dc_val_base + s->b8_stride + 1; - s->dc_val[1] = s->dc_val_base + y_size + s->mb_stride + 1; - s->dc_val[2] = s->dc_val[1] + c_size; - for (i = 0; i < yc_size; i++) + s->dc_val = s->dc_val_base + s->b8_stride + 1; + for (size_t i = 0; i < allslice_yc_size; ++i) s->dc_val_base[i] = 1024; } // Note the + 1 is for a quicker MPEG-4 slice_end detection if (!(s->mbskip_table = av_mallocz(mb_array_size + 2)) || /* which mb is an intra block, init macroblock skip table */ - !(s->mbintra_table = av_malloc(mb_array_size))) + !(s->mbintra_table = av_mallocz(mb_array_size))) return AVERROR(ENOMEM); - memset(s->mbintra_table, 1, mb_array_size); ALLOC_POOL(qscale_table, mv_table_size, 0); ALLOC_POOL(mb_type, mv_table_size * sizeof(uint32_t), 0); @@ -626,7 +341,7 @@ int ff_mpv_init_context_frame(MpegEncContext *s) /* FIXME: The output of H.263 with OBMC depends upon * the earlier content of the buffer; therefore we set * the flags to always reset returned buffers here. */ - ALLOC_POOL(motion_val, mv_size, FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); + ALLOC_POOL(motion_val, mv_size, AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); ALLOC_POOL(ref_index, ref_index_size, 0); } #undef ALLOC_POOL @@ -637,65 +352,14 @@ int ff_mpv_init_context_frame(MpegEncContext *s) return !CONFIG_MPEGVIDEODEC || s->encoding ? 0 : ff_mpeg_er_init(s); } -static void clear_context(MpegEncContext *s) -{ - memset(&s->buffer_pools, 0, sizeof(s->buffer_pools)); - memset(&s->next_pic, 0, sizeof(s->next_pic)); - memset(&s->last_pic, 0, sizeof(s->last_pic)); - memset(&s->cur_pic, 0, sizeof(s->cur_pic)); - - memset(s->thread_context, 0, sizeof(s->thread_context)); - - s->me.map = NULL; - s->me.score_map = NULL; - s->dct_error_sum = NULL; - s->block = NULL; - s->blocks = NULL; - s->ac_val_base = NULL; - s->ac_val[0] = - s->ac_val[1] = - s->ac_val[2] =NULL; - s->me.scratchpad = NULL; - s->me.temp = NULL; - memset(&s->sc, 0, sizeof(s->sc)); - - - s->bitstream_buffer = NULL; - s->allocated_bitstream_buffer_size = 0; - s->p_field_mv_table_base = NULL; - for (int i = 0; i < 2; i++) - for (int j = 0; j < 2; j++) - s->p_field_mv_table[i][j] = NULL; - - s->dc_val_base = NULL; - s->coded_block_base = NULL; - s->mbintra_table = NULL; - s->cbp_table = NULL; - s->pred_dir_table = NULL; - - s->mbskip_table = NULL; - - s->er.error_status_table = NULL; - s->er.er_temp_buffer = NULL; - s->mb_index2xy = NULL; -} - /** * init common structure for both encoder and decoder. * this assumes that some variables like width/height are already set */ av_cold int ff_mpv_common_init(MpegEncContext *s) { - int nb_slices = (HAVE_THREADS && - s->avctx->active_thread_type & FF_THREAD_SLICE) ? - s->avctx->thread_count : 1; int ret; - clear_context(s); - - if (s->encoding && s->avctx->slices) - nb_slices = s->avctx->slices; - if (s->avctx->pix_fmt == AV_PIX_FMT_NONE) { av_log(s->avctx, AV_LOG_ERROR, "decoding to AV_PIX_FMT_NONE is not supported.\n"); @@ -718,26 +382,15 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) if ((ret = ff_mpv_init_context_frame(s))) goto fail; - if (nb_slices > MAX_THREADS || (nb_slices > s->mb_height && s->mb_height)) { - int max_slices; - if (s->mb_height) - max_slices = FFMIN(MAX_THREADS, s->mb_height); - else - max_slices = MAX_THREADS; - av_log(s->avctx, AV_LOG_WARNING, "too many threads/slices (%d)," - " reducing to %d\n", nb_slices, max_slices); - nb_slices = max_slices; - } - s->context_initialized = 1; - memset(s->thread_context, 0, sizeof(s->thread_context)); s->thread_context[0] = s; - s->slice_context_count = nb_slices; // if (s->width && s->height) { - ret = ff_mpv_init_duplicate_contexts(s); - if (ret < 0) - goto fail; + if (!s->encoding) { + ret = ff_mpv_init_duplicate_contexts(s); + if (ret < 0) + goto fail; + } // } return 0; @@ -746,7 +399,7 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) return ret; } -void ff_mpv_free_context_frame(MpegEncContext *s) +av_cold void ff_mpv_free_context_frame(MpegEncContext *s) { free_duplicate_contexts(s); @@ -756,6 +409,7 @@ void ff_mpv_free_context_frame(MpegEncContext *s) for (int j = 0; j < 2; j++) s->p_field_mv_table[i][j] = NULL; + av_freep(&s->ac_val_base); av_freep(&s->dc_val_base); av_freep(&s->coded_block_base); av_freep(&s->mbintra_table); @@ -771,15 +425,12 @@ void ff_mpv_free_context_frame(MpegEncContext *s) s->linesize = s->uvlinesize = 0; } -void ff_mpv_common_end(MpegEncContext *s) +av_cold void ff_mpv_common_end(MpegEncContext *s) { ff_mpv_free_context_frame(s); if (s->slice_context_count > 1) s->slice_context_count = 1; - av_freep(&s->bitstream_buffer); - s->allocated_bitstream_buffer_size = 0; - ff_mpv_unref_picture(&s->last_pic); ff_mpv_unref_picture(&s->cur_pic); ff_mpv_unref_picture(&s->next_pic); @@ -797,24 +448,25 @@ void ff_clean_intra_table_entries(MpegEncContext *s) { int wrap = s->b8_stride; int xy = s->block_index[0]; - - s->dc_val[0][xy ] = - s->dc_val[0][xy + 1 ] = - s->dc_val[0][xy + wrap] = - s->dc_val[0][xy + 1 + wrap] = 1024; - /* ac pred */ - memset(s->ac_val[0][xy ], 0, 32 * sizeof(int16_t)); - memset(s->ac_val[0][xy + wrap], 0, 32 * sizeof(int16_t)); /* chroma */ - wrap = s->mb_stride; - xy = s->mb_x + s->mb_y * wrap; - s->dc_val[1][xy] = - s->dc_val[2][xy] = 1024; - /* ac pred */ - memset(s->ac_val[1][xy], 0, 16 * sizeof(int16_t)); - memset(s->ac_val[2][xy], 0, 16 * sizeof(int16_t)); + unsigned uxy = s->block_index[4]; + unsigned vxy = s->block_index[5]; + int16_t *dc_val = s->dc_val; - s->mbintra_table[xy]= 0; + AV_WN32A(dc_val + xy, 1024 << 16 | 1024); + AV_WN32 (dc_val + xy + wrap, 1024 << 16 | 1024); + dc_val[uxy] = + dc_val[vxy] = 1024; + /* ac pred */ + int16_t (*ac_val)[16] = s->ac_val; + av_assume(!((uintptr_t)ac_val & 0xF)); + // Don't reset the upper-left luma block, as it will only ever be + // referenced by blocks from the same macroblock. + memset(ac_val[xy + 1], 0, sizeof(*ac_val)); + memset(ac_val[xy + wrap], 0, 2 * sizeof(*ac_val)); + /* ac pred */ + memset(ac_val[uxy], 0, sizeof(*ac_val)); + memset(ac_val[vxy], 0, sizeof(*ac_val)); } void ff_init_block_index(MpegEncContext *s){ //FIXME maybe rename diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 8083299b6..d448ac6b5 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -30,25 +30,17 @@ #include "blockdsp.h" #include "error_resilience.h" -#include "fdctdsp.h" -#include "get_bits.h" #include "h264chroma.h" #include "h263dsp.h" #include "hpeldsp.h" #include "idctdsp.h" -#include "me_cmp.h" -#include "motion_est.h" #include "mpegpicture.h" -#include "mpegvideoencdsp.h" -#include "pixblockdsp.h" -#include "put_bits.h" -#include "ratecontrol.h" #include "qpeldsp.h" #include "videodsp.h" -#define MAX_THREADS 32 +#include "libavutil/mem_internal.h" -#define MAX_B_FRAMES 16 +#define MAX_THREADS 32 /** * Scantable. @@ -67,6 +59,8 @@ enum OutputFormat { FMT_SPEEDHQ, }; +typedef struct MpegEncContext MPVContext; + /** * MpegEncContext. */ @@ -80,47 +74,25 @@ typedef struct MpegEncContext { /* scantables */ ScanTable inter_scantable; ///< if inter == intra then intra should be used to reduce the cache usage + ScanTable intra_scantable; /* WARNING: changes above this line require updates to hardcoded * offsets used in ASM. */ - ScanTable intra_scantable; - uint8_t permutated_intra_h_scantable[64]; - uint8_t permutated_intra_v_scantable[64]; - struct AVCodecContext *avctx; - /* The following pointer is intended for codecs sharing code - * between decoder and encoder and in need of a common context to do so. */ - void *private_ctx; /* the following parameters must be initialized before encoding */ int width, height;///< picture size. must be a multiple of 16 - int gop_size; - int intra_only; ///< if true, only intra pictures are generated - int64_t bit_rate; ///< wanted bit rate enum OutputFormat out_format; ///< output format int h263_pred; ///< use MPEG-4/H.263 ac/dc predictions - int pb_frame; ///< PB-frame mode (0 = none, 1 = base, 2 = improved) - -/* the following codec id fields are deprecated in favor of codec_id */ - int h263_plus; ///< H.263+ headers - int h263_flv; ///< use flv H.263 header enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */ - int fixed_qscale; ///< fixed qscale if non zero int encoding; ///< true if we are encoding (vs decoding) - int max_b_frames; ///< max number of B-frames for encoding - int luma_elim_threshold; - int chroma_elim_threshold; int workaround_bugs; ///< workaround bugs in encoders which cannot be detected automatically int codec_tag; ///< internal codec_tag upper case converted from avctx codec_tag /* the following fields are managed internally by the encoder */ /* sequence parameters */ int context_initialized; - int input_picture_number; ///< used to set pic->display_picture_number, should not be used for/by anything else - int coded_picture_number; ///< used to set pic->coded_picture_number, should not be used for/by anything else - int picture_number; //FIXME remove, unclear definition - int picture_in_gop_number; ///< 0-> first pic in gop, ... int mb_width, mb_height; ///< number of MBs horizontally & vertically int mb_stride; ///< mb_width+1 used for some arrays to allow simple addressing of left & top MBs without sig11 int b8_stride; ///< 2*mb_width+1 used for some 8x8 block arrays to allow simple addressing @@ -128,28 +100,17 @@ typedef struct MpegEncContext { int mb_num; ///< number of MBs of a picture ptrdiff_t linesize; ///< line size, in bytes, may be different from width ptrdiff_t uvlinesize; ///< line size, for chroma in bytes, may be different from width - struct FFRefStructPool *picture_pool; ///< Pool for MPVPictures - MPVPicture **input_picture;///< next pictures on display order for encoding - MPVPicture **reordered_input_picture; ///< pointer to the next pictures in coded order for encoding + struct AVRefStructPool *picture_pool; ///< Pool for MPVPictures BufferPoolContext buffer_pools; - int64_t user_specified_pts; ///< last non-zero pts from AVFrame which was passed into avcodec_send_frame() - /** - * pts difference between the first and second input frame, used for - * calculating dts of the first frame when there's a delay */ - int64_t dts_delta; - /** - * reordered pts to be used as dts for the next output frame when there's - * a delay */ - int64_t reordered_pts; - - /** bit output */ - PutBitContext pb; - int start_mb_y; ///< start mb_y of this thread (so current thread should process start_mb_y <= row < end_mb_y) int end_mb_y; ///< end mb_y of this thread (so current thread should process start_mb_y <= row < end_mb_y) - struct MpegEncContext *thread_context[MAX_THREADS]; + union { + struct MpegEncContext *thread_context[MAX_THREADS]; + struct Mpeg12SliceContext *mpeg12_contexts[MAX_THREADS]; + struct MPVEncContext *enc_contexts[MAX_THREADS]; + }; int slice_context_count; ///< number of used thread_contexts /** @@ -164,29 +125,21 @@ typedef struct MpegEncContext { */ MPVWorkPicture next_pic; - /** - * Reference to the source picture for encoding. - * note, linesize & data, might not match the source picture (for field pictures) - */ - AVFrame *new_pic; - /** * copy of the current picture structure. * note, linesize & data, might not match the current picture (for field pictures) */ MPVWorkPicture cur_pic; - int skipped_last_frame; - int last_dc[3]; ///< last DC values for MPEG-1 int16_t *dc_val_base; - int16_t *dc_val[3]; ///< used for MPEG-4 DC prediction, all 3 arrays must be continuous const uint8_t *y_dc_scale_table; ///< qscale -> y_dc_scale table const uint8_t *c_dc_scale_table; ///< qscale -> c_dc_scale table const uint8_t *chroma_qscale_table; ///< qscale -> chroma_qscale (H.263) uint8_t *coded_block_base; uint8_t *coded_block; ///< used for coded block pattern prediction (msmpeg4v3, wmv1) int16_t (*ac_val_base)[16]; - int16_t (*ac_val[3])[16]; ///< used for MPEG-4 AC prediction, all 3 arrays must be continuous + int16_t *dc_val; ///< used for H.263 AIC/MPEG-4 DC prediction and ER + int16_t (*ac_val)[16]; ///< used for H.263 AIC, MPEG-4 AC prediction int mb_skipped; ///< MUST BE SET only during DECODING uint8_t *mbskip_table; /**< used to avoid copy if macroblock skipped (for black regions for example) and used for B-frame encoding & decoding (contains skip table of next P-frame) */ @@ -198,65 +151,19 @@ typedef struct MpegEncContext { int qscale; ///< QP int chroma_qscale; ///< chroma QP - unsigned int lambda; ///< Lagrange multiplier used in rate distortion - unsigned int lambda2; ///< (lambda*lambda) >> FF_LAMBDA_SHIFT - int *lambda_table; - int adaptive_quant; ///< use adaptive quantization - int dquant; ///< qscale difference to prev qscale - int pict_type; ///< AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B, ... - int vbv_delay; - int last_pict_type; //FIXME removes - int last_non_b_pict_type; ///< used for MPEG-4 gmc B-frames & ratecontrol + enum AVPictureType pict_type; ///< AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B, ... int droppable; - int last_lambda_for[5]; ///< last lambda for a specific pict type - int skipdct; ///< skip dct and code zero residual - - /* motion compensation */ - int unrestricted_mv; ///< mv can point outside of the coded picture - int h263_long_vectors; ///< use horrible H.263v1 long vector mode BlockDSPContext bdsp; - FDCTDSPContext fdsp; H264ChromaContext h264chroma; HpelDSPContext hdsp; IDCTDSPContext idsp; - MpegvideoEncDSPContext mpvencdsp; - PixblockDSPContext pdsp; QpelDSPContext qdsp; VideoDSPContext vdsp; H263DSPContext h263dsp; - int f_code; ///< forward MV resolution - int b_code; ///< backward MV resolution for B-frames (MPEG-4) - int16_t (*p_mv_table_base)[2]; - int16_t (*b_forw_mv_table_base)[2]; - int16_t (*b_back_mv_table_base)[2]; - int16_t (*b_bidir_forw_mv_table_base)[2]; - int16_t (*b_bidir_back_mv_table_base)[2]; - int16_t (*b_direct_mv_table_base)[2]; int16_t (*p_field_mv_table_base)[2]; - int16_t (*b_field_mv_table_base)[2]; - int16_t (*p_mv_table)[2]; ///< MV table (1MV per MB) P-frame encoding - int16_t (*b_forw_mv_table)[2]; ///< MV table (1MV per MB) forward mode B-frame encoding - int16_t (*b_back_mv_table)[2]; ///< MV table (1MV per MB) backward mode B-frame encoding - int16_t (*b_bidir_forw_mv_table)[2]; ///< MV table (1MV per MB) bidir mode B-frame encoding - int16_t (*b_bidir_back_mv_table)[2]; ///< MV table (1MV per MB) bidir mode B-frame encoding - int16_t (*b_direct_mv_table)[2]; ///< MV table (1MV per MB) direct mode B-frame encoding int16_t (*p_field_mv_table[2][2])[2]; ///< MV table (2MV per MB) interlaced P-frame encoding - int16_t (*b_field_mv_table[2][2][2])[2];///< MV table (4MV per MB) interlaced B-frame encoding - uint8_t (*p_field_select_table[2]); ///< Only the first element is allocated - uint8_t (*b_field_select_table[2][2]); ///< Only the first element is allocated - /* The following fields are encoder-only */ - uint16_t *mb_var; ///< Table for MB variances - uint16_t *mc_mb_var; ///< Table for motion compensated MB variances - uint8_t *mb_mean; ///< Table for MB luminance - int64_t mb_var_sum; ///< sum of MB variance for current frame - int64_t mc_mb_var_sum; ///< motion compensated MB variance for current frame - uint64_t encoding_error[MPV_MAX_PLANES]; - - int motion_est; ///< ME algorithm - int me_penalty_compensation; - int me_pre; ///< prepass for motion estimation int mv_dir; #define MV_DIR_FORWARD 1 #define MV_DIR_BACKWARD 2 @@ -275,19 +182,14 @@ typedef struct MpegEncContext { int mv[2][4][2]; int field_select[2][2]; int last_mv[2][2][2]; ///< last MV, used for MV prediction in MPEG-1 & B-frame MPEG-4 - const uint8_t *fcode_tab; ///< smallest fcode needed for each MV int16_t direct_scale_mv[2][64]; ///< precomputed to avoid divisions in ff_mpeg4_set_direct_mv - MotionEstContext me; - int no_rounding; /**< apply no rounding to motion compensation (MPEG-4, msmpeg4, ...) for B-frames rounding mode is always 0 */ /* macroblock layer */ int mb_x, mb_y; - int mb_skip_run; int mb_intra; - uint16_t *mb_type; ///< Table for candidate MB types for encoding (defines in mpegvideoenc.h) int block_index[6]; ///< index to current MB in block based arrays with edges int block_wrap[6]; @@ -296,85 +198,26 @@ typedef struct MpegEncContext { int *mb_index2xy; ///< mb_index -> mb_x + mb_y*mb_stride /** matrix transmitted in the bitstream */ - uint16_t intra_matrix[64]; - uint16_t chroma_intra_matrix[64]; - uint16_t inter_matrix[64]; - uint16_t chroma_inter_matrix[64]; - - int intra_quant_bias; ///< bias for the quantizer - int inter_quant_bias; ///< bias for the quantizer - int min_qcoeff; ///< minimum encodable coefficient - int max_qcoeff; ///< maximum encodable coefficient - int ac_esc_length; ///< num of bits needed to encode the longest esc - uint8_t *intra_ac_vlc_length; - uint8_t *intra_ac_vlc_last_length; - uint8_t *intra_chroma_ac_vlc_length; - uint8_t *intra_chroma_ac_vlc_last_length; - uint8_t *inter_ac_vlc_length; - uint8_t *inter_ac_vlc_last_length; - uint8_t *luma_dc_vlc_length; - - int coded_score[12]; - - /** precomputed matrix (combine qscale and DCT renorm) */ - int (*q_intra_matrix)[64]; - int (*q_chroma_intra_matrix)[64]; - int (*q_inter_matrix)[64]; - /** identical to the above but for MMX & these are not permutated, second 64 entries are bias*/ - uint16_t (*q_intra_matrix16)[2][64]; - uint16_t (*q_chroma_intra_matrix16)[2][64]; - uint16_t (*q_inter_matrix16)[2][64]; - - /* noise reduction */ - int (*dct_error_sum)[64]; - int dct_count[2]; - uint16_t (*dct_offset)[64]; - - /* bit rate control */ - int64_t total_bits; - int frame_bits; ///< bits used for the current frame - int stuffing_bits; ///< bits used for stuffing - int next_lambda; ///< next lambda used for retrying to encode a frame - RateControlContext rc_context; ///< contains stuff only accessed in ratecontrol.c - - /* statistics, used for 2-pass encoding */ - int mv_bits; - int header_bits; - int i_tex_bits; - int p_tex_bits; - int i_count; - int misc_bits; ///< cbp, mb_type - int last_bits; ///< temp var used for calculating the above vars + DECLARE_ALIGNED(16, uint16_t, intra_matrix)[64]; + DECLARE_ALIGNED(16, uint16_t, chroma_intra_matrix)[64]; + DECLARE_ALIGNED(16, uint16_t, inter_matrix)[64]; + DECLARE_ALIGNED(16, uint16_t, chroma_inter_matrix)[64]; /* error concealment / resync */ int resync_mb_x; ///< x position of last resync marker int resync_mb_y; ///< y position of last resync marker - GetBitContext last_resync_gb; ///< used to search for the next resync marker - int mb_num_left; ///< number of MBs left in this video packet (for partitioned Slices only) + + /* H.261 specific */ + int mtype; /* H.263 specific */ - int gob_index; int obmc; ///< overlapped block motion compensation - int mb_info; ///< interval for outputting info about mb offsets as side data - int prev_mb_info, last_mb_info; - uint8_t *mb_info_ptr; - int mb_info_size; - int ehc_mode; /* H.263+ specific */ - int umvplus; ///< == H.263+ && unrestricted_mv int h263_aic_dir; ///< AIC direction: 0 = left, 1 = top - int h263_slice_structured; - int alt_inter_vlc; ///< alternative inter vlc - int modified_quant; - int loop_filter; - int custom_pcf; /* MPEG-4 specific */ int studio_profile; - int dct_precision; - ///< number of bits to represent the fractional part of time (encoder only) - int time_increment_bits; int last_time_base; int time_base; ///< time in seconds of last I,P,S Frame int64_t time; ///< time of current frame @@ -385,37 +228,10 @@ typedef struct MpegEncContext { uint16_t pb_field_time; ///< like above, just for interlaced int mcsel; int quarter_sample; ///< 1->qpel, 0->half pel ME/MC - int data_partitioning; ///< data partitioning flag from header - int partitioned_frame; ///< is current frame partitioned int low_delay; ///< no reordering needed / has no B-frames - PutBitContext tex_pb; ///< used for data partitioned VOPs - PutBitContext pb2; ///< used for data partitioned VOPs - int mpeg_quant; - int padding_bug_score; ///< used to detect the VERY common padding bug in MPEG-4 - - /* divx specific, used to workaround (many) bugs in divx5 */ - int divx_packed; - uint8_t *bitstream_buffer; //Divx 5.01 puts several frames in a single one, this is used to reorder them - int bitstream_buffer_size; - unsigned int allocated_bitstream_buffer_size; - - /* RV10 specific */ - int rv10_version; ///< RV10 version: 0 or 3 - int rv10_first_dc_coded[3]; - - /* MJPEG specific */ - struct MJpegContext *mjpeg_ctx; - int esc_pos; /* MSMPEG4 specific */ - int mv_table_index; - int rl_table_index; - int rl_chroma_table_index; - int dc_table_index; - int use_skip_mb_code; - int slice_height; ///< in macroblocks int first_slice_line; ///< used in MPEG-4 too to handle resync markers - int flipflop_rounding; enum { MSMP4_UNUSED, MSMP4_V1, @@ -425,19 +241,9 @@ typedef struct MpegEncContext { MSMP4_WMV2, MSMP4_VC1, ///< for VC1 (image), WMV3 (image) and MSS2. } msmpeg4_version; - int per_mb_rl_table; - int esc3_level_length; - int esc3_run_length; int inter_intra_pred; int mspel; - /* decompression specific */ - GetBitContext gb; - - /* MPEG-1 specific */ - int last_mv_dir; ///< last mv_dir, used for B-frame encoding - int vbv_delay_pos; ///< offset of vbv_delay in the bitstream - /* MPEG-2-specific - I wished not to have to support this mess. */ int progressive_sequence; int mpeg_f_code[2][2]; @@ -450,7 +256,6 @@ typedef struct MpegEncContext { int top_field_first; int concealment_motion_vectors; int q_scale_type; - int brd_scale; int intra_vlc_format; int alternate_scan; int repeat_first_field; @@ -467,94 +272,21 @@ typedef struct MpegEncContext { int interlaced_dct; int first_field; ///< is 1 for the first field of a field picture 0 otherwise - /* RTP specific */ - int rtp_mode; - int rtp_payload_size; - - uint8_t *ptr_lastgob; - - int16_t (*block)[64]; ///< points to one of the following blocks - int16_t (*blocks)[12][64]; // for HQ mode we need to keep the best block - int (*decode_mb)(struct MpegEncContext *s, int16_t block[12][64]); // used by some codecs to avoid a switch() - -#define SLICE_OK 0 -#define SLICE_ERROR -1 -#define SLICE_END -2 /// clipping, 1-> use a nice continuous function to limit qscale within qmin/qmax. - */ - float rc_qsquish; - float rc_qmod_amp; - int rc_qmod_freq; - float rc_initial_cplx; - float rc_buffer_aggressivity; - float border_masking; - int lmin, lmax; - int vbv_ignore_qmax; - - char *rc_eq; - - /* temp buffers for rate control */ - float *cplx_tab, *bits_tab; + void (*dct_unquantize_intra)(const MPVContext *s, // unquantizer to use (MPEG-4 can use both) + int16_t *block/*align 16*/, int n, int qscale); + void (*dct_unquantize_inter)(const MPVContext *s, // unquantizer to use (MPEG-4 can use both) + int16_t *block/*align 16*/, int n, int qscale); /* flag to indicate a reinitialization is required, e.g. after * a frame size change */ int context_reinit; + /// If set, ff_mpv_common_init() will allocate slice contexts of this size + unsigned slice_ctx_size; + ERContext er; - - int error_rate; - - /* temporary frames used by b_frame_strategy = 2 */ - AVFrame *tmp_frames[MAX_B_FRAMES + 2]; - int b_frame_strategy; - int b_sensitivity; - - /* frame skip options for encoding */ - int frame_skip_threshold; - int frame_skip_factor; - int frame_skip_exp; - int frame_skip_cmp; - me_cmp_func frame_skip_cmp_fn; - - int scenechange_threshold; - int noise_reduction; - - int intra_penalty; } MpegEncContext; - /** * Set the given MpegEncContext to common defaults (same for encoding * and decoding). The changed fields will not depend upon the prior @@ -563,12 +295,6 @@ typedef struct MpegEncContext { void ff_mpv_common_defaults(MpegEncContext *s); int ff_mpv_common_init(MpegEncContext *s); -void ff_mpv_common_init_arm(MpegEncContext *s); -void ff_mpv_common_init_axp(MpegEncContext *s); -void ff_mpv_common_init_neon(MpegEncContext *s); -void ff_mpv_common_init_ppc(MpegEncContext *s); -void ff_mpv_common_init_x86(MpegEncContext *s); -void ff_mpv_common_init_mips(MpegEncContext *s); /** * Initialize an MpegEncContext's thread contexts. Presumes that * slice_context_count is already set and that all the fields diff --git a/libavcodec/mpegvideo_dec.c b/libavcodec/mpegvideo_dec.c index 0c2937a7c..ad27180ef 100644 --- a/libavcodec/mpegvideo_dec.c +++ b/libavcodec/mpegvideo_dec.c @@ -32,18 +32,58 @@ #include "avcodec.h" #include "decode.h" +#include "h263.h" #include "h264chroma.h" #include "internal.h" #include "mpegutils.h" #include "mpegvideo.h" #include "mpegvideodec.h" #include "mpeg4videodec.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadprogress.h" #include "wmv2dec.h" -int ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx) +#define H264_CHROMA_MC(OPNAME, OP)\ +static void OPNAME ## h264_chroma_mc1(uint8_t *dst /*align 8*/, const uint8_t *src /*align 1*/, ptrdiff_t stride, int h, int x, int y)\ +{\ + const int A = (8-x) * (8-y);\ + const int B = ( x) * (8-y);\ + const int C = (8-x) * ( y);\ + const int D = ( x) * ( y);\ + \ + av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0);\ +\ + if (D) {\ + for (int i = 0; i < h; ++i) {\ + OP(dst[0], (A*src[0] + B*src[1] + C*src[stride+0] + D*src[stride+1]));\ + dst += stride;\ + src += stride;\ + }\ + } else if (B + C) {\ + const int E = B + C;\ + const int step = C ? stride : 1;\ + for (int i = 0; i < h; ++i) {\ + OP(dst[0], (A*src[0] + E*src[step+0]));\ + dst += stride;\ + src += stride;\ + }\ + } else {\ + for (int i = 0; i < h; ++i) {\ + OP(dst[0], (A*src[0]));\ + dst += stride;\ + src += stride;\ + }\ + }\ +}\ + +#define op_avg(a, b) a = (((a)+(((b) + 32)>>6)+1)>>1) +#define op_put(a, b) a = (((b) + 32)>>6) + +H264_CHROMA_MC(put_, op_put) +H264_CHROMA_MC(avg_, op_avg) + +av_cold int ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx) { enum ThreadingStatus thread_status; @@ -61,6 +101,8 @@ int ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx) ff_mpv_idct_init(s); ff_h264chroma_init(&s->h264chroma, 8); //for lowres + s->h264chroma.avg_h264_chroma_pixels_tab[3] = avg_h264_chroma_mc1; + s->h264chroma.put_h264_chroma_pixels_tab[3] = put_h264_chroma_mc1; if (s->picture_pool) // VC-1 can call this multiple times return 0; @@ -79,44 +121,23 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, { MpegEncContext *const s1 = src->priv_data; MpegEncContext *const s = dst->priv_data; - int ret; + int ret = 0; if (dst == src) return 0; av_assert0(s != s1); - // FIXME can parameters change on I-frames? - // in that case dst may need a reinit - if (!s->context_initialized) { - void *private_ctx = s->private_ctx; - int err; - memcpy(s, s1, sizeof(*s)); - - s->context_initialized = 0; - s->context_reinit = 0; - s->avctx = dst; - s->private_ctx = private_ctx; - s->bitstream_buffer = NULL; - s->bitstream_buffer_size = s->allocated_bitstream_buffer_size = 0; - - if (s1->context_initialized) { - if ((err = ff_mpv_common_init(s)) < 0) - return err; - } - } - if (s->height != s1->height || s->width != s1->width || s->context_reinit) { s->height = s1->height; s->width = s1->width; if ((ret = ff_mpv_common_frame_size_change(s)) < 0) return ret; + ret = 1; } s->quarter_sample = s1->quarter_sample; - s->picture_number = s1->picture_number; - ff_mpv_replace_picture(&s->cur_pic, &s1->cur_pic); ff_mpv_replace_picture(&s->last_pic, &s1->last_pic); ff_mpv_replace_picture(&s->next_pic, &s1->next_pic); @@ -126,7 +147,6 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, // Error/bug resilience s->workaround_bugs = s1->workaround_bugs; - s->padding_bug_score = s1->padding_bug_score; // MPEG-4 timing info memcpy(&s->last_time_base, &s1->last_time_base, @@ -134,42 +154,25 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, (char *) &s1->last_time_base); // B-frame info - s->max_b_frames = s1->max_b_frames; s->low_delay = s1->low_delay; - // DivX handling (doesn't work) - s->divx_packed = s1->divx_packed; - - if (s1->bitstream_buffer) { - av_fast_padded_malloc(&s->bitstream_buffer, - &s->allocated_bitstream_buffer_size, - s1->bitstream_buffer_size); - if (!s->bitstream_buffer) { - s->bitstream_buffer_size = 0; - return AVERROR(ENOMEM); - } - s->bitstream_buffer_size = s1->bitstream_buffer_size; - memcpy(s->bitstream_buffer, s1->bitstream_buffer, - s1->bitstream_buffer_size); - } - // MPEG-2/interlacing info memcpy(&s->progressive_sequence, &s1->progressive_sequence, - (char *) &s1->rtp_mode - (char *) &s1->progressive_sequence); + (char *) &s1->first_field + sizeof(s1->first_field) - (char *) &s1->progressive_sequence); - return 0; + return ret; } -int ff_mpv_decode_close(AVCodecContext *avctx) +av_cold int ff_mpv_decode_close(AVCodecContext *avctx) { MpegEncContext *s = avctx->priv_data; - ff_refstruct_pool_uninit(&s->picture_pool); + av_refstruct_pool_uninit(&s->picture_pool); ff_mpv_common_end(s); return 0; } -int ff_mpv_common_frame_size_change(MpegEncContext *s) +av_cold int ff_mpv_common_frame_size_change(MpegEncContext *s) { int err = 0; @@ -216,7 +219,7 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s) static int alloc_picture(MpegEncContext *s, MPVWorkPicture *dst, int reference) { AVCodecContext *avctx = s->avctx; - MPVPicture *pic = ff_refstruct_pool_get(s->picture_pool); + MPVPicture *pic = av_refstruct_pool_get(s->picture_pool); int ret; if (!pic) @@ -404,7 +407,7 @@ void ff_print_debug_info(const MpegEncContext *s, const MPVPicture *p, AVFrame * { ff_print_debug_info2(s->avctx, pict, p->mb_type, p->qscale_table, p->motion_val, - s->mb_width, s->mb_height, s->mb_stride, s->quarter_sample); + p->mb_width, p->mb_height, p->mb_stride, s->quarter_sample); } int ff_mpv_export_qp_table(const MpegEncContext *s, AVFrame *f, @@ -446,7 +449,7 @@ void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h) s->first_field, s->low_delay); } -void ff_mpeg_flush(AVCodecContext *avctx) +av_cold void ff_mpeg_flush(AVCodecContext *avctx) { MpegEncContext *const s = avctx->priv_data; @@ -456,17 +459,9 @@ void ff_mpeg_flush(AVCodecContext *avctx) s->mb_x = s->mb_y = 0; - s->bitstream_buffer_size = 0; s->pp_time = 0; } -void ff_mpv_report_decode_progress(MpegEncContext *s) -{ - if (s->pict_type != AV_PICTURE_TYPE_B && !s->partitioned_frame && !s->er.error_occurred) - ff_thread_progress_report(&s->cur_pic.ptr->progress, s->mb_y); -} - - static inline int hpel_motion_lowres(MpegEncContext *s, uint8_t *dest, const uint8_t *src, int field_based, int field_select, @@ -853,7 +848,7 @@ static inline void MPV_motion_lowres(MpegEncContext *s, } break; default: - av_assert2(0); + av_unreachable("No other mpegvideo MV types exist"); } } @@ -897,29 +892,255 @@ unhandled: /* add block[] to dest[] */ static inline void add_dct(MpegEncContext *s, - int16_t *block, int i, uint8_t *dest, int line_size) + int16_t block[][64], int i, uint8_t *dest, int line_size) { if (s->block_last_index[i] >= 0) { - s->idsp.idct_add(dest, line_size, block); + s->idsp.idct_add(dest, line_size, block[i]); } } -#define IS_ENCODER 0 -#include "mpv_reconstruct_mb_template.c" - -void ff_mpv_reconstruct_mb(MpegEncContext *s, int16_t block[12][64]) +/* put block[] to dest[] */ +static inline void put_dct(MpegEncContext *s, + int16_t *block, int i, uint8_t *dest, int line_size, int qscale) { - if (s->avctx->debug & FF_DEBUG_DCT_COEFF) { - /* print DCT coefficients */ - av_log(s->avctx, AV_LOG_DEBUG, "DCT coeffs of MB at %dx%d:\n", s->mb_x, s->mb_y); - for (int i = 0; i < 6; i++) { - for (int j = 0; j < 64; j++) { - av_log(s->avctx, AV_LOG_DEBUG, "%5d", - block[i][s->idsp.idct_permutation[j]]); - } - av_log(s->avctx, AV_LOG_DEBUG, "\n"); - } + s->dct_unquantize_intra(s, block, i, qscale); + s->idsp.idct_put(dest, line_size, block); +} + +static inline void add_dequant_dct(MpegEncContext *s, + int16_t block[][64], int i, uint8_t *dest, int line_size, int qscale) +{ + if (s->block_last_index[i] >= 0) { + s->dct_unquantize_inter(s, block[i], i, qscale); + + s->idsp.idct_add(dest, line_size, block[i]); } +} + +#define NOT_MPEG12_H261 0 +#define MAY_BE_MPEG12_H261 1 +#define DEFINITELY_MPEG12_H261 2 + +/* generic function called after a macroblock has been parsed by the decoder. + + Important variables used: + s->mb_intra : true if intra macroblock + s->mv_dir : motion vector direction + s->mv_type : motion vector type + s->mv : motion vector + s->interlaced_dct : true if interlaced dct used (mpeg2) + */ +static av_always_inline +void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], + int lowres_flag, int is_mpeg12) +{ +#define IS_MPEG12_H261(s) (is_mpeg12 == MAY_BE_MPEG12_H261 ? ((s)->out_format <= FMT_H261) : is_mpeg12) + uint8_t *dest_y = s->dest[0], *dest_cb = s->dest[1], *dest_cr = s->dest[2]; + int dct_linesize, dct_offset; + const int linesize = s->cur_pic.linesize[0]; //not s->linesize as this would be wrong for field pics + const int uvlinesize = s->cur_pic.linesize[1]; + const int block_size = lowres_flag ? 8 >> s->avctx->lowres : 8; + + dct_linesize = linesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? linesize : linesize * block_size; + + if (!s->mb_intra) { + /* motion handling */ + if (HAVE_THREADS && is_mpeg12 != DEFINITELY_MPEG12_H261 && + s->avctx->active_thread_type & FF_THREAD_FRAME) { + if (s->mv_dir & MV_DIR_FORWARD) { + ff_thread_progress_await(&s->last_pic.ptr->progress, + lowest_referenced_row(s, 0)); + } + if (s->mv_dir & MV_DIR_BACKWARD) { + ff_thread_progress_await(&s->next_pic.ptr->progress, + lowest_referenced_row(s, 1)); + } + } + + if (lowres_flag) { + const h264_chroma_mc_func *op_pix = s->h264chroma.put_h264_chroma_pixels_tab; + + if (s->mv_dir & MV_DIR_FORWARD) { + MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, s->last_pic.data, op_pix); + op_pix = s->h264chroma.avg_h264_chroma_pixels_tab; + } + if (s->mv_dir & MV_DIR_BACKWARD) { + MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 1, s->next_pic.data, op_pix); + } + } else { + const op_pixels_func (*op_pix)[4]; + const qpel_mc_func (*op_qpix)[16]; + + if ((is_mpeg12 == DEFINITELY_MPEG12_H261 || !s->no_rounding) || s->pict_type == AV_PICTURE_TYPE_B) { + op_pix = s->hdsp.put_pixels_tab; + op_qpix = s->qdsp.put_qpel_pixels_tab; + } else { + op_pix = s->hdsp.put_no_rnd_pixels_tab; + op_qpix = s->qdsp.put_no_rnd_qpel_pixels_tab; + } + if (s->mv_dir & MV_DIR_FORWARD) { + ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 0, s->last_pic.data, op_pix, op_qpix); + op_pix = s->hdsp.avg_pixels_tab; + op_qpix = s->qdsp.avg_qpel_pixels_tab; + } + if (s->mv_dir & MV_DIR_BACKWARD) { + ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 1, s->next_pic.data, op_pix, op_qpix); + } + } + + /* skip dequant / idct if we are really late ;) */ + if (s->avctx->skip_idct) { + if ( (s->avctx->skip_idct >= AVDISCARD_NONREF && s->pict_type == AV_PICTURE_TYPE_B) + ||(s->avctx->skip_idct >= AVDISCARD_NONKEY && s->pict_type != AV_PICTURE_TYPE_I) + || s->avctx->skip_idct >= AVDISCARD_ALL) + return; + } + + /* add dct residue */ + if (is_mpeg12 != DEFINITELY_MPEG12_H261 && s->dct_unquantize_inter) { + // H.263, H.263+, H.263I, FLV, RV10, RV20 and MPEG-4 with MPEG-2 quantization + add_dequant_dct(s, block, 0, dest_y , dct_linesize, s->qscale); + add_dequant_dct(s, block, 1, dest_y + block_size, dct_linesize, s->qscale); + add_dequant_dct(s, block, 2, dest_y + dct_offset , dct_linesize, s->qscale); + add_dequant_dct(s, block, 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + av_assert2(s->chroma_y_shift); + add_dequant_dct(s, block, 4, dest_cb, uvlinesize, s->chroma_qscale); + add_dequant_dct(s, block, 5, dest_cr, uvlinesize, s->chroma_qscale); + } + } else if (is_mpeg12 == DEFINITELY_MPEG12_H261 || lowres_flag || (s->codec_id != AV_CODEC_ID_WMV2)) { + // H.261, MPEG-1, MPEG-2, MPEG-4 with H.263 quantization, + // MSMP4V1-3 and WMV1. + // Also RV30, RV40 and the VC-1 family when performing error resilience, + // but all blocks are skipped in this case. + add_dct(s, block, 0, dest_y , dct_linesize); + add_dct(s, block, 1, dest_y + block_size, dct_linesize); + add_dct(s, block, 2, dest_y + dct_offset , dct_linesize); + add_dct(s, block, 3, dest_y + dct_offset + block_size, dct_linesize); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + if (s->chroma_y_shift) {//Chroma420 + add_dct(s, block, 4, dest_cb, uvlinesize); + add_dct(s, block, 5, dest_cr, uvlinesize); + } else { + //chroma422 + dct_linesize = uvlinesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; + + add_dct(s, block, 4, dest_cb, dct_linesize); + add_dct(s, block, 5, dest_cr, dct_linesize); + add_dct(s, block, 6, dest_cb + dct_offset, dct_linesize); + add_dct(s, block, 7, dest_cr + dct_offset, dct_linesize); + if (!s->chroma_x_shift) {//Chroma444 + add_dct(s, block, 8, dest_cb + block_size, dct_linesize); + add_dct(s, block, 9, dest_cr + block_size, dct_linesize); + add_dct(s, block, 10, dest_cb + block_size + dct_offset, dct_linesize); + add_dct(s, block, 11, dest_cr + block_size + dct_offset, dct_linesize); + } + } + } //fi gray + } else if (CONFIG_WMV2_DECODER) { + ff_wmv2_add_mb(s, block, dest_y, dest_cb, dest_cr); + } + } else { + /* Only MPEG-4 Simple Studio Profile is supported in > 8-bit mode. + TODO: Integrate 10-bit properly into mpegvideo.c so that ER works properly */ + if (is_mpeg12 != DEFINITELY_MPEG12_H261 && CONFIG_MPEG4_DECODER && + /* s->codec_id == AV_CODEC_ID_MPEG4 && */ + s->avctx->bits_per_raw_sample > 8) { + ff_mpeg4_decode_studio(s, dest_y, dest_cb, dest_cr, block_size, + uvlinesize, dct_linesize, dct_offset); + } else if (!IS_MPEG12_H261(s)) { + /* dct only in intra block */ + put_dct(s, block[0], 0, dest_y , dct_linesize, s->qscale); + put_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->qscale); + put_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->qscale); + put_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + if (s->chroma_y_shift) { + put_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); + put_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); + } else { + dct_offset >>= 1; + dct_linesize >>= 1; + put_dct(s, block[4], 4, dest_cb, dct_linesize, s->chroma_qscale); + put_dct(s, block[5], 5, dest_cr, dct_linesize, s->chroma_qscale); + put_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->chroma_qscale); + put_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->chroma_qscale); + } + } + } else { + s->idsp.idct_put(dest_y, dct_linesize, block[0]); + s->idsp.idct_put(dest_y + block_size, dct_linesize, block[1]); + s->idsp.idct_put(dest_y + dct_offset, dct_linesize, block[2]); + s->idsp.idct_put(dest_y + dct_offset + block_size, dct_linesize, block[3]); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + if (s->chroma_y_shift) { + s->idsp.idct_put(dest_cb, uvlinesize, block[4]); + s->idsp.idct_put(dest_cr, uvlinesize, block[5]); + } else { + dct_linesize = uvlinesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; + + s->idsp.idct_put(dest_cb, dct_linesize, block[4]); + s->idsp.idct_put(dest_cr, dct_linesize, block[5]); + s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, block[6]); + s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, block[7]); + if (!s->chroma_x_shift) { //Chroma444 + s->idsp.idct_put(dest_cb + block_size, dct_linesize, block[8]); + s->idsp.idct_put(dest_cr + block_size, dct_linesize, block[9]); + s->idsp.idct_put(dest_cb + block_size + dct_offset, dct_linesize, block[10]); + s->idsp.idct_put(dest_cr + block_size + dct_offset, dct_linesize, block[11]); + } + } + } //gray + } + } +} + +static av_cold void debug_dct_coeffs(MPVContext *s, const int16_t block[][64]) +{ + if (!block) // happens when called via error resilience + return; + + void *const logctx = s->avctx; + const uint8_t *const idct_permutation = s->idsp.idct_permutation; + + /* print DCT coefficients */ + av_log(logctx, AV_LOG_DEBUG, "DCT coeffs of MB at %dx%d:\n", s->mb_x, s->mb_y); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 64; j++) { + av_log(logctx, AV_LOG_DEBUG, "%5d", + block[i][idct_permutation[j]]); + } + av_log(logctx, AV_LOG_DEBUG, "\n"); + } +} + +void ff_mpv_reconstruct_mb(MPVContext *s, int16_t block[][64]) +{ + const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; + uint8_t *mbskip_ptr = &s->mbskip_table[mb_xy]; + + s->cur_pic.qscale_table[mb_xy] = s->qscale; + + /* avoid copy if macroblock skipped in last frame too */ + if (s->mb_skipped) { + s->mb_skipped = 0; + av_assert2(s->pict_type != AV_PICTURE_TYPE_I); + *mbskip_ptr = 1; + } else if (!s->cur_pic.reference) { + *mbskip_ptr = 1; + } else{ + *mbskip_ptr = 0; /* not skipped */ + } + + if (s->avctx->debug & FF_DEBUG_DCT_COEFF) + debug_dct_coeffs(s, block); av_assert2((s->out_format <= FMT_H261) == (s->out_format == FMT_H261 || s->out_format == FMT_MPEG1)); if (!s->avctx->lowres) { diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index 3dd486518..83bc4cee0 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -33,6 +33,7 @@ #include "config_components.h" +#include #include #include "libavutil/emms.h" @@ -46,7 +47,6 @@ #include "avcodec.h" #include "encode.h" #include "idctdsp.h" -#include "mpeg12codecs.h" #include "mpeg12data.h" #include "mpeg12enc.h" #include "mpegvideo.h" @@ -59,6 +59,7 @@ #include "mjpegenc_common.h" #include "mathops.h" #include "mpegutils.h" +#include "mpegvideo_unquantize.h" #include "mjpegenc.h" #include "speedhqenc.h" #include "msmpeg4enc.h" @@ -66,16 +67,13 @@ #include "qpeldsp.h" #include "faandct.h" #include "aandcttab.h" -#include "flvenc.h" #include "mpeg4video.h" #include "mpeg4videodata.h" #include "mpeg4videoenc.h" #include "internal.h" #include "bytestream.h" -#include "wmv2enc.h" -#include "rv10enc.h" -#include "packet_internal.h" -#include "refstruct.h" +#include "rv20enc.h" +#include "libavutil/refstruct.h" #include #include "sp5x.h" @@ -84,16 +82,14 @@ #define QMAT_SHIFT_MMX 16 #define QMAT_SHIFT 21 -static int encode_picture(MpegEncContext *s, const AVPacket *pkt); -static int dct_quantize_refine(MpegEncContext *s, int16_t *block, int16_t *weight, int16_t *orig, int n, int qscale); -static int sse_mb(MpegEncContext *s); -static void denoise_dct_c(MpegEncContext *s, int16_t *block); -static int dct_quantize_c(MpegEncContext *s, +static int encode_picture(MPVMainEncContext *const s, const AVPacket *pkt); +static int dct_quantize_refine(MPVEncContext *const s, int16_t *block, int16_t *weight, int16_t *orig, int n, int qscale); +static int sse_mb(MPVEncContext *const s); +static int dct_quantize_c(MPVEncContext *const s, int16_t *block, int n, int qscale, int *overflow); -static int dct_quantize_trellis_c(MpegEncContext *s, int16_t *block, int n, int qscale, int *overflow); +static int dct_quantize_trellis_c(MPVEncContext *const s, int16_t *block, int n, int qscale, int *overflow); -static uint8_t default_mv_penalty[MAX_FCODE + 1][MAX_DMV * 2 + 1]; static uint8_t default_fcode_tab[MAX_MV * 2 + 1]; static const AVOption mpv_generic_options[] = { @@ -109,7 +105,7 @@ const AVClass ff_mpv_enc_class = { .version = LIBAVUTIL_VERSION_INT, }; -void ff_convert_matrix(MpegEncContext *s, int (*qmat)[64], +void ff_convert_matrix(MPVEncContext *const s, int (*qmat)[64], uint16_t (*qmat16)[2][64], const uint16_t *quant_matrix, int bias, int qmin, int qmax, int intra) @@ -122,7 +118,7 @@ void ff_convert_matrix(MpegEncContext *s, int (*qmat)[64], int i; int qscale2; - if (s->q_scale_type) qscale2 = ff_mpeg2_non_linear_qscale[qscale]; + if (s->c.q_scale_type) qscale2 = ff_mpeg2_non_linear_qscale[qscale]; else qscale2 = qscale << 1; if (fdsp->fdct == ff_jpeg_fdct_islow_8 || @@ -131,40 +127,43 @@ void ff_convert_matrix(MpegEncContext *s, int (*qmat)[64], #endif /* CONFIG_FAANDCT */ fdsp->fdct == ff_jpeg_fdct_islow_10) { for (i = 0; i < 64; i++) { - const int j = s->idsp.idct_permutation[i]; + const int j = s->c.idsp.idct_permutation[i]; int64_t den = (int64_t) qscale2 * quant_matrix[j]; - /* 16 <= qscale * quant_matrix[i] <= 7905 - * Assume x = ff_aanscales[i] * qscale * quant_matrix[i] - * 19952 <= x <= 249205026 - * (1 << 36) / 19952 >= (1 << 36) / (x) >= (1 << 36) / 249205026 - * 3444240 >= (1 << 36) / (x) >= 275 */ + /* 1 * 1 <= qscale2 * quant_matrix[j] <= 112 * 255 + * Assume x = qscale2 * quant_matrix[j] + * 1 <= x <= 28560 + * (1 << 22) / 1 >= (1 << 22) / (x) >= (1 << 22) / 28560 + * 4194304 >= (1 << 22) / (x) >= 146 */ qmat[qscale][i] = (int)((UINT64_C(2) << QMAT_SHIFT) / den); } } else if (fdsp->fdct == ff_fdct_ifast) { for (i = 0; i < 64; i++) { - const int j = s->idsp.idct_permutation[i]; + const int j = s->c.idsp.idct_permutation[i]; int64_t den = ff_aanscales[i] * (int64_t) qscale2 * quant_matrix[j]; - /* 16 <= qscale * quant_matrix[i] <= 7905 - * Assume x = ff_aanscales[i] * qscale * quant_matrix[i] - * 19952 <= x <= 249205026 - * (1 << 36) / 19952 >= (1 << 36) / (x) >= (1 << 36) / 249205026 - * 3444240 >= (1 << 36) / (x) >= 275 */ + /* 1247 * 1 * 1 <= ff_aanscales[i] * qscale2 * quant_matrix[j] <= 31521 * 112 * 255 + * Assume x = ff_aanscales[i] * qscale2 * quant_matrix[j] + * 1247 <= x <= 900239760 + * (1 << 36) / 1247 >= (1 << 36) / (x) >= (1 << 36) / 900239760 + * 55107840 >= (1 << 36) / (x) >= 76 */ qmat[qscale][i] = (int)((UINT64_C(2) << (QMAT_SHIFT + 14)) / den); } } else { for (i = 0; i < 64; i++) { - const int j = s->idsp.idct_permutation[i]; + const int j = s->c.idsp.idct_permutation[i]; int64_t den = (int64_t) qscale2 * quant_matrix[j]; - /* We can safely suppose that 16 <= quant_matrix[i] <= 255 - * Assume x = qscale * quant_matrix[i] - * So 16 <= x <= 7905 - * so (1 << 19) / 16 >= (1 << 19) / (x) >= (1 << 19) / 7905 - * so 32768 >= (1 << 19) / (x) >= 67 */ + /* 1 * 1 <= qscale2 * quant_matrix[j] <= 112 * 255 + * Assume x = qscale2 * quant_matrix[j] + * 1 <= x <= 28560 + * (1 << 22) / 1 >= (1 << 22) / (x) >= (1 << 22) / 28560 + * 4194304 >= (1 << 22) / (x) >= 146 + * + * 1 <= x <= 28560 + * (1 << 17) / 1 >= (1 << 17) / (x) >= (1 << 17) / 28560 + * 131072 >= (1 << 17) / (x) >= 4 */ + qmat[qscale][i] = (int)((UINT64_C(2) << QMAT_SHIFT) / den); - //qmat [qscale][i] = (1 << QMAT_SHIFT_MMX) / - // (qscale * quant_matrix[i]); qmat16[qscale][0][i] = (2 << QMAT_SHIFT_MMX) / den; if (qmat16[qscale][0][i] == 0 || @@ -187,34 +186,36 @@ void ff_convert_matrix(MpegEncContext *s, int (*qmat)[64], } } if (shift) { - av_log(s->avctx, AV_LOG_INFO, + av_log(s->c.avctx, AV_LOG_INFO, "Warning, QMAT_SHIFT is larger than %d, overflows possible\n", QMAT_SHIFT - shift); } } -static inline void update_qscale(MpegEncContext *s) +static inline void update_qscale(MPVMainEncContext *const m) { - if (s->q_scale_type == 1 && 0) { + MPVEncContext *const s = &m->s; + + if (s->c.q_scale_type == 1 && 0) { int i; int bestdiff=INT_MAX; int best = 1; for (i = 0 ; ilambda * 139); - if (ff_mpeg2_non_linear_qscale[i] < s->avctx->qmin || - (ff_mpeg2_non_linear_qscale[i] > s->avctx->qmax && !s->vbv_ignore_qmax)) + if (ff_mpeg2_non_linear_qscale[i] < s->c.avctx->qmin || + (ff_mpeg2_non_linear_qscale[i] > s->c.avctx->qmax && !m->vbv_ignore_qmax)) continue; if (diff < bestdiff) { bestdiff = diff; best = i; } } - s->qscale = best; + s->c.qscale = best; } else { - s->qscale = (s->lambda * 139 + FF_LAMBDA_SCALE * 64) >> + s->c.qscale = (s->lambda * 139 + FF_LAMBDA_SCALE * 64) >> (FF_LAMBDA_SHIFT + 7); - s->qscale = av_clip(s->qscale, s->avctx->qmin, s->vbv_ignore_qmax ? 31 : s->avctx->qmax); + s->c.qscale = av_clip(s->c.qscale, s->c.avctx->qmin, m->vbv_ignore_qmax ? 31 : s->c.avctx->qmax); } s->lambda2 = (s->lambda * s->lambda + FF_LAMBDA_SCALE / 2) >> @@ -235,79 +236,100 @@ void ff_write_quant_matrix(PutBitContext *pb, uint16_t *matrix) } /** - * init s->cur_pic.qscale_table from s->lambda_table + * init s->c.cur_pic.qscale_table from s->lambda_table */ -static void init_qscale_tab(MpegEncContext *s) +static void init_qscale_tab(MPVEncContext *const s) { - int8_t * const qscale_table = s->cur_pic.qscale_table; - int i; + int8_t *const qscale_table = s->c.cur_pic.qscale_table; - for (i = 0; i < s->mb_num; i++) { - unsigned int lam = s->lambda_table[s->mb_index2xy[i]]; + for (int i = 0; i < s->c.mb_num; i++) { + unsigned int lam = s->lambda_table[s->c.mb_index2xy[i]]; int qp = (lam * 139 + FF_LAMBDA_SCALE * 64) >> (FF_LAMBDA_SHIFT + 7); - qscale_table[s->mb_index2xy[i]] = av_clip(qp, s->avctx->qmin, - s->avctx->qmax); + qscale_table[s->c.mb_index2xy[i]] = av_clip(qp, s->c.avctx->qmin, + s->c.avctx->qmax); } } -static void update_duplicate_context_after_me(MpegEncContext *dst, - const MpegEncContext *src) +static void update_duplicate_context_after_me(MPVEncContext *const dst, + const MPVEncContext *const src) { -#define COPY(a) dst->a= src->a - COPY(pict_type); +#define COPY(a) dst->a = src->a + COPY(c.pict_type); COPY(f_code); COPY(b_code); - COPY(qscale); + COPY(c.qscale); COPY(lambda); COPY(lambda2); - COPY(frame_pred_frame_dct); // FIXME don't set in encode_header - COPY(progressive_frame); // FIXME don't set in encode_header - COPY(partitioned_frame); // FIXME don't set in encode_header + COPY(c.frame_pred_frame_dct); // FIXME don't set in encode_header + COPY(c.progressive_frame); // FIXME don't set in encode_header + COPY(partitioned_frame); // FIXME don't set in encode_header #undef COPY } -static void mpv_encode_init_static(void) +static av_cold void mpv_encode_init_static(void) { for (int i = -16; i < 16; i++) default_fcode_tab[i + MAX_MV] = 1; } /** - * Set the given MpegEncContext to defaults for encoding. - * the changed fields will not depend upon the prior state of the MpegEncContext. + * Set the given MPVEncContext to defaults for encoding. */ -static void mpv_encode_defaults(MpegEncContext *s) +static av_cold void mpv_encode_defaults(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; static AVOnce init_static_once = AV_ONCE_INIT; - ff_mpv_common_defaults(s); + ff_mpv_common_defaults(&s->c); - ff_thread_once(&init_static_once, mpv_encode_init_static); + s->f_code = 1; + s->b_code = 1; - s->me.mv_penalty = default_mv_penalty; - s->fcode_tab = default_fcode_tab; - - s->input_picture_number = 0; - s->picture_in_gop_number = 0; + if (!m->fcode_tab) { + m->fcode_tab = default_fcode_tab + MAX_MV; + ff_thread_once(&init_static_once, mpv_encode_init_static); + } + if (!s->c.y_dc_scale_table) { + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_mpeg1_dc_scale_table; + } } -av_cold void ff_dct_encode_init(MpegEncContext *s) +av_cold void ff_dct_encode_init(MPVEncContext *const s) { s->dct_quantize = dct_quantize_c; - s->denoise_dct = denoise_dct_c; -#if ARCH_MIPS - ff_mpvenc_dct_init_mips(s); -#elif ARCH_X86 +#if ARCH_X86 ff_dct_encode_init_x86(s); #endif - if (s->avctx->trellis) + if (s->c.avctx->trellis) s->dct_quantize = dct_quantize_trellis_c; } -static av_cold int me_cmp_init(MpegEncContext *s, AVCodecContext *avctx) +static av_cold void init_unquantize(MPVEncContext *const s2, AVCodecContext *avctx) { + MpegEncContext *const s = &s2->c; + MPVUnquantDSPContext unquant_dsp_ctx; + + ff_mpv_unquantize_init(&unquant_dsp_ctx, + avctx->flags & AV_CODEC_FLAG_BITEXACT, s->q_scale_type); + + if (s2->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + s->dct_unquantize_intra = unquant_dsp_ctx.dct_unquantize_mpeg2_intra; + s->dct_unquantize_inter = unquant_dsp_ctx.dct_unquantize_mpeg2_inter; + } else if (s->out_format == FMT_H263 || s->out_format == FMT_H261) { + s->dct_unquantize_intra = unquant_dsp_ctx.dct_unquantize_h263_intra; + s->dct_unquantize_inter = unquant_dsp_ctx.dct_unquantize_h263_inter; + } else { + s->dct_unquantize_intra = unquant_dsp_ctx.dct_unquantize_mpeg1_intra; + s->dct_unquantize_inter = unquant_dsp_ctx.dct_unquantize_mpeg1_inter; + } +} + +static av_cold int me_cmp_init(MPVMainEncContext *const m, AVCodecContext *avctx) +{ + MPVEncContext *const s = &m->s; MECmpContext mecc; me_cmp_func me_cmp[6]; int ret; @@ -316,10 +338,10 @@ static av_cold int me_cmp_init(MpegEncContext *s, AVCodecContext *avctx) ret = ff_me_init(&s->me, avctx, &mecc, 1); if (ret < 0) return ret; - ret = ff_set_cmp(&mecc, me_cmp, s->frame_skip_cmp, 1); + ret = ff_set_cmp(&mecc, me_cmp, m->frame_skip_cmp, 1); if (ret < 0) return ret; - s->frame_skip_cmp_fn = me_cmp[1]; + m->frame_skip_cmp_fn = me_cmp[1]; if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) { ret = ff_set_cmp(&mecc, me_cmp, avctx->ildct_cmp, 1); if (ret < 0) @@ -347,37 +369,218 @@ static av_cold int me_cmp_init(MpegEncContext *s, AVCodecContext *avctx) return 0; } +#define ALLOCZ_ARRAYS(p, mult, numb) ((p) = av_calloc(numb, mult * sizeof(*(p)))) +static av_cold int init_matrices(MPVMainEncContext *const m, AVCodecContext *avctx) +{ + MPVEncContext *const s = &m->s; + const int nb_matrices = 1 + (s->c.out_format == FMT_MJPEG) + !m->intra_only; + const uint16_t *intra_matrix, *inter_matrix; + int ret; + + if (!ALLOCZ_ARRAYS(s->q_intra_matrix, 32, nb_matrices) || + !ALLOCZ_ARRAYS(s->q_intra_matrix16, 32, nb_matrices)) + return AVERROR(ENOMEM); + + if (s->c.out_format == FMT_MJPEG) { + s->q_chroma_intra_matrix = s->q_intra_matrix + 32; + s->q_chroma_intra_matrix16 = s->q_intra_matrix16 + 32; + // No need to set q_inter_matrix + av_assert1(m->intra_only); + // intra_matrix, chroma_intra_matrix will be set later for MJPEG. + return 0; + } else { + s->q_chroma_intra_matrix = s->q_intra_matrix; + s->q_chroma_intra_matrix16 = s->q_intra_matrix16; + } + if (!m->intra_only) { + s->q_inter_matrix = s->q_intra_matrix + 32; + s->q_inter_matrix16 = s->q_intra_matrix16 + 32; + } + + if (CONFIG_MPEG4_ENCODER && s->c.codec_id == AV_CODEC_ID_MPEG4 && + s->mpeg_quant) { + intra_matrix = ff_mpeg4_default_intra_matrix; + inter_matrix = ff_mpeg4_default_non_intra_matrix; + } else if (s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) { + intra_matrix = + inter_matrix = ff_mpeg1_default_non_intra_matrix; + } else { + /* MPEG-1/2, SpeedHQ */ + intra_matrix = ff_mpeg1_default_intra_matrix; + inter_matrix = ff_mpeg1_default_non_intra_matrix; + } + if (avctx->intra_matrix) + intra_matrix = avctx->intra_matrix; + if (avctx->inter_matrix) + inter_matrix = avctx->inter_matrix; + + /* init q matrix */ + for (int i = 0; i < 64; i++) { + int j = s->c.idsp.idct_permutation[i]; + + s->c.intra_matrix[j] = s->c.chroma_intra_matrix[j] = intra_matrix[i]; + s->c.inter_matrix[j] = inter_matrix[i]; + } + + /* precompute matrix */ + ret = ff_check_codec_matrices(avctx, FF_MATRIX_TYPE_INTRA | FF_MATRIX_TYPE_INTER, 1, 255); + if (ret < 0) + return ret; + + ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16, + s->c.intra_matrix, s->intra_quant_bias, avctx->qmin, + 31, 1); + if (s->q_inter_matrix) + ff_convert_matrix(s, s->q_inter_matrix, s->q_inter_matrix16, + s->c.inter_matrix, s->inter_quant_bias, avctx->qmin, + 31, 0); + + return 0; +} + +static av_cold int init_buffers(MPVMainEncContext *const m) +{ + MPVEncContext *const s = &m->s; + int has_b_frames = !!m->max_b_frames; + int16_t (*mv_table)[2]; + + /* Allocate MB type table */ + unsigned mb_array_size = s->c.mb_stride * s->c.mb_height; + s->mb_type = av_calloc(mb_array_size, 3 * sizeof(*s->mb_type) + sizeof(*s->mb_mean)); + if (!s->mb_type) + return AVERROR(ENOMEM); + s->mc_mb_var = s->mb_type + mb_array_size; + s->mb_var = s->mc_mb_var + mb_array_size; + s->mb_mean = (uint8_t*)(s->mb_var + mb_array_size); + + if (!FF_ALLOCZ_TYPED_ARRAY(s->lambda_table, mb_array_size)) + return AVERROR(ENOMEM); + + unsigned mv_table_size = (s->c.mb_height + 2) * s->c.mb_stride + 1; + unsigned nb_mv_tables = 1 + 5 * has_b_frames; + if (s->c.codec_id == AV_CODEC_ID_MPEG4 || + (s->c.avctx->flags & AV_CODEC_FLAG_INTERLACED_ME)) { + nb_mv_tables += 8 * has_b_frames; + s->p_field_select_table[0] = av_calloc(mv_table_size, 2 * (2 + 4 * has_b_frames)); + if (!s->p_field_select_table[0]) + return AVERROR(ENOMEM); + s->p_field_select_table[1] = s->p_field_select_table[0] + 2 * mv_table_size; + } + + mv_table = av_calloc(mv_table_size, nb_mv_tables * sizeof(*mv_table)); + if (!mv_table) + return AVERROR(ENOMEM); + m->mv_table_base = mv_table; + mv_table += s->c.mb_stride + 1; + + s->p_mv_table = mv_table; + if (has_b_frames) { + s->b_forw_mv_table = mv_table += mv_table_size; + s->b_back_mv_table = mv_table += mv_table_size; + s->b_bidir_forw_mv_table = mv_table += mv_table_size; + s->b_bidir_back_mv_table = mv_table += mv_table_size; + s->b_direct_mv_table = mv_table += mv_table_size; + + if (s->p_field_select_table[1]) { // MPEG-4 or INTERLACED_ME above + uint8_t *field_select = s->p_field_select_table[1]; + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + for (int l = 0; l < 2; l++) + s->b_field_mv_table[j][k][l] = mv_table += mv_table_size; + s->b_field_select_table[j][k] = field_select += 2 * mv_table_size; + } + } + } + } + + return 0; +} + +static av_cold int init_slice_buffers(MPVMainEncContext *const m) +{ + MPVEncContext *const s = &m->s; + // Align the following per-thread buffers to avoid false sharing. + enum { +#ifndef _MSC_VER + /// The number is supposed to match/exceed the cache-line size. + ALIGN = FFMAX(128, _Alignof(max_align_t)), +#else + ALIGN = 128, +#endif + DCT_ERROR_SIZE = FFALIGN(2 * sizeof(*s->dct_error_sum), ALIGN), + }; + static_assert(DCT_ERROR_SIZE * MAX_THREADS + ALIGN - 1 <= SIZE_MAX, + "Need checks for potential overflow."); + unsigned nb_slices = s->c.slice_context_count; + char *dct_error = NULL; + + if (m->noise_reduction) { + if (!FF_ALLOCZ_TYPED_ARRAY(s->dct_offset, 2)) + return AVERROR(ENOMEM); + dct_error = av_mallocz(ALIGN - 1 + nb_slices * DCT_ERROR_SIZE); + if (!dct_error) + return AVERROR(ENOMEM); + m->dct_error_sum_base = dct_error; + dct_error += FFALIGN((uintptr_t)dct_error, ALIGN) - (uintptr_t)dct_error; + } + + const int y_size = s->c.b8_stride * (2 * s->c.mb_height + 1); + const int c_size = s->c.mb_stride * (s->c.mb_height + 1); + const int yc_size = y_size + 2 * c_size; + ptrdiff_t offset = 0; + + for (unsigned i = 0; i < nb_slices; ++i) { + MPVEncContext *const s2 = s->c.enc_contexts[i]; + + s2->block = s2->blocks[0]; + + if (dct_error) { + s2->dct_offset = s->dct_offset; + s2->dct_error_sum = (void*)dct_error; + dct_error += DCT_ERROR_SIZE; + } + + if (s2->c.ac_val) { + s2->c.dc_val += offset + i; + s2->c.ac_val += offset; + offset += yc_size; + } + } + return 0; +} + /* init video encoder */ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) { - MpegEncContext *s = avctx->priv_data; + MPVMainEncContext *const m = avctx->priv_data; + MPVEncContext *const s = &m->s; AVCPBProperties *cpb_props; - int i, ret; - int mb_array_size, mv_table_size; + int gcd, ret; - mpv_encode_defaults(s); + mpv_encode_defaults(m); switch (avctx->pix_fmt) { case AV_PIX_FMT_YUVJ444P: case AV_PIX_FMT_YUV444P: - s->chroma_format = CHROMA_444; + s->c.chroma_format = CHROMA_444; break; case AV_PIX_FMT_YUVJ422P: case AV_PIX_FMT_YUV422P: - s->chroma_format = CHROMA_422; + s->c.chroma_format = CHROMA_422; break; + default: + av_unreachable("Already checked via CODEC_PIXFMTS"); case AV_PIX_FMT_YUVJ420P: case AV_PIX_FMT_YUV420P: - default: - s->chroma_format = CHROMA_420; + s->c.chroma_format = CHROMA_420; break; } avctx->bits_per_raw_sample = av_clip(avctx->bits_per_raw_sample, 0, 8); - s->bit_rate = avctx->bit_rate; - s->width = avctx->width; - s->height = avctx->height; + m->bit_rate = avctx->bit_rate; + s->c.width = avctx->width; + s->c.height = avctx->height; if (avctx->gop_size > 600 && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { av_log(avctx, AV_LOG_WARNING, @@ -385,65 +588,46 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) avctx->gop_size, 600); avctx->gop_size = 600; } - s->gop_size = avctx->gop_size; - s->avctx = avctx; - if (avctx->max_b_frames > MAX_B_FRAMES) { + m->gop_size = avctx->gop_size; + s->c.avctx = avctx; + if (avctx->max_b_frames > MPVENC_MAX_B_FRAMES) { av_log(avctx, AV_LOG_ERROR, "Too many B-frames requested, maximum " - "is %d.\n", MAX_B_FRAMES); - avctx->max_b_frames = MAX_B_FRAMES; + "is " AV_STRINGIFY(MPVENC_MAX_B_FRAMES) ".\n"); + avctx->max_b_frames = MPVENC_MAX_B_FRAMES; } else if (avctx->max_b_frames < 0) { av_log(avctx, AV_LOG_ERROR, "max b frames must be 0 or positive for mpegvideo based encoders\n"); return AVERROR(EINVAL); } - s->max_b_frames = avctx->max_b_frames; - s->codec_id = avctx->codec->id; - if (s->max_b_frames && !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)) { + m->max_b_frames = avctx->max_b_frames; + s->c.codec_id = avctx->codec->id; + if (m->max_b_frames && !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)) { av_log(avctx, AV_LOG_ERROR, "B-frames not supported by codec\n"); return AVERROR(EINVAL); } - s->quarter_sample = (avctx->flags & AV_CODEC_FLAG_QPEL) != 0; + s->c.quarter_sample = (avctx->flags & AV_CODEC_FLAG_QPEL) != 0; s->rtp_mode = !!s->rtp_payload_size; - s->intra_dc_precision = avctx->intra_dc_precision; + m->user_specified_pts = AV_NOPTS_VALUE; - // workaround some differences between how applications specify dc precision - if (s->intra_dc_precision < 0) { - s->intra_dc_precision += 8; - } else if (s->intra_dc_precision >= 8) - s->intra_dc_precision -= 8; - - if (s->intra_dc_precision < 0) { - av_log(avctx, AV_LOG_ERROR, - "intra dc precision must be positive, note some applications use" - " 0 and some 8 as base meaning 8bit, the value must not be smaller than that\n"); - return AVERROR(EINVAL); - } - - if (s->intra_dc_precision > (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ? 3 : 0)) { - av_log(avctx, AV_LOG_ERROR, "intra dc precision too large\n"); - return AVERROR(EINVAL); - } - s->user_specified_pts = AV_NOPTS_VALUE; - - if (s->gop_size <= 1) { - s->intra_only = 1; - s->gop_size = 12; + if (m->gop_size <= 1) { + m->intra_only = 1; + m->gop_size = 12; } else { - s->intra_only = 0; + m->intra_only = 0; } /* Fixed QSCALE */ - s->fixed_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE); + m->fixed_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE); s->adaptive_quant = (avctx->lumi_masking || avctx->dark_masking || avctx->temporal_cplx_masking || avctx->spatial_cplx_masking || avctx->p_masking || - s->border_masking || + m->border_masking || (s->mpv_flags & FF_MPV_FLAG_QP_RD)) && - !s->fixed_qscale; + !m->fixed_qscale; s->loop_filter = !!(avctx->flags & AV_CODEC_FLAG_LOOP_FILTER); @@ -507,7 +691,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - if (!s->fixed_qscale && + if (!m->fixed_qscale && avctx->bit_rate * av_q2d(avctx->time_base) > avctx->bit_rate_tolerance) { double nbt = avctx->bit_rate * av_q2d(avctx->time_base) * 5; @@ -519,38 +703,27 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) avctx->bit_rate_tolerance = INT_MAX; } - if (avctx->rc_max_rate && - avctx->rc_min_rate == avctx->rc_max_rate && - (s->codec_id == AV_CODEC_ID_MPEG1VIDEO || - s->codec_id == AV_CODEC_ID_MPEG2VIDEO) && - 90000LL * (avctx->rc_buffer_size - 1) > - avctx->rc_max_rate * 0xFFFFLL) { - av_log(avctx, AV_LOG_INFO, - "Warning vbv_delay will be set to 0xFFFF (=VBR) as the " - "specified vbv buffer is too large for the given bitrate!\n"); - } - - if ((avctx->flags & AV_CODEC_FLAG_4MV) && s->codec_id != AV_CODEC_ID_MPEG4 && - s->codec_id != AV_CODEC_ID_H263 && s->codec_id != AV_CODEC_ID_H263P && - s->codec_id != AV_CODEC_ID_FLV1) { + if ((avctx->flags & AV_CODEC_FLAG_4MV) && s->c.codec_id != AV_CODEC_ID_MPEG4 && + s->c.codec_id != AV_CODEC_ID_H263 && s->c.codec_id != AV_CODEC_ID_H263P && + s->c.codec_id != AV_CODEC_ID_FLV1) { av_log(avctx, AV_LOG_ERROR, "4MV not supported by codec\n"); return AVERROR(EINVAL); } - if (s->obmc && avctx->mb_decision != FF_MB_DECISION_SIMPLE) { + if (s->c.obmc && avctx->mb_decision != FF_MB_DECISION_SIMPLE) { av_log(avctx, AV_LOG_ERROR, "OBMC is only supported with simple mb decision\n"); return AVERROR(EINVAL); } - if (s->quarter_sample && s->codec_id != AV_CODEC_ID_MPEG4) { + if (s->c.quarter_sample && s->c.codec_id != AV_CODEC_ID_MPEG4) { av_log(avctx, AV_LOG_ERROR, "qpel not supported by codec\n"); return AVERROR(EINVAL); } - if ((s->codec_id == AV_CODEC_ID_MPEG4 || - s->codec_id == AV_CODEC_ID_H263 || - s->codec_id == AV_CODEC_ID_H263P) && + if ((s->c.codec_id == AV_CODEC_ID_MPEG4 || + s->c.codec_id == AV_CODEC_ID_H263 || + s->c.codec_id == AV_CODEC_ID_H263P) && (avctx->sample_aspect_ratio.num > 255 || avctx->sample_aspect_ratio.den > 255)) { av_log(avctx, AV_LOG_WARNING, @@ -560,44 +733,37 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den, 255); } - if ((s->codec_id == AV_CODEC_ID_H263 || - s->codec_id == AV_CODEC_ID_H263P) && + if ((s->c.codec_id == AV_CODEC_ID_H263 || + s->c.codec_id == AV_CODEC_ID_H263P) && (avctx->width > 2048 || avctx->height > 1152 )) { av_log(avctx, AV_LOG_ERROR, "H.263 does not support resolutions above 2048x1152\n"); return AVERROR(EINVAL); } - if (s->codec_id == AV_CODEC_ID_FLV1 && + if (s->c.codec_id == AV_CODEC_ID_FLV1 && (avctx->width > 65535 || avctx->height > 65535 )) { av_log(avctx, AV_LOG_ERROR, "FLV does not support resolutions above 16bit\n"); return AVERROR(EINVAL); } - if ((s->codec_id == AV_CODEC_ID_H263 || - s->codec_id == AV_CODEC_ID_H263P || - s->codec_id == AV_CODEC_ID_RV20) && + if ((s->c.codec_id == AV_CODEC_ID_H263 || + s->c.codec_id == AV_CODEC_ID_H263P || + s->c.codec_id == AV_CODEC_ID_RV20) && ((avctx->width &3) || (avctx->height&3) )) { av_log(avctx, AV_LOG_ERROR, "width and height must be a multiple of 4\n"); return AVERROR(EINVAL); } - if (s->codec_id == AV_CODEC_ID_RV10 && - (avctx->width &15 || - avctx->height&15 )) { - av_log(avctx, AV_LOG_ERROR, "width and height must be a multiple of 16\n"); - return AVERROR(EINVAL); - } - - if ((s->codec_id == AV_CODEC_ID_WMV1 || - s->codec_id == AV_CODEC_ID_WMV2) && + if ((s->c.codec_id == AV_CODEC_ID_WMV1 || + s->c.codec_id == AV_CODEC_ID_WMV2) && avctx->width & 1) { av_log(avctx, AV_LOG_ERROR, "width must be multiple of 2\n"); return AVERROR(EINVAL); } if ((avctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME)) && - s->codec_id != AV_CODEC_ID_MPEG4 && s->codec_id != AV_CODEC_ID_MPEG2VIDEO) { + s->c.codec_id != AV_CODEC_ID_MPEG4 && s->c.codec_id != AV_CODEC_ID_MPEG2VIDEO) { av_log(avctx, AV_LOG_ERROR, "interlacing not supported by codec\n"); return AVERROR(EINVAL); } @@ -613,7 +779,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - if (s->scenechange_threshold < 1000000000 && + if (m->scenechange_threshold < 1000000000 && (avctx->flags & AV_CODEC_FLAG_CLOSED_GOP)) { av_log(avctx, AV_LOG_ERROR, "closed gop with scene change detection are not supported yet, " @@ -622,49 +788,41 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) } if (avctx->flags & AV_CODEC_FLAG_LOW_DELAY) { - if (s->codec_id != AV_CODEC_ID_MPEG2VIDEO && + if (s->c.codec_id != AV_CODEC_ID_MPEG2VIDEO && avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL) { av_log(avctx, AV_LOG_ERROR, "low delay forcing is only available for mpeg2, " "set strict_std_compliance to 'unofficial' or lower in order to allow it\n"); return AVERROR(EINVAL); } - if (s->max_b_frames != 0) { + if (m->max_b_frames != 0) { av_log(avctx, AV_LOG_ERROR, "B-frames cannot be used with low delay\n"); return AVERROR(EINVAL); } } - if (s->q_scale_type == 1) { - if (avctx->qmax > 28) { - av_log(avctx, AV_LOG_ERROR, - "non linear quant only supports qmax <= 28 currently\n"); - return AVERROR_PATCHWELCOME; - } - } - if (avctx->slices > 1 && !(avctx->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS)) { av_log(avctx, AV_LOG_ERROR, "Multiple slices are not supported by this codec\n"); return AVERROR(EINVAL); } - if (s->b_frame_strategy && (avctx->flags & AV_CODEC_FLAG_PASS2)) { + if (m->b_frame_strategy && (avctx->flags & AV_CODEC_FLAG_PASS2)) { av_log(avctx, AV_LOG_INFO, "notice: b_frame_strategy only affects the first pass\n"); - s->b_frame_strategy = 0; + m->b_frame_strategy = 0; } - i = av_gcd(avctx->time_base.den, avctx->time_base.num); - if (i > 1) { + gcd = av_gcd(avctx->time_base.den, avctx->time_base.num); + if (gcd > 1) { av_log(avctx, AV_LOG_INFO, "removing common factors from framerate\n"); - avctx->time_base.den /= i; - avctx->time_base.num /= i; + avctx->time_base.den /= gcd; + avctx->time_base.num /= gcd; //return -1; } - if (s->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG1VIDEO || s->codec_id == AV_CODEC_ID_MPEG2VIDEO || s->codec_id == AV_CODEC_ID_MJPEG || s->codec_id == AV_CODEC_ID_AMV || s->codec_id == AV_CODEC_ID_SPEEDHQ) { + if (s->mpeg_quant || s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO || s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO || s->c.codec_id == AV_CODEC_ID_MJPEG || s->c.codec_id == AV_CODEC_ID_AMV || s->c.codec_id == AV_CODEC_ID_SPEEDHQ) { // (a + x * 3 / 8) / x s->intra_quant_bias = 3 << (QUANT_BIAS_SHIFT - 3); s->inter_quant_bias = 0; @@ -681,340 +839,236 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_DEBUG, "intra_quant_bias = %d inter_quant_bias = %d\n",s->intra_quant_bias,s->inter_quant_bias); - if (avctx->codec_id == AV_CODEC_ID_MPEG4 && - avctx->time_base.den > (1 << 16) - 1) { - av_log(avctx, AV_LOG_ERROR, - "timebase %d/%d not supported by MPEG 4 standard, " - "the maximum admitted value for the timebase denominator " - "is %d\n", avctx->time_base.num, avctx->time_base.den, - (1 << 16) - 1); - return AVERROR(EINVAL); - } - s->time_increment_bits = av_log2(avctx->time_base.den - 1) + 1; - switch (avctx->codec->id) { #if CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER case AV_CODEC_ID_MPEG2VIDEO: s->rtp_mode = 1; /* fallthrough */ case AV_CODEC_ID_MPEG1VIDEO: - s->out_format = FMT_MPEG1; - s->low_delay = !!(avctx->flags & AV_CODEC_FLAG_LOW_DELAY); - avctx->delay = s->low_delay ? 0 : (s->max_b_frames + 1); - ff_mpeg1_encode_init(s); + s->c.out_format = FMT_MPEG1; + s->c.low_delay = !!(avctx->flags & AV_CODEC_FLAG_LOW_DELAY); + avctx->delay = s->c.low_delay ? 0 : (m->max_b_frames + 1); break; #endif #if CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER case AV_CODEC_ID_MJPEG: case AV_CODEC_ID_AMV: - s->out_format = FMT_MJPEG; - s->intra_only = 1; /* force intra only for jpeg */ - if ((ret = ff_mjpeg_encode_init(s)) < 0) - return ret; + s->c.out_format = FMT_MJPEG; + m->intra_only = 1; /* force intra only for jpeg */ avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; #endif case AV_CODEC_ID_SPEEDHQ: - s->out_format = FMT_SPEEDHQ; - s->intra_only = 1; /* force intra only for SHQ */ - if (!CONFIG_SPEEDHQ_ENCODER) - return AVERROR_ENCODER_NOT_FOUND; - if ((ret = ff_speedhq_encode_init(s)) < 0) - return ret; + s->c.out_format = FMT_SPEEDHQ; + m->intra_only = 1; /* force intra only for SHQ */ avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_H261: - if (!CONFIG_H261_ENCODER) - return AVERROR_ENCODER_NOT_FOUND; - ret = ff_h261_encode_init(s); - if (ret < 0) - return ret; - s->out_format = FMT_H261; + s->c.out_format = FMT_H261; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; s->rtp_mode = 0; /* Sliced encoding not supported */ break; case AV_CODEC_ID_H263: if (!CONFIG_H263_ENCODER) return AVERROR_ENCODER_NOT_FOUND; if (ff_match_2uint16(ff_h263_format, FF_ARRAY_ELEMS(ff_h263_format), - s->width, s->height) == 8) { + s->c.width, s->c.height) == 8) { av_log(avctx, AV_LOG_ERROR, "The specified picture size of %dx%d is not valid for " "the H.263 codec.\nValid sizes are 128x96, 176x144, " "352x288, 704x576, and 1408x1152. " - "Try H.263+.\n", s->width, s->height); + "Try H.263+.\n", s->c.width, s->c.height); return AVERROR(EINVAL); } - s->out_format = FMT_H263; + s->c.out_format = FMT_H263; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_H263P: - s->out_format = FMT_H263; - s->h263_plus = 1; + s->c.out_format = FMT_H263; /* Fx */ - s->h263_aic = (avctx->flags & AV_CODEC_FLAG_AC_PRED) ? 1 : 0; - s->modified_quant = s->h263_aic; - s->loop_filter = (avctx->flags & AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; - s->unrestricted_mv = s->obmc || s->loop_filter || s->umvplus; + s->c.h263_aic = (avctx->flags & AV_CODEC_FLAG_AC_PRED) ? 1 : 0; + s->modified_quant = s->c.h263_aic; + s->loop_filter = !!(avctx->flags & AV_CODEC_FLAG_LOOP_FILTER); + s->me.unrestricted_mv = s->c.obmc || s->loop_filter || s->umvplus; s->flipflop_rounding = 1; /* /Fx */ /* These are just to be sure */ avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_FLV1: - s->out_format = FMT_H263; - s->h263_flv = 2; /* format = 1; 11-bit codes */ - s->unrestricted_mv = 1; + s->c.out_format = FMT_H263; + s->me.unrestricted_mv = 1; s->rtp_mode = 0; /* don't allow GOB */ avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; +#if CONFIG_RV10_ENCODER case AV_CODEC_ID_RV10: - s->out_format = FMT_H263; + s->c.out_format = FMT_H263; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; +#endif +#if CONFIG_RV20_ENCODER case AV_CODEC_ID_RV20: - s->out_format = FMT_H263; + m->encode_picture_header = ff_rv20_encode_picture_header; + s->c.out_format = FMT_H263; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; s->modified_quant = 1; - s->h263_aic = 1; - s->h263_plus = 1; + // Set here to force allocation of dc_val; + // will be set later on a per-frame basis. + s->c.h263_aic = 1; s->loop_filter = 1; - s->unrestricted_mv = 0; + s->me.unrestricted_mv = 0; break; +#endif case AV_CODEC_ID_MPEG4: - s->out_format = FMT_H263; - s->h263_pred = 1; - s->unrestricted_mv = 1; + s->c.out_format = FMT_H263; + s->c.h263_pred = 1; + s->me.unrestricted_mv = 1; s->flipflop_rounding = 1; - s->low_delay = s->max_b_frames ? 0 : 1; - avctx->delay = s->low_delay ? 0 : (s->max_b_frames + 1); + s->c.low_delay = m->max_b_frames ? 0 : 1; + avctx->delay = s->c.low_delay ? 0 : (m->max_b_frames + 1); break; case AV_CODEC_ID_MSMPEG4V2: - s->out_format = FMT_H263; - s->h263_pred = 1; - s->unrestricted_mv = 1; - s->msmpeg4_version = MSMP4_V2; + s->c.out_format = FMT_H263; + s->c.h263_pred = 1; + s->me.unrestricted_mv = 1; + s->c.msmpeg4_version = MSMP4_V2; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_MSMPEG4V3: - s->out_format = FMT_H263; - s->h263_pred = 1; - s->unrestricted_mv = 1; - s->msmpeg4_version = MSMP4_V3; + s->c.out_format = FMT_H263; + s->c.h263_pred = 1; + s->me.unrestricted_mv = 1; + s->c.msmpeg4_version = MSMP4_V3; s->flipflop_rounding = 1; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_WMV1: - s->out_format = FMT_H263; - s->h263_pred = 1; - s->unrestricted_mv = 1; - s->msmpeg4_version = MSMP4_WMV1; + s->c.out_format = FMT_H263; + s->c.h263_pred = 1; + s->me.unrestricted_mv = 1; + s->c.msmpeg4_version = MSMP4_WMV1; s->flipflop_rounding = 1; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_WMV2: - s->out_format = FMT_H263; - s->h263_pred = 1; - s->unrestricted_mv = 1; - s->msmpeg4_version = MSMP4_WMV2; + s->c.out_format = FMT_H263; + s->c.h263_pred = 1; + s->me.unrestricted_mv = 1; + s->c.msmpeg4_version = MSMP4_WMV2; s->flipflop_rounding = 1; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; default: - return AVERROR(EINVAL); + av_unreachable("List contains all codecs using ff_mpv_encode_init()"); } - avctx->has_b_frames = !s->low_delay; + avctx->has_b_frames = !s->c.low_delay; - s->encoding = 1; + s->c.encoding = 1; - s->progressive_frame = - s->progressive_sequence = !(avctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | - AV_CODEC_FLAG_INTERLACED_ME) || - s->alternate_scan); + s->c.progressive_frame = + s->c.progressive_sequence = !(avctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | + AV_CODEC_FLAG_INTERLACED_ME) || + s->c.alternate_scan); - if (s->lmin > s->lmax) { - av_log(avctx, AV_LOG_WARNING, "Clipping lmin value to %d\n", s->lmax); - s->lmin = s->lmax; + if (avctx->flags & AV_CODEC_FLAG_PSNR || avctx->mb_decision == FF_MB_DECISION_RD || + m->frame_skip_threshold || m->frame_skip_factor) { + s->frame_reconstruction_bitfield = (1 << AV_PICTURE_TYPE_I) | + (1 << AV_PICTURE_TYPE_P) | + (1 << AV_PICTURE_TYPE_B); + } else if (!m->intra_only) { + s->frame_reconstruction_bitfield = (1 << AV_PICTURE_TYPE_I) | + (1 << AV_PICTURE_TYPE_P); + } else { + s->frame_reconstruction_bitfield = 0; } - /* init */ - ff_mpv_idct_init(s); - if ((ret = ff_mpv_common_init(s)) < 0) - return ret; + if (m->lmin > m->lmax) { + av_log(avctx, AV_LOG_WARNING, "Clipping lmin value to %d\n", m->lmax); + m->lmin = m->lmax; + } + /* ff_mpv_init_duplicate_contexts() will copy (memdup) the contents of the + * main slice to the slice contexts, so we initialize various fields of it + * before calling ff_mpv_init_duplicate_contexts(). */ + s->parent = m; + ff_mpv_idct_init(&s->c); + init_unquantize(s, avctx); ff_fdctdsp_init(&s->fdsp, avctx); ff_mpegvideoencdsp_init(&s->mpvencdsp, avctx); - ff_pixblockdsp_init(&s->pdsp, avctx); - ret = me_cmp_init(s, avctx); + ff_pixblockdsp_init(&s->pdsp, 8); + ret = me_cmp_init(m, avctx); if (ret < 0) return ret; if (!(avctx->stats_out = av_mallocz(256)) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_intra_matrix, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_chroma_intra_matrix, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_inter_matrix, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_intra_matrix16, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_chroma_intra_matrix16, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_inter_matrix16, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->input_picture, MAX_B_FRAMES + 1) || - !FF_ALLOCZ_TYPED_ARRAY(s->reordered_input_picture, MAX_B_FRAMES + 1) || !(s->new_pic = av_frame_alloc()) || - !(s->picture_pool = ff_mpv_alloc_pic_pool(0))) + !(s->c.picture_pool = ff_mpv_alloc_pic_pool(0))) return AVERROR(ENOMEM); - /* Allocate MV tables; the MV and MB tables will be copied - * to slice contexts by ff_update_duplicate_context(). */ - mv_table_size = (s->mb_height + 2) * s->mb_stride + 1; - if (!FF_ALLOCZ_TYPED_ARRAY(s->p_mv_table_base, mv_table_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->b_forw_mv_table_base, mv_table_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->b_back_mv_table_base, mv_table_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->b_bidir_forw_mv_table_base, mv_table_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->b_bidir_back_mv_table_base, mv_table_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->b_direct_mv_table_base, mv_table_size)) - return AVERROR(ENOMEM); - s->p_mv_table = s->p_mv_table_base + s->mb_stride + 1; - s->b_forw_mv_table = s->b_forw_mv_table_base + s->mb_stride + 1; - s->b_back_mv_table = s->b_back_mv_table_base + s->mb_stride + 1; - s->b_bidir_forw_mv_table = s->b_bidir_forw_mv_table_base + s->mb_stride + 1; - s->b_bidir_back_mv_table = s->b_bidir_back_mv_table_base + s->mb_stride + 1; - s->b_direct_mv_table = s->b_direct_mv_table_base + s->mb_stride + 1; - - /* Allocate MB type table */ - mb_array_size = s->mb_stride * s->mb_height; - if (!FF_ALLOCZ_TYPED_ARRAY(s->mb_type, mb_array_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->lambda_table, mb_array_size) || - !FF_ALLOC_TYPED_ARRAY (s->cplx_tab, mb_array_size) || - !FF_ALLOC_TYPED_ARRAY (s->bits_tab, mb_array_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->mc_mb_var, mb_array_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->mb_var, mb_array_size) || - !(s->mb_mean = av_mallocz(mb_array_size))) - return AVERROR(ENOMEM); - -#define ALLOCZ_ARRAYS(p, mult, numb) ((p) = av_calloc(numb, mult * sizeof(*(p)))) - if (s->codec_id == AV_CODEC_ID_MPEG4 || - (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME)) { - int16_t (*tmp1)[2]; - uint8_t *tmp2; - if (!(tmp1 = ALLOCZ_ARRAYS(s->b_field_mv_table_base, 8, mv_table_size)) || - !(tmp2 = ALLOCZ_ARRAYS(s->b_field_select_table[0][0], 2 * 4, mv_table_size)) || - !ALLOCZ_ARRAYS(s->p_field_select_table[0], 2 * 2, mv_table_size)) - return AVERROR(ENOMEM); - - s->p_field_select_table[1] = s->p_field_select_table[0] + 2 * mv_table_size; - tmp1 += s->mb_stride + 1; - - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) { - s->b_field_mv_table[i][j][k] = tmp1; - tmp1 += mv_table_size; - } - s->b_field_select_table[i][j] = tmp2; - tmp2 += 2 * mv_table_size; - } - } - } - - if (s->noise_reduction) { - if (!FF_ALLOCZ_TYPED_ARRAY(s->dct_offset, 2)) - return AVERROR(ENOMEM); - } + ret = init_matrices(m, avctx); + if (ret < 0) + return ret; ff_dct_encode_init(s); - if (s->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { - s->dct_unquantize_intra = s->dct_unquantize_mpeg2_intra; - s->dct_unquantize_inter = s->dct_unquantize_mpeg2_inter; - } else if (s->out_format == FMT_H263 || s->out_format == FMT_H261) { - s->dct_unquantize_intra = s->dct_unquantize_h263_intra; - s->dct_unquantize_inter = s->dct_unquantize_h263_inter; - } else { - s->dct_unquantize_intra = s->dct_unquantize_mpeg1_intra; - s->dct_unquantize_inter = s->dct_unquantize_mpeg1_inter; - } - - if ((CONFIG_H263P_ENCODER || CONFIG_RV20_ENCODER) && s->modified_quant) - s->chroma_qscale_table = ff_h263_chroma_qscale_table; - - if (s->slice_context_count > 1) { - s->rtp_mode = 1; - - if (avctx->codec_id == AV_CODEC_ID_H263P) - s->h263_slice_structured = 1; - } - - if (CONFIG_H263_ENCODER && s->out_format == FMT_H263) { - ff_h263_encode_init(s); + if (CONFIG_H263_ENCODER && s->c.out_format == FMT_H263) { + ff_h263_encode_init(m); #if CONFIG_MSMPEG4ENC - if (s->msmpeg4_version != MSMP4_UNUSED) - ff_msmpeg4_encode_init(s); + if (s->c.msmpeg4_version != MSMP4_UNUSED) + ff_msmpeg4_encode_init(m); #endif } - /* init q matrix */ - for (i = 0; i < 64; i++) { - int j = s->idsp.idct_permutation[i]; - if (CONFIG_MPEG4_ENCODER && s->codec_id == AV_CODEC_ID_MPEG4 && - s->mpeg_quant) { - s->intra_matrix[j] = ff_mpeg4_default_intra_matrix[i]; - s->inter_matrix[j] = ff_mpeg4_default_non_intra_matrix[i]; - } else if (s->out_format == FMT_H263 || s->out_format == FMT_H261) { - s->intra_matrix[j] = - s->inter_matrix[j] = ff_mpeg1_default_non_intra_matrix[i]; - } else if (CONFIG_SPEEDHQ_ENCODER && s->codec_id == AV_CODEC_ID_SPEEDHQ) { - s->intra_matrix[j] = - s->inter_matrix[j] = ff_mpeg1_default_intra_matrix[i]; - } else { - /* MPEG-1/2 */ - s->chroma_intra_matrix[j] = - s->intra_matrix[j] = ff_mpeg1_default_intra_matrix[i]; - s->inter_matrix[j] = ff_mpeg1_default_non_intra_matrix[i]; - } - if (avctx->intra_matrix) - s->intra_matrix[j] = avctx->intra_matrix[i]; - if (avctx->inter_matrix) - s->inter_matrix[j] = avctx->inter_matrix[i]; + s->c.slice_ctx_size = sizeof(*s); + ret = ff_mpv_common_init(&s->c); + if (ret < 0) + return ret; + ret = init_buffers(m); + if (ret < 0) + return ret; + if (s->c.slice_context_count > 1) { + s->rtp_mode = 1; + if (avctx->codec_id == AV_CODEC_ID_H263P) + s->h263_slice_structured = 1; } - - /* precompute matrix */ - /* for mjpeg, we do include qscale in the matrix */ - if (s->out_format != FMT_MJPEG) { - ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16, - s->intra_matrix, s->intra_quant_bias, avctx->qmin, - 31, 1); - ff_convert_matrix(s, s->q_inter_matrix, s->q_inter_matrix16, - s->inter_matrix, s->inter_quant_bias, avctx->qmin, - 31, 0); - } - - if ((ret = ff_rate_control_init(s)) < 0) + ret = ff_mpv_init_duplicate_contexts(&s->c); + if (ret < 0) return ret; - if (s->b_frame_strategy == 2) { - for (i = 0; i < s->max_b_frames + 2; i++) { - s->tmp_frames[i] = av_frame_alloc(); - if (!s->tmp_frames[i]) + ret = init_slice_buffers(m); + if (ret < 0) + return ret; + + ret = ff_rate_control_init(m); + if (ret < 0) + return ret; + + if (m->b_frame_strategy == 2) { + for (int i = 0; i < m->max_b_frames + 2; i++) { + m->tmp_frames[i] = av_frame_alloc(); + if (!m->tmp_frames[i]) return AVERROR(ENOMEM); - s->tmp_frames[i]->format = AV_PIX_FMT_YUV420P; - s->tmp_frames[i]->width = s->width >> s->brd_scale; - s->tmp_frames[i]->height = s->height >> s->brd_scale; + m->tmp_frames[i]->format = AV_PIX_FMT_YUV420P; + m->tmp_frames[i]->width = s->c.width >> m->brd_scale; + m->tmp_frames[i]->height = s->c.height >> m->brd_scale; - ret = av_frame_get_buffer(s->tmp_frames[i], 0); + ret = av_frame_get_buffer(m->tmp_frames[i], 0); if (ret < 0) return ret; } @@ -1033,79 +1087,126 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) av_cold int ff_mpv_encode_end(AVCodecContext *avctx) { - MpegEncContext *s = avctx->priv_data; - int i; + MPVMainEncContext *const m = avctx->priv_data; + MPVEncContext *const s = &m->s; - ff_rate_control_uninit(&s->rc_context); + ff_rate_control_uninit(&m->rc_context); - ff_mpv_common_end(s); - ff_refstruct_pool_uninit(&s->picture_pool); + ff_mpv_common_end(&s->c); + av_refstruct_pool_uninit(&s->c.picture_pool); - if (s->input_picture && s->reordered_input_picture) { - for (int i = 0; i < MAX_B_FRAMES + 1; i++) { - ff_refstruct_unref(&s->input_picture[i]); - ff_refstruct_unref(&s->reordered_input_picture[i]); - } + for (int i = 0; i < MPVENC_MAX_B_FRAMES + 1; i++) { + av_refstruct_unref(&m->input_picture[i]); + av_refstruct_unref(&m->reordered_input_picture[i]); } - for (i = 0; i < FF_ARRAY_ELEMS(s->tmp_frames); i++) - av_frame_free(&s->tmp_frames[i]); + for (int i = 0; i < FF_ARRAY_ELEMS(m->tmp_frames); i++) + av_frame_free(&m->tmp_frames[i]); av_frame_free(&s->new_pic); av_freep(&avctx->stats_out); - av_freep(&s->p_mv_table_base); - av_freep(&s->b_forw_mv_table_base); - av_freep(&s->b_back_mv_table_base); - av_freep(&s->b_bidir_forw_mv_table_base); - av_freep(&s->b_bidir_back_mv_table_base); - av_freep(&s->b_direct_mv_table_base); - av_freep(&s->b_field_mv_table_base); - av_freep(&s->b_field_select_table[0][0]); + av_freep(&m->mv_table_base); av_freep(&s->p_field_select_table[0]); + av_freep(&m->dct_error_sum_base); av_freep(&s->mb_type); av_freep(&s->lambda_table); - av_freep(&s->cplx_tab); - av_freep(&s->bits_tab); - - if(s->q_chroma_intra_matrix != s->q_intra_matrix ) av_freep(&s->q_chroma_intra_matrix); - if(s->q_chroma_intra_matrix16 != s->q_intra_matrix16) av_freep(&s->q_chroma_intra_matrix16); - s->q_chroma_intra_matrix= NULL; - s->q_chroma_intra_matrix16= NULL; av_freep(&s->q_intra_matrix); - av_freep(&s->q_inter_matrix); av_freep(&s->q_intra_matrix16); - av_freep(&s->q_inter_matrix16); - av_freep(&s->input_picture); - av_freep(&s->reordered_input_picture); av_freep(&s->dct_offset); - av_freep(&s->mb_var); - av_freep(&s->mc_mb_var); - av_freep(&s->mb_mean); return 0; } -#define IS_ENCODER 1 -#include "mpv_reconstruct_mb_template.c" - -static void mpv_reconstruct_mb(MpegEncContext *s, int16_t block[12][64]) +/* put block[] to dest[] */ +static inline void put_dct(MPVEncContext *const s, + int16_t *block, int i, uint8_t *dest, int line_size, int qscale) { - if (s->avctx->debug & FF_DEBUG_DCT_COEFF) { + s->c.dct_unquantize_intra(&s->c, block, i, qscale); + s->c.idsp.idct_put(dest, line_size, block); +} + +static inline void add_dequant_dct(MPVEncContext *const s, + int16_t *block, int i, uint8_t *dest, int line_size, int qscale) +{ + if (s->c.block_last_index[i] >= 0) { + s->c.dct_unquantize_inter(&s->c, block, i, qscale); + + s->c.idsp.idct_add(dest, line_size, block); + } +} + +/** + * Performs dequantization and IDCT (if necessary) + */ +static void mpv_reconstruct_mb(MPVEncContext *const s, int16_t block[12][64]) +{ + if (s->c.avctx->debug & FF_DEBUG_DCT_COEFF) { /* print DCT coefficients */ - av_log(s->avctx, AV_LOG_DEBUG, "DCT coeffs of MB at %dx%d:\n", s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_DEBUG, "DCT coeffs of MB at %dx%d:\n", s->c.mb_x, s->c.mb_y); for (int i = 0; i < 6; i++) { for (int j = 0; j < 64; j++) { - av_log(s->avctx, AV_LOG_DEBUG, "%5d", - block[i][s->idsp.idct_permutation[j]]); + av_log(s->c.avctx, AV_LOG_DEBUG, "%5d", + block[i][s->c.idsp.idct_permutation[j]]); } - av_log(s->avctx, AV_LOG_DEBUG, "\n"); + av_log(s->c.avctx, AV_LOG_DEBUG, "\n"); } } - mpv_reconstruct_mb_internal(s, block, 0, MAY_BE_MPEG12_H261); + if ((1 << s->c.pict_type) & s->frame_reconstruction_bitfield) { + uint8_t *dest_y = s->c.dest[0], *dest_cb = s->c.dest[1], *dest_cr = s->c.dest[2]; + int dct_linesize, dct_offset; + const int linesize = s->c.cur_pic.linesize[0]; + const int uvlinesize = s->c.cur_pic.linesize[1]; + const int block_size = 8; + + dct_linesize = linesize << s->c.interlaced_dct; + dct_offset = s->c.interlaced_dct ? linesize : linesize * block_size; + + if (!s->c.mb_intra) { + /* No MC, as that was already done otherwise */ + add_dequant_dct(s, block[0], 0, dest_y , dct_linesize, s->c.qscale); + add_dequant_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->c.qscale); + add_dequant_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->c.qscale); + add_dequant_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->c.qscale); + + if (!CONFIG_GRAY || !(s->c.avctx->flags & AV_CODEC_FLAG_GRAY)) { + if (s->c.chroma_y_shift) { + add_dequant_dct(s, block[4], 4, dest_cb, uvlinesize, s->c.chroma_qscale); + add_dequant_dct(s, block[5], 5, dest_cr, uvlinesize, s->c.chroma_qscale); + } else { + dct_linesize >>= 1; + dct_offset >>= 1; + add_dequant_dct(s, block[4], 4, dest_cb, dct_linesize, s->c.chroma_qscale); + add_dequant_dct(s, block[5], 5, dest_cr, dct_linesize, s->c.chroma_qscale); + add_dequant_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->c.chroma_qscale); + add_dequant_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->c.chroma_qscale); + } + } + } else { + /* dct only in intra block */ + put_dct(s, block[0], 0, dest_y , dct_linesize, s->c.qscale); + put_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->c.qscale); + put_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->c.qscale); + put_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->c.qscale); + + if (!CONFIG_GRAY || !(s->c.avctx->flags & AV_CODEC_FLAG_GRAY)) { + if (s->c.chroma_y_shift) { + put_dct(s, block[4], 4, dest_cb, uvlinesize, s->c.chroma_qscale); + put_dct(s, block[5], 5, dest_cr, uvlinesize, s->c.chroma_qscale); + } else { + dct_offset >>= 1; + dct_linesize >>= 1; + put_dct(s, block[4], 4, dest_cb, dct_linesize, s->c.chroma_qscale); + put_dct(s, block[5], 5, dest_cr, dct_linesize, s->c.chroma_qscale); + put_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->c.chroma_qscale); + put_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->c.chroma_qscale); + } + } + } + } } static int get_sae(const uint8_t *src, int ref, int stride) @@ -1122,14 +1223,14 @@ static int get_sae(const uint8_t *src, int ref, int stride) return acc; } -static int get_intra_count(MpegEncContext *s, const uint8_t *src, +static int get_intra_count(MPVEncContext *const s, const uint8_t *src, const uint8_t *ref, int stride) { int x, y, w, h; int acc = 0; - w = s->width & ~15; - h = s->height & ~15; + w = s->c.width & ~15; + h = s->c.height & ~15; for (y = 0; y < h; y += 16) { for (x = 0; x < w; x += 16) { @@ -1149,9 +1250,9 @@ static int get_intra_count(MpegEncContext *s, const uint8_t *src, * Allocates new buffers for an AVFrame and copies the properties * from another AVFrame. */ -static int prepare_picture(MpegEncContext *s, AVFrame *f, const AVFrame *props_frame) +static int prepare_picture(MPVEncContext *const s, AVFrame *f, const AVFrame *props_frame) { - AVCodecContext *avctx = s->avctx; + AVCodecContext *avctx = s->c.avctx; int ret; f->width = avctx->width + 2 * EDGE_WIDTH; @@ -1161,14 +1262,14 @@ static int prepare_picture(MpegEncContext *s, AVFrame *f, const AVFrame *props_f if (ret < 0) return ret; - ret = ff_mpv_pic_check_linesize(avctx, f, &s->linesize, &s->uvlinesize); + ret = ff_mpv_pic_check_linesize(avctx, f, &s->c.linesize, &s->c.uvlinesize); if (ret < 0) return ret; for (int i = 0; f->data[i]; i++) { - int offset = (EDGE_WIDTH >> (i ? s->chroma_y_shift : 0)) * + int offset = (EDGE_WIDTH >> (i ? s->c.chroma_y_shift : 0)) * f->linesize[i] + - (EDGE_WIDTH >> (i ? s->chroma_x_shift : 0)); + (EDGE_WIDTH >> (i ? s->c.chroma_x_shift : 0)); f->data[i] += offset; } f->width = avctx->width; @@ -1181,42 +1282,43 @@ static int prepare_picture(MpegEncContext *s, AVFrame *f, const AVFrame *props_f return 0; } -static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) +static int load_input_picture(MPVMainEncContext *const m, const AVFrame *pic_arg) { + MPVEncContext *const s = &m->s; MPVPicture *pic = NULL; int64_t pts; int display_picture_number = 0, ret; - int encoding_delay = s->max_b_frames ? s->max_b_frames - : (s->low_delay ? 0 : 1); + int encoding_delay = m->max_b_frames ? m->max_b_frames + : (s->c.low_delay ? 0 : 1); int flush_offset = 1; int direct = 1; - av_assert1(!s->input_picture[0]); + av_assert1(!m->input_picture[0]); if (pic_arg) { pts = pic_arg->pts; - display_picture_number = s->input_picture_number++; + display_picture_number = m->input_picture_number++; if (pts != AV_NOPTS_VALUE) { - if (s->user_specified_pts != AV_NOPTS_VALUE) { - int64_t last = s->user_specified_pts; + if (m->user_specified_pts != AV_NOPTS_VALUE) { + int64_t last = m->user_specified_pts; if (pts <= last) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(s->c.avctx, AV_LOG_ERROR, "Invalid pts (%"PRId64") <= last (%"PRId64")\n", pts, last); return AVERROR(EINVAL); } - if (!s->low_delay && display_picture_number == 1) - s->dts_delta = pts - last; + if (!s->c.low_delay && display_picture_number == 1) + m->dts_delta = pts - last; } - s->user_specified_pts = pts; + m->user_specified_pts = pts; } else { - if (s->user_specified_pts != AV_NOPTS_VALUE) { - s->user_specified_pts = - pts = s->user_specified_pts + 1; - av_log(s->avctx, AV_LOG_INFO, + if (m->user_specified_pts != AV_NOPTS_VALUE) { + m->user_specified_pts = + pts = m->user_specified_pts + 1; + av_log(s->c.avctx, AV_LOG_INFO, "Warning: AVFrame.pts=? trying to guess (%"PRId64")\n", pts); } else { @@ -1224,21 +1326,21 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) } } - if (pic_arg->linesize[0] != s->linesize || - pic_arg->linesize[1] != s->uvlinesize || - pic_arg->linesize[2] != s->uvlinesize) + if (pic_arg->linesize[0] != s->c.linesize || + pic_arg->linesize[1] != s->c.uvlinesize || + pic_arg->linesize[2] != s->c.uvlinesize) direct = 0; - if ((s->width & 15) || (s->height & 15)) + if ((s->c.width & 15) || (s->c.height & 15)) direct = 0; if (((intptr_t)(pic_arg->data[0])) & (STRIDE_ALIGN-1)) direct = 0; - if (s->linesize & (STRIDE_ALIGN-1)) + if (s->c.linesize & (STRIDE_ALIGN-1)) direct = 0; - ff_dlog(s->avctx, "%d %d %"PTRDIFF_SPECIFIER" %"PTRDIFF_SPECIFIER"\n", pic_arg->linesize[0], - pic_arg->linesize[1], s->linesize, s->uvlinesize); + ff_dlog(s->c.avctx, "%d %d %td %td\n", pic_arg->linesize[0], + pic_arg->linesize[1], s->c.linesize, s->c.uvlinesize); - pic = ff_refstruct_pool_get(s->picture_pool); + pic = av_refstruct_pool_get(s->c.picture_pool); if (!pic) return AVERROR(ENOMEM); @@ -1253,21 +1355,21 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) for (int i = 0; i < 3; i++) { ptrdiff_t src_stride = pic_arg->linesize[i]; - ptrdiff_t dst_stride = i ? s->uvlinesize : s->linesize; - int h_shift = i ? s->chroma_x_shift : 0; - int v_shift = i ? s->chroma_y_shift : 0; - int w = AV_CEIL_RSHIFT(s->width , h_shift); - int h = AV_CEIL_RSHIFT(s->height, v_shift); + ptrdiff_t dst_stride = i ? s->c.uvlinesize : s->c.linesize; + int h_shift = i ? s->c.chroma_x_shift : 0; + int v_shift = i ? s->c.chroma_y_shift : 0; + int w = AV_CEIL_RSHIFT(s->c.width , h_shift); + int h = AV_CEIL_RSHIFT(s->c.height, v_shift); const uint8_t *src = pic_arg->data[i]; uint8_t *dst = pic->f->data[i]; int vpad = 16; - if ( s->codec_id == AV_CODEC_ID_MPEG2VIDEO - && !s->progressive_sequence - && FFALIGN(s->height, 32) - s->height > 16) + if ( s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO + && !s->c.progressive_sequence + && FFALIGN(s->c.height, 32) - s->c.height > 16) vpad = 32; - if (!s->avctx->rc_buffer_size) + if (!s->c.avctx->rc_buffer_size) dst += INPLACE_OFFSET; if (src_stride == dst_stride) @@ -1281,7 +1383,7 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) src += src_stride; } } - if ((s->width & 15) || (s->height & (vpad-1))) { + if ((s->c.width & 15) || (s->c.height & (vpad-1))) { s->mpvencdsp.draw_edges(dst, dst_stride, w, h, 16 >> h_shift, @@ -1289,55 +1391,55 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) EDGE_BOTTOM); } } - emms_c(); } pic->display_picture_number = display_picture_number; pic->f->pts = pts; // we set this here to avoid modifying pic_arg - } else if (!s->reordered_input_picture[1]) { + } else if (!m->reordered_input_picture[1]) { /* Flushing: When the above check is true, the encoder is about to run * out of frames to encode. Check if there are input_pictures left; - * if so, ensure s->input_picture[0] contains the first picture. + * if so, ensure m->input_picture[0] contains the first picture. * A flush_offset != 1 will only happen if we did not receive enough * input frames. */ for (flush_offset = 0; flush_offset < encoding_delay + 1; flush_offset++) - if (s->input_picture[flush_offset]) + if (m->input_picture[flush_offset]) break; encoding_delay -= flush_offset - 1; } /* shift buffer entries */ - for (int i = flush_offset; i <= MAX_B_FRAMES; i++) - s->input_picture[i - flush_offset] = s->input_picture[i]; - for (int i = MAX_B_FRAMES + 1 - flush_offset; i <= MAX_B_FRAMES; i++) - s->input_picture[i] = NULL; + for (int i = flush_offset; i <= MPVENC_MAX_B_FRAMES; i++) + m->input_picture[i - flush_offset] = m->input_picture[i]; + for (int i = MPVENC_MAX_B_FRAMES + 1 - flush_offset; i <= MPVENC_MAX_B_FRAMES; i++) + m->input_picture[i] = NULL; - s->input_picture[encoding_delay] = pic; + m->input_picture[encoding_delay] = pic; return 0; fail: - ff_refstruct_unref(&pic); + av_refstruct_unref(&pic); return ret; } -static int skip_check(MpegEncContext *s, const MPVPicture *p, const MPVPicture *ref) +static int skip_check(MPVMainEncContext *const m, + const MPVPicture *p, const MPVPicture *ref) { - int x, y, plane; + MPVEncContext *const s = &m->s; int score = 0; int64_t score64 = 0; - for (plane = 0; plane < 3; plane++) { + for (int plane = 0; plane < 3; plane++) { const int stride = p->f->linesize[plane]; const int bw = plane ? 1 : 2; - for (y = 0; y < s->mb_height * bw; y++) { - for (x = 0; x < s->mb_width * bw; x++) { + for (int y = 0; y < s->c.mb_height * bw; y++) { + for (int x = 0; x < s->c.mb_width * bw; x++) { int off = p->shared ? 0 : 16; const uint8_t *dptr = p->f->data[plane] + 8 * (x + y * stride) + off; const uint8_t *rptr = ref->f->data[plane] + 8 * (x + y * stride); - int v = s->frame_skip_cmp_fn(s, dptr, rptr, stride, 8); + int v = m->frame_skip_cmp_fn(s, dptr, rptr, stride, 8); - switch (FFABS(s->frame_skip_exp)) { + switch (FFABS(m->frame_skip_exp)) { case 0: score = FFMAX(score, v); break; case 1: score += FFABS(v); break; case 2: score64 += v * (int64_t)v; break; @@ -1351,13 +1453,13 @@ static int skip_check(MpegEncContext *s, const MPVPicture *p, const MPVPicture * if (score) score64 = score; - if (s->frame_skip_exp < 0) - score64 = pow(score64 / (double)(s->mb_width * s->mb_height), - -1.0/s->frame_skip_exp); + if (m->frame_skip_exp < 0) + score64 = pow(score64 / (double)(s->c.mb_width * s->c.mb_height), + -1.0/m->frame_skip_exp); - if (score64 < s->frame_skip_threshold) + if (score64 < m->frame_skip_threshold) return 1; - if (score64 < ((s->frame_skip_factor * (int64_t) s->lambda) >> 8)) + if (score64 < ((m->frame_skip_factor * (int64_t) s->lambda) >> 8)) return 1; return 0; } @@ -1383,13 +1485,14 @@ static int encode_frame(AVCodecContext *c, const AVFrame *frame, AVPacket *pkt) return size; } -static int estimate_best_b_count(MpegEncContext *s) +static int estimate_best_b_count(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; AVPacket *pkt; - const int scale = s->brd_scale; - int width = s->width >> scale; - int height = s->height >> scale; - int i, j, out_size, p_lambda, b_lambda, lambda2; + const int scale = m->brd_scale; + int width = s->c.width >> scale; + int height = s->c.height >> scale; + int out_size, p_lambda, b_lambda, lambda2; int64_t best_rd = INT64_MAX; int best_b_count = -1; int ret = 0; @@ -1400,18 +1503,17 @@ static int estimate_best_b_count(MpegEncContext *s) if (!pkt) return AVERROR(ENOMEM); - //emms_c(); - p_lambda = s->last_lambda_for[AV_PICTURE_TYPE_P]; - //p_lambda * FFABS(s->avctx->b_quant_factor) + s->avctx->b_quant_offset; - b_lambda = s->last_lambda_for[AV_PICTURE_TYPE_B]; + p_lambda = m->last_lambda_for[AV_PICTURE_TYPE_P]; + //p_lambda * FFABS(s->c.avctx->b_quant_factor) + s->c.avctx->b_quant_offset; + b_lambda = m->last_lambda_for[AV_PICTURE_TYPE_B]; if (!b_lambda) // FIXME we should do this somewhere else b_lambda = p_lambda; lambda2 = (b_lambda * b_lambda + (1 << FF_LAMBDA_SHIFT) / 2) >> FF_LAMBDA_SHIFT; - for (i = 0; i < s->max_b_frames + 2; i++) { - const MPVPicture *pre_input_ptr = i ? s->input_picture[i - 1] : - s->next_pic.ptr; + for (int i = 0; i < m->max_b_frames + 2; i++) { + const MPVPicture *pre_input_ptr = i ? m->input_picture[i - 1] : + s->c.next_pic.ptr; if (pre_input_ptr) { const uint8_t *data[4]; @@ -1423,29 +1525,29 @@ static int estimate_best_b_count(MpegEncContext *s) data[2] += INPLACE_OFFSET; } - s->mpvencdsp.shrink[scale](s->tmp_frames[i]->data[0], - s->tmp_frames[i]->linesize[0], + s->mpvencdsp.shrink[scale](m->tmp_frames[i]->data[0], + m->tmp_frames[i]->linesize[0], data[0], pre_input_ptr->f->linesize[0], width, height); - s->mpvencdsp.shrink[scale](s->tmp_frames[i]->data[1], - s->tmp_frames[i]->linesize[1], + s->mpvencdsp.shrink[scale](m->tmp_frames[i]->data[1], + m->tmp_frames[i]->linesize[1], data[1], pre_input_ptr->f->linesize[1], width >> 1, height >> 1); - s->mpvencdsp.shrink[scale](s->tmp_frames[i]->data[2], - s->tmp_frames[i]->linesize[2], + s->mpvencdsp.shrink[scale](m->tmp_frames[i]->data[2], + m->tmp_frames[i]->linesize[2], data[2], pre_input_ptr->f->linesize[2], width >> 1, height >> 1); } } - for (j = 0; j < s->max_b_frames + 1; j++) { + for (int j = 0; j < m->max_b_frames + 1; j++) { AVCodecContext *c; int64_t rd = 0; - if (!s->input_picture[j]) + if (!m->input_picture[j]) break; c = avcodec_alloc_context3(NULL); @@ -1457,24 +1559,24 @@ static int estimate_best_b_count(MpegEncContext *s) c->width = width; c->height = height; c->flags = AV_CODEC_FLAG_QSCALE | AV_CODEC_FLAG_PSNR; - c->flags |= s->avctx->flags & AV_CODEC_FLAG_QPEL; - c->mb_decision = s->avctx->mb_decision; - c->me_cmp = s->avctx->me_cmp; - c->mb_cmp = s->avctx->mb_cmp; - c->me_sub_cmp = s->avctx->me_sub_cmp; + c->flags |= s->c.avctx->flags & AV_CODEC_FLAG_QPEL; + c->mb_decision = s->c.avctx->mb_decision; + c->me_cmp = s->c.avctx->me_cmp; + c->mb_cmp = s->c.avctx->mb_cmp; + c->me_sub_cmp = s->c.avctx->me_sub_cmp; c->pix_fmt = AV_PIX_FMT_YUV420P; - c->time_base = s->avctx->time_base; - c->max_b_frames = s->max_b_frames; + c->time_base = s->c.avctx->time_base; + c->max_b_frames = m->max_b_frames; - ret = avcodec_open2(c, s->avctx->codec, NULL); + ret = avcodec_open2(c, s->c.avctx->codec, NULL); if (ret < 0) goto fail; - s->tmp_frames[0]->pict_type = AV_PICTURE_TYPE_I; - s->tmp_frames[0]->quality = 1 * FF_QP2LAMBDA; + m->tmp_frames[0]->pict_type = AV_PICTURE_TYPE_I; + m->tmp_frames[0]->quality = 1 * FF_QP2LAMBDA; - out_size = encode_frame(c, s->tmp_frames[0], pkt); + out_size = encode_frame(c, m->tmp_frames[0], pkt); if (out_size < 0) { ret = out_size; goto fail; @@ -1482,14 +1584,14 @@ static int estimate_best_b_count(MpegEncContext *s) //rd += (out_size * lambda2) >> FF_LAMBDA_SHIFT; - for (i = 0; i < s->max_b_frames + 1; i++) { - int is_p = i % (j + 1) == j || i == s->max_b_frames; + for (int i = 0; i < m->max_b_frames + 1; i++) { + int is_p = i % (j + 1) == j || i == m->max_b_frames; - s->tmp_frames[i + 1]->pict_type = is_p ? + m->tmp_frames[i + 1]->pict_type = is_p ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_B; - s->tmp_frames[i + 1]->quality = is_p ? p_lambda : b_lambda; + m->tmp_frames[i + 1]->quality = is_p ? p_lambda : b_lambda; - out_size = encode_frame(c, s->tmp_frames[i + 1], pkt); + out_size = encode_frame(c, m->tmp_frames[i + 1], pkt); if (out_size < 0) { ret = out_size; goto fail; @@ -1535,233 +1637,232 @@ fail: * input_picture[0] is always NULL when exiting this function, even on error; * reordered_input_picture[0] is always NULL when exiting this function on error. */ -static int set_bframe_chain_length(MpegEncContext *s) +static int set_bframe_chain_length(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; + /* Either nothing to do or can't do anything */ - if (s->reordered_input_picture[0] || !s->input_picture[0]) + if (m->reordered_input_picture[0] || !m->input_picture[0]) return 0; /* set next picture type & ordering */ - if (s->frame_skip_threshold || s->frame_skip_factor) { - if (s->picture_in_gop_number < s->gop_size && - s->next_pic.ptr && - skip_check(s, s->input_picture[0], s->next_pic.ptr)) { + if (m->frame_skip_threshold || m->frame_skip_factor) { + if (m->picture_in_gop_number < m->gop_size && + s->c.next_pic.ptr && + skip_check(m, m->input_picture[0], s->c.next_pic.ptr)) { // FIXME check that the gop check above is +-1 correct - ff_refstruct_unref(&s->input_picture[0]); + av_refstruct_unref(&m->input_picture[0]); - ff_vbv_update(s, 0); + ff_vbv_update(m, 0); return 0; } } - if (/*s->picture_in_gop_number >= s->gop_size ||*/ - !s->next_pic.ptr || s->intra_only) { - s->reordered_input_picture[0] = s->input_picture[0]; - s->input_picture[0] = NULL; - s->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_I; - s->reordered_input_picture[0]->coded_picture_number = - s->coded_picture_number++; + if (/* m->picture_in_gop_number >= m->gop_size || */ + !s->c.next_pic.ptr || m->intra_only) { + m->reordered_input_picture[0] = m->input_picture[0]; + m->input_picture[0] = NULL; + m->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_I; + m->reordered_input_picture[0]->coded_picture_number = + m->coded_picture_number++; } else { int b_frames = 0; - if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { - for (int i = 0; i < s->max_b_frames + 1; i++) { - int pict_num = s->input_picture[0]->display_picture_number + i; + if (s->c.avctx->flags & AV_CODEC_FLAG_PASS2) { + for (int i = 0; i < m->max_b_frames + 1; i++) { + int pict_num = m->input_picture[0]->display_picture_number + i; - if (pict_num >= s->rc_context.num_entries) + if (pict_num >= m->rc_context.num_entries) break; - if (!s->input_picture[i]) { - s->rc_context.entry[pict_num - 1].new_pict_type = AV_PICTURE_TYPE_P; + if (!m->input_picture[i]) { + m->rc_context.entry[pict_num - 1].new_pict_type = AV_PICTURE_TYPE_P; break; } - s->input_picture[i]->f->pict_type = - s->rc_context.entry[pict_num].new_pict_type; + m->input_picture[i]->f->pict_type = + m->rc_context.entry[pict_num].new_pict_type; } } - if (s->b_frame_strategy == 0) { - b_frames = s->max_b_frames; - while (b_frames && !s->input_picture[b_frames]) + if (m->b_frame_strategy == 0) { + b_frames = m->max_b_frames; + while (b_frames && !m->input_picture[b_frames]) b_frames--; - } else if (s->b_frame_strategy == 1) { - int i; - for (i = 1; i < s->max_b_frames + 1; i++) { - if (s->input_picture[i] && - s->input_picture[i]->b_frame_score == 0) { - s->input_picture[i]->b_frame_score = + } else if (m->b_frame_strategy == 1) { + for (int i = 1; i < m->max_b_frames + 1; i++) { + if (m->input_picture[i] && + m->input_picture[i]->b_frame_score == 0) { + m->input_picture[i]->b_frame_score = get_intra_count(s, - s->input_picture[i ]->f->data[0], - s->input_picture[i - 1]->f->data[0], - s->linesize) + 1; + m->input_picture[i ]->f->data[0], + m->input_picture[i - 1]->f->data[0], + s->c.linesize) + 1; } } - for (i = 0; i < s->max_b_frames + 1; i++) { - if (!s->input_picture[i] || - s->input_picture[i]->b_frame_score - 1 > - s->mb_num / s->b_sensitivity) + for (int i = 0;; i++) { + if (i >= m->max_b_frames + 1 || + !m->input_picture[i] || + m->input_picture[i]->b_frame_score - 1 > + s->c.mb_num / m->b_sensitivity) { + b_frames = FFMAX(0, i - 1); break; + } } - b_frames = FFMAX(0, i - 1); - /* reset scores */ - for (i = 0; i < b_frames + 1; i++) { - s->input_picture[i]->b_frame_score = 0; - } - } else if (s->b_frame_strategy == 2) { - b_frames = estimate_best_b_count(s); + for (int i = 0; i < b_frames + 1; i++) + m->input_picture[i]->b_frame_score = 0; + } else if (m->b_frame_strategy == 2) { + b_frames = estimate_best_b_count(m); if (b_frames < 0) { - ff_refstruct_unref(&s->input_picture[0]); + av_refstruct_unref(&m->input_picture[0]); return b_frames; } } - emms_c(); - for (int i = b_frames - 1; i >= 0; i--) { - int type = s->input_picture[i]->f->pict_type; + int type = m->input_picture[i]->f->pict_type; if (type && type != AV_PICTURE_TYPE_B) b_frames = i; } - if (s->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_B && - b_frames == s->max_b_frames) { - av_log(s->avctx, AV_LOG_ERROR, + if (m->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_B && + b_frames == m->max_b_frames) { + av_log(s->c.avctx, AV_LOG_ERROR, "warning, too many B-frames in a row\n"); } - if (s->picture_in_gop_number + b_frames >= s->gop_size) { + if (m->picture_in_gop_number + b_frames >= m->gop_size) { if ((s->mpv_flags & FF_MPV_FLAG_STRICT_GOP) && - s->gop_size > s->picture_in_gop_number) { - b_frames = s->gop_size - s->picture_in_gop_number - 1; + m->gop_size > m->picture_in_gop_number) { + b_frames = m->gop_size - m->picture_in_gop_number - 1; } else { - if (s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) + if (s->c.avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) b_frames = 0; - s->input_picture[b_frames]->f->pict_type = AV_PICTURE_TYPE_I; + m->input_picture[b_frames]->f->pict_type = AV_PICTURE_TYPE_I; } } - if ((s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) && b_frames && - s->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_I) + if ((s->c.avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) && b_frames && + m->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_I) b_frames--; - s->reordered_input_picture[0] = s->input_picture[b_frames]; - s->input_picture[b_frames] = NULL; - if (s->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_I) - s->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_P; - s->reordered_input_picture[0]->coded_picture_number = - s->coded_picture_number++; + m->reordered_input_picture[0] = m->input_picture[b_frames]; + m->input_picture[b_frames] = NULL; + if (m->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_I) + m->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_P; + m->reordered_input_picture[0]->coded_picture_number = + m->coded_picture_number++; for (int i = 0; i < b_frames; i++) { - s->reordered_input_picture[i + 1] = s->input_picture[i]; - s->input_picture[i] = NULL; - s->reordered_input_picture[i + 1]->f->pict_type = + m->reordered_input_picture[i + 1] = m->input_picture[i]; + m->input_picture[i] = NULL; + m->reordered_input_picture[i + 1]->f->pict_type = AV_PICTURE_TYPE_B; - s->reordered_input_picture[i + 1]->coded_picture_number = - s->coded_picture_number++; + m->reordered_input_picture[i + 1]->coded_picture_number = + m->coded_picture_number++; } } return 0; } -static int select_input_picture(MpegEncContext *s) +static int select_input_picture(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int ret; - av_assert1(!s->reordered_input_picture[0]); + av_assert1(!m->reordered_input_picture[0]); - for (int i = 1; i <= MAX_B_FRAMES; i++) - s->reordered_input_picture[i - 1] = s->reordered_input_picture[i]; - s->reordered_input_picture[MAX_B_FRAMES] = NULL; + for (int i = 1; i <= MPVENC_MAX_B_FRAMES; i++) + m->reordered_input_picture[i - 1] = m->reordered_input_picture[i]; + m->reordered_input_picture[MPVENC_MAX_B_FRAMES] = NULL; - ret = set_bframe_chain_length(s); - av_assert1(!s->input_picture[0]); + ret = set_bframe_chain_length(m); + av_assert1(!m->input_picture[0]); if (ret < 0) return ret; av_frame_unref(s->new_pic); - if (s->reordered_input_picture[0]) { - s->reordered_input_picture[0]->reference = - s->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_B; + if (m->reordered_input_picture[0]) { + m->reordered_input_picture[0]->reference = + m->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_B; - if (s->reordered_input_picture[0]->shared || s->avctx->rc_buffer_size) { + if (m->reordered_input_picture[0]->shared || s->c.avctx->rc_buffer_size) { // input is a shared pix, so we can't modify it -> allocate a new - // one & ensure that the shared one is reuseable - av_frame_move_ref(s->new_pic, s->reordered_input_picture[0]->f); + // one & ensure that the shared one is reusable + av_frame_move_ref(s->new_pic, m->reordered_input_picture[0]->f); - ret = prepare_picture(s, s->reordered_input_picture[0]->f, s->new_pic); + ret = prepare_picture(s, m->reordered_input_picture[0]->f, s->new_pic); if (ret < 0) goto fail; } else { // input is not a shared pix -> reuse buffer for current_pix - ret = av_frame_ref(s->new_pic, s->reordered_input_picture[0]->f); + ret = av_frame_ref(s->new_pic, m->reordered_input_picture[0]->f); if (ret < 0) goto fail; - for (int i = 0; i < MPV_MAX_PLANES; i++) { - if (s->new_pic->data[i]) - s->new_pic->data[i] += INPLACE_OFFSET; - } + for (int i = 0; i < MPV_MAX_PLANES; i++) + s->new_pic->data[i] += INPLACE_OFFSET; } - s->cur_pic.ptr = s->reordered_input_picture[0]; - s->reordered_input_picture[0] = NULL; - av_assert1(s->mb_width == s->buffer_pools.alloc_mb_width); - av_assert1(s->mb_height == s->buffer_pools.alloc_mb_height); - av_assert1(s->mb_stride == s->buffer_pools.alloc_mb_stride); - ret = ff_mpv_alloc_pic_accessories(s->avctx, &s->cur_pic, - &s->sc, &s->buffer_pools, s->mb_height); + s->c.cur_pic.ptr = m->reordered_input_picture[0]; + m->reordered_input_picture[0] = NULL; + av_assert1(s->c.mb_width == s->c.buffer_pools.alloc_mb_width); + av_assert1(s->c.mb_height == s->c.buffer_pools.alloc_mb_height); + av_assert1(s->c.mb_stride == s->c.buffer_pools.alloc_mb_stride); + ret = ff_mpv_alloc_pic_accessories(s->c.avctx, &s->c.cur_pic, + &s->c.sc, &s->c.buffer_pools, s->c.mb_height); if (ret < 0) { - ff_mpv_unref_picture(&s->cur_pic); + ff_mpv_unref_picture(&s->c.cur_pic); return ret; } - s->picture_number = s->cur_pic.ptr->display_picture_number; + s->picture_number = s->c.cur_pic.ptr->display_picture_number; } return 0; fail: - ff_refstruct_unref(&s->reordered_input_picture[0]); + av_refstruct_unref(&m->reordered_input_picture[0]); return ret; } -static void frame_end(MpegEncContext *s) +static void frame_end(MPVMainEncContext *const m) { - if (s->unrestricted_mv && - s->cur_pic.reference && - !s->intra_only) { - int hshift = s->chroma_x_shift; - int vshift = s->chroma_y_shift; - s->mpvencdsp.draw_edges(s->cur_pic.data[0], - s->cur_pic.linesize[0], - s->h_edge_pos, s->v_edge_pos, + MPVEncContext *const s = &m->s; + + if (s->me.unrestricted_mv && + s->c.cur_pic.reference && + !m->intra_only) { + int hshift = s->c.chroma_x_shift; + int vshift = s->c.chroma_y_shift; + s->mpvencdsp.draw_edges(s->c.cur_pic.data[0], + s->c.cur_pic.linesize[0], + s->c.h_edge_pos, s->c.v_edge_pos, EDGE_WIDTH, EDGE_WIDTH, EDGE_TOP | EDGE_BOTTOM); - s->mpvencdsp.draw_edges(s->cur_pic.data[1], - s->cur_pic.linesize[1], - s->h_edge_pos >> hshift, - s->v_edge_pos >> vshift, + s->mpvencdsp.draw_edges(s->c.cur_pic.data[1], + s->c.cur_pic.linesize[1], + s->c.h_edge_pos >> hshift, + s->c.v_edge_pos >> vshift, EDGE_WIDTH >> hshift, EDGE_WIDTH >> vshift, EDGE_TOP | EDGE_BOTTOM); - s->mpvencdsp.draw_edges(s->cur_pic.data[2], - s->cur_pic.linesize[2], - s->h_edge_pos >> hshift, - s->v_edge_pos >> vshift, + s->mpvencdsp.draw_edges(s->c.cur_pic.data[2], + s->c.cur_pic.linesize[2], + s->c.h_edge_pos >> hshift, + s->c.v_edge_pos >> vshift, EDGE_WIDTH >> hshift, EDGE_WIDTH >> vshift, EDGE_TOP | EDGE_BOTTOM); } - emms_c(); - - s->last_pict_type = s->pict_type; - s->last_lambda_for [s->pict_type] = s->cur_pic.ptr->f->quality; - if (s->pict_type!= AV_PICTURE_TYPE_B) - s->last_non_b_pict_type = s->pict_type; + m->last_pict_type = s->c.pict_type; + m->last_lambda_for[s->c.pict_type] = s->c.cur_pic.ptr->f->quality; + if (s->c.pict_type != AV_PICTURE_TYPE_B) + m->last_non_b_pict_type = s->c.pict_type; } -static void update_noise_reduction(MpegEncContext *s) +static void update_noise_reduction(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int intra, i; for (intra = 0; intra < 2; intra++) { @@ -1773,7 +1874,7 @@ static void update_noise_reduction(MpegEncContext *s) } for (i = 0; i < 64; i++) { - s->dct_offset[intra][i] = (s->noise_reduction * + s->dct_offset[intra][i] = (m->noise_reduction * s->dct_count[intra] + s->dct_error_sum[intra][i] / 2) / (s->dct_error_sum[intra][i] + 1); @@ -1781,45 +1882,49 @@ static void update_noise_reduction(MpegEncContext *s) } } -static void frame_start(MpegEncContext *s) +static void frame_start(MPVMainEncContext *const m) { - s->cur_pic.ptr->f->pict_type = s->pict_type; + MPVEncContext *const s = &m->s; - if (s->pict_type != AV_PICTURE_TYPE_B) { - ff_mpv_replace_picture(&s->last_pic, &s->next_pic); - ff_mpv_replace_picture(&s->next_pic, &s->cur_pic); + s->c.cur_pic.ptr->f->pict_type = s->c.pict_type; + + if (s->c.pict_type != AV_PICTURE_TYPE_B) { + ff_mpv_replace_picture(&s->c.last_pic, &s->c.next_pic); + ff_mpv_replace_picture(&s->c.next_pic, &s->c.cur_pic); } + av_assert2(!!m->noise_reduction == !!s->dct_error_sum); if (s->dct_error_sum) { - av_assert2(s->noise_reduction && s->encoding); - update_noise_reduction(s); + update_noise_reduction(m); } } int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pic_arg, int *got_packet) { - MpegEncContext *s = avctx->priv_data; + MPVMainEncContext *const m = avctx->priv_data; + MPVEncContext *const s = &m->s; int stuffing_count, ret; - int context_count = s->slice_context_count; + int context_count = s->c.slice_context_count; - ff_mpv_unref_picture(&s->cur_pic); + ff_mpv_unref_picture(&s->c.cur_pic); - s->vbv_ignore_qmax = 0; + m->vbv_ignore_qmax = 0; - s->picture_in_gop_number++; + m->picture_in_gop_number++; - if (load_input_picture(s, pic_arg) < 0) - return -1; + ret = load_input_picture(m, pic_arg); + if (ret < 0) + return ret; - if (select_input_picture(s) < 0) { - return -1; - } + ret = select_input_picture(m); + if (ret < 0) + return ret; /* output? */ if (s->new_pic->data[0]) { int growing_buffer = context_count == 1 && !s->data_partitioning; - size_t pkt_size = 10000 + s->mb_width * s->mb_height * + size_t pkt_size = 10000 + s->c.mb_width * s->c.mb_height * (growing_buffer ? 64 : (MAX_MB_BYTES + 100)); if (CONFIG_MJPEG_ENCODER && avctx->codec_id == AV_CODEC_ID_MJPEG) { ret = ff_mjpeg_add_icc_profile_size(avctx, s->new_pic, &pkt_size); @@ -1832,17 +1937,16 @@ int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, if (s->mb_info) { s->mb_info_ptr = av_packet_new_side_data(pkt, AV_PKT_DATA_H263_MB_INFO, - s->mb_width*s->mb_height*12); + s->c.mb_width*s->c.mb_height*12); if (!s->mb_info_ptr) return AVERROR(ENOMEM); s->prev_mb_info = s->last_mb_info = s->mb_info_size = 0; } - s->pict_type = s->new_pic->pict_type; - //emms_c(); - frame_start(s); + s->c.pict_type = s->new_pic->pict_type; + frame_start(m); vbv_retry: - ret = encode_picture(s, pkt); + ret = encode_picture(m, pkt); if (growing_buffer) { av_assert0(s->pb.buf == avctx->internal->byte_buffer); pkt->data = s->pb.buf; @@ -1851,39 +1955,38 @@ vbv_retry: if (ret < 0) return -1; - frame_end(s); + frame_end(m); - if ((CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER) && s->out_format == FMT_MJPEG) - ff_mjpeg_encode_picture_trailer(&s->pb, s->header_bits); + if ((CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER) && s->c.out_format == FMT_MJPEG) + ff_mjpeg_encode_picture_trailer(&s->pb, m->header_bits); if (avctx->rc_buffer_size) { - RateControlContext *rcc = &s->rc_context; + RateControlContext *rcc = &m->rc_context; int max_size = FFMAX(rcc->buffer_index * avctx->rc_max_available_vbv_use, rcc->buffer_index - 500); int hq = (avctx->mb_decision == FF_MB_DECISION_RD || avctx->trellis); int min_step = hq ? 1 : (1<<(FF_LAMBDA_SHIFT + 7))/139; if (put_bits_count(&s->pb) > max_size && - s->lambda < s->lmax) { - s->next_lambda = FFMAX(s->lambda + min_step, s->lambda * - (s->qscale + 1) / s->qscale); + s->lambda < m->lmax) { + m->next_lambda = FFMAX(s->lambda + min_step, s->lambda * + (s->c.qscale + 1) / s->c.qscale); if (s->adaptive_quant) { - int i; - for (i = 0; i < s->mb_height * s->mb_stride; i++) + for (int i = 0; i < s->c.mb_height * s->c.mb_stride; i++) s->lambda_table[i] = FFMAX(s->lambda_table[i] + min_step, - s->lambda_table[i] * (s->qscale + 1) / - s->qscale); + s->lambda_table[i] * (s->c.qscale + 1) / + s->c.qscale); } - s->mb_skipped = 0; // done in frame_start() + s->c.mb_skipped = 0; // done in frame_start() // done in encode_picture() so we must undo it - if (s->pict_type == AV_PICTURE_TYPE_P) { - s->no_rounding ^= s->flipflop_rounding; + if (s->c.pict_type == AV_PICTURE_TYPE_P) { + s->c.no_rounding ^= s->flipflop_rounding; } - if (s->pict_type != AV_PICTURE_TYPE_B) { - s->time_base = s->last_time_base; - s->last_non_b_time = s->time - s->pp_time; + if (s->c.pict_type != AV_PICTURE_TYPE_B) { + s->c.time_base = s->c.last_time_base; + s->c.last_non_b_time = s->c.time - s->c.pp_time; } - s->vbv_ignore_qmax = 1; + m->vbv_ignore_qmax = 1; av_log(avctx, AV_LOG_VERBOSE, "reencoding frame due to VBV\n"); goto vbv_retry; } @@ -1892,31 +1995,31 @@ vbv_retry: } if (avctx->flags & AV_CODEC_FLAG_PASS1) - ff_write_pass1_stats(s); + ff_write_pass1_stats(m); for (int i = 0; i < MPV_MAX_PLANES; i++) avctx->error[i] += s->encoding_error[i]; - ff_side_data_set_encoder_stats(pkt, s->cur_pic.ptr->f->quality, - s->encoding_error, - (avctx->flags&AV_CODEC_FLAG_PSNR) ? MPV_MAX_PLANES : 0, - s->pict_type); + ff_encode_add_stats_side_data(pkt, s->c.cur_pic.ptr->f->quality, + s->encoding_error, + (avctx->flags&AV_CODEC_FLAG_PSNR) ? MPV_MAX_PLANES : 0, + s->c.pict_type); if (avctx->flags & AV_CODEC_FLAG_PASS1) - assert(put_bits_count(&s->pb) == s->header_bits + s->mv_bits + + assert(put_bits_count(&s->pb) == m->header_bits + s->mv_bits + s->misc_bits + s->i_tex_bits + s->p_tex_bits); flush_put_bits(&s->pb); - s->frame_bits = put_bits_count(&s->pb); + m->frame_bits = put_bits_count(&s->pb); - stuffing_count = ff_vbv_update(s, s->frame_bits); - s->stuffing_bits = 8*stuffing_count; + stuffing_count = ff_vbv_update(m, m->frame_bits); + m->stuffing_bits = 8*stuffing_count; if (stuffing_count) { if (put_bytes_left(&s->pb, 0) < stuffing_count + 50) { av_log(avctx, AV_LOG_ERROR, "stuffing too large\n"); return -1; } - switch (s->codec_id) { + switch (s->c.codec_id) { case AV_CODEC_ID_MPEG1VIDEO: case AV_CODEC_ID_MPEG2VIDEO: while (stuffing_count--) { @@ -1933,16 +2036,16 @@ vbv_retry: break; default: av_log(avctx, AV_LOG_ERROR, "vbv buffer overflow\n"); - s->stuffing_bits = 0; + m->stuffing_bits = 0; } flush_put_bits(&s->pb); - s->frame_bits = put_bits_count(&s->pb); + m->frame_bits = put_bits_count(&s->pb); } /* update MPEG-1/2 vbv_delay for CBR */ if (avctx->rc_max_rate && avctx->rc_min_rate == avctx->rc_max_rate && - s->out_format == FMT_MPEG1 && + s->c.out_format == FMT_MPEG1 && 90000LL * (avctx->rc_buffer_size - 1) <= avctx->rc_max_rate * 0xFFFFLL) { AVCPBProperties *props; @@ -1951,16 +2054,16 @@ vbv_retry: int vbv_delay, min_delay; double inbits = avctx->rc_max_rate * av_q2d(avctx->time_base); - int minbits = s->frame_bits - 8 * - (s->vbv_delay_pos - 1); - double bits = s->rc_context.buffer_index + minbits - inbits; - uint8_t *const vbv_delay_ptr = s->pb.buf + s->vbv_delay_pos; + int minbits = m->frame_bits - 8 * + (m->vbv_delay_pos - 1); + double bits = m->rc_context.buffer_index + minbits - inbits; + uint8_t *const vbv_delay_ptr = s->pb.buf + m->vbv_delay_pos; if (bits < 0) av_log(avctx, AV_LOG_ERROR, "Internal error, negative bits\n"); - av_assert1(s->repeat_first_field == 0); + av_assert1(s->c.repeat_first_field == 0); vbv_delay = bits * 90000 / avctx->rc_max_rate; min_delay = (minbits * 90000LL + avctx->rc_max_rate - 1) / @@ -1988,44 +2091,44 @@ vbv_retry: return ret; } } - s->total_bits += s->frame_bits; + m->total_bits += m->frame_bits; - pkt->pts = s->cur_pic.ptr->f->pts; - pkt->duration = s->cur_pic.ptr->f->duration; - if (!s->low_delay && s->pict_type != AV_PICTURE_TYPE_B) { - if (!s->cur_pic.ptr->coded_picture_number) - pkt->dts = pkt->pts - s->dts_delta; + pkt->pts = s->c.cur_pic.ptr->f->pts; + pkt->duration = s->c.cur_pic.ptr->f->duration; + if (!s->c.low_delay && s->c.pict_type != AV_PICTURE_TYPE_B) { + if (!s->c.cur_pic.ptr->coded_picture_number) + pkt->dts = pkt->pts - m->dts_delta; else - pkt->dts = s->reordered_pts; - s->reordered_pts = pkt->pts; + pkt->dts = m->reordered_pts; + m->reordered_pts = pkt->pts; } else pkt->dts = pkt->pts; // the no-delay case is handled in generic code if (avctx->codec->capabilities & AV_CODEC_CAP_DELAY) { - ret = ff_encode_reordered_opaque(avctx, pkt, s->cur_pic.ptr->f); + ret = ff_encode_reordered_opaque(avctx, pkt, s->c.cur_pic.ptr->f); if (ret < 0) return ret; } - if (s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY) + if (s->c.cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY) pkt->flags |= AV_PKT_FLAG_KEY; if (s->mb_info) av_packet_shrink_side_data(pkt, AV_PKT_DATA_H263_MB_INFO, s->mb_info_size); } else { - s->frame_bits = 0; + m->frame_bits = 0; } - ff_mpv_unref_picture(&s->cur_pic); + ff_mpv_unref_picture(&s->c.cur_pic); - av_assert1((s->frame_bits & 7) == 0); + av_assert1((m->frame_bits & 7) == 0); - pkt->size = s->frame_bits / 8; + pkt->size = m->frame_bits / 8; *got_packet = !!pkt->size; return 0; } -static inline void dct_single_coeff_elimination(MpegEncContext *s, +static inline void dct_single_coeff_elimination(MPVEncContext *const s, int n, int threshold) { static const char tab[64] = { @@ -2042,7 +2145,7 @@ static inline void dct_single_coeff_elimination(MpegEncContext *s, int run = 0; int i; int16_t *block = s->block[n]; - const int last_index = s->block_last_index[n]; + const int last_index = s->c.block_last_index[n]; int skip_dc; if (threshold < 0) { @@ -2056,7 +2159,7 @@ static inline void dct_single_coeff_elimination(MpegEncContext *s, return; for (i = 0; i <= last_index; i++) { - const int j = s->intra_scantable.permutated[i]; + const int j = s->c.intra_scantable.permutated[i]; const int level = FFABS(block[j]); if (level == 1) { if (skip_dc && i == 0) @@ -2072,16 +2175,16 @@ static inline void dct_single_coeff_elimination(MpegEncContext *s, if (score >= threshold) return; for (i = skip_dc; i <= last_index; i++) { - const int j = s->intra_scantable.permutated[i]; + const int j = s->c.intra_scantable.permutated[i]; block[j] = 0; } if (block[0]) - s->block_last_index[n] = 0; + s->c.block_last_index[n] = 0; else - s->block_last_index[n] = -1; + s->c.block_last_index[n] = -1; } -static inline void clip_coeffs(MpegEncContext *s, int16_t *block, +static inline void clip_coeffs(const MPVEncContext *const s, int16_t block[], int last_index) { int i; @@ -2089,13 +2192,13 @@ static inline void clip_coeffs(MpegEncContext *s, int16_t *block, const int minlevel = s->min_qcoeff; int overflow = 0; - if (s->mb_intra) { + if (s->c.mb_intra) { i = 1; // skip clipping of intra dc } else i = 0; for (; i <= last_index; i++) { - const int j = s->intra_scantable.permutated[i]; + const int j = s->c.intra_scantable.permutated[i]; int level = block[j]; if (level > maxlevel) { @@ -2109,8 +2212,8 @@ static inline void clip_coeffs(MpegEncContext *s, int16_t *block, block[j] = level; } - if (overflow && s->avctx->mb_decision == FF_MB_DECISION_SIMPLE) - av_log(s->avctx, AV_LOG_INFO, + if (overflow && s->c.avctx->mb_decision == FF_MB_DECISION_SIMPLE) + av_log(s->c.avctx, AV_LOG_INFO, "warning, clipping %d dct coefficients to %d..%d\n", overflow, minlevel, maxlevel); } @@ -2139,7 +2242,7 @@ static void get_visual_weight(int16_t *weight, const uint8_t *ptr, int stride) } } -static av_always_inline void encode_mb_internal(MpegEncContext *s, +static av_always_inline void encode_mb_internal(MPVEncContext *const s, int motion_x, int motion_y, int mb_block_height, int mb_block_width, @@ -2151,15 +2254,15 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, /* Interlaced DCT is only possible with MPEG-2 and MPEG-4 * and neither of these encoders currently supports 444. */ #define INTERLACED_DCT(s) ((chroma_format == CHROMA_420 || chroma_format == CHROMA_422) && \ - (s)->avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) - int16_t weight[12][64]; + (s)->c.avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) + DECLARE_ALIGNED(16, int16_t, weight)[12][64]; int16_t orig[12][64]; - const int mb_x = s->mb_x; - const int mb_y = s->mb_y; + const int mb_x = s->c.mb_x; + const int mb_y = s->c.mb_y; int i; int skip_dct[12]; - int dct_offset = s->linesize * 8; // default for progressive frames - int uv_dct_offset = s->uvlinesize * 8; + int dct_offset = s->c.linesize * 8; // default for progressive frames + int uv_dct_offset = s->c.uvlinesize * 8; const uint8_t *ptr_y, *ptr_cb, *ptr_cr; ptrdiff_t wrap_y, wrap_c; @@ -2167,37 +2270,37 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, skip_dct[i] = s->skipdct; if (s->adaptive_quant) { - const int last_qp = s->qscale; - const int mb_xy = mb_x + mb_y * s->mb_stride; + const int last_qp = s->c.qscale; + const int mb_xy = mb_x + mb_y * s->c.mb_stride; - s->lambda = s->lambda_table[mb_xy]; + s->lambda = s->lambda_table[mb_xy]; s->lambda2 = (s->lambda * s->lambda + FF_LAMBDA_SCALE / 2) >> - FF_LAMBDA_SHIFT; + FF_LAMBDA_SHIFT; if (!(s->mpv_flags & FF_MPV_FLAG_QP_RD)) { - s->dquant = s->cur_pic.qscale_table[mb_xy] - last_qp; + s->dquant = s->c.cur_pic.qscale_table[mb_xy] - last_qp; - if (s->out_format == FMT_H263) { + if (s->c.out_format == FMT_H263) { s->dquant = av_clip(s->dquant, -2, 2); - if (s->codec_id == AV_CODEC_ID_MPEG4) { - if (!s->mb_intra) { - if (s->pict_type == AV_PICTURE_TYPE_B) { - if (s->dquant & 1 || s->mv_dir & MV_DIRECT) + if (s->c.codec_id == AV_CODEC_ID_MPEG4) { + if (!s->c.mb_intra) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) { + if (s->dquant & 1 || s->c.mv_dir & MV_DIRECT) s->dquant = 0; } - if (s->mv_type == MV_TYPE_8X8) + if (s->c.mv_type == MV_TYPE_8X8) s->dquant = 0; } } } } - ff_set_qscale(s, last_qp + s->dquant); + ff_set_qscale(&s->c, last_qp + s->dquant); } else if (s->mpv_flags & FF_MPV_FLAG_QP_RD) - ff_set_qscale(s, s->qscale + s->dquant); + ff_set_qscale(&s->c, s->c.qscale + s->dquant); - wrap_y = s->linesize; - wrap_c = s->uvlinesize; + wrap_y = s->c.linesize; + wrap_c = s->c.uvlinesize; ptr_y = s->new_pic->data[0] + (mb_y * 16 * wrap_y) + mb_x * 16; ptr_cb = s->new_pic->data[1] + @@ -2205,22 +2308,23 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, ptr_cr = s->new_pic->data[2] + (mb_y * mb_block_height * wrap_c) + mb_x * mb_block_width; - if((mb_x * 16 + 16 > s->width || mb_y * 16 + 16 > s->height) && s->codec_id != AV_CODEC_ID_AMV){ - uint8_t *ebuf = s->sc.edge_emu_buffer + 38 * wrap_y; - int cw = (s->width + chroma_x_shift) >> chroma_x_shift; - int ch = (s->height + chroma_y_shift) >> chroma_y_shift; - s->vdsp.emulated_edge_mc(ebuf, ptr_y, + if ((mb_x * 16 + 16 > s->c.width || mb_y * 16 + 16 > s->c.height) && + s->c.codec_id != AV_CODEC_ID_AMV) { + uint8_t *ebuf = s->c.sc.edge_emu_buffer + 38 * wrap_y; + int cw = (s->c.width + chroma_x_shift) >> chroma_x_shift; + int ch = (s->c.height + chroma_y_shift) >> chroma_y_shift; + s->c.vdsp.emulated_edge_mc(ebuf, ptr_y, wrap_y, wrap_y, 16, 16, mb_x * 16, mb_y * 16, - s->width, s->height); + s->c.width, s->c.height); ptr_y = ebuf; - s->vdsp.emulated_edge_mc(ebuf + 16 * wrap_y, ptr_cb, + s->c.vdsp.emulated_edge_mc(ebuf + 16 * wrap_y, ptr_cb, wrap_c, wrap_c, mb_block_width, mb_block_height, mb_x * mb_block_width, mb_y * mb_block_height, cw, ch); ptr_cb = ebuf + 16 * wrap_y; - s->vdsp.emulated_edge_mc(ebuf + 16 * wrap_y + 16, ptr_cr, + s->c.vdsp.emulated_edge_mc(ebuf + 16 * wrap_y + 16, ptr_cr, wrap_c, wrap_c, mb_block_width, mb_block_height, mb_x * mb_block_width, mb_y * mb_block_height, @@ -2228,11 +2332,11 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, ptr_cr = ebuf + 16 * wrap_y + 16; } - if (s->mb_intra) { + if (s->c.mb_intra) { if (INTERLACED_DCT(s)) { int progressive_score, interlaced_score; - s->interlaced_dct = 0; + s->c.interlaced_dct = 0; progressive_score = s->ildct_cmp[1](s, ptr_y, NULL, wrap_y, 8) + s->ildct_cmp[1](s, ptr_y + wrap_y * 8, NULL, wrap_y, 8) - 400; @@ -2243,7 +2347,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, s->ildct_cmp[1](s, ptr_y + wrap_y, NULL, wrap_y * 2, 8); if (progressive_score > interlaced_score) { - s->interlaced_dct = 1; + s->c.interlaced_dct = 1; dct_offset = wrap_y; uv_dct_offset = wrap_c; @@ -2260,7 +2364,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, s->pdsp.get_pixels(s->block[2], ptr_y + dct_offset, wrap_y); s->pdsp.get_pixels(s->block[3], ptr_y + dct_offset + 8, wrap_y); - if (s->avctx->flags & AV_CODEC_FLAG_GRAY) { + if (s->c.avctx->flags & AV_CODEC_FLAG_GRAY) { skip_dct[4] = 1; skip_dct[5] = 1; } else { @@ -2283,41 +2387,41 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, qpel_mc_func (*op_qpix)[16]; uint8_t *dest_y, *dest_cb, *dest_cr; - dest_y = s->dest[0]; - dest_cb = s->dest[1]; - dest_cr = s->dest[2]; + dest_y = s->c.dest[0]; + dest_cb = s->c.dest[1]; + dest_cr = s->c.dest[2]; - if ((!s->no_rounding) || s->pict_type == AV_PICTURE_TYPE_B) { - op_pix = s->hdsp.put_pixels_tab; - op_qpix = s->qdsp.put_qpel_pixels_tab; + if ((!s->c.no_rounding) || s->c.pict_type == AV_PICTURE_TYPE_B) { + op_pix = s->c.hdsp.put_pixels_tab; + op_qpix = s->c.qdsp.put_qpel_pixels_tab; } else { - op_pix = s->hdsp.put_no_rnd_pixels_tab; - op_qpix = s->qdsp.put_no_rnd_qpel_pixels_tab; + op_pix = s->c.hdsp.put_no_rnd_pixels_tab; + op_qpix = s->c.qdsp.put_no_rnd_qpel_pixels_tab; } - if (s->mv_dir & MV_DIR_FORWARD) { - ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 0, - s->last_pic.data, + if (s->c.mv_dir & MV_DIR_FORWARD) { + ff_mpv_motion(&s->c, dest_y, dest_cb, dest_cr, 0, + s->c.last_pic.data, op_pix, op_qpix); - op_pix = s->hdsp.avg_pixels_tab; - op_qpix = s->qdsp.avg_qpel_pixels_tab; + op_pix = s->c.hdsp.avg_pixels_tab; + op_qpix = s->c.qdsp.avg_qpel_pixels_tab; } - if (s->mv_dir & MV_DIR_BACKWARD) { - ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 1, - s->next_pic.data, + if (s->c.mv_dir & MV_DIR_BACKWARD) { + ff_mpv_motion(&s->c, dest_y, dest_cb, dest_cr, 1, + s->c.next_pic.data, op_pix, op_qpix); } if (INTERLACED_DCT(s)) { int progressive_score, interlaced_score; - s->interlaced_dct = 0; + s->c.interlaced_dct = 0; progressive_score = s->ildct_cmp[0](s, dest_y, ptr_y, wrap_y, 8) + s->ildct_cmp[0](s, dest_y + wrap_y * 8, ptr_y + wrap_y * 8, wrap_y, 8) - 400; - if (s->avctx->ildct_cmp == FF_CMP_VSSE) + if (s->c.avctx->ildct_cmp == FF_CMP_VSSE) progressive_score -= 400; if (progressive_score > 0) { @@ -2328,7 +2432,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, wrap_y * 2, 8); if (progressive_score > interlaced_score) { - s->interlaced_dct = 1; + s->c.interlaced_dct = 1; dct_offset = wrap_y; uv_dct_offset = wrap_c; @@ -2346,7 +2450,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, s->pdsp.diff_pixels(s->block[3], ptr_y + dct_offset + 8, dest_y + dct_offset + 8, wrap_y); - if (s->avctx->flags & AV_CODEC_FLAG_GRAY) { + if (s->c.avctx->flags & AV_CODEC_FLAG_GRAY) { skip_dct[4] = 1; skip_dct[5] = 1; } else { @@ -2360,30 +2464,30 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, } } /* pre quantization */ - if (s->mc_mb_var[s->mb_stride * mb_y + mb_x] < 2 * s->qscale * s->qscale) { + if (s->mc_mb_var[s->c.mb_stride * mb_y + mb_x] < 2 * s->c.qscale * s->c.qscale) { // FIXME optimize - if (s->sad_cmp[1](NULL, ptr_y, dest_y, wrap_y, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_y, dest_y, wrap_y, 8) < 20 * s->c.qscale) skip_dct[0] = 1; - if (s->sad_cmp[1](NULL, ptr_y + 8, dest_y + 8, wrap_y, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_y + 8, dest_y + 8, wrap_y, 8) < 20 * s->c.qscale) skip_dct[1] = 1; if (s->sad_cmp[1](NULL, ptr_y + dct_offset, dest_y + dct_offset, - wrap_y, 8) < 20 * s->qscale) + wrap_y, 8) < 20 * s->c.qscale) skip_dct[2] = 1; if (s->sad_cmp[1](NULL, ptr_y + dct_offset + 8, dest_y + dct_offset + 8, - wrap_y, 8) < 20 * s->qscale) + wrap_y, 8) < 20 * s->c.qscale) skip_dct[3] = 1; - if (s->sad_cmp[1](NULL, ptr_cb, dest_cb, wrap_c, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_cb, dest_cb, wrap_c, 8) < 20 * s->c.qscale) skip_dct[4] = 1; - if (s->sad_cmp[1](NULL, ptr_cr, dest_cr, wrap_c, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_cr, dest_cr, wrap_c, 8) < 20 * s->c.qscale) skip_dct[5] = 1; if (!chroma_y_shift) { /* 422 */ if (s->sad_cmp[1](NULL, ptr_cb + uv_dct_offset, dest_cb + uv_dct_offset, - wrap_c, 8) < 20 * s->qscale) + wrap_c, 8) < 20 * s->c.qscale) skip_dct[6] = 1; if (s->sad_cmp[1](NULL, ptr_cr + uv_dct_offset, dest_cr + uv_dct_offset, - wrap_c, 8) < 20 * s->qscale) + wrap_c, 8) < 20 * s->c.qscale) skip_dct[7] = 1; } } @@ -2414,230 +2518,207 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, } /* DCT & quantize */ - av_assert2(s->out_format != FMT_MJPEG || s->qscale == 8); + av_assert2(s->c.out_format != FMT_MJPEG || s->c.qscale == 8); { for (i = 0; i < mb_block_count; i++) { if (!skip_dct[i]) { int overflow; - s->block_last_index[i] = s->dct_quantize(s, s->block[i], i, s->qscale, &overflow); + s->c.block_last_index[i] = s->dct_quantize(s, s->block[i], i, s->c.qscale, &overflow); // FIXME we could decide to change to quantizer instead of // clipping // JS: I don't think that would be a good idea it could lower // quality instead of improve it. Just INTRADC clipping // deserves changes in quantizer if (overflow) - clip_coeffs(s, s->block[i], s->block_last_index[i]); + clip_coeffs(s, s->block[i], s->c.block_last_index[i]); } else - s->block_last_index[i] = -1; + s->c.block_last_index[i] = -1; } if (s->quantizer_noise_shaping) { for (i = 0; i < mb_block_count; i++) { if (!skip_dct[i]) { - s->block_last_index[i] = + s->c.block_last_index[i] = dct_quantize_refine(s, s->block[i], weight[i], - orig[i], i, s->qscale); + orig[i], i, s->c.qscale); } } } - if (s->luma_elim_threshold && !s->mb_intra) + if (s->luma_elim_threshold && !s->c.mb_intra) for (i = 0; i < 4; i++) dct_single_coeff_elimination(s, i, s->luma_elim_threshold); - if (s->chroma_elim_threshold && !s->mb_intra) + if (s->chroma_elim_threshold && !s->c.mb_intra) for (i = 4; i < mb_block_count; i++) dct_single_coeff_elimination(s, i, s->chroma_elim_threshold); if (s->mpv_flags & FF_MPV_FLAG_CBP_RD) { for (i = 0; i < mb_block_count; i++) { - if (s->block_last_index[i] == -1) + if (s->c.block_last_index[i] == -1) s->coded_score[i] = INT_MAX / 256; } } } - if ((s->avctx->flags & AV_CODEC_FLAG_GRAY) && s->mb_intra) { - s->block_last_index[4] = - s->block_last_index[5] = 0; + if ((s->c.avctx->flags & AV_CODEC_FLAG_GRAY) && s->c.mb_intra) { + s->c.block_last_index[4] = + s->c.block_last_index[5] = 0; s->block[4][0] = - s->block[5][0] = (1024 + s->c_dc_scale / 2) / s->c_dc_scale; + s->block[5][0] = (1024 + s->c.c_dc_scale / 2) / s->c.c_dc_scale; if (!chroma_y_shift) { /* 422 / 444 */ for (i=6; i<12; i++) { - s->block_last_index[i] = 0; + s->c.block_last_index[i] = 0; s->block[i][0] = s->block[4][0]; } } } // non c quantize code returns incorrect block_last_index FIXME - if (s->alternate_scan && s->dct_quantize != dct_quantize_c) { + if (s->c.alternate_scan && s->dct_quantize != dct_quantize_c) { for (i = 0; i < mb_block_count; i++) { int j; - if (s->block_last_index[i] > 0) { + if (s->c.block_last_index[i] > 0) { for (j = 63; j > 0; j--) { - if (s->block[i][s->intra_scantable.permutated[j]]) + if (s->block[i][s->c.intra_scantable.permutated[j]]) break; } - s->block_last_index[i] = j; + s->c.block_last_index[i] = j; } } } - /* huffman encode */ - switch(s->codec_id){ //FIXME funct ptr could be slightly faster - case AV_CODEC_ID_MPEG1VIDEO: - case AV_CODEC_ID_MPEG2VIDEO: - if (CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER) - ff_mpeg1_encode_mb(s, s->block, motion_x, motion_y); - break; - case AV_CODEC_ID_MPEG4: - if (CONFIG_MPEG4_ENCODER) - ff_mpeg4_encode_mb(s, s->block, motion_x, motion_y); - break; - case AV_CODEC_ID_MSMPEG4V2: - case AV_CODEC_ID_MSMPEG4V3: - case AV_CODEC_ID_WMV1: - if (CONFIG_MSMPEG4ENC) - ff_msmpeg4_encode_mb(s, s->block, motion_x, motion_y); - break; - case AV_CODEC_ID_WMV2: - if (CONFIG_WMV2_ENCODER) - ff_wmv2_encode_mb(s, s->block, motion_x, motion_y); - break; - case AV_CODEC_ID_H261: - if (CONFIG_H261_ENCODER) - ff_h261_encode_mb(s, s->block, motion_x, motion_y); - break; - case AV_CODEC_ID_H263: - case AV_CODEC_ID_H263P: - case AV_CODEC_ID_FLV1: - case AV_CODEC_ID_RV10: - case AV_CODEC_ID_RV20: - if (CONFIG_H263_ENCODER) - ff_h263_encode_mb(s, s->block, motion_x, motion_y); - break; -#if CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER - case AV_CODEC_ID_MJPEG: - case AV_CODEC_ID_AMV: - ff_mjpeg_encode_mb(s, s->block); - break; -#endif - case AV_CODEC_ID_SPEEDHQ: - if (CONFIG_SPEEDHQ_ENCODER) - ff_speedhq_encode_mb(s, s->block); - break; - default: - av_assert1(0); - } + s->encode_mb(s, s->block, motion_x, motion_y); } -static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) +static void encode_mb(MPVEncContext *const s, int motion_x, int motion_y) { - if (s->chroma_format == CHROMA_420) + if (s->c.chroma_format == CHROMA_420) encode_mb_internal(s, motion_x, motion_y, 8, 8, 6, 1, 1, CHROMA_420); - else if (s->chroma_format == CHROMA_422) + else if (s->c.chroma_format == CHROMA_422) encode_mb_internal(s, motion_x, motion_y, 16, 8, 8, 1, 0, CHROMA_422); else encode_mb_internal(s, motion_x, motion_y, 16, 16, 12, 0, 0, CHROMA_444); } -static inline void copy_context_before_encode(MpegEncContext *d, - const MpegEncContext *s) -{ - int i; +typedef struct MBBackup { + struct { + int mv[2][4][2]; + int last_mv[2][2][2]; + int mv_type, mv_dir; + int mb_intra, mb_skipped; + int qscale; + int block_last_index[8]; + int interlaced_dct; + } c; + int mb_skip_run; + int last_dc[3]; + int mv_bits, i_tex_bits, p_tex_bits, i_count, misc_bits, last_bits; + int dquant; + int esc3_level_length; + int16_t (*block)[64]; + PutBitContext pb, pb2, tex_pb; +} MBBackup; - memcpy(d->last_mv, s->last_mv, 2*2*2*sizeof(int)); //FIXME is memcpy faster than a loop? - - /* MPEG-1 */ - d->mb_skip_run= s->mb_skip_run; - for(i=0; i<3; i++) - d->last_dc[i] = s->last_dc[i]; - - /* statistics */ - d->mv_bits= s->mv_bits; - d->i_tex_bits= s->i_tex_bits; - d->p_tex_bits= s->p_tex_bits; - d->i_count= s->i_count; - d->misc_bits= s->misc_bits; - d->last_bits= 0; - - d->mb_skipped= 0; - d->qscale= s->qscale; - d->dquant= s->dquant; - - d->esc3_level_length= s->esc3_level_length; +#define COPY_CONTEXT(BEFORE, AFTER, DST_TYPE, SRC_TYPE) \ +static inline void BEFORE ##_context_before_encode(DST_TYPE *const d, \ + const SRC_TYPE *const s) \ +{ \ + /* FIXME is memcpy faster than a loop? */ \ + memcpy(d->c.last_mv, s->c.last_mv, 2*2*2*sizeof(int)); \ + \ + /* MPEG-1 */ \ + d->mb_skip_run = s->mb_skip_run; \ + for (int i = 0; i < 3; i++) \ + d->last_dc[i] = s->last_dc[i]; \ + \ + /* statistics */ \ + d->mv_bits = s->mv_bits; \ + d->i_tex_bits = s->i_tex_bits; \ + d->p_tex_bits = s->p_tex_bits; \ + d->i_count = s->i_count; \ + d->misc_bits = s->misc_bits; \ + d->last_bits = 0; \ + \ + d->c.mb_skipped = 0; \ + d->c.qscale = s->c.qscale; \ + d->dquant = s->dquant; \ + \ + d->esc3_level_length = s->esc3_level_length; \ +} \ + \ +static inline void AFTER ## _context_after_encode(DST_TYPE *const d, \ + const SRC_TYPE *const s, \ + int data_partitioning) \ +{ \ + /* FIXME is memcpy faster than a loop? */ \ + memcpy(d->c.mv, s->c.mv, 2*4*2*sizeof(int)); \ + memcpy(d->c.last_mv, s->c.last_mv, 2*2*2*sizeof(int)); \ + \ + /* MPEG-1 */ \ + d->mb_skip_run = s->mb_skip_run; \ + for (int i = 0; i < 3; i++) \ + d->last_dc[i] = s->last_dc[i]; \ + \ + /* statistics */ \ + d->mv_bits = s->mv_bits; \ + d->i_tex_bits = s->i_tex_bits; \ + d->p_tex_bits = s->p_tex_bits; \ + d->i_count = s->i_count; \ + d->misc_bits = s->misc_bits; \ + \ + d->c.mb_intra = s->c.mb_intra; \ + d->c.mb_skipped = s->c.mb_skipped; \ + d->c.mv_type = s->c.mv_type; \ + d->c.mv_dir = s->c.mv_dir; \ + d->pb = s->pb; \ + if (data_partitioning) { \ + d->pb2 = s->pb2; \ + d->tex_pb = s->tex_pb; \ + } \ + d->block = s->block; \ + for (int i = 0; i < 8; i++) \ + d->c.block_last_index[i] = s->c.block_last_index[i]; \ + d->c.interlaced_dct = s->c.interlaced_dct; \ + d->c.qscale = s->c.qscale; \ + \ + d->esc3_level_length = s->esc3_level_length; \ } -static inline void copy_context_after_encode(MpegEncContext *d, - const MpegEncContext *s) -{ - int i; +COPY_CONTEXT(backup, save, MBBackup, MPVEncContext) +COPY_CONTEXT(reset, store, MPVEncContext, MBBackup) - memcpy(d->mv, s->mv, 2*4*2*sizeof(int)); - memcpy(d->last_mv, s->last_mv, 2*2*2*sizeof(int)); //FIXME is memcpy faster than a loop? - - /* MPEG-1 */ - d->mb_skip_run= s->mb_skip_run; - for(i=0; i<3; i++) - d->last_dc[i] = s->last_dc[i]; - - /* statistics */ - d->mv_bits= s->mv_bits; - d->i_tex_bits= s->i_tex_bits; - d->p_tex_bits= s->p_tex_bits; - d->i_count= s->i_count; - d->misc_bits= s->misc_bits; - - d->mb_intra= s->mb_intra; - d->mb_skipped= s->mb_skipped; - d->mv_type= s->mv_type; - d->mv_dir= s->mv_dir; - d->pb= s->pb; - if(s->data_partitioning){ - d->pb2= s->pb2; - d->tex_pb= s->tex_pb; - } - d->block= s->block; - for(i=0; i<8; i++) - d->block_last_index[i]= s->block_last_index[i]; - d->interlaced_dct= s->interlaced_dct; - d->qscale= s->qscale; - - d->esc3_level_length= s->esc3_level_length; -} - -static void encode_mb_hq(MpegEncContext *s, MpegEncContext *backup, MpegEncContext *best, +static void encode_mb_hq(MPVEncContext *const s, MBBackup *const backup, MBBackup *const best, PutBitContext pb[2], PutBitContext pb2[2], PutBitContext tex_pb[2], int *dmin, int *next_block, int motion_x, int motion_y) { int score; uint8_t *dest_backup[3]; - copy_context_before_encode(s, backup); + reset_context_before_encode(s, backup); - s->block= s->blocks[*next_block]; - s->pb= pb[*next_block]; - if(s->data_partitioning){ + s->block = s->blocks[*next_block]; + s->pb = pb[*next_block]; + if (s->data_partitioning) { s->pb2 = pb2 [*next_block]; s->tex_pb= tex_pb[*next_block]; } if(*next_block){ - memcpy(dest_backup, s->dest, sizeof(s->dest)); - s->dest[0] = s->sc.rd_scratchpad; - s->dest[1] = s->sc.rd_scratchpad + 16*s->linesize; - s->dest[2] = s->sc.rd_scratchpad + 16*s->linesize + 8; - av_assert0(s->linesize >= 32); //FIXME + memcpy(dest_backup, s->c.dest, sizeof(s->c.dest)); + s->c.dest[0] = s->c.sc.rd_scratchpad; + s->c.dest[1] = s->c.sc.rd_scratchpad + 16*s->c.linesize; + s->c.dest[2] = s->c.sc.rd_scratchpad + 16*s->c.linesize + 8; + av_assert0(s->c.linesize >= 32); //FIXME } encode_mb(s, motion_x, motion_y); score= put_bits_count(&s->pb); - if(s->data_partitioning){ + if (s->data_partitioning) { score+= put_bits_count(&s->pb2); score+= put_bits_count(&s->tex_pb); } - if(s->avctx->mb_decision == FF_MB_DECISION_RD){ + if (s->c.avctx->mb_decision == FF_MB_DECISION_RD) { mpv_reconstruct_mb(s, s->block); score *= s->lambda2; @@ -2645,18 +2726,19 @@ static void encode_mb_hq(MpegEncContext *s, MpegEncContext *backup, MpegEncConte } if(*next_block){ - memcpy(s->dest, dest_backup, sizeof(s->dest)); + memcpy(s->c.dest, dest_backup, sizeof(s->c.dest)); } if(score<*dmin){ *dmin= score; *next_block^=1; - copy_context_after_encode(best, s); + save_context_after_encode(best, s, s->data_partitioning); } } -static int sse(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, int w, int h, int stride){ +static int sse(const MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, int w, int h, int stride) +{ const uint32_t *sq = ff_square_tab + 256; int acc=0; int x,y; @@ -2677,129 +2759,128 @@ static int sse(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, int return acc; } -static int sse_mb(MpegEncContext *s){ +static int sse_mb(MPVEncContext *const s) +{ int w= 16; int h= 16; - int chroma_mb_w = w >> s->chroma_x_shift; - int chroma_mb_h = h >> s->chroma_y_shift; + int chroma_mb_w = w >> s->c.chroma_x_shift; + int chroma_mb_h = h >> s->c.chroma_y_shift; - if(s->mb_x*16 + 16 > s->width ) w= s->width - s->mb_x*16; - if(s->mb_y*16 + 16 > s->height) h= s->height- s->mb_y*16; + if (s->c.mb_x*16 + 16 > s->c.width ) w = s->c.width - s->c.mb_x*16; + if (s->c.mb_y*16 + 16 > s->c.height) h = s->c.height- s->c.mb_y*16; if(w==16 && h==16) - return s->n_sse_cmp[0](s, s->new_pic->data[0] + s->mb_x * 16 + s->mb_y * s->linesize * 16, - s->dest[0], s->linesize, 16) + - s->n_sse_cmp[1](s, s->new_pic->data[1] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, - s->dest[1], s->uvlinesize, chroma_mb_h) + - s->n_sse_cmp[1](s, s->new_pic->data[2] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, - s->dest[2], s->uvlinesize, chroma_mb_h); + return s->n_sse_cmp[0](s, s->new_pic->data[0] + s->c.mb_x * 16 + s->c.mb_y * s->c.linesize * 16, + s->c.dest[0], s->c.linesize, 16) + + s->n_sse_cmp[1](s, s->new_pic->data[1] + s->c.mb_x * chroma_mb_w + s->c.mb_y * s->c.uvlinesize * chroma_mb_h, + s->c.dest[1], s->c.uvlinesize, chroma_mb_h) + + s->n_sse_cmp[1](s, s->new_pic->data[2] + s->c.mb_x * chroma_mb_w + s->c.mb_y * s->c.uvlinesize * chroma_mb_h, + s->c.dest[2], s->c.uvlinesize, chroma_mb_h); else - return sse(s, s->new_pic->data[0] + s->mb_x * 16 + s->mb_y * s->linesize * 16, - s->dest[0], w, h, s->linesize) + - sse(s, s->new_pic->data[1] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, - s->dest[1], w >> s->chroma_x_shift, h >> s->chroma_y_shift, s->uvlinesize) + - sse(s, s->new_pic->data[2] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, - s->dest[2], w >> s->chroma_x_shift, h >> s->chroma_y_shift, s->uvlinesize); + return sse(s, s->new_pic->data[0] + s->c.mb_x * 16 + s->c.mb_y * s->c.linesize * 16, + s->c.dest[0], w, h, s->c.linesize) + + sse(s, s->new_pic->data[1] + s->c.mb_x * chroma_mb_w + s->c.mb_y * s->c.uvlinesize * chroma_mb_h, + s->c.dest[1], w >> s->c.chroma_x_shift, h >> s->c.chroma_y_shift, s->c.uvlinesize) + + sse(s, s->new_pic->data[2] + s->c.mb_x * chroma_mb_w + s->c.mb_y * s->c.uvlinesize * chroma_mb_h, + s->c.dest[2], w >> s->c.chroma_x_shift, h >> s->c.chroma_y_shift, s->c.uvlinesize); } static int pre_estimate_motion_thread(AVCodecContext *c, void *arg){ - MpegEncContext *s= *(void**)arg; + MPVEncContext *const s = *(void**)arg; - s->me.pre_pass=1; - s->me.dia_size= s->avctx->pre_dia_size; - s->first_slice_line=1; - for(s->mb_y= s->end_mb_y-1; s->mb_y >= s->start_mb_y; s->mb_y--) { - for(s->mb_x=s->mb_width-1; s->mb_x >=0 ;s->mb_x--) { - ff_pre_estimate_p_frame_motion(s, s->mb_x, s->mb_y); - } - s->first_slice_line=0; + s->me.pre_pass = 1; + s->me.dia_size = s->c.avctx->pre_dia_size; + s->c.first_slice_line = 1; + for (s->c.mb_y = s->c.end_mb_y - 1; s->c.mb_y >= s->c.start_mb_y; s->c.mb_y--) { + for (s->c.mb_x = s->c.mb_width - 1; s->c.mb_x >=0 ; s->c.mb_x--) + ff_pre_estimate_p_frame_motion(s, s->c.mb_x, s->c.mb_y); + s->c.first_slice_line = 0; } - s->me.pre_pass=0; + s->me.pre_pass = 0; return 0; } static int estimate_motion_thread(AVCodecContext *c, void *arg){ - MpegEncContext *s= *(void**)arg; + MPVEncContext *const s = *(void**)arg; - s->me.dia_size= s->avctx->dia_size; - s->first_slice_line=1; - for(s->mb_y= s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) { - s->mb_x=0; //for block init below - ff_init_block_index(s); - for(s->mb_x=0; s->mb_x < s->mb_width; s->mb_x++) { - s->block_index[0]+=2; - s->block_index[1]+=2; - s->block_index[2]+=2; - s->block_index[3]+=2; + s->me.dia_size = s->c.avctx->dia_size; + s->c.first_slice_line = 1; + for (s->c.mb_y = s->c.start_mb_y; s->c.mb_y < s->c.end_mb_y; s->c.mb_y++) { + s->c.mb_x = 0; //for block init below + ff_init_block_index(&s->c); + for (s->c.mb_x = 0; s->c.mb_x < s->c.mb_width; s->c.mb_x++) { + s->c.block_index[0] += 2; + s->c.block_index[1] += 2; + s->c.block_index[2] += 2; + s->c.block_index[3] += 2; /* compute motion vector & mb_type and store in context */ - if(s->pict_type==AV_PICTURE_TYPE_B) - ff_estimate_b_frame_motion(s, s->mb_x, s->mb_y); + if (s->c.pict_type == AV_PICTURE_TYPE_B) + ff_estimate_b_frame_motion(s, s->c.mb_x, s->c.mb_y); else - ff_estimate_p_frame_motion(s, s->mb_x, s->mb_y); + ff_estimate_p_frame_motion(s, s->c.mb_x, s->c.mb_y); } - s->first_slice_line=0; + s->c.first_slice_line = 0; } return 0; } static int mb_var_thread(AVCodecContext *c, void *arg){ - MpegEncContext *s= *(void**)arg; - int mb_x, mb_y; + MPVEncContext *const s = *(void**)arg; - for(mb_y=s->start_mb_y; mb_y < s->end_mb_y; mb_y++) { - for(mb_x=0; mb_x < s->mb_width; mb_x++) { + for (int mb_y = s->c.start_mb_y; mb_y < s->c.end_mb_y; mb_y++) { + for (int mb_x = 0; mb_x < s->c.mb_width; mb_x++) { int xx = mb_x * 16; int yy = mb_y * 16; - const uint8_t *pix = s->new_pic->data[0] + (yy * s->linesize) + xx; + const uint8_t *pix = s->new_pic->data[0] + (yy * s->c.linesize) + xx; int varc; - int sum = s->mpvencdsp.pix_sum(pix, s->linesize); + int sum = s->mpvencdsp.pix_sum(pix, s->c.linesize); - varc = (s->mpvencdsp.pix_norm1(pix, s->linesize) - + varc = (s->mpvencdsp.pix_norm1(pix, s->c.linesize) - (((unsigned) sum * sum) >> 8) + 500 + 128) >> 8; - s->mb_var [s->mb_stride * mb_y + mb_x] = varc; - s->mb_mean[s->mb_stride * mb_y + mb_x] = (sum+128)>>8; + s->mb_var [s->c.mb_stride * mb_y + mb_x] = varc; + s->mb_mean[s->c.mb_stride * mb_y + mb_x] = (sum+128)>>8; s->me.mb_var_sum_temp += varc; } } return 0; } -static void write_slice_end(MpegEncContext *s){ - if(CONFIG_MPEG4_ENCODER && s->codec_id==AV_CODEC_ID_MPEG4){ - if(s->partitioned_frame){ +static void write_slice_end(MPVEncContext *const s) +{ + if (CONFIG_MPEG4_ENCODER && s->c.codec_id == AV_CODEC_ID_MPEG4) { + if (s->partitioned_frame) ff_mpeg4_merge_partitions(s); - } ff_mpeg4_stuffing(&s->pb); } else if ((CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER) && - s->out_format == FMT_MJPEG) { + s->c.out_format == FMT_MJPEG) { ff_mjpeg_encode_stuffing(s); - } else if (CONFIG_SPEEDHQ_ENCODER && s->out_format == FMT_SPEEDHQ) { + } else if (CONFIG_SPEEDHQ_ENCODER && s->c.out_format == FMT_SPEEDHQ) { ff_speedhq_end_slice(s); } flush_put_bits(&s->pb); - if ((s->avctx->flags & AV_CODEC_FLAG_PASS1) && !s->partitioned_frame) + if ((s->c.avctx->flags & AV_CODEC_FLAG_PASS1) && !s->partitioned_frame) s->misc_bits+= get_bits_diff(s); } -static void write_mb_info(MpegEncContext *s) +static void write_mb_info(MPVEncContext *const s) { uint8_t *ptr = s->mb_info_ptr + s->mb_info_size - 12; int offset = put_bits_count(&s->pb); - int mba = s->mb_x + s->mb_width * (s->mb_y % s->gob_index); - int gobn = s->mb_y / s->gob_index; + int mba = s->c.mb_x + s->c.mb_width * (s->c.mb_y % s->gob_index); + int gobn = s->c.mb_y / s->gob_index; int pred_x, pred_y; if (CONFIG_H263_ENCODER) - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); bytestream_put_le32(&ptr, offset); - bytestream_put_byte(&ptr, s->qscale); + bytestream_put_byte(&ptr, s->c.qscale); bytestream_put_byte(&ptr, gobn); bytestream_put_le16(&ptr, mba); bytestream_put_byte(&ptr, pred_x); /* hmv1 */ @@ -2809,7 +2890,7 @@ static void write_mb_info(MpegEncContext *s) bytestream_put_byte(&ptr, 0); /* vmv2 */ } -static void update_mb_info(MpegEncContext *s) +static void update_mb_info(MPVEncContext *const s) { if (!s->mb_info) return; @@ -2824,32 +2905,32 @@ static void update_mb_info(MpegEncContext *s) write_mb_info(s); } -int ff_mpv_reallocate_putbitbuffer(MpegEncContext *s, size_t threshold, size_t size_increase) +int ff_mpv_reallocate_putbitbuffer(MPVEncContext *const s, size_t threshold, size_t size_increase) { if (put_bytes_left(&s->pb, 0) < threshold - && s->slice_context_count == 1 - && s->pb.buf == s->avctx->internal->byte_buffer) { + && s->c.slice_context_count == 1 + && s->pb.buf == s->c.avctx->internal->byte_buffer) { int lastgob_pos = s->ptr_lastgob - s->pb.buf; uint8_t *new_buffer = NULL; int new_buffer_size = 0; - if ((s->avctx->internal->byte_buffer_size + size_increase) >= INT_MAX/8) { - av_log(s->avctx, AV_LOG_ERROR, "Cannot reallocate putbit buffer\n"); + if ((s->c.avctx->internal->byte_buffer_size + size_increase) >= INT_MAX/8) { + av_log(s->c.avctx, AV_LOG_ERROR, "Cannot reallocate putbit buffer\n"); return AVERROR(ENOMEM); } emms_c(); av_fast_padded_malloc(&new_buffer, &new_buffer_size, - s->avctx->internal->byte_buffer_size + size_increase); + s->c.avctx->internal->byte_buffer_size + size_increase); if (!new_buffer) return AVERROR(ENOMEM); - memcpy(new_buffer, s->avctx->internal->byte_buffer, s->avctx->internal->byte_buffer_size); - av_free(s->avctx->internal->byte_buffer); - s->avctx->internal->byte_buffer = new_buffer; - s->avctx->internal->byte_buffer_size = new_buffer_size; + memcpy(new_buffer, s->c.avctx->internal->byte_buffer, s->c.avctx->internal->byte_buffer_size); + av_free(s->c.avctx->internal->byte_buffer); + s->c.avctx->internal->byte_buffer = new_buffer; + s->c.avctx->internal->byte_buffer_size = new_buffer_size; rebase_put_bits(&s->pb, new_buffer, new_buffer_size); s->ptr_lastgob = s->pb.buf + lastgob_pos; } @@ -2859,20 +2940,20 @@ int ff_mpv_reallocate_putbitbuffer(MpegEncContext *s, size_t threshold, size_t s } static int encode_thread(AVCodecContext *c, void *arg){ - MpegEncContext *s= *(void**)arg; - int mb_x, mb_y, mb_y_order; - int chr_h= 16>>s->chroma_y_shift; - int i, j; - MpegEncContext best_s = { 0 }, backup_s; + MPVEncContext *const s = *(void**)arg; + int chr_h = 16 >> s->c.chroma_y_shift; + int i; + MBBackup best_s = { 0 }, backup_s; uint8_t bit_buf[2][MAX_MB_BYTES]; - uint8_t bit_buf2[2][MAX_MB_BYTES]; - uint8_t bit_buf_tex[2][MAX_MB_BYTES]; + // + 2 because ff_copy_bits() overreads + uint8_t bit_buf2[2][MAX_PB2_MB_SIZE + 2]; + uint8_t bit_buf_tex[2][MAX_AC_TEX_MB_SIZE + 2]; PutBitContext pb[2], pb2[2], tex_pb[2]; for(i=0; i<2; i++){ init_put_bits(&pb [i], bit_buf [i], MAX_MB_BYTES); - init_put_bits(&pb2 [i], bit_buf2 [i], MAX_MB_BYTES); - init_put_bits(&tex_pb[i], bit_buf_tex[i], MAX_MB_BYTES); + init_put_bits(&pb2 [i], bit_buf2 [i], MAX_PB2_MB_SIZE); + init_put_bits(&tex_pb[i], bit_buf_tex[i], MAX_AC_TEX_MB_SIZE); } s->last_bits= put_bits_count(&s->pb); @@ -2885,84 +2966,75 @@ static int encode_thread(AVCodecContext *c, void *arg){ for(i=0; i<3; i++){ /* init last dc values */ /* note: quant matrix value (8) is implied here */ - s->last_dc[i] = 128 << s->intra_dc_precision; + s->last_dc[i] = 128 << s->c.intra_dc_precision; s->encoding_error[i] = 0; } - if(s->codec_id==AV_CODEC_ID_AMV){ - s->last_dc[0] = 128*8/13; - s->last_dc[1] = 128*8/14; - s->last_dc[2] = 128*8/14; + if (s->c.codec_id == AV_CODEC_ID_AMV) { + s->last_dc[0] = 128 * 8 / 13; + s->last_dc[1] = 128 * 8 / 14; + s->last_dc[2] = 128 * 8 / 14; +#if CONFIG_MPEG4_ENCODER + } else if (s->partitioned_frame) { + av_assert1(s->c.codec_id == AV_CODEC_ID_MPEG4); + ff_mpeg4_init_partitions(s); +#endif } s->mb_skip_run = 0; - memset(s->last_mv, 0, sizeof(s->last_mv)); + memset(s->c.last_mv, 0, sizeof(s->c.last_mv)); s->last_mv_dir = 0; - switch(s->codec_id){ - case AV_CODEC_ID_H263: - case AV_CODEC_ID_H263P: - case AV_CODEC_ID_FLV1: - if (CONFIG_H263_ENCODER) - s->gob_index = H263_GOB_HEIGHT(s->height); - break; - case AV_CODEC_ID_MPEG4: - if(CONFIG_MPEG4_ENCODER && s->partitioned_frame) - ff_mpeg4_init_partitions(s); - break; - } - - s->resync_mb_x=0; - s->resync_mb_y=0; - s->first_slice_line = 1; + s->c.resync_mb_x = 0; + s->c.resync_mb_y = 0; + s->c.first_slice_line = 1; s->ptr_lastgob = s->pb.buf; - for (mb_y_order = s->start_mb_y; mb_y_order < s->end_mb_y; mb_y_order++) { - if (CONFIG_SPEEDHQ_ENCODER && s->codec_id == AV_CODEC_ID_SPEEDHQ) { + for (int mb_y_order = s->c.start_mb_y; mb_y_order < s->c.end_mb_y; mb_y_order++) { + int mb_y; + if (CONFIG_SPEEDHQ_ENCODER && s->c.codec_id == AV_CODEC_ID_SPEEDHQ) { int first_in_slice; - mb_y = ff_speedhq_mb_y_order_to_mb(mb_y_order, s->mb_height, &first_in_slice); - if (first_in_slice && mb_y_order != s->start_mb_y) + mb_y = ff_speedhq_mb_y_order_to_mb(mb_y_order, s->c.mb_height, &first_in_slice); + if (first_in_slice && mb_y_order != s->c.start_mb_y) ff_speedhq_end_slice(s); - s->last_dc[0] = s->last_dc[1] = s->last_dc[2] = 1024 << s->intra_dc_precision; + s->last_dc[0] = s->last_dc[1] = s->last_dc[2] = 1024; } else { mb_y = mb_y_order; } - s->mb_x=0; - s->mb_y= mb_y; + s->c.mb_x = 0; + s->c.mb_y = mb_y; - ff_set_qscale(s, s->qscale); - ff_init_block_index(s); + ff_set_qscale(&s->c, s->c.qscale); + ff_init_block_index(&s->c); - for(mb_x=0; mb_x < s->mb_width; mb_x++) { - int xy= mb_y*s->mb_stride + mb_x; // removed const, H261 needs to adjust this - int mb_type= s->mb_type[xy]; + for (int mb_x = 0; mb_x < s->c.mb_width; mb_x++) { + int mb_type, xy; // int d; int dmin= INT_MAX; int dir; - int size_increase = s->avctx->internal->byte_buffer_size/4 - + s->mb_width*MAX_MB_BYTES; + int size_increase = s->c.avctx->internal->byte_buffer_size/4 + + s->c.mb_width*MAX_MB_BYTES; ff_mpv_reallocate_putbitbuffer(s, MAX_MB_BYTES, size_increase); if (put_bytes_left(&s->pb, 0) < MAX_MB_BYTES){ - av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "encoded frame too large\n"); return -1; } - if(s->data_partitioning){ + if (s->data_partitioning) { if (put_bytes_left(&s->pb2, 0) < MAX_MB_BYTES || put_bytes_left(&s->tex_pb, 0) < MAX_MB_BYTES) { - av_log(s->avctx, AV_LOG_ERROR, "encoded partitioned frame too large\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "encoded partitioned frame too large\n"); return -1; } } - s->mb_x = mb_x; - s->mb_y = mb_y; // moved into loop, can get changed by H.261 - ff_update_block_index(s, 8, 0, s->chroma_x_shift); + s->c.mb_x = mb_x; + s->c.mb_y = mb_y; // moved into loop, can get changed by H.261 + ff_update_block_index(&s->c, 8, 0, s->c.chroma_x_shift); - if(CONFIG_H261_ENCODER && s->codec_id == AV_CODEC_ID_H261){ + if (CONFIG_H261_ENCODER && s->c.codec_id == AV_CODEC_ID_H261) ff_h261_reorder_mb_index(s); - xy= s->mb_y*s->mb_stride + s->mb_x; - mb_type= s->mb_type[xy]; - } + xy = s->c.mb_y * s->c.mb_stride + s->c.mb_x; + mb_type = s->mb_type[xy]; /* write gob / video packet header */ if(s->rtp_mode){ @@ -2975,38 +3047,39 @@ static int encode_thread(AVCodecContext *c, void *arg){ current_packet_size >= s->rtp_payload_size && mb_y + mb_x > 0; - if(s->start_mb_y == mb_y && mb_y > 0 && mb_x==0) is_gob_start=1; + if (s->c.start_mb_y == mb_y && mb_y > 0 && mb_x == 0) is_gob_start = 1; - switch(s->codec_id){ + switch (s->c.codec_id) { case AV_CODEC_ID_H263: case AV_CODEC_ID_H263P: - if(!s->h263_slice_structured) - if(s->mb_x || s->mb_y%s->gob_index) is_gob_start=0; + if (!s->h263_slice_structured) + if (s->c.mb_x || s->c.mb_y % s->gob_index) is_gob_start = 0; break; case AV_CODEC_ID_MPEG2VIDEO: - if(s->mb_x==0 && s->mb_y!=0) is_gob_start=1; + if (s->c.mb_x == 0 && s->c.mb_y != 0) is_gob_start = 1; case AV_CODEC_ID_MPEG1VIDEO: - if(s->mb_skip_run) is_gob_start=0; + if (s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO && s->c.mb_y >= 175 || + s->mb_skip_run) + is_gob_start=0; break; case AV_CODEC_ID_MJPEG: - if(s->mb_x==0 && s->mb_y!=0) is_gob_start=1; + if (s->c.mb_x == 0 && s->c.mb_y != 0) is_gob_start = 1; break; } if(is_gob_start){ - if(s->start_mb_y != mb_y || mb_x!=0){ + if (s->c.start_mb_y != mb_y || mb_x != 0) { write_slice_end(s); - if(CONFIG_MPEG4_ENCODER && s->codec_id==AV_CODEC_ID_MPEG4 && s->partitioned_frame){ + if (CONFIG_MPEG4_ENCODER && s->c.codec_id == AV_CODEC_ID_MPEG4 && s->partitioned_frame) ff_mpeg4_init_partitions(s); - } } av_assert2((put_bits_count(&s->pb)&7) == 0); current_packet_size= put_bits_ptr(&s->pb) - s->ptr_lastgob; - if (s->error_rate && s->resync_mb_x + s->resync_mb_y > 0) { - int r = put_bytes_count(&s->pb, 0) + s->picture_number + 16 + s->mb_x + s->mb_y; + if (s->error_rate && s->c.resync_mb_x + s->c.resync_mb_y > 0) { + int r = put_bytes_count(&s->pb, 0) + s->picture_number + 16 + s->c.mb_x + s->c.mb_y; int d = 100 / s->error_rate; if(r % d == 0){ current_packet_size=0; @@ -3015,11 +3088,12 @@ static int encode_thread(AVCodecContext *c, void *arg){ } } - switch(s->codec_id){ + switch (s->c.codec_id) { case AV_CODEC_ID_MPEG4: if (CONFIG_MPEG4_ENCODER) { ff_mpeg4_encode_video_packet_header(s); - ff_mpeg4_clean_buffers(s); + ff_mpeg4_clean_buffers(&s->c); + ff_h263_mpeg4_reset_dc(s); } break; case AV_CODEC_ID_MPEG1VIDEO: @@ -3029,8 +3103,13 @@ static int encode_thread(AVCodecContext *c, void *arg){ ff_mpeg1_clean_buffers(s); } break; - case AV_CODEC_ID_H263: +#if CONFIG_H263P_ENCODER case AV_CODEC_ID_H263P: + if (s->c.dc_val) + ff_h263_mpeg4_reset_dc(s); + // fallthrough +#endif + case AV_CODEC_ID_H263: if (CONFIG_H263_ENCODER) { if (s->mb_info && put_bytes_count(&s->pb, 0) - s->prev_mb_info >= s->mb_info) s->mb_info_size += 12; @@ -3041,25 +3120,24 @@ static int encode_thread(AVCodecContext *c, void *arg){ break; } - if (s->avctx->flags & AV_CODEC_FLAG_PASS1) { + if (s->c.avctx->flags & AV_CODEC_FLAG_PASS1) { int bits= put_bits_count(&s->pb); s->misc_bits+= bits - s->last_bits; s->last_bits= bits; } - s->ptr_lastgob += current_packet_size; - s->first_slice_line=1; - s->resync_mb_x=mb_x; - s->resync_mb_y=mb_y; + s->ptr_lastgob += current_packet_size; + s->c.first_slice_line = 1; + s->c.resync_mb_x = mb_x; + s->c.resync_mb_y = mb_y; } } - if( (s->resync_mb_x == s->mb_x) - && s->resync_mb_y+1 == s->mb_y){ - s->first_slice_line=0; - } + if (s->c.resync_mb_x == s->c.mb_x && + s->c.resync_mb_y+1 == s->c.mb_y) + s->c.first_slice_line = 0; - s->mb_skipped=0; + s->c.mb_skipped = 0; s->dquant=0; //only for QP_RD update_mb_info(s); @@ -3068,180 +3146,173 @@ static int encode_thread(AVCodecContext *c, void *arg){ int next_block=0; int pb_bits_count, pb2_bits_count, tex_pb_bits_count; - copy_context_before_encode(&backup_s, s); + backup_context_before_encode(&backup_s, s); backup_s.pb= s->pb; - best_s.data_partitioning= s->data_partitioning; - best_s.partitioned_frame= s->partitioned_frame; - if(s->data_partitioning){ + if (s->data_partitioning) { backup_s.pb2= s->pb2; backup_s.tex_pb= s->tex_pb; } if(mb_type&CANDIDATE_MB_TYPE_INTER){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 0; - s->mv[0][0][0] = s->p_mv_table[xy][0]; - s->mv[0][0][1] = s->p_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 0; + s->c.mv[0][0][0] = s->p_mv_table[xy][0]; + s->c.mv[0][0][1] = s->p_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, - &dmin, &next_block, s->mv[0][0][0], s->mv[0][0][1]); + &dmin, &next_block, s->c.mv[0][0][0], s->c.mv[0][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_INTER_I){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[0][i] = s->p_field_select_table[i][xy]; - s->mv[0][i][0] = s->p_field_mv_table[i][j][xy][0]; - s->mv[0][i][1] = s->p_field_mv_table[i][j][xy][1]; + int j = s->c.field_select[0][i] = s->p_field_select_table[i][xy]; + s->c.mv[0][i][0] = s->c.p_field_mv_table[i][j][xy][0]; + s->c.mv[0][i][1] = s->c.p_field_mv_table[i][j][xy][1]; } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_SKIPPED){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 0; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 0; + s->c.mv[0][0][0] = 0; + s->c.mv[0][0][1] = 0; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, - &dmin, &next_block, s->mv[0][0][0], s->mv[0][0][1]); + &dmin, &next_block, s->c.mv[0][0][0], s->c.mv[0][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_INTER4V){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_8X8; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_8X8; + s->c.mb_intra = 0; for(i=0; i<4; i++){ - s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0]; - s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1]; + s->c.mv[0][i][0] = s->c.cur_pic.motion_val[0][s->c.block_index[i]][0]; + s->c.mv[0][i][1] = s->c.cur_pic.motion_val[0][s->c.block_index[i]][1]; } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_FORWARD){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 0; - s->mv[0][0][0] = s->b_forw_mv_table[xy][0]; - s->mv[0][0][1] = s->b_forw_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 0; + s->c.mv[0][0][0] = s->b_forw_mv_table[xy][0]; + s->c.mv[0][0][1] = s->b_forw_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, - &dmin, &next_block, s->mv[0][0][0], s->mv[0][0][1]); + &dmin, &next_block, s->c.mv[0][0][0], s->c.mv[0][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_BACKWARD){ - s->mv_dir = MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 0; - s->mv[1][0][0] = s->b_back_mv_table[xy][0]; - s->mv[1][0][1] = s->b_back_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 0; + s->c.mv[1][0][0] = s->b_back_mv_table[xy][0]; + s->c.mv[1][0][1] = s->b_back_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, - &dmin, &next_block, s->mv[1][0][0], s->mv[1][0][1]); + &dmin, &next_block, s->c.mv[1][0][0], s->c.mv[1][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_BIDIR){ - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 0; - s->mv[0][0][0] = s->b_bidir_forw_mv_table[xy][0]; - s->mv[0][0][1] = s->b_bidir_forw_mv_table[xy][1]; - s->mv[1][0][0] = s->b_bidir_back_mv_table[xy][0]; - s->mv[1][0][1] = s->b_bidir_back_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 0; + s->c.mv[0][0][0] = s->b_bidir_forw_mv_table[xy][0]; + s->c.mv[0][0][1] = s->b_bidir_forw_mv_table[xy][1]; + s->c.mv[1][0][0] = s->b_bidir_back_mv_table[xy][0]; + s->c.mv[1][0][1] = s->b_bidir_back_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_FORWARD_I){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[0][i] = s->b_field_select_table[0][i][xy]; - s->mv[0][i][0] = s->b_field_mv_table[0][i][j][xy][0]; - s->mv[0][i][1] = s->b_field_mv_table[0][i][j][xy][1]; + int j = s->c.field_select[0][i] = s->b_field_select_table[0][i][xy]; + s->c.mv[0][i][0] = s->b_field_mv_table[0][i][j][xy][0]; + s->c.mv[0][i][1] = s->b_field_mv_table[0][i][j][xy][1]; } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_BACKWARD_I){ - s->mv_dir = MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[1][i] = s->b_field_select_table[1][i][xy]; - s->mv[1][i][0] = s->b_field_mv_table[1][i][j][xy][0]; - s->mv[1][i][1] = s->b_field_mv_table[1][i][j][xy][1]; + int j = s->c.field_select[1][i] = s->b_field_select_table[1][i][xy]; + s->c.mv[1][i][0] = s->b_field_mv_table[1][i][j][xy][0]; + s->c.mv[1][i][1] = s->b_field_mv_table[1][i][j][xy][1]; } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_BIDIR_I){ - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(dir=0; dir<2; dir++){ for(i=0; i<2; i++){ - j= s->field_select[dir][i] = s->b_field_select_table[dir][i][xy]; - s->mv[dir][i][0] = s->b_field_mv_table[dir][i][j][xy][0]; - s->mv[dir][i][1] = s->b_field_mv_table[dir][i][j][xy][1]; + int j = s->c.field_select[dir][i] = s->b_field_select_table[dir][i][xy]; + s->c.mv[dir][i][0] = s->b_field_mv_table[dir][i][j][xy][0]; + s->c.mv[dir][i][1] = s->b_field_mv_table[dir][i][j][xy][1]; } } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_INTRA){ - s->mv_dir = 0; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 1; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; + s->c.mv_dir = 0; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 1; + s->c.mv[0][0][0] = 0; + s->c.mv[0][0][1] = 0; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); - if(s->h263_pred || s->h263_aic){ - if(best_s.mb_intra) - s->mbintra_table[mb_x + mb_y*s->mb_stride]=1; - else - ff_clean_intra_table_entries(s); //old mode? - } + s->c.mbintra_table[xy] = 1; } if ((s->mpv_flags & FF_MPV_FLAG_QP_RD) && dmin < INT_MAX) { - if(best_s.mv_type==MV_TYPE_16X16){ //FIXME move 4mv after QPRD - const int last_qp= backup_s.qscale; + if (best_s.c.mv_type == MV_TYPE_16X16) { //FIXME move 4mv after QPRD + const int last_qp = backup_s.c.qscale; int qpi, qp, dc[6]; int16_t ac[6][16]; - const int mvdir= (best_s.mv_dir&MV_DIR_BACKWARD) ? 1 : 0; + const int mvdir = (best_s.c.mv_dir & MV_DIR_BACKWARD) ? 1 : 0; static const int dquant_tab[4]={-1,1,-2,2}; - int storecoefs = s->mb_intra && s->dc_val[0]; + int storecoefs = s->c.mb_intra && s->c.dc_val; av_assert2(backup_s.dquant == 0); //FIXME intra - s->mv_dir= best_s.mv_dir; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= best_s.mb_intra; - s->mv[0][0][0] = best_s.mv[0][0][0]; - s->mv[0][0][1] = best_s.mv[0][0][1]; - s->mv[1][0][0] = best_s.mv[1][0][0]; - s->mv[1][0][1] = best_s.mv[1][0][1]; + s->c.mv_dir = best_s.c.mv_dir; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = best_s.c.mb_intra; + s->c.mv[0][0][0] = best_s.c.mv[0][0][0]; + s->c.mv[0][0][1] = best_s.c.mv[0][0][1]; + s->c.mv[1][0][0] = best_s.c.mv[1][0][0]; + s->c.mv[1][0][1] = best_s.c.mv[1][0][1]; - qpi = s->pict_type == AV_PICTURE_TYPE_B ? 2 : 0; + qpi = s->c.pict_type == AV_PICTURE_TYPE_B ? 2 : 0; for(; qpi<4; qpi++){ int dquant= dquant_tab[qpi]; qp= last_qp + dquant; - if(qp < s->avctx->qmin || qp > s->avctx->qmax) + if (qp < s->c.avctx->qmin || qp > s->c.avctx->qmax) continue; backup_s.dquant= dquant; if(storecoefs){ for(i=0; i<6; i++){ - dc[i]= s->dc_val[0][ s->block_index[i] ]; - memcpy(ac[i], s->ac_val[0][s->block_index[i]], sizeof(int16_t)*16); + dc[i] = s->c.dc_val[s->c.block_index[i]]; + memcpy(ac[i], s->c.ac_val[s->c.block_index[i]], sizeof(*s->c.ac_val)); } } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, - &dmin, &next_block, s->mv[mvdir][0][0], s->mv[mvdir][0][1]); - if(best_s.qscale != qp){ + &dmin, &next_block, s->c.mv[mvdir][0][0], s->c.mv[mvdir][0][1]); + if (best_s.c.qscale != qp) { if(storecoefs){ for(i=0; i<6; i++){ - s->dc_val[0][ s->block_index[i] ]= dc[i]; - memcpy(s->ac_val[0][s->block_index[i]], ac[i], sizeof(int16_t)*16); + s->c.dc_val[s->c.block_index[i]] = dc[i]; + memcpy(s->c.ac_val[s->c.block_index[i]], ac[i], sizeof(*s->c.ac_val)); } } } @@ -3253,45 +3324,45 @@ static int encode_thread(AVCodecContext *c, void *arg){ int my= s->b_direct_mv_table[xy][1]; backup_s.dquant = 0; - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; - s->mb_intra= 0; - ff_mpeg4_set_direct_mv(s, mx, my); + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; + s->c.mb_intra = 0; + ff_mpeg4_set_direct_mv(&s->c, mx, my); encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, mx, my); } if(CONFIG_MPEG4_ENCODER && mb_type&CANDIDATE_MB_TYPE_DIRECT0){ backup_s.dquant = 0; - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; - s->mb_intra= 0; - ff_mpeg4_set_direct_mv(s, 0, 0); + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; + s->c.mb_intra = 0; + ff_mpeg4_set_direct_mv(&s->c, 0, 0); encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } - if (!best_s.mb_intra && s->mpv_flags & FF_MPV_FLAG_SKIP_RD) { + if (!best_s.c.mb_intra && s->mpv_flags & FF_MPV_FLAG_SKIP_RD) { int coded=0; for(i=0; i<6; i++) - coded |= s->block_last_index[i]; + coded |= s->c.block_last_index[i]; if(coded){ int mx,my; - memcpy(s->mv, best_s.mv, sizeof(s->mv)); - if(CONFIG_MPEG4_ENCODER && best_s.mv_dir & MV_DIRECT){ + memcpy(s->c.mv, best_s.c.mv, sizeof(s->c.mv)); + if (CONFIG_MPEG4_ENCODER && best_s.c.mv_dir & MV_DIRECT) { mx=my=0; //FIXME find the one we actually used - ff_mpeg4_set_direct_mv(s, mx, my); - }else if(best_s.mv_dir&MV_DIR_BACKWARD){ - mx= s->mv[1][0][0]; - my= s->mv[1][0][1]; + ff_mpeg4_set_direct_mv(&s->c, mx, my); + } else if (best_s.c.mv_dir & MV_DIR_BACKWARD) { + mx = s->c.mv[1][0][0]; + my = s->c.mv[1][0][1]; }else{ - mx= s->mv[0][0][0]; - my= s->mv[0][0][1]; + mx = s->c.mv[0][0][0]; + my = s->c.mv[0][0][1]; } - s->mv_dir= best_s.mv_dir; - s->mv_type = best_s.mv_type; - s->mb_intra= 0; -/* s->mv[0][0][0] = best_s.mv[0][0][0]; - s->mv[0][0][1] = best_s.mv[0][0][1]; - s->mv[1][0][0] = best_s.mv[1][0][0]; - s->mv[1][0][1] = best_s.mv[1][0][1];*/ + s->c.mv_dir = best_s.c.mv_dir; + s->c.mv_type = best_s.c.mv_type; + s->c.mb_intra = 0; +/* s->c.mv[0][0][0] = best_s.mv[0][0][0]; + s->c.mv[0][0][1] = best_s.mv[0][0][1]; + s->c.mv[1][0][0] = best_s.mv[1][0][0]; + s->c.mv[1][0][1] = best_s.mv[1][0][1];*/ backup_s.dquant= 0; s->skipdct=1; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, @@ -3300,16 +3371,14 @@ static int encode_thread(AVCodecContext *c, void *arg){ } } - s->cur_pic.qscale_table[xy] = best_s.qscale; - - copy_context_after_encode(s, &best_s); + store_context_after_encode(s, &best_s, s->data_partitioning); pb_bits_count= put_bits_count(&s->pb); flush_put_bits(&s->pb); ff_copy_bits(&backup_s.pb, bit_buf[next_block^1], pb_bits_count); s->pb= backup_s.pb; - if(s->data_partitioning){ + if (s->data_partitioning) { pb2_bits_count= put_bits_count(&s->pb2); flush_put_bits(&s->pb2); ff_copy_bits(&backup_s.pb2, bit_buf2[next_block^1], pb2_bits_count); @@ -3323,174 +3392,184 @@ static int encode_thread(AVCodecContext *c, void *arg){ s->last_bits= put_bits_count(&s->pb); if (CONFIG_H263_ENCODER && - s->out_format == FMT_H263 && s->pict_type!=AV_PICTURE_TYPE_B) + s->c.out_format == FMT_H263 && s->c.pict_type != AV_PICTURE_TYPE_B) ff_h263_update_mb(s); if(next_block==0){ //FIXME 16 vs linesize16 - s->hdsp.put_pixels_tab[0][0](s->dest[0], s->sc.rd_scratchpad , s->linesize ,16); - s->hdsp.put_pixels_tab[1][0](s->dest[1], s->sc.rd_scratchpad + 16*s->linesize , s->uvlinesize, 8); - s->hdsp.put_pixels_tab[1][0](s->dest[2], s->sc.rd_scratchpad + 16*s->linesize + 8, s->uvlinesize, 8); + s->c.hdsp.put_pixels_tab[0][0](s->c.dest[0], s->c.sc.rd_scratchpad , s->c.linesize ,16); + s->c.hdsp.put_pixels_tab[1][0](s->c.dest[1], s->c.sc.rd_scratchpad + 16*s->c.linesize , s->c.uvlinesize, 8); + s->c.hdsp.put_pixels_tab[1][0](s->c.dest[2], s->c.sc.rd_scratchpad + 16*s->c.linesize + 8, s->c.uvlinesize, 8); } - if(s->avctx->mb_decision == FF_MB_DECISION_BITS) + if (s->c.avctx->mb_decision == FF_MB_DECISION_BITS) mpv_reconstruct_mb(s, s->block); } else { int motion_x = 0, motion_y = 0; - s->mv_type=MV_TYPE_16X16; + s->c.mv_type = MV_TYPE_16X16; // only one MB-Type possible switch(mb_type){ case CANDIDATE_MB_TYPE_INTRA: - s->mv_dir = 0; - s->mb_intra= 1; - motion_x= s->mv[0][0][0] = 0; - motion_y= s->mv[0][0][1] = 0; + s->c.mv_dir = 0; + s->c.mb_intra = 1; + motion_x= s->c.mv[0][0][0] = 0; + motion_y= s->c.mv[0][0][1] = 0; + s->c.mbintra_table[xy] = 1; break; case CANDIDATE_MB_TYPE_INTER: - s->mv_dir = MV_DIR_FORWARD; - s->mb_intra= 0; - motion_x= s->mv[0][0][0] = s->p_mv_table[xy][0]; - motion_y= s->mv[0][0][1] = s->p_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mb_intra = 0; + motion_x= s->c.mv[0][0][0] = s->p_mv_table[xy][0]; + motion_y= s->c.mv[0][0][1] = s->p_mv_table[xy][1]; break; case CANDIDATE_MB_TYPE_INTER_I: - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[0][i] = s->p_field_select_table[i][xy]; - s->mv[0][i][0] = s->p_field_mv_table[i][j][xy][0]; - s->mv[0][i][1] = s->p_field_mv_table[i][j][xy][1]; + int j = s->c.field_select[0][i] = s->p_field_select_table[i][xy]; + s->c.mv[0][i][0] = s->c.p_field_mv_table[i][j][xy][0]; + s->c.mv[0][i][1] = s->c.p_field_mv_table[i][j][xy][1]; } break; case CANDIDATE_MB_TYPE_INTER4V: - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_8X8; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_8X8; + s->c.mb_intra = 0; for(i=0; i<4; i++){ - s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0]; - s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1]; + s->c.mv[0][i][0] = s->c.cur_pic.motion_val[0][s->c.block_index[i]][0]; + s->c.mv[0][i][1] = s->c.cur_pic.motion_val[0][s->c.block_index[i]][1]; } break; case CANDIDATE_MB_TYPE_DIRECT: if (CONFIG_MPEG4_ENCODER) { - s->mv_dir = MV_DIR_FORWARD|MV_DIR_BACKWARD|MV_DIRECT; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD|MV_DIR_BACKWARD|MV_DIRECT; + s->c.mb_intra = 0; motion_x=s->b_direct_mv_table[xy][0]; motion_y=s->b_direct_mv_table[xy][1]; - ff_mpeg4_set_direct_mv(s, motion_x, motion_y); + ff_mpeg4_set_direct_mv(&s->c, motion_x, motion_y); } break; case CANDIDATE_MB_TYPE_DIRECT0: if (CONFIG_MPEG4_ENCODER) { - s->mv_dir = MV_DIR_FORWARD|MV_DIR_BACKWARD|MV_DIRECT; - s->mb_intra= 0; - ff_mpeg4_set_direct_mv(s, 0, 0); + s->c.mv_dir = MV_DIR_FORWARD|MV_DIR_BACKWARD|MV_DIRECT; + s->c.mb_intra = 0; + ff_mpeg4_set_direct_mv(&s->c, 0, 0); } break; case CANDIDATE_MB_TYPE_BIDIR: - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; - s->mb_intra= 0; - s->mv[0][0][0] = s->b_bidir_forw_mv_table[xy][0]; - s->mv[0][0][1] = s->b_bidir_forw_mv_table[xy][1]; - s->mv[1][0][0] = s->b_bidir_back_mv_table[xy][0]; - s->mv[1][0][1] = s->b_bidir_back_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; + s->c.mb_intra = 0; + s->c.mv[0][0][0] = s->b_bidir_forw_mv_table[xy][0]; + s->c.mv[0][0][1] = s->b_bidir_forw_mv_table[xy][1]; + s->c.mv[1][0][0] = s->b_bidir_back_mv_table[xy][0]; + s->c.mv[1][0][1] = s->b_bidir_back_mv_table[xy][1]; break; case CANDIDATE_MB_TYPE_BACKWARD: - s->mv_dir = MV_DIR_BACKWARD; - s->mb_intra= 0; - motion_x= s->mv[1][0][0] = s->b_back_mv_table[xy][0]; - motion_y= s->mv[1][0][1] = s->b_back_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_BACKWARD; + s->c.mb_intra = 0; + motion_x= s->c.mv[1][0][0] = s->b_back_mv_table[xy][0]; + motion_y= s->c.mv[1][0][1] = s->b_back_mv_table[xy][1]; break; case CANDIDATE_MB_TYPE_FORWARD: - s->mv_dir = MV_DIR_FORWARD; - s->mb_intra= 0; - motion_x= s->mv[0][0][0] = s->b_forw_mv_table[xy][0]; - motion_y= s->mv[0][0][1] = s->b_forw_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mb_intra = 0; + motion_x= s->c.mv[0][0][0] = s->b_forw_mv_table[xy][0]; + motion_y= s->c.mv[0][0][1] = s->b_forw_mv_table[xy][1]; break; case CANDIDATE_MB_TYPE_FORWARD_I: - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[0][i] = s->b_field_select_table[0][i][xy]; - s->mv[0][i][0] = s->b_field_mv_table[0][i][j][xy][0]; - s->mv[0][i][1] = s->b_field_mv_table[0][i][j][xy][1]; + int j = s->c.field_select[0][i] = s->b_field_select_table[0][i][xy]; + s->c.mv[0][i][0] = s->b_field_mv_table[0][i][j][xy][0]; + s->c.mv[0][i][1] = s->b_field_mv_table[0][i][j][xy][1]; } break; case CANDIDATE_MB_TYPE_BACKWARD_I: - s->mv_dir = MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[1][i] = s->b_field_select_table[1][i][xy]; - s->mv[1][i][0] = s->b_field_mv_table[1][i][j][xy][0]; - s->mv[1][i][1] = s->b_field_mv_table[1][i][j][xy][1]; + int j = s->c.field_select[1][i] = s->b_field_select_table[1][i][xy]; + s->c.mv[1][i][0] = s->b_field_mv_table[1][i][j][xy][0]; + s->c.mv[1][i][1] = s->b_field_mv_table[1][i][j][xy][1]; } break; case CANDIDATE_MB_TYPE_BIDIR_I: - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(dir=0; dir<2; dir++){ for(i=0; i<2; i++){ - j= s->field_select[dir][i] = s->b_field_select_table[dir][i][xy]; - s->mv[dir][i][0] = s->b_field_mv_table[dir][i][j][xy][0]; - s->mv[dir][i][1] = s->b_field_mv_table[dir][i][j][xy][1]; + int j = s->c.field_select[dir][i] = s->b_field_select_table[dir][i][xy]; + s->c.mv[dir][i][0] = s->b_field_mv_table[dir][i][j][xy][0]; + s->c.mv[dir][i][1] = s->b_field_mv_table[dir][i][j][xy][1]; } } break; default: - av_log(s->avctx, AV_LOG_ERROR, "illegal MB type\n"); + av_unreachable("There is a case for every CANDIDATE_MB_TYPE_* " + "except CANDIDATE_MB_TYPE_SKIPPED which is never " + "the only candidate (always coupled with INTER) " + "so that it never reaches this switch"); } encode_mb(s, motion_x, motion_y); // RAL: Update last macroblock type - s->last_mv_dir = s->mv_dir; + s->last_mv_dir = s->c.mv_dir; if (CONFIG_H263_ENCODER && - s->out_format == FMT_H263 && s->pict_type!=AV_PICTURE_TYPE_B) + s->c.out_format == FMT_H263 && s->c.pict_type != AV_PICTURE_TYPE_B) ff_h263_update_mb(s); mpv_reconstruct_mb(s, s->block); } + s->c.cur_pic.qscale_table[xy] = s->c.qscale; + /* clean the MV table in IPS frames for direct mode in B-frames */ - if(s->mb_intra /* && I,P,S_TYPE */){ + if (s->c.mb_intra /* && I,P,S_TYPE */) { s->p_mv_table[xy][0]=0; s->p_mv_table[xy][1]=0; +#if CONFIG_H263_ENCODER + } else if (s->c.h263_pred || s->c.h263_aic) { + ff_h263_clean_intra_table_entries(&s->c, xy); +#endif } - if (s->avctx->flags & AV_CODEC_FLAG_PSNR) { + if (s->c.avctx->flags & AV_CODEC_FLAG_PSNR) { int w= 16; int h= 16; - if(s->mb_x*16 + 16 > s->width ) w= s->width - s->mb_x*16; - if(s->mb_y*16 + 16 > s->height) h= s->height- s->mb_y*16; + if (s->c.mb_x*16 + 16 > s->c.width ) w = s->c.width - s->c.mb_x*16; + if (s->c.mb_y*16 + 16 > s->c.height) h = s->c.height- s->c.mb_y*16; s->encoding_error[0] += sse( - s, s->new_pic->data[0] + s->mb_x*16 + s->mb_y*s->linesize*16, - s->dest[0], w, h, s->linesize); + s, s->new_pic->data[0] + s->c.mb_x*16 + s->c.mb_y*s->c.linesize*16, + s->c.dest[0], w, h, s->c.linesize); s->encoding_error[1] += sse( - s, s->new_pic->data[1] + s->mb_x*8 + s->mb_y*s->uvlinesize*chr_h, - s->dest[1], w>>1, h>>s->chroma_y_shift, s->uvlinesize); + s, s->new_pic->data[1] + s->c.mb_x*8 + s->c.mb_y*s->c.uvlinesize*chr_h, + s->c.dest[1], w>>1, h>>s->c.chroma_y_shift, s->c.uvlinesize); s->encoding_error[2] += sse( - s, s->new_pic->data[2] + s->mb_x*8 + s->mb_y*s->uvlinesize*chr_h, - s->dest[2], w>>1, h>>s->chroma_y_shift, s->uvlinesize); + s, s->new_pic->data[2] + s->c.mb_x*8 + s->c.mb_y*s->c.uvlinesize*chr_h, + s->c.dest[2], w>>1, h>>s->c.chroma_y_shift, s->c.uvlinesize); } - if(s->loop_filter){ - if(CONFIG_H263_ENCODER && s->out_format == FMT_H263) - ff_h263_loop_filter(s); + if (s->loop_filter) { + if (CONFIG_H263_ENCODER && s->c.out_format == FMT_H263) + ff_h263_loop_filter(&s->c); } - ff_dlog(s->avctx, "MB %d %d bits\n", - s->mb_x + s->mb_y * s->mb_stride, put_bits_count(&s->pb)); + ff_dlog(s->c.avctx, "MB %d %d bits\n", + s->c.mb_x + s->c.mb_y * s->c.mb_stride, put_bits_count(&s->pb)); } } #if CONFIG_MSMPEG4ENC //not beautiful here but we must write it before flushing so it has to be here - if (s->msmpeg4_version != MSMP4_UNUSED && s->msmpeg4_version < MSMP4_WMV1 && - s->pict_type == AV_PICTURE_TYPE_I) + if (s->c.msmpeg4_version != MSMP4_UNUSED && s->c.msmpeg4_version < MSMP4_WMV1 && + s->c.pict_type == AV_PICTURE_TYPE_I) ff_msmpeg4_encode_ext_header(s); #endif @@ -3499,28 +3578,31 @@ static int encode_thread(AVCodecContext *c, void *arg){ return 0; } +#define ADD(field) dst->field += src->field; #define MERGE(field) dst->field += src->field; src->field=0 -static void merge_context_after_me(MpegEncContext *dst, MpegEncContext *src){ - MERGE(me.scene_change_score); - MERGE(me.mc_mb_var_sum_temp); - MERGE(me.mb_var_sum_temp); +static void merge_context_after_me(MPVEncContext *const dst, MPVEncContext *const src) +{ + ADD(me.scene_change_score); + ADD(me.mc_mb_var_sum_temp); + ADD(me.mb_var_sum_temp); } -static void merge_context_after_encode(MpegEncContext *dst, MpegEncContext *src){ +static void merge_context_after_encode(MPVEncContext *const dst, MPVEncContext *const src) +{ int i; MERGE(dct_count[0]); //note, the other dct vars are not part of the context MERGE(dct_count[1]); - MERGE(mv_bits); - MERGE(i_tex_bits); - MERGE(p_tex_bits); - MERGE(i_count); - MERGE(misc_bits); - MERGE(encoding_error[0]); - MERGE(encoding_error[1]); - MERGE(encoding_error[2]); + ADD(mv_bits); + ADD(i_tex_bits); + ADD(p_tex_bits); + ADD(i_count); + ADD(misc_bits); + ADD(encoding_error[0]); + ADD(encoding_error[1]); + ADD(encoding_error[2]); - if (dst->noise_reduction){ + if (dst->dct_error_sum) { for(i=0; i<64; i++){ MERGE(dct_error_sum[0][i]); MERGE(dct_error_sum[1][i]); @@ -3533,21 +3615,24 @@ static void merge_context_after_encode(MpegEncContext *dst, MpegEncContext *src) flush_put_bits(&dst->pb); } -static int estimate_qp(MpegEncContext *s, int dry_run){ - if (s->next_lambda){ - s->cur_pic.ptr->f->quality = s->next_lambda; - if(!dry_run) s->next_lambda= 0; - } else if (!s->fixed_qscale) { - int quality = ff_rate_estimate_qscale(s, dry_run); - s->cur_pic.ptr->f->quality = quality; - if (s->cur_pic.ptr->f->quality < 0) +static int estimate_qp(MPVMainEncContext *const m, int dry_run) +{ + MPVEncContext *const s = &m->s; + + if (m->next_lambda){ + s->c.cur_pic.ptr->f->quality = m->next_lambda; + if(!dry_run) m->next_lambda= 0; + } else if (!m->fixed_qscale) { + int quality = ff_rate_estimate_qscale(m, dry_run); + s->c.cur_pic.ptr->f->quality = quality; + if (s->c.cur_pic.ptr->f->quality < 0) return -1; } if(s->adaptive_quant){ init_qscale_tab(s); - switch(s->codec_id){ + switch (s->c.codec_id) { case AV_CODEC_ID_MPEG4: if (CONFIG_MPEG4_ENCODER) ff_clean_mpeg4_qscales(s); @@ -3560,174 +3645,166 @@ static int estimate_qp(MpegEncContext *s, int dry_run){ break; } - s->lambda= s->lambda_table[0]; + s->lambda = s->lambda_table[0]; //FIXME broken }else - s->lambda = s->cur_pic.ptr->f->quality; - update_qscale(s); + s->lambda = s->c.cur_pic.ptr->f->quality; + update_qscale(m); return 0; } /* must be called before writing the header */ -static void set_frame_distances(MpegEncContext * s){ - av_assert1(s->cur_pic.ptr->f->pts != AV_NOPTS_VALUE); - s->time = s->cur_pic.ptr->f->pts * s->avctx->time_base.num; +static void set_frame_distances(MPVEncContext *const s) +{ + av_assert1(s->c.cur_pic.ptr->f->pts != AV_NOPTS_VALUE); + s->c.time = s->c.cur_pic.ptr->f->pts * s->c.avctx->time_base.num; - if(s->pict_type==AV_PICTURE_TYPE_B){ - s->pb_time= s->pp_time - (s->last_non_b_time - s->time); - av_assert1(s->pb_time > 0 && s->pb_time < s->pp_time); + if (s->c.pict_type == AV_PICTURE_TYPE_B) { + s->c.pb_time = s->c.pp_time - (s->c.last_non_b_time - s->c.time); + av_assert1(s->c.pb_time > 0 && s->c.pb_time < s->c.pp_time); }else{ - s->pp_time= s->time - s->last_non_b_time; - s->last_non_b_time= s->time; - av_assert1(s->picture_number==0 || s->pp_time > 0); + s->c.pp_time = s->c.time - s->c.last_non_b_time; + s->c.last_non_b_time = s->c.time; + av_assert1(s->picture_number == 0 || s->c.pp_time > 0); } } -static int encode_picture(MpegEncContext *s, const AVPacket *pkt) +static int encode_picture(MPVMainEncContext *const m, const AVPacket *pkt) { + MPVEncContext *const s = &m->s; int i, ret; int bits; - int context_count = s->slice_context_count; - - /* Reset the average MB variance */ - s->me.mb_var_sum_temp = - s->me.mc_mb_var_sum_temp = 0; + int context_count = s->c.slice_context_count; /* we need to initialize some time vars before we can encode B-frames */ // RAL: Condition added for MPEG1VIDEO - if (s->out_format == FMT_MPEG1 || (s->h263_pred && s->msmpeg4_version == MSMP4_UNUSED)) + if (s->c.out_format == FMT_MPEG1 || (s->c.h263_pred && s->c.msmpeg4_version == MSMP4_UNUSED)) set_frame_distances(s); - if(CONFIG_MPEG4_ENCODER && s->codec_id == AV_CODEC_ID_MPEG4) + if (CONFIG_MPEG4_ENCODER && s->c.codec_id == AV_CODEC_ID_MPEG4) ff_set_mpeg4_time(s); - s->me.scene_change_score=0; +// s->lambda = s->c.cur_pic.ptr->quality; //FIXME qscale / ... stuff for ME rate distortion -// s->lambda= s->cur_pic.ptr->quality; //FIXME qscale / ... stuff for ME rate distortion - - if(s->pict_type==AV_PICTURE_TYPE_I){ - s->no_rounding = s->msmpeg4_version >= MSMP4_V3; - }else if(s->pict_type!=AV_PICTURE_TYPE_B){ - s->no_rounding ^= s->flipflop_rounding; + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + s->c.no_rounding = s->c.msmpeg4_version >= MSMP4_V3; + } else if (s->c.pict_type != AV_PICTURE_TYPE_B) { + s->c.no_rounding ^= s->flipflop_rounding; } - if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { - if (estimate_qp(s,1) < 0) - return -1; - ff_get_2pass_fcode(s); - } else if (!(s->avctx->flags & AV_CODEC_FLAG_QSCALE)) { - if(s->pict_type==AV_PICTURE_TYPE_B) - s->lambda= s->last_lambda_for[s->pict_type]; + if (s->c.avctx->flags & AV_CODEC_FLAG_PASS2) { + ret = estimate_qp(m, 1); + if (ret < 0) + return ret; + ff_get_2pass_fcode(m); + } else if (!(s->c.avctx->flags & AV_CODEC_FLAG_QSCALE)) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) + s->lambda = m->last_lambda_for[s->c.pict_type]; else - s->lambda= s->last_lambda_for[s->last_non_b_pict_type]; - update_qscale(s); + s->lambda = m->last_lambda_for[m->last_non_b_pict_type]; + update_qscale(m); } - if (s->out_format != FMT_MJPEG) { - if(s->q_chroma_intra_matrix != s->q_intra_matrix ) av_freep(&s->q_chroma_intra_matrix); - if(s->q_chroma_intra_matrix16 != s->q_intra_matrix16) av_freep(&s->q_chroma_intra_matrix16); - s->q_chroma_intra_matrix = s->q_intra_matrix; - s->q_chroma_intra_matrix16 = s->q_intra_matrix16; - } - - ff_me_init_pic(s); - - s->mb_intra=0; //for the rate distortion & bit compare functions + s->c.mb_intra = 0; //for the rate distortion & bit compare functions for (int i = 0; i < context_count; i++) { - MpegEncContext *const slice = s->thread_context[i]; - uint8_t *start, *end; - int h; + MPVEncContext *const slice = s->c.enc_contexts[i]; + int h = s->c.mb_height; + uint8_t *start = pkt->data + (int64_t)pkt->size * slice->c.start_mb_y / h; + uint8_t *end = pkt->data + (int64_t)pkt->size * slice->c. end_mb_y / h; + + init_put_bits(&slice->pb, start, end - start); if (i) { - ret = ff_update_duplicate_context(slice, s); + ret = ff_update_duplicate_context(&slice->c, &s->c); if (ret < 0) return ret; + slice->lambda = s->lambda; + slice->lambda2 = s->lambda2; } - slice->me.temp = slice->me.scratchpad = slice->sc.scratchpad_buf; - - h = s->mb_height; - start = pkt->data + (size_t)(((int64_t) pkt->size) * slice->start_mb_y / h); - end = pkt->data + (size_t)(((int64_t) pkt->size) * slice-> end_mb_y / h); - - init_put_bits(&s->thread_context[i]->pb, start, end - start); + slice->me.temp = slice->me.scratchpad = slice->c.sc.scratchpad_buf; + ff_me_init_pic(slice); } /* Estimate motion for every MB */ - if(s->pict_type != AV_PICTURE_TYPE_I){ - s->lambda = (s->lambda * s->me_penalty_compensation + 128) >> 8; - s->lambda2 = (s->lambda2 * (int64_t) s->me_penalty_compensation + 128) >> 8; - if (s->pict_type != AV_PICTURE_TYPE_B) { - if ((s->me_pre && s->last_non_b_pict_type == AV_PICTURE_TYPE_I) || - s->me_pre == 2) { - s->avctx->execute(s->avctx, pre_estimate_motion_thread, &s->thread_context[0], NULL, context_count, sizeof(void*)); + if (s->c.pict_type != AV_PICTURE_TYPE_I) { + s->lambda = (s->lambda * m->me_penalty_compensation + 128) >> 8; + s->lambda2 = (s->lambda2 * (int64_t) m->me_penalty_compensation + 128) >> 8; + if (s->c.pict_type != AV_PICTURE_TYPE_B) { + if ((m->me_pre && m->last_non_b_pict_type == AV_PICTURE_TYPE_I) || + m->me_pre == 2) { + s->c.avctx->execute(s->c.avctx, pre_estimate_motion_thread, + &s->c.enc_contexts[0], NULL, + context_count, sizeof(void*)); } } - s->avctx->execute(s->avctx, estimate_motion_thread, &s->thread_context[0], NULL, context_count, sizeof(void*)); - }else /* if(s->pict_type == AV_PICTURE_TYPE_I) */{ + s->c.avctx->execute(s->c.avctx, estimate_motion_thread, &s->c.enc_contexts[0], + NULL, context_count, sizeof(void*)); + }else /* if (s->c.pict_type == AV_PICTURE_TYPE_I) */{ /* I-Frame */ - for(i=0; imb_stride*s->mb_height; i++) + for (int i = 0; i < s->c.mb_stride * s->c.mb_height; i++) s->mb_type[i]= CANDIDATE_MB_TYPE_INTRA; - if(!s->fixed_qscale){ + if (!m->fixed_qscale) { /* finding spatial complexity for I-frame rate control */ - s->avctx->execute(s->avctx, mb_var_thread, &s->thread_context[0], NULL, context_count, sizeof(void*)); + s->c.avctx->execute(s->c.avctx, mb_var_thread, &s->c.enc_contexts[0], + NULL, context_count, sizeof(void*)); } } for(i=1; ithread_context[i]); + merge_context_after_me(s, s->c.enc_contexts[i]); } - s->mc_mb_var_sum = s->me.mc_mb_var_sum_temp; - s->mb_var_sum = s->me. mb_var_sum_temp; + m->mc_mb_var_sum = s->me.mc_mb_var_sum_temp; + m->mb_var_sum = s->me. mb_var_sum_temp; emms_c(); - if (s->me.scene_change_score > s->scenechange_threshold && - s->pict_type == AV_PICTURE_TYPE_P) { - s->pict_type= AV_PICTURE_TYPE_I; - for(i=0; imb_stride*s->mb_height; i++) - s->mb_type[i]= CANDIDATE_MB_TYPE_INTRA; - if (s->msmpeg4_version >= MSMP4_V3) - s->no_rounding=1; - ff_dlog(s, "Scene change detected, encoding as I Frame %"PRId64" %"PRId64"\n", - s->mb_var_sum, s->mc_mb_var_sum); + if (s->me.scene_change_score > m->scenechange_threshold && + s->c.pict_type == AV_PICTURE_TYPE_P) { + s->c.pict_type = AV_PICTURE_TYPE_I; + for (int i = 0; i < s->c.mb_stride * s->c.mb_height; i++) + s->mb_type[i] = CANDIDATE_MB_TYPE_INTRA; + if (s->c.msmpeg4_version >= MSMP4_V3) + s->c.no_rounding = 1; + ff_dlog(s->c.avctx, "Scene change detected, encoding as I Frame %"PRId64" %"PRId64"\n", + m->mb_var_sum, m->mc_mb_var_sum); } - if(!s->umvplus){ - if(s->pict_type==AV_PICTURE_TYPE_P || s->pict_type==AV_PICTURE_TYPE_S) { - s->f_code= ff_get_best_fcode(s, s->p_mv_table, CANDIDATE_MB_TYPE_INTER); + if (!s->umvplus) { + if (s->c.pict_type == AV_PICTURE_TYPE_P || s->c.pict_type == AV_PICTURE_TYPE_S) { + s->f_code = ff_get_best_fcode(m, s->p_mv_table, CANDIDATE_MB_TYPE_INTER); - if (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { + if (s->c.avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { int a,b; - a= ff_get_best_fcode(s, s->p_field_mv_table[0][0], CANDIDATE_MB_TYPE_INTER_I); //FIXME field_select - b= ff_get_best_fcode(s, s->p_field_mv_table[1][1], CANDIDATE_MB_TYPE_INTER_I); - s->f_code= FFMAX3(s->f_code, a, b); + a = ff_get_best_fcode(m, s->c.p_field_mv_table[0][0], CANDIDATE_MB_TYPE_INTER_I); //FIXME field_select + b = ff_get_best_fcode(m, s->c.p_field_mv_table[1][1], CANDIDATE_MB_TYPE_INTER_I); + s->f_code = FFMAX3(s->f_code, a, b); } ff_fix_long_p_mvs(s, s->intra_penalty ? CANDIDATE_MB_TYPE_INTER : CANDIDATE_MB_TYPE_INTRA); ff_fix_long_mvs(s, NULL, 0, s->p_mv_table, s->f_code, CANDIDATE_MB_TYPE_INTER, !!s->intra_penalty); - if (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { + if (s->c.avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { int j; for(i=0; i<2; i++){ for(j=0; j<2; j++) ff_fix_long_mvs(s, s->p_field_select_table[i], j, - s->p_field_mv_table[i][j], s->f_code, CANDIDATE_MB_TYPE_INTER_I, !!s->intra_penalty); + s->c.p_field_mv_table[i][j], s->f_code, CANDIDATE_MB_TYPE_INTER_I, !!s->intra_penalty); } } - } else if (s->pict_type == AV_PICTURE_TYPE_B) { + } else if (s->c.pict_type == AV_PICTURE_TYPE_B) { int a, b; - a = ff_get_best_fcode(s, s->b_forw_mv_table, CANDIDATE_MB_TYPE_FORWARD); - b = ff_get_best_fcode(s, s->b_bidir_forw_mv_table, CANDIDATE_MB_TYPE_BIDIR); + a = ff_get_best_fcode(m, s->b_forw_mv_table, CANDIDATE_MB_TYPE_FORWARD); + b = ff_get_best_fcode(m, s->b_bidir_forw_mv_table, CANDIDATE_MB_TYPE_BIDIR); s->f_code = FFMAX(a, b); - a = ff_get_best_fcode(s, s->b_back_mv_table, CANDIDATE_MB_TYPE_BACKWARD); - b = ff_get_best_fcode(s, s->b_bidir_back_mv_table, CANDIDATE_MB_TYPE_BIDIR); + a = ff_get_best_fcode(m, s->b_back_mv_table, CANDIDATE_MB_TYPE_BACKWARD); + b = ff_get_best_fcode(m, s->b_bidir_back_mv_table, CANDIDATE_MB_TYPE_BIDIR); s->b_code = FFMAX(a, b); ff_fix_long_mvs(s, NULL, 0, s->b_forw_mv_table, s->f_code, CANDIDATE_MB_TYPE_FORWARD, 1); ff_fix_long_mvs(s, NULL, 0, s->b_back_mv_table, s->b_code, CANDIDATE_MB_TYPE_BACKWARD, 1); ff_fix_long_mvs(s, NULL, 0, s->b_bidir_forw_mv_table, s->f_code, CANDIDATE_MB_TYPE_BIDIR, 1); ff_fix_long_mvs(s, NULL, 0, s->b_bidir_back_mv_table, s->b_code, CANDIDATE_MB_TYPE_BIDIR, 1); - if (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { + if (s->c.avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { int dir, j; for(dir=0; dir<2; dir++){ for(i=0; i<2; i++){ @@ -3743,160 +3820,106 @@ static int encode_picture(MpegEncContext *s, const AVPacket *pkt) } } - if (estimate_qp(s, 0) < 0) - return -1; + ret = estimate_qp(m, 0); + if (ret < 0) + return ret; - if (s->qscale < 3 && s->max_qcoeff <= 128 && - s->pict_type == AV_PICTURE_TYPE_I && - !(s->avctx->flags & AV_CODEC_FLAG_QSCALE)) - s->qscale= 3; //reduce clipping problems + if (s->c.qscale < 3 && s->max_qcoeff <= 128 && + s->c.pict_type == AV_PICTURE_TYPE_I && + !(s->c.avctx->flags & AV_CODEC_FLAG_QSCALE)) + s->c.qscale = 3; //reduce clipping problems - if (s->out_format == FMT_MJPEG) { - const uint16_t * luma_matrix = ff_mpeg1_default_intra_matrix; - const uint16_t *chroma_matrix = ff_mpeg1_default_intra_matrix; + if (s->c.out_format == FMT_MJPEG) { + ret = ff_check_codec_matrices(s->c.avctx, FF_MATRIX_TYPE_INTRA | FF_MATRIX_TYPE_CHROMA_INTRA, + (7 + s->c.qscale) / s->c.qscale, 65535); + if (ret < 0) + return ret; - if (s->avctx->intra_matrix) { - chroma_matrix = - luma_matrix = s->avctx->intra_matrix; - } - if (s->avctx->chroma_intra_matrix) - chroma_matrix = s->avctx->chroma_intra_matrix; + if (s->c.codec_id != AV_CODEC_ID_AMV) { + const uint16_t * luma_matrix = ff_mpeg1_default_intra_matrix; + const uint16_t *chroma_matrix = ff_mpeg1_default_intra_matrix; - /* for mjpeg, we do include qscale in the matrix */ - for(i=1;i<64;i++){ - int j = s->idsp.idct_permutation[i]; + if (s->c.avctx->intra_matrix) { + chroma_matrix = + luma_matrix = s->c.avctx->intra_matrix; + } + if (s->c.avctx->chroma_intra_matrix) + chroma_matrix = s->c.avctx->chroma_intra_matrix; - s->chroma_intra_matrix[j] = av_clip_uint8((chroma_matrix[i] * s->qscale) >> 3); - s-> intra_matrix[j] = av_clip_uint8(( luma_matrix[i] * s->qscale) >> 3); - } - s->y_dc_scale_table= - s->c_dc_scale_table = ff_mpeg12_dc_scale_table[s->intra_dc_precision]; - s->chroma_intra_matrix[0] = - s->intra_matrix[0] = ff_mpeg12_dc_scale_table[s->intra_dc_precision][8]; - ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16, - s->intra_matrix, s->intra_quant_bias, 8, 8, 1); - ff_convert_matrix(s, s->q_chroma_intra_matrix, s->q_chroma_intra_matrix16, - s->chroma_intra_matrix, s->intra_quant_bias, 8, 8, 1); - s->qscale= 8; + /* for mjpeg, we do include qscale in the matrix */ + for (int i = 1; i < 64; i++) { + int j = s->c.idsp.idct_permutation[i]; - if (s->codec_id == AV_CODEC_ID_AMV) { + s->c.chroma_intra_matrix[j] = av_clip_uint8((chroma_matrix[i] * s->c.qscale) >> 3); + s->c. intra_matrix[j] = av_clip_uint8(( luma_matrix[i] * s->c.qscale) >> 3); + } + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_mpeg12_dc_scale_table[0]; + s->c.chroma_intra_matrix[0] = s->c.intra_matrix[0] = 8; + } else { static const uint8_t y[32] = {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}; static const uint8_t c[32] = {14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14}; for (int i = 1; i < 64; i++) { - int j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; + int j = s->c.idsp.idct_permutation[ff_zigzag_direct[i]]; - s->intra_matrix[j] = sp5x_qscale_five_quant_table[0][i]; - s->chroma_intra_matrix[j] = sp5x_qscale_five_quant_table[1][i]; + s->c.intra_matrix[j] = sp5x_qscale_five_quant_table[0][i]; + s->c.chroma_intra_matrix[j] = sp5x_qscale_five_quant_table[1][i]; } - s->y_dc_scale_table = y; - s->c_dc_scale_table = c; - s->intra_matrix[0] = 13; - s->chroma_intra_matrix[0] = 14; - ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16, - s->intra_matrix, s->intra_quant_bias, 8, 8, 1); - ff_convert_matrix(s, s->q_chroma_intra_matrix, s->q_chroma_intra_matrix16, - s->chroma_intra_matrix, s->intra_quant_bias, 8, 8, 1); - s->qscale = 8; + s->c.y_dc_scale_table = y; + s->c.c_dc_scale_table = c; + s->c.intra_matrix[0] = 13; + s->c.chroma_intra_matrix[0] = 14; } + ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16, + s->c.intra_matrix, s->intra_quant_bias, 8, 8, 1); + ff_convert_matrix(s, s->q_chroma_intra_matrix, s->q_chroma_intra_matrix16, + s->c.chroma_intra_matrix, s->intra_quant_bias, 8, 8, 1); + s->c.qscale = 8; } - if (s->pict_type == AV_PICTURE_TYPE_I) { - s->cur_pic.ptr->f->flags |= AV_FRAME_FLAG_KEY; + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + s->c.cur_pic.ptr->f->flags |= AV_FRAME_FLAG_KEY; } else { - s->cur_pic.ptr->f->flags &= ~AV_FRAME_FLAG_KEY; + s->c.cur_pic.ptr->f->flags &= ~AV_FRAME_FLAG_KEY; } - s->cur_pic.ptr->f->pict_type = s->pict_type; + s->c.cur_pic.ptr->f->pict_type = s->c.pict_type; - if (s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY) - s->picture_in_gop_number=0; + if (s->c.cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY) + m->picture_in_gop_number = 0; - s->mb_x = s->mb_y = 0; + s->c.mb_x = s->c.mb_y = 0; s->last_bits= put_bits_count(&s->pb); - switch(s->out_format) { -#if CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER - case FMT_MJPEG: - ff_mjpeg_amv_encode_picture_header(s); - break; -#endif - case FMT_SPEEDHQ: - if (CONFIG_SPEEDHQ_ENCODER) - ff_speedhq_encode_picture_header(s); - break; - case FMT_H261: - if (CONFIG_H261_ENCODER) - ff_h261_encode_picture_header(s); - break; - case FMT_H263: - if (CONFIG_WMV2_ENCODER && s->codec_id == AV_CODEC_ID_WMV2) - ff_wmv2_encode_picture_header(s); -#if CONFIG_MSMPEG4ENC - else if (s->msmpeg4_version != MSMP4_UNUSED) - ff_msmpeg4_encode_picture_header(s); -#endif - else if (CONFIG_MPEG4_ENCODER && s->h263_pred) { - ret = ff_mpeg4_encode_picture_header(s); - if (ret < 0) - return ret; - } else if (CONFIG_RV10_ENCODER && s->codec_id == AV_CODEC_ID_RV10) { - ret = ff_rv10_encode_picture_header(s); - if (ret < 0) - return ret; - } - else if (CONFIG_RV20_ENCODER && s->codec_id == AV_CODEC_ID_RV20) - ff_rv20_encode_picture_header(s); - else if (CONFIG_FLV_ENCODER && s->codec_id == AV_CODEC_ID_FLV1) - ff_flv_encode_picture_header(s); - else if (CONFIG_H263_ENCODER) - ff_h263_encode_picture_header(s); - break; - case FMT_MPEG1: - if (CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER) - ff_mpeg1_encode_picture_header(s); - break; - default: - av_assert0(0); - } + ret = m->encode_picture_header(m); + if (ret < 0) + return ret; bits= put_bits_count(&s->pb); - s->header_bits= bits - s->last_bits; + m->header_bits = bits - s->last_bits; for(i=1; ithread_context[i], s); + update_duplicate_context_after_me(s->c.enc_contexts[i], s); } - s->avctx->execute(s->avctx, encode_thread, &s->thread_context[0], NULL, context_count, sizeof(void*)); + s->c.avctx->execute(s->c.avctx, encode_thread, &s->c.enc_contexts[0], + NULL, context_count, sizeof(void*)); for(i=1; ipb.buf_end == s->thread_context[i]->pb.buf) - set_put_bits_buffer_size(&s->pb, FFMIN(s->thread_context[i]->pb.buf_end - s->pb.buf, INT_MAX/8-BUF_BITS)); - merge_context_after_encode(s, s->thread_context[i]); + if (s->pb.buf_end == s->c.enc_contexts[i]->pb.buf) + set_put_bits_buffer_size(&s->pb, FFMIN(s->c.enc_contexts[i]->pb.buf_end - s->pb.buf, INT_MAX/8-BUF_BITS)); + merge_context_after_encode(s, s->c.enc_contexts[i]); } emms_c(); return 0; } -static void denoise_dct_c(MpegEncContext *s, int16_t *block){ - const int intra= s->mb_intra; - int i; +static inline void denoise_dct(MPVEncContext *const s, int16_t block[]) +{ + if (!s->dct_error_sum) + return; + const int intra = s->c.mb_intra; s->dct_count[intra]++; - - for(i=0; i<64; i++){ - int level= block[i]; - - if(level){ - if(level>0){ - s->dct_error_sum[intra][i] += level; - level -= s->dct_offset[intra][i]; - if(level<0) level=0; - }else{ - s->dct_error_sum[intra][i] -= level; - level += s->dct_offset[intra][i]; - if(level>0) level=0; - } - block[i]= level; - } - } + s->mpvencdsp.denoise_dct(block, s->dct_error_sum[intra], s->dct_offset[intra]); } -static int dct_quantize_trellis_c(MpegEncContext *s, +static int dct_quantize_trellis_c(MPVEncContext *const s, int16_t *block, int n, int qscale, int *overflow){ const int *qmat; @@ -3920,28 +3943,28 @@ static int dct_quantize_trellis_c(MpegEncContext *s, int qmul, qadd, start_i, last_non_zero, i, dc; const int esc_length= s->ac_esc_length; const uint8_t *length, *last_length; - const int lambda= s->lambda2 >> (FF_LAMBDA_SHIFT - 6); + const int lambda = s->lambda2 >> (FF_LAMBDA_SHIFT - 6); int mpeg2_qscale; s->fdsp.fdct(block); - if(s->dct_error_sum) - s->denoise_dct(s, block); + denoise_dct(s, block); + qmul= qscale*16; qadd= ((qscale-1)|1)*8; - if (s->q_scale_type) mpeg2_qscale = ff_mpeg2_non_linear_qscale[qscale]; + if (s->c.q_scale_type) mpeg2_qscale = ff_mpeg2_non_linear_qscale[qscale]; else mpeg2_qscale = qscale << 1; - if (s->mb_intra) { + if (s->c.mb_intra) { int q; - scantable= s->intra_scantable.scantable; - perm_scantable= s->intra_scantable.permutated; - if (!s->h263_aic) { + scantable = s->c.intra_scantable.scantable; + perm_scantable = s->c.intra_scantable.permutated; + if (!s->c.h263_aic) { if (n < 4) - q = s->y_dc_scale; + q = s->c.y_dc_scale; else - q = s->c_dc_scale; + q = s->c.c_dc_scale; q = q << 3; } else{ /* For AIC we skip quant/dequant of INTRADC */ @@ -3954,8 +3977,8 @@ static int dct_quantize_trellis_c(MpegEncContext *s, start_i = 1; last_non_zero = 0; qmat = n < 4 ? s->q_intra_matrix[qscale] : s->q_chroma_intra_matrix[qscale]; - matrix = n < 4 ? s->intra_matrix : s->chroma_intra_matrix; - if(s->mpeg_quant || s->out_format == FMT_MPEG1 || s->out_format == FMT_MJPEG) + matrix = n < 4 ? s->c.intra_matrix : s->c.chroma_intra_matrix; + if (s->mpeg_quant || s->c.out_format == FMT_MPEG1 || s->c.out_format == FMT_MJPEG) bias= 1<<(QMAT_SHIFT-1); if (n > 3 && s->intra_chroma_ac_vlc_length) { @@ -3966,12 +3989,12 @@ static int dct_quantize_trellis_c(MpegEncContext *s, last_length= s->intra_ac_vlc_last_length; } } else { - scantable= s->inter_scantable.scantable; - perm_scantable= s->inter_scantable.permutated; + scantable = s->c.inter_scantable.scantable; + perm_scantable = s->c.inter_scantable.permutated; start_i = 0; last_non_zero = -1; qmat = s->q_inter_matrix[qscale]; - matrix = s->inter_matrix; + matrix = s->c.inter_matrix; length = s->inter_ac_vlc_length; last_length= s->inter_ac_vlc_last_length; } @@ -3982,9 +4005,9 @@ static int dct_quantize_trellis_c(MpegEncContext *s, for(i=63; i>=start_i; i--) { const int j = scantable[i]; - int level = block[j] * qmat[j]; + int64_t level = (int64_t)block[j] * qmat[j]; - if(((unsigned)(level+threshold1))>threshold2){ + if(((uint64_t)(level+threshold1))>threshold2){ last_non_zero = i; break; } @@ -3992,11 +4015,11 @@ static int dct_quantize_trellis_c(MpegEncContext *s, for(i=start_i; i<=last_non_zero; i++) { const int j = scantable[i]; - int level = block[j] * qmat[j]; + int64_t level = (int64_t)block[j] * qmat[j]; // if( bias+level >= (1<<(QMAT_SHIFT - 3)) // || bias-level >= (1<<(QMAT_SHIFT - 3))){ - if(((unsigned)(level+threshold1))>threshold2){ + if(((uint64_t)(level+threshold1))>threshold2){ if(level>0){ level= (bias + level)>>QMAT_SHIFT; coeff[0][i]= level; @@ -4045,14 +4068,14 @@ static int dct_quantize_trellis_c(MpegEncContext *s, av_assert2(level); - if(s->out_format == FMT_H263 || s->out_format == FMT_H261){ + if (s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) { unquant_coeff= alevel*qmul + qadd; - } else if(s->out_format == FMT_MJPEG) { - j = s->idsp.idct_permutation[scantable[i]]; + } else if (s->c.out_format == FMT_MJPEG) { + j = s->c.idsp.idct_permutation[scantable[i]]; unquant_coeff = alevel * matrix[j] * 8; }else{ // MPEG-1 - j = s->idsp.idct_permutation[scantable[i]]; // FIXME: optimize - if(s->mb_intra){ + j = s->c.idsp.idct_permutation[scantable[i]]; // FIXME: optimize + if (s->c.mb_intra) { unquant_coeff = (int)( alevel * mpeg2_qscale * matrix[j]) >> 4; unquant_coeff = (unquant_coeff - 1) | 1; }else{ @@ -4077,7 +4100,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s, } } - if(s->out_format == FMT_H263 || s->out_format == FMT_H261){ + if (s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) { for(j=survivor_count-1; j>=0; j--){ int run= i - survivor[j]; int score= distortion + last_length[UNI_AC_ENC_INDEX(run, level)]*lambda; @@ -4103,7 +4126,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s, } } - if(s->out_format == FMT_H263 || s->out_format == FMT_H261){ + if (s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) { for(j=survivor_count-1; j>=0; j--){ int run= i - survivor[j]; int score= distortion + score_tab[i-run]; @@ -4136,7 +4159,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s, survivor[ survivor_count++ ]= i+1; } - if(s->out_format != FMT_H263 && s->out_format != FMT_H261){ + if (s->c.out_format != FMT_H263 && s->c.out_format != FMT_H261) { last_score= 256*256*256*120; for(i= survivor[0]; i<=last_non_zero + 1; i++){ int score= score_tab[i]; @@ -4170,7 +4193,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s, int alevel= FFABS(level); int unquant_coeff, score, distortion; - if(s->out_format == FMT_H263 || s->out_format == FMT_H261){ + if (s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) { unquant_coeff= (alevel*qmul + qadd)>>3; } else{ // MPEG-1 unquant_coeff = ((( alevel << 1) + 1) * mpeg2_qscale * ((int) matrix[0])) >> 5; @@ -4208,7 +4231,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s, return last_non_zero; } -static int16_t basis[64][64]; +static DECLARE_ALIGNED(16, int16_t, basis)[64][64]; static void build_basis(uint8_t *perm){ int i, j, x, y; @@ -4229,10 +4252,10 @@ static void build_basis(uint8_t *perm){ } } -static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? +static int dct_quantize_refine(MPVEncContext *const s, //FIXME breaks denoise? int16_t *block, int16_t *weight, int16_t *orig, int n, int qscale){ - int16_t rem[64]; + DECLARE_ALIGNED(16, int16_t, rem)[64]; LOCAL_ALIGNED_16(int16_t, d1, [64]); const uint8_t *scantable; const uint8_t *perm_scantable; @@ -4245,21 +4268,21 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? const uint8_t *length; const uint8_t *last_length; int lambda; - int rle_index, run, q = 1, sum; //q is only used when s->mb_intra is true + int rle_index, run, q = 1, sum; //q is only used when s->c.mb_intra is true if(basis[0][0] == 0) - build_basis(s->idsp.idct_permutation); + build_basis(s->c.idsp.idct_permutation); qmul= qscale*2; qadd= (qscale-1)|1; - if (s->mb_intra) { - scantable= s->intra_scantable.scantable; - perm_scantable= s->intra_scantable.permutated; - if (!s->h263_aic) { + if (s->c.mb_intra) { + scantable = s->c.intra_scantable.scantable; + perm_scantable = s->c.intra_scantable.permutated; + if (!s->c.h263_aic) { if (n < 4) - q = s->y_dc_scale; + q = s->c.y_dc_scale; else - q = s->c_dc_scale; + q = s->c.c_dc_scale; } else{ /* For AIC we skip quant/dequant of INTRADC */ q = 1; @@ -4270,7 +4293,7 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? dc= block[0]*q; // block[0] = (block[0] + (q >> 1)) / q; start_i = 1; -// if(s->mpeg_quant || s->out_format == FMT_MPEG1) +// if (s->mpeg_quant || s->c.out_format == FMT_MPEG1) // bias= 1<<(QMAT_SHIFT-1); if (n > 3 && s->intra_chroma_ac_vlc_length) { length = s->intra_chroma_ac_vlc_length; @@ -4280,14 +4303,14 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? last_length= s->intra_ac_vlc_last_length; } } else { - scantable= s->inter_scantable.scantable; - perm_scantable= s->inter_scantable.permutated; + scantable = s->c.inter_scantable.scantable; + perm_scantable = s->c.inter_scantable.permutated; dc= 0; start_i = 0; length = s->inter_ac_vlc_length; last_length= s->inter_ac_vlc_last_length; } - last_non_zero = s->block_last_index[n]; + last_non_zero = s->c.block_last_index[n]; dc += (1<<(RECON_SHIFT-1)); for(i=0; i<64; i++){ @@ -4310,7 +4333,7 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? av_assert2(w<(1<<6)); sum += w*w; } - lambda= sum*(uint64_t)s->lambda2 >> (FF_LAMBDA_SHIFT - 6 + 6 + 6 + 6); + lambda = sum*(uint64_t)s->lambda2 >> (FF_LAMBDA_SHIFT - 6 + 6 + 6 + 6); run=0; rle_index=0; @@ -4351,7 +4374,7 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? const int level= block[0]; int change, old_coeff; - av_assert2(s->mb_intra); + av_assert2(s->c.mb_intra); old_coeff= q*level; @@ -4581,11 +4604,11 @@ void ff_block_permute(int16_t *block, const uint8_t *permutation, } } -static int dct_quantize_c(MpegEncContext *s, +static int dct_quantize_c(MPVEncContext *const s, int16_t *block, int n, int qscale, int *overflow) { - int i, j, level, last_non_zero, q, start_i; + int i, last_non_zero, q, start_i; const int *qmat; const uint8_t *scantable; int bias; @@ -4594,16 +4617,15 @@ static int dct_quantize_c(MpegEncContext *s, s->fdsp.fdct(block); - if(s->dct_error_sum) - s->denoise_dct(s, block); + denoise_dct(s, block); - if (s->mb_intra) { - scantable= s->intra_scantable.scantable; - if (!s->h263_aic) { + if (s->c.mb_intra) { + scantable = s->c.intra_scantable.scantable; + if (!s->c.h263_aic) { if (n < 4) - q = s->y_dc_scale; + q = s->c.y_dc_scale; else - q = s->c_dc_scale; + q = s->c.c_dc_scale; q = q << 3; } else /* For AIC we skip quant/dequant of INTRADC */ @@ -4616,7 +4638,7 @@ static int dct_quantize_c(MpegEncContext *s, qmat = n < 4 ? s->q_intra_matrix[qscale] : s->q_chroma_intra_matrix[qscale]; bias= s->intra_quant_bias*(1<<(QMAT_SHIFT - QUANT_BIAS_SHIFT)); } else { - scantable= s->inter_scantable.scantable; + scantable = s->c.inter_scantable.scantable; start_i = 0; last_non_zero = -1; qmat = s->q_inter_matrix[qscale]; @@ -4625,10 +4647,10 @@ static int dct_quantize_c(MpegEncContext *s, threshold1= (1<=start_i;i--) { - j = scantable[i]; - level = block[j] * qmat[j]; + const int j = scantable[i]; + int64_t level = (int64_t)block[j] * qmat[j]; - if(((unsigned)(level+threshold1))>threshold2){ + if(((uint64_t)(level+threshold1))>threshold2){ last_non_zero = i; break; }else{ @@ -4636,12 +4658,12 @@ static int dct_quantize_c(MpegEncContext *s, } } for(i=start_i; i<=last_non_zero; i++) { - j = scantable[i]; - level = block[j] * qmat[j]; + const int j = scantable[i]; + int64_t level = (int64_t)block[j] * qmat[j]; // if( bias+level >= (1<= (1<threshold2){ + if(((uint64_t)(level+threshold1))>threshold2){ if(level>0){ level= (bias + level)>>QMAT_SHIFT; block[j]= level; @@ -4657,8 +4679,8 @@ static int dct_quantize_c(MpegEncContext *s, *overflow= s->max_qcoeff < max; //overflow might have happened /* we need this permutation so that we correct the IDCT, we only permute the !=0 elements */ - if (s->idsp.perm_type != FF_IDCT_PERM_NONE) - ff_block_permute(block, s->idsp.idct_permutation, + if (s->c.idsp.perm_type != FF_IDCT_PERM_NONE) + ff_block_permute(block, s->c.idsp.idct_permutation, scantable, last_non_zero); return last_non_zero; diff --git a/libavcodec/mpegvideo_motion.c b/libavcodec/mpegvideo_motion.c index 6e9368dd9..741927d80 100644 --- a/libavcodec/mpegvideo_motion.c +++ b/libavcodec/mpegvideo_motion.c @@ -29,11 +29,12 @@ #include "avcodec.h" #include "h261.h" +#include "h263.h" #include "mpegutils.h" #include "mpegvideo.h" #include "mpeg4videodec.h" #include "qpeldsp.h" -#include "wmv2.h" +#include "wmv2dec.h" static inline int hpel_motion(MpegEncContext *s, uint8_t *dest, uint8_t *src, @@ -705,11 +706,13 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, 0, 0, 0, ref_picture, pix_op, qpix_op, s->mv[dir][0][0], s->mv[dir][0][1], 16); - } else if (!is_mpeg12 && (CONFIG_WMV2_DECODER || CONFIG_WMV2_ENCODER) && - s->mspel && s->codec_id == AV_CODEC_ID_WMV2) { +#if CONFIG_WMV2_DECODER + } else if (!is_mpeg12 && s->mspel && s->codec_id == AV_CODEC_ID_WMV2) { + av_assert2(av_codec_is_decoder(s->avctx->codec)); ff_mspel_motion(s, dest_y, dest_cb, dest_cr, ref_picture, pix_op, s->mv[dir][0][0], s->mv[dir][0][1], 16); +#endif } else { mpeg_motion(s, dest_y, dest_cb, dest_cr, 0, ref_picture, pix_op, @@ -812,7 +815,8 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, } break; } - default: av_assert2(0); + default: + av_unreachable("No other mpegvideo MV types exist"); } } diff --git a/libavcodec/mpegvideo_parser.c b/libavcodec/mpegvideo_parser.c index 2cd034831..1afb695d0 100644 --- a/libavcodec/mpegvideo_parser.c +++ b/libavcodec/mpegvideo_parser.c @@ -25,6 +25,7 @@ #include "parser.h" #include "mpeg12.h" #include "mpeg12data.h" +#include "parser_internal.h" #include "startcode.h" struct MpvParseContext { @@ -147,11 +148,6 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s, pc->frame_rate = avctx->framerate = ff_mpeg12_frame_rate_tab[frame_rate_index]; bit_rate = (buf[4]<<10) | (buf[5]<<2) | (buf[6]>>6); avctx->codec_id = AV_CODEC_ID_MPEG1VIDEO; -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - avctx->ticks_per_frame = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } break; case EXT_START_CODE: @@ -181,11 +177,6 @@ FF_ENABLE_DEPRECATION_WARNINGS avctx->framerate.num = pc->frame_rate.num * (frame_rate_ext_n + 1); avctx->framerate.den = pc->frame_rate.den * (frame_rate_ext_d + 1); avctx->codec_id = AV_CODEC_ID_MPEG2VIDEO; -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - avctx->ticks_per_frame = 2; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } break; case 0x8: /* picture coding extension */ @@ -303,16 +294,16 @@ static int mpegvideo_parse(AVCodecParserContext *s, return next; } -static int mpegvideo_parse_init(AVCodecParserContext *s) +static av_cold int mpegvideo_parse_init(AVCodecParserContext *s) { s->pict_type = AV_PICTURE_TYPE_NONE; // first frame might be partial return 0; } -const AVCodecParser ff_mpegvideo_parser = { - .codec_ids = { AV_CODEC_ID_MPEG1VIDEO, AV_CODEC_ID_MPEG2VIDEO }, +const FFCodecParser ff_mpegvideo_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_MPEG1VIDEO, AV_CODEC_ID_MPEG2VIDEO), .priv_data_size = sizeof(struct MpvParseContext), - .parser_init = mpegvideo_parse_init, - .parser_parse = mpegvideo_parse, - .parser_close = ff_parse_close, + .init = mpegvideo_parse_init, + .parse = mpegvideo_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/mpegvideo_unquantize.c b/libavcodec/mpegvideo_unquantize.c new file mode 100644 index 000000000..054f5c018 --- /dev/null +++ b/libavcodec/mpegvideo_unquantize.c @@ -0,0 +1,290 @@ +/* + * Unquantize functions for mpegvideo + * Copyright (c) 2000,2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * 4MV & hq & B-frame encoding stuff by 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 "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "avcodec.h" +#include "mpegvideo.h" +#include "mpegvideodata.h" +#include "mpegvideo_unquantize.h" + +av_cold void ff_init_scantable(const uint8_t *permutation, ScanTable *st, + const uint8_t *src_scantable) +{ + st->scantable = src_scantable; + + for (int i = 0, end = -1; i < 64; i++) { + int j = src_scantable[i]; + st->permutated[i] = permutation[j]; + if (permutation[j] > end) + end = permutation[j]; + st->raster_end[i] = end; + } +} + +static void dct_unquantize_mpeg1_intra_c(const MPVContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + + nCoeffs= s->block_last_index[n]; + + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + /* XXX: only MPEG-1 */ + quant_matrix = s->intra_matrix; + for(i=1;i<=nCoeffs;i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (int)(level * qscale * quant_matrix[j]) >> 3; + level = (level - 1) | 1; + level = -level; + } else { + level = (int)(level * qscale * quant_matrix[j]) >> 3; + level = (level - 1) | 1; + } + block[j] = level; + } + } +} + +static void dct_unquantize_mpeg1_inter_c(const MPVContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + + nCoeffs= s->block_last_index[n]; + + quant_matrix = s->inter_matrix; + for(i=0; i<=nCoeffs; i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 4; + level = (level - 1) | 1; + level = -level; + } else { + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 4; + level = (level - 1) | 1; + } + block[j] = level; + } + } +} + +static void dct_unquantize_mpeg2_intra_c(const MPVContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + + if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; + else qscale <<= 1; + + nCoeffs= s->block_last_index[n]; + + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + quant_matrix = s->intra_matrix; + for(i=1;i<=nCoeffs;i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (int)(level * qscale * quant_matrix[j]) >> 4; + level = -level; + } else { + level = (int)(level * qscale * quant_matrix[j]) >> 4; + } + block[j] = level; + } + } +} + +static void dct_unquantize_mpeg2_intra_bitexact(const MPVContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + int sum=-1; + + if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; + else qscale <<= 1; + + nCoeffs= s->block_last_index[n]; + + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + sum += block[0]; + quant_matrix = s->intra_matrix; + for(i=1;i<=nCoeffs;i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (int)(level * qscale * quant_matrix[j]) >> 4; + level = -level; + } else { + level = (int)(level * qscale * quant_matrix[j]) >> 4; + } + block[j] = level; + sum+=level; + } + } + block[63]^=sum&1; +} + +static void dct_unquantize_mpeg2_inter_c(const MPVContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + int sum=-1; + + if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; + else qscale <<= 1; + + nCoeffs= s->block_last_index[n]; + + quant_matrix = s->inter_matrix; + for(i=0; i<=nCoeffs; i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 5; + level = -level; + } else { + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 5; + } + block[j] = level; + sum+=level; + } + } + block[63]^=sum&1; +} + +static void dct_unquantize_h263_intra_c(const MPVContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, qmul, qadd; + int nCoeffs; + + av_assert2(s->block_last_index[n]>=0 || s->h263_aic); + + qmul = qscale << 1; + + if (!s->h263_aic) { + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + qadd = (qscale - 1) | 1; + }else{ + qadd = 0; + } + if(s->ac_pred) + nCoeffs=63; + else + nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; + + for(i=1; i<=nCoeffs; i++) { + level = block[i]; + if (level) { + if (level < 0) { + level = level * qmul - qadd; + } else { + level = level * qmul + qadd; + } + block[i] = level; + } + } +} + +static void dct_unquantize_h263_inter_c(const MPVContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, qmul, qadd; + int nCoeffs; + + av_assert2(s->block_last_index[n]>=0); + + qadd = (qscale - 1) | 1; + qmul = qscale << 1; + + nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ]; + + for(i=0; i<=nCoeffs; i++) { + level = block[i]; + if (level) { + if (level < 0) { + level = level * qmul - qadd; + } else { + level = level * qmul + qadd; + } + block[i] = level; + } + } +} + +av_cold void ff_mpv_unquantize_init(MPVUnquantDSPContext *s, + int bitexact, int q_scale_type) +{ + s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_c; + s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_c; + s->dct_unquantize_mpeg1_intra = dct_unquantize_mpeg1_intra_c; + s->dct_unquantize_mpeg1_inter = dct_unquantize_mpeg1_inter_c; + s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_c; + if (bitexact) + s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_bitexact; + s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_c; + +#if HAVE_INTRINSICS_NEON + ff_mpv_unquantize_init_neon(s, bitexact); +#endif + +#if ARCH_ARM + ff_mpv_unquantize_init_arm(s, bitexact); +#elif ARCH_PPC + ff_mpv_unquantize_init_ppc(s, bitexact); +#elif ARCH_RISCV + ff_mpv_unquantize_init_riscv(s, bitexact); +#elif ARCH_X86 + ff_mpv_unquantize_init_x86(s, bitexact); +#elif ARCH_MIPS + ff_mpv_unquantize_init_mips(s, bitexact, q_scale_type); +#endif +} diff --git a/libavcodec/mpegvideo_unquantize.h b/libavcodec/mpegvideo_unquantize.h new file mode 100644 index 000000000..50319d7ad --- /dev/null +++ b/libavcodec/mpegvideo_unquantize.h @@ -0,0 +1,63 @@ +/* + * Unquantize functions for mpegvideo + * Copyright (c) 2000,2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * 4MV & hq & B-frame encoding stuff by 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 AVCODEC_MPEGVIDEO_UNQUANTIZE_H +#define AVCODEC_MPEGVIDEO_UNQUANTIZE_H + +#include + +#include "config.h" + +typedef struct MpegEncContext MPVContext; + +typedef struct MPVUnquantDSPContext { + void (*dct_unquantize_mpeg1_intra)(const MPVContext *s, + int16_t *block/*align 16*/, int n, int qscale); + void (*dct_unquantize_mpeg1_inter)(const MPVContext *s, + int16_t *block/*align 16*/, int n, int qscale); + void (*dct_unquantize_mpeg2_intra)(const MPVContext *s, + int16_t *block/*align 16*/, int n, int qscale); + void (*dct_unquantize_mpeg2_inter)(const MPVContext *s, + int16_t *block/*align 16*/, int n, int qscale); + void (*dct_unquantize_h263_intra)(const MPVContext *s, + int16_t *block/*align 16*/, int n, int qscale); + void (*dct_unquantize_h263_inter)(const MPVContext *s, + int16_t *block/*align 16*/, int n, int qscale); +} MPVUnquantDSPContext; + +#if !ARCH_MIPS +#define ff_mpv_unquantize_init(s, bitexact, q_scale_type) ff_mpv_unquantize_init(s, bitexact) +#endif + +void ff_mpv_unquantize_init(MPVUnquantDSPContext *s, + int bitexact, int q_scale_type); +void ff_mpv_unquantize_init_arm (MPVUnquantDSPContext *s, int bitexact); +void ff_mpv_unquantize_init_neon(MPVUnquantDSPContext *s, int bitexact); +void ff_mpv_unquantize_init_ppc (MPVUnquantDSPContext *s, int bitexact); +void ff_mpv_unquantize_init_riscv(MPVUnquantDSPContext *s, int bitexact); +void ff_mpv_unquantize_init_x86 (MPVUnquantDSPContext *s, int bitexact); +void ff_mpv_unquantize_init_mips(MPVUnquantDSPContext *s, int bitexact, + int q_scale_type); + +#endif /* AVCODEC_MPEGVIDEO_UNQUANTIZE_H */ diff --git a/libavcodec/mpegvideodec.h b/libavcodec/mpegvideodec.h index 610036471..16b3eb1b1 100644 --- a/libavcodec/mpegvideodec.h +++ b/libavcodec/mpegvideodec.h @@ -56,12 +56,20 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx); * Ensure that the dummy frames are allocated according to pict_type if necessary. */ int ff_mpv_alloc_dummy_frames(MpegEncContext *s); -void ff_mpv_reconstruct_mb(MpegEncContext *s, int16_t block[12][64]); -void ff_mpv_report_decode_progress(MpegEncContext *s); +void ff_mpv_reconstruct_mb(MPVContext *s, int16_t block[][64]); void ff_mpv_frame_end(MpegEncContext *s); int ff_mpv_export_qp_table(const MpegEncContext *s, AVFrame *f, const MPVPicture *p, int qp_type); +/** + * update_thread_context for mpegvideo-based decoders. It updates + * the MPVPictures and generic stream-level parameters. If necessary + * (on dimension changes), it also performs reinitialization. + * + * @retval 1 if a reinitialization happened + * @retval 0 on success if no reinitialization happened + * @retval "<0" error code + */ int ff_mpeg_update_thread_context(AVCodecContext *dst, const AVCodecContext *src); void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h); void ff_mpeg_flush(AVCodecContext *avctx); @@ -69,10 +77,10 @@ int ff_mpv_decode_close(AVCodecContext *avctx); void ff_print_debug_info(const MpegEncContext *s, const MPVPicture *p, AVFrame *pict); -static inline int mpeg_get_qscale(MpegEncContext *s) +static inline int mpeg_get_qscale(GetBitContext *const gb, int q_scale_type) { - int qscale = get_bits(&s->gb, 5); - if (s->q_scale_type) + int qscale = get_bits(gb, 5); + if (q_scale_type) return ff_mpeg2_non_linear_qscale[qscale]; else return qscale << 1; diff --git a/libavcodec/mpegvideoenc.h b/libavcodec/mpegvideoenc.h index f5044a030..3943a284e 100644 --- a/libavcodec/mpegvideoenc.h +++ b/libavcodec/mpegvideoenc.h @@ -30,9 +30,262 @@ #include +#include "libavutil/avassert.h" +#include "libavutil/mem_internal.h" #include "libavutil/opt.h" +#include "fdctdsp.h" +#include "motion_est.h" #include "mpegvideo.h" +#include "mpegvideoencdsp.h" +#include "pixblockdsp.h" +#include "put_bits.h" +#include "ratecontrol.h" +#define MPVENC_MAX_B_FRAMES 16 + +typedef struct MPVEncContext { + MpegEncContext c; ///< the common base context + + /** bit output */ + PutBitContext pb; + + unsigned int lambda; ///< Lagrange multiplier used in rate distortion + unsigned int lambda2; ///< (lambda*lambda) >> FF_LAMBDA_SHIFT + int *lambda_table; + int adaptive_quant; ///< use adaptive quantization + int dquant; ///< qscale difference to prev qscale + int skipdct; ///< skip dct and code zero residual + + int quantizer_noise_shaping; + + int luma_elim_threshold; + int chroma_elim_threshold; + + int mpv_flags; ///< flags set by private options + /// Bitfield containing information which frames to reconstruct. + int frame_reconstruction_bitfield; + + /** + * Reference to the source picture. + */ + AVFrame *new_pic; + + struct MPVMainEncContext *parent; + + FDCTDSPContext fdsp; + MpegvideoEncDSPContext mpvencdsp; + PixblockDSPContext pdsp; + MotionEstContext me; + + int f_code; ///< forward MV resolution + int b_code; ///< backward MV resolution for B-frames + + int16_t (*p_mv_table)[2]; ///< MV table (1MV per MB) P-frame + int16_t (*b_forw_mv_table)[2]; ///< MV table (1MV per MB) forward mode B-frame + int16_t (*b_back_mv_table)[2]; ///< MV table (1MV per MB) backward mode B-frame + int16_t (*b_bidir_forw_mv_table)[2]; ///< MV table (1MV per MB) bidir mode B-frame + int16_t (*b_bidir_back_mv_table)[2]; ///< MV table (1MV per MB) bidir mode B-frame + int16_t (*b_direct_mv_table)[2]; ///< MV table (1MV per MB) direct mode B-frame + int16_t (*b_field_mv_table[2][2][2])[2];///< MV table (4MV per MB) interlaced B-frame + uint8_t (*p_field_select_table[2]); ///< Only the first element is allocated + uint8_t (*b_field_select_table[2][2]); ///< allocated jointly with p_field_select_table + + uint16_t *mb_type; ///< Table for candidate MB types + uint16_t *mb_var; ///< Table for MB variances + uint16_t *mc_mb_var; ///< Table for motion compensated MB variances + uint8_t *mb_mean; ///< Table for MB luminance + uint64_t encoding_error[MPV_MAX_PLANES]; + + int intra_quant_bias; ///< bias for the quantizer + int inter_quant_bias; ///< bias for the quantizer + int min_qcoeff; ///< minimum encodable coefficient + int max_qcoeff; ///< maximum encodable coefficient + int ac_esc_length; ///< num of bits needed to encode the longest esc + const uint8_t *intra_ac_vlc_length; + const uint8_t *intra_ac_vlc_last_length; + const uint8_t *intra_chroma_ac_vlc_length; + const uint8_t *intra_chroma_ac_vlc_last_length; + const uint8_t *inter_ac_vlc_length; + const uint8_t *inter_ac_vlc_last_length; + const uint8_t *luma_dc_vlc_length; + + int coded_score[12]; + + int16_t (*block)[64]; ///< points into blocks below + + /** precomputed matrix (combine qscale and DCT renorm) */ + int (*q_intra_matrix)[64]; + int (*q_chroma_intra_matrix)[64]; + int (*q_inter_matrix)[64]; + /** identical to the above but for SSE & these are not permutated, second 64 entries are bias*/ + uint16_t (*q_intra_matrix16)[2][64]; + uint16_t (*q_chroma_intra_matrix16)[2][64]; + uint16_t (*q_inter_matrix16)[2][64]; + + /* noise reduction */ + int (*dct_error_sum)[64]; + int dct_count[2]; + uint16_t (*dct_offset)[64]; + + int picture_number; + + /* statistics, used for 2-pass encoding */ + int mv_bits; + int i_tex_bits; + int p_tex_bits; + int i_count; + int misc_bits; ///< cbp, mb_type + int last_bits; ///< temp var used for calculating the above vars + + int mb_skip_run; + int last_dc[3]; ///< last DC values + + /* H.263 specific */ + int gob_index; + int mb_info; ///< interval for outputting info about mb offsets as side data + int prev_mb_info, last_mb_info; + int mb_info_size; + uint8_t *mb_info_ptr; + + /* H.263+ specific */ + int umvplus; ///< == H.263+ && unrestricted_mv + int h263_slice_structured; + int alt_inter_vlc; ///< alternative inter vlc + int modified_quant; + int loop_filter; + + /* MJPEG specific */ + struct MJpegContext *mjpeg_ctx; + int esc_pos; + + /* MPEG-1 specific */ + int last_mv_dir; ///< last mv_dir, used for B-frame encoding + + /* MPEG-4 specific */ + int data_partitioning; ///< data partitioning flag, set via option + int partitioned_frame; ///< is current frame partitioned + int mpeg_quant; + PutBitContext tex_pb; ///< used for data partitioned VOPs + PutBitContext pb2; ///< used for data partitioned VOPs + + /* MSMPEG4 specific */ + int slice_height; ///< in macroblocks + int flipflop_rounding; ///< also used for MPEG-4, H.263+ + int esc3_level_length; + + /* RTP specific */ + int rtp_mode; + int rtp_payload_size; + int error_rate; + + uint8_t *ptr_lastgob; + + void (*encode_mb)(struct MPVEncContext *s, int16_t block[][64], + int motion_x, int motion_y); + + int (*dct_quantize)(struct MPVEncContext *s, int16_t *block/*align 16*/, int n, int qscale, int *overflow); + + me_cmp_func ildct_cmp[2]; ///< 0 = intra, 1 = non-intra + me_cmp_func n_sse_cmp[2]; ///< either SSE or NSSE cmp func + me_cmp_func sad_cmp[2]; + me_cmp_func sse_cmp[2]; + int (*sum_abs_dctelem)(const int16_t *block); + + int intra_penalty; + + uint8_t permutated_intra_h_scantable[64]; + uint8_t permutated_intra_v_scantable[64]; + + DECLARE_ALIGNED_32(int16_t, blocks)[2][12][64]; // for HQ mode we need to keep the best block +} MPVEncContext; + +typedef struct MPVMainEncContext { + MPVEncContext s; ///< The main slicecontext + + int intra_only; ///< if true, only intra pictures are generated + int gop_size; + int max_b_frames; ///< max number of B-frames + int picture_in_gop_number; ///< 0-> first pic in gop, ... + int input_picture_number; ///< used to set pic->display_picture_number + int coded_picture_number; ///< used to set pic->coded_picture_number + + MPVPicture *input_picture[MPVENC_MAX_B_FRAMES + 1]; ///< next pictures in display order + MPVPicture *reordered_input_picture[MPVENC_MAX_B_FRAMES + 1]; ///< next pictures in coded order + + int64_t user_specified_pts; ///< last non-zero pts from user-supplied AVFrame + /** + * pts difference between the first and second input frame, used for + * calculating dts of the first frame when there's a delay */ + int64_t dts_delta; + /** + * reordered pts to be used as dts for the next output frame when there's + * a delay */ + int64_t reordered_pts; + + /// temporary frames used by b_frame_strategy = 2 + AVFrame *tmp_frames[MPVENC_MAX_B_FRAMES + 2]; + int b_frame_strategy; + int b_sensitivity; + int brd_scale; + + int scenechange_threshold; + + int noise_reduction; + + float border_masking; + int lmin, lmax; + int vbv_ignore_qmax; + + /* MPEG-1/2 specific */ + int vbv_delay_pos; ///< offset of vbv_delay in the bitstream + + const uint8_t *fcode_tab; ///< smallest fcode needed for each MV + + /* frame skip options */ + int frame_skip_threshold; + int frame_skip_factor; + int frame_skip_exp; + int frame_skip_cmp; + me_cmp_func frame_skip_cmp_fn; + + int (*encode_picture_header)(struct MPVMainEncContext *m); + + /* bit rate control */ + int64_t bit_rate; + int64_t total_bits; + int frame_bits; ///< bits used for the current frame + int header_bits; + int stuffing_bits; ///< bits used for stuffing + int next_lambda; ///< next lambda used for retrying to encode a frame + int fixed_qscale; ///< fixed qscale if non zero + int last_lambda_for[5]; ///< last lambda for a specific pict type + int last_pict_type; //FIXME removes + int last_non_b_pict_type; ///< used for MPEG-4 gmc B-frames & ratecontrol + RateControlContext rc_context; ///< contains stuff only accessed in ratecontrol.c + + int me_penalty_compensation; + int me_pre; ///< prepass for motion estimation + + int64_t mb_var_sum; ///< sum of MB variance for current frame + int64_t mc_mb_var_sum; ///< motion compensated MB variance for current frame + + char *me_map_base; ///< backs MotionEstContext.(map|score_map) + char *dct_error_sum_base; ///< backs dct_error_sum + int16_t (*mv_table_base)[2]; +} MPVMainEncContext; + +static inline const MPVMainEncContext *slice_to_mainenc(const MPVEncContext *s) +{ +#ifdef NO_SLICE_THREADING_HERE + av_assert2(s->c.slice_context_count <= 1 && + !(s->c.avctx->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS)); + return (const MPVMainEncContext*)s; +#else + return s->parent; +#endif +} + +#define MAX_FCODE 7 #define UNI_AC_ENC_INDEX(run,level) ((run)*128 + (level)) #define INPLACE_OFFSET 16 @@ -79,7 +332,9 @@ { "chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_CHROMA }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, .unit = "cmp_func" }, \ { "msad", "Sum of absolute differences, median predicted", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_MEDIAN_SAD }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, .unit = "cmp_func" } -#define FF_MPV_OFFSET(x) offsetof(MpegEncContext, x) +#define FF_MPV_OFFSET(x) offsetof(MPVEncContext, x) +#define FF_MPV_MAIN_OFFSET(x) offsetof(MPVMainEncContext, x) +#define FF_RC_OFFSET(x) offsetof(MPVMainEncContext, rc_context.x) #define FF_MPV_OPT_FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) #define FF_MPV_COMMON_OPTS \ FF_MPV_OPT_CMP_FUNC, \ @@ -89,7 +344,6 @@ FF_MPV_OPT_CMP_FUNC, \ { "qp_rd", "Use rate distortion optimization for qp selection", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_QP_RD }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "mpv_flags" },\ { "cbp_rd", "use rate distortion optimization for CBP", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_CBP_RD }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "mpv_flags" },\ { "naq", "normalize adaptive quantization", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_NAQ }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "mpv_flags" },\ -{ "mv0", "always try a mb with mv=<0,0>", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_MV0 }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "mpv_flags" },\ { "luma_elim_threshold", "single coefficient elimination threshold for luminance (negative values also consider dc coefficient)",\ FF_MPV_OFFSET(luma_elim_threshold), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS },\ { "chroma_elim_threshold", "single coefficient elimination threshold for chrominance (negative values also consider dc coefficient)",\ @@ -98,64 +352,63 @@ FF_MPV_OPT_CMP_FUNC, \ { "error_rate", "Simulate errors in the bitstream to test error concealment.", \ FF_MPV_OFFSET(error_rate), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FF_MPV_OPT_FLAGS },\ {"qsquish", "how to keep quantizer between qmin and qmax (0 = clip, 1 = use differentiable function)", \ - FF_MPV_OFFSET(rc_qsquish), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, 0, 99, FF_MPV_OPT_FLAGS}, \ -{"rc_qmod_amp", "experimental quantizer modulation", FF_MPV_OFFSET(rc_qmod_amp), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ -{"rc_qmod_freq", "experimental quantizer modulation", FF_MPV_OFFSET(rc_qmod_freq), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS}, \ + FF_RC_OFFSET(qsquish), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, 0, 99, FF_MPV_OPT_FLAGS}, \ +{"rc_qmod_amp", "experimental quantizer modulation", FF_RC_OFFSET(qmod_amp), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"rc_qmod_freq", "experimental quantizer modulation", FF_RC_OFFSET(qmod_freq), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS}, \ {"rc_eq", "Set rate control equation. When computing the expression, besides the standard functions " \ "defined in the section 'Expression Evaluation', the following functions are available: " \ "bits2qp(bits), qp2bits(qp). Also the following constants are available: iTex pTex tex mv " \ "fCode iCount mcVar var isI isP isB avgQP qComp avgIITex avgPITex avgPPTex avgBPTex avgTex.", \ - FF_MPV_OFFSET(rc_eq), AV_OPT_TYPE_STRING, .flags = FF_MPV_OPT_FLAGS }, \ -{"rc_init_cplx", "initial complexity for 1-pass encoding", FF_MPV_OFFSET(rc_initial_cplx), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ -{"rc_buf_aggressivity", "currently useless", FF_MPV_OFFSET(rc_buffer_aggressivity), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ -{"border_mask", "increase the quantizer for macroblocks close to borders", FF_MPV_OFFSET(border_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ -{"lmin", "minimum Lagrange factor (VBR)", FF_MPV_OFFSET(lmin), AV_OPT_TYPE_INT, {.i64 = 2*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"lmax", "maximum Lagrange factor (VBR)", FF_MPV_OFFSET(lmax), AV_OPT_TYPE_INT, {.i64 = 31*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"skip_threshold", "Frame skip threshold", FF_MPV_OFFSET(frame_skip_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"skip_factor", "Frame skip factor", FF_MPV_OFFSET(frame_skip_factor), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"skip_exp", "Frame skip exponent", FF_MPV_OFFSET(frame_skip_exp), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"skip_cmp", "Frame skip compare function", FF_MPV_OFFSET(frame_skip_cmp), AV_OPT_TYPE_INT, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, .unit = "cmp_func" }, \ -{"sc_threshold", "Scene change threshold", FF_MPV_OFFSET(scenechange_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"noise_reduction", "Noise reduction", FF_MPV_OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ + FF_RC_OFFSET(rc_eq), AV_OPT_TYPE_STRING, .flags = FF_MPV_OPT_FLAGS }, \ +{"rc_init_cplx", "initial complexity for 1-pass encoding", FF_RC_OFFSET(initial_cplx), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"rc_buf_aggressivity", "currently useless", FF_RC_OFFSET(buffer_aggressivity), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"border_mask", "increase the quantizer for macroblocks close to borders", FF_MPV_MAIN_OFFSET(border_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"lmin", "minimum Lagrange factor (VBR)", FF_MPV_MAIN_OFFSET(lmin), AV_OPT_TYPE_INT, {.i64 = 2*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"lmax", "maximum Lagrange factor (VBR)", FF_MPV_MAIN_OFFSET(lmax), AV_OPT_TYPE_INT, {.i64 = 31*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"skip_threshold", "Frame skip threshold", FF_MPV_MAIN_OFFSET(frame_skip_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"skip_factor", "Frame skip factor", FF_MPV_MAIN_OFFSET(frame_skip_factor), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"skip_exp", "Frame skip exponent", FF_MPV_MAIN_OFFSET(frame_skip_exp), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"skip_cmp", "Frame skip compare function", FF_MPV_MAIN_OFFSET(frame_skip_cmp), AV_OPT_TYPE_INT, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, .unit = "cmp_func" }, \ +{"noise_reduction", "Noise reduction", FF_MPV_MAIN_OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ {"ps", "RTP payload size in bytes", FF_MPV_OFFSET(rtp_payload_size), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ #define FF_MPV_COMMON_BFRAME_OPTS \ -{"b_strategy", "Strategy to choose between I/P/B-frames", FF_MPV_OFFSET(b_frame_strategy), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, FF_MPV_OPT_FLAGS }, \ -{"b_sensitivity", "Adjust sensitivity of b_frame_strategy 1", FF_MPV_OFFSET(b_sensitivity), AV_OPT_TYPE_INT, {.i64 = 40 }, 1, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"brd_scale", "Downscale frames for dynamic B-frame decision", FF_MPV_OFFSET(brd_scale), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 3, FF_MPV_OPT_FLAGS }, +{"b_strategy", "Strategy to choose between I/P/B-frames", FF_MPV_MAIN_OFFSET(b_frame_strategy), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, FF_MPV_OPT_FLAGS }, \ +{"b_sensitivity", "Adjust sensitivity of b_frame_strategy 1", FF_MPV_MAIN_OFFSET(b_sensitivity), AV_OPT_TYPE_INT, {.i64 = 40 }, 1, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"brd_scale", "Downscale frames for dynamic B-frame decision", FF_MPV_MAIN_OFFSET(brd_scale), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 3, FF_MPV_OPT_FLAGS }, #define FF_MPV_COMMON_MOTION_EST_OPTS \ -{"motion_est", "motion estimation algorithm", FF_MPV_OFFSET(motion_est), AV_OPT_TYPE_INT, {.i64 = FF_ME_EPZS }, FF_ME_ZERO, FF_ME_XONE, FF_MPV_OPT_FLAGS, .unit = "motion_est" }, \ +{ "mv0", "always try a mb with mv=<0,0>", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_MV0 }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "mpv_flags" },\ +{"motion_est", "motion estimation algorithm", FF_MPV_OFFSET(me.motion_est), AV_OPT_TYPE_INT, {.i64 = FF_ME_EPZS }, FF_ME_ZERO, FF_ME_XONE, FF_MPV_OPT_FLAGS, .unit = "motion_est" }, \ { "zero", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_ZERO }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion_est" }, \ { "epzs", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_EPZS }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion_est" }, \ { "xone", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_XONE }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion_est" }, \ -{"mepc", "Motion estimation bitrate penalty compensation (1.0 = 256)", FF_MPV_OFFSET(me_penalty_compensation), AV_OPT_TYPE_INT, {.i64 = 256 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"mepre", "pre motion estimation", FF_MPV_OFFSET(me_pre), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"mepc", "Motion estimation bitrate penalty compensation (1.0 = 256)", FF_MPV_MAIN_OFFSET(me_penalty_compensation), AV_OPT_TYPE_INT, {.i64 = 256 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"mepre", "pre motion estimation", FF_MPV_MAIN_OFFSET(me_pre), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ {"intra_penalty", "Penalty for intra blocks in block decision", FF_MPV_OFFSET(intra_penalty), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX/2, FF_MPV_OPT_FLAGS }, \ +{"sc_threshold", "Scene change threshold", FF_MPV_MAIN_OFFSET(scenechange_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ extern const AVClass ff_mpv_enc_class; int ff_mpv_encode_init(AVCodecContext *avctx); -void ff_mpv_encode_init_x86(MpegEncContext *s); int ff_mpv_encode_end(AVCodecContext *avctx); int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet); -int ff_mpv_reallocate_putbitbuffer(MpegEncContext *s, size_t threshold, size_t size_increase); +int ff_mpv_reallocate_putbitbuffer(MPVEncContext *s, size_t threshold, size_t size_increase); void ff_write_quant_matrix(PutBitContext *pb, uint16_t *matrix); -void ff_dct_encode_init(MpegEncContext *s); -void ff_mpvenc_dct_init_mips(MpegEncContext *s); -void ff_dct_encode_init_x86(MpegEncContext *s); +void ff_dct_encode_init(MPVEncContext *s); +void ff_dct_encode_init_x86(MPVEncContext *s); -void ff_convert_matrix(MpegEncContext *s, int (*qmat)[64], uint16_t (*qmat16)[2][64], +void ff_convert_matrix(MPVEncContext *s, int (*qmat)[64], uint16_t (*qmat16)[2][64], const uint16_t *quant_matrix, int bias, int qmin, int qmax, int intra); void ff_block_permute(int16_t *block, const uint8_t *permutation, const uint8_t *scantable, int last); -static inline int get_bits_diff(MpegEncContext *s) +static inline int get_bits_diff(MPVEncContext *s) { const int bits = put_bits_count(&s->pb); const int last = s->last_bits; diff --git a/libavcodec/mpegvideoencdsp.c b/libavcodec/mpegvideoencdsp.c index 5e4c446d9..3b4a57d58 100644 --- a/libavcodec/mpegvideoencdsp.c +++ b/libavcodec/mpegvideoencdsp.c @@ -25,9 +25,32 @@ #include "libavutil/attributes.h" #include "libavutil/imgutils.h" #include "avcodec.h" -#include "me_cmp.h" +#include "mathops.h" #include "mpegvideoencdsp.h" +static void denoise_dct_c(int16_t block[64], int dct_error_sum[64], + const uint16_t dct_offset[64]) +{ + for (int i = 0; i < 64; ++i) { + int level = block[i]; + + if (level) { + if (level > 0) { + dct_error_sum[i] += level; + level -= dct_offset[i]; + if (level < 0) + level = 0; + } else { + dct_error_sum[i] -= level; + level += dct_offset[i]; + if (level > 0) + level = 0; + } + block[i] = level; + } + } +} + static int try_8x8basis_c(const int16_t rem[64], const int16_t weight[64], const int16_t basis[64], int scale) { @@ -253,6 +276,8 @@ static void shrink88(uint8_t *dst, ptrdiff_t dst_wrap, av_cold void ff_mpegvideoencdsp_init(MpegvideoEncDSPContext *c, AVCodecContext *avctx) { + c->denoise_dct = denoise_dct_c; + c->try_8x8basis = try_8x8basis_c; c->add_8x8basis = add_8x8basis_c; diff --git a/libavcodec/mpegvideoencdsp.h b/libavcodec/mpegvideoencdsp.h index 6ec665677..989503f25 100644 --- a/libavcodec/mpegvideoencdsp.h +++ b/libavcodec/mpegvideoencdsp.h @@ -30,6 +30,9 @@ #define EDGE_BOTTOM 2 typedef struct MpegvideoEncDSPContext { + void (*denoise_dct)(int16_t block[64], int dct_error_sum[64], + const uint16_t dct_offset[64]); + int (*try_8x8basis)(const int16_t rem[64], const int16_t weight[64], const int16_t basis[64], int scale); void (*add_8x8basis)(int16_t rem[64], const int16_t basis[64], int scale); diff --git a/libavcodec/mpv_reconstruct_mb_template.c b/libavcodec/mpv_reconstruct_mb_template.c deleted file mode 100644 index 50f76fa22..000000000 --- a/libavcodec/mpv_reconstruct_mb_template.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * MPEG macroblock reconstruction - * Copyright (c) 2000,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 - */ - -#define NOT_MPEG12_H261 0 -#define MAY_BE_MPEG12_H261 1 -#define DEFINITELY_MPEG12_H261 2 - -/* put block[] to dest[] */ -static inline void put_dct(MpegEncContext *s, - int16_t *block, int i, uint8_t *dest, int line_size, int qscale) -{ - s->dct_unquantize_intra(s, block, i, qscale); - s->idsp.idct_put(dest, line_size, block); -} - -static inline void add_dequant_dct(MpegEncContext *s, - int16_t *block, int i, uint8_t *dest, int line_size, int qscale) -{ - if (s->block_last_index[i] >= 0) { - s->dct_unquantize_inter(s, block, i, qscale); - - s->idsp.idct_add(dest, line_size, block); - } -} - -/* generic function called after a macroblock has been parsed by the - decoder or after it has been encoded by the encoder. - - Important variables used: - s->mb_intra : true if intra macroblock - s->mv_dir : motion vector direction - s->mv_type : motion vector type - s->mv : motion vector - s->interlaced_dct : true if interlaced dct used (mpeg2) - */ -static av_always_inline -void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], - int lowres_flag, int is_mpeg12) -{ -#define IS_MPEG12_H261(s) (is_mpeg12 == MAY_BE_MPEG12_H261 ? ((s)->out_format <= FMT_H261) : is_mpeg12) - const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; - - s->cur_pic.qscale_table[mb_xy] = s->qscale; - - /* update DC predictors for P macroblocks */ - if (!s->mb_intra) { - if (is_mpeg12 != DEFINITELY_MPEG12_H261 && (s->h263_pred || s->h263_aic)) { - if (s->mbintra_table[mb_xy]) - ff_clean_intra_table_entries(s); - } else { - s->last_dc[0] = - s->last_dc[1] = - s->last_dc[2] = 128 << s->intra_dc_precision; - } - } else if (is_mpeg12 != DEFINITELY_MPEG12_H261 && (s->h263_pred || s->h263_aic)) - s->mbintra_table[mb_xy] = 1; - -#if IS_ENCODER - if ((s->avctx->flags & AV_CODEC_FLAG_PSNR) || s->frame_skip_threshold || s->frame_skip_factor || - !((s->intra_only || s->pict_type == AV_PICTURE_TYPE_B) && - s->avctx->mb_decision != FF_MB_DECISION_RD)) // FIXME precalc -#endif /* IS_ENCODER */ - { - uint8_t *dest_y = s->dest[0], *dest_cb = s->dest[1], *dest_cr = s->dest[2]; - int dct_linesize, dct_offset; - const int linesize = s->cur_pic.linesize[0]; //not s->linesize as this would be wrong for field pics - const int uvlinesize = s->cur_pic.linesize[1]; - const int block_size = lowres_flag ? 8 >> s->avctx->lowres : 8; - - /* avoid copy if macroblock skipped in last frame too */ - /* skip only during decoding as we might trash the buffers during encoding a bit */ - if (!IS_ENCODER) { - uint8_t *mbskip_ptr = &s->mbskip_table[mb_xy]; - - if (s->mb_skipped) { - s->mb_skipped = 0; - av_assert2(s->pict_type!=AV_PICTURE_TYPE_I); - *mbskip_ptr = 1; - } else if (!s->cur_pic.reference) { - *mbskip_ptr = 1; - } else{ - *mbskip_ptr = 0; /* not skipped */ - } - } - - dct_linesize = linesize << s->interlaced_dct; - dct_offset = s->interlaced_dct ? linesize : linesize * block_size; - - if (!s->mb_intra) { - /* motion handling */ - /* decoding or more than one mb_type (MC was already done otherwise) */ - -#if !IS_ENCODER - if (HAVE_THREADS && is_mpeg12 != DEFINITELY_MPEG12_H261 && - s->avctx->active_thread_type & FF_THREAD_FRAME) { - if (s->mv_dir & MV_DIR_FORWARD) { - ff_thread_progress_await(&s->last_pic.ptr->progress, - lowest_referenced_row(s, 0)); - } - if (s->mv_dir & MV_DIR_BACKWARD) { - ff_thread_progress_await(&s->next_pic.ptr->progress, - lowest_referenced_row(s, 1)); - } - } - - if (lowres_flag) { - const h264_chroma_mc_func *op_pix = s->h264chroma.put_h264_chroma_pixels_tab; - - if (s->mv_dir & MV_DIR_FORWARD) { - MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, s->last_pic.data, op_pix); - op_pix = s->h264chroma.avg_h264_chroma_pixels_tab; - } - if (s->mv_dir & MV_DIR_BACKWARD) { - MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 1, s->next_pic.data, op_pix); - } - } else { - const op_pixels_func (*op_pix)[4]; - const qpel_mc_func (*op_qpix)[16]; - - if ((is_mpeg12 == DEFINITELY_MPEG12_H261 || !s->no_rounding) || s->pict_type == AV_PICTURE_TYPE_B) { - op_pix = s->hdsp.put_pixels_tab; - op_qpix = s->qdsp.put_qpel_pixels_tab; - } else { - op_pix = s->hdsp.put_no_rnd_pixels_tab; - op_qpix = s->qdsp.put_no_rnd_qpel_pixels_tab; - } - if (s->mv_dir & MV_DIR_FORWARD) { - ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 0, s->last_pic.data, op_pix, op_qpix); - op_pix = s->hdsp.avg_pixels_tab; - op_qpix = s->qdsp.avg_qpel_pixels_tab; - } - if (s->mv_dir & MV_DIR_BACKWARD) { - ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 1, s->next_pic.data, op_pix, op_qpix); - } - } - - /* skip dequant / idct if we are really late ;) */ - if (s->avctx->skip_idct) { - if( (s->avctx->skip_idct >= AVDISCARD_NONREF && s->pict_type == AV_PICTURE_TYPE_B) - ||(s->avctx->skip_idct >= AVDISCARD_NONKEY && s->pict_type != AV_PICTURE_TYPE_I) - || s->avctx->skip_idct >= AVDISCARD_ALL) - return; - } - - /* add dct residue */ - if (!(IS_MPEG12_H261(s) || s->msmpeg4_version != MSMP4_UNUSED || - (s->codec_id == AV_CODEC_ID_MPEG4 && !s->mpeg_quant))) -#endif /* !IS_ENCODER */ - { - add_dequant_dct(s, block[0], 0, dest_y , dct_linesize, s->qscale); - add_dequant_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->qscale); - add_dequant_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->qscale); - add_dequant_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); - - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - av_assert2(IS_ENCODER || s->chroma_y_shift); - if (!IS_ENCODER || s->chroma_y_shift) { - add_dequant_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); - add_dequant_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); - } else { - dct_linesize >>= 1; - dct_offset >>= 1; - add_dequant_dct(s, block[4], 4, dest_cb, dct_linesize, s->chroma_qscale); - add_dequant_dct(s, block[5], 5, dest_cr, dct_linesize, s->chroma_qscale); - add_dequant_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->chroma_qscale); - add_dequant_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->chroma_qscale); - } - } - } -#if !IS_ENCODER - else if (is_mpeg12 == DEFINITELY_MPEG12_H261 || lowres_flag || (s->codec_id != AV_CODEC_ID_WMV2)) { - add_dct(s, block[0], 0, dest_y , dct_linesize); - add_dct(s, block[1], 1, dest_y + block_size, dct_linesize); - add_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize); - add_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize); - - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - if (s->chroma_y_shift) {//Chroma420 - add_dct(s, block[4], 4, dest_cb, uvlinesize); - add_dct(s, block[5], 5, dest_cr, uvlinesize); - } else { - //chroma422 - dct_linesize = uvlinesize << s->interlaced_dct; - dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; - - add_dct(s, block[4], 4, dest_cb, dct_linesize); - add_dct(s, block[5], 5, dest_cr, dct_linesize); - add_dct(s, block[6], 6, dest_cb+dct_offset, dct_linesize); - add_dct(s, block[7], 7, dest_cr+dct_offset, dct_linesize); - if (!s->chroma_x_shift) {//Chroma444 - add_dct(s, block[8], 8, dest_cb+block_size, dct_linesize); - add_dct(s, block[9], 9, dest_cr+block_size, dct_linesize); - add_dct(s, block[10], 10, dest_cb+block_size+dct_offset, dct_linesize); - add_dct(s, block[11], 11, dest_cr+block_size+dct_offset, dct_linesize); - } - } - } //fi gray - } else if (CONFIG_WMV2_DECODER) { - ff_wmv2_add_mb(s, block, dest_y, dest_cb, dest_cr); - } -#endif /* !IS_ENCODER */ - } else { -#if !IS_ENCODER - /* Only MPEG-4 Simple Studio Profile is supported in > 8-bit mode. - TODO: Integrate 10-bit properly into mpegvideo.c so that ER works properly */ - if (is_mpeg12 != DEFINITELY_MPEG12_H261 && CONFIG_MPEG4_DECODER && - /* s->codec_id == AV_CODEC_ID_MPEG4 && */ - s->avctx->bits_per_raw_sample > 8) { - ff_mpeg4_decode_studio(s, dest_y, dest_cb, dest_cr, block_size, - uvlinesize, dct_linesize, dct_offset); - } else if (!IS_MPEG12_H261(s)) -#endif /* !IS_ENCODER */ - { - /* dct only in intra block */ - put_dct(s, block[0], 0, dest_y , dct_linesize, s->qscale); - put_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->qscale); - put_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->qscale); - put_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); - - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - if (s->chroma_y_shift) { - put_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); - put_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); - } else { - dct_offset >>=1; - dct_linesize >>=1; - put_dct(s, block[4], 4, dest_cb, dct_linesize, s->chroma_qscale); - put_dct(s, block[5], 5, dest_cr, dct_linesize, s->chroma_qscale); - put_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->chroma_qscale); - put_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->chroma_qscale); - } - } - } -#if !IS_ENCODER - else { - s->idsp.idct_put(dest_y, dct_linesize, block[0]); - s->idsp.idct_put(dest_y + block_size, dct_linesize, block[1]); - s->idsp.idct_put(dest_y + dct_offset, dct_linesize, block[2]); - s->idsp.idct_put(dest_y + dct_offset + block_size, dct_linesize, block[3]); - - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - if (s->chroma_y_shift) { - s->idsp.idct_put(dest_cb, uvlinesize, block[4]); - s->idsp.idct_put(dest_cr, uvlinesize, block[5]); - } else { - dct_linesize = uvlinesize << s->interlaced_dct; - dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; - - s->idsp.idct_put(dest_cb, dct_linesize, block[4]); - s->idsp.idct_put(dest_cr, dct_linesize, block[5]); - s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, block[6]); - s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, block[7]); - if (!s->chroma_x_shift) { //Chroma444 - s->idsp.idct_put(dest_cb + block_size, dct_linesize, block[8]); - s->idsp.idct_put(dest_cr + block_size, dct_linesize, block[9]); - s->idsp.idct_put(dest_cb + block_size + dct_offset, dct_linesize, block[10]); - s->idsp.idct_put(dest_cr + block_size + dct_offset, dct_linesize, block[11]); - } - } - } //gray - } -#endif /* !IS_ENCODER */ - } - } -} diff --git a/libavcodec/mscc.c b/libavcodec/mscc.c index 6d57f1b62..ba48fc08d 100644 --- a/libavcodec/mscc.c +++ b/libavcodec/mscc.c @@ -184,16 +184,11 @@ inflate_error: const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &size); if (pal && size == AVPALETTE_SIZE) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif for (j = 0; j < 256; j++) s->pal[j] = 0xFF000000 | AV_RL32(pal + j * 4); } else if (pal) { av_log(avctx, AV_LOG_ERROR, - "Palette size %"SIZE_SPECIFIER" is wrong\n", size); + "Palette size %zu is wrong\n", size); } memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); } diff --git a/libavcodec/msmpeg4.c b/libavcodec/msmpeg4.c index 01e6f3ccc..fed255989 100644 --- a/libavcodec/msmpeg4.c +++ b/libavcodec/msmpeg4.c @@ -28,7 +28,9 @@ */ #include "config.h" +#include "config_components.h" +#include "libavutil/avassert.h" #include "libavutil/thread.h" #if ARCH_X86 #include "libavutil/x86/asm.h" @@ -36,11 +38,13 @@ #include "avcodec.h" #include "idctdsp.h" +#include "mathops.h" #include "mpegvideo.h" #include "msmpeg4.h" #include "mpeg4videodata.h" #include "msmpeg4data.h" #include "msmpeg4_vc1_data.h" +#include "wmv2dsp.h" /* * You can also call this codec: MPEG-4 with a twist! @@ -114,11 +118,15 @@ static av_cold void msmpeg4_common_init_static(void) init_h263_dc_for_msmpeg4(); } -av_cold void ff_msmpeg4_common_init(MpegEncContext *s) +av_cold void ff_msmpeg4_common_init(MPVContext *const s, + uint8_t permutated_intra_h_scantable[64], + uint8_t permutated_intra_v_scantable[64]) { static AVOnce init_static_once = AV_ONCE_INIT; switch(s->msmpeg4_version){ + default: + av_unreachable("ff_msmpeg4_common_init only called by MSMP4 1-3 and WMV1/2"); case MSMP4_V1: case MSMP4_V2: // Correct *_dc_scale_tables (ff_mpeg1_dc_scale_table) is the default @@ -132,22 +140,22 @@ av_cold void ff_msmpeg4_common_init(MpegEncContext *s) s->c_dc_scale_table= ff_mpeg4_c_dc_scale_table; } break; - case MSMP4_WMV1: +#if CONFIG_WMV2_DECODER || CONFIG_WMV2_ENCODER case MSMP4_WMV2: + ff_wmv2dsp_init(&s->idsp); + // fallthrough +#endif + case MSMP4_WMV1: s->y_dc_scale_table= ff_wmv1_y_dc_scale_table; s->c_dc_scale_table= ff_wmv1_c_dc_scale_table; - break; - } - - if (s->msmpeg4_version >= MSMP4_WMV1) { ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_wmv1_scantable[1]); ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, ff_wmv1_scantable[0]); - ff_permute_scantable(s->permutated_intra_h_scantable, ff_wmv1_scantable[2], + ff_permute_scantable(permutated_intra_h_scantable, ff_wmv1_scantable[2], s->idsp.idct_permutation); - ff_permute_scantable(s->permutated_intra_v_scantable, ff_wmv1_scantable[3], + ff_permute_scantable(permutated_intra_v_scantable, ff_wmv1_scantable[3], s->idsp.idct_permutation); + break; } - //Note the default tables are set in common_init in mpegvideo.c ff_thread_once(&init_static_once, msmpeg4_common_init_static); } @@ -197,7 +205,7 @@ int ff_msmpeg4_pred_dc(MpegEncContext *s, int n, int16_t **dc_val_ptr, int *dir_ptr) { int a, b, c, wrap, pred, scale; - int16_t *dc_val; + int16_t *const dc_val = s->dc_val + s->block_index[n]; /* find prediction */ if (n < 4) { @@ -207,7 +215,6 @@ int ff_msmpeg4_pred_dc(MpegEncContext *s, int n, } wrap = s->block_wrap[n]; - dc_val= s->dc_val[0] + s->block_index[n]; /* B C * A X diff --git a/libavcodec/msmpeg4.h b/libavcodec/msmpeg4.h index b918028fe..69299c000 100644 --- a/libavcodec/msmpeg4.h +++ b/libavcodec/msmpeg4.h @@ -31,7 +31,9 @@ #define DC_MAX 119 -void ff_msmpeg4_common_init(MpegEncContext *s); +void ff_msmpeg4_common_init(MPVContext *const s, + uint8_t permutated_intra_h_scantable[64], + uint8_t permutated_intra_v_scantable[64]); int ff_msmpeg4_coded_block_pred(MpegEncContext * s, int n, uint8_t **coded_block_ptr); diff --git a/libavcodec/msmpeg4data.c b/libavcodec/msmpeg4data.c index 65546da66..b3603f7db 100644 --- a/libavcodec/msmpeg4data.c +++ b/libavcodec/msmpeg4data.c @@ -481,1144 +481,513 @@ RLTable ff_rl_table[NB_RL_TABLES] = { /* motion vector table 0 */ -static const uint16_t table0_mv_code[1100] = { - 0x0001, 0x0003, 0x0005, 0x0007, 0x0003, 0x0008, 0x000c, 0x0001, - 0x0002, 0x001b, 0x0006, 0x000b, 0x0015, 0x0002, 0x000e, 0x000f, - 0x0014, 0x0020, 0x0022, 0x0025, 0x0027, 0x0029, 0x002d, 0x004b, - 0x004d, 0x0003, 0x0022, 0x0023, 0x0025, 0x0027, 0x0042, 0x0048, - 0x0049, 0x0050, 0x005c, 0x0091, 0x009f, 0x000e, 0x0043, 0x004c, - 0x0054, 0x0056, 0x008c, 0x0098, 0x009a, 0x009b, 0x00b1, 0x00b2, - 0x0120, 0x0121, 0x0126, 0x0133, 0x0139, 0x01a1, 0x01a4, 0x01a5, - 0x01a6, 0x01a7, 0x01ae, 0x01af, 0x000b, 0x0019, 0x0085, 0x0090, - 0x009b, 0x00aa, 0x00af, 0x010c, 0x010e, 0x011c, 0x011e, 0x0133, - 0x0144, 0x0160, 0x0174, 0x0175, 0x0177, 0x0178, 0x0249, 0x024b, - 0x0252, 0x0261, 0x0265, 0x0270, 0x0352, 0x0353, 0x0355, 0x0359, - 0x0010, 0x0011, 0x0013, 0x0034, 0x0035, 0x0036, 0x0037, 0x003d, - 0x003e, 0x0109, 0x0126, 0x0156, 0x021a, 0x021e, 0x023a, 0x023e, - 0x028e, 0x028f, 0x02cf, 0x0491, 0x0494, 0x049f, 0x04a0, 0x04a3, - 0x04a6, 0x04a7, 0x04ad, 0x04ae, 0x04c0, 0x04c4, 0x04c6, 0x04c8, - 0x04c9, 0x04f5, 0x04f6, 0x04f7, 0x0680, 0x0682, 0x0683, 0x0688, - 0x0689, 0x068d, 0x068e, 0x068f, 0x06a2, 0x06a3, 0x06a9, 0x06b0, - 0x06b1, 0x06b4, 0x06b5, 0x0024, 0x0060, 0x0063, 0x0078, 0x0079, - 0x0211, 0x0244, 0x0245, 0x0247, 0x0248, 0x0249, 0x024a, 0x024b, - 0x026b, 0x02af, 0x02b8, 0x02bb, 0x0436, 0x0476, 0x0477, 0x047e, - 0x04c8, 0x04c9, 0x04ca, 0x0514, 0x0586, 0x0587, 0x0598, 0x059d, - 0x05d9, 0x05da, 0x0920, 0x0921, 0x093b, 0x093c, 0x093d, 0x0942, - 0x0943, 0x0944, 0x0945, 0x0959, 0x095e, 0x095f, 0x0982, 0x0983, - 0x098e, 0x098f, 0x09c4, 0x09e7, 0x09e8, 0x09e9, 0x0d02, 0x0d17, - 0x0d18, 0x0d19, 0x0d41, 0x0d42, 0x0d43, 0x0d50, 0x0d5f, 0x0d6d, - 0x0d6e, 0x0d6f, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x041e, 0x041f, 0x0420, 0x0421, - 0x048c, 0x048d, 0x04d3, 0x04d4, 0x04d5, 0x055c, 0x055d, 0x0572, - 0x0573, 0x0574, 0x0575, 0x08de, 0x08df, 0x08fe, 0x08ff, 0x0996, - 0x0a36, 0x0a37, 0x0b08, 0x0b09, 0x0b0a, 0x0b0b, 0x0b32, 0x0b33, - 0x0b34, 0x0b35, 0x0b36, 0x0b37, 0x0b38, 0x0b39, 0x0bb0, 0x0bf7, - 0x0bf8, 0x0bf9, 0x0bfa, 0x0bfb, 0x0bfc, 0x0bfd, 0x0bfe, 0x0bff, - 0x1254, 0x1255, 0x1256, 0x1257, 0x1270, 0x1271, 0x1272, 0x1273, - 0x1274, 0x1275, 0x12ab, 0x12ac, 0x12ad, 0x12ae, 0x12af, 0x12b0, - 0x12b1, 0x1315, 0x1316, 0x1317, 0x13bf, 0x13c0, 0x13c1, 0x13c2, - 0x13c3, 0x13c4, 0x13c5, 0x13c6, 0x13c7, 0x13c8, 0x13c9, 0x13ca, - 0x13cb, 0x13cc, 0x13cd, 0x1a06, 0x1a07, 0x1a28, 0x1a29, 0x1a2a, - 0x1a2b, 0x1a2c, 0x1a2d, 0x1a80, 0x1abb, 0x1abc, 0x1abd, 0x1ad8, - 0x1ad9, 0x0094, 0x0095, 0x0096, 0x0097, 0x00a0, 0x00a1, 0x00a2, - 0x00a3, 0x0831, 0x0832, 0x0833, 0x0834, 0x0835, 0x0836, 0x0837, - 0x0838, 0x0839, 0x083a, 0x083b, 0x0939, 0x093a, 0x093b, 0x093c, - 0x093d, 0x093e, 0x093f, 0x09a0, 0x09a1, 0x09a2, 0x09a3, 0x09a4, - 0x09a5, 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, - 0x11b3, 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, - 0x11bb, 0x132f, 0x1454, 0x1455, 0x1456, 0x1457, 0x1458, 0x1459, - 0x145a, 0x145b, 0x145c, 0x145d, 0x145e, 0x145f, 0x1460, 0x1461, - 0x1462, 0x1463, 0x1464, 0x1465, 0x1466, 0x1467, 0x1468, 0x1469, - 0x146a, 0x146b, 0x17de, 0x17df, 0x17e0, 0x17e1, 0x17e2, 0x17e3, - 0x17e4, 0x17e5, 0x17e6, 0x17e7, 0x17e8, 0x17e9, 0x17ea, 0x17eb, - 0x17ec, 0x17ed, 0x2540, 0x2541, 0x2542, 0x2543, 0x2544, 0x2545, - 0x2546, 0x2547, 0x2548, 0x2549, 0x254a, 0x254b, 0x254c, 0x254d, - 0x254e, 0x254f, 0x2550, 0x2551, 0x2552, 0x2553, 0x2554, 0x2555, - 0x2628, 0x2766, 0x2767, 0x2768, 0x2769, 0x276a, 0x276b, 0x276c, - 0x276d, 0x276e, 0x276f, 0x2770, 0x2771, 0x2772, 0x2773, 0x2774, - 0x2775, 0x2776, 0x2777, 0x2778, 0x2779, 0x277a, 0x277b, 0x277c, - 0x277d, 0x3503, 0x3544, 0x3545, 0x3546, 0x3547, 0x3560, 0x3561, - 0x3562, 0x3563, 0x3564, 0x3565, 0x3566, 0x3567, 0x3568, 0x3569, - 0x356a, 0x356b, 0x356c, 0x356d, 0x356e, 0x356f, 0x3570, 0x3571, - 0x3572, 0x3573, 0x3574, 0x3575, 0x03f0, 0x103d, 0x103e, 0x103f, - 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, - 0x1048, 0x1049, 0x104a, 0x104b, 0x104c, 0x104d, 0x104e, 0x104f, - 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, - 0x1058, 0x1059, 0x105a, 0x105b, 0x105c, 0x105d, 0x105e, 0x105f, - 0x1060, 0x1061, 0x1270, 0x1271, 0x21b8, 0x21b9, 0x21ba, 0x21bb, - 0x21bc, 0x21bd, 0x21be, 0x21bf, 0x21f0, 0x21f1, 0x21f2, 0x21f3, - 0x21f4, 0x21f5, 0x21f6, 0x21f7, 0x21f8, 0x21f9, 0x21fa, 0x21fb, - 0x21fc, 0x21fd, 0x21fe, 0x21ff, 0x2340, 0x2341, 0x2342, 0x2343, - 0x2344, 0x2345, 0x2346, 0x2347, 0x2348, 0x2349, 0x234a, 0x234b, - 0x234c, 0x234d, 0x234e, 0x234f, 0x2350, 0x2351, 0x2352, 0x2353, - 0x2354, 0x2355, 0x2356, 0x2357, 0x265c, 0x2f88, 0x2f89, 0x2f8a, - 0x2f8b, 0x2f8c, 0x2f8d, 0x2f8e, 0x2f8f, 0x2f90, 0x2f91, 0x2f92, - 0x2f93, 0x2f94, 0x2f95, 0x2f96, 0x2f97, 0x2f98, 0x2f99, 0x2f9a, - 0x2f9b, 0x2f9c, 0x2f9d, 0x2f9e, 0x2f9f, 0x2fa0, 0x2fa1, 0x2fa2, - 0x2fa3, 0x2fa4, 0x2fa5, 0x2fa6, 0x2fa7, 0x2fa8, 0x2fa9, 0x2faa, - 0x2fab, 0x2fac, 0x2fad, 0x2fae, 0x2faf, 0x2fb0, 0x2fb1, 0x2fb2, - 0x2fb3, 0x2fb4, 0x2fb5, 0x2fb6, 0x2fb7, 0x2fb8, 0x2fb9, 0x2fba, - 0x2fbb, 0x4c52, 0x4c53, 0x4e28, 0x4e29, 0x4e2a, 0x4e2b, 0x4e2c, - 0x4e2d, 0x4e2e, 0x4e2f, 0x4e30, 0x4e31, 0x4e32, 0x4e33, 0x4e34, - 0x4e35, 0x4e36, 0x4e37, 0x4e38, 0x4e39, 0x4e3a, 0x4e3b, 0x4e3c, - 0x4e3d, 0x4e3e, 0x4e3f, 0x4e80, 0x4e81, 0x4e82, 0x4e83, 0x4e84, - 0x4e85, 0x4e86, 0x4e87, 0x4e88, 0x4e89, 0x4e8a, 0x4e8b, 0x4e8c, - 0x4e8d, 0x4e8e, 0x4e8f, 0x4e90, 0x4e91, 0x4e92, 0x4e93, 0x4e94, - 0x4e95, 0x4e96, 0x4e97, 0x4e98, 0x4e99, 0x4e9a, 0x4e9b, 0x4e9c, - 0x4e9d, 0x4e9e, 0x4e9f, 0x4ea0, 0x4ea1, 0x4ea2, 0x4ea3, 0x4ea4, - 0x4ea5, 0x4ea6, 0x4ea7, 0x4ea8, 0x4ea9, 0x4eaa, 0x4eab, 0x4eac, - 0x4ead, 0x4eae, 0x4eaf, 0x4eb0, 0x4eb1, 0x4eb2, 0x4eb3, 0x4eb4, - 0x4eb5, 0x4eb6, 0x4eb7, 0x4eb8, 0x4eb9, 0x4eba, 0x4ebb, 0x4ebc, - 0x4ebd, 0x4ebe, 0x4ebf, 0x4ec0, 0x4ec1, 0x4ec2, 0x4ec3, 0x4ec4, - 0x4ec5, 0x4ec6, 0x4ec7, 0x4ec8, 0x4ec9, 0x4eca, 0x4ecb, 0x6a04, - 0x6a05, 0x07e2, 0x07e3, 0x07e4, 0x07e5, 0x07e6, 0x07e7, 0x07e8, - 0x07e9, 0x07ea, 0x07eb, 0x07ec, 0x07ed, 0x07ee, 0x07ef, 0x07f0, - 0x07f1, 0x07f2, 0x07f3, 0x07f4, 0x07f5, 0x07f6, 0x07f7, 0x07f8, - 0x07f9, 0x07fa, 0x07fb, 0x07fc, 0x07fd, 0x07fe, 0x07ff, 0x2000, - 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, - 0x2009, 0x200a, 0x200b, 0x200c, 0x200d, 0x200e, 0x200f, 0x2010, - 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, - 0x2019, 0x201a, 0x201b, 0x201c, 0x201d, 0x201e, 0x201f, 0x2020, - 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, - 0x2029, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e, 0x202f, 0x2030, - 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, - 0x2039, 0x203a, 0x203b, 0x203c, 0x203d, 0x203e, 0x203f, 0x2040, - 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, - 0x2049, 0x204a, 0x204b, 0x204c, 0x204d, 0x204e, 0x204f, 0x2050, - 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, - 0x2059, 0x205a, 0x205b, 0x205c, 0x205d, 0x205e, 0x205f, 0x2060, - 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, - 0x2069, 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0x2070, - 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, - 0x2079, 0x4cba, 0x4cbb, 0x5d88, 0x5d89, 0x5d8a, 0x5d8b, 0x5d8c, - 0x5d8d, 0x5d8e, 0x5d8f, 0x5db0, 0x5db1, 0x5db2, 0x5db3, 0x5db4, - 0x5db5, 0x5db6, 0x5db7, 0x5db8, 0x5db9, 0x5dba, 0x5dbb, 0x5dbc, - 0x5dbd, 0x5dbe, 0x5dbf, 0x5e40, 0x5e41, 0x5e42, 0x5e43, 0x5e44, - 0x5e45, 0x5e46, 0x5e47, 0x5e48, 0x5e49, 0x5e4a, 0x5e4b, 0x5e4c, - 0x5e4d, 0x5e4e, 0x5e4f, 0x5e50, 0x5e51, 0x5e52, 0x5e53, 0x5e54, - 0x5e55, 0x5e56, 0x5e57, 0x5e58, 0x5e59, 0x5e5a, 0x5e5b, 0x5e5c, - 0x5e5d, 0x5e5e, 0x5e5f, 0x5e60, 0x5e61, 0x5e62, 0x5e63, 0x5e64, - 0x5e65, 0x5e66, 0x5e67, 0x5e68, 0x5e69, 0x5e6a, 0x5e6b, 0x5e6c, - 0x5e6d, 0x5e6e, 0x5e6f, 0x5e70, 0x5e71, 0x5e72, 0x5e73, 0x5e74, - 0x5e75, 0x5e76, 0x5e77, 0x5e78, 0x5e79, 0x5e7a, 0x5e7b, 0x5e7c, - 0x5e7d, 0x5e7e, 0x5e7f, 0x5e80, 0x5e81, 0x5e82, 0x5e83, 0x5e84, - 0x5e85, 0x5e86, 0x5e87, 0x5e88, 0x5e89, 0x5e8a, 0x5e8b, 0x5e8c, - 0x5e8d, 0x5e8e, 0x5e8f, 0x5e90, 0x5e91, 0x5e92, 0x5e93, 0x5e94, - 0x5e95, 0x5e96, 0x5e97, 0x5e98, 0x5e99, 0x5e9a, 0x5e9b, 0x5e9c, - 0x5e9d, 0x5e9e, 0x5e9f, 0x5ea0, 0x5ea1, 0x5ea2, 0x5ea3, 0x5ea4, - 0x5ea5, 0x5ea6, 0x5ea7, 0x5ea8, 0x5ea9, 0x5eaa, 0x5eab, 0x5eac, - 0x5ead, 0x5eae, 0x5eaf, 0x5eb0, 0x5eb1, 0x5eb2, 0x5eb3, 0x5eb4, - 0x5eb5, 0x5eb6, 0x5eb7, 0x5eb8, 0x5eb9, 0x5eba, 0x5ebb, 0x5ebc, - 0x5ebd, 0x5ebe, 0x5ebf, 0x5ec0, 0x5ec1, 0x5ec2, 0x5ec3, 0x5ec4, - 0x5ec5, 0x5ec6, 0x5ec7, 0x5ec8, 0x5ec9, 0x5eca, 0x5ecb, 0x5ecc, - 0x5ecd, 0x5ece, 0x5ecf, 0x5ed0, 0x5ed1, 0x5ed2, 0x5ed3, 0x5ed4, - 0x5ed5, 0x5ed6, 0x5ed7, 0x5ed8, 0x5ed9, 0x5eda, 0x5edb, 0x5edc, - 0x5edd, 0x5ede, 0x5edf, 0x5ee0, 0x5ee1, 0x5ee2, 0x5ee3, 0x5ee4, - 0x5ee5, 0x5ee6, 0x5ee7, 0x5ee8, 0x5ee9, 0x5eea, 0x5eeb, 0x5eec, - 0x5eed, 0x5eee, 0x5eef, 0x5ef0, 0x5ef1, 0x5ef2, 0x5ef3, 0x5ef4, - 0x5ef5, 0x5ef6, 0x5ef7, 0x5ef8, 0x5ef9, 0x5efa, 0x5efb, 0x5efc, - 0x5efd, 0x5efe, 0x5eff, 0x5f00, 0x5f01, 0x5f02, 0x5f03, 0x5f04, - 0x5f05, 0x5f06, 0x5f07, 0x5f08, 0x5f09, 0x5f0a, 0x5f0b, 0x5f0c, - 0x5f0d, 0x5f0e, 0x5f0f, 0x0000, +#define E(mvx, mvy) ((mvx << 8) | mvy) +#define ESCAPE 0 + +const uint16_t ff_msmp4_mv_table0[MSMPEG4_MV_TABLES_NB_ELEMS] = { + ESCAPE, E(31, 39), E(38, 31), E(24, 32), E(23, 30), E(34, 20), + E(33, 22), E(21, 29), E(28, 34), E(33, 24), E(49, 32), E(27, 41), + E(32, 2), E(40, 33), E(34, 39), E(37, 25), E(29, 26), E(38, 28), + E(43, 31), E(37, 33), E(31, 35), E(32, 35), E(25, 29), E(26, 28), + E(32, 42), E(33, 23), E(42, 31), E(35, 36), E(27, 31), E(36, 30), + E(21, 32), E(23, 32), E(43, 32), E(36, 32), E(39, 29), E(38, 30), + E(36, 34), E(34, 36), E(19, 30), E(20, 38), E(41, 41), E(26, 44), + E(41, 53), E(42, 11), E(42, 20), E(42, 25), E(26, 45), E(26, 46), + E(26, 47), E(26, 48), E( 1, 39), E(26, 52), E(37, 46), E(37, 49), + E(37, 63), E(23, 55), E(34, 44), E(42, 38), E(27, 13), E(43, 13), + E(34, 57), E(27, 22), E(31, 51), E(24, 16), E(33, 12), E(16, 28), + E( 3, 35), E(31, 57), E(24, 25), E(31, 33), E(33, 33), E(34, 32), + E(31, 34), E(34, 31), E(33, 20), E(24, 26), E( 4, 28), E(44, 28), + E(44, 29), E(11, 32), E(44, 31), E(31, 62), E(13, 34), E(13, 35), + E(44, 35), E(45, 19), E(13, 49), E(25, 48), E(22, 39), E(38, 40), + E(26, 18), E(38, 43), E(38, 46), E(39, 11), E(32, 6), E(30, 48), + E(39, 19), E(30, 49), E(22, 41), E(32, 10), E(26, 23), E(30, 58), + E(47, 17), E(47, 21), E(47, 23), E(19, 34), E(47, 30), E(30, 60), + E(31, 0), E(35, 44), E( 8, 34), E(23, 26), E(47, 37), E(47, 46), + E(27, 43), E(35, 49), E(47, 59), E(31, 4), E(48, 34), E(35, 59), + E(19, 37), E(36, 22), E(49, 25), E(49, 28), E(33, 46), E(31, 6), + E(39, 40), E(27, 59), E(39, 42), E(49, 36), E(49, 61), E(50, 28), + E(50, 30), E(50, 31), E(39, 43), E(31, 10), E(51, 22), E(51, 23), + E(39, 47), E(28, 20), E(33, 52), E(33, 55), E(21, 36), E(40, 25), + E(31, 16), E(52, 1), E(53, 11), E(40, 27), E(53, 29), E( 9, 5), + E(33, 63), E(31, 18), E(53, 41), E(54, 31), E(54, 34), E(54, 38), + E(55, 1), E(55, 5), E(34, 13), E(15, 28), E(56, 31), E(25, 17), + E(56, 38), E(21, 39), E(21, 41), E(40, 36), E(40, 37), E(25, 22), + E(40, 39), E(58, 33), E(36, 43), E( 5, 43), E(41, 15), E(41, 17), + E(12, 49), E(60, 30), E(41, 21), E(41, 22), E(37, 20), E(22, 10), + E(61, 17), E(18, 25), E(29, 54), E(29, 57), E(30, 3), E(61, 34), + E(30, 8), E(61, 36), E(62, 25), E(62, 31), E(30, 14), E(30, 15), + E(63, 19), E(18, 29), E(13, 25), E(30, 18), E(45, 30), E( 1, 63), + E(34, 16), E(31, 42), E(22, 28), E(35, 13), E(15, 33), E(46, 33), + E(46, 35), E(35, 19), E(31, 46), E(28, 43), E(29, 17), E(29, 19), + E(23, 36), E(41, 39), E(27, 24), E(14, 31), E(53, 32), E(53, 33), + E(27, 26), E(24, 28), E(32, 62), E(57, 33), E(32, 63), E(17, 33), + E(42, 39), E(37, 19), E(29, 49), E(33, 17), E( 1, 31), E(25, 43), + E(32, 13), E(32, 15), E(63, 29), E(26, 25), E(40, 35), E(23, 34), + E(27, 25), E(22, 33), E(24, 29), E(22, 31), E(39, 39), E(43, 35), + E(27, 36), E(37, 24), E( 6, 32), E(42, 30), E(24, 33), E(40, 31), + E(28, 39), E(32, 1), E(32, 41), E(41, 32), E(36, 31), E(28, 32), + E(35, 31), E(29, 31), E(38, 32), E(23, 31), E(27, 30), E(32, 59), + E(32, 22), E(32, 21), E(30, 39), E(35, 25), E(26, 34), E(34, 38), + E(30, 28), E(44, 33), E(36, 23), E(47, 33), E(26, 27), E(30, 44), + E(31, 60), E(41, 30), E(39, 36), E(33, 19), E(33, 29), E(32, 36), + E(22, 34), E(45, 31), E(36, 24), E(32, 16), E(45, 35), E(19, 32), + E(36, 27), E(32, 4), E(43, 33), E(60, 32), E(37, 31), E(35, 33), + E(35, 32), E(34, 29), E(33, 28), E(25, 33), E(25, 34), E(21, 33), + E(36, 35), E(37, 32), E(29, 39), E(31, 24), E(30, 41), E(31, 3), + E(41, 35), E(22, 32), E(32, 39), E(32, 30), E(33, 32), E(32, 29), + E(33, 35), E(31, 28), E(28, 30), E(26, 33), E(31, 49), E(39, 41), + E(20, 28), E(20, 29), E(44, 34), E(23, 38), E(33, 7), E(34, 61), + E(29, 29), E(31, 38), E(35, 11), E(33, 50), E(33, 13), E(28, 41), + E(41, 19), E(23, 47), E(41, 25), E(41, 26), E(29, 15), E(25, 42), + E(26, 41), E(49, 29), E(29, 45), E(24, 27), E(37, 17), E(49, 35), + E(34, 33), E(30, 35), E(50, 32), E(51, 29), E(51, 32), E(26, 24), + E(39, 13), E(25, 26), E(26, 26), E(15, 31), E(39, 24), E(18, 33), + E(42, 28), E(17, 30), E( 4, 31), E(31, 11), E(32, 45), E(32, 46), + E(60, 33), E( 1, 33), E(42, 35), E(32, 57), E( 0, 32), E(12, 32), + E(19, 35), E(35, 45), E(22, 38), E(30, 21), E( 5, 33), E( 5, 31), + E(17, 31), E(29, 21), E(22, 35), E(31, 5), E(31, 17), E(43, 29), + E(37, 38), E(27, 38), E(32, 18), E(32, 58), E(32, 19), E(33, 43), + E(29, 41), E(33, 41), E(31, 37), E(30, 37), E(41, 33), E( 7, 32), + E(28, 31), E(34, 27), E(30, 27), E(37, 28), E(26, 36), E(34, 30), + E(31, 29), E(33, 30), E(27, 32), E(38, 29), E(30, 25), E(36, 28), + E(37, 36), E(21, 34), E(23, 39), E(19, 53), E(34, 41), E(36, 33), + E(32, 28), E(25, 32), E(29, 32), E(29, 33), E(33, 27), E(29, 27), + E(43, 30), E(35, 41), E(29, 43), E(26, 39), E(22, 29), E(32, 7), + E(19, 29), E(32, 17), E(25, 28), E(31, 19), E(41, 28), E(49, 31), + E(28, 25), E(34, 19), E(28, 40), E(39, 26), E(34, 21), E(19, 33), + E(37, 39), E(38, 23), E(29, 40), E(21, 30), E(36, 39), E(42, 34), + E(27, 28), E(59, 33), E(38, 33), E(35, 28), E(33, 34), E(30, 32), + E(30, 36), E(23, 35), E(33, 21), E(35, 23), E(31, 21), E(30, 26), + E(41, 31), E(39, 32), E(32, 27), E(26, 30), E(31, 22), E(37, 37), + E(38, 27), E(39, 27), E(32, 43), E(23, 29), E(32, 60), E(27, 39), + E(25, 35), E(61, 32), E(30, 33), E(30, 34), E(34, 28), E(33, 36), + E(37, 27), E(20, 22), E(20, 27), E(41, 20), E(13, 29), E( 2, 33), + E( 5, 41), E( 5, 42), E( 1, 35), E(32, 24), E(34, 24), E( 5, 62), + E(32, 50), E( 6, 29), E(32, 53), E(35, 50), E(20, 35), E(35, 55), + E(27, 42), E(35, 61), E(35, 63), E(36, 4), E(36, 7), E(13, 42), + E(36, 21), E(41, 46), E(41, 47), E(33, 37), E(28, 33), E(41, 49), + E( 3, 27), E(30, 46), E(42, 17), E(27, 55), E(20, 41), E(30, 50), + E(27, 63), E(28, 4), E(30, 56), E(21, 18), E(33, 8), E(33, 10), + E(14, 18), E(24, 51), E(30, 63), E(42, 36), E(24, 55), E(33, 18), + E(25, 5), E(42, 55), E(43, 9), E(14, 29), E(43, 17), E(43, 21), + E(14, 30), E(43, 27), E( 7, 1), E(36, 59), E(37, 7), E(37, 11), + E(37, 12), E(37, 15), E( 7, 5), E(14, 42), E(25, 24), E(43, 41), + E(43, 43), E(44, 7), E(15, 27), E(37, 22), E( 7, 25), E( 7, 31), + E( 3, 30), E( 1, 37), E( 8, 22), E(15, 39), E(15, 53), E( 8, 29), + E(44, 36), E(44, 37), E(44, 48), E(45, 0), E(45, 5), E(45, 13), + E(45, 17), E( 8, 31), E( 8, 32), E(45, 26), E(21, 46), E(45, 28), + E(28, 44), E(28, 45), E(28, 46), E(21, 53), E(28, 49), E(28, 51), + E(22, 3), E(37, 41), E(46, 3), E(46, 22), E(37, 42), E( 8, 33), + E(29, 5), E(37, 45), E(29, 7), E(22, 22), E(46, 40), E(37, 53), + E(22, 24), E(29, 14), E(47, 25), E(47, 27), E(38, 10), E(38, 12), + E(16, 34), E(38, 16), E(38, 17), E(33, 53), E(38, 20), E(22, 26), + E(47, 39), E(47, 45), E(29, 18), E(25, 45), E(16, 35), E( 0, 33), + E(48, 31), E( 1, 49), E(34, 4), E(48, 39), E(48, 42), E(34, 11), + E(25, 51), E(26, 5), E(26, 13), E(49, 26), E(49, 27), E(26, 17), + E( 1, 52), E(49, 30), E( 4, 0), E(26, 22), E( 4, 12), E(49, 34), + E( 1, 62), E( 9, 36), E(49, 38), E(49, 41), E(49, 47), E(10, 30), + E(49, 63), E(17, 38), E(38, 41), E(17, 43), E(17, 59), E(50, 33), + E(38, 45), E(50, 37), E(50, 38), E(22, 40), E(38, 47), E(51, 24), + E(38, 48), E(38, 49), E(51, 30), E(39, 1), E(39, 10), E(18, 22), + E(22, 49), E(39, 15), E(51, 39), E(22, 59), E(52, 31), E(52, 32), + E(52, 33), E(39, 18), E(53, 13), E(53, 15), E(10, 31), E(23, 21), + E(18, 27), E(29, 44), E(10, 42), E(53, 39), E(29, 46), E(54, 17), + E(11, 26), E(54, 32), E(11, 30), E(11, 31), E(55, 0), E( 1, 30), + E(18, 34), E(55, 9), E(55, 12), E(55, 13), E(55, 25), E(55, 31), + E(55, 32), E(29, 55), E(34, 43), E(18, 35), E(29, 61), E(56, 33), + E(56, 35), E(34, 46), E(57, 25), E(34, 47), E(34, 48), E(29, 62), + E(29, 63), E(57, 38), E(57, 61), E(35, 1), E(35, 2), E(35, 5), + E(35, 7), E(35, 9), E(39, 46), E(35, 10), E(59, 34), E(59, 35), + E(18, 36), E(59, 55), E(39, 51), E(30, 7), E(18, 40), E(40, 23), + E(60, 34), E(60, 37), E(61, 5), E(30, 13), E(18, 42), E(61, 18), + E(61, 25), E(19, 27), E(19, 28), E(41, 11), E(17, 37), E(26, 42), + E(20, 39), E(45, 37), E(46, 31), E(32, 49), E(37, 21), E(22, 27), + E(47, 29), E(29, 47), E(31, 53), E(27, 40), E(29, 51), E(30, 16), + E(21, 26), E(33, 1), E(35, 40), E(18, 30), E(25, 41), E(33, 44), + E(50, 34), E(51, 25), E(42, 27), E( 2, 31), E(15, 35), E(51, 35), + E(53, 31), E(33, 15), E(25, 49), E(29, 1), E(55, 35), E(37, 40), + E(38, 5), E(33, 58), E(38, 21), E(59, 29), E(38, 22), E(33, 59), + E(39, 45), E(13, 31), E(32, 9), E(40, 26), E(61, 9), E(61, 29), + E(32, 11), E( 9, 32), E(44, 30), E( 3, 3), E(31, 13), E(29, 20), + E(25, 18), E(24, 35), E(48, 32), E(16, 32), E(28, 24), E(49, 33), + E(22, 30), E(34, 40), E(31, 47), E(38, 39), E(39, 37), E(44, 32), + E(11, 33), E(35, 24), E(30, 23), E(33, 45), E(33, 47), E(36, 25), + E(31, 59), E(40, 34), E(25, 27), E(27, 27), E(38, 26), E(31, 40), + E(36, 37), E(28, 27), E(32, 31), E(31, 31), E(34, 35), E(32, 37), + E(34, 34), E(24, 31), E(39, 34), E(34, 37), E(27, 33), E(28, 35), + E(31, 61), E(36, 26), E(25, 39), E(45, 33), E(25, 31), E(35, 34), + E( 3, 31), E(34, 22), E(38, 37), E(39, 25), E(40, 30), E(38, 25), + E( 1, 32), E(25, 30), E(39, 35), E(30, 38), E(37, 29), E(32, 40), + E(28, 28), E(29, 38), E(32, 5), E(37, 34), E(31, 27), E(35, 27), + E(27, 29), E(23, 27), E(28, 23), E(33, 42), E(46, 32), E(15, 32), + E(13, 33), E(24, 36), E(41, 37), E(24, 37), E(34, 17), E(34, 18), + E(30, 22), E(26, 40), E(24, 38), E(14, 32), E(60, 31), E(21, 35), + E(29, 24), E(39, 17), E(23, 25), E(35, 17), E(37, 23), E(30, 24), + E(32, 61), E(19, 31), E(24, 34), E(25, 25), E(26, 38), E(45, 32), + E(38, 35), E(36, 29), E( 3, 32), E(26, 29), E(36, 36), E(30, 31), + E(59, 32), E(28, 36), E(63, 32), E(26, 32), E(38, 34), E(63, 33), + E(31, 20), E(27, 11), E(20, 32), E(24, 30), E(33, 3), E(37, 35), + E(28, 38), E(39, 30), E(32, 3), E(31, 26), E(39, 31), E(35, 29), + E(31, 30), E(32, 38), E(23, 33), E(23, 3), E( 9, 29), E(25, 40), + E( 9, 31), E(29, 53), E(20, 30), E(30, 17), E(30, 20), E(42, 37), + E(18, 31), E(28, 42), E(25, 47), E(28, 47), E(28, 54), E(21, 38), + E(29, 9), E(43, 34), E(29, 13), E(43, 37), E(26, 21), E(44, 25), + E(44, 27), E(21, 43), E(38, 42), E(35, 30), E(21, 45), E(24, 40), + E(45, 25), E(45, 27), E(35, 46), E(39, 22), E(22, 25), E(35, 53), + E(36, 20), E(34, 2), E(34, 14), E(45, 39), E(34, 15), E(29, 22), + E(31, 44), E(46, 34), E(25, 21), E(46, 38), E(16, 33), E(17, 27), + E(31, 48), E(20, 34), E(32, 52), E(47, 35), E(47, 47), E(47, 49), + E(32, 54), E(49, 2), E(49, 13), E(49, 23), E(31, 52), E( 1, 29), + E(27, 45), E(28, 22), E(39, 49), E(39, 54), E(21, 21), E(36, 40), + E(23, 42), E(51, 31), E( 2, 30), E(40, 29), E(51, 34), E(32, 0), + E(53, 25), E(24, 23), E(30, 51), E(24, 24), E(30, 59), E(21, 28), + E(40, 38), E(57, 29), E(57, 31), E(31, 2), E(41, 13), E(58, 31), + E(32, 8), E(12, 31), E( 4, 33), E(32, 12), E(34, 45), E(59, 41), + E(31, 7), E(32, 14), E(13, 30), E( 9, 25), E(35, 18), E(26, 43), + E(35, 20), E(37, 43), E(61, 35), E(37, 44), E(63, 1), E(26, 49), + E(29, 42), E(41, 42), E(45, 34), E(33, 51), E(34, 42), E(47, 31), + E(41, 36), E(22, 36), E(42, 29), E(35, 21), E(35, 22), E(23, 37), + E(32, 44), E(35, 43), E(43, 25), E(32, 47), E( 7, 33), E(31, 45), + E(41, 27), E(20, 31), E(31, 58), E(16, 31), E(13, 32), E(63, 31), + E(25, 38), E(30, 43), E(33, 61), E(31, 43), E(41, 29), E(34, 23), + E(39, 28), E(47, 32), E(40, 28), E(58, 32), E(59, 31), E(41, 34), + E(33, 5), E( 3, 33), E(17, 32), E(61, 33), E(42, 33), E(21, 31), + E(26, 35), E(35, 26), E(29, 36), E(26, 31), E(33, 38), E(30, 30), + E(31, 32), E(33, 31), E(37, 30), E(31, 23), E(30, 42), E(26, 37), + E(33, 26), E(27, 35), E(31, 36), E(27, 34), E(35, 37), E(29, 23), + E(36, 38), E(61, 31), E(33, 40), E(37, 26), E(62, 32), E(35, 38), + E(57, 32), E(31, 41), E(34, 26), E(34, 25), E(40, 32), E(35, 35), + E(29, 34), E(32, 25), E(29, 30), E(28, 26), E(38, 18), E(23, 41), + E(32, 20), E(29, 28), E(29, 25), E(28, 37), E(42, 32), E(33, 39), + E(32, 26), E(31, 25), E(30, 40), E(35, 47), E(30, 45), E(30, 54), + E(31, 1), E(32, 23), E(33, 25), E(42, 26), E(47, 34), E(39, 38), + E(38, 14), E(40, 22), E(40, 24), E(51, 33), E(55, 34), E(56, 32), + E(18, 32), E(21, 37), E(39, 21), E(39, 23), E(33, 49), E(17, 35), + E(41, 23), E(23, 28), E(24, 39), E(43, 39), E(25, 23), E(31, 55), + E(20, 33), E(25, 37), E(38, 38), E(25, 36), E(27, 37), E(29, 37), + E( 4, 32), E(39, 33), E( 5, 32), E(28, 29), E(38, 24), E(17, 29), + E(35, 39), E( 2, 32), E(38, 36), E(30, 29), E(29, 35), E(32, 34), + E(32, 33), E(32, 32), }; -static const uint8_t table0_mv_bits[1100] = { - 1, 4, 4, 4, 5, 5, 5, 6, - 6, 6, 7, 7, 7, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 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, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 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, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 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, 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, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 8, -}; - -static const uint8_t table0_mvx[1099] = { - 32, 32, 31, 32, 33, 31, 33, 31, - 33, 32, 34, 32, 30, 32, 31, 34, - 35, 32, 34, 33, 29, 33, 30, 30, - 31, 31, 35, 29, 33, 35, 33, 34, - 31, 29, 30, 34, 30, 36, 28, 32, - 34, 37, 30, 27, 32, 25, 39, 32, - 34, 32, 35, 35, 35, 31, 35, 29, - 32, 29, 30, 29, 37, 27, 36, 38, - 37, 33, 32, 31, 29, 31, 28, 36, - 33, 30, 34, 33, 33, 28, 27, 25, - 31, 26, 39, 32, 32, 31, 33, 39, - 31, 38, 28, 36, 21, 23, 43, 36, - 34, 41, 30, 25, 28, 31, 30, 34, - 38, 35, 61, 34, 28, 30, 37, 37, - 35, 27, 36, 3, 59, 38, 37, 32, - 31, 29, 26, 33, 37, 33, 27, 27, - 35, 34, 34, 40, 42, 33, 32, 29, - 4, 5, 28, 24, 25, 35, 39, 38, - 32, 23, 27, 32, 30, 35, 26, 34, - 60, 36, 29, 22, 26, 41, 7, 30, - 38, 30, 36, 29, 30, 41, 26, 25, - 32, 34, 24, 39, 1, 25, 39, 32, - 28, 29, 32, 38, 26, 36, 28, 63, - 28, 39, 23, 21, 26, 35, 31, 35, - 57, 31, 29, 29, 28, 30, 27, 35, - 2, 38, 40, 34, 37, 29, 38, 43, - 26, 32, 33, 42, 24, 40, 28, 32, - 32, 32, 36, 32, 43, 25, 21, 31, - 30, 31, 41, 29, 33, 37, 26, 37, - 27, 59, 23, 33, 35, 31, 31, 37, - 38, 39, 32, 23, 32, 27, 37, 36, - 31, 40, 25, 27, 38, 31, 36, 28, - 31, 36, 25, 45, 3, 34, 38, 39, - 40, 38, 30, 32, 19, 24, 25, 26, - 45, 20, 24, 33, 33, 31, 41, 34, - 39, 47, 40, 58, 59, 41, 33, 3, - 17, 61, 42, 30, 26, 29, 36, 61, - 33, 37, 62, 28, 25, 38, 25, 38, - 17, 23, 34, 33, 21, 33, 49, 27, - 32, 23, 27, 22, 24, 22, 39, 43, - 27, 37, 6, 42, 47, 26, 30, 31, - 41, 39, 33, 22, 45, 36, 32, 45, - 19, 22, 30, 5, 5, 17, 29, 22, - 31, 31, 43, 37, 27, 32, 32, 32, - 33, 34, 43, 35, 29, 26, 22, 32, - 19, 32, 25, 31, 41, 49, 28, 34, - 28, 39, 34, 19, 37, 38, 29, 21, - 36, 42, 24, 48, 16, 28, 49, 22, - 34, 31, 38, 39, 44, 11, 35, 30, - 33, 33, 23, 28, 33, 46, 15, 13, - 24, 41, 24, 34, 34, 30, 26, 24, - 14, 60, 21, 29, 39, 23, 35, 37, - 63, 45, 33, 34, 47, 41, 22, 42, - 35, 35, 23, 32, 35, 43, 32, 7, - 31, 41, 20, 31, 16, 13, 63, 25, - 30, 32, 35, 30, 30, 31, 42, 47, - 39, 38, 40, 40, 51, 55, 56, 18, - 21, 39, 39, 33, 17, 41, 23, 24, - 43, 25, 31, 20, 19, 45, 1, 34, - 31, 22, 35, 15, 46, 46, 35, 31, - 28, 29, 29, 23, 41, 27, 14, 53, - 53, 27, 24, 32, 57, 32, 17, 42, - 37, 29, 33, 1, 25, 32, 32, 63, - 26, 40, 44, 36, 31, 39, 20, 20, - 44, 23, 33, 34, 35, 33, 33, 28, - 41, 23, 41, 41, 29, 25, 26, 49, - 29, 24, 37, 49, 50, 51, 51, 26, - 39, 25, 26, 15, 39, 18, 42, 17, - 4, 31, 32, 32, 60, 1, 42, 32, - 0, 12, 19, 35, 21, 41, 17, 26, - 20, 45, 46, 32, 37, 22, 47, 29, - 31, 27, 29, 30, 21, 33, 35, 18, - 25, 33, 50, 51, 42, 2, 15, 51, - 53, 33, 25, 29, 55, 37, 38, 33, - 38, 59, 38, 33, 39, 13, 32, 40, - 61, 61, 32, 9, 44, 3, 31, 29, - 25, 31, 27, 23, 9, 25, 9, 29, - 20, 30, 30, 42, 18, 28, 25, 28, - 28, 21, 29, 43, 29, 43, 26, 44, - 44, 21, 38, 21, 24, 45, 45, 35, - 39, 22, 35, 36, 34, 34, 45, 34, - 29, 31, 46, 25, 46, 16, 17, 31, - 20, 32, 47, 47, 47, 32, 49, 49, - 49, 31, 1, 27, 28, 39, 39, 21, - 36, 23, 51, 2, 40, 51, 32, 53, - 24, 30, 24, 30, 21, 40, 57, 57, - 31, 41, 58, 32, 12, 4, 32, 34, - 59, 31, 32, 13, 9, 35, 26, 35, - 37, 61, 37, 63, 26, 29, 41, 38, - 23, 20, 41, 26, 41, 42, 42, 42, - 26, 26, 26, 26, 1, 26, 37, 37, - 37, 23, 34, 42, 27, 43, 34, 27, - 31, 24, 33, 16, 3, 31, 24, 33, - 24, 4, 44, 44, 11, 44, 31, 13, - 13, 44, 45, 13, 25, 22, 38, 26, - 38, 38, 39, 32, 30, 39, 30, 22, - 32, 26, 30, 47, 47, 47, 19, 47, - 30, 31, 35, 8, 23, 47, 47, 27, - 35, 47, 31, 48, 35, 19, 36, 49, - 49, 33, 31, 39, 27, 39, 49, 49, - 50, 50, 50, 39, 31, 51, 51, 39, - 28, 33, 33, 21, 40, 31, 52, 53, - 40, 53, 9, 33, 31, 53, 54, 54, - 54, 55, 55, 34, 15, 56, 25, 56, - 21, 21, 40, 40, 25, 40, 58, 36, - 5, 41, 41, 12, 60, 41, 41, 37, - 22, 61, 18, 29, 29, 30, 61, 30, - 61, 62, 62, 30, 30, 63, 18, 13, - 30, 23, 19, 20, 20, 41, 13, 2, - 5, 5, 1, 5, 32, 6, 32, 35, - 20, 35, 27, 35, 35, 36, 36, 13, - 36, 41, 41, 41, 3, 30, 42, 27, - 20, 30, 27, 28, 30, 21, 33, 33, - 14, 24, 30, 42, 24, 33, 25, 42, - 43, 14, 43, 43, 14, 43, 7, 36, - 37, 37, 37, 37, 7, 14, 25, 43, - 43, 44, 15, 37, 7, 7, 3, 1, - 8, 15, 15, 8, 44, 44, 44, 45, - 45, 45, 45, 8, 8, 45, 21, 45, - 28, 28, 28, 21, 28, 28, 22, 37, - 46, 46, 37, 8, 29, 37, 29, 22, - 46, 37, 22, 29, 47, 47, 38, 38, - 16, 38, 38, 33, 38, 22, 47, 47, - 29, 25, 16, 0, 48, 1, 34, 48, - 48, 34, 25, 26, 26, 49, 49, 26, - 1, 49, 4, 26, 4, 49, 1, 9, - 49, 49, 49, 10, 49, 17, 38, 17, - 17, 50, 38, 50, 50, 22, 38, 51, - 38, 38, 51, 39, 39, 18, 22, 39, - 51, 22, 52, 52, 52, 39, 53, 53, - 10, 23, 18, 29, 10, 53, 29, 54, - 11, 54, 11, 11, 55, 1, 18, 55, - 55, 55, 55, 55, 55, 29, 34, 18, - 29, 56, 56, 34, 57, 34, 34, 29, - 29, 57, 57, 35, 35, 35, 35, 35, - 39, 35, 59, 59, 18, 59, 39, 30, - 18, 40, 60, 60, 61, 30, 18, 61, - 61, 19, 19, -}; - -static const uint8_t table0_mvy[1099] = { - 32, 31, 32, 33, 32, 31, 31, 33, - 33, 34, 32, 30, 32, 35, 34, 31, - 32, 29, 33, 30, 32, 34, 33, 31, - 30, 35, 31, 31, 29, 33, 35, 30, - 29, 33, 34, 34, 30, 32, 32, 36, - 29, 32, 35, 32, 28, 32, 32, 27, - 35, 37, 34, 29, 30, 36, 35, 34, - 25, 30, 29, 35, 33, 31, 31, 32, - 31, 28, 39, 28, 29, 37, 31, 33, - 27, 36, 28, 36, 37, 33, 33, 31, - 27, 32, 31, 38, 26, 25, 25, 33, - 39, 31, 34, 30, 32, 32, 32, 34, - 36, 32, 28, 33, 30, 38, 37, 27, - 33, 28, 32, 37, 35, 38, 29, 34, - 27, 29, 29, 32, 32, 34, 35, 3, - 26, 36, 31, 38, 30, 26, 35, 34, - 37, 26, 25, 32, 32, 39, 23, 37, - 32, 32, 29, 32, 29, 36, 29, 30, - 41, 31, 30, 21, 39, 25, 34, 38, - 32, 35, 39, 32, 33, 33, 32, 27, - 29, 25, 28, 27, 26, 31, 30, 35, - 24, 24, 31, 34, 32, 30, 35, 40, - 28, 38, 5, 35, 29, 36, 36, 32, - 38, 30, 33, 31, 35, 26, 23, 38, - 32, 41, 28, 25, 37, 40, 37, 39, - 32, 36, 33, 39, 25, 26, 28, 31, - 28, 42, 23, 31, 33, 31, 39, 1, - 59, 22, 27, 4, 33, 34, 33, 24, - 41, 3, 35, 41, 41, 28, 36, 36, - 28, 33, 35, 21, 23, 21, 22, 37, - 27, 27, 43, 29, 60, 39, 27, 25, - 59, 34, 27, 27, 26, 40, 37, 27, - 61, 26, 39, 33, 31, 22, 37, 25, - 30, 25, 24, 61, 31, 34, 25, 38, - 32, 32, 30, 3, 61, 43, 29, 23, - 28, 32, 28, 32, 31, 34, 5, 33, - 32, 33, 33, 42, 37, 23, 38, 31, - 40, 26, 32, 26, 37, 38, 36, 24, - 29, 30, 20, 22, 29, 24, 32, 41, - 2, 34, 25, 33, 29, 31, 39, 35, - 36, 24, 32, 30, 33, 27, 44, 60, - 30, 36, 19, 34, 31, 24, 16, 35, - 32, 38, 21, 33, 31, 31, 21, 35, - 5, 17, 29, 38, 38, 18, 58, 19, - 43, 41, 30, 41, 43, 39, 29, 7, - 29, 17, 28, 19, 28, 31, 25, 19, - 40, 26, 21, 33, 39, 23, 40, 30, - 39, 34, 35, 32, 32, 24, 33, 30, - 40, 47, 39, 37, 32, 33, 24, 23, - 45, 47, 27, 23, 42, 32, 32, 33, - 36, 37, 37, 17, 18, 22, 40, 38, - 32, 31, 35, 24, 17, 25, 17, 23, - 33, 34, 51, 42, 31, 36, 36, 29, - 21, 22, 37, 44, 43, 25, 47, 33, - 45, 27, 31, 58, 31, 32, 31, 38, - 43, 20, 47, 45, 54, 1, 26, 34, - 38, 14, 22, 24, 33, 34, 32, 32, - 37, 21, 23, 49, 35, 23, 28, 39, - 39, 23, 55, 33, 30, 30, 63, 16, - 42, 28, 13, 33, 33, 35, 19, 46, - 43, 17, 19, 36, 39, 24, 31, 32, - 33, 26, 28, 62, 33, 63, 33, 39, - 19, 49, 17, 31, 43, 13, 15, 29, - 25, 35, 33, 23, 49, 41, 28, 29, - 34, 38, 7, 61, 11, 50, 13, 41, - 19, 47, 25, 26, 15, 42, 41, 29, - 45, 27, 17, 35, 32, 29, 32, 24, - 13, 26, 26, 31, 24, 33, 28, 30, - 31, 11, 45, 46, 33, 33, 35, 57, - 32, 32, 35, 45, 34, 11, 37, 42, - 39, 37, 31, 49, 21, 27, 29, 47, - 53, 40, 51, 16, 26, 1, 40, 30, - 41, 44, 34, 25, 27, 31, 35, 35, - 31, 15, 49, 1, 35, 40, 5, 58, - 21, 29, 22, 59, 45, 31, 9, 26, - 9, 29, 11, 32, 30, 3, 13, 20, - 18, 20, 11, 3, 29, 40, 31, 53, - 30, 17, 20, 37, 31, 42, 47, 47, - 54, 38, 9, 34, 13, 37, 21, 25, - 27, 43, 42, 45, 40, 25, 27, 46, - 22, 25, 53, 20, 2, 14, 39, 15, - 22, 44, 34, 21, 38, 33, 27, 48, - 34, 52, 35, 47, 49, 54, 2, 13, - 23, 52, 29, 45, 22, 49, 54, 21, - 40, 42, 31, 30, 29, 34, 0, 25, - 23, 51, 24, 59, 28, 38, 29, 31, - 2, 13, 31, 8, 31, 33, 12, 45, - 41, 7, 14, 30, 25, 18, 43, 20, - 43, 35, 44, 1, 49, 42, 42, 18, - 41, 38, 41, 44, 53, 11, 20, 25, - 45, 46, 47, 48, 39, 52, 46, 49, - 63, 55, 44, 38, 13, 13, 57, 22, - 51, 16, 12, 28, 35, 57, 25, 20, - 26, 28, 28, 29, 32, 31, 62, 34, - 35, 35, 19, 49, 48, 39, 40, 18, - 43, 46, 11, 6, 48, 19, 49, 41, - 10, 23, 58, 17, 21, 23, 34, 30, - 60, 0, 44, 34, 26, 37, 46, 43, - 49, 59, 4, 34, 59, 37, 22, 25, - 28, 46, 6, 40, 59, 42, 36, 61, - 28, 30, 31, 43, 10, 22, 23, 47, - 20, 52, 55, 36, 25, 16, 1, 11, - 27, 29, 5, 63, 18, 41, 31, 34, - 38, 1, 5, 13, 28, 31, 17, 38, - 39, 41, 36, 37, 22, 39, 33, 43, - 43, 15, 17, 49, 30, 21, 22, 20, - 10, 17, 25, 54, 57, 3, 34, 8, - 36, 25, 31, 14, 15, 19, 29, 25, - 18, 39, 53, 22, 27, 20, 29, 33, - 41, 42, 35, 62, 50, 29, 53, 50, - 35, 55, 42, 61, 63, 4, 7, 42, - 21, 46, 47, 49, 27, 46, 17, 55, - 41, 50, 63, 4, 56, 18, 8, 10, - 18, 51, 63, 36, 55, 18, 5, 55, - 9, 29, 17, 21, 30, 27, 1, 59, - 7, 11, 12, 15, 5, 42, 24, 41, - 43, 7, 27, 22, 25, 31, 30, 37, - 22, 39, 53, 29, 36, 37, 48, 0, - 5, 13, 17, 31, 32, 26, 46, 28, - 44, 45, 46, 53, 49, 51, 3, 41, - 3, 22, 42, 33, 5, 45, 7, 22, - 40, 53, 24, 14, 25, 27, 10, 12, - 34, 16, 17, 53, 20, 26, 39, 45, - 18, 45, 35, 33, 31, 49, 4, 39, - 42, 11, 51, 5, 13, 26, 27, 17, - 52, 30, 0, 22, 12, 34, 62, 36, - 38, 41, 47, 30, 63, 38, 41, 43, - 59, 33, 45, 37, 38, 40, 47, 24, - 48, 49, 30, 1, 10, 22, 49, 15, - 39, 59, 31, 32, 33, 18, 13, 15, - 31, 21, 27, 44, 42, 39, 46, 17, - 26, 32, 30, 31, 0, 30, 34, 9, - 12, 13, 25, 31, 32, 55, 43, 35, - 61, 33, 35, 46, 25, 47, 48, 62, - 63, 38, 61, 1, 2, 5, 7, 9, - 46, 10, 34, 35, 36, 55, 51, 7, - 40, 23, 34, 37, 5, 13, 42, 18, - 25, 27, 28, +const uint8_t ff_msmp4_mv_table0_lens[MSMPEG4_MV_TABLES_NB_ELEMS] = { + 8, 12, 12, 13, 15, 15, 15, 15, 12, 15, 15, 15, 15, 14, 14, 14, 14, 14, + 14, 11, 9, 8, 13, 14, 14, 14, 14, 13, 11, 12, 12, 12, 12, 10, 13, 13, + 12, 12, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 6, 6, 7, + 8, 8, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 13, 12, 11, 10, + 9, 9, 11, 13, 13, 14, 14, 13, 13, 13, 13, 13, 12, 16, 16, 15, 15, 15, + 15, 15, 15, 15, 9, 10, 15, 15, 15, 15, 15, 15, 14, 14, 14, 13, 11, 9, + 8, 10, 11, 12, 14, 14, 13, 10, 13, 14, 14, 14, 14, 13, 11, 7, 5, 8, + 9, 11, 12, 13, 16, 16, 16, 16, 16, 16, 16, 16, 11, 12, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 10, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 14, 11, 12, 13, 13, 11, 12, 13, 14, 14, 9, 9, 8, 10, 13, 13, 13, + 14, 16, 17, 17, 15, 11, 10, 10, 8, 9, 11, 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, + 14, 14, 12, 12, 8, 7, 11, 14, 14, 14, 14, 13, 13, 10, 10, 13, 14, 14, + 14, 14, 14, 14, 14, 14, 13, 12, 8, 9, 11, 11, 14, 17, 17, 17, 17, 17, + 17, 17, 17, 13, 13, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 11, 11, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 4, 5, 10, 10, 9, 13, 13, 12, 11, 12, 14, 14, 14, 14, 11, 10, + 14, 14, 14, 14, 14, 14, 13, 13, 13, 12, 12, 13, 13, 13, 13, 12, 11, 12, + 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 13, 12, 12, 13, 13, 8, + 12, 13, 13, 11, 12, 15, 16, 16, 14, 14, 14, 12, 13, 13, 12, 12, 11, 10, + 8, 11, 13, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 10, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, + 13, 13, 12, 12, 12, 9, 4, 5, 12, 13, 14, 14, 12, 12, 10, 12, 12, 14, + 14, 14, 14, 14, 14, 13, 13, 13, 12, 12, 12, 10, 10, 10, 10, 14, 16, 16, + 15, 13, 13, 13, 12, 12, 11, 11, 13, 15, 15, 15, 15, 12, 11, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 14, 14, 14, 13, 12, 12, 11, 12, 12, 14, 14, 13, 13, 13, 10, 10, 6, + 4, 1, }; /* motion vector table 1 */ -static const uint16_t table1_mv_code[1100] = { - 0x0000, 0x0007, 0x0009, 0x000f, 0x000a, 0x0011, 0x001a, 0x001c, - 0x0011, 0x0031, 0x0025, 0x002d, 0x002f, 0x006f, 0x0075, 0x0041, - 0x004c, 0x004e, 0x005c, 0x0060, 0x0062, 0x0066, 0x0068, 0x0069, - 0x006b, 0x00a6, 0x00c1, 0x00cb, 0x00cc, 0x00ce, 0x00da, 0x00e8, - 0x00ee, 0x0087, 0x0090, 0x009e, 0x009f, 0x00ba, 0x00ca, 0x00d8, - 0x00db, 0x00df, 0x0104, 0x0109, 0x010c, 0x0143, 0x0145, 0x014a, - 0x0156, 0x015c, 0x01b3, 0x01d3, 0x01da, 0x0103, 0x0109, 0x010b, - 0x0122, 0x0127, 0x0134, 0x0161, 0x0164, 0x0176, 0x0184, 0x018d, - 0x018e, 0x018f, 0x0190, 0x0193, 0x0196, 0x019d, 0x019e, 0x019f, - 0x01a9, 0x01b2, 0x01b4, 0x01ba, 0x01bb, 0x01bc, 0x0201, 0x0202, - 0x0205, 0x0207, 0x020d, 0x0210, 0x0211, 0x0215, 0x021b, 0x021f, - 0x0281, 0x0285, 0x0290, 0x029c, 0x029d, 0x02a2, 0x02a7, 0x02a8, - 0x02aa, 0x02b0, 0x02b1, 0x02b4, 0x02bc, 0x02bf, 0x0320, 0x0326, - 0x0327, 0x0329, 0x032a, 0x0336, 0x0360, 0x0362, 0x0363, 0x0372, - 0x03b2, 0x03bc, 0x03bd, 0x0203, 0x0205, 0x021a, 0x0249, 0x024a, - 0x024c, 0x02c7, 0x02ca, 0x02ce, 0x02ef, 0x030d, 0x0322, 0x0325, - 0x0338, 0x0373, 0x037a, 0x0409, 0x0415, 0x0416, 0x0418, 0x0428, - 0x042d, 0x042f, 0x0434, 0x0508, 0x0509, 0x0510, 0x0511, 0x051c, - 0x051e, 0x0524, 0x0541, 0x0543, 0x0546, 0x0547, 0x054d, 0x0557, - 0x055f, 0x056a, 0x056c, 0x056d, 0x056f, 0x0576, 0x0577, 0x057a, - 0x057b, 0x057c, 0x057d, 0x0600, 0x0601, 0x0603, 0x0614, 0x0616, - 0x0617, 0x061c, 0x061f, 0x0642, 0x0648, 0x0649, 0x064a, 0x064b, - 0x0657, 0x0668, 0x0669, 0x066b, 0x066e, 0x067f, 0x06c2, 0x06c8, - 0x06cb, 0x06de, 0x06df, 0x06e2, 0x06e3, 0x06ef, 0x0748, 0x074b, - 0x076e, 0x076f, 0x077c, 0x0409, 0x0423, 0x0428, 0x0429, 0x042a, - 0x042b, 0x0432, 0x0433, 0x0496, 0x049a, 0x04d5, 0x04db, 0x0581, - 0x0582, 0x058b, 0x058c, 0x058d, 0x0598, 0x0599, 0x059a, 0x059e, - 0x05dd, 0x0619, 0x0632, 0x0633, 0x0648, 0x0672, 0x06a1, 0x06a2, - 0x06a3, 0x06af, 0x06e2, 0x06e3, 0x06e4, 0x0800, 0x0801, 0x0802, - 0x0803, 0x081a, 0x081b, 0x0829, 0x082f, 0x0832, 0x083e, 0x083f, - 0x0852, 0x0853, 0x0858, 0x086b, 0x0877, 0x0878, 0x0879, 0x087a, - 0x087b, 0x0a00, 0x0a01, 0x0a0d, 0x0a0e, 0x0a0f, 0x0a24, 0x0a37, - 0x0a3a, 0x0a3b, 0x0a3e, 0x0a46, 0x0a47, 0x0a4a, 0x0a4b, 0x0a5f, - 0x0a79, 0x0a7a, 0x0a7b, 0x0a80, 0x0a81, 0x0a84, 0x0a85, 0x0a99, - 0x0aa5, 0x0aa6, 0x0ab8, 0x0aba, 0x0abb, 0x0abc, 0x0abd, 0x0ac8, - 0x0ace, 0x0acf, 0x0ad7, 0x0adc, 0x0aeb, 0x0c04, 0x0c25, 0x0c26, - 0x0c27, 0x0c2a, 0x0c2b, 0x0c3a, 0x0c3b, 0x0c3c, 0x0c3d, 0x0ca0, - 0x0cad, 0x0cd4, 0x0cd5, 0x0cfc, 0x0cfd, 0x0d86, 0x0d92, 0x0d93, - 0x0d94, 0x0d95, 0x0db0, 0x0db8, 0x0db9, 0x0dba, 0x0dbb, 0x0dc0, - 0x0dc2, 0x0dc3, 0x0dda, 0x0ddb, 0x0ddc, 0x0ddd, 0x0e92, 0x0e93, - 0x0e94, 0x0e95, 0x0ec7, 0x0ecc, 0x0ece, 0x0ecf, 0x0ed8, 0x0ed9, - 0x0eda, 0x0edb, 0x0808, 0x0809, 0x080a, 0x0810, 0x0811, 0x0844, - 0x0845, 0x0861, 0x0862, 0x0863, 0x086c, 0x0922, 0x0923, 0x092e, - 0x092f, 0x0936, 0x0937, 0x09b1, 0x09b2, 0x09b3, 0x09b4, 0x09b5, - 0x09b8, 0x09b9, 0x09ba, 0x09bb, 0x09bc, 0x09bd, 0x09be, 0x09bf, - 0x0b00, 0x0b15, 0x0b2c, 0x0b2d, 0x0b2e, 0x0b2f, 0x0b36, 0x0bb9, - 0x0c28, 0x0c2a, 0x0c2b, 0x0c2c, 0x0c2d, 0x0c2e, 0x0c2f, 0x0c30, - 0x0c31, 0x0c38, 0x0c60, 0x0c61, 0x0c62, 0x0c63, 0x0c8d, 0x0c8e, - 0x0c8f, 0x0c92, 0x0cbe, 0x0cbf, 0x0ce6, 0x0ce7, 0x0d40, 0x0d41, - 0x0d57, 0x0d58, 0x0d59, 0x0d5a, 0x0d5b, 0x0d5c, 0x0d5d, 0x0d98, - 0x0d99, 0x0d9a, 0x0d9b, 0x0d9c, 0x0d9d, 0x0dad, 0x0dae, 0x0daf, - 0x0dc0, 0x0dc1, 0x0dc2, 0x0dc3, 0x0dca, 0x0dcb, 0x0dec, 0x0ded, - 0x0dee, 0x0def, 0x1018, 0x1022, 0x1023, 0x1030, 0x1031, 0x1032, - 0x1033, 0x1050, 0x1051, 0x105c, 0x1074, 0x1075, 0x1076, 0x1077, - 0x1078, 0x1079, 0x107a, 0x107b, 0x10b2, 0x10b3, 0x10b8, 0x10b9, - 0x10ba, 0x10bb, 0x10d4, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x1404, - 0x1405, 0x1406, 0x1407, 0x1410, 0x1411, 0x1412, 0x1413, 0x1414, - 0x1415, 0x1416, 0x1417, 0x1418, 0x1419, 0x1466, 0x1467, 0x1468, - 0x1469, 0x146a, 0x146b, 0x146c, 0x146d, 0x147e, 0x147f, 0x1488, - 0x1489, 0x148a, 0x148b, 0x14b6, 0x14b7, 0x14b8, 0x14b9, 0x14ba, - 0x14bb, 0x14bc, 0x14bd, 0x14f0, 0x14f1, 0x14f8, 0x14f9, 0x14fa, - 0x14fb, 0x14fc, 0x14fd, 0x14fe, 0x14ff, 0x152a, 0x152b, 0x152c, - 0x152d, 0x152e, 0x152f, 0x1530, 0x1531, 0x1548, 0x1549, 0x154e, - 0x154f, 0x1558, 0x1559, 0x155a, 0x155b, 0x1572, 0x159a, 0x159b, - 0x15ac, 0x15ba, 0x15bb, 0x15d0, 0x15d1, 0x15d2, 0x15d3, 0x15d4, - 0x15d5, 0x181d, 0x181e, 0x181f, 0x1840, 0x1841, 0x1842, 0x1843, - 0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x1861, 0x1862, - 0x1863, 0x1864, 0x1865, 0x1866, 0x1867, 0x1868, 0x1869, 0x186a, - 0x186b, 0x186c, 0x186d, 0x186e, 0x191b, 0x191c, 0x191d, 0x191e, - 0x191f, 0x1942, 0x1943, 0x1944, 0x1945, 0x1946, 0x1947, 0x1958, - 0x1959, 0x19ed, 0x19ee, 0x19ef, 0x19f0, 0x19f1, 0x19f2, 0x19f3, - 0x19f4, 0x19f5, 0x19f6, 0x19f7, 0x1b0e, 0x1b0f, 0x1b62, 0x1b63, - 0x1b64, 0x1b65, 0x1b66, 0x1b67, 0x1b68, 0x1b69, 0x1b6a, 0x1b6b, - 0x1b6c, 0x1b6d, 0x1b6e, 0x1b6f, 0x1b82, 0x1ba8, 0x1ba9, 0x1baa, - 0x1bab, 0x1bac, 0x1bad, 0x1bae, 0x1baf, 0x1bb0, 0x1bb1, 0x1bb2, - 0x1bb3, 0x1d80, 0x1d81, 0x1d82, 0x1d83, 0x1d84, 0x1d85, 0x1d86, - 0x1d87, 0x1d88, 0x1d89, 0x1d8a, 0x1d8b, 0x1d8c, 0x1d8d, 0x1007, - 0x1008, 0x1009, 0x100a, 0x100b, 0x100c, 0x100d, 0x100e, 0x100f, - 0x1016, 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, - 0x1087, 0x10c0, 0x123a, 0x123b, 0x123c, 0x123d, 0x123e, 0x123f, - 0x1240, 0x1241, 0x1242, 0x1243, 0x1350, 0x1352, 0x1353, 0x1358, - 0x1359, 0x135a, 0x135b, 0x135c, 0x135d, 0x135e, 0x135f, 0x1360, - 0x1361, 0x1602, 0x1603, 0x160c, 0x160d, 0x160e, 0x160f, 0x1620, - 0x1621, 0x1622, 0x1623, 0x1624, 0x1625, 0x1626, 0x1627, 0x1628, - 0x1629, 0x166e, 0x166f, 0x167c, 0x167d, 0x167e, 0x167f, 0x1770, - 0x1771, 0x1852, 0x1853, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, - 0x1877, 0x1878, 0x1879, 0x187a, 0x187b, 0x187c, 0x187d, 0x187e, - 0x187f, 0x1918, 0x1919, 0x1926, 0x1927, 0x1970, 0x1971, 0x1972, - 0x1973, 0x1974, 0x1975, 0x1976, 0x1977, 0x1978, 0x1979, 0x197a, - 0x197b, 0x1aa0, 0x1aa1, 0x1aa2, 0x1aa3, 0x1aa4, 0x1aa5, 0x1aa6, - 0x1aa7, 0x1aa8, 0x1aa9, 0x1aaa, 0x1aab, 0x1aac, 0x1aad, 0x1b3c, - 0x1b3d, 0x1b3e, 0x1b3f, 0x1b50, 0x1b51, 0x1b52, 0x1b53, 0x1b54, - 0x1b55, 0x1b56, 0x1b57, 0x1b58, 0x1b59, 0x2032, 0x2033, 0x2034, - 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203a, 0x203b, 0x203c, - 0x203d, 0x203e, 0x203f, 0x2040, 0x2041, 0x2042, 0x2043, 0x20ba, - 0x20bb, 0x20cc, 0x20cd, 0x20ce, 0x20cf, 0x20e0, 0x20e1, 0x20e2, - 0x20e3, 0x20e4, 0x20e5, 0x20e6, 0x20e7, 0x21aa, 0x21ab, 0x21c0, - 0x21c1, 0x21c2, 0x21c3, 0x21c4, 0x21c5, 0x21c6, 0x21c7, 0x21c8, - 0x21c9, 0x21ca, 0x21cb, 0x21cc, 0x21cd, 0x21ce, 0x21cf, 0x21d0, - 0x21d1, 0x21d2, 0x21d3, 0x2894, 0x2895, 0x2896, 0x2897, 0x2898, - 0x2899, 0x289a, 0x289b, 0x289c, 0x289d, 0x289e, 0x289f, 0x28c0, - 0x28c1, 0x28c2, 0x28c3, 0x28c4, 0x28c5, 0x28c6, 0x28c7, 0x28c8, - 0x28c9, 0x28ca, 0x28cb, 0x2930, 0x2931, 0x2932, 0x2933, 0x2934, - 0x2935, 0x2936, 0x2937, 0x2938, 0x2939, 0x293a, 0x293b, 0x293c, - 0x293d, 0x293e, 0x293f, 0x2960, 0x2961, 0x2962, 0x2963, 0x2964, - 0x2965, 0x2966, 0x2967, 0x2968, 0x2969, 0x296a, 0x296b, 0x2a40, - 0x2a41, 0x2a42, 0x2a43, 0x2a44, 0x2a45, 0x2a46, 0x2a47, 0x2a48, - 0x2a49, 0x2a4a, 0x2a4b, 0x2a4c, 0x2a4d, 0x2a4e, 0x2a4f, 0x2a50, - 0x2a51, 0x2a52, 0x2a53, 0x2ae6, 0x2ae7, 0x2b24, 0x2b25, 0x2b26, - 0x2b27, 0x2b28, 0x2b29, 0x2b2a, 0x2b2b, 0x2b2c, 0x2b2d, 0x2b2e, - 0x2b2f, 0x2b30, 0x2b31, 0x2b32, 0x2b33, 0x2b5a, 0x2b5b, 0x3014, - 0x3015, 0x3016, 0x3017, 0x3020, 0x3021, 0x3022, 0x3023, 0x3024, - 0x3025, 0x3026, 0x3027, 0x3028, 0x3029, 0x302a, 0x302b, 0x302c, - 0x302d, 0x302e, 0x302f, 0x3030, 0x3031, 0x3032, 0x3033, 0x3034, - 0x3035, 0x3036, 0x3037, 0x3038, 0x3039, 0x30c0, 0x30c1, 0x30de, - 0x30df, 0x3218, 0x3219, 0x321a, 0x321b, 0x321c, 0x321d, 0x321e, - 0x321f, 0x3220, 0x3221, 0x3222, 0x3223, 0x3224, 0x3225, 0x3226, - 0x3227, 0x3228, 0x3229, 0x322a, 0x322b, 0x322c, 0x322d, 0x322e, - 0x322f, 0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3378, - 0x3379, 0x337a, 0x337b, 0x337c, 0x337d, 0x337e, 0x337f, 0x33c0, - 0x33c1, 0x33c2, 0x33c3, 0x33c4, 0x33c5, 0x33c6, 0x33c7, 0x33c8, - 0x33c9, 0x33ca, 0x33cb, 0x33cc, 0x33cd, 0x33ce, 0x33cf, 0x33d0, - 0x33d1, 0x33d2, 0x33d3, 0x33d4, 0x33d5, 0x33d6, 0x33d7, 0x33d8, - 0x33d9, 0x3706, 0x3707, 0x3730, 0x3731, 0x3732, 0x3733, 0x3734, - 0x3735, 0x3736, 0x3737, 0x3738, 0x3739, 0x373a, 0x373b, 0x373c, - 0x373d, 0x373e, 0x373f, 0x3740, 0x3741, 0x3742, 0x3743, 0x3744, - 0x3745, 0x3746, 0x3747, 0x3748, 0x3749, 0x374a, 0x374b, 0x374c, - 0x374d, 0x374e, 0x374f, 0x3b34, 0x3b35, 0x3b36, 0x3b37, 0x3be8, - 0x3be9, 0x3bea, 0x3beb, 0x3bec, 0x3bed, 0x3bee, 0x3bef, 0x3bf0, - 0x3bf1, 0x3bf2, 0x3bf3, 0x3bf4, 0x3bf5, 0x3bf6, 0x3bf7, 0x3bf8, - 0x3bf9, 0x3bfa, 0x3bfb, 0x3bfc, 0x3bfd, 0x3bfe, 0x3bff, 0x2000, - 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, - 0x2009, 0x200a, 0x200b, 0x200c, 0x200d, 0x202e, 0x202f, 0x2182, - 0x2183, 0x21b4, 0x21b5, 0x21b6, 0x21b7, 0x21b8, 0x21b9, 0x21ba, - 0x21bb, 0x21bc, 0x21bd, 0x21be, 0x21bf, 0x2460, 0x2461, 0x2462, - 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, 0x2468, 0x2469, 0x246a, - 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, 0x2470, 0x2471, 0x2472, - 0x2473, 0x26a2, 0x26a3, 0x000b, + +const uint16_t ff_msmp4_mv_table1[MSMPEG4_MV_TABLES_NB_ELEMS] = { + E(32, 32), E(42, 39), E(35, 53), E( 3, 28), E(51, 39), E(35, 57), + E(16, 46), E(35, 10), E(30, 52), E(63, 27), E(57, 35), E(39, 42), + E(39, 45), E(25, 59), E(35, 15), E(51, 34), E(31, 9), E(48, 34), + E( 2, 33), E( 6, 31), E(34, 49), E(30, 43), E(28, 42), E(33, 51), + E(39, 27), E(33, 42), E(37, 25), E(60, 34), E(38, 60), E( 9, 38), + E(38, 33), E(51, 32), E(30, 22), E(33, 23), E(32, 24), E(32, 26), + E(32, 29), E(40, 29), E(27, 23), E(46, 29), E(31, 14), E( 9, 30), + E(35, 45), E(29, 49), E(31, 11), E(47, 32), E(32, 48), E(39, 35), + E(37, 31), E(25, 34), E(30, 25), E(24, 30), E(35, 25), E(61, 32), + E(39, 24), E(16, 24), E(36, 23), E(50, 32), E(32, 45), E(19, 33), + E(59, 33), E(29, 25), E(30, 36), E(63, 33), E(45, 39), E(31, 12), + E(60, 29), E(14, 24), E(34, 0), E(42, 20), E(24, 16), E( 0, 28), + E(37, 43), E(18, 35), E(61, 28), E(57, 1), E(30, 30), E(31, 33), + E(31, 35), E(26, 32), E(37, 49), E(28, 4), E(53, 21), E(20, 42), + E(46, 39), E(14, 29), E(47, 3), E(38, 44), E(38, 21), E(38, 53), + E( 9, 55), E(34, 11), E(39, 5), E(43, 3), E(17, 39), E(39, 53), + E(59, 28), E( 5, 25), E(27, 19), E( 0, 34), E(55, 31), E(46, 28), + E(19, 35), E(37, 41), E(62, 30), E(34, 44), E(30, 18), E(16, 29), + E(19, 34), E(49, 35), E(30, 41), E(25, 27), E(43, 32), E( 4, 32), + E(34, 25), E(27, 25), E(33, 19), E(32, 41), E(25, 29), E(62, 31), + E(24, 35), E(32, 38), E(30, 32), E(34, 33), E(34, 29), E(41, 36), + E(12, 28), E(27, 21), E(41, 25), E(39, 26), E(30, 24), E(37, 21), + E(14, 31), E( 5, 30), E(13, 34), E(35, 19), E(55, 34), E(30, 44), + E(40, 36), E(40, 38), E(42, 25), E(31, 19), E(27, 36), E(30, 42), + E(37, 27), E(31, 17), E(21, 33), E(45, 31), E(32, 44), E(39, 28), + E(20, 33), E(46, 33), E(47, 31), E(35, 23), E(19, 31), E(33, 30), + E(28, 32), E(36, 32), E(33, 32), E(34, 40), E( 8, 31), E(20, 28), + E(35, 39), E(43, 33), E(25, 23), E(45, 37), E(35, 3), E(33, 55), + E(35, 29), E(36, 41), E(54, 30), E(38, 22), E(27, 41), E(37, 24), + E(62, 33), E(40, 26), E(15, 35), E(59, 35), E(49, 30), E( 1, 33), + E(40, 33), E(32, 0), E(29, 37), E(32, 2), E( 3, 32), E(42, 32), + E(49, 31), E(21, 34), E(21, 30), E(14, 32), E( 5, 31), E(28, 36), + E(31, 21), E(51, 33), E(31, 55), E(29, 51), E(31, 38), E(62, 32), + E(34, 47), E(34, 48), E(39, 38), E(24, 24), E(32, 30), E(29, 32), + E(30, 34), E(35, 34), E(29, 15), E(25, 21), E(26, 36), E(33, 61), + E(31, 26), E(32, 34), E(30, 33), E(27, 31), E(23, 35), E(29, 50), + E(21, 25), E(31, 47), E(36, 37), E(35, 41), E(58, 31), E(29, 23), + E(29, 41), E(21, 29), E(20, 30), E(33, 24), E(32, 22), E(42, 35), + E(29, 46), E(10, 30), E(61, 29), E(33, 10), E(49, 34), E(35, 42), + E(34, 45), E( 3, 29), E(38, 42), E(39, 22), E(29, 3), E( 7, 33), + E(41, 27), E( 1, 34), E(30, 31), E(13, 32), E(28, 25), E(12, 32), + E(40, 28), E(25, 35), E(31, 61), E(28, 31), E(29, 34), E(34, 35), + E(28, 33), E(26, 33), E(35, 1), E( 4, 34), E(31, 58), E(33, 2), + E(39, 37), E(21, 31), E(60, 33), E(23, 28), E(15, 34), E(38, 30), + E(37, 33), E(34, 34), E(31, 28), E(23, 36), E(11, 35), E(37, 23), + E(28, 23), E(35, 13), E(30, 58), E(30, 3), E(24, 26), E( 1, 63), + E(43, 25), E(56, 31), E( 8, 34), E(32, 14), E(44, 33), E(32, 35), + E(26, 31), E(31, 5), E(33, 49), E(31, 20), E(36, 33), E(32, 1), + E(27, 33), E(31, 34), E(31, 30), E(28, 39), E(37, 36), E(43, 31), + E(31, 59), E(34, 39), E(31, 27), E(34, 61), E(42, 38), E(24, 39), + E(45, 25), E(30, 61), E(20, 29), E(23, 37), E( 8, 30), E(38, 41), + E(22, 26), E(33, 48), E(17, 28), E(52, 33), E(34, 50), E(29, 21), + E(32, 9), E(30, 23), E(49, 33), E(43, 35), E(28, 24), E(39, 39), + E(33, 21), E(33, 34), E(32, 28), E(30, 29), E(25, 37), E(32, 11), + E(48, 33), E( 2, 30), E(15, 31), E(20, 31), E(22, 35), E(53, 30), + E(43, 37), E(44, 29), E(29, 30), E( 1, 29), E(27, 40), E(31, 6), + E(41, 39), E(43, 28), E(41, 28), E(30, 19), E(31, 8), E(36, 22), + E(30, 45), E(25, 28), E(31, 51), E(28, 40), E(32, 25), E(21, 35), + E(24, 29), E(25, 25), E(15, 33), E(20, 32), E(40, 30), E(39, 34), + E(31, 46), E(17, 35), E(22, 32), E(39, 31), E(33, 28), E(29, 29), + E(21, 32), E(37, 37), E(43, 30), E(18, 30), E(32, 8), E(37, 32), + E(31, 32), E(31, 22), E(31, 40), E(57, 32), E(38, 29), E(33, 37), + E(35, 35), E(33, 63), E( 5, 34), E(55, 35), E(31, 10), E(33, 58), + E(30, 17), E(40, 37), E(23, 39), E(15, 30), E(29, 18), E(34, 54), + E(34, 14), E(59, 29), E(34, 16), E(30, 59), E(11, 30), E(13, 35), + E(38, 23), E( 5, 35), E(24, 28), E(33, 15), E(37, 30), E(25, 31), + E(36, 40), E(13, 33), E(33, 45), E(31, 49), E(32, 16), E(42, 31), + E(25, 33), E(32, 36), E(39, 25), E(11, 32), E(33, 5), E(61, 31), + E(63, 32), E(31, 4), E( 0, 30), E(30, 47), E(32, 62), E(37, 29), + E(31, 2), E(42, 36), E( 5, 29), E(30, 55), E(29, 20), E(29, 35), + E(34, 12), E(10, 31), E(44, 35), E(30, 14), E(63, 29), E(35, 18), + E(12, 34), E( 3, 34), E(33, 47), E(32, 51), E(39, 36), E(37, 39), + E(32, 53), E(32, 10), E(29, 24), E(17, 29), E(32, 20), E(29, 39), + E(33, 27), E(31, 36), E(32, 27), E(31, 3), E(30, 39), E(44, 32), + E(31, 37), E( 5, 33), E(44, 30), E(46, 31), E(32, 40), E(36, 25), + E(35, 40), E(26, 38), E(37, 38), E(33, 38), E(25, 32), E( 2, 32), + E(58, 33), E(26, 24), E(15, 29), E(31, 1), E(31, 25), E(17, 26), + E(25, 22), E(34, 2), E(43, 27), E(39, 23), E(34, 8), E(56, 30), + E(29, 55), E(23, 38), E(30, 60), E(12, 31), E(30, 4), E(10, 34), + E(35, 49), E( 9, 34), E(24, 27), E(58, 34), E(10, 33), E(12, 30), + E(54, 31), E(32, 56), E(34, 23), E(38, 27), E( 8, 32), E(22, 31), + E(34, 24), E(36, 36), E(17, 32), E(38, 36), E(33, 25), E(32, 33), + E(32, 31), E(58, 32), E(38, 28), E(38, 37), E(38, 26), E(22, 29), + E(29, 43), E(32, 61), E(25, 36), E(16, 33), E(35, 24), E(32, 55), + E(35, 43), E(33, 9), E(43, 29), E(18, 34), E(46, 34), E(38, 24), + E(35, 26), E(32, 6), E(60, 31), E( 1, 32), E(23, 33), E(30, 35), + E(27, 32), E(33, 26), E(41, 31), E(35, 38), E(33, 54), E(37, 42), + E(20, 35), E(41, 38), E(35, 46), E(29, 44), E(18, 26), E(61, 27), + E(30, 9), E(40, 39), E(24, 25), E(39, 21), E(39, 32), E(53, 29), + E(62, 28), E(26, 42), E(29, 13), E(33, 0), E(34, 5), E(53, 34), + E(49, 37), E(21, 28), E(27, 24), E(11, 29), E(63, 63), E(50, 33), + E(33, 18), E(18, 33), E(53, 33), E(60, 30), E(13, 31), E(32, 50), + E(36, 24), E(24, 34), E(27, 34), E(32, 58), E(38, 35), E(35, 28), + E(16, 32), E(33, 60), E(51, 30), E(32, 4), E(36, 39), E(43, 34), + E(45, 30), E(27, 39), E(45, 33), E(42, 33), E(30, 38), E(32, 17), + E(31, 43), E(20, 26), E(26, 22), E(23, 27), E( 7, 29), E(13, 25), + E( 6, 33), E(47, 25), E(29, 61), E(30, 0), E( 9, 35), E(51, 25), + E(22, 36), E(34, 15), E(21, 27), E(25, 40), E(33, 53), E(32, 37), + E(56, 33), E(57, 3), E(30, 10), E(38, 16), E(51, 37), E(51, 38), + E(38, 18), E(63, 30), E(28, 46), E(40, 27), E(35, 9), E(33, 6), + E(42, 28), E(29, 22), E(24, 38), E(30, 2), E(25, 26), E(31, 63), + E(52, 32), E(31, 57), E(29, 26), E(35, 31), E(32, 5), E(41, 32), + E(35, 21), E(38, 39), E( 4, 31), E(30, 40), E(17, 31), E( 9, 33), + E(22, 28), E(34, 18), E( 4, 30), E(17, 34), E(28, 22), E(55, 33), + E(42, 29), E(40, 34), E(46, 32), E(38, 34), E(48, 32), E(63, 31), + E(23, 31), E(39, 33), E(33, 3), E( 3, 31), E(18, 29), E(33, 62), + E(33, 8), E(24, 42), E(58, 28), E(58, 29), E(34, 3), E(49, 25), + E(29, 16), E(43, 26), E( 4, 29), E( 1, 35), E( 4, 28), E(42, 27), + E(35, 51), E(35, 61), E(30, 48), E(17, 37), E( 5, 9), E(56, 34), + E(25, 41), E(17, 30), E(20, 34), E(47, 35), E(34, 21), E(33, 13), + E(16, 34), E(40, 35), E(32, 19), E(28, 35), E(33, 36), E(36, 30), + E(25, 39), E(16, 30), E(42, 30), E(19, 32), E(30, 46), E(53, 32), + E(32, 23), E(29, 42), E(10, 32), E(11, 31), E(14, 33), E(34, 38), + E(32, 39), E(41, 29), E(26, 26), E(61, 7), E(25, 49), E(22, 33), + E(28, 38), E(36, 38), E(45, 32), E(34, 27), E(28, 30), E(34, 28), + E(33, 59), E(37, 45), E(36, 20), E(55, 29), E(28, 21), E(35, 5), + E(29, 5), E(50, 29), E(48, 28), E(52, 34), E( 2, 29), E(42, 24), + E(34, 10), E(40, 24), E(46, 35), E(46, 36), E(43, 38), E(33, 11), + E( 4, 33), E(33, 40), E(32, 18), E(36, 34), E(27, 35), E(35, 22), + E(35, 55), E(29, 11), E(29, 38), E(41, 33), E(29, 28), E( 7, 32), + E(44, 31), E(26, 25), E(39, 29), E(32, 3), E(16, 31), E(31, 53), + E(26, 27), E(34, 43), E(38, 25), E(29, 40), E(41, 35), E(35, 27), + E(36, 29), E(38, 31), E(29, 27), E(32, 43), E(27, 29), E(30, 37), + E(24, 32), ESCAPE, E(32, 63), E(24, 31), E(42, 34), E(48, 36), + E(20, 38), E(29, 53), E(31, 54), E(61, 33), E(41, 26), E( 7, 30), + E(30, 49), E(35, 20), E(19, 27), E(14, 30), E(21, 39), E( 8, 33), + E(39, 41), E(39, 49), E(40, 22), E(46, 38), E(55, 38), E(34, 4), + E( 6, 30), E(30, 8), E(34, 9), E(37, 3), E(25, 24), E(37, 22), + E(33, 50), E(22, 37), E(44, 36), E(52, 31), E(17, 27), E(35, 2), + E(31, 50), E(30, 21), E(24, 36), E(35, 33), E(22, 38), E(61, 30), + E(32, 12), E( 9, 31), E(45, 34), E(34, 20), E(31, 15), E(19, 29), + E( 9, 32), E(31, 62), E(18, 32), E(33, 17), E(33, 1), E(37, 34), + E(32, 15), E(22, 30), E(26, 30), E(59, 31), E(29, 9), E(36, 42), + E(46, 30), E(31, 13), E(35, 17), E(54, 32), E(29, 19), E(57, 31), + E(30, 20), E(50, 31), E( 3, 30), E(31, 7), E(63, 1), E(34, 17), + E(47, 34), E(41, 37), E(35, 63), E(40, 25), E(25, 30), E(37, 28), + E( 1, 31), E(26, 28), E(22, 34), E(35, 37), E(34, 32), E(60, 32), + E(27, 30), E(37, 19), E(28, 44), E(30, 1), E(50, 28), E(14, 28), + E(28, 48), E(55, 30), E( 6, 34), E(23, 41), E(19, 41), E(14, 38), + E(30, 12), E( 3, 27), E(30, 15), E(28, 0), E(28, 16), E(61, 34), + E(61, 35), E(47, 38), E(45, 28), E(48, 29), E(40, 40), E(40, 42), + E(34, 51), E(34, 52), E(25, 45), E(30, 54), E(29, 59), E(35, 59), + E( 4, 42), E(51, 31), E(18, 31), E(31, 44), E(14, 34), E(37, 26), + E(36, 35), E(37, 35), E(30, 26), E(31, 41), E(31, 39), E(23, 32), + E(23, 29), E(38, 40), E(31, 16), E(24, 37), E(32, 52), E(31, 48), + E(50, 30), E(28, 34), E(32, 21), E(33, 20), E(31, 18), E(49, 32), + E(34, 37), E(33, 29), E(31, 29), E(40, 31), E( 3, 33), E(28, 27), + E(26, 35), E(28, 28), E(33, 39), E(34, 26), E(26, 44), E(53, 37), + E(50, 26), E(26, 46), E(41, 24), E(27, 15), E(59, 39), E(27, 22), + E(29, 31), E(38, 46), E(39, 19), E( 3, 35), E(50, 38), E(43, 17), + E(47, 37), E(23, 23), E(33, 52), E(55, 55), E(35, 50), E(21, 37), + E(23, 26), E(35, 11), E(61, 37), E(33, 12), E(46, 24), E(52, 30), + E(35, 16), E(34, 13), E(24, 22), E(30, 13), E(43, 36), E(16, 35), + E(37, 40), E(21, 41), E( 2, 34), E(54, 33), E(27, 38), E( 9, 29), + E(33, 7), E(23, 25), E(19, 30), E(32, 54), E(29, 45), E(29, 47), + E(33, 46), E(28, 41), E(27, 27), E(32, 49), E(39, 30), E(33, 31), + E(59, 32), E(32, 42), E(33, 22), E(47, 29), E(49, 29), E(32, 59), + E(40, 32), E(31, 24), E(27, 37), E(23, 34), E(28, 37), E(36, 26), + E(32, 7), E(38, 32), E(29, 33), E(15, 32), E(30, 16), E(47, 30), + E(33, 14), E(27, 26), E(25, 38), E(54, 34), E(44, 34), E(45, 29), + E(50, 34), E(58, 30), E(51, 29), E(48, 30), E(33, 57), E(59, 30), + E( 6, 32), E(34, 22), E(27, 28), E(31, 45), E(30, 27), E(24, 33), + E(26, 29), E(33, 4), E(24, 41), E(45, 26), E(23, 30), E( 2, 31), + E(28, 29), E(35, 36), E(30, 28), E(34, 53), E(30, 51), E(55, 5), + E(55, 21), E( 1, 30), E(29, 2), E(29, 63), E(26, 41), E(28, 20), + E(25, 1), E(31, 56), E(36, 21), E(22, 24), E(17, 25), E(30, 5), + E(52, 28), E( 2, 35), E(44, 26), E(44, 28), E(57, 30), E(26, 18), + E(62, 29), E(41, 23), E(39, 40), E(57, 34), E(26, 20), E(46, 42), + E(49, 39), E(11, 34), E(16, 28), E(19, 61), E( 5, 38), E(34, 46), + E(57, 33), E(13, 29), E(26, 39), E(33, 44), E(13, 30), E(48, 31), + E(30, 50), E(11, 33), E( 7, 31), E(56, 32), E(34, 19), E(33, 43), + E(32, 46), E(34, 41), E(41, 30), E(36, 28), E(34, 31), E(33, 33), + E(33, 35), E(26, 34), E(28, 26), E(32, 13), E(41, 34), E( 0, 32), + E(32, 57), E(35, 30), E(35, 32), E(55, 32), E(26, 40), E( 0, 31), + E(26, 37), E(35, 47), E( 1, 1), E(51, 35), E(33, 16), E(53, 31), + E(31, 0), E(45, 35), E(12, 33), E(29, 1), E(29, 17), E(36, 27), + E( 5, 32), E(38, 38), E(59, 27), E(38, 62), E(39, 9), E(58, 36), + E(34, 42), E(31, 42), E(36, 31), E(47, 33), E(32, 47), E(17, 33), + E(31, 60), E(31, 23), E(33, 41), E(34, 30), E(34, 36), E(32, 60), + E(29, 36), E(38, 17), E(25, 9), E(49, 49), E(50, 24), E(22, 25), + E(28, 54), E(59, 34), E( 9, 39), E(59, 37), E( 7, 3), E(28, 1), + E(55, 25), E(17, 38), E( 4, 38), E(35, 44), E(50, 35), E(21, 36), + E(29, 12), E(44, 60), E(47, 36), E(18, 38), E(24, 40), E(19, 25), + E(25, 43), E(31, 31), }; -static const uint8_t table1_mv_bits[1100] = { - 2, 4, 4, 4, 5, 5, 5, 5, - 6, 6, 7, 7, 7, 7, 7, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 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, 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, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 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, 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, 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, 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, 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, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 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, 4, -}; - -static const uint8_t table1_mvx[1099] = { - 32, 31, 32, 31, 33, 32, 33, 33, - 31, 34, 30, 32, 32, 34, 35, 32, - 34, 33, 29, 30, 30, 32, 31, 31, - 33, 35, 35, 33, 31, 29, 29, 33, - 34, 30, 31, 28, 36, 30, 34, 32, - 32, 37, 32, 32, 25, 27, 39, 32, - 32, 32, 38, 35, 36, 32, 37, 61, - 26, 32, 34, 35, 3, 35, 27, 28, - 29, 34, 28, 37, 31, 36, 32, 27, - 31, 30, 29, 39, 33, 29, 33, 35, - 25, 25, 29, 33, 31, 31, 31, 33, - 32, 30, 32, 32, 41, 39, 33, 36, - 32, 28, 34, 36, 38, 24, 60, 31, - 23, 28, 32, 33, 59, 32, 40, 30, - 5, 34, 32, 38, 32, 30, 43, 4, - 32, 32, 42, 31, 31, 32, 26, 38, - 26, 22, 21, 37, 61, 63, 37, 31, - 32, 33, 2, 1, 23, 33, 41, 27, - 35, 30, 38, 23, 33, 3, 28, 34, - 34, 27, 41, 29, 39, 35, 36, 29, - 32, 27, 30, 32, 24, 61, 37, 26, - 59, 25, 35, 27, 36, 37, 30, 31, - 34, 40, 3, 28, 34, 39, 32, 31, - 32, 30, 24, 28, 35, 36, 26, 32, - 31, 33, 29, 33, 39, 25, 30, 24, - 35, 59, 29, 34, 25, 30, 21, 35, - 43, 40, 32, 29, 5, 28, 31, 62, - 33, 33, 25, 31, 21, 31, 43, 31, - 34, 33, 20, 40, 39, 31, 31, 57, - 38, 32, 42, 33, 32, 31, 32, 29, - 30, 44, 5, 31, 22, 34, 36, 17, - 38, 58, 38, 35, 32, 60, 35, 24, - 32, 38, 16, 45, 42, 32, 31, 29, - 4, 30, 17, 40, 46, 48, 63, 32, - 42, 19, 41, 22, 28, 36, 45, 33, - 33, 32, 29, 7, 41, 42, 18, 33, - 33, 32, 22, 37, 1, 26, 22, 23, - 49, 28, 26, 27, 32, 33, 27, 23, - 28, 36, 15, 6, 34, 27, 31, 26, - 23, 2, 33, 32, 34, 41, 28, 32, - 41, 0, 36, 38, 34, 31, 47, 32, - 17, 31, 39, 33, 37, 51, 30, 47, - 32, 50, 32, 19, 63, 30, 25, 27, - 33, 62, 24, 31, 27, 30, 37, 31, - 45, 32, 39, 20, 46, 47, 35, 19, - 34, 1, 49, 21, 21, 14, 51, 26, - 23, 31, 36, 35, 58, 29, 29, 21, - 20, 42, 13, 28, 12, 40, 31, 33, - 39, 60, 32, 44, 33, 31, 28, 37, - 29, 32, 30, 49, 43, 28, 39, 25, - 32, 48, 2, 15, 20, 25, 31, 28, - 21, 24, 25, 15, 31, 17, 37, 43, - 18, 32, 33, 24, 33, 36, 13, 33, - 31, 39, 11, 31, 33, 32, 39, 37, - 32, 32, 29, 17, 44, 46, 36, 35, - 26, 37, 58, 32, 34, 38, 8, 38, - 38, 22, 29, 25, 16, 35, 32, 35, - 33, 43, 18, 46, 38, 50, 33, 18, - 53, 60, 13, 32, 36, 33, 51, 36, - 43, 45, 27, 42, 29, 24, 30, 25, - 31, 52, 31, 35, 38, 9, 22, 34, - 4, 17, 28, 55, 42, 25, 17, 20, - 47, 34, 33, 16, 40, 25, 16, 30, - 53, 29, 10, 11, 14, 26, 33, 4, - 35, 44, 26, 16, 31, 26, 34, 38, - 29, 31, 30, 24, 22, 61, 32, 9, - 45, 34, 31, 19, 9, 31, 46, 31, - 35, 54, 29, 57, 30, 50, 3, 31, - 63, 34, 47, 41, 51, 18, 31, 14, - 37, 38, 31, 24, 32, 31, 50, 33, - 31, 54, 27, 9, 33, 23, 19, 32, - 29, 29, 33, 28, 47, 49, 30, 47, - 33, 27, 25, 54, 44, 45, 50, 58, - 51, 48, 33, 59, 33, 34, 57, 13, - 26, 33, 13, 48, 30, 11, 7, 56, - 34, 55, 26, 0, 26, 35, 1, 51, - 33, 53, 31, 45, 12, 29, 29, 51, - 31, 48, 2, 6, 34, 30, 28, 33, - 60, 40, 27, 46, 31, 9, 35, 29, - 31, 39, 55, 46, 19, 37, 62, 34, - 30, 16, 19, 49, 41, 41, 39, 37, - 14, 5, 13, 35, 55, 30, 40, 40, - 42, 8, 20, 25, 45, 35, 33, 36, - 54, 38, 27, 37, 62, 40, 15, 59, - 49, 31, 29, 34, 34, 39, 24, 29, - 25, 29, 21, 29, 10, 61, 33, 49, - 35, 34, 3, 38, 39, 29, 7, 41, - 1, 35, 4, 23, 15, 23, 11, 37, - 28, 35, 30, 30, 24, 1, 43, 56, - 8, 34, 42, 24, 45, 30, 20, 23, - 8, 38, 22, 33, 17, 52, 34, 22, - 53, 43, 44, 1, 27, 31, 41, 43, - 41, 30, 31, 36, 30, 5, 55, 31, - 33, 30, 40, 23, 15, 29, 34, 34, - 59, 34, 30, 11, 13, 38, 5, 0, - 30, 42, 5, 30, 29, 34, 10, 44, - 30, 63, 35, 12, 3, 26, 15, 17, - 25, 34, 43, 39, 34, 56, 29, 23, - 30, 12, 30, 10, 35, 9, 24, 58, - 10, 12, 54, 33, 37, 20, 41, 35, - 29, 18, 61, 30, 40, 24, 39, 53, - 62, 26, 29, 33, 34, 53, 49, 21, - 27, 11, 63, 20, 26, 23, 7, 13, - 6, 47, 29, 30, 9, 51, 22, 34, - 21, 25, 33, 56, 57, 30, 38, 51, - 51, 38, 63, 28, 40, 35, 33, 18, - 33, 33, 24, 58, 58, 34, 49, 29, - 43, 4, 1, 4, 42, 35, 35, 30, - 17, 5, 56, 61, 25, 37, 36, 55, - 28, 35, 29, 50, 48, 52, 2, 42, - 34, 40, 46, 46, 43, 35, 29, 48, - 20, 29, 31, 41, 7, 30, 35, 19, - 14, 21, 8, 39, 39, 40, 46, 55, - 34, 6, 30, 34, 37, 25, 37, 33, - 22, 44, 52, 17, 35, 29, 36, 35, - 40, 37, 28, 30, 50, 14, 28, 55, - 6, 23, 19, 14, 30, 3, 30, 28, - 28, 61, 61, 47, 45, 48, 40, 40, - 34, 34, 25, 30, 29, 35, 4, 26, - 53, 50, 26, 41, 27, 59, 27, 38, - 39, 3, 50, 43, 47, 23, 33, 55, - 35, 21, 23, 35, 61, 33, 46, 52, - 35, 34, 24, 30, 43, 16, 37, 21, - 2, 24, 45, 34, 30, 55, 55, 1, - 29, 29, 26, 28, 25, 31, 36, 22, - 17, 30, 52, 2, 44, 44, 57, 26, - 62, 41, 39, 57, 26, 46, 49, 11, - 16, 19, 5, 59, 38, 39, 58, 38, - 25, 49, 50, 22, 28, 59, 9, 59, - 7, 28, 55, 17, 4, 35, 50, 21, - 29, 44, 47, 18, 24, 19, 25, 42, - 35, 3, 51, 35, 16, 35, 30, 63, - 57, 39, 39, 25, 35, 38, 9, 16, - 36, 45, 31, 60, 14, 34, 42, 24, - 0, 37, 18, 61, 57, 37, 28, 53, - 20, 46, 14, 47, 38, 38, 38, 9, - 34, 39, 43, 17, 39, 59, 5, 27, - 0, 12, 27, -}; - -static const uint8_t table1_mvy[1099] = { - 32, 32, 31, 31, 32, 33, 31, 33, - 33, 32, 32, 30, 34, 31, 32, 29, - 33, 30, 32, 33, 31, 35, 34, 30, - 34, 31, 33, 29, 29, 31, 33, 35, - 30, 30, 35, 32, 32, 34, 34, 28, - 25, 32, 36, 27, 32, 32, 32, 37, - 39, 3, 32, 30, 31, 26, 31, 32, - 32, 38, 29, 29, 32, 34, 31, 31, - 34, 35, 33, 33, 28, 33, 1, 33, - 27, 29, 30, 31, 28, 29, 37, 35, - 31, 33, 35, 27, 36, 37, 25, 25, - 61, 35, 4, 5, 32, 33, 36, 30, - 23, 30, 28, 34, 31, 32, 32, 39, - 32, 34, 21, 39, 32, 59, 32, 28, - 32, 36, 60, 33, 24, 36, 32, 32, - 41, 2, 32, 38, 26, 22, 33, 30, - 31, 32, 32, 30, 31, 32, 29, 3, - 40, 38, 32, 32, 33, 26, 31, 34, - 28, 38, 34, 31, 3, 31, 35, 38, - 27, 35, 33, 28, 29, 27, 29, 27, - 43, 29, 37, 63, 31, 33, 34, 30, - 31, 30, 37, 30, 35, 35, 26, 41, - 37, 31, 33, 28, 26, 30, 42, 24, - 7, 27, 33, 29, 36, 28, 34, 57, - 23, 41, 36, 23, 35, 34, 25, 30, - 25, 33, 25, 25, 29, 24, 33, 39, - 33, 33, 0, 37, 31, 36, 21, 32, - 61, 24, 35, 61, 31, 5, 31, 59, - 39, 21, 32, 30, 34, 22, 40, 32, - 29, 16, 31, 5, 62, 2, 20, 39, - 39, 32, 33, 1, 31, 24, 36, 32, - 36, 32, 28, 26, 6, 31, 38, 34, - 58, 35, 32, 33, 33, 17, 43, 26, - 31, 40, 31, 34, 32, 32, 31, 19, - 30, 32, 29, 33, 38, 38, 32, 59, - 40, 18, 38, 32, 35, 34, 32, 17, - 1, 15, 30, 28, 31, 28, 34, 29, - 32, 27, 35, 27, 49, 22, 37, 34, - 37, 26, 32, 32, 22, 28, 45, 29, - 30, 31, 43, 46, 41, 30, 26, 13, - 34, 32, 27, 38, 42, 42, 33, 47, - 33, 60, 27, 42, 25, 32, 22, 32, - 48, 32, 45, 33, 33, 41, 27, 25, - 19, 31, 35, 19, 36, 42, 27, 17, - 31, 44, 28, 33, 33, 31, 23, 31, - 40, 33, 31, 34, 30, 32, 33, 36, - 35, 47, 37, 41, 31, 23, 41, 29, - 30, 35, 32, 25, 32, 28, 58, 2, - 37, 33, 14, 33, 49, 20, 39, 36, - 21, 9, 23, 33, 35, 24, 39, 37, - 11, 33, 30, 31, 31, 28, 51, 40, - 35, 29, 25, 33, 46, 35, 37, 30, - 30, 8, 63, 28, 15, 40, 33, 45, - 49, 25, 32, 4, 47, 51, 36, 39, - 53, 10, 24, 29, 30, 31, 25, 40, - 38, 38, 33, 56, 23, 27, 32, 37, - 26, 29, 43, 36, 33, 24, 55, 43, - 9, 29, 34, 34, 24, 33, 18, 33, - 33, 30, 31, 50, 24, 60, 30, 39, - 34, 30, 39, 28, 22, 38, 2, 26, - 63, 32, 57, 21, 39, 33, 28, 18, - 30, 34, 22, 33, 29, 41, 30, 34, - 35, 21, 13, 34, 35, 39, 30, 46, - 32, 42, 32, 31, 33, 26, 11, 33, - 22, 31, 25, 31, 53, 27, 43, 25, - 40, 50, 21, 36, 38, 30, 12, 31, - 34, 20, 15, 29, 32, 62, 30, 13, - 17, 32, 19, 31, 20, 31, 30, 7, - 1, 17, 34, 37, 31, 31, 44, 34, - 26, 40, 16, 37, 52, 48, 30, 20, - 18, 33, 38, 29, 7, 25, 30, 54, - 45, 47, 46, 41, 29, 29, 16, 30, - 14, 26, 38, 34, 34, 29, 34, 30, - 29, 30, 57, 30, 4, 46, 33, 29, - 39, 44, 30, 31, 50, 33, 31, 32, - 19, 32, 40, 31, 37, 47, 1, 35, - 16, 31, 0, 35, 33, 1, 17, 34, - 9, 34, 33, 31, 49, 43, 42, 51, - 34, 29, 23, 29, 14, 30, 45, 49, - 11, 24, 31, 28, 35, 41, 30, 44, - 18, 29, 34, 35, 36, 25, 26, 21, - 31, 30, 34, 19, 34, 44, 36, 38, - 25, 31, 28, 23, 37, 3, 55, 41, - 30, 22, 41, 24, 33, 26, 35, 35, - 30, 55, 51, 47, 48, 38, 24, 15, - 21, 50, 25, 46, 30, 29, 10, 34, - 42, 45, 29, 42, 22, 3, 33, 27, - 34, 1, 34, 28, 34, 36, 35, 23, - 23, 13, 58, 3, 26, 63, 25, 31, - 34, 61, 38, 39, 25, 61, 29, 37, - 30, 41, 26, 48, 28, 33, 50, 35, - 30, 37, 29, 29, 40, 6, 39, 28, - 28, 19, 8, 22, 45, 34, 35, 10, - 58, 17, 37, 39, 30, 18, 54, 14, - 29, 16, 59, 30, 35, 23, 35, 30, - 47, 36, 29, 55, 20, 12, 31, 35, - 14, 29, 18, 34, 34, 24, 29, 26, - 22, 2, 27, 23, 8, 30, 55, 38, - 60, 31, 4, 34, 49, 34, 27, 34, - 33, 30, 31, 54, 42, 35, 38, 46, - 44, 26, 27, 9, 39, 25, 21, 29, - 28, 42, 13, 0, 5, 34, 37, 28, - 24, 29, 63, 26, 22, 27, 29, 25, - 33, 25, 61, 0, 35, 25, 36, 15, - 27, 40, 53, 33, 3, 10, 16, 37, - 38, 18, 30, 46, 27, 9, 6, 29, - 62, 8, 42, 28, 29, 3, 25, 16, - 26, 29, 35, 28, 27, 51, 61, 48, - 37, 9, 34, 7, 49, 45, 20, 29, - 21, 5, 5, 29, 28, 34, 29, 24, - 10, 24, 35, 36, 38, 55, 11, 36, - 38, 53, 54, 26, 30, 49, 20, 27, - 30, 39, 33, 41, 49, 22, 38, 38, - 4, 30, 8, 9, 3, 24, 22, 50, - 37, 36, 31, 27, 2, 9, 42, 63, - 25, 19, 44, 1, 28, 28, 48, 30, - 34, 41, 41, 38, 12, 27, 15, 0, - 16, 34, 35, 38, 28, 29, 40, 42, - 51, 52, 45, 54, 59, 59, 42, 44, - 37, 26, 46, 24, 15, 39, 22, 46, - 19, 35, 38, 17, 37, 23, 52, 55, - 50, 37, 26, 11, 37, 12, 24, 30, - 16, 13, 22, 13, 36, 35, 40, 41, - 34, 41, 26, 53, 51, 5, 21, 30, - 2, 63, 41, 20, 1, 56, 21, 24, - 25, 5, 28, 35, 26, 28, 30, 18, - 29, 23, 40, 34, 20, 42, 39, 34, - 28, 61, 38, 27, 62, 9, 36, 17, - 9, 49, 24, 25, 54, 34, 39, 37, - 3, 1, 25, 38, 38, 44, 35, 36, - 12, 60, 36, 38, 40, 25, 43, 39, - 53, 28, 39, 57, 46, 10, 52, 27, - 35, 42, 45, 59, 15, 60, 38, 24, - 23, 39, 12, 29, 24, 0, 20, 16, - 28, 43, 35, 28, 1, 49, 4, 21, - 42, 39, 29, 3, 44, 21, 53, 55, - 11, 5, 3, 39, 53, 28, 25, 19, - 34, 28, 21, -}; - -MVTable ff_mv_tables[2] = { - { table0_mv_code, - table0_mv_bits, - table0_mvx, - table0_mvy, }, - { table1_mv_code, - table1_mv_bits, - table1_mvx, - table1_mvy, } +const uint8_t ff_msmp4_mv_table1_lens[MSMPEG4_MV_TABLES_NB_ELEMS] = { + 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 13, 13, 13, 14, 15, 15, 11, 13, 13, 12, 11, 10, + 8, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 12, 10, 12, 12, 12, 12, 10, + 14, 15, 15, 13, 13, 13, 12, 12, 11, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 9, 6, 9, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 13, 13, 11, 11, 12, 13, 13, 11, 12, 13, 13, 10, 7, 8, 10, 14, + 15, 15, 14, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, + 13, 13, 12, 13, 13, 13, 13, 13, 13, 13, 13, 8, 9, 9, 5, 13, 14, 14, + 12, 12, 14, 14, 14, 14, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, + 12, 12, 12, 11, 10, 11, 13, 13, 13, 13, 12, 12, 12, 13, 14, 14, 11, 12, + 14, 14, 14, 14, 7, 8, 9, 10, 14, 14, 13, 12, 11, 7, 8, 10, 13, 14, + 14, 13, 13, 13, 13, 13, 13, 13, 13, 12, 11, 13, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 8, 13, 13, 13, 13, 12, 12, 10, 10, 10, + 10, 11, 14, 14, 13, 13, 13, 12, 13, 14, 14, 11, 10, 9, 10, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 8, 11, 12, 13, 13, 10, 10, + 10, 8, 8, 13, 13, 12, 12, 12, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 8, 9, 10, 13, 13, + 13, 13, 13, 13, 14, 14, 14, 14, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 13, 13, 13, 9, 13, 13, 13, 13, 12, 12, 12, 13, 13, 11, 10, 10, 10, + 11, 13, 13, 13, 13, 9, 4, 12, 12, 12, 12, 10, 10, 13, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 11, 10, + 13, 13, 13, 13, 12, 12, 10, 9, 13, 13, 12, 11, 11, 13, 14, 14, 12, 11, + 12, 14, 14, 14, 14, 10, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, + 13, 13, 13, 13, 12, 12, 10, 10, 9, 11, 12, 12, 10, 12, 13, 13, 11, 13, + 13, 13, 13, 11, 9, 11, 13, 14, 14, 12, 10, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 12, + 12, 12, 12, 12, 10, 5, 4, 12, 12, 13, 13, 13, 13, 10, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 12, 12, 12, 11, 11, 10, 9, 11, 11, 12, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 12, 11, 12, 12, 11, + 12, 13, 13, 10, 13, 13, 13, 13, 12, 12, 11, 12, 12, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 12, 8, 10, 10, + 13, 13, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 11, 12, 12, + 11, 10, 11, 11, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 12, 11, 10, 10, + 13, 13, 12, 12, 13, 13, 10, 13, 13, 13, 13, 11, 9, 12, 13, 14, 14, 12, + 12, 12, 12, 11, 10, 10, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 13, 13, 12, 12, 10, 11, 13, 14, 14, 12, 11, 11, 12, + 13, 13, 11, 9, 13, 13, 13, 13, 13, 13, 12, 11, 11, 10, 11, 11, 11, 11, + 10, 4, 11, 11, 12, 14, 14, 14, 14, 11, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 13, 13, 13, 8, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 11, + 12, 12, 11, 11, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 14, 14, 11, 12, 12, 12, 12, 11, 6, 10, 11, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 11, 11, 11, 11, 10, 10, + 12, 13, 13, 13, 13, 13, 13, 10, 10, 13, 13, 12, 11, 8, 8, 11, 11, 12, + 12, 11, 10, 11, 14, 14, 14, 14, 14, 14, 14, 14, 8, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 11, 5, + 10, 11, 12, 13, 13, 10, 10, 11, 12, 12, 12, 12, 11, 9, 8, 12, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, + 12, 13, 14, 14, 12, 12, 11, 11, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, + 12, 12, 12, 11, 7, 5, 8, 11, 12, 12, 12, 12, 11, 9, 7, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 10, 12, 14, 14, 14, 14, + 12, 12, 9, 12, 12, 12, 12, 11, 11, 8, 10, 10, 11, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 4, }; const uint8_t ff_v2_mb_type[8][2] = { diff --git a/libavcodec/msmpeg4data.h b/libavcodec/msmpeg4data.h index aa4ca86a0..13267d25c 100644 --- a/libavcodec/msmpeg4data.h +++ b/libavcodec/msmpeg4data.h @@ -35,17 +35,6 @@ #include "libavutil/attributes_internal.h" #include "rl.h" -#include "vlc.h" - -/* motion vector table */ -typedef struct MVTable { - const uint16_t *table_mv_code; - const uint8_t *table_mv_bits; - const uint8_t *table_mvx; - const uint8_t *table_mvy; - uint16_t *table_mv_index; /* encoding: convert mv to index in table_mv */ - const VLCElem *vlc; /* decoding: vlc */ -} MVTable; FF_VISIBILITY_PUSH_HIDDEN #define NB_RL_TABLES 6 @@ -59,8 +48,12 @@ extern const uint8_t ff_wmv1_y_dc_scale_table[32]; extern const uint8_t ff_wmv1_c_dc_scale_table[32]; extern const uint8_t ff_old_ff_y_dc_scale_table[32]; -#define MSMPEG4_MV_TABLES_NB_ELEMS 1099 -extern MVTable ff_mv_tables[2]; +#define MSMPEG4_MV_TABLES_NB_ELEMS 1100 +/// The entries are of the form (8 << mvx) | mvy. Escape value is zero. +extern const uint16_t ff_msmp4_mv_table0[MSMPEG4_MV_TABLES_NB_ELEMS]; +extern const uint8_t ff_msmp4_mv_table0_lens[MSMPEG4_MV_TABLES_NB_ELEMS]; +extern const uint16_t ff_msmp4_mv_table1[MSMPEG4_MV_TABLES_NB_ELEMS]; +extern const uint8_t ff_msmp4_mv_table1_lens[MSMPEG4_MV_TABLES_NB_ELEMS]; extern const uint8_t ff_v2_mb_type[8][2]; extern const uint8_t ff_v2_intra_cbpc[4][2]; diff --git a/libavcodec/msmpeg4dec.c b/libavcodec/msmpeg4dec.c index 12bef4f50..23f302dee 100644 --- a/libavcodec/msmpeg4dec.c +++ b/libavcodec/msmpeg4dec.c @@ -46,7 +46,9 @@ #define DEFAULT_INTER_INDEX 3 -static inline int msmpeg4v1_pred_dc(MpegEncContext * s, int n, +static const VLCElem *mv_tables[2]; + +static inline int msmpeg4v1_pred_dc(H263DecContext *const h, int n, int32_t **dc_val_ptr) { int i; @@ -57,8 +59,8 @@ static inline int msmpeg4v1_pred_dc(MpegEncContext * s, int n, i= n-3; } - *dc_val_ptr= &s->last_dc[i]; - return s->last_dc[i]; + *dc_val_ptr= &h->last_dc[i]; + return h->last_dc[i]; } /****************************************/ @@ -72,23 +74,24 @@ static VLCElem v2_mb_type_vlc[128]; VLCElem ff_inter_intra_vlc[8]; /* This is identical to H.263 except that its range is multiplied by 2. */ -static int msmpeg4v2_decode_motion(MpegEncContext * s, int pred, int f_code) +static int msmpeg4v2_decode_motion(H263DecContext *const h, int pred, int f_code) { int code, val, sign, shift; - code = get_vlc2(&s->gb, ff_h263_mv_vlc, H263_MV_VLC_BITS, 2); - ff_dlog(s, "MV code %d at %d %d pred: %d\n", code, s->mb_x,s->mb_y, pred); + code = get_vlc2(&h->gb, ff_h263_mv_vlc, H263_MV_VLC_BITS, 2); + ff_dlog(h->c.avctx, "MV code %d at %d %d pred: %d\n", + code, h->c.mb_x,h->c.mb_y, pred); if (code < 0) return 0xffff; if (code == 0) return pred; - sign = get_bits1(&s->gb); + sign = get_bits1(&h->gb); shift = f_code - 1; val = code; if (shift) { val = (val - 1) << shift; - val |= get_bits(&s->gb, shift); + val |= get_bits(&h->gb, shift); val++; } if (sign) @@ -103,149 +106,155 @@ static int msmpeg4v2_decode_motion(MpegEncContext * s, int pred, int f_code) return val; } -static int msmpeg4v12_decode_mb(MpegEncContext *s, int16_t block[6][64]) +static int msmpeg4v12_decode_mb(H263DecContext *const h) { + MSMP4DecContext *const ms = mpv_to_msmpeg4(h); int cbp, code, i; - uint32_t * const mb_type_ptr = &s->cur_pic.mb_type[s->mb_x + s->mb_y*s->mb_stride]; + uint32_t * const mb_type_ptr = &h->c.cur_pic.mb_type[h->c.mb_x + h->c.mb_y*h->c.mb_stride]; - if (s->pict_type == AV_PICTURE_TYPE_P) { - if (s->use_skip_mb_code) { - if (get_bits1(&s->gb)) { + if (h->c.pict_type == AV_PICTURE_TYPE_P) { + if (ms->use_skip_mb_code) { + if (get_bits1(&h->gb)) { /* skip mb */ - s->mb_intra = 0; + h->c.mb_intra = 0; for(i=0;i<6;i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; - s->mb_skipped = 1; + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = 0; + h->c.mv[0][0][1] = 0; + h->c.mb_skipped = 1; *mb_type_ptr = MB_TYPE_SKIP | MB_TYPE_FORWARD_MV | MB_TYPE_16x16; return 0; } } - if (s->msmpeg4_version == MSMP4_V2) - code = get_vlc2(&s->gb, v2_mb_type_vlc, V2_MB_TYPE_VLC_BITS, 1); + if (h->c.msmpeg4_version == MSMP4_V2) + code = get_vlc2(&h->gb, v2_mb_type_vlc, V2_MB_TYPE_VLC_BITS, 1); else - code = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); + code = get_vlc2(&h->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); if(code<0 || code>7){ - av_log(s->avctx, AV_LOG_ERROR, "cbpc %d invalid at %d %d\n", code, s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpc %d invalid at %d %d\n", + code, h->c.mb_x, h->c.mb_y); return -1; } - s->mb_intra = code >>2; + h->c.mb_intra = code >>2; cbp = code & 0x3; } else { - s->mb_intra = 1; - if (s->msmpeg4_version == MSMP4_V2) - cbp = get_vlc2(&s->gb, v2_intra_cbpc_vlc, V2_INTRA_CBPC_VLC_BITS, 1); + h->c.mb_intra = 1; + if (h->c.msmpeg4_version == MSMP4_V2) + cbp = get_vlc2(&h->gb, v2_intra_cbpc_vlc, V2_INTRA_CBPC_VLC_BITS, 1); else - cbp = get_vlc2(&s->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); + cbp = get_vlc2(&h->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); if(cbp<0 || cbp>3){ - av_log(s->avctx, AV_LOG_ERROR, "cbpc %d invalid at %d %d\n", cbp, s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpc %d invalid at %d %d\n", + cbp, h->c.mb_x, h->c.mb_y); return -1; } } - if (!s->mb_intra) { + if (!h->c.mb_intra) { int mx, my, cbpy; - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if(cbpy<0){ - av_log(s->avctx, AV_LOG_ERROR, "cbpy %d invalid at %d %d\n", cbp, s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpy %d invalid at %d %d\n", + cbp, h->c.mb_x, h->c.mb_y); return -1; } cbp|= cbpy<<2; - if (s->msmpeg4_version == MSMP4_V1 || (cbp&3) != 3) + if (h->c.msmpeg4_version == MSMP4_V1 || (cbp&3) != 3) cbp ^= 0x3C; - ff_h263_pred_motion(s, 0, 0, &mx, &my); - mx= msmpeg4v2_decode_motion(s, mx, 1); - my= msmpeg4v2_decode_motion(s, my, 1); + ff_h263_pred_motion(&h->c, 0, 0, &mx, &my); + mx = msmpeg4v2_decode_motion(h, mx, 1); + my = msmpeg4v2_decode_motion(h, my, 1); - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; *mb_type_ptr = MB_TYPE_FORWARD_MV | MB_TYPE_16x16; } else { int v; - if (s->msmpeg4_version == MSMP4_V2) { - s->ac_pred = get_bits1(&s->gb); - v = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + if (h->c.msmpeg4_version == MSMP4_V2) { + h->c.ac_pred = get_bits1(&h->gb); + v = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (v < 0) { - av_log(s->avctx, AV_LOG_ERROR, "cbpy vlc invalid\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpy vlc invalid\n"); return -1; } cbp|= v<<2; } else{ - s->ac_pred = 0; - v = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + h->c.ac_pred = 0; + v = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (v < 0) { - av_log(s->avctx, AV_LOG_ERROR, "cbpy vlc invalid\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpy vlc invalid\n"); return -1; } cbp|= v<<2; - if(s->pict_type==AV_PICTURE_TYPE_P) cbp^=0x3C; + if (h->c.pict_type==AV_PICTURE_TYPE_P) cbp^=0x3C; } *mb_type_ptr = MB_TYPE_INTRA; } - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); for (i = 0; i < 6; i++) { - if (ff_msmpeg4_decode_block(s, block[i], i, (cbp >> (5 - i)) & 1, NULL) < 0) + if (ff_msmpeg4_decode_block(ms, h->block[i], i, (cbp >> (5 - i)) & 1, NULL) < 0) { - av_log(s->avctx, AV_LOG_ERROR, "\nerror while decoding block: %d x %d (%d)\n", s->mb_x, s->mb_y, i); + av_log(h->c.avctx, AV_LOG_ERROR, "\nerror while decoding block: %d x %d (%d)\n", + h->c.mb_x, h->c.mb_y, i); return -1; } } return 0; } -static int msmpeg4v34_decode_mb(MpegEncContext *s, int16_t block[6][64]) +static int msmpeg4v34_decode_mb(H263DecContext *const h) { + MSMP4DecContext *const ms = mpv_to_msmpeg4(h); int cbp, code, i; uint8_t *coded_val; - uint32_t * const mb_type_ptr = &s->cur_pic.mb_type[s->mb_x + s->mb_y*s->mb_stride]; + uint32_t * const mb_type_ptr = &h->c.cur_pic.mb_type[h->c.mb_x + h->c.mb_y*h->c.mb_stride]; - if (get_bits_left(&s->gb) <= 0) + if (get_bits_left(&h->gb) <= 0) return AVERROR_INVALIDDATA; - if (s->pict_type == AV_PICTURE_TYPE_P) { - if (s->use_skip_mb_code) { - if (get_bits1(&s->gb)) { + if (h->c.pict_type == AV_PICTURE_TYPE_P) { + if (ms->use_skip_mb_code) { + if (get_bits1(&h->gb)) { /* skip mb */ - s->mb_intra = 0; + h->c.mb_intra = 0; for(i=0;i<6;i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; - s->mb_skipped = 1; + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = 0; + h->c.mv[0][0][1] = 0; + h->c.mb_skipped = 1; *mb_type_ptr = MB_TYPE_SKIP | MB_TYPE_FORWARD_MV | MB_TYPE_16x16; return 0; } } - code = get_vlc2(&s->gb, ff_mb_non_intra_vlc[DEFAULT_INTER_INDEX], MB_NON_INTRA_VLC_BITS, 3); - //s->mb_intra = (code & 0x40) ? 0 : 1; - s->mb_intra = (~code & 0x40) >> 6; + code = get_vlc2(&h->gb, ff_mb_non_intra_vlc[DEFAULT_INTER_INDEX], MB_NON_INTRA_VLC_BITS, 3); + //h->c.mb_intra = (code & 0x40) ? 0 : 1; + h->c.mb_intra = (~code & 0x40) >> 6; cbp = code & 0x3f; } else { - s->mb_intra = 1; - code = get_vlc2(&s->gb, ff_msmp4_mb_i_vlc, MSMP4_MB_INTRA_VLC_BITS, 2); + h->c.mb_intra = 1; + code = get_vlc2(&h->gb, ff_msmp4_mb_i_vlc, MSMP4_MB_INTRA_VLC_BITS, 2); /* predict coded block pattern */ cbp = 0; for(i=0;i<6;i++) { int val = ((code >> (5 - i)) & 1); if (i < 4) { - int pred = ff_msmpeg4_coded_block_pred(s, i, &coded_val); + int pred = ff_msmpeg4_coded_block_pred(&h->c, i, &coded_val); val = val ^ pred; *coded_val = val; } @@ -253,41 +262,42 @@ static int msmpeg4v34_decode_mb(MpegEncContext *s, int16_t block[6][64]) } } - if (!s->mb_intra) { + if (!h->c.mb_intra) { int mx, my; - if(s->per_mb_rl_table && cbp){ - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + if (ms->per_mb_rl_table && cbp) { + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; } - ff_h263_pred_motion(s, 0, 0, &mx, &my); - ff_msmpeg4_decode_motion(s, &mx, &my); - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + ff_h263_pred_motion(&h->c, 0, 0, &mx, &my); + ff_msmpeg4_decode_motion(ms, &mx, &my); + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; *mb_type_ptr = MB_TYPE_FORWARD_MV | MB_TYPE_16x16; } else { - ff_dlog(s, "I at %d %d %d %06X\n", s->mb_x, s->mb_y, + ff_dlog(h->c.avctx, "I at %d %d %d %06X\n", h->c.mb_x, h->c.mb_y, ((cbp & 3) ? 1 : 0) +((cbp & 0x3C)? 2 : 0), - show_bits(&s->gb, 24)); - s->ac_pred = get_bits1(&s->gb); + show_bits(&h->gb, 24)); + h->c.ac_pred = get_bits1(&h->gb); *mb_type_ptr = MB_TYPE_INTRA; - if(s->inter_intra_pred){ - s->h263_aic_dir= get_vlc2(&s->gb, ff_inter_intra_vlc, INTER_INTRA_VLC_BITS, 1); - ff_dlog(s, "%d%d %d %d/", - s->ac_pred, s->h263_aic_dir, s->mb_x, s->mb_y); + if (h->c.inter_intra_pred) { + h->c.h263_aic_dir = get_vlc2(&h->gb, ff_inter_intra_vlc, INTER_INTRA_VLC_BITS, 1); + ff_dlog(h->c.avctx, "%d%d %d %d/", + h->c.ac_pred, h->c.h263_aic_dir, h->c.mb_x, h->c.mb_y); } - if(s->per_mb_rl_table && cbp){ - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + if (ms->per_mb_rl_table && cbp) { + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; } } - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); for (i = 0; i < 6; i++) { - if (ff_msmpeg4_decode_block(s, block[i], i, (cbp >> (5 - i)) & 1, NULL) < 0) + if (ff_msmpeg4_decode_block(ms, h->block[i], i, (cbp >> (5 - i)) & 1, NULL) < 0) { - av_log(s->avctx, AV_LOG_ERROR, "\nerror while decoding block: %d x %d (%d)\n", s->mb_x, s->mb_y, i); + av_log(h->c.avctx, AV_LOG_ERROR, "\nerror while decoding block: %d x %d (%d)\n", + h->c.mb_x, h->c.mb_y, i); return -1; } } @@ -300,7 +310,6 @@ static av_cold void msmpeg4_decode_init_static(void) { static VLCElem vlc_buf[3714 + 2694 + 1636 + 2648 + 1532 + 2488]; VLCInitState state = VLC_INIT_STATE(vlc_buf); - MVTable *mv; INIT_FIRST_VLC_RL(ff_rl_table[0], 642); INIT_FIRST_VLC_RL(ff_rl_table[1], 1104); @@ -326,18 +335,16 @@ static av_cold void msmpeg4_decode_init_static(void) &ff_v2_mb_type[0][1], 2, 1, &ff_v2_mb_type[0][0], 2, 1, 0); - mv = &ff_mv_tables[0]; - mv->vlc = ff_vlc_init_tables_sparse(&state, MV_VLC_BITS, - MSMPEG4_MV_TABLES_NB_ELEMS + 1, - mv->table_mv_bits, 1, 1, - mv->table_mv_code, 2, 2, - NULL, 0, 0, 0); - mv = &ff_mv_tables[1]; - mv->vlc = ff_vlc_init_tables_sparse(&state, MV_VLC_BITS, - MSMPEG4_MV_TABLES_NB_ELEMS + 1, - mv->table_mv_bits, 1, 1, - mv->table_mv_code, 2, 2, - NULL, 0, 0, 0); + mv_tables[0] = ff_vlc_init_tables_from_lengths(&state, MV_VLC_BITS, + MSMPEG4_MV_TABLES_NB_ELEMS, + ff_msmp4_mv_table0_lens, 1, + ff_msmp4_mv_table0, 2, 2, + 0, 0); + mv_tables[1] = ff_vlc_init_tables_from_lengths(&state, MV_VLC_BITS, + MSMPEG4_MV_TABLES_NB_ELEMS, + ff_msmp4_mv_table1_lens, 1, + ff_msmp4_mv_table1, 2, 2, + 0, 0); for (unsigned i = 0; i < 4; i++) { ff_mb_non_intra_vlc[i] = @@ -353,42 +360,9 @@ static av_cold void msmpeg4_decode_init_static(void) ff_msmp4_vc1_vlcs_init_once(); } -av_cold int ff_msmpeg4_decode_init(AVCodecContext *avctx) -{ - static AVOnce init_static_once = AV_ONCE_INIT; - MpegEncContext *s = avctx->priv_data; - int ret; - - if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0) - return ret; - - if (ff_h263_decode_init(avctx) < 0) - return -1; - - ff_msmpeg4_common_init(s); - - switch (s->msmpeg4_version) { - case MSMP4_V1: - case MSMP4_V2: - s->decode_mb= msmpeg4v12_decode_mb; - break; - case MSMP4_V3: - case MSMP4_WMV1: - s->decode_mb= msmpeg4v34_decode_mb; - break; - case MSMP4_WMV2: - break; - } - - s->slice_height= s->mb_height; //to avoid 1/0 if the first frame is not a keyframe - - ff_thread_once(&init_static_once, msmpeg4_decode_init_static); - - return 0; -} - -int ff_msmpeg4_decode_picture_header(MpegEncContext * s) +static int msmpeg4_decode_picture_header(H263DecContext *const h) { + MSMP4DecContext *const ms = mpv_to_msmpeg4(h); int code; // at minimum one bit per macroblock is required at least in a valid frame, @@ -396,355 +370,370 @@ int ff_msmpeg4_decode_picture_header(MpegEncContext * s) // smallest "black/skip" frame generally contain not much recoverable content // while at the same time they have the highest computational requirements // per byte - if (get_bits_left(&s->gb) * 8LL < (s->width+15)/16 * ((s->height+15)/16)) + if (get_bits_left(&h->gb) * 8LL < (h->c.width+15)/16 * ((h->c.height+15)/16)) return AVERROR_INVALIDDATA; - if (s->msmpeg4_version == MSMP4_V1) { - int start_code = get_bits_long(&s->gb, 32); + if (h->c.msmpeg4_version == MSMP4_V1) { + int start_code = get_bits_long(&h->gb, 32); if(start_code!=0x00000100){ - av_log(s->avctx, AV_LOG_ERROR, "invalid startcode\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "invalid startcode\n"); return -1; } - skip_bits(&s->gb, 5); // frame number */ + skip_bits(&h->gb, 5); // frame number */ } - s->pict_type = get_bits(&s->gb, 2) + 1; - if (s->pict_type != AV_PICTURE_TYPE_I && - s->pict_type != AV_PICTURE_TYPE_P){ - av_log(s->avctx, AV_LOG_ERROR, "invalid picture type\n"); + h->c.pict_type = get_bits(&h->gb, 2) + 1; + if (h->c.pict_type != AV_PICTURE_TYPE_I && + h->c.pict_type != AV_PICTURE_TYPE_P){ + av_log(h->c.avctx, AV_LOG_ERROR, "invalid picture type\n"); return -1; } - s->chroma_qscale= s->qscale = get_bits(&s->gb, 5); - if(s->qscale==0){ - av_log(s->avctx, AV_LOG_ERROR, "invalid qscale\n"); + h->c.chroma_qscale = h->c.qscale = get_bits(&h->gb, 5); + if (h->c.qscale == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "invalid qscale\n"); return -1; } - if (s->pict_type == AV_PICTURE_TYPE_I) { - code = get_bits(&s->gb, 5); - if (s->msmpeg4_version == MSMP4_V1) { - if(code==0 || code>s->mb_height){ - av_log(s->avctx, AV_LOG_ERROR, "invalid slice height %d\n", code); + if (h->c.pict_type == AV_PICTURE_TYPE_I) { + code = get_bits(&h->gb, 5); + if (h->c.msmpeg4_version == MSMP4_V1) { + if(code==0 || code>h->c.mb_height) { + av_log(h->c.avctx, AV_LOG_ERROR, "invalid slice height %d\n", code); return -1; } - s->slice_height = code; + h->slice_height = code; }else{ /* 0x17: one slice, 0x18: two slices, ... */ if (code < 0x17){ - av_log(s->avctx, AV_LOG_ERROR, "error, slice code was %X\n", code); + av_log(h->c.avctx, AV_LOG_ERROR, "error, slice code was %X\n", code); return -1; } - s->slice_height = s->mb_height / (code - 0x16); + h->slice_height = h->c.mb_height / (code - 0x16); } - switch(s->msmpeg4_version){ + switch (h->c.msmpeg4_version) { case MSMP4_V1: case MSMP4_V2: - s->rl_chroma_table_index = 2; - s->rl_table_index = 2; + ms->rl_chroma_table_index = 2; + ms->rl_table_index = 2; - s->dc_table_index = 0; //not used + ms->dc_table_index = 0; //not used break; case MSMP4_V3: - s->rl_chroma_table_index = decode012(&s->gb); - s->rl_table_index = decode012(&s->gb); + ms->rl_chroma_table_index = decode012(&h->gb); + ms->rl_table_index = decode012(&h->gb); - s->dc_table_index = get_bits1(&s->gb); + ms->dc_table_index = get_bits1(&h->gb); break; case MSMP4_WMV1: - ff_msmpeg4_decode_ext_header(s, (2+5+5+17+7)/8); + ff_msmpeg4_decode_ext_header(h, (2+5+5+17+7)/8); - if(s->bit_rate > MBAC_BITRATE) s->per_mb_rl_table= get_bits1(&s->gb); - else s->per_mb_rl_table= 0; - - if(!s->per_mb_rl_table){ - s->rl_chroma_table_index = decode012(&s->gb); - s->rl_table_index = decode012(&s->gb); - } - - s->dc_table_index = get_bits1(&s->gb); - s->inter_intra_pred= 0; - break; - } - s->no_rounding = 1; - if(s->avctx->debug&FF_DEBUG_PICT_INFO) - av_log(s->avctx, AV_LOG_DEBUG, "qscale:%d rlc:%d rl:%d dc:%d mbrl:%d slice:%d \n", - s->qscale, - s->rl_chroma_table_index, - s->rl_table_index, - s->dc_table_index, - s->per_mb_rl_table, - s->slice_height); - } else { - switch(s->msmpeg4_version){ - case MSMP4_V1: - case MSMP4_V2: - if (s->msmpeg4_version == MSMP4_V1) - s->use_skip_mb_code = 1; + if (ms->bit_rate > MBAC_BITRATE) + ms->per_mb_rl_table = get_bits1(&h->gb); else - s->use_skip_mb_code = get_bits1(&s->gb); - s->rl_table_index = 2; - s->rl_chroma_table_index = s->rl_table_index; - s->dc_table_index = 0; //not used - s->mv_table_index = 0; - break; - case MSMP4_V3: - s->use_skip_mb_code = get_bits1(&s->gb); - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + ms->per_mb_rl_table = 0; - s->dc_table_index = get_bits1(&s->gb); - - s->mv_table_index = get_bits1(&s->gb); - break; - case MSMP4_WMV1: - s->use_skip_mb_code = get_bits1(&s->gb); - - if(s->bit_rate > MBAC_BITRATE) s->per_mb_rl_table= get_bits1(&s->gb); - else s->per_mb_rl_table= 0; - - if(!s->per_mb_rl_table){ - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + if (!ms->per_mb_rl_table) { + ms->rl_chroma_table_index = decode012(&h->gb); + ms->rl_table_index = decode012(&h->gb); } - s->dc_table_index = get_bits1(&s->gb); - - s->mv_table_index = get_bits1(&s->gb); - s->inter_intra_pred= (s->width*s->height < 320*240 && s->bit_rate<=II_BITRATE); + ms->dc_table_index = get_bits1(&h->gb); + h->c.inter_intra_pred= 0; break; + default: + av_unreachable("msmpeg4_decode_picture_header() only used by MSMP4V1-3, WMV1"); + } + h->c.no_rounding = 1; + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) + av_log(h->c.avctx, AV_LOG_DEBUG, "qscale:%d rlc:%d rl:%d dc:%d mbrl:%d slice:%d \n", + h->c.qscale, + ms->rl_chroma_table_index, + ms->rl_table_index, + ms->dc_table_index, + ms->per_mb_rl_table, + h->slice_height); + } else { + switch (h->c.msmpeg4_version) { + case MSMP4_V1: + case MSMP4_V2: + if (h->c.msmpeg4_version == MSMP4_V1) + ms->use_skip_mb_code = 1; + else + ms->use_skip_mb_code = get_bits1(&h->gb); + ms->rl_table_index = 2; + ms->rl_chroma_table_index = ms->rl_table_index; + ms->dc_table_index = 0; //not used + ms->mv_table_index = 0; + break; + case MSMP4_V3: + ms->use_skip_mb_code = get_bits1(&h->gb); + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; + + ms->dc_table_index = get_bits1(&h->gb); + + ms->mv_table_index = get_bits1(&h->gb); + break; + case MSMP4_WMV1: + ms->use_skip_mb_code = get_bits1(&h->gb); + + if (ms->bit_rate > MBAC_BITRATE) + ms->per_mb_rl_table = get_bits1(&h->gb); + else + ms->per_mb_rl_table = 0; + + if (!ms->per_mb_rl_table) { + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; + } + + ms->dc_table_index = get_bits1(&h->gb); + + ms->mv_table_index = get_bits1(&h->gb); + h->c.inter_intra_pred = h->c.width*h->c.height < 320*240 && + ms->bit_rate <= II_BITRATE; + break; + default: + av_unreachable("msmpeg4_decode_picture_header() only used by MSMP4V1-3, WMV1"); } - if(s->avctx->debug&FF_DEBUG_PICT_INFO) - av_log(s->avctx, AV_LOG_DEBUG, "skip:%d rl:%d rlc:%d dc:%d mv:%d mbrl:%d qp:%d \n", - s->use_skip_mb_code, - s->rl_table_index, - s->rl_chroma_table_index, - s->dc_table_index, - s->mv_table_index, - s->per_mb_rl_table, - s->qscale); + if (h->c.avctx->debug&FF_DEBUG_PICT_INFO) + av_log(h->c.avctx, AV_LOG_DEBUG, "skip:%d rl:%d rlc:%d dc:%d mv:%d mbrl:%d qp:%d \n", + ms->use_skip_mb_code, + ms->rl_table_index, + ms->rl_chroma_table_index, + ms->dc_table_index, + ms->mv_table_index, + ms->per_mb_rl_table, + h->c.qscale); - if(s->flipflop_rounding){ - s->no_rounding ^= 1; + if (ms->flipflop_rounding) { + h->c.no_rounding ^= 1; }else{ - s->no_rounding = 0; + h->c.no_rounding = 0; } } - ff_dlog(s->avctx, "%d %"PRId64" %d %d %d\n", s->pict_type, s->bit_rate, - s->inter_intra_pred, s->width, s->height); + ff_dlog(h->c.avctx, "%d %d %d %d %d\n", h->c.pict_type, ms->bit_rate, + h->c.inter_intra_pred, h->c.width, h->c.height); - s->esc3_level_length= 0; - s->esc3_run_length= 0; + ms->esc3_level_length = 0; + ms->esc3_run_length = 0; return 0; } -int ff_msmpeg4_decode_ext_header(MpegEncContext * s, int buf_size) +int ff_msmpeg4_decode_ext_header(H263DecContext *const h, int buf_size) { - int left= buf_size*8 - get_bits_count(&s->gb); - int length = s->msmpeg4_version >= MSMP4_V3 ? 17 : 16; + MSMP4DecContext *const ms = mpv_to_msmpeg4(h); + int left = buf_size*8 - get_bits_count(&h->gb); + int length = h->c.msmpeg4_version >= MSMP4_V3 ? 17 : 16; /* the alt_bitstream reader could read over the end so we need to check it */ if(left>=length && leftgb, 5); /* fps */ - s->bit_rate= get_bits(&s->gb, 11)*1024; - if (s->msmpeg4_version >= MSMP4_V3) - s->flipflop_rounding= get_bits1(&s->gb); + skip_bits(&h->gb, 5); /* fps */ + ms->bit_rate = get_bits(&h->gb, 11) * 1024; + if (h->c.msmpeg4_version >= MSMP4_V3) + ms->flipflop_rounding = get_bits1(&h->gb); else - s->flipflop_rounding= 0; + ms->flipflop_rounding = 0; } else if(leftflipflop_rounding= 0; - if (s->msmpeg4_version != MSMP4_V2) - av_log(s->avctx, AV_LOG_ERROR, "ext header missing, %d left\n", left); + ms->flipflop_rounding = 0; + if (h->c.msmpeg4_version != MSMP4_V2) + av_log(h->c.avctx, AV_LOG_ERROR, "ext header missing, %d left\n", left); } else { - av_log(s->avctx, AV_LOG_ERROR, "I-frame too long, ignoring ext header\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "I-frame too long, ignoring ext header\n"); } return 0; } -static int msmpeg4_decode_dc(MpegEncContext * s, int n, int *dir_ptr) +static int msmpeg4_decode_dc(MSMP4DecContext *const ms, int n, int *dir_ptr) { + H263DecContext *const h = &ms->h; int level, pred; - if (s->msmpeg4_version <= MSMP4_V2) { + if (h->c.msmpeg4_version <= MSMP4_V2) { if (n < 4) { - level = get_vlc2(&s->gb, v2_dc_lum_vlc, MSMP4_DC_VLC_BITS, 3); + level = get_vlc2(&h->gb, v2_dc_lum_vlc, MSMP4_DC_VLC_BITS, 3); } else { - level = get_vlc2(&s->gb, v2_dc_chroma_vlc, MSMP4_DC_VLC_BITS, 3); + level = get_vlc2(&h->gb, v2_dc_chroma_vlc, MSMP4_DC_VLC_BITS, 3); } if (level < 0) { - av_log(s->avctx, AV_LOG_ERROR, "illegal dc vlc\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal dc vlc\n"); *dir_ptr = 0; return -1; } level-=256; } else { - level = get_vlc2(&s->gb, ff_msmp4_dc_vlc[s->dc_table_index][n >= 4], + level = get_vlc2(&h->gb, ff_msmp4_dc_vlc[ms->dc_table_index][n >= 4], MSMP4_DC_VLC_BITS, 3); if (level == DC_MAX) { - level = get_bits(&s->gb, 8); - if (get_bits1(&s->gb)) + level = get_bits(&h->gb, 8); + if (get_bits1(&h->gb)) level = -level; } else if (level != 0) { - if (get_bits1(&s->gb)) + if (get_bits1(&h->gb)) level = -level; } } - if (s->msmpeg4_version == MSMP4_V1) { + if (h->c.msmpeg4_version == MSMP4_V1) { int32_t *dc_val; - pred = msmpeg4v1_pred_dc(s, n, &dc_val); + pred = msmpeg4v1_pred_dc(h, n, &dc_val); level += pred; /* update predictor */ *dc_val= level; }else{ int16_t *dc_val; - pred = ff_msmpeg4_pred_dc(s, n, &dc_val, dir_ptr); + pred = ff_msmpeg4_pred_dc(&h->c, n, &dc_val, dir_ptr); level += pred; /* update predictor */ if (n < 4) { - *dc_val = level * s->y_dc_scale; + *dc_val = level * h->c.y_dc_scale; } else { - *dc_val = level * s->c_dc_scale; + *dc_val = level * h->c.c_dc_scale; } } return level; } -int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, +int ff_msmpeg4_decode_block(MSMP4DecContext *const ms, int16_t * block, int n, int coded, const uint8_t *scan_table) { + H263DecContext *const h = &ms->h; int level, i, last, run, run_diff; int dc_pred_dir = -1; //unused but its passed around, so it needs to be initialized const RLTable *rl; const RL_VLC_ELEM *rl_vlc; int qmul, qadd; - if (s->mb_intra) { + if (h->c.mb_intra) { qmul=1; qadd=0; /* DC coef */ - level = msmpeg4_decode_dc(s, n, &dc_pred_dir); + level = msmpeg4_decode_dc(ms, n, &dc_pred_dir); if (level < 0){ - av_log(s->avctx, AV_LOG_ERROR, "dc overflow- block: %d qscale: %d//\n", n, s->qscale); - if(s->inter_intra_pred) level=0; + av_log(h->c.avctx, AV_LOG_ERROR, "dc overflow- block: %d qscale: %d//\n", n, h->c.qscale); + if (h->c.inter_intra_pred) + level = 0; } if (n < 4) { - rl = &ff_rl_table[s->rl_table_index]; - if(level > 256*s->y_dc_scale){ - av_log(s->avctx, AV_LOG_ERROR, "dc overflow+ L qscale: %d//\n", s->qscale); - if(!s->inter_intra_pred) return -1; + rl = &ff_rl_table[ms->rl_table_index]; + if (level > 256 * h->c.y_dc_scale) { + av_log(h->c.avctx, AV_LOG_ERROR, "dc overflow+ L qscale: %d//\n", h->c.qscale); + if (!h->c.inter_intra_pred) + return -1; } } else { - rl = &ff_rl_table[3 + s->rl_chroma_table_index]; - if(level > 256*s->c_dc_scale){ - av_log(s->avctx, AV_LOG_ERROR, "dc overflow+ C qscale: %d//\n", s->qscale); - if(!s->inter_intra_pred) return -1; + rl = &ff_rl_table[3 + ms->rl_chroma_table_index]; + if (level > 256 * h->c.c_dc_scale) { + av_log(h->c.avctx, AV_LOG_ERROR, "dc overflow+ C qscale: %d//\n", h->c.qscale); + if (!h->c.inter_intra_pred) + return -1; } } block[0] = level; - run_diff = s->msmpeg4_version >= MSMP4_WMV1; + run_diff = h->c.msmpeg4_version >= MSMP4_WMV1; i = 0; if (!coded) { goto not_coded; } - if (s->ac_pred) { + if (h->c.ac_pred) { if (dc_pred_dir == 0) - scan_table = s->permutated_intra_v_scantable; /* left */ + scan_table = h->permutated_intra_v_scantable; /* left */ else - scan_table = s->permutated_intra_h_scantable; /* top */ + scan_table = h->permutated_intra_h_scantable; /* top */ } else { - scan_table = s->intra_scantable.permutated; + scan_table = h->c.intra_scantable.permutated; } rl_vlc= rl->rl_vlc[0]; } else { - qmul = s->qscale << 1; - qadd = (s->qscale - 1) | 1; + qmul = h->c.qscale << 1; + qadd = (h->c.qscale - 1) | 1; i = -1; - rl = &ff_rl_table[3 + s->rl_table_index]; + rl = &ff_rl_table[3 + ms->rl_table_index]; - if (s->msmpeg4_version == MSMP4_V2) + if (h->c.msmpeg4_version == MSMP4_V2) run_diff = 0; else run_diff = 1; if (!coded) { - s->block_last_index[n] = i; + h->c.block_last_index[n] = i; return 0; } if(!scan_table) - scan_table = s->inter_scantable.permutated; - rl_vlc= rl->rl_vlc[s->qscale]; + scan_table = h->c.inter_scantable.permutated; + rl_vlc= rl->rl_vlc[h->c.qscale]; } { - OPEN_READER(re, &s->gb); + OPEN_READER(re, &h->gb); for(;;) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 0); + UPDATE_CACHE(re, &h->gb); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 0); if (level==0) { int cache; - cache= GET_CACHE(re, &s->gb); + cache= GET_CACHE(re, &h->gb); /* escape */ - if (s->msmpeg4_version == MSMP4_V1 || (cache&0x80000000)==0) { - if (s->msmpeg4_version == MSMP4_V1 || (cache&0x40000000)==0) { + if (h->c.msmpeg4_version == MSMP4_V1 || (cache&0x80000000)==0) { + if (h->c.msmpeg4_version == MSMP4_V1 || (cache&0x40000000)==0) { /* third escape */ - if (s->msmpeg4_version != MSMP4_V1) - LAST_SKIP_BITS(re, &s->gb, 2); - UPDATE_CACHE(re, &s->gb); - if (s->msmpeg4_version <= MSMP4_V3) { - last= SHOW_UBITS(re, &s->gb, 1); SKIP_CACHE(re, &s->gb, 1); - run= SHOW_UBITS(re, &s->gb, 6); SKIP_CACHE(re, &s->gb, 6); - level= SHOW_SBITS(re, &s->gb, 8); - SKIP_COUNTER(re, &s->gb, 1+6+8); + if (h->c.msmpeg4_version != MSMP4_V1) + LAST_SKIP_BITS(re, &h->gb, 2); + UPDATE_CACHE(re, &h->gb); + if (h->c.msmpeg4_version <= MSMP4_V3) { + last = SHOW_UBITS(re, &h->gb, 1); SKIP_CACHE(re, &h->gb, 1); + run = SHOW_UBITS(re, &h->gb, 6); SKIP_CACHE(re, &h->gb, 6); + level = SHOW_SBITS(re, &h->gb, 8); + SKIP_COUNTER(re, &h->gb, 1 + 6 + 8); }else{ int sign; - last= SHOW_UBITS(re, &s->gb, 1); SKIP_BITS(re, &s->gb, 1); - if(!s->esc3_level_length){ + last = SHOW_UBITS(re, &h->gb, 1); SKIP_BITS(re, &h->gb, 1); + if (!ms->esc3_level_length) { int ll; - ff_dlog(s->avctx, "ESC-3 %X at %d %d\n", - show_bits(&s->gb, 24), s->mb_x, s->mb_y); - if(s->qscale<8){ - ll= SHOW_UBITS(re, &s->gb, 3); SKIP_BITS(re, &s->gb, 3); + ff_dlog(h->c.avctx, "ESC-3 %X at %d %d\n", + show_bits(&h->gb, 24), h->c.mb_x, h->c.mb_y); + if (h->c.qscale < 8) { + ll = SHOW_UBITS(re, &h->gb, 3); SKIP_BITS(re, &h->gb, 3); if(ll==0){ - ll= 8+SHOW_UBITS(re, &s->gb, 1); SKIP_BITS(re, &s->gb, 1); + ll = 8+SHOW_UBITS(re, &h->gb, 1); SKIP_BITS(re, &h->gb, 1); } }else{ ll=2; - while(ll<8 && SHOW_UBITS(re, &s->gb, 1)==0){ + while (ll < 8 && SHOW_UBITS(re, &h->gb, 1) == 0) { ll++; - SKIP_BITS(re, &s->gb, 1); + SKIP_BITS(re, &h->gb, 1); } - if(ll<8) SKIP_BITS(re, &s->gb, 1); + if (ll<8) SKIP_BITS(re, &h->gb, 1); } - s->esc3_level_length= ll; - s->esc3_run_length= SHOW_UBITS(re, &s->gb, 2) + 3; SKIP_BITS(re, &s->gb, 2); - UPDATE_CACHE(re, &s->gb); + ms->esc3_level_length = ll; + ms->esc3_run_length = SHOW_UBITS(re, &h->gb, 2) + 3; SKIP_BITS(re, &h->gb, 2); + UPDATE_CACHE(re, &h->gb); } - run= SHOW_UBITS(re, &s->gb, s->esc3_run_length); - SKIP_BITS(re, &s->gb, s->esc3_run_length); + run = SHOW_UBITS(re, &h->gb, ms->esc3_run_length); + SKIP_BITS(re, &h->gb, ms->esc3_run_length); - sign= SHOW_UBITS(re, &s->gb, 1); - SKIP_BITS(re, &s->gb, 1); + sign= SHOW_UBITS(re, &h->gb, 1); + SKIP_BITS(re, &h->gb, 1); - level= SHOW_UBITS(re, &s->gb, s->esc3_level_length); - SKIP_BITS(re, &s->gb, s->esc3_level_length); + level = SHOW_UBITS(re, &h->gb, ms->esc3_level_length); + SKIP_BITS(re, &h->gb, ms->esc3_level_length); if(sign) level= -level; } @@ -755,38 +744,40 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, if(last) i+=192; } else { /* second escape */ - SKIP_BITS(re, &s->gb, 2); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 1); + SKIP_BITS(re, &h->gb, 2); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 1); i+= run + rl->max_run[run>>7][level/qmul] + run_diff; //FIXME opt indexing - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } } else { /* first escape */ - SKIP_BITS(re, &s->gb, 1); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 1); + SKIP_BITS(re, &h->gb, 1); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 1); i+= run; level = level + rl->max_level[run>>7][(run-1)&63] * qmul;//FIXME opt indexing - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } } else { i+= run; - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } if (i > 62){ i-= 192; if(i&(~63)){ - const int left= get_bits_left(&s->gb); + const int left = get_bits_left(&h->gb); if (((i + 192 == 64 && level / qmul == -1) || - !(s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))) && + !(h->c.avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))) && left >= 0) { - av_log(s->avctx, AV_LOG_ERROR, "ignoring overflow at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "ignoring overflow at %d %d\n", + h->c.mb_x, h->c.mb_y); i = 63; break; }else{ - av_log(s->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return -1; } } @@ -797,35 +788,31 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, block[scan_table[i]] = level; } - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); } + if (h->c.mb_intra) { not_coded: - if (s->mb_intra) { - ff_mpeg4_pred_ac(s, block, n, dc_pred_dir); - if (s->ac_pred) { - i = 63; /* XXX: not optimal */ - } + ff_mpeg4_pred_ac(h, block, n, dc_pred_dir); } - if (s->msmpeg4_version >= MSMP4_WMV1 && i > 0) i=63; //FIXME/XXX optimize - s->block_last_index[n] = i; + h->c.block_last_index[n] = i; return 0; } -void ff_msmpeg4_decode_motion(MpegEncContext *s, int *mx_ptr, int *my_ptr) +void ff_msmpeg4_decode_motion(MSMP4DecContext *const ms, int *mx_ptr, int *my_ptr) { - const MVTable *mv; - int code, mx, my; + const VLCElem *const mv_vlc = mv_tables[ms->mv_table_index]; + H263DecContext *const h = &ms->h; + int sym, mx, my; - mv = &ff_mv_tables[s->mv_table_index]; - - code = get_vlc2(&s->gb, mv->vlc, MV_VLC_BITS, 2); - if (code == MSMPEG4_MV_TABLES_NB_ELEMS) { - mx = get_bits(&s->gb, 6); - my = get_bits(&s->gb, 6); + sym = get_vlc2(&h->gb, mv_vlc, MV_VLC_BITS, 2); + if (sym) { + mx = sym >> 8; + my = sym & 0xFF; } else { - mx = mv->table_mvx[code]; - my = mv->table_mvy[code]; + /* Escape */ + mx = get_bits(&h->gb, 6); + my = get_bits(&h->gb, 6); } mx += *mx_ptr - 32; @@ -844,12 +831,55 @@ void ff_msmpeg4_decode_motion(MpegEncContext *s, int *mx_ptr, int *my_ptr) *my_ptr = my; } +av_cold int ff_msmpeg4_decode_init(AVCodecContext *avctx) +{ + static AVOnce init_static_once = AV_ONCE_INIT; + H263DecContext *const h = avctx->priv_data; + int ret; + + ret = av_image_check_size(avctx->width, avctx->height, 0, avctx); + if (ret < 0) + return ret; + + if (ff_h263_decode_init(avctx) < 0) + return -1; + + // We unquantize inter blocks as we parse them. + h->c.dct_unquantize_inter = NULL; + + h->decode_header = msmpeg4_decode_picture_header; + + ff_msmpeg4_common_init(&h->c, h->permutated_intra_h_scantable, + h->permutated_intra_v_scantable); + + switch (h->c.msmpeg4_version) { + case MSMP4_V1: + case MSMP4_V2: + h->decode_mb = msmpeg4v12_decode_mb; + break; + case MSMP4_V3: + case MSMP4_WMV1: + h->decode_mb = msmpeg4v34_decode_mb; + break; + case MSMP4_WMV2: + break; + default: + av_unreachable("List contains all cases using ff_msmpeg4_decode_init()"); + } + + h->slice_height = h->c.mb_height; //to avoid 1/0 if the first frame is not a keyframe + + ff_thread_once(&init_static_once, msmpeg4_decode_init_static); + + return 0; +} + const FFCodec ff_msmpeg4v1_decoder = { .p.name = "msmpeg4v1", CODEC_LONG_NAME("MPEG-4 part 2 Microsoft variant version 1"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MSMPEG4V1, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MSMP4DecContext), .init = ff_msmpeg4_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, @@ -864,7 +894,7 @@ const FFCodec ff_msmpeg4v2_decoder = { CODEC_LONG_NAME("MPEG-4 part 2 Microsoft variant version 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MSMPEG4V2, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MSMP4DecContext), .init = ff_msmpeg4_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, @@ -879,7 +909,7 @@ const FFCodec ff_msmpeg4v3_decoder = { CODEC_LONG_NAME("MPEG-4 part 2 Microsoft variant version 3"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MSMPEG4V3, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MSMP4DecContext), .init = ff_msmpeg4_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, @@ -894,7 +924,7 @@ const FFCodec ff_wmv1_decoder = { CODEC_LONG_NAME("Windows Media Video 7"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_WMV1, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MSMP4DecContext), .init = ff_msmpeg4_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, diff --git a/libavcodec/msmpeg4dec.h b/libavcodec/msmpeg4dec.h index 5daa7c6bc..e0fb3cf48 100644 --- a/libavcodec/msmpeg4dec.h +++ b/libavcodec/msmpeg4dec.h @@ -23,19 +23,39 @@ #define AVCODEC_MSMPEG4DEC_H #include "avcodec.h" +#include "h263dec.h" #include "mpegvideo.h" #define INTER_INTRA_VLC_BITS 3 #define MB_NON_INTRA_VLC_BITS 9 +typedef struct MSMP4DecContext { + H263DecContext h; + int bit_rate; + int flipflop_rounding; + int mv_table_index; + int rl_table_index; + int rl_chroma_table_index; + int dc_table_index; + int use_skip_mb_code; + int per_mb_rl_table; + int esc3_level_length; + int esc3_run_length; +} MSMP4DecContext; + +static inline MSMP4DecContext *mpv_to_msmpeg4(H263DecContext *const h) +{ + // Only legal because no MSMPEG-4 decoder uses slice-threading. + return (MSMP4DecContext*)h; +} + extern const VLCElem *ff_mb_non_intra_vlc[4]; extern VLCElem ff_inter_intra_vlc[8]; int ff_msmpeg4_decode_init(AVCodecContext *avctx); -int ff_msmpeg4_decode_picture_header(MpegEncContext *s); -int ff_msmpeg4_decode_ext_header(MpegEncContext *s, int buf_size); -void ff_msmpeg4_decode_motion(MpegEncContext * s, int *mx_ptr, int *my_ptr); -int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, +int ff_msmpeg4_decode_ext_header(H263DecContext *const h, int buf_size); +void ff_msmpeg4_decode_motion(MSMP4DecContext *ms, int *mx_ptr, int *my_ptr); +int ff_msmpeg4_decode_block(MSMP4DecContext *ms, int16_t * block, int n, int coded, const uint8_t *scan_table); #endif diff --git a/libavcodec/msmpeg4enc.c b/libavcodec/msmpeg4enc.c index 5ce4e6e30..6141c63e1 100644 --- a/libavcodec/msmpeg4enc.c +++ b/libavcodec/msmpeg4enc.c @@ -30,6 +30,8 @@ #include #include +#define NO_SLICE_THREADING_HERE + #include "libavutil/attributes.h" #include "libavutil/avutil.h" #include "libavutil/thread.h" @@ -48,22 +50,32 @@ static uint8_t rl_length[NB_RL_TABLES][MAX_LEVEL+1][MAX_RUN+1][2]; +// The lowest 8 bits of each entry are length, the other bits are the code. +// The index of the (mx, my) entry is (mx * 64) + my. +static uint32_t mv_vector_tables[2][4096]; + /* build the table which associate a (x,y) motion vector to a vlc */ -static av_cold void init_mv_table(MVTable *tab, uint16_t table_mv_index[4096]) +static av_cold void init_mv_table(const uint16_t mv_table[], const uint8_t mv_table_lens[], + uint32_t mv_vector_table[4096], + unsigned escape_code, int escape_length) { - int i, x, y; - - tab->table_mv_index = table_mv_index; - - /* mark all entries as not used */ - for(i=0;i<4096;i++) - tab->table_mv_index[i] = MSMPEG4_MV_TABLES_NB_ELEMS; - - for (i = 0; i < MSMPEG4_MV_TABLES_NB_ELEMS; i++) { - x = tab->table_mvx[i]; - y = tab->table_mvy[i]; - tab->table_mv_index[(x << 6) | y] = i; + for (int i = 0; i < 4096; i++) { + // Initialize to the table to "escaped". This code is equivalent to + // the following double loop (with x and y ranging over 0..63): + // tab[x * 64 + y] = (esc_code << 20) | (x << 14) | (y << 8) | esc_length + mv_vector_table[i] = (escape_code << 20) | (i << 8) | escape_length; } + + for (uint32_t i = 0, code = 0; i < MSMPEG4_MV_TABLES_NB_ELEMS; i++) { + int sym = mv_table[i]; + int len = mv_table_lens[i]; + int x = sym >> 8; + int y = sym & 0xFF; + // We ignore the escape value here and restore it after the loop. + mv_vector_table[(x << 6) | y] = (code >> (24 - len)) | len; + code += 1U << (32 - len); + } + mv_vector_table[0] = (escape_code << 20) | escape_length; } void ff_msmpeg4_code012(PutBitContext *pb, int n) @@ -120,9 +132,10 @@ static int get_size_of_code(const RLTable *rl, int last, int run, static av_cold void msmpeg4_encode_init_static(void) { - static uint16_t mv_index_tables[2][4096]; - init_mv_table(&ff_mv_tables[0], mv_index_tables[0]); - init_mv_table(&ff_mv_tables[1], mv_index_tables[1]); + init_mv_table(ff_msmp4_mv_table0, ff_msmp4_mv_table0_lens, + mv_vector_tables[0], 0x0000, 8 + 12); + init_mv_table(ff_msmp4_mv_table1, ff_msmp4_mv_table1_lens, + mv_vector_tables[1], 0x000b, 4 + 12); for (int i = 0; i < NB_RL_TABLES; i++) { for (int level = 1; level <= MAX_LEVEL; level++) { @@ -135,23 +148,9 @@ static av_cold void msmpeg4_encode_init_static(void) } } -av_cold void ff_msmpeg4_encode_init(MpegEncContext *s) -{ - static AVOnce init_static_once = AV_ONCE_INIT; - - ff_msmpeg4_common_init(s); - if (s->msmpeg4_version >= MSMP4_WMV1) { - s->min_qcoeff = -255; - s->max_qcoeff = 255; - } - - /* init various encoding tables */ - ff_thread_once(&init_static_once, msmpeg4_encode_init_static); -} - static void find_best_tables(MSMPEG4EncContext *ms) { - MpegEncContext *const s = &ms->s; + MPVEncContext *const s = &ms->m.s; int i; int best = 0, best_size = INT_MAX; int chroma_best = 0, best_chroma_size = INT_MAX; @@ -175,7 +174,7 @@ static void find_best_tables(MSMPEG4EncContext *ms) int intra_luma_count = ms->ac_stats[1][0][level][run][last]; int intra_chroma_count= ms->ac_stats[1][1][level][run][last]; - if(s->pict_type==AV_PICTURE_TYPE_I){ + if (s->c.pict_type == AV_PICTURE_TYPE_I) { size += intra_luma_count *rl_length[i ][level][run][last]; chroma_size+= intra_chroma_count*rl_length[i+3][level][run][last]; }else{ @@ -197,117 +196,119 @@ static void find_best_tables(MSMPEG4EncContext *ms) } } - if(s->pict_type==AV_PICTURE_TYPE_P) chroma_best= best; + if (s->c.pict_type == AV_PICTURE_TYPE_P) chroma_best = best; memset(ms->ac_stats, 0, sizeof(ms->ac_stats)); - s->rl_table_index = best; - s->rl_chroma_table_index= chroma_best; + ms->rl_table_index = best; + ms->rl_chroma_table_index = chroma_best; - if(s->pict_type != s->last_non_b_pict_type){ - s->rl_table_index= 2; - if(s->pict_type==AV_PICTURE_TYPE_I) - s->rl_chroma_table_index= 1; + if (s->c.pict_type != ms->m.last_non_b_pict_type) { + ms->rl_table_index= 2; + if (s->c.pict_type == AV_PICTURE_TYPE_I) + ms->rl_chroma_table_index = 1; else - s->rl_chroma_table_index= 2; + ms->rl_chroma_table_index = 2; } } /* write MSMPEG4 compatible frame header */ -void ff_msmpeg4_encode_picture_header(MpegEncContext * s) +static int msmpeg4_encode_picture_header(MPVMainEncContext *const m) { - MSMPEG4EncContext *const ms = (MSMPEG4EncContext*)s; + MSMPEG4EncContext *const ms = (MSMPEG4EncContext*)m; + MPVEncContext *const s = &m->s; find_best_tables(ms); - align_put_bits(&s->pb); - put_bits(&s->pb, 2, s->pict_type - 1); + put_bits_assume_flushed(&s->pb); - put_bits(&s->pb, 5, s->qscale); - if (s->msmpeg4_version <= MSMP4_V2) { - s->rl_table_index = 2; - s->rl_chroma_table_index = 2; + put_bits(&s->pb, 2, s->c.pict_type - 1); + + put_bits(&s->pb, 5, s->c.qscale); + if (s->c.msmpeg4_version <= MSMP4_V2) { + ms->rl_table_index = 2; + ms->rl_chroma_table_index = 2; } - s->dc_table_index = 1; - s->mv_table_index = 1; /* only if P-frame */ - s->use_skip_mb_code = 1; /* only if P-frame */ - s->per_mb_rl_table = 0; - if (s->msmpeg4_version == MSMP4_WMV1) - s->inter_intra_pred= (s->width*s->height < 320*240 && s->bit_rate<=II_BITRATE && s->pict_type==AV_PICTURE_TYPE_P); - ff_dlog(s, "%d %"PRId64" %d %d %d\n", s->pict_type, s->bit_rate, - s->inter_intra_pred, s->width, s->height); + ms->dc_table_index = 1; + ms->mv_table_index = 1; /* only if P-frame */ + ms->use_skip_mb_code = 1; /* only if P-frame */ + ms->per_mb_rl_table = 0; + if (s->c.msmpeg4_version == MSMP4_WMV1) + s->c.inter_intra_pred = s->c.width * s->c.height < 320*240 && + m->bit_rate <= II_BITRATE && + s->c.pict_type == AV_PICTURE_TYPE_P; + ff_dlog(s->c.avctx, "%d %"PRId64" %d %d %d\n", s->c.pict_type, m->bit_rate, + s->c.inter_intra_pred, s->c.width, s->c.height); - if (s->pict_type == AV_PICTURE_TYPE_I) { - s->slice_height= s->mb_height/1; - put_bits(&s->pb, 5, 0x16 + s->mb_height/s->slice_height); + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + s->slice_height = s->c.mb_height/1; + put_bits(&s->pb, 5, 0x16 + s->c.mb_height / s->slice_height); - if (s->msmpeg4_version == MSMP4_WMV1) { + if (s->c.msmpeg4_version == MSMP4_WMV1) { ff_msmpeg4_encode_ext_header(s); - if(s->bit_rate>MBAC_BITRATE) - put_bits(&s->pb, 1, s->per_mb_rl_table); + if (m->bit_rate > MBAC_BITRATE) + put_bits(&s->pb, 1, ms->per_mb_rl_table); } - if (s->msmpeg4_version > MSMP4_V2) { - if(!s->per_mb_rl_table){ - ff_msmpeg4_code012(&s->pb, s->rl_chroma_table_index); - ff_msmpeg4_code012(&s->pb, s->rl_table_index); + if (s->c.msmpeg4_version > MSMP4_V2) { + if (!ms->per_mb_rl_table){ + ff_msmpeg4_code012(&s->pb, ms->rl_chroma_table_index); + ff_msmpeg4_code012(&s->pb, ms->rl_table_index); } - put_bits(&s->pb, 1, s->dc_table_index); + put_bits(&s->pb, 1, ms->dc_table_index); } } else { - put_bits(&s->pb, 1, s->use_skip_mb_code); + put_bits(&s->pb, 1, ms->use_skip_mb_code); - if (s->msmpeg4_version == MSMP4_WMV1 && s->bit_rate > MBAC_BITRATE) - put_bits(&s->pb, 1, s->per_mb_rl_table); + if (s->c.msmpeg4_version == MSMP4_WMV1 && m->bit_rate > MBAC_BITRATE) + put_bits(&s->pb, 1, ms->per_mb_rl_table); - if (s->msmpeg4_version > MSMP4_V2) { - if(!s->per_mb_rl_table) - ff_msmpeg4_code012(&s->pb, s->rl_table_index); + if (s->c.msmpeg4_version > MSMP4_V2) { + if (!ms->per_mb_rl_table) + ff_msmpeg4_code012(&s->pb, ms->rl_table_index); - put_bits(&s->pb, 1, s->dc_table_index); + put_bits(&s->pb, 1, ms->dc_table_index); - put_bits(&s->pb, 1, s->mv_table_index); + put_bits(&s->pb, 1, ms->mv_table_index); } } - s->esc3_level_length= 0; - s->esc3_run_length= 0; + s->esc3_level_length = 0; + ms->esc3_run_length = 0; + + return 0; } -void ff_msmpeg4_encode_ext_header(MpegEncContext * s) +void ff_msmpeg4_encode_ext_header(MPVEncContext *const s) { + const MPVMainEncContext *const m = slice_to_mainenc(s); unsigned fps; - if (s->avctx->framerate.num > 0 && s->avctx->framerate.den > 0) - fps = s->avctx->framerate.num / s->avctx->framerate.den; + if (s->c.avctx->framerate.num > 0 && s->c.avctx->framerate.den > 0) + fps = s->c.avctx->framerate.num / s->c.avctx->framerate.den; else { -FF_DISABLE_DEPRECATION_WARNINGS - fps = s->avctx->time_base.den / s->avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - / FFMAX(s->avctx->ticks_per_frame, 1) -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + fps = s->c.avctx->time_base.den / s->c.avctx->time_base.num; } put_bits(&s->pb, 5, FFMIN(fps, 31)); //yes 29.97 -> 29 - put_bits(&s->pb, 11, FFMIN(s->bit_rate / 1024, 2047)); + put_bits(&s->pb, 11, FFMIN(m->bit_rate / 1024, 2047)); - if (s->msmpeg4_version >= MSMP4_V3) + if (s->c.msmpeg4_version >= MSMP4_V3) put_bits(&s->pb, 1, s->flipflop_rounding); else av_assert0(!s->flipflop_rounding); } -void ff_msmpeg4_encode_motion(MpegEncContext * s, +void ff_msmpeg4_encode_motion(MSMPEG4EncContext *const ms, int mx, int my) { - int code; - MVTable *mv; + MPVEncContext *const s = &ms->m.s; + const uint32_t *const mv_vector_table = mv_vector_tables[ms->mv_table_index]; + uint32_t code; /* modulo encoding */ /* WARNING : you cannot reach all the MVs even with the modulo @@ -323,40 +324,31 @@ void ff_msmpeg4_encode_motion(MpegEncContext * s, mx += 32; my += 32; - mv = &ff_mv_tables[s->mv_table_index]; - code = mv->table_mv_index[(mx << 6) | my]; - put_bits(&s->pb, - mv->table_mv_bits[code], - mv->table_mv_code[code]); - if (code == MSMPEG4_MV_TABLES_NB_ELEMS) { - /* escape : code literally */ - put_bits(&s->pb, 6, mx); - put_bits(&s->pb, 6, my); - } + code = mv_vector_table[(mx << 6) | my]; + put_bits(&s->pb, code & 0xff, code >> 8); } -void ff_msmpeg4_handle_slices(MpegEncContext *s){ - if (s->mb_x == 0) { - if (s->slice_height && (s->mb_y % s->slice_height) == 0) { - if (s->msmpeg4_version < MSMP4_WMV1) { - ff_mpeg4_clean_buffers(s); - } - s->first_slice_line = 1; +void ff_msmpeg4_handle_slices(MPVEncContext *const s) +{ + if (s->c.mb_x == 0) { + if (s->slice_height && (s->c.mb_y % s->slice_height) == 0) { + if (s->c.msmpeg4_version < MSMP4_WMV1) + ff_mpeg4_clean_buffers(&s->c); + s->c.first_slice_line = 1; } else { - s->first_slice_line = 0; + s->c.first_slice_line = 0; } } } -static void msmpeg4v2_encode_motion(MpegEncContext * s, int val) +static void msmpeg4v2_encode_motion(MPVEncContext *const s, int val) { int range, bit_size, sign, code, bits; if (val == 0) { - /* zero vector */ - code = 0; - put_bits(&s->pb, ff_mvtab[code][1], ff_mvtab[code][0]); + /* zero vector; corresponds to ff_mvtab[0] */ + put_bits(&s->pb, 1, 0x1); } else { bit_size = s->f_code - 1; range = 1 << bit_size; @@ -382,23 +374,24 @@ static void msmpeg4v2_encode_motion(MpegEncContext * s, int val) } } -void ff_msmpeg4_encode_mb(MpegEncContext * s, - int16_t block[6][64], - int motion_x, int motion_y) +static void msmpeg4_encode_mb(MPVEncContext *const s, + int16_t block[][64], + int motion_x, int motion_y) { + MSMPEG4EncContext *const ms = mpv_to_msmpeg4(s); int cbp, coded_cbp, i; int pred_x, pred_y; ff_msmpeg4_handle_slices(s); - if (!s->mb_intra) { + if (!s->c.mb_intra) { /* compute cbp */ cbp = 0; for (i = 0; i < 6; i++) { - if (s->block_last_index[i] >= 0) + if (s->c.block_last_index[i] >= 0) cbp |= 1 << (5 - i); } - if (s->use_skip_mb_code && (cbp | motion_x | motion_y) == 0) { + if (ms->use_skip_mb_code && (cbp | motion_x | motion_y) == 0) { /* skip macroblock */ put_bits(&s->pb, 1, 1); s->last_bits++; @@ -406,10 +399,10 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, return; } - if (s->use_skip_mb_code) + if (ms->use_skip_mb_code) put_bits(&s->pb, 1, 0); /* mb coded */ - if (s->msmpeg4_version <= MSMP4_V2) { + if (s->c.msmpeg4_version <= MSMP4_V2) { put_bits(&s->pb, ff_v2_mb_type[cbp&3][1], ff_v2_mb_type[cbp&3][0]); @@ -422,7 +415,7 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, s->misc_bits += get_bits_diff(s); - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); msmpeg4v2_encode_motion(s, motion_x - pred_x); msmpeg4v2_encode_motion(s, motion_y - pred_y); }else{ @@ -433,9 +426,9 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, s->misc_bits += get_bits_diff(s); /* motion vector */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - ff_msmpeg4_encode_motion(s, motion_x - pred_x, - motion_y - pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); + ff_msmpeg4_encode_motion(ms, motion_x - pred_x, + motion_y - pred_y); } s->mv_bits += get_bits_diff(s); @@ -448,15 +441,15 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, /* compute cbp */ cbp = 0; for (int i = 0; i < 6; i++) { - int val = (s->block_last_index[i] >= 1); + int val = (s->c.block_last_index[i] >= 1); cbp |= val << (5 - i); } - if (s->msmpeg4_version <= MSMP4_V2) { - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.msmpeg4_version <= MSMP4_V2) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { put_bits(&s->pb, ff_v2_intra_cbpc[cbp&3][1], ff_v2_intra_cbpc[cbp&3][0]); } else { - if (s->use_skip_mb_code) + if (ms->use_skip_mb_code) put_bits(&s->pb, 1, 0); /* mb coded */ put_bits(&s->pb, ff_v2_mb_type[(cbp&3) + 4][1], @@ -467,14 +460,14 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, ff_h263_cbpy_tab[cbp>>2][1], ff_h263_cbpy_tab[cbp>>2][0]); }else{ - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { /* compute coded_cbp; the 0x3 corresponds to chroma cbp; * luma coded_cbp are set in the loop below */ coded_cbp = cbp & 0x3; for (int i = 0; i < 4; i++) { uint8_t *coded_block; - int pred = ff_msmpeg4_coded_block_pred(s, i, &coded_block); - int val = (s->block_last_index[i] >= 1); + int pred = ff_msmpeg4_coded_block_pred(&s->c, i, &coded_block); + int val = (s->c.block_last_index[i] >= 1); *coded_block = val; val ^= pred; coded_cbp |= val << (5 - i); @@ -483,16 +476,17 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, put_bits(&s->pb, ff_msmp4_mb_i_table[coded_cbp][1], ff_msmp4_mb_i_table[coded_cbp][0]); } else { - if (s->use_skip_mb_code) + if (ms->use_skip_mb_code) put_bits(&s->pb, 1, 0); /* mb coded */ put_bits(&s->pb, ff_table_mb_non_intra[cbp][1], ff_table_mb_non_intra[cbp][0]); } put_bits(&s->pb, 1, 0); /* no AC prediction yet */ - if(s->inter_intra_pred){ - s->h263_aic_dir=0; - put_bits(&s->pb, ff_table_inter_intra[s->h263_aic_dir][1], ff_table_inter_intra[s->h263_aic_dir][0]); + if (s->c.inter_intra_pred) { + s->c.h263_aic_dir = 0; + put_bits(&s->pb, ff_table_inter_intra[s->c.h263_aic_dir][1], + ff_table_inter_intra[s->c.h263_aic_dir][0]); } } s->misc_bits += get_bits_diff(s); @@ -505,25 +499,26 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, } } -static void msmpeg4_encode_dc(MpegEncContext * s, int level, int n, int *dir_ptr) +static void msmpeg4_encode_dc(MSMPEG4EncContext *const ms, int level, int n, int *dir_ptr) { + MPVEncContext *const s = &ms->m.s; int sign, code; int pred; int16_t *dc_val; - pred = ff_msmpeg4_pred_dc(s, n, &dc_val, dir_ptr); + pred = ff_msmpeg4_pred_dc(&s->c, n, &dc_val, dir_ptr); /* update predictor */ if (n < 4) { - *dc_val = level * s->y_dc_scale; + *dc_val = level * s->c.y_dc_scale; } else { - *dc_val = level * s->c_dc_scale; + *dc_val = level * s->c.c_dc_scale; } /* do the prediction */ level -= pred; - if (s->msmpeg4_version <= MSMP4_V2) { + if (s->c.msmpeg4_version <= MSMP4_V2) { if (n < 4) { put_bits(&s->pb, ff_v2_dc_lum_table[level + 256][1], @@ -543,8 +538,8 @@ static void msmpeg4_encode_dc(MpegEncContext * s, int level, int n, int *dir_ptr if (code > DC_MAX) code = DC_MAX; - put_bits(&s->pb, ff_msmp4_dc_tables[s->dc_table_index][n >= 4][code][1], - ff_msmp4_dc_tables[s->dc_table_index][n >= 4][code][0]); + put_bits(&s->pb, ff_msmp4_dc_tables[ms->dc_table_index][n >= 4][code][1], + ff_msmp4_dc_tables[ms->dc_table_index][n >= 4][code][0]); if (code == DC_MAX) put_bits(&s->pb, 8, level); @@ -557,7 +552,7 @@ static void msmpeg4_encode_dc(MpegEncContext * s, int level, int n, int *dir_ptr /* Encoding of a block; very similar to MPEG-4 except for a different * escape coding (same as H.263) and more VLC tables. */ -void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) +void ff_msmpeg4_encode_block(MPVEncContext *const s, int16_t * block, int n) { MSMPEG4EncContext *const ms = (MSMPEG4EncContext*)s; int level, run, last, i, j, last_index; @@ -566,31 +561,31 @@ void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) const RLTable *rl; const uint8_t *scantable; - if (s->mb_intra) { - msmpeg4_encode_dc(s, block[0], n, &dc_pred_dir); + if (s->c.mb_intra) { + msmpeg4_encode_dc(ms, block[0], n, &dc_pred_dir); i = 1; if (n < 4) { - rl = &ff_rl_table[s->rl_table_index]; + rl = &ff_rl_table[ms->rl_table_index]; } else { - rl = &ff_rl_table[3 + s->rl_chroma_table_index]; + rl = &ff_rl_table[3 + ms->rl_chroma_table_index]; } - run_diff = s->msmpeg4_version >= MSMP4_WMV1; - scantable= s->intra_scantable.permutated; + run_diff = s->c.msmpeg4_version >= MSMP4_WMV1; + scantable = s->c.intra_scantable.permutated; } else { i = 0; - rl = &ff_rl_table[3 + s->rl_table_index]; - run_diff = s->msmpeg4_version > MSMP4_V2; - scantable= s->inter_scantable.permutated; + rl = &ff_rl_table[3 + ms->rl_table_index]; + run_diff = s->c.msmpeg4_version > MSMP4_V2; + scantable = s->c.inter_scantable.permutated; } /* recalculate block_last_index for M$ wmv1 */ - if (s->msmpeg4_version >= MSMP4_WMV1 && s->block_last_index[n] > 0) { + if (s->c.msmpeg4_version >= MSMP4_WMV1 && s->c.block_last_index[n] > 0) { for(last_index=63; last_index>=0; last_index--){ if(block[scantable[last_index]]) break; } - s->block_last_index[n]= last_index; + s->c.block_last_index[n] = last_index; }else - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; /* AC coefs */ last_non_zero = i - 1; for (; i <= last_index; i++) { @@ -607,10 +602,10 @@ void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) } if(level<=MAX_LEVEL && run<=MAX_RUN){ - ms->ac_stats[s->mb_intra][n>3][level][run][last]++; + ms->ac_stats[s->c.mb_intra][n>3][level][run][last]++; } - ms->ac_stats[s->mb_intra][n > 3][40][63][0]++; //esc3 like + ms->ac_stats[s->c.mb_intra][n > 3][40][63][0]++; //esc3 like code = get_rl_index(rl, last, run, level); put_bits(&s->pb, rl->table_vlc[code][1], rl->table_vlc[code][0]); @@ -630,7 +625,7 @@ void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) if (run1 < 0) goto esc3; code = get_rl_index(rl, last, run1+1, level); - if (s->msmpeg4_version == MSMP4_WMV1 && code == rl->n) + if (s->c.msmpeg4_version == MSMP4_WMV1 && code == rl->n) goto esc3; code = get_rl_index(rl, last, run1, level); if (code == rl->n) { @@ -638,17 +633,17 @@ void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) /* third escape */ put_bits(&s->pb, 1, 0); put_bits(&s->pb, 1, last); - if (s->msmpeg4_version >= MSMP4_WMV1) { - if(s->esc3_level_length==0){ - s->esc3_level_length=8; - s->esc3_run_length= 6; + if (s->c.msmpeg4_version >= MSMP4_WMV1) { + if (s->esc3_level_length == 0) { + s->esc3_level_length = 8; + ms->esc3_run_length = 6; //ESCLVLSZ + ESCRUNSZ - if(s->qscale<8) + if (s->c.qscale < 8) put_bits(&s->pb, 6, 3); else put_bits(&s->pb, 8, 3); } - put_bits(&s->pb, s->esc3_run_length, run); + put_bits(&s->pb, ms->esc3_run_length, run); put_bits(&s->pb, 1, sign); put_bits(&s->pb, s->esc3_level_length, level); }else{ @@ -675,15 +670,37 @@ void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) } } +av_cold void ff_msmpeg4_encode_init(MPVMainEncContext *const m) +{ + MPVEncContext *const s = &m->s; + static AVOnce init_static_once = AV_ONCE_INIT; + + ff_msmpeg4_common_init(&s->c, s->permutated_intra_h_scantable, + s->permutated_intra_v_scantable); + + if (s->c.msmpeg4_version <= MSMP4_WMV1) { + m->encode_picture_header = msmpeg4_encode_picture_header; + s->encode_mb = msmpeg4_encode_mb; + } + + if (s->c.msmpeg4_version >= MSMP4_WMV1) { + s->min_qcoeff = -255; + s->max_qcoeff = 255; + } + + /* init various encoding tables */ + ff_thread_once(&init_static_once, msmpeg4_encode_init_static); +} + const FFCodec ff_msmpeg4v2_encoder = { .p.name = "msmpeg4v2", CODEC_LONG_NAME("MPEG-4 part 2 Microsoft variant version 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MSMPEG4V2, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .priv_data_size = sizeof(MSMPEG4EncContext), .init = ff_mpv_encode_init, @@ -696,10 +713,10 @@ const FFCodec ff_msmpeg4v3_encoder = { CODEC_LONG_NAME("MPEG-4 part 2 Microsoft variant version 3"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MSMPEG4V3, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .priv_data_size = sizeof(MSMPEG4EncContext), .init = ff_mpv_encode_init, @@ -712,10 +729,10 @@ const FFCodec ff_wmv1_encoder = { CODEC_LONG_NAME("Windows Media Video 7"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_WMV1, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .priv_data_size = sizeof(MSMPEG4EncContext), .init = ff_mpv_encode_init, diff --git a/libavcodec/msmpeg4enc.h b/libavcodec/msmpeg4enc.h index da9a45b58..167600f01 100644 --- a/libavcodec/msmpeg4enc.h +++ b/libavcodec/msmpeg4enc.h @@ -22,25 +22,36 @@ #ifndef AVCODEC_MSMPEG4ENC_H #define AVCODEC_MSMPEG4ENC_H -#include "mpegvideo.h" +#include "mpegvideoenc.h" #include "put_bits.h" #include "rl.h" typedef struct MSMPEG4EncContext { - MpegEncContext s; + MPVMainEncContext m; + + int mv_table_index; + int rl_table_index; + int rl_chroma_table_index; + int dc_table_index; + int use_skip_mb_code; + int per_mb_rl_table; + int esc3_run_length; /** [mb_intra][isChroma][level][run][last] */ unsigned ac_stats[2][2][MAX_LEVEL + 1][MAX_RUN + 1][2]; } MSMPEG4EncContext; -void ff_msmpeg4_encode_init(MpegEncContext *s); -void ff_msmpeg4_encode_picture_header(MpegEncContext *s); -void ff_msmpeg4_encode_ext_header(MpegEncContext *s); -void ff_msmpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], - int motion_x, int motion_y); -void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n); -void ff_msmpeg4_handle_slices(MpegEncContext *s); -void ff_msmpeg4_encode_motion(MpegEncContext * s, int mx, int my); +static inline MSMPEG4EncContext *mpv_to_msmpeg4(MPVEncContext *s) +{ + // Only legal because no MSMPEG-4 decoder uses slice-threading. + return (MSMPEG4EncContext*)s; +} + +void ff_msmpeg4_encode_init(MPVMainEncContext *m); +void ff_msmpeg4_encode_ext_header(MPVEncContext *s); +void ff_msmpeg4_encode_block(MPVEncContext * s, int16_t * block, int n); +void ff_msmpeg4_handle_slices(MPVEncContext *s); +void ff_msmpeg4_encode_motion(MSMPEG4EncContext *ms, int mx, int my); void ff_msmpeg4_code012(PutBitContext *pb, int n); diff --git a/libavcodec/msrle.c b/libavcodec/msrle.c index 51e843e4a..24db12bc4 100644 --- a/libavcodec/msrle.c +++ b/libavcodec/msrle.c @@ -34,6 +34,7 @@ #include "codec_internal.h" #include "decode.h" #include "msrledec.h" +#include "libavutil/attributes.h" #include "libavutil/imgutils.h" typedef struct MsrleContext { @@ -95,15 +96,7 @@ static int msrle_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return ret; if (avctx->bits_per_coded_sample > 1 && avctx->bits_per_coded_sample <= 8) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif - /* make the palette available */ memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); } @@ -146,7 +139,7 @@ FF_ENABLE_DEPRECATION_WARNINGS return buf_size; } -static void msrle_decode_flush(AVCodecContext *avctx) +static av_cold void msrle_decode_flush(AVCodecContext *avctx) { MsrleContext *s = avctx->priv_data; diff --git a/libavcodec/msrleenc.c b/libavcodec/msrleenc.c index cc39aa308..d4775a8d3 100644 --- a/libavcodec/msrleenc.c +++ b/libavcodec/msrleenc.c @@ -30,6 +30,8 @@ #include "codec_internal.h" #include "encode.h" +#include "libavutil/attributes.h" + typedef struct MSRLEContext { int curframe; AVFrame *last_frame; @@ -276,7 +278,7 @@ static int msrle_encode_frame(AVCodecContext *avctx, AVPacket *pkt, return av_frame_replace(s->last_frame, pict); } -static int msrle_encode_close(AVCodecContext *avctx) +static av_cold int msrle_encode_close(AVCodecContext *avctx) { MSRLEContext *s = avctx->priv_data; av_frame_free(&s->last_frame); @@ -293,8 +295,6 @@ const FFCodec ff_msrle_encoder = { .init = msrle_encode_init, FF_CODEC_ENCODE_CB(msrle_encode_frame), .close = msrle_encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_PAL8), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/mss1.c b/libavcodec/mss1.c index 546067313..cfda18c6d 100644 --- a/libavcodec/mss1.c +++ b/libavcodec/mss1.c @@ -121,13 +121,13 @@ static void arith_init(ArithCoder *c, GetBitContext *gb) c->get_number = arith_get_number; } -static int decode_pal(MSS12Context *ctx, ArithCoder *acoder) +static void decode_pal(MSS12Context *ctx, ArithCoder *acoder) { int i, ncol, r, g, b; uint32_t *pal = ctx->pal + 256 - ctx->free_colours; if (!ctx->free_colours) - return 0; + return; ncol = arith_get_number(acoder, ctx->free_colours + 1); for (i = 0; i < ncol; i++) { @@ -136,8 +136,6 @@ static int decode_pal(MSS12Context *ctx, ArithCoder *acoder) b = arith_get_bits(acoder, 8); *pal++ = (0xFFU << 24) | (r << 16) | (g << 8) | b; } - - return !!ncol; } static int mss1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, @@ -147,7 +145,6 @@ static int mss1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, MSS12Context *c = &ctx->ctx; GetBitContext gb; ArithCoder acoder; - int pal_changed = 0; int ret; if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0) @@ -164,7 +161,7 @@ static int mss1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (c->keyframe) { c->corrupted = 0; ff_mss12_slicecontext_reset(&ctx->sc); - pal_changed = decode_pal(c, &acoder); + decode_pal(c, &acoder); ctx->pic->flags |= AV_FRAME_FLAG_KEY; ctx->pic->pict_type = AV_PICTURE_TYPE_I; } else { @@ -178,11 +175,6 @@ static int mss1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (c->corrupted) return AVERROR_INVALIDDATA; memcpy(ctx->pic->data[1], c->pal, AVPALETTE_SIZE); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - ctx->pic->palette_has_changed = pal_changed; -FF_ENABLE_DEPRECATION_WARNINGS -#endif if ((ret = av_frame_ref(rframe, ctx->pic)) < 0) return ret; diff --git a/libavcodec/mss2.c b/libavcodec/mss2.c index 1888053eb..aaeceb055 100644 --- a/libavcodec/mss2.c +++ b/libavcodec/mss2.c @@ -387,12 +387,12 @@ static int decode_wmv9(AVCodecContext *avctx, const uint8_t *buf, int buf_size, ff_mpeg_flush(avctx); - if ((ret = init_get_bits8(&s->gb, buf, buf_size)) < 0) + if ((ret = init_get_bits8(&v->gb, buf, buf_size)) < 0) return ret; - s->loop_filter = avctx->skip_loop_filter < AVDISCARD_ALL; + v->loop_filter = avctx->skip_loop_filter < AVDISCARD_ALL; - if (ff_vc1_parse_frame_header(v, &s->gb) < 0) { + if (ff_vc1_parse_frame_header(v, &v->gb) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "header error\n"); return AVERROR_INVALIDDATA; } @@ -844,7 +844,7 @@ static av_cold int wmv9_init(AVCodecContext *avctx) v->resync_marker = 0; v->rangered = 0; - v->s.max_b_frames = avctx->max_b_frames = 0; + v->max_b_frames = avctx->max_b_frames = 0; v->quantizer_mode = 0; v->finterpflag = 0; diff --git a/libavcodec/msvideo1.c b/libavcodec/msvideo1.c index ca4583d84..27ec26f3a 100644 --- a/libavcodec/msvideo1.c +++ b/libavcodec/msvideo1.c @@ -312,14 +312,7 @@ static int msvideo1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return ret; if (s->mode_8bit) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif } if (s->mode_8bit) diff --git a/libavcodec/msvideo1enc.c b/libavcodec/msvideo1enc.c index b8704367c..b1cae7208 100644 --- a/libavcodec/msvideo1enc.c +++ b/libavcodec/msvideo1enc.c @@ -315,5 +315,5 @@ const FFCodec ff_msvideo1_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_RGB555, AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_RGB555), }; diff --git a/libavcodec/mv30.c b/libavcodec/mv30.c index 124a37e23..2ca74496a 100644 --- a/libavcodec/mv30.c +++ b/libavcodec/mv30.c @@ -23,6 +23,7 @@ #include #include +#include "libavutil/attributes.h" #include "libavutil/mem.h" #include "libavutil/thread.h" @@ -682,7 +683,7 @@ static av_cold int decode_init(AVCodecContext *avctx) return 0; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { MV30Context *s = avctx->priv_data; diff --git a/libavcodec/mxpegdec.c b/libavcodec/mxpegdec.c index c5c14cbe7..2a8e58398 100644 --- a/libavcodec/mxpegdec.c +++ b/libavcodec/mxpegdec.c @@ -28,6 +28,7 @@ #include "libavutil/mem.h" #include "codec_internal.h" #include "decode.h" +#include "hpeldsp.h" #include "mjpeg.h" #include "mjpegdec.h" @@ -47,10 +48,8 @@ typedef struct MXpegDecodeContext { static av_cold int mxpeg_decode_end(AVCodecContext *avctx) { MXpegDecodeContext *s = avctx->priv_data; - MJpegDecodeContext *jpg = &s->jpg; int i; - jpg->picture_ptr = NULL; ff_mjpeg_decode_end(avctx); for (i = 0; i < 2; ++i) @@ -66,6 +65,10 @@ static av_cold int mxpeg_decode_end(AVCodecContext *avctx) static av_cold int mxpeg_decode_init(AVCodecContext *avctx) { MXpegDecodeContext *s = avctx->priv_data; + HpelDSPContext hdsp; + + ff_hpeldsp_init(&hdsp, avctx->flags); + s->jpg.copy_block = hdsp.put_pixels_tab[1][0]; s->picture[0] = av_frame_alloc(); s->picture[1] = av_frame_alloc(); @@ -83,7 +86,7 @@ static int mxpeg_decode_app(MXpegDecodeContext *s, if (buf_size < 2) return 0; len = AV_RB16(buf_ptr); - skip_bits(&s->jpg.gb, 8*FFMIN(len,buf_size)); + bytestream2_skipu(&s->jpg.gB, FFMIN(len, buf_size)); return 0; } @@ -151,7 +154,7 @@ static int mxpeg_decode_com(MXpegDecodeContext *s, if (len > 14 && len <= buf_size && !strncmp(buf_ptr + 2, "MXM", 3)) { ret = mxpeg_decode_mxm(s, buf_ptr + 2, len - 2); } - skip_bits(&s->jpg.gb, 8*FFMIN(len,buf_size)); + bytestream2_skipu(&s->jpg.gB, FFMIN(len, buf_size)); return ret; } @@ -176,6 +179,12 @@ static int mxpeg_check_dimensions(MXpegDecodeContext *s, MJpegDecodeContext *jpg return AVERROR(EINVAL); } } + if (reference_ptr->width != jpg->picture_ptr->width || + reference_ptr->height != jpg->picture_ptr->height || + reference_ptr->format != jpg->picture_ptr->format) { + av_log(jpg->avctx, AV_LOG_ERROR, "Reference mismatching\n"); + return AVERROR_INVALIDDATA; + } } return 0; @@ -189,8 +198,6 @@ static int mxpeg_decode_frame(AVCodecContext *avctx, AVFrame *rframe, MXpegDecodeContext *s = avctx->priv_data; MJpegDecodeContext *jpg = &s->jpg; const uint8_t *buf_end, *buf_ptr; - const uint8_t *unescaped_buf_ptr; - int unescaped_buf_size; int start_code; int ret; @@ -203,123 +210,125 @@ static int mxpeg_decode_frame(AVCodecContext *avctx, AVFrame *rframe, s->got_mxm_bitmask = 0; s->got_sof_data = !!s->got_sof_data; while (buf_ptr < buf_end) { - start_code = ff_mjpeg_find_marker(jpg, &buf_ptr, buf_end, - &unescaped_buf_ptr, &unescaped_buf_size); + start_code = ff_mjpeg_find_marker(&buf_ptr, buf_end); if (start_code < 0) goto the_end; - { - init_get_bits(&jpg->gb, unescaped_buf_ptr, unescaped_buf_size*8); - if (start_code >= APP0 && start_code <= APP15) { - mxpeg_decode_app(s, unescaped_buf_ptr, unescaped_buf_size); - } + int bytes_left = buf_end - buf_ptr; + bytestream2_init(&jpg->gB, buf_ptr, bytes_left); - switch (start_code) { - case SOI: - if (jpg->got_picture) //emulating EOI - goto the_end; - break; - case EOI: - goto the_end; - case DQT: - ret = ff_mjpeg_decode_dqt(jpg); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, - "quantization table decode error\n"); - return ret; - } - break; - case DHT: - ret = ff_mjpeg_decode_dht(jpg); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, - "huffman table decode error\n"); - return ret; - } - break; - case COM: - ret = mxpeg_decode_com(s, unescaped_buf_ptr, - unescaped_buf_size); - if (ret < 0) - return ret; - break; - case SOF0: - if (s->got_sof_data > 1) { - av_log(avctx, AV_LOG_ERROR, - "Multiple SOF in a frame\n"); - return AVERROR_INVALIDDATA; - } - ret = ff_mjpeg_decode_sof(jpg); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, - "SOF data decode error\n"); - s->got_sof_data = 0; - return ret; - } - if (jpg->interlaced) { - av_log(avctx, AV_LOG_ERROR, - "Interlaced mode not supported in MxPEG\n"); - s->got_sof_data = 0; - return AVERROR(EINVAL); - } - s->got_sof_data ++; - break; - case SOS: - if (!s->got_sof_data) { - av_log(avctx, AV_LOG_WARNING, - "Can not process SOS without SOF data, skipping\n"); - break; - } - if (!jpg->got_picture) { - if (jpg->first_picture) { - av_log(avctx, AV_LOG_WARNING, - "First picture has no SOF, skipping\n"); - break; - } - if (!s->got_mxm_bitmask){ - av_log(avctx, AV_LOG_WARNING, - "Non-key frame has no MXM, skipping\n"); - break; - } - /* use stored SOF data to allocate current picture */ - av_frame_unref(jpg->picture_ptr); - if ((ret = ff_get_buffer(avctx, jpg->picture_ptr, - AV_GET_BUFFER_FLAG_REF)) < 0) - return ret; - jpg->picture_ptr->pict_type = AV_PICTURE_TYPE_P; - jpg->picture_ptr->flags &= ~AV_FRAME_FLAG_KEY; - jpg->got_picture = 1; - } else { - jpg->picture_ptr->pict_type = AV_PICTURE_TYPE_I; - jpg->picture_ptr->flags |= AV_FRAME_FLAG_KEY; - } - - if (s->got_mxm_bitmask) { - AVFrame *reference_ptr = s->picture[s->picture_index ^ 1]; - if (mxpeg_check_dimensions(s, jpg, reference_ptr) < 0) - break; - - /* allocate dummy reference picture if needed */ - if (!reference_ptr->data[0] && - (ret = ff_get_buffer(avctx, reference_ptr, - AV_GET_BUFFER_FLAG_REF)) < 0) - return ret; - - ret = ff_mjpeg_decode_sos(jpg, s->mxm_bitmask, s->bitmask_size, reference_ptr); - if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) - return ret; - } else { - ret = ff_mjpeg_decode_sos(jpg, NULL, 0, NULL); - if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) - return ret; - } - - break; - } - - buf_ptr += (get_bits_count(&jpg->gb)+7) >> 3; + if (start_code >= APP0 && start_code <= APP15) { + mxpeg_decode_app(s, buf_ptr, bytes_left); } + switch (start_code) { + case SOI: + if (jpg->got_picture) //emulating EOI + goto the_end; + break; + case EOI: + goto the_end; + case DQT: + ret = ff_mjpeg_decode_dqt(jpg); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "quantization table decode error\n"); + return ret; + } + break; + case DHT: + ret = ff_mjpeg_decode_dht(jpg); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "huffman table decode error\n"); + return ret; + } + break; + case COM: + ret = mxpeg_decode_com(s, buf_ptr, bytes_left); + if (ret < 0) + return ret; + break; + case SOF0: + if (s->got_sof_data > 1) { + av_log(avctx, AV_LOG_ERROR, + "Multiple SOF in a frame\n"); + return AVERROR_INVALIDDATA; + } + ret = ff_mjpeg_decode_sof(jpg); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "SOF data decode error\n"); + s->got_sof_data = 0; + return ret; + } + if (jpg->interlaced) { + av_log(avctx, AV_LOG_ERROR, + "Interlaced mode not supported in MxPEG\n"); + s->got_sof_data = 0; + return AVERROR(EINVAL); + } + s->got_sof_data ++; + break; + case SOS: + if (!s->got_sof_data) { + av_log(avctx, AV_LOG_WARNING, + "Can not process SOS without SOF data, skipping\n"); + break; + } + if (!jpg->got_picture) { + if (jpg->first_picture) { + av_log(avctx, AV_LOG_WARNING, + "First picture has no SOF, skipping\n"); + break; + } + if (!s->got_mxm_bitmask){ + av_log(avctx, AV_LOG_WARNING, + "Non-key frame has no MXM, skipping\n"); + break; + } + /* use stored SOF data to allocate current picture */ + av_frame_unref(jpg->picture_ptr); + if ((ret = ff_get_buffer(avctx, jpg->picture_ptr, + AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + jpg->picture_ptr->pict_type = AV_PICTURE_TYPE_P; + jpg->picture_ptr->flags &= ~AV_FRAME_FLAG_KEY; + jpg->got_picture = 1; + } else { + jpg->picture_ptr->pict_type = AV_PICTURE_TYPE_I; + jpg->picture_ptr->flags |= AV_FRAME_FLAG_KEY; + } + + if (s->got_mxm_bitmask) { + AVFrame *reference_ptr = s->picture[s->picture_index ^ 1]; + if (mxpeg_check_dimensions(s, jpg, reference_ptr) < 0) + break; + + /* allocate dummy reference picture if needed */ + if (!reference_ptr->data[0] && + (ret = ff_get_buffer(avctx, reference_ptr, + AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + + jpg->mb_bitmask = s->mxm_bitmask; + jpg->mb_bitmask_size = s->bitmask_size; + jpg->reference = reference_ptr; + ret = ff_mjpeg_decode_sos(jpg); + if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) + return ret; + } else { + jpg->mb_bitmask = NULL; + jpg->reference = NULL; + ret = ff_mjpeg_decode_sos(jpg); + if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) + return ret; + } + + break; + } + + buf_ptr += bytestream2_tell(&jpg->gB); } the_end: diff --git a/libavcodec/nellymoser.c b/libavcodec/nellymoser.c index 66c5f83a5..890e573ab 100644 --- a/libavcodec/nellymoser.c +++ b/libavcodec/nellymoser.c @@ -28,7 +28,7 @@ /** * @file * The 3 alphanumeric copyright notices are md5summed they are from the original - * implementors. The original code is available from http://code.google.com/p/nelly2pcm/ + * implementers. The original code is available from http://code.google.com/p/nelly2pcm/ */ #include diff --git a/libavcodec/nellymoser.h b/libavcodec/nellymoser.h index 6d032c97b..3470bfa6b 100644 --- a/libavcodec/nellymoser.h +++ b/libavcodec/nellymoser.h @@ -28,7 +28,7 @@ /** * @file * The 3 alphanumeric copyright notices are md5summed they are from the original - * implementors. The original code is available from http://code.google.com/p/nelly2pcm/ + * implementers. The original code is available from http://code.google.com/p/nelly2pcm/ */ #ifndef AVCODEC_NELLYMOSER_H diff --git a/libavcodec/nellymoserdec.c b/libavcodec/nellymoserdec.c index e9b124399..36477173f 100644 --- a/libavcodec/nellymoserdec.c +++ b/libavcodec/nellymoserdec.c @@ -28,7 +28,7 @@ /** * @file * The 3 alphanumeric copyright notices are md5summed they are from the original - * implementors. The original code is available from http://code.google.com/p/nelly2pcm/ + * implementers. The original code is available from http://code.google.com/p/nelly2pcm/ */ #include "libavutil/channel_layout.h" @@ -202,6 +202,4 @@ const FFCodec ff_nellymoser_decoder = { .close = decode_end, FF_CODEC_DECODE_CB(decode_tag), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_PARAM_CHANGE | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/nellymoserenc.c b/libavcodec/nellymoserenc.c index 32ae5f782..6f002eb89 100644 --- a/libavcodec/nellymoserenc.c +++ b/libavcodec/nellymoserenc.c @@ -427,8 +427,7 @@ const FFCodec ff_nellymoser_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, { 0 } }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLT), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/neon/mpegvideo.c b/libavcodec/neon/mpegvideo.c index 8f05d77a6..45ac36df1 100644 --- a/libavcodec/neon/mpegvideo.c +++ b/libavcodec/neon/mpegvideo.c @@ -32,17 +32,15 @@ #endif #include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideo_unquantize.h" static void inline ff_dct_unquantize_h263_neon(int qscale, int qadd, int nCoeffs, int16_t *block) { int16x8_t q0s16, q2s16, q3s16, q8s16, q10s16, q11s16, q13s16; int16x8_t q14s16, q15s16, qzs16; - int16x4_t d0s16, d2s16, d3s16, dzs16; uint16x8_t q1u16, q9u16; - uint16x4_t d1u16; - dzs16 = vdup_n_s16(0); qzs16 = vdupq_n_s16(0); q15s16 = vdupq_n_s16(qscale << 1); @@ -72,18 +70,17 @@ static void inline ff_dct_unquantize_h263_neon(int qscale, int qadd, int nCoeffs if (nCoeffs <= 0) return; - d0s16 = vld1_s16(block); - d3s16 = vreinterpret_s16_u16(vclt_s16(d0s16, dzs16)); - d1u16 = vceq_s16(d0s16, dzs16); - d2s16 = vmul_s16(d0s16, vget_high_s16(q15s16)); - d3s16 = vbsl_s16(vreinterpret_u16_s16(d3s16), - vget_high_s16(q13s16), vget_high_s16(q14s16)); - d2s16 = vadd_s16(d2s16, d3s16); - d0s16 = vbsl_s16(d1u16, d0s16, d2s16); - vst1_s16(block, d0s16); + q0s16 = vld1q_s16(block); + q3s16 = vreinterpretq_s16_u16(vcltq_s16(q0s16, qzs16)); + q1u16 = vceqq_s16(q0s16, qzs16); + q2s16 = vmulq_s16(q0s16, q15s16); + q3s16 = vbslq_s16(vreinterpretq_u16_s16(q3s16), q13s16, q14s16); + q2s16 = vaddq_s16(q2s16, q3s16); + q0s16 = vbslq_s16(q1u16, q0s16, q2s16); + vst1q_s16(block, q0s16); } -static void dct_unquantize_h263_inter_neon(MpegEncContext *s, int16_t *block, +static void dct_unquantize_h263_inter_neon(const MPVContext *s, int16_t *block, int n, int qscale) { int nCoeffs = s->inter_scantable.raster_end[s->block_last_index[n]]; @@ -92,7 +89,7 @@ static void dct_unquantize_h263_inter_neon(MpegEncContext *s, int16_t *block, ff_dct_unquantize_h263_neon(qscale, qadd, nCoeffs + 1, block); } -static void dct_unquantize_h263_intra_neon(MpegEncContext *s, int16_t *block, +static void dct_unquantize_h263_intra_neon(const MPVContext *s, int16_t *block, int n, int qscale) { int qadd; @@ -111,7 +108,7 @@ static void dct_unquantize_h263_intra_neon(MpegEncContext *s, int16_t *block, if (s->ac_pred) { nCoeffs = 63; } else { - nCoeffs = s->inter_scantable.raster_end[s->block_last_index[n]]; + nCoeffs = s->intra_scantable.raster_end[s->block_last_index[n]]; if (nCoeffs <= 0) return; } @@ -124,7 +121,7 @@ static void dct_unquantize_h263_intra_neon(MpegEncContext *s, int16_t *block, } -av_cold void ff_mpv_common_init_neon(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_neon(MPVUnquantDSPContext *s, int bitexact) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/notchlc.c b/libavcodec/notchlc.c index 695c1d50f..396089254 100644 --- a/libavcodec/notchlc.c +++ b/libavcodec/notchlc.c @@ -79,7 +79,7 @@ static int lz4_decompress(AVCodecContext *avctx, PutByteContext *pb) { unsigned reference_pos, delta, pos = 0; - uint8_t history[64 * 1024] = { 0 }; + uint8_t history[HISTORY_SIZE] = { 0 }; int match_length; while (bytestream2_get_bytes_left(gb) > 0) { diff --git a/libavcodec/null.c b/libavcodec/null.c index d8e334437..e443ddf4f 100644 --- a/libavcodec/null.c +++ b/libavcodec/null.c @@ -81,15 +81,12 @@ const FFCodec ff_anull_encoder = { .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_ANULL, .p.capabilities = AV_CODEC_CAP_VARIABLE_FRAME_SIZE, - .p.sample_fmts = (const enum AVSampleFormat[]){ - AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P, - AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP, - AV_SAMPLE_FMT_NONE, - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P, + AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P, + AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP), FF_CODEC_ENCODE_CB(null_encode), }; #endif diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c index 932544564..7c29f2571 100644 --- a/libavcodec/nvdec.c +++ b/libavcodec/nvdec.c @@ -36,7 +36,7 @@ #include "decode.h" #include "nvdec.h" #include "internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #if !NVDECAPI_CHECK_VERSION(9, 0) #define cudaVideoSurfaceFormat_YUV444 2 @@ -163,7 +163,7 @@ static int nvdec_test_capabilities(NVDECDecoder *decoder, return 0; } -static void nvdec_decoder_free(FFRefStructOpaque unused, void *obj) +static void nvdec_decoder_free(AVRefStructOpaque unused, void *obj) { NVDECDecoder *decoder = obj; @@ -192,7 +192,7 @@ static int nvdec_decoder_create(NVDECDecoder **out, AVBufferRef *hw_device_ref, CUcontext dummy; int ret; - decoder = ff_refstruct_alloc_ext(sizeof(*decoder), 0, + decoder = av_refstruct_alloc_ext(sizeof(*decoder), 0, NULL, nvdec_decoder_free); if (!decoder) return AVERROR(ENOMEM); @@ -234,11 +234,11 @@ static int nvdec_decoder_create(NVDECDecoder **out, AVBufferRef *hw_device_ref, return 0; fail: - ff_refstruct_unref(&decoder); + av_refstruct_unref(&decoder); return ret; } -static int nvdec_decoder_frame_init(FFRefStructOpaque opaque, void *obj) +static int nvdec_decoder_frame_init(AVRefStructOpaque opaque, void *obj) { NVDECFramePool *pool = opaque.nc; unsigned int *intp = obj; @@ -251,7 +251,7 @@ static int nvdec_decoder_frame_init(FFRefStructOpaque opaque, void *obj) return 0; } -static void nvdec_decoder_frame_pool_free(FFRefStructOpaque opaque) +static void nvdec_decoder_frame_pool_free(AVRefStructOpaque opaque) { av_free(opaque.nc); } @@ -269,8 +269,8 @@ int ff_nvdec_decode_uninit(AVCodecContext *avctx) ctx->nb_slices = 0; ctx->slice_offsets_allocated = 0; - ff_refstruct_unref(&ctx->decoder); - ff_refstruct_pool_uninit(&ctx->decoder_pool); + av_refstruct_unref(&ctx->decoder); + av_refstruct_pool_uninit(&ctx->decoder_pool); return 0; } @@ -375,13 +375,27 @@ int ff_nvdec_decode_init(AVCodecContext *avctx) switch (sw_desc->comp[0].depth) { case 8: - output_format = chroma_444 ? cudaVideoSurfaceFormat_YUV444 : - cudaVideoSurfaceFormat_NV12; + if (chroma_444) { + output_format = cudaVideoSurfaceFormat_YUV444; +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (cuvid_chroma_format == cudaVideoChromaFormat_422) { + output_format = cudaVideoSurfaceFormat_NV16; +#endif + } else { + output_format = cudaVideoSurfaceFormat_NV12; + } break; case 10: case 12: - output_format = chroma_444 ? cudaVideoSurfaceFormat_YUV444_16Bit : - cudaVideoSurfaceFormat_P016; + if (chroma_444) { + output_format = cudaVideoSurfaceFormat_YUV444_16Bit; +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (cuvid_chroma_format == cudaVideoChromaFormat_422) { + output_format = cudaVideoSurfaceFormat_P216; +#endif + } else { + output_format = cudaVideoSurfaceFormat_P016; + } break; default: av_log(avctx, AV_LOG_ERROR, "Unsupported bit depth\n"); @@ -426,7 +440,7 @@ int ff_nvdec_decode_init(AVCodecContext *avctx) } pool->dpb_size = frames_ctx->initial_pool_size; - ctx->decoder_pool = ff_refstruct_pool_alloc_ext(sizeof(unsigned int), 0, pool, + ctx->decoder_pool = av_refstruct_pool_alloc_ext(sizeof(unsigned int), 0, pool, nvdec_decoder_frame_init, NULL, NULL, nvdec_decoder_frame_pool_free); if (!ctx->decoder_pool) { @@ -447,9 +461,9 @@ static void nvdec_fdd_priv_free(void *priv) if (!cf) return; - ff_refstruct_unref(&cf->idx_ref); - ff_refstruct_unref(&cf->ref_idx_ref); - ff_refstruct_unref(&cf->decoder); + av_refstruct_unref(&cf->idx_ref); + av_refstruct_unref(&cf->ref_idx_ref); + av_refstruct_unref(&cf->decoder); av_freep(&priv); } @@ -472,15 +486,15 @@ static void nvdec_unmap_mapped_frame(void *opaque, uint8_t *data) CHECK_CU(decoder->cudl->cuCtxPopCurrent(&dummy)); finish: - ff_refstruct_unref(&unmap_data->idx_ref); - ff_refstruct_unref(&unmap_data->ref_idx_ref); - ff_refstruct_unref(&unmap_data->decoder); + av_refstruct_unref(&unmap_data->idx_ref); + av_refstruct_unref(&unmap_data->ref_idx_ref); + av_refstruct_unref(&unmap_data->decoder); av_free(unmap_data); } static int nvdec_retrieve_data(void *logctx, AVFrame *frame) { - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FrameDecodeData *fdd = frame->private_ref; NVDECFrame *cf = (NVDECFrame*)fdd->hwaccel_priv; NVDECDecoder *decoder = cf->decoder; @@ -529,8 +543,8 @@ static int nvdec_retrieve_data(void *logctx, AVFrame *frame) goto copy_fail; unmap_data->idx = cf->idx; - unmap_data->idx_ref = ff_refstruct_ref(cf->idx_ref); - unmap_data->decoder = ff_refstruct_ref(cf->decoder); + unmap_data->idx_ref = av_refstruct_ref(cf->idx_ref); + unmap_data->decoder = av_refstruct_ref(cf->decoder); av_pix_fmt_get_chroma_sub_sample(hwctx->sw_format, &shift_h, &shift_v); for (i = 0; frame->linesize[i]; i++) { @@ -561,7 +575,7 @@ finish: int ff_nvdec_start_frame(AVCodecContext *avctx, AVFrame *frame) { NVDECContext *ctx = avctx->internal->hwaccel_priv_data; - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FrameDecodeData *fdd = frame->private_ref; NVDECFrame *cf = NULL; int ret; @@ -575,9 +589,9 @@ int ff_nvdec_start_frame(AVCodecContext *avctx, AVFrame *frame) if (!cf) return AVERROR(ENOMEM); - cf->decoder = ff_refstruct_ref(ctx->decoder); + cf->decoder = av_refstruct_ref(ctx->decoder); - cf->idx_ref = ff_refstruct_pool_get(ctx->decoder_pool); + cf->idx_ref = av_refstruct_pool_get(ctx->decoder_pool); if (!cf->idx_ref) { av_log(avctx, AV_LOG_ERROR, "No decoder surfaces left\n"); ret = AVERROR(ENOMEM); @@ -599,7 +613,7 @@ fail: int ff_nvdec_start_frame_sep_ref(AVCodecContext *avctx, AVFrame *frame, int has_sep_ref) { NVDECContext *ctx = avctx->internal->hwaccel_priv_data; - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FrameDecodeData *fdd = frame->private_ref; NVDECFrame *cf; int ret; @@ -611,7 +625,7 @@ int ff_nvdec_start_frame_sep_ref(AVCodecContext *avctx, AVFrame *frame, int has_ if (has_sep_ref) { if (!cf->ref_idx_ref) { - cf->ref_idx_ref = ff_refstruct_pool_get(ctx->decoder_pool); + cf->ref_idx_ref = av_refstruct_pool_get(ctx->decoder_pool); if (!cf->ref_idx_ref) { av_log(avctx, AV_LOG_ERROR, "No decoder surfaces left\n"); ret = AVERROR(ENOMEM); @@ -620,7 +634,7 @@ int ff_nvdec_start_frame_sep_ref(AVCodecContext *avctx, AVFrame *frame, int has_ } cf->ref_idx = *cf->ref_idx_ref; } else { - ff_refstruct_unref(&cf->ref_idx_ref); + av_refstruct_unref(&cf->ref_idx_ref); cf->ref_idx = cf->idx; } @@ -729,13 +743,53 @@ int ff_nvdec_frame_params(AVCodecContext *avctx, switch (sw_desc->comp[0].depth) { case 8: - frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_NV12; + if (chroma_444) { + frames_ctx->sw_format = AV_PIX_FMT_YUV444P; +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (cuvid_chroma_format == cudaVideoChromaFormat_422) { + frames_ctx->sw_format = AV_PIX_FMT_NV16; +#endif + } else { + frames_ctx->sw_format = AV_PIX_FMT_NV12; + } break; case 10: - frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P010; + if (chroma_444) { +#if FF_API_NVDEC_OLD_PIX_FMTS + frames_ctx->sw_format = AV_PIX_FMT_YUV444P16; +#else + frames_ctx->sw_format = AV_PIX_FMT_YUV444P10MSB; +#endif +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (cuvid_chroma_format == cudaVideoChromaFormat_422) { + frames_ctx->sw_format = AV_PIX_FMT_P210; +#endif + } else { + frames_ctx->sw_format = AV_PIX_FMT_P010; + } break; case 12: - frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P016; + if (chroma_444) { +#if FF_API_NVDEC_OLD_PIX_FMTS + frames_ctx->sw_format = AV_PIX_FMT_YUV444P16; +#else + frames_ctx->sw_format = AV_PIX_FMT_YUV444P12MSB; +#endif +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (cuvid_chroma_format == cudaVideoChromaFormat_422) { +#if FF_API_NVDEC_OLD_PIX_FMTS + frames_ctx->sw_format = AV_PIX_FMT_P216; +#else + frames_ctx->sw_format = AV_PIX_FMT_P212; +#endif +#endif + } else { +#if FF_API_NVDEC_OLD_PIX_FMTS + frames_ctx->sw_format = AV_PIX_FMT_P016; +#else + frames_ctx->sw_format = AV_PIX_FMT_P012; +#endif + } break; default: return AVERROR(EINVAL); @@ -752,7 +806,7 @@ int ff_nvdec_get_ref_idx(AVFrame *frame) if (!frame || !frame->private_ref) return -1; - fdd = (FrameDecodeData*)frame->private_ref->data; + fdd = frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; if (!cf) return -1; diff --git a/libavcodec/nvdec.h b/libavcodec/nvdec.h index 555300d27..2e80c0dc1 100644 --- a/libavcodec/nvdec.h +++ b/libavcodec/nvdec.h @@ -41,6 +41,11 @@ ((major) < 8 || ((major) == 8 && (minor) <= 0)) #endif +// SDK 13.0 compile time feature checks +#if NVDECAPI_CHECK_VERSION(13, 0) +#define NVDEC_HAVE_422_SUPPORT +#endif + typedef struct NVDECFrame { unsigned int idx; unsigned int ref_idx; @@ -52,7 +57,7 @@ typedef struct NVDECFrame { typedef struct NVDECContext { CUVIDPICPARAMS pic_params; - struct FFRefStructPool *decoder_pool; + struct AVRefStructPool *decoder_pool; struct NVDECDecoder *decoder; ///< RefStruct reference diff --git a/libavcodec/nvdec_av1.c b/libavcodec/nvdec_av1.c index 6b408edb8..d07fe6324 100644 --- a/libavcodec/nvdec_av1.c +++ b/libavcodec/nvdec_av1.c @@ -39,7 +39,9 @@ static int get_bit_depth_from_seq(const AV1RawSequenceHeader *seq) return 8; } -static int nvdec_av1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_av1_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { const AV1DecContext *s = avctx->priv_data; const AV1RawSequenceHeader *seq = s->raw_seq; @@ -62,7 +64,7 @@ static int nvdec_av1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvdec_h264.c b/libavcodec/nvdec_h264.c index 9adbc521e..54c98e611 100644 --- a/libavcodec/nvdec_h264.c +++ b/libavcodec/nvdec_h264.c @@ -34,7 +34,7 @@ static void dpb_add(const H264Context *h, CUVIDH264DPBENTRY *dst, const H264Picture *src, int frame_idx) { - FrameDecodeData *fdd = (FrameDecodeData*)src->f->private_ref->data; + FrameDecodeData *fdd = src->f->private_ref; const NVDECFrame *cf = fdd->hwaccel_priv; dst->PicIdx = cf ? cf->idx : -1; @@ -47,6 +47,7 @@ static void dpb_add(const H264Context *h, CUVIDH264DPBENTRY *dst, const H264Pict } static int nvdec_h264_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { const H264Context *h = avctx->priv_data; @@ -65,7 +66,7 @@ static int nvdec_h264_start_frame(AVCodecContext *avctx, if (ret < 0) return ret; - fdd = (FrameDecodeData*)h->cur_pic_ptr->f->private_ref->data; + fdd = h->cur_pic_ptr->f->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { @@ -97,7 +98,7 @@ static int nvdec_h264_start_frame(AVCodecContext *avctx, .num_ref_idx_l1_active_minus1 = pps->ref_count[1] - 1, .weighted_pred_flag = pps->weighted_pred, .weighted_bipred_idc = pps->weighted_bipred_idc, - .pic_init_qp_minus26 = pps->init_qp - 26, + .pic_init_qp_minus26 = pps->init_qp - 26 - 6 * (sps->bit_depth_luma - 8), .deblocking_filter_control_present_flag = pps->deblocking_filter_parameters_present, .redundant_pic_cnt_present_flag = pps->redundant_pic_cnt_present, .transform_8x8_mode_flag = pps->transform_8x8_mode, diff --git a/libavcodec/nvdec_hevc.c b/libavcodec/nvdec_hevc.c index e01ce4c78..2b9df3e70 100644 --- a/libavcodec/nvdec_hevc.c +++ b/libavcodec/nvdec_hevc.c @@ -34,7 +34,7 @@ static void dpb_add(CUVIDHEVCPICPARAMS *pp, int idx, const HEVCFrame *src) { - FrameDecodeData *fdd = (FrameDecodeData*)src->f->private_ref->data; + FrameDecodeData *fdd = src->f->private_ref; const NVDECFrame *cf = fdd->hwaccel_priv; pp->RefPicIdx[idx] = cf ? cf->idx : -1; @@ -70,6 +70,7 @@ static void fill_scaling_lists(CUVIDHEVCPICPARAMS *ppc, const HEVCContext *s) } static int nvdec_hevc_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { const HEVCContext *s = avctx->priv_data; @@ -89,7 +90,7 @@ static int nvdec_hevc_start_frame(AVCodecContext *avctx, if (ret < 0) return ret; - fdd = (FrameDecodeData*)s->cur_frame->f->private_ref->data; + fdd = s->cur_frame->f->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvdec_mjpeg.c b/libavcodec/nvdec_mjpeg.c index 850634bf1..f0c941639 100644 --- a/libavcodec/nvdec_mjpeg.c +++ b/libavcodec/nvdec_mjpeg.c @@ -27,7 +27,9 @@ #include "decode.h" #include "hwaccel_internal.h" -static int nvdec_mjpeg_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_mjpeg_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { MJpegDecodeContext *s = avctx->priv_data; @@ -43,7 +45,7 @@ static int nvdec_mjpeg_start_frame(AVCodecContext *avctx, const uint8_t *buffer, if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvdec_mpeg12.c b/libavcodec/nvdec_mpeg12.c index 99b2b14f1..ca0a1001d 100644 --- a/libavcodec/nvdec_mpeg12.c +++ b/libavcodec/nvdec_mpeg12.c @@ -30,7 +30,9 @@ #include "nvdec.h" #include "decode.h" -static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { MpegEncContext *s = avctx->priv_data; @@ -47,7 +49,7 @@ static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, const uint8_t *buffer if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvdec_mpeg4.c b/libavcodec/nvdec_mpeg4.c index 80da11b5b..369bd5b99 100644 --- a/libavcodec/nvdec_mpeg4.c +++ b/libavcodec/nvdec_mpeg4.c @@ -28,10 +28,12 @@ #include "decode.h" #include "hwaccel_internal.h" -static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { Mpeg4DecContext *m = avctx->priv_data; - MpegEncContext *s = &m->m; + MPVContext *const s = &m->h.c; NVDECContext *ctx = avctx->internal->hwaccel_priv_data; CUVIDPICPARAMS *pp = &ctx->pic_params; @@ -46,7 +48,7 @@ static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const uint8_t *buffer, if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { @@ -68,18 +70,18 @@ static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const uint8_t *buffer, .vop_time_increment_bitcount = m->time_increment_bits, .top_field_first = s->top_field_first, .resync_marker_disable = !m->resync_marker, - .quant_type = s->mpeg_quant, + .quant_type = m->mpeg_quant, .quarter_sample = s->quarter_sample, .short_video_header = avctx->codec->id == AV_CODEC_ID_H263, - .divx_flags = s->divx_packed ? 5 : 0, + .divx_flags = m->h.divx_packed ? 5 : 0, .vop_coding_type = s->pict_type - AV_PICTURE_TYPE_I, .vop_coded = 1, .vop_rounding_type = s->no_rounding, .alternate_vertical_scan_flag = s->alternate_scan, .interlaced = !s->progressive_sequence, - .vop_fcode_forward = s->f_code, - .vop_fcode_backward = s->b_code, + .vop_fcode_forward = m->f_code, + .vop_fcode_backward = m->b_code, .trd = { s->pp_time, s->pp_field_time >> 1 }, .trb = { s->pb_time, s->pb_field_time >> 1 }, diff --git a/libavcodec/nvdec_vc1.c b/libavcodec/nvdec_vc1.c index 0668863cb..d00cf5237 100644 --- a/libavcodec/nvdec_vc1.c +++ b/libavcodec/nvdec_vc1.c @@ -22,6 +22,7 @@ #include "config_components.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "hwaccel_internal.h" #include "internal.h" @@ -29,7 +30,9 @@ #include "decode.h" #include "vc1.h" -static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_vc1_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { VC1Context *v = avctx->priv_data; MpegEncContext *s = &v->s; @@ -46,7 +49,7 @@ static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { @@ -84,14 +87,14 @@ static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u .multires = v->multires, .syncmarker = v->resync_marker, .rangered = v->rangered, - .maxbframes = s->max_b_frames, + .maxbframes = v->max_b_frames, .panscan_flag = v->panscanflag, .refdist_flag = v->refdist_flag, .extended_mv = v->extended_mv, .dquant = v->dquant, .vstransform = v->vstransform, - .loopfilter = v->s.loop_filter, + .loopfilter = v->loop_filter, .fastuvmc = v->fastuvmc, .overlap = v->overlap, .quantizer = v->quantizer_mode, @@ -107,6 +110,48 @@ static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u return 0; } +static int nvdec_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, + uint32_t size) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + const VC1Context *v = avctx->priv_data; + uint32_t marker; + int marker_size; + void *tmp; + + if (ctx->bitstream_len) + marker = VC1_CODE_SLICE; + else if (v->profile == PROFILE_ADVANCED && v->fcm == ILACE_FIELD && v->second_field) + marker = VC1_CODE_FIELD; + else + marker = VC1_CODE_FRAME; + + /* Only insert the marker if not already present in the bitstream */ + marker_size = (size >= sizeof(marker) && AV_RB32(buffer) != marker) ? sizeof(marker) : 0; + + tmp = av_fast_realloc(ctx->bitstream_internal, &ctx->bitstream_allocated, + ctx->bitstream_len + size + marker_size); + if (!tmp) + return AVERROR(ENOMEM); + ctx->bitstream = ctx->bitstream_internal = tmp; + + tmp = av_fast_realloc(ctx->slice_offsets, &ctx->slice_offsets_allocated, + (ctx->nb_slices + 1) * sizeof(*ctx->slice_offsets)); + if (!tmp) + return AVERROR(ENOMEM); + ctx->slice_offsets = tmp; + + if (marker_size) + AV_WB32(ctx->bitstream_internal + ctx->bitstream_len, marker); + + memcpy(ctx->bitstream_internal + ctx->bitstream_len + marker_size, buffer, size); + ctx->slice_offsets[ctx->nb_slices] = ctx->bitstream_len; + ctx->bitstream_len += size + marker_size; + ctx->nb_slices++; + + return 0; +} + static int nvdec_vc1_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { @@ -121,7 +166,7 @@ const FFHWAccel ff_vc1_nvdec_hwaccel = { .p.pix_fmt = AV_PIX_FMT_CUDA, .start_frame = nvdec_vc1_start_frame, .end_frame = ff_nvdec_simple_end_frame, - .decode_slice = ff_nvdec_simple_decode_slice, + .decode_slice = nvdec_vc1_decode_slice, .frame_params = nvdec_vc1_frame_params, .init = ff_nvdec_decode_init, .uninit = ff_nvdec_decode_uninit, diff --git a/libavcodec/nvdec_vp8.c b/libavcodec/nvdec_vp8.c index ff3b3f259..e273a6ec3 100644 --- a/libavcodec/nvdec_vp8.c +++ b/libavcodec/nvdec_vp8.c @@ -32,7 +32,9 @@ static unsigned char safe_get_ref_idx(VP8Frame *frame) return frame ? ff_nvdec_get_ref_idx(frame->tf.f) : 255; } -static int nvdec_vp8_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_vp8_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { VP8Context *h = avctx->priv_data; @@ -48,7 +50,7 @@ static int nvdec_vp8_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvdec_vp9.c b/libavcodec/nvdec_vp9.c index e196391c6..f83ff9381 100644 --- a/libavcodec/nvdec_vp9.c +++ b/libavcodec/nvdec_vp9.c @@ -29,7 +29,9 @@ #include "internal.h" #include "vp9shared.h" -static int nvdec_vp9_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_vp9_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { VP9SharedContext *h = avctx->priv_data; const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); @@ -47,7 +49,7 @@ static int nvdec_vp9_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index 2cce478be..392230526 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -34,12 +34,15 @@ #include "libavutil/imgutils.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" +#include "libavutil/timecode_internal.h" #include "libavutil/mathematics.h" +#include "libavutil/mastering_display_metadata.h" +#include "libavutil/stereo3d.h" +#include "libavutil/tdrdi.h" #include "atsc_a53.h" #include "codec_desc.h" #include "encode.h" #include "internal.h" -#include "packet_internal.h" #define CHECK_CU(x) FF_CUDA_CHECK_DL(avctx, dl_fn->cuda_dl, x) @@ -59,6 +62,12 @@ const enum AVPixelFormat ff_nvenc_pix_fmts[] = { AV_PIX_FMT_P010, AV_PIX_FMT_YUV444P, AV_PIX_FMT_P016, // Truncated to 10bits +#ifdef NVENC_HAVE_422_SUPPORT + AV_PIX_FMT_NV16, + AV_PIX_FMT_P210, + AV_PIX_FMT_P216, +#endif + AV_PIX_FMT_YUV444P10MSB, AV_PIX_FMT_YUV444P16, // Truncated to 10bits AV_PIX_FMT_0RGB32, AV_PIX_FMT_RGB32, @@ -67,6 +76,7 @@ const enum AVPixelFormat ff_nvenc_pix_fmts[] = { AV_PIX_FMT_X2RGB10, AV_PIX_FMT_X2BGR10, AV_PIX_FMT_GBRP, + AV_PIX_FMT_GBRP10MSB, AV_PIX_FMT_GBRP16, // Truncated to 10bits AV_PIX_FMT_CUDA, #if CONFIG_D3D11VA @@ -85,11 +95,15 @@ const AVCodecHWConfigInternal *const ff_nvenc_hw_configs[] = { NULL, }; -#define IS_10BIT(pix_fmt) (pix_fmt == AV_PIX_FMT_P010 || \ - pix_fmt == AV_PIX_FMT_P016 || \ - pix_fmt == AV_PIX_FMT_YUV444P16 || \ - pix_fmt == AV_PIX_FMT_X2RGB10 || \ - pix_fmt == AV_PIX_FMT_X2BGR10 || \ +#define IS_10BIT(pix_fmt) (pix_fmt == AV_PIX_FMT_P010 || \ + pix_fmt == AV_PIX_FMT_P016 || \ + pix_fmt == AV_PIX_FMT_P210 || \ + pix_fmt == AV_PIX_FMT_P216 || \ + pix_fmt == AV_PIX_FMT_YUV444P10MSB || \ + pix_fmt == AV_PIX_FMT_YUV444P16 || \ + pix_fmt == AV_PIX_FMT_X2RGB10 || \ + pix_fmt == AV_PIX_FMT_X2BGR10 || \ + pix_fmt == AV_PIX_FMT_GBRP10MSB || \ pix_fmt == AV_PIX_FMT_GBRP16) #define IS_RGB(pix_fmt) (pix_fmt == AV_PIX_FMT_0RGB32 || \ @@ -99,13 +113,20 @@ const AVCodecHWConfigInternal *const ff_nvenc_hw_configs[] = { pix_fmt == AV_PIX_FMT_X2RGB10 || \ pix_fmt == AV_PIX_FMT_X2BGR10) -#define IS_YUV444(pix_fmt) (pix_fmt == AV_PIX_FMT_YUV444P || \ - pix_fmt == AV_PIX_FMT_YUV444P16 || \ - pix_fmt == AV_PIX_FMT_GBRP || \ - pix_fmt == AV_PIX_FMT_GBRP16 || \ +#define IS_YUV444(pix_fmt) (pix_fmt == AV_PIX_FMT_YUV444P || \ + pix_fmt == AV_PIX_FMT_YUV444P10MSB || \ + pix_fmt == AV_PIX_FMT_YUV444P16 || \ + pix_fmt == AV_PIX_FMT_GBRP || \ + pix_fmt == AV_PIX_FMT_GBRP10MSB || \ + pix_fmt == AV_PIX_FMT_GBRP16 || \ (ctx->rgb_mode == NVENC_RGB_MODE_444 && IS_RGB(pix_fmt))) -#define IS_GBRP(pix_fmt) (pix_fmt == AV_PIX_FMT_GBRP || \ +#define IS_YUV422(pix_fmt) (pix_fmt == AV_PIX_FMT_NV16 || \ + pix_fmt == AV_PIX_FMT_P210 || \ + pix_fmt == AV_PIX_FMT_P216) + +#define IS_GBRP(pix_fmt) (pix_fmt == AV_PIX_FMT_GBRP || \ + pix_fmt == AV_PIX_FMT_GBRP10MSB || \ pix_fmt == AV_PIX_FMT_GBRP16) static const struct { @@ -242,8 +263,10 @@ static void nvenc_map_preset(NvencContext *ctx) static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level) { -#if NVENCAPI_CHECK_VERSION(12, 3) +#if NVENCAPI_CHECK_VERSION(13, 1) const char *minver = "(unknown)"; +#elif NVENCAPI_CHECK_VERSION(13, 0) + const char *minver = "570.0"; #elif NVENCAPI_CHECK_VERSION(12, 2) # if defined(_WIN32) || defined(__CYGWIN__) const char *minver = "551.76"; @@ -314,6 +337,16 @@ static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level) av_log(avctx, level, "The minimum required Nvidia driver for nvenc is %s or newer\n", minver); } +#if NVENCAPI_CHECK_VERSION(12, 0) +#define to_nv_color_matrix(n) (NV_ENC_VUI_MATRIX_COEFFS)(n) +#define to_nv_color_pri(n) (NV_ENC_VUI_COLOR_PRIMARIES)(n) +#define to_nv_color_trc(n) (NV_ENC_VUI_TRANSFER_CHARACTERISTIC)(n) +#else +#define to_nv_color_matrix(n) (uint32_t)(n) +#define to_nv_color_pri(n) (uint32_t)(n) +#define to_nv_color_trc(n) (uint32_t)(n) +#endif + static av_cold int nvenc_load_libraries(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; @@ -477,6 +510,16 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) return AVERROR(ENOSYS); } +#ifdef NVENC_HAVE_422_SUPPORT + ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_YUV422_ENCODE); +#else + ret = 0; +#endif + if (IS_YUV422(ctx->data_pix_fmt) && ret <= 0) { + av_log(avctx, AV_LOG_WARNING, "YUV422P not supported\n"); + return AVERROR(ENOSYS); + } + ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE); if (ctx->flags & NVENC_LOSSLESS && ret <= 0) { av_log(avctx, AV_LOG_WARNING, "Lossless encoding not supported\n"); @@ -606,7 +649,7 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) return AVERROR(ENOSYS); } -#ifdef NVENC_HAVE_TEMPORAL_FILTER +#if defined(NVENC_HAVE_TEMPORAL_FILTER) || defined(NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER) ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_TEMPORAL_FILTER); if(ctx->tf_level > 0 && ret <= 0) { av_log(avctx, AV_LOG_WARNING, "Temporal filtering not supported by the device\n"); @@ -635,6 +678,14 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) ctx->support_dyn_bitrate = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE); +#ifdef NVENC_HAVE_MVHEVC + ctx->multiview_supported = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_MVHEVC_ENCODE) > 0; + if(ctx->profile == NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN && !ctx->multiview_supported) { + av_log(avctx, AV_LOG_WARNING, "Multiview not supported by the device\n"); + return AVERROR(ENOSYS); + } +#endif + return 0; } @@ -863,8 +914,8 @@ static av_cold void set_constqp(AVCodecContext *avctx) rc->constQP.qpIntra = av_clip(ctx->cqp * fabs(avctx->i_quant_factor) + avctx->i_quant_offset + 0.5, 0, qmax); } - avctx->qmin = -1; - avctx->qmax = -1; + avctx->qmin = ctx->qmin = -1; + avctx->qmax = ctx->qmax = -1; } static av_cold void set_vbr(AVCodecContext *avctx) @@ -878,27 +929,37 @@ static av_cold void set_vbr(AVCodecContext *avctx) int qmax = 51; #endif - if (avctx->qmin >= 0 && avctx->qmax >= 0) { + if (avctx->qmin >= 0 || avctx->qmax >= 0) + av_log(avctx, AV_LOG_WARNING, "Passing qmin/qmax via global AVCodecContext options. Use encoder options instead.\n"); + + if (avctx->qmin >= 0 && ctx->qmin < 0) + ctx->qmin = avctx->qmin; + if (avctx->qmax >= 0 && ctx->qmax < 0) + ctx->qmax = avctx->qmax; + avctx->qmin = ctx->qmin; + avctx->qmax = ctx->qmax; + + if (ctx->qmin >= 0 && ctx->qmax >= 0) { rc->enableMinQP = 1; rc->enableMaxQP = 1; - rc->minQP.qpInterB = avctx->qmin; - rc->minQP.qpInterP = avctx->qmin; - rc->minQP.qpIntra = avctx->qmin; + rc->minQP.qpInterB = ctx->qmin; + rc->minQP.qpInterP = ctx->qmin; + rc->minQP.qpIntra = ctx->qmin; - rc->maxQP.qpInterB = avctx->qmax; - rc->maxQP.qpInterP = avctx->qmax; - rc->maxQP.qpIntra = avctx->qmax; + rc->maxQP.qpInterB = ctx->qmax; + rc->maxQP.qpInterP = ctx->qmax; + rc->maxQP.qpIntra = ctx->qmax; - qp_inter_p = (avctx->qmax + 3 * avctx->qmin) / 4; // biased towards Qmin - } else if (avctx->qmin >= 0) { + qp_inter_p = (ctx->qmax + 3 * ctx->qmin) / 4; // biased towards Qmin + } else if (ctx->qmin >= 0) { rc->enableMinQP = 1; - rc->minQP.qpInterB = avctx->qmin; - rc->minQP.qpInterP = avctx->qmin; - rc->minQP.qpIntra = avctx->qmin; + rc->minQP.qpInterB = ctx->qmin; + rc->minQP.qpInterP = ctx->qmin; + rc->minQP.qpIntra = ctx->qmin; - qp_inter_p = avctx->qmin; + qp_inter_p = ctx->qmin; } else { qp_inter_p = 26; // default to 26 } @@ -944,8 +1005,8 @@ static av_cold void set_lossless(AVCodecContext *avctx) rc->constQP.qpInterP = 0; rc->constQP.qpIntra = 0; - avctx->qmin = -1; - avctx->qmax = -1; + avctx->qmin = ctx->qmin = -1; + avctx->qmax = ctx->qmax = -1; } static void nvenc_override_rate_control(AVCodecContext *avctx) @@ -959,7 +1020,7 @@ static void nvenc_override_rate_control(AVCodecContext *avctx) return; #ifndef NVENC_NO_DEPRECATED_RC case NV_ENC_PARAMS_RC_VBR_MINQP: - if (avctx->qmin < 0) { + if (avctx->qmin < 0 && ctx->qmin < 0) { av_log(avctx, AV_LOG_WARNING, "The variable bitrate rate-control requires " "the 'qmin' option set.\n"); @@ -1082,7 +1143,8 @@ static av_cold int nvenc_setup_rate_control(AVCodecContext *avctx) ctx->rc = NV_ENC_PARAMS_RC_CONSTQP; } else if (ctx->twopass) { ctx->rc = NV_ENC_PARAMS_RC_VBR_HQ; - } else if (avctx->qmin >= 0 && avctx->qmax >= 0) { + } else if ((avctx->qmin >= 0 && avctx->qmax >= 0) || + (ctx->qmin >= 0 && ctx->qmax >= 0)) { ctx->rc = NV_ENC_PARAMS_RC_VBR_MINQP; } } @@ -1214,14 +1276,14 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(ctx->data_pix_fmt); if ((pixdesc->flags & AV_PIX_FMT_FLAG_RGB) && !IS_GBRP(ctx->data_pix_fmt)) { - vui->colourMatrix = AVCOL_SPC_BT470BG; - vui->colourPrimaries = avctx->color_primaries; - vui->transferCharacteristics = avctx->color_trc; + vui->colourMatrix = to_nv_color_matrix(AVCOL_SPC_BT470BG); + vui->colourPrimaries = to_nv_color_pri(avctx->color_primaries); + vui->transferCharacteristics = to_nv_color_trc(avctx->color_trc); vui->videoFullRangeFlag = 0; } else { - vui->colourMatrix = IS_GBRP(ctx->data_pix_fmt) ? AVCOL_SPC_RGB : avctx->colorspace; - vui->colourPrimaries = avctx->color_primaries; - vui->transferCharacteristics = avctx->color_trc; + vui->colourMatrix = to_nv_color_matrix(IS_GBRP(ctx->data_pix_fmt) ? AVCOL_SPC_RGB : avctx->colorspace); + vui->colourPrimaries = to_nv_color_pri(avctx->color_primaries); + vui->transferCharacteristics = to_nv_color_trc(avctx->color_trc); vui->videoFullRangeFlag = (avctx->color_range == AVCOL_RANGE_JPEG || ctx->data_pix_fmt == AV_PIX_FMT_YUVJ420P || ctx->data_pix_fmt == AV_PIX_FMT_YUVJ422P || ctx->data_pix_fmt == AV_PIX_FMT_YUVJ444P); } @@ -1247,6 +1309,7 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) h264->intraRefreshPeriod = cc->gopLength; h264->intraRefreshCnt = cc->gopLength - 1; cc->gopLength = NVENC_INFINITE_GOPLENGTH; + h264->outputRecoveryPointSEI = 1; #ifdef NVENC_HAVE_SINGLE_SLICE_INTRA_REFRESH h264->singleSliceIntraRefresh = ctx->single_slice_intra_refresh; #endif @@ -1267,7 +1330,12 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) h264->idrPeriod = cc->gopLength; if (IS_CBR(cc->rcParams.rateControlMode)) { - h264->outputBufferingPeriodSEI = 1; + /* Older SDKs use outputBufferingPeriodSEI to control filler data */ + h264->outputBufferingPeriodSEI = ctx->cbr_padding; + +#ifdef NVENC_HAVE_FILLER_DATA + h264->enableFillerDataInsertion = ctx->cbr_padding; +#endif } h264->outputPictureTimingSEI = 1; @@ -1297,6 +1365,18 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID; avctx->profile = AV_PROFILE_H264_HIGH; break; +#ifdef NVENC_HAVE_H264_10BIT_SUPPORT + case NV_ENC_H264_PROFILE_HIGH_10: + cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_10_GUID; + avctx->profile = AV_PROFILE_H264_HIGH_10; + break; +#endif +#ifdef NVENC_HAVE_422_SUPPORT + case NV_ENC_H264_PROFILE_HIGH_422: + cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_422_GUID; + avctx->profile = AV_PROFILE_H264_HIGH_422; + break; +#endif case NV_ENC_H264_PROFILE_HIGH_444P: cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID; avctx->profile = AV_PROFILE_H264_HIGH_444_PREDICTIVE; @@ -1304,19 +1384,37 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) } } +#ifdef NVENC_HAVE_H264_10BIT_SUPPORT + // force setting profile as high10 if input is 10 bit or if it should be encoded as 10 bit + if (IS_10BIT(ctx->data_pix_fmt) || ctx->highbitdepth) { + cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_10_GUID; + avctx->profile = AV_PROFILE_H264_HIGH_10; + } +#endif + // force setting profile as high444p if input is AV_PIX_FMT_YUV444P if (IS_YUV444(ctx->data_pix_fmt)) { cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID; avctx->profile = AV_PROFILE_H264_HIGH_444_PREDICTIVE; } - h264->chromaFormatIDC = avctx->profile == AV_PROFILE_H264_HIGH_444_PREDICTIVE ? 3 : 1; +#ifdef NVENC_HAVE_422_SUPPORT + // force setting profile as high422p if input is AV_PIX_FMT_YUV422P + if (IS_YUV422(ctx->data_pix_fmt)) { + cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_422_GUID; + avctx->profile = AV_PROFILE_H264_HIGH_422; + } +#endif + + vui->bitstreamRestrictionFlag = cc->gopLength != 1 || avctx->profile < AV_PROFILE_H264_HIGH; + + h264->chromaFormatIDC = IS_YUV444(ctx->data_pix_fmt) ? 3 : IS_YUV422(ctx->data_pix_fmt) ? 2 : 1; h264->level = ctx->level; #ifdef NVENC_HAVE_NEW_BIT_DEPTH_API - h264->inputBitDepth = h264->outputBitDepth = - IS_10BIT(ctx->data_pix_fmt) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; + h264->inputBitDepth = IS_10BIT(ctx->data_pix_fmt) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; + h264->outputBitDepth = (IS_10BIT(ctx->data_pix_fmt) || ctx->highbitdepth) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; #endif if (ctx->coder >= 0) @@ -1332,6 +1430,30 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) h264->numRefL1 = avctx->refs; #endif +#ifdef NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER + if (ctx->tf_level >= 0) { + h264->tfLevel = ctx->tf_level; + + switch (ctx->tf_level) + { + case NV_ENC_TEMPORAL_FILTER_LEVEL_0: + case NV_ENC_TEMPORAL_FILTER_LEVEL_4: + break; + default: + av_log(avctx, AV_LOG_ERROR, "Invalid temporal filtering level.\n"); + return AVERROR(EINVAL); + } + + if (ctx->encode_config.frameIntervalP < 5) + av_log(avctx, AV_LOG_WARNING, "Temporal filtering needs at least 4 B-Frames (-bf 4).\n"); + } +#endif + +#ifdef NVENC_HAVE_TIME_CODE + if (ctx->s12m_tc) + h264->enableTimeCode = 1; +#endif + return 0; } @@ -1345,14 +1467,14 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(ctx->data_pix_fmt); if ((pixdesc->flags & AV_PIX_FMT_FLAG_RGB) && !IS_GBRP(ctx->data_pix_fmt)) { - vui->colourMatrix = AVCOL_SPC_BT470BG; - vui->colourPrimaries = avctx->color_primaries; - vui->transferCharacteristics = avctx->color_trc; + vui->colourMatrix = to_nv_color_matrix(AVCOL_SPC_BT470BG); + vui->colourPrimaries = to_nv_color_pri(avctx->color_primaries); + vui->transferCharacteristics = to_nv_color_trc(avctx->color_trc); vui->videoFullRangeFlag = 0; } else { - vui->colourMatrix = IS_GBRP(ctx->data_pix_fmt) ? AVCOL_SPC_RGB : avctx->colorspace; - vui->colourPrimaries = avctx->color_primaries; - vui->transferCharacteristics = avctx->color_trc; + vui->colourMatrix = to_nv_color_matrix(IS_GBRP(ctx->data_pix_fmt) ? AVCOL_SPC_RGB : avctx->colorspace); + vui->colourPrimaries = to_nv_color_pri(avctx->color_primaries); + vui->transferCharacteristics = to_nv_color_trc(avctx->color_trc); vui->videoFullRangeFlag = (avctx->color_range == AVCOL_RANGE_JPEG || ctx->data_pix_fmt == AV_PIX_FMT_YUVJ420P || ctx->data_pix_fmt == AV_PIX_FMT_YUVJ422P || ctx->data_pix_fmt == AV_PIX_FMT_YUVJ444P); } @@ -1378,11 +1500,23 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) hevc->intraRefreshPeriod = cc->gopLength; hevc->intraRefreshCnt = cc->gopLength - 1; cc->gopLength = NVENC_INFINITE_GOPLENGTH; +#ifdef NVENC_HAVE_HEVC_OUTPUT_RECOVERY_POINT_SEI + hevc->outputRecoveryPointSEI = 1; +#endif #ifdef NVENC_HAVE_SINGLE_SLICE_INTRA_REFRESH hevc->singleSliceIntraRefresh = ctx->single_slice_intra_refresh; #endif } +#ifdef NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA + ctx->mdm = hevc->outputMasteringDisplay = !!av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + ctx->cll = hevc->outputMaxCll = !!av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); +#endif + #ifdef NVENC_HAVE_HEVC_CONSTRAINED_ENCODING if (ctx->constrained_encoding) hevc->enableConstrainedEncoding = 1; @@ -1400,11 +1534,36 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) hevc->idrPeriod = cc->gopLength; if (IS_CBR(cc->rcParams.rateControlMode)) { - hevc->outputBufferingPeriodSEI = 1; + /* Older SDKs use outputBufferingPeriodSEI to control filler data */ + hevc->outputBufferingPeriodSEI = ctx->cbr_padding; + +#ifdef NVENC_HAVE_FILLER_DATA + hevc->enableFillerDataInsertion = ctx->cbr_padding; +#endif } hevc->outputPictureTimingSEI = 1; +#ifdef NVENC_HAVE_MVHEVC + if (ctx->multiview_supported && (ctx->profile == NV_ENC_HEVC_PROFILE_MAIN || ctx->profile == NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN)) { + const AVFrameSideData *sd_stereo3d = av_frame_side_data_get(avctx->decoded_side_data, avctx->nb_decoded_side_data, AV_FRAME_DATA_STEREO3D); + const AVFrameSideData *sd_tdrdi = av_frame_side_data_get(avctx->decoded_side_data, avctx->nb_decoded_side_data, AV_FRAME_DATA_3D_REFERENCE_DISPLAYS); + const AVStereo3D *stereo3d = sd_stereo3d ? (const AVStereo3D*)sd_stereo3d->data : NULL; + + if (sd_tdrdi && stereo3d && stereo3d->type == AV_STEREO3D_FRAMESEQUENCE) + ctx->profile = NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN; + + if (ctx->profile == NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN && stereo3d && + stereo3d->type != AV_STEREO3D_2D && + stereo3d->type != AV_STEREO3D_UNSPEC && + stereo3d->type != AV_STEREO3D_FRAMESEQUENCE) + { + av_log(avctx, AV_LOG_WARNING, "Unsupported multiview input, disabling multiview encoding.\n"); + ctx->profile = NV_ENC_HEVC_PROFILE_MAIN; + } + } +#endif + switch (ctx->profile) { case NV_ENC_HEVC_PROFILE_MAIN: cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID; @@ -1418,6 +1577,18 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) cc->profileGUID = NV_ENC_HEVC_PROFILE_FREXT_GUID; avctx->profile = AV_PROFILE_HEVC_REXT; break; +#ifdef NVENC_HAVE_MVHEVC + case NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN: + cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID; + avctx->profile = AV_PROFILE_HEVC_MULTIVIEW_MAIN; + ctx->multiview = 1; + + hevc->enableMVHEVC = 1; + hevc->outputHevc3DReferenceDisplayInfo = 1; + + av_log(avctx, AV_LOG_VERBOSE, "Enabling MV HEVC encoding.\n"); + break; +#endif } // force setting profile as main10 if input is 10 bit or if it should be encoded as 10 bit @@ -1426,13 +1597,20 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) avctx->profile = AV_PROFILE_HEVC_MAIN_10; } - // force setting profile as rext if input is yuv444 - if (IS_YUV444(ctx->data_pix_fmt)) { + // force setting profile as rext if input is yuv444 or yuv422 + if (IS_YUV444(ctx->data_pix_fmt) || IS_YUV422(ctx->data_pix_fmt)) { cc->profileGUID = NV_ENC_HEVC_PROFILE_FREXT_GUID; avctx->profile = AV_PROFILE_HEVC_REXT; } - hevc->chromaFormatIDC = IS_YUV444(ctx->data_pix_fmt) ? 3 : 1; +#ifdef NVENC_HAVE_MVHEVC + if (ctx->multiview && avctx->profile != AV_PROFILE_HEVC_MULTIVIEW_MAIN) { + av_log(avctx, AV_LOG_ERROR, "Multiview encoding only works for Main profile content.\n"); + return AVERROR(EINVAL); + } +#endif + + hevc->chromaFormatIDC = IS_YUV444(ctx->data_pix_fmt) ? 3 : IS_YUV422(ctx->data_pix_fmt) ? 2 : 1; #ifdef NVENC_HAVE_NEW_BIT_DEPTH_API hevc->inputBitDepth = IS_10BIT(ctx->data_pix_fmt) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; @@ -1487,14 +1665,14 @@ static av_cold int nvenc_setup_av1_config(AVCodecContext *avctx) const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(ctx->data_pix_fmt); if ((pixdesc->flags & AV_PIX_FMT_FLAG_RGB) && !IS_GBRP(ctx->data_pix_fmt)) { - av1->matrixCoefficients = AVCOL_SPC_BT470BG; - av1->colorPrimaries = avctx->color_primaries; - av1->transferCharacteristics = avctx->color_trc; + av1->matrixCoefficients = to_nv_color_matrix(AVCOL_SPC_BT470BG); + av1->colorPrimaries = to_nv_color_pri(avctx->color_primaries); + av1->transferCharacteristics = to_nv_color_trc(avctx->color_trc); av1->colorRange = 0; } else { - av1->matrixCoefficients = IS_GBRP(ctx->data_pix_fmt) ? AVCOL_SPC_RGB : avctx->colorspace; - av1->colorPrimaries = avctx->color_primaries; - av1->transferCharacteristics = avctx->color_trc; + av1->matrixCoefficients = to_nv_color_matrix(IS_GBRP(ctx->data_pix_fmt) ? AVCOL_SPC_RGB : avctx->colorspace); + av1->colorPrimaries = to_nv_color_pri(avctx->color_primaries); + av1->transferCharacteristics = to_nv_color_trc(avctx->color_trc); av1->colorRange = (avctx->color_range == AVCOL_RANGE_JPEG || ctx->data_pix_fmt == AV_PIX_FMT_YUVJ420P || ctx->data_pix_fmt == AV_PIX_FMT_YUVJ422P || ctx->data_pix_fmt == AV_PIX_FMT_YUVJ444P); } @@ -1522,7 +1700,7 @@ static av_cold int nvenc_setup_av1_config(AVCodecContext *avctx) av1->idrPeriod = cc->gopLength; if (IS_CBR(cc->rcParams.rateControlMode)) { - av1->enableBitstreamPadding = 1; + av1->enableBitstreamPadding = ctx->cbr_padding; } if (ctx->tile_cols >= 0) @@ -1551,12 +1729,40 @@ static av_cold int nvenc_setup_av1_config(AVCodecContext *avctx) av1->pixelBitDepthMinus8 = (IS_10BIT(ctx->data_pix_fmt) || ctx->highbitdepth) ? 2 : 0; #endif +#ifdef NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA + ctx->mdm = av1->outputMasteringDisplay = !!av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + ctx->cll = av1->outputMaxCll = !!av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); +#endif + if (ctx->b_ref_mode >= 0) av1->useBFramesAsRef = ctx->b_ref_mode; av1->numFwdRefs = avctx->refs; av1->numBwdRefs = avctx->refs; +#ifdef NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER + if (ctx->tf_level >= 0) { + av1->tfLevel = ctx->tf_level; + + switch (ctx->tf_level) + { + case NV_ENC_TEMPORAL_FILTER_LEVEL_0: + case NV_ENC_TEMPORAL_FILTER_LEVEL_4: + break; + default: + av_log(avctx, AV_LOG_ERROR, "Invalid temporal filtering level.\n"); + return AVERROR(EINVAL); + } + + if (ctx->encode_config.frameIntervalP < 5) + av_log(avctx, AV_LOG_WARNING, "Temporal filtering needs at least 4 B-Frames (-bf 4).\n"); + } +#endif + return 0; } #endif @@ -1669,13 +1875,7 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) ctx->init_encode_params.frameRateDen = avctx->framerate.den; } else { ctx->init_encode_params.frameRateNum = avctx->time_base.den; -FF_DISABLE_DEPRECATION_WARNINGS - ctx->init_encode_params.frameRateDen = avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + ctx->init_encode_params.frameRateDen = avctx->time_base.num; } #ifdef NVENC_HAVE_UNIDIR_B @@ -1807,7 +2007,9 @@ static NV_ENC_BUFFER_FORMAT nvenc_map_buffer_format(enum AVPixelFormat pix_fmt) case AV_PIX_FMT_YUV444P: return NV_ENC_BUFFER_FORMAT_YUV444; case AV_PIX_FMT_GBRP16: + case AV_PIX_FMT_GBRP10MSB: case AV_PIX_FMT_YUV444P16: + case AV_PIX_FMT_YUV444P10MSB: return NV_ENC_BUFFER_FORMAT_YUV444_10BIT; case AV_PIX_FMT_0RGB32: case AV_PIX_FMT_RGB32: @@ -1819,6 +2021,13 @@ static NV_ENC_BUFFER_FORMAT nvenc_map_buffer_format(enum AVPixelFormat pix_fmt) return NV_ENC_BUFFER_FORMAT_ARGB10; case AV_PIX_FMT_X2BGR10: return NV_ENC_BUFFER_FORMAT_ABGR10; +#ifdef NVENC_HAVE_422_SUPPORT + case AV_PIX_FMT_NV16: + return NV_ENC_BUFFER_FORMAT_NV16; + case AV_PIX_FMT_P210: + case AV_PIX_FMT_P216: + return NV_ENC_BUFFER_FORMAT_P210; +#endif default: return NV_ENC_BUFFER_FORMAT_UNDEFINED; } @@ -2288,7 +2497,52 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame, } } -static void nvenc_codec_specific_pic_params(AVCodecContext *avctx, +#ifdef NVENC_HAVE_TIME_CODE +static void nvenc_fill_time_code(AVCodecContext *avctx, const AVFrame *frame, NV_ENC_TIME_CODE *time_code) +{ + AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE); + + if (sd) { + uint32_t *tc = (uint32_t*)sd->data; + int cnt = FFMIN(tc[0], FF_ARRAY_ELEMS(time_code->clockTimestamp)); + + switch (cnt) { + case 0: + time_code->displayPicStruct = NV_ENC_PIC_STRUCT_DISPLAY_FRAME; + time_code->skipClockTimestampInsertion = 1; + break; + case 2: + time_code->displayPicStruct = NV_ENC_PIC_STRUCT_DISPLAY_FRAME_DOUBLING; + break; + case 3: + time_code->displayPicStruct = NV_ENC_PIC_STRUCT_DISPLAY_FRAME_TRIPLING; + break; + default: + time_code->displayPicStruct = NV_ENC_PIC_STRUCT_DISPLAY_FRAME; + break; + } + + for (int i = 0; i < cnt; i++) { + unsigned hh, mm, ss, ff, drop; + ff_timecode_set_smpte(&drop, &hh, &mm, &ss, &ff, avctx->framerate, tc[i + 1], 0, 0); + + time_code->clockTimestamp[i].countingType = 0; + time_code->clockTimestamp[i].discontinuityFlag = 0; + time_code->clockTimestamp[i].cntDroppedFrames = drop; + time_code->clockTimestamp[i].nFrames = ff; + time_code->clockTimestamp[i].secondsValue = ss; + time_code->clockTimestamp[i].minutesValue = mm; + time_code->clockTimestamp[i].hoursValue = hh; + time_code->clockTimestamp[i].timeOffset = 0; + } + } else { + time_code->displayPicStruct = NV_ENC_PIC_STRUCT_DISPLAY_FRAME; + time_code->skipClockTimestampInsertion = 1; + } +} +#endif + +static void nvenc_codec_specific_pic_params(AVCodecContext *avctx, const AVFrame *frame, NV_ENC_PIC_PARAMS *params, NV_ENC_SEI_PAYLOAD *sei_data, int sei_count) @@ -2306,6 +2560,11 @@ static void nvenc_codec_specific_pic_params(AVCodecContext *avctx, params->codecPicParams.h264PicParams.seiPayloadArrayCnt = sei_count; } +#ifdef NVENC_HAVE_TIME_CODE + if (ctx->s12m_tc) + nvenc_fill_time_code(avctx, frame, ¶ms->codecPicParams.h264PicParams.timeCode); +#endif + break; case AV_CODEC_ID_HEVC: params->codecPicParams.hevcPicParams.sliceMode = @@ -2373,6 +2632,9 @@ static int nvenc_set_timestamp(AVCodecContext *avctx, // This can be more than necessary, but we don't know the real reorder delay. delay = FFMAX(ctx->encode_config.frameIntervalP - 1, 0); +#ifdef NVENC_HAVE_MVHEVC + delay *= ctx->multiview ? 2 : 1; +#endif if (ctx->output_frame_num >= delay) { pkt->dts = timestamp_queue_dequeue(ctx->timestamp_list); ctx->output_frame_num++; @@ -2536,7 +2798,7 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur goto error; } - ff_side_data_set_encoder_stats(pkt, + ff_encode_add_stats_side_data(pkt, (lock_params.frameAvgQP - 1) * FF_QP2LAMBDA, NULL, 0, pict_type); res = nvenc_set_timestamp(avctx, &lock_params, pkt); @@ -2607,7 +2869,7 @@ static int prepare_sei_data_array(AVCodecContext *avctx, const AVFrame *frame) } } - if (ctx->s12m_tc && av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE)) { + if (ctx->s12m_tc && avctx->codec->id != AV_CODEC_ID_H264 && av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE)) { void *tc_data = NULL; size_t tc_size = 0; @@ -2772,6 +3034,78 @@ static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame) } } +#ifdef NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA +static int nvenc_set_mastering_display_data(AVCodecContext *avctx, const AVFrame *frame, NV_ENC_PIC_PARAMS *pic_params, + MASTERING_DISPLAY_INFO *mastering_disp_info, CONTENT_LIGHT_LEVEL *content_light_level) +{ + NvencContext *ctx = avctx->priv_data; + + if (ctx->mdm || ctx->cll) { + const AVFrameSideData *sd_mdm = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + const AVFrameSideData *sd_cll = av_frame_get_side_data(frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + const int chroma_den = (avctx->codec->id == AV_CODEC_ID_AV1) ? 1 << 16 : 50000; + const int max_luma_den = (avctx->codec->id == AV_CODEC_ID_AV1) ? 1 << 8 : 10000; + const int min_luma_den = (avctx->codec->id == AV_CODEC_ID_AV1) ? 1 << 14 : 10000; + + if (!sd_mdm) + sd_mdm = av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + if (!sd_cll) + sd_cll = av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + + if (sd_mdm) { + const AVMasteringDisplayMetadata *mdm = (AVMasteringDisplayMetadata *)sd_mdm->data; + + mastering_disp_info->r.x = av_rescale(mdm->display_primaries[0][0].num, chroma_den, + mdm->display_primaries[0][0].den); + mastering_disp_info->r.y = av_rescale(mdm->display_primaries[0][1].num, chroma_den, + mdm->display_primaries[0][1].den); + mastering_disp_info->g.x = av_rescale(mdm->display_primaries[1][0].num, chroma_den, + mdm->display_primaries[1][0].den); + mastering_disp_info->g.y = av_rescale(mdm->display_primaries[1][1].num, chroma_den, + mdm->display_primaries[1][1].den); + mastering_disp_info->b.x = av_rescale(mdm->display_primaries[2][0].num, chroma_den, + mdm->display_primaries[2][0].den); + mastering_disp_info->b.y = av_rescale(mdm->display_primaries[2][1].num, chroma_den, + mdm->display_primaries[2][1].den); + mastering_disp_info->whitePoint.x = av_rescale(mdm->white_point[0].num, chroma_den, + mdm->white_point[0].den); + mastering_disp_info->whitePoint.y = av_rescale(mdm->white_point[1].num, chroma_den, + mdm->white_point[1].den); + mastering_disp_info->maxLuma = av_rescale(mdm->max_luminance.num, max_luma_den, + mdm->max_luminance.den); + mastering_disp_info->minLuma = av_rescale(mdm->min_luminance.num, min_luma_den, + mdm->min_luminance.den); + + if (avctx->codec->id == AV_CODEC_ID_HEVC) + pic_params->codecPicParams.hevcPicParams.pMasteringDisplay = mastering_disp_info; + else if (avctx->codec->id == AV_CODEC_ID_AV1) + pic_params->codecPicParams.av1PicParams.pMasteringDisplay = mastering_disp_info; + else + return AVERROR_BUG; + } + if (sd_cll) { + const AVContentLightMetadata *cll = (AVContentLightMetadata *)sd_cll->data; + + content_light_level->maxContentLightLevel = cll->MaxCLL; + content_light_level->maxPicAverageLightLevel = cll->MaxFALL; + + if (avctx->codec->id == AV_CODEC_ID_HEVC) + pic_params->codecPicParams.hevcPicParams.pMaxCll = content_light_level; + else if (avctx->codec->id == AV_CODEC_ID_AV1) + pic_params->codecPicParams.av1PicParams.pMaxCll = content_light_level; + else + return AVERROR_BUG; + } + } + + return 0; +} +#endif + static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) { NVENCSTATUS nv_status; @@ -2779,6 +3113,13 @@ static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) int res, res2; int sei_count = 0; int i; +#ifdef NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA + MASTERING_DISPLAY_INFO mastering_disp_info = { 0 }; + CONTENT_LIGHT_LEVEL content_light_level = { 0 }; +#endif +#ifdef NVENC_HAVE_MVHEVC + HEVC_3D_REFERENCE_DISPLAY_INFO ref_disp_info = { 0 }; +#endif NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; @@ -2843,11 +3184,64 @@ static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) sei_count = res; } +#ifdef NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA + res = nvenc_set_mastering_display_data(avctx, frame, &pic_params, &mastering_disp_info, &content_light_level); + if (res < 0) + return res; +#endif + +#ifdef NVENC_HAVE_MVHEVC + if (ctx->multiview) { + const AVFrameSideData *sd_tdrdi = av_frame_get_side_data(frame, AV_FRAME_DATA_3D_REFERENCE_DISPLAYS); + const AVFrameSideData *sd_view_id = av_frame_get_side_data(frame, AV_FRAME_DATA_VIEW_ID); + + if (sd_view_id) + ctx->next_view_id = *(int*)sd_view_id->data; + + pic_params.codecPicParams.hevcPicParams.viewId = ctx->next_view_id; + + if (sd_tdrdi) { + AV3DReferenceDisplaysInfo *tdrdi = (AV3DReferenceDisplaysInfo*)sd_tdrdi->data; + + ref_disp_info.refViewingDistanceFlag = tdrdi->ref_viewing_distance_flag; + ref_disp_info.precRefViewingDist = tdrdi->prec_ref_viewing_dist; + ref_disp_info.precRefDisplayWidth = tdrdi->prec_ref_display_width; + + ref_disp_info.numRefDisplaysMinus1 = tdrdi->num_ref_displays - 1; + + for (i = 0; i < tdrdi->num_ref_displays && + i < FF_ARRAY_ELEMS(ref_disp_info.leftViewId); i++) { + const AV3DReferenceDisplay *display = av_tdrdi_get_display(tdrdi, i); + ref_disp_info.leftViewId[i] = display->left_view_id; + ref_disp_info.rightViewId[i] = display->right_view_id; + ref_disp_info.exponentRefDisplayWidth[i] = display->exponent_ref_display_width; + ref_disp_info.mantissaRefDisplayWidth[i] = display->mantissa_ref_display_width; + ref_disp_info.exponentRefViewingDistance[i] = display->exponent_ref_viewing_distance; + ref_disp_info.mantissaRefViewingDistance[i] = display->mantissa_ref_viewing_distance; + ref_disp_info.additionalShiftPresentFlag[i] = display->additional_shift_present_flag; + ref_disp_info.numSampleShiftPlus512[i] = display->num_sample_shift + 512; + } + + pic_params.codecPicParams.hevcPicParams.p3DReferenceDisplayInfo = &ref_disp_info; + ctx->display_sei_sent = 1; + } else if (!ctx->display_sei_sent) { + ref_disp_info.precRefDisplayWidth = 31; + ref_disp_info.leftViewId[0] = 0; + ref_disp_info.rightViewId[0] = 1; + + pic_params.codecPicParams.hevcPicParams.p3DReferenceDisplayInfo = &ref_disp_info; + ctx->display_sei_sent = 1; + } + + ctx->next_view_id = !ctx->next_view_id; + } +#endif + res = nvenc_store_frame_data(avctx, &pic_params, frame); if (res < 0) return res; - nvenc_codec_specific_pic_params(avctx, &pic_params, ctx->sei_data, sei_count); + nvenc_codec_specific_pic_params(avctx, frame, &pic_params, ctx->sei_data, sei_count); } else { pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS; } diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index 0130b9936..069ba82bc 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -61,6 +61,7 @@ typedef void ID3D11Device; #define NVENC_HAVE_MULTIPLE_REF_FRAMES #define NVENC_HAVE_CUSTREAM_PTR #define NVENC_HAVE_GETLASTERRORSTRING +#define NVENC_HAVE_FILLER_DATA #endif // SDK 10.0 compile time feature checks @@ -78,6 +79,11 @@ typedef void ID3D11Device; #define NVENC_HAVE_SINGLE_SLICE_INTRA_REFRESH #endif +// SDK 12.0 compile time feature checks +#if NVENCAPI_CHECK_VERSION(12, 0) +#define NVENC_HAVE_HEVC_OUTPUT_RECOVERY_POINT_SEI +#endif + // SDK 12.1 compile time feature checks #if NVENCAPI_CHECK_VERSION(12, 1) #define NVENC_NO_DEPRECATED_RC @@ -91,6 +97,18 @@ typedef void ID3D11Device; #define NVENC_HAVE_LOOKAHEAD_LEVEL #define NVENC_HAVE_UHQ_TUNING #define NVENC_HAVE_UNIDIR_B +#define NVENC_HAVE_TIME_CODE // added in 12.0, but incomplete until 12.2 +#endif + +// SDK 13.0 compile time feature checks +#if NVENCAPI_CHECK_VERSION(13, 0) +#define NVENC_HAVE_H264_10BIT_SUPPORT +#define NVENC_HAVE_422_SUPPORT +#define NVENC_HAVE_SFE_FOUR_WAYS_SUPPORT +#define NVENC_HAVE_AV1_UHQ_TUNING +#define NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER +#define NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA +#define NVENC_HAVE_MVHEVC #endif typedef struct NvencSurface @@ -151,6 +169,12 @@ enum { NV_ENC_H264_PROFILE_BASELINE, NV_ENC_H264_PROFILE_MAIN, NV_ENC_H264_PROFILE_HIGH, +#ifdef NVENC_HAVE_H264_10BIT_SUPPORT + NV_ENC_H264_PROFILE_HIGH_10, +#endif +#ifdef NVENC_HAVE_422_SUPPORT + NV_ENC_H264_PROFILE_HIGH_422, +#endif NV_ENC_H264_PROFILE_HIGH_444P, }; @@ -158,6 +182,11 @@ enum { NV_ENC_HEVC_PROFILE_MAIN, NV_ENC_HEVC_PROFILE_MAIN_10, NV_ENC_HEVC_PROFILE_REXT, +#ifdef NVENC_HAVE_MVHEVC + NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN, +#endif + + NV_ENC_HEVC_PROFILE_COUNT }; enum { @@ -231,6 +260,7 @@ typedef struct NvencContext void *nvencoder; uint32_t frame_idx_counter; + uint32_t next_view_id; int preset; int profile; @@ -257,6 +287,8 @@ typedef struct NvencContext float quality; int aud; int bluray_compat; + int qmin; + int qmax; int init_qp_p; int init_qp_b; int init_qp_i; @@ -285,6 +317,10 @@ typedef struct NvencContext int lookahead_level; int unidir_b; int split_encode_mode; + int mdm, cll; + int cbr_padding; + int multiview, multiview_supported; + int display_sei_sent; } NvencContext; int ff_nvenc_encode_init(AVCodecContext *avctx); diff --git a/libavcodec/nvenc_av1.c b/libavcodec/nvenc_av1.c index 79253cff6..98fcc76e3 100644 --- a/libavcodec/nvenc_av1.c +++ b/libavcodec/nvenc_av1.c @@ -38,8 +38,11 @@ static const AVOption options[] = { { "p5", "slow (good quality)", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_P5 }, 0, 0, VE, .unit = "preset" }, { "p6", "slower (better quality)", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_P6 }, 0, 0, VE, .unit = "preset" }, { "p7", "slowest (best quality)", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_P7 }, 0, 0, VE, .unit = "preset" }, - { "tune", "Set the encoding tuning info", OFFSET(tuning_info), AV_OPT_TYPE_INT, { .i64 = NV_ENC_TUNING_INFO_HIGH_QUALITY }, NV_ENC_TUNING_INFO_HIGH_QUALITY, NV_ENC_TUNING_INFO_LOSSLESS, VE, .unit = "tune" }, + { "tune", "Set the encoding tuning info", OFFSET(tuning_info), AV_OPT_TYPE_INT, { .i64 = NV_ENC_TUNING_INFO_HIGH_QUALITY }, NV_ENC_TUNING_INFO_HIGH_QUALITY, NV_ENC_TUNING_INFO_COUNT - 1, VE, .unit = "tune" }, { "hq", "High quality", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_HIGH_QUALITY }, 0, 0, VE, .unit = "tune" }, +#ifdef NVENC_HAVE_AV1_UHQ_TUNING + { "uhq", "Ultra high quality", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_ULTRA_HIGH_QUALITY }, 0, 0, VE, .unit = "tune" }, +#endif { "ll", "Low latency", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_LOW_LATENCY }, 0, 0, VE, .unit = "tune" }, { "ull", "Ultra low latency", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "tune" }, { "lossless", "Lossless", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_LOSSLESS }, 0, 0, VE, .unit = "tune" }, @@ -116,6 +119,10 @@ static const AVOption options[] = { OFFSET(qp_cb_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, { "qp_cr_offset", "Quantization parameter offset for cr channel", OFFSET(qp_cr_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, + { "qmin", "Specifies the minimum QP used for rate control", + OFFSET(qmin), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, VE }, + { "qmax", "Specifies the maximum QP used for rate control", + OFFSET(qmax), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, VE }, { "no-scenecut", "When lookahead is enabled, set this to 1 to disable adaptive I-frame insertion at scene cuts", OFFSET(no_scenecut), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "forced-idr", "If forcing keyframes, force them as IDR frames.", @@ -136,7 +143,7 @@ static const AVOption options[] = { { "b_ref_mode", "Use B frames as references", OFFSET(b_ref_mode), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, NV_ENC_BFRAME_REF_MODE_MIDDLE, VE, .unit = "b_ref_mode" }, { "disabled", "B frames will not be used for reference", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_BFRAME_REF_MODE_DISABLED }, 0, 0, VE, .unit = "b_ref_mode" }, { "each", "Each B frame will be used for reference", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_BFRAME_REF_MODE_EACH }, 0, 0, VE, .unit = "b_ref_mode" }, - { "middle", "Only (number of B frames)/2 will be used for reference", 0,AV_OPT_TYPE_CONST, { .i64 = NV_ENC_BFRAME_REF_MODE_MIDDLE }, 0, 0, VE, .unit = "b_ref_mode" }, + { "middle", "Every other B-frame as Altref2 reference, except last in Altref interval", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_BFRAME_REF_MODE_MIDDLE }, 0, 0, VE, .unit = "b_ref_mode" }, { "dpb_size", "Specifies the DPB size used for encoding (0 means automatic)", OFFSET(dpb_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "ldkfs", "Low delay key frame scale; Specifies the Scene Change frame size increase allowed in case of single frame VBV and CBR", @@ -149,6 +156,14 @@ static const AVOption options[] = { OFFSET(extra_sei), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, { "s12m_tc", "Use timecode (if available)", OFFSET(s12m_tc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, + { "cbr_padding", "Pad the bitstream to ensure bitrate does not drop below the target in CBR mode", + OFFSET(cbr_padding), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#ifdef NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER + { "tf_level", "Specifies the strength of the temporal filtering", + OFFSET(tf_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE, .unit = "tf_level" }, + { "0", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TEMPORAL_FILTER_LEVEL_0 }, 0, 0, VE, .unit = "tf_level" }, + { "4", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TEMPORAL_FILTER_LEVEL_4 }, 0, 0, VE, .unit = "tf_level" }, +#endif #ifdef NVENC_HAVE_LOOKAHEAD_LEVEL { "lookahead_level", "Specifies the lookahead level. Higher level may improve quality at the expense of performance.", OFFSET(lookahead_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, NV_ENC_LOOKAHEAD_LEVEL_AUTOSELECT, VE, .unit = "lookahead_level" }, @@ -165,6 +180,9 @@ static const AVOption options[] = { { "forced", "Enabled with number of horizontal strips selected by the driver", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_AUTO_FORCED_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, { "2", "Enabled with number of horizontal strips forced to 2 when number of NVENCs > 1", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_TWO_FORCED_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, { "3", "Enabled with number of horizontal strips forced to 3 when number of NVENCs > 2", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_THREE_FORCED_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, +#ifdef NVENC_HAVE_SFE_FOUR_WAYS_SUPPORT + { "4", "Enabled with number of horizontal strips forced to 4 when number of NVENCs > 3", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_FOUR_FORCED_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, +#endif #endif { NULL } }; @@ -201,7 +219,7 @@ const FFCodec ff_av1_nvenc_encoder = { .priv_data_size = sizeof(NvencContext), .p.priv_class = &av1_nvenc_class, .defaults = defaults, - .p.pix_fmts = ff_nvenc_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_nvenc_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1 | diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c index 8cbe4dca3..842e4eef6 100644 --- a/libavcodec/nvenc_h264.c +++ b/libavcodec/nvenc_h264.c @@ -61,6 +61,12 @@ static const AVOption options[] = { { "baseline", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_BASELINE }, 0, 0, VE, .unit = "profile" }, { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_MAIN }, 0, 0, VE, .unit = "profile" }, { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_HIGH }, 0, 0, VE, .unit = "profile" }, +#ifdef NVENC_HAVE_H264_10BIT_SUPPORT + { "high10", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_HIGH_10 }, 0, 0, VE, .unit = "profile" }, +#endif +#ifdef NVENC_HAVE_422_SUPPORT + { "high422", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_HIGH_422 }, 0, 0, VE, .unit = "profile" }, +#endif { "high444p", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_HIGH_444P }, 0, 0, VE, .unit = "profile" }, #ifdef NVENC_HAVE_H264_LVL6 { "level", "Set the encoding level restriction", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = NV_ENC_LEVEL_AUTOSELECT }, NV_ENC_LEVEL_AUTOSELECT, NV_ENC_LEVEL_H264_62, VE, .unit = "level" }, @@ -168,6 +174,10 @@ static const AVOption options[] = { OFFSET(qp_cb_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, { "qp_cr_offset", "Quantization parameter offset for cr channel", OFFSET(qp_cr_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, + { "qmin", "Specifies the minimum QP used for rate control", + OFFSET(qmin), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qmax", "Specifies the maximum QP used for rate control", + OFFSET(qmax), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, { "weighted_pred","Set 1 to enable weighted prediction", OFFSET(weighted_pred),AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, { "coder", "Coder type", OFFSET(coder), AV_OPT_TYPE_INT, { .i64 = -1 },-1, 2, VE, .unit = "coder" }, @@ -189,6 +199,9 @@ static const AVOption options[] = { { "middle", "", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, VE, .unit = "b_ref_mode" }, #endif { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, +#ifdef NVENC_HAVE_TIME_CODE + { "s12m_tc", "Use timecode (if available)", OFFSET(s12m_tc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, +#endif { "dpb_size", "Specifies the DPB size used for encoding (0 means automatic)", OFFSET(dpb_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, #ifdef NVENC_HAVE_MULTIPASS @@ -199,6 +212,9 @@ static const AVOption options[] = { { "fullres", "Two Pass encoding is enabled where first Pass is full resolution", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TWO_PASS_FULL_RESOLUTION }, 0, 0, VE, .unit = "multipass" }, #endif +#ifdef NVENC_HAVE_H264_10BIT_SUPPORT + { "highbitdepth", "Enable 10 bit encode for 8 bit input",OFFSET(highbitdepth),AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#endif #ifdef NVENC_HAVE_LDKFS { "ldkfs", "Low delay key frame scale; Specifies the Scene Change frame size increase allowed in case of single frame VBV and CBR", OFFSET(ldkfs), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, UCHAR_MAX, VE }, @@ -215,6 +231,16 @@ static const AVOption options[] = { OFFSET(max_slice_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "constrained-encoding", "Enable constrainedFrame encoding where each slice in the constrained picture is independent of other slices", OFFSET(constrained_encoding), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#ifdef NVENC_HAVE_FILLER_DATA + { "cbr_padding", "Pad the bitstream to ensure bitrate does not drop below the target in CBR mode", + OFFSET(cbr_padding), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#endif +#ifdef NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER + { "tf_level", "Specifies the strength of the temporal filtering", + OFFSET(tf_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE, .unit = "tf_level" }, + { "0", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TEMPORAL_FILTER_LEVEL_0 }, 0, 0, VE, .unit = "tf_level" }, + { "4", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TEMPORAL_FILTER_LEVEL_4 }, 0, 0, VE, .unit = "tf_level" }, +#endif #ifdef NVENC_HAVE_LOOKAHEAD_LEVEL { "lookahead_level", "Specifies the lookahead level. Higher level may improve quality at the expense of performance.", OFFSET(lookahead_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, NV_ENC_LOOKAHEAD_LEVEL_AUTOSELECT, VE, .unit = "lookahead_level" }, @@ -264,7 +290,7 @@ const FFCodec ff_h264_nvenc_encoder = { AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = ff_nvenc_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_nvenc_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.wrapper_name = "nvenc", .hw_configs = ff_nvenc_hw_configs, diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c index 5696e14dd..31624f45b 100644 --- a/libavcodec/nvenc_hevc.c +++ b/libavcodec/nvenc_hevc.c @@ -60,10 +60,13 @@ static const AVOption options[] = { { "ull", "Ultra low latency", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "tune" }, { "lossless", "Lossless", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_LOSSLESS }, 0, 0, VE, .unit = "tune" }, #endif - { "profile", "Set the encoding profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = NV_ENC_HEVC_PROFILE_MAIN }, NV_ENC_HEVC_PROFILE_MAIN, AV_PROFILE_HEVC_REXT, VE, .unit = "profile" }, + { "profile", "Set the encoding profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = NV_ENC_HEVC_PROFILE_MAIN }, NV_ENC_HEVC_PROFILE_MAIN, NV_ENC_HEVC_PROFILE_COUNT - 1, VE, .unit = "profile" }, { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_HEVC_PROFILE_MAIN }, 0, 0, VE, .unit = "profile" }, { "main10", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_HEVC_PROFILE_MAIN_10 }, 0, 0, VE, .unit = "profile" }, { "rext", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_HEVC_PROFILE_REXT }, 0, 0, VE, .unit = "profile" }, +#ifdef NVENC_HAVE_MVHEVC + { "mv", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN }, 0, 0, VE, .unit = "profile" }, +#endif { "level", "Set the encoding level restriction", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = NV_ENC_LEVEL_AUTOSELECT }, NV_ENC_LEVEL_AUTOSELECT, NV_ENC_LEVEL_HEVC_62, VE, .unit = "level" }, { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LEVEL_AUTOSELECT }, 0, 0, VE, .unit = "level" }, { "1", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LEVEL_HEVC_1 }, 0, 0, VE, .unit = "level" }, @@ -133,6 +136,8 @@ static const AVOption options[] = { OFFSET(no_scenecut), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "forced-idr", "If forcing keyframes, force them as IDR frames.", OFFSET(forced_idr), AV_OPT_TYPE_BOOL, { .i64 = 0 }, -1, 1, VE }, + { "b_adapt", "When lookahead is enabled, set this to 0 to disable adaptive B-frame decision", + OFFSET(b_adapt), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, { "spatial_aq", "set to 1 to enable Spatial AQ", OFFSET(aq), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "spatial-aq", "set to 1 to enable Spatial AQ", OFFSET(aq), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "temporal_aq", "set to 1 to enable Temporal AQ", OFFSET(temporal_aq), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, @@ -158,6 +163,10 @@ static const AVOption options[] = { OFFSET(qp_cb_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, { "qp_cr_offset", "Quantization parameter offset for cr channel", OFFSET(qp_cr_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, + { "qmin", "Specifies the minimum QP used for rate control", + OFFSET(qmin), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qmax", "Specifies the maximum QP used for rate control", + OFFSET(qmax), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, { "weighted_pred","Set 1 to enable weighted prediction", OFFSET(weighted_pred),AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, #ifdef NVENC_HAVE_HEVC_BFRAME_REF_MODE @@ -202,6 +211,10 @@ static const AVOption options[] = { OFFSET(max_slice_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "constrained-encoding", "Enable constrainedFrame encoding where each slice in the constrained picture is independent of other slices", OFFSET(constrained_encoding), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#ifdef NVENC_HAVE_FILLER_DATA + { "cbr_padding", "Pad the bitstream to ensure bitrate does not drop below the target in CBR mode", + OFFSET(cbr_padding), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#endif #ifdef NVENC_HAVE_TEMPORAL_FILTER { "tf_level", "Specifies the strength of the temporal filtering", OFFSET(tf_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE, .unit = "tf_level" }, @@ -227,6 +240,9 @@ static const AVOption options[] = { { "forced", "Enabled with number of horizontal strips selected by the driver", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_AUTO_FORCED_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, { "2", "Enabled with number of horizontal strips forced to 2 when number of NVENCs > 1", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_TWO_FORCED_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, { "3", "Enabled with number of horizontal strips forced to 3 when number of NVENCs > 2", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_THREE_FORCED_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, +#ifdef NVENC_HAVE_SFE_FOUR_WAYS_SUPPORT + { "4", "Enabled with number of horizontal strips forced to 4 when number of NVENCs > 3", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_FOUR_FORCED_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, +#endif #endif { NULL } }; @@ -263,7 +279,7 @@ const FFCodec ff_hevc_nvenc_encoder = { .priv_data_size = sizeof(NvencContext), .p.priv_class = &hevc_nvenc_class, .defaults = defaults, - .p.pix_fmts = ff_nvenc_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_nvenc_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1 | diff --git a/libavcodec/ohcodec.c b/libavcodec/ohcodec.c new file mode 100644 index 000000000..f8a6faaba --- /dev/null +++ b/libavcodec/ohcodec.c @@ -0,0 +1,79 @@ +/* + * This file is part of FFmpeg. + * + * Copyright (c) 2025 Zhao Zhili + * + * 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 "ohcodec.h" + +#include "libavutil/error.h" + +int ff_oh_err_to_ff_err(OH_AVErrCode err) +{ + switch (err) { + case AV_ERR_OK: + return 0; + case AV_ERR_NO_MEMORY: + return AVERROR(ENOMEM); + case AV_ERR_OPERATE_NOT_PERMIT: + return AVERROR(EPERM); + case AV_ERR_INVALID_VAL: + return AVERROR(EINVAL); + case AV_ERR_IO: + return AVERROR(EIO); + case AV_ERR_TIMEOUT: + return AVERROR(ETIMEDOUT); + case AV_ERR_UNKNOWN: + return AVERROR_UNKNOWN; + case AV_ERR_SERVICE_DIED: + return AVERROR_EXTERNAL; + case AV_ERR_INVALID_STATE: + return AVERROR(EINVAL); + case AV_ERR_UNSUPPORT: + return AVERROR(ENOTSUP); + default: + return AVERROR_EXTERNAL; + } +} + +static const struct { + OH_AVPixelFormat oh_pix; + enum AVPixelFormat pix; +} oh_pix_map[] = { + {AV_PIXEL_FORMAT_NV12, AV_PIX_FMT_NV12}, + {AV_PIXEL_FORMAT_NV21, AV_PIX_FMT_NV21}, + {AV_PIXEL_FORMAT_YUVI420, AV_PIX_FMT_YUV420P}, + {AV_PIXEL_FORMAT_SURFACE_FORMAT, AV_PIX_FMT_OHCODEC}, +}; + +enum AVPixelFormat ff_oh_pix_to_ff_pix(OH_AVPixelFormat oh_pix) +{ + for (size_t i = 0; i < FF_ARRAY_ELEMS(oh_pix_map); i++) + if (oh_pix_map[i].oh_pix == oh_pix) + return oh_pix_map[i].pix; + + return AV_PIX_FMT_NONE; +} + +int ff_oh_pix_from_ff_pix(enum AVPixelFormat pix) +{ + for (size_t i = 0; i < FF_ARRAY_ELEMS(oh_pix_map); i++) + if (oh_pix_map[i].pix == pix) + return oh_pix_map[i].oh_pix; + + return 0; +} diff --git a/libavcodec/ohcodec.h b/libavcodec/ohcodec.h new file mode 100644 index 000000000..074747247 --- /dev/null +++ b/libavcodec/ohcodec.h @@ -0,0 +1,57 @@ +/* + * This file is part of FFmpeg. + * + * Copyright (c) 2025 Zhao Zhili + * + * 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_OHCODEC_H +#define AVCODEC_OHCODEC_H + +#include +#include +#include +#include + +#include "libavutil/pixfmt.h" + +#include "codec_id.h" + +typedef struct OHBufferQueueItem { + uint32_t index; + OH_AVBuffer *buffer; +} OHBufferQueueItem; + +int ff_oh_err_to_ff_err(OH_AVErrCode err); + +static inline const char *ff_oh_mime(enum AVCodecID codec_id, void *log) +{ + switch (codec_id) { + case AV_CODEC_ID_H264: + return OH_AVCODEC_MIMETYPE_VIDEO_AVC; + case AV_CODEC_ID_HEVC: + return OH_AVCODEC_MIMETYPE_VIDEO_HEVC; + default: + av_log(log, AV_LOG_ERROR, "Unsupported codec %s\n", + avcodec_get_name(codec_id)); + return NULL; + } +} + +enum AVPixelFormat ff_oh_pix_to_ff_pix(OH_AVPixelFormat oh_pix); +int ff_oh_pix_from_ff_pix(enum AVPixelFormat pix); + +#endif diff --git a/libavcodec/ohdec.c b/libavcodec/ohdec.c new file mode 100644 index 000000000..943b02768 --- /dev/null +++ b/libavcodec/ohdec.c @@ -0,0 +1,769 @@ +/* + * This file is part of FFmpeg. + * + * Copyright (c) 2025 Zhao Zhili + * + * 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 "config_components.h" + +#include +#include +#include + +#include "libavutil/fifo.h" +#include "libavutil/hwcontext_oh.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/refstruct.h" +#include "libavutil/thread.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "decode.h" +#include "hwconfig.h" +#include "ohcodec.h" +#include "pthread_internal.h" + +typedef struct OHCodecDecContext { + AVClass *avclass; + OH_AVCodec *dec; + /* A RefStruct reference backing dec. Each hardware frame has a reference count to + * dec. dec will be destroyed only after oh_decode_close and all hardware + * frames have been released. + */ + OH_AVCodec **dec_ref; + + AVMutex input_mutex; + AVCond input_cond; + AVFifo *input_queue; + + AVMutex output_mutex; + AVCond output_cond; + AVFifo *output_queue; + + AVPacket pkt; + + int decode_status; + bool eof_sent; + + bool output_to_window; + bool got_stream_info; + int width; + int height; + int stride; + int slice_height; + OH_AVPixelFormat pix_fmt; + + char *name; + int allow_sw; + unsigned mutex_cond_cnt; +} OHCodecDecContext; + +#define OFFSET(x) offsetof(OHCodecDecContext, x) +DEFINE_OFFSET_ARRAY(OHCodecDecContext, mutex_cond, mutex_cond_cnt, + (OFFSET(input_mutex), OFFSET(output_mutex)), + (OFFSET(input_cond), OFFSET(output_cond))); + +typedef struct OHCodecBuffer { + uint32_t index; + OH_AVBuffer *buffer; + OH_AVCodec **dec_ref; ///< RefStruct reference +} OHCodecBuffer; + +static void oh_decode_release(AVRefStructOpaque unused, void *obj) +{ + OH_AVCodec **decp = obj; + OH_AVErrCode err = OH_VideoDecoder_Destroy(*decp); + if (err == AV_ERR_OK) + av_log(NULL, AV_LOG_DEBUG, "Destroy decoder success\n"); + else + av_log(NULL, AV_LOG_ERROR, "Destroy decoder failed, %d, %s\n", + err, av_err2str(ff_oh_err_to_ff_err(err))); +} + +static int oh_decode_create(OHCodecDecContext *s, AVCodecContext *avctx) +{ + const char *name = s->name; + + if (!name) { + const char *mime = ff_oh_mime(avctx->codec_id, avctx); + if (!mime) + return AVERROR_BUG; + OH_AVCapability *cap = OH_AVCodec_GetCapabilityByCategory(mime, false, HARDWARE); + if (!cap) { + if (!s->allow_sw) { + av_log(avctx, AV_LOG_ERROR, "Failed to get hardware codec %s\n", mime); + return AVERROR_EXTERNAL; + } + av_log(avctx, AV_LOG_WARNING, + "Failed to get hardware codec %s, try software backend\n", mime); + cap = OH_AVCodec_GetCapabilityByCategory(mime, false, SOFTWARE); + if (!cap) { + av_log(avctx, AV_LOG_ERROR, "Failed to get software codec %s\n", mime); + return AVERROR_EXTERNAL; + } + } + name = OH_AVCapability_GetName(cap); + if (!name) + return AVERROR_EXTERNAL; + } + + s->dec = OH_VideoDecoder_CreateByName(name); + if (!s->dec) { + av_log(avctx, AV_LOG_ERROR, "Create decoder with name %s failed\n", name); + return AVERROR_EXTERNAL; + } + av_log(avctx, AV_LOG_DEBUG, "Create decoder %s success\n", name); + + s->dec_ref = av_refstruct_alloc_ext(sizeof(*s->dec_ref), 0, NULL, oh_decode_release); + if (!s->dec_ref) { + oh_decode_release((AVRefStructOpaque){.nc = NULL }, &s->dec); + s->dec = NULL; + return AVERROR(ENOMEM); + } + *s->dec_ref = s->dec; + + return 0; +} + +static int oh_decode_set_format(OHCodecDecContext *s, AVCodecContext *avctx) +{ + int ret; + OHNativeWindow *window = NULL; + + if (avctx->hw_device_ctx) { + AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)(avctx->hw_device_ctx->data); + if (device_ctx->type == AV_HWDEVICE_TYPE_OHCODEC) { + AVOHCodecDeviceContext *dev = device_ctx->hwctx; + window = dev->native_window; + s->output_to_window = true; + } else { + av_log(avctx, AV_LOG_WARNING, "Ignore invalid hw device type %s\n", + av_hwdevice_get_type_name(device_ctx->type)); + } + } + + if (avctx->width <= 0 || avctx->height <= 0) { + av_log(avctx, AV_LOG_ERROR, + "Invalid width/height (%dx%d), width and height are mandatory for ohcodec\n", + avctx->width, avctx->height); + return AVERROR(EINVAL); + } + + OH_AVFormat *format = OH_AVFormat_Create(); + if (!format) + return AVERROR(ENOMEM); + + OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, avctx->width); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, avctx->height); + if (!s->output_to_window) + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, + AV_PIXEL_FORMAT_NV12); + else + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, + AV_PIXEL_FORMAT_SURFACE_FORMAT); + OH_AVErrCode err = OH_VideoDecoder_Configure(s->dec, format); + OH_AVFormat_Destroy(format); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Decoder configure failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + + if (s->output_to_window) { + err = OH_VideoDecoder_SetSurface(s->dec, window); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Set surface failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + } + + return 0; +} + +static void oh_decode_on_err(OH_AVCodec *codec, int32_t err, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecDecContext *s = avctx->priv_data; + + // Careful on the lock order. + // Always lock input first. + ff_mutex_lock(&s->input_mutex); + ff_mutex_lock(&s->output_mutex); + s->decode_status = ff_oh_err_to_ff_err(err); + ff_mutex_unlock(&s->output_mutex); + ff_mutex_unlock(&s->input_mutex); + + ff_cond_signal(&s->output_cond); + ff_cond_signal(&s->input_cond); +} + +static void oh_decode_on_stream_changed(OH_AVCodec *codec, OH_AVFormat *format, + void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecDecContext *s = avctx->priv_data; + int32_t n; + double d; + + if (!OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_WIDTH, &s->width) || + !OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_HEIGHT, &s->height) || + !OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &s->stride) || + !OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, + &s->slice_height)) { + av_log(avctx, AV_LOG_ERROR, "Get dimension info from format failed\n"); + goto out; + } + + if (ff_set_dimensions(avctx, s->width, s->height) < 0) + goto out; + + if (s->stride <= 0 || s->slice_height <= 0) { + av_log(avctx, AV_LOG_ERROR, + "Buffer stride (%d) or slice height (%d) is invalid\n", + s->stride, s->slice_height); + goto out; + } + + if (OH_AVFormat_GetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, &n)) { + s->pix_fmt = n; + /* When use output_to_window, the returned format is the memory + * layout of hardware frame, not AV_PIXEL_FORMAT_SURFACE_FORMAT as + * expected. + */ + if (s->output_to_window) + avctx->pix_fmt = AV_PIX_FMT_OHCODEC; + else + avctx->pix_fmt = ff_oh_pix_to_ff_pix(s->pix_fmt); + // Check whether this pixel format is supported + if (avctx->pix_fmt == AV_PIX_FMT_NONE) { + av_log(avctx, AV_LOG_ERROR, "Unsupported OH_AVPixelFormat %d\n", + n); + goto out; + } + } else { + av_log(avctx, AV_LOG_ERROR, "Failed to get pixel format\n"); + goto out; + } + + if (OH_AVFormat_GetIntValue(format, + OH_MD_KEY_MATRIX_COEFFICIENTS, + &n)) + avctx->colorspace = n; + if (OH_AVFormat_GetIntValue(format, + OH_MD_KEY_COLOR_PRIMARIES, + &n)) + avctx->color_primaries = n; + if (OH_AVFormat_GetIntValue(format, + OH_MD_KEY_TRANSFER_CHARACTERISTICS, + &n)) + avctx->color_trc = n; + if (OH_AVFormat_GetIntValue(format, + OH_MD_KEY_RANGE_FLAG, + &n)) + avctx->color_range = n ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + + if (OH_AVFormat_GetDoubleValue(format, OH_MD_KEY_VIDEO_SAR, &d)) { + AVRational sar = av_d2q(d, 4096 * 4); + ff_set_sar(avctx, sar); + } + + s->got_stream_info = true; + + return; +out: + av_log(avctx, AV_LOG_ERROR, "Invalid format from decoder: %s\n", + OH_AVFormat_DumpInfo(format)); + oh_decode_on_err(codec, AV_ERR_UNKNOWN, userdata); +} + +static void oh_decode_on_need_input(OH_AVCodec *codec, uint32_t index, + OH_AVBuffer *buffer, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecDecContext *s = avctx->priv_data; + OHBufferQueueItem item = { + index, buffer, + }; + + ff_mutex_lock(&s->input_mutex); + int ret = av_fifo_write(s->input_queue, &item, 1); + if (ret >= 0) + ff_cond_signal(&s->input_cond); + ff_mutex_unlock(&s->input_mutex); + + if (ret < 0) + oh_decode_on_err(codec, AV_ERR_NO_MEMORY, userdata); +} + +static void oh_decode_on_output(OH_AVCodec *codec, uint32_t index, + OH_AVBuffer *buffer, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecDecContext *s = avctx->priv_data; + OHBufferQueueItem item = { + index, buffer, + }; + + ff_mutex_lock(&s->output_mutex); + int ret = av_fifo_write(s->output_queue, &item, 1); + if (ret >= 0) + ff_cond_signal(&s->output_cond); + ff_mutex_unlock(&s->output_mutex); + + if (ret < 0) + oh_decode_on_err(codec, AV_ERR_NO_MEMORY, userdata); +} + +static int oh_decode_start(OHCodecDecContext *s, AVCodecContext *avctx) +{ + int ret; + OH_AVErrCode err; + OH_AVCodecCallback cb = { + .onError = oh_decode_on_err, + .onStreamChanged = oh_decode_on_stream_changed, + .onNeedInputBuffer = oh_decode_on_need_input, + .onNewOutputBuffer = oh_decode_on_output, + }; + + err = OH_VideoDecoder_RegisterCallback(s->dec, cb, avctx); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Register callback failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + err = OH_VideoDecoder_Prepare(s->dec); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Prepare failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + err = OH_VideoDecoder_Start(s->dec); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Start failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + + return 0; +} + +static av_cold int oh_decode_init(AVCodecContext *avctx) +{ + OHCodecDecContext *s = avctx->priv_data; + + // Initialize these fields first, so oh_decode_close can destroy them safely + int ret = ff_pthread_init(s, mutex_cond_offsets); + if (ret < 0) + return ret; + + ret = oh_decode_create(s, avctx); + if (ret < 0) + return ret; + ret = oh_decode_set_format(s, avctx); + if (ret < 0) + return ret; + + size_t fifo_size = 16; + s->input_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem), + AV_FIFO_FLAG_AUTO_GROW); + s->output_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem), + AV_FIFO_FLAG_AUTO_GROW); + if (!s->input_queue || !s->output_queue) + return AVERROR(ENOMEM); + + ret = oh_decode_start(s, avctx); + if (ret < 0) + return ret; + + return 0; +} + +static av_cold int oh_decode_close(AVCodecContext *avctx) +{ + OHCodecDecContext *s = avctx->priv_data; + + if (s->dec) { + /* Stop but don't destroy dec directly, to keep hardware frames on + * the fly valid. + */ + OH_AVErrCode err = OH_VideoDecoder_Stop(s->dec); + if (err == AV_ERR_OK) + av_log(avctx, AV_LOG_DEBUG, "Stop decoder success\n"); + else + av_log(avctx, AV_LOG_ERROR, "Stop decoder failed, %d, %s\n", + err, av_err2str(ff_oh_err_to_ff_err(err))); + s->dec = NULL; + av_refstruct_unref(&s->dec_ref); + } + + av_packet_unref(&s->pkt); + + av_fifo_freep2(&s->input_queue); + + av_fifo_freep2(&s->output_queue); + + ff_pthread_free(s, mutex_cond_offsets); + + return 0; +} + +static void oh_buffer_release(void *opaque, uint8_t *data) +{ + if (!opaque) + return; + + OHCodecBuffer *buffer = opaque; + + if (buffer->buffer) { + OH_AVCodec *dec = *buffer->dec_ref; + OH_AVCodecBufferAttr attr; + OH_AVErrCode err = OH_AVBuffer_GetBufferAttr(buffer->buffer, &attr); + if (err == AV_ERR_OK && !(attr.flags & AVCODEC_BUFFER_FLAGS_DISCARD)) + OH_VideoDecoder_RenderOutputBuffer(dec, buffer->index); + else + OH_VideoDecoder_FreeOutputBuffer(dec, buffer->index); + } + + av_refstruct_unref(&buffer->dec_ref); + av_free(buffer); +} + +static int oh_decode_wrap_hw_buffer(AVCodecContext *avctx, AVFrame *frame, + OHBufferQueueItem *output, + const OH_AVCodecBufferAttr *attr) +{ + OHCodecDecContext *s = avctx->priv_data; + + frame->width = s->width; + frame->height = s->height; + int ret = ff_decode_frame_props(avctx, frame); + if (ret < 0) + return ret; + + frame->format = AV_PIX_FMT_OHCODEC; + OHCodecBuffer *buffer = av_mallocz(sizeof(*buffer)); + if (!buffer) + return AVERROR(ENOMEM); + + buffer->dec_ref = av_refstruct_ref(s->dec_ref); + + buffer->index = output->index; + buffer->buffer = output->buffer; + frame->buf[0] = av_buffer_create((uint8_t *)buffer->buffer, 1, + oh_buffer_release, + buffer, AV_BUFFER_FLAG_READONLY); + if (!frame->buf[0]) { + oh_buffer_release(buffer, NULL); + return AVERROR(ENOMEM); + } + // Point to OH_AVBuffer + frame->data[3] = frame->buf[0]->data; + frame->pts = av_rescale_q(attr->pts, AV_TIME_BASE_Q, avctx->pkt_timebase); + frame->pkt_dts = AV_NOPTS_VALUE; + + return 0; +} + +static int oh_decode_wrap_sw_buffer(AVCodecContext *avctx, AVFrame *frame, + OHBufferQueueItem *output, + const OH_AVCodecBufferAttr *attr) +{ + OHCodecDecContext *s = avctx->priv_data; + + frame->format = avctx->pix_fmt; + frame->width = s->width; + frame->height = s->height; + int ret = ff_get_buffer(avctx, frame, 0); + if (ret < 0) + return ret; + + frame->pts = av_rescale_q(attr->pts, AV_TIME_BASE_Q, avctx->pkt_timebase); + frame->pkt_dts = AV_NOPTS_VALUE; + + uint8_t *p = OH_AVBuffer_GetAddr(output->buffer); + if (!p) { + av_log(avctx, AV_LOG_ERROR, "Failed to get output buffer addr\n"); + return AVERROR_EXTERNAL; + } + + uint8_t *src[4] = {0}; + int src_linesizes[4] = {0}; + + ret = av_image_fill_linesizes(src_linesizes, frame->format, s->stride); + if (ret < 0) + return ret; + ret = av_image_fill_pointers(src, frame->format, s->slice_height, p, + src_linesizes); + if (ret < 0) + return ret; + av_image_copy2(frame->data, frame->linesize, src, src_linesizes, + frame->format, frame->width, frame->height); + + OH_AVErrCode err = OH_VideoDecoder_FreeOutputBuffer(s->dec, output->index); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "FreeOutputBuffer failed, %d, %s\n", err, + av_err2str(ret)); + return ret; + } + + return 0; +} + +static int oh_decode_output_frame(AVCodecContext *avctx, AVFrame *frame, + OHBufferQueueItem *output) +{ + OHCodecDecContext *s = avctx->priv_data; + OH_AVCodecBufferAttr attr; + + OH_AVErrCode err = OH_AVBuffer_GetBufferAttr(output->buffer, &attr); + if (err != AV_ERR_OK) + return ff_oh_err_to_ff_err(err); + + if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) { + av_log(avctx, AV_LOG_DEBUG, "Buffer flag eos\n"); + OH_VideoDecoder_FreeOutputBuffer(s->dec, output->index); + return AVERROR_EOF; + } + + if (!s->got_stream_info) { + // This shouldn't happen, add a warning message. + av_log(avctx, AV_LOG_WARNING, + "decoder didn't notify stream info, try get format explicitly\n"); + + OH_AVFormat *format = OH_VideoDecoder_GetOutputDescription(s->dec); + if (!format) { + av_log(avctx, AV_LOG_ERROR, "GetOutputDescription failed\n"); + return AVERROR_EXTERNAL; + } + + oh_decode_on_stream_changed(s->dec, format, avctx); + OH_AVFormat_Destroy(format); + if (!s->got_stream_info) + return AVERROR_EXTERNAL; + } + + if (s->output_to_window) + return oh_decode_wrap_hw_buffer(avctx, frame, output, &attr); + return oh_decode_wrap_sw_buffer(avctx, frame, output, &attr); +} + +static int oh_decode_send_pkt(AVCodecContext *avctx, OHBufferQueueItem *input) +{ + OHCodecDecContext *s = avctx->priv_data; + OH_AVErrCode err; + int ret; + + if (!s->pkt.size && !s->eof_sent) { + OH_AVCodecBufferAttr attr = { + .flags = AVCODEC_BUFFER_FLAGS_EOS, + }; + err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr); + if (err != AV_ERR_OK) + return ff_oh_err_to_ff_err(err); + err = OH_VideoDecoder_PushInputBuffer(s->dec, input->index); + if (err != AV_ERR_OK) + return ff_oh_err_to_ff_err(err); + s->eof_sent = true; + return 0; + } + + uint8_t *p = OH_AVBuffer_GetAddr(input->buffer); + int32_t n = OH_AVBuffer_GetCapacity(input->buffer); + if (!p || n <= 0) { + av_log(avctx, AV_LOG_ERROR, + "Failed to get buffer addr (%p) or capacity (%d)\n", + p, n); + return AVERROR_EXTERNAL; + } + n = FFMIN(s->pkt.size, n); + memcpy(p, s->pkt.data, n); + + OH_AVCodecBufferAttr attr = { + .size = n, + .offset = 0, + .pts = av_rescale_q(s->pkt.pts, avctx->pkt_timebase, + AV_TIME_BASE_Q), + .flags = (s->pkt.flags & AV_PKT_FLAG_KEY) + ? AVCODEC_BUFFER_FLAGS_SYNC_FRAME : 0, + }; + + err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + return ret; + } + err = OH_VideoDecoder_PushInputBuffer(s->dec, input->index); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Push input buffer failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + + if (n < s->pkt.size) { + s->pkt.size -= n; + s->pkt.data += n; + } else { + av_packet_unref(&s->pkt); + } + + return 0; +} + +static int oh_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + OHCodecDecContext *s = avctx->priv_data; + + while (1) { + OHBufferQueueItem buffer = {0}; + int ret; + + // Try get output + ff_mutex_lock(&s->output_mutex); + while (!s->decode_status) { + if (av_fifo_read(s->output_queue, &buffer, 1) >= 0) + break; + // Only wait after send EOF + if (s->eof_sent && !s->decode_status) + ff_cond_wait(&s->output_cond, &s->output_mutex); + else + break; + } + + ret = s->decode_status; + ff_mutex_unlock(&s->output_mutex); + + // Got a frame + if (buffer.buffer) + return oh_decode_output_frame(avctx, frame, &buffer); + if (ret < 0) + return ret; + + if (!s->pkt.size) { + /* fetch new packet or eof */ + ret = ff_decode_get_packet(avctx, &s->pkt); + if (ret < 0 && ret != AVERROR_EOF) + return ret; + } + + // Wait input buffer + ff_mutex_lock(&s->input_mutex); + while (!s->decode_status) { + if (av_fifo_read(s->input_queue, &buffer, 1) >= 0) + break; + ff_cond_wait(&s->input_cond, &s->input_mutex); + } + + ret = s->decode_status; + ff_mutex_unlock(&s->input_mutex); + + if (ret < 0) + return ret; + + ret = oh_decode_send_pkt(avctx, &buffer); + if (ret < 0) + return ret; + } + + return AVERROR(EAGAIN); +} + +static void oh_decode_flush(AVCodecContext *avctx) +{ + OHCodecDecContext *s = avctx->priv_data; + + OH_VideoDecoder_Flush(s->dec); + + ff_mutex_lock(&s->input_mutex); + ff_mutex_lock(&s->output_mutex); + av_fifo_reset2(s->input_queue); + av_fifo_reset2(s->output_queue); + s->decode_status = 0; + s->eof_sent = false; + ff_mutex_unlock(&s->output_mutex); + ff_mutex_unlock(&s->input_mutex); + + OH_VideoDecoder_Start(s->dec); +} + +static const AVCodecHWConfigInternal *const oh_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_OHCODEC, + .methods = AV_CODEC_HW_CONFIG_METHOD_AD_HOC | + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, + .device_type = AV_HWDEVICE_TYPE_OHCODEC, + }, + .hwaccel = NULL, + }, + NULL +}; + +#define VD (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM) +static const AVOption ohcodec_vdec_options[] = { + {"codec_name", "Select codec by name", + OFFSET(name), AV_OPT_TYPE_STRING, .flags = VD}, + {"allow_sw", "Allow software decoding", + OFFSET(allow_sw), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VD}, + {NULL} +}; + +#define DECLARE_OHCODEC_VCLASS(short_name) \ + static const AVClass short_name##_oh_dec_class = { \ + .class_name = #short_name "_ohcodec", \ + .item_name = av_default_item_name, \ + .option = ohcodec_vdec_options, \ + .version = LIBAVUTIL_VERSION_INT, \ + }; + +#define DECLARE_OHCODEC_VDEC(short_name, full_name, codec_id, bsf) \ + DECLARE_OHCODEC_VCLASS(short_name) \ + const FFCodec ff_##short_name##_oh_decoder = { \ + .p.name = #short_name "_ohcodec", \ + CODEC_LONG_NAME(full_name " OpenHarmony Codec"), \ + .p.type = AVMEDIA_TYPE_VIDEO, \ + .p.id = codec_id, \ + .p.priv_class = &short_name##_oh_dec_class, \ + .priv_data_size = sizeof(OHCodecDecContext), \ + .init = oh_decode_init, \ + FF_CODEC_RECEIVE_FRAME_CB(oh_decode_receive_frame), \ + .flush = oh_decode_flush, \ + .close = oh_decode_close, \ + .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | \ + AV_CODEC_CAP_HARDWARE, \ + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \ + .bsfs = bsf, \ + .hw_configs = oh_hw_configs, \ + .p.wrapper_name = "ohcodec", \ + }; + +#if CONFIG_H264_OH_DECODER +DECLARE_OHCODEC_VDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb") +#endif + +#if CONFIG_HEVC_OH_DECODER +DECLARE_OHCODEC_VDEC(hevc, "H.265", AV_CODEC_ID_HEVC, "hevc_mp4toannexb") +#endif diff --git a/libavcodec/ohenc.c b/libavcodec/ohenc.c new file mode 100644 index 000000000..76bddd45b --- /dev/null +++ b/libavcodec/ohenc.c @@ -0,0 +1,711 @@ +/* + * This file is part of FFmpeg. + * + * Copyright (c) 2025 Zhao Zhili + * + * 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 "config_components.h" + +#include +#include +#include +#include + +#include "libavutil/fifo.h" +#include "libavutil/hwcontext_oh.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/thread.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "encode.h" +#include "hwconfig.h" +#include "ohcodec.h" + +typedef struct OHCodecEncContext { + AVClass *avclass; + OH_AVCodec *enc; + + AVMutex input_mutex; + AVCond input_cond; + AVFifo *input_queue; + + AVMutex output_mutex; + AVCond output_cond; + AVFifo *output_queue; + + AVFrame *frame; + uint8_t *extradata; + int extradata_size; + + int encode_status; + bool eof_sent; + + bool got_stream_info; + int stride; + int slice_height; + + OHNativeWindow *native_window; + char *name; + int allow_sw; + int bitrate_mode; +} OHCodecEncContext; + +static const enum AVPixelFormat ohcodec_pix_fmts[] = { + AV_PIX_FMT_OHCODEC, + AV_PIX_FMT_NV12, + AV_PIX_FMT_NONE +}; + +static int oh_encode_create(OHCodecEncContext *s, AVCodecContext *avctx) +{ + const char *name = s->name; + + if (!name) { + const char *mime = ff_oh_mime(avctx->codec_id, avctx); + if (!mime) + return AVERROR_BUG; + OH_AVCapability *cap = OH_AVCodec_GetCapabilityByCategory(mime, true, HARDWARE); + if (!cap) { + if (!s->allow_sw) { + av_log(avctx, AV_LOG_ERROR, "Failed to get hardware codec %s\n", mime); + return AVERROR_EXTERNAL; + } + av_log(avctx, AV_LOG_WARNING, + "Failed to get hardware codec %s, try software backend\n", mime); + cap = OH_AVCodec_GetCapabilityByCategory(mime, true, SOFTWARE); + if (!cap) { + av_log(avctx, AV_LOG_ERROR, "Failed to get software codec %s\n", mime); + return AVERROR_EXTERNAL; + } + } + name = OH_AVCapability_GetName(cap); + if (!name) + return AVERROR_EXTERNAL; + } + + s->enc = OH_VideoEncoder_CreateByName(name); + if (!s->enc) { + av_log(avctx, AV_LOG_ERROR, "Create encoder with name %s failed\n", name); + return AVERROR_EXTERNAL; + } + av_log(avctx, AV_LOG_DEBUG, "Create encoder %s success\n", name); + + return 0; +} + +static int oh_encode_set_format(OHCodecEncContext *s, AVCodecContext *avctx) +{ + int ret; + + OH_AVFormat *format = OH_AVFormat_Create(); + if (!format) + return AVERROR(ENOMEM); + + bool b = OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, avctx->width); + b = b && OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, avctx->height); + if (!b) { + av_log(avctx, AV_LOG_ERROR, "Set width/height (%dx%d) failed\n", + avctx->width, avctx->height); + ret = AVERROR_EXTERNAL; + goto out; + } + if (avctx->framerate.num && avctx->framerate.den) + OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, + av_q2d(avctx->framerate)); + int pix = ff_oh_pix_from_ff_pix(avctx->pix_fmt); + if (!pix) { + ret = AVERROR_BUG; + goto out; + } + b = OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, pix); + if (!b) { + av_log(avctx, AV_LOG_ERROR, "Set pixel format to %d failed\n", pix); + ret = AVERROR_EXTERNAL; + goto out; + } + + if (s->bitrate_mode != -1) { + b = OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, s->bitrate_mode); + if (!b) { + av_log(avctx, AV_LOG_ERROR, "Set bitrate mode to %d failed\n", + s->bitrate_mode); + ret = AVERROR_EXTERNAL; + goto out; + } + } + OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, avctx->bit_rate); + + if (avctx->gop_size > 0) { + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + // In milliseconds + int gop = av_rescale_q(avctx->gop_size, + av_make_q(avctx->framerate.den, + avctx->framerate.num), + av_make_q(1, 1000)); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, gop); + } else { + av_log(avctx, AV_LOG_WARNING, "Skip setting gop without framerate\n"); + } + } else if (!avctx->gop_size) { + // All frames are key frame + OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, 0); + } else if (avctx->gop_size == -1) { + // Infinite gop + OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, -1); + } + + OH_AVErrCode err = OH_VideoEncoder_Configure(s->enc, format); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Decoder configure failed, %d, %s\n", + err, av_err2str(ret)); + goto out; + } + + if (avctx->pix_fmt == AV_PIX_FMT_OHCODEC) { + if (avctx->hw_device_ctx) { + av_log(avctx, AV_LOG_ERROR, + "ohcodec can only export native window via hw device, " + "doesn't support import hw device\n"); + ret = AVERROR(EINVAL); + goto out; + } + + err = OH_VideoEncoder_GetSurface(s->enc, &s->native_window); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Get surface failed, %d, %s\n", + err, av_err2str(ret)); + goto out; + } + av_log(avctx, AV_LOG_INFO, "Native window %p\n", s->native_window); + + ret = av_hwdevice_ctx_create(&avctx->hw_device_ctx, + AV_HWDEVICE_TYPE_OHCODEC, NULL, NULL, 0); + if (ret < 0) + goto out; + + AVOHCodecDeviceContext *dev = ((AVHWDeviceContext *)avctx->hw_device_ctx->data)->hwctx; + dev->native_window = s->native_window; + } + + return 0; +out: + OH_AVFormat_Destroy(format); + return ret; +} + +static void oh_encode_on_err(OH_AVCodec *codec, int32_t err, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecEncContext *s = avctx->priv_data; + + // Careful on the lock order. + // Always lock input first. + ff_mutex_lock(&s->input_mutex); + ff_mutex_lock(&s->output_mutex); + s->encode_status = ff_oh_err_to_ff_err(err); + ff_mutex_unlock(&s->output_mutex); + ff_mutex_unlock(&s->input_mutex); + + ff_cond_signal(&s->output_cond); + ff_cond_signal(&s->input_cond); +} + +static void oh_encode_on_stream_changed(OH_AVCodec *codec, OH_AVFormat *format, + void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecEncContext *s = avctx->priv_data; + + if (!OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &s->stride)) + s->stride = avctx->width; + if (!OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, &s->slice_height)) + s->slice_height = avctx->height; + + s->got_stream_info = true; +} + +static void oh_encode_on_need_input(OH_AVCodec *codec, uint32_t index, + OH_AVBuffer *buffer, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecEncContext *s = avctx->priv_data; + OHBufferQueueItem item = { + index, buffer, + }; + + ff_mutex_lock(&s->input_mutex); + int ret = av_fifo_write(s->input_queue, &item, 1); + if (ret >= 0) + ff_cond_signal(&s->input_cond); + ff_mutex_unlock(&s->input_mutex); + + if (ret < 0) + oh_encode_on_err(codec, AV_ERR_NO_MEMORY, userdata); +} + +static void oh_encode_on_output(OH_AVCodec *codec, uint32_t index, + OH_AVBuffer *buffer, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecEncContext *s = avctx->priv_data; + OHBufferQueueItem item = { + index, buffer, + }; + + ff_mutex_lock(&s->output_mutex); + int ret = av_fifo_write(s->output_queue, &item, 1); + if (ret >= 0) + ff_cond_signal(&s->output_cond); + ff_mutex_unlock(&s->output_mutex); + + if (ret < 0) + oh_encode_on_err(codec, AV_ERR_NO_MEMORY, userdata); +} + +static int oh_encode_start(OHCodecEncContext *s, AVCodecContext *avctx) +{ + int ret; + OH_AVErrCode err; + OH_AVCodecCallback cb = { + .onError = oh_encode_on_err, + .onStreamChanged = oh_encode_on_stream_changed, + .onNeedInputBuffer = oh_encode_on_need_input, + .onNewOutputBuffer = oh_encode_on_output, + }; + + err = OH_VideoEncoder_RegisterCallback(s->enc, cb, avctx); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Register callback failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + err = OH_VideoEncoder_Prepare(s->enc); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Prepare failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + err = OH_VideoEncoder_Start(s->enc); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Start failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + + return 0; +} + +static av_cold int oh_encode_init(AVCodecContext *avctx) +{ + OHCodecEncContext *s = avctx->priv_data; + + // Initialize these fields first, so oh_decode_close can destroy them safely + ff_mutex_init(&s->input_mutex, NULL); + ff_cond_init(&s->input_cond, NULL); + ff_mutex_init(&s->output_mutex, NULL); + ff_cond_init(&s->output_cond, NULL); + + int ret = oh_encode_create(s, avctx); + if (ret < 0) + return ret; + ret = oh_encode_set_format(s, avctx); + if (ret < 0) + return ret; + + size_t fifo_size = 16; + s->input_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem), + AV_FIFO_FLAG_AUTO_GROW); + s->output_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem), + AV_FIFO_FLAG_AUTO_GROW); + s->frame = av_frame_alloc(); + if (!s->input_queue || !s->output_queue || !s->frame) + return AVERROR(ENOMEM); + + ret = oh_encode_start(s, avctx); + if (ret < 0) + return ret; + + return 0; +} + +static av_cold int oh_encode_close(AVCodecContext *avctx) +{ + OHCodecEncContext *s = avctx->priv_data; + + if (s->enc) { + if (s->native_window) { + OH_NativeWindow_DestroyNativeWindow(s->native_window); + s->native_window = NULL; + } + OH_VideoEncoder_Stop(s->enc); + OH_AVErrCode err = OH_VideoEncoder_Destroy(s->enc); + if (err == AV_ERR_OK) + av_log(avctx, AV_LOG_DEBUG, "Destroy encoder success\n"); + else + av_log(avctx, AV_LOG_ERROR, "Destroy decoder failed, %d, %s\n", + err, av_err2str(ff_oh_err_to_ff_err(err))); + s->enc = NULL; + } + + av_freep(&s->extradata); + av_frame_free(&s->frame); + + ff_mutex_destroy(&s->input_mutex); + ff_cond_destroy(&s->input_cond); + av_fifo_freep2(&s->input_queue); + + ff_mutex_destroy(&s->output_mutex); + ff_cond_destroy(&s->output_cond); + av_fifo_freep2(&s->output_queue); + + return 0; +} + +static int oh_encode_output_packet(AVCodecContext *avctx, AVPacket *pkt, + OHBufferQueueItem *output) +{ + OHCodecEncContext *s = avctx->priv_data; + uint8_t *p; + OH_AVCodecBufferAttr attr; + int ret; + + OH_AVErrCode err = OH_AVBuffer_GetBufferAttr(output->buffer, &attr); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + goto out; + } + if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) { + av_log(avctx, AV_LOG_DEBUG, "Buffer flag eos\n"); + ret = AVERROR_EOF; + goto out; + } + + p = OH_AVBuffer_GetAddr(output->buffer); + if (!p) { + av_log(avctx, AV_LOG_ERROR, "Failed to get output buffer addr\n"); + ret = AVERROR_EXTERNAL; + goto out; + } + if (attr.flags & AVCODEC_BUFFER_FLAGS_CODEC_DATA) { + av_freep(&s->extradata); + s->extradata = av_malloc(attr.size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!s->extradata) { + ret = AVERROR(ENOMEM); + goto out; + } + memset(s->extradata + attr.size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + memcpy(s->extradata, p + attr.offset, attr.size); + s->extradata_size = attr.size; + ret = 0; + goto out; + } + + int64_t extradata_size = s->extradata_size; + s->extradata_size = 0; + + if (extradata_size && (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) { + ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, + s->extradata, extradata_size); + if (ret < 0) + goto out; + s->extradata = NULL; + extradata_size = 0; + } + + ret = ff_get_encode_buffer(avctx, pkt, attr.size + extradata_size, 0); + if (ret < 0) + goto out; + + if (extradata_size) + memcpy(pkt->data, s->extradata, extradata_size); + + memcpy(pkt->data + extradata_size, p + attr.offset, attr.size); + pkt->pts = av_rescale_q(attr.pts, AV_TIME_BASE_Q, avctx->time_base); + if (attr.flags & AVCODEC_BUFFER_FLAGS_SYNC_FRAME) + pkt->flags |= AV_PKT_FLAG_KEY; + ret = 0; +out: + OH_VideoEncoder_FreeOutputBuffer(s->enc, output->index); + return ret; +} + +static int oh_encode_send_hw_frame(AVCodecContext *avctx) +{ + OHCodecEncContext *s = avctx->priv_data; + + if (s->eof_sent) + return 0; + + if (s->frame->buf[0]) { + av_frame_unref(s->frame); + return 0; + } + + OH_AVErrCode err = OH_VideoEncoder_NotifyEndOfStream(s->enc); + s->eof_sent = true; + return ff_oh_err_to_ff_err(err); +} + +static int oh_encode_send_sw_frame(AVCodecContext *avctx, OHBufferQueueItem *input) +{ + OHCodecEncContext *s = avctx->priv_data; + AVFrame *frame = s->frame; + OH_AVErrCode err; + int ret; + + if (!s->got_stream_info) { + // This shouldn't happen, add a warning message. + av_log(avctx, AV_LOG_WARNING, + "decoder didn't notify stream info, try get format explicitly\n"); + + OH_AVFormat *format = OH_VideoEncoder_GetOutputDescription(s->enc); + if (!format) { + av_log(avctx, AV_LOG_ERROR, "GetOutputDescription failed\n"); + return AVERROR_EXTERNAL; + } + + oh_encode_on_stream_changed(s->enc, format, avctx); + OH_AVFormat_Destroy(format); + if (!s->got_stream_info) + return AVERROR_EXTERNAL; + } + + if (!frame->buf[0] && !s->eof_sent) { + OH_AVCodecBufferAttr attr = { + .flags = AVCODEC_BUFFER_FLAGS_EOS, + }; + err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr); + if (err != AV_ERR_OK) + return ff_oh_err_to_ff_err(err); + err = OH_VideoEncoder_PushInputBuffer(s->enc, input->index); + if (err != AV_ERR_OK) + return ff_oh_err_to_ff_err(err); + s->eof_sent = true; + return 0; + } + + uint8_t *p = OH_AVBuffer_GetAddr(input->buffer); + int32_t n = OH_AVBuffer_GetCapacity(input->buffer); + if (!p || n <= 0) { + av_log(avctx, AV_LOG_ERROR, + "Failed to get buffer addr (%p) or capacity (%d)\n", + p, n); + return AVERROR_EXTERNAL; + } + + uint8_t *dst[4] = {0}; + int dst_linesizes[4] = {0}; + ret = av_image_fill_linesizes(dst_linesizes, frame->format, s->stride); + if (ret < 0) + return ret; + ret = av_image_fill_pointers(dst, frame->format, s->slice_height, p, + dst_linesizes); + if (ret < 0) + return ret; + + av_image_copy2(dst, dst_linesizes, frame->data, frame->linesize, + frame->format, frame->width, frame->height); + OH_AVCodecBufferAttr attr = { + .size = n, + .offset = 0, + .pts = av_rescale_q(s->frame->pts, avctx->pkt_timebase, + AV_TIME_BASE_Q), + .flags = (s->frame->flags & AV_FRAME_FLAG_KEY) + ? AVCODEC_BUFFER_FLAGS_SYNC_FRAME : 0, + }; + + err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + return ret; + } + err = OH_VideoEncoder_PushInputBuffer(s->enc, input->index); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Push input buffer failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + av_frame_unref(s->frame); + + return 0; +} + +static int oh_encode_receive(AVCodecContext *avctx, AVPacket *pkt) +{ + OHCodecEncContext *s = avctx->priv_data; + + while (1) { + OHBufferQueueItem buffer = {0}; + int ret; + + // Try get output + ff_mutex_lock(&s->output_mutex); + while (!s->encode_status) { + if (av_fifo_read(s->output_queue, &buffer, 1) >= 0) + break; + // Only wait after send EOF + if (s->eof_sent && !s->encode_status) + ff_cond_wait(&s->output_cond, &s->output_mutex); + else + break; + } + + ret = s->encode_status; + ff_mutex_unlock(&s->output_mutex); + + // Got a packet + if (buffer.buffer) + return oh_encode_output_packet(avctx, pkt, &buffer); + if (ret < 0) + return ret; + + if (!s->frame->buf[0]) { + /* fetch new frame or eof */ + ret = ff_encode_get_frame(avctx, s->frame); + if (ret < 0 && ret != AVERROR_EOF) + return ret; + } + + if (s->native_window) { + ret = oh_encode_send_hw_frame(avctx); + if (ret < 0) + return ret; + continue; + } + + // Wait input buffer + ff_mutex_lock(&s->input_mutex); + while (!s->encode_status) { + if (av_fifo_read(s->input_queue, &buffer, 1) >= 0) + break; + ff_cond_wait(&s->input_cond, &s->input_mutex); + } + + ret = s->encode_status; + ff_mutex_unlock(&s->input_mutex); + + if (ret < 0) + return ret; + + ret = oh_encode_send_sw_frame(avctx, &buffer); + if (ret < 0) + return ret; + } + + return AVERROR(EAGAIN); +} + +static void oh_encode_flush(AVCodecContext *avctx) +{ + OHCodecEncContext *s = avctx->priv_data; + + OH_VideoEncoder_Flush(s->enc); + + ff_mutex_lock(&s->input_mutex); + ff_mutex_lock(&s->output_mutex); + av_fifo_reset2(s->input_queue); + av_fifo_reset2(s->output_queue); + s->encode_status = 0; + s->eof_sent = false; + ff_mutex_unlock(&s->output_mutex); + ff_mutex_unlock(&s->input_mutex); + + OH_VideoEncoder_Start(s->enc); +} + +static const AVCodecHWConfigInternal *const oh_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_OHCODEC, + .methods = AV_CODEC_HW_CONFIG_METHOD_AD_HOC, + }, + .hwaccel = NULL, + }, + NULL +}; + +static const FFCodecDefault ohcodec_defaults[] = { + {"g", "-2"}, + {NULL}, +}; + +#define OFFSET(x) offsetof(OHCodecEncContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption ohcodec_venc_options[] = { + {"codec_name", "Select codec by name", + OFFSET(name), AV_OPT_TYPE_STRING, .flags = VE}, + {"allow_sw", "Allow software encoding", + OFFSET(allow_sw), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VE}, + {"bitrate_mode", "Bitrate control method", + OFFSET(bitrate_mode), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE, .unit = "bitrate_mode"}, + {"cbr", "Constant bitrate mode", + 0, AV_OPT_TYPE_CONST, {.i64 = CBR}, 0, 0, VE, .unit = "bitrate_mode"}, + {"vbr", "Variable bitrate mode", + 0, AV_OPT_TYPE_CONST, {.i64 = VBR}, 0, 0, VE, .unit = "bitrate_mode"}, + {"cq", "Constant quality mode", + 0, AV_OPT_TYPE_CONST, {.i64 = CQ}, 0, 0, VE, .unit = "bitrate_mode"}, + {NULL}, +}; + +#define DECLARE_OHCODEC_CLASS(name) \ +static const AVClass name ## _oh_enc_class = { \ + .class_name = #name "_ohcodec", \ + .item_name = av_default_item_name, \ + .option = ohcodec_venc_options, \ + .version = LIBAVUTIL_VERSION_INT, \ +}; \ + +#define DECLARE_OHCODEC_ENCODER(short_name, long_name, codec_id) \ +DECLARE_OHCODEC_CLASS(short_name) \ +const FFCodec ff_ ## short_name ## _oh_encoder = { \ + .p.name = #short_name "_ohcodec", \ + CODEC_LONG_NAME(long_name " OpenHarmony Codec"), \ + .p.type = AVMEDIA_TYPE_VIDEO, \ + .p.id = codec_id, \ + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | \ + AV_CODEC_CAP_HARDWARE | \ + AV_CODEC_CAP_ENCODER_FLUSH, \ + .priv_data_size = sizeof(OHCodecEncContext), \ + CODEC_PIXFMTS_ARRAY(ohcodec_pix_fmts), \ + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, \ + .defaults = ohcodec_defaults, \ + .init = oh_encode_init, \ + FF_CODEC_RECEIVE_PACKET_CB(oh_encode_receive), \ + .close = oh_encode_close, \ + .flush = oh_encode_flush, \ + .p.priv_class = &short_name ## _oh_enc_class, \ + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \ + .p.wrapper_name = "ohcodec", \ + .hw_configs = oh_hw_configs, \ +}; \ + +#if CONFIG_H264_OH_ENCODER +DECLARE_OHCODEC_ENCODER(h264, "H.264", AV_CODEC_ID_H264) +#endif // CONFIG_H264_OH_ENCODER + +#if CONFIG_HEVC_OH_ENCODER +DECLARE_OHCODEC_ENCODER(hevc, "H.265", AV_CODEC_ID_HEVC) +#endif // CONFIG_HEVC_OH_ENCODER diff --git a/libavcodec/omx.c b/libavcodec/omx.c index 2b9fa636f..7b003ac1b 100644 --- a/libavcodec/omx.c +++ b/libavcodec/omx.c @@ -648,6 +648,10 @@ static av_cold int omx_encode_init(AVCodecContext *avctx) OMX_BUFFERHEADERTYPE *buffer; OMX_ERRORTYPE err; + av_log(avctx, AV_LOG_WARNING, + "The %s encoder is deprecated and will be removed in future versions\n", + avctx->codec->name); + /* cleanup relies on the mutexes/conditions being initialized first. */ ret = ff_pthread_init(s, omx_codec_context_offsets); if (ret < 0) @@ -952,7 +956,7 @@ const FFCodec ff_mpeg4_omx_encoder = { .init = omx_encode_init, FF_CODEC_ENCODE_CB(omx_encode_frame), .close = omx_encode_end, - .p.pix_fmts = omx_encoder_pix_fmts, + CODEC_PIXFMTS_ARRAY(omx_encoder_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, .p.capabilities = AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, @@ -974,7 +978,7 @@ const FFCodec ff_h264_omx_encoder = { .init = omx_encode_init, FF_CODEC_ENCODE_CB(omx_encode_frame), .close = omx_encode_end, - .p.pix_fmts = omx_encoder_pix_fmts, + CODEC_PIXFMTS_ARRAY(omx_encoder_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .p.capabilities = AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/on2avc.c b/libavcodec/on2avc.c index 3badfae89..0a912cc30 100644 --- a/libavcodec/on2avc.c +++ b/libavcodec/on2avc.c @@ -1023,6 +1023,4 @@ const FFCodec ff_on2avc_decoder = { .close = on2avc_decode_close, .p.capabilities = AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/options.c b/libavcodec/options.c index f60c41bdc..834beb575 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -69,7 +69,7 @@ static const AVClass *codec_child_class_iterate(void **iter) static AVClassCategory get_category(void *ptr) { AVCodecContext* avctx = ptr; - if (avctx->codec && av_codec_is_decoder(avctx->codec)) + if (avctx->codec && ff_codec_is_decoder(avctx->codec)) return AV_CLASS_CATEGORY_DECODER; else return AV_CLASS_CATEGORY_ENCODER; diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h index 47da41b0a..99e700207 100644 --- a/libavcodec/options_table.h +++ b/libavcodec/options_table.h @@ -47,7 +47,7 @@ #define AV_CODEC_DEFAULT_BITRATE 200*1000 static const AVOption avcodec_options[] = { -{"b", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT64, {.i64 = AV_CODEC_DEFAULT_BITRATE }, 0, INT64_MAX, A|V|E}, +{"b", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT64, {.i64 = AV_CODEC_DEFAULT_BITRATE }, 0, (double)INT64_MAX, A|V|E}, {"ab", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT64, {.i64 = 128*1000 }, 0, INT_MAX, A|E}, {"bt", "Set video bitrate tolerance (in bits/s). In 1-pass mode, bitrate tolerance specifies how far " "ratecontrol is willing to deviate from the target average bitrate value. This is not related " @@ -74,9 +74,6 @@ static const AVOption avcodec_options[] = { {"ilme", "interlaced motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_INTERLACED_ME }, INT_MIN, INT_MAX, V|E, .unit = "flags"}, {"cgop", "closed GOP", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_CLOSED_GOP }, INT_MIN, INT_MAX, V|E, .unit = "flags"}, {"output_corrupt", "Output even potentially corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_OUTPUT_CORRUPT }, INT_MIN, INT_MAX, V|D, .unit = "flags"}, -#if FF_API_DROPCHANGED -{"drop_changed", "Drop frames whose parameters differ from first decoded frame", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_DROPCHANGED }, INT_MIN, INT_MAX, A|V|D | AV_OPT_FLAG_DEPRECATED, .unit = "flags"}, -#endif {"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT}, 0, UINT_MAX, V|A|E|D|S, .unit = "flags2"}, {"fast", "allow non-spec-compliant speedup tricks", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_FAST }, INT_MIN, INT_MAX, V|E, .unit = "flags2"}, {"noout", "skip bitstream encoding", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_NO_OUTPUT }, INT_MIN, INT_MAX, V|E, .unit = "flags2"}, @@ -217,15 +214,17 @@ static const AVOption avcodec_options[] = { {"rc_init_occupancy", "number of bits which should be loaded into the rc buffer before decoding starts", OFFSET(rc_initial_buffer_occupancy), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"threads", "set the number of threads", OFFSET(thread_count), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, INT_MAX, V|A|E|D, .unit = "threads"}, {"auto", "autodetect a suitable number of threads to use", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, V|E|D, .unit = "threads"}, -{"dc", "intra_dc_precision", OFFSET(intra_dc_precision), AV_OPT_TYPE_INT, {.i64 = 0 }, -8, 16, V|E}, +#if FF_API_INTRA_DC_PRECISION +{"dc", "deprecated; use intra_dc_precision for MPEG-2 instead", OFFSET(intra_dc_precision), AV_OPT_TYPE_INT, {.i64 = 0 }, -8, 16, AV_OPT_FLAG_DEPRECATED|V|E}, +#endif {"nssew", "nsse weight", OFFSET(nsse_weight), AV_OPT_TYPE_INT, {.i64 = 8 }, INT_MIN, INT_MAX, V|E}, {"skip_top", "number of macroblock rows at the top which are skipped", OFFSET(skip_top), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|D}, {"skip_bottom", "number of macroblock rows at the bottom which are skipped", OFFSET(skip_bottom), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|D}, {"profile", NULL, OFFSET(profile), AV_OPT_TYPE_INT, {.i64 = AV_PROFILE_UNKNOWN }, INT_MIN, INT_MAX, V|A|E|CC, .unit = "avctx.profile"}, {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_PROFILE_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, .unit = "avctx.profile"}, {"main10", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_PROFILE_HEVC_MAIN_10 }, INT_MIN, INT_MAX, V|E, .unit = "avctx.profile"}, -{"level", "encoding level, usually corresponding to the profile level, codec-specific", OFFSET(level), AV_OPT_TYPE_INT, {.i64 = FF_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E|CC, .unit = "avctx.level"}, -{"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, .unit = "avctx.level"}, +{"level", "encoding level, usually corresponding to the profile level, codec-specific", OFFSET(level), AV_OPT_TYPE_INT, {.i64 = AV_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E|CC, .unit = "avctx.level"}, +{"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, .unit = "avctx.level"}, {"lowres", "decode at 1= 1/2, 2=1/4, 3=1/8 resolutions", OFFSET(lowres), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, V|A|D}, {"cmp", "full-pel ME compare function", OFFSET(me_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, .unit = "cmp_func"}, {"subcmp", "sub-pel ME compare function", OFFSET(me_sub_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, .unit = "cmp_func"}, @@ -272,9 +271,6 @@ static const AVOption avcodec_options[] = { {"ch_layout", NULL, OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str = NULL }, 0, 0, A|E|D, .unit = "ch_layout"}, {"rc_max_vbv_use", NULL, OFFSET(rc_max_available_vbv_use), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, 0.0, FLT_MAX, V|E}, {"rc_min_vbv_use", NULL, OFFSET(rc_min_vbv_overflow_use), AV_OPT_TYPE_FLOAT, {.dbl = 3 }, 0.0, FLT_MAX, V|E}, -#if FF_API_TICKS_PER_FRAME -{"ticks_per_frame", NULL, OFFSET(ticks_per_frame), AV_OPT_TYPE_INT, {.i64 = 1 }, 1, INT_MAX, A|V|E|D}, -#endif {"color_primaries", "color primaries", OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64 = AVCOL_PRI_UNSPECIFIED }, 1, INT_MAX, V|E|D, .unit = "color_primaries_type"}, {"bt709", "BT.709", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_BT709 }, INT_MIN, INT_MAX, V|E|D, .unit = "color_primaries_type"}, {"unknown", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, .unit = "color_primaries_type"}, @@ -358,6 +354,11 @@ static const AVOption avcodec_options[] = { {"bottomleft", "Bottom-left", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_BOTTOMLEFT }, INT_MIN, INT_MAX, V|E|D, .unit = "chroma_sample_location_type"}, {"bottom", "Bottom", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_BOTTOM }, INT_MIN, INT_MAX, V|E|D, .unit = "chroma_sample_location_type"}, {"unspecified", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, .unit = "chroma_sample_location_type"}, +{"alpha_mode", "alpha mode", OFFSET(alpha_mode), AV_OPT_TYPE_INT, {.i64 = AVALPHA_MODE_UNSPECIFIED }, 0, INT_MAX, V|E|D, .unit = "alpha_mode_type"}, +{"unknown", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVALPHA_MODE_UNSPECIFIED }, 0, 0, V|E|D, .unit = "alpha_mode_type"}, +{"unspecified", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVALPHA_MODE_UNSPECIFIED }, 0, 0, V|E|D, .unit = "alpha_mode_type"}, +{"premultiplied", "Premultiplied", 0, AV_OPT_TYPE_CONST, {.i64 = AVALPHA_MODE_PREMULTIPLIED }, 0, 0, V|E|D, .unit = "alpha_mode_type"}, +{"straight", "Straight", 0, AV_OPT_TYPE_CONST, {.i64 = AVALPHA_MODE_STRAIGHT }, 0, 0, V|E|D, .unit = "alpha_mode_type"}, {"log_level_offset", "set the log level offset", OFFSET(log_level_offset), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX }, {"slices", "set the number of slices, used in parallelized encoding", OFFSET(slices), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, V|E}, {"thread_type", "select multithreading type", OFFSET(thread_type), AV_OPT_TYPE_FLAGS, {.i64 = FF_THREAD_SLICE|FF_THREAD_FRAME }, 0, INT_MAX, V|A|E|D, .unit = "thread_type"}, @@ -412,6 +413,7 @@ static const AVOption avcodec_options[] = { {"mastering_display_metadata", .default_val.i64 = AV_PKT_DATA_MASTERING_DISPLAY_METADATA, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, {"content_light_level", .default_val.i64 = AV_PKT_DATA_CONTENT_LIGHT_LEVEL, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, {"icc_profile", .default_val.i64 = AV_PKT_DATA_ICC_PROFILE, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, + {"exif", .default_val.i64 = AV_PKT_DATA_EXIF, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, {NULL}, }; diff --git a/libavcodec/opus/Makefile b/libavcodec/opus/Makefile index 53cb98e28..6f0a1ab2c 100644 --- a/libavcodec/opus/Makefile +++ b/libavcodec/opus/Makefile @@ -5,6 +5,7 @@ OBJS-$(CONFIG_OPUS_DECODER) += \ opus/dec.o \ opus/dec_celt.o \ opus/celt.o \ + opus/frame_duration_tab.o \ opus/pvq.o \ opus/silk.o \ opus/tab.o \ @@ -14,6 +15,7 @@ OBJS-$(CONFIG_OPUS_DECODER) += \ OBJS-$(CONFIG_OPUS_PARSER) += \ + opus/frame_duration_tab.o \ opus/parser.o \ opus/parse.o \ @@ -26,5 +28,7 @@ OBJS-$(CONFIG_OPUS_ENCODER) += \ opus/rc.o \ opus/tab.o \ +STLIBOBJS-$(CONFIG_MATROSKA_MUXER) += opus/frame_duration_tab.o +STLIBOBJS-$(CONFIG_WEBM_MUXER) += opus/frame_duration_tab.o libavcodec/opus/%.o: CPPFLAGS += -I$(SRC_PATH)/libavcodec/ diff --git a/libavcodec/opus/dec.c b/libavcodec/opus/dec.c index dbefcddb0..29c490ae3 100644 --- a/libavcodec/opus/dec.c +++ b/libavcodec/opus/dec.c @@ -323,7 +323,7 @@ static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size } else { av_log(s->avctx, AV_LOG_WARNING, "Spurious CELT delay samples present.\n"); - av_audio_fifo_drain(s->celt_delay, delay_samples); + av_audio_fifo_reset(s->celt_delay); if (s->avctx->err_recognition & AV_EF_EXPLODE) return AVERROR_BUG; } @@ -393,9 +393,7 @@ static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size return samples; } -static int opus_decode_subpacket(OpusStreamContext *s, - const uint8_t *buf, int buf_size, - int nb_samples) +static int opus_decode_subpacket(OpusStreamContext *s, const uint8_t *buf) { int output_samples = 0; int flush_needed = 0; @@ -491,8 +489,9 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, OpusStreamContext *s = &c->streams[i]; s->out[0] = s->out[1] = NULL; + int fifo_samples = av_audio_fifo_size(s->sync_buffer); delayed_samples = FFMAX(delayed_samples, - s->delayed_samples + av_audio_fifo_size(s->sync_buffer)); + s->delayed_samples + fifo_samples); } /* decode the header of the first sub-packet to find out the sample count */ @@ -578,8 +577,7 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, s->silk_samplerate = get_silk_samplerate(s->packet.config); } - ret = opus_decode_subpacket(&c->streams[i], buf, s->packet.data_size, - coded_samples); + ret = opus_decode_subpacket(&c->streams[i], buf); if (ret < 0) return ret; s->decoded_samples = ret; @@ -642,10 +640,10 @@ static av_cold void opus_decode_flush(AVCodecContext *ctx) memset(&s->packet, 0, sizeof(s->packet)); s->delayed_samples = 0; - av_audio_fifo_drain(s->celt_delay, av_audio_fifo_size(s->celt_delay)); + av_audio_fifo_reset(s->celt_delay); swr_close(s->swr); - av_audio_fifo_drain(s->sync_buffer, av_audio_fifo_size(s->sync_buffer)); + av_audio_fifo_reset(s->sync_buffer); ff_silk_flush(s->silk); ff_celt_flush(s->celt); diff --git a/libavcodec/opus/dec_celt.c b/libavcodec/opus/dec_celt.c index 3feb4a4e4..a43d63d9d 100644 --- a/libavcodec/opus/dec_celt.c +++ b/libavcodec/opus/dec_celt.c @@ -463,6 +463,8 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, block->emph_coeff, ff_opus_deemph_weights, frame_size); + if (!isnormal(block->emph_coeff)) + block->emph_coeff = 0.0; } if (channels == 1) diff --git a/libavcodec/opus/dsp.c b/libavcodec/opus/dsp.c index 6cd76cece..f2278c5bd 100644 --- a/libavcodec/opus/dsp.c +++ b/libavcodec/opus/dsp.c @@ -62,7 +62,7 @@ av_cold void ff_opus_dsp_init(OpusDSP *ctx) ff_opus_dsp_init_aarch64(ctx); #elif ARCH_RISCV ff_opus_dsp_init_riscv(ctx); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_opus_dsp_init_x86(ctx); #endif } diff --git a/libavcodec/opus/enc.c b/libavcodec/opus/enc.c index 539826311..587e4ed69 100644 --- a/libavcodec/opus/enc.c +++ b/libavcodec/opus/enc.c @@ -433,7 +433,7 @@ static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc, if (f->silence) { if (f->framebits >= 16) - ff_opus_rc_enc_log(rc, 1, 15); /* Silence (if using explicit singalling) */ + ff_opus_rc_enc_log(rc, 1, 15); /* Silence (if using explicit signalling) */ for (int ch = 0; ch < s->channels; ch++) memset(s->last_quantized_energy[ch], 0.0f, sizeof(float)*CELT_MAX_BANDS); return; @@ -548,7 +548,7 @@ static int opus_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr) { OpusEncContext *s = avctx->priv_data; - int ret, frame_size, alloc_size = 0; + int ret, frame_size, discard_padding, alloc_size = 0; if (frame) { /* Add new frame to queue */ if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) @@ -600,11 +600,13 @@ static int opus_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, /* Remove samples from queue and skip if needed */ ff_af_queue_remove(&s->afq, s->packet.frames*frame_size, &avpkt->pts, &avpkt->duration); - if (s->packet.frames*frame_size > avpkt->duration) { + + discard_padding = s->packet.frames*frame_size - ff_samples_from_time_base(avctx, avpkt->duration); + if (discard_padding > 0) { uint8_t *side = av_packet_new_side_data(avpkt, AV_PKT_DATA_SKIP_SAMPLES, 10); if (!side) return AVERROR(ENOMEM); - AV_WL32(&side[4], s->packet.frames*frame_size - avpkt->duration + 120); + AV_WL32(&side[4], discard_padding); } *got_packet_ptr = 1; @@ -638,12 +640,8 @@ static av_cold int opus_encode_init(AVCodecContext *avctx) s->avctx = avctx; s->channels = avctx->ch_layout.nb_channels; - /* Opus allows us to change the framesize on each packet (and each packet may - * have multiple frames in it) but we can't change the codec's frame size on - * runtime, so fix it to the lowest possible number of samples and use a queue - * to accumulate AVFrames until we have enough to encode whatever the encoder - * decides is the best */ - avctx->frame_size = 120; + int max_delay_samples = (s->options.max_delay_ms * s->avctx->sample_rate) / 1000; + avctx->frame_size = OPUS_BLOCK_SIZE(FFMIN(OPUS_SAMPLES_TO_BLOCK_SIZE(max_delay_samples), CELT_BLOCK_960)); /* Initial padding will change if SILK is ever supported */ avctx->initial_padding = 120; @@ -746,9 +744,7 @@ const FFCodec ff_opus_encoder = { FF_CODEC_ENCODE_CB(opus_encode_frame), .close = opus_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.supported_samplerates = (const int []){ 48000, 0 }, - .p.ch_layouts = (const AVChannelLayout []){ AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLERATES(48000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), }; diff --git a/libavcodec/opus/frame_duration_tab.c b/libavcodec/opus/frame_duration_tab.c new file mode 100644 index 000000000..3e408d978 --- /dev/null +++ b/libavcodec/opus/frame_duration_tab.c @@ -0,0 +1,31 @@ +/* + * 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 "tab.h" + +const uint16_t ff_opus_frame_duration[32] = { + 480, 960, 1920, 2880, + 480, 960, 1920, 2880, + 480, 960, 1920, 2880, + 480, 960, + 480, 960, + 120, 240, 480, 960, + 120, 240, 480, 960, + 120, 240, 480, 960, + 120, 240, 480, 960, +}; diff --git a/libavcodec/opus/parse.c b/libavcodec/opus/parse.c index 687199b1b..1c7876e37 100644 --- a/libavcodec/opus/parse.c +++ b/libavcodec/opus/parse.c @@ -36,20 +36,9 @@ #include "mathops.h" #include "opus.h" #include "parse.h" +#include "tab.h" #include "vorbis_data.h" -static const uint16_t opus_frame_duration[32] = { - 480, 960, 1920, 2880, - 480, 960, 1920, 2880, - 480, 960, 1920, 2880, - 480, 960, - 480, 960, - 120, 240, 480, 960, - 120, 240, 480, 960, - 120, 240, 480, 960, - 120, 240, 480, 960, -}; - /** * Read a 1- or 2-byte frame length */ @@ -257,7 +246,7 @@ int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size, pkt->data_size = pkt->packet_size - padding; /* total packet duration cannot be larger than 120ms */ - pkt->frame_duration = opus_frame_duration[pkt->config]; + pkt->frame_duration = ff_opus_frame_duration[pkt->config]; if (pkt->frame_duration * pkt->frame_count > OPUS_MAX_PACKET_DUR) goto fail; @@ -332,8 +321,6 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx, } avctx->delay = AV_RL16(extradata + 10); - if (avctx->internal) - avctx->internal->skip_samples = avctx->delay; channels = avctx->extradata ? extradata[9] : (channels == 1) ? 1 : 2; if (!channels) { diff --git a/libavcodec/opus/parser.c b/libavcodec/opus/parser.c index 41665e68f..bab0e5041 100644 --- a/libavcodec/opus/parser.c +++ b/libavcodec/opus/parser.c @@ -31,6 +31,7 @@ #include "opus.h" #include "parse.h" #include "parser.h" +#include "parser_internal.h" typedef struct OpusParserContext { ParseContext pc; @@ -78,6 +79,21 @@ static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_le return buf + bytestream2_tell(&gb); } +static int set_frame_duration(AVCodecParserContext *ctx, AVCodecContext *avctx, + const uint8_t *buf, int buf_size) +{ + OpusParserContext *s = ctx->priv_data; + + if (ff_opus_parse_packet(&s->pkt, buf, buf_size, s->ctx.nb_streams > 1) < 0) { + av_log(avctx, AV_LOG_ERROR, "Error parsing Opus packet header.\n"); + return AVERROR_INVALIDDATA; + } + + ctx->duration = s->pkt.frame_count * s->pkt.frame_duration; + + return 0; +} + /** * Find the end of the current frame in the bitstream. * @return the position of the first byte of the next frame, or -1 @@ -126,25 +142,12 @@ static int opus_find_frame_end(AVCodecParserContext *ctx, AVCodecContext *avctx, if (!s->ts_framing) payload_len = buf_size; - if (avctx->extradata && !s->extradata_parsed) { - ret = ff_opus_parse_extradata(avctx, &s->ctx); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error parsing Ogg extradata.\n"); - return AVERROR_INVALIDDATA; - } - av_freep(&s->ctx.channel_maps); - s->extradata_parsed = 1; - } - if (payload_len <= buf_size && (!s->ts_framing || start_found)) { - ret = ff_opus_parse_packet(&s->pkt, payload, payload_len, s->ctx.nb_streams > 1); + ret = set_frame_duration(ctx, avctx, payload, payload_len); if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error parsing Opus packet header.\n"); pc->frame_start_found = 0; return AVERROR_INVALIDDATA; } - - ctx->duration = s->pkt.frame_count * s->pkt.frame_duration; } if (s->ts_framing) { @@ -170,31 +173,50 @@ static int opus_parse(AVCodecParserContext *ctx, AVCodecContext *avctx, { OpusParserContext *s = ctx->priv_data; ParseContext *pc = &s->pc; - int next, header_len; + int next, header_len = 0; - next = opus_find_frame_end(ctx, avctx, buf, buf_size, &header_len); + avctx->sample_rate = 48000; - if (s->ts_framing && next != AVERROR_INVALIDDATA && - ff_combine_frame(pc, next, &buf, &buf_size) < 0) { - *poutbuf = NULL; - *poutbuf_size = 0; - return buf_size; + if (avctx->extradata && !s->extradata_parsed) { + if (ff_opus_parse_extradata(avctx, &s->ctx) < 0) { + av_log(avctx, AV_LOG_ERROR, "Error parsing Ogg extradata.\n"); + goto fail; + } + av_freep(&s->ctx.channel_maps); + s->extradata_parsed = 1; } - if (next == AVERROR_INVALIDDATA){ - *poutbuf = NULL; - *poutbuf_size = 0; - return buf_size; + if (ctx->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + + if (buf_size && set_frame_duration(ctx, avctx, buf, buf_size) < 0) + goto fail; + } else { + next = opus_find_frame_end(ctx, avctx, buf, buf_size, &header_len); + + if (s->ts_framing && next != AVERROR_INVALIDDATA && + ff_combine_frame(pc, next, &buf, &buf_size) < 0) { + goto fail; + } + + if (next == AVERROR_INVALIDDATA){ + goto fail; + } } *poutbuf = buf + header_len; *poutbuf_size = buf_size - header_len; return next; + +fail: + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; } -const AVCodecParser ff_opus_parser = { - .codec_ids = { AV_CODEC_ID_OPUS }, +const FFCodecParser ff_opus_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_OPUS), .priv_data_size = sizeof(OpusParserContext), - .parser_parse = opus_parse, - .parser_close = ff_parse_close + .parse = opus_parse, + .close = ff_parse_close }; diff --git a/libavcodec/opus/pvq.c b/libavcodec/opus/pvq.c index fe57ab02c..3dea7c19f 100644 --- a/libavcodec/opus/pvq.c +++ b/libavcodec/opus/pvq.c @@ -914,7 +914,7 @@ int av_cold ff_celt_pvq_init(CeltPVQ **pvq, int encode) #if CONFIG_OPUS_ENCODER s->pvq_search = ppp_pvq_search_c; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_celt_pvq_init_x86(s); #endif #endif diff --git a/libavcodec/opus/silk.c b/libavcodec/opus/silk.c index 97bb95037..ffa2ec996 100644 --- a/libavcodec/opus/silk.c +++ b/libavcodec/opus/silk.c @@ -844,8 +844,10 @@ int ff_silk_decode_superframe(SilkContext *s, OpusRangeCoder *rc, } for (i = 0; i < nb_frames; i++) { - for (j = 0; j < coded_channels && !s->midonly; j++) - silk_decode_frame(s, rc, i, j, coded_channels, active[j][i], active[1][i], 0); + for (j = 0; j < coded_channels && !s->midonly; j++) { + int active1 = coded_channels > 1 ? active[1][i] : 0; + silk_decode_frame(s, rc, i, j, coded_channels, active[j][i], active1, 0); + } /* reset the side channel if it is not coded */ if (s->midonly && s->frame[1].coded) diff --git a/libavcodec/opus/tab.c b/libavcodec/opus/tab.c index e7d20d168..5147b66b6 100644 --- a/libavcodec/opus/tab.c +++ b/libavcodec/opus/tab.c @@ -110,12 +110,8 @@ const uint16_t ff_silk_model_pitch_highbits[] = { 216, 224, 231, 237, 241, 243, 245, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256 }; -const uint16_t ff_silk_model_pitch_lowbits_nb[] = { 256, 64, 128, 192, 256 }; - const uint16_t ff_silk_model_pitch_lowbits_mb[] = { 256, 43, 85, 128, 171, 213, 256 }; -const uint16_t ff_silk_model_pitch_lowbits_wb[] = { 256, 32, 64, 96, 128, 160, 192, 224, 256 }; - const uint16_t ff_silk_model_pitch_delta[] = { 256, 46, 48, 50, 53, 57, 63, 73, 88, 114, 152, 182, 204, 219, 229, 236, 242, 246, 250, 252, 254, 256 @@ -763,8 +759,6 @@ const uint16_t ff_celt_model_alloc_trim[] = { 128, 2, 4, 9, 19, 41, 87, 109, 119, 124, 126, 128 }; -const uint16_t ff_celt_model_energy_small[] = { 4, 2, 3, 4 }; - const uint8_t ff_celt_freq_bands[] = { /* in steps of 200Hz */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100 }; @@ -1161,7 +1155,7 @@ const uint32_t * const ff_celt_pvq_u_row[15] = { }; /* Deemphasis constant (alpha_p), as specified in RFC6716 as 0.8500061035. - * libopus uses a slighly rounded constant, set to 0.85 exactly, + * libopus uses a slightly rounded constant, set to 0.85 exactly, * to simplify its fixed-point version, but it's not significant to impact * compliance. */ #define CELT_EMPH_COEFF 0.8500061035 diff --git a/libavcodec/opus/tab.h b/libavcodec/opus/tab.h index 109a422b9..04d2a59bb 100644 --- a/libavcodec/opus/tab.h +++ b/libavcodec/opus/tab.h @@ -28,6 +28,8 @@ #include "libavutil/attributes_internal.h" FF_VISIBILITY_PUSH_HIDDEN +extern const uint16_t ff_opus_frame_duration[32]; + extern const uint8_t ff_celt_band_end[]; extern const uint8_t ff_opus_default_coupled_streams[]; @@ -53,9 +55,9 @@ extern const uint16_t ff_silk_model_lsf_s2_ext[]; extern const uint16_t ff_silk_model_lsf_interpolation_offset[]; extern const uint16_t ff_silk_model_pitch_highbits[]; -extern const uint16_t ff_silk_model_pitch_lowbits_nb[]; +#define ff_silk_model_pitch_lowbits_nb ff_silk_model_lcg_seed extern const uint16_t ff_silk_model_pitch_lowbits_mb[]; -extern const uint16_t ff_silk_model_pitch_lowbits_wb[]; +#define ff_silk_model_pitch_lowbits_wb ff_silk_model_gain_lowbits extern const uint16_t ff_silk_model_pitch_delta[]; extern const uint16_t ff_silk_model_pitch_contour_nb10ms[]; extern const uint16_t ff_silk_model_pitch_contour_nb20ms[]; @@ -124,7 +126,7 @@ extern const int ff_silk_stereo_interp_len[3]; extern const uint16_t ff_celt_model_tapset[]; extern const uint16_t ff_celt_model_spread[]; extern const uint16_t ff_celt_model_alloc_trim[]; -extern const uint16_t ff_celt_model_energy_small[]; +#define ff_celt_model_energy_small ff_celt_model_tapset extern const uint8_t ff_celt_freq_bands[]; extern const uint8_t ff_celt_freq_range[]; @@ -159,7 +161,7 @@ extern const float ff_celt_postfilter_taps[3][3]; extern const float ff_celt_window2[120]; extern const float ff_celt_window_padded[]; -static const float *const ff_celt_window = &ff_celt_window_padded[8]; +#define ff_celt_window (ff_celt_window_padded + 8) extern const float ff_opus_deemph_weights[]; diff --git a/libavcodec/osq.c b/libavcodec/osq.c index 39743acbc..512581e0a 100644 --- a/libavcodec/osq.c +++ b/libavcodec/osq.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" @@ -62,7 +63,7 @@ typedef struct OSQContext { int pkt_offset; } OSQContext; -static void osq_flush(AVCodecContext *avctx) +static av_cold void osq_flush(AVCodecContext *avctx) { OSQContext *s = avctx->priv_data; @@ -494,9 +495,5 @@ const FFCodec ff_osq_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, .flush = osq_flush, }; diff --git a/libavcodec/packet.c b/libavcodec/packet.c index 381001fd6..348159f7f 100644 --- a/libavcodec/packet.c +++ b/libavcodec/packet.c @@ -23,7 +23,7 @@ #include "libavutil/avassert.h" #include "libavutil/avutil.h" -#include "libavutil/intreadwrite.h" +#include "libavutil/container_fifo.h" #include "libavutil/mathematics.h" #include "libavutil/mem.h" #include "libavutil/rational.h" @@ -307,6 +307,9 @@ const char *av_packet_side_data_name(enum AVPacketSideDataType type) case AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM: return "IAMF Recon Gain Info Parameter Data"; case AV_PKT_DATA_FRAME_CROPPING: return "Frame Cropping"; case AV_PKT_DATA_LCEVC: return "LCEVC NAL data"; + case AV_PKT_DATA_3D_REFERENCE_DISPLAYS: return "3D Reference Displays Info"; + case AV_PKT_DATA_RTCP_SR: return "RTCP Sender Report"; + case AV_PKT_DATA_EXIF: return "EXIF metadata"; } return NULL; } @@ -546,6 +549,7 @@ int avpriv_packet_list_put(PacketList *packet_buffer, int flags) { PacketListEntry *pktl = av_malloc(sizeof(*pktl)); + unsigned int update_end_point = 1; int ret; if (!pktl) @@ -569,13 +573,22 @@ int avpriv_packet_list_put(PacketList *packet_buffer, pktl->next = NULL; - if (packet_buffer->head) - packet_buffer->tail->next = pktl; - else + if (packet_buffer->head) { + if (flags & FF_PACKETLIST_FLAG_PREPEND) { + pktl->next = packet_buffer->head; + packet_buffer->head = pktl; + update_end_point = 0; + } else { + packet_buffer->tail->next = pktl; + } + } else packet_buffer->head = pktl; - /* Add the packet in the buffered packet list. */ - packet_buffer->tail = pktl; + if (update_end_point) { + /* Add the packet in the buffered packet list. */ + packet_buffer->tail = pktl; + } + return 0; } @@ -606,31 +619,6 @@ void avpriv_packet_list_free(PacketList *pkt_buf) pkt_buf->head = pkt_buf->tail = NULL; } -int ff_side_data_set_encoder_stats(AVPacket *pkt, int quality, int64_t *error, int error_count, int pict_type) -{ - uint8_t *side_data; - size_t side_data_size; - int i; - - side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, &side_data_size); - if (!side_data) { - side_data_size = 4+4+8*error_count; - side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, - side_data_size); - } - - if (!side_data || side_data_size < 4+4+8*error_count) - return AVERROR(ENOMEM); - - AV_WL32(side_data , quality ); - side_data[4] = pict_type; - side_data[5] = error_count; - for (i = 0; i= 0 Success + * @retval AVERROR(EINVAL) The frame side data type does not have a matching + * packet side data type. + * @retval AVERROR(ENOMEM) Failed to add a side data entry to the array, or + * similar. + */ +int av_packet_side_data_from_frame(AVPacketSideData **sd, int *nb_sd, + const struct AVFrameSideData *src, unsigned int flags); +/** + * Add a new frame side data entry to an array based on existing packet + * side data, if a matching type exists for frame side data. + * + * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, + * or 0. + * @retval >= 0 Success + * @retval AVERROR(EINVAL) The packet side data type does not have a matching + * frame side data type. + * @retval AVERROR(ENOMEM) Failed to add a side data entry to the array, or + * similar. + */ +int av_packet_side_data_to_frame(struct AVFrameSideData ***sd, int *nb_sd, + const AVPacketSideData *src, unsigned int flags); + const char *av_packet_side_data_name(enum AVPacketSideDataType type); /** @@ -880,6 +929,13 @@ int av_packet_make_writable(AVPacket *pkt); */ void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst); +/** + * Allocate an AVContainerFifo instance for AVPacket. + * + * @param flags currently unused + */ +struct AVContainerFifo *av_container_fifo_alloc_avpacket(unsigned flags); + /** * @} */ diff --git a/libavcodec/packet_internal.h b/libavcodec/packet_internal.h index 52fa6d9be..02471ed6d 100644 --- a/libavcodec/packet_internal.h +++ b/libavcodec/packet_internal.h @@ -34,6 +34,8 @@ typedef struct PacketList { PacketListEntry *head, *tail; } PacketList; +#define FF_PACKETLIST_FLAG_PREPEND (1 << 0) /**< Prepend created AVPacketList instead of appending */ + /** * Append an AVPacket to the list. * @@ -68,8 +70,6 @@ int avpriv_packet_list_get(PacketList *list, AVPacket *pkt); */ void avpriv_packet_list_free(PacketList *list); -int ff_side_data_set_encoder_stats(AVPacket *pkt, int quality, int64_t *error, int error_count, int pict_type); - int ff_side_data_set_prft(AVPacket *pkt, int64_t timestamp); #endif // AVCODEC_PACKET_INTERNAL_H diff --git a/libavcodec/pafvideo.c b/libavcodec/pafvideo.c index c17ae9ae4..d8d6db521 100644 --- a/libavcodec/pafvideo.c +++ b/libavcodec/pafvideo.c @@ -328,11 +328,6 @@ static int paf_video_decode(AVCodecContext *avctx, AVFrame *rframe, b = b << 2 | b >> 4; *out++ = (0xFFU << 24) | (r << 16) | (g << 8) | b; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - c->pic->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } c->dirty[c->current_frame] = 1; diff --git a/libavcodec/pamenc.c b/libavcodec/pamenc.c index 45ec29ccb..e0c6eda23 100644 --- a/libavcodec/pamenc.c +++ b/libavcodec/pamenc.c @@ -135,11 +135,9 @@ const FFCodec ff_pam_encoder = { .p.id = AV_CODEC_ID_PAM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pam_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, - AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE, - AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, + AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE, + AV_PIX_FMT_MONOBLACK), }; diff --git a/libavcodec/parser.c b/libavcodec/parser.c index 426cc314f..28f4de582 100644 --- a/libavcodec/parser.c +++ b/libavcodec/parser.c @@ -24,15 +24,23 @@ #include #include +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/mem.h" +#include "codec_desc.h" #include "parser.h" +#include "parser_internal.h" -AVCodecParserContext *av_parser_init(int codec_id) +#if FF_API_PARSER_CODECID +av_cold AVCodecParserContext *av_parser_init(int codec_id) +#else +av_cold AVCodecParserContext *av_parser_init(enum AVCodecID codec_id) +#endif { AVCodecParserContext *s = NULL; const AVCodecParser *parser; + const FFCodecParser *ffparser; void *i = 0; int ret; @@ -52,17 +60,18 @@ AVCodecParserContext *av_parser_init(int codec_id) return NULL; found: + ffparser = ffcodecparser(parser); s = av_mallocz(sizeof(AVCodecParserContext)); if (!s) goto err_out; s->parser = parser; - s->priv_data = av_mallocz(parser->priv_data_size); + s->priv_data = av_mallocz(ffparser->priv_data_size); if (!s->priv_data) goto err_out; s->fetch_timestamp=1; s->pict_type = AV_PICTURE_TYPE_I; - if (parser->parser_init) { - ret = parser->parser_init(s); + if (ffparser->init) { + ret = ffparser->init(s); if (ret != 0) goto err_out; } @@ -117,6 +126,7 @@ int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t *buf, int buf_size, int64_t pts, int64_t dts, int64_t pos) { + const AVCodecDescriptor *desc; int index, i; uint8_t dummy_buf[AV_INPUT_BUFFER_PADDING_SIZE]; @@ -131,6 +141,8 @@ int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, avctx->codec_id == s->parser->codec_ids[5] || avctx->codec_id == s->parser->codec_ids[6]); + desc = avcodec_descriptor_get(avctx->codec_id); + if (!(s->flags & PARSER_FLAG_FETCHED_OFFSET)) { s->next_frame_offset = s->cur_offset = pos; @@ -160,8 +172,8 @@ int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, ff_fetch_timestamp(s, 0, 0, 0); } /* WARNING: the returned index can be negative */ - index = s->parser->parser_parse(s, avctx, (const uint8_t **) poutbuf, - poutbuf_size, buf, buf_size); + index = ffcodecparser(s->parser)->parse(s, avctx, (const uint8_t **) poutbuf, + poutbuf_size, buf, buf_size); av_assert0(index > -0x20000000); // The API does not allow returning AVERROR codes #define FILL(name) if(s->name > 0 && avctx->name <= 0) avctx->name = s->name if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { @@ -170,6 +182,8 @@ int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, FILL(coded_height); FILL(width); FILL(height); + if (desc && (desc->props & AV_CODEC_PROP_ENHANCEMENT) && + s->format >= 0 && avctx->pix_fmt < 0) avctx->pix_fmt = s->format; } /* update the file pointer */ @@ -190,11 +204,11 @@ int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, return index; } -void av_parser_close(AVCodecParserContext *s) +av_cold void av_parser_close(AVCodecParserContext *s) { if (s) { - if (s->parser->parser_close) - s->parser->parser_close(s); + if (ffcodecparser(s->parser)->close) + ffcodecparser(s->parser)->close(s); av_freep(&s->priv_data); av_free(s); } @@ -287,7 +301,7 @@ int ff_combine_frame(ParseContext *pc, int next, return 0; } -void ff_parse_close(AVCodecParserContext *s) +av_cold void ff_parse_close(AVCodecParserContext *s) { ParseContext *pc = s->priv_data; diff --git a/libavcodec/parser_internal.h b/libavcodec/parser_internal.h new file mode 100644 index 000000000..fa9af971c --- /dev/null +++ b/libavcodec/parser_internal.h @@ -0,0 +1,83 @@ +/* + * 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_PARSER_INTERNAL_H +#define AVCODEC_PARSER_INTERNAL_H + +#include + +#include "libavutil/macros.h" +#include "avcodec.h" +#include "codec_id.h" + +#if FF_API_PARSER_PRIVATE +typedef union FFCodecParser { + struct { +#if FF_API_PARSER_CODECID + int codec_ids[7]; /* several codec IDs are permitted */ +#else + enum AVCodecID codec_ids[7]; /* several codec IDs are permitted */ +#endif + int priv_data_size; + int (*init)(AVCodecParserContext *s); + int (*parse)(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size); + void (*close)(AVCodecParserContext *s); + int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); + }; + AVCodecParser p; +#else +typedef struct FFCodecParser { + AVCodecParser p; + unsigned priv_data_size; + int (*init)(AVCodecParserContext *s); + int (*parse)(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size); + void (*close)(AVCodecParserContext *s); +#endif +} FFCodecParser; + +static inline const FFCodecParser *ffcodecparser(const AVCodecParser *parser) +{ + return (const FFCodecParser*)parser; +} + +#define EIGTH_ARG(a,b,c,d,e,f,g,h,...) h +#define NO_FAIL +// Expands to nothing if <= 7 args; induces compilation failure if not. +#define CHECK_FOR_TOO_MANY_IDS(...) AV_JOIN(EIGTH_ARG(__VA_ARGS__, NO, NO, NO, NO, NO, NO, NO, NO), _FAIL) + +// For compatibility with MSVC's old, spec-incompliant preprocessor. +#define FF_MSVC_EXPAND(...) __VA_ARGS__ +#define FIRST_SEVEN2(a,b,c,d,e,f,g,...) a,b,c,d,e,f,g +#define FIRST_SEVEN(...) FF_MSVC_EXPAND(FIRST_SEVEN2(__VA_ARGS__)) +#define TIMES_SEVEN(a) a,a,a,a,a,a,a + +#if FF_API_PARSER_PRIVATE +#define PARSER_CODEC_LIST(...) CHECK_FOR_TOO_MANY_IDS(__VA_ARGS__) \ + .codec_ids = { FIRST_SEVEN(__VA_ARGS__, TIMES_SEVEN(AV_CODEC_ID_NONE)) } +#else +#define PARSER_CODEC_LIST(...) CHECK_FOR_TOO_MANY_IDS(__VA_ARGS__) \ + .p.codec_ids = { FIRST_SEVEN(__VA_ARGS__, TIMES_SEVEN(AV_CODEC_ID_NONE)) } +#endif + +#endif /* AVCODEC_PARSER_INTERNAL_H */ diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c index 5128009cd..162b96cb6 100644 --- a/libavcodec/parsers.c +++ b/libavcodec/parsers.c @@ -19,77 +19,104 @@ #include #include "avcodec.h" +#include "parser_internal.h" -extern const AVCodecParser ff_aac_parser; -extern const AVCodecParser ff_aac_latm_parser; -extern const AVCodecParser ff_ac3_parser; -extern const AVCodecParser ff_adx_parser; -extern const AVCodecParser ff_amr_parser; -extern const AVCodecParser ff_av1_parser; -extern const AVCodecParser ff_avs2_parser; -extern const AVCodecParser ff_avs3_parser; -extern const AVCodecParser ff_bmp_parser; -extern const AVCodecParser ff_cavsvideo_parser; -extern const AVCodecParser ff_cook_parser; -extern const AVCodecParser ff_cri_parser; -extern const AVCodecParser ff_dca_parser; -extern const AVCodecParser ff_dirac_parser; -extern const AVCodecParser ff_dnxhd_parser; -extern const AVCodecParser ff_dolby_e_parser; -extern const AVCodecParser ff_dpx_parser; -extern const AVCodecParser ff_dvaudio_parser; -extern const AVCodecParser ff_dvbsub_parser; -extern const AVCodecParser ff_dvdsub_parser; -extern const AVCodecParser ff_dvd_nav_parser; -extern const AVCodecParser ff_evc_parser; -extern const AVCodecParser ff_flac_parser; -extern const AVCodecParser ff_ftr_parser; -extern const AVCodecParser ff_g723_1_parser; -extern const AVCodecParser ff_g729_parser; -extern const AVCodecParser ff_gif_parser; -extern const AVCodecParser ff_gsm_parser; -extern const AVCodecParser ff_h261_parser; -extern const AVCodecParser ff_h263_parser; -extern const AVCodecParser ff_h264_parser; -extern const AVCodecParser ff_hevc_parser; -extern const AVCodecParser ff_hdr_parser; -extern const AVCodecParser ff_ipu_parser; -extern const AVCodecParser ff_jpeg2000_parser; -extern const AVCodecParser ff_jpegxl_parser; -extern const AVCodecParser ff_misc4_parser; -extern const AVCodecParser ff_mjpeg_parser; -extern const AVCodecParser ff_mlp_parser; -extern const AVCodecParser ff_mpeg4video_parser; -extern const AVCodecParser ff_mpegaudio_parser; -extern const AVCodecParser ff_mpegvideo_parser; -extern const AVCodecParser ff_opus_parser; -extern const AVCodecParser ff_png_parser; -extern const AVCodecParser ff_pnm_parser; -extern const AVCodecParser ff_qoi_parser; -extern const AVCodecParser ff_rv34_parser; -extern const AVCodecParser ff_sbc_parser; -extern const AVCodecParser ff_sipr_parser; -extern const AVCodecParser ff_tak_parser; -extern const AVCodecParser ff_vc1_parser; -extern const AVCodecParser ff_vorbis_parser; -extern const AVCodecParser ff_vp3_parser; -extern const AVCodecParser ff_vp8_parser; -extern const AVCodecParser ff_vp9_parser; -extern const AVCodecParser ff_vvc_parser; -extern const AVCodecParser ff_webp_parser; -extern const AVCodecParser ff_xbm_parser; -extern const AVCodecParser ff_xma_parser; -extern const AVCodecParser ff_xwd_parser; +#if FF_API_PARSER_PRIVATE +#include "libavutil/internal.h" +#include +#include + +FF_DISABLE_DEPRECATION_WARNINGS +#define CHECK_OFFSET(field, public_prefix) static_assert(offsetof(FFCodecParser, field) == offsetof(FFCodecParser, p.public_prefix ## field), "Wrong offsets") +CHECK_OFFSET(codec_ids,); +CHECK_OFFSET(priv_data_size,); +CHECK_OFFSET(init, parser_); +CHECK_OFFSET(parse, parser_); +CHECK_OFFSET(close, parser_); +CHECK_OFFSET(split,); +FF_ENABLE_DEPRECATION_WARNINGS +#endif + +extern const FFCodecParser ff_aac_parser; +extern const FFCodecParser ff_aac_latm_parser; +extern const FFCodecParser ff_ac3_parser; +extern const FFCodecParser ff_adx_parser; +extern const FFCodecParser ff_ahx_parser; +extern const FFCodecParser ff_amr_parser; +extern const FFCodecParser ff_apv_parser; +extern const FFCodecParser ff_av1_parser; +extern const FFCodecParser ff_avs2_parser; +extern const FFCodecParser ff_avs3_parser; +extern const FFCodecParser ff_bmp_parser; +extern const FFCodecParser ff_cavsvideo_parser; +extern const FFCodecParser ff_cook_parser; +extern const FFCodecParser ff_cri_parser; +extern const FFCodecParser ff_dca_parser; +extern const FFCodecParser ff_dirac_parser; +extern const FFCodecParser ff_dnxhd_parser; +extern const FFCodecParser ff_dnxuc_parser; +extern const FFCodecParser ff_dolby_e_parser; +extern const FFCodecParser ff_dpx_parser; +extern const FFCodecParser ff_dvaudio_parser; +extern const FFCodecParser ff_dvbsub_parser; +extern const FFCodecParser ff_dvdsub_parser; +extern const FFCodecParser ff_dvd_nav_parser; +extern const FFCodecParser ff_evc_parser; +extern const FFCodecParser ff_flac_parser; +extern const FFCodecParser ff_ftr_parser; +extern const FFCodecParser ff_ffv1_parser; +extern const FFCodecParser ff_g723_1_parser; +extern const FFCodecParser ff_g729_parser; +extern const FFCodecParser ff_gif_parser; +extern const FFCodecParser ff_gsm_parser; +extern const FFCodecParser ff_h261_parser; +extern const FFCodecParser ff_h263_parser; +extern const FFCodecParser ff_h264_parser; +extern const FFCodecParser ff_hevc_parser; +extern const FFCodecParser ff_hdr_parser; +extern const FFCodecParser ff_ipu_parser; +extern const FFCodecParser ff_jpeg2000_parser; +extern const FFCodecParser ff_jpegxl_parser; +extern const FFCodecParser ff_jpegxs_parser; +extern const FFCodecParser ff_lcevc_parser; +extern const FFCodecParser ff_misc4_parser; +extern const FFCodecParser ff_mjpeg_parser; +extern const FFCodecParser ff_mlp_parser; +extern const FFCodecParser ff_mpeg4video_parser; +extern const FFCodecParser ff_mpegaudio_parser; +extern const FFCodecParser ff_mpegvideo_parser; +extern const FFCodecParser ff_opus_parser; +extern const FFCodecParser ff_prores_parser; +extern const FFCodecParser ff_png_parser; +extern const FFCodecParser ff_pnm_parser; +extern const FFCodecParser ff_prores_raw_parser; +extern const FFCodecParser ff_qoi_parser; +extern const FFCodecParser ff_rv34_parser; +extern const FFCodecParser ff_sbc_parser; +extern const FFCodecParser ff_sipr_parser; +extern const FFCodecParser ff_tak_parser; +extern const FFCodecParser ff_vc1_parser; +extern const FFCodecParser ff_vorbis_parser; +extern const FFCodecParser ff_vp3_parser; +extern const FFCodecParser ff_vp8_parser; +extern const FFCodecParser ff_vp9_parser; +extern const FFCodecParser ff_vvc_parser; +extern const FFCodecParser ff_webp_parser; +extern const FFCodecParser ff_xbm_parser; +extern const FFCodecParser ff_xma_parser; +extern const FFCodecParser ff_xwd_parser; #include "libavcodec/parser_list.c" const AVCodecParser *av_parser_iterate(void **opaque) { uintptr_t i = (uintptr_t)*opaque; - const AVCodecParser *p = parser_list[i]; + const FFCodecParser *p = parser_list[i]; - if (p) + if (p) { *opaque = (void*)(i + 1); + return &p->p; + } - return p; + return NULL; } diff --git a/libavcodec/pcm-bluray.c b/libavcodec/pcm-bluray.c index 235020d78..194224c67 100644 --- a/libavcodec/pcm-bluray.c +++ b/libavcodec/pcm-bluray.c @@ -307,7 +307,4 @@ const FFCodec ff_pcm_bluray_decoder = { .p.id = AV_CODEC_ID_PCM_BLURAY, FF_CODEC_DECODE_CB(pcm_bluray_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]){ - AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE - }, }; diff --git a/libavcodec/pcm-blurayenc.c b/libavcodec/pcm-blurayenc.c index 7147c804a..006c16d2d 100644 --- a/libavcodec/pcm-blurayenc.c +++ b/libavcodec/pcm-blurayenc.c @@ -278,20 +278,12 @@ const FFCodec ff_pcm_bluray_encoder = { .priv_data_size = sizeof(BlurayPCMEncContext), .init = pcm_bluray_encode_init, FF_CODEC_ENCODE_CB(pcm_bluray_encode_frame), - .p.supported_samplerates = (const int[]) { 48000, 96000, 192000, 0 }, - .p.ch_layouts = (const AVChannelLayout[]) { - AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - AV_CHANNEL_LAYOUT_SURROUND, - AV_CHANNEL_LAYOUT_2_1, - AV_CHANNEL_LAYOUT_4POINT0, - AV_CHANNEL_LAYOUT_2_2, - AV_CHANNEL_LAYOUT_5POINT0, - AV_CHANNEL_LAYOUT_5POINT1, - AV_CHANNEL_LAYOUT_7POINT0, - AV_CHANNEL_LAYOUT_7POINT1, - { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLERATES(48000, 96000, 192000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO, + AV_CHANNEL_LAYOUT_SURROUND, AV_CHANNEL_LAYOUT_2_1, + AV_CHANNEL_LAYOUT_4POINT0, AV_CHANNEL_LAYOUT_2_2, + AV_CHANNEL_LAYOUT_5POINT0, AV_CHANNEL_LAYOUT_5POINT1, + AV_CHANNEL_LAYOUT_7POINT0, AV_CHANNEL_LAYOUT_7POINT1), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, }; diff --git a/libavcodec/pcm-dvd.c b/libavcodec/pcm-dvd.c index 319746c62..b3f0624b5 100644 --- a/libavcodec/pcm-dvd.c +++ b/libavcodec/pcm-dvd.c @@ -305,7 +305,4 @@ const FFCodec ff_pcm_dvd_decoder = { FF_CODEC_DECODE_CB(pcm_dvd_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE - }, }; diff --git a/libavcodec/pcm-dvdenc.c b/libavcodec/pcm-dvdenc.c index 71e9b6915..a740f0e38 100644 --- a/libavcodec/pcm-dvdenc.c +++ b/libavcodec/pcm-dvdenc.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "avcodec.h" #include "bytestream.h" @@ -45,7 +46,7 @@ static av_cold int pcm_dvd_encode_init(AVCodecContext *avctx) freq = 1; break; default: - av_assert1(0); + av_unreachable("Already checked via CODEC_SAMPLERATES"); } switch (avctx->sample_fmt) { @@ -58,7 +59,7 @@ static av_cold int pcm_dvd_encode_init(AVCodecContext *avctx) quant = 2; break; default: - av_assert1(0); + av_unreachable("Already checked via CODEC_SAMPLEFMTS"); } avctx->bits_per_coded_sample = 16 + quant * 4; @@ -181,13 +182,8 @@ const FFCodec ff_pcm_dvd_encoder = { .priv_data_size = sizeof(PCMDVDContext), .init = pcm_dvd_encode_init, FF_CODEC_ENCODE_CB(pcm_dvd_encode_frame), - .p.supported_samplerates = (const int[]) { 48000, 96000, 0}, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - AV_CHANNEL_LAYOUT_5POINT1, - AV_CHANNEL_LAYOUT_7POINT1, - { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLERATES(48000, 96000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO, + AV_CHANNEL_LAYOUT_5POINT1, AV_CHANNEL_LAYOUT_7POINT1), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), }; diff --git a/libavcodec/pcm.c b/libavcodec/pcm.c index a51086a92..157adc92d 100644 --- a/libavcodec/pcm.c +++ b/libavcodec/pcm.c @@ -38,21 +38,32 @@ #include "encode.h" #include "pcm_tablegen.h" -static av_cold int pcm_encode_init(AVCodecContext *avctx) +av_unused av_cold static int pcm_encode_init(AVCodecContext *avctx) { avctx->frame_size = 0; #if !CONFIG_HARDCODED_TABLES switch (avctx->codec->id) { -#define INIT_ONCE(id, name) \ - case AV_CODEC_ID_PCM_ ## id: \ - if (CONFIG_PCM_ ## id ## _ENCODER) { \ - static AVOnce init_static_once = AV_ONCE_INIT; \ - ff_thread_once(&init_static_once, pcm_ ## name ## _tableinit); \ - } \ - break - INIT_ONCE(ALAW, alaw); - INIT_ONCE(MULAW, ulaw); - INIT_ONCE(VIDC, vidc); +#if CONFIG_PCM_ALAW_ENCODER + case AV_CODEC_ID_PCM_ALAW: { + static AVOnce once_alaw = AV_ONCE_INIT; + ff_thread_once(&once_alaw, pcm_alaw_tableinit); + break; + } +#endif +#if CONFIG_PCM_MULAW_ENCODER + case AV_CODEC_ID_PCM_MULAW: { + static AVOnce once_mulaw = AV_ONCE_INIT; + ff_thread_once(&once_mulaw, pcm_ulaw_tableinit); + break; + } +#endif +#if CONFIG_PCM_VIDC_ENCODER + case AV_CODEC_ID_PCM_VIDC: { + static AVOnce once_vidc = AV_ONCE_INIT; + ff_thread_once(&once_vidc, pcm_vidc_tableinit); + break; + } +#endif default: break; } @@ -93,10 +104,10 @@ static av_cold int pcm_encode_init(AVCodecContext *avctx) } \ } -static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, - const AVFrame *frame, int *got_packet_ptr) +av_unused static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) { - int n, c, sample_size, v, ret; + int n, c, sample_size, ret; const short *samples; unsigned char *dst; const uint8_t *samples_uint8_t; @@ -216,24 +227,30 @@ static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, bytestream_put_buffer(&dst, src, n * sample_size); } break; +#if CONFIG_PCM_ALAW_ENCODER case AV_CODEC_ID_PCM_ALAW: for (; n > 0; n--) { - v = *samples++; + int v = *samples++; *dst++ = linear_to_alaw[(v + 32768) >> 2]; } break; +#endif +#if CONFIG_PCM_MULAW_ENCODER case AV_CODEC_ID_PCM_MULAW: for (; n > 0; n--) { - v = *samples++; + int v = *samples++; *dst++ = linear_to_ulaw[(v + 32768) >> 2]; } break; +#endif +#if CONFIG_PCM_VIDC_ENCODER case AV_CODEC_ID_PCM_VIDC: for (; n > 0; n--) { - v = *samples++; + int v = *samples++; *dst++ = linear_to_vidc[(v + 32768) >> 2]; } break; +#endif default: return -1; } @@ -243,51 +260,114 @@ static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } typedef struct PCMDecode { - short table[256]; + int sample_size; +} PCMDecode; + +av_unused av_cold static int pcm_decode_init(AVCodecContext *avctx) +{ + PCMDecode *s = avctx->priv_data; + static const struct { + enum AVCodecID codec_id; + int8_t sample_fmt; + uint8_t sample_size; + uint8_t bits_per_sample; + } codec_id_to_samplefmt[] = { + #define ENTRY(CODEC_ID, SAMPLE_FMT, BITS_PER_SAMPLE) \ + { AV_CODEC_ID_PCM_ ## CODEC_ID, AV_SAMPLE_FMT_ ## SAMPLE_FMT, \ + BITS_PER_SAMPLE / 8, BITS_PER_SAMPLE } + ENTRY(S8, U8, 8), ENTRY(S8_PLANAR, U8P, 8), + ENTRY(S16BE, S16, 16), ENTRY(S16BE_PLANAR, S16P, 16), + ENTRY(S16LE, S16, 16), ENTRY(S16LE_PLANAR, S16P, 16), + ENTRY(S24DAUD, S16, 24), ENTRY(S24BE, S32, 24), + ENTRY(S24LE, S32, 24), ENTRY(S24LE_PLANAR, S32P, 24), + ENTRY(S32BE, S32, 32), ENTRY(S32LE, S32, 32), + ENTRY(S32LE_PLANAR, S32P, 32), + ENTRY(S64BE, S64, 64), ENTRY(S64LE, S64, 64), + ENTRY(SGA, U8, 8), ENTRY(U8, U8, 8), + ENTRY(U16BE, S16, 16), ENTRY(U16LE, S16, 16), + ENTRY(U24BE, S32, 24), ENTRY(U24LE, S32, 24), + ENTRY(U32BE, S32, 32), ENTRY(U32LE, S32, 32), + ENTRY(F32BE, FLT, 32), ENTRY(F32LE, FLT, 32), + ENTRY(F64BE, DBL, 64), ENTRY(F64LE, DBL, 64), + { .codec_id = AV_CODEC_ID_PCM_LXF, .sample_fmt = AV_SAMPLE_FMT_S32P, .sample_size = 5 }, + }; + + for (unsigned i = 0; i < FF_ARRAY_ELEMS(codec_id_to_samplefmt); ++i) { + if (codec_id_to_samplefmt[i].codec_id == avctx->codec_id) { + s->sample_size = codec_id_to_samplefmt[i].sample_size; + avctx->sample_fmt = codec_id_to_samplefmt[i].sample_fmt; + if (avctx->sample_fmt == AV_SAMPLE_FMT_S32) + avctx->bits_per_raw_sample = codec_id_to_samplefmt[i].bits_per_sample; + break; + } + av_assert1(i + 1 < FF_ARRAY_ELEMS(codec_id_to_samplefmt)); + } + + return 0; +} + +typedef struct PCMScaleDecode { + PCMDecode base; void (*vector_fmul_scalar)(float *dst, const float *src, float mul, int len); float scale; -} PCMDecode; +} PCMScaleDecode; -static av_cold int pcm_decode_init(AVCodecContext *avctx) +av_unused av_cold static int pcm_scale_decode_init(AVCodecContext *avctx) { - PCMDecode *s = avctx->priv_data; + PCMScaleDecode *s = avctx->priv_data; AVFloatDSPContext *fdsp; - int i; + + avctx->sample_fmt = AV_SAMPLE_FMT_FLT; + s->base.sample_size = 4; + + if (avctx->bits_per_coded_sample < 1 || avctx->bits_per_coded_sample > 24) + return AVERROR_INVALIDDATA; + + s->scale = 1. / (1 << (avctx->bits_per_coded_sample - 1)); + fdsp = avpriv_float_dsp_alloc(0); + if (!fdsp) + return AVERROR(ENOMEM); + s->vector_fmul_scalar = fdsp->vector_fmul_scalar; + av_free(fdsp); + + return 0; +} + +typedef struct PCMLUTDecode { + PCMDecode base; + int16_t table[256]; +} PCMLUTDecode; + +av_unused av_cold static int pcm_lut_decode_init(AVCodecContext *avctx) +{ + PCMLUTDecode *s = avctx->priv_data; switch (avctx->codec_id) { + default: + av_unreachable("pcm_lut_decode_init() only used with alaw, mulaw and vidc"); +#if CONFIG_PCM_ALAW_DECODER case AV_CODEC_ID_PCM_ALAW: - for (i = 0; i < 256; i++) + for (int i = 0; i < 256; i++) s->table[i] = alaw2linear(i); break; +#endif +#if CONFIG_PCM_MULAW_DECODER case AV_CODEC_ID_PCM_MULAW: - for (i = 0; i < 256; i++) + for (int i = 0; i < 256; i++) s->table[i] = ulaw2linear(i); break; +#endif +#if CONFIG_PCM_VIDC_DECODER case AV_CODEC_ID_PCM_VIDC: - for (i = 0; i < 256; i++) + for (int i = 0; i < 256; i++) s->table[i] = vidc2linear(i); break; - case AV_CODEC_ID_PCM_F16LE: - case AV_CODEC_ID_PCM_F24LE: - if (avctx->bits_per_coded_sample < 1 || avctx->bits_per_coded_sample > 24) - return AVERROR_INVALIDDATA; - - s->scale = 1. / (1 << (avctx->bits_per_coded_sample - 1)); - fdsp = avpriv_float_dsp_alloc(0); - if (!fdsp) - return AVERROR(ENOMEM); - s->vector_fmul_scalar = fdsp->vector_fmul_scalar; - av_free(fdsp); - break; - default: - break; +#endif } - avctx->sample_fmt = avctx->codec->sample_fmts[0]; - - if (avctx->sample_fmt == AV_SAMPLE_FMT_S32) - avctx->bits_per_raw_sample = av_get_bits_per_sample(avctx->codec_id); + avctx->sample_fmt = AV_SAMPLE_FMT_S16; + s->base.sample_size = 1; return 0; } @@ -328,23 +408,15 @@ static int pcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, int buf_size = avpkt->size; PCMDecode *s = avctx->priv_data; int channels = avctx->ch_layout.nb_channels; - int sample_size, c, n, ret, samples_per_block; + int sample_size = s->sample_size; + int c, n, ret, samples_per_block; uint8_t *samples; int32_t *dst_int32_t; - sample_size = av_get_bits_per_sample(avctx->codec_id) / 8; - - /* av_get_bits_per_sample returns 0 for AV_CODEC_ID_PCM_DVD */ samples_per_block = 1; if (avctx->codec_id == AV_CODEC_ID_PCM_LXF) { /* we process 40-bit blocks per channel for LXF */ samples_per_block = 2; - sample_size = 5; - } - - if (sample_size == 0) { - av_log(avctx, AV_LOG_ERROR, "Invalid sample_size\n"); - return AVERROR(EINVAL); } if (channels == 0) { @@ -498,14 +570,19 @@ static int pcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, bytestream_get_buffer(&src, samples, n * sample_size); } break; +#if CONFIG_PCM_ALAW_DECODER || CONFIG_PCM_MULAW_DECODER || \ + CONFIG_PCM_VIDC_DECODER case AV_CODEC_ID_PCM_ALAW: case AV_CODEC_ID_PCM_MULAW: - case AV_CODEC_ID_PCM_VIDC: - for (; n > 0; n--) { - AV_WN16A(samples, s->table[*src++]); - samples += 2; - } + case AV_CODEC_ID_PCM_VIDC: { + const int16_t *const lut = ((PCMLUTDecode*)avctx->priv_data)->table; + int16_t *restrict samples_16 = (int16_t*)samples; + + for (; n > 0; n--) + *samples_16++ = lut[*src++]; break; + } +#endif case AV_CODEC_ID_PCM_LXF: { int i; @@ -536,9 +613,10 @@ static int pcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, if (avctx->codec_id == AV_CODEC_ID_PCM_F16LE || avctx->codec_id == AV_CODEC_ID_PCM_F24LE) { - s->vector_fmul_scalar((float *)frame->extended_data[0], - (const float *)frame->extended_data[0], - s->scale, FFALIGN(frame->nb_samples * avctx->ch_layout.nb_channels, 4)); + PCMScaleDecode *s2 = avctx->priv_data; + s2->vector_fmul_scalar((float *)frame->extended_data[0], + (const float *)frame->extended_data[0], + s2->scale, FFALIGN(frame->nb_samples * avctx->ch_layout.nb_channels, 4)); } *got_frame_ptr = 1; @@ -552,13 +630,12 @@ const FFCodec ff_ ## name_ ## _encoder = { \ .p.name = #name_, \ CODEC_LONG_NAME(long_name_), \ .p.type = AVMEDIA_TYPE_AUDIO, \ - .p.id = AV_CODEC_ID_ ## id_, \ + .p.id = id_, \ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_VARIABLE_FRAME_SIZE | \ AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, \ .init = pcm_encode_init, \ FF_CODEC_ENCODE_CB(pcm_encode_frame), \ - .p.sample_fmts = (const enum AVSampleFormat[]){ sample_fmt_, \ - AV_SAMPLE_FMT_NONE }, \ + CODEC_SAMPLEFMTS(sample_fmt_), \ } #define PCM_ENCODER_2(cf, id, sample_fmt, name, long_name) \ @@ -566,65 +643,76 @@ const FFCodec ff_ ## name_ ## _encoder = { \ #define PCM_ENCODER_3(cf, id, sample_fmt, name, long_name) \ PCM_ENCODER_2(cf, id, sample_fmt, name, long_name) #define PCM_ENCODER(id, sample_fmt, name, long_name) \ - PCM_ENCODER_3(CONFIG_ ## id ## _ENCODER, id, sample_fmt, name, long_name) + PCM_ENCODER_3(CONFIG_PCM_ ## id ## _ENCODER, AV_CODEC_ID_PCM_ ## id, \ + AV_SAMPLE_FMT_ ## sample_fmt, pcm_ ## name, long_name) -#define PCM_DECODER_0(id, sample_fmt, name, long_name) -#define PCM_DECODER_1(id_, sample_fmt_, name_, long_name_) \ +#define PCM_DECODER_0(id, sample_fmt, name, long_name, Context, init_func) +#define PCM_DECODER_1(id_, sample_fmt, name_, long_name, Context, init_func)\ const FFCodec ff_ ## name_ ## _decoder = { \ .p.name = #name_, \ - CODEC_LONG_NAME(long_name_), \ + CODEC_LONG_NAME(long_name), \ .p.type = AVMEDIA_TYPE_AUDIO, \ - .p.id = AV_CODEC_ID_ ## id_, \ - .priv_data_size = sizeof(PCMDecode), \ - .init = pcm_decode_init, \ + .p.id = id_, \ + .priv_data_size = sizeof(Context), \ + .init = init_func, \ FF_CODEC_DECODE_CB(pcm_decode_frame), \ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_PARAM_CHANGE, \ - .p.sample_fmts = (const enum AVSampleFormat[]){ sample_fmt_, \ - AV_SAMPLE_FMT_NONE }, \ } -#define PCM_DECODER_2(cf, id, sample_fmt, name, long_name) \ - PCM_DECODER_ ## cf(id, sample_fmt, name, long_name) -#define PCM_DECODER_3(cf, id, sample_fmt, name, long_name) \ - PCM_DECODER_2(cf, id, sample_fmt, name, long_name) -#define PCM_DECODER(id, sample_fmt, name, long_name) \ - PCM_DECODER_3(CONFIG_ ## id ## _DECODER, id, sample_fmt, name, long_name) +#define PCM_DECODER_2(cf, id, sample_fmt, name, long_name, Context, init_func) \ + PCM_DECODER_ ## cf(id, sample_fmt, name, long_name, Context, init_func) +#define PCM_DECODER_3(cf, id, sample_fmt, name, long_name, Context, init_func) \ + PCM_DECODER_2(cf, id, sample_fmt, name, long_name, Context, init_func) +#define PCM_DEC_EXT(id, sample_fmt, name, long_name, Context, init_func) \ + PCM_DECODER_3(CONFIG_PCM_ ## id ## _DECODER, AV_CODEC_ID_PCM_ ## id, \ + AV_SAMPLE_FMT_ ## sample_fmt, pcm_ ## name, long_name, \ + Context, init_func) + +#define PCM_DECODER(id, sample_fmt, name, long_name) \ + PCM_DEC_EXT(id, sample_fmt, name, long_name, PCMDecode, pcm_decode_init) #define PCM_CODEC(id, sample_fmt_, name, long_name_) \ PCM_ENCODER(id, sample_fmt_, name, long_name_); \ PCM_DECODER(id, sample_fmt_, name, long_name_) -/* Note: Do not forget to add new entries to the Makefile as well. */ -PCM_CODEC (PCM_ALAW, AV_SAMPLE_FMT_S16, pcm_alaw, "PCM A-law / G.711 A-law"); -PCM_DECODER(PCM_F16LE, AV_SAMPLE_FMT_FLT, pcm_f16le, "PCM 16.8 floating point little-endian"); -PCM_DECODER(PCM_F24LE, AV_SAMPLE_FMT_FLT, pcm_f24le, "PCM 24.0 floating point little-endian"); -PCM_CODEC (PCM_F32BE, AV_SAMPLE_FMT_FLT, pcm_f32be, "PCM 32-bit floating point big-endian"); -PCM_CODEC (PCM_F32LE, AV_SAMPLE_FMT_FLT, pcm_f32le, "PCM 32-bit floating point little-endian"); -PCM_CODEC (PCM_F64BE, AV_SAMPLE_FMT_DBL, pcm_f64be, "PCM 64-bit floating point big-endian"); -PCM_CODEC (PCM_F64LE, AV_SAMPLE_FMT_DBL, pcm_f64le, "PCM 64-bit floating point little-endian"); -PCM_DECODER(PCM_LXF, AV_SAMPLE_FMT_S32P,pcm_lxf, "PCM signed 20-bit little-endian planar"); -PCM_CODEC (PCM_MULAW, AV_SAMPLE_FMT_S16, pcm_mulaw, "PCM mu-law / G.711 mu-law"); -PCM_CODEC (PCM_S8, AV_SAMPLE_FMT_U8, pcm_s8, "PCM signed 8-bit"); -PCM_CODEC (PCM_S8_PLANAR, AV_SAMPLE_FMT_U8P, pcm_s8_planar, "PCM signed 8-bit planar"); -PCM_CODEC (PCM_S16BE, AV_SAMPLE_FMT_S16, pcm_s16be, "PCM signed 16-bit big-endian"); -PCM_CODEC (PCM_S16BE_PLANAR, AV_SAMPLE_FMT_S16P,pcm_s16be_planar, "PCM signed 16-bit big-endian planar"); -PCM_CODEC (PCM_S16LE, AV_SAMPLE_FMT_S16, pcm_s16le, "PCM signed 16-bit little-endian"); -PCM_CODEC (PCM_S16LE_PLANAR, AV_SAMPLE_FMT_S16P,pcm_s16le_planar, "PCM signed 16-bit little-endian planar"); -PCM_CODEC (PCM_S24BE, AV_SAMPLE_FMT_S32, pcm_s24be, "PCM signed 24-bit big-endian"); -PCM_CODEC (PCM_S24DAUD, AV_SAMPLE_FMT_S16, pcm_s24daud, "PCM D-Cinema audio signed 24-bit"); -PCM_CODEC (PCM_S24LE, AV_SAMPLE_FMT_S32, pcm_s24le, "PCM signed 24-bit little-endian"); -PCM_CODEC (PCM_S24LE_PLANAR, AV_SAMPLE_FMT_S32P,pcm_s24le_planar, "PCM signed 24-bit little-endian planar"); -PCM_CODEC (PCM_S32BE, AV_SAMPLE_FMT_S32, pcm_s32be, "PCM signed 32-bit big-endian"); -PCM_CODEC (PCM_S32LE, AV_SAMPLE_FMT_S32, pcm_s32le, "PCM signed 32-bit little-endian"); -PCM_CODEC (PCM_S32LE_PLANAR, AV_SAMPLE_FMT_S32P,pcm_s32le_planar, "PCM signed 32-bit little-endian planar"); -PCM_CODEC (PCM_U8, AV_SAMPLE_FMT_U8, pcm_u8, "PCM unsigned 8-bit"); -PCM_CODEC (PCM_U16BE, AV_SAMPLE_FMT_S16, pcm_u16be, "PCM unsigned 16-bit big-endian"); -PCM_CODEC (PCM_U16LE, AV_SAMPLE_FMT_S16, pcm_u16le, "PCM unsigned 16-bit little-endian"); -PCM_CODEC (PCM_U24BE, AV_SAMPLE_FMT_S32, pcm_u24be, "PCM unsigned 24-bit big-endian"); -PCM_CODEC (PCM_U24LE, AV_SAMPLE_FMT_S32, pcm_u24le, "PCM unsigned 24-bit little-endian"); -PCM_CODEC (PCM_U32BE, AV_SAMPLE_FMT_S32, pcm_u32be, "PCM unsigned 32-bit big-endian"); -PCM_CODEC (PCM_U32LE, AV_SAMPLE_FMT_S32, pcm_u32le, "PCM unsigned 32-bit little-endian"); -PCM_CODEC (PCM_S64BE, AV_SAMPLE_FMT_S64, pcm_s64be, "PCM signed 64-bit big-endian"); -PCM_CODEC (PCM_S64LE, AV_SAMPLE_FMT_S64, pcm_s64le, "PCM signed 64-bit little-endian"); -PCM_CODEC (PCM_VIDC, AV_SAMPLE_FMT_S16, pcm_vidc, "PCM Archimedes VIDC"); -PCM_DECODER(PCM_SGA, AV_SAMPLE_FMT_U8, pcm_sga, "PCM SGA"); +#define PCM_CODEC_EXT(id, sample_fmt, name, long_name, DecContext, dec_init_func) \ + PCM_DEC_EXT(id, sample_fmt, name, long_name, DecContext, dec_init_func); \ + PCM_ENCODER(id, sample_fmt, name, long_name) + +/* Note: Do not forget to add new entries to the Makefile and + * to the table in pcm_decode_init() as well. */ +// AV_CODEC_ID_* pcm_* name +// AV_SAMPLE_FMT_* long name DecodeContext decode init func +PCM_CODEC_EXT(ALAW, S16, alaw, "PCM A-law / G.711 A-law", PCMLUTDecode, pcm_lut_decode_init); +PCM_DEC_EXT (F16LE, FLT, f16le, "PCM 16.8 floating point little-endian", PCMScaleDecode, pcm_scale_decode_init); +PCM_DEC_EXT (F24LE, FLT, f24le, "PCM 24.0 floating point little-endian", PCMScaleDecode, pcm_scale_decode_init); +PCM_CODEC (F32BE, FLT, f32be, "PCM 32-bit floating point big-endian"); +PCM_CODEC (F32LE, FLT, f32le, "PCM 32-bit floating point little-endian"); +PCM_CODEC (F64BE, DBL, f64be, "PCM 64-bit floating point big-endian"); +PCM_CODEC (F64LE, DBL, f64le, "PCM 64-bit floating point little-endian"); +PCM_DECODER (LXF, S32P,lxf, "PCM signed 20-bit little-endian planar"); +PCM_CODEC_EXT(MULAW, S16, mulaw, "PCM mu-law / G.711 mu-law", PCMLUTDecode, pcm_lut_decode_init); +PCM_CODEC (S8, U8, s8, "PCM signed 8-bit"); +PCM_CODEC (S8_PLANAR, U8P, s8_planar, "PCM signed 8-bit planar"); +PCM_CODEC (S16BE, S16, s16be, "PCM signed 16-bit big-endian"); +PCM_CODEC (S16BE_PLANAR, S16P,s16be_planar, "PCM signed 16-bit big-endian planar"); +PCM_CODEC (S16LE, S16, s16le, "PCM signed 16-bit little-endian"); +PCM_CODEC (S16LE_PLANAR, S16P,s16le_planar, "PCM signed 16-bit little-endian planar"); +PCM_CODEC (S24BE, S32, s24be, "PCM signed 24-bit big-endian"); +PCM_CODEC (S24DAUD, S16, s24daud, "PCM D-Cinema audio signed 24-bit"); +PCM_CODEC (S24LE, S32, s24le, "PCM signed 24-bit little-endian"); +PCM_CODEC (S24LE_PLANAR, S32P,s24le_planar, "PCM signed 24-bit little-endian planar"); +PCM_CODEC (S32BE, S32, s32be, "PCM signed 32-bit big-endian"); +PCM_CODEC (S32LE, S32, s32le, "PCM signed 32-bit little-endian"); +PCM_CODEC (S32LE_PLANAR, S32P,s32le_planar, "PCM signed 32-bit little-endian planar"); +PCM_CODEC (U8, U8, u8, "PCM unsigned 8-bit"); +PCM_CODEC (U16BE, S16, u16be, "PCM unsigned 16-bit big-endian"); +PCM_CODEC (U16LE, S16, u16le, "PCM unsigned 16-bit little-endian"); +PCM_CODEC (U24BE, S32, u24be, "PCM unsigned 24-bit big-endian"); +PCM_CODEC (U24LE, S32, u24le, "PCM unsigned 24-bit little-endian"); +PCM_CODEC (U32BE, S32, u32be, "PCM unsigned 32-bit big-endian"); +PCM_CODEC (U32LE, S32, u32le, "PCM unsigned 32-bit little-endian"); +PCM_CODEC (S64BE, S64, s64be, "PCM signed 64-bit big-endian"); +PCM_CODEC (S64LE, S64, s64le, "PCM signed 64-bit little-endian"); +PCM_CODEC_EXT(VIDC, S16, vidc, "PCM Archimedes VIDC", PCMLUTDecode, pcm_lut_decode_init); +PCM_DECODER (SGA, U8, sga, "PCM SGA"); diff --git a/libavcodec/pcm_tablegen.c b/libavcodec/pcm_tablegen.c index 473a47f6d..cff713606 100644 --- a/libavcodec/pcm_tablegen.c +++ b/libavcodec/pcm_tablegen.c @@ -21,21 +21,27 @@ */ #include +#include "config_components.h" #define CONFIG_HARDCODED_TABLES 0 #include "pcm_tablegen.h" #include "tableprint.h" int main(void) { - pcm_alaw_tableinit(); - pcm_ulaw_tableinit(); - pcm_vidc_tableinit(); - write_fileheader(); +#if CONFIG_PCM_ALAW_ENCODER + pcm_alaw_tableinit(); WRITE_ARRAY("static const", uint8_t, linear_to_alaw); +#endif +#if CONFIG_PCM_MULAW_ENCODER + pcm_ulaw_tableinit(); WRITE_ARRAY("static const", uint8_t, linear_to_ulaw); +#endif +#if CONFIG_PCM_VIDC_ENCODER + pcm_vidc_tableinit(); WRITE_ARRAY("static const", uint8_t, linear_to_vidc); +#endif return 0; } diff --git a/libavcodec/pcm_tablegen.h b/libavcodec/pcm_tablegen.h index 7274c3cd1..2fd2e0e4f 100644 --- a/libavcodec/pcm_tablegen.h +++ b/libavcodec/pcm_tablegen.h @@ -24,6 +24,7 @@ #define AVCODEC_PCM_TABLEGEN_H #include +#include "config_components.h" #include "libavutil/attributes.h" /* from g711.c by SUN microsystems (unrestricted use) */ @@ -42,6 +43,7 @@ #define VIDC_SEG_SHIFT (5) #define VIDC_SEG_MASK (0xE0) +#if CONFIG_PCM_ALAW_DECODER || CONFIG_PCM_ALAW_ENCODER /* alaw2linear() - Convert an A-law value to 16-bit linear PCM */ static av_cold int alaw2linear(unsigned char a_val) { @@ -57,7 +59,9 @@ static av_cold int alaw2linear(unsigned char a_val) return (a_val & SIGN_BIT) ? t : -t; } +#endif +#if CONFIG_PCM_MULAW_DECODER || CONFIG_PCM_MULAW_ENCODER static av_cold int ulaw2linear(unsigned char u_val) { int t; @@ -74,7 +78,9 @@ static av_cold int ulaw2linear(unsigned char u_val) return (u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS); } +#endif +#if CONFIG_PCM_VIDC_DECODER || CONFIG_PCM_VIDC_ENCODER static av_cold int vidc2linear(unsigned char u_val) { int t; @@ -88,6 +94,7 @@ static av_cold int vidc2linear(unsigned char u_val) return (u_val & VIDC_SIGN_BIT) ? (BIAS - t) : (t - BIAS); } +#endif #if CONFIG_HARDCODED_TABLES #define pcm_alaw_tableinit() @@ -95,11 +102,9 @@ static av_cold int vidc2linear(unsigned char u_val) #define pcm_vidc_tableinit() #include "libavcodec/pcm_tables.h" #else -/* 16384 entries per table */ -static uint8_t linear_to_alaw[16384]; -static uint8_t linear_to_ulaw[16384]; -static uint8_t linear_to_vidc[16384]; +#if CONFIG_PCM_ALAW_ENCODER || CONFIG_PCM_MULAW_ENCODER || \ + CONFIG_PCM_VIDC_ENCODER static av_cold void build_xlaw_table(uint8_t *linear_to_xlaw, int (*xlaw2linear)(unsigned char), int mask) @@ -123,21 +128,31 @@ static av_cold void build_xlaw_table(uint8_t *linear_to_xlaw, } linear_to_xlaw[0] = linear_to_xlaw[1]; } +#endif +#if CONFIG_PCM_ALAW_ENCODER +static uint8_t linear_to_alaw[16384]; static void pcm_alaw_tableinit(void) { build_xlaw_table(linear_to_alaw, alaw2linear, 0xd5); } +#endif +#if CONFIG_PCM_MULAW_ENCODER +static uint8_t linear_to_ulaw[16384]; static void pcm_ulaw_tableinit(void) { build_xlaw_table(linear_to_ulaw, ulaw2linear, 0xff); } +#endif +#if CONFIG_PCM_VIDC_ENCODER +static uint8_t linear_to_vidc[16384]; static void pcm_vidc_tableinit(void) { build_xlaw_table(linear_to_vidc, vidc2linear, 0xff); } +#endif #endif /* CONFIG_HARDCODED_TABLES */ #endif /* AVCODEC_PCM_TABLEGEN_H */ diff --git a/libavcodec/pcxenc.c b/libavcodec/pcxenc.c index b763c7df4..f450d7bca 100644 --- a/libavcodec/pcxenc.c +++ b/libavcodec/pcxenc.c @@ -199,11 +199,9 @@ const FFCodec ff_pcx_encoder = { .p.id = AV_CODEC_ID_PCX, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pcx_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGB24, - AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, - AV_PIX_FMT_MONOBLACK, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, + AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, + AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, + AV_PIX_FMT_MONOBLACK), }; diff --git a/libavcodec/pdvdec.c b/libavcodec/pdvdec.c index dae9f63cc..4eaa0ff30 100644 --- a/libavcodec/pdvdec.c +++ b/libavcodec/pdvdec.c @@ -25,6 +25,8 @@ #include "decode.h" #include "zlib_wrapper.h" +#include "libavutil/attributes.h" + #include typedef struct PDVContext { @@ -120,7 +122,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, return avpkt->size; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { PDVContext *s = avctx->priv_data; diff --git a/libavcodec/pel_template.c b/libavcodec/pel_template.c index 6da7a56b2..7de3db72f 100644 --- a/libavcodec/pel_template.c +++ b/libavcodec/pel_template.c @@ -66,7 +66,7 @@ static inline void FUNCC(OPNAME ## _pixels8)(uint8_t *block, \ block += line_size; \ } \ } \ - \ +av_unused \ CALL_2X_PIXELS(FUNCC(OPNAME ## _pixels16), \ FUNCC(OPNAME ## _pixels8), \ 8 * sizeof(pixel)) diff --git a/libavcodec/pgssubdec.c b/libavcodec/pgssubdec.c index d93bcf1b6..20583c9af 100644 --- a/libavcodec/pgssubdec.c +++ b/libavcodec/pgssubdec.c @@ -447,7 +447,7 @@ static int parse_presentation_segment(AVCodecContext *avctx, PGSSubObjectRef *const object = &ctx->presentation.objects[i]; if (buf_end - buf < 8) { - av_log(avctx, AV_LOG_ERROR, "Insufficent space for object\n"); + av_log(avctx, AV_LOG_ERROR, "Insufficient space for object\n"); ctx->presentation.object_count = i; return AVERROR_INVALIDDATA; } diff --git a/libavcodec/pictordec.c b/libavcodec/pictordec.c index 845a88245..428bc150a 100644 --- a/libavcodec/pictordec.c +++ b/libavcodec/pictordec.c @@ -172,7 +172,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, 1 byte run (=0) 2 bytes run 1 byte val - thats 5 bytes and the maximum run we can code is 65535 + that's 5 bytes and the maximum run we can code is 65535 The RLE decoder can exit prematurly but it does not on any image available Based on this the formula is assumed correct for undamaged images. @@ -192,11 +192,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, return ret; memset(frame->data[0], 0, s->height * frame->linesize[0]); frame->pict_type = AV_PICTURE_TYPE_I; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif pos_after_pal = bytestream2_tell(&s->g) + esize; palette = (uint32_t*)frame->data[1]; diff --git a/libavcodec/pixblockdsp.c b/libavcodec/pixblockdsp.c index 1fff24451..5ae840f10 100644 --- a/libavcodec/pixblockdsp.c +++ b/libavcodec/pixblockdsp.c @@ -21,7 +21,6 @@ #include "config.h" #include "libavutil/attributes.h" #include "libavutil/intreadwrite.h" -#include "avcodec.h" #include "pixblockdsp.h" static void get_pixels_16_c(int16_t *restrict block, const uint8_t *pixels, @@ -85,40 +84,33 @@ static void diff_pixels_c(int16_t *restrict block, const uint8_t *s1, } } -av_cold void ff_pixblockdsp_init(PixblockDSPContext *c, AVCodecContext *avctx) +av_cold void ff_pixblockdsp_init(PixblockDSPContext *c, int bits_per_raw_sample) { - av_unused const unsigned high_bit_depth = avctx->bits_per_raw_sample > 8; + const unsigned high_bit_depth = bits_per_raw_sample > 8 && + bits_per_raw_sample <= 16; c->diff_pixels_unaligned = c->diff_pixels = diff_pixels_c; - switch (avctx->bits_per_raw_sample) { - case 9: - case 10: - case 12: - case 14: + if (high_bit_depth) { c->get_pixels_unaligned = get_pixels_unaligned_16_c; - c->get_pixels = get_pixels_16_c; - break; - default: - if (avctx->bits_per_raw_sample<=8 || avctx->codec_type != AVMEDIA_TYPE_VIDEO) { - c->get_pixels_unaligned = - c->get_pixels = get_pixels_8_c; - } - break; + c->get_pixels = get_pixels_16_c; + } else { + c->get_pixels_unaligned = + c->get_pixels = get_pixels_8_c; } #if ARCH_AARCH64 - ff_pixblockdsp_init_aarch64(c, avctx, high_bit_depth); + ff_pixblockdsp_init_aarch64(c, high_bit_depth); #elif ARCH_ARM - ff_pixblockdsp_init_arm(c, avctx, high_bit_depth); + ff_pixblockdsp_init_arm(c, high_bit_depth); #elif ARCH_PPC - ff_pixblockdsp_init_ppc(c, avctx, high_bit_depth); + ff_pixblockdsp_init_ppc(c, high_bit_depth); #elif ARCH_RISCV - ff_pixblockdsp_init_riscv(c, avctx, high_bit_depth); -#elif ARCH_X86 - ff_pixblockdsp_init_x86(c, avctx, high_bit_depth); + ff_pixblockdsp_init_riscv(c, high_bit_depth); +#elif ARCH_X86 && HAVE_X86ASM + ff_pixblockdsp_init_x86(c, high_bit_depth); #elif ARCH_MIPS - ff_pixblockdsp_init_mips(c, avctx, high_bit_depth); + ff_pixblockdsp_init_mips(c, high_bit_depth); #endif } diff --git a/libavcodec/pixblockdsp.h b/libavcodec/pixblockdsp.h index cac5f3d4a..d493d0e22 100644 --- a/libavcodec/pixblockdsp.h +++ b/libavcodec/pixblockdsp.h @@ -19,13 +19,17 @@ #ifndef AVCODEC_PIXBLOCKDSP_H #define AVCODEC_PIXBLOCKDSP_H +#include #include -#include "avcodec.h" +#define PIXBLOCKDSP_8BPP_GET_PIXELS_SUPPORTS_UNALIGNED \ + !(ARCH_ARM || ARCH_MIPS || ARCH_PPC || ARCH_RISCV) typedef struct PixblockDSPContext { void (*get_pixels)(int16_t *restrict block /* align 16 */, - const uint8_t *pixels /* align 8 */, + /* align 16 for > 8 bits; align 8 for <= 8 bits + * (or 1 if PIXBLOCKDSP_8BPP_GET_PIXELS_SUPPORTS_UNALIGNED is set) */ + const uint8_t *pixels, ptrdiff_t stride); void (*get_pixels_unaligned)(int16_t *restrict block /* align 16 */, const uint8_t *pixels, @@ -41,20 +45,18 @@ typedef struct PixblockDSPContext { } PixblockDSPContext; -void ff_pixblockdsp_init(PixblockDSPContext *c, AVCodecContext *avctx); -void ff_pixblockdsp_init_aarch64(PixblockDSPContext *c, AVCodecContext *avctx, +void ff_pixblockdsp_init(PixblockDSPContext *c, int bits_per_raw_sample); +void ff_pixblockdsp_init_aarch64(PixblockDSPContext *c, unsigned high_bit_depth); -void ff_pixblockdsp_init_alpha(PixblockDSPContext *c, AVCodecContext *avctx, +void ff_pixblockdsp_init_arm(PixblockDSPContext *c, + unsigned high_bit_depth); +void ff_pixblockdsp_init_ppc(PixblockDSPContext *c, + unsigned high_bit_depth); +void ff_pixblockdsp_init_riscv(PixblockDSPContext *c, unsigned high_bit_depth); -void ff_pixblockdsp_init_arm(PixblockDSPContext *c, AVCodecContext *avctx, +void ff_pixblockdsp_init_x86(PixblockDSPContext *c, unsigned high_bit_depth); -void ff_pixblockdsp_init_ppc(PixblockDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth); -void ff_pixblockdsp_init_riscv(PixblockDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth); -void ff_pixblockdsp_init_x86(PixblockDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth); -void ff_pixblockdsp_init_mips(PixblockDSPContext *c, AVCodecContext *avctx, +void ff_pixblockdsp_init_mips(PixblockDSPContext *c, unsigned high_bit_depth); #endif /* AVCODEC_PIXBLOCKDSP_H */ diff --git a/libavcodec/png.h b/libavcodec/png.h index 01171e682..1e2cf11d1 100644 --- a/libavcodec/png.h +++ b/libavcodec/png.h @@ -57,9 +57,7 @@ int ff_png_get_nb_channels(int color_type); /* compute the row size of an interleaved pass */ int ff_png_pass_row_size(int pass, int bits_per_pixel, int width); -void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp); - void ff_png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type, - uint8_t *src, uint8_t *last, int size, int bpp); + const uint8_t *src, const uint8_t *last, int size, int bpp); #endif /* AVCODEC_PNG_H */ diff --git a/libavcodec/png_parser.c b/libavcodec/png_parser.c index 314de1b43..fbeae1103 100644 --- a/libavcodec/png_parser.c +++ b/libavcodec/png_parser.c @@ -25,6 +25,7 @@ */ #include "parser.h" +#include "parser_internal.h" #include "png.h" typedef struct PNGParseContext { @@ -110,9 +111,9 @@ flush: return next; } -const AVCodecParser ff_png_parser = { - .codec_ids = { AV_CODEC_ID_PNG }, +const FFCodecParser ff_png_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_PNG), .priv_data_size = sizeof(PNGParseContext), - .parser_parse = png_parse, - .parser_close = ff_parse_close, + .parse = png_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index c5b32c166..d63061700 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -39,6 +39,7 @@ #include "bytestream.h" #include "codec_internal.h" #include "decode.h" +#include "exif_internal.h" #include "apng.h" #include "png.h" #include "pngdsp.h" @@ -125,6 +126,8 @@ typedef struct PNGDecContext { int pass_row_size; /* decompress row size of the current pass */ int y; FFZStream zstream; + + AVBufferRef *exif_data; } PNGDecContext; /* Mask to determine which pixels are valid in a pass */ @@ -215,34 +218,6 @@ static void png_put_interlaced_row(uint8_t *dst, int width, } } -void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, - int w, int bpp) -{ - int i; - for (i = 0; i < w; i++) { - int a, b, c, p, pa, pb, pc; - - a = dst[i - bpp]; - b = top[i]; - c = top[i - bpp]; - - p = b - c; - pc = a - c; - - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); - - if (pa <= pb && pa <= pc) - p = a; - else if (pb <= pc) - p = b; - else - p = c; - dst[i] = p + src[i]; - } -} - #define UNROLL1(bpp, op) \ { \ r = dst[0]; \ @@ -282,7 +257,7 @@ void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, /* NOTE: 'dst' can be equal to 'last' */ void ff_png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type, - uint8_t *src, uint8_t *last, int size, int bpp) + const uint8_t *src, const uint8_t *last, int size, int bpp) { int i, p, r, g, b, a; @@ -296,7 +271,7 @@ void ff_png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type, if (bpp == 4) { p = *(int *)dst; for (; i < size; i += bpp) { - unsigned s = *(int *)(src + i); + unsigned s = *(const int *)(src + i); p = ((s & 0x7f7f7f7f) + (p & 0x7f7f7f7f)) ^ ((s ^ p) & 0x80808080); *(int *)(dst + i) = p; } @@ -331,7 +306,7 @@ void ff_png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type, i = w; } } - ff_add_png_paeth_prediction(dst + i, src + i, last + i, size - i, bpp); + ff_png_add_paeth_prediction(dst + i, src + i, last + i, size - i, bpp); break; } } @@ -540,6 +515,98 @@ static char *iso88591_to_utf8(const char *in, size_t size_in) return out; } +static int decode_text_to_exif(PNGDecContext *s, const char *txt_utf8) +{ + size_t len = strlen(txt_utf8); + const char *ptr = txt_utf8; + const char *end = txt_utf8 + len; + size_t exif_len = 0; + uint8_t *exif_ptr; + const uint8_t *exif_end; + + // first we find a newline + while (*ptr++ != '\n') { + if (ptr >= end) + return AVERROR_BUFFER_TOO_SMALL; + } + + // we check for "exif" and skip over it + if (end - ptr < 4 || strncmp("exif", ptr, 4)) + return AVERROR_INVALIDDATA; + ptr += 3; + + // then we find the next printable non-space character + while (!av_isgraph(*++ptr)) { + if (ptr >= end) + return AVERROR_BUFFER_TOO_SMALL; + } + + // parse the length + while (av_isdigit(*ptr)) { + size_t nlen = exif_len * 10 + (*ptr - '0'); + if (nlen < exif_len) // overflow + return AVERROR_INVALIDDATA; + exif_len = nlen; + if (++ptr >= end) + return AVERROR_BUFFER_TOO_SMALL; + } + + // then we find the next printable non-space character + while (!av_isgraph(*ptr)) { + if (++ptr >= end) + return AVERROR_BUFFER_TOO_SMALL; + } + + // first condition checks for overflow in 2 * exif_len + if (exif_len > SIZE_MAX / 2 || end - ptr < 2 * exif_len) + return AVERROR_INVALIDDATA; + if (exif_len < 10) + return AVERROR_INVALIDDATA; + + av_buffer_unref(&s->exif_data); + // the buffer starts with "Exif " which we skip over + // we don't use AV_EXIF_EXIF00 because that disagrees + // with the eXIf chunk format + s->exif_data = av_buffer_alloc(exif_len - 6); + if (!s->exif_data) + return AVERROR(ENOMEM); + + // we subtract one because we call ++ptr later + // compiler will optimize out the call + ptr += strlen("Exif ") * 2 - 1; + + exif_ptr = s->exif_data->data; + exif_end = exif_ptr + s->exif_data->size; + + while (exif_ptr < exif_end) { + while (++ptr < end) { + if (*ptr >= '0' && *ptr <= '9') { + *exif_ptr = (*ptr - '0') << 4; + break; + } + if (*ptr >= 'a' && *ptr <= 'f') { + *exif_ptr = (*ptr - 'a' + 10) << 4; + break; + } + } + while (++ptr < end) { + if (*ptr >= '0' && *ptr <= '9') { + *exif_ptr += *ptr - '0'; + break; + } + if (*ptr >= 'a' && *ptr <= 'f') { + *exif_ptr += *ptr - 'a' + 10; + break; + } + } + if (ptr > end) + return AVERROR_INVALIDDATA; + exif_ptr++; + } + + return 0; +} + static int decode_text_chunk(PNGDecContext *s, GetByteContext *gb, int compressed) { int ret, method; @@ -582,6 +649,17 @@ static int decode_text_chunk(PNGDecContext *s, GetByteContext *gb, int compresse return AVERROR(ENOMEM); } + if (!strcmp(kw_utf8, "Raw profile type exif")) { + ret = decode_text_to_exif(s, txt_utf8); + if (ret < 0) {; + av_buffer_unref(&s->exif_data); + } else { + av_freep(&kw_utf8); + av_freep(&txt_utf8); + return ret; + } + } + av_dict_set(&s->frame_metadata, kw_utf8, txt_utf8, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); return 0; @@ -654,6 +732,23 @@ static int decode_phys_chunk(AVCodecContext *avctx, PNGDecContext *s, return 0; } +static int decode_exif_chunk(AVCodecContext *avctx, PNGDecContext *s, + GetByteContext *gb) +{ + if (!(s->hdr_state & PNG_IHDR)) { + av_log(avctx, AV_LOG_ERROR, "eXIf before IHDR\n"); + return AVERROR_INVALIDDATA; + } + + av_buffer_unref(&s->exif_data); + s->exif_data = av_buffer_alloc(bytestream2_get_bytes_left(gb)); + if (!s->exif_data) + return AVERROR(ENOMEM); + bytestream2_get_buffer(gb, s->exif_data->data, s->exif_data->size); + + return 0; +} + /* * This populates AVCodecContext fields so it must be called before * ff_thread_finish_setup() to avoid a race condition with respect to the @@ -757,7 +852,7 @@ static int populate_avctx_color_fields(AVCodecContext *avctx, AVFrame *frame) if (clli) { /* * 0.0001 divisor value - * see: https://www.w3.org/TR/png-3/#cLLi-chunk + * see: https://www.w3.org/TR/png-3/#cLLI-chunk */ clli->MaxCLL = s->clli_max / 10000; clli->MaxFALL = s->clli_avg / 10000; @@ -875,6 +970,11 @@ static int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s, s->bpp += byte_depth; } + /* PNG spec mandates independent alpha channel */ + if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + avctx->alpha_mode = AVALPHA_MODE_STRAIGHT; + ff_progress_frame_unref(&s->picture); if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) { /* We only need a buffer for the current picture. */ @@ -1073,6 +1173,7 @@ static int decode_sbit_chunk(AVCodecContext *avctx, PNGDecContext *s, { int bits = 0; int channels; + int remainder = bytestream2_get_bytes_left(gb); if (!(s->hdr_state & PNG_IHDR)) { av_log(avctx, AV_LOG_ERROR, "sBIT before IHDR\n"); @@ -1080,16 +1181,17 @@ static int decode_sbit_chunk(AVCodecContext *avctx, PNGDecContext *s, } if (s->pic_state & PNG_IDAT) { - av_log(avctx, AV_LOG_ERROR, "sBIT after IDAT\n"); - return AVERROR_INVALIDDATA; + av_log(avctx, AV_LOG_WARNING, "Ignoring illegal sBIT chunk after IDAT\n"); + return 0; } channels = s->color_type & PNG_COLOR_MASK_PALETTE ? 3 : ff_png_get_nb_channels(s->color_type); - if (bytestream2_get_bytes_left(gb) != channels) { - av_log(avctx, AV_LOG_ERROR, "Invalid sBIT size: %d, expected: %d\n", - bytestream2_get_bytes_left(gb), channels); - return AVERROR_INVALIDDATA; + if (remainder != channels) { + av_log(avctx, AV_LOG_WARNING, "Invalid sBIT size: %d, expected: %d\n", remainder, channels); + /* not enough space left in chunk to read info */ + if (remainder < channels) + return 0; } for (int i = 0; i < channels; i++) { @@ -1098,8 +1200,8 @@ static int decode_sbit_chunk(AVCodecContext *avctx, PNGDecContext *s, } if (bits <= 0 || bits > (s->color_type & PNG_COLOR_MASK_PALETTE ? 8 : s->bit_depth)) { - av_log(avctx, AV_LOG_ERROR, "Invalid significant bits: %d\n", bits); - return AVERROR_INVALIDDATA; + av_log(avctx, AV_LOG_WARNING, "Invalid significant bits: %d\n", bits); + return 0; } s->significant_bits = bits; @@ -1566,18 +1668,20 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s, break; } - case MKTAG('c', 'L', 'L', 'i'): + case MKTAG('c', 'L', 'L', 'i'): /* legacy spelling, for backwards compat */ + case MKTAG('c', 'L', 'L', 'I'): if (bytestream2_get_bytes_left(&gb_chunk) != 8) { - av_log(avctx, AV_LOG_WARNING, "Invalid cLLi chunk size: %d\n", bytestream2_get_bytes_left(&gb_chunk)); + av_log(avctx, AV_LOG_WARNING, "Invalid cLLI chunk size: %d\n", bytestream2_get_bytes_left(&gb_chunk)); break; } s->have_clli = 1; s->clli_max = bytestream2_get_be32u(&gb_chunk); s->clli_avg = bytestream2_get_be32u(&gb_chunk); break; - case MKTAG('m', 'D', 'C', 'v'): + case MKTAG('m', 'D', 'C', 'v'): /* legacy spelling, for backward compat */ + case MKTAG('m', 'D', 'C', 'V'): if (bytestream2_get_bytes_left(&gb_chunk) != 24) { - av_log(avctx, AV_LOG_WARNING, "Invalid mDCv chunk size: %d\n", bytestream2_get_bytes_left(&gb_chunk)); + av_log(avctx, AV_LOG_WARNING, "Invalid mDCV chunk size: %d\n", bytestream2_get_bytes_left(&gb_chunk)); break; } s->have_mdcv = 1; @@ -1590,6 +1694,11 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s, s->mdcv_max_lum = bytestream2_get_be32u(&gb_chunk); s->mdcv_min_lum = bytestream2_get_be32u(&gb_chunk); break; + case MKTAG('e', 'X', 'I', 'f'): + ret = decode_exif_chunk(avctx, s, &gb_chunk); + if (ret < 0) + goto fail; + break; case MKTAG('I', 'E', 'N', 'D'): if (!(s->pic_state & PNG_ALLIMAGE)) av_log(avctx, AV_LOG_ERROR, "IEND without all image\n"); @@ -1618,6 +1727,17 @@ exit_loop: if (s->bits_per_pixel <= 4) handle_small_bpp(s, p); + if (s->exif_data) { + // we swap because ff_decode_exif_attach_buffer adds to p->metadata + FFSWAP(AVDictionary *, p->metadata, s->frame_metadata); + ret = ff_decode_exif_attach_buffer(avctx, p, &s->exif_data, AV_EXIF_TIFF_HEADER); + FFSWAP(AVDictionary *, p->metadata, s->frame_metadata); + if (ret < 0) { + av_log(avctx, AV_LOG_WARNING, "unable to attach EXIF buffer\n"); + return ret; + } + } + if (s->color_type == PNG_COLOR_TYPE_PALETTE && avctx->codec_id == AV_CODEC_ID_APNG) { for (int y = 0; y < s->height; y++) { uint8_t *row = &p->data[0][p->linesize[0] * y]; @@ -1910,6 +2030,7 @@ static av_cold int png_dec_end(AVCodecContext *avctx) s->tmp_row_size = 0; av_freep(&s->iccp_data); + av_buffer_unref(&s->exif_data); av_dict_free(&s->frame_metadata); ff_inflate_end(&s->zstream); diff --git a/libavcodec/pngdsp.c b/libavcodec/pngdsp.c index 50ee96a68..a932701b0 100644 --- a/libavcodec/pngdsp.c +++ b/libavcodec/pngdsp.c @@ -19,11 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "config.h" #include "libavutil/attributes.h" #include "libavutil/intreadwrite.h" #include "libavutil/macros.h" -#include "png.h" #include "pngdsp.h" #if HAVE_FAST_64BIT @@ -41,7 +42,8 @@ typedef uint32_t uint_native; #define pb_7f (~(uint_native)0 / 255 * 0x7f) #define pb_80 (~(uint_native)0 / 255 * 0x80) -static void add_bytes_l2_c(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w) +static void add_bytes_l2_c(uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, int w) { long i; for (i = 0; i <= w - (int) sizeof(uint_native); i += sizeof(uint_native)) { @@ -53,12 +55,41 @@ static void add_bytes_l2_c(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w) dst[i] = src1[i] + src2[i]; } +void ff_png_add_paeth_prediction(uint8_t *dst, const uint8_t *src, + const uint8_t *top, int w, int bpp) +{ + for (int i = 0; i < w; ++i) { + int a, b, c, p, pa, pb, pc; + + a = dst[i - bpp]; + b = top[i]; + c = top[i - bpp]; + + p = b - c; + pc = a - c; + + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); + + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + dst[i] = p + src[i]; + } +} + av_cold void ff_pngdsp_init(PNGDSPContext *dsp) { dsp->add_bytes_l2 = add_bytes_l2_c; - dsp->add_paeth_prediction = ff_add_png_paeth_prediction; + dsp->add_paeth_prediction = ff_png_add_paeth_prediction; -#if ARCH_X86 +#if ARCH_AARCH64 + ff_pngdsp_init_aarch64(dsp); +#elif ARCH_X86 && HAVE_X86ASM ff_pngdsp_init_x86(dsp); #endif } diff --git a/libavcodec/pngdsp.h b/libavcodec/pngdsp.h index 5475d0d94..99f578f53 100644 --- a/libavcodec/pngdsp.h +++ b/libavcodec/pngdsp.h @@ -24,17 +24,25 @@ #include +#include "libavutil/attributes_internal.h" + typedef struct PNGDSPContext { void (*add_bytes_l2)(uint8_t *dst, - uint8_t *src1 /* align 16 */, - uint8_t *src2, int w); + const uint8_t *src1 /* align 16 */, + const uint8_t *src2, int w); /* this might write to dst[w] */ - void (*add_paeth_prediction)(uint8_t *dst, uint8_t *src, - uint8_t *top, int w, int bpp); + void (*add_paeth_prediction)(uint8_t *dst, const uint8_t *src, + const uint8_t *top, int w, int bpp); } PNGDSPContext; +FF_VISIBILITY_PUSH_HIDDEN +void ff_png_add_paeth_prediction(uint8_t *dst, const uint8_t *src, + const uint8_t *top, int w, int bpp); + void ff_pngdsp_init(PNGDSPContext *dsp); +void ff_pngdsp_init_aarch64(PNGDSPContext *dsp); void ff_pngdsp_init_x86(PNGDSPContext *dsp); +FF_VISIBILITY_POP_HIDDEN #endif /* AVCODEC_PNGDSP_H */ diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c index cb79c04e1..82a9d5b83 100644 --- a/libavcodec/pngenc.c +++ b/libavcodec/pngenc.c @@ -22,6 +22,7 @@ #include "avcodec.h" #include "codec_internal.h" #include "encode.h" +#include "exif_internal.h" #include "bytestream.h" #include "lossless_videoencdsp.h" #include "png.h" @@ -29,15 +30,16 @@ #include "zlib_wrapper.h" #include "libavutil/avassert.h" +#include "libavutil/buffer.h" #include "libavutil/crc.h" #include "libavutil/csp.h" #include "libavutil/libm.h" #include "libavutil/mastering_display_metadata.h" #include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "libavutil/rational.h" #include "libavutil/stereo3d.h" - #include #define IOBUF_SIZE 4096 @@ -193,6 +195,8 @@ static void png_filter_row(PNGEncContext *c, uint8_t *dst, int filter_type, dst[i] = src[i] - top[i]; sub_png_paeth_prediction(dst + i, src + i, top + i, size - i, bpp); break; + default: + av_unreachable("PNG_FILTER_VALUE_MIXED can't happen here and all others are covered"); } } @@ -319,7 +323,7 @@ static int png_get_chrm(enum AVColorPrimaries prim, uint8_t *buf) static int png_get_gama(enum AVColorTransferCharacteristic trc, uint8_t *buf) { - double gamma = av_csp_approximate_trc_gamma(trc); + double gamma = av_csp_approximate_eotf_gamma(trc); if (gamma <= 1e-6) return 0; @@ -373,6 +377,7 @@ static int encode_headers(AVCodecContext *avctx, const AVFrame *pict) { AVFrameSideData *side_data; PNGEncContext *s = avctx->priv_data; + AVBufferRef *exif_data = NULL; int ret; /* write png header */ @@ -414,6 +419,19 @@ static int encode_headers(AVCodecContext *avctx, const AVFrame *pict) } } + ret = ff_exif_get_buffer(avctx, pict, &exif_data, AV_EXIF_TIFF_HEADER); + if (exif_data) { + // png_write_chunk accepts an int, not a size_t, so we have to check overflow + if (exif_data->size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) + // that's a very big exif chunk, probably a bug + av_log(avctx, AV_LOG_ERROR, "extremely large EXIF buffer detected, not writing\n"); + else + png_write_chunk(&s->bytestream, MKTAG('e','X','I','f'), exif_data->data, exif_data->size); + av_buffer_unref(&exif_data); + } else if (ret < 0) { + av_log(avctx, AV_LOG_WARNING, "unable to attach EXIF metadata: %s\n", av_err2str(ret)); + } + side_data = av_frame_get_side_data(pict, AV_FRAME_DATA_ICC_PROFILE); if ((ret = png_write_iccp(s, side_data))) return ret; @@ -445,7 +463,7 @@ static int encode_headers(AVCodecContext *avctx, const AVFrame *pict) AVContentLightMetadata *clli = (AVContentLightMetadata *) side_data->data; AV_WB32(s->buf, clli->MaxCLL * 10000); AV_WB32(s->buf + 4, clli->MaxFALL * 10000); - png_write_chunk(&s->bytestream, MKTAG('c', 'L', 'L', 'i'), s->buf, 8); + png_write_chunk(&s->bytestream, MKTAG('c', 'L', 'L', 'I'), s->buf, 8); } side_data = av_frame_get_side_data(pict, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); @@ -460,7 +478,7 @@ static int encode_headers(AVCodecContext *avctx, const AVFrame *pict) AV_WB16(s->buf + 14, PNG_Q2D(mdcv->white_point[1], 50000)); AV_WB32(s->buf + 16, PNG_Q2D(mdcv->max_luminance, 10000)); AV_WB32(s->buf + 20, PNG_Q2D(mdcv->min_luminance, 10000)); - png_write_chunk(&s->bytestream, MKTAG('m', 'D', 'C', 'v'), s->buf, 24); + png_write_chunk(&s->bytestream, MKTAG('m', 'D', 'C', 'V'), s->buf, 24); } } @@ -628,6 +646,34 @@ static int add_icc_profile_size(AVCodecContext *avctx, const AVFrame *pict, return 0; } +static int add_exif_profile_size(AVCodecContext *avctx, const AVFrame *pict, + uint64_t *max_packet_size) +{ + const AVFrameSideData *sd; + uint64_t new_pkt_size; + /* includes orientation tag */ + const int base_exif_size = 92; + uint64_t estimated_exif_size; + + sd = av_frame_get_side_data(pict, AV_FRAME_DATA_EXIF); + estimated_exif_size = sd ? sd->size : 0; + sd = av_frame_get_side_data(pict, AV_FRAME_DATA_DISPLAYMATRIX); + if (sd) + estimated_exif_size += base_exif_size; + + if (!estimated_exif_size) + return 0; + + /* 12 is the png chunk header size */ + new_pkt_size = *max_packet_size + estimated_exif_size + 12; + if (new_pkt_size < *max_packet_size) + return AVERROR_INVALIDDATA; + + *max_packet_size = new_pkt_size; + + return 0; +} + static int encode_png(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet) { @@ -646,6 +692,10 @@ static int encode_png(AVCodecContext *avctx, AVPacket *pkt, ); if ((ret = add_icc_profile_size(avctx, pict, &max_packet_size))) return ret; + ret = add_exif_profile_size(avctx, pict, &max_packet_size); + if (ret < 0) + return ret; + ret = ff_alloc_packet(avctx, pkt, max_packet_size); if (ret < 0) return ret; @@ -800,6 +850,9 @@ static int apng_do_inverse_blend(AVFrame *output, const AVFrame *input, palette[*background] >> 24 == 0) break; return -1; + + default: + av_unreachable("Pixfmt has been checked before"); } memmove(output_data, foreground, bpp); @@ -832,6 +885,7 @@ static int apng_encode_frame(AVCodecContext *avctx, const AVFrame *pict, size_t best_bytestream_size = SIZE_MAX; APNGFctlChunk last_fctl_chunk = *best_last_fctl_chunk; APNGFctlChunk fctl_chunk = *best_fctl_chunk; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pict->format); if (avctx->frame_num == 0) { best_fctl_chunk->width = pict->width; @@ -866,7 +920,10 @@ static int apng_encode_frame(AVCodecContext *avctx, const AVFrame *pict, // 0: APNG_DISPOSE_OP_NONE // 1: APNG_DISPOSE_OP_BACKGROUND // 2: APNG_DISPOSE_OP_PREVIOUS - + if (last_fctl_chunk.dispose_op == APNG_DISPOSE_OP_BACKGROUND) { + if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)) + continue; + } for (fctl_chunk.blend_op = 0; fctl_chunk.blend_op < 2; ++fctl_chunk.blend_op) { // 0: APNG_BLEND_OP_SOURCE // 1: APNG_BLEND_OP_OVER @@ -975,16 +1032,23 @@ static int encode_apng(AVCodecContext *avctx, AVPacket *pkt, enc_row_size + (4 + 12) * (((int64_t)enc_row_size + IOBUF_SIZE - 1) / IOBUF_SIZE) // fdAT * ceil(enc_row_size / IOBUF_SIZE) ); - if ((ret = add_icc_profile_size(avctx, pict, &max_packet_size))) - return ret; if (max_packet_size > INT_MAX) return AVERROR(ENOMEM); if (avctx->frame_num == 0) { if (!pict) return AVERROR(EINVAL); - - s->bytestream = s->extra_data = av_malloc(FF_INPUT_BUFFER_MIN_SIZE); + uint64_t extradata_size = FF_INPUT_BUFFER_MIN_SIZE; + ret = add_icc_profile_size(avctx, pict, &extradata_size); + if (ret < 0) + return ret; + ret = add_exif_profile_size(avctx, pict, &extradata_size); + if (ret < 0) + return ret; + /* the compiler will optimize this out if UINT64_MAX == SIZE_MAX */ + if (extradata_size > SIZE_MAX) + return AVERROR(ENOMEM); + s->bytestream = s->extra_data = av_malloc(extradata_size); if (!s->extra_data) return AVERROR(ENOMEM); @@ -1177,7 +1241,7 @@ static av_cold int png_enc_init(AVCodecContext *avctx) s->color_type = PNG_COLOR_TYPE_PALETTE; break; default: - return -1; + av_unreachable("Already checked via CODEC_PIXFMTS"); } s->bits_per_pixel = ff_png_get_nb_channels(s->color_type) * s->bit_depth; @@ -1205,7 +1269,7 @@ static av_cold int png_enc_close(AVCodecContext *avctx) static const AVOption options[] = { {"dpi", "Set image resolution (in dots per inch)", OFFSET(dpi), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 0x10000, VE}, {"dpm", "Set image resolution (in dots per meter)", OFFSET(dpm), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 0x10000, VE}, - { "pred", "Prediction method", OFFSET(filter_type), AV_OPT_TYPE_INT, { .i64 = PNG_FILTER_VALUE_NONE }, PNG_FILTER_VALUE_NONE, PNG_FILTER_VALUE_MIXED, VE, .unit = "pred" }, + { "pred", "Prediction method", OFFSET(filter_type), AV_OPT_TYPE_INT, { .i64 = PNG_FILTER_VALUE_PAETH }, PNG_FILTER_VALUE_NONE, PNG_FILTER_VALUE_MIXED, VE, .unit = "pred" }, { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_NONE }, INT_MIN, INT_MAX, VE, .unit = "pred" }, { "sub", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_SUB }, INT_MIN, INT_MAX, VE, .unit = "pred" }, { "up", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_UP }, INT_MIN, INT_MAX, VE, .unit = "pred" }, @@ -1233,14 +1297,13 @@ const FFCodec ff_png_encoder = { .init = png_enc_init, .close = png_enc_close, FF_CODEC_ENCODE_CB(encode_png), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, - AV_PIX_FMT_PAL8, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, - AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE, - AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, + AV_PIX_FMT_PAL8, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, + AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE, + AV_PIX_FMT_MONOBLACK), + .alpha_modes = AVALPHA_MODE_STRAIGHT, .p.priv_class = &pngenc_class, .caps_internal = FF_CODEC_CAP_ICC_PROFILES, }; @@ -1256,14 +1319,12 @@ const FFCodec ff_apng_encoder = { .init = png_enc_init, .close = png_enc_close, FF_CODEC_ENCODE_CB(encode_apng), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, - AV_PIX_FMT_PAL8, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, - AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, + AV_PIX_FMT_PAL8, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, + AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE), + .alpha_modes = AVALPHA_MODE_STRAIGHT, .p.priv_class = &pngenc_class, .caps_internal = FF_CODEC_CAP_ICC_PROFILES, }; diff --git a/libavcodec/pnm_parser.c b/libavcodec/pnm_parser.c index 74f918a94..27030f851 100644 --- a/libavcodec/pnm_parser.c +++ b/libavcodec/pnm_parser.c @@ -23,6 +23,7 @@ #include "libavutil/imgutils.h" #include "parser.h" //for ParseContext +#include "parser_internal.h" #include "pnm.h" typedef struct PNMParseContext { @@ -133,11 +134,11 @@ end: return next; } -const AVCodecParser ff_pnm_parser = { - .codec_ids = { AV_CODEC_ID_PGM, AV_CODEC_ID_PGMYUV, AV_CODEC_ID_PPM, - AV_CODEC_ID_PBM, AV_CODEC_ID_PAM, AV_CODEC_ID_PFM, - AV_CODEC_ID_PHM }, +const FFCodecParser ff_pnm_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_PGM, AV_CODEC_ID_PGMYUV, AV_CODEC_ID_PPM, + AV_CODEC_ID_PBM, AV_CODEC_ID_PAM, AV_CODEC_ID_PFM, + AV_CODEC_ID_PHM), .priv_data_size = sizeof(PNMParseContext), - .parser_parse = pnm_parse, - .parser_close = ff_parse_close, + .parse = pnm_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/pnmdec.c b/libavcodec/pnmdec.c index 61fb994b9..b99b26a39 100644 --- a/libavcodec/pnmdec.c +++ b/libavcodec/pnmdec.c @@ -22,6 +22,7 @@ #include "config_components.h" #include "libavutil/half2float.h" +#include "libavutil/intfloat.h" #include "avcodec.h" #include "codec_internal.h" diff --git a/libavcodec/pnmenc.c b/libavcodec/pnmenc.c index 9e1b11382..8f67fe0a3 100644 --- a/libavcodec/pnmenc.c +++ b/libavcodec/pnmenc.c @@ -25,6 +25,7 @@ #include "libavutil/imgutils.h" #include "libavutil/pixdesc.h" #include "libavutil/float2half.h" +#include "libavutil/intfloat.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" @@ -231,9 +232,7 @@ const FFCodec ff_pgm_encoder = { .p.id = AV_CODEC_ID_PGM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16BE), }; #endif @@ -245,9 +244,7 @@ const FFCodec ff_pgmyuv_encoder = { .p.id = AV_CODEC_ID_PGMYUV, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P16BE), }; #endif @@ -259,9 +256,7 @@ const FFCodec ff_ppm_encoder = { .p.id = AV_CODEC_ID_PPM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48BE, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48BE), }; #endif @@ -273,8 +268,7 @@ const FFCodec ff_pbm_encoder = { .p.id = AV_CODEC_ID_PBM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_MONOWHITE, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_MONOWHITE), }; #endif @@ -286,11 +280,8 @@ const FFCodec ff_pfm_encoder = { .p.id = AV_CODEC_ID_PFM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_GBRPF32LE, - AV_PIX_FMT_GRAYF32LE, - AV_PIX_FMT_GBRPF32BE, - AV_PIX_FMT_GRAYF32BE, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_GBRPF32LE, AV_PIX_FMT_GRAYF32LE, + AV_PIX_FMT_GBRPF32BE, AV_PIX_FMT_GRAYF32BE), }; #endif @@ -313,8 +304,6 @@ const FFCodec ff_phm_encoder = { .priv_data_size = sizeof(PHMEncContext), .init = phm_enc_init, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_GBRPF32, - AV_PIX_FMT_GRAYF32, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GRAYF32), }; #endif diff --git a/libavcodec/ppc/Makefile b/libavcodec/ppc/Makefile index 10b9ca60d..bddba2772 100644 --- a/libavcodec/ppc/Makefile +++ b/libavcodec/ppc/Makefile @@ -12,7 +12,7 @@ OBJS-$(CONFIG_LLVIDDSP) += ppc/lossless_videodsp_altivec.o OBJS-$(CONFIG_ME_CMP) += ppc/me_cmp.o OBJS-$(CONFIG_MPEGAUDIODSP) += ppc/mpegaudiodsp_altivec.o OBJS-$(CONFIG_MPEGVIDEO) += ppc/mpegvideo_altivec.o -OBJS-$(CONFIG_MPEGVIDEOENC) += ppc/mpegvideoencdsp.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += ppc/mpegvideoencdsp.o OBJS-$(CONFIG_PIXBLOCKDSP) += ppc/pixblockdsp.o OBJS-$(CONFIG_VC1DSP) += ppc/vc1dsp_altivec.o OBJS-$(CONFIG_VIDEODSP) += ppc/videodsp.o @@ -21,7 +21,6 @@ OBJS-$(CONFIG_VP8DSP) += ppc/vp8dsp_altivec.o # decoders/encoders OBJS-$(CONFIG_HEVC_DECODER) += ppc/hevcdsp.o -OBJS-$(CONFIG_LLAUDDSP) += ppc/lossless_audiodsp_altivec.o OBJS-$(CONFIG_MPEG4_DECODER) += ppc/mpeg4videodsp.o OBJS-$(CONFIG_SVQ1_ENCODER) += ppc/svq1enc_altivec.o OBJS-$(CONFIG_VORBIS_DECODER) += ppc/vorbisdsp_altivec.o diff --git a/libavcodec/ppc/h264dsp.c b/libavcodec/ppc/h264dsp.c index 0650768d7..22d3db64a 100644 --- a/libavcodec/ppc/h264dsp.c +++ b/libavcodec/ppc/h264dsp.c @@ -793,22 +793,22 @@ av_cold void ff_h264dsp_init_ppc(H264DSPContext *c, const int bit_depth, return; if (bit_depth == 8) { - c->h264_idct_add = h264_idct_add_altivec; + c->idct_add = h264_idct_add_altivec; if (chroma_format_idc <= 1) - c->h264_idct_add8 = h264_idct_add8_altivec; - c->h264_idct_add16 = h264_idct_add16_altivec; - c->h264_idct_add16intra = h264_idct_add16intra_altivec; - c->h264_idct_dc_add= h264_idct_dc_add_altivec; - c->h264_idct8_dc_add = h264_idct8_dc_add_altivec; - c->h264_idct8_add = h264_idct8_add_altivec; - c->h264_idct8_add4 = h264_idct8_add4_altivec; - c->h264_v_loop_filter_luma= h264_v_loop_filter_luma_altivec; - c->h264_h_loop_filter_luma= h264_h_loop_filter_luma_altivec; + c->idct_add8 = h264_idct_add8_altivec; + c->idct_add16 = h264_idct_add16_altivec; + c->idct_add16intra = h264_idct_add16intra_altivec; + c->idct_dc_add = h264_idct_dc_add_altivec; + c->idct8_dc_add = h264_idct8_dc_add_altivec; + c->idct8_add = h264_idct8_add_altivec; + c->idct8_add4 = h264_idct8_add4_altivec; + c->v_loop_filter_luma = h264_v_loop_filter_luma_altivec; + c->h_loop_filter_luma = h264_h_loop_filter_luma_altivec; - c->weight_h264_pixels_tab[0] = weight_h264_pixels16_altivec; - c->weight_h264_pixels_tab[1] = weight_h264_pixels8_altivec; - c->biweight_h264_pixels_tab[0] = biweight_h264_pixels16_altivec; - c->biweight_h264_pixels_tab[1] = biweight_h264_pixels8_altivec; + c->weight_pixels_tab[0] = weight_h264_pixels16_altivec; + c->weight_pixels_tab[1] = weight_h264_pixels8_altivec; + c->biweight_pixels_tab[0] = biweight_h264_pixels16_altivec; + c->biweight_pixels_tab[1] = biweight_h264_pixels8_altivec; } #endif /* HAVE_ALTIVEC */ } diff --git a/libavcodec/ppc/hpeldsp_altivec.c b/libavcodec/ppc/hpeldsp_altivec.c index 4bf6b28ed..d8cf7518d 100644 --- a/libavcodec/ppc/hpeldsp_altivec.c +++ b/libavcodec/ppc/hpeldsp_altivec.c @@ -46,7 +46,7 @@ void ff_put_pixels16_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t li register ptrdiff_t line_size_4 = line_size * (1 << 2); // hand-unrolling the loop by 4 gains about 15% -// mininum execution time goes from 74 to 60 cycles +// minimum execution time goes from 74 to 60 cycles // it's faster than -funroll-loops, but using // -funroll-loops w/ this is bad - 74 cycles again. // all this is on a 7450, tuning for the 7450 diff --git a/libavcodec/ppc/lossless_audiodsp_altivec.c b/libavcodec/ppc/lossless_audiodsp_altivec.c deleted file mode 100644 index 298e6c38a..000000000 --- a/libavcodec/ppc/lossless_audiodsp_altivec.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2007 Luca Barbato - * - * 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 "config.h" - -#include "libavutil/attributes.h" -#include "libavutil/cpu.h" -#include "libavutil/ppc/cpu.h" -#include "libavutil/ppc/util_altivec.h" - -#include "libavcodec/lossless_audiodsp.h" - -#if HAVE_BIGENDIAN -#define GET_T(tt0,tt1,src,a,b){ \ - a = vec_ld(16, src); \ - tt0 = vec_perm(b, a, align); \ - b = vec_ld(32, src); \ - tt1 = vec_perm(a, b, align); \ - } -#else -#define GET_T(tt0,tt1,src,a,b){ \ - tt0 = vec_vsx_ld(0, src); \ - tt1 = vec_vsx_ld(16, src); \ - } -#endif - -#if HAVE_ALTIVEC -static int32_t scalarproduct_and_madd_int16_altivec(int16_t *v1, - const int16_t *v2, - const int16_t *v3, - int order, int mul) -{ - LOAD_ZERO; - vec_s16 *pv1 = (vec_s16 *) v1; - register vec_s16 muls = { mul, mul, mul, mul, mul, mul, mul, mul }; - register vec_s16 t0, t1, i0, i1, i4, i2, i3; - register vec_s32 res = zero_s32v; -#if HAVE_BIGENDIAN - register vec_u8 align = vec_lvsl(0, v2); - i2 = vec_ld(0, v2); - i3 = vec_ld(0, v3); -#endif - int32_t ires; - - order >>= 4; - do { - GET_T(t0,t1,v2,i1,i2); - i0 = pv1[0]; - i1 = pv1[1]; - res = vec_msum(t0, i0, res); - res = vec_msum(t1, i1, res); - GET_T(t0,t1,v3,i4,i3); - pv1[0] = vec_mladd(t0, muls, i0); - pv1[1] = vec_mladd(t1, muls, i1); - pv1 += 2; - v2 += 16; - v3 += 16; - } while (--order); - res = vec_splat(vec_sums(res, zero_s32v), 3); - vec_ste(res, 0, &ires); - - return ires; -} -#endif /* HAVE_ALTIVEC */ - -av_cold void ff_llauddsp_init_ppc(LLAudDSPContext *c) -{ -#if HAVE_ALTIVEC - if (!PPC_ALTIVEC(av_get_cpu_flags())) - return; - - c->scalarproduct_and_madd_int16 = scalarproduct_and_madd_int16_altivec; -#endif /* HAVE_ALTIVEC */ -} diff --git a/libavcodec/ppc/me_cmp.c b/libavcodec/ppc/me_cmp.c index 90f21525d..764e30da2 100644 --- a/libavcodec/ppc/me_cmp.c +++ b/libavcodec/ppc/me_cmp.c @@ -51,7 +51,7 @@ iv = vec_vsx_ld(1, pix);\ } #endif -static int sad16_x2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sad16_x2_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -91,7 +91,7 @@ static int sad16_x2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_ return s; } -static int sad16_y2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sad16_y2_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -141,7 +141,7 @@ static int sad16_y2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_ return s; } -static int sad16_xy2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sad16_xy2_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -230,7 +230,7 @@ static int sad16_xy2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8 return s; } -static int sad16_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sad16_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -265,7 +265,7 @@ static int sad16_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t * return s; } -static int sad8_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sad8_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -309,7 +309,7 @@ static int sad8_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *p /* Sum of Squared Errors for an 8x8 block, AltiVec-enhanced. * It's the sad8_altivec code above w/ squaring added. */ -static int sse8_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sse8_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -354,7 +354,7 @@ static int sse8_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *p /* Sum of Squared Errors for a 16x16 block, AltiVec-enhanced. * It's the sad16_altivec code above w/ squaring added. */ -static int sse16_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sse16_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -392,7 +392,7 @@ static int sse16_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t * return s; } -static int hadamard8_diff8x8_altivec(MpegEncContext *s, const uint8_t *dst, +static int hadamard8_diff8x8_altivec(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) { int __attribute__((aligned(16))) sum; @@ -518,7 +518,7 @@ static int hadamard8_diff8x8_altivec(MpegEncContext *s, const uint8_t *dst, * On the 970, the hand-made RA is still a win (around 690 vs. around 780), * but xlc goes to around 660 on the regular C code... */ -static int hadamard8_diff16x8_altivec(MpegEncContext *s, const uint8_t *dst, +static int hadamard8_diff16x8_altivec(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) { int __attribute__((aligned(16))) sum; @@ -709,7 +709,7 @@ static int hadamard8_diff16x8_altivec(MpegEncContext *s, const uint8_t *dst, return sum; } -static int hadamard8_diff16_altivec(MpegEncContext *s, const uint8_t *dst, +static int hadamard8_diff16_altivec(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) { int score = hadamard8_diff16x8_altivec(s, dst, src, stride, 8); diff --git a/libavcodec/ppc/mpegvideo_altivec.c b/libavcodec/ppc/mpegvideo_altivec.c index bcb59ba84..71894e760 100644 --- a/libavcodec/ppc/mpegvideo_altivec.c +++ b/libavcodec/ppc/mpegvideo_altivec.c @@ -27,105 +27,85 @@ #include "config.h" #include "libavutil/attributes.h" +#include "libavutil/avassert.h" #include "libavutil/cpu.h" #include "libavutil/mem_internal.h" #include "libavutil/ppc/cpu.h" #include "libavutil/ppc/util_altivec.h" #include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideo_unquantize.h" #if HAVE_ALTIVEC /* AltiVec version of dct_unquantize_h263 this code assumes `block' is 16 bytes-aligned */ -static void dct_unquantize_h263_altivec(MpegEncContext *s, - int16_t *block, int n, int qscale) +static av_always_inline +void dct_unquantize_h263_altivec(int16_t *block, int nb_coeffs, int qadd, int qmul) { - int i, level, qmul, qadd; - int nCoeffs; + register const vector signed short vczero = (const vector signed short)vec_splat_s16(0); + DECLARE_ALIGNED(16, short, qmul8) = qmul; + DECLARE_ALIGNED(16, short, qadd8) = qadd; + register vector signed short blockv, qmulv, qaddv, nqaddv, temp1; + register vector bool short blockv_null, blockv_neg; - qadd = (qscale - 1) | 1; - qmul = qscale << 1; + qmulv = vec_splat((vec_s16)vec_lde(0, &qmul8), 0); + qaddv = vec_splat((vec_s16)vec_lde(0, &qadd8), 0); + nqaddv = vec_sub(vczero, qaddv); - if (s->mb_intra) { - if (!s->h263_aic) { - if (n < 4) - block[0] = block[0] * s->y_dc_scale; - else - block[0] = block[0] * s->c_dc_scale; - }else - qadd = 0; - i = 1; - nCoeffs= 63; //does not always use zigzag table - } else { - i = 0; - av_assert2(s->block_last_index[n]>=0); - nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; - } - - { - register const vector signed short vczero = (const vector signed short)vec_splat_s16(0); - DECLARE_ALIGNED(16, short, qmul8) = qmul; - DECLARE_ALIGNED(16, short, qadd8) = qadd; - register vector signed short blockv, qmulv, qaddv, nqaddv, temp1; - register vector bool short blockv_null, blockv_neg; - register short backup_0 = block[0]; - register int j = 0; - - qmulv = vec_splat((vec_s16)vec_lde(0, &qmul8), 0); - qaddv = vec_splat((vec_s16)vec_lde(0, &qadd8), 0); - nqaddv = vec_sub(vczero, qaddv); - - // vectorize all the 16 bytes-aligned blocks - // of 8 elements - for(; (j + 7) <= nCoeffs ; j+=8) { - blockv = vec_ld(j << 1, block); - blockv_neg = vec_cmplt(blockv, vczero); - blockv_null = vec_cmpeq(blockv, vczero); - // choose between +qadd or -qadd as the third operand - temp1 = vec_sel(qaddv, nqaddv, blockv_neg); - // multiply & add (block{i,i+7} * qmul [+-] qadd) - temp1 = vec_mladd(blockv, qmulv, temp1); - // put 0 where block[{i,i+7} used to have 0 - blockv = vec_sel(temp1, blockv, blockv_null); - vec_st(blockv, j << 1, block); - } - - // if nCoeffs isn't a multiple of 8, finish the job - // using good old scalar units. - // (we could do it using a truncated vector, - // but I'm not sure it's worth the hassle) - for(; j <= nCoeffs ; j++) { - level = block[j]; - if (level) { - if (level < 0) { - level = level * qmul - qadd; - } else { - level = level * qmul + qadd; - } - block[j] = level; - } - } - - if (i == 1) { - // cheat. this avoid special-casing the first iteration - block[0] = backup_0; - } + // vectorize all the 16 bytes-aligned blocks + // of 8 elements + for (register int j = 0; j <= nb_coeffs; j += 8) { + blockv = vec_ld(j << 1, block); + blockv_neg = vec_cmplt(blockv, vczero); + blockv_null = vec_cmpeq(blockv, vczero); + // choose between +qadd or -qadd as the third operand + temp1 = vec_sel(qaddv, nqaddv, blockv_neg); + // multiply & add (block{i,i+7} * qmul [+-] qadd) + temp1 = vec_mladd(blockv, qmulv, temp1); + // put 0 where block[{i,i+7} used to have 0 + blockv = vec_sel(temp1, blockv, blockv_null); + vec_st(blockv, j << 1, block); } } +static void dct_unquantize_h263_intra_altivec(const MPVContext *s, + int16_t *block, int n, int qscale) +{ + int qadd = (qscale - 1) | 1; + int qmul = qscale << 1; + int block0 = block[0]; + if (!s->h263_aic) { + block0 *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + } else + qadd = 0; + int nb_coeffs = s->ac_pred ? 63 : s->intra_scantable.raster_end[s->block_last_index[n]]; + + dct_unquantize_h263_altivec(block, nb_coeffs, qadd, qmul); + + // cheat. this avoid special-casing the first iteration + block[0] = block0; +} + +static void dct_unquantize_h263_inter_altivec(const MPVContext *s, + int16_t *block, int n, int qscale) +{ + int qadd = (qscale - 1) | 1; + int qmul = qscale << 1; + av_assert2(s->block_last_index[n]>=0); + int nb_coeffs = s->inter_scantable.raster_end[s->block_last_index[n]]; + + dct_unquantize_h263_altivec(block, nb_coeffs, qadd, qmul); +} #endif /* HAVE_ALTIVEC */ -av_cold void ff_mpv_common_init_ppc(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_ppc(MPVUnquantDSPContext *s, int bitexact) { #if HAVE_ALTIVEC if (!PPC_ALTIVEC(av_get_cpu_flags())) return; - if ((s->avctx->dct_algo == FF_DCT_AUTO) || - (s->avctx->dct_algo == FF_DCT_ALTIVEC)) { - s->dct_unquantize_h263_intra = dct_unquantize_h263_altivec; - s->dct_unquantize_h263_inter = dct_unquantize_h263_altivec; - } + s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_altivec; + s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_altivec; #endif /* HAVE_ALTIVEC */ } diff --git a/libavcodec/ppc/pixblockdsp.c b/libavcodec/ppc/pixblockdsp.c index 01d14b412..75287b1e8 100644 --- a/libavcodec/ppc/pixblockdsp.c +++ b/libavcodec/ppc/pixblockdsp.c @@ -27,7 +27,6 @@ #include "libavutil/ppc/cpu.h" #include "libavutil/ppc/util_altivec.h" -#include "libavcodec/avcodec.h" #include "libavcodec/pixblockdsp.h" #if HAVE_ALTIVEC @@ -263,7 +262,6 @@ static void diff_pixels_vsx(int16_t *restrict block, const uint8_t *s1, #endif /* HAVE_VSX */ av_cold void ff_pixblockdsp_init_ppc(PixblockDSPContext *c, - AVCodecContext *avctx, unsigned high_bit_depth) { #if HAVE_ALTIVEC diff --git a/libavcodec/ppc/vc1dsp_altivec.c b/libavcodec/ppc/vc1dsp_altivec.c index bbadb2aae..dd0473664 100644 --- a/libavcodec/ppc/vc1dsp_altivec.c +++ b/libavcodec/ppc/vc1dsp_altivec.c @@ -235,7 +235,7 @@ static void vc1_inv_trans_8x4_altivec(uint8_t *dest, ptrdiff_t stride, { vector signed short src0, src1, src2, src3, src4, src5, src6, src7; vector signed int s0, s1, s2, s3, s4, s5, s6, s7; - vector signed int s8, s9, sA, sB, sC, sD, sE, sF; + vector signed int s8, s9, sA, sB; vector signed int t0, t1, t2, t3, t4, t5, t6, t7; const vector signed int vec_64 = vec_sl(vec_splat_s32(4), vec_splat_u32(4)); const vector unsigned int vec_7 = vec_splat_u32(7); @@ -253,40 +253,42 @@ static void vc1_inv_trans_8x4_altivec(uint8_t *dest, ptrdiff_t stride, src1 = vec_ld( 16, block); src2 = vec_ld( 32, block); src3 = vec_ld( 48, block); - src4 = vec_ld( 64, block); - src5 = vec_ld( 80, block); - src6 = vec_ld( 96, block); - src7 = vec_ld(112, block); - TRANSPOSE8(src0, src1, src2, src3, src4, src5, src6, src7); - s0 = vec_unpackl(src0); - s1 = vec_unpackl(src1); - s2 = vec_unpackl(src2); - s3 = vec_unpackl(src3); - s4 = vec_unpackl(src4); - s5 = vec_unpackl(src5); - s6 = vec_unpackl(src6); - s7 = vec_unpackl(src7); - s8 = vec_unpackh(src0); - s9 = vec_unpackh(src1); - sA = vec_unpackh(src2); - sB = vec_unpackh(src3); - sC = vec_unpackh(src4); - sD = vec_unpackh(src5); - sE = vec_unpackh(src6); - sF = vec_unpackh(src7); +// Transpose 8x4 matrix of 16-bit elements (in-place) + vec_s16 A1, B1, C1, D1; + vec_s16 A2, B2, C2, D2; + + A1 = vec_mergeh(src0, src2); + B1 = vec_mergel(src0, src2); + C1 = vec_mergeh(src1, src3); + D1 = vec_mergel(src1, src3); + + A2 = vec_mergeh(A1, C1); + B2 = vec_mergel(A1, C1); + C2 = vec_mergeh(B1, D1); + D2 = vec_mergel(B1, D1); + + s0 = vec_unpackh(A2); + s1 = vec_unpackl(A2); + s2 = vec_unpackh(B2); + s3 = vec_unpackl(B2); + s4 = vec_unpackh(C2); + s5 = vec_unpackl(C2); + s6 = vec_unpackh(D2); + s7 = vec_unpackl(D2); + STEP8(s0, s1, s2, s3, s4, s5, s6, s7, vec_4s); SHIFT_HOR8(s0, s1, s2, s3, s4, s5, s6, s7); - STEP8(s8, s9, sA, sB, sC, sD, sE, sF, vec_4s); - SHIFT_HOR8(s8, s9, sA, sB, sC, sD, sE, sF); - src0 = vec_pack(s8, s0); - src1 = vec_pack(s9, s1); - src2 = vec_pack(sA, s2); - src3 = vec_pack(sB, s3); - src4 = vec_pack(sC, s4); - src5 = vec_pack(sD, s5); - src6 = vec_pack(sE, s6); - src7 = vec_pack(sF, s7); + + src0 = vec_pack(s0, s0); + src1 = vec_pack(s1, s1); + src2 = vec_pack(s2, s2); + src3 = vec_pack(s3, s3); + src4 = vec_pack(s4, s4); + src5 = vec_pack(s5, s5); + src6 = vec_pack(s6, s6); + src7 = vec_pack(s7, s7); + TRANSPOSE8(src0, src1, src2, src3, src4, src5, src6, src7); s0 = vec_unpackh(src0); diff --git a/libavcodec/ppc/vp3dsp_altivec.c b/libavcodec/ppc/vp3dsp_altivec.c index a9a48d145..30551a1a2 100644 --- a/libavcodec/ppc/vp3dsp_altivec.c +++ b/libavcodec/ppc/vp3dsp_altivec.c @@ -192,7 +192,7 @@ static void vp3_idct_add_altivec(uint8_t *dst, ptrdiff_t stride, int16_t block[6 #endif /* HAVE_ALTIVEC */ -av_cold void ff_vp3dsp_init_ppc(VP3DSPContext *c, int flags) +av_cold void ff_vp3dsp_init_ppc(VP3DSPContext *c) { #if HAVE_ALTIVEC if (!PPC_ALTIVEC(av_get_cpu_flags())) diff --git a/libavcodec/ppc/vp8dsp_altivec.c b/libavcodec/ppc/vp8dsp_altivec.c index 061914fc3..9d637af00 100644 --- a/libavcodec/ppc/vp8dsp_altivec.c +++ b/libavcodec/ppc/vp8dsp_altivec.c @@ -312,7 +312,7 @@ static void put_vp8_pixels16_altivec(uint8_t *dst, ptrdiff_t dstride, const uint perm = vec_lvsl(0, src); #endif // hand-unrolling the loop by 4 gains about 15% -// mininum execution time goes from 74 to 60 cycles +// minimum execution time goes from 74 to 60 cycles // it's faster than -funroll-loops, but using // -funroll-loops w/ this is bad - 74 cycles again. // all this is on a 7450, tuning for the 7450 diff --git a/libavcodec/profiles.c b/libavcodec/profiles.c index 3cef82be3..1b67870c4 100644 --- a/libavcodec/profiles.c +++ b/libavcodec/profiles.c @@ -182,6 +182,12 @@ const AVProfile ff_prores_profiles[] = { { AV_PROFILE_UNKNOWN } }; +const AVProfile ff_prores_raw_profiles[] = { + { AV_PROFILE_PRORES_RAW, "RAW" }, + { AV_PROFILE_PRORES_RAW_HQ, "RAW HQ" }, + { AV_PROFILE_UNKNOWN } +}; + const AVProfile ff_mjpeg_profiles[] = { { AV_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, "Baseline" }, { AV_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT, "Sequential" }, @@ -203,4 +209,15 @@ const AVProfile ff_evc_profiles[] = { { AV_PROFILE_UNKNOWN }, }; +const AVProfile ff_apv_profiles[] = { + { AV_PROFILE_APV_422_10, "422-10" }, + { AV_PROFILE_APV_422_12, "422-12" }, + { AV_PROFILE_APV_444_10, "444-10" }, + { AV_PROFILE_APV_444_12, "444-12" }, + { AV_PROFILE_APV_4444_10, "4444-10" }, + { AV_PROFILE_APV_4444_12, "4444-12" }, + { AV_PROFILE_APV_400_10, "400-10" }, + { AV_PROFILE_UNKNOWN }, +}; + #endif /* !CONFIG_SMALL */ diff --git a/libavcodec/profiles.h b/libavcodec/profiles.h index 33b7ffc17..6f4011ff0 100644 --- a/libavcodec/profiles.h +++ b/libavcodec/profiles.h @@ -74,8 +74,10 @@ extern const AVProfile ff_vp9_profiles[]; extern const AVProfile ff_av1_profiles[]; extern const AVProfile ff_sbc_profiles[]; extern const AVProfile ff_prores_profiles[]; +extern const AVProfile ff_prores_raw_profiles[]; extern const AVProfile ff_mjpeg_profiles[]; extern const AVProfile ff_arib_caption_profiles[]; extern const AVProfile ff_evc_profiles[]; +extern const AVProfile ff_apv_profiles[]; #endif /* AVCODEC_PROFILES_H */ diff --git a/libavcodec/progressframe.h b/libavcodec/progressframe.h index 32a345bee..e3cb83c5b 100644 --- a/libavcodec/progressframe.h +++ b/libavcodec/progressframe.h @@ -102,10 +102,9 @@ void ff_progress_frame_report(ProgressFrame *f, int progress); void ff_progress_frame_await(const ProgressFrame *f, int progress); /** - * This function allocates ProgressFrame.f - * May be called before ff_progress_frame_get_buffer() in the cases where the - * AVFrame needs to be accessed before the ff_thread_get_buffer() call in - * ff_progress_frame_alloc(). + * This function sets up the ProgressFrame, i.e. ProgressFrame.f + * and ProgressFrame.progress. ProgressFrame.f will be blank + * (as if from av_frame_alloc() or av_frame_unref()) on success. * * @note: This must only be called by codecs with the * FF_CODEC_CAP_USES_PROGRESSFRAMES internal cap. @@ -113,8 +112,7 @@ void ff_progress_frame_await(const ProgressFrame *f, int progress); int ff_progress_frame_alloc(struct AVCodecContext *avctx, ProgressFrame *f); /** - * This function sets up the ProgressFrame, i.e. allocates ProgressFrame.f - * if needed, and also calls ff_thread_get_buffer() on the frame. + * Wrapper around ff_progress_frame_alloc() and ff_thread_get_buffer(). * * @note: This must only be called by codecs with the * FF_CODEC_CAP_USES_PROGRESSFRAMES internal cap. diff --git a/libavcodec/prores_parser.c b/libavcodec/prores_parser.c new file mode 100644 index 000000000..aadf76d79 --- /dev/null +++ b/libavcodec/prores_parser.c @@ -0,0 +1,129 @@ +/* + * 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/intreadwrite.h" +#include "bytestream.h" + +#include "avcodec.h" +#include "parser_internal.h" + +static int parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + GetByteContext gb; + uint8_t flags, depth, chroma_format, alpha_channel_type; + + *poutbuf = buf; + *poutbuf_size = buf_size; + + /* Frame fields + frame header size */ + if (buf_size < 28) + return buf_size; + + bytestream2_init(&gb, buf, buf_size); + + /* Frame size */ + if (bytestream2_get_be32(&gb) != buf_size) + return buf_size; + + /* Frame identifier */ + if (bytestream2_get_le32(&gb) != MKTAG('i','c','p','f')) + return buf_size; + + /* Frame header size */ + if (bytestream2_get_be16(&gb) < 20) + return buf_size; + + bytestream2_skip(&gb, 6); /* Bitstream version, encoder identifier */ + + s->key_frame = 1; + s->pict_type = AV_PICTURE_TYPE_I; + + s->width = bytestream2_get_be16(&gb); + s->height = bytestream2_get_be16(&gb); + s->coded_width = FFALIGN(s->width, 16); + s->coded_height = FFALIGN(s->height, 16); + + flags = bytestream2_get_byte(&gb); + + /* Interlace mode */ + switch (flags >> 2 & 3) { + case 0: + s->field_order = AV_FIELD_PROGRESSIVE; + s->picture_structure = AV_PICTURE_STRUCTURE_FRAME; + break; + case 1: + s->field_order = AV_FIELD_TT; + s->picture_structure = AV_PICTURE_STRUCTURE_TOP_FIELD; + break; + case 2: + s->field_order = AV_FIELD_BB; + s->picture_structure = AV_PICTURE_STRUCTURE_BOTTOM_FIELD; + break; + default: + break; + } + + bytestream2_skip(&gb, 4); /* Aspect ratio information, frame rate code, color primaries, transfer characteristic, matrix coefficients */ + + /* Determine pixel format based on color depth, chroma format and alpha type */ + switch (avctx->codec_tag) { + case MKTAG('a','p','c','o'): + case MKTAG('a','p','c','s'): + case MKTAG('a','p','c','n'): + case MKTAG('a','p','c','h'): + depth = 10; + break; + case MKTAG('a','p','4','h'): + case MKTAG('a','p','4','x'): + depth = 12; + break; + default: + return buf_size; + } + + chroma_format = flags >> 6 & 3; + if (chroma_format < 2) + return buf_size; + + alpha_channel_type = bytestream2_get_byte(&gb) & 0xf; + + switch (depth | (chroma_format << 4) | (alpha_channel_type << 8)) { + case 10 | (2 << 4) | (0 << 8): s->format = AV_PIX_FMT_YUV422P10; break; + case 10 | (2 << 4) | (1 << 8): + case 10 | (2 << 4) | (2 << 8): s->format = AV_PIX_FMT_YUVA422P10; break; + case 10 | (3 << 4) | (0 << 8): s->format = AV_PIX_FMT_YUV444P10; break; + case 10 | (3 << 4) | (1 << 8): + case 10 | (3 << 4) | (2 << 8): s->format = AV_PIX_FMT_YUVA444P10; break; + case 12 | (2 << 4) | (0 << 8): s->format = AV_PIX_FMT_YUV422P12; break; + case 12 | (2 << 4) | (1 << 8): + case 12 | (2 << 4) | (2 << 8): s->format = AV_PIX_FMT_YUVA422P12; break; + case 12 | (3 << 4) | (0 << 8): s->format = AV_PIX_FMT_YUV444P12; break; + case 12 | (3 << 4) | (1 << 8): + case 12 | (3 << 4) | (2 << 8): s->format = AV_PIX_FMT_YUVA444P12; break; + } + + return buf_size; +} + +const FFCodecParser ff_prores_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_PRORES), + .parse = parse, +}; diff --git a/libavcodec/prores_raw.c b/libavcodec/prores_raw.c new file mode 100644 index 000000000..c1c05fd95 --- /dev/null +++ b/libavcodec/prores_raw.c @@ -0,0 +1,555 @@ +/* + * ProRes RAW decoder + * Copyright (c) 2023-2025 Paul B Mahol + * Copyright (c) 2025 Lynne + * + * 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/intreadwrite.h" +#include "libavutil/mem_internal.h" +#include "libavutil/mem.h" + +#define CACHED_BITSTREAM_READER !ARCH_X86_32 + +#include "config_components.h" +#include "avcodec.h" +#include "bytestream.h" +#include "codec_internal.h" +#include "decode.h" +#include "get_bits.h" +#include "idctdsp.h" +#include "proresdata.h" +#include "thread.h" +#include "hwconfig.h" +#include "hwaccel_internal.h" + +#include "prores_raw.h" + +static av_cold int decode_init(AVCodecContext *avctx) +{ + ProResRAWContext *s = avctx->priv_data; + + avctx->bits_per_raw_sample = 12; + avctx->color_primaries = AVCOL_PRI_UNSPECIFIED; + avctx->color_trc = AVCOL_TRC_UNSPECIFIED; + avctx->colorspace = AVCOL_SPC_UNSPECIFIED; + + s->pix_fmt = AV_PIX_FMT_NONE; + + ff_blockdsp_init(&s->bdsp); + ff_proresdsp_init(&s->prodsp, avctx->bits_per_raw_sample); + + ff_permute_scantable(s->scan, ff_prores_interlaced_scan, s->prodsp.idct_permutation); + + return 0; +} + +static uint16_t get_value(GetBitContext *gb, int16_t codebook) +{ + const int16_t switch_bits = codebook >> 8; + const int16_t rice_order = codebook & 0xf; + const int16_t exp_order = (codebook >> 4) & 0xf; + int16_t q, bits; + + uint32_t b = show_bits_long(gb, 32); + if (!b) + return 0; + q = ff_clz(b); + + if (b & 0x80000000) { + skip_bits_long(gb, 1 + rice_order); + return (b & 0x7FFFFFFF) >> (31 - rice_order); + } + + if (q <= switch_bits) { + skip_bits_long(gb, 1 + rice_order + q); + return (q << rice_order) + + (((b << (q + 1)) >> 1) >> (31 - rice_order)); + } + + bits = exp_order + (q << 1) - switch_bits; + if (bits > 32) + return 0; // we do not return a negative error code so that we dont produce out of range values on errors + skip_bits_long(gb, bits); + return (b >> (32 - bits)) + + ((switch_bits + 1) << rice_order) - + (1 << exp_order); +} + +#define TODCCODEBOOK(x) ((x + 1) >> 1) + +#define DC_CB_MAX 12 +const uint8_t ff_prores_raw_dc_cb[DC_CB_MAX + 1] = { + 0x010, 0x021, 0x032, 0x033, 0x033, 0x033, 0x044, 0x044, 0x044, 0x044, 0x044, 0x044, 0x076, +}; + +#define AC_CB_MAX 94 +const int16_t ff_prores_raw_ac_cb[AC_CB_MAX + 1] = { + 0x000, 0x211, 0x111, 0x111, 0x222, 0x222, 0x222, 0x122, 0x122, 0x122, + 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x133, 0x133, + 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, + 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, + 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, + 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, + 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, + 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x166, +}; + +#define RN_CB_MAX 27 +const int16_t ff_prores_raw_rn_cb[RN_CB_MAX + 1] = { + 0x200, 0x100, 0x000, 0x000, 0x211, 0x211, 0x111, 0x111, 0x011, 0x011, 0x021, 0x021, 0x222, 0x022, + 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x032, 0x032, 0x044 +}; + +#define LN_CB_MAX 14 +const int16_t ff_prores_raw_ln_cb[LN_CB_MAX + 1] = { + 0x100, 0x111, 0x222, 0x222, 0x122, 0x122, 0x433, 0x433, 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x033, +}; + +static int decode_comp(AVCodecContext *avctx, TileContext *tile, + AVFrame *frame, const uint8_t *data, int size, + int component, int16_t *qmat) +{ + int ret; + ProResRAWContext *s = avctx->priv_data; + const ptrdiff_t linesize = frame->linesize[0] >> 1; + uint16_t *dst = (uint16_t *)(frame->data[0] + tile->y*frame->linesize[0] + 2*tile->x); + + int idx; + const int w = FFMIN(s->tw, avctx->width - tile->x) / 2; + const int nb_blocks = w / 8; + const int log2_nb_blocks = 31 - ff_clz(nb_blocks); + const int block_mask = (1 << log2_nb_blocks) - 1; + const int nb_codes = 64 * nb_blocks; + + LOCAL_ALIGNED_32(int16_t, block, [64*16]); + + int16_t sign = 0; + int16_t dc_add = 0; + int16_t dc_codebook; + + uint16_t ac, rn, ln; + int16_t ac_codebook = 49; + int16_t rn_codebook = 0; + int16_t ln_codebook = 66; + + const uint8_t *scan = s->scan; + GetBitContext gb; + + if (component > 1) + dst += linesize; + dst += component & 1; + + if ((ret = init_get_bits8(&gb, data, size)) < 0) + return ret; + + for (int n = 0; n < nb_blocks; n++) + s->bdsp.clear_block(block + n*64); + + /* Special handling for first block */ + int dc = get_value(&gb, 700); + int prev_dc = (dc >> 1) ^ -(dc & 1); + block[0] = (((dc&1) + (dc>>1) ^ -(int)(dc & 1)) + (dc & 1)) + 1; + + for (int n = 1; n < nb_blocks; n++) { + if (get_bits_left(&gb) <= 0) + break; + + if ((n & 15) == 1) + dc_codebook = 100; + else + dc_codebook = ff_prores_raw_dc_cb[FFMIN(TODCCODEBOOK(dc), DC_CB_MAX)]; + + dc = get_value(&gb, dc_codebook); + + sign = sign ^ dc & 1; + dc_add = (-sign ^ TODCCODEBOOK(dc)) + sign; + sign = dc_add < 0; + prev_dc += dc_add; + + block[n*64] = prev_dc + 1; + } + + for (int n = nb_blocks; n <= nb_codes;) { + if (get_bits_left(&gb) <= 0) + break; + + ln = get_value(&gb, ln_codebook); + + for (int i = 0; i < ln; i++) { + if (get_bits_left(&gb) <= 0) + break; + + if ((n + i) >= nb_codes) + break; + + ac = get_value(&gb, ac_codebook); + ac_codebook = ff_prores_raw_ac_cb[FFMIN(ac, AC_CB_MAX)]; + sign = -get_bits1(&gb); + + idx = scan[(n + i) >> log2_nb_blocks] + (((n + i) & block_mask) << 6); + block[idx] = ((ac + 1) ^ sign) - sign; + } + + n += ln; + if (n >= nb_codes) + break; + + rn = get_value(&gb, rn_codebook); + rn_codebook = ff_prores_raw_rn_cb[FFMIN(rn, RN_CB_MAX)]; + + n += rn + 1; + if (n >= nb_codes) + break; + + if (get_bits_left(&gb) <= 0) + break; + + ac = get_value(&gb, ac_codebook); + sign = -get_bits1(&gb); + + idx = scan[n >> log2_nb_blocks] + ((n & block_mask) << 6); + block[idx] = ((ac + 1) ^ sign) - sign; + + ac_codebook = ff_prores_raw_ac_cb[FFMIN(ac, AC_CB_MAX)]; + ln_codebook = ff_prores_raw_ln_cb[FFMIN(ac, LN_CB_MAX)]; + + n++; + } + + for (int n = 0; n < nb_blocks; n++) { + uint16_t *ptr = dst + n*16; + s->prodsp.idct_put_bayer(ptr, linesize, block + n*64, qmat); + } + + return 0; +} + +static int decode_tile(AVCodecContext *avctx, TileContext *tile, + AVFrame *frame) +{ + int ret; + ProResRAWContext *s = avctx->priv_data; + + GetByteContext *gb = &tile->gb; + LOCAL_ALIGNED_32(int16_t, qmat, [64]); + + if (tile->x >= avctx->width) + return 0; + + /* Tile header */ + int header_len = bytestream2_get_byteu(gb) >> 3; + int16_t scale = bytestream2_get_byteu(gb); + + int size[4]; + size[0] = bytestream2_get_be16(gb); + size[1] = bytestream2_get_be16(gb); + size[2] = bytestream2_get_be16(gb); + size[3] = bytestream2_size(gb) - size[0] - size[1] - size[2] - header_len; + if (size[3] < 0) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < 64; i++) + qmat[i] = s->qmat[i] * scale >> 1; + + const uint8_t *comp_start = gb->buffer_start + header_len; + + ret = decode_comp(avctx, tile, frame, comp_start, + size[0], 2, qmat); + if (ret < 0) + goto fail; + + ret = decode_comp(avctx, tile, frame, comp_start + size[0], + size[1], 1, qmat); + if (ret < 0) + goto fail; + + ret = decode_comp(avctx, tile, frame, comp_start + size[0] + size[1], + size[2], 3, qmat); + if (ret < 0) + goto fail; + + ret = decode_comp(avctx, tile, frame, comp_start + size[0] + size[1] + size[2], + size[3], 0, qmat); + if (ret < 0) + goto fail; + + return 0; +fail: + av_log(avctx, AV_LOG_ERROR, "tile %d/%d decoding error\n", tile->x, tile->y); + return ret; +} + +static int decode_tiles(AVCodecContext *avctx, void *arg, + int n, int thread_nb) +{ + ProResRAWContext *s = avctx->priv_data; + TileContext *tile = &s->tiles[n]; + AVFrame *frame = arg; + + return decode_tile(avctx, tile, frame); +} + +static enum AVPixelFormat get_pixel_format(AVCodecContext *avctx, + enum AVPixelFormat pix_fmt) +{ + enum AVPixelFormat pix_fmts[] = { +#if CONFIG_PRORES_RAW_VULKAN_HWACCEL + AV_PIX_FMT_VULKAN, +#endif + pix_fmt, + AV_PIX_FMT_NONE, + }; + + return ff_get_format(avctx, pix_fmts); +} + +static int decode_frame(AVCodecContext *avctx, + AVFrame *frame, int *got_frame_ptr, + AVPacket *avpkt) +{ + ProResRAWContext *s = avctx->priv_data; + int ret, dimensions_changed = 0, old_version = s->version; + DECLARE_ALIGNED(32, uint8_t, qmat)[64]; + memset(qmat, 1, 64); + + if (avctx->skip_frame >= AVDISCARD_ALL) + return avpkt->size; + + switch (avctx->codec_tag) { + case 0: + break; + case MKTAG('a','p','r','n'): + avctx->profile = AV_PROFILE_PRORES_RAW; + break; + case MKTAG('a','p','r','h'): + avctx->profile = AV_PROFILE_PRORES_RAW_HQ; + break; + default: + avpriv_request_sample(avctx, "Profile %d", avctx->codec_tag); + return AVERROR_PATCHWELCOME; + break; + } + + GetByteContext gb; + bytestream2_init(&gb, avpkt->data, avpkt->size); + if (bytestream2_get_be32(&gb) != avpkt->size) + return AVERROR_INVALIDDATA; + + /* ProRes RAW frame */ + if (bytestream2_get_be32(&gb) != MKBETAG('p','r','r','f')) + return AVERROR_INVALIDDATA; + + int header_len = bytestream2_get_be16(&gb); + if (header_len < 62 || bytestream2_get_bytes_left(&gb) < header_len - 2) + return AVERROR_INVALIDDATA; + + GetByteContext gb_hdr; + bytestream2_init(&gb_hdr, gb.buffer, header_len - 2); + bytestream2_skip(&gb, header_len - 2); + + bytestream2_skip(&gb_hdr, 1); + s->version = bytestream2_get_byte(&gb_hdr); + if (s->version > 1) { + avpriv_request_sample(avctx, "Version %d", s->version); + return AVERROR_PATCHWELCOME; + } + + /* Vendor header (e.g. "peac" for Panasonic or "atm0" for Atmos) */ + bytestream2_skip(&gb_hdr, 4); + + /* Width and height must always be even */ + int w = bytestream2_get_be16(&gb_hdr); + int h = bytestream2_get_be16(&gb_hdr); + if ((w & 1) || (h & 1)) + return AVERROR_INVALIDDATA; + + if (w != avctx->width || h != avctx->height) { + av_log(avctx, AV_LOG_WARNING, "picture resolution change: %ix%i -> %ix%i\n", + avctx->width, avctx->height, w, h); + if ((ret = ff_set_dimensions(avctx, w, h)) < 0) + return ret; + dimensions_changed = 1; + } + + avctx->coded_width = FFALIGN(w, 16); + avctx->coded_height = FFALIGN(h, 16); + + enum AVPixelFormat pix_fmt = AV_PIX_FMT_BAYER_RGGB16; + if (pix_fmt != s->pix_fmt || dimensions_changed || + s->version != old_version) { + s->pix_fmt = pix_fmt; + + ret = get_pixel_format(avctx, pix_fmt); + if (ret < 0) + return ret; + + avctx->pix_fmt = ret; + } + + bytestream2_skip(&gb_hdr, 1 * 4); + bytestream2_skip(&gb_hdr, 2); /* & 0x3 */ + bytestream2_skip(&gb_hdr, 2); + bytestream2_skip(&gb_hdr, 4); + bytestream2_skip(&gb_hdr, 4); + bytestream2_skip(&gb_hdr, 4 * 3 * 3); + bytestream2_skip(&gb_hdr, 4); + bytestream2_skip(&gb_hdr, 2); + + /* Flags */ + int flags = bytestream2_get_be16(&gb_hdr); + int align = (flags >> 1) & 0x7; + + /* Quantization matrix */ + if (flags & 1) + bytestream2_get_buffer(&gb_hdr, qmat, 64); + + if ((flags >> 4) & 1) { + bytestream2_skip(&gb_hdr, 2); + bytestream2_skip(&gb_hdr, 2 * 7); + } + + ff_permute_scantable(s->qmat, s->prodsp.idct_permutation, qmat); + + s->nb_tw = (w + 15) >> 4; + s->nb_th = (h + 15) >> 4; + s->nb_tw = (s->nb_tw >> align) + av_popcount(~(-1 * (1 << align)) & s->nb_tw); + s->nb_tiles = s->nb_tw * s->nb_th; + av_log(avctx, AV_LOG_DEBUG, "%dx%d | nb_tiles: %d\n", s->nb_tw, s->nb_th, s->nb_tiles); + + s->tw = s->version == 0 ? 128 : 256; + s->th = 16; + av_log(avctx, AV_LOG_DEBUG, "tile_size: %dx%d\n", s->tw, s->th); + + av_fast_mallocz(&s->tiles, &s->tiles_size, s->nb_tiles * sizeof(*s->tiles)); + if (!s->tiles) + return AVERROR(ENOMEM); + + if (bytestream2_get_bytes_left(&gb) < s->nb_tiles * 2) + return AVERROR_INVALIDDATA; + + /* Read tile data offsets */ + int offset = bytestream2_tell(&gb) + s->nb_tiles * 2; + for (int n = 0; n < s->nb_tiles; n++) { + TileContext *tile = &s->tiles[n]; + + int size = bytestream2_get_be16(&gb); + if (offset >= avpkt->size) + return AVERROR_INVALIDDATA; + if (size >= avpkt->size) + return AVERROR_INVALIDDATA; + if (offset > avpkt->size - size) + return AVERROR_INVALIDDATA; + + bytestream2_init(&tile->gb, avpkt->data + offset, size); + + tile->y = (n / s->nb_tw) * s->th; + tile->x = (n % s->nb_tw) * s->tw; + + if (avctx->width - tile->x < 16) + return AVERROR_PATCHWELCOME; + + offset += size; + } + + ret = ff_thread_get_buffer(avctx, frame, 0); + if (ret < 0) + return ret; + + s->frame = frame; + + /* Start */ + if (avctx->hwaccel) { + const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel); + + ret = ff_hwaccel_frame_priv_alloc(avctx, &s->hwaccel_picture_private); + if (ret < 0) + return ret; + + ret = hwaccel->start_frame(avctx, avpkt->buf, avpkt->data, avpkt->size); + if (ret < 0) + return ret; + + for (int n = 0; n < s->nb_tiles; n++) { + TileContext *tile = &s->tiles[n]; + ret = hwaccel->decode_slice(avctx, tile->gb.buffer, + tile->gb.buffer_end - tile->gb.buffer); + if (ret < 0) + return ret; + } + + ret = hwaccel->end_frame(avctx); + if (ret < 0) + return ret; + + av_refstruct_unref(&s->hwaccel_picture_private); + } else { + avctx->execute2(avctx, decode_tiles, frame, NULL, s->nb_tiles); + } + + frame->pict_type = AV_PICTURE_TYPE_I; + frame->flags |= AV_FRAME_FLAG_KEY; + + *got_frame_ptr = 1; + + return avpkt->size; +} + +static av_cold int decode_end(AVCodecContext *avctx) +{ + ProResRAWContext *s = avctx->priv_data; + av_refstruct_unref(&s->hwaccel_picture_private); + av_freep(&s->tiles); + return 0; +} + +#if HAVE_THREADS +static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) +{ + ProResRAWContext *rsrc = src->priv_data; + ProResRAWContext *rdst = dst->priv_data; + + rdst->pix_fmt = rsrc->pix_fmt; + rdst->version = rsrc->version; + + return 0; +} +#endif + +const FFCodec ff_prores_raw_decoder = { + .p.name = "prores_raw", + CODEC_LONG_NAME("Apple ProRes RAW"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_PRORES_RAW, + .priv_data_size = sizeof(ProResRAWContext), + .init = decode_init, + .close = decode_end, + FF_CODEC_DECODE_CB(decode_frame), + UPDATE_THREAD_CONTEXT(update_thread_context), + .p.capabilities = AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_FRAME_THREADS | + AV_CODEC_CAP_SLICE_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .hw_configs = (const AVCodecHWConfigInternal *const []) { +#if CONFIG_PRORES_RAW_VULKAN_HWACCEL + HWACCEL_VULKAN(prores_raw), +#endif + NULL + }, +}; diff --git a/libavcodec/prores_raw.h b/libavcodec/prores_raw.h new file mode 100644 index 000000000..3ac8068dd --- /dev/null +++ b/libavcodec/prores_raw.h @@ -0,0 +1,63 @@ +/* + * ProRes RAW decoder + * Copyright (c) 2025 Lynne + * + * 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_PRORES_RAW_H +#define AVCODEC_PRORES_RAW_H + +#include "libavutil/frame.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixfmt.h" + +#include "bytestream.h" +#include "blockdsp.h" +#include "proresdsp.h" + +typedef struct TileContext { + GetByteContext gb; + unsigned x, y; +} TileContext; + +typedef struct ProResRAWContext { + ProresDSPContext prodsp; + BlockDSPContext bdsp; + + TileContext *tiles; + unsigned int tiles_size; + int nb_tiles; + int tw, th; + int nb_tw, nb_th; + + enum AVPixelFormat pix_fmt; + AVFrame *frame; + void *hwaccel_picture_private; + + int version; + + DECLARE_ALIGNED(32, uint8_t, scan)[64]; + DECLARE_ALIGNED(32, uint8_t, qmat)[64]; +} ProResRAWContext; + +extern const uint8_t ff_prores_raw_dc_cb[13]; +extern const int16_t ff_prores_raw_ac_cb[95]; +extern const int16_t ff_prores_raw_rn_cb[28]; +extern const int16_t ff_prores_raw_ln_cb[15]; + +#endif /* AVCODEC_PRORES_RAW_H */ diff --git a/libavcodec/prores_raw_parser.c b/libavcodec/prores_raw_parser.c new file mode 100644 index 000000000..a32e4cf39 --- /dev/null +++ b/libavcodec/prores_raw_parser.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2025 Lynne + * + * 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 "parser.h" +#include "bytestream.h" +#include "parser_internal.h" + +static int prores_raw_parse(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + GetByteContext gb; + + switch (avctx->codec_tag) { + case 0: + break; + case MKTAG('a','p','r','n'): + avctx->profile = AV_PROFILE_PRORES_RAW; + break; + case MKTAG('a','p','r','h'): + avctx->profile = AV_PROFILE_PRORES_RAW_HQ; + break; + default: + avpriv_request_sample(avctx, "Profile %d", avctx->codec_tag); + return buf_size; + break; + } + + bytestream2_init(&gb, buf, buf_size); + if (bytestream2_get_be32(&gb) != buf_size) /* Packet size */ + return buf_size; + + if (bytestream2_get_be32(&gb) != MKBETAG('p','r','r','f')) /* Frame header */ + return buf_size; + + int header_size = bytestream2_get_be16(&gb); + if (header_size < 62) + return buf_size; + + bytestream2_skip(&gb, 1); + int version = bytestream2_get_byte(&gb); + if (version > 1) { + avpriv_request_sample(avctx, "Version %d", version); + return buf_size; + } + + /* Vendor header (e.g. "peac" for Panasonic or "atm0" for Atmos) */ + switch (bytestream2_get_be32(&gb)) { + case MKBETAG('p','e','a','c'): + /* Internal recording from a Panasonic camera, V-Log */ + avctx->color_primaries = AVCOL_PRI_V_GAMUT; + avctx->color_trc = AVCOL_TRC_V_LOG; + break; + case MKBETAG('a','t','m','0'): + /* External recording from an Atomos recorder. Cameras universally + * record in their own native log curve internally, but linearize it + * when outputting RAW externally */ + avctx->color_primaries = AVCOL_PRI_UNSPECIFIED; + avctx->color_trc = AVCOL_TRC_LINEAR; + break; + default: + avctx->color_trc = AVCOL_TRC_UNSPECIFIED; + break; + }; + + s->width = bytestream2_get_be16(&gb); + s->height = bytestream2_get_be16(&gb); + s->coded_width = FFALIGN(s->width, 16); + s->coded_height = FFALIGN(s->height, 16); + s->format = AV_PIX_FMT_BAYER_RGGB16; + s->key_frame = 1; + s->pict_type = AV_PICTURE_TYPE_I; + s->field_order = AV_FIELD_PROGRESSIVE; + s->picture_structure = AV_PICTURE_STRUCTURE_FRAME; + + /* This parser only performs analysis */ + *poutbuf = buf; + *poutbuf_size = buf_size; + + return buf_size; +} + +const FFCodecParser ff_prores_raw_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_PRORES_RAW), + .parse = prores_raw_parse, +}; diff --git a/libavcodec/proresdec.c b/libavcodec/proresdec.c index 6a256107b..b971d1797 100644 --- a/libavcodec/proresdec.c +++ b/libavcodec/proresdec.c @@ -26,8 +26,6 @@ //#define DEBUG -#define LONG_BITSTREAM_READER - #include "config_components.h" #include "libavutil/internal.h" @@ -134,9 +132,7 @@ static void unpack_alpha_12(GetBitContext *gb, uint16_t *dst, int num_coeffs, static av_cold int decode_init(AVCodecContext *avctx) { - int ret = 0; ProresContext *ctx = avctx->priv_data; - uint8_t idct_permutation[64]; avctx->bits_per_raw_sample = 10; @@ -166,45 +162,34 @@ static av_cold int decode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_WARNING, "Unknown prores profile %d\n", avctx->codec_tag); } - if (avctx->bits_per_raw_sample == 10) { - av_log(avctx, AV_LOG_DEBUG, "Auto bitdepth precision. Use 10b decoding based on codec tag.\n"); - } else { /* 12b */ - av_log(avctx, AV_LOG_DEBUG, "Auto bitdepth precision. Use 12b decoding based on codec tag.\n"); - } + ctx->unpack_alpha = avctx->bits_per_raw_sample == 10 ? + unpack_alpha_10 : unpack_alpha_12; + + av_log(avctx, AV_LOG_DEBUG, + "Auto bitdepth precision. Use %db decoding based on codec tag.\n", + avctx->bits_per_raw_sample); ff_blockdsp_init(&ctx->bdsp); - ret = ff_proresdsp_init(&ctx->prodsp, avctx->bits_per_raw_sample); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Fail to init proresdsp for bits per raw sample %d\n", avctx->bits_per_raw_sample); - return ret; - } + ff_proresdsp_init(&ctx->prodsp, avctx->bits_per_raw_sample); - ff_init_scantable_permutation(idct_permutation, - ctx->prodsp.idct_permutation_type); - - ff_permute_scantable(ctx->progressive_scan, ff_prores_progressive_scan, idct_permutation); - ff_permute_scantable(ctx->interlaced_scan, ff_prores_interlaced_scan, idct_permutation); + ff_permute_scantable(ctx->progressive_scan, ff_prores_progressive_scan, + ctx->prodsp.idct_permutation); + ff_permute_scantable(ctx->interlaced_scan, ff_prores_interlaced_scan, + ctx->prodsp.idct_permutation); ctx->pix_fmt = AV_PIX_FMT_NONE; - if (avctx->bits_per_raw_sample == 10){ - ctx->unpack_alpha = unpack_alpha_10; - } else if (avctx->bits_per_raw_sample == 12){ - ctx->unpack_alpha = unpack_alpha_12; - } else { - av_log(avctx, AV_LOG_ERROR, "Fail to set unpack_alpha for bits per raw sample %d\n", avctx->bits_per_raw_sample); - return AVERROR_BUG; - } - return ret; + return 0; } static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, const int data_size, AVCodecContext *avctx) { - int hdr_size, width, height, flags; + int hdr_size, width, height, flags, dimensions_changed = 0; int version; const uint8_t *ptr; enum AVPixelFormat pix_fmt; + int old_frame_type = ctx->frame_type; hdr_size = AV_RB16(buf); ff_dlog(avctx, "header size %d\n", hdr_size); @@ -230,6 +215,7 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, avctx->width, avctx->height, width, height); if ((ret = ff_set_dimensions(avctx, width, height)) < 0) return ret; + dimensions_changed = 1; } ctx->frame_type = (buf[12] >> 2) & 3; @@ -266,8 +252,10 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, } } - if (pix_fmt != ctx->pix_fmt) { -#define HWACCEL_MAX (CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL) + if (pix_fmt != ctx->pix_fmt || dimensions_changed || + ctx->frame_type != old_frame_type) { +#define HWACCEL_MAX (CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL + CONFIG_PRORES_VULKAN_HWACCEL) +#if HWACCEL_MAX enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts; int ret; @@ -275,6 +263,9 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, #if CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL *fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX; +#endif +#if CONFIG_PRORES_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; #endif *fmtp++ = ctx->pix_fmt; *fmtp = AV_PIX_FMT_NONE; @@ -283,12 +274,15 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, return ret; avctx->pix_fmt = ret; +#else + avctx->pix_fmt = ctx->pix_fmt = pix_fmt; +#endif } - ctx->frame->color_primaries = buf[14]; - ctx->frame->color_trc = buf[15]; - ctx->frame->colorspace = buf[16]; - ctx->frame->color_range = AVCOL_RANGE_MPEG; + avctx->color_primaries = buf[14]; + avctx->color_trc = buf[15]; + avctx->colorspace = buf[16]; + avctx->color_range = AVCOL_RANGE_MPEG; ptr = buf + 20; flags = buf[19]; @@ -347,6 +341,9 @@ static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, cons return AVERROR_INVALIDDATA; } + ctx->slice_mb_width = 1 << log2_slice_mb_width; + ctx->slice_mb_height = 1 << log2_slice_mb_height; + ctx->mb_width = (avctx->width + 15) >> 4; if (ctx->frame_type) ctx->mb_height = (avctx->height + 31) >> 5; @@ -356,7 +353,7 @@ static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, cons // QT ignores the written value // slice_count = AV_RB16(buf + 5); slice_count = ctx->mb_height * ((ctx->mb_width >> log2_slice_mb_width) + - av_popcount(ctx->mb_width & (1 << log2_slice_mb_width) - 1)); + av_popcount(ctx->mb_width & ctx->slice_mb_width - 1)); if (ctx->slice_count != slice_count || !ctx->slices) { av_freep(&ctx->slices); @@ -379,7 +376,7 @@ static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, cons index_ptr = buf + hdr_size; data_ptr = index_ptr + slice_count*2; - slice_mb_count = 1 << log2_slice_mb_width; + slice_mb_count = ctx->slice_mb_width; mb_x = 0; mb_y = 0; @@ -404,7 +401,7 @@ static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, cons mb_x += slice_mb_count; if (mb_x == ctx->mb_width) { - slice_mb_count = 1 << log2_slice_mb_width; + slice_mb_count = ctx->slice_mb_width; mb_x = 0; mb_y++; } @@ -428,7 +425,7 @@ static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, cons unsigned int rice_order, exp_order, switch_bits; \ unsigned int q, buf, bits; \ \ - UPDATE_CACHE(re, gb); \ + UPDATE_CACHE_32(re, gb); /* We really need 32 bits */ \ buf = GET_CACHE(re, gb); \ \ /* number of bits to switch between rice and exp golomb */ \ @@ -440,7 +437,7 @@ static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, cons \ if (q > switch_bits) { /* exp golomb */ \ bits = exp_order - switch_bits + (q<<1); \ - if (bits > FFMIN(MIN_CACHE_BITS, 31)) \ + if (bits > 31) \ return AVERROR_INVALIDDATA; \ val = SHOW_UBITS(re, gb, bits) - (1 << exp_order) + \ ((switch_bits + 1) << rice_order); \ @@ -502,7 +499,7 @@ static av_always_inline int decode_ac_coeffs(AVCodecContext *avctx, GetBitContex int log2_block_count = av_log2(blocks_per_slice); OPEN_READER(re, gb); - UPDATE_CACHE(re, gb); \ + UPDATE_CACHE_32(re, gb); run = 4; level = 2; @@ -584,12 +581,15 @@ static int decode_slice_chroma(AVCodecContext *avctx, SliceContext *slice, for (i = 0; i < blocks_per_slice; i++) ctx->bdsp.clear_block(blocks+(i<<6)); - init_get_bits(&gb, buf, buf_size << 3); + /* Some encodes have empty chroma scans to simulate grayscale */ + if (buf_size) { + init_get_bits(&gb, buf, buf_size << 3); - if ((ret = decode_dc_coeffs(&gb, blocks, blocks_per_slice)) < 0) - return ret; - if ((ret = decode_ac_coeffs(avctx, &gb, blocks, blocks_per_slice)) < 0) - return ret; + if ((ret = decode_dc_coeffs(&gb, blocks, blocks_per_slice)) < 0) + return ret; + if ((ret = decode_ac_coeffs(avctx, &gb, blocks, blocks_per_slice)) < 0) + return ret; + } block = blocks; for (i = 0; i < slice->mb_count; i++) { @@ -650,7 +650,6 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int LOCAL_ALIGNED_16(int16_t, qmat_chroma_scaled,[64]); int mb_x_shift; int ret; - uint16_t val_no_chroma; slice->ret = -1; //av_log(avctx, AV_LOG_INFO, "slice %d mb width %d mb x %d y %d\n", @@ -714,7 +713,7 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int if (ret < 0) return ret; - if (!(avctx->flags & AV_CODEC_FLAG_GRAY) && (u_data_size + v_data_size) > 0) { + if (!(avctx->flags & AV_CODEC_FLAG_GRAY)) { ret = decode_slice_chroma(avctx, slice, (uint16_t*)dest_u, chroma_stride, buf + y_data_size, u_data_size, qmat_chroma_scaled, log2_chroma_blocks_per_mb); @@ -727,20 +726,6 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int if (ret < 0) return ret; } - else { - size_t mb_max_x = slice->mb_count << (mb_x_shift - 1); - size_t i, j; - if (avctx->bits_per_raw_sample == 10) { - val_no_chroma = 511; - } else { /* 12b */ - val_no_chroma = 511 * 4; - } - for (i = 0; i < 16; ++i) - for (j = 0; j < mb_max_x; ++j) { - *(uint16_t*)(dest_u + (i * chroma_stride) + (j << 1)) = val_no_chroma; - *(uint16_t*)(dest_v + (i * chroma_stride) + (j << 1)) = val_no_chroma; - } - } /* decode alpha plane if available */ if (ctx->alpha_info && pic->data[3] && a_data_size) { @@ -780,6 +765,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; int frame_hdr_size, pic_size, ret; + int i; if (buf_size < 28 || AV_RL32(buf + 4) != AV_RL32("icpf")) { av_log(avctx, AV_LOG_ERROR, "invalid frame header\n"); @@ -796,26 +782,21 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if (frame_hdr_size < 0) return frame_hdr_size; + if (avctx->skip_frame == AVDISCARD_ALL) + return 0; + buf += frame_hdr_size; buf_size -= frame_hdr_size; if ((ret = ff_thread_get_buffer(avctx, frame, 0)) < 0) return ret; - ff_thread_finish_setup(avctx); - if (avctx->hwaccel) { - const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel); - ret = hwaccel->start_frame(avctx, NULL, 0); - if (ret < 0) - return ret; - ret = hwaccel->decode_slice(avctx, avpkt->data, avpkt->size); - if (ret < 0) - return ret; - ret = hwaccel->end_frame(avctx); - if (ret < 0) - return ret; - goto finish; - } + av_refstruct_unref(&ctx->hwaccel_picture_private); + + if ((ret = ff_hwaccel_frame_priv_alloc(avctx, &ctx->hwaccel_picture_private)) < 0) + return ret; + + ff_thread_finish_setup(avctx); decode_picture: pic_size = decode_picture_header(avctx, buf, buf_size); @@ -824,7 +805,23 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, return pic_size; } - if ((ret = decode_picture(avctx)) < 0) { + if (HWACCEL_MAX && avctx->hwaccel) { + const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel); + + ret = hwaccel->start_frame(avctx, avpkt->buf, avpkt->data, avpkt->size); + if (ret < 0) + return ret; + + for (i = 0; i < ctx->slice_count; ++i) { + ret = hwaccel->decode_slice(avctx, ctx->slices[i].data, ctx->slices[i].data_size); + if (ret < 0) + return ret; + } + + ret = hwaccel->end_frame(avctx); + if (ret < 0) + return ret; + } else if ((ret = decode_picture(avctx)) < 0) { av_log(avctx, AV_LOG_ERROR, "error decoding picture\n"); return ret; } @@ -837,7 +834,8 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, goto decode_picture; } -finish: + av_refstruct_unref(&ctx->hwaccel_picture_private); + *got_frame = 1; return avpkt->size; @@ -848,6 +846,7 @@ static av_cold int decode_close(AVCodecContext *avctx) ProresContext *ctx = avctx->priv_data; av_freep(&ctx->slices); + av_refstruct_unref(&ctx->hwaccel_picture_private); return 0; } @@ -859,6 +858,7 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) ProresContext *cdst = dst->priv_data; cdst->pix_fmt = csrc->pix_fmt; + cdst->frame_type = csrc->frame_type; return 0; } @@ -875,11 +875,17 @@ const FFCodec ff_prores_decoder = { FF_CODEC_DECODE_CB(decode_frame), UPDATE_THREAD_CONTEXT(update_thread_context), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, + .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .p.profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), +#if HWACCEL_MAX .hw_configs = (const AVCodecHWConfigInternal *const []) { #if CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL HWACCEL_VIDEOTOOLBOX(prores), +#endif +#if CONFIG_PRORES_VULKAN_HWACCEL + HWACCEL_VULKAN(prores), #endif NULL }, +#endif }; diff --git a/libavcodec/proresdec.h b/libavcodec/proresdec.h index 230fca41f..965fc85b7 100644 --- a/libavcodec/proresdec.h +++ b/libavcodec/proresdec.h @@ -44,6 +44,7 @@ typedef struct { BlockDSPContext bdsp; ProresDSPContext prodsp; AVFrame *frame; + void *hwaccel_picture_private; int frame_type; ///< 0 = progressive, 1 = tff, 2 = bff uint8_t qmat_luma[64]; uint8_t qmat_chroma[64]; @@ -51,6 +52,8 @@ typedef struct { int slice_count; ///< number of slices in the current picture unsigned mb_width; ///< width of the current picture in mb unsigned mb_height; ///< height of the current picture in mb + unsigned slice_mb_width; ///< maximum width of a slice in mb + unsigned slice_mb_height; ///< maximum height of a slice in mb uint8_t progressive_scan[64]; uint8_t interlaced_scan[64]; const uint8_t *scan; diff --git a/libavcodec/proresdsp.c b/libavcodec/proresdsp.c index bc253e55f..eb5dbf479 100644 --- a/libavcodec/proresdsp.c +++ b/libavcodec/proresdsp.c @@ -22,10 +22,57 @@ #include "config.h" #include "libavutil/attributes.h" +#include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/intreadwrite.h" #include "idctdsp.h" #include "proresdsp.h" -#include "simple_idct.h" + +#define IN_IDCT_DEPTH 16 +#define PRORES_ONLY + +#define BIT_DEPTH 10 +#define EXTRA_SHIFT +#include "simple_idct_template.c" +#undef BIT_DEPTH +#undef EXTRA_SHIFT + +#define BIT_DEPTH 12 +#include "simple_idct_template.c" +#undef BIT_DEPTH + +/** + * Special version of ff_simple_idct_int16_10bit() which does dequantization + * and scales by a factor of 2 more between the two IDCTs to account + * for larger scale of input coefficients. + */ +static void prores_idct_10(int16_t *restrict block, const int16_t *restrict qmat) +{ + for (int i = 0; i < 64; i++) + block[i] *= qmat[i]; + + for (int i = 0; i < 8; i++) + idctRowCondDC_extrashift_10(block + i*8, 2); + + for (int i = 0; i < 8; i++) { + block[i] += 8192; + idctSparseCol_extrashift_10(block + i); + } +} + +static void prores_idct_12(int16_t *restrict block, const int16_t *restrict qmat) +{ + for (int i = 0; i < 64; i++) + block[i] *= qmat[i]; + + for (int i = 0; i < 8; i++) + idctRowCondDC_int16_12bit(block + i*8, 0); + + for (int i = 0; i < 8; i++) { + block[i] += 8192; + idctSparseCol_int16_12bit(block + i); + } +} #define CLIP_MIN (1 << 2) ///< minimum value for clipping resulting pixels #define CLIP_MAX_10 (1 << 10) - CLIP_MIN - 1 ///< maximum value for clipping resulting pixels @@ -39,21 +86,28 @@ */ static inline void put_pixel(uint16_t *dst, ptrdiff_t linesize, const int16_t *in, int bits_per_raw_sample) { - int x, y, src_offset, dst_offset; - - for (y = 0, dst_offset = 0; y < 8; y++, dst_offset += linesize) { - for (x = 0; x < 8; x++) { - src_offset = (y << 3) + x; + for (int y = 0; y < 8; y++, dst += linesize) { + for (int x = 0; x < 8; x++) { + int src_offset = (y << 3) + x; if (bits_per_raw_sample == 10) { - dst[dst_offset + x] = CLIP_10(in[src_offset]); + dst[x] = CLIP_10(in[src_offset]); } else {//12b - dst[dst_offset + x] = CLIP_12(in[src_offset]); + dst[x] = CLIP_12(in[src_offset]); } } } } +static inline void put_pixel_bayer_12(uint16_t *dst, ptrdiff_t linesize, + const int16_t *in) +{ + for (int y = 0; y < 8; y++, dst += linesize) { + for (int x = 0; x < 8; x++) + dst[x*2] = CLIP_12(in[(y << 3) + x]) << 4; + } +} + static void put_pixels_10(uint16_t *dst, ptrdiff_t linesize, const int16_t *in) { put_pixel(dst, linesize, in, 10); @@ -66,33 +120,39 @@ static void put_pixels_12(uint16_t *dst, ptrdiff_t linesize, const int16_t *in) static void prores_idct_put_10_c(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat) { - ff_prores_idct_10(block, qmat); + prores_idct_10(block, qmat); put_pixels_10(out, linesize >> 1, block); } static void prores_idct_put_12_c(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat) { - ff_prores_idct_12(block, qmat); + prores_idct_12(block, qmat); put_pixels_12(out, linesize >> 1, block); } -av_cold int ff_proresdsp_init(ProresDSPContext *dsp, int bits_per_raw_sample) +static void prores_idct_put_bayer_12_c(uint16_t *out, ptrdiff_t linesize, + int16_t *block, const int16_t *qmat) +{ + prores_idct_12(block, qmat); + put_pixel_bayer_12(out, linesize << 1, block); +} + +av_cold void ff_proresdsp_init(ProresDSPContext *dsp, int bits_per_raw_sample) { if (bits_per_raw_sample == 10) { dsp->idct_put = prores_idct_put_10_c; dsp->idct_permutation_type = FF_IDCT_PERM_NONE; - } else if (bits_per_raw_sample == 12) { - dsp->idct_put = prores_idct_put_12_c; - dsp->idct_permutation_type = FF_IDCT_PERM_NONE; } else { - return AVERROR_BUG; + av_assert1(bits_per_raw_sample == 12); + dsp->idct_put = prores_idct_put_12_c; + dsp->idct_put_bayer = prores_idct_put_bayer_12_c; + dsp->idct_permutation_type = FF_IDCT_PERM_NONE; } -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_proresdsp_init_x86(dsp, bits_per_raw_sample); #endif ff_init_scantable_permutation(dsp->idct_permutation, dsp->idct_permutation_type); - return 0; } diff --git a/libavcodec/proresdsp.h b/libavcodec/proresdsp.h index 966ba3d79..f8b57d7e8 100644 --- a/libavcodec/proresdsp.h +++ b/libavcodec/proresdsp.h @@ -30,9 +30,10 @@ typedef struct ProresDSPContext { int idct_permutation_type; uint8_t idct_permutation[64]; void (*idct_put)(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat); + void (*idct_put_bayer)(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat); } ProresDSPContext; -int ff_proresdsp_init(ProresDSPContext *dsp, int bits_per_raw_sample); +void ff_proresdsp_init(ProresDSPContext *dsp, int bits_per_raw_sample); void ff_proresdsp_init_x86(ProresDSPContext *dsp, int bits_per_raw_sample); diff --git a/libavcodec/proresenc_anatoliy.c b/libavcodec/proresenc_anatoliy.c index 4493ed03b..1d4041019 100644 --- a/libavcodec/proresenc_anatoliy.c +++ b/libavcodec/proresenc_anatoliy.c @@ -27,6 +27,7 @@ * Known FOURCCs: 'ap4h' (444), 'apch' (HQ), 'apcn' (422), 'apcs' (LT), 'acpo' (Proxy) */ +#include "libavutil/avassert.h" #include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" @@ -382,7 +383,7 @@ static int encode_slice_plane(int16_t *blocks, int mb_count, uint8_t *buf, unsig encode_acs(&pb, blocks, blocks_per_slice, qmat, scan); flush_put_bits(&pb); - return put_bits_ptr(&pb) - pb.buf; + return put_bytes_output(&pb); } static av_always_inline unsigned encode_slice_data(AVCodecContext *avctx, @@ -396,14 +397,12 @@ static av_always_inline unsigned encode_slice_data(AVCodecContext *avctx, *y_data_size = encode_slice_plane(blocks_y, mb_count, buf, data_size, ctx->qmat_luma[qp - 1], 0, ctx->scantable); - if (!(avctx->flags & AV_CODEC_FLAG_GRAY)) { - *u_data_size = encode_slice_plane(blocks_u, mb_count, buf + *y_data_size, data_size - *y_data_size, - ctx->qmat_chroma[qp - 1], ctx->is_422, ctx->scantable); + *u_data_size = encode_slice_plane(blocks_u, mb_count, buf + *y_data_size, data_size - *y_data_size, + ctx->qmat_chroma[qp - 1], ctx->is_422, ctx->scantable); - *v_data_size = encode_slice_plane(blocks_v, mb_count, buf + *y_data_size + *u_data_size, - data_size - *y_data_size - *u_data_size, - ctx->qmat_chroma[qp - 1], ctx->is_422, ctx->scantable); - } + *v_data_size = encode_slice_plane(blocks_v, mb_count, buf + *y_data_size + *u_data_size, + data_size - *y_data_size - *u_data_size, + ctx->qmat_chroma[qp - 1], ctx->is_422, ctx->scantable); return *y_data_size + *u_data_size + *v_data_size; } @@ -845,20 +844,25 @@ static av_cold int prores_encode_init(AVCodecContext *avctx) } if (avctx->profile == AV_PROFILE_UNKNOWN) { - if (avctx->pix_fmt == AV_PIX_FMT_YUV422P10) { + switch (avctx->pix_fmt) { + case AV_PIX_FMT_YUV422P10: avctx->profile = AV_PROFILE_PRORES_STANDARD; av_log(avctx, AV_LOG_INFO, "encoding with ProRes standard (apcn) profile\n"); - } else if (avctx->pix_fmt == AV_PIX_FMT_YUV444P10) { + break; + case AV_PIX_FMT_YUV444P10: avctx->profile = AV_PROFILE_PRORES_4444; av_log(avctx, AV_LOG_INFO, "encoding with ProRes 4444 (ap4h) profile\n"); - } else if (avctx->pix_fmt == AV_PIX_FMT_YUVA444P10) { + break; + case AV_PIX_FMT_YUVA444P10: avctx->profile = AV_PROFILE_PRORES_4444; av_log(avctx, AV_LOG_INFO, "encoding with ProRes 4444+ (ap4h) profile\n"); - } else - av_assert0(0); + break; + default: + av_unreachable("Already checked via CODEC_PIXFMTS"); + } } else if (avctx->profile < AV_PROFILE_PRORES_PROXY || avctx->profile > AV_PROFILE_PRORES_XQ) { av_log( @@ -955,7 +959,7 @@ const FFCodec ff_prores_aw_encoder = { .p.id = AV_CODEC_ID_PRORES, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = pix_fmts, + CODEC_PIXFMTS_ARRAY(pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, .priv_data_size = sizeof(ProresContext), .init = prores_encode_init, @@ -973,7 +977,7 @@ const FFCodec ff_prores_encoder = { .p.id = AV_CODEC_ID_PRORES, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = pix_fmts, + CODEC_PIXFMTS_ARRAY(pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, .priv_data_size = sizeof(ProresContext), .init = prores_encode_init, diff --git a/libavcodec/proresenc_kostya.c b/libavcodec/proresenc_kostya.c index 226f95f8c..ccb41c0d2 100644 --- a/libavcodec/proresenc_kostya.c +++ b/libavcodec/proresenc_kostya.c @@ -33,179 +33,7 @@ #include "profiles.h" #include "bytestream.h" #include "proresdata.h" - -#define CFACTOR_Y422 2 -#define CFACTOR_Y444 3 - -#define MAX_MBS_PER_SLICE 8 - -#define MAX_PLANES 4 - -enum { - PRORES_PROFILE_AUTO = -1, - PRORES_PROFILE_PROXY = 0, - PRORES_PROFILE_LT, - PRORES_PROFILE_STANDARD, - PRORES_PROFILE_HQ, - PRORES_PROFILE_4444, - PRORES_PROFILE_4444XQ, -}; - -enum { - QUANT_MAT_PROXY = 0, - QUANT_MAT_PROXY_CHROMA, - QUANT_MAT_LT, - QUANT_MAT_STANDARD, - QUANT_MAT_HQ, - QUANT_MAT_XQ_LUMA, - QUANT_MAT_DEFAULT, -}; - -static const uint8_t prores_quant_matrices[][64] = { - { // proxy - 4, 7, 9, 11, 13, 14, 15, 63, - 7, 7, 11, 12, 14, 15, 63, 63, - 9, 11, 13, 14, 15, 63, 63, 63, - 11, 11, 13, 14, 63, 63, 63, 63, - 11, 13, 14, 63, 63, 63, 63, 63, - 13, 14, 63, 63, 63, 63, 63, 63, - 13, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - }, - { // proxy chromas - 4, 7, 9, 11, 13, 14, 63, 63, - 7, 7, 11, 12, 14, 63, 63, 63, - 9, 11, 13, 14, 63, 63, 63, 63, - 11, 11, 13, 14, 63, 63, 63, 63, - 11, 13, 14, 63, 63, 63, 63, 63, - 13, 14, 63, 63, 63, 63, 63, 63, - 13, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63 - }, - { // LT - 4, 5, 6, 7, 9, 11, 13, 15, - 5, 5, 7, 8, 11, 13, 15, 17, - 6, 7, 9, 11, 13, 15, 15, 17, - 7, 7, 9, 11, 13, 15, 17, 19, - 7, 9, 11, 13, 14, 16, 19, 23, - 9, 11, 13, 14, 16, 19, 23, 29, - 9, 11, 13, 15, 17, 21, 28, 35, - 11, 13, 16, 17, 21, 28, 35, 41, - }, - { // standard - 4, 4, 5, 5, 6, 7, 7, 9, - 4, 4, 5, 6, 7, 7, 9, 9, - 5, 5, 6, 7, 7, 9, 9, 10, - 5, 5, 6, 7, 7, 9, 9, 10, - 5, 6, 7, 7, 8, 9, 10, 12, - 6, 7, 7, 8, 9, 10, 12, 15, - 6, 7, 7, 9, 10, 11, 14, 17, - 7, 7, 9, 10, 11, 14, 17, 21, - }, - { // high quality - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 5, - 4, 4, 4, 4, 4, 4, 5, 5, - 4, 4, 4, 4, 4, 5, 5, 6, - 4, 4, 4, 4, 5, 5, 6, 7, - 4, 4, 4, 4, 5, 6, 7, 7, - }, - { // XQ luma - 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, - 2, 2, 2, 2, 2, 2, 3, 3, - 2, 2, 2, 2, 2, 3, 3, 3, - 2, 2, 2, 2, 3, 3, 3, 4, - 2, 2, 2, 2, 3, 3, 4, 4, - }, - { // codec default - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - }, -}; - -#define NUM_MB_LIMITS 4 -static const int prores_mb_limits[NUM_MB_LIMITS] = { - 1620, // up to 720x576 - 2700, // up to 960x720 - 6075, // up to 1440x1080 - 9216, // up to 2048x1152 -}; - -static const struct prores_profile { - const char *full_name; - uint32_t tag; - int min_quant; - int max_quant; - int br_tab[NUM_MB_LIMITS]; - int quant; - int quant_chroma; -} prores_profile_info[6] = { - { - .full_name = "proxy", - .tag = MKTAG('a', 'p', 'c', 'o'), - .min_quant = 4, - .max_quant = 8, - .br_tab = { 300, 242, 220, 194 }, - .quant = QUANT_MAT_PROXY, - .quant_chroma = QUANT_MAT_PROXY_CHROMA, - }, - { - .full_name = "LT", - .tag = MKTAG('a', 'p', 'c', 's'), - .min_quant = 1, - .max_quant = 9, - .br_tab = { 720, 560, 490, 440 }, - .quant = QUANT_MAT_LT, - .quant_chroma = QUANT_MAT_LT, - }, - { - .full_name = "standard", - .tag = MKTAG('a', 'p', 'c', 'n'), - .min_quant = 1, - .max_quant = 6, - .br_tab = { 1050, 808, 710, 632 }, - .quant = QUANT_MAT_STANDARD, - .quant_chroma = QUANT_MAT_STANDARD, - }, - { - .full_name = "high quality", - .tag = MKTAG('a', 'p', 'c', 'h'), - .min_quant = 1, - .max_quant = 6, - .br_tab = { 1566, 1216, 1070, 950 }, - .quant = QUANT_MAT_HQ, - .quant_chroma = QUANT_MAT_HQ, - }, - { - .full_name = "4444", - .tag = MKTAG('a', 'p', '4', 'h'), - .min_quant = 1, - .max_quant = 6, - .br_tab = { 2350, 1828, 1600, 1425 }, - .quant = QUANT_MAT_HQ, - .quant_chroma = QUANT_MAT_HQ, - }, - { - .full_name = "4444XQ", - .tag = MKTAG('a', 'p', '4', 'x'), - .min_quant = 1, - .max_quant = 6, - .br_tab = { 3525, 2742, 2400, 2137 }, - .quant = QUANT_MAT_HQ, /* Fix me : use QUANT_MAT_XQ_LUMA */ - .quant_chroma = QUANT_MAT_HQ, - } -}; +#include "proresenc_kostya_common.h" #define TRELLIS_WIDTH 16 #define SCORE_LIMIT INT_MAX / 2 @@ -217,8 +45,6 @@ struct TrellisNode { int score; }; -#define MAX_STORED_Q 16 - typedef struct ProresThreadData { DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE]; DECLARE_ALIGNED(16, uint16_t, emu_buf)[16 * 16]; @@ -227,49 +53,6 @@ typedef struct ProresThreadData { struct TrellisNode *nodes; } ProresThreadData; -typedef struct ProresContext { - AVClass *class; - DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE]; - DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16]; - int16_t quants[MAX_STORED_Q][64]; - int16_t quants_chroma[MAX_STORED_Q][64]; - int16_t custom_q[64]; - int16_t custom_chroma_q[64]; - const uint8_t *quant_mat; - const uint8_t *quant_chroma_mat; - const uint8_t *scantable; - - void (*fdct)(FDCTDSPContext *fdsp, const uint16_t *src, - ptrdiff_t linesize, int16_t *block); - FDCTDSPContext fdsp; - - const AVFrame *pic; - int mb_width, mb_height; - int mbs_per_slice; - int num_chroma_blocks, chroma_factor; - int slices_width; - int slices_per_picture; - int pictures_per_frame; // 1 for progressive, 2 for interlaced - int cur_picture_idx; - int num_planes; - int bits_per_mb; - int force_quant; - int alpha_bits; - int warn; - - char *vendor; - int quant_sel; - - int frame_size_upper_bound; - - int profile; - const struct prores_profile *profile_info; - - int *slice_q; - - ProresThreadData *tdata; -} ProresContext; - static void get_slice_data(ProresContext *ctx, const uint16_t *src, ptrdiff_t linesize, int x, int y, int w, int h, int16_t *blocks, uint16_t *emu_buf, @@ -437,7 +220,6 @@ static void encode_acs(PutBitContext *pb, int16_t *blocks, int prev_level = 2; int run = 0, level; int max_coeffs, abs_level; - max_coeffs = blocks_per_slice << 6; for (i = 1; i < 64; i++) { @@ -685,7 +467,6 @@ static int estimate_acs(int *error, int16_t *blocks, int blocks_per_slice, bits += estimate_vlc(ff_prores_run_to_cb[prev_run], run); bits += estimate_vlc(ff_prores_level_to_cb[prev_level], abs_level - 1) + 1; - prev_run = FFMIN(run, 15); prev_level = FFMIN(abs_level, 9); run = 0; @@ -905,7 +686,6 @@ static int find_slice_quant(AVCodecContext *avctx, for (q = min_quant; q < max_quant + 2; q++) { cur = trellis_node + q; - bits = td->nodes[prev].bits + slice_bits[q]; error = slice_score[q]; if (bits > bits_limit) @@ -970,7 +750,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, PutBitContext pb; int x, y, i, mb, q = 0; int sizes[4] = { 0 }; - int slice_hdr_size = 2 + 2 * (ctx->num_planes - 1); + int slice_hdr_size = 2 * ctx->num_planes; int frame_size, picture_size, slice_size; int pkt_size, ret; int max_slice_size = (ctx->frame_size_upper_bound - 200) / (ctx->pictures_per_frame * ctx->slices_per_picture + 1); @@ -1033,7 +813,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, // slices if (!ctx->force_quant) { - ret = avctx->execute2(avctx, find_quant_thread, (void*)pic, NULL, + ret = avctx->execute2(avctx, find_quant_thread, NULL, NULL, ctx->mb_height); if (ret) return ret; @@ -1076,7 +856,6 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, return ret; pkt_size += delta; - // restore pointers orig_buf = pkt->data + (orig_buf - start); buf = pkt->data + (buf - start); picture_size_pos = pkt->data + (picture_size_pos - start); @@ -1149,105 +928,18 @@ static void prores_fdct(FDCTDSPContext *fdsp, const uint16_t *src, static av_cold int encode_init(AVCodecContext *avctx) { ProresContext *ctx = avctx->priv_data; - int mps; - int i, j; - int min_quant, max_quant; - int interlaced = !!(avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT); + int err = 0, i, j, min_quant, max_quant; - avctx->bits_per_raw_sample = 10; + err = ff_prores_kostya_encode_init(avctx, ctx, avctx->pix_fmt); + if (err < 0) + return err; ctx->fdct = prores_fdct; - ctx->scantable = interlaced ? ff_prores_interlaced_scan - : ff_prores_progressive_scan; ff_fdctdsp_init(&ctx->fdsp, avctx); - mps = ctx->mbs_per_slice; - if (mps & (mps - 1)) { - av_log(avctx, AV_LOG_ERROR, - "there should be an integer power of two MBs per slice\n"); - return AVERROR(EINVAL); - } - if (ctx->profile == PRORES_PROFILE_AUTO) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); - ctx->profile = (desc->flags & AV_PIX_FMT_FLAG_ALPHA || - !(desc->log2_chroma_w + desc->log2_chroma_h)) - ? PRORES_PROFILE_4444 : PRORES_PROFILE_HQ; - av_log(avctx, AV_LOG_INFO, "Autoselected %s. It can be overridden " - "through -profile option.\n", ctx->profile == PRORES_PROFILE_4444 - ? "4:4:4:4 profile because of the used input colorspace" - : "HQ profile to keep best quality"); - } - if (av_pix_fmt_desc_get(avctx->pix_fmt)->flags & AV_PIX_FMT_FLAG_ALPHA) { - if (ctx->profile != PRORES_PROFILE_4444 && - ctx->profile != PRORES_PROFILE_4444XQ) { - // force alpha and warn - av_log(avctx, AV_LOG_WARNING, "Profile selected will not " - "encode alpha. Override with -profile if needed.\n"); - ctx->alpha_bits = 0; - } - if (ctx->alpha_bits & 7) { - av_log(avctx, AV_LOG_ERROR, "alpha bits should be 0, 8 or 16\n"); - return AVERROR(EINVAL); - } - avctx->bits_per_coded_sample = 32; - } else { - ctx->alpha_bits = 0; - } - - ctx->chroma_factor = avctx->pix_fmt == AV_PIX_FMT_YUV422P10 - ? CFACTOR_Y422 - : CFACTOR_Y444; - ctx->profile_info = prores_profile_info + ctx->profile; - ctx->num_planes = 3 + !!ctx->alpha_bits; - - ctx->mb_width = FFALIGN(avctx->width, 16) >> 4; - - if (interlaced) - ctx->mb_height = FFALIGN(avctx->height, 32) >> 5; - else - ctx->mb_height = FFALIGN(avctx->height, 16) >> 4; - - ctx->slices_width = ctx->mb_width / mps; - ctx->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps); - ctx->slices_per_picture = ctx->mb_height * ctx->slices_width; - ctx->pictures_per_frame = 1 + interlaced; - - if (ctx->quant_sel == -1) { - ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant]; - ctx->quant_chroma_mat = prores_quant_matrices[ctx->profile_info->quant_chroma]; - } else { - ctx->quant_mat = prores_quant_matrices[ctx->quant_sel]; - ctx->quant_chroma_mat = prores_quant_matrices[ctx->quant_sel]; - } - - if (strlen(ctx->vendor) != 4) { - av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n"); - return AVERROR_INVALIDDATA; - } - - ctx->force_quant = avctx->global_quality / FF_QP2LAMBDA; if (!ctx->force_quant) { - if (!ctx->bits_per_mb) { - for (i = 0; i < NUM_MB_LIMITS - 1; i++) - if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height * - ctx->pictures_per_frame) - break; - ctx->bits_per_mb = ctx->profile_info->br_tab[i]; - if (ctx->alpha_bits) - ctx->bits_per_mb *= 20; - } else if (ctx->bits_per_mb < 128) { - av_log(avctx, AV_LOG_ERROR, "too few bits per MB, please set at least 128\n"); - return AVERROR_INVALIDDATA; - } - min_quant = ctx->profile_info->min_quant; max_quant = ctx->profile_info->max_quant; - for (i = min_quant; i < MAX_STORED_Q; i++) { - for (j = 0; j < 64; j++) { - ctx->quants[i][j] = ctx->quant_mat[j] * i; - ctx->quants_chroma[i][j] = ctx->quant_chroma_mat[j] * i; - } - } ctx->slice_q = av_malloc_array(ctx->slices_per_picture, sizeof(*ctx->slice_q)); if (!ctx->slice_q) @@ -1269,51 +961,8 @@ static av_cold int encode_init(AVCodecContext *avctx) ctx->tdata[j].nodes[i].score = 0; } } - } else { - int ls = 0; - int ls_chroma = 0; - - if (ctx->force_quant > 64) { - av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is 64\n"); - return AVERROR_INVALIDDATA; - } - - for (j = 0; j < 64; j++) { - ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant; - ctx->quants_chroma[0][j] = ctx->quant_chroma_mat[j] * ctx->force_quant; - ls += av_log2((1 << 11) / ctx->quants[0][j]) * 2 + 1; - ls_chroma += av_log2((1 << 11) / ctx->quants_chroma[0][j]) * 2 + 1; - } - - ctx->bits_per_mb = ls * 4 + ls_chroma * 4; - if (ctx->chroma_factor == CFACTOR_Y444) - ctx->bits_per_mb += ls_chroma * 4; } - ctx->frame_size_upper_bound = (ctx->pictures_per_frame * - ctx->slices_per_picture + 1) * - (2 + 2 * ctx->num_planes + - (mps * ctx->bits_per_mb) / 8) - + 200; - - if (ctx->alpha_bits) { - // The alpha plane is run-coded and might exceed the bit budget. - ctx->frame_size_upper_bound += (ctx->pictures_per_frame * - ctx->slices_per_picture + 1) * - /* num pixels per slice */ (ctx->mbs_per_slice * 256 * - /* bits per pixel */ (1 + ctx->alpha_bits + 1) + 7 >> 3); - } - - avctx->codec_tag = ctx->profile_info->tag; - avctx->profile = ctx->profile; - - av_log(avctx, AV_LOG_DEBUG, - "profile %d, %d slices, interlacing: %s, %d bits per MB\n", - ctx->profile, ctx->slices_per_picture * ctx->pictures_per_frame, - interlaced ? "yes" : "no", ctx->bits_per_mb); - av_log(avctx, AV_LOG_DEBUG, "frame size upper bound: %d\n", - ctx->frame_size_upper_bound); - return 0; } @@ -1381,10 +1030,7 @@ const FFCodec ff_prores_ks_encoder = { FF_CODEC_ENCODE_CB(encode_frame), .p.capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, - AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUVA444P10), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &proresenc_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), diff --git a/libavcodec/proresenc_kostya_common.c b/libavcodec/proresenc_kostya_common.c new file mode 100644 index 000000000..558637d14 --- /dev/null +++ b/libavcodec/proresenc_kostya_common.c @@ -0,0 +1,364 @@ +/* + * Apple ProRes encoder + * + * Copyright (c) 2011 Anatoliy Wasserman + * Copyright (c) 2012 Konstantin Shishkov + * + * 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 "avcodec.h" +#include "bytestream.h" +#include "proresdata.h" +#include +#include "proresenc_kostya_common.h" + +static const uint8_t prores_quant_matrices[][64] = { + { // proxy + 4, 7, 9, 11, 13, 14, 15, 63, + 7, 7, 11, 12, 14, 15, 63, 63, + 9, 11, 13, 14, 15, 63, 63, 63, + 11, 11, 13, 14, 63, 63, 63, 63, + 11, 13, 14, 63, 63, 63, 63, 63, + 13, 14, 63, 63, 63, 63, 63, 63, + 13, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + }, + { // proxy chromas + 4, 7, 9, 11, 13, 14, 63, 63, + 7, 7, 11, 12, 14, 63, 63, 63, + 9, 11, 13, 14, 63, 63, 63, 63, + 11, 11, 13, 14, 63, 63, 63, 63, + 11, 13, 14, 63, 63, 63, 63, 63, + 13, 14, 63, 63, 63, 63, 63, 63, + 13, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63 + }, + { // LT + 4, 5, 6, 7, 9, 11, 13, 15, + 5, 5, 7, 8, 11, 13, 15, 17, + 6, 7, 9, 11, 13, 15, 15, 17, + 7, 7, 9, 11, 13, 15, 17, 19, + 7, 9, 11, 13, 14, 16, 19, 23, + 9, 11, 13, 14, 16, 19, 23, 29, + 9, 11, 13, 15, 17, 21, 28, 35, + 11, 13, 16, 17, 21, 28, 35, 41, + }, + { // standard + 4, 4, 5, 5, 6, 7, 7, 9, + 4, 4, 5, 6, 7, 7, 9, 9, + 5, 5, 6, 7, 7, 9, 9, 10, + 5, 5, 6, 7, 7, 9, 9, 10, + 5, 6, 7, 7, 8, 9, 10, 12, + 6, 7, 7, 8, 9, 10, 12, 15, + 6, 7, 7, 9, 10, 11, 14, 17, + 7, 7, 9, 10, 11, 14, 17, 21, + }, + { // high quality + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 5, + 4, 4, 4, 4, 4, 4, 5, 5, + 4, 4, 4, 4, 4, 5, 5, 6, + 4, 4, 4, 4, 5, 5, 6, 7, + 4, 4, 4, 4, 5, 6, 7, 7, + }, + { // XQ luma + 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, + 2, 2, 2, 2, 2, 2, 3, 3, + 2, 2, 2, 2, 2, 3, 3, 3, + 2, 2, 2, 2, 3, 3, 3, 4, + 2, 2, 2, 2, 3, 3, 4, 4, + }, + { // codec default + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + }, +}; + +static const int prores_mb_limits[NUM_MB_LIMITS] = { + 1620, // up to 720x576 + 2700, // up to 960x720 + 6075, // up to 1440x1080 + 9216, // up to 2048x1152 +}; + +static const prores_profile prores_profile_info[6] = { + { + .full_name = "proxy", + .tag = MKTAG('a', 'p', 'c', 'o'), + .min_quant = 4, + .max_quant = 8, + .br_tab = { 300, 242, 220, 194 }, + .quant = QUANT_MAT_PROXY, + .quant_chroma = QUANT_MAT_PROXY_CHROMA, + }, + { + .full_name = "LT", + .tag = MKTAG('a', 'p', 'c', 's'), + .min_quant = 1, + .max_quant = 9, + .br_tab = { 720, 560, 490, 440 }, + .quant = QUANT_MAT_LT, + .quant_chroma = QUANT_MAT_LT, + }, + { + .full_name = "standard", + .tag = MKTAG('a', 'p', 'c', 'n'), + .min_quant = 1, + .max_quant = 6, + .br_tab = { 1050, 808, 710, 632 }, + .quant = QUANT_MAT_STANDARD, + .quant_chroma = QUANT_MAT_STANDARD, + }, + { + .full_name = "high quality", + .tag = MKTAG('a', 'p', 'c', 'h'), + .min_quant = 1, + .max_quant = 6, + .br_tab = { 1566, 1216, 1070, 950 }, + .quant = QUANT_MAT_HQ, + .quant_chroma = QUANT_MAT_HQ, + }, + { + .full_name = "4444", + .tag = MKTAG('a', 'p', '4', 'h'), + .min_quant = 1, + .max_quant = 6, + .br_tab = { 2350, 1828, 1600, 1425 }, + .quant = QUANT_MAT_HQ, + .quant_chroma = QUANT_MAT_HQ, + }, + { + .full_name = "4444XQ", + .tag = MKTAG('a', 'p', '4', 'x'), + .min_quant = 1, + .max_quant = 6, + .br_tab = { 3525, 2742, 2400, 2137 }, + .quant = QUANT_MAT_HQ, /* Fix me : use QUANT_MAT_XQ_LUMA */ + .quant_chroma = QUANT_MAT_HQ, + } +}; + +av_cold int ff_prores_kostya_encode_init(AVCodecContext *avctx, ProresContext *ctx, + enum AVPixelFormat pix_fmt) +{ + int mps, i, j, min_quant; + int interlaced = !!(avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT); + + avctx->bits_per_raw_sample = 10; + + ctx->scantable = interlaced ? ff_prores_interlaced_scan + : ff_prores_progressive_scan; + + mps = ctx->mbs_per_slice; + if (mps & (mps - 1)) { + av_log(avctx, AV_LOG_ERROR, + "there should be an integer power of two MBs per slice\n"); + return AVERROR(EINVAL); + } + if (ctx->profile == PRORES_PROFILE_AUTO) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + ctx->profile = (desc->flags & AV_PIX_FMT_FLAG_ALPHA || + !(desc->log2_chroma_w + desc->log2_chroma_h)) + ? PRORES_PROFILE_4444 : PRORES_PROFILE_HQ; + av_log(avctx, AV_LOG_INFO, "Autoselected %s. It can be overridden " + "through -profile option.\n", ctx->profile == PRORES_PROFILE_4444 + ? "4:4:4:4 profile because of the used input colorspace" + : "HQ profile to keep best quality"); + } + if (av_pix_fmt_desc_get(pix_fmt)->flags & AV_PIX_FMT_FLAG_ALPHA) { + if (ctx->profile != PRORES_PROFILE_4444 && + ctx->profile != PRORES_PROFILE_4444XQ) { + // force alpha and warn + av_log(avctx, AV_LOG_WARNING, "Profile selected will not " + "encode alpha. Override with -profile if needed.\n"); + ctx->alpha_bits = 0; + } + if (ctx->alpha_bits & 7) { + av_log(avctx, AV_LOG_ERROR, "alpha bits should be 0, 8 or 16\n"); + return AVERROR(EINVAL); + } + avctx->bits_per_coded_sample = 32; + } else { + ctx->alpha_bits = 0; + } + + ctx->chroma_factor = pix_fmt == AV_PIX_FMT_YUV422P10 + ? CFACTOR_Y422 + : CFACTOR_Y444; + ctx->profile_info = prores_profile_info + ctx->profile; + ctx->num_planes = 3 + !!ctx->alpha_bits; + + ctx->mb_width = FFALIGN(avctx->width, 16) >> 4; + + if (interlaced) + ctx->mb_height = FFALIGN(avctx->height, 32) >> 5; + else + ctx->mb_height = FFALIGN(avctx->height, 16) >> 4; + + ctx->slices_width = ctx->mb_width / mps; + ctx->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps); + ctx->slices_per_picture = ctx->mb_height * ctx->slices_width; + ctx->pictures_per_frame = 1 + interlaced; + + if (ctx->quant_sel == -1) { + ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant]; + ctx->quant_chroma_mat = prores_quant_matrices[ctx->profile_info->quant_chroma]; + } else { + ctx->quant_mat = prores_quant_matrices[ctx->quant_sel]; + ctx->quant_chroma_mat = prores_quant_matrices[ctx->quant_sel]; + } + + if (strlen(ctx->vendor) != 4) { + av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n"); + return AVERROR_INVALIDDATA; + } + + ctx->force_quant = avctx->global_quality / FF_QP2LAMBDA; + if (!ctx->force_quant) { + if (!ctx->bits_per_mb) { + for (i = 0; i < NUM_MB_LIMITS - 1; i++) + if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height * + ctx->pictures_per_frame) + break; + ctx->bits_per_mb = ctx->profile_info->br_tab[i]; + if (ctx->alpha_bits) + ctx->bits_per_mb *= 20; + } else if (ctx->bits_per_mb < 128) { + av_log(avctx, AV_LOG_ERROR, "too few bits per MB, please set at least 128\n"); + return AVERROR_INVALIDDATA; + } + + min_quant = ctx->profile_info->min_quant; + for (i = min_quant; i < MAX_STORED_Q; i++) { + for (j = 0; j < 64; j++) { + ctx->quants[i][j] = ctx->quant_mat[j] * i; + ctx->quants_chroma[i][j] = ctx->quant_chroma_mat[j] * i; + } + } + } else { + int ls = 0; + int ls_chroma = 0; + + if (ctx->force_quant > 64) { + av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is 64\n"); + return AVERROR_INVALIDDATA; + } + + for (j = 0; j < 64; j++) { + ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant; + ctx->quants_chroma[0][j] = ctx->quant_chroma_mat[j] * ctx->force_quant; + ls += av_log2((1 << 11) / ctx->quants[0][j]) * 2 + 1; + ls_chroma += av_log2((1 << 11) / ctx->quants_chroma[0][j]) * 2 + 1; + } + + ctx->bits_per_mb = ls * 4 + ls_chroma * 4; + if (ctx->chroma_factor == CFACTOR_Y444) + ctx->bits_per_mb += ls_chroma * 4; + } + + ctx->frame_size_upper_bound = (ctx->pictures_per_frame * + ctx->slices_per_picture + 1) * + (2 + 2 * ctx->num_planes + + (mps * ctx->bits_per_mb) / 8) + + 200; + + if (ctx->alpha_bits) { + // The alpha plane is run-coded and might exceed the bit budget. + ctx->frame_size_upper_bound += (ctx->pictures_per_frame * + ctx->slices_per_picture + 1) * + /* num pixels per slice */ (ctx->mbs_per_slice * 256 * + /* bits per pixel */ (1 + ctx->alpha_bits + 1) + 7 >> 3); + } + + avctx->codec_tag = ctx->profile_info->tag; + avctx->profile = ctx->profile; + + av_log(avctx, AV_LOG_DEBUG, + "profile %d, %d slices, interlacing: %s, %d bits per MB\n", + ctx->profile, ctx->slices_per_picture * ctx->pictures_per_frame, + interlaced ? "yes" : "no", ctx->bits_per_mb); + av_log(avctx, AV_LOG_DEBUG, "frame size upper bound: %d\n", + ctx->frame_size_upper_bound); + + return 0; +} + +uint8_t *ff_prores_kostya_write_frame_header(AVCodecContext *avctx, ProresContext *ctx, + uint8_t **orig_buf, int flags, + enum AVColorPrimaries color_primaries, + enum AVColorTransferCharacteristic color_trc, + enum AVColorSpace colorspace) +{ + uint8_t *buf, *tmp; + uint8_t frame_flags; + + // frame atom + *orig_buf += 4; // frame size + bytestream_put_be32 (orig_buf, FRAME_ID); // frame container ID + buf = *orig_buf; + + // frame header + tmp = buf; + buf += 2; // frame header size will be stored here + bytestream_put_be16 (&buf, ctx->chroma_factor != CFACTOR_Y422 || ctx->alpha_bits ? 1 : 0); + bytestream_put_buffer(&buf, (uint8_t*)ctx->vendor, 4); + bytestream_put_be16 (&buf, avctx->width); + bytestream_put_be16 (&buf, avctx->height); + + frame_flags = ctx->chroma_factor << 6; + if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) + frame_flags |= (flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? 0x04 : 0x08; + bytestream_put_byte (&buf, frame_flags); + + bytestream_put_byte (&buf, 0); // reserved + bytestream_put_byte (&buf, color_primaries); + bytestream_put_byte (&buf, color_trc); + bytestream_put_byte (&buf, colorspace); + bytestream_put_byte (&buf, ctx->alpha_bits >> 3); + bytestream_put_byte (&buf, 0); // reserved + if (ctx->quant_sel != QUANT_MAT_DEFAULT) { + bytestream_put_byte (&buf, 0x03); // matrix flags - both matrices are present + bytestream_put_buffer(&buf, ctx->quant_mat, 64); // luma quantisation matrix + bytestream_put_buffer(&buf, ctx->quant_chroma_mat, 64); // chroma quantisation matrix + } else { + bytestream_put_byte (&buf, 0x00); // matrix flags - default matrices are used + } + bytestream_put_be16 (&tmp, buf - *orig_buf); // write back frame header size + return buf; +} + +uint8_t *ff_prores_kostya_write_picture_header(ProresContext *ctx, uint8_t *buf) +{ + bytestream_put_byte (&buf, 0x40); // picture header size (in bits) + buf += 4; // picture data size will be stored here + bytestream_put_be16 (&buf, ctx->slices_per_picture); + bytestream_put_byte (&buf, av_log2(ctx->mbs_per_slice) << 4); // slice width and height in MBs + return buf; +} diff --git a/libavcodec/proresenc_kostya_common.h b/libavcodec/proresenc_kostya_common.h new file mode 100644 index 000000000..ed5355db0 --- /dev/null +++ b/libavcodec/proresenc_kostya_common.h @@ -0,0 +1,137 @@ +/* + * Apple ProRes encoder + * + * Copyright (c) 2011 Anatoliy Wasserman + * Copyright (c) 2012 Konstantin Shishkov + * + * 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_PRORESENC_KOSTYA_COMMON_H +#define AVCODEC_PRORESENC_KOSTYA_COMMON_H + +#include + +#include "libavutil/attributes_internal.h" +#include "libavutil/log.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixfmt.h" +#include "fdctdsp.h" + +FF_VISIBILITY_PUSH_HIDDEN + +#define CFACTOR_Y422 2 +#define CFACTOR_Y444 3 + +#define MAX_MBS_PER_SLICE 8 + +#define MAX_PLANES 4 + +#define NUM_MB_LIMITS 4 + +#define MAX_STORED_Q 16 + +enum { + PRORES_PROFILE_AUTO = -1, + PRORES_PROFILE_PROXY = 0, + PRORES_PROFILE_LT, + PRORES_PROFILE_STANDARD, + PRORES_PROFILE_HQ, + PRORES_PROFILE_4444, + PRORES_PROFILE_4444XQ, +}; + +enum { + QUANT_MAT_PROXY = 0, + QUANT_MAT_PROXY_CHROMA, + QUANT_MAT_LT, + QUANT_MAT_STANDARD, + QUANT_MAT_HQ, + QUANT_MAT_XQ_LUMA, + QUANT_MAT_DEFAULT, +}; + +struct AVCodecContext; +struct AVFrame; + +typedef struct prores_profile { + const char *full_name; + uint32_t tag; + int min_quant; + int max_quant; + int br_tab[NUM_MB_LIMITS]; + int quant; + int quant_chroma; +} prores_profile; + +typedef struct ProresContext { + AVClass *class; + DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE]; + DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16]; + int16_t quants[MAX_STORED_Q][64]; + int16_t quants_chroma[MAX_STORED_Q][64]; + int16_t custom_q[64]; + int16_t custom_chroma_q[64]; + const uint8_t *quant_mat; + const uint8_t *quant_chroma_mat; + const uint8_t *scantable; + + void (*fdct)(FDCTDSPContext *fdsp, const uint16_t *src, + ptrdiff_t linesize, int16_t *block); + FDCTDSPContext fdsp; + + const struct AVFrame *pic; + int mb_width, mb_height; + int mbs_per_slice; + int num_chroma_blocks, chroma_factor; + int slices_width; + int slices_per_picture; + int pictures_per_frame; // 1 for progressive, 2 for interlaced + int cur_picture_idx; + int num_planes; + int bits_per_mb; + int force_quant; + int alpha_bits; + int warn; + + char *vendor; + int quant_sel; + + int frame_size_upper_bound; + + int profile; + const struct prores_profile *profile_info; + + int *slice_q; + + struct ProresThreadData *tdata; +} ProresContext; + +av_cold int ff_prores_kostya_encode_init(struct AVCodecContext *avctx, ProresContext *ctx, + enum AVPixelFormat pixfmt); + +uint8_t *ff_prores_kostya_write_frame_header(struct AVCodecContext *avctx, ProresContext *ctx, + uint8_t **orig_buf, int flags, + enum AVColorPrimaries color_primaries, + enum AVColorTransferCharacteristic color_trc, + enum AVColorSpace colorspace); + +uint8_t *ff_prores_kostya_write_picture_header(ProresContext *ctx, uint8_t *buf); + +FF_VISIBILITY_POP_HIDDEN + +#endif // AVCODEC_PRORESENC_KOSTYA_COMMON_H diff --git a/libavcodec/proresenc_kostya_vulkan.c b/libavcodec/proresenc_kostya_vulkan.c new file mode 100644 index 000000000..11b11675b --- /dev/null +++ b/libavcodec/proresenc_kostya_vulkan.c @@ -0,0 +1,1015 @@ +/* + * Apple ProRes encoder + * + * Copyright (c) 2011 Anatoliy Wasserman + * Copyright (c) 2012 Konstantin Shishkov + * + * 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/buffer.h" +#include "libavutil/macros.h" +#include "libavutil/mem.h" +#include "libavutil/mem_internal.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/vulkan_spirv.h" +#include "libavutil/hwcontext_vulkan.h" +#include "libavutil/vulkan_loader.h" +#include "libavutil/vulkan.h" +#include "avcodec.h" +#include "codec.h" +#include "codec_internal.h" +#include "encode.h" +#include "packet.h" +#include "put_bits.h" +#include "profiles.h" +#include "bytestream.h" +#include "proresdata.h" +#include "proresenc_kostya_common.h" +#include "hwconfig.h" + +#define DCTSIZE 8 + +typedef struct ProresDataTables { + int16_t qmat[128][64]; + int16_t qmat_chroma[128][64]; +} ProresDataTables; + +typedef struct SliceDataInfo { + int plane; + int line_add; + int bits_per_sample; +} SliceDataInfo; + +typedef struct EncodeSliceInfo { + VkDeviceAddress bytestream; + VkDeviceAddress seek_table; +} EncodeSliceInfo; + +typedef struct SliceData { + uint32_t mbs_per_slice; + int16_t rows[MAX_PLANES * MAX_MBS_PER_SLICE * 256]; +} SliceData; + +typedef struct SliceScore { + int bits[MAX_STORED_Q][4]; + int error[MAX_STORED_Q][4]; + int total_bits[MAX_STORED_Q]; + int total_error[MAX_STORED_Q]; + int overquant; + int buf_start; + int quant; +} SliceScore; + +typedef struct VulkanEncodeProresFrameData { + /* Intermediate buffers */ + AVBufferRef *out_data_ref[2]; + AVBufferRef *slice_data_ref[2]; + AVBufferRef *slice_score_ref[2]; + AVBufferRef *frame_size_ref[2]; + + /* Copied from the source */ + int64_t pts; + int64_t duration; + void *frame_opaque; + AVBufferRef *frame_opaque_ref; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace colorspace; + enum AVColorPrimaries color_primaries; + int key_frame; + int flags; +} VulkanEncodeProresFrameData; + +typedef struct ProresVulkanContext { + ProresContext ctx; + + /* Vulkan state */ + FFVulkanContext vkctx; + AVVulkanDeviceQueueFamily *qf; + FFVkExecPool e; + AVVulkanDeviceQueueFamily *transfer_qf; + FFVkExecPool transfer_exec_pool; + AVBufferPool *pkt_buf_pool; + AVBufferPool *slice_data_buf_pool; + AVBufferPool *slice_score_buf_pool; + AVBufferPool *frame_size_buf_pool; + + FFVulkanShader alpha_data_shd; + FFVulkanShader slice_data_shd[2]; + FFVulkanShader estimate_slice_shd; + FFVulkanShader encode_slice_shd; + FFVulkanShader trellis_node_shd; + FFVkBuffer prores_data_tables_buf; + + int *slice_quants; + SliceScore *slice_scores; + ProresDataTables *tables; + + int in_flight; + int async_depth; + AVFrame *frame; + VulkanEncodeProresFrameData *exec_ctx_info; +} ProresVulkanContext; + +extern const unsigned char ff_prores_ks_alpha_data_comp_spv_data[]; +extern const unsigned int ff_prores_ks_alpha_data_comp_spv_len; + +extern const unsigned char ff_prores_ks_slice_data_comp_spv_data[]; +extern const unsigned int ff_prores_ks_slice_data_comp_spv_len; + +extern const unsigned char ff_prores_ks_estimate_slice_comp_spv_data[]; +extern const unsigned int ff_prores_ks_estimate_slice_comp_spv_len; + +extern const unsigned char ff_prores_ks_trellis_node_comp_spv_data[]; +extern const unsigned int ff_prores_ks_trellis_node_comp_spv_len; + +extern const unsigned char ff_prores_ks_encode_slice_comp_spv_data[]; +extern const unsigned int ff_prores_ks_encode_slice_comp_spv_len; + +static int init_slice_data_pipeline(ProresVulkanContext *pv, FFVulkanShader *shd, int blocks_per_mb) +{ + int err = 0; + FFVulkanContext *vkctx = &pv->vkctx; + FFVulkanDescriptorSetBinding *desc; + + SPEC_LIST_CREATE(sl, 5, 5 * sizeof(uint32_t)) + SPEC_LIST_ADD(sl, 0, 32, pv->ctx.mbs_per_slice); + SPEC_LIST_ADD(sl, 1, 32, blocks_per_mb); + SPEC_LIST_ADD(sl, 2, 32, pv->ctx.mb_width); + SPEC_LIST_ADD(sl, 3, 32, pv->ctx.pictures_per_frame); + SPEC_LIST_ADD(sl, 16, 32, blocks_per_mb * pv->ctx.mbs_per_slice); /* nb_blocks */ + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { DCTSIZE, blocks_per_mb, pv->ctx.mbs_per_slice }, 0); + + desc = (FFVulkanDescriptorSetBinding []) { + { + .name = "SliceBuffer", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { + .name = "planes", + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .elems = av_pix_fmt_count_planes(vkctx->frames->sw_format), + }, + }; + RET(ff_vk_shader_add_descriptor_set(vkctx, shd, desc, 2, 0, 0)); + + ff_vk_shader_add_push_const(shd, 0, sizeof(SliceDataInfo), VK_SHADER_STAGE_COMPUTE_BIT); + + RET(ff_vk_shader_link(vkctx, shd, + ff_prores_ks_slice_data_comp_spv_data, + ff_prores_ks_slice_data_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(vkctx, &pv->e, shd)); + +fail: + return err; +} + +static int init_alpha_data_pipeline(ProresVulkanContext *pv, FFVulkanShader* shd) +{ + int err = 0; + FFVulkanContext *vkctx = &pv->vkctx; + FFVulkanDescriptorSetBinding *desc; + + SPEC_LIST_CREATE(sl, 4, 4 * sizeof(uint32_t)) + SPEC_LIST_ADD(sl, 0, 32, pv->ctx.alpha_bits); + SPEC_LIST_ADD(sl, 1, 32, pv->ctx.slices_width); + SPEC_LIST_ADD(sl, 2, 32, pv->ctx.mb_width); + SPEC_LIST_ADD(sl, 3, 32, pv->ctx.mbs_per_slice); + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { 16, 16, 1 }, 0); + + desc = (FFVulkanDescriptorSetBinding []) { + { + .name = "SliceBuffer", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { + .name = "plane", + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + RET(ff_vk_shader_add_descriptor_set(vkctx, shd, desc, 2, 0, 0)); + + RET(ff_vk_shader_link(vkctx, shd, + ff_prores_ks_alpha_data_comp_spv_data, + ff_prores_ks_alpha_data_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(vkctx, &pv->e, shd)); + +fail: + return err; +} + +static int init_estimate_slice_pipeline(ProresVulkanContext *pv, FFVulkanShader* shd) +{ + int err = 0; + FFVulkanContext *vkctx = &pv->vkctx; + FFVulkanDescriptorSetBinding *desc; + int subgroup_size = vkctx->subgroup_props.maxSubgroupSize; + int dim_x = pv->ctx.alpha_bits ? subgroup_size : (subgroup_size / 3) * 3; + + SPEC_LIST_CREATE(sl, 8, 8 * sizeof(uint32_t)) + SPEC_LIST_ADD(sl, 0, 32, pv->ctx.mbs_per_slice); + SPEC_LIST_ADD(sl, 1, 32, pv->ctx.chroma_factor); + SPEC_LIST_ADD(sl, 2, 32, pv->ctx.alpha_bits); + SPEC_LIST_ADD(sl, 3, 32, pv->ctx.num_planes); + SPEC_LIST_ADD(sl, 4, 32, pv->ctx.slices_per_picture); + SPEC_LIST_ADD(sl, 5, 32, pv->ctx.force_quant ? 0 : pv->ctx.profile_info->min_quant); + SPEC_LIST_ADD(sl, 6, 32, pv->ctx.force_quant ? 0 : pv->ctx.profile_info->max_quant); + SPEC_LIST_ADD(sl, 7, 32, pv->ctx.bits_per_mb); + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { dim_x, 1, 1 }, 0); + + desc = (FFVulkanDescriptorSetBinding []) { + { + .name = "SliceBuffer", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { + .name = "SliceScores", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { + .name = "ProresDataTables", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + RET(ff_vk_shader_add_descriptor_set(vkctx, shd, desc, 3, 0, 0)); + + RET(ff_vk_shader_link(vkctx, shd, + ff_prores_ks_estimate_slice_comp_spv_data, + ff_prores_ks_estimate_slice_comp_spv_len, "main")); + RET(ff_vk_shader_register_exec(vkctx, &pv->e, shd)); + +fail: + return err; +} + +static int init_trellis_node_pipeline(ProresVulkanContext *pv, FFVulkanShader* shd) +{ + int err = 0; + FFVulkanContext *vkctx = &pv->vkctx; + FFVulkanDescriptorSetBinding *desc; + int subgroup_size = vkctx->subgroup_props.maxSubgroupSize; + int num_subgroups = FFALIGN(pv->ctx.mb_height, subgroup_size) / subgroup_size; + + SPEC_LIST_CREATE(sl, 8, 8 * sizeof(uint32_t)) + SPEC_LIST_ADD(sl, 0, 32, pv->ctx.slices_width); + SPEC_LIST_ADD(sl, 1, 32, num_subgroups); + SPEC_LIST_ADD(sl, 2, 32, pv->ctx.num_planes); + SPEC_LIST_ADD(sl, 3, 32, pv->ctx.force_quant); + SPEC_LIST_ADD(sl, 4, 32, pv->ctx.profile_info->min_quant); + SPEC_LIST_ADD(sl, 5, 32, pv->ctx.profile_info->max_quant); + SPEC_LIST_ADD(sl, 6, 32, pv->ctx.mbs_per_slice); + SPEC_LIST_ADD(sl, 7, 32, pv->ctx.bits_per_mb); + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { pv->ctx.mb_height, 1, 1 }, 0); + + desc = (FFVulkanDescriptorSetBinding []) { + { + .name = "FrameSize", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { + .name = "SliceScores", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + RET(ff_vk_shader_add_descriptor_set(vkctx, shd, desc, 2, 0, 0)); + + RET(ff_vk_shader_link(vkctx, shd, + ff_prores_ks_trellis_node_comp_spv_data, + ff_prores_ks_trellis_node_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(vkctx, &pv->e, shd)); + +fail: + return err; +} + +static int init_encode_slice_pipeline(ProresVulkanContext *pv, FFVulkanShader* shd) +{ + int err = 0; + FFVulkanContext *vkctx = &pv->vkctx; + FFVulkanDescriptorSetBinding *desc; + + SPEC_LIST_CREATE(sl, 6, 6 * sizeof(uint32_t)) + SPEC_LIST_ADD(sl, 0, 32, pv->ctx.mbs_per_slice); + SPEC_LIST_ADD(sl, 1, 32, pv->ctx.chroma_factor); + SPEC_LIST_ADD(sl, 2, 32, pv->ctx.alpha_bits); + SPEC_LIST_ADD(sl, 3, 32, pv->ctx.num_planes); + SPEC_LIST_ADD(sl, 4, 32, pv->ctx.slices_per_picture); + SPEC_LIST_ADD(sl, 5, 32, pv->ctx.force_quant ? pv->ctx.force_quant : pv->ctx.profile_info->max_quant); + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { 64, 1, 1 }, 0); + + desc = (FFVulkanDescriptorSetBinding []) { + { + .name = "SliceBuffer", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { + .name = "SliceScores", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { + .name = "ProresDataTables", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + RET(ff_vk_shader_add_descriptor_set(vkctx, shd, desc, 3, 0, 0)); + + ff_vk_shader_add_push_const(shd, 0, sizeof(EncodeSliceInfo), VK_SHADER_STAGE_COMPUTE_BIT); + + RET(ff_vk_shader_link(vkctx, shd, + ff_prores_ks_encode_slice_comp_spv_data, + ff_prores_ks_encode_slice_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(vkctx, &pv->e, shd)); + +fail: + return err; +} + +static int vulkan_encode_prores_submit_frame(AVCodecContext *avctx, FFVkExecContext *exec, + AVFrame *frame, int picture_idx) +{ + ProresVulkanContext *pv = avctx->priv_data; + ProresContext *ctx = &pv->ctx; + VulkanEncodeProresFrameData *pd = exec->opaque; + FFVulkanContext *vkctx = &pv->vkctx; + FFVulkanFunctions *vk = &vkctx->vkfn; + int err = 0, nb_img_bar = 0, i, is_chroma; + int min_quant = ctx->profile_info->min_quant; + int max_quant = ctx->profile_info->max_quant; + int subgroup_size = vkctx->subgroup_props.maxSubgroupSize; + int estimate_dim_x = ctx->alpha_bits ? subgroup_size : (subgroup_size / 3) * 3; + int transfer_slices = vkctx->extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(vkctx->frames->sw_format); + VkImageView views[AV_NUM_DATA_POINTERS]; + VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS]; + FFVkBuffer *pkt_vk_buf, *slice_data_buf, *slice_score_buf, *frame_size_buf; + SliceDataInfo slice_data_info; + EncodeSliceInfo encode_info; + FFVulkanShader *shd; + + /* Start recording */ + ff_vk_exec_start(vkctx, exec); + + /* Get a pooled buffer for writing output data */ + RET(ff_vk_get_pooled_buffer(vkctx, &pv->pkt_buf_pool, &pd->out_data_ref[picture_idx], + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, NULL, + ctx->frame_size_upper_bound + FF_INPUT_BUFFER_MIN_SIZE, + transfer_slices ? VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT + : (VK_MEMORY_PROPERTY_HOST_CACHED_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))); + pkt_vk_buf = (FFVkBuffer*)pd->out_data_ref[picture_idx]->data; + ff_vk_exec_add_dep_buf(vkctx, exec, &pd->out_data_ref[picture_idx], 1, 1); + + /* Allocate buffer for writing slice data */ + RET(ff_vk_get_pooled_buffer(vkctx, &pv->slice_data_buf_pool, &pd->slice_data_ref[picture_idx], + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, NULL, + ctx->slices_per_picture * sizeof(SliceData), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); + slice_data_buf = (FFVkBuffer*)pd->slice_data_ref[picture_idx]->data; + ff_vk_exec_add_dep_buf(vkctx, exec, &pd->slice_data_ref[picture_idx], 1, 1); + + /* Allocate buffer for writing slice scores */ + RET(ff_vk_get_pooled_buffer(vkctx, &pv->slice_score_buf_pool, &pd->slice_score_ref[picture_idx], + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, NULL, + ctx->slices_per_picture * sizeof(SliceScore), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); + slice_score_buf = (FFVkBuffer*)pd->slice_score_ref[picture_idx]->data; + ff_vk_exec_add_dep_buf(vkctx, exec, &pd->slice_score_ref[picture_idx], 1, 1); + + /* Allocate buffer for writing frame size */ + RET(ff_vk_get_pooled_buffer(vkctx, &pv->frame_size_buf_pool, &pd->frame_size_ref[picture_idx], + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, NULL, + sizeof(int), + VK_MEMORY_PROPERTY_HOST_CACHED_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)); + frame_size_buf = (FFVkBuffer*)pd->frame_size_ref[picture_idx]->data; + ff_vk_exec_add_dep_buf(vkctx, exec, &pd->frame_size_ref[picture_idx], 1, 1); + + /* Generate barriers and image views for frame images. */ + RET(ff_vk_exec_add_dep_frame(vkctx, exec, frame, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + RET(ff_vk_create_imageviews(vkctx, exec, views, frame, FF_VK_REP_INT)); + ff_vk_frame_barrier(vkctx, exec, frame, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + /* Submit the image barriers. */ + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + + /* Apply FDCT on input image data for future passes */ + slice_data_info = (SliceDataInfo) { + .line_add = ctx->pictures_per_frame == 1 ? 0 : picture_idx ^ !(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST), + }; + for (i = 0; i < ctx->num_planes; i++) { + is_chroma = (i == 1 || i == 2); + shd = &pv->slice_data_shd[!is_chroma || ctx->chroma_factor == CFACTOR_Y444]; + if (i < 3) { + slice_data_info.plane = i; + slice_data_info.bits_per_sample = desc->comp[i].depth; + ff_vk_shader_update_desc_buffer(vkctx, exec, shd, 0, 0, 0, + slice_data_buf, 0, slice_data_buf->size, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_img_array(vkctx, exec, shd, frame, views, 0, 1, + VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE); + ff_vk_exec_bind_shader(vkctx, exec, shd); + ff_vk_shader_update_push_const(vkctx, exec, shd, VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(SliceDataInfo), &slice_data_info); + vk->CmdDispatch(exec->buf, ctx->slices_width, ctx->mb_height, 1); + } else { + ff_vk_shader_update_desc_buffer(vkctx, exec, &pv->alpha_data_shd, 0, 0, 0, + slice_data_buf, 0, slice_data_buf->size, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_img(vkctx, exec, &pv->alpha_data_shd, 0, 1, 0, views[3], + VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE); + ff_vk_exec_bind_shader(vkctx, exec, &pv->alpha_data_shd); + vk->CmdDispatch(exec->buf, ctx->mb_width, ctx->mb_height, 1); + } + } + + /* Wait for writes to slice buffer. */ + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pBufferMemoryBarriers = & (VkBufferMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .pNext = NULL, + .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = slice_data_buf->buf, + .offset = 0, + .size = slice_data_buf->size, + }, + .bufferMemoryBarrierCount = 1, + }); + + /* Estimate slice bits and error for each quant */ + ff_vk_shader_update_desc_buffer(vkctx, exec, &pv->estimate_slice_shd, 0, 0, 0, + slice_data_buf, 0, slice_data_buf->size, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(vkctx, exec, &pv->estimate_slice_shd, 0, 1, 0, + slice_score_buf, 0, slice_score_buf->size, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(vkctx, exec, &pv->estimate_slice_shd, 0, 2, 0, + &pv->prores_data_tables_buf, 0, pv->prores_data_tables_buf.size, + VK_FORMAT_UNDEFINED); + ff_vk_exec_bind_shader(vkctx, exec, &pv->estimate_slice_shd); + vk->CmdDispatch(exec->buf, (ctx->slices_per_picture * ctx->num_planes + estimate_dim_x - 1) / estimate_dim_x, + ctx->force_quant ? 1 : (max_quant - min_quant + 1), 1); + + /* Wait for writes to score buffer. */ + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pBufferMemoryBarriers = & (VkBufferMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .pNext = NULL, + .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT | VK_ACCESS_2_SHADER_READ_BIT, + .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .dstAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT | VK_ACCESS_2_SHADER_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = slice_score_buf->buf, + .offset = 0, + .size = slice_score_buf->size, + }, + .bufferMemoryBarrierCount = 1, + }); + + /* Compute optimal quant value for each slice */ + ff_vk_shader_update_desc_buffer(vkctx, exec, &pv->trellis_node_shd, 0, 0, 0, + frame_size_buf, 0, frame_size_buf->size, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(vkctx, exec, &pv->trellis_node_shd, 0, 1, 0, + slice_score_buf, 0, slice_score_buf->size, + VK_FORMAT_UNDEFINED); + ff_vk_exec_bind_shader(vkctx, exec, &pv->trellis_node_shd); + vk->CmdDispatch(exec->buf, 1, 1, 1); + + /* Wait for writes to quant buffer. */ + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pBufferMemoryBarriers = & (VkBufferMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .pNext = NULL, + .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .dstAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT | VK_ACCESS_2_SHADER_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = frame_size_buf->buf, + .offset = 0, + .size = frame_size_buf->size, + }, + .bufferMemoryBarrierCount = 1, + }); + + /* Encode slices. */ + encode_info = (EncodeSliceInfo) { + .seek_table = pkt_vk_buf->address, + .bytestream = pkt_vk_buf->address + ctx->slices_per_picture * 2, + }; + ff_vk_shader_update_desc_buffer(vkctx, exec, &pv->encode_slice_shd, 0, 0, 0, + slice_data_buf, 0, slice_data_buf->size, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(vkctx, exec, &pv->encode_slice_shd, 0, 1, 0, + slice_score_buf, 0, slice_score_buf->size, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(vkctx, exec, &pv->encode_slice_shd, 0, 2, 0, + &pv->prores_data_tables_buf, 0, pv->prores_data_tables_buf.size, + VK_FORMAT_UNDEFINED); + ff_vk_exec_bind_shader(vkctx, exec, &pv->encode_slice_shd); + ff_vk_shader_update_push_const(vkctx, exec, &pv->encode_slice_shd, + VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(encode_info), &encode_info); + vk->CmdDispatch(exec->buf, FFALIGN(ctx->slices_per_picture, 64) / 64, + ctx->num_planes, 1); + +fail: + return err; +} + +static uint8_t *write_frame_header(AVCodecContext *avctx, ProresContext *ctx, + uint8_t **orig_buf, int flags, + enum AVColorPrimaries color_primaries, + enum AVColorTransferCharacteristic color_trc, + enum AVColorSpace colorspace) +{ + uint8_t *buf, *tmp; + uint8_t frame_flags; + + // frame atom + *orig_buf += 4; // frame size + bytestream_put_be32 (orig_buf, FRAME_ID); // frame container ID + buf = *orig_buf; + + // frame header + tmp = buf; + buf += 2; // frame header size will be stored here + bytestream_put_be16 (&buf, ctx->chroma_factor != CFACTOR_Y422 || ctx->alpha_bits ? 1 : 0); + bytestream_put_buffer(&buf, (uint8_t*)ctx->vendor, 4); + bytestream_put_be16 (&buf, avctx->width); + bytestream_put_be16 (&buf, avctx->height); + + frame_flags = ctx->chroma_factor << 6; + if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) + frame_flags |= (flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? 0x04 : 0x08; + bytestream_put_byte (&buf, frame_flags); + + bytestream_put_byte (&buf, 0); // reserved + bytestream_put_byte (&buf, color_primaries); + bytestream_put_byte (&buf, color_trc); + bytestream_put_byte (&buf, colorspace); + bytestream_put_byte (&buf, ctx->alpha_bits >> 3); + bytestream_put_byte (&buf, 0); // reserved + if (ctx->quant_sel != QUANT_MAT_DEFAULT) { + bytestream_put_byte (&buf, 0x03); // matrix flags - both matrices are present + bytestream_put_buffer(&buf, ctx->quant_mat, 64); // luma quantisation matrix + bytestream_put_buffer(&buf, ctx->quant_chroma_mat, 64); // chroma quantisation matrix + } else { + bytestream_put_byte (&buf, 0x00); // matrix flags - default matrices are used + } + bytestream_put_be16 (&tmp, buf - *orig_buf); // write back frame header size + return buf; +} + +static int get_packet(AVCodecContext *avctx, FFVkExecContext *exec, AVPacket *pkt) +{ + ProresVulkanContext *pv = avctx->priv_data; + ProresContext *ctx = &pv->ctx; + VulkanEncodeProresFrameData *pd = exec->opaque; + FFVulkanContext *vkctx = &pv->vkctx; + FFVulkanFunctions *vk = &vkctx->vkfn; + FFVkExecContext *transfer_exec; + uint8_t *orig_buf, *buf, *slice_sizes; + uint8_t *picture_size_pos; + int picture_idx, err = 0; + int frame_size, picture_size; + int pkt_size = ctx->frame_size_upper_bound; + int transfer_slices = vkctx->extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY; + FFVkBuffer *out_data_buf, *frame_size_buf; + VkMappedMemoryRange invalidate_data; + AVBufferRef *mapped_ref; + FFVkBuffer *mapped_buf; + + /* Allocate packet */ + RET(ff_get_encode_buffer(avctx, pkt, pkt_size + FF_INPUT_BUFFER_MIN_SIZE, 0)); + + /* Initialize packet. */ + pkt->pts = pd->pts; + pkt->dts = pd->pts; + pkt->duration = pd->duration; + pkt->flags |= AV_PKT_FLAG_KEY * pd->key_frame; + + if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { + pkt->opaque = pd->frame_opaque; + pkt->opaque_ref = pd->frame_opaque_ref; + pd->frame_opaque_ref = NULL; + } + + /* Write frame atom */ + orig_buf = pkt->data; + buf = write_frame_header(avctx, ctx, &orig_buf, pd->flags, + pd->color_primaries, pd->color_trc, + pd->colorspace); + + /* Make sure encoding's done */ + ff_vk_exec_wait(vkctx, exec); + + /* Roll transfer execution context */ + if (transfer_slices) { + RET(ff_vk_host_map_buffer(vkctx, &mapped_ref, pkt->data, pkt->buf, + VK_BUFFER_USAGE_TRANSFER_DST_BIT)); + mapped_buf = (FFVkBuffer *)mapped_ref->data; + transfer_exec = ff_vk_exec_get(vkctx, &pv->transfer_exec_pool); + ff_vk_exec_start(vkctx, transfer_exec); + } + + for (picture_idx = 0; picture_idx < ctx->pictures_per_frame; picture_idx++) { + /* Fetch buffers for the current picture. */ + out_data_buf = (FFVkBuffer *)pd->out_data_ref[picture_idx]->data; + frame_size_buf = (FFVkBuffer *)pd->frame_size_ref[picture_idx]->data; + + /* Invalidate slice/output data if needed */ + invalidate_data = (VkMappedMemoryRange) { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .offset = 0, + .size = VK_WHOLE_SIZE, + }; + if (!(frame_size_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + invalidate_data.memory = frame_size_buf->mem; + vk->InvalidateMappedMemoryRanges(vkctx->hwctx->act_dev, 1, &invalidate_data); + } + + /* Write picture header */ + picture_size_pos = buf + 1; + bytestream_put_byte(&buf, 0x40); // picture header size (in bits) + buf += 4; // picture data size will be stored here + bytestream_put_be16(&buf, ctx->slices_per_picture); + bytestream_put_byte(&buf, av_log2(ctx->mbs_per_slice) << 4); // slice width and height in MBs + + /* Skip over seek table */ + slice_sizes = buf; + buf += ctx->slices_per_picture * 2; + + /* Calculate final size */ + buf += *(int*)frame_size_buf->mapped_mem; + + if (transfer_slices) { + /* Perform host mapped transfer of slice data */ + ff_vk_exec_add_dep_buf(vkctx, transfer_exec, &pd->out_data_ref[picture_idx], 1, 0); + ff_vk_exec_add_dep_buf(vkctx, transfer_exec, &mapped_ref, 1, 0); + vk->CmdCopyBuffer(transfer_exec->buf, out_data_buf->buf, mapped_buf->buf, 1, & (VkBufferCopy) { + .srcOffset = 0, + .dstOffset = mapped_buf->virtual_offset + slice_sizes - pkt->data, + .size = buf - slice_sizes, + }); + } else { + /* Fallback to regular memcpy if transfer is not available */ + if (!(out_data_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + invalidate_data.memory = out_data_buf->mem; + vk->InvalidateMappedMemoryRanges(vkctx->hwctx->act_dev, 1, &invalidate_data); + } + memcpy(slice_sizes, out_data_buf->mapped_mem, buf - slice_sizes); + av_buffer_unref(&pd->out_data_ref[picture_idx]); + } + + /* Write picture size with header */ + picture_size = buf - (picture_size_pos - 1); + bytestream_put_be32(&picture_size_pos, picture_size); + + /* Slice output buffers no longer needed */ + av_buffer_unref(&pd->slice_data_ref[picture_idx]); + av_buffer_unref(&pd->slice_score_ref[picture_idx]); + av_buffer_unref(&pd->frame_size_ref[picture_idx]); + } + + /* Write frame size in header */ + orig_buf -= 8; + frame_size = buf - orig_buf; + bytestream_put_be32(&orig_buf, frame_size); + + av_shrink_packet(pkt, frame_size); + av_log(avctx, AV_LOG_VERBOSE, "Encoded data: %iMiB\n", pkt->size / (1024*1024)); + + /* Wait for slice transfer */ + if (transfer_slices) { + RET(ff_vk_exec_submit(vkctx, transfer_exec)); + ff_vk_exec_wait(vkctx, transfer_exec); + } + +fail: + return err; +} + +static int vulkan_encode_prores_receive_packet(AVCodecContext *avctx, AVPacket *pkt) +{ + int err; + ProresVulkanContext *pv = avctx->priv_data; + ProresContext *ctx = &pv->ctx; + VulkanEncodeProresFrameData *pd; + FFVkExecContext *exec; + AVFrame *frame; + + while (1) { + /* Roll an execution context */ + exec = ff_vk_exec_get(&pv->vkctx, &pv->e); + + /* If it had a frame, immediately output it */ + if (exec->had_submission) { + exec->had_submission = 0; + pv->in_flight--; + return get_packet(avctx, exec, pkt); + } + + /* Get next frame to encode */ + frame = pv->frame; + err = ff_encode_get_frame(avctx, frame); + if (err < 0 && err != AVERROR_EOF) { + return err; + } else if (err == AVERROR_EOF) { + if (!pv->in_flight) + return err; + continue; + } + + /* Encode frame */ + pd = exec->opaque; + pd->color_primaries = frame->color_primaries; + pd->color_trc = frame->color_trc; + pd->colorspace = frame->colorspace; + pd->pts = frame->pts; + pd->duration = frame->duration; + pd->flags = frame->flags; + if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { + pd->frame_opaque = frame->opaque; + pd->frame_opaque_ref = frame->opaque_ref; + frame->opaque_ref = NULL; + } + + err = vulkan_encode_prores_submit_frame(avctx, exec, frame, 0); + if (ctx->pictures_per_frame > 1) + vulkan_encode_prores_submit_frame(avctx, exec, frame, 1); + + /* Submit execution context */ + ff_vk_exec_submit(&pv->vkctx, exec); + av_frame_unref(frame); + if (err < 0) + return err; + + pv->in_flight++; + if (pv->in_flight < pv->async_depth) + return AVERROR(EAGAIN); + } + + return 0; +} + +static av_cold int encode_close(AVCodecContext *avctx) +{ + ProresVulkanContext *pv = avctx->priv_data; + ProresContext *ctx = &pv->ctx; + FFVulkanContext *vkctx = &pv->vkctx; + + ff_vk_exec_pool_free(vkctx, &pv->e); + ff_vk_exec_pool_free(vkctx, &pv->transfer_exec_pool); + + if (ctx->alpha_bits) + ff_vk_shader_free(vkctx, &pv->alpha_data_shd); + + ff_vk_shader_free(vkctx, &pv->slice_data_shd[0]); + ff_vk_shader_free(vkctx, &pv->slice_data_shd[1]); + ff_vk_shader_free(vkctx, &pv->estimate_slice_shd); + ff_vk_shader_free(vkctx, &pv->encode_slice_shd); + ff_vk_shader_free(vkctx, &pv->trellis_node_shd); + + ff_vk_free_buf(vkctx, &pv->prores_data_tables_buf); + + av_buffer_pool_uninit(&pv->pkt_buf_pool); + av_buffer_pool_uninit(&pv->slice_data_buf_pool); + av_buffer_pool_uninit(&pv->slice_score_buf_pool); + av_buffer_pool_uninit(&pv->frame_size_buf_pool); + + ff_vk_uninit(vkctx); + + return 0; +} + +static av_cold int encode_init(AVCodecContext *avctx) +{ + ProresVulkanContext *pv = avctx->priv_data; + ProresContext *ctx = &pv->ctx; + int err = 0, i, q; + FFVulkanContext *vkctx = &pv->vkctx; + + /* Init vulkan */ + RET(ff_vk_init(vkctx, avctx, NULL, avctx->hw_frames_ctx)); + + pv->qf = ff_vk_qf_find(vkctx, VK_QUEUE_COMPUTE_BIT, 0); + if (!pv->qf) { + av_log(avctx, AV_LOG_ERROR, "Device has no compute queues!\n"); + return AVERROR(ENOTSUP); + } + + RET(ff_vk_exec_pool_init(vkctx, pv->qf, &pv->e, 1, 0, 0, 0, NULL)); + + pv->transfer_qf = ff_vk_qf_find(vkctx, VK_QUEUE_TRANSFER_BIT, 0); + if (!pv->transfer_qf) { + av_log(avctx, AV_LOG_ERROR, "Device has no transfer queues!\n"); + return err; + } + + RET(ff_vk_exec_pool_init(vkctx, pv->transfer_qf, &pv->transfer_exec_pool, + pv->async_depth, 0, 0, 0, NULL)); + + /* Init common prores structures */ + err = ff_prores_kostya_encode_init(avctx, ctx, vkctx->frames->sw_format); + if (err < 0) + return err; + + /* Temporary frame */ + pv->frame = av_frame_alloc(); + if (!pv->frame) + return AVERROR(ENOMEM); + + /* Async data pool */ + pv->async_depth = pv->e.pool_size; + pv->exec_ctx_info = av_calloc(pv->async_depth, sizeof(*pv->exec_ctx_info)); + if (!pv->exec_ctx_info) + return AVERROR(ENOMEM); + for (int i = 0; i < pv->async_depth; i++) + pv->e.contexts[i].opaque = &pv->exec_ctx_info[i]; + + /* Compile shaders used by encoder */ + init_slice_data_pipeline(pv, &pv->slice_data_shd[0], 2); + init_slice_data_pipeline(pv, &pv->slice_data_shd[1], 4); + init_estimate_slice_pipeline(pv, &pv->estimate_slice_shd); + init_trellis_node_pipeline(pv, &pv->trellis_node_shd); + init_encode_slice_pipeline(pv, &pv->encode_slice_shd); + + if (ctx->alpha_bits) + init_alpha_data_pipeline(pv, &pv->alpha_data_shd); + + /* Create prores data tables uniform buffer. */ + RET(ff_vk_create_buf(vkctx, &pv->prores_data_tables_buf, + sizeof(ProresDataTables), NULL, NULL, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + RET(ff_vk_map_buffer(vkctx, &pv->prores_data_tables_buf, (void *)&pv->tables, 0)); + for (q = 0; q < MAX_STORED_Q; ++q) { + for (i = 0; i < 64; i++) { + pv->tables->qmat[q][i] = ctx->quants[q][ctx->scantable[i]]; + pv->tables->qmat_chroma[q][i] = ctx->quants_chroma[q][ctx->scantable[i]]; + } + } + for (q = MAX_STORED_Q; q < 128; ++q) { + for (i = 0; i < 64; i++) { + pv->tables->qmat[q][i] = ctx->quant_mat[ctx->scantable[i]] * q; + pv->tables->qmat_chroma[q][i] = ctx->quant_chroma_mat[ctx->scantable[i]] * q; + } + } + +fail: + return err; +} + +#define OFFSET(x) offsetof(ProresVulkanContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM + +static const AVOption options[] = { + { "mbs_per_slice", "macroblocks per slice", OFFSET(ctx.mbs_per_slice), + AV_OPT_TYPE_INT, { .i64 = 8 }, 1, MAX_MBS_PER_SLICE, VE }, + { "profile", NULL, OFFSET(ctx.profile), AV_OPT_TYPE_INT, + { .i64 = PRORES_PROFILE_AUTO }, + PRORES_PROFILE_AUTO, PRORES_PROFILE_4444XQ, VE, .unit = "profile" }, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_AUTO }, + 0, 0, VE, .unit = "profile" }, + { "proxy", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_PROXY }, + 0, 0, VE, .unit = "profile" }, + { "lt", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_LT }, + 0, 0, VE, .unit = "profile" }, + { "standard", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_STANDARD }, + 0, 0, VE, .unit = "profile" }, + { "hq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_HQ }, + 0, 0, VE, .unit = "profile" }, + { "4444", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_4444 }, + 0, 0, VE, .unit = "profile" }, + { "4444xq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_4444XQ }, + 0, 0, VE, .unit = "profile" }, + { "vendor", "vendor ID", OFFSET(ctx.vendor), + AV_OPT_TYPE_STRING, { .str = "Lavc" }, 0, 0, VE }, + { "bits_per_mb", "desired bits per macroblock", OFFSET(ctx.bits_per_mb), + AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8192, VE }, + { "quant_mat", "quantiser matrix", OFFSET(ctx.quant_sel), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, QUANT_MAT_DEFAULT, VE, .unit = "quant_mat" }, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, + 0, 0, VE, .unit = "quant_mat" }, + { "proxy", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_PROXY }, + 0, 0, VE, .unit = "quant_mat" }, + { "lt", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_LT }, + 0, 0, VE, .unit = "quant_mat" }, + { "standard", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_STANDARD }, + 0, 0, VE, .unit = "quant_mat" }, + { "hq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_HQ }, + 0, 0, VE, .unit = "quant_mat" }, + { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_DEFAULT }, + 0, 0, VE, .unit = "quant_mat" }, + { "alpha_bits", "bits for alpha plane", OFFSET(ctx.alpha_bits), AV_OPT_TYPE_INT, + { .i64 = 16 }, 0, 16, VE }, + { "async_depth", "Internal parallelization depth", OFFSET(async_depth), AV_OPT_TYPE_INT, + { .i64 = 1 }, 1, INT_MAX, VE }, + { NULL } +}; + +static const AVClass proresenc_class = { + .class_name = "ProRes vulkan encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVCodecHWConfigInternal *const prores_ks_hw_configs[] = { + HW_CONFIG_ENCODER_FRAMES(VULKAN, VULKAN), + HW_CONFIG_ENCODER_DEVICE(NONE, VULKAN), + NULL, +}; + +const FFCodec ff_prores_ks_vulkan_encoder = { + .p.name = "prores_ks_vulkan", + CODEC_LONG_NAME("Apple ProRes (iCodec Pro)"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_PRORES, + .priv_data_size = sizeof(ProresVulkanContext), + .init = encode_init, + .close = encode_close, + FF_CODEC_RECEIVE_PACKET_CB(&vulkan_encode_prores_receive_packet), + .p.capabilities = AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_HARDWARE | + AV_CODEC_CAP_ENCODER_FLUSH | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + CODEC_PIXFMTS(AV_PIX_FMT_VULKAN), + .hw_configs = prores_ks_hw_configs, + .color_ranges = AVCOL_RANGE_MPEG, + .p.priv_class = &proresenc_class, + .p.profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_EOF_FLUSH, +}; diff --git a/libavcodec/psd.c b/libavcodec/psd.c index 35c76a601..426ac40b0 100644 --- a/libavcodec/psd.c +++ b/libavcodec/psd.c @@ -52,6 +52,7 @@ typedef struct PSDContext { uint16_t channel_count; uint16_t channel_depth; + uint16_t primary_channels; uint64_t uncompressed_size; unsigned int pixel_size;/* 1 for 8 bits, 2 for 16 bits */ @@ -60,6 +61,8 @@ typedef struct PSDContext { int width; int height; + int16_t layer_count; + enum PsdCompr compression; enum PsdColorMode color_mode; @@ -173,10 +176,10 @@ static int decode_header(PSDContext * s) } bytestream2_skip(&s->gb, len_section); - /* image ressources */ + /* image resources */ len_section = bytestream2_get_be32(&s->gb); if (len_section < 0) { - av_log(s->avctx, AV_LOG_ERROR, "Negative size for image ressources section.\n"); + av_log(s->avctx, AV_LOG_ERROR, "Negative size for image resources section.\n"); return AVERROR_INVALIDDATA; } @@ -193,6 +196,13 @@ static int decode_header(PSDContext * s) return AVERROR_INVALIDDATA; } + if (len_section >= 6) { + /* layer count (in layers and masks section) */ + bytestream2_skip(&s->gb, 4); + s->layer_count = bytestream2_get_be16(&s->gb); + len_section -= 6; + } + if (bytestream2_get_bytes_left(&s->gb) < len_section) { av_log(s->avctx, AV_LOG_ERROR, "Incomplete file.\n"); return AVERROR_INVALIDDATA; @@ -301,11 +311,13 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, uint8_t plane_number; PSDContext *s = avctx->priv_data; - s->avctx = avctx; - s->channel_count = 0; - s->channel_depth = 0; - s->tmp = NULL; - s->line_size = 0; + s->avctx = avctx; + s->channel_count = 0; + s->channel_depth = 0; + s->primary_channels = 0; + s->tmp = NULL; + s->line_size = 0; + s->layer_count = 0; bytestream2_init(&s->gb, avpkt->data, avpkt->size); @@ -317,35 +329,28 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, switch (s->color_mode) { case PSD_BITMAP: - if (s->channel_depth != 1 || s->channel_count != 1) { + if (s->channel_depth != 1 || s->channel_count < 1) { av_log(s->avctx, AV_LOG_ERROR, "Invalid bitmap file (channel_depth %d, channel_count %d)\n", s->channel_depth, s->channel_count); return AVERROR_INVALIDDATA; } s->line_size = s->width + 7 >> 3; + s->primary_channels = 1; avctx->pix_fmt = AV_PIX_FMT_MONOWHITE; break; case PSD_INDEXED: - if (s->channel_depth != 8 || s->channel_count != 1) { + if (s->channel_depth != 8 || s->channel_count < 1) { av_log(s->avctx, AV_LOG_ERROR, "Invalid indexed file (channel_depth %d, channel_count %d)\n", s->channel_depth, s->channel_count); return AVERROR_INVALIDDATA; } + s->primary_channels = 1; avctx->pix_fmt = AV_PIX_FMT_PAL8; break; case PSD_CMYK: - if (s->channel_count == 4) { - if (s->channel_depth == 8) { - avctx->pix_fmt = AV_PIX_FMT_GBRP; - } else if (s->channel_depth == 16) { - avctx->pix_fmt = AV_PIX_FMT_GBRP16BE; - } else { - avpriv_report_missing_feature(avctx, "channel depth %d for cmyk", s->channel_depth); - return AVERROR_PATCHWELCOME; - } - } else if (s->channel_count == 5) { + if (s->layer_count < 0 && s->channel_count >= 5) { if (s->channel_depth == 8) { avctx->pix_fmt = AV_PIX_FMT_GBRAP; } else if (s->channel_depth == 16) { @@ -354,22 +359,26 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, avpriv_report_missing_feature(avctx, "channel depth %d for cmyk", s->channel_depth); return AVERROR_PATCHWELCOME; } + s->primary_channels = 5; + } else if (s->channel_count >= 4) { + if (s->channel_depth == 8) { + avctx->pix_fmt = AV_PIX_FMT_GBRP; + } else if (s->channel_depth == 16) { + avctx->pix_fmt = AV_PIX_FMT_GBRP16BE; + } else { + avpriv_report_missing_feature(avctx, "channel depth %d for cmyk", s->channel_depth); + return AVERROR_PATCHWELCOME; + } + s->primary_channels = 4; } else { - avpriv_report_missing_feature(avctx, "channel count %d for cmyk", s->channel_count); - return AVERROR_PATCHWELCOME; + av_log(s->avctx, AV_LOG_ERROR, + "Invalid cmyk file (channel_count %d)\n", + s->channel_count); + return AVERROR_INVALIDDATA; } break; case PSD_RGB: - if (s->channel_count == 3) { - if (s->channel_depth == 8) { - avctx->pix_fmt = AV_PIX_FMT_GBRP; - } else if (s->channel_depth == 16) { - avctx->pix_fmt = AV_PIX_FMT_GBRP16BE; - } else { - avpriv_report_missing_feature(avctx, "channel depth %d for rgb", s->channel_depth); - return AVERROR_PATCHWELCOME; - } - } else if (s->channel_count == 4) { + if (s->layer_count < 0 && s->channel_count >= 4) { if (s->channel_depth == 8) { avctx->pix_fmt = AV_PIX_FMT_GBRAP; } else if (s->channel_depth == 16) { @@ -378,15 +387,38 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, avpriv_report_missing_feature(avctx, "channel depth %d for rgb", s->channel_depth); return AVERROR_PATCHWELCOME; } + s->primary_channels = 4; + } else if (s->channel_count >= 3) { + if (s->channel_depth == 8) { + avctx->pix_fmt = AV_PIX_FMT_GBRP; + } else if (s->channel_depth == 16) { + avctx->pix_fmt = AV_PIX_FMT_GBRP16BE; + } else { + avpriv_report_missing_feature(avctx, "channel depth %d for rgb", s->channel_depth); + return AVERROR_PATCHWELCOME; + } + s->primary_channels = 3; } else { - avpriv_report_missing_feature(avctx, "channel count %d for rgb", s->channel_count); - return AVERROR_PATCHWELCOME; + av_log(s->avctx, AV_LOG_ERROR, + "Invalid rgb file (channel_count %d)\n", + s->channel_count); + return AVERROR_INVALIDDATA; } break; case PSD_DUOTONE: av_log(avctx, AV_LOG_WARNING, "ignoring unknown duotone specification.\n"); case PSD_GRAYSCALE: - if (s->channel_count == 1) { + if (s->layer_count < 0 && s->channel_count >= 2) { + if (s->channel_depth == 8) { + avctx->pix_fmt = AV_PIX_FMT_YA8; + } else if (s->channel_depth == 16) { + avctx->pix_fmt = AV_PIX_FMT_YA16BE; + } else { + avpriv_report_missing_feature(avctx, "channel depth %d for grayscale", s->channel_depth); + return AVERROR_PATCHWELCOME; + } + s->primary_channels = 2; + } else if (s->channel_count >= 1) { if (s->channel_depth == 8) { avctx->pix_fmt = AV_PIX_FMT_GRAY8; } else if (s->channel_depth == 16) { @@ -397,18 +429,12 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, avpriv_report_missing_feature(avctx, "channel depth %d for grayscale", s->channel_depth); return AVERROR_PATCHWELCOME; } - } else if (s->channel_count == 2) { - if (s->channel_depth == 8) { - avctx->pix_fmt = AV_PIX_FMT_YA8; - } else if (s->channel_depth == 16) { - avctx->pix_fmt = AV_PIX_FMT_YA16BE; - } else { - avpriv_report_missing_feature(avctx, "channel depth %d for grayscale", s->channel_depth); - return AVERROR_PATCHWELCOME; - } + s->primary_channels = 1; } else { - avpriv_report_missing_feature(avctx, "channel count %d for grayscale", s->channel_count); - return AVERROR_PATCHWELCOME; + av_log(s->avctx, AV_LOG_ERROR, + "Invalid grayscale file (channel_count %d)\n", + s->channel_count); + return AVERROR_INVALIDDATA; } break; default: @@ -446,10 +472,10 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, /* Store data */ if ((avctx->pix_fmt == AV_PIX_FMT_YA8)||(avctx->pix_fmt == AV_PIX_FMT_YA16BE)){/* Interleaved */ ptr = picture->data[0]; - for (c = 0; c < s->channel_count; c++) { + for (c = 0; c < 2; c++) { for (y = 0; y < s->height; y++) { for (x = 0; x < s->width; x++) { - index_out = y * picture->linesize[0] + x * s->channel_count * s->pixel_size + c * s->pixel_size; + index_out = y * picture->linesize[0] + x * 2 * s->pixel_size + c * s->pixel_size; for (p = 0; p < s->pixel_size; p++) { ptr[index_out + p] = *ptr_data; ptr_data ++; @@ -518,10 +544,10 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, } } } else {/* Planar */ - if (s->channel_count == 1)/* gray 8 or gray 16be */ + if (s->primary_channels == 1)/* bitmap, indexed, grayscale */ eq_channel[0] = 0;/* assign first channel, to first plane */ - for (c = 0; c < s->channel_count; c++) { + for (c = 0; c < s->primary_channels; c++) { plane_number = eq_channel[c]; ptr = picture->data[plane_number];/* get the right plane */ for (y = 0; y < s->height; y++) { @@ -533,11 +559,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, } if (s->color_mode == PSD_INDEXED) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - picture->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(picture->data[1], s->palette, AVPALETTE_SIZE); } diff --git a/libavcodec/psymodel.c b/libavcodec/psymodel.c index 890b13e1c..87f7b216c 100644 --- a/libavcodec/psymodel.c +++ b/libavcodec/psymodel.c @@ -19,11 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - #include "avcodec.h" #include "psymodel.h" -#include "iirfilter.h" #include "libavutil/mem.h" extern const FFPsyModel ff_aac_psy_model; @@ -37,8 +34,8 @@ av_cold int ff_psy_init(FFPsyContext *ctx, AVCodecContext *avctx, int num_lens, ctx->avctx = avctx; ctx->ch = av_calloc(avctx->ch_layout.nb_channels, 2 * sizeof(ctx->ch[0])); ctx->group = av_calloc(num_groups, sizeof(ctx->group[0])); - ctx->bands = av_malloc_array (sizeof(ctx->bands[0]), num_lens); - ctx->num_bands = av_malloc_array (sizeof(ctx->num_bands[0]), num_lens); + ctx->bands = av_memdup(bands, num_lens * sizeof(ctx->bands[0])); + ctx->num_bands = av_memdup(num_bands, num_lens * sizeof(ctx->num_bands[0])); ctx->cutoff = avctx->cutoff; if (!ctx->ch || !ctx->group || !ctx->bands || !ctx->num_bands) { @@ -46,9 +43,6 @@ av_cold int ff_psy_init(FFPsyContext *ctx, AVCodecContext *avctx, int num_lens, return AVERROR(ENOMEM); } - memcpy(ctx->bands, bands, sizeof(ctx->bands[0]) * num_lens); - memcpy(ctx->num_bands, num_bands, sizeof(ctx->num_bands[0]) * num_lens); - /* assign channels to groups (with virtual channels for coupling) */ for (i = 0; i < num_groups; i++) { /* NOTE: Add 1 to handle the AAC chan_config without modification. @@ -89,73 +83,3 @@ av_cold void ff_psy_end(FFPsyContext *ctx) av_freep(&ctx->group); av_freep(&ctx->ch); } - -typedef struct FFPsyPreprocessContext{ - AVCodecContext *avctx; - float stereo_att; - struct FFIIRFilterCoeffs *fcoeffs; - struct FFIIRFilterState **fstate; - struct FFIIRFilterContext fiir; -}FFPsyPreprocessContext; - -#define FILT_ORDER 4 - -av_cold struct FFPsyPreprocessContext* ff_psy_preprocess_init(AVCodecContext *avctx) -{ - FFPsyPreprocessContext *ctx; - int i; - float cutoff_coeff = 0; - ctx = av_mallocz(sizeof(FFPsyPreprocessContext)); - if (!ctx) - return NULL; - ctx->avctx = avctx; - - /* AAC has its own LP method */ - if (avctx->codec_id != AV_CODEC_ID_AAC) { - if (avctx->cutoff > 0) - cutoff_coeff = 2.0 * avctx->cutoff / avctx->sample_rate; - - if (cutoff_coeff && cutoff_coeff < 0.98) - ctx->fcoeffs = ff_iir_filter_init_coeffs(avctx, FF_FILTER_TYPE_BUTTERWORTH, - FF_FILTER_MODE_LOWPASS, FILT_ORDER, - cutoff_coeff, 0.0, 0.0); - if (ctx->fcoeffs) { - ctx->fstate = av_calloc(avctx->ch_layout.nb_channels, sizeof(ctx->fstate[0])); - if (!ctx->fstate) { - av_free(ctx->fcoeffs); - av_free(ctx); - return NULL; - } - for (i = 0; i < avctx->ch_layout.nb_channels; i++) - ctx->fstate[i] = ff_iir_filter_init_state(FILT_ORDER); - } - } - - ff_iir_filter_init(&ctx->fiir); - - return ctx; -} - -void ff_psy_preprocess(struct FFPsyPreprocessContext *ctx, float **audio, int channels) -{ - int ch; - int frame_size = ctx->avctx->frame_size; - FFIIRFilterContext *iir = &ctx->fiir; - - if (ctx->fstate) { - for (ch = 0; ch < channels; ch++) - iir->filter_flt(ctx->fcoeffs, ctx->fstate[ch], frame_size, - &audio[ch][frame_size], 1, &audio[ch][frame_size], 1); - } -} - -av_cold void ff_psy_preprocess_end(struct FFPsyPreprocessContext *ctx) -{ - int i; - ff_iir_filter_free_coeffsp(&ctx->fcoeffs); - if (ctx->fstate) - for (i = 0; i < ctx->avctx->ch_layout.nb_channels; i++) - ff_iir_filter_free_statep(&ctx->fstate[i]); - av_freep(&ctx->fstate); - av_free(ctx); -} diff --git a/libavcodec/pthread.c b/libavcodec/pthread.c index d32e56de0..6d604566e 100644 --- a/libavcodec/pthread.c +++ b/libavcodec/pthread.c @@ -29,13 +29,13 @@ * @see doc/multithreading.txt */ +#include "libavutil/attributes.h" #include "libavutil/thread.h" #include "avcodec.h" #include "avcodec_internal.h" #include "codec_internal.h" #include "pthread_internal.h" -#include "thread.h" /** * Set the threading algorithms used. @@ -46,7 +46,7 @@ * * @param avctx The context. */ -static void validate_thread_parameters(AVCodecContext *avctx) +static av_cold void validate_thread_parameters(AVCodecContext *avctx) { int frame_threading_supported = (avctx->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) && !(avctx->flags & AV_CODEC_FLAG_LOW_DELAY) @@ -69,7 +69,7 @@ static void validate_thread_parameters(AVCodecContext *avctx) avctx->thread_count, MAX_AUTO_THREADS); } -int ff_thread_init(AVCodecContext *avctx) +av_cold int ff_thread_init(AVCodecContext *avctx) { validate_thread_parameters(avctx); @@ -81,7 +81,7 @@ int ff_thread_init(AVCodecContext *avctx) return 0; } -void ff_thread_free(AVCodecContext *avctx) +av_cold void ff_thread_free(AVCodecContext *avctx) { if (avctx->active_thread_type&FF_THREAD_FRAME) ff_frame_thread_free(avctx, avctx->thread_count); diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index 5b4b0b342..c2853086c 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -34,7 +34,7 @@ #include "internal.h" #include "packet_internal.h" #include "pthread_internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadframe.h" #include "version_major.h" @@ -361,7 +361,11 @@ static int update_context_from_thread(AVCodecContext *dst, const AVCodecContext dst->has_b_frames = src->has_b_frames; dst->idct_algo = src->idct_algo; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS dst->properties = src->properties; +FF_ENABLE_DEPRECATION_WARNINGS +#endif dst->bits_per_coded_sample = src->bits_per_coded_sample; dst->sample_aspect_ratio = src->sample_aspect_ratio; @@ -370,13 +374,10 @@ static int update_context_from_thread(AVCodecContext *dst, const AVCodecContext dst->level = src->level; dst->bits_per_raw_sample = src->bits_per_raw_sample; -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - dst->ticks_per_frame = src->ticks_per_frame; -FF_ENABLE_DEPRECATION_WARNINGS -#endif dst->color_primaries = src->color_primaries; + dst->alpha_mode = src->alpha_mode; + dst->color_trc = src->color_trc; dst->colorspace = src->colorspace; dst->color_range = src->color_range; @@ -401,7 +402,7 @@ FF_ENABLE_DEPRECATION_WARNINGS dst->hwaccel_flags = src->hwaccel_flags; - ff_refstruct_replace(&dst->internal->pool, src->internal->pool); + av_refstruct_replace(&dst->internal->pool, src->internal->pool); ff_decode_internal_sync(dst, src); } @@ -559,7 +560,7 @@ static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx, return 0; } -int ff_thread_receive_frame(AVCodecContext *avctx, AVFrame *frame) +int ff_thread_receive_frame(AVCodecContext *avctx, AVFrame *frame, unsigned flags) { FrameThreadContext *fctx = avctx->internal->thread_ctx; int ret = 0; @@ -572,6 +573,10 @@ int ff_thread_receive_frame(AVCodecContext *avctx, AVFrame *frame) while (!fctx->df.nb_f && !fctx->result) { PerThreadContext *p; + if (fctx->next_decoding != fctx->next_finished && + (flags & AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS)) + goto wait_for_result; + /* get a packet to be submitted to the next thread */ av_packet_unref(fctx->next_pkt); ret = ff_decode_get_packet(avctx, fctx->next_pkt); @@ -588,6 +593,7 @@ int ff_thread_receive_frame(AVCodecContext *avctx, AVFrame *frame) !avctx->internal->draining) continue; + wait_for_result: p = &fctx->threads[fctx->next_finished]; fctx->next_finished = (fctx->next_finished + 1) % avctx->thread_count; @@ -710,7 +716,7 @@ void ff_thread_finish_setup(AVCodecContext *avctx) { } /// Waits for all threads to finish. -static void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count) +static av_cold void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count) { int i; @@ -742,7 +748,7 @@ DEFINE_OFFSET_ARRAY(PerThreadContext, per_thread, pthread_init_cnt, (OFF(input_cond), OFF(progress_cond), OFF(output_cond))); #undef OFF -void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) +av_cold void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) { FrameThreadContext *fctx = avctx->internal->thread_ctx; const FFCodec *codec = ffcodec(avctx->codec); @@ -776,7 +782,7 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) av_freep(&ctx->priv_data); } - ff_refstruct_unref(&ctx->internal->pool); + av_refstruct_unref(&ctx->internal->pool); av_packet_free(&ctx->internal->in_pkt); av_packet_free(&ctx->internal->last_pkt_props); ff_decode_internal_uninit(ctx); @@ -907,7 +913,7 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free, return 0; } -int ff_frame_thread_init(AVCodecContext *avctx) +av_cold int ff_frame_thread_init(AVCodecContext *avctx) { int thread_count = avctx->thread_count; const FFCodec *codec = ffcodec(avctx->codec); @@ -970,7 +976,7 @@ error: return err; } -void ff_thread_flush(AVCodecContext *avctx) +av_cold void ff_thread_flush(AVCodecContext *avctx) { int i; FrameThreadContext *fctx = avctx->internal->thread_ctx; @@ -1051,7 +1057,7 @@ int ff_thread_get_ext_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) if (!(avctx->active_thread_type & FF_THREAD_FRAME)) return ff_get_buffer(avctx, f->f, flags); - f->progress = ff_refstruct_allocz(sizeof(*f->progress)); + f->progress = av_refstruct_allocz(sizeof(*f->progress)); if (!f->progress) return AVERROR(ENOMEM); @@ -1060,19 +1066,19 @@ int ff_thread_get_ext_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) ret = ff_thread_get_buffer(avctx, f->f, flags); if (ret) - ff_refstruct_unref(&f->progress); + av_refstruct_unref(&f->progress); return ret; } void ff_thread_release_ext_buffer(ThreadFrame *f) { - ff_refstruct_unref(&f->progress); + av_refstruct_unref(&f->progress); f->owner[0] = f->owner[1] = NULL; if (f->f) av_frame_unref(f->f); } -enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) +av_cold enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) { PerThreadContext *p; const void *ref; @@ -1087,7 +1093,7 @@ enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) memcpy(&ref, (const char*)p->parent->threads[0].avctx->priv_data + offset, sizeof(ref)); av_assert1(ref); - ff_refstruct_replace((char*)avctx->priv_data + offset, ref); + av_refstruct_replace((char*)avctx->priv_data + offset, ref); return FF_THREAD_IS_COPY; } diff --git a/libavcodec/pthread_slice.c b/libavcodec/pthread_slice.c index ac455e48e..f9da67073 100644 --- a/libavcodec/pthread_slice.c +++ b/libavcodec/pthread_slice.c @@ -22,19 +22,16 @@ * @see doc/multithreading.txt */ -#include "config.h" - #include "avcodec.h" #include "codec_internal.h" #include "internal.h" #include "pthread_internal.h" #include "thread.h" -#include "libavutil/avassert.h" -#include "libavutil/common.h" +#include "libavutil/attributes.h" #include "libavutil/cpu.h" +#include "libavutil/macros.h" #include "libavutil/mem.h" -#include "libavutil/thread.h" #include "libavutil/slicethread.h" typedef int (action_func)(AVCodecContext *c, void *arg); @@ -69,7 +66,7 @@ static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb c->rets[jobnr] = ret; } -void ff_slice_thread_free(AVCodecContext *avctx) +av_cold void ff_slice_thread_free(AVCodecContext *avctx) { SliceThreadContext *c = avctx->internal->thread_ctx; @@ -112,18 +109,12 @@ int ff_slice_thread_execute_with_mainfunc(AVCodecContext *avctx, action_func2* f return thread_execute(avctx, NULL, arg, ret, job_count, 0); } -int ff_slice_thread_init(AVCodecContext *avctx) +av_cold int ff_slice_thread_init(AVCodecContext *avctx) { SliceThreadContext *c; int thread_count = avctx->thread_count; void (*mainfunc)(void *); - // We cannot do this in the encoder init as the threads are created before - if (av_codec_is_encoder(avctx->codec) && - avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && - avctx->height > 2800) - thread_count = avctx->thread_count = 1; - if (!thread_count) { int nb_cpus = av_cpu_count(); if (avctx->height) @@ -141,14 +132,16 @@ int ff_slice_thread_init(AVCodecContext *avctx) } avctx->internal->thread_ctx = c = av_mallocz(sizeof(*c)); + if (!c) + return AVERROR(ENOMEM); mainfunc = ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_SLICE_THREAD_HAS_MF ? &main_function : NULL; - if (!c || (thread_count = avpriv_slicethread_create(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) { - if (c) - avpriv_slicethread_free(&c->thread); - av_freep(&avctx->internal->thread_ctx); + thread_count = avpriv_slicethread_create(&c->thread, avctx, worker_func, + mainfunc, thread_count); + if (thread_count <= 1) { + ff_slice_thread_free(avctx); avctx->thread_count = 1; avctx->active_thread_type = 0; - return 0; + return thread_count < 0 ? thread_count : 0; } avctx->thread_count = thread_count; diff --git a/libavcodec/put_bits.h b/libavcodec/put_bits.h index 0caaa6b33..98c0d7e51 100644 --- a/libavcodec/put_bits.h +++ b/libavcodec/put_bits.h @@ -39,14 +39,14 @@ typedef uint64_t BitBuf; #define AV_WBBUF AV_WB64 #define AV_WLBUF AV_WL64 +#define BUF_BITS 64 #else typedef uint32_t BitBuf; #define AV_WBBUF AV_WB32 #define AV_WLBUF AV_WL32 +#define BUF_BITS 32 #endif -static const int BUF_BITS = 8 * sizeof(BitBuf); - typedef struct PutBitContext { BitBuf bit_buf; int bit_left; @@ -74,6 +74,16 @@ static inline void init_put_bits(PutBitContext *s, uint8_t *buffer, s->bit_buf = 0; } +/** + * Inform the compiler that a PutBitContext is flushed (i.e. if it has just + * been initialized or flushed). Undefined behaviour occurs if this is used + * with a PutBitContext for which this is not true. + */ +static inline void put_bits_assume_flushed(const PutBitContext *s) +{ + av_assume(s->bit_left == BUF_BITS); +} + /** * @return the total number of bits written to the bitstream. */ @@ -246,7 +256,7 @@ static inline void put_bits_no_assert(PutBitContext *s, int n, BitBuf value) */ static inline void put_bits(PutBitContext *s, int n, BitBuf value) { - av_assert2(n <= 31 && value < (1UL << n)); + av_assert2(n <= 31 && value < (BitBuf)(1U << n)); put_bits_no_assert(s, n, value); } @@ -255,7 +265,7 @@ static inline void put_bits_le(PutBitContext *s, int n, BitBuf value) BitBuf bit_buf; int bit_left; - av_assert2(n <= 31 && value < (1UL << n)); + av_assert2(n <= 31 && value < (BitBuf)(1U << n)); bit_buf = s->bit_buf; bit_left = s->bit_left; @@ -288,7 +298,7 @@ static inline void put_sbits(PutBitContext *pb, int n, int32_t value) /** * Write exactly 32 bits into a bitstream. */ -static void av_unused put_bits32(PutBitContext *s, uint32_t value) +av_unused static void put_bits32(PutBitContext *s, uint32_t value) { BitBuf bit_buf; int bit_left; @@ -329,12 +339,15 @@ static void av_unused put_bits32(PutBitContext *s, uint32_t value) } /** - * Write up to 64 bits into a bitstream. + * Write up to 63 bits into a bitstream. */ -static inline void put_bits64(PutBitContext *s, int n, uint64_t value) +static inline void put_bits63(PutBitContext *s, int n, uint64_t value) { - av_assert2((n == 64) || (n < 64 && value < (UINT64_C(1) << n))); + av_assert2(n < 64U && value < (UINT64_C(1) << n)); +#if BUF_BITS >= 64 + put_bits_no_assert(s, n, value); +#else if (n < 32) put_bits(s, n, value); else if (n == 32) @@ -349,6 +362,19 @@ static inline void put_bits64(PutBitContext *s, int n, uint64_t value) put_bits(s, n - 32, hi); put_bits32(s, lo); #endif + } +#endif +} + +/** + * Write up to 64 bits into a bitstream. + */ +static inline void put_bits64(PutBitContext *s, int n, uint64_t value) +{ + av_assert2((n == 64) || (n < 64 && value < (UINT64_C(1) << n))); + + if (n < 64) { + put_bits63(s, n, value); } else { uint32_t lo = value & 0xffffffff; uint32_t hi = value >> 32; @@ -359,7 +385,6 @@ static inline void put_bits64(PutBitContext *s, int n, uint64_t value) put_bits32(s, hi); put_bits32(s, lo); #endif - } } @@ -367,7 +392,7 @@ static inline void put_sbits63(PutBitContext *pb, int n, int64_t value) { av_assert2(n >= 0 && n < 64); - put_bits64(pb, n, (uint64_t)(value) & (~(UINT64_MAX << n))); + put_bits63(pb, n, (uint64_t)(value) & (~(UINT64_MAX << n))); } /** diff --git a/libavcodec/put_golomb.h b/libavcodec/put_golomb.h index 43c1233fd..91e7852a1 100644 --- a/libavcodec/put_golomb.h +++ b/libavcodec/put_golomb.h @@ -62,7 +62,7 @@ static inline void set_ue_golomb_long(PutBitContext *pb, uint32_t i) put_bits(pb, ff_ue_golomb_len[i], i + 1); else { int e = av_log2(i + 1); - put_bits64(pb, 2 * e + 1, i + 1); + put_bits63(pb, 2 * e + 1, i + 1); } } diff --git a/libavcodec/qcelpdec.c b/libavcodec/qcelpdec.c index 1435fecc2..4ec25a8f0 100644 --- a/libavcodec/qcelpdec.c +++ b/libavcodec/qcelpdec.c @@ -89,6 +89,8 @@ static av_cold int qcelp_decode_init(AVCodecContext *avctx) av_channel_layout_uninit(&avctx->ch_layout); avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; avctx->sample_fmt = AV_SAMPLE_FMT_FLT; + if (!avctx->sample_rate) + avctx->sample_rate = 8000; for (i = 0; i < 10; i++) q->prev_lspf[i] = (i + 1) / 11.0; @@ -397,7 +399,7 @@ static void apply_gain_ctrl(float *v_out, const float *v_ref, const float *v_in) int i; for (i = 0; i < 160; i += 40) { - float res = avpriv_scalarproduct_float_c(v_ref + i, v_ref + i, 40); + float res = ff_scalarproduct_float_c(v_ref + i, v_ref + i, 40); ff_scale_vector_to_given_sum_of_squares(v_out + i, v_in + i, res, 40); } } @@ -676,9 +678,9 @@ static void postfilter(QCELPContext *q, float *samples, float *lpc) ff_tilt_compensation(&q->postfilter_tilt_mem, 0.3, pole_out + 10, 160); ff_adaptive_gain_control(samples, pole_out + 10, - avpriv_scalarproduct_float_c(q->formant_mem + 10, - q->formant_mem + 10, - 160), + ff_scalarproduct_float_c(q->formant_mem + 10, + q->formant_mem + 10, + 160), 160, 0.9375, &q->postfilter_agc_mem); } diff --git a/libavcodec/qdm2.c b/libavcodec/qdm2.c index b4aaf179f..796321f9d 100644 --- a/libavcodec/qdm2.c +++ b/libavcodec/qdm2.c @@ -34,6 +34,7 @@ #include #include +#include "libavutil/attributes.h" #include "libavutil/channel_layout.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" @@ -199,9 +200,8 @@ static const int switchtable[23] = { static int qdm2_get_vlc(GetBitContext *gb, const VLC *vlc, int flag, int depth) { - int value; - - value = get_vlc2(gb, vlc->table, vlc->bits, depth); + int value = get_vlc2(gb, vlc->table, vlc->bits, + av_builtin_constant_p(depth) ? depth : 2); /* stage-2, 3 bits exponent escape sequence */ if (value < 0) @@ -339,14 +339,14 @@ static void average_quantized_coeffs(QDM2Context *q) * @param q context * @param sb subband index */ -static void build_sb_samples_from_noise(QDM2Context *q, int sb) +static int build_sb_samples_from_noise(QDM2Context *q, int sb) { int ch, j; FIX_NOISE_IDX(q->noise_idx); if (!q->nb_channels) - return; + return AVERROR_INVALIDDATA; for (ch = 0; ch < q->nb_channels; ch++) { for (j = 0; j < 64; j++) { @@ -356,6 +356,8 @@ static void build_sb_samples_from_noise(QDM2Context *q, int sb) SB_DITHERING_NOISE(sb, q->noise_idx) * q->tone_level[ch][sb][j]; } } + + return 0; } /** @@ -526,7 +528,7 @@ static void fill_tone_level_array(QDM2Context *q, int flag) * @param superblocktype_2_3 flag based on superblock packet type * @param cm_table_select q->cm_table_select */ -static void fill_coding_method_array(sb_int8_array tone_level_idx, +static int fill_coding_method_array(sb_int8_array tone_level_idx, sb_int8_array tone_level_idx_temp, sb_int8_array coding_method, int nb_channels, @@ -534,14 +536,17 @@ static void fill_coding_method_array(sb_int8_array tone_level_idx, int cm_table_select) { int ch, sb, j; +#if 0 int tmp, acc, esp_40, comp; int add1, add2, add3, add4; int64_t multres; +#endif if (!superblocktype_2_3) { /* This case is untested, no samples available */ avpriv_request_sample(NULL, "!superblocktype_2_3"); - return; + return AVERROR_PATCHWELCOME; +#if 0 for (ch = 0; ch < nb_channels; ch++) { for (sb = 0; sb < 30; sb++) { for (j = 1; j < 63; j++) { // The loop only iterates to 63 so the code doesn't overflow the buffer @@ -633,12 +638,14 @@ static void fill_coding_method_array(sb_int8_array tone_level_idx, coding_method[ch][sb][j] = 30; } } +#endif } else { // superblocktype_2_3 != 0 for (ch = 0; ch < nb_channels; ch++) for (sb = 0; sb < 30; sb++) for (j = 0; j < 64; j++) coding_method[ch][sb][j] = coding_method_table[cm_table_select][sb]; } + return 0; } /** @@ -666,8 +673,11 @@ static int synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb, if (length == 0) { // If no data use noise - for (sb=sb_min; sb < sb_max; sb++) - build_sb_samples_from_noise(q, sb); + for (sb=sb_min; sb < sb_max; sb++) { + int ret = build_sb_samples_from_noise(q, sb); + if (ret < 0) + return ret; + } return 0; } @@ -694,7 +704,9 @@ static int synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb, if (fix_coding_method_array(sb, q->nb_channels, q->coding_method)) { av_log(NULL, AV_LOG_ERROR, "coding method invalid\n"); - build_sb_samples_from_noise(q, sb); + int ret = build_sb_samples_from_noise(q, sb); + if (ret < 0) + return ret; continue; } channels = 1; @@ -875,21 +887,21 @@ static int init_quantized_coeffs_elem0(int8_t *quantized_coeffs, int i, k, run, level, diff; if (get_bits_left(gb) < 16) - return -1; + return AVERROR_INVALIDDATA; level = qdm2_get_vlc(gb, &vlc_tab_level, 0, 2); quantized_coeffs[0] = level; for (i = 0; i < 7; ) { if (get_bits_left(gb) < 16) - return -1; + return AVERROR_INVALIDDATA; run = qdm2_get_vlc(gb, &vlc_tab_run, 0, 1) + 1; if (i + run >= 8) - return -1; + return AVERROR_INVALIDDATA; if (get_bits_left(gb) < 16) - return -1; + return AVERROR_INVALIDDATA; diff = qdm2_get_se_vlc(&vlc_tab_diff, gb, 2); for (k = 1; k <= run; k++) @@ -910,12 +922,15 @@ static int init_quantized_coeffs_elem0(int8_t *quantized_coeffs, * @param q context * @param gb bitreader context */ -static void init_tone_level_dequantization(QDM2Context *q, GetBitContext *gb) +static int init_tone_level_dequantization(QDM2Context *q, GetBitContext *gb) { int sb, j, k, n, ch; for (ch = 0; ch < q->nb_channels; ch++) { - init_quantized_coeffs_elem0(q->quantized_coeffs[ch][0], gb); + int ret = init_quantized_coeffs_elem0(q->quantized_coeffs[ch][0], gb); + + if (ret < 0) + return ret; if (get_bits_left(gb) < 16) { memset(q->quantized_coeffs[ch][0], 0, 8); @@ -965,6 +980,8 @@ static void init_tone_level_dequantization(QDM2Context *q, GetBitContext *gb) break; q->tone_level_idx_mid[ch][sb][j] = qdm2_get_vlc(gb, &vlc_tab_tone_level_idx_mid, 0, 2) - 32; } + + return 0; } /** @@ -978,7 +995,9 @@ static int process_subpacket_9(QDM2Context *q, QDM2SubPNode *node) GetBitContext gb; int i, j, k, n, ch, run, level, diff; - init_get_bits(&gb, node->packet->data, node->packet->size * 8); + int ret = init_get_bits8(&gb, node->packet->data, node->packet->size); + if (ret < 0) + return ret; n = coeff_per_sb_for_avg[q->coeff_per_sb_select][QDM2_SB_USED(q->sub_sampling) - 1] + 1; @@ -1015,17 +1034,22 @@ static int process_subpacket_9(QDM2Context *q, QDM2SubPNode *node) * @param q context * @param node pointer to node with packet */ -static void process_subpacket_10(QDM2Context *q, QDM2SubPNode *node) +static int process_subpacket_10(QDM2Context *q, QDM2SubPNode *node) { GetBitContext gb; if (node) { - init_get_bits(&gb, node->packet->data, node->packet->size * 8); - init_tone_level_dequantization(q, &gb); + int ret = init_get_bits8(&gb, node->packet->data, node->packet->size); + if (ret < 0) + return ret; + ret = init_tone_level_dequantization(q, &gb); + if (ret < 0) + return ret; fill_tone_level_array(q, 1); } else { fill_tone_level_array(q, 0); } + return 0; } /** @@ -1034,27 +1058,32 @@ static void process_subpacket_10(QDM2Context *q, QDM2SubPNode *node) * @param q context * @param node pointer to node with packet */ -static void process_subpacket_11(QDM2Context *q, QDM2SubPNode *node) +static int process_subpacket_11(QDM2Context *q, QDM2SubPNode *node) { GetBitContext gb; - int length = 0; + int ret, length = 0; if (node) { + ret = init_get_bits8(&gb, node->packet->data, node->packet->size); + if (ret < 0) + return ret; length = node->packet->size * 8; - init_get_bits(&gb, node->packet->data, length); } if (length >= 32) { int c = get_bits(&gb, 13); - if (c > 3) - fill_coding_method_array(q->tone_level_idx, + if (c > 3) { + ret = fill_coding_method_array(q->tone_level_idx, q->tone_level_idx_temp, q->coding_method, q->nb_channels, 8 * c, q->superblocktype_2_3, q->cm_table_select); + if (ret < 0) + return ret; + } } - synthfilt_build_sb_samples(q, &gb, length, 0, 8); + return synthfilt_build_sb_samples(q, &gb, length, 0, 8); } /** @@ -1063,17 +1092,19 @@ static void process_subpacket_11(QDM2Context *q, QDM2SubPNode *node) * @param q context * @param node pointer to node with packet */ -static void process_subpacket_12(QDM2Context *q, QDM2SubPNode *node) +static int process_subpacket_12(QDM2Context *q, QDM2SubPNode *node) { GetBitContext gb; int length = 0; if (node) { + int ret = init_get_bits8(&gb, node->packet->data, length); + if (ret < 0) + return ret; length = node->packet->size * 8; - init_get_bits(&gb, node->packet->data, length); } - synthfilt_build_sb_samples(q, &gb, length, 8, QDM2_SB_USED(q->sub_sampling)); + return synthfilt_build_sb_samples(q, &gb, length, 8, QDM2_SB_USED(q->sub_sampling)); } /** @@ -1082,31 +1113,43 @@ static void process_subpacket_12(QDM2Context *q, QDM2SubPNode *node) * @param q context * @param list list with synthesis filter packets (list D) */ -static void process_synthesis_subpackets(QDM2Context *q, QDM2SubPNode *list) +static int process_synthesis_subpackets(QDM2Context *q, QDM2SubPNode *list) { QDM2SubPNode *nodes[4]; + int ret = 0; nodes[0] = qdm2_search_subpacket_type_in_list(list, 9); if (nodes[0]) - process_subpacket_9(q, nodes[0]); + ret = process_subpacket_9(q, nodes[0]); + + if (ret < 0) + return ret; nodes[1] = qdm2_search_subpacket_type_in_list(list, 10); if (nodes[1]) - process_subpacket_10(q, nodes[1]); + ret = process_subpacket_10(q, nodes[1]); else - process_subpacket_10(q, NULL); + ret = process_subpacket_10(q, NULL); + + if (ret < 0) + return ret; nodes[2] = qdm2_search_subpacket_type_in_list(list, 11); if (nodes[0] && nodes[1] && nodes[2]) - process_subpacket_11(q, nodes[2]); + ret = process_subpacket_11(q, nodes[2]); else - process_subpacket_11(q, NULL); + ret = process_subpacket_11(q, NULL); + + if (ret < 0) + return ret; nodes[3] = qdm2_search_subpacket_type_in_list(list, 12); if (nodes[0] && nodes[1] && nodes[3]) - process_subpacket_12(q, nodes[3]); + ret = process_subpacket_12(q, nodes[3]); else - process_subpacket_12(q, NULL); + ret = process_subpacket_12(q, NULL); + + return ret; } /** @@ -1114,11 +1157,12 @@ static void process_synthesis_subpackets(QDM2Context *q, QDM2SubPNode *list) * * @param q context */ -static void qdm2_decode_super_block(QDM2Context *q) +static int qdm2_decode_super_block(QDM2Context *q) { GetBitContext gb; QDM2SubPacket header, *packet; int i, packet_bytes, sub_packet_size, sub_packets_D; + int ret; unsigned int next_index = 0; memset(q->tone_level_idx_hi1, 0, sizeof(q->tone_level_idx_hi1)); @@ -1130,19 +1174,24 @@ static void qdm2_decode_super_block(QDM2Context *q) average_quantized_coeffs(q); // average elements in quantized_coeffs[max_ch][10][8] - init_get_bits(&gb, q->compressed_data, q->compressed_size * 8); + ret = init_get_bits8(&gb, q->compressed_data, q->compressed_size); + if (ret < 0) + return ret; + qdm2_decode_sub_packet_header(&gb, &header); if (header.type < 2 || header.type >= 8) { q->has_errors = 1; av_log(NULL, AV_LOG_ERROR, "bad superblock type\n"); - return; + return AVERROR_INVALIDDATA; } q->superblocktype_2_3 = (header.type == 2 || header.type == 3); packet_bytes = (q->compressed_size - get_bits_count(&gb) / 8); - init_get_bits(&gb, header.data, header.size * 8); + ret = init_get_bits8(&gb, header.data, header.size); + if (ret < 0) + return ret; if (header.type == 2 || header.type == 4 || header.type == 5) { int csum = 257 * get_bits(&gb, 8); @@ -1153,7 +1202,7 @@ static void qdm2_decode_super_block(QDM2Context *q) if (csum != 0) { q->has_errors = 1; av_log(NULL, AV_LOG_ERROR, "bad packet checksum\n"); - return; + return AVERROR_INVALIDDATA; } } @@ -1169,7 +1218,7 @@ static void qdm2_decode_super_block(QDM2Context *q) if (i >= FF_ARRAY_ELEMS(q->sub_packet_list_A)) { SAMPLES_NEEDED_2("too many packet bytes"); - return; + return AVERROR_PATCHWELCOME; } q->sub_packet_list_A[i].next = NULL; @@ -1178,7 +1227,10 @@ static void qdm2_decode_super_block(QDM2Context *q) q->sub_packet_list_A[i - 1].next = &q->sub_packet_list_A[i]; /* seek to next block */ - init_get_bits(&gb, header.data, header.size * 8); + ret = init_get_bits8(&gb, header.data, header.size); + if (ret < 0) + return ret; + skip_bits(&gb, next_index * 8); if (next_index >= header.size) @@ -1208,7 +1260,7 @@ static void qdm2_decode_super_block(QDM2Context *q) /* add subpacket to related list */ if (packet->type == 8) { SAMPLES_NEEDED_2("packet type 8"); - return; + return AVERROR_PATCHWELCOME; } else if (packet->type >= 9 && packet->type <= 12) { /* packets for MPEG Audio like Synthesis Filter */ QDM2_LIST_ADD(q->sub_packet_list_D, sub_packets_D, packet); @@ -1220,7 +1272,7 @@ static void qdm2_decode_super_block(QDM2Context *q) q->fft_level_exp[j] = qdm2_get_vlc(&gb, &fft_level_exp_vlc, 0, 2); } else if (packet->type == 15) { SAMPLES_NEEDED_2("packet type 15") - return; + return AVERROR_PATCHWELCOME; } else if (packet->type >= 16 && packet->type < 48 && !fft_subpackets[packet->type - 16]) { /* packets for FFT */ @@ -1229,13 +1281,22 @@ static void qdm2_decode_super_block(QDM2Context *q) } // Packet bytes loop if (q->sub_packet_list_D[0].packet) { - process_synthesis_subpackets(q, q->sub_packet_list_D); + ret = process_synthesis_subpackets(q, q->sub_packet_list_D); + if (ret < 0) + return ret; q->do_synth_filter = 1; } else if (q->do_synth_filter) { - process_subpacket_10(q, NULL); - process_subpacket_11(q, NULL); - process_subpacket_12(q, NULL); + ret = process_subpacket_10(q, NULL); + if (ret < 0) + return ret; + ret = process_subpacket_11(q, NULL); + if (ret < 0) + return ret; + ret = process_subpacket_12(q, NULL); + if (ret < 0) + return ret; } + return 0; } static void qdm2_fft_init_coefficient(QDM2Context *q, int sub_packet, @@ -1254,7 +1315,7 @@ static void qdm2_fft_init_coefficient(QDM2Context *q, int sub_packet, q->fft_coefs_index++; } -static void qdm2_fft_decode_tones(QDM2Context *q, int duration, +static int qdm2_fft_decode_tones(QDM2Context *q, int duration, GetBitContext *gb, int b) { int channel, stereo, phase, exp; @@ -1275,7 +1336,7 @@ static void qdm2_fft_decode_tones(QDM2Context *q, int duration, if (get_bits_left(gb)<0) { if(local_int_4 < q->group_size) av_log(NULL, AV_LOG_ERROR, "overread in qdm2_fft_decode_tones()\n"); - return; + return AVERROR_INVALIDDATA; } offset = 1; if (n == 0) { @@ -1290,7 +1351,7 @@ static void qdm2_fft_decode_tones(QDM2Context *q, int duration, } else { if (local_int_10 <= 2) { av_log(NULL, AV_LOG_ERROR, "qdm2_fft_decode_tones() stuck\n"); - return; + return AVERROR_INVALIDDATA; } offset += qdm2_get_vlc(gb, &vlc_tab_fft_tone_offset[local_int_8], 1, 2); while (offset >= (local_int_10 - 1)) { @@ -1301,11 +1362,11 @@ static void qdm2_fft_decode_tones(QDM2Context *q, int duration, } if (local_int_4 >= q->group_size) - return; + return AVERROR_INVALIDDATA; local_int_14 = (offset >> local_int_8); if (local_int_14 >= FF_ARRAY_ELEMS(fft_level_index_table)) - return; + return AVERROR_INVALIDDATA; if (q->nb_channels > 1) { channel = get_bits1(gb); @@ -1334,7 +1395,7 @@ static void qdm2_fft_decode_tones(QDM2Context *q, int duration, int sub_packet = (local_int_20 + local_int_28); if (q->fft_coefs_index + stereo >= FF_ARRAY_ELEMS(q->fft_coefs)) - return; + return AVERROR_INVALIDDATA; qdm2_fft_init_coefficient(q, sub_packet, offset, duration, channel, exp, phase); @@ -1345,15 +1406,17 @@ static void qdm2_fft_decode_tones(QDM2Context *q, int duration, } offset++; } + + return 0; } -static void qdm2_decode_fft_packets(QDM2Context *q) +static int qdm2_decode_fft_packets(QDM2Context *q) { int i, j, min, max, value, type, unknown_flag; GetBitContext gb; if (!q->sub_packet_list_B[0].packet) - return; + return AVERROR_INVALIDDATA; /* reset minimum indexes for FFT coefficients */ q->fft_coefs_index = 0; @@ -1377,15 +1440,17 @@ static void qdm2_decode_fft_packets(QDM2Context *q) /* check for errors (?) */ if (!packet) - return; + return AVERROR_INVALIDDATA; if (i == 0 && (packet->type < 16 || packet->type >= 48 || fft_subpackets[packet->type - 16])) - return; + return AVERROR_INVALIDDATA; /* decode FFT tones */ - init_get_bits(&gb, packet->data, packet->size * 8); + int ret = init_get_bits8(&gb, packet->data, packet->size); + if (ret < 0) + return ret; if (packet->type >= 32 && packet->type < 48 && !fft_subpackets[packet->type - 16]) unknown_flag = 1; @@ -1419,6 +1484,8 @@ static void qdm2_decode_fft_packets(QDM2Context *q) } if (j >= 0) q->fft_coefs_max_index[j] = q->fft_coefs_index; + + return 0; } static void qdm2_fft_generate_tone(QDM2Context *q, FFTTone *tone) @@ -1661,20 +1728,20 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx) bytestream2_init(&gb, avctx->extradata, avctx->extradata_size); while (bytestream2_get_bytes_left(&gb) > 8) { - if (bytestream2_peek_be64(&gb) == (((uint64_t)MKBETAG('f','r','m','a') << 32) | + if (bytestream2_peek_be64u(&gb) == (((uint64_t)MKBETAG('f','r','m','a') << 32) | (uint64_t)MKBETAG('Q','D','M','2'))) break; - bytestream2_skip(&gb, 1); + bytestream2_skipu(&gb, 1); } - if (bytestream2_get_bytes_left(&gb) < 12) { + if (bytestream2_get_bytes_left(&gb) < 44) { av_log(avctx, AV_LOG_ERROR, "not enough extradata (%i)\n", bytestream2_get_bytes_left(&gb)); return AVERROR_INVALIDDATA; } - bytestream2_skip(&gb, 8); - size = bytestream2_get_be32(&gb); + bytestream2_skipu(&gb, 8); + size = bytestream2_get_be32u(&gb); if (size > bytestream2_get_bytes_left(&gb)) { av_log(avctx, AV_LOG_ERROR, "extradata size too small, %i < %i\n", @@ -1683,14 +1750,14 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx) } av_log(avctx, AV_LOG_DEBUG, "size: %d\n", size); - if (bytestream2_get_be32(&gb) != MKBETAG('Q','D','C','A')) { + if (bytestream2_get_be32u(&gb) != MKBETAG('Q','D','C','A')) { av_log(avctx, AV_LOG_ERROR, "invalid extradata, expecting QDCA\n"); return AVERROR_INVALIDDATA; } - bytestream2_skip(&gb, 4); + bytestream2_skipu(&gb, 4); - s->nb_channels = s->channels = bytestream2_get_be32(&gb); + s->nb_channels = s->channels = bytestream2_get_be32u(&gb); if (s->channels <= 0 || s->channels > MPA_MAX_CHANNELS) { av_log(avctx, AV_LOG_ERROR, "Invalid number of channels\n"); return AVERROR_INVALIDDATA; @@ -1698,11 +1765,11 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx) av_channel_layout_uninit(&avctx->ch_layout); av_channel_layout_default(&avctx->ch_layout, s->channels); - avctx->sample_rate = bytestream2_get_be32(&gb); - avctx->bit_rate = bytestream2_get_be32(&gb); - s->group_size = bytestream2_get_be32(&gb); - s->fft_size = bytestream2_get_be32(&gb); - s->checksum_size = bytestream2_get_be32(&gb); + avctx->sample_rate = bytestream2_get_be32u(&gb); + avctx->bit_rate = bytestream2_get_be32u(&gb); + s->group_size = bytestream2_get_be32u(&gb); + s->fft_size = bytestream2_get_be32u(&gb); + s->checksum_size = bytestream2_get_be32u(&gb); if (s->checksum_size >= 1U << 28 || s->checksum_size <= 1) { av_log(avctx, AV_LOG_ERROR, "data block size invalid (%u)\n", s->checksum_size); return AVERROR_INVALIDDATA; @@ -1787,7 +1854,7 @@ static int qdm2_decode(QDM2Context *q, const uint8_t *in, int16_t *out) const int frame_size = (q->frame_size * q->channels); if((unsigned)frame_size > FF_ARRAY_ELEMS(q->output_buffer)/2) - return -1; + return AVERROR_INVALIDDATA; /* select input buffer */ q->compressed_data = in; @@ -1801,13 +1868,18 @@ static int qdm2_decode(QDM2Context *q, const uint8_t *in, int16_t *out) if (q->sub_packet == 0) { q->has_errors = 0; // zero it for a new super block av_log(NULL,AV_LOG_DEBUG,"Superblock follows\n"); - qdm2_decode_super_block(q); + int ret = qdm2_decode_super_block(q); + if (ret < 0) + return ret; } /* parse subpackets */ if (!q->has_errors) { + int ret = 0; if (q->sub_packet == 2) - qdm2_decode_fft_packets(q); + ret = qdm2_decode_fft_packets(q); + if (ret < 0) + return ret; qdm2_fft_tone_synthesizer(q, q->sub_packet); } @@ -1818,7 +1890,7 @@ static int qdm2_decode(QDM2Context *q, const uint8_t *in, int16_t *out) if (!q->has_errors && q->sub_packet_list_C[0].packet) { SAMPLES_NEEDED_2("has errors, and C list is not empty") - return -1; + return AVERROR_PATCHWELCOME; } } @@ -1855,7 +1927,7 @@ static int qdm2_decode_frame(AVCodecContext *avctx, AVFrame *frame, if(!buf) return 0; if(buf_size < s->checksum_size) - return -1; + return AVERROR_INVALIDDATA; s->sub_packet = 0; diff --git a/libavcodec/qdrw.c b/libavcodec/qdrw.c index ca38f48bd..fd2d89447 100644 --- a/libavcodec/qdrw.c +++ b/libavcodec/qdrw.c @@ -384,11 +384,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, ret = parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors, flags & 0x8000); if (ret < 0) return ret; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - p->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* jump to image data */ bytestream2_skip(&gbc, 18); diff --git a/libavcodec/qoadec.c b/libavcodec/qoadec.c index c5cf351f9..aa3e30a1b 100644 --- a/libavcodec/qoadec.c +++ b/libavcodec/qoadec.c @@ -165,6 +165,4 @@ const FFCodec ff_qoa_decoder = { FF_CODEC_DECODE_CB(qoa_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/qoi_parser.c b/libavcodec/qoi_parser.c index e5af11e94..f7bf2a05b 100644 --- a/libavcodec/qoi_parser.c +++ b/libavcodec/qoi_parser.c @@ -25,6 +25,7 @@ */ #include "parser.h" +#include "parser_internal.h" typedef struct QOIParseContext { ParseContext pc; @@ -69,9 +70,9 @@ static int qoi_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_qoi_parser = { - .codec_ids = { AV_CODEC_ID_QOI }, +const FFCodecParser ff_qoi_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_QOI), .priv_data_size = sizeof(QOIParseContext), - .parser_parse = qoi_parse, - .parser_close = ff_parse_close, + .parse = qoi_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/qoienc.c b/libavcodec/qoienc.c index b9efdc2fa..3149f162d 100644 --- a/libavcodec/qoienc.c +++ b/libavcodec/qoienc.c @@ -134,8 +134,5 @@ const FFCodec ff_qoi_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(qoi_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB24, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB24), }; diff --git a/libavcodec/qpeg.c b/libavcodec/qpeg.c index 9b4ad8e25..41b083bc1 100644 --- a/libavcodec/qpeg.c +++ b/libavcodec/qpeg.c @@ -29,6 +29,8 @@ #include "codec_internal.h" #include "decode.h" +#include "libavutil/attributes.h" + typedef struct QpegContext{ AVCodecContext *avctx; AVFrame *ref; @@ -297,14 +299,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, } /* make the palette available on the way out */ -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - p->palette_has_changed = -#endif ff_copy_palette(a->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(p->data[1], a->pal, AVPALETTE_SIZE); if ((ret = av_frame_replace(ref, p)) < 0) @@ -321,7 +316,8 @@ FF_ENABLE_DEPRECATION_WARNINGS return avpkt->size; } -static void decode_flush(AVCodecContext *avctx){ +static av_cold void decode_flush(AVCodecContext *avctx) +{ QpegContext * const a = avctx->priv_data; int i, pal_size; const uint8_t *pal_src; diff --git a/libavcodec/qpeldsp.c b/libavcodec/qpeldsp.c index 5f937f9d9..33a5eccd0 100644 --- a/libavcodec/qpeldsp.c +++ b/libavcodec/qpeldsp.c @@ -810,7 +810,7 @@ av_cold void ff_qpeldsp_init(QpelDSPContext *c) dspfunc(avg_qpel, 0, 16); dspfunc(avg_qpel, 1, 8); -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_qpeldsp_init_x86(c); #elif ARCH_MIPS ff_qpeldsp_init_mips(c); diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index 8a3dc9570..cd5195a54 100644 --- a/libavcodec/qsv.c +++ b/libavcodec/qsv.c @@ -35,7 +35,7 @@ #include "avcodec.h" #include "qsv_internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl)) #define QSV_HAVE_USER_PLUGIN !QSV_ONEVPL @@ -745,7 +745,7 @@ int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs, return 0; } -static void mids_buf_free(FFRefStructOpaque opaque, void *obj) +static void mids_buf_free(AVRefStructOpaque opaque, void *obj) { AVBufferRef *hw_frames_ref = opaque.nc; av_buffer_unref(&hw_frames_ref); @@ -765,7 +765,7 @@ static QSVMid *qsv_create_mids(AVBufferRef *hw_frames_ref) if (!hw_frames_ref1) return NULL; - mids = ff_refstruct_alloc_ext(nb_surfaces * sizeof(*mids), 0, + mids = av_refstruct_alloc_ext(nb_surfaces * sizeof(*mids), 0, hw_frames_ref1, mids_buf_free); if (!mids) { av_buffer_unref(&hw_frames_ref1); @@ -806,7 +806,7 @@ static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_re return AVERROR(ENOMEM); } - resp->mids[resp->NumFrameActual + 1] = ff_refstruct_ref(mids); + resp->mids[resp->NumFrameActual + 1] = av_refstruct_ref(mids); return 0; } @@ -899,7 +899,7 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, } ret = qsv_setup_mids(resp, frames_ref, mids); - ff_refstruct_unref(&mids); + av_refstruct_unref(&mids); av_buffer_unref(&frames_ref); if (ret < 0) { av_log(ctx->logctx, AV_LOG_ERROR, @@ -919,7 +919,7 @@ static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp) return MFX_ERR_NONE; av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]); - ff_refstruct_unref(&resp->mids[resp->NumFrameActual + 1]); + av_refstruct_unref(&resp->mids[resp->NumFrameActual + 1]); av_freep(&resp->mids); return MFX_ERR_NONE; } @@ -1139,7 +1139,7 @@ int ff_qsv_init_session_frames(AVCodecContext *avctx, mfxSession *psession, /* allocate the memory ids for the external frames */ if (frames_hwctx->nb_surfaces) { - ff_refstruct_unref(&qsv_frames_ctx->mids); + av_refstruct_unref(&qsv_frames_ctx->mids); qsv_frames_ctx->mids = qsv_create_mids(qsv_frames_ctx->hw_frames_ctx); if (!qsv_frames_ctx->mids) return AVERROR(ENOMEM); diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index 039ba6248..a85c1785c 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -51,7 +51,7 @@ #include "hwconfig.h" #include "qsv.h" #include "qsv_internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #if QSV_ONEVPL #include @@ -202,6 +202,7 @@ static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses MFXClose(q->internal_qs.session); q->internal_qs.session = NULL; } + av_refstruct_unref(&q->frames_ctx.mids); av_buffer_unref(&q->frames_ctx.hw_frames_ctx); q->frames_ctx.hw_frames_ctx = av_buffer_ref(hw_frames_ref); @@ -696,7 +697,7 @@ static int qsv_export_hdr_side_data(AVCodecContext *avctx, mfxExtMasteringDispla { int ret; - // The SDK re-uses this flag for HDR SEI parsing + // The SDK reuses this flag for HDR SEI parsing if (mdcv->InsertPayloadToggle) { AVMasteringDisplayMetadata *mastering; const int mapping[3] = {2, 0, 1}; @@ -726,7 +727,7 @@ static int qsv_export_hdr_side_data(AVCodecContext *avctx, mfxExtMasteringDispla } } - // The SDK re-uses this flag for HDR SEI parsing + // The SDK reuses this flag for HDR SEI parsing if (clli->InsertPayloadToggle) { AVContentLightMetadata *light; @@ -984,7 +985,7 @@ static void qsv_decode_close_qsvcontext(QSVContext *q) ff_qsv_close_internal_session(&q->internal_qs); av_buffer_unref(&q->frames_ctx.hw_frames_ctx); - ff_refstruct_unref(&q->frames_ctx.mids); + av_refstruct_unref(&q->frames_ctx.mids); av_buffer_pool_uninit(&q->pool); } @@ -1002,7 +1003,7 @@ static int qsv_process_data(AVCodecContext *avctx, QSVContext *q, // sw_pix_fmt, coded_width/height should be set for ff_get_format(), // assume sw_pix_fmt is NV12 and coded_width/height to be 1280x720, - // the assumption may be not corret but will be updated after header decoded if not true. + // the assumption may be not correct but will be updated after header decoded if not true. if (q->orig_pix_fmt != AV_PIX_FMT_NONE) pix_fmt = q->orig_pix_fmt; if (!avctx->coded_width) diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c index 8200a1401..fc1b8795d 100644 --- a/libavcodec/qsvenc.c +++ b/libavcodec/qsvenc.c @@ -37,12 +37,10 @@ #include "avcodec.h" #include "encode.h" -#include "internal.h" -#include "packet_internal.h" #include "qsv.h" #include "qsv_internal.h" #include "qsvenc.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" struct profile_names { mfxU16 profile; @@ -2057,7 +2055,7 @@ static int submit_frame(QSVEncContext *q, const AVFrame *frame, } } else { /* make a copy if the input is not padded as libmfx requires */ - /* and to make allocation continious for data[0]/data[1] */ + /* and to make allocation continuous for data[0]/data[1] */ if ((frame->height & (q->height_align - 1) || frame->linesize[0] & (q->width_align - 1)) || ((frame->format == AV_PIX_FMT_NV12 || frame->format == AV_PIX_FMT_P010 || frame->format == AV_PIX_FMT_P012) && (frame->data[1] - frame->data[0] != frame->linesize[0] * FFALIGN(qf->frame->height, q->height_align)))) { @@ -2689,7 +2687,7 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q, if (avctx->codec_id == AV_CODEC_ID_H264) { enc_buf = qpkt.bs->ExtParam; enc_info = (mfxExtAVCEncodedFrameInfo *)(*enc_buf); - ff_side_data_set_encoder_stats(&qpkt.pkt, + ff_encode_add_stats_side_data(&qpkt.pkt, enc_info->QP * FF_QP2LAMBDA, NULL, 0, pict_type); av_freep(&enc_info); av_freep(&enc_buf); @@ -2716,7 +2714,7 @@ int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext *q) ff_qsv_close_internal_session(&q->internal_qs); av_buffer_unref(&q->frames_ctx.hw_frames_ctx); - ff_refstruct_unref(&q->frames_ctx.mids); + av_refstruct_unref(&q->frames_ctx.mids); cur = q->work_frames; while (cur) { diff --git a/libavcodec/qsvenc_av1.c b/libavcodec/qsvenc_av1.c index a86b409be..c7aa6e58d 100644 --- a/libavcodec/qsvenc_av1.c +++ b/libavcodec/qsvenc_av1.c @@ -217,10 +217,7 @@ FFCodec ff_av1_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_P010, - AV_PIX_FMT_QSV, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_QSV), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c index 304d1e7dc..7d39338d6 100644 --- a/libavcodec/qsvenc_h264.c +++ b/libavcodec/qsvenc_h264.c @@ -199,9 +199,7 @@ const FFCodec ff_h264_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_QSV, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_QSV), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qsvenc_hevc.c b/libavcodec/qsvenc_hevc.c index 80fdf782a..ae3981fb7 100644 --- a/libavcodec/qsvenc_hevc.c +++ b/libavcodec/qsvenc_hevc.c @@ -396,17 +396,10 @@ const FFCodec ff_hevc_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_P010, - AV_PIX_FMT_P012, - AV_PIX_FMT_YUYV422, - AV_PIX_FMT_Y210, - AV_PIX_FMT_QSV, - AV_PIX_FMT_BGRA, - AV_PIX_FMT_X2RGB10, - AV_PIX_FMT_VUYX, - AV_PIX_FMT_XV30, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_P012, + AV_PIX_FMT_YUYV422, AV_PIX_FMT_Y210, AV_PIX_FMT_QSV, + AV_PIX_FMT_BGRA, AV_PIX_FMT_X2RGB10, AV_PIX_FMT_VUYX, + AV_PIX_FMT_XV30), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qsvenc_jpeg.c b/libavcodec/qsvenc_jpeg.c index b2458eee0..0e04c2025 100644 --- a/libavcodec/qsvenc_jpeg.c +++ b/libavcodec/qsvenc_jpeg.c @@ -88,11 +88,8 @@ const FFCodec ff_mjpeg_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_YUYV422, - AV_PIX_FMT_BGRA, - AV_PIX_FMT_QSV, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_YUYV422, AV_PIX_FMT_BGRA, + AV_PIX_FMT_QSV), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qsvenc_mpeg2.c b/libavcodec/qsvenc_mpeg2.c index ad3da6d67..c52a2c1f9 100644 --- a/libavcodec/qsvenc_mpeg2.c +++ b/libavcodec/qsvenc_mpeg2.c @@ -102,9 +102,7 @@ const FFCodec ff_mpeg2_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_QSV, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_QSV), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qsvenc_vp9.c b/libavcodec/qsvenc_vp9.c index b247c39c8..db93cca15 100644 --- a/libavcodec/qsvenc_vp9.c +++ b/libavcodec/qsvenc_vp9.c @@ -111,12 +111,8 @@ const FFCodec ff_vp9_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_P010, - AV_PIX_FMT_VUYX, - AV_PIX_FMT_QSV, - AV_PIX_FMT_XV30, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_VUYX, + AV_PIX_FMT_QSV, AV_PIX_FMT_XV30), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c index 9b016d7e8..1c2fbc357 100644 --- a/libavcodec/qtrle.c +++ b/libavcodec/qtrle.c @@ -38,6 +38,8 @@ #include "bytestream.h" #include "codec_internal.h" +#include "libavutil/attributes.h" + typedef struct QtrleContext { AVCodecContext *avctx; AVFrame *frame; @@ -537,15 +539,7 @@ static int qtrle_decode_frame(AVCodecContext *avctx, AVFrame *rframe, } if(has_palette) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif - /* make the palette available on the way out */ memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); } @@ -569,7 +563,7 @@ done: return avpkt->size; } -static void qtrle_decode_flush(AVCodecContext *avctx) +static av_cold void qtrle_decode_flush(AVCodecContext *avctx) { QtrleContext *s = avctx->priv_data; diff --git a/libavcodec/qtrleenc.c b/libavcodec/qtrleenc.c index 71d57d7eb..ae341c60b 100644 --- a/libavcodec/qtrleenc.c +++ b/libavcodec/qtrleenc.c @@ -409,8 +409,7 @@ const FFCodec ff_qtrle_encoder = { .init = qtrle_encode_init, FF_CODEC_ENCODE_CB(qtrle_encode_frame), .close = qtrle_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_ARGB, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_ARGB, + AV_PIX_FMT_GRAY8), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/r210enc.c b/libavcodec/r210enc.c index ec1ebc8d6..b1ade5cde 100644 --- a/libavcodec/r210enc.c +++ b/libavcodec/r210enc.c @@ -99,7 +99,7 @@ const FFCodec ff_r210_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = pix_fmt, + CODEC_PIXFMTS_ARRAY(pix_fmt), }; #endif #if CONFIG_R10K_ENCODER @@ -111,7 +111,7 @@ const FFCodec ff_r10k_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = pix_fmt, + CODEC_PIXFMTS_ARRAY(pix_fmt), }; #endif #if CONFIG_AVRP_ENCODER @@ -123,6 +123,6 @@ const FFCodec ff_avrp_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = pix_fmt, + CODEC_PIXFMTS_ARRAY(pix_fmt), }; #endif diff --git a/libavcodec/ra144enc.c b/libavcodec/ra144enc.c index 92c35ac12..d38c39ce1 100644 --- a/libavcodec/ra144enc.c +++ b/libavcodec/ra144enc.c @@ -546,8 +546,7 @@ const FFCodec ff_ra_144_encoder = { .init = ra144_encode_init, FF_CODEC_ENCODE_CB(ra144_encode_frame), .close = ra144_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]){ 8000, 0 }, - .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, { 0 } }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_SAMPLERATES(8000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), }; diff --git a/libavcodec/ra288.c b/libavcodec/ra288.c index 5b186a7a3..550af7f29 100644 --- a/libavcodec/ra288.c +++ b/libavcodec/ra288.c @@ -37,6 +37,8 @@ #define MAX_BACKWARD_FILTER_ORDER 36 #define MAX_BACKWARD_FILTER_LEN 40 #define MAX_BACKWARD_FILTER_NONREC 35 +#define ATTEN 0.5625 +#include "g728_template.c" #define RA288_BLOCK_SIZE 5 #define RA288_BLOCKS_PER_FRAME 32 @@ -87,13 +89,6 @@ static av_cold int ra288_decode_init(AVCodecContext *avctx) return 0; } -static void convolve(float *tgt, const float *src, int len, int n) -{ - for (; n >= 0; n--) - tgt[n] = avpriv_scalarproduct_float_c(src, src - n, len); - -} - static void decode(RA288Context *ractx, float gain, int cb_coef) { int i; @@ -119,7 +114,7 @@ static void decode(RA288Context *ractx, float gain, int cb_coef) for (i=0; i < 5; i++) buffer[i] = codetable[cb_coef][i] * sumsum; - sum = avpriv_scalarproduct_float_c(buffer, buffer, 5); + sum = ff_scalarproduct_float_c(buffer, buffer, 5); sum = FFMAX(sum, 5.0 / (1<<24)); @@ -131,45 +126,6 @@ static void decode(RA288Context *ractx, float gain, int cb_coef) ff_celp_lp_synthesis_filterf(block, ractx->sp_lpc, buffer, 5, 36); } -/** - * Hybrid window filtering, see blocks 36 and 49 of the G.728 specification. - * - * @param order filter order - * @param n input length - * @param non_rec number of non-recursive samples - * @param out filter output - * @param hist pointer to the input history of the filter - * @param out pointer to the non-recursive part of the output - * @param out2 pointer to the recursive part of the output - * @param window pointer to the windowing function table - */ -static void do_hybrid_window(RA288Context *ractx, - int order, int n, int non_rec, float *out, - float *hist, float *out2, const float *window) -{ - int i; - float buffer1[MAX_BACKWARD_FILTER_ORDER + 1]; - float buffer2[MAX_BACKWARD_FILTER_ORDER + 1]; - LOCAL_ALIGNED(32, float, work, [FFALIGN(MAX_BACKWARD_FILTER_ORDER + - MAX_BACKWARD_FILTER_LEN + - MAX_BACKWARD_FILTER_NONREC, 16)]); - - av_assert2(order>=0); - - ractx->vector_fmul(work, window, hist, FFALIGN(order + n + non_rec, 16)); - - convolve(buffer1, work + order , n , order); - convolve(buffer2, work + order + n, non_rec, order); - - for (i=0; i <= order; i++) { - out2[i] = out2[i] * 0.5625 + buffer1[i]; - out [i] = out2[i] + buffer2[i]; - } - - /* Multiply by the white noise correcting factor (WNCF). */ - *out *= 257.0 / 256.0; -} - /** * Backward synthesis filter, find the LPC coefficients from past speech data. */ @@ -180,9 +136,9 @@ static void backward_filter(RA288Context *ractx, { float temp[MAX_BACKWARD_FILTER_ORDER+1]; - do_hybrid_window(ractx, order, n, non_rec, temp, hist, rec, window); + do_hybrid_window(ractx->vector_fmul, order, n, non_rec, temp, hist, rec, window); - if (!compute_lpc_coefs(temp, order, lpc, 0, 1, 1)) + if (!compute_lpc_coefs(temp, 0, order, lpc, 0, 1, 1, NULL)) ractx->vector_fmul(lpc, lpc, tab, FFALIGN(order, 16)); memmove(hist, hist + n, move_size*sizeof(*hist)); diff --git a/libavcodec/ralf.c b/libavcodec/ralf.c index 36ad51fab..9c28ce580 100644 --- a/libavcodec/ralf.c +++ b/libavcodec/ralf.c @@ -504,7 +504,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, return avpkt->size; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { RALFContext *ctx = avctx->priv_data; @@ -524,7 +524,5 @@ const FFCodec ff_ralf_decoder = { .flush = decode_flush, .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/rangecoder.h b/libavcodec/rangecoder.h index 110908d6b..ee2dba95f 100644 --- a/libavcodec/rangecoder.h +++ b/libavcodec/rangecoder.h @@ -61,25 +61,19 @@ void ff_build_rac_states(RangeCoder *c, int factor, int max_p); static inline void renorm_encoder(RangeCoder *c) { - // FIXME: optimize - if (c->outstanding_byte < 0) { - c->outstanding_byte = c->low >> 8; - } else if (c->low <= 0xFF00) { - *c->bytestream++ = c->outstanding_byte; - for (; c->outstanding_count; c->outstanding_count--) - *c->bytestream++ = 0xFF; - c->outstanding_byte = c->low >> 8; - } else if (c->low >= 0x10000) { - *c->bytestream++ = c->outstanding_byte + 1; - for (; c->outstanding_count; c->outstanding_count--) - *c->bytestream++ = 0x00; - c->outstanding_byte = (c->low >> 8) & 0xFF; - } else { - c->outstanding_count++; - } + if (c->low - 0xFF01 >= 0x10000 - 0xFF01U) { + int mask = c->low - 0xFF01 >> 31; + *c->bytestream = c->outstanding_byte + 1 + mask; + c->bytestream += c->outstanding_byte >= 0; + for (; c->outstanding_count; c->outstanding_count--) + *c->bytestream++ = mask; + c->outstanding_byte = c->low >> 8; + } else { + c->outstanding_count++; + } - c->low = (c->low & 0xFF) << 8; - c->range <<= 8; + c->low = (c->low & 0xFF) << 8; + c->range <<= 8; } static inline int get_rac_count(RangeCoder *c) @@ -106,21 +100,19 @@ static inline void put_rac(RangeCoder *c, uint8_t *const state, int bit) *state = c->one_state[*state]; } - while (c->range < 0x100) + if (c->range < 0x100) renorm_encoder(c); } static inline void refill(RangeCoder *c) { - if (c->range < 0x100) { - c->range <<= 8; - c->low <<= 8; - if (c->bytestream < c->bytestream_end) { - c->low += c->bytestream[0]; - c->bytestream++; - } else - c->overread ++; - } + c->range <<= 8; + c->low <<= 8; + if (c->bytestream < c->bytestream_end) { + c->low += c->bytestream[0]; + c->bytestream++; + } else + c->overread ++; } static inline int get_rac(RangeCoder *c, uint8_t *const state) @@ -130,13 +122,15 @@ static inline int get_rac(RangeCoder *c, uint8_t *const state) c->range -= range1; if (c->low < c->range) { *state = c->zero_state[*state]; - refill(c); + if (c->range < 0x100) + refill(c); return 0; } else { c->low -= c->range; *state = c->one_state[*state]; c->range = range1; - refill(c); + if (c->range < 0x100) + refill(c); return 1; } } diff --git a/libavcodec/rasc.c b/libavcodec/rasc.c index 4f5a30092..5f956a9b2 100644 --- a/libavcodec/rasc.c +++ b/libavcodec/rasc.c @@ -781,7 +781,7 @@ static av_cold int decode_close(AVCodecContext *avctx) return 0; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { RASCContext *s = avctx->priv_data; diff --git a/libavcodec/ratecontrol.c b/libavcodec/ratecontrol.c index 86ec7a344..d48ede909 100644 --- a/libavcodec/ratecontrol.c +++ b/libavcodec/ratecontrol.c @@ -26,7 +26,6 @@ */ #include "libavutil/attributes.h" -#include "libavutil/emms.h" #include "libavutil/internal.h" #include "libavutil/mem.h" @@ -35,25 +34,26 @@ #include "mpegvideoenc.h" #include "libavutil/eval.h" -void ff_write_pass1_stats(MpegEncContext *s) +void ff_write_pass1_stats(MPVMainEncContext *const m) { - snprintf(s->avctx->stats_out, 256, + const MPVEncContext *const s = &m->s; + snprintf(s->c.avctx->stats_out, 256, "in:%d out:%d type:%d q:%d itex:%d ptex:%d mv:%d misc:%d " "fcode:%d bcode:%d mc-var:%"PRId64" var:%"PRId64" icount:%d hbits:%d;\n", - s->cur_pic.ptr->display_picture_number, - s->cur_pic.ptr->coded_picture_number, - s->pict_type, - s->cur_pic.ptr->f->quality, + s->c.cur_pic.ptr->display_picture_number, + s->c.cur_pic.ptr->coded_picture_number, + s->c.pict_type, + s->c.cur_pic.ptr->f->quality, s->i_tex_bits, s->p_tex_bits, s->mv_bits, s->misc_bits, s->f_code, s->b_code, - s->mc_mb_var_sum, - s->mb_var_sum, + m->mc_mb_var_sum, + m->mb_var_sum, s->i_count, - s->header_bits); + m->header_bits); } static AVRational get_fpsQ(AVCodecContext *avctx) @@ -61,13 +61,7 @@ static AVRational get_fpsQ(AVCodecContext *avctx) if (avctx->framerate.num > 0 && avctx->framerate.den > 0) return avctx->framerate; -FF_DISABLE_DEPRECATION_WARNINGS -#if FF_API_TICKS_PER_FRAME - return av_div_q((AVRational){1, FFMAX(avctx->ticks_per_frame, 1)}, avctx->time_base); -#else return av_inv_q(avctx->time_base); -#endif -FF_ENABLE_DEPRECATION_WARNINGS } static double get_fps(AVCodecContext *avctx) @@ -101,10 +95,11 @@ static double bits2qp_cb(void *rce, double qp) return bits2qp(rce, qp); } -static double get_diff_limited_q(MpegEncContext *s, const RateControlEntry *rce, double q) +static double get_diff_limited_q(MPVMainEncContext *m, const RateControlEntry *rce, double q) { - RateControlContext *rcc = &s->rc_context; - AVCodecContext *a = s->avctx; + MPVEncContext *const s = &m->s; + RateControlContext *const rcc = &m->rc_context; + AVCodecContext *const a = s->c.avctx; const int pict_type = rce->new_pict_type; const double last_p_q = rcc->last_qscale_for[AV_PICTURE_TYPE_P]; const double last_non_b_q = rcc->last_qscale_for[rcc->last_non_b_pict_type]; @@ -140,21 +135,22 @@ static double get_diff_limited_q(MpegEncContext *s, const RateControlEntry *rce, /** * Get the qmin & qmax for pict_type. */ -static void get_qminmax(int *qmin_ret, int *qmax_ret, MpegEncContext *s, int pict_type) +static void get_qminmax(int *qmin_ret, int *qmax_ret, MPVMainEncContext *const m, int pict_type) { - int qmin = s->lmin; - int qmax = s->lmax; + MPVEncContext *const s = &m->s; + int qmin = m->lmin; + int qmax = m->lmax; av_assert0(qmin <= qmax); switch (pict_type) { case AV_PICTURE_TYPE_B: - qmin = (int)(qmin * FFABS(s->avctx->b_quant_factor) + s->avctx->b_quant_offset + 0.5); - qmax = (int)(qmax * FFABS(s->avctx->b_quant_factor) + s->avctx->b_quant_offset + 0.5); + qmin = (int)(qmin * FFABS(s->c.avctx->b_quant_factor) + s->c.avctx->b_quant_offset + 0.5); + qmax = (int)(qmax * FFABS(s->c.avctx->b_quant_factor) + s->c.avctx->b_quant_offset + 0.5); break; case AV_PICTURE_TYPE_I: - qmin = (int)(qmin * FFABS(s->avctx->i_quant_factor) + s->avctx->i_quant_offset + 0.5); - qmax = (int)(qmax * FFABS(s->avctx->i_quant_factor) + s->avctx->i_quant_offset + 0.5); + qmin = (int)(qmin * FFABS(s->c.avctx->i_quant_factor) + s->c.avctx->i_quant_offset + 0.5); + qmax = (int)(qmax * FFABS(s->c.avctx->i_quant_factor) + s->c.avctx->i_quant_offset + 0.5); break; } @@ -168,24 +164,25 @@ static void get_qminmax(int *qmin_ret, int *qmax_ret, MpegEncContext *s, int pic *qmax_ret = qmax; } -static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce, +static double modify_qscale(MPVMainEncContext *const m, const RateControlEntry *rce, double q, int frame_num) { - RateControlContext *rcc = &s->rc_context; - const double buffer_size = s->avctx->rc_buffer_size; - const double fps = get_fps(s->avctx); - const double min_rate = s->avctx->rc_min_rate / fps; - const double max_rate = s->avctx->rc_max_rate / fps; + MPVEncContext *const s = &m->s; + RateControlContext *const rcc = &m->rc_context; + const double buffer_size = s->c.avctx->rc_buffer_size; + const double fps = get_fps(s->c.avctx); + const double min_rate = s->c.avctx->rc_min_rate / fps; + const double max_rate = s->c.avctx->rc_max_rate / fps; const int pict_type = rce->new_pict_type; int qmin, qmax; - get_qminmax(&qmin, &qmax, s, pict_type); + get_qminmax(&qmin, &qmax, m, pict_type); /* modulation */ - if (s->rc_qmod_freq && - frame_num % s->rc_qmod_freq == 0 && + if (rcc->qmod_freq && + frame_num % rcc->qmod_freq == 0 && pict_type == AV_PICTURE_TYPE_P) - q *= s->rc_qmod_amp; + q *= rcc->qmod_amp; /* buffer overflow/underflow protection */ if (buffer_size) { @@ -198,15 +195,15 @@ static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce, d = 1.0; else if (d < 0.0001) d = 0.0001; - q *= pow(d, 1.0 / s->rc_buffer_aggressivity); + q *= pow(d, 1.0 / rcc->buffer_aggressivity); q_limit = bits2qp(rce, FFMAX((min_rate - buffer_size + rcc->buffer_index) * - s->avctx->rc_min_vbv_overflow_use, 1)); + s->c.avctx->rc_min_vbv_overflow_use, 1)); if (q > q_limit) { - if (s->avctx->debug & FF_DEBUG_RC) - av_log(s->avctx, AV_LOG_DEBUG, + if (s->c.avctx->debug & FF_DEBUG_RC) + av_log(s->c.avctx, AV_LOG_DEBUG, "limiting QP %f -> %f\n", q, q_limit); q = q_limit; } @@ -218,24 +215,24 @@ static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce, d = 1.0; else if (d < 0.0001) d = 0.0001; - q /= pow(d, 1.0 / s->rc_buffer_aggressivity); + q /= pow(d, 1.0 / rcc->buffer_aggressivity); q_limit = bits2qp(rce, FFMAX(rcc->buffer_index * - s->avctx->rc_max_available_vbv_use, + s->c.avctx->rc_max_available_vbv_use, 1)); if (q < q_limit) { - if (s->avctx->debug & FF_DEBUG_RC) - av_log(s->avctx, AV_LOG_DEBUG, + if (s->c.avctx->debug & FF_DEBUG_RC) + av_log(s->c.avctx, AV_LOG_DEBUG, "limiting QP %f -> %f\n", q, q_limit); q = q_limit; } } } - ff_dlog(s, "q:%f max:%f min:%f size:%f index:%f agr:%f\n", + ff_dlog(s->c.avctx, "q:%f max:%f min:%f size:%f index:%f agr:%f\n", q, max_rate, min_rate, buffer_size, rcc->buffer_index, - s->rc_buffer_aggressivity); - if (s->rc_qsquish == 0.0 || qmin == qmax) { + rcc->buffer_aggressivity); + if (rcc->qsquish == 0.0 || qmin == qmax) { if (q < qmin) q = qmin; else if (q > qmax) @@ -259,13 +256,14 @@ static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce, /** * Modify the bitrate curve from pass1 for one frame. */ -static double get_qscale(MpegEncContext *s, RateControlEntry *rce, +static double get_qscale(MPVMainEncContext *const m, RateControlEntry *rce, double rate_factor, int frame_num) { - RateControlContext *rcc = &s->rc_context; - AVCodecContext *a = s->avctx; + MPVEncContext *const s = &m->s; + RateControlContext *rcc = &m->rc_context; + AVCodecContext *const avctx = s->c.avctx; const int pict_type = rce->new_pict_type; - const double mb_num = s->mb_num; + const double mb_num = s->c.mb_num; double q, bits; int i; @@ -284,7 +282,7 @@ static double get_qscale(MpegEncContext *s, RateControlEntry *rce, rce->pict_type == AV_PICTURE_TYPE_P, rce->pict_type == AV_PICTURE_TYPE_B, rcc->qscale_sum[pict_type] / (double)rcc->frame_count[pict_type], - a->qcompress, + avctx->qcompress, rcc->i_cplx_sum[AV_PICTURE_TYPE_I] / (double)rcc->frame_count[AV_PICTURE_TYPE_I], rcc->i_cplx_sum[AV_PICTURE_TYPE_P] / (double)rcc->frame_count[AV_PICTURE_TYPE_P], rcc->p_cplx_sum[AV_PICTURE_TYPE_P] / (double)rcc->frame_count[AV_PICTURE_TYPE_P], @@ -295,7 +293,7 @@ static double get_qscale(MpegEncContext *s, RateControlEntry *rce, bits = av_expr_eval(rcc->rc_eq_eval, const_values, rce); if (isnan(bits)) { - av_log(s->avctx, AV_LOG_ERROR, "Error evaluating rc_eq \"%s\"\n", s->rc_eq); + av_log(avctx, AV_LOG_ERROR, "Error evaluating rc_eq \"%s\"\n", rcc->rc_eq); return -1; } @@ -306,8 +304,8 @@ static double get_qscale(MpegEncContext *s, RateControlEntry *rce, bits += 1.0; // avoid 1/0 issues /* user override */ - for (i = 0; i < s->avctx->rc_override_count; i++) { - RcOverride *rco = s->avctx->rc_override; + for (i = 0; i < avctx->rc_override_count; i++) { + RcOverride *rco = avctx->rc_override; if (rco[i].start_frame > frame_num) continue; if (rco[i].end_frame < frame_num) @@ -322,31 +320,32 @@ static double get_qscale(MpegEncContext *s, RateControlEntry *rce, q = bits2qp(rce, bits); /* I/B difference */ - if (pict_type == AV_PICTURE_TYPE_I && s->avctx->i_quant_factor < 0.0) - q = -q * s->avctx->i_quant_factor + s->avctx->i_quant_offset; - else if (pict_type == AV_PICTURE_TYPE_B && s->avctx->b_quant_factor < 0.0) - q = -q * s->avctx->b_quant_factor + s->avctx->b_quant_offset; + if (pict_type == AV_PICTURE_TYPE_I && avctx->i_quant_factor < 0.0) + q = -q * avctx->i_quant_factor + avctx->i_quant_offset; + else if (pict_type == AV_PICTURE_TYPE_B && avctx->b_quant_factor < 0.0) + q = -q * avctx->b_quant_factor + avctx->b_quant_offset; if (q < 1) q = 1; return q; } -static int init_pass2(MpegEncContext *s) +static int init_pass2(MPVMainEncContext *const m) { - RateControlContext *rcc = &s->rc_context; - AVCodecContext *a = s->avctx; + RateControlContext *const rcc = &m->rc_context; + MPVEncContext *const s = &m->s; + AVCodecContext *const avctx = s->c.avctx; int i, toobig; - AVRational fps = get_fpsQ(s->avctx); + AVRational fps = get_fpsQ(avctx); double complexity[5] = { 0 }; // approximate bits at quant=1 uint64_t const_bits[5] = { 0 }; // quantizer independent bits uint64_t all_const_bits; - uint64_t all_available_bits = av_rescale_q(s->bit_rate, + uint64_t all_available_bits = av_rescale_q(m->bit_rate, (AVRational){rcc->num_entries,1}, fps); double rate_factor = 0; double step; - const int filter_size = (int)(a->qblur * 4) | 1; + const int filter_size = (int)(avctx->qblur * 4) | 1; double expected_bits = 0; // init to silence gcc warning double *qscale, *blurred_qscale, qscale_sum; @@ -370,7 +369,7 @@ static int init_pass2(MpegEncContext *s) const_bits[AV_PICTURE_TYPE_B]; if (all_available_bits < all_const_bits) { - av_log(s->avctx, AV_LOG_ERROR, "requested bitrate is too low\n"); + av_log(avctx, AV_LOG_ERROR, "requested bitrate is too low\n"); return -1; } @@ -387,13 +386,13 @@ static int init_pass2(MpegEncContext *s) expected_bits = 0; rate_factor += step; - rcc->buffer_index = s->avctx->rc_buffer_size / 2; + rcc->buffer_index = avctx->rc_buffer_size / 2; /* find qscale */ for (i = 0; i < rcc->num_entries; i++) { const RateControlEntry *rce = &rcc->entry[i]; - qscale[i] = get_qscale(s, &rcc->entry[i], rate_factor, i); + qscale[i] = get_qscale(m, &rcc->entry[i], rate_factor, i); rcc->last_qscale_for[rce->pict_type] = qscale[i]; } av_assert0(filter_size % 2 == 1); @@ -402,13 +401,13 @@ static int init_pass2(MpegEncContext *s) for (i = FFMAX(0, rcc->num_entries - 300); i < rcc->num_entries; i++) { const RateControlEntry *rce = &rcc->entry[i]; - qscale[i] = get_diff_limited_q(s, rce, qscale[i]); + qscale[i] = get_diff_limited_q(m, rce, qscale[i]); } for (i = rcc->num_entries - 1; i >= 0; i--) { const RateControlEntry *rce = &rcc->entry[i]; - qscale[i] = get_diff_limited_q(s, rce, qscale[i]); + qscale[i] = get_diff_limited_q(m, rce, qscale[i]); } /* smooth curve */ @@ -421,7 +420,7 @@ static int init_pass2(MpegEncContext *s) for (j = 0; j < filter_size; j++) { int index = i + j - filter_size / 2; double d = index - i; - double coeff = a->qblur == 0 ? 1.0 : exp(-d * d / (a->qblur * a->qblur)); + double coeff = avctx->qblur == 0 ? 1.0 : exp(-d * d / (avctx->qblur * avctx->qblur)); if (index < 0 || index >= rcc->num_entries) continue; @@ -438,16 +437,16 @@ static int init_pass2(MpegEncContext *s) RateControlEntry *rce = &rcc->entry[i]; double bits; - rce->new_qscale = modify_qscale(s, rce, blurred_qscale[i], i); + rce->new_qscale = modify_qscale(m, rce, blurred_qscale[i], i); bits = qp2bits(rce, rce->new_qscale) + rce->mv_bits + rce->misc_bits; - bits += 8 * ff_vbv_update(s, bits); + bits += 8 * ff_vbv_update(m, bits); rce->expected_bits = expected_bits; expected_bits += bits; } - ff_dlog(s->avctx, + ff_dlog(avctx, "expected_bits: %f all_available_bits: %d rate_factor: %f\n", expected_bits, (int)all_available_bits, rate_factor); if (expected_bits > all_available_bits) { @@ -461,32 +460,32 @@ static int init_pass2(MpegEncContext *s) /* check bitrate calculations and print info */ qscale_sum = 0.0; for (i = 0; i < rcc->num_entries; i++) { - ff_dlog(s, "[lavc rc] entry[%d].new_qscale = %.3f qp = %.3f\n", + ff_dlog(avctx, "[lavc rc] entry[%d].new_qscale = %.3f qp = %.3f\n", i, rcc->entry[i].new_qscale, rcc->entry[i].new_qscale / FF_QP2LAMBDA); qscale_sum += av_clip(rcc->entry[i].new_qscale / FF_QP2LAMBDA, - s->avctx->qmin, s->avctx->qmax); + avctx->qmin, avctx->qmax); } av_assert0(toobig <= 40); - av_log(s->avctx, AV_LOG_DEBUG, + av_log(avctx, AV_LOG_DEBUG, "[lavc rc] requested bitrate: %"PRId64" bps expected bitrate: %"PRId64" bps\n", - s->bit_rate, - (int64_t)(expected_bits / ((double)all_available_bits / s->bit_rate))); - av_log(s->avctx, AV_LOG_DEBUG, + m->bit_rate, + (int64_t)(expected_bits / ((double)all_available_bits / m->bit_rate))); + av_log(avctx, AV_LOG_DEBUG, "[lavc rc] estimated target average qp: %.3f\n", (float)qscale_sum / rcc->num_entries); if (toobig == 0) { - av_log(s->avctx, AV_LOG_INFO, + av_log(avctx, AV_LOG_INFO, "[lavc rc] Using all of requested bitrate is not " "necessary for this video with these parameters.\n"); } else if (toobig == 40) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(avctx, AV_LOG_ERROR, "[lavc rc] Error: bitrate too low for this video " "with these parameters.\n"); return -1; } else if (fabs(expected_bits / all_available_bits - 1.0) > 0.01) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(avctx, AV_LOG_ERROR, "[lavc rc] Error: 2pass curve failed to converge\n"); return -1; } @@ -494,9 +493,11 @@ static int init_pass2(MpegEncContext *s) return 0; } -av_cold int ff_rate_control_init(MpegEncContext *s) +av_cold int ff_rate_control_init(MPVMainEncContext *const m) { - RateControlContext *rcc = &s->rc_context; + MPVEncContext *const s = &m->s; + RateControlContext *rcc = &m->rc_context; + AVCodecContext *const avctx = s->c.avctx; int i, res; static const char * const const_names[] = { "PI", @@ -531,21 +532,20 @@ av_cold int ff_rate_control_init(MpegEncContext *s) "qp2bits", NULL }; - emms_c(); - if (!s->avctx->rc_max_available_vbv_use && s->avctx->rc_buffer_size) { - if (s->avctx->rc_max_rate) { - s->avctx->rc_max_available_vbv_use = av_clipf(s->avctx->rc_max_rate/(s->avctx->rc_buffer_size*get_fps(s->avctx)), 1.0/3, 1.0); + if (!avctx->rc_max_available_vbv_use && avctx->rc_buffer_size) { + if (avctx->rc_max_rate) { + avctx->rc_max_available_vbv_use = av_clipf(avctx->rc_max_rate/(avctx->rc_buffer_size*get_fps(avctx)), 1.0/3, 1.0); } else - s->avctx->rc_max_available_vbv_use = 1.0; + avctx->rc_max_available_vbv_use = 1.0; } res = av_expr_parse(&rcc->rc_eq_eval, - s->rc_eq ? s->rc_eq : "tex^qComp", + rcc->rc_eq ? rcc->rc_eq : "tex^qComp", const_names, func1_names, func1, - NULL, NULL, 0, s->avctx); + NULL, NULL, 0, avctx); if (res < 0) { - av_log(s->avctx, AV_LOG_ERROR, "Error parsing rc_eq \"%s\"\n", s->rc_eq); + av_log(avctx, AV_LOG_ERROR, "Error parsing rc_eq \"%s\"\n", rcc->rc_eq); return res; } @@ -562,19 +562,19 @@ av_cold int ff_rate_control_init(MpegEncContext *s) rcc->last_qscale_for[i] = FF_QP2LAMBDA * 5; } - rcc->buffer_index = s->avctx->rc_initial_buffer_occupancy; + rcc->buffer_index = avctx->rc_initial_buffer_occupancy; if (!rcc->buffer_index) - rcc->buffer_index = s->avctx->rc_buffer_size * 3 / 4; + rcc->buffer_index = avctx->rc_buffer_size * 3 / 4; - if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { + if (avctx->flags & AV_CODEC_FLAG_PASS2) { int i; char *p; /* find number of pics */ - p = s->avctx->stats_in; + p = avctx->stats_in; for (i = -1; p; i++) p = strchr(p + 1, ';'); - i += s->max_b_frames; + i += m->max_b_frames; if (i <= 0 || i >= INT_MAX / sizeof(RateControlEntry)) return -1; rcc->entry = av_mallocz(i * sizeof(RateControlEntry)); @@ -589,13 +589,13 @@ av_cold int ff_rate_control_init(MpegEncContext *s) rce->pict_type = rce->new_pict_type = AV_PICTURE_TYPE_P; rce->qscale = rce->new_qscale = FF_QP2LAMBDA * 2; - rce->misc_bits = s->mb_num + 10; - rce->mb_var_sum = s->mb_num * 100; + rce->misc_bits = s->c.mb_num + 10; + rce->mb_var_sum = s->c.mb_num * 100; } /* read stats */ - p = s->avctx->stats_in; - for (i = 0; i < rcc->num_entries - s->max_b_frames; i++) { + p = avctx->stats_in; + for (i = 0; i < rcc->num_entries - m->max_b_frames; i++) { RateControlEntry *rce; int picture_number; int e; @@ -623,7 +623,7 @@ av_cold int ff_rate_control_init(MpegEncContext *s) &rce->mc_mb_var_sum, &rce->mb_var_sum, &rce->i_count, &rce->header_bits); if (e != 13) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(avctx, AV_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e); return -1; @@ -632,46 +632,46 @@ av_cold int ff_rate_control_init(MpegEncContext *s) p = next; } - res = init_pass2(s); + res = init_pass2(m); if (res < 0) return res; } - if (!(s->avctx->flags & AV_CODEC_FLAG_PASS2)) { + if (!(avctx->flags & AV_CODEC_FLAG_PASS2)) { rcc->short_term_qsum = 0.001; rcc->short_term_qcount = 0.001; rcc->pass1_rc_eq_output_sum = 0.001; rcc->pass1_wanted_bits = 0.001; - if (s->avctx->qblur > 1.0) { - av_log(s->avctx, AV_LOG_ERROR, "qblur too large\n"); + if (avctx->qblur > 1.0) { + av_log(avctx, AV_LOG_ERROR, "qblur too large\n"); return -1; } /* init stuff with the user specified complexity */ - if (s->rc_initial_cplx) { + if (rcc->initial_cplx) { for (i = 0; i < 60 * 30; i++) { - double bits = s->rc_initial_cplx * (i / 10000.0 + 1.0) * s->mb_num; + double bits = rcc->initial_cplx * (i / 10000.0 + 1.0) * s->c.mb_num; RateControlEntry rce; - if (i % ((s->gop_size + 3) / 4) == 0) + if (i % ((m->gop_size + 3) / 4) == 0) rce.pict_type = AV_PICTURE_TYPE_I; - else if (i % (s->max_b_frames + 1)) + else if (i % (m->max_b_frames + 1)) rce.pict_type = AV_PICTURE_TYPE_B; else rce.pict_type = AV_PICTURE_TYPE_P; rce.new_pict_type = rce.pict_type; - rce.mc_mb_var_sum = bits * s->mb_num / 100000; - rce.mb_var_sum = s->mb_num; + rce.mc_mb_var_sum = bits * s->c.mb_num / 100000; + rce.mb_var_sum = s->c.mb_num; rce.qscale = FF_QP2LAMBDA * 2; rce.f_code = 2; rce.b_code = 1; rce.misc_bits = 1; - if (s->pict_type == AV_PICTURE_TYPE_I) { - rce.i_count = s->mb_num; + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + rce.i_count = s->c.mb_num; rce.i_tex_bits = bits; rce.p_tex_bits = 0; rce.mv_bits = 0; @@ -686,35 +686,46 @@ av_cold int ff_rate_control_init(MpegEncContext *s) rcc->mv_bits_sum[rce.pict_type] += rce.mv_bits; rcc->frame_count[rce.pict_type]++; - get_qscale(s, &rce, rcc->pass1_wanted_bits / rcc->pass1_rc_eq_output_sum, i); + get_qscale(m, &rce, rcc->pass1_wanted_bits / rcc->pass1_rc_eq_output_sum, i); // FIXME misbehaves a little for variable fps - rcc->pass1_wanted_bits += s->bit_rate / get_fps(s->avctx); + rcc->pass1_wanted_bits += m->bit_rate / get_fps(avctx); } } } + if (s->adaptive_quant) { + unsigned mb_array_size = s->c.mb_stride * s->c.mb_height; + + rcc->cplx_tab = av_malloc_array(mb_array_size, 2 * sizeof(*rcc->cplx_tab)); + if (!rcc->cplx_tab) + return AVERROR(ENOMEM); + rcc->bits_tab = rcc->cplx_tab + mb_array_size; + } + return 0; } av_cold void ff_rate_control_uninit(RateControlContext *rcc) { - emms_c(); - + // rc_eq is always managed via an AVOption and therefore not freed here. av_expr_free(rcc->rc_eq_eval); rcc->rc_eq_eval = NULL; av_freep(&rcc->entry); + av_freep(&rcc->cplx_tab); } -int ff_vbv_update(MpegEncContext *s, int frame_size) +int ff_vbv_update(MPVMainEncContext *m, int frame_size) { - RateControlContext *rcc = &s->rc_context; - const double fps = get_fps(s->avctx); - const int buffer_size = s->avctx->rc_buffer_size; - const double min_rate = s->avctx->rc_min_rate / fps; - const double max_rate = s->avctx->rc_max_rate / fps; + MPVEncContext *const s = &m->s; + RateControlContext *const rcc = &m->rc_context; + AVCodecContext *const avctx = s->c.avctx; + const double fps = get_fps(avctx); + const int buffer_size = avctx->rc_buffer_size; + const double min_rate = avctx->rc_min_rate / fps; + const double max_rate = avctx->rc_max_rate / fps; - ff_dlog(s, "%d %f %d %f %f\n", + ff_dlog(avctx, "%d %f %d %f %f\n", buffer_size, rcc->buffer_index, frame_size, min_rate, max_rate); if (buffer_size) { @@ -722,9 +733,9 @@ int ff_vbv_update(MpegEncContext *s, int frame_size) rcc->buffer_index -= frame_size; if (rcc->buffer_index < 0) { - av_log(s->avctx, AV_LOG_ERROR, "rc buffer underflow\n"); - if (frame_size > max_rate && s->qscale == s->avctx->qmax) { - av_log(s->avctx, AV_LOG_ERROR, "max bitrate possibly too small or try trellis with large lmax or increase qmax\n"); + av_log(avctx, AV_LOG_ERROR, "rc buffer underflow\n"); + if (frame_size > max_rate && s->c.qscale == avctx->qmax) { + av_log(avctx, AV_LOG_ERROR, "max bitrate possibly too small or try trellis with large lmax or increase qmax\n"); } rcc->buffer_index = 0; } @@ -735,12 +746,12 @@ int ff_vbv_update(MpegEncContext *s, int frame_size) if (rcc->buffer_index > buffer_size) { int stuffing = ceil((rcc->buffer_index - buffer_size) / 8); - if (stuffing < 4 && s->codec_id == AV_CODEC_ID_MPEG4) + if (stuffing < 4 && s->c.codec_id == AV_CODEC_ID_MPEG4) stuffing = 4; rcc->buffer_index -= 8 * stuffing; - if (s->avctx->debug & FF_DEBUG_RC) - av_log(s->avctx, AV_LOG_DEBUG, "stuffing %d bytes\n", stuffing); + if (avctx->debug & FF_DEBUG_RC) + av_log(avctx, AV_LOG_DEBUG, "stuffing %d bytes\n", stuffing); return stuffing; } @@ -765,32 +776,33 @@ static void update_predictor(Predictor *p, double q, double var, double size) p->coeff += new_coeff; } -static void adaptive_quantization(MpegEncContext *s, double q) +static void adaptive_quantization(RateControlContext *const rcc, + MPVMainEncContext *const m, double q) { - int i; - const float lumi_masking = s->avctx->lumi_masking / (128.0 * 128.0); - const float dark_masking = s->avctx->dark_masking / (128.0 * 128.0); - const float temp_cplx_masking = s->avctx->temporal_cplx_masking; - const float spatial_cplx_masking = s->avctx->spatial_cplx_masking; - const float p_masking = s->avctx->p_masking; - const float border_masking = s->border_masking; + MPVEncContext *const s = &m->s; + const float lumi_masking = s->c.avctx->lumi_masking / (128.0 * 128.0); + const float dark_masking = s->c.avctx->dark_masking / (128.0 * 128.0); + const float temp_cplx_masking = s->c.avctx->temporal_cplx_masking; + const float spatial_cplx_masking = s->c.avctx->spatial_cplx_masking; + const float p_masking = s->c.avctx->p_masking; + const float border_masking = m->border_masking; float bits_sum = 0.0; float cplx_sum = 0.0; - float *cplx_tab = s->cplx_tab; - float *bits_tab = s->bits_tab; - const int qmin = s->avctx->mb_lmin; - const int qmax = s->avctx->mb_lmax; - const int mb_width = s->mb_width; - const int mb_height = s->mb_height; + float *cplx_tab = rcc->cplx_tab; + float *bits_tab = rcc->bits_tab; + const int qmin = s->c.avctx->mb_lmin; + const int qmax = s->c.avctx->mb_lmax; + const int mb_width = s->c.mb_width; + const int mb_height = s->c.mb_height; - for (i = 0; i < s->mb_num; i++) { - const int mb_xy = s->mb_index2xy[i]; + for (int i = 0; i < s->c.mb_num; i++) { + const int mb_xy = s->c.mb_index2xy[i]; float temp_cplx = sqrt(s->mc_mb_var[mb_xy]); // FIXME merge in pow() float spat_cplx = sqrt(s->mb_var[mb_xy]); const int lumi = s->mb_mean[mb_xy]; float bits, cplx, factor; - int mb_x = mb_xy % s->mb_stride; - int mb_y = mb_xy / s->mb_stride; + int mb_x = mb_xy % s->c.mb_stride; + int mb_y = mb_xy / s->c.mb_stride; int mb_distance; float mb_factor = 0.0; if (spat_cplx < 4) @@ -844,7 +856,7 @@ static void adaptive_quantization(MpegEncContext *s, double q) /* handle qmin/qmax clipping */ if (s->mpv_flags & FF_MPV_FLAG_NAQ) { float factor = bits_sum / cplx_sum; - for (i = 0; i < s->mb_num; i++) { + for (int i = 0; i < s->c.mb_num; i++) { float newq = q * cplx_tab[i] / bits_tab[i]; newq *= factor; @@ -862,8 +874,8 @@ static void adaptive_quantization(MpegEncContext *s, double q) cplx_sum = 0.001; } - for (i = 0; i < s->mb_num; i++) { - const int mb_xy = s->mb_index2xy[i]; + for (int i = 0; i < s->c.mb_num; i++) { + const int mb_xy = s->c.mb_index2xy[i]; float newq = q * cplx_tab[i] / bits_tab[i]; int intq; @@ -881,9 +893,10 @@ static void adaptive_quantization(MpegEncContext *s, double q) } } -void ff_get_2pass_fcode(MpegEncContext *s) +void ff_get_2pass_fcode(MPVMainEncContext *const m) { - const RateControlContext *rcc = &s->rc_context; + MPVEncContext *const s = &m->s; + const RateControlContext *rcc = &m->rc_context; const RateControlEntry *rce = &rcc->entry[s->picture_number]; s->f_code = rce->f_code; @@ -892,8 +905,11 @@ void ff_get_2pass_fcode(MpegEncContext *s) // FIXME rd or at least approx for dquant -float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) +float ff_rate_estimate_qscale(MPVMainEncContext *const m, int dry_run) { + MPVEncContext *const s = &m->s; + RateControlContext *rcc = &m->rc_context; + AVCodecContext *const a = s->c.avctx; float q; int qmin, qmax; float br_compensation; @@ -902,34 +918,31 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) double fps; int picture_number = s->picture_number; int64_t wanted_bits; - RateControlContext *rcc = &s->rc_context; - AVCodecContext *a = s->avctx; RateControlEntry local_rce, *rce; double bits; double rate_factor; int64_t var; - const int pict_type = s->pict_type; - emms_c(); + const int pict_type = s->c.pict_type; - get_qminmax(&qmin, &qmax, s, pict_type); + get_qminmax(&qmin, &qmax, m, pict_type); - fps = get_fps(s->avctx); + fps = get_fps(s->c.avctx); /* update predictors */ if (picture_number > 2 && !dry_run) { const int64_t last_var = - s->last_pict_type == AV_PICTURE_TYPE_I ? rcc->last_mb_var_sum + m->last_pict_type == AV_PICTURE_TYPE_I ? rcc->last_mb_var_sum : rcc->last_mc_mb_var_sum; - av_assert1(s->frame_bits >= s->stuffing_bits); - update_predictor(&rcc->pred[s->last_pict_type], + av_assert1(m->frame_bits >= m->stuffing_bits); + update_predictor(&rcc->pred[m->last_pict_type], rcc->last_qscale, sqrt(last_var), - s->frame_bits - s->stuffing_bits); + m->frame_bits - m->stuffing_bits); } - if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { + if (s->c.avctx->flags & AV_CODEC_FLAG_PASS2) { av_assert0(picture_number >= 0); if (picture_number >= rcc->num_entries) { - av_log(s, AV_LOG_ERROR, "Input is longer than 2-pass log file\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "Input is longer than 2-pass log file\n"); return -1; } rce = &rcc->entry[picture_number]; @@ -942,42 +955,42 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) /* FIXME add a dts field to AVFrame and ensure it is set and use it * here instead of reordering but the reordering is simpler for now * until H.264 B-pyramid must be handled. */ - if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) - dts_pic = s->cur_pic.ptr; + if (s->c.pict_type == AV_PICTURE_TYPE_B || s->c.low_delay) + dts_pic = s->c.cur_pic.ptr; else - dts_pic = s->last_pic.ptr; + dts_pic = s->c.last_pic.ptr; if (!dts_pic || dts_pic->f->pts == AV_NOPTS_VALUE) - wanted_bits_double = s->bit_rate * (double)picture_number / fps; + wanted_bits_double = m->bit_rate * (double)picture_number / fps; else - wanted_bits_double = s->bit_rate * (double)dts_pic->f->pts / fps; + wanted_bits_double = m->bit_rate * (double)dts_pic->f->pts / fps; if (wanted_bits_double > INT64_MAX) { - av_log(s, AV_LOG_WARNING, "Bits exceed 64bit range\n"); + av_log(s->c.avctx, AV_LOG_WARNING, "Bits exceed 64bit range\n"); wanted_bits = INT64_MAX; } else wanted_bits = (int64_t)wanted_bits_double; } - diff = s->total_bits - wanted_bits; + diff = m->total_bits - wanted_bits; br_compensation = (a->bit_rate_tolerance - diff) / a->bit_rate_tolerance; if (br_compensation <= 0.0) br_compensation = 0.001; - var = pict_type == AV_PICTURE_TYPE_I ? s->mb_var_sum : s->mc_mb_var_sum; + var = pict_type == AV_PICTURE_TYPE_I ? m->mb_var_sum : m->mc_mb_var_sum; short_term_q = 0; /* avoid warning */ - if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { + if (s->c.avctx->flags & AV_CODEC_FLAG_PASS2) { if (pict_type != AV_PICTURE_TYPE_I) av_assert0(pict_type == rce->new_pict_type); q = rce->new_qscale / br_compensation; - ff_dlog(s, "%f %f %f last:%d var:%"PRId64" type:%d//\n", q, rce->new_qscale, - br_compensation, s->frame_bits, var, pict_type); + ff_dlog(s->c.avctx, "%f %f %f last:%d var:%"PRId64" type:%d//\n", q, rce->new_qscale, + br_compensation, m->frame_bits, var, pict_type); } else { rce->pict_type = rce->new_pict_type = pict_type; - rce->mc_mb_var_sum = s->mc_mb_var_sum; - rce->mb_var_sum = s->mb_var_sum; + rce->mc_mb_var_sum = m->mc_mb_var_sum; + rce->mb_var_sum = m->mb_var_sum; rce->qscale = FF_QP2LAMBDA * 2; rce->f_code = s->f_code; rce->b_code = s->b_code; @@ -985,7 +998,7 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) bits = predict_size(&rcc->pred[pict_type], rce->qscale, sqrt(var)); if (pict_type == AV_PICTURE_TYPE_I) { - rce->i_count = s->mb_num; + rce->i_count = s->c.mb_num; rce->i_tex_bits = bits; rce->p_tex_bits = 0; rce->mv_bits = 0; @@ -1003,16 +1016,16 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) rate_factor = rcc->pass1_wanted_bits / rcc->pass1_rc_eq_output_sum * br_compensation; - q = get_qscale(s, rce, rate_factor, picture_number); + q = get_qscale(m, rce, rate_factor, picture_number); if (q < 0) return -1; av_assert0(q > 0.0); - q = get_diff_limited_q(s, rce, q); + q = get_diff_limited_q(m, rce, q); av_assert0(q > 0.0); // FIXME type dependent blur like in 2-pass - if (pict_type == AV_PICTURE_TYPE_P || s->intra_only) { + if (pict_type == AV_PICTURE_TYPE_P || m->intra_only) { rcc->short_term_qsum *= a->qblur; rcc->short_term_qcount *= a->qblur; @@ -1022,23 +1035,23 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) } av_assert0(q > 0.0); - q = modify_qscale(s, rce, q, picture_number); + q = modify_qscale(m, rce, q, picture_number); - rcc->pass1_wanted_bits += s->bit_rate / fps; + rcc->pass1_wanted_bits += m->bit_rate / fps; av_assert0(q > 0.0); } - if (s->avctx->debug & FF_DEBUG_RC) { - av_log(s->avctx, AV_LOG_DEBUG, + if (s->c.avctx->debug & FF_DEBUG_RC) { + av_log(s->c.avctx, AV_LOG_DEBUG, "%c qp:%d<%2.1f<%d %d want:%"PRId64" total:%"PRId64" comp:%f st_q:%2.2f " "size:%d var:%"PRId64"/%"PRId64" br:%"PRId64" fps:%d\n", av_get_picture_type_char(pict_type), qmin, q, qmax, picture_number, - wanted_bits / 1000, s->total_bits / 1000, - br_compensation, short_term_q, s->frame_bits, - s->mb_var_sum, s->mc_mb_var_sum, - s->bit_rate / 1000, (int)fps); + wanted_bits / 1000, m->total_bits / 1000, + br_compensation, short_term_q, m->frame_bits, + m->mb_var_sum, m->mc_mb_var_sum, + m->bit_rate / 1000, (int)fps); } if (q < qmin) @@ -1047,14 +1060,14 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) q = qmax; if (s->adaptive_quant) - adaptive_quantization(s, q); + adaptive_quantization(rcc, m, q); else q = (int)(q + 0.5); if (!dry_run) { rcc->last_qscale = q; - rcc->last_mc_mb_var_sum = s->mc_mb_var_sum; - rcc->last_mb_var_sum = s->mb_var_sum; + rcc->last_mc_mb_var_sum = m->mc_mb_var_sum; + rcc->last_mb_var_sum = m->mb_var_sum; } return q; } diff --git a/libavcodec/ratecontrol.h b/libavcodec/ratecontrol.h index 4d71a181b..3bcfa5658 100644 --- a/libavcodec/ratecontrol.h +++ b/libavcodec/ratecontrol.h @@ -77,17 +77,30 @@ typedef struct RateControlContext{ int frame_count[5]; int last_non_b_pict_type; + /** + * ratecontrol qmin qmax limiting method + * 0-> clipping, 1-> use a nice continuous function to limit qscale within qmin/qmax. + */ + float qsquish; + float qmod_amp; + int qmod_freq; + float initial_cplx; + float buffer_aggressivity; + + char *rc_eq; struct AVExpr *rc_eq_eval; + + float *cplx_tab, *bits_tab; }RateControlContext; -struct MpegEncContext; +typedef struct MPVMainEncContext MPVMainEncContext; /* rate control */ -int ff_rate_control_init(struct MpegEncContext *s); -float ff_rate_estimate_qscale(struct MpegEncContext *s, int dry_run); -void ff_write_pass1_stats(struct MpegEncContext *s); -int ff_vbv_update(struct MpegEncContext *s, int frame_size); -void ff_get_2pass_fcode(struct MpegEncContext *s); +int ff_rate_control_init(MPVMainEncContext *m); +float ff_rate_estimate_qscale(MPVMainEncContext *m, int dry_run); +void ff_write_pass1_stats(MPVMainEncContext *m); +int ff_vbv_update(MPVMainEncContext *m, int frame_size); +void ff_get_2pass_fcode(MPVMainEncContext *m); void ff_rate_control_uninit(RateControlContext *rcc); #endif /* AVCODEC_RATECONTROL_H */ diff --git a/libavcodec/raw.c b/libavcodec/raw.c index b73b80e5f..095bd4310 100644 --- a/libavcodec/raw.c +++ b/libavcodec/raw.c @@ -24,286 +24,9 @@ * Raw Video Codec */ -#include "libavutil/macros.h" #include "avcodec.h" #include "raw.h" - -static const PixelFormatTag raw_pix_fmt_tags[] = { - { AV_PIX_FMT_YUV420P, MKTAG('I', '4', '2', '0') }, /* Planar formats */ - { AV_PIX_FMT_YUV420P, MKTAG('I', 'Y', 'U', 'V') }, - { AV_PIX_FMT_YUV420P, MKTAG('y', 'v', '1', '2') }, - { AV_PIX_FMT_YUV420P, MKTAG('Y', 'V', '1', '2') }, - { AV_PIX_FMT_YUV410P, MKTAG('Y', 'U', 'V', '9') }, - { AV_PIX_FMT_YUV410P, MKTAG('Y', 'V', 'U', '9') }, - { AV_PIX_FMT_YUV411P, MKTAG('Y', '4', '1', 'B') }, - { AV_PIX_FMT_YUV422P, MKTAG('Y', '4', '2', 'B') }, - { AV_PIX_FMT_YUV422P, MKTAG('P', '4', '2', '2') }, - { AV_PIX_FMT_YUV422P, MKTAG('Y', 'V', '1', '6') }, - /* yuvjXXX formats are deprecated hacks specific to libav*, - they are identical to yuvXXX */ - { AV_PIX_FMT_YUVJ420P, MKTAG('I', '4', '2', '0') }, /* Planar formats */ - { AV_PIX_FMT_YUVJ420P, MKTAG('I', 'Y', 'U', 'V') }, - { AV_PIX_FMT_YUVJ420P, MKTAG('Y', 'V', '1', '2') }, - { AV_PIX_FMT_YUVJ422P, MKTAG('Y', '4', '2', 'B') }, - { AV_PIX_FMT_YUVJ422P, MKTAG('P', '4', '2', '2') }, - { AV_PIX_FMT_GRAY8, MKTAG('Y', '8', '0', '0') }, - { AV_PIX_FMT_GRAY8, MKTAG('Y', '8', ' ', ' ') }, - - { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'Y', '2') }, /* Packed formats */ - { AV_PIX_FMT_YUYV422, MKTAG('Y', '4', '2', '2') }, - { AV_PIX_FMT_YUYV422, MKTAG('V', '4', '2', '2') }, - { AV_PIX_FMT_YUYV422, MKTAG('V', 'Y', 'U', 'Y') }, - { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'N', 'V') }, - { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'Y', 'V') }, - { AV_PIX_FMT_YVYU422, MKTAG('Y', 'V', 'Y', 'U') }, /* Philips */ - { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'V', 'Y') }, - { AV_PIX_FMT_UYVY422, MKTAG('H', 'D', 'Y', 'C') }, - { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'N', 'V') }, - { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'N', 'Y') }, - { AV_PIX_FMT_UYVY422, MKTAG('u', 'y', 'v', '1') }, - { AV_PIX_FMT_UYVY422, MKTAG('2', 'V', 'u', '1') }, - { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'R', 'n') }, /* Avid AVI Codec 1:1 */ - { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', '1', 'x') }, /* Avid 1:1x */ - { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'u', 'p') }, - { AV_PIX_FMT_UYVY422, MKTAG('V', 'D', 'T', 'Z') }, /* SoftLab-NSK VideoTizer */ - { AV_PIX_FMT_UYVY422, MKTAG('a', 'u', 'v', '2') }, - { AV_PIX_FMT_UYVY422, MKTAG('c', 'y', 'u', 'v') }, /* CYUV is also Creative YUV */ - { AV_PIX_FMT_UYYVYY411, MKTAG('Y', '4', '1', '1') }, - { AV_PIX_FMT_GRAY8, MKTAG('G', 'R', 'E', 'Y') }, - { AV_PIX_FMT_NV12, MKTAG('N', 'V', '1', '2') }, - { AV_PIX_FMT_NV21, MKTAG('N', 'V', '2', '1') }, - { AV_PIX_FMT_VUYA, MKTAG('A', 'Y', 'U', 'V') }, /* MS 4:4:4:4 */ - - /* nut */ - { AV_PIX_FMT_RGB555LE, MKTAG('R', 'G', 'B', 15) }, - { AV_PIX_FMT_BGR555LE, MKTAG('B', 'G', 'R', 15) }, - { AV_PIX_FMT_RGB565LE, MKTAG('R', 'G', 'B', 16) }, - { AV_PIX_FMT_BGR565LE, MKTAG('B', 'G', 'R', 16) }, - { AV_PIX_FMT_RGB555BE, MKTAG(15 , 'B', 'G', 'R') }, - { AV_PIX_FMT_BGR555BE, MKTAG(15 , 'R', 'G', 'B') }, - { AV_PIX_FMT_RGB565BE, MKTAG(16 , 'B', 'G', 'R') }, - { AV_PIX_FMT_BGR565BE, MKTAG(16 , 'R', 'G', 'B') }, - { AV_PIX_FMT_RGB444LE, MKTAG('R', 'G', 'B', 12) }, - { AV_PIX_FMT_BGR444LE, MKTAG('B', 'G', 'R', 12) }, - { AV_PIX_FMT_RGB444BE, MKTAG(12 , 'B', 'G', 'R') }, - { AV_PIX_FMT_BGR444BE, MKTAG(12 , 'R', 'G', 'B') }, - { AV_PIX_FMT_RGBA64LE, MKTAG('R', 'B', 'A', 64 ) }, - { AV_PIX_FMT_BGRA64LE, MKTAG('B', 'R', 'A', 64 ) }, - { AV_PIX_FMT_RGBA64BE, MKTAG(64 , 'R', 'B', 'A') }, - { AV_PIX_FMT_BGRA64BE, MKTAG(64 , 'B', 'R', 'A') }, - { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') }, - { AV_PIX_FMT_RGB0, MKTAG('R', 'G', 'B', 0 ) }, - { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') }, - { AV_PIX_FMT_BGR0, MKTAG('B', 'G', 'R', 0 ) }, - { AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') }, - { AV_PIX_FMT_0BGR, MKTAG( 0 , 'B', 'G', 'R') }, - { AV_PIX_FMT_ARGB, MKTAG('A', 'R', 'G', 'B') }, - { AV_PIX_FMT_0RGB, MKTAG( 0 , 'R', 'G', 'B') }, - { AV_PIX_FMT_RGB24, MKTAG('R', 'G', 'B', 24 ) }, - { AV_PIX_FMT_BGR24, MKTAG('B', 'G', 'R', 24 ) }, - { AV_PIX_FMT_YUV411P, MKTAG('4', '1', '1', 'P') }, - { AV_PIX_FMT_YUV422P, MKTAG('4', '2', '2', 'P') }, - { AV_PIX_FMT_YUVJ422P, MKTAG('4', '2', '2', 'P') }, - { AV_PIX_FMT_YUV440P, MKTAG('4', '4', '0', 'P') }, - { AV_PIX_FMT_YUVJ440P, MKTAG('4', '4', '0', 'P') }, - { AV_PIX_FMT_YUV444P, MKTAG('4', '4', '4', 'P') }, - { AV_PIX_FMT_YUVJ444P, MKTAG('4', '4', '4', 'P') }, - { AV_PIX_FMT_MONOWHITE,MKTAG('B', '1', 'W', '0') }, - { AV_PIX_FMT_MONOBLACK,MKTAG('B', '0', 'W', '1') }, - { AV_PIX_FMT_BGR8, MKTAG('B', 'G', 'R', 8 ) }, - { AV_PIX_FMT_RGB8, MKTAG('R', 'G', 'B', 8 ) }, - { AV_PIX_FMT_BGR4, MKTAG('B', 'G', 'R', 4 ) }, - { AV_PIX_FMT_RGB4, MKTAG('R', 'G', 'B', 4 ) }, - { AV_PIX_FMT_RGB4_BYTE,MKTAG('B', '4', 'B', 'Y') }, - { AV_PIX_FMT_BGR4_BYTE,MKTAG('R', '4', 'B', 'Y') }, - { AV_PIX_FMT_RGB48LE, MKTAG('R', 'G', 'B', 48 ) }, - { AV_PIX_FMT_RGB48BE, MKTAG( 48, 'R', 'G', 'B') }, - { AV_PIX_FMT_BGR48LE, MKTAG('B', 'G', 'R', 48 ) }, - { AV_PIX_FMT_BGR48BE, MKTAG( 48, 'B', 'G', 'R') }, - { AV_PIX_FMT_GRAY9LE, MKTAG('Y', '1', 0 , 9 ) }, - { AV_PIX_FMT_GRAY9BE, MKTAG( 9 , 0 , '1', 'Y') }, - { AV_PIX_FMT_GRAY10LE, MKTAG('Y', '1', 0 , 10 ) }, - { AV_PIX_FMT_GRAY10BE, MKTAG(10 , 0 , '1', 'Y') }, - { AV_PIX_FMT_GRAY12LE, MKTAG('Y', '1', 0 , 12 ) }, - { AV_PIX_FMT_GRAY12BE, MKTAG(12 , 0 , '1', 'Y') }, - { AV_PIX_FMT_GRAY14LE, MKTAG('Y', '1', 0 , 14 ) }, - { AV_PIX_FMT_GRAY14BE, MKTAG(14 , 0 , '1', 'Y') }, - { AV_PIX_FMT_GRAY16LE, MKTAG('Y', '1', 0 , 16 ) }, - { AV_PIX_FMT_GRAY16BE, MKTAG(16 , 0 , '1', 'Y') }, - { AV_PIX_FMT_YUV420P9LE, MKTAG('Y', '3', 11 , 9 ) }, - { AV_PIX_FMT_YUV420P9BE, MKTAG( 9 , 11 , '3', 'Y') }, - { AV_PIX_FMT_YUV422P9LE, MKTAG('Y', '3', 10 , 9 ) }, - { AV_PIX_FMT_YUV422P9BE, MKTAG( 9 , 10 , '3', 'Y') }, - { AV_PIX_FMT_YUV444P9LE, MKTAG('Y', '3', 0 , 9 ) }, - { AV_PIX_FMT_YUV444P9BE, MKTAG( 9 , 0 , '3', 'Y') }, - { AV_PIX_FMT_YUV420P10LE, MKTAG('Y', '3', 11 , 10 ) }, - { AV_PIX_FMT_YUV420P10BE, MKTAG(10 , 11 , '3', 'Y') }, - { AV_PIX_FMT_YUV422P10LE, MKTAG('Y', '3', 10 , 10 ) }, - { AV_PIX_FMT_YUV422P10BE, MKTAG(10 , 10 , '3', 'Y') }, - { AV_PIX_FMT_YUV444P10LE, MKTAG('Y', '3', 0 , 10 ) }, - { AV_PIX_FMT_YUV444P10BE, MKTAG(10 , 0 , '3', 'Y') }, - { AV_PIX_FMT_YUV420P12LE, MKTAG('Y', '3', 11 , 12 ) }, - { AV_PIX_FMT_YUV420P12BE, MKTAG(12 , 11 , '3', 'Y') }, - { AV_PIX_FMT_YUV422P12LE, MKTAG('Y', '3', 10 , 12 ) }, - { AV_PIX_FMT_YUV422P12BE, MKTAG(12 , 10 , '3', 'Y') }, - { AV_PIX_FMT_YUV444P12LE, MKTAG('Y', '3', 0 , 12 ) }, - { AV_PIX_FMT_YUV444P12BE, MKTAG(12 , 0 , '3', 'Y') }, - { AV_PIX_FMT_YUV420P14LE, MKTAG('Y', '3', 11 , 14 ) }, - { AV_PIX_FMT_YUV420P14BE, MKTAG(14 , 11 , '3', 'Y') }, - { AV_PIX_FMT_YUV422P14LE, MKTAG('Y', '3', 10 , 14 ) }, - { AV_PIX_FMT_YUV422P14BE, MKTAG(14 , 10 , '3', 'Y') }, - { AV_PIX_FMT_YUV444P14LE, MKTAG('Y', '3', 0 , 14 ) }, - { AV_PIX_FMT_YUV444P14BE, MKTAG(14 , 0 , '3', 'Y') }, - { AV_PIX_FMT_YUV420P16LE, MKTAG('Y', '3', 11 , 16 ) }, - { AV_PIX_FMT_YUV420P16BE, MKTAG(16 , 11 , '3', 'Y') }, - { AV_PIX_FMT_YUV422P16LE, MKTAG('Y', '3', 10 , 16 ) }, - { AV_PIX_FMT_YUV422P16BE, MKTAG(16 , 10 , '3', 'Y') }, - { AV_PIX_FMT_YUV444P16LE, MKTAG('Y', '3', 0 , 16 ) }, - { AV_PIX_FMT_YUV444P16BE, MKTAG(16 , 0 , '3', 'Y') }, - { AV_PIX_FMT_YUVA420P, MKTAG('Y', '4', 11 , 8 ) }, - { AV_PIX_FMT_YUVA422P, MKTAG('Y', '4', 10 , 8 ) }, - { AV_PIX_FMT_YUVA444P, MKTAG('Y', '4', 0 , 8 ) }, - { AV_PIX_FMT_YA8, MKTAG('Y', '2', 0 , 8 ) }, - { AV_PIX_FMT_PAL8, MKTAG('P', 'A', 'L', 8 ) }, - - { AV_PIX_FMT_YUVA420P9LE, MKTAG('Y', '4', 11 , 9 ) }, - { AV_PIX_FMT_YUVA420P9BE, MKTAG( 9 , 11 , '4', 'Y') }, - { AV_PIX_FMT_YUVA422P9LE, MKTAG('Y', '4', 10 , 9 ) }, - { AV_PIX_FMT_YUVA422P9BE, MKTAG( 9 , 10 , '4', 'Y') }, - { AV_PIX_FMT_YUVA444P9LE, MKTAG('Y', '4', 0 , 9 ) }, - { AV_PIX_FMT_YUVA444P9BE, MKTAG( 9 , 0 , '4', 'Y') }, - { AV_PIX_FMT_YUVA420P10LE, MKTAG('Y', '4', 11 , 10 ) }, - { AV_PIX_FMT_YUVA420P10BE, MKTAG(10 , 11 , '4', 'Y') }, - { AV_PIX_FMT_YUVA422P10LE, MKTAG('Y', '4', 10 , 10 ) }, - { AV_PIX_FMT_YUVA422P10BE, MKTAG(10 , 10 , '4', 'Y') }, - { AV_PIX_FMT_YUVA444P10LE, MKTAG('Y', '4', 0 , 10 ) }, - { AV_PIX_FMT_YUVA444P10BE, MKTAG(10 , 0 , '4', 'Y') }, - { AV_PIX_FMT_YUVA422P12LE, MKTAG('Y', '4', 10 , 12 ) }, - { AV_PIX_FMT_YUVA422P12BE, MKTAG(12 , 10 , '4', 'Y') }, - { AV_PIX_FMT_YUVA444P12LE, MKTAG('Y', '4', 0 , 12 ) }, - { AV_PIX_FMT_YUVA444P12BE, MKTAG(12 , 0 , '4', 'Y') }, - { AV_PIX_FMT_YUVA420P16LE, MKTAG('Y', '4', 11 , 16 ) }, - { AV_PIX_FMT_YUVA420P16BE, MKTAG(16 , 11 , '4', 'Y') }, - { AV_PIX_FMT_YUVA422P16LE, MKTAG('Y', '4', 10 , 16 ) }, - { AV_PIX_FMT_YUVA422P16BE, MKTAG(16 , 10 , '4', 'Y') }, - { AV_PIX_FMT_YUVA444P16LE, MKTAG('Y', '4', 0 , 16 ) }, - { AV_PIX_FMT_YUVA444P16BE, MKTAG(16 , 0 , '4', 'Y') }, - - { AV_PIX_FMT_GBRP, MKTAG('G', '3', 00 , 8 ) }, - { AV_PIX_FMT_GBRP9LE, MKTAG('G', '3', 00 , 9 ) }, - { AV_PIX_FMT_GBRP9BE, MKTAG( 9 , 00 , '3', 'G') }, - { AV_PIX_FMT_GBRP10LE, MKTAG('G', '3', 00 , 10 ) }, - { AV_PIX_FMT_GBRP10BE, MKTAG(10 , 00 , '3', 'G') }, - { AV_PIX_FMT_GBRP12LE, MKTAG('G', '3', 00 , 12 ) }, - { AV_PIX_FMT_GBRP12BE, MKTAG(12 , 00 , '3', 'G') }, - { AV_PIX_FMT_GBRP14LE, MKTAG('G', '3', 00 , 14 ) }, - { AV_PIX_FMT_GBRP14BE, MKTAG(14 , 00 , '3', 'G') }, - { AV_PIX_FMT_GBRP16LE, MKTAG('G', '3', 00 , 16 ) }, - { AV_PIX_FMT_GBRP16BE, MKTAG(16 , 00 , '3', 'G') }, - - { AV_PIX_FMT_GBRAP, MKTAG('G', '4', 00 , 8 ) }, - { AV_PIX_FMT_GBRAP10LE, MKTAG('G', '4', 00 , 10 ) }, - { AV_PIX_FMT_GBRAP10BE, MKTAG(10 , 00 , '4', 'G') }, - { AV_PIX_FMT_GBRAP12LE, MKTAG('G', '4', 00 , 12 ) }, - { AV_PIX_FMT_GBRAP12BE, MKTAG(12 , 00 , '4', 'G') }, - { AV_PIX_FMT_GBRAP14LE, MKTAG('G', '4', 00 , 14 ) }, - { AV_PIX_FMT_GBRAP14BE, MKTAG(14 , 00 , '4', 'G') }, - { AV_PIX_FMT_GBRAP16LE, MKTAG('G', '4', 00 , 16 ) }, - { AV_PIX_FMT_GBRAP16BE, MKTAG(16 , 00 , '4', 'G') }, - - { AV_PIX_FMT_XYZ12LE, MKTAG('X', 'Y', 'Z' , 36 ) }, - { AV_PIX_FMT_XYZ12BE, MKTAG(36 , 'Z' , 'Y', 'X') }, - - { AV_PIX_FMT_BAYER_BGGR8, MKTAG(0xBA, 'B', 'G', 8 ) }, - { AV_PIX_FMT_BAYER_BGGR16LE, MKTAG(0xBA, 'B', 'G', 16 ) }, - { AV_PIX_FMT_BAYER_BGGR16BE, MKTAG(16 , 'G', 'B', 0xBA) }, - { AV_PIX_FMT_BAYER_RGGB8, MKTAG(0xBA, 'R', 'G', 8 ) }, - { AV_PIX_FMT_BAYER_RGGB16LE, MKTAG(0xBA, 'R', 'G', 16 ) }, - { AV_PIX_FMT_BAYER_RGGB16BE, MKTAG(16 , 'G', 'R', 0xBA) }, - { AV_PIX_FMT_BAYER_GBRG8, MKTAG(0xBA, 'G', 'B', 8 ) }, - { AV_PIX_FMT_BAYER_GBRG16LE, MKTAG(0xBA, 'G', 'B', 16 ) }, - { AV_PIX_FMT_BAYER_GBRG16BE, MKTAG(16, 'B', 'G', 0xBA) }, - { AV_PIX_FMT_BAYER_GRBG8, MKTAG(0xBA, 'G', 'R', 8 ) }, - { AV_PIX_FMT_BAYER_GRBG16LE, MKTAG(0xBA, 'G', 'R', 16 ) }, - { AV_PIX_FMT_BAYER_GRBG16BE, MKTAG(16, 'R', 'G', 0xBA) }, - - /* quicktime */ - { AV_PIX_FMT_YUV420P, MKTAG('R', '4', '2', '0') }, /* Radius DV YUV PAL */ - { AV_PIX_FMT_YUV411P, MKTAG('R', '4', '1', '1') }, /* Radius DV YUV NTSC */ - { AV_PIX_FMT_UYVY422, MKTAG('2', 'v', 'u', 'y') }, - { AV_PIX_FMT_UYVY422, MKTAG('2', 'V', 'u', 'y') }, - { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'U', 'I') }, /* FIXME merge both fields */ - { AV_PIX_FMT_UYVY422, MKTAG('b', 'x', 'y', 'v') }, - { AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', '2') }, - { AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', 's') }, - { AV_PIX_FMT_YUYV422, MKTAG('D', 'V', 'O', 'O') }, /* Digital Voodoo SD 8 Bit */ - { AV_PIX_FMT_RGB555LE,MKTAG('L', '5', '5', '5') }, - { AV_PIX_FMT_RGB565LE,MKTAG('L', '5', '6', '5') }, - { AV_PIX_FMT_RGB565BE,MKTAG('B', '5', '6', '5') }, - { AV_PIX_FMT_BGR24, MKTAG('2', '4', 'B', 'G') }, - { AV_PIX_FMT_BGR24, MKTAG('b', 'x', 'b', 'g') }, - { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') }, - { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') }, - { AV_PIX_FMT_RGB24, MKTAG('b', 'x', 'r', 'g') }, - { AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') }, - { AV_PIX_FMT_GRAY16BE,MKTAG('b', '1', '6', 'g') }, - { AV_PIX_FMT_RGB48BE, MKTAG('b', '4', '8', 'r') }, - { AV_PIX_FMT_RGBA64BE,MKTAG('b', '6', '4', 'a') }, - { AV_PIX_FMT_BAYER_RGGB16BE, MKTAG('B', 'G', 'G', 'R') }, - - /* vlc */ - { AV_PIX_FMT_YUV410P, MKTAG('I', '4', '1', '0') }, - { AV_PIX_FMT_YUV411P, MKTAG('I', '4', '1', '1') }, - { AV_PIX_FMT_YUV422P, MKTAG('I', '4', '2', '2') }, - { AV_PIX_FMT_YUV440P, MKTAG('I', '4', '4', '0') }, - { AV_PIX_FMT_YUV444P, MKTAG('I', '4', '4', '4') }, - { AV_PIX_FMT_YUVJ420P, MKTAG('J', '4', '2', '0') }, - { AV_PIX_FMT_YUVJ422P, MKTAG('J', '4', '2', '2') }, - { AV_PIX_FMT_YUVJ440P, MKTAG('J', '4', '4', '0') }, - { AV_PIX_FMT_YUVJ444P, MKTAG('J', '4', '4', '4') }, - { AV_PIX_FMT_YUVA444P, MKTAG('Y', 'U', 'V', 'A') }, - { AV_PIX_FMT_YUVA420P, MKTAG('I', '4', '0', 'A') }, - { AV_PIX_FMT_YUVA422P, MKTAG('I', '4', '2', 'A') }, - { AV_PIX_FMT_RGB8, MKTAG('R', 'G', 'B', '2') }, - { AV_PIX_FMT_RGB555LE, MKTAG('R', 'V', '1', '5') }, - { AV_PIX_FMT_RGB565LE, MKTAG('R', 'V', '1', '6') }, - { AV_PIX_FMT_BGR24, MKTAG('R', 'V', '2', '4') }, - { AV_PIX_FMT_BGR0, MKTAG('R', 'V', '3', '2') }, - { AV_PIX_FMT_RGBA, MKTAG('A', 'V', '3', '2') }, - { AV_PIX_FMT_YUV420P9LE, MKTAG('I', '0', '9', 'L') }, - { AV_PIX_FMT_YUV420P9BE, MKTAG('I', '0', '9', 'B') }, - { AV_PIX_FMT_YUV422P9LE, MKTAG('I', '2', '9', 'L') }, - { AV_PIX_FMT_YUV422P9BE, MKTAG('I', '2', '9', 'B') }, - { AV_PIX_FMT_YUV444P9LE, MKTAG('I', '4', '9', 'L') }, - { AV_PIX_FMT_YUV444P9BE, MKTAG('I', '4', '9', 'B') }, - { AV_PIX_FMT_YUV420P10LE, MKTAG('I', '0', 'A', 'L') }, - { AV_PIX_FMT_YUV420P10BE, MKTAG('I', '0', 'A', 'B') }, - { AV_PIX_FMT_YUV422P10LE, MKTAG('I', '2', 'A', 'L') }, - { AV_PIX_FMT_YUV422P10BE, MKTAG('I', '2', 'A', 'B') }, - { AV_PIX_FMT_YUV444P10LE, MKTAG('I', '4', 'A', 'L') }, - { AV_PIX_FMT_YUV444P10BE, MKTAG('I', '4', 'A', 'B') }, - { AV_PIX_FMT_YUV420P12LE, MKTAG('I', '0', 'C', 'L') }, - { AV_PIX_FMT_YUV420P12BE, MKTAG('I', '0', 'C', 'B') }, - { AV_PIX_FMT_YUV422P12LE, MKTAG('I', '2', 'C', 'L') }, - { AV_PIX_FMT_YUV422P12BE, MKTAG('I', '2', 'C', 'B') }, - { AV_PIX_FMT_YUV444P12LE, MKTAG('I', '4', 'C', 'L') }, - { AV_PIX_FMT_YUV444P12BE, MKTAG('I', '4', 'C', 'B') }, - { AV_PIX_FMT_YUV420P16LE, MKTAG('I', '0', 'F', 'L') }, - { AV_PIX_FMT_YUV420P16BE, MKTAG('I', '0', 'F', 'B') }, - { AV_PIX_FMT_YUV444P16LE, MKTAG('I', '4', 'F', 'L') }, - { AV_PIX_FMT_YUV444P16BE, MKTAG('I', '4', 'F', 'B') }, - - /* special */ - { AV_PIX_FMT_RGB565LE,MKTAG( 3 , 0 , 0 , 0 ) }, /* flipped RGB565LE */ - { AV_PIX_FMT_YUV444P, MKTAG('Y', 'V', '2', '4') }, /* YUV444P, swapped UV */ - - { AV_PIX_FMT_NONE, 0 }, -}; - -const struct PixelFormatTag *avpriv_get_raw_pix_fmt_tags(void) -{ - return raw_pix_fmt_tags; -} +#include "raw_pix_fmt_tags.h" unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat fmt) { diff --git a/libavcodec/raw.h b/libavcodec/raw.h index 9a4ddef8f..69f7f530a 100644 --- a/libavcodec/raw.h +++ b/libavcodec/raw.h @@ -34,8 +34,6 @@ typedef struct PixelFormatTag { unsigned int fourcc; } PixelFormatTag; -const struct PixelFormatTag *avpriv_get_raw_pix_fmt_tags(void); - enum PixelFormatTagLists { PIX_FMT_LIST_RAW, PIX_FMT_LIST_AVI, diff --git a/libavcodec/raw_pix_fmt_tags.h b/libavcodec/raw_pix_fmt_tags.h new file mode 100644 index 000000000..bdde060cf --- /dev/null +++ b/libavcodec/raw_pix_fmt_tags.h @@ -0,0 +1,316 @@ +/* + * Raw Video Codec + * 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_RAW_PIX_FMT_TAGS_H +#define AVCODEC_RAW_PIX_FMT_TAGS_H + +#include "raw.h" +#include "libavutil/macros.h" + +static const PixelFormatTag raw_pix_fmt_tags[] = { + { AV_PIX_FMT_YUV420P, MKTAG('I', '4', '2', '0') }, /* Planar formats */ + { AV_PIX_FMT_YUV420P, MKTAG('I', 'Y', 'U', 'V') }, + { AV_PIX_FMT_YUV420P, MKTAG('y', 'v', '1', '2') }, + { AV_PIX_FMT_YUV420P, MKTAG('Y', 'V', '1', '2') }, + { AV_PIX_FMT_YUV410P, MKTAG('Y', 'U', 'V', '9') }, + { AV_PIX_FMT_YUV410P, MKTAG('Y', 'V', 'U', '9') }, + { AV_PIX_FMT_YUV411P, MKTAG('Y', '4', '1', 'B') }, + { AV_PIX_FMT_YUV422P, MKTAG('Y', '4', '2', 'B') }, + { AV_PIX_FMT_YUV422P, MKTAG('P', '4', '2', '2') }, + { AV_PIX_FMT_YUV422P, MKTAG('Y', 'V', '1', '6') }, + /* yuvjXXX formats are deprecated hacks specific to libav*, + they are identical to yuvXXX */ + { AV_PIX_FMT_YUVJ420P, MKTAG('I', '4', '2', '0') }, /* Planar formats */ + { AV_PIX_FMT_YUVJ420P, MKTAG('I', 'Y', 'U', 'V') }, + { AV_PIX_FMT_YUVJ420P, MKTAG('Y', 'V', '1', '2') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('Y', '4', '2', 'B') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('P', '4', '2', '2') }, + { AV_PIX_FMT_GRAY8, MKTAG('Y', '8', '0', '0') }, + { AV_PIX_FMT_GRAY8, MKTAG('Y', '8', ' ', ' ') }, + + { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'Y', '2') }, /* Packed formats */ + { AV_PIX_FMT_YUYV422, MKTAG('Y', '4', '2', '2') }, + { AV_PIX_FMT_YUYV422, MKTAG('V', '4', '2', '2') }, + { AV_PIX_FMT_YUYV422, MKTAG('V', 'Y', 'U', 'Y') }, + { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'N', 'V') }, + { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'Y', 'V') }, + { AV_PIX_FMT_YVYU422, MKTAG('Y', 'V', 'Y', 'U') }, /* Philips */ + { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'V', 'Y') }, + { AV_PIX_FMT_UYVY422, MKTAG('H', 'D', 'Y', 'C') }, + { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'N', 'V') }, + { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'N', 'Y') }, + { AV_PIX_FMT_UYVY422, MKTAG('u', 'y', 'v', '1') }, + { AV_PIX_FMT_UYVY422, MKTAG('2', 'V', 'u', '1') }, + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'R', 'n') }, /* Avid AVI Codec 1:1 */ + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', '1', 'x') }, /* Avid 1:1x */ + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'u', 'p') }, + { AV_PIX_FMT_UYVY422, MKTAG('V', 'D', 'T', 'Z') }, /* SoftLab-NSK VideoTizer */ + { AV_PIX_FMT_UYVY422, MKTAG('a', 'u', 'v', '2') }, + { AV_PIX_FMT_UYVY422, MKTAG('c', 'y', 'u', 'v') }, /* CYUV is also Creative YUV */ + { AV_PIX_FMT_UYYVYY411, MKTAG('Y', '4', '1', '1') }, + { AV_PIX_FMT_GRAY8, MKTAG('G', 'R', 'E', 'Y') }, + { AV_PIX_FMT_NV12, MKTAG('N', 'V', '1', '2') }, + { AV_PIX_FMT_NV21, MKTAG('N', 'V', '2', '1') }, + { AV_PIX_FMT_VUYA, MKTAG('A', 'Y', 'U', 'V') }, /* MS 4:4:4:4 */ + { AV_PIX_FMT_XV30LE, MKTAG('Y', '4', '1', '0') }, + { AV_PIX_FMT_XV48LE, MKTAG('Y', '4', '1', '6') }, + { AV_PIX_FMT_Y210LE, MKTAG('Y', '2', '1', '0') }, + { AV_PIX_FMT_Y216LE, MKTAG('Y', '2', '1', '6') }, + + /* nut */ + { AV_PIX_FMT_RGB555LE, MKTAG('R', 'G', 'B', 15) }, + { AV_PIX_FMT_BGR555LE, MKTAG('B', 'G', 'R', 15) }, + { AV_PIX_FMT_RGB565LE, MKTAG('R', 'G', 'B', 16) }, + { AV_PIX_FMT_BGR565LE, MKTAG('B', 'G', 'R', 16) }, + { AV_PIX_FMT_RGB555BE, MKTAG(15 , 'B', 'G', 'R') }, + { AV_PIX_FMT_BGR555BE, MKTAG(15 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGB565BE, MKTAG(16 , 'B', 'G', 'R') }, + { AV_PIX_FMT_BGR565BE, MKTAG(16 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGB444LE, MKTAG('R', 'G', 'B', 12) }, + { AV_PIX_FMT_BGR444LE, MKTAG('B', 'G', 'R', 12) }, + { AV_PIX_FMT_RGB444BE, MKTAG(12 , 'B', 'G', 'R') }, + { AV_PIX_FMT_BGR444BE, MKTAG(12 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGBA64LE, MKTAG('R', 'B', 'A', 64 ) }, + { AV_PIX_FMT_BGRA64LE, MKTAG('B', 'R', 'A', 64 ) }, + { AV_PIX_FMT_RGBA64BE, MKTAG(64 , 'R', 'B', 'A') }, + { AV_PIX_FMT_BGRA64BE, MKTAG(64 , 'B', 'R', 'A') }, + { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') }, + { AV_PIX_FMT_RGB0, MKTAG('R', 'G', 'B', 0 ) }, + { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') }, + { AV_PIX_FMT_BGR0, MKTAG('B', 'G', 'R', 0 ) }, + { AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') }, + { AV_PIX_FMT_0BGR, MKTAG( 0 , 'B', 'G', 'R') }, + { AV_PIX_FMT_ARGB, MKTAG('A', 'R', 'G', 'B') }, + { AV_PIX_FMT_0RGB, MKTAG( 0 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGB24, MKTAG('R', 'G', 'B', 24 ) }, + { AV_PIX_FMT_BGR24, MKTAG('B', 'G', 'R', 24 ) }, + { AV_PIX_FMT_YUV411P, MKTAG('4', '1', '1', 'P') }, + { AV_PIX_FMT_YUV422P, MKTAG('4', '2', '2', 'P') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('4', '2', '2', 'P') }, + { AV_PIX_FMT_YUV440P, MKTAG('4', '4', '0', 'P') }, + { AV_PIX_FMT_YUVJ440P, MKTAG('4', '4', '0', 'P') }, + { AV_PIX_FMT_YUV444P, MKTAG('4', '4', '4', 'P') }, + { AV_PIX_FMT_YUVJ444P, MKTAG('4', '4', '4', 'P') }, + { AV_PIX_FMT_MONOWHITE, MKTAG('B', '1', 'W', '0') }, + { AV_PIX_FMT_MONOBLACK, MKTAG('B', '0', 'W', '1') }, + { AV_PIX_FMT_BGR8, MKTAG('B', 'G', 'R', 8 ) }, + { AV_PIX_FMT_RGB8, MKTAG('R', 'G', 'B', 8 ) }, + { AV_PIX_FMT_BGR4, MKTAG('B', 'G', 'R', 4 ) }, + { AV_PIX_FMT_RGB4, MKTAG('R', 'G', 'B', 4 ) }, + { AV_PIX_FMT_RGB4_BYTE, MKTAG('B', '4', 'B', 'Y') }, + { AV_PIX_FMT_BGR4_BYTE, MKTAG('R', '4', 'B', 'Y') }, + { AV_PIX_FMT_RGB48LE, MKTAG('R', 'G', 'B', 48 ) }, + { AV_PIX_FMT_RGB48BE, MKTAG( 48, 'R', 'G', 'B') }, + { AV_PIX_FMT_BGR48LE, MKTAG('B', 'G', 'R', 48 ) }, + { AV_PIX_FMT_BGR48BE, MKTAG( 48, 'B', 'G', 'R') }, + { AV_PIX_FMT_GRAY9LE, MKTAG('Y', '1', 0 , 9 ) }, + { AV_PIX_FMT_GRAY9BE, MKTAG( 9 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY10LE, MKTAG('Y', '1', 0 , 10 ) }, + { AV_PIX_FMT_GRAY10BE, MKTAG(10 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY12LE, MKTAG('Y', '1', 0 , 12 ) }, + { AV_PIX_FMT_GRAY12BE, MKTAG(12 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY14LE, MKTAG('Y', '1', 0 , 14 ) }, + { AV_PIX_FMT_GRAY14BE, MKTAG(14 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY16LE, MKTAG('Y', '1', 0 , 16 ) }, + { AV_PIX_FMT_GRAY16BE, MKTAG(16 , 0 , '1', 'Y') }, + { AV_PIX_FMT_YUV420P9LE, MKTAG('Y', '3', 11 , 9 ) }, + { AV_PIX_FMT_YUV420P9BE, MKTAG( 9 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P9LE, MKTAG('Y', '3', 10 , 9 ) }, + { AV_PIX_FMT_YUV422P9BE, MKTAG( 9 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P9LE, MKTAG('Y', '3', 0 , 9 ) }, + { AV_PIX_FMT_YUV444P9BE, MKTAG( 9 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P10LE, MKTAG('Y', '3', 11 , 10 ) }, + { AV_PIX_FMT_YUV420P10BE, MKTAG(10 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P10LE, MKTAG('Y', '3', 10 , 10 ) }, + { AV_PIX_FMT_YUV422P10BE, MKTAG(10 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P10LE, MKTAG('Y', '3', 0 , 10 ) }, + { AV_PIX_FMT_YUV444P10BE, MKTAG(10 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P12LE, MKTAG('Y', '3', 11 , 12 ) }, + { AV_PIX_FMT_YUV420P12BE, MKTAG(12 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P12LE, MKTAG('Y', '3', 10 , 12 ) }, + { AV_PIX_FMT_YUV422P12BE, MKTAG(12 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P12LE, MKTAG('Y', '3', 0 , 12 ) }, + { AV_PIX_FMT_YUV444P12BE, MKTAG(12 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P14LE, MKTAG('Y', '3', 11 , 14 ) }, + { AV_PIX_FMT_YUV420P14BE, MKTAG(14 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P14LE, MKTAG('Y', '3', 10 , 14 ) }, + { AV_PIX_FMT_YUV422P14BE, MKTAG(14 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P14LE, MKTAG('Y', '3', 0 , 14 ) }, + { AV_PIX_FMT_YUV444P14BE, MKTAG(14 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P16LE, MKTAG('Y', '3', 11 , 16 ) }, + { AV_PIX_FMT_YUV420P16BE, MKTAG(16 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P16LE, MKTAG('Y', '3', 10 , 16 ) }, + { AV_PIX_FMT_YUV422P16BE, MKTAG(16 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P16LE, MKTAG('Y', '3', 0 , 16 ) }, + { AV_PIX_FMT_YUV444P16BE, MKTAG(16 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUVA420P, MKTAG('Y', '4', 11 , 8 ) }, + { AV_PIX_FMT_YUVA422P, MKTAG('Y', '4', 10 , 8 ) }, + { AV_PIX_FMT_YUVA444P, MKTAG('Y', '4', 0 , 8 ) }, + { AV_PIX_FMT_YA8, MKTAG('Y', '2', 0 , 8 ) }, + { AV_PIX_FMT_PAL8, MKTAG('P', 'A', 'L', 8 ) }, + + { AV_PIX_FMT_YUVA420P9LE, MKTAG('Y', '4', 11 , 9 ) }, + { AV_PIX_FMT_YUVA420P9BE, MKTAG( 9 , 11 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P9LE, MKTAG('Y', '4', 10 , 9 ) }, + { AV_PIX_FMT_YUVA422P9BE, MKTAG( 9 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P9LE, MKTAG('Y', '4', 0 , 9 ) }, + { AV_PIX_FMT_YUVA444P9BE, MKTAG( 9 , 0 , '4', 'Y') }, + { AV_PIX_FMT_YUVA420P10LE, MKTAG('Y', '4', 11 , 10 ) }, + { AV_PIX_FMT_YUVA420P10BE, MKTAG(10 , 11 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P10LE, MKTAG('Y', '4', 10 , 10 ) }, + { AV_PIX_FMT_YUVA422P10BE, MKTAG(10 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P10LE, MKTAG('Y', '4', 0 , 10 ) }, + { AV_PIX_FMT_YUVA444P10BE, MKTAG(10 , 0 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P12LE, MKTAG('Y', '4', 10 , 12 ) }, + { AV_PIX_FMT_YUVA422P12BE, MKTAG(12 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P12LE, MKTAG('Y', '4', 0 , 12 ) }, + { AV_PIX_FMT_YUVA444P12BE, MKTAG(12 , 0 , '4', 'Y') }, + { AV_PIX_FMT_YUVA420P16LE, MKTAG('Y', '4', 11 , 16 ) }, + { AV_PIX_FMT_YUVA420P16BE, MKTAG(16 , 11 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P16LE, MKTAG('Y', '4', 10 , 16 ) }, + { AV_PIX_FMT_YUVA422P16BE, MKTAG(16 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P16LE, MKTAG('Y', '4', 0 , 16 ) }, + { AV_PIX_FMT_YUVA444P16BE, MKTAG(16 , 0 , '4', 'Y') }, + + { AV_PIX_FMT_GBRP, MKTAG('G', '3', 00 , 8 ) }, + { AV_PIX_FMT_GBRP9LE, MKTAG('G', '3', 00 , 9 ) }, + { AV_PIX_FMT_GBRP9BE, MKTAG( 9 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP10LE, MKTAG('G', '3', 00 , 10 ) }, + { AV_PIX_FMT_GBRP10BE, MKTAG(10 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP12LE, MKTAG('G', '3', 00 , 12 ) }, + { AV_PIX_FMT_GBRP12BE, MKTAG(12 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP14LE, MKTAG('G', '3', 00 , 14 ) }, + { AV_PIX_FMT_GBRP14BE, MKTAG(14 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP16LE, MKTAG('G', '3', 00 , 16 ) }, + { AV_PIX_FMT_GBRP16BE, MKTAG(16 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRPF16LE, MKTAG('G', '3', 00 , 17 ) }, + { AV_PIX_FMT_GBRPF16BE, MKTAG(17 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRPF32LE, MKTAG('G', '3', 00 , 33 ) }, + { AV_PIX_FMT_GBRPF32BE, MKTAG(33 , 00 , '3', 'G') }, + + { AV_PIX_FMT_GBRAP, MKTAG('G', '4', 00 , 8 ) }, + { AV_PIX_FMT_GBRAP10LE, MKTAG('G', '4', 00 , 10 ) }, + { AV_PIX_FMT_GBRAP10BE, MKTAG(10 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAP12LE, MKTAG('G', '4', 00 , 12 ) }, + { AV_PIX_FMT_GBRAP12BE, MKTAG(12 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAP14LE, MKTAG('G', '4', 00 , 14 ) }, + { AV_PIX_FMT_GBRAP14BE, MKTAG(14 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAP16LE, MKTAG('G', '4', 00 , 16 ) }, + { AV_PIX_FMT_GBRAP16BE, MKTAG(16 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAPF16LE, MKTAG('G', '4', 00 , 17 ) }, + { AV_PIX_FMT_GBRAPF16BE, MKTAG(17 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAPF32LE, MKTAG('G', '4', 00 , 33 ) }, + { AV_PIX_FMT_GBRAPF32BE, MKTAG(33 , 00 , '4', 'G') }, + + { AV_PIX_FMT_XYZ12LE, MKTAG('X', 'Y', 'Z' , 36 ) }, + { AV_PIX_FMT_XYZ12BE, MKTAG(36 , 'Z' , 'Y', 'X') }, + + { AV_PIX_FMT_BAYER_BGGR8, MKTAG(0xBA, 'B', 'G', 8 ) }, + { AV_PIX_FMT_BAYER_BGGR16LE, MKTAG(0xBA, 'B', 'G', 16 ) }, + { AV_PIX_FMT_BAYER_BGGR16BE, MKTAG(16 , 'G', 'B', 0xBA) }, + { AV_PIX_FMT_BAYER_RGGB8, MKTAG(0xBA, 'R', 'G', 8 ) }, + { AV_PIX_FMT_BAYER_RGGB16LE, MKTAG(0xBA, 'R', 'G', 16 ) }, + { AV_PIX_FMT_BAYER_RGGB16BE, MKTAG(16 , 'G', 'R', 0xBA) }, + { AV_PIX_FMT_BAYER_GBRG8, MKTAG(0xBA, 'G', 'B', 8 ) }, + { AV_PIX_FMT_BAYER_GBRG16LE, MKTAG(0xBA, 'G', 'B', 16 ) }, + { AV_PIX_FMT_BAYER_GBRG16BE, MKTAG(16, 'B', 'G', 0xBA) }, + { AV_PIX_FMT_BAYER_GRBG8, MKTAG(0xBA, 'G', 'R', 8 ) }, + { AV_PIX_FMT_BAYER_GRBG16LE, MKTAG(0xBA, 'G', 'R', 16 ) }, + { AV_PIX_FMT_BAYER_GRBG16BE, MKTAG(16, 'R', 'G', 0xBA) }, + + /* quicktime */ + { AV_PIX_FMT_YUV420P, MKTAG('R', '4', '2', '0') }, /* Radius DV YUV PAL */ + { AV_PIX_FMT_YUV411P, MKTAG('R', '4', '1', '1') }, /* Radius DV YUV NTSC */ + { AV_PIX_FMT_UYVY422, MKTAG('2', 'v', 'u', 'y') }, + { AV_PIX_FMT_UYVY422, MKTAG('2', 'V', 'u', 'y') }, + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'U', 'I') }, /* FIXME merge both fields */ + { AV_PIX_FMT_UYVY422, MKTAG('b', 'x', 'y', 'v') }, + { AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', '2') }, + { AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', 's') }, + { AV_PIX_FMT_YUYV422, MKTAG('D', 'V', 'O', 'O') }, /* Digital Voodoo SD 8 Bit */ + { AV_PIX_FMT_VYU444, MKTAG('v', '3', '0', '8') }, + { AV_PIX_FMT_UYVA, MKTAG('v', '4', '0', '8') }, + { AV_PIX_FMT_V30XLE, MKTAG('v', '4', '1', '0') }, + { AV_PIX_FMT_AYUV, MKTAG('y', '4', '0', '8') }, + { AV_PIX_FMT_RGB555LE, MKTAG('L', '5', '5', '5') }, + { AV_PIX_FMT_RGB565LE, MKTAG('L', '5', '6', '5') }, + { AV_PIX_FMT_RGB565BE, MKTAG('B', '5', '6', '5') }, + { AV_PIX_FMT_BGR24, MKTAG('2', '4', 'B', 'G') }, + { AV_PIX_FMT_BGR24, MKTAG('b', 'x', 'b', 'g') }, + { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') }, + { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') }, + { AV_PIX_FMT_RGB24, MKTAG('b', 'x', 'r', 'g') }, + { AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') }, + { AV_PIX_FMT_GRAY16BE, MKTAG('b', '1', '6', 'g') }, + { AV_PIX_FMT_RGB48BE, MKTAG('b', '4', '8', 'r') }, + { AV_PIX_FMT_RGBA64BE, MKTAG('b', '6', '4', 'a') }, + { AV_PIX_FMT_BAYER_RGGB16BE, MKTAG('B', 'G', 'G', 'R') }, + + /* vlc */ + { AV_PIX_FMT_YUV410P, MKTAG('I', '4', '1', '0') }, + { AV_PIX_FMT_YUV411P, MKTAG('I', '4', '1', '1') }, + { AV_PIX_FMT_YUV422P, MKTAG('I', '4', '2', '2') }, + { AV_PIX_FMT_YUV440P, MKTAG('I', '4', '4', '0') }, + { AV_PIX_FMT_YUV444P, MKTAG('I', '4', '4', '4') }, + { AV_PIX_FMT_YUVJ420P, MKTAG('J', '4', '2', '0') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('J', '4', '2', '2') }, + { AV_PIX_FMT_YUVJ440P, MKTAG('J', '4', '4', '0') }, + { AV_PIX_FMT_YUVJ444P, MKTAG('J', '4', '4', '4') }, + { AV_PIX_FMT_YUVA444P, MKTAG('Y', 'U', 'V', 'A') }, + { AV_PIX_FMT_YUVA420P, MKTAG('I', '4', '0', 'A') }, + { AV_PIX_FMT_YUVA422P, MKTAG('I', '4', '2', 'A') }, + { AV_PIX_FMT_RGB8, MKTAG('R', 'G', 'B', '2') }, + { AV_PIX_FMT_RGB555LE, MKTAG('R', 'V', '1', '5') }, + { AV_PIX_FMT_RGB565LE, MKTAG('R', 'V', '1', '6') }, + { AV_PIX_FMT_BGR24, MKTAG('R', 'V', '2', '4') }, + { AV_PIX_FMT_BGR0, MKTAG('R', 'V', '3', '2') }, + { AV_PIX_FMT_RGBA, MKTAG('A', 'V', '3', '2') }, + { AV_PIX_FMT_YUV420P9LE, MKTAG('I', '0', '9', 'L') }, + { AV_PIX_FMT_YUV420P9BE, MKTAG('I', '0', '9', 'B') }, + { AV_PIX_FMT_YUV422P9LE, MKTAG('I', '2', '9', 'L') }, + { AV_PIX_FMT_YUV422P9BE, MKTAG('I', '2', '9', 'B') }, + { AV_PIX_FMT_YUV444P9LE, MKTAG('I', '4', '9', 'L') }, + { AV_PIX_FMT_YUV444P9BE, MKTAG('I', '4', '9', 'B') }, + { AV_PIX_FMT_YUV420P10LE, MKTAG('I', '0', 'A', 'L') }, + { AV_PIX_FMT_YUV420P10BE, MKTAG('I', '0', 'A', 'B') }, + { AV_PIX_FMT_YUV422P10LE, MKTAG('I', '2', 'A', 'L') }, + { AV_PIX_FMT_YUV422P10BE, MKTAG('I', '2', 'A', 'B') }, + { AV_PIX_FMT_YUV444P10LE, MKTAG('I', '4', 'A', 'L') }, + { AV_PIX_FMT_YUV444P10BE, MKTAG('I', '4', 'A', 'B') }, + { AV_PIX_FMT_YUV420P12LE, MKTAG('I', '0', 'C', 'L') }, + { AV_PIX_FMT_YUV420P12BE, MKTAG('I', '0', 'C', 'B') }, + { AV_PIX_FMT_YUV422P12LE, MKTAG('I', '2', 'C', 'L') }, + { AV_PIX_FMT_YUV422P12BE, MKTAG('I', '2', 'C', 'B') }, + { AV_PIX_FMT_YUV444P12LE, MKTAG('I', '4', 'C', 'L') }, + { AV_PIX_FMT_YUV444P12BE, MKTAG('I', '4', 'C', 'B') }, + { AV_PIX_FMT_YUV420P16LE, MKTAG('I', '0', 'F', 'L') }, + { AV_PIX_FMT_YUV420P16BE, MKTAG('I', '0', 'F', 'B') }, + { AV_PIX_FMT_YUV444P16LE, MKTAG('I', '4', 'F', 'L') }, + { AV_PIX_FMT_YUV444P16BE, MKTAG('I', '4', 'F', 'B') }, + + /* special */ + { AV_PIX_FMT_RGB565LE, MKTAG( 3 , 0 , 0 , 0 ) }, /* flipped RGB565LE */ + { AV_PIX_FMT_YUV444P, MKTAG('Y', 'V', '2', '4') }, /* YUV444P, swapped UV */ + + { AV_PIX_FMT_NONE, 0 }, +}; + +#endif /* AVCODEC_RAW_PIX_FMT_TAGS_H */ diff --git a/libavcodec/rawdec.c b/libavcodec/rawdec.c index b02edac37..53d1fba58 100644 --- a/libavcodec/rawdec.c +++ b/libavcodec/rawdec.c @@ -368,24 +368,13 @@ static int raw_decode(AVCodecContext *avctx, AVFrame *frame, return ret; } - if (ff_copy_palette(context->palette->data, avpkt, avctx)) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - } else if (context->is_nut_pal8) { + if (!ff_copy_palette(context->palette->data, avpkt, avctx) && context->is_nut_pal8) { int vid_size = avctx->width * avctx->height; int pal_size = avpkt->size - vid_size; if (avpkt->size > vid_size && pal_size <= AVPALETTE_SIZE) { const uint8_t *pal = avpkt->data + vid_size; memcpy(context->palette->data, pal, pal_size); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } } } diff --git a/libavcodec/rectangle.h b/libavcodec/rectangle.h index df7c18a4e..9f982b277 100644 --- a/libavcodec/rectangle.h +++ b/libavcodec/rectangle.h @@ -46,7 +46,7 @@ static av_always_inline void fill_rectangle(void *vp, int w, int h, int stride, w *= size; stride *= size; - av_assert2((((long)vp)&(FFMIN(w, 8<<(HAVE_NEON|ARCH_PPC|HAVE_MMX))-1)) == 0); + av_assert2((((uintptr_t)vp)&(FFMIN(w, 8<<(HAVE_NEON|ARCH_PPC|HAVE_MMX))-1)) == 0); av_assert2((stride&(w-1))==0); if(w==2){ const uint16_t v= size==4 ? val : val*0x0101; diff --git a/libavcodec/riscv/Makefile b/libavcodec/riscv/Makefile index 27befce92..2c5333492 100644 --- a/libavcodec/riscv/Makefile +++ b/libavcodec/riscv/Makefile @@ -32,7 +32,11 @@ OBJS-$(CONFIG_H264CHROMA) += riscv/h264_chroma_init_riscv.o RVV-OBJS-$(CONFIG_H264CHROMA) += riscv/h264_mc_chroma.o OBJS-$(CONFIG_H264DSP) += riscv/h264dsp_init.o RVV-OBJS-$(CONFIG_H264DSP) += riscv/h264addpx_rvv.o riscv/h264dsp_rvv.o \ - riscv/h264idct_rvv.o + riscv/h264idct_rvv.o riscv/h264idct_dequant_rvv.o +OBJS-$(CONFIG_H264QPEL) += riscv/h264qpel_init.o +RVV-OBJS-$(CONFIG_H264QPEL) += riscv/h264qpel_rvv.o +OBJS-$(CONFIG_HEVC_DECODER) += riscv/hevcdsp_init.o +RVV-OBJS-$(CONFIG_HEVC_DECODER) += riscv/h26x/h2656_inter_rvv.o OBJS-$(CONFIG_HUFFYUV_DECODER) += riscv/huffyuvdsp_init.o RVV-OBJS-$(CONFIG_HUFFYUV_DECODER) += riscv/huffyuvdsp_rvv.o OBJS-$(CONFIG_IDCTDSP) += riscv/idctdsp_init.o @@ -42,13 +46,16 @@ RVV-OBJS-$(CONFIG_LLAUDDSP) += riscv/llauddsp_rvv.o OBJS-$(CONFIG_LLVIDDSP) += riscv/llviddsp_init.o RVV-OBJS-$(CONFIG_LLVIDDSP) += riscv/llviddsp_rvv.o OBJS-$(CONFIG_LLVIDENCDSP) += riscv/llvidencdsp_init.o +RV-OBJS-$(CONFIG_LLVIDENCDSP) += riscv/llvidencdsp_rvb.o RVV-OBJS-$(CONFIG_LLVIDENCDSP) += riscv/llvidencdsp_rvv.o OBJS-$(CONFIG_LPC) += riscv/lpc_init.o RVV-OBJS-$(CONFIG_LPC) += riscv/lpc_rvv.o OBJS-$(CONFIG_ME_CMP) += riscv/me_cmp_init.o RVV-OBJS-$(CONFIG_ME_CMP) += riscv/me_cmp_rvv.o -OBJS-$(CONFIG_MPEGVIDEOENC) += riscv/mpegvideoencdsp_init.o -RVV-OBJS-$(CONFIG_MPEGVIDEOENC) += riscv/mpegvideoencdsp_rvv.o +OBJS-$(CONFIG_MPEGVIDEO) += riscv/mpegvideo_init.o +RVV-OBJS-$(CONFIG_MPEGVIDEO) += riscv/mpegvideo_rvv.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += riscv/mpegvideoencdsp_init.o +RVV-OBJS-$(CONFIG_MPEGVIDEOENCDSP) += riscv/mpegvideoencdsp_rvv.o OBJS-$(CONFIG_OPUS_DECODER) += riscv/opusdsp_init.o RVV-OBJS-$(CONFIG_OPUS_DECODER) += riscv/opusdsp_rvv.o OBJS-$(CONFIG_PIXBLOCKDSP) += riscv/pixblockdsp_init.o diff --git a/libavcodec/riscv/aacencdsp_init.c b/libavcodec/riscv/aacencdsp_init.c index a2dc0a8d3..7b4e595af 100644 --- a/libavcodec/riscv/aacencdsp_init.c +++ b/libavcodec/riscv/aacencdsp_init.c @@ -1,6 +1,6 @@ /* * AAC encoder assembly optimizations - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/aacencdsp_rvv.S b/libavcodec/riscv/aacencdsp_rvv.S index 83d186807..e19b209a1 100644 --- a/libavcodec/riscv/aacencdsp_rvv.S +++ b/libavcodec/riscv/aacencdsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * Copyright © 2024 Rémi Denis-Courmont. * * This file is part of FFmpeg. diff --git a/libavcodec/riscv/ac3dsp_init.c b/libavcodec/riscv/ac3dsp_init.c index 24b388185..f68a59283 100644 --- a/libavcodec/riscv/ac3dsp_init.c +++ b/libavcodec/riscv/ac3dsp_init.c @@ -65,8 +65,8 @@ av_cold void ff_ac3dsp_init_riscv(AC3DSPContext *c) c->sum_square_butterfly_int32 = ff_sum_square_butterfly_int32_rvv; # endif -# endif } } +# endif #endif } diff --git a/libavcodec/riscv/ac3dsp_rvb.S b/libavcodec/riscv/ac3dsp_rvb.S index a3c5187cf..ecf45a000 100644 --- a/libavcodec/riscv/ac3dsp_rvb.S +++ b/libavcodec/riscv/ac3dsp_rvb.S @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" func ff_ac3_exponent_min_rvb, zbb diff --git a/libavcodec/riscv/ac3dsp_rvv.S b/libavcodec/riscv/ac3dsp_rvv.S index 261cb9628..b1eded028 100644 --- a/libavcodec/riscv/ac3dsp_rvv.S +++ b/libavcodec/riscv/ac3dsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" func ff_ac3_exponent_min_rvv, zve32x diff --git a/libavcodec/riscv/ac3dsp_rvvb.S b/libavcodec/riscv/ac3dsp_rvvb.S index 2f4e64455..b8f714d87 100644 --- a/libavcodec/riscv/ac3dsp_rvvb.S +++ b/libavcodec/riscv/ac3dsp_rvvb.S @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" func ff_extract_exponents_rvvb, zve32x, zvbb, zba diff --git a/libavcodec/riscv/blockdsp_init.c b/libavcodec/riscv/blockdsp_init.c index adde0b890..81c0e38b9 100644 --- a/libavcodec/riscv/blockdsp_init.c +++ b/libavcodec/riscv/blockdsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/blockdsp_rvv.S b/libavcodec/riscv/blockdsp_rvv.S index 04da26541..99760e98b 100644 --- a/libavcodec/riscv/blockdsp_rvv.S +++ b/libavcodec/riscv/blockdsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/bswapdsp_rvb.S b/libavcodec/riscv/bswapdsp_rvb.S index 8c7c791fe..9dff287a3 100644 --- a/libavcodec/riscv/bswapdsp_rvb.S +++ b/libavcodec/riscv/bswapdsp_rvb.S @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" #include "libavutil/riscv/bswap_rvb.S" diff --git a/libavcodec/riscv/bswapdsp_rvv.S b/libavcodec/riscv/bswapdsp_rvv.S index b4911bf0e..ea0be2de4 100644 --- a/libavcodec/riscv/bswapdsp_rvv.S +++ b/libavcodec/riscv/bswapdsp_rvv.S @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" func ff_bswap16_buf_rvv, zve32x, zba diff --git a/libavcodec/riscv/bswapdsp_rvvb.S b/libavcodec/riscv/bswapdsp_rvvb.S index 165ac104a..e420099f7 100644 --- a/libavcodec/riscv/bswapdsp_rvvb.S +++ b/libavcodec/riscv/bswapdsp_rvvb.S @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" func ff_bswap32_buf_rvvb, zve32x, zvbb, zba diff --git a/libavcodec/riscv/h263dsp_rvv.S b/libavcodec/riscv/h263dsp_rvv.S index e9cb4ec07..704344ec0 100644 --- a/libavcodec/riscv/h263dsp_rvv.S +++ b/libavcodec/riscv/h263dsp_rvv.S @@ -43,7 +43,7 @@ func ff_h263_h_loop_filter_rvv, zve32x vsrl.vi v18, v16, 16 - 3 # v18 = (v16 < 0) ? 7 : 0 slli t2, t1, 1 # 2 * strength vadd.vv v16, v16, v18 - # v16 (d) is signed 7-bit, but later arithmetics require 9 bits. + # v16 (d) is signed 7-bit, but later arithmetic require 9 bits. vsra.vi v16, v16, 3 # d vmv.v.x v20, t2 vmslt.vi v0, v16, 0 diff --git a/libavcodec/riscv/h264dsp_init.c b/libavcodec/riscv/h264dsp_init.c index 9ffc9b033..5efec9eb5 100644 --- a/libavcodec/riscv/h264dsp_init.c +++ b/libavcodec/riscv/h264dsp_init.c @@ -40,6 +40,12 @@ void ff_h264_h_loop_filter_luma_8_rvv(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); void ff_h264_h_loop_filter_luma_mbaff_8_rvv(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); +void ff_h264_v_loop_filter_luma_intra_8_rvv(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_luma_intra_8_rvv(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_luma_mbaff_intra_8_rvv(uint8_t *pix, ptrdiff_t s, + int a, int b); void ff_h264_v_loop_filter_chroma_8_rvv(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); void ff_h264_h_loop_filter_chroma_8_rvv(uint8_t *pix, ptrdiff_t stride, @@ -47,6 +53,13 @@ void ff_h264_h_loop_filter_chroma_8_rvv(uint8_t *pix, ptrdiff_t stride, void ff_h264_h_loop_filter_chroma_mbaff_8_rvv(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); +void ff_h264_v_loop_filter_chroma_intra_8_rvv(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_chroma_intra_8_rvv(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_chroma_mbaff_intra_8_rvv(uint8_t *pix, + ptrdiff_t stride, + int alpha, int beta); #define IDCT_DEPTH(depth) \ void ff_h264_idct_add_##depth##_rvv(uint8_t *d, int16_t *s, int stride); \ @@ -67,7 +80,8 @@ void ff_h264_idct4_add8_##depth##_rvv(uint8_t **d, const int *soffset, \ const uint8_t nnzc[5 * 8]); \ void ff_h264_idct4_add8_422_##depth##_rvv(uint8_t **d, const int *soffset, \ int16_t *s, int stride, \ - const uint8_t nnzc[5 * 8]); + const uint8_t nnzc[5 * 8]); \ +void ff_h264_luma_dc_dequant_idct_##depth##_rvv(int16_t *d, int16_t *s, int q); IDCT_DEPTH(8) IDCT_DEPTH(9) @@ -96,72 +110,109 @@ av_cold void ff_h264dsp_init_riscv(H264DSPContext *dsp, const int bit_depth, if (flags & AV_CPU_FLAG_RVV_I32) { const bool zvl128b = ff_rv_vlen_least(128); - if (bit_depth == 8 && zvl128b) { - for (int i = 0; i < 4; i++) { - dsp->weight_h264_pixels_tab[i] = - ff_h264_weight_funcs_8_rvv[i].weight; - dsp->biweight_h264_pixels_tab[i] = - ff_h264_weight_funcs_8_rvv[i].biweight; - } - - dsp->h264_v_loop_filter_luma = ff_h264_v_loop_filter_luma_8_rvv; - dsp->h264_h_loop_filter_luma = ff_h264_h_loop_filter_luma_8_rvv; - dsp->h264_h_loop_filter_luma_mbaff = - ff_h264_h_loop_filter_luma_mbaff_8_rvv; - dsp->h264_v_loop_filter_chroma = - ff_h264_v_loop_filter_chroma_8_rvv; - if (chroma_format_idc <= 1) { - dsp->h264_h_loop_filter_chroma = - ff_h264_h_loop_filter_chroma_8_rvv; - dsp->h264_h_loop_filter_chroma_mbaff = - ff_h264_h_loop_filter_chroma_mbaff_8_rvv; - } - - dsp->h264_idct_add = ff_h264_idct_add_8_rvv; - dsp->h264_idct8_add = ff_h264_idct8_add_8_rvv; - if (flags & AV_CPU_FLAG_RVB) { - dsp->h264_idct_dc_add = ff_h264_idct4_dc_add_8_rvv; - dsp->h264_idct_add16 = ff_h264_idct_add16_8_rvv; - dsp->h264_idct_add16intra = ff_h264_idct_add16intra_8_rvv; -# if __riscv_xlen == 64 - dsp->h264_idct8_add4 = ff_h264_idct8_add4_8_rvv; - if (chroma_format_idc <= 1) - dsp->h264_idct_add8 = ff_h264_idct4_add8_8_rvv; - else - dsp->h264_idct_add8 = ff_h264_idct4_add8_422_8_rvv; -# endif + if (bit_depth == 8) { + if (zvl128b) { + if (flags & AV_CPU_FLAG_RVB) + dsp->weight_pixels_tab[0] = + ff_h264_weight_funcs_8_rvv[0].weight; + dsp->biweight_pixels_tab[0] = + ff_h264_weight_funcs_8_rvv[0].biweight; } if (flags & AV_CPU_FLAG_RVV_I64) { - dsp->h264_add_pixels8_clear = ff_h264_add_pixels8_8_rvv; - if (flags & AV_CPU_FLAG_RVB) - dsp->h264_idct8_dc_add = ff_h264_idct8_dc_add_8_rvv; + dsp->weight_pixels_tab[1] = + ff_h264_weight_funcs_8_rvv[1].weight; + dsp->biweight_pixels_tab[1] = + ff_h264_weight_funcs_8_rvv[1].biweight; } - dsp->h264_add_pixels4_clear = ff_h264_add_pixels4_8_rvv; + dsp->weight_pixels_tab[2] = + ff_h264_weight_funcs_8_rvv[2].weight; + dsp->biweight_pixels_tab[2] = + ff_h264_weight_funcs_8_rvv[2].biweight; + dsp->weight_pixels_tab[3] = + ff_h264_weight_funcs_8_rvv[3].weight; + dsp->biweight_pixels_tab[3] = + ff_h264_weight_funcs_8_rvv[3].biweight; + } + + if (bit_depth == 8 && zvl128b) { + dsp->v_loop_filter_luma = ff_h264_v_loop_filter_luma_8_rvv; + dsp->h_loop_filter_luma = ff_h264_h_loop_filter_luma_8_rvv; + dsp->h_loop_filter_luma_mbaff = + ff_h264_h_loop_filter_luma_mbaff_8_rvv; + dsp->v_loop_filter_luma_intra = + ff_h264_v_loop_filter_luma_intra_8_rvv; + dsp->h_loop_filter_luma_intra = + ff_h264_h_loop_filter_luma_intra_8_rvv; + dsp->h_loop_filter_luma_mbaff_intra = + ff_h264_h_loop_filter_luma_mbaff_intra_8_rvv; + dsp->v_loop_filter_chroma = + ff_h264_v_loop_filter_chroma_8_rvv; + dsp->v_loop_filter_chroma_intra = + ff_h264_v_loop_filter_chroma_intra_8_rvv; + + if (chroma_format_idc <= 1) { + dsp->h_loop_filter_chroma = + ff_h264_h_loop_filter_chroma_8_rvv; + dsp->h_loop_filter_chroma_mbaff = + ff_h264_h_loop_filter_chroma_mbaff_8_rvv; + dsp->h_loop_filter_chroma_intra = + ff_h264_h_loop_filter_chroma_intra_8_rvv; + dsp->h_loop_filter_chroma_mbaff_intra = + ff_h264_h_loop_filter_chroma_mbaff_intra_8_rvv; + } + + dsp->idct_add = ff_h264_idct_add_8_rvv; + dsp->idct8_add = ff_h264_idct8_add_8_rvv; + if (flags & AV_CPU_FLAG_RVB) { + dsp->idct_dc_add = ff_h264_idct4_dc_add_8_rvv; + dsp->idct_add16 = ff_h264_idct_add16_8_rvv; + dsp->idct_add16intra = ff_h264_idct_add16intra_8_rvv; +# if __riscv_xlen == 64 + dsp->idct8_add4 = ff_h264_idct8_add4_8_rvv; + if (chroma_format_idc <= 1) + dsp->idct_add8 = ff_h264_idct4_add8_8_rvv; + else + dsp->idct_add8 = ff_h264_idct4_add8_422_8_rvv; +# endif + } + + dsp->luma_dc_dequant_idct = + ff_h264_luma_dc_dequant_idct_8_rvv; + + if (flags & AV_CPU_FLAG_RVV_I64) { + dsp->add_pixels8_clear = ff_h264_add_pixels8_8_rvv; + if (flags & AV_CPU_FLAG_RVB) + dsp->idct8_dc_add = ff_h264_idct8_dc_add_8_rvv; + } + dsp->add_pixels4_clear = ff_h264_add_pixels4_8_rvv; } #define IDCT_DEPTH(depth) \ if (bit_depth == depth) { \ - if (zvl128b) \ - dsp->h264_idct_add = ff_h264_idct_add_##depth##_rvv; \ + if (zvl128b) { \ + dsp->idct_add = ff_h264_idct_add_##depth##_rvv; \ + dsp->luma_dc_dequant_idct = \ + ff_h264_luma_dc_dequant_idct_9_rvv; \ + } \ if (flags & AV_CPU_FLAG_RVB) \ - dsp->h264_idct8_add = ff_h264_idct8_add_##depth##_rvv; \ + dsp->idct8_add = ff_h264_idct8_add_##depth##_rvv; \ if (zvl128b && (flags & AV_CPU_FLAG_RVB)) { \ - dsp->h264_idct_dc_add = ff_h264_idct4_dc_add_##depth##_rvv; \ - dsp->h264_idct8_dc_add = ff_h264_idct8_dc_add_##depth##_rvv; \ - dsp->h264_idct_add16 = ff_h264_idct_add16_##depth##_rvv; \ - dsp->h264_idct_add16intra = \ + dsp->idct_dc_add = ff_h264_idct4_dc_add_##depth##_rvv; \ + dsp->idct8_dc_add = ff_h264_idct8_dc_add_##depth##_rvv; \ + dsp->idct_add16 = ff_h264_idct_add16_##depth##_rvv; \ + dsp->idct_add16intra = \ ff_h264_idct_add16intra_##depth##_rvv; \ if (__riscv_xlen == 64) { \ if (chroma_format_idc <= 1) \ - dsp->h264_idct_add8 = \ + dsp->idct_add8 = \ ff_h264_idct4_add8_##depth##_rvv; \ else \ - dsp->h264_idct_add8 = \ + dsp->idct_add8 = \ ff_h264_idct4_add8_422_##depth##_rvv; \ } \ } \ if (__riscv_xlen == 64 && (flags & AV_CPU_FLAG_RVB)) \ - dsp->h264_idct8_add4 = ff_h264_idct8_add4_##depth##_rvv; \ + dsp->idct8_add4 = ff_h264_idct8_add4_##depth##_rvv; \ } IDCT_DEPTH(9) @@ -170,9 +221,9 @@ av_cold void ff_h264dsp_init_riscv(H264DSPContext *dsp, const int bit_depth, IDCT_DEPTH(14) if (bit_depth > 8 && zvl128b) { - dsp->h264_add_pixels8_clear = ff_h264_add_pixels8_16_rvv; + dsp->add_pixels8_clear = ff_h264_add_pixels8_16_rvv; if (flags & AV_CPU_FLAG_RVV_I64) - dsp->h264_add_pixels4_clear = ff_h264_add_pixels4_16_rvv; + dsp->add_pixels4_clear = ff_h264_add_pixels4_16_rvv; } dsp->startcode_find_candidate = ff_startcode_find_candidate_rvv; diff --git a/libavcodec/riscv/h264dsp_rvv.S b/libavcodec/riscv/h264dsp_rvv.S index 97c670830..60015a702 100644 --- a/libavcodec/riscv/h264dsp_rvv.S +++ b/libavcodec/riscv/h264dsp_rvv.S @@ -28,21 +28,30 @@ #include "libavutil/riscv/asm.S" -func ff_h264_weight_pixels_simple_8_rvv, zve32x + .variant_cc ff_h264_weight_pixels_simple_8_rvv +func ff_h264_weight_pixels_simple_8_rvv, zve32x, b csrwi vxrm, 0 sll a5, a5, a3 1: - vsetvli zero, a6, e16, m2, ta, ma - vle8.v v8, (a0) - addi a2, a2, -1 + vsetvli zero, t6, e16, m2, ta, ma + add t0, a0, a1 + vle8.v v8, (a0) + addi a2, a2, -2 + vle8.v v9, (t0) vzext.vf2 v24, v8 + vzext.vf2 v26, v9 vmul.vx v16, v24, a4 + vmul.vx v18, v26, a4 vsadd.vx v16, v16, a5 - vmax.vx v16, v16, zero - vsetvli zero, zero, e8, m1, ta, ma + vsadd.vx v18, v18, a5 + vmax.vx v16, v16, zero + vmax.vx v18, v18, zero + vsetvli zero, zero, e8, m1, ta, ma vnclipu.wx v8, v16, a3 - vse8.v v8, (a0) - add a0, a0, a1 + vnclipu.wx v9, v18, a3 + vse8.v v8, (a0) + vse8.v v9, (t0) + sh1add a0, a1, a0 bnez a2, 1b ret @@ -76,103 +85,77 @@ func ff_h264_biweight_pixels_simple_8_rvv, zve32x ret endfunc -func ff_h264_weight_pixels_8_rvv, zve32x +.macro h264_weight depth, w, b= +func ff_h264_weight_pixels\w\()_\depth\()_rvv, zve64x + lpad 0 + .ifb \b + li t6, \w + j ff_h264_weight_pixels_simple_\depth\()_rvv + .else csrwi vxrm, 0 sll a5, a5, a3 1: - mv t0, a0 - mv t6, a6 -2: - vsetvli t2, a2, e16, m8, ta, ma - vlsseg2e8.v v0, (t0), a1 - addi t6, t6, -2 - vzext.vf2 v16, v0 - vzext.vf2 v24, v4 - vmul.vx v16, v16, a4 - vmul.vx v24, v24, a4 + vsetvli t1, a2, e\b, m2, ta, ma + vlse\b\().v v8, (a0), a1 + vsetvli t0, zero, e16, m4, ta, ma + vzext.vf2 v24, v8 + sub a2, a2, t1 + vmul.vx v16, v24, a4 + mul t2, t1, a1 vsadd.vx v16, v16, a5 - vsadd.vx v24, v24, a5 vmax.vx v16, v16, zero - vmax.vx v24, v24, zero - vsetvli zero, zero, e8, m4, ta, ma - vnclipu.wx v0, v16, a3 - vnclipu.wx v4, v24, a3 - vssseg2e8.v v0, (t0), a1 - addi t0, t0, 2 - bnez t6, 2b - - mul t3, a1, t2 - sub a2, a2, t2 - add a0, a0, t3 + vsetvli zero, zero, e8, m2, ta, ma + vnclipu.wx v8, v16, a3 + vsetvli zero, t1, e\b, m2, ta, ma + vsse\b\().v v8, (a0), a1 + add a0, a0, t2 bnez a2, 1b ret + .endif endfunc - .variant_cc ff_h264_biweight_pixels_8_rvv -func ff_h264_biweight_pixels_8_rvv, zve32x +func ff_h264_biweight_pixels\w\()_\depth\()_rvv, zve64x + lpad 0 + li t6, \w + .ifb \b + j ff_h264_biweight_pixels_simple_8_rvv + .else csrwi vxrm, 2 addi a7, a7, 1 ori a7, a7, 1 sll a7, a7, a4 addi a4, a4, 1 1: - mv t0, a0 - mv t1, a1 - mv t5, t6 -2: - vsetvli t2, a3, e16, m8, ta, ma - vlsseg2e8.v v0, (t0), a2 - vlsseg2e8.v v8, (t1), a2 - addi t5, t5, -2 - vmv.v.x v16, a7 - vmv.v.x v24, a7 - vsetvli zero, zero, e8, m4, ta, ma - vwmaccsu.vx v16, a5, v0 - vwmaccsu.vx v24, a5, v4 - vwmaccsu.vx v16, a6, v8 - vwmaccsu.vx v24, a6, v12 - vsetvli zero, zero, e16, m8, ta, ma + vsetvli t1, a3, e\b, m2, ta, ma + vlse\b\().v v8, (a0), a2 + sub a3, a3, t1 + vlse\b\().v v12, (a1), a2 + mul t2, t1, a2 + vsetvli t0, zero, e16, m4, ta, ma + vmv.v.x v16, a7 + vsetvli zero, zero, e8, m2, ta, ma + vwmaccsu.vx v16, a5, v8 + add a1, a1, t2 + vwmaccsu.vx v16, a6, v12 + vsetvli zero, zero, e16, m4, ta, ma vmax.vx v16, v16, zero - vmax.vx v24, v24, zero - vsetvli zero, zero, e8, m4, ta, ma - vnclipu.wx v0, v16, a4 - vnclipu.wx v4, v24, a4 - vssseg2e8.v v0, (t0), a2 - addi t0, t0, 2 - addi t1, t1, 2 - bnez t5, 2b - - mul t3, a2, t2 - sub a3, a3, t2 - add a0, a0, t3 - add a1, a1, t3 + vsetvli zero, zero, e8, m2, ta, ma + vnclipu.wx v8, v16, a4 + vsetvli zero, t1, e\b, m2, ta, ma + vsse\b\().v v8, (a0), a2 + add a0, a0, t2 + .endif bnez a3, 1b ret endfunc +.endm -.irp w, 16, 8, 4, 2 -func ff_h264_weight_pixels\w\()_8_rvv, zve32x - lpad 0 - li a6, \w - .if \w == 16 - j ff_h264_weight_pixels_simple_8_rvv - .else - j ff_h264_weight_pixels_8_rvv - .endif -endfunc - -func ff_h264_biweight_pixels\w\()_8_rvv, zve32x - lpad 0 - li t6, \w - .if \w == 16 - j ff_h264_biweight_pixels_simple_8_rvv - .else - j ff_h264_biweight_pixels_8_rvv - .endif -endfunc -.endr +h264_weight 8, 2, 16 +h264_weight 8, 4, 32 +h264_weight 8, 8, 64 +h264_weight 8, 16 .global ff_h264_weight_funcs_8_rvv .hidden ff_h264_weight_funcs_8_rvv @@ -304,7 +287,6 @@ func ff_h264_v_loop_filter_\type\()_8_rvv, zve32x vsetivli zero, 4 * \inners, e8, \e8mul, ta, ma vle8.v v11, (a0) sub t2, t3, a1 - vid.v v0 vle8.v v10, (t3) add t5, a0, a1 vle8.v v9, (t2) @@ -326,6 +308,125 @@ func ff_h264_v_loop_filter_\type\()_8_rvv, zve32x vse8.v v11, (a0) ret endfunc + + .variant_cc ff_h264_loop_filter_\type\()_intra_8_rvv +func ff_h264_loop_filter_\type\()_intra_8_rvv, zve32x + # p3: v8, p2: v9, p1: v10, p0: v11, q0: v12, q1: v13, q2: v14, q3: v15 + # alpha: a2, beta: a3 + csrwi vxrm, 0 + srai a4, a2, 2 + vwsubu.vv v16, v11, v12 + addi a4, a4, 2 + vwsubu.vv v18, v12, v11 + vwsubu.vv v20, v10, v11 + vwsubu.vv v22, v11, v10 + vwsubu.vv v24, v13, v12 + vwsubu.vv v26, v12, v13 + vwsubu.vv v28, v11, v9 + vwsubu.vv v30, v9, v11 + vwsubu.vv v4, v14, v12 + vwsubu.vv v6, v12, v14 + vsetvli zero, zero, e16, \e16mul, ta, ma + vmax.vv v16, v16, v18 # abs(p0 - q0) + vmax.vv v20, v20, v22 # abs(p1 - p0) + vmslt.vx v18, v16, a2 + vmax.vv v24, v24, v26 # abs(q1 - q0) + vmslt.vx v22, v20, a3 +.ifc \type, luma + vmax.vv v28, v28, v30 # abs(p2 - p0) +.endif + vmand.mm v18, v18, v22 + vmslt.vx v23, v24, a3 +.ifc \type, luma + vmax.vv v4, v4, v6 # abs(q2 - q0) + vmand.mm v1, v18, v23 # abs(...) < A && abs(..) < B && abs(..) < B + vmslt.vx v3, v16, a4 # abs(p0 - q0) < (alpha / 4) + 2 + vmslt.vx v6, v28, a3 # abs(p2 - p0) < beta + vmslt.vx v7, v4, a3 # abs(q2 - q0) < beta + vmand.mm v2, v3, v6 + vmand.mm v3, v3, v7 +.else + vmand.mm v0, v18, v23 +.endif + vsetvli zero, zero, e8, \e8mul, ta, mu + vwaddu.vv v22, v11, v13 + vwaddu.vv v30, v10, v12 + vwaddu.wv v22, v22, v10 + vwaddu.wv v30, v30, v13 + vwaddu.wv v22, v22, v10 # 2p1 + p0 + q1 + vwaddu.wv v30, v30, v13 # p1 + q0 + 2q1 +.ifc \type, luma + vwaddu.vv v16, v10, v11 + vwaddu.vv v20, v8, v9 + vwaddu.wv v16, v16, v12 # p1 + p0 + q0 + vwaddu.vv v24, v11, v12 + vwaddu.vv v28, v14, v15 + vwaddu.wv v24, v24, v13 # p0 + q0 + q1 + vwaddu.wv v18, v16, v9 # p2 + p1 + p0 + q0 + vwaddu.wv v16, v16, v13 # p1 + p0 + q0 + q1 + vwaddu.wv v26, v24, v14 # p0 + q0 + q1 + q2 + vwaddu.wv v24, v24, v10 # p1 + p0 + q0 + q1 + vsetvli zero, zero, e16, \e16mul, ta, ma + vsll.vi v20, v20, 1 # 2p3 +2p2 + vadd.vv v16, v16, v18 # p2 +2p1 +2p0 +2q0 + q1 + vadd.vv v20, v18, v20 # 2p3 +3p3 + p1 + p0 + q0 + vsll.vi v28, v28, 1 # 2q2 +2q3 + vadd.vv v24, v24, v26 # p1 +2p0 +2q0 +2q1 + q2 + vadd.vv v28, v26, v28 # p0 + q0 + q1 +3q2 +2q3 + vsetvli zero, zero, e8, \e8mul, ta, mu + vmand.mm v0, v1, v2 + vnclipu.wi v11, v16, 3, v0.t # p0' + vnclipu.wi v10, v18, 2, v0.t # p1' + vnclipu.wi v9, v20, 3, v0.t # p2' + vmandn.mm v0, v1, v2 +.endif + vnclipu.wi v11, v22, 2, v0.t # p0' +.ifc \type, luma + vmand.mm v0, v1, v3 + vnclipu.wi v12, v24, 3, v0.t # q0' + vnclipu.wi v13, v26, 2, v0.t # q1' + vnclipu.wi v14, v28, 3, v0.t # q2' + vmandn.mm v0, v1, v3 +.endif + vnclipu.wi v12, v30, 2, v0.t # q0' + jr t0 +endfunc + +func ff_h264_v_loop_filter_\type\()_intra_8_rvv, zve32x + lpad 0 + sub t3, a0, a1 + vsetivli zero, 4 * \inners, e8, \e8mul, ta, ma + vle8.v v12, (a0) + sub t2, t3, a1 + vle8.v v11, (t3) + add t4, a0, a1 + vle8.v v10, (t2) +.ifc \type, luma + sub t1, t2, a1 +.endif + vle8.v v13, (t4) +.ifc \type, luma + sub t0, t1, a1 + vle8.v v9, (t1) + add t5, t4, a1 + vle8.v v8, (t0) + add t6, t5, a1 + vle8.v v14, (t5) + vle8.v v15, (t6) +.endif + jal t0, ff_h264_loop_filter_\type\()_intra_8_rvv +.ifc \type, luma + vse8.v v9, (t1) + vse8.v v10, (t2) +.endif + vse8.v v11, (t3) + vse8.v v12, (a0) +.ifc \type, luma + vse8.v v13, (t4) + vse8.v v14, (t5) +.endif + ret +endfunc .endm loop_filter luma, 4, m1, m2 @@ -391,3 +492,47 @@ func ff_h264_h_loop_filter_chroma_mbaff_8_rvv, zve32x vssseg2e8.v v10, (a0), a1 ret endfunc + +func ff_h264_h_loop_filter_luma_intra_8_rvv, zve32x + lpad 0 + addi a0, a0, -4 + vsetivli zero, 16, e8, m1, ta, ma + vlsseg8e8.v v8, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_luma_intra_8_rvv + vssseg6e8.v v9, (a0), a1 + ret +endfunc + +func ff_h264_h_loop_filter_luma_mbaff_intra_8_rvv, zve32x + lpad 0 + addi a0, a0, -4 + vsetivli zero, 8, e8, m1, ta, ma + vlsseg8e8.v v8, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_luma_intra_8_rvv + vssseg6e8.v v9, (a0), a1 + ret +endfunc + +func ff_h264_h_loop_filter_chroma_intra_8_rvv, zve32x + lpad 0 + addi a0, a0, -2 + vsetivli zero, 8, e8, mf2, ta, ma + vlsseg4e8.v v10, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_chroma_intra_8_rvv + vssseg2e8.v v11, (a0), a1 + ret +endfunc + +func ff_h264_h_loop_filter_chroma_mbaff_intra_8_rvv, zve32x + lpad 0 + addi a0, a0, -2 + vsetivli zero, 4, e8, mf2, ta, ma + vlsseg4e8.v v10, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_chroma_intra_8_rvv + vssseg2e8.v v11, (a0), a1 + ret +endfunc diff --git a/libavcodec/riscv/h264idct_dequant_rvv.S b/libavcodec/riscv/h264idct_dequant_rvv.S new file mode 100644 index 000000000..bc49ca6ad --- /dev/null +++ b/libavcodec/riscv/h264idct_dequant_rvv.S @@ -0,0 +1,141 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright © 2025 Rémi Denis-Courmont. + * + * 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. + * + * 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 OWNER 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 "libavutil/riscv/asm.S" + +const offsets_8, 1 + .short 0, 64, 256, 320 +endconst + +func ff_h264_luma_dc_dequant_idct_8_rvv, zve32x + lpad 0 + csrwi vxrm, 0 + vsetivli zero, 4, e16, mf2, ta, ma + vlseg4e16.v v8, (a1) + vwadd.vv v16, v8, v9 # z0 + addi t1, sp, 4 * 4 * -3 + vwadd.vv v19, v10, v11 # z3 + addi t2, sp, 4 * 4 * -2 + vwsub.vv v17, v8, v9 # z1 + addi t3, sp, 4 * 4 * -1 + vwsub.vv v18, v10, v11 # z2 + vsetvli zero, zero, e32, m1, ta, ma + vadd.vv v8, v16, v19 + addi sp, sp, 4 * 4 * -4 + vsub.vv v9, v16, v19 + vsub.vv v10, v17, v18 + vadd.vv v11, v17, v18 + vsseg4e32.v v8, (sp) + vle32.v v8, (sp) + vle32.v v9, (t1) + vle32.v v10, (t2) + vle32.v v11, (t3) + vadd.vv v16, v8, v10 # z0 + addi sp, sp, 4 * 4 * 4 + vadd.vv v19, v9, v11 # z3 + lla t0, offsets_8 + vsub.vv v17, v8, v10 # z1 + vsub.vv v18, v9, v11 # z2 + vadd.vv v8, v16, v19 + vadd.vv v9, v17, v18 + vsub.vv v10, v17, v18 + vsub.vv v11, v16, v19 + vle16.v v24, (t0) + vmul.vx v8, v8, a2 + vmul.vx v9, v9, a2 + vmul.vx v10, v10, a2 + vmul.vx v11, v11, a2 + vsetvli zero, zero, e16, mf2, ta, ma + vnclip.wi v16, v8, 8 + addi t1, a0, 2 * 16 * 1 + vnclip.wi v17, v9, 8 + addi t2, a0, 2 * 16 * 4 + vnclip.wi v18, v10, 8 + addi t3, a0, 2 * 16 * 5 + vnclip.wi v19, v11, 8 + vsuxei16.v v16, (a0), v24 + vsuxei16.v v17, (t1), v24 + vsuxei16.v v18, (t2), v24 + vsuxei16.v v19, (t3), v24 + ret +endfunc + +const offsets_9, 1 + .short 0, 128, 512, 640 +endconst + +func ff_h264_luma_dc_dequant_idct_9_rvv, zve32x + lpad 0 + csrwi vxrm, 0 + vsetivli zero, 4, e32, m1, ta, ma + vlseg4e32.v v8, (a1) + vadd.vv v16, v8, v9 # z0 + addi t1, sp, 4 * 4 * -3 + vadd.vv v19, v10, v11 # z3 + addi t2, sp, 4 * 4 * -2 + vsub.vv v17, v8, v9 # z1 + addi t3, sp, 4 * 4 * -1 + vsub.vv v18, v10, v11 # z2 + vadd.vv v8, v16, v19 + addi sp, sp, 4 * 4 * -4 + vsub.vv v9, v16, v19 + vsub.vv v10, v17, v18 + vadd.vv v11, v17, v18 + vsseg4e32.v v8, (sp) + vle32.v v8, (sp) + vle32.v v9, (t1) + vle32.v v10, (t2) + vle32.v v11, (t3) + vadd.vv v16, v8, v10 # z0 + addi sp, sp, 4 * 4 * 4 + vadd.vv v19, v9, v11 # z3 + lla t0, offsets_9 + vsub.vv v17, v8, v10 # z1 + vsub.vv v18, v9, v11 # z2 + vadd.vv v8, v16, v19 + vadd.vv v9, v17, v18 + vsub.vv v10, v17, v18 + vsub.vv v11, v16, v19 + vle16.v v24, (t0) + vmul.vx v8, v8, a2 + vmul.vx v9, v9, a2 + vmul.vx v10, v10, a2 + vmul.vx v11, v11, a2 + vssra.vi v16, v8, 8 + addi t1, a0, 4 * 16 * 1 + vssra.vi v17, v9, 8 + addi t2, a0, 4 * 16 * 4 + vssra.vi v18, v10, 8 + addi t3, a0, 4 * 16 * 5 + vssra.vi v19, v11, 8 + vsuxei16.v v16, (a0), v24 + vsuxei16.v v17, (t1), v24 + vsuxei16.v v18, (t2), v24 + vsuxei16.v v19, (t3), v24 + ret +endfunc diff --git a/libavcodec/riscv/h264idct_rvv.S b/libavcodec/riscv/h264idct_rvv.S index b1e06d93f..2a40e87d6 100644 --- a/libavcodec/riscv/h264idct_rvv.S +++ b/libavcodec/riscv/h264idct_rvv.S @@ -542,7 +542,7 @@ func ff_h264_idct8_dc_add_\depth\()_rvv, zve64x endfunc .endr -const ff_h264_scan8 +const ff_h264_scan8, align=0 .byte 014, 015, 024, 025, 016, 017, 026, 027 .byte 034, 035, 044, 045, 036, 037, 046, 047 .byte 064, 065, 074, 075, 066, 067, 076, 077 @@ -629,6 +629,7 @@ endfunc .endm .macro idct4_add8 type, depth +#if (__riscv_xlen == 64) func ff_h264_idct4_add\type\()_\depth\()_rvv, zve32x .if \depth == 8 lpad 0 @@ -682,6 +683,7 @@ func ff_h264_idct4_add\type\()_\depth\()_rvv, zve32x vsetivli zero, 4, e8, m1, ta, ma j .Lidct4_add4_\depth\()_rvv endfunc +#endif .endm .irp depth, 8, 16 diff --git a/libavcodec/riscv/h264qpel_init.c b/libavcodec/riscv/h264qpel_init.c new file mode 100644 index 000000000..ad407ebff --- /dev/null +++ b/libavcodec/riscv/h264qpel_init.c @@ -0,0 +1,113 @@ +/* + * RISC-V optimised DSP functions + * Copyright (c) 2024 Niklas Haas + * + * 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 "config.h" +#include "libavutil/attributes.h" +#include "libavutil/riscv/cpu.h" +#include "libavcodec/h264qpel.h" + +#define DECL_QPEL_OPS(OP, SIZE, EXT) \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc00_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc10_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc20_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc30_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc01_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc11_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc21_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc31_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc02_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc12_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc22_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc32_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc03_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc13_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc23_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc33_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); + +DECL_QPEL_OPS(put, 16, rvv256) +DECL_QPEL_OPS(put, 8, rvv256) +// DECL_QPEL_OPS(put, 4, rvv256) + +DECL_QPEL_OPS(avg, 16, rvv256) +DECL_QPEL_OPS(avg, 8, rvv256) +// DECL_QPEL_OPS(avg, 4, rvv256) + +DECL_QPEL_OPS(put, 16, rvv) +DECL_QPEL_OPS(put, 8, rvv) +DECL_QPEL_OPS(put, 4, rvv) + +DECL_QPEL_OPS(avg, 16, rvv) +DECL_QPEL_OPS(avg, 8, rvv) +DECL_QPEL_OPS(avg, 4, rvv) + +#define SET_QPEL_FNS(OP, IDX, SIZE, EXT) \ +do { \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 0] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc00_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 1] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc10_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 2] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc20_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 3] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc30_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 4] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc01_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 5] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc11_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 6] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc21_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 7] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc31_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 8] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc02_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 9] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc12_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][10] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc22_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][11] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc32_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][12] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc03_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][13] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc13_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][14] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc23_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][15] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc33_ ## EXT; \ +} while (0) + +av_cold void ff_h264qpel_init_riscv(H264QpelContext *c, int bit_depth) +{ +#if HAVE_RVV + int flags = av_get_cpu_flags(); + if (flags & AV_CPU_FLAG_RVV_I32) { + const int vlen = 8 * ff_get_rv_vlenb(); + + switch (bit_depth) { + case 8: + if (vlen >= 256) { + SET_QPEL_FNS(put, 0, 16, rvv256); + SET_QPEL_FNS(put, 1, 8, rvv256); + SET_QPEL_FNS(put, 2, 4, rvv); + + SET_QPEL_FNS(avg, 0, 16, rvv256); + SET_QPEL_FNS(avg, 1, 8, rvv256); + SET_QPEL_FNS(avg, 2, 4, rvv); + } else if (vlen >= 128) { + SET_QPEL_FNS(put, 0, 16, rvv); + SET_QPEL_FNS(put, 1, 8, rvv); + SET_QPEL_FNS(put, 2, 4, rvv); + + SET_QPEL_FNS(avg, 0, 16, rvv); + SET_QPEL_FNS(avg, 1, 8, rvv); + SET_QPEL_FNS(avg, 2, 4, rvv); + } + break; + } + } +#endif +} diff --git a/libavcodec/riscv/h264qpel_rvv.S b/libavcodec/riscv/h264qpel_rvv.S new file mode 100644 index 000000000..df6796748 --- /dev/null +++ b/libavcodec/riscv/h264qpel_rvv.S @@ -0,0 +1,467 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 Niklas Haas + * + * 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. + * + * 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 OWNER 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 "libavutil/riscv/asm.S" + +.macro lx rd, addr +#if (__riscv_xlen == 32) + lw \rd, \addr +#elif (__riscv_xlen == 64) + ld \rd, \addr +#else + lq \rd, \addr +#endif +.endm + +.macro sx rd, addr +#if (__riscv_xlen == 32) + sw \rd, \addr +#elif (__riscv_xlen == 64) + sd \rd, \addr +#else + sq \rd, \addr +#endif +.endm + +#define XSZ (__riscv_xlen / 8) +#define STACK_ALIGN(x) (((x) + 15) & ~15) + + /* output is unclipped; clobbers v26-v31 plus t0 and t02 */ +.macro lowpass_h vdst, src + addi t4, \src, 3 + lbu t5, 2(\src) + vle8.v v31, (t4) + lbu t4, 1(\src) + vslide1up.vx v30, v31, t5 + lbu t5, 0(\src) + vslide1up.vx v29, v30, t4 + lbu t4, -1(\src) + vslide1up.vx v28, v29, t5 + lbu t5, -2(\src) + vslide1up.vx v27, v28, t4 + vslide1up.vx v26, v27, t5 + vwaddu.vv \vdst, v26, v31 + vwmaccu.vx \vdst, t6, v28 + vwmaccu.vx \vdst, t6, v29 + vwmaccsu.vx \vdst, a7, v27 + vwmaccsu.vx \vdst, a7, v30 +.endm + + /* output is unclipped */ +.macro lowpass_v vdst, vsrc0, vsrc1, vsrc2, vsrc3, vsrc4, vsrc5, signed=0 + .if \signed + vwadd.vv \vdst, \vsrc0, \vsrc5 + vwmacc.vx \vdst, t6, \vsrc2 + vwmacc.vx \vdst, t6, \vsrc3 + vwmacc.vx \vdst, a7, \vsrc1 + vwmacc.vx \vdst, a7, \vsrc4 + .else + vwaddu.vv \vdst, \vsrc0, \vsrc5 + vwmaccu.vx \vdst, t6, \vsrc2 + vwmaccu.vx \vdst, t6, \vsrc3 + vwmaccsu.vx \vdst, a7, \vsrc1 + vwmaccsu.vx \vdst, a7, \vsrc4 + .endif +.endm + +.macro qpel_mc00 op, dst, src, stride, size +func ff_\op\()_h264_qpel_pixels, zve32x +1: add t1, a2, a1 + add t2, a2, t1 + add t3, a2, t2 + vle8.v v0, (a1) + vle8.v v1, (t1) + vle8.v v2, (t2) + vle8.v v3, (t3) + addi a4, a4, -4 + add a1, a2, t3 + add t1, a2, a0 + add t2, a2, t1 + add t3, a2, t2 + .ifc \op, avg + vle8.v v4, (a0) + vle8.v v5, (t1) + vle8.v v6, (t2) + vle8.v v7, (t3) + vaaddu.vv v0, v0, v4 + vaaddu.vv v1, v1, v5 + vaaddu.vv v2, v2, v6 + vaaddu.vv v3, v3, v7 + .endif + vse8.v v0, (a0) + vse8.v v1, (t1) + vse8.v v2, (t2) + vse8.v v3, (t3) + add a0, a2, t3 + bnez a4, 1b + jr t0 +endfunc +.endm + + qpel_mc00 put, a0, a1, a2, a4 + qpel_mc00 avg, a0, a1, a2, a4 + +.macro qpel_lowpass op, ext, lmul, lmul2 +func ff_\op\()_h264_qpel_h_lowpass_\lmul\ext, zve32x +1: add t1, a3, a1 + add t2, a3, t1 + add t3, a3, t2 + lowpass_h v0, a1 + lowpass_h v2, t1 + lowpass_h v4, t2 + lowpass_h v6, t3 + add a1, a3, t3 + addi a4, a4, -4 + vsetvli zero, zero, e16, \lmul2, ta, ma + vmax.vx v0, v0, zero + vmax.vx v2, v2, zero + vmax.vx v4, v4, zero + vmax.vx v6, v6, zero + vsetvli zero, zero, e8, \lmul, ta, ma + vnclipu.wi v0, v0, 5 + vnclipu.wi v2, v2, 5 + vnclipu.wi v4, v4, 5 + vnclipu.wi v6, v6, 5 + .ifc \ext, _l2 + add t1, a6, a5 + add t2, a6, t1 + add t3, a6, t2 + vle8.v v8, (a5) + vle8.v v10, (t1) + vle8.v v12, (t2) + vle8.v v14, (t3) + add a5, a2, t3 + vaaddu.vv v0, v0, v8 + vaaddu.vv v2, v2, v10 + vaaddu.vv v4, v4, v12 + vaaddu.vv v6, v6, v14 + .endif + add t1, a2, a0 + add t2, a2, t1 + add t3, a2, t2 + .ifc \op, avg + vle8.v v1, (a0) + vle8.v v3, (t1) + vle8.v v5, (t2) + vle8.v v7, (t3) + vaaddu.vv v0, v0, v1 + vaaddu.vv v2, v2, v3 + vaaddu.vv v4, v4, v5 + vaaddu.vv v6, v6, v7 + .endif + vse8.v v0, (a0) + vse8.v v2, (t1) + vse8.v v4, (t2) + vse8.v v6, (t3) + add a0, a2, t3 + bnez a4, 1b + jr t0 +endfunc + +func ff_\op\()_h264_qpel_v_lowpass_\lmul\ext, zve32x + sub t1, a1, a3 + sub t2, t1, a3 + vle8.v v2, (a1) + vle8.v v1, (t1) + vle8.v v0, (t2) + add t1, a1, a3 + add t2, t1, a3 + add a1, t2, a3 + vle8.v v3, (t1) + vle8.v v4, (t2) +1: add t1, a3, a1 + add t2, a3, t1 + add t3, a3, t2 + vle8.v v5, (a1) + vle8.v v6, (t1) + vle8.v v7, (t2) + vle8.v v8, (t3) + add a1, a3, t3 + lowpass_v v24, v0, v1, v2, v3, v4, v5 + lowpass_v v26, v1, v2, v3, v4, v5, v6 + lowpass_v v28, v2, v3, v4, v5, v6, v7 + lowpass_v v30, v3, v4, v5, v6, v7, v8 + addi a4, a4, -4 + vsetvli zero, zero, e16, \lmul2, ta, ma + vmax.vx v24, v24, zero + vmax.vx v26, v26, zero + vmax.vx v28, v28, zero + vmax.vx v30, v30, zero + vsetvli zero, zero, e8, \lmul, ta, ma + vnclipu.wi v24, v24, 5 + vnclipu.wi v26, v26, 5 + vnclipu.wi v28, v28, 5 + vnclipu.wi v30, v30, 5 + .ifc \ext, _l2 + add t1, a6, a5 + add t2, a6, t1 + add t3, a6, t2 + vle8.v v9, (a5) + vle8.v v10, (t1) + vle8.v v11, (t2) + vle8.v v12, (t3) + add a5, a6, t3 + vaaddu.vv v24, v24, v9 + vaaddu.vv v26, v26, v10 + vaaddu.vv v28, v28, v11 + vaaddu.vv v30, v30, v12 + .endif + add t1, a2, a0 + add t2, a2, t1 + add t3, a2, t2 + .ifc \op, avg + vle8.v v9, (a0) + vle8.v v10, (t1) + vle8.v v11, (t2) + vle8.v v12, (t3) + vaaddu.vv v24, v24, v9 + vaaddu.vv v26, v26, v10 + vaaddu.vv v28, v28, v11 + vaaddu.vv v30, v30, v12 + .endif + vse8.v v24, (a0) + vse8.v v26, (t1) + vse8.v v28, (t2) + vse8.v v30, (t3) + add a0, a2, t3 + vmv.v.v v0, v4 + vmv.v.v v1, v5 + vmv.v.v v2, v6 + vmv.v.v v3, v7 + vmv.v.v v4, v8 + bnez a4, 1b + jr t0 +endfunc + +func ff_\op\()_h264_qpel_hv_lowpass_\lmul\ext, zve32x + sub t1, a1, a3 + sub t2, t1, a3 + lowpass_h v4, a1 + lowpass_h v2, t1 + lowpass_h v0, t2 + add t1, a1, a3 + add t2, t1, a3 + add a1, t2, a3 + lowpass_h v6, t1 + lowpass_h v8, t2 +1: add t1, a3, a1 + add t2, a3, t1 + add t3, a3, t2 + lowpass_h v10, a1 + lowpass_h v12, t1 + lowpass_h v14, t2 + lowpass_h v16, t3 + vsetvli zero, zero, e16, \lmul2, ta, ma + addi a4, a4, -4 + lowpass_v v20, v0, v2, v4, v6, v8, v10, signed=1 + lowpass_v v24, v2, v4, v6, v8, v10, v12, signed=1 + lowpass_v v28, v4, v6, v8, v10, v12, v14, signed=1 + vnclip.wi v0, v20, 10 + lowpass_v v20, v6, v8, v10, v12, v14, v16, signed=1 + vnclip.wi v2, v24, 10 + vnclip.wi v4, v28, 10 + vnclip.wi v6, v20, 10 + vmax.vx v18, v0, zero + vmax.vx v20, v2, zero + vmax.vx v22, v4, zero + vmax.vx v24, v6, zero + vmv.v.v v0, v8 + vmv.v.v v2, v10 + vmv.v.v v4, v12 + vmv.v.v v6, v14 + vmv.v.v v8, v16 + add a1, a3, t3 + vsetvli zero, zero, e8, \lmul, ta, ma + vnclipu.wi v18, v18, 0 + vnclipu.wi v20, v20, 0 + vnclipu.wi v22, v22, 0 + vnclipu.wi v24, v24, 0 + .ifc \ext, _l2 + add t1, a6, a5 + add t2, a6, t1 + add t3, a6, t2 + vle8.v v26, (a5) + vle8.v v27, (t1) + vle8.v v28, (t2) + vle8.v v29, (t3) + add a5, a6, t3 + vaaddu.vv v18, v18, v26 + vaaddu.vv v20, v20, v27 + vaaddu.vv v22, v22, v28 + vaaddu.vv v24, v24, v29 + .endif + add t1, a2, a0 + add t2, a2, t1 + add t3, a2, t2 + .ifc \op, avg + vle8.v v26, (a0) + vle8.v v27, (t1) + vle8.v v28, (t2) + vle8.v v29, (t3) + vaaddu.vv v18, v18, v26 + vaaddu.vv v20, v20, v27 + vaaddu.vv v22, v22, v28 + vaaddu.vv v24, v24, v29 + .endif + vse8.v v18, (a0) + vse8.v v20, (t1) + vse8.v v22, (t2) + vse8.v v24, (t3) + add a0, a2, t3 + bnez a4, 1b + jr t0 +endfunc +.endm + +/* Note: We could possibly specialize for the width 8 / width 4 cases by + loading 32 bit integers, but this makes the convolutions more complicated + to implement, so it's not necessarily any faster. */ + +.macro h264_qpel lmul, lmul2 + qpel_lowpass put, , \lmul, \lmul2 + qpel_lowpass put, _l2, \lmul, \lmul2 + qpel_lowpass avg, , \lmul, \lmul2 + qpel_lowpass avg, _l2, \lmul, \lmul2 +.endm + + h264_qpel m1, m2 + h264_qpel mf2, m1 + h264_qpel mf4, mf2 + h264_qpel mf8, mf4 + +.macro h264_qpel_1pass op, case, lmul, size, ext=rvv, dir, offset +func ff_\op\()_h264_qpel\size\()_\case\()_\ext, zve32x + lpad 0 + vsetivli zero, \size, e8, \lmul, ta, ma + csrwi vxrm, 0 + li a4, \size + li t6, 20 + li a7, -5 + mv a3, a2 + mv t0, ra +.ifnb \offset + .ifc \dir, v + add a5, a1, \offset + .else + addi a5, a1, \offset + .endif + mv a6, a3 + j ff_\op\()_h264_qpel_\dir\()_lowpass_\lmul\()_l2 +.else + j ff_\op\()_h264_qpel_\dir\()_lowpass_\lmul\() +.endif +endfunc +.endm + +.macro h264_qpel_2pass op, case, lmul, size, ext=rvv, dir1, dir2, off1=0, off2 +func ff_\op\()_h264_qpel\size\()_\case\()_\ext, zve32x + lpad 0 + vsetivli zero, \size, e8, \lmul, ta, ma + csrwi vxrm, 0 + addi sp, sp, -STACK_ALIGN(2 * XSZ + \size * \size) + li a4, \size + li t6, 20 + li a7, -5 + sx a0, (sp) + sx a1, XSZ(sp) + .ifc \off1, a2 + add a1, a1, \off1 + .elseif \off1 + addi a1, a1, \off1 + .endif + mv a3, a2 + .ifc \op, avg + // Use temporary array on stack for the first pass + addi a0, sp, 2 * XSZ + li a2, \size + .endif + jal t0, ff_put_h264_qpel_\dir1\()_lowpass_\lmul + lx a0, (sp) + lx a1, XSZ(sp) + .ifc \op, put + // Directly reuse the first pass output buffer + mv a5, a0 + mv a6, a2 + .else + addi a5, sp, 2 * XSZ + li a6, \size + mv a2, a3 + .endif + .ifnb \off2 + addi a1, a1, \off2 + .endif + li a4, \size + mv t0, ra + addi sp, sp, STACK_ALIGN(2 * XSZ + \size * \size) + j ff_\op\()_h264_qpel_\dir2\()_lowpass_\lmul\()_l2 +endfunc +.endm + +.macro ff_h264_qpel_fns op, lmul, size, ext=rvv +func ff_\op\()_h264_qpel\size\()_mc00_\ext, zve32x + lpad 0 + vsetivli zero, \size, e8, \lmul, ta, ma + csrwi vxrm, 0 + li a4, \size + mv t0, ra + j ff_\op\()_h264_qpel_pixels +endfunc + + h264_qpel_1pass \op, mc20, \lmul, \size, \ext, h + h264_qpel_1pass \op, mc02, \lmul, \size, \ext, v + h264_qpel_1pass \op, mc10, \lmul, \size, \ext, h, 0 + h264_qpel_1pass \op, mc30, \lmul, \size, \ext, h, 1 + h264_qpel_1pass \op, mc01, \lmul, \size, \ext, v, zero + h264_qpel_1pass \op, mc03, \lmul, \size, \ext, v, a2 + h264_qpel_1pass \op, mc22, \lmul, \size, \ext, hv + + h264_qpel_2pass \op, mc11, \lmul, \size, \ext, h, v + h264_qpel_2pass \op, mc21, \lmul, \size, \ext, h, hv + h264_qpel_2pass \op, mc12, \lmul, \size, \ext, v, hv + h264_qpel_2pass \op, mc31, \lmul, \size, \ext, h, v, off2=1 + h264_qpel_2pass \op, mc13, \lmul, \size, \ext, h, v, a2 + h264_qpel_2pass \op, mc33, \lmul, \size, \ext, h, v, a2, 1 + h264_qpel_2pass \op, mc23, \lmul, \size, \ext, h, hv, a2 + h264_qpel_2pass \op, mc32, \lmul, \size, \ext, v, hv, 1 +.endm + + ff_h264_qpel_fns put, mf2, 16, rvv256 + ff_h264_qpel_fns put, mf4, 8, rvv256 + /* ff_h264_qpel_fns put, mf8, 4, rvv256 */ + + ff_h264_qpel_fns avg, mf2, 16, rvv256 + ff_h264_qpel_fns avg, mf4, 8, rvv256 + /* ff_h264_qpel_fns avg, mf8, 4, rvv256 */ + + ff_h264_qpel_fns put, m1, 16, rvv + ff_h264_qpel_fns put, mf2, 8, rvv + ff_h264_qpel_fns put, mf4, 4, rvv + + ff_h264_qpel_fns avg, m1, 16, rvv + ff_h264_qpel_fns avg, mf2, 8, rvv + ff_h264_qpel_fns avg, mf4, 4, rvv diff --git a/libavcodec/riscv/h26x/asm.S b/libavcodec/riscv/h26x/asm.S new file mode 100644 index 000000000..38c68e36b --- /dev/null +++ b/libavcodec/riscv/h26x/asm.S @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * 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/riscv/asm.S" + +.macro vsetvlstatic w, vlen, en, mn1, mn2, mn3, mn4, mn5, mn6, vta=ta + .if \w == 2 && \vlen == 128 + vsetivli zero, \w, \en, \mn1, \vta, ma + .elseif \w <= 4 && \vlen == 128 + vsetivli zero, \w, \en, \mn2, \vta, ma + .elseif \w <= 8 && \vlen == 128 + vsetivli zero, \w, \en, \mn3, \vta, ma + .elseif \w <= 16 && \vlen == 128 + vsetivli zero, \w, \en, \mn4, \vta, ma + .elseif \w <= 32 && \vlen == 128 + li t0, \w + vsetvli zero, t0, \en, \mn5, \vta, ma + .elseif \w <= 4 && \vlen == 256 + vsetivli zero, \w, \en, \mn1, \vta, ma + .elseif \w <= 8 && \vlen == 256 + vsetivli zero, \w, \en, \mn2, \vta, ma + .elseif \w <= 16 && \vlen == 256 + vsetivli zero, \w, \en, \mn3, \vta, ma + .elseif \w <= 32 && \vlen == 256 + li t0, \w + vsetvli zero, t0, \en, \mn4, \vta, ma + .elseif \w <= 64 && \vlen == 256 + li t0, \w + vsetvli zero, t0, \en, \mn5, \vta, ma + .else + li t0, \w + vsetvli zero, t0, \en, \mn6, \vta, ma + .endif +.endm + +.macro vsetvlstatic8 w, vlen, vta + vsetvlstatic \w, \vlen, e8, mf8, mf4, mf2, m1, m2, m4, \vta +.endm + +.macro vsetvlstatic16 w, vlen, vta + vsetvlstatic \w, \vlen, e16, mf4, mf2, m1, m2, m4, m8, \vta +.endm + +.macro vsetvlstatic32 w, vlen, vta + vsetvlstatic \w, \vlen, e32, mf2, m1, m2, m4, m8, m8, \vta +.endm + +.macro POW2_JMP_TABLE id, vlen +const jmp_table_\id\vlen + .4byte \id\()2\vlen\()f - jmp_table_\id\vlen + .4byte \id\()4\vlen\()f - jmp_table_\id\vlen + .4byte \id\()8\vlen\()f - jmp_table_\id\vlen + .4byte \id\()16\vlen\()f - jmp_table_\id\vlen + .4byte \id\()32\vlen\()f - jmp_table_\id\vlen + .4byte \id\()64\vlen\()f - jmp_table_\id\vlen + .4byte \id\()128\vlen\()f - jmp_table_\id\vlen +endconst +.endm + +.macro POW2_J vlen, id, w + clz t1, \w + neg t1, t1 + lla t5, jmp_table_\id\vlen + sh2add t1, t1, t5 + lw t1, ((__riscv_xlen-2)<<2)(t1) + add t1, t1, t5 + jr t1 +.endm + +.macro put_pixels w, vlen, id, MAX_PB_SIZE +\id\w\vlen: + vsetvlstatic8 \w, \vlen + li t2, 1<<6 +.if \w == 128 && \vlen == 128 +1: + addi t0, a1, 64 + addi t1, a0, 64*2 + vle8.v v0, (a1) + vle8.v v16, (t0) + vwmulu.vx v8, v0, t2 + vwmulu.vx v24, v16, t2 + vse16.v v8, (a0) + vse16.v v24, (t1) + add a1, a1, a2 + addi a3, a3, -1 + addi a0, a0, 128*2 + bnez a3, 1b +.else +1: + vle8.v v0, (a1) + vwmulu.vx v8, v0, t2 + vse16.v v8, (a0) + add a1, a1, a2 + addi a3, a3, -1 + addi a0, a0, \MAX_PB_SIZE<<1 + bnez a3, 1b +.endif + ret +.endm + +.macro func_put_pixels vlen, MAX_PB_SIZE, name +func ff_\name\()_put_pixels_8_rvv_\vlen\(), zve32x, zbb, zba + lpad 0 + POW2_JMP_TABLE 3, \vlen + POW2_J \vlen, 3, a6 + .irp w,2,4,8,16,32,64,128 + put_pixels \w, \vlen, 3, \MAX_PB_SIZE + .endr +endfunc +.endm diff --git a/libavcodec/riscv/h26x/h2656_inter_rvv.S b/libavcodec/riscv/h26x/h2656_inter_rvv.S new file mode 100644 index 000000000..b7ee88fb2 --- /dev/null +++ b/libavcodec/riscv/h26x/h2656_inter_rvv.S @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * 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 "libavcodec/riscv/h26x/asm.S" + +func_put_pixels 256, 64, h2656 +func_put_pixels 128, 64, h2656 diff --git a/libavcodec/riscv/h26x/h2656dsp.h b/libavcodec/riscv/h26x/h2656dsp.h new file mode 100644 index 000000000..6d2ac5555 --- /dev/null +++ b/libavcodec/riscv/h26x/h2656dsp.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * 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_RISCV_H26X_H2656DSP_H +#define AVCODEC_RISCV_H26X_H2656DSP_H + +void ff_h2656_put_pixels_8_rvv_256(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_h2656_put_pixels_8_rvv_128(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, int height, intptr_t mx, intptr_t my, int width); + +#endif diff --git a/libavcodec/riscv/hevcdsp_init.c b/libavcodec/riscv/hevcdsp_init.c new file mode 100644 index 000000000..70bc8ebea --- /dev/null +++ b/libavcodec/riscv/hevcdsp_init.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * 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 "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/riscv/cpu.h" + +#include "libavcodec/hevc/dsp.h" +#include "libavcodec/riscv/h26x/h2656dsp.h" + +#define RVV_FNASSIGN(member, v, h, fn, ext) \ + member[1][v][h] = ff_h2656_put_pixels_##8_##ext; \ + member[3][v][h] = ff_h2656_put_pixels_##8_##ext; \ + member[5][v][h] = ff_h2656_put_pixels_##8_##ext; \ + member[7][v][h] = ff_h2656_put_pixels_##8_##ext; \ + member[9][v][h] = ff_h2656_put_pixels_##8_##ext; + +void ff_hevc_dsp_init_riscv(HEVCDSPContext *c, const int bit_depth) +{ +#if HAVE_RVV + const int flags = av_get_cpu_flags(); + int vlenb; + + if (!(flags & AV_CPU_FLAG_RVV_I32) || !(flags & AV_CPU_FLAG_RVB)) + return; + + vlenb = ff_get_rv_vlenb(); + if (vlenb >= 32) { + switch (bit_depth) { + case 8: + RVV_FNASSIGN(c->put_hevc_qpel, 0, 0, pel_pixels, rvv_256); + RVV_FNASSIGN(c->put_hevc_epel, 0, 0, pel_pixels, rvv_256); + break; + default: + break; + } + } else if (vlenb >= 16) { + switch (bit_depth) { + case 8: + RVV_FNASSIGN(c->put_hevc_qpel, 0, 0, pel_pixels, rvv_128); + RVV_FNASSIGN(c->put_hevc_epel, 0, 0, pel_pixels, rvv_128); + break; + default: + break; + } + } +#endif +} diff --git a/libavcodec/riscv/llvidencdsp_init.c b/libavcodec/riscv/llvidencdsp_init.c index e35406dc4..017aa778d 100644 --- a/libavcodec/riscv/llvidencdsp_init.c +++ b/libavcodec/riscv/llvidencdsp_init.c @@ -24,16 +24,35 @@ #include "libavutil/cpu.h" #include "libavcodec/lossless_videoencdsp.h" +#include "libavcodec/mathops.h" +#include + +void ff_llvidenc_sub_median_pred_rvb(uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, intptr_t w, + int *left, int *left_top); void ff_llvidenc_diff_bytes_rvv(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, intptr_t w); +void ff_llvidenc_sub_median_pred_rvv(uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, intptr_t width, + int *left, int *left_top); +void ff_llvidenc_sub_left_predict_rvv(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride, ptrdiff_t width, + int height); av_cold void ff_llvidencdsp_init_riscv(LLVidEncDSPContext *c) { -#if HAVE_RVV +#if HAVE_RV int flags = av_get_cpu_flags(); + if (flags & AV_CPU_FLAG_RVB_BASIC) + c->sub_median_pred = ff_llvidenc_sub_median_pred_rvb; + +#if HAVE_RVV if (flags & AV_CPU_FLAG_RVV_I32) { c->diff_bytes = ff_llvidenc_diff_bytes_rvv; + c->sub_median_pred = ff_llvidenc_sub_median_pred_rvv; + c->sub_left_predict = ff_llvidenc_sub_left_predict_rvv; } #endif +#endif } diff --git a/libavcodec/riscv/llvidencdsp_rvb.S b/libavcodec/riscv/llvidencdsp_rvb.S new file mode 100644 index 000000000..d34aef394 --- /dev/null +++ b/libavcodec/riscv/llvidencdsp_rvb.S @@ -0,0 +1,49 @@ +/* + * Copyright © 2025 Rémi Denis-Courmont. + * + * 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/riscv/asm.S" + +func ff_llvidenc_sub_median_pred_rvb, zbb + lpad 0 + lbu t4, (a4) # l + lbu t5, (a5) # lt + add a3, a0, a3 +1: + lbu t1, (a1) # src1 + addi a1, a1, 1 + add t6, t4, t1 + max t3, t4, t1 + sub t6, t6, t5 # l + src1 - lt + min t0, t4, t1 + andi t6, t6, 0xff + mv t5, t1 + min t3, t3, t6 + lbu t4, (a2) # src2 + addi a0, a0, 1 + max t6, t0, t3 # mid_pred(...) + sub t0, t4, t6 + addi a2, a2, 1 + sb t0, -1(a0) + bne a0, a3, 1b + + sw t4, (a4) + sw t5, (a5) + ret +endfunc diff --git a/libavcodec/riscv/llvidencdsp_rvv.S b/libavcodec/riscv/llvidencdsp_rvv.S index 44bf3ac7e..35ac976dd 100644 --- a/libavcodec/riscv/llvidencdsp_rvv.S +++ b/libavcodec/riscv/llvidencdsp_rvv.S @@ -36,3 +36,59 @@ func ff_llvidenc_diff_bytes_rvv, zve32x ret endfunc + +func ff_llvidenc_sub_median_pred_rvv, zve32x + lpad 0 + lw t4, (a4) + lw t5, (a5) +1: + vsetvli t3, a3, e8, m4, ta, ma + vle8.v v16, (a1) # src1 + sub a3, a3, t3 + vle8.v v24, (a2) # src2 + add a1, t3, a1 + vslide1up.vx v20, v16, t5 # lt + add a2, t3, a2 + vslide1up.vx v28, v24, t4 # l + lbu t5, -1(a1) + vsub.vv v20, v16, v20 + lbu t4, -1(a2) + vmaxu.vv v8, v28, v16 + vadd.vv v20, v28, v20 # l + src1 - lt + vminu.vv v12, v28, v16 + vminu.vv v8, v8, v20 + vmaxu.vv v8, v12, v8 # mid_pred(...) + vsub.vv v8, v24, v8 + vse8.v v8, (a0) + add a0, t3, a0 + bnez a3, 1b + + sw t4, (a4) + sw t5, (a5) + ret +endfunc + +func ff_llvidenc_sub_left_predict_rvv, zve32x + lpad 0 + li a5, -0x80 + sub a2, a2, a3 +1: + mv t3, a3 + addi a4, a4, -1 +2: + vsetvli t0, t3, e8, m8, ta, ma + vle8.v v16, (a1) + sub t3, t3, t0 + vslide1up.vx v24, v16, a5 + add a1, a1, t0 + vsub.vv v8, v16, v24 + lb a5, -1(a1) + vse8.v v8, (a0) + add a0, a0, t0 + bnez t3, 2b + + add a1, a1, a2 + bnez a4, 1b + + ret +endfunc diff --git a/libavcodec/riscv/mathops.h b/libavcodec/riscv/mathops.h new file mode 100644 index 000000000..c2258f49d --- /dev/null +++ b/libavcodec/riscv/mathops.h @@ -0,0 +1,54 @@ +/* + * Copyright © 2025 Rémi Denis-Courmont. + * + * 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_RISCV_MATHOPS_H +#define AVCODEC_RISCV_MATHOPS_H + +#include "config.h" +#include +#include "libavutil/attributes_internal.h" +#include "libavutil/riscv/cpu.h" + +#if HAVE_RV && !defined(__riscv_zbb) +static inline int median3_c(int a, int b, int c); + +static inline av_const int median3_rv(int a, int b, int c) +{ + if (__builtin_expect(ff_rv_zbb_support(), true)) { + int min2, max2; + + __asm__ ( + ".option push\n" + ".option arch, +zbb\n" + "max %1, %2, %3\n" + "min %0, %2, %3\n" + "min %1, %4, %1\n" + "max %0, %0, %1\n" + ".option pop\n" + : "=&r" (min2), "=&r" (max2) : "r" (a), "r" (b), "r" (c)); + + return min2; + } + return median3_c(a, b, c); +} +#define mid_pred median3_rv +#endif + +#endif /* HAVE_RVV */ diff --git a/libavcodec/riscv/me_cmp_init.c b/libavcodec/riscv/me_cmp_init.c index f246e55cb..dac136633 100644 --- a/libavcodec/riscv/me_cmp_init.c +++ b/libavcodec/riscv/me_cmp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * @@ -24,55 +24,55 @@ #include "libavutil/cpu.h" #include "libavutil/riscv/cpu.h" #include "libavcodec/me_cmp.h" -#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideoenc.h" -int ff_pix_abs16_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_x2_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_x2_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_x2_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_x2_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_y2_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_y2_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_y2_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_y2_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sse16_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sse16_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sse8_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sse8_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sse4_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sse4_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_vsse16_rvv(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int ff_vsse8_rvv(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int ff_vsse_intra16_rvv(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); -int ff_vsse_intra8_rvv(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); -int ff_vsad16_rvv(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int ff_vsad8_rvv(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int ff_vsad_intra16_rvv(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); -int ff_vsad_intra8_rvv(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); +int ff_vsse16_rvv(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); +int ff_vsse8_rvv(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); +int ff_vsse_intra16_rvv(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); +int ff_vsse_intra8_rvv(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); +int ff_vsad16_rvv(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); +int ff_vsad8_rvv(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); +int ff_vsad_intra16_rvv(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); +int ff_vsad_intra8_rvv(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); int ff_nsse16_rvv(int multiplier, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); int ff_nsse8_rvv(int multiplier, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -static int nsse16_rvv_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +static int nsse16_rvv_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { if (c) - return ff_nsse16_rvv(c->avctx->nsse_weight, s1, s2, stride, h); + return ff_nsse16_rvv(c->c.avctx->nsse_weight, s1, s2, stride, h); else return ff_nsse16_rvv(8, s1, s2, stride, h); } -static int nsse8_rvv_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +static int nsse8_rvv_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { if (c) - return ff_nsse8_rvv(c->avctx->nsse_weight, s1, s2, stride, h); + return ff_nsse8_rvv(c->c.avctx->nsse_weight, s1, s2, stride, h); else return ff_nsse8_rvv(8, s1, s2, stride, h); } diff --git a/libavcodec/riscv/me_cmp_rvv.S b/libavcodec/riscv/me_cmp_rvv.S index 8989c91dd..0b7a49bb0 100644 --- a/libavcodec/riscv/me_cmp_rvv.S +++ b/libavcodec/riscv/me_cmp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/mpegvideo_init.c b/libavcodec/riscv/mpegvideo_init.c new file mode 100644 index 000000000..418b91f43 --- /dev/null +++ b/libavcodec/riscv/mpegvideo_init.c @@ -0,0 +1,62 @@ +/* + * Copyright © 2022 Rémi Denis-Courmont. + * + * 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 "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideo_unquantize.h" + +void ff_h263_dct_unquantize_intra_rvv(const MPVContext *s, int16_t *block, + ptrdiff_t len, int qscale, int aic); +void ff_h263_dct_unquantize_inter_rvv(const MPVContext *s, int16_t *block, + ptrdiff_t len, int qscale); + +static void dct_unquantize_h263_intra_rvv(const MPVContext *s, + int16_t *block, int n, int qscale) +{ + if (!s->h263_aic) + block[0] *= (n < 4) ? s->y_dc_scale : s->c_dc_scale; + + n = s->ac_pred ? 63 + : s->intra_scantable.raster_end[s->block_last_index[n]]; + ff_h263_dct_unquantize_intra_rvv(s, block, n, qscale, s->h263_aic); +} + +static void dct_unquantize_h263_inter_rvv(const MPVContext *s, + int16_t *block, int n, int qscale) +{ + n = s->inter_scantable.raster_end[s->block_last_index[n]]; + ff_h263_dct_unquantize_inter_rvv(s, block, n, qscale); +} + +av_cold +void ff_mpv_unquantize_init_riscv(MPVUnquantDSPContext *c, int bitexact) +{ +#if HAVE_RVV + int flags = av_get_cpu_flags(); + + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { + c->dct_unquantize_h263_intra = dct_unquantize_h263_intra_rvv; + c->dct_unquantize_h263_inter = dct_unquantize_h263_inter_rvv; + } +#endif +} diff --git a/libavcodec/riscv/mpegvideo_rvv.S b/libavcodec/riscv/mpegvideo_rvv.S new file mode 100644 index 000000000..5312413db --- /dev/null +++ b/libavcodec/riscv/mpegvideo_rvv.S @@ -0,0 +1,53 @@ +/* + * Copyright © 2024 Rémi Denis-Courmont. + * + * 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/riscv/asm.S" + +func ff_h263_dct_unquantize_intra_rvv + lpad 0 + addi a1, a1, 2 + beqz a4, 1f + slli a3, a3, 1 + mv a4, zero + j 2f +endfunc + +func ff_h263_dct_unquantize_inter_rvv, zve32x, zba + lpad 0 + addi a2, a2, 1 +1: + addi a4, a3, -1 + slli a3, a3, 1 + ori a4, a4, 1 +2: + vsetvli t0, a2, e16, m8, ta, mu + vle16.v v8, (a1) + sub a2, a2, t0 + vmv.v.x v16, a4 + vmslt.vi v0, v8, 0 + vneg.v v16, v16, v0.t + vmsne.vi v0, v8, 0 + vmadd.vx v8, a3, v16, v0.t + vse16.v v8, (a1) + sh1add a1, t0, a1 + bnez a2, 2b + + ret +endfunc diff --git a/libavcodec/riscv/pixblockdsp_init.c b/libavcodec/riscv/pixblockdsp_init.c index 273577610..804165695 100644 --- a/libavcodec/riscv/pixblockdsp_init.c +++ b/libavcodec/riscv/pixblockdsp_init.c @@ -24,30 +24,29 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/riscv/cpu.h" -#include "libavcodec/avcodec.h" #include "libavcodec/pixblockdsp.h" -void ff_get_pixels_8_rvi(int16_t *block, const uint8_t *pixels, +void ff_get_pixels_8_rvi(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t stride); -void ff_get_pixels_16_rvi(int16_t *block, const uint8_t *pixels, +void ff_get_pixels_16_rvi(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t stride); -void ff_get_pixels_8_rvv(int16_t *block, const uint8_t *pixels, +void ff_get_pixels_8_rvv(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t stride); -void ff_get_pixels_unaligned_8_rvv(int16_t *block, const uint8_t *pixels, +void ff_get_pixels_unaligned_8_rvv(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t stride); -void ff_diff_pixels_rvv(int16_t *block, const uint8_t *s1, +void ff_diff_pixels_rvv(int16_t *restrict block, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride); -void ff_diff_pixels_unaligned_rvv(int16_t *block, const uint8_t *s1, +void ff_diff_pixels_unaligned_rvv(int16_t *restrict block, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride); av_cold void ff_pixblockdsp_init_riscv(PixblockDSPContext *c, - AVCodecContext *avctx, unsigned high_bit_depth) { #if HAVE_RV int cpu_flags = av_get_cpu_flags(); +#if __riscv_xlen >= 64 if (cpu_flags & AV_CPU_FLAG_RVI) { if (high_bit_depth) c->get_pixels = ff_get_pixels_16_rvi; @@ -61,20 +60,23 @@ av_cold void ff_pixblockdsp_init_riscv(PixblockDSPContext *c, else c->get_pixels_unaligned = ff_get_pixels_8_rvi; } - +#endif #if HAVE_RVV if ((cpu_flags & AV_CPU_FLAG_RVV_I32) && ff_rv_vlen_least(128)) { c->diff_pixels = ff_diff_pixels_unaligned_rvv; c->diff_pixels_unaligned = ff_diff_pixels_unaligned_rvv; - } - if ((cpu_flags & AV_CPU_FLAG_RVV_I64) && ff_get_rv_vlenb() >= 16) { if (!high_bit_depth) { - c->get_pixels = ff_get_pixels_8_rvv; + c->get_pixels = ff_get_pixels_unaligned_8_rvv; c->get_pixels_unaligned = ff_get_pixels_unaligned_8_rvv; } - c->diff_pixels = ff_diff_pixels_rvv; + if (cpu_flags & AV_CPU_FLAG_RVV_I64) { + if (!high_bit_depth) + c->get_pixels = ff_get_pixels_8_rvv; + + c->diff_pixels = ff_diff_pixels_rvv; + } } #endif #endif diff --git a/libavcodec/riscv/pixblockdsp_rvi.S b/libavcodec/riscv/pixblockdsp_rvi.S index ed1af7025..c47204856 100644 --- a/libavcodec/riscv/pixblockdsp_rvi.S +++ b/libavcodec/riscv/pixblockdsp_rvi.S @@ -20,6 +20,7 @@ #include "libavutil/riscv/asm.S" +#if __riscv_xlen >= 64 func ff_get_pixels_8_rvi lpad 0 .irp row, 0, 1, 2, 3, 4, 5, 6, 7 @@ -58,3 +59,4 @@ func ff_get_pixels_16_rvi .endr ret endfunc +#endif diff --git a/libavcodec/riscv/pixblockdsp_rvv.S b/libavcodec/riscv/pixblockdsp_rvv.S index 85233470c..78dcddf33 100644 --- a/libavcodec/riscv/pixblockdsp_rvv.S +++ b/libavcodec/riscv/pixblockdsp_rvv.S @@ -24,7 +24,6 @@ func ff_get_pixels_8_rvv, zve64x lpad 0 vsetivli zero, 8, e8, mf2, ta, ma li t0, 8 * 8 -1: vlse64.v v16, (a1), a2 vsetvli zero, t0, e8, m4, ta, ma vwcvtu.x.x.v v8, v16 @@ -32,24 +31,24 @@ func ff_get_pixels_8_rvv, zve64x ret endfunc -func ff_get_pixels_unaligned_8_rvv, zve64x +func ff_get_pixels_unaligned_8_rvv, zve32x lpad 0 - andi t1, a1, 7 - vsetivli zero, 8, e64, m4, ta, ma - li t0, 8 * 8 - beqz t1, 1b - andi a1, a1, -8 - slli t2, t1, 3 - addi t1, a1, 8 - sub t3, t0, t2 - vlse64.v v16, (a1), a2 - vlse64.v v24, (t1), a2 - vsrl.vx v16, v16, t2 - vsll.vx v24, v24, t3 - vor.vv v16, v16, v24 - vsetvli zero, t0, e8, m4, ta, ma + li t2, 8 + vsetivli zero, 8, e8, mf2, ta, ma +1: + add t1, a1, a2 + vle8.v v16, (a1) + addi t0, a0, 2 * 8 + vle8.v v17, (t1) + addi t2, t2, -2 vwcvtu.x.x.v v8, v16 + vwcvtu.x.x.v v9, v17 vse16.v v8, (a0) + add a1, t1, a2 + vse16.v v9, (t0) + addi a0, t0, 2 * 8 + bnez t2, 1b + ret endfunc @@ -67,17 +66,18 @@ endfunc func ff_diff_pixels_unaligned_rvv, zve32x lpad 0 + li t3, 8 vsetivli zero, 8, e8, mf2, ta, ma - vlsseg8e8.v v16, (a1), a3 - vlsseg8e8.v v24, (a2), a3 +1: + vle8.v v16, (a1) + add a1, a1, a3 + vle8.v v24, (a2) + add a2, a2, a3 vwsubu.vv v8, v16, v24 - vwsubu.vv v9, v17, v25 - vwsubu.vv v10, v18, v26 - vwsubu.vv v11, v19, v27 - vwsubu.vv v12, v20, v28 - vwsubu.vv v13, v21, v29 - vwsubu.vv v14, v22, v30 - vwsubu.vv v15, v23, v31 - vsseg8e16.v v8, (a0) + addi t3, t3, -1 + vse16.v v8, (a0) + addi a0, a0, 2 * 8 + bnez t3, 1b + ret endfunc diff --git a/libavcodec/riscv/rv34dsp_init.c b/libavcodec/riscv/rv34dsp_init.c index 051dc7565..a8437f070 100644 --- a/libavcodec/riscv/rv34dsp_init.c +++ b/libavcodec/riscv/rv34dsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/rv34dsp_rvv.S b/libavcodec/riscv/rv34dsp_rvv.S index fc0ffec4f..69b930694 100644 --- a/libavcodec/riscv/rv34dsp_rvv.S +++ b/libavcodec/riscv/rv34dsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/rv40dsp_init.c b/libavcodec/riscv/rv40dsp_init.c index 6aba57179..65790fa59 100644 --- a/libavcodec/riscv/rv40dsp_init.c +++ b/libavcodec/riscv/rv40dsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/rv40dsp_rvv.S b/libavcodec/riscv/rv40dsp_rvv.S index ca431eb8a..7f80f2834 100644 --- a/libavcodec/riscv/rv40dsp_rvv.S +++ b/libavcodec/riscv/rv40dsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * @@ -20,15 +20,30 @@ #include "libavutil/riscv/asm.S" -.macro manual_avg dst src1 src2 - vadd.vv \dst, \src1, \src2 - vadd.vi \dst, \dst, 1 - vsrl.vi \dst, \dst, 1 -.endm +const rv40_bias + .byte 0, 16, 32, 16 + .byte 32, 28, 32, 28 + .byte 0, 32, 16, 32 + .byte 32, 28, 32, 28 +endconst .macro do_chroma_mc type unroll - csrwi vxrm, 2 + csrwi vxrm, 0 + addi sp, sp, -16 +#if __riscv_xlen == 32 + sw s2, (sp) +#elif __riscv_xlen == 64 + sd s2, (sp) +#else + sq s2, (sp) +#endif + lla t4, rv40_bias + srli t5, a5, 1 + sh2add t4, t5, t4 + srli t5, a4, 1 + add t5, t4, t5 slli t2, a5, 3 + lb s2, (t5) mul t1, a5, a4 sh3add a5, a4, t2 slli a4, a4, 3 @@ -80,17 +95,19 @@ vwmulu.vx v12, v14, a6 vwmaccu.vx v10, t1, v15 vwmaccu.vx v12, a7, v15 - vnclipu.wi v15, v8, 6 + vwaddu.wx v20, v8, s2 + vnsrl.wi v15, v20, 6 .ifc \type,avg vle8.v v9, (a0) - manual_avg v15, v15, v9 + vaaddu.vv v15, v15, v9 .endif vse8.v v15, (a0) add a0, a0, a2 - vnclipu.wi v8, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v9, (a0) - manual_avg v8, v8, v9 + vaaddu.vv v8, v8, v9 .endif add t4, t4, t3 vse8.v v8, (a0) @@ -115,17 +132,19 @@ vslide1down.vx v14, v14, t5 vsetvli zero, t6, e8, m1, ta, ma vwmaccu.vx v16, t1, v14 - vnclipu.wi v8, v12, 6 + vwaddu.wx v20, v12, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v9, (a0) - manual_avg v8, v8, v9 + vaaddu.vv v8, v8, v9 .endif vse8.v v8, (a0) add a0, a0, a2 - vnclipu.wi v8, v16, 6 + vwaddu.wx v20, v16, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v9, (a0) - manual_avg v8, v8, v9 + vaaddu.vv v8, v8, v9 .endif vse8.v v8, (a0) add a0, a0, a2 @@ -159,18 +178,20 @@ vwmaccu.vx v10, t0, v8 add a4, a4, a7 vwmaccu.vx v12, t0, v9 - vnclipu.wi v15, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v15, v20, 6 vwmulu.vx v10, v9, a6 - vnclipu.wi v9, v12, 6 + vwaddu.wx v20, v12, s2 + vnsrl.wi v9, v20, 6 .ifc \type,avg vle8.v v16, (a0) - manual_avg v15, v15, v16 + vaaddu.vv v15, v15, v16 .endif vse8.v v15, (a0) add a0, a0, a2 .ifc \type,avg vle8.v v16, (a0) - manual_avg v9, v9, v16 + vaaddu.vv v9, v9, v16 .endif vse8.v v9, (a0) add a0, a0, a2 @@ -179,18 +200,20 @@ vle8.v v14, (a5) vwmaccu.vx v10, t0, v8 vwmulu.vx v12, v8, a6 - vnclipu.wi v8, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v8, v20, 6 vwmaccu.vx v12, t0, v14 .ifc \type,avg vle8.v v16, (a0) - manual_avg v8, v8, v16 + vaaddu.vv v8, v8, v16 .endif vse8.v v8, (a0) add a0, a0, a2 - vnclipu.wi v8, v12, 6 + vwaddu.wx v20, v12, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v16, (a0) - manual_avg v8, v8, v16 + vaaddu.vv v8, v8, v16 .endif vse8.v v8, (a0) add a0, a0, a2 @@ -226,17 +249,19 @@ vsetvli zero, t6, e8, m1, ta, ma vwmulu.vx v12, v8, a6 vwmaccu.vx v12, a7, v9 - vnclipu.wi v16, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v16, v20, 6 .ifc \type,avg vle8.v v18, (a0) - manual_avg v16, v16, v18 + vaaddu.vv v16, v16, v18 .endif vse8.v v16, (a0) add a0, a0, a2 - vnclipu.wi v10, v12, 6 + vwaddu.wx v20, v12, s2 + vnsrl.wi v10, v20, 6 .ifc \type,avg vle8.v v18, (a0) - manual_avg v10, v10, v18 + vaaddu.vv v10, v10, v18 .endif add a4, a4, t1 vse8.v v10, (a0) @@ -254,18 +279,20 @@ vslide1down.vx v9, v8, t5 vsetvli zero, t6, e8, m1, ta, ma vwmulu.vx v12, v8, a6 - vnclipu.wi v8, v14, 6 + vwaddu.wx v20, v14, s2 + vnsrl.wi v8, v20, 6 vwmaccu.vx v12, a7, v9 .ifc \type,avg vle8.v v18, (a0) - manual_avg v8, v8, v18 + vaaddu.vv v8, v8, v18 .endif vse8.v v8, (a0) add a0, a0, a2 - vnclipu.wi v8, v12, 6 + vwaddu.wx v20, v12, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v18, (a0) - manual_avg v8, v8, v18 + vaaddu.vv v8, v8, v18 .endif vse8.v v8, (a0) add a0, a0, a2 @@ -293,18 +320,20 @@ vwmulu.vx v10, v8, a6 vle8.v v8, (t0) add t0, t1, a2 - vnclipu.wi v13, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v13, v20, 6 vwmulu.vx v10, v8, a6 .ifc \type,avg vle8.v v18, (a5) - manual_avg v13, v13, v18 + vaaddu.vv v13, v13, v18 .endif vse8.v v13, (a5) add a5, a5, a2 - vnclipu.wi v8, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v18, (a5) - manual_avg v8, v8, v18 + vaaddu.vv v8, v8, v18 .endif vse8.v v8, (a5) add a5, a5, a2 @@ -312,23 +341,34 @@ vle8.v v9, (t1) vle8.v v12, (t0) vwmulu.vx v10, v9, a6 - vnclipu.wi v8, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v8, v20, 6 vwmulu.vx v10, v12, a6 .ifc \type,avg vle8.v v18, (a5) - manual_avg v8, v8, v18 + vaaddu.vv v8, v8, v18 .endif vse8.v v8, (a5) add a5, a5, a2 - vnclipu.wi v8, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v18, (a5) - manual_avg v8, v8, v18 + vaaddu.vv v8, v8, v18 .endif vse8.v v8, (a5) .endif blt t2, a3, 7b 8: +#if __riscv_xlen == 32 + lw s2, (sp) +#elif __riscv_xlen == 64 + ld s2, (sp) +#else + lq s2, (sp) +#endif + addi sp, sp, 16 + ret .endm diff --git a/libavcodec/riscv/svqenc_init.c b/libavcodec/riscv/svqenc_init.c index 5021849e4..b2eacb6b4 100644 --- a/libavcodec/riscv/svqenc_init.c +++ b/libavcodec/riscv/svqenc_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/svqenc_rvv.S b/libavcodec/riscv/svqenc_rvv.S index d37c319db..b04998a57 100644 --- a/libavcodec/riscv/svqenc_rvv.S +++ b/libavcodec/riscv/svqenc_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/takdsp_init.c b/libavcodec/riscv/takdsp_init.c index 12d2d8dab..be3dd97d4 100644 --- a/libavcodec/riscv/takdsp_init.c +++ b/libavcodec/riscv/takdsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/takdsp_rvv.S b/libavcodec/riscv/takdsp_rvv.S index a914ab818..c0952ab16 100644 --- a/libavcodec/riscv/takdsp_rvv.S +++ b/libavcodec/riscv/takdsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * Copyright (c) 2023 Rémi Denis-Courmont * * This file is part of FFmpeg. diff --git a/libavcodec/riscv/vc1dsp_init.c b/libavcodec/riscv/vc1dsp_init.c index de9002f39..d70dd7931 100644 --- a/libavcodec/riscv/vc1dsp_init.c +++ b/libavcodec/riscv/vc1dsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vc1dsp_rvi.S b/libavcodec/riscv/vc1dsp_rvi.S index 7725bfb62..261a2382a 100644 --- a/libavcodec/riscv/vc1dsp_rvi.S +++ b/libavcodec/riscv/vc1dsp_rvi.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vc1dsp_rvv.S b/libavcodec/riscv/vc1dsp_rvv.S index f9b59688a..e54167c34 100644 --- a/libavcodec/riscv/vc1dsp_rvv.S +++ b/libavcodec/riscv/vc1dsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * Copyright (c) 2024 Rémi Denis-Courmont. * * This file is part of FFmpeg. diff --git a/libavcodec/riscv/vp8dsp_init.c b/libavcodec/riscv/vp8dsp_init.c index 250fecb2f..fecf6ef9b 100644 --- a/libavcodec/riscv/vp8dsp_init.c +++ b/libavcodec/riscv/vp8dsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * @@ -90,27 +90,22 @@ av_cold void ff_vp78dsp_init_riscv(VP8DSPContext *c) c->put_vp8_epel_pixels_tab[0][0][2] = ff_put_vp8_epel16_h6_rvv; c->put_vp8_epel_pixels_tab[1][0][2] = ff_put_vp8_epel8_h6_rvv; c->put_vp8_epel_pixels_tab[2][0][2] = ff_put_vp8_epel4_h6_rvv; - c->put_vp8_epel_pixels_tab[0][0][1] = ff_put_vp8_epel16_h4_rvv; c->put_vp8_epel_pixels_tab[1][0][1] = ff_put_vp8_epel8_h4_rvv; c->put_vp8_epel_pixels_tab[2][0][1] = ff_put_vp8_epel4_h4_rvv; c->put_vp8_epel_pixels_tab[0][2][0] = ff_put_vp8_epel16_v6_rvv; c->put_vp8_epel_pixels_tab[1][2][0] = ff_put_vp8_epel8_v6_rvv; c->put_vp8_epel_pixels_tab[2][2][0] = ff_put_vp8_epel4_v6_rvv; - c->put_vp8_epel_pixels_tab[0][1][0] = ff_put_vp8_epel16_v4_rvv; c->put_vp8_epel_pixels_tab[1][1][0] = ff_put_vp8_epel8_v4_rvv; c->put_vp8_epel_pixels_tab[2][1][0] = ff_put_vp8_epel4_v4_rvv; #if __riscv_xlen <= 64 c->put_vp8_epel_pixels_tab[0][2][2] = ff_put_vp8_epel16_h6v6_rvv; c->put_vp8_epel_pixels_tab[1][2][2] = ff_put_vp8_epel8_h6v6_rvv; c->put_vp8_epel_pixels_tab[2][2][2] = ff_put_vp8_epel4_h6v6_rvv; - c->put_vp8_epel_pixels_tab[0][2][1] = ff_put_vp8_epel16_h4v6_rvv; c->put_vp8_epel_pixels_tab[1][2][1] = ff_put_vp8_epel8_h4v6_rvv; c->put_vp8_epel_pixels_tab[2][2][1] = ff_put_vp8_epel4_h4v6_rvv; - c->put_vp8_epel_pixels_tab[0][1][1] = ff_put_vp8_epel16_h4v4_rvv; c->put_vp8_epel_pixels_tab[1][1][1] = ff_put_vp8_epel8_h4v4_rvv; c->put_vp8_epel_pixels_tab[2][1][1] = ff_put_vp8_epel4_h4v4_rvv; - c->put_vp8_epel_pixels_tab[0][1][2] = ff_put_vp8_epel16_h6v4_rvv; c->put_vp8_epel_pixels_tab[1][1][2] = ff_put_vp8_epel8_h6v4_rvv; c->put_vp8_epel_pixels_tab[2][1][2] = ff_put_vp8_epel4_h6v4_rvv; #endif @@ -129,8 +124,8 @@ av_cold void ff_vp8dsp_init_riscv(VP8DSPContext *c) #if __riscv_xlen >= 64 if (flags & AV_CPU_FLAG_RVV_I64) c->vp8_luma_dc_wht = ff_vp8_luma_dc_wht_rvv; -#endif c->vp8_idct_add = ff_vp8_idct_add_rvv; +#endif c->vp8_idct_dc_add = ff_vp8_idct_dc_add_rvv; c->vp8_idct_dc_add4y = ff_vp8_idct_dc_add4y_rvv; if (flags & AV_CPU_FLAG_RVV_I64) diff --git a/libavcodec/riscv/vp8dsp_rvi.S b/libavcodec/riscv/vp8dsp_rvi.S index 07d5c8503..fa9843856 100644 --- a/libavcodec/riscv/vp8dsp_rvi.S +++ b/libavcodec/riscv/vp8dsp_rvi.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vp8dsp_rvv.S b/libavcodec/riscv/vp8dsp_rvv.S index a8b3e239b..ed08f72cd 100644 --- a/libavcodec/riscv/vp8dsp_rvv.S +++ b/libavcodec/riscv/vp8dsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * Copyright © 2024 Rémi Denis-Courmont. * * This file is part of FFmpeg. @@ -97,7 +97,6 @@ func ff_vp8_luma_dc_wht_rvv, zve64x vsse16.v v3, (t3), t0 ret endfunc -#endif func ff_vp8_idct_add_rvv, zve32x lpad 0 @@ -158,6 +157,7 @@ func ff_vp8_idct_add_rvv, zve32x vsub.vv v3, v4, v7 jr t0 endfunc +#endif func ff_vp8_idct_dc_add_rvv, zve32x lpad 0 @@ -365,7 +365,7 @@ func ff_put_vp8_bilin\len\()_hv_rvv, zve32x endfunc .endr -const subpel_filters +const subpel_filters, align=0 .byte 0, -6, 123, 12, -1, 0 .byte 2, -11, 108, 36, -8, 1 .byte 0, -9, 93, 50, -6, 0 @@ -537,7 +537,14 @@ func ff_put_vp8_epel\len\()_h\hsize\()v\vsize\()_rvv, zve32x, zba endfunc .endm -.irp len,16,8,4 +# Only the sixtaps versions are used for epel16. +epel 16 6 h +epel 16 6 v +#if __riscv_xlen <= 64 +epel_hv 16 6 6 +#endif + +.irp len,8,4 epel \len 6 h epel \len 4 h epel \len 6 v diff --git a/libavcodec/riscv/vp9_intra_rvv.S b/libavcodec/riscv/vp9_intra_rvv.S index 13d695c83..89e984c63 100644 --- a/libavcodec/riscv/vp9_intra_rvv.S +++ b/libavcodec/riscv/vp9_intra_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vp9_mc_rvi.S b/libavcodec/riscv/vp9_mc_rvi.S index 4a8371b23..764ac1771 100644 --- a/libavcodec/riscv/vp9_mc_rvi.S +++ b/libavcodec/riscv/vp9_mc_rvi.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vp9_mc_rvv.S b/libavcodec/riscv/vp9_mc_rvv.S index d1ddbe007..422ec9033 100644 --- a/libavcodec/riscv/vp9_mc_rvv.S +++ b/libavcodec/riscv/vp9_mc_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vp9dsp.h b/libavcodec/riscv/vp9dsp.h index 601939882..2422cd83e 100644 --- a/libavcodec/riscv/vp9dsp.h +++ b/libavcodec/riscv/vp9dsp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vp9dsp_init.c b/libavcodec/riscv/vp9dsp_init.c index d53852f67..67c227cf3 100644 --- a/libavcodec/riscv/vp9dsp_init.c +++ b/libavcodec/riscv/vp9dsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vvc/Makefile b/libavcodec/riscv/vvc/Makefile new file mode 100644 index 000000000..e17ab93ab --- /dev/null +++ b/libavcodec/riscv/vvc/Makefile @@ -0,0 +1,3 @@ +OBJS-$(CONFIG_VVC_DECODER) += riscv/vvc/dsp_init.o +RVV-OBJS-$(CONFIG_VVC_DECODER) += riscv/vvc/mc_rvv.o \ + riscv/vvc/sad_rvv.o diff --git a/libavcodec/riscv/vvc/dsp_init.c b/libavcodec/riscv/vvc/dsp_init.c new file mode 100644 index 000000000..f8fde4152 --- /dev/null +++ b/libavcodec/riscv/vvc/dsp_init.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * 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 "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/riscv/cpu.h" +#include "libavcodec/vvc/dsp.h" +#include "libavcodec/vvc/dec.h" +#include "libavcodec/riscv/h26x/h2656dsp.h" + +#define bf(fn, bd, opt) fn##_##bd##_##opt + +#define AVG_PROTOTYPES(bd, opt) \ +void bf(ff_vvc_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ + const int16_t *src0, const int16_t *src1, int width, int height); \ +void bf(ff_vvc_w_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ + const int16_t *src0, const int16_t *src1, int width, int height, \ + int denom, int w0, int w1, int o); + +AVG_PROTOTYPES(8, rvv_128) +AVG_PROTOTYPES(8, rvv_256) + +#define DMVR_PROTOTYPES(bd, opt) \ +void ff_vvc_dmvr_##bd##_##opt(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, \ + int height, intptr_t mx, intptr_t my, int width); \ +void ff_vvc_dmvr_h_##bd##_##opt(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, \ + int height, intptr_t mx, intptr_t my, int width); \ +void ff_vvc_dmvr_v_##bd##_##opt(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, \ + int height, intptr_t mx, intptr_t my, int width); \ +void ff_vvc_dmvr_hv_##bd##_##opt(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, \ + int height, intptr_t mx, intptr_t my, int width); \ + +DMVR_PROTOTYPES(8, rvv_128) +DMVR_PROTOTYPES(8, rvv_256) + +#define DMVR_INIT(bd, opt) do { \ + c->inter.dmvr[0][0] = ff_vvc_dmvr_##bd##_##opt; \ + c->inter.dmvr[0][1] = ff_vvc_dmvr_h_##bd##_##opt; \ + c->inter.dmvr[1][0] = ff_vvc_dmvr_v_##bd##_##opt; \ + c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_##bd##_##opt; \ +} while (0) + +int ff_vvc_sad_rvv_128(const int16_t *src0, const int16_t *src1, int dx, int dy, int block_w, int block_h); +int ff_vvc_sad_rvv_256(const int16_t *src0, const int16_t *src1, int dx, int dy, int block_w, int block_h); + +#define PUT_PIXELS_PROTOTYPES2(bd, opt) \ +void bf(ff_vvc_put_pixels, bd, opt)(int16_t *dst, \ + const uint8_t *_src, const ptrdiff_t _src_stride, \ + const int height, const int8_t *hf, const int8_t *vf, const int width); + +PUT_PIXELS_PROTOTYPES2(8, rvv_128) +PUT_PIXELS_PROTOTYPES2(8, rvv_256) + +#define PEL_FUNC(dst, C, idx1, idx2, a) \ + do { \ + for (int w = 1; w < 7; w++) \ + c->inter.dst[C][w][idx1][idx2] = a; \ + } while (0) \ + +#define FUNCS(C, opt) \ + PEL_FUNC(put, C, 0, 0, ff_vvc_put_pixels_8_##opt); \ + +void ff_vvc_dsp_init_riscv(VVCDSPContext *const c, const int bd) +{ +#if HAVE_RVV + const int flags = av_get_cpu_flags(); + int vlenb; + + if (!(flags & AV_CPU_FLAG_RVV_I32) || !(flags & AV_CPU_FLAG_RVB)) + return; + + vlenb = ff_get_rv_vlenb(); + if (vlenb >= 32) { + switch (bd) { + case 8: + c->inter.avg = ff_vvc_avg_8_rvv_256; +# if (__riscv_xlen == 64) + c->inter.w_avg = ff_vvc_w_avg_8_rvv_256; +# endif + DMVR_INIT(8, rvv_256); + FUNCS(LUMA, rvv_256); + FUNCS(CHROMA, rvv_256); + break; + case 10: + c->inter.sad = ff_vvc_sad_rvv_256; + default: + break; + } + } else if (vlenb >= 16) { + switch (bd) { + case 8: + c->inter.avg = ff_vvc_avg_8_rvv_128; +# if (__riscv_xlen == 64) + c->inter.w_avg = ff_vvc_w_avg_8_rvv_128; +# endif + DMVR_INIT(8, rvv_128); + FUNCS(LUMA, rvv_128); + FUNCS(CHROMA, rvv_128); + break; + case 10: + c->inter.sad = ff_vvc_sad_rvv_128; + default: + break; + } + } +#endif +} diff --git a/libavcodec/riscv/vvc/mc_rvv.S b/libavcodec/riscv/vvc/mc_rvv.S new file mode 100644 index 000000000..a612290e3 --- /dev/null +++ b/libavcodec/riscv/vvc/mc_rvv.S @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * 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 "libavcodec/riscv/h26x/asm.S" + +.macro avg w, vlen, id +\id\w\vlen: +.if \w < 128 + vsetvlstatic16 \w, \vlen + addi t0, a2, 128*2 + addi t1, a3, 128*2 + add t2, a0, a1 + vle16.v v0, (a2) + vle16.v v8, (a3) + addi a5, a5, -2 + vle16.v v16, (t0) + vle16.v v24, (t1) + vadd.vv v8, v8, v0 + vadd.vv v24, v24, v16 + vmax.vx v8, v8, zero + vmax.vx v24, v24, zero + vsetvlstatic8 \w, \vlen + addi a2, a2, 128*4 + vnclipu.wi v8, v8, 7 + vnclipu.wi v24, v24, 7 + addi a3, a3, 128*4 + vse8.v v8, (a0) + vse8.v v24, (t2) + sh1add a0, a1, a0 +.else + addi a5, a5, -1 + mv t1, a0 + mv t2, a2 + mv t3, a3 + mv t4, a4 +1: + vsetvli t0, a4, e16, m8, ta, ma + sub a4, a4, t0 + vle16.v v0, (a2) + vle16.v v8, (a3) + vadd.vv v8, v8, v0 + vmax.vx v8, v8, zero + vsetvli zero, zero, e8, m4, ta, ma + vnclipu.wi v8, v8, 7 + vse8.v v8, (a0) + sh1add a2, t0, a2 + sh1add a3, t0, a3 + add a0, a0, t0 + bnez a4, 1b + add a0, t1, a1 + addi a2, t2, 128*2 + addi a3, t3, 128*2 + mv a4, t4 +.endif + bnez a5, \id\w\vlen\()b + ret +.endm + +.macro func_avg vlen +func ff_vvc_avg_8_rvv_\vlen\(), zve32x, zbb, zba + lpad 0 + POW2_JMP_TABLE 1, \vlen + csrwi vxrm, 0 + POW2_J \vlen, 1, a4 + .irp w,2,4,8,16,32,64,128 + avg \w, \vlen, 1 + .endr +endfunc +.endm + +func_avg 128 +func_avg 256 + +#if (__riscv_xlen == 64) +.macro w_avg w, vlen, id +\id\w\vlen: +.if \w <= 32 || (\w == 64 && \vlen == 256) + vsetvlstatic16 \w, \vlen + addi t0, a2, 128*2 + addi t1, a3, 128*2 + vle16.v v0, (a2) + vle16.v v4, (a3) + addi a5, a5, -2 + vle16.v v8, (t0) + vle16.v v12, (t1) + vwmul.vx v16, v0, a7 + vwmul.vx v24, v8, a7 + vwmacc.vx v16, t3, v4 + vwmacc.vx v24, t3, v12 + vsetvlstatic32 \w, \vlen + add t2, a0, a1 + vadd.vx v16, v16, t4 + vadd.vx v24, v24, t4 + vsetvlstatic16 \w, \vlen + vnsrl.wx v16, v16, t6 + vnsrl.wx v24, v24, t6 + vmax.vx v16, v16, zero + vmax.vx v24, v24, zero + vsetvlstatic8 \w, \vlen + addi a2, a2, 128*4 + vnclipu.wi v16, v16, 0 + vnclipu.wi v24, v24, 0 + vse8.v v16, (a0) + addi a3, a3, 128*4 + vse8.v v24, (t2) + sh1add a0, a1, a0 +.else + addi a5, a5, -1 + mv t1, a0 + mv t2, a2 + mv t5, a3 + mv a6, a4 +1: + vsetvli t0, a4, e16, m4, ta, ma + sub a4, a4, t0 + vle16.v v0, (a2) + vle16.v v4, (a3) + vwmul.vx v16, v0, a7 + vwmacc.vx v16, t3, v4 + vsetvli zero, zero, e32, m8, ta, ma + vadd.vx v16, v16, t4 + vsetvli zero, zero, e16, m4, ta, ma + vnsrl.wx v16, v16, t6 + vmax.vx v16, v16, zero + vsetvli zero, zero, e8, m2, ta, ma + vnclipu.wi v16, v16, 0 + vse8.v v16, (a0) + sh1add a2, t0, a2 + sh1add a3, t0, a3 + add a0, a0, t0 + bnez a4, 1b + add a0, t1, a1 + addi a2, t2, 128*2 + addi a3, t5, 128*2 + mv a4, a6 +.endif + bnez a5, \id\w\vlen\()b + ret +.endm + +.macro func_w_avg vlen +func ff_vvc_w_avg_8_rvv_\vlen\(), zve32x, zbb, zba + lpad 0 + POW2_JMP_TABLE 2, \vlen + csrwi vxrm, 0 + addi t6, a6, 7 + ld t3, (sp) + ld t4, 8(sp) + addi t4, t4, 1 // o0 + o1 + 1 + addi t5, t6, -1 // shift - 1 + sll t4, t4, t5 + POW2_J \vlen, 2, a4 + .irp w,2,4,8,16,32,64,128 + w_avg \w, \vlen, 2 + .endr +endfunc +.endm + +func_w_avg 128 +func_w_avg 256 +#endif + +func dmvr zve32x, zbb, zba + lpad 0 + li t0, 4 +1: + add t1, a1, a2 + addi t4, a0, 128*2 + vle8.v v0, (a1) + vle8.v v4, (t1) + addi a3, a3, -2 + vwmulu.vx v16, v0, t0 + vwmulu.vx v20, v4, t0 + vse16.v v16, (a0) + vse16.v v20, (t4) + sh1add a1, a2, a1 + add a0, a0, 128*2*2 + bnez a3, 1b + ret +endfunc + +.macro dmvr_h_v mn, type, w, vlen +func dmvr_\type\vlen\w, zve32x, zbb, zba + lla t4, ff_vvc_inter_luma_dmvr_filters + sh1add t4, \mn, t4 + lbu t5, (t4) + lbu t6, 1(t4) +1: + vsetvlstatic8 \w, \vlen +.ifc \type,h + addi t0, a1, 1 + addi t1, a1, 2 +.else + add t0, a1, a2 + add t1, t0, a2 +.endif + vle8.v v0, (a1) + vle8.v v4, (t0) + vle8.v v8, (t1) + addi a3, a3, -2 + addi t2, a0, 128*2 + vwmulu.vx v12, v0, t5 + vwmulu.vx v24, v4, t5 + vwmaccu.vx v12, t6, v4 + vwmaccu.vx v24, t6, v8 + vsetvlstatic16 \w, \vlen + vssrl.vi v12, v12, 2 + vssrl.vi v24, v24, 2 + vse16.v v12, (a0) + vse16.v v24, (t2) + add a0, a0, 128*4 + sh1add a1, a2, a1 + bnez a3, 1b + ret +endfunc +.endm + +.macro dmvr_load_h dst, filter0, filter1, w, vlen + vsetvlstatic8 \w, \vlen + addi a6, a1, 1 + vle8.v \dst, (a1) + vle8.v v2, (a6) + vwmulu.vx v4, \dst, \filter0 + vwmaccu.vx v4, \filter1, v2 + vsetvlstatic16 \w, \vlen + vssrl.vi \dst, v4, 2 +.endm + +.macro dmvr_hv w, vlen +func dmvr_hv\vlen\w, zve32x, zbb, zba + lla t0, ff_vvc_inter_luma_dmvr_filters + sh1add t1, a4, t0 + sh1add t2, a5, t0 + lbu t3, (t1) // filter[mx][0] + lbu t4, 1(t1) // filter[mx][1] + lbu t5, (t2) // filter[my][0] + lbu t6, 1(t2) // filter[my][1] + dmvr_load_h v12, t3, t4, \w, \vlen + add a1, a1, a2 +1: + vmul.vx v28, v12, t5 + addi a3, a3, -1 + dmvr_load_h v12, t3, t4, \w, \vlen + vmacc.vx v28, t6, v12 + vssrl.vi v28, v28, 4 + vse16.v v28, (a0) + add a1, a1, a2 + addi a0, a0, 128*2 + bnez a3, 1b + ret +endfunc +.endm + +.macro func_dmvr vlen, name +func ff_vvc_\name\()_8_rvv_\vlen\(), zve32x, zbb, zba + lpad 0 + li t0, 20 + beq a6, t0, DMVR\name\vlen\()20 + .irp w,12,20 +DMVR\name\vlen\w: + .ifc \name, dmvr + vsetvlstatic8 \w, \vlen + j \name + .else + csrwi vxrm, 0 + j \name\()\vlen\w + .endif + .endr +endfunc +.endm + + +.irp vlen,256,128 +.irp w,12,20 +dmvr_h_v a4, h, \w, \vlen +dmvr_h_v a5, v, \w, \vlen +dmvr_hv \w, \vlen +.endr +func_dmvr \vlen, dmvr +func_dmvr \vlen, dmvr_h +func_dmvr \vlen, dmvr_v +func_dmvr \vlen, dmvr_hv +.endr + +func_put_pixels 256, 128, vvc +func_put_pixels 128, 128, vvc diff --git a/libavcodec/riscv/vvc/sad_rvv.S b/libavcodec/riscv/vvc/sad_rvv.S new file mode 100644 index 000000000..d906de232 --- /dev/null +++ b/libavcodec/riscv/vvc/sad_rvv.S @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * 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 "libavcodec/riscv/h26x/asm.S" + +.macro func_sad vlen +func ff_vvc_sad_rvv_\vlen, zve32x, zbb, zba + lpad 0 + slli t2, a3, 7 // dy * 128 + li t1, 4*128+4 + add t3, t2, a2 // dy * 128 + dx + sub t1, t1, t2 + sub t1, t1, a2 + sh1add a0, t3, a0 + sh1add a1, t1, a1 + li t3, 16 + beq a4, t3, SADVSET\vlen\()16 + .irp w,8,16 +SADVSET\vlen\w: + vsetvlstatic32 \w, \vlen + vmv.v.i v0, 0 + vmv.s.x v24, zero + vsetvlstatic16 \w, \vlen, tu +SAD\vlen\w: + addi a5, a5, -2 + vle16.v v8, (a0) + vle16.v v16, (a1) + vsub.vv v8, v8, v16 + vneg.v v16, v8 + addi a0, a0, 2 * 128 * 2 + vmax.vv v8, v8, v16 + vwaddu.wv v0, v0, v8 + addi a1, a1, 2 * 128 * 2 + bnez a5, SAD\vlen\w + vsetvlstatic32 \w, \vlen + vredsum.vs v24, v0, v24 + vmv.x.s a0, v24 + ret + .endr +endfunc +.endm + +func_sad 256 +func_sad 128 diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c index 47b076dbd..a6bc56577 100644 --- a/libavcodec/rkmppdec.c +++ b/libavcodec/rkmppdec.c @@ -29,8 +29,9 @@ #include "avcodec.h" #include "codec_internal.h" #include "decode.h" +#include "decode_bsf.h" #include "hwconfig.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "libavutil/buffer.h" #include "libavutil/common.h" #include "libavutil/frame.h" @@ -123,14 +124,14 @@ static int rkmpp_write_data(AVCodecContext *avctx, uint8_t *buffer, int size, in return ret; } -static int rkmpp_close_decoder(AVCodecContext *avctx) +static av_cold int rkmpp_close_decoder(AVCodecContext *avctx) { RKMPPDecodeContext *rk_context = avctx->priv_data; - ff_refstruct_unref(&rk_context->decoder); + av_refstruct_unref(&rk_context->decoder); return 0; } -static void rkmpp_release_decoder(FFRefStructOpaque unused, void *obj) +static void rkmpp_release_decoder(AVRefStructOpaque unused, void *obj) { RKMPPDecoder *decoder = obj; @@ -149,7 +150,7 @@ static void rkmpp_release_decoder(FFRefStructOpaque unused, void *obj) av_buffer_unref(&decoder->device_ref); } -static int rkmpp_init_decoder(AVCodecContext *avctx) +static av_cold int rkmpp_init_decoder(AVCodecContext *avctx) { RKMPPDecodeContext *rk_context = avctx->priv_data; RKMPPDecoder *decoder = NULL; @@ -161,7 +162,7 @@ static int rkmpp_init_decoder(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME; // create a decoder and a ref to it - decoder = ff_refstruct_alloc_ext(sizeof(*decoder), 0, + decoder = av_refstruct_alloc_ext(sizeof(*decoder), 0, NULL, rkmpp_release_decoder); if (!decoder) { ret = AVERROR(ENOMEM); @@ -256,7 +257,6 @@ static int rkmpp_init_decoder(AVCodecContext *avctx) fail: av_log(avctx, AV_LOG_ERROR, "Failed to initialize RKMPP decoder.\n"); - rkmpp_close_decoder(avctx); return ret; } @@ -279,9 +279,11 @@ static int rkmpp_send_packet(AVCodecContext *avctx, const AVPacket *avpkt) // on first packet, send extradata if (decoder->first_packet) { if (avctx->extradata_size) { - ret = rkmpp_write_data(avctx, avctx->extradata, - avctx->extradata_size, - avpkt->pts); + const uint8_t *extradata; + int extradata_size; + ff_decode_get_extradata(avctx, &extradata, &extradata_size); + ret = rkmpp_write_data(avctx, (uint8_t*)extradata, extradata_size, + avpkt->pts); if (ret) { av_log(avctx, AV_LOG_ERROR, "Failed to write extradata to decoder (code = %d)\n", ret); return ret; @@ -304,7 +306,7 @@ static void rkmpp_release_frame(void *opaque, uint8_t *data) RKMPPFrameContext *framecontext = opaque; mpp_frame_deinit(&framecontext->frame); - ff_refstruct_unref(&framecontext->decoder_ref); + av_refstruct_unref(&framecontext->decoder_ref); av_free(desc); } @@ -449,7 +451,7 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame) ret = AVERROR(ENOMEM); goto fail; } - framecontext->decoder_ref = ff_refstruct_ref(rk_context->decoder); + framecontext->decoder_ref = av_refstruct_ref(rk_context->decoder); frame->hw_frames_ctx = av_buffer_ref(decoder->frames_ref); if (!frame->hw_frames_ctx) { @@ -482,7 +484,6 @@ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame) RKMPPDecodeContext *rk_context = avctx->priv_data; RKMPPDecoder *decoder = rk_context->decoder; int ret = MPP_NOK; - AVPacket pkt = {0}; RK_S32 usedslots, freeslots; if (!decoder->eos_reached) { @@ -495,29 +496,41 @@ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame) freeslots = INPUT_MAX_PACKETS - usedslots; if (freeslots > 0) { - ret = ff_decode_get_packet(avctx, &pkt); - if (ret < 0 && ret != AVERROR_EOF) { - return ret; + AVPacket *const pkt = avctx->internal->in_pkt; + + if (!pkt->size) { + ret = ff_decode_get_packet(avctx, pkt); + if (ret < 0 && ret != AVERROR_EOF) { + return ret; + } } - ret = rkmpp_send_packet(avctx, &pkt); - av_packet_unref(&pkt); - - if (ret < 0) { + ret = rkmpp_send_packet(avctx, pkt); + if (ret < 0 && ret != AVERROR(EAGAIN)) { + av_packet_unref(pkt); av_log(avctx, AV_LOG_ERROR, "Failed to send packet to decoder (code = %d)\n", ret); return ret; + } else if (ret == AVERROR(EAGAIN)) { + // Input queue is full, don't queue more packet. + freeslots = 0; + } else { + av_packet_unref(pkt); } } // make sure we keep decoder full - if (freeslots > 1) + if (freeslots > 1 && !decoder->eos_reached) return AVERROR(EAGAIN); } - return rkmpp_retrieve_frame(avctx, frame); + do { + ret = rkmpp_retrieve_frame(avctx, frame); + } while (decoder->eos_reached && ret == AVERROR(EAGAIN)); + + return ret; } -static void rkmpp_flush(AVCodecContext *avctx) +static av_cold void rkmpp_flush(AVCodecContext *avctx) { RKMPPDecodeContext *rk_context = avctx->priv_data; RKMPPDecoder *decoder = rk_context->decoder; @@ -560,7 +573,7 @@ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = { .hw_configs = rkmpp_hw_configs, \ .bsfs = BSFS, \ .p.wrapper_name = "rkmpp", \ - .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, \ + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_NOT_INIT_THREADSAFE, \ }; RKMPP_DEC(h264, AV_CODEC_ID_H264, "h264_mp4toannexb") diff --git a/libavcodec/rkmppenc.c b/libavcodec/rkmppenc.c new file mode 100644 index 000000000..09501f0bc --- /dev/null +++ b/libavcodec/rkmppenc.c @@ -0,0 +1,584 @@ +/* + * RockChip MPP Video Encoder + * + * This file is part of FFmpeg. + * + * Copyright (c) 2025 Zhao Zhili + * + * 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 "config_components.h" + +#include +#include + +#include +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_drm.h" +#include "libavutil/imgutils.h" +#include "libavutil/log.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "encode.h" +#include "hwconfig.h" + +#define RKMPP_TIME_BASE AV_TIME_BASE_Q +#define RKMPP_ALIGN_SIZE 16 + +typedef struct RKMPPEncoderContext { + const AVClass *av_class; + + MppCtx enc; + MppApi *mpi; + MppEncCfg cfg; + AVFrame *frame; + + MppFrameFormat pix_fmt; + int mpp_stride; + int mpp_height; + // When pix_fmt isn't hardware pixel format + MppBufferGroup buf_group; + MppBuffer frame_buf; + + MppEncRcMode rc_mode; + bool eof_sent; +} RKMPPEncoderContext; + +static const enum AVPixelFormat rkmpp_pix_fmts[] = { + AV_PIX_FMT_DRM_PRIME, + AV_PIX_FMT_NV12, + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NONE +}; + +static av_cold int rkmpp_close_encoder(AVCodecContext *avctx) +{ + RKMPPEncoderContext *ctx = avctx->priv_data; + + if (ctx->enc) { + ctx->mpi->reset(ctx->enc); + mpp_destroy(ctx->enc); + ctx->enc = NULL; + } + + if (ctx->cfg) { + mpp_enc_cfg_deinit(ctx->cfg); + ctx->cfg = NULL; + } + + if (ctx->frame_buf) { + mpp_buffer_put(ctx->frame_buf); + ctx->frame_buf = NULL; + } + + if (ctx->buf_group) { + mpp_buffer_group_put(ctx->buf_group); + ctx->buf_group = NULL; + } + + av_frame_free(&ctx->frame); + + return 0; +} + +static int rkmpp_create_frame_buf(AVCodecContext *avctx) +{ + RKMPPEncoderContext *ctx = avctx->priv_data; + + ctx->frame = av_frame_alloc(); + if (!ctx->frame) + return AVERROR(ENOMEM); + + if (avctx->pix_fmt == AV_PIX_FMT_DRM_PRIME) + return 0; + + int ret = mpp_buffer_group_get_internal(&ctx->buf_group, + MPP_BUFFER_TYPE_DRM | MPP_BUFFER_FLAGS_CACHABLE); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to create buffer group, %d\n", + ret); + return AVERROR_EXTERNAL; + } + + int n = av_image_get_buffer_size(avctx->pix_fmt, ctx->mpp_stride, + ctx->mpp_height, 1); + if (n < 0) + return ret; + ret = mpp_buffer_get(ctx->buf_group, &ctx->frame_buf, n); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to get frame buffer, %d\n", + ret); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int rkmpp_export_extradata(AVCodecContext *avctx) +{ + RKMPPEncoderContext *ctx = avctx->priv_data; + MppEncHeaderMode mode = (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) ? + MPP_ENC_HEADER_MODE_DEFAULT : MPP_ENC_HEADER_MODE_EACH_IDR; + + int ret = ctx->mpi->control(ctx->enc, MPP_ENC_SET_HEADER_MODE, &mode); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to set header mode: %d\n", ret); + return AVERROR_EXTERNAL; + } + + if (!(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) + return 0; + + size_t size = 4096; + avctx->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) + return AVERROR(ENOMEM); + + MppPacket packet = NULL; + mpp_packet_init(&packet, avctx->extradata, size); + mpp_packet_set_length(packet, 0); + ret = ctx->mpi->control(ctx->enc, MPP_ENC_GET_HDR_SYNC, packet); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to get header: %d\n", ret); + ret = AVERROR_EXTERNAL; + goto out; + } + + avctx->extradata_size = mpp_packet_get_length(packet); + if (avctx->extradata_size == 0 || avctx->extradata_size > size) { + av_log(avctx, AV_LOG_ERROR, "Invalid extradata size %d\n", + avctx->extradata_size); + ret = AVERROR_EXTERNAL; + goto out; + } + + ret = 0; +out: + mpp_packet_deinit(&packet); + + return ret; +} + +static av_cold int rkmpp_init_encoder(AVCodecContext *avctx) +{ + RKMPPEncoderContext *ctx = avctx->priv_data; + int ret; + + MppCodingType codectype; + switch (avctx->codec_id) { + case AV_CODEC_ID_H264: + codectype = MPP_VIDEO_CodingAVC; + break; + case AV_CODEC_ID_HEVC: + codectype = MPP_VIDEO_CodingHEVC; + break; + default: + av_unreachable("Invalid codec_id"); + } + + ret = mpp_check_support_format(MPP_CTX_ENC, codectype); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "The device doesn't support %s\n", + avcodec_get_name(avctx->codec_id)); + return AVERROR_EXTERNAL; + } + + ret = mpp_create(&ctx->enc, &ctx->mpi); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to create MPP context (%d).\n", ret); + return AVERROR_EXTERNAL; + } + + ret = mpp_init(ctx->enc, MPP_CTX_ENC, codectype); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialize MPP context (%d).\n", ret); + return AVERROR_EXTERNAL; + } + + ret = mpp_enc_cfg_init(&ctx->cfg); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialize config (%d).\n", ret); + return AVERROR_EXTERNAL; + } + + MppEncCfg cfg = ctx->cfg; + ret = ctx->mpi->control(ctx->enc, MPP_ENC_GET_CFG, cfg); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to get encoder config: %d\n", ret); + return AVERROR_EXTERNAL; + } + + mpp_enc_cfg_set_s32(cfg, "prep:width", avctx->width); + mpp_enc_cfg_set_s32(cfg, "prep:height", avctx->height); + ctx->mpp_stride = FFALIGN(avctx->width, RKMPP_ALIGN_SIZE); + ctx->mpp_height = FFALIGN(avctx->height, RKMPP_ALIGN_SIZE); + mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", ctx->mpp_stride); + mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", ctx->mpp_height); + + if (avctx->pix_fmt == AV_PIX_FMT_DRM_PRIME || avctx->pix_fmt == AV_PIX_FMT_NV12) + ctx->pix_fmt = MPP_FMT_YUV420SP; + else if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) + ctx->pix_fmt = MPP_FMT_YUV420P; + else // Can only happen during development + return AVERROR_BUG; + mpp_enc_cfg_set_s32(cfg, "prep:format", ctx->pix_fmt); + + if (avctx->colorspace != AVCOL_SPC_UNSPECIFIED) + mpp_enc_cfg_set_s32(cfg, "prep:colorspace", avctx->colorspace); + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) + mpp_enc_cfg_set_s32(cfg, "prep:colorprim", avctx->color_primaries); + if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED) + mpp_enc_cfg_set_s32(cfg, "prep:colortrc", avctx->color_trc); + static_assert((int)AVCOL_RANGE_MPEG == (int)MPP_FRAME_RANGE_MPEG && + (int)AVCOL_RANGE_JPEG == (int)MPP_FRAME_RANGE_JPEG && + (int)AVCOL_RANGE_UNSPECIFIED == (int) MPP_FRAME_RANGE_UNSPECIFIED, + "MppFrameColorRange not equal to AVColorRange"); + mpp_enc_cfg_set_s32(cfg, "prep:colorrange", avctx->color_range); + + /* These two options sound like variable frame rate from the doc, but they + * are not. When they are false, bitrate control is based on frame numbers + * and framerate. But when they are true, bitrate control is based on wall + * clock time, not based on frame timestamps, which makes these options + * almost useless, except in certain rare realtime case. + */ + mpp_enc_cfg_set_s32(cfg, "rc:fps_in_flex", 0); + mpp_enc_cfg_set_s32(cfg, "rc:fps_out_flex", 0); + if (avctx->framerate.den > 0 && avctx->framerate.num > 0) { + mpp_enc_cfg_set_s32(cfg, "rc:fps_in_num", avctx->framerate.num); + mpp_enc_cfg_set_s32(cfg, "rc:fps_in_denom", avctx->framerate.den); + mpp_enc_cfg_set_s32(cfg, "rc:fps_out_num", avctx->framerate.num); + mpp_enc_cfg_set_s32(cfg, "rc:fps_out_denom", avctx->framerate.den); + } + + if (avctx->gop_size >= 0) + mpp_enc_cfg_set_s32(cfg, "rc:gop", avctx->gop_size); + + mpp_enc_cfg_set_u32(cfg, "rc:mode", ctx->rc_mode); + if (avctx->bit_rate > 0) { + mpp_enc_cfg_set_s32(cfg, "rc:bps_target", avctx->bit_rate); + if (avctx->rc_buffer_size >= avctx->bit_rate) { + int seconds = round((double)avctx->rc_buffer_size / avctx->bit_rate); + // 60 is the upper bound from the doc + seconds = FFMIN(seconds, 60); + mpp_enc_cfg_set_s32(cfg, "rc:stats_time", seconds); + } + } + if (avctx->rc_max_rate > 0) + mpp_enc_cfg_set_s32(cfg, "rc:bps_max", avctx->rc_max_rate); + if (avctx->rc_min_rate > 0) + mpp_enc_cfg_set_s32(cfg, "rc:bps_min", avctx->rc_min_rate); + + mpp_enc_cfg_set_u32(cfg, "rc:drop_mode", MPP_ENC_RC_DROP_FRM_DISABLED); + + ret = ctx->mpi->control(ctx->enc, MPP_ENC_SET_CFG, cfg); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to set config: %d\n", ret); + return AVERROR_EXTERNAL; + } + + ret = rkmpp_create_frame_buf(avctx); + if (ret < 0) + return ret; + + ret = rkmpp_export_extradata(avctx); + if (ret < 0) + return ret; + + return 0; +} + +static int rkmpp_output_pkt(AVCodecContext *avctx, AVPacket *pkt, MppPacket packet) +{ + if (mpp_packet_get_eos(packet)) { + av_log(avctx, AV_LOG_INFO, "Receive eos packet\n"); + return AVERROR_EOF; + } + + size_t size = mpp_packet_get_length(packet); + void *data = mpp_packet_get_pos(packet); + + if (!size || !data) { + av_log(avctx, AV_LOG_ERROR, "Encoder return empty packet\n"); + return AVERROR_EXTERNAL; + } + + int ret = ff_get_encode_buffer(avctx, pkt, size, 0); + if (ret < 0) + return ret; + memcpy(pkt->data, data, size); + + int64_t pts = mpp_packet_get_pts(packet); + int64_t dts = mpp_packet_get_dts(packet); + + pkt->pts = av_rescale_q(pts, RKMPP_TIME_BASE, avctx->time_base); + /* dts is always zero currently, since rkmpp copy dts from MppFrame to + * MppPacket, and we don't set dts for MppFrame (it make no sense for + * encoder). rkmpp encoder doesn't support reordering, so we can just + * set dts as pts. + * + * TODO: remove this workaround once rkmpp fixed the issue. + */ + if (dts) + pkt->dts = av_rescale_q(dts, RKMPP_TIME_BASE, avctx->time_base); + else + pkt->dts = pkt->pts; + + MppMeta meta = mpp_packet_get_meta(packet); + if (!meta) { + av_log(avctx, AV_LOG_ERROR, "Failed to get meta from mpp packet\n"); + return AVERROR_EXTERNAL; + } + + int key_frame = 0; + ret = mpp_meta_get_s32(meta, KEY_OUTPUT_INTRA, &key_frame); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to get key frame info\n"); + return AVERROR_EXTERNAL; + } + + if (key_frame) + pkt->flags |= AV_PKT_FLAG_KEY; + + return 0; +} + +static int rkmpp_set_hw_frame(AVCodecContext *avctx, MppFrame frame) +{ + RKMPPEncoderContext *ctx = avctx->priv_data; + AVBufferRef *hw_ref = ctx->frame->hw_frames_ctx; + int ret; + + if (!hw_ref) + return AVERROR(EINVAL); + + AVHWFramesContext *hwframes = (AVHWFramesContext *)hw_ref->data; + if (hwframes->sw_format != AV_PIX_FMT_NV12) + return AVERROR(EINVAL); + + + const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)ctx->frame->data[0]; + const AVDRMLayerDescriptor *layer = &desc->layers[0]; + + int stride = layer->planes[0].pitch; + int vertical = layer->planes[1].offset / stride; + if (stride != ctx->mpp_stride || vertical != ctx->mpp_height) { + // Update stride info + ctx->mpp_stride = stride; + ctx->mpp_height = vertical; + mpp_enc_cfg_set_s32(ctx->cfg, "prep:hor_stride", ctx->mpp_stride); + mpp_enc_cfg_set_s32(ctx->cfg, "prep:ver_stride", ctx->mpp_height); + ret = ctx->mpi->control(ctx->enc, MPP_ENC_SET_CFG, ctx->cfg); + if (ret != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to set config: %d\n", ret); + return AVERROR_EXTERNAL; + } + } + mpp_frame_set_hor_stride(frame, stride); + mpp_frame_set_ver_stride(frame, vertical); + + MppBuffer buffer = {0}; + MppBufferInfo info = { + .type = MPP_BUFFER_TYPE_DRM, + .size = desc->objects[0].size, + .fd = desc->objects[0].fd, + }; + ret = mpp_buffer_import(&buffer, &info); + if (ret != MPP_OK) + return AVERROR_EXTERNAL; + + mpp_frame_set_buffer(frame, buffer); + mpp_buffer_put(buffer); + + return 0; +} + +static int rkmpp_set_sw_frame(AVCodecContext *avctx, MppFrame frame) +{ + RKMPPEncoderContext *ctx = avctx->priv_data; + AVFrame *f = ctx->frame; + + mpp_buffer_sync_begin(ctx->frame_buf); + void *buf = mpp_buffer_get_ptr(ctx->frame_buf); + + uint8_t *dst[4] = {NULL}; + int dst_linesizes[4] = {0}; + int ret = av_image_fill_linesizes(dst_linesizes, f->format, ctx->mpp_stride); + if (ret < 0) + goto out; + ret = av_image_fill_pointers(dst, f->format, ctx->mpp_height, buf, + dst_linesizes); + if (ret < 0) + goto out; + + av_image_copy2(dst, dst_linesizes, f->data, f->linesize, + f->format, f->width, f->height); + mpp_frame_set_hor_stride(frame, ctx->mpp_stride); + mpp_frame_set_ver_stride(frame, ctx->mpp_height); + + ret = 0; + +out: + mpp_buffer_sync_end(ctx->frame_buf); + if (!ret) + mpp_frame_set_buffer(frame, ctx->frame_buf); + + return ret; +} + +static int rkmpp_send_frame(AVCodecContext *avctx) +{ + RKMPPEncoderContext *ctx = avctx->priv_data; + MppFrame frame = NULL; + int ret = 0; + + ret = mpp_frame_init(&frame); + if (ret != MPP_OK) { + ret = AVERROR_EXTERNAL; + goto out; + } + + if (ctx->frame->buf[0]) { + if (ctx->frame->format == AV_PIX_FMT_DRM_PRIME) + ret = rkmpp_set_hw_frame(avctx, frame); + else + ret = rkmpp_set_sw_frame(avctx, frame); + + if (ret < 0) + goto out; + + mpp_frame_set_fmt(frame, ctx->pix_fmt); + mpp_frame_set_width(frame, ctx->frame->width); + mpp_frame_set_height(frame, ctx->frame->height); + mpp_frame_set_pts(frame, av_rescale_q(ctx->frame->pts, + avctx->time_base, RKMPP_TIME_BASE)); + } else { + mpp_frame_set_buffer(frame, NULL); + mpp_frame_set_eos(frame, 1); + } + + ret = ctx->mpi->encode_put_frame(ctx->enc, frame); + if (ret != MPP_OK) + ret = AVERROR_EXTERNAL; + +out: + if (frame) + mpp_frame_deinit(&frame); + + return ret; +} + +static int rkmpp_receive(AVCodecContext *avctx, AVPacket *pkt) +{ + RKMPPEncoderContext *ctx = avctx->priv_data; + + while (true) { + MppPacket packet = NULL; + int ret = ctx->mpi->encode_get_packet(ctx->enc, &packet); + + if (ret == MPP_OK && packet) { + ret = rkmpp_output_pkt(avctx, pkt, packet); + mpp_packet_deinit(&packet); + return ret; + } + + if (ctx->eof_sent) + continue; + + if (!ctx->frame->buf[0]) { + ret = ff_encode_get_frame(avctx, ctx->frame); + if (ret < 0 && ret != AVERROR_EOF) + return ret; + } + + ret = rkmpp_send_frame(avctx); + if (ret < 0) + return ret; + + if (!ctx->frame->buf[0]) + ctx->eof_sent = true; + else + av_frame_unref(ctx->frame); + } +} + +static av_cold void rkmpp_flush(AVCodecContext *avctx) +{ + RKMPPEncoderContext *ctx = avctx->priv_data; + ctx->mpi->reset(ctx->enc); + ctx->eof_sent = true; +} + +static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = { + HW_CONFIG_ENCODER_FRAMES(DRM_PRIME, DRM), + NULL +}; + +#define OFFSET(x) offsetof(RKMPPEncoderContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption rkmpp_options[] = { + {"rc", "rate-control mode", + OFFSET(rc_mode), AV_OPT_TYPE_INT, { .i64 = MPP_ENC_RC_MODE_VBR }, MPP_ENC_RC_MODE_VBR, INT_MAX, VE, .unit = "rc"}, + {"vbr", "Variable bitrate mode", + 0, AV_OPT_TYPE_CONST, {.i64 = MPP_ENC_RC_MODE_VBR}, 0, 0, VE, .unit = "rc"}, + {"cbr", "Constant bitrate mode", + 0, AV_OPT_TYPE_CONST, {.i64 = MPP_ENC_RC_MODE_CBR}, 0, 0, VE, .unit = "rc"}, + {"avbr", "Adaptive bit rate mode", + 0, AV_OPT_TYPE_CONST, {.i64 = MPP_ENC_RC_MODE_AVBR}, 0, 0, VE, .unit = "rc"}, + {NULL}, +}; + +static const AVClass rkmpp_enc_class = { + .class_name = "rkmpp_enc", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = rkmpp_options, +}; + +#define RKMPP_ENC(NAME, ID) \ + const FFCodec ff_##NAME##_rkmpp_encoder = { \ + .p.name = #NAME "_rkmpp", \ + CODEC_LONG_NAME(#NAME " (rkmpp)"), \ + .p.type = AVMEDIA_TYPE_VIDEO, \ + .p.id = ID, \ + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | \ + AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_ENCODER_FLUSH, \ + .priv_data_size = sizeof(RKMPPEncoderContext), \ + CODEC_PIXFMTS_ARRAY(rkmpp_pix_fmts), \ + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, \ + .init = rkmpp_init_encoder, \ + FF_CODEC_RECEIVE_PACKET_CB(rkmpp_receive), \ + .close = rkmpp_close_encoder, \ + .flush = rkmpp_flush, \ + .p.priv_class = &rkmpp_enc_class, \ + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \ + .p.wrapper_name = "rkmpp", \ + .hw_configs = rkmpp_hw_configs, \ + }; + +#if CONFIG_H264_RKMPP_ENCODER +RKMPP_ENC(h264, AV_CODEC_ID_H264) +#endif + +#if CONFIG_HEVC_RKMPP_ENCODER +RKMPP_ENC(hevc, AV_CODEC_ID_HEVC) +#endif diff --git a/libavcodec/rl.c b/libavcodec/rl.c index a78242d48..af304c5f8 100644 --- a/libavcodec/rl.c +++ b/libavcodec/rl.c @@ -20,7 +20,6 @@ #include #include "libavutil/attributes.h" -#include "libavutil/avassert.h" #include "rl.h" @@ -78,28 +77,30 @@ av_cold void ff_rl_init(RLTable *rl, av_cold void ff_rl_init_vlc(RLTable *rl, unsigned static_size) { - int i, q; - VLCElem table[1500] = { 0 }; - VLC vlc = { .table = table, .table_allocated = static_size }; - av_assert0(static_size <= FF_ARRAY_ELEMS(table)); - vlc_init(&vlc, 9, rl->n + 1, - &rl->table_vlc[0][1], 4, 2, - &rl->table_vlc[0][0], 4, 2, VLC_INIT_USE_STATIC); + VLCElem *vlc; - for (q = 0; q < 32; q++) { + ff_vlc_init_table_sparse(rl->rl_vlc[0], static_size, 9, rl->n + 1, + &rl->table_vlc[0][1], 4, 2, + &rl->table_vlc[0][0], 4, 2, + NULL, 0, 0, 0); + + vlc = rl->rl_vlc[0]; + + // We count down to avoid trashing the first RL-VLC + for (int q = 32; --q >= 0;) { int qmul = q * 2; int qadd = (q - 1) | 1; if (!rl->rl_vlc[q]) - return; + continue; if (q == 0) { qmul = 1; qadd = 0; } - for (i = 0; i < vlc.table_size; i++) { - int code = vlc.table[i].sym; - int len = vlc.table[i].len; + for (unsigned i = 0; i < static_size; i++) { + int idx = vlc[i].sym; + int len = vlc[i].len; int level, run; if (len == 0) { // illegal code @@ -107,18 +108,18 @@ av_cold void ff_rl_init_vlc(RLTable *rl, unsigned static_size) level = MAX_LEVEL; } else if (len < 0) { // more bits needed run = 0; - level = code; + level = idx; } else { - if (code == rl->n) { // esc + if (idx == rl->n) { // esc run = 66; level = 0; } else { - run = rl->table_run[code] + 1; - level = rl->table_level[code] * qmul + qadd; - if (code >= rl->last) run += 192; + run = rl->table_run[idx] + 1; + level = rl->table_level[idx] * qmul + qadd; + if (idx >= rl->last) run += 192; } } - rl->rl_vlc[q][i].len = len; + rl->rl_vlc[q][i].len8 = len; rl->rl_vlc[q][i].level = level; rl->rl_vlc[q][i].run = run; } diff --git a/libavcodec/rl.h b/libavcodec/rl.h index c45d8659d..2588de244 100644 --- a/libavcodec/rl.h +++ b/libavcodec/rl.h @@ -100,13 +100,9 @@ do { \ static inline int get_rl_index(const RLTable *rl, int last, int run, int level) { - int index; - index = rl->index_run[last][run]; - if (index >= rl->n) - return rl->n; if (level > rl->max_level[last][run]) return rl->n; - return index + level - 1; + return rl->index_run[last][run] + level - 1; } #endif /* AVCODEC_RL_H */ diff --git a/libavcodec/roqaudioenc.c b/libavcodec/roqaudioenc.c index 8d08a1365..8a626c0d2 100644 --- a/libavcodec/roqaudioenc.c +++ b/libavcodec/roqaudioenc.c @@ -198,6 +198,5 @@ const FFCodec ff_roq_dpcm_encoder = { .init = roq_dpcm_encode_init, FF_CODEC_ENCODE_CB(roq_dpcm_encode_frame), .close = roq_dpcm_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), }; diff --git a/libavcodec/roqvideoenc.c b/libavcodec/roqvideoenc.c index 7cbe820f9..03a1651c7 100644 --- a/libavcodec/roqvideoenc.c +++ b/libavcodec/roqvideoenc.c @@ -1126,8 +1126,7 @@ const FFCodec ff_roq_encoder = { .init = roq_encode_init, FF_CODEC_ENCODE_CB(roq_encode_frame), .close = roq_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUVJ444P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUVJ444P), .color_ranges = AVCOL_RANGE_JPEG, .p.priv_class = &roq_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/rpzaenc.c b/libavcodec/rpzaenc.c index 3a1924d38..32e06c991 100644 --- a/libavcodec/rpzaenc.c +++ b/libavcodec/rpzaenc.c @@ -619,7 +619,7 @@ static void rpza_encode_stream(RpzaContext *s, const AVFrame *pict) if (compare_blocks(&prev_pixels[pblock_offset], &src_pixels[block_offset], &bi, s->skip_frame_thresh) != 0) { - // write out skipable blocks + // write out skippable blocks if (n_blocks) { // write skip opcode @@ -788,7 +788,7 @@ post_skip : } } -static int rpza_encode_init(AVCodecContext *avctx) +static av_cold int rpza_encode_init(AVCodecContext *avctx) { RpzaContext *s = avctx->priv_data; @@ -847,7 +847,7 @@ static int rpza_encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } -static int rpza_encode_end(AVCodecContext *avctx) +static av_cold int rpza_encode_end(AVCodecContext *avctx) { RpzaContext *s = (RpzaContext *)avctx->priv_data; @@ -884,6 +884,5 @@ const FFCodec ff_rpza_encoder = { .init = rpza_encode_init, FF_CODEC_ENCODE_CB(rpza_encode_frame), .close = rpza_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB555, - AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_RGB555), }; diff --git a/libavcodec/rscc.c b/libavcodec/rscc.c index e601ff39e..3715e1c6d 100644 --- a/libavcodec/rscc.c +++ b/libavcodec/rscc.c @@ -347,14 +347,7 @@ static int rscc_decode_frame(AVCodecContext *avctx, AVFrame *frame, /* Palette handling */ if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = -#endif ff_copy_palette(ctx->palette, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(frame->data[1], ctx->palette, AVPALETTE_SIZE); } // We only return a picture when enough of it is undamaged, this avoids copying nearly broken frames around diff --git a/libavcodec/rtjpeg.c b/libavcodec/rtjpeg.c index 734e3875d..839eea20b 100644 --- a/libavcodec/rtjpeg.c +++ b/libavcodec/rtjpeg.c @@ -18,6 +18,8 @@ * 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 "get_bits.h" #include "rtjpeg.h" @@ -167,7 +169,7 @@ void ff_rtjpeg_decode_init(RTJpegContext *c, int width, int height, c->h = height; } -void ff_rtjpeg_init(RTJpegContext *c, struct AVCodecContext *avctx) +av_cold void ff_rtjpeg_init(RTJpegContext *c, struct AVCodecContext *avctx) { int i; diff --git a/libavcodec/rv10.c b/libavcodec/rv10.c index 753c6c6cb..1958f36c9 100644 --- a/libavcodec/rv10.c +++ b/libavcodec/rv10.c @@ -52,7 +52,7 @@ #define DC_VLC_BITS 9 typedef struct RVDecContext { - MpegEncContext m; + H263DecContext h; int sub_id; int orig_width, orig_height; } RVDecContext; @@ -78,18 +78,18 @@ static const uint16_t rv_chrom_len_count[15] = { 1, 2, 4, 0, 8, 0, 16, 0, 32, 0, 64, 0, 128, 0, 256, }; -static VLC rv_dc_lum, rv_dc_chrom; +static VLCElem rv_dc_lum[1472], rv_dc_chrom[992]; -int ff_rv_decode_dc(MpegEncContext *s, int n) +int ff_rv_decode_dc(H263DecContext *const h, int n) { int code; if (n < 4) { - code = get_vlc2(&s->gb, rv_dc_lum.table, DC_VLC_BITS, 2); + code = get_vlc2(&h->gb, rv_dc_lum, DC_VLC_BITS, 2); } else { - code = get_vlc2(&s->gb, rv_dc_chrom.table, DC_VLC_BITS, 2); + code = get_vlc2(&h->gb, rv_dc_chrom, DC_VLC_BITS, 2); if (code < 0) { - av_log(s->avctx, AV_LOG_ERROR, "chroma dc error\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "chroma dc error\n"); return -1; } } @@ -97,60 +97,59 @@ int ff_rv_decode_dc(MpegEncContext *s, int n) } /* read RV 1.0 compatible frame header */ -static int rv10_decode_picture_header(MpegEncContext *s) +static int rv10_decode_picture_header(H263DecContext *const h) { int mb_count, pb_frame, marker, mb_xy; - marker = get_bits1(&s->gb); + marker = get_bits1(&h->gb); - if (get_bits1(&s->gb)) - s->pict_type = AV_PICTURE_TYPE_P; + if (get_bits1(&h->gb)) + h->c.pict_type = AV_PICTURE_TYPE_P; else - s->pict_type = AV_PICTURE_TYPE_I; + h->c.pict_type = AV_PICTURE_TYPE_I; if (!marker) - av_log(s->avctx, AV_LOG_ERROR, "marker missing\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "marker missing\n"); - pb_frame = get_bits1(&s->gb); + pb_frame = get_bits1(&h->gb); - ff_dlog(s->avctx, "pict_type=%d pb_frame=%d\n", s->pict_type, pb_frame); + ff_dlog(h->c.avctx, "pict_type=%d pb_frame=%d\n", h->c.pict_type, pb_frame); if (pb_frame) { - avpriv_request_sample(s->avctx, "PB-frame"); + avpriv_request_sample(h->c.avctx, "PB-frame"); return AVERROR_PATCHWELCOME; } - s->qscale = get_bits(&s->gb, 5); - if (s->qscale == 0) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid qscale value: 0\n"); + h->c.qscale = get_bits(&h->gb, 5); + if (h->c.qscale == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Invalid qscale value: 0\n"); return AVERROR_INVALIDDATA; } - if (s->pict_type == AV_PICTURE_TYPE_I) { - if (s->rv10_version == 3) { + if (h->c.pict_type == AV_PICTURE_TYPE_I) { + if (h->rv10_version == 3) { /* specific MPEG like DC coding not used */ - s->last_dc[0] = get_bits(&s->gb, 8); - s->last_dc[1] = get_bits(&s->gb, 8); - s->last_dc[2] = get_bits(&s->gb, 8); - ff_dlog(s->avctx, "DC:%d %d %d\n", s->last_dc[0], - s->last_dc[1], s->last_dc[2]); + h->last_dc[0] = get_bits(&h->gb, 8); + h->last_dc[1] = get_bits(&h->gb, 8); + h->last_dc[2] = get_bits(&h->gb, 8); + ff_dlog(h->c.avctx, "DC:%d %d %d\n", h->last_dc[0], + h->last_dc[1], h->last_dc[2]); } } /* if multiple packets per frame are sent, the position at which * to display the macroblocks is coded here */ - mb_xy = s->mb_x + s->mb_y * s->mb_width; - if (show_bits(&s->gb, 12) == 0 || (mb_xy && mb_xy < s->mb_num)) { - s->mb_x = get_bits(&s->gb, 6); /* mb_x */ - s->mb_y = get_bits(&s->gb, 6); /* mb_y */ - mb_count = get_bits(&s->gb, 12); + mb_xy = h->c.mb_x + h->c.mb_y * h->c.mb_width; + if (show_bits(&h->gb, 12) == 0 || (mb_xy && mb_xy < h->c.mb_num)) { + h->c.mb_x = get_bits(&h->gb, 6); /* mb_x */ + h->c.mb_y = get_bits(&h->gb, 6); /* mb_y */ + mb_count = get_bits(&h->gb, 12); } else { - s->mb_x = 0; - s->mb_y = 0; - mb_count = s->mb_width * s->mb_height; + h->c.mb_x = 0; + h->c.mb_y = 0; + mb_count = h->c.mb_width * h->c.mb_height; } - skip_bits(&s->gb, 3); /* ignored */ - s->f_code = 1; + skip_bits(&h->gb, 3); /* ignored */ return mb_count; } @@ -160,149 +159,155 @@ static int rv20_decode_picture_header(RVDecContext *rv, int whole_size) static const enum AVPictureType pict_types[] = { AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_I /* hmm ... */, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B }; - MpegEncContext *s = &rv->m; + H263DecContext *const h = &rv->h; int seq, mb_pos, ret; int rpr_max; - s->pict_type = pict_types[get_bits(&s->gb, 2)]; + h->c.pict_type = pict_types[get_bits(&h->gb, 2)]; - if (s->low_delay && s->pict_type == AV_PICTURE_TYPE_B) { - av_log(s->avctx, AV_LOG_ERROR, "low delay B\n"); + if (h->c.low_delay && h->c.pict_type == AV_PICTURE_TYPE_B) { + av_log(h->c.avctx, AV_LOG_ERROR, "low delay B\n"); return -1; } - if (!s->last_pic.ptr && s->pict_type == AV_PICTURE_TYPE_B) { - av_log(s->avctx, AV_LOG_ERROR, "early B-frame\n"); + if (!h->c.last_pic.ptr && h->c.pict_type == AV_PICTURE_TYPE_B) { + av_log(h->c.avctx, AV_LOG_ERROR, "early B-frame\n"); return AVERROR_INVALIDDATA; } - if (get_bits1(&s->gb)) { - av_log(s->avctx, AV_LOG_ERROR, "reserved bit set\n"); + if (get_bits1(&h->gb)) { + av_log(h->c.avctx, AV_LOG_ERROR, "reserved bit set\n"); return AVERROR_INVALIDDATA; } - s->qscale = get_bits(&s->gb, 5); - if (s->qscale == 0) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid qscale value: 0\n"); + h->c.qscale = get_bits(&h->gb, 5); + if (h->c.qscale == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Invalid qscale value: 0\n"); return AVERROR_INVALIDDATA; } if (RV_GET_MINOR_VER(rv->sub_id) >= 2) - s->loop_filter = get_bits1(&s->gb) && !s->avctx->lowres; + h->loop_filter = get_bits1(&h->gb) && !h->c.avctx->lowres; if (RV_GET_MINOR_VER(rv->sub_id) <= 1) - seq = get_bits(&s->gb, 8) << 7; + seq = get_bits(&h->gb, 8) << 7; else - seq = get_bits(&s->gb, 13) << 2; + seq = get_bits(&h->gb, 13) << 2; - rpr_max = s->avctx->extradata[1] & 7; + rpr_max = h->c.avctx->extradata[1] & 7; if (rpr_max) { int f, new_w, new_h; int rpr_bits = av_log2(rpr_max) + 1; - f = get_bits(&s->gb, rpr_bits); + f = get_bits(&h->gb, rpr_bits); if (f) { - if (s->avctx->extradata_size < 8 + 2 * f) { - av_log(s->avctx, AV_LOG_ERROR, "Extradata too small.\n"); + if (h->c.avctx->extradata_size < 8 + 2 * f) { + av_log(h->c.avctx, AV_LOG_ERROR, "Extradata too small.\n"); return AVERROR_INVALIDDATA; } - new_w = 4 * ((uint8_t *) s->avctx->extradata)[6 + 2 * f]; - new_h = 4 * ((uint8_t *) s->avctx->extradata)[7 + 2 * f]; + new_w = 4 * h->c.avctx->extradata[6 + 2 * f]; + new_h = 4 * h->c.avctx->extradata[7 + 2 * f]; } else { new_w = rv->orig_width; new_h = rv->orig_height; } - if (new_w != s->width || new_h != s->height || !s->context_initialized) { - AVRational old_aspect = s->avctx->sample_aspect_ratio; - av_log(s->avctx, AV_LOG_DEBUG, + if (new_w != h->c.width || new_h != h->c.height || !h->c.context_initialized) { + AVRational old_aspect = h->c.avctx->sample_aspect_ratio; + av_log(h->c.avctx, AV_LOG_DEBUG, "attempting to change resolution to %dx%d\n", new_w, new_h); - if (av_image_check_size(new_w, new_h, 0, s->avctx) < 0) + if (av_image_check_size(new_w, new_h, 0, h->c.avctx) < 0) return AVERROR_INVALIDDATA; if (whole_size < (new_w + 15)/16 * ((new_h + 15)/16) / 8) return AVERROR_INVALIDDATA; - ff_mpv_common_end(s); + ff_mpv_common_end(&h->c); // attempt to keep aspect during typical resolution switches if (!old_aspect.num) old_aspect = (AVRational){1, 1}; - if (2 * (int64_t)new_w * s->height == (int64_t)new_h * s->width) - s->avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){2, 1}); - if ((int64_t)new_w * s->height == 2 * (int64_t)new_h * s->width) - s->avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){1, 2}); + if (2 * (int64_t)new_w * h->c.height == (int64_t)new_h * h->c.width) + h->c.avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){2, 1}); + if ((int64_t)new_w * h->c.height == 2 * (int64_t)new_h * h->c.width) + h->c.avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){1, 2}); - ret = ff_set_dimensions(s->avctx, new_w, new_h); + ret = ff_set_dimensions(h->c.avctx, new_w, new_h); if (ret < 0) return ret; - s->width = new_w; - s->height = new_h; - if ((ret = ff_mpv_common_init(s)) < 0) + h->c.width = new_w; + h->c.height = new_h; + if ((ret = ff_mpv_common_init(&h->c)) < 0) return ret; } - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, "F %d/%d/%d\n", f, rpr_bits, rpr_max); + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "F %d/%d/%d\n", f, rpr_bits, rpr_max); } } - if (av_image_check_size(s->width, s->height, 0, s->avctx) < 0) + if (av_image_check_size(h->c.width, h->c.height, 0, h->c.avctx) < 0) return AVERROR_INVALIDDATA; - mb_pos = ff_h263_decode_mba(s); + mb_pos = ff_h263_decode_mba(h); - seq |= s->time & ~0x7FFF; - if (seq - s->time > 0x4000) + seq |= h->c.time & ~0x7FFF; + if (seq - h->c.time > 0x4000) seq -= 0x8000; - if (seq - s->time < -0x4000) + if (seq - h->c.time < -0x4000) seq += 0x8000; - if (seq != s->time) { - if (s->pict_type != AV_PICTURE_TYPE_B) { - s->time = seq; - s->pp_time = s->time - s->last_non_b_time; - s->last_non_b_time = s->time; + if (seq != h->c.time) { + if (h->c.pict_type != AV_PICTURE_TYPE_B) { + h->c.time = seq; + h->c.pp_time = h->c.time - h->c.last_non_b_time; + h->c.last_non_b_time = h->c.time; } else { - s->time = seq; - s->pb_time = s->pp_time - (s->last_non_b_time - s->time); + h->c.time = seq; + h->c.pb_time = h->c.pp_time - (h->c.last_non_b_time - h->c.time); } } - if (s->pict_type == AV_PICTURE_TYPE_B) { - if (s->pp_time <=s->pb_time || s->pp_time <= s->pp_time - s->pb_time || s->pp_time<=0) { - av_log(s->avctx, AV_LOG_DEBUG, + if (h->c.pict_type == AV_PICTURE_TYPE_B) { + if (h->c.pp_time <=h->c.pb_time || h->c.pp_time <= h->c.pp_time - h->c.pb_time || h->c.pp_time<=0) { + av_log(h->c.avctx, AV_LOG_DEBUG, "messed up order, possible from seeking? skipping current B-frame\n"); #define ERROR_SKIP_FRAME -123 return ERROR_SKIP_FRAME; } - ff_mpeg4_init_direct_mv(s); + ff_mpeg4_init_direct_mv(&h->c); } - s->no_rounding = get_bits1(&s->gb); + h->c.no_rounding = get_bits1(&h->gb); - if (RV_GET_MINOR_VER(rv->sub_id) <= 1 && s->pict_type == AV_PICTURE_TYPE_B) + if (RV_GET_MINOR_VER(rv->sub_id) <= 1 && h->c.pict_type == AV_PICTURE_TYPE_B) // binary decoder reads 3+2 bits here but they don't seem to be used - skip_bits(&s->gb, 5); + skip_bits(&h->gb, 5); - s->f_code = 1; - s->h263_aic = s->pict_type == AV_PICTURE_TYPE_I; - s->modified_quant = 1; - if (!s->avctx->lowres) - s->loop_filter = 1; + h->c.h263_aic = h->c.pict_type == AV_PICTURE_TYPE_I; + if (h->c.h263_aic) { + h->c.y_dc_scale_table = + h->c.c_dc_scale_table = ff_aic_dc_scale_table; + } else { + h->c.y_dc_scale_table = + h->c.c_dc_scale_table = ff_mpeg1_dc_scale_table; + } + if (!h->c.avctx->lowres) + h->loop_filter = 1; - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_INFO, + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_INFO, "num:%5d x:%2d y:%2d type:%d qscale:%2d rnd:%d\n", - seq, s->mb_x, s->mb_y, s->pict_type, s->qscale, - s->no_rounding); + seq, h->c.mb_x, h->c.mb_y, h->c.pict_type, h->c.qscale, + h->c.no_rounding); } - av_assert0(s->pict_type != AV_PICTURE_TYPE_B || !s->low_delay); + av_assert0(h->c.pict_type != AV_PICTURE_TYPE_B || !h->c.low_delay); - return s->mb_width * s->mb_height - mb_pos; + return h->c.mb_width * h->c.mb_height - mb_pos; } -static av_cold void rv10_build_vlc(VLC *vlc, const uint16_t len_count[15], +static av_cold void rv10_build_vlc(VLCElem vlc[], int table_size, + const uint16_t len_count[15], const uint8_t sym_rl[][2], int sym_rl_elems) { uint16_t syms[MAX_VLC_ENTRIES]; @@ -319,32 +324,26 @@ static av_cold void rv10_build_vlc(VLC *vlc, const uint16_t len_count[15], for (unsigned tmp = nb_lens + len_count[i]; nb_lens < tmp; nb_lens++) lens[nb_lens] = i + 2; av_assert1(nb_lens == nb_syms); - ff_vlc_init_from_lengths(vlc, DC_VLC_BITS, nb_lens, lens, 1, - syms, 2, 2, 0, VLC_INIT_STATIC_OVERLONG, NULL); + ff_vlc_init_table_from_lengths(vlc, table_size, DC_VLC_BITS, nb_lens, + lens, 1, syms, 2, 2, 0, 0); } static av_cold void rv10_init_static(void) { - static VLCElem table[1472 + 992]; - - rv_dc_lum.table = table; - rv_dc_lum.table_allocated = 1472; - rv10_build_vlc(&rv_dc_lum, rv_lum_len_count, + rv10_build_vlc(rv_dc_lum, FF_ARRAY_ELEMS(rv_dc_lum), rv_lum_len_count, rv_sym_run_len, FF_ARRAY_ELEMS(rv_sym_run_len)); for (int i = 0; i < 1 << (DC_VLC_BITS - 7 /* Length of skip prefix */); i++) { /* All codes beginning with 0x7F have the same length and value. * Modifying the table directly saves us the useless subtables. */ - rv_dc_lum.table[(0x7F << (DC_VLC_BITS - 7)) + i].sym = 255; - rv_dc_lum.table[(0x7F << (DC_VLC_BITS - 7)) + i].len = 18; + rv_dc_lum[(0x7F << (DC_VLC_BITS - 7)) + i].sym = 255; + rv_dc_lum[(0x7F << (DC_VLC_BITS - 7)) + i].len = 18; } - rv_dc_chrom.table = &table[1472]; - rv_dc_chrom.table_allocated = 992; - rv10_build_vlc(&rv_dc_chrom, rv_chrom_len_count, + rv10_build_vlc(rv_dc_chrom, FF_ARRAY_ELEMS(rv_dc_chrom), rv_chrom_len_count, rv_sym_run_len, FF_ARRAY_ELEMS(rv_sym_run_len) - 2); for (int i = 0; i < 1 << (DC_VLC_BITS - 9 /* Length of skip prefix */); i++) { /* Same as above. */ - rv_dc_chrom.table[(0x1FE << (DC_VLC_BITS - 9)) + i].sym = 255; - rv_dc_chrom.table[(0x1FE << (DC_VLC_BITS - 9)) + i].len = 18; + rv_dc_chrom[(0x1FE << (DC_VLC_BITS - 9)) + i].sym = 255; + rv_dc_chrom[(0x1FE << (DC_VLC_BITS - 9)) + i].len = 18; } } @@ -352,7 +351,7 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; RVDecContext *rv = avctx->priv_data; - MpegEncContext *s = &rv->m; + H263DecContext *const h = &rv->h; int major_ver, minor_ver, micro_ver, ret; if (avctx->extradata_size < 8) { @@ -370,8 +369,12 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) rv->orig_width = avctx->coded_width; rv->orig_height = avctx->coded_height; - s->h263_long_vectors = ((uint8_t *) avctx->extradata)[3] & 1; - rv->sub_id = AV_RB32((uint8_t *) avctx->extradata + 4); + h->h263_long_vectors = avctx->extradata[3] & 1; + rv->sub_id = AV_RB32A(avctx->extradata + 4); + if (avctx->codec_id == AV_CODEC_ID_RV20) { + h->modified_quant = 1; + h->c.chroma_qscale_table = ff_h263_chroma_qscale_table; + } major_ver = RV_GET_MAJOR_VER(rv->sub_id); minor_ver = RV_GET_MINOR_VER(rv->sub_id); @@ -379,12 +382,12 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) switch (major_ver) { case 1: - s->rv10_version = micro_ver ? 3 : 1; - s->obmc = micro_ver == 2; + h->rv10_version = micro_ver ? 3 : 1; + h->c.obmc = micro_ver == 2; break; case 2: if (minor_ver >= 2) { - s->low_delay = 0; + h->c.low_delay = 0; avctx->has_b_frames = 1; } break; @@ -396,7 +399,7 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) if (avctx->debug & FF_DEBUG_PICT_INFO) { av_log(avctx, AV_LOG_DEBUG, "ver:%X ver0:%"PRIX32"\n", rv->sub_id, - ((uint32_t *) avctx->extradata)[0]); + AV_RL32A(avctx->extradata)); } /* init static VLCs */ @@ -409,136 +412,126 @@ static int rv10_decode_packet(AVCodecContext *avctx, const uint8_t *buf, int buf_size, int buf_size2, int whole_size) { RVDecContext *rv = avctx->priv_data; - MpegEncContext *s = &rv->m; + H263DecContext *const h = &rv->h; int mb_count, mb_pos, left, start_mb_x, active_bits_size, ret; active_bits_size = buf_size * 8; - init_get_bits(&s->gb, buf, FFMAX(buf_size, buf_size2) * 8); - if (s->codec_id == AV_CODEC_ID_RV10) - mb_count = rv10_decode_picture_header(s); + init_get_bits(&h->gb, buf, FFMAX(buf_size, buf_size2) * 8); + if (h->c.codec_id == AV_CODEC_ID_RV10) + mb_count = rv10_decode_picture_header(h); else mb_count = rv20_decode_picture_header(rv, whole_size); if (mb_count < 0) { if (mb_count != ERROR_SKIP_FRAME) - av_log(s->avctx, AV_LOG_ERROR, "HEADER ERROR\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "HEADER ERROR\n"); return AVERROR_INVALIDDATA; } - if (s->mb_x >= s->mb_width || - s->mb_y >= s->mb_height) { - av_log(s->avctx, AV_LOG_ERROR, "POS ERROR %d %d\n", s->mb_x, s->mb_y); + if (h->c.mb_x >= h->c.mb_width || + h->c.mb_y >= h->c.mb_height) { + av_log(h->c.avctx, AV_LOG_ERROR, "POS ERROR %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } - mb_pos = s->mb_y * s->mb_width + s->mb_x; - left = s->mb_width * s->mb_height - mb_pos; + mb_pos = h->c.mb_y * h->c.mb_width + h->c.mb_x; + left = h->c.mb_width * h->c.mb_height - mb_pos; if (mb_count > left) { - av_log(s->avctx, AV_LOG_ERROR, "COUNT ERROR\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "COUNT ERROR\n"); return AVERROR_INVALIDDATA; } - if (whole_size < s->mb_width * s->mb_height / 8) + if (whole_size < h->c.mb_width * h->c.mb_height / 8) return AVERROR_INVALIDDATA; - if ((s->mb_x == 0 && s->mb_y == 0) || !s->cur_pic.ptr) { + if ((h->c.mb_x == 0 && h->c.mb_y == 0) || !h->c.cur_pic.ptr) { // FIXME write parser so we always have complete frames? - if (s->cur_pic.ptr) { - ff_er_frame_end(&s->er, NULL); - ff_mpv_frame_end(s); - s->mb_x = s->mb_y = s->resync_mb_x = s->resync_mb_y = 0; + if (h->c.cur_pic.ptr) { + ff_er_frame_end(&h->c.er, NULL); + ff_mpv_frame_end(&h->c); + h->c.mb_x = h->c.mb_y = h->c.resync_mb_x = h->c.resync_mb_y = 0; } - if ((ret = ff_mpv_frame_start(s, avctx)) < 0) + if ((ret = ff_mpv_frame_start(&h->c, avctx)) < 0) return ret; - ff_mpeg_er_frame_start(s); + ff_mpv_er_frame_start_ext(&h->c, 0, h->c.pp_time, h->c.pb_time); } else { - if (s->cur_pic.ptr->f->pict_type != s->pict_type) { - av_log(s->avctx, AV_LOG_ERROR, "Slice type mismatch\n"); + if (h->c.cur_pic.ptr->f->pict_type != h->c.pict_type) { + av_log(h->c.avctx, AV_LOG_ERROR, "Slice type mismatch\n"); return AVERROR_INVALIDDATA; } } - ff_dlog(avctx, "qscale=%d\n", s->qscale); + ff_dlog(avctx, "qscale=%d\n", h->c.qscale); /* default quantization values */ - if (s->codec_id == AV_CODEC_ID_RV10) { - if (s->mb_y == 0) - s->first_slice_line = 1; + if (h->c.codec_id == AV_CODEC_ID_RV10) { + if (h->c.mb_y == 0) + h->c.first_slice_line = 1; } else { - s->first_slice_line = 1; - s->resync_mb_x = s->mb_x; - } - start_mb_x = s->mb_x; - s->resync_mb_y = s->mb_y; - if (s->h263_aic) { - s->y_dc_scale_table = - s->c_dc_scale_table = ff_aic_dc_scale_table; - } else { - s->y_dc_scale_table = - s->c_dc_scale_table = ff_mpeg1_dc_scale_table; + h->c.first_slice_line = 1; + h->c.resync_mb_x = h->c.mb_x; } + start_mb_x = h->c.mb_x; + h->c.resync_mb_y = h->c.mb_y; - if (s->modified_quant) - s->chroma_qscale_table = ff_h263_chroma_qscale_table; + ff_set_qscale(&h->c, h->c.qscale); - ff_set_qscale(s, s->qscale); - - s->rv10_first_dc_coded[0] = 0; - s->rv10_first_dc_coded[1] = 0; - s->rv10_first_dc_coded[2] = 0; - ff_init_block_index(s); + h->rv10_first_dc_coded[0] = 0; + h->rv10_first_dc_coded[1] = 0; + h->rv10_first_dc_coded[2] = 0; + ff_init_block_index(&h->c); /* decode each macroblock */ - for (s->mb_num_left = mb_count; s->mb_num_left > 0; s->mb_num_left--) { + for (h->mb_num_left = mb_count; h->mb_num_left > 0; h->mb_num_left--) { int ret; - ff_update_block_index(s, 8, s->avctx->lowres, 1); - ff_tlog(avctx, "**mb x=%d y=%d\n", s->mb_x, s->mb_y); + ff_update_block_index(&h->c, 8, h->c.avctx->lowres, 1); + ff_tlog(avctx, "**mb x=%d y=%d\n", h->c.mb_x, h->c.mb_y); - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - ret = ff_h263_decode_mb(s, s->block); + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + ret = ff_h263_decode_mb(h); // Repeat the slice end check from ff_h263_decode_mb with our active // bitstream size - if (ret != SLICE_ERROR && active_bits_size >= get_bits_count(&s->gb)) { - int v = show_bits(&s->gb, 16); + if (ret != SLICE_ERROR && active_bits_size >= get_bits_count(&h->gb)) { + int v = show_bits(&h->gb, 16); - if (get_bits_count(&s->gb) + 16 > active_bits_size) - v >>= get_bits_count(&s->gb) + 16 - active_bits_size; + if (get_bits_count(&h->gb) + 16 > active_bits_size) + v >>= get_bits_count(&h->gb) + 16 - active_bits_size; if (!v) ret = SLICE_END; } - if (ret != SLICE_ERROR && active_bits_size < get_bits_count(&s->gb) && - 8 * buf_size2 >= get_bits_count(&s->gb)) { + if (ret != SLICE_ERROR && active_bits_size < get_bits_count(&h->gb) && + 8 * buf_size2 >= get_bits_count(&h->gb)) { active_bits_size = buf_size2 * 8; av_log(avctx, AV_LOG_DEBUG, "update size from %d to %d\n", 8 * buf_size, active_bits_size); ret = SLICE_OK; } - if (ret == SLICE_ERROR || active_bits_size < get_bits_count(&s->gb)) { - av_log(s->avctx, AV_LOG_ERROR, "ERROR at MB %d %d\n", s->mb_x, - s->mb_y); + if (ret == SLICE_ERROR || active_bits_size < get_bits_count(&h->gb)) { + av_log(h->c.avctx, AV_LOG_ERROR, "ERROR at MB %d %d\n", h->c.mb_x, + h->c.mb_y); return AVERROR_INVALIDDATA; } - if (s->pict_type != AV_PICTURE_TYPE_B) - ff_h263_update_motion_val(s); - ff_mpv_reconstruct_mb(s, s->block); - if (s->loop_filter) - ff_h263_loop_filter(s); + if (h->c.pict_type != AV_PICTURE_TYPE_B) + ff_h263_update_motion_val(&h->c); + ff_mpv_reconstruct_mb(&h->c, h->block); + if (h->loop_filter) + ff_h263_loop_filter(&h->c); - if (++s->mb_x == s->mb_width) { - s->mb_x = 0; - s->mb_y++; - ff_init_block_index(s); + if (++h->c.mb_x == h->c.mb_width) { + h->c.mb_x = 0; + h->c.mb_y++; + ff_init_block_index(&h->c); } - if (s->mb_x == s->resync_mb_x) - s->first_slice_line = 0; + if (h->c.mb_x == h->c.resync_mb_x) + h->c.first_slice_line = 0; if (ret == SLICE_END) break; } - ff_er_add_slice(&s->er, start_mb_x, s->resync_mb_y, s->mb_x - 1, s->mb_y, + ff_er_add_slice(&h->c.er, start_mb_x, h->c.resync_mb_y, h->c.mb_x - 1, h->c.mb_y, ER_MB_END); return active_bits_size; diff --git a/libavcodec/rv10dec.h b/libavcodec/rv10dec.h index daa6b8d65..e878e164b 100644 --- a/libavcodec/rv10dec.h +++ b/libavcodec/rv10dec.h @@ -21,8 +21,8 @@ #ifndef AVCODEC_RV10DEC_H #define AVCODEC_RV10DEC_H -#include "mpegvideo.h" +struct H263DecContext; -int ff_rv_decode_dc(MpegEncContext *s, int n); +int ff_rv_decode_dc(struct H263DecContext *const h, int n); #endif /* AVCODEC_RV10DEC_H */ diff --git a/libavcodec/rv10enc.c b/libavcodec/rv10enc.c index 2104ee0a2..54941e6ac 100644 --- a/libavcodec/rv10enc.c +++ b/libavcodec/rv10enc.c @@ -29,54 +29,68 @@ #include "mpegvideo.h" #include "mpegvideoenc.h" #include "put_bits.h" -#include "rv10enc.h" -int ff_rv10_encode_picture_header(MpegEncContext *s) +static int rv10_encode_picture_header(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int full_frame= 0; - align_put_bits(&s->pb); + put_bits_assume_flushed(&s->pb); put_bits(&s->pb, 1, 1); /* marker */ - put_bits(&s->pb, 1, (s->pict_type == AV_PICTURE_TYPE_P)); + put_bits(&s->pb, 1, (s->c.pict_type == AV_PICTURE_TYPE_P)); put_bits(&s->pb, 1, 0); /* not PB-mframe */ - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { /* specific MPEG like DC coding not used */ } /* if multiple packets per frame are sent, the position at which to display the macroblocks is coded here */ if(!full_frame){ - if (s->mb_width * s->mb_height >= (1U << 12)) { - avpriv_report_missing_feature(s->avctx, "Encoding frames with %d (>= 4096) macroblocks", - s->mb_width * s->mb_height); - return AVERROR(ENOSYS); - } put_bits(&s->pb, 6, 0); /* mb_x */ put_bits(&s->pb, 6, 0); /* mb_y */ - put_bits(&s->pb, 12, s->mb_width * s->mb_height); + put_bits(&s->pb, 12, s->c.mb_width * s->c.mb_height); } put_bits(&s->pb, 3, 0); /* ignored */ return 0; } +static av_cold int rv10_encode_init(AVCodecContext *avctx) +{ + MPVMainEncContext *const m = avctx->priv_data; + + m->encode_picture_header = rv10_encode_picture_header; + + if ((avctx->width | avctx->height) & 15) { + av_log(avctx, AV_LOG_ERROR, "width and height must be a multiple of 16\n"); + return AVERROR(EINVAL); + } + if (avctx->width * avctx->height >= 1U << 20) { + avpriv_report_missing_feature(avctx, "Encoding frames with %d (>= 4096) macroblocks", + avctx->width * avctx->height >> 8); + return AVERROR(ENOSYS); + } + + return ff_mpv_encode_init(avctx); +} + const FFCodec ff_rv10_encoder = { .p.name = "rv10", CODEC_LONG_NAME("RealVideo 1.0"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_RV10, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .priv_data_size = sizeof(MpegEncContext), - .init = ff_mpv_encode_init, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .priv_data_size = sizeof(MPVMainEncContext), + .init = rv10_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, }; diff --git a/libavcodec/rv20enc.c b/libavcodec/rv20enc.c index d0e24f2f2..835dc7b4c 100644 --- a/libavcodec/rv20enc.c +++ b/libavcodec/rv20enc.c @@ -32,34 +32,40 @@ #include "h263data.h" #include "h263enc.h" #include "put_bits.h" -#include "rv10enc.h" +#include "rv20enc.h" -void ff_rv20_encode_picture_header(MpegEncContext *s) { - put_bits(&s->pb, 2, s->pict_type); //I 0 vs. 1 ? +int ff_rv20_encode_picture_header(MPVMainEncContext *const m) +{ + MPVEncContext *const s = &m->s; + + put_bits_assume_flushed(&s->pb); + + put_bits(&s->pb, 2, s->c.pict_type); //I 0 vs. 1 ? put_bits(&s->pb, 1, 0); /* unknown bit */ - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); put_sbits(&s->pb, 8, s->picture_number); //FIXME wrong, but correct is not known - s->mb_x= s->mb_y= 0; + s->c.mb_x = s->c.mb_y = 0; ff_h263_encode_mba(s); - put_bits(&s->pb, 1, s->no_rounding); + put_bits(&s->pb, 1, s->c.no_rounding); - av_assert0(s->f_code == 1); - av_assert0(s->unrestricted_mv == 0); - av_assert0(s->alt_inter_vlc == 0); - av_assert0(s->umvplus == 0); - av_assert0(s->modified_quant==1); - av_assert0(s->loop_filter==1); + av_assert1(s->f_code == 1); + av_assert1(!s->me.unrestricted_mv); + av_assert1(!s->alt_inter_vlc); + av_assert1(!s->umvplus); + av_assert1(s->modified_quant == 1); + av_assert1(s->loop_filter == 1); - s->h263_aic= s->pict_type == AV_PICTURE_TYPE_I; - if(s->h263_aic){ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_aic_dc_scale_table; + s->c.h263_aic = s->c.pict_type == AV_PICTURE_TYPE_I; + if (s->c.h263_aic) { + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_aic_dc_scale_table; }else{ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_mpeg1_dc_scale_table; + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_mpeg1_dc_scale_table; } + return 0; } const FFCodec ff_rv20_encoder = { @@ -68,12 +74,12 @@ const FFCodec ff_rv20_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_RV20, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .priv_data_size = sizeof(MpegEncContext), + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .priv_data_size = sizeof(MPVMainEncContext), .init = ff_mpv_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, }; diff --git a/libavcodec/rv10enc.h b/libavcodec/rv20enc.h similarity index 78% rename from libavcodec/rv10enc.h rename to libavcodec/rv20enc.h index fc3665e83..e70f1ddfd 100644 --- a/libavcodec/rv10enc.h +++ b/libavcodec/rv20enc.h @@ -18,12 +18,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_RV10ENC_H -#define AVCODEC_RV10ENC_H +#ifndef AVCODEC_RV20ENC_H +#define AVCODEC_RV20ENC_H -#include "mpegvideo.h" +typedef struct MPVMainEncContext MPVMainEncContext; -int ff_rv10_encode_picture_header(MpegEncContext *s); -void ff_rv20_encode_picture_header(MpegEncContext *s); +int ff_rv20_encode_picture_header(MPVMainEncContext *m); -#endif /* AVCODEC_RV10ENC_H */ +#endif /* AVCODEC_RV20ENC_H */ diff --git a/libavcodec/rv30.c b/libavcodec/rv30.c index 5e1dd01aa..e0b5395fa 100644 --- a/libavcodec/rv30.c +++ b/libavcodec/rv30.c @@ -38,7 +38,6 @@ static int rv30_parse_slice_header(RV34DecContext *r, GetBitContext *gb, SliceInfo *si) { AVCodecContext *avctx = r->s.avctx; - int mb_bits; int w = r->s.width, h = r->s.height; int mb_size; int rpr; @@ -76,8 +75,7 @@ static int rv30_parse_slice_header(RV34DecContext *r, GetBitContext *gb, SliceIn si->width = w; si->height = h; mb_size = ((w + 15) >> 4) * ((h + 15) >> 4); - mb_bits = ff_rv34_get_start_offset(gb, mb_size); - si->start = get_bits(gb, mb_bits); + si->start = ff_rv34_get_start_offset(gb, mb_size); skip_bits1(gb); return 0; } @@ -118,7 +116,7 @@ static int rv30_decode_mb_info(RV34DecContext *r) static const int rv30_p_types[6] = { RV34_MB_SKIP, RV34_MB_P_16x16, RV34_MB_P_8x8, -1, RV34_MB_TYPE_INTRA, RV34_MB_TYPE_INTRA16x16 }; static const int rv30_b_types[6] = { RV34_MB_SKIP, RV34_MB_B_DIRECT, RV34_MB_B_FORWARD, RV34_MB_B_BACKWARD, RV34_MB_TYPE_INTRA, RV34_MB_TYPE_INTRA16x16 }; MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; unsigned code = get_interleaved_ue_golomb(gb); if (code > 11) { diff --git a/libavcodec/rv34.c b/libavcodec/rv34.c index d94285431..f78b91e7d 100644 --- a/libavcodec/rv34.c +++ b/libavcodec/rv34.c @@ -342,7 +342,7 @@ int ff_rv34_get_start_offset(GetBitContext *gb, int mb_size) for(i = 0; i < 5; i++) if(rv34_mb_max_sizes[i] >= mb_size - 1) break; - return rv34_mb_bits_sizes[i]; + return get_bits(gb, rv34_mb_bits_sizes[i]); } /** @@ -363,7 +363,7 @@ static inline RV34VLC* choose_vlc_set(int quant, int mod, int type) static int rv34_decode_intra_mb_header(RV34DecContext *r, int8_t *intra_types) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int t; @@ -398,7 +398,7 @@ static int rv34_decode_intra_mb_header(RV34DecContext *r, int8_t *intra_types) static int rv34_decode_inter_mb_header(RV34DecContext *r, int8_t *intra_types) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int i, t; @@ -871,7 +871,7 @@ static const int num_mvs[RV34_MB_TYPES] = { 0, 0, 1, 4, 1, 1, 0, 0, 2, 2, 2, 1 } static int rv34_decode_mv(RV34DecContext *r, int block_type) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int i, j, k, l; int mv_pos = s->mb_x * 2 + s->mb_y * 2 * s->b8_stride; int next_bt; @@ -1029,9 +1029,8 @@ static inline void rv34_process_block(RV34DecContext *r, uint8_t *pdst, int stride, int fc, int sc, int q_dc, int q_ac) { - MpegEncContext *s = &r->s; - int16_t *ptr = s->block[0]; - int has_ac = rv34_decode_block(ptr, &s->gb, r->cur_vlcs, + int16_t *const ptr = r->block; + int has_ac = rv34_decode_block(ptr, &r->gb, r->cur_vlcs, fc, sc, q_dc, q_ac, q_ac); if(has_ac){ r->rdsp.rv34_idct_add(pdst, stride, ptr); @@ -1045,11 +1044,11 @@ static void rv34_output_i16x16(RV34DecContext *r, int8_t *intra_types, int cbp) { LOCAL_ALIGNED_16(int16_t, block16, [16]); MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int q_dc = rv34_qscale_tab[ r->luma_dc_quant_i[s->qscale] ], q_ac = rv34_qscale_tab[s->qscale]; uint8_t *dst = s->dest[0]; - int16_t *ptr = s->block[0]; + int16_t *const ptr = r->block; int i, j, itype, has_ac; memset(block16, 0, 16 * sizeof(*block16)); @@ -1213,9 +1212,9 @@ static int rv34_set_deblock_coef(RV34DecContext *r) static int rv34_decode_inter_macroblock(RV34DecContext *r, int8_t *intra_types) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; uint8_t *dst = s->dest[0]; - int16_t *ptr = s->block[0]; + int16_t *const ptr = r->block; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp, cbp2; int q_dc, q_ac, has_ac; @@ -1363,12 +1362,12 @@ static int check_slice_end(RV34DecContext *r, MpegEncContext *s) int bits; if(s->mb_y >= s->mb_height) return 1; - if(!s->mb_num_left) + if (!r->mb_num_left) return 1; - if(r->s.mb_skip_run > 1) + if (r->mb_skip_run > 1) return 0; - bits = get_bits_left(&s->gb); - if(bits <= 0 || (bits < 8 && !show_bits(&s->gb, bits))) + bits = get_bits_left(&r->gb); + if (bits <= 0 || (bits < 8 && !show_bits(&r->gb, bits))) return 1; return 0; } @@ -1424,11 +1423,11 @@ static int rv34_decoder_realloc(RV34DecContext *r) static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int buf_size) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int mb_pos, slice_type; int res; - init_get_bits(&r->s.gb, buf, buf_size*8); + init_get_bits(gb, buf, buf_size*8); res = r->parse_slice_header(r, gb, &r->si); if(res < 0){ av_log(s->avctx, AV_LOG_ERROR, "Incorrect or unknown slice header\n"); @@ -1447,8 +1446,8 @@ static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int r->si.end = end; s->qscale = r->si.quant; - s->mb_num_left = r->si.end - r->si.start; - r->s.mb_skip_run = 0; + r->mb_num_left = r->si.end - r->si.start; + r->mb_skip_run = 0; mb_pos = s->mb_x + s->mb_y * s->mb_width; if(r->si.start != mb_pos){ @@ -1463,7 +1462,9 @@ static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int ff_init_block_index(s); while(!check_slice_end(r, s)) { - ff_update_block_index(s, 8, 0, 1); + s->dest[0] += 16; + s->dest[1] += 8; + s->dest[2] += 8; if(r->si.type) res = rv34_decode_inter_macroblock(r, r->intra_types + s->mb_x * 4 + 4); @@ -1491,7 +1492,7 @@ static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int } if(s->mb_x == s->resync_mb_x) s->first_slice_line=0; - s->mb_num_left--; + r->mb_num_left--; } ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, ER_MB_END); @@ -1536,19 +1537,21 @@ av_cold int ff_rv34_decode_init(AVCodecContext *avctx) int ff_rv34_decode_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { RV34DecContext *r = dst->priv_data, *r1 = src->priv_data; - MpegEncContext * const s = &r->s, * const s1 = &r1->s; - int err; + MpegEncContext *const s1 = &r1->s; + int ret; if (dst == src || !s1->context_initialized) return 0; - if (s->height != s1->height || s->width != s1->width || s->context_reinit) { - s->height = s1->height; - s->width = s1->width; - if ((err = ff_mpv_common_frame_size_change(s)) < 0) - return err; - if ((err = rv34_decoder_realloc(r)) < 0) - return err; + ret = ff_mpeg_update_thread_context(dst, src); + if (ret < 0) + return ret; + + // Did ff_mpeg_update_thread_context reinit? + if (ret > 0) { + ret = rv34_decoder_realloc(r); + if (ret < 0) + return ret; } r->cur_pts = r1->cur_pts; @@ -1557,12 +1560,7 @@ int ff_rv34_decode_update_thread_context(AVCodecContext *dst, const AVCodecConte memset(&r->si, 0, sizeof(r->si)); - // Do no call ff_mpeg_update_thread_context on a partially initialized - // decoder context. - if (!s1->context_initialized) - return 0; - - return ff_mpeg_update_thread_context(dst, src); + return 0; } static int get_slice_offset(AVCodecContext *avctx, const uint8_t *buf, int n, int slice_count, int buf_size) @@ -1581,10 +1579,7 @@ static int finish_frame(AVCodecContext *avctx, AVFrame *pict) ff_er_frame_end(&s->er, NULL); ff_mpv_frame_end(s); - s->mb_num_left = 0; - - if (HAVE_THREADS && (s->avctx->active_thread_type & FF_THREAD_FRAME)) - ff_thread_progress_report(&s->cur_pic.ptr->progress, INT_MAX); + r->mb_num_left = 0; if (s->pict_type == AV_PICTURE_TYPE_B) { if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) @@ -1652,8 +1647,8 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, av_log(avctx, AV_LOG_ERROR, "Slice offset is invalid\n"); return AVERROR_INVALIDDATA; } - init_get_bits(&s->gb, buf+offset, (buf_size-offset)*8); - if(r->parse_slice_header(r, &r->s.gb, &si) < 0 || si.start){ + init_get_bits(&r->gb, buf+offset, (buf_size-offset)*8); + if (r->parse_slice_header(r, &r->gb, &si) < 0 || si.start) { av_log(avctx, AV_LOG_ERROR, "First slice header is incorrect\n"); return AVERROR_INVALIDDATA; } @@ -1669,9 +1664,9 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, /* first slice */ if (si.start == 0) { - if (s->mb_num_left > 0 && s->cur_pic.ptr) { + if (r->mb_num_left > 0 && s->cur_pic.ptr) { av_log(avctx, AV_LOG_ERROR, "New frame but still %d MB left.\n", - s->mb_num_left); + r->mb_num_left); if (!s->context_reinit) ff_er_frame_end(&s->er, NULL); ff_mpv_frame_end(s); @@ -1774,7 +1769,7 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, size = offset1 - offset; r->si.end = s->mb_width * s->mb_height; - s->mb_num_left = r->s.mb_x + r->s.mb_y*r->s.mb_width - r->si.start; + r->mb_num_left = r->s.mb_x + r->s.mb_y*r->s.mb_width - r->si.start; if(i+1 < slice_count){ int offset2 = get_slice_offset(avctx, slices_hdr, i+2, slice_count, buf_size); @@ -1782,8 +1777,8 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, av_log(avctx, AV_LOG_ERROR, "Slice offset is invalid\n"); break; } - init_get_bits(&s->gb, buf+offset1, (buf_size-offset1)*8); - if(r->parse_slice_header(r, &r->s.gb, &si) < 0){ + init_get_bits(&r->gb, buf+offset1, (buf_size-offset1)*8); + if (r->parse_slice_header(r, &r->gb, &si) < 0) { size = offset2 - offset; }else r->si.end = si.start; @@ -1805,13 +1800,12 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, *got_picture_ptr = ret; } else if (HAVE_THREADS && (s->avctx->active_thread_type & FF_THREAD_FRAME)) { - av_log(avctx, AV_LOG_INFO, "marking unfished frame as finished\n"); + av_log(avctx, AV_LOG_INFO, "marking unfinished frame as finished\n"); /* always mark the current frame as finished, frame-mt supports * only complete frames */ ff_er_frame_end(&s->er, NULL); ff_mpv_frame_end(s); - s->mb_num_left = 0; - ff_thread_progress_report(&s->cur_pic.ptr->progress, INT_MAX); + r->mb_num_left = 0; return AVERROR_INVALIDDATA; } } diff --git a/libavcodec/rv34.h b/libavcodec/rv34.h index 6fe1f8087..85ab6b4c2 100644 --- a/libavcodec/rv34.h +++ b/libavcodec/rv34.h @@ -30,6 +30,7 @@ #include "libavutil/mem_internal.h" #include "avcodec.h" +#include "get_bits.h" #include "mpegvideo.h" #include "h264pred.h" @@ -85,6 +86,7 @@ typedef struct SliceInfo{ /** decoder context */ typedef struct RV34DecContext{ MpegEncContext s; + GetBitContext gb; RV34DSPContext rdsp; int8_t *intra_types_hist;///< old block types, used for prediction int8_t *intra_types; ///< block types @@ -96,6 +98,9 @@ typedef struct RV34DecContext{ H264PredContext h; ///< functions for 4x4 and 16x16 intra block prediction SliceInfo si; ///< current slice information + int mb_num_left; ///< number of MBs left in this video packet + int mb_skip_run; + int *mb_type; ///< internal macroblock types int block_type; ///< current block type int luma_vlc; ///< which VLC set will be used for decoding of luma blocks @@ -117,6 +122,7 @@ typedef struct RV34DecContext{ uint8_t *cbp_chroma; ///< CBP values for chroma subblocks uint16_t *deblock_coefs; ///< deblock coefficients for each macroblock + DECLARE_ALIGNED_16(int16_t, block)[16]; /** 8x8 block available flags (for MV prediction) */ DECLARE_ALIGNED(8, uint32_t, avail_cache)[3*4]; diff --git a/libavcodec/rv34_parser.c b/libavcodec/rv34_parser.c index 2997a4db7..c3aa8357d 100644 --- a/libavcodec/rv34_parser.c +++ b/libavcodec/rv34_parser.c @@ -25,6 +25,7 @@ */ #include "avcodec.h" +#include "parser_internal.h" #include "libavutil/intreadwrite.h" typedef struct RV34ParseContext { @@ -75,8 +76,8 @@ static int rv34_parse(AVCodecParserContext *s, return buf_size; } -const AVCodecParser ff_rv34_parser = { - .codec_ids = { AV_CODEC_ID_RV30, AV_CODEC_ID_RV40 }, +const FFCodecParser ff_rv34_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_RV30, AV_CODEC_ID_RV40), .priv_data_size = sizeof(RV34ParseContext), - .parser_parse = rv34_parse, + .parse = rv34_parse, }; diff --git a/libavcodec/rv34dsp.c b/libavcodec/rv34dsp.c index 44486f8ed..2e27137be 100644 --- a/libavcodec/rv34dsp.c +++ b/libavcodec/rv34dsp.c @@ -140,7 +140,7 @@ av_cold void ff_rv34dsp_init(RV34DSPContext *c) ff_rv34dsp_init_arm(c); #elif ARCH_RISCV ff_rv34dsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_rv34dsp_init_x86(c); #endif } diff --git a/libavcodec/rv34dsp.h b/libavcodec/rv34dsp.h index d59b3c273..c9fbd95e4 100644 --- a/libavcodec/rv34dsp.h +++ b/libavcodec/rv34dsp.h @@ -55,8 +55,8 @@ typedef int (*rv40_loop_filter_strength_func)(uint8_t *src, ptrdiff_t stride, int *p1, int *q1); typedef struct RV34DSPContext { - qpel_mc_func put_pixels_tab[4][16]; - qpel_mc_func avg_pixels_tab[4][16]; + qpel_mc_func put_pixels_tab[2][16]; + qpel_mc_func avg_pixels_tab[2][16]; h264_chroma_mc_func put_chroma_pixels_tab[3]; h264_chroma_mc_func avg_chroma_pixels_tab[3]; /** diff --git a/libavcodec/rv40.c b/libavcodec/rv40.c index 0a5136d12..2b010295d 100644 --- a/libavcodec/rv40.c +++ b/libavcodec/rv40.c @@ -131,7 +131,6 @@ static void rv40_parse_picture_size(GetBitContext *gb, int *w, int *h) static int rv40_parse_slice_header(RV34DecContext *r, GetBitContext *gb, SliceInfo *si) { - int mb_bits; int w = r->s.width, h = r->s.height; int mb_size; int ret; @@ -154,8 +153,7 @@ static int rv40_parse_slice_header(RV34DecContext *r, GetBitContext *gb, SliceIn si->width = w; si->height = h; mb_size = ((w + 15) >> 4) * ((h + 15) >> 4); - mb_bits = ff_rv34_get_start_offset(gb, mb_size); - si->start = get_bits(gb, mb_bits); + si->start = ff_rv34_get_start_offset(gb, mb_size); return 0; } @@ -228,18 +226,18 @@ static int rv40_decode_intra_types(RV34DecContext *r, GetBitContext *gb, int8_t static int rv40_decode_mb_info(RV34DecContext *r) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int q, i; int prev_type = 0; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; - if(!r->s.mb_skip_run) { - r->s.mb_skip_run = get_interleaved_ue_golomb(gb) + 1; - if(r->s.mb_skip_run > (unsigned)s->mb_num) + if (!r->mb_skip_run) { + r->mb_skip_run = get_interleaved_ue_golomb(gb) + 1; + if (r->mb_skip_run > (unsigned)s->mb_num) return -1; } - if(--r->s.mb_skip_run) + if (--r->mb_skip_run) return RV34_MB_SKIP; if(r->avail_cache[6-4]){ diff --git a/libavcodec/rv40dsp.c b/libavcodec/rv40dsp.c index 970faec5d..7370b89e1 100644 --- a/libavcodec/rv40dsp.c +++ b/libavcodec/rv40dsp.c @@ -24,6 +24,7 @@ * RV40 decoder motion compensation functions */ +#include "libavutil/attributes_internal.h" #include "libavutil/common.h" #include "libavutil/intreadwrite.h" #include "h264qpel.h" @@ -283,7 +284,7 @@ static void avg_rv40_qpel8_mc33_c(uint8_t *dst, const uint8_t *src, ptrdiff_t st avg_pixels8_xy2_8_c(dst, src, stride, 8); } -static const int rv40_bias[4][4] = { +attribute_visibility_hidden const int ff_rv40_bias[4][4] = { { 0, 16, 32, 16 }, { 32, 28, 32, 28 }, { 0, 32, 16, 32 }, @@ -300,7 +301,7 @@ static void OPNAME ## rv40_chroma_mc4_c(uint8_t *dst /*align 8*/,\ const int C = (8-x) * ( y);\ const int D = ( x) * ( y);\ int i;\ - int bias = rv40_bias[y>>1][x>>1];\ + int bias = ff_rv40_bias[y>>1][x>>1];\ \ av_assert2(x<8 && y<8 && x>=0 && y>=0);\ \ @@ -336,7 +337,7 @@ static void OPNAME ## rv40_chroma_mc8_c(uint8_t *dst/*align 8*/,\ const int C = (8-x) * ( y);\ const int D = ( x) * ( y);\ int i;\ - int bias = rv40_bias[y>>1][x>>1];\ + int bias = ff_rv40_bias[y>>1][x>>1];\ \ av_assert2(x<8 && y<8 && x>=0 && y>=0);\ \ @@ -711,7 +712,7 @@ av_cold void ff_rv40dsp_init(RV34DSPContext *c) ff_rv40dsp_init_arm(c); #elif ARCH_RISCV ff_rv40dsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_rv40dsp_init_x86(c); #endif } diff --git a/libavcodec/rv60data.h b/libavcodec/rv60data.h new file mode 100644 index 000000000..d96a7e4e4 --- /dev/null +++ b/libavcodec/rv60data.h @@ -0,0 +1,118 @@ +/* + * RV60 decoder + * + * 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_RV60DATA_H +#define AVCODEC_RV60DATA_H + +#include + +static const uint8_t rv60_candidate_intra_angles[6] = { + 0, 1, 10, 26, 18, 2 +}; + +static const uint8_t rv60_ipred_angle[9] = { + 0, 2, 5, 9, 13, 17, 21, 26, 32 +}; + +static const uint16_t rv60_ipred_inv_angle[9] = { + 0, 4096, 1638, 910, 630, 482, 390, 315, 256 +}; + +static const uint8_t rv60_avail_mask[64] = { + 0, 1, 0, 3, 0, 1, 0, 7, 0, 1, 0, 3, 0, 1, 0, 0xF, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const uint8_t rv60_edge1[4] = { + 0, 2, 2, 2 +}; + +static const uint8_t rv60_edge2[4] = { + 0, 3, 3, 3 +}; + +static const uint8_t rv60_qp_to_idx[64] = { + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, + 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 0, 0 +}; + +static const uint16_t rv60_quants_b[32] = { + 60, 67, 76, 85, 96, 108, 121, 136, + 152, 171, 192, 216, 242, 272, 305, 341, + 383, 432, 481, 544, 606, 683, 767, 854, + 963, 1074, 1212, 1392, 1566, 1708, 1978, 2211 +}; + +static const uint8_t rv60_chroma_quant_dc[32] = { + 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 15, 16, 17, 18, 18, 19, 20, 20, 21, 21, 22, 22, 23, 23 +}; + +static const uint8_t rv60_chroma_quant_ac[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 25 +}; + +static const uint8_t rv60_dsc_to_lx[][4] = { + {0, 0, 0, 1}, {0, 0, 0, 2}, {0, 0, 1, 0}, + {0, 0, 1, 1}, {0, 0, 1, 2}, {0, 0, 2, 0}, {0, 0, 2, 1}, + {0, 0, 2, 2}, {0, 1, 0, 0}, {0, 1, 0, 1}, {0, 1, 0, 2}, + {0, 1, 1, 0}, {0, 1, 1, 1}, {0, 1, 1, 2}, {0, 1, 2, 0}, + {0, 1, 2, 1}, {0, 1, 2, 2}, {0, 2, 0, 0}, {0, 2, 0, 1}, + {0, 2, 0, 2}, {0, 2, 1, 0}, {0, 2, 1, 1}, {0, 2, 1, 2}, + {0, 2, 2, 0}, {0, 2, 2, 1}, {0, 2, 2, 2}, {1, 0, 0, 0}, + {1, 0, 0, 1}, {1, 0, 0, 2}, {1, 0, 1, 0}, {1, 0, 1, 1}, + {1, 0, 1, 2}, {1, 0, 2, 0}, {1, 0, 2, 1}, {1, 0, 2, 2}, + {1, 1, 0, 0}, {1, 1, 0, 1}, {1, 1, 0, 2}, {1, 1, 1, 0}, + {1, 1, 1, 1}, {1, 1, 1, 2}, {1, 1, 2, 0}, {1, 1, 2, 1}, + {1, 1, 2, 2}, {1, 2, 0, 0}, {1, 2, 0, 1}, {1, 2, 0, 2}, + {1, 2, 1, 0}, {1, 2, 1, 1}, {1, 2, 1, 2}, {1, 2, 2, 0}, + {1, 2, 2, 1}, {1, 2, 2, 2}, {2, 0, 0, 0}, {2, 0, 0, 1}, + {2, 0, 0, 2}, {2, 0, 1, 0}, {2, 0, 1, 1}, {2, 0, 1, 2}, + {2, 0, 2, 0}, {2, 0, 2, 1}, {2, 0, 2, 2}, {2, 1, 0, 0}, + {2, 1, 0, 1}, {2, 1, 0, 2}, {2, 1, 1, 0}, {2, 1, 1, 1}, + {2, 1, 1, 2}, {2, 1, 2, 0}, {2, 1, 2, 1}, {2, 1, 2, 2}, + {2, 2, 0, 0}, {2, 2, 0, 1}, {2, 2, 0, 2}, {2, 2, 1, 0}, + {2, 2, 1, 1}, {2, 2, 1, 2}, {2, 2, 2, 0}, {2, 2, 2, 1}, + {2, 2, 2, 2}, {3, 0, 0, 0}, {3, 0, 0, 1}, {3, 0, 0, 2}, + {3, 0, 1, 0}, {3, 0, 1, 1}, {3, 0, 1, 2}, {3, 0, 2, 0}, + {3, 0, 2, 1}, {3, 0, 2, 2}, {3, 1, 0, 0}, {3, 1, 0, 1}, + {3, 1, 0, 2}, {3, 1, 1, 0}, {3, 1, 1, 1}, {3, 1, 1, 2}, + {3, 1, 2, 0}, {3, 1, 2, 1}, {3, 1, 2, 2}, {3, 2, 0, 0}, + {3, 2, 0, 1}, {3, 2, 0, 2}, {3, 2, 1, 0}, {3, 2, 1, 1}, + {3, 2, 1, 2}, {3, 2, 2, 0}, {3, 2, 2, 1}, {3, 2, 2, 2}, +}; + +static const uint8_t rv60_deblock_limits[32][4] = { + {0, 0, 128, 0}, {0, 0, 128, 0}, {0, 0, 128, 0}, {0, 0, 128, 0}, + {0, 0, 128, 0}, {0, 0, 128, 0}, {0, 0, 128, 0}, {0, 0, 128, 0}, + {0, 0, 128, 3}, {0, 1, 128, 3}, {0, 1, 122, 3}, {1, 1, 96, 4}, + {1, 1, 75, 4}, {1, 1, 59, 4}, {1, 1, 47, 6}, {1, 1, 37, 6}, + {1, 1, 29, 6}, {1, 2, 23, 7}, {1, 2, 18, 8}, {1, 2, 15, 8}, + {1, 2, 13, 9}, {2, 3, 11, 9}, {2, 3, 10, 10}, {2, 3, 9, 10}, + {2, 4, 8, 11}, {3, 4, 7, 11}, {3, 5, 6, 12}, {3, 5, 5, 13}, + {3, 5, 4, 14}, {4, 7, 3, 15}, {5, 8, 2, 16}, {5, 9, 1, 17} +}; + +#endif /* AVCODEC_RV60DATA_H */ diff --git a/libavcodec/rv60dec.c b/libavcodec/rv60dec.c new file mode 100644 index 000000000..2a7c5c114 --- /dev/null +++ b/libavcodec/rv60dec.c @@ -0,0 +1,2442 @@ +/* + * RV60 decoder + * Copyright (c) 2007 Mike Melanson, Konstantin Shishkov + * Copyright (C) 2023 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 + */ + +#include "avcodec.h" +#include "codec_internal.h" +#include "decode.h" +#include "get_bits.h" +#include "golomb.h" +#include "libavutil/mem.h" +#include "rv60data.h" +#include "rv60dsp.h" +#include "rv60vlcs.h" +#include "threadprogress.h" +#include "unary.h" +#include "videodsp.h" + +#include "libavutil/attributes.h" + +static const int8_t frame_types[4] = {AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B, AV_PICTURE_TYPE_NONE}; + +enum CUType { + CU_INTRA = 0, + CU_INTER_MV, + CU_SKIP, + CU_INTER +}; + +enum PUType { + PU_FULL = 0, + PU_N2HOR, + PU_N2VER, + PU_QUARTERS, + PU_N4HOR, + PU_N34HOR, + PU_N4VER, + PU_N34VER +}; + +enum IntraMode { + INTRAMODE_INDEX = 0, + INTRAMODE_DC64, + INTRAMODE_PLANE64, + INTRAMODE_MODE +}; + +enum MVRefEnum { + MVREF_NONE = 0, + MVREF_REF0, + MVREF_REF1, + MVREF_BREF, + MVREF_REF0ANDBREF, + MVREF_SKIP0, + MVREF_SKIP1, + MVREF_SKIP2, + MVREF_SKIP3 +}; + +static const uint8_t skip_mv_ref[4] = {MVREF_SKIP0, MVREF_SKIP1, MVREF_SKIP2, MVREF_SKIP3}; + +enum { + TRANSFORM_NONE = 0, + TRANSFORM_16X16, + TRANSFORM_8X8, + TRANSFORM_4X4 +}; + +static const VLCElem * cbp8_vlc[7][4]; +static const VLCElem * cbp16_vlc[7][4][4]; + +typedef struct { + const VLCElem * l0[2]; + const VLCElem * l12[2]; + const VLCElem * l3[2]; + const VLCElem * esc; +} CoeffVLCs; + +static CoeffVLCs intra_coeff_vlc[5]; +static CoeffVLCs inter_coeff_vlc[7]; + +#define MAX_VLC_SIZE 864 +static VLCElem table_data[129148]; + +/* 32-bit version of rv34_gen_vlc */ +static const VLCElem * gen_vlc(const uint8_t * bits, int size, VLCInitState * state) +{ + int counts[17] = {0}; + uint32_t codes[18]; + uint32_t cw[MAX_VLC_SIZE]; + + for (int i = 0; i < size; i++) + counts[bits[i]]++; + + codes[0] = counts[0] = 0; + for (int i = 0; i < 17; i++) + codes[i+1] = (codes[i] + counts[i]) << 1; + + for (int i = 0; i < size; i++) + cw[i] = codes[bits[i]]++; + + return ff_vlc_init_tables(state, 9, size, + bits, 1, 1, + cw, 4, 4, 0); +} + +static void build_coeff_vlc(const CoeffLens * lens, CoeffVLCs * vlc, int count, VLCInitState * state) +{ + for (int i = 0; i < count; i++) { + for (int j = 0; j < 2; j++) { + vlc[i].l0[j] = gen_vlc(lens[i].l0[j], 864, state); + vlc[i].l12[j] = gen_vlc(lens[i].l12[j], 108, state); + vlc[i].l3[j] = gen_vlc(lens[i].l3[j], 108, state); + } + vlc[i].esc = gen_vlc(lens[i].esc, 32, state); + } +} + +static av_cold void rv60_init_static_data(void) +{ + VLCInitState state = VLC_INIT_STATE(table_data); + + for (int i = 0; i < 7; i++) + for (int j = 0; j < 4; j++) + cbp16_vlc[i][0][j] = cbp8_vlc[i][j] = gen_vlc(rv60_cbp8_lens[i][j], 64, &state); + + for (int i = 0; i < 7; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 4; k++) + cbp16_vlc[i][j + 1][k] = gen_vlc(rv60_cbp16_lens[i][j][k], 64, &state); + + build_coeff_vlc(rv60_intra_lens, intra_coeff_vlc, 5, &state); + build_coeff_vlc(rv60_inter_lens, inter_coeff_vlc, 7, &state); +} + +typedef struct { + int sign; + int size; + const uint8_t * data; + int data_size; +} Slice; + +typedef struct { + int cu_split_pos; + uint8_t cu_split[1+4+16+64]; + + uint8_t coded_blk[64]; + + uint8_t avg_buffer[64*64 + 32*32*2]; + uint8_t * avg_data[3]; + int avg_linesize[3]; +} ThreadContext; + +typedef struct { + int16_t x; + int16_t y; +} MV; + +typedef struct { + enum MVRefEnum mvref; + MV f_mv; + MV b_mv; +} MVInfo; + +typedef struct { + enum IntraMode imode; + MVInfo mv; +} BlockInfo; + +typedef struct { + enum CUType cu_type; + enum PUType pu_type; +} PUInfo; + +typedef struct RV60Context { + AVCodecContext * avctx; + VideoDSPContext vdsp; + +#define CUR_PIC 0 +#define LAST_PIC 1 +#define NEXT_PIC 2 + AVFrame *last_frame[3]; + + int pict_type; + int qp; + int osvquant; + int ts; + int two_f_refs; + int qp_off_type; + int deblock; + int deblock_chroma; + int awidth; + int aheight; + int cu_width; + int cu_height; + + Slice * slice; + + int pu_stride; + PUInfo * pu_info; + + int blk_stride; + BlockInfo * blk_info; + + int dblk_stride; + uint8_t * left_str; + uint8_t * top_str; + + uint64_t ref_pts[2], ts_scale; + uint32_t ref_ts[2]; + + struct ThreadProgress *progress; + unsigned nb_progress; +} RV60Context; + +static int progress_init(RV60Context *s, unsigned count) +{ + if (s->nb_progress < count) { + void *tmp = av_realloc_array(s->progress, count, sizeof(*s->progress)); + if (!tmp) + return AVERROR(ENOMEM); + s->progress = tmp; + memset(s->progress + s->nb_progress, 0, (count - s->nb_progress) * sizeof(*s->progress)); + for (int i = s->nb_progress; i < count; i++) { + int ret = ff_thread_progress_init(&s->progress[i], 1); + if (ret < 0) + return ret; + s->nb_progress = i + 1; + } + } + + for (int i = 0; i < count; i++) + ff_thread_progress_reset(&s->progress[i]); + + return 0; +} + +static av_cold int rv60_decode_init(AVCodecContext * avctx) +{ + static AVOnce init_static_once = AV_ONCE_INIT; + RV60Context *s = avctx->priv_data; + + s->avctx = avctx; + + ff_videodsp_init(&s->vdsp, 8); + + avctx->pix_fmt = AV_PIX_FMT_YUV420P; + + for (int i = 0; i < 3; i++) { + s->last_frame[i] = av_frame_alloc(); + if (!s->last_frame[i]) + return AVERROR(ENOMEM); + } + + ff_thread_once(&init_static_once, rv60_init_static_data); + + return 0; +} + +static int update_dimensions_clear_info(RV60Context *s, int width, int height) +{ + int ret; + + if (width != s->avctx->width || height != s->avctx->height) { + + av_log(s->avctx, AV_LOG_INFO, "changing dimensions to %dx%d\n", width, height); + + for (int i = 0; i < 3; i++) + av_frame_unref(s->last_frame[i]); + + if ((ret = ff_set_dimensions(s->avctx, width, height)) < 0) + return ret; + + if (s->avctx->width <= 64 || s->avctx->height <= 64) + av_log(s->avctx, AV_LOG_WARNING, "unable to faithfully reproduce emulated edges; expect visual artefacts\n"); + } + + s->awidth = FFALIGN(width, 16); + s->aheight = FFALIGN(height, 16); + + s->cu_width = (width + 63) >> 6; + s->cu_height = (height + 63) >> 6; + + s->pu_stride = s->cu_width << 3; + s->blk_stride = s->cu_width << 4; + + if ((ret = av_reallocp_array(&s->slice, s->cu_height, sizeof(s->slice[0]))) < 0) + return ret; + + if ((ret = av_reallocp_array(&s->pu_info, s->pu_stride * (s->cu_height << 3), sizeof(s->pu_info[0]))) < 0) + return ret; + + if ((ret = av_reallocp_array(&s->blk_info, s->blk_stride * (s->cu_height << 4), sizeof(s->blk_info[0]))) < 0) + return ret; + + memset(s->pu_info, 0, s->pu_stride * (s->cu_height << 3) * sizeof(s->pu_info[0])); + memset(s->blk_info, 0, s->blk_stride * (s->cu_height << 4) * sizeof(s->blk_info[0])); + + for (int j = 0; j < s->cu_height << 4; j++) + for (int i = 0; i < s->cu_width << 4; i++) + s->blk_info[j*s->blk_stride + i].mv.mvref = MVREF_NONE; + + if (s->deblock) { + int size; + + s->dblk_stride = s->awidth >> 2; + + size = s->dblk_stride * (s->aheight >> 2); + + if ((ret = av_reallocp_array(&s->top_str, size, sizeof(s->top_str[0]))) < 0) + return ret; + + if ((ret = av_reallocp_array(&s->left_str, size, sizeof(s->left_str[0]))) < 0) + return ret; + + memset(s->top_str, 0, size); + memset(s->left_str, 0, size); + } + + return 0; +} + +static int read_code012(GetBitContext * gb) +{ + if (!get_bits1(gb)) + return 0; + return get_bits1(gb) + 1; +} + +static int read_frame_header(RV60Context *s, GetBitContext *gb, int * width, int * height) +{ + if (get_bits(gb, 2) != 3) + return AVERROR_INVALIDDATA; + + skip_bits(gb, 2); + skip_bits(gb, 4); + + s->pict_type = frame_types[get_bits(gb, 2)]; + if (s->pict_type == AV_PICTURE_TYPE_NONE) + return AVERROR_INVALIDDATA; + + s->qp = get_bits(gb, 6); + skip_bits1(gb); + skip_bits(gb, 2); + s->osvquant = get_bits(gb, 2); + skip_bits1(gb); + skip_bits(gb, 2); + s->ts = get_bits(gb, 24); + *width = (get_bits(gb, 11) + 1) * 4; + *height = get_bits(gb, 11) * 4; + skip_bits1(gb); + if (s->pict_type == AV_PICTURE_TYPE_I) { + s->two_f_refs = 0; + } else { + if (get_bits1(gb)) + skip_bits(gb, 3); + s->two_f_refs = get_bits1(gb); + } + read_code012(gb); + read_code012(gb); + s->qp_off_type = read_code012(gb); + s->deblock = get_bits1(gb); + s->deblock_chroma = s->deblock && !get_bits1(gb); + + if (get_bits1(gb)) { + int count = get_bits(gb, 2); + if (count) { + skip_bits(gb, 2); + for (int i = 0; i < count; i++) + for (int j = 0; j < 2 << i; j++) + skip_bits(gb, 8); + } + } + + return 0; +} + +static int read_slice_sizes(RV60Context *s, GetBitContext *gb) +{ + int nbits = get_bits(gb, 5) + 1; + int64_t last_size; + + for (int i = 0; i < s->cu_height; i++) + s->slice[i].sign = get_bits1(gb); + + s->slice[0].size = last_size = get_bits_long(gb, nbits); + + if (last_size < 0 || last_size > INT32_MAX) + return AVERROR_INVALIDDATA; + + for (int i = 1; i < s->cu_height; i++) { + int diff = get_bits_long(gb, nbits); + if (s->slice[i].sign) + last_size += diff; + else + last_size -= diff; + if (last_size <= 0 || last_size > INT32_MAX) + return AVERROR_INVALIDDATA; + s->slice[i].size = last_size; + } + + align_get_bits(gb); + return 0; +} + +static int read_intra_mode(GetBitContext * gb, int * param) +{ + if (get_bits1(gb)) { + *param = read_code012(gb); + return INTRAMODE_INDEX; + } else { + *param = get_bits(gb, 5); + return INTRAMODE_MODE; + } +} + +static int has_top_block(const RV60Context * s, int xpos, int ypos, int dx, int dy, int size) +{ + return ypos + dy && xpos + dx + size <= s->awidth; +} + +static int has_left_block(const RV60Context * s, int xpos, int ypos, int dx, int dy, int size) +{ + return xpos + dx && ypos + dy + size <= s->aheight; +} + +static int has_top_right_block(const RV60Context * s, int xpos, int ypos, int dx, int dy, int size) +{ + if (has_top_block(s, xpos, ypos, dx, dy, size * 2)) { + int cxpos = ((xpos + dx) & 63) >> ff_log2(size); + int cypos = ((ypos + dy) & 63) >> ff_log2(size); + return !(rv60_avail_mask[cxpos] & cypos); + } + return 0; +} + +static int has_left_down_block(const RV60Context * s, int xpos, int ypos, int dx, int dy, int size) +{ + if (has_left_block(s, xpos, ypos, dx, dy, size * 2)) { + int cxpos = (~(xpos + dx) & 63) >> ff_log2(size); + int cypos = (~(ypos + dy) & 63) >> ff_log2(size); + return rv60_avail_mask[cxpos] & cypos; + } + return 0; +} + +typedef struct { + uint8_t t[129]; + uint8_t l[129]; + int has_t; + int has_tr; + int has_l; + int has_ld; +} IntraPredContext; + +typedef struct { + int xpos; + int ypos; + int pu_pos; + int blk_pos; + + enum CUType cu_type; + enum PUType pu_type; + enum IntraMode imode[4]; + int imode_param[4]; + MVInfo mv[4]; + + IntraPredContext ipred; +} CUContext; + +static void ipred_init(IntraPredContext * i) +{ + memset(i->t, 0x80, sizeof(i->t)); + memset(i->l, 0x80, sizeof(i->l)); + i->has_t = i->has_tr = i->has_l = i->has_ld = 0; +} + +static void populate_ipred(const RV60Context * s, CUContext * cu, const uint8_t * src, int stride, int xoff, int yoff, int size, int is_luma) +{ + if (is_luma) + src += (cu->ypos + yoff) * stride + cu->xpos + xoff; + else + src += (cu->ypos >> 1) * stride + (cu->xpos >> 1); + + ipred_init(&cu->ipred); + + if (cu->ypos + yoff > 0) { + cu->ipred.has_t = 1; + + memcpy(cu->ipred.t + 1, src - stride, size); + + if ((is_luma && has_top_right_block(s, cu->xpos, cu->ypos, xoff, yoff, size)) || + (!is_luma && has_top_right_block(s, cu->xpos, cu->ypos, 0, 0, size << 1))) { + cu->ipred.has_tr = 1; + memcpy(cu->ipred.t + size + 1, src - stride + size, size); + } else + memset(cu->ipred.t + size + 1, cu->ipred.t[size], size); + + if (cu->xpos + xoff > 0) + cu->ipred.t[0] = src[-stride - 1]; + } + + if (cu->xpos + xoff > 0) { + cu->ipred.has_l = 1; + + for (int y = 0; y < size; y++) + cu->ipred.l[y + 1] = src[y*stride - 1]; + + if ((is_luma && has_left_down_block(s, cu->xpos, cu->ypos, xoff, yoff, size)) || + (!is_luma && has_left_down_block(s, cu->xpos, cu->ypos, 0, 0, size << 1))) { + cu->ipred.has_ld = 1; + for (int y = size; y < size * 2; y++) + cu->ipred.l[y + 1] = src[y*stride - 1]; + } else + memset(cu->ipred.l + size + 1, cu->ipred.l[size], size); + + if (cu->ypos + yoff > 0) + cu->ipred.l[0] = src[-stride - 1]; + } +} + +static void pred_plane(const IntraPredContext * p, uint8_t * dst, int stride, int size) +{ + int lastl = p->l[size + 1]; + int lastt = p->t[size + 1]; + int tmp1[64], tmp2[64]; + int top_ref[64], left_ref[64]; + int shift; + + for (int i = 0; i < size; i++) { + tmp1[i] = lastl - p->t[i + 1]; + tmp2[i] = lastt - p->l[i + 1]; + } + + shift = ff_log2(size) + 1; + for (int i = 0; i < size; i++) { + top_ref[i] = p->t[i + 1] << (shift - 1); + left_ref[i] = p->l[i + 1] << (shift - 1); + } + + for (int y = 0; y < size; y++) { + int add = tmp2[y]; + int sum = left_ref[y] + size; + for (int x = 0; x < size; x++) { + int v = tmp1[x] + top_ref[x]; + sum += add; + top_ref[x] = v; + dst[y*stride + x] = (sum + v) >> shift; + } + } +} + +static void pred_dc(const IntraPredContext * p, uint8_t * dst, int stride, int size, int filter) +{ + int dc; + + if (!p->has_t && !p->has_l) + dc = 0x80; + else { + int sum = 0; + if (p->has_t) + for (int x = 0; x < size; x++) + sum += p->t[x + 1]; + if (p->has_l) + for (int y = 0; y < size; y++) + sum += p->l[y + 1]; + if (p->has_t && p->has_l) + dc = (sum + size) / (size * 2); + else + dc = (sum + size / 2) / size; + } + + for (int y = 0; y < size; y++) + memset(dst + y*stride, dc, size); + + if (filter && p->has_t && p->has_l) { + dst[0] = (p->t[1] + p->l[1] + 2 * dst[0] + 2) >> 2; + for (int x = 1; x < size; x++) + dst[x] = (p->t[x + 1] + 3 * dst[x] + 2) >> 2; + for (int y = 1; y < size; y++) + dst[y*stride] = (p->l[y + 1] + 3 * dst[y*stride] + 2) >> 2; + } +} + +static void filter_weak(uint8_t * dst, const uint8_t * src, int size) +{ + dst[0] = src[0]; + for (int i = 1; i < size - 1; i++) + dst[i] = (src[i - 1] + 2*src[i] + src[i + 1] + 2) >> 2; + dst[size - 1] = src[size - 1]; +} + +static void filter_bilin32(uint8_t * dst, int v0, int v1, int size) +{ + int diff = v1 - v0; + int sum = (v0 << 5) + (1 << (5 - 1)); + for (int i = 0; i < size; i++) { + dst[i] = sum >> 5; + sum += diff; + } +} + +static void pred_hor_angle(uint8_t * dst, int stride, int size, int weight, const uint8_t * src) +{ + int sum = 0; + for (int x = 0; x < size; x++) { + int off, frac; + sum += weight; + off = (sum >> 5) + 32; + frac = sum & 0x1F; + if (!frac) + for (int y = 0; y < size; y++) + dst[y*stride + x] = src[off + y]; + else { + for (int y = 0; y < size; y++) { + int a = src[off + y]; + int b = src[off + y + 1]; + dst[y*stride + x] = ((32 - frac) * a + frac * b + 16) >> 5; + } + } + } +} + +static void pred_ver_angle(uint8_t * dst, int stride, int size, int weight, const uint8_t * src) +{ + int sum = 0; + for (int y = 0; y < size; y++) { + int off, frac; + sum += weight; + off = (sum >> 5) + 32; + frac = sum & 0x1F; + if (!frac) + memcpy(dst + y*stride, src + off, size); + else { + for (int x = 0; x < size; x++) { + int a = src[off + x]; + int b = src[off + x + 1]; + dst[y*stride + x] = ((32 - frac) * a + frac * b + 16) >> 5; + } + } + } +} + +static int pred_angle(const IntraPredContext * p, uint8_t * dst, int stride, int size, int imode, int filter) +{ + uint8_t filtered1[96], filtered2[96]; + + if (!imode) { + pred_plane(p, dst, stride, size); + } else if (imode == 1) { + pred_dc(p, dst, stride, size, filter); + } else if (imode <= 9) { + int ang_weight = rv60_ipred_angle[10 - imode]; + int add_size = (size * ang_weight + 31) >> 5; + if (size <= 16) { + filter_weak(filtered1 + 32, &p->l[1], size + add_size); + } else { + filter_bilin32(filtered1 + 32, p->l[1], p->l[33], 32); + filter_bilin32(filtered1 + 64, p->l[32], p->l[64], add_size); + } + pred_hor_angle(dst, stride, size, ang_weight, filtered1); + } else if (imode == 10) { + if (size <= 16) + filter_weak(filtered1 + 32, &p->l[1], size); + else + filter_bilin32(filtered1 + 32, p->l[1], p->l[33], 32); + for (int y = 0; y < size; y++) + for (int x = 0; x < size; x++) + dst[y*stride + x] = filtered1[32 + y]; + if (filter) { + int tl = p->t[0]; + for (int x = 0; x < size; x++) + dst[x] = av_clip_uint8(dst[x] + ((p->t[x + 1] - tl) >> 1)); + } + } else if (imode <= 17) { + int ang_weight = rv60_ipred_angle[imode - 10]; + int inv_angle = rv60_ipred_inv_angle[imode - 10]; + int add_size = (size * ang_weight + 31) >> 5; + if (size <= 16) { + memcpy(filtered1 + 32 - 1, p->l, size + 1); + memcpy(filtered2 + 32 - 1, p->t, size + 1); + } else { + filtered1[32 - 1] = p->l[0]; + filter_bilin32(filtered1 + 32, p->l[0], p->l[32], 32); + filtered2[32 - 1] = p->t[0]; + filter_bilin32(filtered2 + 32, p->t[0], p->t[32], 32); + } + if (add_size > 1) { + int sum = 0x80; + for (int i = 1; i < add_size; i++) { + sum += inv_angle; + filtered1[32 - 1 - i] = filtered2[32 - 1 + (sum >> 8)]; + } + } + pred_hor_angle(dst, stride, size, -ang_weight, filtered1); + } else if (imode <= 25) { + int ang_weight = rv60_ipred_angle[26 - imode]; + int inv_angle = rv60_ipred_inv_angle[26 - imode]; + int add_size = (size * ang_weight + 31) >> 5; + if (size <= 16) { + memcpy(filtered1 + 32 - 1, p->t, size + 1); + memcpy(filtered2 + 32 - 1, p->l, size + 1); + } else { + filtered1[32 - 1] = p->t[0]; + filter_bilin32(filtered1 + 32, p->t[0], p->t[32], 32); + filtered2[32 - 1] = p->l[0]; + filter_bilin32(filtered2 + 32, p->l[0], p->l[32], 32); + } + if (add_size > 1) { + int sum = 0x80; + for (int i = 1; i < add_size; i++) { + sum += inv_angle; + filtered1[32 - 1 - i] = filtered2[32 - 1 + (sum >> 8)]; + } + } + pred_ver_angle(dst, stride, size, -ang_weight, filtered1); + } else if (imode == 26) { + if (size <= 16) + filter_weak(&filtered1[32], &p->t[1], size); + else + filter_bilin32(filtered1 + 32, p->t[1], p->t[33], 32); + for (int i = 0; i < size; i++) + memcpy(dst + i*stride, filtered1 + 32, size); + if (filter) { + int tl = p->l[0]; + for (int y = 0; y < size; y++) + dst[y*stride] = av_clip_uint8(dst[y*stride] + ((p->l[y+1] - tl) >> 1)); + } + } else if (imode <= 34) { + int ang_weight = rv60_ipred_angle[imode - 26]; + int add_size = (size * ang_weight + 31) >> 5; + if (size <= 16) + filter_weak(&filtered1[32], &p->t[1], size + add_size); + else { + filter_bilin32(filtered1 + 32, p->t[1], p->t[33], 32); + filter_bilin32(filtered1 + 64, p->t[32], p->t[64], add_size); + } + pred_ver_angle(dst, stride, size, ang_weight, filtered1); + } else + return AVERROR_INVALIDDATA; + return 0; +} + +static int pu_is_intra(const PUInfo * pu) +{ + return pu->cu_type == CU_INTRA; +} + +static int ipm_compar(const void * a, const void * b) +{ + return *(const enum IntraMode *)a - *(const enum IntraMode *)b; +} + +#define MK_UNIQUELIST(name, type, max_size) \ +typedef struct { \ + type list[max_size]; \ + int size; \ +} unique_list_##name; \ +\ +static void unique_list_##name##_init(unique_list_##name * s) \ +{ \ + memset(s->list, 0, sizeof(s->list)); \ + s->size = 0; \ +} \ +\ +static void unique_list_##name##_add(unique_list_##name * s, type cand) \ +{ \ + if (s->size == max_size) \ + return; \ + \ + for (int i = 0; i < s->size; i++) { \ + if (!memcmp(&s->list[i], &cand, sizeof(type))) { \ + return; \ + } \ + } \ + s->list[s->size++] = cand; \ +} + +MK_UNIQUELIST(intramode, enum IntraMode, 3) +MK_UNIQUELIST(mvinfo, MVInfo, 4) + +static int reconstruct_intra(const RV60Context * s, const CUContext * cu, int size, int sub) +{ + int blk_pos, tl_x, tl_y; + unique_list_intramode ipm_cand; + + if (cu->imode[0] == INTRAMODE_DC64) + return 1; + + if (cu->imode[0] == INTRAMODE_PLANE64) + return 0; + + unique_list_intramode_init(&ipm_cand); + + if (has_top_block(s, cu->xpos, cu->ypos, (sub & 1) * 4, 0, size)) { + const PUInfo * pu = &s->pu_info[cu->pu_pos - s->pu_stride]; + if (pu_is_intra(pu)) + unique_list_intramode_add(&ipm_cand, s->blk_info[cu->blk_pos - s->blk_stride + (sub & 1)].imode); + } + + blk_pos = cu->blk_pos + (sub >> 1) * s->blk_stride + (sub & 1); + + if (has_left_block(s, cu->xpos, cu->ypos, 0, (sub & 2) * 2, size)) { + const PUInfo * pu = &s->pu_info[cu->pu_pos - 1]; + if (pu_is_intra(pu)) + unique_list_intramode_add(&ipm_cand, s->blk_info[blk_pos - 1 - (sub & 1)].imode); + } + + tl_x = !(sub & 2) ? (cu->xpos + (sub & 1) * 4) : cu->xpos; + tl_y = cu->ypos + (sub & 2) * 4; + if (tl_x > 0 && tl_y > 0) { + const PUInfo * pu; + switch (sub) { + case 0: pu = &s->pu_info[cu->pu_pos - s->pu_stride - 1]; break; + case 1: pu = &s->pu_info[cu->pu_pos - s->pu_stride]; break; + default: pu = &s->pu_info[cu->pu_pos - 1]; + } + if (pu_is_intra(pu)) { + if (sub != 3) + unique_list_intramode_add(&ipm_cand, s->blk_info[blk_pos - s->blk_stride - 1].imode); + else + unique_list_intramode_add(&ipm_cand, s->blk_info[blk_pos - s->blk_stride - 2].imode); + } + } + + for (int i = 0; i < FF_ARRAY_ELEMS(rv60_candidate_intra_angles); i++) + unique_list_intramode_add(&ipm_cand, rv60_candidate_intra_angles[i]); + + if (cu->imode[sub] == INTRAMODE_INDEX) + return ipm_cand.list[cu->imode_param[sub]]; + + if (cu->imode[sub] == INTRAMODE_MODE) { + enum IntraMode imode = cu->imode_param[sub]; + qsort(ipm_cand.list, 3, sizeof(ipm_cand.list[0]), ipm_compar); + for (int i = 0; i < 3; i++) + if (imode >= ipm_cand.list[i]) + imode++; + return imode; + } + + av_assert0(0); // should never reach here + return 0; +} + +static int get_skip_mv_index(enum MVRefEnum mvref) +{ + switch (mvref) { + case MVREF_SKIP1: return 1; + case MVREF_SKIP2: return 2; + case MVREF_SKIP3: return 3; + default: return 0; + } +} + +static void add_if_valid(unique_list_mvinfo * skip_cand, const MVInfo * mvi) +{ + if (mvi->mvref != MVREF_NONE) + unique_list_mvinfo_add(skip_cand, *mvi); +} + +static void fill_mv_skip_cand(RV60Context * s, const CUContext * cu, unique_list_mvinfo * skip_cand, int size) +{ + int mv_size = size >> 2; + + if (cu->xpos) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos - 1].mv); + if (cu->ypos) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos - s->blk_stride].mv); + if (cu->ypos && cu->xpos + size < s->awidth) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos - s->blk_stride + mv_size].mv); + if (cu->xpos && cu->ypos + size < s->aheight) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos + s->blk_stride * mv_size - 1].mv); + if (cu->xpos) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos + s->blk_stride * (mv_size - 1) - 1].mv); + if (cu->ypos) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos - s->blk_stride + mv_size - 1].mv); + if (cu->xpos && cu->ypos) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos - s->blk_stride - 1].mv); + + for (int i = skip_cand->size; i < 4; i++) + skip_cand->list[i] = (MVInfo){.mvref=MVREF_REF0,.f_mv={0,0},.b_mv={0,0}}; +} + +typedef struct { + int w, h; +} Dimensions; + +static void get_mv_dimensions(Dimensions * dim, enum PUType pu_type, int part_no, int size) +{ + int mv_size = size >> 2; + switch (pu_type) { + case PU_FULL: + dim->w = dim->h = mv_size; + break; + case PU_N2HOR: + dim->w = mv_size; + dim->h = mv_size >> 1; + break; + case PU_N2VER: + dim->w = mv_size >> 1; + dim->h = mv_size; + break; + case PU_QUARTERS: + dim->w = dim->h = mv_size >> 1; + break; + case PU_N4HOR: + dim->w = mv_size; + dim->h = !part_no ? (mv_size >> 2) : ((3 * mv_size) >> 2); + break; + case PU_N34HOR: + dim->w = mv_size; + dim->h = !part_no ? ((3 * mv_size) >> 2) : (mv_size >> 2); + break; + case PU_N4VER: + dim->w = !part_no ? (mv_size >> 2) : ((3 * mv_size) >> 2); + dim->h = mv_size; + break; + case PU_N34VER: + dim->w = !part_no ? ((3 * mv_size) >> 2) : (mv_size >> 2); + dim->h = mv_size; + break; + } +} + +static int has_hor_split(enum PUType pu_type) +{ + return pu_type == PU_N2HOR || pu_type == PU_N4HOR || pu_type == PU_N34HOR || pu_type == PU_QUARTERS; +} + +static int has_ver_split(enum PUType pu_type) +{ + return pu_type == PU_N2VER || pu_type == PU_N4VER || pu_type == PU_N34VER || pu_type == PU_QUARTERS; +} + +static int pu_type_num_parts(enum PUType pu_type) +{ + switch (pu_type) { + case PU_FULL: return 1; + case PU_QUARTERS: return 4; + default: return 2; + } +} + +static void get_next_mv(const RV60Context * s, const Dimensions * dim, enum PUType pu_type, int part_no, int * mv_pos, int * mv_x, int * mv_y) +{ + if (pu_type == PU_QUARTERS) { + if (part_no != 1) { + *mv_pos += dim->w; + *mv_x += dim->w; + } else { + *mv_pos += dim->h*s->blk_stride - dim->w; + *mv_x -= dim->w; + *mv_y += dim->h; + } + } else if (has_hor_split(pu_type)) { + *mv_pos += dim->h * s->blk_stride; + *mv_y += dim->h; + } else if (has_ver_split(pu_type)) { + *mv_pos += dim->w; + *mv_x += dim->w; + } +} + +static int mv_is_ref0(enum MVRefEnum mvref) +{ + return mvref == MVREF_REF0 || mvref == MVREF_REF0ANDBREF; +} + +static int mv_is_forward(enum MVRefEnum mvref) +{ + return mvref == MVREF_REF0 || mvref == MVREF_REF1 || mvref == MVREF_REF0ANDBREF; +} + +static int mv_is_backward(enum MVRefEnum mvref) +{ + return mvref == MVREF_BREF || mvref == MVREF_REF0ANDBREF; +} + +static int mvinfo_matches_forward(const MVInfo * a, const MVInfo * b) +{ + return a->mvref == b->mvref || (mv_is_ref0(a->mvref) && mv_is_ref0(b->mvref)); +} + +static int mvinfo_matches_backward(const MVInfo * a, const MVInfo * b) +{ + return mv_is_backward(a->mvref) && mv_is_backward(b->mvref); +} + +static int mvinfo_is_deblock_cand(const MVInfo * a, const MVInfo * b) +{ + int diff; + + if (a->mvref != b->mvref) + return 1; + + diff = 0; + if (mv_is_forward(a->mvref)) { + int dx = a->f_mv.x - b->f_mv.x; + int dy = a->f_mv.y - b->f_mv.y; + diff += FFABS(dx) + FFABS(dy); + } + if (mv_is_backward(a->mvref)) { + int dx = a->b_mv.x - b->b_mv.x; + int dy = a->b_mv.y - b->b_mv.y; + diff += FFABS(dx) + FFABS(dy); + } + return diff > 4; +} + +static void mv_pred(MV * ret, MV a, MV b, MV c) +{ +#define MEDIAN(x) \ + if (a.x < b.x) \ + if (b.x < c.x) \ + ret->x = b.x; \ + else \ + ret->x = a.x < c.x ? c.x : a.x; \ + else \ + if (b.x < c.x) \ + ret->x = a.x < c.x ? a.x : c.x; \ + else \ + ret->x = b.x; \ + + MEDIAN(x) + MEDIAN(y) +} + +static void predict_mv(const RV60Context * s, MVInfo * dst, int mv_x, int mv_y, int mv_w, const MVInfo * src) +{ + int mv_pos = mv_y * s->blk_stride + mv_x; + MV f_mv, b_mv; + + dst->mvref = src->mvref; + + if (mv_is_forward(src->mvref)) { + MV cand[3] = {0}; + int cand_size = 0; + if (mv_x > 0) { + const MVInfo * mv = &s->blk_info[mv_pos - 1].mv; + if (mvinfo_matches_forward(mv, src)) + cand[cand_size++] = mv->f_mv; + } + if (mv_y > 0) { + const MVInfo * mv = &s->blk_info[mv_pos - s->blk_stride].mv; + if (mvinfo_matches_forward(mv, src)) + cand[cand_size++] = mv->f_mv; + } + if (has_top_block(s, mv_x << 2, mv_y << 2, mv_w << 2, 0, 4)) { + const MVInfo * mv = &s->blk_info[mv_pos - s->blk_stride + mv_w].mv; + if (mvinfo_matches_forward(mv, src)) + cand[cand_size++] = mv->f_mv; + } + + switch (cand_size) { + case 1: + f_mv.x = cand[0].x; + f_mv.y = cand[0].y; + break; + case 2: + f_mv.x = (cand[0].x + cand[1].x) >> 1; + f_mv.y = (cand[0].y + cand[1].y) >> 1; + break; + case 3: + mv_pred(&f_mv, cand[0], cand[1], cand[2]); + break; + default: + f_mv = (MV){0,0}; + break; + } + } else { + f_mv = (MV){0,0}; + } + + dst->f_mv.x = src->f_mv.x + f_mv.x; + dst->f_mv.y = src->f_mv.y + f_mv.y; + + if (mv_is_backward(src->mvref)) { + MV cand[3] = {0}; + int cand_size = 0; + if (mv_x > 0) { + const MVInfo * mv = &s->blk_info[mv_pos - 1].mv; + if (mvinfo_matches_backward(mv, src)) + cand[cand_size++] = mv->b_mv; + } + if (mv_y > 0) { + const MVInfo * mv = &s->blk_info[mv_pos - s->blk_stride].mv; + if (mvinfo_matches_backward(mv, src)) + cand[cand_size++] = mv->b_mv; + } + if (has_top_block(s, mv_x << 2, mv_y << 2, mv_w << 2, 0, 4)) { + const MVInfo * mv = &s->blk_info[mv_pos - s->blk_stride + mv_w].mv; + if (mvinfo_matches_backward(mv, src)) + cand[cand_size++] = mv->b_mv; + } + + switch (cand_size) { + case 1: + b_mv.x = cand[0].x; + b_mv.y = cand[0].y; + break; + case 2: + b_mv.x = (cand[0].x + cand[1].x) >> 1; + b_mv.y = (cand[0].y + cand[1].y) >> 1; + break; + case 3: + mv_pred(&b_mv, cand[0], cand[1], cand[2]); + break; + default: + b_mv = (MV){0,0}; + break; + } + } else { + b_mv = (MV){0,0}; + } + + dst->b_mv.x = src->b_mv.x + b_mv.x; + dst->b_mv.y = src->b_mv.y + b_mv.y; +} + +static void reconstruct(RV60Context * s, const CUContext * cu, int size) +{ + int pu_size = size >> 3; + PUInfo pui; + int imode, mv_x, mv_y, mv_pos, count, mv_size; + unique_list_mvinfo skip_cand; + Dimensions dim; + MVInfo mv; + + pui.cu_type = cu->cu_type; + pui.pu_type = cu->pu_type; + + if (cu->cu_type == CU_INTRA && cu->pu_type == PU_QUARTERS) { + s->pu_info[cu->pu_pos] = pui; + for (int y = 0; y < 2; y++) + for (int x = 0; x < 2; x++) + s->blk_info[cu->blk_pos + y*s->blk_stride + x].imode = + reconstruct_intra(s, cu, 4, y*2 + x); + return; + } + + switch (cu->cu_type) { + case CU_INTRA: + imode = reconstruct_intra(s, cu, size, 0); + for (int y = 0; y < size >> 2; y++) + for (int x = 0; x < size >> 2; x++) + s->blk_info[cu->blk_pos + y*s->blk_stride + x].imode = imode; + break; + case CU_INTER_MV: + mv_x = cu->xpos >> 2; + mv_y = cu->ypos >> 2; + mv_pos = cu->blk_pos; + count = pu_type_num_parts(cu->pu_type); + for (int part_no = 0; part_no < count; part_no++) { + MVInfo mv; + get_mv_dimensions(&dim, cu->pu_type, part_no, size); + predict_mv(s, &mv, mv_x, mv_y, dim.w, &cu->mv[part_no]); + for (int y = 0; y < dim.h; y++) + for (int x = 0; x < dim.w; x++) + s->blk_info[mv_pos + y*s->blk_stride + x].mv = mv; + get_next_mv(s, &dim, cu->pu_type, part_no, &mv_pos, &mv_x, &mv_y); + } + break; + default: + unique_list_mvinfo_init(&skip_cand); + fill_mv_skip_cand(s, cu, &skip_cand, size); + mv = skip_cand.list[get_skip_mv_index(cu->mv[0].mvref)]; + mv_size = size >> 2; + for (int y = 0; y < mv_size; y++) + for (int x = 0; x < mv_size; x++) + s->blk_info[cu->blk_pos + y*s->blk_stride + x].mv = mv; + } + + for (int y = 0; y < pu_size; y++) + for (int x = 0; x < pu_size; x++) + s->pu_info[cu->pu_pos + y*s->pu_stride + x] = pui; +} + +static void read_mv(GetBitContext * gb, MV * mv) +{ + mv->x = get_interleaved_se_golomb(gb); + mv->y = get_interleaved_se_golomb(gb); +} + +static void read_mv_info(RV60Context *s, GetBitContext * gb, MVInfo * mvinfo, int size, enum PUType pu_type) +{ + if (s->pict_type != AV_PICTURE_TYPE_B) { + if (s->two_f_refs && get_bits1(gb)) + mvinfo->mvref = MVREF_REF1; + else + mvinfo->mvref = MVREF_REF0; + read_mv(gb, &mvinfo->f_mv); + mvinfo->b_mv.x = mvinfo->b_mv.y = 0; + } else { + if ((size <= 8 && (size != 8 || pu_type != PU_FULL)) || get_bits1(gb)) { + if (!get_bits1(gb)) { + mvinfo->mvref = MVREF_REF0; + read_mv(gb, &mvinfo->f_mv); + mvinfo->b_mv.x = mvinfo->b_mv.y = 0; + } else { + mvinfo->mvref = MVREF_BREF; + mvinfo->f_mv.x = mvinfo->f_mv.y = 0; + read_mv(gb, &mvinfo->b_mv); + } + } else { + mvinfo->mvref = MVREF_REF0ANDBREF; + read_mv(gb, &mvinfo->f_mv); + read_mv(gb, &mvinfo->b_mv); + } + } +} + +#define FILTER1(src, src_stride, src_y_ofs, step) \ + ( (src)[(y + src_y_ofs)*(src_stride) + x - 2*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x - 1*step] \ + +52 * (src)[(y + src_y_ofs)*(src_stride) + x ] \ + +20 * (src)[(y + src_y_ofs)*(src_stride) + x + 1*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x + 2*step] \ + + (src)[(y + src_y_ofs)*(src_stride) + x + 3*step] + 32) >> 6 + +#define FILTER2(src, src_stride, src_y_ofs, step) \ + ( (src)[(y + src_y_ofs)*(src_stride) + x - 2*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x - 1*step] \ + +20 * (src)[(y + src_y_ofs)*(src_stride) + x ] \ + +20 * (src)[(y + src_y_ofs)*(src_stride) + x + 1*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x + 2*step] \ + + (src)[(y + src_y_ofs)*(src_stride) + x + 3*step] + 16) >> 5 + +#define FILTER3(src, src_stride, src_y_ofs, step) \ + ( (src)[(y + src_y_ofs)*(src_stride) + x - 2*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x - 1*step] \ + +20 * (src)[(y + src_y_ofs)*(src_stride) + x ] \ + +52 * (src)[(y + src_y_ofs)*(src_stride) + x + 1*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x + 2*step] \ + + (src)[(y + src_y_ofs)*(src_stride) + x + 3*step] + 32) >> 6 + +#define FILTER_CASE(idx, dst, dst_stride, filter, w, h) \ + case idx: \ + for (int y = 0; y < h; y++) \ + for (int x = 0; x < w; x++) \ + (dst)[y*dst_stride + x] = av_clip_uint8(filter); \ + break; + +#define FILTER_BLOCK(dst, dst_stride, src, src_stride, src_y_ofs, w, h, cond, step) \ + switch (cond) { \ + FILTER_CASE(1, dst, dst_stride, FILTER1(src, src_stride, src_y_ofs, step), w, h) \ + FILTER_CASE(2, dst, dst_stride, FILTER2(src, src_stride, src_y_ofs, step), w, h) \ + FILTER_CASE(3, dst, dst_stride, FILTER3(src, src_stride, src_y_ofs, step), w, h) \ + } + +static void luma_mc(uint8_t * dst, int dst_stride, const uint8_t * src, int src_stride, int w, int h, int cx, int cy) +{ + if (!cx && !cy) { + for (int y = 0; y < h; y++) + memcpy(dst + y*dst_stride, src + y*src_stride, w); + } else if (!cy) { + FILTER_BLOCK(dst, dst_stride, src, src_stride, 0, w, h, cx, 1) + } else if (!cx) { + FILTER_BLOCK(dst, dst_stride, src, src_stride, 0, w, h, cy, src_stride) + } else if (cx != 3 || cy != 3) { + uint8_t tmp[70 * 64]; + FILTER_BLOCK(tmp, 64, src - src_stride * 2, src_stride, 0, w, h + 5, cx, 1) + FILTER_BLOCK(dst, dst_stride, tmp + 2*64, 64, 0, w, h, cy, 64) + } else { + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + dst[j*dst_stride + i] = ( + src[j*src_stride + i] + + src[j*src_stride + i + 1] + + src[(j + 1)*src_stride + i] + + src[(j + 1)*src_stride + i + 1] + 2) >> 2; + } +} + +static void chroma_mc(uint8_t * dst, int dst_stride, const uint8_t * src, int src_stride, int w, int h, int x, int y) +{ + if (!x && !y) { + for (int j = 0; j < h; j++) + memcpy(dst + j*dst_stride, src + j*src_stride, w); + } else if (x > 0 && y > 0) { + int a, b, c, d; + + if (x == 3 && y == 3) + y = 2; //reproduce bug in rv60 decoder. tested with realplayer version 18.1.7.344 and 22.0.0.321 + + a = (4 - x) * (4 - y); + b = x * (4 - y); + c = (4 - x) * y; + d = x * y; + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + dst[j*dst_stride + i] = + (a * src[j*src_stride + i] + + b * src[j*src_stride + i + 1] + + c * src[(j + 1)*src_stride + i] + + d * src[(j + 1)*src_stride + i + 1] + 8) >> 4; + } else { + int a = (4 - x) * (4 - y); + int e = x * (4 - y) + (4 - x) * y; + int step = y > 0 ? src_stride : 1; + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + dst[j*dst_stride + i] = + (a * src[j*src_stride + i] + + e * src[j*src_stride + i + step] + 8) >> 4; + } +} + +static int check_pos(int x, int y, int cw, int ch, int w, int h, int dx, int dy, int e0, int e1, int e2, int e3) +{ + int x2 = x + dx; + int y2 = y + dy; + return x2 - e0 >= 0 && x2 + cw + e1 <= w && y2 - e2 >= 0 && y2 + ch + e3 <= h; +} + +static void mc(RV60Context * s, uint8_t * frame_data[3], int frame_linesize[3], const AVFrame * ref, int x, int y, int w, int h, MV mv, int avg) +{ + { + int off = !avg ? y * frame_linesize[0] + x : 0; + int fw = s->awidth; + int fh = s->aheight; + int dx = mv.x >> 2; + int cx = mv.x & 3; + int dy = mv.y >> 2; + int cy = mv.y & 3; + + if (check_pos(x, y, w, h, fw, fh, dx, dy, rv60_edge1[cx], rv60_edge2[cx], rv60_edge1[cy], rv60_edge2[cy])) { + luma_mc( + frame_data[0] + off, + frame_linesize[0], + ref->data[0] + (y + dy) * ref->linesize[0] + x + dx, + ref->linesize[0], + w, h, cx, cy); + } else { + uint8_t buf[70*70]; + int xoff = x + dx - 2; + int yoff = y + dy - 2; + s->vdsp.emulated_edge_mc(buf, + ref->data[0] + yoff * ref->linesize[0] + xoff, + 70, ref->linesize[0], + w + 5, h + 5, + xoff, yoff, + fw, fh); + + luma_mc(frame_data[0] + off, frame_linesize[0], + buf + 70 * 2 + 2, 70, w, h, cx, cy); + } + } + { + int fw = s->awidth >> 1; + int fh = s->aheight >> 1; + int mvx = mv.x / 2; + int mvy = mv.y / 2; + int dx = mvx >> 2; + int cx = mvx & 3; + int dy = mvy >> 2; + int cy = mvy & 3; + int cw = w >> 1; + int ch = h >> 1; + + for (int plane = 1; plane < 3; plane++) { + int off = !avg ? (y >> 1) * frame_linesize[plane] + (x >> 1) : 0; + if (check_pos(x >> 1, y >> 1, cw, ch, fw, fh, dx, dy, 0, 1, 0, 1)) { + chroma_mc( + frame_data[plane] + off, + frame_linesize[plane], + ref->data[plane] + ((y >> 1) + dy) * ref->linesize[plane] + (x >> 1) + dx, + ref->linesize[plane], + cw, ch, cx, cy); + } else { + uint8_t buf[40*40]; + s->vdsp.emulated_edge_mc(buf, + ref->data[plane] + ((y >> 1) + dy) * ref->linesize[plane] + (x >> 1) + dx, + 40, ref->linesize[plane], + cw + 1, ch + 1, + (x >> 1) + dx, (y >> 1) + dy, + fw, fh); + chroma_mc(frame_data[plane] + off, frame_linesize[plane], buf, 40, cw, ch, cx, cy); + } + } + } +} + +static void avg_plane(uint8_t * dst, int dst_stride, const uint8_t * src, int src_stride, int w, int h) +{ + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + dst[j*dst_stride + i] = (dst[j*dst_stride + i] + src[j*src_stride + i]) >> 1; +} + +static void avg(AVFrame * frame, uint8_t * prev_frame_data[3], int prev_frame_linesize[3], int x, int y, int w, int h) +{ + for (int plane = 0; plane < 3; plane++) { + int shift = !plane ? 0 : 1; + avg_plane(frame->data[plane] + (y >> shift) * frame->linesize[plane] + (x >> shift), frame->linesize[plane], + prev_frame_data[plane], prev_frame_linesize[plane], + w >> shift, h >> shift); + } +} + +static int get_c4x4_set(int qp, int is_intra) +{ + if (is_intra) + return rv60_qp_to_idx[qp + 32]; + else + return rv60_qp_to_idx[qp]; +} + +static int quant(int v, int q) +{ + return (v * q + 8) >> 4; +} + +static int decode_coeff(GetBitContext * gb, const CoeffVLCs * vlcs, int inval, int val) +{ + int esc_sym; + + if (inval != val) + return inval && get_bits1(gb) ? -inval : inval; + + esc_sym = get_vlc2(gb, vlcs->esc, 9, 2); + if (esc_sym > 23) { + int esc_bits = esc_sym - 23; + val += (1 << esc_bits) + get_bits(gb, esc_bits) + 22; + } else + val += esc_sym; + + return get_bits1(gb) ? -val : val; +} + +static void decode_2x2_dc(GetBitContext * gb, const CoeffVLCs * vlcs, int16_t * coeffs, int stride, int block2, int dsc, int q_dc, int q_ac) +{ + const uint8_t * lx; + if (!dsc) + return; + + lx = rv60_dsc_to_lx[dsc - 1]; + + coeffs[0] = quant(decode_coeff(gb, vlcs, lx[0], 3), q_dc); + if (!block2) { + coeffs[1] = quant(decode_coeff(gb, vlcs, lx[1], 2), q_ac); + coeffs[stride] = quant(decode_coeff(gb, vlcs, lx[2], 2), q_ac); + } else { + coeffs[stride] = quant(decode_coeff(gb, vlcs, lx[1], 2), q_ac); + coeffs[1] = quant(decode_coeff(gb, vlcs, lx[2], 2), q_ac); + } + coeffs[stride + 1] = quant(decode_coeff(gb, vlcs, lx[3], 2), q_ac); +} + +static void decode_2x2(GetBitContext * gb, const CoeffVLCs * vlcs, int16_t * coeffs, int stride, int block2, int dsc, int q_ac) +{ + const uint8_t * lx; + if (!dsc) + return; + + lx = rv60_dsc_to_lx[dsc - 1]; + + coeffs[0] = quant(decode_coeff(gb, vlcs, lx[0], 3), q_ac); + if (!block2) { + coeffs[1] = quant(decode_coeff(gb, vlcs, lx[1], 2), q_ac); + coeffs[stride] = quant(decode_coeff(gb, vlcs, lx[2], 2), q_ac); + } else { + coeffs[stride] = quant(decode_coeff(gb, vlcs, lx[1], 2), q_ac); + coeffs[1] = quant(decode_coeff(gb, vlcs, lx[2], 2), q_ac); + } + coeffs[stride + 1] = quant(decode_coeff(gb, vlcs, lx[3], 2), q_ac); +} + +static void decode_4x4_block_dc(GetBitContext * gb, const CoeffVLCs * vlcs, int is_luma, int16_t * coeffs, int stride, int q_dc, int q_ac) +{ + int sym0 = get_vlc2(gb, vlcs->l0[!is_luma], 9, 2); + int grp0 = sym0 >> 3; + + if (grp0) + decode_2x2_dc(gb, vlcs, coeffs, stride, 0, grp0, q_dc, q_ac); + + if (sym0 & 4) { + int grp = get_vlc2(gb, vlcs->l12[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2, stride, 0, grp, q_ac); + } + if (sym0 & 2) { + int grp = get_vlc2(gb, vlcs->l12[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2*stride, stride, 1, grp, q_ac); + } + if (sym0 & 1) { + int grp = get_vlc2(gb, vlcs->l3[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2*stride + 2, stride, 0, grp, q_ac); + } +} + +static void decode_4x4_block(GetBitContext * gb, const CoeffVLCs * vlcs, int is_luma, int16_t * coeffs, int stride, int q_ac) +{ + int sym0 = get_vlc2(gb, vlcs->l0[!is_luma], 9, 2); + int grp0 = (sym0 >> 3); + + if (grp0) + decode_2x2(gb, vlcs, coeffs, stride, 0, grp0, q_ac); + + if (sym0 & 4) { + int grp = get_vlc2(gb, vlcs->l12[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2, stride, 0, grp, q_ac); + } + if (sym0 & 2) { + int grp = get_vlc2(gb, vlcs->l12[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2*stride, stride, 1, grp, q_ac); + } + if (sym0 & 1) { + int grp = get_vlc2(gb, vlcs->l3[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2*stride + 2, stride, 0, grp, q_ac); + } +} + +static void decode_cu_4x4in16x16(GetBitContext * gb, int is_intra, int qp, int sel_qp, int16_t * y_coeffs, int16_t * u_coeffs, int16_t * v_coeffs, int cbp) +{ + int cb_set = get_c4x4_set(sel_qp, is_intra); + const CoeffVLCs * vlc = is_intra ? &intra_coeff_vlc[cb_set] : &inter_coeff_vlc[cb_set]; + int q_y = rv60_quants_b[qp]; + int q_c_dc = rv60_quants_b[rv60_chroma_quant_dc[qp]]; + int q_c_ac = rv60_quants_b[rv60_chroma_quant_ac[qp]]; + + memset(y_coeffs, 0, sizeof(y_coeffs[0])*256); + for (int i = 0; i < 16; i++) + if ((cbp >> i) & 1) + decode_4x4_block(gb, vlc, 1, y_coeffs + i * 16 , 4, q_y); + + memset(u_coeffs, 0, sizeof(u_coeffs[0])*64); + for (int i = 0; i < 4; i++) + if ((cbp >> (16 + i)) & 1) + decode_4x4_block_dc(gb, vlc, 0, u_coeffs + i * 16, 4, q_c_dc, q_c_ac); + + memset(v_coeffs, 0, sizeof(v_coeffs[0])*64); + for (int i = 0; i < 4; i++) + if ((cbp >> (20 + i)) & 1) + decode_4x4_block_dc(gb, vlc, 0, v_coeffs + i * 16, 4, q_c_dc, q_c_ac); +} + +static int decode_cbp8(GetBitContext * gb, int subset, int qp) +{ + int cb_set = rv60_qp_to_idx[qp]; + return get_vlc2(gb, cbp8_vlc[cb_set][subset], 9, 2); +} + +static void decode_cu_8x8(GetBitContext * gb, int is_intra, int qp, int sel_qp, int16_t * y_coeffs, int16_t * u_coeffs, int16_t * v_coeffs, int ccbp, int mode4x4) +{ + int cb_set = get_c4x4_set(sel_qp, is_intra); + const CoeffVLCs * vlc = is_intra ? &intra_coeff_vlc[cb_set] : &inter_coeff_vlc[cb_set]; + int q_y = rv60_quants_b[qp]; + int q_c_dc = rv60_quants_b[rv60_chroma_quant_dc[qp]]; + int q_c_ac = rv60_quants_b[rv60_chroma_quant_ac[qp]]; + + memset(y_coeffs, 0, sizeof(y_coeffs[0])*64); + for (int i = 0; i < 4; i++) { + if ((ccbp >> i) & 1) { + int offset, stride; + if (mode4x4) { + offset = i*16; + stride = 4; + } else { + offset = (i & 1) * 4 + (i & 2) * 2 * 8; + stride = 8; + } + decode_4x4_block(gb, vlc, 1, y_coeffs + offset, stride, q_y); + } + } + + if ((ccbp >> 4) & 1) { + memset(u_coeffs, 0, sizeof(u_coeffs[0])*16); + decode_4x4_block_dc(gb, vlc, 0, u_coeffs, 4, q_c_dc, q_c_ac); + } + + if ((ccbp >> 5) & 1) { + memset(v_coeffs, 0, sizeof(u_coeffs[0])*16); + decode_4x4_block_dc(gb, vlc, 0, v_coeffs, 4, q_c_dc, q_c_ac); + } +} + +static void decode_cu_16x16(GetBitContext * gb, int is_intra, int qp, int sel_qp, int16_t * y_coeffs, int16_t * u_coeffs, int16_t * v_coeffs, int ccbp) +{ + int cb_set = get_c4x4_set(sel_qp, is_intra); + const CoeffVLCs * vlc = is_intra ? &intra_coeff_vlc[cb_set] : &inter_coeff_vlc[cb_set]; + int q_y = rv60_quants_b[qp]; + int q_c_dc = rv60_quants_b[rv60_chroma_quant_dc[qp]]; + int q_c_ac = rv60_quants_b[rv60_chroma_quant_ac[qp]]; + + memset(y_coeffs, 0, sizeof(y_coeffs[0])*256); + for (int i = 0; i < 16; i++) + if ((ccbp >> i) & 1) { + int off = (i & 3) * 4 + (i >> 2) * 4 * 16; + decode_4x4_block(gb, vlc, 1, y_coeffs + off, 16, q_y); + } + + memset(u_coeffs, 0, sizeof(u_coeffs[0])*64); + for (int i = 0; i < 4; i++) + if ((ccbp >> (16 + i)) & 1) { + int off = (i & 1) * 4 + (i & 2) * 2 * 8; + if (!i) + decode_4x4_block_dc(gb, vlc, 0, u_coeffs + off, 8, q_c_dc, q_c_ac); + else + decode_4x4_block(gb, vlc, 0, u_coeffs + off, 8, q_c_ac); + } + + memset(v_coeffs, 0, sizeof(v_coeffs[0])*64); + for (int i = 0; i < 4; i++) + if ((ccbp >> (20 + i)) & 1) { + int off = (i & 1) * 4 + (i & 2) * 2 * 8; + if (!i) + decode_4x4_block_dc(gb, vlc, 0, v_coeffs + off, 8, q_c_dc, q_c_ac); + else + decode_4x4_block(gb, vlc, 0, v_coeffs + off, 8, q_c_ac); + } +} + +static int decode_super_cbp(GetBitContext * gb, const VLCElem * vlc[4]) +{ + int sym0 = get_vlc2(gb, vlc[0], 9, 2); + int sym1 = get_vlc2(gb, vlc[1], 9, 2); + int sym2 = get_vlc2(gb, vlc[2], 9, 2); + int sym3 = get_vlc2(gb, vlc[3], 9, 2); + return 0 + + ((sym0 & 0x03) << 0) + + ((sym0 & 0x0C) << 2) + + ((sym0 & 0x10) << 12) + + ((sym0 & 0x20) << 15) + + ((sym1 & 0x03) << 2) + + ((sym1 & 0x0C) << 4) + + ((sym1 & 0x10) << 13) + + ((sym1 & 0x20) << 16) + + ((sym2 & 0x03) << 8) + + ((sym2 & 0x0C) << 10) + + ((sym2 & 0x10) << 14) + + ((sym2 & 0x20) << 17) + + ((sym3 & 0x03) << 10) + + ((sym3 & 0x0C) << 12) + + ((sym3 & 0x10) << 15) + + ((sym3 & 0x20) << 18); +} + +static int decode_cbp16(GetBitContext * gb, int subset, int qp) +{ + int cb_set = rv60_qp_to_idx[qp]; + return decode_super_cbp(gb, cbp16_vlc[cb_set][subset]); +} + +static int decode_cu_r(RV60Context * s, AVFrame * frame, ThreadContext * thread, GetBitContext * gb, int xpos, int ypos, int log_size, int qp, int sel_qp) +{ + int size = 1 << log_size; + int split, ret, ttype, count, is_intra, cu_pos, subset, cbp8, imode, split_i4x4, num_clusters, cl_cbp, super_cbp, mv_x, mv_y, mv_pos; + int16_t y_coeffs[16*16], u_coeffs[8*8], v_coeffs[8*8]; + CUContext cu; + + if (xpos >= s->awidth || ypos >= s->aheight) + return 0; + + split = xpos + size > s->awidth || ypos + size > s->aheight || (size > 8 && get_bits1(gb)); + thread->cu_split[thread->cu_split_pos++] = split; + if (split) { + size >>= 1; + log_size -= 1; + if ((ret = decode_cu_r(s, frame, thread, gb, xpos, ypos, log_size, qp, sel_qp)) < 0 || + (ret = decode_cu_r(s, frame, thread, gb, xpos + size, ypos, log_size, qp, sel_qp)) < 0 || + (ret = decode_cu_r(s, frame, thread, gb, xpos, ypos + size, log_size, qp, sel_qp)) < 0 || + (ret = decode_cu_r(s, frame, thread, gb, xpos + size, ypos + size, log_size, qp, sel_qp)) < 0) + return ret; + return 0; + } + + cu.xpos = xpos; + cu.ypos = ypos; + cu.pu_pos = (xpos >> 3) + (ypos >> 3) * s->pu_stride; + cu.blk_pos = (xpos >> 2) + (ypos >> 2) * s->blk_stride; + cu.cu_type = s->pict_type != AV_PICTURE_TYPE_I ? get_bits(gb, 2) : CU_INTRA; + + switch (cu.cu_type) { + case CU_INTRA: + cu.pu_type = size == 8 && get_bits1(gb) ? PU_QUARTERS : PU_FULL; + if (cu.pu_type == PU_QUARTERS) + for (int i = 0; i < 4; i++) + cu.imode[i] = read_intra_mode(gb, &cu.imode_param[i]); + else if (size <= 32) + cu.imode[0] = read_intra_mode(gb, &cu.imode_param[0]); + else + cu.imode[0] = get_bits1(gb) ? INTRAMODE_PLANE64 : INTRAMODE_DC64; + break; + case CU_INTER_MV: + cu.pu_type = get_bits(gb, size == 8 ? 2 : 3); + count = pu_type_num_parts(cu.pu_type); + for (int i = 0; i < count; i++) + read_mv_info(s, gb, &cu.mv[i], size, cu.pu_type); + break; + default: + cu.pu_type = PU_FULL; + cu.mv[0].mvref = skip_mv_ref[get_unary(gb, 0, 3)]; + break; + } + + reconstruct(s, &cu, size); + + split_i4x4 = cu.cu_type == CU_INTRA && size == 8 && cu.pu_type == PU_QUARTERS; + + switch (cu.cu_type) { + case CU_INTRA: + imode = s->blk_info[cu.blk_pos].imode; + if (!split_i4x4) { + int off = ypos * frame->linesize[0] + xpos; + populate_ipred(s, &cu, frame->data[0], frame->linesize[0], 0, 0, size, 1); + if (pred_angle(&cu.ipred, frame->data[0] + off, frame->linesize[0], size, imode, 1) < 0) + return AVERROR_INVALIDDATA; + } + for (int plane = 1; plane < 3; plane++) { + int off = (ypos >> 1) * frame->linesize[plane] + (xpos >> 1); + populate_ipred(s, &cu, frame->data[plane], frame->linesize[plane], 0, 0, size >> 1, 0); + if (pred_angle(&cu.ipred, frame->data[plane] + off, frame->linesize[plane], size >> 1, imode, 0) < 0) + return AVERROR_INVALIDDATA; + } + break; + default: + mv_x = xpos >> 2; + mv_y = ypos >> 2; + mv_pos = mv_y * s->blk_stride + mv_x; + count = pu_type_num_parts(cu.pu_type); + for (int part_no = 0; part_no < count; part_no++) { + MVInfo mv; + Dimensions dim; + int bw, bh, bx, by; + + mv = s->blk_info[mv_pos].mv; + get_mv_dimensions(&dim, cu.pu_type, part_no, size); + bw = dim.w << 2; + bh = dim.h << 2; + bx = mv_x << 2; + by = mv_y << 2; + + if (!(mv.mvref & 2)) { + if (!s->last_frame[LAST_PIC]->data[0]) { + av_log(s->avctx, AV_LOG_ERROR, "missing reference frame\n"); + return AVERROR_INVALIDDATA; + } + } + if (mv.mvref & 6) { + if (!s->last_frame[NEXT_PIC]->data[0]) { + av_log(s->avctx, AV_LOG_ERROR, "missing reference frame\n"); + return AVERROR_INVALIDDATA; + } + } + + switch (mv.mvref) { + case MVREF_REF0: + mc(s, frame->data, frame->linesize, s->last_frame[LAST_PIC], bx, by, bw, bh, mv.f_mv, 0); + break; + case MVREF_REF1: + mc(s, frame->data, frame->linesize, s->last_frame[NEXT_PIC], bx, by, bw, bh, mv.f_mv, 0); + break; + case MVREF_BREF: + mc(s, frame->data, frame->linesize, s->last_frame[NEXT_PIC], bx, by, bw, bh, mv.b_mv, 0); + break; + case MVREF_REF0ANDBREF: + mc(s, frame->data, frame->linesize, s->last_frame[LAST_PIC], bx, by, bw, bh, mv.f_mv, 0); + mc(s, thread->avg_data, thread->avg_linesize, s->last_frame[NEXT_PIC], bx, by, bw, bh, mv.b_mv, 1); + avg(frame, thread->avg_data, thread->avg_linesize, bx, by, bw, bh); + break; + default: + av_assert0(0); //should never reach here + } + get_next_mv(s, &dim, cu.pu_type, part_no, &mv_pos, &mv_x, &mv_y); + } + break; + } + + if (cu.cu_type == CU_SKIP) + ttype = TRANSFORM_NONE; + else if (size >= 32) + ttype = TRANSFORM_16X16; + else if (size == 16) + ttype = cu.cu_type == CU_INTRA || cu.pu_type == PU_FULL ? TRANSFORM_16X16 : TRANSFORM_4X4; + else + ttype = cu.pu_type == PU_FULL ? TRANSFORM_8X8 : TRANSFORM_4X4; + + is_intra = cu.cu_type == CU_INTRA; + if (qp >= 32) + return AVERROR_INVALIDDATA; + cu_pos = ((xpos & 63) >> 3) + ((ypos & 63) >> 3) * 8; + + switch (ttype) { + case TRANSFORM_4X4: + subset = is_intra ? 0 : 2; + if (size == 16) { + int cbp16 = get_bits1(gb) ? decode_cbp16(gb, subset, sel_qp) : 0; + if (cbp16) { + decode_cu_4x4in16x16(gb, is_intra, qp, sel_qp, y_coeffs, u_coeffs, v_coeffs, cbp16); + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) { + int i = y*4 + x; + if ((cbp16 >> i) & 1) { + int off = (ypos + y * 4)*frame->linesize[0] + xpos + x * 4; + ff_rv60_idct4x4_add(y_coeffs + i*16, frame->data[0] + off, frame->linesize[0]); + thread->coded_blk[cu_pos + (y/2)*8 + (x/2)] = 1; + } + } + for (int y = 0; y < 2; y++) + for (int x = 0; x < 2; x++) { + int i = y * 2 + x; + int xoff = (xpos >> 1) + x * 4; + int yoff = (ypos >> 1) + y * 4; + if ((cbp16 >> (16 + i)) & 1) { + int off = yoff * frame->linesize[1] + xoff; + ff_rv60_idct4x4_add(u_coeffs + i * 16, frame->data[1] + off, frame->linesize[1]); + thread->coded_blk[cu_pos + y*8 + x] = 1; + } + if ((cbp16 >> (20 + i)) & 1) { + int off = yoff * frame->linesize[2] + xoff; + ff_rv60_idct4x4_add(v_coeffs + i * 16, frame->data[2] + off, frame->linesize[2]); + thread->coded_blk[cu_pos + y*8 + x] = 1; + } + } + } + } else { + cbp8 = decode_cbp8(gb, subset, sel_qp); + if (cbp8) { + thread->coded_blk[cu_pos] = 1; + decode_cu_8x8(gb, is_intra, qp, sel_qp, y_coeffs, u_coeffs, v_coeffs, cbp8, 1); + } + for (int i = 0; i < 4; i++) { + int xoff = (i & 1) << 2; + int yoff = (i & 2) << 1; + if (split_i4x4) { + int off = (ypos + yoff) * frame->linesize[0] + xpos + xoff; + int imode = s->blk_info[cu.blk_pos + (i >> 1) * s->blk_stride + (i & 1)].imode; + populate_ipred(s, &cu, frame->data[0], frame->linesize[0], xoff, yoff, 4, 1); + if (pred_angle(&cu.ipred, frame->data[0] + off, frame->linesize[0], 4, imode, 1) < 0) + return AVERROR_INVALIDDATA; + } + if ((cbp8 >> i) & 1) { + int off = (ypos + yoff) * frame->linesize[0] + xpos + xoff; + ff_rv60_idct4x4_add(y_coeffs + i * 16, frame->data[0] + off, frame->linesize[0]); + } + } + if ((cbp8 >> 4) & 1) { + int off = (ypos >> 1) * frame->linesize[1] + (xpos >> 1); + ff_rv60_idct4x4_add(u_coeffs, frame->data[1] + off, frame->linesize[1]); + } + if ((cbp8 >> 5) & 1) { + int off = (ypos >> 1) * frame->linesize[2] + (xpos >> 1); + ff_rv60_idct4x4_add(v_coeffs, frame->data[2] + off, frame->linesize[2]); + } + } + break; + case TRANSFORM_8X8: + subset = is_intra ? 1 : 3; + cbp8 = decode_cbp8(gb, subset, sel_qp); + if (cbp8) { + thread->coded_blk[cu_pos] = 1; + decode_cu_8x8(gb, is_intra, qp, sel_qp, y_coeffs, u_coeffs, v_coeffs, cbp8, 0); + if (cbp8 & 0xF) { + int off = ypos * frame->linesize[0] + xpos; + ff_rv60_idct8x8_add(y_coeffs, frame->data[0] + off, frame->linesize[0]); + } + if ((cbp8 >> 4) & 1) { + int off = (ypos >> 1) * frame->linesize[1] + (xpos >> 1); + ff_rv60_idct4x4_add(u_coeffs, frame->data[1] + off, frame->linesize[1]); + } + if ((cbp8 >> 5) & 1) { + int off = (ypos >> 1) * frame->linesize[2] + (xpos >> 1); + ff_rv60_idct4x4_add(v_coeffs, frame->data[2] + off, frame->linesize[2]); + } + } + break; + case TRANSFORM_16X16: + subset = is_intra ? 1 : 3; + num_clusters = size >> 4; + cl_cbp = get_bits(gb, num_clusters * num_clusters); + for (int y = 0; y < num_clusters; y++) { + for (int x = 0; x < num_clusters; x++) { + if (!((cl_cbp >> (y*num_clusters + x)) & 1)) + continue; + thread->coded_blk[cu_pos + y*2*8 + x*2 + 0] = 1; + thread->coded_blk[cu_pos + y*2*8 + x*2 + 1] = 1; + thread->coded_blk[cu_pos + y*2*8 + x*2 + 8] = 1; + thread->coded_blk[cu_pos + y*2*8 + x*2 + 9] = 1; + super_cbp = decode_cbp16(gb, subset, sel_qp); + if (super_cbp) { + decode_cu_16x16(gb, is_intra, qp, sel_qp, y_coeffs, u_coeffs, v_coeffs, super_cbp); + if (super_cbp & 0xFFFF) { + int off = (ypos + y * 16) * frame->linesize[0] + xpos + x * 16; + ff_rv60_idct16x16_add(y_coeffs, frame->data[0] + off, frame->linesize[0]); + } + if ((super_cbp >> 16) & 0xF) { + int off = ((ypos >> 1) + y * 8) * frame->linesize[1] + (xpos >> 1) + x * 8; + ff_rv60_idct8x8_add(u_coeffs, frame->data[1] + off, frame->linesize[1]); + } + if ((super_cbp >> 20) & 0xF) { + int off = ((ypos >> 1) + y * 8) * frame->linesize[2] + (xpos >> 1) + x * 8; + ff_rv60_idct8x8_add(v_coeffs, frame->data[2] + off, frame->linesize[2]); + } + } + } + } + break; + } + + return 0; +} + +static int deblock_get_pos(RV60Context * s, int xpos, int ypos) +{ + return (ypos >> 2) * s->dblk_stride + (xpos >> 2); +} + +static void deblock_set_strength(RV60Context * s, int xpos, int ypos, int size, int q, int strength) +{ + int pos = deblock_get_pos(s, xpos, ypos); + int dsize = size >> 2; + int dval = (q << 2) + strength; + + for (int x = 0; x < dsize; x++) { + s->top_str[pos + x] = dval; + s->top_str[pos + (dsize - 1)*s->dblk_stride + x] = dval; + } + + for (int y = 0; y < dsize; y++) { + s->left_str[pos + y*s->dblk_stride] = dval; + s->left_str[pos + y*s->dblk_stride + dsize - 1] = dval; + } +} + +static int deblock_get_top_strength(const RV60Context * s, int pos) +{ + return s->top_str[pos] & 3; +} + +static int deblock_get_left_strength(const RV60Context * s, int pos) +{ + return s->left_str[pos] & 3; +} + +static void deblock_set_top_strength(RV60Context * s, int pos, int strength) +{ + s->top_str[pos] |= strength; +} + +static void deblock_set_left_strength(RV60Context * s, int pos, int strength) +{ + s->left_str[pos] |= strength; +} + +static void derive_deblock_strength(RV60Context * s, int xpos, int ypos, int size) +{ + int blk_pos = (ypos >> 2) * s->blk_stride + (xpos >> 2); + int dblk_pos = deblock_get_pos(s, xpos, ypos); + if (ypos > 0) + for (int i = 0; i < size; i++) + if (!deblock_get_top_strength(s, dblk_pos - s->dblk_stride + i) && mvinfo_is_deblock_cand(&s->blk_info[blk_pos + i].mv, &s->blk_info[blk_pos - s->blk_stride + i].mv)) + deblock_set_top_strength(s, dblk_pos + i, 1); + if (xpos > 0) + for (int i = 0; i < size; i++) + if (!deblock_get_left_strength(s, dblk_pos + i *s->dblk_stride - 1) && mvinfo_is_deblock_cand(&s->blk_info[blk_pos + i*s->blk_stride].mv, &s->blk_info[blk_pos + i*s->blk_stride - 1].mv)) + deblock_set_left_strength(s, dblk_pos + i *s->dblk_stride, 1); +} + +#define STRENGTH(el, lim) (FFABS(el) < (lim) ? 3 : 1) +#define CLIP_SYMM(a, b) av_clip(a, -(b), b) + +static void filter_luma_edge(uint8_t * dst, int step, int stride, int mode1, int mode2, int lim1, int lim2) +{ + int16_t diff_q1q0[4]; + int16_t diff_p1p0[4]; + int str_p, str_q, msum, maxprod, weak; + + for (int i = 0; i < 4; i++) { + diff_q1q0[i] = dst[i * stride - 2*step] - dst[i*stride - step]; + diff_p1p0[i] = dst[i * stride + step] - dst[i*stride]; + } + + str_p = STRENGTH(diff_q1q0[0] + diff_q1q0[1] + diff_q1q0[2] + diff_q1q0[3], lim2); + str_q = STRENGTH(diff_p1p0[0] + diff_p1p0[1] + diff_p1p0[2] + diff_p1p0[3], lim2); + + if (str_p + str_q <= 2) + return; + + msum = (mode1 + mode2 + str_q + str_p) >> 1; + if (str_q == 1 || str_p == 1) { + maxprod = 384; + weak = 1; + } else { + maxprod = 256; + weak = 0; + } + + for (int y = 0; y < 4; y++) { + int diff_p0q0 = dst[0] - dst[-step]; + int result = (lim1 * FFABS(diff_p0q0)) & -128; + if (diff_p0q0 && result <= maxprod) { + int diff_q1q2 = dst[-2*step] - dst[-3*step]; + int diff_p1p2 = dst[step] - dst[2*step]; + int delta; + if (weak) { + delta = CLIP_SYMM((diff_p0q0 + 1) >> 1, msum >> 1); + } else { + int diff_strg = (dst[-2*step] - dst[step] + 4 * diff_p0q0 + 4) >> 3; + delta = CLIP_SYMM(diff_strg, msum); + } + dst[-step] = av_clip_uint8(dst[-step] + delta); + dst[0] = av_clip_uint8(dst[0] - delta); + if (str_p != 1 && FFABS(diff_q1q2) <= (lim2 >> 2)) { + int diff = (diff_q1q0[y] + diff_q1q2 - delta) >> 1; + int delta_q1 = weak ? CLIP_SYMM(diff, mode1 >> 1) : CLIP_SYMM(diff, mode1); + dst[-2 * step] = av_clip_uint8(dst[-2*step] - delta_q1); + } + if (str_q != 1 && FFABS(diff_p1p2) <= (lim2 >> 2)) { + int diff = (diff_p1p0[y] + diff_p1p2 + delta) >> 1; + int delta_p1 = weak ? CLIP_SYMM(diff, mode2 >> 1) : CLIP_SYMM(diff, mode2); + dst[step] = av_clip_uint8(dst[step] - delta_p1); + } + } + dst += stride; + } +} + +static void filter_chroma_edge(uint8_t * dst, int step, int stride, int mode1, int mode2, int lim1, int lim2) +{ + int diff_q = 4 * FFABS(dst[-2*step] - dst[-step]); + int diff_p = 4 * FFABS(dst[ step] - dst[0]); + int str_q = STRENGTH(diff_q, lim2); + int str_p = STRENGTH(diff_p, lim2); + int msum, maxprod, weak; + + if (str_p + str_q <= 2) + return; + + msum = (mode1 + mode2 + str_q + str_p) >> 1; + if (str_q == 1 || str_p == 1) { + maxprod = 384; + weak = 1; + } else { + maxprod = 256; + weak = 0; + } + + for (int y = 0; y < 2; y++) { + int diff_pq = dst[0] - dst[-step]; + int result = (lim1 * FFABS(diff_pq)) & -128; + if (diff_pq && result <= maxprod) { + int delta; + if (weak) { + delta = CLIP_SYMM((diff_pq + 1) >> 1, msum >> 1); + } else { + int diff_strg = (dst[-2*step] - dst[step] + 4 * diff_pq + 4) >> 3; + delta = CLIP_SYMM(diff_strg, msum); + } + dst[-step] = av_clip_uint8(dst[-step] + delta); + dst[ 0 ] = av_clip_uint8(dst[ 0 ] - delta); + } + dst += stride; + } +} + +static void deblock_edge_ver(AVFrame * frame, int xpos, int ypos, int dblk_l, int dblk_r, int deblock_chroma) +{ + int qp_l = dblk_l >> 2; + int str_l = dblk_l & 3; + int qp_r = dblk_r >> 2; + int str_r = dblk_r & 3; + const uint8_t * dl_l = rv60_deblock_limits[qp_l]; + const uint8_t * dl_r = rv60_deblock_limits[qp_r]; + int mode_l = str_l ? dl_l[str_l - 1] : 0; + int mode_r = str_r ? dl_r[str_r - 1] : 0; + int lim1 = dl_r[2]; + int lim2 = dl_r[3] * 4; + + filter_luma_edge(frame->data[0] + ypos * frame->linesize[0] + xpos, 1, frame->linesize[0], mode_l, mode_r, lim1, lim2); + if ((str_l | str_r) >= 2 && deblock_chroma) + for (int plane = 1; plane < 3; plane++) + filter_chroma_edge(frame->data[plane] + (ypos >> 1) * frame->linesize[plane] + (xpos >> 1), 1, frame->linesize[plane], mode_l, mode_r, lim1, lim2); +} + +static void deblock_edge_hor(AVFrame * frame, int xpos, int ypos, int dblk_t, int dblk_d, int deblock_chroma) +{ + int qp_t = dblk_t >> 2; + int str_t = dblk_t & 3; + int qp_d = dblk_d >> 2; + int str_d = dblk_d & 3; + const uint8_t * dl_t = rv60_deblock_limits[qp_t]; + const uint8_t * dl_d = rv60_deblock_limits[qp_d]; + int mode_t = str_t ? dl_t[str_t - 1] : 0; + int mode_d = str_d ? dl_d[str_d - 1] : 0; + int lim1 = dl_d[2]; + int lim2 = dl_d[3] * 4; + + filter_luma_edge(frame->data[0] + ypos * frame->linesize[0] + xpos, frame->linesize[0], 1, mode_t, mode_d, lim1, lim2); + if ((str_t | str_d) >= 2 && deblock_chroma) + for (int plane = 1; plane < 3; plane++) + filter_chroma_edge(frame->data[plane] + (ypos >> 1) * frame->linesize[plane] + (xpos >> 1), frame->linesize[plane], 1, mode_t, mode_d, lim1, lim2); +} + +static void deblock8x8(const RV60Context * s, AVFrame * frame, int xpos, int ypos, int dblkpos) +{ + if (xpos > 0) { + if (ypos > 0) { + int str_l = s->left_str[dblkpos - s->dblk_stride - 1]; + int str_r = s->left_str[dblkpos - s->dblk_stride]; + if ((str_l | str_r) & 3) + deblock_edge_ver(frame, xpos, ypos - 4, str_l, str_r, s->deblock_chroma); + } + { + int str_l = s->left_str[dblkpos - 1]; + int str_r = s->left_str[dblkpos]; + if ((str_l | str_r) & 3) + deblock_edge_ver(frame, xpos, ypos, str_l, str_r, s->deblock_chroma); + } + if (ypos + 8 >= s->aheight) { + int str_l = s->left_str[dblkpos + s->dblk_stride - 1]; + int str_r = s->left_str[dblkpos + s->dblk_stride]; + if ((str_l | str_r) & 3) + deblock_edge_ver(frame, xpos, ypos + 4, str_l, str_r, s->deblock_chroma); + } + } + if (ypos > 0) { + if (xpos > 0) { + int str_t = s->top_str[dblkpos - s->dblk_stride - 1]; + int str_d = s->top_str[dblkpos - 1]; + if ((str_t | str_d) & 3) + deblock_edge_hor(frame, xpos - 4, ypos, str_t, str_d, s->deblock_chroma); + } + { + int str_t = s->top_str[dblkpos - s->dblk_stride]; + int str_d = s->top_str[dblkpos]; + if ((str_t | str_d) & 3) + deblock_edge_hor(frame, xpos, ypos, str_t, str_d, s->deblock_chroma); + } + if (xpos + 8 >= s->awidth) { + int str_t = s->top_str[dblkpos - s->dblk_stride + 1]; + int str_d = s->top_str[dblkpos + 1]; + if ((str_t | str_d) & 3) + deblock_edge_hor(frame, xpos + 4, ypos, str_t, str_d, s->deblock_chroma); + } + } +} + +static void deblock(const RV60Context * s, AVFrame * frame, int xpos, int ypos, int size, int dpos) +{ + for (int x = 0; x < size >> 3; x++) + deblock8x8(s, frame, xpos + x * 8, ypos, dpos + x * 2); + + for (int y = 1; y < size >> 3; y++) + deblock8x8(s, frame, xpos, ypos + y * 8, dpos + y * 2 * s->dblk_stride); +} + +static void deblock_cu_r(RV60Context * s, AVFrame * frame, ThreadContext * thread, int xpos, int ypos, int log_size, int qp) +{ + int pu_pos, tsize, ntiles; + enum CUType cu_type; + + if (xpos >= s->awidth || ypos >= s->aheight) + return; + + if (thread->cu_split[thread->cu_split_pos++]) { + int hsize = 1 << (log_size - 1); + log_size--; + deblock_cu_r(s, frame, thread, xpos, ypos, log_size, qp); + deblock_cu_r(s, frame, thread, xpos + hsize, ypos, log_size, qp); + deblock_cu_r(s, frame, thread, xpos, ypos + hsize, log_size, qp); + deblock_cu_r(s, frame, thread, xpos + hsize, ypos + hsize, log_size, qp); + return; + } + + pu_pos = (ypos >> 3) * s->pu_stride + (xpos >> 3); + cu_type = s->pu_info[pu_pos].cu_type; + switch (log_size) { + case 3: tsize = 3; break; + case 4: tsize = cu_type && s->pu_info[pu_pos].pu_type ? 3 : 4; break; + case 5: + case 6: tsize = 4; break; + } + ntiles = 1 << (log_size - tsize); + + for (int ty = 0; ty < ntiles; ty++) + for (int tx = 0; tx < ntiles; tx++) { + int x = xpos + (tx << tsize); + int y = ypos + (ty << tsize); + int cu_pos = ((y & 63) >> 3) * 8 + ((x & 63) >> 3); + + if (cu_type == CU_INTRA) + deblock_set_strength(s, x, y, 1 << tsize, qp, 2); + else if (cu_type != CU_SKIP && thread->coded_blk[cu_pos]) + deblock_set_strength(s, x, y, 1 << tsize, qp, 1); + else { + deblock_set_strength(s, x, y, 1 << tsize, qp, 0); + derive_deblock_strength(s, x, y, 1 << (tsize - 2)); + } + + deblock(s, frame, x, y, 1 << tsize, deblock_get_pos(s, x, y)); + } +} + +static int read_qp_offset(GetBitContext *gb, int qp_off_type) +{ + int val; + + switch (qp_off_type) { + case 0: + return 0; + case 1: + val = read_code012(gb); + return val != 2 ? val : -1; + default: + if (!get_bits1(gb)) + return 0; + val = get_bits(gb, 2); + if (!(val & 2)) + return val + 1; + else + return -((val & 1) + 1); + } +} + +static int calc_sel_qp(int osvquant, int qp) +{ + switch (osvquant) { + case 0: return qp; + case 1: return qp <= 25 ? qp + 5 : qp; + default: + if (qp <= 18) + return qp + 10; + else if (qp <= 25) + return qp + 5; + else + return qp; + } +} + +static int decode_slice(AVCodecContext *avctx, void *tdata, int cu_y, int threadnr) +{ + RV60Context *s = avctx->priv_data; + AVFrame * frame = tdata; + ThreadContext thread; + GetBitContext gb; + int qp, sel_qp, ret; + + thread.avg_data[0] = thread.avg_buffer; + thread.avg_data[1] = thread.avg_buffer + 64*64; + thread.avg_data[2] = thread.avg_buffer + 64*64 + 32*32; + thread.avg_linesize[0] = 64; + thread.avg_linesize[1] = 32; + thread.avg_linesize[2] = 32; + + if ((ret = init_get_bits8(&gb, s->slice[cu_y].data, s->slice[cu_y].data_size)) < 0) + return ret; + + for (int cu_x = 0; cu_x < s->cu_width; cu_x++) { + if ((s->avctx->active_thread_type & FF_THREAD_SLICE) && cu_y) + ff_thread_progress_await(&s->progress[cu_y - 1], cu_x + 2); + + qp = s->qp + read_qp_offset(&gb, s->qp_off_type); + if (qp < 0 || qp >= 64) { + ret = AVERROR_INVALIDDATA; + break; + } + sel_qp = calc_sel_qp(s->osvquant, qp); + + memset(thread.coded_blk, 0, sizeof(thread.coded_blk)); + thread.cu_split_pos = 0; + + if ((ret = decode_cu_r(s, frame, &thread, &gb, cu_x << 6, cu_y << 6, 6, qp, sel_qp)) < 0) + break; + + if (s->deblock) { + thread.cu_split_pos = 0; + deblock_cu_r(s, frame, &thread, cu_x << 6, cu_y << 6, 6, qp); + } + + if (s->avctx->active_thread_type & FF_THREAD_SLICE) + ff_thread_progress_report(&s->progress[cu_y], cu_x + 1); + } + + if (s->avctx->active_thread_type & FF_THREAD_SLICE) + ff_thread_progress_report(&s->progress[cu_y], INT_MAX); + + return ret; +} + +static int rv60_decode_frame(AVCodecContext *avctx, AVFrame * frame, + int * got_frame, AVPacket * avpkt) +{ + RV60Context *s = avctx->priv_data; + GetBitContext gb; + int ret, header_size, width, height, ofs; + + if (avpkt->size == 0) { + if (s->last_frame[NEXT_PIC]->data[0]) { + av_frame_move_ref(frame, s->last_frame[NEXT_PIC]); + *got_frame = 1; + } + return 0; + } + + if (avpkt->size < 9) + return AVERROR_INVALIDDATA; + + header_size = avpkt->data[0] * 8 + 9; + if (avpkt->size < header_size) + return AVERROR_INVALIDDATA; + + if ((ret = init_get_bits8(&gb, avpkt->data + header_size, avpkt->size - header_size)) < 0) + return ret; + + if ((ret = read_frame_header(s, &gb, &width, &height)) < 0) + return ret; + + if (avctx->skip_frame >= AVDISCARD_NONREF && s->pict_type == AV_PICTURE_TYPE_B || + avctx->skip_frame >= AVDISCARD_NONKEY && s->pict_type != AV_PICTURE_TYPE_I || + avctx->skip_frame >= AVDISCARD_ALL) + return avpkt->size; + + if (s->pict_type != AV_PICTURE_TYPE_B) + FFSWAP(AVFrame *, s->last_frame[NEXT_PIC], s->last_frame[LAST_PIC]); + + if ((s->pict_type == AV_PICTURE_TYPE_P && !s->last_frame[LAST_PIC]->data[0]) || + (s->pict_type == AV_PICTURE_TYPE_B && (!s->last_frame[LAST_PIC]->data[0] || !s->last_frame[NEXT_PIC]->data[0]))) { + av_log(s->avctx, AV_LOG_ERROR, "missing reference frame\n"); + return AVERROR_INVALIDDATA; + } + + s->last_frame[CUR_PIC]->pict_type = s->pict_type; + if (s->pict_type == AV_PICTURE_TYPE_I) + s->last_frame[CUR_PIC]->flags |= AV_FRAME_FLAG_KEY; + + if ((ret = update_dimensions_clear_info(s, width, height)) < 0) + return ret; + + if (!s->last_frame[CUR_PIC]->data[0]) + if ((ret = ff_get_buffer(avctx, s->last_frame[CUR_PIC], 0)) < 0) + return ret; + + if ((ret = read_slice_sizes(s, &gb)) < 0) + return ret; + + ofs = get_bits_count(&gb) / 8; + + for (int i = 0; i < s->cu_height; i++) { + if (ofs >= avpkt->size - header_size) + return AVERROR_INVALIDDATA; + s->slice[i].data = avpkt->data + header_size + ofs; + s->slice[i].data_size = FFMIN(s->slice[i].size, avpkt->size - header_size - ofs); + if (s->slice[i].size > INT32_MAX - ofs) + return AVERROR_INVALIDDATA; + ofs += s->slice[i].size; + } + + ret = progress_init(s, s->cu_height); + if (ret < 0) + return ret; + + s->avctx->execute2(s->avctx, decode_slice, s->last_frame[CUR_PIC], NULL, s->cu_height); + + ret = 0; + if (s->pict_type == AV_PICTURE_TYPE_B) + av_frame_move_ref(frame, s->last_frame[CUR_PIC]); + else if (s->last_frame[LAST_PIC]->data[0]) + ret = av_frame_ref(frame, s->last_frame[LAST_PIC]); + if (ret < 0) + return ret; + + if (frame->data[0]) + *got_frame = 1; + + if (s->pict_type != AV_PICTURE_TYPE_B) { + av_frame_unref(s->last_frame[NEXT_PIC]); + FFSWAP(AVFrame *, s->last_frame[CUR_PIC], s->last_frame[NEXT_PIC]); + } + + if (s->pict_type != AV_PICTURE_TYPE_B) { + s->ref_pts[0] = s->ref_pts[1]; + s->ref_pts[1] = avpkt->pts; + + s->ref_ts[0] = s->ref_ts[1]; + s->ref_ts[1] = s->ts; + + if (s->ref_pts[1] > s->ref_pts[0] && s->ref_ts[1] > s->ref_ts[0]) + s->ts_scale = (s->ref_pts[1] - s->ref_pts[0]) / (s->ref_ts[1] - s->ref_ts[0]); + } else { + frame->pts = s->ref_pts[0] + (s->ts - s->ref_ts[0]) * s->ts_scale; + } + + return avpkt->size; +} + +static av_cold void rv60_flush(AVCodecContext *avctx) +{ + RV60Context *s = avctx->priv_data; + + for (int i = 0; i < 3; i++) + av_frame_unref(s->last_frame[i]); +} + +static av_cold int rv60_decode_end(AVCodecContext * avctx) +{ + RV60Context *s = avctx->priv_data; + + for (int i = 0; i < 3; i++) + av_frame_free(&s->last_frame[i]); + + av_freep(&s->slice); + av_freep(&s->pu_info); + av_freep(&s->blk_info); + av_freep(&s->top_str); + av_freep(&s->left_str); + + for (int i = 0; i < s->nb_progress; i++) + ff_thread_progress_destroy(&s->progress[i]); + av_freep(&s->progress); + + return 0; +} + +const FFCodec ff_rv60_decoder = { + .p.name = "rv60", + CODEC_LONG_NAME("RealVideo 6.0"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_RV60, + .priv_data_size = sizeof(RV60Context), + .init = rv60_decode_init, + .close = rv60_decode_end, + FF_CODEC_DECODE_CB(rv60_decode_frame), + .flush = rv60_flush, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/rv60dsp.c b/libavcodec/rv60dsp.c new file mode 100644 index 000000000..a891c0d09 --- /dev/null +++ b/libavcodec/rv60dsp.c @@ -0,0 +1,164 @@ +/* + * RV60 dsp routines + * + * 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 "rv60dsp.h" +#include "libavutil/common.h" + +void ff_rv60_idct4x4_add(const int16_t * block, uint8_t * dst, int dst_stride) +{ + int tmp[16]; +#define IDCT4X4(src, src_stride, src_step, dst, dst_stride, dst_step) \ + for (int y = 0; y < 4; y++) { \ + int a = src[y*src_stride + 0*src_step]; \ + int b = src[y*src_stride + 1*src_step]; \ + int c = src[y*src_stride + 2*src_step]; \ + int d = src[y*src_stride + 3*src_step]; \ + int t0 = 13 * (a + c); \ + int t1 = 13 * (a - c); \ + int t2 = 7 * b - 17 * d; \ + int t3 = 7 * d + 17 * b; \ + STORE(dst[y*dst_stride + 0*dst_step], (t0 + t3 + 16) >> 5); \ + STORE(dst[y*dst_stride + 1*dst_step], (t1 + t2 + 16) >> 5); \ + STORE(dst[y*dst_stride + 2*dst_step], (t1 - t2 + 16) >> 5); \ + STORE(dst[y*dst_stride + 3*dst_step], (t0 - t3 + 16) >> 5); \ + } +#define STORE(a, b) a = b + IDCT4X4(block, 1, 4, tmp, 1, 4) +#undef STORE +#define STORE(a, b) a = av_clip_uint8(a + (b)) + IDCT4X4(tmp, 4, 1, dst, dst_stride, 1) +#undef STORE +} + +void ff_rv60_idct8x8_add(const int16_t * block, uint8_t * dst, int dst_stride) +{ + int tmp[64]; +#define IDCT8X8(src, src_stride, src_step, dst, dst_stride, dst_step) \ + for (int y = 0; y < 8; y++) { \ + int a = src[y*src_stride + 0*src_step]; \ + int b = src[y*src_stride + 1*src_step]; \ + int c = src[y*src_stride + 2*src_step]; \ + int d = src[y*src_stride + 3*src_step]; \ + int e = src[y*src_stride + 4*src_step]; \ + int f = src[y*src_stride + 5*src_step]; \ + int g = src[y*src_stride + 6*src_step]; \ + int h = src[y*src_stride + 7*src_step]; \ + int t0 = 37 * (a + e); \ + int t1 = 37 * (a - e); \ + int t2 = 48 * c + 20 * g; \ + int t3 = 20 * c - 48 * g; \ + int t4 = t0 + t2; \ + int t5 = t0 - t2; \ + int t6 = t1 + t3; \ + int t7 = t1 - t3; \ + int t8 = 51 * b + 43 * d + 29 * f + 10 * h; \ + int t9 = 43 * b - 10 * d - 51 * f - 29 * h; \ + int ta = 29 * b - 51 * d + 10 * f + 43 * h; \ + int tb = 10 * b - 29 * d + 43 * f - 51 * h; \ + STORE(dst[y*dst_stride + 0*dst_step], (t4 + t8 + 64) >> 7); \ + STORE(dst[y*dst_stride + 1*dst_step], (t6 + t9 + 64) >> 7); \ + STORE(dst[y*dst_stride + 2*dst_step], (t7 + ta + 64) >> 7); \ + STORE(dst[y*dst_stride + 3*dst_step], (t5 + tb + 64) >> 7); \ + STORE(dst[y*dst_stride + 4*dst_step], (t5 - tb + 64) >> 7); \ + STORE(dst[y*dst_stride + 5*dst_step], (t7 - ta + 64) >> 7); \ + STORE(dst[y*dst_stride + 6*dst_step], (t6 - t9 + 64) >> 7); \ + STORE(dst[y*dst_stride + 7*dst_step], (t4 - t8 + 64) >> 7); \ + } +#define STORE(a, b) a = b + IDCT8X8(block, 1, 8, tmp, 1, 8) +#undef STORE +#define STORE(a, b) a = av_clip_uint8(a + (b)) + IDCT8X8(tmp, 8, 1, dst, dst_stride, 1) +#undef STORE +} + +void ff_rv60_idct16x16_add(const int16_t * block, uint8_t * dst, int dst_stride) +{ + int16_t tmp[256]; +#define IDCT16X16(src, src_stride, src_step, dst, dst_stride, dst_step) \ + for (int y = 0; y < 16; y++) { \ + int a = src[y*src_stride + 0*src_step]; \ + int b = src[y*src_stride + 1*src_step]; \ + int c = src[y*src_stride + 2*src_step]; \ + int d = src[y*src_stride + 3*src_step]; \ + int e = src[y*src_stride + 4*src_step]; \ + int f = src[y*src_stride + 5*src_step]; \ + int g = src[y*src_stride + 6*src_step]; \ + int h = src[y*src_stride + 7*src_step]; \ + int i = src[y*src_stride + 8*src_step]; \ + int j = src[y*src_stride + 9*src_step]; \ + int k = src[y*src_stride + 10*src_step]; \ + int l = src[y*src_stride + 11*src_step]; \ + int m = src[y*src_stride + 12*src_step]; \ + int n = src[y*src_stride + 13*src_step]; \ + int o = src[y*src_stride + 14*src_step]; \ + int p = src[y*src_stride + 15*src_step]; \ + int t0 = 26 * (a + i); \ + int t1 = 26 * (a - i); \ + int t2 = 14 * e - 34 * m; \ + int t3 = 34 * e + 14 * m; \ + int t4 = t0 + t3; \ + int t5 = t0 - t3; \ + int t6 = t1 + t2; \ + int t7 = t1 - t2; \ + int tmp00 = 31 * c - 7 * g - 36 * k - 20 * o; \ + int tmp01 = 36 * c + 31 * g + 20 * k + 7 * o; \ + int tmp02 = 20 * c - 36 * g + 7 * k + 31 * o; \ + int tmp03 = 7 * c - 20 * g + 31 * k - 36 * o; \ + int tm0 = t4 + tmp01; \ + int tm1 = t4 - tmp01; \ + int tm2 = t5 + tmp03; \ + int tm3 = t5 - tmp03; \ + int tm4 = t6 + tmp00; \ + int tm5 = t6 - tmp00; \ + int tm6 = t7 + tmp02; \ + int tm7 = t7 - tmp02; \ + int tt0 = 37 * b + 35 * d + 32 * f + 28 * h + 23 * j + 17 * l + 11 * n + 4 * p; \ + int tt1 = 35 * b + 23 * d + 4 * f - 17 * h - 32 * j - 37 * l - 28 * n - 11 * p; \ + int tt2 = 32 * b + 4 * d - 28 * f - 35 * h - 11 * j + 23 * l + 37 * n + 17 * p; \ + int tt3 = 28 * b - 17 * d - 35 * f + 4 * h + 37 * j + 11 * l - 32 * n - 23 * p; \ + int tt4 = 23 * b - 32 * d - 11 * f + 37 * h - 4 * j - 35 * l + 17 * n + 28 * p; \ + int tt5 = 17 * b - 37 * d + 23 * f + 11 * h - 35 * j + 28 * l + 4 * n - 32 * p; \ + int tt6 = 11 * b - 28 * d + 37 * f - 32 * h + 17 * j + 4 * l - 23 * n + 35 * p; \ + int tt7 = 4 * b - 11 * d + 17 * f - 23 * h + 28 * j - 32 * l + 35 * n - 37 * p; \ + STORE(dst[y*dst_stride+ 0*dst_step], (tm0 + tt0 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 1*dst_step], (tm4 + tt1 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 2*dst_step], (tm6 + tt2 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 3*dst_step], (tm2 + tt3 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 4*dst_step], (tm3 + tt4 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 5*dst_step], (tm7 + tt5 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 6*dst_step], (tm5 + tt6 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 7*dst_step], (tm1 + tt7 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 8*dst_step], (tm1 - tt7 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 9*dst_step], (tm5 - tt6 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 10*dst_step], (tm7 - tt5 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 11*dst_step], (tm3 - tt4 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 12*dst_step], (tm2 - tt3 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 13*dst_step], (tm6 - tt2 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 14*dst_step], (tm4 - tt1 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 15*dst_step], (tm0 - tt0 + 64) >> 7); \ + } +#define STORE(a, x) a = av_clip_intp2(x, 15) + IDCT16X16(block, 1, 16, tmp, 1, 16) +#undef STORE +#define STORE(a, x) a = av_clip_uint8(a + (x)) + IDCT16X16(tmp, 16, 1, dst, dst_stride, 1) +#undef STORE +} diff --git a/libavcodec/rv60dsp.h b/libavcodec/rv60dsp.h new file mode 100644 index 000000000..99448517b --- /dev/null +++ b/libavcodec/rv60dsp.h @@ -0,0 +1,30 @@ +/* + * RV60 dsp routines + * + * 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_RV60DSP_H +#define AVCODEC_RV60DSP_H + +#include + +void ff_rv60_idct4x4_add(const int16_t * block, uint8_t * dst, int dst_stride); +void ff_rv60_idct8x8_add(const int16_t * block, uint8_t * dst, int dst_stride); +void ff_rv60_idct16x16_add(const int16_t * block, uint8_t * dst, int dst_stride); + +#endif /* AVCODEC_RV60DSP_H */ diff --git a/libavcodec/rv60vlcs.h b/libavcodec/rv60vlcs.h new file mode 100644 index 000000000..d2a8a6d93 --- /dev/null +++ b/libavcodec/rv60vlcs.h @@ -0,0 +1,2315 @@ +/* + * RV60 decoder + * + * 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_RV60VLCS_H +#define AVCODEC_RV60VLCS_H + +#include + +static const uint8_t rv60_cbp8_lens[7][4][64] = { + { + { 7, 7, 7, 7, 7, 7, 8, 6, 7, 7, 7, 6, 7, 6, 6, 4, + 8, 8, 8, 7, 8, 7, 8, 6, 8, 8, 7, 6, 7, 6, 6, 3, + 9, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 4, + 9, 9, 9, 7, 9, 7, 8, 5, 9, 8, 7, 5, 7, 5, 5, 2 }, + { 7, 4, 9, 4, 12, 6, 10, 5, 14, 9, 12, 8, 12, 7, 11, 3, + 9, 5, 11, 6, 12, 6, 11, 4, 14, 9, 13, 8, 12, 7, 11, 3, + 10, 5, 12, 6, 14, 6, 13, 6, 15, 11, 15, 10, 15, 9, 13, 5, + 11, 5, 14, 5, 13, 5, 12, 4, 15, 10, 14, 8, 14, 7, 12, 3 }, + { 5, 6, 6, 6, 6, 6, 7, 6, 6, 7, 6, 6, 6, 6, 6, 3, + 7, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 3, + 9, 9, 9, 9, 9, 9, 10, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 9, 9, 10, 8, 9, 8, 9, 7, 9, 9, 9, 7, 8, 7, 7, 2 }, + { 8, 4, 7, 4, 10, 5, 9, 4, 12, 8, 10, 7, 11, 7, 9, 4, + 9, 5, 10, 5, 10, 6, 11, 5, 14, 9, 13, 8, 12, 7, 10, 3, + 11, 6, 12, 6, 13, 7, 13, 6, 15, 11, 14, 9, 14, 10, 13, 5, + 11, 6, 12, 6, 12, 6, 13, 5, 15, 10, 14, 9, 14, 8, 12, 2 } + }, + { + { 7, 7, 7, 7, 7, 7, 8, 6, 7, 7, 7, 6, 7, 6, 6, 4, + 8, 8, 8, 7, 8, 7, 8, 6, 8, 8, 7, 6, 7, 6, 6, 3, + 9, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 4, + 9, 9, 9, 7, 9, 7, 8, 5, 9, 8, 7, 5, 7, 5, 5, 2 }, + { 7, 4, 9, 4, 12, 6, 10, 5, 14, 9, 12, 8, 12, 7, 11, 3, + 9, 5, 11, 6, 12, 6, 11, 4, 14, 9, 13, 8, 12, 7, 11, 3, + 10, 5, 12, 6, 14, 6, 13, 6, 15, 11, 15, 10, 15, 9, 13, 5, + 11, 5, 14, 5, 13, 5, 12, 4, 15, 10, 14, 8, 14, 7, 12, 3 }, + { 5, 6, 6, 6, 6, 6, 7, 6, 6, 7, 6, 6, 6, 6, 6, 3, + 7, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 3, + 9, 9, 9, 9, 9, 9, 10, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 9, 9, 10, 8, 9, 8, 9, 7, 9, 9, 9, 7, 8, 7, 7, 2 }, + { 8, 4, 7, 4, 10, 5, 9, 4, 12, 8, 10, 7, 11, 7, 9, 4, + 9, 5, 10, 5, 10, 6, 11, 5, 14, 9, 13, 8, 12, 7, 10, 3, + 11, 6, 12, 6, 13, 7, 13, 6, 15, 11, 14, 9, 14, 10, 13, 5, + 11, 6, 12, 6, 12, 6, 13, 5, 15, 10, 14, 9, 14, 8, 12, 2 } + }, + { + { 5, 6, 6, 6, 6, 6, 7, 6, 6, 7, 6, 5, 6, 6, 5, 4, + 7, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 4, + 8, 8, 8, 8, 8, 8, 9, 7, 8, 9, 8, 7, 8, 7, 7, 5, + 8, 8, 9, 7, 8, 7, 8, 6, 9, 8, 7, 6, 7, 6, 6, 2 }, + { 5, 2, 9, 5, 9, 5, 10, 4, 9, 7, 10, 6, 10, 6, 9, 3, + 8, 4, 11, 6, 9, 5, 11, 5, 11, 8, 12, 8, 11, 8, 11, 5, + 9, 5, 13, 7, 13, 7, 14, 7, 14, 10, 14, 9, 14, 9, 13, 6, + 10, 5, 14, 6, 12, 5, 14, 5, 14, 10, 14, 9, 14, 8, 14, 5 }, + { 4, 5, 6, 5, 5, 6, 6, 5, 5, 6, 5, 5, 5, 5, 5, 3, + 7, 7, 8, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 3, + 9, 9, 10, 9, 9, 9, 10, 8, 9, 10, 9, 8, 8, 8, 8, 5, + 10, 10, 10, 9, 10, 9, 10, 7, 10, 10, 9, 7, 9, 7, 7, 4 }, + { 6, 3, 7, 4, 8, 4, 8, 4, 9, 7, 9, 6, 8, 6, 7, 3, + 9, 5, 10, 6, 9, 5, 10, 5, 12, 9, 11, 8, 10, 6, 9, 3, + 10, 5, 12, 7, 12, 7, 12, 7, 14, 11, 13, 9, 13, 9, 11, 5, + 10, 6, 12, 7, 11, 7, 13, 6, 14, 11, 13, 9, 13, 8, 11, 4 } + }, + { + { 4, 5, 5, 5, 6, 6, 7, 6, 5, 6, 5, 5, 6, 5, 5, 4, + 7, 7, 7, 7, 8, 7, 8, 6, 8, 8, 7, 6, 7, 6, 6, 4, + 8, 8, 8, 8, 8, 8, 9, 7, 8, 9, 7, 7, 8, 7, 7, 5, + 8, 8, 9, 7, 8, 7, 9, 6, 9, 9, 7, 6, 7, 6, 6, 3 }, + { 3, 2, 9, 4, 9, 4, 11, 5, 9, 7, 10, 7, 11, 7, 10, 5, + 7, 4, 12, 6, 10, 5, 13, 6, 13, 9, 14, 9, 13, 9, 14, 6, + 7, 4, 13, 6, 12, 6, 14, 7, 14, 10, 14, 10, 14, 10, 15, 8, + 9, 4, 13, 6, 12, 6, 15, 6, 14, 10, 15, 9, 15, 9, 14, 6 }, + { 3, 5, 5, 5, 5, 5, 6, 5, 5, 6, 5, 5, 4, 5, 5, 3, + 7, 7, 8, 7, 7, 7, 8, 6, 7, 8, 7, 7, 7, 7, 6, 4, + 8, 9, 9, 8, 9, 8, 9, 8, 9, 9, 8, 8, 8, 8, 8, 6, + 10, 10, 10, 9, 9, 8, 10, 8, 10, 10, 9, 8, 8, 8, 8, 5 }, + { 5, 2, 7, 4, 7, 4, 8, 4, 9, 6, 8, 6, 8, 5, 7, 3, + 8, 4, 10, 6, 9, 6, 10, 6, 12, 9, 11, 8, 10, 7, 9, 5, + 9, 5, 11, 7, 11, 7, 12, 7, 14, 10, 12, 9, 13, 9, 11, 6, + 10, 6, 12, 7, 11, 7, 12, 7, 14, 11, 13, 9, 13, 9, 12, 6 } + }, + { + { 4, 5, 5, 5, 5, 5, 6, 6, 5, 6, 5, 5, 5, 5, 5, 4, + 7, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 7, 6, 4, + 7, 8, 8, 8, 8, 8, 9, 7, 8, 9, 7, 7, 8, 7, 7, 5, + 8, 8, 8, 7, 8, 7, 9, 6, 9, 8, 7, 6, 7, 6, 6, 4 }, + { 3, 1, 9, 5, 10, 5, 13, 6, 11, 9, 12, 8, 15, 10, 14, 8, + 7, 4, 13, 6, 12, 6, 15, 7, 15, 11, 15, 11, 15, 11, 15, 8, + 7, 4, 13, 7, 13, 7, 15, 8, 15, 12, 15, 11, 15, 12, 15, 9, + 9, 5, 14, 6, 13, 7, 15, 7, 15, 12, 15, 11, 15, 11, 15, 7 }, + { 3, 4, 4, 4, 4, 5, 6, 5, 4, 6, 5, 5, 4, 5, 5, 4, + 7, 8, 8, 7, 7, 7, 8, 7, 7, 8, 7, 7, 7, 7, 7, 6, + 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 6, + 10, 10, 10, 9, 9, 9, 10, 9, 10, 10, 9, 9, 9, 9, 9, 7 }, + { 5, 1, 7, 4, 7, 4, 8, 5, 10, 7, 8, 6, 8, 6, 7, 4, + 8, 5, 10, 6, 10, 7, 11, 7, 12, 10, 11, 9, 11, 9, 10, 7, + 9, 5, 11, 7, 11, 7, 11, 8, 13, 11, 12, 9, 12, 10, 11, 8, + 9, 7, 11, 8, 12, 8, 13, 8, 14, 12, 13, 10, 14, 11, 12, 8 } + }, + { + { 3, 5, 5, 5, 5, 5, 6, 6, 4, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 7, 7, 7, 7, 8, 7, 7, 8, 7, 7, 7, 7, 7, 5, + 7, 8, 8, 8, 8, 8, 9, 8, 8, 9, 7, 7, 8, 7, 7, 6, + 8, 8, 8, 7, 8, 7, 9, 6, 8, 9, 7, 7, 8, 7, 7, 4 }, + { 2, 1, 10, 5, 10, 6, 15, 8, 14, 11, 14, 10, 15, 11, 15, 9, + 7, 4, 13, 7, 13, 7, 15, 8, 15, 13, 15, 12, 15, 12, 15, 10, + 7, 5, 13, 8, 13, 8, 15, 10, 15, 14, 15, 12, 15, 13, 15, 10, + 9, 5, 14, 7, 14, 8, 15, 8, 15, 13, 15, 12, 15, 12, 15, 9 }, + { 2, 4, 4, 5, 4, 5, 6, 5, 4, 6, 5, 5, 4, 5, 5, 5, + 7, 8, 8, 8, 7, 8, 9, 8, 7, 9, 8, 8, 8, 8, 8, 7, + 7, 8, 8, 8, 8, 8, 9, 8, 8, 10, 8, 9, 8, 9, 9, 7, + 9, 10, 10, 10, 9, 9, 11, 9, 10, 11, 10, 10, 9, 10, 10, 8 }, + { 4, 1, 6, 4, 6, 4, 8, 5, 9, 8, 8, 7, 8, 7, 7, 6, + 8, 4, 9, 6, 9, 7, 11, 8, 12, 10, 11, 10, 11, 10, 11, 8, + 8, 5, 10, 7, 10, 8, 11, 9, 13, 11, 11, 10, 12, 10, 11, 9, + 9, 6, 11, 8, 12, 9, 13, 9, 14, 13, 13, 11, 14, 11, 13, 9 } + }, + { + { 2, 4, 4, 5, 4, 5, 6, 6, 4, 6, 5, 6, 5, 6, 5, 5, + 6, 7, 7, 7, 7, 8, 8, 8, 7, 8, 7, 8, 7, 8, 8, 7, + 7, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7, + 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7 }, + { 1, 2, 9, 5, 9, 6, 14, 8, 14, 11, 14, 11, 14, 11, 14, 10, + 6, 4, 12, 7, 13, 8, 14, 10, 14, 14, 14, 13, 14, 13, 14, 12, + 6, 5, 13, 8, 13, 9, 14, 11, 14, 14, 14, 13, 14, 14, 14, 12, + 7, 5, 14, 8, 14, 9, 14, 11, 14, 14, 14, 14, 14, 14, 14, 12 }, + { 1, 4, 4, 6, 4, 5, 6, 7, 4, 6, 5, 7, 5, 7, 7, 7, + 7, 8, 9, 9, 8, 9, 10, 10, 8, 10, 9, 11, 9, 10, 10, 10, + 7, 9, 9, 10, 9, 9, 10, 10, 9, 11, 10, 11, 10, 10, 10, 10, + 9, 11, 11, 11, 10, 11, 12, 12, 11, 12, 11, 12, 11, 12, 12, 11 }, + { 2, 1, 6, 4, 7, 5, 9, 8, 10, 9, 9, 8, 10, 9, 9, 8, + 8, 5, 11, 8, 11, 9, 13, 11, 14, 13, 13, 12, 14, 12, 14, 11, + 8, 5, 11, 8, 12, 9, 13, 11, 14, 13, 14, 12, 13, 13, 13, 12, + 9, 6, 12, 9, 13, 10, 14, 12, 14, 14, 14, 13, 14, 14, 14, 12 } + } +}; + +static const uint8_t rv60_cbp16_lens[7][3][4][64] = { + { + { + { 9, 6, 7, 4, 11, 6, 10, 5, 11, 8, 10, 6, 12, 8, 11, 5, + 10, 6, 9, 5, 12, 6, 11, 5, 12, 9, 11, 7, 13, 8, 11, 4, + 10, 7, 8, 5, 12, 7, 11, 5, 12, 9, 11, 7, 14, 9, 12, 3, + 11, 6, 10, 5, 13, 5, 13, 4, 14, 9, 13, 7, 13, 7, 12, 2 }, + { 1, 3, 6, 3, 6, 5, 8, 5, 9, 8, 10, 8, 9, 7, 10, 6, + 6, 7, 9, 6, 9, 8, 10, 8, 11, 11, 11, 10, 11, 8, 10, 7, + 6, 7, 11, 7, 11, 10, 14, 11, 15, 15, 15, 14, 15, 13, 16, 12, + 10, 9, 12, 8, 12, 10, 14, 9, 16, 14, 14, 11, 15, 11, 13, 9 }, + { 1, 3, 6, 5, 6, 5, 8, 6, 7, 8, 9, 7, 8, 7, 8, 5, + 6, 6, 10, 8, 9, 7, 10, 7, 11, 10, 12, 9, 11, 8, 9, 5, + 5, 6, 10, 9, 10, 8, 12, 10, 12, 12, 14, 12, 13, 11, 14, 10, + 9, 8, 12, 9, 11, 7, 13, 8, 13, 12, 14, 11, 14, 9, 13, 6 }, + { 1, 4, 6, 6, 4, 4, 7, 5, 7, 7, 9, 8, 7, 5, 8, 5, + 7, 8, 10, 9, 9, 6, 9, 6, 11, 9, 10, 8, 9, 5, 8, 5, + 7, 12, 13, 13, 13, 11, 13, 12, 13, 13, 13, 13, 13, 13, 13, 11, + 12, 12, 13, 12, 13, 11, 12, 10, 13, 12, 12, 10, 12, 10, 10, 8 } + }, + { + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 5, 7, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 } + }, + { + { 9, 6, 7, 4, 10, 7, 9, 5, 10, 7, 9, 6, 11, 7, 8, 3, + 10, 7, 9, 6, 10, 6, 10, 5, 12, 8, 10, 6, 11, 6, 9, 3, + 11, 8, 9, 7, 13, 8, 12, 7, 13, 10, 12, 8, 13, 9, 11, 4, + 11, 8, 10, 7, 12, 6, 11, 4, 13, 8, 12, 7, 12, 6, 10, 2 }, + { 2, 3, 6, 4, 5, 4, 7, 4, 7, 7, 9, 7, 8, 5, 8, 4, + 5, 6, 8, 7, 7, 6, 8, 6, 10, 9, 11, 9, 10, 7, 10, 5, + 7, 6, 11, 8, 9, 7, 11, 8, 13, 12, 14, 12, 13, 10, 13, 7, + 9, 8, 11, 9, 10, 8, 12, 7, 13, 12, 14, 10, 12, 9, 13, 5 }, + { 2, 3, 5, 4, 6, 5, 7, 5, 7, 7, 8, 6, 8, 7, 8, 4, + 5, 5, 7, 6, 8, 6, 9, 6, 9, 8, 10, 8, 10, 8, 9, 4, + 6, 6, 9, 7, 10, 8, 11, 8, 11, 10, 11, 9, 12, 10, 11, 7, + 9, 8, 10, 8, 10, 7, 11, 7, 12, 10, 12, 9, 12, 9, 11, 5 }, + { 1, 3, 5, 6, 5, 5, 7, 5, 7, 7, 9, 7, 8, 5, 9, 5, + 6, 8, 10, 10, 9, 7, 11, 6, 11, 10, 12, 9, 11, 6, 11, 5, + 8, 10, 12, 11, 11, 10, 13, 10, 14, 13, 14, 12, 14, 11, 14, 8, + 11, 12, 14, 13, 13, 11, 14, 9, 14, 14, 14, 12, 14, 10, 13, 6 } + } + }, + { + { + { 9, 6, 7, 4, 11, 6, 10, 5, 11, 8, 10, 6, 12, 8, 11, 5, + 10, 6, 9, 5, 12, 6, 11, 5, 12, 9, 11, 7, 13, 8, 11, 4, + 10, 7, 8, 5, 12, 7, 11, 5, 12, 9, 11, 7, 14, 9, 12, 3, + 11, 6, 10, 5, 13, 5, 13, 4, 14, 9, 13, 7, 13, 7, 12, 2 }, + { 1, 3, 6, 3, 6, 5, 8, 5, 9, 8, 10, 8, 9, 7, 10, 6, + 6, 7, 9, 6, 9, 8, 10, 8, 11, 11, 11, 10, 11, 8, 10, 7, + 6, 7, 11, 7, 11, 10, 14, 11, 15, 15, 15, 14, 15, 13, 16, 12, + 10, 9, 12, 8, 12, 10, 14, 9, 16, 14, 14, 11, 15, 11, 13, 9 }, + { 1, 3, 6, 5, 6, 5, 8, 6, 7, 8, 9, 7, 8, 7, 8, 5, + 6, 6, 10, 8, 9, 7, 10, 7, 11, 10, 12, 9, 11, 8, 9, 5, + 5, 6, 10, 9, 10, 8, 12, 10, 12, 12, 14, 12, 13, 11, 14, 10, + 9, 8, 12, 9, 11, 7, 13, 8, 13, 12, 14, 11, 14, 9, 13, 6 }, + { 1, 4, 6, 6, 4, 4, 7, 5, 7, 7, 9, 8, 7, 5, 8, 5, + 7, 8, 10, 9, 9, 6, 9, 6, 11, 9, 10, 8, 9, 5, 8, 5, + 7, 12, 13, 13, 13, 11, 13, 12, 13, 13, 13, 13, 13, 13, 13, 11, + 12, 12, 13, 12, 13, 11, 12, 10, 13, 12, 12, 10, 12, 10, 10, 8 } + }, + { + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 5, 7, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 } + }, + { + { 9, 6, 7, 4, 10, 7, 9, 5, 10, 7, 9, 6, 11, 7, 8, 3, + 10, 7, 9, 6, 10, 6, 10, 5, 12, 8, 10, 6, 11, 6, 9, 3, + 11, 8, 9, 7, 13, 8, 12, 7, 13, 10, 12, 8, 13, 9, 11, 4, + 11, 8, 10, 7, 12, 6, 11, 4, 13, 8, 12, 7, 12, 6, 10, 2 }, + { 2, 3, 6, 4, 5, 4, 7, 4, 7, 7, 9, 7, 8, 5, 8, 4, + 5, 6, 8, 7, 7, 6, 8, 6, 10, 9, 11, 9, 10, 7, 10, 5, + 7, 6, 11, 8, 9, 7, 11, 8, 13, 12, 14, 12, 13, 10, 13, 7, + 9, 8, 11, 9, 10, 8, 12, 7, 13, 12, 14, 10, 12, 9, 13, 5 }, + { 2, 3, 5, 4, 6, 5, 7, 5, 7, 7, 8, 6, 8, 7, 8, 4, + 5, 5, 7, 6, 8, 6, 9, 6, 9, 8, 10, 8, 10, 8, 9, 4, + 6, 6, 9, 7, 10, 8, 11, 8, 11, 10, 11, 9, 12, 10, 11, 7, + 9, 8, 10, 8, 10, 7, 11, 7, 12, 10, 12, 9, 12, 9, 11, 5 }, + { 1, 3, 5, 6, 5, 5, 7, 5, 7, 7, 9, 7, 8, 5, 9, 5, + 6, 8, 10, 10, 9, 7, 11, 6, 11, 10, 12, 9, 11, 6, 11, 5, + 8, 10, 12, 11, 11, 10, 13, 10, 14, 13, 14, 12, 14, 11, 14, 8, + 11, 12, 14, 13, 13, 11, 14, 9, 14, 14, 14, 12, 14, 10, 13, 6 } + } + }, + { + { + { 7, 4, 7, 4, 9, 5, 10, 4, 9, 7, 10, 7, 11, 7, 12, 5, + 7, 4, 9, 5, 8, 5, 10, 4, 9, 8, 11, 7, 10, 7, 11, 5, + 8, 5, 10, 6, 10, 6, 12, 5, 12, 9, 14, 8, 12, 8, 13, 5, + 9, 5, 11, 5, 10, 5, 11, 3, 11, 8, 12, 7, 11, 7, 14, 4 }, + { 1, 3, 4, 4, 4, 5, 6, 6, 6, 8, 7, 8, 8, 8, 8, 7, + 6, 7, 8, 7, 8, 8, 10, 8, 9, 10, 10, 11, 10, 10, 11, 10, + 8, 9, 12, 9, 12, 11, 14, 11, 14, 14, 14, 14, 14, 13, 14, 13, + 10, 9, 13, 9, 14, 10, 14, 10, 14, 14, 14, 13, 14, 13, 14, 10 }, + { 1, 3, 5, 5, 5, 5, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, + 6, 6, 8, 8, 7, 6, 8, 6, 8, 8, 9, 8, 8, 6, 8, 6, + 7, 8, 11, 11, 11, 10, 14, 12, 13, 14, 14, 12, 14, 13, 14, 11, + 10, 9, 13, 11, 11, 8, 13, 9, 14, 13, 14, 12, 13, 10, 14, 9 }, + { 1, 3, 5, 6, 3, 4, 7, 7, 6, 7, 9, 10, 7, 7, 10, 9, + 5, 7, 8, 9, 7, 7, 9, 10, 8, 9, 10, 11, 9, 9, 12, 10, + 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, 14, 14, 13 } + }, + { + { 3, 4, 5, 5, 4, 5, 6, 5, 5, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 7, 7, 7, 7, 4, + 8, 9, 9, 8, 9, 9, 10, 8, 9, 10, 9, 8, 9, 8, 8, 6, + 9, 10, 10, 8, 10, 8, 10, 7, 10, 10, 9, 8, 9, 8, 8, 4 }, + { 3, 5, 4, 5, 5, 5, 6, 5, 4, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 7, 7, 7, 7, 8, 7, 7, 8, 7, 6, 7, 7, 7, 4, + 8, 9, 9, 9, 9, 9, 10, 8, 9, 10, 9, 8, 9, 8, 8, 6, + 9, 10, 10, 8, 10, 9, 10, 7, 10, 10, 9, 7, 9, 8, 8, 4 }, + { 3, 4, 5, 5, 4, 5, 6, 5, 5, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 7, 7, 7, 7, 8, 7, 7, 8, 7, 7, 7, 7, 7, 4, + 7, 9, 9, 9, 9, 9, 10, 8, 9, 10, 9, 8, 8, 8, 8, 6, + 9, 9, 10, 9, 9, 9, 10, 7, 10, 10, 9, 8, 8, 7, 8, 4 }, + { 3, 5, 4, 5, 5, 5, 6, 6, 4, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 7, 7, 7, 7, 8, 7, 7, 8, 7, 7, 7, 7, 6, 4, + 7, 9, 9, 9, 9, 9, 10, 8, 9, 10, 9, 8, 9, 8, 8, 5, + 9, 10, 10, 9, 10, 9, 10, 8, 10, 10, 9, 8, 8, 8, 7, 4 } + }, + { + { 7, 4, 6, 4, 8, 5, 8, 4, 9, 6, 8, 5, 9, 6, 7, 3, + 8, 4, 9, 5, 9, 5, 9, 5, 10, 7, 10, 6, 10, 7, 9, 4, + 9, 6, 10, 7, 11, 6, 11, 5, 13, 9, 11, 8, 12, 8, 10, 5, + 9, 6, 11, 6, 10, 6, 11, 5, 13, 8, 12, 7, 12, 7, 11, 4 }, + { 1, 3, 5, 5, 4, 4, 8, 5, 8, 8, 9, 7, 8, 7, 9, 5, + 6, 7, 9, 8, 8, 7, 11, 8, 11, 10, 12, 11, 11, 9, 12, 7, + 8, 9, 13, 10, 11, 9, 13, 10, 14, 14, 15, 13, 14, 11, 14, 8, + 10, 10, 12, 9, 12, 10, 13, 9, 15, 14, 15, 11, 15, 11, 14, 7 }, + { 1, 3, 5, 5, 6, 6, 7, 6, 6, 7, 7, 6, 7, 7, 7, 5, + 6, 6, 9, 8, 9, 7, 9, 7, 10, 9, 10, 8, 9, 7, 8, 5, + 7, 8, 11, 10, 11, 9, 13, 10, 11, 12, 11, 11, 13, 11, 12, 8, + 9, 8, 12, 10, 11, 8, 12, 9, 14, 12, 14, 11, 13, 10, 12, 7 }, + { 1, 3, 6, 6, 4, 3, 7, 5, 7, 7, 9, 8, 8, 6, 9, 6, + 7, 8, 10, 10, 8, 7, 10, 8, 10, 9, 12, 10, 10, 8, 11, 7, + 10, 11, 13, 12, 11, 10, 14, 11, 14, 14, 14, 13, 14, 12, 13, 9, + 13, 13, 14, 13, 14, 11, 14, 11, 14, 13, 14, 13, 14, 11, 14, 9 } + } + }, + { + { + { 7, 3, 7, 4, 9, 4, 11, 4, 10, 8, 11, 7, 13, 7, 13, 5, + 6, 4, 9, 5, 9, 5, 12, 5, 11, 9, 13, 8, 13, 8, 15, 6, + 8, 5, 11, 5, 12, 6, 14, 6, 14, 10, 15, 9, 15, 9, 15, 6, + 8, 4, 12, 4, 12, 4, 15, 4, 13, 9, 15, 8, 15, 8, 15, 5 }, + { 1, 3, 4, 3, 5, 5, 7, 5, 8, 9, 8, 8, 9, 8, 9, 7, + 6, 7, 10, 7, 10, 8, 13, 9, 12, 13, 13, 13, 13, 13, 13, 11, + 9, 9, 12, 9, 12, 11, 13, 12, 13, 13, 13, 13, 13, 13, 13, 12, + 11, 9, 12, 9, 13, 11, 13, 10, 13, 13, 13, 13, 13, 13, 13, 11 }, + { 1, 3, 5, 5, 5, 5, 7, 7, 5, 7, 7, 7, 7, 8, 7, 8, + 4, 6, 8, 8, 6, 6, 9, 9, 8, 9, 11, 10, 9, 9, 11, 9, + 7, 9, 13, 12, 12, 9, 13, 12, 13, 14, 13, 12, 14, 14, 14, 12, + 10, 9, 13, 11, 12, 9, 13, 11, 13, 13, 13, 13, 13, 12, 13, 11 }, + { 1, 3, 5, 6, 3, 4, 7, 7, 6, 7, 10, 9, 8, 7, 10, 8, + 4, 9, 11, 11, 8, 10, 11, 12, 10, 11, 12, 12, 12, 12, 12, 11, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 } + }, + { + { 2, 4, 4, 5, 4, 5, 6, 5, 5, 6, 5, 5, 5, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 8, 7, 7, 8, 8, 7, 7, 7, 8, 6, + 7, 9, 9, 8, 9, 9, 10, 8, 9, 10, 9, 9, 9, 9, 9, 6, + 9, 10, 10, 9, 10, 9, 10, 8, 10, 10, 9, 9, 9, 9, 9, 6 }, + { 2, 4, 4, 5, 5, 5, 6, 5, 4, 6, 5, 5, 5, 6, 5, 4, + 6, 7, 7, 7, 8, 8, 9, 7, 8, 9, 8, 7, 7, 8, 7, 6, + 7, 9, 9, 9, 9, 9, 10, 9, 9, 10, 9, 8, 9, 9, 8, 6, + 9, 10, 10, 9, 10, 9, 10, 9, 10, 10, 9, 8, 9, 9, 9, 6 }, + { 2, 4, 4, 5, 4, 5, 6, 5, 4, 6, 5, 6, 5, 5, 6, 4, + 6, 7, 8, 7, 7, 8, 9, 7, 8, 9, 8, 8, 7, 7, 8, 6, + 7, 9, 9, 9, 9, 9, 10, 9, 9, 10, 9, 9, 9, 8, 9, 7, + 9, 10, 10, 9, 10, 9, 11, 9, 10, 11, 10, 9, 9, 8, 9, 6 }, + { 2, 5, 4, 5, 4, 5, 6, 6, 4, 6, 5, 5, 5, 6, 5, 4, + 6, 7, 7, 8, 7, 8, 8, 8, 7, 8, 8, 8, 7, 8, 7, 5, + 7, 9, 9, 9, 9, 9, 10, 9, 9, 10, 9, 8, 9, 9, 8, 6, + 9, 10, 10, 9, 10, 9, 10, 9, 10, 10, 9, 9, 9, 9, 8, 6 } + }, + { + { 6, 2, 6, 4, 7, 4, 8, 4, 9, 6, 8, 6, 9, 6, 8, 4, + 7, 4, 9, 5, 9, 5, 10, 6, 11, 8, 10, 7, 11, 7, 10, 5, + 8, 5, 10, 6, 10, 6, 11, 6, 12, 9, 12, 8, 12, 9, 11, 6, + 9, 6, 11, 7, 10, 6, 11, 6, 12, 10, 12, 8, 12, 9, 11, 6 }, + { 1, 3, 5, 4, 4, 5, 6, 5, 7, 8, 9, 7, 8, 7, 8, 5, + 6, 7, 10, 8, 9, 8, 11, 8, 12, 12, 13, 10, 13, 10, 12, 8, + 8, 9, 12, 9, 11, 10, 13, 9, 14, 14, 14, 11, 14, 12, 13, 9, + 10, 10, 11, 9, 12, 11, 13, 9, 14, 14, 14, 11, 14, 12, 13, 8 }, + { 1, 3, 5, 5, 5, 5, 7, 6, 6, 7, 6, 6, 7, 7, 7, 5, + 6, 6, 9, 8, 7, 7, 9, 7, 9, 9, 10, 9, 9, 8, 9, 7, + 7, 9, 11, 11, 11, 9, 12, 11, 11, 12, 12, 11, 13, 11, 12, 9, + 9, 8, 12, 11, 10, 9, 13, 10, 13, 13, 13, 12, 13, 11, 12, 9 }, + { 1, 3, 5, 6, 3, 4, 7, 5, 7, 7, 9, 8, 8, 6, 9, 6, + 6, 8, 11, 11, 9, 9, 12, 10, 11, 10, 13, 11, 12, 11, 12, 9, + 9, 11, 12, 11, 11, 10, 13, 11, 13, 13, 12, 12, 12, 12, 12, 10, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10 } + } + }, + { + { + { 8, 2, 7, 4, 9, 4, 12, 4, 12, 9, 14, 8, 14, 8, 15, 5, + 7, 4, 10, 5, 11, 5, 14, 5, 13, 10, 15, 9, 15, 9, 15, 6, + 8, 4, 12, 6, 12, 6, 15, 6, 15, 11, 15, 10, 15, 10, 15, 7, + 9, 4, 13, 5, 13, 5, 15, 5, 15, 10, 15, 9, 15, 8, 15, 5 }, + { 1, 2, 4, 4, 5, 6, 8, 6, 10, 10, 11, 9, 11, 10, 12, 8, + 7, 7, 11, 8, 12, 9, 13, 9, 13, 13, 13, 13, 13, 13, 13, 9, + 8, 8, 12, 9, 13, 11, 13, 10, 13, 13, 13, 13, 13, 13, 13, 12, + 10, 9, 13, 9, 13, 10, 13, 10, 13, 13, 13, 13, 13, 12, 13, 11 }, + { 1, 2, 5, 5, 5, 5, 9, 7, 6, 8, 8, 8, 8, 9, 10, 8, + 6, 6, 11, 9, 8, 7, 12, 9, 13, 11, 13, 11, 12, 10, 13, 9, + 7, 8, 13, 11, 13, 9, 13, 11, 13, 13, 13, 11, 13, 12, 13, 11, + 10, 9, 13, 11, 13, 9, 13, 10, 13, 13, 13, 13, 13, 12, 13, 11 }, + { 1, 2, 6, 7, 3, 5, 9, 7, 8, 10, 10, 10, 10, 9, 11, 9, + 7, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 10 } + }, + { + { 2, 4, 4, 5, 4, 5, 6, 5, 4, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 8, 7, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7, + 7, 8, 9, 8, 8, 8, 10, 8, 8, 10, 9, 9, 9, 9, 9, 7, + 9, 10, 10, 9, 10, 9, 11, 9, 10, 11, 10, 10, 10, 10, 10, 8 }, + { 2, 4, 4, 4, 4, 5, 6, 5, 4, 6, 5, 5, 5, 6, 5, 4, + 6, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7, + 7, 8, 8, 8, 9, 9, 10, 9, 9, 10, 9, 9, 9, 9, 9, 7, + 9, 10, 10, 10, 10, 10, 11, 10, 10, 11, 10, 9, 10, 10, 10, 8 }, + { 2, 4, 4, 5, 4, 5, 6, 5, 4, 6, 5, 6, 4, 5, 5, 4, + 6, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7, + 7, 8, 9, 9, 8, 8, 10, 9, 9, 10, 9, 9, 9, 9, 9, 7, + 9, 10, 10, 10, 10, 9, 11, 10, 10, 11, 10, 10, 10, 10, 10, 8 }, + { 2, 4, 4, 5, 4, 5, 6, 5, 4, 6, 5, 5, 4, 6, 5, 4, + 6, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7, + 7, 9, 9, 9, 8, 9, 10, 9, 8, 10, 9, 9, 9, 9, 8, 7, + 9, 10, 10, 10, 10, 10, 11, 10, 10, 11, 10, 10, 10, 10, 9, 8 } + }, + { + { 7, 1, 7, 4, 7, 4, 9, 5, 9, 7, 9, 6, 10, 7, 9, 5, + 7, 4, 9, 6, 9, 6, 10, 7, 11, 9, 11, 8, 11, 9, 11, 7, + 8, 5, 10, 7, 10, 7, 11, 7, 12, 10, 11, 9, 12, 10, 11, 7, + 9, 6, 11, 7, 11, 8, 12, 8, 13, 10, 12, 9, 13, 10, 12, 8 }, + { 1, 3, 4, 4, 4, 5, 6, 5, 8, 8, 8, 7, 9, 8, 8, 6, + 7, 8, 9, 8, 10, 9, 11, 8, 13, 12, 12, 10, 13, 11, 12, 8, + 7, 9, 10, 8, 11, 10, 12, 9, 14, 14, 13, 10, 14, 12, 12, 9, + 9, 10, 11, 9, 12, 11, 14, 9, 14, 14, 14, 11, 14, 12, 13, 9 }, + { 1, 3, 4, 5, 5, 5, 7, 6, 6, 7, 6, 6, 7, 7, 7, 5, + 6, 6, 9, 8, 8, 8, 11, 9, 10, 10, 11, 10, 11, 10, 11, 9, + 7, 8, 10, 11, 10, 9, 13, 11, 11, 12, 12, 12, 12, 11, 12, 10, + 8, 9, 12, 11, 10, 9, 13, 12, 13, 13, 13, 13, 13, 12, 13, 11 }, + { 1, 2, 5, 6, 4, 4, 7, 7, 7, 8, 8, 8, 8, 7, 8, 7, + 8, 10, 12, 12, 12, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, + 9, 11, 12, 12, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 } + } + }, + { + { + { 9, 2, 7, 4, 9, 4, 13, 5, 12, 10, 14, 9, 14, 9, 15, 6, + 7, 3, 11, 5, 12, 5, 15, 6, 15, 11, 15, 10, 15, 10, 15, 7, + 7, 4, 12, 6, 12, 6, 15, 7, 15, 11, 15, 11, 15, 11, 15, 8, + 9, 3, 13, 5, 13, 5, 15, 6, 15, 11, 15, 10, 15, 10, 15, 6 }, + { 1, 2, 4, 4, 6, 5, 9, 6, 10, 11, 12, 10, 11, 9, 12, 8, + 8, 7, 10, 8, 12, 9, 12, 9, 12, 12, 12, 12, 12, 12, 12, 10, + 7, 8, 12, 9, 12, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 9, 12, 8, 12, 11, 12, 11, 12, 12, 12, 12, 12, 12, 12, 12 }, + { 1, 2, 5, 5, 6, 4, 10, 7, 8, 9, 9, 8, 10, 11, 11, 7, + 6, 6, 10, 9, 10, 8, 11, 10, 11, 11, 11, 10, 11, 11, 11, 10, + 7, 8, 11, 10, 11, 10, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, + 10, 8, 11, 10, 11, 9, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, + { 1, 3, 7, 5, 4, 5, 8, 7, 8, 7, 8, 8, 8, 8, 8, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 } + }, + { + { 1, 4, 4, 5, 4, 5, 6, 6, 5, 7, 6, 7, 5, 7, 7, 6, + 6, 8, 8, 8, 8, 9, 10, 9, 8, 10, 9, 10, 9, 9, 9, 9, + 7, 9, 9, 9, 9, 9, 11, 9, 9, 10, 10, 10, 10, 10, 10, 9, + 9, 10, 10, 10, 10, 10, 12, 10, 11, 12, 11, 11, 11, 11, 11, 10 }, + { 1, 4, 4, 5, 5, 6, 6, 6, 4, 7, 5, 6, 5, 7, 6, 6, + 7, 8, 8, 9, 9, 9, 10, 9, 8, 10, 9, 9, 9, 10, 10, 9, + 7, 9, 9, 9, 9, 10, 10, 10, 9, 11, 9, 10, 10, 10, 10, 9, + 9, 10, 10, 11, 11, 11, 12, 11, 11, 12, 11, 11, 11, 11, 11, 10 }, + { 1, 4, 5, 5, 4, 5, 7, 6, 4, 7, 6, 7, 5, 6, 6, 6, + 6, 8, 9, 9, 8, 9, 10, 9, 8, 10, 9, 10, 9, 9, 10, 9, + 7, 9, 9, 10, 9, 9, 11, 10, 9, 11, 10, 10, 9, 10, 10, 9, + 9, 10, 11, 11, 10, 10, 12, 11, 11, 12, 11, 11, 11, 11, 11, 10 }, + { 1, 4, 4, 5, 5, 6, 6, 7, 4, 7, 5, 6, 5, 7, 6, 6, + 6, 8, 8, 9, 8, 9, 10, 10, 8, 10, 9, 10, 9, 10, 9, 9, + 7, 9, 9, 10, 9, 10, 10, 10, 9, 11, 9, 10, 9, 10, 10, 9, + 9, 11, 11, 11, 11, 11, 12, 11, 10, 12, 11, 12, 11, 12, 11, 10 } + }, + { + { 6, 1, 6, 4, 7, 4, 8, 5, 9, 7, 9, 6, 10, 7, 9, 6, + 6, 4, 9, 6, 9, 6, 10, 7, 11, 9, 11, 9, 12, 9, 11, 7, + 7, 5, 9, 7, 10, 7, 11, 8, 12, 10, 11, 9, 12, 10, 12, 8, + 8, 6, 10, 8, 10, 8, 12, 8, 12, 10, 12, 10, 13, 11, 13, 9 }, + { 1, 3, 4, 3, 5, 5, 7, 6, 8, 9, 8, 7, 9, 9, 9, 7, + 7, 7, 9, 7, 10, 9, 11, 9, 12, 12, 12, 10, 13, 12, 12, 10, + 7, 8, 10, 8, 11, 10, 12, 10, 13, 13, 12, 10, 13, 13, 12, 10, + 8, 9, 10, 8, 12, 12, 13, 10, 13, 13, 13, 11, 13, 13, 13, 11 }, + { 1, 3, 4, 6, 5, 4, 7, 7, 5, 7, 7, 7, 7, 7, 7, 6, + 5, 6, 9, 10, 9, 8, 12, 11, 10, 11, 11, 11, 12, 11, 11, 10, + 6, 9, 11, 12, 10, 10, 13, 11, 11, 13, 12, 12, 12, 11, 12, 11, + 8, 9, 12, 13, 11, 10, 13, 12, 13, 13, 13, 13, 13, 12, 13, 12 }, + { 1, 2, 5, 6, 4, 5, 7, 7, 7, 7, 8, 7, 7, 7, 8, 6, + 8, 10, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 8, 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 } + } + }, + { + { + { 9, 1, 8, 5, 8, 4, 14, 7, 13, 10, 13, 10, 15, 10, 15, 8, + 6, 3, 12, 7, 11, 6, 15, 8, 14, 12, 15, 11, 15, 11, 15, 9, + 6, 4, 12, 7, 12, 7, 15, 9, 15, 12, 15, 11, 15, 12, 15, 10, + 7, 4, 13, 6, 12, 6, 15, 8, 15, 12, 15, 11, 15, 11, 15, 8 }, + { 1, 2, 5, 4, 6, 5, 10, 6, 10, 10, 10, 10, 10, 10, 10, 10, + 7, 7, 10, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 6, 8, 10, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 8, 10, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11 }, + { 1, 2, 5, 5, 6, 5, 9, 8, 8, 8, 8, 8, 9, 8, 9, 8, + 6, 6, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 6, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }, + { 1, 4, 7, 8, 6, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 8, 8 } + }, + { + { 1, 3, 4, 5, 4, 6, 7, 7, 4, 7, 6, 8, 6, 8, 8, 8, + 6, 9, 9, 10, 9, 9, 11, 11, 9, 11, 10, 11, 10, 11, 11, 11, + 6, 9, 9, 10, 9, 10, 12, 11, 9, 11, 10, 12, 11, 11, 12, 11, + 8, 11, 11, 10, 11, 11, 12, 12, 11, 13, 12, 13, 12, 13, 13, 12 }, + { 1, 4, 4, 5, 4, 6, 6, 7, 4, 7, 5, 7, 5, 7, 7, 7, + 6, 8, 8, 9, 9, 9, 11, 10, 9, 11, 9, 11, 10, 11, 11, 11, + 6, 9, 9, 10, 9, 10, 11, 11, 9, 11, 10, 11, 10, 12, 12, 11, + 8, 11, 10, 11, 11, 11, 13, 12, 11, 12, 11, 12, 12, 13, 12, 11 }, + { 1, 4, 4, 5, 4, 5, 7, 7, 4, 7, 6, 7, 5, 7, 7, 7, + 6, 8, 9, 10, 8, 9, 11, 10, 8, 11, 10, 11, 9, 11, 11, 10, + 6, 8, 9, 10, 8, 10, 11, 11, 9, 11, 10, 12, 10, 10, 11, 11, + 8, 10, 11, 11, 10, 11, 12, 12, 10, 12, 11, 12, 11, 11, 12, 11 }, + { 1, 4, 4, 5, 4, 6, 6, 7, 4, 7, 5, 7, 5, 7, 7, 7, + 6, 9, 9, 10, 8, 10, 11, 11, 8, 12, 9, 11, 9, 11, 10, 11, + 6, 9, 9, 10, 9, 10, 11, 11, 9, 11, 10, 11, 10, 11, 11, 11, + 8, 11, 11, 12, 10, 11, 12, 12, 10, 12, 11, 12, 11, 12, 12, 11 } + }, + { + { 6, 1, 6, 4, 6, 4, 9, 6, 9, 8, 10, 8, 10, 8, 11, 8, + 5, 4, 9, 7, 9, 7, 11, 9, 11, 10, 12, 10, 12, 11, 14, 10, + 5, 4, 9, 7, 9, 7, 12, 9, 12, 10, 13, 11, 13, 12, 14, 11, + 7, 5, 10, 8, 10, 8, 13, 10, 12, 11, 13, 11, 14, 12, 14, 11 }, + { 1, 2, 4, 4, 5, 7, 8, 8, 8, 9, 8, 8, 9, 9, 9, 8, + 6, 8, 10, 8, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 7, 9, 10, 9, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, + 9, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, + { 1, 2, 5, 7, 5, 5, 9, 9, 5, 7, 6, 7, 7, 7, 8, 8, + 6, 8, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 6, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 9, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, + { 1, 3, 5, 6, 4, 5, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9 } + } + } +}; + +typedef struct { + uint8_t l0[2][864]; + uint8_t l12[2][108]; + uint8_t l3[2][108]; + uint8_t esc[32]; +} CoeffLens; + +static const CoeffLens rv60_intra_lens[5] = { + { + { + { 0, 7, 5, 7, 5, 7, 6, 6, 7, 9, 7, 8, 8, 9, 7, 7, + 10, 13, 10, 12, 11, 12, 10, 10, 6, 9, 6, 8, 7, 8, 7, 7, + 9, 11, 8, 9, 9, 10, 8, 8, 12, 14, 12, 13, 13, 13, 11, 10, + 9, 12, 9, 11, 10, 11, 9, 9, 12, 14, 10, 11, 12, 12, 10, 9, + 12, 15, 12, 13, 13, 14, 11, 10, 6, 9, 7, 8, 7, 8, 7, 7, + 8, 11, 9, 9, 9, 9, 8, 8, 12, 14, 12, 13, 12, 13, 11, 10, + 8, 10, 8, 9, 9, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 13, 13, 13, 13, 11, 10, 11, 13, 11, 11, 12, 12, 10, 9, + 13, 15, 11, 12, 13, 13, 11, 10, 15, 15, 13, 13, 14, 15, 12, 10, + 9, 12, 10, 11, 9, 11, 9, 9, 12, 14, 12, 12, 11, 12, 10, 9, + 12, 15, 12, 14, 12, 13, 11, 10, 11, 14, 11, 12, 11, 12, 10, 9, + 13, 15, 12, 13, 12, 12, 11, 10, 15, 15, 14, 14, 13, 14, 12, 10, + 12, 15, 12, 13, 12, 13, 11, 10, 14, 15, 13, 13, 13, 14, 11, 10, + 14, 15, 13, 14, 14, 14, 11, 9, 5, 8, 6, 7, 7, 8, 7, 7, + 8, 10, 8, 9, 9, 9, 8, 8, 12, 14, 11, 12, 12, 13, 11, 10, + 6, 10, 7, 8, 8, 9, 8, 7, 9, 11, 9, 10, 10, 10, 9, 8, + 13, 15, 12, 13, 13, 13, 11, 10, 10, 13, 10, 11, 11, 12, 10, 9, + 12, 14, 11, 11, 12, 13, 10, 9, 14, 15, 12, 13, 14, 14, 12, 10, + 7, 10, 8, 9, 8, 9, 8, 7, 9, 11, 9, 10, 9, 10, 9, 8, + 13, 15, 13, 13, 13, 13, 11, 10, 8, 11, 9, 10, 9, 10, 8, 8, + 10, 12, 10, 11, 10, 11, 9, 8, 14, 15, 13, 13, 13, 14, 12, 11, + 11, 14, 11, 11, 12, 12, 10, 9, 12, 15, 11, 12, 12, 13, 10, 9, + 15, 15, 13, 13, 14, 15, 12, 10, 10, 13, 11, 12, 10, 11, 10, 9, + 12, 14, 12, 13, 11, 12, 10, 10, 14, 15, 13, 14, 13, 13, 12, 10, + 11, 14, 12, 12, 11, 12, 10, 9, 12, 15, 12, 13, 12, 12, 11, 10, + 15, 15, 14, 14, 13, 13, 11, 10, 13, 15, 12, 13, 13, 13, 11, 10, + 14, 15, 13, 13, 13, 13, 11, 10, 15, 15, 13, 13, 13, 14, 10, 9, + 7, 10, 8, 10, 9, 10, 9, 8, 10, 12, 10, 11, 11, 11, 10, 9, + 12, 15, 12, 14, 13, 14, 12, 11, 9, 12, 9, 10, 10, 11, 9, 9, + 11, 13, 11, 11, 11, 12, 10, 9, 15, 15, 14, 14, 14, 14, 13, 11, + 11, 14, 10, 12, 11, 12, 10, 9, 13, 15, 12, 12, 13, 13, 11, 10, + 14, 15, 13, 14, 14, 15, 12, 10, 9, 12, 9, 10, 10, 11, 9, 9, + 11, 13, 11, 11, 11, 12, 10, 9, 15, 15, 14, 14, 14, 14, 13, 11, + 10, 12, 10, 11, 10, 11, 10, 9, 11, 14, 11, 12, 11, 12, 11, 10, + 15, 15, 14, 14, 14, 15, 12, 11, 12, 15, 11, 12, 12, 13, 11, 10, + 13, 15, 12, 13, 13, 13, 11, 10, 15, 15, 13, 14, 15, 15, 12, 10, + 11, 14, 11, 12, 11, 12, 10, 10, 13, 15, 13, 13, 12, 13, 11, 10, + 14, 15, 14, 15, 13, 14, 12, 11, 12, 15, 12, 13, 11, 13, 11, 10, + 13, 15, 13, 13, 12, 13, 11, 10, 15, 15, 14, 15, 13, 14, 12, 10, + 13, 15, 12, 13, 13, 13, 11, 10, 14, 15, 13, 13, 13, 14, 11, 10, + 15, 15, 13, 13, 13, 14, 10, 9, 10, 13, 10, 11, 11, 11, 10, 9, + 12, 14, 12, 12, 12, 12, 10, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 10, 13, 10, 11, 10, 11, 10, 9, 12, 14, 12, 12, 12, 12, 10, 9, + 15, 15, 14, 14, 14, 14, 12, 10, 11, 14, 11, 11, 11, 12, 10, 8, + 13, 15, 11, 12, 12, 12, 10, 9, 15, 15, 13, 13, 13, 14, 10, 8, + 10, 13, 10, 11, 11, 12, 10, 9, 12, 14, 11, 12, 12, 12, 10, 9, + 15, 15, 14, 14, 14, 14, 12, 10, 10, 13, 10, 11, 11, 12, 10, 9, + 12, 15, 11, 12, 12, 12, 10, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 11, 14, 11, 11, 11, 12, 10, 8, 12, 15, 11, 12, 12, 12, 10, 8, + 15, 15, 12, 12, 13, 13, 10, 8, 11, 14, 11, 12, 11, 12, 10, 9, + 13, 15, 12, 12, 12, 12, 10, 9, 15, 15, 13, 14, 13, 13, 10, 9, + 11, 14, 11, 12, 11, 12, 10, 9, 12, 15, 12, 12, 11, 12, 10, 9, + 15, 15, 13, 13, 12, 13, 10, 8, 12, 14, 11, 11, 11, 12, 9, 8, + 11, 14, 10, 11, 11, 12, 9, 7, 13, 15, 10, 11, 10, 11, 8, 6 }, + { 0, 7, 4, 8, 5, 9, 8, 9, 6, 10, 8, 10, 9, 12, 10, 11, + 14, 15, 14, 14, 15, 15, 14, 13, 5, 10, 6, 10, 8, 11, 9, 10, + 9, 12, 9, 11, 11, 13, 11, 11, 15, 15, 14, 15, 15, 15, 14, 14, + 10, 14, 10, 12, 12, 14, 11, 12, 12, 15, 11, 13, 14, 15, 12, 13, + 15, 15, 14, 15, 15, 15, 14, 14, 5, 10, 8, 10, 7, 11, 9, 10, + 9, 12, 10, 11, 10, 13, 11, 11, 15, 15, 14, 15, 15, 15, 14, 14, + 8, 12, 9, 11, 10, 12, 10, 11, 10, 14, 11, 12, 11, 14, 11, 12, + 15, 15, 14, 15, 15, 15, 14, 14, 12, 15, 11, 13, 13, 15, 12, 13, + 13, 15, 12, 14, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 14, + 10, 14, 12, 13, 10, 13, 11, 12, 12, 15, 13, 14, 12, 14, 12, 13, + 15, 15, 15, 15, 15, 15, 14, 14, 12, 15, 12, 14, 12, 14, 12, 13, + 13, 15, 13, 14, 12, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 14, + 14, 15, 14, 15, 14, 15, 13, 13, 15, 15, 14, 15, 14, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 14, 13, 2, 8, 5, 9, 6, 10, 8, 10, + 7, 11, 8, 10, 9, 12, 10, 11, 15, 15, 14, 14, 14, 15, 13, 13, + 5, 10, 7, 10, 8, 11, 9, 10, 9, 12, 9, 11, 11, 13, 11, 11, + 15, 15, 14, 14, 15, 15, 14, 14, 10, 14, 9, 12, 12, 14, 11, 12, + 12, 15, 11, 13, 13, 15, 12, 13, 15, 15, 14, 15, 15, 15, 14, 14, + 5, 10, 8, 10, 8, 11, 9, 10, 9, 13, 10, 12, 10, 13, 11, 11, + 15, 15, 14, 15, 15, 15, 14, 14, 7, 12, 9, 11, 10, 12, 10, 11, + 10, 14, 10, 12, 11, 13, 11, 12, 15, 15, 14, 15, 15, 15, 14, 14, + 11, 15, 11, 13, 13, 15, 12, 12, 13, 15, 12, 14, 14, 15, 12, 13, + 15, 15, 14, 15, 15, 15, 14, 14, 10, 14, 12, 13, 10, 13, 11, 12, + 12, 15, 13, 14, 12, 14, 12, 13, 15, 15, 15, 15, 14, 15, 14, 14, + 11, 15, 12, 13, 12, 14, 12, 12, 13, 15, 13, 14, 12, 14, 12, 13, + 15, 15, 15, 15, 14, 15, 14, 14, 14, 15, 14, 15, 14, 15, 13, 13, + 14, 15, 14, 15, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 13, 13, + 4, 10, 7, 10, 8, 11, 9, 10, 9, 12, 10, 12, 10, 13, 11, 11, + 15, 15, 14, 15, 15, 15, 14, 14, 7, 12, 8, 11, 10, 12, 10, 11, + 10, 13, 10, 12, 12, 14, 11, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 10, 15, 10, 13, 12, 15, 12, 12, 12, 15, 12, 13, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 14, 7, 12, 9, 11, 9, 12, 10, 11, + 10, 14, 11, 12, 11, 13, 11, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 8, 13, 10, 12, 10, 13, 11, 12, 10, 14, 11, 13, 12, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 14, 14, 11, 15, 11, 13, 13, 15, 12, 13, + 12, 15, 12, 14, 14, 15, 13, 13, 15, 15, 14, 15, 15, 15, 14, 14, + 10, 15, 12, 13, 10, 14, 12, 12, 12, 15, 13, 14, 12, 14, 12, 13, + 15, 15, 15, 15, 15, 15, 14, 14, 11, 15, 12, 14, 12, 14, 12, 13, + 12, 15, 13, 15, 12, 15, 13, 13, 15, 15, 15, 15, 14, 15, 14, 14, + 14, 15, 14, 15, 14, 15, 13, 13, 14, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 14, 15, 14, 15, 13, 13, 7, 11, 8, 11, 9, 12, 10, 10, + 10, 13, 10, 12, 11, 13, 11, 11, 15, 15, 14, 14, 14, 15, 13, 13, + 8, 12, 9, 11, 10, 12, 10, 11, 10, 14, 11, 12, 11, 13, 11, 12, + 15, 15, 14, 14, 14, 15, 13, 13, 10, 14, 10, 12, 11, 13, 10, 11, + 12, 15, 11, 13, 12, 14, 11, 12, 15, 15, 14, 14, 14, 15, 12, 12, + 8, 12, 9, 11, 9, 12, 10, 11, 10, 14, 11, 12, 11, 13, 11, 12, + 15, 15, 14, 14, 14, 15, 13, 13, 8, 13, 10, 12, 10, 13, 10, 11, + 10, 14, 11, 12, 11, 14, 11, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 10, 14, 10, 12, 11, 14, 11, 11, 11, 15, 11, 13, 12, 14, 11, 11, + 15, 15, 13, 14, 14, 15, 12, 12, 9, 14, 10, 12, 10, 13, 10, 11, + 12, 15, 12, 13, 11, 13, 11, 11, 15, 15, 14, 15, 13, 14, 12, 12, + 10, 14, 11, 13, 10, 13, 10, 11, 11, 15, 12, 13, 11, 13, 11, 11, + 14, 15, 14, 15, 13, 14, 12, 12, 11, 15, 11, 13, 11, 13, 10, 10, + 11, 15, 11, 13, 11, 13, 10, 10, 13, 15, 11, 12, 11, 12, 10, 9 } + }, + { + { 0, 4, 7, 3, 5, 9, 6, 8, 9, 3, 5, 9, 5, 6, 9, 8, + 9, 10, 6, 8, 9, 7, 9, 10, 9, 10, 10, 3, 5, 8, 4, 6, + 9, 7, 8, 10, 5, 6, 9, 6, 7, 10, 8, 9, 10, 7, 8, 10, + 8, 9, 10, 9, 10, 10, 6, 8, 9, 7, 8, 11, 8, 9, 10, 7, + 8, 11, 8, 9, 11, 9, 10, 11, 8, 10, 10, 9, 10, 11, 10, 10, + 10, 8, 9, 10, 8, 9, 10, 8, 9, 9, 8, 9, 11, 8, 9, 10, + 8, 9, 9, 9, 9, 10, 9, 9, 9, 8, 8, 7 }, + { 0, 4, 10, 2, 6, 10, 7, 9, 12, 3, 6, 10, 6, 8, 11, 9, + 10, 12, 8, 9, 12, 9, 10, 13, 12, 12, 13, 2, 6, 10, 4, 7, + 11, 8, 10, 12, 5, 7, 11, 6, 8, 11, 9, 10, 13, 8, 10, 12, + 10, 11, 13, 12, 12, 13, 6, 8, 12, 7, 9, 12, 9, 11, 13, 7, + 9, 12, 8, 10, 13, 10, 11, 13, 10, 11, 13, 11, 11, 13, 12, 12, + 13, 8, 10, 12, 9, 10, 13, 10, 11, 12, 9, 11, 13, 9, 11, 13, + 10, 11, 12, 10, 11, 13, 11, 11, 13, 11, 11, 12 } + }, + { + { 0, 4, 6, 3, 5, 8, 5, 8, 9, 4, 6, 8, 5, 7, 9, 8, + 9, 11, 6, 9, 9, 8, 9, 10, 9, 10, 10, 2, 5, 8, 4, 6, + 9, 7, 9, 10, 5, 7, 9, 6, 7, 10, 9, 9, 11, 8, 9, 10, + 9, 10, 11, 10, 11, 11, 5, 8, 9, 7, 9, 11, 8, 10, 11, 7, + 9, 11, 8, 9, 11, 10, 11, 12, 8, 11, 11, 10, 11, 12, 10, 11, + 11, 8, 10, 11, 9, 10, 11, 10, 10, 11, 9, 10, 11, 10, 10, 11, + 10, 10, 11, 10, 11, 11, 10, 11, 11, 10, 10, 9 }, + { 0, 5, 12, 2, 7, 13, 8, 11, 15, 4, 8, 13, 7, 9, 13, 11, + 12, 15, 10, 12, 15, 11, 12, 15, 13, 13, 15, 1, 7, 12, 4, 8, + 13, 9, 12, 15, 6, 9, 13, 8, 10, 13, 11, 12, 15, 11, 12, 15, + 11, 13, 15, 13, 14, 14, 7, 9, 13, 8, 10, 14, 11, 13, 15, 9, + 11, 14, 10, 11, 14, 12, 13, 15, 12, 13, 15, 12, 13, 15, 14, 14, + 15, 11, 11, 13, 11, 12, 14, 13, 14, 15, 12, 12, 14, 12, 13, 14, + 13, 14, 15, 13, 14, 15, 13, 14, 15, 14, 14, 14 } + }, + { 1, 2, 4, 4, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 11, 10, 10, 10, 12, 13, 15, 15, 14 } + }, + { + { + { 0, 6, 4, 7, 5, 7, 6, 6, 6, 9, 7, 9, 8, 9, 8, 8, + 12, 15, 13, 14, 13, 14, 12, 11, 5, 9, 6, 8, 7, 8, 7, 7, + 8, 11, 8, 10, 9, 10, 9, 9, 14, 15, 13, 14, 14, 14, 12, 12, + 10, 13, 9, 11, 11, 12, 10, 10, 12, 15, 10, 12, 12, 13, 11, 10, + 15, 15, 13, 13, 14, 15, 12, 11, 5, 9, 7, 8, 7, 8, 7, 7, + 8, 11, 9, 10, 9, 10, 8, 9, 14, 15, 13, 14, 13, 14, 12, 11, + 7, 11, 8, 10, 8, 10, 8, 8, 9, 12, 10, 11, 10, 11, 9, 9, + 15, 15, 13, 14, 13, 14, 12, 11, 11, 14, 11, 12, 12, 13, 11, 10, + 12, 15, 11, 13, 13, 14, 11, 11, 15, 15, 13, 14, 14, 15, 12, 11, + 10, 13, 11, 12, 9, 11, 10, 10, 12, 14, 12, 13, 10, 12, 11, 10, + 14, 15, 14, 15, 13, 13, 12, 11, 12, 14, 12, 13, 11, 12, 10, 10, + 12, 15, 12, 14, 11, 13, 11, 11, 15, 15, 14, 15, 13, 14, 12, 10, + 13, 15, 13, 14, 13, 14, 11, 10, 14, 15, 13, 14, 13, 14, 11, 10, + 15, 15, 13, 14, 13, 14, 11, 9, 4, 8, 6, 8, 6, 8, 7, 7, + 8, 10, 8, 10, 9, 10, 8, 8, 14, 15, 13, 14, 13, 14, 12, 11, + 6, 10, 7, 9, 8, 9, 8, 8, 9, 12, 9, 11, 10, 11, 9, 9, + 15, 15, 13, 14, 14, 14, 12, 11, 10, 13, 10, 11, 11, 13, 10, 10, + 12, 15, 11, 12, 12, 13, 11, 10, 15, 15, 13, 14, 14, 15, 12, 11, + 6, 10, 8, 9, 7, 9, 8, 8, 9, 12, 9, 11, 9, 11, 9, 9, + 15, 15, 14, 14, 13, 14, 12, 11, 8, 11, 9, 10, 9, 10, 9, 9, + 10, 12, 10, 11, 10, 11, 10, 10, 15, 15, 13, 14, 13, 14, 12, 11, + 11, 14, 11, 12, 12, 13, 10, 10, 12, 15, 11, 12, 12, 14, 11, 10, + 15, 15, 12, 14, 14, 15, 11, 10, 10, 14, 11, 12, 10, 11, 10, 10, + 12, 15, 12, 13, 11, 12, 11, 10, 15, 15, 14, 15, 13, 13, 12, 11, + 11, 14, 12, 13, 11, 12, 11, 10, 12, 15, 12, 13, 11, 13, 11, 10, + 15, 15, 14, 15, 12, 13, 11, 10, 13, 15, 13, 14, 13, 14, 11, 10, + 14, 15, 12, 14, 12, 14, 11, 10, 15, 15, 13, 14, 13, 14, 10, 9, + 7, 11, 8, 10, 9, 11, 9, 9, 10, 13, 10, 12, 11, 12, 10, 10, + 15, 15, 14, 15, 14, 15, 13, 12, 8, 12, 9, 11, 9, 11, 10, 10, + 11, 13, 11, 12, 11, 12, 11, 10, 15, 15, 14, 15, 15, 15, 13, 12, + 11, 14, 10, 12, 12, 13, 11, 10, 12, 15, 11, 13, 13, 14, 11, 11, + 15, 15, 13, 14, 15, 15, 12, 11, 9, 12, 10, 11, 9, 11, 10, 10, + 11, 14, 11, 12, 11, 12, 11, 10, 15, 15, 15, 15, 14, 15, 13, 12, + 9, 13, 10, 12, 10, 12, 10, 10, 11, 14, 11, 13, 11, 13, 11, 11, + 15, 15, 14, 15, 14, 15, 13, 12, 12, 15, 11, 13, 12, 13, 11, 11, + 12, 15, 11, 13, 13, 14, 11, 11, 15, 15, 13, 14, 14, 15, 12, 11, + 11, 15, 12, 13, 11, 12, 11, 10, 12, 15, 13, 14, 11, 13, 11, 11, + 15, 15, 15, 15, 13, 14, 12, 11, 12, 15, 12, 14, 11, 13, 11, 11, + 12, 15, 13, 14, 11, 13, 11, 11, 15, 15, 14, 15, 13, 14, 12, 11, + 13, 15, 13, 14, 13, 14, 11, 10, 13, 15, 12, 14, 12, 14, 11, 10, + 15, 15, 12, 13, 13, 14, 10, 9, 10, 13, 10, 11, 10, 12, 10, 10, + 12, 15, 12, 13, 12, 13, 11, 10, 15, 15, 14, 14, 14, 15, 12, 11, + 10, 13, 10, 12, 10, 12, 10, 10, 12, 15, 11, 12, 11, 13, 11, 10, + 15, 15, 14, 14, 14, 14, 12, 11, 11, 14, 10, 12, 11, 12, 10, 9, + 12, 15, 11, 12, 11, 13, 10, 9, 15, 15, 13, 13, 13, 14, 10, 9, + 10, 14, 10, 12, 10, 12, 10, 10, 12, 15, 11, 13, 12, 13, 11, 10, + 15, 15, 14, 14, 14, 14, 12, 11, 10, 14, 10, 12, 10, 12, 10, 10, + 11, 15, 11, 13, 11, 13, 11, 10, 15, 15, 14, 14, 14, 14, 12, 10, + 11, 14, 10, 12, 11, 12, 10, 9, 11, 15, 10, 12, 11, 13, 10, 9, + 14, 15, 11, 13, 13, 14, 10, 9, 11, 14, 11, 12, 10, 12, 10, 9, + 12, 15, 11, 13, 11, 12, 10, 9, 15, 15, 13, 14, 13, 13, 10, 9, + 11, 15, 11, 12, 10, 12, 10, 9, 12, 15, 11, 13, 11, 12, 10, 9, + 14, 15, 13, 13, 12, 13, 10, 9, 11, 15, 10, 12, 10, 12, 9, 8, + 11, 15, 10, 12, 10, 12, 9, 8, 12, 15, 9, 11, 10, 11, 8, 6 }, + { 0, 8, 5, 9, 5, 10, 8, 10, 7, 11, 8, 11, 9, 12, 11, 12, + 14, 15, 14, 15, 15, 15, 15, 15, 4, 10, 6, 10, 9, 12, 10, 11, + 9, 13, 9, 12, 11, 14, 12, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 10, 13, 12, 15, 12, 14, 12, 15, 12, 15, 14, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 11, 8, 11, 7, 11, 10, 11, + 9, 13, 10, 13, 10, 13, 11, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 12, 9, 12, 10, 13, 11, 13, 10, 14, 11, 14, 11, 14, 12, 13, + 15, 15, 15, 15, 15, 15, 14, 15, 11, 15, 12, 15, 13, 15, 13, 14, + 13, 15, 12, 15, 14, 15, 13, 14, 15, 15, 15, 15, 15, 15, 14, 15, + 10, 15, 12, 14, 10, 14, 12, 14, 12, 15, 13, 15, 11, 14, 13, 14, + 15, 15, 15, 15, 14, 15, 15, 15, 11, 15, 13, 15, 12, 15, 13, 14, + 12, 15, 14, 15, 12, 15, 13, 14, 15, 15, 15, 15, 14, 15, 14, 15, + 14, 15, 14, 15, 14, 15, 13, 14, 15, 15, 14, 15, 14, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 14, 14, 2, 9, 6, 9, 6, 11, 9, 11, + 7, 11, 9, 11, 10, 12, 11, 12, 15, 15, 15, 15, 15, 15, 14, 15, + 5, 11, 7, 11, 9, 12, 10, 12, 9, 13, 10, 12, 11, 14, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 9, 14, 12, 15, 12, 13, + 12, 15, 11, 14, 14, 15, 13, 14, 15, 15, 14, 15, 15, 15, 15, 15, + 5, 11, 8, 11, 7, 12, 10, 12, 9, 13, 10, 13, 10, 13, 11, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 7, 13, 9, 12, 10, 13, 11, 13, + 9, 14, 10, 14, 11, 14, 12, 13, 15, 15, 14, 15, 15, 15, 14, 15, + 11, 15, 11, 14, 13, 15, 13, 14, 12, 15, 12, 15, 14, 15, 13, 14, + 15, 15, 14, 15, 15, 15, 14, 15, 9, 15, 12, 14, 9, 14, 12, 13, + 12, 15, 13, 15, 11, 14, 13, 14, 15, 15, 15, 15, 14, 15, 14, 15, + 11, 15, 13, 15, 11, 15, 12, 14, 12, 15, 13, 15, 11, 15, 13, 14, + 15, 15, 15, 15, 14, 15, 14, 14, 14, 15, 14, 15, 14, 15, 13, 14, + 14, 15, 14, 15, 14, 15, 13, 14, 15, 15, 14, 15, 14, 15, 13, 13, + 4, 11, 7, 11, 8, 12, 10, 12, 9, 13, 10, 12, 10, 13, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 12, 8, 12, 9, 13, 11, 12, + 10, 14, 11, 13, 11, 14, 12, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 15, 10, 14, 12, 15, 12, 13, 12, 15, 12, 15, 14, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 12, 9, 12, 8, 13, 11, 12, + 10, 14, 11, 14, 11, 14, 12, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 13, 10, 13, 10, 14, 11, 13, 10, 14, 11, 14, 11, 14, 12, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 11, 15, 13, 15, 13, 14, + 12, 15, 12, 15, 14, 15, 13, 14, 15, 15, 14, 15, 15, 15, 14, 14, + 10, 15, 12, 15, 10, 14, 12, 13, 12, 15, 13, 15, 11, 15, 13, 14, + 15, 15, 15, 15, 14, 15, 15, 15, 11, 15, 13, 15, 11, 15, 13, 14, + 12, 15, 13, 15, 11, 15, 13, 14, 15, 15, 15, 15, 14, 15, 14, 14, + 13, 15, 13, 15, 14, 15, 13, 14, 13, 15, 14, 15, 13, 15, 13, 14, + 15, 15, 14, 15, 14, 15, 13, 13, 6, 12, 8, 12, 9, 12, 10, 12, + 10, 14, 10, 13, 11, 13, 11, 13, 15, 15, 14, 15, 14, 15, 13, 13, + 7, 13, 9, 13, 9, 13, 10, 12, 10, 14, 11, 13, 11, 14, 11, 13, + 15, 15, 14, 15, 14, 15, 13, 13, 9, 15, 9, 13, 10, 13, 11, 12, + 11, 15, 11, 14, 12, 14, 11, 12, 15, 15, 14, 15, 14, 15, 13, 12, + 7, 13, 9, 12, 9, 13, 10, 12, 10, 14, 11, 14, 11, 14, 11, 13, + 15, 15, 14, 15, 14, 15, 13, 13, 8, 13, 10, 13, 10, 13, 11, 12, + 10, 14, 11, 14, 11, 14, 11, 13, 15, 15, 14, 15, 14, 15, 13, 13, + 9, 15, 10, 13, 11, 14, 11, 12, 10, 15, 10, 13, 11, 14, 11, 12, + 14, 15, 13, 14, 14, 15, 12, 12, 9, 14, 10, 13, 9, 13, 10, 12, + 11, 15, 12, 14, 11, 14, 11, 12, 15, 15, 14, 15, 13, 15, 13, 12, + 9, 15, 11, 14, 10, 13, 11, 12, 10, 15, 11, 14, 10, 13, 11, 12, + 14, 15, 14, 15, 12, 14, 12, 12, 10, 15, 11, 13, 11, 13, 10, 11, + 10, 14, 11, 13, 10, 13, 10, 11, 12, 14, 11, 12, 11, 12, 10, 10 } + }, + { + { 0, 4, 9, 3, 5, 10, 7, 9, 10, 3, 5, 10, 5, 6, 10, 8, + 9, 10, 7, 8, 10, 8, 9, 10, 10, 10, 10, 3, 5, 10, 4, 6, + 10, 7, 8, 10, 4, 6, 10, 6, 7, 10, 8, 9, 10, 7, 9, 10, + 8, 9, 10, 9, 10, 9, 6, 8, 11, 7, 8, 11, 8, 9, 11, 7, + 8, 11, 8, 9, 11, 9, 9, 10, 9, 10, 11, 9, 10, 10, 10, 10, + 9, 8, 9, 10, 8, 9, 10, 8, 8, 9, 8, 9, 10, 8, 9, 10, + 8, 8, 9, 8, 9, 9, 8, 9, 9, 8, 8, 7 }, + { 0, 5, 12, 3, 7, 13, 8, 11, 14, 3, 7, 13, 6, 9, 14, 11, + 12, 14, 9, 11, 15, 11, 12, 15, 13, 14, 15, 1, 6, 13, 4, 8, + 13, 9, 11, 14, 5, 8, 13, 7, 9, 13, 11, 11, 14, 10, 12, 14, + 11, 12, 15, 13, 13, 15, 6, 9, 13, 8, 10, 14, 10, 12, 14, 8, + 11, 14, 9, 11, 14, 11, 12, 15, 11, 13, 15, 12, 13, 15, 13, 13, + 15, 9, 11, 13, 10, 11, 13, 11, 12, 14, 10, 11, 14, 10, 12, 14, + 11, 12, 14, 11, 13, 15, 12, 13, 14, 12, 13, 14 } + }, + { + { 0, 4, 9, 3, 5, 10, 7, 9, 11, 3, 5, 10, 5, 7, 11, 9, + 10, 12, 8, 9, 11, 9, 10, 11, 10, 11, 11, 2, 5, 10, 4, 7, + 11, 8, 9, 11, 4, 7, 11, 6, 8, 11, 9, 10, 11, 9, 10, 11, + 9, 10, 11, 10, 10, 10, 6, 8, 11, 7, 9, 12, 9, 10, 12, 7, + 9, 12, 8, 9, 12, 10, 10, 12, 9, 10, 12, 10, 11, 12, 11, 11, + 11, 8, 10, 11, 9, 10, 11, 9, 10, 10, 9, 10, 11, 9, 10, 11, + 9, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9 }, + { 0, 5, 12, 2, 7, 13, 10, 12, 15, 4, 7, 14, 6, 9, 14, 11, + 12, 15, 10, 12, 15, 11, 12, 15, 13, 13, 15, 1, 6, 12, 5, 8, + 14, 10, 12, 15, 5, 8, 13, 8, 9, 13, 11, 12, 15, 11, 12, 15, + 11, 12, 15, 13, 13, 15, 7, 9, 12, 9, 11, 14, 12, 13, 15, 9, + 10, 14, 10, 11, 13, 13, 13, 15, 12, 13, 15, 12, 14, 15, 14, 15, + 15, 11, 11, 12, 12, 12, 13, 14, 15, 15, 12, 13, 14, 12, 13, 14, + 14, 14, 15, 13, 14, 15, 14, 14, 15, 14, 14, 15 } + }, + { 1, 3, 3, 4, 4, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 11, 10, 10, 10, 12, 14, 14, 14, 14 } + }, + { + { + { 0, 9, 5, 9, 5, 9, 8, 9, 7, 11, 8, 11, 8, 11, 9, 10, + 14, 15, 13, 14, 13, 14, 12, 11, 5, 11, 6, 10, 8, 11, 9, 10, + 8, 12, 9, 11, 9, 12, 10, 10, 14, 15, 13, 14, 13, 14, 12, 11, + 9, 15, 9, 12, 11, 14, 10, 10, 11, 15, 9, 12, 12, 14, 10, 11, + 14, 15, 12, 13, 13, 14, 11, 11, 5, 11, 8, 11, 6, 10, 9, 10, + 8, 12, 9, 12, 9, 11, 10, 10, 14, 15, 13, 14, 13, 14, 12, 11, + 7, 13, 8, 12, 9, 12, 9, 10, 9, 13, 9, 12, 9, 12, 10, 10, + 14, 15, 13, 14, 12, 14, 12, 11, 11, 15, 10, 13, 12, 14, 10, 11, + 11, 15, 10, 13, 12, 14, 10, 11, 14, 15, 12, 13, 13, 14, 11, 10, + 9, 15, 11, 13, 8, 12, 10, 10, 10, 15, 12, 14, 9, 12, 10, 11, + 14, 15, 13, 15, 12, 13, 11, 11, 11, 15, 11, 14, 10, 13, 10, 10, + 11, 15, 12, 14, 10, 13, 10, 11, 14, 15, 13, 14, 12, 13, 11, 10, + 13, 15, 12, 14, 12, 14, 11, 10, 13, 15, 12, 14, 12, 14, 10, 10, + 15, 15, 12, 13, 12, 13, 10, 9, 3, 10, 6, 10, 6, 10, 9, 10, + 8, 12, 9, 11, 9, 11, 10, 10, 14, 15, 13, 14, 13, 14, 12, 11, + 5, 12, 7, 11, 8, 11, 9, 10, 8, 13, 9, 12, 9, 12, 10, 10, + 14, 15, 13, 14, 13, 14, 12, 11, 9, 15, 9, 12, 11, 13, 10, 10, + 11, 15, 9, 12, 12, 14, 10, 11, 14, 15, 12, 13, 13, 15, 11, 10, + 6, 12, 8, 11, 7, 11, 9, 10, 8, 13, 10, 12, 9, 11, 10, 10, + 14, 15, 13, 14, 13, 13, 12, 11, 7, 13, 9, 12, 9, 12, 10, 10, + 9, 13, 9, 12, 9, 12, 10, 10, 14, 15, 13, 14, 13, 14, 12, 11, + 10, 15, 10, 13, 11, 14, 10, 10, 11, 15, 10, 12, 12, 14, 10, 10, + 14, 15, 11, 13, 13, 14, 11, 10, 9, 15, 11, 13, 8, 12, 10, 10, + 11, 15, 12, 14, 9, 12, 10, 10, 14, 15, 13, 15, 12, 13, 11, 10, + 10, 15, 11, 14, 10, 13, 10, 10, 11, 15, 11, 14, 10, 13, 10, 11, + 14, 15, 13, 14, 11, 13, 11, 10, 13, 15, 12, 14, 12, 14, 10, 10, + 13, 15, 11, 13, 12, 13, 10, 10, 14, 15, 11, 13, 12, 13, 10, 9, + 6, 13, 8, 12, 8, 12, 10, 10, 10, 14, 10, 12, 10, 12, 11, 11, + 15, 15, 14, 14, 14, 14, 12, 12, 7, 13, 8, 12, 9, 12, 10, 11, + 10, 14, 10, 12, 11, 13, 11, 11, 15, 15, 14, 14, 14, 14, 12, 12, + 10, 15, 9, 13, 11, 13, 10, 10, 11, 15, 10, 13, 12, 14, 11, 11, + 15, 15, 12, 14, 14, 15, 11, 11, 7, 13, 9, 12, 9, 12, 10, 11, + 10, 14, 10, 13, 10, 13, 11, 11, 15, 15, 14, 14, 14, 14, 12, 12, + 8, 14, 9, 12, 9, 13, 10, 11, 10, 14, 10, 13, 10, 13, 11, 11, + 15, 15, 13, 14, 13, 14, 12, 11, 10, 15, 10, 13, 11, 14, 10, 11, + 10, 15, 9, 13, 12, 14, 11, 11, 14, 15, 11, 13, 13, 15, 11, 10, + 10, 15, 11, 13, 9, 12, 10, 10, 11, 15, 12, 14, 10, 13, 11, 11, + 14, 15, 14, 15, 12, 13, 11, 11, 10, 15, 11, 14, 10, 13, 10, 11, + 10, 15, 12, 14, 10, 13, 11, 11, 14, 15, 13, 15, 11, 13, 11, 10, + 12, 15, 12, 14, 12, 14, 10, 10, 11, 15, 11, 13, 11, 13, 10, 10, + 13, 15, 11, 12, 11, 13, 9, 9, 9, 14, 10, 13, 10, 13, 10, 10, + 11, 15, 11, 13, 11, 13, 10, 11, 15, 15, 14, 14, 13, 14, 12, 10, + 9, 14, 10, 13, 9, 13, 10, 10, 11, 15, 11, 13, 11, 13, 10, 10, + 15, 15, 14, 14, 13, 14, 12, 10, 10, 14, 9, 12, 10, 12, 9, 9, + 11, 15, 10, 13, 11, 13, 9, 9, 14, 15, 12, 13, 13, 13, 10, 9, + 9, 15, 9, 13, 10, 13, 10, 10, 11, 15, 11, 13, 11, 13, 11, 11, + 15, 15, 14, 14, 13, 14, 12, 10, 8, 15, 9, 13, 9, 13, 10, 10, + 10, 15, 11, 13, 10, 13, 10, 11, 15, 15, 13, 14, 13, 14, 11, 10, + 9, 15, 9, 12, 10, 12, 9, 9, 10, 15, 9, 12, 10, 13, 9, 9, + 13, 15, 11, 12, 12, 13, 10, 9, 10, 15, 10, 12, 9, 12, 9, 9, + 11, 15, 10, 13, 10, 13, 9, 9, 14, 15, 13, 13, 12, 13, 10, 9, + 10, 15, 10, 12, 9, 12, 9, 9, 10, 15, 10, 12, 9, 12, 9, 9, + 14, 15, 12, 13, 11, 12, 10, 9, 10, 15, 9, 12, 10, 12, 8, 8, + 9, 14, 9, 11, 9, 11, 8, 8, 10, 14, 8, 10, 9, 10, 7, 6 }, + { 0, 11, 6, 13, 6, 12, 11, 14, 8, 13, 11, 14, 10, 14, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 5, 14, 8, 14, 10, 15, 12, 14, + 9, 15, 11, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 11, 15, 14, 15, 14, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 14, 10, 15, 8, 14, 12, 15, + 9, 15, 12, 15, 11, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 11, 15, 11, 15, 13, 15, 10, 15, 12, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 14, 15, 14, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 14, 15, 11, 15, 14, 15, 12, 15, 15, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 14, 15, 12, 15, 14, 15, + 13, 15, 15, 15, 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, 1, 12, 7, 13, 7, 13, 12, 13, + 8, 13, 11, 14, 10, 14, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 14, 8, 14, 10, 15, 12, 14, 9, 15, 11, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 10, 15, 13, 15, 13, 15, + 13, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 14, 10, 15, 8, 14, 12, 14, 9, 15, 12, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 7, 15, 11, 15, 10, 15, 13, 15, + 9, 15, 12, 15, 11, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 12, 15, 14, 15, 14, 15, 13, 15, 13, 15, 14, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 13, 15, 10, 15, 14, 15, + 12, 15, 15, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 14, 15, 12, 15, 14, 15, 12, 15, 15, 15, 12, 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, + 4, 14, 9, 14, 8, 14, 12, 14, 9, 14, 11, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 9, 15, 10, 15, 13, 14, + 10, 15, 12, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 10, 15, 13, 15, 13, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 10, 15, 9, 15, 13, 15, + 10, 15, 13, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 11, 15, 11, 15, 13, 15, 10, 15, 12, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 12, 15, 14, 15, 14, 15, + 12, 15, 12, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 15, 13, 15, 10, 15, 13, 15, 12, 15, 15, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 12, 15, 14, 15, + 12, 15, 14, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 14, 10, 15, 9, 15, 12, 14, + 10, 15, 12, 15, 11, 15, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 15, 10, 15, 10, 15, 12, 14, 11, 15, 12, 15, 12, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 10, 15, 11, 15, 12, 14, + 12, 15, 12, 15, 13, 15, 13, 14, 15, 15, 15, 15, 15, 15, 14, 15, + 7, 15, 10, 15, 10, 15, 12, 14, 11, 15, 12, 15, 11, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 15, 11, 15, 10, 15, 12, 14, + 10, 15, 12, 15, 11, 15, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 15, 10, 15, 12, 15, 12, 14, 11, 15, 11, 15, 12, 15, 12, 14, + 15, 15, 14, 15, 15, 15, 14, 15, 9, 15, 11, 15, 10, 15, 12, 14, + 12, 15, 13, 15, 12, 15, 13, 14, 15, 15, 15, 15, 15, 15, 14, 15, + 9, 15, 12, 15, 10, 15, 12, 14, 11, 15, 12, 15, 11, 15, 12, 14, + 15, 15, 15, 15, 14, 15, 14, 15, 11, 15, 12, 15, 12, 15, 11, 13, + 11, 15, 12, 14, 12, 14, 12, 13, 13, 15, 13, 14, 12, 14, 12, 13 } + }, + { + { 0, 5, 10, 3, 6, 10, 7, 8, 10, 4, 6, 10, 6, 7, 10, 8, + 8, 10, 8, 9, 10, 9, 9, 10, 9, 9, 10, 2, 6, 10, 4, 6, + 10, 7, 8, 10, 5, 7, 10, 6, 7, 10, 8, 8, 10, 8, 9, 10, + 9, 9, 10, 9, 9, 9, 5, 7, 10, 6, 8, 10, 7, 8, 10, 6, + 8, 11, 7, 8, 11, 8, 8, 10, 8, 9, 10, 9, 9, 10, 9, 9, + 9, 7, 8, 10, 7, 8, 10, 7, 8, 9, 7, 9, 10, 7, 8, 10, + 8, 8, 9, 8, 9, 9, 8, 9, 9, 8, 8, 7 }, + { 0, 6, 14, 3, 7, 15, 8, 11, 15, 3, 8, 14, 7, 9, 15, 10, + 12, 15, 9, 12, 15, 11, 13, 15, 13, 14, 14, 1, 6, 13, 4, 8, + 14, 8, 11, 15, 5, 9, 15, 7, 9, 14, 10, 12, 15, 10, 12, 15, + 11, 12, 15, 15, 15, 15, 5, 9, 14, 7, 10, 14, 10, 12, 15, 7, + 10, 15, 8, 11, 15, 11, 13, 15, 11, 13, 15, 12, 13, 15, 15, 14, + 15, 8, 11, 14, 9, 11, 15, 11, 13, 15, 9, 12, 15, 10, 12, 15, + 12, 13, 15, 12, 13, 15, 12, 13, 15, 14, 13, 15 } + }, + { + { 0, 5, 10, 3, 7, 10, 7, 9, 11, 3, 7, 10, 5, 7, 11, 8, + 9, 11, 8, 9, 11, 8, 9, 11, 9, 10, 10, 2, 6, 10, 4, 7, + 10, 7, 9, 11, 4, 7, 10, 6, 8, 10, 8, 9, 11, 8, 9, 11, + 8, 9, 11, 9, 10, 10, 5, 7, 10, 6, 8, 11, 8, 9, 11, 6, + 8, 11, 7, 9, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, 10, 10, + 10, 7, 8, 10, 8, 9, 10, 9, 10, 10, 8, 9, 10, 8, 9, 10, + 9, 10, 10, 9, 10, 10, 9, 10, 10, 9, 9, 9 }, + { 0, 4, 12, 3, 8, 13, 10, 14, 14, 3, 7, 14, 6, 8, 13, 10, + 12, 13, 9, 12, 14, 10, 13, 14, 12, 13, 14, 1, 5, 12, 5, 9, + 13, 11, 13, 14, 5, 8, 12, 7, 9, 14, 12, 12, 14, 10, 14, 14, + 11, 12, 13, 14, 12, 14, 6, 8, 10, 9, 10, 13, 14, 13, 13, 8, + 11, 13, 10, 12, 13, 13, 14, 14, 12, 12, 14, 12, 14, 14, 14, 14, + 14, 10, 10, 12, 14, 14, 14, 14, 14, 14, 12, 12, 13, 12, 11, 14, + 14, 14, 14, 14, 14, 14, 13, 14, 14, 14, 14, 14 } + }, + { 1, 2, 3, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 10, 10, 11, + 11, 11, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 16, 16 } + }, + { + { + { 0, 9, 5, 10, 5, 10, 8, 9, 7, 11, 8, 11, 8, 11, 9, 10, + 14, 15, 13, 14, 13, 14, 12, 12, 5, 12, 6, 10, 8, 11, 9, 10, + 8, 13, 8, 11, 9, 12, 10, 10, 14, 15, 13, 14, 13, 14, 12, 12, + 9, 15, 9, 12, 11, 14, 10, 11, 11, 15, 9, 12, 12, 14, 11, 11, + 14, 15, 12, 13, 13, 15, 11, 11, 4, 11, 8, 11, 6, 10, 9, 10, + 8, 12, 9, 12, 8, 11, 10, 10, 14, 15, 13, 14, 13, 14, 12, 12, + 7, 13, 9, 11, 9, 12, 9, 10, 8, 13, 9, 12, 9, 12, 10, 10, + 14, 15, 13, 14, 12, 14, 12, 11, 11, 15, 10, 13, 12, 14, 10, 11, + 11, 15, 10, 13, 12, 14, 11, 11, 15, 15, 12, 13, 13, 15, 11, 11, + 9, 15, 11, 14, 9, 12, 10, 10, 10, 15, 12, 14, 9, 12, 10, 11, + 14, 15, 13, 15, 12, 13, 11, 11, 11, 15, 12, 14, 10, 13, 10, 11, + 11, 15, 12, 14, 10, 13, 11, 11, 14, 15, 13, 14, 12, 13, 11, 11, + 13, 15, 12, 14, 12, 14, 11, 11, 13, 15, 12, 14, 12, 14, 11, 10, + 15, 15, 12, 14, 12, 14, 11, 10, 3, 11, 6, 10, 6, 10, 9, 10, + 8, 12, 9, 11, 9, 11, 10, 10, 15, 15, 13, 14, 13, 13, 12, 12, + 5, 12, 7, 11, 8, 11, 9, 10, 8, 13, 9, 12, 9, 12, 10, 10, + 15, 15, 13, 14, 13, 14, 12, 12, 9, 15, 9, 12, 11, 14, 10, 10, + 11, 15, 9, 12, 12, 14, 10, 11, 14, 15, 12, 13, 13, 15, 11, 11, + 5, 12, 8, 11, 7, 11, 9, 10, 8, 13, 10, 12, 9, 12, 10, 10, + 15, 15, 13, 14, 13, 13, 12, 12, 7, 13, 9, 12, 8, 12, 9, 10, + 8, 13, 9, 12, 9, 12, 10, 10, 14, 15, 12, 14, 13, 14, 12, 11, + 10, 15, 10, 13, 11, 14, 10, 11, 11, 15, 9, 12, 12, 14, 10, 11, + 14, 15, 11, 13, 13, 14, 11, 11, 9, 15, 11, 13, 8, 12, 10, 10, + 11, 15, 12, 14, 9, 12, 10, 11, 14, 15, 13, 15, 12, 13, 11, 11, + 11, 15, 11, 14, 10, 13, 10, 11, 11, 15, 11, 14, 9, 13, 10, 11, + 14, 15, 13, 14, 11, 13, 11, 11, 13, 15, 12, 14, 12, 14, 11, 10, + 12, 15, 12, 14, 12, 14, 10, 10, 14, 15, 11, 13, 12, 13, 10, 9, + 6, 13, 8, 12, 8, 12, 10, 10, 10, 14, 10, 12, 10, 12, 11, 11, + 15, 15, 14, 14, 14, 14, 12, 12, 7, 13, 8, 12, 9, 12, 10, 11, + 10, 14, 10, 12, 10, 13, 11, 11, 15, 15, 14, 14, 14, 15, 12, 12, + 10, 15, 9, 13, 11, 13, 10, 11, 11, 15, 10, 13, 12, 14, 11, 11, + 15, 15, 13, 14, 14, 15, 12, 11, 7, 14, 9, 12, 9, 12, 10, 11, + 10, 14, 10, 13, 10, 13, 11, 11, 15, 15, 14, 14, 14, 14, 13, 12, + 8, 14, 9, 12, 9, 13, 10, 11, 9, 14, 10, 13, 10, 13, 11, 11, + 15, 15, 13, 15, 13, 15, 12, 12, 10, 15, 10, 13, 11, 14, 10, 11, + 10, 15, 9, 13, 12, 14, 11, 11, 14, 15, 11, 13, 13, 15, 11, 11, + 10, 15, 11, 14, 9, 13, 10, 11, 11, 15, 12, 14, 10, 13, 11, 11, + 15, 15, 14, 15, 13, 14, 12, 11, 10, 15, 12, 14, 10, 13, 11, 11, + 10, 15, 12, 14, 10, 13, 10, 11, 14, 15, 13, 15, 12, 13, 11, 11, + 12, 15, 12, 14, 12, 14, 11, 10, 11, 15, 11, 13, 11, 14, 10, 10, + 13, 15, 11, 13, 11, 13, 10, 9, 8, 15, 10, 13, 10, 13, 10, 11, + 11, 15, 11, 13, 11, 13, 11, 11, 15, 15, 14, 14, 13, 14, 12, 11, + 9, 15, 10, 13, 9, 13, 10, 11, 11, 15, 11, 13, 11, 13, 11, 11, + 15, 15, 14, 14, 14, 14, 12, 11, 10, 15, 9, 12, 10, 13, 9, 10, + 12, 15, 10, 13, 11, 13, 10, 10, 15, 15, 13, 13, 13, 14, 10, 10, + 9, 15, 10, 13, 10, 13, 10, 11, 11, 15, 11, 13, 11, 13, 11, 11, + 15, 15, 14, 14, 14, 14, 12, 11, 8, 15, 10, 13, 9, 13, 10, 11, + 10, 15, 11, 13, 10, 13, 10, 11, 15, 15, 13, 14, 14, 14, 12, 11, + 9, 15, 9, 12, 10, 13, 9, 10, 10, 15, 9, 12, 10, 13, 9, 10, + 14, 15, 11, 12, 12, 13, 10, 9, 10, 15, 10, 13, 9, 13, 9, 10, + 11, 15, 11, 13, 10, 13, 10, 10, 14, 15, 13, 14, 12, 13, 10, 9, + 10, 15, 10, 13, 9, 13, 9, 10, 10, 15, 11, 13, 9, 13, 10, 10, + 14, 15, 13, 13, 11, 13, 10, 9, 10, 15, 10, 12, 10, 12, 8, 8, + 9, 14, 9, 11, 9, 12, 8, 8, 10, 14, 9, 10, 9, 11, 8, 7 }, + { 0, 11, 7, 13, 7, 13, 12, 14, 8, 13, 11, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 14, 8, 15, 10, 15, 13, 15, + 9, 15, 11, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 11, 15, 14, 15, 15, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 14, 10, 15, 8, 14, 13, 15, + 9, 14, 13, 15, 11, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 11, 15, 11, 15, 13, 15, 10, 15, 12, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 14, 15, 11, 15, 14, 15, 13, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 15, 15, 13, 15, 15, 15, + 14, 15, 15, 15, 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, 1, 12, 7, 13, 7, 13, 12, 14, + 8, 13, 11, 15, 11, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 15, 8, 15, 10, 15, 13, 15, 9, 15, 11, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 11, 15, 14, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 15, 10, 15, 8, 14, 13, 15, 9, 15, 13, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 7, 15, 11, 15, 11, 15, 13, 15, + 9, 15, 12, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 13, 15, 14, 15, 14, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 14, 15, 10, 15, 14, 15, + 13, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 14, 15, 12, 15, 15, 15, 13, 15, 15, 15, 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, + 4, 14, 9, 15, 9, 15, 13, 15, 9, 14, 12, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 9, 15, 10, 15, 13, 15, + 10, 15, 12, 15, 13, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 11, 15, 13, 15, 14, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 10, 15, 9, 15, 13, 15, + 10, 15, 13, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 11, 15, 11, 15, 13, 15, 10, 15, 13, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 12, 15, 14, 15, 14, 15, + 12, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 15, 13, 15, 10, 15, 14, 15, 13, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 12, 15, 15, 15, + 12, 15, 15, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 10, 15, 9, 15, 12, 15, + 10, 15, 12, 15, 11, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 15, 10, 15, 10, 15, 12, 15, 11, 15, 12, 15, 12, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 10, 15, 12, 15, 12, 15, + 12, 15, 12, 15, 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 15, 10, 15, 10, 15, 12, 15, 11, 15, 12, 15, 12, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 15, 11, 15, 10, 15, 12, 15, + 10, 15, 12, 15, 12, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 11, 15, 12, 15, 12, 15, 11, 15, 11, 15, 13, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 12, 15, 10, 15, 12, 15, + 12, 15, 14, 15, 12, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 12, 15, 11, 15, 13, 15, 11, 15, 13, 15, 11, 15, 13, 15, + 15, 15, 15, 15, 14, 15, 15, 15, 11, 15, 12, 15, 12, 15, 12, 14, + 11, 15, 12, 15, 12, 15, 12, 14, 14, 15, 13, 15, 13, 15, 13, 14 } + }, + { + { 0, 5, 10, 3, 6, 10, 7, 8, 11, 4, 6, 10, 6, 7, 10, 8, + 9, 10, 8, 9, 10, 9, 9, 10, 10, 10, 10, 2, 6, 10, 4, 6, + 10, 7, 8, 10, 4, 7, 10, 6, 7, 10, 8, 8, 10, 8, 9, 10, + 8, 9, 10, 10, 9, 10, 5, 7, 10, 6, 8, 11, 7, 9, 11, 6, + 8, 11, 7, 8, 11, 8, 9, 11, 8, 9, 11, 9, 9, 11, 10, 9, + 10, 7, 8, 10, 7, 9, 10, 8, 9, 10, 7, 9, 10, 8, 8, 10, + 8, 8, 9, 8, 9, 10, 8, 9, 10, 8, 8, 8 }, + { 0, 6, 14, 3, 7, 14, 8, 11, 14, 3, 8, 14, 7, 9, 14, 10, + 12, 14, 9, 12, 14, 11, 13, 14, 14, 14, 14, 1, 6, 13, 4, 8, + 14, 9, 11, 14, 5, 8, 14, 7, 9, 14, 11, 12, 14, 9, 12, 14, + 12, 13, 14, 14, 14, 14, 5, 8, 14, 7, 10, 14, 10, 13, 14, 7, + 10, 14, 9, 11, 14, 12, 12, 14, 11, 13, 14, 12, 14, 14, 14, 14, + 14, 8, 11, 14, 9, 12, 14, 11, 14, 14, 9, 12, 14, 10, 12, 14, + 13, 13, 14, 12, 14, 14, 13, 14, 14, 14, 13, 14 } + }, + { + { 0, 5, 10, 3, 6, 11, 7, 9, 12, 3, 6, 11, 5, 7, 11, 8, + 9, 11, 8, 9, 11, 8, 9, 11, 10, 10, 11, 2, 5, 10, 4, 7, + 10, 8, 9, 12, 4, 7, 11, 6, 7, 11, 8, 9, 11, 8, 9, 11, + 9, 9, 11, 10, 10, 11, 5, 7, 10, 6, 8, 11, 9, 10, 12, 6, + 8, 11, 7, 9, 11, 9, 10, 12, 9, 10, 12, 9, 10, 12, 10, 11, + 11, 8, 9, 10, 8, 9, 11, 10, 10, 11, 8, 9, 11, 9, 10, 11, + 10, 10, 11, 10, 10, 11, 10, 10, 11, 10, 10, 10 }, + { 0, 4, 14, 3, 7, 14, 11, 15, 15, 3, 7, 15, 6, 9, 12, 11, + 12, 15, 11, 14, 14, 12, 14, 14, 14, 14, 14, 1, 5, 9, 5, 9, + 14, 11, 14, 14, 5, 8, 14, 7, 9, 14, 12, 14, 14, 14, 12, 14, + 14, 14, 14, 12, 14, 14, 6, 7, 10, 8, 10, 14, 12, 12, 14, 9, + 11, 14, 11, 12, 14, 14, 14, 14, 12, 14, 14, 11, 14, 14, 14, 14, + 14, 12, 10, 12, 12, 12, 14, 14, 14, 14, 14, 12, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14 } + }, + { 1, 2, 3, 4, 5, 6, 8, 8, 9, 9, 10, 10, 11, 12, 12, 12, + 13, 13, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 15 } + }, + { + { + { 0, 9, 5, 10, 5, 10, 9, 10, 7, 11, 8, 11, 8, 11, 10, 11, + 15, 15, 14, 15, 14, 14, 13, 13, 4, 12, 6, 11, 8, 11, 9, 10, + 8, 13, 9, 12, 9, 12, 10, 11, 15, 15, 13, 14, 14, 15, 13, 13, + 10, 15, 9, 13, 12, 14, 11, 12, 11, 15, 10, 13, 12, 15, 11, 12, + 15, 15, 13, 14, 14, 15, 13, 13, 4, 11, 8, 11, 6, 11, 9, 10, + 8, 12, 9, 12, 9, 11, 10, 11, 15, 15, 14, 15, 14, 14, 13, 13, + 7, 13, 9, 12, 9, 12, 10, 11, 8, 13, 9, 12, 9, 12, 10, 11, + 14, 15, 13, 15, 13, 14, 12, 13, 11, 15, 11, 14, 12, 15, 11, 12, + 12, 15, 10, 14, 12, 15, 11, 12, 15, 15, 13, 14, 14, 15, 13, 13, + 9, 15, 12, 14, 9, 13, 11, 11, 11, 15, 13, 15, 10, 13, 11, 12, + 15, 15, 15, 15, 13, 14, 13, 13, 11, 15, 12, 14, 10, 14, 11, 12, + 12, 15, 13, 15, 11, 14, 11, 12, 15, 15, 15, 15, 13, 14, 12, 12, + 14, 15, 13, 15, 13, 15, 12, 12, 14, 15, 13, 15, 13, 15, 12, 12, + 15, 15, 14, 15, 14, 15, 12, 12, 2, 11, 6, 11, 6, 10, 9, 10, + 8, 12, 9, 12, 9, 11, 10, 11, 15, 15, 14, 14, 14, 14, 13, 13, + 5, 12, 7, 11, 8, 11, 9, 10, 8, 13, 9, 12, 10, 12, 10, 11, + 15, 15, 13, 14, 14, 15, 13, 13, 9, 15, 9, 13, 11, 14, 10, 11, + 11, 15, 10, 13, 12, 14, 11, 12, 15, 15, 13, 14, 15, 15, 13, 12, + 5, 12, 8, 12, 7, 11, 9, 10, 8, 13, 10, 12, 9, 12, 10, 11, + 15, 15, 14, 15, 13, 14, 13, 13, 7, 13, 9, 12, 9, 12, 10, 11, + 8, 13, 9, 12, 9, 12, 10, 11, 15, 15, 13, 14, 13, 15, 12, 13, + 11, 15, 10, 14, 12, 14, 11, 12, 11, 15, 10, 13, 12, 14, 11, 12, + 15, 15, 12, 14, 14, 15, 12, 12, 9, 15, 12, 14, 8, 13, 10, 11, + 11, 15, 12, 15, 10, 13, 11, 12, 15, 15, 15, 15, 13, 14, 13, 12, + 11, 15, 12, 14, 10, 14, 11, 12, 11, 15, 12, 15, 10, 13, 11, 12, + 15, 15, 14, 15, 12, 14, 12, 12, 13, 15, 13, 15, 13, 15, 12, 12, + 13, 15, 12, 14, 13, 15, 12, 12, 15, 15, 13, 14, 13, 14, 12, 11, + 6, 13, 8, 12, 8, 12, 10, 11, 10, 14, 10, 13, 10, 13, 11, 12, + 15, 15, 15, 15, 14, 15, 13, 13, 7, 14, 8, 13, 9, 13, 10, 11, + 10, 15, 10, 13, 11, 13, 11, 12, 15, 15, 14, 15, 15, 15, 14, 13, + 10, 15, 9, 13, 11, 14, 11, 12, 12, 15, 11, 14, 13, 15, 12, 12, + 15, 15, 14, 15, 15, 15, 13, 13, 7, 14, 9, 13, 9, 13, 10, 11, + 10, 14, 11, 14, 10, 13, 11, 12, 15, 15, 15, 15, 14, 15, 13, 13, + 8, 14, 10, 13, 9, 13, 11, 12, 9, 15, 10, 13, 10, 13, 11, 12, + 15, 15, 14, 15, 14, 15, 13, 13, 10, 15, 10, 14, 12, 14, 11, 12, + 10, 15, 9, 14, 12, 14, 11, 12, 15, 15, 12, 14, 15, 15, 13, 12, + 10, 15, 11, 14, 9, 13, 11, 11, 12, 15, 13, 15, 11, 14, 11, 12, + 15, 15, 15, 15, 14, 15, 13, 13, 11, 15, 12, 15, 10, 14, 11, 12, + 11, 15, 12, 15, 10, 13, 11, 12, 15, 15, 15, 15, 13, 14, 13, 12, + 13, 15, 13, 15, 13, 15, 12, 12, 12, 15, 12, 14, 12, 14, 12, 12, + 13, 15, 12, 13, 12, 14, 11, 11, 8, 15, 10, 14, 10, 14, 11, 12, + 11, 15, 12, 14, 11, 14, 11, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 9, 15, 10, 14, 10, 13, 11, 12, 11, 15, 11, 14, 11, 14, 11, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 10, 15, 10, 13, 11, 13, 10, 11, + 12, 15, 11, 14, 11, 14, 11, 11, 15, 15, 14, 14, 14, 15, 12, 11, + 9, 15, 10, 14, 10, 14, 11, 12, 12, 15, 11, 14, 11, 14, 11, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 9, 15, 10, 14, 10, 14, 11, 12, + 11, 15, 11, 14, 11, 14, 11, 12, 15, 15, 14, 15, 14, 15, 13, 12, + 9, 15, 9, 13, 11, 13, 10, 11, 11, 15, 9, 13, 11, 14, 10, 11, + 15, 15, 12, 14, 13, 14, 12, 11, 10, 15, 11, 13, 10, 14, 10, 11, + 12, 15, 12, 14, 11, 14, 11, 11, 15, 15, 14, 15, 14, 14, 12, 11, + 10, 15, 11, 14, 10, 14, 10, 11, 11, 15, 11, 14, 10, 14, 10, 11, + 15, 15, 14, 14, 13, 14, 12, 11, 10, 15, 10, 13, 11, 13, 9, 10, + 10, 15, 10, 12, 10, 13, 10, 10, 12, 15, 11, 11, 11, 12, 10, 9 }, + { 0, 12, 7, 14, 7, 14, 13, 14, 8, 13, 11, 14, 11, 15, 14, 15, + 15, 15, 14, 14, 14, 14, 14, 14, 5, 14, 8, 14, 11, 14, 14, 14, + 10, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 11, 14, 11, 14, 14, 14, 14, 14, 13, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 15, 15, 15, 4, 15, 11, 15, 8, 15, 14, 15, + 10, 15, 13, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 12, 15, 12, 15, 13, 15, 10, 15, 13, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 13, 15, 14, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 15, 15, 11, 15, 15, 15, 14, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 13, 15, 15, 15, 13, 15, 15, 15, + 14, 15, 15, 15, 14, 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, 1, 13, 8, 14, 7, 15, 13, 15, + 8, 13, 12, 15, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 15, 9, 15, 10, 15, 13, 15, 10, 15, 12, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 11, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 15, 11, 15, 8, 15, 14, 15, 10, 15, 13, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 15, 12, 15, 11, 15, 14, 15, + 9, 15, 13, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 13, 15, 15, 15, 15, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 15, 15, 11, 15, 15, 15, + 13, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 15, 15, 13, 15, 15, 15, 13, 15, 15, 15, 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, + 3, 15, 9, 15, 9, 15, 13, 15, 9, 14, 12, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 10, 15, 10, 15, 14, 15, + 11, 15, 13, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 11, 15, 14, 15, 15, 15, 13, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 11, 15, 9, 15, 13, 15, + 11, 15, 14, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 12, 15, 11, 15, 14, 15, 10, 15, 13, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 15, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 15, 15, 10, 15, 15, 15, 13, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 15, 15, 12, 15, 15, 15, + 12, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 10, 15, 10, 15, 13, 15, + 10, 15, 12, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 15, 10, 15, 10, 15, 13, 15, 11, 15, 13, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 11, 15, 12, 15, 13, 15, + 14, 15, 13, 15, 13, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 15, 11, 15, 10, 15, 13, 15, 11, 15, 13, 15, 12, 15, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 8, 14, 11, 14, 10, 14, 13, 14, + 11, 14, 13, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 10, 14, 11, 14, 13, 14, 13, 14, 12, 14, 12, 14, 13, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 12, 14, 10, 14, 13, 14, + 13, 14, 14, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 10, 14, 13, 14, 11, 14, 13, 14, 12, 14, 13, 14, 11, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 11, 14, 13, 14, 13, 14, 13, 14, + 12, 14, 14, 14, 12, 14, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14 } + }, + { + { 0, 6, 12, 3, 7, 12, 8, 10, 13, 4, 7, 12, 6, 8, 12, 9, + 10, 12, 9, 10, 12, 10, 10, 12, 11, 12, 13, 1, 6, 11, 4, 7, + 12, 8, 9, 13, 5, 8, 12, 6, 8, 12, 9, 10, 12, 8, 10, 12, + 10, 10, 12, 11, 11, 12, 6, 8, 12, 7, 9, 12, 9, 10, 13, 7, + 9, 12, 7, 9, 12, 10, 10, 13, 9, 11, 12, 10, 10, 13, 11, 11, + 12, 8, 10, 12, 9, 10, 12, 9, 10, 12, 9, 10, 12, 9, 10, 12, + 10, 10, 12, 10, 11, 12, 10, 10, 12, 10, 11, 11 }, + { 0, 6, 14, 3, 8, 15, 9, 12, 15, 3, 8, 15, 7, 9, 15, 11, + 12, 15, 10, 13, 14, 12, 14, 15, 15, 15, 15, 1, 7, 12, 4, 8, + 13, 10, 12, 13, 4, 9, 15, 8, 9, 15, 12, 13, 15, 10, 13, 15, + 12, 14, 15, 14, 15, 14, 5, 9, 13, 7, 10, 15, 11, 12, 13, 7, + 11, 15, 9, 12, 15, 12, 15, 15, 10, 13, 14, 13, 13, 14, 13, 15, + 15, 9, 11, 14, 10, 13, 15, 11, 13, 14, 9, 13, 15, 11, 12, 15, + 13, 15, 15, 13, 13, 15, 12, 13, 14, 14, 14, 14 } + }, + { + { 0, 5, 12, 3, 7, 12, 9, 11, 13, 3, 7, 12, 6, 8, 12, 9, + 11, 13, 9, 10, 13, 10, 10, 14, 11, 12, 13, 1, 6, 11, 5, 7, + 12, 9, 11, 13, 5, 8, 11, 6, 8, 12, 10, 11, 13, 9, 11, 13, + 10, 11, 13, 12, 12, 13, 6, 8, 12, 8, 9, 12, 10, 12, 13, 8, + 9, 12, 8, 10, 12, 11, 12, 14, 10, 12, 13, 11, 12, 13, 12, 13, + 14, 9, 10, 12, 10, 11, 12, 13, 13, 13, 10, 11, 12, 11, 12, 13, + 12, 13, 13, 12, 12, 13, 12, 12, 14, 12, 13, 13 }, + { 0, 5, 14, 3, 10, 14, 14, 14, 14, 3, 8, 14, 6, 8, 14, 9, + 14, 14, 9, 14, 14, 14, 14, 14, 14, 14, 14, 1, 5, 14, 5, 9, + 14, 8, 14, 14, 4, 9, 14, 7, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 5, 7, 14, 9, 9, 14, 14, 14, 14, 14, + 14, 14, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 10, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14 } + }, + { 1, 2, 3, 4, 5, 6, 8, 8, 9, 9, 10, 10, 11, 12, 12, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 14 } + } +}; + +static const CoeffLens rv60_inter_lens[7] = { + { + { + { 0, 6, 4, 6, 5, 6, 5, 5, 6, 8, 7, 8, 7, 8, 7, 6, + 11, 13, 11, 11, 12, 11, 10, 8, 6, 8, 6, 7, 7, 8, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 7, 13, 14, 12, 12, 13, 12, 11, 9, + 10, 12, 9, 10, 11, 11, 9, 8, 12, 14, 11, 11, 12, 12, 10, 9, + 14, 15, 13, 13, 14, 14, 12, 10, 6, 8, 7, 8, 7, 8, 7, 6, + 8, 10, 9, 9, 9, 9, 8, 7, 13, 14, 12, 12, 13, 12, 11, 9, + 8, 10, 8, 9, 9, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 13, 12, 13, 13, 11, 9, 12, 14, 11, 11, 12, 12, 10, 9, + 14, 15, 12, 12, 13, 13, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 10, 12, 10, 11, 10, 11, 9, 8, 12, 14, 12, 12, 12, 12, 10, 9, + 14, 15, 13, 13, 14, 13, 11, 9, 12, 14, 11, 12, 12, 12, 10, 9, + 14, 15, 13, 12, 13, 12, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 13, 15, 12, 13, 13, 13, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 15, 15, 14, 14, 15, 14, 12, 9, 5, 8, 6, 7, 6, 8, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 7, 12, 14, 12, 12, 12, 12, 11, 9, + 7, 10, 8, 9, 8, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 12, 12, 13, 13, 11, 9, 11, 13, 10, 11, 12, 12, 10, 9, + 13, 15, 12, 12, 13, 13, 11, 9, 15, 15, 13, 13, 14, 14, 12, 10, + 7, 10, 8, 9, 8, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 13, 13, 13, 13, 11, 9, 9, 11, 9, 10, 10, 10, 9, 8, + 11, 13, 11, 11, 11, 11, 10, 8, 15, 15, 13, 13, 14, 13, 12, 10, + 13, 14, 11, 12, 13, 13, 11, 9, 14, 15, 12, 13, 13, 13, 11, 9, + 15, 15, 14, 14, 15, 14, 12, 10, 11, 13, 11, 11, 11, 11, 10, 8, + 13, 15, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 14, 13, 12, 10, + 13, 15, 12, 12, 12, 12, 11, 9, 14, 15, 13, 13, 13, 13, 11, 9, + 15, 15, 14, 14, 14, 14, 12, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 14, 14, 15, 14, 12, 9, + 8, 11, 9, 10, 9, 10, 9, 8, 11, 13, 11, 11, 11, 12, 10, 9, + 14, 15, 13, 13, 14, 14, 12, 10, 10, 12, 10, 11, 11, 11, 10, 9, + 13, 14, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 15, 14, 12, 10, + 12, 15, 11, 12, 13, 13, 11, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 14, 14, 15, 15, 13, 11, 10, 13, 11, 11, 10, 11, 10, 9, + 13, 14, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 15, 14, 12, 10, + 12, 14, 11, 12, 12, 12, 11, 9, 13, 15, 13, 13, 13, 13, 11, 10, + 15, 15, 15, 14, 15, 14, 13, 11, 14, 15, 12, 13, 14, 14, 12, 10, + 15, 15, 13, 13, 14, 14, 12, 10, 15, 15, 15, 15, 15, 15, 13, 10, + 12, 15, 12, 13, 12, 12, 11, 10, 14, 15, 14, 14, 13, 13, 12, 10, + 15, 15, 15, 15, 15, 14, 13, 10, 14, 15, 13, 13, 13, 13, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 15, 15, 15, 15, 13, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 14, 14, 15, 15, 12, 10, + 15, 15, 15, 14, 15, 15, 12, 10, 11, 13, 11, 12, 11, 12, 11, 10, + 13, 15, 13, 13, 13, 13, 12, 10, 15, 15, 14, 14, 15, 15, 13, 11, + 12, 14, 12, 12, 12, 13, 11, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 15, 15, 15, 15, 13, 11, 13, 15, 12, 13, 13, 14, 11, 10, + 15, 15, 13, 13, 14, 14, 12, 10, 15, 15, 14, 14, 15, 15, 12, 10, + 12, 14, 12, 13, 12, 13, 11, 10, 14, 15, 13, 14, 13, 13, 12, 10, + 15, 15, 15, 15, 15, 15, 13, 11, 13, 15, 13, 13, 13, 13, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 14, 15, 13, 13, 14, 14, 12, 10, 15, 15, 13, 14, 15, 14, 12, 10, + 15, 15, 14, 14, 15, 15, 12, 10, 13, 15, 13, 14, 12, 13, 11, 10, + 15, 15, 14, 14, 13, 13, 12, 10, 15, 15, 15, 15, 15, 14, 12, 10, + 14, 15, 14, 14, 13, 13, 12, 10, 15, 15, 14, 14, 14, 14, 12, 10, + 15, 15, 15, 15, 15, 14, 12, 10, 15, 15, 13, 14, 14, 14, 11, 9, + 15, 15, 14, 14, 14, 14, 11, 9, 15, 15, 13, 13, 14, 13, 11, 8 }, + { 0, 6, 3, 7, 4, 7, 6, 7, 5, 9, 7, 9, 8, 10, 8, 9, + 13, 15, 13, 13, 14, 14, 12, 12, 4, 9, 6, 8, 7, 10, 8, 9, + 8, 11, 9, 10, 10, 11, 10, 10, 15, 15, 14, 14, 14, 15, 13, 12, + 11, 14, 11, 12, 13, 14, 11, 11, 13, 15, 12, 13, 14, 15, 12, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 5, 9, 7, 9, 7, 9, 8, 9, + 8, 11, 9, 10, 10, 11, 10, 10, 15, 15, 14, 14, 14, 15, 13, 12, + 8, 11, 9, 10, 10, 11, 10, 10, 11, 13, 11, 11, 11, 12, 11, 11, + 15, 15, 14, 14, 15, 15, 13, 13, 13, 15, 12, 13, 14, 15, 12, 12, + 15, 15, 14, 14, 15, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 14, 12, 13, 11, 13, 12, 11, 14, 15, 13, 14, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 13, 14, 13, 14, 12, 12, + 15, 15, 14, 14, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 2, 8, 5, 8, 6, 9, 7, 8, + 7, 10, 8, 10, 9, 10, 9, 9, 14, 15, 13, 13, 14, 14, 13, 12, + 6, 10, 7, 9, 8, 10, 9, 9, 9, 12, 10, 11, 11, 12, 10, 10, + 15, 15, 14, 14, 15, 15, 13, 12, 12, 14, 11, 12, 13, 14, 12, 11, + 14, 15, 13, 13, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 6, 10, 8, 10, 8, 10, 9, 9, 9, 12, 10, 11, 10, 12, 10, 10, + 15, 15, 14, 14, 15, 15, 13, 13, 9, 12, 9, 11, 10, 12, 10, 10, + 11, 13, 11, 12, 12, 13, 11, 11, 15, 15, 14, 14, 15, 15, 14, 13, + 14, 15, 13, 13, 14, 15, 13, 12, 15, 15, 13, 14, 15, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 12, 15, 12, 13, 11, 13, 12, 12, + 14, 15, 14, 14, 13, 14, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 13, 14, 13, 14, 13, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 7, 11, 9, 10, 9, 11, 10, 10, 11, 13, 11, 12, 12, 13, 11, 11, + 15, 15, 15, 15, 15, 15, 14, 13, 9, 13, 10, 11, 11, 13, 11, 11, + 12, 14, 12, 13, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 13, 15, 12, 14, 14, 15, 13, 12, 15, 15, 14, 14, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 13, 10, 12, 10, 12, 11, 11, + 12, 14, 12, 13, 12, 13, 12, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 11, 14, 12, 12, 12, 13, 12, 11, 13, 15, 13, 13, 13, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 14, 14, 15, 15, 14, 13, + 15, 15, 14, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 13, 15, 14, 14, 12, 14, 13, 12, 15, 15, 15, 15, 14, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 10, 14, 11, 13, 12, 14, 12, 12, + 13, 15, 13, 14, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 15, 12, 13, 13, 14, 12, 12, 14, 15, 14, 14, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 14, 15, 13, 14, 15, 15, 13, 13, + 15, 15, 14, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 15, 13, 13, 12, 14, 12, 12, 14, 15, 14, 14, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 13, 14, 13, 15, 13, 13, + 15, 15, 14, 15, 15, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 14, 15, 15, 15, 14, 13, 15, 15, 14, 15, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 14, 15, 12, 15, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 15, 15, 14, 15, 13, 13, 15, 15, 15, 15, 14, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 13, 12 } + }, + { + { 0, 4, 7, 3, 5, 8, 6, 8, 9, 3, 5, 8, 5, 6, 8, 8, + 8, 9, 6, 7, 9, 7, 8, 9, 8, 9, 9, 3, 5, 8, 4, 6, + 9, 7, 8, 9, 5, 6, 8, 6, 7, 9, 8, 9, 9, 7, 8, 9, + 8, 9, 9, 9, 9, 9, 6, 8, 9, 7, 8, 10, 8, 9, 10, 7, + 8, 10, 8, 9, 10, 9, 10, 10, 8, 9, 10, 9, 10, 10, 10, 10, + 10, 8, 10, 10, 9, 10, 11, 9, 10, 10, 9, 10, 10, 9, 10, 11, + 10, 10, 10, 9, 10, 10, 9, 10, 10, 9, 9, 9 }, + { 0, 4, 9, 2, 6, 10, 8, 9, 12, 3, 6, 10, 5, 7, 10, 9, + 10, 12, 8, 9, 11, 9, 10, 12, 11, 12, 13, 2, 5, 10, 4, 7, + 10, 8, 10, 12, 5, 7, 10, 6, 8, 11, 10, 10, 12, 8, 10, 12, + 9, 10, 12, 12, 12, 13, 7, 9, 11, 8, 9, 12, 10, 11, 13, 8, + 9, 12, 9, 10, 12, 11, 12, 13, 10, 11, 13, 11, 12, 13, 13, 13, + 13, 10, 11, 13, 11, 12, 14, 12, 13, 14, 10, 12, 13, 11, 12, 14, + 12, 13, 14, 11, 12, 14, 12, 13, 14, 13, 13, 13 } + }, + { + { 0, 4, 7, 3, 5, 8, 6, 8, 9, 3, 5, 8, 5, 6, 9, 7, + 8, 9, 6, 8, 9, 8, 8, 9, 8, 9, 9, 3, 5, 8, 4, 6, + 8, 7, 8, 9, 5, 6, 8, 6, 7, 9, 8, 9, 10, 7, 8, 9, + 8, 9, 10, 9, 10, 9, 5, 8, 9, 7, 8, 10, 8, 9, 10, 7, + 8, 10, 8, 9, 10, 9, 10, 10, 8, 10, 10, 9, 10, 10, 10, 10, + 10, 8, 10, 11, 9, 10, 11, 9, 10, 10, 9, 10, 11, 10, 10, 11, + 10, 10, 10, 10, 11, 11, 10, 11, 11, 10, 10, 9 }, + { 0, 3, 10, 2, 6, 11, 7, 10, 13, 3, 6, 11, 5, 8, 12, 9, + 11, 14, 9, 10, 13, 10, 11, 14, 13, 13, 15, 2, 6, 11, 4, 7, + 12, 8, 10, 14, 5, 8, 12, 7, 9, 12, 10, 11, 14, 10, 11, 14, + 11, 12, 14, 13, 14, 15, 7, 9, 12, 8, 10, 13, 11, 13, 15, 9, + 10, 13, 10, 11, 14, 12, 13, 15, 12, 13, 15, 12, 13, 15, 14, 14, + 15, 11, 12, 14, 12, 13, 15, 14, 14, 15, 12, 13, 15, 13, 14, 15, + 14, 15, 15, 14, 14, 15, 14, 14, 15, 15, 15, 15 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, + 11, 12, 12, 12, 12, 12, 13, 13, 12, 12, 12, 13, 15, 15, 15, 15 } + }, + { + { + { 0, 6, 4, 6, 5, 6, 5, 5, 6, 8, 7, 8, 7, 8, 7, 6, + 11, 13, 11, 11, 12, 11, 10, 8, 6, 8, 6, 7, 7, 8, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 7, 13, 14, 12, 12, 13, 12, 11, 9, + 10, 12, 9, 10, 11, 11, 9, 8, 12, 14, 11, 11, 12, 12, 10, 9, + 14, 15, 13, 13, 14, 14, 12, 10, 6, 8, 7, 8, 7, 8, 7, 6, + 8, 10, 9, 9, 9, 9, 8, 7, 13, 14, 12, 12, 13, 12, 11, 9, + 8, 10, 8, 9, 9, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 13, 12, 13, 13, 11, 9, 12, 14, 11, 11, 12, 12, 10, 9, + 14, 15, 12, 12, 13, 13, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 10, 12, 10, 11, 10, 11, 9, 8, 12, 14, 12, 12, 12, 12, 10, 9, + 14, 15, 13, 13, 14, 13, 11, 9, 12, 14, 11, 12, 12, 12, 10, 9, + 14, 15, 13, 12, 13, 12, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 13, 15, 12, 13, 13, 13, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 15, 15, 14, 14, 15, 14, 12, 9, 5, 8, 6, 7, 6, 8, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 7, 12, 14, 12, 12, 12, 12, 11, 9, + 7, 10, 8, 9, 8, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 12, 12, 13, 13, 11, 9, 11, 13, 10, 11, 12, 12, 10, 9, + 13, 15, 12, 12, 13, 13, 11, 9, 15, 15, 13, 13, 14, 14, 12, 10, + 7, 10, 8, 9, 8, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 13, 13, 13, 13, 11, 9, 9, 11, 9, 10, 10, 10, 9, 8, + 11, 13, 11, 11, 11, 11, 10, 8, 15, 15, 13, 13, 14, 13, 12, 10, + 13, 14, 11, 12, 13, 13, 11, 9, 14, 15, 12, 13, 13, 13, 11, 9, + 15, 15, 14, 14, 15, 14, 12, 10, 11, 13, 11, 11, 11, 11, 10, 8, + 13, 15, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 14, 13, 12, 10, + 13, 15, 12, 12, 12, 12, 11, 9, 14, 15, 13, 13, 13, 13, 11, 9, + 15, 15, 14, 14, 14, 14, 12, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 14, 14, 15, 14, 12, 9, + 8, 11, 9, 10, 9, 10, 9, 8, 11, 13, 11, 11, 11, 12, 10, 9, + 14, 15, 13, 13, 14, 14, 12, 10, 10, 12, 10, 11, 11, 11, 10, 9, + 13, 14, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 15, 14, 12, 10, + 12, 15, 11, 12, 13, 13, 11, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 14, 14, 15, 15, 13, 11, 10, 13, 11, 11, 10, 11, 10, 9, + 13, 14, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 15, 14, 12, 10, + 12, 14, 11, 12, 12, 12, 11, 9, 13, 15, 13, 13, 13, 13, 11, 10, + 15, 15, 15, 14, 15, 14, 13, 11, 14, 15, 12, 13, 14, 14, 12, 10, + 15, 15, 13, 13, 14, 14, 12, 10, 15, 15, 15, 15, 15, 15, 13, 10, + 12, 15, 12, 13, 12, 12, 11, 10, 14, 15, 14, 14, 13, 13, 12, 10, + 15, 15, 15, 15, 15, 14, 13, 10, 14, 15, 13, 13, 13, 13, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 15, 15, 15, 15, 13, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 14, 14, 15, 15, 12, 10, + 15, 15, 15, 14, 15, 15, 12, 10, 11, 13, 11, 12, 11, 12, 11, 10, + 13, 15, 13, 13, 13, 13, 12, 10, 15, 15, 14, 14, 15, 15, 13, 11, + 12, 14, 12, 12, 12, 13, 11, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 15, 15, 15, 15, 13, 11, 13, 15, 12, 13, 13, 14, 11, 10, + 15, 15, 13, 13, 14, 14, 12, 10, 15, 15, 14, 14, 15, 15, 12, 10, + 12, 14, 12, 13, 12, 13, 11, 10, 14, 15, 13, 14, 13, 13, 12, 10, + 15, 15, 15, 15, 15, 15, 13, 11, 13, 15, 13, 13, 13, 13, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 14, 15, 13, 13, 14, 14, 12, 10, 15, 15, 13, 14, 15, 14, 12, 10, + 15, 15, 14, 14, 15, 15, 12, 10, 13, 15, 13, 14, 12, 13, 11, 10, + 15, 15, 14, 14, 13, 13, 12, 10, 15, 15, 15, 15, 15, 14, 12, 10, + 14, 15, 14, 14, 13, 13, 12, 10, 15, 15, 14, 14, 14, 14, 12, 10, + 15, 15, 15, 15, 15, 14, 12, 10, 15, 15, 13, 14, 14, 14, 11, 9, + 15, 15, 14, 14, 14, 14, 11, 9, 15, 15, 13, 13, 14, 13, 11, 8 }, + { 0, 6, 3, 7, 4, 7, 6, 7, 5, 9, 7, 9, 8, 10, 8, 9, + 13, 15, 13, 13, 14, 14, 12, 12, 4, 9, 6, 8, 7, 10, 8, 9, + 8, 11, 9, 10, 10, 11, 10, 10, 15, 15, 14, 14, 14, 15, 13, 12, + 11, 14, 11, 12, 13, 14, 11, 11, 13, 15, 12, 13, 14, 15, 12, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 5, 9, 7, 9, 7, 9, 8, 9, + 8, 11, 9, 10, 10, 11, 10, 10, 15, 15, 14, 14, 14, 15, 13, 12, + 8, 11, 9, 10, 10, 11, 10, 10, 11, 13, 11, 11, 11, 12, 11, 11, + 15, 15, 14, 14, 15, 15, 13, 13, 13, 15, 12, 13, 14, 15, 12, 12, + 15, 15, 14, 14, 15, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 14, 12, 13, 11, 13, 12, 11, 14, 15, 13, 14, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 13, 14, 13, 14, 12, 12, + 15, 15, 14, 14, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 2, 8, 5, 8, 6, 9, 7, 8, + 7, 10, 8, 10, 9, 10, 9, 9, 14, 15, 13, 13, 14, 14, 13, 12, + 6, 10, 7, 9, 8, 10, 9, 9, 9, 12, 10, 11, 11, 12, 10, 10, + 15, 15, 14, 14, 15, 15, 13, 12, 12, 14, 11, 12, 13, 14, 12, 11, + 14, 15, 13, 13, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 6, 10, 8, 10, 8, 10, 9, 9, 9, 12, 10, 11, 10, 12, 10, 10, + 15, 15, 14, 14, 15, 15, 13, 13, 9, 12, 9, 11, 10, 12, 10, 10, + 11, 13, 11, 12, 12, 13, 11, 11, 15, 15, 14, 14, 15, 15, 14, 13, + 14, 15, 13, 13, 14, 15, 13, 12, 15, 15, 13, 14, 15, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 12, 15, 12, 13, 11, 13, 12, 12, + 14, 15, 14, 14, 13, 14, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 13, 14, 13, 14, 13, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 7, 11, 9, 10, 9, 11, 10, 10, 11, 13, 11, 12, 12, 13, 11, 11, + 15, 15, 15, 15, 15, 15, 14, 13, 9, 13, 10, 11, 11, 13, 11, 11, + 12, 14, 12, 13, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 13, 15, 12, 14, 14, 15, 13, 12, 15, 15, 14, 14, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 13, 10, 12, 10, 12, 11, 11, + 12, 14, 12, 13, 12, 13, 12, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 11, 14, 12, 12, 12, 13, 12, 11, 13, 15, 13, 13, 13, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 14, 14, 15, 15, 14, 13, + 15, 15, 14, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 13, 15, 14, 14, 12, 14, 13, 12, 15, 15, 15, 15, 14, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 10, 14, 11, 13, 12, 14, 12, 12, + 13, 15, 13, 14, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 15, 12, 13, 13, 14, 12, 12, 14, 15, 14, 14, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 14, 15, 13, 14, 15, 15, 13, 13, + 15, 15, 14, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 15, 13, 13, 12, 14, 12, 12, 14, 15, 14, 14, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 13, 14, 13, 15, 13, 13, + 15, 15, 14, 15, 15, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 14, 15, 15, 15, 14, 13, 15, 15, 14, 15, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 14, 15, 12, 15, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 15, 15, 14, 15, 13, 13, 15, 15, 15, 15, 14, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 13, 12 } + }, + { + { 0, 4, 7, 3, 5, 8, 6, 8, 9, 3, 5, 8, 5, 6, 8, 8, + 8, 9, 6, 7, 9, 7, 8, 9, 8, 9, 9, 3, 5, 8, 4, 6, + 9, 7, 8, 9, 5, 6, 8, 6, 7, 9, 8, 9, 9, 7, 8, 9, + 8, 9, 9, 9, 9, 9, 6, 8, 9, 7, 8, 10, 8, 9, 10, 7, + 8, 10, 8, 9, 10, 9, 10, 10, 8, 9, 10, 9, 10, 10, 10, 10, + 10, 8, 10, 10, 9, 10, 11, 9, 10, 10, 9, 10, 10, 9, 10, 11, + 10, 10, 10, 9, 10, 10, 9, 10, 10, 9, 9, 9 }, + { 0, 4, 9, 2, 6, 10, 8, 9, 12, 3, 6, 10, 5, 7, 10, 9, + 10, 12, 8, 9, 11, 9, 10, 12, 11, 12, 13, 2, 5, 10, 4, 7, + 10, 8, 10, 12, 5, 7, 10, 6, 8, 11, 10, 10, 12, 8, 10, 12, + 9, 10, 12, 12, 12, 13, 7, 9, 11, 8, 9, 12, 10, 11, 13, 8, + 9, 12, 9, 10, 12, 11, 12, 13, 10, 11, 13, 11, 12, 13, 13, 13, + 13, 10, 11, 13, 11, 12, 14, 12, 13, 14, 10, 12, 13, 11, 12, 14, + 12, 13, 14, 11, 12, 14, 12, 13, 14, 13, 13, 13 } + }, + { + { 0, 4, 7, 3, 5, 8, 6, 8, 9, 3, 5, 8, 5, 6, 9, 7, + 8, 9, 6, 8, 9, 8, 8, 9, 8, 9, 9, 3, 5, 8, 4, 6, + 8, 7, 8, 9, 5, 6, 8, 6, 7, 9, 8, 9, 10, 7, 8, 9, + 8, 9, 10, 9, 10, 9, 5, 8, 9, 7, 8, 10, 8, 9, 10, 7, + 8, 10, 8, 9, 10, 9, 10, 10, 8, 10, 10, 9, 10, 10, 10, 10, + 10, 8, 10, 11, 9, 10, 11, 9, 10, 10, 9, 10, 11, 10, 10, 11, + 10, 10, 10, 10, 11, 11, 10, 11, 11, 10, 10, 9 }, + { 0, 3, 10, 2, 6, 11, 7, 10, 13, 3, 6, 11, 5, 8, 12, 9, + 11, 14, 9, 10, 13, 10, 11, 14, 13, 13, 15, 2, 6, 11, 4, 7, + 12, 8, 10, 14, 5, 8, 12, 7, 9, 12, 10, 11, 14, 10, 11, 14, + 11, 12, 14, 13, 14, 15, 7, 9, 12, 8, 10, 13, 11, 13, 15, 9, + 10, 13, 10, 11, 14, 12, 13, 15, 12, 13, 15, 12, 13, 15, 14, 14, + 15, 11, 12, 14, 12, 13, 15, 14, 14, 15, 12, 13, 15, 13, 14, 15, + 14, 15, 15, 14, 14, 15, 14, 14, 15, 15, 15, 15 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, + 11, 12, 12, 12, 12, 12, 13, 13, 12, 12, 12, 13, 15, 15, 15, 15 } + }, + { + { + { 0, 5, 4, 5, 4, 5, 5, 5, 6, 8, 7, 8, 7, 8, 7, 6, + 12, 14, 12, 12, 12, 12, 11, 10, 5, 8, 6, 7, 7, 8, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 8, 13, 15, 13, 13, 13, 13, 12, 10, + 11, 13, 10, 11, 11, 12, 10, 9, 13, 15, 12, 12, 13, 13, 11, 10, + 15, 15, 14, 14, 15, 15, 13, 11, 5, 8, 6, 8, 6, 7, 7, 6, + 8, 10, 9, 9, 9, 9, 8, 8, 13, 15, 13, 13, 13, 13, 12, 10, + 8, 10, 8, 9, 9, 9, 8, 8, 10, 12, 10, 11, 10, 11, 10, 9, + 15, 15, 14, 14, 14, 14, 12, 11, 12, 15, 12, 12, 13, 13, 11, 10, + 14, 15, 13, 13, 14, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 11, 13, 11, 12, 10, 11, 10, 9, 13, 14, 12, 13, 12, 12, 11, 10, + 15, 15, 14, 14, 14, 14, 13, 11, 12, 15, 12, 13, 12, 12, 11, 10, + 14, 15, 13, 13, 13, 13, 12, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 15, 15, 14, 14, 14, 15, 13, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 4, 8, 6, 7, 6, 7, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 8, 13, 15, 13, 13, 13, 13, 12, 10, + 7, 10, 8, 9, 8, 9, 8, 8, 10, 12, 10, 10, 10, 11, 9, 9, + 14, 15, 14, 14, 14, 14, 12, 11, 11, 14, 10, 12, 12, 13, 11, 10, + 13, 15, 12, 13, 13, 14, 12, 10, 15, 15, 15, 15, 15, 15, 13, 11, + 7, 10, 8, 9, 8, 9, 8, 8, 10, 12, 10, 11, 10, 10, 9, 9, + 14, 15, 14, 14, 14, 14, 12, 11, 9, 12, 10, 10, 10, 10, 9, 9, + 11, 13, 11, 12, 11, 12, 10, 9, 15, 15, 14, 14, 14, 14, 13, 11, + 13, 15, 12, 13, 13, 13, 12, 10, 14, 15, 13, 13, 14, 14, 12, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 12, 14, 12, 12, 11, 12, 11, 10, + 13, 15, 13, 13, 12, 13, 12, 10, 15, 15, 15, 15, 15, 14, 13, 11, + 13, 15, 13, 13, 12, 13, 11, 10, 14, 15, 14, 14, 13, 13, 12, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 15, 15, 14, 15, 15, 15, 13, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 8, 11, 9, 11, 10, 11, 10, 9, 11, 14, 11, 12, 12, 12, 11, 10, + 15, 15, 15, 15, 15, 15, 14, 12, 10, 13, 10, 12, 11, 12, 11, 10, + 13, 15, 12, 13, 13, 13, 12, 11, 15, 15, 15, 15, 15, 15, 14, 12, + 13, 15, 12, 13, 14, 14, 12, 11, 15, 15, 13, 14, 15, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 12, 10, 13, 11, 12, 11, 12, 11, 10, + 13, 15, 13, 13, 12, 13, 12, 11, 15, 15, 15, 15, 15, 15, 14, 12, + 12, 14, 12, 13, 12, 13, 11, 11, 13, 15, 13, 14, 13, 14, 12, 11, + 15, 15, 15, 15, 15, 15, 14, 12, 14, 15, 13, 14, 14, 15, 13, 12, + 15, 15, 14, 14, 15, 15, 13, 12, 15, 15, 15, 15, 15, 15, 14, 12, + 13, 15, 13, 14, 12, 13, 12, 11, 15, 15, 14, 15, 13, 14, 13, 11, + 15, 15, 15, 15, 15, 15, 14, 12, 14, 15, 14, 15, 13, 14, 13, 11, + 15, 15, 15, 15, 14, 14, 13, 12, 15, 15, 15, 15, 15, 15, 14, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 13, 11, 11, 13, 11, 13, 12, 13, 11, 11, + 13, 15, 13, 14, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 12, + 12, 15, 12, 13, 13, 14, 12, 11, 14, 15, 14, 14, 14, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 12, 13, 15, 12, 13, 14, 14, 12, 11, + 15, 15, 13, 14, 15, 15, 13, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 12, 15, 13, 14, 12, 13, 12, 11, 14, 15, 14, 15, 14, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 12, 13, 15, 13, 14, 13, 14, 12, 12, + 15, 15, 14, 15, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 14, 12, + 14, 15, 13, 14, 14, 15, 12, 11, 15, 15, 14, 14, 15, 15, 13, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 13, 15, 14, 14, 12, 13, 12, 11, + 15, 15, 15, 15, 13, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 14, 15, 14, 15, 13, 14, 12, 11, 15, 15, 15, 15, 13, 14, 13, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 15, 15, 14, 14, 14, 14, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 13, 14, 14, 14, 11, 9 }, + { 0, 5, 3, 7, 4, 7, 6, 8, 5, 9, 7, 9, 8, 10, 9, 10, + 13, 15, 13, 14, 14, 15, 14, 14, 4, 9, 6, 9, 7, 10, 8, 9, + 8, 11, 9, 11, 10, 12, 10, 11, 15, 15, 14, 15, 15, 15, 15, 15, + 11, 14, 11, 13, 13, 15, 13, 13, 14, 15, 13, 15, 15, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 9, 7, 9, 7, 9, 8, 9, + 8, 11, 9, 11, 9, 11, 10, 11, 15, 15, 14, 15, 15, 15, 14, 15, + 8, 11, 9, 11, 10, 12, 10, 11, 10, 13, 11, 13, 11, 13, 12, 12, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 13, 15, 14, 15, 14, 14, + 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 12, 14, 11, 14, 12, 13, 14, 15, 14, 15, 13, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 14, 15, 13, 15, 14, 14, + 15, 15, 15, 15, 14, 15, 14, 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, 2, 8, 5, 8, 6, 9, 7, 9, + 7, 10, 8, 10, 9, 11, 10, 11, 14, 15, 14, 15, 15, 15, 14, 14, + 6, 10, 7, 10, 9, 11, 9, 10, 9, 12, 10, 12, 11, 13, 11, 12, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 11, 14, 14, 15, 13, 13, + 14, 15, 13, 15, 15, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 10, 8, 10, 8, 11, 9, 10, 9, 12, 10, 12, 10, 12, 11, 12, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 12, 10, 12, 10, 12, 11, 12, + 11, 14, 11, 13, 12, 14, 12, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 13, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 11, 14, 13, 13, + 14, 15, 15, 15, 13, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 13, 15, 14, 14, 15, 15, 15, 15, 14, 15, 14, 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, + 7, 11, 9, 11, 9, 12, 10, 11, 10, 13, 11, 13, 12, 13, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 13, 10, 12, 11, 13, 11, 12, + 12, 15, 12, 14, 13, 15, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 12, 15, 14, 15, 14, 14, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 13, 10, 13, 10, 13, 11, 12, + 12, 15, 13, 14, 12, 14, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 12, 14, 12, 14, 13, 13, 12, 15, 13, 15, 13, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 14, 15, 12, 15, 13, 14, 15, 15, 15, 15, 14, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 14, 15, 14, 15, + 15, 15, 15, 15, 14, 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, 10, 14, 12, 14, 12, 14, 13, 13, + 13, 15, 13, 15, 14, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 12, 15, 13, 15, 13, 14, 14, 15, 14, 15, 14, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 13, 15, 13, 15, 14, 15, 14, 14, + 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 13, 15, 12, 15, 13, 14, 14, 15, 14, 15, 14, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 13, 15, 14, 14, + 14, 15, 14, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 14, 14, 15, 15, 14, 15, 15, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 14, 15, 12, 15, 13, 14, + 15, 15, 15, 15, 14, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 15, 15, 13, 15, 14, 14, 14, 15, 15, 15, 13, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 15, 15, 14, 15, 14, 14, 15, 15, 15, 15, 14, 15, 14, 13 } + }, + { + { 0, 3, 8, 3, 5, 9, 7, 9, 10, 3, 5, 9, 5, 7, 9, 9, + 9, 11, 7, 8, 10, 8, 9, 10, 10, 11, 11, 2, 5, 9, 5, 7, + 10, 8, 9, 11, 5, 6, 9, 6, 7, 10, 9, 10, 11, 8, 9, 10, + 9, 9, 11, 10, 11, 11, 7, 8, 11, 8, 9, 11, 9, 10, 12, 8, + 9, 11, 9, 10, 11, 10, 11, 12, 9, 10, 11, 10, 11, 11, 11, 11, + 11, 9, 11, 12, 10, 11, 12, 10, 11, 11, 10, 11, 12, 10, 11, 12, + 11, 11, 11, 10, 11, 11, 10, 11, 11, 11, 10, 10 }, + { 0, 3, 10, 2, 6, 11, 9, 10, 14, 3, 6, 11, 6, 8, 12, 10, + 12, 14, 8, 10, 13, 10, 11, 14, 13, 14, 15, 2, 5, 11, 5, 7, + 12, 9, 11, 14, 4, 7, 12, 7, 8, 12, 11, 12, 14, 9, 11, 13, + 11, 11, 14, 13, 14, 15, 7, 9, 13, 9, 11, 14, 11, 13, 15, 8, + 10, 14, 10, 11, 14, 12, 13, 15, 10, 12, 14, 12, 13, 14, 14, 14, + 14, 11, 12, 14, 12, 13, 14, 13, 14, 14, 11, 13, 14, 12, 13, 14, + 13, 14, 15, 12, 14, 15, 13, 14, 14, 14, 14, 14 } + }, + { + { 0, 3, 8, 3, 5, 9, 7, 9, 10, 3, 5, 9, 5, 7, 10, 9, + 10, 11, 7, 9, 10, 9, 10, 11, 10, 11, 11, 2, 5, 9, 4, 7, + 10, 8, 9, 11, 5, 7, 10, 6, 8, 10, 9, 10, 11, 8, 9, 11, + 9, 10, 11, 11, 11, 11, 6, 9, 11, 8, 9, 11, 10, 11, 12, 8, + 10, 11, 9, 10, 12, 11, 11, 12, 10, 11, 12, 11, 11, 12, 12, 12, + 12, 10, 11, 12, 11, 11, 12, 11, 12, 12, 11, 12, 13, 11, 12, 13, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11 }, + { 0, 5, 12, 2, 7, 13, 10, 12, 16, 3, 8, 13, 7, 10, 14, 12, + 13, 16, 11, 12, 16, 12, 14, 16, 15, 16, 16, 1, 7, 13, 5, 9, + 14, 11, 13, 16, 6, 9, 14, 8, 11, 15, 13, 14, 16, 12, 13, 16, + 13, 14, 16, 15, 15, 16, 9, 11, 14, 11, 12, 16, 14, 15, 16, 11, + 13, 16, 12, 13, 16, 15, 16, 16, 14, 15, 16, 15, 15, 16, 16, 16, + 16, 14, 15, 16, 15, 15, 16, 16, 16, 16, 15, 16, 16, 15, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, + 11, 12, 12, 12, 12, 13, 13, 13, 12, 12, 12, 13, 14, 14, 14, 14 } + }, + { + { + { 0, 5, 3, 5, 4, 5, 5, 5, 5, 8, 6, 8, 7, 8, 7, 7, + 13, 14, 12, 13, 13, 13, 12, 11, 5, 8, 6, 7, 7, 8, 7, 7, + 8, 10, 8, 10, 9, 10, 9, 9, 14, 15, 13, 14, 14, 14, 12, 11, + 11, 14, 10, 12, 12, 13, 11, 10, 13, 15, 12, 13, 13, 14, 12, 11, + 15, 15, 14, 15, 15, 15, 13, 12, 5, 8, 6, 8, 6, 7, 7, 7, + 8, 10, 9, 10, 9, 9, 9, 9, 14, 15, 13, 13, 13, 13, 12, 11, + 8, 10, 8, 10, 9, 10, 9, 9, 10, 12, 10, 11, 10, 11, 10, 10, + 15, 15, 14, 14, 14, 14, 13, 12, 12, 15, 12, 13, 13, 14, 12, 11, + 14, 15, 13, 14, 14, 15, 12, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 11, 13, 11, 12, 10, 11, 10, 10, 12, 15, 13, 13, 12, 12, 11, 11, + 15, 15, 14, 15, 14, 14, 13, 12, 12, 15, 13, 13, 12, 13, 12, 11, + 14, 15, 13, 14, 13, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 12, + 15, 15, 14, 15, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 4, 7, 6, 7, 6, 8, 7, 7, + 8, 10, 8, 10, 9, 10, 9, 9, 14, 15, 13, 14, 14, 14, 13, 11, + 7, 10, 7, 9, 8, 10, 8, 8, 10, 12, 10, 11, 10, 11, 10, 10, + 15, 15, 14, 14, 14, 14, 13, 12, 11, 14, 10, 12, 12, 13, 11, 11, + 13, 15, 12, 13, 14, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 12, + 7, 10, 8, 10, 8, 9, 8, 8, 10, 12, 10, 11, 10, 11, 10, 10, + 15, 15, 14, 14, 14, 14, 13, 12, 9, 12, 10, 11, 10, 11, 10, 10, + 11, 13, 11, 12, 11, 12, 11, 10, 15, 15, 14, 15, 14, 15, 13, 12, + 13, 15, 12, 13, 13, 14, 12, 11, 14, 15, 13, 14, 14, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 11, 14, 12, 13, 10, 12, 11, 11, + 13, 15, 13, 14, 12, 13, 12, 11, 15, 15, 15, 15, 15, 15, 13, 12, + 13, 15, 13, 14, 12, 13, 12, 11, 14, 15, 14, 15, 13, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 15, 15, 14, 15, 14, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 15, 15, 15, 15, 15, 15, 13, 11, + 8, 12, 9, 11, 10, 11, 10, 10, 11, 14, 12, 13, 12, 13, 12, 11, + 15, 15, 15, 15, 15, 15, 14, 13, 10, 13, 10, 12, 11, 12, 11, 11, + 12, 15, 12, 13, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 12, 15, 11, 13, 13, 15, 12, 12, 14, 15, 13, 14, 15, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 10, 13, 11, 12, 10, 12, 11, 11, + 12, 15, 13, 14, 12, 13, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 14, 12, 13, 12, 13, 12, 11, 13, 15, 13, 14, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 14, 15, 13, 14, 14, 15, 13, 12, + 14, 15, 13, 15, 15, 15, 13, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 12, 15, 13, 14, 11, 13, 12, 11, 14, 15, 14, 15, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 14, 15, 14, 15, 13, 14, 13, 12, + 14, 15, 15, 15, 13, 14, 13, 12, 15, 15, 15, 15, 15, 15, 14, 12, + 15, 15, 15, 15, 15, 15, 14, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 15, 15, 14, 15, 15, 15, 13, 11, 10, 13, 11, 13, 11, 13, 12, 12, + 13, 15, 13, 14, 13, 14, 13, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 15, 12, 14, 12, 14, 12, 12, 14, 15, 13, 15, 14, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 12, 15, 12, 14, 13, 15, 12, 11, + 15, 15, 13, 14, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 11, 15, 12, 14, 12, 13, 12, 12, 14, 15, 14, 15, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 12, 15, 13, 14, 13, 14, 13, 12, + 14, 15, 14, 15, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 13, + 13, 15, 13, 14, 14, 15, 12, 12, 14, 15, 13, 14, 14, 15, 13, 12, + 15, 15, 14, 15, 15, 15, 13, 11, 12, 15, 13, 15, 11, 13, 12, 11, + 14, 15, 14, 15, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 13, 11, + 13, 15, 14, 15, 12, 14, 12, 11, 14, 15, 14, 15, 13, 14, 12, 12, + 15, 15, 15, 15, 14, 15, 13, 11, 14, 15, 13, 14, 13, 14, 12, 11, + 14, 15, 13, 14, 13, 14, 12, 11, 15, 15, 13, 14, 13, 13, 11, 9 }, + { 0, 6, 3, 7, 3, 7, 7, 9, 5, 9, 7, 10, 8, 10, 10, 11, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 9, 6, 10, 8, 11, 9, 11, + 8, 12, 10, 12, 10, 13, 11, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 12, 15, 14, 15, 14, 15, 14, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 9, 7, 10, 6, 10, 9, 11, + 8, 12, 10, 13, 10, 12, 11, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 12, 10, 13, 10, 13, 11, 13, 10, 14, 12, 14, 12, 14, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 14, 15, 11, 15, 13, 15, 14, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 14, 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, 2, 8, 5, 9, 6, 9, 8, 10, + 7, 11, 9, 12, 9, 12, 11, 12, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 11, 7, 11, 9, 12, 10, 12, 9, 13, 11, 13, 11, 14, 12, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 12, 15, 14, 15, 14, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 11, 8, 12, 8, 11, 10, 12, 9, 13, 11, 14, 10, 13, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 13, 11, 13, 10, 13, 12, 13, + 10, 15, 12, 15, 12, 14, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 14, 15, 11, 15, 13, 15, + 14, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 14, 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, + 6, 12, 9, 13, 9, 13, 11, 13, 11, 14, 12, 14, 12, 14, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 14, 10, 14, 11, 14, 12, 14, + 12, 15, 13, 15, 13, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 12, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 14, 11, 14, 10, 14, 12, 13, + 12, 15, 13, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 12, 15, 12, 15, 13, 14, 12, 15, 13, 15, 13, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 14, 15, 11, 15, 14, 15, 15, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 14, 15, 15, 15, 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, 9, 15, 12, 15, 12, 15, 13, 14, + 13, 15, 14, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 12, 15, 13, 15, 13, 14, 14, 15, 14, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 12, 15, 14, 15, 14, 15, + 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 13, 15, 12, 15, 13, 14, 13, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 13, 15, 13, 15, 14, 15, + 14, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 14, 15, 15, 15, 15, 15, 14, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 11, 15, 13, 14, + 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 15, 15, 13, 15, 14, 15, 14, 15, 15, 15, 13, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 14, 15, 15, 15, 15, 15, 14, 15, 14, 15, 14, 14 } + }, + { + { 0, 3, 8, 3, 5, 9, 8, 9, 11, 3, 5, 9, 5, 7, 10, 9, + 10, 11, 7, 8, 10, 9, 10, 11, 11, 11, 11, 2, 5, 9, 5, 7, + 10, 8, 9, 11, 4, 7, 10, 6, 8, 11, 9, 10, 11, 8, 9, 11, + 9, 10, 11, 11, 11, 11, 7, 9, 11, 8, 9, 12, 10, 11, 12, 8, + 9, 12, 9, 10, 12, 10, 11, 12, 9, 10, 12, 10, 11, 12, 11, 11, + 11, 9, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12, + 11, 11, 11, 10, 11, 12, 10, 11, 12, 11, 11, 10 }, + { 0, 4, 12, 3, 7, 13, 10, 12, 15, 3, 6, 13, 6, 9, 14, 12, + 13, 15, 9, 11, 14, 11, 12, 15, 15, 15, 15, 1, 6, 12, 5, 8, + 14, 10, 12, 15, 4, 8, 14, 8, 10, 14, 12, 13, 15, 9, 12, 15, + 12, 13, 15, 15, 15, 15, 8, 10, 14, 9, 12, 15, 12, 13, 15, 9, + 11, 15, 11, 12, 15, 13, 13, 15, 11, 13, 15, 13, 14, 15, 15, 15, + 15, 11, 13, 15, 13, 14, 15, 14, 15, 15, 12, 14, 15, 13, 14, 15, + 14, 15, 15, 13, 15, 15, 14, 15, 15, 15, 15, 15 } + }, + { + { 0, 3, 9, 2, 6, 10, 8, 10, 12, 3, 5, 10, 5, 7, 11, 9, + 10, 12, 8, 10, 12, 10, 10, 12, 11, 12, 13, 2, 6, 10, 5, 7, + 11, 9, 10, 12, 5, 7, 11, 7, 9, 11, 10, 11, 12, 9, 10, 12, + 10, 11, 12, 12, 12, 13, 7, 9, 12, 9, 10, 12, 11, 12, 13, 9, + 10, 12, 10, 11, 13, 11, 12, 13, 11, 12, 13, 12, 12, 13, 13, 13, + 13, 11, 12, 13, 11, 12, 13, 12, 13, 13, 11, 12, 13, 12, 13, 13, + 12, 13, 13, 12, 13, 13, 12, 13, 13, 13, 13, 13 }, + { 0, 4, 14, 2, 8, 15, 12, 14, 16, 3, 8, 15, 7, 11, 16, 13, + 15, 16, 12, 14, 16, 13, 15, 16, 16, 16, 16, 1, 7, 14, 6, 11, + 15, 13, 15, 16, 6, 10, 15, 10, 12, 15, 14, 16, 16, 13, 15, 16, + 14, 16, 16, 16, 16, 16, 10, 12, 15, 12, 14, 16, 15, 16, 16, 12, + 14, 16, 13, 15, 16, 16, 16, 16, 15, 16, 16, 16, 16, 16, 16, 16, + 16, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, + 11, 11, 12, 12, 12, 13, 13, 13, 13, 12, 12, 13, 15, 15, 15, 15 } + }, + { + { + { 0, 5, 3, 6, 3, 6, 5, 6, 5, 8, 7, 8, 7, 8, 8, 8, + 13, 15, 13, 13, 13, 13, 12, 12, 5, 8, 6, 8, 7, 9, 8, 8, + 8, 11, 9, 10, 9, 11, 10, 10, 14, 15, 14, 14, 13, 14, 13, 12, + 11, 14, 10, 12, 12, 14, 11, 11, 12, 15, 12, 13, 13, 14, 12, 12, + 15, 15, 14, 15, 14, 15, 13, 12, 5, 8, 7, 8, 6, 8, 8, 8, + 8, 11, 9, 10, 9, 10, 9, 10, 14, 15, 13, 14, 13, 14, 13, 12, + 8, 11, 9, 10, 9, 11, 9, 10, 10, 13, 10, 12, 11, 12, 11, 11, + 15, 15, 14, 15, 14, 15, 13, 12, 12, 15, 12, 14, 13, 14, 12, 12, + 14, 15, 13, 14, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 13, 13, + 10, 14, 12, 13, 10, 12, 11, 11, 12, 15, 13, 14, 11, 13, 12, 12, + 15, 15, 14, 15, 14, 15, 13, 12, 12, 15, 13, 14, 12, 13, 12, 12, + 13, 15, 13, 15, 13, 14, 12, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 14, 15, 14, 15, 14, 15, 13, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 13, 12, 3, 8, 6, 8, 6, 8, 7, 8, + 8, 11, 9, 10, 9, 10, 10, 10, 14, 15, 14, 14, 14, 14, 13, 12, + 6, 10, 7, 10, 8, 10, 9, 9, 10, 13, 10, 12, 11, 12, 11, 11, + 15, 15, 14, 15, 14, 15, 13, 13, 11, 15, 10, 13, 12, 14, 11, 11, + 13, 15, 12, 14, 13, 15, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 6, 10, 8, 10, 8, 10, 9, 9, 10, 12, 10, 12, 10, 11, 11, 11, + 15, 15, 14, 15, 14, 15, 13, 12, 9, 12, 10, 12, 10, 12, 10, 11, + 10, 14, 11, 13, 11, 13, 11, 11, 15, 15, 14, 15, 14, 15, 13, 13, + 13, 15, 12, 14, 13, 15, 12, 12, 13, 15, 12, 14, 14, 15, 13, 12, + 15, 15, 14, 15, 15, 15, 13, 13, 11, 14, 12, 14, 10, 12, 11, 11, + 13, 15, 13, 14, 12, 13, 12, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 13, 15, 13, 14, 12, 14, 12, 12, 13, 15, 14, 15, 12, 14, 12, 12, + 15, 15, 15, 15, 14, 15, 13, 12, 15, 15, 14, 15, 14, 15, 13, 12, + 15, 15, 14, 15, 14, 15, 13, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 7, 12, 9, 12, 9, 12, 10, 11, 11, 14, 12, 13, 11, 13, 12, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 9, 13, 10, 13, 11, 13, 11, 11, + 12, 15, 12, 14, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 12, 15, 11, 14, 13, 15, 12, 12, 14, 15, 13, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 9, 13, 11, 13, 10, 12, 11, 11, + 12, 15, 12, 14, 12, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 15, 12, 14, 12, 14, 12, 12, 12, 15, 13, 14, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 13, 15, 13, 15, 14, 15, 13, 13, + 14, 15, 13, 15, 14, 15, 13, 13, 15, 15, 14, 15, 15, 15, 14, 13, + 12, 15, 13, 15, 11, 13, 12, 12, 14, 15, 14, 15, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 13, 15, 14, 15, 13, 14, 13, 12, + 14, 15, 14, 15, 13, 14, 13, 13, 15, 15, 15, 15, 14, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 13, 13, 14, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 14, 15, 14, 15, 13, 12, 9, 14, 11, 14, 11, 13, 12, 12, + 13, 15, 13, 15, 13, 14, 13, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 15, 12, 14, 12, 14, 12, 12, 13, 15, 13, 15, 13, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 12, 15, 11, 14, 13, 15, 12, 12, + 14, 15, 13, 14, 14, 15, 12, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 11, 15, 12, 14, 11, 14, 12, 12, 13, 15, 14, 15, 13, 14, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 11, 15, 13, 15, 12, 14, 13, 12, + 13, 15, 14, 15, 13, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 13, + 12, 15, 12, 14, 13, 15, 12, 12, 13, 15, 12, 15, 14, 15, 12, 12, + 15, 15, 14, 15, 15, 15, 13, 12, 12, 15, 13, 15, 11, 13, 12, 11, + 14, 15, 14, 15, 12, 14, 12, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 12, 15, 13, 15, 12, 14, 12, 12, 13, 15, 14, 15, 12, 14, 12, 12, + 15, 15, 15, 15, 14, 15, 13, 12, 13, 15, 13, 14, 13, 14, 12, 11, + 13, 15, 12, 14, 12, 14, 12, 11, 14, 15, 12, 13, 12, 13, 11, 10 }, + { 0, 6, 4, 9, 4, 9, 8, 10, 5, 10, 9, 12, 8, 12, 11, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 11, 7, 11, 8, 12, 11, 13, + 9, 13, 11, 14, 11, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 11, 8, 12, 7, 11, 10, 13, + 9, 13, 11, 14, 10, 14, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 14, 11, 15, 11, 14, 13, 14, 11, 15, 13, 15, 13, 15, 14, 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, + 12, 15, 15, 15, 12, 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, 1, 9, 6, 11, 6, 11, 10, 12, + 7, 11, 10, 13, 10, 13, 12, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 12, 8, 13, 10, 13, 12, 13, 10, 15, 12, 15, 12, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 12, 10, 13, 8, 13, 11, 13, 10, 15, 12, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 12, 15, 11, 15, 13, 15, + 11, 15, 13, 15, 12, 15, 14, 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, 12, 15, 15, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 14, 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, + 7, 14, 10, 14, 10, 14, 13, 14, 11, 15, 13, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 11, 15, 12, 15, 13, 15, + 12, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 12, 15, 11, 15, 13, 15, + 12, 15, 14, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 13, 15, 13, 15, 14, 15, 12, 15, 14, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 15, 15, 12, 15, 14, 15, 15, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 14, 15, 15, 15, 14, 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, 9, 15, 13, 15, 12, 15, 14, 15, + 13, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 13, 15, 13, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 13, 15, 12, 15, 14, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 14, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 14, 15, 15, 15, 15, 15, 14, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 15, 15, 13, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 } + }, + { + { 0, 3, 9, 3, 6, 10, 8, 9, 12, 2, 6, 10, 6, 7, 11, 10, + 10, 12, 7, 9, 11, 9, 10, 12, 11, 12, 12, 2, 6, 10, 5, 7, + 11, 8, 10, 12, 5, 7, 11, 7, 8, 11, 10, 10, 12, 8, 10, 12, + 10, 10, 12, 11, 12, 12, 7, 9, 12, 8, 10, 12, 10, 11, 13, 8, + 10, 12, 9, 10, 13, 11, 11, 13, 9, 11, 13, 11, 11, 13, 12, 12, + 12, 9, 11, 12, 10, 11, 13, 10, 11, 12, 10, 11, 13, 11, 11, 13, + 11, 11, 12, 10, 11, 12, 11, 11, 12, 11, 11, 11 }, + { 0, 5, 14, 3, 8, 15, 11, 13, 15, 2, 7, 15, 7, 10, 15, 13, + 14, 15, 10, 12, 15, 13, 14, 15, 15, 15, 15, 1, 7, 14, 6, 10, + 15, 12, 14, 15, 5, 10, 15, 9, 11, 15, 13, 14, 15, 10, 13, 15, + 13, 14, 15, 15, 15, 15, 8, 11, 15, 10, 13, 15, 13, 15, 15, 10, + 13, 15, 11, 13, 15, 14, 15, 15, 12, 14, 15, 14, 15, 15, 15, 15, + 15, 12, 15, 15, 13, 15, 15, 15, 15, 15, 13, 15, 15, 14, 15, 15, + 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15 } + }, + { + { 0, 3, 9, 2, 6, 10, 8, 10, 12, 3, 6, 10, 5, 7, 11, 9, + 10, 12, 8, 10, 12, 10, 11, 12, 12, 12, 13, 2, 5, 10, 5, 7, + 11, 9, 10, 12, 5, 7, 11, 7, 9, 11, 10, 11, 13, 9, 10, 12, + 10, 11, 13, 12, 12, 13, 7, 9, 12, 8, 10, 12, 11, 12, 14, 9, + 10, 12, 10, 11, 13, 12, 12, 14, 11, 12, 13, 12, 12, 13, 13, 13, + 14, 11, 12, 13, 11, 12, 13, 12, 13, 14, 11, 12, 13, 12, 13, 14, + 13, 13, 14, 12, 13, 14, 13, 13, 14, 13, 13, 13 }, + { 0, 4, 14, 2, 8, 16, 13, 16, 16, 3, 8, 16, 7, 11, 16, 14, + 16, 16, 12, 14, 16, 13, 15, 16, 16, 16, 16, 1, 7, 14, 6, 10, + 16, 13, 16, 16, 6, 10, 15, 10, 12, 16, 15, 16, 16, 14, 16, 16, + 14, 16, 16, 16, 16, 16, 10, 12, 15, 12, 14, 16, 16, 16, 16, 12, + 14, 16, 13, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, + 11, 12, 12, 12, 12, 13, 13, 13, 12, 12, 12, 13, 14, 14, 14, 14 } + }, + { + { + { 0, 5, 4, 6, 3, 6, 6, 7, 5, 8, 7, 9, 7, 9, 8, 9, + 13, 15, 13, 14, 13, 14, 12, 12, 4, 9, 6, 9, 7, 9, 8, 9, + 8, 11, 9, 11, 9, 11, 10, 10, 14, 15, 14, 14, 13, 14, 13, 12, + 10, 15, 10, 13, 12, 14, 11, 12, 12, 15, 12, 13, 13, 14, 12, 12, + 15, 15, 14, 15, 14, 15, 13, 13, 4, 8, 7, 9, 6, 8, 8, 8, + 8, 11, 9, 11, 8, 10, 10, 10, 14, 15, 13, 14, 13, 14, 13, 12, + 7, 11, 9, 11, 9, 11, 10, 10, 9, 13, 10, 12, 10, 12, 11, 11, + 14, 15, 14, 15, 14, 14, 13, 13, 12, 15, 12, 14, 13, 14, 12, 12, + 13, 15, 12, 14, 13, 15, 13, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 10, 14, 11, 13, 9, 12, 11, 11, 12, 15, 12, 14, 11, 13, 12, 12, + 15, 15, 14, 15, 13, 15, 13, 12, 12, 15, 13, 14, 11, 13, 12, 12, + 13, 15, 13, 15, 12, 14, 12, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 14, 15, 14, 15, 14, 15, 13, 13, 15, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 13, 12, 3, 8, 6, 8, 6, 8, 8, 8, + 7, 11, 9, 11, 9, 10, 10, 10, 14, 15, 14, 14, 13, 14, 13, 12, + 6, 11, 7, 10, 8, 10, 9, 10, 9, 12, 10, 12, 10, 12, 10, 11, + 15, 15, 14, 15, 14, 15, 13, 13, 10, 15, 10, 13, 12, 14, 11, 12, + 13, 15, 12, 14, 13, 15, 12, 12, 15, 15, 14, 15, 15, 15, 13, 13, + 6, 10, 8, 10, 7, 10, 9, 10, 9, 12, 10, 12, 10, 11, 10, 11, + 15, 15, 14, 15, 14, 14, 13, 13, 8, 12, 10, 12, 9, 12, 10, 11, + 10, 13, 10, 13, 10, 12, 11, 11, 15, 15, 14, 15, 14, 15, 13, 13, + 12, 15, 12, 14, 13, 14, 12, 12, 13, 15, 12, 14, 13, 15, 12, 12, + 15, 15, 14, 15, 15, 15, 13, 13, 10, 15, 12, 14, 9, 12, 11, 11, + 12, 15, 13, 14, 11, 13, 12, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 12, 15, 13, 15, 11, 13, 12, 12, 12, 15, 13, 15, 12, 14, 12, 12, + 15, 15, 15, 15, 14, 15, 13, 12, 14, 15, 14, 15, 14, 15, 13, 13, + 14, 15, 14, 15, 14, 15, 13, 12, 15, 15, 14, 15, 14, 15, 13, 12, + 7, 12, 9, 12, 9, 12, 10, 11, 10, 14, 11, 13, 11, 13, 12, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 8, 13, 10, 13, 10, 13, 11, 11, + 11, 15, 12, 14, 12, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 15, 11, 14, 12, 15, 12, 12, 13, 15, 12, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 8, 13, 10, 13, 10, 12, 11, 11, + 11, 15, 12, 14, 11, 13, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 10, 14, 11, 13, 11, 13, 12, 12, 11, 15, 12, 14, 12, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 12, 15, 12, 14, 13, 15, 12, 13, + 13, 15, 12, 15, 14, 15, 13, 13, 15, 15, 14, 15, 15, 15, 14, 13, + 11, 15, 12, 14, 10, 13, 11, 12, 13, 15, 14, 15, 12, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 12, 15, 13, 15, 12, 14, 12, 12, + 13, 15, 14, 15, 12, 14, 13, 12, 15, 15, 15, 15, 14, 15, 13, 13, + 14, 15, 14, 15, 14, 15, 13, 13, 14, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 13, 15, 13, 15, 12, 12, 9, 14, 11, 13, 10, 13, 11, 12, + 12, 15, 12, 14, 12, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 10, 14, 11, 14, 11, 14, 12, 12, 13, 15, 13, 15, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 11, 15, 11, 14, 12, 14, 11, 12, + 13, 15, 12, 14, 13, 15, 12, 12, 15, 15, 14, 15, 15, 15, 13, 12, + 10, 14, 12, 14, 11, 13, 12, 12, 13, 15, 13, 15, 12, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 11, 15, 12, 14, 12, 14, 12, 12, + 13, 15, 13, 15, 13, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 15, 12, 14, 12, 15, 12, 12, 13, 15, 12, 14, 13, 15, 12, 12, + 15, 15, 14, 15, 15, 15, 13, 12, 11, 15, 12, 14, 10, 13, 11, 11, + 13, 15, 13, 15, 12, 14, 12, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 11, 15, 13, 14, 11, 14, 12, 12, 13, 15, 13, 15, 12, 14, 12, 12, + 15, 15, 15, 15, 14, 14, 13, 12, 12, 15, 12, 15, 12, 14, 11, 11, + 12, 15, 12, 14, 12, 14, 11, 11, 13, 15, 12, 13, 12, 13, 11, 10 }, + { 0, 7, 4, 9, 4, 9, 9, 11, 5, 10, 9, 12, 9, 12, 12, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 11, 7, 12, 9, 13, 11, 13, + 9, 14, 11, 14, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 11, 9, 13, 7, 12, 11, 13, + 9, 14, 12, 15, 11, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 14, 11, 15, 11, 15, 13, 15, 11, 15, 13, 15, 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, + 12, 15, 15, 15, 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, 1, 10, 6, 11, 6, 11, 10, 12, + 8, 12, 10, 14, 10, 14, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 13, 8, 14, 10, 14, 12, 14, 10, 15, 12, 15, 13, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 13, 10, 14, 8, 13, 12, 14, 10, 15, 13, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 12, 15, 12, 15, 14, 15, + 10, 15, 13, 15, 12, 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, 12, 15, 15, 15, 12, 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, + 6, 14, 10, 15, 10, 14, 13, 14, 11, 15, 13, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 11, 15, 12, 15, 14, 15, + 12, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 15, 12, 15, 11, 15, 14, 15, + 12, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 13, 15, 13, 15, 15, 15, 12, 15, 14, 15, 14, 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, + 12, 15, 15, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 14, 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, 8, 15, 12, 15, 12, 15, 14, 15, + 13, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 13, 15, 13, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 13, 15, 12, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 13, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 14, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 } + }, + { + { 0, 3, 9, 3, 6, 10, 8, 9, 12, 3, 5, 10, 6, 7, 11, 9, + 10, 12, 7, 9, 11, 9, 10, 12, 11, 12, 12, 2, 5, 10, 4, 7, + 11, 8, 10, 12, 4, 7, 11, 6, 8, 11, 10, 10, 12, 8, 9, 12, + 10, 10, 12, 11, 11, 12, 6, 9, 12, 7, 9, 12, 9, 11, 13, 7, + 9, 12, 9, 10, 12, 10, 11, 13, 9, 11, 13, 10, 11, 13, 12, 12, + 12, 9, 11, 12, 10, 11, 13, 10, 11, 12, 9, 11, 12, 10, 11, 13, + 11, 11, 12, 10, 11, 12, 11, 11, 12, 11, 11, 11 }, + { 0, 5, 14, 3, 8, 15, 11, 14, 15, 2, 7, 15, 7, 10, 15, 13, + 15, 15, 10, 13, 15, 13, 15, 15, 15, 15, 15, 1, 7, 15, 6, 10, + 15, 12, 15, 15, 5, 10, 15, 9, 11, 15, 14, 14, 15, 10, 14, 15, + 14, 15, 15, 15, 15, 15, 8, 11, 15, 10, 13, 15, 13, 15, 15, 9, + 13, 15, 12, 13, 15, 15, 15, 15, 12, 15, 15, 15, 15, 15, 15, 15, + 15, 12, 15, 15, 14, 15, 15, 15, 15, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 } + }, + { + { 0, 3, 9, 2, 6, 10, 8, 10, 12, 3, 6, 11, 5, 7, 11, 10, + 11, 13, 8, 10, 12, 10, 11, 13, 12, 12, 13, 2, 5, 10, 5, 7, + 11, 9, 11, 13, 5, 7, 11, 7, 9, 12, 10, 11, 13, 9, 10, 13, + 10, 11, 13, 12, 13, 13, 7, 9, 12, 8, 10, 13, 11, 12, 14, 8, + 10, 13, 9, 11, 13, 12, 12, 14, 11, 12, 14, 12, 12, 14, 13, 13, + 14, 10, 11, 13, 11, 12, 13, 12, 13, 14, 11, 12, 13, 12, 13, 14, + 13, 13, 14, 12, 13, 14, 13, 13, 14, 13, 13, 13 }, + { 0, 4, 14, 2, 8, 16, 13, 16, 16, 3, 8, 16, 7, 11, 16, 15, + 15, 16, 12, 15, 16, 13, 15, 16, 15, 16, 16, 1, 6, 16, 7, 10, + 16, 15, 16, 16, 6, 10, 16, 10, 13, 16, 16, 16, 16, 14, 16, 16, + 14, 16, 16, 16, 16, 16, 10, 11, 15, 12, 15, 16, 16, 16, 16, 12, + 13, 16, 13, 15, 16, 16, 16, 16, 16, 16, 16, 15, 16, 16, 16, 16, + 16, 16, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 10, 11, + 11, 12, 12, 12, 13, 13, 13, 13, 13, 12, 13, 14, 14, 15, 15, 14 } + }, + { + { + { 0, 6, 4, 8, 4, 7, 7, 8, 6, 9, 8, 10, 7, 10, 9, 10, + 14, 15, 14, 15, 13, 15, 13, 14, 4, 10, 6, 10, 7, 10, 9, 10, + 7, 12, 9, 12, 9, 12, 10, 11, 14, 15, 14, 15, 14, 15, 14, 14, + 10, 15, 10, 14, 12, 14, 12, 13, 12, 15, 12, 14, 13, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 14, 14, 4, 9, 7, 10, 6, 9, 9, 10, + 7, 11, 9, 12, 9, 11, 10, 11, 14, 15, 14, 15, 14, 15, 14, 14, + 7, 12, 9, 12, 9, 12, 10, 11, 9, 13, 10, 13, 10, 13, 11, 12, + 15, 15, 14, 15, 14, 15, 14, 14, 12, 15, 12, 15, 13, 15, 12, 13, + 13, 15, 13, 15, 14, 15, 13, 14, 15, 15, 15, 15, 15, 15, 14, 15, + 10, 15, 12, 14, 10, 13, 11, 12, 11, 15, 13, 15, 11, 14, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 14, 11, 15, 13, 15, 12, 14, 12, 13, + 13, 15, 14, 15, 12, 14, 13, 13, 15, 15, 15, 15, 15, 15, 14, 14, + 14, 15, 14, 15, 14, 15, 14, 14, 15, 15, 15, 15, 15, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 14, 14, 2, 9, 6, 9, 6, 9, 8, 9, + 7, 11, 9, 11, 9, 11, 10, 11, 14, 15, 14, 15, 14, 15, 14, 14, + 5, 11, 7, 11, 8, 11, 9, 11, 9, 13, 10, 12, 10, 13, 11, 12, + 15, 15, 15, 15, 14, 15, 14, 14, 10, 15, 10, 14, 12, 15, 12, 13, + 12, 15, 12, 15, 13, 15, 13, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 5, 11, 8, 11, 7, 11, 9, 11, 8, 13, 10, 13, 9, 12, 11, 12, + 15, 15, 15, 15, 14, 15, 14, 14, 7, 12, 9, 13, 9, 12, 11, 12, + 9, 13, 10, 13, 10, 13, 11, 12, 14, 15, 14, 15, 14, 15, 14, 14, + 12, 15, 12, 15, 13, 15, 13, 14, 12, 15, 11, 15, 13, 15, 13, 14, + 15, 15, 14, 15, 15, 15, 14, 14, 10, 15, 12, 14, 9, 13, 11, 12, + 12, 15, 13, 15, 11, 14, 12, 13, 15, 15, 15, 15, 14, 15, 14, 14, + 11, 15, 13, 15, 11, 14, 12, 13, 12, 15, 13, 15, 11, 14, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 14, 14, 15, 14, 15, 14, 15, 14, 14, + 14, 15, 14, 15, 14, 15, 13, 14, 15, 15, 15, 15, 14, 15, 14, 14, + 6, 12, 9, 12, 8, 12, 10, 11, 10, 14, 11, 13, 11, 13, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 14, 9, 13, 10, 13, 11, 12, + 11, 15, 12, 14, 12, 14, 12, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 10, 14, 12, 15, 12, 13, 13, 15, 12, 15, 14, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 13, 10, 13, 9, 13, 11, 12, + 11, 15, 12, 14, 11, 14, 12, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 14, 11, 14, 11, 14, 12, 13, 11, 15, 12, 14, 12, 14, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 12, 15, 13, 15, 13, 14, + 12, 15, 11, 15, 13, 15, 13, 14, 15, 15, 13, 15, 15, 15, 14, 15, + 10, 15, 12, 15, 10, 14, 12, 13, 13, 15, 13, 15, 12, 14, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 13, 15, 12, 15, 13, 13, + 12, 15, 13, 15, 11, 14, 13, 14, 15, 15, 15, 15, 14, 15, 14, 14, + 14, 15, 15, 15, 14, 15, 14, 14, 13, 15, 14, 15, 14, 15, 13, 14, + 14, 15, 13, 15, 14, 15, 13, 14, 8, 14, 11, 14, 10, 14, 12, 13, + 12, 15, 12, 15, 12, 14, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 9, 15, 11, 14, 11, 14, 12, 13, 13, 15, 13, 15, 13, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 14, 10, 15, 10, 14, 12, 15, 12, 13, + 13, 15, 12, 15, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 14, + 9, 15, 12, 14, 11, 14, 12, 13, 12, 15, 13, 15, 12, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 14, 10, 15, 12, 15, 11, 15, 12, 13, + 12, 15, 13, 15, 13, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 11, 15, 11, 15, 12, 15, 12, 13, 12, 15, 11, 15, 13, 15, 13, 13, + 15, 15, 14, 15, 15, 15, 14, 13, 10, 15, 12, 15, 10, 14, 11, 12, + 13, 15, 14, 15, 12, 14, 12, 13, 15, 15, 15, 15, 15, 15, 14, 14, + 11, 15, 12, 15, 11, 14, 12, 13, 12, 15, 13, 15, 12, 15, 12, 13, + 15, 15, 15, 15, 14, 15, 14, 13, 12, 15, 12, 15, 13, 15, 12, 13, + 12, 15, 12, 15, 12, 15, 12, 12, 13, 15, 12, 13, 13, 14, 12, 12 }, + { 0, 7, 5, 10, 4, 10, 9, 12, 6, 11, 10, 13, 10, 13, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 4, 12, 7, 13, 10, 14, 12, 14, + 9, 14, 12, 14, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 4, 12, 10, 14, 7, 13, 12, 14, + 9, 14, 13, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 9, 14, 12, 14, 12, 14, 14, 14, 11, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 12, 14, 14, 14, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 1, 11, 7, 12, 6, 12, 11, 13, + 7, 12, 11, 14, 11, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 5, 13, 9, 14, 10, 14, 13, 14, 10, 14, 12, 14, 13, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 13, 14, 13, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 5, 14, 11, 14, 8, 14, 13, 14, 10, 14, 14, 14, 13, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 12, 14, 13, 14, 14, 14, + 10, 14, 14, 14, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 12, 14, 14, 14, 12, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 5, 14, 10, 14, 9, 14, 13, 14, 10, 14, 13, 14, 12, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 8, 14, 11, 14, 12, 14, 14, 14, + 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 12, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 7, 14, 12, 14, 10, 14, 14, 14, + 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 10, 14, 14, 14, 13, 14, 14, 14, 11, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 11, 14, 14, 14, 11, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 7, 14, 12, 14, 11, 14, 14, 14, + 12, 14, 14, 14, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 10, 14, 12, 14, 13, 14, 14, 14, 13, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 12, 14, 12, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 9, 14, 14, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 11, 14, 14, 14, 13, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 11, 14, 14, 14, 12, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 14 } + }, + { + { 0, 4, 11, 3, 7, 12, 9, 11, 14, 3, 7, 12, 6, 8, 13, 11, + 12, 14, 9, 10, 13, 11, 12, 14, 13, 14, 15, 1, 6, 12, 5, 8, + 13, 9, 11, 14, 5, 8, 13, 7, 9, 14, 11, 12, 14, 9, 11, 14, + 11, 12, 14, 13, 14, 15, 6, 9, 13, 8, 10, 14, 10, 12, 15, 8, + 10, 14, 9, 11, 15, 11, 12, 15, 10, 12, 15, 12, 12, 15, 14, 13, + 15, 10, 11, 14, 11, 12, 14, 11, 13, 15, 10, 12, 14, 11, 12, 15, + 12, 13, 15, 11, 13, 15, 12, 13, 14, 13, 13, 14 }, + { 0, 5, 14, 3, 7, 15, 11, 13, 15, 2, 8, 15, 7, 10, 15, 15, + 15, 15, 11, 13, 15, 14, 15, 15, 15, 15, 15, 1, 7, 13, 6, 9, + 15, 12, 14, 15, 5, 10, 15, 9, 11, 15, 14, 14, 15, 11, 14, 15, + 15, 15, 15, 15, 15, 15, 8, 10, 15, 11, 13, 15, 15, 15, 15, 9, + 11, 15, 13, 13, 15, 14, 14, 15, 12, 15, 15, 15, 15, 15, 15, 15, + 15, 14, 14, 15, 14, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 } + }, + { + { 0, 4, 12, 3, 6, 12, 10, 12, 15, 3, 6, 12, 6, 8, 13, 11, + 13, 15, 9, 11, 14, 10, 12, 15, 14, 14, 15, 1, 5, 11, 5, 8, + 13, 11, 13, 15, 5, 8, 13, 8, 9, 14, 12, 13, 15, 10, 12, 14, + 11, 12, 15, 14, 14, 15, 7, 9, 12, 9, 11, 14, 13, 14, 15, 9, + 11, 14, 11, 12, 15, 13, 14, 15, 12, 14, 15, 13, 14, 15, 15, 15, + 15, 12, 13, 14, 13, 14, 15, 15, 15, 15, 12, 13, 15, 13, 14, 15, + 15, 15, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15 }, + { 0, 4, 14, 3, 8, 14, 15, 15, 15, 2, 9, 15, 7, 10, 15, 15, + 15, 15, 11, 15, 15, 15, 12, 15, 15, 15, 15, 1, 6, 15, 7, 11, + 15, 15, 15, 15, 6, 10, 15, 9, 12, 15, 15, 15, 15, 12, 15, 15, + 15, 15, 15, 15, 15, 15, 11, 11, 15, 15, 15, 15, 15, 15, 15, 12, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 12, 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, 14 } + }, + { 1, 2, 3, 4, 5, 6, 8, 8, 9, 9, 10, 10, 11, 11, 12, 14, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 15, 15, 14 } + } +}; + +#endif /* AVCODEC_RV60VLCS_H */ diff --git a/libavcodec/s302menc.c b/libavcodec/s302menc.c index 4b8996f9a..ba84ab73b 100644 --- a/libavcodec/s302menc.c +++ b/libavcodec/s302menc.c @@ -181,8 +181,6 @@ const FFCodec ff_s302m_encoder = { .priv_data_size = sizeof(S302MEncContext), .init = s302m_encode_init, FF_CODEC_ENCODE_CB(s302m_encode2_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]) { 48000, 0 }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), + CODEC_SAMPLERATES(48000), }; diff --git a/libavcodec/samidec.c b/libavcodec/samidec.c index 6576ce93f..d8a7624bc 100644 --- a/libavcodec/samidec.c +++ b/libavcodec/samidec.c @@ -25,6 +25,7 @@ */ #include "ass.h" +#include "libavutil/attributes.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/mem.h" @@ -174,7 +175,7 @@ static av_cold int sami_close(AVCodecContext *avctx) return 0; } -static void sami_flush(AVCodecContext *avctx) +static av_cold void sami_flush(AVCodecContext *avctx) { SAMIContext *sami = avctx->priv_data; if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP)) diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c index abd7981ac..fc07ec659 100644 --- a/libavcodec/sanm.c +++ b/libavcodec/sanm.c @@ -50,7 +50,8 @@ static const int8_t glyph8_y[GLYPH_COORD_VECT_SIZE] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 }; -static const int8_t motion_vectors[256][2] = { +/* codec47/bl16 motion vectors */ +static const int8_t c47_mv[256][2] = { { 0, 0 }, { -1, -43 }, { 6, -43 }, { -9, -42 }, { 13, -41 }, { -16, -40 }, { 19, -39 }, { -23, -36 }, { 26, -34 }, { -2, -33 }, { 4, -33 }, { -29, -32 }, { -9, -32 }, { 11, -31 }, { -16, -29 }, @@ -104,6 +105,7 @@ static const int8_t motion_vectors[256][2] = { { -6, 43 }, { 1, 43 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, }; +/* codec37/48 motion vector tables: 3x 510 bytes/255 x-y pairs */ static const int8_t c37_mv[] = { 0, 0, 1, 0, 2, 0, 3, 0, 5, 0, 8, 0, 13, 0, 21, 0, -1, 0, -2, 0, @@ -264,9 +266,9 @@ typedef struct SANMVideoContext { AVCodecContext *avctx; GetByteContext gb; - int version, subversion; + int version, subversion, have_dimensions, first_fob; uint32_t pal[PALETTE_SIZE]; - int16_t delta_pal[PALETTE_DELTA]; + int16_t delta_pal[PALETTE_DELTA], shift_pal[PALETTE_DELTA]; ptrdiff_t pitch; int width, height; @@ -274,16 +276,15 @@ typedef struct SANMVideoContext { int prev_seq; AVFrame *frame; - uint16_t *frm0, *frm1, *frm2; + uint16_t *fbuf, *frm0, *frm1, *frm2; uint8_t *stored_frame; - uint32_t frm0_size, frm1_size, frm2_size; + uint32_t fbuf_size, frm0_size, frm1_size, frm2_size; + uint32_t stor_size; uint32_t stored_frame_size; uint8_t *rle_buf; unsigned int rle_buf_size; - int rotate_code; - long npixels, buf_size; uint16_t codebook[256]; @@ -291,15 +292,15 @@ typedef struct SANMVideoContext { int8_t p4x4glyphs[NGLYPHS][16]; int8_t p8x8glyphs[NGLYPHS][64]; + uint8_t c47itbl[0x10000]; + uint8_t c23lut[256]; + uint8_t c4tbl[2][256][16]; + uint16_t c4param; + uint8_t c47cb[4]; + uint8_t c45tbl1[0x300]; + uint8_t c45tbl2[0x8000]; } SANMVideoContext; -typedef struct SANMFrameHeader { - int seq_num, codec, rotate_code, rle_output_size; - - uint16_t bg_color; - uint32_t width, height; -} SANMFrameHeader; - enum GlyphEdge { LEFT_EDGE, TOP_EDGE, @@ -449,6 +450,7 @@ static void init_sizes(SANMVideoContext *ctx, int width, int height) static void destroy_buffers(SANMVideoContext *ctx) { + av_freep(&ctx->fbuf); av_freep(&ctx->frm0); av_freep(&ctx->frm1); av_freep(&ctx->frm2); @@ -462,12 +464,15 @@ static void destroy_buffers(SANMVideoContext *ctx) static av_cold int init_buffers(SANMVideoContext *ctx) { + av_fast_padded_mallocz(&ctx->fbuf, &ctx->fbuf_size, ctx->buf_size); av_fast_padded_mallocz(&ctx->frm0, &ctx->frm0_size, ctx->buf_size); av_fast_padded_mallocz(&ctx->frm1, &ctx->frm1_size, ctx->buf_size); av_fast_padded_mallocz(&ctx->frm2, &ctx->frm2_size, ctx->buf_size); - if (!ctx->version) + if (!ctx->version) { av_fast_padded_mallocz(&ctx->stored_frame, &ctx->stored_frame_size, ctx->buf_size); + ctx->stor_size = 0; + } if (!ctx->frm0 || !ctx->frm1 || !ctx->frm2 || (!ctx->stored_frame && !ctx->version)) { @@ -478,6 +483,137 @@ static av_cold int init_buffers(SANMVideoContext *ctx) return 0; } +static void codec33_gen_tiles(SANMVideoContext *ctx, int8_t param1) +{ + uint8_t *dst = &(ctx->c4tbl[0][0][0]); + int i, j, k, l, m, n, o, p; + + for (i = 0; i < 8; i++) { + for (k = 0; k < 8; k++) { + j = i + param1; + l = k + param1; + p = (j + l) >> 1; + n = (j + p) >> 1; + m = (p + l) >> 1; + + *dst++ = p; *dst++ = p; *dst++ = n; *dst++ = j; + *dst++ = p; *dst++ = p; *dst++ = n; *dst++ = j; + *dst++ = m; *dst++ = m; *dst++ = p; *dst++ = j; + *dst++ = l; *dst++ = l; *dst++ = m; *dst++ = p; + } + } + + for (i = 0; i < 8; i++) { + for (k = 0; k < 8; k++) { + j = i + param1; + l = k + param1; + n = (j + l) >> 1; + m = (l + n) >> 1; + + *dst++ = j; *dst++ = j; *dst++ = j; *dst++ = j; + *dst++ = n; *dst++ = n; *dst++ = n; *dst++ = n; + *dst++ = m; *dst++ = m; *dst++ = m; *dst++ = m; + *dst++ = l; *dst++ = l; *dst++ = l; *dst++ = l; + } + } + + for (i = 0; i < 8; i++) { + for (k = 0; k < 8; k++) { + j = i + param1; + l = k + param1; + m = (j + l) >> 1; + n = (j + m) >> 1; + o = (l + m) >> 1; + + *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m; + *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m; + *dst++ = n; *dst++ = n; *dst++ = m; *dst++ = o; + *dst++ = m; *dst++ = m; *dst++ = o; *dst++ = l; + } + } + + for (i = 0; i < 8; i++) { + for (k = 0; k < 8; k++) { + j = i + param1; + l = k + param1; + m = (j + l) >> 1; + n = (l + m) >> 1; + + *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; + *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; + *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; + *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; + } + } +} + +static void codec4_gen_tiles(SANMVideoContext *ctx, uint16_t param1) +{ + uint8_t *dst = &(ctx->c4tbl[0][0][0]); + int i, j, k, l, m, n, o; + + for (i = 1; i < 16; i += 2) { + for (k = 0; k < 16; k++) { + j = i + param1; + l = k + param1; + m = (j + l) / 2; + n = (j + m) / 2; + o = (l + m) / 2; + if (j == m || l == m) { + *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = j; + *dst++ = j; *dst++ = l; *dst++ = j; *dst++ = j; + *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = j; + *dst++ = l; *dst++ = l; *dst++ = j; *dst++ = l; + } else { + *dst++ = m; *dst++ = m; *dst++ = n; *dst++ = j; + *dst++ = m; *dst++ = m; *dst++ = n; *dst++ = j; + *dst++ = o; *dst++ = o; *dst++ = m; *dst++ = n; + *dst++ = l; *dst++ = l; *dst++ = o; *dst++ = m; + } + } + } + + for (i = 0; i < 16; i += 2) { + for (k = 0; k < 16; k++) { + j = i + param1; + l = k + param1; + m = (j + l) / 2; + n = (j + m) / 2; + o = (l + m) / 2; + if (m == j || m == l) { + *dst++ = j; *dst++ = j; *dst++ = l; *dst++ = j; + *dst++ = j; *dst++ = j; *dst++ = j; *dst++ = l; + *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = l; + *dst++ = j; *dst++ = l; *dst++ = j; *dst++ = l; + } else { + *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m; + *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m; + *dst++ = n; *dst++ = n; *dst++ = m; *dst++ = o; + *dst++ = m; *dst++ = m; *dst++ = o; *dst++ = l; + } + } + } +} + + +static int codec4_load_tiles(SANMVideoContext *ctx, GetByteContext *gb, + uint16_t param2, uint8_t clr) +{ + uint8_t c, *dst = (uint8_t *)&(ctx->c4tbl[1][0][0]); + uint32_t loop = param2 * 8; + + if ((param2 > 256) || (bytestream2_get_bytes_left(gb) < loop)) + return AVERROR_INVALIDDATA; + + while (loop--) { + c = bytestream2_get_byteu(gb); + *dst++ = (c >> 4) + clr; + *dst++ = (c & 0xf) + clr; + } + + return 0; +} + static void rotate_bufs(SANMVideoContext *ctx, int rotate_code) { if (rotate_code == 2) @@ -499,6 +635,15 @@ static av_cold int decode_init(AVCodecContext *avctx) avctx->pix_fmt = ctx->version ? AV_PIX_FMT_RGB565 : AV_PIX_FMT_PAL8; + if (!ctx->version) { + // ANIM has no dimensions in the header, distrust the incoming data. + avctx->width = avctx->height = 0; + ctx->have_dimensions = 0; + } else if (avctx->width > 800 || avctx->height > 600 || + avctx->width < 8 || avctx->height < 8) { + // BL16 valid range is 8x8 - 800x600 + return AVERROR_INVALIDDATA; + } init_sizes(ctx, avctx->width, avctx->height); if (init_buffers(ctx)) { av_log(avctx, AV_LOG_ERROR, "Error allocating buffers.\n"); @@ -514,7 +659,10 @@ static av_cold int decode_init(AVCodecContext *avctx) ctx->subversion = AV_RL16(avctx->extradata); for (i = 0; i < PALETTE_SIZE; i++) ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4); + if (ctx->subversion < 2) + ctx->pal[0] = 0xFFU << 24; } + ctx->c4param = 0xffff; return 0; } @@ -528,23 +676,90 @@ static av_cold int decode_end(AVCodecContext *avctx) return 0; } -static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size) +static int old_codec4(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, + int w, int h, uint8_t param, uint16_t param2, int codec) +{ + const uint16_t mx = ctx->width, my = ctx->height, p = ctx->pitch; + uint8_t mask, bits, idx, *gs, *dst = (uint8_t *)ctx->fbuf; + int i, j, k, l, bit, ret, x, y; + + if (ctx->c4param != param) { + if (codec > 32) + codec33_gen_tiles(ctx, param); + else + codec4_gen_tiles(ctx, param); + ctx->c4param = param; + } + if (param2 > 0) { + ret = codec4_load_tiles(ctx, gb, param2, param); + if (ret) + return ret; + } + + if (codec > 32) + codec -= 29; + + for (j = 0; j < w; j += 4) { + mask = bits = 0; + x = left + j; + for (i = 0; i < h; i += 4) { + y = top + i; + if (param2 > 0) { + if (bits == 0) { + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + mask = bytestream2_get_byteu(gb); + bits = 8; + } + bit = !!(mask & 0x80); + mask <<= 1; + bits--; + } else { + bit = 0; + } + + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + idx = bytestream2_get_byteu(gb); + if ((bit == 0) && (idx == 0x80) && (codec != 5)) + continue; + if ((y >= my) || ((y + 4) < 0) || ((x + 4) < 0) || (x >= mx)) + continue; + gs = &(ctx->c4tbl[bit][idx][0]); + if ((y >= 0) && (x >= 0) && ((y + 4) < my) && ((x + 4) < mx)) { + for (k = 0; k < 4; k++, gs += 4) + memcpy(dst + x + (y + k) * p, gs, 4); + } else { + for (k = 0; k < 4; k++) { + for (l = 0; l < 4; l++, gs++) { + const int yo = y + k, xo = x + l; + if ((yo >= 0) && (yo < my) && (xo >= 0) && (xo < mx)) + *(dst + yo * p + xo) = *gs; + } + } + } + } + } + return 0; +} + +static int rle_decode(SANMVideoContext *ctx, GetByteContext *gb, uint8_t *dst, const int out_size) { int opcode, color, run_len, left = out_size; while (left > 0) { - opcode = bytestream2_get_byte(&ctx->gb); + opcode = bytestream2_get_byte(gb); run_len = (opcode >> 1) + 1; - if (run_len > left || bytestream2_get_bytes_left(&ctx->gb) <= 0) + if (run_len > left || bytestream2_get_bytes_left(gb) <= 0) return AVERROR_INVALIDDATA; if (opcode & 1) { - color = bytestream2_get_byte(&ctx->gb); + color = bytestream2_get_byte(gb); memset(dst, color, run_len); } else { - if (bytestream2_get_bytes_left(&ctx->gb) < run_len) + if (bytestream2_get_bytes_left(gb) < run_len) return AVERROR_INVALIDDATA; - bytestream2_get_bufferu(&ctx->gb, dst, run_len); + bytestream2_get_bufferu(gb, dst, run_len); } dst += run_len; @@ -554,49 +769,431 @@ static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size) return 0; } -static int old_codec1(SANMVideoContext *ctx, int top, - int left, int width, int height) +static int old_codec23(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, + int width, int height, uint8_t param, uint16_t param2) { - uint8_t *dst = ((uint8_t *)ctx->frm0) + left + top * ctx->pitch; - int i, j, len, flag, code, val, pos, end; + const uint16_t mx = ctx->width, my = ctx->height, p = ctx->pitch; + uint8_t c, lut[256], *dst = (uint8_t *)ctx->fbuf; + int sk, i, j, ls, pc, y; - for (i = 0; i < height; i++) { - pos = 0; - - if (bytestream2_get_bytes_left(&ctx->gb) < 2) + if (ctx->subversion < 2) { + /* Rebel Assault 1: constant offset + 0xd0 */ + for (i = 0; i < 256; i++) + lut[i] = (i + param + 0xd0) & 0xff; + } else if (param2 == 256) { + if (bytestream2_get_bytes_left(gb) < 256) return AVERROR_INVALIDDATA; + bytestream2_get_bufferu(gb, ctx->c23lut, 256); + } else if (param2 < 256) { + for (i = 0; i < 256; i++) + lut[i] = (i + param2) & 0xff; + } else { + memcpy(lut, ctx->c23lut, 256); + } + if (bytestream2_get_bytes_left(gb) < 1) + return 0; /* some c23 frames just set up the LUT */ - len = bytestream2_get_le16u(&ctx->gb); - end = bytestream2_tell(&ctx->gb) + len; + if (((top + height) < 0) || (top >= my) || (left + width < 0) || (left >= mx)) + return 0; - while (bytestream2_tell(&ctx->gb) < end) { - if (bytestream2_get_bytes_left(&ctx->gb) < 2) + if (top < 0) { + y = -top; + while (y-- && bytestream2_get_bytes_left(gb) > 1) { + ls = bytestream2_get_le16u(gb); + if (bytestream2_get_bytes_left(gb) < ls) return AVERROR_INVALIDDATA; + bytestream2_skip(gb, ls); + } + height += top; + top = 0; + } - code = bytestream2_get_byteu(&ctx->gb); - flag = code & 1; - code = (code >> 1) + 1; - if (pos + code > width) - return AVERROR_INVALIDDATA; - if (flag) { - val = bytestream2_get_byteu(&ctx->gb); - if (val) - memset(dst + pos, val, code); - pos += code; + y = top; + for (; (bytestream2_get_bytes_left(gb) > 1) && (height > 0) && (y < my); height--, y++) { + ls = bytestream2_get_le16u(gb); + sk = 1; + pc = left; + while ((bytestream2_get_bytes_left(gb) > 0) && (ls > 0) && (pc <= (width + left))) { + j = bytestream2_get_byteu(gb); + ls--; + if (!sk) { + while (j--) { + if ((pc >= 0) && (pc < mx)) { + c = *(dst + (y * p) + pc); + *(dst + (y * p) + pc) = lut[c]; + } + if (pc < mx) + pc++; + } } else { - if (bytestream2_get_bytes_left(&ctx->gb) < code) - return AVERROR_INVALIDDATA; - for (j = 0; j < code; j++) { - val = bytestream2_get_byteu(&ctx->gb); - if (val) - dst[pos] = val; - pos++; + if (pc < mx) + pc += j; + } + sk ^= 1; + } + } + return 0; +} + +static int old_codec21(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, + int width, int height) +{ + const uint16_t mx = ctx->width, my = ctx->height, p = ctx->pitch; + uint8_t *dst = (uint8_t *)ctx->fbuf, c; + int j, y, pc, sk, ls; + + if (((top + height) < 0) || (top >= my) || (left + width < 0) || (left >= mx)) + return 0; + + y = top; + for (; (bytestream2_get_bytes_left(gb) > 2) && (height > 0) && (y < my); height--, y++) { + ls = bytestream2_get_le16u(gb); + if (y < 0) { + if (ls >= bytestream2_get_bytes_left(gb)) + return 0; + bytestream2_skip(gb, ls); + continue; + } + sk = 1; + pc = left; + while ((bytestream2_get_bytes_left(gb) > 1) && (ls > 1) && (pc <= (width + left))) { + j = bytestream2_get_le16u(gb); + ls -= 2; + if (sk) { + if (pc < mx) + pc += j; + } else { + while ((bytestream2_get_bytes_left(gb) > 0) && (ls > 0) && (j >= 0)) { + c = bytestream2_get_byteu(gb); + if ((pc >= 0) && (pc < mx)) { + *(dst + (y * p) + pc) = c; + } + ls--; + j--; + if (pc < mx) + pc++; } } + sk ^= 1; } - dst += ctx->pitch; } - ctx->rotate_code = 0; + return 0; +} + +static int old_codec1(SANMVideoContext *ctx, GetByteContext *gb, int top, + int left, int width, int height, int opaque) +{ + const uint16_t mx = ctx->width, my = ctx->height, p = ctx->pitch; + uint8_t *dst = (uint8_t *)ctx->fbuf, code, c; + int j, x, y, flag, dlen; + + if (((top + height) < 0) || (top >= my) || (left + width < 0) || (left >= mx)) + return 0; + + if (top < 0) { + y = -top; + while (y-- && bytestream2_get_bytes_left(gb) > 1) { + dlen = bytestream2_get_le16u(gb); + if (bytestream2_get_bytes_left(gb) <= dlen) + return AVERROR_INVALIDDATA; + bytestream2_skip(gb, dlen); + } + height += top; + top = 0; + } + + y = top; + for (; (bytestream2_get_bytes_left(gb) > 1) && (height > 0) && (y < my); height--, y++) { + dlen = bytestream2_get_le16u(gb); + x = left; + while (bytestream2_get_bytes_left(gb) > 1 && dlen) { + code = bytestream2_get_byteu(gb); + dlen--; + flag = code & 1; + code = (code >> 1) + 1; + if (flag) { + c = bytestream2_get_byteu(gb); + dlen--; + if (x >= mx) + continue; + if (x < 0) { + int dff = FFMIN(-x, code); + code -= dff; + x += dff; + } + if (x + code >= mx) + code = mx - x; + if (code < 1) + continue; + for (j = 0; (j < code) && (c || opaque); j++) { + *(dst + (y * p) + x + j) = c; + } + x += code; + } else { + if (bytestream2_get_bytes_left(gb) < code) + return AVERROR_INVALIDDATA; + for (j = 0; j < code; j++) { + c = bytestream2_get_byteu(gb); + if ((x >= 0) && (x < mx) && (c || opaque)) + *(dst + (y * p) + x) = c; + if (x < mx) + x++; + } + dlen -= code; + } + } + } + + return 0; +} + +static int old_codec31(SANMVideoContext *ctx, GetByteContext *gb, int top, + int left, int width, int height, int p1, int opaque) +{ + const uint16_t mx = ctx->width, my = ctx->height, p = ctx->pitch; + uint8_t *dst = (uint8_t *)ctx->fbuf, c; + int j, x, y, flag, dlen, code; + + if (((top + height) < 0) || (top >= my) || (left + width < 0) || (left >= mx)) + return 0; + + if (top < 0) { + y = -top; + while (y-- && bytestream2_get_bytes_left(gb) > 1) { + dlen = bytestream2_get_le16u(gb); + if (bytestream2_get_bytes_left(gb) <= dlen) + return AVERROR_INVALIDDATA; + bytestream2_skip(gb, dlen); + } + height += top; + top = 0; + } + + y = top; + for (; (bytestream2_get_bytes_left(gb) > 1) && (height > 0) && (y < my); height--, y++) { + dlen = bytestream2_get_le16u(gb); + x = left; + while (bytestream2_get_bytes_left(gb) > 1 && dlen) { + code = bytestream2_get_byteu(gb); + dlen--; + flag = code & 1; + code = (code >> 1) + 1; + if (flag) { + c = bytestream2_get_byteu(gb); + dlen--; + for (j = 0; (j < code); j++) { + if ((opaque || (c & 0xf)) && (x >= 0) && (x < mx)) + *(dst + (y * p) + x) = p1 + (c & 0xf); + if (x < mx) + x++; + if ((opaque || (c >> 4)) && (x >= 0) && (x < mx)) + *(dst + (y * p) + x) = p1 + (c >> 4); + if (x < mx) + x++; + } + } else { + if (bytestream2_get_bytes_left(gb) < code) + return AVERROR_INVALIDDATA; + for (j = 0; j < code; j++) { + c = bytestream2_get_byteu(gb); + if ((opaque || (c & 0xf)) && (x >= 0) && (x < mx)) + *(dst + (y * p) + x) = p1 + (c & 0xf); + if (x < mx) + x++; + if ((opaque || (c >> 4)) && (x >= 0) && (x < mx)) + *(dst + (y * p) + x) = p1 + (c >> 4); + if (x < mx) + x++; + } + dlen -= code; + } + } + } + + return 0; +} + +static int old_codec2(SANMVideoContext *ctx, GetByteContext *gb, int top, + int left, int width, int height) +{ + uint8_t *dst = (uint8_t *)ctx->fbuf, col; + int16_t xpos = left, ypos = top; + + while (bytestream2_get_bytes_left(gb) > 3) { + xpos += bytestream2_get_le16u(gb); + ypos += bytestream2_get_byteu(gb); + col = bytestream2_get_byteu(gb); + if (xpos >= 0 && ypos >= 0 && + xpos < ctx->width && ypos < ctx->height) { + *(dst + xpos + ypos * ctx->pitch) = col; + } + } + return 0; +} + +static void blt_solid(uint8_t *dst, const uint8_t *src, int16_t left, int16_t top, + uint16_t srcxoff, uint16_t srcyoff, uint16_t srcwidth, + uint16_t srcheight, const uint16_t srcpitch, const uint16_t dstpitch, + const uint16_t dstheight, int32_t size) +{ + if ((srcwidth < 1) || (srcheight < 1) || (size < 1)) + return; + + if (top < 0) { + if (-top >= srcheight) + return; + srcyoff -= top; + srcheight += top; + size += (srcpitch * top); + top = 0; + } + + if ((top + srcheight) > dstheight) { + int clip = (top + srcheight) - dstheight; + if (clip >= srcheight) + return; + srcheight -= clip; + } + + if (left < 0) { + if (-left >= srcwidth) + return; + srcxoff -= left; + srcwidth += left; + size += left; + left = 0; + } + + if (left + srcwidth > dstpitch) { + int clip = (left + srcwidth) - dstpitch; + if (clip >= srcwidth) + return; + srcwidth -= clip; + } + + src += ((uintptr_t)srcyoff * srcpitch) + srcxoff; + dst += ((uintptr_t)top * dstpitch) + left; + while ((srcheight--) && (size >= srcwidth)) { + memcpy(dst, src, srcwidth); + src += srcpitch; + dst += dstpitch; + size -= srcpitch; + } + if ((size > 0) && (size < srcwidth) && (srcheight > 0)) + memcpy(dst, src, size); +} + +static void blt_mask(uint8_t *dst, const uint8_t *src, int16_t left, int16_t top, + uint16_t srcxoff, uint16_t srcyoff, uint16_t srcwidth, + uint16_t srcheight, const uint16_t srcpitch, const uint16_t dstpitch, + const uint16_t dstheight, int32_t size, const uint8_t skipcolor) +{ + if ((srcwidth < 1) || (srcheight < 1) || (size < 1)) + return; + + if (top < 0) { + if (-top >= srcheight) + return; + srcyoff -= top; + srcheight += top; + size += (srcpitch * top); + top = 0; + } + + if ((top + srcheight) > dstheight) { + int clip = (top + srcheight) - dstheight; + if (clip >= srcheight) + return; + srcheight -= clip; + } + + if (left < 0) { + if (-left >= srcwidth) + return; + srcxoff -= left; + srcwidth += left; + size += left; + left = 0; + } + + if (left + srcwidth > dstpitch) { + int clip = (left + srcwidth) - dstpitch; + if (clip >= srcwidth) + return; + srcwidth -= clip; + } + + src += ((uintptr_t)srcyoff * srcpitch) + srcxoff; + dst += ((uintptr_t)top * dstpitch) + left; + for (int i = 0; (size > 0) && (i < srcheight); i++) { + for (int j = 0; (size > 0) && (j < srcwidth); j++, size--) { + if (src[j] != skipcolor) + dst[j] = src[j]; + } + src += srcpitch; + dst += dstpitch; + } +} + +static void blt_ipol(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + int16_t left, int16_t top, uint16_t srcxoff, uint16_t srcyoff, + uint16_t srcwidth, uint16_t srcheight, const uint16_t srcpitch, + const uint16_t dstpitch, const uint16_t dstheight, int32_t size, + const uint8_t *itbl) +{ + if ((srcwidth < 1) || (srcheight < 1) || (size < 1)) + return; + + if (top < 0) { + if (-top >= srcheight) + return; + srcyoff -= top; + srcheight += top; + size += (srcpitch * top); + top = 0; + } + + if ((top + srcheight) > dstheight) { + int clip = (top + srcheight) - dstheight; + if (clip >= srcheight) + return; + srcheight -= clip; + } + + if (left < 0) { + if (-left >= srcwidth) + return; + srcxoff -= left; + srcwidth += left; + size += left; + left = 0; + } + + if (left + srcwidth > dstpitch) { + int clip = (left + srcwidth) - dstpitch; + if (clip >= srcwidth) + return; + srcwidth -= clip; + } + + src1 += ((uintptr_t)srcyoff * srcpitch) + srcxoff; + src2 += ((uintptr_t)srcyoff * srcpitch) + srcxoff; + dst += ((uintptr_t)top * dstpitch) + left; + for (int i = 0; (size > 0) && (i < srcheight); i++) { + for (int j = 0; (size > 0) && (j < srcwidth); j++, size--) { + dst[j] = itbl[(src1[j] << 8) | src2[j]]; + } + src1 += srcpitch; + src2 += srcpitch; + dst += dstpitch; + } +} + +static int old_codec20(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, + const int w, const int h) +{ + blt_solid((uint8_t*)ctx->fbuf, gb->buffer, left, top, 0, 0, w, h, w, ctx->pitch, + ctx->height, FFMIN(bytestream2_get_bytes_left(gb), w * h)); return 0; } @@ -620,35 +1217,41 @@ static inline void codec37_mv(uint8_t *dst, const uint8_t *src, } } -static int old_codec37(SANMVideoContext *ctx, int top, - int left, int width, int height) +static int old_codec37(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, + int width, int height) { - ptrdiff_t stride = ctx->pitch; - int i, j, k, t; + int i, j, k, l, t, run, len, code, skip, mx, my; uint8_t *dst, *prev; int skip_run = 0; - int compr = bytestream2_get_byte(&ctx->gb); - int mvoff = bytestream2_get_byte(&ctx->gb); - int seq = bytestream2_get_le16(&ctx->gb); - uint32_t decoded_size = bytestream2_get_le32(&ctx->gb); + + width = FFALIGN(width, 4); + if (width > ctx->aligned_width) + return AVERROR_INVALIDDATA; + + if (bytestream2_get_bytes_left(gb) < 16) + return AVERROR_INVALIDDATA; + + int compr = bytestream2_get_byteu(gb); + int mvoff = bytestream2_get_byteu(gb); + int seq = bytestream2_get_le16u(gb); + uint32_t decoded_size = bytestream2_get_le32u(gb); int flags; - bytestream2_skip(&ctx->gb, 4); - flags = bytestream2_get_byte(&ctx->gb); - bytestream2_skip(&ctx->gb, 3); + bytestream2_skip(gb, 4); + flags = bytestream2_get_byteu(gb); + bytestream2_skip(gb, 3); - if (decoded_size > ctx->height * stride - left - top * stride) { - decoded_size = ctx->height * stride - left - top * stride; + if (decoded_size > height * width) { + decoded_size = height * width; av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n"); } - ctx->rotate_code = 0; + if (((seq & 1) || !(flags & 1)) && (compr && compr != 2)) { + FFSWAP(uint16_t*, ctx->frm0, ctx->frm2); + } - if (((seq & 1) || !(flags & 1)) && (compr && compr != 2)) - rotate_bufs(ctx, 1); - - dst = ((uint8_t*)ctx->frm0) + left + top * stride; - prev = ((uint8_t*)ctx->frm2) + left + top * stride; + dst = ((uint8_t*)ctx->frm0); + prev = ((uint8_t*)ctx->frm2); if (mvoff > 2) { av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvoff); @@ -657,104 +1260,130 @@ static int old_codec37(SANMVideoContext *ctx, int top, switch (compr) { case 0: - for (i = 0; i < height; i++) { - bytestream2_get_buffer(&ctx->gb, dst, width); - dst += stride; + if (bytestream2_get_bytes_left(gb) < width * height) + return AVERROR_INVALIDDATA; + bytestream2_get_bufferu(gb, dst, width * height); + memset(ctx->frm2, 0, ctx->frm2_size); + break; + case 1: + run = 0; + len = -1; + code = 0; + + for (j = 0; j < height; j += 4) { + for (i = 0; i < width; i += 4) { + if (len < 0) { + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byte(gb); + len = code >> 1; + run = code & 1; + skip = 0; + } else { + skip = run; + } + + if (!skip) { + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byte(gb); + if (code == 0xff) { + len--; + for (k = 0; k < 4; k++) { + for (l = 0; l < 4; l++) { + if (len < 0) { + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byte(gb); + len = code >> 1; + run = code & 1; + if (run) { + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byte(gb); + } + } + if (!run) { + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byte(gb); + } + *(dst + i + (k * width) + l) = code; + len--; + } + } + continue; + } + } + /* 4x4 block copy from prev with MV */ + code = (code == 0xff) ? 0 : code; + mx = c37_mv[(mvoff * 255 + code) * 2]; + my = c37_mv[(mvoff * 255 + code) * 2 + 1]; + codec37_mv(dst + i, prev + i + mx + my * width, + height, width, i + mx, j + my); + len--; + } + dst += width * 4; + prev += width * 4; } - memset(ctx->frm1, 0, ctx->height * stride); - memset(ctx->frm2, 0, ctx->height * stride); break; case 2: - if (rle_decode(ctx, dst, decoded_size)) + if (rle_decode(ctx, gb, dst, decoded_size)) return AVERROR_INVALIDDATA; - memset(ctx->frm1, 0, ctx->frm1_size); memset(ctx->frm2, 0, ctx->frm2_size); break; case 3: case 4: - if (flags & 4) { - for (j = 0; j < height; j += 4) { - for (i = 0; i < width; i += 4) { - int code; - if (skip_run) { - skip_run--; - copy_block4(dst + i, prev + i, stride, stride, 4); - continue; - } - if (bytestream2_get_bytes_left(&ctx->gb) < 1) + for (j = 0; j < height; j += 4) { + for (i = 0; i < width; i += 4) { + int code; + if (skip_run) { + skip_run--; + copy_block4(dst + i, prev + i, width, width, 4); + continue; + } + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byteu(gb); + if (code == 0xFF) { + if (bytestream2_get_bytes_left(gb) < 16) return AVERROR_INVALIDDATA; - code = bytestream2_get_byteu(&ctx->gb); - switch (code) { - case 0xFF: - if (bytestream2_get_bytes_left(&ctx->gb) < 16) - return AVERROR_INVALIDDATA; - for (k = 0; k < 4; k++) - bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4); - break; - case 0xFE: - if (bytestream2_get_bytes_left(&ctx->gb) < 4) - return AVERROR_INVALIDDATA; - for (k = 0; k < 4; k++) - memset(dst + i + k * stride, bytestream2_get_byteu(&ctx->gb), 4); - break; - case 0xFD: - if (bytestream2_get_bytes_left(&ctx->gb) < 1) - return AVERROR_INVALIDDATA; - t = bytestream2_get_byteu(&ctx->gb); - for (k = 0; k < 4; k++) - memset(dst + i + k * stride, t, 4); - break; - default: - if (compr == 4 && !code) { - if (bytestream2_get_bytes_left(&ctx->gb) < 1) - return AVERROR_INVALIDDATA; - skip_run = bytestream2_get_byteu(&ctx->gb) + 1; - i -= 4; - } else { - int mx, my; - - mx = c37_mv[(mvoff * 255 + code) * 2]; - my = c37_mv[(mvoff * 255 + code) * 2 + 1]; - codec37_mv(dst + i, prev + i + mx + my * stride, - ctx->height, stride, i + mx, j + my); + for (k = 0; k < 4; k++) + bytestream2_get_bufferu(gb, dst + i + k * width, 4); + } else if ((flags & 4) && (code == 0xFE)) { + if (bytestream2_get_bytes_left(gb) < 4) + return AVERROR_INVALIDDATA; + for (k = 0; k < 4; k += 2) { + uint8_t c1 = bytestream2_get_byteu(gb); + uint8_t c2 = bytestream2_get_byteu(gb); + for (l = 0; l < 2; l++) { + *(dst + i + ((k + l) * width) + 0) = c1; + *(dst + i + ((k + l) * width) + 1) = c1; + *(dst + i + ((k + l) * width) + 2) = c2; + *(dst + i + ((k + l) * width) + 3) = c2; } } - } - dst += stride * 4; - prev += stride * 4; - } - } else { - for (j = 0; j < height; j += 4) { - for (i = 0; i < width; i += 4) { - int code; - if (skip_run) { - skip_run--; - copy_block4(dst + i, prev + i, stride, stride, 4); - continue; - } - code = bytestream2_get_byte(&ctx->gb); - if (code == 0xFF) { - if (bytestream2_get_bytes_left(&ctx->gb) < 16) - return AVERROR_INVALIDDATA; - for (k = 0; k < 4; k++) - bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4); - } else if (compr == 4 && !code) { - if (bytestream2_get_bytes_left(&ctx->gb) < 1) - return AVERROR_INVALIDDATA; - skip_run = bytestream2_get_byteu(&ctx->gb) + 1; - i -= 4; - } else { - int mx, my; + } else if ((flags & 4) && (code == 0xFD)) { + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + t = bytestream2_get_byteu(gb); + for (k = 0; k < 4; k++) + memset(dst + i + k * width, t, 4); + } else { + mx = c37_mv[(mvoff * 255 + code) * 2]; + my = c37_mv[(mvoff * 255 + code) * 2 + 1]; + codec37_mv(dst + i, prev + i + mx + my * width, + height, width, i + mx, j + my); - mx = c37_mv[(mvoff * 255 + code) * 2]; - my = c37_mv[(mvoff * 255 + code) * 2 + 1]; - codec37_mv(dst + i, prev + i + mx + my * stride, - ctx->height, stride, i + mx, j + my); + if ((compr == 4) && (code == 0)) { + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + skip_run = bytestream2_get_byteu(gb); } } - dst += stride * 4; - prev += stride * 4; } + dst += width * 4; + prev += width * 4; } break; default: @@ -763,62 +1392,69 @@ static int old_codec37(SANMVideoContext *ctx, int top, return AVERROR_PATCHWELCOME; } + if ((flags & 2) == 0) { + blt_solid((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, left, top, 0, 0, width, + height, width, ctx->pitch, ctx->height, width * height); + } else { + blt_mask((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, left, top, 0, 0, width, + height, width, ctx->pitch, ctx->height, width * height, 0); + } return 0; } -static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1, - uint8_t *prev2, int stride, int tbl, int size) +static int codec47_block(SANMVideoContext *ctx, GetByteContext *gb,uint8_t *dst, + uint8_t *prev1, uint8_t *prev2, int stride, int size) { int code, k, t; uint8_t colors[2]; int8_t *pglyph; - if (bytestream2_get_bytes_left(&ctx->gb) < 1) + if (bytestream2_get_bytes_left(gb) < 1) return AVERROR_INVALIDDATA; - code = bytestream2_get_byteu(&ctx->gb); + code = bytestream2_get_byteu(gb); if (code >= 0xF8) { switch (code) { case 0xFF: if (size == 2) { - if (bytestream2_get_bytes_left(&ctx->gb) < 4) + if (bytestream2_get_bytes_left(gb) < 4) return AVERROR_INVALIDDATA; - dst[0] = bytestream2_get_byteu(&ctx->gb); - dst[1] = bytestream2_get_byteu(&ctx->gb); - dst[0 + stride] = bytestream2_get_byteu(&ctx->gb); - dst[1 + stride] = bytestream2_get_byteu(&ctx->gb); + dst[0] = bytestream2_get_byteu(gb); + dst[1] = bytestream2_get_byteu(gb); + dst[0 + stride] = bytestream2_get_byteu(gb); + dst[1 + stride] = bytestream2_get_byteu(gb); } else { size >>= 1; - if (process_block(ctx, dst, prev1, prev2, stride, tbl, size)) + if (codec47_block(ctx, gb, dst, prev1, prev2, stride, size)) return AVERROR_INVALIDDATA; - if (process_block(ctx, dst + size, prev1 + size, prev2 + size, - stride, tbl, size)) + if (codec47_block(ctx, gb, dst + size, prev1 + size, prev2 + size, + stride, size)) return AVERROR_INVALIDDATA; dst += size * stride; prev1 += size * stride; prev2 += size * stride; - if (process_block(ctx, dst, prev1, prev2, stride, tbl, size)) + if (codec47_block(ctx, gb, dst, prev1, prev2, stride, size)) return AVERROR_INVALIDDATA; - if (process_block(ctx, dst + size, prev1 + size, prev2 + size, - stride, tbl, size)) + if (codec47_block(ctx, gb, dst + size, prev1 + size, prev2 + size, + stride, size)) return AVERROR_INVALIDDATA; } break; case 0xFE: - if (bytestream2_get_bytes_left(&ctx->gb) < 1) + if (bytestream2_get_bytes_left(gb) < 1) return AVERROR_INVALIDDATA; - t = bytestream2_get_byteu(&ctx->gb); + t = bytestream2_get_byteu(gb); for (k = 0; k < size; k++) memset(dst + k * stride, t, size); break; case 0xFD: - if (bytestream2_get_bytes_left(&ctx->gb) < 3) + if (bytestream2_get_bytes_left(gb) < 3) return AVERROR_INVALIDDATA; - code = bytestream2_get_byteu(&ctx->gb); + code = bytestream2_get_byteu(gb); pglyph = (size == 8) ? ctx->p8x8glyphs[code] : ctx->p4x4glyphs[code]; - bytestream2_get_bufferu(&ctx->gb, colors, 2); + bytestream2_get_bufferu(gb, colors, 2); for (k = 0; k < size; k++) for (t = 0; t < size; t++) @@ -829,16 +1465,12 @@ static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1, memcpy(dst + k * stride, prev1 + k * stride, size); break; default: - k = bytestream2_tell(&ctx->gb); - bytestream2_seek(&ctx->gb, tbl + (code & 7), SEEK_SET); - t = bytestream2_get_byte(&ctx->gb); - bytestream2_seek(&ctx->gb, k, SEEK_SET); for (k = 0; k < size; k++) - memset(dst + k * stride, t, size); + memset(dst + k * stride, ctx->c47cb[code & 3], size); } } else { - int mx = motion_vectors[code][0]; - int my = motion_vectors[code][1]; + int mx = c47_mv[code][0]; + int my = c47_mv[code][1]; int index = prev2 - (const uint8_t *)ctx->frm2; av_assert2(index >= 0 && index < (ctx->buf_size >> 1)); @@ -856,81 +1488,131 @@ static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1, return 0; } -static int old_codec47(SANMVideoContext *ctx, int top, - int left, int width, int height) +static void codec47_read_interptable(GetByteContext *gb, uint8_t *itbl) +{ + uint8_t *p1, *p2; + int i, j; + + for (i = 0; i < 256; i++) { + p1 = p2 = itbl + i; + for (j = 256 - i; j; j--) { + *p1 = *p2 = bytestream2_get_byte(gb); + p1 += 1; + p2 += 256; + } + itbl += 256; + } +} + +static void codec47_comp1(GetByteContext *gb, uint8_t *dst_in, int width, + const int height, const ptrdiff_t stride, const uint8_t *itbl) +{ + uint8_t p1, *dst; + uint16_t px; + int i, j; + + dst = dst_in + stride; + for (i = 0; i < height; i += 2) { + p1 = bytestream2_get_byte(gb); + *dst++ = p1; + *dst++ = p1; + px = p1; + for (j = 2; j < width; j += 2) { + p1 = bytestream2_get_byte(gb); + px = (px << 8) | p1; + *dst++ = itbl[px]; + *dst++ = p1; + } + dst += stride; + } + + memcpy(dst_in, dst_in + stride, width); + dst = dst_in + stride + stride; + for (i = 2; i < height - 1; i += 2) { + for (j = 0; j < width; j++) { + px = (*(dst - stride) << 8) | *(dst + stride); + *dst++ = itbl[px]; + } + dst += stride; + } +} + +static int old_codec47(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, + int width, int height) { uint32_t decoded_size; int i, j; - ptrdiff_t stride = ctx->pitch; - uint8_t *dst = (uint8_t *)ctx->frm0 + left + top * stride; + uint8_t *dst = (uint8_t *)ctx->frm0; uint8_t *prev1 = (uint8_t *)ctx->frm1; uint8_t *prev2 = (uint8_t *)ctx->frm2; - int tbl_pos = bytestream2_tell(&ctx->gb); - int seq = bytestream2_get_le16(&ctx->gb); - int compr = bytestream2_get_byte(&ctx->gb); - int new_rot = bytestream2_get_byte(&ctx->gb); - int skip = bytestream2_get_byte(&ctx->gb); + uint8_t auxcol[2]; - bytestream2_skip(&ctx->gb, 9); - decoded_size = bytestream2_get_le32(&ctx->gb); - bytestream2_skip(&ctx->gb, 8); + width = FFALIGN(width, 8); + if (width > ctx->aligned_width) + return AVERROR_INVALIDDATA; - if (decoded_size > ctx->height * stride - left - top * stride) { - decoded_size = ctx->height * stride - left - top * stride; + if (bytestream2_get_bytes_left(gb) < 26) + return AVERROR_INVALIDDATA; + + int seq = bytestream2_get_le16u(gb); + int compr = bytestream2_get_byteu(gb); + int new_rot = bytestream2_get_byteu(gb); + int skip = bytestream2_get_byteu(gb); + + bytestream2_skip(gb, 3); + bytestream2_get_bufferu(gb, ctx->c47cb, 4); + auxcol[0] = bytestream2_get_byteu(gb); + auxcol[1] = bytestream2_get_byteu(gb); + decoded_size = bytestream2_get_le32u(gb); + bytestream2_skip(gb, 8); + + if (decoded_size > ctx->aligned_height * width) { + decoded_size = height * width; av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n"); } - if (skip & 1) - bytestream2_skip(&ctx->gb, 0x8080); + if (skip & 1) { + if (bytestream2_get_bytes_left(gb) < 0x8080) + return AVERROR_INVALIDDATA; + codec47_read_interptable(gb, ctx->c47itbl); + } if (!seq) { ctx->prev_seq = -1; - memset(prev1, 0, ctx->height * stride); - memset(prev2, 0, ctx->height * stride); + memset(prev1, auxcol[0], ctx->frm0_size); + memset(prev2, auxcol[1], ctx->frm0_size); } switch (compr) { case 0: - if (bytestream2_get_bytes_left(&ctx->gb) < width * height) + if (bytestream2_get_bytes_left(gb) < width * height) return AVERROR_INVALIDDATA; - for (j = 0; j < height; j++) { - bytestream2_get_bufferu(&ctx->gb, dst, width); - dst += stride; - } + bytestream2_get_bufferu(gb, dst, width * height); break; case 1: - if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1)) + if (bytestream2_get_bytes_left(gb) < ((width + 1) >> 1) * ((height + 1) >> 1)) return AVERROR_INVALIDDATA; - for (j = 0; j < height; j += 2) { - for (i = 0; i < width; i += 2) { - dst[i] = - dst[i + 1] = - dst[stride + i] = - dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb); - } - dst += stride * 2; - } + codec47_comp1(gb, dst, width, height, width, ctx->c47itbl); break; case 2: if (seq == ctx->prev_seq + 1) { for (j = 0; j < height; j += 8) { for (i = 0; i < width; i += 8) - if (process_block(ctx, dst + i, prev1 + i, prev2 + i, stride, - tbl_pos + 8, 8)) + if (codec47_block(ctx, gb, dst + i, prev1 + i, prev2 + i, width, 8)) return AVERROR_INVALIDDATA; - dst += stride * 8; - prev1 += stride * 8; - prev2 += stride * 8; + dst += width * 8; + prev1 += width * 8; + prev2 += width * 8; } } break; case 3: - memcpy(ctx->frm0, ctx->frm2, ctx->pitch * ctx->height); + memcpy(ctx->frm0, ctx->frm2, ctx->frm0_size); break; case 4: - memcpy(ctx->frm0, ctx->frm1, ctx->pitch * ctx->height); + memcpy(ctx->frm0, ctx->frm1, ctx->frm0_size); break; case 5: - if (rle_decode(ctx, dst, decoded_size)) + if (rle_decode(ctx, gb, dst, decoded_size)) return AVERROR_INVALIDDATA; break; default: @@ -938,62 +1620,628 @@ static int old_codec47(SANMVideoContext *ctx, int top, "Subcodec 47 compression %d", compr); return AVERROR_PATCHWELCOME; } - if (seq == ctx->prev_seq + 1) - ctx->rotate_code = new_rot; - else - ctx->rotate_code = 0; + + blt_solid((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, left, top, 0, 0, width, + height, width, ctx->pitch, ctx->height, width * height); + + if ((seq == ctx->prev_seq + 1) && new_rot) + rotate_bufs(ctx, new_rot); + ctx->prev_seq = seq; return 0; } -static int process_frame_obj(SANMVideoContext *ctx) +// scale 4x4 input block to an 8x8 output block +static void c48_4to8(uint8_t *dst, const uint8_t *src, const uint16_t w) { - uint16_t codec = bytestream2_get_le16u(&ctx->gb); - uint16_t left = bytestream2_get_le16u(&ctx->gb); - uint16_t top = bytestream2_get_le16u(&ctx->gb); - uint16_t w = bytestream2_get_le16u(&ctx->gb); - uint16_t h = bytestream2_get_le16u(&ctx->gb); + uint16_t p; + // dst is always at least 16bit aligned + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 8; j += 2) { + p = *src++; + p = (p << 8) | p; + *((uint16_t *)(dst + w * 0 + j)) = p; + *((uint16_t *)(dst + w * 1 + j)) = p; + } + dst += w * 2; + } +} - if (!w || !h) { - av_log(ctx->avctx, AV_LOG_ERROR, "Dimensions are invalid.\n"); +static int c48_invalid_mv(int x, int y, const uint16_t w, int h, int blocksize, int mvofs) { + if (mvofs < -x + -y*w) + return AVERROR_INVALIDDATA; + + if (mvofs > w-x-blocksize + w*(h-y-blocksize)) + return AVERROR_INVALIDDATA; + + return 0; +} + +static int codec48_block(GetByteContext *gb, uint8_t *dst, uint8_t *db, int x, int y, + const uint16_t w, const int aligned_height, const uint8_t *itbl) +{ + uint8_t opc, sb[16]; + int i, j, k, l; + int16_t mvofs; + uint32_t ofs; + + if (bytestream2_get_bytes_left(gb) < 1) + return 1; + + opc = bytestream2_get_byteu(gb); + switch (opc) { + case 0xFF: // 1x1 -> 8x8 block scale + if (bytestream2_get_bytes_left(gb) < 1) + return 1; + + if (y > 0 && x > 0) { + sb[15] = bytestream2_get_byteu(gb); + sb[ 7] = itbl[(*(dst - 1*w + 7) << 8) | sb[15]]; + sb[ 3] = itbl[(*(dst - 1*w + 7) << 8) | sb[ 7]]; + sb[11] = itbl[(sb[15] << 8) | sb[ 7]]; + sb[ 1] = itbl[(*(dst + 0*w - 1) << 8) | sb[ 3]]; + sb[ 0] = itbl[(*(dst + 0*w - 1) << 8) | sb[ 1]]; + sb[ 2] = itbl[(sb[ 3] << 8) | sb[ 1]]; + sb[ 5] = itbl[(*(dst + 2*w - 1) << 8) | sb[ 7]]; + sb[ 4] = itbl[(*(dst + 2*w - 1) << 8) | sb[ 5]]; + sb[ 6] = itbl[(sb[ 7] << 8) | sb[ 5]]; + sb[ 9] = itbl[(*(dst + 3*w - 1) << 8) | sb[11]]; + sb[ 8] = itbl[(*(dst + 3*w - 1) << 8) | sb[ 9]]; + sb[10] = itbl[(sb[11] << 8) | sb[ 9]]; + sb[13] = itbl[(*(dst + 4*w - 1) << 8) | sb[15]]; + sb[12] = itbl[(*(dst + 4*w - 1) << 8) | sb[13]]; + sb[14] = itbl[(sb[15] << 8) | sb[13]]; + } else { + opc = bytestream2_get_byteu(gb); + for (i = 0; i < 16; i++) + sb[i] = opc; + } + c48_4to8(dst, sb, w); + break; + case 0xFE: // 1x 8x8 copy from deltabuf, 16bit mv from source + if (bytestream2_get_bytes_left(gb) < 2) + return 1; + mvofs = bytestream2_get_le16(gb); + if (c48_invalid_mv(x, y, w, aligned_height, 8, mvofs)) + break; + for (i = 0; i < 8; i++) { + ofs = w * i; + for (k = 0; k < 8; k++) + *(dst + ofs + k) = *(db + ofs + k + mvofs); + } + break; + case 0xFD: // 2x2 -> 8x8 block scale + if (bytestream2_get_bytes_left(gb) < 4) + return 1; + sb[ 5] = bytestream2_get_byteu(gb); + sb[ 7] = bytestream2_get_byteu(gb); + sb[13] = bytestream2_get_byteu(gb); + sb[15] = bytestream2_get_byteu(gb); + + if (y > 0 && x >0) { + sb[ 1] = itbl[(*(dst - 1*w + 3) << 8) | sb[ 5]]; + sb[ 3] = itbl[(*(dst - 1*w + 7) << 8) | sb[ 7]]; + sb[ 9] = itbl[(sb[13] << 8) | sb[ 5]]; + sb[11] = itbl[(sb[15] << 8) | sb[ 7]]; + sb[ 0] = itbl[(*(dst + 0*w - 1) << 8) | sb[ 1]]; + sb[ 2] = itbl[(sb[ 3] << 8) | sb[ 1]]; + sb[ 4] = itbl[(*(dst + 2*w - 1) << 8) | sb[ 5]]; + sb[ 6] = itbl[(sb[ 7] << 8) | sb[ 5]]; + sb[ 8] = itbl[(*(dst + 3*w - 1) << 8) | sb[ 9]]; + sb[10] = itbl[(sb[11] << 8) | sb[ 9]]; + sb[12] = itbl[(*(dst + 4*w - 1) << 8) | sb[13]]; + sb[14] = itbl[(sb[15] << 8) | sb[13]]; + } else { + sb[ 0] = sb[ 1] = sb[ 4] = sb[ 5]; + sb[ 2] = sb[ 3] = sb[ 6] = sb[ 7]; + sb[ 8] = sb[ 9] = sb[12] = sb[13]; + sb[10] = sb[11] = sb[14] = sb[15]; + } + c48_4to8(dst, sb, w); + break; + case 0xFC: // 4x copy 4x4 block, per-block c37_mv from source + if (bytestream2_get_bytes_left(gb) < 4) + return 1; + for (i = 0; i < 8; i += 4) { + for (k = 0; k < 8; k += 4) { + opc = bytestream2_get_byteu(gb); + opc = (opc == 255) ? 0 : opc; + mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w); + if (c48_invalid_mv(x+k, y+i, w, aligned_height, 4, mvofs)) + continue; + for (j = 0; j < 4; j++) { + ofs = (w * (j + i)) + k; + for (l = 0; l < 4; l++) + *(dst + ofs + l) = *(db + ofs + l + mvofs); + } + } + } + break; + case 0xFB: // Copy 4x 4x4 blocks, per-block mv from source + if (bytestream2_get_bytes_left(gb) < 8) + return 1; + for (i = 0; i < 8; i += 4) { + for (k = 0; k < 8; k += 4) { + mvofs = bytestream2_get_le16(gb); + if (c48_invalid_mv(x+k, y+i, w, aligned_height, 4, mvofs)) + continue; + for (j = 0; j < 4; j++) { + ofs = (w * (j + i)) + k; + for (l = 0; l < 4; l++) + *(dst + ofs + l) = *(db + ofs + l + mvofs); + } + } + } + break; + case 0xFA: // scale 4x4 input block to 8x8 dest block + if (bytestream2_get_bytes_left(gb) < 16) + return 1; + bytestream2_get_bufferu(gb, sb, 16); + c48_4to8(dst, sb, w); + break; + case 0xF9: // 16x 2x2 copy from delta, per-block c37_mv from source + if (bytestream2_get_bytes_left(gb) < 16) + return 1; + for (i = 0; i < 8; i += 2) { + for (j = 0; j < 8; j += 2) { + ofs = (w * i) + j; + opc = bytestream2_get_byteu(gb); + opc = (opc == 255) ? 0 : opc; + mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w); + if (c48_invalid_mv(x+j, y+i, w, aligned_height, 2, mvofs)) + continue; + for (l = 0; l < 2; l++) { + *(dst + ofs + l + 0) = *(db + ofs + l + 0 + mvofs); + *(dst + ofs + l + w) = *(db + ofs + l + w + mvofs); + } + } + } + break; + case 0xF8: // 16x 2x2 blocks copy, 16bit mv from source + if (bytestream2_get_bytes_left(gb) < 32) + return 1; + for (i = 0; i < 8; i += 2) { + for (j = 0; j < 8; j += 2) { + ofs = w * i + j; + mvofs = bytestream2_get_le16(gb); + if (c48_invalid_mv(x+j, y+i, w, aligned_height, 2, mvofs)) + continue; + for (l = 0; l < 2; l++) { + *(dst + ofs + l + 0) = *(db + ofs + l + 0 + mvofs); + *(dst + ofs + l + w) = *(db + ofs + l + w + mvofs); + } + } + } + break; + case 0xF7: // copy 8x8 block from src to dest + if (bytestream2_get_bytes_left(gb) < 64) + return 1; + for (i = 0; i < 8; i++) { + ofs = i * w; + for (l = 0; l < 8; l++) + *(dst + ofs + l) = bytestream2_get_byteu(gb); + } + break; + default: // copy 8x8 block from prev, c37_mv from source + mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w); + if (c48_invalid_mv(x, y, w, aligned_height, 8, mvofs)) + break; + for (i = 0; i < 8; i++) { + ofs = i * w; + for (l = 0; l < 8; l++) + *(dst + ofs + l) = *(db + ofs + l + mvofs); + } + break; + } + return 0; +} + +static int old_codec48(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, + int width, int height) +{ + uint8_t *dst, *prev; + int i, j, flags, ah; + + width = FFALIGN(width, 8); + if (width > ctx->aligned_width) + return AVERROR_INVALIDDATA; + + ah = FFALIGN(height, 8); + if (ah > ctx->aligned_height) + return AVERROR_INVALIDDATA; + + if (bytestream2_get_bytes_left(gb) < 16) + return AVERROR_INVALIDDATA; + + int compr = bytestream2_get_byteu(gb); + int mvidx = bytestream2_get_byteu(gb); + int seq = bytestream2_get_le16u(gb); + uint32_t decoded_size = bytestream2_get_le32u(gb); + + // all codec48 videos use 1, but just to be safe... + if (mvidx != 1) { + av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvidx); return AVERROR_INVALIDDATA; } - if (ctx->width < left + w || ctx->height < top + h) { - int ret = ff_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width), - FFMAX(top + h, ctx->height)); - if (ret < 0) - return ret; - init_sizes(ctx, FFMAX(left + w, ctx->width), - FFMAX(top + h, ctx->height)); - if (init_buffers(ctx)) { - av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n"); - return AVERROR(ENOMEM); + bytestream2_skip(gb, 4); + flags = bytestream2_get_byteu(gb); + bytestream2_skip(gb, 3); + + if (flags & 8) { + if (bytestream2_get_bytes_left(gb) < 0x8080) + return AVERROR_INVALIDDATA; + codec47_read_interptable(gb, ctx->c47itbl); + } + + dst = (uint8_t*)ctx->frm0; + prev = (uint8_t*)ctx->frm2; + + if (seq == 0) + memset(ctx->frm2, 0, ctx->frm2_size); + + switch (compr) { + case 0: + if (bytestream2_get_bytes_left(gb) < width * height) + return AVERROR_INVALIDDATA; + bytestream2_get_bufferu(gb, dst, width * height); + break; + case 2: + if (decoded_size > width * height) { + av_log(ctx->avctx, AV_LOG_ERROR, "Decoded size %u is too large.\n", decoded_size); + decoded_size = width * height; + } + + if (rle_decode(ctx, gb, dst, decoded_size)) + return AVERROR_INVALIDDATA; + break; + case 3: + if ((seq == 0) || (seq == ctx->prev_seq + 1)) { + if ((seq & 1) || ((flags & 1) == 0) || (flags & 0x10)) { + FFSWAP(uint16_t*, ctx->frm0, ctx->frm2); + dst = (uint8_t*)ctx->frm0; + prev = (uint8_t*)ctx->frm2; + } + for (j = 0; j < height; j += 8) { + for (i = 0; i < width; i += 8) { + if (codec48_block(gb, dst + i, prev + i, i, j, width, + ah, ctx->c47itbl)) + return AVERROR_INVALIDDATA; + } + dst += width * 8; + prev += width * 8; + } + } + break; + case 5: + if (bytestream2_get_bytes_left(gb) < ((width + 1) >> 1) * ((height + 1) >> 1)) + return AVERROR_INVALIDDATA; + codec47_comp1(gb, dst, width, height, width, ctx->c47itbl); + break; + case 6: /* this is a "stub" frame that follows a frame with flag 0x10 set. */ + break; + default: + avpriv_report_missing_feature(ctx->avctx, + "Subcodec 48 compression %d", compr); + return AVERROR_PATCHWELCOME; + } + + ctx->prev_seq = seq; + if ((flags & 2) == 0) { + if (flags & 0x10) { + /* generate an artificial frame from the 2 buffers. This will be + * followed up immediately with a codec48 compression 6 frame, which + * will then blit the actual decoding result (frm0) to the main buffer. + */ + blt_ipol((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, (uint8_t*)ctx->frm2, + left, top, 0, 0, width, height, width, ctx->pitch, ctx->height, + width * height, ctx->c47itbl); + return 0; + } + blt_solid((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, left, top, 0, 0, width, + height, width, ctx->pitch, ctx->height, width * height); + } else { + blt_mask((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, left, top, 0, 0, width, + height, width, ctx->pitch, ctx->height, width * height, 0); + } + return 0; +} + +static void old_codec45(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, int flag) +{ + int t1, t2, i; + + if (bytestream2_get_bytes_left(gb) < 6) + return; + + bytestream2_skip(gb, 2); + t1 = bytestream2_get_le16u(gb); + t2 = bytestream2_get_byteu(gb); + bytestream2_skip(gb, 1); + if (t2 != 1) + return; + if (t1 == 0) { + if (bytestream2_get_bytes_left(gb) < 0x300) + return; + bytestream2_get_bufferu(gb, ctx->c45tbl1, 0x300); + i = 0; + while ((bytestream2_get_bytes_left(gb) > 1) && (i < 0x8000)) { + uint8_t len = bytestream2_get_byteu(gb); + uint8_t val = bytestream2_get_byteu(gb); + if ((i + len) > 0x8000) + len = 0x8000 - i; + memset(ctx->c45tbl2 + i, val, len); + i += len; } } - bytestream2_skip(&ctx->gb, 4); - if (w + FFMAX(left, 0) > ctx->avctx->width || h + FFMAX(top, 0) > ctx->avctx->height) { - avpriv_request_sample(ctx->avctx, "overly large frame\n"); - return AVERROR_PATCHWELCOME; + if (flag) + return; + + while (bytestream2_get_bytes_left(gb) > 3) { + left += (int16_t)bytestream2_get_le16u(gb); + top += bytestream2_get_byteu(gb); + int len = bytestream2_get_byteu(gb); + while (len >= 0) { + if ((left > 0) && (top > 0) && (left < (ctx->width - 1))) { + if (top >= (ctx->height - 1)) + return; + + uint8_t *dst = (uint8_t *)ctx->fbuf + left + top * ctx->pitch; + unsigned int c1 = *(dst - 1) * 3; + unsigned int c2 = *(dst + 1) * 3; + unsigned int r = ctx->c45tbl1[c1 + 0] + ctx->c45tbl1[c2 + 0]; + unsigned int g = ctx->c45tbl1[c1 + 1] + ctx->c45tbl1[c2 + 1]; + unsigned int b = ctx->c45tbl1[c1 + 2] + ctx->c45tbl1[c2 + 2]; + c1 = *(dst - ctx->pitch) * 3; + c2 = *(dst + ctx->pitch) * 3; + r += ctx->c45tbl1[c1 + 0] + ctx->c45tbl1[c2 + 0]; + g += ctx->c45tbl1[c1 + 1] + ctx->c45tbl1[c2 + 1]; + b += ctx->c45tbl1[c1 + 2] + ctx->c45tbl1[c2 + 2]; + *dst = ctx->c45tbl2[((r << 5) & 0x7c00) | (g & 0x3e0) | (b >> 5)]; + } + left++; + len--; + } + left--; + } +} + +static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb, + int xoff, int yoff) +{ + uint16_t w, h, parm2; + uint8_t codec, param; + int16_t left, top; + int fsc; + + codec = bytestream2_get_byteu(gb); + param = bytestream2_get_byteu(gb); + left = bytestream2_get_le16u(gb) + xoff; + top = bytestream2_get_le16u(gb) + yoff; + w = bytestream2_get_le16u(gb); + h = bytestream2_get_le16u(gb); + bytestream2_skip(gb, 2); + parm2 = bytestream2_get_le16u(gb); + + if (w < 1 || h < 1 || w > 640 || h > 480 || left > 640 || top > 480 || left + w <= 0 || top + h <= 0) { + /* codec45 frames with data for the 2 tables have nonsensical dimensions */ + if (codec == 45) { + old_codec45(ctx, gb, 0, 0, 1); + return 0; + } + + av_log(ctx->avctx, AV_LOG_WARNING, + "ignoring invalid fobj dimensions: c%d %d %d @ %d %d\n", + codec, w, h, left, top); + return 0; + } + + /* codecs with their own buffers */ + fsc = (codec == 37 || codec == 47 || codec == 48); + + /* special case for "Shadows of the Empire" videos: they have top=60 + * at all frames to vertically center the video in the 640x480 game + * window, but we don't need that. + */ + if ((w == 640) && (h == 272) && (top == 60) && (codec == 47)) + left = top = 0; + + if (!ctx->have_dimensions && (codec != 45)) { + int xres, yres; + if (ctx->subversion < 2) { + /* Rebel Assault 1: 384x242 internal size */ + xres = 384; + yres = 242; + if (w > xres || h > yres) + return AVERROR_INVALIDDATA; + ctx->have_dimensions = 1; + } else if (fsc) { + /* these codecs work on full frames, trust their dimensions */ + xres = w; + yres = h; + ctx->have_dimensions = 1; + } else { + /* detect common sizes */ + xres = w + left; + yres = h + top; + if (((xres == 424) && (yres == 260)) || /* RA2 */ + ((xres == 320) && (yres == 200)) || /* FT/Dig */ + ((xres == 640) && (yres == 272)) || /* SotE */ + ((xres == 640) && (yres == 350)) || /* MotS */ + ((xres == 640) && (yres == 480))) { + ctx->have_dimensions = 1; + } + + xres = FFMAX(xres, ctx->width); + yres = FFMAX(yres, ctx->height); + } + + if ((xres < (fsc ? 8 : 1)) || (yres < (fsc ? 8 : 1)) || (xres > 640) || (yres > 480)) + return AVERROR_INVALIDDATA; + + if (ctx->width < xres || ctx->height < yres) { + int ret = ff_set_dimensions(ctx->avctx, xres, yres); + if (ret < 0) + return ret; + init_sizes(ctx, xres, yres); + if (init_buffers(ctx)) { + av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n"); + return AVERROR(ENOMEM); + } + } + } else { + if (((w > ctx->width) || (h > ctx->height) || (w * h > ctx->buf_size)) && fsc) { + /* correct unexpected overly large frames: this happens + * for instance with The Dig's sq1.san video: it has a few + * (all black) 640x480 frames halfway in, while the rest is + * 320x200. + */ + av_log(ctx->avctx, AV_LOG_WARNING, + "resizing too large fobj: c%d %d %d @ %d %d\n", codec, w, h, left, top); + w = ctx->width; + h = ctx->height; + } + } + + /* users of codecs>=37 are subversion 2, enforce that for STOR/FTCH */ + if (fsc && ctx->subversion < 2) { + ctx->subversion = 2; + ctx->stor_size = 0; /* invalidate existing data */ + } + + /* clear the main buffer on the first fob */ + if (ctx->first_fob) { + ctx->first_fob = 0; + if (!fsc) + memset(ctx->fbuf, 0, ctx->frm0_size); } switch (codec) { case 1: case 3: - return old_codec1(ctx, top, left, w, h); + return old_codec1(ctx, gb, top, left, w, h, codec == 3); + case 2: + return old_codec2(ctx, gb, top, left, w, h); + case 4: + case 5: + case 33: + case 34: + return old_codec4(ctx, gb, top, left, w, h, param, parm2, codec); + case 20: + return old_codec20(ctx, gb, top, left, w, h); + case 21: + return old_codec21(ctx, gb, top, left, w, h); + case 23: + return old_codec23(ctx, gb, top, left, w, h, param, parm2); + case 31: + case 32: + return old_codec31(ctx, gb, top, left, w, h, param, (codec == 32)); case 37: - return old_codec37(ctx, top, left, w, h); + return old_codec37(ctx, gb, top, left, w, h); break; + case 45: + old_codec45(ctx, gb, top, left, 0); break; case 47: - return old_codec47(ctx, top, left, w, h); + return old_codec47(ctx, gb, top, left, w, h); break; + case 48: + return old_codec48(ctx, gb, top, left, w, h); break; default: avpriv_request_sample(ctx->avctx, "Subcodec %d", codec); - return AVERROR_PATCHWELCOME; + ctx->frame->flags |= AV_FRAME_FLAG_CORRUPT; + break; } + return 0; } -static int decode_0(SANMVideoContext *ctx) +static int process_ftch(SANMVideoContext *ctx, int size) +{ + int xoff, yoff, ret; + GetByteContext gb; + + /* FTCH defines additional x/y offsets */ + if (size == 6) { + bytestream2_skip(&ctx->gb, 2); + xoff = bytestream2_get_le16u(&ctx->gb); + yoff = bytestream2_get_le16u(&ctx->gb); + } else if (size == 12) { + av_assert0(bytestream2_get_bytes_left(&ctx->gb) >= 12); + bytestream2_skip(&ctx->gb, 4); + xoff = bytestream2_get_be32u(&ctx->gb); + yoff = bytestream2_get_be32u(&ctx->gb); + } else + return 1; + + if (ctx->stor_size > 0) { + /* decode the stored FOBJ */ + uint8_t *bitstream = av_malloc(ctx->stor_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!bitstream) + return AVERROR(ENOMEM); + memcpy(bitstream, ctx->stored_frame, ctx->stor_size); + bytestream2_init(&gb, bitstream, ctx->stor_size); + ret = process_frame_obj(ctx, &gb, xoff, yoff); + av_free(bitstream); + } else { + /* this happens a lot in RA1: The individual files are meant to + * be played in sequence, with some referencing objects STORed + * by previous files, e.g. the cockpit codec21 object in RA1 LVL8. + * But spamming the log with errors is also not helpful, so + * here we simply ignore this case. Return 1 to indicate that + * there was no valid image fetched. + */ + ret = 1; + } + return ret; +} + +static int process_xpal(SANMVideoContext *ctx, int size) +{ + int16_t *dp = ctx->delta_pal; + uint32_t *pal = ctx->pal; + uint16_t cmd; + uint8_t c[3]; + int i, j; + + if (size < 4) + return AVERROR_INVALIDDATA; + bytestream2_skip(&ctx->gb, 2); + cmd = bytestream2_get_be16(&ctx->gb); + size -= 4; + + if (cmd == 1) { + for (i = 0; i < PALETTE_DELTA; i += 3) { + for (j = 0; j < 3; j++) { + ctx->shift_pal[i + j] += dp[i + j]; + c[j] = av_clip_uint8(ctx->shift_pal[i + j] >> 7) & 0xFFU; + } + *pal++ = 0xFFU << 24 | c[0] << 16 | c[1] << 8 | c[2]; + } + } else if (cmd == 0 || cmd == 2) { + if (size < PALETTE_DELTA * 2) { + av_log(ctx->avctx, AV_LOG_ERROR, + "Incorrect palette change block size %"PRIu32".\n", size); + return AVERROR_INVALIDDATA; + } + for (i = 0; i < PALETTE_DELTA; i++) + dp[i] = bytestream2_get_le16u(&ctx->gb); + size -= PALETTE_DELTA * 2; + + if (size >= PALETTE_SIZE * 3) { + for (i = 0; i < PALETTE_SIZE; i++) + ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb); + if (ctx->subversion < 2) + ctx->pal[0] = 0xFFU << 24; + } + for (i = 0, j = 0; i < PALETTE_DELTA; i += 3, j++) { + ctx->shift_pal[i + 0] = (((ctx->pal[j]) >> 16) & 0xFFU) << 7; + ctx->shift_pal[i + 1] = (((ctx->pal[j]) >> 8) & 0xFFU) << 7; + ctx->shift_pal[i + 2] = (((ctx->pal[j]) >> 0) & 0xFFU) << 7; + } + } + return 0; +} + +static int bl16_decode_0(SANMVideoContext *ctx) { uint16_t *frm = ctx->frm0; int x, y; @@ -1010,10 +2258,60 @@ static int decode_0(SANMVideoContext *ctx) return 0; } -static int decode_nop(SANMVideoContext *ctx) +/* BL16 pixel interpolation function, see tgsmush.dll c690 */ +static inline uint16_t bl16_c1_avg_col(uint16_t c1, uint16_t c2) { - avpriv_request_sample(ctx->avctx, "Unknown/unsupported compression type"); - return AVERROR_PATCHWELCOME; + return (((c2 & 0x07e0) + (c1 & 0x07e0)) & 0x00fc0) | + (((c2 & 0xf800) + (c1 & 0xf800)) & 0x1f000) | + (((c2 & 0x001f) + (c1 & 0x001f))) >> 1; +} + +/* Quarter-sized keyframe encoded as stream of 16bit pixel values. Interpolate + * missing pixels by averaging the colors of immediate neighbours. + * Identical to codec47_comp1() but with 16bit-pixels. tgsmush.dll c6f0 + */ +static int bl16_decode_1(SANMVideoContext *ctx) +{ + uint16_t hh, hw, hw1, c1, c2, *dst1, *dst2; + + hh = (ctx->height + 1) >> 1; + hw1 = (ctx->width - 1) >> 1; + if (!hw1 || (bytestream2_get_bytes_left(&ctx->gb) < (hh * hw1 * 2))) + return AVERROR_INVALIDDATA; + dst1 = (uint16_t *)ctx->frm0 + ctx->pitch; /* start with line 1 */ + while (hh--) { + hw = hw1; + c1 = bytestream2_get_le16u(&ctx->gb); + dst1[0] = c1; + dst1[1] = c1; + dst2 = dst1 + 2; + while (--hw) { + c2 = bytestream2_get_le16u(&ctx->gb); + *dst2++ = bl16_c1_avg_col(c1, c2); + *dst2++ = c2; + c1 = c2; + } + dst1 += ctx->pitch * 2; /* skip to overnext line */ + } + /* line 0 is a copy of line 1 */ + memcpy(ctx->frm0, ctx->frm0 + ctx->pitch, ctx->pitch); + + /* complete the skipped lines by averaging from the pixels in the lines + * above and below + */ + dst1 = ctx->frm0 + (ctx->pitch * 2); + hh = (ctx->height - 1) >> 1; + while (hh--) { + hw = ctx->width; + dst2 = dst1; + while (hw--) { + c1 = *(dst2 - ctx->pitch); /* pixel from line above */ + c2 = *(dst2 + ctx->pitch); /* pixel from line below */ + *dst2++ = bl16_c1_avg_col(c1, c2); + } + dst1 += ctx->pitch * 2; + } + return 0; } static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, ptrdiff_t pitch) @@ -1145,7 +2443,7 @@ static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my, return good; } -static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size) +static int bl16_block(SANMVideoContext *ctx, int cx, int cy, int blk_size) { int16_t mx, my, index; int opcode; @@ -1157,9 +2455,23 @@ static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size) switch (opcode) { default: - mx = motion_vectors[opcode][0]; - my = motion_vectors[opcode][1]; + mx = c47_mv[opcode][0]; + my = c47_mv[opcode][1]; + /* The original implementation of this codec precomputes a table + * of int16_t of all motion vectors a for given image width. + * For widths starting at 762 pixels, the calculation of + * mv table indices 1+ and 255- overflow the int16_t, inverting the + * sign of the offset. This is actively exploited in e.g. the + * "jonesopn_8.snm" video of "Indiana Jones and the Infernal Machine". + * Therefore let the overflow happen and extract x/y components from + * the new value. + */ + if (ctx->width > 761) { + index = (int16_t)(my * ctx->width + mx); + mx = index % ctx->width; + my = index / ctx->width; + } if (good_mvec(ctx, cx, cy, mx, my, blk_size)) { copy_block(ctx->frm0 + cx + ctx->pitch * cy, ctx->frm2 + cx + mx + ctx->pitch * (cy + my), @@ -1216,13 +2528,13 @@ static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size) opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch); } else { blk_size >>= 1; - if (codec2subblock(ctx, cx, cy, blk_size)) + if (bl16_block(ctx, cx, cy, blk_size)) return AVERROR_INVALIDDATA; - if (codec2subblock(ctx, cx + blk_size, cy, blk_size)) + if (bl16_block(ctx, cx + blk_size, cy, blk_size)) return AVERROR_INVALIDDATA; - if (codec2subblock(ctx, cx, cy + blk_size, blk_size)) + if (bl16_block(ctx, cx, cy + blk_size, blk_size)) return AVERROR_INVALIDDATA; - if (codec2subblock(ctx, cx + blk_size, cy + blk_size, blk_size)) + if (bl16_block(ctx, cx + blk_size, cy + blk_size, blk_size)) return AVERROR_INVALIDDATA; } break; @@ -1230,31 +2542,19 @@ static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size) return 0; } -static int decode_2(SANMVideoContext *ctx) +static int bl16_decode_2(SANMVideoContext *ctx) { int cx, cy, ret; for (cy = 0; cy < ctx->aligned_height; cy += 8) for (cx = 0; cx < ctx->aligned_width; cx += 8) - if (ret = codec2subblock(ctx, cx, cy, 8)) + if (ret = bl16_block(ctx, cx, cy, 8)) return ret; return 0; } -static int decode_3(SANMVideoContext *ctx) -{ - memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size); - return 0; -} - -static int decode_4(SANMVideoContext *ctx) -{ - memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size); - return 0; -} - -static int decode_5(SANMVideoContext *ctx) +static int bl16_decode_5(SANMVideoContext *ctx, int rle_size) { #if HAVE_BIGENDIAN uint16_t *frm; @@ -1262,7 +2562,7 @@ static int decode_5(SANMVideoContext *ctx) #endif uint8_t *dst = (uint8_t*)ctx->frm0; - if (rle_decode(ctx, dst, ctx->buf_size)) + if (rle_decode(ctx, &ctx->gb, dst, rle_size)) return AVERROR_INVALIDDATA; #if HAVE_BIGENDIAN @@ -1277,7 +2577,7 @@ static int decode_5(SANMVideoContext *ctx) return 0; } -static int decode_6(SANMVideoContext *ctx) +static int bl16_decode_6(SANMVideoContext *ctx) { int npixels = ctx->npixels; uint16_t *frm = ctx->frm0; @@ -1292,7 +2592,56 @@ static int decode_6(SANMVideoContext *ctx) return 0; } -static int decode_8(SANMVideoContext *ctx) +/* Quarter-sized keyframe encoded as stream of codebook indices. Interpolate + * missing pixels by averaging the colors of immediate neighbours. + * Identical to codec47_comp1(), but without the interpolation table. + * tgsmush.dll c6f0 + */ +static int bl16_decode_7(SANMVideoContext *ctx) +{ + uint16_t hh, hw, hw1, c1, c2, *dst1, *dst2; + + hh = (ctx->height + 1) >> 1; + hw1 = (ctx->width - 1) >> 1; + if (!hw1 || (bytestream2_get_bytes_left(&ctx->gb) < (hh * hw1))) + return AVERROR_INVALIDDATA; + dst1 = (uint16_t *)ctx->frm0 + ctx->pitch; /* start with line 1 */ + while (hh--) { + hw = hw1; + c1 = ctx->codebook[bytestream2_get_byteu(&ctx->gb)]; + dst1[0] = c1; /* leftmost 2 pixels of a row are identical */ + dst1[1] = c1; + dst2 = dst1 + 2; + while (--hw) { + c2 = ctx->codebook[bytestream2_get_byteu(&ctx->gb)]; + *dst2++ = bl16_c1_avg_col(c1, c2); + *dst2++ = c2; + c1 = c2; + } + dst1 += ctx->pitch * 2; /* skip to overnext line */ + } + /* line 0 is a copy of line 1 */ + memcpy(ctx->frm0, ctx->frm0 + ctx->pitch, ctx->pitch); + + /* complete the skipped lines by averaging from the pixels in the lines + * above and below. + */ + dst1 = ctx->frm0 + (ctx->pitch * 2); + hh = (ctx->height - 1) >> 1; + while (hh--) { + hw = ctx->width; + dst2 = dst1; + while (hw--) { + c1 = *(dst2 - ctx->pitch); /* pixel from line above */ + c2 = *(dst2 + ctx->pitch); /* pixel from line below */ + *dst2++ = bl16_c1_avg_col(c1, c2); + } + dst1 += ctx->pitch * 2; + } + return 0; +} + +static int bl16_decode_8(SANMVideoContext *ctx) { uint16_t *pdest = ctx->frm0; uint8_t *rsrc; @@ -1305,7 +2654,7 @@ static int decode_8(SANMVideoContext *ctx) } rsrc = ctx->rle_buf; - if (rle_decode(ctx, rsrc, npixels)) + if (rle_decode(ctx, &ctx->gb, rsrc, npixels)) return AVERROR_INVALIDDATA; while (npixels--) @@ -1314,53 +2663,6 @@ static int decode_8(SANMVideoContext *ctx) return 0; } -typedef int (*frm_decoder)(SANMVideoContext *ctx); - -static const frm_decoder v1_decoders[] = { - decode_0, decode_nop, decode_2, decode_3, decode_4, decode_5, - decode_6, decode_nop, decode_8 -}; - -static int read_frame_header(SANMVideoContext *ctx, SANMFrameHeader *hdr) -{ - int i, ret; - - if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) { - av_log(ctx->avctx, AV_LOG_ERROR, "Input frame too short (%d bytes).\n", - ret); - return AVERROR_INVALIDDATA; - } - bytestream2_skip(&ctx->gb, 8); // skip pad - - hdr->width = bytestream2_get_le32u(&ctx->gb); - hdr->height = bytestream2_get_le32u(&ctx->gb); - - if (hdr->width != ctx->width || hdr->height != ctx->height) { - avpriv_report_missing_feature(ctx->avctx, "Variable size frames"); - return AVERROR_PATCHWELCOME; - } - - hdr->seq_num = bytestream2_get_le16u(&ctx->gb); - hdr->codec = bytestream2_get_byteu(&ctx->gb); - hdr->rotate_code = bytestream2_get_byteu(&ctx->gb); - - bytestream2_skip(&ctx->gb, 4); // skip pad - - for (i = 0; i < 4; i++) - ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb); - hdr->bg_color = bytestream2_get_le16u(&ctx->gb); - - bytestream2_skip(&ctx->gb, 2); // skip pad - - hdr->rle_output_size = bytestream2_get_le32u(&ctx->gb); - for (i = 0; i < 256; i++) - ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb); - - bytestream2_skip(&ctx->gb, 8); // skip pad - - return 0; -} - static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color) { if (buf_size--) { @@ -1369,12 +2671,12 @@ static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color) } } -static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr) +static int copy_output(SANMVideoContext *ctx, int sanm) { uint8_t *dst; - const uint8_t *src = (uint8_t*) ctx->frm0; + const uint8_t *src = sanm ? (uint8_t *)ctx->frm0 : (uint8_t *)ctx->fbuf; int ret, height = ctx->height; - ptrdiff_t dstpitch, srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1); + ptrdiff_t dstpitch, srcpitch = ctx->pitch * (sanm ? sizeof(ctx->frm0[0]) : 1); if ((ret = ff_get_buffer(ctx->avctx, ctx->frame, 0)) < 0) return ret; @@ -1391,134 +2693,218 @@ static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr) return 0; } +static int decode_bl16(AVCodecContext *avctx,int *got_frame_ptr) +{ + SANMVideoContext *ctx = avctx->priv_data; + int i, ret, w, h, seq_num, codec, bg_color, rle_output_size, rcode; + + if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) { + av_log(ctx->avctx, AV_LOG_ERROR, "Input frame too short (%d bytes).\n", + ret); + return AVERROR_INVALIDDATA; + } + bytestream2_skip(&ctx->gb, 8); // skip pad + + w = bytestream2_get_le32u(&ctx->gb); + h = bytestream2_get_le32u(&ctx->gb); + + if (w != ctx->width || h != ctx->height) { + avpriv_report_missing_feature(ctx->avctx, "Variable size frames"); + return AVERROR_PATCHWELCOME; + } + + seq_num = bytestream2_get_le16u(&ctx->gb); + codec = bytestream2_get_byteu(&ctx->gb); + rcode = bytestream2_get_byteu(&ctx->gb); + + bytestream2_skip(&ctx->gb, 4); // skip pad + + for (i = 0; i < 4; i++) + ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb); + bg_color = bytestream2_get_le16u(&ctx->gb); + + bytestream2_skip(&ctx->gb, 2); // skip pad + + rle_output_size = bytestream2_get_le32u(&ctx->gb); + if (rle_output_size > w * ctx->aligned_height * 2) { + av_log(avctx, AV_LOG_WARNING, "bl16 rle size too large, truncated: %d\n", + rle_output_size); + rle_output_size = w * ctx->aligned_height * 2; + } + + for (i = 0; i < 256; i++) + ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb); + + bytestream2_skip(&ctx->gb, 8); // skip pad + + if (seq_num == 0) { + ctx->frame->flags |= AV_FRAME_FLAG_KEY; + ctx->frame->pict_type = AV_PICTURE_TYPE_I; + fill_frame(ctx->frm1, ctx->npixels, bg_color); + fill_frame(ctx->frm2, ctx->npixels, bg_color); + } else { + ctx->frame->flags &= ~AV_FRAME_FLAG_KEY; + ctx->frame->pict_type = AV_PICTURE_TYPE_P; + } + + ret = 0; + switch (codec) { + case 0: ret = bl16_decode_0(ctx); break; + case 1: ret = bl16_decode_1(ctx); break; + case 2: ret = bl16_decode_2(ctx); break; + case 3: memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size); break; + case 4: memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size); break; + case 5: ret = bl16_decode_5(ctx, rle_output_size); break; + case 6: ret = bl16_decode_6(ctx); break; + case 7: ret = bl16_decode_7(ctx); break; + case 8: ret = bl16_decode_8(ctx); break; + default: + avpriv_request_sample(ctx->avctx, "Unknown/unsupported compression type %d", codec); + return AVERROR_PATCHWELCOME; + } + + if (ret) { + av_log(avctx, AV_LOG_ERROR, + "Subcodec %d: error decoding frame.\n", codec); + return ret; + } + + ret = copy_output(ctx, 1); + if (rcode) + rotate_bufs(ctx, rcode); + if (ret) + return ret; + + *got_frame_ptr = 1; + return 0; +} + +static int decode_anim(AVCodecContext *avctx, int *got_frame_ptr) +{ + SANMVideoContext *ctx = avctx->priv_data; + int i, ret, to_store = 0, have_img = 0; + + ctx->first_fob = 1; + while (bytestream2_get_bytes_left(&ctx->gb) >= 8) { + uint32_t sig, size; + int pos; + + sig = bytestream2_get_be32u(&ctx->gb); + size = bytestream2_get_be32u(&ctx->gb); + pos = bytestream2_tell(&ctx->gb); + + if (bytestream2_get_bytes_left(&ctx->gb) < size) { + av_log(avctx, AV_LOG_ERROR, "Incorrect chunk size %"PRIu32".\n", size); + break; + } + switch (sig) { + case MKBETAG('N', 'P', 'A', 'L'): + if (size != PALETTE_SIZE * 3) { + av_log(avctx, AV_LOG_ERROR, + "Incorrect palette block size %"PRIu32".\n", size); + return AVERROR_INVALIDDATA; + } + for (i = 0; i < PALETTE_SIZE; i++) + ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb); + if (ctx->subversion < 2) + ctx->pal[0] = 0xFFU << 24; + break; + case MKBETAG('F', 'O', 'B', 'J'): + if (size < 16) + return AVERROR_INVALIDDATA; + GetByteContext fc; + bytestream2_init(&fc, ctx->gb.buffer, size); + if (ret = process_frame_obj(ctx, &fc, 0, 0)) { + return ret; + } + have_img = 1; + + /* STOR: for ANIMv0/1 store the whole FOBJ datablock, as it + * needs to be replayed on FTCH, since none of the codecs + * it uses work on the full buffer. + * For ANIMv2, it's enough to store the current framebuffer. + */ + if (to_store) { + to_store = 0; + if (ctx->subversion < 2) { + if (size <= ctx->stored_frame_size) { + bytestream2_seek(&fc, 0, SEEK_SET); + bytestream2_get_bufferu(&fc, ctx->stored_frame, size); + ctx->stor_size = size; + } else { + av_log(avctx, AV_LOG_ERROR, "FOBJ too large for STOR\n"); + ret = AVERROR(ENOMEM); + } + } else { + memcpy(ctx->stored_frame, ctx->fbuf, ctx->buf_size); + ctx->stor_size = ctx->buf_size; + } + } + bytestream2_skip(&ctx->gb, size); + break; + case MKBETAG('X', 'P', 'A', 'L'): + if (ret = process_xpal(ctx, size)) + return ret; + break; + case MKBETAG('S', 'T', 'O', 'R'): + to_store = 1; + break; + case MKBETAG('F', 'T', 'C', 'H'): + if (ctx->subversion < 2) { + if ((ret = process_ftch(ctx, size)) < 0) + return ret; + have_img = (ret == 0) ? 1 : 0; + } else { + if (ctx->stor_size > 0) { + memcpy(ctx->fbuf, ctx->stored_frame, ctx->buf_size); + have_img = 1; + } + } + break; + default: + bytestream2_skip(&ctx->gb, size); + av_log(avctx, AV_LOG_DEBUG, + "Unknown/unsupported chunk %"PRIx32".\n", sig); + break; + } + + /* the sizes of chunks are usually a multiple of 2. However + * there are a few unaligned FOBJs in RA1 L2PLAY.ANM only (looks + * like a game bug) and IACT audio chunks which have odd sizes + * but are padded with a zero byte. + */ + bytestream2_seek(&ctx->gb, pos + size, SEEK_SET); + if ((pos + size) & 1) { + if (bytestream2_peek_byte(&ctx->gb) == 0) + bytestream2_skip(&ctx->gb, 1); + } + } + + if (have_img) { + if ((ret = copy_output(ctx, 0))) + return ret; + memcpy(ctx->frame->data[1], ctx->pal, 1024); + *got_frame_ptr = 1; + } + return 0; +} + static int decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *pkt) { SANMVideoContext *ctx = avctx->priv_data; - int i, ret; + int ret; ctx->frame = frame; bytestream2_init(&ctx->gb, pkt->data, pkt->size); if (!ctx->version) { - int to_store = 0; - - while (bytestream2_get_bytes_left(&ctx->gb) >= 8) { - uint32_t sig, size; - int pos; - - sig = bytestream2_get_be32u(&ctx->gb); - size = bytestream2_get_be32u(&ctx->gb); - pos = bytestream2_tell(&ctx->gb); - - if (bytestream2_get_bytes_left(&ctx->gb) < size) { - av_log(avctx, AV_LOG_ERROR, "Incorrect chunk size %"PRIu32".\n", size); - break; - } - switch (sig) { - case MKBETAG('N', 'P', 'A', 'L'): - if (size != PALETTE_SIZE * 3) { - av_log(avctx, AV_LOG_ERROR, - "Incorrect palette block size %"PRIu32".\n", size); - return AVERROR_INVALIDDATA; - } - for (i = 0; i < PALETTE_SIZE; i++) - ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb); - break; - case MKBETAG('F', 'O', 'B', 'J'): - if (size < 16) - return AVERROR_INVALIDDATA; - if (ret = process_frame_obj(ctx)) - return ret; - break; - case MKBETAG('X', 'P', 'A', 'L'): - if (size == 6 || size == 4) { - uint8_t tmp[3]; - int j; - - for (i = 0; i < PALETTE_SIZE; i++) { - for (j = 0; j < 3; j++) { - int t = (ctx->pal[i] >> (16 - j * 8)) & 0xFF; - tmp[j] = av_clip_uint8((t * 129 + ctx->delta_pal[i * 3 + j]) >> 7); - } - ctx->pal[i] = 0xFFU << 24 | AV_RB24(tmp); - } - } else { - if (size < PALETTE_DELTA * 2 + 4) { - av_log(avctx, AV_LOG_ERROR, - "Incorrect palette change block size %"PRIu32".\n", - size); - return AVERROR_INVALIDDATA; - } - bytestream2_skipu(&ctx->gb, 4); - for (i = 0; i < PALETTE_DELTA; i++) - ctx->delta_pal[i] = bytestream2_get_le16u(&ctx->gb); - if (size >= PALETTE_DELTA * 5 + 4) { - for (i = 0; i < PALETTE_SIZE; i++) - ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb); - } else { - memset(ctx->pal, 0, sizeof(ctx->pal)); - } - } - break; - case MKBETAG('S', 'T', 'O', 'R'): - to_store = 1; - break; - case MKBETAG('F', 'T', 'C', 'H'): - memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size); - break; - default: - bytestream2_skip(&ctx->gb, size); - av_log(avctx, AV_LOG_DEBUG, - "Unknown/unsupported chunk %"PRIx32".\n", sig); - break; - } - - bytestream2_seek(&ctx->gb, pos + size, SEEK_SET); - if (size & 1) - bytestream2_skip(&ctx->gb, 1); - } - if (to_store) - memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size); - if ((ret = copy_output(ctx, NULL))) + if ((ret = decode_anim(avctx, got_frame_ptr))) return ret; - memcpy(ctx->frame->data[1], ctx->pal, 1024); } else { - SANMFrameHeader header; - - if ((ret = read_frame_header(ctx, &header))) - return ret; - - ctx->rotate_code = header.rotate_code; - if (!header.seq_num) { - ctx->frame->flags |= AV_FRAME_FLAG_KEY; - ctx->frame->pict_type = AV_PICTURE_TYPE_I; - fill_frame(ctx->frm1, ctx->npixels, header.bg_color); - fill_frame(ctx->frm2, ctx->npixels, header.bg_color); - } else { - ctx->frame->flags &= ~AV_FRAME_FLAG_KEY; - ctx->frame->pict_type = AV_PICTURE_TYPE_P; - } - - if (header.codec < FF_ARRAY_ELEMS(v1_decoders)) { - if ((ret = v1_decoders[header.codec](ctx))) { - av_log(avctx, AV_LOG_ERROR, - "Subcodec %d: error decoding frame.\n", header.codec); - return ret; - } - } else { - avpriv_request_sample(avctx, "Subcodec %d", header.codec); - return AVERROR_PATCHWELCOME; - } - - if ((ret = copy_output(ctx, &header))) + if ((ret = decode_bl16(avctx, got_frame_ptr))) return ret; } - if (ctx->rotate_code) - rotate_bufs(ctx, ctx->rotate_code); - - *got_frame_ptr = 1; - return pkt->size; } diff --git a/libavcodec/sbc_parser.c b/libavcodec/sbc_parser.c index 2d427cc7c..58150885e 100644 --- a/libavcodec/sbc_parser.c +++ b/libavcodec/sbc_parser.c @@ -22,6 +22,7 @@ #include "sbc.h" #include "parser.h" +#include "parser_internal.h" typedef struct SBCParseContext { ParseContext pc; @@ -116,9 +117,9 @@ static int sbc_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_sbc_parser = { - .codec_ids = { AV_CODEC_ID_SBC }, +const FFCodecParser ff_sbc_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_SBC), .priv_data_size = sizeof(SBCParseContext), - .parser_parse = sbc_parse, - .parser_close = ff_parse_close, + .parse = sbc_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/sbcdec.c b/libavcodec/sbcdec.c index 033a8380d..d999cefd2 100644 --- a/libavcodec/sbcdec.c +++ b/libavcodec/sbcdec.c @@ -229,10 +229,10 @@ static inline void sbc_synthesize_four(struct sbc_decoder_state *state, /* Distribute the new matrix value to the shifted position */ v[offset[i]] = - (int)( (unsigned)ff_synmatrix4[i][0] * frame->sb_sample[blk][ch][0] + - (unsigned)ff_synmatrix4[i][1] * frame->sb_sample[blk][ch][1] + - (unsigned)ff_synmatrix4[i][2] * frame->sb_sample[blk][ch][2] + - (unsigned)ff_synmatrix4[i][3] * frame->sb_sample[blk][ch][3] ) >> 15; + (int)( (unsigned)synmatrix4[i][0] * frame->sb_sample[blk][ch][0] + + (unsigned)synmatrix4[i][1] * frame->sb_sample[blk][ch][1] + + (unsigned)synmatrix4[i][2] * frame->sb_sample[blk][ch][2] + + (unsigned)synmatrix4[i][3] * frame->sb_sample[blk][ch][3] ) >> 15; } /* Compute the samples */ @@ -241,16 +241,16 @@ static inline void sbc_synthesize_four(struct sbc_decoder_state *state, /* Store in output, Q0 */ AV_WN16A(&output_frame->data[ch][blk * 8 + i * 2], av_clip_int16( - (int)( (unsigned)v[offset[i] + 0] * ff_sbc_proto_4_40m0[idx + 0] + - (unsigned)v[offset[k] + 1] * ff_sbc_proto_4_40m1[idx + 0] + - (unsigned)v[offset[i] + 2] * ff_sbc_proto_4_40m0[idx + 1] + - (unsigned)v[offset[k] + 3] * ff_sbc_proto_4_40m1[idx + 1] + - (unsigned)v[offset[i] + 4] * ff_sbc_proto_4_40m0[idx + 2] + - (unsigned)v[offset[k] + 5] * ff_sbc_proto_4_40m1[idx + 2] + - (unsigned)v[offset[i] + 6] * ff_sbc_proto_4_40m0[idx + 3] + - (unsigned)v[offset[k] + 7] * ff_sbc_proto_4_40m1[idx + 3] + - (unsigned)v[offset[i] + 8] * ff_sbc_proto_4_40m0[idx + 4] + - (unsigned)v[offset[k] + 9] * ff_sbc_proto_4_40m1[idx + 4] ) >> 15)); + (int)( (unsigned)v[offset[i] + 0] * sbc_proto_4_40m0[idx + 0] + + (unsigned)v[offset[k] + 1] * sbc_proto_4_40m1[idx + 0] + + (unsigned)v[offset[i] + 2] * sbc_proto_4_40m0[idx + 1] + + (unsigned)v[offset[k] + 3] * sbc_proto_4_40m1[idx + 1] + + (unsigned)v[offset[i] + 4] * sbc_proto_4_40m0[idx + 2] + + (unsigned)v[offset[k] + 5] * sbc_proto_4_40m1[idx + 2] + + (unsigned)v[offset[i] + 6] * sbc_proto_4_40m0[idx + 3] + + (unsigned)v[offset[k] + 7] * sbc_proto_4_40m1[idx + 3] + + (unsigned)v[offset[i] + 8] * sbc_proto_4_40m0[idx + 4] + + (unsigned)v[offset[k] + 9] * sbc_proto_4_40m1[idx + 4] ) >> 15)); } } @@ -272,14 +272,14 @@ static inline void sbc_synthesize_eight(struct sbc_decoder_state *state, /* Distribute the new matrix value to the shifted position */ v[offset[i]] = - (int)( (unsigned)ff_synmatrix8[i][0] * frame->sb_sample[blk][ch][0] + - (unsigned)ff_synmatrix8[i][1] * frame->sb_sample[blk][ch][1] + - (unsigned)ff_synmatrix8[i][2] * frame->sb_sample[blk][ch][2] + - (unsigned)ff_synmatrix8[i][3] * frame->sb_sample[blk][ch][3] + - (unsigned)ff_synmatrix8[i][4] * frame->sb_sample[blk][ch][4] + - (unsigned)ff_synmatrix8[i][5] * frame->sb_sample[blk][ch][5] + - (unsigned)ff_synmatrix8[i][6] * frame->sb_sample[blk][ch][6] + - (unsigned)ff_synmatrix8[i][7] * frame->sb_sample[blk][ch][7] ) >> 15; + (int)( (unsigned)synmatrix8[i][0] * frame->sb_sample[blk][ch][0] + + (unsigned)synmatrix8[i][1] * frame->sb_sample[blk][ch][1] + + (unsigned)synmatrix8[i][2] * frame->sb_sample[blk][ch][2] + + (unsigned)synmatrix8[i][3] * frame->sb_sample[blk][ch][3] + + (unsigned)synmatrix8[i][4] * frame->sb_sample[blk][ch][4] + + (unsigned)synmatrix8[i][5] * frame->sb_sample[blk][ch][5] + + (unsigned)synmatrix8[i][6] * frame->sb_sample[blk][ch][6] + + (unsigned)synmatrix8[i][7] * frame->sb_sample[blk][ch][7] ) >> 15; } /* Compute the samples */ @@ -288,16 +288,16 @@ static inline void sbc_synthesize_eight(struct sbc_decoder_state *state, /* Store in output, Q0 */ AV_WN16A(&output_frame->data[ch][blk * 16 + i * 2], av_clip_int16( - (int)( (unsigned)v[offset[i] + 0] * ff_sbc_proto_8_80m0[idx + 0] + - (unsigned)v[offset[k] + 1] * ff_sbc_proto_8_80m1[idx + 0] + - (unsigned)v[offset[i] + 2] * ff_sbc_proto_8_80m0[idx + 1] + - (unsigned)v[offset[k] + 3] * ff_sbc_proto_8_80m1[idx + 1] + - (unsigned)v[offset[i] + 4] * ff_sbc_proto_8_80m0[idx + 2] + - (unsigned)v[offset[k] + 5] * ff_sbc_proto_8_80m1[idx + 2] + - (unsigned)v[offset[i] + 6] * ff_sbc_proto_8_80m0[idx + 3] + - (unsigned)v[offset[k] + 7] * ff_sbc_proto_8_80m1[idx + 3] + - (unsigned)v[offset[i] + 8] * ff_sbc_proto_8_80m0[idx + 4] + - (unsigned)v[offset[k] + 9] * ff_sbc_proto_8_80m1[idx + 4] ) >> 15)); + (int)( (unsigned)v[offset[i] + 0] * sbc_proto_8_80m0[idx + 0] + + (unsigned)v[offset[k] + 1] * sbc_proto_8_80m1[idx + 0] + + (unsigned)v[offset[i] + 2] * sbc_proto_8_80m0[idx + 1] + + (unsigned)v[offset[k] + 3] * sbc_proto_8_80m1[idx + 1] + + (unsigned)v[offset[i] + 4] * sbc_proto_8_80m0[idx + 2] + + (unsigned)v[offset[k] + 5] * sbc_proto_8_80m1[idx + 2] + + (unsigned)v[offset[i] + 6] * sbc_proto_8_80m0[idx + 3] + + (unsigned)v[offset[k] + 7] * sbc_proto_8_80m1[idx + 3] + + (unsigned)v[offset[i] + 8] * sbc_proto_8_80m0[idx + 4] + + (unsigned)v[offset[k] + 9] * sbc_proto_8_80m1[idx + 4] ) >> 15)); } } @@ -321,7 +321,7 @@ static void sbc_synthesize_audio(struct sbc_decoder_state *state, } } -static int sbc_decode_init(AVCodecContext *avctx) +static av_cold int sbc_decode_init(AVCodecContext *avctx) { SBCDecContext *sbc = avctx->priv_data; int i, ch; @@ -371,10 +371,4 @@ const FFCodec ff_sbc_decoder = { .init = sbc_decode_init, FF_CODEC_DECODE_CB(sbc_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]) { 16000, 32000, 44100, 48000, 0 }, }; diff --git a/libavcodec/sbcdec_data.c b/libavcodec/sbcdec_data.c deleted file mode 100644 index 215216220..000000000 --- a/libavcodec/sbcdec_data.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Bluetooth low-complexity, subband codec (SBC) - * - * Copyright (C) 2017 Aurelien Jacobs - * Copyright (C) 2008-2010 Nokia Corporation - * Copyright (C) 2004-2010 Marcel Holtmann - * Copyright (C) 2004-2005 Henryk Ploetz - * Copyright (C) 2005-2006 Brad Midgley - * - * 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 - * SBC decoder tables - */ - -#include -#include "sbcdec_data.h" -#include "sbc.h" - -#define SS4(val) ((int32_t)val >> 12) -#define SS8(val) ((int32_t)val >> 14) -#define SN4(val) ((int32_t)val >> 11 + 1 + SBCDEC_FIXED_EXTRA_BITS) -#define SN8(val) ((int32_t)val >> 11 + 1 + SBCDEC_FIXED_EXTRA_BITS) - -const int32_t ff_sbc_proto_4_40m0[] = { - SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8), - SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8), - SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330), - SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00), - SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7) -}; - -const int32_t ff_sbc_proto_4_40m1[] = { - SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475), - SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370), - SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b), - SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b), - SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7) -}; - -const int32_t ff_sbc_proto_8_80m0[] = { - SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100), - SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0), - SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c), - SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705), - SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db), - SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948), - SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200), - SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358), - SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31), - SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170) -}; - -const int32_t ff_sbc_proto_8_80m1[] = { - SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620), - SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40), - SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01), - SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94), - SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b), - SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68), - SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20), - SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410), - SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da), - SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a) -}; - -const int32_t ff_synmatrix4[8][4] = { - { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) }, - { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) }, - { SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) }, - { SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) }, - { SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) }, - { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }, - { SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) }, - { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) } -}; - -const int32_t ff_synmatrix8[16][8] = { - { SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798), - SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) }, - { SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988), - SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) }, - { SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac), - SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) }, - { SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10), - SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) }, - { SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), - SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) }, - { SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0), - SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) }, - { SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54), - SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) }, - { SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678), - SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) }, - { SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868), - SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) }, - { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), - SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }, - { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), - SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, - { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), - SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, - { SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), - SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) }, - { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), - SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, - { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), - SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, - { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), - SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) } -}; diff --git a/libavcodec/sbcdec_data.h b/libavcodec/sbcdec_data.h index 1b79d1de2..d8ae06221 100644 --- a/libavcodec/sbcdec_data.h +++ b/libavcodec/sbcdec_data.h @@ -33,12 +33,99 @@ #define AVCODEC_SBCDEC_DATA_H #include +#include "sbc.h" -extern const int32_t ff_sbc_proto_4_40m0[]; -extern const int32_t ff_sbc_proto_4_40m1[]; -extern const int32_t ff_sbc_proto_8_80m0[]; -extern const int32_t ff_sbc_proto_8_80m1[]; -extern const int32_t ff_synmatrix4[8][4]; -extern const int32_t ff_synmatrix8[16][8]; +#define SS4(val) ((int32_t)val >> 12) +#define SS8(val) ((int32_t)val >> 14) +#define SN4(val) ((int32_t)val >> 11 + 1 + SBCDEC_FIXED_EXTRA_BITS) +#define SN8(val) ((int32_t)val >> 11 + 1 + SBCDEC_FIXED_EXTRA_BITS) + +static const int32_t sbc_proto_4_40m0[] = { + SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8), + SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8), + SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330), + SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00), + SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7) +}; + +static const int32_t sbc_proto_4_40m1[] = { + SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475), + SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370), + SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b), + SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b), + SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7) +}; + +static const int32_t sbc_proto_8_80m0[] = { + SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100), + SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0), + SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c), + SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705), + SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db), + SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948), + SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200), + SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358), + SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31), + SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170) +}; + +static const int32_t sbc_proto_8_80m1[] = { + SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620), + SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40), + SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01), + SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94), + SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b), + SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68), + SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20), + SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410), + SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da), + SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a) +}; + +static const int32_t synmatrix4[8][4] = { + { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) }, + { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) }, + { SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) }, + { SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) }, + { SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) }, + { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }, + { SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) }, + { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) } +}; + +static const int32_t synmatrix8[16][8] = { + { SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798), + SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) }, + { SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988), + SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) }, + { SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac), + SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) }, + { SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10), + SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) }, + { SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), + SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) }, + { SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0), + SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) }, + { SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54), + SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) }, + { SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678), + SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) }, + { SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868), + SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) }, + { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), + SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }, + { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), + SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, + { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), + SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, + { SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), + SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) }, + { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), + SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, + { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), + SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, + { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), + SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) } +}; #endif /* AVCODEC_SBCDEC_DATA_H */ diff --git a/libavcodec/sbcdsp.c b/libavcodec/sbcdsp.c index 400526ce6..5674bdc4a 100644 --- a/libavcodec/sbcdsp.c +++ b/libavcodec/sbcdsp.c @@ -107,26 +107,26 @@ static inline void sbc_analyze_4b_4s_simd(SBCDSPContext *s, int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ - s->sbc_analyze_4(x + 12, out, ff_sbcdsp_analysis_consts_fixed4_simd_odd); + s->sbc_analyze_4(x + 12, out, sbcdsp_analysis_consts_fixed4_simd_odd); out += out_stride; - s->sbc_analyze_4(x + 8, out, ff_sbcdsp_analysis_consts_fixed4_simd_even); + s->sbc_analyze_4(x + 8, out, sbcdsp_analysis_consts_fixed4_simd_even); out += out_stride; - s->sbc_analyze_4(x + 4, out, ff_sbcdsp_analysis_consts_fixed4_simd_odd); + s->sbc_analyze_4(x + 4, out, sbcdsp_analysis_consts_fixed4_simd_odd); out += out_stride; - s->sbc_analyze_4(x + 0, out, ff_sbcdsp_analysis_consts_fixed4_simd_even); + s->sbc_analyze_4(x + 0, out, sbcdsp_analysis_consts_fixed4_simd_even); } static inline void sbc_analyze_4b_8s_simd(SBCDSPContext *s, int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ - s->sbc_analyze_8(x + 24, out, ff_sbcdsp_analysis_consts_fixed8_simd_odd); + s->sbc_analyze_8(x + 24, out, sbcdsp_analysis_consts_fixed8_simd_odd); out += out_stride; - s->sbc_analyze_8(x + 16, out, ff_sbcdsp_analysis_consts_fixed8_simd_even); + s->sbc_analyze_8(x + 16, out, sbcdsp_analysis_consts_fixed8_simd_even); out += out_stride; - s->sbc_analyze_8(x + 8, out, ff_sbcdsp_analysis_consts_fixed8_simd_odd); + s->sbc_analyze_8(x + 8, out, sbcdsp_analysis_consts_fixed8_simd_odd); out += out_stride; - s->sbc_analyze_8(x + 0, out, ff_sbcdsp_analysis_consts_fixed8_simd_even); + s->sbc_analyze_8(x + 0, out, sbcdsp_analysis_consts_fixed8_simd_even); } static inline void sbc_analyze_1b_8s_simd_even(SBCDSPContext *s, @@ -137,7 +137,7 @@ static inline void sbc_analyze_1b_8s_simd_odd(SBCDSPContext *s, int16_t *x, int32_t *out, int out_stride) { - s->sbc_analyze_8(x, out, ff_sbcdsp_analysis_consts_fixed8_simd_odd); + s->sbc_analyze_8(x, out, sbcdsp_analysis_consts_fixed8_simd_odd); s->sbc_analyze_8s = sbc_analyze_1b_8s_simd_even; } @@ -145,7 +145,7 @@ static inline void sbc_analyze_1b_8s_simd_even(SBCDSPContext *s, int16_t *x, int32_t *out, int out_stride) { - s->sbc_analyze_8(x, out, ff_sbcdsp_analysis_consts_fixed8_simd_even); + s->sbc_analyze_8(x, out, sbcdsp_analysis_consts_fixed8_simd_even); s->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd; } @@ -382,7 +382,7 @@ av_cold void ff_sbcdsp_init(SBCDSPContext *s) #if ARCH_ARM ff_sbcdsp_init_arm(s); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_sbcdsp_init_x86(s); #endif } diff --git a/libavcodec/sbcdsp.h b/libavcodec/sbcdsp.h index 24264df51..20266bf25 100644 --- a/libavcodec/sbcdsp.h +++ b/libavcodec/sbcdsp.h @@ -32,10 +32,11 @@ #ifndef AVCODEC_SBCDSP_H #define AVCODEC_SBCDSP_H +#include + #include "libavutil/mem_internal.h" #include "sbc.h" -#include "sbcdsp_data.h" #define SCALE_OUT_BITS 15 #define SBC_X_BUFFER_SIZE 328 diff --git a/libavcodec/sbcdsp_data.c b/libavcodec/sbcdsp_data.c deleted file mode 100644 index ad6390c7c..000000000 --- a/libavcodec/sbcdsp_data.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Bluetooth low-complexity, subband codec (SBC) - * - * Copyright (C) 2017 Aurelien Jacobs - * Copyright (C) 2008-2010 Nokia Corporation - * Copyright (C) 2004-2010 Marcel Holtmann - * Copyright (C) 2004-2005 Henryk Ploetz - * Copyright (C) 2005-2006 Brad Midgley - * - * 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 - * miscellaneous SBC tables - */ - -#include "libavutil/mem_internal.h" - -#include "sbcdsp_data.h" - -#define F_PROTO(x) ((int32_t) (((x) * 2) * ((int32_t) 1 << 15) + 0.5)) -#define F_COS(x) ((int32_t) (((x) ) * ((int32_t) 1 << 15) + 0.5)) - -/* - * Constant tables for the use in SIMD optimized analysis filters - * Each table consists of two parts: - * 1. reordered "proto" table - * 2. reordered "cos" table - * - * Due to non-symmetrical reordering, separate tables for "even" - * and "odd" cases are needed - */ - -DECLARE_ALIGNED(SBC_ALIGN, const int16_t, ff_sbcdsp_analysis_consts_fixed4_simd_even)[40 + 16] = { -#define C0 1.0932568993 -#define C1 1.3056875580 -#define C2 1.3056875580 -#define C3 1.6772280856 - -#define F(x) F_PROTO(x) - F(0.00000000E+00 * C0), F(3.83720193E-03 * C0), - F(5.36548976E-04 * C1), F(2.73370904E-03 * C1), - F(3.06012286E-03 * C2), F(3.89205149E-03 * C2), - F(0.00000000E+00 * C3), -F(1.49188357E-03 * C3), - F(1.09137620E-02 * C0), F(2.58767811E-02 * C0), - F(2.04385087E-02 * C1), F(3.21939290E-02 * C1), - F(7.76463494E-02 * C2), F(6.13245186E-03 * C2), - F(0.00000000E+00 * C3), -F(2.88757392E-02 * C3), - F(1.35593274E-01 * C0), F(2.94315332E-01 * C0), - F(1.94987841E-01 * C1), F(2.81828203E-01 * C1), - -F(1.94987841E-01 * C2), F(2.81828203E-01 * C2), - F(0.00000000E+00 * C3), -F(2.46636662E-01 * C3), - -F(1.35593274E-01 * C0), F(2.58767811E-02 * C0), - -F(7.76463494E-02 * C1), F(6.13245186E-03 * C1), - -F(2.04385087E-02 * C2), F(3.21939290E-02 * C2), - F(0.00000000E+00 * C3), F(2.88217274E-02 * C3), - -F(1.09137620E-02 * C0), F(3.83720193E-03 * C0), - -F(3.06012286E-03 * C1), F(3.89205149E-03 * C1), - -F(5.36548976E-04 * C2), F(2.73370904E-03 * C2), - F(0.00000000E+00 * C3), -F(1.86581691E-03 * C3), -#undef F -#define F(x) F_COS(x) - F(0.7071067812 / C0), F(0.9238795325 / C1), - -F(0.7071067812 / C0), F(0.3826834324 / C1), - -F(0.7071067812 / C0), -F(0.3826834324 / C1), - F(0.7071067812 / C0), -F(0.9238795325 / C1), - F(0.3826834324 / C2), -F(1.0000000000 / C3), - -F(0.9238795325 / C2), -F(1.0000000000 / C3), - F(0.9238795325 / C2), -F(1.0000000000 / C3), - -F(0.3826834324 / C2), -F(1.0000000000 / C3), -#undef F - -#undef C0 -#undef C1 -#undef C2 -#undef C3 -}; - -DECLARE_ALIGNED(SBC_ALIGN, const int16_t, ff_sbcdsp_analysis_consts_fixed4_simd_odd)[40 + 16] = { -#define C0 1.3056875580 -#define C1 1.6772280856 -#define C2 1.0932568993 -#define C3 1.3056875580 - -#define F(x) F_PROTO(x) - F(2.73370904E-03 * C0), F(5.36548976E-04 * C0), - -F(1.49188357E-03 * C1), F(0.00000000E+00 * C1), - F(3.83720193E-03 * C2), F(1.09137620E-02 * C2), - F(3.89205149E-03 * C3), F(3.06012286E-03 * C3), - F(3.21939290E-02 * C0), F(2.04385087E-02 * C0), - -F(2.88757392E-02 * C1), F(0.00000000E+00 * C1), - F(2.58767811E-02 * C2), F(1.35593274E-01 * C2), - F(6.13245186E-03 * C3), F(7.76463494E-02 * C3), - F(2.81828203E-01 * C0), F(1.94987841E-01 * C0), - -F(2.46636662E-01 * C1), F(0.00000000E+00 * C1), - F(2.94315332E-01 * C2), -F(1.35593274E-01 * C2), - F(2.81828203E-01 * C3), -F(1.94987841E-01 * C3), - F(6.13245186E-03 * C0), -F(7.76463494E-02 * C0), - F(2.88217274E-02 * C1), F(0.00000000E+00 * C1), - F(2.58767811E-02 * C2), -F(1.09137620E-02 * C2), - F(3.21939290E-02 * C3), -F(2.04385087E-02 * C3), - F(3.89205149E-03 * C0), -F(3.06012286E-03 * C0), - -F(1.86581691E-03 * C1), F(0.00000000E+00 * C1), - F(3.83720193E-03 * C2), F(0.00000000E+00 * C2), - F(2.73370904E-03 * C3), -F(5.36548976E-04 * C3), -#undef F -#define F(x) F_COS(x) - F(0.9238795325 / C0), -F(1.0000000000 / C1), - F(0.3826834324 / C0), -F(1.0000000000 / C1), - -F(0.3826834324 / C0), -F(1.0000000000 / C1), - -F(0.9238795325 / C0), -F(1.0000000000 / C1), - F(0.7071067812 / C2), F(0.3826834324 / C3), - -F(0.7071067812 / C2), -F(0.9238795325 / C3), - -F(0.7071067812 / C2), F(0.9238795325 / C3), - F(0.7071067812 / C2), -F(0.3826834324 / C3), -#undef F - -#undef C0 -#undef C1 -#undef C2 -#undef C3 -}; - -DECLARE_ALIGNED(SBC_ALIGN, const int16_t, ff_sbcdsp_analysis_consts_fixed8_simd_even)[80 + 64] = { -#define C0 2.7906148894 -#define C1 2.4270044280 -#define C2 2.8015616024 -#define C3 3.1710363741 -#define C4 2.5377944043 -#define C5 2.4270044280 -#define C6 2.8015616024 -#define C7 3.1710363741 - -#define F(x) F_PROTO(x) - F(0.00000000E+00 * C0), F(2.01182542E-03 * C0), - F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), - F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), - F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), - -F(8.23919506E-04 * C4), F(0.00000000E+00 * C4), - F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), - F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), - F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), - F(5.65949473E-03 * C0), F(1.29371806E-02 * C0), - F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), - F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), - F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), - -F(1.46525263E-02 * C4), F(0.00000000E+00 * C4), - F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), - F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), - -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), - F(6.79989431E-02 * C0), F(1.46955068E-01 * C0), - F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), - F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), - F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), - -F(1.23264548E-01 * C4), F(0.00000000E+00 * C4), - F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), - F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), - F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), - -F(6.79989431E-02 * C0), F(1.29371806E-02 * C0), - -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), - -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), - -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), - F(1.46404076E-02 * C4), F(0.00000000E+00 * C4), - F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), - F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), - F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), - -F(5.65949473E-03 * C0), F(2.01182542E-03 * C0), - -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), - -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), - -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), - -F(9.02154502E-04 * C4), F(0.00000000E+00 * C4), - F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), - F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), - F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), -#undef F -#define F(x) F_COS(x) - F(0.7071067812 / C0), F(0.8314696123 / C1), - -F(0.7071067812 / C0), -F(0.1950903220 / C1), - -F(0.7071067812 / C0), -F(0.9807852804 / C1), - F(0.7071067812 / C0), -F(0.5555702330 / C1), - F(0.7071067812 / C0), F(0.5555702330 / C1), - -F(0.7071067812 / C0), F(0.9807852804 / C1), - -F(0.7071067812 / C0), F(0.1950903220 / C1), - F(0.7071067812 / C0), -F(0.8314696123 / C1), - F(0.9238795325 / C2), F(0.9807852804 / C3), - F(0.3826834324 / C2), F(0.8314696123 / C3), - -F(0.3826834324 / C2), F(0.5555702330 / C3), - -F(0.9238795325 / C2), F(0.1950903220 / C3), - -F(0.9238795325 / C2), -F(0.1950903220 / C3), - -F(0.3826834324 / C2), -F(0.5555702330 / C3), - F(0.3826834324 / C2), -F(0.8314696123 / C3), - F(0.9238795325 / C2), -F(0.9807852804 / C3), - -F(1.0000000000 / C4), F(0.5555702330 / C5), - -F(1.0000000000 / C4), -F(0.9807852804 / C5), - -F(1.0000000000 / C4), F(0.1950903220 / C5), - -F(1.0000000000 / C4), F(0.8314696123 / C5), - -F(1.0000000000 / C4), -F(0.8314696123 / C5), - -F(1.0000000000 / C4), -F(0.1950903220 / C5), - -F(1.0000000000 / C4), F(0.9807852804 / C5), - -F(1.0000000000 / C4), -F(0.5555702330 / C5), - F(0.3826834324 / C6), F(0.1950903220 / C7), - -F(0.9238795325 / C6), -F(0.5555702330 / C7), - F(0.9238795325 / C6), F(0.8314696123 / C7), - -F(0.3826834324 / C6), -F(0.9807852804 / C7), - -F(0.3826834324 / C6), F(0.9807852804 / C7), - F(0.9238795325 / C6), -F(0.8314696123 / C7), - -F(0.9238795325 / C6), F(0.5555702330 / C7), - F(0.3826834324 / C6), -F(0.1950903220 / C7), -#undef F - -#undef C0 -#undef C1 -#undef C2 -#undef C3 -#undef C4 -#undef C5 -#undef C6 -#undef C7 -}; - -DECLARE_ALIGNED(SBC_ALIGN, const int16_t, ff_sbcdsp_analysis_consts_fixed8_simd_odd)[80 + 64] = { -#define C0 2.5377944043 -#define C1 2.4270044280 -#define C2 2.8015616024 -#define C3 3.1710363741 -#define C4 2.7906148894 -#define C5 2.4270044280 -#define C6 2.8015616024 -#define C7 3.1710363741 - -#define F(x) F_PROTO(x) - F(0.00000000E+00 * C0), -F(8.23919506E-04 * C0), - F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), - F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), - F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), - F(2.01182542E-03 * C4), F(5.65949473E-03 * C4), - F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), - F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), - F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), - F(0.00000000E+00 * C0), -F(1.46525263E-02 * C0), - F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), - F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), - F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), - F(1.29371806E-02 * C4), F(6.79989431E-02 * C4), - F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), - F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), - -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), - F(0.00000000E+00 * C0), -F(1.23264548E-01 * C0), - F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), - F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), - F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), - F(1.46955068E-01 * C4), -F(6.79989431E-02 * C4), - F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), - F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), - F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), - F(0.00000000E+00 * C0), F(1.46404076E-02 * C0), - -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), - -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), - -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), - F(1.29371806E-02 * C4), -F(5.65949473E-03 * C4), - F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), - F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), - F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), - F(0.00000000E+00 * C0), -F(9.02154502E-04 * C0), - -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), - -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), - -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), - F(2.01182542E-03 * C4), F(0.00000000E+00 * C4), - F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), - F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), - F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), -#undef F -#define F(x) F_COS(x) - -F(1.0000000000 / C0), F(0.8314696123 / C1), - -F(1.0000000000 / C0), -F(0.1950903220 / C1), - -F(1.0000000000 / C0), -F(0.9807852804 / C1), - -F(1.0000000000 / C0), -F(0.5555702330 / C1), - -F(1.0000000000 / C0), F(0.5555702330 / C1), - -F(1.0000000000 / C0), F(0.9807852804 / C1), - -F(1.0000000000 / C0), F(0.1950903220 / C1), - -F(1.0000000000 / C0), -F(0.8314696123 / C1), - F(0.9238795325 / C2), F(0.9807852804 / C3), - F(0.3826834324 / C2), F(0.8314696123 / C3), - -F(0.3826834324 / C2), F(0.5555702330 / C3), - -F(0.9238795325 / C2), F(0.1950903220 / C3), - -F(0.9238795325 / C2), -F(0.1950903220 / C3), - -F(0.3826834324 / C2), -F(0.5555702330 / C3), - F(0.3826834324 / C2), -F(0.8314696123 / C3), - F(0.9238795325 / C2), -F(0.9807852804 / C3), - F(0.7071067812 / C4), F(0.5555702330 / C5), - -F(0.7071067812 / C4), -F(0.9807852804 / C5), - -F(0.7071067812 / C4), F(0.1950903220 / C5), - F(0.7071067812 / C4), F(0.8314696123 / C5), - F(0.7071067812 / C4), -F(0.8314696123 / C5), - -F(0.7071067812 / C4), -F(0.1950903220 / C5), - -F(0.7071067812 / C4), F(0.9807852804 / C5), - F(0.7071067812 / C4), -F(0.5555702330 / C5), - F(0.3826834324 / C6), F(0.1950903220 / C7), - -F(0.9238795325 / C6), -F(0.5555702330 / C7), - F(0.9238795325 / C6), F(0.8314696123 / C7), - -F(0.3826834324 / C6), -F(0.9807852804 / C7), - -F(0.3826834324 / C6), F(0.9807852804 / C7), - F(0.9238795325 / C6), -F(0.8314696123 / C7), - -F(0.9238795325 / C6), F(0.5555702330 / C7), - F(0.3826834324 / C6), -F(0.1950903220 / C7), -#undef F - -#undef C0 -#undef C1 -#undef C2 -#undef C3 -#undef C4 -#undef C5 -#undef C6 -#undef C7 -}; diff --git a/libavcodec/sbcdsp_data.h b/libavcodec/sbcdsp_data.h index 10fad5caa..006b5f9cc 100644 --- a/libavcodec/sbcdsp_data.h +++ b/libavcodec/sbcdsp_data.h @@ -32,11 +32,18 @@ #ifndef AVCODEC_SBCDSP_DATA_H #define AVCODEC_SBCDSP_DATA_H +#include + +#include "libavutil/mem_internal.h" + #include "sbc.h" #define SBC_PROTO_FIXED_SCALE 16 #define SBC_COS_TABLE_FIXED_SCALE 15 +#define F_PROTO(x) ((int32_t) (((x) * 2) * ((int32_t) 1 << 15) + 0.5)) +#define F_COS(x) ((int32_t) (((x) ) * ((int32_t) 1 << 15) + 0.5)) + /* * Constant tables for the use in SIMD optimized analysis filters * Each table consists of two parts: @@ -47,9 +54,288 @@ * and "odd" cases are needed */ -extern const int16_t ff_sbcdsp_analysis_consts_fixed4_simd_even[]; -extern const int16_t ff_sbcdsp_analysis_consts_fixed4_simd_odd[]; -extern const int16_t ff_sbcdsp_analysis_consts_fixed8_simd_even[]; -extern const int16_t ff_sbcdsp_analysis_consts_fixed8_simd_odd[]; +DECLARE_ALIGNED(SBC_ALIGN, static const int16_t, sbcdsp_analysis_consts_fixed4_simd_even)[40 + 16] = { +#define C0 1.0932568993 +#define C1 1.3056875580 +#define C2 1.3056875580 +#define C3 1.6772280856 + +#define F(x) F_PROTO(x) + F(0.00000000E+00 * C0), F(3.83720193E-03 * C0), + F(5.36548976E-04 * C1), F(2.73370904E-03 * C1), + F(3.06012286E-03 * C2), F(3.89205149E-03 * C2), + F(0.00000000E+00 * C3), -F(1.49188357E-03 * C3), + F(1.09137620E-02 * C0), F(2.58767811E-02 * C0), + F(2.04385087E-02 * C1), F(3.21939290E-02 * C1), + F(7.76463494E-02 * C2), F(6.13245186E-03 * C2), + F(0.00000000E+00 * C3), -F(2.88757392E-02 * C3), + F(1.35593274E-01 * C0), F(2.94315332E-01 * C0), + F(1.94987841E-01 * C1), F(2.81828203E-01 * C1), + -F(1.94987841E-01 * C2), F(2.81828203E-01 * C2), + F(0.00000000E+00 * C3), -F(2.46636662E-01 * C3), + -F(1.35593274E-01 * C0), F(2.58767811E-02 * C0), + -F(7.76463494E-02 * C1), F(6.13245186E-03 * C1), + -F(2.04385087E-02 * C2), F(3.21939290E-02 * C2), + F(0.00000000E+00 * C3), F(2.88217274E-02 * C3), + -F(1.09137620E-02 * C0), F(3.83720193E-03 * C0), + -F(3.06012286E-03 * C1), F(3.89205149E-03 * C1), + -F(5.36548976E-04 * C2), F(2.73370904E-03 * C2), + F(0.00000000E+00 * C3), -F(1.86581691E-03 * C3), +#undef F +#define F(x) F_COS(x) + F(0.7071067812 / C0), F(0.9238795325 / C1), + -F(0.7071067812 / C0), F(0.3826834324 / C1), + -F(0.7071067812 / C0), -F(0.3826834324 / C1), + F(0.7071067812 / C0), -F(0.9238795325 / C1), + F(0.3826834324 / C2), -F(1.0000000000 / C3), + -F(0.9238795325 / C2), -F(1.0000000000 / C3), + F(0.9238795325 / C2), -F(1.0000000000 / C3), + -F(0.3826834324 / C2), -F(1.0000000000 / C3), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +}; + +DECLARE_ALIGNED(SBC_ALIGN, static const int16_t, sbcdsp_analysis_consts_fixed4_simd_odd)[40 + 16] = { +#define C0 1.3056875580 +#define C1 1.6772280856 +#define C2 1.0932568993 +#define C3 1.3056875580 + +#define F(x) F_PROTO(x) + F(2.73370904E-03 * C0), F(5.36548976E-04 * C0), + -F(1.49188357E-03 * C1), F(0.00000000E+00 * C1), + F(3.83720193E-03 * C2), F(1.09137620E-02 * C2), + F(3.89205149E-03 * C3), F(3.06012286E-03 * C3), + F(3.21939290E-02 * C0), F(2.04385087E-02 * C0), + -F(2.88757392E-02 * C1), F(0.00000000E+00 * C1), + F(2.58767811E-02 * C2), F(1.35593274E-01 * C2), + F(6.13245186E-03 * C3), F(7.76463494E-02 * C3), + F(2.81828203E-01 * C0), F(1.94987841E-01 * C0), + -F(2.46636662E-01 * C1), F(0.00000000E+00 * C1), + F(2.94315332E-01 * C2), -F(1.35593274E-01 * C2), + F(2.81828203E-01 * C3), -F(1.94987841E-01 * C3), + F(6.13245186E-03 * C0), -F(7.76463494E-02 * C0), + F(2.88217274E-02 * C1), F(0.00000000E+00 * C1), + F(2.58767811E-02 * C2), -F(1.09137620E-02 * C2), + F(3.21939290E-02 * C3), -F(2.04385087E-02 * C3), + F(3.89205149E-03 * C0), -F(3.06012286E-03 * C0), + -F(1.86581691E-03 * C1), F(0.00000000E+00 * C1), + F(3.83720193E-03 * C2), F(0.00000000E+00 * C2), + F(2.73370904E-03 * C3), -F(5.36548976E-04 * C3), +#undef F +#define F(x) F_COS(x) + F(0.9238795325 / C0), -F(1.0000000000 / C1), + F(0.3826834324 / C0), -F(1.0000000000 / C1), + -F(0.3826834324 / C0), -F(1.0000000000 / C1), + -F(0.9238795325 / C0), -F(1.0000000000 / C1), + F(0.7071067812 / C2), F(0.3826834324 / C3), + -F(0.7071067812 / C2), -F(0.9238795325 / C3), + -F(0.7071067812 / C2), F(0.9238795325 / C3), + F(0.7071067812 / C2), -F(0.3826834324 / C3), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +}; + +DECLARE_ALIGNED(SBC_ALIGN, static const int16_t, sbcdsp_analysis_consts_fixed8_simd_even)[80 + 64] = { +#define C0 2.7906148894 +#define C1 2.4270044280 +#define C2 2.8015616024 +#define C3 3.1710363741 +#define C4 2.5377944043 +#define C5 2.4270044280 +#define C6 2.8015616024 +#define C7 3.1710363741 + +#define F(x) F_PROTO(x) + F(0.00000000E+00 * C0), F(2.01182542E-03 * C0), + F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), + F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), + F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), + -F(8.23919506E-04 * C4), F(0.00000000E+00 * C4), + F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), + F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), + F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), + F(5.65949473E-03 * C0), F(1.29371806E-02 * C0), + F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), + F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), + F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), + -F(1.46525263E-02 * C4), F(0.00000000E+00 * C4), + F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), + F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), + -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), + F(6.79989431E-02 * C0), F(1.46955068E-01 * C0), + F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), + F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), + F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), + -F(1.23264548E-01 * C4), F(0.00000000E+00 * C4), + F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), + F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), + F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), + -F(6.79989431E-02 * C0), F(1.29371806E-02 * C0), + -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), + -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), + -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), + F(1.46404076E-02 * C4), F(0.00000000E+00 * C4), + F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), + F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), + F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), + -F(5.65949473E-03 * C0), F(2.01182542E-03 * C0), + -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), + -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), + -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), + -F(9.02154502E-04 * C4), F(0.00000000E+00 * C4), + F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), + F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), + F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), +#undef F +#define F(x) F_COS(x) + F(0.7071067812 / C0), F(0.8314696123 / C1), + -F(0.7071067812 / C0), -F(0.1950903220 / C1), + -F(0.7071067812 / C0), -F(0.9807852804 / C1), + F(0.7071067812 / C0), -F(0.5555702330 / C1), + F(0.7071067812 / C0), F(0.5555702330 / C1), + -F(0.7071067812 / C0), F(0.9807852804 / C1), + -F(0.7071067812 / C0), F(0.1950903220 / C1), + F(0.7071067812 / C0), -F(0.8314696123 / C1), + F(0.9238795325 / C2), F(0.9807852804 / C3), + F(0.3826834324 / C2), F(0.8314696123 / C3), + -F(0.3826834324 / C2), F(0.5555702330 / C3), + -F(0.9238795325 / C2), F(0.1950903220 / C3), + -F(0.9238795325 / C2), -F(0.1950903220 / C3), + -F(0.3826834324 / C2), -F(0.5555702330 / C3), + F(0.3826834324 / C2), -F(0.8314696123 / C3), + F(0.9238795325 / C2), -F(0.9807852804 / C3), + -F(1.0000000000 / C4), F(0.5555702330 / C5), + -F(1.0000000000 / C4), -F(0.9807852804 / C5), + -F(1.0000000000 / C4), F(0.1950903220 / C5), + -F(1.0000000000 / C4), F(0.8314696123 / C5), + -F(1.0000000000 / C4), -F(0.8314696123 / C5), + -F(1.0000000000 / C4), -F(0.1950903220 / C5), + -F(1.0000000000 / C4), F(0.9807852804 / C5), + -F(1.0000000000 / C4), -F(0.5555702330 / C5), + F(0.3826834324 / C6), F(0.1950903220 / C7), + -F(0.9238795325 / C6), -F(0.5555702330 / C7), + F(0.9238795325 / C6), F(0.8314696123 / C7), + -F(0.3826834324 / C6), -F(0.9807852804 / C7), + -F(0.3826834324 / C6), F(0.9807852804 / C7), + F(0.9238795325 / C6), -F(0.8314696123 / C7), + -F(0.9238795325 / C6), F(0.5555702330 / C7), + F(0.3826834324 / C6), -F(0.1950903220 / C7), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +}; + +DECLARE_ALIGNED(SBC_ALIGN, static const int16_t, sbcdsp_analysis_consts_fixed8_simd_odd)[80 + 64] = { +#define C0 2.5377944043 +#define C1 2.4270044280 +#define C2 2.8015616024 +#define C3 3.1710363741 +#define C4 2.7906148894 +#define C5 2.4270044280 +#define C6 2.8015616024 +#define C7 3.1710363741 + +#define F(x) F_PROTO(x) + F(0.00000000E+00 * C0), -F(8.23919506E-04 * C0), + F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), + F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), + F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), + F(2.01182542E-03 * C4), F(5.65949473E-03 * C4), + F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), + F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), + F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), + F(0.00000000E+00 * C0), -F(1.46525263E-02 * C0), + F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), + F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), + F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), + F(1.29371806E-02 * C4), F(6.79989431E-02 * C4), + F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), + F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), + -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), + F(0.00000000E+00 * C0), -F(1.23264548E-01 * C0), + F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), + F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), + F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), + F(1.46955068E-01 * C4), -F(6.79989431E-02 * C4), + F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), + F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), + F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), + F(0.00000000E+00 * C0), F(1.46404076E-02 * C0), + -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), + -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), + -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), + F(1.29371806E-02 * C4), -F(5.65949473E-03 * C4), + F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), + F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), + F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), + F(0.00000000E+00 * C0), -F(9.02154502E-04 * C0), + -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), + -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), + -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), + F(2.01182542E-03 * C4), F(0.00000000E+00 * C4), + F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), + F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), + F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), +#undef F +#define F(x) F_COS(x) + -F(1.0000000000 / C0), F(0.8314696123 / C1), + -F(1.0000000000 / C0), -F(0.1950903220 / C1), + -F(1.0000000000 / C0), -F(0.9807852804 / C1), + -F(1.0000000000 / C0), -F(0.5555702330 / C1), + -F(1.0000000000 / C0), F(0.5555702330 / C1), + -F(1.0000000000 / C0), F(0.9807852804 / C1), + -F(1.0000000000 / C0), F(0.1950903220 / C1), + -F(1.0000000000 / C0), -F(0.8314696123 / C1), + F(0.9238795325 / C2), F(0.9807852804 / C3), + F(0.3826834324 / C2), F(0.8314696123 / C3), + -F(0.3826834324 / C2), F(0.5555702330 / C3), + -F(0.9238795325 / C2), F(0.1950903220 / C3), + -F(0.9238795325 / C2), -F(0.1950903220 / C3), + -F(0.3826834324 / C2), -F(0.5555702330 / C3), + F(0.3826834324 / C2), -F(0.8314696123 / C3), + F(0.9238795325 / C2), -F(0.9807852804 / C3), + F(0.7071067812 / C4), F(0.5555702330 / C5), + -F(0.7071067812 / C4), -F(0.9807852804 / C5), + -F(0.7071067812 / C4), F(0.1950903220 / C5), + F(0.7071067812 / C4), F(0.8314696123 / C5), + F(0.7071067812 / C4), -F(0.8314696123 / C5), + -F(0.7071067812 / C4), -F(0.1950903220 / C5), + -F(0.7071067812 / C4), F(0.9807852804 / C5), + F(0.7071067812 / C4), -F(0.5555702330 / C5), + F(0.3826834324 / C6), F(0.1950903220 / C7), + -F(0.9238795325 / C6), -F(0.5555702330 / C7), + F(0.9238795325 / C6), F(0.8314696123 / C7), + -F(0.3826834324 / C6), -F(0.9807852804 / C7), + -F(0.3826834324 / C6), F(0.9807852804 / C7), + F(0.9238795325 / C6), -F(0.8314696123 / C7), + -F(0.9238795325 / C6), F(0.5555702330 / C7), + F(0.3826834324 / C6), -F(0.1950903220 / C7), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +}; #endif /* AVCODEC_SBCDSP_DATA_H */ diff --git a/libavcodec/sbcenc.c b/libavcodec/sbcenc.c index f2c4fbe32..fb810c4c5 100644 --- a/libavcodec/sbcenc.c +++ b/libavcodec/sbcenc.c @@ -49,6 +49,8 @@ typedef struct SBCEncContext { DECLARE_ALIGNED(SBC_ALIGN, SBCDSPContext, dsp); } SBCEncContext; +static const int sbc_samplerates[] = { 16000, 32000, 44100, 48000, 0 }; + static int sbc_analyze_audio(SBCDSPContext *s, struct sbc_frame *frame) { int ch, blk; @@ -194,7 +196,7 @@ static size_t sbc_pack_frame(AVPacket *avpkt, struct sbc_frame *frame, return put_bytes_output(&pb); } -static int sbc_encode_init(AVCodecContext *avctx) +static av_cold int sbc_encode_init(AVCodecContext *avctx) { SBCEncContext *sbc = avctx->priv_data; struct sbc_frame *frame = &sbc->frame; @@ -260,8 +262,8 @@ static int sbc_encode_init(AVCodecContext *avctx) avctx->frame_size = 4*((frame->subbands >> 3) + 1) * 4*(frame->blocks >> 2); } - for (int i = 0; avctx->codec->supported_samplerates[i]; i++) - if (avctx->sample_rate == avctx->codec->supported_samplerates[i]) + for (int i = 0; sbc_samplerates[i]; i++) + if (avctx->sample_rate == sbc_samplerates[i]) frame->frequency = i; frame->channels = avctx->ch_layout.nb_channels; @@ -354,12 +356,9 @@ const FFCodec ff_sbc_encoder = { .priv_data_size = sizeof(SBCEncContext), .init = sbc_encode_init, FF_CODEC_ENCODE_CB(sbc_encode_frame), - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]) { 16000, 32000, 44100, 48000, 0 }, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_SAMPLERATES_ARRAY(sbc_samplerates), .p.priv_class = &sbc_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_sbc_profiles), }; diff --git a/libavcodec/sbrdsp_template.c b/libavcodec/sbrdsp_template.c index 9a94af867..b5766c698 100644 --- a/libavcodec/sbrdsp_template.c +++ b/libavcodec/sbrdsp_template.c @@ -102,7 +102,7 @@ av_cold void AAC_RENAME(ff_sbrdsp_init)(SBRDSPContext *s) ff_sbrdsp_init_aarch64(s); #elif ARCH_RISCV ff_sbrdsp_init_riscv(s); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_sbrdsp_init_x86(s); #endif #endif /* !USE_FIXED */ diff --git a/libavcodec/sga.c b/libavcodec/sga.c index c828f7147..b6902452d 100644 --- a/libavcodec/sga.c +++ b/libavcodec/sga.c @@ -254,7 +254,7 @@ static int decode_palmapdata(AVCodecContext *avctx) const int bits = (s->nb_pal + 1) / 2; GetByteContext *gb = &s->gb; GetBitContext pm; - int ret; + av_unused int ret; bytestream2_seek(gb, s->palmapdata_offset, SEEK_SET); if (bytestream2_get_bytes_left(gb) < s->palmapdata_size) @@ -279,7 +279,7 @@ static int decode_tiledata(AVCodecContext *avctx) SGAVideoContext *s = avctx->priv_data; GetByteContext *gb = &s->gb; GetBitContext tm; - int ret; + av_unused int ret; bytestream2_seek(gb, s->tiledata_offset, SEEK_SET); if (bytestream2_get_bytes_left(gb) < s->tiledata_size) @@ -501,11 +501,6 @@ static int sga_decode_frame(AVCodecContext *avctx, AVFrame *frame, } memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif frame->pict_type = AV_PICTURE_TYPE_I; frame->flags |= AV_FRAME_FLAG_KEY; diff --git a/libavcodec/sgienc.c b/libavcodec/sgienc.c index 0901cf58b..93ec9ff6c 100644 --- a/libavcodec/sgienc.c +++ b/libavcodec/sgienc.c @@ -281,11 +281,8 @@ const FFCodec ff_sgi_encoder = { .p.priv_class = &sgi_class, .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE, - AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE, - AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY8, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE, + AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE, + AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY8), }; diff --git a/libavcodec/shorten.c b/libavcodec/shorten.c index b846aa248..c0325a81f 100644 --- a/libavcodec/shorten.c +++ b/libavcodec/shorten.c @@ -816,11 +816,5 @@ const FFCodec ff_shorten_decoder = { FF_CODEC_DECODE_CB(shorten_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DELAY | -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/simple_idct.c b/libavcodec/simple_idct.c index eb13cff14..5253afc6d 100644 --- a/libavcodec/simple_idct.c +++ b/libavcodec/simple_idct.c @@ -37,11 +37,6 @@ #define BIT_DEPTH 10 #include "simple_idct_template.c" - -#define EXTRA_SHIFT 2 -#include "simple_idct_template.c" - -#undef EXTRA_SHIFT #undef BIT_DEPTH #define BIT_DEPTH 12 @@ -235,35 +230,3 @@ void ff_simple_idct44_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block) idct4col_add(dest + i, line_size, block + i); } } - -void ff_prores_idct_10(int16_t *block, const int16_t *qmat) -{ - int i; - - for (i = 0; i < 64; i++) - block[i] *= qmat[i]; - - for (i = 0; i < 8; i++) - idctRowCondDC_extrashift_10(block + i*8, 2); - - for (i = 0; i < 8; i++) { - block[i] += 8192; - idctSparseCol_extrashift_10(block + i); - } -} - -void ff_prores_idct_12(int16_t *block, const int16_t *qmat) -{ - int i; - - for (i = 0; i < 64; i++) - block[i] *= qmat[i]; - - for (i = 0; i < 8; i++) - idctRowCondDC_int16_12bit(block + i*8, 0); - - for (i = 0; i < 8; i++) { - block[i] += 8192; - idctSparseCol_int16_12bit(block + i); - } -} diff --git a/libavcodec/simple_idct.h b/libavcodec/simple_idct.h index 20578b334..a3f6cf911 100644 --- a/libavcodec/simple_idct.h +++ b/libavcodec/simple_idct.h @@ -47,14 +47,6 @@ void ff_simple_idct_put_int16_12bit(uint8_t *dest, ptrdiff_t line_size, int16_t void ff_simple_idct_add_int16_12bit(uint8_t *dest, ptrdiff_t line_size, int16_t *block); void ff_simple_idct_int16_12bit(int16_t *block); -/** - * Special version of ff_simple_idct_int16_10bit() which does dequantization - * and scales by a factor of 2 more between the two IDCTs to account - * for larger scale of input coefficients. - */ -void ff_prores_idct_10(int16_t *block, const int16_t *qmat); -void ff_prores_idct_12(int16_t *block, const int16_t *qmat); - void ff_simple_idct248_put(uint8_t *dest, ptrdiff_t line_size, int16_t *block); void ff_simple_idct84_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block); diff --git a/libavcodec/simple_idct_template.c b/libavcodec/simple_idct_template.c index 5ddd0b45a..e189ef1a8 100644 --- a/libavcodec/simple_idct_template.c +++ b/libavcodec/simple_idct_template.c @@ -28,8 +28,6 @@ /* Based upon some commented-out C code from mpeg2dec (idct_mmx.c * written by Aaron Holtzman ). */ -#include "simple_idct.h" - #include "bit_depth_template.c" #undef W1 @@ -261,6 +259,25 @@ static inline void FUNC6(idctRowCondDC)(idctin *row, int extra_shift) #ifdef EXTRA_SHIFT static inline void FUNC(idctSparseCol_extrashift)(int16_t *col) #else +static inline void FUNC6(idctSparseCol)(idctin *col) +#endif +{ + unsigned a0, a1, a2, a3, b0, b1, b2, b3; + + IDCT_COLS; + + col[0 ] = ((int)(a0 + b0) >> COL_SHIFT); + col[8 ] = ((int)(a1 + b1) >> COL_SHIFT); + col[16] = ((int)(a2 + b2) >> COL_SHIFT); + col[24] = ((int)(a3 + b3) >> COL_SHIFT); + col[32] = ((int)(a3 - b3) >> COL_SHIFT); + col[40] = ((int)(a2 - b2) >> COL_SHIFT); + col[48] = ((int)(a1 - b1) >> COL_SHIFT); + col[56] = ((int)(a0 - b0) >> COL_SHIFT); +} + +#ifndef PRORES_ONLY +#ifndef EXTRA_SHIFT static inline void FUNC6(idctSparseColPut)(pixel *dest, ptrdiff_t line_size, idctin *col) { @@ -309,24 +326,6 @@ static inline void FUNC6(idctSparseColAdd)(pixel *dest, ptrdiff_t line_size, dest[0] = av_clip_pixel(dest[0] + ((int)(a0 - b0) >> COL_SHIFT)); } -static inline void FUNC6(idctSparseCol)(idctin *col) -#endif -{ - unsigned a0, a1, a2, a3, b0, b1, b2, b3; - - IDCT_COLS; - - col[0 ] = ((int)(a0 + b0) >> COL_SHIFT); - col[8 ] = ((int)(a1 + b1) >> COL_SHIFT); - col[16] = ((int)(a2 + b2) >> COL_SHIFT); - col[24] = ((int)(a3 + b3) >> COL_SHIFT); - col[32] = ((int)(a3 - b3) >> COL_SHIFT); - col[40] = ((int)(a2 - b2) >> COL_SHIFT); - col[48] = ((int)(a1 - b1) >> COL_SHIFT); - col[56] = ((int)(a0 - b0) >> COL_SHIFT); -} - -#ifndef EXTRA_SHIFT void FUNC6(ff_simple_idct_put)(uint8_t *dest_, ptrdiff_t line_size, int16_t *block_) { idctin *block = (idctin *)block_; @@ -369,3 +368,4 @@ void FUNC6(ff_simple_idct)(int16_t *block) } #endif #endif +#endif /* PRORES_ONLY */ diff --git a/libavcodec/sipr.c b/libavcodec/sipr.c index 3ddc579f0..ebd7dab03 100644 --- a/libavcodec/sipr.c +++ b/libavcodec/sipr.c @@ -412,9 +412,9 @@ static void decode_frame(SiprContext *ctx, SiprParameters *params, convolute_with_sparse(fixed_vector, &fixed_cb, impulse_response, SUBFR_SIZE); - avg_energy = (0.01 + avpriv_scalarproduct_float_c(fixed_vector, - fixed_vector, - SUBFR_SIZE)) / + avg_energy = (0.01 + ff_scalarproduct_float_c(fixed_vector, + fixed_vector, + SUBFR_SIZE)) / SUBFR_SIZE; ctx->past_pitch_gain = pitch_gain = gain_cb[params->gc_index[i]][0]; @@ -456,9 +456,9 @@ static void decode_frame(SiprContext *ctx, SiprParameters *params, if (ctx->mode == MODE_5k0) { for (i = 0; i < subframe_count; i++) { - float energy = avpriv_scalarproduct_float_c(ctx->postfilter_syn5k0 + LP_FILTER_ORDER + i * SUBFR_SIZE, - ctx->postfilter_syn5k0 + LP_FILTER_ORDER + i * SUBFR_SIZE, - SUBFR_SIZE); + float energy = ff_scalarproduct_float_c(ctx->postfilter_syn5k0 + LP_FILTER_ORDER + i * SUBFR_SIZE, + ctx->postfilter_syn5k0 + LP_FILTER_ORDER + i * SUBFR_SIZE, + SUBFR_SIZE); ff_adaptive_gain_control(&synth[i * SUBFR_SIZE], &synth[i * SUBFR_SIZE], energy, SUBFR_SIZE, 0.9, &ctx->postfilter_agc); diff --git a/libavcodec/sipr16k.c b/libavcodec/sipr16k.c index 9c8f68400..ab892d054 100644 --- a/libavcodec/sipr16k.c +++ b/libavcodec/sipr16k.c @@ -163,11 +163,11 @@ static float acelp_decode_gain_codef(float gain_corr_factor, const float *fc_v, const float *ma_prediction_coeff, int subframe_size, int ma_pred_order) { - mr_energy += avpriv_scalarproduct_float_c(quant_energy, ma_prediction_coeff, - ma_pred_order); + mr_energy += ff_scalarproduct_float_c(quant_energy, ma_prediction_coeff, + ma_pred_order); mr_energy = gain_corr_factor * exp(M_LN10 / 20. * mr_energy) / - sqrt((0.01 + avpriv_scalarproduct_float_c(fc_v, fc_v, subframe_size))); + sqrt((0.01 + ff_scalarproduct_float_c(fc_v, fc_v, subframe_size))); return mr_energy; } diff --git a/libavcodec/sipr_parser.c b/libavcodec/sipr_parser.c index e01da3c8a..82a37c690 100644 --- a/libavcodec/sipr_parser.c +++ b/libavcodec/sipr_parser.c @@ -22,6 +22,7 @@ */ #include "parser.h" +#include "parser_internal.h" typedef struct SiprParserContext{ ParseContext pc; @@ -66,9 +67,9 @@ static int sipr_parse(AVCodecParserContext *s1, AVCodecContext *avctx, return next; } -const AVCodecParser ff_sipr_parser = { - .codec_ids = { AV_CODEC_ID_SIPR }, +const FFCodecParser ff_sipr_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_SIPR), .priv_data_size = sizeof(SiprParserContext), - .parser_parse = sipr_parse, - .parser_close = ff_parse_close, + .parse = sipr_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/smacker.c b/libavcodec/smacker.c index 1883dc3f1..e0c4dac35 100644 --- a/libavcodec/smacker.c +++ b/libavcodec/smacker.c @@ -393,11 +393,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, pal = (uint32_t*)smk->pic->data[1]; bytestream2_init(&gb2, avpkt->data, avpkt->size); flags = bytestream2_get_byteu(&gb2); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - smk->pic->palette_has_changed = flags & 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif if (flags & 2) { smk->pic->flags |= AV_FRAME_FLAG_KEY; smk->pic->pict_type = AV_PICTURE_TYPE_I; @@ -667,9 +662,13 @@ static int smka_decode_frame(AVCodecContext *avctx, AVFrame *frame, } else values[i] = h.entries[0].value; } + if (get_bits_left(&gb) < (stereo+1) * (bits+1) * 8) { + ret = AVERROR_INVALIDDATA; + goto error; + } if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) - return ret; + goto error; samples = (int16_t *)frame->data[0]; samples8 = frame->data[0]; diff --git a/libavcodec/smc.c b/libavcodec/smc.c index 3e8a89ced..673d7a5e1 100644 --- a/libavcodec/smc.c +++ b/libavcodec/smc.c @@ -437,14 +437,7 @@ static int smc_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) return ret; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif bytestream2_init(&gb, buf, buf_size); ret = smc_decode_stream(s, &gb); diff --git a/libavcodec/smcenc.c b/libavcodec/smcenc.c index f8a3322bb..dfa1c17d2 100644 --- a/libavcodec/smcenc.c +++ b/libavcodec/smcenc.c @@ -515,7 +515,7 @@ static void smc_encode_stream(SMCContext *s, const AVFrame *frame, } } -static int smc_encode_init(AVCodecContext *avctx) +static av_cold int smc_encode_init(AVCodecContext *avctx) { SMCContext *s = avctx->priv_data; @@ -580,7 +580,7 @@ static int smc_encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } -static int smc_encode_end(AVCodecContext *avctx) +static av_cold int smc_encode_end(AVCodecContext *avctx) { SMCContext *s = avctx->priv_data; @@ -599,6 +599,5 @@ const FFCodec ff_smc_encoder = { .init = smc_encode_init, FF_CODEC_ENCODE_CB(smc_encode_frame), .close = smc_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_PAL8, - AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_PAL8), }; diff --git a/libavcodec/smpte_436m.c b/libavcodec/smpte_436m.c new file mode 100644 index 000000000..b2324cac1 --- /dev/null +++ b/libavcodec/smpte_436m.c @@ -0,0 +1,475 @@ +/* + * MXF SMPTE-436M VBI/ANC parsing functions + * Copyright (c) 2025 Jacob Lifshay + * + * 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 "libavcodec/smpte_436m.h" +#include "bytestream.h" +#include "libavcodec/packet.h" +#include "libavutil/avassert.h" +#include "libavutil/error.h" +#include "libavutil/intreadwrite.h" + +static int validate_smpte_436m_anc_wrapping_type(AVSmpte436mWrappingType wrapping_type) +{ + switch (wrapping_type) { + case AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME: + case AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_1: + case AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_2: + case AV_SMPTE_436M_WRAPPING_TYPE_VANC_PROGRESSIVE_FRAME: + case AV_SMPTE_436M_WRAPPING_TYPE_HANC_FRAME: + case AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_1: + case AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_2: + case AV_SMPTE_436M_WRAPPING_TYPE_HANC_PROGRESSIVE_FRAME: + return 0; + default: + return AVERROR_INVALIDDATA; + } +} + +static int validate_smpte_436m_anc_payload_sample_coding(AVSmpte436mPayloadSampleCoding payload_sample_coding) +{ + switch (payload_sample_coding) { + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF: + // not allowed for ANC packets + return AVERROR_INVALIDDATA; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR: + return 0; + default: + return AVERROR_INVALIDDATA; + } +} + +int av_smpte_436m_coded_anc_validate(const AVSmpte436mCodedAnc *anc) +{ + int ret = validate_smpte_436m_anc_wrapping_type(anc->wrapping_type); + if (ret < 0) + return ret; + ret = validate_smpte_436m_anc_payload_sample_coding(anc->payload_sample_coding); + if (ret < 0) + return ret; + if (anc->payload_array_length > AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY) + return AVERROR_INVALIDDATA; + ret = av_smpte_436m_coded_anc_payload_size(anc->payload_sample_coding, anc->payload_sample_count); + if (ret < 0) + return ret; + if (anc->payload_array_length < ret) + return AVERROR_INVALIDDATA; + return 0; +} + +// Based off Table 7 (page 13) of: +// https://pub.smpte.org/latest/st436/s436m-2006.pdf +#define SMPTE_436M_ANC_ENTRY_HEADER_SIZE ( \ + 2 /* line_number */ \ + + 1 /* wrapping_type */ \ + + 1 /* payload_sample_coding */ \ + + 2 /* payload_sample_count */ \ + + 4 /* payload_array_length */ \ + + 4 /* payload_array_element_size */ \ +) + +/** + * Decode an ANC packet. + * @param[in] in Input bytes. + * @param[in] size the size of in. + * @param[out] anc the decoded ANC packet + * @return The number of read bytes on success, AVERROR_INVALIDDATA otherwise. + */ +static int smpte_436m_anc_decode_entry(const uint8_t *in, int size, AVSmpte436mCodedAnc *anc) +{ + // Based off Table 7 (page 13) of: + // https://pub.smpte.org/latest/st436/s436m-2006.pdf + if (SMPTE_436M_ANC_ENTRY_HEADER_SIZE > size) + return AVERROR_INVALIDDATA; + int needed_size = SMPTE_436M_ANC_ENTRY_HEADER_SIZE; + anc->line_number = AV_RB16(in); + in += 2; + anc->wrapping_type = AV_RB8(in); + in++; + anc->payload_sample_coding = AV_RB8(in); + in++; + anc->payload_sample_count = AV_RB16(in); + in += 2; + anc->payload_array_length = AV_RB32(in); + in += 4; + uint32_t payload_array_element_size = AV_RB32(in); + in += 4; + if (payload_array_element_size != 1) + return AVERROR_INVALIDDATA; + needed_size += anc->payload_array_length; + if (needed_size > size) + return AVERROR_INVALIDDATA; + if (anc->payload_array_length > AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY) + return AVERROR_INVALIDDATA; + memcpy(anc->payload, in, anc->payload_array_length); + int ret = av_smpte_436m_coded_anc_validate(anc); + if (ret < 0) + return ret; + return needed_size; +} + +/** + * Encode an ANC packet. + * @param[in] anc the ANC packet to encode + * @param[in] size the size of out. ignored if out is NULL. + * @param[out] out Output bytes. Doesn't write anything if out is NULL. + * @return the number of bytes written on success, AVERROR codes otherwise. + * If out is NULL, returns the number of bytes it would have written. + */ +static int smpte_436m_anc_encode_entry(uint8_t *out, int size, const AVSmpte436mCodedAnc *anc) +{ + // Based off Table 7 (page 13) of: + // https://pub.smpte.org/latest/st436/s436m-2006.pdf + if (anc->payload_array_length > AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY) + return AVERROR_INVALIDDATA; + int needed_size = SMPTE_436M_ANC_ENTRY_HEADER_SIZE + (int)anc->payload_array_length; + if (!out) + return needed_size; + if (needed_size > size) + return AVERROR_BUFFER_TOO_SMALL; + AV_WB16(out, anc->line_number); + out += 2; + AV_WB8(out, anc->wrapping_type); + out++; + AV_WB8(out, anc->payload_sample_coding); + out++; + AV_WB16(out, anc->payload_sample_count); + out += 2; + AV_WB32(out, anc->payload_array_length); + out += 4; + AV_WB32(out, 1); // payload_array_element_size + out += 4; + memcpy(out, anc->payload, anc->payload_array_length); + return needed_size; +} + +int av_smpte_436m_anc_encode(uint8_t *out, int size, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets) +{ + // Based off Table 7 (page 13) of: + // https://pub.smpte.org/latest/st436/s436m-2006.pdf + if (anc_packet_count < 0 || anc_packet_count >= (1L << 16) || size < 0) + return AVERROR_INVALIDDATA; + + int needed_size = 2; + if (out) { + if (size < needed_size) + return AVERROR_BUFFER_TOO_SMALL; + AV_WB16(out, anc_packet_count); + out += 2; + size -= 2; + } + for (int i = 0; i < anc_packet_count; i++) { + int ret = smpte_436m_anc_encode_entry(out, size, &anc_packets[i]); + if (ret < 0) + return ret; + needed_size += ret; + if (out) { + size -= ret; + out += ret; + } + } + return needed_size; +} + +int av_smpte_436m_anc_append(AVPacket *pkt, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets) +{ + int final_packet_count = 0; + int write_start = 2; + if (pkt->size >= 2) { + final_packet_count = AV_RB16(pkt->data); + write_start = pkt->size; + } else if (pkt->size != 0) // if packet isn't empty + return AVERROR_INVALIDDATA; + if (anc_packet_count < 0 || anc_packet_count >= (1L << 16)) + return AVERROR_INVALIDDATA; + final_packet_count += anc_packet_count; + if (final_packet_count >= (1L << 16)) + return AVERROR_INVALIDDATA; + int ret, additional_size = write_start - pkt->size; + for (int i = 0; i < anc_packet_count; i++) { + ret = smpte_436m_anc_encode_entry(NULL, 0, &anc_packets[i]); + if (ret < 0) + return ret; + additional_size += ret; + } + ret = av_grow_packet(pkt, additional_size); + if (ret < 0) + return ret; + for (int i = 0; i < anc_packet_count; i++) { + ret = smpte_436m_anc_encode_entry(pkt->data + write_start, pkt->size - write_start, &anc_packets[i]); + av_assert0(ret >= 0); + write_start += ret; + } + AV_WB16(pkt->data, final_packet_count); + return 0; +} + +int av_smpte_436m_anc_iter_init(AVSmpte436mAncIterator *iter, const uint8_t *buf, int buf_size) +{ + // Based off Table 7 (page 13) of: + // https://pub.smpte.org/latest/st436/s436m-2006.pdf + if (buf_size < 2) + return AVERROR_INVALIDDATA; + *iter = (AVSmpte436mAncIterator){ + .anc_packets_left = AV_RB16(buf), + .size_left = buf_size - 2, + .data_left = buf + 2, + }; + if (iter->anc_packets_left > iter->size_left) + return AVERROR_INVALIDDATA; + return 0; +} + +int av_smpte_436m_anc_iter_next(AVSmpte436mAncIterator *iter, AVSmpte436mCodedAnc *anc) +{ + if (iter->anc_packets_left <= 0) + return AVERROR_EOF; + iter->anc_packets_left--; + int ret = smpte_436m_anc_decode_entry(iter->data_left, iter->size_left, anc); + if (ret < 0) { + iter->anc_packets_left = 0; + return ret; + } + iter->data_left += ret; + iter->size_left -= ret; + return 0; +} + +int av_smpte_436m_coded_anc_payload_size(AVSmpte436mPayloadSampleCoding sample_coding, uint16_t sample_count) +{ + if (sample_count > AV_SMPTE_436M_CODED_ANC_SAMPLE_CAPACITY) + return AVERROR_INVALIDDATA; + switch (sample_coding) { + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF: + return AVERROR_INVALIDDATA; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR: + // "The Payload Byte Array shall be padded to achieve UInt32 alignment." + // section 4.4 of https://pub.smpte.org/latest/st436/s436m-2006.pdf + return (sample_count + 3) & -4; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF: + // encoded with 3 10-bit samples in a UInt32. + // "The Payload Byte Array shall be padded to achieve UInt32 alignment." + // section 4.4 of https://pub.smpte.org/latest/st436/s436m-2006.pdf + return 4 * ((sample_count + 2) / 3); + default: + return AVERROR_INVALIDDATA; + } +} + +int av_smpte_291m_anc_8bit_decode(AVSmpte291mAnc8bit *out, + AVSmpte436mPayloadSampleCoding sample_coding, + uint16_t sample_count, + const uint8_t *payload, + void *log_ctx) +{ + switch (sample_coding) { + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF: + return AVERROR_INVALIDDATA; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR: + { + if (sample_count < 3) + return AVERROR_INVALIDDATA; + out->did = *payload++; + out->sdid_or_dbn = *payload++; + out->data_count = *payload++; + if (sample_count < out->data_count + 3) + return AVERROR_INVALIDDATA; + memcpy(out->payload, payload, out->data_count); + // the checksum isn't stored in 8-bit mode, so calculate it. + av_smpte_291m_anc_8bit_fill_checksum(out); + return 0; + } + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF: + av_log(log_ctx, + AV_LOG_ERROR, + "decoding an ANC packet using the 10-bit SMPTE 436M sample coding isn't implemented.\n"); + return AVERROR_PATCHWELCOME; + default: + return AVERROR_INVALIDDATA; + } +} + +void av_smpte_291m_anc_8bit_fill_checksum(AVSmpte291mAnc8bit *anc) +{ + uint8_t checksum = anc->did + anc->sdid_or_dbn + anc->data_count; + for (unsigned i = 0; i < anc->data_count; i++) { + checksum += anc->payload[i]; + } + anc->checksum = checksum; +} + +int av_smpte_291m_anc_8bit_get_sample_count(const AVSmpte291mAnc8bit *anc, + AVSmpte436mPayloadSampleCoding sample_coding, + void *log_ctx) +{ + switch (sample_coding) { + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF: + return AVERROR_INVALIDDATA; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR: + // 3 for did, sdid_or_dbn, and data_count; checksum isn't stored in 8-bit modes + return 3 + anc->data_count; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF: + av_log(log_ctx, + AV_LOG_ERROR, + "encoding an ANC packet using the 10-bit SMPTE 436M sample coding isn't implemented.\n"); + return AVERROR_PATCHWELCOME; + default: + return AVERROR_INVALIDDATA; + } +} + +int av_smpte_291m_anc_8bit_encode(AVSmpte436mCodedAnc *out, + uint16_t line_number, + AVSmpte436mWrappingType wrapping_type, + AVSmpte436mPayloadSampleCoding sample_coding, + const AVSmpte291mAnc8bit *payload, + void *log_ctx) +{ + out->line_number = line_number; + out->wrapping_type = wrapping_type; + out->payload_sample_coding = sample_coding; + + int ret = av_smpte_291m_anc_8bit_get_sample_count(payload, sample_coding, log_ctx); + if (ret < 0) + return ret; + + out->payload_sample_count = ret; + + ret = av_smpte_436m_coded_anc_payload_size(sample_coding, out->payload_sample_count); + if (ret < 0) + return ret; + + out->payload_array_length = ret; + + switch (sample_coding) { + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF: + return AVERROR_INVALIDDATA; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR: + { + // fill trailing padding with zeros + av_assert0(out->payload_array_length >= 4); + memset(out->payload + out->payload_array_length - 4, 0, 4); + + out->payload[0] = payload->did; + out->payload[1] = payload->sdid_or_dbn; + out->payload[2] = payload->data_count; + + memcpy(out->payload + 3, payload->payload, payload->data_count); + return 0; + } + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF: + av_log(log_ctx, + AV_LOG_ERROR, + "encoding an ANC packet using the 10-bit SMPTE 436M sample coding isn't implemented.\n"); + return AVERROR_PATCHWELCOME; + default: + return AVERROR_INVALIDDATA; + } +} + +int av_smpte_291m_anc_8bit_extract_cta_708(const AVSmpte291mAnc8bit *anc, uint8_t *cc_data, void *log_ctx) +{ + if (anc->did != AV_SMPTE_291M_ANC_DID_CTA_708 || anc->sdid_or_dbn != AV_SMPTE_291M_ANC_SDID_CTA_708) + return AVERROR(EAGAIN); + GetByteContext gb; + bytestream2_init(&gb, anc->payload, anc->data_count); + // based on Caption Distribution Packet (CDP) Definition: + // https://pub.smpte.org/latest/st334-2/st0334-2-2015.pdf + uint16_t cdp_identifier = bytestream2_get_be16(&gb); + if (cdp_identifier != 0x9669) { // CDPs always have this value + av_log(log_ctx, AV_LOG_ERROR, "wrong cdp identifier %x\n", cdp_identifier); + return AVERROR_INVALIDDATA; + } + bytestream2_get_byte(&gb); // cdp_length + bytestream2_get_byte(&gb); // cdp_frame_rate and reserved + bytestream2_get_byte(&gb); // flags + bytestream2_get_be16(&gb); // cdp_hdr_sequence_cntr + unsigned section_id = bytestream2_get_byte(&gb); + + const unsigned TIME_CODE_SECTION_ID = 0x71; + if (section_id == TIME_CODE_SECTION_ID) { + bytestream2_skip(&gb, 4); // skip time code section + section_id = bytestream2_get_byte(&gb); + } + const unsigned CC_DATA_SECTION_ID = 0x72; + if (section_id == CC_DATA_SECTION_ID) { + if (bytestream2_get_bytes_left(&gb) < 1) + goto too_short; + // 0x1F for lower 5 bits, upper 3 bits are marker bits + unsigned cc_count = bytestream2_get_byte(&gb) & 0x1F; + unsigned data_length = cc_count * 3; // EIA-608/CTA-708 triples are 3 bytes long + if (bytestream2_get_bytes_left(&gb) < data_length) + goto too_short; + if (cc_data) + bytestream2_get_bufferu(&gb, cc_data, data_length); + return cc_count; + } + return AVERROR(EAGAIN); + +too_short: + av_log(log_ctx, AV_LOG_ERROR, "not enough bytes in cdp\n"); + return AVERROR_INVALIDDATA; +} diff --git a/libavcodec/smpte_436m.h b/libavcodec/smpte_436m.h new file mode 100644 index 000000000..9c0e2a5a0 --- /dev/null +++ b/libavcodec/smpte_436m.h @@ -0,0 +1,254 @@ +/* + * MXF SMPTE-436M VBI/ANC parsing functions + * Copyright (c) 2025 Jacob Lifshay + * + * 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_SMPTE_436M_H +#define AVCODEC_SMPTE_436M_H + +#include + +/** + * Iterator over the ANC packets in a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data + */ +typedef struct AVSmpte436mAncIterator { + uint16_t anc_packets_left; + int size_left; + const uint8_t *data_left; +} AVSmpte436mAncIterator; + +/** + * Wrapping Type from Table 7 (page 13) of: + * https://pub.smpte.org/latest/st436/s436m-2006.pdf + */ +typedef enum AVSmpte436mWrappingType +{ + AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME = 1, + AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_1 = 2, + AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_2 = 3, + AV_SMPTE_436M_WRAPPING_TYPE_VANC_PROGRESSIVE_FRAME = 4, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_FRAME = 0x11, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_1 = 0x12, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_2 = 0x13, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_PROGRESSIVE_FRAME = 0x14, + /** not a real wrapping type, just here to guarantee the enum is big enough */ + AV_SMPTE_436M_WRAPPING_TYPE_MAX = 0xFF, +} AVSmpte436mWrappingType; + +/** + * Payload Sample Coding from Table 4 (page 10) and Table 7 (page 13) of: + * https://pub.smpte.org/latest/st436/s436m-2006.pdf + */ +typedef enum AVSmpte436mPayloadSampleCoding +{ + /** only used for VBI */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA = 1, + /** only used for VBI */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF = 2, + /** only used for VBI */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF = 3, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA = 4, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF = 5, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF = 6, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA = 7, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF = 8, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF = 9, + /** only used for ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR = 10, + /** only used for ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR = 11, + /** only used for ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR = 12, + /** not a real sample coding, just here to guarantee the enum is big enough */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_MAX = 0xFF, +} AVSmpte436mPayloadSampleCoding; + +/** the payload capacity of AVSmpte291mAnc8bit (and of AVSmpte291mAnc10bit when that gets added) */ +#define AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY 0xFF + +/** + * An ANC packet with an 8-bit payload. + * This can be decoded from AVSmpte436mCodedAnc::payload. + * + * Note: Some ANC packets need a 10-bit payload, if stored in this struct, + * the most-significant 2 bits of each sample are discarded. + */ +typedef struct AVSmpte291mAnc8bit { + uint8_t did; + uint8_t sdid_or_dbn; + uint8_t data_count; + uint8_t payload[AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY]; + uint8_t checksum; +} AVSmpte291mAnc8bit; + +/** max number of samples that can be stored in the payload of AVSmpte436mCodedAnc */ +#define AV_SMPTE_436M_CODED_ANC_SAMPLE_CAPACITY \ + (AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY + 4) /* 4 for did, sdid_or_dbn, data_count, and checksum */ +/** max number of bytes that can be stored in the payload of AVSmpte436mCodedAnc */ +#define AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY (((AV_SMPTE_436M_CODED_ANC_SAMPLE_CAPACITY + 2) / 3) * 4) + +/** + * An encoded ANC packet within a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * The repeated section of Table 7 (page 13) of: + * https://pub.smpte.org/latest/st436/s436m-2006.pdf + */ +typedef struct AVSmpte436mCodedAnc { + uint16_t line_number; + AVSmpte436mWrappingType wrapping_type; + AVSmpte436mPayloadSampleCoding payload_sample_coding; + uint16_t payload_sample_count; + uint32_t payload_array_length; + /** the payload, has size payload_array_length. + * can be decoded into AVSmpte291mAnc8bit + */ + uint8_t payload[AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY]; +} AVSmpte436mCodedAnc; + +/** + * Validate a AVSmpte436mCodedAnc structure. Doesn't check if the payload is valid. + * @param[in] anc ANC packet to validate + * @return 0 on success, AVERROR codes otherwise. + */ +int av_smpte_436m_coded_anc_validate(const AVSmpte436mCodedAnc *anc); + +/** + * Encode ANC packets into a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * @param[in] anc_packet_count number of ANC packets to encode + * @param[in] anc_packets the ANC packets to encode + * @param[in] size the size of out. ignored if out is NULL. + * @param[out] out Output bytes. Doesn't write anything if out is NULL. + * @return the number of bytes written on success, AVERROR codes otherwise. + * If out is NULL, returns the number of bytes it would have written. + */ +int av_smpte_436m_anc_encode(uint8_t *out, int size, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets); + +struct AVPacket; + +/** + * Append more ANC packets to a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * @param[in] anc_packet_count number of ANC packets to encode + * @param[in] anc_packets the ANC packets to encode + * @param pkt the AVPacket to append to. + * it must either be size 0 or contain valid SMPTE_436M_ANC data. + * @return 0 on success, AVERROR codes otherwise. + */ +int av_smpte_436m_anc_append(struct AVPacket *pkt, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets); + +/** + * Set up iteration over the ANC packets in a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * @param[in] buf Pointer to the data from a AV_CODEC_ID_SMPTE_436M_ANC AVPacket. + * @param[in] buf_size Size of the data from a AV_CODEC_ID_SMPTE_436M_ANC AVPacket. + * @param[out] iter Pointer to the iterator. + * @return 0 on success, AVERROR codes otherwise. + */ +int av_smpte_436m_anc_iter_init(AVSmpte436mAncIterator *iter, const uint8_t *buf, int buf_size); + +/** + * Get the next ANC packet from the iterator, advancing the iterator. + * @param[in,out] iter Pointer to the iterator. + * @param[out] anc The returned ANC packet. + * @return 0 on success, AVERROR_EOF when the iterator has reached the end, AVERROR codes otherwise. + */ +int av_smpte_436m_anc_iter_next(AVSmpte436mAncIterator *iter, AVSmpte436mCodedAnc *anc); + +/** + * Get the minimum number of bytes needed to store a AVSmpte436mCodedAnc payload. + * @param sample_coding the payload sample coding + * @param sample_count the number of samples stored in the payload + * @return returns the minimum number of bytes needed, on error returns < 0. + * always <= SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY + */ +int av_smpte_436m_coded_anc_payload_size(AVSmpte436mPayloadSampleCoding sample_coding, uint16_t sample_count); + +/** + * Decode a AVSmpte436mCodedAnc payload into AVSmpte291mAnc8bit + * @param[in] sample_coding the payload sample coding + * @param[in] sample_count the number of samples stored in the payload + * @param[in] payload the bytes storing the payload, + * the needed size can be obtained from + avpriv_smpte_436m_coded_anc_payload_size + * @param[in] log_ctx context pointer for av_log + * @param[out] out The decoded ANC packet. + * @return returns 0 on success, otherwise < 0. + */ +int av_smpte_291m_anc_8bit_decode(AVSmpte291mAnc8bit *out, + AVSmpte436mPayloadSampleCoding sample_coding, + uint16_t sample_count, + const uint8_t *payload, + void *log_ctx); + +/** + * Fill in the correct checksum for a AVSmpte291mAnc8bit + * @param[in,out] anc The ANC packet. + */ +void av_smpte_291m_anc_8bit_fill_checksum(AVSmpte291mAnc8bit *anc); + +/** + * Compute the sample count needed to encode a AVSmpte291mAnc8bit into a AVSmpte436mCodedAnc payload + * @param[in] anc The ANC packet. + * @param[in] sample_coding The sample coding. + * @param[in] log_ctx context pointer for av_log + * @return returns the sample count on success, otherwise < 0. + */ +int av_smpte_291m_anc_8bit_get_sample_count(const AVSmpte291mAnc8bit *anc, + AVSmpte436mPayloadSampleCoding sample_coding, + void *log_ctx); + +/** + * Encode a AVSmpte291mAnc8bit into a AVSmpte436mCodedAnc + * @param[in] line_number the line number the ANC packet is on + * @param[in] wrapping_type the wrapping type + * @param[in] sample_coding the payload sample coding + * @param[in] payload the ANC packet to encode. + * @param[in] log_ctx context pointer for av_log + * @param[out] out The encoded ANC packet. + * @return returns 0 on success, otherwise < 0. + */ +int av_smpte_291m_anc_8bit_encode(AVSmpte436mCodedAnc *out, + uint16_t line_number, + AVSmpte436mWrappingType wrapping_type, + AVSmpte436mPayloadSampleCoding sample_coding, + const AVSmpte291mAnc8bit *payload, + void *log_ctx); + +/** AVSmpte291mAnc8bit::did when carrying CTA-708 data (for AV_CODEC_ID_EIA_608) */ +#define AV_SMPTE_291M_ANC_DID_CTA_708 0x61 + +/** AVSmpte291mAnc8bit::sdid_or_dbn when carrying CTA-708 data (for AV_CODEC_ID_EIA_608) */ +#define AV_SMPTE_291M_ANC_SDID_CTA_708 0x1 + +/** + * Try to decode an ANC packet into EIA-608/CTA-708 data (AV_CODEC_ID_EIA_608). This + * @param[in] anc The ANC packet. + * @param[in] log_ctx Context pointer for av_log + * @param[out] cc_data the buffer to store the extracted EIA-608/CTA-708 data, + * you can pass NULL to not store the data. + * the required size is 3 * cc_count bytes. + * SMPTE_291M_ANC_PAYLOAD_CAPACITY is always enough size. + * @return returns cc_count (>= 0) on success, AVERROR(EAGAIN) if it wasn't a CTA-708 ANC packet, < 0 on error. + */ +int av_smpte_291m_anc_8bit_extract_cta_708(const AVSmpte291mAnc8bit *anc, uint8_t *cc_data, void *log_ctx); + +#endif /* AVCODEC_SMPTE_436M_H */ diff --git a/libavcodec/smpte_436m_internal.h b/libavcodec/smpte_436m_internal.h new file mode 100644 index 000000000..7481949fb --- /dev/null +++ b/libavcodec/smpte_436m_internal.h @@ -0,0 +1,98 @@ +/* + * MXF SMPTE-436M VBI/ANC internals + * Copyright (c) 2025 Jacob Lifshay + * + * 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_SMPTE_436M_INTERNAL_H +#define AVCODEC_SMPTE_436M_INTERNAL_H + +#include "smpte_436m.h" + +// clang-format off +#define FF_SMPTE_436M_WRAPPING_TYPE_VANC_AVOPTIONS(flags, unit_name) \ + { "vanc_frame", "VANC frame (interlaced or segmented progressive frame)", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME}, 0, 0xFF, flags, .unit = unit_name }, \ + { "vanc_field_1", "VANC field 1", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_1}, 0, 0xFF, flags, .unit = unit_name }, \ + { "vanc_field_2", "VANC field 2", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_2}, 0, 0xFF, flags, .unit = unit_name }, \ + { "vanc_progressive_frame", "VANC progressive frame", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_VANC_PROGRESSIVE_FRAME}, 0, 0xFF, flags, .unit = unit_name } + +#define FF_SMPTE_436M_WRAPPING_TYPE_HANC_AVOPTIONS(flags, unit_name) \ + { "hanc_frame", "HANC frame (interlaced or segmented progressive frame)", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_HANC_FRAME}, 0, 0xFF, flags, .unit = unit_name }, \ + { "hanc_field_1", "HANC field 1", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_1}, 0, 0xFF, flags, .unit = unit_name }, \ + { "hanc_field_2", "HANC field 2", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_2}, 0, 0xFF, flags, .unit = unit_name }, \ + { "hanc_progressive_frame", "HANC progressive frame", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_HANC_PROGRESSIVE_FRAME}, 0, 0xFF, flags, .unit = unit_name } + +#define FF_SMPTE_436M_WRAPPING_TYPE_AVOPTIONS(flags, unit_name) \ + FF_SMPTE_436M_WRAPPING_TYPE_VANC_AVOPTIONS(flags, unit_name), \ + FF_SMPTE_436M_WRAPPING_TYPE_HANC_AVOPTIONS(flags, unit_name) +// clang-format on + +// clang-format off +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_VBI_AVOPTIONS(flags, unit_name) \ + { "1bit_luma", "1-bit component luma samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA}, 0, 0xFF, flags, .unit = unit_name }, \ + { "1bit_color_diff", "1-bit component color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name }, \ + { "1bit_luma_and_color_diff", "1-bit component luma and color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name } + +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_SHARED_AVOPTIONS(flags, unit_name) \ + { "8bit_luma", "8-bit component luma samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA}, 0, 0xFF, flags, .unit = unit_name }, \ + { "8bit_color_diff", "8-bit component color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name }, \ + { "8bit_luma_and_color_diff", "8-bit component luma and color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name }, \ + { "10bit_luma", "10-bit component luma samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA}, 0, 0xFF, flags, .unit = unit_name }, \ + { "10bit_color_diff", "10-bit component color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name }, \ + { "10bit_luma_and_color_diff", "10-bit component luma and color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name } + +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_ANC_AVOPTIONS(flags, unit_name) \ + { "8bit_luma_parity_error", "8-bit component luma samples with parity error", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR}, 0, 0xFF, flags, .unit = unit_name }, \ + { "8bit_color_diff_parity_error", "8-bit component color difference samples with parity error", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR}, 0, 0xFF, flags, .unit = unit_name }, \ + { "8bit_luma_and_color_diff_parity_error", "8-bit component luma and color difference samples with parity error", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR}, 0, 0xFF, flags, .unit = unit_name } + +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_VBI_AVOPTIONS(flags, unit_name) \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_VBI_AVOPTIONS(flags, unit_name), \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_SHARED_AVOPTIONS(flags, unit_name) + +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ANC_AVOPTIONS(flags, unit_name) \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_SHARED_AVOPTIONS(flags, unit_name), \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_ANC_AVOPTIONS(flags, unit_name) + +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_AVOPTIONS(flags, unit_name) \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_VBI_AVOPTIONS(flags, unit_name), \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_SHARED_AVOPTIONS(flags, unit_name), \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_ANC_AVOPTIONS(flags, unit_name) +// clang-format on + +#endif /* AVCODEC_SMPTE_436M_INTERNAL_H */ diff --git a/libavcodec/snow.c b/libavcodec/snow.c index af6214d07..b2850356e 100644 --- a/libavcodec/snow.c +++ b/libavcodec/snow.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "libavutil/log.h" #include "libavutil/mem.h" #include "libavutil/thread.h" @@ -26,6 +28,91 @@ #include "snow.h" #include "snowdata.h" +#define pixeltmp int16_t +#define BIT_DEPTH 8 +#define SNOW +#include "h264qpel_template.c" + +static void put_snow_qpel2_h_lowpass_8(uint8_t *dst, const uint8_t *restrict src, int dstStride, int srcStride) +{ + const int h = 2; + for (int i = 0; i < h; ++i) { + dst[0] = av_clip_uint8(((src[0]+src[1])*20 - (src[-1]+src[2])*5 + (src[-2]+src[3]) + 16) >> 5); + dst[1] = av_clip_uint8(((src[1]+src[2])*20 - (src[0 ]+src[3])*5 + (src[-1]+src[4]) + 16) >> 5); + dst += dstStride; + src += srcStride; + } +} + +static void put_snow_qpel2_v_lowpass_8(uint8_t *dst, const uint8_t *restrict src, int dstStride, int srcStride) +{ + const int w = 2; + for (int i = 0; i < w; ++i) { + const int srcB = src[-2*srcStride]; + const int srcA = src[-1*srcStride]; + const int src0 = src[0 *srcStride]; + const int src1 = src[1 *srcStride]; + const int src2 = src[2 *srcStride]; + const int src3 = src[3 *srcStride]; + const int src4 = src[4 *srcStride]; + dst[0*dstStride] = av_clip_uint8(((src0+src1)*20 - (srcA+src2)*5 + (srcB+src3) + 16) >> 5); + dst[1*dstStride] = av_clip_uint8(((src1+src2)*20 - (src0+src3)*5 + (srcA+src4) + 16) >> 5); + dst++; + src++; + } +} + +static void put_snow_qpel2_hv_lowpass_8(uint8_t *dst, pixeltmp *tmp, const uint8_t *restrict src, int dstStride, int tmpStride, int srcStride) +{ + const int h = 2; + const int w = 2; + src -= 2*srcStride; + for (int i = 0; i < h + 5; ++i) { + tmp[0] = (src[0]+src[1])*20 - (src[-1]+src[2])*5 + (src[-2]+src[3]); + tmp[1] = (src[1]+src[2])*20 - (src[0 ]+src[3])*5 + (src[-1]+src[4]); + tmp += tmpStride; + src += srcStride; + } + tmp -= tmpStride*(h+5-2); + for (int i = 0; i < w; ++i) { + const int tmpB = tmp[-2*tmpStride]; + const int tmpA = tmp[-1*tmpStride]; + const int tmp0 = tmp[0 *tmpStride]; + const int tmp1 = tmp[1 *tmpStride]; + const int tmp2 = tmp[2 *tmpStride]; + const int tmp3 = tmp[3 *tmpStride]; + const int tmp4 = tmp[4 *tmpStride]; + dst[0*dstStride] = av_clip_uint8(((tmp0+tmp1)*20 - (tmpA+tmp2)*5 + (tmpB+tmp3) + 512) >> 10); + dst[1*dstStride] = av_clip_uint8(((tmp1+tmp2)*20 - (tmp0+tmp3)*5 + (tmpA+tmp4) + 512) >> 10); + dst++; + tmp++; + } +} + +H264_MC(put_, snow, 2) + +static av_cold void init_qpel(SnowContext *const s) +{ + static_assert(offsetof(H264QpelContext, put_h264_qpel_pixels_tab) == 0, + "put_h264_qpel_pixels_tab not at start of H264QpelContext"); + ff_h264qpel_init(&s->h264qpel, 8); + s->put_snow_qpel_pixels_tab[3][0] = put_snow_qpel2_mc00_8_c; + s->put_snow_qpel_pixels_tab[3][1] = put_snow_qpel2_mc10_8_c; + s->put_snow_qpel_pixels_tab[3][2] = put_snow_qpel2_mc20_8_c; + s->put_snow_qpel_pixels_tab[3][3] = put_snow_qpel2_mc30_8_c; + s->put_snow_qpel_pixels_tab[3][4] = put_snow_qpel2_mc01_8_c; + s->put_snow_qpel_pixels_tab[3][5] = put_snow_qpel2_mc11_8_c; + s->put_snow_qpel_pixels_tab[3][6] = put_snow_qpel2_mc21_8_c; + s->put_snow_qpel_pixels_tab[3][7] = put_snow_qpel2_mc31_8_c; + s->put_snow_qpel_pixels_tab[3][8] = put_snow_qpel2_mc02_8_c; + s->put_snow_qpel_pixels_tab[3][9] = put_snow_qpel2_mc12_8_c; + s->put_snow_qpel_pixels_tab[3][10] = put_snow_qpel2_mc22_8_c; + s->put_snow_qpel_pixels_tab[3][11] = put_snow_qpel2_mc32_8_c; + s->put_snow_qpel_pixels_tab[3][12] = put_snow_qpel2_mc03_8_c; + s->put_snow_qpel_pixels_tab[3][13] = put_snow_qpel2_mc13_8_c; + s->put_snow_qpel_pixels_tab[3][14] = put_snow_qpel2_mc23_8_c; + s->put_snow_qpel_pixels_tab[3][15] = put_snow_qpel2_mc33_8_c; +} void ff_snow_inner_add_yblock(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h, int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8){ @@ -354,18 +441,18 @@ void ff_snow_pred_block(SnowContext *s, uint8_t *dst, uint8_t *tmp, ptrdiff_t st else if(b_w==32){ int y; for(y=0; yh264qpel.put_h264_qpel_pixels_tab[0][dy+(dx>>2)](dst + y*stride, src + 3 + (y+3)*stride,stride); - s->h264qpel.put_h264_qpel_pixels_tab[0][dy+(dx>>2)](dst + 16 + y*stride, src + 19 + (y+3)*stride,stride); + s->put_snow_qpel_pixels_tab[0][dy+(dx>>2)](dst + y*stride, src + 3 + (y+3)*stride,stride); + s->put_snow_qpel_pixels_tab[0][dy+(dx>>2)](dst + 16 + y*stride, src + 19 + (y+3)*stride,stride); } }else if(b_w==b_h) - s->h264qpel.put_h264_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst,src + 3 + 3*stride,stride); + s->put_snow_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst,src + 3 + 3*stride,stride); else if(b_w==2*b_h){ - s->h264qpel.put_h264_qpel_pixels_tab[tab_index+1][dy+(dx>>2)](dst ,src + 3 + 3*stride,stride); - s->h264qpel.put_h264_qpel_pixels_tab[tab_index+1][dy+(dx>>2)](dst+b_h,src + 3 + b_h + 3*stride,stride); + s->put_snow_qpel_pixels_tab[tab_index+1][dy+(dx>>2)](dst ,src + 3 + 3*stride,stride); + s->put_snow_qpel_pixels_tab[tab_index+1][dy+(dx>>2)](dst+b_h,src + 3 + b_h + 3*stride,stride); }else{ av_assert2(2*b_w==b_h); - s->h264qpel.put_h264_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst ,src + 3 + 3*stride ,stride); - s->h264qpel.put_h264_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst+b_w*stride,src + 3 + 3*stride+b_w*stride,stride); + s->put_snow_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst ,src + 3 + 3*stride ,stride); + s->put_snow_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst+b_w*stride,src + 3 + 3*stride+b_w*stride,stride); } } } @@ -404,7 +491,8 @@ av_cold int ff_snow_common_init(AVCodecContext *avctx){ ff_videodsp_init(&s->vdsp, 8); ff_dwt_init(&s->dwt); - ff_h264qpel_init(&s->h264qpel, 8); + + init_qpel(s); #define mcfh(dx,dy)\ s->hdsp.put_pixels_tab [0][dy/4+dx/8]=\ @@ -452,10 +540,7 @@ int ff_snow_common_init_after_header(AVCodecContext *avctx) { int plane_index, level, orientation; if(!s->scratchbuf) { - int emu_buf_size; - emu_buf_size = FFMAX(s->mconly_picture->linesize[0], 2*avctx->width+256) * (2 * MB_SIZE + HTAPS_MAX - 1); - if (!FF_ALLOCZ_TYPED_ARRAY(s->scratchbuf, FFMAX(s->mconly_picture->linesize[0], 2*avctx->width+256) * 7 * MB_SIZE) || - !FF_ALLOCZ_TYPED_ARRAY(s->emu_edge_buffer, emu_buf_size)) + if (!FF_ALLOCZ_TYPED_ARRAY(s->scratchbuf, FFMAX(s->current_picture->linesize[0], 2*avctx->width+256) * 7 * MB_SIZE)) return AVERROR(ENOMEM); } @@ -511,27 +596,18 @@ int ff_snow_common_init_after_header(AVCodecContext *avctx) { return 0; } -void ff_snow_release_buffer(AVCodecContext *avctx) -{ - SnowContext *s = avctx->priv_data; - - if(s->last_picture[s->max_ref_frames-1]->data[0]){ - av_frame_unref(s->last_picture[s->max_ref_frames-1]); - } -} - int ff_snow_frames_prepare(SnowContext *s) { AVFrame *tmp; - ff_snow_release_buffer(s->avctx); - tmp= s->last_picture[s->max_ref_frames-1]; for (int i = s->max_ref_frames - 1; i > 0; i--) s->last_picture[i] = s->last_picture[i-1]; s->last_picture[0] = s->current_picture; s->current_picture = tmp; + av_frame_unref(s->current_picture); + if(s->keyframe){ s->ref_frames= 0; s->current_picture->flags |= AV_FRAME_FLAG_KEY; @@ -563,12 +639,8 @@ av_cold void ff_snow_common_end(SnowContext *s) av_freep(&s->block); av_freep(&s->scratchbuf); - av_freep(&s->emu_edge_buffer); for(i=0; ilast_picture[i] && s->last_picture[i]->data[0]) { - av_assert0(s->last_picture[i]->data[0] != s->current_picture->data[0]); - } av_frame_free(&s->last_picture[i]); } diff --git a/libavcodec/snow.h b/libavcodec/snow.h index a5e2c138c..f8f45b876 100644 --- a/libavcodec/snow.h +++ b/libavcodec/snow.h @@ -92,7 +92,7 @@ typedef struct SubBand{ int stride_line; ///< Stride measured in lines, not pixels. x_and_coeff * x_coeff; struct SubBand *parent; - uint8_t state[/*7*2*/ 7 + 512][32]; + uint8_t state[34][32]; }SubBand; typedef struct Plane{ @@ -116,7 +116,11 @@ typedef struct SnowContext{ RangeCoder c; HpelDSPContext hdsp; VideoDSPContext vdsp; - H264QpelContext h264qpel; + union { + /// everything except size 2 are from H.264 + qpel_mc_func put_snow_qpel_pixels_tab[4][16]; + H264QpelContext h264qpel; + }; SnowDWTContext dwt; AVFrame *input_picture; ///< new_picture with the internal linesizes AVFrame *current_picture; @@ -164,7 +168,6 @@ typedef struct SnowContext{ slice_buffer sb; uint8_t *scratchbuf; - uint8_t *emu_edge_buffer; AVMotionVector *avmv; unsigned avmv_size; @@ -181,7 +184,6 @@ extern int ff_scale_mv_ref[MAX_REF_FRAMES][MAX_REF_FRAMES]; int ff_snow_common_init(AVCodecContext *avctx); int ff_snow_common_init_after_header(AVCodecContext *avctx); void ff_snow_common_end(SnowContext *s); -void ff_snow_release_buffer(AVCodecContext *avctx); void ff_snow_reset_contexts(SnowContext *s); int ff_snow_alloc_blocks(SnowContext *s); int ff_snow_frames_prepare(SnowContext *s); @@ -273,7 +275,8 @@ static av_always_inline void add_yblock(SnowContext *s, int sliced, slice_buffer if(!sliced && offset_dst) dst += src_x + src_y*dst_stride; - dst8+= src_x + src_y*src_stride; + if (sliced || add) + dst8+= src_x + src_y*src_stride; // src += src_x + src_y*src_stride; ptmp= tmp + 3*tmp_step; diff --git a/libavcodec/snow_dwt.c b/libavcodec/snow_dwt.c index 26a8b9adc..eb4d1e4d3 100644 --- a/libavcodec/snow_dwt.c +++ b/libavcodec/snow_dwt.c @@ -741,7 +741,7 @@ void ff_spatial_idwt(IDWTELEM *buffer, IDWTELEM *temp, int width, int height, decomposition_count, y); } -static inline int w_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, +static inline int w_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int w, int h, int type) { int s, i, j; @@ -810,32 +810,32 @@ static inline int w_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8 return s >> 9; } -static int w53_8_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +static int w53_8_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 8, h, 1); } -static int w97_8_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +static int w97_8_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 8, h, 0); } -static int w53_16_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +static int w53_16_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 16, h, 1); } -static int w97_16_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +static int w97_16_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 16, h, 0); } -int ff_w53_32_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +int ff_w53_32_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 32, h, 1); } -int ff_w97_32_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +int ff_w97_32_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 32, h, 0); } diff --git a/libavcodec/snow_dwt.h b/libavcodec/snow_dwt.h index 6e7d22c71..b5803bc99 100644 --- a/libavcodec/snow_dwt.h +++ b/libavcodec/snow_dwt.h @@ -26,7 +26,7 @@ #include "libavutil/attributes.h" -struct MpegEncContext; +typedef struct MPVEncContext MPVEncContext; typedef int DWTELEM; typedef short IDWTELEM; @@ -144,8 +144,8 @@ void ff_snow_inner_add_yblock(const uint8_t *obmc, const int obmc_stride, int src_y, int src_stride, slice_buffer *sb, int add, uint8_t *dst8); -int ff_w53_32_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h); -int ff_w97_32_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h); +int ff_w53_32_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h); +int ff_w97_32_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h); void ff_spatial_dwt(int *buffer, int *temp, int width, int height, int stride, int type, int decomposition_count); diff --git a/libavcodec/snowdec.c b/libavcodec/snowdec.c index 50dcaf8b9..aaf01295a 100644 --- a/libavcodec/snowdec.c +++ b/libavcodec/snowdec.c @@ -481,14 +481,16 @@ static int decode_header(SnowContext *s){ }else if(s->chroma_h_shift == 2 && s->chroma_v_shift==2){ s->avctx->pix_fmt= AV_PIX_FMT_YUV410P; } else { - av_log(s, AV_LOG_ERROR, "unsupported color subsample mode %d %d\n", s->chroma_h_shift, s->chroma_v_shift); + av_log(s->avctx, AV_LOG_ERROR, + "unsupported color subsample mode %d %d\n", + s->chroma_h_shift, s->chroma_v_shift); s->chroma_h_shift = s->chroma_v_shift = 1; s->avctx->pix_fmt= AV_PIX_FMT_YUV420P; return AVERROR_INVALIDDATA; } s->nb_planes = 3; } else { - av_log(s, AV_LOG_ERROR, "unsupported color space\n"); + av_log(s->avctx, AV_LOG_ERROR, "unsupported color space\n"); s->chroma_h_shift = s->chroma_v_shift = 1; s->avctx->pix_fmt= AV_PIX_FMT_YUV420P; return AVERROR_INVALIDDATA; @@ -603,14 +605,16 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, if ((res = decode_header(s)) < 0) return res; - if (!s->mconly_picture->data[0]) { + if (avctx->debug & 2048) { + av_frame_unref(s->mconly_picture); res = ff_get_buffer(avctx, s->mconly_picture, AV_GET_BUFFER_FLAG_REF); if (res < 0) return res; } - if (s->mconly_picture->format != avctx->pix_fmt) { + + if (s->current_picture->data[0] && s->current_picture->format != avctx->pix_fmt) { av_log(avctx, AV_LOG_ERROR, "pixel format changed\n"); - return AVERROR_INVALIDDATA; + return AVERROR_PATCHWELCOME; } if ((res=ff_snow_common_init_after_header(avctx)) < 0) @@ -779,7 +783,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, emms_c(); - ff_snow_release_buffer(avctx); + av_frame_unref(s->last_picture[s->max_ref_frames - 1]); if(!(s->avctx->debug&2048)) res = av_frame_ref(picture, s->current_picture); diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index 58dd7017c..5312d48e9 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -30,7 +30,6 @@ #include "encode.h" #include "internal.h" //For AVCodecInternal.recon_frame #include "me_cmp.h" -#include "packet_internal.h" #include "qpeldsp.h" #include "snow_dwt.h" #include "snow.h" @@ -61,13 +60,17 @@ typedef struct SnowEncContext { int scenechange_threshold; MECmpContext mecc; - MpegEncContext m; // needed for motion estimation, should not be used for anything else, the idea is to eventually make the motion estimation independent of MpegEncContext, so this will be removed then (FIXME/XXX) + MPVMainEncContext m; // needed for motion estimation, should not be used for anything else, the idea is to eventually make the motion estimation independent of MPVEncContext, so this will be removed then (FIXME/XXX) MPVPicture cur_pic, last_pic; #define ME_CACHE_SIZE 1024 unsigned me_cache[ME_CACHE_SIZE]; unsigned me_cache_generation; uint64_t encoding_error[SNOW_MAX_PLANES]; + + uint8_t *emu_edge_buffer; + + IDWTELEM obmc_scratchpad[MB_SIZE * MB_SIZE * 12 * 2]; } SnowEncContext; #define PTR_ADD(ptr, off) ((ptr) ? (ptr) + (off) : NULL) @@ -162,7 +165,7 @@ static av_cold int encode_init(AVCodecContext *avctx) { SnowEncContext *const enc = avctx->priv_data; SnowContext *const s = &enc->com; - MpegEncContext *const mpv = &enc->m; + MPVEncContext *const mpv = &enc->m.s; int plane_index, ret; int i; @@ -219,7 +222,7 @@ static av_cold int encode_init(AVCodecContext *avctx) mcf(12,12) ff_me_cmp_init(&enc->mecc, avctx); - ret = ff_me_init(&enc->m.me, avctx, &enc->mecc, 0); + ret = ff_me_init(&mpv->me, avctx, &enc->mecc, 0); if (ret < 0) return ret; ff_mpegvideoencdsp_init(&enc->mpvencdsp, avctx); @@ -228,21 +231,18 @@ static av_cold int encode_init(AVCodecContext *avctx) s->version=0; - mpv->avctx = avctx; - mpv->bit_rate= avctx->bit_rate; - mpv->lmin = avctx->mb_lmin; - mpv->lmax = avctx->mb_lmax; - mpv->mb_num = (avctx->width * avctx->height + 255) / 256; // For ratecontrol + mpv->c.avctx = avctx; + enc->m.bit_rate = avctx->bit_rate; + enc->m.lmin = avctx->mb_lmin; + enc->m.lmax = avctx->mb_lmax; + mpv->c.mb_num = (avctx->width * avctx->height + 255) / 256; // For ratecontrol mpv->me.temp = mpv->me.scratchpad = av_calloc(avctx->width + 64, 2*16*2*sizeof(uint8_t)); - mpv->sc.obmc_scratchpad= av_mallocz(MB_SIZE*MB_SIZE*12*sizeof(uint32_t)); - mpv->me.map = av_mallocz(2 * ME_MAP_SIZE * sizeof(*mpv->me.map)); - if (!mpv->me.scratchpad || !mpv->me.map || !mpv->sc.obmc_scratchpad) + if (!mpv->me.scratchpad) return AVERROR(ENOMEM); - mpv->me.score_map = mpv->me.map + ME_MAP_SIZE; - ff_h263_encode_init(mpv); //mv_penalty + mpv->me.mv_penalty = ff_h263_get_mv_penalty(); s->max_ref_frames = av_clip(avctx->refs, 1, MAX_REF_FRAMES); @@ -254,7 +254,7 @@ static av_cold int encode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); } if((avctx->flags&AV_CODEC_FLAG_PASS2) || !(avctx->flags&AV_CODEC_FLAG_QSCALE)){ - ret = ff_rate_control_init(mpv); + ret = ff_rate_control_init(&enc->m); if(ret < 0) return ret; } @@ -290,6 +290,10 @@ static av_cold int encode_init(AVCodecContext *avctx) if ((ret = get_encode_buffer(s, s->input_picture)) < 0) return ret; + enc->emu_edge_buffer = av_calloc(avctx->width + 128, 2 * (2 * MB_SIZE + HTAPS_MAX - 1)); + if (!enc->emu_edge_buffer) + return AVERROR(ENOMEM); + if (enc->motion_est == FF_ME_ITER) { int size= s->b_width * s->b_height << 2*s->block_max_depth; for(i=0; imax_ref_frames; i++){ @@ -371,7 +375,7 @@ static inline int get_penalty_factor(int lambda, int lambda2, int type){ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) { SnowContext *const s = &enc->com; - MotionEstContext *const c = &enc->m.me; + MotionEstContext *const c = &enc->m.s.me; uint8_t p_buffer[1024]; uint8_t i_buffer[1024]; uint8_t p_state[sizeof(s->block_state)]; @@ -437,9 +441,9 @@ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) last_mv[2][0]= bottom->mx; last_mv[2][1]= bottom->my; - enc->m.mb_stride = 2; - enc->m.mb_x = - enc->m.mb_y = 0; + enc->m.s.c.mb_stride = 2; + enc->m.s.c.mb_x = + enc->m.s.c.mb_y = 0; c->skip= 0; av_assert1(c-> stride == stride); @@ -448,7 +452,7 @@ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) c->penalty_factor = get_penalty_factor(enc->lambda, enc->lambda2, c->avctx->me_cmp); c->sub_penalty_factor= get_penalty_factor(enc->lambda, enc->lambda2, c->avctx->me_sub_cmp); c->mb_penalty_factor = get_penalty_factor(enc->lambda, enc->lambda2, c->avctx->mb_cmp); - c->current_mv_penalty = c->mv_penalty[enc->m.f_code=1] + MAX_DMV; + c->current_mv_penalty = c->mv_penalty[enc->m.s.f_code=1] + MAX_DMV; c->xmin = - x*block_w - 16+3; c->ymin = - y*block_w - 16+3; @@ -484,7 +488,7 @@ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) for(ref=0; refref_frames; ref++){ init_ref(c, current_data, s->last_picture[ref]->data, NULL, block_w*x, block_w*y, 0); - ref_score= ff_epzs_motion_search(&enc->m, &ref_mx, &ref_my, P, 0, /*ref_index*/ 0, last_mv, + ref_score = ff_epzs_motion_search(&enc->m.s, &ref_mx, &ref_my, P, 0, /*ref_index*/ 0, last_mv, (1<<16)>>shift, level-LOG2_MB_SIZE+4, block_w); av_assert2(ref_mx >= c->xmin); @@ -492,8 +496,10 @@ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) av_assert2(ref_my >= c->ymin); av_assert2(ref_my <= c->ymax); - ref_score= c->sub_motion_search(&enc->m, &ref_mx, &ref_my, ref_score, 0, 0, level-LOG2_MB_SIZE+4, block_w); - ref_score= ff_get_mb_score(&enc->m, ref_mx, ref_my, 0, 0, level-LOG2_MB_SIZE+4, block_w, 0); + ref_score = c->sub_motion_search(&enc->m.s, &ref_mx, &ref_my, ref_score, + 0, 0, level-LOG2_MB_SIZE+4, block_w); + ref_score = ff_get_mb_score(&enc->m.s, ref_mx, ref_my, 0, 0, + level-LOG2_MB_SIZE+4, block_w, 0); ref_score+= 2*av_log2(2*ref)*c->penalty_factor; if(s->ref_mvs[ref]){ s->ref_mvs[ref][index][0]= ref_mx; @@ -569,7 +575,7 @@ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) if (vard <= 64 || vard < varc) c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc); else - c->scene_change_score += enc->m.qscale; + c->scene_change_score += enc->m.s.c.qscale; } if(level!=s->block_max_depth){ @@ -672,7 +678,7 @@ static int get_dc(SnowEncContext *enc, int mb_x, int mb_y, int plane_index) const int obmc_stride= plane_index ? (2*block_size)>>s->chroma_h_shift : 2*block_size; const int ref_stride= s->current_picture->linesize[plane_index]; const uint8_t *src = s->input_picture->data[plane_index]; - IDWTELEM *dst= (IDWTELEM*)enc->m.sc.obmc_scratchpad + plane_index*block_size*block_size*4; //FIXME change to unsigned + IDWTELEM *dst = enc->obmc_scratchpad + plane_index * block_size * block_size * 4; //FIXME change to unsigned const int b_stride = s->b_width << s->block_max_depth; const int w= p->width; const int h= p->height; @@ -770,9 +776,9 @@ static int get_block_rd(SnowEncContext *enc, int mb_x, int mb_y, const int ref_stride= s->current_picture->linesize[plane_index]; uint8_t *dst= s->current_picture->data[plane_index]; const uint8_t *src = s->input_picture->data[plane_index]; - IDWTELEM *pred= (IDWTELEM*)enc->m.sc.obmc_scratchpad + plane_index*block_size*block_size*4; + IDWTELEM *pred = enc->obmc_scratchpad + plane_index * block_size * block_size * 4; uint8_t *cur = s->scratchbuf; - uint8_t *tmp = s->emu_edge_buffer; + uint8_t *tmp = enc->emu_edge_buffer; const int b_stride = s->b_width << s->block_max_depth; const int b_height = s->b_height<< s->block_max_depth; const int w= p->width; @@ -788,7 +794,7 @@ static int get_block_rd(SnowEncContext *enc, int mb_x, int mb_y, int y1= FFMIN(block_h*2, h-sy); int i,x,y; - av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumtions below chckinhg only block_w + av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumptions below chckinhg only block_w ff_snow_pred_block(s, cur, tmp, ref_stride, sx, sy, block_w*2, block_h*2, &s->block[mb_x + mb_y*b_stride], plane_index, w, h); @@ -833,19 +839,19 @@ static int get_block_rd(SnowEncContext *enc, int mb_x, int mb_y, * to improve the score of the whole frame, thus iterative motion * estimation does not always converge. */ if(s->avctx->me_cmp == FF_CMP_W97) - distortion = ff_w97_32_c(&enc->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32); + distortion = ff_w97_32_c(&enc->m.s, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32); else if(s->avctx->me_cmp == FF_CMP_W53) - distortion = ff_w53_32_c(&enc->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32); + distortion = ff_w53_32_c(&enc->m.s, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32); else{ distortion = 0; for(i=0; i<4; i++){ int off = sx+16*(i&1) + (sy+16*(i>>1))*ref_stride; - distortion += enc->m.me.me_cmp[0](&enc->m, src + off, dst + off, ref_stride, 16); + distortion += enc->m.s.me.me_cmp[0](&enc->m.s, src + off, dst + off, ref_stride, 16); } } }else{ av_assert2(block_w==8); - distortion = enc->m.me.me_cmp[0](&enc->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, block_w*2); + distortion = enc->m.s.me.me_cmp[0](&enc->m.s, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, block_w*2); } if(plane_index==0){ @@ -885,7 +891,7 @@ static int get_4block_rd(SnowEncContext *enc, int mb_x, int mb_y, int plane_inde int rate= 0; const int penalty_factor= get_penalty_factor(enc->lambda, enc->lambda2, s->avctx->me_cmp); - av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumtions below + av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumptions below for(i=0; i<9; i++){ int mb_x2= mb_x + (i%3) - 1; @@ -911,7 +917,7 @@ static int get_4block_rd(SnowEncContext *enc, int mb_x, int mb_y, int plane_inde } av_assert1(block_w== 8 || block_w==16); - distortion += enc->m.me.me_cmp[block_w==8](&enc->m, src + x + y*ref_stride, dst + x + y*ref_stride, ref_stride, block_h); + distortion += enc->m.s.me.me_cmp[block_w==8](&enc->m.s, src + x + y*ref_stride, dst + x + y*ref_stride, ref_stride, block_h); } if(plane_index==0){ @@ -1702,6 +1708,7 @@ static int ratecontrol_1pass(SnowEncContext *enc, AVFrame *pict) coef_sum+= abs(buf[x+y*stride]) * qdiv >> 16; } } + emms_c(); /* ugly, ratecontrol just takes a sqrt again */ av_assert0(coef_sum < INT_MAX); @@ -1759,7 +1766,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, { SnowEncContext *const enc = avctx->priv_data; SnowContext *const s = &enc->com; - MpegEncContext *const mpv = &enc->m; + MPVEncContext *const mpv = &enc->m.s; RangeCoder * const c= &s->c; AVCodecInternal *avci = avctx->internal; AVFrame *pic; @@ -1788,23 +1795,22 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, EDGE_TOP | EDGE_BOTTOM); } - emms_c(); pic = s->input_picture; pic->pict_type = pict->pict_type; pic->quality = pict->quality; mpv->picture_number = avctx->frame_num; if(avctx->flags&AV_CODEC_FLAG_PASS2){ - mpv->pict_type = pic->pict_type = mpv->rc_context.entry[avctx->frame_num].new_pict_type; + mpv->c.pict_type = pic->pict_type = enc->m.rc_context.entry[avctx->frame_num].new_pict_type; s->keyframe = pic->pict_type == AV_PICTURE_TYPE_I; if(!(avctx->flags&AV_CODEC_FLAG_QSCALE)) { - pic->quality = ff_rate_estimate_qscale(mpv, 0); + pic->quality = ff_rate_estimate_qscale(&enc->m, 0); if (pic->quality < 0) return -1; } }else{ s->keyframe= avctx->gop_size==0 || avctx->frame_num % avctx->gop_size == 0; - mpv->pict_type = pic->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + mpv->c.pict_type = pic->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; } if (enc->pass1_rc && avctx->frame_num == 0) @@ -1833,7 +1839,6 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, s->current_picture->linesize[2], w>>s->chroma_h_shift, h>>s->chroma_v_shift, EDGE_WIDTH>>s->chroma_h_shift, EDGE_WIDTH>>s->chroma_v_shift, EDGE_TOP | EDGE_BOTTOM); } - emms_c(); } ff_snow_frames_prepare(s); @@ -1841,9 +1846,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, if (ret < 0) return ret; - mpv->cur_pic.ptr = &enc->cur_pic; - mpv->cur_pic.ptr->f = s->current_picture; - mpv->cur_pic.ptr->f->pts = pict->pts; + mpv->c.cur_pic.ptr = &enc->cur_pic; + mpv->c.cur_pic.ptr->f = s->current_picture; + mpv->c.cur_pic.ptr->f->pts = pict->pts; if(pic->pict_type == AV_PICTURE_TYPE_P){ int block_width = (width +15)>>4; int block_height= (height+15)>>4; @@ -1852,35 +1857,34 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, av_assert0(s->current_picture->data[0]); av_assert0(s->last_picture[0]->data[0]); - mpv->avctx = s->avctx; - mpv->last_pic.ptr = &enc->last_pic; - mpv->last_pic.ptr->f = s->last_picture[0]; + mpv->c.avctx = s->avctx; + mpv->c.last_pic.ptr = &enc->last_pic; + mpv->c.last_pic.ptr->f = s->last_picture[0]; mpv-> new_pic = s->input_picture; - mpv->linesize = stride; - mpv->uvlinesize = s->current_picture->linesize[1]; - mpv->width = width; - mpv->height = height; - mpv->mb_width = block_width; - mpv->mb_height = block_height; - mpv->mb_stride = mpv->mb_width + 1; - mpv->b8_stride = 2 * mpv->mb_width + 1; - mpv->f_code = 1; - mpv->pict_type = pic->pict_type; - mpv->motion_est = enc->motion_est; - mpv->me.scene_change_score = 0; + mpv->c.linesize = stride; + mpv->c.uvlinesize = s->current_picture->linesize[1]; + mpv->c.width = width; + mpv->c.height = height; + mpv->c.mb_width = block_width; + mpv->c.mb_height = block_height; + mpv->c.mb_stride = mpv->c.mb_width + 1; + mpv->c.b8_stride = 2 * mpv->c.mb_width + 1; + mpv->f_code = 1; + mpv->c.pict_type = pic->pict_type; + mpv->me.motion_est = enc->motion_est; mpv->me.dia_size = avctx->dia_size; - mpv->quarter_sample = (s->avctx->flags & AV_CODEC_FLAG_QPEL)!=0; - mpv->out_format = FMT_H263; - mpv->unrestricted_mv = 1; + mpv->c.quarter_sample = (s->avctx->flags & AV_CODEC_FLAG_QPEL)!=0; + mpv->c.out_format = FMT_H263; + mpv->me.unrestricted_mv = 1; - mpv->lambda = enc->lambda; - mpv->qscale = (mpv->lambda*139 + FF_LAMBDA_SCALE*64) >> (FF_LAMBDA_SHIFT + 7); + mpv->lambda = enc->lambda; + mpv->c.qscale = (mpv->lambda*139 + FF_LAMBDA_SCALE*64) >> (FF_LAMBDA_SHIFT + 7); enc->lambda2 = mpv->lambda2 = (mpv->lambda*mpv->lambda + FF_LAMBDA_SCALE/2) >> FF_LAMBDA_SHIFT; - mpv->qdsp = enc->qdsp; //move - mpv->hdsp = s->hdsp; - ff_me_init_pic(&enc->m); - s->hdsp = mpv->hdsp; + mpv->c.qdsp = enc->qdsp; //move + mpv->c.hdsp = s->hdsp; + ff_me_init_pic(mpv); + s->hdsp = mpv->c.hdsp; } if (enc->pass1_rc) { @@ -1901,7 +1905,7 @@ redo_frame: return AVERROR(EINVAL); } - mpv->pict_type = pic->pict_type; + mpv->c.pict_type = pic->pict_type; s->qbias = pic->pict_type == AV_PICTURE_TYPE_P ? 2 : 0; ff_snow_common_init_after_header(avctx); @@ -1943,6 +1947,7 @@ redo_frame: pic->pict_type= AV_PICTURE_TYPE_I; s->keyframe=1; s->current_picture->flags |= AV_FRAME_FLAG_KEY; + emms_c(); goto redo_frame; } @@ -2041,29 +2046,29 @@ redo_frame: update_last_header_values(s); - ff_snow_release_buffer(avctx); + av_frame_unref(s->last_picture[s->max_ref_frames - 1]); s->current_picture->pict_type = pic->pict_type; s->current_picture->quality = pic->quality; - mpv->frame_bits = 8 * (s->c.bytestream - s->c.bytestream_start); - mpv->p_tex_bits = mpv->frame_bits - mpv->misc_bits - mpv->mv_bits; - mpv->total_bits += 8*(s->c.bytestream - s->c.bytestream_start); + enc->m.frame_bits = 8 * (s->c.bytestream - s->c.bytestream_start); + mpv->p_tex_bits = enc->m.frame_bits - mpv->misc_bits - mpv->mv_bits; + enc->m.total_bits += 8*(s->c.bytestream - s->c.bytestream_start); enc->cur_pic.display_picture_number = enc->cur_pic.coded_picture_number = avctx->frame_num; enc->cur_pic.f->quality = pic->quality; - if (enc->pass1_rc) - if (ff_rate_estimate_qscale(mpv, 0) < 0) - return -1; + if (enc->pass1_rc) { + ret = ff_rate_estimate_qscale(&enc->m, 0); + if (ret < 0) + return ret; + } if(avctx->flags&AV_CODEC_FLAG_PASS1) - ff_write_pass1_stats(mpv); - mpv->last_pict_type = mpv->pict_type; + ff_write_pass1_stats(&enc->m); + enc->m.last_pict_type = mpv->c.pict_type; - emms_c(); - - ff_side_data_set_encoder_stats(pkt, s->current_picture->quality, - enc->encoding_error, - (s->avctx->flags&AV_CODEC_FLAG_PSNR) ? SNOW_MAX_PLANES : 0, - s->current_picture->pict_type); + ff_encode_add_stats_side_data(pkt, s->current_picture->quality, + enc->encoding_error, + (s->avctx->flags&AV_CODEC_FLAG_PSNR) ? SNOW_MAX_PLANES : 0, + s->current_picture->pict_type); if (s->avctx->flags & AV_CODEC_FLAG_RECON_FRAME) { av_frame_replace(avci->recon_frame, s->current_picture); } @@ -2090,10 +2095,9 @@ static av_cold int encode_end(AVCodecContext *avctx) av_freep(&s->ref_scores[i]); } - enc->m.me.temp = NULL; - av_freep(&enc->m.me.scratchpad); - av_freep(&enc->m.me.map); - av_freep(&enc->m.sc.obmc_scratchpad); + enc->m.s.me.temp = NULL; + av_freep(&enc->m.s.me.scratchpad); + av_freep(&enc->emu_edge_buffer); av_freep(&avctx->stats_out); @@ -2110,7 +2114,7 @@ static const AVOption options[] = { { "iter", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_ITER }, 0, 0, VE, .unit = "motion_est" }, { "memc_only", "Only do ME/MC (I frames -> ref, P frame -> ME+MC).", OFFSET(memc_only), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "no_bitstream", "Skip final bitstream writeout.", OFFSET(no_bitstream), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "intra_penalty", "Penalty for intra blocks in block decission", OFFSET(intra_penalty), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, + { "intra_penalty", "Penalty for intra blocks in block decision", OFFSET(intra_penalty), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "iterative_dia_size", "Dia size for the iterative ME", OFFSET(iterative_dia_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "sc_threshold", "Scene change threshold", OFFSET(scenechange_threshold), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, VE }, { "pred", "Spatial decomposition type", OFFSET(pred), AV_OPT_TYPE_INT, { .i64 = 0 }, DWT_97, DWT_53, VE, .unit = "pred" }, @@ -2120,7 +2124,7 @@ static const AVOption options[] = { "defined in the section 'Expression Evaluation', the following functions are available: " "bits2qp(bits), qp2bits(qp). Also the following constants are available: iTex pTex tex mv " "fCode iCount mcVar var isI isP isB avgQP qComp avgIITex avgPITex avgPPTex avgBPTex avgTex.", - OFFSET(m.rc_eq), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VE }, + OFFSET(m.rc_context.rc_eq), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VE }, { NULL }, }; @@ -2143,11 +2147,8 @@ const FFCodec ff_snow_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_GRAY8, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_GRAY8), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &snowenc_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/sonic.c b/libavcodec/sonic.c index d2057ac18..08549aacf 100644 --- a/libavcodec/sonic.c +++ b/libavcodec/sonic.c @@ -96,411 +96,6 @@ static inline int shift_down(int a,int b) return (a>>b)+(a<0); } -static av_always_inline av_flatten void put_symbol(RangeCoder *c, uint8_t *state, int v, int is_signed, uint64_t rc_stat[256][2], uint64_t rc_stat2[32][2]){ - int i; - -#define put_rac(C,S,B) \ -do{\ - if(rc_stat){\ - rc_stat[*(S)][B]++;\ - rc_stat2[(S)-state][B]++;\ - }\ - put_rac(C,S,B);\ -}while(0) - - if(v){ - const int a= FFABS(v); - const int e= av_log2(a); - put_rac(c, state+0, 0); - if(e<=9){ - for(i=0; i=0; i--){ - put_rac(c, state+22+i, (a>>i)&1); //22..31 - } - - if(is_signed) - put_rac(c, state+11 + e, v < 0); //11..21 - }else{ - for(i=0; i=0; i--){ - put_rac(c, state+22+FFMIN(i,9), (a>>i)&1); //22..31 - } - - if(is_signed) - put_rac(c, state+11 + 10, v < 0); //11..21 - } - }else{ - put_rac(c, state+0, 1); - } -#undef put_rac -} - -static inline av_flatten int get_symbol(RangeCoder *c, uint8_t *state, int is_signed){ - if(get_rac(c, state+0)) - return 0; - else{ - int i, e; - unsigned a; - e= 0; - while(get_rac(c, state+1 + FFMIN(e,9))){ //1..10 - e++; - if (e > 31) - return AVERROR_INVALIDDATA; - } - - a= 1; - for(i=e-1; i>=0; i--){ - a += a + get_rac(c, state+22 + FFMIN(i,9)); //22..31 - } - - e= -(is_signed && get_rac(c, state+11 + FFMIN(e, 10))); //11..21 - return (a^e)-e; - } -} - -#if 1 -static inline int intlist_write(RangeCoder *c, uint8_t *state, int *buf, int entries, int base_2_part) -{ - int i; - - for (i = 0; i < entries; i++) - put_symbol(c, state, buf[i], 1, NULL, NULL); - - return 1; -} - -static inline int intlist_read(RangeCoder *c, uint8_t *state, int *buf, int entries, int base_2_part) -{ - int i; - - for (i = 0; i < entries; i++) - buf[i] = get_symbol(c, state, 1); - - return 1; -} -#elif 1 -static inline int intlist_write(PutBitContext *pb, int *buf, int entries, int base_2_part) -{ - int i; - - for (i = 0; i < entries; i++) - set_se_golomb(pb, buf[i]); - - return 1; -} - -static inline int intlist_read(GetBitContext *gb, int *buf, int entries, int base_2_part) -{ - int i; - - for (i = 0; i < entries; i++) - buf[i] = get_se_golomb(gb); - - return 1; -} - -#else - -#define ADAPT_LEVEL 8 - -static int bits_to_store(uint64_t x) -{ - int res = 0; - - while(x) - { - res++; - x >>= 1; - } - return res; -} - -static void write_uint_max(PutBitContext *pb, unsigned int value, unsigned int max) -{ - int i, bits; - - if (!max) - return; - - bits = bits_to_store(max); - - for (i = 0; i < bits-1; i++) - put_bits(pb, 1, value & (1 << i)); - - if ( (value | (1 << (bits-1))) <= max) - put_bits(pb, 1, value & (1 << (bits-1))); -} - -static unsigned int read_uint_max(GetBitContext *gb, int max) -{ - int i, bits, value = 0; - - if (!max) - return 0; - - bits = bits_to_store(max); - - for (i = 0; i < bits-1; i++) - if (get_bits1(gb)) - value += 1 << i; - - if ( (value | (1<<(bits-1))) <= max) - if (get_bits1(gb)) - value += 1 << (bits-1); - - return value; -} - -static int intlist_write(PutBitContext *pb, int *buf, int entries, int base_2_part) -{ - int i, j, x = 0, low_bits = 0, max = 0; - int step = 256, pos = 0, dominant = 0, any = 0; - int *copy, *bits; - - copy = av_calloc(entries, sizeof(*copy)); - if (!copy) - return AVERROR(ENOMEM); - - if (base_2_part) - { - int energy = 0; - - for (i = 0; i < entries; i++) - energy += abs(buf[i]); - - low_bits = bits_to_store(energy / (entries * 2)); - if (low_bits > 15) - low_bits = 15; - - put_bits(pb, 4, low_bits); - } - - for (i = 0; i < entries; i++) - { - put_bits(pb, low_bits, abs(buf[i])); - copy[i] = abs(buf[i]) >> low_bits; - if (copy[i] > max) - max = abs(copy[i]); - } - - bits = av_calloc(entries*max, sizeof(*bits)); - if (!bits) - { - av_free(copy); - return AVERROR(ENOMEM); - } - - for (i = 0; i <= max; i++) - { - for (j = 0; j < entries; j++) - if (copy[j] >= i) - bits[x++] = copy[j] > i; - } - - // store bitstream - while (pos < x) - { - int steplet = step >> 8; - - if (pos + steplet > x) - steplet = x - pos; - - for (i = 0; i < steplet; i++) - if (bits[i+pos] != dominant) - any = 1; - - put_bits(pb, 1, any); - - if (!any) - { - pos += steplet; - step += step / ADAPT_LEVEL; - } - else - { - int interloper = 0; - - while (((pos + interloper) < x) && (bits[pos + interloper] == dominant)) - interloper++; - - // note change - write_uint_max(pb, interloper, (step >> 8) - 1); - - pos += interloper + 1; - step -= step / ADAPT_LEVEL; - } - - if (step < 256) - { - step = 65536 / step; - dominant = !dominant; - } - } - - // store signs - for (i = 0; i < entries; i++) - if (buf[i]) - put_bits(pb, 1, buf[i] < 0); - - av_free(bits); - av_free(copy); - - return 0; -} - -static int intlist_read(GetBitContext *gb, int *buf, int entries, int base_2_part) -{ - int i, low_bits = 0, x = 0; - int n_zeros = 0, step = 256, dominant = 0; - int pos = 0, level = 0; - int *bits = av_calloc(entries, sizeof(*bits)); - - if (!bits) - return AVERROR(ENOMEM); - - if (base_2_part) - { - low_bits = get_bits(gb, 4); - - if (low_bits) - for (i = 0; i < entries; i++) - buf[i] = get_bits(gb, low_bits); - } - -// av_log(NULL, AV_LOG_INFO, "entries: %d, low bits: %d\n", entries, low_bits); - - while (n_zeros < entries) - { - int steplet = step >> 8; - - if (!get_bits1(gb)) - { - for (i = 0; i < steplet; i++) - bits[x++] = dominant; - - if (!dominant) - n_zeros += steplet; - - step += step / ADAPT_LEVEL; - } - else - { - int actual_run = read_uint_max(gb, steplet-1); - -// av_log(NULL, AV_LOG_INFO, "actual run: %d\n", actual_run); - - for (i = 0; i < actual_run; i++) - bits[x++] = dominant; - - bits[x++] = !dominant; - - if (!dominant) - n_zeros += actual_run; - else - n_zeros++; - - step -= step / ADAPT_LEVEL; - } - - if (step < 256) - { - step = 65536 / step; - dominant = !dominant; - } - } - - // reconstruct unsigned values - n_zeros = 0; - for (i = 0; n_zeros < entries; i++) - { - while(1) - { - if (pos >= entries) - { - pos = 0; - level += 1 << low_bits; - } - - if (buf[pos] >= level) - break; - - pos++; - } - - if (bits[i]) - buf[pos] += 1 << low_bits; - else - n_zeros++; - - pos++; - } - av_free(bits); - - // read signs - for (i = 0; i < entries; i++) - if (buf[i] && get_bits1(gb)) - buf[i] = -buf[i]; - -// av_log(NULL, AV_LOG_INFO, "zeros: %d pos: %d\n", n_zeros, pos); - - return 0; -} -#endif - -static void predictor_init_state(int *k, int *state, int order) -{ - int i; - - for (i = order-2; i >= 0; i--) - { - int j, p, x = state[i]; - - for (j = 0, p = i+1; p < order; j++,p++) - { - int tmp = x + shift_down(k[j] * (unsigned)state[p], LATTICE_SHIFT); - state[p] += shift_down(k[j]* (unsigned)x, LATTICE_SHIFT); - x = tmp; - } - } -} - -static int predictor_calc_error(int *k, int *state, int order, int error) -{ - int i, x = error - (unsigned)shift_down(k[order-1] * (unsigned)state[order-1], LATTICE_SHIFT); - -#if 1 - int *k_ptr = &(k[order-2]), - *state_ptr = &(state[order-2]); - for (i = order-2; i >= 0; i--, k_ptr--, state_ptr--) - { - int k_value = *k_ptr, state_value = *state_ptr; - x -= (unsigned)shift_down(k_value * (unsigned)state_value, LATTICE_SHIFT); - state_ptr[1] = state_value + shift_down(k_value * (unsigned)x, LATTICE_SHIFT); - } -#else - for (i = order-2; i >= 0; i--) - { - x -= (unsigned)shift_down(k[i] * state[i], LATTICE_SHIFT); - state[i+1] = state[i] + shift_down(k[i] * x, LATTICE_SHIFT); - } -#endif - - // don't drift too far, to avoid overflows - if (x > (SAMPLE_FACTOR<<16)) x = (SAMPLE_FACTOR<<16); - if (x < -(SAMPLE_FACTOR<<16)) x = -(SAMPLE_FACTOR<<16); - - state[0] = x; - - return x; -} #if CONFIG_SONIC_ENCODER || CONFIG_SONIC_LS_ENCODER // Heavily modified Levinson-Durbin algorithm which @@ -519,7 +114,6 @@ static void modified_levinson_durbin(int *window, int window_entries, { int step = (i+1)*channels, k, j; double xx = 0.0, xy = 0.0; -#if 1 int *x_ptr = &(window[step]); int *state_ptr = &(state[0]); j = window_entries - step; @@ -530,17 +124,6 @@ static void modified_levinson_durbin(int *window, int window_entries, xx += state_value*state_value; xy += x_value*state_value; } -#else - for (j = 0; j <= (window_entries - step); j++); - { - double stepval = window[step+j]; - double stateval = window[j]; -// xx += (double)window[j]*(double)window[j]; -// xy += (double)window[step+j]*(double)window[j]; - xx += stateval*stateval; - xy += stepval*stateval; - } -#endif if (xx == 0.0) k = 0; else @@ -554,7 +137,6 @@ static void modified_levinson_durbin(int *window, int window_entries, out[i] = k; k *= tap_quant[i]; -#if 1 x_ptr = &(window[step]); state_ptr = &(state[0]); j = window_entries - step; @@ -565,15 +147,6 @@ static void modified_levinson_durbin(int *window, int window_entries, *x_ptr = x_value + shift_down(k*state_value,LATTICE_SHIFT); *state_ptr = state_value + shift_down(k*x_value, LATTICE_SHIFT); } -#else - for (j=0; j <= (window_entries - step); j++) - { - int stepval = window[step+j]; - int stateval=state[j]; - window[step+j] += shift_down(k * stateval, LATTICE_SHIFT); - state[j] += shift_down(k * stepval, LATTICE_SHIFT); - } -#endif } } @@ -718,6 +291,63 @@ static av_cold int sonic_encode_close(AVCodecContext *avctx) return 0; } +static av_always_inline av_flatten void put_symbol(RangeCoder *c, uint8_t *state, int v, int is_signed, uint64_t rc_stat[256][2], uint64_t rc_stat2[32][2]){ + int i; + +#define put_rac(C,S,B) \ +do{\ + if(rc_stat){\ + rc_stat[*(S)][B]++;\ + rc_stat2[(S)-state][B]++;\ + }\ + put_rac(C,S,B);\ +}while(0) + + if(v){ + const int a= FFABS(v); + const int e= av_log2(a); + put_rac(c, state+0, 0); + if(e<=9){ + for(i=0; i=0; i--){ + put_rac(c, state+22+i, (a>>i)&1); //22..31 + } + + if(is_signed) + put_rac(c, state+11 + e, v < 0); //11..21 + }else{ + for(i=0; i=0; i--){ + put_rac(c, state+22+FFMIN(i,9), (a>>i)&1); //22..31 + } + + if(is_signed) + put_rac(c, state+11 + 10, v < 0); //11..21 + } + }else{ + put_rac(c, state+0, 1); + } +#undef put_rac +} + +static inline int intlist_write(RangeCoder *c, uint8_t *state, int *buf, int entries, int base_2_part) +{ + int i; + + for (i = 0; i < entries; i++) + put_symbol(c, state, buf[i], 1, NULL, NULL); + + return 1; +} + static int sonic_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr) { @@ -984,6 +614,78 @@ static av_cold int sonic_decode_close(AVCodecContext *avctx) return 0; } +static inline av_flatten int get_symbol(RangeCoder *c, uint8_t *state, int is_signed){ + if(get_rac(c, state+0)) + return 0; + else{ + int i, e; + unsigned a; + e= 0; + while(get_rac(c, state+1 + FFMIN(e,9))){ //1..10 + e++; + if (e > 31) + return AVERROR_INVALIDDATA; + } + + a= 1; + for(i=e-1; i>=0; i--){ + a += a + get_rac(c, state+22 + FFMIN(i,9)); //22..31 + } + + e= -(is_signed && get_rac(c, state+11 + FFMIN(e, 10))); //11..21 + return (a^e)-e; + } +} + +static inline int intlist_read(RangeCoder *c, uint8_t *state, int *buf, int entries, int base_2_part) +{ + int i; + + for (i = 0; i < entries; i++) + buf[i] = get_symbol(c, state, 1); + + return 1; +} + +static void predictor_init_state(int *k, int *state, int order) +{ + int i; + + for (i = order-2; i >= 0; i--) + { + int j, p, x = state[i]; + + for (j = 0, p = i+1; p < order; j++,p++) + { + int tmp = x + shift_down(k[j] * (unsigned)state[p], LATTICE_SHIFT); + state[p] += shift_down(k[j]* (unsigned)x, LATTICE_SHIFT); + x = tmp; + } + } +} + +static int predictor_calc_error(int *k, int *state, int order, int error) +{ + int i, x = error - (unsigned)shift_down(k[order-1] * (unsigned)state[order-1], LATTICE_SHIFT); + + int *k_ptr = &(k[order-2]), + *state_ptr = &(state[order-2]); + for (i = order-2; i >= 0; i--, k_ptr--, state_ptr--) + { + int k_value = *k_ptr, state_value = *state_ptr; + x -= (unsigned)shift_down(k_value * (unsigned)state_value, LATTICE_SHIFT); + state_ptr[1] = state_value + shift_down(k_value * (unsigned)x, LATTICE_SHIFT); + } + + // don't drift too far, to avoid overflows + if (x > (SAMPLE_FACTOR<<16)) x = (SAMPLE_FACTOR<<16); + if (x < -(SAMPLE_FACTOR<<16)) x = -(SAMPLE_FACTOR<<16); + + state[0] = x; + + return x; +} + static int sonic_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt) { @@ -1105,7 +807,7 @@ const FFCodec ff_sonic_encoder = { .priv_data_size = sizeof(SonicContext), .init = sonic_encode_init, FF_CODEC_ENCODE_CB(sonic_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .close = sonic_encode_close, }; @@ -1122,7 +824,7 @@ const FFCodec ff_sonic_ls_encoder = { .priv_data_size = sizeof(SonicContext), .init = sonic_encode_init, FF_CODEC_ENCODE_CB(sonic_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .close = sonic_encode_close, }; diff --git a/libavcodec/sparc/README b/libavcodec/sparc/README deleted file mode 100644 index f9f2349cd..000000000 --- a/libavcodec/sparc/README +++ /dev/null @@ -1,6 +0,0 @@ -SPARC optimizations have been removed in -commit b4dd424d96f09f9bafb88e47f37df65dc4529143 -The last revission with the optimizations is fb1b70c1ed50951c5fc1a309c3c446b2eaaf564b - -If you want to maintain these (or other) SPARC optimizations in ffmpeg, then please -contact ffmpeg-devel@ffmpeg.org diff --git a/libavcodec/speedhqenc.c b/libavcodec/speedhqenc.c index 81a5151b7..3041c0686 100644 --- a/libavcodec/speedhqenc.c +++ b/libavcodec/speedhqenc.c @@ -27,15 +27,18 @@ * SpeedHQ encoder. */ +#include "libavutil/avassert.h" #include "libavutil/thread.h" #include "avcodec.h" #include "codec_internal.h" +#include "mathops.h" #include "mpeg12data.h" #include "mpeg12vlc.h" #include "mpegvideo.h" #include "mpegvideodata.h" #include "mpegvideoenc.h" +#include "put_bits.h" #include "rl.h" #include "speedhq.h" #include "speedhqenc.h" @@ -59,7 +62,7 @@ static uint32_t speedhq_chr_dc_uni[512]; static uint8_t uni_speedhq_ac_vlc_len[64 * 64 * 2]; typedef struct SpeedHQEncContext { - MpegEncContext m; + MPVMainEncContext m; int slice_start; } SpeedHQEncContext; @@ -95,64 +98,24 @@ static av_cold void speedhq_init_static_data(void) ff_speedhq_vlc_table, uni_speedhq_ac_vlc_len); } -av_cold int ff_speedhq_encode_init(MpegEncContext *s) +static int speedhq_encode_picture_header(MPVMainEncContext *const m) { - static AVOnce init_static_once = AV_ONCE_INIT; + SpeedHQEncContext *const ctx = (SpeedHQEncContext*)m; + MPVEncContext *const s = &m->s; - if (s->width > 65500 || s->height > 65500) { - av_log(s, AV_LOG_ERROR, "SpeedHQ does not support resolutions above 65500x65500\n"); - return AVERROR(EINVAL); - } + put_bits_assume_flushed(&s->pb); - // border is not implemented correctly at the moment, see ticket #10078 - if (s->width % 16) { - av_log(s, AV_LOG_ERROR, "width must be a multiple of 16\n"); - return AVERROR_PATCHWELCOME; - } - - s->min_qcoeff = -2048; - s->max_qcoeff = 2047; - - ff_thread_once(&init_static_once, speedhq_init_static_data); - - s->intra_ac_vlc_length = - s->intra_ac_vlc_last_length = - s->intra_chroma_ac_vlc_length = - s->intra_chroma_ac_vlc_last_length = uni_speedhq_ac_vlc_len; - - s->y_dc_scale_table = - s->c_dc_scale_table = ff_mpeg12_dc_scale_table[3]; - - switch (s->avctx->pix_fmt) { - case AV_PIX_FMT_YUV420P: - s->avctx->codec_tag = MKTAG('S','H','Q','0'); - break; - case AV_PIX_FMT_YUV422P: - s->avctx->codec_tag = MKTAG('S','H','Q','2'); - break; - case AV_PIX_FMT_YUV444P: - s->avctx->codec_tag = MKTAG('S','H','Q','4'); - break; - default: - av_assert0(0); - } - - return 0; -} - -void ff_speedhq_encode_picture_header(MpegEncContext *s) -{ - SpeedHQEncContext *ctx = (SpeedHQEncContext*)s; - - put_bits_le(&s->pb, 8, 100 - s->qscale * 2); /* FIXME why doubled */ + put_bits_le(&s->pb, 8, 100 - s->c.qscale * 2); /* FIXME why doubled */ put_bits_le(&s->pb, 24, 4); /* no second field */ ctx->slice_start = 4; /* length of first slice, will be filled out later */ put_bits_le(&s->pb, 24, 0); + + return 0; } -void ff_speedhq_end_slice(MpegEncContext *s) +void ff_speedhq_end_slice(MPVEncContext *const s) { SpeedHQEncContext *ctx = (SpeedHQEncContext*)s; int slice_len; @@ -200,7 +163,7 @@ static inline void encode_dc(PutBitContext *pb, int diff, int component) } } -static void encode_block(MpegEncContext *s, int16_t *block, int n) +static void encode_block(MPVEncContext *const s, const int16_t block[], int n) { int alevel, level, last_non_zero, dc, i, j, run, last_index, sign; int code; @@ -215,10 +178,10 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n) /* now quantify & encode AC coefs */ last_non_zero = 0; - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; for (i = 1; i <= last_index; i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; level = block[j]; /* encode using VLC */ @@ -236,11 +199,10 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n) ff_speedhq_vlc_table[code][0] | (sign << ff_speedhq_vlc_table[code][1])); } else { /* escape seems to be pretty rare <5% so I do not optimize it; - * the values correspond to ff_speedhq_vlc_table[121] */ - put_bits_le(&s->pb, 6, 32); - /* escape: only clip in this case */ - put_bits_le(&s->pb, 6, run); - put_bits_le(&s->pb, 12, level + 2048); + * The following encodes the escape value 100000b together with + * run and level. */ + put_bits_le(&s->pb, 6 + 6 + 12, 0x20 | run << 6 | + (level + 2048) << 12); } last_non_zero = i; } @@ -249,13 +211,14 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n) put_bits_le(&s->pb, 4, 6); } -void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]) +static void speedhq_encode_mb(MPVEncContext *const s, int16_t block[12][64], + int unused_x, int unused_y) { int i; for(i=0;i<6;i++) { encode_block(s, block[i], i); } - if (s->chroma_format == CHROMA_444) { + if (s->c.chroma_format == CHROMA_444) { encode_block(s, block[8], 8); encode_block(s, block[9], 9); @@ -264,7 +227,7 @@ void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]) encode_block(s, block[10], 10); encode_block(s, block[11], 11); - } else if (s->chroma_format == CHROMA_422) { + } else if (s->c.chroma_format == CHROMA_422) { encode_block(s, block[6], 6); encode_block(s, block[7], 7); } @@ -272,20 +235,59 @@ void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]) s->i_tex_bits += get_bits_diff(s); } -static int ff_speedhq_mb_rows_in_slice(int slice_num, int mb_height) +static av_cold int speedhq_encode_init(AVCodecContext *avctx) { - return mb_height / 4 + (slice_num < (mb_height % 4)); -} + static AVOnce init_static_once = AV_ONCE_INIT; + MPVMainEncContext *const m = avctx->priv_data; + MPVEncContext *const s = &m->s; + int ret; -int ff_speedhq_mb_y_order_to_mb(int mb_y_order, int mb_height, int *first_in_slice) -{ - int slice_num = 0; - while (mb_y_order >= ff_speedhq_mb_rows_in_slice(slice_num, mb_height)) { - mb_y_order -= ff_speedhq_mb_rows_in_slice(slice_num, mb_height); - slice_num++; + if (avctx->width > 65500 || avctx->height > 65500) { + av_log(avctx, AV_LOG_ERROR, "SpeedHQ does not support resolutions above 65500x65500\n"); + return AVERROR(EINVAL); } - *first_in_slice = (mb_y_order == 0); - return mb_y_order * 4 + slice_num; + + // border is not implemented correctly at the moment, see ticket #10078 + if (avctx->width % 16) { + av_log(avctx, AV_LOG_ERROR, "width must be a multiple of 16\n"); + return AVERROR_PATCHWELCOME; + } + + switch (avctx->pix_fmt) { + case AV_PIX_FMT_YUV420P: + avctx->codec_tag = MKTAG('S','H','Q','0'); + break; + case AV_PIX_FMT_YUV422P: + avctx->codec_tag = MKTAG('S','H','Q','2'); + break; + case AV_PIX_FMT_YUV444P: + avctx->codec_tag = MKTAG('S','H','Q','4'); + break; + default: + av_unreachable("Already checked via CODEC_PIXFMTS"); + } + + m->encode_picture_header = speedhq_encode_picture_header; + s->encode_mb = speedhq_encode_mb; + + s->min_qcoeff = -2048; + s->max_qcoeff = 2047; + + s->intra_ac_vlc_length = + s->intra_ac_vlc_last_length = + s->intra_chroma_ac_vlc_length = + s->intra_chroma_ac_vlc_last_length = uni_speedhq_ac_vlc_len; + + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_mpeg12_dc_scale_table[3]; + + ret = ff_mpv_encode_init(avctx); + if (ret < 0) + return ret; + + ff_thread_once(&init_static_once, speedhq_init_static_data); + + return 0; } const FFCodec ff_speedhq_encoder = { @@ -294,15 +296,12 @@ const FFCodec ff_speedhq_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_SPEEDHQ, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(SpeedHQEncContext), - .init = ff_mpv_encode_init, + .init = speedhq_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .color_ranges = AVCOL_RANGE_MPEG, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P), }; diff --git a/libavcodec/speedhqenc.h b/libavcodec/speedhqenc.h index 0c52e6a38..568f82c76 100644 --- a/libavcodec/speedhqenc.h +++ b/libavcodec/speedhqenc.h @@ -29,17 +29,24 @@ #ifndef AVCODEC_SPEEDHQENC_H #define AVCODEC_SPEEDHQENC_H -#include +typedef struct MPVEncContext MPVEncContext; -#include "mpegvideo.h" +void ff_speedhq_end_slice(MPVEncContext *s); -int ff_speedhq_encode_init(MpegEncContext *s); -void ff_speedhq_encode_close(MpegEncContext *s); -void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]); +static inline int ff_speedhq_mb_rows_in_slice(int slice_num, int mb_height) +{ + return mb_height / 4 + (slice_num < (mb_height % 4)); +} -void ff_speedhq_encode_picture_header(MpegEncContext *s); -void ff_speedhq_end_slice(MpegEncContext *s); - -int ff_speedhq_mb_y_order_to_mb(int mb_y_order, int mb_height, int *first_in_slice); +static inline int ff_speedhq_mb_y_order_to_mb(int mb_y_order, int mb_height, int *first_in_slice) +{ + int slice_num = 0; + while (mb_y_order >= ff_speedhq_mb_rows_in_slice(slice_num, mb_height)) { + mb_y_order -= ff_speedhq_mb_rows_in_slice(slice_num, mb_height); + slice_num++; + } + *first_in_slice = (mb_y_order == 0); + return mb_y_order * 4 + slice_num; +} #endif /* AVCODEC_SPEEDHQENC_H */ diff --git a/libavcodec/speexdec.c b/libavcodec/speexdec.c index 2c14d7d04..6caf0d96a 100644 --- a/libavcodec/speexdec.c +++ b/libavcodec/speexdec.c @@ -54,6 +54,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/float_dsp.h" +#include "libavutil/intfloat.h" #include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" @@ -1298,7 +1299,7 @@ static int sb_decode(AVCodecContext *avctx, void *ptr_st, lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpc_size, sub, st->nb_subframes, 0.05f); lsp_to_lpc(interp_qlsp, ak, st->lpc_size); - /* Calculate reponse ratio between the low and high filter in the middle + /* Calculate response ratio between the low and high filter in the middle of the band (4000 Hz) */ st->pi_gain[sub] = 1.f; rh = 1.f; @@ -1424,10 +1425,10 @@ static int parse_speex_extradata(AVCodecContext *avctx, return AVERROR_INVALIDDATA; s->bitrate = bytestream_get_le32(&buf); s->frame_size = bytestream_get_le32(&buf); - if (s->frame_size < NB_FRAME_SIZE << (s->mode > 0) || - s->frame_size > INT32_MAX >> (s->mode > 0)) + if (s->frame_size < NB_FRAME_SIZE << (s->mode > 1) || + s->frame_size > INT32_MAX >> (s->mode > 1)) return AVERROR_INVALIDDATA; - s->frame_size <<= (s->mode > 0); + s->frame_size = FFMIN(s->frame_size << (s->mode > 1), NB_FRAME_SIZE << s->mode); s->vbr = bytestream_get_le32(&buf); s->frames_per_packet = bytestream_get_le32(&buf); if (s->frames_per_packet <= 0 || diff --git a/libavcodec/srtenc.c b/libavcodec/srtenc.c index a607beb99..7fd6bfee0 100644 --- a/libavcodec/srtenc.c +++ b/libavcodec/srtenc.c @@ -145,7 +145,7 @@ static void srt_text_cb(void *priv, const char *text, int len) static void srt_new_line_cb(void *priv, int forced) { - srt_print(priv, "\r\n"); + srt_print(priv, "\n"); } static void srt_style_cb(void *priv, char style, int close) @@ -275,7 +275,7 @@ static int text_encode_frame(AVCodecContext *avctx, return encode_frame(avctx, buf, bufsize, sub, &text_callbacks); } -static int srt_encode_close(AVCodecContext *avctx) +static av_cold int srt_encode_close(AVCodecContext *avctx) { SRTContext *s = avctx->priv_data; ff_ass_split_free(s->ass_ctx); diff --git a/libavcodec/sunrast.c b/libavcodec/sunrast.c index 9e49c4f27..cc27838f5 100644 --- a/libavcodec/sunrast.c +++ b/libavcodec/sunrast.c @@ -163,8 +163,10 @@ static int sunrast_decode_frame(AVCodecContext *avctx, AVFrame *p, x = 0; while (ptr != end && buf < buf_end) { run = 1; - if (buf_end - buf < 1) + if (buf_end - buf < 1) { + av_freep(&ptr2); return AVERROR_INVALIDDATA; + } if ((value = *buf++) == RLE_TRIGGER) { run = *buf++ + 1; diff --git a/libavcodec/sunrastenc.c b/libavcodec/sunrastenc.c index b2d57f723..9922dbd06 100644 --- a/libavcodec/sunrastenc.c +++ b/libavcodec/sunrastenc.c @@ -218,9 +218,8 @@ const FFCodec ff_sunrast_encoder = { .init = sunrast_encode_init, FF_CODEC_ENCODE_CB(sunrast_encode_frame), .p.priv_class = &sunrast_class, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, - AV_PIX_FMT_PAL8, - AV_PIX_FMT_GRAY8, - AV_PIX_FMT_MONOWHITE, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24, + AV_PIX_FMT_PAL8, + AV_PIX_FMT_GRAY8, + AV_PIX_FMT_MONOWHITE), }; diff --git a/libavcodec/svq1dec.c b/libavcodec/svq1dec.c index 3a508849a..9325c7599 100644 --- a/libavcodec/svq1dec.c +++ b/libavcodec/svq1dec.c @@ -32,6 +32,7 @@ * http://www.pcisys.net/~melanson/codecs/ */ +#include "libavutil/attributes.h" #include "libavutil/crc.h" #include "libavutil/mem.h" #include "libavutil/thread.h" @@ -851,7 +852,7 @@ static av_cold int svq1_decode_end(AVCodecContext *avctx) return 0; } -static void svq1_flush(AVCodecContext *avctx) +static av_cold void svq1_flush(AVCodecContext *avctx) { SVQ1Context *s = avctx->priv_data; diff --git a/libavcodec/svq1enc.c b/libavcodec/svq1enc.c index d969be25c..4855bed18 100644 --- a/libavcodec/svq1enc.c +++ b/libavcodec/svq1enc.c @@ -38,7 +38,6 @@ #include "h263enc.h" #include "internal.h" #include "mpegutils.h" -#include "packet_internal.h" #include "put_bits.h" #include "svq1.h" #include "svq1encdsp.h" @@ -58,11 +57,10 @@ typedef struct SVQ1EncContext { /* FIXME: Needed for motion estimation, should not be used for anything * else, the idea is to make the motion estimation eventually independent - * of MpegEncContext, so this will be removed then. */ - MpegEncContext m; + * of MPVEncContext, so this will be removed then. */ + MPVEncContext m; AVCodecContext *avctx; MECmpContext mecc; - HpelDSPContext hdsp; AVFrame *current_picture; AVFrame *last_picture; @@ -81,10 +79,6 @@ typedef struct SVQ1EncContext { int y_block_width; int y_block_height; - /* U & V plane (C planes) block dimensions */ - int c_block_width; - int c_block_height; - DECLARE_ALIGNED(16, int16_t, encoded_block_levels)[6][7][256]; uint16_t *mb_type; @@ -96,8 +90,6 @@ typedef struct SVQ1EncContext { uint8_t *scratchbuf; - int motion_est; - SVQ1EncDSPContext svq1encdsp; } SVQ1EncContext; @@ -291,13 +283,12 @@ static int encode_block(SVQ1EncContext *s, uint8_t *src, uint8_t *ref, return best_score; } -static void init_block_index(MpegEncContext *s){ +static void init_block_index(MpegEncContext *const s) +{ s->block_index[0]= s->b8_stride*(s->mb_y*2 ) + s->mb_x*2; s->block_index[1]= s->b8_stride*(s->mb_y*2 ) + 1 + s->mb_x*2; s->block_index[2]= s->b8_stride*(s->mb_y*2 + 1) + s->mb_x*2; s->block_index[3]= s->b8_stride*(s->mb_y*2 + 1) + 1 + s->mb_x*2; - s->block_index[4]= s->mb_stride*(s->mb_y + 1) + s->b8_stride*s->mb_height*2 + s->mb_x; - s->block_index[5]= s->mb_stride*(s->mb_y + s->mb_height + 2) + s->b8_stride*s->mb_height*2 + s->mb_x; } static int svq1_encode_plane(SVQ1EncContext *s, int plane, @@ -307,6 +298,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, unsigned char *decoded_plane, int width, int height, int src_stride, int stride) { + MpegEncContext *const s2 = &s->m.c; int x, y; int i; int block_width, block_height; @@ -325,61 +317,48 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, block_height = (height + 15) / 16; if (s->pict_type == AV_PICTURE_TYPE_P) { - s->m.avctx = s->avctx; - s->m.last_pic.data[0] = ref_plane; - s->m.linesize = - s->m.last_pic.linesize[0] = + s2->last_pic.data[0] = ref_plane; + s2->linesize = + s2->last_pic.linesize[0] = s->m.new_pic->linesize[0] = - s->m.cur_pic.linesize[0] = stride; - s->m.width = width; - s->m.height = height; - s->m.mb_width = block_width; - s->m.mb_height = block_height; - s->m.mb_stride = s->m.mb_width + 1; - s->m.b8_stride = 2 * s->m.mb_width + 1; - s->m.f_code = 1; - s->m.pict_type = s->pict_type; - s->m.motion_est = s->motion_est; - s->m.me.scene_change_score = 0; - // s->m.out_format = FMT_H263; - // s->m.unrestricted_mv = 1; - s->m.lambda = s->quality; - s->m.qscale = s->m.lambda * 139 + + s2->cur_pic.linesize[0] = stride; + s2->width = width; + s2->height = height; + s2->mb_width = block_width; + s2->mb_height = block_height; + s2->mb_stride = s2->mb_width + 1; + s2->b8_stride = 2 * s2->mb_width + 1; + s->m.f_code = 1; + s2->pict_type = s->pict_type; + s->m.me.scene_change_score = 0; + // s2->out_format = FMT_H263; + // s->m.me.unrestricted_mv = 1; + s->m.lambda = s->quality; + s2->qscale = s->m.lambda * 139 + FF_LAMBDA_SCALE * 64 >> FF_LAMBDA_SHIFT + 7; - s->m.lambda2 = s->m.lambda * s->m.lambda + + s->m.lambda2 = s->m.lambda * s->m.lambda + FF_LAMBDA_SCALE / 2 >> FF_LAMBDA_SHIFT; - if (!s->motion_val8[plane]) { - s->motion_val8[plane] = av_mallocz((s->m.b8_stride * - block_height * 2 + 2) * - 2 * sizeof(int16_t)); - s->motion_val16[plane] = av_mallocz((s->m.mb_stride * - (block_height + 2) + 1) * - 2 * sizeof(int16_t)); - if (!s->motion_val8[plane] || !s->motion_val16[plane]) - return AVERROR(ENOMEM); - } - s->m.mb_type = s->mb_type; // dummies, to avoid segfaults s->m.mb_mean = (uint8_t *)s->dummy; s->m.mb_var = (uint16_t *)s->dummy; s->m.mc_mb_var = (uint16_t *)s->dummy; - s->m.cur_pic.mb_type = s->dummy; + s2->cur_pic.mb_type = s->dummy; - s->m.cur_pic.motion_val[0] = s->motion_val8[plane] + 2; - s->m.p_mv_table = s->motion_val16[plane] + - s->m.mb_stride + 1; + s2->cur_pic.motion_val[0] = s->motion_val8[plane] + 2; + s->m.p_mv_table = s->motion_val16[plane] + + s2->mb_stride + 1; ff_me_init_pic(&s->m); - s->m.me.dia_size = s->avctx->dia_size; - s->m.first_slice_line = 1; + s->m.me.dia_size = s->avctx->dia_size; + s2->first_slice_line = 1; for (y = 0; y < block_height; y++) { s->m.new_pic->data[0] = src - y * 16 * stride; // ugly - s->m.mb_y = y; + s2->mb_y = y; for (i = 0; i < 16 && i + 16 * y < height; i++) { memcpy(&src[i * stride], &src_plane[(i + 16 * y) * src_stride], @@ -392,12 +371,12 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, 16 * block_width); for (x = 0; x < block_width; x++) { - s->m.mb_x = x; - init_block_index(&s->m); + s2->mb_x = x; + init_block_index(s2); ff_estimate_p_frame_motion(&s->m, x, y); } - s->m.first_slice_line = 0; + s2->first_slice_line = 0; } ff_fix_long_p_mvs(&s->m, CANDIDATE_MB_TYPE_INTRA); @@ -405,7 +384,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, CANDIDATE_MB_TYPE_INTER, 0); } - s->m.first_slice_line = 1; + s2->first_slice_line = 1; for (y = 0; y < block_height; y++) { for (i = 0; i < 16 && i + 16 * y < height; i++) { memcpy(&src[i * stride], &src_plane[(i + 16 * y) * src_stride], @@ -416,7 +395,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, for (; i < 16 && i + 16 * y < 16 * block_height; i++) memcpy(&src[i * stride], &src[(i - 1) * stride], 16 * block_width); - s->m.mb_y = y; + s2->mb_y = y; for (x = 0; x < block_width; x++) { uint8_t reorder_buffer[2][6][7 * 32]; int count[2][6]; @@ -431,11 +410,11 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, return -1; } - s->m.mb_x = x; - init_block_index(&s->m); + s2->mb_x = x; + init_block_index(s2); if (s->pict_type == AV_PICTURE_TYPE_I || - (s->m.mb_type[x + y * s->m.mb_stride] & + (s->m.mb_type[x + y * s2->mb_stride] & CANDIDATE_MB_TYPE_INTRA)) { for (i = 0; i < 6; i++) init_put_bits(&s->reorder_pb[i], reorder_buffer[0][i], @@ -444,8 +423,8 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, put_bits(&s->reorder_pb[5], SVQ1_BLOCK_INTRA_LEN, SVQ1_BLOCK_INTRA_CODE); score[0] = SVQ1_BLOCK_INTRA_LEN * lambda; } - score[0] += encode_block(s, src + 16 * x, NULL, temp, stride, - 5, 64, lambda, 1); + score[0] += encode_block(s, src + 16 * x, src + 16 * x /* unused */, + temp, stride, 5, 64, lambda, 1); for (i = 0; i < 6; i++) { count[0][i] = put_bits_count(&s->reorder_pb[i]); flush_put_bits(&s->reorder_pb[i]); @@ -459,8 +438,8 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, int mx, my, pred_x, pred_y, dxy; int16_t *motion_ptr; - motion_ptr = ff_h263_pred_motion(&s->m, 0, 0, &pred_x, &pred_y); - if (s->m.mb_type[x + y * s->m.mb_stride] & + motion_ptr = ff_h263_pred_motion(s2, 0, 0, &pred_x, &pred_y); + if (s->m.mb_type[x + y * s2->mb_stride] & CANDIDATE_MB_TYPE_INTER) { for (i = 0; i < 6; i++) init_put_bits(&s->reorder_pb[i], reorder_buffer[1][i], @@ -480,10 +459,10 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, dxy = (mx & 1) + 2 * (my & 1); - s->hdsp.put_pixels_tab[0][dxy](temp + 16*stride, - ref + (mx >> 1) + - stride * (my >> 1), - stride, 16); + s2->hdsp.put_pixels_tab[0][dxy](temp + 16*stride, + ref + (mx >> 1) + + stride * (my >> 1), + stride, 16); score[1] += encode_block(s, src + 16 * x, temp + 16*stride, decoded, stride, 5, 64, lambda, 0); @@ -494,7 +473,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, score[2] += SVQ1_BLOCK_SKIP_LEN * lambda; if (score[2] < score[best] && mx == 0 && my == 0) { best = 2; - s->hdsp.put_pixels_tab[0][0](decoded, ref, stride, 16); + s2->hdsp.put_pixels_tab[0][0](decoded, ref, stride, 16); put_bits(pb, SVQ1_BLOCK_SKIP_LEN, SVQ1_BLOCK_SKIP_CODE); } } @@ -509,10 +488,10 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, motion_ptr[1] = motion_ptr[2] = motion_ptr[3] = - motion_ptr[0 + 2 * s->m.b8_stride] = - motion_ptr[1 + 2 * s->m.b8_stride] = - motion_ptr[2 + 2 * s->m.b8_stride] = - motion_ptr[3 + 2 * s->m.b8_stride] = 0; + motion_ptr[0 + 2 * s2->b8_stride] = + motion_ptr[1 + 2 * s2->b8_stride] = + motion_ptr[2 + 2 * s2->b8_stride] = + motion_ptr[3 + 2 * s2->b8_stride] = 0; } } @@ -523,9 +502,9 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, ff_copy_bits(pb, reorder_buffer[best][i], count[best][i]); if (best == 0) - s->hdsp.put_pixels_tab[0][0](decoded, temp, stride, 16); + s2->hdsp.put_pixels_tab[0][0](decoded, temp, stride, 16); } - s->m.first_slice_line = 0; + s2->first_slice_line = 0; } return 0; } @@ -541,14 +520,10 @@ static av_cold int svq1_encode_end(AVCodecContext *avctx) avctx->frame_num)); av_freep(&s->m.me.scratchpad); - av_freep(&s->m.me.map); av_freep(&s->mb_type); av_freep(&s->dummy); av_freep(&s->scratchbuf); - s->m.mb_type = NULL; - ff_mpv_common_end(&s->m); - for (i = 0; i < 3; i++) { av_freep(&s->motion_val8[i]); av_freep(&s->motion_val16[i]); @@ -584,7 +559,7 @@ static av_cold int svq1_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - ff_hpeldsp_init(&s->hdsp, avctx->flags); + ff_hpeldsp_init(&s->m.c.hdsp, avctx->flags); ff_me_cmp_init(&s->mecc, avctx); ret = ff_me_init(&s->m.me, avctx, &s->mecc, 0); if (ret < 0) @@ -596,6 +571,15 @@ static av_cold int svq1_encode_init(AVCodecContext *avctx) if (!s->current_picture || !s->last_picture) { return AVERROR(ENOMEM); } + ret = ff_encode_alloc_frame(avctx, s->current_picture); + if (ret < 0) + return ret; + ret = ff_encode_alloc_frame(avctx, s->last_picture); + if (ret < 0) + return ret; + s->scratchbuf = av_malloc_array(s->current_picture->linesize[0], 16 * 3); + if (!s->scratchbuf) + return AVERROR(ENOMEM); s->frame_width = avctx->width; s->frame_height = avctx->height; @@ -603,17 +587,23 @@ static av_cold int svq1_encode_init(AVCodecContext *avctx) s->y_block_width = (s->frame_width + 15) / 16; s->y_block_height = (s->frame_height + 15) / 16; - s->c_block_width = (s->frame_width / 4 + 15) / 16; - s->c_block_height = (s->frame_height / 4 + 15) / 16; - s->avctx = avctx; - s->m.avctx = avctx; + s->m.c.avctx = avctx; - if ((ret = ff_mpv_common_init(&s->m)) < 0) { - return ret; + for (size_t plane = 0; plane < FF_ARRAY_ELEMS(s->motion_val16); ++plane) { + const int shift = plane ? 2 : 0; + unsigned block_height = ((s->frame_height >> shift) + 15U) / 16; + unsigned block_width = ((s->frame_width >> shift) + 15U) / 16; + + s->motion_val8[plane] = av_calloc((2 * block_width + 1) * block_height * 2 + 2, + 2 * sizeof(int16_t)); + s->motion_val16[plane] = av_calloc((block_width + 1) * (block_height + 2) + 1, + 2 * sizeof(int16_t)); + if (!s->motion_val8[plane] || !s->motion_val16[plane]) + return AVERROR(ENOMEM); } - s->m.picture_structure = PICT_FRAME; + s->m.c.picture_structure = PICT_FRAME; s->m.me.temp = s->m.me.scratchpad = av_mallocz((avctx->width + 64) * 2 * 16 * 2 * sizeof(uint8_t)); @@ -621,17 +611,15 @@ static av_cold int svq1_encode_init(AVCodecContext *avctx) s->y_block_height * sizeof(int16_t)); s->dummy = av_mallocz((s->y_block_width + 1) * s->y_block_height * sizeof(int32_t)); - s->m.me.map = av_mallocz(2 * ME_MAP_SIZE * sizeof(*s->m.me.map)); s->m.new_pic = av_frame_alloc(); - if (!s->m.me.scratchpad || !s->m.me.map || + if (!s->m.me.scratchpad || !s->mb_type || !s->dummy || !s->m.new_pic) return AVERROR(ENOMEM); - s->m.me.score_map = s->m.me.map + ME_MAP_SIZE; ff_svq1enc_init(&s->svq1encdsp); - ff_h263_encode_init(&s->m); // mv_penalty + s->m.me.mv_penalty = ff_h263_get_mv_penalty(); return write_ident(avctx, s->avctx->flags & AV_CODEC_FLAG_BITEXACT ? "Lavc" : LIBAVCODEC_IDENT); } @@ -648,27 +636,6 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt, if (ret < 0) return ret; - if (avctx->pix_fmt != AV_PIX_FMT_YUV410P) { - av_log(avctx, AV_LOG_ERROR, "unsupported pixel format\n"); - return -1; - } - - if (!s->current_picture->data[0]) { - if ((ret = ff_encode_alloc_frame(avctx, s->current_picture)) < 0) { - return ret; - } - } - if (!s->last_picture->data[0]) { - ret = ff_encode_alloc_frame(avctx, s->last_picture); - if (ret < 0) - return ret; - } - if (!s->scratchbuf) { - s->scratchbuf = av_malloc_array(s->current_picture->linesize[0], 16 * 3); - if (!s->scratchbuf) - return AVERROR(ENOMEM); - } - FFSWAP(AVFrame*, s->current_picture, s->last_picture); if (avctx->gop_size && (avctx->frame_num % avctx->gop_size)) @@ -677,7 +644,7 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt, s->pict_type = AV_PICTURE_TYPE_I; s->quality = pict->quality; - ff_side_data_set_encoder_stats(pkt, pict->quality, NULL, 0, s->pict_type); + ff_encode_add_stats_side_data(pkt, pict->quality, NULL, 0, s->pict_type); init_put_bits(&pb, pkt->data, pkt->size); svq1_write_header(s, &pb, s->pict_type); @@ -691,15 +658,8 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt, pict->linesize[i], s->current_picture->linesize[i]); emms_c(); - if (ret < 0) { - int j; - for (j = 0; j < i; j++) { - av_freep(&s->motion_val8[j]); - av_freep(&s->motion_val16[j]); - } - av_freep(&s->scratchbuf); - return -1; - } + if (ret < 0) + return ret; } // align_put_bits(&pb); @@ -719,7 +679,7 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt, #define OFFSET(x) offsetof(struct SVQ1EncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "motion-est", "Motion estimation algorithm", OFFSET(motion_est), AV_OPT_TYPE_INT, { .i64 = FF_ME_EPZS }, FF_ME_ZERO, FF_ME_XONE, VE, .unit = "motion-est"}, + { "motion-est", "Motion estimation algorithm", OFFSET(m.me.motion_est), AV_OPT_TYPE_INT, { .i64 = FF_ME_EPZS }, FF_ME_ZERO, FF_ME_XONE, VE, .unit = "motion-est"}, { "zero", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_ZERO }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion-est" }, { "epzs", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_EPZS }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion-est" }, { "xone", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_XONE }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion-est" }, @@ -745,8 +705,7 @@ const FFCodec ff_svq1_encoder = { .init = svq1_encode_init, FF_CODEC_ENCODE_CB(svq1_encode_frame), .close = svq1_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV410P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV410P), .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/svq1encdsp.h b/libavcodec/svq1encdsp.h index 751b5eed8..dcc8e825a 100644 --- a/libavcodec/svq1encdsp.h +++ b/libavcodec/svq1encdsp.h @@ -52,7 +52,7 @@ static inline void ff_svq1enc_init(SVQ1EncDSPContext *c) ff_svq1enc_init_ppc(c); #elif ARCH_RISCV ff_svq1enc_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_svq1enc_init_x86(c); #endif } diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c index 6319e9b02..296e81f32 100644 --- a/libavcodec/svq3.c +++ b/libavcodec/svq3.c @@ -71,13 +71,14 @@ * svq3 decoder. */ +#define NUM_PICS 3 + typedef struct SVQ3Frame { AVFrame *f; - int16_t (*motion_val_buf[2])[2]; int16_t (*motion_val[2])[2]; - uint32_t *mb_type_buf, *mb_type; + uint32_t *mb_type; } SVQ3Frame; typedef struct SVQ3Context { @@ -103,7 +104,6 @@ typedef struct SVQ3Context { int adaptive_quant; int h_edge_pos; int v_edge_pos; - int last_frame_output; int slice_num; int qscale; int cbp; @@ -142,7 +142,10 @@ typedef struct SVQ3Context { DECLARE_ALIGNED(8, uint8_t, non_zero_count_cache)[15 * 8]; uint32_t dequant4_coeff[QP_MAX_NUM + 1][16]; int block_offset[2 * (16 * 3)]; - SVQ3Frame frames[3]; + SVQ3Frame frames[NUM_PICS]; + + uint32_t *mb_type_buf; + int16_t (*motion_val_buf)[2]; } SVQ3Context; #define FULLPEL_MODE 1 @@ -501,6 +504,7 @@ static inline int svq3_mc_dir(SVQ3Context *s, int size, int mode, int dir, int avg) { int i, j, k, mx, my, dx, dy, x, y; + // 0->16x16,1->8x16,2->16x8,3->8x8,4->4x8,5->8x4,6->4x4 const int part_width = ((size & 5) == 4) ? 4 : 16 >> (size & 1); const int part_height = 16 >> ((unsigned)(size + 1) / 3); const int extra_width = (mode == PREDICT_MODE) ? -16 * 6 : 0; @@ -692,10 +696,10 @@ static void hl_decode_mb(SVQ3Context *s) if (s->cbp & 0x30) { uint8_t *dest[2] = { dest_cb, dest_cr }; - s->h264dsp.h264_chroma_dc_dequant_idct(s->mb + 16 * 16 * 1, - s->dequant4_coeff[4][0]); - s->h264dsp.h264_chroma_dc_dequant_idct(s->mb + 16 * 16 * 2, - s->dequant4_coeff[4][0]); + s->h264dsp.chroma_dc_dequant_idct(s->mb + 16 * 16 * 1, + s->dequant4_coeff[4][0]); + s->h264dsp.chroma_dc_dequant_idct(s->mb + 16 * 16 * 2, + s->dequant4_coeff[4][0]); for (j = 1; j < 3; j++) { for (i = j * 16; i < j * 16 + 4; i++) if (s->non_zero_count_cache[scan8[i]] || s->mb[i * 16]) { @@ -1114,14 +1118,139 @@ static void init_dequant4_coeff_table(SVQ3Context *s) } } +static av_cold int svq3_decode_extradata(AVCodecContext *avctx, SVQ3Context *s, + int seqh_offset) +{ + const uint8_t *extradata = avctx->extradata + seqh_offset; + unsigned int size = AV_RB32(extradata + 4); + GetBitContext gb; + int ret; + + if (size > avctx->extradata_size - seqh_offset - 8) + return AVERROR_INVALIDDATA; + extradata += 8; + init_get_bits(&gb, extradata, size * 8); + + /* 'frame size code' and optional 'width, height' */ + int frame_size_code = get_bits(&gb, 3); + int w, h; + switch (frame_size_code) { + case 0: + w = 160; + h = 120; + break; + case 1: + w = 128; + h = 96; + break; + case 2: + w = 176; + h = 144; + break; + case 3: + w = 352; + h = 288; + break; + case 4: + w = 704; + h = 576; + break; + case 5: + w = 240; + h = 180; + break; + case 6: + w = 320; + h = 240; + break; + case 7: + w = get_bits(&gb, 12); + h = get_bits(&gb, 12); + break; + } + ret = ff_set_dimensions(avctx, w, h); + if (ret < 0) + return ret; + + s->halfpel_flag = get_bits1(&gb); + s->thirdpel_flag = get_bits1(&gb); + + /* unknown fields */ + int unk0 = get_bits1(&gb); + int unk1 = get_bits1(&gb); + int unk2 = get_bits1(&gb); + int unk3 = get_bits1(&gb); + + s->low_delay = get_bits1(&gb); + avctx->has_b_frames = !s->low_delay; + + /* unknown field */ + int unk4 = get_bits1(&gb); + + av_log(avctx, AV_LOG_DEBUG, "Unknown fields %d %d %d %d %d\n", + unk0, unk1, unk2, unk3, unk4); + + if (skip_1stop_8data_bits(&gb) < 0) + return AVERROR_INVALIDDATA; + + s->has_watermark = get_bits1(&gb); + + if (!s->has_watermark) + return 0; + +#if CONFIG_ZLIB + unsigned watermark_width = get_interleaved_ue_golomb(&gb); + unsigned watermark_height = get_interleaved_ue_golomb(&gb); + int u1 = get_interleaved_ue_golomb(&gb); + int u2 = get_bits(&gb, 8); + int u3 = get_bits(&gb, 2); + int u4 = get_interleaved_ue_golomb(&gb); + unsigned long buf_len = watermark_width * + watermark_height * 4; + int offset = get_bits_count(&gb) + 7 >> 3; + + if (watermark_height <= 0 || + get_bits_left(&gb) <= 0 || + (uint64_t)watermark_width * 4 > UINT_MAX / watermark_height) + return AVERROR_INVALIDDATA; + + av_log(avctx, AV_LOG_DEBUG, "watermark size: %ux%u\n", + watermark_width, watermark_height); + av_log(avctx, AV_LOG_DEBUG, + "u1: %x u2: %x u3: %x compressed data size: %d offset: %d\n", + u1, u2, u3, u4, offset); + + uint8_t *buf = av_malloc(buf_len); + if (!buf) + return AVERROR(ENOMEM); + + if (uncompress(buf, &buf_len, extradata + offset, + size - offset) != Z_OK) { + av_log(avctx, AV_LOG_ERROR, + "could not uncompress watermark logo\n"); + av_free(buf); + return AVERROR_EXTERNAL; + } + s->watermark_key = av_bswap16(av_crc(av_crc_get_table(AV_CRC_16_CCITT), 0, buf, buf_len)); + + s->watermark_key = s->watermark_key << 16 | s->watermark_key; + av_log(avctx, AV_LOG_DEBUG, + "watermark key %#"PRIx32"\n", s->watermark_key); + av_free(buf); + + return 0; +#else + av_log(avctx, AV_LOG_ERROR, + "this svq3 file contains watermark which need zlib support compiled in\n"); + return AVERROR(ENOSYS); +#endif +} + static av_cold int svq3_decode_init(AVCodecContext *avctx) { SVQ3Context *s = avctx->priv_data; int m, x, y; unsigned char *extradata; - unsigned char *extradata_end; - unsigned int size; - int marker_found = 0; int ret; s->cur_pic = &s->frames[0]; @@ -1154,139 +1283,19 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx) /* prowl for the "SEQH" marker in the extradata */ extradata = (unsigned char *)avctx->extradata; - extradata_end = avctx->extradata + avctx->extradata_size; if (extradata) { for (m = 0; m + 8 < avctx->extradata_size; m++) { if (!memcmp(extradata, "SEQH", 4)) { - marker_found = 1; + /* if a match was found, parse the extra data */ + ret = svq3_decode_extradata(avctx, s, m); + if (ret < 0) + return ret; break; } extradata++; } } - /* if a match was found, parse the extra data */ - if (marker_found) { - GetBitContext gb; - int frame_size_code; - int unk0, unk1, unk2, unk3, unk4; - int w,h; - - size = AV_RB32(&extradata[4]); - if (size > extradata_end - extradata - 8) - return AVERROR_INVALIDDATA; - init_get_bits(&gb, extradata + 8, size * 8); - - /* 'frame size code' and optional 'width, height' */ - frame_size_code = get_bits(&gb, 3); - switch (frame_size_code) { - case 0: - w = 160; - h = 120; - break; - case 1: - w = 128; - h = 96; - break; - case 2: - w = 176; - h = 144; - break; - case 3: - w = 352; - h = 288; - break; - case 4: - w = 704; - h = 576; - break; - case 5: - w = 240; - h = 180; - break; - case 6: - w = 320; - h = 240; - break; - case 7: - w = get_bits(&gb, 12); - h = get_bits(&gb, 12); - break; - } - ret = ff_set_dimensions(avctx, w, h); - if (ret < 0) - return ret; - - s->halfpel_flag = get_bits1(&gb); - s->thirdpel_flag = get_bits1(&gb); - - /* unknown fields */ - unk0 = get_bits1(&gb); - unk1 = get_bits1(&gb); - unk2 = get_bits1(&gb); - unk3 = get_bits1(&gb); - - s->low_delay = get_bits1(&gb); - - /* unknown field */ - unk4 = get_bits1(&gb); - - av_log(avctx, AV_LOG_DEBUG, "Unknown fields %d %d %d %d %d\n", - unk0, unk1, unk2, unk3, unk4); - - if (skip_1stop_8data_bits(&gb) < 0) - return AVERROR_INVALIDDATA; - - s->has_watermark = get_bits1(&gb); - avctx->has_b_frames = !s->low_delay; - if (s->has_watermark) { -#if CONFIG_ZLIB - unsigned watermark_width = get_interleaved_ue_golomb(&gb); - unsigned watermark_height = get_interleaved_ue_golomb(&gb); - int u1 = get_interleaved_ue_golomb(&gb); - int u2 = get_bits(&gb, 8); - int u3 = get_bits(&gb, 2); - int u4 = get_interleaved_ue_golomb(&gb); - unsigned long buf_len = watermark_width * - watermark_height * 4; - int offset = get_bits_count(&gb) + 7 >> 3; - uint8_t *buf; - - if (watermark_height <= 0 || - get_bits_left(&gb) <= 0 || - (uint64_t)watermark_width * 4 > UINT_MAX / watermark_height) - return AVERROR_INVALIDDATA; - - buf = av_malloc(buf_len); - if (!buf) - return AVERROR(ENOMEM); - - av_log(avctx, AV_LOG_DEBUG, "watermark size: %ux%u\n", - watermark_width, watermark_height); - av_log(avctx, AV_LOG_DEBUG, - "u1: %x u2: %x u3: %x compressed data size: %d offset: %d\n", - u1, u2, u3, u4, offset); - if (uncompress(buf, &buf_len, extradata + 8 + offset, - size - offset) != Z_OK) { - av_log(avctx, AV_LOG_ERROR, - "could not uncompress watermark logo\n"); - av_free(buf); - return -1; - } - s->watermark_key = av_bswap16(av_crc(av_crc_get_table(AV_CRC_16_CCITT), 0, buf, buf_len)); - - s->watermark_key = s->watermark_key << 16 | s->watermark_key; - av_log(avctx, AV_LOG_DEBUG, - "watermark key %#"PRIx32"\n", s->watermark_key); - av_free(buf); -#else - av_log(avctx, AV_LOG_ERROR, - "this svq3 file contains watermark which need zlib support compiled in\n"); - return AVERROR(ENOSYS); -#endif - } - } - s->mb_width = (avctx->width + 15) / 16; s->mb_height = (avctx->height + 15) / 16; s->mb_stride = s->mb_width + 1; @@ -1295,6 +1304,34 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx) s->h_edge_pos = s->mb_width * 16; s->v_edge_pos = s->mb_height * 16; + const unsigned big_mb_num = s->mb_stride * (s->mb_height + 2) + 1; + + s->mb_type_buf = av_calloc(big_mb_num, NUM_PICS * sizeof(*s->mb_type_buf)); + if (!s->mb_type_buf) + return AVERROR(ENOMEM); + uint32_t *mb_type_buf = s->mb_type_buf + 2 * s->mb_stride + 1; + + const unsigned b4_stride = s->mb_width * 4 + 1; + const unsigned b4_array_size = b4_stride * s->mb_height * 4; + const unsigned motion_val_buf_size = b4_array_size + 4; + + s->motion_val_buf = av_calloc(motion_val_buf_size, + NUM_PICS * 2 * sizeof(*s->motion_val_buf)); + if (!s->motion_val_buf) + return AVERROR(ENOMEM); + int16_t (*motion_val_buf)[2] = s->motion_val_buf + 4; + + for (size_t i = 0; i < NUM_PICS; ++i) { + SVQ3Frame *const pic = &s->frames[i]; + + pic->mb_type = mb_type_buf; + mb_type_buf += big_mb_num; + for (size_t j = 0; j < FF_ARRAY_ELEMS(pic->motion_val); ++j) { + pic->motion_val[j] = motion_val_buf; + motion_val_buf += motion_val_buf_size; + } + } + s->intra4x4_pred_mode = av_mallocz(s->mb_stride * 2 * 8); if (!s->intra4x4_pred_mode) return AVERROR(ENOMEM); @@ -1316,49 +1353,14 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx) return 0; } -static void free_picture(SVQ3Frame *pic) -{ - int i; - for (i = 0; i < 2; i++) { - av_freep(&pic->motion_val_buf[i]); - } - av_freep(&pic->mb_type_buf); - - av_frame_unref(pic->f); -} - static int get_buffer(AVCodecContext *avctx, SVQ3Frame *pic) { SVQ3Context *s = avctx->priv_data; - const int big_mb_num = s->mb_stride * (s->mb_height + 1) + 1; - const int b4_stride = s->mb_width * 4 + 1; - const int b4_array_size = b4_stride * s->mb_height * 4; - int ret; - - if (!pic->motion_val_buf[0]) { - int i; - - pic->mb_type_buf = av_calloc(big_mb_num + s->mb_stride, sizeof(uint32_t)); - if (!pic->mb_type_buf) - return AVERROR(ENOMEM); - pic->mb_type = pic->mb_type_buf + 2 * s->mb_stride + 1; - - for (i = 0; i < 2; i++) { - pic->motion_val_buf[i] = av_calloc(b4_array_size + 4, 2 * sizeof(int16_t)); - if (!pic->motion_val_buf[i]) { - ret = AVERROR(ENOMEM); - goto fail; - } - - pic->motion_val[i] = pic->motion_val_buf[i] + 4; - } - } - - ret = ff_get_buffer(avctx, pic->f, - (s->pict_type != AV_PICTURE_TYPE_B) ? - AV_GET_BUFFER_FLAG_REF : 0); + int ret = ff_get_buffer(avctx, pic->f, + (s->pict_type != AV_PICTURE_TYPE_B) ? + AV_GET_BUFFER_FLAG_REF : 0); if (ret < 0) - goto fail; + return ret; if (!s->edge_emu_buffer) { s->edge_emu_buffer = av_calloc(pic->f->linesize[0], 17); @@ -1367,9 +1369,23 @@ static int get_buffer(AVCodecContext *avctx, SVQ3Frame *pic) } return 0; -fail: - free_picture(pic); - return ret; +} + +static av_cold int alloc_dummy_frame(AVCodecContext *avctx, SVQ3Frame *pic) +{ + av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); + av_frame_unref(pic->f); + int ret = get_buffer(avctx, pic); + if (ret < 0) + return ret; + + memset(pic->f->data[0], 0, avctx->height * pic->f->linesize[0]); + memset(pic->f->data[1], 0x80, (avctx->height / 2) * + pic->f->linesize[1]); + memset(pic->f->data[2], 0x80, (avctx->height / 2) * + pic->f->linesize[2]); + + return 0; } static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe, @@ -1382,11 +1398,8 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe, /* special case for last picture */ if (buf_size == 0) { - if (s->next_pic->f->data[0] && !s->low_delay && !s->last_frame_output) { - ret = av_frame_ref(rframe, s->next_pic->f); - if (ret < 0) - return ret; - s->last_frame_output = 1; + if (s->next_pic->f->data[0] && !s->low_delay) { + av_frame_move_ref(rframe, s->next_pic->f); *got_frame = 1; } return 0; @@ -1398,8 +1411,9 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (ret < 0) return ret; - if (svq3_decode_slice_header(avctx)) - return -1; + ret = svq3_decode_slice_header(avctx); + if (ret < 0) + return ret; if (avpkt->size < s->mb_width * s->mb_height / 8) return AVERROR_INVALIDDATA; @@ -1435,29 +1449,15 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (s->pict_type != AV_PICTURE_TYPE_I) { if (!s->last_pic->f->data[0]) { - av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); - av_frame_unref(s->last_pic->f); - ret = get_buffer(avctx, s->last_pic); + ret = alloc_dummy_frame(avctx, s->last_pic); if (ret < 0) return ret; - memset(s->last_pic->f->data[0], 0, avctx->height * s->last_pic->f->linesize[0]); - memset(s->last_pic->f->data[1], 0x80, (avctx->height / 2) * - s->last_pic->f->linesize[1]); - memset(s->last_pic->f->data[2], 0x80, (avctx->height / 2) * - s->last_pic->f->linesize[2]); } if (s->pict_type == AV_PICTURE_TYPE_B && !s->next_pic->f->data[0]) { - av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); - av_frame_unref(s->next_pic->f); - ret = get_buffer(avctx, s->next_pic); + ret = alloc_dummy_frame(avctx, s->next_pic); if (ret < 0) return ret; - memset(s->next_pic->f->data[0], 0, avctx->height * s->next_pic->f->linesize[0]); - memset(s->next_pic->f->data[1], 0x80, (avctx->height / 2) * - s->next_pic->f->linesize[1]); - memset(s->next_pic->f->data[2], 0x80, (avctx->height / 2) * - s->next_pic->f->linesize[2]); } } @@ -1512,8 +1512,9 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (((get_bits_count(&s->gb_slice) & 7) == 0 || show_bits(&s->gb_slice, get_bits_left(&s->gb_slice) & 7) == 0)) { - if (svq3_decode_slice_header(avctx)) - return -1; + ret = svq3_decode_slice_header(avctx); + if (ret < 0) + return ret; } if (s->slice_type != s->pict_type) { avpriv_request_sample(avctx, "non constant slice type"); @@ -1583,10 +1584,10 @@ static av_cold int svq3_decode_end(AVCodecContext *avctx) { SVQ3Context *s = avctx->priv_data; - for (int i = 0; i < FF_ARRAY_ELEMS(s->frames); i++) { - free_picture(&s->frames[i]); + for (int i = 0; i < NUM_PICS; i++) av_frame_free(&s->frames[i].f); - } + av_freep(&s->motion_val_buf); + av_freep(&s->mb_type_buf); av_freep(&s->slice_buf); av_freep(&s->intra4x4_pred_mode); av_freep(&s->edge_emu_buffer); diff --git a/libavcodec/synth_filter.c b/libavcodec/synth_filter.c index f90c6be7a..82a2f812b 100644 --- a/libavcodec/synth_filter.c +++ b/libavcodec/synth_filter.c @@ -180,7 +180,7 @@ av_cold void ff_synth_filter_init(SynthFilterContext *c) ff_synth_filter_init_aarch64(c); #elif ARCH_ARM ff_synth_filter_init_arm(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_synth_filter_init_x86(c); #endif } diff --git a/libavcodec/tableprint_vlc.h b/libavcodec/tableprint_vlc.h index e42bf08a7..e7c676457 100644 --- a/libavcodec/tableprint_vlc.h +++ b/libavcodec/tableprint_vlc.h @@ -26,6 +26,7 @@ #define AVUTIL_LOG_H #define av_log(a, ...) while(0) #define ff_dlog(a, ...) while(0) +#define ff_tlog(a, ...) while(0) #define AVUTIL_MEM_H #define av_mallocz(s) NULL #define av_malloc_array(a, b) NULL diff --git a/libavcodec/tak_parser.c b/libavcodec/tak_parser.c index 7f5f5314a..060a90fac 100644 --- a/libavcodec/tak_parser.c +++ b/libavcodec/tak_parser.c @@ -27,6 +27,7 @@ #define CACHED_BITSTREAM_READER !ARCH_X86_32 #define BITSTREAM_READER_LE #include "parser.h" +#include "parser_internal.h" #include "tak.h" typedef struct TAKParseContext { @@ -123,9 +124,9 @@ fail: return buf_size + consumed; } -const AVCodecParser ff_tak_parser = { - .codec_ids = { AV_CODEC_ID_TAK }, +const FFCodecParser ff_tak_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_TAK), .priv_data_size = sizeof(TAKParseContext), - .parser_parse = tak_parse, - .parser_close = ff_parse_close, + .parse = tak_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/takdec.c b/libavcodec/takdec.c index 84c19f648..42a43e869 100644 --- a/libavcodec/takdec.c +++ b/libavcodec/takdec.c @@ -953,8 +953,4 @@ const FFCodec ff_tak_decoder = { FF_CODEC_DECODE_CB(tak_decode_frame), UPDATE_THREAD_CONTEXT(update_thread_context), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/takdsp.c b/libavcodec/takdsp.c index 51b6658de..a7e281b6e 100644 --- a/libavcodec/takdsp.c +++ b/libavcodec/takdsp.c @@ -79,7 +79,7 @@ av_cold void ff_takdsp_init(TAKDSPContext *c) #if ARCH_RISCV ff_takdsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_takdsp_init_x86(c); #endif } diff --git a/libavcodec/targa.c b/libavcodec/targa.c index 59fdc428d..7e016ea4a 100644 --- a/libavcodec/targa.c +++ b/libavcodec/targa.c @@ -249,11 +249,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, } break; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - p->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } } diff --git a/libavcodec/targaenc.c b/libavcodec/targaenc.c index 8f496c62b..04422013e 100644 --- a/libavcodec/targaenc.c +++ b/libavcodec/targaenc.c @@ -215,8 +215,6 @@ const FFCodec ff_targa_encoder = { .p.priv_class = &targa_class, .init = targa_encode_init, FF_CODEC_ENCODE_CB(targa_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB555LE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB555LE, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8), }; diff --git a/libavcodec/tdsc.c b/libavcodec/tdsc.c index b65f81a4a..763ad5cc2 100644 --- a/libavcodec/tdsc.c +++ b/libavcodec/tdsc.c @@ -36,6 +36,7 @@ #include #include +#include "libavutil/attributes_internal.h" #include "libavutil/imgutils.h" #include "libavutil/mem.h" @@ -95,7 +96,6 @@ static av_cold int tdsc_close(AVCodecContext *avctx) static av_cold int tdsc_init(AVCodecContext *avctx) { TDSCContext *ctx = avctx->priv_data; - const AVCodec *codec; int ret; avctx->pix_fmt = AV_PIX_FMT_BGR24; @@ -120,16 +120,14 @@ static av_cold int tdsc_init(AVCodecContext *avctx) return AVERROR(ENOMEM); /* Prepare everything needed for JPEG decoding */ - codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG); - if (!codec) - return AVERROR_BUG; - ctx->jpeg_avctx = avcodec_alloc_context3(codec); + EXTERN const FFCodec ff_mjpeg_decoder; + ctx->jpeg_avctx = avcodec_alloc_context3(&ff_mjpeg_decoder.p); if (!ctx->jpeg_avctx) return AVERROR(ENOMEM); ctx->jpeg_avctx->flags = avctx->flags; ctx->jpeg_avctx->flags2 = avctx->flags2; ctx->jpeg_avctx->idct_algo = avctx->idct_algo; - ret = avcodec_open2(ctx->jpeg_avctx, codec, NULL); + ret = avcodec_open2(ctx->jpeg_avctx, NULL, NULL); if (ret < 0) return ret; diff --git a/libavcodec/tests/apv.c b/libavcodec/tests/apv.c new file mode 100644 index 000000000..365a395af --- /dev/null +++ b/libavcodec/tests/apv.c @@ -0,0 +1,449 @@ +/* + * 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/lfg.h" +#include "libavutil/random_seed.h" + +#include "libavcodec/apv_decode.h" +#include "libavcodec/apv_dsp.h" +#include "libavcodec/put_bits.h" + + +// Whole file included here to get internal symbols. +#include "libavcodec/apv_entropy.c" + + +// As defined in 7.1.4, for testing. +// Adds a check to limit loop after reading 16 zero bits to avoid +// getting stuck reading a stream of zeroes forever (this matches +// the behaviour of the faster version). + +static unsigned int apv_read_vlc_spec(GetBitContext *gbc, int k_param) +{ + unsigned int symbol_value = 0; + int parse_exp_golomb = 1; + int k = k_param; + int stop_loop = 0; + + if(get_bits1(gbc) == 1) { + parse_exp_golomb = 0; + } else { + if (get_bits1(gbc) == 0) { + symbol_value += (1 << k); + parse_exp_golomb = 0; + } else { + symbol_value += (2 << k); + parse_exp_golomb = 1; + } + } + if (parse_exp_golomb) { + int read_limit = 0; + do { + if (get_bits1(gbc) == 1) { + stop_loop = 1; + } else { + if (++read_limit == 16) + break; + symbol_value += (1 << k); + k++; + } + } while (!stop_loop); + } + if (k > 0) + symbol_value += get_bits(gbc, k); + + return symbol_value; +} + +// As defined in 7.2.4, for testing. + +static void apv_write_vlc_spec(PutBitContext *pbc, + unsigned int symbol_val, int k_param) +{ + int prefix_vlc_table[3][2] = {{1, 0}, {0, 0}, {0, 1}}; + + unsigned int symbol_value = symbol_val; + int val_prefix_vlc = av_clip(symbol_val >> k_param, 0, 2); + int bit_count = 0; + int k = k_param; + + while (symbol_value >= (1 << k)) { + symbol_value -= (1 << k); + if (bit_count < 2) + put_bits(pbc, 1, prefix_vlc_table[val_prefix_vlc][bit_count]); + else + put_bits(pbc, 1, 0); + if (bit_count >= 2) + ++k; + ++bit_count; + } + + if(bit_count < 2) + put_bits(pbc, 1, prefix_vlc_table[val_prefix_vlc][bit_count]); + else + put_bits(pbc, 1, 1); + + if(k > 0) + put_bits(pbc, k, symbol_value); +} + +// Old version of ff_apv_entropy_decode_block, for test comparison. + +static int apv_entropy_decode_block(int16_t *restrict coeff, + GetBitContext *restrict gbc, + APVEntropyState *restrict state) +{ + const APVVLCLUT *lut = state->decode_lut; + + // DC coefficient. + { + int abs_dc_coeff_diff; + int sign_dc_coeff_diff; + int dc_coeff; + + abs_dc_coeff_diff = apv_read_vlc(gbc, state->prev_k_dc, lut); + + if (abs_dc_coeff_diff > 0) + sign_dc_coeff_diff = get_bits1(gbc); + else + sign_dc_coeff_diff = 0; + + if (sign_dc_coeff_diff) + dc_coeff = state->prev_dc - abs_dc_coeff_diff; + else + dc_coeff = state->prev_dc + abs_dc_coeff_diff; + + if (dc_coeff < APV_MIN_TRANS_COEFF || + dc_coeff > APV_MAX_TRANS_COEFF) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range DC coefficient value: %d " + "(from prev_dc %d abs_dc_coeff_diff %d sign_dc_coeff_diff %d)\n", + dc_coeff, state->prev_dc, abs_dc_coeff_diff, sign_dc_coeff_diff); + return AVERROR_INVALIDDATA; + } + + coeff[0] = dc_coeff; + + state->prev_dc = dc_coeff; + state->prev_k_dc = FFMIN(abs_dc_coeff_diff >> 1, 5); + } + + // AC coefficients. + { + int scan_pos = 1; + int first_ac = 1; + int k_run = 0; + int k_level = state->prev_k_level; + + do { + int coeff_zero_run; + + coeff_zero_run = apv_read_vlc(gbc, k_run, lut); + + if (coeff_zero_run > APV_BLK_COEFFS - scan_pos) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range zero-run value: %d (at scan pos %d)\n", + coeff_zero_run, scan_pos); + return AVERROR_INVALIDDATA; + } + + for (int i = 0; i < coeff_zero_run; i++) { + coeff[ff_zigzag_direct[scan_pos]] = 0; + ++scan_pos; + } + k_run = FFMIN(coeff_zero_run >> 2, 2); + + if (scan_pos < APV_BLK_COEFFS) { + int abs_ac_coeff_minus1; + int sign_ac_coeff; + int abs_level, level; + + abs_ac_coeff_minus1 = apv_read_vlc(gbc, k_level, lut); + sign_ac_coeff = get_bits(gbc, 1); + + abs_level = abs_ac_coeff_minus1 + 1; + if (sign_ac_coeff) + level = -abs_level; + else + level = abs_level; + + if (level < APV_MIN_TRANS_COEFF || + level > APV_MAX_TRANS_COEFF) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range AC coefficient value: %d " + "(from k_param %d abs_ac_coeff_minus1 %d sign_ac_coeff %d)\n", + level, k_level, abs_ac_coeff_minus1, sign_ac_coeff); + } + + coeff[ff_zigzag_direct[scan_pos]] = level; + + k_level = FFMIN(abs_level >> 2, 4); + if (first_ac) { + state->prev_k_level = k_level; + first_ac = 0; + } + + ++scan_pos; + } + + } while (scan_pos < APV_BLK_COEFFS); + } + + return 0; +} + +static void binary(char *buf, uint32_t value, int bits) +{ + for (int i = 0; i < bits; i++) + buf[i] = (value >> (bits - i - 1) & 1) ? '1' : '0'; + buf[bits] = '\0'; +} + +static int test_apv_read_vlc(void) +{ + APVVLCLUT lut; + int err = 0; + + ff_apv_entropy_build_decode_lut(&lut); + + // Generate all possible 20 bit sequences (padded with zeroes), then + // verify that spec and improved parsing functions get the same result + // and consume the same number of bits for each possible k_param. + + for (int k = 0; k <= 5; k++) { + for (uint32_t b = 0; b < (1 << 20); b++) { + uint8_t buf[8] = { + b >> 12, + b >> 4, + b << 4, + 0, 0, 0, 0, 0 + }; + + GetBitContext gbc_test, gbc_spec; + unsigned int res_test, res_spec; + int con_test, con_spec; + + init_get_bits8(&gbc_test, buf, 8); + init_get_bits8(&gbc_spec, buf, 8); + + res_test = apv_read_vlc (&gbc_test, k, &lut); + res_spec = apv_read_vlc_spec(&gbc_spec, k); + + con_test = get_bits_count(&gbc_test); + con_spec = get_bits_count(&gbc_spec); + + if (res_test != res_spec || + con_test != con_spec) { + char str[21]; + binary(str, b, 20); + av_log(NULL, AV_LOG_ERROR, + "Mismatch reading %s (%d) with k=%d:\n", str, b, k); + av_log(NULL, AV_LOG_ERROR, + "Test function result %d consumed %d bits.\n", + res_test, con_test); + av_log(NULL, AV_LOG_ERROR, + "Spec function result %d consumed %d bits.\n", + res_spec, con_spec); + ++err; + if (err > 10) + return err; + } + } + } + + return err; +} + +static int random_coeff(AVLFG *lfg) +{ + // Geometric distribution of code lengths (1-14 bits), + // uniform distribution within codes of the length, + // equal probability of either sign. + int length = (av_lfg_get(lfg) / (UINT_MAX / 14 + 1)); + int random = av_lfg_get(lfg); + int value = (1 << length) + (random & (1 << length) - 1); + if (random & (1 << length)) + return value; + else + return -value; +} + +static int random_run(AVLFG *lfg) +{ + // Expoenential distribution of run lengths. + unsigned int random = av_lfg_get(lfg); + for (int len = 0;; len++) { + if (random & (1 << len)) + return len; + } + // You rolled zero on a 2^32 sided die; well done! + return 64; +} + +static int test_apv_entropy_decode_block(void) +{ + // Generate random entropy blocks, code them, then ensure they + // decode to the same block with both implementations. + + APVVLCLUT decode_lut; + AVLFG lfg; + unsigned int seed = av_get_random_seed(); + av_lfg_init(&lfg, seed); + + av_log(NULL, AV_LOG_INFO, "seed = %u\n", seed); + + ff_apv_entropy_build_decode_lut(&decode_lut); + + for (int t = 0; t < 100; t++) { + APVEntropyState state, save_state; + int16_t block[64]; + int16_t block_test1[64]; + int16_t block_test2[64]; + uint8_t buffer[1024]; + PutBitContext pbc; + GetBitContext gbc; + int bits_written; + int pos, run, coeff, level, err; + int k_dc, k_run, k_level; + + memset(block, 0, sizeof(block)); + memset(buffer, 0, sizeof(buffer)); + init_put_bits(&pbc, buffer, sizeof(buffer)); + + // Randomly-constructed state. + memset(&state, 0, sizeof(state)); + state.decode_lut = &decode_lut; + state.prev_dc = random_coeff(&lfg); + state.prev_k_dc = av_lfg_get(&lfg) % 5; + state.prev_k_level = av_lfg_get(&lfg) % 4; + save_state = state; + + k_dc = state.prev_k_dc; + k_run = 0; + k_level = state.prev_k_level; + + coeff = random_coeff(&lfg) / 2; + block[ff_zigzag_direct[0]] = state.prev_dc + coeff; + apv_write_vlc_spec(&pbc, FFABS(coeff), k_dc); + if (coeff != 0) + put_bits(&pbc, 1, coeff < 0); + + pos = 1; + while (pos < 64) { + run = random_run(&lfg); + if (pos + run > 64) + run = 64 - pos; + apv_write_vlc_spec(&pbc, run, k_run); + k_run = av_clip(run >> 2, 0, 2); + pos += run; + if (pos < 64) { + coeff = random_coeff(&lfg); + level = FFABS(coeff) - 1; + block[ff_zigzag_direct[pos]] = coeff; + apv_write_vlc_spec(&pbc, level, k_level); + put_bits(&pbc, 1, coeff < 0); + k_level = av_clip((level + 1) >> 2, 0, 4); + ++pos; + } + } + bits_written = put_bits_count(&pbc); + flush_put_bits(&pbc); + + // Fill output block with a distinctive error value. + for (int i = 0; i < 64; i++) + block_test1[i] = -9999; + init_get_bits8(&gbc, buffer, sizeof(buffer)); + + err = apv_entropy_decode_block(block_test1, &gbc, &state); + if (err < 0) { + av_log(NULL, AV_LOG_ERROR, "Entropy decode returned error.\n"); + return 1; + } else { + int bits_read = get_bits_count(&gbc); + if (bits_written != bits_read) { + av_log(NULL, AV_LOG_ERROR, "Wrote %d bits but read %d.\n", + bits_written, bits_read); + return 1; + } else { + err = 0; + for (int i = 0; i < 64; i++) { + if (block[i] != block_test1[i]) + ++err; + } + if (err > 0) { + av_log(NULL, AV_LOG_ERROR, "%d mismatches in output block.\n", err); + return err; + } + } + } + + init_get_bits8(&gbc, buffer, sizeof(buffer)); + memset(block_test2, 0, 64 * sizeof(int16_t)); + + err = ff_apv_entropy_decode_block(block_test2, &gbc, &save_state); + if (err < 0) { + av_log(NULL, AV_LOG_ERROR, "Entropy decode returned error.\n"); + return 1; + } else { + int bits_read = get_bits_count(&gbc); + if (bits_written != bits_read) { + av_log(NULL, AV_LOG_ERROR, "Wrote %d bits but read %d.\n", + bits_written, bits_read); + return 1; + } else { + err = 0; + for (int i = 0; i < 64; i++) { + if (block[i] != block_test2[i]) + ++err; + } + if (err > 0) { + av_log(NULL, AV_LOG_ERROR, "%d mismatches in output block.\n", err); + return err; + } + } + } + + if (state.prev_dc != save_state.prev_dc || + state.prev_k_dc != save_state.prev_k_dc || + state.prev_k_level != save_state.prev_k_level) { + av_log(NULL, AV_LOG_ERROR, "Entropy state mismatch.\n"); + return 1; + } + } + + return 0; +} + +int main(void) +{ + int err; + + err = test_apv_read_vlc(); + if (err) { + av_log(NULL, AV_LOG_ERROR, "Read VLC test failed.\n"); + return err; + } + + err = test_apv_entropy_decode_block(); + if (err) { + av_log(NULL, AV_LOG_ERROR, "Entropy decode block test failed.\n"); + return err; + } + + return 0; +} diff --git a/libavcodec/tests/avcodec.c b/libavcodec/tests/avcodec.c index cd949f638..893175c28 100644 --- a/libavcodec/tests/avcodec.c +++ b/libavcodec/tests/avcodec.c @@ -17,6 +17,7 @@ */ #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "libavcodec/codec.h" #include "libavcodec/codec_desc.h" #include "libavcodec/codec_internal.h" @@ -55,6 +56,30 @@ static int priv_data_size_wrong(const FFCodec *codec) return 0; } +#define ARRAY_CHECK(field, var, type, is_sentinel, check, sentinel_check) \ +do { \ + const type *ptr = codec->field; \ + if (!ptr) \ + break; \ + type var = *ptr; \ + if (is_sentinel) { \ + ERR("Codec %s sets " #field ", but without valid elements.\n"); \ + break; \ + } \ + do { \ + if (!(check)) { \ + ERR("Codec's %s " #field " array contains invalid element\n");\ + break; \ + } \ + ++ptr; \ + var = *ptr; \ + } while (!(is_sentinel)); \ + if (!(sentinel_check)) { \ + ERR("Codec's %s " #field " array has malformed sentinel\n"); \ + break; \ + } \ +} while (0) + int main(void){ void *iter = NULL; const AVCodec *codec = NULL; @@ -77,17 +102,32 @@ int main(void){ ERR_EXT("Codec %s has unsupported type %s\n", get_type_string(codec->type)); if (codec->type != AVMEDIA_TYPE_AUDIO) { +FF_DISABLE_DEPRECATION_WARNINGS if (codec->ch_layouts || codec->sample_fmts || codec->supported_samplerates) ERR("Non-audio codec %s has audio-only fields set\n"); +FF_ENABLE_DEPRECATION_WARNINGS if (codec->capabilities & (AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_VARIABLE_FRAME_SIZE)) ERR("Non-audio codec %s has audio-only capabilities set\n"); + } else { +FF_DISABLE_DEPRECATION_WARNINGS + ARRAY_CHECK(supported_samplerates, sample_rate, int, sample_rate == 0, + sample_rate > 0, 1); + ARRAY_CHECK(sample_fmts, sample_fmt, enum AVSampleFormat, sample_fmt == AV_SAMPLE_FMT_NONE, + (unsigned)sample_fmt < AV_SAMPLE_FMT_NB, 1); + static const AVChannelLayout zero_channel_layout = { 0 }; + ARRAY_CHECK(ch_layouts, ch_layout, AVChannelLayout, ch_layout.nb_channels == 0, + av_channel_layout_check(&ch_layout), !memcmp(ptr, &zero_channel_layout, sizeof(ch_layout))); +FF_ENABLE_DEPRECATION_WARNINGS } if (codec->type != AVMEDIA_TYPE_VIDEO) { - if (codec->pix_fmts || codec->supported_framerates) +FF_DISABLE_DEPRECATION_WARNINGS + if (codec->pix_fmts || codec->supported_framerates || + codec2->color_ranges || codec2->alpha_modes) ERR("Non-video codec %s has video-only fields set\n"); +FF_ENABLE_DEPRECATION_WARNINGS if (codec2->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING) ERR("Non-video codec %s exports cropping\n"); } @@ -136,10 +176,17 @@ int main(void){ if (codec2->update_thread_context || codec2->update_thread_context_for_user || codec2->bsfs) ERR("Encoder %s has decoder-only thread functions or bsf.\n"); if (codec->type == AVMEDIA_TYPE_AUDIO) { +FF_DISABLE_DEPRECATION_WARNINGS if (!codec->sample_fmts) { av_log(NULL, AV_LOG_FATAL, "Encoder %s is missing the sample_fmts field\n", codec->name); ret = 1; } + } else if (codec->type == AVMEDIA_TYPE_VIDEO) { + ARRAY_CHECK(pix_fmts, pix_fmt, enum AVPixelFormat, pix_fmt == AV_PIX_FMT_NONE, + av_pix_fmt_desc_get(pix_fmt), 1); + ARRAY_CHECK(supported_framerates, framerate, AVRational, framerate.num == 0, + framerate.num > 0 && framerate.den > 0, framerate.den == 0); +FF_ENABLE_DEPRECATION_WARNINGS } if (codec2->caps_internal & (FF_CODEC_CAP_USES_PROGRESSFRAMES | FF_CODEC_CAP_SETS_PKT_DTS | @@ -161,6 +208,9 @@ int main(void){ !(codec->capabilities & AV_CODEC_CAP_DELAY)) ERR("EOF_FLUSH encoder %s is not marked as having delay\n"); } else { + if ((codec2->update_thread_context || codec2->update_thread_context_for_user) && + !(codec->capabilities & AV_CODEC_CAP_FRAME_THREADS)) + ERR("Non-frame-threaded decoder %s has update_thread_context set"); if ((codec->type == AVMEDIA_TYPE_SUBTITLE) != (codec2->cb_type == FF_CODEC_CB_TYPE_DECODE_SUB)) ERR("Subtitle decoder %s does not implement decode_sub callback\n"); if (codec->type == AVMEDIA_TYPE_SUBTITLE && codec2->bsfs) @@ -175,6 +225,10 @@ int main(void){ codec2->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS) ERR("Decoder %s is marked as setting pkt_dts when it doesn't have" "any effect\n"); +FF_DISABLE_DEPRECATION_WARNINGS + if (codec->type == AVMEDIA_TYPE_VIDEO && (codec->pix_fmts || codec->supported_framerates)) + ERR("Decoder %s sets pix_fmts or supported_framerates.\n"); +FF_ENABLE_DEPRECATION_WARNINGS } if (priv_data_size_wrong(codec2)) ERR_EXT("Private context of codec %s is impossibly-sized (size %d).", diff --git a/libavcodec/tests/avpacket.c b/libavcodec/tests/avpacket.c index 1572e1147..edb117952 100644 --- a/libavcodec/tests/avpacket.c +++ b/libavcodec/tests/avpacket.c @@ -88,7 +88,7 @@ int main(void) /* test av_packet_alloc */ avpkt = av_packet_alloc(); if(!avpkt) { - av_log(NULL, AV_LOG_ERROR, "av_packet_alloc failed to allcoate AVPacket\n"); + av_log(NULL, AV_LOG_ERROR, "av_packet_alloc failed to allocate AVPacket\n"); return 1; } diff --git a/libavcodec/tests/celp_math.c b/libavcodec/tests/celp_math.c index 669ea7036..115817894 100644 --- a/libavcodec/tests/celp_math.c +++ b/libavcodec/tests/celp_math.c @@ -16,8 +16,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/float_dsp.h" #include "libavutil/libm.h" -#include "libavcodec/celp_math.c" +#include "libavutil/macros.h" + +#include "libavcodec/celp_math.h" static inline void IsAlmostEqual(float A, float B, float epsilon) { @@ -36,7 +43,7 @@ int main(void) const int16_t i1[3] = {6, 7, 8}; const int16_t i2[3] = {9, 10, 11}; - float r = ff_dot_productf(f1, f2, FF_ARRAY_ELEMS(f1)); + float r = ff_scalarproduct_float_c(f1, f2, FF_ARRAY_ELEMS(f1)); int64_t d = ff_dot_product(i1, i2, FF_ARRAY_ELEMS(i1)); IsAlmostEqual(16.94f, r, 0.000001f); diff --git a/libavcodec/tests/dct.c b/libavcodec/tests/dct.c index 17a081445..eb74f3559 100644 --- a/libavcodec/tests/dct.c +++ b/libavcodec/tests/dct.c @@ -37,7 +37,6 @@ #include "libavutil/cpu.h" #include "libavutil/common.h" -#include "libavutil/emms.h" #include "libavutil/internal.h" #include "libavutil/lfg.h" #include "libavutil/mem_internal.h" @@ -52,6 +51,9 @@ #include "libavcodec/faandct.h" #include "libavcodec/faanidct.h" #include "libavcodec/dctref.h" +#if CONFIG_PRORES_DECODER +#include "libavcodec/proresdsp.c" +#endif struct algo { const char *name; @@ -70,6 +72,7 @@ static const struct algo fdct_tab[] = { #endif /* CONFIG_FAANDCT */ }; +#if CONFIG_PRORES_DECODER static void ff_prores_idct_wrap(int16_t *dst){ LOCAL_ALIGNED(16, int16_t, qmat, [64]); int i; @@ -77,11 +80,12 @@ static void ff_prores_idct_wrap(int16_t *dst){ for(i=0; i<64; i++){ qmat[i]=4; } - ff_prores_idct_10(dst, qmat); + prores_idct_10(dst, qmat); for(i=0; i<64; i++) { dst[i] -= 512; } } +#endif static const struct algo idct_tab[] = { { "REF-DBL", ff_ref_idct, FF_IDCT_PERM_NONE }, @@ -89,7 +93,9 @@ static const struct algo idct_tab[] = { { "SIMPLE-C", ff_simple_idct_int16_8bit, FF_IDCT_PERM_NONE }, { "SIMPLE-C10", ff_simple_idct_int16_10bit, FF_IDCT_PERM_NONE }, { "SIMPLE-C12", ff_simple_idct_int16_12bit, FF_IDCT_PERM_NONE, 0, 1 }, +#if CONFIG_PRORES_DECODER { "PR-C", ff_prores_idct_wrap, FF_IDCT_PERM_NONE, 0, 1 }, +#endif #if CONFIG_FAANIDCT { "FAANI", ff_faanidct, FF_IDCT_PERM_NONE }, #endif /* CONFIG_FAANIDCT */ @@ -205,7 +211,6 @@ static int dct_error(const struct algo *dct, int test, int is_idct, int speed, c permute(block, block1, dct->perm_type); dct->func(block); - emms_c(); if (!strcmp(dct->name, "IJG-AAN-INT")) { for (i = 0; i < 64; i++) { @@ -280,7 +285,6 @@ static int dct_error(const struct algo *dct, int test, int is_idct, int speed, c memcpy(block, block1, sizeof(block)); dct->func(block); } - emms_c(); it1 += NB_ITS_SPEED; ti1 = av_gettime_relative() - ti; } while (ti1 < 1000000); @@ -442,7 +446,6 @@ static void idct248_error(const char *name, block[i] = block1[i]; idct248_put(img_dest, 8, block); } - emms_c(); it1 += NB_ITS_SPEED; ti1 = av_gettime_relative() - ti; } while (ti1 < 1000000); diff --git a/libavcodec/tests/hashtable.c b/libavcodec/tests/hashtable.c new file mode 100644 index 000000000..02c0ac8af --- /dev/null +++ b/libavcodec/tests/hashtable.c @@ -0,0 +1,110 @@ +/* + * Generic hashtable tests + * Copyright (C) 2024 Emma Worley + * + * 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 "libavutil/avassert.h" +#include "libavcodec/hashtable.h" + +int main(void) +{ + struct FFHashtableContext *ctx; + uint8_t k; + uint64_t v; + + // impossibly large allocation should fail gracefully + av_assert0(ff_hashtable_alloc(&ctx, -1, -1, -1) < 0); + + // hashtable can store up to 3 uint8_t->uint64_t entries + av_assert0(!ff_hashtable_alloc(&ctx, sizeof(k), sizeof(v), 3)); + + // unsuccessful deletes return 0 + k = 1; + av_assert0(!ff_hashtable_delete(ctx, &k)); + + // unsuccessful gets return 0 + k = 1; + av_assert0(!ff_hashtable_get(ctx, &k, &v)); + + // successful sets returns 1 + k = 1; + v = 1; + av_assert0(ff_hashtable_set(ctx, &k, &v)); + + // get should now contain 1 + k = 1; + v = 0; + av_assert0(ff_hashtable_get(ctx, &k, &v)); + av_assert0(v == 1); + + // updating sets should return 1 + k = 1; + v = 2; + av_assert0(ff_hashtable_set(ctx, &k, &v)); + + // get should now contain 2 + k = 1; + v = 0; + av_assert0(ff_hashtable_get(ctx, &k, &v)); + av_assert0(v == 2); + + // fill the table + k = 2; + v = 2; + av_assert0(ff_hashtable_set(ctx, &k, &v)); + k = 3; + v = 3; + av_assert0(ff_hashtable_set(ctx, &k, &v)); + + // inserting sets on a full table should return 0 + k = 4; + v = 4; + av_assert0(!ff_hashtable_set(ctx, &k, &v)); + + // updating sets on a full table should return 1 + k = 1; + v = 4; + av_assert0(ff_hashtable_set(ctx, &k, &v)); + v = 0; + av_assert0(ff_hashtable_get(ctx, &k, &v)); + av_assert0(v == 4); + + // successful deletes should return 1 + k = 1; + av_assert0(ff_hashtable_delete(ctx, &k)); + + // get should now return 0 + av_assert0(!ff_hashtable_get(ctx, &k, &v)); + + // sanity check remaining keys + k = 2; + v = 0; + av_assert0(ff_hashtable_get(ctx, &k, &v)); + av_assert0(v == 2); + k = 3; + v = 0; + av_assert0(ff_hashtable_get(ctx, &k, &v)); + av_assert0(v == 3); + + ff_hashtable_freep(&ctx); + + return 0; +} diff --git a/libavcodec/tests/iirfilter.c b/libavcodec/tests/iirfilter.c deleted file mode 100644 index e03e842b8..000000000 --- a/libavcodec/tests/iirfilter.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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 - -#include "libavutil/libm.h" - -#include "libavcodec/iirfilter.h" -#include "libavcodec/iirfilter.c" - -#define FILT_ORDER 4 -#define SIZE 1024 - -static void iir_filter_int16(const struct FFIIRFilterCoeffs *c, - struct FFIIRFilterState *s, int size, - const int16_t *src, ptrdiff_t sstep, - int16_t *dst, ptrdiff_t dstep) -{ - if (c->order == 2) { - FILTER_O2(int16_t, S16) - } else if (c->order == 4) { - FILTER_BW_O4(int16_t, S16) - } else { - FILTER_DIRECT_FORM_II(int16_t, S16) - } -} - -int main(void) -{ - struct FFIIRFilterCoeffs *fcoeffs = NULL; - struct FFIIRFilterState *fstate = NULL; - float cutoff_coeff = 0.4; - int16_t x[SIZE], y[SIZE]; - int i; - - fcoeffs = ff_iir_filter_init_coeffs(NULL, FF_FILTER_TYPE_BUTTERWORTH, - FF_FILTER_MODE_LOWPASS, FILT_ORDER, - cutoff_coeff, 0.0, 0.0); - fstate = ff_iir_filter_init_state(FILT_ORDER); - - for (i = 0; i < SIZE; i++) - x[i] = lrint(0.75 * INT16_MAX * sin(0.5 * M_PI * i * i / SIZE)); - - iir_filter_int16(fcoeffs, fstate, SIZE, x, 1, y, 1); - - for (i = 0; i < SIZE; i++) - printf("%6d %6d\n", x[i], y[i]); - - ff_iir_filter_free_coeffsp(&fcoeffs); - ff_iir_filter_free_statep(&fstate); - return 0; -} diff --git a/libavcodec/tests/jpeg2000dwt.c b/libavcodec/tests/jpeg2000dwt.c index 520ecc05a..a6ba190a5 100644 --- a/libavcodec/tests/jpeg2000dwt.c +++ b/libavcodec/tests/jpeg2000dwt.c @@ -46,6 +46,11 @@ static int test_dwt(int *array, int *ref, int border[2][2], int decomp_levels, i fprintf(stderr, "ff_dwt_encode failed\n"); return 1; } + if (type == FF_DWT97_INT) { + // pre-scaling to simulate dequantization which places the binary point at 1 bit above from LSB + for (j = 0; j< s->linelen[decomp_levels-1][0] * s->linelen[decomp_levels-1][1]; j++) + array[j] = (uint32_t)array[j] << I_PRESHIFT; + } ret = ff_dwt_decode(s, array); if (ret < 0) { fprintf(stderr, "ff_dwt_encode failed\n"); @@ -53,7 +58,7 @@ static int test_dwt(int *array, int *ref, int border[2][2], int decomp_levels, i } for (j = 0; j max_diff) { - fprintf(stderr, "missmatch at %d (%d != %d) decomp:%d border %d %d %d %d\n", + fprintf(stderr, "mismatch at %d (%d != %d) decomp:%d border %d %d %d %d\n", j, array[j], ref[j],decomp_levels, border[0][0], border[0][1], border[1][0], border[1][1]); return 2; } @@ -92,7 +97,7 @@ static int test_dwtf(float *array, float *ref, int border[2][2], int decomp_leve } for (j = 0; j max_diff) { - fprintf(stderr, "missmatch at %d (%f != %f) decomp:%d border %d %d %d %d\n", + fprintf(stderr, "mismatch at %d (%f != %f) decomp:%d border %d %d %d %d\n", j, array[j], ref[j],decomp_levels, border[0][0], border[0][1], border[1][0], border[1][1]); return 2; } diff --git a/libavcodec/tests/mjpegenc_huffman.c b/libavcodec/tests/mjpegenc_huffman.c index 2ed92d07d..9cc5d9b50 100644 --- a/libavcodec/tests/mjpegenc_huffman.c +++ b/libavcodec/tests/mjpegenc_huffman.c @@ -23,58 +23,80 @@ * Optimal Huffman Encoding tests. */ -#include "libavcodec/avcodec.h" -#include -#include "libavcodec/mjpegenc.h" -#include "libavcodec/mjpegenc_huffman.h" -#include "libavcodec/mjpegenc_common.h" -#include "libavcodec/mpegvideo.h" +#include + +#include "libavutil/avassert.h" +#include "libavutil/macros.h" + +#include "libavcodec/mjpegenc_huffman.c" // Validate the computed lengths satisfy the JPEG restrictions and is optimal. -static int check_lengths(int L, int expected_length, - const int *probs, int nprobs) +static int check_lengths(int L, const int *probs, int nprobs, + int expected_length, const uint8_t expected_len_counts[/* L + 1 */]) { - HuffTable lengths[256]; PTable val_counts[256]; - int actual_length = 0, i, j, k, prob, length; + uint8_t len_counts[17]; + int actual_length = 0, i; int ret = 0; - double cantor_measure = 0; av_assert0(nprobs <= 256); + av_assert0(L < FF_ARRAY_ELEMS(len_counts)); for (i = 0; i < nprobs; i++) { val_counts[i] = (PTable){.value = i, .prob = probs[i]}; } - ff_mjpegenc_huffman_compute_bits(val_counts, lengths, nprobs, L); + mjpegenc_huffman_compute_bits(val_counts, len_counts, nprobs, L); - for (i = 0; i < nprobs; i++) { - // Find the value's prob and length - for (j = 0; j < nprobs; j++) - if (val_counts[j].value == i) break; - for (k = 0; k < nprobs; k++) - if (lengths[k].code == i) break; - if (!(j < nprobs && k < nprobs)) return 1; - prob = val_counts[j].prob; - length = lengths[k].length; - - if (prob) { - actual_length += prob * length; - cantor_measure += 1. / (1 << length); + // Test that the lengths can be made part of a complete, prefix-free tree: + unsigned code = 0, count = 0; + for (int i = 1; i <= L; ++i) { + count += len_counts[i]; + code <<= 1; + code += len_counts[i]; + } + if (code > 1U << L) { + fprintf(stderr, "Huffman tree overdetermined/invalid\n"); + ret = 1; + } + if (count != nprobs) { + fprintf(stderr, "Total count %u does not match expected value %d\n", + count, nprobs); + ret = 1; + } + // Test that the input values have been properly ordered. + for (unsigned i = 0; i < count; ++i) { + if (val_counts[i].prob != probs[val_counts[i].value]) { + fprintf(stderr, "PTable not properly reordered\n"); + ret = 1; } - - if (length > L || length < 1) return 1; + if (i && val_counts[i - 1].prob > val_counts[i].prob) { + fprintf(stderr, "PTable not order ascendingly: [%u] = %d > [%u] = %d\n", + i - 1, val_counts[i - 1].prob, i, val_counts[i].prob); + ret = 1; + } + unsigned j; + for (j = 0; j < count; ++j) + if (val_counts[j].value == i) + break; + if (j >= count) { + fprintf(stderr, "Element %u missing after sorting\n", i); + ret = 1; + } + } + for (int len = L, j = 0; len; --len) { + int prob = 0; + for (int end = j + len_counts[len]; j < end; ++j) + prob += val_counts[j].prob; + actual_length += prob * len; } - // Check that the codes can be prefix-free. - if (cantor_measure > 1) ret = 1; // Check that the total length is optimal if (actual_length != expected_length) ret = 1; if (ret == 1) { fprintf(stderr, - "Cantor measure: %f\n" "Actual length: %d\n" "Expected length: %d\n", - cantor_measure, actual_length, expected_length); + actual_length, expected_length); } return ret; @@ -83,6 +105,9 @@ static int check_lengths(int L, int expected_length, static const int probs_zeroes[] = { 6, 6, 0, 0, 0 }; +static const uint8_t len_counts_zeroes[] = { + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, +}; static const int probs_skewed[] = { 2, 0, 0, 0, 0, 1, 0, 0, 20, 0, 2, 0, 10, 5, 1, 1, 9, 1, 1, 6, 0, 5, 0, 1, 0, 7, 6, @@ -96,6 +121,9 @@ static const int probs_skewed[] = { 0, 3, 0, 0, 28, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 21, 1, 0, 3, 24, 2, 0, 0, 7, 0, 0, 1, 5, 1, 2, 0, 5 }; +static const uint8_t len_counts_skewed[] = { + 0, 1, 0, 0, 1, 2, 7, 11, 18, 31, 28, 40, 0, 1, 0, 0, 116, +}; static const int probs_sat[] = { 74, 8, 14, 7, 9345, 40, 0, 2014, 2, 1, 115, 0, 2, 1, 194, 388, 20, 0, 0, 2, 1, 121, @@ -110,12 +138,18 @@ static const int probs_sat[] = { 0, 1085, 0, 0, 0, 3, 489, 36, 1, 0, 1, 9420, 294, 28, 0, 57, 5, 0, 9, 2, 0, 1, 2, 2, 0, 0, 9, 2, 29, 2, 2, 7, 0, 5, 490, 0, 7, 5, 0, 1, 8, 0, 0, 23255, 0, 1 }; +static const uint8_t len_counts_sat[] = { + 0, 1, 0, 2, 1, 2, 2, 5, 5, 7, 7, 8, 17, 23, 16, 24, 136, +}; // Test the example given on @see // http://guru.multimedia.cx/small-tasks-for-ffmpeg/ int main(int argc, char **argv) { - int i, ret = 0; + enum { + MAX_LEN = 3, + }; + int ret = 0; // Probabilities of symbols 0..4 PTable val_counts[] = { {.value = 0, .prob = 1}, @@ -125,42 +159,45 @@ int main(int argc, char **argv) {.value = 4, .prob = 21}, }; // Expected code lengths for each symbol - static const HuffTable expected[] = { - {.code = 0, .length = 3}, - {.code = 1, .length = 3}, - {.code = 2, .length = 3}, - {.code = 3, .length = 3}, - {.code = 4, .length = 1}, + static const uint8_t expected[MAX_LEN + 1] = { + [1] = 1, [3] = 4, }; // Actual code lengths - HuffTable distincts[5]; + uint8_t len_counts[MAX_LEN + 1]; // Build optimal huffman tree using an internal function, to allow for // smaller-than-normal test cases. This mutates val_counts by sorting. - ff_mjpegenc_huffman_compute_bits(val_counts, distincts, - FF_ARRAY_ELEMS(distincts), 3); + mjpegenc_huffman_compute_bits(val_counts, len_counts, + FF_ARRAY_ELEMS(val_counts), MAX_LEN); - for (i = 0; i < FF_ARRAY_ELEMS(distincts); i++) { - if (distincts[i].code != expected[i].code || - distincts[i].length != expected[i].length) { + for (unsigned i = 1; i < FF_ARRAY_ELEMS(len_counts); i++) { + if (len_counts[i] != expected[i]) { fprintf(stderr, "Built huffman does not equal expectations. " - "Expected: code %d probability %d, " - "Actual: code %d probability %d\n", - expected[i].code, expected[i].length, - distincts[i].code, distincts[i].length); + "Expected: %d codes of length %u, " + "Actual: %d codes of length %u\n", + (int)expected[i], i, + (int)len_counts[i], i); + ret = 1; + } + } + for (unsigned i = 1; i < FF_ARRAY_ELEMS(val_counts); ++i) { + if (val_counts[i - 1].prob > val_counts[i].prob) { + fprintf(stderr, "Probability table not ordered ascendingly. " + "val_counts[%u] == %d, val_counts[%u] == %d\n", + i - 1, val_counts[i - 1].prob, i, val_counts[i].prob); ret = 1; } } // Check handling of zero probabilities - if (check_lengths(16, 18, probs_zeroes, FF_ARRAY_ELEMS(probs_zeroes))) + if (check_lengths(16, probs_zeroes, FF_ARRAY_ELEMS(probs_zeroes), 18, len_counts_zeroes)) ret = 1; // Check skewed distribution over 256 without saturated lengths - if (check_lengths(16, 41282, probs_skewed, FF_ARRAY_ELEMS(probs_skewed))) + if (check_lengths(16, probs_skewed, FF_ARRAY_ELEMS(probs_skewed), 41282, len_counts_skewed)) ret = 1; // Check skewed distribution over 256 with saturated lengths - if (check_lengths(16, 669904, probs_sat, FF_ARRAY_ELEMS(probs_sat))) + if (check_lengths(16, probs_sat, FF_ARRAY_ELEMS(probs_sat), 669904, len_counts_sat)) ret = 1; return ret; diff --git a/libavcodec/tests/motion.c b/libavcodec/tests/motion.c index 719fba537..ad2d65ec7 100644 --- a/libavcodec/tests/motion.c +++ b/libavcodec/tests/motion.c @@ -36,8 +36,6 @@ #include "libavutil/mem.h" #include "libavutil/time.h" -#undef printf - #define WIDTH 64 #define HEIGHT 64 diff --git a/libavcodec/tests/snowenc.c b/libavcodec/tests/snowenc.c index 311374e5d..35feedba0 100644 --- a/libavcodec/tests/snowenc.c +++ b/libavcodec/tests/snowenc.c @@ -20,10 +20,6 @@ #include "libavcodec/snowenc.c" -#undef malloc -#undef free -#undef printf - #include "libavutil/lfg.h" #include "libavutil/mathematics.h" #include "libavutil/mem.h" diff --git a/libavcodec/tests/x86/dct.c b/libavcodec/tests/x86/dct.c index 7800abc7f..f879ab1d4 100644 --- a/libavcodec/tests/x86/dct.c +++ b/libavcodec/tests/x86/dct.c @@ -88,6 +88,10 @@ static const struct algo idct_tab_arch[] = { { "SIMPLE10-AVX", ff_simple_idct10_avx, FF_IDCT_PERM_TRANSPOSE, AV_CPU_FLAG_AVX}, { "SIMPLE12-AVX", ff_simple_idct12_avx, FF_IDCT_PERM_TRANSPOSE, AV_CPU_FLAG_AVX, 1 }, #endif +#else +#if HAVE_SSE2_EXTERNAL + { "SIMPLE-SSE2", ff_simple_idct_sse2, FF_IDCT_PERM_SIMPLE, AV_CPU_FLAG_SSE2}, +#endif #endif #endif { 0 } diff --git a/libavcodec/textdec.c b/libavcodec/textdec.c index b9aebff00..e38cba3af 100644 --- a/libavcodec/textdec.c +++ b/libavcodec/textdec.c @@ -28,6 +28,7 @@ #include "avcodec.h" #include "ass.h" #include "codec_internal.h" +#include "libavutil/attributes.h" #include "libavutil/bprint.h" #include "libavutil/opt.h" @@ -65,7 +66,7 @@ static int text_decode_frame(AVCodecContext *avctx, AVSubtitle *sub, return avpkt->size; } -static void text_flush(AVCodecContext *avctx) +static av_cold void text_flush(AVCodecContext *avctx) { TextContext *text = avctx->priv_data; if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP)) @@ -95,7 +96,7 @@ const FFCodec ff_text_decoder = { #if CONFIG_VPLAYER_DECODER || CONFIG_PJS_DECODER || CONFIG_SUBVIEWER1_DECODER || CONFIG_STL_DECODER -static int linebreak_init(AVCodecContext *avctx) +static av_cold int linebreak_init(AVCodecContext *avctx) { TextContext *text = avctx->priv_data; text->linebreaks = "|"; diff --git a/libavcodec/threadprogress.c b/libavcodec/threadprogress.c index 62c4fd898..aa72ff80e 100644 --- a/libavcodec/threadprogress.c +++ b/libavcodec/threadprogress.c @@ -55,9 +55,8 @@ void ff_thread_progress_report(ThreadProgress *pro, int n) if (atomic_load_explicit(&pro->progress, memory_order_relaxed) >= n) return; - atomic_store_explicit(&pro->progress, n, memory_order_release); - ff_mutex_lock(&pro->progress_mutex); + atomic_store_explicit(&pro->progress, n, memory_order_release); ff_cond_broadcast(&pro->progress_cond); ff_mutex_unlock(&pro->progress_mutex); } diff --git a/libavcodec/tiertexseqv.c b/libavcodec/tiertexseqv.c index cdc885558..31acc9b43 100644 --- a/libavcodec/tiertexseqv.c +++ b/libavcodec/tiertexseqv.c @@ -182,11 +182,6 @@ static int seqvideo_decode(SeqVideoContext *seq, const unsigned char *data, int c[j] = (*data << 2) | (*data >> 4); palette[i] = 0xFFU << 24 | AV_RB24(c); } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - seq->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } if (flags & 2) { diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c index 37b56e975..bb8120bc1 100644 --- a/libavcodec/tiff.c +++ b/libavcodec/tiff.c @@ -36,6 +36,7 @@ #include #include "libavutil/attributes.h" +#include "libavutil/attributes_internal.h" #include "libavutil/avstring.h" #include "libavutil/error.h" #include "libavutil/intreadwrite.h" @@ -46,6 +47,7 @@ #include "bytestream.h" #include "codec_internal.h" #include "decode.h" +#include "exif_internal.h" #include "faxcompr.h" #include "lzw.h" #include "tiff.h" @@ -123,6 +125,8 @@ typedef struct TiffContext { int geotag_count; TiffGeoTag *geotags; + + AVExifMetadata exif_meta; } TiffContext; static const float d65_white[3] = { 0.950456f, 1.f, 1.088754f }; @@ -272,9 +276,9 @@ static int add_metadata(int count, int type, const char *name, const char *sep, TiffContext *s, AVFrame *frame) { switch(type) { - case TIFF_DOUBLE: return ff_tadd_doubles_metadata(count, name, sep, &s->gb, s->le, &frame->metadata); - case TIFF_SHORT : return ff_tadd_shorts_metadata(count, name, sep, &s->gb, s->le, 0, &frame->metadata); - case TIFF_STRING: return ff_tadd_string_metadata(count, name, &s->gb, s->le, &frame->metadata); + case AV_TIFF_DOUBLE: return ff_tadd_doubles_metadata(count, name, sep, &s->gb, s->le, &frame->metadata); + case AV_TIFF_SHORT : return ff_tadd_shorts_metadata(count, name, sep, &s->gb, s->le, 0, &frame->metadata); + case AV_TIFF_STRING: return ff_tadd_string_metadata(count, name, &s->gb, s->le, &frame->metadata); default : return AVERROR_INVALIDDATA; }; } @@ -1270,12 +1274,12 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) off = bytestream2_tell(&s->gb); if (count == 1) { switch (type) { - case TIFF_BYTE: - case TIFF_SHORT: - case TIFF_LONG: + case AV_TIFF_BYTE: + case AV_TIFF_SHORT: + case AV_TIFF_LONG: value = ff_tget(&s->gb, type, s->le); break; - case TIFF_RATIONAL: + case AV_TIFF_RATIONAL: value = ff_tget_long(&s->gb, s->le); value2 = ff_tget_long(&s->gb, s->le); if (!value2) { @@ -1284,7 +1288,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) } break; - case TIFF_STRING: + case AV_TIFF_STRING: if (count <= 4) { break; } @@ -1319,9 +1323,9 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) s->bpp = value; else { switch (type) { - case TIFF_BYTE: - case TIFF_SHORT: - case TIFF_LONG: + case AV_TIFF_BYTE: + case AV_TIFF_SHORT: + case AV_TIFF_LONG: s->bpp = 0; if (bytestream2_get_bytes_left(&s->gb) < type_sizes[type] * count) return AVERROR_INVALIDDATA; @@ -1388,7 +1392,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) } break; case TIFF_ROWSPERSTRIP: - if (!value || (type == TIFF_LONG && value == UINT_MAX)) + if (!value || (type == AV_TIFF_LONG && value == UINT_MAX)) value = s->height; s->rps = FFMIN(value, s->height); break; @@ -1469,7 +1473,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) return AVERROR_INVALIDDATA; s->black_level[0] = value / (float)value2; for (int i = 0; i < count && count > 1; i++) { - if (type == TIFF_RATIONAL) { + if (type == AV_TIFF_RATIONAL) { value = ff_tget_long(&s->gb, s->le); value2 = ff_tget_long(&s->gb, s->le); if (!value2) { @@ -1478,7 +1482,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) } s->black_level[i] = value / (float)value2; - } else if (type == TIFF_SRATIONAL) { + } else if (type == AV_TIFF_SRATIONAL) { int value = ff_tget_long(&s->gb, s->le); int value2 = ff_tget_long(&s->gb, s->le); if (!value2) { @@ -1785,7 +1789,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) } break; case DNG_ANALOG_BALANCE: - if (type != TIFF_RATIONAL) + if (type != AV_TIFF_RATIONAL) break; for (int i = 0; i < 3; i++) { @@ -1800,7 +1804,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) } break; case DNG_AS_SHOT_NEUTRAL: - if (type != TIFF_RATIONAL) + if (type != AV_TIFF_RATIONAL) break; for (int i = 0; i < 3; i++) { @@ -1815,7 +1819,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) } break; case DNG_AS_SHOT_WHITE_XY: - if (type != TIFF_RATIONAL) + if (type != AV_TIFF_RATIONAL) break; for (int i = 0; i < 2; i++) { @@ -1936,6 +1940,12 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, int is_dng; int has_tile_bits, has_strip_bits; + av_exif_free(&s->exif_meta); + /* this will not parse the image data */ + ret = av_exif_parse_buffer(avctx, avpkt->data, avpkt->size, &s->exif_meta, AV_EXIF_TIFF_HEADER); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "could not parse EXIF data: %s\n", av_err2str(ret)); + bytestream2_init(&s->gb, avpkt->data, avpkt->size); // parse image header @@ -2401,6 +2411,10 @@ again: } } + ret = ff_decode_exif_attach_ifd(avctx, p, &s->exif_meta); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "error attaching EXIF ifd: %s\n", av_err2str(ret)); + *got_frame = 1; return avpkt->size; @@ -2409,7 +2423,6 @@ again: static av_cold int tiff_init(AVCodecContext *avctx) { TiffContext *s = avctx->priv_data; - const AVCodec *codec; int ret; s->width = 0; @@ -2429,17 +2442,15 @@ static av_cold int tiff_init(AVCodecContext *avctx) return AVERROR(ENOMEM); /* Prepare everything needed for JPEG decoding */ - codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG); - if (!codec) - return AVERROR_BUG; - s->avctx_mjpeg = avcodec_alloc_context3(codec); + EXTERN const FFCodec ff_mjpeg_decoder; + s->avctx_mjpeg = avcodec_alloc_context3(&ff_mjpeg_decoder.p); if (!s->avctx_mjpeg) return AVERROR(ENOMEM); s->avctx_mjpeg->flags = avctx->flags; s->avctx_mjpeg->flags2 = avctx->flags2; s->avctx_mjpeg->idct_algo = avctx->idct_algo; s->avctx_mjpeg->max_pixels = avctx->max_pixels; - ret = avcodec_open2(s->avctx_mjpeg, codec, NULL); + ret = avcodec_open2(s->avctx_mjpeg, NULL, NULL); if (ret < 0) { return ret; } @@ -2452,6 +2463,7 @@ static av_cold int tiff_end(AVCodecContext *avctx) TiffContext *const s = avctx->priv_data; free_geotags(s); + av_exif_free(&s->exif_meta); ff_lzw_decode_close(&s->lzw); av_freep(&s->deinvert_buf); diff --git a/libavcodec/tiff.h b/libavcodec/tiff.h index 12afcfa6e..dc44eda01 100644 --- a/libavcodec/tiff.h +++ b/libavcodec/tiff.h @@ -54,6 +54,7 @@ enum TiffTags { TIFF_MAKE = 0x10F, TIFF_MODEL = 0x110, TIFF_STRIP_OFFS = 0x111, + TIFF_ORIENTATION = 0x112, TIFF_SAMPLES_PER_PIXEL = 0x115, TIFF_ROWSPERSTRIP = 0x116, TIFF_STRIP_SIZE, diff --git a/libavcodec/tiff_common.c b/libavcodec/tiff_common.c index 22ebca814..265f84303 100644 --- a/libavcodec/tiff_common.c +++ b/libavcodec/tiff_common.c @@ -64,9 +64,9 @@ double ff_tget_double(GetByteContext *gb, int le) unsigned ff_tget(GetByteContext *gb, int type, int le) { switch (type) { - case TIFF_BYTE: return bytestream2_get_byte(gb); - case TIFF_SHORT: return ff_tget_short(gb, le); - case TIFF_LONG: return ff_tget_long(gb, le); + case AV_TIFF_BYTE: return bytestream2_get_byte(gb); + case AV_TIFF_SHORT: return ff_tget_short(gb, le); + case AV_TIFF_LONG: return ff_tget_long(gb, le); default: return UINT_MAX; } } @@ -97,51 +97,6 @@ static int bprint_to_avdict(AVBPrint *bp, const char *name, return av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL); } -int ff_tadd_rational_metadata(int count, const char *name, const char *sep, - GetByteContext *gb, int le, AVDictionary **metadata) -{ - AVBPrint bp; - int32_t nom, denom; - int i; - - if (count >= INT_MAX / sizeof(int64_t) || count <= 0) - return AVERROR_INVALIDDATA; - if (bytestream2_get_bytes_left(gb) < count * sizeof(int64_t)) - return AVERROR_INVALIDDATA; - - av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_UNLIMITED); - - for (i = 0; i < count; i++) { - nom = ff_tget_long(gb, le); - denom = ff_tget_long(gb, le); - av_bprintf(&bp, "%s%7"PRId32":%-7"PRId32, auto_sep(count, sep, i, 4), nom, denom); - } - - return bprint_to_avdict(&bp, name, metadata); -} - - -int ff_tadd_long_metadata(int count, const char *name, const char *sep, - GetByteContext *gb, int le, AVDictionary **metadata) -{ - AVBPrint bp; - int i; - - if (count >= INT_MAX / sizeof(int32_t) || count <= 0) - return AVERROR_INVALIDDATA; - if (bytestream2_get_bytes_left(gb) < count * sizeof(int32_t)) - return AVERROR_INVALIDDATA; - - av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_UNLIMITED); - - for (i = 0; i < count; i++) { - av_bprintf(&bp, "%s%7i", auto_sep(count, sep, i, 8), ff_tget_long(gb, le)); - } - - return bprint_to_avdict(&bp, name, metadata); -} - - int ff_tadd_doubles_metadata(int count, const char *name, const char *sep, GetByteContext *gb, int le, AVDictionary **metadata) { @@ -184,28 +139,6 @@ int ff_tadd_shorts_metadata(int count, const char *name, const char *sep, return bprint_to_avdict(&bp, name, metadata); } - -int ff_tadd_bytes_metadata(int count, const char *name, const char *sep, - GetByteContext *gb, int le, int is_signed, AVDictionary **metadata) -{ - AVBPrint bp; - int i; - - if (count >= INT_MAX / sizeof(int8_t) || count < 0) - return AVERROR_INVALIDDATA; - if (bytestream2_get_bytes_left(gb) < count * sizeof(int8_t)) - return AVERROR_INVALIDDATA; - - av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_UNLIMITED); - - for (i = 0; i < count; i++) { - int v = is_signed ? (int8_t)bytestream2_get_byte(gb) : bytestream2_get_byte(gb); - av_bprintf(&bp, "%s%3i", auto_sep(count, sep, i, 16), v); - } - - return bprint_to_avdict(&bp, name, metadata); -} - int ff_tadd_string_metadata(int count, const char *name, GetByteContext *gb, int le, AVDictionary **metadata) { @@ -273,7 +206,7 @@ int ff_tread_tag(GetByteContext *gb, int le, unsigned *tag, unsigned *type, // seek to offset if this is an IFD-tag or // if count values do not fit into the offset value - if (ifd_tag || (*count > 4 || !(type_sizes[*type] * (*count) <= 4 || *type == TIFF_STRING))) { + if (ifd_tag || (*count > 4 || !(type_sizes[*type] * (*count) <= 4 || *type == AV_TIFF_STRING))) { bytestream2_seek(gb, ff_tget_long (gb, le), SEEK_SET); } diff --git a/libavcodec/tiff_common.h b/libavcodec/tiff_common.h index e429b8eae..67f23bd4f 100644 --- a/libavcodec/tiff_common.h +++ b/libavcodec/tiff_common.h @@ -31,23 +31,7 @@ #include #include "libavutil/dict.h" #include "bytestream.h" - -/** data type identifiers for TIFF tags */ -enum TiffTypes { - TIFF_BYTE = 1, - TIFF_STRING, - TIFF_SHORT, - TIFF_LONG, - TIFF_RATIONAL, - TIFF_SBYTE, - TIFF_UNDEFINED, - TIFF_SSHORT, - TIFF_SLONG, - TIFF_SRATIONAL, - TIFF_FLOAT, - TIFF_DOUBLE, - TIFF_IFD -}; +#include "exif.h" /** sizes of various TIFF field types (string size = 100)*/ static const uint8_t type_sizes[14] = { @@ -78,18 +62,6 @@ double ff_tget_double(GetByteContext *gb, int le); /** Reads a byte from the bytestream using given endianness. */ unsigned ff_tget(GetByteContext *gb, int type, int le); -/** Adds count rationals converted to a string - * into the metadata dictionary. - */ -int ff_tadd_rational_metadata(int count, const char *name, const char *sep, - GetByteContext *gb, int le, AVDictionary **metadata); - -/** Adds count longs converted to a string - * into the metadata dictionary. - */ -int ff_tadd_long_metadata(int count, const char *name, const char *sep, - GetByteContext *gb, int le, AVDictionary **metadata); - /** Adds count doubles converted to a string * into the metadata dictionary. */ @@ -102,12 +74,6 @@ int ff_tadd_doubles_metadata(int count, const char *name, const char *sep, int ff_tadd_shorts_metadata(int count, const char *name, const char *sep, GetByteContext *gb, int le, int is_signed, AVDictionary **metadata); -/** Adds count bytes converted to a string - * into the metadata dictionary. - */ -int ff_tadd_bytes_metadata(int count, const char *name, const char *sep, - GetByteContext *gb, int le, int is_signed, AVDictionary **metadata); - /** Adds a string of count characters * into the metadata dictionary. */ diff --git a/libavcodec/tiffenc.c b/libavcodec/tiffenc.c index 5e65979c7..1916db9a3 100644 --- a/libavcodec/tiffenc.c +++ b/libavcodec/tiffenc.c @@ -105,7 +105,7 @@ static inline int check_size(TiffEncoderContext *s, uint64_t need) * @param type type of values * @param flip = 0 - normal copy, >0 - flip */ -static void tnput(uint8_t **p, int n, const uint8_t *val, enum TiffTypes type, +static void tnput(uint8_t **p, int n, const uint8_t *val, enum AVTiffDataType type, int flip) { int i; @@ -126,7 +126,7 @@ static void tnput(uint8_t **p, int n, const uint8_t *val, enum TiffTypes type, * @param ptr_val pointer to values */ static int add_entry(TiffEncoderContext *s, enum TiffTags tag, - enum TiffTypes type, int count, const void *ptr_val) + enum AVTiffDataType type, int count, const void *ptr_val) { uint8_t *entries_ptr = s->entries + 12 * s->num_entries; @@ -150,12 +150,12 @@ static int add_entry(TiffEncoderContext *s, enum TiffTags tag, } static int add_entry1(TiffEncoderContext *s, - enum TiffTags tag, enum TiffTypes type, int val) + enum TiffTags tag, enum AVTiffDataType type, int val) { uint16_t w = val; uint32_t dw = val; return add_entry(s, tag, type, 1, - type == TIFF_SHORT ? (void *)&w : (void *)&dw); + type == AV_TIFF_SHORT ? (void *)&w : (void *)&dw); } /** @@ -453,23 +453,30 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, s->num_entries = 0; - ADD_ENTRY1(s, TIFF_SUBFILE, TIFF_LONG, 0); - ADD_ENTRY1(s, TIFF_WIDTH, TIFF_LONG, s->width); - ADD_ENTRY1(s, TIFF_HEIGHT, TIFF_LONG, s->height); + ADD_ENTRY1(s, TIFF_SUBFILE, AV_TIFF_LONG, 0); + ADD_ENTRY1(s, TIFF_WIDTH, AV_TIFF_LONG, s->width); + ADD_ENTRY1(s, TIFF_HEIGHT, AV_TIFF_LONG, s->height); if (s->bpp_tab_size) - ADD_ENTRY(s, TIFF_BPP, TIFF_SHORT, s->bpp_tab_size, bpp_tab); + ADD_ENTRY(s, TIFF_BPP, AV_TIFF_SHORT, s->bpp_tab_size, bpp_tab); - ADD_ENTRY1(s, TIFF_COMPR, TIFF_SHORT, s->compr); - ADD_ENTRY1(s, TIFF_PHOTOMETRIC, TIFF_SHORT, s->photometric_interpretation); - ADD_ENTRY(s, TIFF_STRIP_OFFS, TIFF_LONG, strips, s->strip_offsets); + ADD_ENTRY1(s, TIFF_COMPR, AV_TIFF_SHORT, s->compr); + ADD_ENTRY1(s, TIFF_PHOTOMETRIC, AV_TIFF_SHORT, s->photometric_interpretation); + ADD_ENTRY(s, TIFF_STRIP_OFFS, AV_TIFF_LONG, strips, s->strip_offsets); + + AVFrameSideData *sd = av_frame_get_side_data(pict, AV_FRAME_DATA_DISPLAYMATRIX); + if (sd) { + int orientation = av_exif_matrix_to_orientation((int32_t *) sd->data); + if (orientation >= 1 && orientation <= 8) + ADD_ENTRY1(s, TIFF_ORIENTATION, AV_TIFF_SHORT, orientation); + } if (s->bpp_tab_size) - ADD_ENTRY1(s, TIFF_SAMPLES_PER_PIXEL, TIFF_SHORT, s->bpp_tab_size); + ADD_ENTRY1(s, TIFF_SAMPLES_PER_PIXEL, AV_TIFF_SHORT, s->bpp_tab_size); - ADD_ENTRY1(s, TIFF_ROWSPERSTRIP, TIFF_LONG, s->rps); - ADD_ENTRY(s, TIFF_STRIP_SIZE, TIFF_LONG, strips, s->strip_sizes); - ADD_ENTRY(s, TIFF_XRES, TIFF_RATIONAL, 1, res); + ADD_ENTRY1(s, TIFF_ROWSPERSTRIP, AV_TIFF_LONG, s->rps); + ADD_ENTRY(s, TIFF_STRIP_SIZE, AV_TIFF_LONG, strips, s->strip_sizes); + ADD_ENTRY(s, TIFF_XRES, AV_TIFF_RATIONAL, 1, res); if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) { AVRational y = av_mul_q(av_make_q(s->dpi, 1), @@ -477,11 +484,11 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, res[0] = y.num; res[1] = y.den; } - ADD_ENTRY(s, TIFF_YRES, TIFF_RATIONAL, 1, res); - ADD_ENTRY1(s, TIFF_RES_UNIT, TIFF_SHORT, 2); + ADD_ENTRY(s, TIFF_YRES, AV_TIFF_RATIONAL, 1, res); + ADD_ENTRY1(s, TIFF_RES_UNIT, AV_TIFF_SHORT, 2); if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) - ADD_ENTRY(s, TIFF_SOFTWARE_NAME, TIFF_STRING, + ADD_ENTRY(s, TIFF_SOFTWARE_NAME, AV_TIFF_STRING, strlen(LIBAVCODEC_IDENT) + 1, LIBAVCODEC_IDENT); if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { @@ -492,17 +499,17 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, pal[i + 256] = ((rgb >> 8) & 0xff) * 257; pal[i + 512] = (rgb & 0xff) * 257; } - ADD_ENTRY(s, TIFF_PAL, TIFF_SHORT, 256 * 3, pal); + ADD_ENTRY(s, TIFF_PAL, AV_TIFF_SHORT, 256 * 3, pal); } if (alpha) - ADD_ENTRY1(s,TIFF_EXTRASAMPLES, TIFF_SHORT, 2); + ADD_ENTRY1(s,TIFF_EXTRASAMPLES, AV_TIFF_SHORT, 2); if (is_yuv) { /** according to CCIR Recommendation 601.1 */ uint32_t refbw[12] = { 15, 1, 235, 1, 128, 1, 240, 1, 128, 1, 240, 1 }; - ADD_ENTRY(s, TIFF_YCBCR_SUBSAMPLING, TIFF_SHORT, 2, s->subsampling); + ADD_ENTRY(s, TIFF_YCBCR_SUBSAMPLING, AV_TIFF_SHORT, 2, s->subsampling); if (avctx->chroma_sample_location == AVCHROMA_LOC_TOPLEFT) - ADD_ENTRY1(s, TIFF_YCBCR_POSITIONING, TIFF_SHORT, 2); - ADD_ENTRY(s, TIFF_REFERENCE_BW, TIFF_RATIONAL, 6, refbw); + ADD_ENTRY1(s, TIFF_YCBCR_POSITIONING, AV_TIFF_SHORT, 2); + ADD_ENTRY(s, TIFF_REFERENCE_BW, AV_TIFF_RATIONAL, 6, refbw); } // write offset to dir bytestream_put_le32(&offset, ptr - pkt->data); @@ -580,15 +587,13 @@ const FFCodec ff_tiff_encoder = { .init = encode_init, .close = encode_close, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { + CODEC_PIXFMTS( AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48LE, AV_PIX_FMT_PAL8, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_YA16LE, AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_MONOWHITE, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, - AV_PIX_FMT_NONE - }, + AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &tiffenc_class, }; diff --git a/libavcodec/timecode_internal.c b/libavcodec/timecode_internal.c new file mode 100644 index 000000000..8682bb1b2 --- /dev/null +++ b/libavcodec/timecode_internal.c @@ -0,0 +1,19 @@ +/* + * 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/timecode_internal.c" diff --git a/libavcodec/tmv.c b/libavcodec/tmv.c index 713a7928c..6aa76fbcc 100644 --- a/libavcodec/tmv.c +++ b/libavcodec/tmv.c @@ -40,6 +40,7 @@ static int tmv_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt) { const uint8_t *src = avpkt->data; + const uint8_t *cga_font = avpriv_cga_font_get(); uint8_t *dst; unsigned char_cols = avctx->width >> 3; unsigned char_rows = avctx->height >> 3; @@ -58,11 +59,6 @@ static int tmv_decode_frame(AVCodecContext *avctx, AVFrame *frame, dst = frame->data[0]; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(frame->data[1], ff_cga_palette, 16 * 4); memset(frame->data[1] + 16 * 4, 0, AVPALETTE_SIZE - 16 * 4); @@ -72,7 +68,7 @@ FF_ENABLE_DEPRECATION_WARNINGS bg = *src >> 4; fg = *src++ & 0xF; ff_draw_pc_font(dst + x * 8, frame->linesize[0], - avpriv_cga_font, 8, c, fg, bg); + cga_font, 8, c, fg, bg); } dst += frame->linesize[0] * 8; } diff --git a/libavcodec/tscc.c b/libavcodec/tscc.c index 575173698..99bb0307b 100644 --- a/libavcodec/tscc.c +++ b/libavcodec/tscc.c @@ -107,11 +107,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, /* make the palette available on the way out */ if (c->avctx->pix_fmt == AV_PIX_FMT_PAL8) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = palette_has_changed; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); } diff --git a/libavcodec/ttadsp.c b/libavcodec/ttadsp.c index 5dda19587..af8285086 100644 --- a/libavcodec/ttadsp.c +++ b/libavcodec/ttadsp.c @@ -57,7 +57,7 @@ av_cold void ff_ttadsp_init(TTADSPContext *c) { c->filter_process = tta_filter_process_c; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_ttadsp_init_x86(c); #endif } diff --git a/libavcodec/ttaenc.c b/libavcodec/ttaenc.c index 1b9aeec8f..16fa37753 100644 --- a/libavcodec/ttaenc.c +++ b/libavcodec/ttaenc.c @@ -211,8 +211,5 @@ const FFCodec ff_tta_encoder = { .init = tta_encode_init, .close = tta_encode_close, FF_CODEC_ENCODE_CB(tta_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_U8, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), }; diff --git a/libavcodec/ttaencdsp.c b/libavcodec/ttaencdsp.c index 0efdc109b..0a717313b 100644 --- a/libavcodec/ttaencdsp.c +++ b/libavcodec/ttaencdsp.c @@ -54,7 +54,7 @@ av_cold void ff_ttaencdsp_init(TTAEncDSPContext *c) { c->filter_process = ttaenc_filter_process_c; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_ttaencdsp_init_x86(c); #endif } diff --git a/libavcodec/twinvqdec.c b/libavcodec/twinvqdec.c index 8b6b2196e..180704c93 100644 --- a/libavcodec/twinvqdec.c +++ b/libavcodec/twinvqdec.c @@ -423,7 +423,5 @@ const FFCodec ff_twinvq_decoder = { .close = ff_twinvq_decode_close, FF_CODEC_DECODE_CB(ff_twinvq_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/utils.c b/libavcodec/utils.c index aeb8f2f09..615d60cd5 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -33,6 +33,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" #include "libavutil/pixfmt.h" +#include "libavutil/timecode_internal.h" #include "avcodec.h" #include "codec.h" #include "codec_desc.h" @@ -40,7 +41,7 @@ #include "codec_par.h" #include "decode.h" #include "hwconfig.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadframe.h" #include "internal.h" @@ -78,17 +79,13 @@ void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size) int av_codec_is_encoder(const AVCodec *avcodec) { const FFCodec *const codec = ffcodec(avcodec); - return codec && (codec->cb_type == FF_CODEC_CB_TYPE_ENCODE || - codec->cb_type == FF_CODEC_CB_TYPE_ENCODE_SUB || - codec->cb_type == FF_CODEC_CB_TYPE_RECEIVE_PACKET); + return codec && !codec->is_decoder; } int av_codec_is_decoder(const AVCodec *avcodec) { const FFCodec *const codec = ffcodec(avcodec); - return codec && (codec->cb_type == FF_CODEC_CB_TYPE_DECODE || - codec->cb_type == FF_CODEC_CB_TYPE_DECODE_SUB || - codec->cb_type == FF_CODEC_CB_TYPE_RECEIVE_FRAME); + return codec && codec->is_decoder; } int ff_set_dimensions(AVCodecContext *s, int width, int height) @@ -339,7 +336,7 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, // H.264 uses edge emulation for out of frame motion vectors, for this // it requires a temporary area large enough to hold a 21x21 block, - // increasing witdth ensure that the temporary area is large enough, + // increasing width ensure that the temporary area is large enough, // the next rounded up width is 32 *width = FFMAX(*width, 32); } @@ -468,6 +465,7 @@ int av_get_exact_bits_per_sample(enum AVCodecID codec_id) case AV_CODEC_ID_ADPCM_IMA_APC: case AV_CODEC_ID_ADPCM_IMA_APM: case AV_CODEC_ID_ADPCM_IMA_EA_SEAD: + case AV_CODEC_ID_ADPCM_IMA_MAGIX: case AV_CODEC_ID_ADPCM_IMA_OKI: case AV_CODEC_ID_ADPCM_IMA_WS: case AV_CODEC_ID_ADPCM_IMA_SSI: @@ -490,6 +488,7 @@ int av_get_exact_bits_per_sample(enum AVCodecID codec_id) case AV_CODEC_ID_CBD2_DPCM: case AV_CODEC_ID_DERF_DPCM: case AV_CODEC_ID_WADY_DPCM: + case AV_CODEC_ID_ADPCM_CIRCUS: return 8; case AV_CODEC_ID_PCM_S16BE: case AV_CODEC_ID_PCM_S16BE_PLANAR: @@ -553,11 +552,13 @@ int av_get_bits_per_sample(enum AVCodecID codec_id) case AV_CODEC_ID_DFPWM: return 1; case AV_CODEC_ID_ADPCM_SBPRO_2: + case AV_CODEC_ID_G728: return 2; case AV_CODEC_ID_ADPCM_SBPRO_3: return 3; case AV_CODEC_ID_ADPCM_SBPRO_4: case AV_CODEC_ID_ADPCM_IMA_WAV: + case AV_CODEC_ID_ADPCM_IMA_XBOX: case AV_CODEC_ID_ADPCM_IMA_QT: case AV_CODEC_ID_ADPCM_SWF: case AV_CODEC_ID_ADPCM_MS: @@ -666,16 +667,27 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, return (frame_bytes - 4 * ch) / (128 * ch) * 256; case AV_CODEC_ID_ADPCM_AFC: return frame_bytes / (9 * ch) * 16; + case AV_CODEC_ID_ADPCM_N64: + frame_bytes /= 9 * ch; + if (frame_bytes > INT_MAX / 16) + return 0; + return frame_bytes * 16; case AV_CODEC_ID_ADPCM_PSX: case AV_CODEC_ID_ADPCM_DTK: frame_bytes /= 16 * ch; if (frame_bytes > INT_MAX / 28) return 0; return frame_bytes * 28; + case AV_CODEC_ID_ADPCM_PSXC: + frame_bytes = (frame_bytes - 1) / ch; + if (frame_bytes > INT_MAX / 2) + return 0; + return frame_bytes * 2; case AV_CODEC_ID_ADPCM_4XM: case AV_CODEC_ID_ADPCM_IMA_ACORN: case AV_CODEC_ID_ADPCM_IMA_DAT4: case AV_CODEC_ID_ADPCM_IMA_ISS: + case AV_CODEC_ID_ADPCM_IMA_PDA: return (frame_bytes - 4 * ch) * 2 / ch; case AV_CODEC_ID_ADPCM_IMA_SMJPEG: return (frame_bytes - 4) * 2 / ch; @@ -720,6 +732,11 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, int blocks = frame_bytes / ba; int64_t tmp = 0; switch (id) { + case AV_CODEC_ID_ADPCM_IMA_XBOX: + if (bps != 4) + return 0; + tmp = blocks * ((ba - 4 * ch) / (bps * ch) * 8); + break; case AV_CODEC_ID_ADPCM_IMA_WAV: if (bps < 2 || bps > 5) return 0; @@ -856,7 +873,7 @@ int ff_thread_ref_frame(ThreadFrame *dst, const ThreadFrame *src) av_assert0(!dst->progress); if (src->progress) - dst->progress = ff_refstruct_ref(src->progress); + dst->progress = av_refstruct_ref(src->progress); return 0; } @@ -872,7 +889,7 @@ int ff_thread_replace_frame(ThreadFrame *dst, const ThreadFrame *src) if (ret < 0) return ret; - ff_refstruct_replace(&dst->progress, src->progress); + av_refstruct_replace(&dst->progress, src->progress); return 0; } @@ -962,15 +979,6 @@ AVCPBProperties *av_cpb_properties_alloc(size_t *size) return props; } -static unsigned bcd2uint(uint8_t bcd) -{ - unsigned low = bcd & 0xf; - unsigned high = bcd >> 4; - if (low > 9 || high > 9) - return 0; - return low + 10*high; -} - int ff_alloc_timecode_sei(const AVFrame *frame, AVRational rate, size_t prefix_len, void **data, size_t *sei_size) { @@ -1000,23 +1008,8 @@ int ff_alloc_timecode_sei(const AVFrame *frame, AVRational rate, size_t prefix_l put_bits(&pb, 2, m); // num_clock_ts for (int j = 1; j <= m; j++) { - uint32_t tcsmpte = tc[j]; - unsigned hh = bcd2uint(tcsmpte & 0x3f); // 6-bit hours - unsigned mm = bcd2uint(tcsmpte>>8 & 0x7f); // 7-bit minutes - unsigned ss = bcd2uint(tcsmpte>>16 & 0x7f); // 7-bit seconds - unsigned ff = bcd2uint(tcsmpte>>24 & 0x3f); // 6-bit frames - unsigned drop = tcsmpte & 1<<30 && !0; // 1-bit drop if not arbitrary bit - - /* Calculate frame number of HEVC by SMPTE ST 12-1:2014 Sec 12.2 if rate > 30FPS */ - if (av_cmp_q(rate, (AVRational) {30, 1}) == 1) { - unsigned pc; - ff *= 2; - if (av_cmp_q(rate, (AVRational) {50, 1}) == 0) - pc = !!(tcsmpte & 1 << 7); - else - pc = !!(tcsmpte & 1 << 23); - ff = (ff + pc) & 0x7f; - } + unsigned hh, mm, ss, ff, drop; + ff_timecode_set_smpte(&drop, &hh, &mm, &ss, &ff, rate, tc[j], 0, 0); put_bits(&pb, 1, 1); // clock_timestamp_flag put_bits(&pb, 1, 1); // units_field_based_flag diff --git a/libavcodec/utvideodsp.c b/libavcodec/utvideodsp.c index b63dafbe1..209f8561a 100644 --- a/libavcodec/utvideodsp.c +++ b/libavcodec/utvideodsp.c @@ -79,7 +79,7 @@ av_cold void ff_utvideodsp_init(UTVideoDSPContext *c) #if ARCH_RISCV ff_utvideodsp_init_riscv(c); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_utvideodsp_init_x86(c); #endif } diff --git a/libavcodec/utvideoenc.c b/libavcodec/utvideoenc.c index 54b1caa9e..7cefca79b 100644 --- a/libavcodec/utvideoenc.c +++ b/libavcodec/utvideoenc.c @@ -24,6 +24,7 @@ * Ut Video encoder */ +#include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" @@ -143,9 +144,7 @@ static av_cold int utvideo_encode_init(AVCodecContext *avctx) original_format = UTVIDEO_444; break; default: - av_log(avctx, AV_LOG_ERROR, "Unknown pixel format: %d\n", - avctx->pix_fmt); - return AVERROR_INVALIDDATA; + av_unreachable("Already checked via CODEC_PIXFMTS"); } ff_bswapdsp_init(&c->bdsp); @@ -153,7 +152,7 @@ static av_cold int utvideo_encode_init(AVCodecContext *avctx) if (c->frame_pred == PRED_GRADIENT) { av_log(avctx, AV_LOG_ERROR, "Gradient prediction is not supported.\n"); - return AVERROR_OPTION_NOT_FOUND; + return AVERROR_PATCHWELCOME; } /* @@ -646,7 +645,6 @@ static const AVOption options[] = { { "pred", "Prediction method", OFFSET(frame_pred), AV_OPT_TYPE_INT, { .i64 = PRED_LEFT }, PRED_NONE, PRED_MEDIAN, VE, .unit = "pred" }, { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_NONE }, INT_MIN, INT_MAX, VE, .unit = "pred" }, { "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_LEFT }, INT_MIN, INT_MAX, VE, .unit = "pred" }, - { "gradient", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_GRADIENT }, INT_MIN, INT_MAX, VE, .unit = "pred" }, { "median", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_MEDIAN }, INT_MIN, INT_MAX, VE, .unit = "pred" }, { NULL}, @@ -671,10 +669,8 @@ const FFCodec ff_utvideo_encoder = { .init = utvideo_encode_init, FF_CODEC_ENCODE_CB(utvideo_encode_frame), .close = utvideo_encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_YUV422P, - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, + AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P), .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/v210dec_init.h b/libavcodec/v210dec_init.h index c7a232fe8..7523cb02b 100644 --- a/libavcodec/v210dec_init.h +++ b/libavcodec/v210dec_init.h @@ -51,10 +51,10 @@ static void v210_planar_unpack_c(const uint32_t *src, uint16_t *y, uint16_t *u, } } -static av_unused av_cold void ff_v210dec_init(V210DecContext *s) +av_unused static av_cold void ff_v210dec_init(V210DecContext *s) { s->unpack_frame = v210_planar_unpack_c; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_v210_x86_init(s); #endif } diff --git a/libavcodec/v210enc.c b/libavcodec/v210enc.c index 2a30ed77d..2194e2128 100644 --- a/libavcodec/v210enc.c +++ b/libavcodec/v210enc.c @@ -117,5 +117,5 @@ const FFCodec ff_v210_encoder = { .priv_data_size = sizeof(V210EncContext), .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P), }; diff --git a/libavcodec/v210enc_init.h b/libavcodec/v210enc_init.h index a0e5622f4..75ce62485 100644 --- a/libavcodec/v210enc_init.h +++ b/libavcodec/v210enc_init.h @@ -76,14 +76,14 @@ static void v210_planar_pack_10_c(const uint16_t *y, const uint16_t *u, } } -static av_cold av_unused void ff_v210enc_init(V210EncContext *s) +av_unused av_cold static void ff_v210enc_init(V210EncContext *s) { s->pack_line_8 = v210_planar_pack_8_c; s->pack_line_10 = v210_planar_pack_10_c; s->sample_factor_8 = 2; s->sample_factor_10 = 1; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_v210enc_init_x86(s); #endif } diff --git a/libavcodec/v308dec.c b/libavcodec/v308dec.c index b591a79dd..64876b7e5 100644 --- a/libavcodec/v308dec.c +++ b/libavcodec/v308dec.c @@ -30,6 +30,8 @@ static av_cold int v308_decode_init(AVCodecContext *avctx) if (avctx->width & 1) av_log(avctx, AV_LOG_WARNING, "v308 requires width to be even.\n"); + av_log(avctx, AV_LOG_WARNING, "This decoder is deprecated and will be removed.\n"); + return 0; } diff --git a/libavcodec/v308enc.c b/libavcodec/v308enc.c index 68f9c3310..884932da4 100644 --- a/libavcodec/v308enc.c +++ b/libavcodec/v308enc.c @@ -33,6 +33,8 @@ static av_cold int v308_encode_init(AVCodecContext *avctx) return AVERROR_INVALIDDATA; } + av_log(avctx, AV_LOG_WARNING, "This encoder is deprecated and will be removed.\n"); + avctx->bits_per_coded_sample = 24; avctx->bit_rate = ff_guess_coded_bitrate(avctx); @@ -78,5 +80,5 @@ const FFCodec ff_v308_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = v308_encode_init, FF_CODEC_ENCODE_CB(v308_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV444P), }; diff --git a/libavcodec/v408dec.c b/libavcodec/v408dec.c index 2433c6de1..4bce5c7b6 100644 --- a/libavcodec/v408dec.c +++ b/libavcodec/v408dec.c @@ -27,6 +27,8 @@ static av_cold int v408_decode_init(AVCodecContext *avctx) { avctx->pix_fmt = AV_PIX_FMT_YUVA444P; + av_log(avctx, AV_LOG_WARNING, "This decoder is deprecated and will be removed.\n"); + return 0; } diff --git a/libavcodec/v408enc.c b/libavcodec/v408enc.c index c173f650e..4b6717a1f 100644 --- a/libavcodec/v408enc.c +++ b/libavcodec/v408enc.c @@ -30,6 +30,8 @@ static av_cold int v408_encode_init(AVCodecContext *avctx) avctx->bits_per_coded_sample = 32; avctx->bit_rate = ff_guess_coded_bitrate(avctx); + av_log(avctx, AV_LOG_WARNING, "This encoder is deprecated and will be removed.\n"); + return 0; } @@ -77,5 +79,5 @@ const FFCodec ff_v408_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = v408_encode_init, FF_CODEC_ENCODE_CB(v408_encode_frame), - .p.pix_fmts = pix_fmt, + CODEC_PIXFMTS_ARRAY(pix_fmt), }; diff --git a/libavcodec/v410dec.c b/libavcodec/v410dec.c index 04be830ad..d3747c18e 100644 --- a/libavcodec/v410dec.c +++ b/libavcodec/v410dec.c @@ -46,6 +46,8 @@ static av_cold int v410_decode_init(AVCodecContext *avctx) } } + av_log(avctx, AV_LOG_WARNING, "This decoder is deprecated and will be removed.\n"); + return 0; } diff --git a/libavcodec/v410enc.c b/libavcodec/v410enc.c index 89ee3a727..1350acebb 100644 --- a/libavcodec/v410enc.c +++ b/libavcodec/v410enc.c @@ -37,6 +37,8 @@ static av_cold int v410_encode_init(AVCodecContext *avctx) avctx->bits_per_coded_sample = 32; avctx->bit_rate = ff_guess_coded_bitrate(avctx); + av_log(avctx, AV_LOG_WARNING, "This encoder is deprecated and will be removed.\n"); + return 0; } @@ -82,5 +84,5 @@ const FFCodec ff_v410_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = v410_encode_init, FF_CODEC_ENCODE_CB(v410_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV444P10, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV444P10), }; diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c index 23474ee14..077c1ee94 100644 --- a/libavcodec/v4l2_buffers.c +++ b/libavcodec/v4l2_buffers.c @@ -29,12 +29,15 @@ #include #include "libavcodec/avcodec.h" #include "libavutil/pixdesc.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "v4l2_context.h" #include "v4l2_buffers.h" #include "v4l2_m2m.h" +#ifndef USEC_PER_SEC #define USEC_PER_SEC 1000000 +#endif + static AVRational v4l2_timebase = { 1, USEC_PER_SEC }; static inline V4L2m2mContext *buf_to_m2mctx(V4L2Buffer *buf) @@ -187,6 +190,9 @@ static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf) switch (xfer) { case V4L2_XFER_FUNC_709: return AVCOL_TRC_BT709; case V4L2_XFER_FUNC_SRGB: return AVCOL_TRC_IEC61966_2_1; + case V4L2_XFER_FUNC_SMPTE240M: return AVCOL_TRC_SMPTE240M; + case V4L2_XFER_FUNC_NONE: return AVCOL_TRC_LINEAR; + case V4L2_XFER_FUNC_SMPTE2084: return AVCOL_TRC_SMPTE2084; default: break; } @@ -210,6 +216,23 @@ static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf) return AVCOL_TRC_UNSPECIFIED; } +static void v4l2_get_interlacing(AVFrame *frame, V4L2Buffer *buf) +{ + enum v4l2_field field = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? + buf->context->format.fmt.pix_mp.field : + buf->context->format.fmt.pix.field; + + switch (field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_INTERLACED_TB: + frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; + /* fallthrough */ + case V4L2_FIELD_INTERLACED_BT: + frame->flags |= AV_FRAME_FLAG_INTERLACED; + break; + } +} + static void v4l2_free_buffer(void *opaque, uint8_t *unused) { V4L2Buffer* avbuf = opaque; @@ -230,7 +253,7 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused) ff_v4l2_buffer_enqueue(avbuf); } - ff_refstruct_unref(&avbuf->context_ref); + av_refstruct_unref(&avbuf->context_ref); } } @@ -241,7 +264,7 @@ static int v4l2_buf_increase_ref(V4L2Buffer *in) if (in->context_ref) atomic_fetch_add(&in->context_refcount, 1); else { - in->context_ref = ff_refstruct_ref(s->self_ref); + in->context_ref = av_refstruct_ref(s->self_ref); in->context_refcount = 1; } @@ -434,6 +457,7 @@ int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf) frame->color_trc = v4l2_get_color_trc(avbuf); frame->pts = v4l2_get_pts(avbuf); frame->pkt_dts = AV_NOPTS_VALUE; + v4l2_get_interlacing(frame, avbuf); /* these values are updated also during re-init in v4l2_process_driver_event */ frame->height = avbuf->context->height; diff --git a/libavcodec/v4l2_context.h b/libavcodec/v4l2_context.h index 6f7460c89..fdd5cf528 100644 --- a/libavcodec/v4l2_context.h +++ b/libavcodec/v4l2_context.h @@ -124,7 +124,7 @@ int ff_v4l2_context_get_format(V4L2Context* ctx, int probe); * Releases a V4L2Context. * * @param[in] ctx A pointer to a V4L2Context. - * The caller is reponsible for freeing it. + * The caller is responsible for freeing it. * It must not be used after calling this function. */ void ff_v4l2_context_release(V4L2Context* ctx); diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c index 15415cfc4..07c750000 100644 --- a/libavcodec/v4l2_m2m.c +++ b/libavcodec/v4l2_m2m.c @@ -32,7 +32,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" #include "libavutil/pixfmt.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "v4l2_context.h" #include "v4l2_fmt.h" #include "v4l2_m2m.h" @@ -134,7 +134,7 @@ done: return ret; } -static int v4l2_configure_contexts(V4L2m2mContext *s) +static av_cold int v4l2_configure_contexts(V4L2m2mContext *s) { void *log_ctx = s->avctx; int ret; @@ -248,7 +248,7 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mContext *s) return 0; } -static void v4l2_m2m_destroy_context(FFRefStructOpaque unused, void *context) +static void v4l2_m2m_destroy_context(AVRefStructOpaque unused, void *context) { V4L2m2mContext *s = context; @@ -261,7 +261,7 @@ static void v4l2_m2m_destroy_context(FFRefStructOpaque unused, void *context) av_packet_unref(&s->buf_pkt); } -int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv) +av_cold int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv) { V4L2m2mContext *s = priv->context; int ret; @@ -282,12 +282,12 @@ int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv) ff_v4l2_context_release(&s->output); s->self_ref = NULL; - ff_refstruct_unref(&priv->context); + av_refstruct_unref(&priv->context); return 0; } -int ff_v4l2_m2m_codec_init(V4L2m2mPriv *priv) +av_cold int ff_v4l2_m2m_codec_init(V4L2m2mPriv *priv) { int ret = AVERROR(EINVAL); struct dirent *entry; @@ -327,7 +327,7 @@ int ff_v4l2_m2m_codec_init(V4L2m2mPriv *priv) int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s) { - *s = ff_refstruct_alloc_ext(sizeof(**s), 0, NULL, + *s = av_refstruct_alloc_ext(sizeof(**s), 0, NULL, &v4l2_m2m_destroy_context); if (!*s) return AVERROR(ENOMEM); @@ -344,7 +344,7 @@ int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s) priv->context->frame = av_frame_alloc(); if (!priv->context->frame) { - ff_refstruct_unref(&priv->context); + av_refstruct_unref(&priv->context); *s = NULL; /* freed when unreferencing context */ return AVERROR(ENOMEM); } diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c index aa2d759e1..ba1fe769e 100644 --- a/libavcodec/v4l2_m2m_dec.c +++ b/libavcodec/v4l2_m2m_dec.c @@ -164,7 +164,7 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) if (!s->draining) { ret = v4l2_try_start(avctx); if (ret) { - /* cant recover */ + /* can't recover */ if (ret != AVERROR(ENOMEM)) ret = 0; goto fail; diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c index 5770e87ea..93703ccc6 100644 --- a/libavcodec/v4l2_m2m_enc.c +++ b/libavcodec/v4l2_m2m_enc.c @@ -187,7 +187,7 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s) return ret; /** - * settingss + * settings */ if (avctx->framerate.num || avctx->framerate.den) v4l2_set_timeperframe(s, avctx->framerate.den, avctx->framerate.num); diff --git a/libavcodec/vaapi_av1.c b/libavcodec/vaapi_av1.c index 5451b6055..b8f5472c1 100644 --- a/libavcodec/vaapi_av1.c +++ b/libavcodec/vaapi_av1.c @@ -74,7 +74,7 @@ static int8_t vaapi_av1_get_bit_depth_idx(AVCodecContext *avctx) return bit_depth == 8 ? 0 : bit_depth == 10 ? 1 : 2; } -static int vaapi_av1_decode_init(AVCodecContext *avctx) +static av_cold int vaapi_av1_decode_init(AVCodecContext *avctx) { VAAPIAV1DecContext *ctx = avctx->internal->hwaccel_priv_data; @@ -92,7 +92,7 @@ static int vaapi_av1_decode_init(AVCodecContext *avctx) return ff_vaapi_decode_init(avctx); } -static int vaapi_av1_decode_uninit(AVCodecContext *avctx) +static av_cold int vaapi_av1_decode_uninit(AVCodecContext *avctx) { VAAPIAV1DecContext *ctx = avctx->internal->hwaccel_priv_data; @@ -108,6 +108,7 @@ static int vaapi_av1_decode_uninit(AVCodecContext *avctx) static int vaapi_av1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c index a59194340..4ac2df5b4 100644 --- a/libavcodec/vaapi_decode.c +++ b/libavcodec/vaapi_decode.c @@ -39,12 +39,24 @@ int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx, { VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; VAStatus vas; - VABufferID buffer; - av_assert0(pic->nb_param_buffers + 1 <= MAX_PARAM_BUFFERS); + av_assert0(pic->nb_param_buffers <= pic->nb_param_buffers_allocated); + if (pic->nb_param_buffers == pic->nb_param_buffers_allocated) { + VABufferID *tmp = + av_realloc_array(pic->param_buffers, + pic->nb_param_buffers_allocated + 16, + sizeof(*pic->param_buffers)); + if (!tmp) + return AVERROR(ENOMEM); + + pic->param_buffers = tmp; + pic->nb_param_buffers_allocated += 16; + } + av_assert0(pic->nb_param_buffers + 1 <= pic->nb_param_buffers_allocated); vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, - type, size, 1, (void*)data, &buffer); + type, size, 1, (void*)data, + &pic->param_buffers[pic->nb_param_buffers]); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create parameter " "buffer (type %d): %d (%s).\n", @@ -52,14 +64,14 @@ int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx, return AVERROR(EIO); } - pic->param_buffers[pic->nb_param_buffers++] = buffer; - av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes) " - "is %#x.\n", type, size, buffer); + "is %#x.\n", type, size, pic->param_buffers[pic->nb_param_buffers]); + + ++pic->nb_param_buffers; + return 0; } - int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx, VAAPIDecodePicture *pic, const void *params_data, @@ -72,19 +84,19 @@ int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx, VAStatus vas; int index; - av_assert0(pic->nb_slices <= pic->slices_allocated); - if (pic->nb_slices == pic->slices_allocated) { + av_assert0(pic->nb_slices <= pic->nb_slice_buffers_allocated); + if (pic->nb_slices == pic->nb_slice_buffers_allocated) { VABufferID *tmp = av_realloc_array(pic->slice_buffers, - pic->slices_allocated ? pic->slices_allocated * 2 : 64, + pic->nb_slice_buffers_allocated ? pic->nb_slice_buffers_allocated * 2 : 64, 2 * sizeof(*pic->slice_buffers)); if (!tmp) return AVERROR(ENOMEM); - pic->slice_buffers = tmp; - pic->slices_allocated = pic->slices_allocated ? pic->slices_allocated * 2 : 64; + pic->slice_buffers = tmp; + pic->nb_slice_buffers_allocated = pic->nb_slice_buffers_allocated ? pic->nb_slice_buffers_allocated * 2 : 64; } - av_assert0(pic->nb_slices + 1 <= pic->slices_allocated); + av_assert0(pic->nb_slices + 1 <= pic->nb_slice_buffers_allocated); index = 2 * pic->nb_slices; @@ -222,9 +234,11 @@ fail: ff_vaapi_decode_destroy_buffers(avctx, pic); fail_at_end: exit: - pic->nb_param_buffers = 0; - pic->nb_slices = 0; - pic->slices_allocated = 0; + pic->nb_param_buffers = 0; + pic->nb_param_buffers_allocated = 0; + av_freep(&pic->param_buffers); + pic->nb_slices = 0; + pic->nb_slice_buffers_allocated = 0; av_freep(&pic->slice_buffers); return err; @@ -235,9 +249,11 @@ int ff_vaapi_decode_cancel(AVCodecContext *avctx, { ff_vaapi_decode_destroy_buffers(avctx, pic); - pic->nb_param_buffers = 0; - pic->nb_slices = 0; - pic->slices_allocated = 0; + pic->nb_param_buffers = 0; + pic->nb_param_buffers_allocated = 0; + av_freep(&pic->param_buffers); + pic->nb_slices = 0; + pic->nb_slice_buffers_allocated = 0; av_freep(&pic->slice_buffers); return 0; @@ -448,6 +464,9 @@ static const struct { MAP(AV1, AV1_MAIN, AV1Profile0), MAP(AV1, AV1_HIGH, AV1Profile1), #endif +#if VA_CHECK_VERSION(1, 22, 0) + MAP(H266, VVC_MAIN_10, VVCMain10), +#endif #undef MAP }; @@ -613,6 +632,7 @@ static int vaapi_decode_make_config(AVCodecContext *avctx, // Add per-codec number of surfaces used for storing reference frames. switch (avctx->codec_id) { case AV_CODEC_ID_H264: + case AV_CODEC_ID_H266: case AV_CODEC_ID_HEVC: case AV_CODEC_ID_AV1: frames->initial_pool_size += 16; diff --git a/libavcodec/vaapi_decode.h b/libavcodec/vaapi_decode.h index 702171e10..7813473c9 100644 --- a/libavcodec/vaapi_decode.h +++ b/libavcodec/vaapi_decode.h @@ -32,19 +32,16 @@ static inline VASurfaceID ff_vaapi_get_surface_id(AVFrame *pic) return (uintptr_t)pic->data[3]; } -enum { - MAX_PARAM_BUFFERS = 16, -}; - typedef struct VAAPIDecodePicture { VASurfaceID output_surface; int nb_param_buffers; - VABufferID param_buffers[MAX_PARAM_BUFFERS]; + VABufferID *param_buffers; + int nb_param_buffers_allocated; int nb_slices; VABufferID *slice_buffers; - int slices_allocated; + int nb_slice_buffers_allocated; } VAAPIDecodePicture; typedef struct VAAPIDecodeContext { diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index 16a9a364f..0e50602e1 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -31,7 +31,7 @@ #include "vaapi_encode.h" #include "encode.h" #include "avcodec.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" const AVCodecHWConfigInternal *const ff_vaapi_encode_hw_configs[] = { HW_CONFIG_ENCODER_FRAMES(VAAPI, VAAPI), @@ -52,7 +52,7 @@ static int vaapi_encode_make_packed_header(AVCodecContext *avctx, .has_emulation_bytes = 1, }; - tmp = av_realloc_array(pic->param_buffers, sizeof(*tmp), pic->nb_param_buffers + 2); + tmp = av_realloc_array(pic->param_buffers, pic->nb_param_buffers + 2, sizeof(*tmp)); if (!tmp) return AVERROR(ENOMEM); pic->param_buffers = tmp; @@ -93,7 +93,7 @@ static int vaapi_encode_make_param_buffer(AVCodecContext *avctx, VABufferID *tmp; VABufferID buffer; - tmp = av_realloc_array(pic->param_buffers, sizeof(*tmp), pic->nb_param_buffers + 1); + tmp = av_realloc_array(pic->param_buffers, pic->nb_param_buffers + 1, sizeof(*tmp)); if (!tmp) return AVERROR(ENOMEM); pic->param_buffers = tmp; @@ -316,7 +316,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, pic->recon_surface = (VASurfaceID)(uintptr_t)base_pic->recon_image->data[3]; av_log(avctx, AV_LOG_DEBUG, "Recon surface is %#x.\n", pic->recon_surface); - pic->output_buffer_ref = ff_refstruct_pool_get(ctx->output_buffer_pool); + pic->output_buffer_ref = av_refstruct_pool_get(ctx->output_buffer_pool); if (!pic->output_buffer_ref) { err = AVERROR(ENOMEM); goto fail; @@ -649,7 +649,7 @@ fail_at_end: av_freep(&pic->param_buffers); av_freep(&pic->slices); av_freep(&pic->roi); - ff_refstruct_unref(&pic->output_buffer_ref); + av_refstruct_unref(&pic->output_buffer_ref); pic->output_buffer = VA_INVALID_ID; return err; } @@ -759,8 +759,8 @@ static int vaapi_encode_get_coded_data(AVCodecContext *avctx, goto end; end: - ff_refstruct_unref(&ctx->coded_buffer_ref); - ff_refstruct_unref(&pic->output_buffer_ref); + av_refstruct_unref(&ctx->coded_buffer_ref); + av_refstruct_unref(&pic->output_buffer_ref); pic->output_buffer = VA_INVALID_ID; return ret; @@ -781,7 +781,7 @@ static int vaapi_encode_output(AVCodecContext *avctx, if (pic->non_independent_frame) { av_assert0(!ctx->coded_buffer_ref); - ctx->coded_buffer_ref = ff_refstruct_ref(pic->output_buffer_ref); + ctx->coded_buffer_ref = av_refstruct_ref(pic->output_buffer_ref); if (pic->tail_size) { if (base_ctx->tail_pkt->size) { @@ -809,7 +809,7 @@ static int vaapi_encode_output(AVCodecContext *avctx, ctx->codec->flags & FLAG_TIMESTAMP_NO_DELAY); end: - ff_refstruct_unref(&pic->output_buffer_ref); + av_refstruct_unref(&pic->output_buffer_ref); pic->output_buffer = VA_INVALID_ID; return err; } @@ -825,7 +825,7 @@ static int vaapi_encode_discard(AVCodecContext *avctx, FFHWBaseEncodePicture *ba "%"PRId64"/%"PRId64".\n", base_pic->display_order, base_pic->encode_order); - ff_refstruct_unref(&pic->output_buffer_ref); + av_refstruct_unref(&pic->output_buffer_ref); pic->output_buffer = VA_INVALID_ID; } @@ -1133,6 +1133,68 @@ fail: return err; } +static av_cold int vaapi_encode_surface_alignment(av_unused AVCodecContext *avctx) +{ +#if VA_CHECK_VERSION(1, 21, 0) + VAAPIEncodeContext *ctx = avctx->priv_data; + VASurfaceAttrib *attr_list = NULL; + unsigned int attr_count = 0; + VAConfigID va_config; + VAStatus vas; + int err = 0; + + vas = vaCreateConfig(ctx->hwctx->display, + ctx->va_profile, ctx->va_entrypoint, + NULL, 0, &va_config); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to create temp encode pipeline " + "configuration: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + + vas = vaQuerySurfaceAttributes(ctx->hwctx->display, va_config, + 0, &attr_count); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR_EXTERNAL; + goto fail; + } + + attr_list = av_malloc(attr_count * sizeof(*attr_list)); + if (!attr_list) { + err = AVERROR(ENOMEM); + goto fail; + } + + vas = vaQuerySurfaceAttributes(ctx->hwctx->display, va_config, + attr_list, &attr_count); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR_EXTERNAL; + goto fail; + } + + for (unsigned int i = 0; i < attr_count; i++) { + if (attr_list[i].type == VASurfaceAttribAlignmentSize) { + ctx->surface_alignment_width = + 1 << (attr_list[i].value.value.i & 0xf); + ctx->surface_alignment_height = + 1 << ((attr_list[i].value.value.i & 0xf0) >> 4); + break; + } + } + +fail: + av_freep(&attr_list); + vaDestroyConfig(ctx->hwctx->display, va_config); + return err; +#else + return 0; +#endif +} + static const VAAPIEncodeRCMode vaapi_encode_rc_modes[] = { // Bitrate Quality // | Maxrate | HRD/VBV @@ -1232,7 +1294,8 @@ static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx) // * If bitrate and quality are both set, try QVBR. // * If quality is set, try ICQ, then CQP. // * If bitrate and maxrate are set and have the same value, try CBR. - // * If a bitrate is set, try AVBR, then VBR, then CBR. + // * If bitrate is set and RC buffer size/occupancy is not, try AVBR. + // * If a bitrate is set, try VBR, then CBR. // * If no bitrate is set, try ICQ, then CQP. #define TRY_RC_MODE(mode, fail) do { \ @@ -1276,7 +1339,10 @@ static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx) TRY_RC_MODE(RC_MODE_CBR, 0); if (avctx->bit_rate > 0) { - TRY_RC_MODE(RC_MODE_AVBR, 0); + // AVBR does not enforce RC buffer constraints + if (!avctx->rc_buffer_size && !avctx->rc_initial_buffer_occupancy) + TRY_RC_MODE(RC_MODE_AVBR, 0); + TRY_RC_MODE(RC_MODE_VBR, 0); TRY_RC_MODE(RC_MODE_CBR, 0); } else { @@ -1987,7 +2053,7 @@ static av_cold int vaapi_encode_init_roi(AVCodecContext *avctx) return 0; } -static void vaapi_encode_free_output_buffer(FFRefStructOpaque opaque, +static void vaapi_encode_free_output_buffer(AVRefStructOpaque opaque, void *obj) { AVCodecContext *avctx = opaque.nc; @@ -2000,7 +2066,7 @@ static void vaapi_encode_free_output_buffer(FFRefStructOpaque opaque, av_log(avctx, AV_LOG_DEBUG, "Freed output buffer %#x\n", buffer_id); } -static int vaapi_encode_alloc_output_buffer(FFRefStructOpaque opaque, void *obj) +static int vaapi_encode_alloc_output_buffer(AVRefStructOpaque opaque, void *obj) { AVCodecContext *avctx = opaque.nc; FFHWBaseEncodeContext *base_ctx = avctx->priv_data; @@ -2111,6 +2177,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) if (err < 0) goto fail; + err = vaapi_encode_surface_alignment(avctx); + if (err < 0) + goto fail; + if (ctx->codec->get_encoder_caps) { err = ctx->codec->get_encoder_caps(avctx); if (err < 0) @@ -2187,7 +2257,7 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) } ctx->output_buffer_pool = - ff_refstruct_pool_alloc_ext(sizeof(VABufferID), 0, avctx, + av_refstruct_pool_alloc_ext(sizeof(VABufferID), 0, avctx, &vaapi_encode_alloc_output_buffer, NULL, vaapi_encode_free_output_buffer, NULL); if (!ctx->output_buffer_pool) { @@ -2288,7 +2358,7 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx) vaapi_encode_free(avctx, pic); } - ff_refstruct_pool_uninit(&ctx->output_buffer_pool); + av_refstruct_pool_uninit(&ctx->output_buffer_pool); if (ctx->va_context != VA_INVALID_ID) { if (ctx->hwctx) diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h index c4f85397a..1fa1e99a3 100644 --- a/libavcodec/vaapi_encode.h +++ b/libavcodec/vaapi_encode.h @@ -202,7 +202,7 @@ typedef struct VAAPIEncodeContext { AVVAAPIDeviceContext *hwctx; // Pool of (reusable) bitstream output buffers. - struct FFRefStructPool *output_buffer_pool; + struct AVRefStructPool *output_buffer_pool; // Global parameters which will be applied at the start of the // sequence (includes rate control parameters below). @@ -260,6 +260,10 @@ typedef struct VAAPIEncodeContext { * This is a RefStruct reference. */ VABufferID *coded_buffer_ref; + + // Surface alignment required by driver. + int surface_alignment_width; + int surface_alignment_height; } VAAPIEncodeContext; typedef struct VAAPIEncodeType { @@ -356,7 +360,7 @@ int ff_vaapi_encode_close(AVCodecContext *avctx); { "max_frame_size", \ "Maximum frame size (in bytes)",\ OFFSET(common.max_frame_size), AV_OPT_TYPE_INT, \ - { .i64 = 0 }, 0, INT_MAX, FLAGS } + { .i64 = 0 }, 0, INT_MAX / 8, FLAGS } #define VAAPI_ENCODE_RC_MODE(name, desc) \ { #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_ ## name }, \ diff --git a/libavcodec/vaapi_encode_av1.c b/libavcodec/vaapi_encode_av1.c index 1b350cd93..9d837f5c6 100644 --- a/libavcodec/vaapi_encode_av1.c +++ b/libavcodec/vaapi_encode_av1.c @@ -476,6 +476,7 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, AV1RawFrameHeader *fh = &fh_obu->obu.frame.header; VAEncPictureParameterBufferAV1 *vpic = vaapi_pic->codec_picture_params; CodedBitstreamFragment *obu = &priv->current_obu; + CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data; FFHWBaseEncodePicture *ref; VAAPIEncodeAV1Picture *href; int slot, i; @@ -523,6 +524,8 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, fh->ref_frame_idx[3] = href->slot; fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame; vpic->ref_frame_ctrl_l0.fields.search_idx1 = AV1_REF_FRAME_GOLDEN; + } else { + fh->ref_order_hint[!href->slot] = cbctx->ref[!href->slot].order_hint; } break; case FF_HW_PICTURE_TYPE_B: @@ -1024,6 +1027,7 @@ static const FFCodecDefault vaapi_encode_av1_defaults[] = { { "g", "120" }, { "qmin", "1" }, { "qmax", "255" }, + { "refs", "0" }, { NULL }, }; @@ -1049,10 +1053,7 @@ const FFCodec ff_av1_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_av1_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index ed20b9cd2..27f655171 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -1153,6 +1153,7 @@ static const FFCodecDefault vaapi_encode_h264_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -1178,10 +1179,7 @@ const FFCodec ff_h264_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_h264_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 2283bcc0b..baf0d77c8 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -526,7 +526,7 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, priv->sei_needed = 0; // Only look for the metadata on I/IDR frame on the output. We - // may force an IDR frame on the output where the medadata gets + // may force an IDR frame on the output where the metadata gets // changed on the input frame. if ((priv->sei & SEI_MASTERING_DISPLAY) && (pic->type == FF_HW_PICTURE_TYPE_I || pic->type == FF_HW_PICTURE_TYPE_IDR)) { @@ -951,8 +951,10 @@ static av_cold int vaapi_encode_h265_get_encoder_caps(AVCodecContext *avctx) "min CB size %dx%d.\n", priv->ctu_size, priv->ctu_size, priv->min_cb_size, priv->min_cb_size); - base_ctx->surface_width = FFALIGN(avctx->width, priv->min_cb_size); - base_ctx->surface_height = FFALIGN(avctx->height, priv->min_cb_size); + base_ctx->surface_width = FFALIGN(avctx->width, + FFMAX(priv->min_cb_size, priv->common.surface_alignment_width)); + base_ctx->surface_height = FFALIGN(avctx->height, + FFMAX(priv->min_cb_size, priv->common.surface_alignment_height)); base_ctx->slice_block_width = base_ctx->slice_block_height = priv->ctu_size; @@ -1182,6 +1184,7 @@ static const FFCodecDefault vaapi_encode_h265_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -1207,10 +1210,7 @@ const FFCodec ff_hevc_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_h265_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_mjpeg.c b/libavcodec/vaapi_encode_mjpeg.c index 5f8266e98..2eef5bf09 100644 --- a/libavcodec/vaapi_encode_mjpeg.c +++ b/libavcodec/vaapi_encode_mjpeg.c @@ -582,10 +582,7 @@ const FFCodec ff_mjpeg_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_mjpeg_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c index 5701e2e80..94cb3d4fb 100644 --- a/libavcodec/vaapi_encode_mpeg2.c +++ b/libavcodec/vaapi_encode_mpeg2.c @@ -705,10 +705,7 @@ const FFCodec ff_mpeg2_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_mpeg2_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG, .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_vp8.c b/libavcodec/vaapi_encode_vp8.c index ad88af63e..69a56a17a 100644 --- a/libavcodec/vaapi_encode_vp8.c +++ b/libavcodec/vaapi_encode_vp8.c @@ -235,6 +235,7 @@ static const FFCodecDefault vaapi_encode_vp8_defaults[] = { { "g", "120" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -260,10 +261,7 @@ const FFCodec ff_vp8_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_vp8_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_vp9.c b/libavcodec/vaapi_encode_vp9.c index ab925e24b..ca8de541d 100644 --- a/libavcodec/vaapi_encode_vp9.c +++ b/libavcodec/vaapi_encode_vp9.c @@ -292,6 +292,7 @@ static const FFCodecDefault vaapi_encode_vp9_defaults[] = { { "g", "250" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -318,10 +319,7 @@ const FFCodec ff_vp9_vaapi_encoder = { FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_vp9_defaults, .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_h264.c b/libavcodec/vaapi_h264.c index 398e92568..7f00da09f 100644 --- a/libavcodec/vaapi_h264.c +++ b/libavcodec/vaapi_h264.c @@ -232,6 +232,7 @@ static void fill_vaapi_plain_pred_weight_table(const H264Context *h, /** Initialize and start decoding a frame with VA API. */ static int vaapi_h264_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c index 0c5a82922..878f7965c 100644 --- a/libavcodec/vaapi_hevc.c +++ b/libavcodec/vaapi_hevc.c @@ -122,6 +122,7 @@ static void fill_vaapi_reference_frames(const HEVCContext *h, const HEVCLayerCon } static int vaapi_hevc_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_mjpeg.c b/libavcodec/vaapi_mjpeg.c index 9557cf5f9..c8b59b8af 100644 --- a/libavcodec/vaapi_mjpeg.c +++ b/libavcodec/vaapi_mjpeg.c @@ -24,6 +24,7 @@ #include "mjpegdec.h" static int vaapi_mjpeg_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_mpeg2.c b/libavcodec/vaapi_mpeg2.c index d4304dfdd..925f0db1b 100644 --- a/libavcodec/vaapi_mpeg2.c +++ b/libavcodec/vaapi_mpeg2.c @@ -39,7 +39,10 @@ static inline int mpeg2_get_is_frame_start(const MpegEncContext *s) return s->first_field || s->picture_structure == PICT_FRAME; } -static int vaapi_mpeg2_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int vaapi_mpeg2_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const MpegEncContext *s = avctx->priv_data; VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; diff --git a/libavcodec/vaapi_mpeg4.c b/libavcodec/vaapi_mpeg4.c index 2c9dfbe42..d936a290c 100644 --- a/libavcodec/vaapi_mpeg4.c +++ b/libavcodec/vaapi_mpeg4.c @@ -45,10 +45,13 @@ static int mpeg4_get_intra_dc_vlc_thr(Mpeg4DecContext *s) return 0; } -static int vaapi_mpeg4_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int vaapi_mpeg4_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { Mpeg4DecContext *ctx = avctx->priv_data; - MpegEncContext *s = &ctx->m; + MPVContext *const s = &ctx->h.c; VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; VAPictureParameterBufferMPEG4 pic_param; int i, err; @@ -67,9 +70,9 @@ static int vaapi_mpeg4_start_frame(AVCodecContext *avctx, av_unused const uint8_ .obmc_disable = 1, .sprite_enable = ctx->vol_sprite_usage, .sprite_warping_accuracy = ctx->sprite_warping_accuracy, - .quant_type = s->mpeg_quant, + .quant_type = ctx->mpeg_quant, .quarter_sample = s->quarter_sample, - .data_partitioned = s->data_partitioning, + .data_partitioned = ctx->h.data_partitioning, .reversible_vlc = ctx->rvlc, .resync_marker_disable = !ctx->resync_marker, }, @@ -84,8 +87,8 @@ static int vaapi_mpeg4_start_frame(AVCodecContext *avctx, av_unused const uint8_ .top_field_first = s->top_field_first, .alternate_vertical_scan_flag = s->alternate_scan, }, - .vop_fcode_forward = s->f_code, - .vop_fcode_backward = s->b_code, + .vop_fcode_forward = ctx->f_code, + .vop_fcode_backward = ctx->b_code, .vop_time_increment_resolution = avctx->framerate.num, .num_macroblocks_in_gob = s->mb_width * H263_GOB_HEIGHT(s->height), .num_gobs_in_vop = @@ -154,8 +157,8 @@ fail: static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { - MpegEncContext *s = avctx->priv_data; - VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; + H263DecContext *const h = avctx->priv_data; + VAAPIDecodePicture *pic = h->c.cur_pic.ptr->hwaccel_picture_private; VASliceParameterBufferMPEG4 slice_param; int err; @@ -163,9 +166,9 @@ static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer .slice_data_size = size, .slice_data_offset = 0, .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, - .macroblock_offset = get_bits_count(&s->gb) % 8, + .macroblock_offset = get_bits_count(&h->gb) % 8, .macroblock_number = 0, - .quant_scale = s->qscale, + .quant_scale = h->c.qscale, }; err = ff_vaapi_decode_make_slice_buffer(avctx, pic, diff --git a/libavcodec/vaapi_vc1.c b/libavcodec/vaapi_vc1.c index 7d001882f..a3dd3140e 100644 --- a/libavcodec/vaapi_vc1.c +++ b/libavcodec/vaapi_vc1.c @@ -249,7 +249,10 @@ static inline void vc1_pack_bitplanes(uint8_t *bitplane, int n, const uint8_t *f bitplane[bitplane_index] = (bitplane[bitplane_index] << 4) | v; } -static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int vaapi_vc1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const VC1Context *v = avctx->priv_data; const MpegEncContext *s = &v->s; @@ -282,7 +285,7 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t .broken_link = v->broken_link, .closed_entry = v->closed_entry, .panscan_flag = v->panscanflag, - .loopfilter = s->loop_filter, + .loopfilter = v->loop_filter, }, .conditional_overlap_flag = v->condover, .fast_uvmc_flag = v->fastuvmc, @@ -340,7 +343,7 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t .mv_fields.bits = { .mv_mode = vc1_get_MVMODE(v), .mv_mode2 = vc1_get_MVMODE2(v), - .mv_table = (v->fcm == PROGRESSIVE ? s->mv_table_index : v->imvtab), + .mv_table = (v->fcm == PROGRESSIVE ? v->mv_table_index : v->imvtab), .two_mv_block_pattern_table = v->twomvbptab, .four_mv_switch = v->fourmvswitch, .four_mv_block_pattern_table = v->fourmvbptab, @@ -368,7 +371,7 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t .frame_level_transform_type = vc1_get_TTFRM(v), .transform_ac_codingset_idx1 = v->c_ac_table_index, .transform_ac_codingset_idx2 = v->y_ac_table_index, - .intra_transform_dc_table = v->s.dc_table_index, + .intra_transform_dc_table = v->dc_table_index, }, }; @@ -487,7 +490,7 @@ static int vaapi_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, .slice_data_size = size, .slice_data_offset = 0, .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, - .macroblock_offset = get_bits_count(&s->gb), + .macroblock_offset = get_bits_count(&v->gb), .slice_vertical_position = s->mb_y % mb_height, }; diff --git a/libavcodec/vaapi_vp8.c b/libavcodec/vaapi_vp8.c index 66fdde1f3..b9b1f2aa5 100644 --- a/libavcodec/vaapi_vp8.c +++ b/libavcodec/vaapi_vp8.c @@ -32,6 +32,7 @@ static VASurfaceID vaapi_vp8_surface_id(VP8Frame *vf) } static int vaapi_vp8_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_vp9.c b/libavcodec/vaapi_vp9.c index a28fc75a5..7d57f340e 100644 --- a/libavcodec/vaapi_vp9.c +++ b/libavcodec/vaapi_vp9.c @@ -35,6 +35,7 @@ static VASurfaceID vaapi_vp9_surface_id(const VP9Frame *vf) } static int vaapi_vp9_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_vvc.c b/libavcodec/vaapi_vvc.c new file mode 100644 index 000000000..908db7bfa --- /dev/null +++ b/libavcodec/vaapi_vvc.c @@ -0,0 +1,658 @@ +/* + * VVC HW decode acceleration through VA API + * + * Copyright (c) 2024 Intel Corporation + * + * 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 "vvc/dec.h" +#include "vvc/refs.h" +#include "hwaccel_internal.h" +#include "vaapi_decode.h" + +typedef struct VAAPIDecodePictureVVC { + VAAPIDecodePicture pic; + VAPictureParameterBufferVVC pic_param; + VASliceParameterBufferVVC slice_param; + int decode_issued; +} VAAPIDecodePictureVVC; + +static void init_vaapi_pic(VAPictureVVC *va_pic) +{ + va_pic->picture_id = VA_INVALID_ID; + va_pic->flags = VA_PICTURE_VVC_INVALID; + va_pic->pic_order_cnt = 0; +} + +static void fill_vaapi_pic(VAPictureVVC *va_pic, const VVCFrame *pic) +{ + va_pic->picture_id = ff_vaapi_get_surface_id(pic->frame); + va_pic->pic_order_cnt = pic->poc; + va_pic->flags = 0; + + if (pic->flags & VVC_FRAME_FLAG_LONG_REF) + va_pic->flags |= VA_PICTURE_VVC_LONG_TERM_REFERENCE; +} + +static void fill_vaapi_reference_frames(const VVCFrameContext *h, VAPictureParameterBufferVVC *pp) +{ + const VVCFrame *current_picture = h->ref; + int i, j; + + for (i = 0, j = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) { + const VVCFrame *frame = NULL; + + while (!frame && j < FF_ARRAY_ELEMS(h->DPB)) { + if ((&h->DPB[j] != current_picture ) && + (h->DPB[j].flags & (VVC_FRAME_FLAG_LONG_REF | VVC_FRAME_FLAG_SHORT_REF))) + frame = &h->DPB[j]; + j++; + } + + init_vaapi_pic(&pp->ReferenceFrames[i]); + + if (frame) { + VAAPIDecodePictureVVC *pic; + fill_vaapi_pic(&pp->ReferenceFrames[i], frame); + pic = frame->hwaccel_picture_private; + if (!pic->decode_issued) + pp->ReferenceFrames[i].flags |= VA_PICTURE_VVC_UNAVAILABLE_REFERENCE; + } + } +} + +static int vaapi_vvc_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + const VVCContext *h = avctx->priv_data; + VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs]; + const H266RawSPS *sps = fc->ps.sps->r; + const H266RawPPS *pps = fc->ps.pps->r; + const H266RawPictureHeader *ph = fc->ps.ph.r; + VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private; + VAPictureParameterBufferVVC *pic_param = &pic->pic_param; + uint16_t tile_dim, exp_slice_height_in_ctus[VVC_MAX_SLICES] = {0}; + int i, j, k, err; + + pic->pic.output_surface = ff_vaapi_get_surface_id(fc->ref->frame); + + *pic_param = (VAPictureParameterBufferVVC) { + .pps_pic_width_in_luma_samples = pps->pps_pic_width_in_luma_samples, + .pps_pic_height_in_luma_samples = pps->pps_pic_height_in_luma_samples, + .sps_num_subpics_minus1 = sps->sps_num_subpics_minus1, + .sps_chroma_format_idc = sps->sps_chroma_format_idc, + .sps_bitdepth_minus8 = sps->sps_bitdepth_minus8, + .sps_log2_ctu_size_minus5 = sps->sps_log2_ctu_size_minus5, + .sps_log2_min_luma_coding_block_size_minus2 = sps->sps_log2_min_luma_coding_block_size_minus2, + .sps_log2_transform_skip_max_size_minus2 = sps->sps_log2_transform_skip_max_size_minus2, + .sps_six_minus_max_num_merge_cand = sps->sps_six_minus_max_num_merge_cand, + .sps_five_minus_max_num_subblock_merge_cand = sps->sps_five_minus_max_num_subblock_merge_cand, + .sps_max_num_merge_cand_minus_max_num_gpm_cand = sps->sps_max_num_merge_cand_minus_max_num_gpm_cand, + .sps_log2_parallel_merge_level_minus2 = sps->sps_log2_parallel_merge_level_minus2, + .sps_min_qp_prime_ts = sps->sps_min_qp_prime_ts, + .sps_six_minus_max_num_ibc_merge_cand = sps->sps_six_minus_max_num_ibc_merge_cand, + .sps_num_ladf_intervals_minus2 = sps->sps_num_ladf_intervals_minus2, + .sps_ladf_lowest_interval_qp_offset = sps->sps_ladf_lowest_interval_qp_offset, + .sps_flags.bits = { + .sps_subpic_info_present_flag = sps->sps_subpic_info_present_flag, + .sps_independent_subpics_flag = sps->sps_independent_subpics_flag, + .sps_subpic_same_size_flag = sps->sps_subpic_same_size_flag, + .sps_entropy_coding_sync_enabled_flag = sps->sps_entropy_coding_sync_enabled_flag, + .sps_qtbtt_dual_tree_intra_flag = sps->sps_qtbtt_dual_tree_intra_flag, + .sps_max_luma_transform_size_64_flag = sps->sps_max_luma_transform_size_64_flag, + .sps_transform_skip_enabled_flag = sps->sps_transform_skip_enabled_flag, + .sps_bdpcm_enabled_flag = sps->sps_bdpcm_enabled_flag, + .sps_mts_enabled_flag = sps->sps_mts_enabled_flag, + .sps_explicit_mts_intra_enabled_flag = sps->sps_explicit_mts_intra_enabled_flag, + .sps_explicit_mts_inter_enabled_flag = sps->sps_explicit_mts_inter_enabled_flag, + .sps_lfnst_enabled_flag = sps->sps_lfnst_enabled_flag, + .sps_joint_cbcr_enabled_flag = sps->sps_joint_cbcr_enabled_flag, + .sps_same_qp_table_for_chroma_flag = sps->sps_same_qp_table_for_chroma_flag, + .sps_sao_enabled_flag = sps->sps_sao_enabled_flag, + .sps_alf_enabled_flag = sps->sps_alf_enabled_flag, + .sps_ccalf_enabled_flag = sps->sps_ccalf_enabled_flag, + .sps_lmcs_enabled_flag = sps->sps_lmcs_enabled_flag, + .sps_sbtmvp_enabled_flag = sps->sps_sbtmvp_enabled_flag, + .sps_amvr_enabled_flag = sps->sps_amvr_enabled_flag, + .sps_smvd_enabled_flag = sps->sps_smvd_enabled_flag, + .sps_mmvd_enabled_flag = sps->sps_mmvd_enabled_flag, + .sps_sbt_enabled_flag = sps->sps_sbt_enabled_flag, + .sps_affine_enabled_flag = sps->sps_affine_enabled_flag, + .sps_6param_affine_enabled_flag = sps->sps_6param_affine_enabled_flag, + .sps_affine_amvr_enabled_flag = sps->sps_affine_amvr_enabled_flag, + .sps_affine_prof_enabled_flag = sps->sps_affine_prof_enabled_flag, + .sps_bcw_enabled_flag = sps->sps_bcw_enabled_flag, + .sps_ciip_enabled_flag = sps->sps_ciip_enabled_flag, + .sps_gpm_enabled_flag = sps->sps_gpm_enabled_flag, + .sps_isp_enabled_flag = sps->sps_isp_enabled_flag, + .sps_mrl_enabled_flag = sps->sps_mrl_enabled_flag, + .sps_mip_enabled_flag = sps->sps_mip_enabled_flag, + .sps_cclm_enabled_flag = sps->sps_cclm_enabled_flag, + .sps_chroma_horizontal_collocated_flag = sps->sps_chroma_horizontal_collocated_flag, + .sps_chroma_vertical_collocated_flag = sps->sps_chroma_vertical_collocated_flag, + .sps_palette_enabled_flag = sps->sps_palette_enabled_flag, + .sps_act_enabled_flag = sps->sps_act_enabled_flag, + .sps_ibc_enabled_flag = sps->sps_ibc_enabled_flag, + .sps_ladf_enabled_flag = sps->sps_ladf_enabled_flag, + .sps_explicit_scaling_list_enabled_flag = sps->sps_explicit_scaling_list_enabled_flag, + .sps_scaling_matrix_for_lfnst_disabled_flag = sps->sps_scaling_matrix_for_lfnst_disabled_flag, + .sps_scaling_matrix_for_alternative_colour_space_disabled_flag = sps->sps_scaling_matrix_for_alternative_colour_space_disabled_flag, + .sps_scaling_matrix_designated_colour_space_flag = sps->sps_scaling_matrix_designated_colour_space_flag, + .sps_virtual_boundaries_enabled_flag = sps->sps_virtual_boundaries_enabled_flag, + .sps_virtual_boundaries_present_flag = sps->sps_virtual_boundaries_present_flag, + }, + .NumVerVirtualBoundaries = sps->sps_virtual_boundaries_present_flag ? + sps->sps_num_ver_virtual_boundaries : + ph->ph_num_ver_virtual_boundaries, + .NumHorVirtualBoundaries = sps->sps_virtual_boundaries_present_flag ? + sps->sps_num_hor_virtual_boundaries : + ph->ph_num_hor_virtual_boundaries, + .pps_scaling_win_left_offset = pps->pps_scaling_win_left_offset, + .pps_scaling_win_right_offset = pps->pps_scaling_win_right_offset, + .pps_scaling_win_top_offset = pps->pps_scaling_win_top_offset, + .pps_scaling_win_bottom_offset = pps->pps_scaling_win_bottom_offset, + .pps_num_exp_tile_columns_minus1 = pps->pps_num_exp_tile_columns_minus1, + .pps_num_exp_tile_rows_minus1 = pps->pps_num_exp_tile_rows_minus1, + .pps_num_slices_in_pic_minus1 = pps->pps_num_slices_in_pic_minus1, + .pps_pic_width_minus_wraparound_offset = pps->pps_pic_width_minus_wraparound_offset, + .pps_cb_qp_offset = pps->pps_cb_qp_offset, + .pps_cr_qp_offset = pps->pps_cr_qp_offset, + .pps_joint_cbcr_qp_offset_value = pps->pps_joint_cbcr_qp_offset_value, + .pps_chroma_qp_offset_list_len_minus1 = pps->pps_chroma_qp_offset_list_len_minus1, + .pps_flags.bits = { + .pps_loop_filter_across_tiles_enabled_flag = pps->pps_loop_filter_across_tiles_enabled_flag, + .pps_rect_slice_flag = pps->pps_rect_slice_flag, + .pps_single_slice_per_subpic_flag = pps->pps_single_slice_per_subpic_flag, + .pps_loop_filter_across_slices_enabled_flag = pps->pps_loop_filter_across_slices_enabled_flag, + .pps_weighted_pred_flag = pps->pps_weighted_pred_flag, + .pps_weighted_bipred_flag = pps->pps_weighted_bipred_flag, + .pps_ref_wraparound_enabled_flag = pps->pps_ref_wraparound_enabled_flag, + .pps_cu_qp_delta_enabled_flag = pps->pps_cu_qp_delta_enabled_flag, + .pps_cu_chroma_qp_offset_list_enabled_flag = pps->pps_cu_chroma_qp_offset_list_enabled_flag, + .pps_deblocking_filter_override_enabled_flag = pps->pps_deblocking_filter_override_enabled_flag, + .pps_deblocking_filter_disabled_flag = pps->pps_deblocking_filter_disabled_flag, + .pps_dbf_info_in_ph_flag = pps->pps_dbf_info_in_ph_flag, + .pps_sao_info_in_ph_flag = pps->pps_sao_info_in_ph_flag, + .pps_alf_info_in_ph_flag = pps->pps_alf_info_in_ph_flag, + }, + .ph_lmcs_aps_id = ph->ph_lmcs_aps_id, + .ph_scaling_list_aps_id = ph->ph_scaling_list_aps_id, + .ph_log2_diff_min_qt_min_cb_intra_slice_luma = ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma, + .ph_max_mtt_hierarchy_depth_intra_slice_luma = ph->ph_max_mtt_hierarchy_depth_intra_slice_luma, + .ph_log2_diff_max_bt_min_qt_intra_slice_luma = ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma, + .ph_log2_diff_max_tt_min_qt_intra_slice_luma = ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma, + .ph_log2_diff_min_qt_min_cb_intra_slice_chroma = ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma, + .ph_max_mtt_hierarchy_depth_intra_slice_chroma = ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma, + .ph_log2_diff_max_bt_min_qt_intra_slice_chroma = ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma, + .ph_log2_diff_max_tt_min_qt_intra_slice_chroma = ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma, + .ph_cu_qp_delta_subdiv_intra_slice = ph->ph_cu_qp_delta_subdiv_intra_slice, + .ph_cu_chroma_qp_offset_subdiv_intra_slice = ph->ph_cu_chroma_qp_offset_subdiv_intra_slice, + .ph_log2_diff_min_qt_min_cb_inter_slice = ph->ph_log2_diff_min_qt_min_cb_inter_slice, + .ph_max_mtt_hierarchy_depth_inter_slice = ph->ph_max_mtt_hierarchy_depth_inter_slice, + .ph_log2_diff_max_bt_min_qt_inter_slice = ph->ph_log2_diff_max_bt_min_qt_inter_slice, + .ph_log2_diff_max_tt_min_qt_inter_slice = ph->ph_log2_diff_max_tt_min_qt_inter_slice, + .ph_cu_qp_delta_subdiv_inter_slice = ph->ph_cu_qp_delta_subdiv_inter_slice, + .ph_cu_chroma_qp_offset_subdiv_inter_slice = ph->ph_cu_chroma_qp_offset_subdiv_inter_slice, + .ph_flags.bits= { + .ph_non_ref_pic_flag = ph->ph_non_ref_pic_flag, + .ph_alf_enabled_flag = ph->ph_alf_enabled_flag, + .ph_alf_cb_enabled_flag = ph->ph_alf_cb_enabled_flag, + .ph_alf_cr_enabled_flag = ph->ph_alf_cr_enabled_flag, + .ph_alf_cc_cb_enabled_flag = ph->ph_alf_cc_cb_enabled_flag, + .ph_alf_cc_cr_enabled_flag = ph->ph_alf_cc_cr_enabled_flag, + .ph_lmcs_enabled_flag = ph->ph_lmcs_enabled_flag, + .ph_chroma_residual_scale_flag = ph->ph_chroma_residual_scale_flag, + .ph_explicit_scaling_list_enabled_flag = ph->ph_explicit_scaling_list_enabled_flag, + .ph_virtual_boundaries_present_flag = ph->ph_virtual_boundaries_present_flag, + .ph_temporal_mvp_enabled_flag = ph->ph_temporal_mvp_enabled_flag, + .ph_mmvd_fullpel_only_flag = ph->ph_mmvd_fullpel_only_flag, + .ph_mvd_l1_zero_flag = ph->ph_mvd_l1_zero_flag, + .ph_bdof_disabled_flag = ph->ph_bdof_disabled_flag, + .ph_dmvr_disabled_flag = ph->ph_dmvr_disabled_flag, + .ph_prof_disabled_flag = ph->ph_prof_disabled_flag, + .ph_joint_cbcr_sign_flag = ph->ph_joint_cbcr_sign_flag, + .ph_sao_luma_enabled_flag = ph->ph_sao_luma_enabled_flag, + .ph_sao_chroma_enabled_flag = ph->ph_sao_chroma_enabled_flag, + .ph_deblocking_filter_disabled_flag = ph->ph_deblocking_filter_disabled_flag, + }, + .PicMiscFlags.fields = { + .IntraPicFlag = pps->pps_mixed_nalu_types_in_pic_flag ? 0 : IS_IRAP(h) ? 1 : 0, + } + }; + + fill_vaapi_pic(&pic_param->CurrPic, fc->ref); + fill_vaapi_reference_frames(fc, pic_param); + + for (i = 0; i < VVC_MAX_SAMPLE_ARRAYS; i++) + for (j = 0; j < VVC_MAX_POINTS_IN_QP_TABLE; j++) + pic_param->ChromaQpTable[i][j] = fc->ps.sps->chroma_qp_table[i][j]; + for (i = 0; i < 4; i++) { + pic_param->sps_ladf_qp_offset[i] = sps->sps_ladf_qp_offset[i]; + pic_param->sps_ladf_delta_threshold_minus1[i] = sps->sps_ladf_delta_threshold_minus1[i]; + } + + for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ? sps->sps_num_ver_virtual_boundaries : ph->ph_num_ver_virtual_boundaries); i++) { + pic_param->VirtualBoundaryPosX[i] = (sps->sps_virtual_boundaries_present_flag ? + (sps->sps_virtual_boundary_pos_x_minus1[i] + 1) : + (ph->ph_virtual_boundary_pos_x_minus1[i] + 1)) * 8; + } + + for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ? sps->sps_num_hor_virtual_boundaries : ph->ph_num_hor_virtual_boundaries); i++) { + pic_param->VirtualBoundaryPosY[i] = (sps->sps_virtual_boundaries_present_flag ? + (sps->sps_virtual_boundary_pos_y_minus1[i] + 1) : + (ph->ph_virtual_boundary_pos_y_minus1[i] + 1)) * 8; + } + + for (i = 0; i < 6; i++) { + pic_param->pps_cb_qp_offset_list[i] = pps->pps_cb_qp_offset_list[i]; + pic_param->pps_cr_qp_offset_list[i] = pps->pps_cr_qp_offset_list[i]; + pic_param->pps_joint_cbcr_qp_offset_list[i] = pps->pps_joint_cbcr_qp_offset_list[i]; + } + + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VAPictureParameterBufferType, + &pic->pic_param, sizeof(VAPictureParameterBufferVVC)); + if (err < 0) + goto fail; + + for (i = 0; i <= sps->sps_num_subpics_minus1 && sps->sps_subpic_info_present_flag; i++) { + VASubPicVVC subpic_param = { + .sps_subpic_ctu_top_left_x = sps->sps_subpic_ctu_top_left_x[i], + .sps_subpic_ctu_top_left_y = sps->sps_subpic_ctu_top_left_y[i], + .sps_subpic_width_minus1 = sps->sps_subpic_width_minus1[i], + .sps_subpic_height_minus1 = sps->sps_subpic_height_minus1[i], + .SubpicIdVal = pps->sub_pic_id_val[i], + .subpic_flags.bits = { + .sps_subpic_treated_as_pic_flag = sps->sps_subpic_treated_as_pic_flag[i], + .sps_loop_filter_across_subpic_enabled_flag = sps->sps_loop_filter_across_subpic_enabled_flag[i], + } + }; + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VASubPicBufferType, + &subpic_param, sizeof(VASubPicVVC)); + if (err < 0) + goto fail; + } + + for (i = 0; i < VVC_MAX_ALF_COUNT; i++) { + const VVCALF *alf_list = h->ps.alf_list[i]; + if (alf_list) { + const H266RawAPS *alf = alf_list->r; + VAAlfDataVVC alf_param = { + .aps_adaptation_parameter_set_id = i, + .alf_luma_num_filters_signalled_minus1 = alf->alf_luma_num_filters_signalled_minus1, + .alf_chroma_num_alt_filters_minus1 = alf->alf_chroma_num_alt_filters_minus1, + .alf_cc_cb_filters_signalled_minus1 = alf->alf_cc_cb_filters_signalled_minus1, + .alf_cc_cr_filters_signalled_minus1 = alf->alf_cc_cr_filters_signalled_minus1, + .alf_flags.bits = { + .alf_luma_filter_signal_flag = alf->alf_luma_filter_signal_flag, + .alf_chroma_filter_signal_flag = alf->alf_chroma_filter_signal_flag, + .alf_cc_cb_filter_signal_flag = alf->alf_cc_cb_filter_signal_flag, + .alf_cc_cr_filter_signal_flag = alf->alf_cc_cr_filter_signal_flag, + .alf_luma_clip_flag = alf->alf_luma_clip_flag, + .alf_chroma_clip_flag = alf->alf_chroma_clip_flag, + } + }; + + for (j = 0; j < 25; j++) + alf_param.alf_luma_coeff_delta_idx[j] = alf->alf_luma_coeff_delta_idx[j]; + + for (j = 0; j < 25; j++) { + for (k = 0; k < 12; k++) { + alf_param.filtCoeff[j][k] = alf->alf_luma_coeff_abs[j][k] * (1 - 2 * alf->alf_luma_coeff_sign[j][k]); + alf_param.alf_luma_clip_idx[j][k] = alf->alf_luma_clip_idx[j][k]; + } + } + + for (j = 0; j < 8; j++) { + for (k = 0; k < 6; k++) { + alf_param.AlfCoeffC[j][k] = alf->alf_chroma_coeff_abs[j][k] * (1 - 2 * alf->alf_chroma_coeff_sign[j][k]); + alf_param.alf_chroma_clip_idx[j][k] = alf->alf_chroma_clip_idx[j][k]; + } + } + + for (j = 0; j < 4; j++) { + for (k = 0; k < 7; k++) { + if (alf->alf_cc_cb_mapped_coeff_abs[j][k]) + alf_param.CcAlfApsCoeffCb[j][k] = (1 - 2 * alf->alf_cc_cb_coeff_sign[j][k]) * (1 << (alf->alf_cc_cb_mapped_coeff_abs[j][k] - 1)); + if (alf->alf_cc_cr_mapped_coeff_abs[j][k]) + alf_param.CcAlfApsCoeffCr[j][k] = (1 - 2 * alf->alf_cc_cr_coeff_sign[j][k]) * (1 << (alf->alf_cc_cr_mapped_coeff_abs[j][k] - 1)); + } + } + + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VAAlfBufferType, + &alf_param, sizeof(VAAlfDataVVC)); + if (err < 0) + goto fail; + } + } + + for (i = 0; i < VVC_MAX_LMCS_COUNT; i++) { + const H266RawAPS *lmcs = h->ps.lmcs_list[i]; + if (lmcs) { + VALmcsDataVVC lmcs_param = { + .aps_adaptation_parameter_set_id = i, + .lmcs_min_bin_idx = lmcs->lmcs_min_bin_idx, + .lmcs_delta_max_bin_idx = lmcs->lmcs_delta_max_bin_idx, + .lmcsDeltaCrs = (1 - 2 * lmcs->lmcs_delta_sign_crs_flag) * lmcs->lmcs_delta_abs_crs, + }; + + for (j = lmcs->lmcs_min_bin_idx; j <= 15 - lmcs->lmcs_delta_max_bin_idx; j++) + lmcs_param.lmcsDeltaCW[j] = (1 - 2 * lmcs->lmcs_delta_sign_cw_flag[j]) * lmcs->lmcs_delta_abs_cw[j]; + + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VALmcsBufferType, + &lmcs_param, sizeof(VALmcsDataVVC)); + if (err < 0) + goto fail; + } + } + + for (i = 0; i < VVC_MAX_SL_COUNT; i++) { + const VVCScalingList *sl = h->ps.scaling_list[i]; + if (sl) { + int l; + + VAScalingListVVC sl_param = { + .aps_adaptation_parameter_set_id = i, + }; + + for (j = 0; j < 14; j++) + sl_param.ScalingMatrixDCRec[j] = sl->scaling_matrix_dc_rec[j]; + + for (j = 0; j < 2; j++) + for (k = 0; k < 2; k++) + for (l = 0; l < 2; l++) + sl_param.ScalingMatrixRec2x2[j][k][l] = sl->scaling_matrix_rec[j][l * 2 + k]; + + for (j = 2; j < 8; j++) + for (k = 0; k < 4; k++) + for (l = 0; l < 4; l++) + sl_param.ScalingMatrixRec4x4[j - 2][k][l] = sl->scaling_matrix_rec[j][l * 4 + k]; + + for (j = 8; j < 28; j++) + for (k = 0; k < 8; k++) + for (l = 0; l < 8; l++) + sl_param.ScalingMatrixRec8x8[j - 8][k][l] = sl->scaling_matrix_rec[j][l * 8 + k]; + + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VAIQMatrixBufferType, + &sl_param, sizeof(VAScalingListVVC)); + if (err < 0) + goto fail; + } + } + + for (i = 0; i <= pps->pps_num_exp_tile_columns_minus1; i++) { + tile_dim = pps->pps_tile_column_width_minus1[i]; + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VATileBufferType, + &tile_dim, sizeof(tile_dim)); + if (err < 0) + goto fail; + } + + for (i = 0; i <= pps->pps_num_exp_tile_rows_minus1; i++) { + tile_dim = pps->pps_tile_row_height_minus1[i]; + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VATileBufferType, + &tile_dim, sizeof(tile_dim)); + if (err < 0) + goto fail; + } + + if (!pps->pps_no_pic_partition_flag && pps->pps_rect_slice_flag && !pps->pps_single_slice_per_subpic_flag) { + for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) { + for (j = 0; j < pps->pps_num_exp_slices_in_tile[i]; j++) { + exp_slice_height_in_ctus[i + j] = pps->pps_exp_slice_height_in_ctus_minus1[i][j] + 1; + } + } + for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) { + VASliceStructVVC ss_param = { + .SliceTopLeftTileIdx = pps->slice_top_left_tile_idx[i], + .pps_slice_width_in_tiles_minus1 = pps->pps_slice_width_in_tiles_minus1[i], + .pps_slice_height_in_tiles_minus1 = pps->pps_slice_height_in_tiles_minus1[i], + }; + + if (pps->pps_slice_width_in_tiles_minus1[i] > 0 || pps->pps_slice_height_in_tiles_minus1[i] > 0) + ss_param.pps_exp_slice_height_in_ctus_minus1 = 0; + else { + if (pps->num_slices_in_tile[i] == 1) + ss_param.pps_exp_slice_height_in_ctus_minus1 = pps->row_height_val[pps->slice_top_left_tile_idx[i] / pps->num_tile_columns] - 1; + else if (exp_slice_height_in_ctus[i]) + ss_param.pps_exp_slice_height_in_ctus_minus1 = exp_slice_height_in_ctus[i] - 1; + else + continue; + } + + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VASliceStructBufferType, + &ss_param, sizeof(VASliceStructVVC)); + if (err < 0) + goto fail; + } + } + + return 0; + +fail: + ff_vaapi_decode_cancel(avctx, &pic->pic); + return err; +} + +static uint8_t get_ref_pic_index(const VVCContext *h, const VVCFrame *frame) +{ + VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs]; + VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private; + VAPictureParameterBufferVVC *pp = (VAPictureParameterBufferVVC *)&pic->pic_param; + uint8_t i; + + if (!frame) + return 0xFF; + + for (i = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) { + VASurfaceID pid = pp->ReferenceFrames[i].picture_id; + int poc = pp->ReferenceFrames[i].pic_order_cnt; + if (pid != VA_INVALID_ID && pid == ff_vaapi_get_surface_id(frame->frame) && poc == frame->poc) + return i; + } + + return 0xFF; +} + +static int get_slice_data_byte_offset(const uint8_t *buffer, uint32_t size, const SliceContext* sc) +{ + const H266RawSlice *slice = sc->ref; + int num_identical_bytes = slice->data_size < 32 ? slice->data_size : 32; + + for (int i = 0; i < size; i++) { + int skip_bytes = 0; + if (i >=2 && buffer[i] == 0x03 && !buffer[i - 1] && !buffer[i - 2]) + continue; + + for (int j = 0; j < num_identical_bytes; j++) { + if (i >= 2 && buffer[i + j + skip_bytes] == 0x03 && !buffer[i + j + skip_bytes - 1] && !buffer[i + j + skip_bytes - 2]) + skip_bytes++; + + if (buffer[i + j + skip_bytes] != slice->data[j]) + break; + + if (j + 1 == num_identical_bytes) + return i; + } + } + + return 0; +} + +static int vaapi_vvc_decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + const VVCContext *h = avctx->priv_data; + VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs]; + const SliceContext *sc = fc->slices[fc->nb_slices]; + const H266RawPPS *pps = fc->ps.pps->r; + const H266RawPictureHeader *ph = fc->ps.ph.r; + const H266RawSliceHeader *sh = sc->sh.r; + VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private; + VASliceParameterBufferVVC *slice_param = &pic->slice_param; + int nb_list, i, err; + + *slice_param = (VASliceParameterBufferVVC) { + .slice_data_size = size, + .slice_data_offset = 0, + .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, + .slice_data_byte_offset = get_slice_data_byte_offset(buffer, size, sc), + .sh_subpic_id = sh->sh_subpic_id, + .sh_slice_address = sh->sh_slice_address, + .sh_num_tiles_in_slice_minus1 = sh->sh_num_tiles_in_slice_minus1, + .sh_slice_type = sh->sh_slice_type, + .sh_num_alf_aps_ids_luma = sh->sh_num_alf_aps_ids_luma, + .sh_alf_aps_id_chroma = sh->sh_alf_aps_id_chroma, + .sh_alf_cc_cb_aps_id = sh->sh_alf_cc_cb_aps_id, + .sh_alf_cc_cr_aps_id = sh->sh_alf_cc_cr_aps_id, + .NumRefIdxActive[0] = sh->num_ref_idx_active[0], + .NumRefIdxActive[1] = sh->num_ref_idx_active[1], + .sh_collocated_ref_idx = sh->sh_collocated_ref_idx, + .SliceQpY = pps->pps_qp_delta_info_in_ph_flag ? + 26 + pps->pps_init_qp_minus26 + ph->ph_qp_delta : + 26 + pps->pps_init_qp_minus26 + sh->sh_qp_delta, + .sh_cb_qp_offset = sh->sh_cb_qp_offset, + .sh_cr_qp_offset = sh->sh_cr_qp_offset, + .sh_joint_cbcr_qp_offset = sh->sh_joint_cbcr_qp_offset, + .sh_luma_beta_offset_div2 = sh->sh_luma_beta_offset_div2, + .sh_luma_tc_offset_div2 = sh->sh_luma_tc_offset_div2, + .sh_cb_beta_offset_div2 = sh->sh_cb_beta_offset_div2, + .sh_cb_tc_offset_div2 = sh->sh_cb_tc_offset_div2, + .sh_cr_beta_offset_div2 = sh->sh_cr_beta_offset_div2, + .sh_cr_tc_offset_div2 = sh->sh_cr_tc_offset_div2, + .WPInfo = { + .luma_log2_weight_denom = sh->sh_pred_weight_table.luma_log2_weight_denom, + .delta_chroma_log2_weight_denom = sh->sh_pred_weight_table.delta_chroma_log2_weight_denom, + .num_l0_weights = sh->sh_pred_weight_table.num_l0_weights, + .num_l1_weights = sh->sh_pred_weight_table.num_l1_weights, + }, + .sh_flags.bits = { + .sh_alf_enabled_flag = sh->sh_alf_enabled_flag, + .sh_alf_cb_enabled_flag = sh->sh_alf_cb_enabled_flag, + .sh_alf_cr_enabled_flag = sh->sh_alf_cr_enabled_flag, + .sh_alf_cc_cb_enabled_flag = sh->sh_alf_cc_cb_enabled_flag, + .sh_alf_cc_cr_enabled_flag = sh->sh_alf_cc_cr_enabled_flag, + .sh_lmcs_used_flag = sh->sh_lmcs_used_flag, + .sh_explicit_scaling_list_used_flag = sh->sh_explicit_scaling_list_used_flag, + .sh_cabac_init_flag = sh->sh_cabac_init_flag, + .sh_collocated_from_l0_flag = sh->sh_collocated_from_l0_flag, + .sh_cu_chroma_qp_offset_enabled_flag = sh->sh_cu_chroma_qp_offset_enabled_flag, + .sh_sao_luma_used_flag = sh->sh_sao_luma_used_flag, + .sh_sao_chroma_used_flag = sh->sh_sao_chroma_used_flag, + .sh_deblocking_filter_disabled_flag = sh->sh_deblocking_filter_disabled_flag, + .sh_dep_quant_used_flag = sh->sh_dep_quant_used_flag, + .sh_sign_data_hiding_used_flag = sh->sh_sign_data_hiding_used_flag, + .sh_ts_residual_coding_disabled_flag = sh->sh_ts_residual_coding_disabled_flag, + }, + }; + + memset(&slice_param->RefPicList, 0xFF, sizeof(slice_param->RefPicList)); + + nb_list = (sh->sh_slice_type == VVC_SLICE_TYPE_B) ? + 2 : (sh->sh_slice_type == VVC_SLICE_TYPE_I ? 0 : 1); + for (int list_idx = 0; list_idx < nb_list; list_idx++) { + RefPicList *rpl = &sc->rpl[list_idx]; + + for (i = 0; i < rpl->nb_refs; i++) + slice_param->RefPicList[list_idx][i] = get_ref_pic_index(h, rpl->refs[i].ref); + } + + for (i = 0; i < 7; i++) + slice_param->sh_alf_aps_id_luma[i] = sh->sh_alf_aps_id_luma[i]; + + for (i = 0; i < 15; i++) { + slice_param->WPInfo.luma_weight_l0_flag[i] = sh->sh_pred_weight_table.luma_weight_l0_flag[i]; + slice_param->WPInfo.chroma_weight_l0_flag[i] = sh->sh_pred_weight_table.chroma_weight_l0_flag[i]; + slice_param->WPInfo.delta_luma_weight_l0[i] = sh->sh_pred_weight_table.delta_luma_weight_l0[i]; + slice_param->WPInfo.luma_offset_l0[i] = sh->sh_pred_weight_table.luma_offset_l0[i]; + slice_param->WPInfo.luma_weight_l1_flag[i] = sh->sh_pred_weight_table.luma_weight_l1_flag[i]; + slice_param->WPInfo.chroma_weight_l1_flag[i] = sh->sh_pred_weight_table.chroma_weight_l1_flag[i]; + slice_param->WPInfo.delta_luma_weight_l1[i] = sh->sh_pred_weight_table.delta_luma_weight_l1[i]; + slice_param->WPInfo.luma_offset_l1[i] = sh->sh_pred_weight_table.luma_offset_l1[i]; + } + + for (i = 0; i < 15; i++) { + for (int j = 0; j < 2; j++) { + slice_param->WPInfo.delta_chroma_weight_l0[i][j] = sh->sh_pred_weight_table.delta_chroma_weight_l0[i][j]; + slice_param->WPInfo.delta_chroma_offset_l0[i][j] = sh->sh_pred_weight_table.delta_chroma_offset_l0[i][j]; + slice_param->WPInfo.delta_chroma_weight_l1[i][j] = sh->sh_pred_weight_table.delta_chroma_weight_l1[i][j]; + slice_param->WPInfo.delta_chroma_offset_l1[i][j] = sh->sh_pred_weight_table.delta_chroma_offset_l1[i][j]; + } + } + + err = ff_vaapi_decode_make_slice_buffer(avctx, &pic->pic, + &pic->slice_param, 1, + sizeof(VASliceParameterBufferVVC), + buffer, size); + if (err) { + ff_vaapi_decode_cancel(avctx, &pic->pic); + return err; + } + + return 0; +} + +static int vaapi_vvc_end_frame(AVCodecContext *avctx) +{ + + const VVCContext *h = avctx->priv_data; + VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs]; + VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private; + int ret; + + ret = ff_vaapi_decode_issue(avctx, &pic->pic); + if (ret < 0) + goto fail; + + pic->decode_issued = 1; + + return 0; + +fail: + ff_vaapi_decode_cancel(avctx, &pic->pic); + return ret; +} + +const FFHWAccel ff_vvc_vaapi_hwaccel = { + .p.name = "vvc_vaapi", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_VVC, + .p.pix_fmt = AV_PIX_FMT_VAAPI, + .start_frame = &vaapi_vvc_start_frame, + .end_frame = &vaapi_vvc_end_frame, + .decode_slice = &vaapi_vvc_decode_slice, + .frame_priv_data_size = sizeof(VAAPIDecodePictureVVC), + .init = &ff_vaapi_decode_init, + .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, + .priv_data_size = sizeof(VAAPIDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE, +}; diff --git a/libavcodec/vb.c b/libavcodec/vb.c index 0a9528a8d..42d6f26f6 100644 --- a/libavcodec/vb.c +++ b/libavcodec/vb.c @@ -231,11 +231,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, } memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = flags & VB_HAS_PALETTE; -FF_ENABLE_DEPRECATION_WARNINGS -#endif outptr = frame->data[0]; srcptr = c->frame; diff --git a/libavcodec/vbndec.c b/libavcodec/vbndec.c index a96843f21..b8acbce47 100644 --- a/libavcodec/vbndec.c +++ b/libavcodec/vbndec.c @@ -142,7 +142,7 @@ static int vbn_decode_frame(AVCodecContext *avctx, return image_len; if (image_len < linesize * avctx->coded_height) { - av_log(avctx, AV_LOG_ERROR, "Insufficent data\n"); + av_log(avctx, AV_LOG_ERROR, "Insufficient data\n"); ret = AVERROR_INVALIDDATA; goto out; } diff --git a/libavcodec/vbnenc.c b/libavcodec/vbnenc.c index 55e436b5e..c65357498 100644 --- a/libavcodec/vbnenc.c +++ b/libavcodec/vbnenc.c @@ -161,8 +161,6 @@ const FFCodec ff_vbn_encoder = { .init = vbn_init, FF_CODEC_ENCODE_CB(vbn_encode), .priv_data_size = sizeof(VBNContext), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB24), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c index d263c70be..e365aaec8 100644 --- a/libavcodec/vc1.c +++ b/libavcodec/vc1.c @@ -94,7 +94,7 @@ static void decode_colskip(uint8_t* plane, int width, int height, int stride, */ static int bitplane_decoding(uint8_t* data, int *raw_flag, VC1Context *v) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; int imode, x, y, code, offset; uint8_t invert, *planep = data; @@ -161,7 +161,7 @@ static int bitplane_decoding(uint8_t* data, int *raw_flag, VC1Context *v) planep += stride * 3; } if (width & 1) - decode_colskip(data, 1, height, stride, &v->s.gb); + decode_colskip(data, 1, height, stride, &v->gb); } else { // 3x2 planep += (height & 1) * stride; for (y = height & 1; y < height; y += 2) { @@ -182,16 +182,16 @@ static int bitplane_decoding(uint8_t* data, int *raw_flag, VC1Context *v) } x = width % 3; if (x) - decode_colskip(data, x, height, stride, &v->s.gb); + decode_colskip(data, x, height, stride, &v->gb); if (height & 1) - decode_rowskip(data + x, width - x, 1, stride, &v->s.gb); + decode_rowskip(data + x, width - x, 1, stride, &v->gb); } break; case IMODE_ROWSKIP: - decode_rowskip(data, width, height, stride, &v->s.gb); + decode_rowskip(data, width, height, stride, &v->gb); break; case IMODE_COLSKIP: - decode_colskip(data, width, height, stride, &v->s.gb); + decode_colskip(data, width, height, stride, &v->gb); break; default: break; @@ -227,7 +227,7 @@ static int bitplane_decoding(uint8_t* data, int *raw_flag, VC1Context *v) */ static int vop_dquant_decoding(VC1Context *v) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; int pqdiff; //variable size @@ -300,13 +300,13 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo v->frmrtq_postproc = get_bits(gb, 3); //common // (bitrate-32kbps)/64kbps v->bitrtq_postproc = get_bits(gb, 5); //common - v->s.loop_filter = get_bits1(gb); //common - if (v->s.loop_filter == 1 && v->profile == PROFILE_SIMPLE) { + v->loop_filter = get_bits1(gb); //common + if (v->loop_filter == 1 && v->profile == PROFILE_SIMPLE) { av_log(avctx, AV_LOG_ERROR, "LOOPFILTER shall not be enabled in Simple Profile\n"); } if (v->s.avctx->skip_loop_filter >= AVDISCARD_ALL) - v->s.loop_filter = 0; + v->loop_filter = 0; v->res_x8 = get_bits1(gb); //reserved v->multires = get_bits1(gb); @@ -343,7 +343,7 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo "RANGERED should be set to 0 in Simple Profile\n"); } - v->s.max_b_frames = avctx->max_b_frames = get_bits(gb, 3); //common + v->max_b_frames = avctx->max_b_frames = get_bits(gb, 3); //common v->quantizer_mode = get_bits(gb, 2); //common v->finterpflag = get_bits1(gb); //common @@ -376,7 +376,7 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo "Rangered=%i, VSTransform=%i, Overlap=%i, SyncMarker=%i\n" "DQuant=%i, Quantizer mode=%i, Max B-frames=%i\n", v->profile, v->frmrtq_postproc, v->bitrtq_postproc, - v->s.loop_filter, v->multires, v->fastuvmc, v->extended_mv, + v->loop_filter, v->multires, v->fastuvmc, v->extended_mv, v->rangered, v->vstransform, v->overlap, v->resync_marker, v->dquant, v->quantizer_mode, avctx->max_b_frames); return 0; @@ -415,23 +415,15 @@ static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb) "LoopFilter=%i, ChromaFormat=%i, Pulldown=%i, Interlace: %i\n" "TFCTRflag=%i, FINTERPflag=%i\n", v->level, v->frmrtq_postproc, v->bitrtq_postproc, - v->s.loop_filter, v->chromaformat, v->broadcast, v->interlace, + v->loop_filter, v->chromaformat, v->broadcast, v->interlace, v->tfcntrflag, v->finterpflag); -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - if (v->broadcast) { // Pulldown may be present - v->s.avctx->ticks_per_frame = 2; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - v->psf = get_bits1(gb); if (v->psf) { //PsF, 6.1.13 av_log(v->s.avctx, AV_LOG_ERROR, "Progressive Segmented Frame mode: not supported (yet)\n"); return -1; } - v->s.max_b_frames = v->s.avctx->max_b_frames = 7; + v->max_b_frames = v->s.avctx->max_b_frames = 7; if (get_bits1(gb)) { //Display Info - decoding is not affected by it int w, h, ar = 0; av_log(v->s.avctx, AV_LOG_DEBUG, "Display extended info:\n"); @@ -509,9 +501,9 @@ int ff_vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContex v->closed_entry = get_bits1(gb); v->panscanflag = get_bits1(gb); v->refdist_flag = get_bits1(gb); - v->s.loop_filter = get_bits1(gb); + v->loop_filter = get_bits1(gb); if (v->s.avctx->skip_loop_filter >= AVDISCARD_ALL) - v->s.loop_filter = 0; + v->loop_filter = 0; v->fastuvmc = get_bits1(gb); v->extended_mv = get_bits1(gb); v->dquant = get_bits(gb, 2); @@ -552,7 +544,7 @@ int ff_vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContex "BrokenLink=%i, ClosedEntry=%i, PanscanFlag=%i\n" "RefDist=%i, Postproc=%i, FastUVMC=%i, ExtMV=%i\n" "DQuant=%i, VSTransform=%i, Overlap=%i, Qmode=%i\n", - v->broken_link, v->closed_entry, v->panscanflag, v->refdist_flag, v->s.loop_filter, + v->broken_link, v->closed_entry, v->panscanflag, v->refdist_flag, v->loop_filter, v->fastuvmc, v->extended_mv, v->dquant, v->vstransform, v->overlap, v->quantizer_mode); return 0; @@ -732,7 +724,6 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) INIT_LUT(v->lumscale, v->lumshift, v->last_luty[0], v->last_lutuv[0], 1); INIT_LUT(v->lumscale, v->lumshift, v->last_luty[1], v->last_lutuv[1], 1); } - v->qs_last = v->s.quarter_sample; if (v->mv_mode == MV_PMODE_INTENSITY_COMP) { v->s.quarter_sample = (v->mv_mode2 != MV_PMODE_1MV_HPEL && v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN); @@ -765,7 +756,7 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) return AVERROR_INVALIDDATA; /* Hopefully this is correct for P-frames */ - v->s.mv_table_index = get_bits(gb, 2); //but using ff_vc1_ tables + v->mv_table_index = get_bits(gb, 2); //but using ff_vc1_ tables v->cbptab = get_bits(gb, 2); v->cbpcy_vlc = ff_vc1_cbpcy_p_vlc[v->cbptab]; @@ -789,7 +780,6 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) v->tt_index = (v->pq > 4) + (v->pq > 12); v->mv_mode = get_bits1(gb) ? MV_PMODE_1MV : MV_PMODE_1MV_HPEL_BILIN; - v->qs_last = v->s.quarter_sample; v->s.quarter_sample = (v->mv_mode == MV_PMODE_1MV); v->s.mspel = v->s.quarter_sample; @@ -804,7 +794,7 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) av_log(v->s.avctx, AV_LOG_DEBUG, "MB Skip plane encoding: " "Imode: %i, Invert: %i\n", status>>1, status&1); - v->s.mv_table_index = get_bits(gb, 2); + v->mv_table_index = get_bits(gb, 2); v->cbptab = get_bits(gb, 2); v->cbpcy_vlc = ff_vc1_cbpcy_p_vlc[v->cbptab]; @@ -833,7 +823,7 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) v->y_ac_table_index = decode012(gb); } /* DC Syntax */ - v->s.dc_table_index = get_bits1(gb); + v->dc_table_index = get_bits1(gb); } if (v->s.pict_type == AV_PICTURE_TYPE_BI) { @@ -1127,7 +1117,6 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) } v->last_use_ic = 1; } - v->qs_last = v->s.quarter_sample; if (v->mv_mode == MV_PMODE_INTENSITY_COMP) { v->s.quarter_sample = (v->mv_mode2 != MV_PMODE_1MV_HPEL && v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN); @@ -1158,11 +1147,10 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) "Imode: %i, Invert: %i\n", status>>1, status&1); /* Hopefully this is correct for P-frames */ - v->s.mv_table_index = get_bits(gb, 2); //but using ff_vc1_ tables + v->mv_table_index = get_bits(gb, 2); //but using ff_vc1_ tables v->cbptab = get_bits(gb, 2); v->cbpcy_vlc = ff_vc1_cbpcy_p_vlc[v->cbptab]; } else if (v->fcm == ILACE_FRAME) { // frame interlaced - v->qs_last = v->s.quarter_sample; v->s.quarter_sample = 1; v->s.mspel = 1; } else { // field interlaced @@ -1226,7 +1214,6 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) mvmode = get_unary(gb, 1, 3); lowquant = (v->pq > 12) ? 0 : 1; v->mv_mode = ff_vc1_mv_pmode_table2[lowquant][mvmode]; - v->qs_last = v->s.quarter_sample; v->s.quarter_sample = (v->mv_mode == MV_PMODE_1MV || v->mv_mode == MV_PMODE_MIXED_MV); v->s.mspel = (v->mv_mode != MV_PMODE_1MV_HPEL_BILIN); status = bitplane_decoding(v->forward_mb_plane, &v->fmb_is_raw, v); @@ -1256,7 +1243,6 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) v->intcomp = 0; v->mv_mode = MV_PMODE_1MV; v->fourmvswitch = 0; - v->qs_last = v->s.quarter_sample; v->s.quarter_sample = 1; v->s.mspel = 1; status = bitplane_decoding(v->direct_mb_plane, &v->dmb_is_raw, v); @@ -1282,7 +1268,6 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) v->fourmvbp_vlc = ff_vc1_4mv_block_pattern_vlc[v->fourmvbptab]; } else { v->mv_mode = get_bits1(gb) ? MV_PMODE_1MV : MV_PMODE_1MV_HPEL_BILIN; - v->qs_last = v->s.quarter_sample; v->s.quarter_sample = (v->mv_mode == MV_PMODE_1MV); v->s.mspel = v->s.quarter_sample; status = bitplane_decoding(v->direct_mb_plane, &v->dmb_is_raw, v); @@ -1295,7 +1280,7 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) return -1; av_log(v->s.avctx, AV_LOG_DEBUG, "MB Skip plane encoding: " "Imode: %i, Invert: %i\n", status>>1, status&1); - v->s.mv_table_index = get_bits(gb, 2); + v->mv_table_index = get_bits(gb, 2); v->cbptab = get_bits(gb, 2); v->cbpcy_vlc = ff_vc1_cbpcy_p_vlc[v->cbptab]; } @@ -1330,7 +1315,7 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) } /* DC Syntax */ - v->s.dc_table_index = get_bits1(gb); + v->dc_table_index = get_bits1(gb); if ((v->s.pict_type == AV_PICTURE_TYPE_I || v->s.pict_type == AV_PICTURE_TYPE_BI) && v->dquant) { av_log(v->s.avctx, AV_LOG_DEBUG, "VOP DQuant info\n"); diff --git a/libavcodec/vc1.h b/libavcodec/vc1.h index 185236662..f2a52c19c 100644 --- a/libavcodec/vc1.h +++ b/libavcodec/vc1.h @@ -24,12 +24,15 @@ #define AVCODEC_VC1_H #include "avcodec.h" +#include "get_bits.h" #include "h264chroma.h" #include "mpegvideo.h" #include "intrax8.h" #include "vc1_common.h" #include "vc1dsp.h" +#include "libavutil/mem_internal.h" + #define AC_VLC_BITS 9 /** Sequence quantizer mode */ @@ -172,6 +175,7 @@ enum Imode { */ typedef struct VC1Context{ MpegEncContext s; + GetBitContext gb; IntraX8Context x8; H264ChromaContext h264chroma; VC1DSPContext vc1dsp; @@ -216,12 +220,14 @@ typedef struct VC1Context{ int profile; ///< 2 bits, Profile int frmrtq_postproc; ///< 3 bits, int bitrtq_postproc; ///< 5 bits, quantized framerate-based postprocessing strength + int loop_filter; int max_coded_width, max_coded_height; int fastuvmc; ///< Rounding of qpel vector to hpel ? (not in Simple) int extended_mv; ///< Ext MV in P/B (not in Simple) int dquant; ///< How qscale varies with MBs, 2 bits (not in Simple) int vstransform; ///< variable-size [48]x[48] transform type + info int overlap; ///< overlapped transforms in use + int max_b_frames; ///< max number of B-frames int quantizer_mode; ///< 2 bits, quantizer mode used for sequence, see QUANT_* int finterpflag; ///< INTERPFRM present //@} @@ -245,6 +251,7 @@ typedef struct VC1Context{ uint8_t dqsbedge; uint8_t dqbilevel; //@} + int dc_table_index; /** AC coding set indexes * @see 8.1.1.10, p(1)10 */ @@ -252,6 +259,8 @@ typedef struct VC1Context{ int c_ac_table_index; ///< Chroma index from ACFRM element int y_ac_table_index; ///< Luma index from AC2FRM element //@} + int esc3_level_length; + int esc3_run_length; int ttfrm; ///< Transform type info present at frame level uint8_t ttmbf; ///< Transform type flag int *ttblk_base, *ttblk; ///< Transform type at the block level @@ -259,7 +268,7 @@ typedef struct VC1Context{ int codingset2; ///< index of current table set from 11.8 to use for chroma block decoding int pqindex; ///< raw pqindex used in coding set selection int a_avail, c_avail; - uint8_t *mb_type_base, *mb_type[3]; + uint8_t *mb_type_base, *mb_type; /** Luma compensation parameters */ @@ -281,6 +290,7 @@ typedef struct VC1Context{ uint8_t pquantizer; ///< Uniform (over sequence) quantizer in use const VLCElem *cbpcy_vlc; ///< CBPCY VLC table int tt_index; ///< Index for Transform Type tables (to decode TTMB) + int mv_table_index; uint8_t* mv_type_mb_plane; ///< bitplane for mv_type == (4MV) uint8_t* direct_mb_plane; ///< bitplane for "direct" MBs uint8_t* forward_mb_plane; ///< bitplane for "forward" MBs @@ -309,10 +319,6 @@ typedef struct VC1Context{ uint8_t numpanscanwin; uint8_t tfcntr; uint8_t rptfrm, tff, rff; - uint16_t topleftx; - uint16_t toplefty; - uint16_t bottomrightx; - uint16_t bottomrighty; uint8_t uvsamp; uint8_t postproc; int hrd_num_leaky_buckets; @@ -360,7 +366,6 @@ typedef struct VC1Context{ int cur_field_type; ///< 0: top, 1: bottom int ref_field_type[2]; ///< forward and backward reference field type (top or bottom) int blocks_off, mb_off; - int qs_last; ///< if qpel has been used in the previous (tr.) picture int bmvtype; int frfd, brfd; ///< reference frame distance (forward or backward) int first_pic_header_flag; @@ -397,6 +402,8 @@ typedef struct VC1Context{ int parse_only; ///< Context is used within parser int resync_marker; ///< could this stream contain resync markers + + DECLARE_ALIGNED_32(int16_t, blocks)[6][64]; } VC1Context; /** diff --git a/libavcodec/vc1_block.c b/libavcodec/vc1_block.c index 1c422d902..10cb45908 100644 --- a/libavcodec/vc1_block.c +++ b/libavcodec/vc1_block.c @@ -90,8 +90,8 @@ static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) if (!s->first_slice_line && v->fcm != ILACE_FRAME) { if (s->mb_x) { for (i = 0; i < block_count; i++) { - if (i > 3 ? v->mb_type[0][s->block_index[i] - s->block_wrap[i] - 1] : - v->mb_type[0][s->block_index[i] - 2 * s->block_wrap[i] - 2]) { + if (i > 3 ? v->mb_type[s->block_index[i] - s->block_wrap[i] - 1] : + v->mb_type[s->block_index[i] - 2 * s->block_wrap[i] - 2]) { dest = s->dest[0] + ((i & 2) - 4) * 4 * s->linesize + ((i & 1) - 2) * 8; if (put_signed) s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][block_map[i]], @@ -106,8 +106,8 @@ static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) } if (s->mb_x == v->end_mb_x - 1) { for (i = 0; i < block_count; i++) { - if (i > 3 ? v->mb_type[0][s->block_index[i] - s->block_wrap[i]] : - v->mb_type[0][s->block_index[i] - 2 * s->block_wrap[i]]) { + if (i > 3 ? v->mb_type[s->block_index[i] - s->block_wrap[i]] : + v->mb_type[s->block_index[i] - 2 * s->block_wrap[i]]) { dest = s->dest[0] + ((i & 2) - 4) * 4 * s->linesize + (i & 1) * 8; if (put_signed) s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][block_map[i]], @@ -126,8 +126,8 @@ static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) if (v->fcm == ILACE_FRAME) fieldtx = v->fieldtx_plane[s->mb_y * s->mb_stride + s->mb_x - 1]; for (i = 0; i < block_count; i++) { - if (i > 3 ? v->mb_type[0][s->block_index[i] - 1] : - v->mb_type[0][s->block_index[i] - 2]) { + if (i > 3 ? v->mb_type[s->block_index[i] - 1] : + v->mb_type[s->block_index[i] - 2]) { if (fieldtx) dest = s->dest[0] + ((i & 2) >> 1) * s->linesize + ((i & 1) - 2) * 8; else @@ -147,7 +147,7 @@ static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) if (v->fcm == ILACE_FRAME) fieldtx = v->fieldtx_plane[s->mb_y * s->mb_stride + s->mb_x]; for (i = 0; i < block_count; i++) { - if (v->mb_type[0][s->block_index[i]]) { + if (v->mb_type[s->block_index[i]]) { if (fieldtx) dest = s->dest[0] + ((i & 2) >> 1) * s->linesize + (i & 1) * 8; else @@ -227,7 +227,7 @@ static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) * @param _dmv_y Vertical differential for decoded MV */ #define GET_MVDATA(_dmv_x, _dmv_y) \ - index = 1 + get_vlc2(gb, ff_vc1_mv_diff_vlc[s->mv_table_index], \ + index = 1 + get_vlc2(gb, ff_vc1_mv_diff_vlc[v->mv_table_index], \ VC1_MV_DIFF_VLC_BITS, 2); \ if (index > 36) { \ mb_has_coeffs = 1; \ @@ -269,7 +269,7 @@ static av_always_inline void get_mvdata_interlaced(VC1Context *v, int *dmv_x, { int index, index1; int extend_x, extend_y; - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; int bits, esc; int val, sign; @@ -354,11 +354,10 @@ static inline int vc1_i_pred_dc(MpegEncContext *s, int overlap, int pq, int n, }; /* find prediction - wmv3_dc_scale always used here in fact */ - if (n < 4) scale = s->y_dc_scale; - else scale = s->c_dc_scale; + scale = s->y_dc_scale; wrap = s->block_wrap[n]; - dc_val = s->dc_val[0] + s->block_index[n]; + dc_val = s->dc_val + s->block_index[n]; /* B A * C X @@ -418,12 +417,12 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, /* scale predictors if needed */ q1 = FFABS(s->cur_pic.qscale_table[mb_pos]); - dqscale_index = s->y_dc_scale_table[q1] - 1; + dqscale_index = ff_wmv3_dc_scale_table[q1] - 1; if (dqscale_index < 0) return 0; wrap = s->block_wrap[n]; - dc_val = s->dc_val[0] + s->block_index[n]; + dc_val = s->dc_val + s->block_index[n]; /* B A * C X @@ -435,12 +434,12 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, if (c_avail && (n != 1 && n != 3)) { q2 = FFABS(s->cur_pic.qscale_table[mb_pos - 1]); if (q2 && q2 != q1) - c = (int)((unsigned)c * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; + c = (int)((unsigned)c * ff_wmv3_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; } if (a_avail && (n != 2 && n != 3)) { q2 = FFABS(s->cur_pic.qscale_table[mb_pos - s->mb_stride]); if (q2 && q2 != q1) - a = (int)((unsigned)a * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; + a = (int)((unsigned)a * ff_wmv3_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; } if (a_avail && c_avail && (n != 3)) { int off = mb_pos; @@ -450,7 +449,7 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, off -= s->mb_stride; q2 = FFABS(s->cur_pic.qscale_table[off]); if (q2 && q2 != q1) - b = (int)((unsigned)b * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; + b = (int)((unsigned)b * ff_wmv3_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; } if (c_avail && (!a_avail || abs(a - b) <= abs(b - c))) { @@ -477,8 +476,7 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, * @{ */ -static inline int vc1_coded_block_pred(MpegEncContext * s, int n, - uint8_t **coded_block_ptr) +static inline int vc1_coded_block_pred(MPVContext *const s, int n, int diff) { int xy, wrap, pred, a, b, c; @@ -499,9 +497,9 @@ static inline int vc1_coded_block_pred(MpegEncContext * s, int n, } /* store value */ - *coded_block_ptr = &s->coded_block[xy]; + s->coded_block[xy] = pred ^ diff; - return pred; + return pred ^ diff; } /** @@ -516,7 +514,7 @@ static inline int vc1_coded_block_pred(MpegEncContext * s, int n, static int vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip, int *value, int codingset) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; int index, run, level, lst, sign; index = get_vlc2(gb, ff_vc1_ac_coeff_table[codingset], AC_VLC_BITS, 3); @@ -550,19 +548,19 @@ static int vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip, sign = get_bits1(gb); } else { lst = get_bits1(gb); - if (v->s.esc3_level_length == 0) { + if (v->esc3_level_length == 0) { if (v->pq < 8 || v->dquantfrm) { // table 59 - v->s.esc3_level_length = get_bits(gb, 3); - if (!v->s.esc3_level_length) - v->s.esc3_level_length = get_bits(gb, 2) + 8; + v->esc3_level_length = get_bits(gb, 3); + if (!v->esc3_level_length) + v->esc3_level_length = get_bits(gb, 2) + 8; } else { // table 60 - v->s.esc3_level_length = get_unary(gb, 1, 6) + 2; + v->esc3_level_length = get_unary(gb, 1, 6) + 2; } - v->s.esc3_run_length = 3 + get_bits(gb, 2); + v->esc3_run_length = 3 + get_bits(gb, 2); } - run = get_bits(gb, v->s.esc3_run_length); + run = get_bits(gb, v->esc3_run_length); sign = get_bits1(gb); - level = get_bits(gb, v->s.esc3_level_length); + level = get_bits(gb, v->esc3_level_length); } } @@ -583,16 +581,15 @@ static int vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip, static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, int coded, int codingset) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; MpegEncContext *s = &v->s; int dc_pred_dir = 0; /* Direction of the DC prediction used */ - int i; int16_t *dc_val; int16_t *ac_val, *ac_val2; int dcdiff, scale; /* Get DC differential */ - dcdiff = get_vlc2(&s->gb, ff_msmp4_dc_vlc[s->dc_table_index][n >= 4], + dcdiff = get_vlc2(gb, ff_msmp4_dc_vlc[v->dc_table_index][n >= 4], MSMP4_DC_VLC_BITS, 3); if (dcdiff) { const int m = (v->pq == 1 || v->pq == 2) ? 3 - v->pq : 0; @@ -611,13 +608,9 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, *dc_val = dcdiff; /* Store the quantized DC coeff, used for prediction */ - if (n < 4) - scale = s->y_dc_scale; - else - scale = s->c_dc_scale; - block[0] = dcdiff * scale; + block[0] = dcdiff * s->y_dc_scale; - ac_val = s->ac_val[0][s->block_index[n]]; + ac_val = s->ac_val[s->block_index[n]]; ac_val2 = ac_val; if (dc_pred_dir) // left ac_val -= 16; @@ -627,7 +620,6 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, scale = v->pq * 2 + v->halfpq; //AC Decoding - i = !!coded; if (coded) { int last = 0, skip, value; @@ -642,14 +634,14 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, } else zz_table = v->zz_8x8[1]; - while (!last) { + for (int i = 1; !last; ++i) { int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); if (ret < 0) return ret; i += skip; if (i > 63) break; - block[zz_table[i++]] = value; + block[zz_table[i]] = value; } /* apply AC prediction if needed */ @@ -701,8 +693,6 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, } } } - if (s->ac_pred) i = 63; - s->block_last_index[n] = i; return 0; } @@ -718,10 +708,9 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, int coded, int codingset, int mquant) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; MpegEncContext *s = &v->s; int dc_pred_dir = 0; /* Direction of the DC prediction used */ - int i; int16_t *dc_val = NULL; int16_t *ac_val, *ac_val2; int dcdiff; @@ -733,7 +722,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, int quant = FFABS(mquant); /* Get DC differential */ - dcdiff = get_vlc2(&s->gb, ff_msmp4_dc_vlc[s->dc_table_index][n >= 4], + dcdiff = get_vlc2(gb, ff_msmp4_dc_vlc[v->dc_table_index][n >= 4], MSMP4_DC_VLC_BITS, 3); if (dcdiff) { const int m = (quant == 1 || quant == 2) ? 3 - quant : 0; @@ -752,11 +741,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, *dc_val = dcdiff; /* Store the quantized DC coeff, used for prediction */ - if (n < 4) - scale = s->y_dc_scale; - else - scale = s->c_dc_scale; - block[0] = dcdiff * scale; + block[0] = dcdiff * s->y_dc_scale; /* check if AC is needed at all */ if (!a_avail && !c_avail) @@ -764,7 +749,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, scale = quant * 2 + ((mquant < 0) ? 0 : v->halfpq); - ac_val = s->ac_val[0][s->block_index[n]]; + ac_val = s->ac_val[s->block_index[n]]; ac_val2 = ac_val; if (dc_pred_dir) // left ac_val -= 16; @@ -787,7 +772,6 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, } //AC Decoding - i = 1; if (coded) { int last = 0, skip, value; @@ -810,14 +794,14 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, zz_table = v->zzi_8x8; } - while (!last) { + for (int i = 1; !last; ++i) { int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); if (ret < 0) return ret; i += skip; if (i > 63) break; - block[zz_table[i++]] = value; + block[zz_table[i]] = value; } /* apply AC prediction if needed */ @@ -889,8 +873,6 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, } } } - if (use_pred) i = 63; - s->block_last_index[n] = i; return 0; } @@ -906,10 +888,9 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, int coded, int mquant, int codingset) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; MpegEncContext *s = &v->s; int dc_pred_dir = 0; /* Direction of the DC prediction used */ - int i; int16_t *dc_val = NULL; int16_t *ac_val, *ac_val2; int dcdiff; @@ -925,12 +906,11 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, /* XXX: Guard against dumb values of mquant */ quant = av_clip_uintp2(quant, 5); - /* Set DC scale - y and c use the same */ - s->y_dc_scale = s->y_dc_scale_table[quant]; - s->c_dc_scale = s->c_dc_scale_table[quant]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[quant]; /* Get DC differential */ - dcdiff = get_vlc2(&s->gb, ff_msmp4_dc_vlc[s->dc_table_index][n >= 4], + dcdiff = get_vlc2(gb, ff_msmp4_dc_vlc[v->dc_table_index][n >= 4], MSMP4_DC_VLC_BITS, 3); if (dcdiff) { const int m = (quant == 1 || quant == 2) ? 3 - quant : 0; @@ -949,21 +929,15 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, *dc_val = dcdiff; /* Store the quantized DC coeff, used for prediction */ - - if (n < 4) { - block[0] = dcdiff * s->y_dc_scale; - } else { - block[0] = dcdiff * s->c_dc_scale; - } + block[0] = dcdiff * s->y_dc_scale; //AC Decoding - i = 1; /* check if AC is needed at all and adjust direction if needed */ if (!a_avail) dc_pred_dir = 1; if (!c_avail) dc_pred_dir = 0; if (!a_avail && !c_avail) use_pred = 0; - ac_val = s->ac_val[0][s->block_index[n]]; + ac_val = s->ac_val[s->block_index[n]]; ac_val2 = ac_val; scale = quant * 2 + ((mquant < 0) ? 0 : v->halfpq); @@ -988,7 +962,7 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, int last = 0, skip, value; int k; - while (!last) { + for (int i = 1; !last; ++i) { int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); if (ret < 0) return ret; @@ -996,15 +970,15 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, if (i > 63) break; if (v->fcm == PROGRESSIVE) - block[v->zz_8x8[0][i++]] = value; + block[v->zz_8x8[0][i]] = value; else { if (use_pred && (v->fcm == ILACE_FRAME)) { if (!dc_pred_dir) // top - block[v->zz_8x8[2][i++]] = value; + block[v->zz_8x8[2][i]] = value; else // left - block[v->zz_8x8[3][i++]] = value; + block[v->zz_8x8[3][i]] = value; } else { - block[v->zzi_8x8[i++]] = value; + block[v->zzi_8x8[i]] = value; } } } @@ -1048,8 +1022,6 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, if (!v->pquantizer) block[k] += (block[k] < 0) ? -quant : quant; } - - if (use_pred) i = 63; } else { // no AC coeffs int k; @@ -1097,10 +1069,8 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, block[k << v->top_blk_sh] += (block[k << v->top_blk_sh] < 0) ? -quant : quant; } } - i = 63; } } - s->block_last_index[n] = i; return 0; } @@ -1113,7 +1083,7 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, int *ttmb_out) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i, j; int subblkpat = 0; int scale, off, idx, last, skip, value; @@ -1282,7 +1252,7 @@ static const uint8_t size_table[6] = { 0, 2, 3, 4, 5, 8 }; static int vc1_decode_p_mb(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i, j; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp; /* cbp decoding stuff */ @@ -1319,7 +1289,7 @@ static int vc1_decode_p_mb(VC1Context *v) s->cur_pic.motion_val[1][s->block_index[0]][1] = 0; } s->cur_pic.mb_type[mb_pos] = s->mb_intra ? MB_TYPE_INTRA : MB_TYPE_16x16; - ff_vc1_pred_mv(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type[0], 0, 0); + ff_vc1_pred_mv(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type, 0, 0); /* FIXME Set DC val for inter block ? */ if (s->mb_intra && !mb_has_coeffs) { @@ -1329,7 +1299,7 @@ static int vc1_decode_p_mb(VC1Context *v) } else if (mb_has_coeffs) { if (s->mb_intra) s->ac_pred = get_bits1(gb); - cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); GET_MQUANT(); } else { mquant = v->pq; @@ -1343,18 +1313,18 @@ static int vc1_decode_p_mb(VC1Context *v) if (!s->mb_intra) ff_vc1_mc_1mv(v, 0); dst_idx = 0; for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize); - v->mb_type[0][s->block_index[i]] = s->mb_intra; + v->mb_type[s->block_index[i]] = s->mb_intra; if (s->mb_intra) { /* check if prediction blocks A and C are available */ v->a_avail = v->c_avail = 0; if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); @@ -1383,12 +1353,12 @@ static int vc1_decode_p_mb(VC1Context *v) } else { // skipped s->mb_intra = 0; for (i = 0; i < 6; i++) { - v->mb_type[0][s->block_index[i]] = 0; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; } s->cur_pic.mb_type[mb_pos] = MB_TYPE_SKIP; s->cur_pic.qscale_table[mb_pos] = 0; - ff_vc1_pred_mv(v, 0, 0, 0, 1, v->range_x, v->range_y, v->mb_type[0], 0, 0); + ff_vc1_pred_mv(v, 0, 0, 0, 1, v->range_x, v->range_y, v->mb_type, 0, 0); ff_vc1_mc_1mv(v, 0); } } else { // 4MV mode @@ -1396,10 +1366,10 @@ static int vc1_decode_p_mb(VC1Context *v) int intra_count = 0, coded_inter = 0; int is_intra[6], is_coded[6]; /* Get CBPCY */ - cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); for (i = 0; i < 6; i++) { val = ((cbp >> (5 - i)) & 1); - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; s->mb_intra = 0; if (i < 4) { dmv_x = dmv_y = 0; @@ -1408,7 +1378,7 @@ static int vc1_decode_p_mb(VC1Context *v) if (val) { GET_MVDATA(dmv_x, dmv_y); } - ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0], 0, 0); + ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type, 0, 0); if (!s->mb_intra) ff_vc1_mc_4mv_luma(v, i, 0, 0); intra_count += s->mb_intra; @@ -1421,7 +1391,7 @@ static int vc1_decode_p_mb(VC1Context *v) } if (i == 4) ff_vc1_mc_4mv_chroma(v, 0); - v->mb_type[0][s->block_index[i]] = is_intra[i]; + v->mb_type[s->block_index[i]] = is_intra[i]; if (!coded_inter) coded_inter = !is_intra[i] & is_coded[i]; } @@ -1436,8 +1406,8 @@ static int vc1_decode_p_mb(VC1Context *v) int intrapred = 0; for (i = 0; i < 6; i++) if (is_intra[i]) { - if (((!s->first_slice_line || (i == 2 || i == 3)) && v->mb_type[0][s->block_index[i] - s->block_wrap[i]]) - || ((s->mb_x || (i == 1 || i == 3)) && v->mb_type[0][s->block_index[i] - 1])) { + if (((!s->first_slice_line || (i == 2 || i == 3)) && v->mb_type[s->block_index[i] - s->block_wrap[i]]) + || ((s->mb_x || (i == 1 || i == 3)) && v->mb_type[s->block_index[i] - 1])) { intrapred = 1; break; } @@ -1457,9 +1427,9 @@ static int vc1_decode_p_mb(VC1Context *v) /* check if prediction blocks A and C are available */ v->a_avail = v->c_avail = 0; if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, is_coded[i], mquant, (i & 4) ? v->codingset2 : v->codingset); @@ -1491,11 +1461,11 @@ static int vc1_decode_p_mb(VC1Context *v) s->mb_intra = 0; s->cur_pic.qscale_table[mb_pos] = 0; for (i = 0; i < 6; i++) { - v->mb_type[0][s->block_index[i]] = 0; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; } for (i = 0; i < 4; i++) { - ff_vc1_pred_mv(v, i, 0, 0, 0, v->range_x, v->range_y, v->mb_type[0], 0, 0); + ff_vc1_pred_mv(v, i, 0, 0, 0, v->range_x, v->range_y, v->mb_type, 0, 0); ff_vc1_mc_4mv_luma(v, i, 0, 0); } ff_vc1_mc_4mv_chroma(v, 0); @@ -1519,7 +1489,7 @@ end: static int vc1_decode_p_mb_intfr(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp = 0; /* cbp decoding stuff */ @@ -1589,24 +1559,23 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) fieldtx = v->fieldtx_plane[mb_pos] = get_bits1(gb); mb_has_coeffs = get_bits1(gb); if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; - /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; - s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[FFABS(mquant)]; dst_idx = 0; for (i = 0; i < 6; i++) { v->a_avail = v->c_avail = 0; - v->mb_type[0][s->block_index[i]] = 1; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 1; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); @@ -1621,7 +1590,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) } else { // inter MB mb_has_coeffs = ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][3]; if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); if (ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][0] == MV_PMODE_INTFR_2MV_FIELD) { v->twomvbp = get_vlc2(gb, v->twomvbp_vlc, VC1_2MV_BLOCK_PATTERN_VLC_BITS, 1); } else { @@ -1632,7 +1601,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) } s->mb_intra = v->is_intra[s->mb_x] = 0; for (i = 0; i < 6; i++) - v->mb_type[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; fieldtx = v->fieldtx_plane[mb_pos] = ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][1]; /* for all motion vector read MVDATA and motion compensate each block */ dst_idx = 0; @@ -1678,7 +1647,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) if (!v->ttmbf && cbp) ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index], VC1_TTMB_VLC_BITS, 2); for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (!fieldtx) @@ -1702,8 +1671,8 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) } else { // skipped s->mb_intra = v->is_intra[s->mb_x] = 0; for (i = 0; i < 6; i++) { - v->mb_type[0][s->block_index[i]] = 0; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; } s->cur_pic.mb_type[mb_pos] = MB_TYPE_SKIP; s->cur_pic.qscale_table[mb_pos] = 0; @@ -1728,7 +1697,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) static int vc1_decode_p_mb_intfi(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp = 0; /* cbp decoding stuff */ @@ -1756,24 +1725,23 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA; GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; - /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; - s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[FFABS(mquant)]; v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); mb_has_coeffs = idx_mbmode & 1; if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_ICBPCY_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_ICBPCY_VLC_BITS, 2); dst_idx = 0; for (i = 0; i < 6; i++) { v->a_avail = v->c_avail = 0; - v->mb_type[0][s->block_index[i]] = 1; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 1; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); @@ -1788,13 +1756,13 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) s->mb_intra = v->is_intra[s->mb_x] = 0; s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_16x16; for (i = 0; i < 6; i++) - v->mb_type[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; if (idx_mbmode <= 5) { // 1-MV dmv_x = dmv_y = pred_flag = 0; if (idx_mbmode & 1) { get_mvdata_interlaced(v, &dmv_x, &dmv_y, &pred_flag); } - ff_vc1_pred_mv(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type[0], pred_flag, 0); + ff_vc1_pred_mv(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type, pred_flag, 0); ff_vc1_mc_1mv(v, 0); mb_has_coeffs = !(idx_mbmode & 2); } else { // 4-MV @@ -1803,14 +1771,14 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) dmv_x = dmv_y = pred_flag = 0; if (v->fourmvbp & (8 >> i)) get_mvdata_interlaced(v, &dmv_x, &dmv_y, &pred_flag); - ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0], pred_flag, 0); + ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type, pred_flag, 0); ff_vc1_mc_4mv_luma(v, i, 0, 0); } ff_vc1_mc_4mv_chroma(v, 0); mb_has_coeffs = idx_mbmode & 1; } if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); if (cbp) { GET_MQUANT(); } @@ -1820,7 +1788,7 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) } dst_idx = 0; for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); off = (i & 4) ? 0 : (i & 1) * 8 + (i & 2) * 4 * s->linesize; @@ -1854,7 +1822,7 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) static int vc1_decode_b_mb(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i, j; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp = 0; /* cbp decoding stuff */ @@ -1884,8 +1852,8 @@ static int vc1_decode_b_mb(VC1Context *v) dmv_x[0] = dmv_x[1] = dmv_y[0] = dmv_y[1] = 0; for (i = 0; i < 6; i++) { - v->mb_type[0][s->block_index[i]] = 0; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; } s->cur_pic.qscale_table[mb_pos] = 0; @@ -1911,7 +1879,7 @@ static int vc1_decode_b_mb(VC1Context *v) } } for (i = 0; i < 6; i++) - v->mb_type[0][s->block_index[i]] = s->mb_intra; + v->mb_type[s->block_index[i]] = s->mb_intra; if (skipped) { if (direct) @@ -1921,7 +1889,7 @@ static int vc1_decode_b_mb(VC1Context *v) return 0; } if (direct) { - cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); GET_MQUANT(); s->mb_intra = 0; s->cur_pic.qscale_table[mb_pos] = mquant; @@ -1959,7 +1927,7 @@ static int vc1_decode_b_mb(VC1Context *v) } if (s->mb_intra) s->ac_pred = get_bits1(gb); - cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; if (!v->ttmbf && !s->mb_intra && mb_has_coeffs) @@ -1968,35 +1936,35 @@ static int vc1_decode_b_mb(VC1Context *v) } dst_idx = 0; for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize); - v->mb_type[0][s->block_index[i]] = s->mb_intra; + v->mb_type[s->block_index[i]] = s->mb_intra; if (s->mb_intra) { /* check if prediction blocks A and C are available */ v->a_avail = v->c_avail = 0; if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; - ret = vc1_decode_intra_block(v, s->block[i], i, val, mquant, + ret = vc1_decode_intra_block(v, v->blocks[i], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); if (ret < 0) return ret; if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(s->block[i]); + v->vc1dsp.vc1_inv_trans_8x8(v->blocks[i]); if (v->rangeredfrm) for (j = 0; j < 64; j++) - s->block[i][j] *= 2; - s->idsp.put_signed_pixels_clamped(s->block[i], + v->blocks[i][j] *= 2; + s->idsp.put_signed_pixels_clamped(v->blocks[i], s->dest[dst_idx] + off, i & 4 ? s->uvlinesize : s->linesize); } else if (val) { - int pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, + int pat = vc1_decode_p_block(v, v->blocks[i], i, mquant, ttmb, first_block, s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize, CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), NULL); @@ -2015,7 +1983,7 @@ static int vc1_decode_b_mb(VC1Context *v) static int vc1_decode_b_mb_intfi(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i, j; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp = 0; /* cbp decoding stuff */ @@ -2044,37 +2012,36 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA; GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; - /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; - s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[FFABS(mquant)]; v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); mb_has_coeffs = idx_mbmode & 1; if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_ICBPCY_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_ICBPCY_VLC_BITS, 2); dst_idx = 0; for (i = 0; i < 6; i++) { v->a_avail = v->c_avail = 0; - v->mb_type[0][s->block_index[i]] = 1; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 1; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; - ret = vc1_decode_intra_block(v, s->block[i], i, val, mquant, + ret = vc1_decode_intra_block(v, v->blocks[i], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); if (ret < 0) return ret; if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(s->block[i]); + v->vc1dsp.vc1_inv_trans_8x8(v->blocks[i]); if (v->rangeredfrm) for (j = 0; j < 64; j++) - s->block[i][j] <<= 1; + v->blocks[i][j] <<= 1; off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize); - s->idsp.put_signed_pixels_clamped(s->block[i], + s->idsp.put_signed_pixels_clamped(v->blocks[i], s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize); @@ -2083,7 +2050,7 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) s->mb_intra = v->is_intra[s->mb_x] = 0; s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_16x16; for (i = 0; i < 6; i++) - v->mb_type[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; if (v->fmb_is_raw) fwd = v->forward_mb_plane[mb_pos] = get_bits1(gb); else @@ -2146,7 +2113,7 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) mb_has_coeffs = idx_mbmode & 1; } if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); if (cbp) { GET_MQUANT(); } @@ -2156,12 +2123,12 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) } dst_idx = 0; for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); off = (i & 4) ? 0 : (i & 1) * 8 + (i & 2) * 4 * s->linesize; if (val) { - pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, + pat = vc1_decode_p_block(v, v->blocks[i], i, mquant, ttmb, first_block, s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize, CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt); @@ -2185,7 +2152,7 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) static int vc1_decode_b_mb_intfr(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i, j; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp = 0; /* cbp decoding stuff */ @@ -2241,32 +2208,31 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) fieldtx = v->fieldtx_plane[mb_pos] = get_bits1(gb); mb_has_coeffs = get_bits1(gb); if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; - /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; - s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[FFABS(mquant)]; dst_idx = 0; for (i = 0; i < 6; i++) { v->a_avail = v->c_avail = 0; - v->mb_type[0][s->block_index[i]] = 1; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 1; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; - ret = vc1_decode_intra_block(v, s->block[i], i, val, mquant, + ret = vc1_decode_intra_block(v, v->blocks[i], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); if (ret < 0) return ret; if (CONFIG_GRAY && i > 3 && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(s->block[i]); + v->vc1dsp.vc1_inv_trans_8x8(v->blocks[i]); if (i < 4) { stride_y = s->linesize << fieldtx; off = (fieldtx) ? ((i & 1) * 8) + ((i & 2) >> 1) * s->linesize : (i & 1) * 8 + 4 * (i & 2) * s->linesize; @@ -2274,7 +2240,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) stride_y = s->uvlinesize; off = 0; } - s->idsp.put_signed_pixels_clamped(s->block[i], + s->idsp.put_signed_pixels_clamped(v->blocks[i], s->dest[dst_idx] + off, stride_y); } @@ -2338,7 +2304,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) if (!skipped) { // inter MB mb_has_coeffs = ff_vc1_mbmode_intfrp[0][idx_mbmode][3]; if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); if (!direct) { if (bmvtype == BMV_TYPE_INTERPOLATED && twomv) { v->fourmvbp = get_vlc2(gb, v->fourmvbp_vlc, VC1_4MV_BLOCK_PATTERN_VLC_BITS, 1); @@ -2348,7 +2314,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) } for (i = 0; i < 6; i++) - v->mb_type[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; fieldtx = v->fieldtx_plane[mb_pos] = ff_vc1_mbmode_intfrp[0][idx_mbmode][1]; /* for all motion vector read MVDATA and motion compensate each block */ dst_idx = 0; @@ -2455,7 +2421,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) if (!v->ttmbf && cbp) ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index], VC1_TTMB_VLC_BITS, 2); for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (!fieldtx) @@ -2463,7 +2429,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) else off = (i & 4) ? 0 : ((i & 1) * 8 + ((i > 1) * s->linesize)); if (val) { - pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, + pat = vc1_decode_p_block(v, v->blocks[i], i, mquant, ttmb, first_block, s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : (s->linesize << fieldtx), CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt); @@ -2479,8 +2445,8 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) } else { // skipped dir = 0; for (i = 0; i < 6; i++) { - v->mb_type[0][s->block_index[i]] = 0; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; } s->cur_pic.mb_type[mb_pos] = MB_TYPE_SKIP; s->cur_pic.qscale_table[mb_pos] = 0; @@ -2540,7 +2506,6 @@ static void vc1_decode_i_blocks(VC1Context *v) int k, j; MpegEncContext *s = &v->s; int cbp, val; - uint8_t *coded_val; int mb_pos; /* select coding mode used for VLC tables selection */ @@ -2568,9 +2533,8 @@ static void vc1_decode_i_blocks(VC1Context *v) break; } - /* Set DC scale - y and c use the same */ - s->y_dc_scale = s->y_dc_scale_table[v->pq]; - s->c_dc_scale = s->c_dc_scale_table[v->pq]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[v->pq]; //do frame decode s->mb_x = s->mb_y = 0; @@ -2591,20 +2555,17 @@ static void vc1_decode_i_blocks(VC1Context *v) } // do actual MB decoding and displaying - cbp = get_vlc2(&v->s.gb, ff_msmp4_mb_i_vlc, + cbp = get_vlc2(&v->gb, ff_msmp4_mb_i_vlc, MSMP4_MB_INTRA_VLC_BITS, 2); - v->s.ac_pred = get_bits1(&v->s.gb); + v->s.ac_pred = get_bits1(&v->gb); for (k = 0; k < 6; k++) { - v->mb_type[0][s->block_index[k]] = 1; + v->mb_type[s->block_index[k]] = 1; val = ((cbp >> (5 - k)) & 1); - if (k < 4) { - int pred = vc1_coded_block_pred(&v->s, k, &coded_val); - val = val ^ pred; - *coded_val = val; - } + if (k < 4) + val = vc1_coded_block_pred(&v->s, k, val); cbp |= val << (5 - k); vc1_decode_i_block(v, v->block[v->cur_blk_idx][block_map[k]], k, val, (k < 4) ? v->codingset : v->codingset2); @@ -2629,13 +2590,13 @@ static void vc1_decode_i_blocks(VC1Context *v) vc1_put_blocks_clamped(v, 0); } - if (v->s.loop_filter) + if (v->loop_filter) ff_vc1_i_loop_filter(v); - if (get_bits_left(&s->gb) < 0) { + if (get_bits_left(&v->gb) < 0) { ff_er_add_slice(&s->er, 0, 0, s->mb_x, s->mb_y, ER_MB_ERROR); av_log(s->avctx, AV_LOG_ERROR, "Bits overconsumption: %i > %i\n", - get_bits_count(&s->gb), s->gb.size_in_bits); + get_bits_count(&v->gb), v->gb.size_in_bits); return; } @@ -2659,12 +2620,11 @@ static int vc1_decode_i_blocks_adv(VC1Context *v) { int k; MpegEncContext *s = &v->s; + GetBitContext *const gb = &v->gb; int cbp, val; - uint8_t *coded_val; int mb_pos; int mquant; int mqdiff; - GetBitContext *gb = &s->gb; if (get_bits_left(gb) <= 1) return AVERROR_INVALIDDATA; @@ -2719,39 +2679,35 @@ static int vc1_decode_i_blocks_adv(VC1Context *v) // do actual MB decoding and displaying if (v->fieldtx_is_raw) - v->fieldtx_plane[mb_pos] = get_bits1(&v->s.gb); - if (get_bits_left(&v->s.gb) <= 1) { + v->fieldtx_plane[mb_pos] = get_bits1(gb); + if (get_bits_left(gb) <= 1) { ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); return 0; } - cbp = get_vlc2(&v->s.gb, ff_msmp4_mb_i_vlc, + cbp = get_vlc2(gb, ff_msmp4_mb_i_vlc, MSMP4_MB_INTRA_VLC_BITS, 2); if (v->acpred_is_raw) - v->s.ac_pred = get_bits1(&v->s.gb); + v->s.ac_pred = get_bits1(gb); else v->s.ac_pred = v->acpred_plane[mb_pos]; if (v->condover == CONDOVER_SELECT && v->overflg_is_raw) - v->over_flags_plane[mb_pos] = get_bits1(&v->s.gb); + v->over_flags_plane[mb_pos] = get_bits1(gb); GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; - /* Set DC scale - y and c use the same */ - s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; - s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[FFABS(mquant)]; for (k = 0; k < 6; k++) { - v->mb_type[0][s->block_index[k]] = 1; + v->mb_type[s->block_index[k]] = 1; val = ((cbp >> (5 - k)) & 1); - if (k < 4) { - int pred = vc1_coded_block_pred(&v->s, k, &coded_val); - val = val ^ pred; - *coded_val = val; - } + if (k < 4) + val = vc1_coded_block_pred(&v->s, k, val); cbp |= val << (5 - k); v->a_avail = !s->first_slice_line || (k == 2 || k == 3); @@ -2768,14 +2724,14 @@ static int vc1_decode_i_blocks_adv(VC1Context *v) if (v->overlap && (v->pq >= 9 || v->condover != CONDOVER_NONE)) ff_vc1_i_overlap_filter(v); vc1_put_blocks_clamped(v, 1); - if (v->s.loop_filter) + if (v->loop_filter) ff_vc1_i_loop_filter(v); - if (get_bits_left(&s->gb) < 0) { + if (get_bits_left(gb) < 0) { // TODO: may need modification to handle slice coding ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); av_log(s->avctx, AV_LOG_ERROR, "Bits overconsumption: %i > %i\n", - get_bits_count(&s->gb), s->gb.size_in_bits); + get_bits_count(gb), gb->size_in_bits); return 0; } inc_blk_idx(v->topleft_blk_idx); @@ -2822,7 +2778,7 @@ static void vc1_decode_p_blocks(VC1Context *v) break; } - apply_loop_filter = s->loop_filter && !(s->avctx->skip_loop_filter >= AVDISCARD_NONKEY); + apply_loop_filter = v->loop_filter && !(s->avctx->skip_loop_filter >= AVDISCARD_NONKEY); s->first_slice_line = 1; memset(v->cbp_base, 0, sizeof(v->cbp_base[0]) * 3 * s->mb_stride); for (s->mb_y = s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) { @@ -2832,7 +2788,7 @@ static void vc1_decode_p_blocks(VC1Context *v) update_block_index(s); if (v->fcm == ILACE_FIELD || (v->fcm == PROGRESSIVE && v->mv_type_is_raw) || v->skip_is_raw) - if (get_bits_left(&v->s.gb) <= 1) { + if (get_bits_left(&v->gb) <= 1) { ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); return; } @@ -2850,11 +2806,11 @@ static void vc1_decode_p_blocks(VC1Context *v) if (apply_loop_filter) ff_vc1_p_loop_filter(v); } - if (ret < 0 || get_bits_left(&s->gb) < 0 || get_bits_count(&s->gb) < 0) { + if (ret < 0 || get_bits_left(&v->gb) < 0 || get_bits_count(&v->gb) < 0) { // TODO: may need modification to handle slice coding ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); av_log(s->avctx, AV_LOG_ERROR, "Error or Bits overconsumption: %i > %i at %ix%i\n", - get_bits_count(&s->gb), s->gb.size_in_bits, s->mb_x, s->mb_y); + get_bits_count(&v->gb), v->gb.size_in_bits, s->mb_x, s->mb_y); return; } inc_blk_idx(v->topleft_blk_idx); @@ -2917,29 +2873,29 @@ static void vc1_decode_b_blocks(VC1Context *v) update_block_index(s); if (v->fcm == ILACE_FIELD || v->skip_is_raw || v->dmb_is_raw) - if (get_bits_left(&v->s.gb) <= 1) { + if (get_bits_left(&v->gb) <= 1) { ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); return; } if (v->fcm == ILACE_FIELD) { vc1_decode_b_mb_intfi(v); - if (v->s.loop_filter) + if (v->loop_filter) ff_vc1_b_intfi_loop_filter(v); } else if (v->fcm == ILACE_FRAME) { vc1_decode_b_mb_intfr(v); - if (v->s.loop_filter) + if (v->loop_filter) ff_vc1_p_intfr_loop_filter(v); } else { vc1_decode_b_mb(v); - if (v->s.loop_filter) + if (v->loop_filter) ff_vc1_i_loop_filter(v); } - if (get_bits_left(&s->gb) < 0 || get_bits_count(&s->gb) < 0) { + if (get_bits_left(&v->gb) < 0 || get_bits_count(&v->gb) < 0) { // TODO: may need modification to handle slice coding ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); av_log(s->avctx, AV_LOG_ERROR, "Bits overconsumption: %i > %i at %ix%i\n", - get_bits_count(&s->gb), s->gb.size_in_bits, s->mb_x, s->mb_y); + get_bits_count(&v->gb), v->gb.size_in_bits, s->mb_x, s->mb_y); return; } } @@ -2981,12 +2937,12 @@ static void vc1_decode_skip_blocks(VC1Context *v) void ff_vc1_decode_blocks(VC1Context *v) { - v->s.esc3_level_length = 0; + v->esc3_level_length = 0; if (v->x8_type) { ff_intrax8_decode_picture(&v->x8, v->s.cur_pic.ptr, - &v->s.gb, &v->s.mb_x, &v->s.mb_y, + &v->gb, &v->s.mb_x, &v->s.mb_y, 2 * v->pq + v->halfpq, v->pq * !v->pquantizer, - v->s.loop_filter, v->s.low_delay); + v->loop_filter, v->s.low_delay); ff_er_add_slice(&v->s.er, 0, 0, (v->s.mb_x >> 1) - 1, (v->s.mb_y >> 1) - 1, diff --git a/libavcodec/vc1_loopfilter.c b/libavcodec/vc1_loopfilter.c index e788d1890..1d71d9d5c 100644 --- a/libavcodec/vc1_loopfilter.c +++ b/libavcodec/vc1_loopfilter.c @@ -175,7 +175,7 @@ void ff_vc1_p_overlap_filter(VC1Context *v) if (s->mb_x == 0 && (i & 5) != 1) continue; - if (v->mb_type[0][s->block_index[i]] && v->mb_type[0][s->block_index[i] - 1]) + if (v->mb_type[s->block_index[i]] && v->mb_type[s->block_index[i] - 1]) vc1_h_overlap_filter(v, s->mb_x ? left_blk : cur_blk, cur_blk, v->fcm == ILACE_FRAME && s->mb_x && v->fieldtx_plane[mb_pos - 1], @@ -188,12 +188,12 @@ void ff_vc1_p_overlap_filter(VC1Context *v) if (s->first_slice_line && !(i & 2)) continue; - if (s->mb_x && v->mb_type[0][s->block_index[i] - 2 + (i > 3)] && - v->mb_type[0][s->block_index[i] - s->block_wrap[i] - 2 + (i > 3)]) + if (s->mb_x && v->mb_type[s->block_index[i] - 2 + (i > 3)] && + v->mb_type[s->block_index[i] - s->block_wrap[i] - 2 + (i > 3)]) vc1_v_overlap_filter(v, s->first_slice_line ? left_blk : topleft_blk, left_blk, i); if (s->mb_x == s->mb_width - 1) - if (v->mb_type[0][s->block_index[i]] && - v->mb_type[0][s->block_index[i] - s->block_wrap[i]]) + if (v->mb_type[s->block_index[i]] && + v->mb_type[s->block_index[i] - s->block_wrap[i]]) vc1_v_overlap_filter(v, s->first_slice_line ? cur_blk : top_blk, cur_blk, i); } } diff --git a/libavcodec/vc1_mc.c b/libavcodec/vc1_mc.c index 9adb71c7a..db19d95ef 100644 --- a/libavcodec/vc1_mc.c +++ b/libavcodec/vc1_mc.c @@ -140,10 +140,10 @@ static av_always_inline int get_luma_mv(VC1Context *v, int dir, int16_t *tx, int static av_always_inline int get_chroma_mv(VC1Context *v, int dir, int16_t *tx, int16_t *ty) { MpegEncContext *s = &v->s; - int idx = !v->mb_type[0][s->block_index[0]] | - (!v->mb_type[0][s->block_index[1]] << 1) | - (!v->mb_type[0][s->block_index[2]] << 2) | - (!v->mb_type[0][s->block_index[3]] << 3); + int idx = !v->mb_type[s->block_index[0]] | + (!v->mb_type[s->block_index[1]] << 1) | + (!v->mb_type[s->block_index[2]] << 2) | + (!v->mb_type[s->block_index[3]] << 3); static const uint8_t index2[16] = { 0, 0, 0, 0x01, 0, 0x02, 0x12, 0, 0, 0x03, 0x13, 0, 0x23, 0, 0, 0 }; int valid_count = popcount4[idx]; diff --git a/libavcodec/vc1_parser.c b/libavcodec/vc1_parser.c index a536a7bcf..595d066de 100644 --- a/libavcodec/vc1_parser.c +++ b/libavcodec/vc1_parser.c @@ -28,6 +28,7 @@ #include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "parser.h" +#include "parser_internal.h" #include "vc1.h" #include "get_bits.h" #include "vc1dsp.h" @@ -179,6 +180,7 @@ static int vc1_parse(AVCodecParserContext *s, // start codes if we know it contains a complete frame and // we've already unescaped all we need of the frame header vc1_extract_header(s, avctx, unesc_buffer, unesc_index); + unesc_index = 0; break; } if (unesc_index >= UNESCAPED_THRESHOLD && !start_code_found) { @@ -215,7 +217,8 @@ static int vc1_parse(AVCodecParserContext *s, if (!pic_found && (b == (VC1_CODE_FRAME & 0xFF) || b == (VC1_CODE_FIELD & 0xFF))) { pic_found = 1; } - else if (pic_found && b != (VC1_CODE_FIELD & 0xFF) && b != (VC1_CODE_SLICE & 0xFF)) { + else if (pic_found && b != (VC1_CODE_FIELD & 0xFF) && b != (VC1_CODE_SLICE & 0xFF) + && b != (VC1_CODE_ENDOFSEQ & 0xFF)) { next = i - 4; pic_found = b == (VC1_CODE_FRAME & 0xFF); break; @@ -269,10 +272,10 @@ static av_cold int vc1_parse_init(AVCodecParserContext *s) return 0; } -const AVCodecParser ff_vc1_parser = { - .codec_ids = { AV_CODEC_ID_VC1 }, +const FFCodecParser ff_vc1_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_VC1), .priv_data_size = sizeof(VC1ParseContext), - .parser_init = vc1_parse_init, - .parser_parse = vc1_parse, - .parser_close = ff_parse_close, + .init = vc1_parse_init, + .parse = vc1_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/vc1_pred.c b/libavcodec/vc1_pred.c index 87d9b6d6d..1ac8f6156 100644 --- a/libavcodec/vc1_pred.c +++ b/libavcodec/vc1_pred.c @@ -420,7 +420,7 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, else sum = FFABS(px - field_predA[0]) + FFABS(py - field_predA[1]); if (sum > hybridmv_thresh) { - if (get_bits1(&s->gb)) { // read HYBRIDPRED bit + if (get_bits1(&v->gb)) { // read HYBRIDPRED bit px = field_predA[0]; py = field_predA[1]; } else { @@ -433,7 +433,7 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, else sum = FFABS(px - field_predC[0]) + FFABS(py - field_predC[1]); if (sum > hybridmv_thresh) { - if (get_bits1(&s->gb)) { + if (get_bits1(&v->gb)) { px = field_predA[0]; py = field_predA[1]; } else { @@ -695,7 +695,7 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], int px, py; int sum; int r_x, r_y; - const uint8_t *is_intra = v->mb_type[0]; + const uint8_t *is_intra = v->mb_type; av_assert0(!v->field_mode); @@ -782,7 +782,7 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], else sum = FFABS(px - A[0]) + FFABS(py - A[1]); if (sum > 32) { - if (get_bits1(&s->gb)) { + if (get_bits1(&v->gb)) { px = A[0]; py = A[1]; } else { @@ -795,7 +795,7 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], else sum = FFABS(px - C[0]) + FFABS(py - C[1]); if (sum > 32) { - if (get_bits1(&s->gb)) { + if (get_bits1(&v->gb)) { px = A[0]; py = A[1]; } else { @@ -852,7 +852,7 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], else sum = FFABS(px - A[0]) + FFABS(py - A[1]); if (sum > 32) { - if (get_bits1(&s->gb)) { + if (get_bits1(&v->gb)) { px = A[0]; py = A[1]; } else { @@ -865,7 +865,7 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], else sum = FFABS(px - C[0]) + FFABS(py - C[1]); if (sum > 32) { - if (get_bits1(&s->gb)) { + if (get_bits1(&v->gb)) { px = A[0]; py = A[1]; } else { @@ -927,19 +927,19 @@ void ff_vc1_pred_b_mv_intfi(VC1Context *v, int n, int *dmv_x, int *dmv_y, return; } if (v->bmvtype == BMV_TYPE_INTERPOLATED) { - ff_vc1_pred_mv(v, 0, dmv_x[0], dmv_y[0], 1, v->range_x, v->range_y, v->mb_type[0], pred_flag[0], 0); - ff_vc1_pred_mv(v, 0, dmv_x[1], dmv_y[1], 1, v->range_x, v->range_y, v->mb_type[0], pred_flag[1], 1); + ff_vc1_pred_mv(v, 0, dmv_x[0], dmv_y[0], 1, v->range_x, v->range_y, v->mb_type, pred_flag[0], 0); + ff_vc1_pred_mv(v, 0, dmv_x[1], dmv_y[1], 1, v->range_x, v->range_y, v->mb_type, pred_flag[1], 1); return; } if (dir) { // backward - ff_vc1_pred_mv(v, n, dmv_x[1], dmv_y[1], mv1, v->range_x, v->range_y, v->mb_type[0], pred_flag[1], 1); + ff_vc1_pred_mv(v, n, dmv_x[1], dmv_y[1], mv1, v->range_x, v->range_y, v->mb_type, pred_flag[1], 1); if (n == 3 || mv1) { - ff_vc1_pred_mv(v, 0, dmv_x[0], dmv_y[0], 1, v->range_x, v->range_y, v->mb_type[0], 0, 0); + ff_vc1_pred_mv(v, 0, dmv_x[0], dmv_y[0], 1, v->range_x, v->range_y, v->mb_type, 0, 0); } } else { // forward - ff_vc1_pred_mv(v, n, dmv_x[0], dmv_y[0], mv1, v->range_x, v->range_y, v->mb_type[0], pred_flag[0], 0); + ff_vc1_pred_mv(v, n, dmv_x[0], dmv_y[0], mv1, v->range_x, v->range_y, v->mb_type, pred_flag[0], 0); if (n == 3 || mv1) { - ff_vc1_pred_mv(v, 0, dmv_x[1], dmv_y[1], 1, v->range_x, v->range_y, v->mb_type[0], 0, 1); + ff_vc1_pred_mv(v, 0, dmv_x[1], dmv_y[1], 1, v->range_x, v->range_y, v->mb_type, 0, 1); } } } diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c index 2c314e7b5..12b1e0941 100644 --- a/libavcodec/vc1dec.c +++ b/libavcodec/vc1dec.c @@ -336,7 +336,7 @@ static int vc1_decode_sprites(VC1Context *v, GetBitContext* gb) return 0; } -static void vc1_sprite_flush(AVCodecContext *avctx) +static av_cold void vc1_sprite_flush(AVCodecContext *avctx) { VC1Context *v = avctx->priv_data; MpegEncContext *s = &v->s; @@ -396,12 +396,10 @@ static av_cold int vc1_decode_init_alloc_tables(VC1Context *v) v->mb_type_base = av_mallocz(s->b8_stride * (mb_height * 2 + 1) + s->mb_stride * (mb_height + 1) * 2); if (!v->mb_type_base) return AVERROR(ENOMEM); - v->mb_type[0] = v->mb_type_base + s->b8_stride + 1; - v->mb_type[1] = v->mb_type_base + s->b8_stride * (mb_height * 2 + 1) + s->mb_stride + 1; - v->mb_type[2] = v->mb_type[1] + s->mb_stride * (mb_height + 1); + v->mb_type = v->mb_type_base + s->b8_stride + 1; /* allocate memory to store block level MV info */ - v->blk_mv_type_base = av_mallocz( s->b8_stride * (mb_height * 2 + 1) + s->mb_stride * (mb_height + 1) * 2); + v->blk_mv_type_base = av_mallocz( s->b8_stride * (mb_height * 2 + 1)); if (!v->blk_mv_type_base) return AVERROR(ENOMEM); v->blk_mv_type = v->blk_mv_type_base + s->b8_stride + 1; @@ -422,8 +420,7 @@ static av_cold int vc1_decode_init_alloc_tables(VC1Context *v) return AVERROR(ENOMEM); } - ret = ff_intrax8_common_init(s->avctx, &v->x8, - s->block, s->block_last_index, + ret = ff_intrax8_common_init(s->avctx, &v->x8, v->blocks[0], s->mb_width, s->mb_height); if (ret < 0) return ret; @@ -471,14 +468,6 @@ av_cold int ff_vc1_decode_init(AVCodecContext *avctx) if (ret < 0) return ret; - s->y_dc_scale_table = ff_wmv3_dc_scale_table; - s->c_dc_scale_table = ff_wmv3_dc_scale_table; - - ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, - ff_wmv1_scantable[0]); - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, - ff_wmv1_scantable[1]); - ret = vc1_decode_init_alloc_tables(v); if (ret < 0) { vc1_decode_reset(avctx); @@ -694,7 +683,11 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx) if (size <= 0) continue; buf2_size = v->vc1dsp.vc1_unescape_buffer(start + 4, size, buf2); - init_get_bits(&gb, buf2, buf2_size * 8); + ret = init_get_bits8(&gb, buf2, buf2_size); + if (ret < 0) { + av_free(buf2); + return ret; + } switch (AV_RB32(start)) { case VC1_CODE_SEQHDR: if ((ret = ff_vc1_decode_sequence_header(avctx, v, &gb)) < 0) { @@ -843,8 +836,11 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, if(s->avctx->flags & AV_CODEC_FLAG_LOW_DELAY) s->low_delay = 1; + if (buf_size >= 4 && AV_RB32(&buf[buf_size-4]) == VC1_CODE_ENDOFSEQ) + buf_size -= 4; + /* no supplementary picture */ - if (buf_size == 0 || (buf_size == 4 && AV_RB32(buf) == VC1_CODE_ENDOFSEQ)) { + if (buf_size == 0) { /* special case for last picture */ if (s->low_delay == 0 && s->next_pic.ptr) { if ((ret = av_frame_ref(pict, s->next_pic.ptr->f)) < 0) @@ -896,8 +892,9 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } buf_size3 = v->vc1dsp.vc1_unescape_buffer(start + 4, size, slices[n_slices].buf); - init_get_bits(&slices[n_slices].gb, slices[n_slices].buf, - buf_size3 << 3); + ret = init_get_bits8(&slices[n_slices].gb, slices[n_slices].buf, buf_size3); + if (ret < 0) + goto err; slices[n_slices].mby_start = avctx->coded_height + 31 >> 5; slices[n_slices].rawbuf = start; slices[n_slices].raw_size = size + 4; @@ -907,8 +904,10 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } case VC1_CODE_ENTRYPOINT: /* it should be before frame data */ buf_size2 = v->vc1dsp.vc1_unescape_buffer(start + 4, size, buf2); - init_get_bits(&s->gb, buf2, buf_size2 * 8); - ff_vc1_decode_entry_point(avctx, v, &s->gb); + ret = init_get_bits8(&v->gb, buf2, buf_size2); + if (ret < 0) + goto err; + ff_vc1_decode_entry_point(avctx, v, &v->gb); break; case VC1_CODE_SLICE: { int buf_size3; @@ -926,8 +925,9 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } buf_size3 = v->vc1dsp.vc1_unescape_buffer(start + 4, size, slices[n_slices].buf); - init_get_bits(&slices[n_slices].gb, slices[n_slices].buf, - buf_size3 << 3); + ret = init_get_bits8(&slices[n_slices].gb, slices[n_slices].buf, buf_size3); + if (ret < 0) + goto err; slices[n_slices].mby_start = get_bits(&slices[n_slices].gb, 9); slices[n_slices].rawbuf = start; slices[n_slices].raw_size = size + 4; @@ -960,8 +960,9 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, goto err; } buf_size3 = v->vc1dsp.vc1_unescape_buffer(divider + 4, buf + buf_size - divider - 4, slices[n_slices].buf); - init_get_bits(&slices[n_slices].gb, slices[n_slices].buf, - buf_size3 << 3); + ret = init_get_bits8(&slices[n_slices].gb, slices[n_slices].buf, buf_size3); + if (ret < 0) + goto err; slices[n_slices].mby_start = s->mb_height + 1 >> 1; slices[n_slices].rawbuf = divider; slices[n_slices].raw_size = buf + buf_size - divider; @@ -972,16 +973,18 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } else { buf_size2 = v->vc1dsp.vc1_unescape_buffer(buf, buf_size, buf2); } - init_get_bits(&s->gb, buf2, buf_size2*8); - } else{ - ret = init_get_bits8(&s->gb, buf, buf_size); + ret = init_get_bits8(&v->gb, buf2, buf_size2); if (ret < 0) - return ret; + goto err; + } else{ + ret = init_get_bits8(&v->gb, buf, buf_size); + if (ret < 0) + goto err; } if (v->res_sprite) { - v->new_sprite = !get_bits1(&s->gb); - v->two_sprites = get_bits1(&s->gb); + v->new_sprite = !get_bits1(&v->gb); + v->two_sprites = get_bits1(&v->gb); /* res_sprite means a Windows Media Image stream, AV_CODEC_ID_*IMAGE means we're using the sprite compositor. These are intentionally kept separate so you can get the raw sprites by using the wmv3 decoder for WMVP or @@ -1024,11 +1027,11 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, v->pic_header_flag = 0; v->first_pic_header_flag = 1; if (v->profile < PROFILE_ADVANCED) { - if ((ret = ff_vc1_parse_frame_header(v, &s->gb)) < 0) { + if ((ret = ff_vc1_parse_frame_header(v, &v->gb)) < 0) { goto err; } } else { - if ((ret = ff_vc1_parse_frame_header_adv(v, &s->gb)) < 0) { + if ((ret = ff_vc1_parse_frame_header_adv(v, &v->gb)) < 0) { goto err; } } @@ -1093,7 +1096,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, if (v->field_mode && buf_start_second_field) { // decode first field s->picture_structure = PICT_BOTTOM_FIELD - v->tff; - ret = hwaccel->start_frame(avctx, buf_start, + ret = hwaccel->start_frame(avctx, avpkt->buf, buf_start, buf_start_second_field - buf_start); if (ret < 0) goto err; @@ -1111,12 +1114,12 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, goto err; for (i = 0 ; i < n_slices1 + 1; i++) { - s->gb = slices[i].gb; + v->gb = slices[i].gb; s->mb_y = slices[i].mby_start; - v->pic_header_flag = get_bits1(&s->gb); + v->pic_header_flag = get_bits1(&v->gb); if (v->pic_header_flag) { - if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) { + if (ff_vc1_parse_frame_header_adv(v, &v->gb) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n"); ret = AVERROR_INVALIDDATA; if (avctx->err_recognition & AV_EF_EXPLODE) @@ -1136,19 +1139,19 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, goto err; // decode second field - s->gb = slices[n_slices1 + 1].gb; + v->gb = slices[n_slices1 + 1].gb; s->mb_y = slices[n_slices1 + 1].mby_start; s->picture_structure = PICT_TOP_FIELD + v->tff; v->second_field = 1; v->pic_header_flag = 0; - if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) { + if (ff_vc1_parse_frame_header_adv(v, &v->gb) < 0) { av_log(avctx, AV_LOG_ERROR, "parsing header for second field failed"); ret = AVERROR_INVALIDDATA; goto err; } v->s.cur_pic.ptr->f->pict_type = v->s.pict_type; - ret = hwaccel->start_frame(avctx, buf_start_second_field, + ret = hwaccel->start_frame(avctx, avpkt->buf, buf_start_second_field, (buf + buf_size) - buf_start_second_field); if (ret < 0) goto err; @@ -1166,12 +1169,12 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, goto err; for (i = n_slices1 + 2; i < n_slices; i++) { - s->gb = slices[i].gb; + v->gb = slices[i].gb; s->mb_y = slices[i].mby_start; - v->pic_header_flag = get_bits1(&s->gb); + v->pic_header_flag = get_bits1(&v->gb); if (v->pic_header_flag) { - if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) { + if (ff_vc1_parse_frame_header_adv(v, &v->gb) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n"); ret = AVERROR_INVALIDDATA; if (avctx->err_recognition & AV_EF_EXPLODE) @@ -1191,7 +1194,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, goto err; } else { s->picture_structure = PICT_FRAME; - ret = hwaccel->start_frame(avctx, buf_start, + ret = hwaccel->start_frame(avctx, avpkt->buf, buf_start, (buf + buf_size) - buf_start); if (ret < 0) goto err; @@ -1211,12 +1214,12 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, // and process the slices as additional slices afterwards for (i = 0 ; i < n_slices; i++) { - s->gb = slices[i].gb; + v->gb = slices[i].gb; s->mb_y = slices[i].mby_start; - v->pic_header_flag = get_bits1(&s->gb); + v->pic_header_flag = get_bits1(&v->gb); if (v->pic_header_flag) { - if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) { + if (ff_vc1_parse_frame_header_adv(v, &v->gb) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n"); ret = AVERROR_INVALIDDATA; if (avctx->err_recognition & AV_EF_EXPLODE) @@ -1271,16 +1274,16 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, if (i) { v->pic_header_flag = 0; if (v->field_mode && i == n_slices1 + 2) { - if ((header_ret = ff_vc1_parse_frame_header_adv(v, &s->gb)) < 0) { + if ((header_ret = ff_vc1_parse_frame_header_adv(v, &v->gb)) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "Field header damaged\n"); ret = AVERROR_INVALIDDATA; if (avctx->err_recognition & AV_EF_EXPLODE) goto err; continue; } - } else if (get_bits1(&s->gb)) { + } else if (get_bits1(&v->gb)) { v->pic_header_flag = 1; - if ((header_ret = ff_vc1_parse_frame_header_adv(v, &s->gb)) < 0) { + if ((header_ret = ff_vc1_parse_frame_header_adv(v, &v->gb)) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n"); ret = AVERROR_INVALIDDATA; if (avctx->err_recognition & AV_EF_EXPLODE) @@ -1313,7 +1316,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } ff_vc1_decode_blocks(v); if (i != n_slices) { - s->gb = slices[i].gb; + v->gb = slices[i].gb; } } if (v->field_mode) { @@ -1329,8 +1332,8 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } } ff_dlog(s->avctx, "Consumed %i/%i bits\n", - get_bits_count(&s->gb), s->gb.size_in_bits); -// if (get_bits_count(&s->gb) > buf_size * 8) + get_bits_count(&v->gb), v->gb.size_in_bits); +// if (get_bits_count(&v->gb) > buf_size * 8) // return -1; if(s->er.error_occurred && s->pict_type == AV_PICTURE_TYPE_B) { ret = AVERROR_INVALIDDATA; @@ -1356,7 +1359,7 @@ image: goto err; } #if CONFIG_WMV3IMAGE_DECODER || CONFIG_VC1IMAGE_DECODER - if ((ret = vc1_decode_sprites(v, &s->gb)) < 0) + if ((ret = vc1_decode_sprites(v, &v->gb)) < 0) goto err; #endif if ((ret = av_frame_ref(pict, v->sprite_output_frame)) < 0) @@ -1366,25 +1369,18 @@ image: if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) { if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) goto err; - if (!v->field_mode) - ff_print_debug_info(s, s->cur_pic.ptr, pict); + ff_print_debug_info(s, s->cur_pic.ptr, pict); *got_frame = 1; } else if (s->last_pic.ptr) { if ((ret = av_frame_ref(pict, s->last_pic.ptr->f)) < 0) goto err; - if (!v->field_mode) - ff_print_debug_info(s, s->last_pic.ptr, pict); + ff_print_debug_info(s, s->last_pic.ptr, pict); *got_frame = 1; } } end: - av_free(buf2); - for (i = 0; i < n_slices; i++) - av_free(slices[i].buf); - av_free(slices); - return buf_size; - + ret = buf_size; err: av_free(buf2); for (i = 0; i < n_slices; i++) diff --git a/libavcodec/vc1dsp.c b/libavcodec/vc1dsp.c index 2caa3c686..864a6e5e7 100644 --- a/libavcodec/vc1dsp.c +++ b/libavcodec/vc1dsp.c @@ -1041,7 +1041,7 @@ av_cold void ff_vc1dsp_init(VC1DSPContext *dsp) ff_vc1dsp_init_ppc(dsp); #elif ARCH_RISCV ff_vc1dsp_init_riscv(dsp); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_vc1dsp_init_x86(dsp); #elif ARCH_MIPS ff_vc1dsp_init_mips(dsp); diff --git a/libavcodec/vc1dsp.h b/libavcodec/vc1dsp.h index e3b90d2b6..b018537af 100644 --- a/libavcodec/vc1dsp.h +++ b/libavcodec/vc1dsp.h @@ -30,7 +30,9 @@ #include "hpeldsp.h" #include "h264chroma.h" -typedef void (*vc1op_pixels_func)(uint8_t *block/*align width (8 or 16)*/, const uint8_t *pixels/*align 1*/, ptrdiff_t line_size, int h); +typedef void (*vc1op_pixels_func)(uint8_t *block/*align width (8 or 16)*/, + const uint8_t *pixels/*align 1*/, + ptrdiff_t line_size, int round); typedef struct VC1DSPContext { /* vc1 functions */ diff --git a/libavcodec/vc2enc.c b/libavcodec/vc2enc.c index b82370a75..2c155c01a 100644 --- a/libavcodec/vc2enc.c +++ b/libavcodec/vc2enc.c @@ -22,6 +22,7 @@ #include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" +#include "libavutil/thread.h" #include "libavutil/version.h" #include "codec_internal.h" #include "dirac.h" @@ -186,51 +187,53 @@ typedef struct VC2EncContext { enum DiracParseCodes last_parse_code; } VC2EncContext; -static av_always_inline void put_vc2_ue_uint(PutBitContext *pb, uint32_t val) +/// x_k x_{k-1} ... x_0 -> 0 x_k 0 x_{k - 1} ... 0 x_0 +static uint16_t interleaved_ue_golomb_tab[256]; +/// 1 x_{k-1} ... x_0 -> 0 0 0 x_{k - 1} ... 0 x_0 +static uint16_t top_interleaved_ue_golomb_tab[256]; +/// 1 x_{k-1} ... x_0 -> 2 * k +static uint8_t golomb_len_tab[256]; +/// quant -> av_log2(ff_dirac_qscale_tab[quant]) + 32 +static uint8_t qscale_len_tab[FF_ARRAY_ELEMS(ff_dirac_qscale_tab)]; + +static av_cold void vc2_init_static_data(void) { - int i; - int bits = 0; - unsigned topbit = 1, maxval = 1; - uint64_t pbits = 0; - - if (!val++) { - put_bits(pb, 1, 1); - return; + interleaved_ue_golomb_tab[1] = 1; + for (unsigned i = 2; i < 256; ++i) { + golomb_len_tab[i] = golomb_len_tab[i >> 1] + 2; + interleaved_ue_golomb_tab[i] = (interleaved_ue_golomb_tab[i >> 1] << 2) | (i & 1); + top_interleaved_ue_golomb_tab[i] = interleaved_ue_golomb_tab[i] ^ (1 << golomb_len_tab[i]); } + for (size_t i = 0; i < FF_ARRAY_ELEMS(qscale_len_tab); ++i) + qscale_len_tab[i] = av_log2(ff_dirac_qscale_tab[i]) + 32; +} - while (val > maxval) { - topbit <<= 1; - maxval <<= 1; - maxval |= 1; +static av_always_inline void put_vc2_ue_uint_inline(PutBitContext *pb, uint32_t val) +{ + uint64_t pbits = 1; + int bits = 1; + + ++val; + + while (val >> 8) { + pbits |= (uint64_t)interleaved_ue_golomb_tab[val & 0xff] << bits; + val >>= 8; + bits += 16; } + pbits |= (uint64_t)top_interleaved_ue_golomb_tab[val] << bits; + bits += golomb_len_tab[val]; - bits = ff_log2(topbit); + put_bits63(pb, bits, pbits); +} - for (i = 0; i < bits; i++) { - topbit >>= 1; - av_assert2(pbits <= UINT64_MAX>>3); - pbits <<= 2; - if (val & topbit) - pbits |= 0x1; - } - - put_bits64(pb, bits*2 + 1, (pbits << 1) | 1); +static av_noinline void put_vc2_ue_uint(PutBitContext *pb, uint32_t val) +{ + put_vc2_ue_uint_inline(pb, val); } static av_always_inline int count_vc2_ue_uint(uint32_t val) { - int topbit = 1, maxval = 1; - - if (!val++) - return 1; - - while (val > maxval) { - topbit <<= 1; - maxval <<= 1; - maxval |= 1; - } - - return ff_log2(topbit)*2 + 1; + return 2 * av_log2(val + 1) + 1; } /* VC-2 10.4 - parse_info() */ @@ -546,12 +549,12 @@ static void encode_subband(const VC2EncContext *s, PutBitContext *pb, dwtcoef *coeff = b->buf + top * b->stride; const uint64_t q_m = ((uint64_t)(s->qmagic_lut[quant][0])) << 2; const uint64_t q_a = s->qmagic_lut[quant][1]; - const int q_s = av_log2(ff_dirac_qscale_tab[quant]) + 32; + const int q_s = qscale_len_tab[quant]; for (y = top; y < bottom; y++) { for (x = left; x < right; x++) { uint32_t c_abs = QUANT(FFABS(coeff[x]), q_m, q_a, q_s); - put_vc2_ue_uint(pb, c_abs); + put_vc2_ue_uint_inline(pb, c_abs); if (c_abs) put_bits(pb, 1, coeff[x] < 0); } @@ -587,7 +590,7 @@ static int count_hq_slice(SliceArgs *slice, int quant_idx) const int q_idx = quants[level][orientation]; const uint64_t q_m = ((uint64_t)s->qmagic_lut[q_idx][0]) << 2; const uint64_t q_a = s->qmagic_lut[q_idx][1]; - const int q_s = av_log2(ff_dirac_qscale_tab[q_idx]) + 32; + const int q_s = qscale_len_tab[q_idx]; const int left = b->width * slice->x / s->num_x; const int right = b->width *(slice->x+1) / s->num_x; @@ -618,7 +621,7 @@ static int count_hq_slice(SliceArgs *slice, int quant_idx) return bits; } -/* Approaches the best possible quantizer asymptotically, its kinda exaustive +/* Approaches the best possible quantizer asymptotically, its kinda exhaustive * but we have a LUT to get the coefficient size in bits. Guaranteed to never * overshoot, which is apparently very important when streaming */ static int rate_control(AVCodecContext *avctx, void *arg) @@ -1027,6 +1030,7 @@ static av_cold int vc2_encode_end(AVCodecContext *avctx) static av_cold int vc2_encode_init(AVCodecContext *avctx) { + static AVOnce init_static_once = AV_ONCE_INIT; Plane *p; SubBand *b; int i, level, o, shift; @@ -1080,13 +1084,13 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) if ((s->slice_width & (s->slice_width - 1)) || (s->slice_height & (s->slice_height - 1))) { av_log(avctx, AV_LOG_ERROR, "Slice size is not a power of two!\n"); - return AVERROR_UNKNOWN; + return AVERROR(EINVAL); } if ((s->slice_width > avctx->width) || (s->slice_height > avctx->height)) { av_log(avctx, AV_LOG_ERROR, "Slice size is bigger than the image!\n"); - return AVERROR_UNKNOWN; + return AVERROR(EINVAL); } if (s->base_vf <= 0) { @@ -1096,7 +1100,7 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) } else { av_log(avctx, AV_LOG_WARNING, "Given format does not strictly comply with " "the specifications, decrease strictness to use it.\n"); - return AVERROR_UNKNOWN; + return AVERROR(EINVAL); } } else { av_log(avctx, AV_LOG_INFO, "Selected base video format = %i (%s)\n", @@ -1189,6 +1193,8 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) } } + ff_thread_once(&init_static_once, vc2_init_static_data); + return 0; } @@ -1244,6 +1250,6 @@ const FFCodec ff_vc2_encoder = { FF_CODEC_ENCODE_CB(vc2_encode_frame), .p.priv_class = &vc2enc_class, .defaults = vc2enc_defaults, - .p.pix_fmts = allowed_pix_fmts, + CODEC_PIXFMTS_ARRAY(allowed_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, }; diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c index 0dd564160..e99ac5338 100644 --- a/libavcodec/vdpau.c +++ b/libavcodec/vdpau.c @@ -28,7 +28,6 @@ #include "decode.h" #include "hwaccel_internal.h" #include "internal.h" -#include "mpegvideodec.h" #include "vdpau.h" #include "vdpau_internal.h" @@ -62,20 +61,6 @@ static int vdpau_error(VdpStatus status) } } -#if FF_API_VDPAU_ALLOC_GET_SET -AVVDPAUContext *av_alloc_vdpaucontext(void) -{ -FF_DISABLE_DEPRECATION_WARNINGS - return av_vdpau_alloc_context(); -FF_ENABLE_DEPRECATION_WARNINGS -} - -#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; } -MAKE_ACCESSORS(AVVDPAUContext, vdpau_hwaccel, AVVDPAU_Render2, render2) -#endif - int av_vdpau_get_surface_parameters(AVCodecContext *avctx, VdpChromaType *type, uint32_t *width, uint32_t *height) @@ -139,8 +124,8 @@ int ff_vdpau_common_frame_params(AVCodecContext *avctx, return 0; } -int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile, - int level) +av_cold int ff_vdpau_common_init(AVCodecContext *avctx, + VdpDecoderProfile profile, int level) { VDPAUHWContext *hwctx = avctx->hwaccel_context; VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data; @@ -290,7 +275,7 @@ int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile, return vdpau_error(status); } -int ff_vdpau_common_uninit(AVCodecContext *avctx) +av_cold int ff_vdpau_common_uninit(AVCodecContext *avctx) { VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data; VdpDecoderDestroy *destroy; @@ -367,6 +352,8 @@ int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame, #if CONFIG_MPEG1_VDPAU_HWACCEL || \ CONFIG_MPEG2_VDPAU_HWACCEL || CONFIG_MPEG4_VDPAU_HWACCEL || \ CONFIG_VC1_VDPAU_HWACCEL || CONFIG_WMV3_VDPAU_HWACCEL +#include "mpegvideodec.h" + int ff_vdpau_mpeg_end_frame(AVCodecContext *avctx) { MpegEncContext *s = avctx->priv_data; @@ -402,13 +389,6 @@ int ff_vdpau_add_buffer(struct vdpau_picture_context *pic_ctx, return 0; } -#if FF_API_VDPAU_ALLOC_GET_SET -AVVDPAUContext *av_vdpau_alloc_context(void) -{ - return av_mallocz(sizeof(VDPAUHWContext)); -} -#endif - int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device, VdpGetProcAddress *get_proc, unsigned flags) { diff --git a/libavcodec/vdpau.h b/libavcodec/vdpau.h index 8021c2576..da77c5dae 100644 --- a/libavcodec/vdpau.h +++ b/libavcodec/vdpau.h @@ -93,28 +93,6 @@ typedef struct AVVDPAUContext { AVVDPAU_Render2 render2; } AVVDPAUContext; -#if FF_API_VDPAU_ALLOC_GET_SET -/** - * @brief allocation function for AVVDPAUContext - * - * Allows extending the struct without breaking API/ABI - * @deprecated use av_vdpau_bind_context() instead - */ -attribute_deprecated -AVVDPAUContext *av_alloc_vdpaucontext(void); - -/** - * @deprecated render2 is public and can be accessed directly - */ -attribute_deprecated -AVVDPAU_Render2 av_vdpau_hwaccel_get_render2(const AVVDPAUContext *); -/** - * @deprecated render2 is public and can be accessed directly - */ -attribute_deprecated -void av_vdpau_hwaccel_set_render2(AVVDPAUContext *, AVVDPAU_Render2); -#endif - /** * Associate a VDPAU device with a codec context for hardware acceleration. * This function is meant to be called from the get_format() codec callback, @@ -155,17 +133,6 @@ int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device, int av_vdpau_get_surface_parameters(AVCodecContext *avctx, VdpChromaType *type, uint32_t *width, uint32_t *height); -#if FF_API_VDPAU_ALLOC_GET_SET -/** - * Allocate an AVVDPAUContext. - * - * @return Newly-allocated AVVDPAUContext or NULL on failure. - * @deprecated use av_vdpau_bind_context() instead - */ -attribute_deprecated -AVVDPAUContext *av_vdpau_alloc_context(void); -#endif - /** @} */ #endif /* AVCODEC_VDPAU_H */ diff --git a/libavcodec/vdpau_av1.c b/libavcodec/vdpau_av1.c index a1aff79bb..b7e7fa8b0 100644 --- a/libavcodec/vdpau_av1.c +++ b/libavcodec/vdpau_av1.c @@ -41,7 +41,8 @@ static int get_bit_depth_from_seq(const AV1RawSequenceHeader *seq) } static int vdpau_av1_start_frame(AVCodecContext *avctx, - const uint8_t *buffer, uint32_t size) + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { AV1DecContext *s = avctx->priv_data; const AV1RawSequenceHeader *seq = s->raw_seq; @@ -330,7 +331,7 @@ static int vdpau_av1_end_frame(AVCodecContext *avctx) return 0; } -static int vdpau_av1_init(AVCodecContext *avctx) +static av_cold int vdpau_av1_init(AVCodecContext *avctx) { VdpDecoderProfile profile; uint32_t level = avctx->level; diff --git a/libavcodec/vdpau_h264.c b/libavcodec/vdpau_h264.c index 9c08e4048..51c7e9990 100644 --- a/libavcodec/vdpau_h264.c +++ b/libavcodec/vdpau_h264.c @@ -118,6 +118,7 @@ static void vdpau_h264_set_reference_frames(AVCodecContext *avctx) } static int vdpau_h264_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { H264Context * const h = avctx->priv_data; @@ -214,7 +215,7 @@ static int vdpau_h264_end_frame(AVCodecContext *avctx) return 0; } -static int vdpau_h264_init(AVCodecContext *avctx) +static av_cold int vdpau_h264_init(AVCodecContext *avctx) { VdpDecoderProfile profile; uint32_t level = avctx->level; diff --git a/libavcodec/vdpau_hevc.c b/libavcodec/vdpau_hevc.c index 0ddcafd89..1a92c32b2 100644 --- a/libavcodec/vdpau_hevc.c +++ b/libavcodec/vdpau_hevc.c @@ -32,6 +32,7 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { HEVCContext *h = avctx->priv_data; @@ -513,7 +514,7 @@ static int vdpau_hevc_parse_rext_profile(AVCodecContext *avctx, VdpDecoderProfil } -static int vdpau_hevc_init(AVCodecContext *avctx) +static av_cold int vdpau_hevc_init(AVCodecContext *avctx) { VdpDecoderProfile profile; uint32_t level = avctx->level; diff --git a/libavcodec/vdpau_mpeg12.c b/libavcodec/vdpau_mpeg12.c index 1ce0bfaa0..4d16f1808 100644 --- a/libavcodec/vdpau_mpeg12.c +++ b/libavcodec/vdpau_mpeg12.c @@ -32,6 +32,7 @@ #include "vdpau_internal.h" static int vdpau_mpeg_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { MpegEncContext * const s = avctx->priv_data; @@ -100,7 +101,7 @@ static int vdpau_mpeg_decode_slice(AVCodecContext *avctx, } #if CONFIG_MPEG1_VDPAU_HWACCEL -static int vdpau_mpeg1_init(AVCodecContext *avctx) +static av_cold int vdpau_mpeg1_init(AVCodecContext *avctx) { return ff_vdpau_common_init(avctx, VDP_DECODER_PROFILE_MPEG1, VDP_DECODER_LEVEL_MPEG1_NA); @@ -123,7 +124,7 @@ const FFHWAccel ff_mpeg1_vdpau_hwaccel = { #endif #if CONFIG_MPEG2_VDPAU_HWACCEL -static int vdpau_mpeg2_init(AVCodecContext *avctx) +static av_cold int vdpau_mpeg2_init(AVCodecContext *avctx) { VdpDecoderProfile profile; diff --git a/libavcodec/vdpau_mpeg4.c b/libavcodec/vdpau_mpeg4.c index 40af8655c..668720a23 100644 --- a/libavcodec/vdpau_mpeg4.c +++ b/libavcodec/vdpau_mpeg4.c @@ -30,10 +30,11 @@ #include "vdpau_internal.h" static int vdpau_mpeg4_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { Mpeg4DecContext *ctx = avctx->priv_data; - MpegEncContext * const s = &ctx->m; + MPVContext *const s = &ctx->h.c; MPVPicture *pic = s->cur_pic.ptr; struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private; VdpPictureInfoMPEG4Part2 *info = &pic_ctx->info.mpeg4; @@ -63,11 +64,11 @@ static int vdpau_mpeg4_start_frame(AVCodecContext *avctx, info->trd[1] = s->pp_field_time >> 1; info->trb[1] = s->pb_field_time >> 1; info->vop_time_increment_resolution = s->avctx->framerate.num; - info->vop_fcode_forward = s->f_code; - info->vop_fcode_backward = s->b_code; + info->vop_fcode_forward = ctx->f_code; + info->vop_fcode_backward = ctx->b_code; info->resync_marker_disable = !ctx->resync_marker; info->interlaced = !s->progressive_sequence; - info->quant_type = s->mpeg_quant; + info->quant_type = ctx->mpeg_quant; info->quarter_sample = s->quarter_sample; info->short_video_header = avctx->codec->id == AV_CODEC_ID_H263; info->rounding_control = s->no_rounding; @@ -90,7 +91,7 @@ static int vdpau_mpeg4_decode_slice(av_unused AVCodecContext *avctx, return 0; } -static int vdpau_mpeg4_init(AVCodecContext *avctx) +static av_cold int vdpau_mpeg4_init(AVCodecContext *avctx) { VdpDecoderProfile profile; diff --git a/libavcodec/vdpau_vc1.c b/libavcodec/vdpau_vc1.c index d02a454bb..a5fd8156f 100644 --- a/libavcodec/vdpau_vc1.c +++ b/libavcodec/vdpau_vc1.c @@ -32,6 +32,7 @@ #include "vdpau_internal.h" static int vdpau_vc1_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { VC1Context * const v = avctx->priv_data; @@ -82,7 +83,7 @@ static int vdpau_vc1_start_frame(AVCodecContext *avctx, info->extended_dmv = v->extended_dmv; info->overlap = v->overlap; info->vstransform = v->vstransform; - info->loopfilter = v->s.loop_filter; + info->loopfilter = v->loop_filter; info->fastuvmc = v->fastuvmc; info->range_mapy_flag = v->range_mapy_flag; info->range_mapy = v->range_mapy; @@ -92,7 +93,7 @@ static int vdpau_vc1_start_frame(AVCodecContext *avctx, info->multires = v->multires; info->syncmarker = v->resync_marker; info->rangered = v->rangered | (v->rangeredfrm << 1); - info->maxbframes = v->s.max_b_frames; + info->maxbframes = v->max_b_frames; info->deblockEnable = v->postprocflag & 1; info->pquant = v->pq; @@ -116,7 +117,7 @@ static int vdpau_vc1_decode_slice(AVCodecContext *avctx, return 0; } -static int vdpau_vc1_init(AVCodecContext *avctx) +static av_cold int vdpau_vc1_init(AVCodecContext *avctx) { VdpDecoderProfile profile; diff --git a/libavcodec/vdpau_vp9.c b/libavcodec/vdpau_vp9.c index 424e2e60f..7b3c1ff4d 100644 --- a/libavcodec/vdpau_vp9.c +++ b/libavcodec/vdpau_vp9.c @@ -29,7 +29,8 @@ #include "vdpau_internal.h" static int vdpau_vp9_start_frame(AVCodecContext *avctx, - const uint8_t *buffer, uint32_t size) + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { VP9Context *s = avctx->priv_data; VP9SharedContext *h = &(s->s); @@ -197,7 +198,7 @@ static int vdpau_vp9_end_frame(AVCodecContext *avctx) return 0; } -static int vdpau_vp9_init(AVCodecContext *avctx) +static av_cold int vdpau_vp9_init(AVCodecContext *avctx) { VdpDecoderProfile profile; uint32_t level = avctx->level; diff --git a/libavcodec/version.c b/libavcodec/version.c index 27f94323b..07e8e47e4 100644 --- a/libavcodec/version.c +++ b/libavcodec/version.c @@ -31,13 +31,13 @@ const char av_codec_ffversion[] = "FFmpeg version " FFMPEG_VERSION; unsigned avcodec_version(void) { - static_assert(AV_CODEC_ID_LEAD == 269 && + static_assert(AV_CODEC_ID_PRORES_RAW == 274 && AV_CODEC_ID_PCM_SGA == 65572 && - AV_CODEC_ID_ADPCM_XMD == 69683 && + AV_CODEC_ID_ADPCM_SANYO == 69685 && AV_CODEC_ID_CBD2_DPCM == 81928 && - AV_CODEC_ID_QOA == 86121 && - AV_CODEC_ID_ARIB_CAPTION == 94233 && - AV_CODEC_ID_SMPTE_2038 == 98315, + AV_CODEC_ID_G728 == 86123 && + AV_CODEC_ID_IVTV_VBI == 94234 && + AV_CODEC_ID_SMPTE_436M_ANC == 98317, "Don't insert new codec ids in the middle of a list"); static_assert(LIBAVCODEC_VERSION_MICRO >= 100, "micro version starts at 100"); diff --git a/libavcodec/version.h b/libavcodec/version.h index b6ca025fa..b564e2d84 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 19 +#define LIBAVCODEC_VERSION_MINOR 28 #define LIBAVCODEC_VERSION_MICRO 101 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/libavcodec/version_major.h b/libavcodec/version_major.h index 63df40e9d..6c652374d 100644 --- a/libavcodec/version_major.h +++ b/libavcodec/version_major.h @@ -25,7 +25,7 @@ * Libavcodec version macros. */ -#define LIBAVCODEC_VERSION_MAJOR 61 +#define LIBAVCODEC_VERSION_MAJOR 62 /** * FF_API_* defines may be placed below to indicate public API that will be @@ -37,16 +37,23 @@ * at once through the bump. This improves the git bisect-ability of the change. */ -#define FF_API_INIT_PACKET (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_SUBFRAMES (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_TICKS_PER_FRAME (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_DROPCHANGED (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_INIT_PACKET (LIBAVCODEC_VERSION_MAJOR < 63) -#define FF_API_AVFFT (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_FF_PROFILE_LEVEL (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_AVCODEC_CLOSE (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_BUFFER_MIN_SIZE (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_VDPAU_ALLOC_GET_SET (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_QUALITY_FACTOR (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_V408_CODECID (LIBAVCODEC_VERSION_MAJOR < 63) +#define FF_API_CODEC_PROPS (LIBAVCODEC_VERSION_MAJOR < 63) +#define FF_API_EXR_GAMMA (LIBAVCODEC_VERSION_MAJOR < 63) +#define FF_API_INTRA_DC_PRECISION (LIBAVCODEC_VERSION_MAJOR < 63) + +#define FF_API_NVDEC_OLD_PIX_FMTS (LIBAVCODEC_VERSION_MAJOR < 63) + +#define FF_API_PARSER_PRIVATE (LIBAVCODEC_VERSION_MAJOR < 63) +#define FF_API_PARSER_CODECID (LIBAVCODEC_VERSION_MAJOR < 63) + +// reminder to remove the OMX encoder on next major bump +#define FF_CODEC_OMX (LIBAVCODEC_VERSION_MAJOR < 63) +// reminder to remove Sonic Lossy/Lossless encoders on next major bump +#define FF_CODEC_SONIC_ENC (LIBAVCODEC_VERSION_MAJOR < 63) +// reminder to remove Sonic decoder on next-next major bump +#define FF_CODEC_SONIC_DEC (LIBAVCODEC_VERSION_MAJOR < 63) #endif /* AVCODEC_VERSION_MAJOR_H */ diff --git a/libavcodec/videodsp.c b/libavcodec/videodsp.c index a19e87a81..c66757ce8 100644 --- a/libavcodec/videodsp.c +++ b/libavcodec/videodsp.c @@ -53,7 +53,7 @@ av_cold void ff_videodsp_init(VideoDSPContext *ctx, int bpc) ff_videodsp_init_ppc(ctx, bpc); #elif ARCH_RISCV ff_videodsp_init_riscv(ctx, bpc); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_videodsp_init_x86(ctx, bpc); #elif ARCH_MIPS ff_videodsp_init_mips(ctx, bpc); diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c index 505483ef6..2cd22cba1 100644 --- a/libavcodec/videotoolbox.c +++ b/libavcodec/videotoolbox.c @@ -56,6 +56,10 @@ enum { kCMVideoCodecType_HEVC = 'hvc1' }; enum { kCMVideoCodecType_VP9 = 'vp09' }; #endif +#if !HAVE_KCMVIDEOCODECTYPE_AV1 +enum { kCMVideoCodecType_AV1 = 'av01' }; +#endif + #define VIDEOTOOLBOX_ESDS_EXTRADATA_PADDING 12 typedef struct VTHWFrame { @@ -79,8 +83,8 @@ int ff_videotoolbox_buffer_copy(VTContext *vtctx, void *tmp; tmp = av_fast_realloc(vtctx->bitstream, - &vtctx->allocated_size, - size); + &vtctx->allocated_size, + size); if (!tmp) return AVERROR(ENOMEM); @@ -92,6 +96,26 @@ int ff_videotoolbox_buffer_copy(VTContext *vtctx, return 0; } +int ff_videotoolbox_buffer_append(VTContext *vtctx, + const uint8_t *buffer, + uint32_t size) +{ + void *tmp; + + tmp = av_fast_realloc(vtctx->bitstream, + &vtctx->allocated_size, + vtctx->bitstream_size + size); + + if (!tmp) + return AVERROR(ENOMEM); + + vtctx->bitstream = tmp; + memcpy(vtctx->bitstream + vtctx->bitstream_size, buffer, size); + vtctx->bitstream_size += size; + + return 0; +} + static int videotoolbox_postproc_frame(void *avctx, AVFrame *frame) { int ret; @@ -143,7 +167,7 @@ int ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame) } frame->buf[0] = buf; - fdd = (FrameDecodeData*)frame->private_ref->data; + fdd = frame->private_ref; fdd->post_process = videotoolbox_postproc_frame; frame->width = avctx->width; @@ -391,6 +415,7 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) } int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { @@ -703,8 +728,13 @@ static void videotoolbox_decoder_callback(void *opaque, } if (!image_buffer) { + // kVTVideoDecoderReferenceMissingErr, defined since the macOS 12 SDKs + if (status != -17694) + vtctx->reconfig_needed = true; + av_log(vtctx->logctx, status ? AV_LOG_WARNING : AV_LOG_DEBUG, - "vt decoder cb: output image buffer is null: %i\n", status); + "vt decoder cb: output image buffer is null: %i, reconfig %d\n", + status, vtctx->reconfig_needed); return; } @@ -846,6 +876,13 @@ static CFDictionaryRef videotoolbox_decoder_config_create(CMVideoCodecType codec if (data) CFDictionarySetValue(avc_info, CFSTR("vpcC"), data); break; +#endif +#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + case kCMVideoCodecType_AV1 : + data = ff_videotoolbox_av1c_extradata_create(avctx); + if (data) + CFDictionarySetValue(avc_info, CFSTR("av1C"), data); + break; #endif default: break; @@ -912,6 +949,9 @@ static int videotoolbox_start(AVCodecContext *avctx) case AV_CODEC_ID_VP9 : videotoolbox->cm_codec_type = kCMVideoCodecType_VP9; break; + case AV_CODEC_ID_AV1 : + videotoolbox->cm_codec_type = kCMVideoCodecType_AV1; + break; default : break; } @@ -1031,10 +1071,8 @@ int ff_videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame) return AVERROR_UNKNOWN; } - if (!vtctx->frame) { - vtctx->reconfig_needed = true; + if (!vtctx->frame) return AVERROR_UNKNOWN; - } return videotoolbox_buffer_create(avctx, frame); } @@ -1050,6 +1088,7 @@ static int videotoolbox_h264_end_frame(AVCodecContext *avctx) } static int videotoolbox_hevc_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { @@ -1093,6 +1132,7 @@ static int videotoolbox_hevc_end_frame(AVCodecContext *avctx) } static int videotoolbox_mpeg_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { @@ -1117,19 +1157,25 @@ static int videotoolbox_mpeg_end_frame(AVCodecContext *avctx) } static int videotoolbox_prores_start_frame(AVCodecContext *avctx, - const uint8_t *buffer, - uint32_t size) + const AVBufferRef *buffer_ref, + const uint8_t *buffer, + uint32_t size) { - return 0; + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + ProresContext *ctx = avctx->priv_data; + + /* Videotoolbox decodes both fields simultaneously */ + if (!ctx->first_field) + return 0; + + return ff_videotoolbox_buffer_copy(vtctx, buffer, size); } static int videotoolbox_prores_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { - VTContext *vtctx = avctx->internal->hwaccel_priv_data; - - return ff_videotoolbox_buffer_copy(vtctx, buffer, size); + return 0; } static int videotoolbox_prores_end_frame(AVCodecContext *avctx) @@ -1137,6 +1183,9 @@ static int videotoolbox_prores_end_frame(AVCodecContext *avctx) ProresContext *ctx = avctx->priv_data; AVFrame *frame = ctx->frame; + if (!ctx->first_field) + return 0; + return ff_videotoolbox_common_end_frame(avctx, frame); } @@ -1146,11 +1195,10 @@ static enum AVPixelFormat videotoolbox_best_pixel_format(AVCodecContext *avctx) if (!descriptor) return AV_PIX_FMT_NV12; // same as av_videotoolbox_alloc_context() + depth = descriptor->comp[0].depth; if (descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) - return AV_PIX_FMT_AYUV64; - - depth = descriptor->comp[0].depth; + return (depth > 8) ? AV_PIX_FMT_AYUV64 : AV_PIX_FMT_AYUV; #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE if (depth > 10) diff --git a/libavcodec/videotoolbox_av1.c b/libavcodec/videotoolbox_av1.c new file mode 100644 index 000000000..e69ef8f02 --- /dev/null +++ b/libavcodec/videotoolbox_av1.c @@ -0,0 +1,106 @@ +/* + * Videotoolbox hardware acceleration for AV1 + * Copyright (c) 2023 Jan Ekström + * Copyright (c) 2024 Ruslan Chernenko + * Copyright (c) 2024 Martin Storsjö + * + * 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/mem.h" + +#include "av1dec.h" +#include "hwaccel_internal.h" +#include "internal.h" +#include "vt_internal.h" + +CFDataRef ff_videotoolbox_av1c_extradata_create(AVCodecContext *avctx) +{ + AV1DecContext *s = avctx->priv_data; + uint8_t *buf; + CFDataRef data; + if (!s->raw_seq) + return NULL; + + buf = av_malloc(s->seq_data_ref->size + 4); + if (!buf) + return NULL; + buf[0] = 0x81; // version and marker (constant) + buf[1] = s->raw_seq->seq_profile << 5 | s->raw_seq->seq_level_idx[0]; + buf[2] = s->raw_seq->seq_tier[0] << 7 | + s->raw_seq->color_config.high_bitdepth << 6 | + s->raw_seq->color_config.twelve_bit << 5 | + s->raw_seq->color_config.mono_chrome << 4 | + s->raw_seq->color_config.subsampling_x << 3 | + s->raw_seq->color_config.subsampling_y << 2 | + s->raw_seq->color_config.chroma_sample_position; + + if (s->raw_seq->initial_display_delay_present_flag) + buf[3] = 0 << 5 | + s->raw_seq->initial_display_delay_present_flag << 4 | + s->raw_seq->initial_display_delay_minus_1[0]; + else + buf[3] = 0x00; + memcpy(buf + 4, s->seq_data_ref->data, s->seq_data_ref->size); + data = CFDataCreate(kCFAllocatorDefault, buf, s->seq_data_ref->size + 4); + av_free(buf); + return data; +}; + + +static int videotoolbox_av1_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, + uint32_t size) +{ + return 0; +} + +static int videotoolbox_av1_decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + return 0; +} + +static int videotoolbox_av1_end_frame(AVCodecContext *avctx) +{ + const AV1DecContext *s = avctx->priv_data; + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + AVFrame *frame = s->cur_frame.f; + + vtctx->bitstream_size = 0; + for (int i = s->start_unit; i < s->nb_unit; i++) + ff_videotoolbox_buffer_append(vtctx, s->current_obu.units[i].data, + s->current_obu.units[i].data_size); + return ff_videotoolbox_common_end_frame(avctx, frame); +} + +const FFHWAccel ff_av1_videotoolbox_hwaccel = { + .p.name = "av1_videotoolbox", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_AV1, + .p.pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX, + .alloc_frame = ff_videotoolbox_alloc_frame, + .start_frame = videotoolbox_av1_start_frame, + .decode_slice = videotoolbox_av1_decode_slice, + .end_frame = videotoolbox_av1_end_frame, + .frame_params = ff_videotoolbox_frame_params, + .init = ff_videotoolbox_common_init, + .uninit = ff_videotoolbox_uninit, + .priv_data_size = sizeof(VTContext), +}; diff --git a/libavcodec/videotoolbox_vp9.c b/libavcodec/videotoolbox_vp9.c index 232468d51..1d3dcce2e 100644 --- a/libavcodec/videotoolbox_vp9.c +++ b/libavcodec/videotoolbox_vp9.c @@ -104,6 +104,7 @@ CFDataRef ff_videotoolbox_vpcc_extradata_create(AVCodecContext *avctx) } static int videotoolbox_vp9_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c index 69656ccb5..cb3571c72 100644 --- a/libavcodec/videotoolboxenc.c +++ b/libavcodec/videotoolboxenc.c @@ -18,28 +18,28 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include -#include -#include #include -#include "avcodec.h" +#include +#include +#include +#include +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" #include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/avassert.h" -#include "libavutil/avstring.h" -#include "libavcodec/avcodec.h" #include "libavutil/pixdesc.h" #include "libavutil/hwcontext_videotoolbox.h" -#include "codec_internal.h" -#include "internal.h" -#include + #include "atsc_a53.h" +#include "codec_internal.h" #include "encode.h" #include "h264.h" #include "h264_sei.h" #include "hwconfig.h" -#include +#include "internal.h" #if !HAVE_KCMVIDEOCODECTYPE_HEVC enum { kCMVideoCodecType_HEVC = 'hvc1' }; @@ -54,6 +54,11 @@ enum { kCVPixelFormatType_420YpCbCr10BiPlanarFullRange = 'xf20' }; enum { kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange = 'x420' }; #endif +#if !HAVE_KVTQPMODULATIONLEVEL_DEFAULT +enum { kVTQPModulationLevel_Default = -1 }; +enum { kVTQPModulationLevel_Disable = 0 }; +#endif + #ifndef TARGET_CPU_ARM64 # define TARGET_CPU_ARM64 0 #endif @@ -115,12 +120,14 @@ static struct{ CFStringRef kVTProfileLevel_HEVC_Main_AutoLevel; CFStringRef kVTProfileLevel_HEVC_Main10_AutoLevel; + CFStringRef kVTProfileLevel_HEVC_Main42210_AutoLevel; CFStringRef kVTCompressionPropertyKey_RealTime; CFStringRef kVTCompressionPropertyKey_TargetQualityForAlpha; CFStringRef kVTCompressionPropertyKey_PrioritizeEncodingSpeedOverQuality; CFStringRef kVTCompressionPropertyKey_ConstantBitRate; CFStringRef kVTCompressionPropertyKey_EncoderID; + CFStringRef kVTCompressionPropertyKey_SpatialAdaptiveQPLevel; CFStringRef kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder; CFStringRef kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder; @@ -186,6 +193,7 @@ static void loadVTEncSymbols(void){ GET_SYM(kVTProfileLevel_HEVC_Main_AutoLevel, "HEVC_Main_AutoLevel"); GET_SYM(kVTProfileLevel_HEVC_Main10_AutoLevel, "HEVC_Main10_AutoLevel"); + GET_SYM(kVTProfileLevel_HEVC_Main42210_AutoLevel, "HEVC_Main42210_AutoLevel"); GET_SYM(kVTCompressionPropertyKey_RealTime, "RealTime"); GET_SYM(kVTCompressionPropertyKey_TargetQualityForAlpha, @@ -208,6 +216,7 @@ static void loadVTEncSymbols(void){ "ReferenceBufferCount"); GET_SYM(kVTCompressionPropertyKey_MaxAllowedFrameQP, "MaxAllowedFrameQP"); GET_SYM(kVTCompressionPropertyKey_MinAllowedFrameQP, "MinAllowedFrameQP"); + GET_SYM(kVTCompressionPropertyKey_SpatialAdaptiveQPLevel, "SpatialAdaptiveQPLevel"); } #define H264_PROFILE_CONSTRAINED_HIGH (AV_PROFILE_H264_HIGH | AV_PROFILE_H264_CONSTRAINED) @@ -279,6 +288,7 @@ typedef struct VTEncContext { int max_slice_bytes; int power_efficient; int max_ref_frames; + int spatialaq; } VTEncContext; static void vtenc_free_buf_node(BufNode *info) @@ -657,7 +667,7 @@ static int copy_param_sets( next_offset = offset + sizeof(start_code) + ps_size; if (dst_size < next_offset) { - av_log(avctx, AV_LOG_ERROR, "Error: buffer too small for parameter sets.\n"); + av_log(avctx, AV_LOG_ERROR, "Buffer too small for parameter sets.\n"); return AVERROR_BUFFER_TOO_SMALL; } @@ -971,6 +981,11 @@ static bool get_vt_hevc_profile_level(AVCodecContext *avctx, *profile_level_val = compat_keys.kVTProfileLevel_HEVC_Main10_AutoLevel; break; + case AV_PROFILE_HEVC_REXT: + // only main42210 is supported, omit depth and chroma subsampling + *profile_level_val = + compat_keys.kVTProfileLevel_HEVC_Main42210_AutoLevel; + break; } if (!*profile_level_val) { @@ -1170,9 +1185,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx, VTEncContext *vtctx = avctx->priv_data; SInt32 bit_rate = avctx->bit_rate; SInt32 max_rate = avctx->rc_max_rate; - Float32 quality = avctx->global_quality / FF_QP2LAMBDA; CFNumberRef bit_rate_num; - CFNumberRef quality_num; CFNumberRef bytes_per_second; CFNumberRef one_second; CFArrayRef data_rate_limits; @@ -1192,7 +1205,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx, session); if (status || !vtctx->session) { - av_log(avctx, AV_LOG_ERROR, "Error: cannot create compression session: %d\n", status); + av_log(avctx, AV_LOG_ERROR, "Cannot create compression session: %d\n", status); #if !TARGET_OS_IPHONE if (!vtctx->allow_sw) { @@ -1204,7 +1217,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx, } #if defined (MAC_OS_X_VERSION_10_13) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13) - if (__builtin_available(macOS 10.13, *)) { + if (__builtin_available(macOS 10.13, iOS 11.0, *)) { if (vtctx->supported_props) { CFRelease(vtctx->supported_props); vtctx->supported_props = NULL; @@ -1228,15 +1241,17 @@ static int vtenc_create_encoder(AVCodecContext *avctx, return status; if (avctx->flags & AV_CODEC_FLAG_QSCALE && !vtenc_qscale_enabled()) { - av_log(avctx, AV_LOG_ERROR, "Error: -q:v qscale not available for encoder. Use -b:v bitrate instead.\n"); + av_log(avctx, AV_LOG_ERROR, "-q:v qscale not available for encoder. Use -b:v bitrate instead.\n"); return AVERROR_EXTERNAL; } - if (avctx->flags & AV_CODEC_FLAG_QSCALE) { - quality = quality >= 100 ? 1.0 : quality / 100; - quality_num = CFNumberCreate(kCFAllocatorDefault, - kCFNumberFloat32Type, - &quality); + if (avctx->flags & AV_CODEC_FLAG_QSCALE || avctx->global_quality > 0) { + float factor = (avctx->flags & AV_CODEC_FLAG_QSCALE) ? + FF_QP2LAMBDA * 100.0f : 100.0f; + Float32 quality = fminf(avctx->global_quality / factor, 1.0f); + CFNumberRef quality_num = CFNumberCreate(kCFAllocatorDefault, + kCFNumberFloat32Type, + &quality); if (!quality_num) return AVERROR(ENOMEM); status = VTSessionSetProperty(vtctx->session, @@ -1254,7 +1269,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx, compat_keys.kVTCompressionPropertyKey_ConstantBitRate, bit_rate_num); if (status == kVTPropertyNotSupportedErr) { - av_log(avctx, AV_LOG_ERROR, "Error: -constant_bit_rate true is not supported by the encoder.\n"); + av_log(avctx, AV_LOG_ERROR, "-constant_bit_rate true is not supported by the encoder.\n"); return AVERROR_EXTERNAL; } } else { @@ -1327,8 +1342,10 @@ static int vtenc_create_encoder(AVCodecContext *avctx, } } - if (vtctx->codec_id == AV_CODEC_ID_HEVC) { - if (avctx->pix_fmt == AV_PIX_FMT_BGRA && vtctx->alpha_quality > 0.0) { + if (vtctx->codec_id == AV_CODEC_ID_HEVC && vtctx->alpha_quality > 0.0) { + const AVPixFmtDescriptor *descriptor = av_pix_fmt_desc_get(avctx->pix_fmt); + + if (descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) { CFNumberRef alpha_quality_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &vtctx->alpha_quality); @@ -1599,9 +1616,16 @@ static int vtenc_create_encoder(AVCodecContext *avctx, } } + if (vtctx->spatialaq >= 0) { + set_encoder_int_property_or_log(avctx, + compat_keys.kVTCompressionPropertyKey_SpatialAdaptiveQPLevel, + "spatialaq", + vtctx->spatialaq ? kVTQPModulationLevel_Default : kVTQPModulationLevel_Disable); + } + status = VTCompressionSessionPrepareToEncodeFrames(vtctx->session); if (status) { - av_log(avctx, AV_LOG_ERROR, "Error: cannot prepare encoder: %d\n", status); + av_log(avctx, AV_LOG_ERROR, "Cannot prepare encoder: %d\n", status); return AVERROR_EXTERNAL; } @@ -1620,7 +1644,7 @@ static int vtenc_configure_encoder(AVCodecContext *avctx) codec_type = get_cm_codec_type(avctx, vtctx->profile, vtctx->alpha_quality); if (!codec_type) { - av_log(avctx, AV_LOG_ERROR, "Error: no mapping for AVCodecID %d\n", avctx->codec_id); + av_log(avctx, AV_LOG_ERROR, "No mapping for AVCodecID %d\n", avctx->codec_id); return AVERROR(EINVAL); } @@ -1685,7 +1709,14 @@ static int vtenc_configure_encoder(AVCodecContext *avctx) #endif // low-latency mode: eliminate frame reordering, follow a one-in-one-out encoding mode - if ((avctx->flags & AV_CODEC_FLAG_LOW_DELAY) && avctx->codec_id == AV_CODEC_ID_H264) { + if ((avctx->flags & AV_CODEC_FLAG_LOW_DELAY) && + ((avctx->codec_id == AV_CODEC_ID_H264) || (TARGET_CPU_ARM64 && avctx->codec_id == AV_CODEC_ID_HEVC))) { + if (!avctx->bit_rate) { + av_log(avctx, AV_LOG_ERROR, "Doesn't support automatic bitrate in low_delay mode, " + "please specify bitrate explicitly\n"); + status = AVERROR(EINVAL); + goto init_cleanup; + } CFDictionarySetValue(enc_info, compat_keys.kVTVideoEncoderSpecification_EnableLowLatencyRateControl, kCFBooleanTrue); @@ -2297,160 +2328,39 @@ static int vtenc_cm_to_avpacket( return 0; } -/* - * contiguous_buf_size is 0 if not contiguous, and the size of the buffer - * containing all planes if so. - */ -static int get_cv_pixel_info( - AVCodecContext *avctx, - const AVFrame *frame, - int *color, - int *plane_count, - size_t *widths, - size_t *heights, - size_t *strides, - size_t *contiguous_buf_size) -{ - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); - VTEncContext *vtctx = avctx->priv_data; - int av_format = frame->format; - int av_color_range = avctx->color_range; - int i; - int range_guessed; - int status; - - if (!desc) - return AVERROR(EINVAL); - - status = get_cv_pixel_format(avctx, av_format, av_color_range, color, &range_guessed); - if (status) - return status; - - if (range_guessed) { - if (!vtctx->warned_color_range) { - vtctx->warned_color_range = true; - av_log(avctx, - AV_LOG_WARNING, - "Color range not set for %s. Using MPEG range.\n", - av_get_pix_fmt_name(av_format)); - } - } - - *plane_count = av_pix_fmt_count_planes(avctx->pix_fmt); - - for (i = 0; i < desc->nb_components; i++) { - int p = desc->comp[i].plane; - bool hasAlpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA); - bool isAlpha = hasAlpha && (p + 1 == *plane_count); - bool isChroma = (p != 0) && !isAlpha; - int shiftw = isChroma ? desc->log2_chroma_w : 0; - int shifth = isChroma ? desc->log2_chroma_h : 0; - widths[p] = (avctx->width + ((1 << shiftw) >> 1)) >> shiftw; - heights[p] = (avctx->height + ((1 << shifth) >> 1)) >> shifth; - strides[p] = frame->linesize[p]; - } - - *contiguous_buf_size = 0; - for (i = 0; i < *plane_count; i++) { - if (i < *plane_count - 1 && - frame->data[i] + strides[i] * heights[i] != frame->data[i + 1]) { - *contiguous_buf_size = 0; - break; - } - - *contiguous_buf_size += strides[i] * heights[i]; - } - - return 0; -} - -//Not used on OSX - frame is never copied. static int copy_avframe_to_pixel_buffer(AVCodecContext *avctx, const AVFrame *frame, - CVPixelBufferRef cv_img, - const size_t *plane_strides, - const size_t *plane_rows) + CVPixelBufferRef cv_img) { - int i, j; - size_t plane_count; int status; - int rows; - int src_stride; - int dst_stride; - uint8_t *src_addr; - uint8_t *dst_addr; - size_t copy_bytes; + + int num_planes = av_pix_fmt_count_planes(frame->format); + size_t num_cv_plane = CVPixelBufferIsPlanar(cv_img) ? + CVPixelBufferGetPlaneCount(cv_img) : 1; + if (num_planes != num_cv_plane) { + av_log(avctx, AV_LOG_ERROR, + "Different number of planes in AVFrame and CVPixelBuffer.\n"); + return AVERROR_BUG; + } status = CVPixelBufferLockBaseAddress(cv_img, 0); if (status) { - av_log( - avctx, - AV_LOG_ERROR, - "Error: Could not lock base address of CVPixelBuffer: %d.\n", - status - ); + av_log(avctx, AV_LOG_ERROR, "Could not lock base address of CVPixelBuffer: %d.\n", status); + return AVERROR_EXTERNAL; } - if (CVPixelBufferIsPlanar(cv_img)) { - plane_count = CVPixelBufferGetPlaneCount(cv_img); - for (i = 0; frame->data[i]; i++) { - if (i == plane_count) { - CVPixelBufferUnlockBaseAddress(cv_img, 0); - av_log(avctx, - AV_LOG_ERROR, - "Error: different number of planes in AVFrame and CVPixelBuffer.\n" - ); - - return AVERROR_EXTERNAL; - } - - dst_addr = (uint8_t*)CVPixelBufferGetBaseAddressOfPlane(cv_img, i); - src_addr = (uint8_t*)frame->data[i]; - dst_stride = CVPixelBufferGetBytesPerRowOfPlane(cv_img, i); - src_stride = plane_strides[i]; - rows = plane_rows[i]; - - if (dst_stride == src_stride) { - memcpy(dst_addr, src_addr, src_stride * rows); - } else { - copy_bytes = dst_stride < src_stride ? dst_stride : src_stride; - - for (j = 0; j < rows; j++) { - memcpy(dst_addr + j * dst_stride, src_addr + j * src_stride, copy_bytes); - } - } - } - } else { - if (frame->data[1]) { - CVPixelBufferUnlockBaseAddress(cv_img, 0); - av_log(avctx, - AV_LOG_ERROR, - "Error: different number of planes in AVFrame and non-planar CVPixelBuffer.\n" - ); - - return AVERROR_EXTERNAL; - } - - dst_addr = (uint8_t*)CVPixelBufferGetBaseAddress(cv_img); - src_addr = (uint8_t*)frame->data[0]; - dst_stride = CVPixelBufferGetBytesPerRow(cv_img); - src_stride = plane_strides[0]; - rows = plane_rows[0]; - - if (dst_stride == src_stride) { - memcpy(dst_addr, src_addr, src_stride * rows); - } else { - copy_bytes = dst_stride < src_stride ? dst_stride : src_stride; - - for (j = 0; j < rows; j++) { - memcpy(dst_addr + j * dst_stride, src_addr + j * src_stride, copy_bytes); - } - } + int dst_stride[4] = {0}; + uint8_t *dst_addr[4] = {0}; + for (int i = 0; i < num_planes; i++) { + dst_addr[i] = (uint8_t*)CVPixelBufferGetBaseAddressOfPlane(cv_img, i); + dst_stride[i] = CVPixelBufferGetBytesPerRowOfPlane(cv_img, i); } + av_image_copy2(dst_addr, dst_stride, frame->data, frame->linesize, + frame->format, frame->width, frame->height); status = CVPixelBufferUnlockBaseAddress(cv_img, 0); if (status) { - av_log(avctx, AV_LOG_ERROR, "Error: Could not unlock CVPixelBuffer base address: %d.\n", status); + av_log(avctx, AV_LOG_ERROR, "Could not unlock CVPixelBuffer base address: %d.\n", status); return AVERROR_EXTERNAL; } @@ -2462,13 +2372,7 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx, CVPixelBufferRef *cv_img, BufNode *node) { - int plane_count; - int color; - size_t widths [AV_NUM_DATA_POINTERS]; - size_t heights[AV_NUM_DATA_POINTERS]; - size_t strides[AV_NUM_DATA_POINTERS]; int status; - size_t contiguous_buf_size; CVPixelBufferPoolRef pix_buf_pool; VTEncContext* vtctx = avctx->priv_data; @@ -2488,33 +2392,21 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx, return 0; } - memset(widths, 0, sizeof(widths)); - memset(heights, 0, sizeof(heights)); - memset(strides, 0, sizeof(strides)); - - status = get_cv_pixel_info( - avctx, - frame, - &color, - &plane_count, - widths, - heights, - strides, - &contiguous_buf_size - ); - + int range_guessed; + status = get_cv_pixel_format(avctx, frame->format, avctx->color_range, + &(int) {0}, &range_guessed); if (status) { - av_log( - avctx, - AV_LOG_ERROR, - "Error: Cannot convert format %d color_range %d: %d\n", - frame->format, - frame->color_range, - status - ); - + av_log(avctx, AV_LOG_ERROR, "Cannot convert format %d color_range %d: %d\n", + frame->format, frame->color_range, status); return status; } + if (range_guessed) { + if (!vtctx->warned_color_range) { + vtctx->warned_color_range = true; + av_log(avctx, AV_LOG_WARNING, "Color range not set for %s. Using MPEG range.\n", + av_get_pix_fmt_name(frame->format)); + } + } pix_buf_pool = VTCompressionSessionGetPixelBufferPool(vtctx->session); if (!pix_buf_pool) { @@ -2551,7 +2443,7 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx, return AVERROR_EXTERNAL; } - status = copy_avframe_to_pixel_buffer(avctx, frame, *cv_img, strides, heights); + status = copy_avframe_to_pixel_buffer(avctx, frame, *cv_img); if (status) { CFRelease(*cv_img); *cv_img = NULL; @@ -2621,7 +2513,7 @@ static int vtenc_send_frame(AVCodecContext *avctx, ); if (status) { - av_log(avctx, AV_LOG_ERROR, "Error: cannot encode frame: %d\n", status); + av_log(avctx, AV_LOG_ERROR, "Cannot encode frame: %d\n", status); status = AVERROR_EXTERNAL; // Not necessary, just in case new code put after here goto out; @@ -2838,7 +2730,9 @@ static const enum AVPixelFormat hevc_pix_fmts[] = { AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, AV_PIX_FMT_BGRA, + AV_PIX_FMT_AYUV, AV_PIX_FMT_P010LE, + AV_PIX_FMT_P210, AV_PIX_FMT_NONE }; @@ -2891,6 +2785,8 @@ static const enum AVPixelFormat prores_pix_fmts[] = { { .i64 = -1 }, -1, 1, VE }, \ { "power_efficient", "Set to 1 to enable more power-efficient encoding if supported.", \ OFFSET(power_efficient), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ + { "spatial_aq", "Set to 1 to enable spatial AQ if supported.", \ + OFFSET(spatialaq), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ { "max_ref_frames", \ "Sets the maximum number of reference frames. This only has an effect when the value is less than the maximum allowed by the profile/level.", \ OFFSET(max_ref_frames), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, @@ -2957,7 +2853,7 @@ const FFCodec ff_h264_videotoolbox_encoder = { .p.id = AV_CODEC_ID_H264, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .priv_data_size = sizeof(VTEncContext), - .p.pix_fmts = avc_pix_fmts, + CODEC_PIXFMTS_ARRAY(avc_pix_fmts), .defaults = vt_defaults, .init = vtenc_init, FF_CODEC_ENCODE_CB(vtenc_frame), @@ -2971,6 +2867,8 @@ static const AVOption hevc_options[] = { { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, INT_MAX, VE, .unit = "profile" }, { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_MAIN }, INT_MIN, INT_MAX, VE, .unit = "profile" }, { "main10", "Main10 Profile", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_MAIN_10 }, INT_MIN, INT_MAX, VE, .unit = "profile" }, + { "main42210","Main 4:2:2 10 Profile",0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_REXT }, INT_MIN, INT_MAX, VE, .unit = "profile" }, + { "rext", "Main 4:2:2 10 Profile",0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_REXT }, INT_MIN, INT_MAX, VE, .unit = "profile" }, { "alpha_quality", "Compression quality for the alpha channel", OFFSET(alpha_quality), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, 0.0, 1.0, VE }, @@ -2995,7 +2893,7 @@ const FFCodec ff_hevc_videotoolbox_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .priv_data_size = sizeof(VTEncContext), - .p.pix_fmts = hevc_pix_fmts, + CODEC_PIXFMTS_ARRAY(hevc_pix_fmts), .defaults = vt_defaults, .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .init = vtenc_init, @@ -3036,7 +2934,7 @@ const FFCodec ff_prores_videotoolbox_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .priv_data_size = sizeof(VTEncContext), - .p.pix_fmts = prores_pix_fmts, + CODEC_PIXFMTS_ARRAY(prores_pix_fmts), .defaults = vt_defaults, .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .init = vtenc_init, diff --git a/libavcodec/vima.c b/libavcodec/vima.c index 56cc1b7a8..bde7033c2 100644 --- a/libavcodec/vima.c +++ b/libavcodec/vima.c @@ -28,6 +28,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/thread.h" +#include "adpcm.h" #include "adpcm_data.h" #include "avcodec.h" #include "codec_internal.h" @@ -159,46 +160,60 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; - for (chan = 0; chan < channels; chan++) { - uint16_t *dest = (uint16_t *)frame->data[0] + chan; - int step_index = channel_hint[chan]; - int output = pcm_data[chan]; - int sample; + if (show_bits_long(&gb, 32) == MKBETAG('I','M','A','4')) { + int16_t *dest = (int16_t *)frame->data[0]; + ADPCMChannelStatus cs; - for (sample = 0; sample < samples; sample++) { - int lookup_size, lookup, highbit, lowbits; + skip_bits_long(&gb, 32); /* skip the 'IMA4' tag */ + cs.predictor = (int16_t)get_xbits_le(&gb, 16); + cs.step_index = av_clip(get_bits(&gb, 8), 0, 88); + for (int i = 0; i < samples; i++) { + ff_adpcm_ima_qt_expand_nibble(&cs, get_bits(&gb, 4)); + for (int j = 0; j < channels; j++) + *dest++ = cs.predictor; + } + } else { + for (chan = 0; chan < channels; chan++) { + uint16_t *dest = (uint16_t *)frame->data[0] + chan; + int step_index = channel_hint[chan]; + int output = pcm_data[chan]; + int sample; - step_index = av_clip(step_index, 0, 88); - lookup_size = size_table[step_index]; - lookup = get_bits(&gb, lookup_size); - highbit = 1 << (lookup_size - 1); - lowbits = highbit - 1; + for (sample = 0; sample < samples; sample++) { + int lookup_size, lookup, highbit, lowbits; - if (lookup & highbit) - lookup ^= highbit; - else - highbit = 0; + step_index = av_clip(step_index, 0, 88); + lookup_size = size_table[step_index]; + lookup = get_bits(&gb, lookup_size); + highbit = 1 << (lookup_size - 1); + lowbits = highbit - 1; - if (lookup == lowbits) { - output = get_sbits(&gb, 16); - } else { - int predict_index, diff; + if (lookup & highbit) + lookup ^= highbit; + else + highbit = 0; - predict_index = (lookup << (7 - lookup_size)) | (step_index << 6); - predict_index = av_clip(predict_index, 0, 5785); - diff = predict_table[predict_index]; - if (lookup) - diff += ff_adpcm_step_table[step_index] >> (lookup_size - 1); - if (highbit) - diff = -diff; + if (lookup == lowbits) { + output = get_sbits(&gb, 16); + } else { + int predict_index, diff; - output = av_clip_int16(output + diff); + predict_index = (lookup << (7 - lookup_size)) | (step_index << 6); + predict_index = av_clip(predict_index, 0, 5785); + diff = predict_table[predict_index]; + if (lookup) + diff += ff_adpcm_step_table[step_index] >> (lookup_size - 1); + if (highbit) + diff = -diff; + + output = av_clip_int16(output + diff); + } + + *dest = output; + dest += channels; + + step_index += step_index_tables[lookup_size - 2][lookup]; } - - *dest = output; - dest += channels; - - step_index += step_index_tables[lookup_size - 2][lookup]; } } diff --git a/libavcodec/vlc.c b/libavcodec/vlc.c index 7209724dc..93d88714f 100644 --- a/libavcodec/vlc.c +++ b/libavcodec/vlc.c @@ -42,6 +42,8 @@ { \ const uint8_t *ptr = (const uint8_t *)table + i * wrap; \ switch(size) { \ + default: \ + av_unreachable("Only uint8/16/32_t are used"); \ case 1: \ v = *(const uint8_t *)ptr; \ break; \ @@ -49,8 +51,6 @@ v = *(const uint16_t *)ptr; \ break; \ case 4: \ - default: \ - av_assert1(size == 4); \ v = *(const uint32_t *)ptr; \ break; \ } \ @@ -155,7 +155,7 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes, int n = codes[i].bits; uint32_t code = codes[i].code; int symbol = codes[i].symbol; - ff_dlog(NULL, "i=%d n=%d code=0x%"PRIx32"\n", i, n, code); + ff_tlog(NULL, "i=%d n=%d code=0x%"PRIx32"\n", i, n, code); if (n <= table_nb_bits) { /* no need to add another table */ int j = code >> (32 - table_nb_bits); @@ -169,7 +169,7 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes, for (int k = 0; k < nb; k++) { int bits = table[j].len; int oldsym = table[j].sym; - ff_dlog(NULL, "%4x: code=%d n=%d\n", j, i, n); + ff_tlog(NULL, "%4x: code=%d n=%d\n", j, i, n); if ((bits || oldsym) && (bits != n || oldsym != symbol)) { av_log(NULL, AV_LOG_ERROR, "incorrect codes\n"); return AVERROR_INVALIDDATA; @@ -260,7 +260,7 @@ int ff_vlc_init_sparse(VLC *vlc, int nb_bits, int nb_codes, if (ret < 0) return ret; - av_assert0(symbols_size <= 2 || !symbols); + av_assert0(symbols_size <= 2U); j = 0; #define COPY(condition)\ for (int i = 0; i < nb_codes; i++) { \ @@ -491,7 +491,7 @@ static int vlc_multi_gen(VLC_MULTI_ELEM *table, const VLC *single, // We can only add a code that fits with the shortest other code into the table // We assume the table is sorted by bits and we skip subtables which from our // point of view are basically random corrupted entries - // If we have not a single useable vlc we end with max = nb_codes + // If we have not a single usable vlc we end with max = nb_codes if (buf[max - 1].bits+minbits > numbits) break; } diff --git a/libavcodec/vlc.h b/libavcodec/vlc.h index bf7b0e65b..7eecd9651 100644 --- a/libavcodec/vlc.h +++ b/libavcodec/vlc.h @@ -30,9 +30,23 @@ typedef int16_t VLCBaseType; typedef struct VLCElem { - VLCBaseType sym, len; + union { + /// The struct is for use as ordinary VLC (with get_vlc2()) + struct { + VLCBaseType sym; + VLCBaseType len; + }; + /// This struct is for use as run-length VLC (with GET_RL_VLC) + struct { + int16_t level; + int8_t len8; + uint8_t run; + }; + }; } VLCElem; +typedef VLCElem RL_VLC_ELEM; + typedef struct VLC { int bits; VLCElem *table; @@ -53,12 +67,6 @@ typedef struct VLC_MULTI { int table_size, table_allocated; } VLC_MULTI; -typedef struct RL_VLC_ELEM { - int16_t level; - int8_t len; - uint8_t run; -} RL_VLC_ELEM; - #define vlc_init(vlc, nb_bits, nb_codes, \ bits, bits_wrap, bits_size, \ codes, codes_wrap, codes_size, \ diff --git a/libavcodec/vorbis_parser.c b/libavcodec/vorbis_parser.c index c6969f139..88b81fcb5 100644 --- a/libavcodec/vorbis_parser.c +++ b/libavcodec/vorbis_parser.c @@ -31,6 +31,7 @@ #include "libavutil/mem.h" #include "get_bits.h" +#include "parser_internal.h" #include "xiph.h" #include "vorbis_parser_internal.h" @@ -329,16 +330,16 @@ end: return buf_size; } -static void vorbis_parser_close(AVCodecParserContext *ctx) +static av_cold void vorbis_parser_close(AVCodecParserContext *ctx) { VorbisParseContext *s = ctx->priv_data; av_vorbis_parse_free(&s->vp); } -const AVCodecParser ff_vorbis_parser = { - .codec_ids = { AV_CODEC_ID_VORBIS }, +const FFCodecParser ff_vorbis_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_VORBIS), .priv_data_size = sizeof(VorbisParseContext), - .parser_parse = vorbis_parse, - .parser_close = vorbis_parser_close, + .parse = vorbis_parse, + .close = vorbis_parser_close, }; #endif /* CONFIG_VORBIS_PARSER */ diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c index 32944af31..aff95f44a 100644 --- a/libavcodec/vorbisdec.c +++ b/libavcodec/vorbisdec.c @@ -375,13 +375,13 @@ static int vorbis_parse_setup_hdr_codebooks(vorbis_context *vc) } ff_dlog(NULL, " We expect %d numbers for building the codevectors. \n", codebook_lookup_values); - ff_dlog(NULL, " delta %f minmum %f \n", + ff_dlog(NULL, " delta %f minimum %f \n", codebook_delta_value, codebook_minimum_value); for (i = 0; i < codebook_lookup_values; ++i) { codebook_multiplicands[i] = get_bits(gb, codebook_value_bits); - ff_dlog(NULL, " multiplicands*delta+minmum : %e \n", + ff_dlog(NULL, " multiplicands*delta+minimum : %e \n", (float)codebook_multiplicands[i] * codebook_delta_value + codebook_minimum_value); ff_dlog(NULL, " multiplicand %u\n", codebook_multiplicands[i]); } @@ -1150,7 +1150,7 @@ static int vorbis_floor0_decode(vorbis_context *vc, ff_dlog(NULL, "floor0 dec: maximum depth: %d\n", codebook.maxdepth); /* read temp vector */ vec_off = get_vlc2(&vc->gb, codebook.vlc.table, - codebook.nb_bits, codebook.maxdepth); + codebook.nb_bits, 3); if (vec_off < 0) return AVERROR_INVALIDDATA; vec_off *= codebook.dimensions; @@ -1896,7 +1896,4 @@ const FFCodec ff_vorbis_decoder = { .flush = vorbis_decode_flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.ch_layouts = ff_vorbis_ch_layouts, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/vorbisdsp.c b/libavcodec/vorbisdsp.c index 70022bd26..54a55d109 100644 --- a/libavcodec/vorbisdsp.c +++ b/libavcodec/vorbisdsp.c @@ -55,7 +55,7 @@ av_cold void ff_vorbisdsp_init(VorbisDSPContext *dsp) ff_vorbisdsp_init_ppc(dsp); #elif ARCH_RISCV ff_vorbisdsp_init_riscv(dsp); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_vorbisdsp_init_x86(dsp); #endif } diff --git a/libavcodec/vorbisenc.c b/libavcodec/vorbisenc.c index 62684a7d8..ab30dd49e 100644 --- a/libavcodec/vorbisenc.c +++ b/libavcodec/vorbisenc.c @@ -463,11 +463,11 @@ static int create_vorbis_context(vorbis_enc_context *venc, venc->modes[1].mapping = 0; venc->have_saved = 0; - venc->saved = av_malloc_array(sizeof(float) * venc->channels, (1 << venc->log2_blocksize[1]) / 2); - venc->samples = av_malloc_array(sizeof(float) * venc->channels, (1 << venc->log2_blocksize[1])); - venc->floor = av_malloc_array(sizeof(float) * venc->channels, (1 << venc->log2_blocksize[1]) / 2); - venc->coeffs = av_malloc_array(sizeof(float) * venc->channels, (1 << venc->log2_blocksize[1]) / 2); - venc->scratch = av_malloc_array(sizeof(float) * venc->channels, (1 << venc->log2_blocksize[1])); + venc->saved = av_malloc_array((1 << venc->log2_blocksize[1]) / 2, sizeof(float) * venc->channels); + venc->samples = av_malloc_array((1 << venc->log2_blocksize[1]), sizeof(float) * venc->channels); + venc->floor = av_malloc_array((1 << venc->log2_blocksize[1]) / 2, sizeof(float) * venc->channels); + venc->coeffs = av_malloc_array((1 << venc->log2_blocksize[1]) / 2, sizeof(float) * venc->channels); + venc->scratch = av_malloc_array((1 << venc->log2_blocksize[1]), sizeof(float) * venc->channels); if (!venc->saved || !venc->samples || !venc->floor || !venc->coeffs || !venc->scratch) return AVERROR(ENOMEM); @@ -740,8 +740,10 @@ static int put_main_header(vorbis_enc_context *venc, uint8_t **out) len = hlens[0] + hlens[1] + hlens[2]; p = *out = av_mallocz(64 + len + len/255); - if (!p) + if (!p) { + av_freep(&buffer); return AVERROR(ENOMEM); + } *p++ = 2; p += av_xiphlacing(p, hlens[0]); @@ -1312,7 +1314,6 @@ const FFCodec ff_vorbis_encoder = { .init = vorbis_encode_init, FF_CODEC_ENCODE_CB(vorbis_encode_frame), .close = vorbis_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index 1bee221bc..edb5594bd 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -35,6 +35,7 @@ #include #include +#include "libavutil/attributes.h" #include "libavutil/emms.h" #include "libavutil/imgutils.h" #include "libavutil/mem.h" @@ -49,7 +50,7 @@ #include "jpegquanttables.h" #include "mathops.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "videodsp.h" #include "vp3data.h" @@ -216,7 +217,6 @@ typedef struct Vp3DecodeContext { int qps[3]; int nqps; - int last_qps[3]; int superblock_count; int y_superblock_width; @@ -323,7 +323,7 @@ typedef struct Vp3DecodeContext { HuffTable huffman_table[5 * 16]; uint8_t filter_limit_values[64]; - DECLARE_ALIGNED(8, int, bounding_values_array)[256 + 2]; + DECLARE_ALIGNED(16, int, bounding_values_array)[256 + 4]; VP4Predictor * dc_pred_row; /* dc_pred_row[y_superblock_width * 4] */ } Vp3DecodeContext; @@ -348,7 +348,7 @@ static av_cold void free_tables(AVCodecContext *avctx) av_freep(&s->motion_val[1]); } -static void vp3_decode_flush(AVCodecContext *avctx) +static av_cold void vp3_decode_flush(AVCodecContext *avctx) { Vp3DecodeContext *s = avctx->priv_data; @@ -369,7 +369,7 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx) /* release all frames */ vp3_decode_flush(avctx); - ff_refstruct_unref(&s->coeff_vlc); + av_refstruct_unref(&s->coeff_vlc); return 0; } @@ -2029,7 +2029,7 @@ static int vp4_mc_loop_filter(Vp3DecodeContext *s, int plane, int motion_x, int plane_height); #define safe_loop_filter(name, ptr, stride, bounding_values) \ - if ((uintptr_t)(ptr) & 7) \ + if (VP3_LOOP_FILTER_NO_UNALIGNED_SUPPORT && (uintptr_t)(ptr) & 7) \ s->vp3dsp.name##_unaligned(ptr, stride, bounding_values); \ else \ s->vp3dsp.name(ptr, stride, bounding_values); @@ -2345,7 +2345,7 @@ static av_cold int allocate_tables(AVCodecContext *avctx) } -static av_cold void free_vlc_tables(FFRefStructOpaque unused, void *obj) +static av_cold void free_vlc_tables(AVRefStructOpaque unused, void *obj) { CoeffVLCs *vlcs = obj; @@ -2383,7 +2383,7 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) avctx->chroma_sample_location = AVCHROMA_LOC_CENTER; ff_hpeldsp_init(&s->hdsp, avctx->flags | AV_CODEC_FLAG_BITEXACT); ff_videodsp_init(&s->vdsp, 8); - ff_vp3dsp_init(&s->vp3dsp, avctx->flags); + ff_vp3dsp_init(&s->vp3dsp); for (int i = 0; i < 64; i++) { #define TRANSPOSE(x) (((x) >> 3) | (((x) & 7) << 3)) @@ -2458,7 +2458,7 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) } if (ff_thread_sync_ref(avctx, offsetof(Vp3DecodeContext, coeff_vlc)) != FF_THREAD_IS_COPY) { - CoeffVLCs *vlcs = ff_refstruct_alloc_ext(sizeof(*s->coeff_vlc), 0, + CoeffVLCs *vlcs = av_refstruct_alloc_ext(sizeof(*s->coeff_vlc), 0, NULL, free_vlc_tables); if (!vlcs) return AVERROR(ENOMEM); @@ -2499,25 +2499,11 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) return allocate_tables(avctx); } -/// Release and shuffle frames after decode finishes -static void update_frames(AVCodecContext *avctx) -{ - Vp3DecodeContext *s = avctx->priv_data; - - if (s->keyframe) - ff_progress_frame_replace(&s->golden_frame, &s->current_frame); - - /* shuffle frames */ - ff_progress_frame_unref(&s->last_frame); - FFSWAP(ProgressFrame, s->last_frame, s->current_frame); -} - #if HAVE_THREADS static void ref_frames(Vp3DecodeContext *dst, const Vp3DecodeContext *src) { ff_progress_frame_replace(&dst->current_frame, &src->current_frame); ff_progress_frame_replace(&dst->golden_frame, &src->golden_frame); - ff_progress_frame_replace(&dst->last_frame, &src->last_frame); } static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) @@ -2528,14 +2514,8 @@ static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext * // copy previous frame data ref_frames(s, s1); - if (!s1->current_frame.f || - s->width != s1->width || s->height != s1->height) { - return -1; - } if (s != s1) { - s->keyframe = s1->keyframe; - // copy qscale data if necessary for (int i = 0; i < 3; i++) { if (s->qps[i] != s1->qps[1]) { @@ -2550,12 +2530,9 @@ static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext * if (qps_changed) { memcpy(s->qps, s1->qps, sizeof(s->qps)); - memcpy(s->last_qps, s1->last_qps, sizeof(s->last_qps)); s->nqps = s1->nqps; } } - - update_frames(dst); return 0; } #endif @@ -2617,8 +2594,10 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame, } if (!s->theora) skip_bits(&gb, 1); + + int last_qps[3]; for (int i = 0; i < 3; i++) - s->last_qps[i] = s->qps[i]; + last_qps[i] = s->qps[i]; s->nqps = 0; do { @@ -2635,26 +2614,26 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame, avctx->skip_loop_filter >= (s->keyframe ? AVDISCARD_ALL : AVDISCARD_NONKEY); - if (s->qps[0] != s->last_qps[0]) + if (s->qps[0] != last_qps[0]) init_loop_filter(s); for (int i = 0; i < s->nqps; i++) // reinit all dequantizers if the first one changed, because // the DC of the first quantizer must be used for all matrices - if (s->qps[i] != s->last_qps[i] || s->qps[0] != s->last_qps[0]) + if (s->qps[i] != last_qps[i] || s->qps[0] != last_qps[0]) init_dequantizer(s, i); if (avctx->skip_frame >= AVDISCARD_NONKEY && !s->keyframe) return buf_size; - ff_progress_frame_unref(&s->current_frame); - ret = ff_progress_frame_get_buffer(avctx, &s->current_frame, + ret = ff_progress_frame_get_buffer(avctx, &s->last_frame, AV_GET_BUFFER_FLAG_REF); if (ret < 0) { // Don't goto error here, as one can't report progress on or // unref a non-existent frame. return ret; } + FFSWAP(ProgressFrame, s->last_frame, s->current_frame); s->current_frame.f->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; if (s->keyframe) @@ -2679,7 +2658,8 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame, #if !CONFIG_VP4_DECODER if (version >= 2) { av_log(avctx, AV_LOG_ERROR, "This build does not support decoding VP4.\n"); - return AVERROR_DECODER_NOT_FOUND; + ret = AVERROR_DECODER_NOT_FOUND; + goto error; } #endif s->version = version; @@ -2710,13 +2690,14 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame, mb_height_mul = get_bits(&gb, 5); mb_height_div = get_bits(&gb, 3); if (mb_width_mul != 1 || mb_width_div != 1 || mb_height_mul != 1 || mb_height_div != 1) - avpriv_request_sample(s->avctx, "unexpected macroblock dimension multipler/divider"); + avpriv_request_sample(s->avctx, "unexpected macroblock dimension multiplier/divider"); if (get_bits(&gb, 2)) avpriv_request_sample(s->avctx, "unknown bits"); } #endif } + ff_progress_frame_replace(&s->golden_frame, &s->current_frame); } else { if (!s->golden_frame.f) { av_log(s->avctx, AV_LOG_WARNING, @@ -2794,6 +2775,8 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame, } vp3_draw_horiz_band(s, s->height); + ff_progress_frame_unref(&s->last_frame); + /* output frame, offset as needed */ if ((ret = av_frame_ref(frame, s->current_frame.f)) < 0) return ret; @@ -2805,16 +2788,11 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame, *got_frame = 1; - if (!HAVE_THREADS || !(s->avctx->active_thread_type & FF_THREAD_FRAME)) - update_frames(avctx); - return buf_size; error: ff_progress_frame_report(&s->current_frame, INT_MAX); - - if (!HAVE_THREADS || !(s->avctx->active_thread_type & FF_THREAD_FRAME)) - av_frame_unref(s->current_frame.f); + ff_progress_frame_unref(&s->last_frame); return ret; } diff --git a/libavcodec/vp3_parser.c b/libavcodec/vp3_parser.c index 1bed43e77..1cd12b9e5 100644 --- a/libavcodec/vp3_parser.c +++ b/libavcodec/vp3_parser.c @@ -18,7 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "parser.h" +#include "avcodec.h" +#include "parser_internal.h" static int parse(AVCodecParserContext *s, AVCodecContext *avctx, @@ -35,10 +36,8 @@ static int parse(AVCodecParserContext *s, return buf_size; } -const AVCodecParser ff_vp3_parser = { - .codec_ids = { - AV_CODEC_ID_THEORA, AV_CODEC_ID_VP3, - AV_CODEC_ID_VP6, AV_CODEC_ID_VP6F, AV_CODEC_ID_VP6A - }, - .parser_parse = parse, +const FFCodecParser ff_vp3_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_THEORA, AV_CODEC_ID_VP3, + AV_CODEC_ID_VP6, AV_CODEC_ID_VP6F, AV_CODEC_ID_VP6A), + .parse = parse, }; diff --git a/libavcodec/vp3dsp.c b/libavcodec/vp3dsp.c index b4621f07e..025ad0423 100644 --- a/libavcodec/vp3dsp.c +++ b/libavcodec/vp3dsp.c @@ -445,7 +445,7 @@ static void put_no_rnd_pixels_l2(uint8_t *dst, const uint8_t *src1, } } -av_cold void ff_vp3dsp_init(VP3DSPContext *c, int flags) +av_cold void ff_vp3dsp_init(VP3DSPContext *c) { c->put_no_rnd_pixels_l2 = put_no_rnd_pixels_l2; @@ -456,13 +456,13 @@ av_cold void ff_vp3dsp_init(VP3DSPContext *c, int flags) c->h_loop_filter = c->h_loop_filter_unaligned = vp3_h_loop_filter_8_c; #if ARCH_ARM - ff_vp3dsp_init_arm(c, flags); + ff_vp3dsp_init_arm(c); #elif ARCH_PPC - ff_vp3dsp_init_ppc(c, flags); -#elif ARCH_X86 - ff_vp3dsp_init_x86(c, flags); + ff_vp3dsp_init_ppc(c); +#elif ARCH_X86 && HAVE_X86ASM + ff_vp3dsp_init_x86(c); #elif ARCH_MIPS - ff_vp3dsp_init_mips(c, flags); + ff_vp3dsp_init_mips(c); #endif } @@ -494,5 +494,10 @@ void ff_vp3dsp_set_bounding_values(int * bounding_values_array, int filter_limit } if (value) bounding_values[128] = value; +#if ARCH_X86 + bounding_values[129] = bounding_values[130] = + bounding_values[131] = bounding_values[132] = filter_limit * 0x00020002U; +#else bounding_values[129] = bounding_values[130] = filter_limit * 0x02020202U; +#endif } diff --git a/libavcodec/vp3dsp.h b/libavcodec/vp3dsp.h index 3b849ec05..751267637 100644 --- a/libavcodec/vp3dsp.h +++ b/libavcodec/vp3dsp.h @@ -22,6 +22,10 @@ #include #include +// If this is one, {v,h}_loop_filter expect src to be aligned on eight bytes; +// otherwise they don't have any alignment requirements for src. +#define VP3_LOOP_FILTER_NO_UNALIGNED_SUPPORT (ARCH_ARM || ARCH_MIPS) + typedef struct VP3DSPContext { /** * Copy 8xH pixels from source to destination buffer using a bilinear @@ -53,11 +57,11 @@ void ff_vp3dsp_h_loop_filter_12(uint8_t *first_pixel, ptrdiff_t stride, int *bou void ff_vp3dsp_idct10_put(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vp3dsp_idct10_add(uint8_t *dest, ptrdiff_t stride, int16_t *block); -void ff_vp3dsp_init(VP3DSPContext *c, int flags); -void ff_vp3dsp_init_arm(VP3DSPContext *c, int flags); -void ff_vp3dsp_init_ppc(VP3DSPContext *c, int flags); -void ff_vp3dsp_init_x86(VP3DSPContext *c, int flags); -void ff_vp3dsp_init_mips(VP3DSPContext *c, int flags); +void ff_vp3dsp_init(VP3DSPContext *c); +void ff_vp3dsp_init_arm(VP3DSPContext *c); +void ff_vp3dsp_init_ppc(VP3DSPContext *c); +void ff_vp3dsp_init_x86(VP3DSPContext *c); +void ff_vp3dsp_init_mips(VP3DSPContext *c); void ff_vp3dsp_set_bounding_values(int * bound_values_array, int filter_limit); diff --git a/libavcodec/vp5.c b/libavcodec/vp5.c index 78d4b38ce..98b8cf41f 100644 --- a/libavcodec/vp5.c +++ b/libavcodec/vp5.c @@ -58,10 +58,7 @@ static int vp5_parse_header(VP56Context *s, const uint8_t *buf, int buf_size) if(vp56_rac_gets(c, 5) > 5) return AVERROR_INVALIDDATA; vp56_rac_gets(c, 2); - if (vpx_rac_get(c)) { - avpriv_report_missing_feature(s->avctx, "Interlacing"); - return AVERROR_PATCHWELCOME; - } + s->interlaced = vp56_rac_gets(c, 1); rows = vp56_rac_gets(c, 8); /* number of stored macroblock rows */ cols = vp56_rac_gets(c, 8); /* number of stored macroblock cols */ if (!rows || !cols) { @@ -288,7 +285,7 @@ static av_cold int vp5_decode_init(AVCodecContext *avctx) if ((ret = ff_vp56_init_context(avctx, s, 1, 0)) < 0) return ret; - ff_vp5dsp_init(&s->vp56dsp); + ff_vp5dsp_init(&s->vp5dsp); s->vp56_coord_div = vp5_coord_div; s->parse_vector_adjustment = vp5_parse_vector_adjustment; s->parse_coeff = vp5_parse_coeff; diff --git a/libavcodec/vp56.c b/libavcodec/vp56.c index 1da47ca43..0d13d7a27 100644 --- a/libavcodec/vp56.c +++ b/libavcodec/vp56.c @@ -325,9 +325,9 @@ static void vp56_deblock_filter(VP56Context *s, uint8_t *yuv, ptrdiff_t stride, int dx, int dy) { if (s->avctx->codec->id == AV_CODEC_ID_VP5) { - int t = ff_vp56_filter_threshold[s->quantizer]; - if (dx) s->vp56dsp.edge_filter_hor(yuv + 10-dx , stride, t); - if (dy) s->vp56dsp.edge_filter_ver(yuv + stride*(10-dy), stride, t); + int t = ff_vp56_filter_threshold[s->quantizer]; + if (dx) s->vp5dsp.edge_filter_hor(yuv + 10-dx , stride, t); + if (dy) s->vp5dsp.edge_filter_ver(yuv + stride*(10-dy), stride, t); } else { int * bounding_values = s->bounding_values_array + 127; if (dx) @@ -338,7 +338,7 @@ static void vp56_deblock_filter(VP56Context *s, uint8_t *yuv, } static void vp56_mc(VP56Context *s, int b, int plane, uint8_t *src, - ptrdiff_t stride, int x, int y) + ptrdiff_t stride, int x, int y, ptrdiff_t ref_stride) { uint8_t *dst = s->frames[VP56_FRAME_CURRENT]->data[plane] + s->block_offset[b]; uint8_t *src_block; @@ -364,7 +364,17 @@ static void vp56_mc(VP56Context *s, int b, int plane, uint8_t *src, x += dx - 2; y += dy - 2; - if (x<0 || x+12>=s->plane_width[plane] || + if (s->interlaced && s->il_block) { + /* extract 12*(4+16+4) block from frame (containing both fields), then treat src_block as specific field */ + s->vdsp.emulated_edge_mc(s->edge_emu_buffer, + src + s->block_offset[b] + (dy-4)*ref_stride + (dx-2), + ref_stride, ref_stride, + 12, 24, x, y - 2, + s->plane_width[plane], + s->plane_height[plane]); + src_block = s->edge_emu_buffer; + src_offset = 2 + 4*ref_stride; + } else if (x<0 || x+12>=s->plane_width[plane] || y<0 || y+12>=s->plane_height[plane]) { s->vdsp.emulated_edge_mc(s->edge_emu_buffer, src + s->block_offset[b] + (dy-2)*stride + (dx-2), @@ -431,6 +441,7 @@ static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, in int b, ab, b_max, plane, off; AVFrame *frame_current, *frame_ref; VP56Frame ref_frame = ff_vp56_reference_frame[mb_type]; + ptrdiff_t ref_stride[4]; vp56_add_predictors_dc(s, ref_frame); @@ -439,6 +450,13 @@ static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, in if (mb_type != VP56_MB_INTRA && !frame_ref->data[0]) return; + memcpy(ref_stride, s->stride, sizeof(s->stride)); + if (s->interlaced && s->il_block) { + s->block_offset[2] -= s->stride[0] * 7; + s->block_offset[3] -= s->stride[0] * 7; + s->stride[0] *= 2; + } + ab = 6*is_alpha; b_max = 6 - 2*is_alpha; @@ -473,10 +491,10 @@ static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, in case VP56_MB_INTER_V2_GF: for (b=0; binterlaced && s->il_block ? 1 : 8) : 0; plane = ff_vp56_b2p[b+ab]; vp56_mc(s, b, plane, frame_ref->data[plane], s->stride[plane], - 16*col+x_off, 16*row+y_off); + 16*col+x_off, 16*row+y_off, ref_stride[plane]); vp56_idct_add(s, frame_current->data[plane] + s->block_offset[b], s->stride[plane], s->block_coeff[b], s->idct_selector[b]); } @@ -487,6 +505,12 @@ static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, in s->block_coeff[4][0] = 0; s->block_coeff[5][0] = 0; } + + if (s->interlaced && s->il_block) { + s->stride[0] /= 2; + s->block_offset[2] += s->stride[0] * 7; + s->block_offset[3] += s->stride[0] * 7; + } } static int vp56_decode_mb(VP56Context *s, int row, int col, int is_alpha) @@ -494,6 +518,19 @@ static int vp56_decode_mb(VP56Context *s, int row, int col, int is_alpha) VP56mb mb_type; int ret; + if (s->interlaced) { + int prob = s->il_prob; + + if (col > 0) { + if (s->il_block) + prob -= prob >> 1; + else + prob += (256 - prob) >> 1; /* can be simplified/combined */ + } + + s->il_block = vpx_rac_get_prob(&s->c, prob); + } + if (s->frames[VP56_FRAME_CURRENT]->flags & AV_FRAME_FLAG_KEY) mb_type = VP56_MB_INTRA; else @@ -552,12 +589,12 @@ static int vp56_size_changed(VP56Context *s) av_reallocp_array(&s->macroblocks, s->mb_width*s->mb_height, sizeof(*s->macroblocks)); av_free(s->edge_emu_buffer_alloc); - s->edge_emu_buffer_alloc = av_malloc(16*stride); + s->edge_emu_buffer_alloc = av_malloc(16*stride*2); s->edge_emu_buffer = s->edge_emu_buffer_alloc; if (!s->above_blocks || !s->macroblocks || !s->edge_emu_buffer_alloc) return AVERROR(ENOMEM); if (s->flip < 0) - s->edge_emu_buffer += 15 * stride; + s->edge_emu_buffer += 15 * stride * 2; if (s->alpha_context) return vp56_size_changed(s->alpha_context); @@ -686,6 +723,11 @@ static int ff_vp56_decode_mbs(AVCodecContext *avctx, void *data, if (s->parse_coeff_models(s)) goto next; + if (s->interlaced) { + s->frames[VP56_FRAME_CURRENT]->flags |= AV_FRAME_FLAG_INTERLACED; + s->il_prob = vp56_rac_gets(&s->c, 8); + } + memset(s->prev_dc, 0, sizeof(s->prev_dc)); s->prev_dc[1][VP56_FRAME_CURRENT] = 128; s->prev_dc[2][VP56_FRAME_CURRENT] = 128; @@ -786,7 +828,7 @@ av_cold int ff_vp56_init_context(AVCodecContext *avctx, VP56Context *s, ff_h264chroma_init(&s->h264chroma, 8); ff_hpeldsp_init(&s->hdsp, avctx->flags); ff_videodsp_init(&s->vdsp, 8); - ff_vp3dsp_init(&s->vp3dsp, avctx->flags); + ff_vp3dsp_init(&s->vp3dsp); for (i = 0; i < 64; i++) { #define TRANSPOSE(x) (((x) >> 3) | (((x) & 7) << 3)) s->idct_scantable[i] = TRANSPOSE(ff_zigzag_direct[i]); diff --git a/libavcodec/vp56.h b/libavcodec/vp56.h index 9dc0b9c7a..6610fc289 100644 --- a/libavcodec/vp56.h +++ b/libavcodec/vp56.h @@ -118,7 +118,10 @@ struct vp56_context { HpelDSPContext hdsp; VideoDSPContext vdsp; VP3DSPContext vp3dsp; - VP56DSPContext vp56dsp; + union { + VP5DSPContext vp5dsp; + VP6DSPContext vp6dsp; + }; uint8_t idct_scantable[64]; AVFrame *frames[4]; uint8_t *edge_emu_buffer_alloc; @@ -151,6 +154,7 @@ struct vp56_context { VP56Macroblock *macroblocks; DECLARE_ALIGNED(16, int16_t, block_coeff)[6][64]; int idct_selector[6]; + const uint8_t *def_coeff_reorder;/* used in vp6 only */ /* motion vectors */ VP56mv mv[6]; /* vectors for each block in MB */ @@ -171,6 +175,11 @@ struct vp56_context { int has_alpha; + /* interlacing params */ + int interlaced; + int il_prob; + int il_block; + /* upside-down flipping hints */ int flip; /* are we flipping ? */ int frbi; /* first row block index in MB */ @@ -197,7 +206,7 @@ struct vp56_context { GetBitContext gb; VLC dccv_vlc[2]; VLC runv_vlc[2]; - VLC ract_vlc[2][3][6]; + VLC ract_vlc[2][3][4]; unsigned int nb_null[2][2]; /* number of consecutive NULL DC/AC */ int have_undamaged_frame; @@ -233,7 +242,7 @@ static int vp56_rac_gets(VPXRangeCoder *c, int bits) } // P(7) -static av_unused int vp56_rac_gets_nn(VPXRangeCoder *c, int bits) +av_unused static int vp56_rac_gets_nn(VPXRangeCoder *c, int bits) { int v = vp56_rac_gets(c, 7) << 1; return v + !v; diff --git a/libavcodec/vp56dsp.h b/libavcodec/vp56dsp.h index e35e232ea..3981de401 100644 --- a/libavcodec/vp56dsp.h +++ b/libavcodec/vp56dsp.h @@ -24,21 +24,19 @@ #include #include -typedef struct VP56DSPContext { +typedef struct VP5DSPContext { void (*edge_filter_hor)(uint8_t *yuv, ptrdiff_t stride, int t); void (*edge_filter_ver)(uint8_t *yuv, ptrdiff_t stride, int t); +} VP5DSPContext; - void (*vp6_filter_diag4)(uint8_t *dst, uint8_t *src, ptrdiff_t stride, +typedef struct VP6DSPContext { + void (*vp6_filter_diag4)(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, const int16_t *h_weights,const int16_t *v_weights); -} VP56DSPContext; +} VP6DSPContext; -void ff_vp6_filter_diag4_c(uint8_t *dst, uint8_t *src, ptrdiff_t stride, - const int16_t *h_weights, const int16_t *v_weights); +void ff_vp5dsp_init(VP5DSPContext *s); -void ff_vp5dsp_init(VP56DSPContext *s); -void ff_vp6dsp_init(VP56DSPContext *s); - -void ff_vp6dsp_init_arm(VP56DSPContext *s); -void ff_vp6dsp_init_x86(VP56DSPContext *s); +void ff_vp6dsp_init(VP6DSPContext *s); +void ff_vp6dsp_init_x86(VP6DSPContext *s); #endif /* AVCODEC_VP56DSP_H */ diff --git a/libavcodec/vp56dsp.c b/libavcodec/vp5dsp.c similarity index 86% rename from libavcodec/vp56dsp.c rename to libavcodec/vp5dsp.c index a66871238..a06c2cfd5 100644 --- a/libavcodec/vp56dsp.c +++ b/libavcodec/vp5dsp.c @@ -21,8 +21,6 @@ #include -#include "config.h" -#include "config_components.h" #include "libavutil/attributes.h" #include "vp56dsp.h" #include "libavutil/common.h" @@ -43,7 +41,6 @@ static void pfx ## _edge_filter_ ## suf(uint8_t *yuv, ptrdiff_t stride, \ } \ } -#if CONFIG_VP5_DECODER /* Gives very similar result than the vp6 version except in a few cases */ static int vp5_adjust(int v, int t) { @@ -65,22 +62,8 @@ static int vp5_adjust(int v, int t) VP56_EDGE_FILTER(vp5, hor, 1, stride) VP56_EDGE_FILTER(vp5, ver, stride, 1) -av_cold void ff_vp5dsp_init(VP56DSPContext *s) +av_cold void ff_vp5dsp_init(VP5DSPContext *s) { s->edge_filter_hor = vp5_edge_filter_hor; s->edge_filter_ver = vp5_edge_filter_ver; } -#endif /* CONFIG_VP5_DECODER */ - -#if CONFIG_VP6_DECODER -av_cold void ff_vp6dsp_init(VP56DSPContext *s) -{ - s->vp6_filter_diag4 = ff_vp6_filter_diag4_c; - -#if ARCH_ARM - ff_vp6dsp_init_arm(s); -#elif ARCH_X86 - ff_vp6dsp_init_x86(s); -#endif -} -#endif /* CONFIG_VP6_DECODER */ diff --git a/libavcodec/vp6.c b/libavcodec/vp6.c index 97d63a587..3f4bd42d0 100644 --- a/libavcodec/vp6.c +++ b/libavcodec/vp6.c @@ -41,6 +41,8 @@ #include "vpx_rac.h" #define VP6_MAX_HUFF_SIZE 12 +#define AC_DC_HUFF_BITS 10 +#define RUN_HUFF_BITS 8 static int vp6_parse_coeff(VP56Context *s); static int vp6_parse_coeff_huffman(VP56Context *s); @@ -68,10 +70,11 @@ static int vp6_parse_header(VP56Context *s, const uint8_t *buf, int buf_size) if (sub_version > 8) return AVERROR_INVALIDDATA; s->filter_header = buf[1] & 0x06; - if (buf[1] & 1) { - avpriv_report_missing_feature(s->avctx, "Interlacing"); - return AVERROR_PATCHWELCOME; - } + s->interlaced = buf[1] & 1; + if (s->interlaced) + s->def_coeff_reorder = vp6_il_coeff_reorder; + else + s->def_coeff_reorder = vp6_def_coeff_reorder; if (separated_coeff || !s->filter_header) { coeff_offset = AV_RB16(buf+2) - 2; buf += 2; @@ -228,7 +231,7 @@ static void vp6_default_models_init(VP56Context *s) memcpy(model->vector_fdv, vp6_def_fdv_vector_model, sizeof(model->vector_fdv)); memcpy(model->vector_pdv, vp6_def_pdv_vector_model, sizeof(model->vector_pdv)); memcpy(model->coeff_runv, vp6_def_runv_coeff_model, sizeof(model->coeff_runv)); - memcpy(model->coeff_reorder, vp6_def_coeff_reorder, sizeof(model->coeff_reorder)); + memcpy(model->coeff_reorder, s->def_coeff_reorder, sizeof(model->coeff_reorder)); vp6_coeff_order_table_init(s); } @@ -265,7 +268,8 @@ static int vp6_huff_cmp(const void *va, const void *vb) } static int vp6_build_huff_tree(VP56Context *s, uint8_t coeff_model[], - const uint8_t *map, unsigned size, VLC *vlc) + const uint8_t *map, unsigned size, + int nb_bits, VLC *vlc) { Node nodes[2*VP6_MAX_HUFF_SIZE], *tmp = &nodes[size]; int a, b, i; @@ -281,7 +285,7 @@ static int vp6_build_huff_tree(VP56Context *s, uint8_t coeff_model[], ff_vlc_free(vlc); /* then build the huffman tree according to probabilities */ - return ff_huff_build_tree(s->avctx, vlc, size, FF_HUFFMAN_BITS, + return ff_huff_build_tree(s->avctx, vlc, size, nb_bits, nodes, vp6_huff_cmp, FF_HUFFMAN_FLAG_HNODE_FIRST); } @@ -294,6 +298,7 @@ static int vp6_parse_coeff_models(VP56Context *s) int node, cg, ctx, pos; int ct; /* code type */ int pt; /* plane type (0 for Y, 1 for U or V) */ + int ret; memset(def_prob, 0x80, sizeof(def_prob)); @@ -331,18 +336,25 @@ static int vp6_parse_coeff_models(VP56Context *s) if (s->use_huffman) { for (pt=0; pt<2; pt++) { - if (vp6_build_huff_tree(s, model->coeff_dccv[pt], - vp6_huff_coeff_map, 12, &s->dccv_vlc[pt])) - return -1; - if (vp6_build_huff_tree(s, model->coeff_runv[pt], - vp6_huff_run_map, 9, &s->runv_vlc[pt])) - return -1; + ret = vp6_build_huff_tree(s, model->coeff_dccv[pt], + vp6_huff_coeff_map, 12, AC_DC_HUFF_BITS, + &s->dccv_vlc[pt]); + if (ret < 0) + return ret; + ret = vp6_build_huff_tree(s, model->coeff_runv[pt], + vp6_huff_run_map, 9, RUN_HUFF_BITS, + &s->runv_vlc[pt]); + if (ret < 0) + return ret; for (ct=0; ct<3; ct++) - for (cg = 0; cg < 6; cg++) - if (vp6_build_huff_tree(s, model->coeff_ract[pt][ct][cg], - vp6_huff_coeff_map, 12, - &s->ract_vlc[pt][ct][cg])) - return -1; + for (int cg = 0; cg < 4; cg++) { + ret = vp6_build_huff_tree(s, model->coeff_ract[pt][ct][cg], + vp6_huff_coeff_map, 12, + AC_DC_HUFF_BITS, + &s->ract_vlc[pt][ct][cg]); + if (ret < 0) + return ret; + } } memset(s->nb_null, 0, sizeof(s->nb_null)); } else { @@ -414,7 +426,7 @@ static int vp6_parse_coeff_huffman(VP56Context *s) VP56Model *model = s->modelp; uint8_t *permute = s->idct_scantable; VLC *vlc_coeff; - int coeff, sign, coeff_idx; + int sign, coeff_idx; int b, cg, idx; int pt = 0; /* plane type (0 for Y, 1 for U or V) */ @@ -432,11 +444,11 @@ static int vp6_parse_coeff_huffman(VP56Context *s) } else { if (get_bits_left(&s->gb) <= 0) return AVERROR_INVALIDDATA; - coeff = get_vlc2(&s->gb, vlc_coeff->table, FF_HUFFMAN_BITS, 3); + int coeff = get_vlc2(&s->gb, vlc_coeff->table, AC_DC_HUFF_BITS, 2); if (coeff == 0) { if (coeff_idx) { int pt = (coeff_idx >= 6); - run += get_vlc2(&s->gb, s->runv_vlc[pt].table, FF_HUFFMAN_BITS, 3); + run += get_vlc2(&s->gb, s->runv_vlc[pt].table, RUN_HUFF_BITS, 1); if (run >= 9) run += get_bits(&s->gb, 6); } else @@ -629,7 +641,7 @@ static void vp6_filter(VP56Context *s, uint8_t *dst, uint8_t *src, vp6_filter_hv4(dst, src+offset1, stride, stride, vp6_block_copy_filter[select][y8]); } else { - s->vp56dsp.vp6_filter_diag4(dst, src+offset1+((mv.x^mv.y)>>31), stride, + s->vp6dsp.vp6_filter_diag4(dst, src+offset1+((mv.x^mv.y)>>31), stride, vp6_block_copy_filter[select][x8], vp6_block_copy_filter[select][y8]); } @@ -649,7 +661,7 @@ static av_cold int vp6_decode_init_context(AVCodecContext *avctx, if (ret < 0) return ret; - ff_vp6dsp_init(&s->vp56dsp); + ff_vp6dsp_init(&s->vp6dsp); s->deblock_filtering = 0; s->vp56_coord_div = vp6_coord_div; @@ -703,15 +715,13 @@ static av_cold int vp6_decode_free(AVCodecContext *avctx) static av_cold void vp6_decode_free_context(VP56Context *s) { - int pt, ct, cg; - ff_vp56_free_context(s); - for (pt=0; pt<2; pt++) { + for (int pt = 0; pt < 2; ++pt) { ff_vlc_free(&s->dccv_vlc[pt]); ff_vlc_free(&s->runv_vlc[pt]); - for (ct=0; ct<3; ct++) - for (cg=0; cg<6; cg++) + for (int ct = 0; ct < 3; ++ct) + for (int cg = 0; cg < 4; ++cg) ff_vlc_free(&s->ract_vlc[pt][ct][cg]); } } diff --git a/libavcodec/vp6data.h b/libavcodec/vp6data.h index 539e19a62..be6e86919 100644 --- a/libavcodec/vp6data.h +++ b/libavcodec/vp6data.h @@ -51,6 +51,17 @@ static const uint8_t vp6_def_coeff_reorder[] = { 14, 14, 15, 15, 15, 15, 15, 15, }; +static const uint8_t vp6_il_coeff_reorder[] = { + 0, 1, 0, 1, 1, 2, 5, 3, + 2, 2, 2, 2, 4, 7, 8, 10, + 9, 7, 5, 4, 2, 3, 5, 6, + 8, 9, 11, 12, 13, 12, 11, 10, + 9, 7, 5, 4, 6, 7, 9, 11, + 12, 12, 13, 13, 14, 12, 11, 9, + 7, 9, 11, 12, 14, 14, 14, 15, + 13, 11, 13, 15, 15, 15, 15, 15, +}; + static const uint8_t vp6_def_runv_coeff_model[2][14] = { { 198, 197, 196, 146, 198, 204, 169, 142, 130, 136, 149, 149, 191, 249 }, { 135, 201, 181, 154, 98, 117, 132, 126, 146, 169, 184, 240, 246, 254 }, diff --git a/libavcodec/vp6dsp.c b/libavcodec/vp6dsp.c index f7f685633..e12a7ed2a 100644 --- a/libavcodec/vp6dsp.c +++ b/libavcodec/vp6dsp.c @@ -27,8 +27,8 @@ #include "vp56dsp.h" -void ff_vp6_filter_diag4_c(uint8_t *dst, uint8_t *src, ptrdiff_t stride, - const int16_t *h_weights, const int16_t *v_weights) +static void vp6_filter_diag4_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, + const int16_t *h_weights, const int16_t *v_weights) { int x, y; int tmp[8*11]; @@ -59,3 +59,12 @@ void ff_vp6_filter_diag4_c(uint8_t *dst, uint8_t *src, ptrdiff_t stride, t += 8; } } + +av_cold void ff_vp6dsp_init(VP6DSPContext *s) +{ + s->vp6_filter_diag4 = vp6_filter_diag4_c; + +#if ARCH_X86 && HAVE_X86ASM + ff_vp6dsp_init_x86(s); +#endif +} diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c index d6df01865..9010e19e6 100644 --- a/libavcodec/vp8.c +++ b/libavcodec/vp8.c @@ -36,7 +36,7 @@ #include "hwconfig.h" #include "mathops.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "vp8.h" #include "vp89_rac.h" @@ -107,7 +107,7 @@ static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int ref) ref ? AV_GET_BUFFER_FLAG_REF : 0); if (ret < 0) return ret; - f->seg_map = ff_refstruct_allocz(s->mb_width * s->mb_height); + f->seg_map = av_refstruct_allocz(s->mb_width * s->mb_height); if (!f->seg_map) { ret = AVERROR(ENOMEM); goto fail; @@ -119,15 +119,15 @@ static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int ref) return 0; fail: - ff_refstruct_unref(&f->seg_map); + av_refstruct_unref(&f->seg_map); ff_progress_frame_unref(&f->tf); return ret; } static void vp8_release_frame(VP8Frame *f) { - ff_refstruct_unref(&f->seg_map); - ff_refstruct_unref(&f->hwaccel_picture_private); + av_refstruct_unref(&f->seg_map); + av_refstruct_unref(&f->hwaccel_picture_private); ff_progress_frame_unref(&f->tf); } @@ -541,9 +541,12 @@ static int vp7_fade_frame(VP8Context *s, int alpha, int beta) /* preserve the golden frame, write a new previous frame */ if (s->framep[VP8_FRAME_GOLDEN] == s->framep[VP8_FRAME_PREVIOUS]) { - s->framep[VP8_FRAME_PREVIOUS] = vp8_find_free_buffer(s); - if ((ret = vp8_alloc_frame(s, s->framep[VP8_FRAME_PREVIOUS], 1)) < 0) + VP8Frame *prev_frame = vp8_find_free_buffer(s); + + ret = vp8_alloc_frame(s, prev_frame, 1); + if (ret < 0) return ret; + s->framep[VP8_FRAME_PREVIOUS] = prev_frame; dst = s->framep[VP8_FRAME_PREVIOUS]->tf.f; @@ -730,7 +733,7 @@ static int vp8_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si int height = s->avctx->height; if (buf_size < 3) { - av_log(s->avctx, AV_LOG_ERROR, "Insufficent data (%d) for header\n", buf_size); + av_log(s->avctx, AV_LOG_ERROR, "Insufficient data (%d) for header\n", buf_size); return AVERROR_INVALIDDATA; } @@ -2413,7 +2416,7 @@ static av_always_inline int decode_mb_row_no_filter(AVCodecContext *avctx, void mb = s->macroblocks_base + ((s->mb_width + 1) * (mb_y + 1) + 1); else { // Make sure the previous frame has read its segmentation map, - // if we re-use the same map. + // if we reuse the same map. if (prev_frame && s->segmentation.enabled && !s->segmentation.update_map) ff_progress_frame_await(&prev_frame->tf, mb_y); @@ -2512,18 +2515,6 @@ static av_always_inline int decode_mb_row_no_filter(AVCodecContext *avctx, void return 0; } -static int vp7_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata, - int jobnr, int threadnr) -{ - return decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr, 1); -} - -static int vp8_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata, - int jobnr, int threadnr) -{ - return decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr, 0); -} - static av_always_inline void filter_mb_row(AVCodecContext *avctx, void *tdata, int jobnr, int threadnr, int is_vp7) { @@ -2531,7 +2522,6 @@ static av_always_inline void filter_mb_row(AVCodecContext *avctx, void *tdata, VP8ThreadData *td = &s->thread_data[threadnr]; int mb_x, mb_y = atomic_load(&td->thread_mb_pos) >> 16, num_jobs = s->num_jobs; AVFrame *curframe = s->curframe->tf.f; - VP8Macroblock *mb; VP8ThreadData *prev_td, *next_td; uint8_t *dst[3] = { curframe->data[0] + 16 * mb_y * s->linesize, @@ -2539,11 +2529,6 @@ static av_always_inline void filter_mb_row(AVCodecContext *avctx, void *tdata, curframe->data[2] + 8 * mb_y * s->uvlinesize }; - if (s->mb_layout == 1) - mb = s->macroblocks_base + ((s->mb_width + 1) * (mb_y + 1) + 1); - else - mb = s->macroblocks + (s->mb_height - mb_y - 1) * 2; - if (mb_y == 0) prev_td = td; else @@ -2553,7 +2538,7 @@ static av_always_inline void filter_mb_row(AVCodecContext *avctx, void *tdata, else next_td = &s->thread_data[(jobnr + 1) % num_jobs]; - for (mb_x = 0; mb_x < s->mb_width; mb_x++, mb++) { + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { const VP8FilterStrength *f = &td->filter_strength[mb_x]; if (prev_td != td) check_thread_pos(td, prev_td, @@ -2583,18 +2568,6 @@ static av_always_inline void filter_mb_row(AVCodecContext *avctx, void *tdata, } } -static void vp7_filter_mb_row(AVCodecContext *avctx, void *tdata, - int jobnr, int threadnr) -{ - filter_mb_row(avctx, tdata, jobnr, threadnr, 1); -} - -static void vp8_filter_mb_row(AVCodecContext *avctx, void *tdata, - int jobnr, int threadnr) -{ - filter_mb_row(avctx, tdata, jobnr, threadnr, 0); -} - static av_always_inline int vp78_decode_mb_row_sliced(AVCodecContext *avctx, void *tdata, int jobnr, int threadnr, int is_vp7) @@ -2699,8 +2672,6 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, &s->frames[i] != s->framep[VP8_FRAME_ALTREF]) vp8_release_frame(&s->frames[i]); - curframe = s->framep[VP8_FRAME_CURRENT] = vp8_find_free_buffer(s); - if (!s->colorspace) avctx->colorspace = AVCOL_SPC_BT470BG; if (s->fullrange) @@ -2721,8 +2692,10 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, goto err; } + curframe = vp8_find_free_buffer(s); if ((ret = vp8_alloc_frame(s, curframe, referenced)) < 0) goto err; + s->framep[VP8_FRAME_CURRENT] = curframe; if (s->keyframe) curframe->tf.f->flags |= AV_FRAME_FLAG_KEY; else @@ -2751,9 +2724,9 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, if (!is_vp7 && !s->actually_webp) ff_thread_finish_setup(avctx); - if (avctx->hwaccel) { + if (!is_vp7 && avctx->hwaccel) { const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel); - ret = hwaccel->start_frame(avctx, avpkt->data, avpkt->size); + ret = hwaccel->start_frame(avctx, avpkt->buf, avpkt->data, avpkt->size); if (ret < 0) goto err; @@ -2782,7 +2755,7 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, if (s->mb_layout == 1) { // Make sure the previous frame has read its segmentation map, - // if we re-use the same map. + // if we reuse the same map. if (prev_frame && s->segmentation.enabled && !s->segmentation.update_map) ff_progress_frame_await(&prev_frame->tf, 1); @@ -2837,20 +2810,6 @@ err: return ret; } -int ff_vp8_decode_frame(AVCodecContext *avctx, AVFrame *frame, - int *got_frame, AVPacket *avpkt) -{ - return vp78_decode_frame(avctx, frame, got_frame, avpkt, IS_VP8); -} - -#if CONFIG_VP7_DECODER -static int vp7_decode_frame(AVCodecContext *avctx, AVFrame *frame, - int *got_frame, AVPacket *avpkt) -{ - return vp78_decode_frame(avctx, frame, got_frame, avpkt, IS_VP7); -} -#endif /* CONFIG_VP7_DECODER */ - av_cold int ff_vp8_decode_free(AVCodecContext *avctx) { vp8_decode_flush_impl(avctx, 1); @@ -2858,8 +2817,7 @@ av_cold int ff_vp8_decode_free(AVCodecContext *avctx) return 0; } -static av_always_inline -int vp78_decode_init(AVCodecContext *avctx, int is_vp7) +static av_cold void vp78_decode_init(AVCodecContext *avctx) { VP8Context *s = avctx->priv_data; @@ -2870,43 +2828,49 @@ int vp78_decode_init(AVCodecContext *avctx, int is_vp7) ff_videodsp_init(&s->vdsp, 8); ff_vp78dsp_init(&s->vp8dsp); - if (CONFIG_VP7_DECODER && is_vp7) { - ff_h264_pred_init(&s->hpc, AV_CODEC_ID_VP7, 8, 1); - ff_vp7dsp_init(&s->vp8dsp); - s->decode_mb_row_no_filter = vp7_decode_mb_row_no_filter; - s->filter_mb_row = vp7_filter_mb_row; - } else if (CONFIG_VP8_DECODER && !is_vp7) { - ff_h264_pred_init(&s->hpc, AV_CODEC_ID_VP8, 8, 1); - ff_vp8dsp_init(&s->vp8dsp); - s->decode_mb_row_no_filter = vp8_decode_mb_row_no_filter; - s->filter_mb_row = vp8_filter_mb_row; - } /* does not change for VP8 */ memcpy(s->prob[0].scan, ff_zigzag_scan, sizeof(s->prob[0].scan)); +} + +#if CONFIG_VP8_DECODER +static int vp8_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata, + int jobnr, int threadnr) +{ + return decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr, 0); +} + +static void vp8_filter_mb_row(AVCodecContext *avctx, void *tdata, + int jobnr, int threadnr) +{ + filter_mb_row(avctx, tdata, jobnr, threadnr, 0); +} + +int ff_vp8_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame, AVPacket *avpkt) +{ + return vp78_decode_frame(avctx, frame, got_frame, avpkt, IS_VP8); +} + +av_cold int ff_vp8_decode_init(AVCodecContext *avctx) +{ + VP8Context *s = avctx->priv_data; + + vp78_decode_init(avctx); + ff_h264_pred_init(&s->hpc, AV_CODEC_ID_VP8, 8, 1); + ff_vp8dsp_init(&s->vp8dsp); + s->decode_mb_row_no_filter = vp8_decode_mb_row_no_filter; + s->filter_mb_row = vp8_filter_mb_row; return 0; } -#if CONFIG_VP7_DECODER -static int vp7_decode_init(AVCodecContext *avctx) -{ - return vp78_decode_init(avctx, IS_VP7); -} -#endif /* CONFIG_VP7_DECODER */ - -av_cold int ff_vp8_decode_init(AVCodecContext *avctx) -{ - return vp78_decode_init(avctx, IS_VP8); -} - -#if CONFIG_VP8_DECODER #if HAVE_THREADS static void vp8_replace_frame(VP8Frame *dst, const VP8Frame *src) { ff_progress_frame_replace(&dst->tf, &src->tf); - ff_refstruct_replace(&dst->seg_map, src->seg_map); - ff_refstruct_replace(&dst->hwaccel_picture_private, + av_refstruct_replace(&dst->seg_map, src->seg_map); + av_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); } @@ -2944,6 +2908,37 @@ static int vp8_decode_update_thread_context(AVCodecContext *dst, #endif /* CONFIG_VP8_DECODER */ #if CONFIG_VP7_DECODER +static int vp7_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata, + int jobnr, int threadnr) +{ + return decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr, 1); +} + +static void vp7_filter_mb_row(AVCodecContext *avctx, void *tdata, + int jobnr, int threadnr) +{ + filter_mb_row(avctx, tdata, jobnr, threadnr, 1); +} + +static int vp7_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame, AVPacket *avpkt) +{ + return vp78_decode_frame(avctx, frame, got_frame, avpkt, IS_VP7); +} + +av_cold static int vp7_decode_init(AVCodecContext *avctx) +{ + VP8Context *s = avctx->priv_data; + + vp78_decode_init(avctx); + ff_h264_pred_init(&s->hpc, AV_CODEC_ID_VP7, 8, 1); + ff_vp7dsp_init(&s->vp8dsp); + s->decode_mb_row_no_filter = vp7_decode_mb_row_no_filter; + s->filter_mb_row = vp7_filter_mb_row; + + return 0; +} + const FFCodec ff_vp7_decoder = { .p.name = "vp7", CODEC_LONG_NAME("On2 VP7"), @@ -2984,4 +2979,4 @@ const FFCodec ff_vp8_decoder = { NULL }, }; -#endif /* CONFIG_VP7_DECODER */ +#endif /* CONFIG_VP8_DECODER */ diff --git a/libavcodec/vp89_rac.h b/libavcodec/vp89_rac.h index bc0924c38..ff6cba5ba 100644 --- a/libavcodec/vp89_rac.h +++ b/libavcodec/vp89_rac.h @@ -38,7 +38,7 @@ static av_always_inline int vp89_rac_get(VPXRangeCoder *c) return vpx_rac_get_prob(c, 128); } -static av_unused int vp89_rac_get_uint(VPXRangeCoder *c, int bits) +av_unused static int vp89_rac_get_uint(VPXRangeCoder *c, int bits) { int value = 0; diff --git a/libavcodec/vp8_parser.c b/libavcodec/vp8_parser.c index 98b752bfb..f99a414f5 100644 --- a/libavcodec/vp8_parser.c +++ b/libavcodec/vp8_parser.c @@ -19,6 +19,7 @@ #include "libavutil/intreadwrite.h" #include "avcodec.h" +#include "parser_internal.h" static int parse(AVCodecParserContext *s, AVCodecContext *avctx, @@ -73,7 +74,7 @@ static int parse(AVCodecParserContext *s, return buf_size; } -const AVCodecParser ff_vp8_parser = { - .codec_ids = { AV_CODEC_ID_VP8 }, - .parser_parse = parse, +const FFCodecParser ff_vp8_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_VP8), + .parse = parse, }; diff --git a/libavcodec/vp8dsp.c b/libavcodec/vp8dsp.c index 88bb67f78..eabe3edb2 100644 --- a/libavcodec/vp8dsp.c +++ b/libavcodec/vp8dsp.c @@ -249,14 +249,14 @@ MK_IDCT_DC_ADD4_C(vp8) // because I like only having two parameters to pass functions... #define LOAD_PIXELS \ - int av_unused p3 = p[-4 * stride]; \ - int av_unused p2 = p[-3 * stride]; \ - int av_unused p1 = p[-2 * stride]; \ - int av_unused p0 = p[-1 * stride]; \ - int av_unused q0 = p[ 0 * stride]; \ - int av_unused q1 = p[ 1 * stride]; \ - int av_unused q2 = p[ 2 * stride]; \ - int av_unused q3 = p[ 3 * stride]; + av_unused int p3 = p[-4 * stride]; \ + av_unused int p2 = p[-3 * stride]; \ + av_unused int p1 = p[-2 * stride]; \ + av_unused int p0 = p[-1 * stride]; \ + av_unused int q0 = p[ 0 * stride]; \ + av_unused int q1 = p[ 1 * stride]; \ + av_unused int q2 = p[ 2 * stride]; \ + av_unused int q3 = p[ 3 * stride]; #define clip_int8(n) (cm[(n) + 0x80] - 0x80) @@ -558,26 +558,21 @@ put_vp8_epel ## SIZE ## _h ## HTAPS ## v ## VTAPS ## _c(uint8_t *dst, \ } \ } -VP8_EPEL_H(16, 4) VP8_EPEL_H(8, 4) VP8_EPEL_H(4, 4) VP8_EPEL_H(16, 6) VP8_EPEL_H(8, 6) VP8_EPEL_H(4, 6) -VP8_EPEL_V(16, 4) VP8_EPEL_V(8, 4) VP8_EPEL_V(4, 4) VP8_EPEL_V(16, 6) VP8_EPEL_V(8, 6) VP8_EPEL_V(4, 6) -VP8_EPEL_HV(16, 4, 4) VP8_EPEL_HV(8, 4, 4) VP8_EPEL_HV(4, 4, 4) -VP8_EPEL_HV(16, 4, 6) VP8_EPEL_HV(8, 4, 6) VP8_EPEL_HV(4, 4, 6) -VP8_EPEL_HV(16, 6, 4) VP8_EPEL_HV(8, 6, 4) VP8_EPEL_HV(4, 6, 4) VP8_EPEL_HV(16, 6, 6) @@ -667,7 +662,11 @@ VP8_BILINEAR(4) av_cold void ff_vp78dsp_init(VP8DSPContext *dsp) { - VP78_MC_FUNC(0, 16); + dsp->put_vp8_epel_pixels_tab[0][0][0] = put_vp8_pixels16_c; + dsp->put_vp8_epel_pixels_tab[0][0][2] = put_vp8_epel16_h6_c; + dsp->put_vp8_epel_pixels_tab[0][2][0] = put_vp8_epel16_v6_c; + dsp->put_vp8_epel_pixels_tab[0][2][2] = put_vp8_epel16_h6v6_c; + VP78_MC_FUNC(1, 8); VP78_MC_FUNC(2, 4); @@ -683,7 +682,7 @@ av_cold void ff_vp78dsp_init(VP8DSPContext *dsp) ff_vp78dsp_init_ppc(dsp); #elif ARCH_RISCV ff_vp78dsp_init_riscv(dsp); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_vp78dsp_init_x86(dsp); #endif } @@ -750,7 +749,7 @@ av_cold void ff_vp8dsp_init(VP8DSPContext *dsp) ff_vp8dsp_init_arm(dsp); #elif ARCH_RISCV ff_vp8dsp_init_riscv(dsp); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_vp8dsp_init_x86(dsp); #elif ARCH_MIPS ff_vp8dsp_init_mips(dsp); diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c index ba4e40377..c175169ce 100644 --- a/libavcodec/vp9.c +++ b/libavcodec/vp9.c @@ -31,7 +31,7 @@ #include "hwconfig.h" #include "profiles.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "pthread_internal.h" @@ -41,6 +41,7 @@ #include "vp9data.h" #include "vp9dec.h" #include "vpx_rac.h" +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" @@ -97,8 +98,9 @@ static void vp9_tile_data_free(VP9TileData *td) static void vp9_frame_unref(VP9Frame *f) { ff_progress_frame_unref(&f->tf); - ff_refstruct_unref(&f->extradata); - ff_refstruct_unref(&f->hwaccel_picture_private); + av_refstruct_unref(&f->header_ref); + av_refstruct_unref(&f->extradata); + av_refstruct_unref(&f->hwaccel_picture_private); f->segmentation_map = NULL; } @@ -113,9 +115,9 @@ static int vp9_frame_alloc(AVCodecContext *avctx, VP9Frame *f) sz = 64 * s->sb_cols * s->sb_rows; if (sz != s->frame_extradata_pool_size) { - ff_refstruct_pool_uninit(&s->frame_extradata_pool); - s->frame_extradata_pool = ff_refstruct_pool_alloc(sz * (1 + sizeof(VP9mvrefPair)), - FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); + av_refstruct_pool_uninit(&s->frame_extradata_pool); + s->frame_extradata_pool = av_refstruct_pool_alloc(sz * (1 + sizeof(VP9mvrefPair)), + AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); if (!s->frame_extradata_pool) { s->frame_extradata_pool_size = 0; ret = AVERROR(ENOMEM); @@ -123,7 +125,7 @@ static int vp9_frame_alloc(AVCodecContext *avctx, VP9Frame *f) } s->frame_extradata_pool_size = sz; } - f->extradata = ff_refstruct_pool_get(s->frame_extradata_pool); + f->extradata = av_refstruct_pool_get(s->frame_extradata_pool); if (!f->extradata) { ret = AVERROR(ENOMEM); goto fail; @@ -145,15 +147,18 @@ fail: static void vp9_frame_replace(VP9Frame *dst, const VP9Frame *src) { + av_refstruct_replace(&dst->header_ref, src->header_ref); + dst->frame_header = src->frame_header; + ff_progress_frame_replace(&dst->tf, &src->tf); - ff_refstruct_replace(&dst->extradata, src->extradata); + av_refstruct_replace(&dst->extradata, src->extradata); dst->segmentation_map = src->segmentation_map; dst->mv = src->mv; dst->uses_2pass = src->uses_2pass; - ff_refstruct_replace(&dst->hwaccel_picture_private, + av_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); } @@ -165,7 +170,8 @@ static int update_size(AVCodecContext *avctx, int w, int h) CONFIG_VP9_NVDEC_HWACCEL + \ CONFIG_VP9_VAAPI_HWACCEL + \ CONFIG_VP9_VDPAU_HWACCEL + \ - CONFIG_VP9_VIDEOTOOLBOX_HWACCEL) + CONFIG_VP9_VIDEOTOOLBOX_HWACCEL + \ + CONFIG_VP9_VULKAN_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts; VP9Context *s = avctx->priv_data; uint8_t *p; @@ -204,6 +210,9 @@ static int update_size(AVCodecContext *avctx, int w, int h) #endif #if CONFIG_VP9_VIDEOTOOLBOX_HWACCEL *fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX; +#endif +#if CONFIG_VP9_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; #endif break; case AV_PIX_FMT_YUV420P12: @@ -215,6 +224,9 @@ static int update_size(AVCodecContext *avctx, int w, int h) #endif #if CONFIG_VP9_VDPAU_HWACCEL *fmtp++ = AV_PIX_FMT_VDPAU; +#endif +#if CONFIG_VP9_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; #endif break; case AV_PIX_FMT_YUV444P: @@ -222,6 +234,9 @@ static int update_size(AVCodecContext *avctx, int w, int h) case AV_PIX_FMT_YUV444P12: #if CONFIG_VP9_VAAPI_HWACCEL *fmtp++ = AV_PIX_FMT_VAAPI; +#endif +#if CONFIG_VP9_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; #endif break; case AV_PIX_FMT_GBRP: @@ -229,6 +244,9 @@ static int update_size(AVCodecContext *avctx, int w, int h) case AV_PIX_FMT_GBRP12: #if CONFIG_VP9_VAAPI_HWACCEL *fmtp++ = AV_PIX_FMT_VAAPI; +#endif +#if CONFIG_VP9_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; #endif break; } @@ -688,8 +706,12 @@ static int decode_frame_header(AVCodecContext *avctx, s->s.h.uvac_qdelta = get_bits1(&s->gb) ? get_sbits_inv(&s->gb, 4) : 0; s->s.h.lossless = s->s.h.yac_qi == 0 && s->s.h.ydc_qdelta == 0 && s->s.h.uvdc_qdelta == 0 && s->s.h.uvac_qdelta == 0; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS if (s->s.h.lossless) avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif /* segmentation header info */ if ((s->s.h.segmentation.enabled = get_bits1(&s->gb))) { @@ -1142,7 +1164,8 @@ static void decode_sb(VP9TileData *td, int row, int col, VP9Filter *lflvl, uvoff + (8 * hbs * bytesperpixel >> s->ss_h), bl + 1); break; default: - av_assert0(0); + av_unreachable("ff_vp9_partition_tree only has " + "the four PARTITION_* terminal codes"); } } else if (vpx_rac_get_prob_branchy(td->c, p[1])) { bp = PARTITION_SPLIT; @@ -1245,10 +1268,11 @@ static av_cold int vp9_decode_free(AVCodecContext *avctx) for (int i = 0; i < 3; i++) vp9_frame_unref(&s->s.frames[i]); - ff_refstruct_pool_uninit(&s->frame_extradata_pool); + av_refstruct_pool_uninit(&s->frame_extradata_pool); for (i = 0; i < 8; i++) { ff_progress_frame_unref(&s->s.refs[i]); ff_progress_frame_unref(&s->next_refs[i]); + vp9_frame_unref(&s->s.ref_frames[i]); } free_buffers(s); @@ -1256,6 +1280,11 @@ static av_cold int vp9_decode_free(AVCodecContext *avctx) av_freep(&s->entries); ff_pthread_free(s, vp9_context_offsets); #endif + + av_refstruct_unref(&s->header_ref); + ff_cbs_fragment_free(&s->current_frag); + ff_cbs_close(&s->cbc); + av_freep(&s->td); return 0; } @@ -1558,22 +1587,41 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, int size = pkt->size; VP9Context *s = avctx->priv_data; int ret, i, j, ref; + CodedBitstreamUnit *unit; + VP9RawFrame *rf; + int retain_segmap_ref = s->s.frames[REF_FRAME_SEGMAP].segmentation_map && (!s->s.h.segmentation.enabled || !s->s.h.segmentation.update_map); const VP9Frame *src; AVFrame *f; + ret = ff_cbs_read_packet(s->cbc, &s->current_frag, pkt); + if (ret < 0) { + ff_cbs_fragment_reset(&s->current_frag); + av_log(avctx, AV_LOG_ERROR, "Failed to read frame header.\n"); + return ret; + } + + unit = &s->current_frag.units[0]; + rf = unit->content; + + av_refstruct_replace(&s->header_ref, unit->content_ref); + s->frame_header = &rf->header; + if ((ret = decode_frame_header(avctx, data, size, &ref)) < 0) { + ff_cbs_fragment_reset(&s->current_frag); return ret; } else if (ret == 0) { if (!s->s.refs[ref].f) { av_log(avctx, AV_LOG_ERROR, "Requested reference %d not available\n", ref); + ff_cbs_fragment_reset(&s->current_frag); return AVERROR_INVALIDDATA; } for (int i = 0; i < 8; i++) ff_progress_frame_replace(&s->next_refs[i], &s->s.refs[i]); ff_thread_finish_setup(avctx); ff_progress_frame_await(&s->s.refs[ref], INT_MAX); + ff_cbs_fragment_reset(&s->current_frag); if ((ret = av_frame_ref(frame, s->s.refs[ref].f)) < 0) return ret; @@ -1593,11 +1641,19 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, vp9_frame_unref(&s->s.frames[CUR_FRAME]); if ((ret = vp9_frame_alloc(avctx, &s->s.frames[CUR_FRAME])) < 0) return ret; + + s->s.frames[CUR_FRAME].header_ref = av_refstruct_ref(s->header_ref); + s->s.frames[CUR_FRAME].frame_header = s->frame_header; + f = s->s.frames[CUR_FRAME].tf.f; if (s->s.h.keyframe) f->flags |= AV_FRAME_FLAG_KEY; else f->flags &= ~AV_FRAME_FLAG_KEY; + if (s->s.h.lossless) + f->flags |= AV_FRAME_FLAG_LOSSLESS; + else + f->flags &= ~AV_FRAME_FLAG_LOSSLESS; f->pict_type = (s->s.h.keyframe || s->s.h.intraonly) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; // Non-existent frames have the implicit dimension 0x0 != CUR_FRAME @@ -1616,7 +1672,7 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, if (avctx->hwaccel) { const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel); - ret = hwaccel->start_frame(avctx, NULL, 0); + ret = hwaccel->start_frame(avctx, pkt->buf, pkt->data, pkt->size); if (ret < 0) return ret; ret = hwaccel->decode_slice(avctx, pkt->data, pkt->size); @@ -1625,6 +1681,13 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, ret = hwaccel->end_frame(avctx); if (ret < 0) return ret; + + for (i = 0; i < 8; i++) { + vp9_frame_replace(&s->s.ref_frames[i], + s->s.h.refreshrefmask & (1 << i) ? + &s->s.frames[CUR_FRAME] : &s->s.ref_frames[i]); + } + goto finish; } @@ -1749,6 +1812,8 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, } finish: + ff_cbs_fragment_reset(&s->current_frag); + ff_progress_frame_report(&s->s.frames[CUR_FRAME].tf, INT_MAX); // ref frame setup for (int i = 0; i < 8; i++) @@ -1762,19 +1827,26 @@ finish: return pkt->size; fail: + ff_cbs_fragment_reset(&s->current_frag); ff_progress_frame_report(&s->s.frames[CUR_FRAME].tf, INT_MAX); return ret; } -static void vp9_decode_flush(AVCodecContext *avctx) +static av_cold void vp9_decode_flush(AVCodecContext *avctx) { VP9Context *s = avctx->priv_data; int i; for (i = 0; i < 3; i++) vp9_frame_unref(&s->s.frames[i]); - for (i = 0; i < 8; i++) + + for (i = 0; i < 8; i++) { ff_progress_frame_unref(&s->s.refs[i]); + vp9_frame_unref(&s->s.ref_frames[i]); + } + + ff_cbs_fragment_reset(&s->current_frag); + ff_cbs_flush(s->cbc); if (FF_HW_HAS_CB(avctx, flush)) FF_HW_SIMPLE_CALL(avctx, flush); @@ -1788,6 +1860,10 @@ static av_cold int vp9_decode_init(AVCodecContext *avctx) s->last_bpp = 0; s->s.h.filter.sharpness = -1; + ret = ff_cbs_init(&s->cbc, AV_CODEC_ID_VP9, avctx); + if (ret < 0) + return ret; + #if HAVE_THREADS if (avctx->active_thread_type & FF_THREAD_SLICE) { ret = ff_pthread_init(s, vp9_context_offsets); @@ -1808,9 +1884,16 @@ static int vp9_decode_update_thread_context(AVCodecContext *dst, const AVCodecCo vp9_frame_replace(&s->s.frames[i], &ssrc->s.frames[i]); for (int i = 0; i < 8; i++) ff_progress_frame_replace(&s->s.refs[i], &ssrc->next_refs[i]); - ff_refstruct_replace(&s->frame_extradata_pool, ssrc->frame_extradata_pool); + av_refstruct_replace(&s->frame_extradata_pool, ssrc->frame_extradata_pool); s->frame_extradata_pool_size = ssrc->frame_extradata_pool_size; + av_refstruct_replace(&s->header_ref, ssrc->header_ref); + for (int i = 0; i < 8; i++) + vp9_frame_replace(&s->s.ref_frames[i], &ssrc->s.ref_frames[i]); + + s->frame_header = ssrc->frame_header; + memcpy(s->cbc->priv_data, ssrc->cbc->priv_data, sizeof(CodedBitstreamVP9Context)); + s->s.h.invisible = ssrc->s.h.invisible; s->s.h.keyframe = ssrc->s.h.keyframe; s->s.h.intraonly = ssrc->s.h.intraonly; @@ -1876,6 +1959,9 @@ const FFCodec ff_vp9_decoder = { #endif #if CONFIG_VP9_VIDEOTOOLBOX_HWACCEL HWACCEL_VIDEOTOOLBOX(vp9), +#endif +#if CONFIG_VP9_VULKAN_HWACCEL + HWACCEL_VULKAN(vp9), #endif NULL }, diff --git a/libavcodec/vp9_parser.c b/libavcodec/vp9_parser.c index ffcb93505..4caa730f4 100644 --- a/libavcodec/vp9_parser.c +++ b/libavcodec/vp9_parser.c @@ -21,9 +21,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/intreadwrite.h" -#include "libavcodec/get_bits.h" -#include "parser.h" +#include "avcodec.h" +#include "get_bits.h" +#include "parser_internal.h" static int parse(AVCodecParserContext *ctx, AVCodecContext *avctx, @@ -64,7 +64,7 @@ static int parse(AVCodecParserContext *ctx, return size; } -const AVCodecParser ff_vp9_parser = { - .codec_ids = { AV_CODEC_ID_VP9 }, - .parser_parse = parse, +const FFCodecParser ff_vp9_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_VP9), + .parse = parse, }; diff --git a/libavcodec/vp9dec.h b/libavcodec/vp9dec.h index 81dc80105..c3ad2bbcd 100644 --- a/libavcodec/vp9dec.h +++ b/libavcodec/vp9dec.h @@ -38,6 +38,7 @@ #include "vp9dsp.h" #include "vp9shared.h" #include "vpx_rac.h" +#include "cbs_vp9.h" #define REF_INVALID_SCALE 0xFFFF @@ -97,6 +98,11 @@ typedef struct VP9Context { VP9SharedContext s; VP9TileData *td; + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_frag; + VP9RawFrame *header_ref; ///< RefStruct reference backing frame_header + VP9RawFrameHeader *frame_header; + VP9DSPContext dsp; VideoDSPContext vdsp; GetBitContext gb; @@ -160,7 +166,7 @@ typedef struct VP9Context { uint8_t mvstep[3][2]; // frame specific buffer pools - struct FFRefStructPool *frame_extradata_pool; + struct AVRefStructPool *frame_extradata_pool; int frame_extradata_pool_size; } VP9Context; @@ -220,8 +226,8 @@ struct VP9TileData { DECLARE_ALIGNED(8, uint8_t, left_ref_ctx)[8]; DECLARE_ALIGNED(8, uint8_t, left_filter_ctx)[8]; // block reconstruction intermediates - DECLARE_ALIGNED(32, uint8_t, tmp_y)[64 * 64 * 2]; - DECLARE_ALIGNED(32, uint8_t, tmp_uv)[2][64 * 64 * 2]; + DECLARE_ALIGNED(64, uint8_t, tmp_y)[64 * 64 * 2]; + DECLARE_ALIGNED(64, uint8_t, tmp_uv)[2][64 * 64 * 2]; struct { int x, y; } min_mv, max_mv; int16_t *block_base, *block, *uvblock_base[2], *uvblock[2]; uint8_t *eob_base, *uveob_base[2], *eob, *uveob[2]; diff --git a/libavcodec/vp9dsp.c b/libavcodec/vp9dsp.c index 967e6e1e1..147486e10 100644 --- a/libavcodec/vp9dsp.c +++ b/libavcodec/vp9dsp.c @@ -102,7 +102,7 @@ av_cold void ff_vp9dsp_init(VP9DSPContext *dsp, int bpp, int bitexact) ff_vp9dsp_init_arm(dsp, bpp); #elif ARCH_RISCV ff_vp9dsp_init_riscv(dsp, bpp, bitexact); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_vp9dsp_init_x86(dsp, bpp, bitexact); #elif ARCH_MIPS ff_vp9dsp_init_mips(dsp, bpp); diff --git a/libavcodec/vp9dsp.h b/libavcodec/vp9dsp.h index 772848e34..0e93224e1 100644 --- a/libavcodec/vp9dsp.h +++ b/libavcodec/vp9dsp.h @@ -121,7 +121,7 @@ typedef struct VP9DSPContext { vp9_scaled_mc_func smc[5][N_FILTERS][2]; } VP9DSPContext; -extern const int16_t attribute_visibility_hidden ff_vp9_subpel_filters[3][16][8]; +EXTERN const int16_t ff_vp9_subpel_filters[3][16][8]; void ff_vp9dsp_init(VP9DSPContext *dsp, int bpp, int bitexact); diff --git a/libavcodec/vp9shared.h b/libavcodec/vp9shared.h index 8a450c26a..098372f8a 100644 --- a/libavcodec/vp9shared.h +++ b/libavcodec/vp9shared.h @@ -30,6 +30,7 @@ #include "libavutil/mem_internal.h" #include "progressframe.h" +#include "cbs_vp9.h" #include "vp9.h" enum BlockPartition { @@ -63,6 +64,9 @@ typedef struct VP9mvrefPair { } VP9mvrefPair; typedef struct VP9Frame { + VP9RawFrame *header_ref; ///< RefStruct reference backing frame_header + VP9RawFrameHeader *frame_header; + ProgressFrame tf; void *extradata; ///< RefStruct reference uint8_t *segmentation_map; @@ -170,6 +174,7 @@ typedef struct VP9SharedContext { #define REF_FRAME_SEGMAP 2 #define BLANK_FRAME 3 VP9Frame frames[4]; + VP9Frame ref_frames[8]; } VP9SharedContext; #endif /* AVCODEC_VP9SHARED_H */ diff --git a/libavcodec/vqavideo.c b/libavcodec/vqavideo.c index 37c083297..99c86a461 100644 --- a/libavcodec/vqavideo.c +++ b/libavcodec/vqavideo.c @@ -812,11 +812,6 @@ static int vqa_decode_frame(AVCodecContext *avctx, AVFrame *rframe, /* make the palette available on the way out */ memcpy(s->frame->data[1], s->palette, PALETTE_COUNT * 4); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } else if (avctx->pix_fmt == AV_PIX_FMT_RGB555LE) { if ((res = vqa_decode_frame_hicolor(s, s->frame)) < 0) return res; diff --git a/libavcodec/vt_internal.h b/libavcodec/vt_internal.h index 9502d7c7d..b1eb07310 100644 --- a/libavcodec/vt_internal.h +++ b/libavcodec/vt_internal.h @@ -56,14 +56,19 @@ int ff_videotoolbox_frame_params(AVCodecContext *avctx, int ff_videotoolbox_buffer_copy(VTContext *vtctx, const uint8_t *buffer, uint32_t size); +int ff_videotoolbox_buffer_append(VTContext *vtctx, + const uint8_t *buffer, + uint32_t size); int ff_videotoolbox_uninit(AVCodecContext *avctx); int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size); int ff_videotoolbox_h264_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size); int ff_videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame); +CFDataRef ff_videotoolbox_av1c_extradata_create(AVCodecContext *avctx); CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx); CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx); CFDataRef ff_videotoolbox_vpcc_extradata_create(AVCodecContext *avctx); diff --git a/libavcodec/vulkan/Makefile b/libavcodec/vulkan/Makefile new file mode 100644 index 000000000..cd21a53f8 --- /dev/null +++ b/libavcodec/vulkan/Makefile @@ -0,0 +1,34 @@ +clean:: + $(RM) $(CLEANSUFFIXES:%=libavcodec/vulkan/%) + +OBJS-$(CONFIG_FFV1_VULKAN_ENCODER) += vulkan/ffv1_enc_setup.comp.spv.o \ + vulkan/ffv1_enc_reset.comp.spv.o \ + vulkan/ffv1_enc_reset_golomb.comp.spv.o \ + vulkan/ffv1_enc.comp.spv.o \ + vulkan/ffv1_enc_golomb.comp.spv.o \ + vulkan/ffv1_enc_rgb.comp.spv.o \ + vulkan/ffv1_enc_rgb_golomb.comp.spv.o \ + vulkan/ffv1_enc_rct_search.comp.spv.o + +OBJS-$(CONFIG_FFV1_VULKAN_HWACCEL) += vulkan/ffv1_dec_setup.comp.spv.o \ + vulkan/ffv1_dec_reset.comp.spv.o \ + vulkan/ffv1_dec_reset_golomb.comp.spv.o \ + vulkan/ffv1_dec.comp.spv.o \ + vulkan/ffv1_dec_golomb.comp.spv.o \ + vulkan/ffv1_dec_rgb.comp.spv.o \ + vulkan/ffv1_dec_rgb_golomb.comp.spv.o + +OBJS-$(CONFIG_PRORES_KS_VULKAN_ENCODER) += vulkan/prores_ks_alpha_data.comp.spv.o \ + vulkan/prores_ks_slice_data.comp.spv.o \ + vulkan/prores_ks_estimate_slice.comp.spv.o \ + vulkan/prores_ks_encode_slice.comp.spv.o \ + vulkan/prores_ks_trellis_node.comp.spv.o + +OBJS-$(CONFIG_PRORES_RAW_VULKAN_HWACCEL) += vulkan/prores_raw_decode.comp.spv.o \ + vulkan/prores_raw_idct.comp.spv.o + +OBJS-$(CONFIG_PRORES_VULKAN_HWACCEL) += vulkan/prores_vld.comp.spv.o \ + vulkan/prores_idct.comp.spv.o + +OBJS-$(CONFIG_DPX_VULKAN_HWACCEL) += vulkan/dpx_unpack.comp.spv.o \ + vulkan/dpx_copy.comp.spv.o diff --git a/libavcodec/vulkan/common.glsl b/libavcodec/vulkan/common.glsl new file mode 100644 index 000000000..578ec17c4 --- /dev/null +++ b/libavcodec/vulkan/common.glsl @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2024 Lynne + * + * 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 VULKAN_COMMON_H +#define VULKAN_COMMON_H + +#pragma use_vulkan_memory_model + +layout (local_size_x_id = 253, local_size_y_id = 254, local_size_z_id = 255) in; + +#ifdef DEBUG +#extension GL_EXT_debug_printf : require +#define printf debugPrintfEXT +#endif + +#extension GL_EXT_shader_explicit_arithmetic_types : require +#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require +#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require +#extension GL_EXT_shader_explicit_arithmetic_types_int32 : require +#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require +#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require +#extension GL_EXT_shader_explicit_arithmetic_types_float32 : require +#extension GL_EXT_shader_explicit_arithmetic_types_float64 : require +#extension GL_EXT_shader_8bit_storage : require +#extension GL_EXT_shader_16bit_storage : require + +#extension GL_EXT_shader_image_load_formatted : require +#extension GL_EXT_nonuniform_qualifier : require +#extension GL_EXT_scalar_block_layout : require +#extension GL_EXT_buffer_reference : require +#extension GL_EXT_buffer_reference2 : require +#extension GL_KHR_memory_scope_semantics : require +#extension GL_EXT_null_initializer : require + +#extension GL_EXT_expect_assume : enable +#extension GL_EXT_control_flow_attributes : enable + +layout(buffer_reference, buffer_reference_align = 1) buffer u8buf { + uint8_t v; +}; + +layout(buffer_reference, buffer_reference_align = 1) buffer u8vec2buf { + u8vec2 v; +}; + +layout(buffer_reference, buffer_reference_align = 1) buffer u8vec4buf { + u8vec4 v; +}; + +layout(buffer_reference, buffer_reference_align = 2) buffer u16buf { + uint16_t v; +}; + +layout(buffer_reference, buffer_reference_align = 4) buffer u32buf { + uint32_t v; +}; + +layout(buffer_reference, buffer_reference_align = 4) buffer u32vec2buf { + u32vec2 v; +}; + +layout(buffer_reference, buffer_reference_align = 4) buffer u32vec4buf { + u32vec4 v; +}; + +layout(buffer_reference, buffer_reference_align = 8) buffer u64buf { + uint64_t v; +}; + +#define U8(x) uint8_t(x) +#define U16(x) uint16_t(x) +#define U32(x) uint32_t(x) +#define U64(x) uint64_t(x) + +#define I8(x) int8_t(x) +#define I16(x) int16_t(x) +#define I32(x) int32_t(x) +#define I64(x) int64_t(x) + +#define OFFBUF(type, b, l) \ + type(uint64_t(b) + uint64_t(l)) + +#define zero_extend(a, p) \ + ((a) & ((1 << (p)) - 1)) + +#define sign_extend(val, bits) \ + bitfieldExtract(val, 0, bits) + +#define fold(diff, bits) \ + sign_extend(diff, bits) + +#define mid_pred(a, b, c) \ + max(min((a), (b)), min(max((a), (b)), (c))) + +#define ceil_rshift(a, b) \ + (-((-(a)) >> (b))) + +/* TODO: optimize */ +uint align(uint src, uint a) +{ + uint res = src % a; + if (res == 0) + return src; + return src + a - res; +} + +/* TODO: optimize */ +uint64_t align64(uint64_t src, uint64_t a) +{ + uint64_t res = src % a; + if (res == 0) + return src; + return src + a - res; +} + +#define reverse2(src) \ + (pack16(unpack8(uint16_t(src)).yx)) + +#define reverse4(src) \ + (pack32(unpack8(uint32_t(src)).wzyx)) + +u32vec2 reverse8(uint64_t src) +{ + u32vec2 tmp = unpack32(src); + tmp.x = reverse4(tmp.x); + tmp.y = reverse4(tmp.y); + return tmp.yx; +} + +#ifdef PB_32 +#define BIT_BUF_TYPE uint32_t +#define BUF_TYPE u32buf +#define BUF_REVERSE(src) reverse4(src) +#define BUF_BITS uint8_t(32) +#define BUF_BYTES uint8_t(4) +#define BYTE_EXTRACT(src, byte_off) \ + (uint8_t(bitfieldExtract((src), ((byte_off) << 3), 8))) +#else +#define BIT_BUF_TYPE uint64_t +#define BUF_TYPE u32vec2buf +#define BUF_REVERSE(src) reverse8(src) +#define BUF_BITS uint8_t(64) +#define BUF_BYTES uint8_t(8) +#define BYTE_EXTRACT(src, byte_off) \ + (uint8_t(((src) >> ((byte_off) << 3)) & 0xFF)) +#endif + +struct PutBitContext { + uint64_t buf_start; + uint64_t buf; + + BIT_BUF_TYPE bit_buf; + uint8_t bit_left; +}; + +void put_bits(inout PutBitContext pb, const uint32_t n, uint32_t value) +{ + if (n < pb.bit_left) { + pb.bit_buf = (pb.bit_buf << n) | value; + pb.bit_left -= uint8_t(n); + } else { + pb.bit_buf <<= pb.bit_left; + pb.bit_buf |= (value >> (n - pb.bit_left)); + +#ifdef PB_UNALIGNED + u8buf bs = u8buf(pb.buf); + [[unroll]] + for (uint8_t i = uint8_t(0); i < BUF_BYTES; i++) + bs[i].v = BYTE_EXTRACT(pb.bit_buf, BUF_BYTES - uint8_t(1) - i); +#else +#ifdef DEBUG + if ((pb.buf % BUF_BYTES) != 0) + debugPrintfEXT("put_bits buffer is not aligned!"); +#endif + + BUF_TYPE bs = BUF_TYPE(pb.buf); + bs.v = BUF_REVERSE(pb.bit_buf); +#endif + pb.buf = uint64_t(bs) + BUF_BYTES; + + pb.bit_left += BUF_BITS - uint8_t(n); + pb.bit_buf = value; + } +} + +uint32_t flush_put_bits(inout PutBitContext pb) +{ + /* Align bits to MSBs */ + if (pb.bit_left < BUF_BITS) + pb.bit_buf <<= pb.bit_left; + + if (pb.bit_left < BUF_BITS) { + uint to_write = ((BUF_BITS - pb.bit_left - 1) >> 3) + 1; + + u8buf bs = u8buf(pb.buf); + for (int i = 0; i < to_write; i++) + bs[i].v = BYTE_EXTRACT(pb.bit_buf, BUF_BYTES - uint8_t(1) - i); + pb.buf = uint64_t(bs) + to_write; + } + + pb.bit_left = BUF_BITS; + pb.bit_buf = 0x0; + + return uint32_t(pb.buf - pb.buf_start); +} + +void init_put_bits(out PutBitContext pb, u8buf data, uint64_t len) +{ + pb.buf_start = uint64_t(data); + pb.buf = uint64_t(data); + + pb.bit_buf = 0; + pb.bit_left = BUF_BITS; +} + +uint64_t put_bits_count(in PutBitContext pb) +{ + return (pb.buf - pb.buf_start)*8 + BUF_BITS - pb.bit_left; +} + +uint32_t put_bytes_count(in PutBitContext pb) +{ + uint64_t num_bytes = (pb.buf - pb.buf_start) + ((BUF_BITS - pb.bit_left) >> 3); + return uint32_t(num_bytes); +} + +struct GetBitContext { + uint64_t buf_start; + uint64_t buf; + uint64_t buf_end; + + uint64_t bits; + int bits_valid; +#ifdef GET_BITS_SMEM + int cur_smem_pos; +#endif +}; + +#ifndef GET_BITS_SMEM +#define LOAD64() \ + { \ + u8vec4buf ptr = u8vec4buf(gb.buf); \ + uint32_t rf1 = pack32((ptr[0].v).wzyx); \ + uint32_t rf2 = pack32((ptr[1].v).wzyx); \ + gb.buf += 8; \ + gb.bits = uint64_t(rf1) << 32 | uint64_t(rf2); \ + gb.bits_valid = 64; \ + } + +#define RELOAD32() \ + { \ + u8vec4buf ptr = u8vec4buf(gb.buf); \ + uint32_t rf = pack32((ptr[0].v).wzyx); \ + gb.buf += 4; \ + gb.bits = uint64_t(rf) << (32 - gb.bits_valid) | gb.bits; \ + gb.bits_valid += 32; \ + } +#else /* GET_BITS_SMEM */ +shared u32vec4 gb_storage[gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z*GET_BITS_SMEM]; + +#define FILL_SMEM() \ + { \ + u32vec4buf ptr = u32vec4buf(gb.buf); \ + [[unroll]] \ + for (uint i = 0; i < GET_BITS_SMEM; ++i) \ + gb_storage[gl_LocalInvocationIndex * GET_BITS_SMEM + i] = ptr[i].v; \ + gb.cur_smem_pos = 0; \ + } + +#define LOAD64() \ + { \ + gb.bits = 0; \ + gb.bits_valid = 0; \ + u8buf ptr = u8buf(gb.buf); \ + for (uint i = 0; i < ((4 - uint(gb.buf_start)) & 3); ++i) { \ + gb.bits |= uint64_t(ptr[i].v) << (56 - i * 8); \ + gb.bits_valid += 8; \ + gb.buf += 1; \ + } \ + FILL_SMEM(); \ + } + +#define RELOAD32() \ + { \ + if (gb.cur_smem_pos >= 4*GET_BITS_SMEM) \ + FILL_SMEM(); \ + u32vec4 vec = gb_storage[gl_LocalInvocationIndex * GET_BITS_SMEM + (gb.cur_smem_pos >> 2)]; \ + uint v = vec[gb.cur_smem_pos & 3]; \ + gb.buf += 4; \ + gb.bits = uint64_t(reverse4(v)) << (32 - gb.bits_valid) | gb.bits; \ + gb.bits_valid += 32; \ + gb.cur_smem_pos += 1; \ + } +#endif /* GET_BITS_SMEM */ + +void init_get_bits(inout GetBitContext gb, u8buf data, int len) +{ + gb.buf = gb.buf_start = uint64_t(data); + gb.buf_end = uint64_t(data) + len; + + /* Preload */ + LOAD64() +} + +bool get_bit(inout GetBitContext gb) +{ + if (gb.bits_valid == 0) + LOAD64() + + bool val = bool(gb.bits >> (64 - 1)); + gb.bits <<= 1; + gb.bits_valid--; + return val; +} + +uint get_bits(inout GetBitContext gb, int n) +{ + if (n == 0) + return 0; + + if (n > gb.bits_valid) + RELOAD32() + + uint val = uint(gb.bits >> (64 - n)); + gb.bits <<= n; + gb.bits_valid -= n; + return val; +} + +uint show_bits(inout GetBitContext gb, int n) +{ + if (n > gb.bits_valid) + RELOAD32() + + return uint(gb.bits >> (64 - n)); +} + +void skip_bits(inout GetBitContext gb, int n) +{ + if (n > gb.bits_valid) + RELOAD32() + + gb.bits <<= n; + gb.bits_valid -= n; +} + +int tell_bits(in GetBitContext gb) +{ + return int(gb.buf - gb.buf_start) * 8 - gb.bits_valid; +} + +int left_bits(in GetBitContext gb) +{ + return int(gb.buf_end - gb.buf) * 8 + gb.bits_valid; +} + +#endif /* VULKAN_COMMON_H */ diff --git a/libavcodec/vulkan/dct.glsl b/libavcodec/vulkan/dct.glsl new file mode 100644 index 000000000..76f799b3e --- /dev/null +++ b/libavcodec/vulkan/dct.glsl @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2025 Lynne + * Copyright (c) 2016 Nathan Egge + * + * 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 + */ + +/** + * Orthonormal inverse 8-point Type-II DCT based on the Chen factorization[1]. + * 1D with scale factors moved up front. + * This computes an n-point Type-II DCT by first computing an n/2-point Type-II DCT + * of the even indexed inputs and an n/2-point Type-IV DST of the odd indexed inputs, + * and then combining them using a "butterfly" operation. + * + * [1] W.H. Chen, C. Smith, and S. Fralick, + * "A Fast Computational Algorithm for the Discrete Cosine Transform", + * IEEE Transactions on Communications, Vol. 25, No. 9, pp 1004-1009, Sept. 1977 + */ + +#ifndef VULKAN_DCT_H +#define VULKAN_DCT_H + +#extension GL_EXT_spec_constant_composites : require + +layout (constant_id = 16) const uint32_t nb_blocks = 1; +layout (constant_id = 17) const uint32_t nb_components = 1; + +#define V(I) layout(constant_id = (18 + I)) const float sv##I = I; +V( 0) V( 1) V( 2) V( 3) V( 4) V( 5) V( 6) V( 7) V( 8) V( 9) V(10) V(11) V(12) +V(13) V(14) V(15) V(16) V(17) V(18) V(19) V(20) V(21) V(22) V(23) V(24) V(25) +V(26) V(27) V(28) V(29) V(30) V(31) V(32) V(33) V(34) V(35) V(36) V(37) V(38) +V(39) V(40) V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) V(49) V(50) V(51) +V(52) V(53) V(54) V(55) V(56) V(57) V(58) V(59) V(60) V(61) V(62) V(63) + +const float idct_scale[64] = { + sv0, sv1, sv2, sv3, sv4, sv5, sv6, sv7, sv8, sv9, sv10, sv11, sv12, + sv13, sv14, sv15, sv16, sv17, sv18, sv19, sv20, sv21, sv22, sv23, sv24, sv25, + sv26, sv27, sv28, sv29, sv30, sv31, sv32, sv33, sv34, sv35, sv36, sv37, sv38, + sv39, sv40, sv41, sv42, sv43, sv44, sv45, sv46, sv47, sv48, sv49, sv50, sv51, + sv52, sv53, sv54, sv55, sv56, sv57, sv58, sv59, sv60, sv61, sv62, sv63 +}; + +/* Padded by 1 row to avoid bank conflicts */ +shared float blocks[nb_blocks][nb_components*8*(8 + 1)]; + +void idct8(uint block, uint offset, uint stride) +{ + float t0, t1, t2, t3, t4, t5, t6, t7, u8; + float u0, u1, u2, u3, u4, u5, u6, u7; + + /* Input */ + t0 = blocks[block][0*stride + offset]; + u4 = blocks[block][1*stride + offset]; + t2 = blocks[block][2*stride + offset]; + u6 = blocks[block][3*stride + offset]; + t1 = blocks[block][4*stride + offset]; + u5 = blocks[block][5*stride + offset]; + t3 = blocks[block][6*stride + offset]; + u7 = blocks[block][7*stride + offset]; + + /* Embedded scaled inverse 4-point Type-II DCT */ + u0 = t0 + t1; + u1 = t0 - t1; + u3 = t2 + t3; + u2 = (t2 - t3)*(1.4142135623730950488016887242097f) - u3; + t0 = u0 + u3; + t3 = u0 - u3; + t1 = u1 + u2; + t2 = u1 - u2; + + /* Embedded scaled inverse 4-point Type-IV DST */ + t5 = u5 + u6; + t6 = u5 - u6; + t7 = u4 + u7; + t4 = u4 - u7; + u7 = t7 + t5; + u5 = (t7 - t5)*(1.4142135623730950488016887242097f); + u8 = (t4 + t6)*(1.8477590650225735122563663787936f); + u4 = u8 - t4*(1.0823922002923939687994464107328f); + u6 = u8 - t6*(2.6131259297527530557132863468544f); + t7 = u7; + t6 = t7 - u6; + t5 = t6 + u5; + t4 = t5 - u4; + + /* Butterflies */ + u0 = t0 + t7; + u7 = t0 - t7; + u6 = t1 + t6; + u1 = t1 - t6; + u2 = t2 + t5; + u5 = t2 - t5; + u4 = t3 + t4; + u3 = t3 - t4; + + /* Output */ + blocks[block][0*stride + offset] = u0; + blocks[block][1*stride + offset] = u1; + blocks[block][2*stride + offset] = u2; + blocks[block][3*stride + offset] = u3; + blocks[block][4*stride + offset] = u4; + blocks[block][5*stride + offset] = u5; + blocks[block][6*stride + offset] = u6; + blocks[block][7*stride + offset] = u7; +} + +void fdct8(uint block, uint offset, uint stride) +{ + const float c_pi = radians(180); + const float c_rt2 = sqrt(2.0); + const float c_norm = 1 / sqrt(8.0); + const float c_a = c_rt2 * cos( c_pi / 16); + const float c_b = c_rt2 * cos( c_pi / 8); + const float c_c = c_rt2 * cos(3 * c_pi / 16); + const float c_d = c_rt2 * cos(5 * c_pi / 16); + const float c_e = c_rt2 * cos(3 * c_pi / 8); + const float c_f = c_rt2 * cos(7 * c_pi / 16); + + float u0, u1, u2, u3, u4, u5, u6, u7; + + /* Input */ + u0 = blocks[block][0*stride + offset]; + u1 = blocks[block][1*stride + offset]; + u2 = blocks[block][2*stride + offset]; + u3 = blocks[block][3*stride + offset]; + u4 = blocks[block][4*stride + offset]; + u5 = blocks[block][5*stride + offset]; + u6 = blocks[block][6*stride + offset]; + u7 = blocks[block][7*stride + offset]; + + float X07P = u0 + u7; + float X16P = u1 + u6; + float X25P = u2 + u5; + float X34P = u3 + u4; + + float X07M = u0 - u7; + float X61M = u6 - u1; + float X25M = u2 - u5; + float X43M = u4 - u3; + + float X07P34PP = X07P + X34P; + float X07P34PM = X07P - X34P; + float X16P25PP = X16P + X25P; + float X16P25PM = X16P - X25P; + + blocks[block][0*stride + offset] = c_norm * (X07P34PP + X16P25PP); + blocks[block][2*stride + offset] = c_norm * (c_b * X07P34PM + c_e * X16P25PM); + blocks[block][4*stride + offset] = c_norm * (X07P34PP - X16P25PP); + blocks[block][6*stride + offset] = c_norm * (c_e * X07P34PM - c_b * X16P25PM); + blocks[block][1*stride + offset] = c_norm * (c_a * X07M - c_c * X61M + c_d * X25M - c_f * X43M); + blocks[block][3*stride + offset] = c_norm * (c_c * X07M + c_f * X61M - c_a * X25M + c_d * X43M); + blocks[block][5*stride + offset] = c_norm * (c_d * X07M + c_a * X61M + c_f * X25M - c_c * X43M); + blocks[block][7*stride + offset] = c_norm * (c_f * X07M + c_d * X61M + c_c * X25M + c_a * X43M); +} + +#endif /* VULKAN_DCT_H */ diff --git a/libavcodec/vulkan/dpx_copy.comp.glsl b/libavcodec/vulkan/dpx_copy.comp.glsl new file mode 100644 index 000000000..124caea49 --- /dev/null +++ b/libavcodec/vulkan/dpx_copy.comp.glsl @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#include "common.glsl" + +layout (constant_id = 0) const bool big_endian = false; +layout (constant_id = 1) const int type_bits = 0; + +layout (set = 0, binding = 0) uniform writeonly uimage2D dst[]; +layout (set = 0, binding = 1, scalar) readonly buffer data_buf8 { + uint8_t data8[]; +}; +layout (set = 0, binding = 2, scalar) readonly buffer data_buf16 { + uint16_t data16[]; +}; +layout (set = 0, binding = 3, scalar) readonly buffer data_buf32 { + uint32_t data32[]; +}; + +layout (push_constant, scalar) uniform pushConstants { + int bits_per_comp; + int nb_comp; + int nb_images; + int stride; + int need_align; + int padded_10bit; + int shift; +}; + +#define READ_FN(bits, bytes) \ +uint read_val##bits(uint off) \ +{ \ + if (big_endian) \ + return uint(reverse##bytes(data##bits[off])); \ + return uint(data##bits[off]); \ +} +READ_FN(16, 2) +READ_FN(32, 4) + +uint read_data(uint off) +{ + if (type_bits == 8) + return uint(data8[off]); + else if (type_bits == 16) + return read_val16(off); + return read_val32(off); +} + +void main(void) +{ + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + ivec2 size = imageSize(dst[0]); + if (any(greaterThanEqual(pos, size))) + return; + + uint linesize; + linesize = align(size.x*bits_per_comp*nb_comp, 32); + + uint offs = pos.y*linesize + pos.x*nb_comp*bits_per_comp; + offs /= bits_per_comp; + + if (nb_images == 1) { + uvec4 val; + for (int i = 0; i < nb_comp; i++) + val[i] = read_data(offs + i); + val >>= shift; + imageStore(dst[0], pos, val); + } else { + const ivec4 fmt_lut = ivec4(2, 0, 1, 3); + for (int i = 0; i < nb_comp; i++) { + uint32_t val = read_data(offs + i); + val >>= shift; + imageStore(dst[fmt_lut[i]], pos, uvec4(val)); + } + } +} diff --git a/libavcodec/vulkan/dpx_unpack.comp.glsl b/libavcodec/vulkan/dpx_unpack.comp.glsl new file mode 100644 index 000000000..e169ac07a --- /dev/null +++ b/libavcodec/vulkan/dpx_unpack.comp.glsl @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#include "common.glsl" + +layout (constant_id = 0) const bool big_endian = false; +layout (constant_id = 1) const bool packed_10bit = false; + +layout (set = 0, binding = 0) uniform writeonly uimage2D dst[]; +layout (set = 0, binding = 1, scalar) readonly buffer data_buf { + uint32_t data[]; +}; + +layout (push_constant, scalar) uniform pushConstants { + int bits_per_comp; + int nb_comp; + int nb_images; + int stride; + int need_align; + int padded_10bit; + int shift; +}; + +uint32_t read_data(uint off) +{ + if (big_endian) + return reverse4(data[off]); + return data[off]; +} + +i16vec4 parse_packed10_in_32(ivec2 pos, int stride) +{ + uint32_t d = read_data(pos.y*stride + pos.x); + i16vec4 v; + d = d << 10 | d >> 22 & 0x3FFFFF; + v[0] = int16_t(d & 0x3FF); + d = d << 10 | d >> 22 & 0x3FFFFF; + v[1] = int16_t(d & 0x3FF); + d = d << 10 | d >> 22 & 0x3FFFFF; + v[2] = int16_t(d & 0x3FF); + v[3] = int16_t(0); + return v; +} + +i16vec4 parse_packed_in_32(ivec2 pos, int stride) +{ + uint line_size = stride*bits_per_comp*nb_comp; + line_size += line_size & 31; + line_size += need_align << 3; + + uint line_off = pos.y*line_size; + uint pix_off = pos.x*bits_per_comp*nb_comp; + + uint off = (line_off + pix_off) >> 5; + uint bit = pix_off & 0x1f; + + uint32_t d0 = read_data(off + 0); + uint32_t d1 = read_data(off + 1); + + uint64_t combined = (uint64_t(d1) << 32) | d0; + combined >>= bit; + + return i16vec4(combined, + combined >> (bits_per_comp*1), + combined >> (bits_per_comp*2), + combined >> (bits_per_comp*3)) & + int16_t((1 << bits_per_comp) - 1); +} + +void main(void) +{ + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + ivec2 size = imageSize(dst[0]); + if (any(greaterThanEqual(pos, size))) + return; + + i16vec4 p; + if (packed_10bit) + p = parse_packed10_in_32(pos, size.x); + else + p = parse_packed_in_32(pos, size.x); + + if (nb_images == 1) { + imageStore(dst[0], pos, p); + } else { + const ivec4 fmt_lut = ivec4(2, 0, 1, 3); + for (uint i = 0; i < nb_comp; i++) + imageStore(dst[fmt_lut[i]], pos, i16vec4(p[i])); + } +} diff --git a/libavcodec/vulkan/ffv1_common.glsl b/libavcodec/vulkan/ffv1_common.glsl new file mode 100644 index 000000000..871927669 --- /dev/null +++ b/libavcodec/vulkan/ffv1_common.glsl @@ -0,0 +1,258 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * 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 VULKAN_FFV1_COMMON_H +#define VULKAN_FFV1_COMMON_H + +#ifdef GOLOMB +#include "ffv1_vlc.glsl" +#endif + +#define MAX_QUANT_TABLES 8 +#define MAX_CONTEXT_INPUTS 5 +#define MAX_QUANT_TABLE_SIZE 256 +#define MAX_QUANT_TABLE_MASK (MAX_QUANT_TABLE_SIZE - 1) + +layout (constant_id = 0) const int rgb_linecache = 2; +layout (constant_id = 1) const bool has_crc = false; +layout (constant_id = 2) const int version = 0; +layout (constant_id = 3) const int quant_table_count = 0; +layout (constant_id = 4) const bool has_extend_lookup = false; + +layout (constant_id = 5) const int rct_offset = 0; +layout (constant_id = 6) const int colorspace = 0; +layout (constant_id = 7) const bool transparency = false; +layout (constant_id = 8) const bool planar_rgb = false; +layout (constant_id = 9) const int codec_planes = 0; +layout (constant_id = 10) const int color_planes = 0; +layout (constant_id = 11) const int planes = 0; +layout (constant_id = 12) const int bits = 0; + +layout (constant_id = 13) const int chroma_shift_x = 0; +layout (constant_id = 14) const int chroma_shift_y = 0; +const ivec2 chroma_shift = ivec2(chroma_shift_x, chroma_shift_y); + +/* Encoder-only */ +layout (constant_id = 15) const bool force_pcm = false; +layout (constant_id = 16) const bool rct_search = false; +layout (constant_id = 17) const uint context_model = 0; + +layout (push_constant, scalar) uniform pushConstants { + u8buf slice_data; + + bool extend_lookup[MAX_QUANT_TABLES]; + uint16_t context_count[MAX_QUANT_TABLES]; + + ivec4 fmt_lut; + u16vec2 img_size; + + uint plane_state_size; + bool key_frame; + uint32_t crcref; + int micro_version; + + /* Encoder-only */ + ivec2 sar; + int pic_mode; + uint slice_size_max; +}; + +#include "rangecoder.glsl" + +#if !defined(RGB) +#define TYPE int16_t +#define VTYPE2 i16vec2 +#define VTYPE3 i16vec3 +#else +#define TYPE int32_t +#define VTYPE2 i32vec2 +#define VTYPE3 i32vec3 +#endif + +struct SliceContext { + RangeCoder c; + + ivec2 slice_dim; + ivec2 slice_pos; + ivec2 slice_rct_coef; + u8vec3 quant_table_idx; + + uint slice_coding_mode; + bool slice_reset_contexts; +}; + +#if !defined(SB_QUALI) +#if (defined(ENCODE) || defined(DECODE)) +#define SB_QUALI readonly +#else +#define SB_QUALI +#endif +#endif + +layout (set = 1, binding = 0, scalar) SB_QUALI buffer slice_ctx_buf { + SliceContext slice_ctx[]; +}; + +uint slice_coord(uint width, uint sx, uint num_h_slices, uint chroma_shift) +{ + uint mpw = 1 << chroma_shift; + uint awidth = align(width, mpw); + + if ((version < 4) || ((version == 4) && (micro_version < 3))) + return width * sx / num_h_slices; + + sx = (2 * awidth * sx + num_h_slices * mpw) / (2 * num_h_slices * mpw) * mpw; + if (sx == awidth) + sx = width; + + return sx; +} + +#if defined(ENCODE) || defined(DECODE) + +layout (set = 0, binding = 1, scalar) readonly uniform quant_buf { + int16_t quant_table[MAX_QUANT_TABLES] + [MAX_CONTEXT_INPUTS] + [MAX_QUANT_TABLE_SIZE]; +}; + +/* -1, { -1, 0 } */ +int predict(int L, ivec2 top) +{ + return mid_pred(L, L + top[1] - top[0], top[1]); +} + +const uint32_t log2_run[41] = { + 0, 0, 0, 0, 1, 1, 1, 1, + 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, +}; + +shared VTYPE2 linecache; + +#ifdef RGB +#define RGB_LBUF (rgb_linecache - 1) +#define LADDR(p) (ivec2((p).x, ((p).y & RGB_LBUF))) + +ivec2 get_pred(readonly uimage2D pred, ivec2 sp, ivec2 off, + uint comp, int sw, uint8_t quant_table_idx, bool extend_lookup) +{ + ivec2 yoff_border1 = expectEXT(off.x == 0, false) ? off + ivec2(1, -1) : off; + + /* Thanks to the same coincidence as below, we can skip checking if off == 0, 1 */ + VTYPE3 top = VTYPE3(TYPE(imageLoad(pred, sp + LADDR(yoff_border1 + ivec2(-1, -1)))[comp]), + TYPE(imageLoad(pred, sp + LADDR(off + ivec2(0, -1)))[comp]), + TYPE(imageLoad(pred, sp + LADDR(off + ivec2(min(1, sw - off.x - 1), -1)))[comp])); + + /* Normally, we'd need to check if off != ivec2(0, 0) here, since otherwise, we must + * return zero. However, ivec2(-1, 0) + ivec2(1, -1) == ivec2(0, -1), e.g. previous + * row, 0 offset, same slice, which is zero since we zero out the buffer for RGB */ + TYPE cur = linecache[1]; + + int base = quant_table[quant_table_idx][0][(cur - top[0]) & MAX_QUANT_TABLE_MASK] + + quant_table[quant_table_idx][1][(top[0] - top[1]) & MAX_QUANT_TABLE_MASK] + + quant_table[quant_table_idx][2][(top[1] - top[2]) & MAX_QUANT_TABLE_MASK]; + + if (has_extend_lookup && extend_lookup) { + TYPE cur2 = linecache[0]; + base += quant_table[quant_table_idx][3][(cur2 - cur) & MAX_QUANT_TABLE_MASK]; + + /* top-2 became current upon swap when rgb_linecache == 2 */ + ivec2 top2_off = off; + if (rgb_linecache != 2) + top2_off += ivec2(0, -2); + + TYPE top2 = TYPE(imageLoad(pred, sp + LADDR(top2_off))[comp]); + base += quant_table[quant_table_idx][4][(top2 - top[1]) & MAX_QUANT_TABLE_MASK]; + } + + /* context, prediction */ + return ivec2(base, predict(cur, VTYPE2(top))); +} + +#else + +#define LADDR(p) (p) + +ivec2 get_pred(readonly uimage2D pred, ivec2 sp, ivec2 off, + uint comp, int sw, uint8_t quant_table_idx, bool extend_lookup) +{ + ivec2 yoff_border1 = off.x == 0 ? ivec2(1, -1) : ivec2(0, 0); + sp += off; + + VTYPE3 top = VTYPE3(TYPE(0), + TYPE(0), + TYPE(0)); + if (off.y > 0 && off != ivec2(0, 1)) + top[0] = TYPE(imageLoad(pred, sp + ivec2(-1, -1) + yoff_border1)[comp]); + if (off.y > 0) { + top[1] = TYPE(imageLoad(pred, sp + ivec2(0, -1))[comp]); + top[2] = TYPE(imageLoad(pred, sp + ivec2(min(1, sw - off.x - 1), -1))[comp]); + } + + TYPE cur = linecache[1]; + + int base = quant_table[quant_table_idx][0][(cur - top[0]) & MAX_QUANT_TABLE_MASK] + + quant_table[quant_table_idx][1][(top[0] - top[1]) & MAX_QUANT_TABLE_MASK] + + quant_table[quant_table_idx][2][(top[1] - top[2]) & MAX_QUANT_TABLE_MASK]; + + if (has_extend_lookup && extend_lookup) { + TYPE cur2 = linecache[0]; + base += quant_table[quant_table_idx][3][(cur2 - cur) & MAX_QUANT_TABLE_MASK]; + + TYPE top2 = TYPE(0); + if (off.y > 1) + top2 = TYPE(imageLoad(pred, sp + ivec2(0, -2))[comp]); + base += quant_table[quant_table_idx][4][(top2 - top[1]) & MAX_QUANT_TABLE_MASK]; + } + + /* context, prediction */ + return ivec2(base, predict(cur, VTYPE2(top))); +} + +#endif /* RGB */ + +void linecache_load(readonly uimage2D src, ivec2 sp, int y, uint comp) +{ + if (gl_LocalInvocationID.x == 0) { + linecache[0] = TYPE(0); + } else if (gl_LocalInvocationID.x == 1) { + TYPE c = TYPE(0); + if (y > 0) + c = TYPE(imageLoad(src, sp + LADDR(ivec2(0, y - 1)))[comp]); + linecache[1] = c; + } + barrier(); +} + +void linecache_next(TYPE cur) +{ + linecache[0] = linecache[1]; + linecache[1] = cur; +} + +#endif /* ENCODE || DECODE */ + +#endif /* VULKAN_FFV1_COMMON_H */ diff --git a/libavcodec/vulkan/ffv1_dec.comp.glsl b/libavcodec/vulkan/ffv1_dec.comp.glsl new file mode 100644 index 000000000..1c9eb46a7 --- /dev/null +++ b/libavcodec/vulkan/ffv1_dec.comp.glsl @@ -0,0 +1,368 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define DECODE +#include "common.glsl" +#include "ffv1_common.glsl" + +layout (set = 1, binding = 1, scalar) readonly buffer slice_offsets_buf { + u32vec2 slice_offsets[]; +}; +layout (set = 1, binding = 2, scalar) writeonly buffer slice_status_buf { + uint32_t slice_status[]; +}; +layout (set = 1, binding = 4) uniform uimage2D dec[]; + +#ifndef GOLOMB + +layout (set = 1, binding = 3, scalar) buffer slice_state_buf { + uint8_t slice_rc_state[]; +}; + +#define READ(idx) get_rac_state(idx) +shared int sym_e; +shared bool rc_dec[CONTEXT_SIZE]; +int get_isymbol(void) +{ + sym_e = 0; + rc_dec[0] = true; + if (READ(0)) + return 0; + + int e = 1; + for (; e < 11; e++) { + rc_dec[e] = true; + if (!READ(e)) + break; + } + + int a = 1; + sym_e = e + 10; + rc_dec[sym_e] = true; + + if (bits > 10 && e == 11) { + do { + rc_state[10] = zero_one_state[rc_state[10] + 256]; + e++; + } while (READ(10)); + + a = READ(31) ? 0x3 : 0x2; + for (e -= 2; e >= 11; e--) { + rc_state[31] = zero_one_state[rc_state[31] + + (rc_data[31] ? 256 : 0)]; + a <<= 1; + a |= int(READ(31)); + } + + rc_dec[31] = true; + } + + e += 20; + for (; e >= 22; e--) { + a <<= 1; + a |= int(READ(e)); + rc_dec[e] = true; + } + + return READ(sym_e) ? -a : a; +} + +void decode_line_pcm(ivec2 sp, int w, int y, int p) +{ + if (gl_LocalInvocationID.x > 0) + return; + +#ifndef RGB + if (p > 0 && p < 3) { + w = ceil_rshift(w, chroma_shift.x); + sp >>= chroma_shift; + } +#endif + + for (int x = 0; x < w; x++) { + uint v = 0; + + for (uint i = (rct_offset >> 1); i > 0; i >>= 1) + v |= get_rac_equi() ? i : 0; + + imageStore(dec[p], sp + LADDR(ivec2(x, y)), uvec4(v)); + } +} + +void decode_line(ivec2 sp, int w, + int y, int p, uint state_off, + uint8_t quant_table_idx, int run_index) +{ +#ifndef RGB + if (p > 0 && p < 3) { + w = ceil_rshift(w, chroma_shift.x); + sp >>= chroma_shift; + } +#endif + + linecache_load(dec[p], sp, y, 0); + + for (int x = 0; x < w; x++) { + ivec2 pr = get_pred(dec[p], sp, ivec2(x, y), 0, w, + quant_table_idx, extend_lookup[quant_table_idx]); + + uint rc_off = state_off + CONTEXT_SIZE*abs(pr[0]) + gl_LocalInvocationID.x; + + rc_dec[gl_LocalInvocationID.x] = false; + rc_state[gl_LocalInvocationID.x] = slice_rc_state[rc_off]; + barrier(); + + if (gl_LocalInvocationID.x == 0) { + int diff = get_isymbol(); + if (pr[0] < 0) + diff = -diff; + + uint v = zero_extend(pr[1] + diff, bits); + imageStore(dec[p], sp + LADDR(ivec2(x, y)), uvec4(v)); + linecache_next(TYPE(v)); + } + + /* Image write now visible to other invocs */ + barrier(); + if (rc_dec[gl_LocalInvocationID.x]) + slice_rc_state[rc_off] = + zero_one_state[rc_state[gl_LocalInvocationID.x] + + (rc_data[gl_LocalInvocationID.x] ? 256 : 0)]; + } +} + +#else /* GOLOMB */ + +layout (set = 1, binding = 3, scalar) buffer slice_state_buf { + VlcState slice_vlc_state[]; +}; + +GetBitContext gb; + +void golomb_init(void) +{ + if (version == 3 && micro_version > 1 || version > 3) + get_rac_internal(rc.range * 129 >> 8); + + uint64_t ac_byte_count = rc.bs_off - rc.bs_start - 1; + init_get_bits(gb, u8buf(rc.bs_start + ac_byte_count), + int(rc.bs_end - rc.bs_start - ac_byte_count)); +} + +void decode_line(ivec2 sp, int w, + int y, int p, uint state_off, + uint8_t quant_table_idx, inout int run_index) +{ +#ifndef RGB + if (p > 0 && p < 3) { + w = ceil_rshift(w, chroma_shift.x); + sp >>= chroma_shift; + } +#endif + + linecache_load(dec[p], sp, y, 0); + + int run_count = 0; + int run_mode = 0; + + for (int x = 0; x < w; x++) { + ivec2 pos = sp + ivec2(x, y); + int diff; + ivec2 pr = get_pred(dec[p], sp, ivec2(x, y), 0, w, + quant_table_idx, extend_lookup[quant_table_idx]); + + uint vlc_off = state_off + abs(pr[0]); + + if (pr[0] == 0 && run_mode == 0) + run_mode = 1; + + if (run_mode != 0) { + if (run_count == 0 && run_mode == 1) { + int tmp_idx = int(log2_run[run_index]); + if (get_bit(gb)) { + run_count = 1 << tmp_idx; + if (x + run_count <= w) + run_index++; + } else { + if (tmp_idx != 0) { + run_count = int(get_bits(gb, tmp_idx)); + } else + run_count = 0; + + if (run_index != 0) + run_index--; + run_mode = 2; + } + } + + run_count--; + if (run_count < 0) { + run_mode = 0; + run_count = 0; + diff = read_vlc_symbol(gb, slice_vlc_state[vlc_off], bits); + if (diff >= 0) + diff++; + } else { + diff = 0; + } + } else { + diff = read_vlc_symbol(gb, slice_vlc_state[vlc_off], bits); + } + + if (pr[0] < 0) + diff = -diff; + + uint v = zero_extend(pr[1] + diff, bits); + imageStore(dec[p], sp + LADDR(ivec2(x, y)), uvec4(v)); + linecache_next(TYPE(v)); + } +} +#endif + +#ifdef RGB +ivec4 transform_sample(ivec4 pix, ivec2 rct_coef) +{ + pix.b -= rct_offset; + pix.r -= rct_offset; + pix.g -= (pix.b*rct_coef.g + pix.r*rct_coef.r) >> 2; + pix.b += pix.g; + pix.r += pix.g; + return ivec4(pix[fmt_lut[0]], pix[fmt_lut[1]], + pix[fmt_lut[2]], pix[fmt_lut[3]]); +} + +void writeout_rgb(in SliceContext sc, ivec2 sp, int w, int y, bool apply_rct) +{ + memoryBarrierImage(); + barrier(); + + for (uint x = gl_LocalInvocationID.x; x < w; x += gl_WorkGroupSize.x) { + ivec2 lpos = sp + LADDR(ivec2(x, y)); + ivec2 pos = sc.slice_pos + ivec2(x, y); + + ivec4 pix; + pix.r = int(imageLoad(dec[2], lpos)[0]); + pix.g = int(imageLoad(dec[0], lpos)[0]); + pix.b = int(imageLoad(dec[1], lpos)[0]); + if (transparency) + pix.a = int(imageLoad(dec[3], lpos)[0]); + + if (apply_rct) + pix = transform_sample(pix, sc.slice_rct_coef); + else + pix = ivec4(pix[fmt_lut[0]], pix[fmt_lut[1]], + pix[fmt_lut[2]], pix[fmt_lut[3]]); + + imageStore(dst[0], pos, pix); + if (planar_rgb) { + for (int i = 1; i < color_planes; i++) + imageStore(dst[i], pos, ivec4(pix[i])); + } + } +} +#endif + +void decode_slice(in SliceContext sc, uint slice_idx) +{ + int w = sc.slice_dim.x; + ivec2 sp = sc.slice_pos; + +#ifdef RGB + sp.y = int(gl_WorkGroupID.y)*rgb_linecache; +#endif + +#ifndef GOLOMB + /* PCM coding */ + if (sc.slice_coding_mode == 1) { +#ifdef RGB + for (int y = 0; y < sc.slice_dim.y; y++) { + for (int p = 0; p < color_planes; p++) + decode_line_pcm(sp, w, y, p); + + writeout_rgb(sc, sp, w, y, false); + } +#else + for (int p = 0; p < planes; p++) { + int h = sc.slice_dim.y; + if (p > 0 && p < 3) + h = ceil_rshift(h, chroma_shift.y); + + for (int y = 0; y < h; y++) + decode_line_pcm(sp, w, y, p); + } +#endif + return; + } +#endif + + u8vec4 quant_table_idx = sc.quant_table_idx.xyyz; + u32vec4 slice_state_off = (slice_idx*codec_planes + + uvec4(0, 1, 1, 2))*plane_state_size; + +#ifdef GOLOMB + slice_state_off >>= 3; // division by VLC_STATE_SIZE + golomb_init(); +#endif + +#ifdef RGB + int run_index = 0; + for (int y = 0; y < sc.slice_dim.y; y++) { + for (int p = 0; p < color_planes; p++) + decode_line(sp, w, y, p, + slice_state_off[p], quant_table_idx[p], run_index); + + writeout_rgb(sc, sp, w, y, true); + } +#else + for (int p = 0; p < planes; p++) { + int h = sc.slice_dim.y; + if (p > 0 && p < 3) + h = ceil_rshift(h, chroma_shift.y); + + int run_index = 0; + for (int y = 0; y < h; y++) + decode_line(sp, w, y, p, + slice_state_off[p], quant_table_idx[p], run_index); + } +#endif +} + +void main(void) +{ + uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + + if (gl_LocalInvocationID.x == 0) + rc = slice_ctx[slice_idx].c; + barrier(); + + decode_slice(slice_ctx[slice_idx], slice_idx); + + if (gl_LocalInvocationID.x == 0) { + uint overread = 0; + if (rc.bs_off >= (rc.bs_end + MAX_OVERREAD)) + overread = rc.bs_off - rc.bs_end; + slice_status[2*slice_idx + 1] = overread; + } +} diff --git a/libavcodec/vulkan/ffv1_dec_golomb.comp.glsl b/libavcodec/vulkan/ffv1_dec_golomb.comp.glsl new file mode 100644 index 000000000..4de62a488 --- /dev/null +++ b/libavcodec/vulkan/ffv1_dec_golomb.comp.glsl @@ -0,0 +1,27 @@ +/* + * FFv1 codec + * + * Copyright (c) 2026 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define GOLOMB +#include "ffv1_dec.comp.glsl" diff --git a/libavcodec/vulkan/ffv1_dec_reset.comp.glsl b/libavcodec/vulkan/ffv1_dec_reset.comp.glsl new file mode 100644 index 000000000..c5f28a195 --- /dev/null +++ b/libavcodec/vulkan/ffv1_dec_reset.comp.glsl @@ -0,0 +1,72 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define SB_QUALI readonly +#include "common.glsl" +#include "ffv1_common.glsl" + +#ifdef GOLOMB +#define PS_SHIFT 3 +layout (set = 1, binding = 1, scalar) writeonly buffer slice_state_buf { + VlcState slice_vlc_state[]; +}; +#else +#define PS_SHIFT 2 +layout (set = 1, binding = 1, scalar) writeonly buffer slice_state_buf { + uint32_t slice_rc_state[]; +}; +#endif + +void main(void) +{ + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + + if (!key_frame && !slice_ctx[slice_idx].slice_reset_contexts) + return; + + const uint8_t qidx = slice_ctx[slice_idx].quant_table_idx[gl_WorkGroupID.z]; + + uint contexts = context_count[qidx]; + uint plane_state_len = plane_state_size >> PS_SHIFT; + uint offs = slice_idx*plane_state_len*codec_planes + + gl_WorkGroupID.z*plane_state_len + + gl_LocalInvocationID.x; + +#ifdef GOLOMB + for (uint x = gl_LocalInvocationID.x; x < contexts; x += gl_WorkGroupSize.x) { + slice_vlc_state[offs].drift = int16_t(0); + slice_vlc_state[offs].error_sum = uint16_t(4); + slice_vlc_state[offs].bias = int8_t(0); + slice_vlc_state[offs].count = uint8_t(1); + offs += gl_WorkGroupSize.x; + } +#else + uint count_total = contexts*(CONTEXT_SIZE /* bytes */ >> 2 /* dwords */); + for (uint x = gl_LocalInvocationID.x; x < count_total; x += gl_WorkGroupSize.x) { + slice_rc_state[offs] = 0x80808080; + offs += gl_WorkGroupSize.x; + } +#endif +} diff --git a/libavcodec/vulkan/ffv1_dec_reset_golomb.comp.glsl b/libavcodec/vulkan/ffv1_dec_reset_golomb.comp.glsl new file mode 100644 index 000000000..8d7ff2723 --- /dev/null +++ b/libavcodec/vulkan/ffv1_dec_reset_golomb.comp.glsl @@ -0,0 +1,27 @@ +/* + * FFv1 codec + * + * Copyright (c) 2026 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define GOLOMB +#include "ffv1_dec_reset.comp.glsl" diff --git a/libavcodec/vulkan/ffv1_dec_rgb.comp.glsl b/libavcodec/vulkan/ffv1_dec_rgb.comp.glsl new file mode 100644 index 000000000..72dc31ba1 --- /dev/null +++ b/libavcodec/vulkan/ffv1_dec_rgb.comp.glsl @@ -0,0 +1,30 @@ +/* + * FFv1 codec + * + * Copyright (c) 2026 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_shader_image_load_formatted : require + +layout (set = 1, binding = 5) writeonly uniform uimage2D dst[]; + +#define RGB +#include "ffv1_dec.comp.glsl" diff --git a/libavcodec/vulkan/ffv1_dec_rgb_golomb.comp.glsl b/libavcodec/vulkan/ffv1_dec_rgb_golomb.comp.glsl new file mode 100644 index 000000000..8b9aadbd5 --- /dev/null +++ b/libavcodec/vulkan/ffv1_dec_rgb_golomb.comp.glsl @@ -0,0 +1,27 @@ +/* + * FFv1 codec + * + * Copyright (c) 2026 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define GOLOMB +#include "ffv1_dec_rgb.comp.glsl" diff --git a/libavcodec/vulkan/ffv1_dec_setup.comp.glsl b/libavcodec/vulkan/ffv1_dec_setup.comp.glsl new file mode 100644 index 000000000..2f2a1dcd9 --- /dev/null +++ b/libavcodec/vulkan/ffv1_dec_setup.comp.glsl @@ -0,0 +1,139 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#include "common.glsl" +#include "ffv1_common.glsl" + +layout (set = 0, binding = 1, scalar) uniform crc_ieee_buf { + uint32_t crc_ieee[256]; +}; + +layout (set = 1, binding = 1, scalar) readonly buffer slice_offsets_buf { + u32vec2 slice_offsets[]; +}; +layout (set = 1, binding = 2, scalar) writeonly buffer slice_status_buf { + uint32_t slice_status[]; +}; + +shared uint hdr_sym[4 + 4 + 3]; +const int nb_hdr_sym = 4 + codec_planes + 3; + +uint get_usymbol(void) +{ + if (get_rac(rc_state[0])) + return 0; + + int e = 0; + while (get_rac(rc_state[1 + min(e, 9)])) // 1..10 + e++; + + uint a = 1; + for (int i = e - 1; i >= 0; i--) { + a <<= 1; + a |= uint(get_rac(rc_state[22 + min(i, 9)])); // 22..31 + } + + return a; +} + +bool decode_slice_header(inout SliceContext sc) +{ + [[unroll]] + for (int i = 0; i < CONTEXT_SIZE; i++) + rc_state[i] = uint8_t(128); + + for (int i = 0; i < nb_hdr_sym; i++) + hdr_sym[i] = get_usymbol(); + + uint sx = hdr_sym[0]; + uint sy = hdr_sym[1]; + uint sw = hdr_sym[2] + 1; + uint sh = hdr_sym[3] + 1; + + if (sx < 0 || sy < 0 || sw <= 0 || sh <= 0 || + sx > (gl_NumWorkGroups.x - sw) || sy > (gl_NumWorkGroups.y - sh)) + return true; + + /* Set coordinates */ + uint sxs = slice_coord(img_size.x, sx , gl_NumWorkGroups.x, chroma_shift.x); + uint sxe = slice_coord(img_size.x, sx + sw, gl_NumWorkGroups.x, chroma_shift.x); + uint sys = slice_coord(img_size.y, sy , gl_NumWorkGroups.y, chroma_shift.y); + uint sye = slice_coord(img_size.y, sy + sh, gl_NumWorkGroups.y, chroma_shift.y); + + sc.slice_pos = ivec2(sxs, sys); + sc.slice_dim = ivec2(sxe - sxs, sye - sys); + sc.slice_rct_coef = ivec2(1, 1); + sc.slice_coding_mode = int(0); + + for (uint i = 0; i < codec_planes; i++) { + uint idx = hdr_sym[4 + i]; + if (idx >= quant_table_count) + return true; + sc.quant_table_idx[i] = uint8_t(idx); + } + + if (version >= 4) { + sc.slice_reset_contexts = get_rac(rc_state[0]); + sc.slice_coding_mode = get_usymbol(); + if (sc.slice_coding_mode != 1 && colorspace == 1) { + sc.slice_rct_coef.g = int(get_usymbol()); + sc.slice_rct_coef.r = int(get_usymbol()); + if (sc.slice_rct_coef.g + sc.slice_rct_coef.r > 4) + return true; + } + } + + return false; +} + +void main(void) +{ + uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + + rac_init_dec(slice_offsets[slice_idx].x, slice_offsets[slice_idx].y); + + if (slice_idx == (gl_NumWorkGroups.x*gl_NumWorkGroups.y - 1)) + get_rac_equi(); + + decode_slice_header(slice_ctx[slice_idx]); + + slice_ctx[slice_idx].c = rc; + + if (has_crc) { + u8buf bs = u8buf(slice_data + slice_offsets[slice_idx].x); + uint32_t slice_size = slice_offsets[slice_idx].y; + + uint32_t crc = crcref; + for (int i = 0; i < slice_size; i++) + crc = crc_ieee[(crc & 0xFF) ^ uint32_t(bs[i].v)] ^ (crc >> 8); + + slice_status[2*slice_idx + 0] = crc; + } + + uint overread = 0; + if (rc.bs_off >= (rc.bs_end + MAX_OVERREAD)) + overread = rc.bs_off - rc.bs_end; + slice_status[2*slice_idx + 1] = overread; +} diff --git a/libavcodec/vulkan/ffv1_enc.comp.glsl b/libavcodec/vulkan/ffv1_enc.comp.glsl new file mode 100644 index 000000000..7a212fd6b --- /dev/null +++ b/libavcodec/vulkan/ffv1_enc.comp.glsl @@ -0,0 +1,387 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define ENCODE +#include "common.glsl" +#include "ffv1_common.glsl" + +layout (set = 0, binding = 2, scalar) uniform crc_ieee_buf { + uint32_t crc_ieee[256]; +}; + +layout (set = 1, binding = 1, scalar) writeonly buffer slice_results_buf { + uint32_t slice_results[]; +}; +layout (set = 1, binding = 3) uniform uimage2D src[]; + +#ifndef GOLOMB + +layout (set = 1, binding = 2, scalar) buffer slice_state_buf { + uint8_t slice_rc_state[]; +}; + +#define WRITE(idx, val) put_rac(rc_state[idx], val) +void put_symbol(int v) +{ + bool is_nil = (v == 0); + WRITE(0, is_nil); + if (is_nil) + return; + + int a = abs(v); + int e = findMSB(a); + + for (int i = 0; i < e; i++) + WRITE(1 + min(i, 9), true); + WRITE(1 + min(e, 9), false); + + for (int i = e - 1; i >= 0; i--) + WRITE(22 + min(i, 9), bool(bitfieldExtract(a, i, 1))); + + WRITE(22 - 11 + min(e, 10), v < 0); +} + +void encode_line_pcm(in SliceContext sc, readonly uimage2D img, + ivec2 sp, int y, uint p, uint comp) +{ + if (gl_LocalInvocationID.x > 0) + return; + + int w = sc.slice_dim.x; + +#ifndef RGB + if (p > 0 && p < 3) { + w = ceil_rshift(w, chroma_shift.x); + sp >>= chroma_shift; + } +#endif + + for (int x = 0; x < w; x++) { + uint v = imageLoad(img, sp + LADDR(ivec2(x, y)))[comp]; + + for (uint i = (rct_offset >> 1); i > 0; i >>= 1) + put_rac_equi(bool(v & i)); + } +} + +void encode_line(in SliceContext sc, readonly uimage2D img, uint state_off, + ivec2 sp, int y, uint p, uint comp, + uint8_t quant_table_idx, in int run_index) +{ + int w = sc.slice_dim.x; + +#ifndef RGB + if (p > 0 && p < 3) { + w = ceil_rshift(w, chroma_shift.x); + sp >>= chroma_shift; + } +#endif + + linecache_load(img, sp, y, comp); + + for (int x = 0; x < w; x++) { + ivec2 d = get_pred(img, sp, ivec2(x, y), comp, w, + quant_table_idx, extend_lookup[quant_table_idx]); + TYPE cur = TYPE(imageLoad(img, sp + LADDR(ivec2(x, y)))[comp]); + d[1] = int(cur) - d[1]; + + if (d[0] < 0) + d = -d; + + d[1] = fold(d[1], bits); + + uint rc_off = state_off + CONTEXT_SIZE*d[0] + gl_LocalInvocationID.x; + + rc_state[gl_LocalInvocationID.x] = slice_rc_state[rc_off]; + barrier(); + + if (gl_LocalInvocationID.x == 0) { + put_symbol(d[1]); + linecache_next(cur); + } + + barrier(); + slice_rc_state[rc_off] = rc_state[gl_LocalInvocationID.x]; + } +} + +#else /* GOLOMB */ + +layout (set = 1, binding = 2, scalar) buffer slice_state_buf { + VlcState slice_vlc_state[]; +}; + +uint hdr_len = 0; +PutBitContext pb; + +void init_golomb(void) +{ + hdr_len = rac_terminate(); + init_put_bits(pb, OFFBUF(u8buf, rc.bs_start, hdr_len), + slice_size_max - hdr_len); +} + +void encode_line(in SliceContext sc, readonly uimage2D img, uint state_off, + ivec2 sp, int y, uint p, uint comp, + uint8_t quant_table_idx, inout int run_index) +{ + int w = sc.slice_dim.x; + +#ifndef RGB + if (p > 0 && p < 3) { + w = ceil_rshift(w, chroma_shift.x); + sp >>= chroma_shift; + } +#endif + + linecache_load(img, sp, y, comp); + + int run_count = 0; + bool run_mode = false; + + for (int x = 0; x < w; x++) { + ivec2 d = get_pred(img, sp, ivec2(x, y), comp, w, + quant_table_idx, extend_lookup[quant_table_idx]); + TYPE cur = TYPE(imageLoad(img, sp + LADDR(ivec2(x, y)))[comp]); + d[1] = int(cur) - d[1]; + linecache_next(cur); + + if (d[0] < 0) + d = -d; + + d[1] = fold(d[1], bits); + + if (d[0] == 0) + run_mode = true; + + if (run_mode) { + if (d[1] != 0) { + /* A very unlikely loop */ + while (run_count >= 1 << log2_run[run_index]) { + run_count -= 1 << log2_run[run_index]; + run_index++; + put_bits(pb, 1, 1); + } + + put_bits(pb, 1 + log2_run[run_index], run_count); + if (run_index != 0) + run_index--; + run_count = 0; + run_mode = false; + if (d[1] > 0) + d[1]--; + } else { + run_count++; + } + } + + if (!run_mode) { + Symbol sym = get_vlc_symbol(slice_vlc_state[state_off + d[0]], + d[1], bits); + put_bits(pb, sym.bits, sym.val); + } + } + + if (run_mode) { + while (run_count >= (1 << log2_run[run_index])) { + run_count -= 1 << log2_run[run_index]; + run_index++; + put_bits(pb, 1, 1); + } + + if (run_count > 0) + put_bits(pb, 1, 1); + } +} +#endif + +#ifdef RGB +const uvec4 rgb_plane_order = { 1, 2, 0, 3 }; + +ivec4 load_components(ivec2 pos) +{ + ivec4 pix = ivec4(imageLoad(src[0], pos)); + if (planar_rgb) { + for (int i = 1; i < (3 + int(transparency)); i++) + pix[i] = int(imageLoad(src[i], pos)[0]); + } + + return ivec4(pix[fmt_lut[0]], pix[fmt_lut[1]], + pix[fmt_lut[2]], pix[fmt_lut[3]]); +} + +void transform_sample(inout ivec4 pix, ivec2 rct_coef) +{ + pix.b -= pix.g; + pix.r -= pix.g; + pix.g += (pix.b*rct_coef.g + pix.r*rct_coef.r) >> 2; + pix.b += rct_offset; + pix.r += rct_offset; +} + +void preload_rgb(in SliceContext sc, ivec2 sp, int w, int y, bool apply_rct) +{ + for (uint x = gl_LocalInvocationID.x; x < w; x += gl_WorkGroupSize.x) { + ivec2 lpos = sp + LADDR(ivec2(x, y)); + ivec2 pos = sc.slice_pos + ivec2(x, y); + + ivec4 pix = load_components(pos); + + if (apply_rct) + transform_sample(pix, sc.slice_rct_coef); + + imageStore(tmp, lpos, pix); + } + + memoryBarrierImage(); + barrier(); +} +#endif + +void encode_slice(in SliceContext sc, uint slice_idx) +{ + ivec2 sp = sc.slice_pos; + +#ifdef RGB + sp.y = int(gl_WorkGroupID.y)*rgb_linecache; +#endif + +#ifndef GOLOMB + if (force_pcm) { +#ifndef RGB + for (int c = 0; c < color_planes; c++) { + + int h = sc.slice_dim.y; + if (c > 0 && c < 3) + h = ceil_rshift(h, chroma_shift.y); + + /* Takes into account dual-plane YUV formats */ + int p = min(c, planes - 1); + int comp = c - p; + + for (int y = 0; y < h; y++) + encode_line_pcm(sc, src[p], sp, y, p, comp); + } +#else + for (int y = 0; y < sc.slice_dim.y; y++) { + preload_rgb(sc, sp, sc.slice_dim.x, y, false); + + for (uint c = 0; c < color_planes; c++) + encode_line_pcm(sc, tmp, sp, y, 0, rgb_plane_order[c]); + } +#endif + return; + } +#endif + + u32vec4 slice_state_off = (slice_idx*codec_planes + + uvec4(0, 1, 1, 2))*plane_state_size; + +#ifdef GOLOMB + slice_state_off >>= 3; + init_golomb(); +#endif + +#ifndef RGB + for (uint c = 0; c < color_planes; c++) { + int run_index = 0; + + int h = sc.slice_dim.y; + if (c > 0 && c < 3) + h = ceil_rshift(h, chroma_shift.y); + + uint p = min(c, planes - 1); + uint comp = c - p; + + for (int y = 0; y < h; y++) + encode_line(sc, src[p], slice_state_off[c], sp, y, p, + comp, U8(context_model), run_index); + } +#else + int run_index = 0; + for (int y = 0; y < sc.slice_dim.y; y++) { + preload_rgb(sc, sp, sc.slice_dim.x, y, true); + + for (uint c = 0; c < color_planes; c++) + encode_line(sc, tmp, slice_state_off[c], + sp, y, 0, rgb_plane_order[c], + U8(context_model), run_index); + } +#endif +} + +void finalize_slice(in uint slice_idx) +{ +#ifdef GOLOMB + uint32_t enc_len = hdr_len + flush_put_bits(pb); +#else + uint32_t enc_len = rac_terminate(); +#endif + + u8buf bs = u8buf(slice_data + rc.bs_start); + + /* Append slice length */ + u8vec4 enc_len_p = unpack8(enc_len); + bs[enc_len + 0].v = enc_len_p.z; + bs[enc_len + 1].v = enc_len_p.y; + bs[enc_len + 2].v = enc_len_p.x; + enc_len += 3; + + /* Calculate and write CRC */ + if (has_crc) { + bs[enc_len].v = uint8_t(0); + enc_len++; + + uint32_t crc = crcref; + for (int i = 0; i < enc_len; i++) + crc = crc_ieee[(crc & 0xFF) ^ uint32_t(bs[i].v)] ^ (crc >> 8); + + if (crcref != 0x00000000) + crc ^= 0x8CD88196; + + u8vec4 crc_p = unpack8(crc); + bs[enc_len + 0].v = crc_p.x; + bs[enc_len + 1].v = crc_p.y; + bs[enc_len + 2].v = crc_p.z; + bs[enc_len + 3].v = crc_p.w; + enc_len += 4; + } + + slice_results[slice_idx] = enc_len; +} + +void main(void) +{ + uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + + if (gl_LocalInvocationID.x == 0) + rc = slice_ctx[slice_idx].c; + barrier(); + + encode_slice(slice_ctx[slice_idx], slice_idx); + + if (gl_LocalInvocationID.x == 0) + finalize_slice(slice_idx); +} diff --git a/libavcodec/vulkan/ffv1_enc_golomb.comp.glsl b/libavcodec/vulkan/ffv1_enc_golomb.comp.glsl new file mode 100644 index 000000000..19dba23af --- /dev/null +++ b/libavcodec/vulkan/ffv1_enc_golomb.comp.glsl @@ -0,0 +1,28 @@ +/* + * FFv1 codec + * + * Copyright (c) 2026 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define PB_UNALIGNED +#define GOLOMB +#include "ffv1_enc.comp.glsl" diff --git a/libavcodec/vulkan/ffv1_enc_rct_search.comp.glsl b/libavcodec/vulkan/ffv1_enc_rct_search.comp.glsl new file mode 100644 index 000000000..d72c667b1 --- /dev/null +++ b/libavcodec/vulkan/ffv1_enc_rct_search.comp.glsl @@ -0,0 +1,149 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define ENCODE +#define SB_QUALI +#include "common.glsl" +#include "ffv1_common.glsl" + +layout (set = 1, binding = 1) uniform uimage2D src[]; + +ivec3 load_components(ivec2 pos) +{ + ivec3 pix = ivec3(imageLoad(src[0], pos)); + if (planar_rgb) + for (int i = 1; i < 3; i++) + pix[i] = int(imageLoad(src[i], pos)[0]); + + return ivec3(pix[fmt_lut[0]], pix[fmt_lut[1]], pix[fmt_lut[2]]); +} + +#define NUM_CHECKS 15 +const ivec2 rct_y_coeff[NUM_CHECKS] = { + ivec2(0, 0), // 4G + + ivec2(0, 1), // 3G + B + ivec2(1, 0), // R + 3G + ivec2(1, 1), // R + 2G + B + + ivec2(0, 2), // 2G + 2B + ivec2(2, 0), // 2R + 2G + ivec2(2, 2), // 2R + 2B + + ivec2(0, 3), // 1G + 3B + ivec2(3, 0), // 3R + 1G + + ivec2(0, 4), // 4B + ivec2(4, 0), // 4R + + ivec2(1, 2), // R + G + 2B + ivec2(2, 1), // 2R + G + B + + ivec2(3, 1), // 3R + B + ivec2(1, 3), // R + 3B +}; + +shared ivec3 pix_buf[gl_WorkGroupSize.x + 1][gl_WorkGroupSize.y + 1] = { }; + +ivec3 transform_sample(ivec3 pix, ivec2 rct_coef) +{ + pix.b -= pix.g; + pix.r -= pix.g; + pix.g += (pix.b*rct_coef.g + pix.r*rct_coef.r) >> 2; + pix.b += rct_offset; + pix.r += rct_offset; + return pix; +} + +uint get_dist(ivec3 cur) +{ + ivec3 LL = pix_buf[gl_LocalInvocationID.x + 0][gl_LocalInvocationID.y + 1]; + ivec3 TL = pix_buf[gl_LocalInvocationID.x + 0][gl_LocalInvocationID.y + 0]; + ivec3 TT = pix_buf[gl_LocalInvocationID.x + 1][gl_LocalInvocationID.y + 0]; + + ivec3 pred = ivec3(predict(LL.r, ivec2(TL.r, TT.r)), + predict(LL.g, ivec2(TL.g, TT.g)), + predict(LL.b, ivec2(TL.b, TT.b))); + + uvec3 c = abs(pred - cur); + return mid_pred(c.r, c.g, c.b); +} + +shared uint score_cols[gl_WorkGroupSize.y] = { }; +shared uint score_mode[16] = { }; + +void process(ivec2 pos) +{ + ivec3 pix = load_components(pos); + + for (int i = 0; i < NUM_CHECKS; i++) { + ivec3 tx_pix = transform_sample(pix, rct_y_coeff[i]); + pix_buf[gl_LocalInvocationID.x + 1][gl_LocalInvocationID.y + 1] = tx_pix; + memoryBarrierShared(); + + uint dist = get_dist(tx_pix); + atomicAdd(score_mode[i], dist); + } +} + +void coeff_search(inout SliceContext sc) +{ + uvec2 img_size = imageSize(src[0]); + uint sxs = slice_coord(img_size.x, gl_WorkGroupID.x + 0, + gl_NumWorkGroups.x, 0); + uint sxe = slice_coord(img_size.x, gl_WorkGroupID.x + 1, + gl_NumWorkGroups.x, 0); + uint sys = slice_coord(img_size.y, gl_WorkGroupID.y + 0, + gl_NumWorkGroups.y, 0); + uint sye = slice_coord(img_size.y, gl_WorkGroupID.y + 1, + gl_NumWorkGroups.y, 0); + + for (uint y = sys + gl_LocalInvocationID.y; y < sye; y += gl_WorkGroupSize.y) { + for (uint x = sxs + gl_LocalInvocationID.x; x < sxe; x += gl_WorkGroupSize.x) { + process(ivec2(x, y)); + } + } + + if (gl_LocalInvocationID.x == 0 && gl_LocalInvocationID.y == 0) { + uint min_score = 0xFFFFFFFF; + uint min_idx = 3; + for (int i = 0; i < NUM_CHECKS; i++) { + if (score_mode[i] < min_score) { + min_score = score_mode[i]; + min_idx = i; + } + } + sc.slice_rct_coef = rct_y_coeff[min_idx]; + } +} + +void main(void) +{ + if (force_pcm) + return; + + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + coeff_search(slice_ctx[slice_idx]); +} diff --git a/libavcodec/vulkan/ffv1_enc_reset.comp.glsl b/libavcodec/vulkan/ffv1_enc_reset.comp.glsl new file mode 100644 index 000000000..549ad2d35 --- /dev/null +++ b/libavcodec/vulkan/ffv1_enc_reset.comp.glsl @@ -0,0 +1,67 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define SB_QUALI readonly +#include "common.glsl" +#include "ffv1_common.glsl" + +#ifdef GOLOMB +#define PS_SHIFT 3 +layout (set = 1, binding = 1, scalar) writeonly buffer slice_state_buf { + VlcState slice_vlc_state[]; +}; +#else +#define PS_SHIFT 2 +layout (set = 1, binding = 1, scalar) writeonly buffer slice_state_buf { + uint32_t slice_rc_state[]; +}; +#endif + +void main(void) +{ + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + + uint contexts = context_count[context_model]; + uint plane_state_len = plane_state_size >> PS_SHIFT; + uint offs = slice_idx*plane_state_len*codec_planes + + gl_WorkGroupID.z*plane_state_len + + gl_LocalInvocationID.x; + +#ifdef GOLOMB + for (uint x = gl_LocalInvocationID.x; x < contexts; x += gl_WorkGroupSize.x) { + slice_vlc_state[offs].drift = int16_t(0); + slice_vlc_state[offs].error_sum = uint16_t(4); + slice_vlc_state[offs].bias = int8_t(0); + slice_vlc_state[offs].count = uint8_t(1); + offs += gl_WorkGroupSize.x; + } +#else + uint count_total = contexts*(CONTEXT_SIZE /* bytes */ >> 2 /* dwords */); + for (uint x = gl_LocalInvocationID.x; x < count_total; x += gl_WorkGroupSize.x) { + slice_rc_state[offs] = 0x80808080; + offs += gl_WorkGroupSize.x; + } +#endif +} diff --git a/libavcodec/vulkan/ffv1_enc_reset_golomb.comp.glsl b/libavcodec/vulkan/ffv1_enc_reset_golomb.comp.glsl new file mode 100644 index 000000000..277f88c6c --- /dev/null +++ b/libavcodec/vulkan/ffv1_enc_reset_golomb.comp.glsl @@ -0,0 +1,27 @@ +/* + * FFv1 codec + * + * Copyright (c) 2026 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define GOLOMB +#include "ffv1_enc_reset.comp.glsl" diff --git a/libavcodec/vulkan/ffv1_enc_rgb.comp.glsl b/libavcodec/vulkan/ffv1_enc_rgb.comp.glsl new file mode 100644 index 000000000..90d136be1 --- /dev/null +++ b/libavcodec/vulkan/ffv1_enc_rgb.comp.glsl @@ -0,0 +1,30 @@ +/* + * FFv1 codec + * + * Copyright (c) 2026 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_shader_image_load_formatted : require + +layout (set = 1, binding = 4) uniform uimage2D tmp; + +#define RGB +#include "ffv1_enc.comp.glsl" diff --git a/libavcodec/vulkan/ffv1_enc_rgb_golomb.comp.glsl b/libavcodec/vulkan/ffv1_enc_rgb_golomb.comp.glsl new file mode 100644 index 000000000..eba2ec30f --- /dev/null +++ b/libavcodec/vulkan/ffv1_enc_rgb_golomb.comp.glsl @@ -0,0 +1,28 @@ +/* + * FFv1 codec + * + * Copyright (c) 2026 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define PB_UNALIGNED +#define GOLOMB +#include "ffv1_enc_rgb.comp.glsl" diff --git a/libavcodec/vulkan/ffv1_enc_setup.comp.glsl b/libavcodec/vulkan/ffv1_enc_setup.comp.glsl new file mode 100644 index 000000000..62e774ef8 --- /dev/null +++ b/libavcodec/vulkan/ffv1_enc_setup.comp.glsl @@ -0,0 +1,122 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define FULL_RENORM +#include "common.glsl" +#include "ffv1_common.glsl" + +void init_slice(inout SliceContext sc, uint slice_idx) +{ + /* Set coordinates */ + uint sxs = slice_coord(img_size.x, gl_WorkGroupID.x + 0, + gl_NumWorkGroups.x, chroma_shift.x); + uint sxe = slice_coord(img_size.x, gl_WorkGroupID.x + 1, + gl_NumWorkGroups.x, chroma_shift.x); + uint sys = slice_coord(img_size.y, gl_WorkGroupID.y + 0, + gl_NumWorkGroups.y, chroma_shift.y); + uint sye = slice_coord(img_size.y, gl_WorkGroupID.y + 1, + gl_NumWorkGroups.y, chroma_shift.y); + + sc.slice_pos = ivec2(sxs, sys); + sc.slice_dim = ivec2(sxe - sxs, sye - sys); + sc.slice_coding_mode = int(force_pcm); + sc.slice_reset_contexts = sc.slice_coding_mode == 1; + sc.quant_table_idx = u8vec3(context_model); + + if (!rct_search || force_pcm) + sc.slice_rct_coef = ivec2(1, 1); + + rac_init(slice_idx*slice_size_max, slice_size_max); +} + +void put_usymbol(uint v) +{ + bool is_nil = (v == 0); + put_rac(rc_state[0], is_nil); + if (is_nil) + return; + + const int e = findMSB(v); + + for (int i = 0; i <= e; i++) + put_rac(rc_state[1 + min(i, 9)], i < e); + + for (int i = e - 1; i >= 0; i--) + put_rac(rc_state[22 + min(i, 9)], bool(bitfieldExtract(v, i, 1))); +} + +shared uint hdr_sym[4 + 4 + 3]; +const int nb_hdr_sym = 4 + codec_planes + 3; + +void write_slice_header(inout SliceContext sc) +{ + [[unroll]] + for (int i = 0; i < CONTEXT_SIZE; i++) + rc_state[i] = uint8_t(128); + + hdr_sym[0] = gl_WorkGroupID.x; + hdr_sym[1] = gl_WorkGroupID.y; + hdr_sym[2] = 0; + hdr_sym[3] = 0; + + [[unroll]] + for (int i = 0; i < codec_planes; i++) + hdr_sym[4 + i] = context_model; + + hdr_sym[nb_hdr_sym - 3] = pic_mode; + hdr_sym[nb_hdr_sym - 2] = sar.x; + hdr_sym[nb_hdr_sym - 1] = sar.y; + + for (int i = 0; i < nb_hdr_sym; i++) + put_usymbol(hdr_sym[i]); + + if (version >= 4) { + put_rac(rc_state[0], force_pcm); + put_usymbol(uint(force_pcm)); + if (!force_pcm && colorspace == 1) { + put_usymbol(sc.slice_rct_coef.g); + put_usymbol(sc.slice_rct_coef.r); + } + } +} + +void write_frame_header(inout SliceContext sc) +{ + put_rac_equi(bool(key_frame)); +} + +void main(void) +{ + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + + init_slice(slice_ctx[slice_idx], slice_idx); + + if (slice_idx == 0) + write_frame_header(slice_ctx[slice_idx]); + + write_slice_header(slice_ctx[slice_idx]); + + slice_ctx[slice_idx].c = rc; +} diff --git a/libavcodec/vulkan/ffv1_vlc.glsl b/libavcodec/vulkan/ffv1_vlc.glsl new file mode 100644 index 000000000..f362d3afb --- /dev/null +++ b/libavcodec/vulkan/ffv1_vlc.glsl @@ -0,0 +1,163 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * 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 VULKAN_FFV1_VLC_H +#define VULKAN_FFV1_VLC_H + +struct VlcState { + uint32_t error_sum; + int16_t drift; + int8_t bias; + uint8_t count; +}; + +void update_vlc_state(inout VlcState state, in int v) +{ + int drift = state.drift; + int count = state.count; + int bias = state.bias; + state.error_sum += uint16_t(abs(v)); + drift += v; + + if (count == 128) { // FIXME: variable + count >>= 1; + drift >>= 1; + state.error_sum >>= 1; + } + count++; + + if (drift <= -count) { + bias = max(bias - 1, -128); + drift = max(drift + count, -count + 1); + } else if (drift > 0) { + bias = min(bias + 1, 127); + drift = min(drift - count, 0); + } + + state.bias = int8_t(bias); + state.drift = int16_t(drift); + state.count = uint8_t(count); +} + +struct Symbol { + uint32_t bits; + uint32_t val; +}; + +Symbol set_ur_golomb(int i, int k, int limit, int esc_len) +{ + int e; + Symbol sym; + +#ifdef DEBUG + if (i < 0) + debugPrintfEXT("Error: i is zero!"); +#endif + + e = i >> k; + if (e < limit) { + sym.bits = e + k + 1; + sym.val = (1 << k) + zero_extend(i, k); + } else { + sym.bits = limit + esc_len; + sym.val = i - limit + 1; + } + + return sym; +} + +/** + * write signed golomb rice code (ffv1). + */ +Symbol set_sr_golomb(int i, int k, int limit, int esc_len) +{ + int v; + + v = -2 * i - 1; + v ^= (v >> 31); + + return set_ur_golomb(v, k, limit, esc_len); +} + +Symbol get_vlc_symbol(inout VlcState state, int v, int bits) +{ + int i, k, code; + Symbol sym; + v = fold(v - int(state.bias), bits); + + i = state.count; + k = 0; + while (i < state.error_sum) { // FIXME: optimize + k++; + i += i; + } + +#ifdef DEBUG + if (k > 16) + debugPrintfEXT("Error: k > 16!"); +#endif + + code = v ^ ((2 * state.drift + state.count) >> 31); + + update_vlc_state(state, v); + + return set_sr_golomb(code, k, 12, bits); +} + +uint get_ur_golomb(inout GetBitContext gb, int k, int limit, int esc_len) +{ + for (uint i = 0; i < 12; i++) + if (get_bit(gb)) + return get_bits(gb, k) + (i << k); + + return get_bits(gb, esc_len) + 11; +} + +int get_sr_golomb(inout GetBitContext gb, int k, int limit, int esc_len) +{ + int v = int(get_ur_golomb(gb, k, limit, esc_len)); + return (v >> 1) ^ -(v & 1); +} + +int read_vlc_symbol(inout GetBitContext gb, inout VlcState state, int bits) +{ + int k, i, v, ret; + + i = state.count; + k = 0; + while (i < state.error_sum) { // FIXME: optimize + k++; + i += i; + } + + v = get_sr_golomb(gb, k, 12, bits); + + v ^= ((2 * state.drift + state.count) >> 31); + + ret = fold(v + state.bias, bits); + + update_vlc_state(state, v); + + return ret; +} + +#endif /* VULKAN_FFV1_VLC_H */ diff --git a/libavcodec/vulkan/prores_idct.comp.glsl b/libavcodec/vulkan/prores_idct.comp.glsl new file mode 100644 index 000000000..b514cb4c7 --- /dev/null +++ b/libavcodec/vulkan/prores_idct.comp.glsl @@ -0,0 +1,114 @@ +/* + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#include "common.glsl" +#include "dct.glsl" + +layout (constant_id = 0) const bool interlaced = false; + +layout (set = 0, binding = 0) readonly buffer quant_idx_buf { + uint8_t quant_idx[]; +}; +layout (set = 0, binding = 1) readonly buffer qmat_buf { + uint8_t qmat[]; +}; +layout (set = 0, binding = 2) uniform uimage2D dst[]; + +layout (push_constant, scalar) uniform pushConstants { + u8buf slice_data; + uint bitstream_size; + + uint16_t width; + uint16_t height; + uint16_t mb_width; + uint16_t mb_height; + uint16_t slice_width; + uint16_t slice_height; + uint8_t log2_slice_width; + uint8_t log2_chroma_w; + uint8_t depth; + uint8_t alpha_info; + uint8_t bottom_field; +}; + +uint get_px(uint tex_idx, ivec2 pos) +{ + if (interlaced) + pos = ivec2(pos.x, (pos.y << 1) + bottom_field); + return uint(imageLoad(dst[nonuniformEXT(tex_idx)], pos).x); +} + +void put_px(uint tex_idx, ivec2 pos, uint v) +{ + if (interlaced) + pos = ivec2(pos.x, (pos.y << 1) + bottom_field); + imageStore(dst[nonuniformEXT(tex_idx)], pos, uvec4(v)); +} + +void main(void) +{ + uvec3 gid = gl_GlobalInvocationID, lid = gl_LocalInvocationID; + uint comp = gid.z, block = (lid.y << 2) | (lid.x >> 3), idx = lid.x & 0x7; + uint chroma_shift = comp != 0 ? log2_chroma_w : 0; + bool act = gid.x < mb_width << (4 - chroma_shift); + + /** + * Normalize coefficients to [-1, 1] for increased precision during the iDCT. + * DCT coeffs have the range of a 12-bit signed integer (7.4 Inverse Transform). + */ + const float norm = 1.0f / (1 << 11); + + /* Coalesced load of DCT coeffs in shared memory, inverse quantization */ + if (act) { + /* Table 15 */ + uint8_t qidx = quant_idx[(gid.y >> 1) * mb_width + (gid.x >> (4 - chroma_shift))]; + int qscale = qidx > 128 ? (qidx - 96) << 2 : qidx, mat = int(gid.z != 0) << 6; + + [[unroll]] for (uint i = 0; i < 8; ++i) { + uint cidx = (i << 3) + idx; + int c = sign_extend(int(get_px(comp, ivec2(gid.x, (gid.y << 3) + i))), 16); + float v = float(c * qscale * int(qmat[mat + cidx])) * norm; + blocks[block][i * 9 + idx] = v * idct_scale[cidx]; + } + } + + /* Column-wise iDCT */ + idct8(block, idx, 9); + barrier(); + + /* Remap [-1, 1] to [0, 2] to remove a per-element addition in the output loop */ + blocks[block][idx * 9] += 1.0f; + + /* Row-wise iDCT */ + idct8(block, idx * 9, 1); + barrier(); + + float fact = 1 << (depth - 1); + int maxv = (1 << depth) - 1; + + /* 7.5.1 Color Component Samples. Rescale, clamp and write back to global memory */ + if (act) { + [[unroll]] for (uint i = 0; i < 8; ++i) { + float v = round(blocks[block][i * 9 + idx] * fact); + put_px(comp, ivec2(gid.x, (gid.y << 3) + i), clamp(int(v), 0, maxv)); + } + } +} diff --git a/libavcodec/vulkan/prores_ks_alpha_data.comp.glsl b/libavcodec/vulkan/prores_ks_alpha_data.comp.glsl new file mode 100644 index 000000000..434a15fde --- /dev/null +++ b/libavcodec/vulkan/prores_ks_alpha_data.comp.glsl @@ -0,0 +1,87 @@ +/* + * 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 + */ + +#version 460 +#pragma shader_stage(compute) + +#extension GL_EXT_shader_image_load_formatted : require +#extension GL_EXT_scalar_block_layout : require +#extension GL_EXT_shader_explicit_arithmetic_types : require + +layout (local_size_x_id = 253, local_size_y_id = 254, local_size_z_id = 255) in; + +layout (constant_id = 0) const int alpha_bits = 0; +layout (constant_id = 1) const int slices_per_row = 0; +layout (constant_id = 2) const int width_in_mb = 0; +layout (constant_id = 3) const int max_mbs_per_slice = 0; + +struct SliceData { + uint mbs_per_slice; + int16_t coeffs[4][8 * 256]; +}; + +layout (set = 0, binding = 0, scalar) writeonly buffer SliceBuffer { + SliceData slices[]; +}; +layout (set = 0, binding = 1) uniform readonly iimage2D plane; + +/* Table of possible edge slice configurations */ +const uvec3 edge_mps_table[8] = uvec3[]( + uvec3(0, 0, 0), + uvec3(1, 0, 0), + uvec3(2, 0, 0), + uvec3(2, 1, 0), + uvec3(4, 0, 0), + uvec3(4, 1, 0), + uvec3(4, 2, 0), + uvec3(4, 2, 1) +); + +void main() +{ + ivec2 coord = min(ivec2(gl_GlobalInvocationID.xy), imageSize(plane) - ivec2(1)); + uint16_t alpha = uint16_t(imageLoad(plane, coord).x); + + if (alpha_bits == 8) + alpha >>= 2; + else + alpha = (alpha << 6) | (alpha >> 4); + + uint mbs_per_slice = max_mbs_per_slice; + uint slices_width = width_in_mb / mbs_per_slice; + uint mb_width = slices_width * mbs_per_slice; + uint slice_x = gl_WorkGroupID.x / mbs_per_slice; + uint slice_y = gl_WorkGroupID.y; + uvec2 slice_base = uvec2(slice_x * mbs_per_slice * 16u, slice_y * 16u); + + /* Handle slice macroblock size reduction on edge slices */ + if (gl_WorkGroupID.x >= mb_width) { + uint edge_mb = gl_WorkGroupID.x - mb_width; + uvec3 table = edge_mps_table[width_in_mb - mb_width]; + uvec3 base = uvec3(0, table.x, table.x + table.y); + uint edge_slice = edge_mb < base.y ? 0 : (edge_mb < base.z ? 1 : 2); + slice_x += edge_slice; + slice_base.x += base[edge_slice] * 16u; + mbs_per_slice = table[edge_slice]; + } + + uint slice = slice_y * slices_per_row + slice_x; + uvec2 coeff_coord = uvec2(coord) - slice_base; + uint coeff = coeff_coord.y * (mbs_per_slice * 16u) + coeff_coord.x; + slices[slice].coeffs[3][coeff] = int16_t(alpha); +} diff --git a/libavcodec/vulkan/prores_ks_encode_slice.comp.glsl b/libavcodec/vulkan/prores_ks_encode_slice.comp.glsl new file mode 100644 index 000000000..7105ad8da --- /dev/null +++ b/libavcodec/vulkan/prores_ks_encode_slice.comp.glsl @@ -0,0 +1,273 @@ +/* + * 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 + */ + +#version 460 +#pragma shader_stage(compute) + +#extension GL_EXT_scalar_block_layout : require +#extension GL_EXT_shader_explicit_arithmetic_types : require +#extension GL_GOOGLE_include_directive : require + +#define PB_UNALIGNED +#include "common.glsl" + +layout (constant_id = 0) const int max_mbs_per_slice = 8; +layout (constant_id = 1) const int chroma_factor = 0; +layout (constant_id = 2) const int alpha_bits = 0; +layout (constant_id = 3) const int num_planes = 0; +layout (constant_id = 4) const int slices_per_picture = 0; +layout (constant_id = 5) const int max_quant = 0; + +struct SliceData { + uint32_t mbs_per_slice; + int16_t coeffs[4][8 * 256]; +}; + +struct SliceScore { + ivec4 bits[16]; + ivec4 score[16]; + int total_bits[16]; + int total_score[16]; + int overquant; + int buf_start; + int quant; +}; + +layout(push_constant, scalar) uniform EncodeSliceInfo { + u8buf bytestream; + u8vec2buf seek_table; +}; + +layout (set = 0, binding = 0, scalar) readonly buffer SliceBuffer { + SliceData slices[]; +}; +layout (set = 0, binding = 1, scalar) readonly buffer SliceScores { + SliceScore scores[]; +}; +layout (set = 0, binding = 2, scalar) uniform ProresDataTables { + int16_t qmat[128][64]; int16_t qmat_chroma[128][64]; +}; + +#define CFACTOR_Y444 3 + +void encode_vlc_codeword(inout PutBitContext pb, uint codebook, int val) +{ + /* number of prefix bits to switch between Rice and expGolomb */ + uint switch_bits = (codebook & 3) + 1; + uint rice_order = codebook >> 5; /* rice code order */ + uint exp_order = (codebook >> 2) & 7; /* exp golomb code order */ + + uint switch_val = switch_bits << rice_order; + + if (val >= switch_val) { + val -= int(switch_val - (1 << exp_order)); + int exponent = findMSB(val); + + put_bits(pb, exponent - exp_order + switch_bits, 0); + put_bits(pb, exponent + 1, val); + } else { + int exponent = val >> rice_order; + if (exponent != 0) + put_bits(pb, exponent, 0); + put_bits(pb, 1, 1); + if (rice_order != 0) + put_bits(pb, rice_order, zero_extend(val, rice_order)); + } +} + +#define GET_SIGN(x) ((x) >> 31) +#define MAKE_CODE(x) (((x) * 2) ^ GET_SIGN(x)) + +#define FIRST_DC_CB 0xB8 // rice_order = 5, exp_golomb_order = 6, switch_bits = 0 + +void encode_dcs(inout PutBitContext pb, bool is_chroma, int q) +{ + const uint8_t dc_codebook[7] = { U8(0x04), U8(0x28), U8(0x28), U8(0x4D), U8(0x4D), U8(0x70), U8(0x70) }; + + uint slice = gl_GlobalInvocationID.x; + uint plane = gl_GlobalInvocationID.y; + uint blocks_per_mb = is_chroma && chroma_factor != CFACTOR_Y444 ? 2 : 4; + uint blocks_per_slice = slices[slice].mbs_per_slice * blocks_per_mb; + int codebook = 5; + int scale = is_chroma ? qmat_chroma[q][0] : qmat[q][0]; + int coeff = slices[slice].coeffs[plane][0]; + int prev_dc = (coeff - 0x4000) / scale; + encode_vlc_codeword(pb, FIRST_DC_CB, MAKE_CODE(prev_dc)); + int sign = 0; + for (int i = 1; i < blocks_per_slice; i++) { + coeff = slices[slice].coeffs[plane][i]; + int dc = (coeff - 0x4000) / scale; + int delta = dc - prev_dc; + int new_sign = GET_SIGN(delta); + delta = (delta ^ sign) - sign; + int code = MAKE_CODE(delta); + encode_vlc_codeword(pb, dc_codebook[codebook], code); + codebook = min(code, 6); + sign = new_sign; + prev_dc = dc; + } +} + +void encode_acs(inout PutBitContext pb, bool is_chroma, int q) +{ + const uint8_t run_to_cb[16] = { U8(0x06), U8(0x06), U8(0x05), U8(0x05), U8(0x04), U8(0x29), + U8(0x29), U8(0x29), U8(0x29), U8(0x28), U8(0x28), U8(0x28), + U8(0x28), U8(0x28), U8(0x28), U8(0x4C) }; + + const uint8_t level_to_cb[10] = { U8(0x04), U8(0x0A), U8(0x05), U8(0x06), U8(0x04), U8(0x28), + U8(0x28), U8(0x28), U8(0x28), U8(0x4C) }; + + uint slice = gl_GlobalInvocationID.x; + uint plane = gl_GlobalInvocationID.y; + uint blocks_per_mb = is_chroma && chroma_factor != CFACTOR_Y444 ? 2 : 4; + uint blocks_per_slice = slices[slice].mbs_per_slice * blocks_per_mb; + int prev_run = 4; + int prev_level = 2; + int run = 0; + + for (uint i = 1; i < 64; i++) { + int quant = is_chroma ? qmat_chroma[q][i] : qmat[q][i]; + for (uint j = 0; j < blocks_per_slice; j++) { + uint idx = i * blocks_per_slice + j; + int coeff = slices[slice].coeffs[plane][idx]; + int level = coeff / quant; + if (level != 0) { + int abs_level = abs(level); + encode_vlc_codeword(pb, run_to_cb[prev_run], run); + encode_vlc_codeword(pb, level_to_cb[prev_level], abs_level - 1); + put_bits(pb, 1, zero_extend(GET_SIGN(level), 1)); + prev_run = min(run, 15); + prev_level = min(abs_level, 9); + run = 0; + } else { + run++; + } + } + } +} + +void encode_slice_plane(inout PutBitContext pb, int q) +{ + uint plane = gl_GlobalInvocationID.y; + bool is_chroma = plane == 1 || plane == 2; + encode_dcs(pb, is_chroma, q); + encode_acs(pb, is_chroma, q); +} + +void put_alpha_diff(inout PutBitContext pb, int cur, int prev) +{ + const int dbits = (alpha_bits == 8) ? 4 : 7; + const int dsize = 1 << dbits - 1; + int diff = cur - prev; + + diff = zero_extend(diff, alpha_bits); + if (diff >= (1 << alpha_bits) - dsize) + diff -= 1 << alpha_bits; + if (diff < -dsize || diff > dsize || diff == 0) { + put_bits(pb, 1, 1); + put_bits(pb, alpha_bits, diff); + } else { + put_bits(pb, 1, 0); + put_bits(pb, dbits - 1, abs(diff) - 1); + put_bits(pb, 1, int(diff < 0)); + } +} + +void put_alpha_run(inout PutBitContext pb, int run) +{ + if (run != 0) { + put_bits(pb, 1, 0); + if (run < 0x10) + put_bits(pb, 4, run); + else + put_bits(pb, 15, run); + } else { + put_bits(pb, 1, 1); + } +} + +void encode_alpha_plane(inout PutBitContext pb) +{ + uint slice = gl_GlobalInvocationID.x; + const int mask = (1 << alpha_bits) - 1; + const int num_coeffs = int(slices[slice].mbs_per_slice) * 256; + int prev = mask, cur; + int idx = 0; + int run = 0; + + cur = slices[slice].coeffs[3][idx++]; + put_alpha_diff(pb, cur, prev); + prev = cur; + do { + cur = slices[slice].coeffs[3][idx++]; + if (cur != prev) { + put_alpha_run(pb, run); + put_alpha_diff(pb, cur, prev); + prev = cur; + run = 0; + } else { + run++; + } + } while (idx < num_coeffs); + put_alpha_run(pb, run); +} + +u8vec2 byteswap16(int value) +{ + return unpack8(uint16_t(value)).yx; +} + +void main() +{ + uint slice = gl_GlobalInvocationID.x; + if (slice >= slices_per_picture) + return; + + uint plane = gl_GlobalInvocationID.y; + int q = scores[slice].quant; + int q_idx = min(q, max_quant + 1); + ivec4 bits = scores[slice].bits[q_idx]; + int slice_hdr_size = 2 * num_planes; + int slice_size = slice_hdr_size + ((bits.x + bits.y + bits.z + bits.w) / 8); + int buf_start = scores[slice].buf_start; + u8buf buf = OFFBUF(u8buf, bytestream, buf_start); + + /* Write slice header */ + if (plane == 0) { + buf[0].v = uint8_t(slice_hdr_size * 8); + buf[1].v = uint8_t(q); + u8vec2buf slice_hdr = OFFBUF(u8vec2buf, buf, 2); + for (int i = 0; i < num_planes - 1; i++) { + slice_hdr[i].v = byteswap16(bits[i] / 8); + } + seek_table[slice].v = byteswap16(slice_size); + } + + int plane_offset = 0; + for (int i = 0; i < plane; ++i) + plane_offset += bits[i] / 8; + + /* Encode slice plane */ + PutBitContext pb; + init_put_bits(pb, OFFBUF(u8buf, buf, slice_hdr_size + plane_offset), 0); + if (plane == 3) + encode_alpha_plane(pb); + else + encode_slice_plane(pb, q); + flush_put_bits(pb); +} diff --git a/libavcodec/vulkan/prores_ks_estimate_slice.comp.glsl b/libavcodec/vulkan/prores_ks_estimate_slice.comp.glsl new file mode 100644 index 000000000..fdaa1c810 --- /dev/null +++ b/libavcodec/vulkan/prores_ks_estimate_slice.comp.glsl @@ -0,0 +1,302 @@ +/* + * 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 + */ + +#version 460 +#pragma shader_stage(compute) + +#extension GL_EXT_scalar_block_layout : require +#extension GL_EXT_shader_explicit_arithmetic_types : require +#extension GL_KHR_shader_subgroup_clustered : require +#extension GL_KHR_shader_subgroup_shuffle : require +#extension GL_GOOGLE_include_directive : require + +#include "common.glsl" + +layout (constant_id = 0) const int max_mbs_per_slice = 8; +layout (constant_id = 1) const int chroma_factor = 0; +layout (constant_id = 2) const int alpha_bits = 0; +layout (constant_id = 3) const int num_planes = 0; +layout (constant_id = 4) const int slices_per_picture = 0; +layout (constant_id = 5) const int min_quant = 0; +layout (constant_id = 6) const int max_quant = 0; +layout (constant_id = 7) const int bits_per_mb = 0; + +struct SliceData { + uint32_t mbs_per_slice; + int16_t coeffs[4][8 * 256]; +}; + +struct SliceScore { + ivec4 bits[16]; + ivec4 score[16]; + int total_bits[16]; + int total_score[16]; + int overquant; + int buf_start; + int quant; +}; + +layout (set = 0, binding = 0, scalar) readonly buffer SliceBuffer { + SliceData slices[]; +}; +layout (set = 0, binding = 1, scalar) writeonly buffer SliceScores { + SliceScore scores[]; +}; +layout (set = 0, binding = 2, scalar) uniform ProresDataTables { + int16_t qmat[128][64]; + int16_t qmat_chroma[128][64]; +}; + +#define CFACTOR_Y444 3 + +#define GET_SIGN(x) ((x) >> 31) +#define MAKE_CODE(x) (((x) * 2) ^ GET_SIGN(x)) + +int estimate_vlc(uint codebook, int val) +{ + /* number of prefix bits to switch between Rice and expGolomb */ + uint switch_bits = (codebook & 3) + 1; + uint rice_order = codebook >> 5; /* rice code order */ + uint exp_order = (codebook >> 2) & 7; /* exp golomb code order */ + + uint switch_val = switch_bits << rice_order; + + if (val >= switch_val) { + val -= int(switch_val - (1 << exp_order)); + int exponent = findMSB(val); + return int(exponent * 2 - exp_order + switch_bits + 1); + } else { + return int((val >> rice_order) + rice_order + 1); + } +} + +#define FIRST_DC_CB 0xB8 // rice_order = 5, exp_golomb_order = 6, switch_bits = 0 + +int estimate_dcs(inout int error, uint slice, uint plane, uint q) +{ + const uint8_t dc_codebook[7] = { U8(0x04), U8(0x28), U8(0x28), U8(0x4D), U8(0x4D), U8(0x70), U8(0x70) }; + + uint blocks_per_mb = plane != 0 && chroma_factor != CFACTOR_Y444 ? 2 : 4; + uint blocks_per_slice = slices[slice].mbs_per_slice * blocks_per_mb; + int codebook = 5; + int coeff = slices[slice].coeffs[plane][0]; + int scale = plane != 0 ? qmat_chroma[q][0] : qmat[q][0]; + int prev_dc = (coeff - 0x4000) / scale; + int bits = estimate_vlc(FIRST_DC_CB, MAKE_CODE(prev_dc)); + int sign = 0; + + for (int i = 1; i < blocks_per_slice; ++i) { + coeff = slices[slice].coeffs[plane][i]; + int dc = (coeff - 0x4000) / scale; + error += abs(coeff - 0x4000) % scale; + int delta = dc - prev_dc; + int new_sign = GET_SIGN(delta); + delta = (delta ^ sign) - sign; + int code = MAKE_CODE(delta); + bits += estimate_vlc(dc_codebook[codebook], code); + codebook = min(code, 6); + sign = new_sign; + prev_dc = dc; + } + + return bits; +} + +#define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1)) +#define SCORE_LIMIT 1073741823 + +int estimate_acs(inout int error, uint slice, uint plane, uint q) +{ + const uint8_t run_to_cb[16] = { U8(0x06), U8(0x06), U8(0x05), U8(0x05), U8(0x04), U8(0x29), + U8(0x29), U8(0x29), U8(0x29), U8(0x28), U8(0x28), U8(0x28), + U8(0x28), U8(0x28), U8(0x28), U8(0x4C) }; + + const uint8_t level_to_cb[10] = { U8(0x04), U8(0x0A), U8(0x05), U8(0x06), U8(0x04), U8(0x28), + U8(0x28), U8(0x28), U8(0x28), U8(0x4C) }; + + uint blocks_per_mb = plane != 0 && chroma_factor != CFACTOR_Y444 ? 2 : 4; + uint blocks_per_slice = slices[slice].mbs_per_slice * blocks_per_mb; + uint max_coeffs = blocks_per_slice << 6; + int prev_run = 4; + int prev_level = 2; + int bits = 0; + int run = 0; + + for (uint i = 1; i < 64; i++) { + int quant = plane != 0 ? qmat_chroma[q][i] : qmat[q][i]; + for (uint j = 0; j < blocks_per_slice; j++) { + uint idx = i * blocks_per_slice + j; + int coeff = slices[slice].coeffs[plane][idx]; + int level = coeff / quant; + error += abs(coeff) % quant; + if (level != 0) { + int abs_level = abs(level); + bits += estimate_vlc(run_to_cb[prev_run], run); + bits += estimate_vlc(level_to_cb[prev_level], abs_level - 1) + 1; + prev_run = min(run, 15); + prev_level = min(abs_level, 9); + run = 0; + } else { + run++; + } + } + } + + return bits; +} + +int estimate_slice_plane(inout int error, uint slice, uint plane, uint q) +{ + int bits = 0; + bits += estimate_dcs(error, slice, plane, q); + bits += estimate_acs(error, slice, plane, q); + return FFALIGN(bits, 8); +} + +int est_alpha_diff(int cur, int prev) +{ + const int dbits = (alpha_bits == 8) ? 4 : 7; + const int dsize = 1 << dbits - 1; + int diff = cur - prev; + + diff = zero_extend(diff, alpha_bits); + if (diff >= (1 << alpha_bits) - dsize) + diff -= 1 << alpha_bits; + if (diff < -dsize || diff > dsize || diff == 0) + return alpha_bits + 1; + else + return dbits + 1; +} + +int estimate_alpha_plane(uint slice) +{ + const int mask = (1 << alpha_bits) - 1; + const int num_coeffs = int(slices[slice].mbs_per_slice) * 256; + int prev = mask, cur; + int idx = 0; + int run = 0; + int bits; + + cur = slices[slice].coeffs[3][idx++]; + bits = est_alpha_diff(cur, prev); + prev = cur; + do { + cur = slices[slice].coeffs[3][idx++]; + if (cur != prev) { + if (run == 0) + bits++; + else if (run < 0x10) + bits += 5; + else + bits += 16; + bits += est_alpha_diff(cur, prev); + prev = cur; + run = 0; + } else { + run++; + } + } while (idx < num_coeffs); + + if (run != 0) { + if (run < 0x10) + bits += 5; + else + bits += 16; + } else { + bits++; + } + + return bits; +} + +int sum_of_planes(int value) +{ + if (num_planes == 3) { + uint base = (gl_SubgroupInvocationID / 3) * 3; + return subgroupShuffle(value, base) + subgroupShuffle(value, base + 1) + subgroupShuffle(value, base + 2); + } else + return subgroupClusteredAdd(value, 4); +} + +void main() +{ + uint slice = gl_GlobalInvocationID.x / num_planes; + uint plane = gl_LocalInvocationID.x % num_planes; + uint q = min_quant + gl_GlobalInvocationID.y; + if (slice >= slices_per_picture) + return; + + /* Estimate slice bits and error for specified quantizer and plane */ + int error = 0; + int bits = 0; + if (plane == 3) + bits = estimate_alpha_plane(slice); + else + bits = estimate_slice_plane(error, slice, plane, q); + + /* Write results to score buffer */ + scores[slice].bits[q][plane] = FFALIGN(bits, 8); + scores[slice].score[q][plane] = error; + + /* Accumulate total bits and error of all planes */ + int total_bits = sum_of_planes(bits); + int total_score = sum_of_planes(error); + if (total_bits > 65000 * 8) + total_score = SCORE_LIMIT; + scores[slice].total_bits[q] = total_bits; + scores[slice].total_score[q] = total_score; + + if (q != max_quant) + return; + + /* Task threads that computed max_quant to also compute overquant if necessary */ + uint mbs_per_slice = slices[slice].mbs_per_slice; + if (total_bits <= bits_per_mb * mbs_per_slice) { + /* Overquant isn't needed for this slice */ + scores[slice].total_bits[max_quant + 1] = total_bits; + scores[slice].total_score[max_quant + 1] = total_score + 1; + scores[slice].bits[max_quant + 1][plane] = FFALIGN(bits, 8); + scores[slice].score[max_quant + 1][plane] = error; + scores[slice].overquant = int(max_quant); + } else { + /* Keep searching until an encoding fits our budget */ + for (q = max_quant + 1; q < 128; ++q) { + /* Estimate slice bits and error for specified quantizer and plane */ + error = 0; + bits = 0; + if (plane == 3) + bits = estimate_alpha_plane(slice); + else + bits = estimate_slice_plane(error, slice, plane, q); + + /* Accumulate total bits and error of all planes */ + total_bits = sum_of_planes(bits); + total_score = sum_of_planes(error); + + /* If estimated bits fit within budget, we are done */ + if (total_bits <= bits_per_mb * mbs_per_slice) + break; + } + + scores[slice].bits[max_quant + 1][plane] = bits; + scores[slice].score[max_quant + 1][plane] = error; + scores[slice].total_bits[max_quant + 1] = total_bits; + scores[slice].total_score[max_quant + 1] = total_score; + scores[slice].overquant = int(q); + } +} diff --git a/libavcodec/vulkan/prores_ks_slice_data.comp.glsl b/libavcodec/vulkan/prores_ks_slice_data.comp.glsl new file mode 100644 index 000000000..be87b7e03 --- /dev/null +++ b/libavcodec/vulkan/prores_ks_slice_data.comp.glsl @@ -0,0 +1,179 @@ +/* + * 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 + */ + +#version 460 +#pragma shader_stage(compute) + +#extension GL_EXT_scalar_block_layout : require +#extension GL_EXT_shared_memory_block : require +#extension GL_GOOGLE_include_directive : require + +#include "common.glsl" +#include "dct.glsl" + +layout (constant_id = 0) const int max_mbs_per_slice = 8; +layout (constant_id = 1) const int blocks_per_mb = 0; +layout (constant_id = 2) const int width_in_mb = 0; +layout (constant_id = 3) const int pictures_per_frame = 0; + +layout(push_constant, scalar) uniform SliceDataInfo { + int plane; + int line_add; + int bits_per_sample; +}; + +struct SliceData { + uint32_t mbs_per_slice; + i16vec4 rows[4][8 * 32][2]; +}; + +layout (set = 0, binding = 0, scalar) writeonly buffer SliceBuffer { + SliceData slices[]; +}; +layout (set = 0, binding = 1) uniform readonly iimage2D planes[3]; + +/* Table of possible edge slice configurations */ +const uvec3 edge_mps_table[8] = uvec3[]( + uvec3(0, 0, 0), + uvec3(1, 0, 0), + uvec3(2, 0, 0), + uvec3(2, 1, 0), + uvec3(4, 0, 0), + uvec3(4, 1, 0), + uvec3(4, 2, 0), + uvec3(4, 2, 1) +); + +const u8vec2 progressive_scan[64] = { + u8vec2(0, 0), u8vec2(1, 0), u8vec2(0, 1), u8vec2(1, 1), + u8vec2(2, 0), u8vec2(3, 0), u8vec2(2, 1), u8vec2(3, 1), + u8vec2(0, 2), u8vec2(1, 2), u8vec2(0, 3), u8vec2(1, 3), + u8vec2(2, 2), u8vec2(3, 2), u8vec2(2, 3), u8vec2(3, 3), + u8vec2(4, 0), u8vec2(5, 0), u8vec2(4, 1), u8vec2(4, 2), + u8vec2(5, 1), u8vec2(6, 0), u8vec2(7, 0), u8vec2(6, 1), + u8vec2(5, 2), u8vec2(4, 3), u8vec2(5, 3), u8vec2(6, 2), + u8vec2(7, 1), u8vec2(7, 2), u8vec2(6, 3), u8vec2(7, 3), + u8vec2(0, 4), u8vec2(1, 4), u8vec2(0, 5), u8vec2(0, 6), + u8vec2(1, 5), u8vec2(2, 4), u8vec2(3, 4), u8vec2(2, 5), + u8vec2(1, 6), u8vec2(0, 7), u8vec2(1, 7), u8vec2(2, 6), + u8vec2(3, 5), u8vec2(4, 4), u8vec2(5, 4), u8vec2(4, 5), + u8vec2(3, 6), u8vec2(2, 7), u8vec2(3, 7), u8vec2(4, 6), + u8vec2(5, 5), u8vec2(6, 4), u8vec2(7, 4), u8vec2(6, 5), + u8vec2(5, 6), u8vec2(4, 7), u8vec2(5, 7), u8vec2(6, 6), + u8vec2(7, 5), u8vec2(7, 6), u8vec2(6, 7), u8vec2(7, 7), +}; + +const u8vec2 interlaced_scan[64] = { + u8vec2(0, 0), u8vec2(0, 1), u8vec2(1, 0), u8vec2(1, 1), + u8vec2(0, 2), u8vec2(0, 3), u8vec2(1, 2), u8vec2(1, 3), + u8vec2(2, 0), u8vec2(2, 1), u8vec2(3, 0), u8vec2(3, 1), + u8vec2(2, 2), u8vec2(2, 3), u8vec2(3, 2), u8vec2(3, 3), + u8vec2(0, 4), u8vec2(0, 5), u8vec2(1, 4), u8vec2(2, 4), + u8vec2(1, 5), u8vec2(0, 6), u8vec2(0, 7), u8vec2(1, 6), + u8vec2(2, 5), u8vec2(3, 4), u8vec2(3, 5), u8vec2(2, 6), + u8vec2(1, 7), u8vec2(2, 7), u8vec2(3, 6), u8vec2(3, 7), + u8vec2(4, 0), u8vec2(4, 1), u8vec2(5, 0), u8vec2(6, 0), + u8vec2(5, 1), u8vec2(4, 2), u8vec2(4, 3), u8vec2(5, 2), + u8vec2(6, 1), u8vec2(7, 0), u8vec2(7, 1), u8vec2(6, 2), + u8vec2(5, 3), u8vec2(4, 4), u8vec2(4, 5), u8vec2(5, 4), + u8vec2(6, 3), u8vec2(7, 2), u8vec2(7, 3), u8vec2(6, 4), + u8vec2(5, 5), u8vec2(4, 6), u8vec2(4, 7), u8vec2(5, 6), + u8vec2(6, 5), u8vec2(7, 4), u8vec2(7, 5), u8vec2(6, 6), + u8vec2(5, 7), u8vec2(6, 7), u8vec2(7, 6), u8vec2(7, 7), +}; + +#define DCTSIZE 8 + +int16_t get_swizzled_coeff(uint blocks_per_slice, uint slice_row, uint idx) +{ + uint coeff = slice_row * DCTSIZE + idx; + u8vec2 coord = pictures_per_frame == 1 ? progressive_scan[coeff / blocks_per_slice] + : interlaced_scan[coeff / blocks_per_slice]; + uint block = coeff % blocks_per_slice; + float v = blocks[block][coord.y * 9 + coord.x]; + return int16_t(v * float(1 << 11)); +} + +void main() +{ + uint row = gl_LocalInvocationID.x; + uint block = gl_LocalInvocationID.y; + uint macroblock = gl_LocalInvocationID.z; + uint slice_x = gl_WorkGroupID.x; + uint slice_block = macroblock * blocks_per_mb + block; + uint slice = gl_WorkGroupID.y * gl_NumWorkGroups.x + slice_x; + + /* Calculate the current thread coordinate in input plane */ + uint mbs_per_slice = max_mbs_per_slice; + uint mb_width = 4u * blocks_per_mb; + uint slices_width = width_in_mb / max_mbs_per_slice; + uvec2 slice_base = gl_WorkGroupID.xy * uvec2(max_mbs_per_slice * mb_width, DCTSIZE * 2u); + + /* Handle slice macroblock size reduction on edge slices */ + if (slice_x >= slices_width) { + uint edge_slice = slice_x - slices_width; + uvec3 table = edge_mps_table[width_in_mb - slices_width * max_mbs_per_slice]; + uvec3 base = uvec3(0u, table.x, table.x + table.y); + slice_base.x = (max_mbs_per_slice * slices_width + base[edge_slice]) * mb_width; + mbs_per_slice = table[edge_slice]; + } + + uvec2 mb_base = slice_base + uvec2(macroblock * mb_width, 0u); + uvec2 block_coord = plane != 0 ? uvec2(block >> 1u, block & 1u) : uvec2(block & 1u, block >> 1u); + ivec2 coord = ivec2(mb_base + block_coord * DCTSIZE + uvec2(0u, row)); + coord.y = coord.y * pictures_per_frame + line_add; + coord = min(coord, imageSize(planes[plane]) - ivec2(1)); + + /* Load and normalize coefficients to [-1, 1] for increased precision during the DCT. */ + [[unroll]] for (int i = 0; i < 8; i++) { + int c = imageLoad(planes[plane], coord + ivec2(i, 0)).x; + blocks[slice_block][row * 9 + i] = float(c) / (1 << (bits_per_sample - 1)); + } + + /* Row-wise DCT */ + fdct8(slice_block, row, 9); + barrier(); + + /* Column-wise DCT */ + fdct8(slice_block, row*9, 1); + barrier(); + + uint slice_row = slice_block * DCTSIZE + row; + uint blocks_per_slice = mbs_per_slice * blocks_per_mb; + + /** + * Swizzle coefficients in morton order before storing to output buffer. + * This allows for more cache friendly and coalesced coefficient loads. + */ + i16vec4 dst_low; + dst_low.x = get_swizzled_coeff(blocks_per_slice, slice_row, 0); + dst_low.y = get_swizzled_coeff(blocks_per_slice, slice_row, 1); + dst_low.z = get_swizzled_coeff(blocks_per_slice, slice_row, 2); + dst_low.w = get_swizzled_coeff(blocks_per_slice, slice_row, 3); + + i16vec4 dst_hi; + dst_hi.x = get_swizzled_coeff(blocks_per_slice, slice_row, 4); + dst_hi.y = get_swizzled_coeff(blocks_per_slice, slice_row, 5); + dst_hi.z = get_swizzled_coeff(blocks_per_slice, slice_row, 6); + dst_hi.w = get_swizzled_coeff(blocks_per_slice, slice_row, 7); + + /* Store DCT result to slice buffer */ + slices[slice].mbs_per_slice = mbs_per_slice; + slices[slice].rows[plane][slice_row][0] = dst_low; + slices[slice].rows[plane][slice_row][1] = dst_hi; +} diff --git a/libavcodec/vulkan/prores_ks_trellis_node.comp.glsl b/libavcodec/vulkan/prores_ks_trellis_node.comp.glsl new file mode 100644 index 000000000..a5e5203e1 --- /dev/null +++ b/libavcodec/vulkan/prores_ks_trellis_node.comp.glsl @@ -0,0 +1,194 @@ +/* + * 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 + */ + +#version 460 +#pragma shader_stage(compute) + +#extension GL_EXT_control_flow_attributes : require +#extension GL_EXT_scalar_block_layout : require +#extension GL_EXT_shader_explicit_arithmetic_types : require +#extension GL_KHR_shader_subgroup_arithmetic : require + +layout (local_size_x_id = 253, local_size_y_id = 254, local_size_z_id = 255) in; + +layout (constant_id = 0) const int slices_per_row = 1; +layout (constant_id = 1) const int num_subgroups = 1; +layout (constant_id = 2) const int num_planes = 0; +layout (constant_id = 3) const int force_quant = 0; +layout (constant_id = 4) const int min_quant = 0; +layout (constant_id = 5) const int max_quant = 0; +layout (constant_id = 6) const int mbs_per_slice = 0; +layout (constant_id = 7) const int bits_per_mb = 0; + +struct SliceScore { + ivec4 bits[16]; + ivec4 score[16]; + int total_bits[16]; + int total_score[16]; + int overquant; + int buf_start; + int quant; +}; + +layout (set = 0, binding = 0, scalar) writeonly buffer FrameSize { + int frame_size; +}; +layout (set = 0, binding = 1, scalar) buffer SliceScores { + SliceScore scores[]; +}; + +#define TRELLIS_WIDTH 16 +#define SCORE_LIMIT 1073741823 + +struct TrellisNode { + int prev_node; + int quant; + int bits; + int score; +}; + +shared int subgroup_sizes[num_subgroups]; + +int slice_sizes[slices_per_row]; + +TrellisNode nodes[(slices_per_row + 1) * TRELLIS_WIDTH]; + +int find_slice_quant(int slice_x) +{ + int slice = int(gl_LocalInvocationID.x) * slices_per_row + slice_x; + + int trellis_node = int(slice_x + 1) * TRELLIS_WIDTH; + [[unroll]] for (int q = min_quant; q < max_quant + 2; q++) { + nodes[trellis_node + q].prev_node = -1; + nodes[trellis_node + q].quant = q; + } + + int mbs = int(slice_x + 1) * mbs_per_slice; + nodes[trellis_node + max_quant + 1].quant = scores[slice].overquant; + + int bits_limit = mbs * bits_per_mb; + for (int pq = min_quant; pq < max_quant + 2; pq++) { + int prev = trellis_node - TRELLIS_WIDTH + pq; + for (int q = min_quant; q < max_quant + 2; q++) { + int cur = trellis_node + q; + int bits = nodes[prev].bits + scores[slice].total_bits[q]; + int error = scores[slice].total_score[q]; + if (bits > bits_limit) + error = SCORE_LIMIT; + + int new_score; + if (nodes[prev].score < SCORE_LIMIT && error < SCORE_LIMIT) + new_score = nodes[prev].score + error; + else + new_score = SCORE_LIMIT; + if (nodes[cur].prev_node == -1 || nodes[cur].score >= new_score) { + nodes[cur].bits = bits; + nodes[cur].score = new_score; + nodes[cur].prev_node = prev; + } + } + } + + int error = nodes[trellis_node + min_quant].score; + int pq = trellis_node + min_quant; + for (int q = min_quant + 1; q < max_quant + 2; q++) { + if (nodes[trellis_node + q].score <= error) { + error = nodes[trellis_node + q].score; + pq = trellis_node + q; + } + } + + return pq; +} + +int find_slice_row_quants() +{ + for (int i = min_quant; i < max_quant + 2; i++) { + nodes[i].prev_node = -1; + nodes[i].bits = 0; + nodes[i].score = 0; + } + + int q = 0; + for (int slice_x = 0; slice_x < slices_per_row; ++slice_x) { + q = find_slice_quant(slice_x); + } + + int slice_hdr_size = 2 * num_planes; + int slice_row_size = slice_hdr_size * slices_per_row; + int y = int(gl_LocalInvocationID.x); + for (int x = slices_per_row - 1; x >= 0; x--) { + int slice = x + y * slices_per_row; + int quant = nodes[q].quant; + int q_idx = min(quant, max_quant + 1); + ivec4 bits = scores[slice].bits[q_idx]; + slice_sizes[x] = (bits.x + bits.y + bits.z + bits.w) / 8; + slice_row_size += slice_sizes[x]; + scores[slice].quant = quant; + q = nodes[q].prev_node; + } + + return slice_row_size; +} + +int force_slice_row_quants() +{ + int slice_hdr_size = 2 * num_planes; + int slice_row_size = slice_hdr_size * slices_per_row; + int y = int(gl_LocalInvocationID.x); + for (int x = slices_per_row - 1; x >= 0; x--) { + int slice = x + y * slices_per_row; + ivec4 bits = scores[slice].bits[0]; + slice_sizes[x] = (bits.x + bits.y + bits.z + bits.w) / 8; + slice_row_size += slice_sizes[x]; + scores[slice].quant = force_quant; + } + + return slice_row_size; +} + +void main() +{ + int slice_row_size; + if (force_quant == 0) + slice_row_size = find_slice_row_quants(); + else + slice_row_size = force_slice_row_quants(); + + int subgroup_sum = subgroupAdd(slice_row_size); + subgroup_sizes[gl_SubgroupID] = subgroup_sum; + barrier(); + + int buf_start = subgroupExclusiveAdd(slice_row_size); + [[unroll]] for (int i = 0; i < num_subgroups; ++i) { + if (i >= gl_SubgroupID) + break; + buf_start += subgroup_sizes[i]; + } + + int slice_hdr_size = 2 * num_planes; + int y = int(gl_LocalInvocationID.x); + [[unroll]] for (int x = 0; x < slices_per_row; ++x) { + int slice = x + y * slices_per_row; + scores[slice].buf_start = buf_start; + buf_start += slice_hdr_size + slice_sizes[x]; + } + + if (y == gl_WorkGroupSize.x - 1) + frame_size = buf_start; +} diff --git a/libavcodec/vulkan/prores_raw_decode.comp.glsl b/libavcodec/vulkan/prores_raw_decode.comp.glsl new file mode 100644 index 000000000..88687da18 --- /dev/null +++ b/libavcodec/vulkan/prores_raw_decode.comp.glsl @@ -0,0 +1,253 @@ +/* + * ProRes RAW decoder + * + * Copyright (c) 2025 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#include "common.glsl" + +struct TileData { + ivec2 pos; + uint offset; + uint size; +}; + +layout (set = 0, binding = 0) uniform writeonly uimage2D dst; +layout (set = 0, binding = 1, scalar) readonly buffer frame_data_buf { + TileData tile_data[]; +}; + +layout (push_constant, scalar) uniform pushConstants { + u8buf pkt_data; + ivec2 tile_size; +}; + +#define COMP_ID (gl_LocalInvocationID.y) + +GetBitContext gb; + +#define DC_CB_MAX 12 +const uint8_t dc_cb[DC_CB_MAX + 1] = { + U8(16), U8(33), U8(50), U8(51), U8(51), U8(51), + U8(68), U8(68), U8(68), U8(68), U8(68), U8(68), U8(118) +}; + +#define AC_CB_MAX 94 +const int16_t ac_cb[AC_CB_MAX + 1] = { + I16( 0), I16(529), I16(273), I16(273), I16(546), I16(546), + I16(546), I16(290), I16(290), I16(290), I16(563), I16(563), + I16(563), I16(563), I16(563), I16(563), I16(563), I16(563), + I16(307), I16(307), I16(580), I16(580), I16(580), I16(580), + I16(580), I16(580), I16(580), I16(580), I16(580), I16(580), + I16(580), I16(580), I16(580), I16(580), I16(580), I16(580), + I16(580), I16(580), I16(580), I16(580), I16(580), I16(580), + I16(853), I16(853), I16(853), I16(853), I16(853), I16(853), + I16(853), I16(853), I16(853), I16(853), I16(853), I16(853), + I16(853), I16(853), I16(853), I16(853), I16(853), I16(853), + I16(853), I16(853), I16(853), I16(853), I16(853), I16(853), + I16(853), I16(853), I16(853), I16(853), I16(853), I16(853), + I16(853), I16(853), I16(853), I16(853), I16(853), I16(853), + I16(853), I16(853), I16(853), I16(853), I16(853), I16(853), + I16(853), I16(853), I16(853), I16(853), I16(853), I16(853), + I16(853), I16(853), I16(853), I16(853), I16(358) +}; + +#define RN_CB_MAX 27 +const int16_t rn_cb[RN_CB_MAX + 1] = { + I16(512), I16(256), I16( 0), I16( 0), I16(529), I16(529), I16(273), + I16(273), I16( 17), I16( 17), I16( 33), I16( 33), I16(546), I16( 34), + I16( 34), I16( 34), I16( 34), I16( 34), I16( 34), I16( 34), I16( 34), + I16( 34), I16( 34), I16( 34), I16( 34), I16( 50), I16( 50), I16( 68), +}; + +#define LN_CB_MAX 14 +const int16_t ln_cb[LN_CB_MAX + 1] = { + I16( 256), I16( 273), I16( 546), I16( 546), I16( 290), I16( 290), I16( 1075), + I16(1075), I16( 563), I16( 563), I16( 563), I16( 563), I16( 563), I16( 563), + I16( 51) +}; + +int16_t get_value(int16_t codebook) +{ + const int16_t switch_bits = codebook >> 8; + const int16_t rice_order = codebook & I16(0xf); + const int16_t exp_order = (codebook >> 4) & I16(0xf); + + uint32_t b = show_bits(gb, 32); + if (expectEXT(b == 0, false)) + return I16(0); + int16_t q = I16(31) - I16(findMSB(b)); + + if ((b & 0x80000000) != 0) { + skip_bits(gb, 1 + rice_order); + return I16((b & 0x7FFFFFFF) >> (31 - rice_order)); + } + + if (q <= switch_bits) { + skip_bits(gb, q + rice_order + 1); + return I16((q << rice_order) + + (((b << (q + 1)) >> 1) >> (31 - rice_order))); + } + + int16_t bits = exp_order + (q << 1) - switch_bits; + skip_bits(gb, bits); + return I16((b >> (32 - bits)) + + ((switch_bits + 1) << rice_order) - + (1 << exp_order)); +} + +#define TODCCODEBOOK(x) ((x + 1) >> 1) + +void store_val(ivec2 offs, int blk, int c, int16_t v) +{ + imageStore(dst, offs + 2*ivec2(blk*8 + (c & 7), c >> 3), + ivec4(v & 0xFFFF)); +} + +void read_dc_vals(ivec2 offs, int nb_blocks) +{ + int16_t dc, dc_add; + int16_t prev_dc = I16(0), sign = I16(0); + + /* Special handling for first block */ + dc = get_value(I16(700)); + prev_dc = (dc >> 1) ^ -(dc & I16(1)); + store_val(offs, 0, 0, prev_dc); + + for (int n = 1; n < nb_blocks; n++) { + if (expectEXT(left_bits(gb) <= 0, false)) + break; + + uint8_t dc_codebook; + if ((n & 15) == 1) + dc_codebook = uint8_t(100); + else + dc_codebook = dc_cb[min(TODCCODEBOOK(dc), 13 - 1)]; + + dc = get_value(dc_codebook); + + sign = sign ^ dc & int16_t(1); + dc_add = (-sign ^ I16(TODCCODEBOOK(dc))) + sign; + sign = I16(dc_add < 0); + prev_dc += dc_add; + + store_val(offs, n, 0, prev_dc); + } +} + +void read_ac_vals(ivec2 offs, int nb_blocks) +{ + const int nb_codes = nb_blocks << 6; + const int log2_nb_blocks = findMSB(nb_blocks); + const int block_mask = (1 << log2_nb_blocks) - 1; + + int16_t ac, rn, ln; + int16_t ac_codebook = I16(49); + int16_t rn_codebook = I16( 0); + int16_t ln_codebook = I16(66); + int16_t sign; + int16_t val; + + for (int n = nb_blocks; n <= nb_codes;) { + if (expectEXT(left_bits(gb) <= 0, false)) + break; + + ln = get_value(ln_codebook); + for (int i = 0; i < ln; i++) { + if (expectEXT(left_bits(gb) <= 0, false)) + break; + + if (expectEXT(n >= nb_codes, false)) + break; + + ac = get_value(ac_codebook); + ac_codebook = ac_cb[min(ac, 95 - 1)]; + sign = -int16_t(get_bit(gb)); + + val = ((ac + I16(1)) ^ sign) - sign; + store_val(offs, n & block_mask, n >> log2_nb_blocks, val); + + n++; + } + + if (expectEXT(n >= nb_codes, false)) + break; + + rn = get_value(rn_codebook); + rn_codebook = rn_cb[min(rn, 28 - 1)]; + + n += rn + 1; + if (expectEXT(n >= nb_codes, false)) + break; + + if (expectEXT(left_bits(gb) <= 0, false)) + break; + + ac = get_value(ac_codebook); + sign = -int16_t(get_bit(gb)); + + val = ((ac + I16(1)) ^ sign) - sign; + store_val(offs, n & block_mask, n >> log2_nb_blocks, val); + + ac_codebook = ac_cb[min(ac, 95 - 1)]; + ln_codebook = ln_cb[min(ac, 15 - 1)]; + + n++; + } +} + +void main(void) +{ + const uint tile_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + TileData td = tile_data[tile_idx]; + + int width = imageSize(dst).x; + if (expectEXT(td.pos.x >= width, false)) + return; + + uint64_t pkt_offset = uint64_t(pkt_data) + td.offset; + u8vec2buf hdr_data = u8vec2buf(pkt_offset); + int header_len = hdr_data[0].v.x >> 3; + + ivec4 size = ivec4(td.size, + pack16(hdr_data[2].v.yx), + pack16(hdr_data[1].v.yx), + pack16(hdr_data[3].v.yx)); + size[0] = size[0] - size[1] - size[2] - size[3] - header_len; + if (expectEXT(size[0] < 0, false)) + return; + + const ivec2 offs = td.pos + ivec2(COMP_ID & 1, COMP_ID >> 1); + const int w = min(tile_size.x, width - td.pos.x) >> 1; + const int nb_blocks = w >> 3; + + const ivec4 comp_offset = ivec4(size[2] + size[1] + size[3], + size[2], + 0, + size[2] + size[1]); + + init_get_bits(gb, u8buf(pkt_offset + header_len + comp_offset[COMP_ID]), + size[COMP_ID]); + + read_dc_vals(offs, nb_blocks); + read_ac_vals(offs, nb_blocks); +} diff --git a/libavcodec/vulkan/prores_raw_idct.comp.glsl b/libavcodec/vulkan/prores_raw_idct.comp.glsl new file mode 100644 index 000000000..04fb02805 --- /dev/null +++ b/libavcodec/vulkan/prores_raw_idct.comp.glsl @@ -0,0 +1,118 @@ +/* + * ProRes RAW decoder + * + * Copyright (c) 2025 Lynne + * + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#include "common.glsl" +#include "dct.glsl" + +struct TileData { + ivec2 pos; + uint offset; + uint size; +}; + +layout (set = 0, binding = 0) uniform uimage2D dst; +layout (set = 0, binding = 1, scalar) readonly buffer frame_data_buf { + TileData tile_data[]; +}; + +layout (push_constant, scalar) uniform pushConstants { + u8buf pkt_data; + ivec2 tile_size; + uint8_t qmat[64]; +}; + +#define COMP_ID (gl_LocalInvocationID.z) +#define BLOCK_ID (gl_LocalInvocationID.y) +#define ROW_ID (gl_LocalInvocationID.x) + +const u8vec2 scan[64] = { + u8vec2( 0, 0), u8vec2( 4, 0), u8vec2( 0, 2), u8vec2( 4, 2), + u8vec2( 0, 8), u8vec2( 4, 8), u8vec2( 6, 8), u8vec2( 2, 10), + u8vec2( 2, 0), u8vec2( 6, 0), u8vec2( 2, 2), u8vec2( 6, 2), + u8vec2( 2, 8), u8vec2( 8, 8), u8vec2( 0, 10), u8vec2( 4, 10), + u8vec2( 8, 0), u8vec2(12, 0), u8vec2( 8, 2), u8vec2(12, 2), + u8vec2(10, 8), u8vec2(14, 8), u8vec2( 6, 10), u8vec2( 2, 12), + u8vec2(10, 0), u8vec2(14, 0), u8vec2(10, 2), u8vec2(14, 2), + u8vec2(12, 8), u8vec2( 8, 10), u8vec2( 0, 12), u8vec2( 4, 12), + u8vec2( 0, 4), u8vec2( 4, 4), u8vec2( 6, 4), u8vec2( 2, 6), + u8vec2(10, 10), u8vec2(14, 10), u8vec2( 6, 12), u8vec2( 2, 14), + u8vec2( 2, 4), u8vec2( 8, 4), u8vec2( 0, 6), u8vec2( 4, 6), + u8vec2(12, 10), u8vec2( 8, 12), u8vec2( 0, 14), u8vec2( 4, 14), + u8vec2(10, 4), u8vec2(14, 4), u8vec2( 6, 6), u8vec2(12, 6), + u8vec2(10, 12), u8vec2(14, 12), u8vec2( 6, 14), u8vec2(12, 14), + u8vec2(12, 4), u8vec2( 8, 6), u8vec2(10, 6), u8vec2(14, 6), + u8vec2(12, 12), u8vec2( 8, 14), u8vec2(10, 14), u8vec2(14, 14), +}; + +void main(void) +{ + const uint tile_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + TileData td = tile_data[tile_idx]; + + int width = imageSize(dst).x; + if (expectEXT(td.pos.x >= width, false)) + return; + + uint64_t pkt_offset = uint64_t(pkt_data) + td.offset; + u8vec2buf hdr_data = u8vec2buf(pkt_offset); + int qscale = pack16(hdr_data[0].v.yx); + + const ivec2 offs = td.pos + ivec2(COMP_ID & 1, COMP_ID >> 1); + const uint w = min(tile_size.x, width - td.pos.x) >> 1; + const uint nb_blocks = w >> 3; + + /* We have to do non-uniform access, so copy it */ + uint8_t qmat_buf[64] = qmat; + + [[unroll]] + for (uint y = 0; y < 8; y++) { + uint block_off = y*8 + ROW_ID; + int v = int(imageLoad(dst, offs + 2*ivec2(BLOCK_ID*8, 0) + scan[block_off])[0]); + float vf = float(sign_extend(v, 16)) / 32768.0; + vf *= qmat_buf[block_off] * qscale; + blocks[BLOCK_ID][COMP_ID*72 + y*9 + ROW_ID] = (vf / (64*4.56)) * + idct_scale[block_off]; + } + + /* Column-wise iDCT */ + idct8(BLOCK_ID, COMP_ID*72 + ROW_ID, 9); + barrier(); + + blocks[BLOCK_ID][COMP_ID*72 + ROW_ID * 9] += 0.5f; + + /* Row-wise iDCT */ + idct8(BLOCK_ID, COMP_ID*72 + ROW_ID * 9, 1); + barrier(); + + [[unroll]] + for (uint y = 0; y < 8; y++) { + int v = int(round(blocks[BLOCK_ID][COMP_ID*72 + y*9 + ROW_ID]*4095.0)); + v = clamp(v, 0, 4095); + v <<= 4; + imageStore(dst, + offs + 2*ivec2(BLOCK_ID*8 + ROW_ID, y), + ivec4(v)); + } +} diff --git a/libavcodec/vulkan/prores_vld.comp.glsl b/libavcodec/vulkan/prores_vld.comp.glsl new file mode 100644 index 000000000..b0b17264a --- /dev/null +++ b/libavcodec/vulkan/prores_vld.comp.glsl @@ -0,0 +1,364 @@ +/* + * 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 + */ + +#pragma shader_stage(compute) +#extension GL_GOOGLE_include_directive : require + +#define GET_BITS_SMEM 4 +#include "common.glsl" + +layout (constant_id = 0) const bool interlaced = false; + +layout (set = 0, binding = 0) readonly buffer slice_offsets_buf { + uint32_t slice_offsets[]; +}; +layout (set = 0, binding = 1) writeonly buffer quant_idx_buf { + uint8_t quant_idx[]; +}; +layout (set = 0, binding = 2) uniform writeonly uimage2D dst[]; + +layout (push_constant, scalar) uniform pushConstants { + u8buf slice_data; + uint bitstream_size; + + uint16_t width; + uint16_t height; + uint16_t mb_width; + uint16_t mb_height; + uint16_t slice_width; + uint16_t slice_height; + uint8_t log2_slice_width; + uint8_t log2_chroma_w; + uint8_t depth; + uint8_t alpha_info; + uint8_t bottom_field; +}; + +/** + * Table 9, encoded as (last_rice_q << 0) | (krice or kexp << 4) | ((kexp or kexp + 1) << 8) + * According to the SMPTE document, abs(prev_dc_diff) should be used + * to index the table, duplicating the entries removes the abs operation. + */ +const uint16_t k_dc_codebook[] = { U16(0x100), + U16(0x210), U16(0x210), + U16(0x321), U16(0x321), + U16(0x430), U16(0x430), }; + +/* Table 10 */ +const uint16_t k_ac_run_codebook [] = { U16(0x102), U16(0x102), U16(0x101), U16(0x101), + U16(0x100), U16(0x211), U16(0x211), U16(0x211), + U16(0x211), U16(0x210), U16(0x210), U16(0x210), + U16(0x210), U16(0x210), U16(0x210), U16(0x320), }; +/* Table 11 */ +const uint16_t k_ac_level_codebook[] = { U16(0x202), U16(0x101), U16(0x102), U16(0x100), + U16(0x210), U16(0x210), U16(0x210), U16(0x210), + U16(0x320) }; + +/* Figure 4, encoded as (x << 0) | (y << 4) */ +const uint8_t k_scan_tbl[] = { + U8(0x00), U8(0x01), U8(0x10), U8(0x11), U8(0x02), U8(0x03), U8(0x12), U8(0x13), + U8(0x20), U8(0x21), U8(0x30), U8(0x31), U8(0x22), U8(0x23), U8(0x32), U8(0x33), + U8(0x04), U8(0x05), U8(0x14), U8(0x24), U8(0x15), U8(0x06), U8(0x07), U8(0x16), + U8(0x25), U8(0x34), U8(0x35), U8(0x26), U8(0x17), U8(0x27), U8(0x36), U8(0x37), + U8(0x40), U8(0x41), U8(0x50), U8(0x60), U8(0x51), U8(0x42), U8(0x43), U8(0x52), + U8(0x61), U8(0x70), U8(0x71), U8(0x62), U8(0x53), U8(0x44), U8(0x45), U8(0x54), + U8(0x63), U8(0x72), U8(0x73), U8(0x64), U8(0x55), U8(0x46), U8(0x47), U8(0x56), + U8(0x65), U8(0x74), U8(0x75), U8(0x66), U8(0x57), U8(0x67), U8(0x76), U8(0x77), +}; + +/* Figure 5 */ +const uint8_t k_scan_tbl_interlaced[] = { + U8(0x00), U8(0x10), U8(0x01), U8(0x11), U8(0x20), U8(0x30), U8(0x21), U8(0x31), + U8(0x02), U8(0x12), U8(0x03), U8(0x13), U8(0x22), U8(0x32), U8(0x23), U8(0x33), + U8(0x40), U8(0x50), U8(0x41), U8(0x42), U8(0x51), U8(0x60), U8(0x70), U8(0x61), + U8(0x52), U8(0x43), U8(0x53), U8(0x62), U8(0x71), U8(0x72), U8(0x63), U8(0x73), + U8(0x04), U8(0x14), U8(0x05), U8(0x06), U8(0x15), U8(0x24), U8(0x34), U8(0x25), + U8(0x16), U8(0x07), U8(0x17), U8(0x26), U8(0x35), U8(0x44), U8(0x54), U8(0x45), + U8(0x36), U8(0x27), U8(0x37), U8(0x46), U8(0x55), U8(0x64), U8(0x74), U8(0x65), + U8(0x56), U8(0x47), U8(0x57), U8(0x66), U8(0x75), U8(0x76), U8(0x67), U8(0x77), +}; + +shared uint16_t dc_codebook [k_dc_codebook .length()], + ac_run_codebook [k_ac_run_codebook .length()], + ac_level_codebook[k_ac_level_codebook.length()]; + +shared uint8_t scan_tbl[k_scan_tbl.length()]; + +void put_px(uint tex_idx, ivec2 pos, uint v) +{ + if (interlaced) + pos = ivec2(pos.x, (pos.y << 1) + bottom_field); + imageStore(dst[nonuniformEXT(tex_idx)], pos, uvec4(uint16_t(v))); +} + +/* 7.5.3 Pixel Arrangement */ +ivec2 pos_to_block(uint pos, uint luma) +{ + return ivec2((pos & -luma - 2) + luma >> 1, pos >> luma & 1) << 3; +} + +/* 7.1.1.2 Signed Golomb Combination Codes */ +uint to_signed(uint x) +{ + return (x >> 1) ^ -(x & 1); +} + +/* 7.1.1.1 Golomb Combination Codes */ +uint decode_codeword(inout GetBitContext gb, int codebook) +{ + int last_rice_q = bitfieldExtract(codebook, 0, 4), + krice = bitfieldExtract(codebook, 4, 4), + kexp = bitfieldExtract(codebook, 8, 4); + + int q = 31 - findMSB(show_bits(gb, 32)); + if (q <= last_rice_q) { + /* Golomb-Rice encoding */ + return (get_bits(gb, krice + q + 1) & ~(1 << krice)) + (q << krice); + } else { + /* exp-Golomb encoding */ + return get_bits(gb, (q << 1) + kexp - last_rice_q) - (1 << kexp) + ((last_rice_q + 1) << krice); + } +} + +void decode_comp(in GetBitContext gb, uvec2 mb_pos, uint mb_count) +{ + uvec3 gid = gl_GlobalInvocationID; + uint is_luma = uint(gid.z == 0); + uint chroma_shift = bool(is_luma) ? 0 : log2_chroma_w; + + uint num_blocks = mb_count << (2 - chroma_shift); + ivec2 base_pos = ivec2(mb_pos.x << (4 - chroma_shift), mb_pos.y << 4); + + /* 7.1.1.3 DC Coefficients */ + { + /* First coeff */ + uint c = to_signed(decode_codeword(gb, 0x650)); + put_px(gid.z, base_pos, c); + + uint cw = 5, prev_dc_diff = 0; + for (int i = 1; i < num_blocks; ++i) { + cw = decode_codeword(gb, dc_codebook[min(cw, 6)]); + + int s = int(prev_dc_diff) >> 31; + c += prev_dc_diff = (to_signed(cw) ^ s) - s; + + put_px(gid.z, base_pos + pos_to_block(i, is_luma), c); + } + } + + /* 7.1.1.4 AC Coefficients */ + { + uint block_mask = num_blocks - 1; + uint block_shift = findLSB(num_blocks); + + uint pos = num_blocks - 1, run = 4, level = 1, s; + while (pos < num_blocks << 6) { + int left = left_bits(gb); + if (left <= 0 || (left < 32 && show_bits(gb, left) == 0)) + break; + + run = decode_codeword(gb, ac_run_codebook [min(run, 15)]); + level = decode_codeword(gb, ac_level_codebook[min(level, 8 )]); + s = get_bits(gb, 1); + + pos += run + 1; + + uint bidx = pos & block_mask, scan = scan_tbl[pos >> block_shift]; + ivec2 spos = pos_to_block(bidx, is_luma); + ivec2 bpos = ivec2(scan & 0xf, scan >> 4); + + uint c = ((level + 1) ^ -s) + s; + put_px(gid.z, base_pos + spos + bpos, c); + } + } +} + +/* 7.1.2 Scanned Alpha */ +void decode_alpha(in GetBitContext gb, uvec2 mb_pos, uint mb_count) +{ + uvec3 gid = gl_GlobalInvocationID; + + ivec2 base_pos = ivec2(mb_pos) << 4; + uint block_shift = findMSB(mb_count) + 4, block_mask = (1 << block_shift) - 1; + + uint mask = (1 << (4 << alpha_info)) - 1; + uint num_values = (mb_count << 4) * min(height - (gid.y << 4), 16); + + int num_cw_bits = alpha_info == 1 ? 5 : 8, + num_flc_bits = alpha_info == 1 ? 9 : 17; + + uint alpha_rescale_lshift = alpha_info == 1 ? depth - 8 : 16, + alpha_rescale_rshift = 16 - depth; + + uint alpha = -1; + for (uint pos = 0; pos < num_values;) { + uint diff, run; + + /* Decode run value */ + { + uint bits = show_bits(gb, num_cw_bits), q = num_cw_bits - 1 - findMSB(bits); + + /* Tables 13/14 */ + if (q != 0) { + uint m = (bits >> 1) + 1, s = bits & 1; + diff = (m ^ -s) + s; + skip_bits(gb, num_cw_bits); + } else { + diff = get_bits(gb, num_flc_bits); + } + + alpha = alpha + diff & mask; + } + + /* Decode run length */ + { + uint bits = show_bits(gb, 5), q = 4 - findMSB(bits); + + /* Table 12 */ + if (q == 0) { + run = 1; + skip_bits(gb, 1); + } else if (q <= 4) { + run = bits + 1; + skip_bits(gb, 5); + } else { + run = get_bits(gb, 16) + 1; + } + + run = min(run, num_values - pos); + } + + /** + * FFmpeg doesn't support color and alpha with different precision, + * so we need to rescale to the color range. + */ + uint val = (alpha << alpha_rescale_lshift) | (alpha >> alpha_rescale_rshift); + for (uint end = pos + run; pos < end; ++pos) + put_px(3, base_pos + ivec2(pos & block_mask, pos >> block_shift), val); + } +} + +void main(void) +{ + uvec3 gid = gl_GlobalInvocationID; + if (gid.x >= slice_width || gid.y >= slice_height) + return; + + uint slice_idx = gid.y * slice_width + gid.x; + uint slice_off = slice_offsets[slice_idx], + slice_size = slice_offsets[slice_idx + 1] - slice_off; + + u8buf bs = u8buf(slice_data + slice_off); + + /* Decode slice header */ + uint hdr_size, qidx, y_size, u_size, v_size, a_size; + hdr_size = bs[0].v >> 3, qidx = clamp(bs[1].v, 1, 224); + y_size = (uint(bs[2].v) << 8) | bs[3].v; + u_size = (uint(bs[4].v) << 8) | bs[5].v; + + /** + * The alpha_info field can be 0 even when an alpha plane is present, + * if skip_alpha is enabled, so use the header size instead. + */ + if (hdr_size > 6) + v_size = (uint(bs[6].v) << 8) | bs[7].v; + else + v_size = slice_size - hdr_size - y_size - u_size; + + a_size = slice_size - hdr_size - y_size - u_size - v_size; + + bs += hdr_size; + int bs_size = 0; + switch (gid.z) { + case 0: + bs_size = int(y_size); + break; + case 1: + bs_size = int(u_size), bs += y_size; + break; + case 2: + bs_size = int(v_size), bs += y_size + u_size; + break; + case 3: + bs_size = int(a_size), bs += y_size + u_size + v_size; + break; + } + + GetBitContext gb; + init_get_bits(gb, bs, bs_size); + + /** + * Support for the grayscale "extension" in the prores_aw encoder. + * According to the spec, entropy coded data should never be empty, + * and instead contain at least the DC coefficients. + * This avoids undefined behavior. + */ + if (left_bits(gb) == 0) + return; + + /* Copy constant tables to local memory */ + dc_codebook = k_dc_codebook; + ac_run_codebook = k_ac_run_codebook; + ac_level_codebook = k_ac_level_codebook; + + if (!interlaced) + scan_tbl = k_scan_tbl; + else + scan_tbl = k_scan_tbl_interlaced; + + /** + * 4 ProRes Frame Structure + * ProRes tiles pictures into a grid of slices, whose size is determined + * by the log2_slice_width parameter (height is always 1 MB). + * Each slice has a width of (1 << log2_slice_width) MBs, until the picture + * cannot accommodate a full one. At this point, the remaining space + * is recursively completed using the first smaller power of two that fits + * (see Figure 1). + * The maximum number of extra slices is 3, when log2_slice_width is 3, + * with sizes 4, 2 and 1 MBs. + * The mb_width parameter therefore also represents the number of full slices, + * when interpreted as a fixed-point number with log2_slice_width fractional bits. + */ + uint frac = bitfieldExtract(uint(mb_width), 0, log2_slice_width), + num_extra = bitCount(frac); + + uint diff = slice_width - gid.x - 1, + off = max(int(diff - num_extra + 1) << 2, 0); + + uint log2_width = min(findLSB(frac - diff >> diff) + diff + off, log2_slice_width); + + uint mb_x = (min(gid.x, slice_width - num_extra) << log2_slice_width) + + (frac & (0xf << log2_width + 1)), + mb_y = gid.y; + uint mb_count = 1 << log2_width; + + if (gid.z < 3) { + /* Color entropy decoding, inverse scanning */ + decode_comp(gb, uvec2(mb_x, mb_y), mb_count); + } else { + /* Alpha entropy decoding */ + decode_alpha(gb, uvec2(mb_x, mb_y), mb_count); + } + + /* Forward the quantization index to the IDCT shader */ + if (gid.z == 0) { + uint base = mb_y * mb_width + mb_x; + for (uint i = 0; i < mb_count; ++i) + quant_idx[base + i] = uint8_t(qidx); + } +} diff --git a/libavcodec/vulkan/rangecoder.glsl b/libavcodec/vulkan/rangecoder.glsl new file mode 100644 index 000000000..f86f632ee --- /dev/null +++ b/libavcodec/vulkan/rangecoder.glsl @@ -0,0 +1,240 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * 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 VULKAN_RANGECODER_H +#define VULKAN_RANGECODER_H + +#define CONTEXT_SIZE 32 +#define MAX_OVERREAD 2 + +#if !defined(GOLOMB) && (defined(DECODE)) +#define RC_BTYPE readonly buffer +#else +#define RC_BTYPE uniform +#endif + +layout (set = 0, binding = 0, scalar) RC_BTYPE rangecoder_buf { + uint8_t zero_one_state[512]; +}; + +struct RangeCoder { + uint bs_start; + uint bs_off; + uint bs_end; + uint low; + uint range; + uint16_t outstanding_count; + uint8_t outstanding_byte; +}; + +shared RangeCoder rc; +shared uint8_t rc_state[CONTEXT_SIZE]; +shared bool rc_data[CONTEXT_SIZE]; + +void rac_init(uint bs_start, uint bs_len) +{ + rc.bs_start = bs_start; + rc.bs_off = bs_start; + rc.bs_end = bs_start + bs_len; + rc.low = 0; + rc.range = 0xFF00; + rc.outstanding_count = uint16_t(0); + rc.outstanding_byte = uint8_t(0xFF); +} + +#ifdef FULL_RENORM +/* Full renorm version that can handle outstanding_byte == 0xFF */ +void renorm_encoder(void) +{ + if (rc.outstanding_byte == 0xFF) { + rc.outstanding_byte = uint8_t(rc.low >> 8); + } else if (rc.low <= 0xFF00) { + slice_data[rc.bs_off++].v = rc.outstanding_byte; + uint16_t cnt = rc.outstanding_count; + for (; cnt > 0; cnt--) + slice_data[rc.bs_off++].v = uint8_t(0xFF); + rc.outstanding_count = uint16_t(0); + rc.outstanding_byte = uint8_t(rc.low >> 8); + } else if (rc.low >= 0x10000) { + slice_data[rc.bs_off++].v = rc.outstanding_byte + uint8_t(1); + uint16_t cnt = rc.outstanding_count; + for (; cnt > 0; cnt--) + slice_data[rc.bs_off++].v = uint8_t(0x00); + rc.outstanding_count = uint16_t(0); + rc.outstanding_byte = uint8_t(bitfieldExtract(rc.low, 8, 8)); + } else { + rc.outstanding_count++; + } + + rc.range <<= 8; + rc.low = bitfieldInsert(0, rc.low, 8, 8); +} + +#else + +/* Cannot deal with outstanding_byte == -1 in the name of speed */ +void renorm_encoder(void) +{ + uint16_t oc = rc.outstanding_count + uint16_t(1); + uint low = rc.low; + + rc.range <<= 8; + rc.low = bitfieldInsert(0, low, 8, 8); + + if (low > 0xFF00 && low < 0x10000) { + rc.outstanding_count = oc; + return; + } + + uint8_t outstanding_byte = rc.outstanding_byte; + + rc.outstanding_count = uint16_t(0); + rc.outstanding_byte = uint8_t(low >> 8); + + uint8_t obs = uint8_t(low > 0xFF00); + uint8_t fill = obs - uint8_t(1); /* unsigned underflow */ + + slice_data[rc.bs_off++].v = outstanding_byte + obs; + for (int i = 1; i < oc; i++) + slice_data[rc.bs_off++].v = fill; +} +#endif + +void put_rac_internal(in uint range1, bool bit) +{ +#ifdef DEBUG + if (range1 >= rc.range) + debugPrintfEXT("Error: range1 >= range"); + if (range1 <= 0) + debugPrintfEXT("Error: range1 <= 0"); +#endif + + uint ranged = rc.range - range1; + rc.low += bit ? ranged : 0; + rc.range = bit ? range1 : ranged; + + if (expectEXT(rc.range < 0x100, false)) + renorm_encoder(); +} + +void put_rac(inout uint8_t state, bool bit) +{ + put_rac_internal((rc.range * state) >> 8, bit); + state = zero_one_state[(uint(bit) << 8) + state]; +} + +void put_rac_equi(bool bit) +{ + put_rac_internal(rc.range >> 1, bit); +} + +void put_rac_terminate(void) +{ + uint range1 = (rc.range * 129) >> 8; + +#ifdef DEBUG + if (range1 >= rc.range) + debugPrintfEXT("Error: range1 >= c.range"); + if (range1 <= 0) + debugPrintfEXT("Error: range1 <= 0"); +#endif + + rc.range -= range1; + if (expectEXT(rc.range < 0x100, false)) + renorm_encoder(); +} + +/* Return the number of bytes written. */ +uint rac_terminate(void) +{ + put_rac_terminate(); + rc.range = uint16_t(0xFF); + rc.low += 0xFF; + renorm_encoder(); + rc.range = uint16_t(0xFF); + renorm_encoder(); + +#ifdef DEBUG + if (rc.low != 0) + debugPrintfEXT("Error: low != 0"); + if (rc.range < 0x100) + debugPrintfEXT("Error: range < 0x100"); +#endif + + return rc.bs_off - rc.bs_start; +} + +void rac_init_dec(uint bs_start, uint bs_len) +{ + /* Skip priming bytes */ + rac_init(bs_start + 2, bs_len - 2); + + u8vec2 prime = u8vec2buf(slice_data + bs_start).v; + /* Switch endianness of the priming bytes */ + rc.low = pack16(prime.yx); + + if (rc.low >= 0xFF00) { + rc.low = 0xFF00; + rc.bs_end = bs_start + 2; + } +} + +void refill(void) +{ + rc.range <<= 8; + rc.low <<= 8; + if (expectEXT(rc.bs_off < rc.bs_end, true)) + rc.low |= slice_data[rc.bs_off].v; + rc.bs_off++; +} + +bool get_rac_internal(in uint range1) +{ + uint ranged = rc.range - range1; + bool bit = rc.low >= ranged; + rc.low -= bit ? ranged : 0; + rc.range = (bit ? 0 : ranged) + (bit ? range1 : 0); + + if (expectEXT(rc.range < 0x100, false)) + refill(); + + return bit; +} + +bool get_rac(inout uint8_t state) +{ + bool bit = get_rac_internal(rc.range * state >> 8); + state = zero_one_state[state + (bit ? 256 : 0)]; + return bit; +} + +bool get_rac_state(uint idx) +{ + return (rc_data[idx] = get_rac_internal(rc.range * rc_state[idx] >> 8)); +} + +bool get_rac_equi(void) +{ + return get_rac_internal(rc.range >> 1); +} + +#endif /* VULKAN_RANGECODER_H */ diff --git a/libavcodec/vulkan_av1.c b/libavcodec/vulkan_av1.c index a0befb9c4..08c371746 100644 --- a/libavcodec/vulkan_av1.c +++ b/libavcodec/vulkan_av1.c @@ -26,6 +26,7 @@ const FFVulkanDecodeDescriptor ff_vk_dec_av1_desc = { .codec_id = AV_CODEC_ID_AV1, .decode_extension = FF_VK_EXT_VIDEO_DECODE_AV1, + .queue_flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR, .decode_op = VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR, .ext_props = { .extensionName = VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME, @@ -122,7 +123,7 @@ static int vk_av1_fill_pict(AVCodecContext *avctx, const AV1Frame **ref_src, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = ((has_grain || dec->dedicated_dpb) && ctx->common.layered_dpb) ? hp->frame_id : 0, - .imageViewBinding = vkpic->img_view_ref, + .imageViewBinding = vkpic->view.ref[0], }; *ref_slot = (VkVideoReferenceSlotInfoKHR) { @@ -138,23 +139,15 @@ static int vk_av1_fill_pict(AVCodecContext *avctx, const AV1Frame **ref_src, return 0; } -static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf) +static void vk_av1_params_fill(AVCodecContext *avctx, + StdVideoAV1TimingInfo *av1_timing_info, + StdVideoAV1ColorConfig *av1_color_config, + StdVideoAV1SequenceHeader *av1_sequence_header) { const AV1DecContext *s = avctx->priv_data; - FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; - FFVulkanDecodeShared *ctx = dec->shared_ctx; - const AV1RawSequenceHeader *seq = s->raw_seq; - StdVideoAV1SequenceHeader av1_sequence_header; - StdVideoAV1TimingInfo av1_timing_info; - StdVideoAV1ColorConfig av1_color_config; - VkVideoDecodeAV1SessionParametersCreateInfoKHR av1_params; - VkVideoSessionParametersCreateInfoKHR session_params_create; - - int err; - - av1_timing_info = (StdVideoAV1TimingInfo) { + *av1_timing_info = (StdVideoAV1TimingInfo) { .flags = (StdVideoAV1TimingInfoFlags) { .equal_picture_interval = seq->timing_info.equal_picture_interval, }, @@ -163,7 +156,7 @@ static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf) .num_ticks_per_picture_minus_1 = seq->timing_info.num_ticks_per_picture_minus_1, }; - av1_color_config = (StdVideoAV1ColorConfig) { + *av1_color_config = (StdVideoAV1ColorConfig) { .flags = (StdVideoAV1ColorConfigFlags) { .mono_chrome = seq->color_config.mono_chrome, .color_range = seq->color_config.color_range, @@ -178,7 +171,7 @@ static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf) .matrix_coefficients = seq->color_config.matrix_coefficients, }; - av1_sequence_header = (StdVideoAV1SequenceHeader) { + *av1_sequence_header = (StdVideoAV1SequenceHeader) { .flags = (StdVideoAV1SequenceHeaderFlags) { .still_picture = seq->still_picture, .reduced_still_picture_header = seq->reduced_still_picture_header, @@ -210,9 +203,26 @@ static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf) .order_hint_bits_minus_1 = seq->order_hint_bits_minus_1, .seq_force_integer_mv = seq->seq_force_integer_mv, .seq_force_screen_content_tools = seq->seq_force_screen_content_tools, - .pTimingInfo = &av1_timing_info, - .pColorConfig = &av1_color_config, + .pTimingInfo = av1_timing_info, + .pColorConfig = av1_color_config, }; +} + +static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf, + AV1VulkanDecodePicture *ap) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + + StdVideoAV1SequenceHeader av1_sequence_header; + StdVideoAV1TimingInfo av1_timing_info; + StdVideoAV1ColorConfig av1_color_config; + VkVideoDecodeAV1SessionParametersCreateInfoKHR av1_params; + VkVideoSessionParametersCreateInfoKHR session_params_create; + + vk_av1_params_fill(avctx, &av1_timing_info, &av1_color_config, + &av1_sequence_header); av1_params = (VkVideoDecodeAV1SessionParametersCreateInfoKHR) { .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR, @@ -235,14 +245,19 @@ static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf) } static int vk_av1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { int err; int ref_count = 0; AV1DecContext *s = avctx->priv_data; + const AV1RawSequenceHeader *seq = s->raw_seq; const AV1Frame *pic = &s->cur_frame; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + uint32_t frame_id_alloc_mask = 0; + uint16_t sb_shift = seq->use_128x128_superblock ? 5 : 4; + AV1VulkanDecodePicture *ap = pic->hwaccel_picture_private; FFVulkanDecodePicture *vp = &ap->vp; @@ -256,23 +271,24 @@ static int vk_av1_start_frame(AVCodecContext *avctx, STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_WIENER, STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_SGRPROJ }; - if (!dec->session_params) { - err = vk_av1_create_params(avctx, &dec->session_params); - if (err < 0) - return err; + /* Use the current frame_ids in ref[] to decide occupied frame_ids */ + for (int i = 0; i < STD_VIDEO_AV1_NUM_REF_FRAMES; i++) { + const AV1VulkanDecodePicture* rp = s->ref[i].hwaccel_picture_private; + if (rp) + frame_id_alloc_mask |= 1 << rp->frame_id; } if (!ap->frame_id_set) { unsigned slot_idx = 0; for (unsigned i = 0; i < 32; i++) { - if (!(dec->frame_id_alloc_mask & (1 << i))) { + if (!(frame_id_alloc_mask & (1 << i))) { slot_idx = i; break; } } ap->frame_id = slot_idx; ap->frame_id_set = 1; - dec->frame_id_alloc_mask |= (1 << slot_idx); + frame_id_alloc_mask |= (1 << slot_idx); } ap->ref_frame_sign_bias_mask = 0x0; @@ -345,7 +361,7 @@ static int vk_av1_start_frame(AVCodecContext *avctx, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = 0, - .imageViewBinding = vp->img_view_out, + .imageViewBinding = vp->view.out[0], }, }; @@ -484,8 +500,8 @@ static int vk_av1_start_frame(AVCodecContext *avctx, for (int i = 0; i < 64; i++) { ap->width_in_sbs_minus1[i] = frame_header->width_in_sbs_minus_1[i]; ap->height_in_sbs_minus1[i] = frame_header->height_in_sbs_minus_1[i]; - ap->mi_col_starts[i] = frame_header->tile_start_col_sb[i]; - ap->mi_row_starts[i] = frame_header->tile_start_row_sb[i]; + ap->mi_col_starts[i] = frame_header->tile_start_col_sb[i] << sb_shift; + ap->mi_row_starts[i] = frame_header->tile_start_row_sb[i] << sb_shift; } for (int i = 0; i < STD_VIDEO_AV1_MAX_SEGMENTS; i++) { @@ -577,17 +593,37 @@ static int vk_av1_end_frame(AVCodecContext *avctx) { const AV1DecContext *s = avctx->priv_data; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + const AV1Frame *pic = &s->cur_frame; AV1VulkanDecodePicture *ap = pic->hwaccel_picture_private; FFVulkanDecodePicture *vp = &ap->vp; FFVulkanDecodePicture *rvp[AV1_NUM_REF_FRAMES] = { 0 }; AVFrame *rav[AV1_NUM_REF_FRAMES] = { 0 }; +#ifdef VK_KHR_video_maintenance2 + StdVideoAV1SequenceHeader av1_sequence_header; + StdVideoAV1TimingInfo av1_timing_info; + StdVideoAV1ColorConfig av1_color_config; + VkVideoDecodeAV1InlineSessionParametersInfoKHR av1_params; + + if (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2) { + vk_av1_params_fill(avctx, &av1_timing_info, &av1_color_config, + &av1_sequence_header); + av1_params = (VkVideoDecodeAV1InlineSessionParametersInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_INLINE_SESSION_PARAMETERS_INFO_KHR, + .pStdSequenceHeader = &av1_sequence_header, + }; + ap->av1_pic_info.pNext = &av1_params; + } +#endif + if (!ap->av1_pic_info.tileCount) return 0; - if (!dec->session_params) { - int err = vk_av1_create_params(avctx, &dec->session_params); + if (!dec->session_params && + !(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) { + int err = vk_av1_create_params(avctx, &dec->session_params, ap); if (err < 0) return err; } @@ -600,21 +636,17 @@ static int vk_av1_end_frame(AVCodecContext *avctx) rav[i] = ap->ref_src[i]->f; } - av_log(avctx, AV_LOG_VERBOSE, "Decoding frame, %"SIZE_SPECIFIER" bytes, %i tiles\n", + av_log(avctx, AV_LOG_DEBUG, "Decoding frame, %zu bytes, %i tiles\n", vp->slices_size, ap->av1_pic_info.tileCount); return ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp); } -static void vk_av1_free_frame_priv(FFRefStructOpaque _hwctx, void *data) +static void vk_av1_free_frame_priv(AVRefStructOpaque _hwctx, void *data) { AVHWDeviceContext *hwctx = _hwctx.nc; AV1VulkanDecodePicture *ap = data; - /* Workaround for a spec issue. */ - if (ap->frame_id_set) - ap->dec->frame_id_alloc_mask &= ~(1 << ap->frame_id); - /* Free frame resources, this also destroys the session parameters. */ ff_vk_decode_free_frame(hwctx, &ap->vp); } @@ -632,19 +664,8 @@ const FFHWAccel ff_av1_vulkan_hwaccel = { .init = &ff_vk_decode_init, .update_thread_context = &ff_vk_update_thread_context, .decode_params = &ff_vk_params_invalidate, - .flush = &ff_vk_decode_flush, .uninit = &ff_vk_decode_uninit, .frame_params = &ff_vk_frame_params, .priv_data_size = sizeof(FFVulkanDecodeContext), - - /* NOTE: Threading is intentionally disabled here. Due to the design of Vulkan, - * where frames are opaque to users, and mostly opaque for driver developers, - * there's an issue with current hardware accelerator implementations of AV1, - * where they require an internal index. With regular hwaccel APIs, this index - * is given to users as an opaque handle directly. With Vulkan, due to increased - * flexibility, this index cannot be present anywhere. - * The current implementation tracks the index for the driver and submits it - * as necessary information. Due to needing to modify the decoding context, - * which is not thread-safe, on frame free, threading is disabled. */ .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vulkan_decode.c b/libavcodec/vulkan_decode.c index a8b906a9d..9ab8d45aa 100644 --- a/libavcodec/vulkan_decode.c +++ b/libavcodec/vulkan_decode.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "vulkan_video.h" #include "vulkan_decode.h" #include "config_components.h" @@ -24,15 +24,36 @@ #include "libavutil/mem.h" #include "libavutil/vulkan_loader.h" +#define DECODER_IS_SDR(codec_id) \ + (((codec_id) == AV_CODEC_ID_FFV1) || \ + ((codec_id) == AV_CODEC_ID_DPX) || \ + ((codec_id) == AV_CODEC_ID_PRORES_RAW) || \ + ((codec_id) == AV_CODEC_ID_PRORES)) + #if CONFIG_H264_VULKAN_HWACCEL extern const FFVulkanDecodeDescriptor ff_vk_dec_h264_desc; #endif #if CONFIG_HEVC_VULKAN_HWACCEL extern const FFVulkanDecodeDescriptor ff_vk_dec_hevc_desc; #endif +#if CONFIG_VP9_VULKAN_HWACCEL +extern const FFVulkanDecodeDescriptor ff_vk_dec_vp9_desc; +#endif #if CONFIG_AV1_VULKAN_HWACCEL extern const FFVulkanDecodeDescriptor ff_vk_dec_av1_desc; #endif +#if CONFIG_FFV1_VULKAN_HWACCEL +extern const FFVulkanDecodeDescriptor ff_vk_dec_ffv1_desc; +#endif +#if CONFIG_PRORES_RAW_VULKAN_HWACCEL +extern const FFVulkanDecodeDescriptor ff_vk_dec_prores_raw_desc; +#endif +#if CONFIG_PRORES_VULKAN_HWACCEL +extern const FFVulkanDecodeDescriptor ff_vk_dec_prores_desc; +#endif +#if CONFIG_DPX_VULKAN_HWACCEL +extern const FFVulkanDecodeDescriptor ff_vk_dec_dpx_desc; +#endif static const FFVulkanDecodeDescriptor *dec_descs[] = { #if CONFIG_H264_VULKAN_HWACCEL @@ -41,11 +62,39 @@ static const FFVulkanDecodeDescriptor *dec_descs[] = { #if CONFIG_HEVC_VULKAN_HWACCEL &ff_vk_dec_hevc_desc, #endif +#if CONFIG_VP9_VULKAN_HWACCEL + &ff_vk_dec_vp9_desc, +#endif #if CONFIG_AV1_VULKAN_HWACCEL &ff_vk_dec_av1_desc, #endif +#if CONFIG_FFV1_VULKAN_HWACCEL + &ff_vk_dec_ffv1_desc, +#endif +#if CONFIG_PRORES_RAW_VULKAN_HWACCEL + &ff_vk_dec_prores_raw_desc, +#endif +#if CONFIG_PRORES_VULKAN_HWACCEL + &ff_vk_dec_prores_desc, +#endif +#if CONFIG_DPX_VULKAN_HWACCEL + &ff_vk_dec_dpx_desc, +#endif }; +typedef struct FFVulkanDecodeProfileData { + VkVideoDecodeH264ProfileInfoKHR h264_profile; + VkVideoDecodeH265ProfileInfoKHR h265_profile; +#if CONFIG_VP9_VULKAN_HWACCEL + VkVideoDecodeVP9ProfileInfoKHR vp9_profile; +#endif + VkVideoDecodeAV1ProfileInfoKHR av1_profile; + + VkVideoDecodeUsageInfoKHR usage; + VkVideoProfileInfoKHR profile; + VkVideoProfileListInfoKHR profile_list; +} FFVulkanDecodeProfileData; + static const FFVulkanDecodeDescriptor *get_codecdesc(enum AVCodecID codec_id) { for (size_t i = 0; i < FF_ARRAY_ELEMS(dec_descs); i++) @@ -62,8 +111,13 @@ static const VkVideoProfileInfoKHR *get_video_profile(FFVulkanDecodeShared *ctx, VkStructureType profile_struct_type = codec_id == AV_CODEC_ID_H264 ? VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR : codec_id == AV_CODEC_ID_HEVC ? VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR : +#if CONFIG_VP9_VULKAN_HWACCEL + codec_id == AV_CODEC_ID_VP9 ? VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_PROFILE_INFO_KHR : +#endif codec_id == AV_CODEC_ID_AV1 ? VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PROFILE_INFO_KHR : - 0; + VK_STRUCTURE_TYPE_MAX_ENUM; + if (profile_struct_type == VK_STRUCTURE_TYPE_MAX_ENUM) + return NULL; profile_list = ff_vk_find_struct(ctx->s.hwfc->create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR); @@ -83,36 +137,14 @@ int ff_vk_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) FFVulkanDecodeContext *src_ctx = src->internal->hwaccel_priv_data; FFVulkanDecodeContext *dst_ctx = dst->internal->hwaccel_priv_data; - if (!dst_ctx->exec_pool.cmd_bufs) { - FFVulkanDecodeShared *ctx = src_ctx->shared_ctx; + av_refstruct_replace(&dst_ctx->shared_ctx, src_ctx->shared_ctx); - const VkVideoProfileInfoKHR *profile = get_video_profile(ctx, dst->codec_id); - if (!profile) { - av_log(dst, AV_LOG_ERROR, "Video profile missing from frames context!\n"); - return AVERROR(EINVAL); - } - - err = ff_vk_exec_pool_init(&ctx->s, &ctx->qf, - &dst_ctx->exec_pool, - src_ctx->exec_pool.pool_size, - src_ctx->exec_pool.nb_queries, - VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR, 0, - profile); - if (err < 0) - return err; - } - - ff_refstruct_replace(&dst_ctx->shared_ctx, src_ctx->shared_ctx); - - if (src_ctx->session_params) { - err = av_buffer_replace(&dst_ctx->session_params, src_ctx->session_params); - if (err < 0) - return err; - } + err = av_buffer_replace(&dst_ctx->session_params, src_ctx->session_params); + if (err < 0) + return err; dst_ctx->dedicated_dpb = src_ctx->dedicated_dpb; dst_ctx->external_fg = src_ctx->external_fg; - dst_ctx->frame_id_alloc_mask = src_ctx->frame_id_alloc_mask; return 0; } @@ -138,32 +170,42 @@ static AVFrame *vk_get_dpb_pool(FFVulkanDecodeShared *ctx) return avf; } +static void init_frame(FFVulkanDecodeContext *dec, FFVulkanDecodePicture *vkpic) +{ + FFVulkanDecodeShared *ctx = dec->shared_ctx; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + vkpic->dpb_frame = NULL; + for (int i = 0; i < AV_NUM_DATA_POINTERS; i++) { + vkpic->view.ref[i] = VK_NULL_HANDLE; + vkpic->view.out[i] = VK_NULL_HANDLE; + vkpic->view.dst[i] = VK_NULL_HANDLE; + } + + vkpic->destroy_image_view = vk->DestroyImageView; + vkpic->wait_semaphores = vk->WaitSemaphores; + vkpic->invalidate_memory_ranges = vk->InvalidateMappedMemoryRanges; +} + int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic, FFVulkanDecodePicture *vkpic, int is_current, int alloc_dpb) { int err; FFVulkanDecodeShared *ctx = dec->shared_ctx; - FFVulkanFunctions *vk = &ctx->s.vkfn; vkpic->slices_size = 0; /* If the decoder made a blank frame to make up for a missing ref, or the * frame is the current frame so it's missing one, create a re-representation */ - if (vkpic->img_view_ref) + if (vkpic->view.ref[0]) return 0; - vkpic->dpb_frame = NULL; - vkpic->img_view_ref = VK_NULL_HANDLE; - vkpic->img_view_out = VK_NULL_HANDLE; - vkpic->img_view_dest = VK_NULL_HANDLE; - - vkpic->destroy_image_view = vk->DestroyImageView; - vkpic->wait_semaphores = vk->WaitSemaphores; + init_frame(dec, vkpic); if (ctx->common.layered_dpb && alloc_dpb) { - vkpic->img_view_ref = ctx->common.layered_view; - vkpic->img_aspect_ref = ctx->common.layered_aspect; + vkpic->view.ref[0] = ctx->common.layered_view; + vkpic->view.aspect_ref[0] = ctx->common.layered_aspect; } else if (alloc_dpb) { AVHWFramesContext *dpb_frames = (AVHWFramesContext *)ctx->common.dpb_hwfc_ref->data; AVVulkanFramesContext *dpb_hwfc = dpb_frames->hwctx; @@ -173,13 +215,13 @@ int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic, return AVERROR(ENOMEM); err = ff_vk_create_view(&ctx->s, &ctx->common, - &vkpic->img_view_ref, &vkpic->img_aspect_ref, + &vkpic->view.ref[0], &vkpic->view.aspect_ref[0], (AVVkFrame *)vkpic->dpb_frame->data[0], - dpb_hwfc->format[0], !is_current); + dpb_hwfc->format[0], VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR); if (err < 0) return err; - vkpic->img_view_dest = vkpic->img_view_ref; + vkpic->view.dst[0] = vkpic->view.ref[0]; } if (!alloc_dpb || is_current) { @@ -187,15 +229,64 @@ int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic, AVVulkanFramesContext *hwfc = frames->hwctx; err = ff_vk_create_view(&ctx->s, &ctx->common, - &vkpic->img_view_out, &vkpic->img_aspect, + &vkpic->view.out[0], &vkpic->view.aspect[0], (AVVkFrame *)pic->data[0], - hwfc->format[0], !is_current); + hwfc->format[0], + VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR | + (!is_current ? VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR : 0)); if (err < 0) return err; if (!alloc_dpb) { - vkpic->img_view_ref = vkpic->img_view_out; - vkpic->img_aspect_ref = vkpic->img_aspect; + vkpic->view.ref[0] = vkpic->view.out[0]; + vkpic->view.aspect_ref[0] = vkpic->view.aspect[0]; + } + } + + return 0; +} + +int ff_vk_decode_prepare_frame_sdr(FFVulkanDecodeContext *dec, AVFrame *pic, + FFVulkanDecodePicture *vkpic, int is_current, + enum FFVkShaderRepFormat rep_fmt, int alloc_dpb) +{ + int err; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + AVHWFramesContext *frames = (AVHWFramesContext *)pic->hw_frames_ctx->data; + + vkpic->slices_size = 0; + + if (vkpic->view.ref[0]) + return 0; + + init_frame(dec, vkpic); + + for (int i = 0; i < av_pix_fmt_count_planes(frames->sw_format); i++) { + if (alloc_dpb) { + vkpic->dpb_frame = vk_get_dpb_pool(ctx); + if (!vkpic->dpb_frame) + return AVERROR(ENOMEM); + + err = ff_vk_create_imageview(&ctx->s, + &vkpic->view.ref[i], &vkpic->view.aspect_ref[i], + vkpic->dpb_frame, i, rep_fmt); + if (err < 0) + return err; + + vkpic->view.dst[i] = vkpic->view.ref[i]; + } + + if (!alloc_dpb || is_current) { + err = ff_vk_create_imageview(&ctx->s, + &vkpic->view.out[i], &vkpic->view.aspect[i], + pic, i, rep_fmt); + if (err < 0) + return err; + + if (!alloc_dpb) { + vkpic->view.ref[i] = vkpic->view.out[i]; + vkpic->view.aspect_ref[i] = vkpic->view.aspect[i]; + } } } @@ -211,7 +302,7 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp, static const uint8_t startcode_prefix[3] = { 0x0, 0x0, 0x1 }; const size_t startcode_len = add_startcode ? sizeof(startcode_prefix) : 0; - const int nb = *nb_slices; + const int nb = nb_slices ? *nb_slices : 0; uint8_t *slices; uint32_t *slice_off; FFVkBuffer *vkbuf; @@ -220,13 +311,16 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp, ctx->caps.minBitstreamBufferSizeAlignment; new_size = FFALIGN(new_size, ctx->caps.minBitstreamBufferSizeAlignment); - slice_off = av_fast_realloc(dec->slice_off, &dec->slice_off_max, - (nb + 1)*sizeof(slice_off)); - if (!slice_off) - return AVERROR(ENOMEM); + if (offsets) { + slice_off = av_fast_realloc(dec->slice_off, &dec->slice_off_max, + (nb + 1)*sizeof(slice_off)); + if (!slice_off) + return AVERROR(ENOMEM); - *offsets = dec->slice_off = slice_off; - slice_off[nb] = vp->slices_size; + *offsets = dec->slice_off = slice_off; + + slice_off[nb] = vp->slices_size; + } vkbuf = vp->slices_buf ? (FFVkBuffer *)vp->slices_buf->data : NULL; if (!vkbuf || vkbuf->size < new_size) { @@ -242,9 +336,14 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp, buf_size = 2 << av_log2(buf_size); err = ff_vk_get_pooled_buffer(&ctx->s, &ctx->buf_pool, &new_ref, + DECODER_IS_SDR(avctx->codec_id) ? + (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) : VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR, ctx->s.hwfc->create_pnext, buf_size, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + (DECODER_IS_SDR(avctx->codec_id) ? + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT : 0x0)); if (err < 0) return err; @@ -267,23 +366,73 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp, /* Slice data */ memcpy(slices + vp->slices_size + startcode_len, data, size); - *nb_slices = nb + 1; + if (nb_slices) + *nb_slices = nb + 1; + vp->slices_size += startcode_len + size; return 0; } -void ff_vk_decode_flush(AVCodecContext *avctx) +static int create_empty_session_parameters(AVCodecContext *avctx, + FFVulkanDecodeShared *ctx, + VkVideoSessionParametersKHR *empty_session_params) { - FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; - FFVulkanDecodeShared *ctx = dec->shared_ctx; + if (avctx->codec_id == AV_CODEC_ID_VP9) + return 0; + + VkVideoDecodeH264SessionParametersCreateInfoKHR h264_params = { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR, + }; + VkVideoDecodeH265SessionParametersCreateInfoKHR h265_params = { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR, + }; + StdVideoAV1SequenceHeader av1_empty_seq = { 0 }; + VkVideoDecodeAV1SessionParametersCreateInfoKHR av1_params = { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR, + .pStdSequenceHeader = &av1_empty_seq, + }; + VkVideoSessionParametersCreateInfoKHR session_params_create = { + .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR, + .pNext = avctx->codec_id == AV_CODEC_ID_H264 ? (void *)&h264_params : + avctx->codec_id == AV_CODEC_ID_HEVC ? (void *)&h265_params : + avctx->codec_id == AV_CODEC_ID_AV1 ? (void *)&av1_params : + NULL, + .videoSession = ctx->common.session, + }; + + VkResult ret; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &s->vkfn; + ret = vk->CreateVideoSessionParametersKHR(s->hwctx->act_dev, &session_params_create, + s->hwctx->alloc, empty_session_params); + if (ret != VK_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Unable to create empty Vulkan video session parameters: %s!\n", + ff_vk_ret2str(ret)); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int decode_reset(AVCodecContext *avctx, FFVulkanDecodeShared *ctx) +{ + int err; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &s->vkfn; - FFVulkanFunctions *vk = &ctx->s.vkfn; VkVideoBeginCodingInfoKHR decode_start = { .sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR, .videoSession = ctx->common.session, - .videoSessionParameters = ctx->empty_session_params, }; + + if (!(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) { + err = create_empty_session_parameters(avctx, ctx, + &decode_start.videoSessionParameters); + if (err < 0) + return err; + } + VkVideoCodingControlInfoKHR decode_ctrl = { .sType = VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR, .flags = VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR, @@ -292,21 +441,30 @@ void ff_vk_decode_flush(AVCodecContext *avctx) .sType = VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR, }; - VkCommandBuffer cmd_buf; - FFVkExecContext *exec = ff_vk_exec_get(&dec->exec_pool); - int had_submission = exec->had_submission; + FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool); ff_vk_exec_start(&ctx->s, exec); - cmd_buf = exec->buf; - vk->CmdBeginVideoCodingKHR(cmd_buf, &decode_start); - vk->CmdControlVideoCodingKHR(cmd_buf, &decode_ctrl); - vk->CmdEndVideoCodingKHR(cmd_buf, &decode_end); - ff_vk_exec_submit(&ctx->s, exec); + vk->CmdBeginVideoCodingKHR(exec->buf, &decode_start); + vk->CmdControlVideoCodingKHR(exec->buf, &decode_ctrl); + vk->CmdEndVideoCodingKHR(exec->buf, &decode_end); - /* If this is the very first time this context is used, then remove the - * had_submission flag to indicate that no query result is available, - * as no decode command was issued. */ - exec->had_submission = had_submission; + err = ff_vk_exec_submit(&ctx->s, exec); + + if (decode_start.videoSessionParameters) { + /* Wait to complete to delete the temporary session parameters */ + if (err >= 0) + ff_vk_exec_wait(&ctx->s, exec); + + vk->DestroyVideoSessionParametersKHR(s->hwctx->act_dev, + decode_start.videoSessionParameters, + s->hwctx->alloc); + } + + if (err < 0) + av_log(avctx, AV_LOG_ERROR, "Unable to reset decoder: %s", + ff_vk_ret2str(err)); + + return err; } int ff_vk_decode_frame(AVCodecContext *avctx, @@ -328,11 +486,12 @@ int ff_vk_decode_frame(AVCodecContext *avctx, /* Quirks */ const int layered_dpb = ctx->common.layered_dpb; - VkVideoSessionParametersKHR *par = (VkVideoSessionParametersKHR *)dec->session_params->data; VkVideoBeginCodingInfoKHR decode_start = { .sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR, .videoSession = ctx->common.session, - .videoSessionParameters = *par, + .videoSessionParameters = dec->session_params ? + *((VkVideoSessionParametersKHR *)dec->session_params->data) : + VK_NULL_HANDLE, .referenceSlotCount = vp->decode_info.referenceSlotCount, .pReferenceSlots = vp->decode_info.pReferenceSlots, }; @@ -345,7 +504,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, size_t data_size = FFALIGN(vp->slices_size, ctx->caps.minBitstreamBufferSizeAlignment); - FFVkExecContext *exec = ff_vk_exec_get(&dec->exec_pool); + FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool); /* The current decoding reference has to be bound as an inactive reference */ VkVideoReferenceSlotInfoKHR *cur_vk_ref; @@ -354,22 +513,6 @@ int ff_vk_decode_frame(AVCodecContext *avctx, cur_vk_ref[0].slotIndex = -1; decode_start.referenceSlotCount++; - if (dec->exec_pool.nb_queries && exec->had_submission) { - uint32_t *result; - ret = ff_vk_exec_get_query(&ctx->s, exec, (void **)&result, - VK_QUERY_RESULT_WAIT_BIT); - if (ret != VK_NOT_READY && ret != VK_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Unable to perform query: %s!\n", - ff_vk_ret2str(ret)); - return AVERROR_EXTERNAL; - } - - av_log(avctx, - result[0] != VK_QUERY_RESULT_STATUS_COMPLETE_KHR ? - AV_LOG_ERROR : AV_LOG_DEBUG, - "Result of previous frame decoding: %u\n", result[0]); - } - sd_buf = (FFVkBuffer *)vp->slices_buf->data; /* Flush if needed */ @@ -438,7 +581,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = vkf->img[0], .subresourceRange = (VkImageSubresourceRange) { - .aspectMask = vp->img_aspect, + .aspectMask = vp->view.aspect[0], .layerCount = 1, .levelCount = 1, }, @@ -494,7 +637,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = rvkf->img[0], .subresourceRange = (VkImageSubresourceRange) { - .aspectMask = rvp->img_aspect_ref, + .aspectMask = rvp->view.aspect_ref[0], .layerCount = 1, .levelCount = 1, }, @@ -504,7 +647,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, } } } else if (vp->decode_info.referenceSlotCount || - vp->img_view_out != vp->img_view_ref) { + vp->view.out[0] != vp->view.ref[0]) { /* Single barrier for a single layered ref */ err = ff_vk_exec_add_dep_frame(&ctx->s, exec, ctx->common.layered_frame, VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, @@ -523,17 +666,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, /* Start, use parameters, decode and end decoding */ vk->CmdBeginVideoCodingKHR(cmd_buf, &decode_start); - - /* Start status query */ - if (dec->exec_pool.nb_queries) - vk->CmdBeginQuery(cmd_buf, dec->exec_pool.query_pool, exec->query_idx + 0, 0); - vk->CmdDecodeVideoKHR(cmd_buf, &vp->decode_info); - - /* End status query */ - if (dec->exec_pool.nb_queries) - vk->CmdEndQuery(cmd_buf, dec->exec_pool.query_pool, exec->query_idx + 0); - vk->CmdEndVideoCodingKHR(cmd_buf, &decode_end); /* End recording and submit for execution */ @@ -561,35 +694,36 @@ void ff_vk_decode_free_frame(AVHWDeviceContext *dev_ctx, FFVulkanDecodePicture * av_buffer_unref(&vp->slices_buf); /* Destroy image view (out) */ - if (vp->img_view_out && vp->img_view_out != vp->img_view_dest) - vp->destroy_image_view(hwctx->act_dev, vp->img_view_out, hwctx->alloc); + for (int i = 0; i < AV_NUM_DATA_POINTERS; i++) { + if (vp->view.out[i] && vp->view.out[i] != vp->view.dst[i]) + vp->destroy_image_view(hwctx->act_dev, vp->view.out[i], hwctx->alloc); - /* Destroy image view (ref, unlayered) */ - if (vp->img_view_dest) - vp->destroy_image_view(hwctx->act_dev, vp->img_view_dest, hwctx->alloc); + /* Destroy image view (ref, unlayered) */ + if (vp->view.dst[i]) + vp->destroy_image_view(hwctx->act_dev, vp->view.dst[i], hwctx->alloc); + } av_frame_free(&vp->dpb_frame); } -static void free_common(FFRefStructOpaque unused, void *obj) +static void free_common(AVRefStructOpaque unused, void *obj) { FFVulkanDecodeShared *ctx = obj; FFVulkanContext *s = &ctx->s; - FFVulkanFunctions *vk = &ctx->s.vkfn; + + /* Wait on and free execution pool */ + ff_vk_exec_pool_free(&ctx->s, &ctx->exec_pool); /* This also frees all references from this pool */ av_frame_free(&ctx->common.layered_frame); - /* Destroy parameters */ - if (ctx->empty_session_params) - vk->DestroyVideoSessionParametersKHR(s->hwctx->act_dev, - ctx->empty_session_params, - s->hwctx->alloc); - av_buffer_pool_uninit(&ctx->buf_pool); ff_vk_video_common_uninit(s, &ctx->common); + if (ctx->sd_ctx_free) + ctx->sd_ctx_free(ctx); + ff_vk_uninit(s); } @@ -597,6 +731,7 @@ static int vulkan_decode_bootstrap(AVCodecContext *avctx, AVBufferRef *frames_re { int err; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + const FFVulkanDecodeDescriptor *vk_desc = get_codecdesc(avctx->codec_id); AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data; AVHWDeviceContext *device = (AVHWDeviceContext *)frames->device_ref->data; AVVulkanDeviceContext *hwctx = device->hwctx; @@ -605,7 +740,7 @@ static int vulkan_decode_bootstrap(AVCodecContext *avctx, AVBufferRef *frames_re if (dec->shared_ctx) return 0; - dec->shared_ctx = ff_refstruct_alloc_ext(sizeof(*ctx), 0, NULL, + dec->shared_ctx = av_refstruct_alloc_ext(sizeof(*ctx), 0, NULL, free_common); if (!dec->shared_ctx) return AVERROR(ENOMEM); @@ -615,16 +750,18 @@ static int vulkan_decode_bootstrap(AVCodecContext *avctx, AVBufferRef *frames_re ctx->s.extensions = ff_vk_extensions_to_mask(hwctx->enabled_dev_extensions, hwctx->nb_enabled_dev_extensions); - if (!(ctx->s.extensions & FF_VK_EXT_VIDEO_DECODE_QUEUE)) { - av_log(avctx, AV_LOG_ERROR, "Device does not support the %s extension!\n", - VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME); - ff_refstruct_unref(&dec->shared_ctx); - return AVERROR(ENOSYS); + if (vk_desc->queue_flags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) { + if (!(ctx->s.extensions & FF_VK_EXT_VIDEO_DECODE_QUEUE)) { + av_log(avctx, AV_LOG_ERROR, "Device does not support the %s extension!\n", + VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME); + av_refstruct_unref(&dec->shared_ctx); + return AVERROR(ENOSYS); + } } err = ff_vk_load_functions(device, &ctx->s.vkfn, ctx->s.extensions, 1, 1); if (err < 0) { - ff_refstruct_unref(&dec->shared_ctx); + av_refstruct_unref(&dec->shared_ctx); return err; } @@ -638,6 +775,9 @@ static VkResult vulkan_setup_profile(AVCodecContext *avctx, const FFVulkanDecodeDescriptor *vk_desc, VkVideoDecodeH264CapabilitiesKHR *h264_caps, VkVideoDecodeH265CapabilitiesKHR *h265_caps, +#if CONFIG_VP9_VULKAN_HWACCEL + VkVideoDecodeVP9CapabilitiesKHR *vp9_caps, +#endif VkVideoDecodeAV1CapabilitiesKHR *av1_caps, VkVideoCapabilitiesKHR *caps, VkVideoDecodeCapabilitiesKHR *dec_caps, @@ -649,6 +789,9 @@ static VkResult vulkan_setup_profile(AVCodecContext *avctx, VkVideoDecodeH264ProfileInfoKHR *h264_profile = &prof->h264_profile; VkVideoDecodeH265ProfileInfoKHR *h265_profile = &prof->h265_profile; +#if CONFIG_VP9_VULKAN_HWACCEL + VkVideoDecodeVP9ProfileInfoKHR *vp9_profile = &prof->vp9_profile; +#endif VkVideoDecodeAV1ProfileInfoKHR *av1_profile = &prof->av1_profile; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); @@ -674,6 +817,13 @@ static VkResult vulkan_setup_profile(AVCodecContext *avctx, usage->pNext = h265_profile; h265_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR; h265_profile->stdProfileIdc = cur_profile; +#if CONFIG_VP9_VULKAN_HWACCEL + } else if (avctx->codec_id == AV_CODEC_ID_VP9) { + dec_caps->pNext = vp9_caps; + usage->pNext = vp9_profile; + vp9_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_PROFILE_INFO_KHR; + vp9_profile->stdProfile = cur_profile; +#endif } else if (avctx->codec_id == AV_CODEC_ID_AV1) { dec_caps->pNext = av1_caps; usage->pNext = av1_profile; @@ -734,6 +884,11 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ VkVideoDecodeH265CapabilitiesKHR h265_caps = { .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_KHR, }; +#if CONFIG_VP9_VULKAN_HWACCEL + VkVideoDecodeVP9CapabilitiesKHR vp9_caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_CAPABILITIES_KHR, + }; +#endif VkVideoDecodeAV1CapabilitiesKHR av1_caps = { .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_CAPABILITIES_KHR, }; @@ -754,12 +909,18 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ cur_profile = avctx->profile; base_profile = avctx->codec_id == AV_CODEC_ID_H264 ? AV_PROFILE_H264_CONSTRAINED_BASELINE : avctx->codec_id == AV_CODEC_ID_H265 ? AV_PROFILE_HEVC_MAIN : +#if CONFIG_VP9_VULKAN_HWACCEL + avctx->codec_id == AV_CODEC_ID_VP9 ? STD_VIDEO_VP9_PROFILE_0 : +#endif avctx->codec_id == AV_CODEC_ID_AV1 ? STD_VIDEO_AV1_PROFILE_MAIN : 0; ret = vulkan_setup_profile(avctx, prof, hwctx, vk, vk_desc, &h264_caps, &h265_caps, +#if CONFIG_VP9_VULKAN_HWACCEL + &vp9_caps, +#endif &av1_caps, caps, dec_caps, @@ -776,6 +937,9 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ ret = vulkan_setup_profile(avctx, prof, hwctx, vk, vk_desc, &h264_caps, &h265_caps, +#if CONFIG_VP9_VULKAN_HWACCEL + &vp9_caps, +#endif &av1_caps, caps, dec_caps, @@ -802,6 +966,9 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ max_level = avctx->codec_id == AV_CODEC_ID_H264 ? ff_vk_h264_level_to_av(h264_caps.maxLevelIdc) : avctx->codec_id == AV_CODEC_ID_H265 ? ff_vk_h265_level_to_av(h265_caps.maxLevelIdc) : +#if CONFIG_VP9_VULKAN_HWACCEL + avctx->codec_id == AV_CODEC_ID_VP9 ? vp9_caps.maxLevel : +#endif avctx->codec_id == AV_CODEC_ID_AV1 ? av1_caps.maxLevel : 0; @@ -887,8 +1054,8 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - if (ctx->s.extensions & (FF_VK_EXT_VIDEO_ENCODE_QUEUE | - FF_VK_EXT_VIDEO_MAINTENANCE_1)) + if ((ctx->s.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) && + (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1)) fmt_info.imageUsage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR; } @@ -973,53 +1140,100 @@ static void free_profile_data(AVHWFramesContext *hwfc) int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { - VkFormat vkfmt; int err, dedicated_dpb; AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data; AVVulkanFramesContext *hwfc = frames_ctx->hwctx; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; - FFVulkanDecodeProfileData *prof; - FFVulkanDecodeShared *ctx; - - frames_ctx->sw_format = AV_PIX_FMT_NONE; + FFVulkanDecodeProfileData *prof = NULL; err = vulkan_decode_bootstrap(avctx, hw_frames_ctx); if (err < 0) return err; - prof = av_mallocz(sizeof(FFVulkanDecodeProfileData)); - if (!prof) - return AVERROR(ENOMEM); - - err = vulkan_decode_get_profile(avctx, hw_frames_ctx, - &frames_ctx->sw_format, &vkfmt, - prof, &dedicated_dpb); - if (err < 0) { - av_free(prof); - return err; - } - - frames_ctx->user_opaque = prof; - frames_ctx->free = free_profile_data; - + frames_ctx->format = AV_PIX_FMT_VULKAN; + frames_ctx->sw_format = avctx->sw_pix_fmt; frames_ctx->width = avctx->coded_width; frames_ctx->height = avctx->coded_height; - frames_ctx->format = AV_PIX_FMT_VULKAN; - hwfc->format[0] = vkfmt; - hwfc->create_pnext = &prof->profile_list; - hwfc->tiling = VK_IMAGE_TILING_OPTIMAL; - hwfc->usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR; + if (!DECODER_IS_SDR(avctx->codec_id)) { + prof = av_mallocz(sizeof(FFVulkanDecodeProfileData)); + if (!prof) + return AVERROR(ENOMEM); - if (!dec->dedicated_dpb) - hwfc->usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR; + err = vulkan_decode_get_profile(avctx, hw_frames_ctx, + &frames_ctx->sw_format, + &hwfc->format[0], + prof, &dedicated_dpb); + if (err < 0) { + av_free(prof); + return err; + } - ctx = dec->shared_ctx; - if (ctx->s.extensions & (FF_VK_EXT_VIDEO_ENCODE_QUEUE | - FF_VK_EXT_VIDEO_MAINTENANCE_1)) - hwfc->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR; + const AVPixFmtDescriptor *pdesc = av_pix_fmt_desc_get(frames_ctx->sw_format); + frames_ctx->width = FFALIGN(frames_ctx->width, 1 << pdesc->log2_chroma_w); + frames_ctx->height = FFALIGN(frames_ctx->height, 1 << pdesc->log2_chroma_h); + frames_ctx->user_opaque = prof; + frames_ctx->free = free_profile_data; + + hwfc->create_pnext = &prof->profile_list; + } else { + hwfc->format[0] = VK_FORMAT_UNDEFINED; + switch (frames_ctx->sw_format) { + case AV_PIX_FMT_GBRAP16: + /* This should be more efficient for downloading and using */ + frames_ctx->sw_format = AV_PIX_FMT_RGBA64; + break; + case AV_PIX_FMT_GBRP10: + /* This saves memory bandwidth when downloading */ + frames_ctx->sw_format = AV_PIX_FMT_X2BGR10; + break; + case AV_PIX_FMT_RGB24: + case AV_PIX_FMT_BGR0: + /* mpv has issues with bgr0 mapping, so just remap it */ + frames_ctx->sw_format = AV_PIX_FMT_RGB0; + break; + /* DPX endian mismatch remappings */ + case AV_PIX_FMT_RGB48LE: + case AV_PIX_FMT_RGB48BE: frames_ctx->sw_format = AV_PIX_FMT_GBRP16; break; + case AV_PIX_FMT_RGBA64BE: frames_ctx->sw_format = AV_PIX_FMT_RGBA64; break; + case AV_PIX_FMT_GRAY16BE: frames_ctx->sw_format = AV_PIX_FMT_GRAY16; break; + /* ProRes needs to clear the input image, which is not possible on YUV formats */ + case AV_PIX_FMT_YUVA422P10: + case AV_PIX_FMT_YUVA444P10: + case AV_PIX_FMT_YUVA422P12: + case AV_PIX_FMT_YUVA444P12: + hwfc->format[3] = VK_FORMAT_R16_UNORM; + /* fallthrough */ + case AV_PIX_FMT_YUV422P10: + case AV_PIX_FMT_YUV444P10: + case AV_PIX_FMT_YUV422P12: + case AV_PIX_FMT_YUV444P12: + hwfc->format[0] = VK_FORMAT_R16_UNORM; + hwfc->format[1] = VK_FORMAT_R16_UNORM; + hwfc->format[2] = VK_FORMAT_R16_UNORM; + break; + default: + break; + } + } + + hwfc->tiling = VK_IMAGE_TILING_OPTIMAL; + hwfc->usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT; + + if (prof) { + FFVulkanDecodeShared *ctx; + + hwfc->usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR; + if (!dec->dedicated_dpb) + hwfc->usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR; + + ctx = dec->shared_ctx; + if ((ctx->s.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) && + (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1)) + hwfc->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR; + } return err; } @@ -1066,48 +1280,24 @@ int ff_vk_decode_create_params(AVBufferRef **par_ref, void *logctx, FFVulkanDeco int ff_vk_decode_uninit(AVCodecContext *avctx) { FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; - FFVulkanDecodeShared *ctx = dec->shared_ctx; - - /* Wait on and free execution pool */ - ff_vk_exec_pool_free(&ctx->s, &dec->exec_pool); av_freep(&dec->hevc_headers); av_buffer_unref(&dec->session_params); - ff_refstruct_unref(&dec->shared_ctx); + av_refstruct_unref(&dec->shared_ctx); av_freep(&dec->slice_off); return 0; } int ff_vk_decode_init(AVCodecContext *avctx) { - int err, nb_q = 0; - VkResult ret; + int err; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; FFVulkanDecodeShared *ctx; FFVulkanContext *s; - FFVulkanFunctions *vk; + int async_depth; const VkVideoProfileInfoKHR *profile; const FFVulkanDecodeDescriptor *vk_desc; - const VkPhysicalDeviceDriverProperties *driver_props; - VkVideoDecodeH264SessionParametersCreateInfoKHR h264_params = { - .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR, - }; - VkVideoDecodeH265SessionParametersCreateInfoKHR h265_params = { - .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR, - }; - StdVideoAV1SequenceHeader av1_empty_seq = { 0 }; - VkVideoDecodeAV1SessionParametersCreateInfoKHR av1_params = { - .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR, - .pStdSequenceHeader = &av1_empty_seq, - }; - VkVideoSessionParametersCreateInfoKHR session_params_create = { - .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR, - .pNext = avctx->codec_id == AV_CODEC_ID_H264 ? (void *)&h264_params : - avctx->codec_id == AV_CODEC_ID_HEVC ? (void *)&h265_params : - avctx->codec_id == AV_CODEC_ID_AV1 ? (void *)&av1_params : - NULL, - }; VkVideoSessionCreateInfoKHR session_create = { .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR, }; @@ -1119,35 +1309,29 @@ int ff_vk_decode_init(AVCodecContext *avctx) /* Initialize contexts */ ctx = dec->shared_ctx; s = &ctx->s; - vk = &ctx->s.vkfn; err = ff_vk_init(s, avctx, NULL, avctx->hw_frames_ctx); if (err < 0) return err; + vk_desc = get_codecdesc(avctx->codec_id); + profile = get_video_profile(ctx, avctx->codec_id); - if (!profile) { + if ((vk_desc->queue_flags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) && !profile) { av_log(avctx, AV_LOG_ERROR, "Video profile missing from frames context!"); return AVERROR(EINVAL); } /* Create queue context */ vk_desc = get_codecdesc(avctx->codec_id); - err = ff_vk_video_qf_init(s, &ctx->qf, - VK_QUEUE_VIDEO_DECODE_BIT_KHR, - vk_desc->decode_op); - if (err < 0) { + ctx->qf = ff_vk_qf_find(s, vk_desc->queue_flags, vk_desc->decode_op); + if (!ctx->qf) { av_log(avctx, AV_LOG_ERROR, "Decoding of %s is not supported by this device\n", avcodec_get_name(avctx->codec_id)); return err; } - /* Enable queries if supported */ - if (s->query_props[ctx->qf.queue_family].queryResultStatusSupport) - nb_q = 1; - - session_create.flags = 0x0; - session_create.queueFamilyIndex = ctx->qf.queue_family; + session_create.queueFamilyIndex = ctx->qf->idx; session_create.maxCodedExtent = ctx->caps.maxCodedExtent; session_create.maxDpbSlots = ctx->caps.maxDpbSlots; session_create.maxActiveReferencePictures = ctx->caps.maxActiveReferencePictures; @@ -1155,19 +1339,30 @@ int ff_vk_decode_init(AVCodecContext *avctx) session_create.referencePictureFormat = session_create.pictureFormat; session_create.pStdHeaderVersion = &vk_desc->ext_props; session_create.pVideoProfile = profile; +#ifdef VK_KHR_video_maintenance2 + if (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2) + session_create.flags = VK_VIDEO_SESSION_CREATE_INLINE_SESSION_PARAMETERS_BIT_KHR; +#endif /* Create decode exec context for this specific main thread. * 2 async contexts per thread was experimentally determined to be optimal * for a majority of streams. */ - err = ff_vk_exec_pool_init(s, &ctx->qf, &dec->exec_pool, 2, - nb_q, VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR, 0, - profile); + async_depth = 2*ctx->qf->num; + /* We don't need more than 2 per thread context */ + async_depth = FFMIN(async_depth, 2*avctx->thread_count); + /* Make sure there are enough async contexts for each thread */ + async_depth = FFMAX(async_depth, avctx->thread_count); + + err = ff_vk_exec_pool_init(s, ctx->qf, &ctx->exec_pool, + async_depth, 0, 0, 0, profile); if (err < 0) goto fail; - err = ff_vk_video_common_init(avctx, s, &ctx->common, &session_create); - if (err < 0) - goto fail; + if (!DECODER_IS_SDR(avctx->codec_id)) { + err = ff_vk_video_common_init(avctx, s, &ctx->common, &session_create); + if (err < 0) + goto fail; + } /* If doing an out-of-place decoding, create a DPB pool */ if (dec->dedicated_dpb || avctx->codec_id == AV_CODEC_ID_AV1) { @@ -1183,16 +1378,15 @@ int ff_vk_decode_init(AVCodecContext *avctx) dpb_frames = (AVHWFramesContext *)ctx->common.dpb_hwfc_ref->data; dpb_frames->format = s->frames->format; dpb_frames->sw_format = s->frames->sw_format; - dpb_frames->width = avctx->coded_width; - dpb_frames->height = avctx->coded_height; + dpb_frames->width = s->frames->width; + dpb_frames->height = s->frames->height; dpb_hwfc = dpb_frames->hwctx; dpb_hwfc->create_pnext = (void *)ff_vk_find_struct(ctx->s.hwfc->create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR); dpb_hwfc->format[0] = s->hwfc->format[0]; dpb_hwfc->tiling = VK_IMAGE_TILING_OPTIMAL; - dpb_hwfc->usage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR | - VK_IMAGE_USAGE_SAMPLED_BIT; /* Shuts validator up. */ + dpb_hwfc->usage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR; if (ctx->common.layered_dpb) dpb_hwfc->nb_layers = ctx->caps.maxDpbSlots; @@ -1212,21 +1406,23 @@ int ff_vk_decode_init(AVCodecContext *avctx) &ctx->common.layered_view, &ctx->common.layered_aspect, (AVVkFrame *)ctx->common.layered_frame->data[0], - s->hwfc->format[0], 1); + s->hwfc->format[0], VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR); if (err < 0) goto fail; } } - session_params_create.videoSession = ctx->common.session; - ret = vk->CreateVideoSessionParametersKHR(s->hwctx->act_dev, &session_params_create, - s->hwctx->alloc, &ctx->empty_session_params); - if (ret != VK_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Unable to create empty Vulkan video session parameters: %s!\n", - ff_vk_ret2str(ret)); - return AVERROR_EXTERNAL; + if (!DECODER_IS_SDR(avctx->codec_id)) { + err = decode_reset(avctx, ctx); + if (err < 0) + return err; + } else { + /* For SDR decoders, this alignment value will be 0. Since this will make + * add_slice() malfunction, set it to a sane default value. */ + ctx->caps.minBitstreamBufferSizeAlignment = AV_INPUT_BUFFER_PADDING_SIZE; } + const VkPhysicalDeviceDriverProperties *driver_props; driver_props = &dec->shared_ctx->s.driver_props; if (driver_props->driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY && driver_props->conformanceVersion.major == 1 && @@ -1235,9 +1431,7 @@ int ff_vk_decode_init(AVCodecContext *avctx) driver_props->conformanceVersion.patch < 3) dec->quirk_av1_offset = 1; - ff_vk_decode_flush(avctx); - - av_log(avctx, AV_LOG_VERBOSE, "Vulkan decoder initialization sucessful\n"); + av_log(avctx, AV_LOG_VERBOSE, "Vulkan decoder initialization successful\n"); return 0; diff --git a/libavcodec/vulkan_decode.h b/libavcodec/vulkan_decode.h index 76e60836b..c75f0710d 100644 --- a/libavcodec/vulkan_decode.h +++ b/libavcodec/vulkan_decode.h @@ -29,41 +29,34 @@ typedef struct FFVulkanDecodeDescriptor { enum AVCodecID codec_id; FFVulkanExtensions decode_extension; + VkQueueFlagBits queue_flags; VkVideoCodecOperationFlagBitsKHR decode_op; VkExtensionProperties ext_props; } FFVulkanDecodeDescriptor; -typedef struct FFVulkanDecodeProfileData { - VkVideoDecodeH264ProfileInfoKHR h264_profile; - VkVideoDecodeH265ProfileInfoKHR h265_profile; - VkVideoDecodeAV1ProfileInfoKHR av1_profile; - VkVideoDecodeUsageInfoKHR usage; - VkVideoProfileInfoKHR profile; - VkVideoProfileListInfoKHR profile_list; -} FFVulkanDecodeProfileData; - typedef struct FFVulkanDecodeShared { FFVulkanContext s; FFVkVideoCommon common; - FFVkQueueFamilyCtx qf; + AVVulkanDeviceQueueFamily *qf; + FFVkExecPool exec_pool; AVBufferPool *buf_pool; VkVideoCapabilitiesKHR caps; VkVideoDecodeCapabilitiesKHR dec_caps; - VkVideoSessionParametersKHR empty_session_params; + /* Software-defined decoder context */ + void *sd_ctx; + void (*sd_ctx_free)(struct FFVulkanDecodeShared *ctx); } FFVulkanDecodeShared; typedef struct FFVulkanDecodeContext { FFVulkanDecodeShared *shared_ctx; AVBufferRef *session_params; - FFVkExecPool exec_pool; int dedicated_dpb; /* Oddity #1 - separate DPB images */ int external_fg; /* Oddity #2 - hardware can't apply film grain */ - uint32_t frame_id_alloc_mask; /* For AV1 only */ /* Workaround for NVIDIA drivers tested with CTS version 1.3.8 for AV1. * The tests were incorrect as the OrderHints were offset by 1. */ @@ -80,11 +73,13 @@ typedef struct FFVulkanDecodeContext { typedef struct FFVulkanDecodePicture { AVFrame *dpb_frame; /* Only used for out-of-place decoding. */ - VkImageView img_view_ref; /* Image representation view (reference) */ - VkImageView img_view_out; /* Image representation view (output-only) */ - VkImageView img_view_dest; /* Set to img_view_out if no layered refs are used */ - VkImageAspectFlags img_aspect; /* Image plane mask bits */ - VkImageAspectFlags img_aspect_ref; /* Only used for out-of-place decoding */ + struct { + VkImageView ref[AV_NUM_DATA_POINTERS]; /* Image representation view (reference) */ + VkImageView out[AV_NUM_DATA_POINTERS]; /* Image representation view (output-only) */ + VkImageView dst[AV_NUM_DATA_POINTERS]; /* Set to img_view_out if no layered refs are used */ + VkImageAspectFlags aspect[AV_NUM_DATA_POINTERS]; /* Image plane mask bits */ + VkImageAspectFlags aspect_ref[AV_NUM_DATA_POINTERS]; /* Only used for out-of-place decoding */ + } view; VkSemaphore sem; uint64_t sem_value; @@ -107,6 +102,7 @@ typedef struct FFVulkanDecodePicture { /* Vulkan functions needed for destruction, as no other context is guaranteed to exist */ PFN_vkWaitSemaphores wait_semaphores; PFN_vkDestroyImageView destroy_image_view; + PFN_vkInvalidateMappedMemoryRanges invalidate_memory_ranges; } FFVulkanDecodePicture; /** @@ -140,6 +136,13 @@ int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic, FFVulkanDecodePicture *vkpic, int is_current, int alloc_dpb); +/** + * Software-defined decoder version of ff_vk_decode_prepare_frame. + */ +int ff_vk_decode_prepare_frame_sdr(FFVulkanDecodeContext *dec, AVFrame *pic, + FFVulkanDecodePicture *vkpic, int is_current, + enum FFVkShaderRepFormat rep_fmt, int alloc_dpb); + /** * Add slice data to frame. */ @@ -171,11 +174,6 @@ int ff_vk_get_decode_buffer(FFVulkanDecodeContext *ctx, AVBufferRef **buf, int ff_vk_decode_create_params(AVBufferRef **par_ref, void *logctx, FFVulkanDecodeShared *ctx, const VkVideoSessionParametersCreateInfoKHR *session_params_create); -/** - * Flush decoder. - */ -void ff_vk_decode_flush(AVCodecContext *avctx); - /** * Free decoder. */ diff --git a/libavcodec/vulkan_dpx.c b/libavcodec/vulkan_dpx.c new file mode 100644 index 000000000..726ae09af --- /dev/null +++ b/libavcodec/vulkan_dpx.c @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2025 Lynne + * + * 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 "vulkan_decode.h" +#include "hwaccel_internal.h" + +#include "dpx.h" +#include "libavutil/mem.h" + +extern const unsigned char ff_dpx_unpack_comp_spv_data[]; +extern const unsigned int ff_dpx_unpack_comp_spv_len; + +extern const unsigned char ff_dpx_copy_comp_spv_data[]; +extern const unsigned int ff_dpx_copy_comp_spv_len; + +const FFVulkanDecodeDescriptor ff_vk_dec_dpx_desc = { + .codec_id = AV_CODEC_ID_DPX, + .queue_flags = VK_QUEUE_COMPUTE_BIT, +}; + +typedef struct DPXVulkanDecodePicture { + FFVulkanDecodePicture vp; +} DPXVulkanDecodePicture; + +typedef struct DPXVulkanDecodeContext { + FFVulkanShader shader; + AVBufferPool *frame_data_pool; +} DPXVulkanDecodeContext; + +typedef struct DecodePushData { + int bits_per_comp; + int nb_comp; + int nb_images; + int stride; + int need_align; + int padded_10bit; + int shift; +} DecodePushData; + +static int vk_dpx_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + DPXDecContext *dpx = avctx->priv_data; + + DPXVulkanDecodePicture *pp = dpx->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + + /* Host map the frame data if supported */ + if (!vp->slices_buf && + ctx->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) + ff_vk_host_map_buffer(&ctx->s, &vp->slices_buf, (uint8_t *)buffer, + buffer_ref, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + + /* Prepare frame to be used */ + err = ff_vk_decode_prepare_frame_sdr(dec, dpx->frame, vp, 1, + FF_VK_REP_NATIVE, 0); + if (err < 0) + return err; + + return 0; +} + +static int vk_dpx_decode_slice(AVCodecContext *avctx, + const uint8_t *data, + uint32_t size) +{ + DPXDecContext *dpx = avctx->priv_data; + + DPXVulkanDecodePicture *pp = dpx->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + + if (!vp->slices_buf) { + int err = ff_vk_decode_add_slice(avctx, vp, data, size, 0, + NULL, NULL); + if (err < 0) + return err; + } + + return 0; +} + +static int vk_dpx_end_frame(AVCodecContext *avctx) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + DPXDecContext *dpx = avctx->priv_data; + DPXVulkanDecodeContext *dxv = ctx->sd_ctx; + + DPXVulkanDecodePicture *pp = dpx->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + + int unpack = (avctx->bits_per_raw_sample == 12 && !dpx->packing) || + avctx->bits_per_raw_sample == 10; + + FFVkBuffer *slices_buf = (FFVkBuffer *)vp->slices_buf->data; + + VkImageMemoryBarrier2 img_bar[8]; + int nb_img_bar = 0; + + FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool); + ff_vk_exec_start(&ctx->s, exec); + + /* Prepare deps */ + RET(ff_vk_exec_add_dep_frame(&ctx->s, exec, dpx->frame, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + + err = ff_vk_exec_mirror_sem_value(&ctx->s, exec, &vp->sem, &vp->sem_value, + dpx->frame); + if (err < 0) + return err; + + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &vp->slices_buf, 1, 0)); + vp->slices_buf = NULL; + + AVVkFrame *vkf = (AVVkFrame *)dpx->frame->data[0]; + for (int i = 0; i < 4; i++) { + vkf->layout[i] = VK_IMAGE_LAYOUT_UNDEFINED; + vkf->access[i] = VK_ACCESS_2_NONE; + } + + ff_vk_frame_barrier(&ctx->s, exec, dpx->frame, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + nb_img_bar = 0; + + FFVulkanShader *shd = &dxv->shader; + ff_vk_shader_update_img_array(&ctx->s, exec, shd, + dpx->frame, vp->view.out, + 0, 0, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, shd, + 0, 1, 0, + slices_buf, + 0, slices_buf->size, + VK_FORMAT_UNDEFINED); + if (!unpack) { + ff_vk_shader_update_desc_buffer(&ctx->s, exec, shd, + 0, 2, 0, + slices_buf, + 0, slices_buf->size, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, shd, + 0, 3, 0, + slices_buf, + 0, slices_buf->size, + VK_FORMAT_UNDEFINED); + } + + ff_vk_exec_bind_shader(&ctx->s, exec, shd); + + /* Update push data */ + DecodePushData pd = (DecodePushData) { + .bits_per_comp = avctx->bits_per_raw_sample, + .nb_comp = dpx->components, + .nb_images = ff_vk_count_images(vkf), + .stride = dpx->stride, + .need_align = dpx->need_align, + .padded_10bit = !dpx->unpadded_10bit, + .shift = FFALIGN(avctx->bits_per_raw_sample, 8) - + avctx->bits_per_raw_sample, + }; + + ff_vk_shader_update_push_const(&ctx->s, exec, shd, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd), &pd); + + vk->CmdDispatch(exec->buf, + FFALIGN(dpx->frame->width, shd->lg_size[0])/shd->lg_size[0], + FFALIGN(dpx->frame->height, shd->lg_size[1])/shd->lg_size[1], + 1); + + err = ff_vk_exec_submit(&ctx->s, exec); + if (err < 0) + return err; + +fail: + return 0; +} + +static int init_shader(AVCodecContext *avctx, FFVulkanContext *s, + FFVkExecPool *pool, FFVulkanShader *shd, int bits) +{ + int err; + DPXDecContext *dpx = avctx->priv_data; + AVHWFramesContext *dec_frames_ctx; + dec_frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + + int unpack = (avctx->bits_per_raw_sample == 12 && !dpx->packing) || + avctx->bits_per_raw_sample == 10; + + SPEC_LIST_CREATE(sl, 2, 2*sizeof(uint32_t)) + SPEC_LIST_ADD(sl, 0, 32, dpx->endian && bits > 8); /* big endian */ + if (unpack) + SPEC_LIST_ADD(sl, 1, 32, bits == 10); /* packed_10bit */ + else + SPEC_LIST_ADD(sl, 1, 32, FFALIGN(bits, 8)); /* type_bits */ + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { 512, 1, 1 }, 0); + + ff_vk_shader_add_push_const(shd, 0, sizeof(DecodePushData), + VK_SHADER_STAGE_COMPUTE_BIT); + + const FFVulkanDescriptorSetBinding desc_set[] = { + { /* dst */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .elems = av_pix_fmt_count_planes(dec_frames_ctx->sw_format), + }, + { /* data_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* data_buf16 */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* data_buf32 */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(s, shd, desc_set, 2 + (2*!unpack), 0, 0); + + const unsigned char *src = ff_dpx_copy_comp_spv_data; + size_t src_len = ff_dpx_copy_comp_spv_len; + if (unpack) { + src = ff_dpx_unpack_comp_spv_data; + src_len = ff_dpx_unpack_comp_spv_len; + } + RET(ff_vk_shader_link(s, shd, src, src_len, "main")); + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + return err; +} + +static void vk_decode_dpx_uninit(FFVulkanDecodeShared *ctx) +{ + DPXVulkanDecodeContext *fv = ctx->sd_ctx; + + ff_vk_shader_free(&ctx->s, &fv->shader); + + av_buffer_pool_uninit(&fv->frame_data_pool); + + av_freep(&fv); +} + +static int vk_decode_dpx_init(AVCodecContext *avctx) +{ + int err; + DPXDecContext *dpx = avctx->priv_data; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + + switch (dpx->pix_fmt) { + case AV_PIX_FMT_GRAY10: + case AV_PIX_FMT_GBRAP10: + case AV_PIX_FMT_UYVY422: + case AV_PIX_FMT_YUV444P: + case AV_PIX_FMT_YUVA444P: + return AVERROR(ENOTSUP); + case AV_PIX_FMT_GBRP10: + if (dpx->unpadded_10bit) + return AVERROR(ENOTSUP); + /* fallthrough */ + default: + break; + } + + err = ff_vk_decode_init(avctx); + if (err < 0) + return err; + + FFVulkanDecodeShared *ctx = dec->shared_ctx; + DPXVulkanDecodeContext *dxv = ctx->sd_ctx = av_mallocz(sizeof(*dxv)); + if (!dxv) + return AVERROR(ENOMEM); + + ctx->sd_ctx_free = &vk_decode_dpx_uninit; + + RET(init_shader(avctx, &ctx->s, &ctx->exec_pool, + &dxv->shader, avctx->bits_per_raw_sample)); + +fail: + return err; +} + +static void vk_dpx_free_frame_priv(AVRefStructOpaque _hwctx, void *data) +{ + AVHWDeviceContext *dev_ctx = _hwctx.nc; + + DPXVulkanDecodePicture *pp = data; + FFVulkanDecodePicture *vp = &pp->vp; + + ff_vk_decode_free_frame(dev_ctx, vp); +} + +const FFHWAccel ff_dpx_vulkan_hwaccel = { + .p.name = "dpx_vulkan", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_DPX, + .p.pix_fmt = AV_PIX_FMT_VULKAN, + .start_frame = &vk_dpx_start_frame, + .decode_slice = &vk_dpx_decode_slice, + .end_frame = &vk_dpx_end_frame, + .free_frame_priv = &vk_dpx_free_frame_priv, + .frame_priv_data_size = sizeof(DPXVulkanDecodePicture), + .init = &vk_decode_dpx_init, + .update_thread_context = &ff_vk_update_thread_context, + .uninit = &ff_vk_decode_uninit, + .frame_params = &ff_vk_frame_params, + .priv_data_size = sizeof(FFVulkanDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE, +}; diff --git a/libavcodec/vulkan_encode.c b/libavcodec/vulkan_encode.c index d187b7cdd..b6f0b26f6 100644 --- a/libavcodec/vulkan_encode.c +++ b/libavcodec/vulkan_encode.c @@ -71,7 +71,7 @@ static int vulkan_encode_init(AVCodecContext *avctx, FFHWBaseEncodePicture *pic) /* Input image view */ err = ff_vk_create_view(&ctx->s, &ctx->common, &vp->in.view, &vp->in.aspect, - vkf, vkfc->format[0], 0); + vkf, vkfc->format[0], VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR); if (err < 0) return err; @@ -81,7 +81,7 @@ static int vulkan_encode_init(AVCodecContext *avctx, FFHWBaseEncodePicture *pic) AVVkFrame *rvkf = (AVVkFrame *)rf->data[0]; err = ff_vk_create_view(&ctx->s, &ctx->common, &vp->dpb.view, &vp->dpb.aspect, - rvkf, ctx->pic_format, 1); + rvkf, ctx->pic_format, VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR); if (err < 0) return err; } else { @@ -182,7 +182,7 @@ static int vulkan_encode_issue(AVCodecContext *avctx, VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR, &ctx->profile_list, max_pkt_size, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT); + ctx->s.host_cached_flag); if (err < 0) return err; @@ -220,8 +220,7 @@ static int vulkan_encode_issue(AVCodecContext *avctx, .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, .pNext = NULL, .codedOffset = { 0 }, - .codedExtent = (VkExtent2D){ ctx->base.surface_width, - ctx->base.surface_height }, + .codedExtent = (VkExtent2D){ avctx->width, avctx->height }, .baseArrayLayer = ctx->common.layered_dpb ? slot_index : 0, .imageViewBinding = vp->dpb.view, }; @@ -339,7 +338,7 @@ static int vulkan_encode_issue(AVCodecContext *avctx, size_align); /* Start command buffer recording */ - exec = vp->exec = ff_vk_exec_get(&ctx->enc_pool); + exec = vp->exec = ff_vk_exec_get(&ctx->s, &ctx->enc_pool); ff_vk_exec_start(&ctx->s, exec); cmd_buf = exec->buf; @@ -465,6 +464,9 @@ static int vulkan_encode_output(AVCodecContext *avctx, VkResult ret; FFVulkanEncodePicture *vp = base_pic->priv; FFVulkanEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + AVPacket *pkt_ptr = pkt; + FFVkBuffer *sd_buf = (FFVkBuffer *)vp->pkt_buf->data; uint32_t *query_data; @@ -514,20 +516,56 @@ static int vulkan_encode_output(AVCodecContext *avctx, vk->FlushMappedMemoryRanges(ctx->s.hwctx->act_dev, 1, &invalidate_buf); } - pkt->data = sd_buf->mapped_mem; - pkt->size = vp->slices_offset + /* base offset */ - query_data[0] /* secondary offset */ + - query_data[1] /* size */; + if (vp->non_independent_frame) { + av_assert0(!ctx->prev_buf_ref); + size_t prev_buf_size = vp->slices_offset + query_data[0] + query_data[1]; + ctx->prev_buf_ref = vp->pkt_buf; + ctx->prev_buf_size = prev_buf_size; + vp->pkt_buf = NULL; - /* Move reference */ - pkt->buf = vp->pkt_buf; - vp->pkt_buf = NULL; + if (vp->tail_size) { + if (base_ctx->tail_pkt->size) + return AVERROR_BUG; + + ret = ff_get_encode_buffer(avctx, base_ctx->tail_pkt, vp->tail_size, 0); + if (ret < 0) + return ret; + + memcpy(base_ctx->tail_pkt->data, vp->tail_data, vp->tail_size); + pkt_ptr = base_ctx->tail_pkt; + } + } else { + if (ctx->prev_buf_ref) { + FFVkBuffer *prev_sd_buf = (FFVkBuffer *)ctx->prev_buf_ref->data; + size_t prev_size = ctx->prev_buf_size; + size_t size = (vp->slices_offset + query_data[0] + query_data[1]); + + ret = ff_get_encode_buffer(avctx, pkt, prev_size + size, 0); + if (ret < 0) + return ret; + + memcpy(pkt->data, prev_sd_buf->mapped_mem, prev_size); + memcpy(pkt->data + prev_size, sd_buf->mapped_mem, size); + + av_buffer_unref(&ctx->prev_buf_ref); + av_buffer_unref(&vp->pkt_buf); + } else { + pkt->data = sd_buf->mapped_mem; + pkt->size = vp->slices_offset + /* base offset */ + query_data[0] /* secondary offset */ + + query_data[1] /* size */; + + /* Move reference */ + pkt->buf = vp->pkt_buf; + vp->pkt_buf = NULL; + } + } av_log(avctx, AV_LOG_DEBUG, "Frame %"PRId64"/%"PRId64 " encoded\n", base_pic->display_order, base_pic->encode_order); return ff_hw_base_encode_set_output_property(&ctx->base, avctx, - base_pic, pkt, + base_pic, pkt_ptr, ctx->codec->flags & VK_ENC_FLAG_NO_DELAY); } @@ -565,14 +603,13 @@ static int vulkan_encode_create_dpb(AVCodecContext *avctx, FFVulkanEncodeContext base_ctx->recon_frames->format = AV_PIX_FMT_VULKAN; base_ctx->recon_frames->sw_format = dpb_format; - base_ctx->recon_frames->width = base_ctx->surface_width; - base_ctx->recon_frames->height = base_ctx->surface_height; + base_ctx->recon_frames->width = avctx->width; + base_ctx->recon_frames->height = avctx->height; hwfc->format[0] = ctx->pic_format; hwfc->create_pnext = &ctx->profile_list; hwfc->tiling = VK_IMAGE_TILING_OPTIMAL; - hwfc->usage = VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR; + hwfc->usage = VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR; if (ctx->common.layered_dpb) hwfc->nb_layers = ctx->caps.maxDpbSlots; @@ -598,7 +635,7 @@ static int vulkan_encode_create_dpb(AVCodecContext *avctx, FFVulkanEncodeContext &ctx->common.layered_view, &ctx->common.layered_aspect, (AVVkFrame *)ctx->common.layered_frame->data[0], - hwfc->format[0], 1); + hwfc->format[0], VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR); if (err < 0) return err; @@ -714,6 +751,8 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * VkVideoFormatPropertiesKHR *ret_info; uint32_t nb_out_fmts = 0; + const uint32_t feedback_flags = VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BUFFER_OFFSET_BIT_KHR | + VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BYTES_WRITTEN_BIT_KHR; VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR quality_info; @@ -733,6 +772,14 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * return AVERROR(EINVAL); } + if ((ctx->enc_caps.supportedEncodeFeedbackFlags & feedback_flags) != + feedback_flags) { + av_log (avctx, AV_LOG_ERROR, + "Driver does not support required encode feedback flags " + "(BUFFER_OFFSET and BYTES_WRITTEN).\n"); + return AVERROR(ENOTSUP); + } + ctx->base.op = &vulkan_base_encode_ops; ctx->codec = codec; @@ -770,10 +817,8 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * return err; /* Create queue context */ - err = ff_vk_video_qf_init(s, &ctx->qf_enc, - VK_QUEUE_VIDEO_ENCODE_BIT_KHR, - vk_desc->encode_op); - if (err < 0) { + ctx->qf_enc = ff_vk_qf_find(s, VK_QUEUE_VIDEO_ENCODE_BIT_KHR, vk_desc->encode_op); + if (!ctx->qf_enc) { av_log(avctx, AV_LOG_ERROR, "Encoding of %s is not supported by this device\n", avcodec_get_name(avctx->codec_id)); return err; @@ -844,10 +889,9 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * query_create = (VkQueryPoolVideoEncodeFeedbackCreateInfoKHR) { .sType = VK_STRUCTURE_TYPE_QUERY_POOL_VIDEO_ENCODE_FEEDBACK_CREATE_INFO_KHR, .pNext = &ctx->profile, - .encodeFeedbackFlags = ctx->enc_caps.supportedEncodeFeedbackFlags & - (~VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_HAS_OVERRIDES_BIT_KHR), + .encodeFeedbackFlags = feedback_flags, }; - err = ff_vk_exec_pool_init(s, &ctx->qf_enc, &ctx->enc_pool, base_ctx->async_depth, + err = ff_vk_exec_pool_init(s, ctx->qf_enc, &ctx->enc_pool, base_ctx->async_depth, 1, VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR, 0, &query_create); if (err < 0) @@ -915,9 +959,9 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * /* Setup width/height alignment */ base_ctx->surface_width = avctx->coded_width = - FFALIGN(avctx->width, ctx->caps.pictureAccessGranularity.width); + FFALIGN(avctx->width, ctx->enc_caps.encodeInputPictureGranularity.width); base_ctx->surface_height = avctx->coded_height = - FFALIGN(avctx->height, ctx->caps.pictureAccessGranularity.height); + FFALIGN(avctx->height, ctx->enc_caps.encodeInputPictureGranularity.height); /* Setup slice width/height */ base_ctx->slice_block_width = ctx->enc_caps.encodeInputPictureGranularity.width; @@ -934,8 +978,7 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * return AVERROR(EINVAL); } - fmt_info.imageUsage = VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR | - VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR; + fmt_info.imageUsage = VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR; ctx->common.layered_dpb = !(ctx->caps.flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR); @@ -995,7 +1038,7 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * /* Create session */ session_create.pVideoProfile = &ctx->profile; session_create.flags = 0x0; - session_create.queueFamilyIndex = ctx->qf_enc.queue_family; + session_create.queueFamilyIndex = ctx->qf_enc->idx; session_create.maxCodedExtent = ctx->caps.maxCodedExtent; session_create.maxDpbSlots = ctx->caps.maxDpbSlots; session_create.maxActiveReferencePictures = ctx->caps.maxActiveReferencePictures; diff --git a/libavcodec/vulkan_encode.h b/libavcodec/vulkan_encode.h index a7a02d5fd..cf5f25562 100644 --- a/libavcodec/vulkan_encode.h +++ b/libavcodec/vulkan_encode.h @@ -57,6 +57,10 @@ typedef struct FFVulkanEncodePicture { FFVkExecContext *exec; AVBufferRef *pkt_buf; int slices_offset; + + int non_independent_frame; + char tail_data[16]; + size_t tail_size; } FFVulkanEncodePicture; /** @@ -188,10 +192,13 @@ typedef struct FFVulkanEncodeContext { VkVideoEncodeCapabilitiesKHR enc_caps; VkVideoEncodeUsageInfoKHR usage_info; - FFVkQueueFamilyCtx qf_enc; + AVVulkanDeviceQueueFamily *qf_enc; FFVkExecPool enc_pool; FFHWBaseEncodePicture *slots[32]; + + AVBufferRef *prev_buf_ref; + size_t prev_buf_size; } FFVulkanEncodeContext; #define VULKAN_ENCODE_COMMON_OPTIONS \ diff --git a/libavcodec/vulkan_encode_av1.c b/libavcodec/vulkan_encode_av1.c new file mode 100644 index 000000000..c280f37a9 --- /dev/null +++ b/libavcodec/vulkan_encode_av1.c @@ -0,0 +1,1464 @@ +/* + * 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/opt.h" +#include "libavutil/mem.h" + +#include "cbs.h" +#include "cbs_av1.h" +#include "av1_levels.h" +#include "libavutil/mastering_display_metadata.h" + +#include "codec_internal.h" +#include "vulkan_encode.h" + +#include "libavutil/avassert.h" + +const FFVulkanEncodeDescriptor ff_vk_enc_av1_desc = { + .codec_id = AV_CODEC_ID_AV1, + .encode_extension = FF_VK_EXT_VIDEO_ENCODE_AV1, + .encode_op = VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR, + .ext_props = { + .extensionName = VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_EXTENSION_NAME, + .specVersion = VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_SPEC_VERSION, + }, +}; + +enum UnitElems { + UNIT_MASTERING_DISPLAY = 1 << 0, + UNIT_CONTENT_LIGHT_LEVEL = 1 << 1, +}; + +typedef struct VulkanEncodeAV1Picture { + int slot; + int64_t last_idr_frame; + + enum UnitElems units_needed; + + StdVideoAV1TileInfo tile_info; + StdVideoAV1Quantization quantization; + StdVideoAV1Segmentation segmentation; + StdVideoAV1LoopFilter loop_filter; + StdVideoAV1CDEF cdef; + StdVideoAV1LoopRestoration loop_restoration; + StdVideoAV1GlobalMotion global_motion; + + StdVideoEncodeAV1PictureInfo av1pic_info; + VkVideoEncodeAV1PictureInfoKHR vkav1pic_info; + + StdVideoEncodeAV1ExtensionHeader ext_header; + StdVideoEncodeAV1ReferenceInfo av1dpb_info; + VkVideoEncodeAV1DpbSlotInfoKHR vkav1dpb_info; + + VkVideoEncodeAV1RateControlInfoKHR vkrc_info; + VkVideoEncodeAV1RateControlLayerInfoKHR vkrc_layer_info; + VkVideoEncodeAV1GopRemainingFrameInfoKHR vkrc_remaining; +} VulkanEncodeAV1Picture; + +typedef struct VulkanEncodeAV1Context { + FFVulkanEncodeContext common; + + CodedBitstreamContext *cbs; + CodedBitstreamFragment current_access_unit; + + enum UnitElems unit_elems; + AV1RawOBU seq_hdr_obu; + AV1RawOBU meta_cll_obu; + AV1RawOBU meta_mastering_obu; + AV1RawOBU hidden_obu; + AV1RawOBU tail_obu; + + VkVideoEncodeAV1ProfileInfoKHR profile; + + VkVideoEncodeAV1CapabilitiesKHR caps; + VkVideoEncodeAV1QualityLevelPropertiesKHR quality_props; + + uint64_t hrd_buffer_size; + uint64_t initial_buffer_fullness; + + int uniform_tile; + int tile_cols; + int tile_rows; + + int seq_tier; + int seq_level_idx; + + int q_idx_idr; + int q_idx_p; + int q_idx_b; + + uint8_t *padding_payload; +} VulkanEncodeAV1Context; + +static int init_pic_rc(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + VkVideoEncodeRateControlInfoKHR *rc_info, + VkVideoEncodeRateControlLayerInfoKHR *rc_layer) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + VulkanEncodeAV1Picture *ap = pic->codec_priv; + + /* This can be easy to calculate */ + ap->vkrc_remaining = (VkVideoEncodeAV1GopRemainingFrameInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_GOP_REMAINING_FRAME_INFO_KHR, + .useGopRemainingFrames = 0, + .gopRemainingIntra = 0, + .gopRemainingPredictive = 0, + .gopRemainingBipredictive = 0, + }; + + ap->vkrc_info = (VkVideoEncodeAV1RateControlInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_RATE_CONTROL_INFO_KHR, + .flags = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_KHR | + VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REGULAR_GOP_BIT_KHR, + .gopFrameCount = ctx->base.gop_size, + .keyFramePeriod = ctx->base.gop_size, + .consecutiveBipredictiveFrameCount = FFMAX(ctx->base.b_per_p - 1, 0), + .temporalLayerCount = 0, + }; + rc_info->pNext = &ap->vkrc_info; + + if (rc_info->rateControlMode > VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) { + rc_info->virtualBufferSizeInMs = (enc->hrd_buffer_size * 1000LL) / avctx->bit_rate; + rc_info->initialVirtualBufferSizeInMs = (enc->initial_buffer_fullness * 1000LL) / avctx->bit_rate; + + ap->vkrc_layer_info = (VkVideoEncodeAV1RateControlLayerInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_RATE_CONTROL_LAYER_INFO_KHR, + + .useMinQIndex = avctx->qmin > 0, + .minQIndex.intraQIndex = avctx->qmin > 0 ? avctx->qmin : 0, + .minQIndex.predictiveQIndex = avctx->qmin > 0 ? avctx->qmin : 0, + .minQIndex.bipredictiveQIndex = avctx->qmin > 0 ? avctx->qmin : 0, + + .useMaxQIndex = avctx->qmax > 0, + .maxQIndex.intraQIndex = avctx->qmax > 0 ? avctx->qmax : 0, + .maxQIndex.predictiveQIndex = avctx->qmax > 0 ? avctx->qmax : 0, + .maxQIndex.bipredictiveQIndex = avctx->qmax > 0 ? avctx->qmax : 0, + + .useMaxFrameSize = 0, + }; + rc_layer->pNext = &ap->vkrc_layer_info; + ap->vkrc_info.temporalLayerCount = 1; + } + + return 0; +} + +static void set_name_slot(int slot, int *slot_indices, uint32_t allowed_idx, int group) +{ + int from = group ? AV1_REF_FRAME_GOLDEN : 0; + int to = group ? AV1_REFS_PER_FRAME : AV1_REF_FRAME_GOLDEN; + + for (int i = from; i < to; i++) { + if ((slot_indices[i] == -1) && (allowed_idx & (1 << i))) { + slot_indices[i] = slot; + return; + } + } + + av_assert0(0); +} + +static int init_pic_params(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + VkVideoEncodeInfoKHR *encode_info) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + + VulkanEncodeAV1Picture *ap = pic->codec_priv; + FFHWBaseEncodePicture *ref; + VulkanEncodeAV1Picture *ap_ref; + VkVideoReferenceSlotInfoKHR *ref_slot; + + uint32_t ref_name_mask = 0x0; + int name_slots[STD_VIDEO_AV1_REFS_PER_FRAME]; + + StdVideoAV1Segmentation *segmentation = &ap->segmentation; + StdVideoAV1LoopFilter *loop_filter = &ap->loop_filter; + StdVideoAV1Quantization *quantization = &ap->quantization; + StdVideoAV1CDEF *cdef = &ap->cdef; + StdVideoAV1LoopRestoration *loop_restoration = &ap->loop_restoration; + StdVideoAV1GlobalMotion *global_motion = &ap->global_motion; + StdVideoAV1TileInfo *tile_info = &ap->tile_info; + static const int8_t default_loop_filter_ref_deltas[STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME] = + { 1, 0, 0, 0, -1, 0, -1, -1 }; + + VkVideoEncodeAV1PredictionModeKHR pred_mode; + VkVideoEncodeAV1RateControlGroupKHR rc_group; + int lr_unit_shift = 0; + int lr_uv_shift = 0; + + ap->ext_header = (StdVideoEncodeAV1ExtensionHeader) { + .temporal_id = 0, + .spatial_id = 0, + }; + + *tile_info = (StdVideoAV1TileInfo) { + .flags = (StdVideoAV1TileInfoFlags) { + .uniform_tile_spacing_flag = enc->uniform_tile, + }, + .TileCols = enc->tile_cols, + .TileRows = enc->tile_rows, + .context_update_tile_id = 0, + .tile_size_bytes_minus_1 = 0, + }; + + for (int i = 0; i < STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME; i++) { + global_motion->GmType[i] = 0; + for (int j = 0; j < STD_VIDEO_AV1_GLOBAL_MOTION_PARAMS; j++) { + global_motion->gm_params[i][j] = 0; + } + } + + for (int i = 0; i < STD_VIDEO_AV1_REFS_PER_FRAME; i++) + name_slots[i] = -1; + + *loop_restoration = (StdVideoAV1LoopRestoration) { + .FrameRestorationType[0] = STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_NONE, + .FrameRestorationType[1] = STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_NONE, + .FrameRestorationType[2] = STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_NONE, + .LoopRestorationSize[0] = 1 + lr_unit_shift, + .LoopRestorationSize[1] = 1 + lr_unit_shift - lr_uv_shift, + .LoopRestorationSize[2] = 1 + lr_unit_shift - lr_uv_shift, + }; + + *cdef = (StdVideoAV1CDEF) { + .cdef_damping_minus_3 = 0, + .cdef_bits = 0, + }; + + for (int i = 0; i < STD_VIDEO_AV1_MAX_SEGMENTS; i++) { + segmentation->FeatureEnabled[i] = 0x0; + for (int j = 0; j < STD_VIDEO_AV1_SEG_LVL_MAX; j++) { + segmentation->FeatureEnabled[i] |= 0x0; + segmentation->FeatureData[i][j] = 0; + } + } + + *loop_filter = (StdVideoAV1LoopFilter) { + .flags = (StdVideoAV1LoopFilterFlags) { + .loop_filter_delta_enabled = 0, + .loop_filter_delta_update = 0, + }, + .loop_filter_level = { 0 }, + .loop_filter_sharpness = 0, + .update_ref_delta = 0, + .loop_filter_ref_deltas = { 0 }, + .update_mode_delta = 0, + .loop_filter_mode_deltas = { 0 }, + }; + loop_filter->update_mode_delta = 1; + memcpy(loop_filter->loop_filter_ref_deltas, default_loop_filter_ref_deltas, + STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME * sizeof(int8_t)); + + *quantization = (StdVideoAV1Quantization) { + .flags = (StdVideoAV1QuantizationFlags) { + .using_qmatrix = 0, + .diff_uv_delta = 0, + /* Reserved */ + }, + .base_q_idx = 0, /* Set later */ + .DeltaQYDc = 0, + .DeltaQUDc = 0, + .DeltaQUAc = 0, + .DeltaQVDc = 0, + .DeltaQVAc = 0, + .qm_y = 0, + .qm_u = 0, + .qm_v = 0, + }; + + ref_slot = (VkVideoReferenceSlotInfoKHR *)encode_info->pSetupReferenceSlot; + ap->av1pic_info = (StdVideoEncodeAV1PictureInfo) { + .flags = (StdVideoEncodeAV1PictureInfoFlags) { + .error_resilient_mode = (pic->type == FF_HW_PICTURE_TYPE_I || + pic->type == FF_HW_PICTURE_TYPE_IDR) && + (pic->display_order <= pic->encode_order), + .disable_cdf_update = 0, + .use_superres = 0, + .render_and_frame_size_different = 0, + .allow_screen_content_tools = 0, + .is_filter_switchable = 0, + .force_integer_mv = 0, + .frame_size_override_flag = 0, + .buffer_removal_time_present_flag = 0, + .allow_intrabc = 0, + .frame_refs_short_signaling = 0, + .allow_high_precision_mv = 0, + .is_motion_mode_switchable = 0, + .use_ref_frame_mvs = 0, + .disable_frame_end_update_cdf = 0, + .allow_warped_motion = 0, + .reduced_tx_set = 0, + .skip_mode_present = 0, + .delta_q_present = 0, + .delta_lf_present = 0, + .delta_lf_multi = 0, + .segmentation_enabled = 0, + .segmentation_update_map = 0, + .segmentation_temporal_update = 0, + .segmentation_update_data = 0, + .UsesLr = 0, + .usesChromaLr = 0, + .show_frame = pic->display_order <= pic->encode_order, + .showable_frame = 0, + /* Reserved */ + }, + .frame_type = 0, // set later + .frame_presentation_time = 0, + .current_frame_id = ref_slot->slotIndex, + .order_hint = 0, // set later + .primary_ref_frame = 0, // set later + .refresh_frame_flags = 0x0, // set later + .coded_denom = 0, + .render_width_minus_1 = base_ctx->surface_width - 1, + .render_height_minus_1 = base_ctx->surface_height - 1, + .interpolation_filter = 0, + .TxMode = STD_VIDEO_AV1_TX_MODE_SELECT, + .delta_q_res = 0, + .delta_lf_res = 0, + .ref_order_hint = { 0 }, // set later + .ref_frame_idx = { 0 }, // set later + /* Reserved */ + .delta_frame_id_minus_1 = { 0 }, + +// .pTileInfo = tile_info, TODO FIX + .pQuantization = quantization, + .pSegmentation = segmentation, + .pLoopFilter = loop_filter, + .pCDEF = cdef, + .pLoopRestoration = loop_restoration, + .pGlobalMotion = global_motion, + .pExtensionHeader = &ap->ext_header, + .pBufferRemovalTimes = NULL, + }; + + switch (pic->type) { + case FF_HW_PICTURE_TYPE_I: + case FF_HW_PICTURE_TYPE_IDR: + av_assert0(pic->nb_refs[0] == 0 || pic->nb_refs[1]); + ap->av1pic_info.frame_type = STD_VIDEO_AV1_FRAME_TYPE_KEY; + ap->av1pic_info.refresh_frame_flags = 0xFF; + quantization->base_q_idx = enc->q_idx_idr; + ap->slot = 0; + ap->last_idr_frame = pic->display_order; + pred_mode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_INTRA_ONLY_KHR; + rc_group = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_GROUP_INTRA_KHR; + break; + case FF_HW_PICTURE_TYPE_P: + ref = pic->refs[0][pic->nb_refs[0] - 1]; + ap_ref = ref->codec_priv; + + ap->av1pic_info.frame_type = STD_VIDEO_AV1_FRAME_TYPE_INTER; + quantization->base_q_idx = enc->q_idx_p; + + ap->last_idr_frame = ap_ref->last_idr_frame; + ap->slot = !ap_ref->slot; + + ap->av1pic_info.refresh_frame_flags = 1 << ap->slot; + + /** set the nearest frame in L0 as all reference frame. */ + for (int i = 0; i < AV1_REFS_PER_FRAME; i++) + ap->av1pic_info.ref_frame_idx[i] = ap_ref->slot; + + ap->av1pic_info.primary_ref_frame = ap_ref->slot; + ap->av1pic_info.ref_order_hint[ap_ref->slot] = ref->display_order - ap_ref->last_idr_frame; + rc_group = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_GROUP_PREDICTIVE_KHR; + pred_mode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_SINGLE_REFERENCE_KHR; + ref_name_mask = enc->caps.singleReferenceNameMask; + set_name_slot(ap_ref->av1pic_info.current_frame_id, name_slots, ref_name_mask, 0); + +// vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST; + + /** set the 2nd nearest frame in L0 as Golden frame. */ + if ((pic->nb_refs[0] > 1) && + ((enc->caps.maxSingleReferenceCount > 1) || + (enc->caps.maxUnidirectionalCompoundReferenceCount > 0))) { + if (enc->caps.maxUnidirectionalCompoundReferenceCount) { + pred_mode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_UNIDIRECTIONAL_COMPOUND_KHR; + ref_name_mask = enc->caps.unidirectionalCompoundReferenceNameMask; + } + ref = pic->refs[0][pic->nb_refs[0] - 2]; + ap_ref = ref->codec_priv; + ap->av1pic_info.ref_frame_idx[3] = ap_ref->slot; + ap->av1pic_info.ref_order_hint[ap_ref->slot] = ref->display_order - ap_ref->last_idr_frame; +// vpic->ref_frame_ctrl_l0.fields.search_idx1 = AV1_REF_FRAME_GOLDEN; + set_name_slot(ap_ref->av1pic_info.current_frame_id, name_slots, ref_name_mask, 0); + } + break; + case FF_HW_PICTURE_TYPE_B: + ap->av1pic_info.frame_type = STD_VIDEO_AV1_FRAME_TYPE_INTER; + quantization->base_q_idx = enc->q_idx_b; + ap->av1pic_info.refresh_frame_flags = 0x0; + + rc_group = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_GROUP_BIPREDICTIVE_KHR; + pred_mode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_BIDIRECTIONAL_COMPOUND_KHR; + ref_name_mask = enc->caps.bidirectionalCompoundReferenceNameMask; + +// fh->reference_select = 1; + /** B frame will not be referenced, disable its recon frame. */ +// vpic->picture_flags.bits.disable_frame_recon = 1; + + /** Use LAST_FRAME and BWDREF_FRAME for reference. */ +// vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST; +// vpic->ref_frame_ctrl_l1.fields.search_idx0 = AV1_REF_FRAME_BWDREF; + + ref = pic->refs[0][pic->nb_refs[0] - 1]; + ap_ref = ref->codec_priv; + ap->last_idr_frame = ap_ref->last_idr_frame; + ap->av1pic_info.primary_ref_frame = ap_ref->slot; + ap->av1pic_info.ref_order_hint[ap_ref->slot] = ref->display_order - ap_ref->last_idr_frame; + for (int i = 0; i < AV1_REF_FRAME_GOLDEN; i++) + ap->av1pic_info.ref_frame_idx[i] = ap_ref->slot; + set_name_slot(ap_ref->av1pic_info.current_frame_id, name_slots, ref_name_mask, 0); + + ref = pic->refs[1][pic->nb_refs[1] - 1]; + ap_ref = ref->codec_priv; + ap->av1pic_info.ref_order_hint[ap_ref->slot] = ref->display_order - ap_ref->last_idr_frame; + for (int i = AV1_REF_FRAME_GOLDEN; i < AV1_REFS_PER_FRAME; i++) + ap->av1pic_info.ref_frame_idx[i] = ap_ref->slot; + set_name_slot(ap_ref->av1pic_info.current_frame_id, name_slots, ref_name_mask, 1); + break; + } + + ap->av1pic_info.flags.showable_frame = ap->av1pic_info.frame_type != STD_VIDEO_AV1_FRAME_TYPE_KEY; + ap->av1pic_info.order_hint = pic->display_order - ap->last_idr_frame; + + ap->vkav1pic_info = (VkVideoEncodeAV1PictureInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_PICTURE_INFO_KHR, + .pNext = NULL, + .predictionMode = pred_mode, + .rateControlGroup = rc_group, + .constantQIndex = quantization->base_q_idx, + .pStdPictureInfo = &ap->av1pic_info, + // .referenceNameSlotIndices is set below + .primaryReferenceCdfOnly = 0, + .generateObuExtensionHeader = 0, + }; + encode_info->pNext = &ap->vkav1pic_info; + + for (int i = 0; i < FF_ARRAY_ELEMS(ap->vkav1pic_info.referenceNameSlotIndices); i++) + ap->vkav1pic_info.referenceNameSlotIndices[i] = name_slots[i]; + + ref_slot = (VkVideoReferenceSlotInfoKHR *)encode_info->pSetupReferenceSlot; + ref_slot->pNext = &ap->vkav1dpb_info; + + ap->av1dpb_info = (StdVideoEncodeAV1ReferenceInfo) { + .flags = (StdVideoEncodeAV1ReferenceInfoFlags) { + .disable_frame_end_update_cdf = 0, + .segmentation_enabled = 0, + /* Reserved */ + }, + .RefFrameId = ref_slot->slotIndex, + .frame_type = ap->av1pic_info.frame_type, + .OrderHint = pic->display_order - ap->last_idr_frame, + /* Reserved */ + .pExtensionHeader = &ap->ext_header, + }; + + ap->vkav1dpb_info = (VkVideoEncodeAV1DpbSlotInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_DPB_SLOT_INFO_KHR, + .pStdReferenceInfo = &ap->av1dpb_info, + }; + + ap->units_needed = 0; + if (pic->type == FF_HW_PICTURE_TYPE_IDR) { + AVFrameSideData *sd = NULL; + if (enc->unit_elems & UNIT_MASTERING_DISPLAY) + sd = av_frame_get_side_data(pic->input_image, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + if (sd) { + AVMasteringDisplayMetadata *mdm = + (AVMasteringDisplayMetadata *)sd->data; + if (mdm->has_primaries && mdm->has_luminance) { + AV1RawOBU *obu = &enc->meta_mastering_obu; + AV1RawMetadata *md = &obu->obu.metadata; + AV1RawMetadataHDRMDCV *mdcv = &md->metadata.hdr_mdcv; + const int chroma_den = 1 << 16; + const int max_luma_den = 1 << 8; + const int min_luma_den = 1 << 14; + + memset(obu, 0, sizeof(*obu)); + obu->header.obu_type = AV1_OBU_METADATA; + md->metadata_type = AV1_METADATA_TYPE_HDR_MDCV; + + for (int i = 0; i < 3; i++) { + mdcv->primary_chromaticity_x[i] = + av_rescale(mdm->display_primaries[i][0].num, chroma_den, + mdm->display_primaries[i][0].den); + mdcv->primary_chromaticity_y[i] = + av_rescale(mdm->display_primaries[i][1].num, chroma_den, + mdm->display_primaries[i][1].den); + } + + mdcv->white_point_chromaticity_x = + av_rescale(mdm->white_point[0].num, chroma_den, + mdm->white_point[0].den); + mdcv->white_point_chromaticity_y = + av_rescale(mdm->white_point[1].num, chroma_den, + mdm->white_point[1].den); + + mdcv->luminance_max = + av_rescale(mdm->max_luminance.num, max_luma_den, + mdm->max_luminance.den); + mdcv->luminance_min = + av_rescale(mdm->min_luminance.num, min_luma_den, + mdm->min_luminance.den); + ap->units_needed |= UNIT_MASTERING_DISPLAY; + } + } + + if (enc->unit_elems & UNIT_CONTENT_LIGHT_LEVEL) + sd = av_frame_get_side_data(pic->input_image, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + if (sd) { + AVContentLightMetadata *cllm = (AVContentLightMetadata *)sd->data; + AV1RawOBU *obu = &enc->meta_cll_obu; + AV1RawMetadata *md = &obu->obu.metadata; + AV1RawMetadataHDRCLL *cll = &md->metadata.hdr_cll; + + memset(obu, 0, sizeof(*obu)); + obu->header.obu_type = AV1_OBU_METADATA; + md->metadata_type = AV1_METADATA_TYPE_HDR_CLL; + cll->max_cll = cllm->MaxCLL; + cll->max_fall = cllm->MaxFALL; + + ap->units_needed |= UNIT_CONTENT_LIGHT_LEVEL; + } + } + + FFVulkanEncodePicture *vp = pic->priv; + vp->tail_size = 0; + vp->non_independent_frame = pic->encode_order < pic->display_order; + if (vp->non_independent_frame) { + AV1RawOBU *obu = &enc->hidden_obu; + AV1RawFrameHeader *fh = &obu->obu.frame_header; + + /** hidden frame header */ + memset(obu, 0, sizeof(*obu)); + obu->header.obu_type = AV1_OBU_FRAME_HEADER; + obu->header.obu_has_size_field = 1; + + fh->frame_type = AV1_FRAME_INTER; + fh->refresh_frame_flags = 1 << ap->slot; + fh->frame_width_minus_1 = base_ctx->surface_width - 1; + fh->frame_height_minus_1 = base_ctx->surface_height - 1; + fh->render_width_minus_1 = fh->frame_width_minus_1; + fh->render_height_minus_1 = fh->frame_height_minus_1; + + memcpy(fh->loop_filter_ref_deltas, default_loop_filter_ref_deltas, + AV1_TOTAL_REFS_PER_FRAME * sizeof(int8_t)); + + obu = &enc->tail_obu; + fh = &obu->obu.frame_header; + + /** tail frame header */ + memset(obu, 0, sizeof(*obu)); + obu->header.obu_type = AV1_OBU_FRAME_HEADER; + obu->header.obu_has_size_field = 1; + + fh->show_existing_frame = 1; + fh->frame_to_show_map_idx = ap->slot != 0; + fh->frame_type = AV1_FRAME_INTER; + fh->frame_width_minus_1 = base_ctx->surface_width - 1; + fh->frame_height_minus_1 = base_ctx->surface_height - 1; + fh->render_width_minus_1 = fh->frame_width_minus_1; + fh->render_height_minus_1 = fh->frame_height_minus_1; + } + + return 0; +} + +static int init_profile(AVCodecContext *avctx, + VkVideoProfileInfoKHR *profile, void *pnext) +{ + VkResult ret; + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + + VkVideoEncodeAV1CapabilitiesKHR av1_caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR, + }; + VkVideoEncodeCapabilitiesKHR enc_caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR, + .pNext = &av1_caps, + }; + VkVideoCapabilitiesKHR caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR, + .pNext = &enc_caps, + }; + + /* In order of preference */ + int last_supported = AV_PROFILE_UNKNOWN; + static const int known_profiles[] = { + AV_PROFILE_AV1_MAIN, + AV_PROFILE_AV1_HIGH, + AV_PROFILE_AV1_PROFESSIONAL, + }; + int nb_profiles = FF_ARRAY_ELEMS(known_profiles); + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->frames->sw_format); + if (!desc) + return AVERROR(EINVAL); + + if (s->frames->sw_format == AV_PIX_FMT_NV12 || + s->frames->sw_format == AV_PIX_FMT_P010) + nb_profiles = 1; + + enc->profile = (VkVideoEncodeAV1ProfileInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_PROFILE_INFO_KHR, + .pNext = pnext, + .stdProfile = ff_vk_av1_profile_to_vk(avctx->profile), + }; + profile->pNext = &enc->profile; + + /* Set level */ + if (avctx->level == AV_LEVEL_UNKNOWN) { + const AV1LevelDescriptor *level; + float framerate = 0.0; + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) + framerate = av_q2d(avctx->framerate); + + level = ff_av1_guess_level(avctx->bit_rate, enc->seq_tier, + base_ctx->surface_width, base_ctx->surface_height, + enc->tile_rows * enc->tile_cols, + enc->tile_cols, framerate); + if (level) { + av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); + enc->seq_level_idx = level->level_idx; + } else { + av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to " + "any normal level, using level 7.3 by default.\n"); + enc->seq_level_idx = STD_VIDEO_AV1_LEVEL_7_3; + enc->seq_tier = 1; + } + } else { + enc->seq_level_idx = ff_vk_av1_level_to_vk(avctx->level); + } + + /* User has explicitly specified a profile. */ + if (avctx->profile != AV_PROFILE_UNKNOWN) + return 0; + + av_log(avctx, AV_LOG_DEBUG, "Supported profiles:\n"); + for (int i = 0; i < nb_profiles; i++) { + enc->profile.stdProfile = ff_vk_av1_profile_to_vk(known_profiles[i]); + ret = vk->GetPhysicalDeviceVideoCapabilitiesKHR(s->hwctx->phys_dev, + profile, + &caps); + if (ret == VK_SUCCESS) { + av_log(avctx, AV_LOG_DEBUG, " %s\n", + avcodec_profile_name(avctx->codec_id, known_profiles[i])); + last_supported = known_profiles[i]; + } + } + + if (last_supported == AV_PROFILE_UNKNOWN) { + av_log(avctx, AV_LOG_ERROR, "No supported profiles for given format\n"); + return AVERROR(ENOTSUP); + } + + enc->profile.stdProfile = ff_vk_av1_profile_to_vk(last_supported); + av_log(avctx, AV_LOG_VERBOSE, "Using profile %s\n", + avcodec_profile_name(avctx->codec_id, last_supported)); + avctx->profile = last_supported; + + return 0; +} + +static int init_enc_options(AVCodecContext *avctx) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + + if (avctx->rc_buffer_size) + enc->hrd_buffer_size = avctx->rc_buffer_size; + else if (avctx->rc_max_rate > 0) + enc->hrd_buffer_size = avctx->rc_max_rate; + else + enc->hrd_buffer_size = avctx->bit_rate; + + if (avctx->rc_initial_buffer_occupancy) { + if (avctx->rc_initial_buffer_occupancy > enc->hrd_buffer_size) { + av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: " + "must have initial buffer size (%d) <= " + "buffer size (%"PRId64").\n", + avctx->rc_initial_buffer_occupancy, enc->hrd_buffer_size); + return AVERROR(EINVAL); + } + enc->initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; + } else { + enc->initial_buffer_fullness = enc->hrd_buffer_size * 3 / 4; + } + + if (enc->common.opts.rc_mode == VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) { + enc->q_idx_p = av_clip(enc->common.opts.qp, + enc->caps.minQIndex, enc->caps.maxQIndex); + if (fabs(avctx->i_quant_factor) > 0.0) + enc->q_idx_idr = + av_clip((fabs(avctx->i_quant_factor) * enc->q_idx_p + + avctx->i_quant_offset) + 0.5, + 0, 255); + else + enc->q_idx_idr = enc->q_idx_p; + + if (fabs(avctx->b_quant_factor) > 0.0) + enc->q_idx_b = + av_clip((fabs(avctx->b_quant_factor) * enc->q_idx_p + + avctx->b_quant_offset) + 0.5, + 0, 255); + else + enc->q_idx_b = enc->q_idx_p; + } else { + /** Arbitrary value */ + enc->q_idx_idr = enc->q_idx_p = enc->q_idx_b = 128; + } + + return 0; +} + +static av_cold int init_sequence_headers(AVCodecContext *avctx) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + + AV1RawOBU *seq_obu = &enc->seq_hdr_obu; + AV1RawSequenceHeader *seq = &seq_obu->obu.sequence_header; + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->frames->sw_format); + if (!desc) + return AVERROR(EINVAL); + + seq_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER; + *seq = (AV1RawSequenceHeader) { + .seq_profile = avctx->profile, + .seq_force_integer_mv = seq->seq_force_screen_content_tools ? + AV1_SELECT_SCREEN_CONTENT_TOOLS : + AV1_SELECT_INTEGER_MV, + .frame_width_bits_minus_1 = av_log2(base_ctx->surface_width), + .frame_height_bits_minus_1 = av_log2(base_ctx->surface_height), + .max_frame_width_minus_1 = base_ctx->surface_width - 1, + .max_frame_height_minus_1 = base_ctx->surface_height - 1, + .enable_order_hint = 1, + .order_hint_bits_minus_1 = av_clip_intp2(av_log2(ctx->base.gop_size), 3), + .use_128x128_superblock = !!(enc->caps.superblockSizes & VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_128_BIT_KHR), + .color_config = (AV1RawColorConfig) { + .high_bitdepth = desc->comp[0].depth > 8, + .color_primaries = avctx->color_primaries, + .transfer_characteristics = avctx->color_trc, + .matrix_coefficients = avctx->colorspace, + .color_description_present_flag = (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED), + .subsampling_x = desc->log2_chroma_w, + .subsampling_y = desc->log2_chroma_h, + .chroma_sample_position = avctx->chroma_sample_location == AVCHROMA_LOC_LEFT ? + AV1_CSP_VERTICAL : + avctx->chroma_sample_location == AVCHROMA_LOC_TOPLEFT ? + AV1_CSP_COLOCATED : + AV1_CSP_UNKNOWN, + }, + + /* Operating point */ + .seq_tier = { enc->seq_tier }, + .seq_level_idx = { enc->seq_level_idx }, + .decoder_buffer_delay = { base_ctx->decode_delay }, + .encoder_buffer_delay = { base_ctx->output_delay }, + .operating_points_cnt_minus_1 = 1 - 1, + }; + + return 0; +} + +typedef struct VulkanAV1Units { + StdVideoAV1SequenceHeader seq_hdr; + StdVideoAV1TimingInfo timing_info; + StdVideoAV1ColorConfig color_config; + + StdVideoEncodeAV1DecoderModelInfo decoder_model; + StdVideoEncodeAV1OperatingPointInfo operating_points[AV1_MAX_OPERATING_POINTS]; + int nb_operating_points; +} VulkanAV1Units; + +static av_cold int base_unit_to_vk(AVCodecContext *avctx, VulkanAV1Units *vk_units) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + + AV1RawOBU *seq_obu = &enc->seq_hdr_obu; + AV1RawSequenceHeader *seq = &seq_obu->obu.sequence_header; + + StdVideoAV1SequenceHeader *seq_hdr = &vk_units->seq_hdr; + StdVideoAV1TimingInfo *timing_info = &vk_units->timing_info; + StdVideoAV1ColorConfig *color_config = &vk_units->color_config; + + StdVideoEncodeAV1OperatingPointInfo *operating_points = vk_units->operating_points; + + *timing_info = (StdVideoAV1TimingInfo) { + .flags = (StdVideoAV1TimingInfoFlags) { + .equal_picture_interval = seq->timing_info.equal_picture_interval, + }, + .num_units_in_display_tick = seq->timing_info.num_units_in_display_tick, + .time_scale = seq->timing_info.time_scale, + .num_ticks_per_picture_minus_1 = seq->timing_info.num_ticks_per_picture_minus_1, + }; + + *color_config = (StdVideoAV1ColorConfig) { + .flags = (StdVideoAV1ColorConfigFlags) { + .mono_chrome = seq->color_config.mono_chrome, + .color_range = seq->color_config.color_range, + .separate_uv_delta_q = seq->color_config.separate_uv_delta_q, + }, + .BitDepth = seq->color_config.twelve_bit ? 12 : + seq->color_config.high_bitdepth ? 10 : 8, + .subsampling_x = seq->color_config.subsampling_x, + .subsampling_y = seq->color_config.subsampling_y, + .color_primaries = seq->color_config.color_primaries, + .transfer_characteristics = seq->color_config.transfer_characteristics, + .matrix_coefficients = seq->color_config.matrix_coefficients, + }; + + *seq_hdr = (StdVideoAV1SequenceHeader) { + .flags = (StdVideoAV1SequenceHeaderFlags) { + .still_picture = seq->still_picture, + .reduced_still_picture_header = seq->reduced_still_picture_header, + .use_128x128_superblock = seq->use_128x128_superblock, + .enable_filter_intra = seq->enable_filter_intra, + .enable_intra_edge_filter = seq->enable_intra_edge_filter, + .enable_interintra_compound = seq->enable_interintra_compound, + .enable_masked_compound = seq->enable_masked_compound, + .enable_warped_motion = seq->enable_warped_motion, + .enable_dual_filter = seq->enable_dual_filter, + .enable_order_hint = seq->enable_order_hint, + .enable_jnt_comp = seq->enable_jnt_comp, + .enable_ref_frame_mvs = seq->enable_ref_frame_mvs, + .frame_id_numbers_present_flag = seq->frame_id_numbers_present_flag, + .enable_superres = seq->enable_superres, + .enable_cdef = seq->enable_cdef, + .enable_restoration = seq->enable_restoration, + .film_grain_params_present = seq->film_grain_params_present, + .timing_info_present_flag = seq->timing_info_present_flag, + .initial_display_delay_present_flag = seq->initial_display_delay_present_flag, + }, + .seq_profile = seq->seq_profile, + .frame_width_bits_minus_1 = seq->frame_width_bits_minus_1, + .frame_height_bits_minus_1 = seq->frame_height_bits_minus_1, + .max_frame_width_minus_1 = seq->max_frame_width_minus_1, + .max_frame_height_minus_1 = seq->max_frame_height_minus_1, + .delta_frame_id_length_minus_2 = seq->delta_frame_id_length_minus_2, + .additional_frame_id_length_minus_1 = seq->additional_frame_id_length_minus_1, + .order_hint_bits_minus_1 = seq->order_hint_bits_minus_1, + .seq_force_integer_mv = seq->seq_force_integer_mv, + .seq_force_screen_content_tools = seq->seq_force_screen_content_tools, + .pTimingInfo = timing_info, + .pColorConfig = color_config, + }; + + for (int i = 0; i <= seq->operating_points_cnt_minus_1; i++) { + operating_points[i] = (StdVideoEncodeAV1OperatingPointInfo) { + .flags = (StdVideoEncodeAV1OperatingPointInfoFlags) { + .decoder_model_present_for_this_op = seq->decoder_model_present_for_this_op[i], + .low_delay_mode_flag = seq->low_delay_mode_flag[i], + .initial_display_delay_present_for_this_op = seq->initial_display_delay_present_for_this_op[i], + /* Reserved */ + }, + .operating_point_idc = seq->operating_point_idc[i], + .seq_level_idx = seq->seq_level_idx[i], + .seq_tier = seq->seq_tier[i], + .decoder_buffer_delay = seq->decoder_buffer_delay[i], + .encoder_buffer_delay = seq->encoder_buffer_delay[i], + .initial_display_delay_minus_1 = seq->initial_display_delay_minus_1[i], + }; + } + vk_units->nb_operating_points = seq->operating_points_cnt_minus_1 + 1; + + return 0; +} + +static int create_session_params(AVCodecContext *avctx) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + VulkanAV1Units vk_units = { 0 }; + + VkVideoEncodeAV1SessionParametersCreateInfoKHR av1_params; + + /* Convert it to Vulkan */ + err = base_unit_to_vk(avctx, &vk_units); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to convert sequence header to Vulkan: %s\n", + av_err2str(err)); + return err; + } + + /* Destroy the session params */ + if (ctx->session_params) + vk->DestroyVideoSessionParametersKHR(s->hwctx->act_dev, + ctx->session_params, + s->hwctx->alloc); + + av1_params = (VkVideoEncodeAV1SessionParametersCreateInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR, + .pStdSequenceHeader = &vk_units.seq_hdr, + .pStdDecoderModelInfo = &vk_units.decoder_model, + .pStdOperatingPoints = vk_units.operating_points, + .stdOperatingPointCount = vk_units.nb_operating_points, + }; + + return ff_vulkan_encode_create_session_params(avctx, ctx, &av1_params); +} + +static int parse_feedback_units(AVCodecContext *avctx, + const uint8_t *data, size_t size) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + AV1RawOBU *seq_obu = &enc->seq_hdr_obu; + AV1RawSequenceHeader *seq = &seq_obu->obu.sequence_header; + + CodedBitstreamContext *cbs; + CodedBitstreamFragment obu = { 0 }; + + err = ff_cbs_init(&cbs, AV_CODEC_ID_AV1, avctx); + if (err < 0) + return err; + + err = ff_cbs_read(cbs, &obu, NULL, data, size); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to parse feedback units, bad drivers: %s\n", + av_err2str(err)); + return err; + } + + /* If PPS has an override, just copy it entirely. */ + for (int i = 0; i < obu.nb_units; i++) { + if (obu.units[i].type == AV1_OBU_SEQUENCE_HEADER) { + AV1RawOBU *f_seq_obu = obu.units[i].content; + AV1RawSequenceHeader *f_seq = &f_seq_obu->obu.sequence_header; + seq->frame_width_bits_minus_1 = f_seq->frame_width_bits_minus_1; + seq->frame_height_bits_minus_1 = f_seq->frame_height_bits_minus_1; + seq->max_frame_width_minus_1 = f_seq->max_frame_width_minus_1; + seq->max_frame_height_minus_1 = f_seq->max_frame_height_minus_1; + seq->seq_choose_screen_content_tools = f_seq->seq_choose_screen_content_tools; + seq->seq_force_screen_content_tools = f_seq->seq_force_screen_content_tools; + seq->seq_choose_integer_mv = f_seq->seq_choose_integer_mv; + seq->seq_force_integer_mv = f_seq->seq_force_integer_mv; + } + } + + ff_cbs_fragment_free(&obu); + ff_cbs_close(&cbs); + + return 0; +} + +static int init_base_units(AVCodecContext *avctx) +{ + int err; + VkResult ret; + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + VkVideoEncodeSessionParametersGetInfoKHR params_info; + VkVideoEncodeSessionParametersFeedbackInfoKHR params_feedback; + + void *data = NULL; + size_t data_size = 0; + + /* Generate SPS/PPS unit info */ + err = init_sequence_headers(avctx); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to initialize sequence header: %s\n", + av_err2str(err)); + return err; + } + + /* Create session parameters from them */ + err = create_session_params(avctx); + if (err < 0) + return err; + + params_info = (VkVideoEncodeSessionParametersGetInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_GET_INFO_KHR, + .videoSessionParameters = ctx->session_params, + }; + params_feedback = (VkVideoEncodeSessionParametersFeedbackInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_FEEDBACK_INFO_KHR, + }; + + ret = vk->GetEncodedVideoSessionParametersKHR(s->hwctx->act_dev, ¶ms_info, + ¶ms_feedback, + &data_size, data); + if (ret == VK_INCOMPLETE || + (ret == VK_SUCCESS) && (data_size > 0)) { + data = av_mallocz(data_size); + if (!data) + return AVERROR(ENOMEM); + } else { + av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for AV1 sequence header = %zu\n", + data_size); + return err; + } + + ret = vk->GetEncodedVideoSessionParametersKHR(s->hwctx->act_dev, ¶ms_info, + ¶ms_feedback, + &data_size, data); + if (ret != VK_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Error writing feedback units\n"); + return err; + } + + av_log(avctx, AV_LOG_VERBOSE, "Feedback units written, overrides: %i\n", + params_feedback.hasOverrides); + + params_feedback.hasOverrides = 1; + + /* No need to sync any overrides */ + if (!params_feedback.hasOverrides) + return 0; + + /* Parse back tne units and override */ + err = parse_feedback_units(avctx, data, data_size); + if (err < 0) + return err; + + /* Create final session parameters */ + err = create_session_params(avctx); + if (err < 0) + return err; + + return 0; +} + +static int vulkan_encode_av1_add_obu(AVCodecContext *avctx, + CodedBitstreamFragment *au, + uint8_t type, void *obu_unit) +{ + int err; + + err = ff_cbs_insert_unit_content(au, -1, + type, obu_unit, NULL); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to add OBU unit: " + "type = %d.\n", type); + return err; + } + + return err; +} + +static int vulkan_encode_av1_write_obu(AVCodecContext *avctx, + uint8_t *data, size_t *data_len, + CodedBitstreamFragment *obu) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + int ret; + + ret = ff_cbs_write_fragment_data(enc->cbs, obu); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return ret; + } + + memcpy(data, obu->data, obu->data_size); + *data_len = obu->data_size; + + return 0; +} + +static int write_sequence_header(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + CodedBitstreamFragment *obu = &enc->current_access_unit; + + err = vulkan_encode_av1_add_obu(avctx, obu, + AV1_OBU_SEQUENCE_HEADER, &enc->seq_hdr_obu); + if (err < 0) + goto fail; + + err = vulkan_encode_av1_write_obu(avctx, data, data_len, obu); + +fail: + ff_cbs_fragment_reset(obu); + return err; +} + +static int write_extra_headers(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + VulkanEncodeAV1Picture *ap = base_pic->codec_priv; + FFVulkanEncodePicture *vp = base_pic->priv; + CodedBitstreamFragment *obu = &enc->current_access_unit; + + if (vp->non_independent_frame) { + err = vulkan_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, &enc->hidden_obu); + if (err < 0) + goto fail; + + // Only for tracking ref frame in context, not to be output + err = ff_cbs_write_fragment_data(enc->cbs, obu); + if (err < 0) + goto fail; + + ff_cbs_fragment_reset(obu); + ((CodedBitstreamAV1Context *)enc->cbs->priv_data)->seen_frame_header = 0; + + err = vulkan_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, &enc->tail_obu); + if (err < 0) + goto fail; + + err = vulkan_encode_av1_write_obu(avctx, vp->tail_data, &vp->tail_size, obu); + if (err < 0) + goto fail; + } + + if (ap->units_needed & UNIT_MASTERING_DISPLAY) { + err = vulkan_encode_av1_add_obu(avctx, obu, + AV1_OBU_METADATA, + &enc->meta_mastering_obu); + if (err < 0) + goto fail; + } + + if (ap->units_needed & UNIT_CONTENT_LIGHT_LEVEL) { + err = vulkan_encode_av1_add_obu(avctx, obu, + AV1_OBU_METADATA, + &enc->meta_cll_obu); + if (err < 0) + goto fail; + } + + if (ap->units_needed) { + err = vulkan_encode_av1_write_obu(avctx, data, data_len, obu); + if (err < 0) + goto fail; + } else { + err = 0; + *data_len = 0; + } + +fail: + ff_cbs_fragment_reset(obu); + return err; +} + +static int write_padding(AVCodecContext *avctx, uint32_t padding, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + CodedBitstreamFragment *obu = &enc->current_access_unit; + + AV1RawOBU padding_obu = { 0 }; + AV1RawPadding *raw_padding = &padding_obu.obu.padding; + + if (!padding) + padding = 16; + + /* 2 byte header + 1 byte trailing bits */ + padding_obu.header.obu_type = AV1_OBU_PADDING; + *raw_padding = (AV1RawPadding) { + .payload = enc->padding_payload, + .payload_size = padding, + }; + + err = vulkan_encode_av1_add_obu(avctx, obu, AV1_OBU_PADDING, &padding_obu); + if (err < 0) + goto fail; + + err = vulkan_encode_av1_write_obu(avctx, data, data_len, obu); +fail: + ff_cbs_fragment_reset(obu); + return err; +} + +static const FFVulkanCodec enc_cb = { + .flags = FF_HW_FLAG_B_PICTURES | + FF_HW_FLAG_B_PICTURE_REFERENCES | + VK_ENC_FLAG_NO_DELAY | + FF_HW_FLAG_SLICE_CONTROL, + .picture_priv_data_size = sizeof(VulkanEncodeAV1Picture), + .filler_header_size = 4, + .init_profile = init_profile, + .init_pic_rc = init_pic_rc, + .init_pic_params = init_pic_params, + .write_sequence_headers = write_sequence_header, + .write_extra_headers = write_extra_headers, + .write_filler = write_padding, +}; + +static av_cold int vulkan_encode_av1_init(AVCodecContext *avctx) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + int flags; + + if (avctx->profile == AV_PROFILE_UNKNOWN) + avctx->profile = enc->common.opts.profile; + + enc->caps = (VkVideoEncodeAV1CapabilitiesKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR, + }; + + enc->quality_props = (VkVideoEncodeAV1QualityLevelPropertiesKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_QUALITY_LEVEL_PROPERTIES_KHR, + }; + + err = ff_vulkan_encode_init(avctx, &enc->common, + &ff_vk_enc_av1_desc, &enc_cb, + &enc->caps, &enc->quality_props); + if (err < 0) + return err; + + av_log(avctx, AV_LOG_VERBOSE, "AV1 encoder capabilities:\n"); + av_log(avctx, AV_LOG_VERBOSE, " Standard capability flags:\n"); + av_log(avctx, AV_LOG_VERBOSE, " per_rate_control_group_min_max_q_index: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_PER_RATE_CONTROL_GROUP_MIN_MAX_Q_INDEX_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " generate_obu_extension_header: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_GENERATE_OBU_EXTENSION_HEADER_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " primary_reference_cdf_only: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_PRIMARY_REFERENCE_CDF_ONLY_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " frame_size_override: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_FRAME_SIZE_OVERRIDE_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " motion_vector_scaling: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_MOTION_VECTOR_SCALING_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " Capabilities:\n"); + av_log(avctx, AV_LOG_VERBOSE, " 64x64 superblocks: %i\n", + !!(enc->caps.superblockSizes & VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_64_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " 128x128 superblocks: %i\n", + !!(enc->caps.superblockSizes & VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_128_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " maxSingleReferenceCount: %i\n", + enc->caps.maxSingleReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " singleReferenceNameMask: 0x%x\n", + enc->caps.singleReferenceNameMask); + av_log(avctx, AV_LOG_VERBOSE, " maxUnidirectionalCompoundReferenceCount: %i\n", + enc->caps.maxUnidirectionalCompoundReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " maxUnidirectionalCompoundGroup1ReferenceCount: %i\n", + enc->caps.maxUnidirectionalCompoundGroup1ReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " unidirectionalCompoundReferenceNameMask: 0x%x\n", + enc->caps.unidirectionalCompoundReferenceNameMask); + av_log(avctx, AV_LOG_VERBOSE, " maxBidirectionalCompoundReferenceCount: %i\n", + enc->caps.maxBidirectionalCompoundReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " maxBidirectionalCompoundGroup1ReferenceCount: %i\n", + enc->caps.maxBidirectionalCompoundGroup1ReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " maxBidirectionalCompoundGroup2ReferenceCount: %i\n", + enc->caps.maxBidirectionalCompoundGroup2ReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " bidirectionalCompoundReferenceNameMask: 0x%x\n", + enc->caps.bidirectionalCompoundReferenceNameMask); + av_log(avctx, AV_LOG_VERBOSE, " maxTemporalLayerCount: %i\n", + enc->caps.maxTemporalLayerCount); + av_log(avctx, AV_LOG_VERBOSE, " maxSpatialLayerCount: %i\n", + enc->caps.maxSpatialLayerCount); + av_log(avctx, AV_LOG_VERBOSE, " maxOperatingPoints: %i\n", + enc->caps.maxOperatingPoints); + av_log(avctx, AV_LOG_VERBOSE, " min/max Qindex: [%i, %i]\n", + enc->caps.minQIndex, enc->caps.maxQIndex); + av_log(avctx, AV_LOG_VERBOSE, " prefersGopRemainingFrames: %i\n", + enc->caps.prefersGopRemainingFrames); + av_log(avctx, AV_LOG_VERBOSE, " requiresGopRemainingFrames: %i\n", + enc->caps.requiresGopRemainingFrames); + av_log(avctx, AV_LOG_VERBOSE, " maxLevel: %i\n", + enc->caps.maxLevel); + av_log(avctx, AV_LOG_VERBOSE, " codedPictureAlignment: %ix%i\n", + enc->caps.codedPictureAlignment.width, enc->caps.codedPictureAlignment.height); + av_log(avctx, AV_LOG_VERBOSE, " maxTiles: %ix%i\n", + enc->caps.maxTiles.width, enc->caps.maxTiles.height); + av_log(avctx, AV_LOG_VERBOSE, " Tile size: %ix%i to %ix%i\n", + enc->caps.minTileSize.width, enc->caps.minTileSize.height, + enc->caps.maxTileSize.width, enc->caps.maxTileSize.height); + + err = init_enc_options(avctx); + if (err < 0) + return err; + + flags = ctx->codec->flags; + err = ff_hw_base_init_gop_structure(base_ctx, avctx, + ctx->caps.maxDpbSlots, + enc->caps.maxBidirectionalCompoundReferenceCount, + flags, 0); + if (err < 0) + return err; + + base_ctx->output_delay = base_ctx->b_per_p; + base_ctx->decode_delay = base_ctx->max_b_depth; + + /* Create units and session parameters */ + err = init_base_units(avctx); + if (err < 0) + return err; + + /* Init CBS */ + err = ff_cbs_init(&enc->cbs, AV_CODEC_ID_AV1, avctx); + if (err < 0) + return err; + + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { + uint8_t data[4096]; + size_t data_len = sizeof(data); + + err = write_sequence_header(avctx, NULL, data, &data_len); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write sequence header " + "for extradata: %d.\n", err); + return err; + } else { + avctx->extradata_size = data_len; + avctx->extradata = av_mallocz(avctx->extradata_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) { + err = AVERROR(ENOMEM); + return err; + } + memcpy(avctx->extradata, data, avctx->extradata_size); + } + } + + enc->padding_payload = av_mallocz(2*ctx->caps.minBitstreamBufferOffsetAlignment); + if (!enc->padding_payload) + return AVERROR(ENOMEM); + + memset(enc->padding_payload, 0xaa, 2*ctx->caps.minBitstreamBufferOffsetAlignment); + + return 0; +} + +static av_cold int vulkan_encode_av1_close(AVCodecContext *avctx) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + av_free(enc->padding_payload); + ff_vulkan_encode_uninit(&enc->common); + return 0; +} + +#define OFFSET(x) offsetof(VulkanEncodeAV1Context, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +static const AVOption vulkan_encode_av1_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, + VULKAN_ENCODE_COMMON_OPTIONS, + + { "profile", "Set profile", + OFFSET(common.opts.profile), AV_OPT_TYPE_INT, + { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, 0xffff, FLAGS, .unit = "profile" }, + +#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, .unit = "profile" + { PROFILE("main", AV_PROFILE_AV1_MAIN) }, + { PROFILE("high", AV_PROFILE_AV1_HIGH) }, + { PROFILE("professional", AV_PROFILE_AV1_PROFESSIONAL) }, +#undef PROFILE + + { "tier", "Set tier (seq_tier)", + OFFSET(common.opts.tier), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS, .unit = "tier" }, + { "main", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, .unit = "tier" }, + { "high", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, .unit = "tier" }, + + { "level", "Set level (level_idc)", + OFFSET(common.opts.level), AV_OPT_TYPE_INT, + { .i64 = AV_LEVEL_UNKNOWN }, AV_LEVEL_UNKNOWN, 0xff, FLAGS, .unit = "level" }, + +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, .unit = "level" + { LEVEL("20", 0) }, + { LEVEL("21", 1) }, + { LEVEL("22", 2) }, + { LEVEL("23", 3) }, + { LEVEL("30", 4) }, + { LEVEL("31", 5) }, + { LEVEL("32", 6) }, + { LEVEL("33", 7) }, + { LEVEL("40", 8) }, + { LEVEL("41", 9) }, + { LEVEL("42", 10) }, + { LEVEL("43", 11) }, + { LEVEL("50", 12) }, + { LEVEL("51", 13) }, + { LEVEL("52", 14) }, + { LEVEL("53", 15) }, + { LEVEL("60", 16) }, + { LEVEL("61", 17) }, + { LEVEL("62", 18) }, + { LEVEL("63", 19) }, + { LEVEL("70", 20) }, + { LEVEL("71", 21) }, + { LEVEL("72", 22) }, + { LEVEL("73", 23) }, +#undef LEVEL + + { "units", "Set units to include", OFFSET(unit_elems), AV_OPT_TYPE_FLAGS, { .i64 = UNIT_MASTERING_DISPLAY | UNIT_CONTENT_LIGHT_LEVEL }, 0, INT_MAX, FLAGS, "units" }, + { "hdr", "Include HDR metadata for mastering display colour volume and content light level information", 0, AV_OPT_TYPE_CONST, { .i64 = UNIT_MASTERING_DISPLAY | UNIT_CONTENT_LIGHT_LEVEL }, INT_MIN, INT_MAX, FLAGS, "units" }, + + { NULL }, +}; + +static const FFCodecDefault vulkan_encode_av1_defaults[] = { + { "b", "0" }, + { "bf", "2" }, + { "g", "300" }, + { "qmin", "1" }, + { "qmax", "255" }, + { "refs", "0" }, + { NULL }, +}; + +static const AVClass vulkan_encode_av1_class = { + .class_name = "av1_vulkan", + .item_name = av_default_item_name, + .option = vulkan_encode_av1_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_av1_vulkan_encoder = { + .p.name = "av1_vulkan", + CODEC_LONG_NAME("AV1 (Vulkan)"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_AV1, + .priv_data_size = sizeof(VulkanEncodeAV1Context), + .init = &vulkan_encode_av1_init, + FF_CODEC_RECEIVE_PACKET_CB(&ff_vulkan_encode_receive_packet), + .close = &vulkan_encode_av1_close, + .p.priv_class = &vulkan_encode_av1_class, + .p.capabilities = AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_HARDWARE | + AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_ENCODER_FLUSH | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .defaults = vulkan_encode_av1_defaults, + CODEC_PIXFMTS(AV_PIX_FMT_VULKAN), + .hw_configs = ff_vulkan_encode_hw_configs, + .p.wrapper_name = "vulkan", +}; diff --git a/libavcodec/vulkan_encode_h264.c b/libavcodec/vulkan_encode_h264.c index a0a00a3db..0327ccba0 100644 --- a/libavcodec/vulkan_encode_h264.c +++ b/libavcodec/vulkan_encode_h264.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/mem.h" @@ -1060,11 +1061,11 @@ static int parse_feedback_units(AVCodecContext *avctx, if (err < 0) return err; - err = ff_cbs_read(cbs, &au, data, size); + err = ff_cbs_read(cbs, &au, NULL, data, size); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Unable to parse feedback units, bad drivers: %s\n", av_err2str(err)); - return err; + goto fail; } /* If PPS has an override, just copy it entirely. */ @@ -1078,10 +1079,12 @@ static int parse_feedback_units(AVCodecContext *avctx, } } + err = 0; +fail: ff_cbs_fragment_free(&au); ff_cbs_close(&cbs); - return 0; + return err; } static int init_base_units(AVCodecContext *avctx) @@ -1144,7 +1147,7 @@ static int init_base_units(AVCodecContext *avctx) if (!data) return AVERROR(ENOMEM); } else { - av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for H.264 units = %lu\n", data_size); + av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for H.264 units = %zu\n", data_size); return err; } @@ -1310,6 +1313,7 @@ static int write_extra_headers(AVCodecContext *avctx, if (err < 0) goto fail; } else { + err = 0; *data_len = 0; } @@ -1630,6 +1634,7 @@ static const FFCodecDefault vulkan_encode_h264_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -1657,10 +1662,7 @@ const FFCodec ff_h264_vulkan_encoder = { AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .defaults = vulkan_encode_h264_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VULKAN, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VULKAN), .hw_configs = ff_vulkan_encode_hw_configs, .p.wrapper_name = "vulkan", }; diff --git a/libavcodec/vulkan_encode_h265.c b/libavcodec/vulkan_encode_h265.c index 6aadbc93f..9cd33abfe 100644 --- a/libavcodec/vulkan_encode_h265.c +++ b/libavcodec/vulkan_encode_h265.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/mem.h" @@ -206,7 +207,7 @@ static int vk_enc_h265_update_pic_info(AVCodecContext *avctx, } // Only look for the metadata on I/IDR frame on the output. We - // may force an IDR frame on the output where the medadata gets + // may force an IDR frame on the output where the metadata gets // changed on the input frame. if ((enc->unit_elems & UNIT_SEI_MASTERING_DISPLAY) && (pic->type == FF_HW_PICTURE_TYPE_I || pic->type == FF_HW_PICTURE_TYPE_IDR)) { @@ -1213,11 +1214,11 @@ static int parse_feedback_units(AVCodecContext *avctx, if (err < 0) return err; - err = ff_cbs_read(cbs, &au, data, size); + err = ff_cbs_read(cbs, &au, NULL, data, size); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Unable to parse feedback units, bad drivers: %s\n", av_err2str(err)); - return err; + goto fail; } if (sps_override) { @@ -1245,10 +1246,12 @@ static int parse_feedback_units(AVCodecContext *avctx, } } + err = 0; +fail: ff_cbs_fragment_free(&au); ff_cbs_close(&cbs); - return 0; + return err; } static int init_base_units(AVCodecContext *avctx) @@ -1313,7 +1316,7 @@ static int init_base_units(AVCodecContext *avctx) if (!data) return AVERROR(ENOMEM); } else { - av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for H.265 units = %lu\n", data_size); + av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for H.265 units = %zu\n", data_size); return err; } @@ -1470,6 +1473,7 @@ static int write_extra_headers(AVCodecContext *avctx, if (err < 0) goto fail; } else { + err = 0; *data_len = 0; } @@ -1757,6 +1761,7 @@ static const FFCodecDefault vulkan_encode_h265_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -1784,10 +1789,7 @@ const FFCodec ff_hevc_vulkan_encoder = { AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .defaults = vulkan_encode_h265_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VULKAN, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VULKAN), .hw_configs = ff_vulkan_encode_hw_configs, .p.wrapper_name = "vulkan", }; diff --git a/libavcodec/vulkan_ffv1.c b/libavcodec/vulkan_ffv1.c new file mode 100644 index 000000000..1ea927ccd --- /dev/null +++ b/libavcodec/vulkan_ffv1.c @@ -0,0 +1,897 @@ +/* + * Copyright (c) 2024 Lynne + * + * 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 "vulkan_decode.h" +#include "hwaccel_internal.h" + +#include "ffv1.h" +#include "ffv1_vulkan.h" +#include "libavutil/mem.h" + +#define RGB_LINECACHE 2 + +extern const unsigned char ff_ffv1_dec_setup_comp_spv_data[]; +extern const unsigned int ff_ffv1_dec_setup_comp_spv_len; + +extern const unsigned char ff_ffv1_dec_reset_comp_spv_data[]; +extern const unsigned int ff_ffv1_dec_reset_comp_spv_len; + +extern const unsigned char ff_ffv1_dec_reset_golomb_comp_spv_data[]; +extern const unsigned int ff_ffv1_dec_reset_golomb_comp_spv_len; + +extern const unsigned char ff_ffv1_dec_comp_spv_data[]; +extern const unsigned int ff_ffv1_dec_comp_spv_len; + +extern const unsigned char ff_ffv1_dec_rgb_comp_spv_data[]; +extern const unsigned int ff_ffv1_dec_rgb_comp_spv_len; + +extern const unsigned char ff_ffv1_dec_golomb_comp_spv_data[]; +extern const unsigned int ff_ffv1_dec_golomb_comp_spv_len; + +extern const unsigned char ff_ffv1_dec_rgb_golomb_comp_spv_data[]; +extern const unsigned int ff_ffv1_dec_rgb_golomb_comp_spv_len; + +const FFVulkanDecodeDescriptor ff_vk_dec_ffv1_desc = { + .codec_id = AV_CODEC_ID_FFV1, + .queue_flags = VK_QUEUE_COMPUTE_BIT, +}; + +typedef struct FFv1VulkanDecodePicture { + FFVulkanDecodePicture vp; + + AVBufferRef *slice_state; + uint32_t plane_state_size; + uint32_t slice_state_size; + uint32_t slice_data_size; + + AVBufferRef *slice_feedback_buf; + uint32_t *slice_offset; + int slice_num; + int crc_checked; +} FFv1VulkanDecodePicture; + +typedef struct FFv1VulkanDecodeContext { + AVBufferRef *intermediate_frames_ref; + + FFVulkanShader setup; + FFVulkanShader reset; + FFVulkanShader decode; + + FFVkBuffer consts_buf; + + AVBufferPool *slice_state_pool; + AVBufferPool *slice_feedback_pool; +} FFv1VulkanDecodeContext; + +static int vk_ffv1_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + FFv1VulkanDecodeContext *fv = ctx->sd_ctx; + FFV1Context *f = avctx->priv_data; + + FFv1VulkanDecodePicture *fp = f->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &fp->vp; + + AVHWFramesContext *hwfc = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + enum AVPixelFormat sw_format = hwfc->sw_format; + + int max_contexts; + int is_rgb = !(f->colorspace == 0 && sw_format != AV_PIX_FMT_YA8) && + !(sw_format == AV_PIX_FMT_YA8); + + fp->slice_num = 0; + + max_contexts = 0; + for (int i = 0; i < f->quant_table_count; i++) + max_contexts = FFMAX(f->context_count[i], max_contexts); + + /* Allocate slice buffer data */ + if (f->ac == AC_GOLOMB_RICE) + fp->plane_state_size = 8; + else + fp->plane_state_size = CONTEXT_SIZE; + + fp->plane_state_size *= max_contexts; + fp->slice_state_size = fp->plane_state_size*f->plane_count; + + fp->slice_data_size = 256; /* Overestimation for the SliceContext struct */ + fp->slice_state_size += fp->slice_data_size; + fp->slice_state_size = FFALIGN(fp->slice_state_size, 8); + + fp->crc_checked = f->ec && (avctx->err_recognition & AV_EF_CRCCHECK); + + /* Host map the input slices data if supported */ + if (ctx->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) + ff_vk_host_map_buffer(&ctx->s, &vp->slices_buf, buffer_ref->data, + buffer_ref, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + + /* Allocate slice state data */ + if (f->picture.f->flags & AV_FRAME_FLAG_KEY) { + err = ff_vk_get_pooled_buffer(&ctx->s, &fv->slice_state_pool, + &fp->slice_state, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + NULL, f->slice_count*fp->slice_state_size, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (err < 0) + return err; + } else { + FFv1VulkanDecodePicture *fpl = f->hwaccel_last_picture_private; + fp->slice_state = av_buffer_ref(fpl->slice_state); + if (!fp->slice_state) + return AVERROR(ENOMEM); + } + + /* Allocate slice offsets/status buffer */ + err = ff_vk_get_pooled_buffer(&ctx->s, &fv->slice_feedback_pool, + &fp->slice_feedback_buf, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + NULL, 2*(2*f->slice_count*sizeof(uint32_t)), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + if (err < 0) + return err; + + /* Prepare frame to be used */ + err = ff_vk_decode_prepare_frame_sdr(dec, f->picture.f, vp, 1, + FF_VK_REP_NATIVE, 0); + if (err < 0) + return err; + + /* Create a temporaty frame for RGB */ + if (is_rgb) { + vp->dpb_frame = av_frame_alloc(); + if (!vp->dpb_frame) + return AVERROR(ENOMEM); + + err = av_hwframe_get_buffer(fv->intermediate_frames_ref, + vp->dpb_frame, 0); + if (err < 0) + return err; + } + + return 0; +} + +static int vk_ffv1_decode_slice(AVCodecContext *avctx, + const uint8_t *data, + uint32_t size) +{ + FFV1Context *f = avctx->priv_data; + + FFv1VulkanDecodePicture *fp = f->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &fp->vp; + + FFVkBuffer *slice_offset = (FFVkBuffer *)fp->slice_feedback_buf->data; + FFVkBuffer *slices_buf = vp->slices_buf ? (FFVkBuffer *)vp->slices_buf->data : NULL; + + if (slices_buf && slices_buf->host_ref) { + AV_WN32(slice_offset->mapped_mem + (2*fp->slice_num + 0)*sizeof(uint32_t), + data - slices_buf->mapped_mem); + AV_WN32(slice_offset->mapped_mem + (2*fp->slice_num + 1)*sizeof(uint32_t), + size); + + fp->slice_num++; + } else { + int err = ff_vk_decode_add_slice(avctx, vp, data, size, 0, + &fp->slice_num, + (const uint32_t **)&fp->slice_offset); + if (err < 0) + return err; + + AV_WN32(slice_offset->mapped_mem + (2*(fp->slice_num - 1) + 0)*sizeof(uint32_t), + fp->slice_offset[fp->slice_num - 1]); + AV_WN32(slice_offset->mapped_mem + (2*(fp->slice_num - 1) + 1)*sizeof(uint32_t), + size); + } + + return 0; +} + +static int vk_ffv1_end_frame(AVCodecContext *avctx) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + FFV1Context *f = avctx->priv_data; + FFv1VulkanDecodeContext *fv = ctx->sd_ctx; + + AVHWFramesContext *hwfc = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + enum AVPixelFormat sw_format = hwfc->sw_format; + + int is_rgb = !(f->colorspace == 0 && sw_format != AV_PIX_FMT_YA8) && + !(sw_format == AV_PIX_FMT_YA8); + int color_planes = av_pix_fmt_desc_get(avctx->sw_pix_fmt)->nb_components; + + FFv1VulkanDecodePicture *fp = f->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &fp->vp; + + FFVkBuffer *slices_buf = (FFVkBuffer *)vp->slices_buf->data; + FFVkBuffer *slice_state = (FFVkBuffer *)fp->slice_state->data; + FFVkBuffer *slice_feedback = (FFVkBuffer *)fp->slice_feedback_buf->data; + + VkImageView rct_image_views[AV_NUM_DATA_POINTERS]; + + VkImageMemoryBarrier2 img_bar[37]; + int nb_img_bar = 0; + VkBufferMemoryBarrier2 buf_bar[8]; + int nb_buf_bar = 0; + + FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool); + ff_vk_exec_start(&ctx->s, exec); + + /* Prepare deps */ + RET(ff_vk_exec_add_dep_frame(&ctx->s, exec, f->picture.f, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + + err = ff_vk_exec_mirror_sem_value(&ctx->s, exec, &vp->sem, &vp->sem_value, + f->picture.f); + if (err < 0) + return err; + + if (is_rgb) { + RET(ff_vk_create_imageviews(&ctx->s, exec, rct_image_views, + vp->dpb_frame, FF_VK_REP_NATIVE)); + RET(ff_vk_exec_add_dep_frame(&ctx->s, exec, vp->dpb_frame, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_CLEAR_BIT)); + } + + if (!(f->picture.f->flags & AV_FRAME_FLAG_KEY)) { + FFv1VulkanDecodePicture *fpl = f->hwaccel_last_picture_private; + FFVulkanDecodePicture *vpl = &fpl->vp; + + /* Wait on the previous frame */ + RET(ff_vk_exec_add_dep_wait_sem(&ctx->s, exec, vpl->sem, vpl->sem_value, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT)); + } + + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &fp->slice_state, 1, 1)); + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &fp->slice_feedback_buf, 1, 1)); + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &vp->slices_buf, 1, 0)); + vp->slices_buf = NULL; + + AVVkFrame *vkf = (AVVkFrame *)f->picture.f->data[0]; + for (int i = 0; i < ff_vk_count_images(vkf); i++) { + vkf->layout[i] = VK_IMAGE_LAYOUT_UNDEFINED; + vkf->access[i] = VK_ACCESS_2_NONE; + } + + /* Setup shader */ + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->setup, + 1, 0, 0, + slice_state, + 0, fp->slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->setup, + 1, 1, 0, + slice_feedback, + 0, 2*f->slice_count*sizeof(uint32_t), + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->setup, + 1, 2, 0, + slice_feedback, + 2*f->slice_count*sizeof(uint32_t), + VK_WHOLE_SIZE, + VK_FORMAT_UNDEFINED); + + ff_vk_exec_bind_shader(&ctx->s, exec, &fv->setup); + + FFv1ShaderParams pd = { + .slice_data = slices_buf->address, + + .img_size[0] = f->picture.f->width, + .img_size[1] = f->picture.f->height, + + .plane_state_size = fp->plane_state_size, + .key_frame = f->picture.f->flags & AV_FRAME_FLAG_KEY, + .crcref = f->crcref, + .micro_version = f->micro_version, + }; + + for (int i = 0; i < f->quant_table_count; i++) { + pd.context_count[i] = f->context_count[i]; + pd.extend_lookup[i] = f->quant_tables[i][3][127] || + f->quant_tables[i][4][127]; + } + + /* For some reason the C FFv1 encoder/decoder treats these differently */ + if (sw_format == AV_PIX_FMT_GBRP10 || sw_format == AV_PIX_FMT_GBRP12 || + sw_format == AV_PIX_FMT_GBRP14) + memcpy(pd.fmt_lut, (int [4]) { 2, 1, 0, 3 }, 4*sizeof(int)); + else + ff_vk_set_perm(sw_format, pd.fmt_lut, 0); + + ff_vk_shader_update_push_const(&ctx->s, exec, &fv->setup, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(FFv1ShaderParams), &pd); + + vk->CmdDispatch(exec->buf, f->num_h_slices, f->num_v_slices, 1); + + if (is_rgb) { + vkf = (AVVkFrame *)vp->dpb_frame->data[0]; + for (int i = 0; i < 4; i++) { + vkf->layout[i] = VK_IMAGE_LAYOUT_UNDEFINED; + vkf->access[i] = VK_ACCESS_2_NONE; + } + + ff_vk_frame_barrier(&ctx->s, exec, vp->dpb_frame, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_CLEAR_BIT, + VK_ACCESS_2_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + nb_img_bar = 0; + nb_buf_bar = 0; + + for (int i = 0; i < color_planes; i++) + vk->CmdClearColorImage(exec->buf, vkf->img[i], VK_IMAGE_LAYOUT_GENERAL, + &((VkClearColorValue) { 0 }), + 1, &((VkImageSubresourceRange) { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + })); + } + + /* Sync between setup and reset shaders */ + ff_vk_buf_barrier(buf_bar[nb_buf_bar++], slice_state, + COMPUTE_SHADER_BIT, SHADER_STORAGE_READ_BIT, + SHADER_STORAGE_WRITE_BIT, + COMPUTE_SHADER_BIT, SHADER_STORAGE_READ_BIT, NONE_KHR, + 0, fp->slice_data_size*f->slice_count); + + /* Probability data barrier for P-frames */ + if (!(f->picture.f->flags & AV_FRAME_FLAG_KEY)) + ff_vk_buf_barrier(buf_bar[nb_buf_bar++], slice_state, + COMPUTE_SHADER_BIT, SHADER_STORAGE_READ_BIT, + SHADER_STORAGE_WRITE_BIT, + COMPUTE_SHADER_BIT, SHADER_STORAGE_WRITE_BIT, NONE_KHR, + fp->slice_data_size*f->slice_count, VK_WHOLE_SIZE); + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + nb_buf_bar = 0; + nb_img_bar = 0; + + /* Reset shader */ + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->reset, + 1, 0, 0, + slice_state, + 0, fp->slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->reset, + 1, 1, 0, + slice_state, + f->slice_count*fp->slice_data_size, + VK_WHOLE_SIZE, + VK_FORMAT_UNDEFINED); + + ff_vk_exec_bind_shader(&ctx->s, exec, &fv->reset); + ff_vk_shader_update_push_const(&ctx->s, exec, &fv->reset, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(FFv1ShaderParams), &pd); + + vk->CmdDispatch(exec->buf, f->num_h_slices, f->num_v_slices, + f->plane_count); + + /* Sync probabilities between reset and decode shaders */ + ff_vk_buf_barrier(buf_bar[nb_buf_bar++], slice_state, + COMPUTE_SHADER_BIT, SHADER_STORAGE_WRITE_BIT, NONE_KHR, + COMPUTE_SHADER_BIT, SHADER_STORAGE_READ_BIT, + SHADER_STORAGE_WRITE_BIT, + fp->slice_data_size*f->slice_count, VK_WHOLE_SIZE); + + /* Input frame barrier */ + ff_vk_frame_barrier(&ctx->s, exec, f->picture.f, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT | + (!is_rgb ? VK_ACCESS_SHADER_READ_BIT : 0), + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + if (is_rgb) + ff_vk_frame_barrier(&ctx->s, exec, vp->dpb_frame, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_CLEAR_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + nb_img_bar = 0; + nb_buf_bar = 0; + + /* Decode */ + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->decode, + 1, 0, 0, + slice_state, + 0, fp->slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->decode, + 1, 1, 0, + slice_feedback, + 0, 2*f->slice_count*sizeof(uint32_t), + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->decode, + 1, 2, 0, + slice_feedback, + 2*f->slice_count*sizeof(uint32_t), + VK_WHOLE_SIZE, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->decode, + 1, 3, 0, + slice_state, + f->slice_count*fp->slice_data_size, + VK_WHOLE_SIZE, + VK_FORMAT_UNDEFINED); + + AVFrame *decode_dst = is_rgb ? vp->dpb_frame : f->picture.f; + VkImageView *decode_dst_view = is_rgb ? rct_image_views : vp->view.out; + ff_vk_shader_update_img_array(&ctx->s, exec, &fv->decode, + decode_dst, decode_dst_view, + 1, 4, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + if (is_rgb) + ff_vk_shader_update_img_array(&ctx->s, exec, &fv->decode, + f->picture.f, vp->view.out, + 1, 5, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + + ff_vk_exec_bind_shader(&ctx->s, exec, &fv->decode); + ff_vk_shader_update_push_const(&ctx->s, exec, &fv->decode, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(FFv1ShaderParams), &pd); + + vk->CmdDispatch(exec->buf, f->num_h_slices, f->num_v_slices, 1); + + err = ff_vk_exec_submit(&ctx->s, exec); + if (err < 0) + return err; + + /* We don't need the temporary frame after decoding */ + av_frame_free(&vp->dpb_frame); + +fail: + return 0; +} + +static int init_setup_shader(FFV1Context *f, FFVulkanContext *s, + FFVkExecPool *pool, FFVulkanShader *shd, + VkSpecializationInfo *sl) +{ + int err; + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { 1, 1, 1 }, 0); + + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1ShaderParams), + VK_SHADER_STAGE_COMPUTE_BIT); + + const FFVulkanDescriptorSetBinding desc_set_const[] = { + { /* rangecoder_buf */ + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* crc_ieee_buf */ + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(s, shd, desc_set_const, 2, 1, 0); + + const FFVulkanDescriptorSetBinding desc_set[] = { + { /* slice_data_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* slice_offsets_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* slice_status_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(s, shd, desc_set, 3, 0, 0); + + RET(ff_vk_shader_link(s, shd, + ff_ffv1_dec_setup_comp_spv_data, + ff_ffv1_dec_setup_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + return err; +} + +static int init_reset_shader(FFV1Context *f, FFVulkanContext *s, + FFVkExecPool *pool, FFVulkanShader *shd, + VkSpecializationInfo *sl, int ac) +{ + int err; + int wg_dim = FFMIN(s->props.properties.limits.maxComputeWorkGroupSize[0], 1024); + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { wg_dim, 1, 1 }, 0); + + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1ShaderParams), + VK_SHADER_STAGE_COMPUTE_BIT); + + const FFVulkanDescriptorSetBinding desc_set_const[] = { + { /* rangecoder_buf */ + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(s, shd, desc_set_const, 1, 1, 0); + + const FFVulkanDescriptorSetBinding desc_set[] = { + { /* slice_data_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* slice_state_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(s, shd, desc_set, 2, 0, 0); + + if (ac == AC_GOLOMB_RICE) + RET(ff_vk_shader_link(s, shd, + ff_ffv1_dec_reset_golomb_comp_spv_data, + ff_ffv1_dec_reset_golomb_comp_spv_len, "main")); + else + RET(ff_vk_shader_link(s, shd, + ff_ffv1_dec_reset_comp_spv_data, + ff_ffv1_dec_reset_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + return err; +} + +static int init_decode_shader(FFV1Context *f, FFVulkanContext *s, + FFVkExecPool *pool, FFVulkanShader *shd, + AVHWFramesContext *dec_frames_ctx, + AVHWFramesContext *out_frames_ctx, + VkSpecializationInfo *sl, int ac, int rgb) +{ + int err; + + uint32_t wg_x = ac != AC_GOLOMB_RICE ? CONTEXT_SIZE : 1; + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { wg_x, 1, 1 }, 0); + + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1ShaderParams), + VK_SHADER_STAGE_COMPUTE_BIT); + + const FFVulkanDescriptorSetBinding desc_set_const[] = { + { /* rangecoder_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* quant_buf */ + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + ff_vk_shader_add_descriptor_set(s, shd, desc_set_const, 2, 1, 0); + + const FFVulkanDescriptorSetBinding desc_set[] = { + { /* slice_data_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* slice_offsets_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* slice_status_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* slice_state_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* dec */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .elems = av_pix_fmt_count_planes(dec_frames_ctx->sw_format), + }, + { /* dst */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .elems = av_pix_fmt_count_planes(out_frames_ctx->sw_format), + }, + }; + ff_vk_shader_add_descriptor_set(s, shd, desc_set, 5 + rgb, 0, 0); + + if (ac == AC_GOLOMB_RICE) { + if (rgb) + ff_vk_shader_link(s, shd, + ff_ffv1_dec_rgb_golomb_comp_spv_data, + ff_ffv1_dec_rgb_golomb_comp_spv_len, "main"); + else + ff_vk_shader_link(s, shd, + ff_ffv1_dec_golomb_comp_spv_data, + ff_ffv1_dec_golomb_comp_spv_len, "main"); + } else { + if (rgb) + ff_vk_shader_link(s, shd, + ff_ffv1_dec_rgb_comp_spv_data, + ff_ffv1_dec_rgb_comp_spv_len, "main"); + else + ff_vk_shader_link(s, shd, + ff_ffv1_dec_comp_spv_data, + ff_ffv1_dec_comp_spv_len, "main"); + } + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + return err; +} + +static int init_indirect(AVCodecContext *avctx, FFVulkanContext *s, + AVBufferRef **dst, enum AVPixelFormat sw_format) +{ + int err; + AVHWFramesContext *frames_ctx; + AVVulkanFramesContext *vk_frames; + FFV1Context *f = avctx->priv_data; + + *dst = av_hwframe_ctx_alloc(s->device_ref); + if (!(*dst)) + return AVERROR(ENOMEM); + + frames_ctx = (AVHWFramesContext *)((*dst)->data); + frames_ctx->format = AV_PIX_FMT_VULKAN; + frames_ctx->sw_format = sw_format; + frames_ctx->width = s->frames->width; + frames_ctx->height = f->num_v_slices*RGB_LINECACHE; + + vk_frames = frames_ctx->hwctx; + vk_frames->tiling = VK_IMAGE_TILING_OPTIMAL; + vk_frames->img_flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + vk_frames->usage = VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT; + + err = av_hwframe_ctx_init(*dst); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, + "Unable to initialize frame pool with format %s: %s\n", + av_get_pix_fmt_name(sw_format), av_err2str(err)); + av_buffer_unref(dst); + return err; + } + + return 0; +} + +static void vk_decode_ffv1_uninit(FFVulkanDecodeShared *ctx) +{ + FFv1VulkanDecodeContext *fv = ctx->sd_ctx; + + av_buffer_unref(&fv->intermediate_frames_ref); + + ff_vk_shader_free(&ctx->s, &fv->setup); + ff_vk_shader_free(&ctx->s, &fv->reset); + ff_vk_shader_free(&ctx->s, &fv->decode); + + ff_vk_free_buf(&ctx->s, &fv->consts_buf); + + av_buffer_pool_uninit(&fv->slice_state_pool); + av_buffer_pool_uninit(&fv->slice_feedback_pool); + + av_freep(&fv); +} + +static int vk_decode_ffv1_init(AVCodecContext *avctx) +{ + int err; + FFV1Context *f = avctx->priv_data; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = NULL; + FFv1VulkanDecodeContext *fv; + + if (f->version < 3 || + (f->version == 4 && f->micro_version > 3)) + return AVERROR(ENOTSUP); + + /* Streams with a low amount of slices will usually be much slower + * to decode, so warn the user. */ + if (f->slice_count < 16) + av_log(avctx, AV_LOG_WARNING, "Stream has a low number of slices (%i), " + "decoding may be very slow\n", f->slice_count); + + err = ff_vk_decode_init(avctx); + if (err < 0) + return err; + ctx = dec->shared_ctx; + + fv = ctx->sd_ctx = av_mallocz(sizeof(*fv)); + if (!fv) { + err = AVERROR(ENOMEM); + goto fail; + } + + ctx->sd_ctx_free = &vk_decode_ffv1_uninit; + + AVHWFramesContext *hwfc = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + AVHWFramesContext *dctx = hwfc; + enum AVPixelFormat sw_format = hwfc->sw_format; + int is_rgb = !(f->colorspace == 0 && sw_format != AV_PIX_FMT_YA8) && + !(sw_format == AV_PIX_FMT_YA8); + + /* Intermediate frame pool for RCT */ + if (is_rgb) { + RET(init_indirect(avctx, &ctx->s, &fv->intermediate_frames_ref, + f->use32bit ? AV_PIX_FMT_GBRAP32 : AV_PIX_FMT_GBRAP16)); + dctx = (AVHWFramesContext *)fv->intermediate_frames_ref->data; + } + + SPEC_LIST_CREATE(sl, 15, 15*sizeof(uint32_t)) + ff_ffv1_vk_set_common_sl(avctx, f, sl, sw_format); + + if (RGB_LINECACHE != 2) + SPEC_LIST_ADD(sl, 0, 32, RGB_LINECACHE); + + if (f->ec && !!(avctx->err_recognition & AV_EF_CRCCHECK)) + SPEC_LIST_ADD(sl, 1, 32, 1); + + /* Setup shader */ + RET(init_setup_shader(f, &ctx->s, &ctx->exec_pool, &fv->setup, sl)); + + /* Reset shader */ + RET(init_reset_shader(f, &ctx->s, &ctx->exec_pool, &fv->reset, sl, f->ac)); + + /* Decode shaders */ + RET(init_decode_shader(f, &ctx->s, &ctx->exec_pool, &fv->decode, + dctx, hwfc, sl, f->ac, is_rgb)); + + /* Init static data */ + RET(ff_ffv1_vk_init_consts(&ctx->s, &fv->consts_buf, f)); + + /* Update setup global descriptors */ + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &fv->setup, 0, 0, 0, + &fv->consts_buf, + 256*sizeof(uint32_t), 512*sizeof(uint8_t), + VK_FORMAT_UNDEFINED)); + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &fv->setup, 0, 1, 0, + &fv->consts_buf, + 0, 256*sizeof(uint32_t), + VK_FORMAT_UNDEFINED)); + + /* Update decode global descriptors */ + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &fv->decode, 0, 0, 0, + &fv->consts_buf, + 256*sizeof(uint32_t), 512*sizeof(uint8_t), + VK_FORMAT_UNDEFINED)); + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &fv->decode, 0, 1, 0, + &fv->consts_buf, + 256*sizeof(uint32_t) + 512*sizeof(uint8_t), + VK_WHOLE_SIZE, + VK_FORMAT_UNDEFINED)); + +fail: + return err; +} + +static void vk_ffv1_free_frame_priv(AVRefStructOpaque _hwctx, void *data) +{ + AVHWDeviceContext *dev_ctx = _hwctx.nc; + AVVulkanDeviceContext *hwctx = dev_ctx->hwctx; + + FFv1VulkanDecodePicture *fp = data; + FFVulkanDecodePicture *vp = &fp->vp; + FFVkBuffer *slice_feedback = (FFVkBuffer *)fp->slice_feedback_buf->data; + uint8_t *ssp = slice_feedback->mapped_mem + 2*fp->slice_num*sizeof(uint32_t); + + ff_vk_decode_free_frame(dev_ctx, vp); + + /* Invalidate slice/output data if needed */ + if (!(slice_feedback->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + VkMappedMemoryRange invalidate_data = { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = slice_feedback->mem, + .offset = 0, + .size = 2*fp->slice_num*sizeof(uint32_t), + }; + vp->invalidate_memory_ranges(hwctx->act_dev, + 1, &invalidate_data); + } + + int slice_error_cnt = 0; + int crc_mismatch_cnt = 0; + uint32_t max_overread = 0; + for (int i = 0; i < fp->slice_num; i++) { + uint32_t crc_res = 0; + if (fp->crc_checked) + crc_res = AV_RN32(ssp + 2*i*sizeof(uint32_t) + 0); + uint32_t overread = AV_RN32(ssp + 2*i*sizeof(uint32_t) + 4); + max_overread = FFMAX(overread, max_overread); + slice_error_cnt += !!overread; + crc_mismatch_cnt += !!crc_res; + } + if (slice_error_cnt || crc_mismatch_cnt) + av_log(dev_ctx, AV_LOG_ERROR, "Decode status: %i slices overread (%i bytes max), " + "%i CRCs mismatched\n", + slice_error_cnt, max_overread, crc_mismatch_cnt); + + av_buffer_unref(&fp->slice_state); + av_buffer_unref(&fp->slice_feedback_buf); +} + +const FFHWAccel ff_ffv1_vulkan_hwaccel = { + .p.name = "ffv1_vulkan", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_FFV1, + .p.pix_fmt = AV_PIX_FMT_VULKAN, + .start_frame = &vk_ffv1_start_frame, + .decode_slice = &vk_ffv1_decode_slice, + .end_frame = &vk_ffv1_end_frame, + .free_frame_priv = &vk_ffv1_free_frame_priv, + .frame_priv_data_size = sizeof(FFv1VulkanDecodePicture), + .init = &vk_decode_ffv1_init, + .update_thread_context = &ff_vk_update_thread_context, + .uninit = &ff_vk_decode_uninit, + .frame_params = &ff_vk_frame_params, + .priv_data_size = sizeof(FFVulkanDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE, +}; diff --git a/libavcodec/vulkan_h264.c b/libavcodec/vulkan_h264.c index 05ac88413..5fc0f4c4c 100644 --- a/libavcodec/vulkan_h264.c +++ b/libavcodec/vulkan_h264.c @@ -24,6 +24,7 @@ const FFVulkanDecodeDescriptor ff_vk_dec_h264_desc = { .codec_id = AV_CODEC_ID_H264, .decode_extension = FF_VK_EXT_VIDEO_DECODE_H264, + .queue_flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR, .decode_op = VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR, .ext_props = { .extensionName = VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME, @@ -97,7 +98,7 @@ static int vk_h264_fill_pict(AVCodecContext *avctx, H264Picture **ref_src, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = ctx->common.layered_dpb ? dpb_slot_index : 0, - .imageViewBinding = vkpic->img_view_ref, + .imageViewBinding = vkpic->view.ref[0], }; *ref_slot = (VkVideoReferenceSlotInfoKHR) { @@ -194,7 +195,7 @@ static void set_sps(const SPS *sps, .video_signal_type_present_flag = sps->vui.video_signal_type_present_flag, .video_full_range_flag = sps->vui.video_full_range_flag, .color_description_present_flag = sps->vui.colour_description_present_flag, - .chroma_loc_info_present_flag = sps->vui.chroma_location, + .chroma_loc_info_present_flag = sps->vui.chroma_loc_info_present_flag, .timing_info_present_flag = sps->timing_info_present_flag, .fixed_frame_rate_flag = sps->fixed_frame_rate_flag, .bitstream_restriction_flag = sps->bitstream_restriction_flag, @@ -358,23 +359,18 @@ static int vk_h264_create_params(AVCodecContext *avctx, AVBufferRef **buf) } static int vk_h264_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { int err; int dpb_slot_index = 0; H264Context *h = avctx->priv_data; + H264Picture *pic = h->cur_pic_ptr; - FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; H264VulkanDecodePicture *hp = pic->hwaccel_picture_private; FFVulkanDecodePicture *vp = &hp->vp; - if (!dec->session_params) { - err = vk_h264_create_params(avctx, &dec->session_params); - if (err < 0) - return err; - } - /* Fill in main slot */ dpb_slot_index = 0; for (unsigned slot = 0; slot < H264_MAX_PICTURE_COUNT; slot++) { @@ -470,7 +466,7 @@ static int vk_h264_start_frame(AVCodecContext *avctx, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = 0, - .imageViewBinding = vp->img_view_out, + .imageViewBinding = vp->view.out[0], }, }; @@ -505,20 +501,45 @@ static int vk_h264_decode_slice(AVCodecContext *avctx, static int vk_h264_end_frame(AVCodecContext *avctx) { const H264Context *h = avctx->priv_data; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + H264Picture *pic = h->cur_pic_ptr; H264VulkanDecodePicture *hp = pic->hwaccel_picture_private; - FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; FFVulkanDecodePicture *vp = &hp->vp; FFVulkanDecodePicture *rvp[H264_MAX_PICTURE_COUNT] = { 0 }; AVFrame *rav[H264_MAX_PICTURE_COUNT] = { 0 }; +#ifdef VK_KHR_video_maintenance2 + StdVideoH264ScalingLists vksps_scaling; + StdVideoH264HrdParameters vksps_vui_header; + StdVideoH264SequenceParameterSetVui vksps_vui; + StdVideoH264SequenceParameterSet vksps; + StdVideoH264ScalingLists vkpps_scaling; + StdVideoH264PictureParameterSet vkpps; + VkVideoDecodeH264InlineSessionParametersInfoKHR h264_params; + + if (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2) { + set_sps(h->ps.sps, &vksps_scaling, + &vksps_vui_header, &vksps_vui, &vksps); + set_pps(h->ps.pps, h->ps.sps, &vkpps_scaling, &vkpps); + h264_params = (VkVideoDecodeH264InlineSessionParametersInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_INLINE_SESSION_PARAMETERS_INFO_KHR, + .pStdSPS = &vksps, + .pStdPPS = &vkpps, + }; + hp->h264_pic_info.pNext = &h264_params; + } +#endif + if (!hp->h264_pic_info.sliceCount) return 0; if (!vp->slices_buf) return AVERROR(EINVAL); - if (!dec->session_params) { + if (!dec->session_params && + !(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) { int err = vk_h264_create_params(avctx, &dec->session_params); if (err < 0) return err; @@ -535,13 +556,13 @@ static int vk_h264_end_frame(AVCodecContext *avctx) rav[i] = hp->ref_src[i]->f; } - av_log(avctx, AV_LOG_VERBOSE, "Decoding frame, %"SIZE_SPECIFIER" bytes, %i slices\n", + av_log(avctx, AV_LOG_DEBUG, "Decoding frame, %zu bytes, %i slices\n", vp->slices_size, hp->h264_pic_info.sliceCount); return ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp); } -static void vk_h264_free_frame_priv(FFRefStructOpaque _hwctx, void *data) +static void vk_h264_free_frame_priv(AVRefStructOpaque _hwctx, void *data) { AVHWDeviceContext *hwctx = _hwctx.nc; H264VulkanDecodePicture *hp = data; @@ -563,9 +584,8 @@ const FFHWAccel ff_h264_vulkan_hwaccel = { .init = &ff_vk_decode_init, .update_thread_context = &ff_vk_update_thread_context, .decode_params = &ff_vk_params_invalidate, - .flush = &ff_vk_decode_flush, .uninit = &ff_vk_decode_uninit, .frame_params = &ff_vk_frame_params, .priv_data_size = sizeof(FFVulkanDecodeContext), - .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE, + .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vulkan_hevc.c b/libavcodec/vulkan_hevc.c index 0b2000568..8f0d1f663 100644 --- a/libavcodec/vulkan_hevc.c +++ b/libavcodec/vulkan_hevc.c @@ -26,6 +26,7 @@ const FFVulkanDecodeDescriptor ff_vk_dec_hevc_desc = { .codec_id = AV_CODEC_ID_HEVC, .decode_extension = FF_VK_EXT_VIDEO_DECODE_H265, + .queue_flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR, .decode_op = VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR, .ext_props = { .extensionName = VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME, @@ -163,7 +164,7 @@ static int vk_hevc_fill_pict(AVCodecContext *avctx, HEVCFrame **ref_src, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = ctx->common.layered_dpb ? pic_id : 0, - .imageViewBinding = vkpic->img_view_ref, + .imageViewBinding = vkpic->view.ref[0], }; *ref_slot = (VkVideoReferenceSlotInfoKHR) { @@ -708,26 +709,21 @@ static int vk_hevc_create_params(AVCodecContext *avctx, AVBufferRef **buf) } static int vk_hevc_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { int err; HEVCContext *h = avctx->priv_data; HEVCLayerContext *l = &h->layers[h->cur_layer]; + HEVCFrame *pic = h->cur_frame; - FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; HEVCVulkanDecodePicture *hp = pic->hwaccel_picture_private; FFVulkanDecodePicture *vp = &hp->vp; const HEVCPPS *pps = h->pps; const HEVCSPS *sps = pps->sps; int nb_refs = 0; - if (!dec->session_params) { - err = vk_hevc_create_params(avctx, &dec->session_params); - if (err < 0) - return err; - } - hp->h265pic = (StdVideoDecodeH265PictureInfo) { .flags = (StdVideoDecodeH265PictureInfoFlags) { .IrapPicFlag = IS_IRAP(h), @@ -822,7 +818,7 @@ static int vk_hevc_start_frame(AVCodecContext *avctx, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = 0, - .imageViewBinding = vp->img_view_out, + .imageViewBinding = vp->view.out[0], }, }; @@ -850,6 +846,8 @@ static int vk_hevc_end_frame(AVCodecContext *avctx) { const HEVCContext *h = avctx->priv_data; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + HEVCFrame *pic = h->cur_frame; HEVCVulkanDecodePicture *hp = pic->hwaccel_picture_private; FFVulkanDecodePicture *vp = &hp->vp; @@ -857,13 +855,45 @@ static int vk_hevc_end_frame(AVCodecContext *avctx) AVFrame *rav[HEVC_MAX_REFS] = { 0 }; int err; + const HEVCPPS *pps = h->pps; + const HEVCSPS *sps = pps->sps; + +#ifdef VK_KHR_video_maintenance2 + HEVCHeaderPPS vkpps_p; + StdVideoH265PictureParameterSet vkpps; + HEVCHeaderSPS vksps_p; + StdVideoH265SequenceParameterSet vksps; + HEVCHeaderVPSSet vkvps_ps[HEVC_MAX_SUB_LAYERS]; + HEVCHeaderVPS vkvps_p; + StdVideoH265VideoParameterSet vkvps; + VkVideoDecodeH265InlineSessionParametersInfoKHR h265_params; + + if (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2) { + set_pps(pps, sps, &vkpps_p.scaling, &vkpps, &vkpps_p.pal); + set_sps(sps, pps->sps_id, &vksps_p.scaling, &vksps_p.vui_header, + &vksps_p.vui, &vksps, vksps_p.nal_hdr, + vksps_p.vcl_hdr, &vksps_p.ptl, &vksps_p.dpbm, + &vksps_p.pal, vksps_p.str, &vksps_p.ltr); + + vkvps_p.sls = vkvps_ps; + set_vps(sps->vps, &vkvps, &vkvps_p.ptl, &vkvps_p.dpbm, + vkvps_p.hdr, vkvps_p.sls); + + h265_params = (VkVideoDecodeH265InlineSessionParametersInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_INLINE_SESSION_PARAMETERS_INFO_KHR, + .pStdSPS = &vksps, + .pStdPPS = &vkpps, + .pStdVPS = &vkvps, + }; + hp->h265_pic_info.pNext = &h265_params; + } +#endif + if (!hp->h265_pic_info.sliceSegmentCount) return 0; - if (!dec->session_params) { - const HEVCPPS *pps = h->pps; - const HEVCSPS *sps = pps->sps; - + if (!dec->session_params && + !(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) { if (!pps) { unsigned int pps_id = h->sh.pps_id; if (pps_id < HEVC_MAX_PPS_COUNT && h->ps.pps_list[pps_id] != NULL) @@ -891,13 +921,13 @@ static int vk_hevc_end_frame(AVCodecContext *avctx) rvp[i] = &rfhp->vp; } - av_log(avctx, AV_LOG_VERBOSE, "Decoding frame, %"SIZE_SPECIFIER" bytes, %i slices\n", + av_log(avctx, AV_LOG_DEBUG, "Decoding frame, %zu bytes, %i slices\n", vp->slices_size, hp->h265_pic_info.sliceSegmentCount); return ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp); } -static void vk_hevc_free_frame_priv(FFRefStructOpaque _hwctx, void *data) +static void vk_hevc_free_frame_priv(AVRefStructOpaque _hwctx, void *data) { AVHWDeviceContext *hwctx = _hwctx.nc; HEVCVulkanDecodePicture *hp = data; @@ -919,9 +949,8 @@ const FFHWAccel ff_hevc_vulkan_hwaccel = { .init = &ff_vk_decode_init, .update_thread_context = &ff_vk_update_thread_context, .decode_params = &ff_vk_params_invalidate, - .flush = &ff_vk_decode_flush, .uninit = &ff_vk_decode_uninit, .frame_params = &ff_vk_frame_params, .priv_data_size = sizeof(FFVulkanDecodeContext), - .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE, + .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vulkan_prores.c b/libavcodec/vulkan_prores.c new file mode 100644 index 000000000..69a9a080b --- /dev/null +++ b/libavcodec/vulkan_prores.c @@ -0,0 +1,530 @@ +/* + * 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 "proresdec.h" +#include "vulkan_decode.h" +#include "hwaccel_internal.h" +#include "libavutil/mem.h" +#include "libavutil/vulkan.h" + +extern const unsigned char ff_prores_vld_comp_spv_data[]; +extern const unsigned int ff_prores_vld_comp_spv_len; + +extern const unsigned char ff_prores_idct_comp_spv_data[]; +extern const unsigned int ff_prores_idct_comp_spv_len; + +const FFVulkanDecodeDescriptor ff_vk_dec_prores_desc = { + .codec_id = AV_CODEC_ID_PRORES, + .queue_flags = VK_QUEUE_COMPUTE_BIT, +}; + +typedef struct ProresVulkanDecodePicture { + FFVulkanDecodePicture vp; + + AVBufferRef *metadata_buf; + + uint32_t bitstream_start; + uint32_t bitstream_size; + uint32_t slice_num; + + uint32_t slice_offsets_sz, qmat_sz, mb_params_sz; + uint32_t slice_offsets_off, qmat_off, mb_params_off; +} ProresVulkanDecodePicture; + +typedef struct ProresVulkanDecodeContext { + FFVulkanShader vld; + FFVulkanShader idct; + + AVBufferPool *metadata_pool; +} ProresVulkanDecodeContext; + +typedef struct ProresVkParameters { + VkDeviceAddress slice_data; + uint32_t bitstream_size; + + uint16_t width; + uint16_t height; + uint16_t mb_width; + uint16_t mb_height; + uint16_t slice_width; + uint16_t slice_height; + uint8_t log2_slice_width; + uint8_t log2_chroma_w; + uint8_t depth; + uint8_t alpha_info; + uint8_t bottom_field; +} ProresVkParameters; + +static int vk_prores_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + ProresContext *pr = avctx->priv_data; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + ProresVulkanDecodeContext *pv = ctx->sd_ctx; + ProresVulkanDecodePicture *pp = pr->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + + int err; + + pp->slice_offsets_sz = (pr->slice_count + 1) * sizeof(uint32_t); + pp->qmat_sz = sizeof(pr->qmat_luma) + sizeof(pr->qmat_chroma); + pp->mb_params_sz = pr->mb_width * pr->mb_height * sizeof(uint8_t); + + pp->slice_offsets_off = 0; + pp->qmat_off = FFALIGN(pp->slice_offsets_off + pp->slice_offsets_sz, + ctx->s.props.properties.limits.minStorageBufferOffsetAlignment); + pp->mb_params_off = FFALIGN(pp->qmat_off + pp->qmat_sz, + ctx->s.props.properties.limits.minStorageBufferOffsetAlignment); + + /* Host map the input slices data if supported */ + if (!vp->slices_buf && ctx->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) + RET(ff_vk_host_map_buffer(&ctx->s, &vp->slices_buf, buffer_ref->data, + buffer_ref, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT)); + + /* Allocate metadata buffer */ + RET(ff_vk_get_pooled_buffer(&ctx->s, &pv->metadata_pool, + &pp->metadata_buf, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + NULL, pp->mb_params_off + pp->mb_params_sz, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + + /* Prepare frame to be used */ + RET(ff_vk_decode_prepare_frame_sdr(dec, pr->frame, vp, 1, + FF_VK_REP_NATIVE, 0)); + + pp->slice_num = 0; + pp->bitstream_start = pp->bitstream_size = 0; + +fail: + return err; +} + +static int vk_prores_decode_slice(AVCodecContext *avctx, + const uint8_t *data, + uint32_t size) +{ + ProresContext *pr = avctx->priv_data; + ProresVulkanDecodePicture *pp = pr->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + + FFVkBuffer *slice_offset = (FFVkBuffer *)pp->metadata_buf->data; + FFVkBuffer *slices_buf = vp->slices_buf ? (FFVkBuffer *)vp->slices_buf->data : NULL; + + /* Skip picture header */ + if (slices_buf && slices_buf->host_ref && !pp->slice_num) + pp->bitstream_size = data - slices_buf->mapped_mem; + + AV_WN32(slice_offset->mapped_mem + (pp->slice_num + 0) * sizeof(uint32_t), + pp->bitstream_size); + AV_WN32(slice_offset->mapped_mem + (pp->slice_num + 1) * sizeof(uint32_t), + pp->bitstream_size += size); + + if (!slices_buf || !slices_buf->host_ref) { + int err = ff_vk_decode_add_slice(avctx, vp, data, size, 0, + &pp->slice_num, NULL); + if (err < 0) + return err; + } else { + pp->slice_num++; + } + + return 0; +} + +static int vk_prores_end_frame(AVCodecContext *avctx) +{ + ProresContext *pr = avctx->priv_data; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + FFVulkanFunctions *vk = &ctx->s.vkfn; + ProresVulkanDecodeContext *pv = ctx->sd_ctx; + ProresVulkanDecodePicture *pp = pr->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + AVFrame *f = pr->frame; + AVVkFrame *vkf = (AVVkFrame *)f->data[0]; + + ProresVkParameters pd; + FFVkBuffer *slice_data, *metadata; + VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS]; + VkBufferMemoryBarrier2 buf_bar[2]; + int nb_img_bar = 0, nb_buf_bar = 0, nb_imgs, i, err; + const AVPixFmtDescriptor *pix_desc; + + if (!pp->slice_num) + return 0; + + pix_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + if (!pix_desc) + return AVERROR(EINVAL); + + slice_data = (FFVkBuffer *)vp->slices_buf->data; + metadata = (FFVkBuffer *)pp->metadata_buf->data; + + pd = (ProresVkParameters) { + .slice_data = slice_data->address, + .bitstream_size = pp->bitstream_size, + + .width = avctx->width, + .height = avctx->height, + .mb_width = pr->mb_width, + .mb_height = pr->mb_height, + .slice_width = pr->slice_count / pr->mb_height, + .slice_height = pr->mb_height, + .log2_slice_width = av_log2(pr->slice_mb_width), + .log2_chroma_w = pix_desc->log2_chroma_w, + .depth = avctx->bits_per_raw_sample, + .alpha_info = pr->alpha_info, + .bottom_field = pr->first_field ^ (pr->frame_type == 1), + }; + + memcpy(metadata->mapped_mem + pp->qmat_off, + pr->qmat_luma, sizeof(pr->qmat_luma)); + memcpy(metadata->mapped_mem + pp->qmat_off + sizeof(pr->qmat_luma), + pr->qmat_chroma, sizeof(pr->qmat_chroma)); + + FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool); + RET(ff_vk_exec_start(&ctx->s, exec)); + + /* Prepare deps */ + RET(ff_vk_exec_add_dep_frame(&ctx->s, exec, f, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + + RET(ff_vk_exec_mirror_sem_value(&ctx->s, exec, &vp->sem, &vp->sem_value, f)); + + /* Transfer ownership to the exec context */ + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &vp->slices_buf, 1, 0)); + vp->slices_buf = NULL; + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &pp->metadata_buf, 1, 0)); + pp->metadata_buf = NULL; + + vkf->layout[0] = VK_IMAGE_LAYOUT_UNDEFINED; + vkf->access[0] = VK_ACCESS_2_NONE; + + nb_imgs = ff_vk_count_images(vkf); + + if (pr->first_field) { + /* Input barrier */ + ff_vk_frame_barrier(&ctx->s, exec, f, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_CLEAR_BIT, + VK_ACCESS_2_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + nb_img_bar = nb_buf_bar = 0; + + /* Clear the input image since the vld shader does sparse writes, except for alpha */ + for (i = 0; i < FFMIN(nb_imgs, 3); ++i) { + vk->CmdClearColorImage(exec->buf, vkf->img[i], + VK_IMAGE_LAYOUT_GENERAL, + &((VkClearColorValue) { 0 }), + 1, &((VkImageSubresourceRange) { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + })); + } + } + + /* Input barrier, or synchronization between clear and vld shader */ + ff_vk_frame_barrier(&ctx->s, exec, f, img_bar, &nb_img_bar, + pr->first_field ? VK_PIPELINE_STAGE_2_CLEAR_BIT : + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + ff_vk_buf_barrier(buf_bar[nb_buf_bar++], metadata, + ALL_COMMANDS_BIT, NONE_KHR, NONE_KHR, + COMPUTE_SHADER_BIT, SHADER_WRITE_BIT, NONE_KHR, + pp->slice_offsets_sz, pp->mb_params_sz); + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + nb_img_bar = nb_buf_bar = 0; + + /* Entropy decode */ + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &pv->vld, + 0, 0, 0, + metadata, + pp->slice_offsets_off, + pp->slice_offsets_sz, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &pv->vld, + 0, 1, 0, + metadata, + pp->mb_params_off, + pp->mb_params_sz, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_img_array(&ctx->s, exec, &pv->vld, + f, vp->view.out, + 0, 2, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + + ff_vk_exec_bind_shader(&ctx->s, exec, &pv->vld); + ff_vk_shader_update_push_const(&ctx->s, exec, &pv->vld, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd), &pd); + + vk->CmdDispatch(exec->buf, AV_CEIL_RSHIFT(pr->slice_count / pr->mb_height, 3), + AV_CEIL_RSHIFT(pr->mb_height, 3), + 3 + !!pr->alpha_info); + + /* Synchronize vld and idct shaders */ + ff_vk_frame_barrier(&ctx->s, exec, f, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + ff_vk_buf_barrier(buf_bar[nb_buf_bar++], metadata, + COMPUTE_SHADER_BIT, SHADER_WRITE_BIT, NONE_KHR, + COMPUTE_SHADER_BIT, SHADER_READ_BIT, NONE_KHR, + pp->slice_offsets_sz, pp->mb_params_sz); + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + nb_img_bar = nb_buf_bar = 0; + + /* Inverse transform */ + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &pv->idct, + 0, 0, 0, + metadata, + pp->mb_params_off, + pp->mb_params_sz, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &pv->idct, + 0, 1, 0, + metadata, + pp->qmat_off, + pp->qmat_sz, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_img_array(&ctx->s, exec, &pv->idct, + f, vp->view.out, + 0, 2, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + + ff_vk_exec_bind_shader(&ctx->s, exec, &pv->idct); + ff_vk_shader_update_push_const(&ctx->s, exec, &pv->idct, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd), &pd); + + vk->CmdDispatch(exec->buf, AV_CEIL_RSHIFT(pr->mb_width, 1), pr->mb_height, 3); + + RET(ff_vk_exec_submit(&ctx->s, exec)); + +fail: + return err; +} + +static int init_decode_shader(AVCodecContext *avctx, FFVulkanContext *s, + FFVkExecPool *pool, FFVulkanShader *shd, + int max_num_mbs, int interlaced) +{ + int err; + AVHWFramesContext *dec_frames_ctx; + dec_frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + + SPEC_LIST_CREATE(sl, 1, 1*sizeof(uint32_t)) + SPEC_LIST_ADD(sl, 0, 32, interlaced); + + ff_vk_shader_load(shd, + VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { 8, 8, 1 }, 0); + + ff_vk_shader_add_push_const(shd, 0, sizeof(ProresVkParameters), + VK_SHADER_STAGE_COMPUTE_BIT); + + const FFVulkanDescriptorSetBinding desc_set[] = { + { /* slice_offsets_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* quant_idx_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* dst */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .elems = av_pix_fmt_count_planes(dec_frames_ctx->sw_format), + }, + }; + ff_vk_shader_add_descriptor_set(s, shd, desc_set, 3, 0, 0); + + RET(ff_vk_shader_link(s, shd, + ff_prores_vld_comp_spv_data, + ff_prores_vld_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + return 0; +} + +static int init_idct_shader(AVCodecContext *avctx, FFVulkanContext *s, + FFVkExecPool *pool, FFVulkanShader *shd, + int max_num_mbs, int interlaced) +{ + int err; + AVHWFramesContext *dec_frames_ctx; + dec_frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + + SPEC_LIST_CREATE(sl, 2 + 64, (2 + 64)*sizeof(uint32_t)) + SPEC_LIST_ADD(sl, 0, 32, interlaced); + SPEC_LIST_ADD(sl, 16, 32, 4*2); /* nb_blocks */ + + const double idct_8_scales[8] = { + cos(4.0*M_PI/16.0) / 2.0, cos(1.0*M_PI/16.0) / 2.0, + cos(2.0*M_PI/16.0) / 2.0, cos(3.0*M_PI/16.0) / 2.0, + cos(4.0*M_PI/16.0) / 2.0, cos(5.0*M_PI/16.0) / 2.0, + cos(6.0*M_PI/16.0) / 2.0, cos(7.0*M_PI/16.0) / 2.0, + }; + for (int i = 0; i < 64; i++) + SPEC_LIST_ADD(sl, 18 + i, 32, + av_float2int(idct_8_scales[i >> 3]*idct_8_scales[i & 7])); + + ff_vk_shader_load(shd, + VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { 32, 2, 1 }, 0); + + ff_vk_shader_add_push_const(shd, 0, sizeof(ProresVkParameters), + VK_SHADER_STAGE_COMPUTE_BIT); + + const FFVulkanDescriptorSetBinding desc_set[] = { + { /* quant_idx_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* qmat_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* dst */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .elems = av_pix_fmt_count_planes(dec_frames_ctx->sw_format), + }, + }; + RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 3, 0, 0)); + + RET(ff_vk_shader_link(s, shd, + ff_prores_idct_comp_spv_data, + ff_prores_idct_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + return 0; +} + +static void vk_decode_prores_uninit(FFVulkanDecodeShared *ctx) +{ + ProresVulkanDecodeContext *pv = ctx->sd_ctx; + + ff_vk_shader_free(&ctx->s, &pv->vld); + ff_vk_shader_free(&ctx->s, &pv->idct); + + av_buffer_pool_uninit(&pv->metadata_pool); + + av_freep(&pv); +} + +static int vk_decode_prores_init(AVCodecContext *avctx) +{ + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = NULL; + ProresContext *pr = avctx->priv_data; + + ProresVulkanDecodeContext *pv; + int max_num_mbs, err; + + max_num_mbs = (avctx->coded_width >> 4) * (avctx->coded_height >> 4); + + err = ff_vk_decode_init(avctx); + if (err < 0) + return err; + ctx = dec->shared_ctx; + + pv = ctx->sd_ctx = av_mallocz(sizeof(*pv)); + if (!pv) { + err = AVERROR(ENOMEM); + goto fail; + } + + ctx->sd_ctx_free = vk_decode_prores_uninit; + + RET(init_decode_shader(avctx, &ctx->s, &ctx->exec_pool, + &pv->vld, max_num_mbs, pr->frame_type != 0)); + RET(init_idct_shader(avctx, &ctx->s, &ctx->exec_pool, + &pv->idct, max_num_mbs, pr->frame_type != 0)); + +fail: + return err; +} + +static void vk_prores_free_frame_priv(AVRefStructOpaque _hwctx, void *data) +{ + AVHWDeviceContext *dev_ctx = _hwctx.nc; + ProresVulkanDecodePicture *pp = data; + + ff_vk_decode_free_frame(dev_ctx, &pp->vp); + + av_buffer_unref(&pp->metadata_buf); +} + +const FFHWAccel ff_prores_vulkan_hwaccel = { + .p.name = "prores_vulkan", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_PRORES, + .p.pix_fmt = AV_PIX_FMT_VULKAN, + .start_frame = &vk_prores_start_frame, + .decode_slice = &vk_prores_decode_slice, + .end_frame = &vk_prores_end_frame, + .free_frame_priv = &vk_prores_free_frame_priv, + .frame_priv_data_size = sizeof(ProresVulkanDecodePicture), + .init = &vk_decode_prores_init, + .update_thread_context = &ff_vk_update_thread_context, + .uninit = &ff_vk_decode_uninit, + .frame_params = &ff_vk_frame_params, + .priv_data_size = sizeof(FFVulkanDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE, +}; diff --git a/libavcodec/vulkan_prores_raw.c b/libavcodec/vulkan_prores_raw.c new file mode 100644 index 000000000..392b74a86 --- /dev/null +++ b/libavcodec/vulkan_prores_raw.c @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2025 Lynne + * + * 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 "vulkan_decode.h" +#include "hwaccel_internal.h" + +#include "prores_raw.h" +#include "libavutil/mem.h" + +extern const unsigned char ff_prores_raw_decode_comp_spv_data[]; +extern const unsigned int ff_prores_raw_decode_comp_spv_len; + +extern const unsigned char ff_prores_raw_idct_comp_spv_data[]; +extern const unsigned int ff_prores_raw_idct_comp_spv_len; + +const FFVulkanDecodeDescriptor ff_vk_dec_prores_raw_desc = { + .codec_id = AV_CODEC_ID_PRORES_RAW, + .queue_flags = VK_QUEUE_COMPUTE_BIT, +}; + +typedef struct ProResRAWVulkanDecodePicture { + FFVulkanDecodePicture vp; + + AVBufferRef *frame_data_buf; + uint32_t nb_tiles; +} ProResRAWVulkanDecodePicture; + +typedef struct ProResRAWVulkanDecodeContext { + FFVulkanShader decode; + FFVulkanShader idct; + + AVBufferPool *frame_data_pool; +} ProResRAWVulkanDecodeContext; + +typedef struct DecodePushData { + VkDeviceAddress pkt_data; + int32_t tile_size[2]; + uint8_t qmat[64]; +} DecodePushData; + +typedef struct TileData { + int32_t pos[2]; + uint32_t offset; + uint32_t size; +} TileData; + +static int vk_prores_raw_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + ProResRAWVulkanDecodeContext *prv = ctx->sd_ctx; + ProResRAWContext *prr = avctx->priv_data; + + ProResRAWVulkanDecodePicture *pp = prr->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + + /* Host map the input tile data if supported */ + if (ctx->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) + ff_vk_host_map_buffer(&ctx->s, &vp->slices_buf, buffer_ref->data, + buffer_ref, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + + /* Allocate tile data */ + err = ff_vk_get_pooled_buffer(&ctx->s, &prv->frame_data_pool, + &pp->frame_data_buf, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + NULL, prr->nb_tiles*sizeof(TileData), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + if (err < 0) + return err; + + /* Prepare frame to be used */ + err = ff_vk_decode_prepare_frame_sdr(dec, prr->frame, vp, 1, + FF_VK_REP_NATIVE, 0); + if (err < 0) + return err; + + return 0; +} + +static int vk_prores_raw_decode_slice(AVCodecContext *avctx, + const uint8_t *data, + uint32_t size) +{ + ProResRAWContext *prr = avctx->priv_data; + + ProResRAWVulkanDecodePicture *pp = prr->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + + FFVkBuffer *frame_data_buf = (FFVkBuffer *)pp->frame_data_buf->data; + TileData *td = (TileData *)frame_data_buf->mapped_mem; + FFVkBuffer *slices_buf = vp->slices_buf ? + (FFVkBuffer *)vp->slices_buf->data : NULL; + + td[pp->nb_tiles].pos[0] = prr->tiles[pp->nb_tiles].x; + td[pp->nb_tiles].pos[1] = prr->tiles[pp->nb_tiles].y; + td[pp->nb_tiles].size = size; + + if (vp->slices_buf && slices_buf->host_ref) { + td[pp->nb_tiles].offset = data - slices_buf->mapped_mem; + pp->nb_tiles++; + } else { + int err; + td[pp->nb_tiles].offset = vp->slices_size; + err = ff_vk_decode_add_slice(avctx, vp, data, size, 0, + &pp->nb_tiles, NULL); + if (err < 0) + return err; + } + + return 0; +} + +static int vk_prores_raw_end_frame(AVCodecContext *avctx) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + ProResRAWContext *prr = avctx->priv_data; + ProResRAWVulkanDecodeContext *prv = ctx->sd_ctx; + + ProResRAWVulkanDecodePicture *pp = prr->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + + FFVkBuffer *slices_buf = (FFVkBuffer *)vp->slices_buf->data; + FFVkBuffer *frame_data_buf = (FFVkBuffer *)pp->frame_data_buf->data; + + VkImageMemoryBarrier2 img_bar[8]; + int nb_img_bar = 0; + + FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool); + ff_vk_exec_start(&ctx->s, exec); + + /* Prepare deps */ + RET(ff_vk_exec_add_dep_frame(&ctx->s, exec, prr->frame, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + + err = ff_vk_exec_mirror_sem_value(&ctx->s, exec, &vp->sem, &vp->sem_value, + prr->frame); + if (err < 0) + return err; + + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &pp->frame_data_buf, 1, 0)); + pp->frame_data_buf = NULL; + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &vp->slices_buf, 1, 0)); + vp->slices_buf = NULL; + + AVVkFrame *vkf = (AVVkFrame *)prr->frame->data[0]; + vkf->layout[0] = VK_IMAGE_LAYOUT_UNDEFINED; + vkf->access[0] = VK_ACCESS_2_NONE; + + ff_vk_frame_barrier(&ctx->s, exec, prr->frame, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_CLEAR_BIT, + VK_ACCESS_2_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + nb_img_bar = 0; + + vk->CmdClearColorImage(exec->buf, vkf->img[0], + VK_IMAGE_LAYOUT_GENERAL, + &((VkClearColorValue) { 0 }), + 1, &((VkImageSubresourceRange) { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + })); + + ff_vk_frame_barrier(&ctx->s, exec, prr->frame, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_CLEAR_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + nb_img_bar = 0; + + FFVulkanShader *decode_shader = &prv->decode; + ff_vk_shader_update_img_array(&ctx->s, exec, decode_shader, + prr->frame, vp->view.out, + 0, 0, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, decode_shader, + 0, 1, 0, + frame_data_buf, + 0, prr->nb_tiles*sizeof(TileData), + VK_FORMAT_UNDEFINED); + + ff_vk_exec_bind_shader(&ctx->s, exec, decode_shader); + + /* Update push data */ + DecodePushData pd_decode = (DecodePushData) { + .pkt_data = slices_buf->address, + .tile_size[0] = prr->tw, + .tile_size[1] = prr->th, + }; + memcpy(pd_decode.qmat, prr->qmat, 64); + ff_vk_shader_update_push_const(&ctx->s, exec, decode_shader, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd_decode) - 64, &pd_decode); + + vk->CmdDispatch(exec->buf, prr->nb_tw, prr->nb_th, 1); + + ff_vk_frame_barrier(&ctx->s, exec, prr->frame, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_2_SHADER_STORAGE_READ_BIT | + VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + FFVulkanShader *idct_shader = &prv->idct; + ff_vk_shader_update_img_array(&ctx->s, exec, idct_shader, + prr->frame, vp->view.out, + 0, 0, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, idct_shader, + 0, 1, 0, + frame_data_buf, + 0, prr->nb_tiles*sizeof(TileData), + VK_FORMAT_UNDEFINED); + ff_vk_exec_bind_shader(&ctx->s, exec, idct_shader); + ff_vk_shader_update_push_const(&ctx->s, exec, idct_shader, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd_decode), &pd_decode); + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + nb_img_bar = 0; + + vk->CmdDispatch(exec->buf, prr->nb_tw, prr->nb_th, 1); + + err = ff_vk_exec_submit(&ctx->s, exec); + if (err < 0) + return err; + +fail: + return 0; +} + +static int add_desc(AVCodecContext *avctx, FFVulkanContext *s, + FFVulkanShader *shd) +{ + const FFVulkanDescriptorSetBinding desc_set[] = { + { /* dst */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { /* frame_data_buf */ + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + + return ff_vk_shader_add_descriptor_set(s, shd, desc_set, 2, 0, 0); +} + +static int init_decode_shader(AVCodecContext *avctx, FFVulkanContext *s, + FFVkExecPool *pool, FFVulkanShader *shd, + int version) +{ + int err; + + ff_vk_shader_add_push_const(shd, 0, sizeof(DecodePushData) - 64, + VK_SHADER_STAGE_COMPUTE_BIT); + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL, + (uint32_t []) { 1, 4, 1 }, 0); + + add_desc(avctx, s, shd); + + RET(ff_vk_shader_link(s, shd, + ff_prores_raw_decode_comp_spv_data, + ff_prores_raw_decode_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + return err; +} + +static int init_idct_shader(AVCodecContext *avctx, FFVulkanContext *s, + FFVkExecPool *pool, FFVulkanShader *shd, + int version) +{ + int err; + SPEC_LIST_CREATE(sl, 2 + 64, (2 + 64)*sizeof(uint32_t)) + + int nb_blocks = version == 0 ? 8 : 16; + SPEC_LIST_ADD(sl, 16, 32, nb_blocks); + SPEC_LIST_ADD(sl, 17, 32, 4); /* nb_components */ + + const double idct_8_scales[8] = { + cos(4.0*M_PI/16.0) / 2.0, cos(1.0*M_PI/16.0) / 2.0, + cos(2.0*M_PI/16.0) / 2.0, cos(3.0*M_PI/16.0) / 2.0, + cos(4.0*M_PI/16.0) / 2.0, cos(5.0*M_PI/16.0) / 2.0, + cos(6.0*M_PI/16.0) / 2.0, cos(7.0*M_PI/16.0) / 2.0, + }; + for (int i = 0; i < 64; i++) + SPEC_LIST_ADD(sl, 18 + i, 32, + av_float2int(idct_8_scales[i >> 3]*idct_8_scales[i & 7])); + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, + (uint32_t []) { 8, nb_blocks, 4 }, 0); + + ff_vk_shader_add_push_const(shd, 0, sizeof(DecodePushData), + VK_SHADER_STAGE_COMPUTE_BIT); + add_desc(avctx, s, shd); + + RET(ff_vk_shader_link(s, shd, + ff_prores_raw_idct_comp_spv_data, + ff_prores_raw_idct_comp_spv_len, "main")); + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + return err; +} + +static void vk_decode_prores_raw_uninit(FFVulkanDecodeShared *ctx) +{ + ProResRAWVulkanDecodeContext *fv = ctx->sd_ctx; + + ff_vk_shader_free(&ctx->s, &fv->decode); + ff_vk_shader_free(&ctx->s, &fv->idct); + + av_buffer_pool_uninit(&fv->frame_data_pool); + + av_freep(&fv); +} + +static int vk_decode_prores_raw_init(AVCodecContext *avctx) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + ProResRAWContext *prr = avctx->priv_data; + + err = ff_vk_decode_init(avctx); + if (err < 0) + return err; + + FFVulkanDecodeShared *ctx = dec->shared_ctx; + ProResRAWVulkanDecodeContext *prv = ctx->sd_ctx = av_mallocz(sizeof(*prv)); + if (!prv) { + err = AVERROR(ENOMEM); + goto fail; + } + + ctx->sd_ctx_free = &vk_decode_prores_raw_uninit; + + /* Setup decode shader */ + RET(init_decode_shader(avctx, &ctx->s, &ctx->exec_pool, &prv->decode, + prr->version)); + RET(init_idct_shader(avctx, &ctx->s, &ctx->exec_pool, &prv->idct, + prr->version)); + +fail: + return err; +} + +static void vk_prores_raw_free_frame_priv(AVRefStructOpaque _hwctx, void *data) +{ + AVHWDeviceContext *dev_ctx = _hwctx.nc; + + ProResRAWVulkanDecodePicture *pp = data; + FFVulkanDecodePicture *vp = &pp->vp; + + ff_vk_decode_free_frame(dev_ctx, vp); + + av_buffer_unref(&pp->frame_data_buf); +} + +const FFHWAccel ff_prores_raw_vulkan_hwaccel = { + .p.name = "prores_raw_vulkan", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_PRORES_RAW, + .p.pix_fmt = AV_PIX_FMT_VULKAN, + .start_frame = &vk_prores_raw_start_frame, + .decode_slice = &vk_prores_raw_decode_slice, + .end_frame = &vk_prores_raw_end_frame, + .free_frame_priv = &vk_prores_raw_free_frame_priv, + .frame_priv_data_size = sizeof(ProResRAWVulkanDecodePicture), + .init = &vk_decode_prores_raw_init, + .update_thread_context = &ff_vk_update_thread_context, + .uninit = &ff_vk_decode_uninit, + .frame_params = &ff_vk_frame_params, + .priv_data_size = sizeof(FFVulkanDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE, +}; diff --git a/libavcodec/vulkan_video.c b/libavcodec/vulkan_video.c index 3a04d60d6..674a0fdc3 100644 --- a/libavcodec/vulkan_video.c +++ b/libavcodec/vulkan_video.c @@ -33,7 +33,6 @@ static const struct FFVkFormatMapEntry { { VK_FORMAT_R32_SFLOAT, AV_PIX_FMT_GRAYF32, VK_IMAGE_ASPECT_COLOR_BIT }, /* RGB formats */ - { VK_FORMAT_R16G16B16A16_UNORM, AV_PIX_FMT_XV36, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_B8G8R8A8_UNORM, AV_PIX_FMT_BGRA, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_R8G8B8A8_UNORM, AV_PIX_FMT_RGBA, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_R8G8B8_UNORM, AV_PIX_FMT_RGB24, VK_IMAGE_ASPECT_COLOR_BIT }, @@ -84,11 +83,16 @@ static const struct FFVkFormatMapEntry { { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P12, ASPECT_3PLANE }, { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P16, ASPECT_3PLANE }, - /* Single plane 422 at 8, 10 and 12 bits */ + /* Single plane 422 at 8, 10, 12 and 16 bits */ { VK_FORMAT_G8B8G8R8_422_UNORM, AV_PIX_FMT_YUYV422, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_B8G8R8G8_422_UNORM, AV_PIX_FMT_UYVY422, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, AV_PIX_FMT_Y210, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, AV_PIX_FMT_Y212, VK_IMAGE_ASPECT_COLOR_BIT }, + { VK_FORMAT_G16B16G16R16_422_UNORM, AV_PIX_FMT_Y216, VK_IMAGE_ASPECT_COLOR_BIT }, + + /* Single plane 444 at 10 and 12 bits */ + { VK_FORMAT_A2R10G10B10_UNORM_PACK32, AV_PIX_FMT_XV30, VK_IMAGE_ASPECT_COLOR_BIT }, + { VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, AV_PIX_FMT_XV36, VK_IMAGE_ASPECT_COLOR_BIT }, }; static const int nb_vk_format_map = FF_ARRAY_ELEMS(vk_format_map); @@ -222,6 +226,37 @@ StdVideoH265LevelIdc ff_vk_h265_level_to_vk(int level_idc) } } +StdVideoAV1Level ff_vk_av1_level_to_vk(int level) +{ + switch (level) { + case 20: return STD_VIDEO_AV1_LEVEL_2_0; + case 21: return STD_VIDEO_AV1_LEVEL_2_1; + case 22: return STD_VIDEO_AV1_LEVEL_2_2; + case 23: return STD_VIDEO_AV1_LEVEL_2_3; + case 30: return STD_VIDEO_AV1_LEVEL_3_0; + case 31: return STD_VIDEO_AV1_LEVEL_3_1; + case 32: return STD_VIDEO_AV1_LEVEL_3_2; + case 33: return STD_VIDEO_AV1_LEVEL_3_3; + case 40: return STD_VIDEO_AV1_LEVEL_4_0; + case 41: return STD_VIDEO_AV1_LEVEL_4_1; + case 42: return STD_VIDEO_AV1_LEVEL_4_2; + case 43: return STD_VIDEO_AV1_LEVEL_4_3; + case 50: return STD_VIDEO_AV1_LEVEL_5_0; + case 51: return STD_VIDEO_AV1_LEVEL_5_1; + case 52: return STD_VIDEO_AV1_LEVEL_5_2; + case 53: return STD_VIDEO_AV1_LEVEL_5_3; + case 60: return STD_VIDEO_AV1_LEVEL_6_0; + case 61: return STD_VIDEO_AV1_LEVEL_6_1; + case 62: return STD_VIDEO_AV1_LEVEL_6_2; + case 63: return STD_VIDEO_AV1_LEVEL_6_3; + case 70: return STD_VIDEO_AV1_LEVEL_7_0; + case 71: return STD_VIDEO_AV1_LEVEL_7_1; + case 72: return STD_VIDEO_AV1_LEVEL_7_2; + default: + case 73: return STD_VIDEO_AV1_LEVEL_7_3; + } +} + StdVideoH264ProfileIdc ff_vk_h264_profile_to_vk(int profile) { switch (profile) { @@ -243,57 +278,34 @@ StdVideoH265ProfileIdc ff_vk_h265_profile_to_vk(int profile) } } -int ff_vk_h264_profile_to_av(StdVideoH264ProfileIdc profile) +StdVideoAV1Profile ff_vk_av1_profile_to_vk(int profile) { switch (profile) { - case STD_VIDEO_H264_PROFILE_IDC_BASELINE: return AV_PROFILE_H264_CONSTRAINED_BASELINE; - case STD_VIDEO_H264_PROFILE_IDC_MAIN: return AV_PROFILE_H264_MAIN; - case STD_VIDEO_H264_PROFILE_IDC_HIGH: return AV_PROFILE_H264_HIGH; - case STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE: return AV_PROFILE_H264_HIGH_444_PREDICTIVE; - default: return AV_PROFILE_UNKNOWN; + case AV_PROFILE_AV1_MAIN: return STD_VIDEO_AV1_PROFILE_MAIN; + case AV_PROFILE_AV1_HIGH: return STD_VIDEO_AV1_PROFILE_HIGH; + case AV_PROFILE_AV1_PROFESSIONAL: return STD_VIDEO_AV1_PROFILE_PROFESSIONAL; + default: return STD_VIDEO_AV1_PROFILE_INVALID; } } -int ff_vk_h265_profile_to_av(StdVideoH264ProfileIdc profile) -{ - switch (profile) { - case STD_VIDEO_H265_PROFILE_IDC_MAIN: return AV_PROFILE_HEVC_MAIN; - case STD_VIDEO_H265_PROFILE_IDC_MAIN_10: return AV_PROFILE_HEVC_MAIN_10; - case STD_VIDEO_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSIONS: return AV_PROFILE_HEVC_REXT; - default: return AV_PROFILE_UNKNOWN; - } -} - -int ff_vk_video_qf_init(FFVulkanContext *s, FFVkQueueFamilyCtx *qf, - VkQueueFlagBits family, VkVideoCodecOperationFlagBitsKHR caps) -{ - for (int i = 0; i < s->hwctx->nb_qf; i++) { - if ((s->hwctx->qf[i].flags & family) && - (s->hwctx->qf[i].video_caps & caps)) { - qf->queue_family = s->hwctx->qf[i].idx; - qf->nb_queues = s->hwctx->qf[i].num; - return 0; - } - } - return AVERROR(ENOTSUP); -} - int ff_vk_create_view(FFVulkanContext *s, FFVkVideoCommon *common, VkImageView *view, VkImageAspectFlags *aspect, - AVVkFrame *src, VkFormat vkf, int is_dpb) + AVVkFrame *src, VkFormat vkf, VkImageUsageFlags usage) { VkResult ret; FFVulkanFunctions *vk = &s->vkfn; VkImageAspectFlags aspect_mask = ff_vk_aspect_bits_from_vkfmt(vkf); + int is_video_dpb = usage & (VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR | + VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR); - VkSamplerYcbcrConversionInfo yuv_sampler_info = { - .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, - .conversion = common->yuv_sampler, + VkImageViewUsageCreateInfo usage_create_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, + .usage = usage, }; VkImageViewCreateInfo img_view_create_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .pNext = &yuv_sampler_info, - .viewType = common->layered_dpb && is_dpb ? + .pNext = &usage_create_info, + .viewType = common->layered_dpb && is_video_dpb ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, .format = vkf, .image = src->img[0], @@ -306,7 +318,7 @@ int ff_vk_create_view(FFVulkanContext *s, FFVkVideoCommon *common, .subresourceRange = (VkImageSubresourceRange) { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseArrayLayer = 0, - .layerCount = common->layered_dpb && is_dpb ? + .layerCount = common->layered_dpb && is_video_dpb ? VK_REMAINING_ARRAY_LAYERS : 1, .levelCount = 1, }, @@ -339,17 +351,15 @@ av_cold void ff_vk_video_common_uninit(FFVulkanContext *s, av_freep(&common->mem); - if (common->layered_view) + if (common->layered_view) { vk->DestroyImageView(s->hwctx->act_dev, common->layered_view, s->hwctx->alloc); + common->layered_view = VK_NULL_HANDLE; + } av_frame_free(&common->layered_frame); av_buffer_unref(&common->dpb_hwfc_ref); - - if (common->yuv_sampler) - vk->DestroySamplerYcbcrConversion(s->hwctx->act_dev, common->yuv_sampler, - s->hwctx->alloc); } av_cold int ff_vk_video_common_init(AVCodecContext *avctx, FFVulkanContext *s, @@ -362,30 +372,13 @@ av_cold int ff_vk_video_common_init(AVCodecContext *avctx, FFVulkanContext *s, VkVideoSessionMemoryRequirementsKHR *mem = NULL; VkBindVideoSessionMemoryInfoKHR *bind_mem = NULL; - int cxpos = 0, cypos = 0; - VkSamplerYcbcrConversionCreateInfo yuv_sampler_info = { - .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, - .components = ff_comp_identity_map, - .ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, - .ycbcrRange = avctx->color_range == AVCOL_RANGE_MPEG, /* Ignored */ - .format = session_create->pictureFormat, - }; - - /* Create identity YUV sampler - * (VkImageViews of YUV image formats require it, even if it does nothing) */ - av_chroma_location_enum_to_pos(&cxpos, &cypos, avctx->chroma_sample_location); - yuv_sampler_info.xChromaOffset = cxpos >> 7; - yuv_sampler_info.yChromaOffset = cypos >> 7; - ret = vk->CreateSamplerYcbcrConversion(s->hwctx->act_dev, &yuv_sampler_info, - s->hwctx->alloc, &common->yuv_sampler); - if (ret != VK_SUCCESS) - return AVERROR_EXTERNAL; - /* Create session */ ret = vk->CreateVideoSessionKHR(s->hwctx->act_dev, session_create, s->hwctx->alloc, &common->session); - if (ret != VK_SUCCESS) - return AVERROR_EXTERNAL; + if (ret != VK_SUCCESS) { + err = AVERROR_EXTERNAL; + goto fail; + } /* Get memory requirements */ ret = vk->GetVideoSessionMemoryRequirementsKHR(s->hwctx->act_dev, diff --git a/libavcodec/vulkan_video.h b/libavcodec/vulkan_video.h index c205f7b88..d63bfae3f 100644 --- a/libavcodec/vulkan_video.h +++ b/libavcodec/vulkan_video.h @@ -20,7 +20,7 @@ #define AVCODEC_VULKAN_VIDEO_H #include "avcodec.h" -#include "vulkan.h" +#include "libavutil/vulkan.h" #include @@ -34,8 +34,6 @@ typedef struct FFVkVideoSession { VkDeviceMemory *mem; uint32_t nb_mem; - VkSamplerYcbcrConversion yuv_sampler; - AVBufferRef *dpb_hwfc_ref; int layered_dpb; AVFrame *layered_frame; @@ -63,12 +61,6 @@ VkVideoChromaSubsamplingFlagBitsKHR ff_vk_subsampling_from_av_desc(const AVPixFm */ VkVideoComponentBitDepthFlagBitsKHR ff_vk_depth_from_av_depth(int depth); -/** - * Chooses a QF and loads it into a context. - */ -int ff_vk_video_qf_init(FFVulkanContext *s, FFVkQueueFamilyCtx *qf, - VkQueueFlagBits family, VkVideoCodecOperationFlagBitsKHR caps); - /** * Convert level from Vulkan to AV. */ @@ -77,21 +69,21 @@ int ff_vk_h265_level_to_av(StdVideoH265LevelIdc level); StdVideoH264LevelIdc ff_vk_h264_level_to_vk(int level_idc); StdVideoH265LevelIdc ff_vk_h265_level_to_vk(int level_idc); +StdVideoAV1Level ff_vk_av1_level_to_vk(int level); /** * Convert profile from/to AV to Vulkan */ StdVideoH264ProfileIdc ff_vk_h264_profile_to_vk(int profile); StdVideoH265ProfileIdc ff_vk_h265_profile_to_vk(int profile); -int ff_vk_h264_profile_to_av(StdVideoH264ProfileIdc profile); -int ff_vk_h265_profile_to_av(StdVideoH264ProfileIdc profile); +StdVideoAV1Profile ff_vk_av1_profile_to_vk(int profile); /** * Creates image views for video frames. */ int ff_vk_create_view(FFVulkanContext *s, FFVkVideoCommon *common, VkImageView *view, VkImageAspectFlags *aspect, - AVVkFrame *src, VkFormat vkf, int is_dpb); + AVVkFrame *src, VkFormat vkf, VkImageUsageFlags flags); /** * Initialize video session, allocating and binding necessary memory. diff --git a/libavcodec/vulkan_vp9.c b/libavcodec/vulkan_vp9.c new file mode 100644 index 000000000..5aeec3fb2 --- /dev/null +++ b/libavcodec/vulkan_vp9.c @@ -0,0 +1,372 @@ +/* + * 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 "vp9dec.h" + +#include "vulkan_decode.h" + +const FFVulkanDecodeDescriptor ff_vk_dec_vp9_desc = { + .codec_id = AV_CODEC_ID_VP9, + .decode_extension = FF_VK_EXT_VIDEO_DECODE_VP9, + .queue_flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR, + .decode_op = VK_VIDEO_CODEC_OPERATION_DECODE_VP9_BIT_KHR, + .ext_props = { + .extensionName = VK_STD_VULKAN_VIDEO_CODEC_VP9_DECODE_EXTENSION_NAME, + .specVersion = VK_STD_VULKAN_VIDEO_CODEC_VP9_DECODE_SPEC_VERSION, + }, +}; + +typedef struct VP9VulkanDecodePicture { + FFVulkanDecodePicture vp; + + /* TODO: investigate if this can be removed to make decoding completely + * independent. */ + FFVulkanDecodeContext *dec; + + /* Current picture */ + StdVideoVP9ColorConfig color_config; + StdVideoVP9Segmentation segmentation; + StdVideoVP9LoopFilter loop_filter; + StdVideoDecodeVP9PictureInfo std_pic_info; + VkVideoDecodeVP9PictureInfoKHR vp9_pic_info; + + const VP9Frame *ref_src[8]; + + uint8_t frame_id_set; + uint8_t frame_id; + uint8_t ref_frame_sign_bias_mask; +} VP9VulkanDecodePicture; + +static int vk_vp9_fill_pict(AVCodecContext *avctx, const VP9Frame **ref_src, + VkVideoReferenceSlotInfoKHR *ref_slot, /* Main structure */ + VkVideoPictureResourceInfoKHR *ref, /* Goes in ^ */ + const VP9Frame *pic, int is_current) +{ + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + VP9VulkanDecodePicture *hp = pic->hwaccel_picture_private; + FFVulkanDecodePicture *vkpic = &hp->vp; + + int err = ff_vk_decode_prepare_frame(dec, pic->tf.f, vkpic, is_current, + dec->dedicated_dpb); + if (err < 0) + return err; + + *ref = (VkVideoPictureResourceInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, + .codedOffset = (VkOffset2D){ 0, 0 }, + .codedExtent = (VkExtent2D){ pic->tf.f->width, pic->tf.f->height }, + .baseArrayLayer = (dec->dedicated_dpb && ctx->common.layered_dpb) ? + hp->frame_id : 0, + .imageViewBinding = vkpic->view.ref[0], + }; + + *ref_slot = (VkVideoReferenceSlotInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR, + .slotIndex = hp->frame_id, + .pPictureResource = ref, + }; + + if (ref_src) + *ref_src = pic; + + return 0; +} + +static enum StdVideoVP9InterpolationFilter remap_interp(uint8_t is_filter_switchable, + uint8_t raw_interpolation_filter_type) +{ + static const enum StdVideoVP9InterpolationFilter remap[] = { + STD_VIDEO_VP9_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH, + STD_VIDEO_VP9_INTERPOLATION_FILTER_EIGHTTAP, + STD_VIDEO_VP9_INTERPOLATION_FILTER_EIGHTTAP_SHARP, + STD_VIDEO_VP9_INTERPOLATION_FILTER_BILINEAR, + }; + if (is_filter_switchable) + return STD_VIDEO_VP9_INTERPOLATION_FILTER_SWITCHABLE; + return remap[raw_interpolation_filter_type]; +} + +static int vk_vp9_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + int err; + int ref_count = 0; + const VP9Context *priv = avctx->priv_data; + const CodedBitstreamVP9Context *vp9 = priv->cbc->priv_data; + const VP9SharedContext *s = &priv->s; + uint32_t frame_id_alloc_mask = 0; + + const VP9Frame *pic = &s->frames[CUR_FRAME]; + const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + uint8_t profile = (pic->frame_header->profile_high_bit << 1) | pic->frame_header->profile_low_bit; + + VP9VulkanDecodePicture *ap = pic->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &ap->vp; + + /* Use the current frame_ids in ref_frames[] to decide occupied frame_ids */ + for (int i = 0; i < STD_VIDEO_VP9_NUM_REF_FRAMES; i++) { + const VP9VulkanDecodePicture* rp = s->ref_frames[i].hwaccel_picture_private; + if (rp) + frame_id_alloc_mask |= 1 << rp->frame_id; + } + + if (!ap->frame_id_set) { + unsigned slot_idx = 0; + for (unsigned i = 0; i < 32; i++) { + if (!(frame_id_alloc_mask & (1 << i))) { + slot_idx = i; + break; + } + } + ap->frame_id = slot_idx; + ap->frame_id_set = 1; + frame_id_alloc_mask |= (1 << slot_idx); + } + + for (int i = 0; i < STD_VIDEO_VP9_REFS_PER_FRAME; i++) { + const int idx = pic->frame_header->ref_frame_idx[i]; + const VP9Frame *ref_frame = &s->ref_frames[idx]; + VP9VulkanDecodePicture *hp = ref_frame->hwaccel_picture_private; + int found = 0; + + if (!ref_frame->tf.f) + continue; + + for (int j = 0; j < ref_count; j++) { + if (vp->ref_slots[j].slotIndex == hp->frame_id) { + found = 1; + break; + } + } + if (found) + continue; + + err = vk_vp9_fill_pict(avctx, &ap->ref_src[ref_count], + &vp->ref_slots[ref_count], &vp->refs[ref_count], + ref_frame, 0); + if (err < 0) + return err; + + ref_count++; + } + + err = vk_vp9_fill_pict(avctx, NULL, &vp->ref_slot, &vp->ref, + pic, 1); + if (err < 0) + return err; + + ap->loop_filter = (StdVideoVP9LoopFilter) { + .flags = (StdVideoVP9LoopFilterFlags) { + .loop_filter_delta_enabled = pic->frame_header->loop_filter_delta_enabled, + .loop_filter_delta_update = pic->frame_header->loop_filter_delta_update, + }, + .loop_filter_level = pic->frame_header->loop_filter_level, + .loop_filter_sharpness = pic->frame_header->loop_filter_sharpness, + .update_ref_delta = 0x0, + .update_mode_delta = 0x0, + }; + + for (int i = 0; i < STD_VIDEO_VP9_MAX_REF_FRAMES; i++) { + ap->loop_filter.loop_filter_ref_deltas[i] = vp9->loop_filter_ref_deltas[i]; + ap->loop_filter.update_ref_delta |= pic->frame_header->update_ref_delta[i]; + } + for (int i = 0; i < STD_VIDEO_VP9_LOOP_FILTER_ADJUSTMENTS; i++) { + ap->loop_filter.loop_filter_mode_deltas[i] = vp9->loop_filter_mode_deltas[i]; + ap->loop_filter.update_mode_delta |= pic->frame_header->update_mode_delta[i]; + } + + ap->segmentation = (StdVideoVP9Segmentation) { + .flags = (StdVideoVP9SegmentationFlags) { + .segmentation_update_map = pic->frame_header->segmentation_update_map, + .segmentation_temporal_update = pic->frame_header->segmentation_temporal_update, + .segmentation_update_data = pic->frame_header->segmentation_update_data, + .segmentation_abs_or_delta_update = pic->frame_header->segmentation_abs_or_delta_update, + }, + }; + + for (int i = 0; i < STD_VIDEO_VP9_MAX_SEGMENTATION_TREE_PROBS; i++) + ap->segmentation.segmentation_tree_probs[i] = vp9->segmentation_tree_probs[i]; + for (int i = 0; i < STD_VIDEO_VP9_MAX_SEGMENTATION_PRED_PROB; i++) + ap->segmentation.segmentation_pred_prob[i] = vp9->segmentation_pred_prob[i]; + for (int i = 0; i < STD_VIDEO_VP9_MAX_SEGMENTS; i++) { + ap->segmentation.FeatureEnabled[i] = 0x0; + for (int j = 0; j < STD_VIDEO_VP9_SEG_LVL_MAX; j++) { + ap->segmentation.FeatureEnabled[i] |= vp9->feature_enabled[i][j] << j; + ap->segmentation.FeatureData[i][j] = vp9->feature_sign[i][j] ? + -vp9->feature_value[i][j] : + +vp9->feature_value[i][j]; + } + } + + ap->color_config = (StdVideoVP9ColorConfig) { + .flags = (StdVideoVP9ColorConfigFlags) { + .color_range = pic->frame_header->color_range, + }, + .BitDepth = profile < 2 ? 8 : + pic->frame_header->ten_or_twelve_bit ? 12 : 10, + .subsampling_x = pixdesc->log2_chroma_w, + .subsampling_y = pixdesc->log2_chroma_h, + + .color_space = pic->frame_header->color_space, + }; + + ap->std_pic_info = (StdVideoDecodeVP9PictureInfo) { + .flags = (StdVideoDecodeVP9PictureInfoFlags) { + .error_resilient_mode = pic->frame_header->error_resilient_mode, + .intra_only = pic->frame_header->intra_only, + .allow_high_precision_mv = pic->frame_header->allow_high_precision_mv, + .refresh_frame_context = pic->frame_header->refresh_frame_context, + .frame_parallel_decoding_mode = pic->frame_header->frame_parallel_decoding_mode, + .segmentation_enabled = pic->frame_header->segmentation_enabled, + .show_frame = !s->h.invisible, + .UsePrevFrameMvs = s->h.use_last_frame_mvs, + }, + .profile = profile, + .frame_type = pic->frame_header->frame_type, + .frame_context_idx = pic->frame_header->frame_context_idx, + .reset_frame_context = pic->frame_header->reset_frame_context, + .refresh_frame_flags = pic->frame_header->refresh_frame_flags, + .ref_frame_sign_bias_mask = 0x0, + .interpolation_filter = remap_interp(pic->frame_header->is_filter_switchable, + pic->frame_header->raw_interpolation_filter_type), + .base_q_idx = pic->frame_header->base_q_idx, + .delta_q_y_dc = pic->frame_header->delta_q_y_dc, + .delta_q_uv_dc = pic->frame_header->delta_q_uv_dc, + .delta_q_uv_ac = pic->frame_header->delta_q_uv_ac, + .tile_cols_log2 = pic->frame_header->tile_cols_log2, + .tile_rows_log2 = pic->frame_header->tile_rows_log2, + /* Reserved */ + .pColorConfig = &ap->color_config, + .pLoopFilter = &ap->loop_filter, + .pSegmentation = &ap->segmentation, + }; + + for (int i = VP9_LAST_FRAME; i <= VP9_ALTREF_FRAME; i++) + ap->std_pic_info.ref_frame_sign_bias_mask |= pic->frame_header->ref_frame_sign_bias[i] << i; + + ap->vp9_pic_info = (VkVideoDecodeVP9PictureInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_PICTURE_INFO_KHR, + .pStdPictureInfo = &ap->std_pic_info, + .uncompressedHeaderOffset = 0, + .compressedHeaderOffset = s->h.uncompressed_header_size, + .tilesOffset = s->h.uncompressed_header_size + + s->h.compressed_header_size, + }; + + for (int i = 0; i < STD_VIDEO_VP9_REFS_PER_FRAME; i++) { + const int idx = pic->frame_header->ref_frame_idx[i]; + const VP9Frame *ref_frame = &s->ref_frames[idx]; + VP9VulkanDecodePicture *hp = ref_frame->hwaccel_picture_private; + + if (!ref_frame->tf.f) + ap->vp9_pic_info.referenceNameSlotIndices[i] = -1; + else + ap->vp9_pic_info.referenceNameSlotIndices[i] = hp->frame_id; + } + + vp->decode_info = (VkVideoDecodeInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR, + .pNext = &ap->vp9_pic_info, + .flags = 0x0, + .pSetupReferenceSlot = &vp->ref_slot, + .referenceSlotCount = ref_count, + .pReferenceSlots = vp->ref_slots, + .dstPictureResource = (VkVideoPictureResourceInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, + .codedOffset = (VkOffset2D){ 0, 0 }, + .codedExtent = (VkExtent2D){ pic->tf.f->width, pic->tf.f->height }, + .baseArrayLayer = 0, + .imageViewBinding = vp->view.out[0], + }, + }; + + ap->dec = dec; + + return 0; +} + +static int vk_vp9_decode_slice(AVCodecContext *avctx, + const uint8_t *data, + uint32_t size) +{ + int err; + const VP9SharedContext *s = avctx->priv_data; + VP9VulkanDecodePicture *ap = s->frames[CUR_FRAME].hwaccel_picture_private; + FFVulkanDecodePicture *vp = &ap->vp; + + err = ff_vk_decode_add_slice(avctx, vp, data, size, 0, NULL, NULL); + if (err < 0) + return err; + + return 0; +} + +static int vk_vp9_end_frame(AVCodecContext *avctx) +{ + const VP9SharedContext *s = avctx->priv_data; + + const VP9Frame *pic = &s->frames[CUR_FRAME]; + VP9VulkanDecodePicture *ap = pic->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &ap->vp; + FFVulkanDecodePicture *rvp[STD_VIDEO_VP9_REFS_PER_FRAME] = { 0 }; + AVFrame *rav[STD_VIDEO_VP9_REFS_PER_FRAME] = { 0 }; + + for (int i = 0; i < vp->decode_info.referenceSlotCount; i++) { + const VP9Frame *rp = ap->ref_src[i]; + VP9VulkanDecodePicture *rhp = rp->hwaccel_picture_private; + + rvp[i] = &rhp->vp; + rav[i] = ap->ref_src[i]->tf.f; + } + + av_log(avctx, AV_LOG_VERBOSE, "Decoding frame, %zu bytes\n", + vp->slices_size); + + return ff_vk_decode_frame(avctx, pic->tf.f, vp, rav, rvp); +} + +static void vk_vp9_free_frame_priv(AVRefStructOpaque _hwctx, void *data) +{ + AVHWDeviceContext *hwctx = _hwctx.nc; + VP9VulkanDecodePicture *ap = data; + + /* Free frame resources, this also destroys the session parameters. */ + ff_vk_decode_free_frame(hwctx, &ap->vp); +} + +const FFHWAccel ff_vp9_vulkan_hwaccel = { + .p.name = "vp9_vulkan", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_VP9, + .p.pix_fmt = AV_PIX_FMT_VULKAN, + .start_frame = &vk_vp9_start_frame, + .decode_slice = &vk_vp9_decode_slice, + .end_frame = &vk_vp9_end_frame, + .free_frame_priv = &vk_vp9_free_frame_priv, + .frame_priv_data_size = sizeof(VP9VulkanDecodePicture), + .init = &ff_vk_decode_init, + .update_thread_context = &ff_vk_update_thread_context, + .uninit = &ff_vk_decode_uninit, + .frame_params = &ff_vk_frame_params, + .priv_data_size = sizeof(FFVulkanDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE, +}; diff --git a/libavcodec/vvc.h b/libavcodec/vvc.h index 92639779c..5490ddb4c 100644 --- a/libavcodec/vvc.h +++ b/libavcodec/vvc.h @@ -154,6 +154,9 @@ enum { // {sps, ph}_num_{ver, hor}_virtual_boundaries should in [0, 3] VVC_MAX_VBS = 3, + + // 8.4.5.3 Decoding process for palette mode - maxNumPalettePredictorSize + VVC_MAX_NUM_PALETTE_PREDICTOR_SIZE = 63 }; #endif /* AVCODEC_VVC_H */ diff --git a/libavcodec/vvc/Makefile b/libavcodec/vvc/Makefile index 6a28d32bc..10125ffc2 100644 --- a/libavcodec/vvc/Makefile +++ b/libavcodec/vvc/Makefile @@ -14,4 +14,5 @@ OBJS-$(CONFIG_VVC_DECODER) += vvc/dec.o \ vvc/mvs.o \ vvc/ps.o \ vvc/refs.o \ + vvc/sei.o \ vvc/thread.o \ diff --git a/libavcodec/vvc/cabac.c b/libavcodec/vvc/cabac.c index 0d45eec75..c2dbd4670 100644 --- a/libavcodec/vvc/cabac.c +++ b/libavcodec/vvc/cabac.c @@ -928,6 +928,32 @@ static int truncated_binary_decode(VVCLocalContext *lc, const int c_max) return v; } +// 9.3.3.5 k-th order Exp - Golomb binarization process +static int kth_order_egk_decode(CABACContext *c, int k, const int max) +{ + int bit = 1; + int value = 0; + int symbol = 0; + + while (bit) { + bit = get_cabac_bypass(c); + if (max - value < (bit << k)) + return AVERROR_INVALIDDATA; + value += bit << k++; + } + + if (--k) { + for (int i = 0; i < k; i++) + symbol = (symbol << 1) | get_cabac_bypass(c); + value += symbol; + } + + if (value > max) + return AVERROR_INVALIDDATA; + + return value; +} + // 9.3.3.6 Limited k-th order Exp-Golomb binarization process static int limited_kth_order_egk_decode(CABACContext *c, const int k, const int max_pre_ext_len, const int trunc_suffix_len) { @@ -947,6 +973,17 @@ static int limited_kth_order_egk_decode(CABACContext *c, const int k, const int return val; } +// 9.3.3.7 Fixed-length binarization process +static int fixed_length_decode(CABACContext* c, const int len) +{ + int value = 0; + + for (int i = 0; i < len; i++) + value = (value << 1) | get_cabac_bypass(c); + + return value; +} + static av_always_inline void get_left_top(const VVCLocalContext *lc, uint8_t *left, uint8_t *top, const int x0, const int y0, const uint8_t *left_ctx, const uint8_t *top_ctx) @@ -990,11 +1027,7 @@ int ff_vvc_sao_type_idx_decode(VVCLocalContext *lc) int ff_vvc_sao_band_position_decode(VVCLocalContext *lc) { - int value = get_cabac_bypass(&lc->ep->cc); - - for (int i = 0; i < 4; i++) - value = (value << 1) | get_cabac_bypass(&lc->ep->cc); - return value; + return fixed_length_decode(&lc->ep->cc, 5); } int ff_vvc_sao_offset_abs_decode(VVCLocalContext *lc) @@ -1014,9 +1047,7 @@ int ff_vvc_sao_offset_sign_decode(VVCLocalContext *lc) int ff_vvc_sao_eo_class_decode(VVCLocalContext *lc) { - int ret = get_cabac_bypass(&lc->ep->cc) << 1; - ret |= get_cabac_bypass(&lc->ep->cc); - return ret; + return (get_cabac_bypass(&lc->ep->cc) << 1) | get_cabac_bypass(&lc->ep->cc); } int ff_vvc_alf_ctb_flag(VVCLocalContext *lc, const int rx, const int ry, const int c_idx) @@ -1257,11 +1288,19 @@ int ff_vvc_pred_mode_ibc_flag(VVCLocalContext *lc, const int is_chroma) return GET_CABAC(PRED_MODE_IBC_FLAG + inc); } +static av_always_inline +uint8_t get_mip_inc(VVCLocalContext *lc, const uint8_t *ctx) +{ + uint8_t left = 0, top = 0; + get_left_top(lc, &left, &top, lc->cu->x0, lc->cu->y0, ctx, ctx); + return (left & 1) + (top & 1); +} + int ff_vvc_intra_mip_flag(VVCLocalContext *lc, const uint8_t *intra_mip_flag) { const int w = lc->cu->cb_width; const int h = lc->cu->cb_height; - const int inc = (w > h * 2 || h > w * 2) ? 3 : get_inc(lc, intra_mip_flag); + const int inc = (w > h * 2 || h > w * 2) ? 3 : get_mip_inc(lc, intra_mip_flag); return GET_CABAC(INTRA_MIP_FLAG + inc); } @@ -1343,6 +1382,58 @@ int ff_vvc_intra_chroma_pred_mode(VVCLocalContext *lc) return (get_cabac_bypass(&lc->ep->cc) << 1) | get_cabac_bypass(&lc->ep->cc); } +int ff_vvc_palette_predictor_run(VVCLocalContext *lc, const int max) +{ + return kth_order_egk_decode(&lc->ep->cc, 0, max); +} + +int ff_vvc_num_signalled_palette_entries(VVCLocalContext *lc, const int max) +{ + return kth_order_egk_decode(&lc->ep->cc, 0, max); +} + +int ff_vvc_new_palette_entries(VVCLocalContext *lc, const int bit_depth) +{ + return fixed_length_decode(&lc->ep->cc, bit_depth); +} + +bool ff_vvc_palette_escape_val_present_flag(VVCLocalContext *lc) +{ + return get_cabac_bypass(&lc->ep->cc); +} + +bool ff_vvc_palette_transpose_flag(VVCLocalContext *lc) +{ + return GET_CABAC(PALETTE_TRANSPOSE_FLAG); +} + +bool ff_vvc_run_copy_flag(VVCLocalContext *lc, const int prev_run_type, const int prev_run_position, const int cur_pos) +{ + uint8_t run_left_lut[] = { 0, 1, 2, 3, 4 }; + uint8_t run_top_lut[] = { 5, 6, 6, 7, 7 }; + + int bin_dist = cur_pos - prev_run_position - 1; + uint8_t *run_lut = prev_run_type == 1 ? run_top_lut : run_left_lut; + uint8_t ctx_inc = bin_dist <= 4 ? run_lut[bin_dist] : run_lut[4]; + + return GET_CABAC(RUN_COPY_FLAG + ctx_inc); +} + +bool ff_vvc_copy_above_palette_indices_flag(VVCLocalContext *lc) +{ + return GET_CABAC(COPY_ABOVE_PALETTE_INDICES_FLAG); +} + +int ff_vvc_palette_idx_idc(VVCLocalContext *lc, const int max_palette_index, const bool adjust) +{ + return truncated_binary_decode(lc, max_palette_index - adjust); +} + +int ff_vvc_palette_escape_val(VVCLocalContext *lc, const int max) +{ + return kth_order_egk_decode(&lc->ep->cc, 5, max); +} + int ff_vvc_general_merge_flag(VVCLocalContext *lc) { return GET_CABAC(GENERAL_MERGE_FLAG); @@ -1450,12 +1541,7 @@ int ff_vvc_merge_idx(VVCLocalContext *lc) int ff_vvc_merge_gpm_partition_idx(VVCLocalContext *lc) { - int i = 0; - - for (int j = 0; j < 6; j++) - i = (i << 1) | get_cabac_bypass(&lc->ep->cc); - - return i; + return fixed_length_decode(&lc->ep->cc, 6); } int ff_vvc_merge_gpm_idx(VVCLocalContext *lc, const int idx) @@ -1622,6 +1708,11 @@ int ff_vvc_tu_y_coded_flag(VVCLocalContext *lc) return lc->parse.prev_tu_cbf_y; } +int ff_vvc_cu_act_enabled_flag(VVCLocalContext *lc) +{ + return GET_CABAC(CU_ACT_ENABLED_FLAG); +} + int ff_vvc_cu_qp_delta_abs(VVCLocalContext *lc) { int v, i, k; diff --git a/libavcodec/vvc/cabac.h b/libavcodec/vvc/cabac.h index e9bc98e23..6a0e713d1 100644 --- a/libavcodec/vvc/cabac.h +++ b/libavcodec/vvc/cabac.h @@ -81,6 +81,15 @@ int ff_vvc_intra_luma_mpm_remainder(VVCLocalContext *lc); int ff_vvc_cclm_mode_flag(VVCLocalContext *lc); int ff_vvc_cclm_mode_idx(VVCLocalContext *lc); int ff_vvc_intra_chroma_pred_mode(VVCLocalContext *lc); +int ff_vvc_palette_predictor_run(VVCLocalContext *lc, const int max); +int ff_vvc_num_signalled_palette_entries(VVCLocalContext *lc, const int max); +int ff_vvc_new_palette_entries(VVCLocalContext *lc, int bit_dpeth); +bool ff_vvc_palette_escape_val_present_flag(VVCLocalContext *lc); +bool ff_vvc_palette_transpose_flag(VVCLocalContext *lc); +bool ff_vvc_run_copy_flag(VVCLocalContext *lc, int prev_run_type, int prev_run_position, int cur_pos); +bool ff_vvc_copy_above_palette_indices_flag(VVCLocalContext *lc); +int ff_vvc_palette_idx_idc(VVCLocalContext *lc, int max_palette_index, bool adjust); +int ff_vvc_palette_escape_val(VVCLocalContext *lc, const int max); //inter int ff_vvc_general_merge_flag(VVCLocalContext *lc); @@ -111,6 +120,7 @@ int ff_vvc_bcw_idx(VVCLocalContext *lc, int no_backward_pred_flag); int ff_vvc_tu_cb_coded_flag(VVCLocalContext *lc); int ff_vvc_tu_cr_coded_flag(VVCLocalContext *lc, int tu_cb_coded_flag); int ff_vvc_tu_y_coded_flag(VVCLocalContext *lc); +int ff_vvc_cu_act_enabled_flag(VVCLocalContext *lc); int ff_vvc_cu_chroma_qp_offset_flag(VVCLocalContext *lc); int ff_vvc_cu_chroma_qp_offset_idx(VVCLocalContext *lc); int ff_vvc_tu_joint_cbcr_residual_flag(VVCLocalContext *lc, int tu_cb_coded_flag, int tu_cr_coded_flag); diff --git a/libavcodec/vvc/ctu.c b/libavcodec/vvc/ctu.c index b33ad576c..e50ac592b 100644 --- a/libavcodec/vvc/ctu.c +++ b/libavcodec/vvc/ctu.c @@ -20,11 +20,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavcodec/refstruct.h" +#include "libavutil/error.h" +#include "libavutil/refstruct.h" #include "cabac.h" #include "ctu.h" #include "inter.h" +#include "intra.h" #include "mvs.h" #define PROF_TEMP_SIZE (PROF_BLOCK_SIZE) * sizeof(int16_t) @@ -38,7 +40,7 @@ typedef enum VVCModeType { MODE_TYPE_INTRA, } VVCModeType; -static void set_tb_pos(const VVCFrameContext *fc, const TransformBlock *tb) +static void set_tb_size(const VVCFrameContext *fc, const TransformBlock *tb) { const int x_tb = tb->x0 >> MIN_TU_LOG2; const int y_tb = tb->y0 >> MIN_TU_LOG2; @@ -50,10 +52,6 @@ static void set_tb_pos(const VVCFrameContext *fc, const TransformBlock *tb) for (int y = y_tb; y < end; y++) { const int off = y * fc->ps.pps->min_tu_width + x_tb; - for (int i = 0; i < width; i++) { - fc->tab.tb_pos_x0[is_chroma][off + i] = tb->x0; - fc->tab.tb_pos_y0[is_chroma][off + i] = tb->y0; - } memset(fc->tab.tb_width [is_chroma] + off, tb->tb_width, width); memset(fc->tab.tb_height[is_chroma] + off, tb->tb_height, width); } @@ -213,7 +211,7 @@ static void set_qp_c(VVCLocalContext *lc) static TransformUnit* alloc_tu(VVCFrameContext *fc, CodingUnit *cu) { - TransformUnit *tu = ff_refstruct_pool_get(fc->tu_pool); + TransformUnit *tu = av_refstruct_pool_get(fc->tu_pool); if (!tu) return NULL; @@ -241,6 +239,7 @@ static TransformUnit* add_tu(VVCFrameContext *fc, CodingUnit *cu, const int x0, tu->height = tu_height; tu->joint_cbcr_residual_flag = 0; memset(tu->coded_flag, 0, sizeof(tu->coded_flag)); + tu->avail[LUMA] = tu->avail[CHROMA] = 0; tu->nb_tbs = 0; return tu; @@ -267,6 +266,7 @@ static TransformBlock* add_tb(TransformUnit *tu, VVCLocalContext *lc, tb->ts = 0; tb->coeffs = lc->coeffs; lc->coeffs += tb_width * tb_height; + tu->avail[!!c_idx] = true; return tb; } @@ -393,9 +393,11 @@ static int hls_transform_unit(VVCLocalContext *lc, int x0, int y0,int tu_width, if (ret < 0) return ret; set_tb_tab(fc->tab.tu_coded_flag[tb->c_idx], tu->coded_flag[tb->c_idx], fc, tb); + } else if (cu->act_enabled_flag) { + memset(tb->coeffs, 0, tb->tb_width * tb->tb_height * sizeof(*tb->coeffs)); } if (tb->c_idx != CR) - set_tb_pos(fc, tb); + set_tb_size(fc, tb); if (tb->c_idx == CB) set_tb_tab(fc->tab.tu_joint_cbcr_residual_flag, tu->joint_cbcr_residual_flag, fc, tb); } @@ -503,16 +505,15 @@ static int skipped_transform_tree(VVCLocalContext *lc, int x0, int y0,int tu_wid SKIPPED_TRANSFORM_TREE(x0, y0 + trafo_height); } else { TransformUnit *tu = add_tu(fc, lc->cu, x0, y0, tu_width, tu_height); - const int has_chroma = sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA; - const int c_start = cu->tree_type == DUAL_TREE_CHROMA ? CB : LUMA; - const int c_end = has_chroma ? VVC_MAX_SAMPLE_ARRAYS : CB; + int start, end; if (!tu) return AVERROR_INVALIDDATA; - for (int i = c_start; i < c_end; i++) { + ff_vvc_channel_range(&start, &end, cu->tree_type, sps->r->sps_chroma_format_idc); + for (int i = start; i < end; i++) { TransformBlock *tb = add_tb(tu, lc, x0, y0, tu_width >> sps->hshift[i], tu_height >> sps->vshift[i], i); if (i != CR) - set_tb_pos(fc, tb); + set_tb_size(fc, tb); } } @@ -897,7 +898,7 @@ static void derive_chroma_intra_pred_mode(VVCLocalContext *lc, enum IntraPredMode luma_intra_pred_mode = SAMPLE_CTB(fc->tab.ipm, x_cb, y_cb); if (cu->tree_type == SINGLE_TREE && sps->r->sps_chroma_format_idc == CHROMA_FORMAT_444 && - intra_chroma_pred_mode == 4 && intra_mip_flag) { + (intra_chroma_pred_mode == 4 || cu->act_enabled_flag) && intra_mip_flag) { cu->mip_chroma_direct_flag = 1; cu->intra_pred_mode_c = luma_intra_pred_mode; return; @@ -948,6 +949,12 @@ static void derive_chroma_intra_pred_mode(VVCLocalContext *lc, } } +static av_always_inline uint8_t pack_mip_info(int intra_mip_flag, + int intra_mip_transposed_flag, int intra_mip_mode) +{ + return (intra_mip_mode << 2) | (intra_mip_transposed_flag << 1) | intra_mip_flag; +} + static void intra_luma_pred_modes(VVCLocalContext *lc) { VVCFrameContext *fc = lc->fc; @@ -976,9 +983,9 @@ static void intra_luma_pred_modes(VVCLocalContext *lc) int x = y_cb * pps->min_cb_width + x_cb; for (int y = 0; y < (cb_height>>log2_min_cb_size); y++) { int width = cb_width>>log2_min_cb_size; - memset(&fc->tab.imf[x], cu->intra_mip_flag, width); - fc->tab.imtf[x] = intra_mip_transposed_flag; - fc->tab.imm[x] = intra_mip_mode; + const uint8_t mip_info = pack_mip_info(cu->intra_mip_flag, + intra_mip_transposed_flag, intra_mip_mode); + memset(&fc->tab.imf[x], mip_info, width); x += pps->min_cb_width; } cu->intra_pred_mode_y = intra_mip_mode; @@ -1003,34 +1010,38 @@ static void intra_luma_pred_modes(VVCLocalContext *lc) static void intra_chroma_pred_modes(VVCLocalContext *lc) { - const VVCSPS *sps = lc->fc->ps.sps; - CodingUnit *cu = lc->cu; - const int hs = sps->hshift[CHROMA]; - const int vs = sps->vshift[CHROMA]; + const VVCSPS *sps = lc->fc->ps.sps; + CodingUnit *cu = lc->cu; + const int hs = sps->hshift[CHROMA]; + const int vs = sps->vshift[CHROMA]; + int cclm_mode_flag = 0; + int cclm_mode_idx = 0; + int intra_chroma_pred_mode = 0; - cu->mip_chroma_direct_flag = 0; - if (sps->r->sps_bdpcm_enabled_flag && - (cu->cb_width >> hs) <= sps->max_ts_size && - (cu->cb_height >> vs) <= sps->max_ts_size) { - cu->bdpcm_flag[CB] = cu->bdpcm_flag[CR] = ff_vvc_intra_bdpcm_chroma_flag(lc); + if (!cu->act_enabled_flag) { + cu->mip_chroma_direct_flag = 0; + if (sps->r->sps_bdpcm_enabled_flag && + (cu->cb_width >> hs) <= sps->max_ts_size && + (cu->cb_height >> vs) <= sps->max_ts_size) { + cu->bdpcm_flag[CB] = cu->bdpcm_flag[CR] = ff_vvc_intra_bdpcm_chroma_flag(lc); + } + if (cu->bdpcm_flag[CHROMA]) { + cu->intra_pred_mode_c = ff_vvc_intra_bdpcm_chroma_dir_flag(lc) ? INTRA_VERT : INTRA_HORZ; + } else { + const int cclm_enabled = get_cclm_enabled(lc, cu->x0, cu->y0); + + if (cclm_enabled) + cclm_mode_flag = ff_vvc_cclm_mode_flag(lc); + + if (cclm_mode_flag) + cclm_mode_idx = ff_vvc_cclm_mode_idx(lc); + else + intra_chroma_pred_mode = ff_vvc_intra_chroma_pred_mode(lc); + } } - if (cu->bdpcm_flag[CHROMA]) { - cu->intra_pred_mode_c = ff_vvc_intra_bdpcm_chroma_dir_flag(lc) ? INTRA_VERT : INTRA_HORZ; - } else { - const int cclm_enabled = get_cclm_enabled(lc, cu->x0, cu->y0); - int cclm_mode_flag = 0; - int cclm_mode_idx = 0; - int intra_chroma_pred_mode = 0; - if (cclm_enabled) - cclm_mode_flag = ff_vvc_cclm_mode_flag(lc); - - if (cclm_mode_flag) - cclm_mode_idx = ff_vvc_cclm_mode_idx(lc); - else - intra_chroma_pred_mode = ff_vvc_intra_chroma_pred_mode(lc); + if (!cu->bdpcm_flag[CHROMA]) derive_chroma_intra_pred_mode(lc, cclm_mode_flag, cclm_mode_idx, intra_chroma_pred_mode); - } } static PredMode pred_mode_decode(VVCLocalContext *lc, @@ -1043,13 +1054,15 @@ static PredMode pred_mode_decode(VVCLocalContext *lc, const H266RawSliceHeader *rsh = lc->sc->sh.r; const int ch_type = tree_type == DUAL_TREE_CHROMA ? 1 : 0; const int is_4x4 = cu->cb_width == 4 && cu->cb_height == 4; + const int is_128 = cu->cb_width == 128 || cu->cb_height == 128; + const int hs = sps->hshift[CHROMA]; + const int vs = sps->vshift[CHROMA]; int pred_mode_flag; int pred_mode_ibc_flag; PredMode pred_mode; cu->skip_flag = 0; if (!IS_I(rsh) || sps->r->sps_ibc_enabled_flag) { - const int is_128 = cu->cb_width == 128 || cu->cb_height == 128; if (tree_type != DUAL_TREE_CHROMA && ((!is_4x4 && mode_type != MODE_TYPE_INTRA) || (sps->r->sps_ibc_enabled_flag && !is_128))) { @@ -1084,6 +1097,14 @@ static PredMode pred_mode_decode(VVCLocalContext *lc, pred_mode = MODE_INTRA; } + if (pred_mode == MODE_INTRA && sps->r->sps_palette_enabled_flag && !is_128 && !cu->skip_flag && + mode_type != MODE_TYPE_INTER && ((cu->cb_width * cu->cb_height) > + (tree_type != DUAL_TREE_CHROMA ? 16 : (16 << hs << vs))) && + (mode_type != MODE_TYPE_INTRA || tree_type != DUAL_TREE_CHROMA)) { + if (ff_vvc_pred_mode_plt_flag(lc)) + pred_mode = MODE_PLT; + } + set_cb_tab(lc, fc->tab.cpm[cu->ch_type], pred_mode); if (tree_type == SINGLE_TREE) set_cb_tab(lc, fc->tab.cpm[CHROMA], pred_mode); @@ -1136,8 +1157,11 @@ static int skipped_transform_tree_unit(VVCLocalContext *lc) const CodingUnit *cu = lc->cu; int ret; - if (cu->tree_type != DUAL_TREE_CHROMA) - set_qp_y(lc, cu->x0, cu->y0, 0); + if (cu->tree_type != DUAL_TREE_CHROMA) { + ret = set_qp_y(lc, cu->x0, cu->y0, 0); + if (ret < 0) + return ret; + } if (rsps->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA) set_qp_c(lc); ret = skipped_transform_tree(lc, cu->x0, cu->y0, cu->cb_width, cu->cb_height); @@ -1180,7 +1204,7 @@ static CodingUnit* alloc_cu(VVCLocalContext *lc, const int x0, const int y0) const int rx = x0 >> sps->ctb_log2_size_y; const int ry = y0 >> sps->ctb_log2_size_y; CodingUnit **cus = fc->tab.cus + ry * pps->ctb_width + rx; - CodingUnit *cu = ff_refstruct_pool_get(fc->cu_pool); + CodingUnit *cu = av_refstruct_pool_get(fc->cu_pool); if (!cu) return NULL; @@ -1240,16 +1264,18 @@ static void set_cu_tabs(const VVCLocalContext *lc, const CodingUnit *cu) set_cb_tab(lc, fc->tab.mmi, pu->mi.motion_model_idc); set_cb_tab(lc, fc->tab.msf, pu->merge_subblock_flag); - if (cu->tree_type != DUAL_TREE_CHROMA) + if (cu->tree_type != DUAL_TREE_CHROMA) { set_cb_tab(lc, fc->tab.skip, cu->skip_flag); + set_cb_tab(lc, fc->tab.pcmf[LUMA], cu->bdpcm_flag[LUMA]); + } + if (cu->tree_type != DUAL_TREE_LUMA) + set_cb_tab(lc, fc->tab.pcmf[CHROMA], cu->bdpcm_flag[CHROMA]); while (tu) { for (int j = 0; j < tu->nb_tbs; j++) { const TransformBlock *tb = tu->tbs + j; if (tb->c_idx != LUMA) set_qp_c_tab(lc, tu, tb); - if (tb->c_idx != CR && cu->bdpcm_flag[tb->c_idx]) - set_tb_tab(fc->tab.pcmf[tb->c_idx], 1, fc, tb); } tu = tu->next; } @@ -1493,7 +1519,7 @@ static int hls_merge_data(VVCLocalContext *lc) static void hls_mvd_coding(VVCLocalContext *lc, Mv* mvd) { - int16_t mv[2]; + int32_t mv[2]; for (int i = 0; i < 2; i++) { mv[i] = ff_vvc_abs_mvd_greater0_flag(lc); @@ -1750,8 +1776,8 @@ static void fill_dmvr_info(const VVCLocalContext *lc) const VVCFrameContext *fc = lc->fc; const CodingUnit *cu = lc->cu; - if (cu->pred_mode == MODE_IBC) { - ff_vvc_set_intra_mvf(lc, 1); + if (cu->pred_mode == MODE_IBC || cu->pred_mode == MODE_PLT) { + ff_vvc_set_intra_mvf(lc, true, cu->pred_mode == MODE_IBC ? PF_IBC : PF_PLT, false); } else { const VVCPPS *pps = fc->ps.pps; const int w = cu->cb_width >> MIN_PU_LOG2; @@ -1778,15 +1804,17 @@ static int inter_data(VVCLocalContext *lc) pu->general_merge_flag = ff_vvc_general_merge_flag(lc); if (pu->general_merge_flag) { - hls_merge_data(lc); - } else if (cu->pred_mode == MODE_IBC){ + ret = hls_merge_data(lc); + } else if (cu->pred_mode == MODE_IBC) { ret = mvp_data_ibc(lc); } else { ret = mvp_data(lc); } - if (cu->pred_mode == MODE_IBC) - { + if (ret) + return ret; + + if (cu->pred_mode == MODE_IBC) { ff_vvc_update_hmvp(lc, mi); } else if (!pu->merge_gpm_flag && !pu->inter_affine_flag && !pu->merge_subblock_flag) { refine_regular_subblock(lc); @@ -1798,17 +1826,364 @@ static int inter_data(VVCLocalContext *lc) return ret; } +static TransformUnit* palette_add_tu(VVCLocalContext *lc, const int start, const int end, const VVCTreeType tree_type) +{ + CodingUnit *cu = lc->cu; + const VVCSPS *sps = lc->fc->ps.sps; + TransformUnit *tu = add_tu(lc->fc, cu, cu->x0, cu->y0, cu->cb_width, cu->cb_height); + + if (!tu) + return NULL; + + for (int c = start; c < end; c++) { + const int w = tu->width >> sps->hshift[c]; + const int h = tu->height >> sps->vshift[c]; + TransformBlock *tb = add_tb(tu, lc, tu->x0, tu->y0, w, h, c); + if (c != CR) + set_tb_size(lc->fc, tb); + } + + for (int i = 0; i < FF_ARRAY_ELEMS(cu->plt); i++) + cu->plt[i].size = 0; + + return tu; +} + +static int palette_predicted(VVCLocalContext *lc, const bool local_dual_tree, int start, int end, + bool *predictor_reused, const int predictor_size, const int max_entries) +{ + CodingUnit *cu = lc->cu; + int nb_predicted = 0; + + if (local_dual_tree) { + start = LUMA; + end = VVC_MAX_SAMPLE_ARRAYS; + } + + for (int i = 0; i < predictor_size && nb_predicted < max_entries; i++) { + const int run = ff_vvc_palette_predictor_run(lc, predictor_size - i); + if (run < 0) + return run; + + if (run == 1) + break; + + if (run > 1) + i += run - 1; + + predictor_reused[i] = true; + for (int c = start; c < end; c++) + cu->plt[c].entries[nb_predicted] = lc->ep->pp[c].entries[i]; + nb_predicted++; + } + + for (int c = start; c < end; c++) + cu->plt[c].size = nb_predicted; + + return 0; +} + +static int palette_signaled(VVCLocalContext *lc, const bool local_dual_tree, + const int start, const int end, const int max_entries) +{ + const VVCSPS *sps = lc->fc->ps.sps; + CodingUnit *cu = lc->cu; + const int nb_predicted = cu->plt[start].size; + const int nb_signaled = nb_predicted < max_entries ? ff_vvc_num_signalled_palette_entries(lc, max_entries - nb_predicted) : 0; + const int size = nb_predicted + nb_signaled; + const bool dual_tree_luma = local_dual_tree && cu->tree_type == DUAL_TREE_LUMA; + + if (nb_signaled < 0) + return AVERROR_INVALIDDATA; + + for (int c = start; c < end; c++) { + Palette *plt = cu->plt + c; + for (int i = nb_predicted; i < size; i++) { + plt->entries[i] = ff_vvc_new_palette_entries(lc, sps->bit_depth); + if (dual_tree_luma) { + plt[CB].entries[i] = 1 << (sps->bit_depth - 1); + plt[CR].entries[i] = 1 << (sps->bit_depth - 1); + } + } + plt->size = size; + } + + return 0; +} + +static void palette_update_predictor(VVCLocalContext *lc, const bool local_dual_tree, int start, int end, + bool *predictor_reused, const int predictor_size) +{ + CodingUnit *cu = lc->cu; + const int max_predictor = VVC_MAX_NUM_PALETTE_PREDICTOR_SIZE >> (cu->tree_type != SINGLE_TREE && !local_dual_tree); + + if (local_dual_tree) { + start = LUMA; + end = VVC_MAX_SAMPLE_ARRAYS; + } + + for (int c = start; c < end; c++) { + Palette *pp = lc->ep->pp + c; + Palette *plt = cu->plt + c; + int i = cu->plt[start].size;; + + // copy unused predictors to the end of plt + for (int j = 0; j < predictor_size && i < max_predictor; j++) { + if (!predictor_reused[j]) { + plt->entries[i] = pp->entries[j]; + i++; + } + } + + memcpy(pp->entries, plt->entries, i * sizeof(pp->entries[0])); + pp->size = i; + } +} + +static int palette_qp(VVCLocalContext *lc, VVCTreeType tree_type, const bool escape_present) +{ + const VVCFrameContext *fc = lc->fc; + const VVCPPS *pps = fc->ps.pps; + const H266RawSliceHeader *rsh = lc->sc->sh.r; + const CodingUnit *cu = lc->cu; + int ret; + + if (tree_type != DUAL_TREE_CHROMA) { + const bool has_qp_delta = escape_present && + pps->r->pps_cu_qp_delta_enabled_flag && !lc->parse.is_cu_qp_delta_coded; + ret = set_qp_y(lc, cu->x0, cu->y0, has_qp_delta); + if (ret < 0) + return ret; + } + + if (tree_type != DUAL_TREE_LUMA) { + if (rsh->sh_cu_chroma_qp_offset_enabled_flag && !lc->parse.is_cu_chroma_qp_offset_coded) + chroma_qp_offset_decode(lc, 0, 1); + set_qp_c(lc); + } + + return 0; +} + +#define PALETTE_SET_PIXEL(xc, yc, pix) \ + do { \ + const int off = ((xc) >> hs) + ((yc) >> vs) * tb->tb_width; \ + if (sps->bit_depth == 8) \ + u8[off] = pix; \ + else \ + u16[off] = pix; \ + } while (0) + +#define PALETTE_INDEX(x, y) index[(y) * width + (x)] + +// 6.5.3 Horizontal and vertical traverse scan order array initialization process +// The hTravScan and vTravScan tables require approximately 576 KB of memory. +// To save space, we use a macro to achieve the same functionality. +#define TRAV_COL(p, wlog, mask) ((p & mask) ^ (-((p >> wlog) & 1) & mask)) +#define TRAV_ROW(p, hlog) (p >> hlog) +#define TRAV(trans, p, wlog, hlog, mask) (trans ? TRAV_ROW((p), hlog) : TRAV_COL((p), wlog, mask)) +#define TRAV_X(pos) TRAV(transpose, pos, wlog2, hlog2, wmask) +#define TRAV_Y(pos) TRAV(!transpose, pos, hlog2, wlog2, hmask) + +static int palette_subblock_data(VVCLocalContext *lc, + const int max_index, const int subset_id, const bool transpose, + uint8_t *run_type, uint8_t *index, int *prev_run_pos, bool *adjust) +{ + const CodingUnit *cu = lc->cu; + TransformUnit *tu = cu->tus.head; + const VVCSPS *sps = lc->fc->ps.sps; + const int width = tu->tbs[0].tb_width; + const int height = tu->tbs[0].tb_height; + const int min_pos = subset_id << 4; + const int max_pos = FFMIN(min_pos + 16, width * height); + const int wmask = width - 1; + const int hmask = height - 1; + const int wlog2 = av_log2(width); + const int hlog2 = av_log2(height); + const int start_idx = tu->tbs[0].c_idx; + const uint8_t esc = cu->plt[tu->tbs[0].c_idx].size; + uint8_t run_copy[16] = { 0 }; + + for (int i = min_pos; i < max_pos; i++) { + const int xc = TRAV_X(i); + const int yc = TRAV_Y(i); + + if (i > 0 && max_index > 0) + run_copy[i - min_pos] = ff_vvc_run_copy_flag(lc, run_type[i - 1], *prev_run_pos, i); + + run_type[i] = 0; + if (max_index > 0 && !run_copy[i - min_pos]) { + if (((!transpose && yc > 0) || (transpose && xc > 0)) + && i > 0 && !run_type[i - 1]) { + run_type[i] = ff_vvc_copy_above_palette_indices_flag(lc); + } + *prev_run_pos = i; + } else if (i > 0) { + run_type[i] = run_type[i - 1]; + } + } + + for (int i = min_pos; i < max_pos; i++) { + const int xc = TRAV_X(i); + const int yc = TRAV_Y(i); + const int prev_xc = i > 0 ? TRAV_X(i - 1) : 0; + const int prev_yc = i > 0 ? TRAV_Y(i - 1) : 0; + + int idx = 0; + if (max_index > 0 && !run_copy[i - min_pos] && !run_type[i]) { + if (max_index - *adjust > 0) + idx = ff_vvc_palette_idx_idc(lc, max_index, *adjust); + if (i > 0) { + const int ref_idx = !run_type[i - 1] ? + PALETTE_INDEX(prev_xc, prev_yc) : PALETTE_INDEX(xc - transpose, yc - !transpose); + idx += (idx >= ref_idx); + } + *adjust = true; + } else { + idx = PALETTE_INDEX(prev_xc, prev_yc); + } + + if (!run_type[i]) + PALETTE_INDEX(xc, yc) = idx; + else + PALETTE_INDEX(xc, yc) = PALETTE_INDEX(xc - transpose, yc - !transpose); + } + + for (int c = 0; c < tu->nb_tbs; c++) { + TransformBlock *tb = &tu->tbs[c]; + const int c_idx = tb->c_idx; + const Palette *plt = &cu->plt[c_idx]; + const int scale = ff_vvc_palette_derive_scale(lc, tu, tb); + const int hs = sps->hshift[c_idx] - sps->hshift[start_idx]; + const int vs = sps->vshift[c_idx] - sps->vshift[start_idx]; + uint8_t *u8 = (uint8_t *)tb->coeffs; + uint16_t *u16 = (uint16_t *)tb->coeffs; + + for (int i = min_pos; i < max_pos; i++) { + const int xc = TRAV_X(i); + const int yc = TRAV_Y(i); + if (!(xc & hs) && !(yc & vs)) { + const int v = PALETTE_INDEX(xc, yc); + if (v == esc) { + const int coeff = ff_vvc_palette_escape_val(lc, (1 << sps->bit_depth) - 1); + if (coeff < 0) + return AVERROR_INVALIDDATA; + const int pixel = av_clip_intp2(RSHIFT(coeff * scale, 6), sps->bit_depth); + PALETTE_SET_PIXEL(xc, yc, pixel); + } else { + PALETTE_SET_PIXEL(xc, yc, plt->entries[v]); + } + } + } + } + + return 0; +} + +static int hls_palette_coding(VVCLocalContext *lc, const VVCTreeType tree_type) +{ + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const H266RawSliceHeader *rsh = lc->sc->sh.r; + CodingUnit *cu = lc->cu; + Palette *pp = lc->ep->pp; + const int max_entries = tree_type == SINGLE_TREE ? 31 : 15; + const bool local_dual_tree = tree_type != SINGLE_TREE && + (!IS_I(rsh) || (IS_I(rsh) && !sps->r->sps_qtbtt_dual_tree_intra_flag)); + bool escape_present = false; + bool transpose = false; + bool adjust = false; + int max_index = 0; + int prev_run_pos = 0; + + int predictor_size, start, end, ret; + bool reused[VVC_MAX_NUM_PALETTE_PREDICTOR_SIZE]; + uint8_t run_type[MAX_PALETTE_CU_SIZE * MAX_PALETTE_CU_SIZE]; + uint8_t index[MAX_PALETTE_CU_SIZE * MAX_PALETTE_CU_SIZE]; + + TransformUnit *tu; + + ff_vvc_channel_range(&start, &end, tree_type, sps->r->sps_chroma_format_idc); + + tu = palette_add_tu(lc, start, end, tree_type); + if (!tu) + return AVERROR(ENOMEM); + + predictor_size = pp[start].size; + memset(reused, 0, sizeof(reused[0]) * predictor_size); + + ret = palette_predicted(lc, local_dual_tree, start, end, reused, predictor_size, max_entries); + if (ret < 0) + return ret; + + ret = palette_signaled(lc, local_dual_tree, start, end, max_entries); + if (ret < 0) + return ret; + + palette_update_predictor(lc, local_dual_tree, start, end, reused, predictor_size); + + if (cu->plt[start].size > 0) + escape_present = ff_vvc_palette_escape_val_present_flag(lc); + + max_index = cu->plt[start].size - 1 + escape_present; + if (max_index > 0) { + adjust = false; + transpose = ff_vvc_palette_transpose_flag(lc); + } + + ret = palette_qp(lc, tree_type, escape_present); + if (ret < 0) + return ret; + + index[0] = 0; + for (int i = 0; i <= (tu->tbs[0].tb_width * tu->tbs[0].tb_height - 1) >> 4; i++) { + ret = palette_subblock_data(lc, max_index, i, transpose, + run_type, index, &prev_run_pos, &adjust); + if (ret < 0) + return ret; + } + + return 0; +} + +static int intra_data(VVCLocalContext *lc) +{ + const VVCSPS *sps = lc->fc->ps.sps; + const CodingUnit *cu = lc->cu; + const VVCTreeType tree_type = cu->tree_type; + const bool pred_mode_plt_flag = cu->pred_mode == MODE_PLT; + int ret = 0; + + if (tree_type == SINGLE_TREE || tree_type == DUAL_TREE_LUMA) { + if (pred_mode_plt_flag) { + if ((ret = hls_palette_coding(lc, tree_type)) < 0) + return ret; + ff_vvc_set_intra_mvf(lc, false, PF_PLT, false); + } else { + intra_luma_pred_modes(lc); + ff_vvc_set_intra_mvf(lc, false, PF_INTRA, cu->ciip_flag); + } + } + if ((tree_type == SINGLE_TREE || tree_type == DUAL_TREE_CHROMA) && sps->r->sps_chroma_format_idc) { + if (pred_mode_plt_flag && tree_type == DUAL_TREE_CHROMA) { + if ((ret = hls_palette_coding(lc, tree_type)) < 0) + return ret; + } else if (!pred_mode_plt_flag) { + intra_chroma_pred_modes(lc); + } + } + + return ret; +} + static int hls_coding_unit(VVCLocalContext *lc, int x0, int y0, int cb_width, int cb_height, int cqt_depth, const VVCTreeType tree_type, VVCModeType mode_type) { - const VVCFrameContext *fc = lc->fc; - const VVCSPS *sps = fc->ps.sps; - const H266RawSliceHeader *rsh = lc->sc->sh.r; - const int hs = sps->hshift[CHROMA]; - const int vs = sps->vshift[CHROMA]; - const int is_128 = cb_width > 64 || cb_height > 64; - int pred_mode_plt_flag = 0; - int ret; + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const H266RawSliceHeader *rsh = lc->sc->sh.r; + const int is_128 = cb_width > 64 || cb_height > 64; + int ret = 0; CodingUnit *cu = add_cu(lc, x0, y0, cb_width, cb_height, cqt_depth, tree_type); @@ -1821,54 +2196,26 @@ static int hls_coding_unit(VVCLocalContext *lc, int x0, int y0, int cb_width, in mode_type = MODE_TYPE_INTRA; cu->pred_mode = pred_mode_decode(lc, tree_type, mode_type); - if (cu->pred_mode == MODE_INTRA && sps->r->sps_palette_enabled_flag && !is_128 && !cu->skip_flag && - mode_type != MODE_TYPE_INTER && ((cb_width * cb_height) > - (tree_type != DUAL_TREE_CHROMA ? 16 : (16 << hs << vs))) && - (mode_type != MODE_TYPE_INTRA || tree_type != DUAL_TREE_CHROMA)) { - pred_mode_plt_flag = ff_vvc_pred_mode_plt_flag(lc); - if (pred_mode_plt_flag) { - avpriv_report_missing_feature(fc->log_ctx, "Palette"); - return AVERROR_PATCHWELCOME; - } - } - if (cu->pred_mode == MODE_INTRA && sps->r->sps_act_enabled_flag && tree_type == SINGLE_TREE) { - avpriv_report_missing_feature(fc->log_ctx, "Adaptive Color Transform"); - return AVERROR_PATCHWELCOME; - } - if (cu->pred_mode == MODE_INTRA || cu->pred_mode == MODE_PLT) { - if (tree_type == SINGLE_TREE || tree_type == DUAL_TREE_LUMA) { - if (pred_mode_plt_flag) { - avpriv_report_missing_feature(fc->log_ctx, "Palette"); - return AVERROR_PATCHWELCOME; - } else { - intra_luma_pred_modes(lc); - } - ff_vvc_set_intra_mvf(lc, 0); - } - if ((tree_type == SINGLE_TREE || tree_type == DUAL_TREE_CHROMA) && sps->r->sps_chroma_format_idc) { - if (pred_mode_plt_flag && tree_type == DUAL_TREE_CHROMA) { - avpriv_report_missing_feature(fc->log_ctx, "Palette"); - return AVERROR_PATCHWELCOME; - } else if (!pred_mode_plt_flag) { - if (!cu->act_enabled_flag) - intra_chroma_pred_modes(lc); - } - } - } else if (tree_type != DUAL_TREE_CHROMA) { /* MODE_INTER or MODE_IBC */ - if ((ret = inter_data(lc)) < 0) - return ret; - } - if (cu->pred_mode != MODE_INTRA && !pred_mode_plt_flag && !lc->cu->pu.general_merge_flag) + if (cu->pred_mode == MODE_INTRA && sps->r->sps_act_enabled_flag && tree_type == SINGLE_TREE) + cu->act_enabled_flag = ff_vvc_cu_act_enabled_flag(lc); + + if (cu->pred_mode == MODE_INTRA || cu->pred_mode == MODE_PLT) + ret = intra_data(lc); + else if (tree_type != DUAL_TREE_CHROMA) /* MODE_INTER or MODE_IBC */ + ret = inter_data(lc); + + if (ret < 0) + return ret; + + if (cu->pred_mode != MODE_INTRA && cu->pred_mode != MODE_PLT && !lc->cu->pu.general_merge_flag) cu->coded_flag = ff_vvc_cu_coded_flag(lc); else - cu->coded_flag = !(cu->skip_flag || pred_mode_plt_flag); + cu->coded_flag = !(cu->skip_flag || cu->pred_mode == MODE_PLT); if (cu->coded_flag) { sbt_info(lc, sps); - if (sps->r->sps_act_enabled_flag && cu->pred_mode != MODE_INTRA && tree_type == SINGLE_TREE) { - avpriv_report_missing_feature(fc->log_ctx, "Adaptive Color Transform"); - return AVERROR_PATCHWELCOME; - } + if (sps->r->sps_act_enabled_flag && cu->pred_mode != MODE_INTRA && tree_type == SINGLE_TREE) + cu->act_enabled_flag = ff_vvc_cu_act_enabled_flag(lc); lc->parse.lfnst_dc_only = 1; lc->parse.lfnst_zero_out_sig_coeff_flag = 1; lc->parse.mts_dc_only = 1; @@ -1879,7 +2226,7 @@ static int hls_coding_unit(VVCLocalContext *lc, int x0, int y0, int cb_width, in cu->lfnst_idx = lfnst_idx_decode(lc); cu->mts_idx = mts_idx_decode(lc); set_qp_c(lc); - } else { + } else if (cu->pred_mode != MODE_PLT) { ret = skipped_transform_tree_unit(lc); if (ret < 0) return ret; @@ -2286,6 +2633,7 @@ static void alf_params(VVCLocalContext *lc, const int rx, const int ry) ALFParams *alf = &CTB(fc->tab.alf, rx, ry); alf->ctb_flag[LUMA] = alf->ctb_flag[CB] = alf->ctb_flag[CR] = 0; + alf->ctb_cc_idc[0] = alf->ctb_cc_idc[1] = 0; if (sh->sh_alf_enabled_flag) { alf->ctb_flag[LUMA] = ff_vvc_alf_ctb_flag(lc, rx, ry, LUMA); if (alf->ctb_flag[LUMA]) { @@ -2316,7 +2664,6 @@ static void alf_params(VVCLocalContext *lc, const int rx, const int ry) const uint8_t cc_enabled[] = { sh->sh_alf_cc_cb_enabled_flag, sh->sh_alf_cc_cr_enabled_flag }; const uint8_t cc_aps_id[] = { sh->sh_alf_cc_cb_aps_id, sh->sh_alf_cc_cr_aps_id }; for (int i = 0; i < 2; i++) { - alf->ctb_cc_idc[i] = 0; if (cc_enabled[i]) { const VVCALF *aps = fc->ps.alf_list[cc_aps_id[i]]; alf->ctb_cc_idc[i] = ff_vvc_alf_ctb_cc_idc(lc, rx, ry, i, aps->num_cc_filters[i]); @@ -2385,13 +2732,19 @@ static int has_inter_luma(const CodingUnit *cu) return cu->pred_mode != MODE_INTRA && cu->pred_mode != MODE_PLT && cu->tree_type != DUAL_TREE_CHROMA; } -static int pred_get_y(const int y0, const Mv *mv, const int height) +static int pred_get_y(const VVCLocalContext *lc, const int y0, const Mv *mv, const int height) { - return FFMAX(0, y0 + (mv->y >> 4) + height); + const VVCPPS *pps = lc->fc->ps.pps; + const int idx = lc->sc->sh.r->curr_subpic_idx; + const int top = pps->subpic_y[idx]; + const int bottom = top + pps->subpic_height[idx]; + + return av_clip(y0 + (mv->y >> 4) + height, top, bottom); } -static void cu_get_max_y(const CodingUnit *cu, int max_y[2][VVC_MAX_REF_ENTRIES], const VVCFrameContext *fc) +static void cu_get_max_y(const CodingUnit *cu, int max_y[2][VVC_MAX_REF_ENTRIES], const VVCLocalContext *lc) { + const VVCFrameContext *fc = lc->fc; const PredictionUnit *pu = &cu->pu; if (pu->merge_gpm_flag) { @@ -2399,7 +2752,7 @@ static void cu_get_max_y(const CodingUnit *cu, int max_y[2][VVC_MAX_REF_ENTRIES] const MvField *mvf = pu->gpm_mv + i; const int lx = mvf->pred_flag - PF_L0; const int idx = mvf->ref_idx[lx]; - const int y = pred_get_y(cu->y0, mvf->mv + lx, cu->cb_height); + const int y = pred_get_y(lc, cu->y0, mvf->mv + lx, cu->cb_height); max_y[lx][idx] = FFMAX(max_y[lx][idx], y); } @@ -2417,7 +2770,7 @@ static void cu_get_max_y(const CodingUnit *cu, int max_y[2][VVC_MAX_REF_ENTRIES] const PredFlag mask = 1 << lx; if (mvf->pred_flag & mask) { const int idx = mvf->ref_idx[lx]; - const int y = pred_get_y(y0, mvf->mv + lx, sbh); + const int y = pred_get_y(lc, y0, mvf->mv + lx, sbh); max_y[lx][idx] = FFMAX(max_y[lx][idx], y + max_dmvr_off); } @@ -2444,7 +2797,7 @@ static void ctu_get_pred(VVCLocalContext *lc, const int rs) while (cu) { if (has_inter_luma(cu)) { - cu_get_max_y(cu, ctu->max_y, fc); + cu_get_max_y(cu, ctu->max_y, lc); ctu->has_dmvr |= cu->pu.dmvr_flag; } cu = cu->next; @@ -2542,11 +2895,11 @@ void ff_vvc_ctu_free_cus(CodingUnit **cus) while (*head) { TransformUnit *tu = *head; *head = tu->next; - ff_refstruct_unref(&tu); + av_refstruct_unref(&tu); } cu->tus.tail = NULL; - ff_refstruct_unref(&cu); + av_refstruct_unref(&cu); } } @@ -2566,3 +2919,12 @@ void ff_vvc_ep_init_stat_coeff(EntryPoint *ep, persistent_rice_adaptation_enabled_flag ? 2 * (av_log2(bit_depth - 10)) : 0; } } + +void ff_vvc_channel_range(int *start, int *end, const VVCTreeType tree_type, const uint8_t chroma_format_idc) +{ + const bool has_chroma = chroma_format_idc && tree_type != DUAL_TREE_LUMA; + const bool has_luma = tree_type != DUAL_TREE_CHROMA; + + *start = has_luma ? LUMA : CB; + *end = has_chroma ? VVC_MAX_SAMPLE_ARRAYS : CB; +} diff --git a/libavcodec/vvc/ctu.h b/libavcodec/vvc/ctu.h index eab461256..e37bacf9d 100644 --- a/libavcodec/vvc/ctu.h +++ b/libavcodec/vvc/ctu.h @@ -23,6 +23,8 @@ #ifndef AVCODEC_VVC_CTU_H #define AVCODEC_VVC_CTU_H +#include + #include "libavcodec/cabac.h" #include "libavutil/mem_internal.h" @@ -34,6 +36,7 @@ #define MIN_CU_SIZE 4 #define MIN_CU_LOG2 2 #define MAX_CU_DEPTH 7 +#define MAX_PALETTE_CU_SIZE 64 #define MAX_PARTS_IN_CTU ((MAX_CTU_SIZE >> MIN_CU_LOG2) * (MAX_CTU_SIZE >> MIN_CU_LOG2)) @@ -172,6 +175,7 @@ typedef struct TransformUnit { int y0; int width; int height; + bool avail[CHROMA + 1]; // contains luma/chroma block uint8_t joint_cbcr_residual_flag; ///< tu_joint_cbcr_residual_flag @@ -221,6 +225,7 @@ typedef enum PredFlag { PF_L1 = 0x2, PF_BI = 0x3, PF_IBC = PF_L0 | 0x4, + PF_PLT = 0x8, } PredFlag; typedef enum IntraPredMode { @@ -274,6 +279,11 @@ typedef struct PredictionUnit { int cb_prof_flag[2]; } PredictionUnit; +typedef struct Palette { + uint8_t size; + uint16_t entries[VVC_MAX_NUM_PALETTE_PREDICTOR_SIZE]; +} Palette; + typedef struct CodingUnit { VVCTreeType tree_type; int x0; @@ -323,6 +333,8 @@ typedef struct CodingUnit { int8_t qp[4]; ///< QpY, Qp′Cb, Qp′Cr, Qp′CbCr + Palette plt[VVC_MAX_SAMPLE_ARRAYS]; + PredictionUnit pu; struct CodingUnit *next; ///< RefStruct reference @@ -353,6 +365,8 @@ typedef struct EntryPoint { int stat_coeff[VVC_MAX_SAMPLE_ARRAYS]; ///< StatCoeff + Palette pp[VVC_MAX_SAMPLE_ARRAYS]; // PalettePredictor + VVCCabacState cabac_state[VVC_CONTEXTS]; CABACContext cc; @@ -486,5 +500,6 @@ void ff_vvc_decode_neighbour(VVCLocalContext *lc, int x_ctb, int y_ctb, int rx, void ff_vvc_ctu_free_cus(CodingUnit **cus); int ff_vvc_get_qPy(const VVCFrameContext *fc, int xc, int yc); void ff_vvc_ep_init_stat_coeff(EntryPoint *ep, int bit_depth, int persistent_rice_adaptation_enabled_flag); +void ff_vvc_channel_range(int *start, int *end, VVCTreeType tree_type, uint8_t chroma_format_idc); #endif // AVCODEC_VVC_CTU_H diff --git a/libavcodec/vvc/data.h b/libavcodec/vvc/data.h index a0512e626..a28150484 100644 --- a/libavcodec/vvc/data.h +++ b/libavcodec/vvc/data.h @@ -23,6 +23,9 @@ #include +#include "libavutil/attributes_internal.h" + +FF_VISIBILITY_PUSH_HIDDEN extern const uint8_t ff_vvc_diag_scan_x[5][5][16 * 16]; extern const uint8_t ff_vvc_diag_scan_y[5][5][16 * 16]; @@ -80,5 +83,6 @@ extern const uint8_t ff_vvc_alf_class_to_filt_map[16][25]; extern const uint8_t ff_vvc_alf_aps_class_to_filt_map[25]; const uint8_t* ff_vvc_get_mip_matrix(const int size_id, const int mode_idx); +FF_VISIBILITY_POP_HIDDEN #endif /* AVCODEC_VVC_DATA_H */ diff --git a/libavcodec/vvc/dec.c b/libavcodec/vvc/dec.c index edf2607f5..194e2fc7e 100644 --- a/libavcodec/vvc/dec.c +++ b/libavcodec/vvc/dec.c @@ -20,19 +20,27 @@ * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "libavcodec/bytestream.h" #include "libavcodec/codec_internal.h" #include "libavcodec/decode.h" +#include "libavcodec/hwaccel_internal.h" +#include "libavcodec/hwconfig.h" #include "libavcodec/profiles.h" -#include "libavcodec/refstruct.h" +#include "libavutil/refstruct.h" +#include "libavcodec/aom_film_grain.h" +#include "libavcodec/thread.h" #include "libavutil/cpu.h" #include "libavutil/mem.h" #include "libavutil/thread.h" +#include "libavutil/film_grain_params.h" #include "dec.h" #include "ctu.h" #include "data.h" #include "refs.h" #include "thread.h" +#include "config_components.h" #define TAB_MAX 32 @@ -125,7 +133,6 @@ static void min_cb_tl_init(TabList *l, VVCFrameContext *fc) tl_init(l, 1, changed); TL_ADD(imf, pic_size_in_min_cb); - TL_ADD(imm, pic_size_in_min_cb); for (int i = LUMA; i <= CHROMA; i++) TL_ADD(cb_width[i], pic_size_in_min_cb); //is_a0_available requires this @@ -140,7 +147,6 @@ static void min_cb_nz_tl_init(TabList *l, VVCFrameContext *fc) tl_init(l, 0, changed); TL_ADD(skip, pic_size_in_min_cb); - TL_ADD(imtf, pic_size_in_min_cb); TL_ADD(ipm, pic_size_in_min_cb); for (int i = LUMA; i <= CHROMA; i++) { @@ -150,6 +156,7 @@ static void min_cb_nz_tl_init(TabList *l, VVCFrameContext *fc) TL_ADD(cb_height[i], pic_size_in_min_cb); TL_ADD(cp_mv[i], pic_size_in_min_cb * MAX_CONTROL_POINTS); TL_ADD(cpm[i], pic_size_in_min_cb); + TL_ADD(pcmf[i], pic_size_in_min_cb); } // For luma, qp can only change at the CU level, so the qp tab size is related to the CU. TL_ADD(qp[LUMA], pic_size_in_min_cb); @@ -189,9 +196,6 @@ static void min_tu_tl_init(TabList *l, VVCFrameContext *fc) TL_ADD(tu_joint_cbcr_residual_flag, pic_size_in_min_tu); - for (int i = LUMA; i <= CHROMA; i++) - TL_ADD(pcmf[i], pic_size_in_min_tu); - for (int i = 0; i < VVC_MAX_SAMPLE_ARRAYS; i++) { TL_ADD(tu_coded_flag[i], pic_size_in_min_tu); @@ -209,8 +213,6 @@ static void min_tu_nz_tl_init(TabList *l, VVCFrameContext *fc) tl_init(l, 0, changed); for (int i = LUMA; i <= CHROMA; i++) { - TL_ADD(tb_pos_x0[i], pic_size_in_min_tu); - TL_ADD(tb_pos_y0[i], pic_size_in_min_tu); TL_ADD(tb_width[i], pic_size_in_min_tu); TL_ADD(tb_height[i], pic_size_in_min_tu); } @@ -355,8 +357,8 @@ static void pic_arrays_free(VVCFrameContext *fc) { free_cus(fc); frame_context_for_each_tl(fc, tl_free); - ff_refstruct_pool_uninit(&fc->rpl_tab_pool); - ff_refstruct_pool_uninit(&fc->tab_dmvr_mvf_pool); + av_refstruct_pool_uninit(&fc->rpl_tab_pool); + av_refstruct_pool_uninit(&fc->tab_dmvr_mvf_pool); memset(&fc->tab.sz, 0, sizeof(fc->tab.sz)); } @@ -381,16 +383,16 @@ static int pic_arrays_init(VVCContext *s, VVCFrameContext *fc) memset(fc->tab.slice_idx, -1, sizeof(*fc->tab.slice_idx) * ctu_count); if (fc->tab.sz.ctu_count != ctu_count) { - ff_refstruct_pool_uninit(&fc->rpl_tab_pool); - fc->rpl_tab_pool = ff_refstruct_pool_alloc(ctu_count * sizeof(RefPicListTab), 0); + av_refstruct_pool_uninit(&fc->rpl_tab_pool); + fc->rpl_tab_pool = av_refstruct_pool_alloc(ctu_count * sizeof(RefPicListTab), 0); if (!fc->rpl_tab_pool) return AVERROR(ENOMEM); } if (fc->tab.sz.pic_size_in_min_pu != pic_size_in_min_pu) { - ff_refstruct_pool_uninit(&fc->tab_dmvr_mvf_pool); - fc->tab_dmvr_mvf_pool = ff_refstruct_pool_alloc( - pic_size_in_min_pu * sizeof(MvField), FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); + av_refstruct_pool_uninit(&fc->tab_dmvr_mvf_pool); + fc->tab_dmvr_mvf_pool = av_refstruct_pool_alloc( + pic_size_in_min_pu * sizeof(MvField), AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); if (!fc->tab_dmvr_mvf_pool) return AVERROR(ENOMEM); } @@ -471,8 +473,8 @@ static void slices_free(VVCFrameContext *fc) for (int i = 0; i < fc->nb_slices_allocated; i++) { SliceContext *slice = fc->slices[i]; if (slice) { - ff_refstruct_unref(&slice->ref); - ff_refstruct_unref(&slice->sh.r); + av_refstruct_unref(&slice->ref); + av_refstruct_unref(&slice->sh.r); eps_free(slice); av_free(slice); } @@ -509,36 +511,56 @@ static int slices_realloc(VVCFrameContext *fc) return 0; } -static int ep_init_cabac_decoder(SliceContext *sc, const int index, - const H2645NAL *nal, GetBitContext *gb, const CodedBitstreamUnit *unit) +static int get_ep_size(const H266RawSliceHeader *rsh, const GetByteContext *gb, + const H2645NAL *nal, const int header_size, const int ep_index) { - const H266RawSlice *slice = unit->content_ref; - const H266RawSliceHeader *rsh = sc->sh.r; - EntryPoint *ep = sc->eps + index; int size; - int ret; - if (index < rsh->num_entry_points) { + if (ep_index < rsh->num_entry_points) { int skipped = 0; - int64_t start = (gb->index >> 3); - int64_t end = start + rsh->sh_entry_point_offset_minus1[index] + 1; - while (skipped < nal->skipped_bytes && nal->skipped_bytes_pos[skipped] <= start + slice->header_size) { + int64_t start = bytestream2_tell(gb); + int64_t end = start + rsh->sh_entry_point_offset_minus1[ep_index] + 1; + while (skipped < nal->skipped_bytes && nal->skipped_bytes_pos[skipped] <= start + header_size) { skipped++; } - while (skipped < nal->skipped_bytes && nal->skipped_bytes_pos[skipped] <= end + slice->header_size) { + while (skipped < nal->skipped_bytes && nal->skipped_bytes_pos[skipped] <= end + header_size) { end--; skipped++; } size = end - start; - size = av_clip(size, 0, get_bits_left(gb) / 8); + size = av_clip(size, 0, bytestream2_get_bytes_left(gb)); } else { - size = get_bits_left(gb) / 8; + size = bytestream2_get_bytes_left(gb); } - av_assert0(gb->buffer + get_bits_count(gb) / 8 + size <= gb->buffer_end); - ret = ff_init_cabac_decoder (&ep->cc, gb->buffer + get_bits_count(gb) / 8, size); + return size; +} + +static int ep_init_cabac_decoder(EntryPoint *ep, GetByteContext *gb, const int size) +{ + int ret; + + av_assert0(size <= bytestream2_get_bytes_left(gb)); + ret = ff_init_cabac_decoder(&ep->cc, gb->buffer, size); if (ret < 0) return ret; - skip_bits(gb, size * 8); + bytestream2_skipu(gb, size); + return 0; +} + +static int ep_init(EntryPoint *ep, const int ctu_addr, const int ctu_end, + GetByteContext *gb, const int size) +{ + const int ret = ep_init_cabac_decoder(ep, gb, size); + + if (ret < 0) + return ret; + + ep->ctu_start = ctu_addr; + ep->ctu_end = ctu_end; + + for (int c_idx = LUMA; c_idx <= CR; c_idx++) + ep->pp[c_idx].size = 0; + return 0; } @@ -549,7 +571,7 @@ static int slice_init_entry_points(SliceContext *sc, const H266RawSlice *slice = unit->content_ref; int nb_eps = sh->r->num_entry_points + 1; int ctu_addr = 0; - GetBitContext gb; + GetByteContext gb; int ret; if (sc->nb_eps != nb_eps) { @@ -560,25 +582,23 @@ static int slice_init_entry_points(SliceContext *sc, sc->nb_eps = nb_eps; } - ret = init_get_bits8(&gb, slice->data, slice->data_size); - if (ret < 0) - return ret; + bytestream2_init(&gb, slice->data, slice->data_size); + for (int i = 0; i < sc->nb_eps; i++) { - EntryPoint *ep = sc->eps + i; + const int size = get_ep_size(sc->sh.r, &gb, nal, slice->header_size, i); + const int ctu_end = (i + 1 == sc->nb_eps ? sh->num_ctus_in_curr_slice : sh->entry_point_start_ctu[i]); + EntryPoint *ep = sc->eps + i; - ep->ctu_start = ctu_addr; - ep->ctu_end = (i + 1 == sc->nb_eps ? sh->num_ctus_in_curr_slice : sh->entry_point_start_ctu[i]); + ret = ep_init(ep, ctu_addr, ctu_end, &gb, size); + if (ret < 0) + return ret; for (int j = ep->ctu_start; j < ep->ctu_end; j++) { const int rs = sc->sh.ctb_addr_in_curr_slice[j]; fc->tab.slice_idx[rs] = sc->slice_idx; } - ret = ep_init_cabac_decoder(sc, i, nal, &gb, unit); - if (ret < 0) - return ret; - if (i + 1 < sc->nb_eps) ctu_addr = sh->entry_point_start_ctu[i]; } @@ -601,15 +621,25 @@ static int ref_frame(VVCFrame *dst, const VVCFrame *src) if (ret < 0) return ret; - ff_refstruct_replace(&dst->sps, src->sps); - ff_refstruct_replace(&dst->pps, src->pps); + av_refstruct_replace(&dst->sps, src->sps); + av_refstruct_replace(&dst->pps, src->pps); - ff_refstruct_replace(&dst->progress, src->progress); + if (src->needs_fg) { + ret = av_frame_ref(dst->frame_grain, src->frame_grain); + if (ret < 0) + return ret; - ff_refstruct_replace(&dst->tab_dmvr_mvf, src->tab_dmvr_mvf); + dst->needs_fg = src->needs_fg; + } - ff_refstruct_replace(&dst->rpl_tab, src->rpl_tab); - ff_refstruct_replace(&dst->rpl, src->rpl); + av_refstruct_replace(&dst->progress, src->progress); + + av_refstruct_replace(&dst->tab_dmvr_mvf, src->tab_dmvr_mvf); + + av_refstruct_replace(&dst->rpl_tab, src->rpl_tab); + av_refstruct_replace(&dst->rpl, src->rpl); + av_refstruct_replace(&dst->hwaccel_picture_private, + src->hwaccel_picture_private); dst->nb_rpl_elems = src->nb_rpl_elems; dst->poc = src->poc; @@ -629,18 +659,20 @@ static av_cold void frame_context_free(VVCFrameContext *fc) { slices_free(fc); - ff_refstruct_pool_uninit(&fc->tu_pool); - ff_refstruct_pool_uninit(&fc->cu_pool); + av_refstruct_pool_uninit(&fc->tu_pool); + av_refstruct_pool_uninit(&fc->cu_pool); for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) { ff_vvc_unref_frame(fc, &fc->DPB[i], ~0); av_frame_free(&fc->DPB[i].frame); + av_frame_free(&fc->DPB[i].frame_grain); } ff_vvc_frame_thread_free(fc); pic_arrays_free(fc); av_frame_free(&fc->output_frame); ff_vvc_frame_ps_free(&fc->ps); + ff_vvc_sei_reset(&fc->sei); } static av_cold int frame_context_init(VVCFrameContext *fc, AVCodecContext *avctx) @@ -656,12 +688,16 @@ static av_cold int frame_context_init(VVCFrameContext *fc, AVCodecContext *avctx fc->DPB[j].frame = av_frame_alloc(); if (!fc->DPB[j].frame) return AVERROR(ENOMEM); + + fc->DPB[j].frame_grain = av_frame_alloc(); + if (!fc->DPB[j].frame_grain) + return AVERROR(ENOMEM); } - fc->cu_pool = ff_refstruct_pool_alloc(sizeof(CodingUnit), 0); + fc->cu_pool = av_refstruct_pool_alloc(sizeof(CodingUnit), 0); if (!fc->cu_pool) return AVERROR(ENOMEM); - fc->tu_pool = ff_refstruct_pool_alloc(sizeof(TransformUnit), 0); + fc->tu_pool = av_refstruct_pool_alloc(sizeof(TransformUnit), 0); if (!fc->tu_pool) return AVERROR(ENOMEM); @@ -672,8 +708,6 @@ static int frame_context_setup(VVCFrameContext *fc, VVCContext *s) { int ret; - fc->ref = NULL; - // copy refs from the last frame if (s->nb_frames && s->nb_fcs > 1) { VVCFrameContext *prev = get_frame_context(s, fc, -1); @@ -685,10 +719,13 @@ static int frame_context_setup(VVCFrameContext *fc, VVCContext *s) return ret; } } + + ret = ff_vvc_sei_replace(&fc->sei, &prev->sei); + if (ret < 0) + return ret; } if (IS_IDR(s)) { - s->seq_decode = (s->seq_decode + 1) & 0xff; ff_vvc_clear_refs(fc); } @@ -700,6 +737,66 @@ static int frame_context_setup(VVCFrameContext *fc, VVCContext *s) return 0; } +/* SEI does not affect decoding, so we ignore the return value */ +static void decode_prefix_sei(VVCFrameContext *fc, VVCContext *s) +{ + CodedBitstreamFragment *frame = &s->current_frame; + + for (int i = 0; i < frame->nb_units; i++) { + const CodedBitstreamUnit *unit = frame->units + i; + + if (unit->type == VVC_PREFIX_SEI_NUT) { + int ret = ff_vvc_sei_decode(&fc->sei, unit->content_ref, fc); + if (ret < 0) + return; + } + } +} + +static int set_side_data(VVCContext *s, VVCFrameContext *fc) +{ + AVFrame *out = fc->ref->frame; + + return ff_h2645_sei_to_frame(out, &fc->sei.common, AV_CODEC_ID_VVC, s->avctx, + NULL, fc->ps.sps->bit_depth, fc->ps.sps->bit_depth, fc->ref->poc); +} + +static int check_film_grain(VVCContext *s, VVCFrameContext *fc) +{ + int ret; + + fc->ref->needs_fg = (fc->sei.common.film_grain_characteristics && + fc->sei.common.film_grain_characteristics->present || + fc->sei.common.aom_film_grain.enable) && + !(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) && + !s->avctx->hwaccel; + + if (fc->ref->needs_fg && + (fc->sei.common.film_grain_characteristics && + fc->sei.common.film_grain_characteristics->present && + !ff_h274_film_grain_params_supported(fc->sei.common.film_grain_characteristics->model_id, + fc->ref->frame->format) || + !av_film_grain_params_select(fc->ref->frame))) { + av_log_once(s->avctx, AV_LOG_WARNING, AV_LOG_DEBUG, &s->film_grain_warning_shown, + "Unsupported film grain parameters. Ignoring film grain.\n"); + fc->ref->needs_fg = 0; + } + + if (fc->ref->needs_fg) { + fc->ref->frame_grain->format = fc->ref->frame->format; + fc->ref->frame_grain->width = fc->ref->frame->width; + fc->ref->frame_grain->height = fc->ref->frame->height; + + ret = ff_thread_get_buffer(s->avctx, fc->ref->frame_grain, 0); + if (ret < 0) + return ret; + + return av_frame_copy_props(fc->ref->frame_grain, fc->ref->frame); + } + + return 0; +} + static int frame_start(VVCContext *s, VVCFrameContext *fc, SliceContext *sc) { const VVCPH *ph = &fc->ps.ph; @@ -710,9 +807,19 @@ static int frame_start(VVCContext *s, VVCFrameContext *fc, SliceContext *sc) if (!s->temporal_id && !ph->r->ph_non_ref_pic_flag && !(IS_RASL(s) || IS_RADL(s))) s->poc_tid0 = ph->poc; + decode_prefix_sei(fc, s); + if ((ret = ff_vvc_set_new_ref(s, fc, &fc->frame)) < 0) goto fail; + ret = set_side_data(s, fc); + if (ret < 0) + goto fail; + + ret = check_film_grain(s, fc); + if (ret < 0) + goto fail; + if (!IS_IDR(s)) ff_vvc_bump_frame(s, fc); @@ -744,8 +851,6 @@ static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc, if (ret < 0) return ret; - ff_refstruct_replace(&sc->ref, unit->content_ref); - if (is_first_slice) { ret = frame_start(s, fc, sc); if (ret < 0) @@ -770,23 +875,56 @@ static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc, return 0; } -static void export_frame_params(VVCContext *s, const VVCFrameContext *fc) +static enum AVPixelFormat get_format(AVCodecContext *avctx, const VVCSPS *sps) +{ +#define HWACCEL_MAX CONFIG_VVC_VAAPI_HWACCEL + + enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts; + + switch (sps->pix_fmt) { + case AV_PIX_FMT_YUV420P: +#if CONFIG_VVC_VAAPI_HWACCEL + *fmt++ = AV_PIX_FMT_VAAPI; +#endif + break; + case AV_PIX_FMT_YUV420P10: +#if CONFIG_VVC_VAAPI_HWACCEL + *fmt++ = AV_PIX_FMT_VAAPI; +#endif + break; + } + + *fmt++ = sps->pix_fmt; + *fmt = AV_PIX_FMT_NONE; + + return ff_get_format(avctx, pix_fmts); +} + +static int export_frame_params(VVCContext *s, const VVCFrameContext *fc) { AVCodecContext *c = s->avctx; const VVCSPS *sps = fc->ps.sps; const VVCPPS *pps = fc->ps.pps; - c->pix_fmt = sps->pix_fmt; - c->coded_width = pps->width; - c->coded_height = pps->height; - c->width = pps->width - ((pps->r->pps_conf_win_left_offset + pps->r->pps_conf_win_right_offset) << sps->hshift[CHROMA]); - c->height = pps->height - ((pps->r->pps_conf_win_top_offset + pps->r->pps_conf_win_bottom_offset) << sps->vshift[CHROMA]); - c->has_b_frames = sps->r->sps_dpb_params.dpb_max_num_reorder_pics[sps->r->sps_max_sublayers_minus1]; + // Reset the format if pix_fmt/w/h change. + if (c->sw_pix_fmt != sps->pix_fmt || c->coded_width != pps->width || c->coded_height != pps->height) { + c->coded_width = pps->width; + c->coded_height = pps->height; + c->sw_pix_fmt = sps->pix_fmt; + c->pix_fmt = get_format(c, sps); + if (c->pix_fmt < 0) + return AVERROR_INVALIDDATA; + } + + c->width = pps->width - ((pps->r->pps_conf_win_left_offset + pps->r->pps_conf_win_right_offset) << sps->hshift[CHROMA]); + c->height = pps->height - ((pps->r->pps_conf_win_top_offset + pps->r->pps_conf_win_bottom_offset) << sps->vshift[CHROMA]); + + return 0; } static int frame_setup(VVCFrameContext *fc, VVCContext *s) { - int ret = ff_vvc_decode_frame_ps(&fc->ps, s); + int ret = ff_vvc_decode_frame_ps(fc, s); if (ret < 0) return ret; @@ -794,11 +932,15 @@ static int frame_setup(VVCFrameContext *fc, VVCContext *s) if (ret < 0) return ret; - export_frame_params(s, fc); - return ret; + ret = export_frame_params(s, fc); + if (ret < 0) + return ret; + + return 0; } -static int decode_slice(VVCContext *s, VVCFrameContext *fc, const H2645NAL *nal, const CodedBitstreamUnit *unit) +static int decode_slice(VVCContext *s, VVCFrameContext *fc, AVBufferRef *buf_ref, + const H2645NAL *nal, const CodedBitstreamUnit *unit) { int ret; SliceContext *sc; @@ -809,6 +951,7 @@ static int decode_slice(VVCContext *s, VVCFrameContext *fc, const H2645NAL *nal, return ret; sc = fc->slices[fc->nb_slices]; + av_refstruct_replace(&sc->ref, unit->content_ref); s->vcl_unit_type = nal->type; if (is_first_slice) { @@ -824,12 +967,27 @@ static int decode_slice(VVCContext *s, VVCFrameContext *fc, const H2645NAL *nal, ret = slice_init_entry_points(sc, fc, nal, unit); if (ret < 0) return ret; + + if (s->avctx->hwaccel) { + if (is_first_slice) { + ret = FF_HW_CALL(s->avctx, start_frame, buf_ref, NULL, 0); + if (ret < 0) + return ret; + } + + ret = FF_HW_CALL(s->avctx, decode_slice, + nal->raw_data, nal->raw_size); + if (ret < 0) + return ret; + } + fc->nb_slices++; return 0; } -static int decode_nal_unit(VVCContext *s, VVCFrameContext *fc, const H2645NAL *nal, const CodedBitstreamUnit *unit) +static int decode_nal_unit(VVCContext *s, VVCFrameContext *fc, AVBufferRef *buf_ref, + const H2645NAL *nal, const CodedBitstreamUnit *unit) { int ret; @@ -855,7 +1013,7 @@ static int decode_nal_unit(VVCContext *s, VVCFrameContext *fc, const H2645NAL *n case VVC_IDR_N_LP: case VVC_CRA_NUT: case VVC_GDR_NUT: - ret = decode_slice(s, fc, nal, unit); + ret = decode_slice(s, fc, buf_ref, nal, unit); if (ret < 0) return ret; break; @@ -865,6 +1023,15 @@ static int decode_nal_unit(VVCContext *s, VVCFrameContext *fc, const H2645NAL *n if (ret < 0) return ret; break; + case VVC_PREFIX_SEI_NUT: + /* handle by decode_prefix_sei() */ + break; + + case VVC_SUFFIX_SEI_NUT: + /* SEI does not affect decoding, so we ignore the return value*/ + if (fc) + ff_vvc_sei_decode(&fc->sei, unit->content_ref, fc); + break; } return 0; @@ -877,6 +1044,7 @@ static int decode_nal_units(VVCContext *s, VVCFrameContext *fc, AVPacket *avpkt) int ret = 0; s->last_eos = s->eos; s->eos = 0; + fc->ref = NULL; ff_cbs_fragment_reset(frame); ret = ff_cbs_read_packet(s->cbc, frame, avpkt); @@ -892,7 +1060,7 @@ static int decode_nal_units(VVCContext *s, VVCFrameContext *fc, AVPacket *avpkt) if (unit->type == VVC_EOB_NUT || unit->type == VVC_EOS_NUT) { s->last_eos = 1; } else { - ret = decode_nal_unit(s, fc, nal, unit); + ret = decode_nal_unit(s, fc, avpkt->buf, nal, unit); if (ret < 0) { av_log(s->avctx, AV_LOG_WARNING, "Error parsing NAL unit #%d.\n", i); @@ -908,16 +1076,47 @@ fail: return ret; } -static int set_output_format(const VVCContext *s, const AVFrame *output) +static int frame_end(VVCContext *s, VVCFrameContext *fc) { - AVCodecContext *c = s->avctx; + const AVFilmGrainParams *fgp; int ret; - if (output->width != c->width || output->height != c->height) { - if ((ret = ff_set_dimensions(c, output->width, output->height)) < 0) - return ret; + if (fc->ref->needs_fg) { + av_assert0(fc->ref->frame_grain->buf[0]); + fgp = av_film_grain_params_select(fc->ref->frame); + switch (fgp->type) { + case AV_FILM_GRAIN_PARAMS_NONE: + av_assert0(0); + return AVERROR_BUG; + case AV_FILM_GRAIN_PARAMS_H274: + ret = ff_h274_apply_film_grain(fc->ref->frame_grain, fc->ref->frame, fgp); + if (ret < 0) + return ret; + break; + case AV_FILM_GRAIN_PARAMS_AV1: + ret = ff_aom_apply_film_grain(fc->ref->frame_grain, fc->ref->frame, fgp); + if (ret < 0) + return ret; + break; + } } - c->pix_fmt = output->format; + + if (!s->avctx->hwaccel && s->avctx->err_recognition & AV_EF_CRCCHECK) { + VVCSEI *sei = &fc->sei; + if (sei->picture_hash.present) { + ret = ff_h274_hash_init(&s->hash_ctx, sei->picture_hash.hash_type); + if (ret < 0) + return ret; + + ret = ff_h274_hash_verify(s->hash_ctx, &sei->picture_hash, fc->ref->frame, fc->ps.pps->width, fc->ps.pps->height); + av_log(s->avctx, ret < 0 ? AV_LOG_ERROR : AV_LOG_DEBUG, + "Verifying checksum for frame with decode_order %d: %s\n", + (int)fc->decode_order, ret < 0 ? "incorrect": "correct"); + if (ret < 0 && (s->avctx->err_recognition & AV_EF_EXPLODE)) + return ret; + } + } + return 0; } @@ -926,11 +1125,12 @@ static int wait_delayed_frame(VVCContext *s, AVFrame *output, int *got_output) VVCFrameContext *delayed = get_frame_context(s, s->fcs, s->nb_frames - s->nb_delayed); int ret = ff_vvc_frame_wait(s, delayed); - if (!ret && delayed->output_frame->buf[0] && output) { - av_frame_move_ref(output, delayed->output_frame); - ret = set_output_format(s, output); - if (!ret) + if (!ret) { + ret = frame_end(s, delayed); + if (ret >= 0 && delayed->output_frame->buf[0] && output) { + av_frame_move_ref(output, delayed->output_frame); *got_output = 1; + } } s->nb_delayed--; @@ -939,17 +1139,26 @@ static int wait_delayed_frame(VVCContext *s, AVFrame *output, int *got_output) static int submit_frame(VVCContext *s, VVCFrameContext *fc, AVFrame *output, int *got_output) { - int ret = ff_vvc_frame_submit(s, fc); + int ret; - if (ret < 0) { - ff_vvc_report_frame_finished(fc->ref); - return ret; + if (s->avctx->hwaccel) { + if (ret = FF_HW_SIMPLE_CALL(s->avctx, end_frame) < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "Hardware accelerator failed to decode picture\n"); + ff_vvc_unref_frame(fc, fc->ref, ~0); + return ret; + } + } else { + if (ret = ff_vvc_frame_submit(s, fc) < 0) { + ff_vvc_report_frame_finished(fc->ref); + return ret; + } } s->nb_frames++; s->nb_delayed++; - if (s->nb_delayed >= s->nb_fcs) { + if (s->nb_delayed >= s->nb_fcs || s->avctx->hwaccel) { if ((ret = wait_delayed_frame(s, output, got_output)) < 0) return ret; } @@ -972,11 +1181,7 @@ static int get_decoded_frame(VVCContext *s, AVFrame *output, int *got_output) ret = ff_vvc_output_frame(s, last, output, 0, 1); if (ret < 0) return ret; - if (ret) { - *got_output = ret; - if ((ret = set_output_format(s, output)) < 0) - return ret; - } + *got_output = ret; } return 0; } @@ -1000,7 +1205,7 @@ static int vvc_decode_frame(AVCodecContext *avctx, AVFrame *output, if (ret < 0) return ret; - if (!fc->ft) + if (!fc->ft || !fc->ref) return avpkt->size; ret = submit_frame(s, fc, output, got_output); @@ -1020,6 +1225,7 @@ static av_cold void vvc_decode_flush(AVCodecContext *avctx) if (s->fcs) { VVCFrameContext *last = get_frame_context(s, s->fcs, s->nb_frames - 1); + ff_vvc_sei_reset(&last->sei); ff_vvc_flush_dpb(last); } @@ -1040,6 +1246,7 @@ static av_cold int vvc_decode_free(AVCodecContext *avctx) frame_context_free(s->fcs + i); av_free(s->fcs); } + ff_h274_hash_freep(&s->hash_ctx); ff_vvc_ps_uninit(&s->ps); ff_cbs_close(&s->cbc); @@ -1112,4 +1319,10 @@ const FFCodec ff_vvc_decoder = { .caps_internal = FF_CODEC_CAP_EXPORTS_CROPPING | FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS, .p.profiles = NULL_IF_CONFIG_SMALL(ff_vvc_profiles), + .hw_configs = (const AVCodecHWConfigInternal *const []) { +#if CONFIG_VVC_VAAPI_HWACCEL + HWACCEL_VAAPI(vvc), +#endif + NULL + }, }; diff --git a/libavcodec/vvc/dec.h b/libavcodec/vvc/dec.h index d27cf52ca..bfb8a2e20 100644 --- a/libavcodec/vvc/dec.h +++ b/libavcodec/vvc/dec.h @@ -26,9 +26,11 @@ #include "libavcodec/videodsp.h" #include "libavcodec/vvc.h" +#include "libavcodec/h274.h" #include "ps.h" #include "dsp.h" +#include "sei.h" #define LUMA 0 #define CHROMA 1 @@ -70,12 +72,15 @@ typedef struct VVCWindow { typedef struct VVCFrame { struct AVFrame *frame; - + struct AVFrame *frame_grain; const VVCSPS *sps; ///< RefStruct reference const VVCPPS *pps; ///< RefStruct reference struct MvField *tab_dmvr_mvf; ///< RefStruct reference RefPicListTab **rpl_tab; ///< RefStruct reference RefPicListTab *rpl; ///< RefStruct reference + + int needs_fg; ///< 1 if grain needs to be applied by the decoder + int nb_rpl_elems; int ctb_count; @@ -101,6 +106,8 @@ typedef struct VVCFrame { * A combination of VVC_FRAME_FLAG_* */ uint8_t flags; + + void *hwaccel_picture_private; ///< hardware accelerator private data } VVCFrame; typedef struct SliceContext { @@ -122,6 +129,7 @@ typedef struct VVCFrameContext { struct AVFrame *output_frame; VVCFrameParamSets ps; + VVCSEI sei; SliceContext **slices; int nb_slices; @@ -136,11 +144,11 @@ typedef struct VVCFrameContext { uint64_t decode_order; - struct FFRefStructPool *tab_dmvr_mvf_pool; - struct FFRefStructPool *rpl_tab_pool; + struct AVRefStructPool *tab_dmvr_mvf_pool; + struct AVRefStructPool *rpl_tab_pool; - struct FFRefStructPool *cu_pool; - struct FFRefStructPool *tu_pool; + struct AVRefStructPool *cu_pool; + struct AVRefStructPool *tu_pool; struct { int16_t *slice_idx; @@ -159,9 +167,7 @@ typedef struct VVCFrameContext { uint8_t *skip; ///< CuSkipFlag[][] uint8_t *ispmf; ///< intra_sub_partitions_mode_flag uint8_t *msm[2]; ///< MttSplitMode[][][] in 32 pixels - uint8_t *imf; ///< IntraMipFlag[][] - uint8_t *imtf; ///< intra_mip_transposed_flag[][] - uint8_t *imm; ///< intra_mip_mode[][] + uint8_t *imf; ///< IntraMipFlag[][], intra_mip_transposed_flag[][], intra_mip_mode[][] uint8_t *ipm; ///< IntraPredModeY[][] uint8_t *cpm[2]; ///< CuPredMode[][][] uint8_t *msf; ///< MergeSubblockFlag[][] @@ -172,8 +178,6 @@ typedef struct VVCFrameContext { uint8_t *tu_coded_flag[VVC_MAX_SAMPLE_ARRAYS]; ///< tu_y_coded_flag[][], tu_cb_coded_flag[][], tu_cr_coded_flag[][] uint8_t *tu_joint_cbcr_residual_flag; ///< tu_joint_cbcr_residual_flag[][] - int *tb_pos_x0[2]; - int *tb_pos_y0[2]; uint8_t *tb_width[2]; uint8_t *tb_height[2]; uint8_t *pcmf[2]; @@ -228,6 +232,7 @@ typedef struct VVCContext { enum VVCNALUnitType vcl_unit_type; int no_output_before_recovery_flag; ///< NoOutputBeforeRecoveryFlag int gdr_recovery_point_poc; ///< recoveryPointPocVal + int film_grain_warning_shown; /** * Sequence counters for decoded and output frames, so that old @@ -236,13 +241,15 @@ typedef struct VVCContext { uint16_t seq_decode; uint16_t seq_output; - struct AVExecutor *executor; + struct FFExecutor *executor; VVCFrameContext *fcs; int nb_fcs; uint64_t nb_frames; ///< processed frames int nb_delayed; ///< delayed frames + + H274HashContext *hash_ctx; } VVCContext ; #endif /* AVCODEC_VVC_DEC_H */ diff --git a/libavcodec/vvc/dsp.c b/libavcodec/vvc/dsp.c index 433353c32..60372cca4 100644 --- a/libavcodec/vvc/dsp.c +++ b/libavcodec/vvc/dsp.c @@ -44,6 +44,15 @@ static int vvc_sad(const int16_t *src0, const int16_t *src1, int dx, int dy, return sad; } +static av_always_inline void unpack_mip_info(int *intra_mip_transposed_flag, + int *intra_mip_mode, const uint8_t mip_info) +{ + if (intra_mip_transposed_flag) + *intra_mip_transposed_flag = (mip_info >> 1) & 0x1; + if (intra_mip_mode) + *intra_mip_mode = (mip_info >> 2) & 0xf; +} + typedef struct IntraEdgeParams { uint8_t* top; uint8_t* left; @@ -102,7 +111,9 @@ void ff_vvc_dsp_init(VVCDSPContext *vvcdsp, int bit_depth) #if ARCH_AARCH64 ff_vvc_dsp_init_aarch64(vvcdsp, bit_depth); -#elif ARCH_X86 +#elif ARCH_RISCV + ff_vvc_dsp_init_riscv(vvcdsp, bit_depth); +#elif ARCH_X86 && HAVE_X86ASM ff_vvc_dsp_init_x86(vvcdsp, bit_depth); #endif } diff --git a/libavcodec/vvc/dsp.h b/libavcodec/vvc/dsp.h index 635ebcafe..29cdd7e8f 100644 --- a/libavcodec/vvc/dsp.h +++ b/libavcodec/vvc/dsp.h @@ -75,7 +75,7 @@ typedef struct VVCInterDSPContext { void (*w_avg)(uint8_t *_dst, const ptrdiff_t _dst_stride, const int16_t *src0, const int16_t *src1, int width, int height, - int denom, int w0, int w1, int o0, int o1); + int denom, int w0, int w1, int o); void (*put_ciip)(uint8_t *dst, ptrdiff_t dst_stride, int width, int height, const uint8_t *inter, ptrdiff_t inter_stride, int inter_weight); @@ -106,7 +106,7 @@ struct VVCLocalContext; typedef struct VVCIntraDSPContext { void (*intra_cclm_pred)(const struct VVCLocalContext *lc, int x0, int y0, int w, int h); - void (*lmcs_scale_chroma)(struct VVCLocalContext *lc, int *dst, const int *coeff, int w, int h, int x0_cu, int y0_cu); + void (*lmcs_scale_chroma)(struct VVCLocalContext *lc, int *coeff, int w, int h, int x0_cu, int y0_cu); void (*intra_pred)(const struct VVCLocalContext *lc, int x0, int y0, int w, int h, int c_idx); void (*pred_planar)(uint8_t *src, const uint8_t *top, const uint8_t *left, int w, int h, ptrdiff_t stride); void (*pred_mip)(uint8_t *src, const uint8_t *top, const uint8_t *left, int w, int h, ptrdiff_t stride, @@ -122,11 +122,12 @@ typedef struct VVCIntraDSPContext { typedef struct VVCItxDSPContext { void (*add_residual)(uint8_t *dst, const int *res, int width, int height, ptrdiff_t stride); - void (*add_residual_joint)(uint8_t *dst, const int *res, int width, int height, ptrdiff_t stride, int c_sign, int shift); - void (*pred_residual_joint)(int *buf, int width, int height, int c_sign, int shift); + void (*pred_residual_joint)(int *dst, const int *src, int width, int height, int c_sign, int shift); void (*itx[VVC_N_TX_TYPE][VVC_N_TX_SIZE])(int *coeffs, ptrdiff_t step, size_t nz); void (*transform_bdpcm)(int *coeffs, int width, int height, int vertical, int log2_transform_range); + + void (*adaptive_color_transform)(int *y, int *u, int *v, int width, int height); } VVCItxDSPContext; typedef struct VVCLMCSDSPContext { @@ -179,6 +180,7 @@ typedef struct VVCDSPContext { void ff_vvc_dsp_init(VVCDSPContext *hpc, int bit_depth); void ff_vvc_dsp_init_aarch64(VVCDSPContext *hpc, const int bit_depth); +void ff_vvc_dsp_init_riscv(VVCDSPContext *hpc, const int bit_depth); void ff_vvc_dsp_init_x86(VVCDSPContext *hpc, const int bit_depth); #endif /* AVCODEC_VVC_DSP_H */ diff --git a/libavcodec/vvc/dsp_template.c b/libavcodec/vvc/dsp_template.c index 1aa1e027b..13bd8cd4a 100644 --- a/libavcodec/vvc/dsp_template.c +++ b/libavcodec/vvc/dsp_template.c @@ -45,32 +45,12 @@ static void FUNC(add_residual)(uint8_t *_dst, const int *res, } } -static void FUNC(add_residual_joint)(uint8_t *_dst, const int *res, - const int w, const int h, const ptrdiff_t _stride, const int c_sign, const int shift) -{ - pixel *dst = (pixel *)_dst; - - const int stride = _stride / sizeof(pixel); - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - const int r = ((*res) * c_sign) >> shift; - dst[x] = av_clip_pixel(dst[x] + r); - res++; - } - dst += stride; - } -} - -static void FUNC(pred_residual_joint)(int *buf, const int w, const int h, +static void FUNC(pred_residual_joint)(int *dst, const int *src, const int w, const int h, const int c_sign, const int shift) { - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - *buf = ((*buf) * c_sign) >> shift; - buf++; - } - } + const int size = w * h; + for (int i = 0; i < size; i++) + dst[i] = (src[i] * c_sign) >> shift; } static void FUNC(transform_bdpcm)(int *coeffs, const int width, const int height, @@ -94,6 +74,24 @@ static void FUNC(transform_bdpcm)(int *coeffs, const int width, const int height } } +// 8.7.4.6 Residual modification process for blocks using colour space conversion +static void FUNC(adaptive_color_transform)(int *y, int *u, int *v, const int width, const int height) +{ + const int size = width * height; + const int bits = BIT_DEPTH + 1; + + for (int i = 0; i < size; i++) { + const int y0 = av_clip_intp2(y[i], bits); + const int cg = av_clip_intp2(u[i], bits); + const int co = av_clip_intp2(v[i], bits); + const int t = y0 - (cg >> 1); + + y[i] = cg + t; + u[i] = t - (co >> 1); + v[i] = co + u[i]; + } +} + static void FUNC(ff_vvc_itx_dsp_init)(VVCItxDSPContext *const itx) { #define VVC_ITX(TYPE, type, s) \ @@ -106,7 +104,6 @@ static void FUNC(ff_vvc_itx_dsp_init)(VVCItxDSPContext *const itx) VVC_ITX(TYPE, type, 32); itx->add_residual = FUNC(add_residual); - itx->add_residual_joint = FUNC(add_residual_joint); itx->pred_residual_joint = FUNC(pred_residual_joint); itx->transform_bdpcm = FUNC(transform_bdpcm); VVC_ITX(DCT2, dct2, 2) @@ -115,6 +112,8 @@ static void FUNC(ff_vvc_itx_dsp_init)(VVCItxDSPContext *const itx) VVC_ITX_COMMON(DCT8, dct8) VVC_ITX_COMMON(DST7, dst7) + itx->adaptive_color_transform = FUNC(adaptive_color_transform); + #undef VVC_ITX #undef VVC_ITX_COMMON } diff --git a/libavcodec/vvc/filter.c b/libavcodec/vvc/filter.c index 25bef45ee..3815668bc 100644 --- a/libavcodec/vvc/filter.c +++ b/libavcodec/vvc/filter.c @@ -385,6 +385,9 @@ static int boundary_strength(const VVCLocalContext *lc, const MvField *curr, con { RefPicList *rpl = lc->sc->rpl; + if (curr->pred_flag == PF_PLT) + return 0; + if (curr->pred_flag == PF_IBC) return FFABS(neigh->mv[0].x - curr->mv[0].x) >= 8 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 8; @@ -451,15 +454,15 @@ static int boundary_strength(const VVCLocalContext *lc, const MvField *curr, con //part of 8.8.3.3 Derivation process of transform block boundary static void derive_max_filter_length_luma(const VVCFrameContext *fc, const int qx, const int qy, - const int is_intra, const int has_subblock, const int vertical, uint8_t *max_len_p, uint8_t *max_len_q) + const int size_q, const int has_subblock, const int vertical, uint8_t *max_len_p, uint8_t *max_len_q) { const int px = vertical ? qx - 1 : qx; const int py = !vertical ? qy - 1 : qy; const uint8_t *tb_size = vertical ? fc->tab.tb_width[LUMA] : fc->tab.tb_height[LUMA]; const int size_p = tb_size[(py >> MIN_TU_LOG2) * fc->ps.pps->min_tu_width + (px >> MIN_TU_LOG2)]; - const int size_q = tb_size[(qy >> MIN_TU_LOG2) * fc->ps.pps->min_tu_width + (qx >> MIN_TU_LOG2)]; const int min_cb_log2 = fc->ps.sps->min_cb_log2_size_y; const int off_p = (py >> min_cb_log2) * fc->ps.pps->min_cb_width + (px >> min_cb_log2); + if (size_p <= 4 || size_q <= 4) { *max_len_p = *max_len_q = 1; } else { @@ -525,7 +528,7 @@ static void vvc_deblock_subblock_bs(const VVCLocalContext *lc, } static av_always_inline int deblock_bs(const VVCLocalContext *lc, - const int x_p, const int y_p, const int x_q, const int y_q, + const int x_p, const int y_p, const int x_q, const int y_q, const CodingUnit *cu, const TransformUnit *tu, const RefPicList *rpl_p, const int c_idx, const int off_to_cb, const uint8_t has_sub_block) { const VVCFrameContext *fc = lc->fc; @@ -542,12 +545,10 @@ static av_always_inline int deblock_bs(const VVCLocalContext *lc, const MvField *mvf_q = &tab_mvf[pu_q]; const uint8_t chroma = !!c_idx; const int tu_p = (y_p >> log2_min_tu_size) * min_tu_width + (x_p >> log2_min_tu_size); - const int tu_q = (y_q >> log2_min_tu_size) * min_tu_width + (x_q >> log2_min_tu_size); - const uint8_t pcmf = fc->tab.pcmf[chroma][tu_p] && fc->tab.pcmf[chroma][tu_q]; const int cb_p = (y_p >> log2_min_cb_size) * min_cb_width + (x_p >> log2_min_cb_size); - const int cb_q = (y_q >> log2_min_cb_size) * min_cb_width + (x_q >> log2_min_cb_size); - const uint8_t intra = fc->tab.cpm[chroma][cb_p] == MODE_INTRA || fc->tab.cpm[chroma][cb_q] == MODE_INTRA; - const uint8_t same_mode = fc->tab.cpm[chroma][cb_p] == fc->tab.cpm[chroma][cb_q]; + const uint8_t pcmf = fc->tab.pcmf[chroma][cb_p] && cu->bdpcm_flag[chroma]; + const uint8_t intra = fc->tab.cpm[chroma][cb_p] == MODE_INTRA || cu->pred_mode == MODE_INTRA; + const uint8_t same_mode = fc->tab.cpm[chroma][cb_p] == cu->pred_mode; if (pcmf) return 0; @@ -557,12 +558,12 @@ static av_always_inline int deblock_bs(const VVCLocalContext *lc, if (chroma) { return fc->tab.tu_coded_flag[c_idx][tu_p] || - fc->tab.tu_coded_flag[c_idx][tu_q] || fc->tab.tu_joint_cbcr_residual_flag[tu_p] || - fc->tab.tu_joint_cbcr_residual_flag[tu_q]; + tu->coded_flag[c_idx] || + tu->joint_cbcr_residual_flag; } - if (fc->tab.tu_coded_flag[LUMA][tu_p] || fc->tab.tu_coded_flag[LUMA][tu_q]) + if (fc->tab.tu_coded_flag[LUMA][tu_p] || tu->coded_flag[LUMA]) return 1; if ((off_to_cb && ((off_to_cb % 8) || !has_sub_block))) @@ -606,27 +607,23 @@ static int deblock_is_boundary(const VVCLocalContext *lc, const int boundary, } static void vvc_deblock_bs_luma(const VVCLocalContext *lc, - const int x0, const int y0, const int width, const int height, const int rs, const int vertical) + const int x0, const int y0, const int width, const int height, + const CodingUnit *cu, const TransformUnit *tu, int rs, const int vertical) { - const VVCFrameContext *fc = lc->fc; - const MvField *tab_mvf = fc->tab.mvf; - const int mask = LUMA_GRID - 1; - const int log2_min_pu_size = MIN_PU_LOG2; - const int min_pu_width = fc->ps.pps->min_pu_width; - const int min_cb_log2 = fc->ps.sps->min_cb_log2_size_y; - const int min_cb_width = fc->ps.pps->min_cb_width; - const int pos = vertical ? x0 : y0; - const int off_q = (y0 >> min_cb_log2) * min_cb_width + (x0 >> min_cb_log2); - const int cb = (vertical ? fc->tab.cb_pos_x : fc->tab.cb_pos_y )[LUMA][off_q]; - const int is_intra = tab_mvf[(y0 >> log2_min_pu_size) * min_pu_width + - (x0 >> log2_min_pu_size)].pred_flag == PF_INTRA; + const VVCFrameContext *fc = lc->fc; + const PredictionUnit *pu = &cu->pu; + const int mask = LUMA_GRID - 1; + const int pos = vertical ? x0 : y0; + const int cb = vertical ? cu->x0 : cu->y0; + const int is_intra = cu->pred_mode == MODE_INTRA; + const int cb_size = vertical ? cu->cb_width : cu->cb_height; + const int has_sb = !is_intra && (pu->merge_subblock_flag || pu->inter_affine_flag) && cb_size > 8; if (deblock_is_boundary(lc, pos > 0 && !(pos & mask), pos, rs, vertical)) { const int is_vb = is_virtual_boundary(fc, pos, vertical); const int size = vertical ? height : width; + const int size_q = vertical ? width : height; const int off = cb - pos; - const int cb_size = (vertical ? fc->tab.cb_width : fc->tab.cb_height)[LUMA][off_q]; - const int has_sb = !is_intra && (fc->tab.msf[off_q] || fc->tab.iaf[off_q]) && cb_size > 8; const int flag = vertical ? BOUNDARY_LEFT_SLICE : BOUNDARY_UPPER_SLICE; const RefPicList *rpl_p = (lc->boundary_flags & flag) ? ff_vvc_get_ref_list(fc, fc->ref, x0 - vertical, y0 - !vertical) : lc->sc->rpl; @@ -635,24 +632,23 @@ static void vvc_deblock_bs_luma(const VVCLocalContext *lc, const int x = x0 + i * !vertical; const int y = y0 + i * vertical; uint8_t max_len_p, max_len_q; - const int bs = is_vb ? 0 : deblock_bs(lc, x - vertical, y - !vertical, x, y, rpl_p, LUMA, off, has_sb); + const int bs = is_vb ? 0 : deblock_bs(lc, x - vertical, y - !vertical, x, y, cu, tu, rpl_p, LUMA, off, has_sb); TAB_BS(fc->tab.bs[vertical][LUMA], x, y) = bs; - derive_max_filter_length_luma(fc, x, y, is_intra, has_sb, vertical, &max_len_p, &max_len_q); + derive_max_filter_length_luma(fc, x, y, size_q, has_sb, vertical, &max_len_p, &max_len_q); TAB_MAX_LEN(fc->tab.max_len_p[vertical], x, y) = max_len_p; TAB_MAX_LEN(fc->tab.max_len_q[vertical], x, y) = max_len_q; } } - if (!is_intra) { - if (fc->tab.msf[off_q] || fc->tab.iaf[off_q]) - vvc_deblock_subblock_bs(lc, cb, x0, y0, width, height, vertical); - } + if (has_sb) + vvc_deblock_subblock_bs(lc, cb, x0, y0, width, height, vertical); } static void vvc_deblock_bs_chroma(const VVCLocalContext *lc, - const int x0, const int y0, const int width, const int height, const int rs, const int vertical) + const int x0, const int y0, const int width, const int height, + const CodingUnit *cu, const TransformUnit *tu, const int rs, const int vertical) { const VVCFrameContext *fc = lc->fc; const int shift = (vertical ? fc->ps.sps->hshift : fc->ps.sps->vshift)[CHROMA]; @@ -667,7 +663,7 @@ static void vvc_deblock_bs_chroma(const VVCLocalContext *lc, for (int i = 0; i < size; i += 2) { const int x = x0 + i * !vertical; const int y = y0 + i * vertical; - const int bs = is_vb ? 0 : deblock_bs(lc, x - vertical, y - !vertical, x, y, NULL, c_idx, 0, 0); + const int bs = is_vb ? 0 : deblock_bs(lc, x - vertical, y - !vertical, x, y, cu, tu, NULL, c_idx, 0, 0); TAB_BS(fc->tab.bs[vertical][c_idx], x, y) = bs; } @@ -678,28 +674,24 @@ static void vvc_deblock_bs_chroma(const VVCLocalContext *lc, typedef void (*deblock_bs_fn)(const VVCLocalContext *lc, const int x0, const int y0, const int width, const int height, const int rs, const int vertical); -static void vvc_deblock_bs(const VVCLocalContext *lc, const int x0, const int y0, const int rs, const int vertical) +void ff_vvc_deblock_bs(VVCLocalContext *lc, const int rx, const int ry, const int rs) { const VVCFrameContext *fc = lc->fc; const VVCSPS *sps = fc->ps.sps; - const VVCPPS *pps = fc->ps.pps; - const int ctb_size = sps->ctb_size_y; - const int x_end = FFMIN(x0 + ctb_size, pps->width) >> MIN_TU_LOG2; - const int y_end = FFMIN(y0 + ctb_size, pps->height) >> MIN_TU_LOG2; - const int has_chroma = !!sps->r->sps_chroma_format_idc; - deblock_bs_fn deblock_bs[] = { - vvc_deblock_bs_luma, vvc_deblock_bs_chroma - }; + const int x0 = rx << sps->ctb_log2_size_y; + const int y0 = ry << sps->ctb_log2_size_y; - for (int is_chroma = 0; is_chroma <= has_chroma; is_chroma++) { - const int hs = sps->hshift[is_chroma]; - const int vs = sps->vshift[is_chroma]; - for (int y = y0 >> MIN_TU_LOG2; y < y_end; y++) { - for (int x = x0 >> MIN_TU_LOG2; x < x_end; x++) { - const int off = y * fc->ps.pps->min_tu_width + x; - if ((fc->tab.tb_pos_x0[is_chroma][off] >> MIN_TU_LOG2) == x && (fc->tab.tb_pos_y0[is_chroma][off] >> MIN_TU_LOG2) == y) { - deblock_bs[is_chroma](lc, x << MIN_TU_LOG2, y << MIN_TU_LOG2, - fc->tab.tb_width[is_chroma][off] << hs, fc->tab.tb_height[is_chroma][off] << vs, rs, vertical); + ff_vvc_decode_neighbour(lc, x0, y0, rx, ry, rs); + for (const CodingUnit *cu = fc->tab.cus[rs]; cu; cu = cu->next) { + for (const TransformUnit *tu = cu->tus.head; tu; tu = tu->next) { + for (int vertical = 0; vertical <= 1; vertical++) { + if (tu->avail[LUMA]) + vvc_deblock_bs_luma(lc, tu->x0, tu->y0, tu->width, tu->height, cu, tu, rs, vertical); + if (tu->avail[CHROMA]) { + if (cu->isp_split_type != ISP_NO_SPLIT && cu->tree_type == SINGLE_TREE) + vvc_deblock_bs_chroma(lc, cu->x0, cu->y0, cu->cb_width, cu->cb_height, cu, tu, rs, vertical); + else + vvc_deblock_bs_chroma(lc, tu->x0, tu->y0, tu->width, tu->height, cu, tu, rs, vertical); } } } @@ -783,19 +775,15 @@ static int get_qp(const VVCFrameContext *fc, const uint8_t *src, const int x, co static void vvc_deblock(const VVCLocalContext *lc, int x0, int y0, const int rs, const int vertical) { - VVCFrameContext *fc = lc->fc; - const VVCSPS *sps = fc->ps.sps; - const int c_end = sps->r->sps_chroma_format_idc ? VVC_MAX_SAMPLE_ARRAYS : 1; - const int ctb_size = fc->ps.sps->ctb_size_y; - const DBParams *params = fc->tab.deblock + rs; - int x_end = FFMIN(x0 + ctb_size, fc->ps.pps->width); - int y_end = FFMIN(y0 + ctb_size, fc->ps.pps->height); - - //not use this yet, may needed by plt. - const uint8_t no_p[4] = { 0 }; - const uint8_t no_q[4] = { 0 } ; - - vvc_deblock_bs(lc, x0, y0, rs, vertical); + VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const int c_end = sps->r->sps_chroma_format_idc ? VVC_MAX_SAMPLE_ARRAYS : 1; + const int ctb_size = fc->ps.sps->ctb_size_y; + const DBParams *params = fc->tab.deblock + rs; + int x_end = FFMIN(x0 + ctb_size, fc->ps.pps->width); + int y_end = FFMIN(y0 + ctb_size, fc->ps.pps->height); + const int log2_min_cb_size = fc->ps.sps->min_cb_log2_size_y; + const int min_cb_width = fc->ps.pps->min_cb_width; if (!vertical) { FFSWAP(int, x_end, y_end); @@ -815,6 +803,8 @@ static void vvc_deblock(const VVCLocalContext *lc, int x0, int y0, const int rs, const uint8_t horizontal_ctu_edge = !vertical && !(x % ctb_size); int32_t bs[4], beta[4], tc[4] = { 0 }, all_zero_bs = 1; uint8_t max_len_p[4], max_len_q[4]; + uint8_t no_p[4] = { 0 }; + uint8_t no_q[4] = { 0 }; for (int i = 0; i < DEBLOCK_STEP >> (2 - vs); i++) { int tx = x; @@ -831,6 +821,13 @@ static void vvc_deblock(const VVCLocalContext *lc, int x0, int y0, const int rs, tc[i] = TC_CALC(qp, bs[i]) ; max_filter_length(fc, tx, ty, c_idx, vertical, horizontal_ctu_edge, bs[i], &max_len_p[i], &max_len_q[i]); all_zero_bs = 0; + + if (sps->r->sps_palette_enabled_flag) { + const int cu_q = (ty >> log2_min_cb_size) * min_cb_width + (tx >> log2_min_cb_size); + const int cu_p = (ty - !vertical >> log2_min_cb_size) * min_cb_width + (tx - vertical >> log2_min_cb_size); + no_q[i] = fc->tab.cpm[!!c_idx][cu_q] == MODE_PLT; + no_p[i] = cu_p >= 0 && fc->tab.cpm[!!c_idx][cu_p] == MODE_PLT; + } } } diff --git a/libavcodec/vvc/filter.h b/libavcodec/vvc/filter.h index 03cc74e07..29abbd98c 100644 --- a/libavcodec/vvc/filter.h +++ b/libavcodec/vvc/filter.h @@ -33,6 +33,15 @@ */ void ff_vvc_lmcs_filter(const VVCLocalContext *lc, const int x0, const int y0); +/** + * derive boundary strength for the CTU + * @param lc local context for CTU + * @param rx raster x position for the CTU + * @param ry raster y position for the CTU + * @param rs raster position for the CTU + */ +void ff_vvc_deblock_bs(VVCLocalContext *lc, const int rx, const int ry, const int rs); + /** * vertical deblock filter for the CTU * @param lc local context for CTU diff --git a/libavcodec/vvc/inter.c b/libavcodec/vvc/inter.c index 64a9dd1e4..7d6e79e49 100644 --- a/libavcodec/vvc/inter.c +++ b/libavcodec/vvc/inter.c @@ -217,34 +217,37 @@ static int derive_weight_uni(int *denom, int *wx, int *ox, } // part of 8.5.6.6 Weighted sample prediction process -static int derive_weight(int *denom, int *w0, int *w1, int *o0, int *o1, - const VVCLocalContext *lc, const MvField *mvf, const int c_idx, const int dmvr_flag) +static void apply_averaging(uint8_t *dst, const ptrdiff_t dst_stride, + const int16_t *src0, const int16_t *src1, int width, int height, + const VVCLocalContext *lc, const MvField *mvf, const int c_idx, const int dmvr_flag) { const VVCFrameContext *fc = lc->fc; const VVCPPS *pps = fc->ps.pps; const VVCSH *sh = &lc->sc->sh; const int bcw_idx = mvf->bcw_idx; - const int weight_flag = (IS_P(sh->r) && pps->r->pps_weighted_pred_flag) || - (IS_B(sh->r) && pps->r->pps_weighted_bipred_flag && !dmvr_flag); - if ((!weight_flag && !bcw_idx) || (bcw_idx && lc->cu->ciip_flag)) - return 0; + av_assert2(IS_B(sh->r)); + const int weight_flag = pps->r->pps_weighted_bipred_flag && !dmvr_flag; + if ((!weight_flag && !bcw_idx) || (bcw_idx && lc->cu->ciip_flag)) { + fc->vvcdsp.inter.avg(dst, dst_stride, src0, src1, width, height); + return; + } + int denom, w0, w1, o; if (bcw_idx) { - *denom = 2; - *w1 = bcw_w_lut[bcw_idx]; - *w0 = 8 - *w1; - *o0 = *o1 = 0; + denom = 2; + w1 = bcw_w_lut[bcw_idx]; + w0 = 8 - w1; + o = 0; } else { - const VVCPPS *pps = fc->ps.pps; const PredWeightTable *w = pps->r->pps_wp_info_in_ph_flag ? &fc->ps.ph.pwt : &sh->pwt; - *denom = w->log2_denom[c_idx > 0]; - *w0 = w->weight[L0][c_idx][mvf->ref_idx[L0]]; - *w1 = w->weight[L1][c_idx][mvf->ref_idx[L1]]; - *o0 = w->offset[L0][c_idx][mvf->ref_idx[L0]]; - *o1 = w->offset[L1][c_idx][mvf->ref_idx[L1]]; + denom = w->log2_denom[c_idx > 0]; + w0 = w->weight[L0][c_idx][mvf->ref_idx[L0]]; + w1 = w->weight[L1][c_idx][mvf->ref_idx[L1]]; + o = w->offset[L0][c_idx][mvf->ref_idx[L0]] + + w->offset[L1][c_idx][mvf->ref_idx[L1]]; } - return 1; + fc->vvcdsp.inter.w_avg(dst, dst_stride, src0, src1, width, height, denom, w0, w1, o); } #define INTER_FILTER(t, frac) (is_chroma ? ff_vvc_inter_chroma_filters[t][frac] : ff_vvc_inter_luma_filters[t][frac]) @@ -321,8 +324,6 @@ static void mc_bi(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, const int idx = av_log2(block_w) - 1; const VVCFrame *refs[] = { ref0, ref1 }; int16_t *tmp[] = { lc->tmp + sb_bdof_flag * PROF_TEMP_OFFSET, lc->tmp1 + sb_bdof_flag * PROF_TEMP_OFFSET }; - int denom, w0, w1, o0, o1; - const int weight_flag = derive_weight(&denom, &w0, &w1, &o0, &o1, lc, mvf, c_idx, pu->dmvr_flag); const int is_chroma = !!c_idx; const int hpel_if_idx = is_chroma ? 0 : pu->mi.hpel_if_idx; @@ -353,10 +354,9 @@ static void mc_bi(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, } if (sb_bdof_flag) fc->vvcdsp.inter.apply_bdof(dst, dst_stride, tmp[L0], tmp[L1], block_w, block_h); - else if (weight_flag) - fc->vvcdsp.inter.w_avg(dst, dst_stride, tmp[L0], tmp[L1], block_w, block_h, denom, w0, w1, o0, o1); else - fc->vvcdsp.inter.avg(dst, dst_stride, tmp[L0], tmp[L1], block_w, block_h); + apply_averaging(dst, dst_stride, tmp[L0], tmp[L1], block_w, block_h, + lc, mvf, c_idx, pu->dmvr_flag); } static const int8_t* inter_filter_scaled(const int scale, const int is_chroma, const int is_affine) @@ -469,9 +469,6 @@ static void mc_bi_scaled(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_ const VVCRefPic *refp0, const VVCRefPic *refp1, const MvField *mvf, const int x_off, const int y_off, const int block_w, const int block_h, const int c_idx) { - int denom, w0, w1, o0, o1; - const VVCFrameContext *fc = lc->fc; - const int weight_flag = derive_weight(&denom, &w0, &w1, &o0, &o1, lc, mvf, c_idx, lc->cu->pu.dmvr_flag); const VVCRefPic *refps[] = { refp0, refp1 }; int16_t *tmp[] = { lc->tmp, lc->tmp1 }; @@ -484,10 +481,8 @@ static void mc_bi_scaled(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_ else mc(lc, tmp[i], refp->ref, mv, x_off, y_off, block_w, block_h, c_idx); } - if (weight_flag) - fc->vvcdsp.inter.w_avg(dst, dst_stride, tmp[L0], tmp[L1], block_w, block_h, denom, w0, w1, o0, o1); - else - fc->vvcdsp.inter.avg(dst, dst_stride, tmp[L0], tmp[L1], block_w, block_h); + apply_averaging(dst, dst_stride, tmp[L0], tmp[L1], block_w, block_h, + lc, mvf, c_idx, lc->cu->pu.dmvr_flag); } static void luma_prof_uni(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, @@ -561,11 +556,8 @@ static void luma_prof_bi(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_ const VVCRefPic *ref0, const VVCRefPic *ref1, const MvField *mvf, const int x_off, const int y_off, const int block_w, const int block_h) { - const VVCFrameContext *fc = lc->fc; const VVCRefPic *refps[] = { ref0, ref1 }; int16_t *tmp[] = { lc->tmp, lc->tmp1 }; - int denom, w0, w1, o0, o1; - const int weight_flag = derive_weight(&denom, &w0, &w1, &o0, &o1, lc, mvf, LUMA, 0); for (int i = L0; i <= L1; i++) { const VVCRefPic *refp = refps[i]; @@ -577,10 +569,7 @@ static void luma_prof_bi(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_ luma_prof(lc, tmp[i], refp->ref, mv, x_off, y_off, block_w, block_h, i); } - if (weight_flag) - fc->vvcdsp.inter.w_avg(dst, dst_stride, tmp[L0], tmp[L1], block_w, block_h, denom, w0, w1, o0, o1); - else - fc->vvcdsp.inter.avg(dst, dst_stride, tmp[L0], tmp[L1], block_w, block_h); + apply_averaging(dst, dst_stride, tmp[L0], tmp[L1], block_w, block_h, lc, mvf, LUMA, 0); } static int pred_get_refs(const VVCLocalContext *lc, VVCRefPic *refp[2], const MvField *mv) diff --git a/libavcodec/vvc/inter_template.c b/libavcodec/vvc/inter_template.c index c073a73e7..efa432d1f 100644 --- a/libavcodec/vvc/inter_template.c +++ b/libavcodec/vvc/inter_template.c @@ -201,12 +201,12 @@ static void FUNC(avg)(uint8_t *_dst, const ptrdiff_t _dst_stride, static void FUNC(w_avg)(uint8_t *_dst, const ptrdiff_t _dst_stride, const int16_t *src0, const int16_t *src1, const int width, const int height, - const int denom, const int w0, const int w1, const int o0, const int o1) + const int denom, const int w0, const int w1, const int o) { pixel *dst = (pixel*)_dst; const ptrdiff_t dst_stride = _dst_stride / sizeof(pixel); const int shift = denom + FFMAX(3, 15 - BIT_DEPTH); - const int offset = ((o0 + o1) * (1 << (BIT_DEPTH - 8)) + 1) * (1 << (shift - 1)); + const int offset = (o * (1 << (BIT_DEPTH - 8)) + 1) * (1 << (shift - 1)); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) @@ -472,6 +472,9 @@ static void FUNC(apply_bdof)(uint8_t *_dst, const ptrdiff_t _dst_stride, const i (filter[0] * src[x] + \ filter[1] * src[x + stride]) +#define DMVR_FILTER2(filter, src0, src1) \ + (filter[0] * src0 + filter[1] * src1) + //8.5.3.2.2 Luma sample bilinear interpolation process static void FUNC(dmvr)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, const int height, const intptr_t mx, const intptr_t my, const int width) @@ -541,31 +544,31 @@ static void FUNC(dmvr_v)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src static void FUNC(dmvr_hv)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, const int height, const intptr_t mx, const intptr_t my, const int width) { - int16_t tmp_array[(MAX_PB_SIZE + BILINEAR_EXTRA) * MAX_PB_SIZE]; - int16_t *tmp = tmp_array; + int16_t tmp_array[MAX_PB_SIZE * 2]; + int16_t *tmp0 = tmp_array; + int16_t *tmp1 = tmp_array + MAX_PB_SIZE; const pixel *src = (const pixel*)_src; const ptrdiff_t src_stride = _src_stride / sizeof(pixel); - const int8_t *filter = ff_vvc_inter_luma_dmvr_filters[mx]; + const int8_t *filter_x = ff_vvc_inter_luma_dmvr_filters[mx]; + const int8_t *filter_y = ff_vvc_inter_luma_dmvr_filters[my]; const int shift1 = BIT_DEPTH - 6; const int offset1 = 1 << (shift1 - 1); const int shift2 = 4; const int offset2 = 1 << (shift2 - 1); src -= BILINEAR_EXTRA_BEFORE * src_stride; - for (int y = 0; y < height + BILINEAR_EXTRA; y++) { - for (int x = 0; x < width; x++) - tmp[x] = (DMVR_FILTER(src, 1) + offset1) >> shift1; - src += src_stride; - tmp += MAX_PB_SIZE; - } + for (int x = 0; x < width; x++) + tmp0[x] = (DMVR_FILTER2(filter_x, src[x], src[x + 1]) + offset1) >> shift1; + src += src_stride; - tmp = tmp_array + BILINEAR_EXTRA_BEFORE * MAX_PB_SIZE; - filter = ff_vvc_inter_luma_dmvr_filters[my]; - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) - dst[x] = (DMVR_FILTER(tmp, MAX_PB_SIZE) + offset2) >> shift2; - tmp += MAX_PB_SIZE; + for (int y = 1; y < height + BILINEAR_EXTRA; y++) { + for (int x = 0; x < width; x++) { + tmp1[x] = (DMVR_FILTER2(filter_x, src[x], src[x + 1]) + offset1) >> shift1; + dst[x] = (DMVR_FILTER2(filter_y, tmp0[x], tmp1[x]) + offset2) >> shift2; + } + src += src_stride; dst += MAX_PB_SIZE; + FFSWAP(int16_t *, tmp0, tmp1); } } diff --git a/libavcodec/vvc/intra.c b/libavcodec/vvc/intra.c index e04129d3b..eccd8ee4c 100644 --- a/libavcodec/vvc/intra.c +++ b/libavcodec/vvc/intra.c @@ -27,6 +27,10 @@ #include "intra.h" #include "itx_1d.h" +#define POS(c_idx, x, y) \ + &fc->frame->data[c_idx][((y) >> fc->ps.sps->vshift[c_idx]) * fc->frame->linesize[c_idx] + \ + (((x) >> fc->ps.sps->hshift[c_idx]) << fc->ps.sps->pixel_shift)] + static int is_cclm(enum IntraPredMode mode) { return mode == INTRA_LT_CCLM || mode == INTRA_L_CCLM || mode == INTRA_T_CCLM; @@ -164,28 +168,6 @@ static void derive_transform_type(const VVCFrameContext *fc, const VVCLocalConte *trv = mts_to_trv[cu->mts_idx]; } -static void add_residual_for_joint_coding_chroma(VVCLocalContext *lc, - const TransformUnit *tu, TransformBlock *tb, const int chroma_scale) -{ - const VVCFrameContext *fc = lc->fc; - const CodingUnit *cu = lc->cu; - const int c_sign = 1 - 2 * fc->ps.ph.r->ph_joint_cbcr_sign_flag; - const int shift = tu->coded_flag[1] ^ tu->coded_flag[2]; - const int c_idx = 1 + tu->coded_flag[1]; - const ptrdiff_t stride = fc->frame->linesize[c_idx]; - const int hs = fc->ps.sps->hshift[c_idx]; - const int vs = fc->ps.sps->vshift[c_idx]; - uint8_t *dst = &fc->frame->data[c_idx][(tb->y0 >> vs) * stride + - ((tb->x0 >> hs) << fc->ps.sps->pixel_shift)]; - if (chroma_scale) { - fc->vvcdsp.itx.pred_residual_joint(tb->coeffs, tb->tb_width, tb->tb_height, c_sign, shift); - fc->vvcdsp.intra.lmcs_scale_chroma(lc, tb->coeffs, tb->coeffs, tb->tb_width, tb->tb_height, cu->x0, cu->y0); - fc->vvcdsp.itx.add_residual(dst, tb->coeffs, tb->tb_width, tb->tb_height, stride); - } else { - fc->vvcdsp.itx.add_residual_joint(dst, tb->coeffs, tb->tb_width, tb->tb_height, stride, c_sign, shift); - } -} - static int add_reconstructed_area(VVCLocalContext *lc, const int ch_type, const int x0, const int y0, const int w, const int h) { const VVCSPS *sps = lc->fc->ps.sps; @@ -243,21 +225,23 @@ static int get_chroma_predict_unit(const CodingUnit *cu, const TransformUnit *tu } //8.4.5.1 General decoding process for intra blocks -static void predict_intra(VVCLocalContext *lc, const TransformUnit *tu, const int idx, const int target_ch_type) +static int predict_intra(VVCLocalContext *lc, const TransformUnit *tu, const int idx, const int target_ch_type) { const VVCFrameContext *fc = lc->fc; const CodingUnit *cu = lc->cu; const VVCTreeType tree_type = cu->tree_type; - int x0, y0, w, h; + int x0, y0, w, h, ret; if (cu->pred_mode != MODE_INTRA) { - add_reconstructed_area(lc, target_ch_type, tu->x0, tu->y0, tu->width, tu->height); - return; + ret = add_reconstructed_area(lc, target_ch_type, tu->x0, tu->y0, tu->width, tu->height); + return ret; } if (!target_ch_type && tree_type != DUAL_TREE_CHROMA) { if (get_luma_predict_unit(cu, tu, idx, &x0, &y0, &w, &h)) { ff_vvc_set_neighbour_available(lc, x0, y0, w, h); fc->vvcdsp.intra.intra_pred(lc, x0, y0, w, h, 0); - add_reconstructed_area(lc, 0, x0, y0, w, h); + ret = add_reconstructed_area(lc, 0, x0, y0, w, h); + if (ret < 0) + return ret; } } if (target_ch_type && tree_type != DUAL_TREE_LUMA) { @@ -269,9 +253,12 @@ static void predict_intra(VVCLocalContext *lc, const TransformUnit *tu, const in fc->vvcdsp.intra.intra_pred(lc, x0, y0, w, h, 1); fc->vvcdsp.intra.intra_pred(lc, x0, y0, w, h, 2); } - add_reconstructed_area(lc, 1, x0, y0, w, h); + ret = add_reconstructed_area(lc, 1, x0, y0, w, h); + if (ret < 0) + return ret; } } + return 0; } static void scale_clip(int *coeff, const int nzw, const int w, const int h, @@ -303,21 +290,15 @@ static void scale(int *out, const int *in, const int w, const int h, const int s // part of 8.7.3 Scaling process for transform coefficients static void derive_qp(const VVCLocalContext *lc, const TransformUnit *tu, TransformBlock *tb) { - const VVCSPS *sps = lc->fc->ps.sps; - const H266RawSliceHeader *rsh = lc->sc->sh.r; - const CodingUnit *cu = lc->cu; - int qp, qp_act_offset; + const VVCSPS *sps = lc->fc->ps.sps; + const H266RawSliceHeader *rsh = lc->sc->sh.r; + const CodingUnit *cu = lc->cu; + const bool is_jcbcr = tb->c_idx && tu->joint_cbcr_residual_flag && tu->coded_flag[CB] && tu->coded_flag[CR]; + const int idx = is_jcbcr ? JCBCR : tb->c_idx; + const int qp = cu->qp[idx] + (idx ? 0 : sps->qp_bd_offset); + const int act_offset[] = { -5, 1, 3, 1 }; + const int qp_act_offset = cu->act_enabled_flag ? act_offset[idx] : 0; - if (tb->c_idx == 0) { - //fix me - qp = cu->qp[LUMA] + sps->qp_bd_offset; - qp_act_offset = cu->act_enabled_flag ? -5 : 0; - } else { - const int is_jcbcr = tu->joint_cbcr_residual_flag && tu->coded_flag[CB] && tu->coded_flag[CR]; - const int idx = is_jcbcr ? JCBCR : tb->c_idx; - qp = cu->qp[idx]; - qp_act_offset = cu->act_enabled_flag ? 1 : 0; - } if (tb->ts) { const int qp_prime_ts_min = 4 + 6 * sps->r->sps_min_qp_prime_ts; @@ -336,29 +317,30 @@ static void derive_qp(const VVCLocalContext *lc, const TransformUnit *tu, Transf tb->bd_offset = (1 << tb->bd_shift) >> 1; } +static const uint8_t rem6[63 + 8 * 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, 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, +}; + +static const uint8_t div6[63 + 8 * 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, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, +}; + +const static int level_scale[2][6] = { + { 40, 45, 51, 57, 64, 72 }, + { 57, 64, 72, 80, 90, 102 } +}; + //8.7.3 Scaling process for transform coefficients static av_always_inline int derive_scale(const TransformBlock *tb, const int sh_dep_quant_used_flag) { - static const uint8_t rem6[63 + 8 * 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, 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, - }; - - static const uint8_t div6[63 + 8 * 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, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, - 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, - }; - - const static int level_scale[2][6] = { - { 40, 45, 51, 57, 64, 72 }, - { 57, 64, 72, 80, 90, 102 } - }; const int addin = sh_dep_quant_used_flag && !tb->ts; const int qp = tb->qp + addin; @@ -515,29 +497,67 @@ static void transform_bdpcm(TransformBlock *tb, const VVCLocalContext *lc, const tb->max_scan_x = tb->tb_width - 1; } -static void itransform(VVCLocalContext *lc, TransformUnit *tu, const int tu_idx, const int target_ch_type) +static void lmcs_scale_chroma(VVCLocalContext *lc, TransformUnit *tu, TransformBlock *tb, const int target_ch_type) { - const VVCFrameContext *fc = lc->fc; - const VVCSPS *sps = fc->ps.sps; - const VVCSH *sh = &lc->sc->sh; - const CodingUnit *cu = lc->cu; - const int ps = fc->ps.sps->pixel_shift; - DECLARE_ALIGNED(32, int, temp)[MAX_TB_SIZE * MAX_TB_SIZE]; + const VVCFrameContext *fc = lc->fc; + const VVCSH *sh = &lc->sc->sh; + const CodingUnit *cu = lc->cu; + const int c_idx = tb->c_idx; + const int ch_type = c_idx > 0; + const int w = tb->tb_width; + const int h = tb->tb_height; + const int chroma_scale = ch_type && sh->r->sh_lmcs_used_flag && fc->ps.ph.r->ph_chroma_residual_scale_flag && (w * h > 4); + const int has_jcbcr = tu->joint_cbcr_residual_flag && c_idx; + + for (int j = 0; j < 1 + has_jcbcr; j++) { + const bool is_jcbcr = j > 0; + const int jcbcr_idx = CB + tu->coded_flag[CB]; + TransformBlock *jcbcr = &tu->tbs[jcbcr_idx - tu->tbs[0].c_idx]; + int *coeffs = is_jcbcr ? jcbcr->coeffs : tb->coeffs; + + if (!j && has_jcbcr) { + const int c_sign = 1 - 2 * fc->ps.ph.r->ph_joint_cbcr_sign_flag; + const int shift = tu->coded_flag[CB] ^ tu->coded_flag[CR]; + fc->vvcdsp.itx.pred_residual_joint(jcbcr->coeffs, tb->coeffs, w, h, c_sign, shift); + } + if (chroma_scale) + fc->vvcdsp.intra.lmcs_scale_chroma(lc, coeffs, w, h, cu->x0, cu->y0); + } +} + +static void add_residual(const VVCLocalContext *lc, TransformUnit *tu, const int target_ch_type) +{ + const VVCFrameContext *fc = lc->fc; + const CodingUnit *cu = lc->cu; for (int i = 0; i < tu->nb_tbs; i++) { - TransformBlock *tb = &tu->tbs[i]; - const int c_idx = tb->c_idx; - const int ch_type = c_idx > 0; + TransformBlock *tb = tu->tbs + i; + const int c_idx = tb->c_idx; + const int ch_type = c_idx > 0; + const ptrdiff_t stride = fc->frame->linesize[c_idx]; + const bool has_residual = tb->has_coeffs || cu->act_enabled_flag || + (c_idx && tu->joint_cbcr_residual_flag); + uint8_t *dst = POS(c_idx, tb->x0, tb->y0); - if (ch_type == target_ch_type && tb->has_coeffs) { - const int w = tb->tb_width; - const int h = tb->tb_height; - const int chroma_scale = ch_type && sh->r->sh_lmcs_used_flag && fc->ps.ph.r->ph_chroma_residual_scale_flag && (w * h > 4); - const ptrdiff_t stride = fc->frame->linesize[c_idx]; - const int hs = sps->hshift[c_idx]; - const int vs = sps->vshift[c_idx]; - uint8_t *dst = &fc->frame->data[c_idx][(tb->y0 >> vs) * stride + ((tb->x0 >> hs) << ps)]; + if (ch_type == target_ch_type && has_residual) + fc->vvcdsp.itx.add_residual(dst, tb->coeffs, tb->tb_width, tb->tb_height, stride); + } +} +static void itransform(VVCLocalContext *lc, TransformUnit *tu, const int target_ch_type) +{ + const VVCFrameContext *fc = lc->fc; + const CodingUnit *cu = lc->cu; + TransformBlock *tbs = tu->tbs; + const bool is_act_luma = cu->act_enabled_flag && target_ch_type == LUMA; + + for (int i = 0; i < tu->nb_tbs; i++) { + TransformBlock *tb = tbs + i; + const int c_idx = tb->c_idx; + const int ch_type = c_idx > 0; + const bool do_itx = is_act_luma || !cu->act_enabled_flag && ch_type == target_ch_type; + + if (tb->has_coeffs && do_itx) { if (cu->bdpcm_flag[tb->c_idx]) transform_bdpcm(tb, lc, cu); dequant(lc, tu, tb); @@ -547,22 +567,22 @@ static void itransform(VVCLocalContext *lc, TransformUnit *tu, const int tu_idx, if (cu->apply_lfnst_flag[c_idx]) ilfnst_transform(lc, tb); derive_transform_type(fc, lc, tb, &trh, &trv); - if (w > 1 && h > 1) + if (tb->tb_width > 1 && tb->tb_height > 1) itx_2d(fc, tb, trh, trv); else itx_1d(fc, tb, trh, trv); } - - if (chroma_scale) - fc->vvcdsp.intra.lmcs_scale_chroma(lc, temp, tb->coeffs, w, h, cu->x0, cu->y0); - // TODO: Address performance issue here by combining transform, lmcs_scale_chroma, and add_residual into one function. - // Complete this task before implementing ASM code. - fc->vvcdsp.itx.add_residual(dst, chroma_scale ? temp : tb->coeffs, w, h, stride); - - if (tu->joint_cbcr_residual_flag && tb->c_idx) - add_residual_for_joint_coding_chroma(lc, tu, tb, chroma_scale); + lmcs_scale_chroma(lc, tu, tb, target_ch_type); } } + + if (is_act_luma) { + fc->vvcdsp.itx.adaptive_color_transform( + tbs[LUMA].coeffs, tbs[CB].coeffs, tbs[CR].coeffs, + tbs[LUMA].tb_width, tbs[LUMA].tb_height); + } + + add_residual(lc, tu, target_ch_type); } static int reconstruct(VVCLocalContext *lc) @@ -571,22 +591,21 @@ static int reconstruct(VVCLocalContext *lc) CodingUnit *cu = lc->cu; const int start = cu->tree_type == DUAL_TREE_CHROMA; const int end = fc->ps.sps->r->sps_chroma_format_idc && (cu->tree_type != DUAL_TREE_LUMA); + int ret; for (int ch_type = start; ch_type <= end; ch_type++) { TransformUnit *tu = cu->tus.head; for (int i = 0; tu; i++) { - predict_intra(lc, tu, i, ch_type); - itransform(lc, tu, i, ch_type); + ret = predict_intra(lc, tu, i, ch_type); + if (ret < 0) + return ret; + itransform(lc, tu, ch_type); tu = tu->next; } } return 0; } -#define POS(c_idx, x, y) \ - &fc->frame->data[c_idx][((y) >> fc->ps.sps->vshift[c_idx]) * fc->frame->linesize[c_idx] + \ - (((x) >> fc->ps.sps->hshift[c_idx]) << fc->ps.sps->pixel_shift)] - #define IBC_POS(c_idx, x, y) \ (fc->tab.ibc_vir_buf[c_idx] + \ (x << ps) + (y + ((cu->y0 & ~(sps->ctb_size_y - 1)) >> vs)) * ibc_stride) @@ -639,11 +658,11 @@ static void ibc_fill_vir_buf(const VVCLocalContext *lc, const CodingUnit *cu) { const VVCFrameContext *fc = lc->fc; const VVCSPS *sps = fc->ps.sps; - const int has_chroma = sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA; - const int start = cu->tree_type == DUAL_TREE_CHROMA; - const int end = has_chroma ? CR : LUMA; + int start, end; - for (int c_idx = start; c_idx <= end; c_idx++) { + ff_vvc_channel_range(&start, &end, cu->tree_type, sps->r->sps_chroma_format_idc); + + for (int c_idx = start; c_idx < end; c_idx++) { const int hs = sps->hshift[c_idx]; const int vs = sps->vshift[c_idx]; const int ps = sps->pixel_shift; @@ -658,6 +677,38 @@ static void ibc_fill_vir_buf(const VVCLocalContext *lc, const CodingUnit *cu) } } +int ff_vvc_palette_derive_scale(VVCLocalContext *lc, const TransformUnit *tu, TransformBlock *tb) +{ + const VVCSPS *sps = lc->fc->ps.sps; + const int qp_prime_ts_min = 4 + 6 * sps->r->sps_min_qp_prime_ts; + int qp; + + derive_qp(lc, tu, tb); + qp = FFMAX(qp_prime_ts_min, tb->qp); + return level_scale[0][rem6[qp]] << div6[qp]; +} + +// 8.4.5.3 Decoding process for palette mode +static void vvc_predict_palette(VVCLocalContext *lc) +{ + const VVCFrameContext *fc = lc->fc; + const CodingUnit *cu = lc->cu; + TransformUnit *tu = cu->tus.head; + const VVCSPS *sps = fc->ps.sps; + const int ps = sps->pixel_shift; + + for (int i = 0; i < tu->nb_tbs; i++) { + TransformBlock *tb = &tu->tbs[i]; + const int c_idx = tb->c_idx; + const int w = tb->tb_width; + const int h = tb->tb_height; + const ptrdiff_t stride = fc->frame->linesize[c_idx]; + uint8_t *dst = POS(c_idx, cu->x0, cu->y0); + + av_image_copy_plane(dst, stride, (uint8_t*)tb->coeffs, w << ps, w << ps, h); + } +} + int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const int ry) { const VVCFrameContext *fc = lc->fc; @@ -678,13 +729,21 @@ int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const in ff_vvc_predict_ciip(lc); else if (cu->pred_mode == MODE_IBC) vvc_predict_ibc(lc); + else if (cu->pred_mode == MODE_PLT) + vvc_predict_palette(lc); if (cu->coded_flag) { ret = reconstruct(lc); } else { - if (cu->tree_type != DUAL_TREE_CHROMA) - add_reconstructed_area(lc, LUMA, cu->x0, cu->y0, cu->cb_width, cu->cb_height); - if (sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA) - add_reconstructed_area(lc, CHROMA, cu->x0, cu->y0, cu->cb_width, cu->cb_height); + if (cu->tree_type != DUAL_TREE_CHROMA) { + ret = add_reconstructed_area(lc, LUMA, cu->x0, cu->y0, cu->cb_width, cu->cb_height); + if (ret < 0) + return ret; + } + if (sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA) { + ret = add_reconstructed_area(lc, CHROMA, cu->x0, cu->y0, cu->cb_width, cu->cb_height); + if (ret < 0) + return ret; + } } if (sps->r->sps_ibc_enabled_flag) ibc_fill_vir_buf(lc, cu); diff --git a/libavcodec/vvc/intra.h b/libavcodec/vvc/intra.h index 8a0269913..1201c7083 100644 --- a/libavcodec/vvc/intra.h +++ b/libavcodec/vvc/intra.h @@ -45,5 +45,6 @@ int ff_vvc_intra_pred_angle_derive(int pred_mode); int ff_vvc_intra_inv_angle_derive(int pred_mode); int ff_vvc_wide_angle_mode_mapping(const CodingUnit *cu, int tb_width, int tb_height, int c_idx, int pred_mode_intra); +int ff_vvc_palette_derive_scale(VVCLocalContext *lc, const TransformUnit *tu, TransformBlock *tb); #endif // AVCODEC_VVC_INTRA_H diff --git a/libavcodec/vvc/intra_template.c b/libavcodec/vvc/intra_template.c index 62342c814..3ec6c7221 100644 --- a/libavcodec/vvc/intra_template.c +++ b/libavcodec/vvc/intra_template.c @@ -428,7 +428,7 @@ static int FUNC(lmcs_derive_chroma_scale)(VVCLocalContext *lc, const int x0, con } // 8.7.5.3 Picture reconstruction with luma dependent chroma residual scaling process for chroma samples -static void FUNC(lmcs_scale_chroma)(VVCLocalContext *lc, int *dst, const int *coeff, +static void FUNC(lmcs_scale_chroma)(VVCLocalContext *lc, int *coeff, const int width, const int height, const int x0_cu, const int y0_cu) { const int chroma_scale = FUNC(lmcs_derive_chroma_scale)(lc, x0_cu, y0_cu); @@ -438,11 +438,10 @@ static void FUNC(lmcs_scale_chroma)(VVCLocalContext *lc, int *dst, const int *co const int c = av_clip_intp2(*coeff, BIT_DEPTH); if (c > 0) - *dst = (c * chroma_scale + (1 << 10)) >> 11; + *coeff = (c * chroma_scale + (1 << 10)) >> 11; else - *dst = -((-c * chroma_scale + (1 << 10)) >> 11); + *coeff = -((-c * chroma_scale + (1 << 10)) >> 11); coeff++; - dst++; } } } @@ -627,8 +626,9 @@ static void FUNC(intra_pred)(const VVCLocalContext *lc, int x0, int y0, FUNC(prepare_intra_edge_params)(lc, &edge, src, stride, x, y, w, h, c_idx, is_intra_mip, mode, ref_idx, need_pdpc); if (is_intra_mip) { - int intra_mip_transposed_flag = SAMPLE_CTB(fc->tab.imtf, x_cb, y_cb); - int intra_mip_mode = SAMPLE_CTB(fc->tab.imm, x_cb, y_cb); + int intra_mip_transposed_flag; + int intra_mip_mode; + unpack_mip_info(&intra_mip_transposed_flag, &intra_mip_mode, intra_mip_flag); fc->vvcdsp.intra.pred_mip((uint8_t *)src, edge.top, edge.left, w, h, stride, intra_mip_mode, intra_mip_transposed_flag); diff --git a/libavcodec/vvc/intra_utils.c b/libavcodec/vvc/intra_utils.c index 8c40eb1b1..e44c3dcd0 100644 --- a/libavcodec/vvc/intra_utils.c +++ b/libavcodec/vvc/intra_utils.c @@ -184,16 +184,16 @@ int ff_vvc_intra_pred_angle_derive(const int pred_mode) return intra_pred_angle; } -#define ROUND(f) (int)(f < 0 ? -(-f + 0.5) : (f + 0.5)) int ff_vvc_intra_inv_angle_derive(const int intra_pred_angle) { - float inv_angle; - av_assert0(intra_pred_angle); - inv_angle = 32 * 512.0 / intra_pred_angle; - return ROUND(inv_angle); + av_assert2(intra_pred_angle != 0); + if (intra_pred_angle > 0) + return ROUNDED_DIV(32*512, intra_pred_angle); + else + return -ROUNDED_DIV(32*512, -intra_pred_angle); } -//8.4.5.2.7 Wide angle intra prediction mode mapping proces +//8.4.5.2.7 Wide angle intra prediction mode mapping process int ff_vvc_wide_angle_mode_mapping(const CodingUnit *cu, const int tb_width, const int tb_height, const int c_idx, int pred_mode_intra) { diff --git a/libavcodec/vvc/mvs.c b/libavcodec/vvc/mvs.c index 86ad31003..955fe4b9f 100644 --- a/libavcodec/vvc/mvs.c +++ b/libavcodec/vvc/mvs.c @@ -144,7 +144,9 @@ static int derive_temporal_colocated_mvs(const VVCLocalContext *lc, MvField temp const SliceContext *sc = lc->sc; RefPicList* refPicList = sc->rpl; - if (temp_col.pred_flag == PF_INTRA) + if (temp_col.pred_flag == PF_INTRA || + temp_col.pred_flag == PF_IBC || + temp_col.pred_flag == PF_PLT) return 0; if (sb_flag){ @@ -266,7 +268,7 @@ void ff_vvc_set_mvf(const VVCLocalContext *lc, const int x0, const int y0, const } } -void ff_vvc_set_intra_mvf(const VVCLocalContext *lc, const int dmvr) +void ff_vvc_set_intra_mvf(const VVCLocalContext *lc, const bool dmvr, const PredFlag pf, const bool ciip_flag) { const VVCFrameContext *fc = lc->fc; const CodingUnit *cu = lc->cu; @@ -277,7 +279,10 @@ void ff_vvc_set_intra_mvf(const VVCLocalContext *lc, const int dmvr) for (int dx = 0; dx < cu->cb_width; dx += min_pu_size) { const int x = cu->x0 + dx; const int y = cu->y0 + dy; - TAB_MVF(x, y).pred_flag = PF_INTRA; + MvField *mv = &TAB_MVF(x, y); + + mv->pred_flag = pf; + mv->ciip_flag = ciip_flag; } } } @@ -599,7 +604,19 @@ static void init_neighbour_context(NeighbourContext *ctx, const VVCLocalContext static av_always_inline PredMode pred_flag_to_mode(PredFlag pred) { - return pred == PF_IBC ? MODE_IBC : (pred == PF_INTRA ? MODE_INTRA : MODE_INTER); + static const PredMode lut[] = { + MODE_INTRA, // PF_INTRA + MODE_INTER, // PF_L0 + MODE_INTER, // PF_L1 + MODE_INTER, // PF_BI + 0, // invalid + MODE_IBC, // PF_IBC + 0, // invalid + 0, // invalid + MODE_PLT, // PF_PLT + }; + + return lut[pred]; } static int check_available(Neighbour *n, const VVCLocalContext *lc, const int check_mer) @@ -909,7 +926,7 @@ static void affine_cps_from_nb(const VVCLocalContext *lc, } } -//derive affine neighbour's postion, width and height, +//derive affine neighbour's position, width and height, static int affine_neighbour_cb(const VVCFrameContext *fc, const int x_nb, const int y_nb, int *x_cb, int *y_cb, int *cbw, int *cbh) { const int log2_min_cb_size = fc->ps.sps->min_cb_log2_size_y; @@ -1627,12 +1644,12 @@ static int ibc_spatial_candidates(const VVCLocalContext *lc, const int merge_idx init_neighbour_context(&nctx, lc); - if (check_available(a1, lc, 1)) { + if (check_available(a1, lc, 0)) { cand_list[num_cands++] = TAB_MVF(a1->x, a1->y).mv[L0]; if (num_cands > merge_idx) return 1; } - if (check_available(b1, lc, 1)) { + if (check_available(b1, lc, 0)) { const MvField *mvf = &TAB_MVF(b1->x, b1->y); if (!num_cands || !IS_SAME_MV(&cand_list[0], mvf->mv)) { cand_list[num_cands++] = mvf->mv[L0]; diff --git a/libavcodec/vvc/mvs.h b/libavcodec/vvc/mvs.h index b2242b2a4..7150c0b8c 100644 --- a/libavcodec/vvc/mvs.h +++ b/libavcodec/vvc/mvs.h @@ -43,6 +43,6 @@ void ff_vvc_update_hmvp(VVCLocalContext *lc, const MotionInfo *mi); int ff_vvc_no_backward_pred_flag(const VVCLocalContext *lc); MvField* ff_vvc_get_mvf(const VVCFrameContext *fc, const int x0, const int y0); void ff_vvc_set_mvf(const VVCLocalContext *lc, const int x0, const int y0, const int w, const int h, const MvField *mvf); -void ff_vvc_set_intra_mvf(const VVCLocalContext *lc, int dmvr); +void ff_vvc_set_intra_mvf(const VVCLocalContext *lc, bool dmvr, PredFlag pf, bool ciip_flag); #endif //AVCODEC_VVC_MVS_H diff --git a/libavcodec/vvc/ps.c b/libavcodec/vvc/ps.c index ff9a6c7a1..a59185123 100644 --- a/libavcodec/vvc/ps.c +++ b/libavcodec/vvc/ps.c @@ -20,11 +20,14 @@ * 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 "libavcodec/cbs_h266.h" +#include "libavcodec/decode.h" +#include "libavcodec/h2645data.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" -#include "libavcodec/refstruct.h" +#include "libavutil/refstruct.h" #include "data.h" #include "ps.h" #include "dec.h" @@ -179,12 +182,58 @@ static void sps_ladf(VVCSPS* sps) } } -static int sps_derive(VVCSPS *sps, void *log_ctx) +#define EXTENDED_SAR 255 +static void sps_vui(AVCodecContext *c, const H266RawVUI *vui) +{ + AVRational sar = (AVRational){ 0, 1 }; + if (vui->vui_aspect_ratio_info_present_flag) { + if (vui->vui_aspect_ratio_idc < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) + sar = ff_h2645_pixel_aspect[vui->vui_aspect_ratio_idc]; + else if (vui->vui_aspect_ratio_idc == EXTENDED_SAR) { + sar = (AVRational){ vui->vui_sar_width, vui->vui_sar_height }; + } else { + av_log(c, AV_LOG_WARNING, "Unknown SAR index: %u.\n", vui->vui_aspect_ratio_idc); + } + } + ff_set_sar(c, sar); + + if (vui->vui_colour_description_present_flag) { + c->color_primaries = vui->vui_colour_primaries; + c->color_trc = vui->vui_transfer_characteristics; + c->colorspace = vui->vui_matrix_coeffs; + c->color_range = vui->vui_full_range_flag ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + + // Set invalid values to "unspecified" + if (!av_color_primaries_name(c->color_primaries)) + c->color_primaries = AVCOL_PRI_UNSPECIFIED; + if (!av_color_transfer_name(c->color_trc)) + c->color_trc = AVCOL_TRC_UNSPECIFIED; + if (!av_color_space_name(c->colorspace)) + c->colorspace = AVCOL_SPC_UNSPECIFIED; + } else { + c->color_primaries = AVCOL_PRI_UNSPECIFIED; + c->color_trc = AVCOL_TRC_UNSPECIFIED; + c->colorspace = AVCOL_SPC_UNSPECIFIED; + c->color_range = AVCOL_RANGE_MPEG; + } +} + + +static void sps_export_stream_params(AVCodecContext *c, const VVCSPS *sps) +{ + const H266RawSPS *r = sps->r; + + c->has_b_frames = !!r->sps_dpb_params.dpb_max_num_reorder_pics[r->sps_max_sublayers_minus1]; + if (r->sps_vui_parameters_present_flag) + sps_vui(c, &r->vui); +} + +static int sps_derive(VVCSPS *sps, AVCodecContext *c) { int ret; const H266RawSPS *r = sps->r; - ret = sps_bit_depth(sps, log_ctx); + ret = sps_bit_depth(sps, c); if (ret < 0) return ret; sps_poc(sps); @@ -196,59 +245,63 @@ static int sps_derive(VVCSPS *sps, void *log_ctx) if (ret < 0) return ret; } + sps_export_stream_params(c, sps); return 0; } -static void sps_free(FFRefStructOpaque opaque, void *obj) +static void sps_free(AVRefStructOpaque opaque, void *obj) { VVCSPS *sps = obj; - ff_refstruct_unref(&sps->r); + av_refstruct_unref(&sps->r); } -static const VVCSPS *sps_alloc(const H266RawSPS *rsps, void *log_ctx) +static const VVCSPS *sps_alloc(const H266RawSPS *rsps, AVCodecContext *c) { int ret; - VVCSPS *sps = ff_refstruct_alloc_ext(sizeof(*sps), 0, NULL, sps_free); + VVCSPS *sps = av_refstruct_alloc_ext(sizeof(*sps), 0, NULL, sps_free); if (!sps) return NULL; - ff_refstruct_replace(&sps->r, rsps); + av_refstruct_replace(&sps->r, rsps); - ret = sps_derive(sps, log_ctx); + ret = sps_derive(sps, c); if (ret < 0) goto fail; return sps; fail: - ff_refstruct_unref(&sps); + av_refstruct_unref(&sps); return NULL; } -static int decode_sps(VVCParamSets *ps, const H266RawSPS *rsps, void *log_ctx, int is_clvss) +static int decode_sps(VVCParamSets *ps, AVCodecContext *c, const H266RawSPS *rsps, int is_clvss) { + VVCContext *s = c->priv_data; const int sps_id = rsps->sps_seq_parameter_set_id; const VVCSPS *old_sps = ps->sps_list[sps_id]; const VVCSPS *sps; if (is_clvss) { ps->sps_id_used = 0; + s->seq_decode = (s->seq_decode + 1) & 0xff; } if (old_sps) { - if (old_sps->r == rsps || !memcmp(old_sps->r, rsps, sizeof(*old_sps->r))) + if (old_sps->r == rsps || !memcmp(old_sps->r, rsps, sizeof(*old_sps->r))) { + ps->sps_id_used |= (1 << sps_id); return 0; - else if (ps->sps_id_used & (1 << sps_id)) + } else if (ps->sps_id_used & (1 << sps_id)) return AVERROR_INVALIDDATA; } - sps = sps_alloc(rsps, log_ctx); + sps = sps_alloc(rsps, c); if (!sps) return AVERROR(ENOMEM); - ff_refstruct_unref(&ps->sps_list[sps_id]); + av_refstruct_unref(&ps->sps_list[sps_id]); ps->sps_list[sps_id] = sps; ps->sps_id_used |= (1 << sps_id); @@ -358,6 +411,8 @@ static int pps_add_ctus(VVCPPS *pps, int *off, const int rx, const int ry, int start = *off; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { + if (*off >= pps->ctb_count) + return AVERROR_INVALIDDATA; pps->ctb_addr_in_slice[*off] = ctu_rs(rx + x, ry + y, pps); (*off)++; } @@ -365,15 +420,21 @@ static int pps_add_ctus(VVCPPS *pps, int *off, const int rx, const int ry, return *off - start; } -static void pps_single_slice_picture(VVCPPS *pps, int *off) +static int pps_single_slice_picture(VVCPPS *pps, int *off) { + pps->num_ctus_in_slice[0] = 0; for (int j = 0; j < pps->r->num_tile_rows; j++) { for (int i = 0; i < pps->r->num_tile_columns; i++) { - pps->num_ctus_in_slice[0] = pps_add_ctus(pps, off, + const int ret = pps_add_ctus(pps, off, pps->col_bd[i], pps->row_bd[j], pps->r->col_width_val[i], pps->r->row_height_val[j]); + if (ret < 0) + return ret; + pps->num_ctus_in_slice[0] += ret; } } + + return 0; } static void subpic_tiles(int *tile_x, int *tile_y, int *tile_x_end, int *tile_y_end, @@ -400,25 +461,36 @@ static void subpic_tiles(int *tile_x, int *tile_y, int *tile_x_end, int *tile_y_ (*tile_y_end)++; } -static void pps_subpic_less_than_one_tile_slice(VVCPPS *pps, const VVCSPS *sps, const int i, const int tx, const int ty, int *off) +static int pps_subpic_less_than_one_tile_slice(VVCPPS *pps, const VVCSPS *sps, const int i, const int tx, const int ty, int *off) { - pps->num_ctus_in_slice[i] = pps_add_ctus(pps, off, - pps->col_bd[tx], pps->row_bd[ty], - pps->r->col_width_val[tx], sps->r->sps_subpic_height_minus1[i] + 1); + const int ret = pps_add_ctus(pps, off, + sps->r->sps_subpic_ctu_top_left_x[i], sps->r->sps_subpic_ctu_top_left_y[i], + sps->r->sps_subpic_width_minus1[i] + 1, sps->r->sps_subpic_height_minus1[i] + 1); + if (ret < 0) + return ret; + + pps->num_ctus_in_slice[i] = ret; + return 0; } -static void pps_subpic_one_or_more_tiles_slice(VVCPPS *pps, const int tile_x, const int tile_y, const int x_end, const int y_end, const int i, int *off) +static int pps_subpic_one_or_more_tiles_slice(VVCPPS *pps, const int tile_x, const int tile_y, const int x_end, const int y_end, + const int i, int *off) { for (int ty = tile_y; ty < y_end; ty++) { for (int tx = tile_x; tx < x_end; tx++) { - pps->num_ctus_in_slice[i] += pps_add_ctus(pps, off, + const int ret = pps_add_ctus(pps, off, pps->col_bd[tx], pps->row_bd[ty], pps->r->col_width_val[tx], pps->r->row_height_val[ty]); + if (ret < 0) + return ret; + + pps->num_ctus_in_slice[i] += ret; } } + return 0; } -static void pps_subpic_slice(VVCPPS *pps, const VVCSPS *sps, const int i, int *off) +static int pps_subpic_slice(VVCPPS *pps, const VVCSPS *sps, const int i, int *off) { int tx, ty, x_end, y_end; @@ -427,19 +499,27 @@ static void pps_subpic_slice(VVCPPS *pps, const VVCSPS *sps, const int i, int *o subpic_tiles(&tx, &ty, &x_end, &y_end, sps, pps, i); if (ty + 1 == y_end && sps->r->sps_subpic_height_minus1[i] + 1 < pps->r->row_height_val[ty]) - pps_subpic_less_than_one_tile_slice(pps, sps, i, tx, ty, off); + return pps_subpic_less_than_one_tile_slice(pps, sps, i, tx, ty, off); else - pps_subpic_one_or_more_tiles_slice(pps, tx, ty, x_end, y_end, i, off); + return pps_subpic_one_or_more_tiles_slice(pps, tx, ty, x_end, y_end, i, off); } -static void pps_single_slice_per_subpic(VVCPPS *pps, const VVCSPS *sps, int *off) +static int pps_single_slice_per_subpic(VVCPPS *pps, const VVCSPS *sps, int *off) { + int ret; + if (!sps->r->sps_subpic_info_present_flag) { - pps_single_slice_picture(pps, off); + ret = pps_single_slice_picture(pps, off); + if (ret < 0) + return ret; } else { - for (int i = 0; i < pps->r->pps_num_slices_in_pic_minus1 + 1; i++) - pps_subpic_slice(pps, sps, i, off); + for (int i = 0; i < pps->r->pps_num_slices_in_pic_minus1 + 1; i++) { + const int ret = pps_subpic_slice(pps, sps, i, off); + if (ret < 0) + return ret; + } } + return 0; } static int pps_one_tile_slices(VVCPPS *pps, const int tile_idx, int i, int *off) @@ -451,16 +531,20 @@ static int pps_one_tile_slices(VVCPPS *pps, const int tile_idx, int i, int *off) ctu_xy(&rx, &ry, tile_x, tile_y, pps); ctu_y_end = ry + r->row_height_val[tile_y]; while (ry < ctu_y_end) { + int ret; pps->slice_start_offset[i] = *off; - pps->num_ctus_in_slice[i] = pps_add_ctus(pps, off, rx, ry, + ret = pps_add_ctus(pps, off, rx, ry, r->col_width_val[tile_x], r->slice_height_in_ctus[i]); + if (ret < 0) + return ret; + pps->num_ctus_in_slice[i] = ret; ry += r->slice_height_in_ctus[i++]; } i--; return i; } -static void pps_multi_tiles_slice(VVCPPS *pps, const int tile_idx, const int i, int *off) +static int pps_multi_tiles_slice(VVCPPS *pps, const int tile_idx, const int i, int *off, bool *tile_in_slice) { const H266RawPPS *r = pps->r; int rx, ry, tile_x, tile_y; @@ -470,57 +554,91 @@ static void pps_multi_tiles_slice(VVCPPS *pps, const int tile_idx, const int i, pps->num_ctus_in_slice[i] = 0; for (int ty = tile_y; ty <= tile_y + r->pps_slice_height_in_tiles_minus1[i]; ty++) { for (int tx = tile_x; tx <= tile_x + r->pps_slice_width_in_tiles_minus1[i]; tx++) { + int ret; + const int idx = ty * r->num_tile_columns + tx; + if (tile_in_slice[idx]) + return AVERROR_INVALIDDATA; + tile_in_slice[idx] = true; ctu_xy(&rx, &ry, tx, ty, pps); - pps->num_ctus_in_slice[i] += pps_add_ctus(pps, off, rx, ry, + ret = pps_add_ctus(pps, off, rx, ry, r->col_width_val[tx], r->row_height_val[ty]); + if (ret < 0) + return ret; + pps->num_ctus_in_slice[i] += ret; } } + + return 0; } -static void pps_rect_slice(VVCPPS *pps, const VVCSPS *sps) +static int pps_rect_slice(VVCPPS *pps, const VVCSPS *sps) { const H266RawPPS *r = pps->r; - int tile_idx = 0, off = 0; + bool tile_in_slice[VVC_MAX_TILES_PER_AU] = {false}; + int tile_idx = 0, off = 0, ret; if (r->pps_single_slice_per_subpic_flag) { - pps_single_slice_per_subpic(pps, sps, &off); - return; + return pps_single_slice_per_subpic(pps, sps, &off); } for (int i = 0; i < r->pps_num_slices_in_pic_minus1 + 1; i++) { if (!r->pps_slice_width_in_tiles_minus1[i] && !r->pps_slice_height_in_tiles_minus1[i]) { - i = pps_one_tile_slices(pps, tile_idx, i, &off); + if (tile_in_slice[tile_idx]) + return AVERROR_INVALIDDATA; + tile_in_slice[tile_idx] = true; + ret = pps_one_tile_slices(pps, tile_idx, i, &off); + if (ret < 0) + return ret; + i = ret; } else { - pps_multi_tiles_slice(pps, tile_idx, i, &off); + ret = pps_multi_tiles_slice(pps, tile_idx, i, &off, tile_in_slice); + if (ret < 0) + return ret; } tile_idx = next_tile_idx(tile_idx, i, r); } + + for (int i = 0; i < r->num_tiles_in_pic; i++) { + if (!tile_in_slice[i]) + return AVERROR_INVALIDDATA; + } + + return 0; } -static void pps_no_rect_slice(VVCPPS* pps) +static int pps_no_rect_slice(VVCPPS* pps) { const H266RawPPS* r = pps->r; int rx, ry, off = 0; for (int tile_y = 0; tile_y < r->num_tile_rows; tile_y++) { for (int tile_x = 0; tile_x < r->num_tile_columns; tile_x++) { + int ret; ctu_xy(&rx, &ry, tile_x, tile_y, pps); - pps_add_ctus(pps, &off, rx, ry, r->col_width_val[tile_x], r->row_height_val[tile_y]); + ret = pps_add_ctus(pps, &off, rx, ry, r->col_width_val[tile_x], r->row_height_val[tile_y]); + if (ret < 0) + return ret; } } + + return 0; } static int pps_slice_map(VVCPPS *pps, const VVCSPS *sps) { + int ret; + pps->ctb_addr_in_slice = av_calloc(pps->ctb_count, sizeof(*pps->ctb_addr_in_slice)); if (!pps->ctb_addr_in_slice) return AVERROR(ENOMEM); if (pps->r->pps_rect_slice_flag) - pps_rect_slice(pps, sps); - else - pps_no_rect_slice(pps); + return pps_rect_slice(pps, sps); + + ret = pps_no_rect_slice(pps); + if (ret < 0) + return ret; return 0; } @@ -572,11 +690,11 @@ static int pps_derive(VVCPPS *pps, const VVCSPS *sps) return 0; } -static void pps_free(FFRefStructOpaque opaque, void *obj) +static void pps_free(AVRefStructOpaque opaque, void *obj) { VVCPPS *pps = obj; - ff_refstruct_unref(&pps->r); + av_refstruct_unref(&pps->r); av_freep(&pps->col_bd); av_freep(&pps->row_bd); @@ -588,12 +706,12 @@ static void pps_free(FFRefStructOpaque opaque, void *obj) static const VVCPPS *pps_alloc(const H266RawPPS *rpps, const VVCSPS *sps) { int ret; - VVCPPS *pps = ff_refstruct_alloc_ext(sizeof(*pps), 0, NULL, pps_free); + VVCPPS *pps = av_refstruct_alloc_ext(sizeof(*pps), 0, NULL, pps_free); if (!pps) return NULL; - ff_refstruct_replace(&pps->r, rpps); + av_refstruct_replace(&pps->r, rpps); ret = pps_derive(pps, sps); if (ret < 0) @@ -602,7 +720,7 @@ static const VVCPPS *pps_alloc(const H266RawPPS *rpps, const VVCSPS *sps) return pps; fail: - ff_refstruct_unref(&pps); + av_refstruct_unref(&pps); return NULL; } @@ -621,34 +739,35 @@ static int decode_pps(VVCParamSets *ps, const H266RawPPS *rpps) if (!pps) return AVERROR(ENOMEM); - ff_refstruct_unref(&ps->pps_list[pps_id]); + av_refstruct_unref(&ps->pps_list[pps_id]); ps->pps_list[pps_id] = pps; return ret; } -static int decode_ps(VVCParamSets *ps, const CodedBitstreamH266Context *h266, void *log_ctx, int is_clvss) +static int decode_ps(VVCParamSets *ps, AVCodecContext *c, const SliceContext *sc, int is_clvss) { - const H266RawPictureHeader *ph = h266->ph; - const H266RawPPS *rpps; - const H266RawSPS *rsps; + const H266RawSlice *sl = sc->ref; + const H266RawPPS *rpps = sl->pps; + const H266RawSPS *rsps = sl->sps; int ret; - if (!ph) - return AVERROR_INVALIDDATA; - - rpps = h266->pps[ph->ph_pic_parameter_set_id]; if (!rpps) return AVERROR_INVALIDDATA; - rsps = h266->sps[rpps->pps_seq_parameter_set_id]; if (!rsps) return AVERROR_INVALIDDATA; - ret = decode_sps(ps, rsps, log_ctx, is_clvss); + ret = decode_sps(ps, c, rsps, is_clvss); if (ret < 0) return ret; + if (rsps->sps_log2_ctu_size_minus5 > 2) { + // CTU > 128 are reserved in vvc spec v3 + av_log(c, AV_LOG_ERROR, "CTU size > 128. \n"); + return AVERROR_PATCHWELCOME; + } + ret = decode_pps(ps, rpps); if (ret < 0) return ret; @@ -728,7 +847,7 @@ static int lmcs_derive_lut(VVCLMCS *lmcs, const H266RawAPS *rlmcs, const H266Raw uint16_t input_pivot[LMCS_MAX_BIN_SIZE]; uint16_t scale_coeff[LMCS_MAX_BIN_SIZE]; uint16_t inv_scale_coeff[LMCS_MAX_BIN_SIZE]; - int i, delta_crs; + int i, delta_crs, sum_cw = 0; if (bit_depth > LMCS_MAX_BIT_DEPTH) return AVERROR_PATCHWELCOME; @@ -736,11 +855,15 @@ static int lmcs_derive_lut(VVCLMCS *lmcs, const H266RawAPS *rlmcs, const H266Raw return AVERROR_INVALIDDATA; lmcs->min_bin_idx = rlmcs->lmcs_min_bin_idx; - lmcs->max_bin_idx = LMCS_MAX_BIN_SIZE - 1 - rlmcs->lmcs_min_bin_idx; + lmcs->max_bin_idx = LMCS_MAX_BIN_SIZE - 1 - rlmcs->lmcs_delta_max_bin_idx; memset(cw, 0, sizeof(cw)); - for (int i = lmcs->min_bin_idx; i <= lmcs->max_bin_idx; i++) + for (int i = lmcs->min_bin_idx; i <= lmcs->max_bin_idx; i++) { cw[i] = org_cw + (1 - 2 * rlmcs->lmcs_delta_sign_cw_flag[i]) * rlmcs->lmcs_delta_abs_cw[i]; + sum_cw += cw[i]; + } + if (sum_cw > (1 << bit_depth) - 1) + return AVERROR_INVALIDDATA; delta_crs = (1 - 2 * rlmcs->lmcs_delta_sign_crs_flag) * rlmcs->lmcs_delta_abs_crs; @@ -748,19 +871,26 @@ static int lmcs_derive_lut(VVCLMCS *lmcs, const H266RawAPS *rlmcs, const H266Raw for (i = 0; i < LMCS_MAX_BIN_SIZE; i++) { input_pivot[i] = i * org_cw; lmcs->pivot[i + 1] = lmcs->pivot[i] + cw[i]; + if (i >= lmcs->min_bin_idx && i <= lmcs->max_bin_idx && + lmcs->pivot[i] % (1 << (bit_depth - 5)) != 0 && + lmcs->pivot[i] >> (bit_depth - 5) == lmcs->pivot[i + 1] >> (bit_depth - 5)) + return AVERROR_INVALIDDATA; scale_coeff[i] = (cw[i] * (1 << 11) + off) >> shift; if (cw[i] == 0) { inv_scale_coeff[i] = 0; lmcs->chroma_scale_coeff[i] = (1 << 11); } else { + const int cw_plus_d = cw[i] + delta_crs; + if (cw_plus_d < (org_cw >> 3) || cw_plus_d > ((org_cw << 3) - 1)) + return AVERROR_INVALIDDATA; inv_scale_coeff[i] = org_cw * (1 << 11) / cw[i]; - lmcs->chroma_scale_coeff[i] = org_cw * (1 << 11) / (cw[i] + delta_crs); + lmcs->chroma_scale_coeff[i] = org_cw * (1 << 11) / cw_plus_d; } } //derive lmcs_fwd_lut for (uint16_t sample = 0; sample < max; sample++) { - const int idx_y = sample / org_cw; + const int idx_y = sample >> shift; const uint16_t fwd_sample = lmcs_derive_lut_sample(sample, lmcs->pivot, input_pivot, scale_coeff, idx_y, max); if (bit_depth > 8) @@ -776,6 +906,7 @@ static int lmcs_derive_lut(VVCLMCS *lmcs, const H266RawAPS *rlmcs, const H266Raw uint16_t inv_sample; while (i <= lmcs->max_bin_idx && sample >= lmcs->pivot[i + 1]) i++; + i = FFMIN(i, LMCS_MAX_BIN_SIZE - 1); inv_sample = lmcs_derive_lut_sample(sample, input_pivot, lmcs->pivot, inv_scale_coeff, i, max); @@ -862,7 +993,7 @@ static int decode_ph(VVCFrameParamSets *fps, const H266RawPictureHeader *rph, vo const H266RawPPS *pps = fps->pps->r; ph->r = rph; - ff_refstruct_replace(&ph->rref, rph_ref); + av_refstruct_replace(&ph->rref, rph_ref); ret = ph_derive(ph, sps, pps, poc_tid0, is_clvss); if (ret < 0) return ret; @@ -871,28 +1002,28 @@ static int decode_ph(VVCFrameParamSets *fps, const H266RawPictureHeader *rph, vo } static int decode_frame_ps(VVCFrameParamSets *fps, const VVCParamSets *ps, - const CodedBitstreamH266Context *h266, const int poc_tid0, const int is_clvss) + const SliceContext *sc, const int poc_tid0, const int is_clvss, const VVCContext *s) { - const H266RawPictureHeader *ph = h266->ph; - const H266RawPPS *rpps; + const H266RawSlice *sl = sc->ref; + const H266RawPictureHeader *ph = sl->ph; + const H266RawPPS *rpps = sl->pps; int ret; if (!ph) return AVERROR_INVALIDDATA; - rpps = h266->pps[ph->ph_pic_parameter_set_id]; if (!rpps) return AVERROR_INVALIDDATA; - ff_refstruct_replace(&fps->sps, ps->sps_list[rpps->pps_seq_parameter_set_id]); - ff_refstruct_replace(&fps->pps, ps->pps_list[rpps->pps_pic_parameter_set_id]); + av_refstruct_replace(&fps->sps, ps->sps_list[rpps->pps_seq_parameter_set_id]); + av_refstruct_replace(&fps->pps, ps->pps_list[rpps->pps_pic_parameter_set_id]); - ret = decode_ph(fps, ph, h266->ph_ref, poc_tid0, is_clvss); + ret = decode_ph(fps, ph, sl->ph_ref, poc_tid0, is_clvss); if (ret < 0) return ret; if (ph->ph_explicit_scaling_list_enabled_flag) - ff_refstruct_replace(&fps->sl, ps->scaling_list[ph->ph_scaling_list_aps_id]); + av_refstruct_replace(&fps->sl, ps->scaling_list[ph->ph_scaling_list_aps_id]); if (ph->ph_lmcs_enabled_flag) { ret = lmcs_derive_lut(&fps->lmcs, ps->lmcs_list[ph->ph_lmcs_aps_id], fps->sps->r); @@ -901,7 +1032,7 @@ static int decode_frame_ps(VVCFrameParamSets *fps, const VVCParamSets *ps, } for (int i = 0; i < FF_ARRAY_ELEMS(fps->alf_list); i++) - ff_refstruct_replace(&fps->alf_list[i], ps->alf_list[i]); + av_refstruct_replace(&fps->alf_list[i], ps->alf_list[i]); return 0; } @@ -924,47 +1055,48 @@ static void decode_recovery_poc(VVCContext *s, const VVCPH *ph) } } -int ff_vvc_decode_frame_ps(VVCFrameParamSets *fps, struct VVCContext *s) +int ff_vvc_decode_frame_ps(struct VVCFrameContext *fc, struct VVCContext *s) { int ret = 0; + VVCFrameParamSets *fps = &fc->ps; VVCParamSets *ps = &s->ps; - const CodedBitstreamH266Context *h266 = s->cbc->priv_data; + const SliceContext *sc = fc->slices[0]; int is_clvss; decode_recovery_flag(s); is_clvss = IS_CLVSS(s); - ret = decode_ps(ps, h266, s->avctx, is_clvss); + ret = decode_ps(ps, s->avctx, sc, is_clvss); if (ret < 0) return ret; - ret = decode_frame_ps(fps, ps, h266, s->poc_tid0, is_clvss); + ret = decode_frame_ps(fps, ps, sc, s->poc_tid0, is_clvss, s); decode_recovery_poc(s, &fps->ph); return ret; } void ff_vvc_frame_ps_free(VVCFrameParamSets *fps) { - ff_refstruct_unref(&fps->sps); - ff_refstruct_unref(&fps->pps); - ff_refstruct_unref(&fps->ph.rref); - ff_refstruct_unref(&fps->sl); + av_refstruct_unref(&fps->sps); + av_refstruct_unref(&fps->pps); + av_refstruct_unref(&fps->ph.rref); + av_refstruct_unref(&fps->sl); for (int i = 0; i < FF_ARRAY_ELEMS(fps->alf_list); i++) - ff_refstruct_unref(&fps->alf_list[i]); + av_refstruct_unref(&fps->alf_list[i]); } void ff_vvc_ps_uninit(VVCParamSets *ps) { for (int i = 0; i < FF_ARRAY_ELEMS(ps->scaling_list); i++) - ff_refstruct_unref(&ps->scaling_list[i]); + av_refstruct_unref(&ps->scaling_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(ps->lmcs_list); i++) - ff_refstruct_unref(&ps->lmcs_list[i]); + av_refstruct_unref(&ps->lmcs_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(ps->alf_list); i++) - ff_refstruct_unref(&ps->alf_list[i]); + av_refstruct_unref(&ps->alf_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(ps->sps_list); i++) - ff_refstruct_unref(&ps->sps_list[i]); + av_refstruct_unref(&ps->sps_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(ps->pps_list); i++) - ff_refstruct_unref(&ps->pps_list[i]); + av_refstruct_unref(&ps->pps_list[i]); } static void alf_coeff(int16_t *coeff, @@ -1043,15 +1175,23 @@ static void alf_derive(VVCALF *alf, const H266RawAPS *aps) alf_cc(alf, aps); } +static void alf_free(AVRefStructOpaque unused, void *obj) +{ + VVCALF *alf = obj; + + av_refstruct_unref(&alf->r); +} + static int aps_decode_alf(const VVCALF **alf, const H266RawAPS *aps) { - VVCALF *a = ff_refstruct_allocz(sizeof(*a)); + VVCALF *a = av_refstruct_alloc_ext(sizeof(*a), 0, NULL, alf_free); if (!a) return AVERROR(ENOMEM); alf_derive(a, aps); - ff_refstruct_replace(alf, a); - ff_refstruct_unref(&a); + av_refstruct_replace(&a->r, aps); + av_refstruct_replace(alf, a); + av_refstruct_unref(&a); return 0; } @@ -1099,17 +1239,17 @@ static void scaling_derive(VVCScalingList *sl, const H266RawAPS *aps) //dc if (id >= SL_START_16x16) { if (!aps->scaling_list_copy_mode_flag[id] && !aps->scaling_list_pred_mode_flag[id]) { - sl->scaling_matrix_dc_rec[id - SL_START_16x16] = 8; + dc += 8; } else if (!aps->scaling_list_pred_id_delta[id]) { - sl->scaling_matrix_dc_rec[id - SL_START_16x16] = 16; + dc += 16; } else { const int ref_id = id - aps->scaling_list_pred_id_delta[id]; if (ref_id >= SL_START_16x16) dc += sl->scaling_matrix_dc_rec[ref_id - SL_START_16x16]; else dc += sl->scaling_matrix_rec[ref_id][0]; - sl->scaling_matrix_dc_rec[id - SL_START_16x16] = dc & 255; } + sl->scaling_matrix_dc_rec[id - SL_START_16x16] = dc & 255; } //ac @@ -1131,13 +1271,13 @@ static void scaling_derive(VVCScalingList *sl, const H266RawAPS *aps) static int aps_decode_scaling(const VVCScalingList **scaling, const H266RawAPS *aps) { - VVCScalingList *sl = ff_refstruct_allocz(sizeof(*sl)); + VVCScalingList *sl = av_refstruct_allocz(sizeof(*sl)); if (!sl) return AVERROR(ENOMEM); scaling_derive(sl, aps); - ff_refstruct_replace(scaling, sl); - ff_refstruct_unref(&sl); + av_refstruct_replace(scaling, sl); + av_refstruct_unref(&sl); return 0; } @@ -1155,7 +1295,7 @@ int ff_vvc_decode_aps(VVCParamSets *ps, const CodedBitstreamUnit *unit) ret = aps_decode_alf(&ps->alf_list[aps->aps_adaptation_parameter_set_id], aps); break; case VVC_ASP_TYPE_LMCS: - ff_refstruct_replace(&ps->lmcs_list[aps->aps_adaptation_parameter_set_id], aps); + av_refstruct_replace(&ps->lmcs_list[aps->aps_adaptation_parameter_set_id], aps); break; case VVC_ASP_TYPE_SCALING: ret = aps_decode_scaling(&ps->scaling_list[aps->aps_adaptation_parameter_set_id], aps); @@ -1198,7 +1338,7 @@ static int sh_alf_aps(const VVCSH *sh, const VVCFrameParamSets *fps) return 0; } -static void sh_slice_address(VVCSH *sh, const H266RawSPS *sps, const VVCPPS *pps) +static int sh_slice_address(VVCSH *sh, const H266RawSPS *sps, const VVCPPS *pps) { const int slice_address = sh->r->sh_slice_address; @@ -1222,6 +1362,11 @@ static void sh_slice_address(VVCSH *sh, const H266RawSPS *sps, const VVCPPS *pps sh->num_ctus_in_curr_slice += pps->r->row_height_val[tile_y] * pps->r->col_width_val[tile_x]; } } + + if (!sh->num_ctus_in_curr_slice) + return AVERROR_INVALIDDATA; + + return 0; } static void sh_qp_y(VVCSH *sh, const H266RawPPS *pps, const H266RawPictureHeader *ph) @@ -1318,7 +1463,9 @@ static int sh_derive(VVCSH *sh, const VVCFrameParamSets *fps) const H266RawPictureHeader *ph = fps->ph.r; int ret; - sh_slice_address(sh, sps, fps->pps); + ret = sh_slice_address(sh, sps, fps->pps); + if (ret < 0) + return ret; ret = sh_alf_aps(sh, fps); if (ret < 0) return ret; @@ -1338,7 +1485,7 @@ int ff_vvc_decode_sh(VVCSH *sh, const VVCFrameParamSets *fps, const CodedBitstre if (!fps->sps || !fps->pps) return AVERROR_INVALIDDATA; - ff_refstruct_replace(&sh->r, unit->content_ref); + av_refstruct_replace(&sh->r, unit->content_ref); ret = sh_derive(sh, fps); if (ret < 0) diff --git a/libavcodec/vvc/ps.h b/libavcodec/vvc/ps.h index 9203e2c57..90bd4c0e9 100644 --- a/libavcodec/vvc/ps.h +++ b/libavcodec/vvc/ps.h @@ -169,6 +169,7 @@ typedef struct VVCPH { #define ALF_NUM_COEFF_CC 7 typedef struct VVCALF { + const H266RawAPS *r; int16_t luma_coeff [ALF_NUM_FILTERS_LUMA][ALF_NUM_COEFF_LUMA]; uint8_t luma_clip_idx [ALF_NUM_FILTERS_LUMA][ALF_NUM_COEFF_LUMA]; @@ -265,8 +266,9 @@ typedef struct VVCSH { } VVCSH; struct VVCContext; +struct VVCFrameContext; -int ff_vvc_decode_frame_ps(VVCFrameParamSets *fps, struct VVCContext *s); +int ff_vvc_decode_frame_ps(struct VVCFrameContext *fc, struct VVCContext *s); int ff_vvc_decode_aps(VVCParamSets *ps, const CodedBitstreamUnit *unit); int ff_vvc_decode_sh(VVCSH *sh, const VVCFrameParamSets *ps, const CodedBitstreamUnit *unit); void ff_vvc_frame_ps_free(VVCFrameParamSets *fps); diff --git a/libavcodec/vvc/refs.c b/libavcodec/vvc/refs.c index bf093bea9..c1f027aed 100644 --- a/libavcodec/vvc/refs.c +++ b/libavcodec/vvc/refs.c @@ -21,18 +21,16 @@ */ #include +#include #include "libavutil/mem.h" #include "libavutil/thread.h" -#include "libavcodec/refstruct.h" +#include "libavutil/refstruct.h" #include "libavcodec/thread.h" +#include "libavcodec/decode.h" #include "refs.h" -#define VVC_FRAME_FLAG_OUTPUT (1 << 0) -#define VVC_FRAME_FLAG_SHORT_REF (1 << 1) -#define VVC_FRAME_FLAG_LONG_REF (1 << 2) -#define VVC_FRAME_FLAG_BUMPING (1 << 3) typedef struct FrameProgress { atomic_int progress[VVC_PROGRESS_LAST]; @@ -50,19 +48,28 @@ void ff_vvc_unref_frame(VVCFrameContext *fc, VVCFrame *frame, int flags) return; frame->flags &= ~flags; + if (!(frame->flags & ~VVC_FRAME_FLAG_CORRUPT)) + frame->flags = 0; if (!frame->flags) { av_frame_unref(frame->frame); - ff_refstruct_unref(&frame->sps); - ff_refstruct_unref(&frame->pps); - ff_refstruct_unref(&frame->progress); - ff_refstruct_unref(&frame->tab_dmvr_mvf); + if (frame->needs_fg) { + av_frame_unref(frame->frame_grain); + frame->needs_fg = 0; + } - ff_refstruct_unref(&frame->rpl); + av_refstruct_unref(&frame->sps); + av_refstruct_unref(&frame->pps); + av_refstruct_unref(&frame->progress); + + av_refstruct_unref(&frame->tab_dmvr_mvf); + + av_refstruct_unref(&frame->rpl); frame->nb_rpl_elems = 0; - ff_refstruct_unref(&frame->rpl_tab); + av_refstruct_unref(&frame->rpl_tab); frame->collocated_ref = NULL; + av_refstruct_unref(&frame->hwaccel_picture_private); } } @@ -89,7 +96,7 @@ void ff_vvc_flush_dpb(VVCFrameContext *fc) ff_vvc_unref_frame(fc, &fc->DPB[i], ~0); } -static void free_progress(FFRefStructOpaque unused, void *obj) +static void free_progress(AVRefStructOpaque unused, void *obj) { FrameProgress *p = (FrameProgress *)obj; @@ -101,13 +108,13 @@ static void free_progress(FFRefStructOpaque unused, void *obj) static FrameProgress *alloc_progress(void) { - FrameProgress *p = ff_refstruct_alloc_ext(sizeof(*p), 0, NULL, free_progress); + FrameProgress *p = av_refstruct_alloc_ext(sizeof(*p), 0, NULL, free_progress); if (p) { p->has_lock = !ff_mutex_init(&p->lock, NULL); p->has_cond = !ff_cond_init(&p->cond, NULL); if (!p->has_lock || !p->has_cond) - ff_refstruct_unref(&p); + av_refstruct_unref(&p); } return p; } @@ -123,23 +130,32 @@ static VVCFrame *alloc_frame(VVCContext *s, VVCFrameContext *fc) if (frame->frame->buf[0]) continue; - frame->sps = ff_refstruct_ref_c(fc->ps.sps); - frame->pps = ff_refstruct_ref_c(fc->ps.pps); + frame->sps = av_refstruct_ref_c(fc->ps.sps); + frame->pps = av_refstruct_ref_c(fc->ps.pps); + + // Add LCEVC SEI metadata here, as it's needed in get_buffer() + if (fc->sei.common.lcevc.info) { + HEVCSEILCEVC *lcevc = &fc->sei.common.lcevc; + ret = ff_frame_new_side_data_from_buf(s->avctx, frame->frame, + AV_FRAME_DATA_LCEVC, &lcevc->info); + if (ret < 0) + goto fail; + } ret = ff_thread_get_buffer(s->avctx, frame->frame, AV_GET_BUFFER_FLAG_REF); if (ret < 0) return NULL; - frame->rpl = ff_refstruct_allocz(s->current_frame.nb_units * sizeof(RefPicListTab)); + frame->rpl = av_refstruct_allocz(s->current_frame.nb_units * sizeof(RefPicListTab)); if (!frame->rpl) goto fail; frame->nb_rpl_elems = s->current_frame.nb_units; - frame->tab_dmvr_mvf = ff_refstruct_pool_get(fc->tab_dmvr_mvf_pool); + frame->tab_dmvr_mvf = av_refstruct_pool_get(fc->tab_dmvr_mvf_pool); if (!frame->tab_dmvr_mvf) goto fail; - frame->rpl_tab = ff_refstruct_pool_get(fc->rpl_tab_pool); + frame->rpl_tab = av_refstruct_pool_get(fc->rpl_tab_pool); if (!frame->rpl_tab) goto fail; frame->ctb_count = pps->ctb_width * pps->ctb_height; @@ -153,10 +169,22 @@ static VVCFrame *alloc_frame(VVCContext *s, VVCFrameContext *fc) frame->ref_width = pps->r->pps_pic_width_in_luma_samples - win->left_offset - win->right_offset; frame->ref_height = pps->r->pps_pic_height_in_luma_samples - win->bottom_offset - win->top_offset; + if (fc->sei.frame_field_info.present) { + if (fc->sei.frame_field_info.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD) + frame->frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; + if (fc->sei.frame_field_info.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD || + fc->sei.frame_field_info.picture_struct == AV_PICTURE_STRUCTURE_BOTTOM_FIELD) + frame->frame->flags |= AV_FRAME_FLAG_INTERLACED; + } + frame->progress = alloc_progress(); if (!frame->progress) goto fail; + ret = ff_hwaccel_frame_priv_alloc(s->avctx, &frame->hwaccel_picture_private); + if (ret < 0) + goto fail; + return frame; fail: ff_vvc_unref_frame(fc, frame, ~0); @@ -166,6 +194,36 @@ fail: return NULL; } +static void set_pict_type(AVFrame *frame, const VVCContext *s, const VVCFrameContext *fc) +{ + bool has_b = false, has_inter = false; + + if (IS_IRAP(s)) { + frame->pict_type = AV_PICTURE_TYPE_I; + frame->flags |= AV_FRAME_FLAG_KEY; + return; + } + + if (fc->ps.ph.r->ph_inter_slice_allowed_flag) { + // At this point, fc->slices is not fully initialized; we need to inspect the CBS directly. + const CodedBitstreamFragment *current = &s->current_frame; + for (int i = 0; i < current->nb_units && !has_b; i++) { + const CodedBitstreamUnit *unit = current->units + i; + if (unit->content_ref && unit->type <= VVC_RSV_IRAP_11) { + const H266RawSliceHeader *rsh = unit->content_ref; + has_inter |= !IS_I(rsh); + has_b |= IS_B(rsh); + } + } + } + if (!has_inter) + frame->pict_type = AV_PICTURE_TYPE_I; + else if (has_b) + frame->pict_type = AV_PICTURE_TYPE_B; + else + frame->pict_type = AV_PICTURE_TYPE_P; +} + int ff_vvc_set_new_ref(VVCContext *s, VVCFrameContext *fc, AVFrame **frame) { const VVCPH *ph= &fc->ps.ph; @@ -187,6 +245,7 @@ int ff_vvc_set_new_ref(VVCContext *s, VVCFrameContext *fc, AVFrame **frame) if (!ref) return AVERROR(ENOMEM); + set_pict_type(ref->frame, s, fc); *frame = ref->frame; fc->ref = ref; @@ -246,11 +305,19 @@ int ff_vvc_output_frame(VVCContext *s, VVCFrameContext *fc, AVFrame *out, const if (nb_output) { VVCFrame *frame = &fc->DPB[min_idx]; - ret = av_frame_ref(out, frame->frame); + if (frame->flags & VVC_FRAME_FLAG_CORRUPT) + frame->frame->flags |= AV_FRAME_FLAG_CORRUPT; + + ret = av_frame_ref(out, frame->needs_fg ? frame->frame_grain : frame->frame); + + if (!ret && !(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN)) + av_frame_remove_side_data(out, AV_FRAME_DATA_FILM_GRAIN_PARAMS); + if (frame->flags & VVC_FRAME_FLAG_BUMPING) ff_vvc_unref_frame(fc, frame, VVC_FRAME_FLAG_OUTPUT | VVC_FRAME_FLAG_BUMPING); else ff_vvc_unref_frame(fc, frame, VVC_FRAME_FLAG_OUTPUT); + if (ret < 0) return ret; @@ -355,7 +422,7 @@ static VVCFrame *generate_missing_ref(VVCContext *s, VVCFrameContext *fc, int po frame->poc = poc; frame->sequence = s->seq_decode; - frame->flags = 0; + frame->flags = VVC_FRAME_FLAG_CORRUPT; ff_vvc_report_frame_finished(frame); @@ -390,6 +457,20 @@ static int add_candidate_ref(VVCContext *s, VVCFrameContext *fc, RefPicList *lis if (ref == fc->ref || list->nb_refs >= VVC_MAX_REF_ENTRIES) return AVERROR_INVALIDDATA; + if (!IS_CVSS(s)) { + const bool ref_corrupt = !ref || (ref->flags & VVC_FRAME_FLAG_CORRUPT); + const bool recovering = s->no_output_before_recovery_flag && + (IS_RASL(s) || !GDR_IS_RECOVERED(s)); + + if (ref_corrupt && !recovering) { + if (!(s->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) && + !(s->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL)) + return AVERROR_INVALIDDATA; + + fc->ref->flags |= VVC_FRAME_FLAG_CORRUPT; + } + } + if (!ref) { ref = generate_missing_ref(s, fc, poc); if (!ref) diff --git a/libavcodec/vvc/refs.h b/libavcodec/vvc/refs.h index 8ae33d4a9..a3081a76b 100644 --- a/libavcodec/vvc/refs.h +++ b/libavcodec/vvc/refs.h @@ -25,6 +25,12 @@ #include "dec.h" +#define VVC_FRAME_FLAG_OUTPUT (1 << 0) +#define VVC_FRAME_FLAG_SHORT_REF (1 << 1) +#define VVC_FRAME_FLAG_LONG_REF (1 << 2) +#define VVC_FRAME_FLAG_BUMPING (1 << 3) +#define VVC_FRAME_FLAG_CORRUPT (1 << 4) + int ff_vvc_output_frame(VVCContext *s, VVCFrameContext *fc, struct AVFrame *out, int no_output_of_prior_pics_flag, int flush); void ff_vvc_bump_frame(VVCContext *s, VVCFrameContext *fc); int ff_vvc_set_new_ref(VVCContext *s, VVCFrameContext *fc, struct AVFrame **frame); diff --git a/libavcodec/vvc/sei.c b/libavcodec/vvc/sei.c new file mode 100644 index 000000000..241943f3c --- /dev/null +++ b/libavcodec/vvc/sei.c @@ -0,0 +1,284 @@ +/* + * VVC Supplementary Enhancement Information messages + * + * copyright (c) 2024 Wu Jianhua + * + * 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 "sei.h" +#include "dec.h" +#include "libavcodec/bytestream.h" +#include "libavutil/refstruct.h" + +static int decode_film_grain_characteristics(H2645SEIFilmGrainCharacteristics *h, const SEIRawFilmGrainCharacteristics *s, const VVCFrameContext *fc) +{ + const VVCSPS *sps = fc->ps.sps; + + h->present = !s->fg_characteristics_cancel_flag; + if (h->present) { + h->model_id = s->fg_model_id; + h->separate_colour_description_present_flag = s->fg_separate_colour_description_present_flag; + if (h->separate_colour_description_present_flag) { + h->bit_depth_luma = s->fg_bit_depth_luma_minus8 + 8; + h->bit_depth_chroma = s->fg_bit_depth_chroma_minus8 + 8; + h->full_range = s->fg_full_range_flag; + h->color_primaries = s->fg_colour_primaries; + h->transfer_characteristics = s->fg_transfer_characteristics; + h->matrix_coeffs = s->fg_matrix_coeffs; + } else { + if (!sps) { + av_log(fc->log_ctx, AV_LOG_ERROR, + "No active SPS for film_grain_characteristics.\n"); + return AVERROR_INVALIDDATA; + } + h->bit_depth_luma = sps->bit_depth; + h->bit_depth_chroma = sps->bit_depth; + h->full_range = sps->r->vui.vui_full_range_flag; + h->color_primaries = sps->r->vui.vui_colour_primaries; + h->transfer_characteristics = sps->r->vui.vui_transfer_characteristics; + h->matrix_coeffs = sps->r->vui.vui_matrix_coeffs ; + } + + h->blending_mode_id = s->fg_blending_mode_id; + h->log2_scale_factor = s->fg_log2_scale_factor; + + for (int c = 0; c < 3; c++) { + h->comp_model_present_flag[c] = s->fg_comp_model_present_flag[c]; + if (h->comp_model_present_flag[c]) { + h->num_intensity_intervals[c] = s->fg_num_intensity_intervals_minus1[c] + 1; + h->num_model_values[c] = s->fg_num_model_values_minus1[c] + 1; + + if (h->num_model_values[c] > 6) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < h->num_intensity_intervals[c]; i++) { + h->intensity_interval_lower_bound[c][i] = s->fg_intensity_interval_lower_bound[c][i]; + h->intensity_interval_upper_bound[c][i] = s->fg_intensity_interval_upper_bound[c][i]; + for (int j = 0; j < h->num_model_values[c]; j++) + h->comp_model_value[c][i][j] = s->fg_comp_model_value[c][i][j]; + } + } + } + + h->persistence_flag = s->fg_characteristics_persistence_flag; + } + + return 0; +} + +static int decode_decoded_picture_hash(H274SEIPictureHash *h, const SEIRawDecodedPictureHash *s) +{ + h->present = 1; + h->hash_type = s->dph_sei_hash_type; + if (h->hash_type == 0) + memcpy(h->md5, s->dph_sei_picture_md5, sizeof(h->md5)); + else if (h->hash_type == 1) + memcpy(h->crc, s->dph_sei_picture_crc, sizeof(h->crc)); + else if (h->hash_type == 2) + memcpy(h->checksum, s->dph_sei_picture_checksum, sizeof(h->checksum)); + + return 0; +} + +static int decode_display_orientation(H2645SEIDisplayOrientation *h, const SEIRawDisplayOrientation *s) +{ + int degrees[] = { 0, 0x8000, 0x4000, 0xC000 }; + + h->present = !s->display_orientation_cancel_flag; + if (h->present) { + if (s->display_orientation_transform_type > 7) + return AVERROR_INVALIDDATA; + + h->vflip = 0; + if (s->display_orientation_transform_type == 1 || + s->display_orientation_transform_type == 3 || + s->display_orientation_transform_type == 4 || + s->display_orientation_transform_type == 6) { + h->hflip = 1; + } else { + h->hflip = 0; + } + h->anticlockwise_rotation = degrees[s->display_orientation_transform_type >> 1]; + } + + return 0; +} + +static int decode_content_light_level_info(H2645SEIContentLight *h, const SEIRawContentLightLevelInfo *s) +{ + h->present = 1; + h->max_content_light_level = s->max_content_light_level; + h->max_pic_average_light_level = s->max_pic_average_light_level; + + return 0; +} + +static int decode_frame_field_info(H274SEIFrameFieldInfo *h, const SEIRawFrameFieldInformation *s) +{ + if (s->ffi_source_scan_type > 3) + return AVERROR_INVALIDDATA; + + h->present = 1; + if (s->ffi_field_pic_flag) { + if (s->ffi_bottom_field_flag) + h->picture_struct = AV_PICTURE_STRUCTURE_BOTTOM_FIELD; + else + h->picture_struct = AV_PICTURE_STRUCTURE_TOP_FIELD; + } else { + h->display_elemental_periods = s->ffi_display_elemental_periods_minus1 + 1; + } + + h->source_scan_type = s->ffi_source_scan_type; + h->duplicate_flag = s->ffi_duplicate_flag; + + return 0; +} + +static int decode_ambient_viewing_environment(H2645SEIAmbientViewingEnvironment *h, const SEIRawAmbientViewingEnvironment *s) +{ + h->present = 1; + h->ambient_illuminance = s->ambient_illuminance; + h->ambient_light_x = s->ambient_light_x; + h->ambient_light_y = s->ambient_light_y; + + return 0; +} + +static int decode_mastering_display_colour_volume(H2645SEIMasteringDisplay *h, const SEIRawMasteringDisplayColourVolume *s) +{ + h->present = 1; + + for (int c = 0; c < 3; c++) { + h->display_primaries[c][0] = s->display_primaries_x[c]; + h->display_primaries[c][1] = s->display_primaries_y[c]; + } + + h->white_point[0] = s->white_point_x; + h->white_point[1] = s->white_point_y; + + h->max_luminance = s->max_display_mastering_luminance; + h->min_luminance = s->min_display_mastering_luminance; + + return 0; +} + +static int decode_user_data_registered_itu_t_t35(H2645SEI *sei, const SEIRawUserDataRegistered *s, + const VVCFrameContext *fc) +{ + GetByteContext gbc; + int offset = (s->itu_t_t35_country_code == 0xff) + 1; + + bytestream2_init(&gbc, s->data_ref, s->data_length + offset); + return ff_h2645_sei_message_decode(sei, SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35, + AV_CODEC_ID_VVC, NULL, &gbc, fc->log_ctx); +} + +static int decode_user_data_uregistered(H2645SEI *sei, const SEIRawUserDataUnregistered *s, + const VVCFrameContext *fc) +{ + GetByteContext gbc; + + bytestream2_init(&gbc, s->data_ref, s->data_length + 16); + return ff_h2645_sei_message_decode(sei, SEI_TYPE_USER_DATA_UNREGISTERED, + AV_CODEC_ID_VVC, NULL, &gbc, fc->log_ctx); +} + +int ff_vvc_sei_decode(VVCSEI *s, const H266RawSEI *sei, const struct VVCFrameContext *fc) +{ + H2645SEI *c = &s->common; + + if (!sei) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < sei->message_list.nb_messages; i++) { + int ret = 0; + SEIRawMessage *message = &sei->message_list.messages[i]; + void *payload = message->payload; + + switch (message->payload_type) { + case SEI_TYPE_FILM_GRAIN_CHARACTERISTICS: + av_refstruct_unref(&c->film_grain_characteristics); + c->film_grain_characteristics = av_refstruct_allocz(sizeof(*c->film_grain_characteristics)); + if (!c->film_grain_characteristics) + return AVERROR(ENOMEM); + ret = decode_film_grain_characteristics(c->film_grain_characteristics, payload, fc); + break; + + case SEI_TYPE_DECODED_PICTURE_HASH: + ret = decode_decoded_picture_hash(&s->picture_hash, payload); + break; + + case SEI_TYPE_DISPLAY_ORIENTATION: + ret = decode_display_orientation(&s->common.display_orientation, payload); + break; + + case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO: + ret = decode_content_light_level_info(&s->common.content_light, payload); + break; + + case SEI_TYPE_FRAME_FIELD_INFO: + ret = decode_frame_field_info(&s->frame_field_info, payload); + break; + + case SEI_TYPE_AMBIENT_VIEWING_ENVIRONMENT: + ret = decode_ambient_viewing_environment(&s->common.ambient_viewing_environment, payload); + break; + + case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME: + ret = decode_mastering_display_colour_volume(&s->common.mastering_display, payload); + break; + + case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35: + ret = decode_user_data_registered_itu_t_t35(&s->common, payload, fc); + break; + + case SEI_TYPE_USER_DATA_UNREGISTERED: + ret = decode_user_data_uregistered(&s->common, payload, fc); + break; + + default: + av_log(fc->log_ctx, AV_LOG_DEBUG, "Skipped %s SEI %d\n", + sei->nal_unit_header.nal_unit_type == VVC_PREFIX_SEI_NUT ? + "PREFIX" : "SUFFIX", message->payload_type); + return FF_H2645_SEI_MESSAGE_UNHANDLED; + } + + if (ret == AVERROR(ENOMEM)) + return ret; + if (ret < 0) + av_log(fc->log_ctx, AV_LOG_WARNING, "Failure to parse %s SEI %d: %s\n", + sei->nal_unit_header.nal_unit_type == VVC_PREFIX_SEI_NUT ? + "PREFIX" : "SUFFIX", message->payload_type, av_err2str(ret)); + } + + return 0; +} + +int ff_vvc_sei_replace(VVCSEI *dst, const VVCSEI *src) +{ + dst->picture_hash.present = 0; // drop hash + dst->frame_field_info.present = 0; // drop field info + return ff_h2645_sei_ctx_replace(&dst->common, &src->common); +} + +void ff_vvc_sei_reset(VVCSEI *s) +{ + ff_h2645_sei_reset(&s->common); + s->picture_hash.present = 0; + s->frame_field_info.present = 0; +} diff --git a/libavcodec/vvc/sei.h b/libavcodec/vvc/sei.h new file mode 100644 index 000000000..578b48a0e --- /dev/null +++ b/libavcodec/vvc/sei.h @@ -0,0 +1,48 @@ +/* + * VVC Supplementary Enhancement Information messages + * + * copyright (c) 2024 Wu Jianhua + * + * 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_VVC_SEI_H +#define AVCODEC_VVC_SEI_H + +#include + +#include "libavcodec/get_bits.h" +#include "libavcodec/cbs.h" +#include "libavcodec/cbs_h266.h" +#include "libavcodec/h2645_sei.h" +#include "libavcodec/sei.h" +#include "libavcodec/vvc.h" +#include "libavcodec/h274.h" + +typedef struct VVCSEI { + H2645SEI common; + H274SEIPictureHash picture_hash; + H274SEIFrameFieldInfo frame_field_info; +} VVCSEI; + +struct VVCFrameContext; + +int ff_vvc_sei_decode(VVCSEI *s, const H266RawSEI *sei, const struct VVCFrameContext *fc); +int ff_vvc_sei_replace(VVCSEI *dst, const VVCSEI *src); +void ff_vvc_sei_reset(VVCSEI *s); + +#endif /* AVCODEC_VVC_SEI_H */ diff --git a/libavcodec/vvc/thread.c b/libavcodec/vvc/thread.c index 86a7753c6..164ad8343 100644 --- a/libavcodec/vvc/thread.c +++ b/libavcodec/vvc/thread.c @@ -22,7 +22,7 @@ #include -#include "libavutil/executor.h" +#include "libavcodec/executor.h" #include "libavutil/mem.h" #include "libavutil/thread.h" @@ -42,6 +42,7 @@ typedef struct ProgressListener { typedef enum VVCTaskStage { VVC_TASK_STAGE_INIT, // for CTU(0, 0) only VVC_TASK_STAGE_PARSE, + VVC_TASK_STAGE_DEBLOCK_BS, VVC_TASK_STAGE_INTER, VVC_TASK_STAGE_RECON, VVC_TASK_STAGE_LMCS, @@ -55,7 +56,7 @@ typedef enum VVCTaskStage { typedef struct VVCTask { union { struct VVCTask *next; //for executor debug only - AVTask task; + FFTask task; } u; VVCTaskStage stage; @@ -103,13 +104,29 @@ typedef struct VVCFrameThread { AVCond cond; } VVCFrameThread; +#define PRIORITY_LOWEST 2 static void add_task(VVCContext *s, VVCTask *t) { - VVCFrameThread *ft = t->fc->ft; + VVCFrameThread *ft = t->fc->ft; + FFTask *task = &t->u.task; + const int priorities[] = { + 0, // VVC_TASK_STAGE_INIT, + 0, // VVC_TASK_STAGE_PARSE, + 1, // VVC_TASK_STAGE_DEBLOCK_BS + // For an 8K clip, a CTU line completed in the reference frame may trigger 64 and more inter tasks. + // We assign these tasks the lowest priority to avoid being overwhelmed with inter tasks. + PRIORITY_LOWEST, // VVC_TASK_STAGE_INTER + 1, // VVC_TASK_STAGE_RECON, + 1, // VVC_TASK_STAGE_LMCS, + 1, // VVC_TASK_STAGE_DEBLOCK_V, + 1, // VVC_TASK_STAGE_DEBLOCK_H, + 1, // VVC_TASK_STAGE_SAO, + 1, // VVC_TASK_STAGE_ALF, + }; atomic_fetch_add(&ft->nb_scheduled_tasks, 1); - - av_executor_execute(s->executor, &t->u.task); + task->priority = priorities[t->stage]; + ff_executor_execute(s->executor, task); } static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const int rx, const int ry) @@ -166,6 +183,8 @@ static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uin // l:left, r:right, t: top, b: bottom static const uint8_t target_score[] = { + 2, //VVC_TASK_STAGE_DEBLOCK_BS,need l + t parse + 0, //VVC_TASK_STAGE_INTER, not used 2, //VVC_TASK_STAGE_RECON, need l + rt recon 3, //VVC_TASK_STAGE_LMCS, need r + b + rb recon 1, //VVC_TASK_STAGE_DEBLOCK_V, need l deblock v @@ -187,7 +206,7 @@ static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uin } else if (stage == VVC_TASK_STAGE_INTER) { target = atomic_load(&t->target_inter_score); } else { - target = target_score[stage - VVC_TASK_STAGE_RECON]; + target = target_score[stage - VVC_TASK_STAGE_DEBLOCK_BS]; } //+1 for previous stage @@ -264,6 +283,13 @@ static void add_progress_listener(VVCFrame *ref, ProgressListener *l, ff_vvc_add_progress_listener(ref, (VVCProgressListener*)l); } +static void ep_init_wpp(EntryPoint *next, const EntryPoint *ep, const VVCSPS *sps) +{ + memcpy(next->cabac_state, ep->cabac_state, sizeof(next->cabac_state)); + memcpy(next->pp, ep->pp, sizeof(next->pp)); + ff_vvc_ep_init_stat_coeff(next, sps->bit_depth, sps->r->sps_persistent_rice_adaptation_enabled_flag); +} + static void schedule_next_parse(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, const VVCTask *t) { VVCFrameThread *ft = fc->ft; @@ -273,10 +299,8 @@ static void schedule_next_parse(VVCContext *s, VVCFrameContext *fc, const SliceC if (sps->r->sps_entropy_coding_sync_enabled_flag) { if (t->rx == fc->ps.pps->ctb_to_col_bd[t->rx]) { EntryPoint *next = ep + 1; - if (next < sc->eps + sc->nb_eps && !is_first_row(fc, t->rx, t->ry + 1)) { - memcpy(next->cabac_state, ep->cabac_state, sizeof(next->cabac_state)); - ff_vvc_ep_init_stat_coeff(next, sps->bit_depth, sps->r->sps_persistent_rice_adaptation_enabled_flag); - } + if (next < sc->eps + sc->nb_eps && !is_first_row(fc, t->rx, t->ry + 1)) + ep_init_wpp(next, ep, sps); } if (t->ry + 1 < ft->ctu_height && !is_first_row(fc, t->rx, t->ry + 1)) frame_thread_add_score(s, ft, t->rx, t->ry + 1, VVC_TASK_STAGE_PARSE); @@ -333,6 +357,10 @@ static void task_stage_done(const VVCTask *t, VVCContext *s) //this is a reserve map of ready_score, ordered by zigzag if (stage == VVC_TASK_STAGE_PARSE) { + ADD( 0, 1, VVC_TASK_STAGE_DEBLOCK_BS); + ADD( 1, 0, VVC_TASK_STAGE_DEBLOCK_BS); + if (t->rx < 0 || t->rx >= ft->ctu_width || t->ry < 0 || t->ry >= ft->ctu_height) + return; parse_task_done(s, fc, t->rx, t->ry); } else if (stage == VVC_TASK_STAGE_RECON) { ADD(-1, 1, VVC_TASK_STAGE_RECON); @@ -372,38 +400,6 @@ static int task_is_stage_ready(VVCTask *t, int add) return task_has_target_score(t, stage, score); } -static int task_ready(const AVTask *_t, void *user_data) -{ - VVCTask *t = (VVCTask*)_t; - - return task_is_stage_ready(t, 0); -} - -#define CHECK(a, b) \ - do { \ - if ((a) != (b)) \ - return (a) < (b); \ - } while (0) - -static int task_priority_higher(const AVTask *_a, const AVTask *_b) -{ - const VVCTask *a = (const VVCTask*)_a; - const VVCTask *b = (const VVCTask*)_b; - - - if (a->stage <= VVC_TASK_STAGE_PARSE || b->stage <= VVC_TASK_STAGE_PARSE) { - CHECK(a->stage, b->stage); - CHECK(a->fc->decode_order, b->fc->decode_order); //decode order - CHECK(a->ry, b->ry); - return a->rx < b->rx; - } - - CHECK(a->fc->decode_order, b->fc->decode_order); //decode order - CHECK(a->rx + a->ry + a->stage, b->rx + b->ry + b->stage); //zigzag with type - CHECK(a->rx + a->ry, b->rx + b->ry); //zigzag - return a->ry < b->ry; -} - static void check_colocation(VVCContext *s, VVCTask *t) { const VVCFrameContext *fc = t->fc; @@ -498,6 +494,14 @@ static int run_parse(VVCContext *s, VVCLocalContext *lc, VVCTask *t) return 0; } +static int run_deblock_bs(VVCContext *s, VVCLocalContext *lc, VVCTask *t) +{ + if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag) + ff_vvc_deblock_bs(lc, t->rx, t->ry, t->rs); + + return 0; +} + static int run_inter(VVCContext *s, VVCLocalContext *lc, VVCTask *t) { VVCFrameContext *fc = lc->fc; @@ -602,11 +606,10 @@ static int run_alf(VVCContext *s, VVCLocalContext *lc, VVCTask *t) return 0; } -#define VVC_THREAD_DEBUG -#ifdef VVC_THREAD_DEBUG const static char* task_name[] = { "INIT", "P", + "B", "I", "R", "L", @@ -615,7 +618,6 @@ const static char* task_name[] = { "S", "A" }; -#endif typedef int (*run_func)(VVCContext *s, VVCLocalContext *lc, VVCTask *t); @@ -628,6 +630,7 @@ static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc) static const run_func run[] = { run_init, run_parse, + run_deblock_bs, run_inter, run_recon, run_lmcs, @@ -637,9 +640,7 @@ static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc) run_alf, }; -#ifdef VVC_THREAD_DEBUG - av_log(s->avctx, AV_LOG_DEBUG, "frame %5d, %s(%3d, %3d)\r\n", (int)t->fc->decode_order, task_name[stage], t->rx, t->ry); -#endif + ff_dlog(s->avctx, "frame %5d, %s(%3d, %3d)\r\n", (int)t->fc->decode_order, task_name[stage], t->rx, t->ry); lc->sc = t->sc; @@ -655,13 +656,13 @@ static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc) "frame %5d, %s(%3d, %3d) failed with %d\r\n", (int)fc->decode_order, task_name[stage], t->rx, t->ry, ret); } + if (!ret) + task_stage_done(t, s); } - - task_stage_done(t, s); return; } -static int task_run(AVTask *_t, void *local_context, void *user_data) +static int task_run(FFTask *_t, void *local_context, void *user_data) { VVCTask *t = (VVCTask*)_t; VVCContext *s = (VVCContext *)user_data; @@ -683,21 +684,20 @@ static int task_run(AVTask *_t, void *local_context, void *user_data) return 0; } -AVExecutor* ff_vvc_executor_alloc(VVCContext *s, const int thread_count) +av_cold FFExecutor* ff_vvc_executor_alloc(VVCContext *s, const int thread_count) { - AVTaskCallbacks callbacks = { + FFTaskCallbacks callbacks = { s, sizeof(VVCLocalContext), - task_priority_higher, - task_ready, + PRIORITY_LOWEST + 1, task_run, }; - return av_executor_alloc(&callbacks, thread_count); + return ff_executor_alloc(&callbacks, thread_count); } -void ff_vvc_executor_free(AVExecutor **e) +av_cold void ff_vvc_executor_free(FFExecutor **e) { - av_executor_free(e); + ff_executor_free(e); } void ff_vvc_frame_thread_free(VVCFrameContext *fc) @@ -719,9 +719,9 @@ static void frame_thread_init_score(VVCFrameContext *fc) const VVCFrameThread *ft = fc->ft; VVCTask task; - task_init(&task, VVC_TASK_STAGE_RECON, fc, 0, 0); + task_init(&task, VVC_TASK_STAGE_PARSE, fc, 0, 0); - for (int i = VVC_TASK_STAGE_RECON; i < VVC_TASK_STAGE_LAST; i++) { + for (int i = VVC_TASK_STAGE_PARSE; i < VVC_TASK_STAGE_LAST; i++) { task.stage = i; for (task.rx = -1; task.rx <= ft->ctu_width; task.rx++) { @@ -822,6 +822,13 @@ int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc) } } } + for (int rs = 0; rs < ft->ctu_count; rs++) { + const VVCTask *t = ft->tasks + rs; + if (!t->sc) { + av_log(s->avctx, AV_LOG_ERROR, "frame %5d, CTU(%d, %d) not belong to any slice\r\n", (int)fc->decode_order, t->rx, t->ry); + return AVERROR_INVALIDDATA; + } + } frame_thread_add_score(s, ft, 0, 0, VVC_TASK_STAGE_INIT); return 0; @@ -839,8 +846,6 @@ int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc) ff_mutex_unlock(&ft->lock); ff_vvc_report_frame_finished(fc->ref); -#ifdef VVC_THREAD_DEBUG - av_log(s->avctx, AV_LOG_DEBUG, "frame %5d done\r\n", (int)fc->decode_order); -#endif + ff_dlog(s->avctx, "frame %5d done\r\n", (int)fc->decode_order); return ft->ret; } diff --git a/libavcodec/vvc/thread.h b/libavcodec/vvc/thread.h index 7b15dbee5..b89aee3b3 100644 --- a/libavcodec/vvc/thread.h +++ b/libavcodec/vvc/thread.h @@ -25,8 +25,8 @@ #include "dec.h" -struct AVExecutor* ff_vvc_executor_alloc(VVCContext *s, int thread_count); -void ff_vvc_executor_free(struct AVExecutor **e); +struct FFExecutor* ff_vvc_executor_alloc(VVCContext *s, int thread_count); +void ff_vvc_executor_free(struct FFExecutor **e); int ff_vvc_frame_thread_init(VVCFrameContext *fc); void ff_vvc_frame_thread_free(VVCFrameContext *fc); diff --git a/libavcodec/vvc_parser.c b/libavcodec/vvc_parser.c index 8d32d6657..6a96dc086 100644 --- a/libavcodec/vvc_parser.c +++ b/libavcodec/vvc_parser.c @@ -24,6 +24,7 @@ #include "cbs.h" #include "cbs_h266.h" #include "parser.h" +#include "parser_internal.h" #define START_CODE 0x000001 ///< start_code_prefix_one_3bytes #define IS_IDR(nut) (nut == VVC_IDR_W_RADL || nut == VVC_IDR_N_LP) @@ -300,14 +301,14 @@ static int get_pu_info(PuInfo *info, const CodedBitstreamH266Context *h266, } info->pps = h266->pps[info->ph->ph_pic_parameter_set_id]; if (!info->pps) { - av_log(logctx, AV_LOG_ERROR, "PPS id %d is not avaliable.\n", + av_log(logctx, AV_LOG_ERROR, "PPS id %d is not available.\n", info->ph->ph_pic_parameter_set_id); ret = AVERROR_INVALIDDATA; goto error; } info->sps = h266->sps[info->pps->pps_seq_parameter_set_id]; if (!info->sps) { - av_log(logctx, AV_LOG_ERROR, "SPS id %d is not avaliable.\n", + av_log(logctx, AV_LOG_ERROR, "SPS id %d is not available.\n", info->pps->pps_seq_parameter_set_id); ret = AVERROR_INVALIDDATA; goto error; @@ -357,7 +358,7 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, return 1; } - if ((ret = ff_cbs_read(ctx->cbc, pu, buf, buf_size)) < 0) { + if ((ret = ff_cbs_read(ctx->cbc, pu, NULL, buf, buf_size)) < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to parse picture unit.\n"); goto end; } @@ -505,10 +506,10 @@ static av_cold void vvc_parser_close(AVCodecParserContext *s) av_freep(&ctx->pc.buffer); } -const AVCodecParser ff_vvc_parser = { - .codec_ids = { AV_CODEC_ID_VVC }, +const FFCodecParser ff_vvc_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_VVC), .priv_data_size = sizeof(VVCParserContext), - .parser_init = vvc_parser_init, - .parser_close = vvc_parser_close, - .parser_parse = vvc_parser_parse, + .init = vvc_parser_init, + .close = vvc_parser_close, + .parse = vvc_parser_parse, }; diff --git a/libavcodec/wasm/hevc/Makefile b/libavcodec/wasm/hevc/Makefile new file mode 100644 index 000000000..7e8ab3776 --- /dev/null +++ b/libavcodec/wasm/hevc/Makefile @@ -0,0 +1,4 @@ +OBJS-$(CONFIG_HEVC_DECODER) += wasm/hevc/dsp_init.o + +SIMD128-OBJS-$(CONFIG_HEVC_DECODER) += wasm/hevc/idct.o \ + wasm/hevc/sao.o diff --git a/libavcodec/wasm/hevc/dsp_init.c b/libavcodec/wasm/hevc/dsp_init.c new file mode 100644 index 000000000..8672bbc2e --- /dev/null +++ b/libavcodec/wasm/hevc/dsp_init.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Zhao Zhili + * + * 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/cpu_internal.h" +#include "libavcodec/hevc/dsp.h" +#include "libavcodec/wasm/hevc/idct.h" +#include "libavcodec/wasm/hevc/sao.h" + +av_cold void ff_hevc_dsp_init_wasm(HEVCDSPContext *c, const int bit_depth) +{ + int cpu_flags = av_get_cpu_flags(); + + if (!CPUEXT(cpu_flags, SIMD128)) + return; + +#if HAVE_SIMD128 + if (bit_depth == 8) { + c->idct[0] = ff_hevc_idct_4x4_8_simd128; + c->idct[1] = ff_hevc_idct_8x8_8_simd128; + c->idct[2] = ff_hevc_idct_16x16_8_simd128; + c->idct[3] = ff_hevc_idct_32x32_8_simd128; + + c->sao_band_filter[0] = ff_hevc_sao_band_filter_8x8_8_simd128; + c->sao_band_filter[1] = + c->sao_band_filter[2] = + c->sao_band_filter[3] = + c->sao_band_filter[4] = ff_hevc_sao_band_filter_16x16_8_simd128; + + c->sao_edge_filter[0] = ff_hevc_sao_edge_filter_8x8_8_simd128; + c->sao_edge_filter[1] = + c->sao_edge_filter[2] = + c->sao_edge_filter[3] = + c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_16x16_8_simd128; + } else if (bit_depth == 10) { + c->idct[0] = ff_hevc_idct_4x4_10_simd128; + c->idct[1] = ff_hevc_idct_8x8_10_simd128; + c->idct[2] = ff_hevc_idct_16x16_10_simd128; + c->idct[3] = ff_hevc_idct_32x32_10_simd128; + } +#endif +} diff --git a/libavcodec/wasm/hevc/idct.c b/libavcodec/wasm/hevc/idct.c new file mode 100644 index 000000000..f2b04f307 --- /dev/null +++ b/libavcodec/wasm/hevc/idct.c @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2024 Zhao Zhili + * + * 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 "libavcodec/wasm/hevc/idct.h" + +#include + +#include "libavutil/mem_internal.h" + +static const int8_t transform[] = { + 64, 83, 64, 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, +}; + +static inline void transpose_4x8h(v128_t *src) +{ + v128_t t0 = wasm_i16x8_shuffle(src[0], src[1], 0, 8, 2, 10, 4, 12, 6, 14); + v128_t t1 = wasm_i16x8_shuffle(src[0], src[1], 1, 9, 3, 11, 5, 13, 7, 15); + v128_t t2 = wasm_i16x8_shuffle(src[2], src[3], 0, 8, 2, 10, 4, 12, 6, 14); + v128_t t3 = wasm_i16x8_shuffle(src[2], src[3], 1, 9, 3, 11, 5, 13, 7, 15); + + src[0] = wasm_i32x4_shuffle(t0, t2, 0, 4, 2, 6); + src[2] = wasm_i32x4_shuffle(t0, t2, 1, 5, 3, 7); + src[1] = wasm_i32x4_shuffle(t1, t3, 0, 4, 2, 6); + src[3] = wasm_i32x4_shuffle(t1, t3, 1, 5, 3, 7); +} + +static inline void transpose_8x8h(v128_t *src) +{ + transpose_4x8h(src); + transpose_4x8h(&src[4]); +} + +static inline void tr_4x4(v128_t *src, v128_t *trans, int shift) +{ + v128_t tmp[4]; + v128_t add = wasm_i32x4_splat(1 << (shift - 1)); + v128_t e0 = wasm_i32x4_extmul_low_i16x8(src[0], trans[0]); + v128_t e1 = wasm_i32x4_extmul_low_i16x8(src[0], trans[0]); + v128_t o0 = wasm_i32x4_extmul_low_i16x8(src[1], trans[1]); + v128_t o1 = wasm_i32x4_extmul_low_i16x8(src[1], trans[3]); + + tmp[0] = wasm_i32x4_extmul_low_i16x8(src[2], trans[0]); + tmp[1] = wasm_i32x4_extmul_low_i16x8(src[2], trans[0]); + tmp[2] = wasm_i32x4_extmul_low_i16x8(src[3], trans[3]); + tmp[3] = wasm_i32x4_extmul_low_i16x8(src[3], trans[1]); + e0 = wasm_i32x4_add(e0, tmp[0]); + e1 = wasm_i32x4_sub(e1, tmp[1]); + o0 = wasm_i32x4_add(o0, tmp[2]); + o1 = wasm_i32x4_sub(o1, tmp[3]); + + tmp[0] = wasm_i32x4_add(e0, o0); + tmp[1] = wasm_i32x4_sub(e0, o0); + tmp[2] = wasm_i32x4_add(e1, o1); + tmp[3] = wasm_i32x4_sub(e1, o1); + + tmp[0] = wasm_i32x4_add(tmp[0], add); + tmp[1] = wasm_i32x4_add(tmp[1], add); + tmp[2] = wasm_i32x4_add(tmp[2], add); + tmp[3] = wasm_i32x4_add(tmp[3], add); + tmp[0] = wasm_i32x4_shr(tmp[0], shift); + tmp[1] = wasm_i32x4_shr(tmp[1], shift); + tmp[2] = wasm_i32x4_shr(tmp[2], shift); + tmp[3] = wasm_i32x4_shr(tmp[3], shift); + + src[0] = wasm_i16x8_narrow_i32x4(tmp[0], tmp[0]); + src[3] = wasm_i16x8_narrow_i32x4(tmp[1], tmp[1]); + src[1] = wasm_i16x8_narrow_i32x4(tmp[2], tmp[2]); + src[2] = wasm_i16x8_narrow_i32x4(tmp[3], tmp[3]); +} + +static void idct_4x4(int16_t *coeffs, int bit_depth) +{ + v128_t src[4]; + v128_t trans[4]; + + src[0] = wasm_v128_load64_zero(&coeffs[0]); + src[1] = wasm_v128_load64_zero(&coeffs[4]); + src[2] = wasm_v128_load64_zero(&coeffs[8]); + src[3] = wasm_v128_load64_zero(&coeffs[12]); + + trans[0] = wasm_i16x8_const_splat(transform[0]); + trans[1] = wasm_i16x8_const_splat(transform[1]); + trans[2] = wasm_i16x8_const_splat(transform[2]); + trans[3] = wasm_i16x8_const_splat(transform[3]); + + tr_4x4(src, trans, 7); + transpose_4x8h(src); + + tr_4x4(src, trans, 20 - bit_depth); + transpose_4x8h(src); + + src[0] = wasm_i64x2_shuffle(src[0], src[1], 0, 2); + src[2] = wasm_i64x2_shuffle(src[2], src[3], 0, 2); + wasm_v128_store(&coeffs[0], src[0]); + wasm_v128_store(&coeffs[8], src[2]); +} + +void ff_hevc_idct_4x4_8_simd128(int16_t *coeffs, int col_limit) +{ + idct_4x4(coeffs, 8); +} + +void ff_hevc_idct_4x4_10_simd128(int16_t *coeffs, int col_limit) +{ + idct_4x4(coeffs, 10); +} + +static inline void shift_narrow_low(v128_t src, v128_t *dst, v128_t add, int shift) +{ + src = wasm_i32x4_add(src, add); + src = wasm_i32x4_shr(src, shift); + *dst = wasm_i64x2_shuffle(wasm_i16x8_narrow_i32x4(src, src), *dst, 0, 3); +} + +static inline void shift_narrow_high(v128_t src, v128_t *dst, v128_t add, int shift) +{ + src = wasm_i32x4_add(src, add); + src = wasm_i32x4_shr(src, shift); + *dst = wasm_i64x2_shuffle(wasm_i16x8_narrow_i32x4(src, src), *dst, 2, 0); +} + +#define tr_4x4_8(in0, in1, in2, in3, dst0, dst1, dst2, dst3, trans, half0, half1) \ + do { \ + v128_t e0, e1, o0, o1; \ + v128_t tmp[4]; \ + \ + e0 = wasm_i32x4_extmul_ ## half0 ## _i16x8(in0, trans[0]); \ + e1 = e0; \ + o0 = wasm_i32x4_extmul_ ## half0 ## _i16x8(in1, trans[1]); \ + o1 = wasm_i32x4_extmul_ ## half0 ## _i16x8(in1, trans[3]); \ + \ + tmp[0] = wasm_i32x4_extmul_ ## half1 ## _i16x8(in2, trans[0]); \ + tmp[1] = wasm_i32x4_extmul_ ## half1 ## _i16x8(in2, trans[0]); \ + tmp[2] = wasm_i32x4_extmul_ ## half1 ## _i16x8(in3, trans[3]); \ + tmp[3] = wasm_i32x4_extmul_ ## half1 ## _i16x8(in3, trans[1]); \ + e0 = wasm_i32x4_add(e0, tmp[0]); \ + e1 = wasm_i32x4_sub(e1, tmp[1]); \ + o0 = wasm_i32x4_add(o0, tmp[2]); \ + o1 = wasm_i32x4_sub(o1, tmp[3]); \ + dst0 = wasm_i32x4_add(e0, o0); \ + dst1 = wasm_i32x4_add(e1, o1); \ + dst2 = wasm_i32x4_sub(e1, o1); \ + dst3 = wasm_i32x4_sub(e0, o0); \ + } while (0) + +#define tr_8x4(src0, src1, half0, half1, trans, shift) \ + do { \ + v128_t v24, v25, v26, v27, v28, v29, v30, v31; \ + v128_t add = wasm_i32x4_splat(1 << (shift - 1)); \ + \ + tr_4x4_8(src0[0], src0[2], src1[0], src1[2], v24, v25, v26, v27, trans, half0, half1); \ + \ + v30 = wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[1], trans[6]); \ + v28 = wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[1], trans[4]); \ + v29 = wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[1], trans[5]); \ + v30 = wasm_i32x4_sub(v30, wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[3], trans[4])); \ + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[3], trans[5])); \ + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[3], trans[7])); \ + \ + v30 = wasm_i32x4_add(v30, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[1], trans[7])); \ + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[1], trans[6])); \ + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[1], trans[4])); \ + \ + v30 = wasm_i32x4_add(v30, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[3], trans[5])); \ + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[3], trans[7])); \ + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[3], trans[6])); \ + \ + v31 = wasm_i32x4_add(v26, v30); \ + v26 = wasm_i32x4_sub(v26, v30); \ + shift_narrow_ ## half0 (v31, &src0[2], add, shift); \ + v31 = wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[1], trans[7]); \ + v31 = wasm_i32x4_sub(v31, wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[3], trans[6])); \ + v31 = wasm_i32x4_add(v31, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[1], trans[5])); \ + v31 = wasm_i32x4_sub(v31, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[3], trans[4])); \ + shift_narrow_ ## half1 (v26, &src1[1], add, shift); \ + v26 = wasm_i32x4_add(v24, v28); \ + v24 = wasm_i32x4_sub(v24, v28); \ + v28 = wasm_i32x4_add(v25, v29); \ + v25 = wasm_i32x4_sub(v25, v29); \ + v30 = wasm_i32x4_add(v27, v31); \ + v27 = wasm_i32x4_sub(v27, v31); \ + shift_narrow_ ## half0 (v26, &src0[0], add, shift); \ + shift_narrow_ ## half1 (v24, &src1[3], add, shift); \ + shift_narrow_ ## half0 (v28, &src0[1], add, shift); \ + shift_narrow_ ## half1 (v25, &src1[2], add, shift); \ + shift_narrow_ ## half0 (v30, &src0[3], add, shift); \ + shift_narrow_ ## half1 (v27, &src1[0], add, shift); \ + } while (0) + +static void idct_8x8(int16_t *coeffs, int bit_depth) +{ + v128_t src[8]; + v128_t trans[8]; + v128_t *src1; + int shift1 = 7; + int shift2 = 20 - bit_depth; + + src[0] = wasm_v128_load(coeffs + 0 * 8); + src[1] = wasm_v128_load(coeffs + 1 * 8); + src[2] = wasm_v128_load(coeffs + 2 * 8); + src[3] = wasm_v128_load(coeffs + 3 * 8); + src[4] = wasm_v128_load(coeffs + 4 * 8); + src[5] = wasm_v128_load(coeffs + 5 * 8); + src[6] = wasm_v128_load(coeffs + 6 * 8); + src[7] = wasm_v128_load(coeffs + 7 * 8); + + trans[0] = wasm_i16x8_const_splat(transform[0]); + trans[1] = wasm_i16x8_const_splat(transform[1]); + trans[2] = wasm_i16x8_const_splat(transform[2]); + trans[3] = wasm_i16x8_const_splat(transform[3]); + trans[4] = wasm_i16x8_const_splat(transform[4]); + trans[5] = wasm_i16x8_const_splat(transform[5]); + trans[6] = wasm_i16x8_const_splat(transform[6]); + trans[7] = wasm_i16x8_const_splat(transform[7]); + + src1 = &src[4]; + tr_8x4(src, src1, low, low, trans, shift1); + tr_8x4(src, src1, high, high, trans, shift1); + transpose_8x8h(src); + tr_8x4(src, src, low, high, trans, shift2); + tr_8x4(src1, src1, low, high, trans, shift2); + transpose_8x8h(src); + + wasm_v128_store(&coeffs[0 * 8], src[0]); + wasm_v128_store(&coeffs[1 * 8], src[1]); + wasm_v128_store(&coeffs[2 * 8], src[2]); + wasm_v128_store(&coeffs[3 * 8], src[3]); + wasm_v128_store(&coeffs[4 * 8], src[4]); + wasm_v128_store(&coeffs[5 * 8], src[5]); + wasm_v128_store(&coeffs[6 * 8], src[6]); + wasm_v128_store(&coeffs[7 * 8], src[7]); +} + +void ff_hevc_idct_8x8_8_simd128(int16_t *coeffs, int col_limit) +{ + idct_8x8(coeffs, 8); +} + +void ff_hevc_idct_8x8_10_simd128(int16_t *coeffs, int col_limit) +{ + idct_8x8(coeffs, 10); +} + +#define load16(x1, x3, x2, in0, in1, in2, in3) \ + in0 = wasm_v128_load64_zero(x1); \ + in0 = wasm_v128_load64_lane(x3, in0, 1); \ + x1 += x2; \ + x3 += x2; \ + in1 = wasm_v128_load64_zero(x1); \ + in1 = wasm_v128_load64_lane(x3, in1, 1); \ + x1 += x2; \ + x3 += x2; \ + in2 = wasm_v128_load64_zero(x1); \ + in2 = wasm_v128_load64_lane(x3, in2, 1); \ + x1 += x2; \ + x3 += x2; \ + in3 = wasm_v128_load64_zero(x1); \ + in3 = wasm_v128_load64_lane(x3, in3, 1); \ + x1 += x2; \ + x3 += x2; \ + +#define butterfly(e, o, p, m) \ + p = wasm_i32x4_add(e, o); \ + m = wasm_i32x4_sub(e, o); \ + +static void tr16_8x4(v128_t in0, v128_t in1, v128_t in2, v128_t in3, + const v128_t *trans, char *sp, int offset) +{ + v128_t v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31; + + tr_4x4_8(in0, in1, in2, in3, v24, v25, v26, v27, trans, low, low); + + v28 = wasm_i32x4_extmul_high_i16x8(in0, trans[4]); + v29 = wasm_i32x4_extmul_high_i16x8(in0, trans[5]); + v30 = wasm_i32x4_extmul_high_i16x8(in0, trans[6]); + v31 = wasm_i32x4_extmul_high_i16x8(in0, trans[7]); + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_high_i16x8(in1, trans[5])); + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_high_i16x8(in1, trans[7])); + v30 = wasm_i32x4_sub(v30, wasm_i32x4_extmul_high_i16x8(in1, trans[4])); + v31 = wasm_i32x4_sub(v31, wasm_i32x4_extmul_high_i16x8(in1, trans[6])); + + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_high_i16x8(in2, trans[6])); + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_high_i16x8(in2, trans[4])); + v30 = wasm_i32x4_add(v30, wasm_i32x4_extmul_high_i16x8(in2, trans[7])); + v31 = wasm_i32x4_add(v31, wasm_i32x4_extmul_high_i16x8(in2, trans[5])); + + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_high_i16x8(in3, trans[7])); + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_high_i16x8(in3, trans[6])); + v30 = wasm_i32x4_add(v30, wasm_i32x4_extmul_high_i16x8(in3, trans[5])); + v31 = wasm_i32x4_sub(v31, wasm_i32x4_extmul_high_i16x8(in3, trans[4])); + + butterfly(v24, v28, v16, v23); + butterfly(v25, v29, v17, v22); + butterfly(v26, v30, v18, v21); + butterfly(v27, v31, v19, v20); + + sp += offset; + wasm_v128_store(sp, v16); sp += 16; + wasm_v128_store(sp, v17); sp += 16; + wasm_v128_store(sp, v18); sp += 16; + wasm_v128_store(sp, v19); sp += 16; + wasm_v128_store(sp, v20); sp += 16; + wasm_v128_store(sp, v21); sp += 16; + wasm_v128_store(sp, v22); sp += 16; + wasm_v128_store(sp, v23); +} + +static void scale(v128_t *out0, v128_t *out1, v128_t *out2, v128_t *out3, + v128_t in0, v128_t in1, v128_t in2, v128_t in3, + v128_t in4, v128_t in5, v128_t in6, v128_t in7, + int shift) +{ + v128_t add = wasm_i32x4_splat(1 << (shift - 1)); + + in0 = wasm_i32x4_add(in0, add); + in1 = wasm_i32x4_add(in1, add); + in2 = wasm_i32x4_add(in2, add); + in3 = wasm_i32x4_add(in3, add); + in4 = wasm_i32x4_add(in4, add); + in5 = wasm_i32x4_add(in5, add); + in6 = wasm_i32x4_add(in6, add); + in7 = wasm_i32x4_add(in7, add); + + in0 = wasm_i32x4_shr(in0, shift); + in1 = wasm_i32x4_shr(in1, shift); + in2 = wasm_i32x4_shr(in2, shift); + in3 = wasm_i32x4_shr(in3, shift); + in4 = wasm_i32x4_shr(in4, shift); + in5 = wasm_i32x4_shr(in5, shift); + in6 = wasm_i32x4_shr(in6, shift); + in7 = wasm_i32x4_shr(in7, shift); + + *out0 = wasm_i16x8_narrow_i32x4(in0, in1); + *out1 = wasm_i16x8_narrow_i32x4(in2, in3); + *out2 = wasm_i16x8_narrow_i32x4(in4, in5); + *out3 = wasm_i16x8_narrow_i32x4(in6, in7); +} + +static void transpose16_4x4_2(v128_t *r0, v128_t *r1, v128_t *r2, v128_t *r3) +{ + v128_t t0, t1, t2, t3, t4, t5; + + t0 = wasm_i16x8_shuffle(*r0, *r1, 0, 8, 2, 10, 4, 12, 6, 14); + t1 = wasm_i16x8_shuffle(*r0, *r1, 1, 9, 3, 11, 5, 13, 7, 15); + t2 = wasm_i16x8_shuffle(*r2, *r3, 0, 8, 2, 10, 4, 12, 6, 14); + t3 = wasm_i16x8_shuffle(*r2, *r3, 1, 9, 3, 11, 5, 13, 7, 15); + t4 = wasm_i32x4_shuffle(t0, t2, 0, 4, 2, 6); + t5 = wasm_i32x4_shuffle(t0, t2, 1, 5, 3, 7); + t0 = wasm_i32x4_shuffle(t1, t3, 0, 4, 2, 6); + t2 = wasm_i32x4_shuffle(t1, t3, 1, 5, 3, 7); + *r0 = wasm_i64x2_shuffle(t4, *r0, 0, 3); + *r2 = wasm_i64x2_shuffle(t5, *r2, 0, 3); + *r1 = wasm_i64x2_shuffle(t0, *r1, 0, 3); + *r3 = wasm_i64x2_shuffle(t2, *r3, 0, 3); + + t0 = wasm_i16x8_shuffle(*r3, *r2, 0, 8, 2, 10, 4, 12, 6, 14); + t1 = wasm_i16x8_shuffle(*r3, *r2, 1, 9, 3, 11, 5, 13, 7, 15); + t2 = wasm_i16x8_shuffle(*r1, *r0, 0, 8, 2, 10, 4, 12, 6, 14); + t3 = wasm_i16x8_shuffle(*r1, *r0, 1, 9, 3, 11, 5, 13, 7, 15); + t4 = wasm_i32x4_shuffle(t0, t2, 0, 4, 2, 6); + t5 = wasm_i32x4_shuffle(t0, t2, 1, 5, 3, 7); + t0 = wasm_i32x4_shuffle(t1, t3, 0, 4, 2, 6); + t2 = wasm_i32x4_shuffle(t1, t3, 1, 5, 3, 7); + *r3 = wasm_i64x2_shuffle(*r3, t4, 0, 3); + *r1 = wasm_i64x2_shuffle(*r1, t5, 0, 3); + *r2 = wasm_i64x2_shuffle(*r2, t0, 0, 3); + *r0 = wasm_i64x2_shuffle(*r0, t2, 0, 3); +} + +static void store16(v128_t in0, v128_t in1, v128_t in2, v128_t in3, + char *x1, char *x3, int x1_step, int x3_step) +{ + wasm_v128_store64_lane(x1, in0, 0); + wasm_v128_store64_lane(x3, in0, 1); + x1 += x1_step; + x3 += x3_step; + + wasm_v128_store64_lane(x1, in1, 0); + wasm_v128_store64_lane(x3, in1, 1); + x1 += x1_step; + x3 += x3_step; + + wasm_v128_store64_lane(x1, in2, 0); + wasm_v128_store64_lane(x3, in2, 1); + x1 += x1_step; + x3 += x3_step; + + wasm_v128_store64_lane(x1, in3, 0); + wasm_v128_store64_lane(x3, in3, 1); +} + + +static void store_to_stack(char *sp, int off1, int off2, + v128_t in0, v128_t in2, v128_t in4, v128_t in6, + v128_t in7, v128_t in5, v128_t in3, v128_t in1) +{ + char *x1 = sp + off1; + char *x3 = sp + off2; + + wasm_v128_store(x1, in0); + wasm_v128_store(x3, in1); + x1 += 16; + x3 -= 16; + wasm_v128_store(x1, in2); + wasm_v128_store(x3, in3); + x1 += 16; + x3 -= 16; + wasm_v128_store(x1, in4); + wasm_v128_store(x3, in5); + x1 += 16; + x3 -= 16; + wasm_v128_store(x1, in6); + wasm_v128_store(x3, in7); +} + +#define sum_sub(out, in0, in1, operation, half) \ + out = wasm_i32x4_ ## operation (out, wasm_i32x4_extmul_ ## half ## _i16x8(in0, in1)); + +#define add_member(in, t0, t1, t2, t3, t4, t5, t6, t7, op0, op1, op2, op3, op4, op5, op6, op7, half) \ + do { \ + sum_sub(v21, in, t0, op0, half) \ + sum_sub(v22, in, t1, op1, half) \ + sum_sub(v23, in, t2, op2, half) \ + sum_sub(v24, in, t3, op3, half) \ + sum_sub(v25, in, t4, op4, half) \ + sum_sub(v26, in, t5, op5, half) \ + sum_sub(v27, in, t6, op6, half) \ + sum_sub(v28, in, t7, op7, half) \ + } while (0) + +#define butterfly16(in0, in1, in2, in3, in4, in5, in6, in7) \ + do { \ + v20 = wasm_i32x4_add(in0, in1); \ + in0 = wasm_i32x4_sub(in0, in1); \ + in1 = wasm_i32x4_add(in2, in3); \ + in2 = wasm_i32x4_sub(in2, in3); \ + in3 = wasm_i32x4_add(in4, in5); \ + in4 = wasm_i32x4_sub(in4, in5); \ + in5 = wasm_i32x4_add(in6, in7); \ + in6 = wasm_i32x4_sub(in6, in7); \ + } while (0) + +static void tr_16x4(char *src, char *buf, char *sp, + int shift, int offset, int step) +{ + char *x1, *x3, *x4; + int x2; + v128_t trans[8]; + v128_t v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31; + + trans[0] = wasm_i16x8_const_splat(transform[0]); + trans[1] = wasm_i16x8_const_splat(transform[1]); + trans[2] = wasm_i16x8_const_splat(transform[2]); + trans[3] = wasm_i16x8_const_splat(transform[3]); + trans[4] = wasm_i16x8_const_splat(transform[4]); + trans[5] = wasm_i16x8_const_splat(transform[5]); + trans[6] = wasm_i16x8_const_splat(transform[6]); + trans[7] = wasm_i16x8_const_splat(transform[7]); + + x1 = src; + x3 = src + step * 64; + x2 = step * 128; + load16(x1, x3, x2, v16, v17, v18, v19); + tr16_8x4(v16, v17, v18, v19, trans, sp, offset); + + x1 = src + step * 32; + x3 = src + step * 3 * 32; + x2 = step * 128; + load16(x1, x3, x2, v20, v17, v18, v19); + + trans[0] = wasm_i16x8_const_splat(transform[0 + 8]); + trans[1] = wasm_i16x8_const_splat(transform[1 + 8]); + trans[2] = wasm_i16x8_const_splat(transform[2 + 8]); + trans[3] = wasm_i16x8_const_splat(transform[3 + 8]); + trans[4] = wasm_i16x8_const_splat(transform[4 + 8]); + trans[5] = wasm_i16x8_const_splat(transform[5 + 8]); + trans[6] = wasm_i16x8_const_splat(transform[6 + 8]); + trans[7] = wasm_i16x8_const_splat(transform[7 + 8]); + + v21 = wasm_i32x4_extmul_low_i16x8(v20, trans[0]); + v22 = wasm_i32x4_extmul_low_i16x8(v20, trans[1]); + v23 = wasm_i32x4_extmul_low_i16x8(v20, trans[2]); + v24 = wasm_i32x4_extmul_low_i16x8(v20, trans[3]); + v25 = wasm_i32x4_extmul_low_i16x8(v20, trans[4]); + v26 = wasm_i32x4_extmul_low_i16x8(v20, trans[5]); + v27 = wasm_i32x4_extmul_low_i16x8(v20, trans[6]); + v28 = wasm_i32x4_extmul_low_i16x8(v20, trans[7]); + + add_member(v20, trans[1], trans[4], trans[7], trans[5], + trans[2], trans[0], trans[3], trans[6], + add, add, add, sub, sub, sub, sub, sub, high); + add_member(v17, trans[2], trans[7], trans[3], trans[1], + trans[6], trans[4], trans[0], trans[5], + add, add, sub, sub, sub, add, add, add, low); + add_member(v17, trans[3], trans[5], trans[1], trans[7], + trans[0], trans[6], trans[2], trans[4], + add, sub, sub, add, add, add, sub, sub, high); + add_member(v18, trans[4], trans[2], trans[6], trans[0], + trans[7], trans[1], trans[5], trans[3], + add, sub, sub, add, sub, sub, add, add, low); + add_member(v18, trans[5], trans[0], trans[4], trans[6], + trans[1], trans[3], trans[7], trans[2], + add, sub, add, add, sub, add, add, sub, high); + add_member(v19, trans[6], trans[3], trans[0], trans[2], + trans[5], trans[7], trans[4], trans[1], + add, sub, add, sub, add, add, sub, add, low); + add_member(v19, trans[7], trans[6], trans[5], trans[4], + trans[3], trans[2], trans[1], trans[0], + add, sub, add, sub, add, sub, add, sub, high); + + x4 = &sp[offset]; + v16 = wasm_v128_load(x4); + x4 += 16; + v17 = wasm_v128_load(x4); + x4 += 16; + v18 = wasm_v128_load(x4); + x4 += 16; + v19 = wasm_v128_load(x4); + butterfly16(v16, v21, v17, v22, v18, v23, v19, v24); + + if (shift > 0) { + scale(&v29, &v30, &v31, &v24, + v20, v16, v21, v17, v22, v18, v23, v19, + shift); + transpose16_4x4_2(&v29, &v30, &v31, &v24); + x1 = buf; + x3 = &buf[24 + 3 * 32]; + store16(v29, v30, v31, v24, x1, x3, 32, -32); + } else { + store_to_stack(sp, offset, offset + 240, + v20, v21, v22, v23, v19, v18, v17, v16); + } + + x4 = &sp[offset + 64]; + v16 = wasm_v128_load(x4); + x4 += 16; + v17 = wasm_v128_load(x4); + x4 += 16; + v18 = wasm_v128_load(x4); + x4 += 16; + v19 = wasm_v128_load(x4); + butterfly16(v16, v25, v17, v26, v18, v27, v19, v28); + + if (shift > 0) { + scale(&v29, &v30, &v31, &v20, + v20, v16, v25, v17, v26, v18, v27, v19, + shift); + transpose16_4x4_2(&v29, &v30, &v31, &v20); + x1 = &buf[8]; + x3 = &buf[16 + 3 * 32]; + store16(v29, v30, v31, v20, x1, x3, 32, -32); + } else { + store_to_stack(sp, offset + 64, offset + 176, + v20, v25, v26, v27, v19, v18, v17, v16); + } +} + +static void idct_16x16(char *coeffs, int bit_depth) +{ + DECLARE_ALIGNED(16, char, sp)[640]; + + for (int i = 0; i < 4; i++) { + char *x5 = &coeffs[8 * i]; + char *x6 = &sp[8 * i * 16]; + tr_16x4(x5, x6, sp, 7, 512, 1); + } + + for (int i = 0; i < 4; i++) { + char *x5 = &sp[8 * i]; + char *x6 = &coeffs[8 * i * 16]; + tr_16x4(x5, x6, sp, 20 - bit_depth, 512, 1); + } +} + +void ff_hevc_idct_16x16_8_simd128(int16_t *coeffs, int col_limit) +{ + idct_16x16((char *)coeffs, 8); +} + +void ff_hevc_idct_16x16_10_simd128(int16_t *coeffs, int col_limit) +{ + idct_16x16((char *)coeffs, 10); +} + +#define add_member32(in, t0, t1, t2, t3, op0, op1, op2, op3, half) \ + do { \ + sum_sub(v24, in, t0, op0, half) \ + sum_sub(v25, in, t1, op1, half) \ + sum_sub(v26, in, t2, op2, half) \ + sum_sub(v27, in, t3, op3, half) \ + } while (0) + +#define butterfly32(in0, in1, in2, in3, out) \ + do { \ + out = wasm_i32x4_add(in0, in1); \ + in0 = wasm_i32x4_sub(in0, in1); \ + in1 = wasm_i32x4_add(in2, in3); \ + in2 = wasm_i32x4_sub(in2, in3); \ + } while (0) + +static void tr_32x4(char *x5, char *x11, char *sp, int shift) +{ + char *x1, *x3, *x4; + // transform in v0 - v4 + v128_t v0[4]; + v128_t v1[4]; + v128_t v2[4]; + v128_t v3[4]; + v128_t v4, v5, v6, v7, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, + v28, v29, v30, v31, v32, v33; + + tr_16x4(x5, x11, sp, 0, 2048, 4); + + // load32 + x1 = &x5[64]; + x3 = &x1[128]; + v4 = wasm_v128_load64_zero(x1); + v4 = wasm_v128_load64_lane(x3, v4, 1); + x1 += 256; + x3 += 256; + v5 = wasm_v128_load64_zero(x1); + v5 = wasm_v128_load64_lane(x3, v5, 1); + x1 += 256; + x3 += 256; + v6 = wasm_v128_load64_zero(x1); + v6 = wasm_v128_load64_lane(x3, v6, 1); + x1 += 256; + x3 += 256; + v7 = wasm_v128_load64_zero(x1); + v7 = wasm_v128_load64_lane(x3, v7, 1); + x1 += 256; + x3 += 256; + v16 = wasm_v128_load64_zero(x1); + v16 = wasm_v128_load64_lane(x3, v16, 1); + x1 += 256; + x3 += 256; + v17 = wasm_v128_load64_zero(x1); + v17 = wasm_v128_load64_lane(x3, v17, 1); + x1 += 256; + x3 += 256; + v18 = wasm_v128_load64_zero(x1); + v18 = wasm_v128_load64_lane(x3, v18, 1); + x1 += 256; + x3 += 256; + v19 = wasm_v128_load64_zero(x1); + v19 = wasm_v128_load64_lane(x3, v19, 1); + + // load transform + v0[0] = wasm_i16x8_const_splat(transform[16 + 0]); + v0[1] = wasm_i16x8_const_splat(transform[16 + 1]); + v0[2] = wasm_i16x8_const_splat(transform[16 + 2]); + v0[3] = wasm_i16x8_const_splat(transform[16 + 3]); + v1[0] = wasm_i16x8_const_splat(transform[16 + 4]); + v1[1] = wasm_i16x8_const_splat(transform[16 + 5]); + v1[2] = wasm_i16x8_const_splat(transform[16 + 6]); + v1[3] = wasm_i16x8_const_splat(transform[16 + 7]); + v2[0] = wasm_i16x8_const_splat(transform[16 + 8]); + v2[1] = wasm_i16x8_const_splat(transform[16 + 9]); + v2[2] = wasm_i16x8_const_splat(transform[16 + 10]); + v2[3] = wasm_i16x8_const_splat(transform[16 + 11]); + v3[0] = wasm_i16x8_const_splat(transform[16 + 12]); + v3[1] = wasm_i16x8_const_splat(transform[16 + 13]); + v3[2] = wasm_i16x8_const_splat(transform[16 + 14]); + v3[3] = wasm_i16x8_const_splat(transform[16 + 15]); + + // tr_block1 + v24 = wasm_i32x4_extmul_low_i16x8(v4, v0[0]); + v25 = wasm_i32x4_extmul_low_i16x8(v4, v0[1]); + v26 = wasm_i32x4_extmul_low_i16x8(v4, v0[2]); + v27 = wasm_i32x4_extmul_low_i16x8(v4, v0[3]); + + add_member32(v4, v0[1], v1[0], v1[3], v2[2], add, add, add, add, high); + add_member32(v5, v0[2], v1[3], v3[0], v3[2], add, add, add, sub, low); + add_member32(v5, v0[3], v2[2], v3[2], v1[3], add, add, sub, sub, high); + add_member32(v6, v1[0], v3[1], v2[1], v0[0], add, add, sub, sub, low); + add_member32(v6, v1[1], v3[3], v1[0], v1[2], add, sub, sub, sub, high); + add_member32(v7, v1[2], v3[0], v0[0], v3[1], add, sub, sub, sub, low); + add_member32(v7, v1[3], v2[1], v1[1], v2[3], add, sub, sub, add, high); + add_member32(v16, v2[0], v1[2], v2[2], v1[0], add, sub, sub, add, low); + add_member32(v16, v2[1], v0[3], v3[3], v0[2], add, sub, sub, add, high); + add_member32(v17, v2[2], v0[1], v2[3], v2[1], add, sub, add, add, low); + add_member32(v17, v2[3], v0[2], v1[2], v3[3], add, sub, add, sub, high); + add_member32(v18, v3[0], v1[1], v0[1], v2[0], add, sub, add, sub, low); + add_member32(v18, v3[1], v2[0], v0[3], v0[1], add, sub, add, sub, high); + add_member32(v19, v3[2], v2[3], v2[0], v1[1], add, sub, add, sub, low); + add_member32(v19, v3[3], v3[2], v3[1], v3[0], add, sub, add, sub, high); + + x4 = &sp[2048]; + // scale_store + v28 = wasm_v128_load(x4); + x4 += 16; + v29 = wasm_v128_load(x4); + x4 += 16; + v30 = wasm_v128_load(x4); + x4 += 16; + v31 = wasm_v128_load(x4); + x4 += 16; + butterfly32(v28, v24, v29, v25, v32); + butterfly32(v30, v26, v31, v27, v33); + scale(&v20, &v21, &v22, &v23, v32, v28, v24, v29, v33, v30, v26, v31, shift); + transpose16_4x4_2(&v20, &v21, &v22, &v23); + x1 = x11; + x3 = &x11[56 + 3 * 64]; + store16(v20, v21, v22, v23, x1, x3, 64, -64); + + // tr_block2 + v24 = wasm_i32x4_extmul_low_i16x8(v4, v1[0]); + v25 = wasm_i32x4_extmul_low_i16x8(v4, v1[1]); + v26 = wasm_i32x4_extmul_low_i16x8(v4, v1[2]); + v27 = wasm_i32x4_extmul_low_i16x8(v4, v1[3]); + + add_member32(v4, v3[1], v3[3], v3[0], v2[1], add, sub, sub, sub, high); + add_member32(v5, v2[1], v1[0], v0[0], v1[1], sub, sub, sub, sub, low); + add_member32(v5, v0[0], v1[2], v3[1], v2[3], sub, sub, sub, add, high); + add_member32(v6, v2[0], v3[2], v1[1], v0[3], sub, add, add, add, low); + add_member32(v6, v3[2], v0[3], v1[3], v3[1], add, add, add, sub, high); + add_member32(v7, v1[1], v1[3], v2[3], v0[0], add, add, sub, sub, low); + add_member32(v7, v0[3], v3[1], v0[1], v3[3], add, sub, sub, add, high); + add_member32(v16, v3[0], v0[2], v3[2], v0[1], add, sub, sub, add, low); + add_member32(v16, v2[2], v2[0], v1[0], v3[2], sub, sub, add, add, high); + add_member32(v17, v0[1], v3[0], v2[0], v0[2], sub, add, add, sub, low); + add_member32(v17, v1[3], v0[1], v2[2], v3[0], sub, add, sub, sub, high); + add_member32(v18, v3[3], v2[1], v0[2], v1[0], add, add, sub, add, low); + add_member32(v18, v1[2], v2[3], v3[3], v2[2], add, sub, sub, add, high); + add_member32(v19, v0[2], v0[1], v0[3], v1[2], add, sub, add, sub, low); + add_member32(v19, v2[3], v2[2], v2[1], v2[0], add, sub, add, sub, high); + + // scale_store + v28 = wasm_v128_load(x4); + x4 += 16; + v29 = wasm_v128_load(x4); + x4 += 16; + v30 = wasm_v128_load(x4); + x4 += 16; + v31 = wasm_v128_load(x4); + x4 += 16; + butterfly32(v28, v24, v29, v25, v32); + butterfly32(v30, v26, v31, v27, v33); + scale(&v20, &v21, &v22, &v23, v32, v28, v24, v29, v33, v30, v26, v31, shift); + transpose16_4x4_2(&v20, &v21, &v22, &v23); + x1 = &x11[8]; + x3 = &x11[48 + 3 * 64]; + store16(v20, v21, v22, v23, x1, x3, 64, -64); + + // tr_block3 + v24 = wasm_i32x4_extmul_low_i16x8(v4, v2[0]); + v25 = wasm_i32x4_extmul_low_i16x8(v4, v2[1]); + v26 = wasm_i32x4_extmul_low_i16x8(v4, v2[2]); + v27 = wasm_i32x4_extmul_low_i16x8(v4, v2[3]); + add_member32(v4, v1[2], v0[3], v0[0], v0[2], sub, sub, sub, sub, high); + add_member32(v5, v2[2], v3[3], v2[3], v1[2], sub, sub, add, add, low); + add_member32(v5, v1[0], v0[2], v2[1], v3[3], add, add, add, sub, high); + add_member32(v6, v3[0], v2[2], v0[1], v1[3], add, sub, sub, sub, low); + add_member32(v6, v0[2], v2[0], v3[0], v0[0], sub, sub, add, add, high); + add_member32(v7, v3[2], v1[0], v2[0], v2[2], sub, add, add, sub, low); + add_member32(v7, v0[0], v3[2], v0[2], v3[0], add, add, sub, sub, high); + add_member32(v16, v3[3], v0[1], v3[1], v0[3], sub, sub, add, add, low); + add_member32(v16, v0[1], v2[3], v1[3], v1[1], sub, add, add, sub, high); + add_member32(v17, v3[1], v1[3], v0[3], v3[2], add, add, sub, add, low); + add_member32(v17, v0[3], v1[1], v3[2], v2[0], add, sub, add, add, high); + add_member32(v18, v2[3], v3[1], v1[2], v0[1], sub, sub, add, sub, low); + add_member32(v18, v1[1], v0[0], v1[0], v2[1], sub, add, sub, add, high); + add_member32(v19, v2[1], v3[0], v3[3], v3[1], add, sub, add, add, low); + add_member32(v19, v1[3], v1[2], v1[1], v1[0], add, sub, add, sub, high); + + // scale_store + v28 = wasm_v128_load(x4); + x4 += 16; + v29 = wasm_v128_load(x4); + x4 += 16; + v30 = wasm_v128_load(x4); + x4 += 16; + v31 = wasm_v128_load(x4); + x4 += 16; + butterfly32(v28, v24, v29, v25, v32); + butterfly32(v30, v26, v31, v27, v33); + scale(&v20, &v21, &v22, &v23, v32, v28, v24, v29, v33, v30, v26, v31, shift); + transpose16_4x4_2(&v20, &v21, &v22, &v23); + x1 = &x11[16]; + x3 = &x11[40 + 3 * 64]; + store16(v20, v21, v22, v23, x1, x3, 64, -64); + + // try_block4 + v24 = wasm_i32x4_extmul_low_i16x8(v4, v3[0]); + v25 = wasm_i32x4_extmul_low_i16x8(v4, v3[1]); + v26 = wasm_i32x4_extmul_low_i16x8(v4, v3[2]); + v27 = wasm_i32x4_extmul_low_i16x8(v4, v3[3]); + add_member32(v4, v1[1], v2[0], v2[3], v3[2], sub, sub, sub, sub, high); + add_member32(v5, v0[0], v0[3], v2[0], v3[1], add, add, add, add, low); + add_member32(v5, v2[0], v0[0], v1[1], v3[0], sub, sub, sub, sub, high); + add_member32(v6, v3[3], v1[2], v0[2], v2[3], add, add, add, add, low); + add_member32(v6, v2[1], v2[3], v0[0], v2[2], add, sub, sub, sub, high); + add_member32(v7, v0[2], v3[3], v0[3], v2[1], sub, sub, add, add, low); + add_member32(v7, v1[0], v2[2], v1[2], v2[0], add, add, sub, sub, high); + add_member32(v16, v2[3], v1[1], v2[1], v1[3], sub, sub, add, add, low); + add_member32(v16, v3[1], v0[1], v3[0], v1[2], sub, add, sub, sub, high); + add_member32(v17, v1[2], v1[0], v3[3], v1[1], add, sub, add, add, low); + add_member32(v17, v0[1], v2[1], v3[1], v1[0], sub, add, add, sub, high); + add_member32(v18, v1[3], v3[2], v2[2], v0[3], add, sub, sub, add, low); + add_member32(v18, v3[2], v3[0], v1[3], v0[2], sub, sub, add, sub, high); + add_member32(v19, v2[2], v1[3], v1[0], v0[1], sub, add, sub, add, low); + add_member32(v19, v0[3], v0[2], v0[1], v0[0], add, sub, add, sub, high); + + // scale_store + v28 = wasm_v128_load(x4); + x4 += 16; + v29 = wasm_v128_load(x4); + x4 += 16; + v30 = wasm_v128_load(x4); + x4 += 16; + v31 = wasm_v128_load(x4); + butterfly32(v28, v24, v29, v25, v32); + butterfly32(v30, v26, v31, v27, v33); + scale(&v20, &v21, &v22, &v23, v32, v28, v24, v29, v33, v30, v26, v31, shift); + transpose16_4x4_2(&v20, &v21, &v22, &v23); + x1 = &x11[24]; + x3 = &x11[32 + 3 * 64]; + store16(v20, v21, v22, v23, x1, x3, 64, -64); +} + +static void idct_32x32(char *coeffs, int bit_depth) +{ + DECLARE_ALIGNED(16, char, sp)[2432]; + char *x5, *x11; + + for (int i = 0; i < 8; i++) { + x5 = &coeffs[8 * i]; + x11 = &sp[8 * i * 32]; + tr_32x4(x5, x11, sp, 7); + } + + for (int i = 0; i < 8; i++) { + x5 = &sp[8 * i]; + x11 = &coeffs[8 * i * 32]; + tr_32x4(x5, x11, sp, 20 - bit_depth); + } +} + +void ff_hevc_idct_32x32_8_simd128(int16_t *coeffs, int col_limit) +{ + idct_32x32((char *)coeffs, 8); +} + +void ff_hevc_idct_32x32_10_simd128(int16_t *coeffs, int col_limit) +{ + idct_32x32((char *)coeffs, 10); +} diff --git a/libavcodec/wasm/hevc/idct.h b/libavcodec/wasm/hevc/idct.h new file mode 100644 index 000000000..05c64ae68 --- /dev/null +++ b/libavcodec/wasm/hevc/idct.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Zhao Zhili + * + * 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_WASM_HEVC_IDCT_H +#define AVCODEC_WASM_HEVC_IDCT_H + +#include + +void ff_hevc_idct_4x4_8_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_8x8_8_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_16x16_8_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_32x32_8_simd128(int16_t *coeffs, int col_limit); + +void ff_hevc_idct_4x4_10_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_8x8_10_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_16x16_10_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_32x32_10_simd128(int16_t *coeffs, int col_limit); + +#endif /* AVCODEC_WASM_HEVC_IDCT_H */ diff --git a/libavcodec/wasm/hevc/sao.c b/libavcodec/wasm/hevc/sao.c new file mode 100644 index 000000000..a863b8e72 --- /dev/null +++ b/libavcodec/wasm/hevc/sao.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2025 Zhao Zhili + * + * 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 "sao.h" + +#include + +#include "libavcodec/defs.h" + +#define HEVC_MAX_PB_SIZE 64 + +void ff_hevc_sao_band_filter_8x8_8_simd128(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride_dst, + ptrdiff_t stride_src, + const int16_t *sao_offset_val, + int sao_left_class, int width, + int height) +{ + int8_t offset_table[32] = {0}; + v128_t offset_low, offset_high; + + for (int k = 0; k < 4; k++) + offset_table[(k + sao_left_class) & 31] = (int8_t)sao_offset_val[k + 1]; + + offset_low = wasm_v128_load(offset_table); + offset_high = wasm_v128_load(&offset_table[16]); + + for (int y = height; y > 0; y -= 2) { + v128_t src_v, src_high; + v128_t v0, v1; + + src_v = wasm_v128_load64_zero(src); + src += stride_src; + src_v = wasm_v128_load64_lane(src, src_v, 1); + src += stride_src; + + v0 = wasm_u8x16_shr(src_v, 3); + v1 = wasm_i8x16_sub(v0, wasm_i8x16_const_splat(16)); + v0 = wasm_i8x16_swizzle(offset_low, v0); + v1 = wasm_i8x16_swizzle(offset_high, v1); + v0 = wasm_v128_or(v0, v1); + src_high = wasm_u16x8_extend_high_u8x16(src_v); + v1 = wasm_i16x8_extend_high_i8x16(v0); + src_v = wasm_u16x8_extend_low_u8x16(src_v); + v0 = wasm_i16x8_extend_low_i8x16(v0); + + v0 = wasm_i16x8_add_sat(src_v, v0); + v1 = wasm_i16x8_add_sat(src_high, v1); + v0 = wasm_u8x16_narrow_i16x8(v0, v1); + + wasm_v128_store64_lane(dst, v0, 0); + dst += stride_dst; + wasm_v128_store64_lane(dst, v0, 1); + dst += stride_dst; + } +} + +void ff_hevc_sao_band_filter_16x16_8_simd128(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride_dst, + ptrdiff_t stride_src, + const int16_t *sao_offset_val, + int sao_left_class, int width, + int height) +{ + int8_t offset_table[32] = {0}; + v128_t offset_low, offset_high; + + for (int k = 0; k < 4; k++) + offset_table[(k + sao_left_class) & 31] = (int8_t)sao_offset_val[k + 1]; + + offset_low = wasm_v128_load(offset_table); + offset_high = wasm_v128_load(&offset_table[16]); + + for (int y = height; y > 0; y--) { + for (int x = 0; x < width; x += 16) { + v128_t src_v, src_high; + v128_t v0, v1; + + src_v = wasm_v128_load(&src[x]); + + v0 = wasm_u8x16_shr(src_v, 3); + v1 = wasm_i8x16_sub(v0, wasm_i8x16_const_splat(16)); + v0 = wasm_i8x16_swizzle(offset_low, v0); + v1 = wasm_i8x16_swizzle(offset_high, v1); + v0 = wasm_v128_or(v0, v1); + src_high = wasm_u16x8_extend_high_u8x16(src_v); + v1 = wasm_i16x8_extend_high_i8x16(v0); + src_v = wasm_u16x8_extend_low_u8x16(src_v); + v0 = wasm_i16x8_extend_low_i8x16(v0); + + v0 = wasm_i16x8_add_sat(src_v, v0); + v1 = wasm_i16x8_add_sat(src_high, v1); + v0 = wasm_u8x16_narrow_i16x8(v0, v1); + wasm_v128_store(&dst[x], v0); + } + + dst += stride_dst; + src += stride_src; + } +} + +void ff_hevc_sao_edge_filter_8x8_8_simd128(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride_dst, + const int16_t *sao_offset_val, + int eo, int width, int height) +{ + 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 + }; + int a_stride, b_stride; + ptrdiff_t stride_src = (2 * HEVC_MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); + const v128_t edge_idx = wasm_u8x16_make(1, 2, 0, 3, + 4, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0); + v128_t sao_offset = wasm_v128_load(sao_offset_val); + v128_t one = wasm_i8x16_const_splat(1); + v128_t two = wasm_i8x16_const_splat(2); + + a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src; + b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src; + for (int y = height; y > 0; y -= 2) { + v128_t v0, v1, v2; + v128_t diff0, diff1; + + v0 = wasm_v128_load64_zero(src); + v1 = wasm_v128_load64_zero(src + a_stride); + v2 = wasm_v128_load64_zero(src + b_stride); + src += stride_src; + v0 = wasm_v128_load64_lane(src, v0, 1); + v1 = wasm_v128_load64_lane(src + a_stride, v1, 1); + v2 = wasm_v128_load64_lane(src + b_stride, v2, 1); + src += stride_src; + + diff0 = wasm_u8x16_gt(v0, v1); + v1 = wasm_u8x16_lt(v0, v1); + diff0 = wasm_i8x16_sub(v1, diff0); + + diff1 = wasm_u8x16_gt(v0, v2); + v2 = wasm_u8x16_lt(v0, v2); + diff1 = wasm_i8x16_sub(v2, diff1); + + v1 = wasm_i8x16_add(diff0, two); + v1 = wasm_i8x16_add(v1, diff1); + + v2 = wasm_i8x16_swizzle(edge_idx, v1); // offset_val + v1 = wasm_i8x16_shl(v2, 1); // Access int16_t + v2 = wasm_i8x16_add(v1, one); // Access upper half of int16_t + diff0 = wasm_i8x16_shuffle(v1, v2, 0, 16, 1, 17, 2, 18, 3, 19, 4, + 20, 5, 21, 6, 22, 7, 23); + diff1 = wasm_i8x16_shuffle(v1, v2, 8, 24, 9, 25, 10, 26, 11, 27, + 12, 28, 13, 29, 14, 30, 15, 31); + v1 = wasm_u16x8_extend_high_u8x16(v0); + v0 = wasm_u16x8_extend_low_u8x16(v0); + diff0 = wasm_i8x16_swizzle(sao_offset, diff0); + diff1 = wasm_i8x16_swizzle(sao_offset, diff1); + + v0 = wasm_i16x8_add_sat(v0, diff0); + v1 = wasm_i16x8_add_sat(v1, diff1); + v0 = wasm_u8x16_narrow_i16x8(v0, v1); + + wasm_v128_store64_lane(dst, v0, 0); + dst += stride_dst; + wasm_v128_store64_lane(dst, v0, 1); + dst += stride_dst; + } +} + +void ff_hevc_sao_edge_filter_16x16_8_simd128(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride_dst, + const int16_t *sao_offset_val, + int eo, int width, int height) +{ + 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 + }; + int a_stride, b_stride; + ptrdiff_t stride_src = (2 * HEVC_MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); + const v128_t edge_idx = wasm_u8x16_make(1, 2, 0, 3, + 4, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0); + v128_t sao_offset = wasm_v128_load(sao_offset_val); + v128_t one = wasm_i8x16_const_splat(1); + v128_t two = wasm_i8x16_const_splat(2); + + a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src; + b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src; + for (int y = height; y > 0; y--) { + for (int x = 0; x < width; x += 16) { + v128_t v0, v1, v2; + v128_t diff0, diff1; + + v0 = wasm_v128_load(&src[x]); + v1 = wasm_v128_load(&src[x + a_stride]); + v2 = wasm_v128_load(&src[x + b_stride]); + + diff0 = wasm_u8x16_gt(v0, v1); + v1 = wasm_u8x16_lt(v0, v1); + diff0 = wasm_i8x16_sub(v1, diff0); + + diff1 = wasm_u8x16_gt(v0, v2); + v2 = wasm_u8x16_lt(v0, v2); + diff1 = wasm_i8x16_sub(v2, diff1); + + v1 = wasm_i8x16_add(diff0, two); + v1 = wasm_i8x16_add(v1, diff1); + + v2 = wasm_i8x16_swizzle(edge_idx, v1); // offset_val + v1 = wasm_i8x16_shl(v2, 1); // Access int16_t + v2 = wasm_i8x16_add(v1, one); // Access upper half of int16_t + diff0 = wasm_i8x16_shuffle(v1, v2, 0, 16, 1, 17, 2, 18, 3, 19, 4, + 20, 5, 21, 6, 22, 7, 23); + diff1 = wasm_i8x16_shuffle(v1, v2, 8, 24, 9, 25, 10, 26, 11, 27, + 12, 28, 13, 29, 14, 30, 15, 31); + v1 = wasm_u16x8_extend_high_u8x16(v0); + v0 = wasm_u16x8_extend_low_u8x16(v0); + diff0 = wasm_i8x16_swizzle(sao_offset, diff0); + diff1 = wasm_i8x16_swizzle(sao_offset, diff1); + + v0 = wasm_i16x8_add_sat(v0, diff0); + v1 = wasm_i16x8_add_sat(v1, diff1); + v0 = wasm_u8x16_narrow_i16x8(v0, v1); + wasm_v128_store(&dst[x], v0); + } + + src += stride_src; + dst += stride_dst; + } +} diff --git a/libavcodec/wasm/hevc/sao.h b/libavcodec/wasm/hevc/sao.h new file mode 100644 index 000000000..b83d1ab78 --- /dev/null +++ b/libavcodec/wasm/hevc/sao.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 Zhao Zhili + * + * 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_WASM_HEVC_SAO_H +#define AVCODEC_WASM_HEVC_SAO_H + +#include +#include + +void ff_hevc_sao_band_filter_8x8_8_simd128(uint8_t *_dst, const uint8_t *_src, + ptrdiff_t _stride_dst, + ptrdiff_t _stride_src, + const int16_t *sao_offset_val, + int sao_left_class, int width, + int height); + +void ff_hevc_sao_band_filter_16x16_8_simd128(uint8_t *_dst, const uint8_t *_src, + ptrdiff_t _stride_dst, + ptrdiff_t _stride_src, + const int16_t *sao_offset_val, + int sao_left_class, int width, + int height); + +void ff_hevc_sao_edge_filter_8x8_8_simd128(uint8_t *_dst, const uint8_t *_src, + ptrdiff_t stride_dst, + const int16_t *sao_offset_val, + int eo, int width, int height); + +void ff_hevc_sao_edge_filter_16x16_8_simd128(uint8_t *_dst, const uint8_t *_src, + ptrdiff_t stride_dst, + const int16_t *sao_offset_val, + int eo, int width, int height); + +#endif diff --git a/libavcodec/wavarc.c b/libavcodec/wavarc.c index 93b76c43e..3169a5f0d 100644 --- a/libavcodec/wavarc.c +++ b/libavcodec/wavarc.c @@ -881,11 +881,6 @@ const FFCodec ff_wavarc_decoder = { FF_CODEC_DECODE_CB(wavarc_decode), .close = wavarc_close, .p.capabilities = AV_CODEC_CAP_DR1 | -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif AV_CODEC_CAP_DELAY, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P), }; diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c index bf9aa0cdc..341315373 100644 --- a/libavcodec/wavpack.c +++ b/libavcodec/wavpack.c @@ -28,7 +28,7 @@ #include "bytestream.h" #include "codec_internal.h" #include "get_bits.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadprogress.h" #include "unary.h" @@ -110,7 +110,7 @@ typedef struct WavpackContext { DSDContext *dsdctx; ///< RefStruct reference ThreadProgress *curr_progress, *prev_progress; ///< RefStruct references - FFRefStructPool *progress_pool; ///< RefStruct reference + AVRefStructPool *progress_pool; ///< RefStruct reference int dsd_channels; } WavpackContext; @@ -992,9 +992,9 @@ static int wv_dsd_reset(WavpackContext *s, int channels) int i; s->dsd_channels = 0; - ff_refstruct_unref(&s->dsdctx); - ff_refstruct_unref(&s->curr_progress); - ff_refstruct_unref(&s->prev_progress); + av_refstruct_unref(&s->dsdctx); + av_refstruct_unref(&s->curr_progress); + av_refstruct_unref(&s->prev_progress); if (!channels) return 0; @@ -1003,7 +1003,7 @@ static int wv_dsd_reset(WavpackContext *s, int channels) channels > SIZE_MAX / sizeof(*s->dsdctx)) return AVERROR(EINVAL); - s->dsdctx = ff_refstruct_allocz(channels * sizeof(*s->dsdctx)); + s->dsdctx = av_refstruct_allocz(channels * sizeof(*s->dsdctx)); if (!s->dsdctx) return AVERROR(ENOMEM); s->dsd_channels = channels; @@ -1022,26 +1022,26 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) WavpackContext *fsrc = src->priv_data; WavpackContext *fdst = dst->priv_data; - ff_refstruct_replace(&fdst->curr_progress, fsrc->curr_progress); - ff_refstruct_replace(&fdst->dsdctx, fsrc->dsdctx); + av_refstruct_replace(&fdst->curr_progress, fsrc->curr_progress); + av_refstruct_replace(&fdst->dsdctx, fsrc->dsdctx); fdst->dsd_channels = fsrc->dsd_channels; return 0; } -static av_cold int progress_pool_init_cb(FFRefStructOpaque opaque, void *obj) +static av_cold int progress_pool_init_cb(AVRefStructOpaque opaque, void *obj) { ThreadProgress *progress = obj; return ff_thread_progress_init(progress, 1); } -static void progress_pool_reset_cb(FFRefStructOpaque opaque, void *obj) +static void progress_pool_reset_cb(AVRefStructOpaque opaque, void *obj) { ThreadProgress *progress = obj; ff_thread_progress_reset(progress); } -static av_cold void progress_pool_free_entry_cb(FFRefStructOpaque opaque, void *obj) +static av_cold void progress_pool_free_entry_cb(AVRefStructOpaque opaque, void *obj) { ThreadProgress *progress = obj; ff_thread_progress_destroy(progress); @@ -1058,8 +1058,8 @@ static av_cold int wavpack_decode_init(AVCodecContext *avctx) #if HAVE_THREADS if (ff_thread_sync_ref(avctx, offsetof(WavpackContext, progress_pool)) == FF_THREAD_IS_FIRST_THREAD) { - s->progress_pool = ff_refstruct_pool_alloc_ext(sizeof(*s->curr_progress), - FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, NULL, + s->progress_pool = av_refstruct_pool_alloc_ext(sizeof(*s->curr_progress), + AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, NULL, progress_pool_init_cb, progress_pool_reset_cb, progress_pool_free_entry_cb, NULL); @@ -1080,7 +1080,7 @@ static av_cold int wavpack_decode_end(AVCodecContext *avctx) av_freep(&s->fdec); s->fdec_num = 0; - ff_refstruct_pool_uninit(&s->progress_pool); + av_refstruct_pool_uninit(&s->progress_pool); wv_dsd_reset(s, 0); return 0; @@ -1552,8 +1552,8 @@ static int wavpack_decode_block(AVCodecContext *avctx, AVFrame *frame, int block av_assert1(!!wc->progress_pool == !!(avctx->active_thread_type & FF_THREAD_FRAME)); if (wc->progress_pool) { if (wc->dsdctx) { - ff_refstruct_unref(&wc->prev_progress); - wc->prev_progress = ff_refstruct_pool_get(wc->progress_pool); + av_refstruct_unref(&wc->prev_progress); + wc->prev_progress = av_refstruct_pool_get(wc->progress_pool); if (!wc->prev_progress) return AVERROR(ENOMEM); FFSWAP(ThreadProgress*, wc->prev_progress, wc->curr_progress); @@ -1611,7 +1611,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, AVFrame *frame, int block return 0; } -static void wavpack_decode_flush(AVCodecContext *avctx) +static av_cold void wavpack_decode_flush(AVCodecContext *avctx) { WavpackContext *s = avctx->priv_data; diff --git a/libavcodec/wavpackenc.c b/libavcodec/wavpackenc.c index e99ab951d..a89f3d167 100644 --- a/libavcodec/wavpackenc.c +++ b/libavcodec/wavpackenc.c @@ -2980,9 +2980,6 @@ const FFCodec ff_wavpack_encoder = { .init = wavpack_encode_init, FF_CODEC_ENCODE_CB(wavpack_encode_frame), .close = wavpack_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_FLTP), }; diff --git a/libavcodec/wbmpdec.c b/libavcodec/wbmpdec.c index 50c729047..5a61510a8 100644 --- a/libavcodec/wbmpdec.c +++ b/libavcodec/wbmpdec.c @@ -72,7 +72,8 @@ static int wbmp_decode_frame(AVCodecContext *avctx, AVFrame *p, if (p->linesize[0] == (width + 7) / 8) bytestream2_get_buffer(&gb, p->data[0], height * ((width + 7) / 8)); else - readbits(p->data[0], width, height, p->linesize[0], gb.buffer, gb.buffer_end - gb.buffer); + readbits(p->data[0], width, height, p->linesize[0], + gb.buffer, bytestream2_get_bytes_left(&gb)); *got_frame = 1; diff --git a/libavcodec/wbmpenc.c b/libavcodec/wbmpenc.c index abb66b4ca..3b624da08 100644 --- a/libavcodec/wbmpenc.c +++ b/libavcodec/wbmpenc.c @@ -83,8 +83,5 @@ const FFCodec ff_wbmp_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(wbmp_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_MONOBLACK, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_MONOBLACK), }; diff --git a/libavcodec/webp.c b/libavcodec/webp.c index b624458d6..62967a394 100644 --- a/libavcodec/webp.c +++ b/libavcodec/webp.c @@ -48,7 +48,7 @@ #include "bytestream.h" #include "codec_internal.h" #include "decode.h" -#include "exif.h" +#include "exif_internal.h" #include "get_bits.h" #include "thread.h" #include "tiff_common.h" @@ -253,64 +253,47 @@ static int huff_reader_get_symbol(HuffReader *r, GetBitContext *gb) } static int huff_reader_build_canonical(HuffReader *r, const uint8_t *code_lengths, - int alphabet_size) + uint16_t len_counts[MAX_HUFFMAN_CODE_LENGTH + 1], + uint8_t lens[], uint16_t syms[], + int alphabet_size, void *logctx) { - int len = 0, sym, code = 0, ret; - int max_code_length = 0; - uint16_t *codes; + unsigned nb_codes = 0; + int ret; - /* special-case 1 symbol since the vlc reader cannot handle it */ - for (sym = 0; sym < alphabet_size; sym++) { - if (code_lengths[sym] > 0) { - len++; - code = sym; - if (len > 1) - break; + // Count the number of symbols of each length and transform len_counts + // into an array of offsets. + for (int len = 1; len <= MAX_HUFFMAN_CODE_LENGTH; ++len) { + unsigned cnt = len_counts[len]; + len_counts[len] = nb_codes; + nb_codes += cnt; + } + + for (int sym = 0; sym < alphabet_size; ++sym) { + if (code_lengths[sym]) { + unsigned idx = len_counts[code_lengths[sym]]++; + syms[idx] = sym; + lens[idx] = code_lengths[sym]; } } - if (len == 1) { + + if (nb_codes == 0) { + // No symbols + return AVERROR_INVALIDDATA; + } + if (nb_codes == 1) { + // Special-case 1 symbol since the VLC reader cannot handle it r->nb_symbols = 1; - r->simple_symbols[0] = code; r->simple = 1; + r->simple_symbols[0] = syms[0]; return 0; } - for (sym = 0; sym < alphabet_size; sym++) - max_code_length = FFMAX(max_code_length, code_lengths[sym]); - - if (max_code_length == 0 || max_code_length > MAX_HUFFMAN_CODE_LENGTH) - return AVERROR(EINVAL); - - codes = av_malloc_array(alphabet_size, sizeof(*codes)); - if (!codes) - return AVERROR(ENOMEM); - - code = 0; - r->nb_symbols = 0; - for (len = 1; len <= max_code_length; len++) { - for (sym = 0; sym < alphabet_size; sym++) { - if (code_lengths[sym] != len) - continue; - codes[sym] = code++; - r->nb_symbols++; - } - code <<= 1; - } - if (!r->nb_symbols) { - av_free(codes); - return AVERROR_INVALIDDATA; - } - - ret = vlc_init(&r->vlc, 8, alphabet_size, - code_lengths, sizeof(*code_lengths), sizeof(*code_lengths), - codes, sizeof(*codes), sizeof(*codes), VLC_INIT_OUTPUT_LE); - if (ret < 0) { - av_free(codes); + ret = ff_vlc_init_from_lengths(&r->vlc, 8, nb_codes, lens, 1, + syms, 2, 2, 0, VLC_INIT_OUTPUT_LE, logctx); + if (ret < 0) return ret; - } r->simple = 0; - av_free(codes); return 0; } @@ -335,23 +318,18 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc, HuffReader code_len_hc = { { 0 }, 0, 0, { 0 } }; uint8_t *code_lengths; uint8_t code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 }; - int i, symbol, max_symbol, prev_code_len, ret; + uint8_t reordered_code_length_code_lengths[NUM_CODE_LENGTH_CODES]; + uint16_t reordered_code_length_syms[NUM_CODE_LENGTH_CODES]; + uint16_t len_counts[MAX_HUFFMAN_CODE_LENGTH + 1] = { 0 }; + int symbol, max_symbol, prev_code_len, ret; int num_codes = 4 + get_bits(&s->gb, 4); av_assert1(num_codes <= NUM_CODE_LENGTH_CODES); - for (i = 0; i < num_codes; i++) - code_length_code_lengths[code_length_code_order[i]] = get_bits(&s->gb, 3); - - ret = huff_reader_build_canonical(&code_len_hc, code_length_code_lengths, - NUM_CODE_LENGTH_CODES); - if (ret < 0) - return ret; - - code_lengths = av_mallocz(alphabet_size); - if (!code_lengths) { - ret = AVERROR(ENOMEM); - goto finish; + for (int i = 0; i < num_codes; i++) { + unsigned len = get_bits(&s->gb, 3); + code_length_code_lengths[code_length_code_order[i]] = len; + len_counts[len]++; } if (get_bits1(&s->gb)) { @@ -360,35 +338,53 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc, if (max_symbol > alphabet_size) { av_log(s->avctx, AV_LOG_ERROR, "max symbol %d > alphabet size %d\n", max_symbol, alphabet_size); - ret = AVERROR_INVALIDDATA; - goto finish; + return AVERROR_INVALIDDATA; } } else { max_symbol = alphabet_size; } + ret = huff_reader_build_canonical(&code_len_hc, code_length_code_lengths, len_counts, + reordered_code_length_code_lengths, + reordered_code_length_syms, + NUM_CODE_LENGTH_CODES, s->avctx); + if (ret < 0) + return ret; + + code_lengths = av_malloc_array(alphabet_size, 2 * sizeof(uint8_t) + sizeof(uint16_t)); + if (!code_lengths) { + ret = AVERROR(ENOMEM); + goto finish; + } + prev_code_len = 8; symbol = 0; + memset(len_counts, 0, sizeof(len_counts)); while (symbol < alphabet_size) { int code_len; if (!max_symbol--) break; code_len = huff_reader_get_symbol(&code_len_hc, &s->gb); - if (code_len < 16) { + if (code_len < 16U) { /* Code length code [0..15] indicates literal code lengths. */ code_lengths[symbol++] = code_len; + len_counts[code_len]++; if (code_len) prev_code_len = code_len; } else { int repeat = 0, length = 0; switch (code_len) { + default: + ret = AVERROR_INVALIDDATA; + goto finish; case 16: /* Code 16 repeats the previous non-zero value [3..6] times, * i.e., 3 + ReadBits(2) times. If code 16 is used before a * non-zero value has been emitted, a value of 8 is repeated. */ repeat = 3 + get_bits(&s->gb, 2); length = prev_code_len; + len_counts[length] += repeat; break; case 17: /* Code 17 emits a streak of zeros [3..10], i.e., @@ -413,7 +409,10 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc, } } - ret = huff_reader_build_canonical(hc, code_lengths, alphabet_size); + ret = huff_reader_build_canonical(hc, code_lengths, len_counts, + code_lengths + symbol, + (uint16_t*)(code_lengths + 2 * symbol), + symbol, s->avctx); finish: ff_vlc_free(&code_len_hc.vlc); @@ -1191,6 +1190,7 @@ static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p, *got_frame = 1; p->pict_type = AV_PICTURE_TYPE_I; p->flags |= AV_FRAME_FLAG_KEY; + p->flags |= AV_FRAME_FLAG_LOSSLESS; ret = data_size; free_and_return: @@ -1406,7 +1406,11 @@ static int webp_decode_frame(AVCodecContext *avctx, AVFrame *p, chunk_size, 0); if (ret < 0) return ret; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif } bytestream2_skip(&gb, chunk_size); break; @@ -1455,38 +1459,31 @@ static int webp_decode_frame(AVCodecContext *avctx, AVFrame *p, break; } case MKTAG('E', 'X', 'I', 'F'): { - int le, ifd_offset, exif_offset = bytestream2_tell(&gb); - AVDictionary *exif_metadata = NULL; - GetByteContext exif_gb; + AVBufferRef *exif_buf = NULL; if (s->has_exif) { av_log(avctx, AV_LOG_VERBOSE, "Ignoring extra EXIF chunk\n"); goto exif_end; } + if (!(vp8x_flags & VP8X_FLAG_EXIF_METADATA)) av_log(avctx, AV_LOG_WARNING, "EXIF chunk present, but Exif bit not set in the " "VP8X header\n"); + exif_buf = av_buffer_alloc(chunk_size); + if (!exif_buf) { + av_log(avctx, AV_LOG_WARNING, "unable to allocate EXIF buffer\n"); + goto exif_end; + } s->has_exif = 1; - bytestream2_init(&exif_gb, avpkt->data + exif_offset, - avpkt->size - exif_offset); - if (ff_tdecode_header(&exif_gb, &le, &ifd_offset) < 0) { - av_log(avctx, AV_LOG_ERROR, "invalid TIFF header " - "in Exif data\n"); - goto exif_end; - } + memcpy(exif_buf->data, gb.buffer, chunk_size); - bytestream2_seek(&exif_gb, ifd_offset, SEEK_SET); - if (ff_exif_decode_ifd(avctx, &exif_gb, le, 0, &exif_metadata) < 0) { - av_log(avctx, AV_LOG_ERROR, "error decoding Exif data\n"); - goto exif_end; - } - - av_dict_copy(&p->metadata, exif_metadata, 0); + ret = ff_decode_exif_attach_buffer(avctx, p, &exif_buf, AV_EXIF_TIFF_HEADER); + if (ret < 0) + av_log(avctx, AV_LOG_WARNING, "unable to attach EXIF buffer\n"); exif_end: - av_dict_free(&exif_metadata); bytestream2_skip(&gb, chunk_size); break; } diff --git a/libavcodec/webp_parser.c b/libavcodec/webp_parser.c index bd5f94dac..86c9bad8d 100644 --- a/libavcodec/webp_parser.c +++ b/libavcodec/webp_parser.c @@ -27,6 +27,7 @@ #include "libavutil/common.h" #include "parser.h" +#include "parser_internal.h" typedef struct WebPParseContext { ParseContext pc; @@ -104,9 +105,9 @@ flush: return next; } -const AVCodecParser ff_webp_parser = { - .codec_ids = { AV_CODEC_ID_WEBP }, +const FFCodecParser ff_webp_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_WEBP), .priv_data_size = sizeof(WebPParseContext), - .parser_parse = webp_parse, - .parser_close = ff_parse_close, + .parse = webp_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/webvttdec.c b/libavcodec/webvttdec.c index 35bdbe805..90675bc66 100644 --- a/libavcodec/webvttdec.c +++ b/libavcodec/webvttdec.c @@ -21,7 +21,7 @@ /** * @file * WebVTT subtitle decoder - * @see http://dev.w3.org/html5/webvtt/ + * @see https://www.w3.org/TR/webvtt1/ * @todo need to support extended markups and cue settings */ @@ -34,20 +34,41 @@ static const struct { const char *from; const char *to; } webvtt_tag_replace[] = { - {"", "{\\i1}"}, {"", "{\\i0}"}, - {"", "{\\b1}"}, {"", "{\\b0}"}, - {"", "{\\u1}"}, {"", "{\\u0}"}, {"{", "\\{{}"}, {"\\", "\\\xe2\x81\xa0"}, // escape to avoid ASS markup conflicts {">", ">"}, {"<", "<"}, {"‎", "\xe2\x80\x8e"}, {"‏", "\xe2\x80\x8f"}, {"&", "&"}, {" ", "\\h"}, }; +static const struct { + const char from[6]; + const char to[6]; +} webvtt_valid_tags[] = { + {"i", "{\\i1}"}, {"/i", "{\\i0}"}, + {"b", "{\\b1}"}, {"/b", "{\\b0}"}, + {"u", "{\\u1}"}, {"/u", "{\\u0}"}, +}; static int webvtt_event_to_ass(AVBPrint *buf, const char *p) { - int i, again = 0, skip = 0; + int i, again = 0; while (*p) { + if (*p == '<') { + const char *tag_end = strchr(p, '>'); + ptrdiff_t len; + if (!tag_end) + break; + len = tag_end - p + 1; + for (i = 0; i < FF_ARRAY_ELEMS(webvtt_valid_tags); i++) { + const char *from = webvtt_valid_tags[i].from; + if(!strncmp(p + 1, from, strlen(from))) { + av_bprintf(buf, "%s", webvtt_valid_tags[i].to); + break; + } + } + p += len; + again = 1; + } for (i = 0; i < FF_ARRAY_ELEMS(webvtt_tag_replace); i++) { const char *from = webvtt_tag_replace[i].from; @@ -59,21 +80,14 @@ static int webvtt_event_to_ass(AVBPrint *buf, const char *p) break; } } - if (!*p) - break; if (again) { again = 0; - skip = 0; continue; } - if (*p == '<') - skip = 1; - else if (*p == '>') - skip = 0; - else if (p[0] == '\n' && p[1]) + if (p[0] == '\n' && p[1]) av_bprintf(buf, "\\N"); - else if (!skip && *p != '\r') + else if (*p != '\r') av_bprint_chars(buf, *p, 1); p++; } diff --git a/libavcodec/webvttenc.c b/libavcodec/webvttenc.c index 3b66b4f2d..d5d3ddd17 100644 --- a/libavcodec/webvttenc.c +++ b/libavcodec/webvttenc.c @@ -187,7 +187,7 @@ static int webvtt_encode_frame(AVCodecContext *avctx, return s->buffer.len; } -static int webvtt_encode_close(AVCodecContext *avctx) +static av_cold int webvtt_encode_close(AVCodecContext *avctx) { WebVTTContext *s = avctx->priv_data; ff_ass_split_free(s->ass_ctx); diff --git a/libavcodec/wma.c b/libavcodec/wma.c index da9c914b5..0a34c1b00 100644 --- a/libavcodec/wma.c +++ b/libavcodec/wma.c @@ -86,8 +86,8 @@ av_cold int ff_wma_init(AVCodecContext *avctx, int flags2) int sample_rate1; int coef_vlc_table; - if (avctx->sample_rate <= 0 || avctx->sample_rate > 50000 || - channels <= 0 || channels > 2 || + if (avctx->sample_rate > 50000 || + channels > 2 || avctx->bit_rate <= 0) return -1; @@ -364,7 +364,7 @@ int ff_wma_total_gain_to_bits(int total_gain) return 9; } -int ff_wma_end(AVCodecContext *avctx) +av_cold int ff_wma_end(AVCodecContext *avctx) { WMACodecContext *s = avctx->priv_data; int i; diff --git a/libavcodec/wmadec.c b/libavcodec/wmadec.c index 3427e482d..c5f7eed53 100644 --- a/libavcodec/wmadec.c +++ b/libavcodec/wmadec.c @@ -36,6 +36,7 @@ #include "config_components.h" #include "libavutil/attributes.h" +#include "libavutil/avassert.h" #include "libavutil/ffmath.h" #include "avcodec.h" @@ -140,7 +141,7 @@ static av_cold int wma_decode_init(AVCodecContext *avctx) avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; - avctx->internal->skip_samples = s->frame_len * 2; + avctx->delay = s->frame_len * 2; return 0; } @@ -368,7 +369,7 @@ static int decode_exp_vlc(WMACodecContext *s, int ch) if ((unsigned) last_exp + 60 >= FF_ARRAY_ELEMS(pow_tab)) { av_log(s->avctx, AV_LOG_ERROR, "Exponent out of range: %d\n", last_exp); - return -1; + return AVERROR_INVALIDDATA; } v = ptab[last_exp]; iv = iptab[last_exp]; @@ -439,19 +440,23 @@ static void wma_window(WMACodecContext *s, float *out) } /** - * @return 0 if OK. 1 if last block of frame. return -1 if - * unrecoverable error. + * @return + * 0 if OK. + * 1 if last block of frame. + * AVERROR if unrecoverable error. */ static int wma_decode_block(WMACodecContext *s) { int channels = s->avctx->ch_layout.nb_channels; - int n, v, a, ch, bsize; + int n, v, a, bsize; int coef_nb_bits, total_gain; int nb_coefs[MAX_CHANNELS]; float mdct_norm; AVTXContext *mdct; av_tx_fn mdct_fn; + av_assert2(channels <= MAX_CHANNELS); + #ifdef TRACE ff_tlog(s->avctx, "***decode_block: %d:%d\n", s->frame_count - 1, s->block_num); @@ -468,7 +473,7 @@ static int wma_decode_block(WMACodecContext *s) av_log(s->avctx, AV_LOG_ERROR, "prev_block_len_bits %d out of range\n", s->frame_len_bits - v); - return -1; + return AVERROR_INVALIDDATA; } s->prev_block_len_bits = s->frame_len_bits - v; v = get_bits(&s->gb, n); @@ -476,7 +481,7 @@ static int wma_decode_block(WMACodecContext *s) av_log(s->avctx, AV_LOG_ERROR, "block_len_bits %d out of range\n", s->frame_len_bits - v); - return -1; + return AVERROR_INVALIDDATA; } s->block_len_bits = s->frame_len_bits - v; } else { @@ -489,7 +494,7 @@ static int wma_decode_block(WMACodecContext *s) av_log(s->avctx, AV_LOG_ERROR, "next_block_len_bits %d out of range\n", s->frame_len_bits - v); - return -1; + return AVERROR_INVALIDDATA; } s->next_block_len_bits = s->frame_len_bits - v; } else { @@ -501,20 +506,20 @@ static int wma_decode_block(WMACodecContext *s) if (s->frame_len_bits - s->block_len_bits >= s->nb_block_sizes){ av_log(s->avctx, AV_LOG_ERROR, "block_len_bits not initialized to a valid value\n"); - return -1; + return AVERROR_INVALIDDATA; } /* now check if the block length is coherent with the frame length */ s->block_len = 1 << s->block_len_bits; if ((s->block_pos + s->block_len) > s->frame_len) { av_log(s->avctx, AV_LOG_ERROR, "frame_len overflow\n"); - return -1; + return AVERROR_INVALIDDATA; } if (channels == 2) s->ms_stereo = get_bits1(&s->gb); v = 0; - for (ch = 0; ch < channels; ch++) { + for (int ch = 0; ch < channels; ch++) { a = get_bits1(&s->gb); s->channel_coded[ch] = a; v |= a; @@ -545,17 +550,17 @@ static int wma_decode_block(WMACodecContext *s) /* compute number of coefficients */ n = s->coefs_end[bsize] - s->coefs_start; - for (ch = 0; ch < channels; ch++) + for (int ch = 0; ch < channels; ch++) nb_coefs[ch] = n; /* complex coding */ if (s->use_noise_coding) { - for (ch = 0; ch < channels; ch++) { + for (int ch = 0; ch < channels; ch++) { if (s->channel_coded[ch]) { - int i, n, a; + int n; n = s->exponent_high_sizes[bsize]; - for (i = 0; i < n; i++) { - a = get_bits1(&s->gb); + for (int i = 0; i < n; i++) { + const unsigned a = get_bits1(&s->gb); s->high_band_coded[ch][i] = a; /* if noise coding, the coefficients are not transmitted */ if (a) @@ -563,13 +568,13 @@ static int wma_decode_block(WMACodecContext *s) } } } - for (ch = 0; ch < channels; ch++) { + for (int ch = 0; ch < channels; ch++) { if (s->channel_coded[ch]) { - int i, n, val; + int n, val; n = s->exponent_high_sizes[bsize]; val = (int) 0x80000000; - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { if (s->high_band_coded[ch][i]) { if (val == (int) 0x80000000) { val = get_bits(&s->gb, 7) - 19; @@ -586,11 +591,11 @@ static int wma_decode_block(WMACodecContext *s) /* exponents can be reused in short blocks. */ if ((s->block_len_bits == s->frame_len_bits) || get_bits1(&s->gb)) { - for (ch = 0; ch < channels; ch++) { + for (int ch = 0; ch < channels; ch++) { if (s->channel_coded[ch]) { if (s->use_exp_vlc) { if (decode_exp_vlc(s, ch) < 0) - return -1; + return AVERROR_INVALIDDATA; } else { decode_exp_lsp(s, ch); } @@ -600,13 +605,13 @@ static int wma_decode_block(WMACodecContext *s) } } - for (ch = 0; ch < channels; ch++) { + for (int ch = 0; ch < channels; ch++) { if (s->channel_coded[ch] && !s->exponents_initialized[ch]) return AVERROR_INVALIDDATA; } /* parse spectral coefficients : just RLE encoding */ - for (ch = 0; ch < channels; ch++) { + for (int ch = 0; ch < channels; ch++) { if (s->channel_coded[ch]) { int tindex; WMACoef *ptr = &s->coefs1[ch][0]; @@ -636,11 +641,11 @@ static int wma_decode_block(WMACodecContext *s) } /* finally compute the MDCT coefficients */ - for (ch = 0; ch < channels; ch++) { + for (int ch = 0; ch < channels; ch++) { if (s->channel_coded[ch]) { WMACoef *coefs1; float *coefs, *exponents, mult, mult1, noise; - int i, j, n, n1, last_high_band, esize; + int n, n1, last_high_band, esize; float exp_power[HIGH_BAND_MAX_SIZE]; coefs1 = s->coefs1[ch]; @@ -652,7 +657,7 @@ static int wma_decode_block(WMACodecContext *s) if (s->use_noise_coding) { mult1 = mult; /* very low freqs : noise */ - for (i = 0; i < s->coefs_start; i++) { + for (int i = 0; i < s->coefs_start; i++) { *coefs++ = s->noise_table[s->noise_index] * exponents[i << bsize >> esize] * mult1; s->noise_index = (s->noise_index + 1) & @@ -665,13 +670,13 @@ static int wma_decode_block(WMACodecContext *s) exponents = s->exponents[ch] + (s->high_band_start[bsize] << bsize >> esize); last_high_band = 0; /* avoid warning */ - for (j = 0; j < n1; j++) { + for (int j = 0; j < n1; j++) { n = s->exponent_high_bands[s->frame_len_bits - s->block_len_bits][j]; if (s->high_band_coded[ch][j]) { float e2, v; e2 = 0; - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { v = exponents[i << bsize >> esize]; e2 += v * v; } @@ -684,7 +689,7 @@ static int wma_decode_block(WMACodecContext *s) /* main freqs and high freqs */ exponents = s->exponents[ch] + (s->coefs_start << bsize >> esize); - for (j = -1; j < n1; j++) { + for (int j = -1; j < n1; j++) { if (j < 0) n = s->high_band_start[bsize] - s->coefs_start; else @@ -697,7 +702,7 @@ static int wma_decode_block(WMACodecContext *s) mult1 = mult1 * ff_exp10(s->high_band_values[ch][j] * 0.05); mult1 = mult1 / (s->max_exponent[ch] * s->noise_mult); mult1 *= mdct_norm; - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { noise = s->noise_table[s->noise_index]; s->noise_index = (s->noise_index + 1) & (NOISE_TAB_SIZE - 1); *coefs++ = noise * exponents[i << bsize >> esize] * mult1; @@ -705,7 +710,7 @@ static int wma_decode_block(WMACodecContext *s) exponents += n << bsize >> esize; } else { /* coded values + small noise */ - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { noise = s->noise_table[s->noise_index]; s->noise_index = (s->noise_index + 1) & (NOISE_TAB_SIZE - 1); *coefs++ = ((*coefs1++) + noise) * @@ -718,26 +723,26 @@ static int wma_decode_block(WMACodecContext *s) /* very high freqs : noise */ n = s->block_len - s->coefs_end[bsize]; mult1 = mult * exponents[(-(1 << bsize)) >> esize]; - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { *coefs++ = s->noise_table[s->noise_index] * mult1; s->noise_index = (s->noise_index + 1) & (NOISE_TAB_SIZE - 1); } } else { /* XXX: optimize more */ - for (i = 0; i < s->coefs_start; i++) + for (int i = 0; i < s->coefs_start; i++) *coefs++ = 0.0; n = nb_coefs[ch]; - for (i = 0; i < n; i++) + for (int i = 0; i < n; i++) *coefs++ = coefs1[i] * exponents[i << bsize >> esize] * mult; n = s->block_len - s->coefs_end[bsize]; - for (i = 0; i < n; i++) + for (int i = 0; i < n; i++) *coefs++ = 0.0; } } } #ifdef TRACE - for (ch = 0; ch < channels; ch++) { + for (int ch = 0; ch < channels; ch++) { if (s->channel_coded[ch]) { dump_floats(s, "exponents", 3, s->exponents[ch], s->block_len); dump_floats(s, "coefs", 1, s->coefs[ch], s->block_len); @@ -762,7 +767,7 @@ next: mdct = s->mdct_ctx[bsize]; mdct_fn = s->mdct_fn[bsize]; - for (ch = 0; ch < channels; ch++) { + for (int ch = 0; ch < channels; ch++) { int n4, index; n4 = s->block_len / 2; @@ -789,8 +794,6 @@ next: static int wma_decode_frame(WMACodecContext *s, float **samples, int samples_offset) { - int ret, ch; - #ifdef TRACE ff_tlog(s->avctx, "***decode_frame: %d size=%d\n", s->frame_count++, s->frame_len); @@ -800,14 +803,14 @@ static int wma_decode_frame(WMACodecContext *s, float **samples, s->block_num = 0; s->block_pos = 0; for (;;) { - ret = wma_decode_block(s); + int ret = wma_decode_block(s); if (ret < 0) - return -1; + return ret; if (ret) break; } - for (ch = 0; ch < s->avctx->ch_layout.nb_channels; ch++) { + for (int ch = 0; ch < s->avctx->ch_layout.nb_channels; ch++) { /* copy current block to output */ memcpy(samples[ch] + samples_offset, s->frame_out[ch], s->frame_len * sizeof(*s->frame_out[ch])); @@ -830,7 +833,7 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; WMACodecContext *s = avctx->priv_data; - int nb_frames, bit_offset, i, pos, len, ret; + int nb_frames, bit_offset, pos, len, ret; uint8_t *q; float **samples; int samples_offset; @@ -846,7 +849,7 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, return ret; frame->pts = AV_NOPTS_VALUE; - for (i = 0; i < s->avctx->ch_layout.nb_channels; i++) + for (int i = 0; i < s->avctx->ch_layout.nb_channels; i++) memcpy(frame->extended_data[i], &s->frame_out[i][0], frame->nb_samples * sizeof(s->frame_out[i][0])); @@ -879,8 +882,10 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, return AVERROR_INVALIDDATA; if ((s->last_superframe_len + buf_size - 1) > - MAX_CODED_SUPERFRAME_SIZE) + MAX_CODED_SUPERFRAME_SIZE) { + ret = AVERROR_INVALIDDATA; goto fail; + } q = s->last_superframe + s->last_superframe_len; len = buf_size - 1; @@ -911,14 +916,17 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, av_log(avctx, AV_LOG_ERROR, "Invalid last frame bit offset %d > buf size %d (%d)\n", bit_offset, get_bits_left(&s->gb), buf_size); + ret = AVERROR_INVALIDDATA; goto fail; } if (s->last_superframe_len > 0) { /* add bit_offset bits to last frame */ if ((s->last_superframe_len + ((bit_offset + 7) >> 3)) > - MAX_CODED_SUPERFRAME_SIZE) + MAX_CODED_SUPERFRAME_SIZE) { + ret = AVERROR_INVALIDDATA; goto fail; + } q = s->last_superframe + s->last_superframe_len; len = bit_offset; while (len > 7) { @@ -937,7 +945,7 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, skip_bits(&s->gb, s->last_bitoffset); /* this frame is stored in the last superframe and in the * current one */ - if (wma_decode_frame(s, samples, samples_offset) < 0) + if ((ret = wma_decode_frame(s, samples, samples_offset)) < 0) goto fail; samples_offset += s->frame_len; nb_frames--; @@ -953,8 +961,8 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, skip_bits(&s->gb, len); s->reset_block_lengths = 1; - for (i = 0; i < nb_frames; i++) { - if (wma_decode_frame(s, samples, samples_offset) < 0) + for (int i = 0; i < nb_frames; i++) { + if ((ret = wma_decode_frame(s, samples, samples_offset)) < 0) goto fail; samples_offset += s->frame_len; } @@ -967,13 +975,14 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, len = buf_size - pos; if (len > MAX_CODED_SUPERFRAME_SIZE || len < 0) { av_log(s->avctx, AV_LOG_ERROR, "len %d invalid\n", len); + ret = AVERROR_INVALIDDATA; goto fail; } s->last_superframe_len = len; memcpy(s->last_superframe, buf + pos, len); } else { /* single frame decode */ - if (wma_decode_frame(s, samples, samples_offset) < 0) + if ((ret = wma_decode_frame(s, samples, samples_offset)) < 0) goto fail; samples_offset += s->frame_len; } @@ -989,7 +998,7 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, fail: /* when error, we reset the bit reservoir */ s->last_superframe_len = 0; - return -1; + return ret; } static av_cold void flush(AVCodecContext *avctx) @@ -1015,8 +1024,6 @@ const FFCodec ff_wmav1_decoder = { FF_CODEC_DECODE_CB(wma_decode_superframe), .flush = flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif @@ -1032,8 +1039,6 @@ const FFCodec ff_wmav2_decoder = { FF_CODEC_DECODE_CB(wma_decode_superframe), .flush = flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/wmaenc.c b/libavcodec/wmaenc.c index a5ed25ed1..0d0a19eb7 100644 --- a/libavcodec/wmaenc.c +++ b/libavcodec/wmaenc.c @@ -79,7 +79,7 @@ static av_cold int encode_init(AVCodecContext *avctx) AV_WL32(extradata, flags1); AV_WL16(extradata + 4, flags2); } else { - av_assert0(0); + av_unreachable("This function is only used with WMAV1/2 encoders"); } avctx->extradata = extradata; s->use_exp_vlc = flags2 & 0x0001; @@ -206,7 +206,7 @@ static int encode_block(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], // FIXME remove duplication relative to decoder if (s->use_variable_block_len) { - av_assert0(0); // FIXME not implemented + av_unreachable("use_variable_block_len unimplemented, set to 0 during init"); } else { /* fixed block len */ s->next_block_len_bits = s->frame_len_bits; @@ -306,7 +306,8 @@ static int encode_block(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], if (s->use_exp_vlc) { encode_exp_vlc(s, ch, fixed_exp); } else { - av_assert0(0); // FIXME not implemented + av_unreachable("use_exp_vlc always set to 1 during init"); + // FIXME not implemented // encode_exp_lsp(s, ch); } } @@ -365,7 +366,7 @@ static int encode_frame(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], init_put_bits(&s->pb, buf, buf_size); if (s->use_bit_reservoir) - av_assert0(0); // FIXME not implemented + av_unreachable("use_bit_reseroir unimplemented, set to 0 during init"); else if (encode_block(s, src_coefs, total_gain) < 0) return INT_MAX; @@ -415,7 +416,6 @@ static int encode_superframe(AVCodecContext *avctx, AVPacket *avpkt, error = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain++); if (error > 0) { av_log(avctx, AV_LOG_ERROR, "Invalid input data or requested bitrate too low, cannot encode\n"); - avpkt->size = 0; return AVERROR(EINVAL); } av_assert0((put_bits_count(&s->pb) & 7) == 0); @@ -425,7 +425,7 @@ static int encode_superframe(AVCodecContext *avctx, AVPacket *avpkt, put_bits(&s->pb, 8, 'N'); flush_put_bits(&s->pb); - av_assert0(put_bits_ptr(&s->pb) - s->pb.buf == avctx->block_align); + av_assert0(put_bytes_output(&s->pb) == avctx->block_align); if (frame->pts != AV_NOPTS_VALUE) avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding); @@ -446,8 +446,7 @@ const FFCodec ff_wmav1_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_superframe), .close = ff_wma_end, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif @@ -462,8 +461,7 @@ const FFCodec ff_wmav2_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_superframe), .close = ff_wma_end, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/wmalosslessdec.c b/libavcodec/wmalosslessdec.c index 9559fe1fa..72d2f3175 100644 --- a/libavcodec/wmalosslessdec.c +++ b/libavcodec/wmalosslessdec.c @@ -1057,7 +1057,7 @@ static int decode_frame(WmallDecodeCtx *s) /* no idea what these are for, might be the number of samples that need to be skipped at the beginning or end of a stream */ if (get_bits1(gb)) { - int av_unused skip; + av_unused int skip; /* usually true for the first frame */ if (get_bits1(gb)) { @@ -1302,7 +1302,7 @@ static int decode_packet(AVCodecContext *avctx, AVFrame *rframe, return (s->packet_loss) ? AVERROR_INVALIDDATA : get_bits_count(gb) >> 3; } -static void flush(AVCodecContext *avctx) +static av_cold void flush(AVCodecContext *avctx) { WmallDecodeCtx *s = avctx->priv_data; s->packet_loss = 1; @@ -1335,13 +1335,6 @@ const FFCodec ff_wmalossless_decoder = { .close = decode_close, FF_CODEC_DECODE_CB(decode_packet), .flush = flush, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c index a6c4a7563..dd33c56e5 100644 --- a/libavcodec/wmaprodec.c +++ b/libavcodec/wmaprodec.c @@ -88,6 +88,7 @@ #include +#include "libavutil/attributes.h" #include "libavutil/audio_fifo.h" #include "libavutil/mem.h" #include "libavutil/tx.h" @@ -370,14 +371,6 @@ static av_cold int decode_init(WMAProDecodeCtx *s, AVCodecContext *avctx, int nu int log2_max_num_subframes; int num_possible_block_sizes; - if (avctx->codec_id == AV_CODEC_ID_XMA1 || avctx->codec_id == AV_CODEC_ID_XMA2) - avctx->block_align = 2048; - - if (!avctx->block_align) { - av_log(avctx, AV_LOG_ERROR, "block_align is not set\n"); - return AVERROR(EINVAL); - } - s->avctx = avctx; init_put_bits(&s->pb, s->frame_data, MAX_FRAMESIZE); @@ -471,11 +464,6 @@ static av_cold int decode_init(WMAProDecodeCtx *s, AVCodecContext *avctx, int nu return AVERROR_INVALIDDATA; } - if (s->avctx->sample_rate <= 0) { - av_log(avctx, AV_LOG_ERROR, "invalid sample rate\n"); - return AVERROR_INVALIDDATA; - } - if (s->nb_channels <= 0) { av_log(avctx, AV_LOG_ERROR, "invalid number of channels %d\n", s->nb_channels); @@ -608,6 +596,11 @@ static av_cold int wmapro_decode_init(AVCodecContext *avctx) { WMAProDecodeCtx *s = avctx->priv_data; + if (!avctx->block_align) { + av_log(avctx, AV_LOG_ERROR, "block_align is not set\n"); + return AVERROR(EINVAL); + } + return decode_init(s, avctx, 0); } @@ -1962,6 +1955,8 @@ static av_cold int xma_decode_init(AVCodecContext *avctx) XMADecodeCtx *s = avctx->priv_data; int i, ret, start_channels = 0; + avctx->block_align = 2048; + if (avctx->ch_layout.nb_channels <= 0 || avctx->extradata_size == 0) return AVERROR_INVALIDDATA; @@ -2046,7 +2041,7 @@ static av_cold int xma_decode_end(AVCodecContext *avctx) return 0; } -static void flush(WMAProDecodeCtx *s) +static av_cold void flush(WMAProDecodeCtx *s) { int i; /** reset output buffer as a part of it is used during the windowing of a @@ -2064,14 +2059,14 @@ static void flush(WMAProDecodeCtx *s) *@brief Clear decoder buffers (for seeking). *@param avctx codec context */ -static void wmapro_flush(AVCodecContext *avctx) +static av_cold void wmapro_flush(AVCodecContext *avctx) { WMAProDecodeCtx *s = avctx->priv_data; flush(s); } -static void xma_flush(AVCodecContext *avctx) +static av_cold void xma_flush(AVCodecContext *avctx) { XMADecodeCtx *s = avctx->priv_data; int i; @@ -2100,14 +2095,8 @@ const FFCodec ff_wmapro_decoder = { .init = wmapro_decode_init, .close = wmapro_decode_end, FF_CODEC_DECODE_CB(wmapro_decode_packet), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, + .p.capabilities = AV_CODEC_CAP_DR1, .flush = wmapro_flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; @@ -2121,13 +2110,7 @@ const FFCodec ff_xma1_decoder = { .close = xma_decode_end, FF_CODEC_DECODE_CB(xma_decode_packet), .flush = xma_flush, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; @@ -2141,12 +2124,6 @@ const FFCodec ff_xma2_decoder = { .close = xma_decode_end, FF_CODEC_DECODE_CB(xma_decode_packet), .flush = xma_flush, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/wmavoice.c b/libavcodec/wmavoice.c index 39868e02b..7fc735ad1 100644 --- a/libavcodec/wmavoice.c +++ b/libavcodec/wmavoice.c @@ -199,7 +199,7 @@ typedef struct WMAVoiceContext { ///< to #wmavoice_decode_packet() (since ///< they're part of the previous superframe) - uint8_t sframe_cache[SFRAME_CACHE_MAXSIZE + AV_INPUT_BUFFER_PADDING_SIZE]; + uint8_t sframe_cache[SFRAME_CACHE_MAXSIZE + AV_INPUT_BUFFER_PADDING_SIZE]; ///< ///< cache for superframe data split over ///< multiple packets int sframe_cache_size; ///< set to >0 if we have data from an @@ -249,10 +249,9 @@ typedef struct WMAVoiceContext { ///< only used for comfort noise in #pRNG() int nb_superframes; ///< number of superframes in current packet float gain_pred_err[6]; ///< cache for gain prediction - float excitation_history[MAX_SIGNAL_HISTORY]; - ///< cache of the signal of previous - ///< superframes, used as a history for - ///< signal generation + float excitation_history[MAX_SIGNAL_HISTORY]; ///< cache of the signal of + ///< previous superframes, used as a history + ///< for signal generation float synth_history[MAX_LSPS]; ///< see #excitation_history /** * @} @@ -272,18 +271,16 @@ typedef struct WMAVoiceContext { float postfilter_agc; ///< gain control memory, used in ///< #adaptive_gain_control() float dcf_mem[2]; ///< DC filter history + /// zero filter output (i.e. excitation) by postfilter float zero_exc_pf[MAX_SIGNAL_HISTORY + MAX_SFRAMESIZE]; - ///< zero filter output (i.e. excitation) - ///< by postfilter float denoise_filter_cache[MAX_FRAMESIZE]; int denoise_filter_cache_size; ///< samples in #denoise_filter_cache + /// aligned buffer for LPC tilting DECLARE_ALIGNED(32, float, tilted_lpcs_pf)[0x82]; - ///< aligned buffer for LPC tilting + /// aligned buffer for denoise coefficients DECLARE_ALIGNED(32, float, denoise_coeffs_pf)[0x82]; - ///< aligned buffer for denoise coefficients + /// aligned buffer for postfilter speech synthesis DECLARE_ALIGNED(32, float, synth_filter_out_buf)[0x80 + MAX_LSPS_ALIGN16]; - ///< aligned buffer for postfilter speech - ///< synthesis /** * @} */ @@ -562,7 +559,7 @@ static int kalman_smoothen(WMAVoiceContext *s, int pitch, /* find best fitting point in history */ do { - dot = avpriv_scalarproduct_float_c(in, ptr, size); + dot = ff_scalarproduct_float_c(in, ptr, size); if (dot > optimal_gain) { optimal_gain = dot; best_hist_ptr = ptr; @@ -571,7 +568,7 @@ static int kalman_smoothen(WMAVoiceContext *s, int pitch, if (optimal_gain <= 0) return -1; - dot = avpriv_scalarproduct_float_c(best_hist_ptr, best_hist_ptr, size); + dot = ff_scalarproduct_float_c(best_hist_ptr, best_hist_ptr, size); if (dot <= 0) // would be 1.0 return -1; @@ -601,8 +598,8 @@ static float tilt_factor(const float *lpcs, int n_lpcs) { float rh0, rh1; - rh0 = 1.0 + avpriv_scalarproduct_float_c(lpcs, lpcs, n_lpcs); - rh1 = lpcs[0] + avpriv_scalarproduct_float_c(lpcs, &lpcs[1], n_lpcs - 1); + rh0 = 1.0 + ff_scalarproduct_float_c(lpcs, lpcs, n_lpcs); + rh1 = lpcs[0] + ff_scalarproduct_float_c(lpcs, &lpcs[1], n_lpcs - 1); return rh1 / rh0; } @@ -702,8 +699,8 @@ static void calc_input_response(WMAVoiceContext *s, float *lpcs_src, -1.8 * tilt_factor(coeffs_dst, remainder - 1), coeffs_dst, remainder); } - sq = (1.0 / 64.0) * sqrtf(1 / avpriv_scalarproduct_float_c(coeffs_dst, coeffs_dst, - remainder)); + sq = (1.0 / 64.0) * sqrtf(1 / ff_scalarproduct_float_c(coeffs_dst, coeffs_dst, + remainder)); for (n = 0; n < remainder; n++) coeffs_dst[n] *= sq; } @@ -1381,8 +1378,8 @@ static void synth_block_fcb_acb(WMAVoiceContext *s, GetBitContext *gb, /* Calculate gain for adaptive & fixed codebook signal. * see ff_amr_set_fixed_gain(). */ idx = get_bits(gb, 7); - fcb_gain = expf(avpriv_scalarproduct_float_c(s->gain_pred_err, - gain_coeff, 6) - + fcb_gain = expf(ff_scalarproduct_float_c(s->gain_pred_err, + gain_coeff, 6) - 5.2409161640 + wmavoice_gain_codebook_fcb[idx]); acb_gain = wmavoice_gain_codebook_acb[idx]; pred_err = av_clipf(wmavoice_gain_codebook_fcb[idx], @@ -2030,11 +2027,7 @@ const FFCodec ff_wmavoice_decoder = { .init = wmavoice_decode_init, .close = wmavoice_decode_end, FF_CODEC_DECODE_CB(wmavoice_decode_packet), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .flush = wmavoice_flush, }; diff --git a/libavcodec/wmv2.c b/libavcodec/wmv2.c deleted file mode 100644 index c2bcb988c..000000000 --- a/libavcodec/wmv2.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2002 The FFmpeg Project - * - * 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 "avcodec.h" -#include "idctdsp.h" -#include "mpegvideo.h" -#include "msmpeg4_vc1_data.h" -#include "wmv2.h" - - -av_cold void ff_wmv2_common_init(MpegEncContext *s) -{ - WMV2Context *const w = s->private_ctx; - - ff_blockdsp_init(&s->bdsp); - ff_wmv2dsp_init(&w->wdsp); - s->idsp.perm_type = w->wdsp.idct_perm; - ff_init_scantable_permutation(s->idsp.idct_permutation, - w->wdsp.idct_perm); - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, - ff_wmv1_scantable[1]); - ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, - ff_wmv1_scantable[0]); - ff_permute_scantable(s->permutated_intra_h_scantable, ff_wmv1_scantable[2], - s->idsp.idct_permutation); - ff_permute_scantable(s->permutated_intra_v_scantable, ff_wmv1_scantable[3], - s->idsp.idct_permutation); - s->idsp.idct_put = w->wdsp.idct_put; - s->idsp.idct_add = w->wdsp.idct_add; - s->idsp.idct = NULL; -} - -void ff_mspel_motion(MpegEncContext *s, uint8_t *dest_y, - uint8_t *dest_cb, uint8_t *dest_cr, - uint8_t *const *ref_picture, - const op_pixels_func (*pix_op)[4], - int motion_x, int motion_y, int h) -{ - WMV2Context *const w = s->private_ctx; - const uint8_t *ptr; - int dxy, mx, my, src_x, src_y, v_edge_pos; - ptrdiff_t offset, linesize, uvlinesize; - int emu = 0; - - dxy = ((motion_y & 1) << 1) | (motion_x & 1); - dxy = 2 * dxy + w->hshift; - src_x = s->mb_x * 16 + (motion_x >> 1); - src_y = s->mb_y * 16 + (motion_y >> 1); - - /* WARNING: do no forget half pels */ - v_edge_pos = s->v_edge_pos; - src_x = av_clip(src_x, -16, s->width); - src_y = av_clip(src_y, -16, s->height); - - if (src_x <= -16 || src_x >= s->width) - dxy &= ~3; - if (src_y <= -16 || src_y >= s->height) - dxy &= ~4; - - linesize = s->linesize; - uvlinesize = s->uvlinesize; - ptr = ref_picture[0] + (src_y * linesize) + src_x; - - if (src_x < 1 || src_y < 1 || src_x + 17 >= s->h_edge_pos || - src_y + h + 1 >= v_edge_pos) { - s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr - 1 - s->linesize, - s->linesize, s->linesize, 19, 19, - src_x - 1, src_y - 1, - s->h_edge_pos, s->v_edge_pos); - ptr = s->sc.edge_emu_buffer + 1 + s->linesize; - emu = 1; - } - - w->wdsp.put_mspel_pixels_tab[dxy](dest_y, ptr, linesize); - w->wdsp.put_mspel_pixels_tab[dxy](dest_y + 8, ptr + 8, linesize); - w->wdsp.put_mspel_pixels_tab[dxy](dest_y + 8 * linesize, ptr + 8 * linesize, linesize); - w->wdsp.put_mspel_pixels_tab[dxy](dest_y + 8 + 8 * linesize, ptr + 8 + 8 * linesize, linesize); - - if (s->avctx->flags & AV_CODEC_FLAG_GRAY) - return; - - dxy = 0; - if ((motion_x & 3) != 0) - dxy |= 1; - if ((motion_y & 3) != 0) - dxy |= 2; - mx = motion_x >> 2; - my = motion_y >> 2; - - src_x = s->mb_x * 8 + mx; - src_y = s->mb_y * 8 + my; - src_x = av_clip(src_x, -8, s->width >> 1); - if (src_x == (s->width >> 1)) - dxy &= ~1; - src_y = av_clip(src_y, -8, s->height >> 1); - if (src_y == (s->height >> 1)) - dxy &= ~2; - offset = (src_y * uvlinesize) + src_x; - ptr = ref_picture[1] + offset; - if (emu) { - s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr, - s->uvlinesize, s->uvlinesize, - 9, 9, - src_x, src_y, - s->h_edge_pos >> 1, s->v_edge_pos >> 1); - ptr = s->sc.edge_emu_buffer; - } - pix_op[1][dxy](dest_cb, ptr, uvlinesize, h >> 1); - - ptr = ref_picture[2] + offset; - if (emu) { - s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr, - s->uvlinesize, s->uvlinesize, - 9, 9, - src_x, src_y, - s->h_edge_pos >> 1, s->v_edge_pos >> 1); - ptr = s->sc.edge_emu_buffer; - } - pix_op[1][dxy](dest_cr, ptr, uvlinesize, h >> 1); -} diff --git a/libavcodec/wmv2.h b/libavcodec/wmv2.h index 6fc9704c3..aef312686 100644 --- a/libavcodec/wmv2.h +++ b/libavcodec/wmv2.h @@ -21,30 +21,16 @@ #ifndef AVCODEC_WMV2_H #define AVCODEC_WMV2_H -#include "mpegvideo.h" -#include "wmv2dsp.h" +#include + +#include "libavutil/attributes.h" #define SKIP_TYPE_NONE 0 #define SKIP_TYPE_MPEG 1 #define SKIP_TYPE_ROW 2 #define SKIP_TYPE_COL 3 - -typedef struct WMV2Context { - WMV2DSPContext wdsp; - int hshift; -} WMV2Context; - -void ff_wmv2_common_init(MpegEncContext *s); - -void ff_mspel_motion(MpegEncContext *s, - uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, - uint8_t *const *ref_picture, - const op_pixels_func (*pix_op)[4], - int motion_x, int motion_y, int h); - - -static av_always_inline int wmv2_get_cbp_table_index(MpegEncContext *s, int cbp_index) +static av_always_inline int wmv2_get_cbp_table_index(int qscale, int cbp_index) { static const uint8_t map[3][3] = { { 0, 2, 1 }, @@ -52,7 +38,7 @@ static av_always_inline int wmv2_get_cbp_table_index(MpegEncContext *s, int cbp_ { 2, 1, 0 }, }; - return map[(s->qscale > 10) + (s->qscale > 20)][cbp_index]; + return map[(qscale > 10) + (qscale > 20)][cbp_index]; } #endif /* AVCODEC_WMV2_H */ diff --git a/libavcodec/wmv2dec.c b/libavcodec/wmv2dec.c index 677467ccc..8a3239fe7 100644 --- a/libavcodec/wmv2dec.c +++ b/libavcodec/wmv2dec.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/mem_internal.h" #include "avcodec.h" @@ -31,15 +32,18 @@ #include "msmpeg4.h" #include "msmpeg4_vc1_data.h" #include "msmpeg4dec.h" +#include "qpeldsp.h" #include "simple_idct.h" #include "wmv2.h" #include "wmv2data.h" #include "wmv2dec.h" typedef struct WMV2DecContext { - MpegEncContext s; - WMV2Context common; + MSMP4DecContext ms; IntraX8Context x8; + + qpel_mc_func put_mspel_pixels_tab[8]; + int j_type_bit; int j_type; int abt_flag; @@ -51,33 +55,242 @@ typedef struct WMV2DecContext { int cbp_table_index; int top_left_mv_flag; int per_mb_rl_bit; - int skip_type; + int hshift; DECLARE_ALIGNED(32, int16_t, abt_block2)[6][64]; } WMV2DecContext; -static void wmv2_add_block(WMV2DecContext *w, int16_t *block1, +static void wmv2_mspel8_h_lowpass(uint8_t *dst, const uint8_t *src, + int dstStride, int srcStride, int h) +{ + const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; + + for (int i = 0; i < h; i++) { + dst[0] = cm[(9 * (src[0] + src[1]) - (src[-1] + src[2]) + 8) >> 4]; + dst[1] = cm[(9 * (src[1] + src[2]) - (src[0] + src[3]) + 8) >> 4]; + dst[2] = cm[(9 * (src[2] + src[3]) - (src[1] + src[4]) + 8) >> 4]; + dst[3] = cm[(9 * (src[3] + src[4]) - (src[2] + src[5]) + 8) >> 4]; + dst[4] = cm[(9 * (src[4] + src[5]) - (src[3] + src[6]) + 8) >> 4]; + dst[5] = cm[(9 * (src[5] + src[6]) - (src[4] + src[7]) + 8) >> 4]; + dst[6] = cm[(9 * (src[6] + src[7]) - (src[5] + src[8]) + 8) >> 4]; + dst[7] = cm[(9 * (src[7] + src[8]) - (src[6] + src[9]) + 8) >> 4]; + dst += dstStride; + src += srcStride; + } +} + +static void wmv2_mspel8_v_lowpass(uint8_t *dst, const uint8_t *src, + int dstStride, int srcStride, int w) +{ + const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; + + for (int i = 0; i < w; i++) { + const int src_1 = src[-srcStride]; + const int src0 = src[0]; + const int src1 = src[srcStride]; + const int src2 = src[2 * srcStride]; + const int src3 = src[3 * srcStride]; + const int src4 = src[4 * srcStride]; + const int src5 = src[5 * srcStride]; + const int src6 = src[6 * srcStride]; + const int src7 = src[7 * srcStride]; + const int src8 = src[8 * srcStride]; + const int src9 = src[9 * srcStride]; + dst[0 * dstStride] = cm[(9 * (src0 + src1) - (src_1 + src2) + 8) >> 4]; + dst[1 * dstStride] = cm[(9 * (src1 + src2) - (src0 + src3) + 8) >> 4]; + dst[2 * dstStride] = cm[(9 * (src2 + src3) - (src1 + src4) + 8) >> 4]; + dst[3 * dstStride] = cm[(9 * (src3 + src4) - (src2 + src5) + 8) >> 4]; + dst[4 * dstStride] = cm[(9 * (src4 + src5) - (src3 + src6) + 8) >> 4]; + dst[5 * dstStride] = cm[(9 * (src5 + src6) - (src4 + src7) + 8) >> 4]; + dst[6 * dstStride] = cm[(9 * (src6 + src7) - (src5 + src8) + 8) >> 4]; + dst[7 * dstStride] = cm[(9 * (src7 + src8) - (src6 + src9) + 8) >> 4]; + src++; + dst++; + } +} + +static void put_mspel8_mc10_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +{ + uint8_t half[64]; + + wmv2_mspel8_h_lowpass(half, src, 8, stride, 8); + ff_put_pixels8_l2_8(dst, src, half, stride, stride, 8, 8); +} + +static void put_mspel8_mc20_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +{ + wmv2_mspel8_h_lowpass(dst, src, stride, stride, 8); +} + +static void put_mspel8_mc30_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +{ + uint8_t half[64]; + + wmv2_mspel8_h_lowpass(half, src, 8, stride, 8); + ff_put_pixels8_l2_8(dst, src + 1, half, stride, stride, 8, 8); +} + +static void put_mspel8_mc02_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +{ + wmv2_mspel8_v_lowpass(dst, src, stride, stride, 8); +} + +static void put_mspel8_mc12_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +{ + uint8_t halfH[88]; + uint8_t halfV[64]; + uint8_t halfHV[64]; + + wmv2_mspel8_h_lowpass(halfH, src - stride, 8, stride, 11); + wmv2_mspel8_v_lowpass(halfV, src, 8, stride, 8); + wmv2_mspel8_v_lowpass(halfHV, halfH + 8, 8, 8, 8); + ff_put_pixels8_l2_8(dst, halfV, halfHV, stride, 8, 8, 8); +} + +static void put_mspel8_mc32_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +{ + uint8_t halfH[88]; + uint8_t halfV[64]; + uint8_t halfHV[64]; + + wmv2_mspel8_h_lowpass(halfH, src - stride, 8, stride, 11); + wmv2_mspel8_v_lowpass(halfV, src + 1, 8, stride, 8); + wmv2_mspel8_v_lowpass(halfHV, halfH + 8, 8, 8, 8); + ff_put_pixels8_l2_8(dst, halfV, halfHV, stride, 8, 8, 8); +} + +static void put_mspel8_mc22_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +{ + uint8_t halfH[88]; + + wmv2_mspel8_h_lowpass(halfH, src - stride, 8, stride, 11); + wmv2_mspel8_v_lowpass(dst, halfH + 8, stride, 8, 8); +} + +static av_cold void wmv2_mspel_init(WMV2DecContext *w) +{ + w->put_mspel_pixels_tab[0] = ff_put_pixels8x8_c; + w->put_mspel_pixels_tab[1] = put_mspel8_mc10_c; + w->put_mspel_pixels_tab[2] = put_mspel8_mc20_c; + w->put_mspel_pixels_tab[3] = put_mspel8_mc30_c; + w->put_mspel_pixels_tab[4] = put_mspel8_mc02_c; + w->put_mspel_pixels_tab[5] = put_mspel8_mc12_c; + w->put_mspel_pixels_tab[6] = put_mspel8_mc22_c; + w->put_mspel_pixels_tab[7] = put_mspel8_mc32_c; +} + +void ff_mspel_motion(MPVContext *const s, uint8_t *dest_y, + uint8_t *dest_cb, uint8_t *dest_cr, + uint8_t *const *ref_picture, + const op_pixels_func (*pix_op)[4], + int motion_x, int motion_y, int h) +{ + WMV2DecContext *const w = (WMV2DecContext *) s; + const uint8_t *ptr; + int dxy, mx, my, src_x, src_y, v_edge_pos; + ptrdiff_t offset, linesize, uvlinesize; + int emu = 0; + + dxy = ((motion_y & 1) << 1) | (motion_x & 1); + dxy = 2 * dxy + w->hshift; + src_x = s->mb_x * 16 + (motion_x >> 1); + src_y = s->mb_y * 16 + (motion_y >> 1); + + /* WARNING: do no forget half pels */ + v_edge_pos = s->v_edge_pos; + src_x = av_clip(src_x, -16, s->width); + src_y = av_clip(src_y, -16, s->height); + + if (src_x <= -16 || src_x >= s->width) + dxy &= ~3; + if (src_y <= -16 || src_y >= s->height) + dxy &= ~4; + + linesize = s->linesize; + uvlinesize = s->uvlinesize; + ptr = ref_picture[0] + (src_y * linesize) + src_x; + + if (src_x < 1 || src_y < 1 || src_x + 17 >= s->h_edge_pos || + src_y + h + 1 >= v_edge_pos) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr - 1 - s->linesize, + s->linesize, s->linesize, 19, 19, + src_x - 1, src_y - 1, + s->h_edge_pos, s->v_edge_pos); + ptr = s->sc.edge_emu_buffer + 1 + s->linesize; + emu = 1; + } + + w->put_mspel_pixels_tab[dxy](dest_y, ptr, linesize); + w->put_mspel_pixels_tab[dxy](dest_y + 8, ptr + 8, linesize); + w->put_mspel_pixels_tab[dxy](dest_y + 8 * linesize, ptr + 8 * linesize, linesize); + w->put_mspel_pixels_tab[dxy](dest_y + 8 + 8 * linesize, ptr + 8 + 8 * linesize, linesize); + + if (s->avctx->flags & AV_CODEC_FLAG_GRAY) + return; + + dxy = 0; + if ((motion_x & 3) != 0) + dxy |= 1; + if ((motion_y & 3) != 0) + dxy |= 2; + mx = motion_x >> 2; + my = motion_y >> 2; + + src_x = s->mb_x * 8 + mx; + src_y = s->mb_y * 8 + my; + src_x = av_clip(src_x, -8, s->width >> 1); + if (src_x == (s->width >> 1)) + dxy &= ~1; + src_y = av_clip(src_y, -8, s->height >> 1); + if (src_y == (s->height >> 1)) + dxy &= ~2; + offset = (src_y * uvlinesize) + src_x; + ptr = ref_picture[1] + offset; + if (emu) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr, + s->uvlinesize, s->uvlinesize, + 9, 9, + src_x, src_y, + s->h_edge_pos >> 1, s->v_edge_pos >> 1); + ptr = s->sc.edge_emu_buffer; + } + pix_op[1][dxy](dest_cb, ptr, uvlinesize, h >> 1); + + ptr = ref_picture[2] + offset; + if (emu) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr, + s->uvlinesize, s->uvlinesize, + 9, 9, + src_x, src_y, + s->h_edge_pos >> 1, s->v_edge_pos >> 1); + ptr = s->sc.edge_emu_buffer; + } + pix_op[1][dxy](dest_cr, ptr, uvlinesize, h >> 1); +} + +static void wmv2_add_block(WMV2DecContext *w, int16_t blocks1[][64], uint8_t *dst, int stride, int n) { - MpegEncContext *const s = &w->s; + H263DecContext *const h = &w->ms.h; - if (s->block_last_index[n] >= 0) { + if (h->c.block_last_index[n] >= 0) { + int16_t *block1 = blocks1[n]; switch (w->abt_type_table[n]) { case 0: - w->common.wdsp.idct_add(dst, stride, block1); + h->c.idsp.idct_add(dst, stride, block1); break; case 1: ff_simple_idct84_add(dst, stride, block1); ff_simple_idct84_add(dst + 4 * stride, stride, w->abt_block2[n]); - s->bdsp.clear_block(w->abt_block2[n]); + h->c.bdsp.clear_block(w->abt_block2[n]); break; case 2: ff_simple_idct48_add(dst, stride, block1); ff_simple_idct48_add(dst + 4, stride, w->abt_block2[n]); - s->bdsp.clear_block(w->abt_block2[n]); + h->c.bdsp.clear_block(w->abt_block2[n]); break; default: - av_log(s->avctx, AV_LOG_ERROR, "internal error in WMV2 abt\n"); + av_unreachable("abt_type_table is read via decode012"); } } } @@ -87,99 +300,102 @@ void ff_wmv2_add_mb(MpegEncContext *s, int16_t block1[6][64], { WMV2DecContext *const w = (WMV2DecContext *) s; - wmv2_add_block(w, block1[0], dest_y, s->linesize, 0); - wmv2_add_block(w, block1[1], dest_y + 8, s->linesize, 1); - wmv2_add_block(w, block1[2], dest_y + 8 * s->linesize, s->linesize, 2); - wmv2_add_block(w, block1[3], dest_y + 8 + 8 * s->linesize, s->linesize, 3); + wmv2_add_block(w, block1, dest_y, s->linesize, 0); + wmv2_add_block(w, block1, dest_y + 8, s->linesize, 1); + wmv2_add_block(w, block1, dest_y + 8 * s->linesize, s->linesize, 2); + wmv2_add_block(w, block1, dest_y + 8 + 8 * s->linesize, s->linesize, 3); if (s->avctx->flags & AV_CODEC_FLAG_GRAY) return; - wmv2_add_block(w, block1[4], dest_cb, s->uvlinesize, 4); - wmv2_add_block(w, block1[5], dest_cr, s->uvlinesize, 5); + wmv2_add_block(w, block1, dest_cb, s->uvlinesize, 4); + wmv2_add_block(w, block1, dest_cr, s->uvlinesize, 5); } static int parse_mb_skip(WMV2DecContext *w) { - int mb_x, mb_y; + H263DecContext *const h = &w->ms.h; int coded_mb_count = 0; - MpegEncContext *const s = &w->s; - uint32_t *const mb_type = s->cur_pic.mb_type; + uint32_t *const mb_type = h->c.cur_pic.mb_type; - w->skip_type = get_bits(&s->gb, 2); - switch (w->skip_type) { + int skip_type = get_bits(&h->gb, 2); + switch (skip_type) { case SKIP_TYPE_NONE: - for (mb_y = 0; mb_y < s->mb_height; mb_y++) - for (mb_x = 0; mb_x < s->mb_width; mb_x++) - mb_type[mb_y * s->mb_stride + mb_x] = + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) + mb_type[mb_y * h->c.mb_stride + mb_x] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; break; case SKIP_TYPE_MPEG: - if (get_bits_left(&s->gb) < s->mb_height * s->mb_width) + if (get_bits_left(&h->gb) < h->c.mb_height * h->c.mb_width) return AVERROR_INVALIDDATA; - for (mb_y = 0; mb_y < s->mb_height; mb_y++) - for (mb_x = 0; mb_x < s->mb_width; mb_x++) - mb_type[mb_y * s->mb_stride + mb_x] = - (get_bits1(&s->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) + mb_type[mb_y * h->c.mb_stride + mb_x] = + (get_bits1(&h->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; break; case SKIP_TYPE_ROW: - for (mb_y = 0; mb_y < s->mb_height; mb_y++) { - if (get_bits_left(&s->gb) < 1) + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) { + if (get_bits_left(&h->gb) < 1) return AVERROR_INVALIDDATA; - if (get_bits1(&s->gb)) { - for (mb_x = 0; mb_x < s->mb_width; mb_x++) - mb_type[mb_y * s->mb_stride + mb_x] = + if (get_bits1(&h->gb)) { + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) + mb_type[mb_y * h->c.mb_stride + mb_x] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } else { - for (mb_x = 0; mb_x < s->mb_width; mb_x++) - mb_type[mb_y * s->mb_stride + mb_x] = - (get_bits1(&s->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + if (get_bits_left(&h->gb) < h->c.mb_width) + return AVERROR_INVALIDDATA; + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) + mb_type[mb_y * h->c.mb_stride + mb_x] = + (get_bits1(&h->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } } break; case SKIP_TYPE_COL: - for (mb_x = 0; mb_x < s->mb_width; mb_x++) { - if (get_bits_left(&s->gb) < 1) + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) { + if (get_bits_left(&h->gb) < 1) return AVERROR_INVALIDDATA; - if (get_bits1(&s->gb)) { - for (mb_y = 0; mb_y < s->mb_height; mb_y++) - mb_type[mb_y * s->mb_stride + mb_x] = + if (get_bits1(&h->gb)) { + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) + mb_type[mb_y * h->c.mb_stride + mb_x] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } else { - for (mb_y = 0; mb_y < s->mb_height; mb_y++) - mb_type[mb_y * s->mb_stride + mb_x] = - (get_bits1(&s->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + if (get_bits_left(&h->gb) < h->c.mb_height) + return AVERROR_INVALIDDATA; + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) + mb_type[mb_y * h->c.mb_stride + mb_x] = + (get_bits1(&h->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } } break; } - for (mb_y = 0; mb_y < s->mb_height; mb_y++) - for (mb_x = 0; mb_x < s->mb_width; mb_x++) - coded_mb_count += !IS_SKIP(mb_type[mb_y * s->mb_stride + mb_x]); + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) + coded_mb_count += !IS_SKIP(mb_type[mb_y * h->c.mb_stride + mb_x]); - if (coded_mb_count > get_bits_left(&s->gb)) + if (coded_mb_count > get_bits_left(&h->gb)) return AVERROR_INVALIDDATA; return 0; } -static int decode_ext_header(WMV2DecContext *w) +static av_cold int decode_ext_header(AVCodecContext *avctx, WMV2DecContext *w) { - MpegEncContext *const s = &w->s; + H263DecContext *const h = &w->ms.h; GetBitContext gb; int fps; int code; - if (s->avctx->extradata_size < 4) + if (avctx->extradata_size < 4) return AVERROR_INVALIDDATA; - init_get_bits(&gb, s->avctx->extradata, 32); + init_get_bits(&gb, avctx->extradata, 32); fps = get_bits(&gb, 5); - s->bit_rate = get_bits(&gb, 11) * 1024; + w->ms.bit_rate = get_bits(&gb, 11) * 1024; w->mspel_bit = get_bits1(&gb); - s->loop_filter = get_bits1(&gb); + h->loop_filter = get_bits1(&gb); w->abt_flag = get_bits1(&gb); w->j_type_bit = get_bits1(&gb); w->top_left_mv_flag = get_bits1(&gb); @@ -189,36 +405,36 @@ static int decode_ext_header(WMV2DecContext *w) if (code == 0) return AVERROR_INVALIDDATA; - s->slice_height = s->mb_height / code; + h->slice_height = h->c.mb_height / code; - if (s->avctx->debug & FF_DEBUG_PICT_INFO) - av_log(s->avctx, AV_LOG_DEBUG, - "fps:%d, br:%"PRId64", qpbit:%d, abt_flag:%d, j_type_bit:%d, " + if (avctx->debug & FF_DEBUG_PICT_INFO) + av_log(avctx, AV_LOG_DEBUG, + "fps:%d, br:%d, qpbit:%d, abt_flag:%d, j_type_bit:%d, " "tl_mv_flag:%d, mbrl_bit:%d, code:%d, loop_filter:%d, " "slices:%d\n", - fps, s->bit_rate, w->mspel_bit, w->abt_flag, w->j_type_bit, - w->top_left_mv_flag, w->per_mb_rl_bit, code, s->loop_filter, + fps, w->ms.bit_rate, w->mspel_bit, w->abt_flag, w->j_type_bit, + w->top_left_mv_flag, w->per_mb_rl_bit, code, h->loop_filter, code); return 0; } -int ff_wmv2_decode_picture_header(MpegEncContext *s) +static int wmv2_decode_picture_header(H263DecContext *const h) { int code; - s->pict_type = get_bits1(&s->gb) + 1; - if (s->pict_type == AV_PICTURE_TYPE_I) { - code = get_bits(&s->gb, 7); - av_log(s->avctx, AV_LOG_DEBUG, "I7:%X/\n", code); + h->c.pict_type = get_bits1(&h->gb) + 1; + if (h->c.pict_type == AV_PICTURE_TYPE_I) { + code = get_bits(&h->gb, 7); + av_log(h->c.avctx, AV_LOG_DEBUG, "I7:%X/\n", code); } - s->chroma_qscale = s->qscale = get_bits(&s->gb, 5); - if (s->qscale <= 0) + h->c.chroma_qscale = h->c.qscale = get_bits(&h->gb, 5); + if (h->c.qscale <= 0) return AVERROR_INVALIDDATA; - if (s->pict_type != AV_PICTURE_TYPE_I && show_bits(&s->gb, 1)) { - GetBitContext gb = s->gb; + if (h->c.pict_type != AV_PICTURE_TYPE_I && show_bits(&h->gb, 1)) { + GetBitContext gb = h->gb; int skip_type = get_bits(&gb, 2); - int run = skip_type == SKIP_TYPE_COL ? s->mb_width : s->mb_height; + int run = skip_type == SKIP_TYPE_COL ? h->c.mb_width : h->c.mb_height; while (run > 0) { int block = FFMIN(run, 25); @@ -233,47 +449,47 @@ int ff_wmv2_decode_picture_header(MpegEncContext *s) return 0; } -int ff_wmv2_decode_secondary_picture_header(MpegEncContext *s) +int ff_wmv2_decode_secondary_picture_header(H263DecContext *const h) { - WMV2DecContext *const w = (WMV2DecContext *) s; + WMV2DecContext *const w = (WMV2DecContext *)h; - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (h->c.pict_type == AV_PICTURE_TYPE_I) { /* Is filling with zeroes really the right thing to do? */ - memset(s->cur_pic.mb_type, 0, - sizeof(*s->cur_pic.mb_type) * s->mb_height * s->mb_stride); + memset(h->c.cur_pic.mb_type, 0, + sizeof(*h->c.cur_pic.mb_type) * h->c.mb_height * h->c.mb_stride); if (w->j_type_bit) - w->j_type = get_bits1(&s->gb); + w->j_type = get_bits1(&h->gb); else w->j_type = 0; // FIXME check if (!w->j_type) { if (w->per_mb_rl_bit) - s->per_mb_rl_table = get_bits1(&s->gb); + w->ms.per_mb_rl_table = get_bits1(&h->gb); else - s->per_mb_rl_table = 0; + w->ms.per_mb_rl_table = 0; - if (!s->per_mb_rl_table) { - s->rl_chroma_table_index = decode012(&s->gb); - s->rl_table_index = decode012(&s->gb); + if (!w->ms.per_mb_rl_table) { + w->ms.rl_chroma_table_index = decode012(&h->gb); + w->ms.rl_table_index = decode012(&h->gb); } - s->dc_table_index = get_bits1(&s->gb); + w->ms.dc_table_index = get_bits1(&h->gb); // at minimum one bit per macroblock is required at least in a valid frame, // we discard frames much smaller than this. Frames smaller than 1/8 of the // smallest "black/skip" frame generally contain not much recoverable content // while at the same time they have the highest computational requirements // per byte - if (get_bits_left(&s->gb) * 8LL < (s->width+15)/16 * ((s->height+15)/16)) + if (get_bits_left(&h->gb) * 8LL < (h->c.width+15)/16 * ((h->c.height+15)/16)) return AVERROR_INVALIDDATA; } - s->inter_intra_pred = 0; - s->no_rounding = 1; - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, + h->c.inter_intra_pred = 0; + h->c.no_rounding = 1; + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "qscale:%d rlc:%d rl:%d dc:%d mbrl:%d j_type:%d \n", - s->qscale, s->rl_chroma_table_index, s->rl_table_index, - s->dc_table_index, s->per_mb_rl_table, w->j_type); + h->c.qscale, w->ms.rl_chroma_table_index, w->ms.rl_table_index, + w->ms.dc_table_index, w->ms.per_mb_rl_table, w->j_type); } } else { int cbp_index; @@ -283,61 +499,61 @@ int ff_wmv2_decode_secondary_picture_header(MpegEncContext *s) ret = parse_mb_skip(w); if (ret < 0) return ret; - cbp_index = decode012(&s->gb); - w->cbp_table_index = wmv2_get_cbp_table_index(s, cbp_index); + cbp_index = decode012(&h->gb); + w->cbp_table_index = wmv2_get_cbp_table_index(h->c.qscale, cbp_index); if (w->mspel_bit) - s->mspel = get_bits1(&s->gb); + h->c.mspel = get_bits1(&h->gb); else - s->mspel = 0; // FIXME check + h->c.mspel = 0; // FIXME check if (w->abt_flag) { - w->per_mb_abt = get_bits1(&s->gb) ^ 1; + w->per_mb_abt = get_bits1(&h->gb) ^ 1; if (!w->per_mb_abt) - w->abt_type = decode012(&s->gb); + w->abt_type = decode012(&h->gb); } if (w->per_mb_rl_bit) - s->per_mb_rl_table = get_bits1(&s->gb); + w->ms.per_mb_rl_table = get_bits1(&h->gb); else - s->per_mb_rl_table = 0; + w->ms.per_mb_rl_table = 0; - if (!s->per_mb_rl_table) { - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + if (!w->ms.per_mb_rl_table) { + w->ms.rl_table_index = decode012(&h->gb); + w->ms.rl_chroma_table_index = w->ms.rl_table_index; } - if (get_bits_left(&s->gb) < 2) + if (get_bits_left(&h->gb) < 2) return AVERROR_INVALIDDATA; - s->dc_table_index = get_bits1(&s->gb); - s->mv_table_index = get_bits1(&s->gb); + w->ms.dc_table_index = get_bits1(&h->gb); + w->ms.mv_table_index = get_bits1(&h->gb); - s->inter_intra_pred = 0; // (s->width * s->height < 320 * 240 && s->bit_rate <= II_BITRATE); - s->no_rounding ^= 1; + h->c.inter_intra_pred = 0; // (h->c.width * h->c.height < 320 * 240 && w->ms.bit_rate <= II_BITRATE); + h->c.no_rounding ^= 1; - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "rl:%d rlc:%d dc:%d mv:%d mbrl:%d qp:%d mspel:%d " "per_mb_abt:%d abt_type:%d cbp:%d ii:%d\n", - s->rl_table_index, s->rl_chroma_table_index, - s->dc_table_index, s->mv_table_index, - s->per_mb_rl_table, s->qscale, s->mspel, + w->ms.rl_table_index, w->ms.rl_chroma_table_index, + w->ms.dc_table_index, w->ms.mv_table_index, + w->ms.per_mb_rl_table, h->c.qscale, h->c.mspel, w->per_mb_abt, w->abt_type, w->cbp_table_index, - s->inter_intra_pred); + h->c.inter_intra_pred); } } - s->esc3_level_length = 0; - s->esc3_run_length = 0; + w->ms.esc3_level_length = 0; + w->ms.esc3_run_length = 0; if (w->j_type) { - ff_intrax8_decode_picture(&w->x8, s->cur_pic.ptr, - &s->gb, &s->mb_x, &s->mb_y, - 2 * s->qscale, (s->qscale - 1) | 1, - s->loop_filter, s->low_delay); + ff_intrax8_decode_picture(&w->x8, h->c.cur_pic.ptr, + &h->gb, &h->c.mb_x, &h->c.mb_y, + 2 * h->c.qscale, (h->c.qscale - 1) | 1, + h->loop_filter, h->c.low_delay); - ff_er_add_slice(&w->s.er, 0, 0, - (w->s.mb_x >> 1) - 1, (w->s.mb_y >> 1) - 1, + ff_er_add_slice(&h->c.er, 0, 0, + (h->c.mb_x >> 1) - 1, (h->c.mb_y >> 1) - 1, ER_MB_END); return 1; } @@ -347,38 +563,37 @@ int ff_wmv2_decode_secondary_picture_header(MpegEncContext *s) static inline void wmv2_decode_motion(WMV2DecContext *w, int *mx_ptr, int *my_ptr) { - MpegEncContext *const s = &w->s; + H263DecContext *const h = &w->ms.h; - ff_msmpeg4_decode_motion(s, mx_ptr, my_ptr); + ff_msmpeg4_decode_motion(&w->ms, mx_ptr, my_ptr); - if ((((*mx_ptr) | (*my_ptr)) & 1) && s->mspel) - w->common.hshift = get_bits1(&s->gb); + if ((((*mx_ptr) | (*my_ptr)) & 1) && h->c.mspel) + w->hshift = get_bits1(&h->gb); else - w->common.hshift = 0; + w->hshift = 0; } static int16_t *wmv2_pred_motion(WMV2DecContext *w, int *px, int *py) { - MpegEncContext *const s = &w->s; - int xy, wrap, diff, type; - int16_t *A, *B, *C, *mot_val; + H263DecContext *const h = &w->ms.h; + int diff, type; - wrap = s->b8_stride; - xy = s->block_index[0]; + int wrap = h->c.b8_stride; + int xy = h->c.block_index[0]; - mot_val = s->cur_pic.motion_val[0][xy]; + int16_t *mot_val = h->c.cur_pic.motion_val[0][xy]; - A = s->cur_pic.motion_val[0][xy - 1]; - B = s->cur_pic.motion_val[0][xy - wrap]; - C = s->cur_pic.motion_val[0][xy + 2 - wrap]; + const int16_t *A = h->c.cur_pic.motion_val[0][xy - 1]; + const int16_t *B = h->c.cur_pic.motion_val[0][xy - wrap]; + const int16_t *C = h->c.cur_pic.motion_val[0][xy + 2 - wrap]; - if (s->mb_x && !s->first_slice_line && !s->mspel && w->top_left_mv_flag) + if (h->c.mb_x && !h->c.first_slice_line && !h->c.mspel && w->top_left_mv_flag) diff = FFMAX(FFABS(A[0] - B[0]), FFABS(A[1] - B[1])); else diff = 0; if (diff >= 8) - type = get_bits1(&s->gb); + type = get_bits1(&h->gb); else type = 2; @@ -390,7 +605,7 @@ static int16_t *wmv2_pred_motion(WMV2DecContext *w, int *px, int *py) *py = B[1]; } else { /* special case for first (slice) line */ - if (s->first_slice_line) { + if (h->c.first_slice_line) { *px = A[0]; *py = A[1]; } else { @@ -405,86 +620,91 @@ static int16_t *wmv2_pred_motion(WMV2DecContext *w, int *px, int *py) static inline int wmv2_decode_inter_block(WMV2DecContext *w, int16_t *block, int n, int cbp) { - MpegEncContext *const s = &w->s; + H263DecContext *const h = &w->ms.h; static const int sub_cbp_table[3] = { 2, 3, 1 }; int sub_cbp, ret; if (!cbp) { - s->block_last_index[n] = -1; + h->c.block_last_index[n] = -1; return 0; } if (w->per_block_abt) - w->abt_type = decode012(&s->gb); + w->abt_type = decode012(&h->gb); w->abt_type_table[n] = w->abt_type; if (w->abt_type) { const uint8_t *scantable = w->abt_type == 1 ? ff_wmv2_scantableA : ff_wmv2_scantableB; - sub_cbp = sub_cbp_table[decode012(&s->gb)]; + sub_cbp = sub_cbp_table[decode012(&h->gb)]; - if (sub_cbp & 1) - if ((ret = ff_msmpeg4_decode_block(s, block, n, 1, scantable)) < 0) + if (sub_cbp & 1) { + ret = ff_msmpeg4_decode_block(&w->ms, block, n, 1, scantable); + if (ret < 0) return ret; + } - if (sub_cbp & 2) - if ((ret = ff_msmpeg4_decode_block(s, w->abt_block2[n], n, 1, scantable)) < 0) + if (sub_cbp & 2) { + ret = ff_msmpeg4_decode_block(&w->ms, w->abt_block2[n], n, 1, scantable); + if (ret < 0) return ret; + } - s->block_last_index[n] = 63; + h->c.block_last_index[n] = 63; return 0; } else { - return ff_msmpeg4_decode_block(s, block, n, 1, - s->inter_scantable.permutated); + return ff_msmpeg4_decode_block(&w->ms, block, n, 1, + h->c.inter_scantable.permutated); } } -static int wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]) +static int wmv2_decode_mb(H263DecContext *const h) { - /* The following is only allowed because this encoder + /* The following is only allowed because this decoder * does not use slice threading. */ - WMV2DecContext *const w = (WMV2DecContext *) s; + WMV2DecContext *const w = (WMV2DecContext *) h; + MSMP4DecContext *const ms = &w->ms; int cbp, code, i, ret; uint8_t *coded_val; if (w->j_type) return 0; - if (s->pict_type == AV_PICTURE_TYPE_P) { - if (IS_SKIP(s->cur_pic.mb_type[s->mb_y * s->mb_stride + s->mb_x])) { + if (h->c.pict_type == AV_PICTURE_TYPE_P) { + if (IS_SKIP(h->c.cur_pic.mb_type[h->c.mb_y * h->c.mb_stride + h->c.mb_x])) { /* skip mb */ - s->mb_intra = 0; + h->c.mb_intra = 0; for (i = 0; i < 6; i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; - s->mb_skipped = 1; - w->common.hshift = 0; + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = 0; + h->c.mv[0][0][1] = 0; + h->c.mb_skipped = 1; + w->hshift = 0; return 0; } - if (get_bits_left(&s->gb) <= 0) + if (get_bits_left(&h->gb) <= 0) return AVERROR_INVALIDDATA; - code = get_vlc2(&s->gb, ff_mb_non_intra_vlc[w->cbp_table_index], + code = get_vlc2(&h->gb, ff_mb_non_intra_vlc[w->cbp_table_index], MB_NON_INTRA_VLC_BITS, 3); - s->mb_intra = (~code & 0x40) >> 6; + h->c.mb_intra = (~code & 0x40) >> 6; cbp = code & 0x3f; } else { - s->mb_intra = 1; - if (get_bits_left(&s->gb) <= 0) + h->c.mb_intra = 1; + if (get_bits_left(&h->gb) <= 0) return AVERROR_INVALIDDATA; - code = get_vlc2(&s->gb, ff_msmp4_mb_i_vlc, + code = get_vlc2(&h->gb, ff_msmp4_mb_i_vlc, MSMP4_MB_INTRA_VLC_BITS, 2); /* predict coded block pattern */ cbp = 0; for (i = 0; i < 6; i++) { int val = ((code >> (5 - i)) & 1); if (i < 4) { - int pred = ff_msmpeg4_coded_block_pred(s, i, &coded_val); + int pred = ff_msmpeg4_coded_block_pred(&h->c, i, &coded_val); val = val ^ pred; *coded_val = val; } @@ -492,64 +712,65 @@ static int wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]) } } - if (!s->mb_intra) { + if (!h->c.mb_intra) { int mx, my; wmv2_pred_motion(w, &mx, &my); if (cbp) { - s->bdsp.clear_blocks(s->block[0]); - if (s->per_mb_rl_table) { - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + h->c.bdsp.clear_blocks(h->block[0]); + if (ms->per_mb_rl_table) { + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; } if (w->abt_flag && w->per_mb_abt) { - w->per_block_abt = get_bits1(&s->gb); + w->per_block_abt = get_bits1(&h->gb); if (!w->per_block_abt) - w->abt_type = decode012(&s->gb); + w->abt_type = decode012(&h->gb); } else w->per_block_abt = 0; } wmv2_decode_motion(w, &mx, &my); - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; for (i = 0; i < 6; i++) { - if ((ret = wmv2_decode_inter_block(w, block[i], i, (cbp >> (5 - i)) & 1)) < 0) { - av_log(s->avctx, AV_LOG_ERROR, + if ((ret = wmv2_decode_inter_block(w, h->block[i], i, (cbp >> (5 - i)) & 1)) < 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "\nerror while decoding inter block: %d x %d (%d)\n", - s->mb_x, s->mb_y, i); + h->c.mb_x, h->c.mb_y, i); return ret; } } } else { - if (s->pict_type == AV_PICTURE_TYPE_P) - ff_dlog(s->avctx, "%d%d ", s->inter_intra_pred, cbp); - ff_dlog(s->avctx, "I at %d %d %d %06X\n", s->mb_x, s->mb_y, + if (h->c.pict_type == AV_PICTURE_TYPE_P) + ff_dlog(h->c.avctx, "%d%d ", h->c.inter_intra_pred, cbp); + ff_dlog(h->c.avctx, "I at %d %d %d %06X\n", h->c.mb_x, h->c.mb_y, ((cbp & 3) ? 1 : 0) + ((cbp & 0x3C) ? 2 : 0), - show_bits(&s->gb, 24)); - s->ac_pred = get_bits1(&s->gb); - if (s->inter_intra_pred) { - s->h263_aic_dir = get_vlc2(&s->gb, ff_inter_intra_vlc, + show_bits(&h->gb, 24)); + h->c.ac_pred = get_bits1(&h->gb); + if (h->c.inter_intra_pred) { + h->c.h263_aic_dir = get_vlc2(&h->gb, ff_inter_intra_vlc, INTER_INTRA_VLC_BITS, 1); - ff_dlog(s->avctx, "%d%d %d %d/", - s->ac_pred, s->h263_aic_dir, s->mb_x, s->mb_y); + ff_dlog(h->c.avctx, "%d%d %d %d/", + h->c.ac_pred, h->c.h263_aic_dir, h->c.mb_x, h->c.mb_y); } - if (s->per_mb_rl_table && cbp) { - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + if (ms->per_mb_rl_table && cbp) { + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; } - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); for (i = 0; i < 6; i++) { - if ((ret = ff_msmpeg4_decode_block(s, block[i], i, (cbp >> (5 - i)) & 1, NULL)) < 0) { - av_log(s->avctx, AV_LOG_ERROR, + ret = ff_msmpeg4_decode_block(ms, h->block[i], i, (cbp >> (5 - i)) & 1, NULL); + if (ret < 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "\nerror while decoding intra block: %d x %d (%d)\n", - s->mb_x, s->mb_y, i); + h->c.mb_x, h->c.mb_y, i); return ret; } } @@ -561,23 +782,22 @@ static int wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]) static av_cold int wmv2_decode_init(AVCodecContext *avctx) { WMV2DecContext *const w = avctx->priv_data; - MpegEncContext *const s = &w->s; + H263DecContext *const h = &w->ms.h; + MpegEncContext *const s = &h->c; int ret; - s->private_ctx = &w->common; + wmv2_mspel_init(w); if ((ret = ff_msmpeg4_decode_init(avctx)) < 0) return ret; - s->decode_mb = wmv2_decode_mb; + h->decode_header = wmv2_decode_picture_header; + h->decode_mb = wmv2_decode_mb; - ff_wmv2_common_init(s); + decode_ext_header(avctx, w); - decode_ext_header(w); - - return ff_intrax8_common_init(avctx, &w->x8, - w->s.block, w->s.block_last_index, - w->s.mb_width, w->s.mb_height); + return ff_intrax8_common_init(avctx, &w->x8, h->block[0], + s->mb_width, s->mb_height); } static av_cold int wmv2_decode_end(AVCodecContext *avctx) diff --git a/libavcodec/wmv2dec.h b/libavcodec/wmv2dec.h index bc8745bf6..d19760b6c 100644 --- a/libavcodec/wmv2dec.h +++ b/libavcodec/wmv2dec.h @@ -22,10 +22,16 @@ #define AVCODEC_WMV2DEC_H #include "mpegvideo.h" +struct H263DecContext; -int ff_wmv2_decode_picture_header(MpegEncContext * s); -int ff_wmv2_decode_secondary_picture_header(MpegEncContext * s); +int ff_wmv2_decode_secondary_picture_header(struct H263DecContext *const h); void ff_wmv2_add_mb(MpegEncContext *s, int16_t block[6][64], uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr); +void ff_mspel_motion(MPVContext *const s, + uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, + uint8_t *const *ref_picture, + const op_pixels_func (*pix_op)[4], + int motion_x, int motion_y, int h); + #endif diff --git a/libavcodec/wmv2dsp.c b/libavcodec/wmv2dsp.c index 4ad8a596b..7ebe4b614 100644 --- a/libavcodec/wmv2dsp.c +++ b/libavcodec/wmv2dsp.c @@ -21,7 +21,6 @@ #include "libavutil/common.h" #include "idctdsp.h" #include "mathops.h" -#include "qpeldsp.h" #include "wmv2dsp.h" #define W0 2048 @@ -140,131 +139,16 @@ static void wmv2_idct_put_c(uint8_t *dest, ptrdiff_t line_size, int16_t *block) } } -static void wmv2_mspel8_h_lowpass(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride, int h) -{ - const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; - int i; - - for (i = 0; i < h; i++) { - dst[0] = cm[(9 * (src[0] + src[1]) - (src[-1] + src[2]) + 8) >> 4]; - dst[1] = cm[(9 * (src[1] + src[2]) - (src[0] + src[3]) + 8) >> 4]; - dst[2] = cm[(9 * (src[2] + src[3]) - (src[1] + src[4]) + 8) >> 4]; - dst[3] = cm[(9 * (src[3] + src[4]) - (src[2] + src[5]) + 8) >> 4]; - dst[4] = cm[(9 * (src[4] + src[5]) - (src[3] + src[6]) + 8) >> 4]; - dst[5] = cm[(9 * (src[5] + src[6]) - (src[4] + src[7]) + 8) >> 4]; - dst[6] = cm[(9 * (src[6] + src[7]) - (src[5] + src[8]) + 8) >> 4]; - dst[7] = cm[(9 * (src[7] + src[8]) - (src[6] + src[9]) + 8) >> 4]; - dst += dstStride; - src += srcStride; - } -} - -static void wmv2_mspel8_v_lowpass(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride, int w) -{ - const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; - int i; - - for (i = 0; i < w; i++) { - const int src_1 = src[-srcStride]; - const int src0 = src[0]; - const int src1 = src[srcStride]; - const int src2 = src[2 * srcStride]; - const int src3 = src[3 * srcStride]; - const int src4 = src[4 * srcStride]; - const int src5 = src[5 * srcStride]; - const int src6 = src[6 * srcStride]; - const int src7 = src[7 * srcStride]; - const int src8 = src[8 * srcStride]; - const int src9 = src[9 * srcStride]; - dst[0 * dstStride] = cm[(9 * (src0 + src1) - (src_1 + src2) + 8) >> 4]; - dst[1 * dstStride] = cm[(9 * (src1 + src2) - (src0 + src3) + 8) >> 4]; - dst[2 * dstStride] = cm[(9 * (src2 + src3) - (src1 + src4) + 8) >> 4]; - dst[3 * dstStride] = cm[(9 * (src3 + src4) - (src2 + src5) + 8) >> 4]; - dst[4 * dstStride] = cm[(9 * (src4 + src5) - (src3 + src6) + 8) >> 4]; - dst[5 * dstStride] = cm[(9 * (src5 + src6) - (src4 + src7) + 8) >> 4]; - dst[6 * dstStride] = cm[(9 * (src6 + src7) - (src5 + src8) + 8) >> 4]; - dst[7 * dstStride] = cm[(9 * (src7 + src8) - (src6 + src9) + 8) >> 4]; - src++; - dst++; - } -} - -static void put_mspel8_mc10_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) -{ - uint8_t half[64]; - - wmv2_mspel8_h_lowpass(half, src, 8, stride, 8); - ff_put_pixels8_l2_8(dst, src, half, stride, stride, 8, 8); -} - -static void put_mspel8_mc20_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) -{ - wmv2_mspel8_h_lowpass(dst, src, stride, stride, 8); -} - -static void put_mspel8_mc30_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) -{ - uint8_t half[64]; - - wmv2_mspel8_h_lowpass(half, src, 8, stride, 8); - ff_put_pixels8_l2_8(dst, src + 1, half, stride, stride, 8, 8); -} - -static void put_mspel8_mc02_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) -{ - wmv2_mspel8_v_lowpass(dst, src, stride, stride, 8); -} - -static void put_mspel8_mc12_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) -{ - uint8_t halfH[88]; - uint8_t halfV[64]; - uint8_t halfHV[64]; - - wmv2_mspel8_h_lowpass(halfH, src - stride, 8, stride, 11); - wmv2_mspel8_v_lowpass(halfV, src, 8, stride, 8); - wmv2_mspel8_v_lowpass(halfHV, halfH + 8, 8, 8, 8); - ff_put_pixels8_l2_8(dst, halfV, halfHV, stride, 8, 8, 8); -} - -static void put_mspel8_mc32_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) -{ - uint8_t halfH[88]; - uint8_t halfV[64]; - uint8_t halfHV[64]; - - wmv2_mspel8_h_lowpass(halfH, src - stride, 8, stride, 11); - wmv2_mspel8_v_lowpass(halfV, src + 1, 8, stride, 8); - wmv2_mspel8_v_lowpass(halfHV, halfH + 8, 8, 8, 8); - ff_put_pixels8_l2_8(dst, halfV, halfHV, stride, 8, 8, 8); -} - -static void put_mspel8_mc22_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) -{ - uint8_t halfH[88]; - - wmv2_mspel8_h_lowpass(halfH, src - stride, 8, stride, 11); - wmv2_mspel8_v_lowpass(dst, halfH + 8, stride, 8, 8); -} - -av_cold void ff_wmv2dsp_init(WMV2DSPContext *c) +av_cold void ff_wmv2dsp_init(IDCTDSPContext *c) { c->idct_add = wmv2_idct_add_c; c->idct_put = wmv2_idct_put_c; - c->idct_perm = FF_IDCT_PERM_NONE; - - c->put_mspel_pixels_tab[0] = ff_put_pixels8x8_c; - c->put_mspel_pixels_tab[1] = put_mspel8_mc10_c; - c->put_mspel_pixels_tab[2] = put_mspel8_mc20_c; - c->put_mspel_pixels_tab[3] = put_mspel8_mc30_c; - c->put_mspel_pixels_tab[4] = put_mspel8_mc02_c; - c->put_mspel_pixels_tab[5] = put_mspel8_mc12_c; - c->put_mspel_pixels_tab[6] = put_mspel8_mc22_c; - c->put_mspel_pixels_tab[7] = put_mspel8_mc32_c; + c->idct = NULL; + c->perm_type = FF_IDCT_PERM_NONE; #if ARCH_MIPS ff_wmv2dsp_init_mips(c); #endif + ff_init_scantable_permutation(c->idct_permutation, + c->perm_type); } diff --git a/libavcodec/wmv2dsp.h b/libavcodec/wmv2dsp.h index 5e40b30a2..1402dbb96 100644 --- a/libavcodec/wmv2dsp.h +++ b/libavcodec/wmv2dsp.h @@ -19,20 +19,9 @@ #ifndef AVCODEC_WMV2DSP_H #define AVCODEC_WMV2DSP_H -#include +struct IDCTDSPContext; -#include "qpeldsp.h" - -typedef struct WMV2DSPContext { - void (*idct_add)(uint8_t *dest, ptrdiff_t line_size, int16_t *block); - void (*idct_put)(uint8_t *dest, ptrdiff_t line_size, int16_t *block); - - qpel_mc_func put_mspel_pixels_tab[8]; - - int idct_perm; -} WMV2DSPContext; - -void ff_wmv2dsp_init(WMV2DSPContext *c); -void ff_wmv2dsp_init_mips(WMV2DSPContext *c); +void ff_wmv2dsp_init(struct IDCTDSPContext *c); +void ff_wmv2dsp_init_mips(struct IDCTDSPContext *c); #endif /* AVCODEC_WMV2DSP_H */ diff --git a/libavcodec/wmv2enc.c b/libavcodec/wmv2enc.c index fded6f0e7..4082b5817 100644 --- a/libavcodec/wmv2enc.c +++ b/libavcodec/wmv2enc.c @@ -28,14 +28,13 @@ #include "msmpeg4enc.h" #include "msmpeg4data.h" #include "msmpeg4_vc1_data.h" +#include "put_bits.h" #include "wmv2.h" -#include "wmv2enc.h" #define WMV2_EXTRADATA_SIZE 4 typedef struct WMV2EncContext { MSMPEG4EncContext msmpeg4; - WMV2Context common; int j_type_bit; int j_type; int abt_flag; @@ -49,14 +48,14 @@ typedef struct WMV2EncContext { static int encode_ext_header(WMV2EncContext *w) { - MpegEncContext *const s = &w->msmpeg4.s; + MPVEncContext *const s = &w->msmpeg4.m.s; PutBitContext pb; int code; - init_put_bits(&pb, s->avctx->extradata, WMV2_EXTRADATA_SIZE); + init_put_bits(&pb, s->c.avctx->extradata, WMV2_EXTRADATA_SIZE); - put_bits(&pb, 5, s->avctx->time_base.den / s->avctx->time_base.num); // yes 29.97 -> 29 - put_bits(&pb, 11, FFMIN(s->bit_rate / 1024, 2047)); + put_bits(&pb, 5, s->c.avctx->time_base.den / s->c.avctx->time_base.num); // yes 29.97 -> 29 + put_bits(&pb, 11, FFMIN(w->msmpeg4.m.bit_rate / 1024, 2047)); put_bits(&pb, 1, w->mspel_bit = 1); put_bits(&pb, 1, s->loop_filter); @@ -68,21 +67,170 @@ static int encode_ext_header(WMV2EncContext *w) flush_put_bits(&pb); - s->slice_height = s->mb_height / code; + s->slice_height = s->c.mb_height / code; return 0; } +static int wmv2_encode_picture_header(MPVMainEncContext *const m) +{ + WMV2EncContext *const w = (WMV2EncContext *) m; + MSMPEG4EncContext *const ms = &w->msmpeg4; + MPVEncContext *const s = &m->s; + + put_bits_assume_flushed(&s->pb); + + put_bits(&s->pb, 1, s->c.pict_type - 1); + if (s->c.pict_type == AV_PICTURE_TYPE_I) + put_bits(&s->pb, 7, 0); + put_bits(&s->pb, 5, s->c.qscale); + + ms->dc_table_index = 1; + ms->mv_table_index = 1; /* only if P-frame */ + ms->per_mb_rl_table = 0; + s->c.mspel = 0; + w->per_mb_abt = 0; + w->abt_type = 0; + w->j_type = 0; + + av_assert0(s->flipflop_rounding); + + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + av_assert0(s->c.no_rounding == 1); + if (w->j_type_bit) + put_bits(&s->pb, 1, w->j_type); + + if (w->per_mb_rl_bit) + put_bits(&s->pb, 1, ms->per_mb_rl_table); + + if (!ms->per_mb_rl_table) { + ff_msmpeg4_code012(&s->pb, ms->rl_chroma_table_index); + ff_msmpeg4_code012(&s->pb, ms->rl_table_index); + } + + put_bits(&s->pb, 1, ms->dc_table_index); + + s->c.inter_intra_pred = 0; + } else { + int cbp_index; + + put_bits(&s->pb, 2, SKIP_TYPE_NONE); + + ff_msmpeg4_code012(&s->pb, cbp_index = 0); + w->cbp_table_index = wmv2_get_cbp_table_index(s->c.qscale, cbp_index); + + if (w->mspel_bit) + put_bits(&s->pb, 1, s->c.mspel); + + if (w->abt_flag) { + put_bits(&s->pb, 1, w->per_mb_abt ^ 1); + if (!w->per_mb_abt) + ff_msmpeg4_code012(&s->pb, w->abt_type); + } + + if (w->per_mb_rl_bit) + put_bits(&s->pb, 1, ms->per_mb_rl_table); + + if (!ms->per_mb_rl_table) { + ff_msmpeg4_code012(&s->pb, ms->rl_table_index); + ms->rl_chroma_table_index = ms->rl_table_index; + } + put_bits(&s->pb, 1, ms->dc_table_index); + put_bits(&s->pb, 1, ms->mv_table_index); + + s->c.inter_intra_pred = 0; // (s->c.width * s->c.height < 320 * 240 && m->bit_rate <= II_BITRATE); + } + s->esc3_level_length = 0; + ms->esc3_run_length = 0; + + return 0; +} + +/* Nearly identical to wmv1 but that is just because we do not use the + * useless M$ crap features. It is duplicated here in case someone wants + * to add support for these crap features. */ +static void wmv2_encode_mb(MPVEncContext *const s, int16_t block[][64], + int motion_x, int motion_y) +{ + WMV2EncContext *const w = (WMV2EncContext *) s; + int cbp, coded_cbp, i; + int pred_x, pred_y; + uint8_t *coded_block; + + ff_msmpeg4_handle_slices(s); + + if (!s->c.mb_intra) { + /* compute cbp */ + cbp = 0; + for (i = 0; i < 6; i++) + if (s->c.block_last_index[i] >= 0) + cbp |= 1 << (5 - i); + + put_bits(&s->pb, + ff_wmv2_inter_table[w->cbp_table_index][cbp + 64][1], + ff_wmv2_inter_table[w->cbp_table_index][cbp + 64][0]); + + s->misc_bits += get_bits_diff(s); + /* motion vector */ + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); + ff_msmpeg4_encode_motion(&w->msmpeg4, motion_x - pred_x, + motion_y - pred_y); + s->mv_bits += get_bits_diff(s); + } else { + /* compute cbp */ + cbp = 0; + coded_cbp = 0; + for (i = 0; i < 6; i++) { + int val = (s->c.block_last_index[i] >= 1); + + cbp |= val << (5 - i); + if (i < 4) { + /* predict value for close blocks only for luma */ + int pred = ff_msmpeg4_coded_block_pred(&s->c, i, &coded_block); + *coded_block = val; + val = val ^ pred; + } + coded_cbp |= val << (5 - i); + } + + if (s->c.pict_type == AV_PICTURE_TYPE_I) + put_bits(&s->pb, + ff_msmp4_mb_i_table[coded_cbp][1], + ff_msmp4_mb_i_table[coded_cbp][0]); + else + put_bits(&s->pb, + ff_wmv2_inter_table[w->cbp_table_index][cbp][1], + ff_wmv2_inter_table[w->cbp_table_index][cbp][0]); + put_bits(&s->pb, 1, 0); /* no AC prediction yet */ + if (s->c.inter_intra_pred) { + s->c.h263_aic_dir = 0; + put_bits(&s->pb, + ff_table_inter_intra[s->c.h263_aic_dir][1], + ff_table_inter_intra[s->c.h263_aic_dir][0]); + } + s->misc_bits += get_bits_diff(s); + } + + for (i = 0; i < 6; i++) + ff_msmpeg4_encode_block(s, block[i], i); + if (s->c.mb_intra) + s->i_tex_bits += get_bits_diff(s); + else + s->p_tex_bits += get_bits_diff(s); +} + static av_cold int wmv2_encode_init(AVCodecContext *avctx) { WMV2EncContext *const w = avctx->priv_data; - MpegEncContext *const s = &w->msmpeg4.s; + MPVEncContext *const s = &w->msmpeg4.m.s; + int ret; - s->private_ctx = &w->common; - if (ff_mpv_encode_init(avctx) < 0) - return -1; + w->msmpeg4.m.encode_picture_header = wmv2_encode_picture_header; + s->encode_mb = wmv2_encode_mb; - ff_wmv2_common_init(s); + ret = ff_mpv_encode_init(avctx); + if (ret < 0) + return ret; avctx->extradata_size = WMV2_EXTRADATA_SIZE; avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); @@ -94,162 +242,18 @@ static av_cold int wmv2_encode_init(AVCodecContext *avctx) return 0; } -int ff_wmv2_encode_picture_header(MpegEncContext *s) -{ - WMV2EncContext *const w = (WMV2EncContext *) s; - - put_bits(&s->pb, 1, s->pict_type - 1); - if (s->pict_type == AV_PICTURE_TYPE_I) - put_bits(&s->pb, 7, 0); - put_bits(&s->pb, 5, s->qscale); - - s->dc_table_index = 1; - s->mv_table_index = 1; /* only if P-frame */ - s->per_mb_rl_table = 0; - s->mspel = 0; - w->per_mb_abt = 0; - w->abt_type = 0; - w->j_type = 0; - - av_assert0(s->flipflop_rounding); - - if (s->pict_type == AV_PICTURE_TYPE_I) { - av_assert0(s->no_rounding == 1); - if (w->j_type_bit) - put_bits(&s->pb, 1, w->j_type); - - if (w->per_mb_rl_bit) - put_bits(&s->pb, 1, s->per_mb_rl_table); - - if (!s->per_mb_rl_table) { - ff_msmpeg4_code012(&s->pb, s->rl_chroma_table_index); - ff_msmpeg4_code012(&s->pb, s->rl_table_index); - } - - put_bits(&s->pb, 1, s->dc_table_index); - - s->inter_intra_pred = 0; - } else { - int cbp_index; - - put_bits(&s->pb, 2, SKIP_TYPE_NONE); - - ff_msmpeg4_code012(&s->pb, cbp_index = 0); - w->cbp_table_index = wmv2_get_cbp_table_index(s, cbp_index); - - if (w->mspel_bit) - put_bits(&s->pb, 1, s->mspel); - - if (w->abt_flag) { - put_bits(&s->pb, 1, w->per_mb_abt ^ 1); - if (!w->per_mb_abt) - ff_msmpeg4_code012(&s->pb, w->abt_type); - } - - if (w->per_mb_rl_bit) - put_bits(&s->pb, 1, s->per_mb_rl_table); - - if (!s->per_mb_rl_table) { - ff_msmpeg4_code012(&s->pb, s->rl_table_index); - s->rl_chroma_table_index = s->rl_table_index; - } - put_bits(&s->pb, 1, s->dc_table_index); - put_bits(&s->pb, 1, s->mv_table_index); - - s->inter_intra_pred = 0; // (s->width * s->height < 320 * 240 && s->bit_rate <= II_BITRATE); - } - s->esc3_level_length = 0; - s->esc3_run_length = 0; - - return 0; -} - -/* Nearly identical to wmv1 but that is just because we do not use the - * useless M$ crap features. It is duplicated here in case someone wants - * to add support for these crap features. */ -void ff_wmv2_encode_mb(MpegEncContext *s, int16_t block[6][64], - int motion_x, int motion_y) -{ - WMV2EncContext *const w = (WMV2EncContext *) s; - int cbp, coded_cbp, i; - int pred_x, pred_y; - uint8_t *coded_block; - - ff_msmpeg4_handle_slices(s); - - if (!s->mb_intra) { - /* compute cbp */ - cbp = 0; - for (i = 0; i < 6; i++) - if (s->block_last_index[i] >= 0) - cbp |= 1 << (5 - i); - - put_bits(&s->pb, - ff_wmv2_inter_table[w->cbp_table_index][cbp + 64][1], - ff_wmv2_inter_table[w->cbp_table_index][cbp + 64][0]); - - s->misc_bits += get_bits_diff(s); - /* motion vector */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - ff_msmpeg4_encode_motion(s, motion_x - pred_x, - motion_y - pred_y); - s->mv_bits += get_bits_diff(s); - } else { - /* compute cbp */ - cbp = 0; - coded_cbp = 0; - for (i = 0; i < 6; i++) { - int val, pred; - val = (s->block_last_index[i] >= 1); - cbp |= val << (5 - i); - if (i < 4) { - /* predict value for close blocks only for luma */ - pred = ff_msmpeg4_coded_block_pred(s, i, &coded_block); - *coded_block = val; - val = val ^ pred; - } - coded_cbp |= val << (5 - i); - } - - if (s->pict_type == AV_PICTURE_TYPE_I) - put_bits(&s->pb, - ff_msmp4_mb_i_table[coded_cbp][1], - ff_msmp4_mb_i_table[coded_cbp][0]); - else - put_bits(&s->pb, - ff_wmv2_inter_table[w->cbp_table_index][cbp][1], - ff_wmv2_inter_table[w->cbp_table_index][cbp][0]); - put_bits(&s->pb, 1, 0); /* no AC prediction yet */ - if (s->inter_intra_pred) { - s->h263_aic_dir = 0; - put_bits(&s->pb, - ff_table_inter_intra[s->h263_aic_dir][1], - ff_table_inter_intra[s->h263_aic_dir][0]); - } - s->misc_bits += get_bits_diff(s); - } - - for (i = 0; i < 6; i++) - ff_msmpeg4_encode_block(s, block[i], i); - if (s->mb_intra) - s->i_tex_bits += get_bits_diff(s); - else - s->p_tex_bits += get_bits_diff(s); -} - const FFCodec ff_wmv2_encoder = { .p.name = "wmv2", CODEC_LONG_NAME("Windows Media Video 8"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_WMV2, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(WMV2EncContext), .init = wmv2_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .color_ranges = AVCOL_RANGE_MPEG, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), }; diff --git a/libavcodec/x86/Makefile b/libavcodec/x86/Makefile index 331183f45..bf723ed1a 100644 --- a/libavcodec/x86/Makefile +++ b/libavcodec/x86/Makefile @@ -1,94 +1,88 @@ OBJS += x86/constants.o \ # subsystems -OBJS-$(CONFIG_AC3DSP) += x86/ac3dsp_init.o -OBJS-$(CONFIG_AUDIODSP) += x86/audiodsp_init.o -OBJS-$(CONFIG_BLOCKDSP) += x86/blockdsp_init.o -OBJS-$(CONFIG_BSWAPDSP) += x86/bswapdsp_init.o -OBJS-$(CONFIG_DIRAC_DECODER) += x86/diracdsp_init.o \ +X86ASM-OBJS-$(CONFIG_AC3DSP) += x86/ac3dsp_init.o +X86ASM-OBJS-$(CONFIG_AUDIODSP) += x86/audiodsp_init.o +X86ASM-OBJS-$(CONFIG_BLOCKDSP) += x86/blockdsp_init.o +X86ASM-OBJS-$(CONFIG_BSWAPDSP) += x86/bswapdsp_init.o +X86ASM-OBJS-$(CONFIG_DIRAC_DECODER) += x86/diracdsp_init.o \ x86/dirac_dwt_init.o -OBJS-$(CONFIG_FDCTDSP) += x86/fdctdsp_init.o -OBJS-$(CONFIG_FMTCONVERT) += x86/fmtconvert_init.o -OBJS-$(CONFIG_H263DSP) += x86/h263dsp_init.o -OBJS-$(CONFIG_H264CHROMA) += x86/h264chroma_init.o -OBJS-$(CONFIG_H264DSP) += x86/h264dsp_init.o -OBJS-$(CONFIG_H264PRED) += x86/h264_intrapred_init.o -OBJS-$(CONFIG_H264QPEL) += x86/h264_qpel.o -OBJS-$(CONFIG_HPELDSP) += x86/hpeldsp_init.o -OBJS-$(CONFIG_LLAUDDSP) += x86/lossless_audiodsp_init.o -OBJS-$(CONFIG_LLVIDDSP) += x86/lossless_videodsp_init.o +OBJS-$(CONFIG_FDCTDSP) += x86/fdctdsp_init.o x86/fdct.o +X86ASM-OBJS-$(CONFIG_FMTCONVERT) += x86/fmtconvert_init.o +X86ASM-OBJS-$(CONFIG_H263DSP) += x86/h263dsp_init.o +X86ASM-OBJS-$(CONFIG_H264CHROMA) += x86/h264chroma_init.o +X86ASM-OBJS-$(CONFIG_H264DSP) += x86/h264dsp_init.o +X86ASM-OBJS-$(CONFIG_H264PRED) += x86/h264_intrapred_init.o +X86ASM-OBJS-$(CONFIG_H264QPEL) += x86/h264_qpel.o +X86ASM-OBJS-$(CONFIG_HPELDSP) += x86/hpeldsp_init.o +X86ASM-OBJS-$(CONFIG_HUFFYUVDSP) += x86/huffyuvdsp_init.o +X86ASM-OBJS-$(CONFIG_HUFFYUVENCDSP) += x86/huffyuvencdsp_init.o +X86ASM-OBJS-$(CONFIG_IDCTDSP) += x86/idctdsp_init.o +X86ASM-OBJS-$(CONFIG_LLAUDDSP) += x86/lossless_audiodsp_init.o +X86ASM-OBJS-$(CONFIG_LLVIDDSP) += x86/lossless_videodsp_init.o OBJS-$(CONFIG_LLVIDENCDSP) += x86/lossless_videoencdsp_init.o -OBJS-$(CONFIG_HUFFYUVDSP) += x86/huffyuvdsp_init.o -OBJS-$(CONFIG_HUFFYUVENCDSP) += x86/huffyuvencdsp_init.o -OBJS-$(CONFIG_IDCTDSP) += x86/idctdsp_init.o OBJS-$(CONFIG_LPC) += x86/lpc_init.o -OBJS-$(CONFIG_ME_CMP) += x86/me_cmp_init.o +X86ASM-OBJS-$(CONFIG_ME_CMP) += x86/me_cmp_init.o OBJS-$(CONFIG_MPEGAUDIODSP) += x86/mpegaudiodsp.o OBJS-$(CONFIG_MPEGVIDEO) += x86/mpegvideo.o -OBJS-$(CONFIG_MPEGVIDEOENC) += x86/mpegvideoenc.o \ - x86/mpegvideoencdsp_init.o -OBJS-$(CONFIG_PIXBLOCKDSP) += x86/pixblockdsp_init.o -OBJS-$(CONFIG_QPELDSP) += x86/qpeldsp_init.o -OBJS-$(CONFIG_RV34DSP) += x86/rv34dsp_init.o -OBJS-$(CONFIG_VC1DSP) += x86/vc1dsp_init.o -OBJS-$(CONFIG_VIDEODSP) += x86/videodsp_init.o -OBJS-$(CONFIG_VP3DSP) += x86/vp3dsp_init.o -OBJS-$(CONFIG_VP8DSP) += x86/vp8dsp_init.o +OBJS-$(CONFIG_MPEGVIDEOENC) += x86/mpegvideoenc.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += x86/mpegvideoencdsp_init.o +X86ASM-OBJS-$(CONFIG_PIXBLOCKDSP) += x86/pixblockdsp_init.o +X86ASM-OBJS-$(CONFIG_QPELDSP) += x86/qpeldsp_init.o +X86ASM-OBJS-$(CONFIG_RV34DSP) += x86/rv34dsp_init.o +X86ASM-OBJS-$(CONFIG_VC1DSP) += x86/vc1dsp_init.o x86/vc1dsp_mmx.o +X86ASM-OBJS-$(CONFIG_VIDEODSP) += x86/videodsp_init.o +X86ASM-OBJS-$(CONFIG_VP3DSP) += x86/vp3dsp_init.o +X86ASM-OBJS-$(CONFIG_VP8DSP) += x86/vp8dsp_init.o OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o # decoders/encoders -OBJS-$(CONFIG_AAC_DECODER) += x86/aacpsdsp_init.o \ +X86ASM-OBJS-$(CONFIG_AAC_DECODER) += x86/aacpsdsp_init.o \ x86/sbrdsp_init.o -OBJS-$(CONFIG_AAC_ENCODER) += x86/aacencdsp_init.o -OBJS-$(CONFIG_ADPCM_G722_DECODER) += x86/g722dsp_init.o -OBJS-$(CONFIG_ADPCM_G722_ENCODER) += x86/g722dsp_init.o -OBJS-$(CONFIG_ALAC_DECODER) += x86/alacdsp_init.o -OBJS-$(CONFIG_APNG_DECODER) += x86/pngdsp_init.o -OBJS-$(CONFIG_CAVS_DECODER) += x86/cavsdsp.o -OBJS-$(CONFIG_CFHD_DECODER) += x86/cfhddsp_init.o -OBJS-$(CONFIG_CFHD_ENCODER) += x86/cfhdencdsp_init.o -OBJS-$(CONFIG_DCA_DECODER) += x86/dcadsp_init.o x86/synth_filter_init.o -OBJS-$(CONFIG_DNXHD_ENCODER) += x86/dnxhdenc_init.o -OBJS-$(CONFIG_EXR_DECODER) += x86/exrdsp_init.o -OBJS-$(CONFIG_FLAC_DECODER) += x86/flacdsp_init.o -OBJS-$(CONFIG_FLAC_ENCODER) += x86/flacencdsp_init.o -OBJS-$(CONFIG_OPUS_DECODER) += x86/opusdsp_init.o -OBJS-$(CONFIG_OPUS_ENCODER) += x86/celt_pvq_init.o -OBJS-$(CONFIG_HEVC_DECODER) += x86/hevcdsp_init.o x86/h26x/h2656dsp.o -OBJS-$(CONFIG_JPEG2000_DECODER) += x86/jpeg2000dsp_init.o -OBJS-$(CONFIG_LSCR_DECODER) += x86/pngdsp_init.o +X86ASM-OBJS-$(CONFIG_AAC_ENCODER) += x86/aacencdsp_init.o +X86ASM-OBJS-$(CONFIG_ADPCM_G722_DECODER) += x86/g722dsp_init.o +X86ASM-OBJS-$(CONFIG_ADPCM_G722_ENCODER) += x86/g722dsp_init.o +X86ASM-OBJS-$(CONFIG_ALAC_DECODER) += x86/alacdsp_init.o +X86ASM-OBJS-$(CONFIG_APNG_DECODER) += x86/pngdsp_init.o +X86ASM-OBJS-$(CONFIG_APV_DECODER) += x86/apv_dsp_init.o +X86ASM-OBJS-$(CONFIG_CAVS_DECODER) += x86/cavsdsp.o +X86ASM-OBJS-$(CONFIG_CFHD_DECODER) += x86/cfhddsp_init.o +X86ASM-OBJS-$(CONFIG_CFHD_ENCODER) += x86/cfhdencdsp_init.o +X86ASM-OBJS-$(CONFIG_DCA_DECODER) += x86/dcadsp_init.o x86/synth_filter_init.o +X86ASM-OBJS-$(CONFIG_DNXHD_ENCODER) += x86/dnxhdenc_init.o +X86ASM-OBJS-$(CONFIG_EXR_DECODER) += x86/exrdsp_init.o +X86ASM-OBJS-$(CONFIG_FLAC_DECODER) += x86/flacdsp_init.o +X86ASM-OBJS-$(CONFIG_FLAC_ENCODER) += x86/flacencdsp_init.o +X86ASM-OBJS-$(CONFIG_OPUS_DECODER) += x86/opusdsp_init.o +X86ASM-OBJS-$(CONFIG_OPUS_ENCODER) += x86/celt_pvq_init.o +X86ASM-OBJS-$(CONFIG_JPEG2000_DECODER) += x86/jpeg2000dsp_init.o +X86ASM-OBJS-$(CONFIG_LSCR_DECODER) += x86/pngdsp_init.o OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp_init.o -OBJS-$(CONFIG_MPEG4_DECODER) += x86/mpeg4videodsp.o x86/xvididct_init.o -OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp_init.o -OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp_init.o -OBJS-$(CONFIG_RV40_DECODER) += x86/rv40dsp_init.o -OBJS-$(CONFIG_SBC_ENCODER) += x86/sbcdsp_init.o -OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc_init.o -OBJS-$(CONFIG_TAK_DECODER) += x86/takdsp_init.o +OBJS-$(CONFIG_MPEG4_DECODER) += x86/mpeg4videodsp.o +X86ASM-OBJS-$(CONFIG_MPEG4_DECODER) += x86/xvididct_init.o +X86ASM-OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp_init.o +X86ASM-OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp_init.o +X86ASM-OBJS-$(CONFIG_PRORES_RAW_DECODER) += x86/proresdsp_init.o +X86ASM-OBJS-$(CONFIG_RV40_DECODER) += x86/rv40dsp_init.o +X86ASM-OBJS-$(CONFIG_SBC_ENCODER) += x86/sbcdsp_init.o +OBJS-$(CONFIG_SNOW_DECODER) += x86/snowdsp.o +OBJS-$(CONFIG_SNOW_ENCODER) += x86/snowdsp.o +X86ASM-OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc_init.o +X86ASM-OBJS-$(CONFIG_TAK_DECODER) += x86/takdsp_init.o OBJS-$(CONFIG_TRUEHD_DECODER) += x86/mlpdsp_init.o -OBJS-$(CONFIG_TTA_DECODER) += x86/ttadsp_init.o -OBJS-$(CONFIG_TTA_ENCODER) += x86/ttaencdsp_init.o -OBJS-$(CONFIG_UTVIDEO_DECODER) += x86/utvideodsp_init.o -OBJS-$(CONFIG_V210_DECODER) += x86/v210-init.o -OBJS-$(CONFIG_V210_ENCODER) += x86/v210enc_init.o -OBJS-$(CONFIG_VORBIS_DECODER) += x86/vorbisdsp_init.o -OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp_init.o -OBJS-$(CONFIG_VP9_DECODER) += x86/vp9dsp_init.o \ +X86ASM-OBJS-$(CONFIG_TTA_DECODER) += x86/ttadsp_init.o +X86ASM-OBJS-$(CONFIG_TTA_ENCODER) += x86/ttaencdsp_init.o +X86ASM-OBJS-$(CONFIG_UTVIDEO_DECODER) += x86/utvideodsp_init.o +X86ASM-OBJS-$(CONFIG_V210_DECODER) += x86/v210-init.o +X86ASM-OBJS-$(CONFIG_V210_ENCODER) += x86/v210enc_init.o +X86ASM-OBJS-$(CONFIG_VORBIS_DECODER) += x86/vorbisdsp_init.o +X86ASM-OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp_init.o +X86ASM-OBJS-$(CONFIG_VP9_DECODER) += x86/vp9dsp_init.o \ x86/vp9dsp_init_10bpp.o \ x86/vp9dsp_init_12bpp.o \ x86/vp9dsp_init_16bpp.o -OBJS-$(CONFIG_WEBP_DECODER) += x86/vp8dsp_init.o -# GCC inline assembly optimizations -# subsystems -MMX-OBJS-$(CONFIG_FDCTDSP) += x86/fdct.o -MMX-OBJS-$(CONFIG_VC1DSP) += x86/vc1dsp_mmx.o - -# decoders/encoders -MMX-OBJS-$(CONFIG_SNOW_DECODER) += x86/snowdsp.o -MMX-OBJS-$(CONFIG_SNOW_ENCODER) += x86/snowdsp.o - # subsystems X86ASM-OBJS-$(CONFIG_AC3DSP) += x86/ac3dsp.o \ x86/ac3dsp_downmix.o @@ -122,7 +116,7 @@ X86ASM-OBJS-$(CONFIG_LLVIDENCDSP) += x86/lossless_videoencdsp.o X86ASM-OBJS-$(CONFIG_LPC) += x86/lpc.o X86ASM-OBJS-$(CONFIG_ME_CMP) += x86/me_cmp.o X86ASM-OBJS-$(CONFIG_MPEGAUDIODSP) += x86/dct32.o x86/imdct36.o -X86ASM-OBJS-$(CONFIG_MPEGVIDEOENC) += x86/mpegvideoencdsp.o +X86ASM-OBJS-$(CONFIG_MPEGVIDEOENCDSP) += x86/mpegvideoencdsp.o X86ASM-OBJS-$(CONFIG_OPUS_DECODER) += x86/opusdsp.o X86ASM-OBJS-$(CONFIG_OPUS_ENCODER) += x86/celt_pvq_search.o X86ASM-OBJS-$(CONFIG_PIXBLOCKDSP) += x86/pixblockdsp.o @@ -131,7 +125,7 @@ X86ASM-OBJS-$(CONFIG_QPELDSP) += x86/qpeldsp.o \ x86/qpel.o X86ASM-OBJS-$(CONFIG_RV34DSP) += x86/rv34dsp.o X86ASM-OBJS-$(CONFIG_VC1DSP) += x86/vc1dsp_loopfilter.o \ - x86/vc1dsp_mc.o + x86/vc1dsp_mc.o x86/fpel.o ifdef ARCH_X86_64 X86ASM-OBJS-$(CONFIG_IDCTDSP) += x86/simple_idct10.o else @@ -150,7 +144,8 @@ X86ASM-OBJS-$(CONFIG_ADPCM_G722_DECODER) += x86/g722dsp.o X86ASM-OBJS-$(CONFIG_ADPCM_G722_ENCODER) += x86/g722dsp.o X86ASM-OBJS-$(CONFIG_ALAC_DECODER) += x86/alacdsp.o X86ASM-OBJS-$(CONFIG_APNG_DECODER) += x86/pngdsp.o -X86ASM-OBJS-$(CONFIG_CAVS_DECODER) += x86/cavsidct.o +X86ASM-OBJS-$(CONFIG_APV_DECODER) += x86/apv_dsp.o +X86ASM-OBJS-$(CONFIG_CAVS_DECODER) += x86/cavsidct.o x86/cavs_qpel.o X86ASM-OBJS-$(CONFIG_CFHD_ENCODER) += x86/cfhdencdsp.o X86ASM-OBJS-$(CONFIG_CFHD_DECODER) += x86/cfhddsp.o X86ASM-OBJS-$(CONFIG_DCA_DECODER) += x86/dcadsp.o x86/synth_filter.o @@ -162,19 +157,13 @@ X86ASM-OBJS-$(CONFIG_FLAC_DECODER) += x86/flacdsp.o ifdef CONFIG_GPL X86ASM-OBJS-$(CONFIG_FLAC_ENCODER) += x86/flac_dsp_gpl.o endif -X86ASM-OBJS-$(CONFIG_HEVC_DECODER) += x86/hevc_add_res.o \ - x86/hevc_deblock.o \ - x86/hevc_idct.o \ - x86/hevc_mc.o \ - x86/h26x/h2656_inter.o \ - x86/hevc_sao.o \ - x86/hevc_sao_10bit.o X86ASM-OBJS-$(CONFIG_JPEG2000_DECODER) += x86/jpeg2000dsp.o X86ASM-OBJS-$(CONFIG_LSCR_DECODER) += x86/pngdsp.o X86ASM-OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp.o X86ASM-OBJS-$(CONFIG_MPEG4_DECODER) += x86/xvididct.o X86ASM-OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp.o X86ASM-OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp.o +X86ASM-OBJS-$(CONFIG_PRORES_RAW_DECODER) += x86/proresdsp.o X86ASM-OBJS-$(CONFIG_RV40_DECODER) += x86/rv40dsp.o X86ASM-OBJS-$(CONFIG_SBC_ENCODER) += x86/sbcdsp.o X86ASM-OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc.o @@ -190,9 +179,11 @@ X86ASM-OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp.o X86ASM-OBJS-$(CONFIG_VP9_DECODER) += x86/vp9intrapred.o \ x86/vp9intrapred_16bpp.o \ x86/vp9itxfm.o \ + x86/vp9itxfm_avx2.o \ + x86/vp9itxfm_avx512.o \ x86/vp9itxfm_16bpp.o \ + x86/vp9itxfm_16bpp_avx512.o \ x86/vp9lpf.o \ x86/vp9lpf_16bpp.o \ x86/vp9mc.o \ x86/vp9mc_16bpp.o -X86ASM-OBJS-$(CONFIG_WEBP_DECODER) += x86/vp8dsp.o diff --git a/libavcodec/x86/aacpsdsp_init.c b/libavcodec/x86/aacpsdsp_init.c index 0b0ee07db..221fe71bc 100644 --- a/libavcodec/x86/aacpsdsp_init.c +++ b/libavcodec/x86/aacpsdsp_init.c @@ -26,14 +26,14 @@ #include "libavutil/attributes.h" #include "libavcodec/aacpsdsp.h" -void ff_ps_add_squares_sse (float *dst, const float (*src)[2], int n); -void ff_ps_add_squares_sse3 (float *dst, const float (*src)[2], int n); -void ff_ps_mul_pair_single_sse (float (*dst)[2], float (*src0)[2], +void ff_ps_add_squares_sse (float *restrict dst, const float (*src)[2], int n); +void ff_ps_add_squares_sse3 (float *restrict dst, const float (*src)[2], int n); +void ff_ps_mul_pair_single_sse (float (*restrict dst)[2], float (*src0)[2], float *src1, int n); -void ff_ps_hybrid_analysis_sse (float (*out)[2], float (*in)[2], +void ff_ps_hybrid_analysis_sse (float (*restrict out)[2], float (*in)[2], const float (*filter)[8][2], ptrdiff_t stride, int n); -void ff_ps_hybrid_analysis_fma3(float (*out)[2], float (*in)[2], +void ff_ps_hybrid_analysis_fma3(float (*restrict out)[2], float (*in)[2], const float (*filter)[8][2], ptrdiff_t stride, int n); void ff_ps_stereo_interpolate_sse3(float (*l)[2], float (*r)[2], @@ -42,11 +42,11 @@ void ff_ps_stereo_interpolate_sse3(float (*l)[2], float (*r)[2], void ff_ps_stereo_interpolate_ipdopd_sse3(float (*l)[2], float (*r)[2], float h[2][4], float h_step[2][4], int len); -void ff_ps_hybrid_synthesis_deint_sse(float out[2][38][64], float (*in)[32][2], +void ff_ps_hybrid_synthesis_deint_sse(float out[2][38][64], float (*restrict in)[32][2], int i, int len); -void ff_ps_hybrid_synthesis_deint_sse4(float out[2][38][64], float (*in)[32][2], +void ff_ps_hybrid_synthesis_deint_sse4(float out[2][38][64], float (*restrict in)[32][2], int i, int len); -void ff_ps_hybrid_analysis_ileave_sse(float (*out)[32][2], float L[2][38][64], +void ff_ps_hybrid_analysis_ileave_sse(float (*restrict out)[32][2], float L[2][38][64], int i, int len); av_cold void ff_psdsp_init_x86(PSDSPContext *s) diff --git a/libavcodec/x86/alacdsp_init.c b/libavcodec/x86/alacdsp_init.c index 18f7308a1..1b2ff9525 100644 --- a/libavcodec/x86/alacdsp_init.c +++ b/libavcodec/x86/alacdsp_init.c @@ -19,7 +19,6 @@ #include "libavutil/attributes.h" #include "libavutil/x86/cpu.h" #include "libavcodec/alacdsp.h" -#include "config.h" void ff_alac_decorrelate_stereo_sse4(int32_t *buffer[2], int nb_samples, int decorr_shift, int decorr_left_weight); @@ -30,7 +29,6 @@ void ff_alac_append_extra_bits_mono_sse2(int32_t *buffer[2], int32_t *extra_bits av_cold void ff_alacdsp_init_x86(ALACDSPContext *c) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE2(cpu_flags)) { @@ -40,5 +38,4 @@ av_cold void ff_alacdsp_init_x86(ALACDSPContext *c) if (EXTERNAL_SSE4(cpu_flags)) { c->decorrelate_stereo = ff_alac_decorrelate_stereo_sse4; } -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/x86/apv_dsp.asm b/libavcodec/x86/apv_dsp.asm new file mode 100644 index 000000000..e2f30fff1 --- /dev/null +++ b/libavcodec/x86/apv_dsp.asm @@ -0,0 +1,308 @@ +;************************************************************************ +;* 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 +;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +%if ARCH_X86_64 + +SECTION_RODATA 32 + +; Full matrix for row transform. +tmatrix_row: + dw 64, 89, 84, 75, 64, 50, 35, 18 + dw 64, -18, -84, 50, 64, -75, -35, 89 + dw 64, 75, 35, -18, -64, -89, -84, -50 + dw 64, -50, -35, 89, -64, -18, 84, -75 + dw 64, 50, -35, -89, -64, 18, 84, 75 + dw 64, -75, 35, 18, -64, 89, -84, 50 + dw 64, 18, -84, -50, 64, 75, -35, -89 + dw 64, -89, 84, -75, 64, -50, 35, -18 + +; Constant pairs for broadcast in column transform. +tmatrix_col_even: + dw 64, 64, 64, -64 + dw 84, 35, 35, -84 +tmatrix_col_odd: + dw 89, 75, 50, 18 + dw 75, -18, -89, -50 + dw 50, -89, 18, 75 + dw 18, -50, 75, -89 + +; Memory targets for vpbroadcastd (register version requires AVX512). +cextern pd_1 +cextern pd_64 + +SECTION .text + +; void ff_apv_decode_transquant_avx2(void *output, +; ptrdiff_t pitch, +; const int16_t *input, +; const int16_t *qmatrix, +; int bit_depth, +; int qp_shift); + +INIT_YMM avx2 + +cglobal apv_decode_transquant, 5, 7, 16, output, pitch, input, qmatrix, bit_depth, qp_shift, tmp + + ; Load input and dequantise + + vpbroadcastd m10, [pd_1] + lea tmpd, [bit_depthd - 2] + movd xm8, qp_shiftm + movd xm9, tmpd + vpslld m10, m10, xm9 + vpsrld m10, m10, 1 + + ; m8 = scalar qp_shift + ; m9 = scalar bd_shift + ; m10 = vector 1 << (bd_shift - 1) + ; m11 = qmatrix load + +%macro LOAD_AND_DEQUANT 2 ; (xmm input, constant offset) + vpmovsxwd m%1, [inputq + %2] + vpmovsxwd m11, [qmatrixq + %2] + vpmaddwd m%1, m%1, m11 + vpslld m%1, m%1, xm8 + vpaddd m%1, m%1, m10 + vpsrad m%1, m%1, xm9 + vpackssdw m%1, m%1, m%1 +%endmacro + + LOAD_AND_DEQUANT 0, 0x00 + LOAD_AND_DEQUANT 1, 0x10 + LOAD_AND_DEQUANT 2, 0x20 + LOAD_AND_DEQUANT 3, 0x30 + LOAD_AND_DEQUANT 4, 0x40 + LOAD_AND_DEQUANT 5, 0x50 + LOAD_AND_DEQUANT 6, 0x60 + LOAD_AND_DEQUANT 7, 0x70 + + ; mN = row N words 0 1 2 3 0 1 2 3 4 5 6 7 4 5 6 7 + + ; Transform columns + ; This applies a 1-D DCT butterfly + + vpunpcklwd m12, m0, m4 + vpunpcklwd m13, m2, m6 + vpunpcklwd m14, m1, m3 + vpunpcklwd m15, m5, m7 + + ; m12 = rows 0 and 4 interleaved + ; m13 = rows 2 and 6 interleaved + ; m14 = rows 1 and 3 interleaved + ; m15 = rows 5 and 7 interleaved + + lea tmpq, [tmatrix_col_even] + vpbroadcastd m0, [tmpq + 0x00] + vpbroadcastd m1, [tmpq + 0x04] + vpbroadcastd m2, [tmpq + 0x08] + vpbroadcastd m3, [tmpq + 0x0c] + + vpmaddwd m4, m12, m0 + vpmaddwd m5, m12, m1 + vpmaddwd m6, m13, m2 + vpmaddwd m7, m13, m3 + vpaddd m8, m4, m6 + vpaddd m9, m5, m7 + vpsubd m10, m5, m7 + vpsubd m11, m4, m6 + + lea tmpq, [tmatrix_col_odd] + vpbroadcastd m0, [tmpq + 0x00] + vpbroadcastd m1, [tmpq + 0x04] + vpbroadcastd m2, [tmpq + 0x08] + vpbroadcastd m3, [tmpq + 0x0c] + + vpmaddwd m4, m14, m0 + vpmaddwd m5, m15, m1 + vpmaddwd m6, m14, m2 + vpmaddwd m7, m15, m3 + vpaddd m12, m4, m5 + vpaddd m13, m6, m7 + + vpbroadcastd m0, [tmpq + 0x10] + vpbroadcastd m1, [tmpq + 0x14] + vpbroadcastd m2, [tmpq + 0x18] + vpbroadcastd m3, [tmpq + 0x1c] + + vpmaddwd m4, m14, m0 + vpmaddwd m5, m15, m1 + vpmaddwd m6, m14, m2 + vpmaddwd m7, m15, m3 + vpaddd m14, m4, m5 + vpaddd m15, m6, m7 + + vpaddd m0, m8, m12 + vpaddd m1, m9, m13 + vpaddd m2, m10, m14 + vpaddd m3, m11, m15 + vpsubd m4, m11, m15 + vpsubd m5, m10, m14 + vpsubd m6, m9, m13 + vpsubd m7, m8, m12 + + ; Mid-transform normalisation + ; Note that outputs here are fitted to 16 bits + + vpbroadcastd m8, [pd_64] + +%macro NORMALISE 1 + vpaddd m%1, m%1, m8 + vpsrad m%1, m%1, 7 + vpackssdw m%1, m%1, m%1 + vpermq m%1, m%1, q3120 +%endmacro + + NORMALISE 0 + NORMALISE 1 + NORMALISE 2 + NORMALISE 3 + NORMALISE 4 + NORMALISE 5 + NORMALISE 6 + NORMALISE 7 + + ; mN = row N words 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + + ; Transform rows + ; This multiplies the rows directly by the transform matrix, + ; avoiding the need to transpose anything + + lea tmpq, [tmatrix_row] + mova m12, [tmpq + 0x00] + mova m13, [tmpq + 0x20] + mova m14, [tmpq + 0x40] + mova m15, [tmpq + 0x60] + +%macro TRANS_ROW_STEP 1 + vpmaddwd m8, m%1, m12 + vpmaddwd m9, m%1, m13 + vpmaddwd m10, m%1, m14 + vpmaddwd m11, m%1, m15 + vphaddd m8, m8, m9 + vphaddd m10, m10, m11 + vphaddd m%1, m8, m10 +%endmacro + + TRANS_ROW_STEP 0 + TRANS_ROW_STEP 1 + TRANS_ROW_STEP 2 + TRANS_ROW_STEP 3 + TRANS_ROW_STEP 4 + TRANS_ROW_STEP 5 + TRANS_ROW_STEP 6 + TRANS_ROW_STEP 7 + + ; Renormalise, clip and store output + + vpbroadcastd m14, [pd_1] + mov tmpd, 20 + sub tmpd, bit_depthd + movd xm9, tmpd + dec tmpd + movd xm13, tmpd + movd xm15, bit_depthd + vpslld m8, m14, xm13 + vpslld m12, m14, xm15 + vpsrld m10, m12, 1 + vpsubd m12, m12, m14 + vpxor m11, m11, m11 + + ; m8 = vector 1 << (bd_shift - 1) + ; m9 = scalar bd_shift + ; m10 = vector 1 << (bit_depth - 1) + ; m11 = zero + ; m12 = vector (1 << bit_depth) - 1 + + cmp bit_depthd, 8 + jne store_10 + + lea tmpq, [pitchq + 2*pitchq] +%macro NORMALISE_AND_STORE_8 4 + vpaddd m%1, m%1, m8 + vpaddd m%2, m%2, m8 + vpaddd m%3, m%3, m8 + vpaddd m%4, m%4, m8 + vpsrad m%1, m%1, xm9 + vpsrad m%2, m%2, xm9 + vpsrad m%3, m%3, xm9 + vpsrad m%4, m%4, xm9 + vpaddd m%1, m%1, m10 + vpaddd m%2, m%2, m10 + vpaddd m%3, m%3, m10 + vpaddd m%4, m%4, m10 + ; m%1 = A0-3 A4-7 + ; m%2 = B0-3 B4-7 + ; m%3 = C0-3 C4-7 + ; m%4 = D0-3 D4-7 + vpackusdw m%1, m%1, m%2 + vpackusdw m%3, m%3, m%4 + ; m%1 = A0-3 B0-3 A4-7 B4-7 + ; m%2 = C0-3 D0-3 C4-7 D4-7 + vpermq m%1, m%1, q3120 + vpermq m%2, m%3, q3120 + ; m%1 = A0-3 A4-7 B0-3 B4-7 + ; m%2 = C0-3 C4-7 D0-3 D4-7 + vpackuswb m%1, m%1, m%2 + ; m%1 = A0-3 A4-7 C0-3 C4-7 B0-3 B4-7 D0-3 D4-7 + vextracti128 xm%2, m%1, 1 + vmovq [outputq], xm%1 + vmovq [outputq + pitchq], xm%2 + vpextrq [outputq + 2*pitchq], xm%1, 1 + vpextrq [outputq + tmpq], xm%2, 1 + lea outputq, [outputq + 4*pitchq] +%endmacro + + NORMALISE_AND_STORE_8 0, 1, 2, 3 + NORMALISE_AND_STORE_8 4, 5, 6, 7 + + RET + +store_10: + +%macro NORMALISE_AND_STORE_10 2 + vpaddd m%1, m%1, m8 + vpaddd m%2, m%2, m8 + vpsrad m%1, m%1, xm9 + vpsrad m%2, m%2, xm9 + vpaddd m%1, m%1, m10 + vpaddd m%2, m%2, m10 + vpmaxsd m%1, m%1, m11 + vpmaxsd m%2, m%2, m11 + vpminsd m%1, m%1, m12 + vpminsd m%2, m%2, m12 + ; m%1 = A0-3 A4-7 + ; m%2 = B0-3 B4-7 + vpackusdw m%1, m%1, m%2 + ; m%1 = A0-3 B0-3 A4-7 B4-7 + vpermq m%1, m%1, q3120 + ; m%1 = A0-3 A4-7 B0-3 B4-7 + mova [outputq], xm%1 + vextracti128 [outputq + pitchq], m%1, 1 + lea outputq, [outputq + 2*pitchq] +%endmacro + + NORMALISE_AND_STORE_10 0, 1 + NORMALISE_AND_STORE_10 2, 3 + NORMALISE_AND_STORE_10 4, 5 + NORMALISE_AND_STORE_10 6, 7 + + RET + +%endif ; ARCH_X86_64 diff --git a/libavfilter/x86/vf_xpsnr_init.c b/libavcodec/x86/apv_dsp_init.c similarity index 52% rename from libavfilter/x86/vf_xpsnr_init.c rename to libavcodec/x86/apv_dsp_init.c index d33657dcd..39360a0ad 100644 --- a/libavfilter/x86/vf_xpsnr_init.c +++ b/libavcodec/x86/apv_dsp_init.c @@ -1,8 +1,4 @@ /* - * Copyright (c) 2024 Christian R. Helmrich - * Copyright (c) 2024 Christian Lehmann - * Copyright (c) 2024 Christian Stoffers - * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -20,24 +16,29 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * @file - * SIMD initialization for calculation of extended perceptually weighted PSNR (XPSNR). - * - * Authors: Christian Helmrich, Lehmann, and Stoffers, Fraunhofer HHI, Berlin, Germany - */ - +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" -#include "libavfilter/xpsnr.h" +#include "libavcodec/apv_dsp.h" -uint64_t ff_sse_line_16bit_sse2(const uint8_t *buf, const uint8_t *ref, const int w); +#if ARCH_X86_64 -void ff_xpsnr_init_x86(PSNRDSPContext *dsp, const int bpp) +void ff_apv_decode_transquant_avx2(void *output, + ptrdiff_t pitch, + const int16_t *input, + const int16_t *qmatrix, + int bit_depth, + int qp_shift); + +av_cold void ff_apv_dsp_init_x86_64(APVDSPContext *dsp) { - if (bpp <= 15) { /* XPSNR always operates with 16-bit internal precision */ - const int cpu_flags = av_get_cpu_flags(); + int cpu_flags = av_get_cpu_flags(); - if (EXTERNAL_SSE2(cpu_flags)) - dsp->sse_line = ff_sse_line_16bit_sse2; + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + dsp->decode_transquant = ff_apv_decode_transquant_avx2; } } + +#endif /* ARCH_X86_64 */ diff --git a/libavcodec/x86/blockdsp_init.c b/libavcodec/x86/blockdsp_init.c index 37f3bb6a8..a2b362e65 100644 --- a/libavcodec/x86/blockdsp_init.c +++ b/libavcodec/x86/blockdsp_init.c @@ -36,7 +36,6 @@ void ff_fill_block_tab_8_avx2(uint8_t *block, uint8_t value, ptrdiff_t line_size av_cold void ff_blockdsp_init_x86(BlockDSPContext *c) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE(cpu_flags)) { @@ -55,5 +54,4 @@ av_cold void ff_blockdsp_init_x86(BlockDSPContext *c) c->fill_block_tab[0] = ff_fill_block_tab_16_avx2; c->fill_block_tab[1] = ff_fill_block_tab_8_avx2; } -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/x86/bswapdsp.asm b/libavcodec/x86/bswapdsp.asm index 31c6c48a2..06f77c592 100644 --- a/libavcodec/x86/bswapdsp.asm +++ b/libavcodec/x86/bswapdsp.asm @@ -33,11 +33,12 @@ SECTION .text ; %1 = aligned/unaligned %macro BSWAP_LOOPS 1 mov r3d, r2d - sar r2d, 3 - jz .left4_%1 %if cpuflag(avx2) - sar r2d, 1 + sar r3d, 4 jz .left8_%1 +%else + sar r3d, 3 + jz .left4_%1 %endif .loop8_%1: mov%1 m0, [r1 + 0] @@ -65,12 +66,11 @@ SECTION .text %endif add r0, mmsize*2 add r1, mmsize*2 - dec r2d + dec r3d jnz .loop8_%1 %if cpuflag(avx2) .left8_%1: - mov r2d, r3d - test r3d, 8 + test r2d, 8 jz .left4_%1 mov%1 m0, [r1] pshufb m0, m2 @@ -79,8 +79,7 @@ SECTION .text add r0, mmsize %endif .left4_%1: - mov r2d, r3d - test r3d, 4 + test r2d, 4 jz .left mov%1 xm0, [r1] %if cpuflag(ssse3) @@ -101,10 +100,15 @@ SECTION .text ; void ff_bswap_buf(uint32_t *dst, const uint32_t *src, int w); %macro BSWAP32_BUF 0 -%if cpuflag(ssse3)||cpuflag(avx2) +%if cpuflag(avx2) cglobal bswap32_buf, 3,4,3 + vbroadcasti128 m2, [pb_bswap32] + BSWAP_LOOPS u +%else +%if cpuflag(ssse3) +cglobal bswap32_buf, 3,4,3 + mova m2, [pb_bswap32] mov r3, r1 - VBROADCASTI128 m2, [pb_bswap32] %else cglobal bswap32_buf, 3,4,5 mov r3, r1 @@ -116,6 +120,7 @@ cglobal bswap32_buf, 3,4,5 jmp .left .start_align: BSWAP_LOOPS a +%endif .left: %if cpuflag(ssse3) test r2d, 2 diff --git a/libavcodec/x86/cavs_qpel.asm b/libavcodec/x86/cavs_qpel.asm new file mode 100644 index 000000000..4e3444e91 --- /dev/null +++ b/libavcodec/x86/cavs_qpel.asm @@ -0,0 +1,220 @@ +;***************************************************************************** +;* SSE2-optimized CAVS QPEL code +;***************************************************************************** +;* Copyright (c) 2006 Stefan Gehrer +;* based on H.264 optimizations by Michael Niedermayer and Loren Merritt +;* Copyright (c) 2025 Andreas Rheinhardt +;* +;* 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/x86/x86util.asm" + +SECTION_RODATA + +cextern pw_4 +cextern pw_5 +cextern pw_7 +cextern pw_64 +pw_42: times 8 dw 42 +pw_96: times 8 dw 96 + +SECTION .text + +%macro op_avgh 3 + movh %3, %2 + pavgb %1, %3 + movh %2, %1 +%endmacro + +%macro op_puth 2-3 + movh %2, %1 +%endmacro + +%macro CAVS_QPEL_H 1 +; ff_put_cavs_qpel8_mc20(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +cglobal %1_cavs_qpel8_mc20, 3,4,6 + mov r3d, 8 + jmp %1_cavs_qpel8_h_after_prologue + +; ff_put_cavs_qpel8_h(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) +cglobal %1_cavs_qpel8_h, 4,4,6 +%1_cavs_qpel8_h_after_prologue: + mova m3, [pw_4] + mova m4, [pw_5] + pxor m5, m5 +.loop: + movh m0, [r1] + movh m1, [r1+1] + punpcklbw m0, m5 + punpcklbw m1, m5 + paddw m0, m1 + movh m1, [r1-1] + movh m2, [r1+2] + pmullw m0, m4 + punpcklbw m1, m5 + punpcklbw m2, m5 + paddw m0, m3 + add r1, r2 + paddw m1, m2 + psubw m0, m1 + psraw m0, 3 + packuswb m0, m5 + op_%1h m0, [r0], m1 + add r0, r2 + dec r3d + jne .loop + RET +%endmacro + +INIT_XMM sse2 +CAVS_QPEL_H avg +CAVS_QPEL_H put + +%macro FILT_V 1 + movh m3, [r1] + punpcklbw m3, m7 + mova m4, m1 + paddw m4, m2 + paddw m0, m3 + add r1, r2 + pmullw m4, m5 + psubw m4, m0 + paddw m4, m6 + psraw m4, 3 + packuswb m4, m7 + op_%1h m4, [r0], m0 + add r0, r2 + SWAP 0, 1, 2, 3 +%endmacro + +%macro CAVS_QPEL_MC02 1 +; ff_put_cavs_qpel8_mc02(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +cglobal %1_cavs_qpel8_mc02, 3,4,8 + mov r3d, 8 + jmp %1_cavs_qpel8_v2_after_prologue + +; ff_put_cavs_qpel8_v2(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) +cglobal %1_cavs_qpel8_v2, 4,4,8 +%1_cavs_qpel8_v2_after_prologue: + movh m1, [r1] + sub r1, r2 + movh m0, [r1] + lea r1, [r1+2*r2] + pxor m7, m7 + movh m2, [r1] + add r1, r2 + punpcklbw m1, m7 + punpcklbw m0, m7 + punpcklbw m2, m7 + mova m5, [pw_5] + mova m6, [pw_4] +.loop: + FILT_V %1 + FILT_V %1 + FILT_V %1 + FILT_V %1 + sub r3d, 4 + jne .loop + RET +%endmacro + +INIT_XMM sse2 +CAVS_QPEL_MC02 avg +CAVS_QPEL_MC02 put + +%macro FILT_V3 1 + pmullw m0, PW_7 + movh m4, [r1] + mova m5, m1 + mova m6, m2 + pmullw m5, PW_42 + punpcklbw m4, m7 + pmullw m6, PW_96 + paddw m0, m3 + add r1, r2 + paddw m0, m3 + paddw m5, m6 + paddw m0, m4 + ; m5-m0 can be in the -10*255..(42 + 96)*255 range and + ; therefore is not guaranteed to fit into either a signed or + ; an unsigned word. Because we need to clamp the result to 0..255 + ; anyway, we use saturated subtraction and a logical right shift + ; for rescaling. + psubusw m5, m0 + paddw m5, PW_64 + psrlw m5, 7 + packuswb m5, m7 + op_%1h m5, [r0], m0 + add r0, r2 + SWAP 0, 1, 2, 3, 4 +%endmacro + +%macro CAVS_QPEL_MC03 1 +; ff_put_cavs_qpel8_mc03(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +cglobal %1_cavs_qpel8_mc03, 3,4,8+4*ARCH_X86_64 + mov r3d, 8 + jmp %1_cavs_qpel8_v3_after_prologue + +; ff_put_cavs_qpel8_v3(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) +cglobal %1_cavs_qpel8_v3, 4,4,8+4*ARCH_X86_64 +%1_cavs_qpel8_v3_after_prologue: + movh m1, [r1] + movh m2, [r1+r2] + movh m3, [r1+2*r2] + sub r1, r2 + pxor m7, m7 + movh m0, [r1] + lea r1, [r1+4*r2] + punpcklbw m1, m7 + punpcklbw m2, m7 +%if ARCH_X86_64 +%define PW_7 m8 +%define PW_42 m9 +%define PW_96 m10 +%define PW_64 m11 + mova m8, [pw_7] + mova m9, [pw_42] + mova m10, [pw_96] + mova m11, [pw_64] +%else +%define PW_7 [pw_7] +%define PW_42 [pw_42] +%define PW_96 [pw_96] +%define PW_64 [pw_64] +%endif + punpcklbw m3, m7 + punpcklbw m0, m7 + +.loop: + FILT_V3 %1 + FILT_V3 %1 + FILT_V3 %1 + FILT_V3 %1 + SWAP 0, 1, 2, 3, 4 + mova m3, m2 + mova m2, m1 + mova m1, m0 + mova m0, m4 + sub r3d, 4 + jne .loop + RET +%endmacro + +INIT_XMM sse2 +CAVS_QPEL_MC03 avg +CAVS_QPEL_MC03 put diff --git a/libavcodec/x86/cavsdsp.c b/libavcodec/x86/cavsdsp.c index 96680836a..e333bbee4 100644 --- a/libavcodec/x86/cavsdsp.c +++ b/libavcodec/x86/cavsdsp.c @@ -23,14 +23,11 @@ */ #include "libavutil/attributes.h" -#include "libavutil/common.h" #include "libavutil/cpu.h" #include "libavutil/mem_internal.h" -#include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" #include "libavcodec/cavsdsp.h" #include "libavcodec/idctdsp.h" -#include "constants.h" #include "fpel.h" #include "idctdsp.h" #include "config.h" @@ -49,345 +46,78 @@ static void cavs_idct8_add_sse2(uint8_t *dst, int16_t *block, ptrdiff_t stride) #endif /* HAVE_SSE2_EXTERNAL */ -#if HAVE_MMXEXT_INLINE +#if HAVE_SSE2_EXTERNAL +#define DEF_QPEL(OPNAME) \ + void ff_ ## OPNAME ## _cavs_qpel8_mc20_sse2(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ + void ff_ ## OPNAME ## _cavs_qpel8_mc02_sse2(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ + void ff_ ## OPNAME ## _cavs_qpel8_mc03_sse2(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ + void ff_ ## OPNAME ## _cavs_qpel8_h_sse2(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h); \ + void ff_ ## OPNAME ## _cavs_qpel8_v2_sse2(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h);\ + void ff_ ## OPNAME ## _cavs_qpel8_v3_sse2(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h);\ -/***************************************************************************** - * - * motion compensation - * - ****************************************************************************/ +DEF_QPEL(put) +DEF_QPEL(avg) -/* vertical filter [-1 -2 96 42 -7 0] */ -#define QPEL_CAVSV1(A,B,C,D,E,F,OP,ADD, MUL1, MUL2) \ - "movd (%0), "#F" \n\t"\ - "movq "#C", %%mm6 \n\t"\ - "pmullw "MANGLE(MUL1)", %%mm6\n\t"\ - "movq "#D", %%mm7 \n\t"\ - "pmullw "MANGLE(MUL2)", %%mm7\n\t"\ - "psllw $3, "#E" \n\t"\ - "psubw "#E", %%mm6 \n\t"\ - "psraw $3, "#E" \n\t"\ - "paddw %%mm7, %%mm6 \n\t"\ - "paddw "#E", %%mm6 \n\t"\ - "paddw "#B", "#B" \n\t"\ - "pxor %%mm7, %%mm7 \n\t"\ - "add %2, %0 \n\t"\ - "punpcklbw %%mm7, "#F" \n\t"\ - "psubw "#B", %%mm6 \n\t"\ - "psraw $1, "#B" \n\t"\ - "psubw "#A", %%mm6 \n\t"\ - "paddw "MANGLE(ADD)", %%mm6 \n\t"\ - "psraw $7, %%mm6 \n\t"\ - "packuswb %%mm6, %%mm6 \n\t"\ - OP(%%mm6, (%1), A, d) \ - "add %3, %1 \n\t" - -/* vertical filter [ 0 -1 5 5 -1 0] */ -#define QPEL_CAVSV2(A,B,C,D,E,F,OP,ADD, MUL1, MUL2) \ - "movd (%0), "#F" \n\t"\ - "movq "#C", %%mm6 \n\t"\ - "paddw "#D", %%mm6 \n\t"\ - "pmullw "MANGLE(MUL1)", %%mm6\n\t"\ - "add %2, %0 \n\t"\ - "punpcklbw %%mm7, "#F" \n\t"\ - "psubw "#B", %%mm6 \n\t"\ - "psubw "#E", %%mm6 \n\t"\ - "paddw "MANGLE(ADD)", %%mm6 \n\t"\ - "psraw $3, %%mm6 \n\t"\ - "packuswb %%mm6, %%mm6 \n\t"\ - OP(%%mm6, (%1), A, d) \ - "add %3, %1 \n\t" - -/* vertical filter [ 0 -7 42 96 -2 -1] */ -#define QPEL_CAVSV3(A,B,C,D,E,F,OP,ADD, MUL1, MUL2) \ - "movd (%0), "#F" \n\t"\ - "movq "#C", %%mm6 \n\t"\ - "pmullw "MANGLE(MUL2)", %%mm6\n\t"\ - "movq "#D", %%mm7 \n\t"\ - "pmullw "MANGLE(MUL1)", %%mm7\n\t"\ - "psllw $3, "#B" \n\t"\ - "psubw "#B", %%mm6 \n\t"\ - "psraw $3, "#B" \n\t"\ - "paddw %%mm7, %%mm6 \n\t"\ - "paddw "#B", %%mm6 \n\t"\ - "paddw "#E", "#E" \n\t"\ - "pxor %%mm7, %%mm7 \n\t"\ - "add %2, %0 \n\t"\ - "punpcklbw %%mm7, "#F" \n\t"\ - "psubw "#E", %%mm6 \n\t"\ - "psraw $1, "#E" \n\t"\ - "psubw "#F", %%mm6 \n\t"\ - "paddw "MANGLE(ADD)", %%mm6 \n\t"\ - "psraw $7, %%mm6 \n\t"\ - "packuswb %%mm6, %%mm6 \n\t"\ - OP(%%mm6, (%1), A, d) \ - "add %3, %1 \n\t" - - -#define QPEL_CAVSVNUM(VOP,OP,ADD,MUL1,MUL2)\ - int w= 2;\ - src -= 2*srcStride;\ - \ - while(w--){\ - __asm__ volatile(\ - "pxor %%mm7, %%mm7 \n\t"\ - "movd (%0), %%mm0 \n\t"\ - "add %2, %0 \n\t"\ - "movd (%0), %%mm1 \n\t"\ - "add %2, %0 \n\t"\ - "movd (%0), %%mm2 \n\t"\ - "add %2, %0 \n\t"\ - "movd (%0), %%mm3 \n\t"\ - "add %2, %0 \n\t"\ - "movd (%0), %%mm4 \n\t"\ - "add %2, %0 \n\t"\ - "punpcklbw %%mm7, %%mm0 \n\t"\ - "punpcklbw %%mm7, %%mm1 \n\t"\ - "punpcklbw %%mm7, %%mm2 \n\t"\ - "punpcklbw %%mm7, %%mm3 \n\t"\ - "punpcklbw %%mm7, %%mm4 \n\t"\ - VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, ADD, MUL1, MUL2)\ - VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, ADD, MUL1, MUL2)\ - VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, ADD, MUL1, MUL2)\ - VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, ADD, MUL1, MUL2)\ - VOP(%%mm4, %%mm5, %%mm0, %%mm1, %%mm2, %%mm3, OP, ADD, MUL1, MUL2)\ - VOP(%%mm5, %%mm0, %%mm1, %%mm2, %%mm3, %%mm4, OP, ADD, MUL1, MUL2)\ - VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, ADD, MUL1, MUL2)\ - VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, ADD, MUL1, MUL2)\ - \ - : "+a"(src), "+c"(dst)\ - : "S"((x86_reg)srcStride), "r"((x86_reg)dstStride)\ - NAMED_CONSTRAINTS_ADD(ADD,MUL1,MUL2)\ - : "memory"\ - );\ - if(h==16){\ - __asm__ volatile(\ - VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, ADD, MUL1, MUL2)\ - VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, ADD, MUL1, MUL2)\ - VOP(%%mm4, %%mm5, %%mm0, %%mm1, %%mm2, %%mm3, OP, ADD, MUL1, MUL2)\ - VOP(%%mm5, %%mm0, %%mm1, %%mm2, %%mm3, %%mm4, OP, ADD, MUL1, MUL2)\ - VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, ADD, MUL1, MUL2)\ - VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, ADD, MUL1, MUL2)\ - VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, ADD, MUL1, MUL2)\ - VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, ADD, MUL1, MUL2)\ - \ - : "+a"(src), "+c"(dst)\ - : "S"((x86_reg)srcStride), "r"((x86_reg)dstStride)\ - NAMED_CONSTRAINTS_ADD(ADD,MUL1,MUL2)\ - : "memory"\ - );\ - }\ - src += 4-(h+5)*srcStride;\ - dst += 4-h*dstStride;\ - } - -#define QPEL_CAVS(OPNAME, OP, MMX)\ -static void OPNAME ## cavs_qpel8_h_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ -{\ - int h=8;\ - __asm__ volatile(\ - "pxor %%mm7, %%mm7 \n\t"\ - "movq "MANGLE(ff_pw_5)", %%mm6\n\t"\ - "1: \n\t"\ - "movq (%0), %%mm0 \n\t"\ - "movq 1(%0), %%mm2 \n\t"\ - "movq %%mm0, %%mm1 \n\t"\ - "movq %%mm2, %%mm3 \n\t"\ - "punpcklbw %%mm7, %%mm0 \n\t"\ - "punpckhbw %%mm7, %%mm1 \n\t"\ - "punpcklbw %%mm7, %%mm2 \n\t"\ - "punpckhbw %%mm7, %%mm3 \n\t"\ - "paddw %%mm2, %%mm0 \n\t"\ - "paddw %%mm3, %%mm1 \n\t"\ - "pmullw %%mm6, %%mm0 \n\t"\ - "pmullw %%mm6, %%mm1 \n\t"\ - "movq -1(%0), %%mm2 \n\t"\ - "movq 2(%0), %%mm4 \n\t"\ - "movq %%mm2, %%mm3 \n\t"\ - "movq %%mm4, %%mm5 \n\t"\ - "punpcklbw %%mm7, %%mm2 \n\t"\ - "punpckhbw %%mm7, %%mm3 \n\t"\ - "punpcklbw %%mm7, %%mm4 \n\t"\ - "punpckhbw %%mm7, %%mm5 \n\t"\ - "paddw %%mm4, %%mm2 \n\t"\ - "paddw %%mm3, %%mm5 \n\t"\ - "psubw %%mm2, %%mm0 \n\t"\ - "psubw %%mm5, %%mm1 \n\t"\ - "movq "MANGLE(ff_pw_4)", %%mm5\n\t"\ - "paddw %%mm5, %%mm0 \n\t"\ - "paddw %%mm5, %%mm1 \n\t"\ - "psraw $3, %%mm0 \n\t"\ - "psraw $3, %%mm1 \n\t"\ - "packuswb %%mm1, %%mm0 \n\t"\ - OP(%%mm0, (%1),%%mm5, q) \ - "add %3, %0 \n\t"\ - "add %4, %1 \n\t"\ - "decl %2 \n\t"\ - " jnz 1b \n\t"\ - : "+a"(src), "+c"(dst), "+m"(h)\ - : "d"((x86_reg)srcStride), "S"((x86_reg)dstStride)\ - NAMED_CONSTRAINTS_ADD(ff_pw_4,ff_pw_5)\ - : "memory"\ - );\ -}\ -\ -static inline void OPNAME ## cavs_qpel8or16_v1_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)\ -{ \ - QPEL_CAVSVNUM(QPEL_CAVSV1,OP,ff_pw_64,ff_pw_96,ff_pw_42) \ -}\ -\ -static inline void OPNAME ## cavs_qpel8or16_v2_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)\ -{ \ - QPEL_CAVSVNUM(QPEL_CAVSV2,OP,ff_pw_4,ff_pw_5,ff_pw_42) \ -}\ -\ -static inline void OPNAME ## cavs_qpel8or16_v3_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)\ -{ \ - QPEL_CAVSVNUM(QPEL_CAVSV3,OP,ff_pw_64,ff_pw_96,ff_pw_42) \ -}\ -\ -static void OPNAME ## cavs_qpel8_v1_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ -{ \ - OPNAME ## cavs_qpel8or16_v1_ ## MMX(dst , src , dstStride, srcStride, 8);\ -}\ -static void OPNAME ## cavs_qpel16_v1_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ -{ \ - OPNAME ## cavs_qpel8or16_v1_ ## MMX(dst , src , dstStride, srcStride, 16);\ - OPNAME ## cavs_qpel8or16_v1_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\ -}\ -\ -static void OPNAME ## cavs_qpel8_v2_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ -{ \ - OPNAME ## cavs_qpel8or16_v2_ ## MMX(dst , src , dstStride, srcStride, 8);\ -}\ -static void OPNAME ## cavs_qpel16_v2_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ -{ \ - OPNAME ## cavs_qpel8or16_v2_ ## MMX(dst , src , dstStride, srcStride, 16);\ - OPNAME ## cavs_qpel8or16_v2_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\ -}\ -\ -static void OPNAME ## cavs_qpel8_v3_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ -{ \ - OPNAME ## cavs_qpel8or16_v3_ ## MMX(dst , src , dstStride, srcStride, 8);\ -}\ -static void OPNAME ## cavs_qpel16_v3_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ -{ \ - OPNAME ## cavs_qpel8or16_v3_ ## MMX(dst , src , dstStride, srcStride, 16);\ - OPNAME ## cavs_qpel8or16_v3_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\ -}\ -\ -static void OPNAME ## cavs_qpel16_h_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ -{ \ - OPNAME ## cavs_qpel8_h_ ## MMX(dst , src , dstStride, srcStride);\ - OPNAME ## cavs_qpel8_h_ ## MMX(dst+8, src+8, dstStride, srcStride);\ - src += 8*srcStride;\ - dst += 8*dstStride;\ - OPNAME ## cavs_qpel8_h_ ## MMX(dst , src , dstStride, srcStride);\ - OPNAME ## cavs_qpel8_h_ ## MMX(dst+8, src+8, dstStride, srcStride);\ -}\ - -#define CAVS_MC(OPNAME, SIZE, MMX) \ -static void OPNAME ## cavs_qpel ## SIZE ## _mc20_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ -{\ - OPNAME ## cavs_qpel ## SIZE ## _h_ ## MMX(dst, src, stride, stride);\ -}\ -\ -static void OPNAME ## cavs_qpel ## SIZE ## _mc01_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ -{\ - OPNAME ## cavs_qpel ## SIZE ## _v1_ ## MMX(dst, src, stride, stride);\ -}\ -\ -static void OPNAME ## cavs_qpel ## SIZE ## _mc02_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ -{\ - OPNAME ## cavs_qpel ## SIZE ## _v2_ ## MMX(dst, src, stride, stride);\ -}\ -\ -static void OPNAME ## cavs_qpel ## SIZE ## _mc03_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ -{\ - OPNAME ## cavs_qpel ## SIZE ## _v3_ ## MMX(dst, src, stride, stride);\ -}\ - -#define PUT_OP(a,b,temp, size) "mov" #size " " #a ", " #b " \n\t" -#define AVG_MMXEXT_OP(a, b, temp, size) \ -"mov" #size " " #b ", " #temp " \n\t"\ -"pavgb " #temp ", " #a " \n\t"\ -"mov" #size " " #a ", " #b " \n\t" - -#endif /* HAVE_MMXEXT_INLINE */ - -#if HAVE_MMX_EXTERNAL -static void put_cavs_qpel8_mc00_mmx(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - ff_put_pixels8_mmx(dst, src, stride, 8); +#define QPEL_CAVS_XMM(OPNAME, XMM) \ +static void OPNAME ## _cavs_qpel16_mc02_ ## XMM(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) \ +{ \ + ff_ ## OPNAME ## _cavs_qpel8_v2_ ## XMM(dst, src, stride, 16); \ + ff_ ## OPNAME ## _cavs_qpel8_v2_ ## XMM(dst + 8, src + 8, stride, 16); \ +} \ +static void OPNAME ## _cavs_qpel16_mc03_ ## XMM(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) \ +{ \ + ff_ ## OPNAME ## _cavs_qpel8_v3_ ## XMM(dst, src, stride, 16); \ + ff_ ## OPNAME ## _cavs_qpel8_v3_ ## XMM(dst + 8, src + 8, stride, 16); \ +} \ +static void OPNAME ## _cavs_qpel8_mc01_ ## XMM(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) \ +{ \ + ff_ ## OPNAME ## _cavs_qpel8_mc03_ ## XMM(dst + 7 * stride, src + 8 * stride, -stride); \ +} \ +static void OPNAME ## _cavs_qpel16_mc01_ ## XMM(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) \ +{ \ + OPNAME ## _cavs_qpel16_mc03_ ## XMM(dst + 15 * stride, src + 16 * stride, -stride); \ +} \ +static void OPNAME ## _cavs_qpel16_mc20_ ## XMM(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) \ +{ \ + ff_ ## OPNAME ## _cavs_qpel8_h_ ## XMM(dst, src, stride, 16); \ + ff_ ## OPNAME ## _cavs_qpel8_h_ ## XMM(dst + 8, src + 8, stride, 16); \ } -static void avg_cavs_qpel8_mc00_mmxext(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - ff_avg_pixels8_mmxext(dst, src, stride, 8); -} - -static void put_cavs_qpel16_mc00_sse2(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - ff_put_pixels16_sse2(dst, src, stride, 16); -} - -static void avg_cavs_qpel16_mc00_sse2(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - ff_avg_pixels16_sse2(dst, src, stride, 16); -} +QPEL_CAVS_XMM(put, sse2) +QPEL_CAVS_XMM(avg, sse2) #endif -static av_cold void cavsdsp_init_mmx(CAVSDSPContext *c) -{ -#if HAVE_MMX_EXTERNAL - c->put_cavs_qpel_pixels_tab[1][0] = put_cavs_qpel8_mc00_mmx; -#endif /* HAVE_MMX_EXTERNAL */ -} - -#define DSPFUNC(PFX, IDX, NUM, EXT) \ - c->PFX ## _cavs_qpel_pixels_tab[IDX][ 2] = PFX ## _cavs_qpel ## NUM ## _mc20_ ## EXT; \ - c->PFX ## _cavs_qpel_pixels_tab[IDX][ 4] = PFX ## _cavs_qpel ## NUM ## _mc01_ ## EXT; \ - c->PFX ## _cavs_qpel_pixels_tab[IDX][ 8] = PFX ## _cavs_qpel ## NUM ## _mc02_ ## EXT; \ - c->PFX ## _cavs_qpel_pixels_tab[IDX][12] = PFX ## _cavs_qpel ## NUM ## _mc03_ ## EXT; \ - -#if HAVE_MMXEXT_INLINE -QPEL_CAVS(put_, PUT_OP, mmxext) -QPEL_CAVS(avg_, AVG_MMXEXT_OP, mmxext) - -CAVS_MC(put_, 8, mmxext) -CAVS_MC(put_, 16, mmxext) -CAVS_MC(avg_, 8, mmxext) -CAVS_MC(avg_, 16, mmxext) -#endif /* HAVE_MMXEXT_INLINE */ - av_cold void ff_cavsdsp_init_x86(CAVSDSPContext *c) { av_unused int cpu_flags = av_get_cpu_flags(); - if (X86_MMX(cpu_flags)) - cavsdsp_init_mmx(c); - -#if HAVE_MMXEXT_INLINE - if (INLINE_MMXEXT(cpu_flags)) { - DSPFUNC(put, 0, 16, mmxext); - DSPFUNC(put, 1, 8, mmxext); - DSPFUNC(avg, 0, 16, mmxext); - DSPFUNC(avg, 1, 8, mmxext); - } -#endif #if HAVE_MMX_EXTERNAL if (EXTERNAL_MMXEXT(cpu_flags)) { - c->avg_cavs_qpel_pixels_tab[1][0] = avg_cavs_qpel8_mc00_mmxext; + c->avg_cavs_qpel_pixels_tab[1][0] = ff_avg_pixels8x8_mmxext; } #endif #if HAVE_SSE2_EXTERNAL if (EXTERNAL_SSE2(cpu_flags)) { - c->put_cavs_qpel_pixels_tab[0][0] = put_cavs_qpel16_mc00_sse2; - c->avg_cavs_qpel_pixels_tab[0][0] = avg_cavs_qpel16_mc00_sse2; + c->put_cavs_qpel_pixels_tab[0][ 0] = ff_put_pixels16x16_sse2; + c->put_cavs_qpel_pixels_tab[0][ 2] = put_cavs_qpel16_mc20_sse2; + c->put_cavs_qpel_pixels_tab[0][ 4] = put_cavs_qpel16_mc01_sse2; + c->put_cavs_qpel_pixels_tab[0][ 8] = put_cavs_qpel16_mc02_sse2; + c->put_cavs_qpel_pixels_tab[0][12] = put_cavs_qpel16_mc03_sse2; + c->put_cavs_qpel_pixels_tab[1][ 0] = ff_put_pixels8x8_sse2; + c->put_cavs_qpel_pixels_tab[1][ 2] = ff_put_cavs_qpel8_mc20_sse2; + c->put_cavs_qpel_pixels_tab[1][ 4] = put_cavs_qpel8_mc01_sse2; + c->put_cavs_qpel_pixels_tab[1][ 8] = ff_put_cavs_qpel8_mc02_sse2; + c->put_cavs_qpel_pixels_tab[1][12] = ff_put_cavs_qpel8_mc03_sse2; + + c->avg_cavs_qpel_pixels_tab[0][ 0] = ff_avg_pixels16x16_sse2; + c->avg_cavs_qpel_pixels_tab[0][ 2] = avg_cavs_qpel16_mc20_sse2; + c->avg_cavs_qpel_pixels_tab[0][ 4] = avg_cavs_qpel16_mc01_sse2; + c->avg_cavs_qpel_pixels_tab[0][ 8] = avg_cavs_qpel16_mc02_sse2; + c->avg_cavs_qpel_pixels_tab[0][12] = avg_cavs_qpel16_mc03_sse2; + c->avg_cavs_qpel_pixels_tab[1][ 2] = ff_avg_cavs_qpel8_mc20_sse2; + c->avg_cavs_qpel_pixels_tab[1][ 4] = avg_cavs_qpel8_mc01_sse2; + c->avg_cavs_qpel_pixels_tab[1][ 8] = ff_avg_cavs_qpel8_mc02_sse2; + c->avg_cavs_qpel_pixels_tab[1][12] = ff_avg_cavs_qpel8_mc03_sse2; c->cavs_idct8_add = cavs_idct8_add_sse2; c->idct_perm = FF_IDCT_PERM_TRANSPOSE; diff --git a/libavcodec/x86/celt_pvq_search.asm b/libavcodec/x86/celt_pvq_search.asm index 3c6974d37..3e21b7df8 100644 --- a/libavcodec/x86/celt_pvq_search.asm +++ b/libavcodec/x86/celt_pvq_search.asm @@ -104,7 +104,7 @@ align 16 addps m5, m7 ; m5 = Sxy_new = X[i] + Sxy_norm %if USE_APPROXIMATION == 1 - andps m5, m0 ; if(X[i] == 0) Sxy_new = 0; Prevent aproximation error from setting pulses in array padding. + andps m5, m0 ; if(X[i] == 0) Sxy_new = 0; Prevent approximation error from setting pulses in array padding. %endif %else diff --git a/libavcodec/x86/cfhddsp.asm b/libavcodec/x86/cfhddsp.asm index 87c2df634..01ba00f8a 100644 --- a/libavcodec/x86/cfhddsp.asm +++ b/libavcodec/x86/cfhddsp.asm @@ -24,7 +24,6 @@ SECTION_RODATA factor_p1_n1: dw 1, -1, 1, -1, 1, -1, 1, -1, -factor_n1_p1: dw -1, 1, -1, 1, -1, 1, -1, 1, factor_p11_n4: dw 11, -4, 11, -4, 11, -4, 11, -4, factor_p5_p4: dw 5, 4, 5, 4, 5, 4, 5, 4, pd_4: times 4 dd 4 @@ -37,20 +36,20 @@ SECTION .text %macro CFHD_HORIZ_FILTER 1 %if %1 == 1023 -cglobal cfhd_horiz_filter_clip10, 5, 6, 8 + 4 * ARCH_X86_64, output, low, high, width, x, temp +cglobal cfhd_horiz_filter_clip10, 5, 6, 8 + 3 * ARCH_X86_64, output, low, high, width, x, temp shl widthd, 1 %define ostrideq widthq %define lwidthq widthq %define hwidthq widthq %elif %1 == 4095 -cglobal cfhd_horiz_filter_clip12, 5, 6, 8 + 4 * ARCH_X86_64, output, low, high, width, x, temp +cglobal cfhd_horiz_filter_clip12, 5, 6, 8 + 3 * ARCH_X86_64, output, low, high, width, x, temp shl widthd, 1 %define ostrideq widthq %define lwidthq widthq %define hwidthq widthq %else %if ARCH_X86_64 -cglobal cfhd_horiz_filter, 8, 11, 12, output, ostride, low, lwidth, high, hwidth, width, height, x, y, temp +cglobal cfhd_horiz_filter, 8, 11, 11, output, ostride, low, lwidth, high, hwidth, width, height, x, y, temp shl ostrided, 1 shl lwidthd, 1 shl hwidthd, 1 @@ -80,9 +79,8 @@ cglobal cfhd_horiz_filter, 7, 7, 8, output, x, low, y, high, temp, width, height %if ARCH_X86_64 mova m8, [factor_p1_n1] - mova m9, [factor_n1_p1] - mova m10, [pw_1] - mova m11, [pd_4] + mova m9, [pw_1] + mova m10, [pd_4] %endif %if %1 == 0 @@ -144,29 +142,23 @@ cglobal cfhd_horiz_filter, 7, 7, 8, output, x, low, y, high, temp, width, height punpcklwd m4, m1 punpckhwd m5, m1 - mova m6, m4 - mova m7, m5 - %if ARCH_X86_64 pmaddwd m4, m8 pmaddwd m5, m8 - pmaddwd m6, m9 - pmaddwd m7, m9 - paddd m4, m11 - paddd m5, m11 - paddd m6, m11 - paddd m7, m11 + psubd m6, m10, m4 + psubd m7, m10, m5 + paddd m4, m10 + paddd m5, m10 %else + mova m2, [pd_4] pmaddwd m4, [factor_p1_n1] pmaddwd m5, [factor_p1_n1] - pmaddwd m6, [factor_n1_p1] - pmaddwd m7, [factor_n1_p1] - paddd m4, [pd_4] - paddd m5, [pd_4] - paddd m6, [pd_4] - paddd m7, [pd_4] + psubd m6, m2, m4 + psubd m7, m2, m5 + paddd m4, m2 + paddd m5, m2 %endif psrad m4, 3 @@ -185,8 +177,8 @@ cglobal cfhd_horiz_filter, 7, 7, 8, output, x, low, y, high, temp, width, height mova m3, m0 %if ARCH_X86_64 - pmaddwd m2, m10 - pmaddwd m0, m10 + pmaddwd m2, m9 + pmaddwd m0, m9 pmaddwd m1, m8 pmaddwd m3, m8 %else @@ -304,7 +296,7 @@ CFHD_HORIZ_FILTER 4095 INIT_XMM sse2 %if ARCH_X86_64 -cglobal cfhd_vert_filter, 8, 11, 14, output, ostride, low, lwidth, high, hwidth, width, height, x, y, pos +cglobal cfhd_vert_filter, 8, 11, 13, output, ostride, low, lwidth, high, hwidth, width, height, x, y, pos shl ostrided, 1 shl lwidthd, 1 shl hwidthd, 1 @@ -313,11 +305,10 @@ cglobal cfhd_vert_filter, 8, 11, 14, output, ostride, low, lwidth, high, hwidth, dec heightd mova m8, [factor_p1_n1] - mova m9, [factor_n1_p1] - mova m10, [pw_1] - mova m11, [pd_4] - mova m12, [factor_p11_n4] - mova m13, [factor_p5_p4] + mova m9, [pw_1] + mova m10, [pd_4] + mova m11, [factor_p11_n4] + mova m12, [factor_p5_p4] %else cglobal cfhd_vert_filter, 7, 7, 8, output, x, low, y, high, pos, width, height shl xd, 1 @@ -353,8 +344,8 @@ cglobal cfhd_vert_filter, 7, 7, 8, output, x, low, y, high, pos, width, height punpckhwd m2, m1 %if ARCH_X86_64 - pmaddwd m0, m12 - pmaddwd m2, m12 + pmaddwd m0, m11 + pmaddwd m2, m11 %else pmaddwd m0, [factor_p11_n4] pmaddwd m2, [factor_p11_n4] @@ -407,8 +398,8 @@ cglobal cfhd_vert_filter, 7, 7, 8, output, x, low, y, high, pos, width, height punpckhwd m2, m1 %if ARCH_X86_64 - pmaddwd m0, m13 - pmaddwd m2, m13 + pmaddwd m0, m12 + pmaddwd m2, m12 %else pmaddwd m0, [factor_p5_p4] pmaddwd m2, [factor_p5_p4] @@ -471,29 +462,23 @@ cglobal cfhd_vert_filter, 7, 7, 8, output, x, low, y, high, pos, width, height punpcklwd m4, m1 punpckhwd m5, m1 - mova m6, m4 - mova m7, m5 - %if ARCH_X86_64 pmaddwd m4, m8 pmaddwd m5, m8 - pmaddwd m6, m9 - pmaddwd m7, m9 - paddd m4, m11 - paddd m5, m11 - paddd m6, m11 - paddd m7, m11 + psubd m6, m10, m4 + psubd m7, m10, m5 + paddd m4, m10 + paddd m5, m10 %else + mova m2, [pd_4] pmaddwd m4, [factor_p1_n1] pmaddwd m5, [factor_p1_n1] - pmaddwd m6, [factor_n1_p1] - pmaddwd m7, [factor_n1_p1] - paddd m4, [pd_4] - paddd m5, [pd_4] - paddd m6, [pd_4] - paddd m7, [pd_4] + psubd m6, m2, m4 + psubd m7, m2, m5 + paddd m4, m2 + paddd m5, m2 %endif psrad m4, 3 @@ -517,8 +502,8 @@ cglobal cfhd_vert_filter, 7, 7, 8, output, x, low, y, high, pos, width, height mova m3, m2 %if ARCH_X86_64 - pmaddwd m0, m10 - pmaddwd m2, m10 + pmaddwd m0, m9 + pmaddwd m2, m9 pmaddwd m1, m8 pmaddwd m3, m8 %else @@ -565,8 +550,8 @@ cglobal cfhd_vert_filter, 7, 7, 8, output, x, low, y, high, pos, width, height punpckhwd m2, m1 %if ARCH_X86_64 - pmaddwd m0, m13 - pmaddwd m2, m13 + pmaddwd m0, m12 + pmaddwd m2, m12 %else pmaddwd m0, [factor_p5_p4] pmaddwd m2, [factor_p5_p4] @@ -586,8 +571,8 @@ cglobal cfhd_vert_filter, 7, 7, 8, output, x, low, y, high, pos, width, height psubd m2, m3 %if ARCH_X86_64 - paddd m0, m11 - paddd m2, m11 + paddd m0, m10 + paddd m2, m10 %else paddd m0, [pd_4] paddd m2, [pd_4] @@ -633,8 +618,8 @@ cglobal cfhd_vert_filter, 7, 7, 8, output, x, low, y, high, pos, width, height punpckhwd m2, m1 %if ARCH_X86_64 - pmaddwd m0, m12 - pmaddwd m2, m12 + pmaddwd m0, m11 + pmaddwd m2, m11 %else pmaddwd m0, [factor_p11_n4] pmaddwd m2, [factor_p11_n4] @@ -654,8 +639,8 @@ cglobal cfhd_vert_filter, 7, 7, 8, output, x, low, y, high, pos, width, height paddd m2, m3 %if ARCH_X86_64 - paddd m0, m11 - paddd m2, m11 + paddd m0, m10 + paddd m2, m10 %else paddd m0, [pd_4] paddd m2, [pd_4] diff --git a/libavcodec/x86/cfhdencdsp.asm b/libavcodec/x86/cfhdencdsp.asm index 4aaeb5697..f2da8720b 100644 --- a/libavcodec/x86/cfhdencdsp.asm +++ b/libavcodec/x86/cfhdencdsp.asm @@ -24,14 +24,10 @@ SECTION_RODATA pw_p1_n1: dw 1, -1, 1, -1, 1, -1, 1, -1 -pw_n1_p1: dw -1, 1, -1, 1, -1, 1, -1, 1 pw_p5_n11: dw 5, -11, 5, -11, 5, -11, 5, -11 -pw_n5_p11: dw -5, 11, -5, 11, -5, 11, -5, 11 pw_p11_n5: dw 11, -5, 11, -5, 11, -5, 11, -5 -pw_n11_p5: dw -11, 5, -11, 5, -11, 5, -11, 5 pd_4: times 4 dd 4 pw_n4: times 8 dw -4 -cextern pw_m1 cextern pw_1 cextern pw_4 @@ -39,16 +35,17 @@ SECTION .text %if ARCH_X86_64 INIT_XMM sse2 -cglobal cfhdenc_horiz_filter, 8, 10, 11, input, low, high, istride, lwidth, hwidth, width, y, x, temp - shl istrideq, 1 +cglobal cfhdenc_horiz_filter, 6, 10, 11, input, low, high, istride, lwidth, hwidth, width, y, x, temp + movsxdifnidn widthq, widthm shl lwidthq, 1 shl hwidthq, 1 mova m7, [pd_4] mova m8, [pw_1] - mova m9, [pw_m1] + pcmpeqw m9, m9 ; -1 + sub istrideq, widthq + shl istrideq, 1 mova m10,[pw_p1_n1] - movsxdifnidn yq, yd - movsxdifnidn widthq, widthd + movsxdifnidn yq, ym neg yq .looph: movsx xq, word [inputq] @@ -140,8 +137,6 @@ cglobal cfhdenc_horiz_filter, 8, 10, 11, input, low, high, istride, lwidth, hwid cmp xq, widthq jl .loopw - add lowq, widthq - add highq, widthq lea inputq, [inputq + widthq * 2] movsx xq, word [inputq - 4] @@ -151,7 +146,7 @@ cglobal cfhdenc_horiz_filter, 8, 10, 11, input, low, high, istride, lwidth, hwid movd xm0, tempd packssdw m0, m0 movd tempd, m0 - mov word [lowq-2], tempw + mov word [lowq+widthq-2], tempw movsx tempq, word [inputq - 4] imul tempq, 11 @@ -179,12 +174,7 @@ cglobal cfhdenc_horiz_filter, 8, 10, 11, input, low, high, istride, lwidth, hwid movd xm0, tempd packssdw m0, m0 movd tempd, m0 - mov word [highq-2], tempw - - sub inputq, widthq - sub inputq, widthq - sub highq, widthq - sub lowq, widthq + mov word [highq+widthq-2], tempw add lowq, lwidthq add highq, hwidthq @@ -197,7 +187,7 @@ cglobal cfhdenc_horiz_filter, 8, 10, 11, input, low, high, istride, lwidth, hwid %if ARCH_X86_64 INIT_XMM sse2 -cglobal cfhdenc_vert_filter, 8, 11, 14, input, low, high, istride, lwidth, hwidth, width, height, x, y, pos +cglobal cfhdenc_vert_filter, 8, 11, 13, input, low, high, istride, lwidth, hwidth, width, height, x, y, pos shl istrideq, 1 shl widthd, 1 @@ -207,11 +197,10 @@ cglobal cfhdenc_vert_filter, 8, 11, 14, input, low, high, istride, lwidth, hwidt mova m7, [pd_4] mova m8, [pw_1] - mova m9, [pw_m1] + pcmpeqw m9, m9 ; -1 mova m10,[pw_p1_n1] - mova m11,[pw_n1_p1] - mova m12,[pw_4] - mova m13,[pw_n4] + mova m11, [pw_4] + mova m12, [pw_n4] .loopw: mov yq, 2 @@ -238,9 +227,7 @@ cglobal cfhdenc_vert_filter, 8, 11, 14, input, low, high, istride, lwidth, hwidt add posq, istrideq movu m5, [inputq + posq] - mova m6, m0 - punpcklwd m0, m1 - punpckhwd m1, m6 + SBUTTERFLY wd, 0, 1, 6 mova m6, m2 punpcklwd m2, m3 @@ -251,9 +238,9 @@ cglobal cfhdenc_vert_filter, 8, 11, 14, input, low, high, istride, lwidth, hwidt punpckhwd m5, m6 pmaddwd m0, [pw_p5_n11] - pmaddwd m1, [pw_n11_p5] - pmaddwd m2, m12 - pmaddwd m3, m12 + pmaddwd m1, [pw_p5_n11] + pmaddwd m2, m11 + pmaddwd m3, m11 pmaddwd m4, m9 pmaddwd m5, m9 @@ -314,9 +301,7 @@ cglobal cfhdenc_vert_filter, 8, 11, 14, input, low, high, istride, lwidth, hwidt punpcklwd m0, m1 punpckhwd m1, m6 - mova m6, m2 - punpcklwd m2, m3 - punpckhwd m3, m6 + SBUTTERFLY wd, 2, 3, 6 mova m6, m4 punpcklwd m4, m5 @@ -325,7 +310,7 @@ cglobal cfhdenc_vert_filter, 8, 11, 14, input, low, high, istride, lwidth, hwidt pmaddwd m0, m9 pmaddwd m1, m9 pmaddwd m2, m10 - pmaddwd m3, m11 + pmaddwd m3, m10 pmaddwd m4, m8 pmaddwd m5, m8 @@ -395,16 +380,14 @@ cglobal cfhdenc_vert_filter, 8, 11, 14, input, low, high, istride, lwidth, hwidt punpcklwd m2, m3 punpckhwd m3, m6 - mova m6, m4 - punpcklwd m4, m5 - punpckhwd m5, m6 + SBUTTERFLY wd, 4, 5, 6 pmaddwd m0, m8 pmaddwd m1, m8 - pmaddwd m2, m13 - pmaddwd m3, m13 + pmaddwd m2, m12 + pmaddwd m3, m12 pmaddwd m4, [pw_p11_n5] - pmaddwd m5, [pw_n5_p11] + pmaddwd m5, [pw_p11_n5] paddd m4, m2 paddd m5, m3 diff --git a/libavcodec/x86/constants.c b/libavcodec/x86/constants.c index bc7f2b17b..eb01221c8 100644 --- a/libavcodec/x86/constants.c +++ b/libavcodec/x86/constants.c @@ -30,6 +30,7 @@ DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_3) = { 0x0003000300030003ULL, 0 DECLARE_ASM_ALIGNED(32, const ymm_reg, ff_pw_4) = { 0x0004000400040004ULL, 0x0004000400040004ULL, 0x0004000400040004ULL, 0x0004000400040004ULL }; DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_5) = { 0x0005000500050005ULL, 0x0005000500050005ULL }; +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_7) = { 0x0007000700070007ULL, 0x0007000700070007ULL }; DECLARE_ALIGNED(16, const xmm_reg, ff_pw_8) = { 0x0008000800080008ULL, 0x0008000800080008ULL }; DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_9) = { 0x0009000900090009ULL, 0x0009000900090009ULL }; DECLARE_ALIGNED(8, const uint64_t, ff_pw_15) = 0x000F000F000F000FULL; @@ -37,10 +38,8 @@ DECLARE_ALIGNED(16, const xmm_reg, ff_pw_16) = { 0x0010001000100010ULL, 0x001 DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_18) = { 0x0012001200120012ULL, 0x0012001200120012ULL }; DECLARE_ALIGNED(16, const xmm_reg, ff_pw_20) = { 0x0014001400140014ULL, 0x0014001400140014ULL }; DECLARE_ALIGNED(16, const xmm_reg, ff_pw_32) = { 0x0020002000200020ULL, 0x0020002000200020ULL }; -DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_42) = 0x002A002A002A002AULL; DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_53) = 0x0035003500350035ULL; DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_64) = { 0x0040004000400040ULL, 0x0040004000400040ULL }; -DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_96) = 0x0060006000600060ULL; DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_128) = 0x0080008000800080ULL; DECLARE_ALIGNED(32, const ymm_reg, ff_pw_255) = { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL }; @@ -77,7 +76,7 @@ DECLARE_ALIGNED(32, const ymm_reg, ff_pb_80) = { 0x8080808080808080ULL, 0x808 0x8080808080808080ULL, 0x8080808080808080ULL }; DECLARE_ALIGNED(32, const ymm_reg, ff_pb_FE) = { 0xFEFEFEFEFEFEFEFEULL, 0xFEFEFEFEFEFEFEFEULL, 0xFEFEFEFEFEFEFEFEULL, 0xFEFEFEFEFEFEFEFEULL }; -DECLARE_ALIGNED(8, const uint64_t, ff_pb_FC) = 0xFCFCFCFCFCFCFCFCULL; +DECLARE_ALIGNED(16, const xmm_reg, ff_pb_FC) = { 0xFCFCFCFCFCFCFCFCULL, 0xFCFCFCFCFCFCFCFCULL }; DECLARE_ALIGNED(16, const xmm_reg, ff_ps_neg) = { 0x8000000080000000ULL, 0x8000000080000000ULL }; @@ -87,6 +86,8 @@ DECLARE_ALIGNED(32, const ymm_reg, ff_pd_16) = { 0x0000001000000010ULL, 0x000 0x0000001000000010ULL, 0x0000001000000010ULL }; DECLARE_ALIGNED(32, const ymm_reg, ff_pd_32) = { 0x0000002000000020ULL, 0x0000002000000020ULL, 0x0000002000000020ULL, 0x0000002000000020ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pd_64) = { 0x0000004000000040ULL, 0x0000004000000040ULL, + 0x0000004000000040ULL, 0x0000004000000040ULL }; DECLARE_ALIGNED(32, const ymm_reg, ff_pd_8192) = { 0x0000200000002000ULL, 0x0000200000002000ULL, 0x0000200000002000ULL, 0x0000200000002000ULL }; DECLARE_ALIGNED(32, const ymm_reg, ff_pd_65535)= { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, diff --git a/libavcodec/x86/constants.h b/libavcodec/x86/constants.h index 85da38b7b..4c4d32ac8 100644 --- a/libavcodec/x86/constants.h +++ b/libavcodec/x86/constants.h @@ -30,6 +30,7 @@ extern const ymm_reg ff_pw_2; extern const xmm_reg ff_pw_3; extern const ymm_reg ff_pw_4; extern const xmm_reg ff_pw_5; +extern const xmm_reg ff_pw_7; extern const xmm_reg ff_pw_8; extern const xmm_reg ff_pw_9; extern const uint64_t ff_pw_15; @@ -37,10 +38,8 @@ extern const xmm_reg ff_pw_16; extern const xmm_reg ff_pw_18; extern const xmm_reg ff_pw_20; extern const xmm_reg ff_pw_32; -extern const uint64_t ff_pw_42; extern const uint64_t ff_pw_53; extern const xmm_reg ff_pw_64; -extern const uint64_t ff_pw_96; extern const uint64_t ff_pw_128; extern const ymm_reg ff_pw_255; extern const ymm_reg ff_pw_256; @@ -58,14 +57,15 @@ extern const ymm_reg ff_pb_1; extern const ymm_reg ff_pb_2; extern const ymm_reg ff_pb_3; extern const ymm_reg ff_pb_80; +extern const xmm_reg ff_pb_FC; extern const ymm_reg ff_pb_FE; -extern const uint64_t ff_pb_FC; extern const xmm_reg ff_ps_neg; extern const ymm_reg ff_pd_1; extern const ymm_reg ff_pd_16; extern const ymm_reg ff_pd_32; +extern const ymm_reg ff_pd_64; extern const ymm_reg ff_pd_8192; extern const ymm_reg ff_pd_65535; diff --git a/libavcodec/x86/dcadsp_init.c b/libavcodec/x86/dcadsp_init.c index 0c78dd1c9..c01bfffab 100644 --- a/libavcodec/x86/dcadsp_init.c +++ b/libavcodec/x86/dcadsp_init.c @@ -22,9 +22,9 @@ #include "libavcodec/dcadsp.h" #define LFE_FIR_FLOAT_FUNC(opt) \ -void ff_lfe_fir0_float_##opt(float *pcm_samples, int32_t *lfe_samples, \ +void ff_lfe_fir0_float_##opt(float *pcm_samples, const int32_t *lfe_samples, \ const float *filter_coeff, ptrdiff_t npcmblocks); \ -void ff_lfe_fir1_float_##opt(float *pcm_samples, int32_t *lfe_samples, \ +void ff_lfe_fir1_float_##opt(float *pcm_samples, const int32_t *lfe_samples, \ const float *filter_coeff, ptrdiff_t npcmblocks); LFE_FIR_FLOAT_FUNC(sse2) diff --git a/libavcodec/x86/dirac_dwt.asm b/libavcodec/x86/dirac_dwt.asm index 1f3b238ae..83fbb15b1 100644 --- a/libavcodec/x86/dirac_dwt.asm +++ b/libavcodec/x86/dirac_dwt.asm @@ -1,5 +1,5 @@ ;****************************************************************************** -;* x86 optimized discrete wavelet trasnform +;* x86 optimized discrete wavelet transform ;* Copyright (c) 2010 David Conrad ;* ;* This file is part of FFmpeg. @@ -252,7 +252,7 @@ cglobal horizontal_compose_dd97i_ssse3, 3,6,8, b, tmp, w, x, w2, b_w2 jl .lowpass_loop EDGE_EXTENSION 1, 2, xw - ; leave the last up to 7 (sse) or 3 (mmx) values for C + ; leave the last up to 7 (sse) values for C xor xd, xd and w2d, ~(mmsize/2 - 1) cmp w2d, mmsize/2 diff --git a/libavcodec/x86/dirac_dwt_init.c b/libavcodec/x86/dirac_dwt_init.c index 13b42b60c..ecf89342b 100644 --- a/libavcodec/x86/dirac_dwt_init.c +++ b/libavcodec/x86/dirac_dwt_init.c @@ -20,7 +20,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" #include "libavcodec/dirac_dwt.h" @@ -133,10 +132,8 @@ static void horizontal_compose_haar1i##ext(uint8_t *_b, uint8_t *_tmp, int w)\ }\ \ -#if HAVE_X86ASM COMPOSE_VERTICAL(_sse2, 8) - void ff_horizontal_compose_dd97i_ssse3(int16_t *_b, int16_t *_tmp, int w); static void horizontal_compose_dd97i_ssse3(uint8_t *_b, uint8_t *_tmp, int w) @@ -153,11 +150,9 @@ static void horizontal_compose_dd97i_ssse3(uint8_t *_b, uint8_t *_tmp, int w) b[2*x+1] = (COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1)>>1; } } -#endif void ff_spatial_idwt_init_x86(DWTContext *d, enum dwt_type type) { -#if HAVE_X86ASM int mm_flags = av_get_cpu_flags(); if (!(mm_flags & AV_CPU_FLAG_SSE2)) @@ -194,5 +189,4 @@ void ff_spatial_idwt_init_x86(DWTContext *d, enum dwt_type type) d->horizontal_compose = horizontal_compose_dd97i_ssse3; break; } -#endif // HAVE_X86ASM } diff --git a/libavcodec/x86/diracdsp.asm b/libavcodec/x86/diracdsp.asm index e5e2b1184..1844aaf89 100644 --- a/libavcodec/x86/diracdsp.asm +++ b/libavcodec/x86/diracdsp.asm @@ -21,11 +21,11 @@ %include "libavutil/x86/x86util.asm" SECTION_RODATA -pw_7: times 8 dw 7 convert_to_unsigned_10bit: times 4 dd 0x200 clip_10bit: times 8 dw 0x3ff cextern pw_3 +cextern pw_7 cextern pw_16 cextern pw_32 cextern pb_80 @@ -216,8 +216,9 @@ cglobal add_rect_clamped_%1, 7,9,3, dst, src, stride, idwt, idwt_stride, w, h %macro ADD_OBMC 2 ; void add_obmc(uint16_t *dst, uint8_t *src, int stride, uint8_t *obmc_weight, int yblen) -cglobal add_dirac_obmc%1_%2, 6,6,5, dst, src, stride, obmc, yblen +cglobal add_dirac_obmc%1_%2, 5,5,5, dst, src, stride, obmc, yblen pxor m4, m4 + movsxdifnidn strideq, strided .loop: %assign i 0 %rep %1 / mmsize @@ -227,7 +228,7 @@ cglobal add_dirac_obmc%1_%2, 6,6,5, dst, src, stride, obmc, yblen punpckhbw m1, m4 mova m2, [obmcq+i] mova m3, m2 - punpcklbw m2, m4 + punpcklbw m2, m4 punpckhbw m3, m4 pmullw m0, m2 pmullw m1, m3 @@ -247,9 +248,6 @@ cglobal add_dirac_obmc%1_%2, 6,6,5, dst, src, stride, obmc, yblen RET %endm -INIT_MMX -ADD_OBMC 8, mmx - INIT_XMM PUT_RECT sse2 ADD_RECT sse2 @@ -258,6 +256,25 @@ HPEL_FILTER sse2 ADD_OBMC 32, sse2 ADD_OBMC 16, sse2 +cglobal add_dirac_obmc8_sse2, 5,5,4, dst, src, stride, obmc, yblen + pxor m3, m3 + movsxdifnidn strideq, strided +.loop: + movh m0, [srcq] + punpcklbw m0, m3 + movh m1, [obmcq] + punpcklbw m1, m3 + pmullw m0, m1 + movu m1, [dstq] + paddw m0, m1 + movu [dstq], m0 + lea srcq, [srcq+strideq] + lea dstq, [dstq+2*strideq] + add obmcq, 32 + sub yblend, 1 + jg .loop + RET + INIT_XMM sse4 ; void dequant_subband_32(uint8_t *src, uint8_t *dst, ptrdiff_t stride, const int qf, const int qs, int tot_v, int tot_h) diff --git a/libavcodec/x86/diracdsp_init.c b/libavcodec/x86/diracdsp_init.c index f678759dc..4f27e1fc2 100644 --- a/libavcodec/x86/diracdsp_init.c +++ b/libavcodec/x86/diracdsp_init.c @@ -24,8 +24,7 @@ void ff_add_rect_clamped_sse2(uint8_t *, const uint16_t *, int, const int16_t *, int, int, int); -void ff_add_dirac_obmc8_mmx(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); - +void ff_add_dirac_obmc8_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); void ff_add_dirac_obmc16_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); void ff_add_dirac_obmc32_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); @@ -35,8 +34,6 @@ void ff_put_signed_rect_clamped_10_sse4(uint8_t *dst, int dst_stride, const uint void ff_dequant_subband_32_sse4(uint8_t *src, uint8_t *dst, ptrdiff_t stride, const int qf, const int qs, int tot_v, int tot_h); -#if HAVE_X86ASM - #define HPEL_FILTER(MMSIZE, EXT) \ void ff_dirac_hpel_filter_v_ ## EXT(uint8_t *, const uint8_t *, int, int); \ void ff_dirac_hpel_filter_h_ ## EXT(uint8_t *, const uint8_t *, int); \ @@ -57,11 +54,6 @@ void ff_dequant_subband_32_sse4(uint8_t *src, uint8_t *dst, ptrdiff_t stride, co } \ } -#define PIXFUNC(PFX, IDX, EXT) \ - /*MMXDISABLEDc->PFX ## _dirac_pixels_tab[0][IDX] = PFX ## _dirac_pixels8_ ## EXT;*/ \ - c->PFX ## _dirac_pixels_tab[1][IDX] = PFX ## _dirac_pixels16_ ## EXT; \ - c->PFX ## _dirac_pixels_tab[2][IDX] = PFX ## _dirac_pixels32_ ## EXT - #define DIRAC_PIXOP(OPNAME, EXT)\ static void OPNAME ## _dirac_pixels16_ ## EXT(uint8_t *dst, const uint8_t *src[5], \ int stride, int h) \ @@ -87,22 +79,16 @@ DIRAC_PIXOP(avg, sse2) HPEL_FILTER(16, sse2) -#endif // HAVE_X86ASM - void ff_diracdsp_init_x86(DiracDSPContext* c) { -#if HAVE_X86ASM int mm_flags = av_get_cpu_flags(); - if (EXTERNAL_MMX(mm_flags)) { - c->add_dirac_obmc[0] = ff_add_dirac_obmc8_mmx; - } - if (EXTERNAL_SSE2(mm_flags)) { c->dirac_hpel_filter = dirac_hpel_filter_sse2; c->add_rect_clamped = ff_add_rect_clamped_sse2; c->put_signed_rect_clamped[0] = (void *)ff_put_signed_rect_clamped_sse2; + c->add_dirac_obmc[0] = ff_add_dirac_obmc8_sse2; c->add_dirac_obmc[1] = ff_add_dirac_obmc16_sse2; c->add_dirac_obmc[2] = ff_add_dirac_obmc32_sse2; @@ -116,5 +102,4 @@ void ff_diracdsp_init_x86(DiracDSPContext* c) c->dequant_subband[1] = ff_dequant_subband_32_sse4; c->put_signed_rect_clamped[1] = ff_put_signed_rect_clamped_10_sse4; } -#endif } diff --git a/libavcodec/x86/dnxhdenc_init.c b/libavcodec/x86/dnxhdenc_init.c index fd6f15005..3010986b3 100644 --- a/libavcodec/x86/dnxhdenc_init.c +++ b/libavcodec/x86/dnxhdenc_init.c @@ -25,7 +25,7 @@ #include "libavutil/x86/cpu.h" #include "libavcodec/dnxhdenc.h" -void ff_get_pixels_8x4_sym_sse2(int16_t *block, const uint8_t *pixels, +void ff_get_pixels_8x4_sym_sse2(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t line_size); av_cold void ff_dnxhdenc_init_x86(DNXHDEncContext *ctx) diff --git a/libavcodec/x86/fdct.c b/libavcodec/x86/fdct.c index f4677ff4b..065af56a4 100644 --- a/libavcodec/x86/fdct.c +++ b/libavcodec/x86/fdct.c @@ -44,10 +44,6 @@ // constants for the forward DCT // ----------------------------- // -// Be sure to check that your compiler is aligning all constants to QWORD -// (8-byte) memory boundaries! Otherwise the unaligned memory access will -// severely stall MMX execution. -// ////////////////////////////////////////////////////////////////////// #define BITS_FRW_ACC 3 //; 2 or 3 for accuracy diff --git a/libavcodec/x86/fdctdsp_init.c b/libavcodec/x86/fdctdsp_init.c index 92a842433..107912afc 100644 --- a/libavcodec/x86/fdctdsp_init.c +++ b/libavcodec/x86/fdctdsp_init.c @@ -26,6 +26,7 @@ av_cold void ff_fdctdsp_init_x86(FDCTDSPContext *c, AVCodecContext *avctx, unsigned high_bit_depth) { +#if HAVE_SSE2_INLINE int cpu_flags = av_get_cpu_flags(); const int dct_algo = avctx->dct_algo; @@ -35,4 +36,5 @@ av_cold void ff_fdctdsp_init_x86(FDCTDSPContext *c, AVCodecContext *avctx, c->fdct = ff_fdct_sse2; } } +#endif } diff --git a/libavcodec/x86/flacdsp_init.c b/libavcodec/x86/flacdsp_init.c index fa993d346..a2c3829d6 100644 --- a/libavcodec/x86/flacdsp_init.c +++ b/libavcodec/x86/flacdsp_init.c @@ -62,7 +62,6 @@ DECORRELATE_IFUNCS(32, avx); av_cold void ff_flacdsp_init_x86(FLACDSPContext *c, enum AVSampleFormat fmt, int channels) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE2(cpu_flags)) { @@ -85,8 +84,10 @@ av_cold void ff_flacdsp_init_x86(FLACDSPContext *c, enum AVSampleFormat fmt, int c->decorrelate[0] = ff_flac_decorrelate_indep4_16_ssse3; else if (channels == 6) c->decorrelate[0] = ff_flac_decorrelate_indep6_16_ssse3; - else if (ARCH_X86_64 && channels == 8) +#if ARCH_X86_64 + else if (channels == 8) c->decorrelate[0] = ff_flac_decorrelate_indep8_16_ssse3; +#endif } else if (fmt == AV_SAMPLE_FMT_S32) { if (channels == 2) c->decorrelate[0] = ff_flac_decorrelate_indep2_32_ssse3; @@ -94,8 +95,10 @@ av_cold void ff_flacdsp_init_x86(FLACDSPContext *c, enum AVSampleFormat fmt, int c->decorrelate[0] = ff_flac_decorrelate_indep4_32_ssse3; else if (channels == 6) c->decorrelate[0] = ff_flac_decorrelate_indep6_32_ssse3; - else if (ARCH_X86_64 && channels == 8) +#if ARCH_X86_64 + else if (channels == 8) c->decorrelate[0] = ff_flac_decorrelate_indep8_32_ssse3; +#endif } } if (EXTERNAL_SSE4(cpu_flags)) { @@ -105,19 +108,22 @@ av_cold void ff_flacdsp_init_x86(FLACDSPContext *c, enum AVSampleFormat fmt, int } if (EXTERNAL_AVX(cpu_flags)) { if (fmt == AV_SAMPLE_FMT_S16) { - if (ARCH_X86_64 && channels == 8) +#if ARCH_X86_64 + if (channels == 8) c->decorrelate[0] = ff_flac_decorrelate_indep8_16_avx; +#endif } else if (fmt == AV_SAMPLE_FMT_S32) { if (channels == 4) c->decorrelate[0] = ff_flac_decorrelate_indep4_32_avx; else if (channels == 6) c->decorrelate[0] = ff_flac_decorrelate_indep6_32_avx; - else if (ARCH_X86_64 && channels == 8) +#if ARCH_X86_64 + else if (channels == 8) c->decorrelate[0] = ff_flac_decorrelate_indep8_32_avx; +#endif } } if (EXTERNAL_XOP(cpu_flags)) { c->lpc32 = ff_flac_lpc_32_xop; } -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/x86/flacencdsp_init.c b/libavcodec/x86/flacencdsp_init.c index 5ab37e0a8..5b45f009d 100644 --- a/libavcodec/x86/flacencdsp_init.c +++ b/libavcodec/x86/flacencdsp_init.c @@ -27,12 +27,12 @@ void ff_flac_enc_lpc_16_sse4(int32_t *, const int32_t *, int, int, const int32_t av_cold void ff_flacencdsp_init_x86(FLACEncDSPContext *c) { -#if HAVE_X86ASM && CONFIG_GPL +#if CONFIG_GPL int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE4(cpu_flags)) { if (CONFIG_GPL) c->lpc16_encode = ff_flac_enc_lpc_16_sse4; } -#endif /* HAVE_X86ASM */ +#endif /* CONFIG_GPL */ } diff --git a/libavcodec/x86/fmtconvert_init.c b/libavcodec/x86/fmtconvert_init.c index acbc33456..6cf3a807a 100644 --- a/libavcodec/x86/fmtconvert_init.c +++ b/libavcodec/x86/fmtconvert_init.c @@ -27,22 +27,16 @@ #include "libavutil/x86/cpu.h" #include "libavcodec/fmtconvert.h" -#if HAVE_X86ASM - void ff_int32_to_float_fmul_scalar_sse2(float *dst, const int32_t *src, float mul, int len); void ff_int32_to_float_fmul_array8_sse2(FmtConvertContext *c, float *dst, const int32_t *src, const float *mul, int len); -#endif /* HAVE_X86ASM */ - av_cold void ff_fmt_convert_init_x86(FmtConvertContext *c) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE2(cpu_flags)) { c->int32_to_float_fmul_scalar = ff_int32_to_float_fmul_scalar_sse2; c->int32_to_float_fmul_array8 = ff_int32_to_float_fmul_array8_sse2; } -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/x86/fpel.asm b/libavcodec/x86/fpel.asm index b07b78907..e4becca5f 100644 --- a/libavcodec/x86/fpel.asm +++ b/libavcodec/x86/fpel.asm @@ -27,37 +27,48 @@ SECTION .text ; void ff_put/avg_pixels(uint8_t *block, const uint8_t *pixels, ; ptrdiff_t line_size, int h) -%macro OP_PIXELS 2 +%macro OP_PIXELS 2-3 0 %if %2 == mmsize/2 %define LOAD movh %define SAVE movh -%define LEN mmsize %else %define LOAD movu %define SAVE mova -%define LEN %2 %endif -cglobal %1_pixels%2, 4,5,4 +cglobal %1_pixels%2x%2, 3,5+4*%3,%3 ? 4 : 0 + mov r3d, %2 + jmp %1_pixels%2_after_prologue + +cglobal %1_pixels%2, 4,5+4*%3,%3 ? 4 : 0 +%1_pixels%2_after_prologue: lea r4, [r2*3] .loop: -%assign %%i 0 -%rep LEN/mmsize - LOAD m0, [r1 + %%i] - LOAD m1, [r1+r2 + %%i] - LOAD m2, [r1+r2*2 + %%i] - LOAD m3, [r1+r4 + %%i] +%if %3 +; Use GPRs on UNIX64 for put8, but not on Win64 due to a lack of volatile GPRs + mov r5q, [r1] + mov r6q, [r1+r2] + mov r7q, [r1+r2*2] + mov r8q, [r1+r4] + mov [r0], r5q + mov [r0+r2], r6q + mov [r0+r2*2], r7q + mov [r0+r4], r8q +%else + LOAD m0, [r1] + LOAD m1, [r1+r2] + LOAD m2, [r1+r2*2] + LOAD m3, [r1+r4] %ifidn %1, avg - pavgb m0, [r0 + %%i] - pavgb m1, [r0+r2 + %%i] - pavgb m2, [r0+r2*2 + %%i] - pavgb m3, [r0+r4 + %%i] + pavgb m0, [r0] + pavgb m1, [r0+r2] + pavgb m2, [r0+r2*2] + pavgb m3, [r0+r4] +%endif + SAVE [r0], m0 + SAVE [r0+r2], m1 + SAVE [r0+r2*2], m2 + SAVE [r0+r4], m3 %endif - SAVE [r0 + %%i], m0 - SAVE [r0+r2 + %%i], m1 - SAVE [r0+r2*2 + %%i], m2 - SAVE [r0+r4 + %%i], m3 -%assign %%i %%i+mmsize -%endrep sub r3d, 4 lea r1, [r1+r2*4] lea r0, [r0+r2*4] @@ -65,15 +76,10 @@ cglobal %1_pixels%2, 4,5,4 RET %endmacro -INIT_MMX mmx -OP_PIXELS put, 8 -OP_PIXELS put, 16 - INIT_MMX mmxext -OP_PIXELS avg, 4 OP_PIXELS avg, 8 -OP_PIXELS avg, 16 INIT_XMM sse2 +OP_PIXELS put, 8, UNIX64 OP_PIXELS put, 16 OP_PIXELS avg, 16 diff --git a/libavcodec/x86/fpel.h b/libavcodec/x86/fpel.h index 47ffc8eec..0b0056021 100644 --- a/libavcodec/x86/fpel.h +++ b/libavcodec/x86/fpel.h @@ -22,20 +22,22 @@ #include #include -void ff_avg_pixels4_mmxext(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h); void ff_avg_pixels8_mmxext(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); -void ff_avg_pixels16_mmxext(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h); +void ff_avg_pixels8x8_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size); void ff_avg_pixels16_sse2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); -void ff_put_pixels8_mmx(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h); -void ff_put_pixels16_mmx(uint8_t *block, const uint8_t *pixels, +void ff_avg_pixels16x16_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size); +void ff_put_pixels8_sse2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); +void ff_put_pixels8x8_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size); void ff_put_pixels16_sse2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); +void ff_put_pixels16x16_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size); #endif /* AVCODEC_X86_FPEL_H */ diff --git a/libavcodec/x86/h263_loopfilter.asm b/libavcodec/x86/h263_loopfilter.asm index 77c8cf154..ebe76f01a 100644 --- a/libavcodec/x86/h263_loopfilter.asm +++ b/libavcodec/x86/h263_loopfilter.asm @@ -1,5 +1,5 @@ ;****************************************************************************** -;* MMX-optimized H.263 loop filter +;* SSE2-optimized H.263 loop filter ;* Copyright (c) 2003-2013 Michael Niedermayer ;* Copyright (c) 2013 Daniel Kang ;* @@ -22,7 +22,6 @@ %include "libavutil/x86/x86util.asm" -SECTION_RODATA cextern pb_FC cextern h263_loop_filter_strength @@ -30,60 +29,45 @@ SECTION .text %macro H263_LOOP_FILTER 5 pxor m7, m7 - mova m0, [%1] - mova m1, [%1] - mova m2, [%4] - mova m3, [%4] + movq m0, [%1] + movq m6, [%4] + mova m5, m0 punpcklbw m0, m7 - punpckhbw m1, m7 + punpcklbw m6, m7 + psubw m0, m6 + movq m2, [%2] + movq m1, [%3] + mova m3, m2 + mova m4, m1 punpcklbw m2, m7 - punpckhbw m3, m7 - psubw m0, m2 - psubw m1, m3 - mova m2, [%2] - mova m3, [%2] - mova m4, [%3] - mova m5, [%3] - punpcklbw m2, m7 - punpckhbw m3, m7 - punpcklbw m4, m7 - punpckhbw m5, m7 - psubw m4, m2 - psubw m5, m3 - psllw m4, 2 - psllw m5, 2 - paddw m4, m0 - paddw m5, m1 + punpcklbw m1, m7 + psubw m1, m2 + psllw m1, 2 + paddw m1, m0 pxor m6, m6 - pcmpgtw m6, m4 - pcmpgtw m7, m5 - pxor m4, m6 - pxor m5, m7 - psubw m4, m6 - psubw m5, m7 - psrlw m4, 3 - psrlw m5, 3 - packuswb m4, m5 + pcmpgtw m6, m1 + pxor m1, m6 + psubw m1, m6 + psrlw m1, 3 + packuswb m1, m7 packsswb m6, m7 - pxor m7, m7 movd m2, %5 punpcklbw m2, m2 punpcklbw m2, m2 punpcklbw m2, m2 - psubusb m2, m4 - mova m3, m2 - psubusb m3, m4 - psubb m2, m3 - mova m3, [%2] - mova m4, [%3] + psubusb m2, m1 + mova m7, m2 + psubusb m7, m1 + psubb m2, m7 pxor m3, m6 pxor m4, m6 paddusb m3, m2 psubusb m4, m2 + pxor m7, m7 pxor m3, m6 pxor m4, m6 paddusb m2, m2 - packsswb m0, m1 + packsswb m0, m7 pcmpgtb m7, m0 pxor m0, m7 psubb m0, m7 @@ -94,22 +78,20 @@ SECTION .text psrlw m1, 2 pxor m1, m7 psubb m1, m7 - mova m5, [%1] - mova m6, [%4] + movq m6, [%4] psubb m5, m1 paddb m6, m1 %endmacro -INIT_MMX mmx -; void ff_h263_v_loop_filter_mmx(uint8_t *src, int stride, int qscale) -cglobal h263_v_loop_filter, 3,5 +INIT_XMM sse2 +; void ff_h263_v_loop_filter_sse2(uint8_t *src, int stride, int qscale) +cglobal h263_v_loop_filter, 3,5,8 movsxdifnidn r1, r1d movsxdifnidn r2, r2d - lea r4, [h263_loop_filter_strength] - movzx r3d, BYTE [r4+r2] - movsx r2, r3b - shl r2, 1 + lea r3, [h263_loop_filter_strength] + movzx r2d, BYTE [r3+r2] + shl r2d, 1 mov r3, r0 sub r3, r1 @@ -117,73 +99,64 @@ cglobal h263_v_loop_filter, 3,5 sub r4, r1 H263_LOOP_FILTER r4, r3, r0, r0+r1, r2d - mova [r3], m3 - mova [r0], m4 - mova [r4], m5 - mova [r0+r1], m6 + movq [r3], m3 + movq [r0], m4 + movq [r4], m5 + movq [r0+r1], m6 RET %macro TRANSPOSE4X4 2 - movd m0, [%1] - movd m1, [%1+r1] - movd m2, [%1+r1*2] - movd m3, [%1+r3] - punpcklbw m0, m1 - punpcklbw m2, m3 - mova m1, m0 - punpcklwd m0, m2 - punpckhwd m1, m2 - movd [%2+ 0], m0 - punpckhdq m0, m0 - movd [%2+ 8], m0 - movd [%2+16], m1 - punpckhdq m1, m1 - movd [%2+24], m1 + movd %1, [%2] + movd m2, [%2+r1] + movd m3, [%2+r1*2] + movd m4, [%2+r3] + punpcklbw %1, m2 + punpcklbw m3, m4 + punpcklwd %1, m3 %endmacro -; void ff_h263_h_loop_filter_mmx(uint8_t *src, int stride, int qscale) -INIT_MMX mmx -cglobal h263_h_loop_filter, 3,5,0,32 +; void ff_h263_h_loop_filter_sse2(uint8_t *src, int stride, int qscale) +INIT_XMM sse2 +cglobal h263_h_loop_filter, 3,5,8,32 movsxdifnidn r1, r1d movsxdifnidn r2, r2d lea r4, [h263_loop_filter_strength] - movzx r3d, BYTE [r4+r2] - movsx r2, r3b - shl r2, 1 + movzx r2d, BYTE [r4+r2] + shl r2d, 1 sub r0, 2 lea r3, [r1*3] - - TRANSPOSE4X4 r0, rsp lea r4, [r0+r1*4] - TRANSPOSE4X4 r4, rsp+4 + + TRANSPOSE4X4 m0, r0 + TRANSPOSE4X4 m1, r4 + mova m2, m0 + punpckldq m0, m1 + mova [rsp], m0 + punpckhdq m2, m1 + mova [rsp+16], m2 H263_LOOP_FILTER rsp, rsp+8, rsp+16, rsp+24, r2d - mova m1, m5 - mova m0, m4 punpcklbw m5, m3 punpcklbw m4, m6 - punpckhbw m1, m3 - punpckhbw m0, m6 - mova m3, m5 - mova m6, m1 + mova m0, m5 punpcklwd m5, m4 - punpcklwd m1, m0 - punpckhwd m3, m4 - punpckhwd m6, m0 + punpckhwd m0, m4 movd [r0], m5 + movd [r4], m0 + pshufd m1, m5, 0x1 + pshufd m2, m0, 0x1 + movd [r0+r1*1], m1 + movd [r4+r1*1], m2 punpckhdq m5, m5 - movd [r0+r1*1], m5 - movd [r0+r1*2], m3 - punpckhdq m3, m3 - movd [r0+r3], m3 - movd [r4], m1 - punpckhdq m1, m1 - movd [r4+r1*1], m1 - movd [r4+r1*2], m6 - punpckhdq m6, m6 - movd [r4+r3], m6 + punpckhdq m0, m0 + movd [r0+r1*2], m5 + movd [r4+r1*2], m0 + punpckhdq m5, m5 + punpckhdq m0, m0 + movd [r0+r3], m5 + movd [r4+r3], m0 RET diff --git a/libavcodec/x86/h263dsp_init.c b/libavcodec/x86/h263dsp_init.c index ab8106323..3dd5d132e 100644 --- a/libavcodec/x86/h263dsp_init.c +++ b/libavcodec/x86/h263dsp_init.c @@ -25,15 +25,15 @@ #include "libavutil/x86/cpu.h" #include "libavcodec/h263dsp.h" -void ff_h263_h_loop_filter_mmx(uint8_t *src, int stride, int qscale); -void ff_h263_v_loop_filter_mmx(uint8_t *src, int stride, int qscale); +void ff_h263_h_loop_filter_sse2(uint8_t *src, int stride, int qscale); +void ff_h263_v_loop_filter_sse2(uint8_t *src, int stride, int qscale); av_cold void ff_h263dsp_init_x86(H263DSPContext *c) { int cpu_flags = av_get_cpu_flags(); - if (EXTERNAL_MMX(cpu_flags)) { - c->h263_h_loop_filter = ff_h263_h_loop_filter_mmx; - c->h263_v_loop_filter = ff_h263_v_loop_filter_mmx; + if (EXTERNAL_SSE2(cpu_flags)) { + c->h263_h_loop_filter = ff_h263_h_loop_filter_sse2; + c->h263_v_loop_filter = ff_h263_v_loop_filter_sse2; } } diff --git a/libavcodec/x86/h264_chromamc.asm b/libavcodec/x86/h264_chromamc.asm index ec6288d48..7c896db17 100644 --- a/libavcodec/x86/h264_chromamc.asm +++ b/libavcodec/x86/h264_chromamc.asm @@ -20,43 +20,11 @@ ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ;****************************************************************************** +%include "config_components.asm" %include "libavutil/x86/x86util.asm" SECTION_RODATA -rnd_rv40_2d_tbl: times 4 dw 0 - times 4 dw 16 - times 4 dw 32 - times 4 dw 16 - times 4 dw 32 - times 4 dw 28 - times 4 dw 32 - times 4 dw 28 - times 4 dw 0 - times 4 dw 32 - times 4 dw 16 - times 4 dw 32 - times 4 dw 32 - times 4 dw 28 - times 4 dw 32 - times 4 dw 28 -rnd_rv40_1d_tbl: times 4 dw 0 - times 4 dw 2 - times 4 dw 4 - times 4 dw 2 - times 4 dw 4 - times 4 dw 3 - times 4 dw 4 - times 4 dw 3 - times 4 dw 0 - times 4 dw 4 - times 4 dw 2 - times 4 dw 4 - times 4 dw 4 - times 4 dw 3 - times 4 dw 4 - times 4 dw 3 - cextern pw_3 cextern pw_4 cextern pw_8 @@ -64,6 +32,8 @@ pw_28: times 8 dw 28 cextern pw_32 cextern pw_64 +cextern rv40_bias + SECTION .text %macro mv0_pixels_mc8 0 @@ -89,285 +59,6 @@ SECTION .text jne .next4rows %endmacro -%macro chroma_mc8_mmx_func 2-3 -%ifidn %2, rv40 -%if PIC -%define rnd_1d_rv40 r8 -%define rnd_2d_rv40 r8 -%define extra_regs 2 -%else ; no-PIC -%define rnd_1d_rv40 rnd_rv40_1d_tbl -%define rnd_2d_rv40 rnd_rv40_2d_tbl -%define extra_regs 1 -%endif ; PIC -%else -%define extra_regs 0 -%endif ; rv40 -; void ff_put/avg_h264_chroma_mc8_*(uint8_t *dst /* align 8 */, -; const uint8_t *src /* align 1 */, -; ptrdiff_t stride, int h, int mx, int my) -cglobal %1_%2_chroma_mc8%3, 6, 7 + extra_regs, 0 - mov r6d, r5d - or r6d, r4d - jne .at_least_one_non_zero - ; mx == 0 AND my == 0 - no filter needed - mv0_pixels_mc8 - RET - -.at_least_one_non_zero: -%ifidn %2, rv40 -%if ARCH_X86_64 - mov r7, r5 - and r7, 6 ; &~1 for mx/my=[0,7] - lea r7, [r7*4+r4] - sar r7d, 1 -%define rnd_bias r7 -%define dest_reg r0 -%else ; x86-32 - mov r0, r5 - and r0, 6 ; &~1 for mx/my=[0,7] - lea r0, [r0*4+r4] - sar r0d, 1 -%define rnd_bias r0 -%define dest_reg r5 -%endif -%else ; vc1, h264 -%define rnd_bias 0 -%define dest_reg r0 -%endif - - test r5d, r5d - mov r6, 1 - je .my_is_zero - test r4d, r4d - mov r6, r2 ; dxy = x ? 1 : stride - jne .both_non_zero -.my_is_zero: - ; mx == 0 XOR my == 0 - 1 dimensional filter only - or r4d, r5d ; x + y - -%ifidn %2, rv40 -%if PIC - lea r8, [rnd_rv40_1d_tbl] -%endif -%if ARCH_X86_64 == 0 - mov r5, r0m -%endif -%endif - - movd m5, r4d - movq m4, [pw_8] - movq m6, [rnd_1d_%2+rnd_bias*8] ; mm6 = rnd >> 3 - punpcklwd m5, m5 - punpckldq m5, m5 ; mm5 = B = x - pxor m7, m7 - psubw m4, m5 ; mm4 = A = 8-x - -.next1drow: - movq m0, [r1 ] ; mm0 = src[0..7] - movq m2, [r1+r6] ; mm1 = src[1..8] - - movq m1, m0 - movq m3, m2 - punpcklbw m0, m7 - punpckhbw m1, m7 - punpcklbw m2, m7 - punpckhbw m3, m7 - pmullw m0, m4 ; [mm0,mm1] = A * src[0..7] - pmullw m1, m4 - pmullw m2, m5 ; [mm2,mm3] = B * src[1..8] - pmullw m3, m5 - - paddw m0, m6 - paddw m1, m6 - paddw m0, m2 - paddw m1, m3 - psrlw m0, 3 - psrlw m1, 3 - packuswb m0, m1 - CHROMAMC_AVG m0, [dest_reg] - movq [dest_reg], m0 ; dst[0..7] = (A * src[0..7] + B * src[1..8] + (rnd >> 3)) >> 3 - - add dest_reg, r2 - add r1, r2 - dec r3d - jne .next1drow - RET - -.both_non_zero: ; general case, bilinear - movd m4, r4d ; x - movd m6, r5d ; y -%ifidn %2, rv40 -%if PIC - lea r8, [rnd_rv40_2d_tbl] -%endif -%if ARCH_X86_64 == 0 - mov r5, r0m -%endif -%endif - mov r6, rsp ; backup stack pointer - and rsp, ~(mmsize-1) ; align stack - sub rsp, 16 ; AA and DD - - punpcklwd m4, m4 - punpcklwd m6, m6 - punpckldq m4, m4 ; mm4 = x words - punpckldq m6, m6 ; mm6 = y words - movq m5, m4 - pmullw m4, m6 ; mm4 = x * y - psllw m5, 3 - psllw m6, 3 - movq m7, m5 - paddw m7, m6 - movq [rsp+8], m4 ; DD = x * y - psubw m5, m4 ; mm5 = B = 8x - xy - psubw m6, m4 ; mm6 = C = 8y - xy - paddw m4, [pw_64] - psubw m4, m7 ; mm4 = A = xy - (8x+8y) + 64 - pxor m7, m7 - movq [rsp ], m4 - - movq m0, [r1 ] ; mm0 = src[0..7] - movq m1, [r1+1] ; mm1 = src[1..8] -.next2drow: - add r1, r2 - - movq m2, m0 - movq m3, m1 - punpckhbw m0, m7 - punpcklbw m1, m7 - punpcklbw m2, m7 - punpckhbw m3, m7 - pmullw m0, [rsp] - pmullw m2, [rsp] - pmullw m1, m5 - pmullw m3, m5 - paddw m2, m1 ; mm2 = A * src[0..3] + B * src[1..4] - paddw m3, m0 ; mm3 = A * src[4..7] + B * src[5..8] - - movq m0, [r1] - movq m1, m0 - punpcklbw m0, m7 - punpckhbw m1, m7 - pmullw m0, m6 - pmullw m1, m6 - paddw m2, m0 - paddw m3, m1 ; [mm2,mm3] += C * src[0..7] - - movq m1, [r1+1] - movq m0, m1 - movq m4, m1 - punpcklbw m0, m7 - punpckhbw m4, m7 - pmullw m0, [rsp+8] - pmullw m4, [rsp+8] - paddw m2, m0 - paddw m3, m4 ; [mm2,mm3] += D * src[1..8] - movq m0, [r1] - - paddw m2, [rnd_2d_%2+rnd_bias*8] - paddw m3, [rnd_2d_%2+rnd_bias*8] - psrlw m2, 6 - psrlw m3, 6 - packuswb m2, m3 - CHROMAMC_AVG m2, [dest_reg] - movq [dest_reg], m2 ; dst[0..7] = ([mm2,mm3] + rnd) >> 6 - - add dest_reg, r2 - dec r3d - jne .next2drow - mov rsp, r6 ; restore stack pointer - RET -%endmacro - -%macro chroma_mc4_mmx_func 2 -%define extra_regs 0 -%ifidn %2, rv40 -%if PIC -%define extra_regs 1 -%endif ; PIC -%endif ; rv40 -cglobal %1_%2_chroma_mc4, 6, 6 + extra_regs, 0 - pxor m7, m7 - movd m2, r4d ; x - movd m3, r5d ; y - movq m4, [pw_8] - movq m5, [pw_8] - punpcklwd m2, m2 - punpcklwd m3, m3 - punpcklwd m2, m2 - punpcklwd m3, m3 - psubw m4, m2 - psubw m5, m3 - -%ifidn %2, rv40 -%if PIC - lea r6, [rnd_rv40_2d_tbl] -%define rnd_2d_rv40 r6 -%else -%define rnd_2d_rv40 rnd_rv40_2d_tbl -%endif - and r5, 6 ; &~1 for mx/my=[0,7] - lea r5, [r5*4+r4] - sar r5d, 1 -%define rnd_bias r5 -%else ; vc1, h264 -%define rnd_bias 0 -%endif - - movd m0, [r1 ] - movd m6, [r1+1] - add r1, r2 - punpcklbw m0, m7 - punpcklbw m6, m7 - pmullw m0, m4 - pmullw m6, m2 - paddw m6, m0 - -.next2rows: - movd m0, [r1 ] - movd m1, [r1+1] - add r1, r2 - punpcklbw m0, m7 - punpcklbw m1, m7 - pmullw m0, m4 - pmullw m1, m2 - paddw m1, m0 - movq m0, m1 - - pmullw m6, m5 - pmullw m1, m3 - paddw m6, [rnd_2d_%2+rnd_bias*8] - paddw m1, m6 - psrlw m1, 6 - packuswb m1, m1 - CHROMAMC_AVG4 m1, m6, [r0] - movd [r0], m1 - add r0, r2 - - movd m6, [r1 ] - movd m1, [r1+1] - add r1, r2 - punpcklbw m6, m7 - punpcklbw m1, m7 - pmullw m6, m4 - pmullw m1, m2 - paddw m1, m6 - movq m6, m1 - pmullw m0, m5 - pmullw m1, m3 - paddw m0, [rnd_2d_%2+rnd_bias*8] - paddw m1, m0 - psrlw m1, 6 - packuswb m1, m1 - CHROMAMC_AVG4 m1, m0, [r0] - movd [r0], m1 - add r0, r2 - sub r3d, 2 - jnz .next2rows - RET -%endmacro - %macro chroma_mc2_mmx_func 2 cglobal %1_%2_chroma_mc2, 6, 7, 0 mov r6d, r4d @@ -425,33 +116,23 @@ cglobal %1_%2_chroma_mc2, 6, 7, 0 PAVGB %1, %2 %endmacro -INIT_MMX mmx -%define CHROMAMC_AVG NOTHING -%define CHROMAMC_AVG4 NOTHING -chroma_mc8_mmx_func put, h264, _rnd -chroma_mc8_mmx_func put, vc1, _nornd -chroma_mc8_mmx_func put, rv40 -chroma_mc4_mmx_func put, h264 -chroma_mc4_mmx_func put, rv40 INIT_MMX mmxext +%define CHROMAMC_AVG NOTHING +%define CHROMAMC_AVG4 NOTHING chroma_mc2_mmx_func put, h264 %define CHROMAMC_AVG DIRECT_AVG %define CHROMAMC_AVG4 COPY_AVG -chroma_mc8_mmx_func avg, h264, _rnd -chroma_mc8_mmx_func avg, vc1, _nornd -chroma_mc8_mmx_func avg, rv40 -chroma_mc4_mmx_func avg, h264 -chroma_mc4_mmx_func avg, rv40 chroma_mc2_mmx_func avg, h264 %macro chroma_mc8_ssse3_func 2-3 -cglobal %1_%2_chroma_mc8%3, 6, 7, 8 +cglobal %1_%2_chroma_mc8%3, 6, 7+UNIX64, 8 mov r6d, r5d or r6d, r4d jne .at_least_one_non_zero ; mx == 0 AND my == 0 - no filter needed +..@%1_%2_chroma_mc8_no_filter_ %+ cpuname: mv0_pixels_mc8 RET @@ -462,6 +143,8 @@ cglobal %1_%2_chroma_mc8%3, 6, 7, 8 je .mx_is_zero ; general case, bilinear + movdqa m5, [rnd_2d_%2] +..@%1_%2_chroma_mc8_both_nonzero_ %+ cpuname: mov r6d, r4d shl r4d, 8 sub r4, r6 @@ -473,7 +156,6 @@ cglobal %1_%2_chroma_mc8%3, 6, 7, 8 movd m7, r6d movd m6, r4d - movdqa m5, [rnd_2d_%2] movq m0, [r1 ] movq m1, [r1+1] pshuflw m7, m7, 0 @@ -517,12 +199,13 @@ cglobal %1_%2_chroma_mc8%3, 6, 7, 8 RET .my_is_zero: + movdqa m6, [rnd_1d_%2] +..@%1_%2_chroma_mc8_my_zero_ %+ cpuname: mov r5d, r4d shl r4d, 8 add r4, 8 sub r4, r5 ; 255*x+8 = x<<8 | (8-x) movd m7, r4d - movdqa m6, [rnd_1d_%2] pshuflw m7, m7, 0 movlhps m7, m7 @@ -554,12 +237,13 @@ cglobal %1_%2_chroma_mc8%3, 6, 7, 8 RET .mx_is_zero: + movdqa m6, [rnd_1d_%2] +..@%1_%2_chroma_mc8_mx_zero_ %+ cpuname: mov r4d, r5d shl r5d, 8 add r5, 8 sub r5, r4 ; 255*y+8 = y<<8 | (8-y) movd m7, r5d - movdqa m6, [rnd_1d_%2] pshuflw m7, m7, 0 movlhps m7, m7 @@ -592,65 +276,132 @@ cglobal %1_%2_chroma_mc8%3, 6, 7, 8 %endmacro %macro chroma_mc4_ssse3_func 2 -cglobal %1_%2_chroma_mc4, 6, 7, 0 - mov r6, r4 +cglobal %1_%2_chroma_mc4, 6, 7+UNIX64, 8 + mova m5, [pw_32] +..@%1_%2_chroma_mc4_after_init_ %+ cpuname: + mov r6d, r4d shl r4d, 8 - sub r4d, r6d - mov r6, 8 - add r4d, 8 ; x*288+8 - sub r6d, r5d - imul r6d, r4d ; (8-y)*(x*255+8) = (8-y)*x<<8 | (8-y)*(8-x) - imul r4d, r5d ; y *(x*255+8) = y *x<<8 | y *(8-x) + movd m0, [r1] + sub r6d, 8 + sub r4d, r6d ; x << 8 | (8-x) + mov r6d, r5d + shl r5d, 16 + movd m1, [r1+1] + sub r6d, 8 + sub r5d, r6d ; y << 16 | (8-y) + imul r4d, r5d ; xy << 24 | (8-x)y << 16 | x(8-y) << 8 | (8-x)(8-y) + add r1, r2 - movd m7, r6d - movd m6, r4d - movq m5, [pw_32] - movd m0, [r1 ] - pshufw m7, m7, 0 - punpcklbw m0, [r1+1] - pshufw m6, m6, 0 + movd m6, r4d ; ABCD + punpcklwd m6, m6 ; ABABCDCD + pshufd m7, m6, 0x55 ; CDCDCDCDCDCDCDCD + punpcklbw m0, m1 + pshufd m6, m6, 0x0 ; ABABABABABABABAB .next2rows: - movd m1, [r1+r2*1 ] - movd m3, [r1+r2*2 ] - punpcklbw m1, [r1+r2*1+1] - punpcklbw m3, [r1+r2*2+1] - lea r1, [r1+r2*2] - movq m2, m1 - movq m4, m3 - pmaddubsw m0, m7 - pmaddubsw m1, m6 - pmaddubsw m2, m7 - pmaddubsw m3, m6 + movd m1, [r1] + movd m2, [r1+1] + movd m3, [r1+r2] + movd m4, [r1+r2+1] + punpcklbw m1, m2 + punpcklqdq m0, m1 + pmaddubsw m0, m6 + punpcklbw m3, m4 + punpcklqdq m1, m3 + pmaddubsw m1, m7 +%ifidn %1, avg + movd m2, [r0] + movd m4, [r0+r2] +%endif paddw m0, m5 - paddw m2, m5 - paddw m1, m0 - paddw m3, m2 - psrlw m1, 6 - movq m0, m4 - psrlw m3, 6 - packuswb m1, m1 - packuswb m3, m3 - CHROMAMC_AVG m1, [r0 ] - CHROMAMC_AVG m3, [r0+r2] - movd [r0 ], m1 - movd [r0+r2], m3 + lea r1, [r1+r2*2] + paddw m0, m1 + psrlw m0, 6 + packuswb m0, m0 + pshufd m1, m0, 0x1 +%ifidn %1, avg + pavgb m0, m2 + pavgb m1, m4 +%endif sub r3d, 2 + movd [r0], m0 + movd [r0+r2], m1 + mova m0, m3 lea r0, [r0+r2*2] jg .next2rows RET %endmacro -%define CHROMAMC_AVG NOTHING +%macro rv40_get_bias 1 ; dst reg +%if !PIC || UNIX64 + ; on UNIX64 we have enough volatile registers +%if PIC && UNIX64 + lea r7, [rv40_bias] +%endif + mov r6d, r5d + and r6d, 6 ; &~1 for mx/my=[0,7] + lea r6d, [r6d*4+r4d] + sar r6d, 1 +%if PIC && UNIX64 + movd %1, [r7+4*r6] +%else + movd %1, [rv40_bias+4*r6] +%endif +%else ; PIC && !UNIX64, de facto WIN64 + lea r6, [rv40_bias] +%ifidn r5d, r5m ; always false for currently supported calling conventions + push r5 +%endif + and r5d, 6 ; &~1 for mx/my=[0,7] + lea r5d, [r5d*4+r4d] + sar r5d, 1 + movd %1, [r6+4*r5] +%ifidn r5d, r5m + pop r5 +%else + mov r5d, r5m +%endif +%endif + SPLATW %1, %1 +%endmacro + +%macro rv40_chroma_mc8_func 1 ; put vs avg +%if CONFIG_RV40_DECODER + cglobal rv40_%1_chroma_mc8, 6, 7+UNIX64, 8 + mov r6d, r5d + or r6d, r4d + jz ..@%1_h264_chroma_mc8_no_filter_ %+ cpuname + rv40_get_bias m5 + ; the bilinear code expects bias in m5, the one-dimensional code in m6 + mova m6, m5 + psraw m6, 3 + test r5d, r5d + je ..@%1_h264_chroma_mc8_my_zero_ %+ cpuname + test r4d, r4d + je ..@%1_h264_chroma_mc8_mx_zero_ %+ cpuname + jmp ..@%1_h264_chroma_mc8_both_nonzero_ %+ cpuname +%endif +%endmacro + +%macro rv40_chroma_mc4_func 1 ; put vs avg +%if CONFIG_RV40_DECODER + cglobal rv40_%1_chroma_mc4, 6, 7+UNIX64, 8 + rv40_get_bias m5 + jmp ..@%1_h264_chroma_mc4_after_init_ %+ cpuname +%endif +%endmacro + INIT_XMM ssse3 +%define CHROMAMC_AVG NOTHING chroma_mc8_ssse3_func put, h264, _rnd chroma_mc8_ssse3_func put, vc1, _nornd -INIT_MMX ssse3 +rv40_chroma_mc8_func put chroma_mc4_ssse3_func put, h264 +rv40_chroma_mc4_func put %define CHROMAMC_AVG DIRECT_AVG -INIT_XMM ssse3 chroma_mc8_ssse3_func avg, h264, _rnd chroma_mc8_ssse3_func avg, vc1, _nornd -INIT_MMX ssse3 +rv40_chroma_mc8_func avg chroma_mc4_ssse3_func avg, h264 +rv40_chroma_mc4_func avg diff --git a/libavcodec/x86/h264_deblock.asm b/libavcodec/x86/h264_deblock.asm index 479e6c346..379adb329 100644 --- a/libavcodec/x86/h264_deblock.asm +++ b/libavcodec/x86/h264_deblock.asm @@ -37,71 +37,25 @@ cextern pb_0 cextern pb_1 cextern pb_3 -%define PASS8ROWS(base, base3, stride, stride3, offset) \ - PASS8ROWS(base+offset, base3+offset, stride, stride3) - -; in: 8 rows of 4 bytes in %4..%11 -; out: 4 rows of 8 bytes in m0..m3 -%macro TRANSPOSE4x8_LOAD 11 - movh m0, %4 - movh m2, %5 - movh m1, %6 - movh m3, %7 - punpckl%1 m0, m2 - punpckl%1 m1, m3 - mova m2, m0 - punpckl%2 m0, m1 - punpckh%2 m2, m1 - - movh m4, %8 - movh m6, %9 - movh m5, %10 - movh m7, %11 - punpckl%1 m4, m6 - punpckl%1 m5, m7 - mova m6, m4 - punpckl%2 m4, m5 - punpckh%2 m6, m5 - - punpckh%3 m1, m0, m4 - punpckh%3 m3, m2, m6 - punpckl%3 m0, m4 - punpckl%3 m2, m6 -%endmacro - -; in: 4 rows of 8 bytes in m0..m3 -; out: 8 rows of 4 bytes in %1..%8 -%macro TRANSPOSE8x4B_STORE 8 - punpckhdq m4, m0, m0 - punpckhdq m5, m1, m1 - punpckhdq m6, m2, m2 - - punpcklbw m0, m1 - punpcklbw m2, m3 - punpcklwd m1, m0, m2 - punpckhwd m0, m2 - movh %1, m1 - punpckhdq m1, m1 - movh %2, m1 - movh %3, m0 - punpckhdq m0, m0 - movh %4, m0 - - punpckhdq m3, m3 - punpcklbw m4, m5 - punpcklbw m6, m3 - punpcklwd m5, m4, m6 - punpckhwd m4, m6 - movh %5, m5 - punpckhdq m5, m5 - movh %6, m5 - movh %7, m4 - punpckhdq m4, m4 - movh %8, m4 -%endmacro - -%macro TRANSPOSE4x8B_LOAD 8 - TRANSPOSE4x8_LOAD bw, wd, dq, %1, %2, %3, %4, %5, %6, %7, %8 +; in: 2 rows of 8 words in %1, %2 +; out: 8 rows of 4 bytes in %3..%10 +%macro TRANSPOSE8x4B_STORE 10 + punpcklwd m6, %1, %2 + movd %3, m6 + pshufd m7, m6, 00110001b + punpckhqdq m6, m6 + movd %4, m7 + punpckhqdq m7, m7 + punpckhwd %1, %2 + movd %5, m6 + movd %6, m7 + pshufd m6, %1, 00110001b + movd %7, %1 + punpckhqdq %1, %1 + movd %8, m6 + punpckhqdq m6, m6 + movd %9, %1 + movd %10, m6 %endmacro %macro SBUTTERFLY3 4 @@ -218,10 +172,16 @@ cextern pb_3 %macro LOAD_MASK 2-3 movd m4, %1 movd m5, %2 +%if cpuflag(ssse3) + pxor m6, m6 + pshufb m4, m6 + pshufb m5, m6 +%else SPLATW m4, m4 SPLATW m5, m5 packuswb m4, m4 ; 16x alpha-1 packuswb m5, m5 ; 16x beta-1 +%endif %if %0>2 mova %3, m4 %endif @@ -249,14 +209,14 @@ cextern pb_3 pavgb m3, m5 mova m6, [pb_A1] paddusb m3, m4 ; d+128+33 - psubusb m6, m3 - psubusb m3, [pb_A1] - pminub m6, m7 + psubusb m4, m6, m3 + psubusb m3, m6 + pminub m4, m7 pminub m3, m7 - psubusb m1, m6 + psubusb m1, m4 psubusb m2, m3 paddusb m1, m3 - paddusb m2, m6 + paddusb m2, m4 %endmacro ; in: m1=p0 m2=q0 @@ -278,7 +238,7 @@ cextern pb_3 %if ARCH_X86_64 ;----------------------------------------------------------------------------- -; void ff_deblock_v_luma(uint8_t *pix, int stride, int alpha, int beta, +; void ff_deblock_v_luma(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, ; int8_t *tc0) ;----------------------------------------------------------------------------- %macro DEBLOCK_LUMA 0 @@ -324,15 +284,15 @@ cglobal deblock_v_luma_8, 5,5,10, pix_, stride_, alpha_, beta_, base3_ RET ;----------------------------------------------------------------------------- -; void ff_deblock_h_luma(uint8_t *pix, int stride, int alpha, int beta, +; void ff_deblock_h_luma(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, ; int8_t *tc0) ;----------------------------------------------------------------------------- -INIT_MMX cpuname -cglobal deblock_h_luma_8, 5,9,0,0x60+16*WIN64 - movsxd r7, r1d - lea r8, [r7+r7*2] +cglobal deblock_h_luma_8, 5,9,8,0x60+16*WIN64 + INIT_MMX cpuname + lea r8, [r1+r1*2] lea r6, [r0-4] lea r5, [r0-4+r8] + mov r7, r1 %if WIN64 %define pix_tmp rsp+0x30 ; shadow space + r4 %else @@ -340,10 +300,10 @@ cglobal deblock_h_luma_8, 5,9,0,0x60+16*WIN64 %endif ; transpose 6x16 -> tmp space - TRANSPOSE6x8_MEM PASS8ROWS(r6, r5, r7, r8), pix_tmp - lea r6, [r6+r7*8] - lea r5, [r5+r7*8] - TRANSPOSE6x8_MEM PASS8ROWS(r6, r5, r7, r8), pix_tmp+8 + TRANSPOSE6x8_MEM PASS8ROWS(r6, r5, r1, r8), pix_tmp + lea r6, [r6+r1*8] + lea r5, [r5+r1*8] + TRANSPOSE6x8_MEM PASS8ROWS(r6, r5, r1, r8), pix_tmp+8 ; vertical filter ; alpha, beta, tc0 are still in r2d, r3d, r4 @@ -355,32 +315,35 @@ cglobal deblock_h_luma_8, 5,9,0,0x60+16*WIN64 %endif call deblock_v_luma_8 - ; transpose 16x4 -> original space (only the middle 4 rows were changed by the filter) add r6, 2 add r5, 2 - movq m0, [pix_tmp+0x18] - movq m1, [pix_tmp+0x28] - movq m2, [pix_tmp+0x38] - movq m3, [pix_tmp+0x48] - TRANSPOSE8x4B_STORE PASS8ROWS(r6, r5, r7, r8) + INIT_XMM cpuname + + ; transpose 16x4 (only the middle 4 rows were changed by the filter) + mova m0, [pix_tmp+0x10] + ; the two middle rows are still in the proper registers + mova m3, [pix_tmp+0x40] + + punpckhbw m4, m0, m1 + punpckhbw m5, m2, m3 + + TRANSPOSE8x4B_STORE m4, m5, PASS8ROWS(r6, r5, r7, r8) + + punpcklbw m0, m1 + punpcklbw m2, m3 shl r7, 3 sub r6, r7 sub r5, r7 shr r7, 3 - movq m0, [pix_tmp+0x10] - movq m1, [pix_tmp+0x20] - movq m2, [pix_tmp+0x30] - movq m3, [pix_tmp+0x40] - TRANSPOSE8x4B_STORE PASS8ROWS(r6, r5, r7, r8) + TRANSPOSE8x4B_STORE m0, m2, PASS8ROWS(r6, r5, r7, r8) RET %endmacro %macro DEBLOCK_H_LUMA_MBAFF 0 cglobal deblock_h_luma_mbaff_8, 5, 9, 10, 8*16, pix_, stride_, alpha_, beta_, tc0_, base3_, stride3_ - movsxd stride_q, stride_d dec alpha_d dec beta_d mov base3_q, pix_q @@ -475,12 +438,12 @@ DEBLOCK_LUMA %else -%macro DEBLOCK_LUMA 2 +%macro DEBLOCK_LUMA 1 ;----------------------------------------------------------------------------- -; void ff_deblock_v8_luma(uint8_t *pix, int stride, int alpha, int beta, -; int8_t *tc0) +; void ff_deblock_v_luma(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, +; int8_t *tc0) ;----------------------------------------------------------------------------- -cglobal deblock_%1_luma_8, 5,5,8,2*%2 +cglobal deblock_v_luma_8, 5,5,8,2*%1 lea r4, [r1*3] dec r2 ; alpha-1 neg r4 @@ -498,7 +461,7 @@ cglobal deblock_%1_luma_8, 5,5,8,2*%2 movd m4, [r3] ; tc0 punpcklbw m4, m4 punpcklbw m4, m4 ; tc = 4x tc0[3], 4x tc0[2], 4x tc0[1], 4x tc0[0] - mova [esp+%2], m4 ; tc + mova [esp+%1], m4 ; tc pcmpgtb m4, m3 mova m3, [r4] ; p2 pand m4, m7 @@ -506,7 +469,7 @@ cglobal deblock_%1_luma_8, 5,5,8,2*%2 DIFF_GT2 m1, m3, m5, m6, m7 ; |p2-p0| > beta-1 pand m6, m4 - pand m4, [esp+%2] ; tc + pand m4, [esp+%1] ; tc psubb m7, m4, m6 pand m6, m4 LUMA_Q1 m0, m3, [r4], [r4+r1], m6, m4 @@ -514,7 +477,7 @@ cglobal deblock_%1_luma_8, 5,5,8,2*%2 mova m4, [r0+2*r1] ; q2 DIFF_GT2 m2, m4, m5, m6, m3 ; |q2-q0| > beta-1 pand m6, [esp] ; mask - mova m5, [esp+%2] ; tc + mova m5, [esp+%1] ; tc psubb m7, m6 pand m5, m6 mova m3, [r0+r1] @@ -526,11 +489,11 @@ cglobal deblock_%1_luma_8, 5,5,8,2*%2 RET ;----------------------------------------------------------------------------- -; void ff_deblock_h_luma(uint8_t *pix, int stride, int alpha, int beta, +; void ff_deblock_h_luma(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, ; int8_t *tc0) ;----------------------------------------------------------------------------- -INIT_MMX cpuname cglobal deblock_h_luma_8, 0,5,8,0x60+12 + INIT_MMX cpuname mov r0, r0mp mov r3, r1m lea r4, [r3*3] @@ -551,41 +514,39 @@ cglobal deblock_h_luma_8, 0,5,8,0x60+12 PUSH dword r2m PUSH dword 16 PUSH dword r0 - call deblock_%1_luma_8 -%ifidn %1, v8 - add dword [esp ], 8 ; pix_tmp+0x38 - add dword [esp+16], 2 ; tc0+2 - call deblock_%1_luma_8 -%endif + call deblock_v_luma_8 ADD esp, 20 - ; transpose 16x4 -> original space (only the middle 4 rows were changed by the filter) - mov r0, r0mp - sub r0, 2 + INIT_XMM cpuname - movq m0, [pix_tmp+0x10] - movq m1, [pix_tmp+0x20] - lea r1, [r0+r4] - movq m2, [pix_tmp+0x30] - movq m3, [pix_tmp+0x40] - TRANSPOSE8x4B_STORE PASS8ROWS(r0, r1, r3, r4) + ; transpose 16x4 (only the middle 4 rows were changed by the filter) + mova m0, [pix_tmp+0x10] + ; the two middle rows are still in the proper registers + mova m3, [pix_tmp+0x40] + mov r0, r0mp + punpcklbw m4, m0, m1 + sub r0, 2 + punpcklbw m5, m2, m3 + lea r1, [r0+r4] + + TRANSPOSE8x4B_STORE m4, m5, PASS8ROWS(r0, r1, r3, r4) + + punpckhbw m0, m1 lea r0, [r0+r3*8] + punpckhbw m2, m3 lea r1, [r1+r3*8] - movq m0, [pix_tmp+0x18] - movq m1, [pix_tmp+0x28] - movq m2, [pix_tmp+0x38] - movq m3, [pix_tmp+0x48] - TRANSPOSE8x4B_STORE PASS8ROWS(r0, r1, r3, r4) + + TRANSPOSE8x4B_STORE m0, m2, PASS8ROWS(r0, r1, r3, r4) RET %endmacro ; DEBLOCK_LUMA INIT_XMM sse2 -DEBLOCK_LUMA v, 16 +DEBLOCK_LUMA 16 %if HAVE_AVX_EXTERNAL INIT_XMM avx -DEBLOCK_LUMA v, 16 +DEBLOCK_LUMA 16 %endif %endif ; ARCH @@ -725,20 +686,18 @@ DEBLOCK_LUMA v, 16 %endif ;----------------------------------------------------------------------------- -; void ff_deblock_v_luma_intra(uint8_t *pix, int stride, int alpha, int beta) +; void ff_deblock_v_luma_intra(uint8_t *pix, ptrdiff_t stride, int alpha, int beta) ;----------------------------------------------------------------------------- %if WIN64 -cglobal deblock_%1_luma_intra_8, 4,6,16,0x10 +cglobal deblock_v_luma_intra_8, 4,6,16,0x10 %else -cglobal deblock_%1_luma_intra_8, 4,6,16,ARCH_X86_64*0x50-0x50 +cglobal deblock_v_luma_intra_8, 4,6,16,ARCH_X86_64*0x50-0x50 %endif lea r4, [r1*4] lea r5, [r1*3] ; 3*stride dec r2d ; alpha-1 - jl .end neg r4 dec r3d ; beta-1 - jl .end add r4, r0 ; pix-4*stride mova p1, [r4+2*r1] mova p0, [r4+r5] @@ -779,19 +738,18 @@ cglobal deblock_%1_luma_intra_8, 4,6,16,ARCH_X86_64*0x50-0x50 LUMA_INTRA_P012 [r4+r5], [r4+2*r1], [r4+r1], [r4] LUMA_INTRA_SWAP_PQ LUMA_INTRA_P012 [r0], [r0+r1], [r0+2*r1], [r0+r5] -.end: RET INIT_MMX cpuname %if ARCH_X86_64 ;----------------------------------------------------------------------------- -; void ff_deblock_h_luma_intra(uint8_t *pix, int stride, int alpha, int beta) +; void ff_deblock_h_luma_intra(uint8_t *pix, ptrdiff_t stride, int alpha, int beta) ;----------------------------------------------------------------------------- cglobal deblock_h_luma_intra_8, 4,9,0,0x80 - movsxd r7, r1d - lea r8, [r7*3] + lea r8, [r1*3] lea r6, [r0-4] lea r5, [r0-4+r8] + mov r7, r1 %if WIN64 %define pix_tmp rsp+0x20 ; shadow space %else @@ -799,10 +757,10 @@ cglobal deblock_h_luma_intra_8, 4,9,0,0x80 %endif ; transpose 8x16 -> tmp space - TRANSPOSE8x8_MEM PASS8ROWS(r6, r5, r7, r8), PASS8ROWS(pix_tmp, pix_tmp+0x30, 0x10, 0x30) - lea r6, [r6+r7*8] - lea r5, [r5+r7*8] - TRANSPOSE8x8_MEM PASS8ROWS(r6, r5, r7, r8), PASS8ROWS(pix_tmp+8, pix_tmp+0x38, 0x10, 0x30) + TRANSPOSE8x8_MEM PASS8ROWS(r6, r5, r1, r8), PASS8ROWS(pix_tmp, pix_tmp+0x30, 0x10, 0x30) + lea r6, [r6+r1*8] + lea r5, [r5+r1*8] + TRANSPOSE8x8_MEM PASS8ROWS(r6, r5, r1, r8), PASS8ROWS(pix_tmp+8, pix_tmp+0x38, 0x10, 0x30) lea r0, [pix_tmp+0x40] mov r1, 0x10 @@ -835,11 +793,7 @@ cglobal deblock_h_luma_intra_8, 2,4,8,0x80 PUSH dword r2m PUSH dword 16 PUSH r0 - call deblock_%1_luma_intra_8 -%ifidn %1, v8 - add dword [rsp], 8 ; pix_tmp+8 - call deblock_%1_luma_intra_8 -%endif + call deblock_v_luma_intra_8 ADD esp, 16 mov r1, r1m @@ -944,7 +898,6 @@ DEBLOCK_LUMA_INTRA v %endmacro %macro CHROMA_V_START_XMM 1 - movsxdifnidn stride_q, stride_d dec alpha_d dec beta_d mov %1, pix_q @@ -953,7 +906,6 @@ DEBLOCK_LUMA_INTRA v %endmacro %macro CHROMA_H_START_XMM 2 - movsxdifnidn stride_q, stride_d dec alpha_d dec beta_d lea %2, [3*stride_q] diff --git a/libavcodec/x86/h264_deblock_10bit.asm b/libavcodec/x86/h264_deblock_10bit.asm index 033f2f4d5..7b95754c8 100644 --- a/libavcodec/x86/h264_deblock_10bit.asm +++ b/libavcodec/x86/h264_deblock_10bit.asm @@ -1,5 +1,5 @@ ;***************************************************************************** -;* MMX/SSE2/AVX-optimized 10-bit H.264 deblocking code +;* SSE2/AVX-optimized 10-bit H.264 deblocking code ;***************************************************************************** ;* Copyright (C) 2005-2011 x264 project ;* @@ -65,12 +65,8 @@ cextern pw_1023 %macro LOAD_TC 2 movd %1, [%2] punpcklbw %1, %1 -%if mmsize == 8 - pshufw %1, %1, 0 -%else pshuflw %1, %1, 01010000b pshufd %1, %1, 01010000b -%endif psraw %1, 6 %endmacro @@ -131,12 +127,6 @@ cextern pw_1023 %endmacro %macro LUMA_H_STORE 2 -%if mmsize == 8 - movq [r0-4], m0 - movq [r0+r1-4], m1 - movq [r0+r1*2-4], m2 - movq [r0+%2-4], m3 -%else movq [r0-4], m0 movhps [r0+r1-4], m0 movq [r0+r1*2-4], m1 @@ -145,7 +135,6 @@ cextern pw_1023 movhps [%1+r1*2-4], m2 movq [%1+%2-4], m3 movhps [%1+r1*4-4], m3 -%endif %endmacro %macro DEBLOCK_LUMA 0 @@ -153,14 +142,12 @@ cextern pw_1023 ; void ff_deblock_v_luma_10(uint16_t *pix, int stride, int alpha, int beta, ; int8_t *tc0) ;----------------------------------------------------------------------------- -cglobal deblock_v_luma_10, 5,5,8*(mmsize/16) - %assign pad 5*mmsize+12-(stack_offset&15) +cglobal deblock_v_luma_10, 5,5,8,-5*mmsize %define tcm [rsp] %define ms1 [rsp+mmsize] %define ms2 [rsp+mmsize*2] %define am [rsp+mmsize*3] %define bm [rsp+mmsize*4] - SUB rsp, pad shl r2d, 2 shl r3d, 2 LOAD_AB m4, m5, r2d, r3d @@ -205,11 +192,9 @@ cglobal deblock_v_luma_10, 5,5,8*(mmsize/16) add r4, mmsize/8 dec r3 jg .loop - ADD rsp, pad RET -cglobal deblock_h_luma_10, 5,6,8*(mmsize/16) - %assign pad 7*mmsize+12-(stack_offset&15) +cglobal deblock_h_luma_10, 5,6,8,-7*mmsize %define tcm [rsp] %define ms1 [rsp+mmsize] %define ms2 [rsp+mmsize*2] @@ -217,7 +202,6 @@ cglobal deblock_h_luma_10, 5,6,8*(mmsize/16) %define p2m [rsp+mmsize*4] %define am [rsp+mmsize*5] %define bm [rsp+mmsize*6] - SUB rsp, pad shl r2d, 2 shl r3d, 2 LOAD_AB m4, m5, r2d, r3d @@ -227,24 +211,9 @@ cglobal deblock_h_luma_10, 5,6,8*(mmsize/16) mov r5, 32/mmsize mova bm, m5 add r3, r1 -%if mmsize == 16 mov r2, r0 add r2, r3 -%endif .loop: -%if mmsize == 8 - movq m2, [r0-8] ; y q2 q1 q0 - movq m7, [r0+0] - movq m5, [r0+r1-8] - movq m3, [r0+r1+0] - movq m0, [r0+r1*2-8] - movq m6, [r0+r1*2+0] - movq m1, [r0+r3-8] - TRANSPOSE4x4W 2, 5, 0, 1, 4 - SWAP 2, 7 - movq m7, [r0+r3] - TRANSPOSE4x4W 2, 3, 6, 7, 4 -%else movu m5, [r0-8] ; y q2 q1 q0 p0 p1 p2 x movu m0, [r0+r1-8] movu m2, [r0+r1*2-8] @@ -263,7 +232,6 @@ cglobal deblock_h_luma_10, 5,6,8*(mmsize/16) punpckhqdq m5, m4 SBUTTERFLY qdq, 0, 1, 7 SBUTTERFLY qdq, 2, 3, 7 -%endif mova p2m, m6 LOAD_MASK m0, m1, m2, m3, am, bm, m7, m4, m6 @@ -295,7 +263,6 @@ cglobal deblock_h_luma_10, 5,6,8*(mmsize/16) lea r2, [r2+r1*(mmsize/2)] dec r5 jg .loop - ADD rsp, pad RET %endmacro @@ -482,7 +449,6 @@ DEBLOCK_LUMA_64 %endmacro %macro LUMA_INTRA_INIT 1 - %xdefine pad %1*mmsize+((gprsize*3) % mmsize)-(stack_offset&15) %define t0 m4 %define t1 m5 %define t2 m6 @@ -492,7 +458,6 @@ DEBLOCK_LUMA_64 CAT_XDEFINE t, i, [rsp+mmsize*(i-4)] %assign i i+1 %endrep - SUB rsp, pad %endmacro ; in: %1-%3=tmp, %4=p2, %5=q2 @@ -523,23 +488,6 @@ DEBLOCK_LUMA_64 %endmacro %macro LUMA_H_INTRA_LOAD 0 -%if mmsize == 8 - movu t0, [r0-8] - movu t1, [r0+r1-8] - movu m0, [r0+r1*2-8] - movu m1, [r0+r4-8] - TRANSPOSE4x4W 4, 5, 0, 1, 2 - mova t4, t0 ; p3 - mova t5, t1 ; p2 - - movu m2, [r0] - movu m3, [r0+r1] - movu t0, [r0+r1*2] - movu t1, [r0+r4] - TRANSPOSE4x4W 2, 3, 4, 5, 6 - mova t6, t0 ; q2 - mova t7, t1 ; q3 -%else movu t0, [r0-8] movu t1, [r0+r1-8] movu m0, [r0+r1*2-8] @@ -553,24 +501,10 @@ DEBLOCK_LUMA_64 mova t5, t1 ; p2 mova t6, t2 ; q2 mova t7, t3 ; q3 -%endif %endmacro ; in: %1=q3 %2=q2' %3=q1' %4=q0' %5=p0' %6=p1' %7=p2' %8=p3 %9=tmp %macro LUMA_H_INTRA_STORE 9 -%if mmsize == 8 - TRANSPOSE4x4W %1, %2, %3, %4, %9 - movq [r0-8], m%1 - movq [r0+r1-8], m%2 - movq [r0+r1*2-8], m%3 - movq [r0+r4-8], m%4 - movq m%1, %8 - TRANSPOSE4x4W %5, %6, %7, %1, %9 - movq [r0], m%5 - movq [r0+r1], m%6 - movq [r0+r1*2], m%7 - movq [r0+r4], m%1 -%else TRANSPOSE2x4x4W %1, %2, %3, %4, %9 movq [r0-8], m%1 movq [r0+r1-8], m%2 @@ -594,7 +528,6 @@ DEBLOCK_LUMA_64 movhps [r4+r1], m%6 movhps [r4+r1*2], m%7 movhps [r4+r5], m%1 -%endif %endmacro %if ARCH_X86_64 @@ -654,7 +587,7 @@ cglobal deblock_v_luma_intra_10, 4,7,16 ; void ff_deblock_h_luma_intra_10(uint16_t *pix, int stride, int alpha, ; int beta) ;----------------------------------------------------------------------------- -cglobal deblock_h_luma_intra_10, 4,7,16 +cglobal deblock_h_luma_intra_10, 4,7,16,mmsize %define t0 m15 %define t1 m14 %define t2 m2 @@ -667,11 +600,8 @@ cglobal deblock_h_luma_intra_10, 4,7,16 %define p2 m13 %define p3 m4 %define spill [rsp] - %assign pad 24-(stack_offset&15) - SUB rsp, pad - lea r4, [r1*4] + lea r4, [r0+r1*4] ; pix+4*stride lea r5, [r1*3] ; 3*stride - add r4, r0 ; pix+4*stride mov r6, 2 mova m0, [pw_2] shl r2d, 2 @@ -709,7 +639,6 @@ cglobal deblock_h_luma_intra_10, 4,7,16 lea r4, [r4+r1*8] dec r6 jg .loop - ADD rsp, pad RET %endmacro @@ -727,7 +656,7 @@ DEBLOCK_LUMA_INTRA_64 ; void ff_deblock_v_luma_intra_10(uint16_t *pix, int stride, int alpha, ; int beta) ;----------------------------------------------------------------------------- -cglobal deblock_v_luma_intra_10, 4,7,8*(mmsize/16) +cglobal deblock_v_luma_intra_10, 4,7,8,-3*mmsize LUMA_INTRA_INIT 3 lea r4, [r1*4] lea r5, [r1*3] @@ -749,24 +678,17 @@ cglobal deblock_v_luma_intra_10, 4,7,8*(mmsize/16) add r4, mmsize dec r6 jg .loop - ADD rsp, pad RET ;----------------------------------------------------------------------------- ; void ff_deblock_h_luma_intra_10(uint16_t *pix, int stride, int alpha, ; int beta) ;----------------------------------------------------------------------------- -cglobal deblock_h_luma_intra_10, 4,7,8*(mmsize/16) +cglobal deblock_h_luma_intra_10, 4,7,8,-8*mmsize LUMA_INTRA_INIT 8 -%if mmsize == 8 - lea r4, [r1*3] - mov r5, 32/mmsize -%else - lea r4, [r1*4] + lea r4, [r0+r1*4] lea r5, [r1*3] ; 3*stride - add r4, r0 ; pix+4*stride mov r6, 32/mmsize -%endif shl r2d, 2 shl r3d, 2 .loop: @@ -786,23 +708,13 @@ cglobal deblock_h_luma_intra_10, 4,7,8*(mmsize/16) LUMA_H_INTRA_STORE 2, 0, 1, 3, 4, 6, 5, t7, 7 lea r0, [r0+r1*(mmsize/2)] -%if mmsize == 8 - dec r5 -%else lea r4, [r4+r1*(mmsize/2)] dec r6 -%endif jg .loop - ADD rsp, pad RET %endmacro %if ARCH_X86_64 == 0 -%if HAVE_ALIGNED_STACK == 0 -INIT_MMX mmxext -DEBLOCK_LUMA -DEBLOCK_LUMA_INTRA -%endif INIT_XMM sse2 DEBLOCK_LUMA DEBLOCK_LUMA_INTRA @@ -889,37 +801,21 @@ DEBLOCK_LUMA_INTRA %endmacro ; %1 = base + 3*stride -; %2 = 3*stride (unused on mmx) +; %2 = 3*stride ; %3, %4 = place to store p1 and q1 values %macro CHROMA_H_LOAD 4 - %if mmsize == 8 - movq m0, [pix_q - 4] - movq m1, [pix_q + stride_q - 4] - movq m2, [pix_q + 2*stride_q - 4] - movq m3, [%1 - 4] - TRANSPOSE4x4W 0, 1, 2, 3, 4 - %else - TRANSPOSE4x8W_LOAD PASS8ROWS(pix_q-4, %1-4, stride_q, %2) - %endif + TRANSPOSE4x8W_LOAD PASS8ROWS(pix_q-4, %1-4, stride_q, %2) mova %3, m0 mova %4, m3 %endmacro ; %1 = base + 3*stride -; %2 = 3*stride (unused on mmx) +; %2 = 3*stride ; %3, %4 = place to load p1 and q1 values %macro CHROMA_H_STORE 4 mova m0, %3 mova m3, %4 - %if mmsize == 8 - TRANSPOSE4x4W 0, 1, 2, 3, 4 - movq [pix_q - 4], m0 - movq [pix_q + stride_q - 4], m1 - movq [pix_q + 2*stride_q - 4], m2 - movq [%1 - 4], m3 - %else - TRANSPOSE8x4W_STORE PASS8ROWS(pix_q-4, %1-4, stride_q, %2) - %endif + TRANSPOSE8x4W_STORE PASS8ROWS(pix_q-4, %1-4, stride_q, %2) %endmacro %macro CHROMA_V_LOAD_TC 2 @@ -934,7 +830,7 @@ DEBLOCK_LUMA_INTRA ; void ff_deblock_v_chroma_10(uint16_t *pix, int stride, int alpha, int beta, ; int8_t *tc0) ;----------------------------------------------------------------------------- -cglobal deblock_v_chroma_10, 5,7-(mmsize/16),8*(mmsize/16) +cglobal deblock_v_chroma_10, 5,6,8 mov r5, r0 sub r0, r1 sub r0, r1 @@ -956,7 +852,7 @@ cglobal deblock_v_chroma_10, 5,7-(mmsize/16),8*(mmsize/16) ; void ff_deblock_v_chroma_intra_10(uint16_t *pix, int stride, int alpha, ; int beta) ;----------------------------------------------------------------------------- -cglobal deblock_v_chroma_intra_10, 4,6-(mmsize/16),8*(mmsize/16) +cglobal deblock_v_chroma_intra_10, 4,5,8 mov r4, r0 sub r0, r1 sub r0, r1 diff --git a/libavcodec/x86/h264_idct.asm b/libavcodec/x86/h264_idct.asm index d9c3c9c86..6ae820274 100644 --- a/libavcodec/x86/h264_idct.asm +++ b/libavcodec/x86/h264_idct.asm @@ -51,11 +51,23 @@ scan8_mem: db 4+ 1*8, 5+ 1*8, 4+ 2*8, 5+ 2*8 %endif cextern pw_32 -cextern pw_1 SECTION .text -; %1=uint8_t *dst, %2=int16_t *block, %3=int stride +; %1=callee, %2=dst to jump to if tail call is impossible (can be empty, +; then no jmp is performed), %3=current iteration, %4=last iteration +%macro TAIL_CALL_IF_LAST 4 +%if (%3 == %4) && !has_epilogue + jmp %1 +%else + call %1 + %ifnempty %2 + jmp %2 + %endif +%endif +%endmacro + +; %1=uint8_t *dst, %2=int16_t *block, %3=ptrdiff_t stride %macro IDCT4_ADD 3 ; Load dct coeffs movq m0, [%2] @@ -77,10 +89,15 @@ SECTION .text paddw m0, m6 IDCT4_1D w, 0, 1, 2, 3, 4, 5 pxor m7, m7 - movq [%2+ 0], m7 - movq [%2+ 8], m7 - movq [%2+16], m7 - movq [%2+24], m7 + %if mmsize == 16 + mova [%2+ 0], m7 + mova [%2+16], m7 + %else + movq [%2+ 0], m7 + movq [%2+ 8], m7 + movq [%2+16], m7 + movq [%2+24], m7 + %endif STORE_DIFFx2 m0, m1, m4, m5, m7, 6, %1, %3 lea %1, [%1+%3*2] @@ -145,62 +162,7 @@ SECTION .text IDCT8_1D [%1], [%1+ 64] %endmacro -; %1=int16_t *block, %2=int16_t *dstblock -%macro IDCT8_ADD_MMX_START 2 - IDCT8_1D_FULL %1 - mova [%1], m7 - TRANSPOSE4x4W 0, 1, 2, 3, 7 - mova m7, [%1] - mova [%2 ], m0 - mova [%2+16], m1 - mova [%2+32], m2 - mova [%2+48], m3 - TRANSPOSE4x4W 4, 5, 6, 7, 3 - mova [%2+ 8], m4 - mova [%2+24], m5 - mova [%2+40], m6 - mova [%2+56], m7 -%endmacro - -; %1=uint8_t *dst, %2=int16_t *block, %3=int stride -%macro IDCT8_ADD_MMX_END 3-4 - IDCT8_1D_FULL %2 - mova [%2 ], m5 - mova [%2+16], m6 - mova [%2+32], m7 - - pxor m7, m7 -%if %0 == 4 - movq [%4+ 0], m7 - movq [%4+ 8], m7 - movq [%4+ 16], m7 - movq [%4+ 24], m7 - movq [%4+ 32], m7 - movq [%4+ 40], m7 - movq [%4+ 48], m7 - movq [%4+ 56], m7 - movq [%4+ 64], m7 - movq [%4+ 72], m7 - movq [%4+ 80], m7 - movq [%4+ 88], m7 - movq [%4+ 96], m7 - movq [%4+104], m7 - movq [%4+112], m7 - movq [%4+120], m7 -%endif - STORE_DIFFx2 m0, m1, m5, m6, m7, 6, %1, %3 - lea %1, [%1+%3*2] - STORE_DIFFx2 m2, m3, m5, m6, m7, 6, %1, %3 - mova m0, [%2 ] - mova m1, [%2+16] - mova m2, [%2+32] - lea %1, [%1+%3*2] - STORE_DIFFx2 m4, m0, m5, m6, m7, 6, %1, %3 - lea %1, [%1+%3*2] - STORE_DIFFx2 m1, m2, m5, m6, m7, 6, %1, %3 -%endmacro - -; %1=uint8_t *dst, %2=int16_t *block, %3=int stride +; %1=uint8_t *dst, %2=int16_t *block, %3=ptrdiff_t stride %macro IDCT8_ADD_SSE 4 IDCT8_1D_FULL %2 %if ARCH_X86_64 @@ -371,30 +333,6 @@ INIT_XMM cpuname RET INIT_MMX mmx -h264_idct_add8_mmx_plane: - movsxdifnidn r3, r3d -.nextblock: - movzx r6, byte [scan8+r5] - movzx r6, byte [r4+r6] - or r6w, word [r2] - test r6, r6 - jz .skipblock -%if ARCH_X86_64 - mov r0d, dword [r1+r5*4] - add r0, [dst2q] -%else - mov r0, r1m ; XXX r1m here is actually r0m of the calling func - mov r0, [r0] - add r0, dword [r1+r5*4] -%endif - IDCT4_ADD r0, r2, r3 -.skipblock: - inc r5 - add r2, 32 - test r5, 3 - jnz .nextblock - rep ret - cglobal h264_idct_add8_422_8, 5, 8 + npicregs, 0, dst1, block_offset, block, stride, nnzc, cntr, coeff, dst2, picreg ; dst1, block_offset, block, stride, nnzc, cntr, coeff, dst2, picreg movsxdifnidn r3, r3d @@ -423,13 +361,34 @@ cglobal h264_idct_add8_422_8, 5, 8 + npicregs, 0, dst1, block_offset, block, str call h264_idct_add8_mmx_plane add r5, 4 - call h264_idct_add8_mmx_plane + TAIL_CALL h264_idct_add8_mmx_plane, 0 - RET ; TODO: check rep ret after a function call +h264_idct_add8_mmx_plane: +.nextblock: + movzx r6d, byte [scan8+r5] + movzx r6d, byte [r4+r6] + or r6w, word [r2] + test r6d, r6d + jz .skipblock +%if ARCH_X86_64 + mov r0d, dword [r1+r5*4] + add r0, [dst2q] +%else + mov r0, r1m ; XXX r1m here is actually r0m of the calling func + mov r0, [r0] + add r0, dword [r1+r5*4] +%endif + IDCT4_ADD r0, r2, r3 +.skipblock: + inc r5d + add r2, 32 + test r5d, 3 + jnz .nextblock + rep ret -; r0 = uint8_t *dst, r2 = int16_t *block, r3 = int stride, r6=clobbered + +; r0 = uint8_t *dst, r2 = int16_t *block, r3 = ptrdiff_t stride, r6=clobbered h264_idct_dc_add8_mmxext: - movsxdifnidn r3, r3d movd m0, [r2 ] ; 0 0 X D mov word [r2+ 0], 0 punpcklwd m0, [r2+32] ; x X d D @@ -448,9 +407,8 @@ h264_idct_dc_add8_mmxext: ALIGN 16 INIT_XMM sse2 -; r0 = uint8_t *dst (clobbered), r2 = int16_t *block, r3 = int stride +; r0 = uint8_t *dst (clobbered), r2 = int16_t *block, r3 = ptrdiff_t stride h264_add8x4_idct_sse2: - movsxdifnidn r3, r3d movq m0, [r2+ 0] movq m1, [r2+ 8] movq m2, [r2+16] @@ -483,7 +441,7 @@ h264_add8x4_idct_sse2: %else add r0, r0m %endif - call h264_add8x4_idct_sse2 + TAIL_CALL_IF_LAST h264_add8x4_idct_sse2, , %1, 7 .cycle%1end: %if %1 < 7 add r2, 64 @@ -520,8 +478,7 @@ RET %else add r0, r0m %endif - call h264_add8x4_idct_sse2 - jmp .cycle%1end + TAIL_CALL_IF_LAST h264_add8x4_idct_sse2, .cycle%1end, %1, 7 .try%1dc: movsx r0, word [r2 ] or r0w, word [r2+32] @@ -532,7 +489,7 @@ RET %else add r0, r0m %endif - call h264_idct_dc_add8_mmxext + TAIL_CALL_IF_LAST h264_idct_dc_add8_mmxext, , %1, 7 .cycle%1end: %if %1 < 7 add r2, 64 @@ -569,8 +526,7 @@ RET mov r0, [r0] add r0, dword [r1+(%1&1)*8+64*(1+(%1>>1))] %endif - call h264_add8x4_idct_sse2 - jmp .cycle%1end + TAIL_CALL_IF_LAST h264_add8x4_idct_sse2, .cycle%1end, %1, 3 .try%1dc: movsx r0, word [r2 ] or r0w, word [r2+32] @@ -583,7 +539,7 @@ RET mov r0, [r0] add r0, dword [r1+(%1&1)*8+64*(1+(%1>>1))] %endif - call h264_idct_dc_add8_mmxext + TAIL_CALL_IF_LAST h264_idct_dc_add8_mmxext, , %1, 3 .cycle%1end: %if %1 == 1 add r2, 384+64 @@ -612,7 +568,7 @@ cglobal h264_idct_add8_8, 5, 7 + ARCH_X86_64, 8 add8_sse2_cycle 3, 0x64 RET -;void ff_h264_luma_dc_dequant_idct_mmx(int16_t *output, int16_t *input, int qmul) +;void ff_h264_luma_dc_dequant_idct_sse2(int16_t *output, int16_t *input, int qmul) %macro WALSH4_1D 5 SUMSUB_BADC w, %4, %3, %2, %1, %5 @@ -620,111 +576,92 @@ RET SWAP %1, %4, %3 %endmacro -%macro DEQUANT 1-3 -%if cpuflag(sse2) - movd xmm4, t3d - movq xmm5, [pw_1] - pshufd xmm4, xmm4, 0 - movq2dq xmm0, m0 - movq2dq xmm1, m1 - movq2dq xmm2, m2 - movq2dq xmm3, m3 - punpcklwd xmm0, xmm5 - punpcklwd xmm1, xmm5 - punpcklwd xmm2, xmm5 - punpcklwd xmm3, xmm5 - pmaddwd xmm0, xmm4 - pmaddwd xmm1, xmm4 - pmaddwd xmm2, xmm4 - pmaddwd xmm3, xmm4 - psrad xmm0, %1 - psrad xmm1, %1 - psrad xmm2, %1 - psrad xmm3, %1 - packssdw xmm0, xmm1 - packssdw xmm2, xmm3 -%else - mova m7, [pw_1] - mova m4, %1 - punpcklwd %1, m7 - punpckhwd m4, m7 - mova m5, %2 - punpcklwd %2, m7 - punpckhwd m5, m7 - movd m7, t3d - punpckldq m7, m7 - pmaddwd %1, m7 - pmaddwd %2, m7 - pmaddwd m4, m7 - pmaddwd m5, m7 - psrad %1, %3 - psrad %2, %3 - psrad m4, %3 - psrad m5, %3 - packssdw %1, m4 - packssdw %2, m5 -%endif +; requires m5 to contain pw_1 +%macro DEQUANT 1 + movd m4, t3d + pshufd m4, m4, 0 + punpcklwd m0, m5 + punpcklwd m1, m5 + punpcklwd m2, m5 + punpcklwd m3, m5 + pmaddwd m0, m4 + pmaddwd m1, m4 + pmaddwd m2, m4 + pmaddwd m3, m4 + psrad m0, %1 + psrad m1, %1 + psrad m2, %1 + psrad m3, %1 %endmacro -%macro STORE_WORDS 5-9 -%if cpuflag(sse) - movd t0d, %1 - psrldq %1, 4 - movd t1d, %1 - psrldq %1, 4 - mov [t2+%2*32], t0w - mov [t2+%4*32], t1w - shr t0d, 16 - shr t1d, 16 +%macro STORE_WORDS 10 +%if ARCH_X86_64 + movq t0, %1 + movq t1, %2 + psrldq %1, 8 + psrldq %2, 8 mov [t2+%3*32], t0w - mov [t2+%5*32], t1w - movd t0d, %1 - psrldq %1, 4 - movd t1d, %1 - mov [t2+%6*32], t0w + mov [t2+%7*32], t1w + shr t0, 32 + shr t1, 32 + mov [t2+%4*32], t0w mov [t2+%8*32], t1w - shr t0d, 16 - shr t1d, 16 - mov [t2+%7*32], t0w + movq t0, %1 + movq t1, %2 + mov [t2+%5*32], t0w mov [t2+%9*32], t1w + shr t0, 32 + shr t1, 32 + mov [t2+%6*32], t0w + mov [t2+%10*32], t1w %else - movd t0d, %1 - psrlq %1, 32 - movd t1d, %1 - mov [t2+%2*32], t0w - mov [t2+%4*32], t1w - shr t0d, 16 - shr t1d, 16 + movd t0d, %1 + movd t1d, %2 + psrldq %1, 4 + psrldq %2, 4 mov [t2+%3*32], t0w - mov [t2+%5*32], t1w + mov [t2+%7*32], t1w + movd t0d, %1 + movd t1d, %2 + psrldq %1, 4 + psrldq %2, 4 + mov [t2+%4*32], t0w + mov [t2+%8*32], t1w + movd t0d, %1 + movd t1d, %2 + psrldq %1, 4 + psrldq %2, 4 + mov [t2+%5*32], t0w + mov [t2+%9*32], t1w + movd t0d, %1 + movd t1d, %2 + mov [t2+%6*32], t0w + mov [t2+%10*32], t1w %endif %endmacro %macro DEQUANT_STORE 1 -%if cpuflag(sse2) DEQUANT %1 - STORE_WORDS xmm0, 0, 1, 4, 5, 2, 3, 6, 7 - STORE_WORDS xmm2, 8, 9, 12, 13, 10, 11, 14, 15 -%else - DEQUANT m0, m1, %1 - STORE_WORDS m0, 0, 1, 4, 5 - STORE_WORDS m1, 2, 3, 6, 7 - - DEQUANT m2, m3, %1 - STORE_WORDS m2, 8, 9, 12, 13 - STORE_WORDS m3, 10, 11, 14, 15 -%endif + STORE_WORDS m0, m1, 0, 1, 4, 5, 2, 3, 6, 7 + STORE_WORDS m2, m3, 8, 9, 12, 13, 10, 11, 14, 15 %endmacro INIT_XMM sse2 cglobal h264_luma_dc_dequant_idct, 3, 4, 7 -INIT_MMX cpuname movq m3, [r1+24] movq m2, [r1+16] movq m1, [r1+ 8] movq m0, [r1+ 0] WALSH4_1D 0,1,2,3,4 - TRANSPOSE4x4W 0,1,2,3,4 + punpcklwd m0, m1 + punpcklwd m2, m3 + mova m4, m0 + pcmpeqw m5, m5 + punpckldq m0, m2 + punpckhdq m4, m2 + movhlps m1, m0 + movhlps m3, m4 + SWAP 2, 4 WALSH4_1D 0,1,2,3,4 ; shift, tmp, output, qmul @@ -737,6 +674,7 @@ INIT_MMX cpuname %else DECLARE_REG_TMP 1,3,0,2 %endif + psrlw m5, 15 cmp t3d, 32767 jg .big_qmul @@ -752,12 +690,12 @@ INIT_MMX cpuname inc t1d shr t3d, t0b sub t1d, t0d - movd xmm6, t1d - DEQUANT_STORE xmm6 + movd m6, t1d + DEQUANT_STORE m6 RET %ifdef __NASM_VER__ -%if __NASM_MAJOR__ >= 2 && __NASM_MINOR__ >= 4 +%if __NASM_MAJOR__ > 2 || (__NASM_MAJOR__ == 2 && __NASM_MINOR__ >= 4) %unmacro STORE_DIFFx2 8 ; remove macro from x86util.asm but yasm doesn't have this yet %endif %endif diff --git a/libavcodec/x86/h264_qpel.c b/libavcodec/x86/h264_qpel.c index d69ccda89..5d618651a 100644 --- a/libavcodec/x86/h264_qpel.c +++ b/libavcodec/x86/h264_qpel.c @@ -19,127 +19,88 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/cpu.h" #include "libavutil/mem_internal.h" -#include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" #include "libavcodec/h264qpel.h" -#include "libavcodec/pixels.h" #include "fpel.h" +#include "qpel.h" -#if HAVE_X86ASM -void ff_put_pixels4_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); -void ff_avg_pixels4_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); -void ff_put_pixels8_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); -void ff_avg_pixels8_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); -void ff_put_pixels16_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); -void ff_avg_pixels16_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); -#define ff_put_pixels8_l2_sse2 ff_put_pixels8_l2_mmxext -#define ff_avg_pixels8_l2_sse2 ff_avg_pixels8_l2_mmxext -#define ff_put_pixels16_l2_sse2 ff_put_pixels16_l2_mmxext -#define ff_avg_pixels16_l2_sse2 ff_avg_pixels16_l2_mmxext -#define ff_put_pixels16_mmxext ff_put_pixels16_mmx -#define ff_put_pixels8_mmxext(...) -#define ff_put_pixels4_mmxext(...) +void ff_avg_pixels4_mmxext(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_pixels4x4_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + ptrdiff_t stride); +void ff_avg_pixels4x4_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + ptrdiff_t stride); +#define ff_put_pixels4x4_l2_mmxext(dst, src1, src2, dststride, src1stride) \ + ff_put_pixels4x4_l2_mmxext((dst), (src1), (src2), (dststride)) +#define ff_avg_pixels4x4_l2_mmxext(dst, src1, src2, dststride, src1stride) \ + ff_avg_pixels4x4_l2_mmxext((dst), (src1), (src2), (dststride)) +#define ff_put_pixels8x8_l2_sse2 ff_put_pixels8x8_l2_mmxext +#define ff_avg_pixels8x8_l2_sse2 ff_avg_pixels8x8_l2_mmxext #define DEF_QPEL(OPNAME)\ -void ff_ ## OPNAME ## _h264_qpel4_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride);\ -void ff_ ## OPNAME ## _h264_qpel8_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride);\ -void ff_ ## OPNAME ## _h264_qpel8_h_lowpass_ssse3(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride);\ -void ff_ ## OPNAME ## _h264_qpel4_h_lowpass_l2_mmxext(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride);\ -void ff_ ## OPNAME ## _h264_qpel8_h_lowpass_l2_mmxext(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride);\ -void ff_ ## OPNAME ## _h264_qpel8_h_lowpass_l2_ssse3(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride);\ -void ff_ ## OPNAME ## _h264_qpel4_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride);\ -void ff_ ## OPNAME ## _h264_qpel8or16_v_lowpass_sse2(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride, int h);\ -void ff_ ## OPNAME ## _h264_qpel4_hv_lowpass_v_mmxext(const uint8_t *src, int16_t *tmp, int srcStride);\ -void ff_ ## OPNAME ## _h264_qpel4_hv_lowpass_h_mmxext(int16_t *tmp, uint8_t *dst, int dstStride);\ -void ff_ ## OPNAME ## _h264_qpel8or16_hv1_lowpass_op_sse2(const uint8_t *src, int16_t *tmp, int srcStride, int size);\ -void ff_ ## OPNAME ## _h264_qpel8or16_hv2_lowpass_op_mmxext(uint8_t *dst, int16_t *tmp, int dstStride, int unused, int h);\ -void ff_ ## OPNAME ## _h264_qpel8or16_hv2_lowpass_ssse3(uint8_t *dst, int16_t *tmp, int dstStride, int tmpStride, int size);\ -void ff_ ## OPNAME ## _pixels4_l2_shift5_mmxext(uint8_t *dst, const int16_t *src16, const uint8_t *src8, int dstStride, int src8Stride, int h);\ -void ff_ ## OPNAME ## _pixels8_l2_shift5_mmxext(uint8_t *dst, const int16_t *src16, const uint8_t *src8, int dstStride, int src8Stride, int h); +void ff_ ## OPNAME ## _h264_qpel4_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride);\ +void ff_ ## OPNAME ## _h264_qpel8_h_lowpass_ssse3(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride);\ +void ff_ ## OPNAME ## _h264_qpel4_h_lowpass_l2_mmxext(uint8_t *dst, const uint8_t *src, const uint8_t *src2, ptrdiff_t dstStride, ptrdiff_t src2Stride);\ +void ff_ ## OPNAME ## _h264_qpel8_h_lowpass_l2_sse2(uint8_t *dst, const uint8_t *src, const uint8_t *src2, ptrdiff_t dstStride, ptrdiff_t src2Stride);\ +void ff_ ## OPNAME ## _h264_qpel16_h_lowpass_l2_sse2(uint8_t *dst, const uint8_t *src, const uint8_t *src2, ptrdiff_t dstStride, ptrdiff_t src2Stride);\ +void ff_ ## OPNAME ## _h264_qpel8_h_lowpass_l2_ssse3(uint8_t *dst, const uint8_t *src, const uint8_t *src2, ptrdiff_t dstStride, ptrdiff_t src2Stride);\ +void ff_ ## OPNAME ## _h264_qpel4_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride);\ +void ff_ ## OPNAME ## _h264_qpel8or16_v_lowpass_sse2(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h);\ +void ff_ ## OPNAME ## _h264_qpel4_hv_lowpass_h_mmxext(int16_t *tmp, uint8_t *dst, ptrdiff_t dstStride);\ +void ff_ ## OPNAME ## _h264_qpel8or16_hv1_lowpass_op_sse2(const uint8_t *src, int16_t *tmp, ptrdiff_t srcStride, int size);\ +void ff_ ## OPNAME ## _h264_qpel8_hv2_lowpass_sse2(uint8_t *dst, int16_t *tmp, ptrdiff_t dstStride);\ +void ff_ ## OPNAME ## _h264_qpel16_hv2_lowpass_sse2(uint8_t *dst, int16_t *tmp, ptrdiff_t dstStride);\ +void ff_ ## OPNAME ## _h264_qpel8_hv2_lowpass_ssse3(uint8_t *dst, int16_t *tmp, ptrdiff_t dstStride);\ +void ff_ ## OPNAME ## _h264_qpel16_hv2_lowpass_ssse3(uint8_t *dst, int16_t *tmp, ptrdiff_t dstStride);\ +void ff_ ## OPNAME ## _pixels4_l2_shift5_mmxext(uint8_t *dst, const int16_t *src16, const uint8_t *src8, ptrdiff_t dstStride);\ +void ff_ ## OPNAME ## _pixels8_l2_shift5_sse2(uint8_t *dst, const int16_t *src16, const uint8_t *src8, ptrdiff_t dstStride);\ +void ff_ ## OPNAME ## _pixels16_l2_shift5_sse2(uint8_t *dst, const int16_t *src16, const uint8_t *src8, ptrdiff_t dstStride);\ + +void ff_put_h264_qpel4_hv_lowpass_v_mmxext(const uint8_t *src, int16_t *tmp, ptrdiff_t srcStride); DEF_QPEL(avg) DEF_QPEL(put) -#define QPEL_H264(OPNAME, OP, MMX)\ -static av_always_inline void ff_ ## OPNAME ## h264_qpel4_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride){\ - int w=3;\ +#define QPEL_H264(OPNAME, MMX)\ +static av_always_inline void OPNAME ## h264_qpel4_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{\ src -= 2*srcStride+2;\ - while(w--){\ - ff_ ## OPNAME ## h264_qpel4_hv_lowpass_v_mmxext(src, tmp, srcStride);\ - tmp += 4;\ - src += 4;\ - }\ - tmp -= 3*4;\ + ff_put_h264_qpel4_hv_lowpass_v_mmxext(src, tmp, srcStride);\ ff_ ## OPNAME ## h264_qpel4_hv_lowpass_h_mmxext(tmp, dst, dstStride);\ }\ -\ -static av_always_inline void ff_ ## OPNAME ## h264_qpel8or16_hv2_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, int dstStride, int tmpStride, int size){\ - int w = size>>4;\ - do{\ - ff_ ## OPNAME ## h264_qpel8or16_hv2_lowpass_op_mmxext(dst, tmp, dstStride, 0, size);\ - tmp += 8;\ - dst += 8;\ - }while(w--);\ -}\ -\ -static av_always_inline void ff_ ## OPNAME ## h264_qpel16_h_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride){\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst , src , dstStride, srcStride);\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst+8, src+8, dstStride, srcStride);\ - src += 8*srcStride;\ - dst += 8*dstStride;\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst , src , dstStride, srcStride);\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst+8, src+8, dstStride, srcStride);\ -}\ -\ -static av_always_inline void ff_ ## OPNAME ## h264_qpel16_h_lowpass_l2_ ## MMX(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride){\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst , src , src2 , dstStride, src2Stride);\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst+8, src+8, src2+8, dstStride, src2Stride);\ + +#define QPEL_H264_H16(OPNAME, EXT) \ +static av_always_inline void ff_ ## OPNAME ## h264_qpel16_h_lowpass_l2_ ## EXT(uint8_t *dst, const uint8_t *src, const uint8_t *src2, ptrdiff_t dstStride, ptrdiff_t src2Stride)\ +{\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## EXT(dst , src , src2 , dstStride, src2Stride);\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## EXT(dst+8, src+8, src2+8, dstStride, src2Stride);\ src += 8*dstStride;\ dst += 8*dstStride;\ src2 += 8*src2Stride;\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst , src , src2 , dstStride, src2Stride);\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst+8, src+8, src2+8, dstStride, src2Stride);\ -}\ -\ -static av_always_inline void ff_ ## OPNAME ## pixels16_l2_shift5_ ## MMX(uint8_t *dst, const int16_t *src16, const uint8_t *src8, int dstStride, int src8Stride, int h)\ -{\ - ff_ ## OPNAME ## pixels8_l2_shift5_ ## MMX(dst , src16 , src8 , dstStride, src8Stride, h);\ - ff_ ## OPNAME ## pixels8_l2_shift5_ ## MMX(dst+8, src16+8, src8+8, dstStride, src8Stride, h);\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## EXT(dst , src , src2 , dstStride, src2Stride);\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## EXT(dst+8, src+8, src2+8, dstStride, src2Stride);\ }\ #if ARCH_X86_64 -#define QPEL_H264_H16_XMM(OPNAME, OP, MMX)\ +#define QPEL_H264_H16_XMM(OPNAME, MMX)\ -void ff_avg_h264_qpel16_h_lowpass_l2_ssse3(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride); -void ff_put_h264_qpel16_h_lowpass_l2_ssse3(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride); +void ff_avg_h264_qpel16_h_lowpass_l2_ssse3(uint8_t *dst, const uint8_t *src, const uint8_t *src2, ptrdiff_t dstStride, ptrdiff_t src2Stride); +void ff_put_h264_qpel16_h_lowpass_l2_ssse3(uint8_t *dst, const uint8_t *src, const uint8_t *src2, ptrdiff_t dstStride, ptrdiff_t src2Stride); #else // ARCH_X86_64 -#define QPEL_H264_H16_XMM(OPNAME, OP, MMX)\ -static av_always_inline void ff_ ## OPNAME ## h264_qpel16_h_lowpass_l2_ ## MMX(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride){\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst , src , src2 , dstStride, src2Stride);\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst+8, src+8, src2+8, dstStride, src2Stride);\ - src += 8*dstStride;\ - dst += 8*dstStride;\ - src2 += 8*src2Stride;\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst , src , src2 , dstStride, src2Stride);\ - ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst+8, src+8, src2+8, dstStride, src2Stride);\ -} +#define QPEL_H264_H16_XMM(OPNAME, EXT) QPEL_H264_H16(OPNAME, EXT) #endif // ARCH_X86_64 -#define QPEL_H264_H_XMM(OPNAME, OP, MMX)\ -QPEL_H264_H16_XMM(OPNAME, OP, MMX)\ -static av_always_inline void ff_ ## OPNAME ## h264_qpel16_h_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride){\ +#define QPEL_H264_H_XMM(OPNAME, MMX)\ +QPEL_H264_H16_XMM(OPNAME, MMX)\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel16_h_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{\ ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst , src , dstStride, srcStride);\ ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst+8, src+8, dstStride, srcStride);\ src += 8*srcStride;\ @@ -148,19 +109,20 @@ static av_always_inline void ff_ ## OPNAME ## h264_qpel16_h_lowpass_ ## MMX(uint ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst+8, src+8, dstStride, srcStride);\ }\ -#define QPEL_H264_V_XMM(OPNAME, OP, MMX)\ -static av_always_inline void ff_ ## OPNAME ## h264_qpel8_v_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride){\ - ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## MMX(dst , src , dstStride, srcStride, 8);\ +#define QPEL_H264_V_XMM(OPNAME, XMM, XMM2)\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel8_v_lowpass_ ## XMM(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{\ + ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## XMM2(dst , src , dstStride, srcStride, 8);\ }\ -static av_always_inline void ff_ ## OPNAME ## h264_qpel16_v_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride){\ - ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## MMX(dst , src , dstStride, srcStride, 16);\ - ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel16_v_lowpass_ ## XMM(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{\ + ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## XMM2(dst , src , dstStride, srcStride, 16);\ + ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## XMM2(dst+8, src+8, dstStride, srcStride, 16);\ } static av_always_inline void put_h264_qpel8or16_hv1_lowpass_sse2(int16_t *tmp, const uint8_t *src, - int tmpStride, - int srcStride, + ptrdiff_t srcStride, int size) { int w = (size+8)>>3; @@ -172,60 +134,24 @@ static av_always_inline void put_h264_qpel8or16_hv1_lowpass_sse2(int16_t *tmp, } } -#define QPEL_H264_HV_XMM(OPNAME, OP, MMX)\ -static av_always_inline void ff_ ## OPNAME ## h264_qpel8or16_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride, int size){\ - put_h264_qpel8or16_hv1_lowpass_sse2(tmp, src, tmpStride, srcStride, size);\ - ff_ ## OPNAME ## h264_qpel8or16_hv2_lowpass_ ## MMX(dst, tmp, dstStride, tmpStride, size);\ -}\ -static av_always_inline void ff_ ## OPNAME ## h264_qpel8_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride){\ - ff_ ## OPNAME ## h264_qpel8or16_hv_lowpass_ ## MMX(dst, tmp, src, dstStride, tmpStride, srcStride, 8);\ -}\ -static av_always_inline void ff_ ## OPNAME ## h264_qpel16_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride){\ - ff_ ## OPNAME ## h264_qpel8or16_hv_lowpass_ ## MMX(dst, tmp, src, dstStride, tmpStride, srcStride, 16);\ -}\ - -#define ff_put_h264_qpel8_h_lowpass_l2_sse2 ff_put_h264_qpel8_h_lowpass_l2_mmxext -#define ff_avg_h264_qpel8_h_lowpass_l2_sse2 ff_avg_h264_qpel8_h_lowpass_l2_mmxext -#define ff_put_h264_qpel16_h_lowpass_l2_sse2 ff_put_h264_qpel16_h_lowpass_l2_mmxext -#define ff_avg_h264_qpel16_h_lowpass_l2_sse2 ff_avg_h264_qpel16_h_lowpass_l2_mmxext - -#define ff_put_h264_qpel8_v_lowpass_ssse3 ff_put_h264_qpel8_v_lowpass_sse2 -#define ff_avg_h264_qpel8_v_lowpass_ssse3 ff_avg_h264_qpel8_v_lowpass_sse2 -#define ff_put_h264_qpel16_v_lowpass_ssse3 ff_put_h264_qpel16_v_lowpass_sse2 -#define ff_avg_h264_qpel16_v_lowpass_ssse3 ff_avg_h264_qpel16_v_lowpass_sse2 - -#define ff_put_h264_qpel8or16_hv2_lowpass_sse2 ff_put_h264_qpel8or16_hv2_lowpass_mmxext -#define ff_avg_h264_qpel8or16_hv2_lowpass_sse2 ff_avg_h264_qpel8or16_hv2_lowpass_mmxext - -#define H264_MC_C_H(OPNAME, SIZE, MMX, ALIGN) \ -H264_MC_C(OPNAME, SIZE, MMX, ALIGN)\ -H264_MC_H(OPNAME, SIZE, MMX, ALIGN)\ - -#define H264_MC_C_V_H_HV(OPNAME, SIZE, MMX, ALIGN) \ -H264_MC_C(OPNAME, SIZE, MMX, ALIGN)\ -H264_MC_V(OPNAME, SIZE, MMX, ALIGN)\ -H264_MC_H(OPNAME, SIZE, MMX, ALIGN)\ -H264_MC_HV(OPNAME, SIZE, MMX, ALIGN)\ - -static void put_h264_qpel16_mc00_sse2 (uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - ff_put_pixels16_sse2(dst, src, stride, 16); -} -static void avg_h264_qpel16_mc00_sse2 (uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - ff_avg_pixels16_sse2(dst, src, stride, 16); -} -#define avg_h264_qpel8_mc00_sse2 avg_h264_qpel8_mc00_mmxext - -#define H264_MC_C(OPNAME, SIZE, MMX, ALIGN) \ -static void av_unused OPNAME ## h264_qpel ## SIZE ## _mc00_ ## MMX (uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +#define QPEL_H264_HV_XMM(OPNAME, MMX)\ +static av_always_inline void OPNAME ## h264_qpel8_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ {\ - ff_ ## OPNAME ## pixels ## SIZE ## _ ## MMX(dst, src, stride, SIZE);\ + put_h264_qpel8or16_hv1_lowpass_sse2(tmp, src, srcStride, 8);\ + ff_ ## OPNAME ## h264_qpel8_hv2_lowpass_ ## MMX(dst, tmp, dstStride);\ +}\ +static av_always_inline void OPNAME ## h264_qpel16_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{\ + put_h264_qpel8or16_hv1_lowpass_sse2(tmp, src, srcStride, 16);\ + ff_ ## OPNAME ## h264_qpel16_hv2_lowpass_ ## MMX(dst, tmp, dstStride);\ }\ -#define H264_MC_H(OPNAME, SIZE, MMX, ALIGN) \ +#define H264_MC_V_H_HV(OPNAME, SIZE, MMX, ALIGN, SHIFT5_EXT) \ +H264_MC_V(OPNAME, SIZE, MMX, ALIGN, SHIFT5_EXT)\ +H264_MC_H(OPNAME, SIZE, MMX, ALIGN, SHIFT5_EXT)\ +H264_MC_HV(OPNAME, SIZE, MMX, ALIGN, SHIFT5_EXT)\ + +#define H264_MC_H(OPNAME, SIZE, MMX, ALIGN, UNUSED) \ static void OPNAME ## h264_qpel ## SIZE ## _mc10_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ {\ ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src, src, stride, stride);\ @@ -241,12 +167,12 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc30_ ## MMX(uint8_t *dst, const uin ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src, src+1, stride, stride);\ }\ -#define H264_MC_V(OPNAME, SIZE, MMX, ALIGN) \ +#define H264_MC_V(OPNAME, SIZE, MMX, ALIGN, UNUSED) \ static void OPNAME ## h264_qpel ## SIZE ## _mc01_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ {\ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\ ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src, SIZE, stride);\ - ff_ ## OPNAME ## pixels ## SIZE ## _l2_ ## MMX(dst, src, temp, stride, stride, SIZE);\ + ff_ ## OPNAME ## pixels ## SIZE ## x ## SIZE ## _l2_ ## MMX(dst, src, temp, stride, stride);\ }\ \ static void OPNAME ## h264_qpel ## SIZE ## _mc02_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ @@ -258,10 +184,10 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc03_ ## MMX(uint8_t *dst, const uin {\ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\ ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src, SIZE, stride);\ - ff_ ## OPNAME ## pixels ## SIZE ## _l2_ ## MMX(dst, src+stride, temp, stride, stride, SIZE);\ + ff_ ## OPNAME ## pixels ## SIZE ## x ## SIZE ## _l2_ ## MMX(dst, src+stride, temp, stride, stride);\ }\ -#define H264_MC_HV(OPNAME, SIZE, MMX, ALIGN) \ +#define H264_MC_HV(OPNAME, SIZE, MMX, ALIGN, SHIFT5_EXT) \ static void OPNAME ## h264_qpel ## SIZE ## _mc11_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ {\ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\ @@ -293,7 +219,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc33_ ## MMX(uint8_t *dst, const uin static void OPNAME ## h264_qpel ## SIZE ## _mc22_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ {\ LOCAL_ALIGNED(ALIGN, uint16_t, temp, [SIZE*(SIZE<8?12:24)]);\ - ff_ ## OPNAME ## h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(dst, temp, src, stride, SIZE, stride);\ + OPNAME ## h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(dst, temp, src, stride, stride);\ }\ \ static void OPNAME ## h264_qpel ## SIZE ## _mc21_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ @@ -302,7 +228,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc21_ ## MMX(uint8_t *dst, const uin uint8_t * const halfHV= temp;\ int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\ av_assert2(((uintptr_t)temp & 7) == 0);\ - ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\ + put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, stride);\ ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src, halfHV, stride, SIZE);\ }\ \ @@ -312,7 +238,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc23_ ## MMX(uint8_t *dst, const uin uint8_t * const halfHV= temp;\ int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\ av_assert2(((uintptr_t)temp & 7) == 0);\ - ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\ + put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, stride);\ ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src+stride, halfHV, stride, SIZE);\ }\ \ @@ -322,8 +248,8 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc12_ ## MMX(uint8_t *dst, const uin uint8_t * const halfHV= temp;\ int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\ av_assert2(((uintptr_t)temp & 7) == 0);\ - ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\ - ff_ ## OPNAME ## pixels ## SIZE ## _l2_shift5_mmxext(dst, halfV+2, halfHV, stride, SIZE, SIZE);\ + put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, stride);\ + ff_ ## OPNAME ## pixels ## SIZE ## _l2_shift5_ ## SHIFT5_EXT(dst, halfV+2, halfHV, stride);\ }\ \ static void OPNAME ## h264_qpel ## SIZE ## _mc32_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ @@ -332,38 +258,37 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc32_ ## MMX(uint8_t *dst, const uin uint8_t * const halfHV= temp;\ int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\ av_assert2(((uintptr_t)temp & 7) == 0);\ - ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\ - ff_ ## OPNAME ## pixels ## SIZE ## _l2_shift5_mmxext(dst, halfV+3, halfHV, stride, SIZE, SIZE);\ + put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, stride);\ + ff_ ## OPNAME ## pixels ## SIZE ## _l2_shift5_ ## SHIFT5_EXT(dst, halfV+3, halfHV, stride);\ }\ -#define H264_MC(QPEL, SIZE, MMX, ALIGN)\ -QPEL(put_, SIZE, MMX, ALIGN) \ -QPEL(avg_, SIZE, MMX, ALIGN) \ +#define H264_MC(QPEL, SIZE, MMX, ALIGN, SHIFT5_EXT)\ +QPEL(put_, SIZE, MMX, ALIGN, SHIFT5_EXT) \ +QPEL(avg_, SIZE, MMX, ALIGN, SHIFT5_EXT) \ -#define H264_MC_816(QPEL, XMM)\ -QPEL(put_, 8, XMM, 16)\ -QPEL(put_, 16,XMM, 16)\ -QPEL(avg_, 8, XMM, 16)\ -QPEL(avg_, 16,XMM, 16)\ +#define H264_MC_816(QPEL, XMM, SHIFT5_EXT)\ +QPEL(put_, 8, XMM, 16, SHIFT5_EXT)\ +QPEL(put_, 16,XMM, 16, SHIFT5_EXT)\ +QPEL(avg_, 8, XMM, 16, SHIFT5_EXT)\ +QPEL(avg_, 16,XMM, 16, SHIFT5_EXT)\ -QPEL_H264(put_, PUT_OP, mmxext) -QPEL_H264(avg_, AVG_MMXEXT_OP, mmxext) -QPEL_H264_V_XMM(put_, PUT_OP, sse2) -QPEL_H264_V_XMM(avg_,AVG_MMXEXT_OP, sse2) -QPEL_H264_HV_XMM(put_, PUT_OP, sse2) -QPEL_H264_HV_XMM(avg_,AVG_MMXEXT_OP, sse2) -QPEL_H264_H_XMM(put_, PUT_OP, ssse3) -QPEL_H264_H_XMM(avg_,AVG_MMXEXT_OP, ssse3) -QPEL_H264_HV_XMM(put_, PUT_OP, ssse3) -QPEL_H264_HV_XMM(avg_,AVG_MMXEXT_OP, ssse3) +QPEL_H264(put_, mmxext) +QPEL_H264(avg_, mmxext) +QPEL_H264_V_XMM(put_, sse2, sse2) +QPEL_H264_V_XMM(avg_, sse2, sse2) +QPEL_H264_HV_XMM(put_, sse2) +QPEL_H264_HV_XMM(avg_, sse2) +QPEL_H264_H_XMM(put_, ssse3) +QPEL_H264_H_XMM(avg_, ssse3) +QPEL_H264_V_XMM(put_, ssse3, sse2) +QPEL_H264_HV_XMM(put_, ssse3) +QPEL_H264_HV_XMM(avg_, ssse3) -H264_MC(H264_MC_C_V_H_HV, 4, mmxext, 8) -H264_MC(H264_MC_C_H, 8, mmxext, 8) -H264_MC(H264_MC_C_H, 16, mmxext, 8) -H264_MC_816(H264_MC_V, sse2) -H264_MC_816(H264_MC_HV, sse2) -H264_MC_816(H264_MC_H, ssse3) -H264_MC_816(H264_MC_HV, ssse3) +H264_MC(H264_MC_V_H_HV, 4, mmxext, 8, mmxext) +H264_MC_816(H264_MC_V, sse2, sse2) +H264_MC_816(H264_MC_HV, sse2, sse2) +H264_MC_816(H264_MC_H, ssse3, sse2) +H264_MC_816(H264_MC_HV, ssse3, sse2) //10bit @@ -400,13 +325,10 @@ LUMA_MC_4(10, mc33, mmxext) LUMA_MC_816(10, mc00, sse2) LUMA_MC_816(10, mc10, sse2) -LUMA_MC_816(10, mc10, sse2_cache64) LUMA_MC_816(10, mc10, ssse3_cache64) LUMA_MC_816(10, mc20, sse2) -LUMA_MC_816(10, mc20, sse2_cache64) LUMA_MC_816(10, mc20, ssse3_cache64) LUMA_MC_816(10, mc30, sse2) -LUMA_MC_816(10, mc30, sse2_cache64) LUMA_MC_816(10, mc30, ssse3_cache64) LUMA_MC_816(10, mc01, sse2) LUMA_MC_816(10, mc11, sse2) @@ -421,22 +343,11 @@ LUMA_MC_816(10, mc13, sse2) LUMA_MC_816(10, mc23, sse2) LUMA_MC_816(10, mc33, sse2) -#endif /* HAVE_X86ASM */ - -#define SET_QPEL_FUNCS123(PFX, IDX, SIZE, CPU, PREFIX) \ +#define SET_QPEL_FUNCS_1PP(PFX, IDX, SIZE, CPU, PREFIX) \ do { \ c->PFX ## _pixels_tab[IDX][ 1] = PREFIX ## PFX ## SIZE ## _mc10_ ## CPU; \ c->PFX ## _pixels_tab[IDX][ 2] = PREFIX ## PFX ## SIZE ## _mc20_ ## CPU; \ c->PFX ## _pixels_tab[IDX][ 3] = PREFIX ## PFX ## SIZE ## _mc30_ ## CPU; \ - } while (0) -#define SET_QPEL_FUNCS0123(PFX, IDX, SIZE, CPU, PREFIX) \ - do { \ - c->PFX ## _pixels_tab[IDX][ 0] = PREFIX ## PFX ## SIZE ## _mc00_ ## CPU; \ - SET_QPEL_FUNCS123(PFX, IDX, SIZE, CPU, PREFIX); \ - } while (0) -#define SET_QPEL_FUNCS_1PP(PFX, IDX, SIZE, CPU, PREFIX) \ - do { \ - SET_QPEL_FUNCS123(PFX, IDX, SIZE, CPU, PREFIX); \ c->PFX ## _pixels_tab[IDX][ 4] = PREFIX ## PFX ## SIZE ## _mc01_ ## CPU; \ c->PFX ## _pixels_tab[IDX][ 5] = PREFIX ## PFX ## SIZE ## _mc11_ ## CPU; \ c->PFX ## _pixels_tab[IDX][ 6] = PREFIX ## PFX ## SIZE ## _mc21_ ## CPU; \ @@ -474,18 +385,15 @@ LUMA_MC_816(10, mc33, sse2) av_cold void ff_h264qpel_init_x86(H264QpelContext *c, int bit_depth) { -#if HAVE_X86ASM int high_bit_depth = bit_depth > 8; int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_MMXEXT(cpu_flags)) { if (!high_bit_depth) { - SET_QPEL_FUNCS0123(put_h264_qpel, 0, 16, mmxext, ); - SET_QPEL_FUNCS123 (put_h264_qpel, 1, 8, mmxext, ); SET_QPEL_FUNCS_1PP(put_h264_qpel, 2, 4, mmxext, ); - SET_QPEL_FUNCS0123(avg_h264_qpel, 0, 16, mmxext, ); - SET_QPEL_FUNCS0123(avg_h264_qpel, 1, 8, mmxext, ); - SET_QPEL_FUNCS(avg_h264_qpel, 2, 4, mmxext, ); + c->avg_h264_qpel_pixels_tab[1][0] = ff_avg_pixels8x8_mmxext; + SET_QPEL_FUNCS_1PP(avg_h264_qpel, 2, 4, mmxext, ); + c->avg_h264_qpel_pixels_tab[2][0] = ff_avg_pixels4_mmxext; } else if (bit_depth == 10) { SET_QPEL_FUNCS(put_h264_qpel, 2, 4, 10_mmxext, ff_); SET_QPEL_FUNCS(avg_h264_qpel, 2, 4, 10_mmxext, ff_); @@ -506,6 +414,8 @@ av_cold void ff_h264qpel_init_x86(H264QpelContext *c, int bit_depth) H264_QPEL_FUNCS(3, 1, sse2); H264_QPEL_FUNCS(3, 2, sse2); H264_QPEL_FUNCS(3, 3, sse2); + c->put_h264_qpel_pixels_tab[0][0] = ff_put_pixels16x16_sse2; + c->avg_h264_qpel_pixels_tab[0][0] = ff_avg_pixels16x16_sse2; } if (bit_depth == 10) { @@ -513,17 +423,9 @@ av_cold void ff_h264qpel_init_x86(H264QpelContext *c, int bit_depth) SET_QPEL_FUNCS(put_h264_qpel, 1, 8, 10_sse2, ff_); SET_QPEL_FUNCS(avg_h264_qpel, 0, 16, 10_sse2, ff_); SET_QPEL_FUNCS(avg_h264_qpel, 1, 8, 10_sse2, ff_); - H264_QPEL_FUNCS_10(1, 0, sse2_cache64); - H264_QPEL_FUNCS_10(2, 0, sse2_cache64); - H264_QPEL_FUNCS_10(3, 0, sse2_cache64); - } - } - - if (EXTERNAL_SSE2_FAST(cpu_flags)) { - if (!high_bit_depth) { - c->put_h264_qpel_pixels_tab[0][0] = put_h264_qpel16_mc00_sse2; - c->avg_h264_qpel_pixels_tab[0][0] = avg_h264_qpel16_mc00_sse2; - c->avg_h264_qpel_pixels_tab[1][0] = avg_h264_qpel8_mc00_sse2; + H264_QPEL_FUNCS_10(1, 0, sse2); + H264_QPEL_FUNCS_10(2, 0, sse2); + H264_QPEL_FUNCS_10(3, 0, sse2); } } @@ -549,17 +451,4 @@ av_cold void ff_h264qpel_init_x86(H264QpelContext *c, int bit_depth) H264_QPEL_FUNCS_10(3, 0, ssse3_cache64); } } - - if (EXTERNAL_AVX(cpu_flags)) { - /* AVX implies 64 byte cache lines without the need to avoid unaligned - * memory accesses that cross the boundary between two cache lines. - * TODO: Port X264_CPU_CACHELINE_32/64 detection from x264 to avoid - * having to treat SSE2 functions with such properties as AVX. */ - if (bit_depth == 10) { - H264_QPEL_FUNCS_10(1, 0, sse2); - H264_QPEL_FUNCS_10(2, 0, sse2); - H264_QPEL_FUNCS_10(3, 0, sse2); - } - } -#endif } diff --git a/libavcodec/x86/h264_qpel_10bit.asm b/libavcodec/x86/h264_qpel_10bit.asm index 80483b15b..bad2d386e 100644 --- a/libavcodec/x86/h264_qpel_10bit.asm +++ b/libavcodec/x86/h264_qpel_10bit.asm @@ -227,8 +227,6 @@ MC00 avg %define OP_MOV mova INIT_MMX mmxext %1 put, 4 -INIT_XMM sse2, cache64 -%1 put, 8 INIT_XMM ssse3, cache64 %1 put, 8 INIT_XMM sse2 @@ -237,8 +235,6 @@ INIT_XMM sse2 %define OP_MOV AVG_MOV INIT_MMX mmxext %1 avg, 4 -INIT_XMM sse2, cache64 -%1 avg, 8 INIT_XMM ssse3, cache64 %1 avg, 8 INIT_XMM sse2 diff --git a/libavcodec/x86/h264_qpel_8bit.asm b/libavcodec/x86/h264_qpel_8bit.asm index 4e6432999..3aa1f233a 100644 --- a/libavcodec/x86/h264_qpel_8bit.asm +++ b/libavcodec/x86/h264_qpel_8bit.asm @@ -25,14 +25,30 @@ %include "libavutil/x86/x86util.asm" -SECTION_RODATA 32 - cextern pw_16 cextern pw_5 cextern pb_0 SECTION .text +; void ff_avg_pixels4_mmxext(uint8_t *block, const uint8_t *pixels, +; ptrdiff_t line_size) +INIT_MMX mmxext +cglobal avg_pixels4, 3,4 + lea r3, [r2*3] + movh m0, [r1] + movh m1, [r1+r2] + movh m2, [r1+r2*2] + movh m3, [r1+r3] + pavgb m0, [r0] + pavgb m1, [r0+r2] + pavgb m2, [r0+r2*2] + pavgb m3, [r0+r3] + movh [r0], m0 + movh [r0+r2], m1 + movh [r0+r2*2], m2 + movh [r0+r3], m3 + RET %macro op_avgh 3 movh %3, %2 @@ -53,10 +69,34 @@ SECTION .text mova %2, %1 %endmacro +; void ff_put/avg_pixels4x4_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, +; ptrdiff_t stride) +%macro PIXELS4_L2 1 +%define OP op_%1h +cglobal %1_pixels4x4_l2, 4,4 + mova m0, [r1] + mova m1, [r1+r3] + lea r1, [r1+2*r3] + pavgb m0, [r2] + pavgb m1, [r2+4] + OP m0, [r0], m3 + OP m1, [r0+r3], m3 + lea r0, [r0+2*r3] + mova m0, [r1] + mova m1, [r1+r3] + pavgb m0, [r2+8] + pavgb m1, [r2+12] + OP m0, [r0], m3 + OP m1, [r0+r3], m3 + RET +%endmacro + +INIT_MMX mmxext +PIXELS4_L2 put +PIXELS4_L2 avg + %macro QPEL4_H_LOWPASS_OP 1 cglobal %1_h264_qpel4_h_lowpass, 4,5 ; dst, src, dstStride, srcStride - movsxdifnidn r2, r2d - movsxdifnidn r3, r3d pxor m7, m7 mova m4, [pw_5] mova m5, [pw_16] @@ -96,70 +136,8 @@ INIT_MMX mmxext QPEL4_H_LOWPASS_OP put QPEL4_H_LOWPASS_OP avg -%macro QPEL8_H_LOWPASS_OP 1 -cglobal %1_h264_qpel8_h_lowpass, 4,5 ; dst, src, dstStride, srcStride - movsxdifnidn r2, r2d - movsxdifnidn r3, r3d - mov r4d, 8 - pxor m7, m7 - mova m6, [pw_5] -.loop: - mova m0, [r1] - mova m2, [r1+1] - mova m1, m0 - mova m3, m2 - punpcklbw m0, m7 - punpckhbw m1, m7 - punpcklbw m2, m7 - punpckhbw m3, m7 - paddw m0, m2 - paddw m1, m3 - psllw m0, 2 - psllw m1, 2 - mova m2, [r1-1] - mova m4, [r1+2] - mova m3, m2 - mova m5, m4 - punpcklbw m2, m7 - punpckhbw m3, m7 - punpcklbw m4, m7 - punpckhbw m5, m7 - paddw m2, m4 - paddw m5, m3 - psubw m0, m2 - psubw m1, m5 - pmullw m0, m6 - pmullw m1, m6 - movd m2, [r1-2] - movd m5, [r1+7] - punpcklbw m2, m7 - punpcklbw m5, m7 - paddw m2, m3 - paddw m4, m5 - mova m5, [pw_16] - paddw m2, m5 - paddw m4, m5 - paddw m0, m2 - paddw m1, m4 - psraw m0, 5 - psraw m1, 5 - packuswb m0, m1 - op_%1 m0, [r0], m4 - add r0, r2 - add r1, r3 - dec r4d - jg .loop - RET -%endmacro - -INIT_MMX mmxext -QPEL8_H_LOWPASS_OP put -QPEL8_H_LOWPASS_OP avg - %macro QPEL8_H_LOWPASS_OP_XMM 1 cglobal %1_h264_qpel8_h_lowpass, 4,5,8 ; dst, src, dstStride, srcStride - movsxdifnidn r2, r2d - movsxdifnidn r3, r3d mov r4d, 8 pxor m7, m7 mova m6, [pw_5] @@ -202,8 +180,6 @@ QPEL8_H_LOWPASS_OP_XMM avg %macro QPEL4_H_LOWPASS_L2_OP 1 cglobal %1_h264_qpel4_h_lowpass_l2, 5,6 ; dst, src, src2, dstStride, srcStride - movsxdifnidn r3, r3d - movsxdifnidn r4, r4d pxor m7, m7 mova m4, [pw_5] mova m5, [pw_16] @@ -248,54 +224,107 @@ QPEL4_H_LOWPASS_L2_OP avg %macro QPEL8_H_LOWPASS_L2_OP 1 -cglobal %1_h264_qpel8_h_lowpass_l2, 5,6 ; dst, src, src2, dstStride, srcStride - movsxdifnidn r3, r3d - movsxdifnidn r4, r4d +cglobal %1_h264_qpel8_h_lowpass_l2, 5,6,6 ; dst, src, src2, dstStride, srcStride + mova m3, [pw_16] mov r5d, 8 + pxor m5, m5 + mova m4, [pw_5] +.loop: + movh m0, [r1] + movh m1, [r1+1] + punpcklbw m0, m5 + punpcklbw m1, m5 + paddw m0, m1 + psllw m0, 2 + movh m1, [r1-1] + movh m2, [r1+2] + punpcklbw m1, m5 + punpcklbw m2, m5 + paddw m1, m2 + psubw m0, m1 + pmullw m0, m4 + movh m1, [r1-2] + movh m2, [r1+3] + punpcklbw m1, m5 + punpcklbw m2, m5 + paddw m0, m1 + paddw m0, m2 + paddw m0, m3 + psraw m0, 5 + packuswb m0, m5 + movh m2, [r2] + pavgb m0, m2 + op_%1h m0, [r0], m2 + add r0, r3 + add r1, r3 + add r2, r4 + dec r5d + jg .loop + RET +%endmacro + +INIT_XMM sse2 +QPEL8_H_LOWPASS_L2_OP put +QPEL8_H_LOWPASS_L2_OP avg + + +%macro QPEL16_H_LOWPASS_L2 1 +%if ARCH_X86_64 +cglobal %1_h264_qpel16_h_lowpass_l2, 5,6,9 ; dst, src, src2, dstStride, srcStride + mova m8, [pw_16] +%define PW_16 m8 +%else +cglobal %1_h264_qpel16_h_lowpass_l2, 5,6,8 ; dst, src, src2, dstStride, srcStride +%define PW_16 [pw_16] +%endif + mov r5d, 16 pxor m7, m7 mova m6, [pw_5] .loop: - mova m0, [r1] - mova m2, [r1+1] + movu m0, [r1] + movu m2, [r1+1] mova m1, m0 mova m3, m2 punpcklbw m0, m7 - punpckhbw m1, m7 punpcklbw m2, m7 + punpckhbw m1, m7 punpckhbw m3, m7 paddw m0, m2 paddw m1, m3 psllw m0, 2 psllw m1, 2 - mova m2, [r1-1] - mova m4, [r1+2] + movu m2, [r1-1] + movu m4, [r1+2] mova m3, m2 mova m5, m4 punpcklbw m2, m7 - punpckhbw m3, m7 punpcklbw m4, m7 + punpckhbw m3, m7 punpckhbw m5, m7 paddw m2, m4 - paddw m5, m3 + paddw m3, m5 psubw m0, m2 - psubw m1, m5 + psubw m1, m3 pmullw m0, m6 pmullw m1, m6 - movd m2, [r1-2] - movd m5, [r1+7] + movu m2, [r1-2] + movu m4, [r1+3] + mova m3, m2 + mova m5, m4 punpcklbw m2, m7 - punpcklbw m5, m7 - paddw m2, m3 - paddw m4, m5 - mova m5, [pw_16] - paddw m2, m5 - paddw m4, m5 + punpcklbw m4, m7 + punpckhbw m3, m7 + punpckhbw m5, m7 + paddw m2, m4 + paddw m3, m5 paddw m0, m2 - paddw m1, m4 + paddw m1, m3 + paddw m0, PW_16 + paddw m1, PW_16 psraw m0, 5 psraw m1, 5 - mova m4, [r2] packuswb m0, m1 + movu m4, [r2] pavgb m0, m4 op_%1 m0, [r0], m4 add r0, r3 @@ -306,15 +335,13 @@ cglobal %1_h264_qpel8_h_lowpass_l2, 5,6 ; dst, src, src2, dstStride, srcStride RET %endmacro -INIT_MMX mmxext -QPEL8_H_LOWPASS_L2_OP put -QPEL8_H_LOWPASS_L2_OP avg +INIT_XMM sse2 +QPEL16_H_LOWPASS_L2 put +QPEL16_H_LOWPASS_L2 avg %macro QPEL8_H_LOWPASS_L2_OP_XMM 1 cglobal %1_h264_qpel8_h_lowpass_l2, 5,6,8 ; dst, src, src2, dstStride, src2Stride - movsxdifnidn r3, r3d - movsxdifnidn r4, r4d mov r5d, 8 pxor m7, m7 mova m6, [pw_5] @@ -360,8 +387,12 @@ QPEL8_H_LOWPASS_L2_OP_XMM avg ; All functions that call this are required to have function arguments of ; dst, src, dstStride, srcStride -%macro FILT_V 1 +%macro FILT_V 1-2 +%ifnidn %2, last mova m6, m2 +%else + SWAP 6, 2 +%endif movh m5, [r1] paddw m6, m3 psllw m6, 2 @@ -376,14 +407,14 @@ QPEL8_H_LOWPASS_L2_OP_XMM avg psraw m6, 5 packuswb m6, m6 op_%1h m6, [r0], m0 ; 1 +%ifnidn %2, last add r0, r2 +%endif SWAP 0, 1, 2, 3, 4, 5 %endmacro %macro QPEL4_V_LOWPASS_OP 1 cglobal %1_h264_qpel4_v_lowpass, 4,4 ; dst, src, dstStride, srcStride - movsxdifnidn r2, r2d - movsxdifnidn r3, r3d sub r1, r3 sub r1, r3 pxor m7, m7 @@ -403,7 +434,7 @@ cglobal %1_h264_qpel4_v_lowpass, 4,4 ; dst, src, dstStride, srcStride FILT_V %1 FILT_V %1 FILT_V %1 - FILT_V %1 + FILT_V %1, last RET %endmacro @@ -414,17 +445,9 @@ QPEL4_V_LOWPASS_OP avg %macro QPEL8OR16_V_LOWPASS_OP 1 -%if cpuflag(sse2) cglobal %1_h264_qpel8or16_v_lowpass, 5,5,8 ; dst, src, dstStride, srcStride, h - movsxdifnidn r2, r2d - movsxdifnidn r3, r3d sub r1, r3 sub r1, r3 -%else -cglobal %1_h264_qpel8or16_v_lowpass_op, 5,5,8 ; dst, src, dstStride, srcStride, h - movsxdifnidn r2, r2d - movsxdifnidn r3, r3d -%endif pxor m7, m7 movh m0, [r1] movh m1, [r1+r3] @@ -456,7 +479,7 @@ cglobal %1_h264_qpel8or16_v_lowpass_op, 5,5,8 ; dst, src, dstStride, srcStride, FILT_V %1 FILT_V %1 FILT_V %1 - FILT_V %1 + FILT_V %1, last .end: RET %endmacro @@ -468,8 +491,12 @@ QPEL8OR16_V_LOWPASS_OP avg ; All functions that use this are required to have args: ; src, tmp, srcSize -%macro FILT_HV 1 ; offset +%macro FILT_HV 1-2 ; offset, last +%ifnidn %2, last mova m6, m2 +%else + SWAP 2, 6 +%endif movh m5, [r0] paddw m6, m3 psllw m6, 2 @@ -479,16 +506,20 @@ QPEL8OR16_V_LOWPASS_OP avg punpcklbw m5, m7 pmullw m6, [pw_5] paddw m0, m5 +%ifnidn %2, last add r0, r2 +%endif paddw m6, m0 mova [r1+%1], m6 SWAP 0, 1, 2, 3, 4, 5 %endmacro -%macro QPEL4_HV1_LOWPASS_OP 1 -cglobal %1_h264_qpel4_hv_lowpass_v, 3,3 ; src, tmp, srcStride - movsxdifnidn r2, r2d +INIT_MMX mmxext +cglobal put_h264_qpel4_hv_lowpass_v, 3,5 ; src, tmp, srcStride + mov r4d, 3 + mov r3, r0 pxor m7, m7 +.loop: movh m0, [r0] movh m1, [r0+r2] lea r0, [r0+2*r2] @@ -505,11 +536,16 @@ cglobal %1_h264_qpel4_hv_lowpass_v, 3,3 ; src, tmp, srcStride FILT_HV 0*24 FILT_HV 1*24 FILT_HV 2*24 - FILT_HV 3*24 + FILT_HV 3*24, last + add r3, 4 + add r1, 8 + mov r0, r3 + dec r4d + jnz .loop RET +%macro QPEL4_HV1_LOWPASS_OP 1 cglobal %1_h264_qpel4_hv_lowpass_h, 3,4 ; tmp, dst, dstStride - movsxdifnidn r2, r2d mov r3d, 4 .loop: mova m0, [r0] @@ -538,9 +574,8 @@ INIT_MMX mmxext QPEL4_HV1_LOWPASS_OP put QPEL4_HV1_LOWPASS_OP avg -%macro QPEL8OR16_HV1_LOWPASS_OP 1 -cglobal %1_h264_qpel8or16_hv1_lowpass_op, 4,4,8 ; src, tmp, srcStride, size - movsxdifnidn r2, r2d +INIT_XMM sse2 +cglobal put_h264_qpel8or16_hv1_lowpass_op, 4,4,8 ; src, tmp, srcStride, size pxor m7, m7 movh m0, [r0] movh m1, [r0+r2] @@ -572,67 +607,64 @@ cglobal %1_h264_qpel8or16_hv1_lowpass_op, 4,4,8 ; src, tmp, srcStride, size FILT_HV 12*48 FILT_HV 13*48 FILT_HV 14*48 - FILT_HV 15*48 + FILT_HV 15*48, last .end: RET + +%macro HV2_LOWPASS 2 + mova %1, [r1+%2] + movu m1, [r1+2+%2] + movu m3, [r1+10+%2] + movu m4, [r1+8+%2] + movu m2, [r1+4+%2] + paddw %1, m3 + movu m3, [r1+6+%2] + paddw m1, m4 + psubw %1, m1 + psraw %1, 2 + paddw m2, m3 + psubw %1, m1 + paddsw %1, m2 + psraw %1, 2 + paddw %1, m2 + psraw %1, 6 %endmacro -INIT_XMM sse2 -QPEL8OR16_HV1_LOWPASS_OP put - - - -%macro QPEL8OR16_HV2_LOWPASS_OP 1 -; unused is to match ssse3 and mmxext args -cglobal %1_h264_qpel8or16_hv2_lowpass_op, 5,5 ; dst, tmp, dstStride, unused, h - movsxdifnidn r2, r2d +%macro QPEL8AND16_HV2_LOWPASS_OP 1 +cglobal %1_h264_qpel8_hv2_lowpass, 3,4,6 ; dst, tmp, dstStride + mov r3d, 8 .loop: - mova m0, [r1] - mova m3, [r1+8] - mova m1, [r1+2] - mova m4, [r1+10] - paddw m0, m4 - paddw m1, m3 - paddw m3, [r1+18] - paddw m4, [r1+16] - mova m2, [r1+4] - mova m5, [r1+12] - paddw m2, [r1+6] - paddw m5, [r1+14] - psubw m0, m1 - psubw m3, m4 - psraw m0, 2 - psraw m3, 2 - psubw m0, m1 - psubw m3, m4 - paddsw m0, m2 - paddsw m3, m5 - psraw m0, 2 - psraw m3, 2 - paddw m0, m2 - paddw m3, m5 - psraw m0, 6 - psraw m3, 6 - packuswb m0, m3 - op_%1 m0, [r0], m7 + HV2_LOWPASS m0, 0 + packuswb m0, m0 + op_%1h m0, [r0], m3 add r1, 48 add r0, r2 - dec r4d + dec r3d + jne .loop + RET + +cglobal %1_h264_qpel16_hv2_lowpass, 3,4,6 ; dst, tmp, dstStride + mov r3d, 16 +.loop: + HV2_LOWPASS m0, 0 + HV2_LOWPASS m5, 16 + packuswb m0, m5 + op_%1 m0, [r0], m3 + add r1, 48 + add r0, r2 + dec r3d jne .loop RET %endmacro -INIT_MMX mmxext -QPEL8OR16_HV2_LOWPASS_OP put -QPEL8OR16_HV2_LOWPASS_OP avg +INIT_XMM sse2 +QPEL8AND16_HV2_LOWPASS_OP put +QPEL8AND16_HV2_LOWPASS_OP avg %macro QPEL8OR16_HV2_LOWPASS_OP_XMM 1 -cglobal %1_h264_qpel8or16_hv2_lowpass, 5,5,8 ; dst, tmp, dstStride, tmpStride, size - movsxdifnidn r2, r2d - movsxdifnidn r3, r3d - cmp r4d, 16 - je .op16 -.loop8: +cglobal %1_h264_qpel8_hv2_lowpass, 3,4,6 ; dst, tmp, dstStride + mov r3d, 8 +.loop: mova m1, [r1+16] mova m0, [r1] mova m2, m1 @@ -655,13 +687,16 @@ cglobal %1_h264_qpel8or16_hv2_lowpass, 5,5,8 ; dst, tmp, dstStride, tmpStride, s paddw m0, m2 psraw m0, 6 packuswb m0, m0 - op_%1h m0, [r0], m7 + op_%1h m0, [r0], m5 add r1, 48 add r0, r2 - dec r4d - jne .loop8 - jmp .done -.op16: + dec r3d + jne .loop + RET + +cglobal %1_h264_qpel16_hv2_lowpass, 3,4,8 ; dst, tmp, dstStride + mov r3d, 16 +.loop: mova m4, [r1+32] mova m5, [r1+16] mova m7, [r1] @@ -707,9 +742,8 @@ cglobal %1_h264_qpel8or16_hv2_lowpass, 5,5,8 ; dst, tmp, dstStride, tmpStride, s op_%1 m3, [r0], m7 add r1, 48 add r0, r2 - dec r4d - jne .op16 -.done: + dec r3d + jne .loop RET %endmacro @@ -719,9 +753,7 @@ QPEL8OR16_HV2_LOWPASS_OP_XMM avg %macro PIXELS4_L2_SHIFT5 1 -cglobal %1_pixels4_l2_shift5,6,6 ; dst, src16, src8, dstStride, src8Stride, h - movsxdifnidn r3, r3d - movsxdifnidn r4, r4d +cglobal %1_pixels4_l2_shift5,4,4 ; dst, src16, src8, dstStride mova m0, [r1] mova m1, [r1+24] psraw m0, 5 @@ -729,10 +761,9 @@ cglobal %1_pixels4_l2_shift5,6,6 ; dst, src16, src8, dstStride, src8Stride, h packuswb m0, m0 packuswb m1, m1 pavgb m0, [r2] - pavgb m1, [r2+r4] + pavgb m1, [r2+4] op_%1h m0, [r0], m4 op_%1h m1, [r0+r3], m5 - lea r2, [r2+r4*2] lea r0, [r0+r3*2] mova m0, [r1+48] mova m1, [r1+72] @@ -740,8 +771,8 @@ cglobal %1_pixels4_l2_shift5,6,6 ; dst, src16, src8, dstStride, src8Stride, h psraw m1, 5 packuswb m0, m0 packuswb m1, m1 - pavgb m0, [r2] - pavgb m1, [r2+r4] + pavgb m0, [r2+2*4] + pavgb m1, [r2+3*4] op_%1h m0, [r0], m4 op_%1h m1, [r0+r3], m5 RET @@ -751,16 +782,35 @@ INIT_MMX mmxext PIXELS4_L2_SHIFT5 put PIXELS4_L2_SHIFT5 avg - %macro PIXELS8_L2_SHIFT5 1 -cglobal %1_pixels8_l2_shift5, 6, 6 ; dst, src16, src8, dstStride, src8Stride, h - movsxdifnidn r3, r3d - movsxdifnidn r4, r4d +cglobal %1_pixels8_l2_shift5, 5, 5, 3 ; dst, src16, src8, dstStride + mov r4d, 8 .loop: - mova m0, [r1] - mova m1, [r1+8] - mova m2, [r1+48] - mova m3, [r1+48+8] + movu m0, [r1] + movu m1, [r1+48] + psraw m0, 5 + psraw m1, 5 + packuswb m0, m1 + pavgb m0, [r2] + pshufd m1, m0, 0xee ; low half of m1 is high half of m0 + op_%1h m0, [r0], m2 + op_%1h m1, [r0+r3], m2 + add r1, 48*2 + add r2, 8*2 + lea r0, [r0+2*r3] + sub r4d, 2 + jne .loop + RET +%endmacro + +%macro PIXELS16_L2_SHIFT5 2 +cglobal %1_pixels%2_l2_shift5, 5, 5, 4 ; dst, src16, src8, dstStride + mov r4d, %2 +.loop: + movu m0, [r1] + movu m1, [r1+%2] + movu m2, [r1+48] + movu m3, [r1+48+%2] psraw m0, 5 psraw m1, 5 psraw m2, 5 @@ -768,27 +818,27 @@ cglobal %1_pixels8_l2_shift5, 6, 6 ; dst, src16, src8, dstStride, src8Stride, h packuswb m0, m1 packuswb m2, m3 pavgb m0, [r2] - pavgb m2, [r2+r4] - op_%1 m0, [r0], m4 - op_%1 m2, [r0+r3], m5 - lea r2, [r2+2*r4] + pavgb m2, [r2+%2] + op_%1 m0, [r0], m1 + op_%1 m2, [r0+r3], m1 + lea r2, [r2+2*%2] add r1, 48*2 lea r0, [r0+2*r3] - sub r5d, 2 + sub r4d, 2 jne .loop RET %endmacro -INIT_MMX mmxext +INIT_XMM sse2 PIXELS8_L2_SHIFT5 put PIXELS8_L2_SHIFT5 avg +PIXELS16_L2_SHIFT5 put, 16 +PIXELS16_L2_SHIFT5 avg, 16 %if ARCH_X86_64 %macro QPEL16_H_LOWPASS_L2_OP 1 cglobal %1_h264_qpel16_h_lowpass_l2, 5, 6, 16 ; dst, src, src2, dstStride, src2Stride - movsxdifnidn r3, r3d - movsxdifnidn r4, r4d mov r5d, 16 pxor m15, m15 mova m14, [pw_5] diff --git a/libavcodec/x86/h264chroma_init.c b/libavcodec/x86/h264chroma_init.c index 34934b6ad..6eb52746a 100644 --- a/libavcodec/x86/h264chroma_init.c +++ b/libavcodec/x86/h264chroma_init.c @@ -24,16 +24,6 @@ #include "libavutil/x86/cpu.h" #include "libavcodec/h264chroma.h" -void ff_put_h264_chroma_mc8_rnd_mmx (uint8_t *dst, const uint8_t *src, - ptrdiff_t stride, int h, int x, int y); -void ff_avg_h264_chroma_mc8_rnd_mmxext(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride, int h, int x, int y); - -void ff_put_h264_chroma_mc4_mmx (uint8_t *dst, const uint8_t *src, - ptrdiff_t stride, int h, int x, int y); -void ff_avg_h264_chroma_mc4_mmxext (uint8_t *dst, const uint8_t *src, - ptrdiff_t stride, int h, int x, int y); - void ff_put_h264_chroma_mc2_mmxext (uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h, int x, int y); void ff_avg_h264_chroma_mc2_mmxext (uint8_t *dst, const uint8_t *src, @@ -68,14 +58,7 @@ av_cold void ff_h264chroma_init_x86(H264ChromaContext *c, int bit_depth) int high_bit_depth = bit_depth > 8; int cpu_flags = av_get_cpu_flags(); - if (EXTERNAL_MMX(cpu_flags) && !high_bit_depth) { - c->put_h264_chroma_pixels_tab[0] = ff_put_h264_chroma_mc8_rnd_mmx; - c->put_h264_chroma_pixels_tab[1] = ff_put_h264_chroma_mc4_mmx; - } - if (EXTERNAL_MMXEXT(cpu_flags) && !high_bit_depth) { - c->avg_h264_chroma_pixels_tab[0] = ff_avg_h264_chroma_mc8_rnd_mmxext; - c->avg_h264_chroma_pixels_tab[1] = ff_avg_h264_chroma_mc4_mmxext; c->avg_h264_chroma_pixels_tab[2] = ff_avg_h264_chroma_mc2_mmxext; c->put_h264_chroma_pixels_tab[2] = ff_put_h264_chroma_mc2_mmxext; } diff --git a/libavcodec/x86/h264dsp_init.c b/libavcodec/x86/h264dsp_init.c index dc8fc4f72..add134402 100644 --- a/libavcodec/x86/h264dsp_init.c +++ b/libavcodec/x86/h264dsp_init.c @@ -127,11 +127,6 @@ LF_FUNC(h, luma_mbaff, 8, avx) LF_FUNCS(uint8_t, 8) LF_FUNCS(uint16_t, 10) -LF_FUNC(v, luma, 10, mmxext) -LF_FUNC(h, luma, 10, mmxext) -LF_IFUNC(v, luma_intra, 10, mmxext) -LF_IFUNC(h, luma_intra, 10, mmxext) - /***********************************/ /* weighted prediction */ @@ -190,178 +185,166 @@ H264_BIWEIGHT_10_SSE(4, 10) av_cold void ff_h264dsp_init_x86(H264DSPContext *c, const int bit_depth, const int chroma_format_idc) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_MMXEXT(cpu_flags) && chroma_format_idc <= 1) - c->h264_loop_filter_strength = ff_h264_loop_filter_strength_mmxext; + c->loop_filter_strength = ff_h264_loop_filter_strength_mmxext; if (bit_depth == 8) { if (EXTERNAL_MMX(cpu_flags)) { if (chroma_format_idc <= 1) { } else { - c->h264_idct_add8 = ff_h264_idct_add8_422_8_mmx; + c->idct_add8 = ff_h264_idct_add8_422_8_mmx; } } if (EXTERNAL_MMXEXT(cpu_flags)) { - c->h264_idct8_dc_add = ff_h264_idct8_dc_add_8_mmxext; + c->idct8_dc_add = ff_h264_idct8_dc_add_8_mmxext; - c->weight_h264_pixels_tab[2] = ff_h264_weight_4_mmxext; + c->weight_pixels_tab[2] = ff_h264_weight_4_mmxext; - c->biweight_h264_pixels_tab[2] = ff_h264_biweight_4_mmxext; + c->biweight_pixels_tab[2] = ff_h264_biweight_4_mmxext; } if (EXTERNAL_SSE2(cpu_flags)) { - c->h264_idct8_add = ff_h264_idct8_add_8_sse2; + c->idct8_add = ff_h264_idct8_add_8_sse2; - c->h264_idct_add16 = ff_h264_idct_add16_8_sse2; - c->h264_idct8_add4 = ff_h264_idct8_add4_8_sse2; + c->idct_add16 = ff_h264_idct_add16_8_sse2; + c->idct8_add4 = ff_h264_idct8_add4_8_sse2; if (chroma_format_idc <= 1) - c->h264_idct_add8 = ff_h264_idct_add8_8_sse2; - c->h264_idct_add16intra = ff_h264_idct_add16intra_8_sse2; - c->h264_luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_sse2; + c->idct_add8 = ff_h264_idct_add8_8_sse2; + c->idct_add16intra = ff_h264_idct_add16intra_8_sse2; + c->luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_sse2; - c->weight_h264_pixels_tab[0] = ff_h264_weight_16_sse2; - c->weight_h264_pixels_tab[1] = ff_h264_weight_8_sse2; + c->weight_pixels_tab[0] = ff_h264_weight_16_sse2; + c->weight_pixels_tab[1] = ff_h264_weight_8_sse2; - c->biweight_h264_pixels_tab[0] = ff_h264_biweight_16_sse2; - c->biweight_h264_pixels_tab[1] = ff_h264_biweight_8_sse2; + c->biweight_pixels_tab[0] = ff_h264_biweight_16_sse2; + c->biweight_pixels_tab[1] = ff_h264_biweight_8_sse2; - c->h264_v_loop_filter_luma = ff_deblock_v_luma_8_sse2; - c->h264_h_loop_filter_luma = ff_deblock_h_luma_8_sse2; - c->h264_v_loop_filter_luma_intra = ff_deblock_v_luma_intra_8_sse2; - c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_8_sse2; + c->v_loop_filter_luma = ff_deblock_v_luma_8_sse2; + c->h_loop_filter_luma = ff_deblock_h_luma_8_sse2; + c->v_loop_filter_luma_intra = ff_deblock_v_luma_intra_8_sse2; + c->h_loop_filter_luma_intra = ff_deblock_h_luma_intra_8_sse2; #if ARCH_X86_64 - c->h264_h_loop_filter_luma_mbaff = ff_deblock_h_luma_mbaff_8_sse2; + c->h_loop_filter_luma_mbaff = ff_deblock_h_luma_mbaff_8_sse2; #endif - c->h264_v_loop_filter_chroma = ff_deblock_v_chroma_8_sse2; - c->h264_v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_8_sse2; + c->v_loop_filter_chroma = ff_deblock_v_chroma_8_sse2; + c->v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_8_sse2; if (chroma_format_idc <= 1) { - c->h264_h_loop_filter_chroma = ff_deblock_h_chroma_8_sse2; - c->h264_h_loop_filter_chroma_intra = ff_deblock_h_chroma_intra_8_sse2; + c->h_loop_filter_chroma = ff_deblock_h_chroma_8_sse2; + c->h_loop_filter_chroma_intra = ff_deblock_h_chroma_intra_8_sse2; } else { - c->h264_h_loop_filter_chroma = ff_deblock_h_chroma422_8_sse2; - c->h264_h_loop_filter_chroma_intra = ff_deblock_h_chroma422_intra_8_sse2; + c->h_loop_filter_chroma = ff_deblock_h_chroma422_8_sse2; + c->h_loop_filter_chroma_intra = ff_deblock_h_chroma422_intra_8_sse2; } - c->h264_idct_add = ff_h264_idct_add_8_sse2; - c->h264_idct_dc_add = ff_h264_idct_dc_add_8_sse2; + c->idct_add = ff_h264_idct_add_8_sse2; + c->idct_dc_add = ff_h264_idct_dc_add_8_sse2; } if (EXTERNAL_SSSE3(cpu_flags)) { - c->biweight_h264_pixels_tab[0] = ff_h264_biweight_16_ssse3; - c->biweight_h264_pixels_tab[1] = ff_h264_biweight_8_ssse3; + c->biweight_pixels_tab[0] = ff_h264_biweight_16_ssse3; + c->biweight_pixels_tab[1] = ff_h264_biweight_8_ssse3; } if (EXTERNAL_AVX(cpu_flags)) { - c->h264_v_loop_filter_luma = ff_deblock_v_luma_8_avx; - c->h264_h_loop_filter_luma = ff_deblock_h_luma_8_avx; - c->h264_v_loop_filter_luma_intra = ff_deblock_v_luma_intra_8_avx; - c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_8_avx; + c->v_loop_filter_luma = ff_deblock_v_luma_8_avx; + c->h_loop_filter_luma = ff_deblock_h_luma_8_avx; + c->v_loop_filter_luma_intra = ff_deblock_v_luma_intra_8_avx; + c->h_loop_filter_luma_intra = ff_deblock_h_luma_intra_8_avx; #if ARCH_X86_64 - c->h264_h_loop_filter_luma_mbaff = ff_deblock_h_luma_mbaff_8_avx; + c->h_loop_filter_luma_mbaff = ff_deblock_h_luma_mbaff_8_avx; #endif - c->h264_v_loop_filter_chroma = ff_deblock_v_chroma_8_avx; - c->h264_v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_8_avx; + c->v_loop_filter_chroma = ff_deblock_v_chroma_8_avx; + c->v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_8_avx; if (chroma_format_idc <= 1) { - c->h264_h_loop_filter_chroma = ff_deblock_h_chroma_8_avx; - c->h264_h_loop_filter_chroma_intra = ff_deblock_h_chroma_intra_8_avx; + c->h_loop_filter_chroma = ff_deblock_h_chroma_8_avx; + c->h_loop_filter_chroma_intra = ff_deblock_h_chroma_intra_8_avx; } else { - c->h264_h_loop_filter_chroma = ff_deblock_h_chroma422_8_avx; - c->h264_h_loop_filter_chroma_intra = ff_deblock_h_chroma422_intra_8_avx; + c->h_loop_filter_chroma = ff_deblock_h_chroma422_8_avx; + c->h_loop_filter_chroma_intra = ff_deblock_h_chroma422_intra_8_avx; } - c->h264_idct_add = ff_h264_idct_add_8_avx; - c->h264_idct_dc_add = ff_h264_idct_dc_add_8_avx; + c->idct_add = ff_h264_idct_add_8_avx; + c->idct_dc_add = ff_h264_idct_dc_add_8_avx; } } else if (bit_depth == 10) { if (EXTERNAL_MMXEXT(cpu_flags)) { -#if ARCH_X86_32 && !HAVE_ALIGNED_STACK - c->h264_v_loop_filter_luma = ff_deblock_v_luma_10_mmxext; - c->h264_h_loop_filter_luma = ff_deblock_h_luma_10_mmxext; - c->h264_v_loop_filter_luma_intra = ff_deblock_v_luma_intra_10_mmxext; - c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_10_mmxext; -#endif /* ARCH_X86_32 && !HAVE_ALIGNED_STACK */ - c->h264_idct_dc_add = ff_h264_idct_dc_add_10_mmxext; + c->idct_dc_add = ff_h264_idct_dc_add_10_mmxext; } if (EXTERNAL_SSE2(cpu_flags)) { - c->h264_idct_add = ff_h264_idct_add_10_sse2; - c->h264_idct8_dc_add = ff_h264_idct8_dc_add_10_sse2; + c->idct_add = ff_h264_idct_add_10_sse2; + c->idct8_dc_add = ff_h264_idct8_dc_add_10_sse2; - c->h264_idct_add16 = ff_h264_idct_add16_10_sse2; + c->idct_add16 = ff_h264_idct_add16_10_sse2; if (chroma_format_idc <= 1) { - c->h264_idct_add8 = ff_h264_idct_add8_10_sse2; + c->idct_add8 = ff_h264_idct_add8_10_sse2; } else { - c->h264_idct_add8 = ff_h264_idct_add8_422_10_sse2; + c->idct_add8 = ff_h264_idct_add8_422_10_sse2; } - c->h264_idct_add16intra = ff_h264_idct_add16intra_10_sse2; + c->idct_add16intra = ff_h264_idct_add16intra_10_sse2; #if HAVE_ALIGNED_STACK - c->h264_idct8_add = ff_h264_idct8_add_10_sse2; - c->h264_idct8_add4 = ff_h264_idct8_add4_10_sse2; + c->idct8_add = ff_h264_idct8_add_10_sse2; + c->idct8_add4 = ff_h264_idct8_add4_10_sse2; #endif /* HAVE_ALIGNED_STACK */ - c->weight_h264_pixels_tab[0] = ff_h264_weight_16_10_sse2; - c->weight_h264_pixels_tab[1] = ff_h264_weight_8_10_sse2; - c->weight_h264_pixels_tab[2] = ff_h264_weight_4_10_sse2; + c->weight_pixels_tab[0] = ff_h264_weight_16_10_sse2; + c->weight_pixels_tab[1] = ff_h264_weight_8_10_sse2; + c->weight_pixels_tab[2] = ff_h264_weight_4_10_sse2; - c->biweight_h264_pixels_tab[0] = ff_h264_biweight_16_10_sse2; - c->biweight_h264_pixels_tab[1] = ff_h264_biweight_8_10_sse2; - c->biweight_h264_pixels_tab[2] = ff_h264_biweight_4_10_sse2; + c->biweight_pixels_tab[0] = ff_h264_biweight_16_10_sse2; + c->biweight_pixels_tab[1] = ff_h264_biweight_8_10_sse2; + c->biweight_pixels_tab[2] = ff_h264_biweight_4_10_sse2; - c->h264_v_loop_filter_chroma = ff_deblock_v_chroma_10_sse2; - c->h264_v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_10_sse2; + c->v_loop_filter_chroma = ff_deblock_v_chroma_10_sse2; + c->v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_10_sse2; if (chroma_format_idc <= 1) { - c->h264_h_loop_filter_chroma = ff_deblock_h_chroma_10_sse2; + c->h_loop_filter_chroma = ff_deblock_h_chroma_10_sse2; } else { - c->h264_h_loop_filter_chroma = ff_deblock_h_chroma422_10_sse2; + c->h_loop_filter_chroma = ff_deblock_h_chroma422_10_sse2; } -#if HAVE_ALIGNED_STACK - c->h264_v_loop_filter_luma = ff_deblock_v_luma_10_sse2; - c->h264_h_loop_filter_luma = ff_deblock_h_luma_10_sse2; - c->h264_v_loop_filter_luma_intra = ff_deblock_v_luma_intra_10_sse2; - c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_10_sse2; -#endif /* HAVE_ALIGNED_STACK */ + c->v_loop_filter_luma = ff_deblock_v_luma_10_sse2; + c->h_loop_filter_luma = ff_deblock_h_luma_10_sse2; + c->v_loop_filter_luma_intra = ff_deblock_v_luma_intra_10_sse2; + c->h_loop_filter_luma_intra = ff_deblock_h_luma_intra_10_sse2; } if (EXTERNAL_SSE4(cpu_flags)) { - c->weight_h264_pixels_tab[0] = ff_h264_weight_16_10_sse4; - c->weight_h264_pixels_tab[1] = ff_h264_weight_8_10_sse4; - c->weight_h264_pixels_tab[2] = ff_h264_weight_4_10_sse4; + c->weight_pixels_tab[0] = ff_h264_weight_16_10_sse4; + c->weight_pixels_tab[1] = ff_h264_weight_8_10_sse4; + c->weight_pixels_tab[2] = ff_h264_weight_4_10_sse4; - c->biweight_h264_pixels_tab[0] = ff_h264_biweight_16_10_sse4; - c->biweight_h264_pixels_tab[1] = ff_h264_biweight_8_10_sse4; - c->biweight_h264_pixels_tab[2] = ff_h264_biweight_4_10_sse4; + c->biweight_pixels_tab[0] = ff_h264_biweight_16_10_sse4; + c->biweight_pixels_tab[1] = ff_h264_biweight_8_10_sse4; + c->biweight_pixels_tab[2] = ff_h264_biweight_4_10_sse4; } if (EXTERNAL_AVX(cpu_flags)) { - c->h264_idct_dc_add = - c->h264_idct_add = ff_h264_idct_add_10_avx; - c->h264_idct8_dc_add = ff_h264_idct8_dc_add_10_avx; + c->idct_dc_add = + c->idct_add = ff_h264_idct_add_10_avx; + c->idct8_dc_add = ff_h264_idct8_dc_add_10_avx; - c->h264_idct_add16 = ff_h264_idct_add16_10_avx; + c->idct_add16 = ff_h264_idct_add16_10_avx; if (chroma_format_idc <= 1) { - c->h264_idct_add8 = ff_h264_idct_add8_10_avx; + c->idct_add8 = ff_h264_idct_add8_10_avx; } else { - c->h264_idct_add8 = ff_h264_idct_add8_422_10_avx; + c->idct_add8 = ff_h264_idct_add8_422_10_avx; } - c->h264_idct_add16intra = ff_h264_idct_add16intra_10_avx; + c->idct_add16intra = ff_h264_idct_add16intra_10_avx; #if HAVE_ALIGNED_STACK - c->h264_idct8_add = ff_h264_idct8_add_10_avx; - c->h264_idct8_add4 = ff_h264_idct8_add4_10_avx; + c->idct8_add = ff_h264_idct8_add_10_avx; + c->idct8_add4 = ff_h264_idct8_add4_10_avx; #endif /* HAVE_ALIGNED_STACK */ - c->h264_v_loop_filter_chroma = ff_deblock_v_chroma_10_avx; - c->h264_v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_10_avx; + c->v_loop_filter_chroma = ff_deblock_v_chroma_10_avx; + c->v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_10_avx; if (chroma_format_idc <= 1) { - c->h264_h_loop_filter_chroma = ff_deblock_h_chroma_10_avx; + c->h_loop_filter_chroma = ff_deblock_h_chroma_10_avx; } else { - c->h264_h_loop_filter_chroma = ff_deblock_h_chroma422_10_avx; + c->h_loop_filter_chroma = ff_deblock_h_chroma422_10_avx; } -#if HAVE_ALIGNED_STACK - c->h264_v_loop_filter_luma = ff_deblock_v_luma_10_avx; - c->h264_h_loop_filter_luma = ff_deblock_h_luma_10_avx; - c->h264_v_loop_filter_luma_intra = ff_deblock_v_luma_intra_10_avx; - c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_10_avx; -#endif /* HAVE_ALIGNED_STACK */ + c->v_loop_filter_luma = ff_deblock_v_luma_10_avx; + c->h_loop_filter_luma = ff_deblock_h_luma_10_avx; + c->v_loop_filter_luma_intra = ff_deblock_v_luma_intra_10_avx; + c->h_loop_filter_luma_intra = ff_deblock_h_luma_intra_10_avx; } } -#endif } diff --git a/libavcodec/x86/h26x/h2656_inter.asm b/libavcodec/x86/h26x/h2656_inter.asm index cbba0c1ea..49a95d58f 100644 --- a/libavcodec/x86/h26x/h2656_inter.asm +++ b/libavcodec/x86/h26x/h2656_inter.asm @@ -1126,7 +1126,6 @@ H2656PUT_8TAP 32, 8 H2656PUT_8TAP 16, 10 H2656PUT_8TAP 16, 12 -H2656PUT_8TAP_HV 32, 8 H2656PUT_8TAP_HV 16, 10 H2656PUT_8TAP_HV 16, 12 diff --git a/libavcodec/x86/hevc_sao.asm b/libavcodec/x86/h26x/h2656_sao.asm similarity index 77% rename from libavcodec/x86/hevc_sao.asm rename to libavcodec/x86/h26x/h2656_sao.asm index 8abb16150..a80ee2617 100644 --- a/libavcodec/x86/hevc_sao.asm +++ b/libavcodec/x86/h26x/h2656_sao.asm @@ -1,5 +1,5 @@ ;****************************************************************************** -;* SIMD optimized SAO functions for HEVC 8bit decoding +;* SIMD optimized SAO functions for HEVC/VVC 8bit decoding ;* ;* Copyright (c) 2013 Pierre-Edouard LEPERE ;* Copyright (c) 2014 James Almer @@ -36,7 +36,7 @@ SECTION .text ;SAO Band Filter ;****************************************************************************** -%macro HEVC_SAO_BAND_FILTER_INIT 0 +%macro H2656_SAO_BAND_FILTER_INIT 0 and leftq, 31 movd xm0, leftd add leftq, 1 @@ -88,7 +88,7 @@ DEFINE_ARGS dst, src, dststride, srcstride, offset, height mov heightd, r7m %endmacro -%macro HEVC_SAO_BAND_FILTER_COMPUTE 2 +%macro H2656_SAO_BAND_FILTER_COMPUTE 2 psraw %1, %2, 3 %if ARCH_X86_64 pcmpeqw m10, %1, m0 @@ -119,48 +119,48 @@ DEFINE_ARGS dst, src, dststride, srcstride, offset, height %endif ; ARCH %endmacro -;void ff_hevc_sao_band_filter__8_(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, +;void ff_{hevc, vvc}_sao_band_filter__8_(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, ; int16_t *sao_offset_val, int sao_left_class, int width, int height); -%macro HEVC_SAO_BAND_FILTER 2 -cglobal hevc_sao_band_filter_%1_8, 6, 6, 15, 7*mmsize*ARCH_X86_32, dst, src, dststride, srcstride, offset, left - HEVC_SAO_BAND_FILTER_INIT +%macro H2656_SAO_BAND_FILTER 3 +cglobal %1_sao_band_filter_%2_8, 6, 6, 15, 7*mmsize*ARCH_X86_32, dst, src, dststride, srcstride, offset, left + H2656_SAO_BAND_FILTER_INIT align 16 .loop: -%if %1 == 8 +%if %2 == 8 movq m8, [srcq] punpcklbw m8, m14 - HEVC_SAO_BAND_FILTER_COMPUTE m9, m8 + H2656_SAO_BAND_FILTER_COMPUTE m9, m8 packuswb m8, m14 movq [dstq], m8 -%endif ; %1 == 8 +%endif ; %2 == 8 %assign i 0 -%rep %2 +%rep %3 mova m13, [srcq + i] punpcklbw m8, m13, m14 - HEVC_SAO_BAND_FILTER_COMPUTE m9, m8 + H2656_SAO_BAND_FILTER_COMPUTE m9, m8 punpckhbw m13, m14 - HEVC_SAO_BAND_FILTER_COMPUTE m9, m13 + H2656_SAO_BAND_FILTER_COMPUTE m9, m13 packuswb m8, m13 mova [dstq + i], m8 %assign i i+mmsize %endrep -%if %1 == 48 +%if %2 == 48 || %2 == 80 || %2 == 112 INIT_XMM cpuname mova m13, [srcq + i] punpcklbw m8, m13, m14 - HEVC_SAO_BAND_FILTER_COMPUTE m9, m8 + H2656_SAO_BAND_FILTER_COMPUTE m9, m8 punpckhbw m13, m14 - HEVC_SAO_BAND_FILTER_COMPUTE m9, m13 + H2656_SAO_BAND_FILTER_COMPUTE m9, m13 packuswb m8, m13 mova [dstq + i], m8 %if cpuflag(avx2) INIT_YMM cpuname %endif -%endif ; %1 == 48 +%endif ; %2 == 48 || %2 == 80 || %2 == 112 add dstq, dststrideq ; dst += dststride add srcq, srcstrideq ; src += srcstride @@ -169,39 +169,14 @@ INIT_YMM cpuname RET %endmacro - -%macro HEVC_SAO_BAND_FILTER_FUNCS 0 -HEVC_SAO_BAND_FILTER 8, 0 -HEVC_SAO_BAND_FILTER 16, 1 -HEVC_SAO_BAND_FILTER 32, 2 -HEVC_SAO_BAND_FILTER 48, 2 -HEVC_SAO_BAND_FILTER 64, 4 -%endmacro - -INIT_XMM sse2 -HEVC_SAO_BAND_FILTER_FUNCS -INIT_XMM avx -HEVC_SAO_BAND_FILTER_FUNCS - -%if HAVE_AVX2_EXTERNAL -INIT_XMM avx2 -HEVC_SAO_BAND_FILTER 8, 0 -HEVC_SAO_BAND_FILTER 16, 1 -INIT_YMM avx2 -HEVC_SAO_BAND_FILTER 32, 1 -HEVC_SAO_BAND_FILTER 48, 1 -HEVC_SAO_BAND_FILTER 64, 2 -%endif - ;****************************************************************************** ;SAO Edge Filter ;****************************************************************************** -%define MAX_PB_SIZE 64 %define PADDING_SIZE 64 ; AV_INPUT_BUFFER_PADDING_SIZE %define EDGE_SRCSTRIDE 2 * MAX_PB_SIZE + PADDING_SIZE -%macro HEVC_SAO_EDGE_FILTER_INIT 0 +%macro H2656_SAO_EDGE_FILTER_INIT 0 %if WIN64 movsxd eoq, dword eom %elif ARCH_X86_64 @@ -220,7 +195,7 @@ HEVC_SAO_BAND_FILTER 64, 2 add b_strideq, tmpq %endmacro -%macro HEVC_SAO_EDGE_FILTER_COMPUTE 1 +%macro H2656_SAO_EDGE_FILTER_COMPUTE 1 pminub m4, m1, m2 pminub m5, m1, m3 pcmpeqb m2, m4 @@ -249,22 +224,22 @@ HEVC_SAO_BAND_FILTER 64, 2 %endif %endmacro -;void ff_hevc_sao_edge_filter__8_(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, +;void ff_{hevc, vvc}_sao_edge_filter__8_(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, ; int eo, int width, int height); -%macro HEVC_SAO_EDGE_FILTER 2-3 +%macro H2656_SAO_EDGE_FILTER 3-4 %if ARCH_X86_64 -cglobal hevc_sao_edge_filter_%1_8, 4, 9, 8, dst, src, dststride, offset, eo, a_stride, b_stride, height, tmp +cglobal %1_sao_edge_filter_%2_8, 4, 9, 8, dst, src, dststride, offset, eo, a_stride, b_stride, height, tmp %define tmp2q heightq - HEVC_SAO_EDGE_FILTER_INIT + H2656_SAO_EDGE_FILTER_INIT mov heightd, r6m %else ; ARCH_X86_32 -cglobal hevc_sao_edge_filter_%1_8, 1, 6, 8, dst, src, dststride, a_stride, b_stride, height +cglobal %1_sao_edge_filter_%2_8, 1, 6, 8, dst, src, dststride, a_stride, b_stride, height %define eoq srcq %define tmpq heightq %define tmp2q dststrideq %define offsetq heightq - HEVC_SAO_EDGE_FILTER_INIT + H2656_SAO_EDGE_FILTER_INIT mov srcq, srcm mov offsetq, r3m mov dststrideq, dststridem @@ -287,36 +262,36 @@ cglobal hevc_sao_edge_filter_%1_8, 1, 6, 8, dst, src, dststride, a_stride, b_str align 16 .loop: -%if %1 == 8 +%if %2 == 8 movq m1, [srcq] movq m2, [srcq + a_strideq] movq m3, [srcq + b_strideq] - HEVC_SAO_EDGE_FILTER_COMPUTE %1 + H2656_SAO_EDGE_FILTER_COMPUTE %2 movq [dstq], m3 %endif %assign i 0 -%rep %2 +%rep %3 mova m1, [srcq + i] movu m2, [srcq + a_strideq + i] movu m3, [srcq + b_strideq + i] - HEVC_SAO_EDGE_FILTER_COMPUTE %1 - mov%3 [dstq + i], m3 + H2656_SAO_EDGE_FILTER_COMPUTE %2 + mov%4 [dstq + i], m3 %assign i i+mmsize %endrep -%if %1 == 48 +%if %2 == 48 || %2 == 80 || %2 == 112 INIT_XMM cpuname mova m1, [srcq + i] movu m2, [srcq + a_strideq + i] movu m3, [srcq + b_strideq + i] - HEVC_SAO_EDGE_FILTER_COMPUTE %1 + H2656_SAO_EDGE_FILTER_COMPUTE %2 mova [dstq + i], m3 %if cpuflag(avx2) INIT_YMM cpuname %endif -%endif +%endif ; %2 == 48 || %2 == 80 || %2 == 112 add dstq, dststrideq add srcq, EDGE_SRCSTRIDE @@ -324,17 +299,3 @@ INIT_YMM cpuname jg .loop RET %endmacro - -INIT_XMM ssse3 -HEVC_SAO_EDGE_FILTER 8, 0 -HEVC_SAO_EDGE_FILTER 16, 1, a -HEVC_SAO_EDGE_FILTER 32, 2, a -HEVC_SAO_EDGE_FILTER 48, 2, a -HEVC_SAO_EDGE_FILTER 64, 4, a - -%if HAVE_AVX2_EXTERNAL -INIT_YMM avx2 -HEVC_SAO_EDGE_FILTER 32, 1, a -HEVC_SAO_EDGE_FILTER 48, 1, u -HEVC_SAO_EDGE_FILTER 64, 2, a -%endif diff --git a/libavcodec/x86/hevc_sao_10bit.asm b/libavcodec/x86/h26x/h2656_sao_10bit.asm similarity index 75% rename from libavcodec/x86/hevc_sao_10bit.asm rename to libavcodec/x86/h26x/h2656_sao_10bit.asm index 0daa9c645..052f2b1d1 100644 --- a/libavcodec/x86/hevc_sao_10bit.asm +++ b/libavcodec/x86/h26x/h2656_sao_10bit.asm @@ -1,5 +1,5 @@ ;****************************************************************************** -;* SIMD optimized SAO functions for HEVC 10/12bit decoding +;* SIMD optimized SAO functions for HEVC/VVC 10/12bit decoding ;* ;* Copyright (c) 2013 Pierre-Edouard LEPERE ;* Copyright (c) 2014 James Almer @@ -39,7 +39,7 @@ SECTION .text ;SAO Band Filter ;****************************************************************************** -%macro HEVC_SAO_BAND_FILTER_INIT 1 +%macro H2656_SAO_BAND_FILTER_INIT 1 and leftq, 31 movd xm0, leftd add leftq, 1 @@ -92,22 +92,22 @@ DEFINE_ARGS dst, src, dststride, srcstride, offset, height mov heightd, r7m %endmacro -;void ff_hevc_sao_band_filter___(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, +;void ff_{hevc, vvc}_sao_band_filter___(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, ; int16_t *sao_offset_val, int sao_left_class, int width, int height); -%macro HEVC_SAO_BAND_FILTER 3 -cglobal hevc_sao_band_filter_%2_%1, 6, 6, 15, 7*mmsize*ARCH_X86_32, dst, src, dststride, srcstride, offset, left - HEVC_SAO_BAND_FILTER_INIT %1 +%macro H2656_SAO_BAND_FILTER 4 +cglobal %1_sao_band_filter_%3_%2, 6, 6, 15, 7*mmsize*ARCH_X86_32, dst, src, dststride, srcstride, offset, left + H2656_SAO_BAND_FILTER_INIT %2 align 16 .loop: %assign i 0 %assign j 0 -%rep %3 +%rep %4 %assign k 8+(j&1) %assign l 9-(j&1) mova m %+ k, [srcq + i] - psraw m %+ l, m %+ k, %1-5 + psraw m %+ l, m %+ k, %2-5 %if ARCH_X86_64 pcmpeqw m10, m %+ l, m0 pcmpeqw m11, m %+ l, m1 @@ -148,48 +148,10 @@ align 16 RET %endmacro -%macro HEVC_SAO_BAND_FILTER_FUNCS 0 -HEVC_SAO_BAND_FILTER 10, 8, 1 -HEVC_SAO_BAND_FILTER 10, 16, 2 -HEVC_SAO_BAND_FILTER 10, 32, 4 -HEVC_SAO_BAND_FILTER 10, 48, 6 -HEVC_SAO_BAND_FILTER 10, 64, 8 - -HEVC_SAO_BAND_FILTER 12, 8, 1 -HEVC_SAO_BAND_FILTER 12, 16, 2 -HEVC_SAO_BAND_FILTER 12, 32, 4 -HEVC_SAO_BAND_FILTER 12, 48, 6 -HEVC_SAO_BAND_FILTER 12, 64, 8 -%endmacro - -INIT_XMM sse2 -HEVC_SAO_BAND_FILTER_FUNCS -INIT_XMM avx -HEVC_SAO_BAND_FILTER_FUNCS - -%if HAVE_AVX2_EXTERNAL -INIT_XMM avx2 -HEVC_SAO_BAND_FILTER 10, 8, 1 -INIT_YMM avx2 -HEVC_SAO_BAND_FILTER 10, 16, 1 -HEVC_SAO_BAND_FILTER 10, 32, 2 -HEVC_SAO_BAND_FILTER 10, 48, 3 -HEVC_SAO_BAND_FILTER 10, 64, 4 - -INIT_XMM avx2 -HEVC_SAO_BAND_FILTER 12, 8, 1 -INIT_YMM avx2 -HEVC_SAO_BAND_FILTER 12, 16, 1 -HEVC_SAO_BAND_FILTER 12, 32, 2 -HEVC_SAO_BAND_FILTER 12, 48, 3 -HEVC_SAO_BAND_FILTER 12, 64, 4 -%endif - ;****************************************************************************** ;SAO Edge Filter ;****************************************************************************** -%define MAX_PB_SIZE 64 %define PADDING_SIZE 64 ; AV_INPUT_BUFFER_PADDING_SIZE %define EDGE_SRCSTRIDE 2 * MAX_PB_SIZE + PADDING_SIZE @@ -202,7 +164,7 @@ HEVC_SAO_BAND_FILTER 12, 64, 4 %endif %endmacro -%macro HEVC_SAO_EDGE_FILTER_INIT 0 +%macro H2656_SAO_EDGE_FILTER_INIT 0 %if WIN64 movsxd eoq, dword eom %elif ARCH_X86_64 @@ -221,19 +183,19 @@ HEVC_SAO_BAND_FILTER 12, 64, 4 add b_strideq, tmpq %endmacro -;void ff_hevc_sao_edge_filter___(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, +;void ff_{hevc, vvc}_sao_edge_filter___(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, ; int eo, int width, int height); -%macro HEVC_SAO_EDGE_FILTER 3 +%macro H2656_SAO_EDGE_FILTER 4 %if ARCH_X86_64 -cglobal hevc_sao_edge_filter_%2_%1, 4, 9, 16, dst, src, dststride, offset, eo, a_stride, b_stride, height, tmp +cglobal %1_sao_edge_filter_%3_%2, 4, 9, 16, dst, src, dststride, offset, eo, a_stride, b_stride, height, tmp %define tmp2q heightq - HEVC_SAO_EDGE_FILTER_INIT + H2656_SAO_EDGE_FILTER_INIT mov heightd, r6m add a_strideq, a_strideq add b_strideq, b_strideq %else ; ARCH_X86_32 -cglobal hevc_sao_edge_filter_%2_%1, 1, 6, 8, 5*mmsize, dst, src, dststride, a_stride, b_stride, height +cglobal %1_sao_edge_filter_%3_%2, 1, 6, 8, 5*mmsize, dst, src, dststride, a_stride, b_stride, height %define eoq srcq %define tmpq heightq %define tmp2q dststrideq @@ -243,7 +205,7 @@ cglobal hevc_sao_edge_filter_%2_%1, 1, 6, 8, 5*mmsize, dst, src, dststride, a_st %define m10 m3 %define m11 m4 %define m12 m5 - HEVC_SAO_EDGE_FILTER_INIT + H2656_SAO_EDGE_FILTER_INIT mov srcq, srcm mov offsetq, r3m mov dststrideq, dststridem @@ -285,7 +247,7 @@ align 16 .loop: %assign i 0 -%rep %3 +%rep %4 mova m1, [srcq + i] movu m2, [srcq+a_strideq + i] movu m3, [srcq+b_strideq + i] @@ -326,7 +288,7 @@ align 16 paddw m2, m7 paddw m2, m1 paddw m2, m5 - CLIPW m2, m0, [pw_mask %+ %1] + CLIPW m2, m0, [pw_mask %+ %2] mova [dstq + i], m2 %assign i i+mmsize %endrep @@ -337,34 +299,3 @@ align 16 jg .loop RET %endmacro - -INIT_XMM sse2 -HEVC_SAO_EDGE_FILTER 10, 8, 1 -HEVC_SAO_EDGE_FILTER 10, 16, 2 -HEVC_SAO_EDGE_FILTER 10, 32, 4 -HEVC_SAO_EDGE_FILTER 10, 48, 6 -HEVC_SAO_EDGE_FILTER 10, 64, 8 - -HEVC_SAO_EDGE_FILTER 12, 8, 1 -HEVC_SAO_EDGE_FILTER 12, 16, 2 -HEVC_SAO_EDGE_FILTER 12, 32, 4 -HEVC_SAO_EDGE_FILTER 12, 48, 6 -HEVC_SAO_EDGE_FILTER 12, 64, 8 - -%if HAVE_AVX2_EXTERNAL -INIT_XMM avx2 -HEVC_SAO_EDGE_FILTER 10, 8, 1 -INIT_YMM avx2 -HEVC_SAO_EDGE_FILTER 10, 16, 1 -HEVC_SAO_EDGE_FILTER 10, 32, 2 -HEVC_SAO_EDGE_FILTER 10, 48, 3 -HEVC_SAO_EDGE_FILTER 10, 64, 4 - -INIT_XMM avx2 -HEVC_SAO_EDGE_FILTER 12, 8, 1 -INIT_YMM avx2 -HEVC_SAO_EDGE_FILTER 12, 16, 1 -HEVC_SAO_EDGE_FILTER 12, 32, 2 -HEVC_SAO_EDGE_FILTER 12, 48, 3 -HEVC_SAO_EDGE_FILTER 12, 64, 4 -%endif diff --git a/libavcodec/x86/h26x/h2656dsp.c b/libavcodec/x86/h26x/h2656dsp.c index c402f9e21..1d8ec1898 100644 --- a/libavcodec/x86/h26x/h2656dsp.c +++ b/libavcodec/x86/h26x/h2656dsp.c @@ -80,9 +80,7 @@ mc_rep_funcs(8tap_hv, 8, 8, 16, sse4) #if HAVE_AVX2_EXTERNAL -#define MC_REP_FUNCS_AVX2(fname) \ - mc_rep_funcs(fname, 8, 32, 64, avx2) \ - mc_rep_funcs(fname, 8, 32,128, avx2) \ +#define MC_REP_FUNCS_AVX2_NO8(fname) \ mc_rep_funcs(fname,10, 16, 32, avx2) \ mc_rep_funcs(fname,10, 16, 64, avx2) \ mc_rep_funcs(fname,10, 16,128, avx2) \ @@ -90,12 +88,17 @@ mc_rep_funcs(8tap_hv, 8, 8, 16, sse4) mc_rep_funcs(fname,12, 16, 64, avx2) \ mc_rep_funcs(fname,12, 16,128, avx2) \ +#define MC_REP_FUNCS_AVX2(fname) \ + mc_rep_funcs(fname, 8, 32, 64, avx2) \ + mc_rep_funcs(fname, 8, 32,128, avx2) \ + MC_REP_FUNCS_AVX2_NO8(fname) + MC_REP_FUNCS_AVX2(pixels) MC_REP_FUNCS_AVX2(8tap_h) MC_REP_FUNCS_AVX2(8tap_v) -MC_REP_FUNCS_AVX2(8tap_hv) +MC_REP_FUNCS_AVX2_NO8(8tap_hv) MC_REP_FUNCS_AVX2(4tap_h) MC_REP_FUNCS_AVX2(4tap_v) -MC_REP_FUNCS_AVX2(4tap_hv) +MC_REP_FUNCS_AVX2_NO8(4tap_hv) #endif #endif diff --git a/libavcodec/x86/hevc/Makefile b/libavcodec/x86/hevc/Makefile new file mode 100644 index 000000000..d09c613a1 --- /dev/null +++ b/libavcodec/x86/hevc/Makefile @@ -0,0 +1,13 @@ +clean:: + $(RM) $(CLEANSUFFIXES:%=libavcodec/x86/hevc/%) $(CLEANSUFFIXES:%=libavcodec/x86/h26x/%) + +X86ASM-OBJS-$(CONFIG_HEVC_DECODER) += x86/hevc/dsp_init.o \ + x86/hevc/add_res.o \ + x86/hevc/deblock.o \ + x86/hevc/dequant.o \ + x86/hevc/idct.o \ + x86/hevc/mc.o \ + x86/hevc/sao.o \ + x86/hevc/sao_10bit.o \ + x86/h26x/h2656dsp.o \ + x86/h26x/h2656_inter.o diff --git a/libavcodec/x86/hevc_add_res.asm b/libavcodec/x86/hevc/add_res.asm similarity index 91% rename from libavcodec/x86/hevc_add_res.asm rename to libavcodec/x86/hevc/add_res.asm index 3ecbd4269..3489e04e2 100644 --- a/libavcodec/x86/hevc_add_res.asm +++ b/libavcodec/x86/hevc/add_res.asm @@ -27,9 +27,9 @@ cextern pw_1023 %define max_pixels_10 pw_1023 ; the add_res macros and functions were largely inspired by h264_idct.asm from the x264 project -%macro ADD_RES_MMX_4_8 0 - mova m0, [r1] - mova m2, [r1+8] +%macro ADD_RES_MMX_4_8 1 + mova m0, [r1+%1] + mova m2, [r1+%1+8] movd m1, [r0] movd m3, [r0+r2] @@ -50,31 +50,26 @@ INIT_MMX mmxext ; void ff_hevc_add_residual_4_8_mmxext(uint8_t *dst, const int16_t *res, ptrdiff_t stride) cglobal hevc_add_residual_4_8, 3, 3, 6 pxor m4, m4 - ADD_RES_MMX_4_8 - add r1, 16 + ADD_RES_MMX_4_8 0 lea r0, [r0+r2*2] - ADD_RES_MMX_4_8 + ADD_RES_MMX_4_8 16 RET -%macro ADD_RES_SSE_8_8 0 +%macro ADD_RES_SSE_8_8 1 movq m0, [r0] movq m1, [r0+r2] punpcklbw m0, m4 punpcklbw m1, m4 - mova m2, [r1] - mova m3, [r1+16] - paddsw m0, m2 - paddsw m1, m3 + paddsw m0, [r1+%1] + paddsw m1, [r1+%1+16] packuswb m0, m1 movq m2, [r0+r2*2] movq m3, [r0+r3] punpcklbw m2, m4 punpcklbw m3, m4 - mova m6, [r1+32] - mova m7, [r1+48] - paddsw m2, m6 - paddsw m3, m7 + paddsw m2, [r1+%1+32] + paddsw m3, [r1+%1+48] packuswb m2, m3 movq [r0], m0 @@ -88,27 +83,33 @@ cglobal hevc_add_residual_4_8, 3, 3, 6 mova m2, m1 punpcklbw m1, m0 punpckhbw m2, m0 +%if cpuflag(avx2) mova xm5, [r1+%1] mova xm6, [r1+%1+16] -%if cpuflag(avx2) vinserti128 m5, m5, [r1+%1+32], 1 vinserti128 m6, m6, [r1+%1+48], 1 -%endif paddsw m1, m5 paddsw m2, m6 +%else + paddsw m1, [r1+%1] + paddsw m2, [r1+%1+16] +%endif mova m3, [%3] mova m4, m3 punpcklbw m3, m0 punpckhbw m4, m0 +%if cpuflag(avx2) mova xm5, [r1+%1+mmsize*2] mova xm6, [r1+%1+mmsize*2+16] -%if cpuflag(avx2) vinserti128 m5, m5, [r1+%1+96], 1 vinserti128 m6, m6, [r1+%1+112], 1 -%endif paddsw m3, m5 paddsw m4, m6 +%else + paddsw m3, [r1+%1+mmsize*2] + paddsw m4, [r1+%1+mmsize*2+16] +%endif packuswb m1, m2 packuswb m3, m4 @@ -117,19 +118,18 @@ cglobal hevc_add_residual_4_8, 3, 3, 6 %endmacro -%macro TRANSFORM_ADD_8 0 +INIT_XMM sse2 ; void ff_hevc_add_residual_8_8_(uint8_t *dst, const int16_t *res, ptrdiff_t stride) -cglobal hevc_add_residual_8_8, 3, 4, 8 +cglobal hevc_add_residual_8_8, 3, 4, 5 pxor m4, m4 lea r3, [r2*3] - ADD_RES_SSE_8_8 - add r1, 64 + ADD_RES_SSE_8_8 0 lea r0, [r0+r2*4] - ADD_RES_SSE_8_8 + ADD_RES_SSE_8_8 64 RET ; void ff_hevc_add_residual_16_8_(uint8_t *dst, const int16_t *res, ptrdiff_t stride) -cglobal hevc_add_residual_16_8, 3, 5, 7 +cglobal hevc_add_residual_16_8, 3, 5, 5 pxor m0, m0 lea r3, [r2*3] mov r4d, 4 @@ -143,7 +143,7 @@ cglobal hevc_add_residual_16_8, 3, 5, 7 RET ; void ff_hevc_add_residual_32_8_(uint8_t *dst, const int16_t *res, ptrdiff_t stride) -cglobal hevc_add_residual_32_8, 3, 5, 7 +cglobal hevc_add_residual_32_8, 3, 5, 5 pxor m0, m0 mov r4d, 16 .loop: @@ -154,12 +154,7 @@ cglobal hevc_add_residual_32_8, 3, 5, 7 dec r4d jg .loop RET -%endmacro -INIT_XMM sse2 -TRANSFORM_ADD_8 -INIT_XMM avx -TRANSFORM_ADD_8 %if HAVE_AVX2_EXTERNAL INIT_YMM avx2 @@ -295,9 +290,8 @@ cglobal hevc_add_residual_4_10, 3, 3, 6 pxor m2, m2 mova m3, [max_pixels_10] ADD_RES_MMX_4_10 r0, r2, r1 - add r1, 16 lea r0, [r0+2*r2] - ADD_RES_MMX_4_10 r0, r2, r1 + ADD_RES_MMX_4_10 r0, r2, r1+16 RET INIT_XMM sse2 @@ -308,8 +302,7 @@ cglobal hevc_add_residual_8_10, 3, 4, 6 ADD_RES_SSE_8_10 r0, r2, r3, r1 lea r0, [r0+r2*4] - add r1, 64 - ADD_RES_SSE_8_10 r0, r2, r3, r1 + ADD_RES_SSE_8_10 r0, r2, r3, r1+64 RET cglobal hevc_add_residual_16_10, 3, 5, 6 diff --git a/libavcodec/x86/hevc_deblock.asm b/libavcodec/x86/hevc/deblock.asm similarity index 92% rename from libavcodec/x86/hevc_deblock.asm rename to libavcodec/x86/hevc/deblock.asm index 61b79f807..d43d95142 100644 --- a/libavcodec/x86/hevc_deblock.asm +++ b/libavcodec/x86/hevc/deblock.asm @@ -257,8 +257,7 @@ INIT_XMM sse2 %macro MASKED_COPY 2 pand %2, m11 ; and mask pandn m10, m11, %1; and -mask - por %2, m10 - mova %1, %2 + por %1, %2, m10 %endmacro ; in: %2 clobbered @@ -267,8 +266,7 @@ INIT_XMM sse2 %macro MASKED_COPY2 3 pand %2, %3 ; and mask pandn %3, %1; and -mask - por %2, %3 - mova %1, %2 + por %1, %2, %3 %endmacro ALIGN 16 @@ -335,8 +333,8 @@ ALIGN 16 ;compare pcmpgtw m15, m13, m14 - movmskps r13, m15 ;filtering mask 0d0 + 0d3 < beta0 (bit 2 or 3) , 1d0 + 1d3 < beta1 (bit 0 or 1) - test r13, r13 + movmskps r10, m15 ;filtering mask 0d0 + 0d3 < beta0 (bit 2 or 3) , 1d0 + 1d3 < beta1 (bit 0 or 1) + test r10d, r10d je .bypassluma ;weak / strong decision compare to beta_2 @@ -347,45 +345,41 @@ ALIGN 16 ;end weak / strong decision ; weak filter nd_p/q calculation - pshufd m8, m10, 0x31 - psrld m8, 16 + psrlq m8, m10, 48 paddw m8, m10 - movd r7d, m8 - pshufd m8, m8, 0x4E - movd r8d, m8 + pshufd m8, m8, 0x8 + movq r7q, m8 - pshufd m8, m11, 0x31 - psrld m8, 16 + psrlq m8, m11, 48 paddw m8, m11 - movd r9d, m8 - pshufd m8, m8, 0x4E - movd r10d, m8 + pshufd m8, m8, 0x8 + movq r8q, m8 ; end calc for weak filter ; filtering mask - mov r11, r13 - shr r11, 3 - movd m15, r11d - and r13, 1 - movd m11, r13d + mov r9, r10 + shr r9d, 3 + movd m15, r9d + and r10d, 1 + movd m11, r10d shufps m11, m15, 0 - shl r11, 1 - or r13, r11 + shl r9d, 1 + or r10d, r9d pcmpeqd m11, [pd_1]; filtering mask ;decide between strong and weak filtering ;tc25 calculations - mov r11d, [tcq]; + mov r9d, [tcq]; %if %1 > 8 - shl r11, %1 - 8 + shl r9d, %1 - 8 %endif - movd m8, r11d; tc0 + movd m8, r9d; tc0 mov r3d, [tcq+4]; %if %1 > 8 - shl r3, %1 - 8 + shl r3d, %1 - 8 %endif - add r11d, r3d; tc0 + tc1 + add r9d, r3d; tc0 + tc1 jz .bypassluma movd m9, r3d; tc1 punpcklwd m8, m8 @@ -410,8 +404,8 @@ ALIGN 16 psraw m13, 3; beta >> 3 pcmpgtw m13, m12; - movmskps r11, m13; - and r6, r11; strong mask , beta_2 and beta_3 comparisons + movmskps r9d, m13; + and r6d, r9d; strong mask , beta_2 and beta_3 comparisons ;----beta_3 comparison end----- ;----tc25 comparison--- psubw m12, m3, m4; p0 - q0 @@ -421,24 +415,24 @@ ALIGN 16 pshuflw m12, m12, 0xf0 ;0b11110000; pcmpgtw m8, m12; tc25 comparisons - movmskps r11, m8; - and r6, r11; strong mask, beta_2, beta_3 and tc25 comparisons + movmskps r9d, m8; + and r6d, r9d; strong mask, beta_2, beta_3 and tc25 comparisons ;----tc25 comparison end--- - mov r11, r6; - shr r11, 1; - and r6, r11; strong mask, bits 2 and 0 + mov r9d, r6d; + shr r9d, 1; + and r6d, r9d; strong mask, bits 2 and 0 pmullw m14, m9, [pw_m2]; -tc * 2 paddw m9, m9 and r6, 5; 0b101 - mov r11, r6; strong mask + mov r9d, r6d; strong mask shr r6, 2; movd m12, r6d; store to xmm for mask generation shl r6, 1 - and r11, 1 - movd m10, r11d; store to xmm for mask generation - or r6, r11; final strong mask, bits 1 and 0 + and r9d, 1 + movd m10, r9d; store to xmm for mask generation + or r6d, r9d; final strong mask, bits 1 and 0 jz .weakfilter shufps m10, m12, 0 @@ -524,21 +518,21 @@ ALIGN 16 .weakfilter: not r6; strong mask -> weak mask - and r6, r13; final weak filtering mask, bits 0 and 1 + and r6d, r10d; final weak filtering mask, bits 0 and 1 jz .store ; weak filtering mask - mov r11, r6 - shr r11, 1 - movd m12, r11d + mov r9, r6 + shr r9d, 1 + movd m12, r9d and r6, 1 movd m11, r6d shufps m11, m12, 0 pcmpeqd m11, [pd_1]; filtering mask - mov r13, betaq - shr r13, 1; - add betaq, r13 + mov r10d, betad + shr r10d, 1; + add betad, r10d shr betaq, 3; ((beta + (beta >> 1)) >> 3)) psubw m12, m4, m3 ; q0 - p0 @@ -607,11 +601,9 @@ ALIGN 16 movd m10, betad SPLATW m10, m10, 0 - movd m13, r7d; 1dp0 + 1dp3 - movd m8, r8d; 0dp0 + 0dp3 - punpcklwd m8, m8 + movq m13, r7q; 1dp0 + 1dp3, 0dp0 + 0dp3 punpcklwd m13, m13 - shufps m13, m8, 0; + pshufd m13, m13, 10100000b pcmpgtw m8, m10, m13 pand m8, m11 ;end beta calculations @@ -625,11 +617,10 @@ ALIGN 16 pminsw m8, m9; av_clip(deltaq1, -tc/2, tc/2) paddw m8, m5; q1' - movd m13, r9d; - movd m15, r10d; - punpcklwd m15, m15 + movq m13, r8q; punpcklwd m13, m13 - shufps m13, m15, 0; dq0 + dq3 + movhlps m15, m13 + pshufd m13, m13, 10100000b pcmpgtw m10, m13; compare to ((beta+(beta>>1))>>3) pand m10, m11 @@ -744,7 +735,7 @@ LOOP_FILTER_CHROMA ; void ff_hevc_v_loop_filter_luma(uint8_t *_pix, ptrdiff_t _stride, int beta, ; int32_t *tc, uint8_t *_no_p, uint8_t *_no_q); ;----------------------------------------------------------------------------- -cglobal hevc_v_loop_filter_luma_8, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride +cglobal hevc_v_loop_filter_luma_8, 4, 11, 16, pix, stride, beta, tc, pix0, src3stride sub pixq, 4 lea pix0q, [3 * r1] mov src3strideq, pixq @@ -756,7 +747,7 @@ cglobal hevc_v_loop_filter_luma_8, 4, 14, 16, pix, stride, beta, tc, pix0, src3s .bypassluma: RET -cglobal hevc_v_loop_filter_luma_10, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride +cglobal hevc_v_loop_filter_luma_10, 4, 11, 16, pix, stride, beta, tc, pix0, src3stride sub pixq, 8 lea pix0q, [3 * strideq] mov src3strideq, pixq @@ -768,7 +759,7 @@ cglobal hevc_v_loop_filter_luma_10, 4, 14, 16, pix, stride, beta, tc, pix0, src3 .bypassluma: RET -cglobal hevc_v_loop_filter_luma_12, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride +cglobal hevc_v_loop_filter_luma_12, 4, 11, 16, pix, stride, beta, tc, pix0, src3stride sub pixq, 8 lea pix0q, [3 * strideq] mov src3strideq, pixq @@ -784,7 +775,7 @@ cglobal hevc_v_loop_filter_luma_12, 4, 14, 16, pix, stride, beta, tc, pix0, src3 ; void ff_hevc_h_loop_filter_luma(uint8_t *_pix, ptrdiff_t _stride, int beta, ; int32_t *tc, uint8_t *_no_p, uint8_t *_no_q); ;----------------------------------------------------------------------------- -cglobal hevc_h_loop_filter_luma_8, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride +cglobal hevc_h_loop_filter_luma_8, 4, 11, 16, pix, stride, beta, tc, pix0, src3stride lea src3strideq, [3 * strideq] mov pix0q, pixq sub pix0q, src3strideq @@ -820,7 +811,7 @@ cglobal hevc_h_loop_filter_luma_8, 4, 14, 16, pix, stride, beta, tc, pix0, src3s .bypassluma: RET -cglobal hevc_h_loop_filter_luma_10, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride +cglobal hevc_h_loop_filter_luma_10, 4, 11, 16, pix, stride, beta, tc, pix0, src3stride lea src3strideq, [3 * strideq] mov pix0q, pixq sub pix0q, src3strideq @@ -851,7 +842,7 @@ cglobal hevc_h_loop_filter_luma_10, 4, 14, 16, pix, stride, beta, tc, pix0, src3 .bypassluma: RET -cglobal hevc_h_loop_filter_luma_12, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride +cglobal hevc_h_loop_filter_luma_12, 4, 11, 16, pix, stride, beta, tc, pix0, src3stride lea src3strideq, [3 * strideq] mov pix0q, pixq sub pix0q, src3strideq diff --git a/libavcodec/x86/hevc/dequant.asm b/libavcodec/x86/hevc/dequant.asm new file mode 100644 index 000000000..f0453c940 --- /dev/null +++ b/libavcodec/x86/hevc/dequant.asm @@ -0,0 +1,60 @@ +;***************************************************************************** +;* SSSE3-optimized HEVC dequant code +;***************************************************************************** +;* 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/x86/x86util.asm" + +SECTION .text + +INIT_XMM ssse3 +; void ff_hevc_dequant_8_ssse3(int16_t *coeffs, int16_t log2_size) +cglobal hevc_dequant_8, 2, 3+UNIX64, 3 + +; coeffs, log2_size (in ecx), tmp/size +%if WIN64 + DECLARE_REG_TMP 1,0,2 + ; r0 is the shift register (ecx) on win64 + xchg r0, r1 +%elif ARCH_X86_64 + DECLARE_REG_TMP 0,3,1 + ; r3 is ecx + mov t1d, r1d +%else + ; r1 is ecx + DECLARE_REG_TMP 0,1,2 +%endif + + mov t2d, 256 + shl t2d, t1b + movd m0, t2d + add t1d, t1d + SPLATW m0, m0 + mov t2d, 1 + shl t2d, t1b +.loop: + mova m1, [t0] + mova m2, [t0+mmsize] + pmulhrsw m1, m0 + pmulhrsw m2, m0 + mova [t0], m1 + mova [t0+mmsize], m2 + add t0, 2*mmsize + sub t2d, mmsize + jg .loop + RET diff --git a/libavcodec/x86/hevc/dsp.h b/libavcodec/x86/hevc/dsp.h new file mode 100644 index 000000000..0062699ce --- /dev/null +++ b/libavcodec/x86/hevc/dsp.h @@ -0,0 +1,185 @@ +/* + * 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_X86_HEVC_DSP_H +#define AVCODEC_X86_HEVC_DSP_H + +#include +#include + +typedef void bi_pel_func(uint8_t *_dst, ptrdiff_t _dststride, + const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, + int height, intptr_t mx, intptr_t my, int width); + +#define BI_PEL_PROTOTYPE(name, W, D, opt) \ +bi_pel_func ff_hevc_put_bi_ ## name ## W ## _ ## D ## _##opt + +/////////////////////////////////////////////////////////////////////////////// +// MC functions +/////////////////////////////////////////////////////////////////////////////// + +#define WEIGHTING_PROTOTYPE(width, bitd, opt) \ +void ff_hevc_put_uni_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const int16_t *_src, int height, int denom, int _wx, int _ox); \ +void ff_hevc_put_bi_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const int16_t *_src, const int16_t *_src2, int height, int denom, int _wx0, int _wx1, int _ox0, int _ox1) + +#define WEIGHTING_PROTOTYPES(bitd, opt) \ + WEIGHTING_PROTOTYPE(4, bitd, opt); \ + WEIGHTING_PROTOTYPE(6, bitd, opt); \ + WEIGHTING_PROTOTYPE(8, bitd, opt); \ + WEIGHTING_PROTOTYPE(12, bitd, opt); \ + WEIGHTING_PROTOTYPE(16, bitd, opt); \ + WEIGHTING_PROTOTYPE(24, bitd, opt); \ + WEIGHTING_PROTOTYPE(32, bitd, opt); \ + WEIGHTING_PROTOTYPE(48, bitd, opt); \ + WEIGHTING_PROTOTYPE(64, bitd, opt) + + +/////////////////////////////////////////////////////////////////////////////// +// EPEL_PIXELS +/////////////////////////////////////////////////////////////////////////////// + +BI_PEL_PROTOTYPE(pel_pixels, 4, 8, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 4, 10, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 4, 12, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 6, 8, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 6, 10, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 6, 12, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 8, 8, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 8, 10, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 8, 12, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 12, 8, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 16, 8, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 16, 10, avx2); +BI_PEL_PROTOTYPE(pel_pixels, 32, 8, avx2); + +/////////////////////////////////////////////////////////////////////////////// +// EPEL +/////////////////////////////////////////////////////////////////////////////// + +BI_PEL_PROTOTYPE(epel_h, 4, 8, sse4); +BI_PEL_PROTOTYPE(epel_h, 4, 10, sse4); +BI_PEL_PROTOTYPE(epel_h, 4, 12, sse4); +BI_PEL_PROTOTYPE(epel_h, 6, 8, sse4); +BI_PEL_PROTOTYPE(epel_h, 6, 10, sse4); +BI_PEL_PROTOTYPE(epel_h, 6, 12, sse4); +BI_PEL_PROTOTYPE(epel_h, 8, 8, sse4); +BI_PEL_PROTOTYPE(epel_h, 8, 10, sse4); +BI_PEL_PROTOTYPE(epel_h, 8, 12, sse4); +BI_PEL_PROTOTYPE(epel_h, 12, 8, sse4); +BI_PEL_PROTOTYPE(epel_h, 16, 8, sse4); +BI_PEL_PROTOTYPE(epel_h, 16, 10, avx2); +BI_PEL_PROTOTYPE(epel_h, 32, 8, avx2); + +BI_PEL_PROTOTYPE(epel_hv, 4, 8, sse4); +BI_PEL_PROTOTYPE(epel_hv, 4, 10, sse4); +BI_PEL_PROTOTYPE(epel_hv, 4, 12, sse4); +BI_PEL_PROTOTYPE(epel_hv, 6, 8, sse4); +BI_PEL_PROTOTYPE(epel_hv, 6, 10, sse4); +BI_PEL_PROTOTYPE(epel_hv, 6, 12, sse4); +BI_PEL_PROTOTYPE(epel_hv, 8, 8, sse4); +BI_PEL_PROTOTYPE(epel_hv, 8, 10, sse4); +BI_PEL_PROTOTYPE(epel_hv, 8, 12, sse4); +BI_PEL_PROTOTYPE(epel_hv, 16, 8, sse4); +BI_PEL_PROTOTYPE(epel_hv, 16, 10, avx2); +BI_PEL_PROTOTYPE(epel_hv, 32, 8, avx2); + +BI_PEL_PROTOTYPE(epel_v, 4, 8, sse4); +BI_PEL_PROTOTYPE(epel_v, 4, 10, sse4); +BI_PEL_PROTOTYPE(epel_v, 4, 12, sse4); +BI_PEL_PROTOTYPE(epel_v, 6, 8, sse4); +BI_PEL_PROTOTYPE(epel_v, 6, 10, sse4); +BI_PEL_PROTOTYPE(epel_v, 6, 12, sse4); +BI_PEL_PROTOTYPE(epel_v, 8, 8, sse4); +BI_PEL_PROTOTYPE(epel_v, 8, 10, sse4); +BI_PEL_PROTOTYPE(epel_v, 8, 12, sse4); +BI_PEL_PROTOTYPE(epel_v, 12, 8, sse4); +BI_PEL_PROTOTYPE(epel_v, 16, 8, sse4); +BI_PEL_PROTOTYPE(epel_v, 16, 10, avx2); +BI_PEL_PROTOTYPE(epel_v, 32, 8, avx2); + +/////////////////////////////////////////////////////////////////////////////// +// QPEL +/////////////////////////////////////////////////////////////////////////////// + +BI_PEL_PROTOTYPE(qpel_h, 4, 8, sse4); +BI_PEL_PROTOTYPE(qpel_h, 4, 10, sse4); +BI_PEL_PROTOTYPE(qpel_h, 4, 12, sse4); +BI_PEL_PROTOTYPE(qpel_h, 8, 8, sse4); +BI_PEL_PROTOTYPE(qpel_h, 8, 10, sse4); +BI_PEL_PROTOTYPE(qpel_h, 8, 12, sse4); +BI_PEL_PROTOTYPE(qpel_h, 12, 8, sse4); +BI_PEL_PROTOTYPE(qpel_h, 16, 8, sse4); +BI_PEL_PROTOTYPE(qpel_h, 16, 10, avx2); +BI_PEL_PROTOTYPE(qpel_h, 32, 8, avx2); + +BI_PEL_PROTOTYPE(qpel_hv, 4, 8, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 4, 10, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 4, 12, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 8, 8, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 8, 10, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 8, 12, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 16, 10, avx2); + +BI_PEL_PROTOTYPE(qpel_v, 4, 8, sse4); +BI_PEL_PROTOTYPE(qpel_v, 4, 10, sse4); +BI_PEL_PROTOTYPE(qpel_v, 4, 12, sse4); +BI_PEL_PROTOTYPE(qpel_v, 8, 8, sse4); +BI_PEL_PROTOTYPE(qpel_v, 8, 10, sse4); +BI_PEL_PROTOTYPE(qpel_v, 8, 12, sse4); +BI_PEL_PROTOTYPE(qpel_v, 12, 8, sse4); +BI_PEL_PROTOTYPE(qpel_v, 16, 8, sse4); +BI_PEL_PROTOTYPE(qpel_v, 16, 10, avx2); +BI_PEL_PROTOTYPE(qpel_v, 32, 8, avx2); + +WEIGHTING_PROTOTYPES(8, sse4); +WEIGHTING_PROTOTYPES(10, sse4); +WEIGHTING_PROTOTYPES(12, sse4); + +void ff_hevc_put_qpel_h4_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_qpel_h8_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_qpel_h16_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_qpel_h32_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_qpel_h64_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_qpel_hv8_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); + +/////////////////////////////////////////////////////////////////////////////// +// TRANSFORM_ADD +/////////////////////////////////////////////////////////////////////////////// + +void ff_hevc_add_residual_4_8_mmxext(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_8_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_16_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_32_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); + +void ff_hevc_add_residual_32_8_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); + +void ff_hevc_add_residual_4_10_mmxext(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_8_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_16_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_32_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); + +void ff_hevc_add_residual_16_10_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_32_10_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); + +#endif // AVCODEC_X86_HEVC_DSP_H diff --git a/libavcodec/x86/hevcdsp_init.c b/libavcodec/x86/hevc/dsp_init.c similarity index 58% rename from libavcodec/x86/hevcdsp_init.c rename to libavcodec/x86/hevc/dsp_init.c index 2c0fca303..bd967eac6 100644 --- a/libavcodec/x86/hevcdsp_init.c +++ b/libavcodec/x86/hevc/dsp_init.c @@ -27,9 +27,11 @@ #include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" #include "libavcodec/hevc/dsp.h" -#include "libavcodec/x86/hevcdsp.h" +#include "libavcodec/x86/hevc/dsp.h" #include "libavcodec/x86/h26x/h2656dsp.h" +void ff_hevc_dequant_8_ssse3(int16_t *coeffs, int16_t log2_size); + #define LFC_FUNC(DIR, DEPTH, OPT) \ void ff_hevc_ ## DIR ## _loop_filter_chroma_ ## DEPTH ## _ ## OPT(uint8_t *pix, ptrdiff_t stride, const int *tc, const uint8_t *no_p, const uint8_t *no_q); @@ -65,7 +67,7 @@ void ff_hevc_idct_ ## W ## _dc_8_ ## opt(int16_t *coeffs); \ void ff_hevc_idct_ ## W ## _dc_10_ ## opt(int16_t *coeffs); \ void ff_hevc_idct_ ## W ## _dc_12_ ## opt(int16_t *coeffs) -IDCT_DC_FUNCS(4x4, mmxext); +IDCT_DC_FUNCS(4x4, sse2); IDCT_DC_FUNCS(8x8, sse2); IDCT_DC_FUNCS(16x16, sse2); IDCT_DC_FUNCS(32x32, sse2); @@ -92,15 +94,15 @@ IDCT_FUNCS(avx) const uint8_t *vf = ff_hevc_ ## f ## _filters[my]; #define FW_PUT(p, a, b, depth, opt) \ -void ff_hevc_put_hevc_ ## a ## _ ## depth ## _##opt(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, \ - int height, intptr_t mx, intptr_t my,int width) \ +static void hevc_put_ ## a ## _ ## depth ## _##opt(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, \ + int height, intptr_t mx, intptr_t my,int width) \ { \ DECL_HV_FILTER(p) \ ff_h2656_put_ ## b ## _ ## depth ## _##opt(dst, 2 * MAX_PB_SIZE, src, srcstride, height, hf, vf, width); \ } #define FW_PUT_UNI(p, a, b, depth, opt) \ -void ff_hevc_put_hevc_uni_ ## a ## _ ## depth ## _##opt(uint8_t *dst, ptrdiff_t dststride, \ +static void hevc_put_uni_ ## a ## _ ## depth ## _##opt(uint8_t *dst, ptrdiff_t dststride, \ const uint8_t *src, ptrdiff_t srcstride, \ int height, intptr_t mx, intptr_t my, int width) \ { \ @@ -190,36 +192,36 @@ FW_QPEL_HV(16, 10, avx2) #endif #define mc_rep_func(name, bitd, step, W, opt) \ -void ff_hevc_put_hevc_##name##W##_##bitd##_##opt(int16_t *_dst, \ - const uint8_t *_src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_##name##W##_##bitd##_##opt(int16_t *_dst, \ + const uint8_t *_src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ int i; \ int16_t *dst; \ for (i = 0; i < W; i += step) { \ const uint8_t *src = _src + (i * ((bitd + 7) / 8)); \ dst = _dst + i; \ - ff_hevc_put_hevc_##name##step##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \ + hevc_put_##name##step##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \ } \ } #define mc_rep_uni_func(name, bitd, step, W, opt) \ -void ff_hevc_put_hevc_uni_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, \ - const uint8_t *_src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_uni_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, \ + const uint8_t *_src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ int i; \ uint8_t *dst; \ for (i = 0; i < W; i += step) { \ const uint8_t *src = _src + (i * ((bitd + 7) / 8)); \ dst = _dst + (i * ((bitd + 7) / 8)); \ - ff_hevc_put_hevc_uni_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, \ - height, mx, my, width); \ + hevc_put_uni_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, \ + height, mx, my, width); \ } \ } #define mc_rep_bi_func(name, bitd, step, W, opt) \ -void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const uint8_t *_src, \ - ptrdiff_t _srcstride, const int16_t *_src2, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void ff_hevc_put_bi_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const uint8_t *_src, \ + ptrdiff_t _srcstride, const int16_t *_src2, \ + int height, intptr_t mx, intptr_t my, int width) \ { \ int i; \ uint8_t *dst; \ @@ -227,8 +229,8 @@ void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dst const uint8_t *src = _src + (i * ((bitd + 7) / 8)); \ const int16_t *src2 = _src2 + i; \ dst = _dst + (i * ((bitd + 7) / 8)); \ - ff_hevc_put_hevc_bi_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, \ - height, mx, my, width); \ + ff_hevc_put_bi_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, \ + height, mx, my, width); \ } \ } @@ -238,33 +240,33 @@ void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dst mc_rep_bi_func(name, bitd, step, W, opt) #define mc_rep_func2(name, bitd, step1, step2, W, opt) \ -void ff_hevc_put_hevc_##name##W##_##bitd##_##opt(int16_t *dst, \ - const uint8_t *src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_##name##W##_##bitd##_##opt(int16_t *dst, \ + const uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_##name##step1##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \ - ff_hevc_put_hevc_##name##step2##_##bitd##_##opt(dst + step1, src + (step1 * ((bitd + 7) / 8)), \ - _srcstride, height, mx, my, width); \ + hevc_put_##name##step1##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \ + hevc_put_##name##step2##_##bitd##_##opt(dst + step1, src + (step1 * ((bitd + 7) / 8)), \ + _srcstride, height, mx, my, width); \ } #define mc_rep_uni_func2(name, bitd, step1, step2, W, opt) \ -void ff_hevc_put_hevc_uni_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, \ - const uint8_t *src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_uni_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_uni_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, height, mx, my, width);\ - ff_hevc_put_hevc_uni_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \ - src + (step1 * ((bitd + 7) / 8)), _srcstride, \ - height, mx, my, width); \ + hevc_put_uni_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, height, mx, my, width); \ + hevc_put_uni_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \ + src + (step1 * ((bitd + 7) / 8)), _srcstride, \ + height, mx, my, width); \ } #define mc_rep_bi_func2(name, bitd, step1, step2, W, opt) \ -void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ - ptrdiff_t _srcstride, const int16_t *src2, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void ff_hevc_put_bi_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ + ptrdiff_t _srcstride, const int16_t *src2, \ + int height, intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_bi_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, height, mx, my, width);\ - ff_hevc_put_hevc_bi_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \ - src + (step1 * ((bitd + 7) / 8)), _srcstride, \ - src2 + step1, height, mx, my, width); \ + ff_hevc_put_bi_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, height, mx, my, width);\ + ff_hevc_put_bi_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \ + src + (step1 * ((bitd + 7) / 8)), _srcstride, \ + src2 + step1, height, mx, my, width); \ } #define mc_rep_funcs2(name, bitd, step1, step2, W, opt) \ @@ -275,34 +277,34 @@ void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dsts #if ARCH_X86_64 && HAVE_SSE4_EXTERNAL #define mc_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ -void ff_hevc_put_hevc_##name##width1##_10_##opt1(int16_t *dst, const uint8_t *src, ptrdiff_t _srcstride, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void hevc_put_##name##width1##_10_##opt1(int16_t *dst, const uint8_t *src, ptrdiff_t _srcstride, \ + int height, intptr_t mx, intptr_t my, int width) \ \ { \ - ff_hevc_put_hevc_##name##width2##_10_##opt1(dst, src, _srcstride, height, mx, my, width); \ - ff_hevc_put_hevc_##name##width3##_10_##opt2(dst+ width2, src+ width4, _srcstride, height, mx, my, width); \ + hevc_put_##name##width2##_10_##opt1(dst, src, _srcstride, height, mx, my, width); \ + hevc_put_##name##width3##_10_##opt2(dst+ width2, src+ width4, _srcstride, height, mx, my, width); \ } #define mc_bi_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ -void ff_hevc_put_hevc_bi_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ - ptrdiff_t _srcstride, const int16_t *src2, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void ff_hevc_put_bi_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ + ptrdiff_t _srcstride, const int16_t *src2, \ + int height, intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_bi_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, src2, \ - height, mx, my, width); \ - ff_hevc_put_hevc_bi_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, src2+width2,\ - height, mx, my, width); \ + ff_hevc_put_bi_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, src2, \ + height, mx, my, width); \ + ff_hevc_put_bi_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, src2+width2, \ + height, mx, my, width); \ } #define mc_uni_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ -void ff_hevc_put_hevc_uni_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, \ - const uint8_t *src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_uni_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_uni_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, \ - height, mx, my, width); \ - ff_hevc_put_hevc_uni_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, \ - height, mx, my, width); \ + hevc_put_uni_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, \ + height, mx, my, width); \ + hevc_put_uni_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, \ + height, mx, my, width); \ } #define mc_rep_mixs_10(name, width1, width2, width3, opt1, opt2, width4) \ @@ -311,34 +313,34 @@ mc_bi_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ mc_uni_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) #define mc_rep_mix_8(name, width1, width2, width3, opt1, opt2) \ -void ff_hevc_put_hevc_##name##width1##_8_##opt1(int16_t *dst, const uint8_t *src, ptrdiff_t _srcstride, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void hevc_put_##name##width1##_8_##opt1(int16_t *dst, const uint8_t *src, ptrdiff_t _srcstride, \ + int height, intptr_t mx, intptr_t my, int width) \ \ { \ - ff_hevc_put_hevc_##name##width2##_8_##opt1(dst, src, _srcstride, height, mx, my, width); \ - ff_hevc_put_hevc_##name##width3##_8_##opt2(dst+ width2, src+ width2, _srcstride, height, mx, my, width); \ + hevc_put_##name##width2##_8_##opt1(dst, src, _srcstride, height, mx, my, width); \ + hevc_put_##name##width3##_8_##opt2(dst+ width2, src+ width2, _srcstride, height, mx, my, width); \ } #define mc_bi_rep_mix_8(name, width1, width2, width3, opt1, opt2) \ -void ff_hevc_put_hevc_bi_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ - ptrdiff_t _srcstride, const int16_t *src2, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void ff_hevc_put_bi_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ + ptrdiff_t _srcstride, const int16_t *src2, \ + int height, intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_bi_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \ - src2, height, mx, my, width); \ - ff_hevc_put_hevc_bi_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \ - src2+width2, height, mx, my, width); \ + ff_hevc_put_bi_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \ + src2, height, mx, my, width); \ + ff_hevc_put_bi_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \ + src2+width2, height, mx, my, width); \ } #define mc_uni_rep_mix_8(name, width1, width2, width3, opt1, opt2) \ -void ff_hevc_put_hevc_uni_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, \ - const uint8_t *src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_uni_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_uni_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \ - height, mx, my, width); \ - ff_hevc_put_hevc_uni_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \ - height, mx, my, width); \ + hevc_put_uni_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \ + height, mx, my, width); \ + hevc_put_uni_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \ + height, mx, my, width); \ } #define mc_rep_mixs_8(name, width1, width2, width3, opt1, opt2) \ @@ -365,11 +367,11 @@ mc_rep_mixs_10(qpel_v , 24, 16, 8, avx2, sse4, 32) mc_rep_mixs_10(qpel_hv, 24, 16, 8, avx2, sse4, 32) +mc_rep_funcs(pel_pixels, 8, 32, 64, avx2) + mc_rep_uni_func(pel_pixels, 8, 64, 128, avx2)//used for 10bit mc_rep_uni_func(pel_pixels, 8, 32, 96, avx2) //used for 10bit -mc_rep_funcs(pel_pixels, 8, 32, 64, avx2) - mc_rep_func(pel_pixels, 10, 16, 32, avx2) mc_rep_func(pel_pixels, 10, 16, 48, avx2) mc_rep_func(pel_pixels, 10, 32, 64, avx2) @@ -536,16 +538,16 @@ mc_rep_funcs(qpel_hv,12, 8, 16, sse4) mc_rep_funcs(qpel_hv,12, 4, 12, sse4) #define mc_rep_uni_w(bitd, step, W, opt) \ -void ff_hevc_put_hevc_uni_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const int16_t *_src, \ - int height, int denom, int _wx, int _ox) \ +void ff_hevc_put_uni_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const int16_t *_src, \ + int height, int denom, int _wx, int _ox) \ { \ int i; \ uint8_t *dst; \ for (i = 0; i < W; i += step) { \ const int16_t *src = _src + i; \ dst= _dst + (i * ((bitd + 7) / 8)); \ - ff_hevc_put_hevc_uni_w##step##_##bitd##_##opt(dst, dststride, src, \ - height, denom, _wx, _ox); \ + ff_hevc_put_uni_w##step##_##bitd##_##opt(dst, dststride, src, \ + height, denom, _wx, _ox); \ } \ } @@ -571,9 +573,9 @@ mc_rep_uni_w(12, 8, 48, sse4) mc_rep_uni_w(12, 8, 64, sse4) #define mc_rep_bi_w(bitd, step, W, opt) \ -void ff_hevc_put_hevc_bi_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const int16_t *_src, \ - const int16_t *_src2, int height, \ - int denom, int _wx0, int _wx1, int _ox0, int _ox1) \ +void ff_hevc_put_bi_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const int16_t *_src, \ + const int16_t *_src2, int height, \ + int denom, int _wx0, int _wx1, int _ox0, int _ox1) \ { \ int i; \ uint8_t *dst; \ @@ -581,8 +583,8 @@ void ff_hevc_put_hevc_bi_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststrid const int16_t *src = _src + i; \ const int16_t *src2 = _src2 + i; \ dst = _dst + (i * ((bitd + 7) / 8)); \ - ff_hevc_put_hevc_bi_w##step##_##bitd##_##opt(dst, dststride, src, src2, \ - height, denom, _wx0, _wx1, _ox0, _ox1); \ + ff_hevc_put_bi_w##step##_##bitd##_##opt(dst, dststride, src, src2, \ + height, denom, _wx0, _wx1, _ox0, _ox1); \ } \ } @@ -608,15 +610,15 @@ mc_rep_bi_w(12, 8, 48, sse4) mc_rep_bi_w(12, 8, 64, sse4) #define mc_uni_w_func(name, bitd, W, opt) \ -void ff_hevc_put_hevc_uni_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \ - const uint8_t *_src, ptrdiff_t _srcstride, \ +static void hevc_put_uni_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \ + const uint8_t *_src, ptrdiff_t _srcstride, \ int height, int denom, \ int _wx, int _ox, \ intptr_t mx, intptr_t my, int width) \ { \ LOCAL_ALIGNED_16(int16_t, temp, [71 * MAX_PB_SIZE]); \ - ff_hevc_put_hevc_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \ - ff_hevc_put_hevc_uni_w##W##_##bitd##_##opt(_dst, _dststride, temp, height, denom, _wx, _ox);\ + hevc_put_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \ + ff_hevc_put_uni_w##W##_##bitd##_##opt(_dst, _dststride, temp, height, denom, _wx, _ox); \ } #define mc_uni_w_funcs(name, bitd, opt) \ @@ -666,17 +668,17 @@ mc_uni_w_funcs(qpel_v, 12, sse4) mc_uni_w_funcs(qpel_hv, 12, sse4) #define mc_bi_w_func(name, bitd, W, opt) \ -void ff_hevc_put_hevc_bi_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \ - const uint8_t *_src, ptrdiff_t _srcstride, \ - const int16_t *_src2, \ +static void hevc_put_bi_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \ + const uint8_t *_src, ptrdiff_t _srcstride, \ + const int16_t *_src2, \ int height, int denom, \ int _wx0, int _wx1, int _ox0, int _ox1, \ intptr_t mx, intptr_t my, int width) \ { \ LOCAL_ALIGNED_16(int16_t, temp, [71 * MAX_PB_SIZE]); \ - ff_hevc_put_hevc_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \ - ff_hevc_put_hevc_bi_w##W##_##bitd##_##opt(_dst, _dststride, temp, _src2, \ - height, denom, _wx0, _wx1, _ox0, _ox1); \ + hevc_put_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \ + ff_hevc_put_bi_w##W##_##bitd##_##opt(_dst, _dststride, temp, _src2, \ + height, denom, _wx0, _wx1, _ox0, _ox1); \ } #define mc_bi_w_funcs(name, bitd, opt) \ @@ -783,6 +785,13 @@ SAO_EDGE_FILTER_FUNCS(12, avx2) c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_64_##bitd##_##opt; \ } while (0) +#define PEL_LINK(dst, idx1, idx2, idx3, name, D, opt) \ +dst [idx1][idx2][idx3] = hevc_put_ ## name ## _ ## D ## _##opt; \ +dst ## _bi [idx1][idx2][idx3] = ff_hevc_put_bi_ ## name ## _ ## D ## _##opt; \ +dst ## _uni [idx1][idx2][idx3] = hevc_put_uni_ ## name ## _ ## D ## _##opt; \ +dst ## _uni_w[idx1][idx2][idx3] = hevc_put_uni_w_ ## name ## _ ## D ## _##opt; \ +dst ## _bi_w [idx1][idx2][idx3] = hevc_put_bi_w_ ## name ## _ ## D ## _##opt + #define EPEL_LINKS(pointer, my, mx, fname, bitd, opt ) \ PEL_LINK(pointer, 1, my , mx , fname##4 , bitd, opt ); \ PEL_LINK(pointer, 2, my , mx , fname##6 , bitd, opt ); \ @@ -809,22 +818,21 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) if (bit_depth == 8) { if (EXTERNAL_MMXEXT(cpu_flags)) { - c->idct_dc[0] = ff_hevc_idct_4x4_dc_8_mmxext; - c->add_residual[0] = ff_hevc_add_residual_4_8_mmxext; } if (EXTERNAL_SSE2(cpu_flags)) { c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_8_sse2; c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_8_sse2; - if (ARCH_X86_64) { - c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_sse2; - c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_sse2; +#if ARCH_X86_64 + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_sse2; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_sse2; - c->idct[2] = ff_hevc_idct_16x16_8_sse2; - c->idct[3] = ff_hevc_idct_32x32_8_sse2; - } + c->idct[2] = ff_hevc_idct_16x16_8_sse2; + c->idct[3] = ff_hevc_idct_32x32_8_sse2; +#endif SAO_BAND_INIT(8, sse2); + c->idct_dc[0] = ff_hevc_idct_4x4_dc_8_sse2; c->idct_dc[1] = ff_hevc_idct_8x8_dc_8_sse2; c->idct_dc[2] = ff_hevc_idct_16x16_dc_8_sse2; c->idct_dc[3] = ff_hevc_idct_32x32_dc_8_sse2; @@ -837,13 +845,15 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) c->add_residual[3] = ff_hevc_add_residual_32_8_sse2; } if (EXTERNAL_SSSE3(cpu_flags)) { - if(ARCH_X86_64) { - c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_ssse3; - c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_ssse3; - } +#if ARCH_X86_64 + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_ssse3; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_ssse3; +#endif + c->dequant = ff_hevc_dequant_8_ssse3; SAO_EDGE_INIT(8, ssse3); } - if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) { +#if HAVE_SSE4_EXTERNAL && ARCH_X86_64 + if (EXTERNAL_SSE4(cpu_flags)) { EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 8, sse4); EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 8, sse4); @@ -855,117 +865,117 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 8, sse4); QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 8, sse4); } +#endif if (EXTERNAL_AVX(cpu_flags)) { c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_8_avx; c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_8_avx; - if (ARCH_X86_64) { - c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_avx; - c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_avx; +#if ARCH_X86_64 + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_avx; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_avx; - c->idct[2] = ff_hevc_idct_16x16_8_avx; - c->idct[3] = ff_hevc_idct_32x32_8_avx; - } + c->idct[2] = ff_hevc_idct_16x16_8_avx; + c->idct[3] = ff_hevc_idct_32x32_8_avx; +#endif SAO_BAND_INIT(8, avx); c->idct[0] = ff_hevc_idct_4x4_8_avx; c->idct[1] = ff_hevc_idct_8x8_8_avx; - - c->add_residual[1] = ff_hevc_add_residual_8_8_avx; - c->add_residual[2] = ff_hevc_add_residual_16_8_avx; - c->add_residual[3] = ff_hevc_add_residual_32_8_avx; } if (EXTERNAL_AVX2(cpu_flags)) { c->sao_band_filter[0] = ff_hevc_sao_band_filter_8_8_avx2; c->sao_band_filter[1] = ff_hevc_sao_band_filter_16_8_avx2; } +#if HAVE_AVX2_EXTERNAL if (EXTERNAL_AVX2_FAST(cpu_flags)) { c->idct_dc[2] = ff_hevc_idct_16x16_dc_8_avx2; c->idct_dc[3] = ff_hevc_idct_32x32_dc_8_avx2; - if (ARCH_X86_64) { - c->put_hevc_epel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_8_avx2; - c->put_hevc_epel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_8_avx2; - c->put_hevc_epel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_8_avx2; - c->put_hevc_qpel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_8_avx2; - c->put_hevc_qpel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_8_avx2; - c->put_hevc_qpel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_8_avx2; +#if ARCH_X86_64 + c->put_hevc_epel[7][0][0] = hevc_put_pel_pixels32_8_avx2; + c->put_hevc_epel[8][0][0] = hevc_put_pel_pixels48_8_avx2; + c->put_hevc_epel[9][0][0] = hevc_put_pel_pixels64_8_avx2; - c->put_hevc_epel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; - c->put_hevc_epel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; - c->put_hevc_epel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; + c->put_hevc_qpel[7][0][0] = hevc_put_pel_pixels32_8_avx2; + c->put_hevc_qpel[8][0][0] = hevc_put_pel_pixels48_8_avx2; + c->put_hevc_qpel[9][0][0] = hevc_put_pel_pixels64_8_avx2; - c->put_hevc_qpel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; - c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; - c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; + c->put_hevc_epel_uni[7][0][0] = hevc_put_uni_pel_pixels32_8_avx2; + c->put_hevc_epel_uni[8][0][0] = hevc_put_uni_pel_pixels48_8_avx2; + c->put_hevc_epel_uni[9][0][0] = hevc_put_uni_pel_pixels64_8_avx2; - c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_8_avx2; - c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_8_avx2; - c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_8_avx2; + c->put_hevc_qpel_uni[7][0][0] = hevc_put_uni_pel_pixels32_8_avx2; + c->put_hevc_qpel_uni[8][0][0] = hevc_put_uni_pel_pixels48_8_avx2; + c->put_hevc_qpel_uni[9][0][0] = hevc_put_uni_pel_pixels64_8_avx2; - c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_8_avx2; - c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_8_avx2; - c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_8_avx2; + c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_bi_pel_pixels32_8_avx2; + c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_bi_pel_pixels48_8_avx2; + c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_bi_pel_pixels64_8_avx2; - c->put_hevc_epel[7][0][1] = ff_hevc_put_hevc_epel_h32_8_avx2; - c->put_hevc_epel[8][0][1] = ff_hevc_put_hevc_epel_h48_8_avx2; - c->put_hevc_epel[9][0][1] = ff_hevc_put_hevc_epel_h64_8_avx2; + c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_bi_pel_pixels32_8_avx2; + c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_bi_pel_pixels48_8_avx2; + c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_bi_pel_pixels64_8_avx2; - c->put_hevc_epel_uni[7][0][1] = ff_hevc_put_hevc_uni_epel_h32_8_avx2; - c->put_hevc_epel_uni[8][0][1] = ff_hevc_put_hevc_uni_epel_h48_8_avx2; - c->put_hevc_epel_uni[9][0][1] = ff_hevc_put_hevc_uni_epel_h64_8_avx2; + c->put_hevc_epel[7][0][1] = hevc_put_epel_h32_8_avx2; + c->put_hevc_epel[8][0][1] = hevc_put_epel_h48_8_avx2; + c->put_hevc_epel[9][0][1] = hevc_put_epel_h64_8_avx2; - c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_hevc_bi_epel_h32_8_avx2; - c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_hevc_bi_epel_h48_8_avx2; - c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_hevc_bi_epel_h64_8_avx2; + c->put_hevc_epel_uni[7][0][1] = hevc_put_uni_epel_h32_8_avx2; + c->put_hevc_epel_uni[8][0][1] = hevc_put_uni_epel_h48_8_avx2; + c->put_hevc_epel_uni[9][0][1] = hevc_put_uni_epel_h64_8_avx2; - c->put_hevc_epel[7][1][0] = ff_hevc_put_hevc_epel_v32_8_avx2; - c->put_hevc_epel[8][1][0] = ff_hevc_put_hevc_epel_v48_8_avx2; - c->put_hevc_epel[9][1][0] = ff_hevc_put_hevc_epel_v64_8_avx2; + c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_bi_epel_h32_8_avx2; + c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_bi_epel_h48_8_avx2; + c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_bi_epel_h64_8_avx2; - c->put_hevc_epel_uni[7][1][0] = ff_hevc_put_hevc_uni_epel_v32_8_avx2; - c->put_hevc_epel_uni[8][1][0] = ff_hevc_put_hevc_uni_epel_v48_8_avx2; - c->put_hevc_epel_uni[9][1][0] = ff_hevc_put_hevc_uni_epel_v64_8_avx2; + c->put_hevc_epel[7][1][0] = hevc_put_epel_v32_8_avx2; + c->put_hevc_epel[8][1][0] = hevc_put_epel_v48_8_avx2; + c->put_hevc_epel[9][1][0] = hevc_put_epel_v64_8_avx2; - c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_hevc_bi_epel_v32_8_avx2; - c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_hevc_bi_epel_v48_8_avx2; - c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_hevc_bi_epel_v64_8_avx2; + c->put_hevc_epel_uni[7][1][0] = hevc_put_uni_epel_v32_8_avx2; + c->put_hevc_epel_uni[8][1][0] = hevc_put_uni_epel_v48_8_avx2; + c->put_hevc_epel_uni[9][1][0] = hevc_put_uni_epel_v64_8_avx2; - c->put_hevc_epel[7][1][1] = ff_hevc_put_hevc_epel_hv32_8_avx2; - c->put_hevc_epel[8][1][1] = ff_hevc_put_hevc_epel_hv48_8_avx2; - c->put_hevc_epel[9][1][1] = ff_hevc_put_hevc_epel_hv64_8_avx2; + c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_bi_epel_v32_8_avx2; + c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_bi_epel_v48_8_avx2; + c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_bi_epel_v64_8_avx2; - c->put_hevc_epel_uni[7][1][1] = ff_hevc_put_hevc_uni_epel_hv32_8_avx2; - c->put_hevc_epel_uni[8][1][1] = ff_hevc_put_hevc_uni_epel_hv48_8_avx2; - c->put_hevc_epel_uni[9][1][1] = ff_hevc_put_hevc_uni_epel_hv64_8_avx2; + c->put_hevc_epel[7][1][1] = hevc_put_epel_hv32_8_avx2; + c->put_hevc_epel[8][1][1] = hevc_put_epel_hv48_8_avx2; + c->put_hevc_epel[9][1][1] = hevc_put_epel_hv64_8_avx2; - c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_hevc_bi_epel_hv32_8_avx2; - c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_hevc_bi_epel_hv48_8_avx2; - c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_hevc_bi_epel_hv64_8_avx2; + c->put_hevc_epel_uni[7][1][1] = hevc_put_uni_epel_hv32_8_avx2; + c->put_hevc_epel_uni[8][1][1] = hevc_put_uni_epel_hv48_8_avx2; + c->put_hevc_epel_uni[9][1][1] = hevc_put_uni_epel_hv64_8_avx2; - c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_8_avx2; - c->put_hevc_qpel[8][0][1] = ff_hevc_put_hevc_qpel_h48_8_avx2; - c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_8_avx2; + c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_bi_epel_hv32_8_avx2; + c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_bi_epel_hv48_8_avx2; + c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_bi_epel_hv64_8_avx2; - c->put_hevc_qpel[7][1][0] = ff_hevc_put_hevc_qpel_v32_8_avx2; - c->put_hevc_qpel[8][1][0] = ff_hevc_put_hevc_qpel_v48_8_avx2; - c->put_hevc_qpel[9][1][0] = ff_hevc_put_hevc_qpel_v64_8_avx2; + c->put_hevc_qpel[7][0][1] = hevc_put_qpel_h32_8_avx2; + c->put_hevc_qpel[8][0][1] = hevc_put_qpel_h48_8_avx2; + c->put_hevc_qpel[9][0][1] = hevc_put_qpel_h64_8_avx2; - c->put_hevc_qpel_uni[7][0][1] = ff_hevc_put_hevc_uni_qpel_h32_8_avx2; - c->put_hevc_qpel_uni[8][0][1] = ff_hevc_put_hevc_uni_qpel_h48_8_avx2; - c->put_hevc_qpel_uni[9][0][1] = ff_hevc_put_hevc_uni_qpel_h64_8_avx2; + c->put_hevc_qpel[7][1][0] = hevc_put_qpel_v32_8_avx2; + c->put_hevc_qpel[8][1][0] = hevc_put_qpel_v48_8_avx2; + c->put_hevc_qpel[9][1][0] = hevc_put_qpel_v64_8_avx2; - c->put_hevc_qpel_uni[7][1][0] = ff_hevc_put_hevc_uni_qpel_v32_8_avx2; - c->put_hevc_qpel_uni[8][1][0] = ff_hevc_put_hevc_uni_qpel_v48_8_avx2; - c->put_hevc_qpel_uni[9][1][0] = ff_hevc_put_hevc_uni_qpel_v64_8_avx2; + c->put_hevc_qpel_uni[7][0][1] = hevc_put_uni_qpel_h32_8_avx2; + c->put_hevc_qpel_uni[8][0][1] = hevc_put_uni_qpel_h48_8_avx2; + c->put_hevc_qpel_uni[9][0][1] = hevc_put_uni_qpel_h64_8_avx2; - c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_hevc_bi_qpel_h32_8_avx2; - c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_hevc_bi_qpel_h48_8_avx2; - c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_hevc_bi_qpel_h64_8_avx2; + c->put_hevc_qpel_uni[7][1][0] = hevc_put_uni_qpel_v32_8_avx2; + c->put_hevc_qpel_uni[8][1][0] = hevc_put_uni_qpel_v48_8_avx2; + c->put_hevc_qpel_uni[9][1][0] = hevc_put_uni_qpel_v64_8_avx2; + + c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_bi_qpel_h32_8_avx2; + c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_bi_qpel_h48_8_avx2; + c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_bi_qpel_h64_8_avx2; + + c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_bi_qpel_v32_8_avx2; + c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_bi_qpel_v48_8_avx2; + c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_bi_qpel_v64_8_avx2; +#endif /* ARCH_X86_64 */ - c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_hevc_bi_qpel_v32_8_avx2; - c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_hevc_bi_qpel_v48_8_avx2; - c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_hevc_bi_qpel_v64_8_avx2; - } SAO_BAND_INIT(8, avx2); c->sao_edge_filter[2] = ff_hevc_sao_edge_filter_32_8_avx2; @@ -974,32 +984,35 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) c->add_residual[3] = ff_hevc_add_residual_32_8_avx2; } - if (EXTERNAL_AVX512ICL(cpu_flags) && ARCH_X86_64) { - c->put_hevc_qpel[1][0][1] = ff_hevc_put_hevc_qpel_h4_8_avx512icl; - c->put_hevc_qpel[3][0][1] = ff_hevc_put_hevc_qpel_h8_8_avx512icl; - c->put_hevc_qpel[5][0][1] = ff_hevc_put_hevc_qpel_h16_8_avx512icl; - c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_8_avx512icl; - c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_8_avx512icl; - c->put_hevc_qpel[3][1][1] = ff_hevc_put_hevc_qpel_hv8_8_avx512icl; +#endif /* HAVE_AVX2_EXTERNAL */ +#if ARCH_X86_64 + if (EXTERNAL_AVX512ICL(cpu_flags)) { + c->put_hevc_qpel[1][0][1] = ff_hevc_put_qpel_h4_8_avx512icl; + c->put_hevc_qpel[3][0][1] = ff_hevc_put_qpel_h8_8_avx512icl; + c->put_hevc_qpel[5][0][1] = ff_hevc_put_qpel_h16_8_avx512icl; + c->put_hevc_qpel[7][0][1] = ff_hevc_put_qpel_h32_8_avx512icl; + c->put_hevc_qpel[9][0][1] = ff_hevc_put_qpel_h64_8_avx512icl; + c->put_hevc_qpel[3][1][1] = ff_hevc_put_qpel_hv8_8_avx512icl; } +#endif } else if (bit_depth == 10) { if (EXTERNAL_MMXEXT(cpu_flags)) { c->add_residual[0] = ff_hevc_add_residual_4_10_mmxext; - c->idct_dc[0] = ff_hevc_idct_4x4_dc_10_mmxext; } if (EXTERNAL_SSE2(cpu_flags)) { c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_10_sse2; c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_10_sse2; - if (ARCH_X86_64) { - c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_sse2; - c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_sse2; +#if ARCH_X86_64 + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_sse2; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_sse2; - c->idct[2] = ff_hevc_idct_16x16_10_sse2; - c->idct[3] = ff_hevc_idct_32x32_10_sse2; - } + c->idct[2] = ff_hevc_idct_16x16_10_sse2; + c->idct[3] = ff_hevc_idct_32x32_10_sse2; +#endif SAO_BAND_INIT(10, sse2); SAO_EDGE_INIT(10, sse2); + c->idct_dc[0] = ff_hevc_idct_4x4_dc_10_sse2; c->idct_dc[1] = ff_hevc_idct_8x8_dc_10_sse2; c->idct_dc[2] = ff_hevc_idct_16x16_dc_10_sse2; c->idct_dc[3] = ff_hevc_idct_32x32_dc_10_sse2; @@ -1011,11 +1024,14 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) c->add_residual[2] = ff_hevc_add_residual_16_10_sse2; c->add_residual[3] = ff_hevc_add_residual_32_10_sse2; } - if (EXTERNAL_SSSE3(cpu_flags) && ARCH_X86_64) { +#if ARCH_X86_64 + if (EXTERNAL_SSSE3(cpu_flags)) { c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_ssse3; c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_ssse3; } - if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) { +#endif +#if HAVE_SSE4_EXTERNAL && ARCH_X86_64 + if (EXTERNAL_SSE4(cpu_flags)) { EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 10, sse4); EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 10, sse4); EPEL_LINKS(c->put_hevc_epel, 1, 0, epel_v, 10, sse4); @@ -1026,16 +1042,17 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 10, sse4); QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 10, sse4); } +#endif if (EXTERNAL_AVX(cpu_flags)) { c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_10_avx; c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_10_avx; - if (ARCH_X86_64) { - c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_avx; - c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_avx; +#if ARCH_X86_64 + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_avx; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_avx; - c->idct[2] = ff_hevc_idct_16x16_10_avx; - c->idct[3] = ff_hevc_idct_32x32_10_avx; - } + c->idct[2] = ff_hevc_idct_16x16_10_avx; + c->idct[3] = ff_hevc_idct_32x32_10_avx; +#endif c->idct[0] = ff_hevc_idct_4x4_10_avx; c->idct[1] = ff_hevc_idct_8x8_10_avx; @@ -1045,182 +1062,187 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) if (EXTERNAL_AVX2(cpu_flags)) { c->sao_band_filter[0] = ff_hevc_sao_band_filter_8_10_avx2; } +#if HAVE_AVX2_EXTERNAL if (EXTERNAL_AVX2_FAST(cpu_flags)) { c->idct_dc[2] = ff_hevc_idct_16x16_dc_10_avx2; c->idct_dc[3] = ff_hevc_idct_32x32_dc_10_avx2; - if (ARCH_X86_64) { - c->put_hevc_epel[5][0][0] = ff_hevc_put_hevc_pel_pixels16_10_avx2; - c->put_hevc_epel[6][0][0] = ff_hevc_put_hevc_pel_pixels24_10_avx2; - c->put_hevc_epel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_10_avx2; - c->put_hevc_epel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_10_avx2; - c->put_hevc_epel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_10_avx2; - c->put_hevc_qpel[5][0][0] = ff_hevc_put_hevc_pel_pixels16_10_avx2; - c->put_hevc_qpel[6][0][0] = ff_hevc_put_hevc_pel_pixels24_10_avx2; - c->put_hevc_qpel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_10_avx2; - c->put_hevc_qpel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_10_avx2; - c->put_hevc_qpel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_10_avx2; +#if ARCH_X86_64 + c->put_hevc_epel[5][0][0] = hevc_put_pel_pixels16_10_avx2; + c->put_hevc_epel[6][0][0] = hevc_put_pel_pixels24_10_avx2; + c->put_hevc_epel[7][0][0] = hevc_put_pel_pixels32_10_avx2; + c->put_hevc_epel[8][0][0] = hevc_put_pel_pixels48_10_avx2; + c->put_hevc_epel[9][0][0] = hevc_put_pel_pixels64_10_avx2; - c->put_hevc_epel_uni[5][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; - c->put_hevc_epel_uni[6][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; - c->put_hevc_epel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; - c->put_hevc_epel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels96_8_avx2; - c->put_hevc_epel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels128_8_avx2; + c->put_hevc_qpel[5][0][0] = hevc_put_pel_pixels16_10_avx2; + c->put_hevc_qpel[6][0][0] = hevc_put_pel_pixels24_10_avx2; + c->put_hevc_qpel[7][0][0] = hevc_put_pel_pixels32_10_avx2; + c->put_hevc_qpel[8][0][0] = hevc_put_pel_pixels48_10_avx2; + c->put_hevc_qpel[9][0][0] = hevc_put_pel_pixels64_10_avx2; - c->put_hevc_qpel_uni[5][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; - c->put_hevc_qpel_uni[6][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; - c->put_hevc_qpel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; - c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels96_8_avx2; - c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels128_8_avx2; + c->put_hevc_epel_uni[5][0][0] = hevc_put_uni_pel_pixels32_8_avx2; + c->put_hevc_epel_uni[6][0][0] = hevc_put_uni_pel_pixels48_8_avx2; + c->put_hevc_epel_uni[7][0][0] = hevc_put_uni_pel_pixels64_8_avx2; + c->put_hevc_epel_uni[8][0][0] = hevc_put_uni_pel_pixels96_8_avx2; + c->put_hevc_epel_uni[9][0][0] = hevc_put_uni_pel_pixels128_8_avx2; - c->put_hevc_epel_bi[5][0][0] = ff_hevc_put_hevc_bi_pel_pixels16_10_avx2; - c->put_hevc_epel_bi[6][0][0] = ff_hevc_put_hevc_bi_pel_pixels24_10_avx2; - c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_10_avx2; - c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_10_avx2; - c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_10_avx2; - c->put_hevc_qpel_bi[5][0][0] = ff_hevc_put_hevc_bi_pel_pixels16_10_avx2; - c->put_hevc_qpel_bi[6][0][0] = ff_hevc_put_hevc_bi_pel_pixels24_10_avx2; - c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_10_avx2; - c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_10_avx2; - c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_10_avx2; + c->put_hevc_qpel_uni[5][0][0] = hevc_put_uni_pel_pixels32_8_avx2; + c->put_hevc_qpel_uni[6][0][0] = hevc_put_uni_pel_pixels48_8_avx2; + c->put_hevc_qpel_uni[7][0][0] = hevc_put_uni_pel_pixels64_8_avx2; + c->put_hevc_qpel_uni[8][0][0] = hevc_put_uni_pel_pixels96_8_avx2; + c->put_hevc_qpel_uni[9][0][0] = hevc_put_uni_pel_pixels128_8_avx2; - c->put_hevc_epel[5][0][1] = ff_hevc_put_hevc_epel_h16_10_avx2; - c->put_hevc_epel[6][0][1] = ff_hevc_put_hevc_epel_h24_10_avx2; - c->put_hevc_epel[7][0][1] = ff_hevc_put_hevc_epel_h32_10_avx2; - c->put_hevc_epel[8][0][1] = ff_hevc_put_hevc_epel_h48_10_avx2; - c->put_hevc_epel[9][0][1] = ff_hevc_put_hevc_epel_h64_10_avx2; + c->put_hevc_epel_bi[5][0][0] = ff_hevc_put_bi_pel_pixels16_10_avx2; + c->put_hevc_epel_bi[6][0][0] = ff_hevc_put_bi_pel_pixels24_10_avx2; + c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_bi_pel_pixels32_10_avx2; + c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_bi_pel_pixels48_10_avx2; + c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_bi_pel_pixels64_10_avx2; + c->put_hevc_qpel_bi[5][0][0] = ff_hevc_put_bi_pel_pixels16_10_avx2; + c->put_hevc_qpel_bi[6][0][0] = ff_hevc_put_bi_pel_pixels24_10_avx2; + c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_bi_pel_pixels32_10_avx2; + c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_bi_pel_pixels48_10_avx2; + c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_bi_pel_pixels64_10_avx2; - c->put_hevc_epel_uni[5][0][1] = ff_hevc_put_hevc_uni_epel_h16_10_avx2; - c->put_hevc_epel_uni[6][0][1] = ff_hevc_put_hevc_uni_epel_h24_10_avx2; - c->put_hevc_epel_uni[7][0][1] = ff_hevc_put_hevc_uni_epel_h32_10_avx2; - c->put_hevc_epel_uni[8][0][1] = ff_hevc_put_hevc_uni_epel_h48_10_avx2; - c->put_hevc_epel_uni[9][0][1] = ff_hevc_put_hevc_uni_epel_h64_10_avx2; + c->put_hevc_epel[5][0][1] = hevc_put_epel_h16_10_avx2; + c->put_hevc_epel[6][0][1] = hevc_put_epel_h24_10_avx2; + c->put_hevc_epel[7][0][1] = hevc_put_epel_h32_10_avx2; + c->put_hevc_epel[8][0][1] = hevc_put_epel_h48_10_avx2; + c->put_hevc_epel[9][0][1] = hevc_put_epel_h64_10_avx2; - c->put_hevc_epel_bi[5][0][1] = ff_hevc_put_hevc_bi_epel_h16_10_avx2; - c->put_hevc_epel_bi[6][0][1] = ff_hevc_put_hevc_bi_epel_h24_10_avx2; - c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_hevc_bi_epel_h32_10_avx2; - c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_hevc_bi_epel_h48_10_avx2; - c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_hevc_bi_epel_h64_10_avx2; + c->put_hevc_epel_uni[5][0][1] = hevc_put_uni_epel_h16_10_avx2; + c->put_hevc_epel_uni[6][0][1] = hevc_put_uni_epel_h24_10_avx2; + c->put_hevc_epel_uni[7][0][1] = hevc_put_uni_epel_h32_10_avx2; + c->put_hevc_epel_uni[8][0][1] = hevc_put_uni_epel_h48_10_avx2; + c->put_hevc_epel_uni[9][0][1] = hevc_put_uni_epel_h64_10_avx2; - c->put_hevc_epel[5][1][0] = ff_hevc_put_hevc_epel_v16_10_avx2; - c->put_hevc_epel[6][1][0] = ff_hevc_put_hevc_epel_v24_10_avx2; - c->put_hevc_epel[7][1][0] = ff_hevc_put_hevc_epel_v32_10_avx2; - c->put_hevc_epel[8][1][0] = ff_hevc_put_hevc_epel_v48_10_avx2; - c->put_hevc_epel[9][1][0] = ff_hevc_put_hevc_epel_v64_10_avx2; + c->put_hevc_epel_bi[5][0][1] = ff_hevc_put_bi_epel_h16_10_avx2; + c->put_hevc_epel_bi[6][0][1] = ff_hevc_put_bi_epel_h24_10_avx2; + c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_bi_epel_h32_10_avx2; + c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_bi_epel_h48_10_avx2; + c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_bi_epel_h64_10_avx2; - c->put_hevc_epel_uni[5][1][0] = ff_hevc_put_hevc_uni_epel_v16_10_avx2; - c->put_hevc_epel_uni[6][1][0] = ff_hevc_put_hevc_uni_epel_v24_10_avx2; - c->put_hevc_epel_uni[7][1][0] = ff_hevc_put_hevc_uni_epel_v32_10_avx2; - c->put_hevc_epel_uni[8][1][0] = ff_hevc_put_hevc_uni_epel_v48_10_avx2; - c->put_hevc_epel_uni[9][1][0] = ff_hevc_put_hevc_uni_epel_v64_10_avx2; + c->put_hevc_epel[5][1][0] = hevc_put_epel_v16_10_avx2; + c->put_hevc_epel[6][1][0] = hevc_put_epel_v24_10_avx2; + c->put_hevc_epel[7][1][0] = hevc_put_epel_v32_10_avx2; + c->put_hevc_epel[8][1][0] = hevc_put_epel_v48_10_avx2; + c->put_hevc_epel[9][1][0] = hevc_put_epel_v64_10_avx2; - c->put_hevc_epel_bi[5][1][0] = ff_hevc_put_hevc_bi_epel_v16_10_avx2; - c->put_hevc_epel_bi[6][1][0] = ff_hevc_put_hevc_bi_epel_v24_10_avx2; - c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_hevc_bi_epel_v32_10_avx2; - c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_hevc_bi_epel_v48_10_avx2; - c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_hevc_bi_epel_v64_10_avx2; + c->put_hevc_epel_uni[5][1][0] = hevc_put_uni_epel_v16_10_avx2; + c->put_hevc_epel_uni[6][1][0] = hevc_put_uni_epel_v24_10_avx2; + c->put_hevc_epel_uni[7][1][0] = hevc_put_uni_epel_v32_10_avx2; + c->put_hevc_epel_uni[8][1][0] = hevc_put_uni_epel_v48_10_avx2; + c->put_hevc_epel_uni[9][1][0] = hevc_put_uni_epel_v64_10_avx2; - c->put_hevc_epel[5][1][1] = ff_hevc_put_hevc_epel_hv16_10_avx2; - c->put_hevc_epel[6][1][1] = ff_hevc_put_hevc_epel_hv24_10_avx2; - c->put_hevc_epel[7][1][1] = ff_hevc_put_hevc_epel_hv32_10_avx2; - c->put_hevc_epel[8][1][1] = ff_hevc_put_hevc_epel_hv48_10_avx2; - c->put_hevc_epel[9][1][1] = ff_hevc_put_hevc_epel_hv64_10_avx2; + c->put_hevc_epel_bi[5][1][0] = ff_hevc_put_bi_epel_v16_10_avx2; + c->put_hevc_epel_bi[6][1][0] = ff_hevc_put_bi_epel_v24_10_avx2; + c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_bi_epel_v32_10_avx2; + c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_bi_epel_v48_10_avx2; + c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_bi_epel_v64_10_avx2; - c->put_hevc_epel_uni[5][1][1] = ff_hevc_put_hevc_uni_epel_hv16_10_avx2; - c->put_hevc_epel_uni[6][1][1] = ff_hevc_put_hevc_uni_epel_hv24_10_avx2; - c->put_hevc_epel_uni[7][1][1] = ff_hevc_put_hevc_uni_epel_hv32_10_avx2; - c->put_hevc_epel_uni[8][1][1] = ff_hevc_put_hevc_uni_epel_hv48_10_avx2; - c->put_hevc_epel_uni[9][1][1] = ff_hevc_put_hevc_uni_epel_hv64_10_avx2; + c->put_hevc_epel[5][1][1] = hevc_put_epel_hv16_10_avx2; + c->put_hevc_epel[6][1][1] = hevc_put_epel_hv24_10_avx2; + c->put_hevc_epel[7][1][1] = hevc_put_epel_hv32_10_avx2; + c->put_hevc_epel[8][1][1] = hevc_put_epel_hv48_10_avx2; + c->put_hevc_epel[9][1][1] = hevc_put_epel_hv64_10_avx2; - c->put_hevc_epel_bi[5][1][1] = ff_hevc_put_hevc_bi_epel_hv16_10_avx2; - c->put_hevc_epel_bi[6][1][1] = ff_hevc_put_hevc_bi_epel_hv24_10_avx2; - c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_hevc_bi_epel_hv32_10_avx2; - c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_hevc_bi_epel_hv48_10_avx2; - c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_hevc_bi_epel_hv64_10_avx2; + c->put_hevc_epel_uni[5][1][1] = hevc_put_uni_epel_hv16_10_avx2; + c->put_hevc_epel_uni[6][1][1] = hevc_put_uni_epel_hv24_10_avx2; + c->put_hevc_epel_uni[7][1][1] = hevc_put_uni_epel_hv32_10_avx2; + c->put_hevc_epel_uni[8][1][1] = hevc_put_uni_epel_hv48_10_avx2; + c->put_hevc_epel_uni[9][1][1] = hevc_put_uni_epel_hv64_10_avx2; - c->put_hevc_qpel[5][0][1] = ff_hevc_put_hevc_qpel_h16_10_avx2; - c->put_hevc_qpel[6][0][1] = ff_hevc_put_hevc_qpel_h24_10_avx2; - c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_10_avx2; - c->put_hevc_qpel[8][0][1] = ff_hevc_put_hevc_qpel_h48_10_avx2; - c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_10_avx2; + c->put_hevc_epel_bi[5][1][1] = ff_hevc_put_bi_epel_hv16_10_avx2; + c->put_hevc_epel_bi[6][1][1] = ff_hevc_put_bi_epel_hv24_10_avx2; + c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_bi_epel_hv32_10_avx2; + c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_bi_epel_hv48_10_avx2; + c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_bi_epel_hv64_10_avx2; - c->put_hevc_qpel_uni[5][0][1] = ff_hevc_put_hevc_uni_qpel_h16_10_avx2; - c->put_hevc_qpel_uni[6][0][1] = ff_hevc_put_hevc_uni_qpel_h24_10_avx2; - c->put_hevc_qpel_uni[7][0][1] = ff_hevc_put_hevc_uni_qpel_h32_10_avx2; - c->put_hevc_qpel_uni[8][0][1] = ff_hevc_put_hevc_uni_qpel_h48_10_avx2; - c->put_hevc_qpel_uni[9][0][1] = ff_hevc_put_hevc_uni_qpel_h64_10_avx2; + c->put_hevc_qpel[5][0][1] = hevc_put_qpel_h16_10_avx2; + c->put_hevc_qpel[6][0][1] = hevc_put_qpel_h24_10_avx2; + c->put_hevc_qpel[7][0][1] = hevc_put_qpel_h32_10_avx2; + c->put_hevc_qpel[8][0][1] = hevc_put_qpel_h48_10_avx2; + c->put_hevc_qpel[9][0][1] = hevc_put_qpel_h64_10_avx2; - c->put_hevc_qpel_bi[5][0][1] = ff_hevc_put_hevc_bi_qpel_h16_10_avx2; - c->put_hevc_qpel_bi[6][0][1] = ff_hevc_put_hevc_bi_qpel_h24_10_avx2; - c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_hevc_bi_qpel_h32_10_avx2; - c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_hevc_bi_qpel_h48_10_avx2; - c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_hevc_bi_qpel_h64_10_avx2; + c->put_hevc_qpel_uni[5][0][1] = hevc_put_uni_qpel_h16_10_avx2; + c->put_hevc_qpel_uni[6][0][1] = hevc_put_uni_qpel_h24_10_avx2; + c->put_hevc_qpel_uni[7][0][1] = hevc_put_uni_qpel_h32_10_avx2; + c->put_hevc_qpel_uni[8][0][1] = hevc_put_uni_qpel_h48_10_avx2; + c->put_hevc_qpel_uni[9][0][1] = hevc_put_uni_qpel_h64_10_avx2; - c->put_hevc_qpel[5][1][0] = ff_hevc_put_hevc_qpel_v16_10_avx2; - c->put_hevc_qpel[6][1][0] = ff_hevc_put_hevc_qpel_v24_10_avx2; - c->put_hevc_qpel[7][1][0] = ff_hevc_put_hevc_qpel_v32_10_avx2; - c->put_hevc_qpel[8][1][0] = ff_hevc_put_hevc_qpel_v48_10_avx2; - c->put_hevc_qpel[9][1][0] = ff_hevc_put_hevc_qpel_v64_10_avx2; + c->put_hevc_qpel_bi[5][0][1] = ff_hevc_put_bi_qpel_h16_10_avx2; + c->put_hevc_qpel_bi[6][0][1] = ff_hevc_put_bi_qpel_h24_10_avx2; + c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_bi_qpel_h32_10_avx2; + c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_bi_qpel_h48_10_avx2; + c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_bi_qpel_h64_10_avx2; - c->put_hevc_qpel_uni[5][1][0] = ff_hevc_put_hevc_uni_qpel_v16_10_avx2; - c->put_hevc_qpel_uni[6][1][0] = ff_hevc_put_hevc_uni_qpel_v24_10_avx2; - c->put_hevc_qpel_uni[7][1][0] = ff_hevc_put_hevc_uni_qpel_v32_10_avx2; - c->put_hevc_qpel_uni[8][1][0] = ff_hevc_put_hevc_uni_qpel_v48_10_avx2; - c->put_hevc_qpel_uni[9][1][0] = ff_hevc_put_hevc_uni_qpel_v64_10_avx2; + c->put_hevc_qpel[5][1][0] = hevc_put_qpel_v16_10_avx2; + c->put_hevc_qpel[6][1][0] = hevc_put_qpel_v24_10_avx2; + c->put_hevc_qpel[7][1][0] = hevc_put_qpel_v32_10_avx2; + c->put_hevc_qpel[8][1][0] = hevc_put_qpel_v48_10_avx2; + c->put_hevc_qpel[9][1][0] = hevc_put_qpel_v64_10_avx2; - c->put_hevc_qpel_bi[5][1][0] = ff_hevc_put_hevc_bi_qpel_v16_10_avx2; - c->put_hevc_qpel_bi[6][1][0] = ff_hevc_put_hevc_bi_qpel_v24_10_avx2; - c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_hevc_bi_qpel_v32_10_avx2; - c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_hevc_bi_qpel_v48_10_avx2; - c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_hevc_bi_qpel_v64_10_avx2; + c->put_hevc_qpel_uni[5][1][0] = hevc_put_uni_qpel_v16_10_avx2; + c->put_hevc_qpel_uni[6][1][0] = hevc_put_uni_qpel_v24_10_avx2; + c->put_hevc_qpel_uni[7][1][0] = hevc_put_uni_qpel_v32_10_avx2; + c->put_hevc_qpel_uni[8][1][0] = hevc_put_uni_qpel_v48_10_avx2; + c->put_hevc_qpel_uni[9][1][0] = hevc_put_uni_qpel_v64_10_avx2; - c->put_hevc_qpel[5][1][1] = ff_hevc_put_hevc_qpel_hv16_10_avx2; - c->put_hevc_qpel[6][1][1] = ff_hevc_put_hevc_qpel_hv24_10_avx2; - c->put_hevc_qpel[7][1][1] = ff_hevc_put_hevc_qpel_hv32_10_avx2; - c->put_hevc_qpel[8][1][1] = ff_hevc_put_hevc_qpel_hv48_10_avx2; - c->put_hevc_qpel[9][1][1] = ff_hevc_put_hevc_qpel_hv64_10_avx2; + c->put_hevc_qpel_bi[5][1][0] = ff_hevc_put_bi_qpel_v16_10_avx2; + c->put_hevc_qpel_bi[6][1][0] = ff_hevc_put_bi_qpel_v24_10_avx2; + c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_bi_qpel_v32_10_avx2; + c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_bi_qpel_v48_10_avx2; + c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_bi_qpel_v64_10_avx2; - c->put_hevc_qpel_uni[5][1][1] = ff_hevc_put_hevc_uni_qpel_hv16_10_avx2; - c->put_hevc_qpel_uni[6][1][1] = ff_hevc_put_hevc_uni_qpel_hv24_10_avx2; - c->put_hevc_qpel_uni[7][1][1] = ff_hevc_put_hevc_uni_qpel_hv32_10_avx2; - c->put_hevc_qpel_uni[8][1][1] = ff_hevc_put_hevc_uni_qpel_hv48_10_avx2; - c->put_hevc_qpel_uni[9][1][1] = ff_hevc_put_hevc_uni_qpel_hv64_10_avx2; + c->put_hevc_qpel[5][1][1] = hevc_put_qpel_hv16_10_avx2; + c->put_hevc_qpel[6][1][1] = hevc_put_qpel_hv24_10_avx2; + c->put_hevc_qpel[7][1][1] = hevc_put_qpel_hv32_10_avx2; + c->put_hevc_qpel[8][1][1] = hevc_put_qpel_hv48_10_avx2; + c->put_hevc_qpel[9][1][1] = hevc_put_qpel_hv64_10_avx2; + + c->put_hevc_qpel_uni[5][1][1] = hevc_put_uni_qpel_hv16_10_avx2; + c->put_hevc_qpel_uni[6][1][1] = hevc_put_uni_qpel_hv24_10_avx2; + c->put_hevc_qpel_uni[7][1][1] = hevc_put_uni_qpel_hv32_10_avx2; + c->put_hevc_qpel_uni[8][1][1] = hevc_put_uni_qpel_hv48_10_avx2; + c->put_hevc_qpel_uni[9][1][1] = hevc_put_uni_qpel_hv64_10_avx2; + + c->put_hevc_qpel_bi[5][1][1] = ff_hevc_put_bi_qpel_hv16_10_avx2; + c->put_hevc_qpel_bi[6][1][1] = ff_hevc_put_bi_qpel_hv24_10_avx2; + c->put_hevc_qpel_bi[7][1][1] = ff_hevc_put_bi_qpel_hv32_10_avx2; + c->put_hevc_qpel_bi[8][1][1] = ff_hevc_put_bi_qpel_hv48_10_avx2; + c->put_hevc_qpel_bi[9][1][1] = ff_hevc_put_bi_qpel_hv64_10_avx2; +#endif /* ARCH_X86_64 */ - c->put_hevc_qpel_bi[5][1][1] = ff_hevc_put_hevc_bi_qpel_hv16_10_avx2; - c->put_hevc_qpel_bi[6][1][1] = ff_hevc_put_hevc_bi_qpel_hv24_10_avx2; - c->put_hevc_qpel_bi[7][1][1] = ff_hevc_put_hevc_bi_qpel_hv32_10_avx2; - c->put_hevc_qpel_bi[8][1][1] = ff_hevc_put_hevc_bi_qpel_hv48_10_avx2; - c->put_hevc_qpel_bi[9][1][1] = ff_hevc_put_hevc_bi_qpel_hv64_10_avx2; - } SAO_BAND_INIT(10, avx2); SAO_EDGE_INIT(10, avx2); c->add_residual[2] = ff_hevc_add_residual_16_10_avx2; c->add_residual[3] = ff_hevc_add_residual_32_10_avx2; } +#endif /* HAVE_AVX2_EXTERNAL */ } else if (bit_depth == 12) { - if (EXTERNAL_MMXEXT(cpu_flags)) { - c->idct_dc[0] = ff_hevc_idct_4x4_dc_12_mmxext; - } if (EXTERNAL_SSE2(cpu_flags)) { c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_12_sse2; c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_12_sse2; - if (ARCH_X86_64) { - c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_sse2; - c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_sse2; - } +#if ARCH_X86_64 + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_sse2; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_sse2; +#endif SAO_BAND_INIT(12, sse2); SAO_EDGE_INIT(12, sse2); + c->idct_dc[0] = ff_hevc_idct_4x4_dc_12_sse2; c->idct_dc[1] = ff_hevc_idct_8x8_dc_12_sse2; c->idct_dc[2] = ff_hevc_idct_16x16_dc_12_sse2; c->idct_dc[3] = ff_hevc_idct_32x32_dc_12_sse2; } - if (EXTERNAL_SSSE3(cpu_flags) && ARCH_X86_64) { +#if ARCH_X86_64 + if (EXTERNAL_SSSE3(cpu_flags)) { c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_ssse3; c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_ssse3; } - if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) { +#endif +#if HAVE_SSE4_EXTERNAL && ARCH_X86_64 + if (EXTERNAL_SSE4(cpu_flags)) { EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 12, sse4); EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 12, sse4); EPEL_LINKS(c->put_hevc_epel, 1, 0, epel_v, 12, sse4); @@ -1231,13 +1253,14 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 12, sse4); QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 12, sse4); } +#endif if (EXTERNAL_AVX(cpu_flags)) { c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_12_avx; c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_12_avx; - if (ARCH_X86_64) { - c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_avx; - c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_avx; - } +#if ARCH_X86_64 + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_avx; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_avx; +#endif SAO_BAND_INIT(12, avx); } if (EXTERNAL_AVX2(cpu_flags)) { diff --git a/libavcodec/x86/hevc_idct.asm b/libavcodec/x86/hevc/idct.asm similarity index 98% rename from libavcodec/x86/hevc_idct.asm rename to libavcodec/x86/hevc/idct.asm index ce41f3382..088144171 100644 --- a/libavcodec/x86/hevc_idct.asm +++ b/libavcodec/x86/hevc/idct.asm @@ -25,7 +25,7 @@ SECTION_RODATA -pd_64: times 4 dd 64 +cextern pd_64 pd_2048: times 4 dd 2048 pd_512: times 4 dd 512 @@ -273,16 +273,11 @@ cglobal hevc_idct_%1x%1_dc_%2, 1, 2, 1, coeff, tmp sar tmpd, (15 - %2) movd m0, tmpd SPLATW m0, xm0 - mova [coeffq+mmsize*0], m0 - mova [coeffq+mmsize*1], m0 - mova [coeffq+mmsize*2], m0 - mova [coeffq+mmsize*3], m0 -%if mmsize == 16 - mova [coeffq+mmsize*4], m0 - mova [coeffq+mmsize*5], m0 - mova [coeffq+mmsize*6], m0 - mova [coeffq+mmsize*7], m0 -%endif +%assign %%offset 0 +%rep 2*%1*%1/mmsize + mova [coeffq+%%offset], m0 + %assign %%offset %%offset+mmsize +%endrep RET %endmacro @@ -532,7 +527,7 @@ cglobal hevc_idct_8x8_%1, 1, 1, 8, coeffs ; %1, %2 - transform constants ; %3, %4 - regs with interleaved coeffs ; %5 - 1/0 SWAP or add -; %6, %7 - registers for intermidiate sums +; %6, %7 - registers for intermediate sums ; %8 - accumulator register %macro ADD_ROWS 8 pmaddwd %6, %3, %1 @@ -809,10 +804,8 @@ cglobal hevc_idct_32x32_%1, 1, 6, 16, 256, coeffs %endmacro %macro INIT_IDCT_DC 1 -INIT_MMX mmxext -IDCT_DC_NL 4, %1 - INIT_XMM sse2 +IDCT_DC_NL 4, %1 IDCT_DC_NL 8, %1 IDCT_DC 16, 4, %1 IDCT_DC 32, 16, %1 diff --git a/libavcodec/x86/hevc_mc.asm b/libavcodec/x86/hevc/mc.asm similarity index 95% rename from libavcodec/x86/hevc_mc.asm rename to libavcodec/x86/hevc/mc.asm index b3b589b27..550f7a0e2 100644 --- a/libavcodec/x86/hevc_mc.asm +++ b/libavcodec/x86/hevc/mc.asm @@ -716,7 +716,7 @@ SECTION .text ; ****************************** %macro HEVC_BI_PEL_PIXELS 2 -cglobal hevc_put_hevc_bi_pel_pixels%1_%2, 6, 6, 6, dst, dststride, src, srcstride, src2, height +cglobal hevc_put_bi_pel_pixels%1_%2, 6, 6, 6, dst, dststride, src, srcstride, src2, height pxor m2, m2 movdqa m5, [pw_bi_%2] .loop: @@ -748,7 +748,7 @@ cglobal hevc_put_hevc_bi_pel_pixels%1_%2, 6, 6, 6, dst, dststride, src, srcstrid %define XMM_REGS 8 %endif -cglobal hevc_put_hevc_bi_epel_h%1_%2, 7, 8, XMM_REGS, dst, dststride, src, srcstride, src2, height, mx, rfilter +cglobal hevc_put_bi_epel_h%1_%2, 7, 8, XMM_REGS, dst, dststride, src, srcstride, src2, height, mx, rfilter %assign %%stride ((%2 + 7)/8) movdqa m6, [pw_bi_%2] EPEL_FILTER %2, mx, m4, m5, rfilter @@ -771,7 +771,7 @@ cglobal hevc_put_hevc_bi_epel_h%1_%2, 7, 8, XMM_REGS, dst, dststride, src, srcst ; int height, int mx, int my, int width) ; ****************************** -cglobal hevc_put_hevc_bi_epel_v%1_%2, 6, 8, XMM_REGS, dst, dststride, src, srcstride, src2, height, r3src, my +cglobal hevc_put_bi_epel_v%1_%2, 6, 8, XMM_REGS, dst, dststride, src, srcstride, src2, height, r3src, my movifnidn myd, mym movdqa m6, [pw_bi_%2] sub srcq, srcstrideq @@ -800,7 +800,7 @@ cglobal hevc_put_hevc_bi_epel_v%1_%2, 6, 8, XMM_REGS, dst, dststride, src, srcst %macro HEVC_PUT_HEVC_EPEL_HV 2 -cglobal hevc_put_hevc_bi_epel_hv%1_%2, 8, 9, 16, dst, dststride, src, srcstride, src2, height, mx, my, r3src +cglobal hevc_put_bi_epel_hv%1_%2, 8, 9, 16, dst, dststride, src, srcstride, src2, height, mx, my, r3src %assign %%stride ((%2 + 7)/8) sub srcq, srcstrideq EPEL_HV_FILTER %2 @@ -882,7 +882,7 @@ cglobal hevc_put_hevc_bi_epel_hv%1_%2, 8, 9, 16, dst, dststride, src, srcstride, %macro HEVC_PUT_HEVC_QPEL 2 -cglobal hevc_put_hevc_bi_qpel_h%1_%2, 7, 8, 16 , dst, dststride, src, srcstride, src2, height, mx, rfilter +cglobal hevc_put_bi_qpel_h%1_%2, 7, 8, 16 , dst, dststride, src, srcstride, src2, height, mx, rfilter movdqa m9, [pw_bi_%2] QPEL_FILTER %2, mx .loop: @@ -909,7 +909,7 @@ cglobal hevc_put_hevc_bi_qpel_h%1_%2, 7, 8, 16 , dst, dststride, src, srcstride, ; ****************************** -cglobal hevc_put_hevc_bi_qpel_v%1_%2, 6, 10, 16, dst, dststride, src, srcstride, src2, height, r3src, my, rfilter +cglobal hevc_put_bi_qpel_v%1_%2, 6, 10, 16, dst, dststride, src, srcstride, src2, height, r3src, my, rfilter movifnidn myd, mym movdqa m9, [pw_bi_%2] lea r3srcq, [srcstrideq*3] @@ -939,7 +939,7 @@ cglobal hevc_put_hevc_bi_qpel_v%1_%2, 6, 10, 16, dst, dststride, src, srcstride, ; ****************************** %macro HEVC_PUT_HEVC_QPEL_HV 2 -cglobal hevc_put_hevc_bi_qpel_hv%1_%2, 8, 10, 16, dst, dststride, src, srcstride, src2, height, mx, my, r3src, rfilter +cglobal hevc_put_bi_qpel_hv%1_%2, 8, 10, 16, dst, dststride, src, srcstride, src2, height, mx, my, r3src, rfilter %if cpuflag(avx2) %assign %%shift 4 %else @@ -1025,11 +1025,11 @@ cglobal hevc_put_hevc_bi_qpel_hv%1_%2, 8, 10, 16, dst, dststride, src, srcstride %macro WEIGHTING_FUNCS 2 %if WIN64 || ARCH_X86_32 -cglobal hevc_put_hevc_uni_w%1_%2, 4, 5, 7, dst, dststride, src, height, denom, wx, ox +cglobal hevc_put_uni_w%1_%2, 4, 5, 7, dst, dststride, src, height, denom, wx, ox mov r4d, denomm %define SHIFT r4d %else -cglobal hevc_put_hevc_uni_w%1_%2, 6, 6, 7, dst, dststride, src, height, denom, wx, ox +cglobal hevc_put_uni_w%1_%2, 6, 6, 7, dst, dststride, src, height, denom, wx, ox %define SHIFT denomd %endif lea SHIFT, [SHIFT+14-%2] ; shift = 14 - bitd + denom @@ -1090,7 +1090,7 @@ cglobal hevc_put_hevc_uni_w%1_%2, 6, 6, 7, dst, dststride, src, height, denom, w jnz .loop ; height loop RET -cglobal hevc_put_hevc_bi_w%1_%2, 4, 6, 10, dst, dststride, src, src2, height, denom, wx0, wx1, ox0, ox1 +cglobal hevc_put_bi_w%1_%2, 4, 6, 10, dst, dststride, src, src2, height, denom, wx0, wx1, ox0, ox1 movifnidn r5d, denomm %if %1 <= 4 pxor m1, m1 @@ -1170,39 +1170,32 @@ cglobal hevc_put_hevc_bi_w%1_%2, 4, 6, 10, dst, dststride, src, src2, height, de INIT_XMM sse4 ; adds ff_ and _sse4 to function name -WEIGHTING_FUNCS 2, 8 WEIGHTING_FUNCS 4, 8 WEIGHTING_FUNCS 6, 8 WEIGHTING_FUNCS 8, 8 -WEIGHTING_FUNCS 2, 10 WEIGHTING_FUNCS 4, 10 WEIGHTING_FUNCS 6, 10 WEIGHTING_FUNCS 8, 10 -WEIGHTING_FUNCS 2, 12 WEIGHTING_FUNCS 4, 12 WEIGHTING_FUNCS 6, 12 WEIGHTING_FUNCS 8, 12 -HEVC_BI_PEL_PIXELS 2, 8 HEVC_BI_PEL_PIXELS 4, 8 HEVC_BI_PEL_PIXELS 6, 8 HEVC_BI_PEL_PIXELS 8, 8 HEVC_BI_PEL_PIXELS 12, 8 HEVC_BI_PEL_PIXELS 16, 8 -HEVC_BI_PEL_PIXELS 2, 10 HEVC_BI_PEL_PIXELS 4, 10 HEVC_BI_PEL_PIXELS 6, 10 HEVC_BI_PEL_PIXELS 8, 10 -HEVC_BI_PEL_PIXELS 2, 12 HEVC_BI_PEL_PIXELS 4, 12 HEVC_BI_PEL_PIXELS 6, 12 HEVC_BI_PEL_PIXELS 8, 12 -HEVC_PUT_HEVC_EPEL 2, 8 HEVC_PUT_HEVC_EPEL 4, 8 HEVC_PUT_HEVC_EPEL 6, 8 HEVC_PUT_HEVC_EPEL 8, 8 @@ -1210,28 +1203,23 @@ HEVC_PUT_HEVC_EPEL 12, 8 HEVC_PUT_HEVC_EPEL 16, 8 -HEVC_PUT_HEVC_EPEL 2, 10 HEVC_PUT_HEVC_EPEL 4, 10 HEVC_PUT_HEVC_EPEL 6, 10 HEVC_PUT_HEVC_EPEL 8, 10 -HEVC_PUT_HEVC_EPEL 2, 12 HEVC_PUT_HEVC_EPEL 4, 12 HEVC_PUT_HEVC_EPEL 6, 12 HEVC_PUT_HEVC_EPEL 8, 12 -HEVC_PUT_HEVC_EPEL_HV 2, 8 HEVC_PUT_HEVC_EPEL_HV 4, 8 HEVC_PUT_HEVC_EPEL_HV 6, 8 HEVC_PUT_HEVC_EPEL_HV 8, 8 HEVC_PUT_HEVC_EPEL_HV 16, 8 -HEVC_PUT_HEVC_EPEL_HV 2, 10 HEVC_PUT_HEVC_EPEL_HV 4, 10 HEVC_PUT_HEVC_EPEL_HV 6, 10 HEVC_PUT_HEVC_EPEL_HV 8, 10 -HEVC_PUT_HEVC_EPEL_HV 2, 12 HEVC_PUT_HEVC_EPEL_HV 4, 12 HEVC_PUT_HEVC_EPEL_HV 6, 12 HEVC_PUT_HEVC_EPEL_HV 8, 12 @@ -1247,19 +1235,13 @@ HEVC_PUT_HEVC_QPEL 8, 10 HEVC_PUT_HEVC_QPEL 4, 12 HEVC_PUT_HEVC_QPEL 8, 12 -HEVC_PUT_HEVC_QPEL_HV 2, 8 HEVC_PUT_HEVC_QPEL_HV 4, 8 -HEVC_PUT_HEVC_QPEL_HV 6, 8 HEVC_PUT_HEVC_QPEL_HV 8, 8 -HEVC_PUT_HEVC_QPEL_HV 2, 10 HEVC_PUT_HEVC_QPEL_HV 4, 10 -HEVC_PUT_HEVC_QPEL_HV 6, 10 HEVC_PUT_HEVC_QPEL_HV 8, 10 -HEVC_PUT_HEVC_QPEL_HV 2, 12 HEVC_PUT_HEVC_QPEL_HV 4, 12 -HEVC_PUT_HEVC_QPEL_HV 6, 12 HEVC_PUT_HEVC_QPEL_HV 8, 12 %if HAVE_AVX2_EXTERNAL @@ -1329,7 +1311,7 @@ HEVC_PUT_HEVC_QPEL_HV 16, 10 %endmacro %macro HEVC_PUT_HEVC_QPEL_AVX512ICL 2 -cglobal hevc_put_hevc_qpel_h%1_%2, 5, 6, 8, dst, src, srcstride, height, mx, tmp +cglobal hevc_put_qpel_h%1_%2, 5, 6, 8, dst, src, srcstride, height, mx, tmp QPEL_FILTER_H %1, mx, 0, 1, tmp QPEL_LOAD_SHUF 2, 3 .loop: @@ -1355,7 +1337,7 @@ cglobal hevc_put_hevc_qpel_h%1_%2, 5, 6, 8, dst, src, srcstride, height, mx, tmp %endmacro %macro HEVC_PUT_HEVC_QPEL_HV_AVX512ICL 2 -cglobal hevc_put_hevc_qpel_hv%1_%2, 6, 7, 27, dst, src, srcstride, height, mx, my, tmp +cglobal hevc_put_qpel_hv%1_%2, 6, 7, 27, dst, src, srcstride, height, mx, my, tmp %assign %%shift 6 %assign %%extra 7 QPEL_FILTER_H %1, mx, 0, 1, tmp diff --git a/libavcodec/x86/hevc/sao.asm b/libavcodec/x86/hevc/sao.asm new file mode 100644 index 000000000..c4f6db4cd --- /dev/null +++ b/libavcodec/x86/hevc/sao.asm @@ -0,0 +1,70 @@ +;****************************************************************************** +;* SIMD optimized SAO functions for HEVC 8bit decoding +;* +;* Copyright (c) 2013 Pierre-Edouard LEPERE +;* Copyright (c) 2014 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 +;****************************************************************************** + +%define MAX_PB_SIZE 64 +%include "libavcodec/x86/h26x/h2656_sao.asm" + +%macro HEVC_SAO_BAND_FILTER 2 + H2656_SAO_BAND_FILTER hevc, %1, %2 +%endmacro + +%macro HEVC_SAO_BAND_FILTER_FUNCS 0 +HEVC_SAO_BAND_FILTER 8, 0 +HEVC_SAO_BAND_FILTER 16, 1 +HEVC_SAO_BAND_FILTER 32, 2 +HEVC_SAO_BAND_FILTER 48, 2 +HEVC_SAO_BAND_FILTER 64, 4 +%endmacro + +INIT_XMM sse2 +HEVC_SAO_BAND_FILTER_FUNCS +INIT_XMM avx +HEVC_SAO_BAND_FILTER_FUNCS + +%if HAVE_AVX2_EXTERNAL +INIT_XMM avx2 +HEVC_SAO_BAND_FILTER 8, 0 +HEVC_SAO_BAND_FILTER 16, 1 +INIT_YMM avx2 +HEVC_SAO_BAND_FILTER 32, 1 +HEVC_SAO_BAND_FILTER 48, 1 +HEVC_SAO_BAND_FILTER 64, 2 +%endif + +%macro HEVC_SAO_EDGE_FILTER 2-3 + H2656_SAO_EDGE_FILTER hevc, %{1:-1} +%endmacro + +INIT_XMM ssse3 +HEVC_SAO_EDGE_FILTER 8, 0 +HEVC_SAO_EDGE_FILTER 16, 1, a +HEVC_SAO_EDGE_FILTER 32, 2, a +HEVC_SAO_EDGE_FILTER 48, 2, a +HEVC_SAO_EDGE_FILTER 64, 4, a + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +HEVC_SAO_EDGE_FILTER 32, 1, a +HEVC_SAO_EDGE_FILTER 48, 1, u +HEVC_SAO_EDGE_FILTER 64, 2, a +%endif diff --git a/libavcodec/x86/hevc/sao_10bit.asm b/libavcodec/x86/hevc/sao_10bit.asm new file mode 100644 index 000000000..0320efd75 --- /dev/null +++ b/libavcodec/x86/hevc/sao_10bit.asm @@ -0,0 +1,97 @@ +;****************************************************************************** +;* SIMD optimized SAO functions for HEVC 10/12bit decoding +;* +;* Copyright (c) 2013 Pierre-Edouard LEPERE +;* Copyright (c) 2014 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 +;****************************************************************************** + +%define MAX_PB_SIZE 64 +%include "libavcodec/x86/h26x/h2656_sao_10bit.asm" + +%macro HEVC_SAO_BAND_FILTER 3 + H2656_SAO_BAND_FILTER hevc, %1, %2, %3 +%endmacro + +%macro HEVC_SAO_BAND_FILTER_FUNCS 1 + HEVC_SAO_BAND_FILTER %1, 8, 1 + HEVC_SAO_BAND_FILTER %1, 16, 2 + HEVC_SAO_BAND_FILTER %1, 32, 4 + HEVC_SAO_BAND_FILTER %1, 48, 6 + HEVC_SAO_BAND_FILTER %1, 64, 8 +%endmacro + +%macro HEVC_SAO_BAND_FILTER_FUNCS 0 + HEVC_SAO_BAND_FILTER_FUNCS 10 + HEVC_SAO_BAND_FILTER_FUNCS 12 +%endmacro + +INIT_XMM sse2 +HEVC_SAO_BAND_FILTER_FUNCS +INIT_XMM avx +HEVC_SAO_BAND_FILTER_FUNCS + +%if HAVE_AVX2_EXTERNAL + +%macro HEVC_SAO_BAND_FILTER_FUNCS_AVX2 1 + INIT_XMM avx2 + HEVC_SAO_BAND_FILTER %1, 8, 1 + INIT_YMM avx2 + HEVC_SAO_BAND_FILTER %1, 16, 1 + HEVC_SAO_BAND_FILTER %1, 32, 2 + HEVC_SAO_BAND_FILTER %1, 48, 3 + HEVC_SAO_BAND_FILTER %1, 64, 4 +%endmacro + + HEVC_SAO_BAND_FILTER_FUNCS_AVX2 10 + HEVC_SAO_BAND_FILTER_FUNCS_AVX2 12 + +%endif + +%macro HEVC_SAO_EDGE_FILTER 3 + H2656_SAO_EDGE_FILTER hevc, %1, %2, %3 +%endmacro + +%macro HEVC_SAO_EDGE_FILTER_FUNCS 1 + HEVC_SAO_EDGE_FILTER %1, 8, 1 + HEVC_SAO_EDGE_FILTER %1, 16, 2 + HEVC_SAO_EDGE_FILTER %1, 32, 4 + HEVC_SAO_EDGE_FILTER %1, 48, 6 + HEVC_SAO_EDGE_FILTER %1, 64, 8 +%endmacro + +INIT_XMM sse2 +HEVC_SAO_EDGE_FILTER_FUNCS 10 +HEVC_SAO_EDGE_FILTER_FUNCS 12 + +%if HAVE_AVX2_EXTERNAL + +%macro HEVC_SAO_EDGE_FILTER_FUNCS_AVX2 1 + INIT_XMM avx2 + HEVC_SAO_EDGE_FILTER %1, 8, 1 + INIT_YMM avx2 + HEVC_SAO_EDGE_FILTER %1, 16, 1 + HEVC_SAO_EDGE_FILTER %1, 32, 2 + HEVC_SAO_EDGE_FILTER %1, 48, 3 + HEVC_SAO_EDGE_FILTER %1, 64, 4 +%endmacro + +HEVC_SAO_EDGE_FILTER_FUNCS_AVX2 10 +HEVC_SAO_EDGE_FILTER_FUNCS_AVX2 12 + +%endif diff --git a/libavcodec/x86/hevcdsp.h b/libavcodec/x86/hevcdsp.h deleted file mode 100644 index 037519fad..000000000 --- a/libavcodec/x86/hevcdsp.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * 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_X86_HEVCDSP_H -#define AVCODEC_X86_HEVCDSP_H - -#include -#include - - -#define PEL_LINK(dst, idx1, idx2, idx3, name, D, opt) \ -dst[idx1][idx2][idx3] = ff_hevc_put_hevc_ ## name ## _ ## D ## _##opt; \ -dst ## _bi[idx1][idx2][idx3] = ff_hevc_put_hevc_bi_ ## name ## _ ## D ## _##opt; \ -dst ## _uni[idx1][idx2][idx3] = ff_hevc_put_hevc_uni_ ## name ## _ ## D ## _##opt; \ -dst ## _uni_w[idx1][idx2][idx3] = ff_hevc_put_hevc_uni_w_ ## name ## _ ## D ## _##opt; \ -dst ## _bi_w[idx1][idx2][idx3] = ff_hevc_put_hevc_bi_w_ ## name ## _ ## D ## _##opt - - -#define PEL_PROTOTYPE(name, D, opt) \ -void ff_hevc_put_hevc_ ## name ## _ ## D ## _##opt(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); \ -void ff_hevc_put_hevc_bi_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); \ -void ff_hevc_put_hevc_uni_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); \ -void ff_hevc_put_hevc_uni_w_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width); \ -void ff_hevc_put_hevc_bi_w_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, int denom, int wx0, int wx1, int ox0, int ox1, intptr_t mx, intptr_t my, int width) - - -/////////////////////////////////////////////////////////////////////////////// -// MC functions -/////////////////////////////////////////////////////////////////////////////// - -#define EPEL_PROTOTYPES(fname, bitd, opt) \ - PEL_PROTOTYPE(fname##4, bitd, opt); \ - PEL_PROTOTYPE(fname##6, bitd, opt); \ - PEL_PROTOTYPE(fname##8, bitd, opt); \ - PEL_PROTOTYPE(fname##12, bitd, opt); \ - PEL_PROTOTYPE(fname##16, bitd, opt); \ - PEL_PROTOTYPE(fname##24, bitd, opt); \ - PEL_PROTOTYPE(fname##32, bitd, opt); \ - PEL_PROTOTYPE(fname##48, bitd, opt); \ - PEL_PROTOTYPE(fname##64, bitd, opt) - -#define QPEL_PROTOTYPES(fname, bitd, opt) \ - PEL_PROTOTYPE(fname##4, bitd, opt); \ - PEL_PROTOTYPE(fname##8, bitd, opt); \ - PEL_PROTOTYPE(fname##12, bitd, opt); \ - PEL_PROTOTYPE(fname##16, bitd, opt); \ - PEL_PROTOTYPE(fname##24, bitd, opt); \ - PEL_PROTOTYPE(fname##32, bitd, opt); \ - PEL_PROTOTYPE(fname##48, bitd, opt); \ - PEL_PROTOTYPE(fname##64, bitd, opt) - -#define WEIGHTING_PROTOTYPE(width, bitd, opt) \ -void ff_hevc_put_hevc_uni_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const int16_t *_src, int height, int denom, int _wx, int _ox); \ -void ff_hevc_put_hevc_bi_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const int16_t *_src, const int16_t *_src2, int height, int denom, int _wx0, int _wx1, int _ox0, int _ox1) - -#define WEIGHTING_PROTOTYPES(bitd, opt) \ - WEIGHTING_PROTOTYPE(2, bitd, opt); \ - WEIGHTING_PROTOTYPE(4, bitd, opt); \ - WEIGHTING_PROTOTYPE(6, bitd, opt); \ - WEIGHTING_PROTOTYPE(8, bitd, opt); \ - WEIGHTING_PROTOTYPE(12, bitd, opt); \ - WEIGHTING_PROTOTYPE(16, bitd, opt); \ - WEIGHTING_PROTOTYPE(24, bitd, opt); \ - WEIGHTING_PROTOTYPE(32, bitd, opt); \ - WEIGHTING_PROTOTYPE(48, bitd, opt); \ - WEIGHTING_PROTOTYPE(64, bitd, opt) - - -/////////////////////////////////////////////////////////////////////////////// -// QPEL_PIXELS EPEL_PIXELS -/////////////////////////////////////////////////////////////////////////////// -EPEL_PROTOTYPES(pel_pixels , 8, sse4); -EPEL_PROTOTYPES(pel_pixels , 10, sse4); -EPEL_PROTOTYPES(pel_pixels , 12, sse4); - -void ff_hevc_put_hevc_pel_pixels16_8_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels24_8_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels32_8_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels48_8_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels64_8_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); - -void ff_hevc_put_hevc_pel_pixels16_10_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels24_10_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels32_10_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels48_10_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels64_10_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); - - - -void ff_hevc_put_hevc_uni_pel_pixels32_8_avx2(uint8_t *dst, ptrdiff_t dststride,const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_uni_pel_pixels48_8_avx2(uint8_t *dst, ptrdiff_t dststride,const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_uni_pel_pixels64_8_avx2(uint8_t *dst, ptrdiff_t dststride,const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_uni_pel_pixels96_8_avx2(uint8_t *dst, ptrdiff_t dststride,const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); //used for 10bit -void ff_hevc_put_hevc_uni_pel_pixels128_8_avx2(uint8_t *dst, ptrdiff_t dststride,const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);//used for 10bit - - -void ff_hevc_put_hevc_bi_pel_pixels16_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels24_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels32_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels48_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels64_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); - -void ff_hevc_put_hevc_bi_pel_pixels16_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels24_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels32_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels48_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels64_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); - -/////////////////////////////////////////////////////////////////////////////// -// EPEL -/////////////////////////////////////////////////////////////////////////////// -EPEL_PROTOTYPES(epel_h , 8, sse4); -EPEL_PROTOTYPES(epel_h , 10, sse4); -EPEL_PROTOTYPES(epel_h , 12, sse4); - -EPEL_PROTOTYPES(epel_v , 8, sse4); -EPEL_PROTOTYPES(epel_v , 10, sse4); -EPEL_PROTOTYPES(epel_v , 12, sse4); - -EPEL_PROTOTYPES(epel_hv , 8, sse4); -EPEL_PROTOTYPES(epel_hv , 10, sse4); -EPEL_PROTOTYPES(epel_hv , 12, sse4); - -PEL_PROTOTYPE(epel_h16, 8, avx2); -PEL_PROTOTYPE(epel_h24, 8, avx2); -PEL_PROTOTYPE(epel_h32, 8, avx2); -PEL_PROTOTYPE(epel_h48, 8, avx2); -PEL_PROTOTYPE(epel_h64, 8, avx2); - -PEL_PROTOTYPE(epel_h16,10, avx2); -PEL_PROTOTYPE(epel_h24,10, avx2); -PEL_PROTOTYPE(epel_h32,10, avx2); -PEL_PROTOTYPE(epel_h48,10, avx2); -PEL_PROTOTYPE(epel_h64,10, avx2); - -PEL_PROTOTYPE(epel_v16, 8, avx2); -PEL_PROTOTYPE(epel_v24, 8, avx2); -PEL_PROTOTYPE(epel_v32, 8, avx2); -PEL_PROTOTYPE(epel_v48, 8, avx2); -PEL_PROTOTYPE(epel_v64, 8, avx2); - -PEL_PROTOTYPE(epel_v16,10, avx2); -PEL_PROTOTYPE(epel_v24,10, avx2); -PEL_PROTOTYPE(epel_v32,10, avx2); -PEL_PROTOTYPE(epel_v48,10, avx2); -PEL_PROTOTYPE(epel_v64,10, avx2); - -PEL_PROTOTYPE(epel_hv16, 8, avx2); -PEL_PROTOTYPE(epel_hv24, 8, avx2); -PEL_PROTOTYPE(epel_hv32, 8, avx2); -PEL_PROTOTYPE(epel_hv48, 8, avx2); -PEL_PROTOTYPE(epel_hv64, 8, avx2); - -PEL_PROTOTYPE(epel_hv16,10, avx2); -PEL_PROTOTYPE(epel_hv24,10, avx2); -PEL_PROTOTYPE(epel_hv32,10, avx2); -PEL_PROTOTYPE(epel_hv48,10, avx2); -PEL_PROTOTYPE(epel_hv64,10, avx2); - -/////////////////////////////////////////////////////////////////////////////// -// QPEL -/////////////////////////////////////////////////////////////////////////////// -QPEL_PROTOTYPES(qpel_h , 8, sse4); -QPEL_PROTOTYPES(qpel_h , 10, sse4); -QPEL_PROTOTYPES(qpel_h , 12, sse4); - -QPEL_PROTOTYPES(qpel_v, 8, sse4); -QPEL_PROTOTYPES(qpel_v, 10, sse4); -QPEL_PROTOTYPES(qpel_v, 12, sse4); - -QPEL_PROTOTYPES(qpel_hv, 8, sse4); -QPEL_PROTOTYPES(qpel_hv, 10, sse4); -QPEL_PROTOTYPES(qpel_hv, 12, sse4); - -PEL_PROTOTYPE(qpel_h16, 8, avx2); -PEL_PROTOTYPE(qpel_h24, 8, avx2); -PEL_PROTOTYPE(qpel_h32, 8, avx2); -PEL_PROTOTYPE(qpel_h48, 8, avx2); -PEL_PROTOTYPE(qpel_h64, 8, avx2); - -PEL_PROTOTYPE(qpel_h16,10, avx2); -PEL_PROTOTYPE(qpel_h24,10, avx2); -PEL_PROTOTYPE(qpel_h32,10, avx2); -PEL_PROTOTYPE(qpel_h48,10, avx2); -PEL_PROTOTYPE(qpel_h64,10, avx2); - -PEL_PROTOTYPE(qpel_v16, 8, avx2); -PEL_PROTOTYPE(qpel_v24, 8, avx2); -PEL_PROTOTYPE(qpel_v32, 8, avx2); -PEL_PROTOTYPE(qpel_v48, 8, avx2); -PEL_PROTOTYPE(qpel_v64, 8, avx2); - -PEL_PROTOTYPE(qpel_v16,10, avx2); -PEL_PROTOTYPE(qpel_v24,10, avx2); -PEL_PROTOTYPE(qpel_v32,10, avx2); -PEL_PROTOTYPE(qpel_v48,10, avx2); -PEL_PROTOTYPE(qpel_v64,10, avx2); - -PEL_PROTOTYPE(qpel_hv16, 8, avx2); -PEL_PROTOTYPE(qpel_hv24, 8, avx2); -PEL_PROTOTYPE(qpel_hv32, 8, avx2); -PEL_PROTOTYPE(qpel_hv48, 8, avx2); -PEL_PROTOTYPE(qpel_hv64, 8, avx2); - -PEL_PROTOTYPE(qpel_hv16,10, avx2); -PEL_PROTOTYPE(qpel_hv24,10, avx2); -PEL_PROTOTYPE(qpel_hv32,10, avx2); -PEL_PROTOTYPE(qpel_hv48,10, avx2); -PEL_PROTOTYPE(qpel_hv64,10, avx2); - -WEIGHTING_PROTOTYPES(8, sse4); -WEIGHTING_PROTOTYPES(10, sse4); -WEIGHTING_PROTOTYPES(12, sse4); - -void ff_hevc_put_hevc_qpel_h4_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_qpel_h8_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_qpel_h16_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_qpel_h32_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_qpel_h64_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_qpel_hv8_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); - -/////////////////////////////////////////////////////////////////////////////// -// TRANSFORM_ADD -/////////////////////////////////////////////////////////////////////////////// - -void ff_hevc_add_residual_4_8_mmxext(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_8_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_16_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_32_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); - -void ff_hevc_add_residual_8_8_avx(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_16_8_avx(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_32_8_avx(uint8_t *dst, const int16_t *res, ptrdiff_t stride); - -void ff_hevc_add_residual_32_8_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); - -void ff_hevc_add_residual_4_10_mmxext(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_8_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_16_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_32_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); - -void ff_hevc_add_residual_16_10_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_32_10_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); - -#endif // AVCODEC_X86_HEVCDSP_H diff --git a/libavcodec/x86/hpeldsp.asm b/libavcodec/x86/hpeldsp.asm index 3bc278618..cbdf0e460 100644 --- a/libavcodec/x86/hpeldsp.asm +++ b/libavcodec/x86/hpeldsp.asm @@ -29,9 +29,9 @@ SECTION_RODATA cextern pb_1 +cextern pw_1 cextern pw_2 pb_interleave16: db 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 -pb_interleave8: db 0, 4, 1, 5, 2, 6, 3, 7 cextern pw_8192 @@ -54,8 +54,8 @@ cglobal put_pixels8_x2, 4,5 pavgb m0, m2 pavgb m1, m3 %else - PAVGB m0, [r1] - PAVGB m1, [r1+r2] + pavgb m0, [r1] + pavgb m1, [r1+r2] %endif mova [r0], m0 mova [r0+r2], m1 @@ -69,8 +69,8 @@ cglobal put_pixels8_x2, 4,5 pavgb m0, m2 pavgb m1, m3 %else - PAVGB m0, [r1] - PAVGB m1, [r1+r2] + pavgb m0, [r1] + pavgb m1, [r1+r2] %endif add r1, r4 mova [r0], m0 @@ -84,47 +84,7 @@ cglobal put_pixels8_x2, 4,5 INIT_MMX mmxext PUT_PIXELS8_X2 - ; void ff_put_pixels16_x2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -%macro PUT_PIXELS_16 0 -cglobal put_pixels16_x2, 4,5 - lea r4, [r2*2] -.loop: - mova m0, [r1] - mova m1, [r1+r2] - mova m2, [r1+8] - mova m3, [r1+r2+8] - PAVGB m0, [r1+1] - PAVGB m1, [r1+r2+1] - PAVGB m2, [r1+9] - PAVGB m3, [r1+r2+9] - mova [r0], m0 - mova [r0+r2], m1 - mova [r0+8], m2 - mova [r0+r2+8], m3 - add r1, r4 - add r0, r4 - mova m0, [r1] - mova m1, [r1+r2] - mova m2, [r1+8] - mova m3, [r1+r2+8] - PAVGB m0, [r1+1] - PAVGB m1, [r1+r2+1] - PAVGB m2, [r1+9] - PAVGB m3, [r1+r2+9] - add r1, r4 - mova [r0], m0 - mova [r0+r2], m1 - mova [r0+8], m2 - mova [r0+r2+8], m3 - add r0, r4 - sub r3d, 4 - jne .loop - RET -%endmacro - -INIT_MMX mmxext -PUT_PIXELS_16 ; The 8_X2 macro can easily be used here INIT_XMM sse2 PUT_PIXELS8_X2 @@ -143,8 +103,8 @@ cglobal put_no_rnd_pixels8_x2, 4,5 add r1, r4 psubusb m0, m6 psubusb m2, m6 - PAVGB m0, m1 - PAVGB m2, m3 + pavgb m0, m1 + pavgb m2, m3 mova [r0], m0 mova [r0+r2], m2 mova m0, [r1] @@ -155,8 +115,8 @@ cglobal put_no_rnd_pixels8_x2, 4,5 add r1, r4 psubusb m0, m6 psubusb m2, m6 - PAVGB m0, m1 - PAVGB m2, m3 + pavgb m0, m1 + pavgb m2, m3 mova [r0], m0 mova [r0+r2], m2 add r0, r4 @@ -165,38 +125,50 @@ cglobal put_no_rnd_pixels8_x2, 4,5 RET +%macro NO_RND_PIXELS_X2 1 +%if cpuflag(sse2) +cglobal %1_no_rnd_pixels16_x2, 4,5,5 +%else ; void ff_put_no_rnd_pixels8_x2_exact(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -INIT_MMX mmxext -cglobal put_no_rnd_pixels8_x2_exact, 4,5 +cglobal %1_no_rnd_pixels8_x2_exact, 4,5 +%endif lea r4, [r2*3] - pcmpeqb m6, m6 + pcmpeqb m4, m4 .loop: - mova m0, [r1] - mova m2, [r1+r2] - mova m1, [r1+1] - mova m3, [r1+r2+1] - pxor m0, m6 - pxor m2, m6 - pxor m1, m6 - pxor m3, m6 - PAVGB m0, m1 - PAVGB m2, m3 - pxor m0, m6 - pxor m2, m6 + movu m0, [r1] + movu m2, [r1+r2] + movu m1, [r1+1] + movu m3, [r1+r2+1] + pxor m0, m4 + pxor m2, m4 + pxor m1, m4 + pxor m3, m4 + pavgb m0, m1 + pavgb m2, m3 + pxor m0, m4 + pxor m2, m4 +%ifidn %1, avg + pavgb m0, [r0] + pavgb m2, [r0+r2] +%endif mova [r0], m0 mova [r0+r2], m2 - mova m0, [r1+r2*2] - mova m1, [r1+r2*2+1] - mova m2, [r1+r4] - mova m3, [r1+r4+1] - pxor m0, m6 - pxor m1, m6 - pxor m2, m6 - pxor m3, m6 - PAVGB m0, m1 - PAVGB m2, m3 - pxor m0, m6 - pxor m2, m6 + movu m0, [r1+r2*2] + movu m1, [r1+r2*2+1] + movu m2, [r1+r4] + movu m3, [r1+r4+1] + pxor m0, m4 + pxor m1, m4 + pxor m2, m4 + pxor m3, m4 + pavgb m0, m1 + pavgb m2, m3 + pxor m0, m4 + pxor m2, m4 +%ifidn %1, avg + pavgb m0, [r0+r2*2] + pavgb m2, [r0+r4] +%endif mova [r0+r2*2], m0 mova [r0+r4], m2 lea r1, [r1+r2*4] @@ -204,7 +176,13 @@ cglobal put_no_rnd_pixels8_x2_exact, 4,5 sub r3d, 4 jg .loop RET +%endmacro +INIT_MMX mmxext +NO_RND_PIXELS_X2 put +INIT_XMM sse2 +NO_RND_PIXELS_X2 avg +NO_RND_PIXELS_X2 put ; void ff_put_pixels8_y2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) %macro PUT_PIXELS8_Y2 0 @@ -220,16 +198,16 @@ cglobal put_pixels8_y2, 4,5 movu m1, [r1+r2] movu m2, [r1+r4] add r1, r4 - PAVGB m0, m1 - PAVGB m1, m2 + pavgb m0, m1 + pavgb m1, m2 mova [r0+r2], m0 mova [r0+r4], m1 movu m1, [r1+r2] movu m0, [r1+r4] add r0, r4 add r1, r4 - PAVGB m2, m1 - PAVGB m1, m0 + pavgb m2, m1 + pavgb m1, m0 mova [r0+r2], m2 mova [r0+r4], m1 add r0, r4 @@ -257,8 +235,8 @@ cglobal put_no_rnd_pixels8_y2, 4,5 mova m2, [r1+r4] add r1, r4 psubusb m1, m6 - PAVGB m0, m1 - PAVGB m1, m2 + pavgb m0, m1 + pavgb m1, m2 mova [r0+r2], m0 mova [r0+r4], m1 mova m1, [r1+r2] @@ -266,8 +244,8 @@ cglobal put_no_rnd_pixels8_y2, 4,5 add r0, r4 add r1, r4 psubusb m1, m6 - PAVGB m2, m1 - PAVGB m1, m0 + pavgb m2, m1 + pavgb m1, m0 mova [r0+r2], m2 mova [r0+r4], m1 add r0, r4 @@ -276,33 +254,45 @@ cglobal put_no_rnd_pixels8_y2, 4,5 RET +%macro NO_RND_PIXELS_Y2 1 +%if cpuflag(sse2) +cglobal %1_no_rnd_pixels16_y2, 4,5,4 +%else ; void ff_put_no_rnd_pixels8_y2_exact(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -INIT_MMX mmxext -cglobal put_no_rnd_pixels8_y2_exact, 4,5 +cglobal %1_no_rnd_pixels8_y2_exact, 4,5 +%endif lea r4, [r2*3] - mova m0, [r1] - pcmpeqb m6, m6 + movu m0, [r1] + pcmpeqb m3, m3 add r1, r2 - pxor m0, m6 + pxor m0, m3 .loop: - mova m1, [r1] - mova m2, [r1+r2] - pxor m1, m6 - pxor m2, m6 - PAVGB m0, m1 - PAVGB m1, m2 - pxor m0, m6 - pxor m1, m6 + movu m1, [r1] + movu m2, [r1+r2] + pxor m1, m3 + pxor m2, m3 + pavgb m0, m1 + pavgb m1, m2 + pxor m0, m3 + pxor m1, m3 +%ifidn %1, avg + pavgb m0, [r0] + pavgb m1, [r0+r2] +%endif mova [r0], m0 mova [r0+r2], m1 - mova m1, [r1+r2*2] - mova m0, [r1+r4] - pxor m1, m6 - pxor m0, m6 - PAVGB m2, m1 - PAVGB m1, m0 - pxor m2, m6 - pxor m1, m6 + movu m1, [r1+r2*2] + movu m0, [r1+r4] + pxor m1, m3 + pxor m0, m3 + pavgb m2, m1 + pavgb m1, m0 + pxor m2, m3 + pxor m1, m3 +%ifidn %1, avg + pavgb m2,[r0+r2*2] + pavgb m1,[r0+r4] +%endif mova [r0+r2*2], m2 mova [r0+r4], m1 lea r1, [r1+r2*4] @@ -310,7 +300,13 @@ cglobal put_no_rnd_pixels8_y2_exact, 4,5 sub r3d, 4 jg .loop RET +%endmacro +INIT_MMX mmxext +NO_RND_PIXELS_Y2 put +INIT_XMM sse2 +NO_RND_PIXELS_Y2 avg +NO_RND_PIXELS_Y2 put ; void ff_avg_pixels8_x2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) %macro AVG_PIXELS8_X2 0 @@ -329,11 +325,11 @@ cglobal avg_pixels8_x2, 4,5 pavgb m0, m1 pavgb m2, m3 %else - PAVGB m0, [r1+1], m3, m5 - PAVGB m2, [r1+r2+1], m4, m5 + pavgb m0, [r1+1] + pavgb m2, [r1+r2+1] %endif - PAVGB m0, [r0], m3, m5 - PAVGB m2, [r0+r2], m4, m5 + pavgb m0, [r0] + pavgb m2, [r0+r2] add r1, r4 mova [r0], m0 mova [r0+r2], m2 @@ -345,13 +341,13 @@ cglobal avg_pixels8_x2, 4,5 pavgb m0, m1 pavgb m2, m3 %else - PAVGB m0, [r1+1], m3, m5 - PAVGB m2, [r1+r2+1], m4, m5 + pavgb m0, [r1+1] + pavgb m2, [r1+r2+1] %endif add r0, r4 add r1, r4 - PAVGB m0, [r0], m3, m5 - PAVGB m2, [r0+r2], m4, m5 + pavgb m0, [r0] + pavgb m2, [r0+r2] mova [r0], m0 mova [r0+r2], m2 add r0, r4 @@ -381,20 +377,20 @@ cglobal avg_pixels8_y2, 4,5 movu m1, [r1+r2] movu m2, [r1+r4] add r1, r4 - PAVGB m0, m1 - PAVGB m1, m2 - PAVGB m0, [r0+r2] - PAVGB m1, [r0+r4] + pavgb m0, m1 + pavgb m1, m2 + pavgb m0, [r0+r2] + pavgb m1, [r0+r4] mova [r0+r2], m0 mova [r0+r4], m1 movu m1, [r1+r2] movu m0, [r1+r4] - PAVGB m2, m1 - PAVGB m1, m0 + pavgb m2, m1 + pavgb m1, m0 add r0, r4 add r1, r4 - PAVGB m2, [r0+r2] - PAVGB m1, [r0+r4] + pavgb m2, [r0+r2] + pavgb m1, [r0+r4] mova [r0+r2], m2 mova [r0+r4], m1 add r0, r4 @@ -410,55 +406,77 @@ INIT_XMM sse2 AVG_PIXELS8_Y2 -; void ff_avg_pixels8_xy2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -; Note this is not correctly rounded, and is therefore used for -; not-bitexact output -INIT_MMX mmxext -cglobal avg_approx_pixels8_xy2, 4,5 - mova m6, [pb_1] - lea r4, [r2*2] - mova m0, [r1] - PAVGB m0, [r1+1] +; void ff_put_no_rnd_pixels8_xy2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) +%macro SET_PIXELS8_XY2 2-3 +cglobal %1%3_pixels8_xy2, 4,5,5 + mova m4, [pb_1] + mova m3, [%2] + movh m0, [r1] + movh m2, [r1+1] + punpcklbw m2, m0 + pmaddubsw m2, m4 + xor r4, r4 + add r1, r2 .loop: - mova m2, [r1+r4] - mova m1, [r1+r2] - psubusb m2, m6 - PAVGB m1, [r1+r2+1] - PAVGB m2, [r1+r4+1] - add r1, r4 - PAVGB m0, m1 - PAVGB m1, m2 - PAVGB m0, [r0] - PAVGB m1, [r0+r2] - mova [r0], m0 - mova [r0+r2], m1 - mova m1, [r1+r2] - mova m0, [r1+r4] - PAVGB m1, [r1+r2+1] - PAVGB m0, [r1+r4+1] - add r0, r4 - add r1, r4 - PAVGB m2, m1 - PAVGB m1, m0 - PAVGB m2, [r0] - PAVGB m1, [r0+r2] - mova [r0], m2 - mova [r0+r2], m1 - add r0, r4 - sub r3d, 4 - jne .loop + movh m0, [r1+r4] + movh m1, [r1+r4+1] + punpcklbw m0, m1 + pmaddubsw m0, m4 +%ifidn %3, _no_rnd + paddw m2, m3 + paddw m2, m0 + psrlw m2, 2 +%else + paddw m2, m0 + pmulhrsw m2, m3 +%endif +%ifidn %1, avg + movh m1, [r0+r4] + packuswb m2, m2 + pavgb m2, m1 +%else + packuswb m2, m2 +%endif + movh [r0+r4], m2 + add r4, r2 + + movh m1, [r1+r4] + movh m2, [r1+r4+1] + punpcklbw m2, m1 + pmaddubsw m2, m4 +%ifidn %3, _no_rnd + paddw m0, m3 + paddw m0, m2 + psrlw m0, 2 +%else + paddw m0, m2 + pmulhrsw m0, m3 +%endif +%ifidn %1, avg + movh m1, [r0+r4] + packuswb m0, m0 + pavgb m0, m1 +%else + packuswb m0, m0 +%endif + movh [r0+r4], m0 + add r4, r2 + sub r3d, 2 + jnz .loop RET +%endmacro + +INIT_XMM ssse3 +SET_PIXELS8_XY2 put, pw_1, _no_rnd +SET_PIXELS8_XY2 avg, pw_8192 +SET_PIXELS8_XY2 put, pw_8192 ; void ff_avg_pixels16_xy2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -%macro SET_PIXELS_XY2 1 -%if cpuflag(sse2) -cglobal %1_pixels16_xy2, 4,5,8 -%else -cglobal %1_pixels8_xy2, 4,5 -%endif +%macro SET_PIXELS_XY2 2-3 +cglobal %1%3_pixels16_xy2, 4,5,8 pxor m7, m7 - mova m6, [pw_2] + mova m6, [%2] movu m0, [r1] movu m4, [r1+1] mova m1, m0 @@ -467,8 +485,8 @@ cglobal %1_pixels8_xy2, 4,5 punpcklbw m4, m7 punpckhbw m1, m7 punpckhbw m5, m7 - paddusw m4, m0 - paddusw m5, m1 + paddw m4, m0 + paddw m5, m1 xor r4, r4 add r1, r2 .loop: @@ -480,18 +498,18 @@ cglobal %1_pixels8_xy2, 4,5 punpcklbw m2, m7 punpckhbw m1, m7 punpckhbw m3, m7 - paddusw m0, m2 - paddusw m1, m3 - paddusw m4, m6 - paddusw m5, m6 - paddusw m4, m0 - paddusw m5, m1 + paddw m0, m2 + paddw m1, m3 + paddw m4, m6 + paddw m5, m6 + paddw m4, m0 + paddw m5, m1 psrlw m4, 2 psrlw m5, 2 %ifidn %1, avg mova m3, [r0+r4] packuswb m4, m5 - PAVGB m4, m3 + pavgb m4, m3 %else packuswb m4, m5 %endif @@ -506,18 +524,18 @@ cglobal %1_pixels8_xy2, 4,5 punpcklbw m4, m7 punpckhbw m3, m7 punpckhbw m5, m7 - paddusw m4, m2 - paddusw m5, m3 - paddusw m0, m6 - paddusw m1, m6 - paddusw m0, m4 - paddusw m1, m5 + paddw m4, m2 + paddw m5, m3 + paddw m0, m6 + paddw m1, m6 + paddw m0, m4 + paddw m1, m5 psrlw m0, 2 psrlw m1, 2 %ifidn %1, avg mova m3, [r0+r4] packuswb m0, m1 - PAVGB m0, m3 + pavgb m0, m3 %else packuswb m0, m1 %endif @@ -528,20 +546,15 @@ cglobal %1_pixels8_xy2, 4,5 RET %endmacro -INIT_MMX mmxext -SET_PIXELS_XY2 avg INIT_XMM sse2 -SET_PIXELS_XY2 put -SET_PIXELS_XY2 avg +SET_PIXELS_XY2 put, pw_2 +SET_PIXELS_XY2 avg, pw_2 +SET_PIXELS_XY2 put, pw_1, _no_rnd +SET_PIXELS_XY2 avg, pw_1, _no_rnd %macro SSSE3_PIXELS_XY2 1-2 -%if %0 == 2 ; sse2 cglobal %1_pixels16_xy2, 4,5,%2 mova m4, [pb_interleave16] -%else -cglobal %1_pixels8_xy2, 4,5 - mova m4, [pb_interleave8] -%endif mova m5, [pb_1] movu m0, [r1] movu m1, [r1+1] @@ -554,8 +567,8 @@ cglobal %1_pixels8_xy2, 4,5 movu m3, [r1+r4+1] pmaddubsw m2, m5 pmaddubsw m3, m5 - paddusw m0, m2 - paddusw m1, m3 + paddw m0, m2 + paddw m1, m3 pmulhrsw m0, [pw_8192] pmulhrsw m1, [pw_8192] %ifidn %1, avg @@ -574,8 +587,8 @@ cglobal %1_pixels8_xy2, 4,5 movu m1, [r1+r4+1] pmaddubsw m0, m5 pmaddubsw m1, m5 - paddusw m2, m0 - paddusw m3, m1 + paddw m2, m0 + paddw m3, m1 pmulhrsw m2, [pw_8192] pmulhrsw m3, [pw_8192] %ifidn %1, avg @@ -594,9 +607,6 @@ cglobal %1_pixels8_xy2, 4,5 RET %endmacro -INIT_MMX ssse3 -SSSE3_PIXELS_XY2 put -SSSE3_PIXELS_XY2 avg INIT_XMM ssse3 SSSE3_PIXELS_XY2 put, 6 SSSE3_PIXELS_XY2 avg, 7 diff --git a/libavcodec/x86/hpeldsp.h b/libavcodec/x86/hpeldsp.h index ac7e625fd..8208e43ac 100644 --- a/libavcodec/x86/hpeldsp.h +++ b/libavcodec/x86/hpeldsp.h @@ -25,22 +25,14 @@ void ff_avg_pixels8_x2_mmx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); -void ff_avg_pixels8_xy2_mmx(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h); -void ff_avg_pixels8_xy2_mmxext(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h); void ff_avg_pixels8_xy2_ssse3(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); -void ff_avg_pixels16_xy2_mmx(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h); void ff_avg_pixels16_xy2_sse2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); void ff_avg_pixels16_xy2_ssse3(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); -void ff_put_pixels8_xy2_mmx(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h); void ff_put_pixels8_xy2_ssse3(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); void ff_put_pixels16_xy2_sse2(uint8_t *block, const uint8_t *pixels, diff --git a/libavcodec/x86/hpeldsp_init.c b/libavcodec/x86/hpeldsp_init.c index 4a0513d06..3500ad187 100644 --- a/libavcodec/x86/hpeldsp_init.c +++ b/libavcodec/x86/hpeldsp_init.c @@ -22,19 +22,19 @@ * MMX optimization by Nick Kurshev */ +#include +#include + #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/x86/cpu.h" #include "libavcodec/avcodec.h" #include "libavcodec/hpeldsp.h" -#include "libavcodec/pixels.h" #include "fpel.h" #include "hpeldsp.h" void ff_put_pixels8_x2_mmxext(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); -void ff_put_pixels16_x2_mmxext(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h); void ff_put_pixels16_x2_sse2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); void ff_avg_pixels16_x2_sse2(uint8_t *block, const uint8_t *pixels, @@ -48,6 +48,10 @@ void ff_put_no_rnd_pixels8_x2_mmxext(uint8_t *block, const uint8_t *pixels, void ff_put_no_rnd_pixels8_x2_exact_mmxext(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels16_x2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_no_rnd_pixels16_x2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); void ff_put_pixels8_y2_mmxext(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); void ff_put_no_rnd_pixels8_y2_mmxext(uint8_t *block, const uint8_t *pixels, @@ -55,164 +59,66 @@ void ff_put_no_rnd_pixels8_y2_mmxext(uint8_t *block, const uint8_t *pixels, void ff_put_no_rnd_pixels8_y2_exact_mmxext(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels16_y2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_no_rnd_pixels16_y2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels8_xy2_ssse3(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels16_xy2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_no_rnd_pixels16_xy2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); void ff_avg_pixels8_x2_mmxext(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); void ff_avg_pixels8_y2_mmxext(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h); -void ff_avg_approx_pixels8_xy2_mmxext(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h); - -#define put_pixels8_mmx ff_put_pixels8_mmx -#define put_pixels16_mmx ff_put_pixels16_mmx -#define put_pixels8_xy2_mmx ff_put_pixels8_xy2_mmx -#define put_no_rnd_pixels8_mmx ff_put_pixels8_mmx -#define put_no_rnd_pixels16_mmx ff_put_pixels16_mmx - -#if HAVE_INLINE_ASM - -/***********************************/ -/* MMX no rounding */ -#define DEF(x, y) x ## _no_rnd_ ## y ## _mmx -#define SET_RND MOVQ_WONE -#define PAVGBP(a, b, c, d, e, f) PAVGBP_MMX_NO_RND(a, b, c, d, e, f) -#define PAVGB(a, b, c, e) PAVGB_MMX_NO_RND(a, b, c, e) -#define STATIC static - -#include "rnd_template.c" -#include "hpeldsp_rnd_template.c" - -#undef DEF -#undef SET_RND -#undef PAVGBP -#undef PAVGB -#undef STATIC - -#if HAVE_MMX -CALL_2X_PIXELS(avg_no_rnd_pixels16_y2_mmx, avg_no_rnd_pixels8_y2_mmx, 8) -CALL_2X_PIXELS(put_no_rnd_pixels16_y2_mmx, put_no_rnd_pixels8_y2_mmx, 8) - -CALL_2X_PIXELS(avg_no_rnd_pixels16_xy2_mmx, avg_no_rnd_pixels8_xy2_mmx, 8) -CALL_2X_PIXELS(put_no_rnd_pixels16_xy2_mmx, put_no_rnd_pixels8_xy2_mmx, 8) -#endif - -/***********************************/ -/* MMX rounding */ - -#define SET_RND MOVQ_WTWO -#define DEF(x, y) ff_ ## x ## _ ## y ## _mmx -#define STATIC -#define NO_AVG - -#include "rnd_template.c" - -#undef NO_AVG -#undef DEF -#undef SET_RND - -#if HAVE_MMX -CALL_2X_PIXELS(put_pixels16_xy2_mmx, ff_put_pixels8_xy2_mmx, 8) -#endif - -#endif /* HAVE_INLINE_ASM */ - - -#if HAVE_X86ASM - -#define HPELDSP_AVG_PIXELS16(CPUEXT) \ - CALL_2X_PIXELS(put_no_rnd_pixels16_x2 ## CPUEXT, ff_put_no_rnd_pixels8_x2 ## CPUEXT, 8) \ - CALL_2X_PIXELS(put_pixels16_y2 ## CPUEXT, ff_put_pixels8_y2 ## CPUEXT, 8) \ - CALL_2X_PIXELS(put_no_rnd_pixels16_y2 ## CPUEXT, ff_put_no_rnd_pixels8_y2 ## CPUEXT, 8) \ - CALL_2X_PIXELS(avg_pixels16 ## CPUEXT, ff_avg_pixels8 ## CPUEXT, 8) \ - CALL_2X_PIXELS(avg_pixels16_x2 ## CPUEXT, ff_avg_pixels8_x2 ## CPUEXT, 8) \ - CALL_2X_PIXELS(avg_pixels16_y2 ## CPUEXT, ff_avg_pixels8_y2 ## CPUEXT, 8) \ - CALL_2X_PIXELS(avg_pixels16_xy2 ## CPUEXT, ff_avg_pixels8_xy2 ## CPUEXT, 8) \ - CALL_2X_PIXELS(avg_approx_pixels16_xy2## CPUEXT, ff_avg_approx_pixels8_xy2## CPUEXT, 8) - -HPELDSP_AVG_PIXELS16(_mmxext) - -#endif /* HAVE_X86ASM */ - -#define SET_HPEL_FUNCS_EXT(PFX, IDX, SIZE, CPU) \ - if (HAVE_MMX_EXTERNAL) \ - c->PFX ## _pixels_tab IDX [0] = PFX ## _pixels ## SIZE ## _ ## CPU - -#define SET_HPEL_FUNCS03(PFX, IDX, SIZE, CPU) \ - do { \ - SET_HPEL_FUNCS_EXT(PFX, IDX, SIZE, CPU); \ - c->PFX ## _pixels_tab IDX [3] = PFX ## _pixels ## SIZE ## _xy2_ ## CPU; \ - } while (0) -#define SET_HPEL_FUNCS12(PFX, IDX, SIZE, CPU) \ - do { \ - c->PFX ## _pixels_tab IDX [1] = PFX ## _pixels ## SIZE ## _x2_ ## CPU; \ - c->PFX ## _pixels_tab IDX [2] = PFX ## _pixels ## SIZE ## _y2_ ## CPU; \ - } while (0) -#define SET_HPEL_FUNCS(PFX, IDX, SIZE, CPU) \ - do { \ - SET_HPEL_FUNCS03(PFX, IDX, SIZE, CPU); \ - SET_HPEL_FUNCS12(PFX, IDX, SIZE, CPU); \ - } while (0) - -static void hpeldsp_init_mmx(HpelDSPContext *c, int flags) -{ -#if HAVE_MMX_INLINE - SET_HPEL_FUNCS03(put, [0], 16, mmx); - SET_HPEL_FUNCS(put_no_rnd, [0], 16, mmx); - SET_HPEL_FUNCS12(avg_no_rnd, , 16, mmx); - c->avg_no_rnd_pixels_tab[3] = avg_no_rnd_pixels16_xy2_mmx; - SET_HPEL_FUNCS03(put, [1], 8, mmx); - SET_HPEL_FUNCS(put_no_rnd, [1], 8, mmx); -#endif -} static void hpeldsp_init_mmxext(HpelDSPContext *c, int flags) { #if HAVE_MMXEXT_EXTERNAL - c->put_pixels_tab[0][1] = ff_put_pixels16_x2_mmxext; - c->put_pixels_tab[0][2] = put_pixels16_y2_mmxext; - - c->avg_pixels_tab[0][0] = avg_pixels16_mmxext; - c->avg_pixels_tab[0][1] = avg_pixels16_x2_mmxext; - c->avg_pixels_tab[0][2] = avg_pixels16_y2_mmxext; - c->avg_pixels_tab[0][3] = avg_pixels16_xy2_mmxext; - c->put_pixels_tab[1][1] = ff_put_pixels8_x2_mmxext; c->put_pixels_tab[1][2] = ff_put_pixels8_y2_mmxext; c->avg_pixels_tab[1][0] = ff_avg_pixels8_mmxext; c->avg_pixels_tab[1][1] = ff_avg_pixels8_x2_mmxext; c->avg_pixels_tab[1][2] = ff_avg_pixels8_y2_mmxext; - c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_mmxext; c->put_no_rnd_pixels_tab[1][1] = ff_put_no_rnd_pixels8_x2_exact_mmxext; c->put_no_rnd_pixels_tab[1][2] = ff_put_no_rnd_pixels8_y2_exact_mmxext; - c->avg_no_rnd_pixels_tab[0] = ff_avg_pixels16_mmxext; - if (!(flags & AV_CODEC_FLAG_BITEXACT)) { - c->put_no_rnd_pixels_tab[0][1] = put_no_rnd_pixels16_x2_mmxext; - c->put_no_rnd_pixels_tab[0][2] = put_no_rnd_pixels16_y2_mmxext; c->put_no_rnd_pixels_tab[1][1] = ff_put_no_rnd_pixels8_x2_mmxext; c->put_no_rnd_pixels_tab[1][2] = ff_put_no_rnd_pixels8_y2_mmxext; - - c->avg_pixels_tab[0][3] = avg_approx_pixels16_xy2_mmxext; - c->avg_pixels_tab[1][3] = ff_avg_approx_pixels8_xy2_mmxext; } #endif /* HAVE_MMXEXT_EXTERNAL */ } -static void hpeldsp_init_sse2_fast(HpelDSPContext *c, int flags) +static void hpeldsp_init_sse2(HpelDSPContext *c, int flags) { #if HAVE_SSE2_EXTERNAL c->put_pixels_tab[0][0] = ff_put_pixels16_sse2; - c->put_no_rnd_pixels_tab[0][0] = ff_put_pixels16_sse2; c->put_pixels_tab[0][1] = ff_put_pixels16_x2_sse2; c->put_pixels_tab[0][2] = ff_put_pixels16_y2_sse2; c->put_pixels_tab[0][3] = ff_put_pixels16_xy2_sse2; + + c->put_no_rnd_pixels_tab[0][0] = ff_put_pixels16_sse2; + c->put_no_rnd_pixels_tab[0][1] = ff_put_no_rnd_pixels16_x2_sse2; + c->put_no_rnd_pixels_tab[0][2] = ff_put_no_rnd_pixels16_y2_sse2; + c->put_no_rnd_pixels_tab[0][3] = ff_put_no_rnd_pixels16_xy2_sse2; + + c->put_no_rnd_pixels_tab[1][0] = + c->put_pixels_tab[1][0] = ff_put_pixels8_sse2; + c->avg_pixels_tab[0][0] = ff_avg_pixels16_sse2; c->avg_pixels_tab[0][1] = ff_avg_pixels16_x2_sse2; c->avg_pixels_tab[0][2] = ff_avg_pixels16_y2_sse2; c->avg_pixels_tab[0][3] = ff_avg_pixels16_xy2_sse2; + c->avg_no_rnd_pixels_tab[0] = ff_avg_pixels16_sse2; + c->avg_no_rnd_pixels_tab[1] = ff_avg_no_rnd_pixels16_x2_sse2; + c->avg_no_rnd_pixels_tab[2] = ff_avg_no_rnd_pixels16_y2_sse2; + c->avg_no_rnd_pixels_tab[3] = ff_avg_no_rnd_pixels16_xy2_sse2; #endif /* HAVE_SSE2_EXTERNAL */ } @@ -223,6 +129,8 @@ static void hpeldsp_init_ssse3(HpelDSPContext *c, int flags) c->avg_pixels_tab[0][3] = ff_avg_pixels16_xy2_ssse3; c->put_pixels_tab[1][3] = ff_put_pixels8_xy2_ssse3; c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_ssse3; + + c->put_no_rnd_pixels_tab[1][3] = ff_put_no_rnd_pixels8_xy2_ssse3; #endif } @@ -230,14 +138,11 @@ av_cold void ff_hpeldsp_init_x86(HpelDSPContext *c, int flags) { int cpu_flags = av_get_cpu_flags(); - if (INLINE_MMX(cpu_flags)) - hpeldsp_init_mmx(c, flags); - if (EXTERNAL_MMXEXT(cpu_flags)) hpeldsp_init_mmxext(c, flags); - if (EXTERNAL_SSE2_FAST(cpu_flags)) - hpeldsp_init_sse2_fast(c, flags); + if (EXTERNAL_SSE2(cpu_flags)) + hpeldsp_init_sse2(c, flags); if (EXTERNAL_SSSE3(cpu_flags)) hpeldsp_init_ssse3(c, flags); diff --git a/libavcodec/x86/hpeldsp_rnd_template.c b/libavcodec/x86/hpeldsp_rnd_template.c deleted file mode 100644 index 2bff2d276..000000000 --- a/libavcodec/x86/hpeldsp_rnd_template.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * SIMD-optimized halfpel functions are compiled twice for rnd/no_rnd - * Copyright (c) 2000, 2001 Fabrice Bellard - * Copyright (c) 2003-2004 Michael Niedermayer - * - * MMX optimization by Nick Kurshev - * mostly rewritten by Michael Niedermayer - * and improved by Zdenek Kabelac - * - * 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 - -// put_pixels -av_unused static void DEF(put, pixels8_x2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -{ - MOVQ_BFE(mm6); - __asm__ volatile( - "lea (%3, %3), %%"FF_REG_a" \n\t" - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm1 \n\t" - "movq (%1, %3), %%mm2 \n\t" - "movq 1(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm1 \n\t" - "movq (%1, %3), %%mm2 \n\t" - "movq 1(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "subl $4, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels), "+D"(block) - :"r"((x86_reg)line_size) - :FF_REG_a, "memory"); -} - -av_unused static void DEF(put, pixels16_x2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -{ - MOVQ_BFE(mm6); - __asm__ volatile( - "lea (%3, %3), %%"FF_REG_a" \n\t" - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm1 \n\t" - "movq (%1, %3), %%mm2 \n\t" - "movq 1(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "movq 8(%1), %%mm0 \n\t" - "movq 9(%1), %%mm1 \n\t" - "movq 8(%1, %3), %%mm2 \n\t" - "movq 9(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, 8(%2) \n\t" - "movq %%mm5, 8(%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm1 \n\t" - "movq (%1, %3), %%mm2 \n\t" - "movq 1(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "movq 8(%1), %%mm0 \n\t" - "movq 9(%1), %%mm1 \n\t" - "movq 8(%1, %3), %%mm2 \n\t" - "movq 9(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, 8(%2) \n\t" - "movq %%mm5, 8(%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "subl $4, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels), "+D"(block) - :"r"((x86_reg)line_size) - :FF_REG_a, "memory"); -} - -av_unused static void DEF(put, pixels8_y2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -{ - MOVQ_BFE(mm6); - __asm__ volatile( - "lea (%3, %3), %%"FF_REG_a" \n\t" - "movq (%1), %%mm0 \n\t" - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1, %3), %%mm1 \n\t" - "movq (%1, %%"FF_REG_a"),%%mm2\n\t" - PAVGBP(%%mm1, %%mm0, %%mm4, %%mm2, %%mm1, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "movq (%1, %3), %%mm1 \n\t" - "movq (%1, %%"FF_REG_a"),%%mm0\n\t" - PAVGBP(%%mm1, %%mm2, %%mm4, %%mm0, %%mm1, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "subl $4, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels), "+D"(block) - :"r"((x86_reg)line_size) - :FF_REG_a, "memory"); -} - -av_unused static void DEF(avg, pixels16_x2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -{ - MOVQ_BFE(mm6); - __asm__ volatile( - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm1 \n\t" - "movq (%2), %%mm3 \n\t" - PAVGB(%%mm0, %%mm1, %%mm2, %%mm6) - PAVGB_MMX(%%mm3, %%mm2, %%mm0, %%mm6) - "movq %%mm0, (%2) \n\t" - "movq 8(%1), %%mm0 \n\t" - "movq 9(%1), %%mm1 \n\t" - "movq 8(%2), %%mm3 \n\t" - PAVGB(%%mm0, %%mm1, %%mm2, %%mm6) - PAVGB_MMX(%%mm3, %%mm2, %%mm0, %%mm6) - "movq %%mm0, 8(%2) \n\t" - "add %3, %1 \n\t" - "add %3, %2 \n\t" - "subl $1, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels), "+D"(block) - :"r"((x86_reg)line_size) - :"memory"); -} - -av_unused static void DEF(avg, pixels8_y2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -{ - MOVQ_BFE(mm6); - __asm__ volatile( - "lea (%3, %3), %%"FF_REG_a" \n\t" - "movq (%1), %%mm0 \n\t" - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1, %3), %%mm1 \n\t" - "movq (%1, %%"FF_REG_a"), %%mm2 \n\t" - PAVGBP(%%mm1, %%mm0, %%mm4, %%mm2, %%mm1, %%mm5) - "movq (%2), %%mm3 \n\t" - PAVGB_MMX(%%mm3, %%mm4, %%mm0, %%mm6) - "movq (%2, %3), %%mm3 \n\t" - PAVGB_MMX(%%mm3, %%mm5, %%mm1, %%mm6) - "movq %%mm0, (%2) \n\t" - "movq %%mm1, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - - "movq (%1, %3), %%mm1 \n\t" - "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" - PAVGBP(%%mm1, %%mm2, %%mm4, %%mm0, %%mm1, %%mm5) - "movq (%2), %%mm3 \n\t" - PAVGB_MMX(%%mm3, %%mm4, %%mm2, %%mm6) - "movq (%2, %3), %%mm3 \n\t" - PAVGB_MMX(%%mm3, %%mm5, %%mm1, %%mm6) - "movq %%mm2, (%2) \n\t" - "movq %%mm1, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - - "subl $4, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels), "+D"(block) - :"r"((x86_reg)line_size) - :FF_REG_a, "memory"); -} diff --git a/libavcodec/x86/huffyuvencdsp.asm b/libavcodec/x86/huffyuvencdsp.asm index 8bfd0face..e8e7a6469 100644 --- a/libavcodec/x86/huffyuvencdsp.asm +++ b/libavcodec/x86/huffyuvencdsp.asm @@ -55,42 +55,70 @@ INIT_YMM avx2 DIFF_INT16 %endif -INIT_MMX mmxext -cglobal sub_hfyu_median_pred_int16, 7,7,0, dst, src1, src2, mask, w, left, left_top - add wd, wd - movd mm7, maskd - SPLATW mm7, mm7 - movq mm0, [src1q] - movq mm2, [src2q] - psllq mm0, 16 - psllq mm2, 16 - movd mm6, [left_topq] - por mm0, mm6 - movd mm6, [leftq] - por mm2, mm6 - xor maskq, maskq +%macro SUB_HFYU_MEDIAN_PRED_INT16 1 ; u,s for pmaxuw vs pmaxsw +cglobal sub_hfyu_median_pred_int16, 7,7,6, dst, src1, src2, mask, w, left, left_top + movd xm5, maskd + lea wd, [wd+wd-(mmsize-1)] + movu xm0, [src1q] + movu xm2, [src2q] + SPLATW m5, xm5 + add dstq, wq + movd xm1, [left_topq] + neg wq + movd xm3, [leftq] +%if mmsize >= 32 + movu xm4, [src1q+14] +%endif + sub src1q, wq + pslldq xm0, 2 + pslldq xm2, 2 + por xm0, xm1 +%if mmsize >= 32 + vinserti128 m0, xm4, 1 +%endif + por xm2, xm3 +%if mmsize >= 32 + vinserti128 m2, [src2q+14], 1 +%endif + sub src2q, wq + jmp .init + .loop: - movq mm1, [src1q + maskq] - movq mm3, [src2q + maskq] - movq mm4, mm2 - psubw mm2, mm0 - paddw mm2, mm1 - pand mm2, mm7 - movq mm5, mm4 - pmaxsw mm4, mm1 - pminsw mm1, mm5 - pminsw mm4, mm2 - pmaxsw mm4, mm1 - psubw mm3, mm4 - pand mm3, mm7 - movq [dstq + maskq], mm3 - add maskq, 8 - movq mm0, [src1q + maskq - 2] - movq mm2, [src2q + maskq - 2] - cmp maskq, wq - jb .loop - movzx maskd, word [src1q + wq - 2] - mov [left_topq], maskd - movzx maskd, word [src2q + wq - 2] - mov [leftq], maskd + movu m0, [src1q + wq - 2] ; lt + movu m2, [src2q + wq - 2] ; l +.init: + movu m1, [src1q + wq] ; t + movu m3, [src2q + wq] + psubw m4, m2, m0 ; l - lt + pmax%1w m0, m1, m2 + paddw m4, m1 ; l - lt + t + pmin%1w m2, m1 + pand m4, m5 ; (l - lt + t)&mask + pmin%1w m4, m0 + pmax%1w m4, m2 ; pred + psubw m3, m4 ; l - pred + pand m3, m5 + movu [dstq + wq], m3 + add wq, mmsize + js .loop + + cmp wd, mmsize-1 + jne .tail + + movzx src1d, word [src1q + (mmsize-1) - 2] + movzx src2d, word [src2q + (mmsize-1) - 2] + mov [left_topq], src1d + mov [leftq], src2d RET +.tail: + mov wq, -1 + jmp .loop +%endmacro + +INIT_XMM sse2 +SUB_HFYU_MEDIAN_PRED_INT16 s + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +SUB_HFYU_MEDIAN_PRED_INT16 u +%endif diff --git a/libavcodec/x86/huffyuvencdsp_init.c b/libavcodec/x86/huffyuvencdsp_init.c index c9c33b75b..b4dd69bd2 100644 --- a/libavcodec/x86/huffyuvencdsp_init.c +++ b/libavcodec/x86/huffyuvencdsp_init.c @@ -24,7 +24,6 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" -#include "libavutil/pixdesc.h" #include "libavutil/x86/cpu.h" #include "libavcodec/huffyuvencdsp.h" @@ -32,23 +31,24 @@ void ff_diff_int16_sse2(uint16_t *dst, const uint16_t *src1, const uint16_t *src unsigned mask, int w); void ff_diff_int16_avx2(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, unsigned mask, int w); -void ff_sub_hfyu_median_pred_int16_mmxext(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, - unsigned mask, int w, int *left, int *left_top); +void ff_sub_hfyu_median_pred_int16_sse2(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, + unsigned mask, int w, int *left, int *left_top); +void ff_sub_hfyu_median_pred_int16_avx2(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, + unsigned mask, int w, int *left, int *left_top); -av_cold void ff_huffyuvencdsp_init_x86(HuffYUVEncDSPContext *c, enum AVPixelFormat pix_fmt) +av_cold void ff_huffyuvencdsp_init_x86(HuffYUVEncDSPContext *c, int bpp, int width) { - av_unused int cpu_flags = av_get_cpu_flags(); - const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(pix_fmt); - - if (EXTERNAL_MMXEXT(cpu_flags) && pix_desc && pix_desc->comp[0].depth<16) { - c->sub_hfyu_median_pred_int16 = ff_sub_hfyu_median_pred_int16_mmxext; - } + int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE2(cpu_flags)) { c->diff_int16 = ff_diff_int16_sse2; + if (bpp < 16 && width >= 8) + c->sub_hfyu_median_pred_int16 = ff_sub_hfyu_median_pred_int16_sse2; } if (EXTERNAL_AVX2_FAST(cpu_flags)) { c->diff_int16 = ff_diff_int16_avx2; + if (width >= 16) + c->sub_hfyu_median_pred_int16 = ff_sub_hfyu_median_pred_int16_avx2; } } diff --git a/libavcodec/x86/idctdsp.h b/libavcodec/x86/idctdsp.h index 738e4e36e..9e8474cac 100644 --- a/libavcodec/x86/idctdsp.h +++ b/libavcodec/x86/idctdsp.h @@ -22,11 +22,11 @@ #include #include -void ff_add_pixels_clamped_sse2(const int16_t *block, uint8_t *pixels, +void ff_add_pixels_clamped_sse2(const int16_t *block, uint8_t *restrict pixels, ptrdiff_t line_size); -void ff_put_pixels_clamped_sse2(const int16_t *block, uint8_t *pixels, +void ff_put_pixels_clamped_sse2(const int16_t *block, uint8_t *restrict pixels, ptrdiff_t line_size); -void ff_put_signed_pixels_clamped_sse2(const int16_t *block, uint8_t *pixels, +void ff_put_signed_pixels_clamped_sse2(const int16_t *block, uint8_t *restrict pixels, ptrdiff_t line_size); diff --git a/libavcodec/x86/idctdsp_init.c b/libavcodec/x86/idctdsp_init.c index 2d165b975..fce62e559 100644 --- a/libavcodec/x86/idctdsp_init.c +++ b/libavcodec/x86/idctdsp_init.c @@ -65,18 +65,6 @@ av_cold void ff_idctdsp_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, { int cpu_flags = av_get_cpu_flags(); -#if ARCH_X86_32 - if (EXTERNAL_MMX(cpu_flags)) { - if (!high_bit_depth && - avctx->lowres == 0 && - (avctx->idct_algo == FF_IDCT_AUTO || - avctx->idct_algo == FF_IDCT_SIMPLEAUTO || - avctx->idct_algo == FF_IDCT_SIMPLEMMX)) { - c->idct = ff_simple_idct_mmx; - } - } -#endif - if (EXTERNAL_SSE2(cpu_flags)) { c->put_signed_pixels_clamped = ff_put_signed_pixels_clamped_sse2; c->put_pixels_clamped = ff_put_pixels_clamped_sse2; @@ -88,14 +76,15 @@ av_cold void ff_idctdsp_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, (avctx->idct_algo == FF_IDCT_AUTO || avctx->idct_algo == FF_IDCT_SIMPLEAUTO || avctx->idct_algo == FF_IDCT_SIMPLEMMX)) { + c->idct = ff_simple_idct_sse2; c->idct_put = ff_simple_idct_put_sse2; c->idct_add = ff_simple_idct_add_sse2; c->perm_type = FF_IDCT_PERM_SIMPLE; } #endif - if (ARCH_X86_64 && - !high_bit_depth && +#if ARCH_X86_64 + if (!high_bit_depth && avctx->lowres == 0 && (avctx->idct_algo == FF_IDCT_AUTO || avctx->idct_algo == FF_IDCT_SIMPLEAUTO || @@ -106,9 +95,11 @@ av_cold void ff_idctdsp_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, c->idct_add = ff_simple_idct8_add_sse2; c->perm_type = FF_IDCT_PERM_TRANSPOSE; } +#endif } - if (ARCH_X86_64 && avctx->lowres == 0) { +#if ARCH_X86_64 + if (avctx->lowres == 0) { if (EXTERNAL_AVX(cpu_flags) && !high_bit_depth && (avctx->idct_algo == FF_IDCT_AUTO || @@ -158,4 +149,5 @@ av_cold void ff_idctdsp_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, } } } +#endif } diff --git a/libavcodec/x86/inline_asm.h b/libavcodec/x86/inline_asm.h deleted file mode 100644 index 019874671..000000000 --- a/libavcodec/x86/inline_asm.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * inline assembly helper macros - * - * 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_X86_INLINE_ASM_H -#define AVCODEC_X86_INLINE_ASM_H - -#include "constants.h" - -#define MOVQ_WONE(regd) \ - __asm__ volatile ( \ - "pcmpeqd %%" #regd ", %%" #regd " \n\t" \ - "psrlw $15, %%" #regd ::) - -#define JUMPALIGN() __asm__ volatile (".p2align 3"::) -#define MOVQ_ZERO(regd) __asm__ volatile ("pxor %%"#regd", %%"#regd ::) - -#define MOVQ_BFE(regd) \ - __asm__ volatile ( \ - "pcmpeqd %%"#regd", %%"#regd" \n\t" \ - "paddb %%"#regd", %%"#regd" \n\t" ::) - -#ifndef PIC -#define MOVQ_WTWO(regd) __asm__ volatile ("movq %0, %%"#regd" \n\t" :: "m"(ff_pw_2)) -#else -// for shared library it's better to use this way for accessing constants -// pcmpeqd -> -1 -#define MOVQ_WTWO(regd) \ - __asm__ volatile ( \ - "pcmpeqd %%"#regd", %%"#regd" \n\t" \ - "psrlw $15, %%"#regd" \n\t" \ - "psllw $1, %%"#regd" \n\t"::) - -#endif - -// using regr as temporary and for the output result -// first argument is unmodified and second is trashed -// regfe is supposed to contain 0xfefefefefefefefe -#define PAVGB_MMX_NO_RND(rega, regb, regr, regfe) \ - "movq "#rega", "#regr" \n\t" \ - "pand "#regb", "#regr" \n\t" \ - "pxor "#rega", "#regb" \n\t" \ - "pand "#regfe", "#regb" \n\t" \ - "psrlq $1, "#regb" \n\t" \ - "paddb "#regb", "#regr" \n\t" - -#define PAVGB_MMX(rega, regb, regr, regfe) \ - "movq "#rega", "#regr" \n\t" \ - "por "#regb", "#regr" \n\t" \ - "pxor "#rega", "#regb" \n\t" \ - "pand "#regfe", "#regb" \n\t" \ - "psrlq $1, "#regb" \n\t" \ - "psubb "#regb", "#regr" \n\t" - -// mm6 is supposed to contain 0xfefefefefefefefe -#define PAVGBP_MMX_NO_RND(rega, regb, regr, regc, regd, regp) \ - "movq "#rega", "#regr" \n\t" \ - "movq "#regc", "#regp" \n\t" \ - "pand "#regb", "#regr" \n\t" \ - "pand "#regd", "#regp" \n\t" \ - "pxor "#rega", "#regb" \n\t" \ - "pxor "#regc", "#regd" \n\t" \ - "pand %%mm6, "#regb" \n\t" \ - "pand %%mm6, "#regd" \n\t" \ - "psrlq $1, "#regb" \n\t" \ - "psrlq $1, "#regd" \n\t" \ - "paddb "#regb", "#regr" \n\t" \ - "paddb "#regd", "#regp" \n\t" - -#define PAVGBP_MMX(rega, regb, regr, regc, regd, regp) \ - "movq "#rega", "#regr" \n\t" \ - "movq "#regc", "#regp" \n\t" \ - "por "#regb", "#regr" \n\t" \ - "por "#regd", "#regp" \n\t" \ - "pxor "#rega", "#regb" \n\t" \ - "pxor "#regc", "#regd" \n\t" \ - "pand %%mm6, "#regb" \n\t" \ - "pand %%mm6, "#regd" \n\t" \ - "psrlq $1, "#regd" \n\t" \ - "psrlq $1, "#regb" \n\t" \ - "psubb "#regb", "#regr" \n\t" \ - "psubb "#regd", "#regp" \n\t" - -#endif /* AVCODEC_X86_INLINE_ASM_H */ diff --git a/libavcodec/x86/lossless_audiodsp_init.c b/libavcodec/x86/lossless_audiodsp_init.c index 462329db3..a8bae6cca 100644 --- a/libavcodec/x86/lossless_audiodsp_init.c +++ b/libavcodec/x86/lossless_audiodsp_init.c @@ -34,7 +34,6 @@ int32_t ff_scalarproduct_and_madd_int32_sse4(int16_t *v1, const int32_t *v2, av_cold void ff_llauddsp_init_x86(LLAudDSPContext *c) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE2(cpu_flags)) @@ -46,5 +45,4 @@ av_cold void ff_llauddsp_init_x86(LLAudDSPContext *c) if (EXTERNAL_SSE4(cpu_flags)) c->scalarproduct_and_madd_int32 = ff_scalarproduct_and_madd_int32_sse4; -#endif } diff --git a/libavcodec/x86/lossless_videodsp.asm b/libavcodec/x86/lossless_videodsp.asm index 7159aafe6..1761a2f08 100644 --- a/libavcodec/x86/lossless_videodsp.asm +++ b/libavcodec/x86/lossless_videodsp.asm @@ -27,9 +27,8 @@ SECTION_RODATA cextern pb_15 pb_zzzzzzzz77777777: times 8 db -1 -pb_7: times 8 db 7 + times 8 db 7 pb_ef: times 8 db 14,15 -pb_67: times 8 db 6, 7 pb_zzzz3333zzzzbbbb: db -1,-1,-1,-1,3,3,3,3,-1,-1,-1,-1,11,11,11,11 pb_zz11zz55zz99zzdd: db -1,-1,1,1,-1,-1,5,5,-1,-1,9,9,-1,-1,13,13 pb_zzzz2323zzzzabab: db -1,-1,-1,-1, 2, 3, 2, 3,-1,-1,-1,-1,10,11,10,11 @@ -102,46 +101,30 @@ cglobal add_median_pred, 6,6,8, dst, top, diff, w, left, left_top RET -%macro ADD_LEFT_LOOP 2 ; %1 = dst_is_aligned, %2 = src_is_aligned +%macro ADD_LEFT_LOOP 2 ; %1 = dst alignment (a/u), %2 = src alignment (a/u) add srcq, wq add dstq, wq neg wq %%.loop: pshufb xm0, xm5 -%if %2 - mova m1, [srcq+wq] -%else - movu m1, [srcq+wq] -%endif + mov%2 m1, [srcq+wq] psllw m2, m1, 8 paddb m1, m2 pshufb m2, m1, m3 paddb m1, m2 pshufb m2, m1, m4 paddb m1, m2 -%if mmsize >= 16 pshufb m2, m1, m6 paddb m1, m2 -%endif paddb xm0, xm1 -%if %1 - mova [dstq+wq], xm0 -%else - movq [dstq+wq], xm0 - movhps [dstq+wq+8], xm0 -%endif + mov%1 [dstq+wq], xm0 %if mmsize == 32 vextracti128 xm2, m1, 1 ; get second lane of the ymm pshufb xm0, xm5 ; set alls val to last val of the first lane paddb xm0, xm2 ;store val -%if %1 - mova [dstq+wq+16], xm0 -%else; - movq [dstq+wq+16], xm0 - movhps [dstq+wq+16+8], xm0 -%endif + mov%1 [dstq+wq+16], xm0 %endif add wq, mmsize jl %%.loop @@ -160,16 +143,6 @@ cglobal add_median_pred, 6,6,8, dst, top, diff, w, left, left_top ;------------------------------------------------------------------------------ ; int ff_add_left_pred(uint8_t *dst, const uint8_t *src, int w, int left) ;------------------------------------------------------------------------------ -INIT_MMX ssse3 -cglobal add_left_pred, 3,3,7, dst, src, w, left -.skip_prologue: - mova m5, [pb_7] - mova m4, [pb_zzzz3333zzzzbbbb] - mova m3, [pb_zz11zz55zz99zzdd] - movd m0, leftm - psllq m0, 56 - ADD_LEFT_LOOP 1, 1 - %macro ADD_LEFT_PRED_UNALIGNED 0 cglobal add_left_pred_unaligned, 3,3,7, dst, src, w, left mova xm5, [pb_15] @@ -178,15 +151,17 @@ cglobal add_left_pred_unaligned, 3,3,7, dst, src, w, left VBROADCASTI128 m3, [pb_zz11zz55zz99zzdd] movd xm0, leftm pslldq xm0, 15 +%if notcpuflag(avx2) test srcq, mmsize - 1 jnz .src_unaligned test dstq, mmsize - 1 jnz .dst_unaligned - ADD_LEFT_LOOP 1, 1 + ADD_LEFT_LOOP a, a .dst_unaligned: - ADD_LEFT_LOOP 0, 1 + ADD_LEFT_LOOP u, a .src_unaligned: - ADD_LEFT_LOOP 0, 0 +%endif + ADD_LEFT_LOOP u, u %endmacro INIT_XMM ssse3 @@ -255,19 +230,12 @@ ADD_BYTES pshufb m1, m3 paddw m1, m2 pshufb m0, m5 -%if mmsize == 16 mova m2, m1 pshufb m1, m4 paddw m1, m2 -%endif paddw m0, m1 - pand m0, m7 -%ifidn %1, a - mova [dstq+wq], m0 -%else - movq [dstq+wq], m0 - movhps [dstq+wq+8], m0 -%endif + pand m0, m6 + mov%1 [dstq+wq], m0 add wq, mmsize jl %%.loop mov eax, mmsize-1 @@ -284,26 +252,15 @@ ADD_BYTES ;--------------------------------------------------------------------------------------------- ; int add_left_pred_int16(uint16_t *dst, const uint16_t *src, unsigned mask, int w, int left) ;--------------------------------------------------------------------------------------------- -INIT_MMX ssse3 -cglobal add_left_pred_int16, 4,4,8, dst, src, mask, w, left -.skip_prologue: - mova m5, [pb_67] - mova m3, [pb_zzzz2323zzzzabab] - movd m0, leftm - psllq m0, 48 - movd m7, maskm - SPLATW m7 ,m7 - ADD_HFYU_LEFT_LOOP_INT16 a, a - INIT_XMM ssse3 -cglobal add_left_pred_int16_unaligned, 4,4,8, dst, src, mask, w, left +cglobal add_left_pred_int16_unaligned, 4,4,7, dst, src, mask, w, left mova m5, [pb_ef] mova m4, [pb_zzzzzzzz67676767] mova m3, [pb_zzzz2323zzzzabab] movd m0, leftm + movd m6, maskm pslldq m0, 14 - movd m7, maskm - SPLATW m7 ,m7 + SPLATW m6, m6 test srcq, 15 jnz .src_unaligned test dstq, 15 diff --git a/libavcodec/x86/lossless_videodsp_init.c b/libavcodec/x86/lossless_videodsp_init.c index 5690cacaa..fce3dd4d6 100644 --- a/libavcodec/x86/lossless_videodsp_init.c +++ b/libavcodec/x86/lossless_videodsp_init.c @@ -29,14 +29,11 @@ void ff_add_median_pred_sse2(uint8_t *dst, const uint8_t *top, const uint8_t *diff, ptrdiff_t w, int *left, int *left_top); -int ff_add_left_pred_ssse3(uint8_t *dst, const uint8_t *src, - ptrdiff_t w, int left); int ff_add_left_pred_unaligned_ssse3(uint8_t *dst, const uint8_t *src, ptrdiff_t w, int left); int ff_add_left_pred_unaligned_avx2(uint8_t *dst, const uint8_t *src, ptrdiff_t w, int left); -int ff_add_left_pred_int16_ssse3(uint16_t *dst, const uint16_t *src, unsigned mask, ptrdiff_t w, unsigned acc); int ff_add_left_pred_int16_unaligned_ssse3(uint16_t *dst, const uint16_t *src, unsigned mask, ptrdiff_t w, unsigned acc); void ff_add_gradient_pred_ssse3(uint8_t *src, const ptrdiff_t stride, const ptrdiff_t width); @@ -52,14 +49,9 @@ void ff_llviddsp_init_x86(LLVidDSPContext *c) } if (EXTERNAL_SSSE3(cpu_flags)) { - c->add_left_pred = ff_add_left_pred_ssse3; - c->add_left_pred_int16 = ff_add_left_pred_int16_ssse3; - c->add_gradient_pred = ff_add_gradient_pred_ssse3; - } - - if (EXTERNAL_SSSE3_FAST(cpu_flags)) { - c->add_left_pred = ff_add_left_pred_unaligned_ssse3; + c->add_left_pred = ff_add_left_pred_unaligned_ssse3; c->add_left_pred_int16 = ff_add_left_pred_int16_unaligned_ssse3; + c->add_gradient_pred = ff_add_gradient_pred_ssse3; } if (EXTERNAL_AVX2_FAST(cpu_flags)) { diff --git a/libavcodec/x86/lossless_videoencdsp.asm b/libavcodec/x86/lossless_videoencdsp.asm index 8ccaea913..47a10ae13 100644 --- a/libavcodec/x86/lossless_videoencdsp.asm +++ b/libavcodec/x86/lossless_videoencdsp.asm @@ -143,6 +143,45 @@ DIFF_BYTES_PROLOGUE %undef i %endif +;-------------------------------------------------------------------------------------------------- +;void sub_median_pred(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, +; intptr_t w, int *left, int *left_top) +;-------------------------------------------------------------------------------------------------- + +INIT_XMM sse2 +cglobal sub_median_pred, 6, 7, 6, dst, src1, src2, w, l, lt + movu m0, [src1q] ; LT + movu m4, [src2q] ; L + movd m1, [ltq] ; LT + movd m3, [lq] ; L + xor r6d, r6d + pslldq m0, 1 + pslldq m4, 1 + por m0, m1 ; LT + por m4, m3 ; L + jmp .first_iteration +.loop: + movu m4, [src2q+r6q-1] ; L + movu m0, [src1q+r6q-1] ; LT +.first_iteration: + movu m1, [src1q+r6q] ; T + movu m3, [src2q+r6q] ; X + psubb m2, m4, m0 ; L - LT + paddb m2, m1 ; L + T - LT + pmaxub m5, m4, m1 ; max(T, L) + pminub m1, m4 ; min(T, L) + pminub m5, m2 + pmaxub m5, m1 + psubb m3, m5 ; dst - pred + movu [dstq+r6q], m3 + add r6d, 16 + cmp r6d, wd + jb .loop + movzx src1d, BYTE [src1q+wq-1] + movzx src2d, BYTE [src2q+wq-1] + mov [ltq], src1d + mov [lq], src2d + RET ;-------------------------------------------------------------------------------------------------- ;void sub_left_predict(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, ptrdiff_t width, int height) diff --git a/libavcodec/x86/lossless_videoencdsp_init.c b/libavcodec/x86/lossless_videoencdsp_init.c index 22a4014ef..c0cddf593 100644 --- a/libavcodec/x86/lossless_videoencdsp_init.c +++ b/libavcodec/x86/lossless_videoencdsp_init.c @@ -24,74 +24,27 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" -#include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" #include "libavcodec/lossless_videoencdsp.h" -#include "libavcodec/mathops.h" void ff_diff_bytes_sse2(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, intptr_t w); void ff_diff_bytes_avx2(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, intptr_t w); +void ff_sub_median_pred_sse2(uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, intptr_t w, + int *left, int *left_top); + void ff_sub_left_predict_avx(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, ptrdiff_t width, int height); -#if HAVE_INLINE_ASM - -static void sub_median_pred_mmxext(uint8_t *dst, const uint8_t *src1, - const uint8_t *src2, intptr_t w, - int *left, int *left_top) -{ - x86_reg i = 0; - uint8_t l, lt; - - __asm__ volatile ( - "movq (%1, %0), %%mm0 \n\t" // LT - "psllq $8, %%mm0 \n\t" - "1: \n\t" - "movq (%1, %0), %%mm1 \n\t" // T - "movq -1(%2, %0), %%mm2 \n\t" // L - "movq (%2, %0), %%mm3 \n\t" // X - "movq %%mm2, %%mm4 \n\t" // L - "psubb %%mm0, %%mm2 \n\t" - "paddb %%mm1, %%mm2 \n\t" // L + T - LT - "movq %%mm4, %%mm5 \n\t" // L - "pmaxub %%mm1, %%mm4 \n\t" // max(T, L) - "pminub %%mm5, %%mm1 \n\t" // min(T, L) - "pminub %%mm2, %%mm4 \n\t" - "pmaxub %%mm1, %%mm4 \n\t" - "psubb %%mm4, %%mm3 \n\t" // dst - pred - "movq %%mm3, (%3, %0) \n\t" - "add $8, %0 \n\t" - "movq -1(%1, %0), %%mm0 \n\t" // LT - "cmp %4, %0 \n\t" - " jb 1b \n\t" - : "+r" (i) - : "r" (src1), "r" (src2), "r" (dst), "r" ((x86_reg) w)); - - l = *left; - lt = *left_top; - - dst[0] = src2[0] - mid_pred(l, src1[0], (l + src1[0] - lt) & 0xFF); - - *left_top = src1[w - 1]; - *left = src2[w - 1]; -} - -#endif /* HAVE_INLINE_ASM */ - av_cold void ff_llvidencdsp_init_x86(LLVidEncDSPContext *c) { - av_unused int cpu_flags = av_get_cpu_flags(); - -#if HAVE_INLINE_ASM - if (INLINE_MMXEXT(cpu_flags)) { - c->sub_median_pred = sub_median_pred_mmxext; - } -#endif /* HAVE_INLINE_ASM */ + int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE2(cpu_flags)) { + c->sub_median_pred = ff_sub_median_pred_sse2; c->diff_bytes = ff_diff_bytes_sse2; } diff --git a/libavcodec/x86/lpc.asm b/libavcodec/x86/lpc.asm index a585c17ef..a4f1ee91e 100644 --- a/libavcodec/x86/lpc.asm +++ b/libavcodec/x86/lpc.asm @@ -257,7 +257,5 @@ cglobal lpc_apply_welch_window, 3, 5, 8, data, len, out, off1, off2 INIT_XMM sse2 APPLY_WELCH_FN -%if HAVE_AVX2_EXTERNAL INIT_YMM avx2 APPLY_WELCH_FN -%endif diff --git a/libavcodec/x86/me_cmp.asm b/libavcodec/x86/me_cmp.asm index 923eb8078..3ac8acee2 100644 --- a/libavcodec/x86/me_cmp.asm +++ b/libavcodec/x86/me_cmp.asm @@ -27,6 +27,10 @@ SECTION_RODATA cextern pb_1 cextern pb_80 +cextern pw_2 + +pb_unpack1: db 0, 0xFF, 1, 0xFF, 2, 0xFF, 3, 0xFF, 4, 0xFF, 5, 0xFF, 6, 0xFF, 0xFF, 0xFF +pb_unpack2: db 1, 0xFF, 2, 0xFF, 3, 0xFF, 4, 0xFF, 5, 0xFF, 6, 0xFF, 7, 0xFF, 0xFF, 0xFF SECTION .text @@ -108,7 +112,6 @@ SECTION .text ; about 100k on extreme inputs. But that's very unlikely to occur in natural video, ; and it's even more unlikely to not have any alternative mvs/modes with lower cost. %macro HSUM 3 -%if cpuflag(sse2) movhlps %2, %1 paddusw %1, %2 pshuflw %2, %1, 0xE @@ -116,55 +119,10 @@ SECTION .text pshuflw %2, %1, 0x1 paddusw %1, %2 movd %3, %1 -%elif cpuflag(mmxext) - pshufw %2, %1, 0xE - paddusw %1, %2 - pshufw %2, %1, 0x1 - paddusw %1, %2 - movd %3, %1 -%elif cpuflag(mmx) - mova %2, %1 - psrlq %1, 32 - paddusw %1, %2 - mova %2, %1 - psrlq %1, 16 - paddusw %1, %2 - movd %3, %1 -%endif %endmacro -%macro STORE4 5 - mova [%1+mmsize*0], %2 - mova [%1+mmsize*1], %3 - mova [%1+mmsize*2], %4 - mova [%1+mmsize*3], %5 -%endmacro - -%macro LOAD4 5 - mova %2, [%1+mmsize*0] - mova %3, [%1+mmsize*1] - mova %4, [%1+mmsize*2] - mova %5, [%1+mmsize*3] -%endmacro - -%macro hadamard8_16_wrapper 2 -cglobal hadamard8_diff, 4, 4, %1 -%ifndef m8 - %assign pad %2*mmsize-(4+stack_offset&(mmsize-1)) - SUB rsp, pad -%endif - call hadamard8x8_diff %+ SUFFIX -%ifndef m8 - ADD rsp, pad -%endif - RET - -cglobal hadamard8_diff16, 5, 6, %1 -%ifndef m8 - %assign pad %2*mmsize-(4+stack_offset&(mmsize-1)) - SUB rsp, pad -%endif - +%macro HADAMARD8_DIFF 1 +cglobal hadamard8_diff16, 5, 6, %1, 2*mmsize*ARCH_X86_32 call hadamard8x8_diff %+ SUFFIX mov r5d, eax @@ -188,14 +146,14 @@ cglobal hadamard8_diff16, 5, 6, %1 .done: mov eax, r5d -%ifndef m8 - ADD rsp, pad -%endif RET -%endmacro -%macro HADAMARD8_DIFF 0-1 -%if cpuflag(sse2) +cglobal hadamard8_diff, 4, 4, %1, 2*mmsize*ARCH_X86_32 + TAIL_CALL hadamard8x8_diff %+ SUFFIX, 0 + +; r1, r2 and r3 are not clobbered in this function, so 16x16 can +; simply call this 2x2x (and that's why we access rsp+gprsize +; everywhere, which is rsp of calling function) hadamard8x8_diff %+ SUFFIX: lea r0, [r3*3] DIFF_PIXELS_8 r1, r2, 0, r3, r0, rsp+gprsize @@ -210,62 +168,8 @@ hadamard8x8_diff %+ SUFFIX: HSUM m0, m1, eax and eax, 0xFFFF ret - -hadamard8_16_wrapper %1, 3 -%elif cpuflag(mmx) -ALIGN 16 -; int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, const uint8_t *src1, -; const uint8_t *src2, ptrdiff_t stride, int h) -; r0 = void *s = unused, int h = unused (always 8) -; note how r1, r2 and r3 are not clobbered in this function, so 16x16 -; can simply call this 2x2x (and that's why we access rsp+gprsize -; everywhere, which is rsp of calling func -hadamard8x8_diff %+ SUFFIX: - lea r0, [r3*3] - - ; first 4x8 pixels - DIFF_PIXELS_8 r1, r2, 0, r3, r0, rsp+gprsize+0x60 - HADAMARD8 - mova [rsp+gprsize+0x60], m7 - TRANSPOSE4x4W 0, 1, 2, 3, 7 - STORE4 rsp+gprsize, m0, m1, m2, m3 - mova m7, [rsp+gprsize+0x60] - TRANSPOSE4x4W 4, 5, 6, 7, 0 - STORE4 rsp+gprsize+0x40, m4, m5, m6, m7 - - ; second 4x8 pixels - DIFF_PIXELS_8 r1, r2, 4, r3, r0, rsp+gprsize+0x60 - HADAMARD8 - mova [rsp+gprsize+0x60], m7 - TRANSPOSE4x4W 0, 1, 2, 3, 7 - STORE4 rsp+gprsize+0x20, m0, m1, m2, m3 - mova m7, [rsp+gprsize+0x60] - TRANSPOSE4x4W 4, 5, 6, 7, 0 - - LOAD4 rsp+gprsize+0x40, m0, m1, m2, m3 - HADAMARD8 - ABS_SUM_8x8_32 rsp+gprsize+0x60 - mova [rsp+gprsize+0x60], m0 - - LOAD4 rsp+gprsize , m0, m1, m2, m3 - LOAD4 rsp+gprsize+0x20, m4, m5, m6, m7 - HADAMARD8 - ABS_SUM_8x8_32 rsp+gprsize - paddusw m0, [rsp+gprsize+0x60] - - HSUM m0, m1, eax - and rax, 0xFFFF - ret - -hadamard8_16_wrapper 0, 14 -%endif %endmacro -%if HAVE_ALIGNED_STACK == 0 -INIT_MMX mmxext -HADAMARD8_DIFF -%endif - INIT_XMM sse2 %if ARCH_X86_64 %define ABS_SUM_8x8 ABS_SUM_8x8_64 @@ -278,37 +182,43 @@ INIT_XMM ssse3 %define ABS_SUM_8x8 ABS_SUM_8x8_64 HADAMARD8_DIFF 9 -; int ff_sse*_*(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, -; ptrdiff_t line_size, int h) +; int ff_sse*_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +; ptrdiff_t line_size, int h) %macro SUM_SQUARED_ERRORS 1 -cglobal sse%1, 5,5,8, v, pix1, pix2, lsize, h -%if %1 == mmsize - shr hd, 1 -%endif +cglobal sse%1, 5,5,%1 < mmsize ? 6 : 8, v, pix1, pix2, lsize, h pxor m0, m0 ; mm0 = 0 - pxor m7, m7 ; mm7 holds the sum + pxor m5, m5 ; m5 holds the sum .next2lines: ; FIXME why are these unaligned movs? pix1[] is aligned - movu m1, [pix1q] ; m1 = pix1[0][0-15], [0-7] for mmx - movu m2, [pix2q] ; m2 = pix2[0][0-15], [0-7] for mmx -%if %1 == mmsize - movu m3, [pix1q+lsizeq] ; m3 = pix1[1][0-15], [0-7] for mmx - movu m4, [pix2q+lsizeq] ; m4 = pix2[1][0-15], [0-7] for mmx -%else ; %1 / 2 == mmsize; mmx only - mova m3, [pix1q+8] ; m3 = pix1[0][8-15] - mova m4, [pix2q+8] ; m4 = pix2[0][8-15] -%endif +%if %1 < mmsize + movh m1, [pix1q] + movh m2, [pix2q] + movh m3, [pix1q+lsizeq] + movh m4, [pix2q+lsizeq] + punpcklbw m1, m0 + punpcklbw m2, m0 + punpcklbw m3, m0 + punpcklbw m4, m0 + psubw m1, m2 + psubw m3, m4 + pmaddwd m1, m1 + pmaddwd m3, m3 +%else + movu m1, [pix1q] ; m1 = pix1[0][0-15] + movu m2, [pix2q] ; m2 = pix2[0][0-15] + movu m3, [pix1q+lsizeq] ; m3 = pix1[1][0-15] + movu m4, [pix2q+lsizeq] ; m4 = pix2[1][0-15] ; todo: mm1-mm2, mm3-mm4 ; algo: subtract mm1 from mm2 with saturation and vice versa ; OR the result to get the absolute difference - mova m5, m1 - mova m6, m3 + mova m6, m1 + mova m7, m3 psubusb m1, m2 psubusb m3, m4 - psubusb m2, m5 - psubusb m4, m6 + psubusb m2, m6 + psubusb m4, m7 por m2, m1 por m4, m3 @@ -329,31 +239,22 @@ cglobal sse%1, 5,5,8, v, pix1, pix2, lsize, h paddd m1, m2 paddd m3, m4 - paddd m7, m1 - paddd m7, m3 +%endif + paddd m5, m1 + paddd m5, m3 -%if %1 == mmsize lea pix1q, [pix1q + 2*lsizeq] lea pix2q, [pix2q + 2*lsizeq] -%else - add pix1q, lsizeq - add pix2q, lsizeq -%endif - dec hd + sub hd, 2 jnz .next2lines - HADDD m7, m1 - movd eax, m7 ; return value + HADDD m5, m1 + movd eax, m5 ; return value RET %endmacro -INIT_MMX mmx -SUM_SQUARED_ERRORS 8 - -INIT_MMX mmx -SUM_SQUARED_ERRORS 16 - INIT_XMM sse2 +SUM_SQUARED_ERRORS 8 SUM_SQUARED_ERRORS 16 ;----------------------------------------------- @@ -390,19 +291,16 @@ INIT_XMM ssse3 SUM_ABS_DCTELEM 6, 2 ;------------------------------------------------------------------------------ -; int ff_hf_noise*_mmx(const uint8_t *pix1, ptrdiff_t lsize, int h) +; int ff_hf_noise*_ssse3(const uint8_t *pix1, ptrdiff_t lsize, int h) ;------------------------------------------------------------------------------ -; %1 = 8/16. %2-5=m# -%macro HF_NOISE_PART1 5 - mova m%2, [pix1q] -%if %1 == 8 +; %1 = 8/16, %2-5=m#, %6 = src +%macro HF_NOISE_PART1 6 +%if %1 == mmsize + movu m%2, [%6] mova m%3, m%2 - psllq m%2, 8 - psrlq m%3, 8 - psrlq m%2, 8 -%else - mova m%3, [pix1q+1] -%endif + pslldq m%2, 1 + psrldq m%3, 1 + psrldq m%2, 1 mova m%4, m%2 mova m%5, m%3 punpcklbw m%2, m7 @@ -411,79 +309,90 @@ SUM_ABS_DCTELEM 6, 2 punpckhbw m%5, m7 psubw m%2, m%3 psubw m%4, m%5 +%else + movh m%2, [%6] + pshufb m%3, m%2, m5 + pshufb m%2, m%2, m4 + psubw m%2, m%3 +%endif %endmacro -; %1-2 = m# -%macro HF_NOISE_PART2 4 - psubw m%1, m%3 - psubw m%2, m%4 - pxor m3, m3 - pxor m1, m1 - pcmpgtw m3, m%1 - pcmpgtw m1, m%2 - pxor m%1, m3 - pxor m%2, m1 - psubw m%1, m3 - psubw m%2, m1 - paddw m%2, m%1 - paddw m6, m%2 +; %1 = 8/16, %2-5 = m# +%macro HF_NOISE_PART2 5 +%if %1 == mmsize + psubw m%2, m%3 + psubw m%4, m%5 + pabsw m%2, m%2 + pabsw m%4, m%4 + paddw m%2, m%4 +%else + psubw m%2, m%3 + pabsw m%2, m%2 +%endif + paddw m0, m%2 %endmacro ; %1 = 8/16 %macro HF_NOISE 1 -cglobal hf_noise%1, 3,3,0, pix1, lsize, h +cglobal hf_noise%1, 3,3,(%1 == 8) ? 6 : 8, pix1, lsize, h +%if %1 == 8 + mova m4, [pb_unpack1] + mova m5, [pb_unpack2] +%else + pxor m4, m4 +%endif sub hd, 2 - pxor m7, m7 - pxor m6, m6 - HF_NOISE_PART1 %1, 0, 1, 2, 3 - add pix1q, lsizeq - HF_NOISE_PART1 %1, 4, 1, 5, 3 - HF_NOISE_PART2 0, 2, 4, 5 - add pix1q, lsizeq + pxor m0, m0 + HF_NOISE_PART1 %1, 1, 2, 5, 7, pix1q + HF_NOISE_PART1 %1, 3, 2, 6, 7, pix1q+lsizeq + lea pix1q, [pix1q+2*lsizeq] + HF_NOISE_PART2 %1, 1, 3, 5, 6 .loop: - HF_NOISE_PART1 %1, 0, 1, 2, 3 - HF_NOISE_PART2 4, 5, 0, 2 - add pix1q, lsizeq - HF_NOISE_PART1 %1, 4, 1, 5, 3 - HF_NOISE_PART2 0, 2, 4, 5 - add pix1q, lsizeq + HF_NOISE_PART1 %1, 1, 2, 5, 7, pix1q + HF_NOISE_PART2 %1, 3, 1, 6, 5 + HF_NOISE_PART1 %1, 3, 2, 6, 7, pix1q+lsizeq + lea pix1q, [pix1q+2*lsizeq] + HF_NOISE_PART2 %1, 1, 3, 5, 6 sub hd, 2 jne .loop - mova m0, m6 - punpcklwd m0, m7 - punpckhwd m6, m7 - paddd m6, m0 - mova m0, m6 - psrlq m6, 32 - paddd m0, m6 - movd eax, m0 ; eax = result of hf_noise8; +%if %1 == 8 + pxor m4, m4 +%endif + movhlps m1, m0 + paddw m0, m1 + punpcklwd m0, m4 + HADDD m0, m1 + movd eax, m0 ; eax = result of hf_noise; RET ; return eax; %endmacro -INIT_MMX mmx +INIT_XMM ssse3 HF_NOISE 8 HF_NOISE 16 ;--------------------------------------------------------------------------------------- -;int ff_sad_(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); +;int ff_sad_(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); ;--------------------------------------------------------------------------------------- -;%1 = 8/16 -%macro SAD 1 -cglobal sad%1, 5, 5, 3, v, pix1, pix2, stride, h +;%1 = 8/16, %2 = a/u (whether pix1 is aligned or not) +%macro SAD 1-2 +%ifidn %2, u +cglobal sad%1u, 5, 5, 5, v, pix1, pix2, stride, h +%else +cglobal sad%1, 5, 5, 3, v, pix1, pix2, stride, h +%endif movu m2, [pix2q] movu m1, [pix2q+strideq] +%ifidn %2, u + movu m0, [pix1q] + movu m3, [pix1q+strideq] + psadbw m2, m0 + psadbw m1, m3 +%else psadbw m2, [pix1q] psadbw m1, [pix1q+strideq] - paddw m2, m1 -%if %1 != mmsize - movu m0, [pix2q+8] - movu m1, [pix2q+strideq+8] - psadbw m0, [pix1q+8] - psadbw m1, [pix1q+strideq+8] - paddw m2, m0 - paddw m2, m1 %endif + paddw m2, m1 sub hd, 2 align 16 @@ -492,18 +401,17 @@ align 16 lea pix2q, [pix2q+strideq*2] movu m0, [pix2q] movu m1, [pix2q+strideq] +%ifidn %2, u + movu m3, [pix1q] + movu m4, [pix1q+strideq] + psadbw m0, m3 + psadbw m1, m4 +%else psadbw m0, [pix1q] psadbw m1, [pix1q+strideq] - paddw m2, m0 - paddw m2, m1 -%if %1 != mmsize - movu m0, [pix2q+8] - movu m1, [pix2q+strideq+8] - psadbw m0, [pix1q+8] - psadbw m1, [pix1q+strideq+8] - paddw m2, m0 - paddw m2, m1 %endif + paddw m2, m0 + paddw m2, m1 sub hd, 2 jg .loop %if mmsize == 16 @@ -516,12 +424,12 @@ align 16 INIT_MMX mmxext SAD 8 -SAD 16 INIT_XMM sse2 SAD 16 +SAD 16, u ;------------------------------------------------------------------------------------------ -;int ff_sad_x2_(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); +;int ff_sad_x2_(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); ;------------------------------------------------------------------------------------------ ;%1 = 8/16 %macro SAD_X2 1 @@ -540,16 +448,6 @@ cglobal sad%1_x2, 5, 5, 5, v, pix1, pix2, stride, h psadbw m0, [pix1q] psadbw m2, [pix1q+strideq] paddw m0, m2 -%if %1 != mmsize - movu m1, [pix2q+8] - movu m2, [pix2q+strideq+8] - pavgb m1, [pix2q+9] - pavgb m2, [pix2q+strideq+9] - psadbw m1, [pix1q+8] - psadbw m2, [pix1q+strideq+8] - paddw m0, m1 - paddw m0, m2 -%endif sub hd, 2 align 16 @@ -571,16 +469,6 @@ align 16 psadbw m2, [pix1q+strideq] paddw m0, m1 paddw m0, m2 -%if %1 != mmsize - movu m1, [pix2q+8] - movu m2, [pix2q+strideq+8] - pavgb m1, [pix2q+9] - pavgb m2, [pix2q+strideq+9] - psadbw m1, [pix1q+8] - psadbw m2, [pix1q+strideq+8] - paddw m0, m1 - paddw m0, m2 -%endif sub hd, 2 jg .loop %if mmsize == 16 @@ -593,12 +481,11 @@ align 16 INIT_MMX mmxext SAD_X2 8 -SAD_X2 16 INIT_XMM sse2 SAD_X2 16 ;------------------------------------------------------------------------------------------ -;int ff_sad_y2_(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); +;int ff_sad_y2_(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); ;------------------------------------------------------------------------------------------ ;%1 = 8/16 %macro SAD_Y2 1 @@ -612,18 +499,6 @@ cglobal sad%1_y2, 5, 5, 4, v, pix1, pix2, stride, h psadbw m0, [pix1q+strideq] paddw m0, m1 mova m1, m3 -%if %1 != mmsize - movu m4, [pix2q+8] - movu m5, [pix2q+strideq+8] - movu m6, [pix2q+2*strideq+8] - pavgb m4, m5 - pavgb m5, m6 - psadbw m4, [pix1q+8] - psadbw m5, [pix1q+strideq+8] - paddw m0, m4 - paddw m0, m5 - mova m4, m6 -%endif add pix2q, strideq sub hd, 2 @@ -640,17 +515,6 @@ align 16 paddw m0, m1 paddw m0, m2 mova m1, m3 -%if %1 != mmsize - movu m5, [pix2q+8] - movu m6, [pix2q+strideq+8] - pavgb m4, m5 - pavgb m5, m6 - psadbw m4, [pix1q+8] - psadbw m5, [pix1q+strideq+8] - paddw m0, m4 - paddw m0, m5 - mova m4, m6 -%endif sub hd, 2 jg .loop %if mmsize == 16 @@ -663,12 +527,107 @@ align 16 INIT_MMX mmxext SAD_Y2 8 -SAD_Y2 16 INIT_XMM sse2 SAD_Y2 16 +;------------------------------------------------------------------------------------------ +;int ff_sad_xy2_(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); +;------------------------------------------------------------------------------------------ + +;%1 = 8/16, %2 = aligned mov, %3 = unaligned mov +%macro SAD_XY2 3 +cglobal sad%1_xy2, 5, 5, mmsize == 16 ? 8 + ARCH_X86_64 : 7, v, pix1, pix2, stride, h + mov%3 m2, [pix2q] + mov%3 m3, [pix2q+1] +%if %1 == mmsize +%if ARCH_X86_64 + mova m8, [pw_2] + %define PW_2 m8 +%else + %define PW_2 [pw_2] +%endif +%else ; %1 != mmsize + mova m6, [pw_2] + %define PW_2 m6 +%endif + pxor m1, m1 + add pix2q, strideq +%if %1 != mmsize/2 + mova m6, m2 + mova m7, m3 + punpckhbw m6, m1 + punpckhbw m7, m1 + paddw m6, m7 +%endif + punpcklbw m2, m1 + punpcklbw m3, m1 + paddw m2, m3 + mova m0, m1 + +.loop: + mov%3 m3, [pix2q] + mov%3 m4, [pix2q+1] +%if %1 != mmsize/2 + mova m5, m3 + mova m7, m4 + punpckhbw m5, m1 + punpckhbw m7, m1 + paddw m7, m5 + paddw m7, PW_2 + paddw m6, m7 + psraw m6, 2 +%endif + mov%2 m5, [pix1q] + punpcklbw m3, m1 + punpcklbw m4, m1 + paddw m3, m4 + paddw m3, PW_2 + paddw m2, m3 + psraw m2, 2 + packuswb m2, m6 + psadbw m2, m5 + paddw m0, m2 + + mov%3 m2, [pix2q+strideq] + mov%3 m4, [pix2q+strideq+1] +%if %1 != mmsize/2 + mova m5, m2 + mova m6, m4 + punpckhbw m5, m1 + punpckhbw m6, m1 + paddw m6, m5 + paddw m7, m6 + psraw m7, 2 +%endif + mov%2 m5, [pix1q+strideq] + punpcklbw m2, m1 + punpcklbw m4, m1 + paddw m2, m4 + paddw m3, m2 + psraw m3, 2 + packuswb m3, m7 + psadbw m3, m5 + paddw m0, m3 + + sub hd, 2 + lea pix1q, [pix1q+2*strideq] + lea pix2q, [pix2q+2*strideq] + jnz .loop + +%if %1 == 16 + movhlps m1, m0 + paddw m0, m1 +%endif + movd eax, m0 + RET +%endmacro + +INIT_XMM sse2 +SAD_XY2 8, h, h +SAD_XY2 16, a, u + ;------------------------------------------------------------------------------------------- -;int ff_sad_approx_xy2_(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); +;int ff_sad_approx_xy2_(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); ;------------------------------------------------------------------------------------------- ;%1 = 8/16 %macro SAD_APPROX_XY2 1 @@ -696,22 +655,6 @@ cglobal sad%1_approx_xy2, 5, 5, 7, v, pix1, pix2, stride, h psadbw m0, [pix1q+strideq] paddw m0, m1 mova m1, m3 -%if %1 != mmsize - movu m5, [pix2q+8] - movu m6, [pix2q+strideq+8] - movu m7, [pix2q+2*strideq+8] - pavgb m5, [pix2q+1+8] - pavgb m6, [pix2q+strideq+1+8] - pavgb m7, [pix2q+2*strideq+1+8] - psubusb m6, m4 - pavgb m5, m6 - pavgb m6, m7 - psadbw m5, [pix1q+8] - psadbw m6, [pix1q+strideq+8] - paddw m0, m5 - paddw m0, m6 - mova m5, m7 -%endif add pix2q, strideq sub hd, 2 @@ -738,20 +681,6 @@ align 16 paddw m0, m1 paddw m0, m2 mova m1, m3 -%if %1 != mmsize - movu m6, [pix2q+8] - movu m7, [pix2q+strideq+8] - pavgb m6, [pix2q+8+1] - pavgb m7, [pix2q+strideq+8+1] - psubusb m6, m4 - pavgb m5, m6 - pavgb m6, m7 - psadbw m5, [pix1q+8] - psadbw m6, [pix1q+strideq+8] - paddw m0, m5 - paddw m0, m6 - mova m5, m7 -%endif sub hd, 2 jg .loop %if mmsize == 16 @@ -764,54 +693,33 @@ align 16 INIT_MMX mmxext SAD_APPROX_XY2 8 -SAD_APPROX_XY2 16 INIT_XMM sse2 SAD_APPROX_XY2 16 ;-------------------------------------------------------------------- -;int ff_vsad_intra(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +;int ff_vsad_intra(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ; ptrdiff_t line_size, int h); ;-------------------------------------------------------------------- -; %1 = 8/16 -%macro VSAD_INTRA 1 -cglobal vsad_intra%1, 5, 5, 3, v, pix1, pix2, lsize, h - mova m0, [pix1q] -%if %1 == mmsize - mova m2, [pix1q+lsizeq] - psadbw m0, m2 +; %1 = 8/16, %2 = a/u (whether pix1 is aligned or not) +%macro VSAD_INTRA 2 +%ifidn %2, u +cglobal vsad_intra%1u, 5, 5, 3, v, pix1, pix2, lsize, h %else - mova m2, [pix1q+lsizeq] - mova m3, [pix1q+8] - mova m4, [pix1q+lsizeq+8] - psadbw m0, m2 - psadbw m3, m4 - paddw m0, m3 +cglobal vsad_intra%1, 5, 5, 3, v, pix1, pix2, lsize, h %endif + mov%2 m0, [pix1q] + mov%2 m2, [pix1q+lsizeq] + psadbw m0, m2 sub hd, 2 .loop: lea pix1q, [pix1q + 2*lsizeq] -%if %1 == mmsize - mova m1, [pix1q] + mov%2 m1, [pix1q] psadbw m2, m1 paddw m0, m2 - mova m2, [pix1q+lsizeq] + mov%2 m2, [pix1q+lsizeq] psadbw m1, m2 paddw m0, m1 -%else - mova m1, [pix1q] - mova m3, [pix1q+8] - psadbw m2, m1 - psadbw m4, m3 - paddw m0, m2 - paddw m0, m4 - mova m2, [pix1q+lsizeq] - mova m4, [pix1q+lsizeq+8] - psadbw m1, m2 - psadbw m3, m4 - paddw m0, m1 - paddw m0, m3 -%endif sub hd, 2 jg .loop @@ -824,22 +732,25 @@ cglobal vsad_intra%1, 5, 5, 3, v, pix1, pix2, lsize, h %endmacro INIT_MMX mmxext -VSAD_INTRA 8 -VSAD_INTRA 16 +VSAD_INTRA 8, a INIT_XMM sse2 -VSAD_INTRA 16 +VSAD_INTRA 16, a +VSAD_INTRA 16, u ;--------------------------------------------------------------------- -;int ff_vsad_approx(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +;int ff_vsad_approx(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ; ptrdiff_t line_size, int h); ;--------------------------------------------------------------------- -; %1 = 8/16 -%macro VSAD_APPROX 1 -cglobal vsad%1_approx, 5, 5, 5, v, pix1, pix2, lsize, h +; %1 = 8/16, %2 = a/u (whether pix1 is aligned or not) +%macro VSAD_APPROX 2 +%ifidn %2, u +cglobal vsad%1u_approx, 5, 5, 5, v, pix1, pix2, lsize, h +%else +cglobal vsad%1_approx, 5, 5, 5, v, pix1, pix2, lsize, h +%endif mova m1, [pb_80] - mova m0, [pix1q] -%if %1 == mmsize ; vsad8_mmxext, vsad16_sse2 - mova m4, [pix1q+lsizeq] + mov%2 m0, [pix1q] + mov%2 m4, [pix1q+lsizeq] %if mmsize == 16 movu m3, [pix2q] movu m2, [pix2q+lsizeq] @@ -852,29 +763,12 @@ cglobal vsad%1_approx, 5, 5, 5, v, pix1, pix2, lsize, h pxor m0, m1 pxor m4, m1 psadbw m0, m4 -%else ; vsad16_mmxext - mova m3, [pix1q+8] - psubb m0, [pix2q] - psubb m3, [pix2q+8] - pxor m0, m1 - pxor m3, m1 - mova m4, [pix1q+lsizeq] - mova m5, [pix1q+lsizeq+8] - psubb m4, [pix2q+lsizeq] - psubb m5, [pix2q+lsizeq+8] - pxor m4, m1 - pxor m5, m1 - psadbw m0, m4 - psadbw m3, m5 - paddw m0, m3 -%endif sub hd, 2 .loop: lea pix1q, [pix1q + 2*lsizeq] lea pix2q, [pix2q + 2*lsizeq] - mova m2, [pix1q] -%if %1 == mmsize ; vsad8_mmxext, vsad16_sse2 + mov%2 m2, [pix1q] %if mmsize == 16 movu m3, [pix2q] psubb m2, m3 @@ -884,33 +778,12 @@ cglobal vsad%1_approx, 5, 5, 5, v, pix1, pix2, lsize, h pxor m2, m1 psadbw m4, m2 paddw m0, m4 - mova m4, [pix1q+lsizeq] + mov%2 m4, [pix1q+lsizeq] movu m3, [pix2q+lsizeq] psubb m4, m3 pxor m4, m1 psadbw m2, m4 paddw m0, m2 -%else ; vsad16_mmxext - mova m3, [pix1q+8] - psubb m2, [pix2q] - psubb m3, [pix2q+8] - pxor m2, m1 - pxor m3, m1 - psadbw m4, m2 - psadbw m5, m3 - paddw m0, m4 - paddw m0, m5 - mova m4, [pix1q+lsizeq] - mova m5, [pix1q+lsizeq+8] - psubb m4, [pix2q+lsizeq] - psubb m5, [pix2q+lsizeq+8] - pxor m4, m1 - pxor m5, m1 - psadbw m2, m4 - psadbw m3, m5 - paddw m0, m2 - paddw m0, m3 -%endif sub hd, 2 jg .loop @@ -923,7 +796,7 @@ cglobal vsad%1_approx, 5, 5, 5, v, pix1, pix2, lsize, h %endmacro INIT_MMX mmxext -VSAD_APPROX 8 -VSAD_APPROX 16 +VSAD_APPROX 8, a INIT_XMM sse2 -VSAD_APPROX 16 +VSAD_APPROX 16, a +VSAD_APPROX 16, u diff --git a/libavcodec/x86/me_cmp_init.c b/libavcodec/x86/me_cmp_init.c index 98b71b189..dbb4ef96b 100644 --- a/libavcodec/x86/me_cmp_init.c +++ b/libavcodec/x86/me_cmp_init.c @@ -24,287 +24,150 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" -#include "libavutil/mem_internal.h" -#include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" #include "libavcodec/me_cmp.h" -#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideoenc.h" int ff_sum_abs_dctelem_sse2(const int16_t *block); int ff_sum_abs_dctelem_ssse3(const int16_t *block); -int ff_sse8_mmx(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h); -int ff_sse16_mmx(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sse8_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sse16_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sse16_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_hf_noise8_mmx(const uint8_t *pix1, ptrdiff_t stride, int h); -int ff_hf_noise16_mmx(const uint8_t *pix1, ptrdiff_t stride, int h); -int ff_sad8_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_hf_noise8_ssse3(const uint8_t *pix1, ptrdiff_t stride, int h); +int ff_hf_noise16_ssse3(const uint8_t *pix1, ptrdiff_t stride, int h); +int ff_sad8_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h); -int ff_sad16_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad8_x2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16u_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad8_x2_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_x2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h); -int ff_sad16_x2_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_x2_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad8_y2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad8_y2_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_y2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h); -int ff_sad16_y2_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_y2_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad8_approx_xy2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad8_approx_xy2_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_approx_xy2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h); -int ff_sad16_approx_xy2_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h); -int ff_vsad_intra8_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h); -int ff_vsad_intra16_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h); -int ff_vsad_intra16_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h); -int ff_vsad8_approx_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h); -int ff_vsad16_approx_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad8_xy2_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_vsad16_approx_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_approx_xy2_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad16_xy2_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_vsad_intra8_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_vsad_intra16_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_vsad_intra16u_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_vsad8_approx_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_vsad16_approx_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); +int ff_vsad16u_approx_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, + ptrdiff_t stride, int h); -#define hadamard_func(cpu) \ - int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, const uint8_t *src1, \ +#define hadamard_func(cpu) \ + int ff_hadamard8_diff_ ## cpu(MPVEncContext *s, const uint8_t *src1, \ const uint8_t *src2, ptrdiff_t stride, int h); \ - int ff_hadamard8_diff16_ ## cpu(MpegEncContext *s, const uint8_t *src1, \ + int ff_hadamard8_diff16_ ## cpu(MPVEncContext *s, const uint8_t *src1, \ const uint8_t *src2, ptrdiff_t stride, int h); -hadamard_func(mmxext) hadamard_func(sse2) hadamard_func(ssse3) -#if HAVE_X86ASM -static int nsse16_mmx(MpegEncContext *c, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h) +static int nsse16_ssse3(MPVEncContext *c, const uint8_t *pix1, const uint8_t *pix2, + ptrdiff_t stride, int h) { - int score1, score2; + int score1 = ff_sse16_sse2(c, pix1, pix2, stride, h); + int score2 = ff_hf_noise16_ssse3(pix1, stride, h) - + ff_hf_noise16_ssse3(pix2, stride, h); if (c) - score1 = c->sse_cmp[0](c, pix1, pix2, stride, h); - else - score1 = ff_sse16_mmx(c, pix1, pix2, stride, h); - score2 = ff_hf_noise16_mmx(pix1, stride, h) + ff_hf_noise8_mmx(pix1+8, stride, h) - - ff_hf_noise16_mmx(pix2, stride, h) - ff_hf_noise8_mmx(pix2+8, stride, h); - - if (c) - return score1 + FFABS(score2) * c->avctx->nsse_weight; + return score1 + FFABS(score2) * c->c.avctx->nsse_weight; else return score1 + FFABS(score2) * 8; } -static int nsse8_mmx(MpegEncContext *c, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t stride, int h) +static int nsse8_ssse3(MPVEncContext *c, const uint8_t *pix1, const uint8_t *pix2, + ptrdiff_t stride, int h) { - int score1 = ff_sse8_mmx(c, pix1, pix2, stride, h); - int score2 = ff_hf_noise8_mmx(pix1, stride, h) - - ff_hf_noise8_mmx(pix2, stride, h); + int score1 = ff_sse8_sse2(c, pix1, pix2, stride, h); + int score2 = ff_hf_noise8_ssse3(pix1, stride, h) - + ff_hf_noise8_ssse3(pix2, stride, h); if (c) - return score1 + FFABS(score2) * c->avctx->nsse_weight; + return score1 + FFABS(score2) * c->c.avctx->nsse_weight; else return score1 + FFABS(score2) * 8; } -#endif /* HAVE_X86ASM */ - -#if HAVE_INLINE_ASM - -DECLARE_ASM_CONST(8, uint64_t, round_tab)[3] = { - 0x0000000000000000ULL, - 0x0001000100010001ULL, - 0x0002000200020002ULL, -}; - -static inline void sad8_4_mmx(const uint8_t *blk1, const uint8_t *blk2, - ptrdiff_t stride, int h) -{ - x86_reg len = -stride * h; - __asm__ volatile ( - "movq (%1, %%"FF_REG_a"), %%mm0\n\t" - "movq 1(%1, %%"FF_REG_a"), %%mm2\n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm2, %%mm3 \n\t" - "punpcklbw %%mm7, %%mm0 \n\t" - "punpckhbw %%mm7, %%mm1 \n\t" - "punpcklbw %%mm7, %%mm2 \n\t" - "punpckhbw %%mm7, %%mm3 \n\t" - "paddw %%mm2, %%mm0 \n\t" - "paddw %%mm3, %%mm1 \n\t" - ".p2align 4 \n\t" - "1: \n\t" - "movq (%2, %%"FF_REG_a"), %%mm2\n\t" - "movq 1(%2, %%"FF_REG_a"), %%mm4\n\t" - "movq %%mm2, %%mm3 \n\t" - "movq %%mm4, %%mm5 \n\t" - "punpcklbw %%mm7, %%mm2 \n\t" - "punpckhbw %%mm7, %%mm3 \n\t" - "punpcklbw %%mm7, %%mm4 \n\t" - "punpckhbw %%mm7, %%mm5 \n\t" - "paddw %%mm4, %%mm2 \n\t" - "paddw %%mm5, %%mm3 \n\t" - "movq %5, %%mm5 \n\t" - "paddw %%mm2, %%mm0 \n\t" - "paddw %%mm3, %%mm1 \n\t" - "paddw %%mm5, %%mm0 \n\t" - "paddw %%mm5, %%mm1 \n\t" - "movq (%3, %%"FF_REG_a"), %%mm4 \n\t" - "movq (%3, %%"FF_REG_a"), %%mm5 \n\t" - "psrlw $2, %%mm0 \n\t" - "psrlw $2, %%mm1 \n\t" - "packuswb %%mm1, %%mm0 \n\t" - "psubusb %%mm0, %%mm4 \n\t" - "psubusb %%mm5, %%mm0 \n\t" - "por %%mm4, %%mm0 \n\t" - "movq %%mm0, %%mm4 \n\t" - "punpcklbw %%mm7, %%mm0 \n\t" - "punpckhbw %%mm7, %%mm4 \n\t" - "paddw %%mm0, %%mm6 \n\t" - "paddw %%mm4, %%mm6 \n\t" - "movq %%mm2, %%mm0 \n\t" - "movq %%mm3, %%mm1 \n\t" - "add %4, %%"FF_REG_a" \n\t" - " js 1b \n\t" - : "+a" (len) - : "r" (blk1 - len), "r" (blk1 - len + stride), "r" (blk2 - len), - "r" (stride), "m" (round_tab[2])); -} - -static inline int sum_mmx(void) -{ - int ret; - __asm__ volatile ( - "movq %%mm6, %%mm0 \n\t" - "psrlq $32, %%mm6 \n\t" - "paddw %%mm0, %%mm6 \n\t" - "movq %%mm6, %%mm0 \n\t" - "psrlq $16, %%mm6 \n\t" - "paddw %%mm0, %%mm6 \n\t" - "movd %%mm6, %0 \n\t" - : "=r" (ret)); - return ret & 0xFFFF; -} - -#define PIX_SADXY(suf) \ -static int sad8_xy2_ ## suf(MpegEncContext *v, const uint8_t *blk2, \ - const uint8_t *blk1, ptrdiff_t stride, int h) \ -{ \ - __asm__ volatile ( \ - "pxor %%mm7, %%mm7 \n\t" \ - "pxor %%mm6, %%mm6 \n\t" \ - ::); \ - \ - sad8_4_ ## suf(blk1, blk2, stride, h); \ - \ - return sum_ ## suf(); \ -} \ - \ -static int sad16_xy2_ ## suf(MpegEncContext *v, const uint8_t *blk2, \ - const uint8_t *blk1, ptrdiff_t stride, int h) \ -{ \ - __asm__ volatile ( \ - "pxor %%mm7, %%mm7 \n\t" \ - "pxor %%mm6, %%mm6 \n\t" \ - ::); \ - \ - sad8_4_ ## suf(blk1, blk2, stride, h); \ - sad8_4_ ## suf(blk1 + 8, blk2 + 8, stride, h); \ - \ - return sum_ ## suf(); \ -} \ - -PIX_SADXY(mmx) - -#endif /* HAVE_INLINE_ASM */ - av_cold void ff_me_cmp_init_x86(MECmpContext *c, AVCodecContext *avctx) { int cpu_flags = av_get_cpu_flags(); -#if HAVE_INLINE_ASM - if (INLINE_MMX(cpu_flags)) { - c->pix_abs[0][3] = sad16_xy2_mmx; - c->pix_abs[1][3] = sad8_xy2_mmx; - } - -#endif /* HAVE_INLINE_ASM */ - - if (EXTERNAL_MMX(cpu_flags)) { - c->sse[1] = ff_sse8_mmx; -#if HAVE_X86ASM - c->nsse[0] = nsse16_mmx; - c->nsse[1] = nsse8_mmx; -#endif - } - if (EXTERNAL_MMXEXT(cpu_flags)) { -#if !HAVE_ALIGNED_STACK - c->hadamard8_diff[0] = ff_hadamard8_diff16_mmxext; - c->hadamard8_diff[1] = ff_hadamard8_diff_mmxext; -#endif - - c->sad[0] = ff_sad16_mmxext; c->sad[1] = ff_sad8_mmxext; - c->pix_abs[0][0] = ff_sad16_mmxext; - c->pix_abs[0][1] = ff_sad16_x2_mmxext; - c->pix_abs[0][2] = ff_sad16_y2_mmxext; c->pix_abs[1][0] = ff_sad8_mmxext; c->pix_abs[1][1] = ff_sad8_x2_mmxext; c->pix_abs[1][2] = ff_sad8_y2_mmxext; - c->vsad[4] = ff_vsad_intra16_mmxext; c->vsad[5] = ff_vsad_intra8_mmxext; if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { - c->pix_abs[0][3] = ff_sad16_approx_xy2_mmxext; c->pix_abs[1][3] = ff_sad8_approx_xy2_mmxext; - c->vsad[0] = ff_vsad16_approx_mmxext; c->vsad[1] = ff_vsad8_approx_mmxext; } } if (EXTERNAL_SSE2(cpu_flags)) { c->sse[0] = ff_sse16_sse2; + c->sse[1] = ff_sse8_sse2; c->sum_abs_dctelem = ff_sum_abs_dctelem_sse2; -#if HAVE_ALIGNED_STACK + c->pix_abs[0][0] = ff_sad16_sse2; + c->pix_abs[0][1] = ff_sad16_x2_sse2; + c->pix_abs[0][2] = ff_sad16_y2_sse2; + c->pix_abs[0][3] = ff_sad16_xy2_sse2; + c->hadamard8_diff[0] = ff_hadamard8_diff16_sse2; c->hadamard8_diff[1] = ff_hadamard8_diff_sse2; -#endif - if (!(cpu_flags & AV_CPU_FLAG_SSE2SLOW) && avctx->codec_id != AV_CODEC_ID_SNOW) { + if (avctx->codec_id != AV_CODEC_ID_SNOW) { c->sad[0] = ff_sad16_sse2; - c->pix_abs[0][0] = ff_sad16_sse2; - c->pix_abs[0][1] = ff_sad16_x2_sse2; - c->pix_abs[0][2] = ff_sad16_y2_sse2; c->vsad[4] = ff_vsad_intra16_sse2; if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { - c->pix_abs[0][3] = ff_sad16_approx_xy2_sse2; c->vsad[0] = ff_vsad16_approx_sse2; } + } else { + // Snow does not abide by the alignment requirements + // of blk1, so we use special versions without them for it. + c->sad[0] = ff_sad16u_sse2; + + c->vsad[4] = ff_vsad_intra16u_sse2; + if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { + c->vsad[0] = ff_vsad16u_approx_sse2; + } + } + if (avctx->flags & AV_CODEC_FLAG_BITEXACT) { + c->pix_abs[1][3] = ff_sad8_xy2_sse2; + } else { + c->pix_abs[0][3] = ff_sad16_approx_xy2_sse2; } } if (EXTERNAL_SSSE3(cpu_flags)) { + c->nsse[0] = nsse16_ssse3; + c->nsse[1] = nsse8_ssse3; + c->sum_abs_dctelem = ff_sum_abs_dctelem_ssse3; -#if HAVE_ALIGNED_STACK c->hadamard8_diff[0] = ff_hadamard8_diff16_ssse3; c->hadamard8_diff[1] = ff_hadamard8_diff_ssse3; -#endif } } diff --git a/libavcodec/x86/mlpdsp_init.c b/libavcodec/x86/mlpdsp_init.c index 950f99683..21a0e3814 100644 --- a/libavcodec/x86/mlpdsp_init.c +++ b/libavcodec/x86/mlpdsp_init.c @@ -200,8 +200,10 @@ av_cold void ff_mlpdsp_init_x86(MLPDSPContext *c) if (INLINE_MMX(cpu_flags)) c->mlp_filter_channel = mlp_filter_channel_x86; #endif - if (ARCH_X86_64 && EXTERNAL_SSE4(cpu_flags)) +#if ARCH_X86_64 + if (EXTERNAL_SSE4(cpu_flags)) c->mlp_rematrix_channel = ff_mlp_rematrix_channel_sse4; - if (ARCH_X86_64 && EXTERNAL_AVX2_FAST(cpu_flags) && cpu_flags & AV_CPU_FLAG_BMI2) + if (EXTERNAL_AVX2_FAST(cpu_flags) && cpu_flags & AV_CPU_FLAG_BMI2) c->mlp_rematrix_channel = ff_mlp_rematrix_channel_avx2_bmi2; +#endif // ARCH_X86_64 } diff --git a/libavcodec/x86/mpegvideo.c b/libavcodec/x86/mpegvideo.c index 9878607a8..7c137cf75 100644 --- a/libavcodec/x86/mpegvideo.c +++ b/libavcodec/x86/mpegvideo.c @@ -20,21 +20,26 @@ */ #include "libavutil/attributes.h" +#include "libavutil/avassert.h" #include "libavutil/cpu.h" #include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" -#include "libavcodec/avcodec.h" #include "libavcodec/mpegvideo.h" #include "libavcodec/mpegvideodata.h" +#include "libavcodec/mpegvideo_unquantize.h" -#if HAVE_MMX_INLINE +#if HAVE_SSE2_INLINE -static void dct_unquantize_h263_intra_mmx(MpegEncContext *s, - int16_t *block, int n, int qscale) +#define SPLATW(reg) "punpcklwd %%" #reg ", %%" #reg "\n\t" \ + "pshufd $0, %%" #reg ", %%" #reg "\n\t" + +#if HAVE_SSSE3_INLINE + +static void dct_unquantize_h263_intra_ssse3(const MPVContext *s, + int16_t *block, int n, int qscale) { - x86_reg level, qmul, qadd, nCoeffs; - - qmul = qscale << 1; + x86_reg qmul = (unsigned)qscale << 1; + int level, qadd; av_assert2(s->block_last_index[n]>=0 || s->h263_aic); @@ -48,125 +53,94 @@ static void dct_unquantize_h263_intra_mmx(MpegEncContext *s, qadd = 0; level= block[0]; } - if(s->ac_pred) - nCoeffs=63; - else - nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; + x86_reg offset = s->ac_pred ? 63 << 1 : s->intra_scantable.raster_end[s->block_last_index[n]] << 1; __asm__ volatile( - "movd %1, %%mm6 \n\t" //qmul - "packssdw %%mm6, %%mm6 \n\t" - "packssdw %%mm6, %%mm6 \n\t" - "movd %2, %%mm5 \n\t" //qadd - "pxor %%mm7, %%mm7 \n\t" - "packssdw %%mm5, %%mm5 \n\t" - "packssdw %%mm5, %%mm5 \n\t" - "psubw %%mm5, %%mm7 \n\t" - "pxor %%mm4, %%mm4 \n\t" - ".p2align 4 \n\t" - "1: \n\t" - "movq (%0, %3), %%mm0 \n\t" - "movq 8(%0, %3), %%mm1 \n\t" + "movd %k1, %%xmm0 \n\t" //qmul + "lea (%2, %0), %1 \n\t" + "neg %0 \n\t" + "movd %3, %%xmm1 \n\t" //qadd + SPLATW(xmm0) + SPLATW(xmm1) - "pmullw %%mm6, %%mm0 \n\t" - "pmullw %%mm6, %%mm1 \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movdqa (%1, %0), %%xmm2 \n\t" + "movdqa 16(%1, %0), %%xmm3 \n\t" - "movq (%0, %3), %%mm2 \n\t" - "movq 8(%0, %3), %%mm3 \n\t" + "movdqa %%xmm1, %%xmm4 \n\t" + "movdqa %%xmm1, %%xmm5 \n\t" - "pcmpgtw %%mm4, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 - "pcmpgtw %%mm4, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 + "psignw %%xmm2, %%xmm4 \n\t" // sgn(block[i])*qadd + "psignw %%xmm3, %%xmm5 \n\t" // sgn(block[i])*qadd - "pxor %%mm2, %%mm0 \n\t" - "pxor %%mm3, %%mm1 \n\t" + "pmullw %%xmm0, %%xmm2 \n\t" + "pmullw %%xmm0, %%xmm3 \n\t" - "paddw %%mm7, %%mm0 \n\t" - "paddw %%mm7, %%mm1 \n\t" + "paddw %%xmm4, %%xmm2 \n\t" + "paddw %%xmm5, %%xmm3 \n\t" - "pxor %%mm0, %%mm2 \n\t" - "pxor %%mm1, %%mm3 \n\t" + "movdqa %%xmm2, (%1, %0) \n\t" + "movdqa %%xmm3, 16(%1, %0) \n\t" - "pcmpeqw %%mm7, %%mm0 \n\t" // block[i] == 0 ? -1 : 0 - "pcmpeqw %%mm7, %%mm1 \n\t" // block[i] == 0 ? -1 : 0 - - "pandn %%mm2, %%mm0 \n\t" - "pandn %%mm3, %%mm1 \n\t" - - "movq %%mm0, (%0, %3) \n\t" - "movq %%mm1, 8(%0, %3) \n\t" - - "add $16, %3 \n\t" - "jng 1b \n\t" - ::"r" (block+nCoeffs), "rm"(qmul), "rm" (qadd), "r" (2*(-nCoeffs)) - : "memory" + "add $32, %0 \n\t" + "jng 1b \n\t" + : "+r"(offset), "+r"(qmul) + : "r" (block), "rm" (qadd) + : XMM_CLOBBERS("%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5",) "memory" ); block[0]= level; } -static void dct_unquantize_h263_inter_mmx(MpegEncContext *s, - int16_t *block, int n, int qscale) +static void dct_unquantize_h263_inter_ssse3(const MPVContext *s, + int16_t *block, int n, int qscale) { - x86_reg qmul, qadd, nCoeffs; - - qmul = qscale << 1; - qadd = (qscale - 1) | 1; + int qmul = qscale << 1; + int qadd = (qscale - 1) | 1; av_assert2(s->block_last_index[n]>=0 || s->h263_aic); - nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ]; + x86_reg offset = s->inter_scantable.raster_end[s->block_last_index[n]] << 1; __asm__ volatile( - "movd %1, %%mm6 \n\t" //qmul - "packssdw %%mm6, %%mm6 \n\t" - "packssdw %%mm6, %%mm6 \n\t" - "movd %2, %%mm5 \n\t" //qadd - "pxor %%mm7, %%mm7 \n\t" - "packssdw %%mm5, %%mm5 \n\t" - "packssdw %%mm5, %%mm5 \n\t" - "psubw %%mm5, %%mm7 \n\t" - "pxor %%mm4, %%mm4 \n\t" - ".p2align 4 \n\t" - "1: \n\t" - "movq (%0, %3), %%mm0 \n\t" - "movq 8(%0, %3), %%mm1 \n\t" + "movd %2, %%xmm0 \n\t" //qmul + "movd %3, %%xmm1 \n\t" //qadd + "add %1, %0 \n\t" + "neg %1 \n\t" + SPLATW(xmm0) + SPLATW(xmm1) - "pmullw %%mm6, %%mm0 \n\t" - "pmullw %%mm6, %%mm1 \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movdqa (%0, %1), %%xmm2 \n\t" + "movdqa 16(%0, %1), %%xmm3 \n\t" - "movq (%0, %3), %%mm2 \n\t" - "movq 8(%0, %3), %%mm3 \n\t" + "movdqa %%xmm1, %%xmm4 \n\t" + "movdqa %%xmm1, %%xmm5 \n\t" - "pcmpgtw %%mm4, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 - "pcmpgtw %%mm4, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 + "psignw %%xmm2, %%xmm4 \n\t" // sgn(block[i])*qadd + "psignw %%xmm3, %%xmm5 \n\t" // sgn(block[i])*qadd - "pxor %%mm2, %%mm0 \n\t" - "pxor %%mm3, %%mm1 \n\t" + "pmullw %%xmm0, %%xmm2 \n\t" + "pmullw %%xmm0, %%xmm3 \n\t" - "paddw %%mm7, %%mm0 \n\t" - "paddw %%mm7, %%mm1 \n\t" + "paddw %%xmm4, %%xmm2 \n\t" + "paddw %%xmm5, %%xmm3 \n\t" - "pxor %%mm0, %%mm2 \n\t" - "pxor %%mm1, %%mm3 \n\t" + "movdqa %%xmm2, (%0, %1) \n\t" + "movdqa %%xmm3, 16(%0, %1) \n\t" - "pcmpeqw %%mm7, %%mm0 \n\t" // block[i] == 0 ? -1 : 0 - "pcmpeqw %%mm7, %%mm1 \n\t" // block[i] == 0 ? -1 : 0 - - "pandn %%mm2, %%mm0 \n\t" - "pandn %%mm3, %%mm1 \n\t" - - "movq %%mm0, (%0, %3) \n\t" - "movq %%mm1, 8(%0, %3) \n\t" - - "add $16, %3 \n\t" - "jng 1b \n\t" - ::"r" (block+nCoeffs), "rm"(qmul), "rm" (qadd), "r" (2*(-nCoeffs)) - : "memory" + "add $32, %1 \n\t" + "jng 1b \n\t" + : "+r" (block), "+r" (offset) + : "rm"(qmul), "rm" (qadd) + : XMM_CLOBBERS("%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5",) "memory" ); } -static void dct_unquantize_mpeg1_intra_mmx(MpegEncContext *s, - int16_t *block, int n, int qscale) +static void dct_unquantize_mpeg1_intra_ssse3(const MPVContext *s, + int16_t *block, int n, int qscale) { x86_reg nCoeffs; const uint16_t *quant_matrix; @@ -182,60 +156,47 @@ static void dct_unquantize_mpeg1_intra_mmx(MpegEncContext *s, block0 = block[0] * s->c_dc_scale; /* XXX: only MPEG-1 */ quant_matrix = s->intra_matrix; + x86_reg offset = -2 * nCoeffs; __asm__ volatile( - "pcmpeqw %%mm7, %%mm7 \n\t" - "psrlw $15, %%mm7 \n\t" - "movd %2, %%mm6 \n\t" - "packssdw %%mm6, %%mm6 \n\t" - "packssdw %%mm6, %%mm6 \n\t" - "mov %3, %%"FF_REG_a" \n\t" - ".p2align 4 \n\t" - "1: \n\t" - "movq (%0, %%"FF_REG_a"), %%mm0 \n\t" - "movq 8(%0, %%"FF_REG_a"), %%mm1\n\t" - "movq (%1, %%"FF_REG_a"), %%mm4 \n\t" - "movq 8(%1, %%"FF_REG_a"), %%mm5\n\t" - "pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i] - "pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i] - "pxor %%mm2, %%mm2 \n\t" - "pxor %%mm3, %%mm3 \n\t" - "pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 - "pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 - "pxor %%mm2, %%mm0 \n\t" - "pxor %%mm3, %%mm1 \n\t" - "psubw %%mm2, %%mm0 \n\t" // abs(block[i]) - "psubw %%mm3, %%mm1 \n\t" // abs(block[i]) - "pmullw %%mm4, %%mm0 \n\t" // abs(block[i])*q - "pmullw %%mm5, %%mm1 \n\t" // abs(block[i])*q - "pxor %%mm4, %%mm4 \n\t" - "pxor %%mm5, %%mm5 \n\t" // FIXME slow - "pcmpeqw (%0, %%"FF_REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0 - "pcmpeqw 8(%0, %%"FF_REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0 - "psraw $3, %%mm0 \n\t" - "psraw $3, %%mm1 \n\t" - "psubw %%mm7, %%mm0 \n\t" - "psubw %%mm7, %%mm1 \n\t" - "por %%mm7, %%mm0 \n\t" - "por %%mm7, %%mm1 \n\t" - "pxor %%mm2, %%mm0 \n\t" - "pxor %%mm3, %%mm1 \n\t" - "psubw %%mm2, %%mm0 \n\t" - "psubw %%mm3, %%mm1 \n\t" - "pandn %%mm0, %%mm4 \n\t" - "pandn %%mm1, %%mm5 \n\t" - "movq %%mm4, (%0, %%"FF_REG_a") \n\t" - "movq %%mm5, 8(%0, %%"FF_REG_a")\n\t" + "movd %3, %%xmm6 \n\t" + "pcmpeqw %%xmm7, %%xmm7 \n\t" + "psrlw $15, %%xmm7 \n\t" + SPLATW(xmm6) + ".p2align 4 \n\t" + "1: \n\t" + "movdqa (%2, %0), %%xmm4 \n\t" + "movdqa 16(%2, %0), %%xmm5 \n\t" + "movdqa (%1, %0), %%xmm0 \n\t" + "movdqa 16(%1, %0), %%xmm1 \n\t" + "pmullw %%xmm6, %%xmm4 \n\t" // q=qscale*quant_matrix[i] + "pmullw %%xmm6, %%xmm5 \n\t" // q=qscale*quant_matrix[i] + "pabsw %%xmm0, %%xmm2 \n\t" // abs(block[i]) + "pabsw %%xmm1, %%xmm3 \n\t" // abs(block[i]) + "pmullw %%xmm4, %%xmm2 \n\t" // abs(block[i])*q + "pmullw %%xmm5, %%xmm3 \n\t" // abs(block[i])*q + "psraw $3, %%xmm2 \n\t" + "psraw $3, %%xmm3 \n\t" + "psubw %%xmm7, %%xmm2 \n\t" + "psubw %%xmm7, %%xmm3 \n\t" + "por %%xmm7, %%xmm2 \n\t" + "por %%xmm7, %%xmm3 \n\t" + "psignw %%xmm0, %%xmm2 \n\t" + "psignw %%xmm1, %%xmm3 \n\t" + "movdqa %%xmm2, (%1, %0) \n\t" + "movdqa %%xmm3, 16(%1, %0) \n\t" - "add $16, %%"FF_REG_a" \n\t" - "js 1b \n\t" - ::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "g" (-2*nCoeffs) - : "%"FF_REG_a, "memory" + "add $32, %0 \n\t" + "js 1b \n\t" + : "+r" (offset) + : "r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale) + : XMM_CLOBBERS("%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",) + "memory" ); block[0]= block0; } -static void dct_unquantize_mpeg1_inter_mmx(MpegEncContext *s, - int16_t *block, int n, int qscale) +static void dct_unquantize_mpeg1_inter_ssse3(const MPVContext *s, + int16_t *block, int n, int qscale) { x86_reg nCoeffs; const uint16_t *quant_matrix; @@ -245,63 +206,52 @@ static void dct_unquantize_mpeg1_inter_mmx(MpegEncContext *s, nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]+1; quant_matrix = s->inter_matrix; + x86_reg offset = -2 * nCoeffs; __asm__ volatile( - "pcmpeqw %%mm7, %%mm7 \n\t" - "psrlw $15, %%mm7 \n\t" - "movd %2, %%mm6 \n\t" - "packssdw %%mm6, %%mm6 \n\t" - "packssdw %%mm6, %%mm6 \n\t" - "mov %3, %%"FF_REG_a" \n\t" - ".p2align 4 \n\t" - "1: \n\t" - "movq (%0, %%"FF_REG_a"), %%mm0 \n\t" - "movq 8(%0, %%"FF_REG_a"), %%mm1\n\t" - "movq (%1, %%"FF_REG_a"), %%mm4 \n\t" - "movq 8(%1, %%"FF_REG_a"), %%mm5\n\t" - "pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i] - "pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i] - "pxor %%mm2, %%mm2 \n\t" - "pxor %%mm3, %%mm3 \n\t" - "pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 - "pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 - "pxor %%mm2, %%mm0 \n\t" - "pxor %%mm3, %%mm1 \n\t" - "psubw %%mm2, %%mm0 \n\t" // abs(block[i]) - "psubw %%mm3, %%mm1 \n\t" // abs(block[i]) - "paddw %%mm0, %%mm0 \n\t" // abs(block[i])*2 - "paddw %%mm1, %%mm1 \n\t" // abs(block[i])*2 - "paddw %%mm7, %%mm0 \n\t" // abs(block[i])*2 + 1 - "paddw %%mm7, %%mm1 \n\t" // abs(block[i])*2 + 1 - "pmullw %%mm4, %%mm0 \n\t" // (abs(block[i])*2 + 1)*q - "pmullw %%mm5, %%mm1 \n\t" // (abs(block[i])*2 + 1)*q - "pxor %%mm4, %%mm4 \n\t" - "pxor %%mm5, %%mm5 \n\t" // FIXME slow - "pcmpeqw (%0, %%"FF_REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0 - "pcmpeqw 8(%0, %%"FF_REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0 - "psraw $4, %%mm0 \n\t" - "psraw $4, %%mm1 \n\t" - "psubw %%mm7, %%mm0 \n\t" - "psubw %%mm7, %%mm1 \n\t" - "por %%mm7, %%mm0 \n\t" - "por %%mm7, %%mm1 \n\t" - "pxor %%mm2, %%mm0 \n\t" - "pxor %%mm3, %%mm1 \n\t" - "psubw %%mm2, %%mm0 \n\t" - "psubw %%mm3, %%mm1 \n\t" - "pandn %%mm0, %%mm4 \n\t" - "pandn %%mm1, %%mm5 \n\t" - "movq %%mm4, (%0, %%"FF_REG_a") \n\t" - "movq %%mm5, 8(%0, %%"FF_REG_a")\n\t" + "movd %3, %%xmm6 \n\t" + "pcmpeqw %%xmm7, %%xmm7 \n\t" + "psrlw $15, %%xmm7 \n\t" + SPLATW(xmm6) + ".p2align 4 \n\t" + "1: \n\t" + "movdqa (%2, %0), %%xmm4 \n\t" + "movdqa 16(%2, %0), %%xmm5 \n\t" + "movdqa (%1, %0), %%xmm0 \n\t" + "movdqa 16(%1, %0), %%xmm1 \n\t" + "pmullw %%xmm6, %%xmm4 \n\t" // q=qscale*quant_matrix[i] + "pmullw %%xmm6, %%xmm5 \n\t" // q=qscale*quant_matrix[i] + "pabsw %%xmm0, %%xmm2 \n\t" // abs(block[i]) + "pabsw %%xmm1, %%xmm3 \n\t" // abs(block[i]) + "paddw %%xmm2, %%xmm2 \n\t" // abs(block[i])*2 + "paddw %%xmm3, %%xmm3 \n\t" // abs(block[i])*2 + "paddw %%xmm7, %%xmm2 \n\t" // abs(block[i])*2 + 1 + "paddw %%xmm7, %%xmm3 \n\t" // abs(block[i])*2 + 1 + "pmullw %%xmm4, %%xmm2 \n\t" // (abs(block[i])*2 + 1)*q + "pmullw %%xmm5, %%xmm3 \n\t" // (abs(block[i])*2 + 1)*q + "psraw $4, %%xmm2 \n\t" + "psraw $4, %%xmm3 \n\t" + "psubw %%xmm7, %%xmm2 \n\t" + "psubw %%xmm7, %%xmm3 \n\t" + "por %%xmm7, %%xmm2 \n\t" + "por %%xmm7, %%xmm3 \n\t" + "psignw %%xmm0, %%xmm2 \n\t" + "psignw %%xmm1, %%xmm3 \n\t" + "movdqa %%xmm2, (%1, %0) \n\t" + "movdqa %%xmm3, 16(%1, %0) \n\t" - "add $16, %%"FF_REG_a" \n\t" - "js 1b \n\t" - ::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "g" (-2*nCoeffs) - : "%"FF_REG_a, "memory" + "add $32, %0 \n\t" + "js 1b \n\t" + : "+r" (offset) + : "r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale) + : XMM_CLOBBERS("%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",) + "memory" ); } -static void dct_unquantize_mpeg2_intra_mmx(MpegEncContext *s, - int16_t *block, int n, int qscale) +#endif /* HAVE_SSSE3_INLINE */ + +static void dct_unquantize_mpeg2_intra_sse2(const MPVContext *s, + int16_t *block, int n, int qscale) { x86_reg nCoeffs; const uint16_t *quant_matrix; @@ -319,149 +269,127 @@ static void dct_unquantize_mpeg2_intra_mmx(MpegEncContext *s, else block0 = block[0] * s->c_dc_scale; quant_matrix = s->intra_matrix; + x86_reg offset = -2 * nCoeffs; __asm__ volatile( - "pcmpeqw %%mm7, %%mm7 \n\t" - "psrlw $15, %%mm7 \n\t" - "movd %2, %%mm6 \n\t" - "packssdw %%mm6, %%mm6 \n\t" - "packssdw %%mm6, %%mm6 \n\t" - "mov %3, %%"FF_REG_a" \n\t" - ".p2align 4 \n\t" - "1: \n\t" - "movq (%0, %%"FF_REG_a"), %%mm0 \n\t" - "movq 8(%0, %%"FF_REG_a"), %%mm1\n\t" - "movq (%1, %%"FF_REG_a"), %%mm4 \n\t" - "movq 8(%1, %%"FF_REG_a"), %%mm5\n\t" - "pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i] - "pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i] - "pxor %%mm2, %%mm2 \n\t" - "pxor %%mm3, %%mm3 \n\t" - "pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 - "pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 - "pxor %%mm2, %%mm0 \n\t" - "pxor %%mm3, %%mm1 \n\t" - "psubw %%mm2, %%mm0 \n\t" // abs(block[i]) - "psubw %%mm3, %%mm1 \n\t" // abs(block[i]) - "pmullw %%mm4, %%mm0 \n\t" // abs(block[i])*q - "pmullw %%mm5, %%mm1 \n\t" // abs(block[i])*q - "pxor %%mm4, %%mm4 \n\t" - "pxor %%mm5, %%mm5 \n\t" // FIXME slow - "pcmpeqw (%0, %%"FF_REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0 - "pcmpeqw 8(%0, %%"FF_REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0 - "psraw $4, %%mm0 \n\t" - "psraw $4, %%mm1 \n\t" - "pxor %%mm2, %%mm0 \n\t" - "pxor %%mm3, %%mm1 \n\t" - "psubw %%mm2, %%mm0 \n\t" - "psubw %%mm3, %%mm1 \n\t" - "pandn %%mm0, %%mm4 \n\t" - "pandn %%mm1, %%mm5 \n\t" - "movq %%mm4, (%0, %%"FF_REG_a") \n\t" - "movq %%mm5, 8(%0, %%"FF_REG_a")\n\t" + "movd %3, %%xmm6 \n\t" + SPLATW(xmm6) + ".p2align 4 \n\t" + "1: \n\t" + "movdqa (%1, %0), %%xmm0 \n\t" + "movdqa 16(%1, %0), %%xmm1 \n\t" + "movdqa (%2, %0), %%xmm4 \n\t" + "movdqa 16(%2, %0), %%xmm5 \n\t" + "pmullw %%xmm6, %%xmm4 \n\t" // q=qscale*quant_matrix[i] + "pmullw %%xmm6, %%xmm5 \n\t" // q=qscale*quant_matrix[i] + "movdqa %%xmm0, %%xmm2 \n\t" + "movdqa %%xmm1, %%xmm3 \n\t" + "psrlw $12, %%xmm2 \n\t" // block[i] < 0 ? 0xf : 0 + "psrlw $12, %%xmm3 \n\t" // (block[i] is in the -2048..2047 range) + "pmullw %%xmm4, %%xmm0 \n\t" // block[i]*q + "pmullw %%xmm5, %%xmm1 \n\t" // block[i]*q + "paddw %%xmm2, %%xmm0 \n\t" // bias negative block[i] + "paddw %%xmm3, %%xmm1 \n\t" // so that a right-shift + "psraw $4, %%xmm0 \n\t" // is equivalent to divide + "psraw $4, %%xmm1 \n\t" // with rounding towards zero + "movdqa %%xmm0, (%1, %0) \n\t" + "movdqa %%xmm1, 16(%1, %0) \n\t" - "add $16, %%"FF_REG_a" \n\t" - "jng 1b \n\t" - ::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "g" (-2*nCoeffs) - : "%"FF_REG_a, "memory" + "add $32, %0 \n\t" + "jng 1b \n\t" + : "+r" (offset) + : "r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale) + : XMM_CLOBBERS("%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6",) + "memory" ); block[0]= block0; //Note, we do not do mismatch control for intra as errors cannot accumulate } -static void dct_unquantize_mpeg2_inter_mmx(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - x86_reg nCoeffs; - const uint16_t *quant_matrix; +#if HAVE_SSSE3_INLINE +static void dct_unquantize_mpeg2_inter_ssse3(const MPVContext *s, + int16_t *block, int n, int qscale) +{ av_assert2(s->block_last_index[n]>=0); - if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; - else qscale <<= 1; + x86_reg qscale2 = s->q_scale_type ? ff_mpeg2_non_linear_qscale[qscale] : (unsigned)qscale << 1; + x86_reg offset = s->intra_scantable.raster_end[s->block_last_index[n]] << 1; + const void *quant_matrix = (const char*)s->inter_matrix + offset; - nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; - quant_matrix = s->inter_matrix; __asm__ volatile( - "pcmpeqw %%mm7, %%mm7 \n\t" - "psrlq $48, %%mm7 \n\t" - "movd %2, %%mm6 \n\t" - "packssdw %%mm6, %%mm6 \n\t" - "packssdw %%mm6, %%mm6 \n\t" - "mov %3, %%"FF_REG_a" \n\t" - ".p2align 4 \n\t" - "1: \n\t" - "movq (%0, %%"FF_REG_a"), %%mm0 \n\t" - "movq 8(%0, %%"FF_REG_a"), %%mm1\n\t" - "movq (%1, %%"FF_REG_a"), %%mm4 \n\t" - "movq 8(%1, %%"FF_REG_a"), %%mm5\n\t" - "pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i] - "pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i] - "pxor %%mm2, %%mm2 \n\t" - "pxor %%mm3, %%mm3 \n\t" - "pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 - "pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 - "pxor %%mm2, %%mm0 \n\t" - "pxor %%mm3, %%mm1 \n\t" - "psubw %%mm2, %%mm0 \n\t" // abs(block[i]) - "psubw %%mm3, %%mm1 \n\t" // abs(block[i]) - "paddw %%mm0, %%mm0 \n\t" // abs(block[i])*2 - "paddw %%mm1, %%mm1 \n\t" // abs(block[i])*2 - "pmullw %%mm4, %%mm0 \n\t" // abs(block[i])*2*q - "pmullw %%mm5, %%mm1 \n\t" // abs(block[i])*2*q - "paddw %%mm4, %%mm0 \n\t" // (abs(block[i])*2 + 1)*q - "paddw %%mm5, %%mm1 \n\t" // (abs(block[i])*2 + 1)*q - "pxor %%mm4, %%mm4 \n\t" - "pxor %%mm5, %%mm5 \n\t" // FIXME slow - "pcmpeqw (%0, %%"FF_REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0 - "pcmpeqw 8(%0, %%"FF_REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0 - "psrlw $5, %%mm0 \n\t" - "psrlw $5, %%mm1 \n\t" - "pxor %%mm2, %%mm0 \n\t" - "pxor %%mm3, %%mm1 \n\t" - "psubw %%mm2, %%mm0 \n\t" - "psubw %%mm3, %%mm1 \n\t" - "pandn %%mm0, %%mm4 \n\t" - "pandn %%mm1, %%mm5 \n\t" - "pxor %%mm4, %%mm7 \n\t" - "pxor %%mm5, %%mm7 \n\t" - "movq %%mm4, (%0, %%"FF_REG_a") \n\t" - "movq %%mm5, 8(%0, %%"FF_REG_a")\n\t" + "movd %k1, %%xmm6 \n\t" + "lea (%2, %0), %1 \n\t" + "neg %0 \n\t" + SPLATW(xmm6) + "pcmpeqw %%xmm7, %%xmm7 \n\t" + "psrldq $14, %%xmm7 \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movdqa (%3, %0), %%xmm4 \n\t" + "movdqa 16(%3, %0), %%xmm5 \n\t" + "movdqa (%1, %0), %%xmm0 \n\t" + "movdqa 16(%1, %0), %%xmm1 \n\t" + "pmullw %%xmm6, %%xmm4 \n\t" // q=qscale*quant_matrix[i] + "pmullw %%xmm6, %%xmm5 \n\t" // q=qscale*quant_matrix[i] + "pabsw %%xmm0, %%xmm2 \n\t" // abs(block[i]) + "pabsw %%xmm1, %%xmm3 \n\t" // abs(block[i]) + "paddw %%xmm2, %%xmm2 \n\t" // abs(block[i])*2 + "paddw %%xmm3, %%xmm3 \n\t" // abs(block[i])*2 + "pmullw %%xmm4, %%xmm2 \n\t" // abs(block[i])*2*q + "pmullw %%xmm5, %%xmm3 \n\t" // abs(block[i])*2*q + "paddw %%xmm4, %%xmm2 \n\t" // (abs(block[i])*2 + 1)*q + "paddw %%xmm5, %%xmm3 \n\t" // (abs(block[i])*2 + 1)*q + "psrlw $5, %%xmm2 \n\t" + "psrlw $5, %%xmm3 \n\t" + "psignw %%xmm0, %%xmm2 \n\t" + "psignw %%xmm1, %%xmm3 \n\t" + "movdqa %%xmm2, (%1, %0) \n\t" + "movdqa %%xmm3, 16(%1, %0) \n\t" + "pxor %%xmm2, %%xmm7 \n\t" + "pxor %%xmm3, %%xmm7 \n\t" - "add $16, %%"FF_REG_a" \n\t" - "jng 1b \n\t" - "movd 124(%0, %3), %%mm0 \n\t" - "movq %%mm7, %%mm6 \n\t" - "psrlq $32, %%mm7 \n\t" - "pxor %%mm6, %%mm7 \n\t" - "movq %%mm7, %%mm6 \n\t" - "psrlq $16, %%mm7 \n\t" - "pxor %%mm6, %%mm7 \n\t" - "pslld $31, %%mm7 \n\t" - "psrlq $15, %%mm7 \n\t" - "pxor %%mm7, %%mm0 \n\t" - "movd %%mm0, 124(%0, %3) \n\t" + "add $32, %0 \n\t" + "jng 1b \n\t" + "movd 124(%2), %%xmm0 \n\t" + "movhlps %%xmm7, %%xmm6 \n\t" + "pxor %%xmm6, %%xmm7 \n\t" + "pshufd $1, %%xmm7, %%xmm6 \n\t" + "pxor %%xmm6, %%xmm7 \n\t" + "pshuflw $1, %%xmm7, %%xmm6 \n\t" + "pxor %%xmm6, %%xmm7 \n\t" + "pslld $31, %%xmm7 \n\t" + "psrld $15, %%xmm7 \n\t" + "pxor %%xmm7, %%xmm0 \n\t" + "movd %%xmm0, 124(%2) \n\t" - ::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "r" (-2*nCoeffs) - : "%"FF_REG_a, "memory" + : "+r"(offset), "+r" (qscale2) + : "r" (block), "r"(quant_matrix) + : XMM_CLOBBERS("%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",) + "memory" ); } -#endif /* HAVE_MMX_INLINE */ +#endif /* HAVE_SSSE3_INLINE */ +#endif /* HAVE_SSE2_INLINE */ -av_cold void ff_mpv_common_init_x86(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_x86(MPVUnquantDSPContext *s, int bitexact) { -#if HAVE_MMX_INLINE +#if HAVE_SSE2_INLINE int cpu_flags = av_get_cpu_flags(); - if (INLINE_MMX(cpu_flags)) { - s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_mmx; - s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_mmx; - s->dct_unquantize_mpeg1_intra = dct_unquantize_mpeg1_intra_mmx; - s->dct_unquantize_mpeg1_inter = dct_unquantize_mpeg1_inter_mmx; - if (!(s->avctx->flags & AV_CODEC_FLAG_BITEXACT)) - s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_mmx; - s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_mmx; + if (INLINE_SSE2(cpu_flags)) { + if (!bitexact) + s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_sse2; } -#endif /* HAVE_MMX_INLINE */ +#if HAVE_SSSE3_INLINE + if (INLINE_SSSE3(cpu_flags)) { + s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_ssse3; + s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_ssse3; + s->dct_unquantize_mpeg1_intra = dct_unquantize_mpeg1_intra_ssse3; + s->dct_unquantize_mpeg1_inter = dct_unquantize_mpeg1_inter_ssse3; + s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_ssse3; + } +#endif /* HAVE_SSSE3_INLINE */ +#endif /* HAVE_SSE2_INLINE */ } diff --git a/libavcodec/x86/mpegvideoenc.c b/libavcodec/x86/mpegvideoenc.c index 612e7ff75..24dd04920 100644 --- a/libavcodec/x86/mpegvideoenc.c +++ b/libavcodec/x86/mpegvideoenc.c @@ -25,7 +25,6 @@ #include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" #include "libavcodec/avcodec.h" -#include "libavcodec/dct.h" #include "libavcodec/mpegvideoenc.h" /* not permutated inverse zigzag_direct + 1 for MMX quantizer */ @@ -40,110 +39,31 @@ DECLARE_ALIGNED(16, static const uint16_t, inv_zigzag_direct16)[64] = { 36, 37, 49, 50, 58, 59, 63, 64, }; -#if HAVE_6REGS - #if HAVE_SSE2_INLINE -#undef COMPILE_TEMPLATE_SSE2 -#undef COMPILE_TEMPLATE_SSSE3 -#define COMPILE_TEMPLATE_SSE2 1 #define COMPILE_TEMPLATE_SSSE3 0 -#undef RENAME -#undef RENAME_FDCT #define RENAME(a) a ## _sse2 -#define RENAME_FDCT(a) a ## _sse2 #include "mpegvideoenc_template.c" #endif /* HAVE_SSE2_INLINE */ #if HAVE_SSSE3_INLINE -#undef COMPILE_TEMPLATE_SSE2 #undef COMPILE_TEMPLATE_SSSE3 -#define COMPILE_TEMPLATE_SSE2 1 #define COMPILE_TEMPLATE_SSSE3 1 #undef RENAME -#undef RENAME_FDCT #define RENAME(a) a ## _ssse3 -#define RENAME_FDCT(a) a ## _sse2 #include "mpegvideoenc_template.c" #endif /* HAVE_SSSE3_INLINE */ -#endif /* HAVE_6REGS */ - -#if HAVE_INLINE_ASM -#if HAVE_SSE2_INLINE -static void denoise_dct_sse2(MpegEncContext *s, int16_t *block){ - const int intra= s->mb_intra; - int *sum= s->dct_error_sum[intra]; - uint16_t *offset= s->dct_offset[intra]; - - s->dct_count[intra]++; - - __asm__ volatile( - "pxor %%xmm7, %%xmm7 \n\t" - "1: \n\t" - "pxor %%xmm0, %%xmm0 \n\t" - "pxor %%xmm1, %%xmm1 \n\t" - "movdqa (%0), %%xmm2 \n\t" - "movdqa 16(%0), %%xmm3 \n\t" - "pcmpgtw %%xmm2, %%xmm0 \n\t" - "pcmpgtw %%xmm3, %%xmm1 \n\t" - "pxor %%xmm0, %%xmm2 \n\t" - "pxor %%xmm1, %%xmm3 \n\t" - "psubw %%xmm0, %%xmm2 \n\t" - "psubw %%xmm1, %%xmm3 \n\t" - "movdqa %%xmm2, %%xmm4 \n\t" - "movdqa %%xmm3, %%xmm5 \n\t" - "psubusw (%2), %%xmm2 \n\t" - "psubusw 16(%2), %%xmm3 \n\t" - "pxor %%xmm0, %%xmm2 \n\t" - "pxor %%xmm1, %%xmm3 \n\t" - "psubw %%xmm0, %%xmm2 \n\t" - "psubw %%xmm1, %%xmm3 \n\t" - "movdqa %%xmm2, (%0) \n\t" - "movdqa %%xmm3, 16(%0) \n\t" - "movdqa %%xmm4, %%xmm6 \n\t" - "movdqa %%xmm5, %%xmm0 \n\t" - "punpcklwd %%xmm7, %%xmm4 \n\t" - "punpckhwd %%xmm7, %%xmm6 \n\t" - "punpcklwd %%xmm7, %%xmm5 \n\t" - "punpckhwd %%xmm7, %%xmm0 \n\t" - "paddd (%1), %%xmm4 \n\t" - "paddd 16(%1), %%xmm6 \n\t" - "paddd 32(%1), %%xmm5 \n\t" - "paddd 48(%1), %%xmm0 \n\t" - "movdqa %%xmm4, (%1) \n\t" - "movdqa %%xmm6, 16(%1) \n\t" - "movdqa %%xmm5, 32(%1) \n\t" - "movdqa %%xmm0, 48(%1) \n\t" - "add $32, %0 \n\t" - "add $64, %1 \n\t" - "add $32, %2 \n\t" - "cmp %3, %0 \n\t" - " jb 1b \n\t" - : "+r" (block), "+r" (sum), "+r" (offset) - : "r"(block+64) - XMM_CLOBBERS_ONLY("%xmm0", "%xmm1", "%xmm2", "%xmm3", - "%xmm4", "%xmm5", "%xmm6", "%xmm7") - ); -} -#endif /* HAVE_SSE2_INLINE */ -#endif /* HAVE_INLINE_ASM */ - -av_cold void ff_dct_encode_init_x86(MpegEncContext *s) +av_cold void ff_dct_encode_init_x86(MPVEncContext *const s) { - const int dct_algo = s->avctx->dct_algo; + const int dct_algo = s->c.avctx->dct_algo; if (dct_algo == FF_DCT_AUTO || dct_algo == FF_DCT_MMX) { -#if HAVE_MMX_INLINE - int cpu_flags = av_get_cpu_flags(); #if HAVE_SSE2_INLINE + int cpu_flags = av_get_cpu_flags(); if (INLINE_SSE2(cpu_flags)) { -#if HAVE_6REGS s->dct_quantize = dct_quantize_sse2; -#endif - s->denoise_dct = denoise_dct_sse2; } -#endif -#if HAVE_6REGS && HAVE_SSSE3_INLINE +#if HAVE_SSSE3_INLINE if (INLINE_SSSE3(cpu_flags)) s->dct_quantize = dct_quantize_ssse3; #endif diff --git a/libavcodec/x86/mpegvideoenc_qns_template.c b/libavcodec/x86/mpegvideoenc_qns_template.c deleted file mode 100644 index 0d6454f45..000000000 --- a/libavcodec/x86/mpegvideoenc_qns_template.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * QNS functions are compiled 3 times for MMX/3DNOW/SSSE3 - * Copyright (c) 2004 Michael Niedermayer - * - * MMX optimization by Michael Niedermayer - * 3DNow! and SSSE3 optimization by Zuxy Meng - * - * 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 "libavutil/avassert.h" -#include "libavutil/common.h" -#include "libavutil/x86/asm.h" - -#include "inline_asm.h" - -#define MAX_ABS (512 >> (SCALE_OFFSET>0 ? SCALE_OFFSET : 0)) - -static int DEF(try_8x8basis)(const int16_t rem[64], const int16_t weight[64], const int16_t basis[64], int scale) -{ - x86_reg i=0; - - av_assert2(FFABS(scale) < MAX_ABS); - scale<<= 16 + SCALE_OFFSET - BASIS_SHIFT + RECON_SHIFT; - - SET_RND(mm6); - __asm__ volatile( - "pxor %%mm7, %%mm7 \n\t" - "movd %4, %%mm5 \n\t" - "punpcklwd %%mm5, %%mm5 \n\t" - "punpcklwd %%mm5, %%mm5 \n\t" - ".p2align 4 \n\t" - "1: \n\t" - "movq (%1, %0), %%mm0 \n\t" - "movq 8(%1, %0), %%mm1 \n\t" - PMULHRW(%%mm0, %%mm1, %%mm5, %%mm6) - "paddw (%2, %0), %%mm0 \n\t" - "paddw 8(%2, %0), %%mm1 \n\t" - "psraw $6, %%mm0 \n\t" - "psraw $6, %%mm1 \n\t" - "pmullw (%3, %0), %%mm0 \n\t" - "pmullw 8(%3, %0), %%mm1 \n\t" - "pmaddwd %%mm0, %%mm0 \n\t" - "pmaddwd %%mm1, %%mm1 \n\t" - "paddd %%mm1, %%mm0 \n\t" - "psrld $4, %%mm0 \n\t" - "paddd %%mm0, %%mm7 \n\t" - "add $16, %0 \n\t" - "cmp $128, %0 \n\t" //FIXME optimize & bench - " jb 1b \n\t" - PHADDD(%%mm7, %%mm6) - "psrld $2, %%mm7 \n\t" - "movd %%mm7, %0 \n\t" - - : "+r" (i) - : "r"(basis), "r"(rem), "r"(weight), "g"(scale) - ); - return i; -} - -static void DEF(add_8x8basis)(int16_t rem[64], const int16_t basis[64], int scale) -{ - x86_reg i=0; - - if(FFABS(scale) < MAX_ABS){ - scale<<= 16 + SCALE_OFFSET - BASIS_SHIFT + RECON_SHIFT; - SET_RND(mm6); - __asm__ volatile( - "movd %3, %%mm5 \n\t" - "punpcklwd %%mm5, %%mm5 \n\t" - "punpcklwd %%mm5, %%mm5 \n\t" - ".p2align 4 \n\t" - "1: \n\t" - "movq (%1, %0), %%mm0 \n\t" - "movq 8(%1, %0), %%mm1 \n\t" - PMULHRW(%%mm0, %%mm1, %%mm5, %%mm6) - "paddw (%2, %0), %%mm0 \n\t" - "paddw 8(%2, %0), %%mm1 \n\t" - "movq %%mm0, (%2, %0) \n\t" - "movq %%mm1, 8(%2, %0) \n\t" - "add $16, %0 \n\t" - "cmp $128, %0 \n\t" // FIXME optimize & bench - " jb 1b \n\t" - - : "+r" (i) - : "r"(basis), "r"(rem), "g"(scale) - ); - }else{ - for(i=0; i<8*8; i++){ - rem[i] += (basis[i]*scale + (1<<(BASIS_SHIFT - RECON_SHIFT-1)))>>(BASIS_SHIFT - RECON_SHIFT); - } - } -} diff --git a/libavcodec/x86/mpegvideoenc_template.c b/libavcodec/x86/mpegvideoenc_template.c index 4096d6391..e6ce79134 100644 --- a/libavcodec/x86/mpegvideoenc_template.c +++ b/libavcodec/x86/mpegvideoenc_template.c @@ -25,53 +25,27 @@ #include "libavutil/internal.h" #include "libavutil/mem_internal.h" #include "libavutil/x86/asm.h" +#include "libavcodec/mathops.h" #include "libavcodec/mpegutils.h" -#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideoenc.h" #include "fdct.h" -#undef MMREG_WIDTH -#undef MM -#undef MOVQ #undef SPREADW #undef PMAXW #undef PMAX #undef SAVE_SIGN #undef RESTORE_SIGN -#if COMPILE_TEMPLATE_SSE2 -#define MMREG_WIDTH "16" -#define MM "%%xmm" -#define MOVQ "movdqa" #define SPREADW(a) \ "pshuflw $0, "a", "a" \n\t"\ "punpcklwd "a", "a" \n\t" -#define PMAXW(a,b) "pmaxsw "a", "b" \n\t" #define PMAX(a,b) \ "movhlps "a", "b" \n\t"\ - PMAXW(b, a)\ + "pmaxsw "b", "a" \n\t"\ "pshuflw $0x0E, "a", "b" \n\t"\ - PMAXW(b, a)\ + "pmaxsw "b", "a" \n\t"\ "pshuflw $0x01, "a", "b" \n\t"\ - PMAXW(b, a) -#else -#define MMREG_WIDTH "8" -#define MM "%%mm" -#define MOVQ "movq" -#define SPREADW(a) \ - "punpcklwd "a", "a" \n\t"\ - "punpcklwd "a", "a" \n\t" -#define PMAXW(a,b) \ - "psubusw "a", "b" \n\t"\ - "paddw "a", "b" \n\t" -#define PMAX(a,b) \ - "movq "a", "b" \n\t"\ - "psrlq $32, "a" \n\t"\ - PMAXW(b, a)\ - "movq "a", "b" \n\t"\ - "psrlq $16, "a" \n\t"\ - PMAXW(b, a) - -#endif + "pmaxsw "b", "a" \n\t" #if COMPILE_TEMPLATE_SSSE3 #define SAVE_SIGN(a,b) \ @@ -90,34 +64,35 @@ "psubw "a", "b" \n\t" // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) #endif -static int RENAME(dct_quantize)(MpegEncContext *s, +static int RENAME(dct_quantize)(MPVEncContext *const s, int16_t *block, int n, int qscale, int *overflow) { x86_reg last_non_zero_p1; int level=0, q; //=0 is because gcc says uninitialized ... - const uint16_t *qmat, *bias; + const uint16_t *qmat; LOCAL_ALIGNED_16(int16_t, temp_block, [64]); //s->fdct (block); - RENAME_FDCT(ff_fdct)(block); // cannot be anything else ... + ff_fdct_sse2(block); // cannot be anything else ... - if(s->dct_error_sum) - s->denoise_dct(s, block); + if (s->dct_error_sum) { + const int intra = s->c.mb_intra; + s->dct_count[intra]++; + s->mpvencdsp.denoise_dct(block, s->dct_error_sum[intra], s->dct_offset[intra]); + } - if (s->mb_intra) { + if (s->c.mb_intra) { int dummy; if (n < 4){ - q = s->y_dc_scale; - bias = s->q_intra_matrix16[qscale][1]; + q = s->c.y_dc_scale; qmat = s->q_intra_matrix16[qscale][0]; }else{ - q = s->c_dc_scale; - bias = s->q_chroma_intra_matrix16[qscale][1]; + q = s->c.c_dc_scale; qmat = s->q_chroma_intra_matrix16[qscale][0]; } /* note: block[0] is assumed to be positive */ - if (!s->h263_aic) { + if (!s->c.h263_aic) { __asm__ volatile ( "mul %%ecx \n\t" : "=d" (level), "=a"(dummy) @@ -132,99 +107,94 @@ static int RENAME(dct_quantize)(MpegEncContext *s, last_non_zero_p1 = 1; } else { last_non_zero_p1 = 0; - bias = s->q_inter_matrix16[qscale][1]; qmat = s->q_inter_matrix16[qscale][0]; } - if((s->out_format == FMT_H263 || s->out_format == FMT_H261) && s->mpeg_quant==0){ - + if ((s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) && !s->mpeg_quant) { __asm__ volatile( - "movd %%"FF_REG_a", "MM"3 \n\t" // last_non_zero_p1 - SPREADW(MM"3") - "pxor "MM"7, "MM"7 \n\t" // 0 - "pxor "MM"4, "MM"4 \n\t" // 0 - MOVQ" (%2), "MM"5 \n\t" // qmat[0] - "pxor "MM"6, "MM"6 \n\t" - "psubw (%3), "MM"6 \n\t" // -bias[0] + "movd %%"FF_REG_a", %%xmm3 \n\t" // last_non_zero_p1 + SPREADW("%%xmm3") + "pxor %%xmm2, %%xmm2 \n\t" // 0 + "pxor %%xmm4, %%xmm4 \n\t" // 0 + "movdqa (%2), %%xmm5 \n\t" // qmat[0] + "pxor %%xmm6, %%xmm6 \n\t" + "psubw 128(%2), %%xmm6 \n\t" // -bias[0] "mov $-128, %%"FF_REG_a" \n\t" ".p2align 4 \n\t" "1: \n\t" - MOVQ" (%1, %%"FF_REG_a"), "MM"0 \n\t" // block[i] - SAVE_SIGN(MM"1", MM"0") // ABS(block[i]) - "psubusw "MM"6, "MM"0 \n\t" // ABS(block[i]) + bias[0] - "pmulhw "MM"5, "MM"0 \n\t" // (ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16 - "por "MM"0, "MM"4 \n\t" - RESTORE_SIGN(MM"1", MM"0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) - MOVQ" "MM"0, (%5, %%"FF_REG_a") \n\t" - "pcmpeqw "MM"7, "MM"0 \n\t" // out==0 ? 0xFF : 0x00 - MOVQ" (%4, %%"FF_REG_a"), "MM"1 \n\t" - MOVQ" "MM"7, (%1, %%"FF_REG_a") \n\t" // 0 - "pandn "MM"1, "MM"0 \n\t" - PMAXW(MM"0", MM"3") - "add $"MMREG_WIDTH", %%"FF_REG_a" \n\t" + "movdqa (%1, %%"FF_REG_a"), %%xmm0 \n\t" // block[i] + SAVE_SIGN("%%xmm1", "%%xmm0") // ABS(block[i]) + "psubusw %%xmm6, %%xmm0 \n\t" // ABS(block[i]) + bias[0] + "pmulhw %%xmm5, %%xmm0 \n\t" // (ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16 + "por %%xmm0, %%xmm4 \n\t" + RESTORE_SIGN("%%xmm1", "%%xmm0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) + "movdqa %%xmm0, (%4, %0) \n\t" + "pcmpeqw %%xmm2, %%xmm0 \n\t" // out==0 ? 0xFF : 0x00 + "movdqa (%3, %0), %%xmm1 \n\t" + "movdqa %%xmm2, (%1, %%"FF_REG_a") \n\t" // 0 + "pandn %%xmm1, %%xmm0 \n\t" + "pmaxsw %%xmm0, %%xmm3 \n\t" + "add $16, %%"FF_REG_a" \n\t" " js 1b \n\t" - PMAX(MM"3", MM"0") - "movd "MM"3, %%"FF_REG_a" \n\t" + PMAX("%%xmm3", "%%xmm0") + "movd %%xmm3, %%"FF_REG_a" \n\t" "movzbl %%al, %%eax \n\t" // last_non_zero_p1 : "+a" (last_non_zero_p1) - : "r" (block+64), "r" (qmat), "r" (bias), + : "r" (block+64), "r" (qmat), "r" (inv_zigzag_direct16 + 64), "r" (temp_block + 64) XMM_CLOBBERS_ONLY("%xmm0", "%xmm1", "%xmm2", "%xmm3", - "%xmm4", "%xmm5", "%xmm6", "%xmm7") + "%xmm4", "%xmm5", "%xmm6") ); }else{ // FMT_H263 __asm__ volatile( - "movd %%"FF_REG_a", "MM"3 \n\t" // last_non_zero_p1 - SPREADW(MM"3") - "pxor "MM"7, "MM"7 \n\t" // 0 - "pxor "MM"4, "MM"4 \n\t" // 0 + "movd %%"FF_REG_a", %%xmm3 \n\t" // last_non_zero_p1 + SPREADW("%%xmm3") + "pxor %%xmm2, %%xmm2 \n\t" // 0 + "pxor %%xmm4, %%xmm4 \n\t" // 0 "mov $-128, %%"FF_REG_a" \n\t" ".p2align 4 \n\t" "1: \n\t" - MOVQ" (%1, %%"FF_REG_a"), "MM"0 \n\t" // block[i] - SAVE_SIGN(MM"1", MM"0") // ABS(block[i]) - MOVQ" (%3, %%"FF_REG_a"), "MM"6 \n\t" // bias[0] - "paddusw "MM"6, "MM"0 \n\t" // ABS(block[i]) + bias[0] - MOVQ" (%2, %%"FF_REG_a"), "MM"5 \n\t" // qmat[i] - "pmulhw "MM"5, "MM"0 \n\t" // (ABS(block[i])*qmat[0] + bias[0]*qmat[0])>>16 - "por "MM"0, "MM"4 \n\t" - RESTORE_SIGN(MM"1", MM"0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) - MOVQ" "MM"0, (%5, %%"FF_REG_a") \n\t" - "pcmpeqw "MM"7, "MM"0 \n\t" // out==0 ? 0xFF : 0x00 - MOVQ" (%4, %%"FF_REG_a"), "MM"1 \n\t" - MOVQ" "MM"7, (%1, %%"FF_REG_a") \n\t" // 0 - "pandn "MM"1, "MM"0 \n\t" - PMAXW(MM"0", MM"3") - "add $"MMREG_WIDTH", %%"FF_REG_a" \n\t" + "movdqa (%1, %%"FF_REG_a"), %%xmm0 \n\t" // block[i] + SAVE_SIGN("%%xmm1", "%%xmm0") // ABS(block[i]) + "movdqa 128(%2, %0), %%xmm6 \n\t" // bias[i] + "paddusw %%xmm6, %%xmm0 \n\t" // ABS(block[i]) + bias[0] + "movdqa (%2, %%"FF_REG_a"), %%xmm5 \n\t" // qmat[i] + "pmulhw %%xmm5, %%xmm0 \n\t" // (ABS(block[i])*qmat[0] + bias[0]*qmat[0])>>16 + "por %%xmm0, %%xmm4 \n\t" + RESTORE_SIGN("%%xmm1", "%%xmm0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) + "movdqa %%xmm0, (%4, %0) \n\t" + "pcmpeqw %%xmm2, %%xmm0 \n\t" // out==0 ? 0xFF : 0x00 + "movdqa (%3, %0), %%xmm1 \n\t" + "movdqa %%xmm2, (%1, %%"FF_REG_a") \n\t" // 0 + "pandn %%xmm1, %%xmm0 \n\t" + "pmaxsw %%xmm0, %%xmm3 \n\t" + "add $16, %%"FF_REG_a" \n\t" " js 1b \n\t" - PMAX(MM"3", MM"0") - "movd "MM"3, %%"FF_REG_a" \n\t" + PMAX("%%xmm3", "%%xmm0") + "movd %%xmm3, %%"FF_REG_a" \n\t" "movzbl %%al, %%eax \n\t" // last_non_zero_p1 : "+a" (last_non_zero_p1) - : "r" (block+64), "r" (qmat+64), "r" (bias+64), + : "r" (block+64), "r" (qmat+64), "r" (inv_zigzag_direct16 + 64), "r" (temp_block + 64) XMM_CLOBBERS_ONLY("%xmm0", "%xmm1", "%xmm2", "%xmm3", - "%xmm4", "%xmm5", "%xmm6", "%xmm7") + "%xmm4", "%xmm5", "%xmm6") ); } __asm__ volatile( - "movd %1, "MM"1 \n\t" // max_qcoeff - SPREADW(MM"1") - "psubusw "MM"1, "MM"4 \n\t" - "packuswb "MM"4, "MM"4 \n\t" -#if COMPILE_TEMPLATE_SSE2 - "packsswb "MM"4, "MM"4 \n\t" -#endif - "movd "MM"4, %0 \n\t" // *overflow + "movd %1, %%xmm1 \n\t" // max_qcoeff + SPREADW("%%xmm1") + "psubusw %%xmm1, %%xmm4 \n\t" + "packuswb %%xmm4, %%xmm4 \n\t" + "packsswb %%xmm4, %%xmm4 \n\t" + "movd %%xmm4, %0 \n\t" // *overflow : "=g" (*overflow) : "g" (s->max_qcoeff) ); - if(s->mb_intra) block[0]= level; - else block[0]= temp_block[0]; + block[0] = s->c.mb_intra ? level : temp_block[0]; - av_assert2(ARCH_X86_32 || s->idsp.perm_type != FF_IDCT_PERM_SIMPLE); - if (ARCH_X86_32 && s->idsp.perm_type == FF_IDCT_PERM_SIMPLE) { + av_assert2(ARCH_X86_32 || s->c.idsp.perm_type != FF_IDCT_PERM_SIMPLE); + if (ARCH_X86_32 && s->c.idsp.perm_type == FF_IDCT_PERM_SIMPLE) { if(last_non_zero_p1 <= 1) goto end; block[0x08] = temp_block[0x01]; block[0x10] = temp_block[0x08]; block[0x20] = temp_block[0x10]; @@ -268,7 +238,7 @@ static int RENAME(dct_quantize)(MpegEncContext *s, block[0x3E] = temp_block[0x3D]; block[0x27] = temp_block[0x36]; block[0x3D] = temp_block[0x2F]; block[0x2F] = temp_block[0x37]; block[0x37] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; - }else if(s->idsp.perm_type == FF_IDCT_PERM_LIBMPEG2){ + } else if (s->c.idsp.perm_type == FF_IDCT_PERM_LIBMPEG2) { if(last_non_zero_p1 <= 1) goto end; block[0x04] = temp_block[0x01]; block[0x08] = temp_block[0x08]; block[0x10] = temp_block[0x10]; @@ -312,7 +282,7 @@ static int RENAME(dct_quantize)(MpegEncContext *s, block[0x3E] = temp_block[0x3D]; block[0x33] = temp_block[0x36]; block[0x2F] = temp_block[0x2F]; block[0x37] = temp_block[0x37]; block[0x3B] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; - } else if (s->idsp.perm_type == FF_IDCT_PERM_NONE) { + } else if (s->c.idsp.perm_type == FF_IDCT_PERM_NONE) { if(last_non_zero_p1 <= 1) goto end; block[0x01] = temp_block[0x01]; block[0x08] = temp_block[0x08]; block[0x10] = temp_block[0x10]; @@ -356,7 +326,7 @@ static int RENAME(dct_quantize)(MpegEncContext *s, block[0x3D] = temp_block[0x3D]; block[0x36] = temp_block[0x36]; block[0x2F] = temp_block[0x2F]; block[0x37] = temp_block[0x37]; block[0x3E] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; - } else if (s->idsp.perm_type == FF_IDCT_PERM_TRANSPOSE) { + } else if (s->c.idsp.perm_type == FF_IDCT_PERM_TRANSPOSE) { if(last_non_zero_p1 <= 1) goto end; block[0x08] = temp_block[0x01]; block[0x01] = temp_block[0x08]; block[0x02] = temp_block[0x10]; @@ -401,12 +371,12 @@ static int RENAME(dct_quantize)(MpegEncContext *s, block[0x3D] = temp_block[0x2F]; block[0x3E] = temp_block[0x37]; block[0x37] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; } else { - av_log(s, AV_LOG_DEBUG, "s->idsp.perm_type: %d\n", - (int)s->idsp.perm_type); - av_assert0(s->idsp.perm_type == FF_IDCT_PERM_NONE || - s->idsp.perm_type == FF_IDCT_PERM_LIBMPEG2 || - s->idsp.perm_type == FF_IDCT_PERM_SIMPLE || - s->idsp.perm_type == FF_IDCT_PERM_TRANSPOSE); + av_log(s->c.avctx, AV_LOG_DEBUG, "s->c.idsp.perm_type: %d\n", + (int)s->c.idsp.perm_type); + av_assert0(s->c.idsp.perm_type == FF_IDCT_PERM_NONE || + s->c.idsp.perm_type == FF_IDCT_PERM_LIBMPEG2 || + s->c.idsp.perm_type == FF_IDCT_PERM_SIMPLE || + s->c.idsp.perm_type == FF_IDCT_PERM_TRANSPOSE); } end: return last_non_zero_p1 - 1; diff --git a/libavcodec/x86/mpegvideoencdsp.asm b/libavcodec/x86/mpegvideoencdsp.asm index d12646ae5..300f98b43 100644 --- a/libavcodec/x86/mpegvideoencdsp.asm +++ b/libavcodec/x86/mpegvideoencdsp.asm @@ -24,6 +24,104 @@ %include "libavutil/x86/x86util.asm" SECTION .text + +; void ff_add_8x8basis_ssse3(int16_t rem[64], const int16_t basis[64], int scale) +INIT_XMM ssse3 +cglobal add_8x8basis, 3, 3+ARCH_X86_64, 4, rem, basis, scale + movd m0, scaled + add scaled, 1024 + add basisq, 128 + add remq, 128 +%if ARCH_X86_64 +%define OFF r3q + mov r3q, -128 + cmp scaled, 2047 +%else +%define OFF r2q + cmp scaled, 2047 + mov r2q, -128 +%endif + ja .huge_scale + + punpcklwd m0, m0 + pshufd m0, m0, 0x0 + psllw m0, 5 +.loop1: + mova m1, [basisq+OFF] + mova m2, [basisq+OFF+16] + pmulhrsw m1, m0 + pmulhrsw m2, m0 + paddw m1, [remq+OFF] + paddw m2, [remq+OFF+16] + mova [remq+OFF], m1 + mova [remq+OFF+16], m2 + add OFF, 32 + js .loop1 + RET + +.huge_scale: + pslld m0, 6 + punpcklwd m0, m0 + pshufd m1, m0, 0x55 + psrlw m0, 1 + pshufd m0, m0, 0x0 +.loop2: + mova m2, [basisq+OFF] + pmulhrsw m3, m2, m0 + pmullw m2, m1 + paddw m2, m3 + paddw m2, [remq+OFF] + mova [remq+OFF], m2 + add OFF, 16 + js .loop2 + RET + + +INIT_XMM sse2 +cglobal mpv_denoise_dct, 3, 4, 7, block, sum, offset + pxor m6, m6 + lea r3, [sumq+256] +.loop: + mova m2, [blockq] + mova m3, [blockq+16] + mova m0, m6 + mova m1, m6 + pcmpgtw m0, m2 + pcmpgtw m1, m3 + pxor m2, m0 + pxor m3, m1 + psubw m2, m0 + psubw m3, m1 + psubusw m4, m2, [offsetq] + psubusw m5, m3, [offsetq+16] + pxor m4, m0 + pxor m5, m1 + add offsetq, 32 + psubw m4, m0 + psubw m5, m1 + mova [blockq], m4 + mova [blockq+16], m5 + mova m0, m2 + mova m1, m3 + add blockq, 32 + punpcklwd m0, m6 + punpckhwd m2, m6 + punpcklwd m1, m6 + punpckhwd m3, m6 + paddd m0, [sumq] + paddd m2, [sumq+16] + paddd m1, [sumq+32] + paddd m3, [sumq+48] + mova [sumq], m0 + mova [sumq+16], m2 + mova [sumq+32], m1 + mova [sumq+48], m3 + add sumq, 64 + cmp sumq, r3 + jb .loop + RET + + ; int ff_pix_sum16(const uint8_t *pix, ptrdiff_t line_size) ; %1 = number of loops ; %2 = number of GPRs used diff --git a/libavcodec/x86/mpegvideoencdsp_init.c b/libavcodec/x86/mpegvideoencdsp_init.c index d39091a5c..1b6c75e9e 100644 --- a/libavcodec/x86/mpegvideoencdsp_init.c +++ b/libavcodec/x86/mpegvideoencdsp_init.c @@ -16,154 +16,129 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "libavutil/attributes.h" #include "libavutil/avassert.h" +#include "libavutil/common.h" #include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" #include "libavcodec/avcodec.h" #include "libavcodec/mpegvideoencdsp.h" +void ff_mpv_denoise_dct_sse2(int16_t block[64], int dct_error_sum[64], + const uint16_t dct_offset[64]); int ff_pix_sum16_sse2(const uint8_t *pix, ptrdiff_t line_size); int ff_pix_sum16_xop(const uint8_t *pix, ptrdiff_t line_size); int ff_pix_norm1_sse2(const uint8_t *pix, ptrdiff_t line_size); - -#if HAVE_INLINE_ASM - -#define PHADDD(a, t) \ - "movq " #a ", " #t " \n\t" \ - "psrlq $32, " #a " \n\t" \ - "paddd " #t ", " #a " \n\t" - -/* - * pmulhw: dst[0 - 15] = (src[0 - 15] * dst[0 - 15])[16 - 31] - * pmulhrw: dst[0 - 15] = (src[0 - 15] * dst[0 - 15] + 0x8000)[16 - 31] - * pmulhrsw: dst[0 - 15] = (src[0 - 15] * dst[0 - 15] + 0x4000)[15 - 30] - */ -#define PMULHRW(x, y, s, o) \ - "pmulhw " #s ", " #x " \n\t" \ - "pmulhw " #s ", " #y " \n\t" \ - "paddw " #o ", " #x " \n\t" \ - "paddw " #o ", " #y " \n\t" \ - "psraw $1, " #x " \n\t" \ - "psraw $1, " #y " \n\t" -#define DEF(x) x ## _mmx -#define SET_RND MOVQ_WONE -#define SCALE_OFFSET 1 - -#include "mpegvideoenc_qns_template.c" - -#undef DEF -#undef SET_RND -#undef SCALE_OFFSET -#undef PMULHRW - -#define DEF(x) x ## _3dnow -#define SET_RND(x) -#define SCALE_OFFSET 0 -#define PMULHRW(x, y, s, o) \ - "pmulhrw " #s ", " #x " \n\t" \ - "pmulhrw " #s ", " #y " \n\t" - -#include "mpegvideoenc_qns_template.c" - -#undef DEF -#undef SET_RND -#undef SCALE_OFFSET -#undef PMULHRW +void ff_add_8x8basis_ssse3(int16_t rem[64], const int16_t basis[64], int scale); #if HAVE_SSSE3_INLINE -#undef PHADDD -#define DEF(x) x ## _ssse3 -#define SET_RND(x) #define SCALE_OFFSET -1 -#define PHADDD(a, t) \ - "pshufw $0x0E, " #a ", " #t " \n\t" \ - /* faster than phaddd on core2 */ \ - "paddd " #t ", " #a " \n\t" +#define MAX_ABS 512 -#define PMULHRW(x, y, s, o) \ - "pmulhrsw " #s ", " #x " \n\t" \ - "pmulhrsw " #s ", " #y " \n\t" +static int try_8x8basis_ssse3(const int16_t rem[64], const int16_t weight[64], const int16_t basis[64], int scale) +{ + x86_reg i=0; -#include "mpegvideoenc_qns_template.c" + av_assert2(FFABS(scale) < MAX_ABS); + scale *= 1 << (16 + SCALE_OFFSET - BASIS_SHIFT + RECON_SHIFT); -#undef DEF -#undef SET_RND -#undef SCALE_OFFSET -#undef PMULHRW -#undef PHADDD -#endif /* HAVE_SSSE3_INLINE */ + __asm__ volatile( + "pxor %%xmm2, %%xmm2 \n\t" + "movd %4, %%xmm3 \n\t" + "punpcklwd %%xmm3, %%xmm3 \n\t" + "pshufd $0, %%xmm3, %%xmm3 \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movdqa (%1, %0), %%xmm0 \n\t" + "movdqa 16(%1, %0), %%xmm1 \n\t" + "pmulhrsw %%xmm3, %%xmm0 \n\t" + "pmulhrsw %%xmm3, %%xmm1 \n\t" + "paddw (%2, %0), %%xmm0 \n\t" + "paddw 16(%2, %0), %%xmm1 \n\t" + "psraw $6, %%xmm0 \n\t" + "psraw $6, %%xmm1 \n\t" + "pmullw (%3, %0), %%xmm0 \n\t" + "pmullw 16(%3, %0), %%xmm1 \n\t" + "pmaddwd %%xmm0, %%xmm0 \n\t" + "pmaddwd %%xmm1, %%xmm1 \n\t" + "paddd %%xmm1, %%xmm0 \n\t" + "psrld $4, %%xmm0 \n\t" + "paddd %%xmm0, %%xmm2 \n\t" + "add $32, %0 \n\t" + "cmp $128, %0 \n\t" //FIXME optimize & bench + " jb 1b \n\t" + "pshufd $0x0E, %%xmm2, %%xmm0 \n\t" + "paddd %%xmm0, %%xmm2 \n\t" + "pshufd $0x01, %%xmm2, %%xmm0 \n\t" + "paddd %%xmm0, %%xmm2 \n\t" + "psrld $2, %%xmm2 \n\t" + "movd %%xmm2, %0 \n\t" + : "+r" (i) + : "r"(basis), "r"(rem), "r"(weight), "g"(scale) + XMM_CLOBBERS_ONLY("%xmm0", "%xmm1", "%xmm2", "%xmm3") + ); + return i; +} /* Draw the edges of width 'w' of an image of size width, height */ -static void draw_edges_mmx(uint8_t *buf, ptrdiff_t wrap, int width, int height, - int w, int h, int sides) +static void draw_edges_ssse3(uint8_t *buf, ptrdiff_t wrap, int width, int height, + int w, int h, int sides) { - uint8_t *ptr, *last_line; + uint8_t *ptr = buf, *last_line; int i; + av_assert1(w == 16 || w == 8 || w == 4); + /* left and right */ - ptr = buf; - if (w == 8) { - __asm__ volatile ( - "1: \n\t" - "movd (%0), %%mm0 \n\t" - "punpcklbw %%mm0, %%mm0 \n\t" - "punpcklwd %%mm0, %%mm0 \n\t" - "punpckldq %%mm0, %%mm0 \n\t" - "movq %%mm0, -8(%0) \n\t" - "movq -8(%0, %2), %%mm1 \n\t" - "punpckhbw %%mm1, %%mm1 \n\t" - "punpckhwd %%mm1, %%mm1 \n\t" - "punpckhdq %%mm1, %%mm1 \n\t" - "movq %%mm1, (%0, %2) \n\t" - "add %1, %0 \n\t" - "cmp %3, %0 \n\t" - "jnz 1b \n\t" - : "+r" (ptr) - : "r" ((x86_reg) wrap), "r" ((x86_reg) width), - "r" (ptr + wrap * height)); - } else if (w == 16) { - __asm__ volatile ( - "1: \n\t" - "movd (%0), %%mm0 \n\t" - "punpcklbw %%mm0, %%mm0 \n\t" - "punpcklwd %%mm0, %%mm0 \n\t" - "punpckldq %%mm0, %%mm0 \n\t" - "movq %%mm0, -8(%0) \n\t" - "movq %%mm0, -16(%0) \n\t" - "movq -8(%0, %2), %%mm1 \n\t" - "punpckhbw %%mm1, %%mm1 \n\t" - "punpckhwd %%mm1, %%mm1 \n\t" - "punpckhdq %%mm1, %%mm1 \n\t" - "movq %%mm1, (%0, %2) \n\t" - "movq %%mm1, 8(%0, %2) \n\t" - "add %1, %0 \n\t" - "cmp %3, %0 \n\t" - "jnz 1b \n\t" - : "+r"(ptr) - : "r"((x86_reg)wrap), "r"((x86_reg)width), "r"(ptr + wrap * height) - ); - } else { - av_assert1(w == 4); - __asm__ volatile ( - "1: \n\t" - "movd (%0), %%mm0 \n\t" - "punpcklbw %%mm0, %%mm0 \n\t" - "punpcklwd %%mm0, %%mm0 \n\t" - "movd %%mm0, -4(%0) \n\t" - "movd -4(%0, %2), %%mm1 \n\t" - "punpcklbw %%mm1, %%mm1 \n\t" - "punpckhwd %%mm1, %%mm1 \n\t" - "punpckhdq %%mm1, %%mm1 \n\t" - "movd %%mm1, (%0, %2) \n\t" - "add %1, %0 \n\t" - "cmp %3, %0 \n\t" - "jnz 1b \n\t" - : "+r" (ptr) - : "r" ((x86_reg) wrap), "r" ((x86_reg) width), - "r" (ptr + wrap * height)); - } + __asm__ volatile ( + "pcmpeqw %%xmm3, %%xmm3 \n\t" + "pxor %%xmm2, %%xmm2 \n\t" + "psrlw $14, %%xmm3 \n\t" // pw_3 + "pshufb %%xmm2, %%xmm3 \n\t" // pb_3 + "cmp $8, %4 \n\t" + "jg 16f \n\t" + "jl 4f \n\t" + "8: \n\t" + "movd (%0), %%xmm0 \n\t" + "movd -4(%0, %2), %%xmm1 \n\t" + "pshufb %%xmm2, %%xmm0 \n\t" + "pshufb %%xmm3, %%xmm1 \n\t" + "movq %%xmm0, -8(%0) \n\t" + "movq %%xmm1, (%0, %2) \n\t" + "add %1, %0 \n\t" + "cmp %3, %0 \n\t" + "jnz 8b \n\t" + "jmp 1f \n\t" + "4: \n\t" + "movd (%0), %%xmm0 \n\t" + "movd -4(%0, %2), %%xmm1 \n\t" + "pshufb %%xmm2, %%xmm0 \n\t" + "pshufb %%xmm3, %%xmm1 \n\t" + "movd %%xmm0, -4(%0) \n\t" + "movd %%xmm1, (%0, %2) \n\t" + "add %1, %0 \n\t" + "cmp %3, %0 \n\t" + "jnz 4b \n\t" + "jmp 1f \n\t" + "16: \n\t" + "movd (%0), %%xmm0 \n\t" + "movd -4(%0, %2), %%xmm1 \n\t" + "pshufb %%xmm2, %%xmm0 \n\t" + "pshufb %%xmm3, %%xmm1 \n\t" + "movdqu %%xmm0, -16(%0) \n\t" + "movdqu %%xmm1, (%0, %2) \n\t" + "add %1, %0 \n\t" + "cmp %3, %0 \n\t" + "jnz 16b \n\t" + "1: \n\t" + : "+r" (ptr) + : "r" ((x86_reg) wrap), "r" ((x86_reg) width), "r"(ptr + wrap * height), "r" (w) + XMM_CLOBBERS_ONLY("%xmm0", "%xmm1", "%xmm2", "%xmm3") + ); /* top and bottom + corners */ buf -= w; @@ -177,8 +152,7 @@ static void draw_edges_mmx(uint8_t *buf, ptrdiff_t wrap, int width, int height, // bottom memcpy(last_line + (i + 1) * wrap, last_line, width + w + w); } - -#endif /* HAVE_INLINE_ASM */ +#endif /* HAVE_SSSE3_INLINE */ av_cold void ff_mpegvideoencdsp_init_x86(MpegvideoEncDSPContext *c, AVCodecContext *avctx) @@ -186,6 +160,7 @@ av_cold void ff_mpegvideoencdsp_init_x86(MpegvideoEncDSPContext *c, int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE2(cpu_flags)) { + c->denoise_dct = ff_mpv_denoise_dct_sse2; c->pix_sum = ff_pix_sum16_sse2; c->pix_norm1 = ff_pix_norm1_sse2; } @@ -194,34 +169,18 @@ av_cold void ff_mpegvideoencdsp_init_x86(MpegvideoEncDSPContext *c, c->pix_sum = ff_pix_sum16_xop; } -#if HAVE_INLINE_ASM - - if (INLINE_MMX(cpu_flags)) { - if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { - c->try_8x8basis = try_8x8basis_mmx; - } - c->add_8x8basis = add_8x8basis_mmx; - - if (avctx->bits_per_raw_sample <= 8) { - c->draw_edges = draw_edges_mmx; - } - } - - if (INLINE_AMD3DNOW(cpu_flags)) { - if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { - c->try_8x8basis = try_8x8basis_3dnow; - } - c->add_8x8basis = add_8x8basis_3dnow; - } - + if (X86_SSSE3(cpu_flags)) { #if HAVE_SSSE3_INLINE - if (INLINE_SSSE3(cpu_flags)) { if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { c->try_8x8basis = try_8x8basis_ssse3; } - c->add_8x8basis = add_8x8basis_ssse3; - } + if (avctx->bits_per_raw_sample <= 8) { + c->draw_edges = draw_edges_ssse3; + } #endif /* HAVE_SSSE3_INLINE */ +#if HAVE_SSSE3_EXTERNAL + c->add_8x8basis = ff_add_8x8basis_ssse3; +#endif + } -#endif /* HAVE_INLINE_ASM */ } diff --git a/libavcodec/x86/pixblockdsp_init.c b/libavcodec/x86/pixblockdsp_init.c index 51f2a0033..650a0eb4f 100644 --- a/libavcodec/x86/pixblockdsp_init.c +++ b/libavcodec/x86/pixblockdsp_init.c @@ -23,12 +23,11 @@ #include "libavutil/x86/cpu.h" #include "libavcodec/pixblockdsp.h" -void ff_get_pixels_sse2(int16_t *block, const uint8_t *pixels, ptrdiff_t stride); -void ff_diff_pixels_sse2(int16_t *block, const uint8_t *s1, const uint8_t *s2, +void ff_get_pixels_sse2(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t stride); +void ff_diff_pixels_sse2(int16_t *restrict block, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride); av_cold void ff_pixblockdsp_init_x86(PixblockDSPContext *c, - AVCodecContext *avctx, unsigned high_bit_depth) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/x86/pngdsp.asm b/libavcodec/x86/pngdsp.asm index 10a1fd648..8ff49565d 100644 --- a/libavcodec/x86/pngdsp.asm +++ b/libavcodec/x86/pngdsp.asm @@ -77,8 +77,8 @@ cglobal add_bytes_l2, 4, 6, 2, dst, src1, src2, wa, w, i jl .loop_s RET -%macro ADD_PAETH_PRED_FN 1 -cglobal add_png_paeth_prediction, 5, 7, %1, dst, src, top, w, bpp, end, cntr +INIT_MMX ssse3 +cglobal png_add_paeth_prediction, 5, 7, 0, dst, src, top, w, bpp, end, cntr %if ARCH_X86_64 movsxd bppq, bppd movsxd wq, wd @@ -109,21 +109,9 @@ cglobal add_png_paeth_prediction, 5, 7, %1, dst, src, top, w, bpp, end, cntr psubw m4, m0 mova m5, m3 paddw m5, m4 -%if cpuflag(ssse3) pabsw m3, m3 pabsw m4, m4 pabsw m5, m5 -%else ; !cpuflag(ssse3) - psubw m7, m5 - pmaxsw m5, m7 - pxor m6, m6 - pxor m7, m7 - psubw m6, m3 - psubw m7, m4 - pmaxsw m3, m6 - pmaxsw m4, m7 - pxor m7, m7 -%endif ; cpuflag(ssse3) mova m6, m4 pminsw m6, m5 pcmpgtw m3, m6 @@ -153,10 +141,3 @@ cglobal add_png_paeth_prediction, 5, 7, %1, dst, src, top, w, bpp, end, cntr POP dstq emms RET -%endmacro - -INIT_MMX mmxext -ADD_PAETH_PRED_FN 0 - -INIT_MMX ssse3 -ADD_PAETH_PRED_FN 0 diff --git a/libavcodec/x86/pngdsp_init.c b/libavcodec/x86/pngdsp_init.c index e2cd5effe..5121140dc 100644 --- a/libavcodec/x86/pngdsp_init.c +++ b/libavcodec/x86/pngdsp_init.c @@ -24,21 +24,17 @@ #include "libavutil/x86/cpu.h" #include "libavcodec/pngdsp.h" -void ff_add_png_paeth_prediction_mmxext(uint8_t *dst, uint8_t *src, - uint8_t *top, int w, int bpp); -void ff_add_png_paeth_prediction_ssse3(uint8_t *dst, uint8_t *src, - uint8_t *top, int w, int bpp); -void ff_add_bytes_l2_sse2(uint8_t *dst, uint8_t *src1, - uint8_t *src2, int w); +void ff_png_add_paeth_prediction_ssse3(uint8_t *dst, const uint8_t *src, + const uint8_t *top, int w, int bpp); +void ff_add_bytes_l2_sse2(uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, int w); av_cold void ff_pngdsp_init_x86(PNGDSPContext *dsp) { int cpu_flags = av_get_cpu_flags(); - if (EXTERNAL_MMXEXT(cpu_flags)) - dsp->add_paeth_prediction = ff_add_png_paeth_prediction_mmxext; if (EXTERNAL_SSE2(cpu_flags)) dsp->add_bytes_l2 = ff_add_bytes_l2_sse2; if (EXTERNAL_SSSE3(cpu_flags)) - dsp->add_paeth_prediction = ff_add_png_paeth_prediction_ssse3; + dsp->add_paeth_prediction = ff_png_add_paeth_prediction_ssse3; } diff --git a/libavcodec/x86/qpel.asm b/libavcodec/x86/qpel.asm index 481251314..8f18cf93d 100644 --- a/libavcodec/x86/qpel.asm +++ b/libavcodec/x86/qpel.asm @@ -25,122 +25,74 @@ SECTION .text -%macro op_avgh 3 - movh %3, %2 - pavgb %1, %3 - movh %2, %1 -%endmacro - %macro op_avg 2 pavgb %1, %2 mova %2, %1 %endmacro -%macro op_puth 2-3 - movh %2, %1 -%endmacro - %macro op_put 2 mova %2, %1 %endmacro -; void ff_put/avg_pixels4_l2_mmxext(uint8_t *dst, uint8_t *src1, uint8_t *src2, -; int dstStride, int src1Stride, int h) -%macro PIXELS4_L2 1 -%define OP op_%1h -cglobal %1_pixels4_l2, 6,6 - movsxdifnidn r3, r3d - movsxdifnidn r4, r4d - test r5d, 1 - je .loop - movd m0, [r1] - movd m1, [r2] - add r1, r4 - add r2, 4 - pavgb m0, m1 - OP m0, [r0], m3 - add r0, r3 - dec r5d -.loop: - mova m0, [r1] - mova m1, [r1+r4] - lea r1, [r1+2*r4] - pavgb m0, [r2] - pavgb m1, [r2+4] - OP m0, [r0], m3 - OP m1, [r0+r3], m3 - lea r0, [r0+2*r3] - mova m0, [r1] - mova m1, [r1+r4] - lea r1, [r1+2*r4] - pavgb m0, [r2+8] - pavgb m1, [r2+12] - OP m0, [r0], m3 - OP m1, [r0+r3], m3 - lea r0, [r0+2*r3] - add r2, 16 - sub r5d, 4 - jne .loop - RET -%endmacro - -INIT_MMX mmxext -PIXELS4_L2 put -PIXELS4_L2 avg - -; void ff_put/avg_pixels8_l2_mmxext(uint8_t *dst, uint8_t *src1, uint8_t *src2, -; int dstStride, int src1Stride, int h) -%macro PIXELS8_L2 1 +%macro PIXELS_L2 2-3 ; avg vs put, size, size+1 %define OP op_%1 -cglobal %1_pixels8_l2, 6,6 - movsxdifnidn r3, r3d - movsxdifnidn r4, r4d - test r5d, 1 - je .loop - mova m0, [r1] - mova m1, [r2] +%ifidn %1, put +%if notcpuflag(sse2) ; SSE2 currently only uses 16x16 +; void ff_put_pixels8x9_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, +; ptrdiff_t dstStride, ptrdiff_t src1Stride) +cglobal put_pixels%2x%3_l2, 5,6,2 + movu m0, [r1] + pavgb m0, [r2] add r1, r4 - add r2, 8 - pavgb m0, m1 + add r2, mmsize OP m0, [r0] add r0, r3 - dec r5d + ; FIXME: avoid jump if prologue is empty + jmp %1_pixels%2x%2_after_prologue_ %+ cpuname +%endif +%endif +; void ff_avg/put_pixels8x8_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, +; ptrdiff_t dstStride, ptrdiff_t src1Stride) +cglobal %1_pixels%2x%2_l2, 5,6,2 +%1_pixels%2x%2_after_prologue_ %+ cpuname: + mov r5d, %2 .loop: - mova m0, [r1] - mova m1, [r1+r4] + movu m0, [r1] + movu m1, [r1+r4] lea r1, [r1+2*r4] pavgb m0, [r2] - pavgb m1, [r2+8] + pavgb m1, [r2+mmsize] OP m0, [r0] OP m1, [r0+r3] lea r0, [r0+2*r3] - mova m0, [r1] - mova m1, [r1+r4] + movu m0, [r1] + movu m1, [r1+r4] lea r1, [r1+2*r4] - pavgb m0, [r2+16] - pavgb m1, [r2+24] + pavgb m0, [r2+2*mmsize] + pavgb m1, [r2+3*mmsize] OP m0, [r0] OP m1, [r0+r3] lea r0, [r0+2*r3] - add r2, 32 + add r2, 4*mmsize sub r5d, 4 jne .loop RET %endmacro INIT_MMX mmxext -PIXELS8_L2 put -PIXELS8_L2 avg +PIXELS_L2 put, 8, 9 +PIXELS_L2 avg, 8 + +INIT_XMM sse2 +PIXELS_L2 put, 16, 17 +PIXELS_L2 avg, 16 -; void ff_put/avg_pixels16_l2_mmxext(uint8_t *dst, uint8_t *src1, uint8_t *src2, -; int dstStride, int src1Stride, int h) %macro PIXELS16_L2 1 %define OP op_%1 -cglobal %1_pixels16_l2, 6,6 - movsxdifnidn r3, r3d - movsxdifnidn r4, r4d - test r5d, 1 - je .loop +%ifidn %1, put +; void ff_put_pixels16x17_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, +; ptrdiff_t dstStride, ptrdiff_t src1Stride) +cglobal put_pixels16x17_l2, 5,6 mova m0, [r1] mova m1, [r1+8] pavgb m0, [r2] @@ -150,7 +102,14 @@ cglobal %1_pixels16_l2, 6,6 OP m0, [r0] OP m1, [r0+8] add r0, r3 - dec r5d + ; FIXME: avoid jump if prologue is empty + jmp %1_pixels16x16_after_prologue_ %+ cpuname +%endif +; void ff_avg/put_pixels16x16_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, +; ptrdiff_t dstStride, ptrdiff_t src1Stride) +cglobal %1_pixels16x16_l2, 5,6 +%1_pixels16x16_after_prologue_ %+ cpuname: + mov r5d, 16 .loop: mova m0, [r1] mova m1, [r1+8] diff --git a/libavcodec/x86/qpel.h b/libavcodec/x86/qpel.h new file mode 100644 index 000000000..61c047333 --- /dev/null +++ b/libavcodec/x86/qpel.h @@ -0,0 +1,44 @@ +/* + * 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_X86_QPEL_H +#define AVCODEC_X86_QPEL_H + +#include +#include + +void ff_put_pixels8x8_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); +void ff_avg_pixels8x8_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); +void ff_put_pixels16x16_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); +void ff_put_pixels16x16_l2_sse2(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); +void ff_avg_pixels16x16_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); +void ff_avg_pixels16x16_l2_sse2(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); + +#endif /* AVCODEC_X86_QPEL_H */ diff --git a/libavcodec/x86/qpeldsp.asm b/libavcodec/x86/qpeldsp.asm index 30d26a5ac..52ddd8a8b 100644 --- a/libavcodec/x86/qpeldsp.asm +++ b/libavcodec/x86/qpeldsp.asm @@ -23,7 +23,6 @@ %include "libavutil/x86/x86util.asm" -SECTION_RODATA cextern pb_1 cextern pw_3 cextern pw_15 @@ -33,14 +32,11 @@ cextern pw_20 SECTION .text -; void ff_put_no_rnd_pixels8_l2(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h) %macro PUT_NO_RND_PIXELS8_L2 0 -cglobal put_no_rnd_pixels8_l2, 6,6 - movsxdifnidn r4, r4d - movsxdifnidn r3, r3d +; void ff_put_no_rnd_pixels8x9_l2(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, +; ptrdiff_t dstStride, ptrdiff_t src1Stride) +cglobal put_no_rnd_pixels8x9_l2, 5,6 pcmpeqb m6, m6 - test r5d, 1 - je .loop mova m0, [r1] mova m1, [r2] add r1, r4 @@ -51,7 +47,14 @@ cglobal put_no_rnd_pixels8_l2, 6,6 pxor m0, m6 mova [r0], m0 add r0, r3 - dec r5d + jmp put_no_rnd_pixels8x8_after_prologue_ %+ cpuname + +; void ff_put_no_rnd_pixels8x8_l2(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, +; ptrdiff_t dstStride, ptrdiff_t src1Stride) +cglobal put_no_rnd_pixels8x8_l2, 5,6 + pcmpeqb m6, m6 +put_no_rnd_pixels8x8_after_prologue_ %+ cpuname: + mov r5d, 8 .loop: mova m0, [r1] add r1, r4 @@ -99,14 +102,11 @@ INIT_MMX mmxext PUT_NO_RND_PIXELS8_L2 -; void ff_put_no_rnd_pixels16_l2(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h) +; void ff_put_no_rnd_pixels16x17_l2(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, +; ptrdiff_t dstStride, ptrdiff_t src1Stride) %macro PUT_NO_RND_PIXELS16_l2 0 -cglobal put_no_rnd_pixels16_l2, 6,6 - movsxdifnidn r3, r3d - movsxdifnidn r4, r4d +cglobal put_no_rnd_pixels16x17_l2, 5,6 pcmpeqb m6, m6 - test r5d, 1 - je .loop mova m0, [r1] mova m1, [r1+8] mova m2, [r2] @@ -124,7 +124,14 @@ cglobal put_no_rnd_pixels16_l2, 6,6 mova [r0], m0 mova [r0+8], m1 add r0, r3 - dec r5d + jmp put_no_rnd_pixels16x16_after_prologue_ %+ cpuname + +; void ff_put_no_rnd_pixels16x16_l2(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, +; ptrdiff_t dstStride, ptrdiff_t src1Stride) +cglobal put_no_rnd_pixels16x16_l2, 5,6 + pcmpeqb m6, m6 +put_no_rnd_pixels16x16_after_prologue_ %+ cpuname: + mov r5d, 16 .loop: mova m0, [r1] mova m1, [r1+8] @@ -169,8 +176,6 @@ PUT_NO_RND_PIXELS16_l2 %macro MPEG4_QPEL16_H_LOWPASS 1 cglobal %1_mpeg4_qpel16_h_lowpass, 5, 5, 0, 16 - movsxdifnidn r2, r2d - movsxdifnidn r3, r3d pxor m7, m7 .loop: mova m0, [r1] @@ -302,8 +307,6 @@ MPEG4_QPEL16_H_LOWPASS put_no_rnd %macro MPEG4_QPEL8_H_LOWPASS 1 cglobal %1_mpeg4_qpel8_h_lowpass, 5, 5, 0, 8 - movsxdifnidn r2, r2d - movsxdifnidn r3, r3d pxor m7, m7 .loop: mova m0, [r1] @@ -398,9 +401,6 @@ MPEG4_QPEL8_H_LOWPASS put_no_rnd %macro MPEG4_QPEL16_V_LOWPASS 1 cglobal %1_mpeg4_qpel16_v_lowpass, 4, 6, 0, 544 - movsxdifnidn r2, r2d - movsxdifnidn r3, r3d - mov r4d, 17 mov r5, rsp pxor m7, m7 @@ -494,9 +494,6 @@ MPEG4_QPEL16_V_LOWPASS put_no_rnd %macro MPEG4_QPEL8_V_LOWPASS 1 cglobal %1_mpeg4_qpel8_v_lowpass, 4, 6, 0, 288 - movsxdifnidn r2, r2d - movsxdifnidn r3, r3d - mov r4d, 9 mov r5, rsp pxor m7, m7 diff --git a/libavcodec/x86/qpeldsp_init.c b/libavcodec/x86/qpeldsp_init.c index 3b05e156c..a569f564e 100644 --- a/libavcodec/x86/qpeldsp_init.c +++ b/libavcodec/x86/qpeldsp_init.c @@ -27,74 +27,60 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/x86/cpu.h" -#include "libavcodec/pixels.h" #include "libavcodec/qpeldsp.h" #include "fpel.h" +#include "qpel.h" -void ff_put_pixels8_l2_mmxext(uint8_t *dst, - const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); -void ff_put_no_rnd_pixels8_l2_mmxext(uint8_t *dst, - const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); -void ff_avg_pixels8_l2_mmxext(uint8_t *dst, - const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); -void ff_put_pixels16_l2_mmxext(uint8_t *dst, - const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); -void ff_avg_pixels16_l2_mmxext(uint8_t *dst, - const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); -void ff_put_no_rnd_pixels16_l2_mmxext(uint8_t *dst, - const uint8_t *src1, const uint8_t *src2, - int dstStride, int src1Stride, int h); +void ff_put_pixels8x9_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); +void ff_put_pixels16x17_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); +void ff_put_no_rnd_pixels8x8_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); +void ff_put_no_rnd_pixels8x9_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); +void ff_put_no_rnd_pixels16x16_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); +void ff_put_no_rnd_pixels16x17_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + ptrdiff_t dstStride, ptrdiff_t src1Stride); void ff_put_mpeg4_qpel16_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride, int h); + ptrdiff_t dstStride, ptrdiff_t srcStride, int h); void ff_avg_mpeg4_qpel16_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride, int h); + ptrdiff_t dstStride, ptrdiff_t srcStride, int h); void ff_put_no_rnd_mpeg4_qpel16_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride, + ptrdiff_t dstStride, ptrdiff_t srcStride, int h); void ff_put_mpeg4_qpel8_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride, int h); + ptrdiff_t dstStride, ptrdiff_t srcStride, int h); void ff_avg_mpeg4_qpel8_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride, int h); + ptrdiff_t dstStride, ptrdiff_t srcStride, int h); void ff_put_no_rnd_mpeg4_qpel8_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride, + ptrdiff_t dstStride, ptrdiff_t srcStride, int h); void ff_put_mpeg4_qpel16_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride); + ptrdiff_t dstStride, ptrdiff_t srcStride); void ff_avg_mpeg4_qpel16_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride); + ptrdiff_t dstStride, ptrdiff_t srcStride); void ff_put_no_rnd_mpeg4_qpel16_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride); + ptrdiff_t dstStride, ptrdiff_t srcStride); void ff_put_mpeg4_qpel8_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride); + ptrdiff_t dstStride, ptrdiff_t srcStride); void ff_avg_mpeg4_qpel8_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride); + ptrdiff_t dstStride, ptrdiff_t srcStride); void ff_put_no_rnd_mpeg4_qpel8_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, - int dstStride, int srcStride); -#define ff_put_no_rnd_pixels16_mmxext ff_put_pixels16_mmx -#define ff_put_no_rnd_pixels8_mmxext ff_put_pixels8_mmx - -#if HAVE_X86ASM - -#define ff_put_pixels16_mmxext ff_put_pixels16_mmx -#define ff_put_pixels8_mmxext ff_put_pixels8_mmx + ptrdiff_t dstStride, ptrdiff_t srcStride); #define QPEL_OP(OPNAME, RND, MMX) \ -static void OPNAME ## qpel8_mc00_ ## MMX(uint8_t *dst, \ - const uint8_t *src, \ - ptrdiff_t stride) \ -{ \ - ff_ ## OPNAME ## pixels8_ ## MMX(dst, src, stride, 8); \ -} \ - \ static void OPNAME ## qpel8_mc10_ ## MMX(uint8_t *dst, \ const uint8_t *src, \ ptrdiff_t stride) \ @@ -103,8 +89,8 @@ static void OPNAME ## qpel8_mc10_ ## MMX(uint8_t *dst, \ uint8_t *const half = (uint8_t *) temp; \ ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(half, src, 8, \ stride, 8); \ - ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, src, half, \ - stride, stride, 8); \ + ff_ ## OPNAME ## pixels8x8_l2_ ## MMX(dst, src, half, \ + stride, stride); \ } \ \ static void OPNAME ## qpel8_mc20_ ## MMX(uint8_t *dst, \ @@ -123,8 +109,8 @@ static void OPNAME ## qpel8_mc30_ ## MMX(uint8_t *dst, \ uint8_t *const half = (uint8_t *) temp; \ ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(half, src, 8, \ stride, 8); \ - ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, src + 1, half, stride, \ - stride, 8); \ + ff_ ## OPNAME ## pixels8x8_l2_ ## MMX(dst, src + 1, half, \ + stride, stride); \ } \ \ static void OPNAME ## qpel8_mc01_ ## MMX(uint8_t *dst, \ @@ -135,8 +121,8 @@ static void OPNAME ## qpel8_mc01_ ## MMX(uint8_t *dst, \ uint8_t *const half = (uint8_t *) temp; \ ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(half, src, \ 8, stride); \ - ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, src, half, \ - stride, stride, 8); \ + ff_ ## OPNAME ## pixels8x8_l2_ ## MMX(dst, src, half, \ + stride, stride); \ } \ \ static void OPNAME ## qpel8_mc02_ ## MMX(uint8_t *dst, \ @@ -155,8 +141,8 @@ static void OPNAME ## qpel8_mc03_ ## MMX(uint8_t *dst, \ uint8_t *const half = (uint8_t *) temp; \ ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(half, src, \ 8, stride); \ - ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, src + stride, half, stride,\ - stride, 8); \ + ff_ ## OPNAME ## pixels8x8_l2_ ## MMX(dst, src + stride, half, \ + stride, stride); \ } \ \ static void OPNAME ## qpel8_mc11_ ## MMX(uint8_t *dst, \ @@ -168,11 +154,11 @@ static void OPNAME ## qpel8_mc11_ ## MMX(uint8_t *dst, \ uint8_t *const halfHV = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ stride, 9); \ - ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src, halfH, 8, \ - stride, 9); \ + ff_put ## RND ## pixels8x9_l2_ ## MMX(halfH, src, halfH, 8, \ + stride); \ ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ - ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH, halfHV, \ - stride, 8, 8); \ + ff_ ## OPNAME ## pixels8x8_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 8); \ } \ \ static void OPNAME ## qpel8_mc31_ ## MMX(uint8_t *dst, \ @@ -184,11 +170,11 @@ static void OPNAME ## qpel8_mc31_ ## MMX(uint8_t *dst, \ uint8_t *const halfHV = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ stride, 9); \ - ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src + 1, halfH, 8, \ - stride, 9); \ + ff_put ## RND ## pixels8x9_l2_ ## MMX(halfH, src + 1, halfH, 8, \ + stride); \ ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ - ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH, halfHV, \ - stride, 8, 8); \ + ff_ ## OPNAME ## pixels8x8_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 8); \ } \ \ static void OPNAME ## qpel8_mc13_ ## MMX(uint8_t *dst, \ @@ -200,11 +186,11 @@ static void OPNAME ## qpel8_mc13_ ## MMX(uint8_t *dst, \ uint8_t *const halfHV = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ stride, 9); \ - ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src, halfH, 8, \ - stride, 9); \ + ff_put ## RND ## pixels8x9_l2_ ## MMX(halfH, src, halfH, 8, \ + stride); \ ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ - ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH + 8, halfHV, \ - stride, 8, 8); \ + ff_ ## OPNAME ## pixels8x8_l2_ ## MMX(dst, halfH + 8, halfHV, \ + stride, 8); \ } \ \ static void OPNAME ## qpel8_mc33_ ## MMX(uint8_t *dst, \ @@ -216,11 +202,11 @@ static void OPNAME ## qpel8_mc33_ ## MMX(uint8_t *dst, \ uint8_t *const halfHV = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ stride, 9); \ - ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src + 1, halfH, 8, \ - stride, 9); \ + ff_put ## RND ## pixels8x9_l2_ ## MMX(halfH, src + 1, halfH, 8, \ + stride); \ ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ - ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH + 8, halfHV, \ - stride, 8, 8); \ + ff_ ## OPNAME ## pixels8x8_l2_ ## MMX(dst, halfH + 8, halfHV, \ + stride, 8); \ } \ \ static void OPNAME ## qpel8_mc21_ ## MMX(uint8_t *dst, \ @@ -233,8 +219,8 @@ static void OPNAME ## qpel8_mc21_ ## MMX(uint8_t *dst, \ ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ stride, 9); \ ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ - ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH, halfHV, \ - stride, 8, 8); \ + ff_ ## OPNAME ## pixels8x8_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 8); \ } \ \ static void OPNAME ## qpel8_mc23_ ## MMX(uint8_t *dst, \ @@ -247,8 +233,8 @@ static void OPNAME ## qpel8_mc23_ ## MMX(uint8_t *dst, \ ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ stride, 9); \ ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ - ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH + 8, halfHV, \ - stride, 8, 8); \ + ff_ ## OPNAME ## pixels8x8_l2_ ## MMX(dst, halfH + 8, halfHV, \ + stride, 8); \ } \ \ static void OPNAME ## qpel8_mc12_ ## MMX(uint8_t *dst, \ @@ -259,8 +245,8 @@ static void OPNAME ## qpel8_mc12_ ## MMX(uint8_t *dst, \ uint8_t *const halfH = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ stride, 9); \ - ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src, halfH, \ - 8, stride, 9); \ + ff_put ## RND ## pixels8x9_l2_ ## MMX(halfH, src, halfH, \ + 8, stride); \ ff_ ## OPNAME ## mpeg4_qpel8_v_lowpass_ ## MMX(dst, halfH, \ stride, 8); \ } \ @@ -273,8 +259,8 @@ static void OPNAME ## qpel8_mc32_ ## MMX(uint8_t *dst, \ uint8_t *const halfH = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ stride, 9); \ - ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src + 1, halfH, 8, \ - stride, 9); \ + ff_put ## RND ## pixels8x9_l2_ ## MMX(halfH, src + 1, halfH, 8, \ + stride); \ ff_ ## OPNAME ## mpeg4_qpel8_v_lowpass_ ## MMX(dst, halfH, \ stride, 8); \ } \ @@ -291,13 +277,6 @@ static void OPNAME ## qpel8_mc22_ ## MMX(uint8_t *dst, \ stride, 8); \ } \ \ -static void OPNAME ## qpel16_mc00_ ## MMX(uint8_t *dst, \ - const uint8_t *src, \ - ptrdiff_t stride) \ -{ \ - ff_ ## OPNAME ## pixels16_ ## MMX(dst, src, stride, 16); \ -} \ - \ static void OPNAME ## qpel16_mc10_ ## MMX(uint8_t *dst, \ const uint8_t *src, \ ptrdiff_t stride) \ @@ -306,8 +285,8 @@ static void OPNAME ## qpel16_mc10_ ## MMX(uint8_t *dst, \ uint8_t *const half = (uint8_t *) temp; \ ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(half, src, 16, \ stride, 16); \ - ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, src, half, stride, \ - stride, 16); \ + ff_ ## OPNAME ## pixels16x16_l2_ ## MMX(dst, src, half, \ + stride, stride); \ } \ \ static void OPNAME ## qpel16_mc20_ ## MMX(uint8_t *dst, \ @@ -326,8 +305,8 @@ static void OPNAME ## qpel16_mc30_ ## MMX(uint8_t *dst, \ uint8_t *const half = (uint8_t*) temp; \ ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(half, src, 16, \ stride, 16); \ - ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, src + 1, half, \ - stride, stride, 16); \ + ff_ ## OPNAME ## pixels16x16_l2_ ## MMX(dst, src + 1, half, \ + stride, stride); \ } \ \ static void OPNAME ## qpel16_mc01_ ## MMX(uint8_t *dst, \ @@ -338,8 +317,8 @@ static void OPNAME ## qpel16_mc01_ ## MMX(uint8_t *dst, \ uint8_t *const half = (uint8_t *) temp; \ ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(half, src, 16, \ stride); \ - ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, src, half, stride, \ - stride, 16); \ + ff_ ## OPNAME ## pixels16x16_l2_ ## MMX(dst, src, half, \ + stride, stride); \ } \ \ static void OPNAME ## qpel16_mc02_ ## MMX(uint8_t *dst, \ @@ -358,8 +337,8 @@ static void OPNAME ## qpel16_mc03_ ## MMX(uint8_t *dst, \ uint8_t *const half = (uint8_t *) temp; \ ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(half, src, 16, \ stride); \ - ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, src+stride, half, \ - stride, stride, 16); \ + ff_ ## OPNAME ## pixels16x16_l2_ ## MMX(dst, src+stride, half, \ + stride, stride); \ } \ \ static void OPNAME ## qpel16_mc11_ ## MMX(uint8_t *dst, \ @@ -371,12 +350,12 @@ static void OPNAME ## qpel16_mc11_ ## MMX(uint8_t *dst, \ uint8_t *const halfHV = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ stride, 17); \ - ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src, halfH, 16, \ - stride, 17); \ + ff_put ## RND ## pixels16x17_l2_ ## MMX(halfH, src, halfH, 16, \ + stride); \ ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ 16, 16); \ - ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH, halfHV, \ - stride, 16, 16); \ + ff_ ## OPNAME ## pixels16x16_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 16); \ } \ \ static void OPNAME ## qpel16_mc31_ ## MMX(uint8_t *dst, \ @@ -388,12 +367,12 @@ static void OPNAME ## qpel16_mc31_ ## MMX(uint8_t *dst, \ uint8_t *const halfHV = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ stride, 17); \ - ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src + 1, halfH, 16, \ - stride, 17); \ + ff_put ## RND ## pixels16x17_l2_ ## MMX(halfH, src + 1, halfH, 16, \ + stride); \ ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ 16, 16); \ - ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH, halfHV, \ - stride, 16, 16); \ + ff_ ## OPNAME ## pixels16x16_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 16); \ } \ \ static void OPNAME ## qpel16_mc13_ ## MMX(uint8_t *dst, \ @@ -405,12 +384,12 @@ static void OPNAME ## qpel16_mc13_ ## MMX(uint8_t *dst, \ uint8_t *const halfHV = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ stride, 17); \ - ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src, halfH, 16, \ - stride, 17); \ + ff_put ## RND ## pixels16x17_l2_ ## MMX(halfH, src, halfH, 16, \ + stride); \ ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ 16, 16); \ - ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH + 16, halfHV, \ - stride, 16, 16); \ + ff_ ## OPNAME ## pixels16x16_l2_ ## MMX(dst, halfH + 16, halfHV, \ + stride, 16); \ } \ \ static void OPNAME ## qpel16_mc33_ ## MMX(uint8_t *dst, \ @@ -422,12 +401,12 @@ static void OPNAME ## qpel16_mc33_ ## MMX(uint8_t *dst, \ uint8_t *const halfHV = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ stride, 17); \ - ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src + 1, halfH, 16, \ - stride, 17); \ + ff_put ## RND ## pixels16x17_l2_ ## MMX(halfH, src + 1, halfH, 16, \ + stride); \ ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ 16, 16); \ - ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH + 16, halfHV, \ - stride, 16, 16); \ + ff_ ## OPNAME ## pixels16x16_l2_ ## MMX(dst, halfH + 16, halfHV, \ + stride, 16); \ } \ \ static void OPNAME ## qpel16_mc21_ ## MMX(uint8_t *dst, \ @@ -441,8 +420,8 @@ static void OPNAME ## qpel16_mc21_ ## MMX(uint8_t *dst, \ stride, 17); \ ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ 16, 16); \ - ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH, halfHV, \ - stride, 16, 16); \ + ff_ ## OPNAME ## pixels16x16_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 16); \ } \ \ static void OPNAME ## qpel16_mc23_ ## MMX(uint8_t *dst, \ @@ -456,8 +435,8 @@ static void OPNAME ## qpel16_mc23_ ## MMX(uint8_t *dst, \ stride, 17); \ ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ 16, 16); \ - ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH + 16, halfHV, \ - stride, 16, 16); \ + ff_ ## OPNAME ## pixels16x16_l2_ ## MMX(dst, halfH + 16, halfHV, \ + stride, 16); \ } \ \ static void OPNAME ## qpel16_mc12_ ## MMX(uint8_t *dst, \ @@ -468,8 +447,8 @@ static void OPNAME ## qpel16_mc12_ ## MMX(uint8_t *dst, \ uint8_t *const halfH = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ stride, 17); \ - ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src, halfH, 16, \ - stride, 17); \ + ff_put ## RND ## pixels16x17_l2_ ## MMX(halfH, src, halfH, 16, \ + stride); \ ff_ ## OPNAME ## mpeg4_qpel16_v_lowpass_ ## MMX(dst, halfH, \ stride, 16); \ } \ @@ -482,8 +461,8 @@ static void OPNAME ## qpel16_mc32_ ## MMX(uint8_t *dst, \ uint8_t *const halfH = (uint8_t *) half; \ ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ stride, 17); \ - ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src + 1, halfH, 16, \ - stride, 17); \ + ff_put ## RND ## pixels16x17_l2_ ## MMX(halfH, src + 1, halfH, 16, \ + stride); \ ff_ ## OPNAME ## mpeg4_qpel16_v_lowpass_ ## MMX(dst, halfH, \ stride, 16); \ } \ @@ -504,11 +483,8 @@ QPEL_OP(put_, _, mmxext) QPEL_OP(avg_, _, mmxext) QPEL_OP(put_no_rnd_, _no_rnd_, mmxext) -#endif /* HAVE_X86ASM */ - #define SET_QPEL_FUNCS(PFX, IDX, SIZE, CPU, PREFIX) \ do { \ - c->PFX ## _pixels_tab[IDX][ 0] = PREFIX ## PFX ## SIZE ## _mc00_ ## CPU; \ c->PFX ## _pixels_tab[IDX][ 1] = PREFIX ## PFX ## SIZE ## _mc10_ ## CPU; \ c->PFX ## _pixels_tab[IDX][ 2] = PREFIX ## PFX ## SIZE ## _mc20_ ## CPU; \ c->PFX ## _pixels_tab[IDX][ 3] = PREFIX ## PFX ## SIZE ## _mc30_ ## CPU; \ @@ -533,6 +509,7 @@ av_cold void ff_qpeldsp_init_x86(QpelDSPContext *c) if (X86_MMXEXT(cpu_flags)) { #if HAVE_MMXEXT_EXTERNAL SET_QPEL_FUNCS(avg_qpel, 0, 16, mmxext, ); + c->avg_qpel_pixels_tab[1][0] = ff_avg_pixels8x8_mmxext; SET_QPEL_FUNCS(avg_qpel, 1, 8, mmxext, ); SET_QPEL_FUNCS(put_qpel, 0, 16, mmxext, ); @@ -541,4 +518,13 @@ av_cold void ff_qpeldsp_init_x86(QpelDSPContext *c) SET_QPEL_FUNCS(put_no_rnd_qpel, 1, 8, mmxext, ); #endif /* HAVE_MMXEXT_EXTERNAL */ } +#if HAVE_SSE2_EXTERNAL + if (EXTERNAL_SSE2(cpu_flags)) { + c->put_no_rnd_qpel_pixels_tab[0][0] = + c->put_qpel_pixels_tab[0][0] = ff_put_pixels16x16_sse2; + c->put_no_rnd_qpel_pixels_tab[1][0] = + c->put_qpel_pixels_tab[1][0] = ff_put_pixels8x8_sse2; + c->avg_qpel_pixels_tab[0][0] = ff_avg_pixels16x16_sse2; + } +#endif } diff --git a/libavcodec/x86/rnd_template.c b/libavcodec/x86/rnd_template.c deleted file mode 100644 index b825eeba6..000000000 --- a/libavcodec/x86/rnd_template.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * SIMD-optimized halfpel functions are compiled twice for rnd/no_rnd - * Copyright (c) 2000, 2001 Fabrice Bellard - * Copyright (c) 2003-2004 Michael Niedermayer - * - * MMX optimization by Nick Kurshev - * mostly rewritten by Michael Niedermayer - * and improved by Zdenek Kabelac - * - * 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 "inline_asm.h" - -// put_pixels -av_unused STATIC void DEF(put, pixels8_xy2)(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h) -{ - MOVQ_ZERO(mm7); - SET_RND(mm6); // =2 for rnd and =1 for no_rnd version - __asm__ volatile( - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm4 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm4, %%mm5 \n\t" - "punpcklbw %%mm7, %%mm0 \n\t" - "punpcklbw %%mm7, %%mm4 \n\t" - "punpckhbw %%mm7, %%mm1 \n\t" - "punpckhbw %%mm7, %%mm5 \n\t" - "paddusw %%mm0, %%mm4 \n\t" - "paddusw %%mm1, %%mm5 \n\t" - "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" - "add %3, %1 \n\t" - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" - "movq 1(%1, %%"FF_REG_a"), %%mm2 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm2, %%mm3 \n\t" - "punpcklbw %%mm7, %%mm0 \n\t" - "punpcklbw %%mm7, %%mm2 \n\t" - "punpckhbw %%mm7, %%mm1 \n\t" - "punpckhbw %%mm7, %%mm3 \n\t" - "paddusw %%mm2, %%mm0 \n\t" - "paddusw %%mm3, %%mm1 \n\t" - "paddusw %%mm6, %%mm4 \n\t" - "paddusw %%mm6, %%mm5 \n\t" - "paddusw %%mm0, %%mm4 \n\t" - "paddusw %%mm1, %%mm5 \n\t" - "psrlw $2, %%mm4 \n\t" - "psrlw $2, %%mm5 \n\t" - "packuswb %%mm5, %%mm4 \n\t" - "movq %%mm4, (%2, %%"FF_REG_a") \n\t" - "add %3, %%"FF_REG_a" \n\t" - - "movq (%1, %%"FF_REG_a"), %%mm2 \n\t" // 0 <-> 2 1 <-> 3 - "movq 1(%1, %%"FF_REG_a"), %%mm4 \n\t" - "movq %%mm2, %%mm3 \n\t" - "movq %%mm4, %%mm5 \n\t" - "punpcklbw %%mm7, %%mm2 \n\t" - "punpcklbw %%mm7, %%mm4 \n\t" - "punpckhbw %%mm7, %%mm3 \n\t" - "punpckhbw %%mm7, %%mm5 \n\t" - "paddusw %%mm2, %%mm4 \n\t" - "paddusw %%mm3, %%mm5 \n\t" - "paddusw %%mm6, %%mm0 \n\t" - "paddusw %%mm6, %%mm1 \n\t" - "paddusw %%mm4, %%mm0 \n\t" - "paddusw %%mm5, %%mm1 \n\t" - "psrlw $2, %%mm0 \n\t" - "psrlw $2, %%mm1 \n\t" - "packuswb %%mm1, %%mm0 \n\t" - "movq %%mm0, (%2, %%"FF_REG_a") \n\t" - "add %3, %%"FF_REG_a" \n\t" - - "subl $2, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels) - :"D"(block), "r"((x86_reg)line_size) - :FF_REG_a, "memory"); -} - -#ifndef NO_AVG -// avg_pixels -// this routine is 'slightly' suboptimal but mostly unused -av_unused STATIC void DEF(avg, pixels8_xy2)(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h) -{ - MOVQ_ZERO(mm7); - SET_RND(mm6); // =2 for rnd and =1 for no_rnd version - __asm__ volatile( - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm4 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm4, %%mm5 \n\t" - "punpcklbw %%mm7, %%mm0 \n\t" - "punpcklbw %%mm7, %%mm4 \n\t" - "punpckhbw %%mm7, %%mm1 \n\t" - "punpckhbw %%mm7, %%mm5 \n\t" - "paddusw %%mm0, %%mm4 \n\t" - "paddusw %%mm1, %%mm5 \n\t" - "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" - "add %3, %1 \n\t" - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" - "movq 1(%1, %%"FF_REG_a"), %%mm2 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm2, %%mm3 \n\t" - "punpcklbw %%mm7, %%mm0 \n\t" - "punpcklbw %%mm7, %%mm2 \n\t" - "punpckhbw %%mm7, %%mm1 \n\t" - "punpckhbw %%mm7, %%mm3 \n\t" - "paddusw %%mm2, %%mm0 \n\t" - "paddusw %%mm3, %%mm1 \n\t" - "paddusw %%mm6, %%mm4 \n\t" - "paddusw %%mm6, %%mm5 \n\t" - "paddusw %%mm0, %%mm4 \n\t" - "paddusw %%mm1, %%mm5 \n\t" - "psrlw $2, %%mm4 \n\t" - "psrlw $2, %%mm5 \n\t" - "movq (%2, %%"FF_REG_a"), %%mm3 \n\t" - "packuswb %%mm5, %%mm4 \n\t" - "pcmpeqd %%mm2, %%mm2 \n\t" - "paddb %%mm2, %%mm2 \n\t" - PAVGB_MMX(%%mm3, %%mm4, %%mm5, %%mm2) - "movq %%mm5, (%2, %%"FF_REG_a") \n\t" - "add %3, %%"FF_REG_a" \n\t" - - "movq (%1, %%"FF_REG_a"), %%mm2 \n\t" // 0 <-> 2 1 <-> 3 - "movq 1(%1, %%"FF_REG_a"), %%mm4 \n\t" - "movq %%mm2, %%mm3 \n\t" - "movq %%mm4, %%mm5 \n\t" - "punpcklbw %%mm7, %%mm2 \n\t" - "punpcklbw %%mm7, %%mm4 \n\t" - "punpckhbw %%mm7, %%mm3 \n\t" - "punpckhbw %%mm7, %%mm5 \n\t" - "paddusw %%mm2, %%mm4 \n\t" - "paddusw %%mm3, %%mm5 \n\t" - "paddusw %%mm6, %%mm0 \n\t" - "paddusw %%mm6, %%mm1 \n\t" - "paddusw %%mm4, %%mm0 \n\t" - "paddusw %%mm5, %%mm1 \n\t" - "psrlw $2, %%mm0 \n\t" - "psrlw $2, %%mm1 \n\t" - "movq (%2, %%"FF_REG_a"), %%mm3 \n\t" - "packuswb %%mm1, %%mm0 \n\t" - "pcmpeqd %%mm2, %%mm2 \n\t" - "paddb %%mm2, %%mm2 \n\t" - PAVGB_MMX(%%mm3, %%mm0, %%mm1, %%mm2) - "movq %%mm1, (%2, %%"FF_REG_a") \n\t" - "add %3, %%"FF_REG_a" \n\t" - - "subl $2, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels) - :"D"(block), "r"((x86_reg)line_size) - :FF_REG_a, "memory"); -} -#endif diff --git a/libavcodec/x86/rv40dsp_init.c b/libavcodec/x86/rv40dsp_init.c index ab9e644c6..97abee321 100644 --- a/libavcodec/x86/rv40dsp_init.c +++ b/libavcodec/x86/rv40dsp_init.c @@ -39,17 +39,6 @@ static void op##_rv40_qpel##size##_mc33_##insn(uint8_t *dst, const uint8_t *src, ff_##op##_pixels##size##_xy2_##insn(dst, src, stride, size); \ } -#if HAVE_X86ASM -void ff_put_rv40_chroma_mc8_mmx (uint8_t *dst, const uint8_t *src, - ptrdiff_t stride, int h, int x, int y); -void ff_avg_rv40_chroma_mc8_mmxext(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride, int h, int x, int y); - -void ff_put_rv40_chroma_mc4_mmx (uint8_t *dst, const uint8_t *src, - ptrdiff_t stride, int h, int x, int y); -void ff_avg_rv40_chroma_mc4_mmxext(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride, int h, int x, int y); - #define DECLARE_WEIGHT(opt) \ void ff_rv40_weight_func_rnd_16_##opt(uint8_t *dst, uint8_t *src1, uint8_t *src2, \ int w1, int w2, ptrdiff_t stride); \ @@ -174,37 +163,20 @@ DEFINE_FN(put, 8, ssse3) DEFINE_FN(put, 16, sse2) DEFINE_FN(put, 16, ssse3) -DEFINE_FN(avg, 8, mmxext) DEFINE_FN(avg, 8, ssse3) DEFINE_FN(avg, 16, sse2) DEFINE_FN(avg, 16, ssse3) -#endif /* HAVE_X86ASM */ -#if HAVE_MMX_INLINE -DEFINE_FN(put, 8, mmx) -#endif +#define CHROMA_MC_FUNC(OP, SIZE, XMM) \ +void ff_rv40_ ## OP ## _chroma_mc ## SIZE ## _ ## XMM(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride, int h, int x, int y);\ + c->OP ## _chroma_pixels_tab[SIZE == 4] = ff_rv40_ ## OP ## _chroma_mc ## SIZE ## _ ## XMM av_cold void ff_rv40dsp_init_x86(RV34DSPContext *c) { av_unused int cpu_flags = av_get_cpu_flags(); -#if HAVE_MMX_INLINE - if (INLINE_MMX(cpu_flags)) { - c->put_pixels_tab[1][15] = put_rv40_qpel8_mc33_mmx; - } -#endif /* HAVE_MMX_INLINE */ - -#if HAVE_X86ASM - if (EXTERNAL_MMX(cpu_flags)) { - c->put_chroma_pixels_tab[0] = ff_put_rv40_chroma_mc8_mmx; - c->put_chroma_pixels_tab[1] = ff_put_rv40_chroma_mc4_mmx; - } - if (EXTERNAL_MMXEXT(cpu_flags)) { - c->avg_pixels_tab[1][15] = avg_rv40_qpel8_mc33_mmxext; - c->avg_chroma_pixels_tab[0] = ff_avg_rv40_chroma_mc8_mmxext; - c->avg_chroma_pixels_tab[1] = ff_avg_rv40_chroma_mc4_mmxext; - } if (EXTERNAL_SSE2(cpu_flags)) { c->put_pixels_tab[0][15] = put_rv40_qpel16_mc33_sse2; c->avg_pixels_tab[0][15] = avg_rv40_qpel16_mc33_sse2; @@ -216,6 +188,10 @@ av_cold void ff_rv40dsp_init_x86(RV34DSPContext *c) QPEL_MC_SET(avg_, _sse2) } if (EXTERNAL_SSSE3(cpu_flags)) { + CHROMA_MC_FUNC(put, 8, ssse3); + CHROMA_MC_FUNC(put, 4, ssse3); + CHROMA_MC_FUNC(avg, 8, ssse3); + CHROMA_MC_FUNC(avg, 4, ssse3); c->put_pixels_tab[0][15] = put_rv40_qpel16_mc33_ssse3; c->put_pixels_tab[1][15] = put_rv40_qpel8_mc33_ssse3; c->avg_pixels_tab[0][15] = avg_rv40_qpel16_mc33_ssse3; @@ -227,5 +203,4 @@ av_cold void ff_rv40dsp_init_x86(RV34DSPContext *c) QPEL_MC_SET(put_, _ssse3) QPEL_MC_SET(avg_, _ssse3) } -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/x86/simple_idct.asm b/libavcodec/x86/simple_idct.asm index c79519372..0dc03738e 100644 --- a/libavcodec/x86/simple_idct.asm +++ b/libavcodec/x86/simple_idct.asm @@ -1,5 +1,5 @@ ; -; Simple IDCT MMX +; Simple IDCT SSE2 ; ; Copyright (c) 2001, 2002 Michael Niedermayer ; @@ -30,8 +30,8 @@ SECTION_RODATA %if ARCH_X86_32 cextern pb_80 +d40000: dd 4 << 16, 0 ; must be 16-byte aligned wm1010: dw 0, 0xffff, 0, 0xffff -d40000: dd 4 << 16, 0 ; 23170.475006 ; 22725.260826 @@ -57,650 +57,675 @@ d40000: dd 4 << 16, 0 coeffs: dw 1 << (ROW_SHIFT - 1), 0 dw 1 << (ROW_SHIFT - 1), 0 + dw 1 << (ROW_SHIFT - 1), 0 + dw 1 << (ROW_SHIFT - 1), 0 + dw 1 << (ROW_SHIFT - 1), 1 + dw 1 << (ROW_SHIFT - 1), 0 dw 1 << (ROW_SHIFT - 1), 1 dw 1 << (ROW_SHIFT - 1), 0 - dw C4, C4, C4, C4 - dw C4, -C4, C4, -C4 + dw C4, C4, C4, C4, C4, C4, C4, C4 + dw C4, -C4, C4, -C4, C4, -C4, C4, -C4 - dw C2, C6, C2, C6 - dw C6, -C2, C6, -C2 + dw C2, C6, C2, C6, C2, C6, C2, C6 + dw C6, -C2, C6, -C2, C6, -C2, C6, -C2 - dw C1, C3, C1, C3 - dw C5, C7, C5, C7 + dw C1, C3, C1, C3, C1, C3, C1, C3 + dw C5, C7, C5, C7, C5, C7, C5, C7 - dw C3, -C7, C3, -C7 - dw -C1, -C5, -C1, -C5 + dw C3, -C7, C3, -C7, C3, -C7, C3, -C7 + dw -C1, -C5, -C1, -C5, -C1, -C5, -C1, -C5 - dw C5, -C1, C5, -C1 - dw C7, C3, C7, C3 + dw C5, -C1, C5, -C1, C5, -C1, C5, -C1 + dw C7, C3, C7, C3, C7, C3, C7, C3 - dw C7, -C5, C7, -C5 - dw C3, -C1, C3, -C1 + dw C7, -C5, C7, -C5, C7, -C5, C7, -C5 + dw C3, -C1, C3, -C1, C3, -C1, C3, -C1 SECTION .text %macro DC_COND_IDCT 7 - movq mm0, [blockq + %1] ; R4 R0 r4 r0 - movq mm1, [blockq + %2] ; R6 R2 r6 r2 - movq mm2, [blockq + %3] ; R3 R1 r3 r1 - movq mm3, [blockq + %4] ; R7 R5 r7 r5 - movq mm4, [wm1010] - pand mm4, mm0 - por mm4, mm1 - por mm4, mm2 - por mm4, mm3 - packssdw mm4, mm4 - movd t0d, mm4 + movq m0, [blockq + %1] ; R4 R0 r4 r0 + movq m1, [blockq + %2] ; R6 R2 r6 r2 + movq m2, [blockq + %3] ; R3 R1 r3 r1 + movq m3, [blockq + %4] ; R7 R5 r7 r5 + movq m4, [wm1010] + pand m4, m0 + por m4, m1 + por m4, m2 + por m4, m3 + packssdw m4, m4 + movd t0d, m4 or t0d, t0d jz %%1 - movq mm4, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm4, mm0 ; C4R4+C4R0 C4r4+C4r0 - movq mm5, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm0, mm5 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm5, [coeffs + 32] ; C6 C2 C6 C2 - pmaddwd mm5, mm1 ; C6R6+C2R2 C6r6+C2r2 - movq mm6, [coeffs + 40] ; -C2 C6 -C2 C6 - pmaddwd mm1, mm6 ; -C2R6+C6R2 -C2r6+C6r2 - movq mm7, [coeffs + 48] ; C3 C1 C3 C1 - pmaddwd mm7, mm2 ; C3R3+C1R1 C3r3+C1r1 - paddd mm4, [coeffs + 8] - movq mm6, mm4 ; C4R4+C4R0 C4r4+C4r0 - paddd mm4, mm5 ; A0 a0 - psubd mm6, mm5 ; A3 a3 - movq mm5, [coeffs + 56] ; C7 C5 C7 C5 - pmaddwd mm5, mm3 ; C7R7+C5R5 C7r7+C5r5 - paddd mm0, [coeffs + 8] - paddd mm1, mm0 ; A1 a1 - paddd mm0, mm0 - psubd mm0, mm1 ; A2 a2 - pmaddwd mm2, [coeffs + 64] ; -C7R3+C3R1 -C7r3+C3r1 - paddd mm7, mm5 ; B0 b0 - movq mm5, [coeffs + 72] ; -C5 -C1 -C5 -C1 - pmaddwd mm5, mm3 ; -C5R7-C1R5 -C5r7-C1r5 - paddd mm7, mm4 ; A0+B0 a0+b0 - paddd mm4, mm4 ; 2A0 2a0 - psubd mm4, mm7 ; A0-B0 a0-b0 - paddd mm5, mm2 ; B1 b1 - psrad mm7, %7 - psrad mm4, %7 - movq mm2, mm1 ; A1 a1 - paddd mm1, mm5 ; A1+B1 a1+b1 - psubd mm2, mm5 ; A1-B1 a1-b1 - psrad mm1, %7 - psrad mm2, %7 - packssdw mm7, mm1 ; A1+B1 a1+b1 A0+B0 a0+b0 - packssdw mm2, mm4 ; A0-B0 a0-b0 A1-B1 a1-b1 - movq [%5], mm7 - movq mm1, [blockq + %3] ; R3 R1 r3 r1 - movq mm4, [coeffs + 80] ; -C1 C5 -C1 C5 - movq [24 + %5], mm2 - pmaddwd mm4, mm1 ; -C1R3+C5R1 -C1r3+C5r1 - movq mm7, [coeffs + 88] ; C3 C7 C3 C7 - pmaddwd mm1, [coeffs + 96] ; -C5R3+C7R1 -C5r3+C7r1 - pmaddwd mm7, mm3 ; C3R7+C7R5 C3r7+C7r5 - movq mm2, mm0 ; A2 a2 - pmaddwd mm3, [coeffs + 104] ; -C1R7+C3R5 -C1r7+C3r5 - paddd mm4, mm7 ; B2 b2 - paddd mm2, mm4 ; A2+B2 a2+b2 - psubd mm0, mm4 ; a2-B2 a2-b2 - psrad mm2, %7 - psrad mm0, %7 - movq mm4, mm6 ; A3 a3 - paddd mm3, mm1 ; B3 b3 - paddd mm6, mm3 ; A3+B3 a3+b3 - psubd mm4, mm3 ; a3-B3 a3-b3 - psrad mm6, %7 - packssdw mm2, mm6 ; A3+B3 a3+b3 A2+B2 a2+b2 - movq [8 + %5], mm2 - psrad mm4, %7 - packssdw mm4, mm0 ; A2-B2 a2-b2 A3-B3 a3-b3 - movq [16 + %5], mm4 + movq m4, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m4, m0 ; C4R4+C4R0 C4r4+C4r0 + movq m5, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m0, m5 ; -C4R4+C4R0 -C4r4+C4r0 + movq m5, [coeffs + 64] ; C6 C2 C6 C2 + pmaddwd m5, m1 ; C6R6+C2R2 C6r6+C2r2 + movq m6, [coeffs + 80] ; -C2 C6 -C2 C6 + pmaddwd m1, m6 ; -C2R6+C6R2 -C2r6+C6r2 + movq m7, [coeffs + 96] ; C3 C1 C3 C1 + pmaddwd m7, m2 ; C3R3+C1R1 C3r3+C1r1 + paddd m4, [coeffs + 16] + movq m6, m4 ; C4R4+C4R0 C4r4+C4r0 + paddd m4, m5 ; A0 a0 + psubd m6, m5 ; A3 a3 + movq m5, [coeffs + 112] ; C7 C5 C7 C5 + pmaddwd m5, m3 ; C7R7+C5R5 C7r7+C5r5 + paddd m0, [coeffs + 16] + paddd m1, m0 ; A1 a1 + paddd m0, m0 + psubd m0, m1 ; A2 a2 + pmaddwd m2, [coeffs + 128] ; -C7R3+C3R1 -C7r3+C3r1 + paddd m7, m5 ; B0 b0 + movq m5, [coeffs + 144] ; -C5 -C1 -C5 -C1 + pmaddwd m5, m3 ; -C5R7-C1R5 -C5r7-C1r5 + paddd m7, m4 ; A0+B0 a0+b0 + paddd m4, m4 ; 2A0 2a0 + psubd m4, m7 ; A0-B0 a0-b0 + paddd m5, m2 ; B1 b1 + psrad m7, %7 + psrad m4, %7 + movq m2, m1 ; A1 a1 + paddd m1, m5 ; A1+B1 a1+b1 + psubd m2, m5 ; A1-B1 a1-b1 + psrad m1, %7 + psrad m2, %7 + packssdw m7, m1 ; A1+B1 a1+b1 A0+B0 a0+b0 + pshufd m7, m7, 0xD8 + packssdw m2, m4 ; A0-B0 a0-b0 A1-B1 a1-b1 + pshufd m2, m2, 0xD8 + movq [%5], m7 + movq m1, [blockq + %3] ; R3 R1 r3 r1 + movq m4, [coeffs + 160] ; -C1 C5 -C1 C5 + movq [24 + %5], m2 + pmaddwd m4, m1 ; -C1R3+C5R1 -C1r3+C5r1 + movq m7, [coeffs + 176] ; C3 C7 C3 C7 + pmaddwd m1, [coeffs + 192] ; -C5R3+C7R1 -C5r3+C7r1 + pmaddwd m7, m3 ; C3R7+C7R5 C3r7+C7r5 + movq m2, m0 ; A2 a2 + pmaddwd m3, [coeffs + 208] ; -C1R7+C3R5 -C1r7+C3r5 + paddd m4, m7 ; B2 b2 + paddd m2, m4 ; A2+B2 a2+b2 + psubd m0, m4 ; a2-B2 a2-b2 + psrad m2, %7 + psrad m0, %7 + movq m4, m6 ; A3 a3 + paddd m3, m1 ; B3 b3 + paddd m6, m3 ; A3+B3 a3+b3 + psubd m4, m3 ; a3-B3 a3-b3 + psrad m6, %7 + packssdw m2, m6 ; A3+B3 a3+b3 A2+B2 a2+b2 + pshufd m2, m2, 0xD8 + movq [8 + %5], m2 + psrad m4, %7 + packssdw m4, m0 ; A2-B2 a2-b2 A3-B3 a3-b3 + pshufd m4, m4, 0xD8 + movq [16 + %5], m4 jmp %%2 %%1: - pslld mm0, 16 - paddd mm0, [d40000] - psrad mm0, 13 - packssdw mm0, mm0 - movq [%5], mm0 - movq [8 + %5], mm0 - movq [16 + %5], mm0 - movq [24 + %5], mm0 + pslld m0, 16 + ; d40000 is only eight bytes long, so this will clobber + ; the upper half of m0 with wm1010. It doesn't matter due to pshufd below. + paddd m0, [d40000] + psrad m0, 13 + packssdw m0, m0 + pshufd m0, m0, 0x0 + mova [%5], m0 + mova [16 + %5], m0 %%2: %endmacro %macro Z_COND_IDCT 8 - movq mm0, [blockq + %1] ; R4 R0 r4 r0 - movq mm1, [blockq + %2] ; R6 R2 r6 r2 - movq mm2, [blockq + %3] ; R3 R1 r3 r1 - movq mm3, [blockq + %4] ; R7 R5 r7 r5 - movq mm4, mm0 - por mm4, mm1 - por mm4, mm2 - por mm4, mm3 - packssdw mm4, mm4 - movd t0d, mm4 + movq m0, [blockq + %1] ; R4 R0 r4 r0 + movq m1, [blockq + %2] ; R6 R2 r6 r2 + movq m2, [blockq + %3] ; R3 R1 r3 r1 + movq m3, [blockq + %4] ; R7 R5 r7 r5 + movq m4, m0 + por m4, m1 + por m4, m2 + por m4, m3 + packssdw m4, m4 + movd t0d, m4 or t0d, t0d jz %8 - movq mm4, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm4, mm0 ; C4R4+C4R0 C4r4+C4r0 - movq mm5, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm0, mm5 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm5, [coeffs + 32] ; C6 C2 C6 C2 - pmaddwd mm5, mm1 ; C6R6+C2R2 C6r6+C2r2 - movq mm6, [coeffs + 40] ; -C2 C6 -C2 C6 - pmaddwd mm1, mm6 ; -C2R6+C6R2 -C2r6+C6r2 - movq mm7, [coeffs + 48] ; C3 C1 C3 C1 - pmaddwd mm7, mm2 ; C3R3+C1R1 C3r3+C1r1 - paddd mm4, [coeffs] - movq mm6, mm4 ; C4R4+C4R0 C4r4+C4r0 - paddd mm4, mm5 ; A0 a0 - psubd mm6, mm5 ; A3 a3 - movq mm5, [coeffs + 56] ; C7 C5 C7 C5 - pmaddwd mm5, mm3 ; C7R7+C5R5 C7r7+C5r5 - paddd mm0, [coeffs] - paddd mm1, mm0 ; A1 a1 - paddd mm0, mm0 - psubd mm0, mm1 ; A2 a2 - pmaddwd mm2, [coeffs + 64] ; -C7R3+C3R1 -C7r3+C3r1 - paddd mm7, mm5 ; B0 b0 - movq mm5, [coeffs + 72] ; -C5 -C1 -C5 -C1 - pmaddwd mm5, mm3 ; -C5R7-C1R5 -C5r7-C1r5 - paddd mm7, mm4 ; A0+B0 a0+b0 - paddd mm4, mm4 ; 2A0 2a0 - psubd mm4, mm7 ; A0-B0 a0-b0 - paddd mm5, mm2 ; B1 b1 - psrad mm7, %7 - psrad mm4, %7 - movq mm2, mm1 ; A1 a1 - paddd mm1, mm5 ; A1+B1 a1+b1 - psubd mm2, mm5 ; A1-B1 a1-b1 - psrad mm1, %7 - psrad mm2, %7 - packssdw mm7, mm1 ; A1+B1 a1+b1 A0+B0 a0+b0 - packssdw mm2, mm4 ; A0-B0 a0-b0 A1-B1 a1-b1 - movq [%5], mm7 - movq mm1, [blockq + %3] ; R3 R1 r3 r1 - movq mm4, [coeffs + 80] ; -C1 C5 -C1 C5 - movq [24 + %5], mm2 - pmaddwd mm4, mm1 ; -C1R3+C5R1 -C1r3+C5r1 - movq mm7, [coeffs + 88] ; C3 C7 C3 C7 - pmaddwd mm1, [coeffs + 96] ; -C5R3+C7R1 -C5r3+C7r1 - pmaddwd mm7, mm3 ; C3R7+C7R5 C3r7+C7r5 - movq mm2, mm0 ; A2 a2 - pmaddwd mm3, [coeffs + 104] ; -C1R7+C3R5 -C1r7+C3r5 - paddd mm4, mm7 ; B2 b2 - paddd mm2, mm4 ; A2+B2 a2+b2 - psubd mm0, mm4 ; a2-B2 a2-b2 - psrad mm2, %7 - psrad mm0, %7 - movq mm4, mm6 ; A3 a3 - paddd mm3, mm1 ; B3 b3 - paddd mm6, mm3 ; A3+B3 a3+b3 - psubd mm4, mm3 ; a3-B3 a3-b3 - psrad mm6, %7 - packssdw mm2, mm6 ; A3+B3 a3+b3 A2+B2 a2+b2 - movq [8 + %5], mm2 - psrad mm4, %7 - packssdw mm4, mm0 ; A2-B2 a2-b2 A3-B3 a3-b3 - movq [16 + %5], mm4 + movq m4, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m4, m0 ; C4R4+C4R0 C4r4+C4r0 + movq m5, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m0, m5 ; -C4R4+C4R0 -C4r4+C4r0 + movq m5, [coeffs + 64] ; C6 C2 C6 C2 + pmaddwd m5, m1 ; C6R6+C2R2 C6r6+C2r2 + movq m6, [coeffs + 80] ; -C2 C6 -C2 C6 + pmaddwd m1, m6 ; -C2R6+C6R2 -C2r6+C6r2 + movq m7, [coeffs + 96] ; C3 C1 C3 C1 + pmaddwd m7, m2 ; C3R3+C1R1 C3r3+C1r1 + paddd m4, [coeffs] + movq m6, m4 ; C4R4+C4R0 C4r4+C4r0 + paddd m4, m5 ; A0 a0 + psubd m6, m5 ; A3 a3 + movq m5, [coeffs + 112] ; C7 C5 C7 C5 + pmaddwd m5, m3 ; C7R7+C5R5 C7r7+C5r5 + paddd m0, [coeffs] + paddd m1, m0 ; A1 a1 + paddd m0, m0 + psubd m0, m1 ; A2 a2 + pmaddwd m2, [coeffs + 128] ; -C7R3+C3R1 -C7r3+C3r1 + paddd m7, m5 ; B0 b0 + movq m5, [coeffs + 144] ; -C5 -C1 -C5 -C1 + pmaddwd m5, m3 ; -C5R7-C1R5 -C5r7-C1r5 + paddd m7, m4 ; A0+B0 a0+b0 + paddd m4, m4 ; 2A0 2a0 + psubd m4, m7 ; A0-B0 a0-b0 + paddd m5, m2 ; B1 b1 + psrad m7, %7 + psrad m4, %7 + movq m2, m1 ; A1 a1 + paddd m1, m5 ; A1+B1 a1+b1 + psubd m2, m5 ; A1-B1 a1-b1 + psrad m1, %7 + psrad m2, %7 + packssdw m7, m1 ; A1+B1 a1+b1 A0+B0 a0+b0 + pshufd m7, m7, 0xD8 + packssdw m2, m4 ; A0-B0 a0-b0 A1-B1 a1-b1 + pshufd m2, m2, 0xD8 + movq [%5], m7 + movq m1, [blockq + %3] ; R3 R1 r3 r1 + movq m4, [coeffs + 160] ; -C1 C5 -C1 C5 + movq [24 + %5], m2 + pmaddwd m4, m1 ; -C1R3+C5R1 -C1r3+C5r1 + movq m7, [coeffs + 176] ; C3 C7 C3 C7 + pmaddwd m1, [coeffs + 192] ; -C5R3+C7R1 -C5r3+C7r1 + pmaddwd m7, m3 ; C3R7+C7R5 C3r7+C7r5 + movq m2, m0 ; A2 a2 + pmaddwd m3, [coeffs + 208] ; -C1R7+C3R5 -C1r7+C3r5 + paddd m4, m7 ; B2 b2 + paddd m2, m4 ; A2+B2 a2+b2 + psubd m0, m4 ; a2-B2 a2-b2 + psrad m2, %7 + psrad m0, %7 + movq m4, m6 ; A3 a3 + paddd m3, m1 ; B3 b3 + paddd m6, m3 ; A3+B3 a3+b3 + psubd m4, m3 ; a3-B3 a3-b3 + psrad m6, %7 + packssdw m2, m6 ; A3+B3 a3+b3 A2+B2 a2+b2 + pshufd m2, m2, 0xD8 + movq [8 + %5], m2 + psrad m4, %7 + packssdw m4, m0 ; A2-B2 a2-b2 A3-B3 a3-b3 + pshufd m4, m4, 0xD8 + movq [16 + %5], m4 %endmacro %macro IDCT1 6 - movq mm0, %1 ; R4 R0 r4 r0 - movq mm1, %2 ; R6 R2 r6 r2 - movq mm2, %3 ; R3 R1 r3 r1 - movq mm3, %4 ; R7 R5 r7 r5 - movq mm4, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm4, mm0 ; C4R4+C4R0 C4r4+C4r0 - movq mm5, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm0, mm5 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm5, [coeffs + 32] ; C6 C2 C6 C2 - pmaddwd mm5, mm1 ; C6R6+C2R2 C6r6+C2r2 - movq mm6, [coeffs + 40] ; -C2 C6 -C2 C6 - pmaddwd mm1, mm6 ; -C2R6+C6R2 -C2r6+C6r2 - movq mm6, mm4 ; C4R4+C4R0 C4r4+C4r0 - movq mm7, [coeffs + 48] ; C3 C1 C3 C1 - pmaddwd mm7, mm2 ; C3R3+C1R1 C3r3+C1r1 - paddd mm4, mm5 ; A0 a0 - psubd mm6, mm5 ; A3 a3 - movq mm5, mm0 ; -C4R4+C4R0 -C4r4+C4r0 - paddd mm0, mm1 ; A1 a1 - psubd mm5, mm1 ; A2 a2 - movq mm1, [coeffs + 56] ; C7 C5 C7 C5 - pmaddwd mm1, mm3 ; C7R7+C5R5 C7r7+C5r5 - pmaddwd mm2, [coeffs + 64] ; -C7R3+C3R1 -C7r3+C3r1 - paddd mm7, mm1 ; B0 b0 - movq mm1, [coeffs + 72] ; -C5 -C1 -C5 -C1 - pmaddwd mm1, mm3 ; -C5R7-C1R5 -C5r7-C1r5 - paddd mm7, mm4 ; A0+B0 a0+b0 - paddd mm4, mm4 ; 2A0 2a0 - psubd mm4, mm7 ; A0-B0 a0-b0 - paddd mm1, mm2 ; B1 b1 - psrad mm7, %6 - psrad mm4, %6 - movq mm2, mm0 ; A1 a1 - paddd mm0, mm1 ; A1+B1 a1+b1 - psubd mm2, mm1 ; A1-B1 a1-b1 - psrad mm0, %6 - psrad mm2, %6 - packssdw mm7, mm7 ; A0+B0 a0+b0 - movd [%5], mm7 - packssdw mm0, mm0 ; A1+B1 a1+b1 - movd [16 + %5], mm0 - packssdw mm2, mm2 ; A1-B1 a1-b1 - movd [96 + %5], mm2 - packssdw mm4, mm4 ; A0-B0 a0-b0 - movd [112 + %5], mm4 - movq mm0, %3 ; R3 R1 r3 r1 - movq mm4, [coeffs + 80] ; -C1 C5 -C1 C5 - pmaddwd mm4, mm0 ; -C1R3+C5R1 -C1r3+C5r1 - movq mm7, [coeffs + 88] ; C3 C7 C3 C7 - pmaddwd mm0, [coeffs + 96] ; -C5R3+C7R1 -C5r3+C7r1 - pmaddwd mm7, mm3 ; C3R7+C7R5 C3r7+C7r5 - movq mm2, mm5 ; A2 a2 - pmaddwd mm3, [coeffs + 104] ; -C1R7+C3R5 -C1r7+C3r5 - paddd mm4, mm7 ; B2 b2 - paddd mm2, mm4 ; A2+B2 a2+b2 - psubd mm5, mm4 ; a2-B2 a2-b2 - psrad mm2, %6 - psrad mm5, %6 - movq mm4, mm6 ; A3 a3 - paddd mm3, mm0 ; B3 b3 - paddd mm6, mm3 ; A3+B3 a3+b3 - psubd mm4, mm3 ; a3-B3 a3-b3 - psrad mm6, %6 - psrad mm4, %6 - packssdw mm2, mm2 ; A2+B2 a2+b2 - packssdw mm6, mm6 ; A3+B3 a3+b3 - movd [32 + %5], mm2 - packssdw mm4, mm4 ; A3-B3 a3-b3 - packssdw mm5, mm5 ; A2-B2 a2-b2 - movd [48 + %5], mm6 - movd [64 + %5], mm4 - movd [80 + %5], mm5 + mova m0, %1 ; R4 R0 r4 r0 + mova m1, %2 ; R6 R2 r6 r2 + mova m2, %3 ; R3 R1 r3 r1 + mova m3, %4 ; R7 R5 r7 r5 + mova m4, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m4, m0 ; C4R4+C4R0 C4r4+C4r0 + mova m5, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m0, m5 ; -C4R4+C4R0 -C4r4+C4r0 + mova m5, [coeffs + 64] ; C6 C2 C6 C2 + pmaddwd m5, m1 ; C6R6+C2R2 C6r6+C2r2 + mova m6, [coeffs + 80] ; -C2 C6 -C2 C6 + pmaddwd m1, m6 ; -C2R6+C6R2 -C2r6+C6r2 + mova m6, m4 ; C4R4+C4R0 C4r4+C4r0 + mova m7, [coeffs + 96] ; C3 C1 C3 C1 + pmaddwd m7, m2 ; C3R3+C1R1 C3r3+C1r1 + paddd m4, m5 ; A0 a0 + psubd m6, m5 ; A3 a3 + mova m5, m0 ; -C4R4+C4R0 -C4r4+C4r0 + paddd m0, m1 ; A1 a1 + psubd m5, m1 ; A2 a2 + mova m1, [coeffs + 112] ; C7 C5 C7 C5 + pmaddwd m1, m3 ; C7R7+C5R5 C7r7+C5r5 + pmaddwd m2, [coeffs + 128] ; -C7R3+C3R1 -C7r3+C3r1 + paddd m7, m1 ; B0 b0 + mova m1, [coeffs + 144] ; -C5 -C1 -C5 -C1 + pmaddwd m1, m3 ; -C5R7-C1R5 -C5r7-C1r5 + paddd m7, m4 ; A0+B0 a0+b0 + paddd m4, m4 ; 2A0 2a0 + psubd m4, m7 ; A0-B0 a0-b0 + paddd m1, m2 ; B1 b1 + psrad m7, %6 + psrad m4, %6 + mova m2, m0 ; A1 a1 + paddd m0, m1 ; A1+B1 a1+b1 + psubd m2, m1 ; A1-B1 a1-b1 + psrad m0, %6 + psrad m2, %6 + packssdw m7, m7 ; A0+B0 a0+b0 + movq [%5], m7 + packssdw m0, m0 ; A1+B1 a1+b1 + movq [16 + %5], m0 + packssdw m2, m2 ; A1-B1 a1-b1 + movq [96 + %5], m2 + packssdw m4, m4 ; A0-B0 a0-b0 + movq [112 + %5], m4 + mova m0, %3 ; R3 R1 r3 r1 + mova m4, [coeffs + 160] ; -C1 C5 -C1 C5 + pmaddwd m4, m0 ; -C1R3+C5R1 -C1r3+C5r1 + mova m7, [coeffs + 176] ; C3 C7 C3 C7 + pmaddwd m0, [coeffs + 192] ; -C5R3+C7R1 -C5r3+C7r1 + pmaddwd m7, m3 ; C3R7+C7R5 C3r7+C7r5 + mova m2, m5 ; A2 a2 + pmaddwd m3, [coeffs + 208] ; -C1R7+C3R5 -C1r7+C3r5 + paddd m4, m7 ; B2 b2 + paddd m2, m4 ; A2+B2 a2+b2 + psubd m5, m4 ; a2-B2 a2-b2 + psrad m2, %6 + psrad m5, %6 + mova m4, m6 ; A3 a3 + paddd m3, m0 ; B3 b3 + paddd m6, m3 ; A3+B3 a3+b3 + psubd m4, m3 ; a3-B3 a3-b3 + psrad m6, %6 + psrad m4, %6 + packssdw m2, m2 ; A2+B2 a2+b2 + packssdw m6, m6 ; A3+B3 a3+b3 + movq [32 + %5], m2 + packssdw m4, m4 ; A3-B3 a3-b3 + packssdw m5, m5 ; A2-B2 a2-b2 + movq [48 + %5], m6 + movq [64 + %5], m4 + movq [80 + %5], m5 %endmacro %macro IDCT2 6 - movq mm0, %1 ; R4 R0 r4 r0 - movq mm1, %2 ; R6 R2 r6 r2 - movq mm3, %4 ; R7 R5 r7 r5 - movq mm4, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm4, mm0 ; C4R4+C4R0 C4r4+C4r0 - movq mm5, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm0, mm5 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm5, [coeffs + 32] ; C6 C2 C6 C2 - pmaddwd mm5, mm1 ; C6R6+C2R2 C6r6+C2r2 - movq mm6, [coeffs + 40] ; -C2 C6 -C2 C6 - pmaddwd mm1, mm6 ; -C2R6+C6R2 -C2r6+C6r2 - movq mm6, mm4 ; C4R4+C4R0 C4r4+C4r0 - paddd mm4, mm5 ; A0 a0 - psubd mm6, mm5 ; A3 a3 - movq mm5, mm0 ; -C4R4+C4R0 -C4r4+C4r0 - paddd mm0, mm1 ; A1 a1 - psubd mm5, mm1 ; A2 a2 - movq mm1, [coeffs + 56] ; C7 C5 C7 C5 - pmaddwd mm1, mm3 ; C7R7+C5R5 C7r7+C5r5 - movq mm7, [coeffs + 72] ; -C5 -C1 -C5 -C1 - pmaddwd mm7, mm3 ; -C5R7-C1R5 -C5r7-C1r5 - paddd mm1, mm4 ; A0+B0 a0+b0 - paddd mm4, mm4 ; 2A0 2a0 - psubd mm4, mm1 ; A0-B0 a0-b0 - psrad mm1, %6 - psrad mm4, %6 - movq mm2, mm0 ; A1 a1 - paddd mm0, mm7 ; A1+B1 a1+b1 - psubd mm2, mm7 ; A1-B1 a1-b1 - psrad mm0, %6 - psrad mm2, %6 - packssdw mm1, mm1 ; A0+B0 a0+b0 - movd [%5], mm1 - packssdw mm0, mm0 ; A1+B1 a1+b1 - movd [16 + %5], mm0 - packssdw mm2, mm2 ; A1-B1 a1-b1 - movd [96 + %5], mm2 - packssdw mm4, mm4 ; A0-B0 a0-b0 - movd [112 + %5], mm4 - movq mm1, [coeffs + 88] ; C3 C7 C3 C7 - pmaddwd mm1, mm3 ; C3R7+C7R5 C3r7+C7r5 - movq mm2, mm5 ; A2 a2 - pmaddwd mm3, [coeffs + 104] ; -C1R7+C3R5 -C1r7+C3r5 - paddd mm2, mm1 ; A2+B2 a2+b2 - psubd mm5, mm1 ; a2-B2 a2-b2 - psrad mm2, %6 - psrad mm5, %6 - movq mm1, mm6 ; A3 a3 - paddd mm6, mm3 ; A3+B3 a3+b3 - psubd mm1, mm3 ; a3-B3 a3-b3 - psrad mm6, %6 - psrad mm1, %6 - packssdw mm2, mm2 ; A2+B2 a2+b2 - packssdw mm6, mm6 ; A3+B3 a3+b3 - movd [32 + %5], mm2 - packssdw mm1, mm1 ; A3-B3 a3-b3 - packssdw mm5, mm5 ; A2-B2 a2-b2 - movd [48 + %5], mm6 - movd [64 + %5], mm1 - movd [80 + %5], mm5 + mova m0, %1 ; R4 R0 r4 r0 + mova m1, %2 ; R6 R2 r6 r2 + mova m3, %4 ; R7 R5 r7 r5 + mova m4, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m4, m0 ; C4R4+C4R0 C4r4+C4r0 + mova m5, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m0, m5 ; -C4R4+C4R0 -C4r4+C4r0 + mova m5, [coeffs + 64] ; C6 C2 C6 C2 + pmaddwd m5, m1 ; C6R6+C2R2 C6r6+C2r2 + mova m6, [coeffs + 80] ; -C2 C6 -C2 C6 + pmaddwd m1, m6 ; -C2R6+C6R2 -C2r6+C6r2 + mova m6, m4 ; C4R4+C4R0 C4r4+C4r0 + paddd m4, m5 ; A0 a0 + psubd m6, m5 ; A3 a3 + mova m5, m0 ; -C4R4+C4R0 -C4r4+C4r0 + paddd m0, m1 ; A1 a1 + psubd m5, m1 ; A2 a2 + mova m1, [coeffs + 112] ; C7 C5 C7 C5 + pmaddwd m1, m3 ; C7R7+C5R5 C7r7+C5r5 + mova m7, [coeffs + 144] ; -C5 -C1 -C5 -C1 + pmaddwd m7, m3 ; -C5R7-C1R5 -C5r7-C1r5 + paddd m1, m4 ; A0+B0 a0+b0 + paddd m4, m4 ; 2A0 2a0 + psubd m4, m1 ; A0-B0 a0-b0 + psrad m1, %6 + psrad m4, %6 + mova m2, m0 ; A1 a1 + paddd m0, m7 ; A1+B1 a1+b1 + psubd m2, m7 ; A1-B1 a1-b1 + psrad m0, %6 + psrad m2, %6 + packssdw m1, m1 ; A0+B0 a0+b0 + movq [%5], m1 + packssdw m0, m0 ; A1+B1 a1+b1 + movq [16 + %5], m0 + packssdw m2, m2 ; A1-B1 a1-b1 + movq [96 + %5], m2 + packssdw m4, m4 ; A0-B0 a0-b0 + movq [112 + %5], m4 + mova m1, [coeffs + 176] ; C3 C7 C3 C7 + pmaddwd m1, m3 ; C3R7+C7R5 C3r7+C7r5 + mova m2, m5 ; A2 a2 + pmaddwd m3, [coeffs + 208] ; -C1R7+C3R5 -C1r7+C3r5 + paddd m2, m1 ; A2+B2 a2+b2 + psubd m5, m1 ; a2-B2 a2-b2 + psrad m2, %6 + psrad m5, %6 + mova m1, m6 ; A3 a3 + paddd m6, m3 ; A3+B3 a3+b3 + psubd m1, m3 ; a3-B3 a3-b3 + psrad m6, %6 + psrad m1, %6 + packssdw m2, m2 ; A2+B2 a2+b2 + packssdw m6, m6 ; A3+B3 a3+b3 + movq [32 + %5], m2 + packssdw m1, m1 ; A3-B3 a3-b3 + packssdw m5, m5 ; A2-B2 a2-b2 + movq [48 + %5], m6 + movq [64 + %5], m1 + movq [80 + %5], m5 %endmacro %macro IDCT3 6 - movq mm0, %1 ; R4 R0 r4 r0 - movq mm3, %4 ; R7 R5 r7 r5 - movq mm4, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm4, mm0 ; C4R4+C4R0 C4r4+C4r0 - movq mm5, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm0, mm5 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm6, mm4 ; C4R4+C4R0 C4r4+C4r0 - movq mm5, mm0 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm1, [coeffs + 56] ; C7 C5 C7 C5 - pmaddwd mm1, mm3 ; C7R7+C5R5 C7r7+C5r5 - movq mm7, [coeffs + 72] ; -C5 -C1 -C5 -C1 - pmaddwd mm7, mm3 ; -C5R7-C1R5 -C5r7-C1r5 - paddd mm1, mm4 ; A0+B0 a0+b0 - paddd mm4, mm4 ; 2A0 2a0 - psubd mm4, mm1 ; A0-B0 a0-b0 - psrad mm1, %6 - psrad mm4, %6 - movq mm2, mm0 ; A1 a1 - paddd mm0, mm7 ; A1+B1 a1+b1 - psubd mm2, mm7 ; A1-B1 a1-b1 - psrad mm0, %6 - psrad mm2, %6 - packssdw mm1, mm1 ; A0+B0 a0+b0 - movd [%5], mm1 - packssdw mm0, mm0 ; A1+B1 a1+b1 - movd [16 + %5], mm0 - packssdw mm2, mm2 ; A1-B1 a1-b1 - movd [96 + %5], mm2 - packssdw mm4, mm4 ; A0-B0 a0-b0 - movd [112 + %5], mm4 - movq mm1, [coeffs + 88] ; C3 C7 C3 C7 - pmaddwd mm1, mm3 ; C3R7+C7R5 C3r7+C7r5 - movq mm2, mm5 ; A2 a2 - pmaddwd mm3, [coeffs + 104] ; -C1R7+C3R5 -C1r7+C3r5 - paddd mm2, mm1 ; A2+B2 a2+b2 - psubd mm5, mm1 ; a2-B2 a2-b2 - psrad mm2, %6 - psrad mm5, %6 - movq mm1, mm6 ; A3 a3 - paddd mm6, mm3 ; A3+B3 a3+b3 - psubd mm1, mm3 ; a3-B3 a3-b3 - psrad mm6, %6 - psrad mm1, %6 - packssdw mm2, mm2 ; A2+B2 a2+b2 - packssdw mm6, mm6 ; A3+B3 a3+b3 - movd [32 + %5], mm2 - packssdw mm1, mm1 ; A3-B3 a3-b3 - packssdw mm5, mm5 ; A2-B2 a2-b2 - movd [48 + %5], mm6 - movd [64 + %5], mm1 - movd [80 + %5], mm5 + mova m0, %1 ; R4 R0 r4 r0 + mova m3, %4 ; R7 R5 r7 r5 + mova m4, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m4, m0 ; C4R4+C4R0 C4r4+C4r0 + mova m5, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m0, m5 ; -C4R4+C4R0 -C4r4+C4r0 + mova m6, m4 ; C4R4+C4R0 C4r4+C4r0 + mova m5, m0 ; -C4R4+C4R0 -C4r4+C4r0 + mova m1, [coeffs + 112] ; C7 C5 C7 C5 + pmaddwd m1, m3 ; C7R7+C5R5 C7r7+C5r5 + mova m7, [coeffs + 144] ; -C5 -C1 -C5 -C1 + pmaddwd m7, m3 ; -C5R7-C1R5 -C5r7-C1r5 + paddd m1, m4 ; A0+B0 a0+b0 + paddd m4, m4 ; 2A0 2a0 + psubd m4, m1 ; A0-B0 a0-b0 + psrad m1, %6 + psrad m4, %6 + mova m2, m0 ; A1 a1 + paddd m0, m7 ; A1+B1 a1+b1 + psubd m2, m7 ; A1-B1 a1-b1 + psrad m0, %6 + psrad m2, %6 + packssdw m1, m1 ; A0+B0 a0+b0 + movq [%5], m1 + packssdw m0, m0 ; A1+B1 a1+b1 + movq [16 + %5], m0 + packssdw m2, m2 ; A1-B1 a1-b1 + movq [96 + %5], m2 + packssdw m4, m4 ; A0-B0 a0-b0 + movq [112 + %5], m4 + mova m1, [coeffs + 176] ; C3 C7 C3 C7 + pmaddwd m1, m3 ; C3R7+C7R5 C3r7+C7r5 + mova m2, m5 ; A2 a2 + pmaddwd m3, [coeffs + 208] ; -C1R7+C3R5 -C1r7+C3r5 + paddd m2, m1 ; A2+B2 a2+b2 + psubd m5, m1 ; a2-B2 a2-b2 + psrad m2, %6 + psrad m5, %6 + mova m1, m6 ; A3 a3 + paddd m6, m3 ; A3+B3 a3+b3 + psubd m1, m3 ; a3-B3 a3-b3 + psrad m6, %6 + psrad m1, %6 + packssdw m2, m2 ; A2+B2 a2+b2 + packssdw m6, m6 ; A3+B3 a3+b3 + movq [32 + %5], m2 + packssdw m1, m1 ; A3-B3 a3-b3 + packssdw m5, m5 ; A2-B2 a2-b2 + movq [48 + %5], m6 + movq [64 + %5], m1 + movq [80 + %5], m5 %endmacro %macro IDCT4 6 - movq mm0, %1 ; R4 R0 r4 r0 - movq mm2, %3 ; R3 R1 r3 r1 - movq mm3, %4 ; R7 R5 r7 r5 - movq mm4, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm4, mm0 ; C4R4+C4R0 C4r4+C4r0 - movq mm5, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm0, mm5 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm6, mm4 ; C4R4+C4R0 C4r4+C4r0 - movq mm7, [coeffs + 48] ; C3 C1 C3 C1 - pmaddwd mm7, mm2 ; C3R3+C1R1 C3r3+C1r1 - movq mm5, mm0 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm1, [coeffs + 56] ; C7 C5 C7 C5 - pmaddwd mm1, mm3 ; C7R7+C5R5 C7r7+C5r5 - pmaddwd mm2, [coeffs + 64] ; -C7R3+C3R1 -C7r3+C3r1 - paddd mm7, mm1 ; B0 b0 - movq mm1, [coeffs + 72] ; -C5 -C1 -C5 -C1 - pmaddwd mm1, mm3 ; -C5R7-C1R5 -C5r7-C1r5 - paddd mm7, mm4 ; A0+B0 a0+b0 - paddd mm4, mm4 ; 2A0 2a0 - psubd mm4, mm7 ; A0-B0 a0-b0 - paddd mm1, mm2 ; B1 b1 - psrad mm7, %6 - psrad mm4, %6 - movq mm2, mm0 ; A1 a1 - paddd mm0, mm1 ; A1+B1 a1+b1 - psubd mm2, mm1 ; A1-B1 a1-b1 - psrad mm0, %6 - psrad mm2, %6 - packssdw mm7, mm7 ; A0+B0 a0+b0 - movd [%5], mm7 - packssdw mm0, mm0 ; A1+B1 a1+b1 - movd [16 + %5], mm0 - packssdw mm2, mm2 ; A1-B1 a1-b1 - movd [96 + %5], mm2 - packssdw mm4, mm4 ; A0-B0 a0-b0 - movd [112 + %5], mm4 - movq mm0, %3 ; R3 R1 r3 r1 - movq mm4, [coeffs + 80] ; -C1 C5 -C1 C5 - pmaddwd mm4, mm0 ; -C1R3+C5R1 -C1r3+C5r1 - movq mm7, [coeffs + 88] ; C3 C7 C3 C7 - pmaddwd mm0, [coeffs + 96] ; -C5R3+C7R1 -C5r3+C7r1 - pmaddwd mm7, mm3 ; C3R7+C7R5 C3r7+C7r5 - movq mm2, mm5 ; A2 a2 - pmaddwd mm3, [coeffs + 104] ; -C1R7+C3R5 -C1r7+C3r5 - paddd mm4, mm7 ; B2 b2 - paddd mm2, mm4 ; A2+B2 a2+b2 - psubd mm5, mm4 ; a2-B2 a2-b2 - psrad mm2, %6 - psrad mm5, %6 - movq mm4, mm6 ; A3 a3 - paddd mm3, mm0 ; B3 b3 - paddd mm6, mm3 ; A3+B3 a3+b3 - psubd mm4, mm3 ; a3-B3 a3-b3 - psrad mm6, %6 - psrad mm4, %6 - packssdw mm2, mm2 ; A2+B2 a2+b2 - packssdw mm6, mm6 ; A3+B3 a3+b3 - movd [32 + %5], mm2 - packssdw mm4, mm4 ; A3-B3 a3-b3 - packssdw mm5, mm5 ; A2-B2 a2-b2 - movd [48 + %5], mm6 - movd [64 + %5], mm4 - movd [80 + %5], mm5 + mova m0, %1 ; R4 R0 r4 r0 + mova m2, %3 ; R3 R1 r3 r1 + mova m3, %4 ; R7 R5 r7 r5 + mova m4, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m4, m0 ; C4R4+C4R0 C4r4+C4r0 + mova m5, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m0, m5 ; -C4R4+C4R0 -C4r4+C4r0 + mova m6, m4 ; C4R4+C4R0 C4r4+C4r0 + mova m7, [coeffs + 96] ; C3 C1 C3 C1 + pmaddwd m7, m2 ; C3R3+C1R1 C3r3+C1r1 + mova m5, m0 ; -C4R4+C4R0 -C4r4+C4r0 + mova m1, [coeffs + 112] ; C7 C5 C7 C5 + pmaddwd m1, m3 ; C7R7+C5R5 C7r7+C5r5 + pmaddwd m2, [coeffs + 128] ; -C7R3+C3R1 -C7r3+C3r1 + paddd m7, m1 ; B0 b0 + mova m1, [coeffs + 144] ; -C5 -C1 -C5 -C1 + pmaddwd m1, m3 ; -C5R7-C1R5 -C5r7-C1r5 + paddd m7, m4 ; A0+B0 a0+b0 + paddd m4, m4 ; 2A0 2a0 + psubd m4, m7 ; A0-B0 a0-b0 + paddd m1, m2 ; B1 b1 + psrad m7, %6 + psrad m4, %6 + mova m2, m0 ; A1 a1 + paddd m0, m1 ; A1+B1 a1+b1 + psubd m2, m1 ; A1-B1 a1-b1 + psrad m0, %6 + psrad m2, %6 + packssdw m7, m7 ; A0+B0 a0+b0 + movq [%5], m7 + packssdw m0, m0 ; A1+B1 a1+b1 + movq [16 + %5], m0 + packssdw m2, m2 ; A1-B1 a1-b1 + movq [96 + %5], m2 + packssdw m4, m4 ; A0-B0 a0-b0 + movq [112 + %5], m4 + mova m0, %3 ; R3 R1 r3 r1 + mova m4, [coeffs + 160] ; -C1 C5 -C1 C5 + pmaddwd m4, m0 ; -C1R3+C5R1 -C1r3+C5r1 + mova m7, [coeffs + 176] ; C3 C7 C3 C7 + pmaddwd m0, [coeffs + 192] ; -C5R3+C7R1 -C5r3+C7r1 + pmaddwd m7, m3 ; C3R7+C7R5 C3r7+C7r5 + mova m2, m5 ; A2 a2 + pmaddwd m3, [coeffs + 208] ; -C1R7+C3R5 -C1r7+C3r5 + paddd m4, m7 ; B2 b2 + paddd m2, m4 ; A2+B2 a2+b2 + psubd m5, m4 ; a2-B2 a2-b2 + psrad m2, %6 + psrad m5, %6 + mova m4, m6 ; A3 a3 + paddd m3, m0 ; B3 b3 + paddd m6, m3 ; A3+B3 a3+b3 + psubd m4, m3 ; a3-B3 a3-b3 + psrad m6, %6 + psrad m4, %6 + packssdw m2, m2 ; A2+B2 a2+b2 + packssdw m6, m6 ; A3+B3 a3+b3 + movq [32 + %5], m2 + packssdw m4, m4 ; A3-B3 a3-b3 + packssdw m5, m5 ; A2-B2 a2-b2 + movq [48 + %5], m6 + movq [64 + %5], m4 + movq [80 + %5], m5 %endmacro %macro IDCT5 6 - movq mm0, %1 ; R4 R0 r4 r0 - movq mm2, %3 ; R3 R1 r3 r1 - movq mm4, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm4, mm0 ; C4R4+C4R0 C4r4+C4r0 - movq mm5, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm0, mm5 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm6, mm4 ; C4R4+C4R0 C4r4+C4r0 - movq mm7, [coeffs + 48] ; C3 C1 C3 C1 - pmaddwd mm7, mm2 ; C3R3+C1R1 C3r3+C1r1 - movq mm5, mm0 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm3, [coeffs + 64] - pmaddwd mm3, mm2 ; -C7R3+C3R1 -C7r3+C3r1 - paddd mm7, mm4 ; A0+B0 a0+b0 - paddd mm4, mm4 ; 2A0 2a0 - psubd mm4, mm7 ; A0-B0 a0-b0 - psrad mm7, %6 - psrad mm4, %6 - movq mm1, mm0 ; A1 a1 - paddd mm0, mm3 ; A1+B1 a1+b1 - psubd mm1, mm3 ; A1-B1 a1-b1 - psrad mm0, %6 - psrad mm1, %6 - packssdw mm7, mm7 ; A0+B0 a0+b0 - movd [%5], mm7 - packssdw mm0, mm0 ; A1+B1 a1+b1 - movd [16 + %5], mm0 - packssdw mm1, mm1 ; A1-B1 a1-b1 - movd [96 + %5], mm1 - packssdw mm4, mm4 ; A0-B0 a0-b0 - movd [112 + %5], mm4 - movq mm4, [coeffs + 80] ; -C1 C5 -C1 C5 - pmaddwd mm4, mm2 ; -C1R3+C5R1 -C1r3+C5r1 - pmaddwd mm2, [coeffs + 96] ; -C5R3+C7R1 -C5r3+C7r1 - movq mm1, mm5 ; A2 a2 - paddd mm1, mm4 ; A2+B2 a2+b2 - psubd mm5, mm4 ; a2-B2 a2-b2 - psrad mm1, %6 - psrad mm5, %6 - movq mm4, mm6 ; A3 a3 - paddd mm6, mm2 ; A3+B3 a3+b3 - psubd mm4, mm2 ; a3-B3 a3-b3 - psrad mm6, %6 - psrad mm4, %6 - packssdw mm1, mm1 ; A2+B2 a2+b2 - packssdw mm6, mm6 ; A3+B3 a3+b3 - movd [32 + %5], mm1 - packssdw mm4, mm4 ; A3-B3 a3-b3 - packssdw mm5, mm5 ; A2-B2 a2-b2 - movd [48 + %5], mm6 - movd [64 + %5], mm4 - movd [80 + %5], mm5 + mova m0, %1 ; R4 R0 r4 r0 + mova m2, %3 ; R3 R1 r3 r1 + mova m4, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m4, m0 ; C4R4+C4R0 C4r4+C4r0 + mova m5, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m0, m5 ; -C4R4+C4R0 -C4r4+C4r0 + mova m6, m4 ; C4R4+C4R0 C4r4+C4r0 + mova m7, [coeffs + 96] ; C3 C1 C3 C1 + pmaddwd m7, m2 ; C3R3+C1R1 C3r3+C1r1 + mova m5, m0 ; -C4R4+C4R0 -C4r4+C4r0 + mova m3, [coeffs + 128] + pmaddwd m3, m2 ; -C7R3+C3R1 -C7r3+C3r1 + paddd m7, m4 ; A0+B0 a0+b0 + paddd m4, m4 ; 2A0 2a0 + psubd m4, m7 ; A0-B0 a0-b0 + psrad m7, %6 + psrad m4, %6 + mova m1, m0 ; A1 a1 + paddd m0, m3 ; A1+B1 a1+b1 + psubd m1, m3 ; A1-B1 a1-b1 + psrad m0, %6 + psrad m1, %6 + packssdw m7, m7 ; A0+B0 a0+b0 + movq [%5], m7 + packssdw m0, m0 ; A1+B1 a1+b1 + movq [16 + %5], m0 + packssdw m1, m1 ; A1-B1 a1-b1 + movq [96 + %5], m1 + packssdw m4, m4 ; A0-B0 a0-b0 + movq [112 + %5], m4 + mova m4, [coeffs + 160] ; -C1 C5 -C1 C5 + pmaddwd m4, m2 ; -C1R3+C5R1 -C1r3+C5r1 + pmaddwd m2, [coeffs + 192] ; -C5R3+C7R1 -C5r3+C7r1 + mova m1, m5 ; A2 a2 + paddd m1, m4 ; A2+B2 a2+b2 + psubd m5, m4 ; a2-B2 a2-b2 + psrad m1, %6 + psrad m5, %6 + mova m4, m6 ; A3 a3 + paddd m6, m2 ; A3+B3 a3+b3 + psubd m4, m2 ; a3-B3 a3-b3 + psrad m6, %6 + psrad m4, %6 + packssdw m1, m1 ; A2+B2 a2+b2 + packssdw m6, m6 ; A3+B3 a3+b3 + movq [32 + %5], m1 + packssdw m4, m4 ; A3-B3 a3-b3 + packssdw m5, m5 ; A2-B2 a2-b2 + movq [48 + %5], m6 + movq [64 + %5], m4 + movq [80 + %5], m5 %endmacro %macro IDCT6 6 - movq mm0, [%1] ; R4 R0 r4 r0 - movq mm1, [%2] ; R6 R2 r6 r2 - movq mm4, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm4, mm0 ; C4R4+C4R0 C4r4+C4r0 - movq mm5, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm0, mm5 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm5, [coeffs + 32] ; C6 C2 C6 C2 - pmaddwd mm5, mm1 ; C6R6+C2R2 C6r6+C2r2 - movq mm6, [coeffs + 40] ; -C2 C6 -C2 C6 - pmaddwd mm1, mm6 ; -C2R6+C6R2 -C2r6+C6r2 - movq mm6, mm4 ; C4R4+C4R0 C4r4+C4r0 - paddd mm4, mm5 ; A0 a0 - psubd mm6, mm5 ; A3 a3 - movq mm5, mm0 ; -C4R4+C4R0 -C4r4+C4r0 - paddd mm0, mm1 ; A1 a1 - psubd mm5, mm1 ; A2 a2 - movq mm2, [8 + %1] ; R4 R0 r4 r0 - movq mm3, [8 + %2] ; R6 R2 r6 r2 - movq mm1, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm1, mm2 ; C4R4+C4R0 C4r4+C4r0 - movq mm7, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm2, mm7 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm7, [coeffs + 32] ; C6 C2 C6 C2 - pmaddwd mm7, mm3 ; C6R6+C2R2 C6r6+C2r2 - pmaddwd mm3, [coeffs + 40] ; -C2R6+C6R2 -C2r6+C6r2 - paddd mm7, mm1 ; A0 a0 - paddd mm1, mm1 ; 2C0 2c0 - psubd mm1, mm7 ; A3 a3 - paddd mm3, mm2 ; A1 a1 - paddd mm2, mm2 ; 2C1 2c1 - psubd mm2, mm3 ; A2 a2 - psrad mm4, %6 - psrad mm7, %6 - psrad mm3, %6 - packssdw mm4, mm7 ; A0 a0 - movq [%5], mm4 - psrad mm0, %6 - packssdw mm0, mm3 ; A1 a1 - movq [16 + %5], mm0 - movq [96 + %5], mm0 - movq [112 + %5], mm4 - psrad mm5, %6 - psrad mm6, %6 - psrad mm2, %6 - packssdw mm5, mm2 ; A2-B2 a2-b2 - movq [32 + %5], mm5 - psrad mm1, %6 - packssdw mm6, mm1 ; A3+B3 a3+b3 - movq [48 + %5], mm6 - movq [64 + %5], mm6 - movq [80 + %5], mm5 + movq m0, [%1] ; R4 R0 r4 r0 + movhps m0, [%1 + 16] + movq m1, [%2] ; R6 R2 r6 r2 + movhps m1, [%2 + 16] + mova m4, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m4, m0 ; C4R4+C4R0 C4r4+C4r0 + mova m5, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m0, m5 ; -C4R4+C4R0 -C4r4+C4r0 + mova m5, [coeffs + 64] ; C6 C2 C6 C2 + pmaddwd m5, m1 ; C6R6+C2R2 C6r6+C2r2 + mova m6, [coeffs + 80] ; -C2 C6 -C2 C6 + pmaddwd m1, m6 ; -C2R6+C6R2 -C2r6+C6r2 + mova m6, m4 ; C4R4+C4R0 C4r4+C4r0 + paddd m4, m5 ; A0 a0 + psubd m6, m5 ; A3 a3 + mova m5, m0 ; -C4R4+C4R0 -C4r4+C4r0 + paddd m0, m1 ; A1 a1 + psubd m5, m1 ; A2 a2 + movq m2, [%1 + 8] ; R4 R0 r4 r0 + movhps m2, [%1 + 24] + movq m3, [%2 + 8] ; R6 R2 r6 r2 + movhps m3, [%2 + 24] + mova m1, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m1, m2 ; C4R4+C4R0 C4r4+C4r0 + mova m7, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m2, m7 ; -C4R4+C4R0 -C4r4+C4r0 + mova m7, [coeffs + 64] ; C6 C2 C6 C2 + pmaddwd m7, m3 ; C6R6+C2R2 C6r6+C2r2 + pmaddwd m3, [coeffs + 80] ; -C2R6+C6R2 -C2r6+C6r2 + paddd m7, m1 ; A0 a0 + paddd m1, m1 ; 2C0 2c0 + psubd m1, m7 ; A3 a3 + paddd m3, m2 ; A1 a1 + paddd m2, m2 ; 2C1 2c1 + psubd m2, m3 ; A2 a2 + psrad m4, %6 + psrad m7, %6 + psrad m3, %6 + packssdw m4, m7 ; A0 a0 + pshufd m4, m4, 0xD8 + mova [%5], m4 + psrad m0, %6 + packssdw m0, m3 ; A1 a1 + pshufd m0, m0, 0xD8 + mova [16 + %5], m0 + mova [96 + %5], m0 + mova [112 + %5], m4 + psrad m5, %6 + psrad m6, %6 + psrad m2, %6 + packssdw m5, m2 ; A2-B2 a2-b2 + pshufd m5, m5, 0xD8 + mova [32 + %5], m5 + psrad m1, %6 + packssdw m6, m1 ; A3+B3 a3+b3 + pshufd m6, m6, 0xD8 + mova [48 + %5], m6 + mova [64 + %5], m6 + mova [80 + %5], m5 %endmacro %macro IDCT7 6 - movq mm0, %1 ; R4 R0 r4 r0 - movq mm1, %2 ; R6 R2 r6 r2 - movq mm2, %3 ; R3 R1 r3 r1 - movq mm4, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm4, mm0 ; C4R4+C4R0 C4r4+C4r0 - movq mm5, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm0, mm5 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm5, [coeffs + 32] ; C6 C2 C6 C2 - pmaddwd mm5, mm1 ; C6R6+C2R2 C6r6+C2r2 - movq mm6, [coeffs + 40] ; -C2 C6 -C2 C6 - pmaddwd mm1, mm6 ; -C2R6+C6R2 -C2r6+C6r2 - movq mm6, mm4 ; C4R4+C4R0 C4r4+C4r0 - movq mm7, [coeffs + 48] ; C3 C1 C3 C1 - pmaddwd mm7, mm2 ; C3R3+C1R1 C3r3+C1r1 - paddd mm4, mm5 ; A0 a0 - psubd mm6, mm5 ; A3 a3 - movq mm5, mm0 ; -C4R4+C4R0 -C4r4+C4r0 - paddd mm0, mm1 ; A1 a1 - psubd mm5, mm1 ; A2 a2 - movq mm1, [coeffs + 64] - pmaddwd mm1, mm2 ; -C7R3+C3R1 -C7r3+C3r1 - paddd mm7, mm4 ; A0+B0 a0+b0 - paddd mm4, mm4 ; 2A0 2a0 - psubd mm4, mm7 ; A0-B0 a0-b0 - psrad mm7, %6 - psrad mm4, %6 - movq mm3, mm0 ; A1 a1 - paddd mm0, mm1 ; A1+B1 a1+b1 - psubd mm3, mm1 ; A1-B1 a1-b1 - psrad mm0, %6 - psrad mm3, %6 - packssdw mm7, mm7 ; A0+B0 a0+b0 - movd [%5], mm7 - packssdw mm0, mm0 ; A1+B1 a1+b1 - movd [16 + %5], mm0 - packssdw mm3, mm3 ; A1-B1 a1-b1 - movd [96 + %5], mm3 - packssdw mm4, mm4 ; A0-B0 a0-b0 - movd [112 + %5], mm4 - movq mm4, [coeffs + 80] ; -C1 C5 -C1 C5 - pmaddwd mm4, mm2 ; -C1R3+C5R1 -C1r3+C5r1 - pmaddwd mm2, [coeffs + 96] ; -C5R3+C7R1 -C5r3+C7r1 - movq mm3, mm5 ; A2 a2 - paddd mm3, mm4 ; A2+B2 a2+b2 - psubd mm5, mm4 ; a2-B2 a2-b2 - psrad mm3, %6 - psrad mm5, %6 - movq mm4, mm6 ; A3 a3 - paddd mm6, mm2 ; A3+B3 a3+b3 - psubd mm4, mm2 ; a3-B3 a3-b3 - psrad mm6, %6 - packssdw mm3, mm3 ; A2+B2 a2+b2 - movd [32 + %5], mm3 - psrad mm4, %6 - packssdw mm6, mm6 ; A3+B3 a3+b3 - movd [48 + %5], mm6 - packssdw mm4, mm4 ; A3-B3 a3-b3 - packssdw mm5, mm5 ; A2-B2 a2-b2 - movd [64 + %5], mm4 - movd [80 + %5], mm5 + mova m0, %1 ; R4 R0 r4 r0 + mova m1, %2 ; R6 R2 r6 r2 + mova m2, %3 ; R3 R1 r3 r1 + mova m4, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m4, m0 ; C4R4+C4R0 C4r4+C4r0 + mova m5, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m0, m5 ; -C4R4+C4R0 -C4r4+C4r0 + mova m5, [coeffs + 64] ; C6 C2 C6 C2 + pmaddwd m5, m1 ; C6R6+C2R2 C6r6+C2r2 + mova m6, [coeffs + 80] ; -C2 C6 -C2 C6 + pmaddwd m1, m6 ; -C2R6+C6R2 -C2r6+C6r2 + mova m6, m4 ; C4R4+C4R0 C4r4+C4r0 + mova m7, [coeffs + 96] ; C3 C1 C3 C1 + pmaddwd m7, m2 ; C3R3+C1R1 C3r3+C1r1 + paddd m4, m5 ; A0 a0 + psubd m6, m5 ; A3 a3 + mova m5, m0 ; -C4R4+C4R0 -C4r4+C4r0 + paddd m0, m1 ; A1 a1 + psubd m5, m1 ; A2 a2 + mova m1, [coeffs + 128] + pmaddwd m1, m2 ; -C7R3+C3R1 -C7r3+C3r1 + paddd m7, m4 ; A0+B0 a0+b0 + paddd m4, m4 ; 2A0 2a0 + psubd m4, m7 ; A0-B0 a0-b0 + psrad m7, %6 + psrad m4, %6 + mova m3, m0 ; A1 a1 + paddd m0, m1 ; A1+B1 a1+b1 + psubd m3, m1 ; A1-B1 a1-b1 + psrad m0, %6 + psrad m3, %6 + packssdw m7, m7 ; A0+B0 a0+b0 + movq [%5], m7 + packssdw m0, m0 ; A1+B1 a1+b1 + movq [16 + %5], m0 + packssdw m3, m3 ; A1-B1 a1-b1 + movq [96 + %5], m3 + packssdw m4, m4 ; A0-B0 a0-b0 + movq [112 + %5], m4 + mova m4, [coeffs + 160] ; -C1 C5 -C1 C5 + pmaddwd m4, m2 ; -C1R3+C5R1 -C1r3+C5r1 + pmaddwd m2, [coeffs + 192] ; -C5R3+C7R1 -C5r3+C7r1 + mova m3, m5 ; A2 a2 + paddd m3, m4 ; A2+B2 a2+b2 + psubd m5, m4 ; a2-B2 a2-b2 + psrad m3, %6 + psrad m5, %6 + mova m4, m6 ; A3 a3 + paddd m6, m2 ; A3+B3 a3+b3 + psubd m4, m2 ; a3-B3 a3-b3 + psrad m6, %6 + packssdw m3, m3 ; A2+B2 a2+b2 + movq [32 + %5], m3 + psrad m4, %6 + packssdw m6, m6 ; A3+B3 a3+b3 + movq [48 + %5], m6 + packssdw m4, m4 ; A3-B3 a3-b3 + packssdw m5, m5 ; A2-B2 a2-b2 + movq [64 + %5], m4 + movq [80 + %5], m5 %endmacro %macro IDCT8 6 - movq mm0, [%1] ; R4 R0 r4 r0 - movq mm4, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm4, mm0 ; C4R4+C4R0 C4r4+C4r0 - movq mm5, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm0, mm5 ; -C4R4+C4R0 -C4r4+C4r0 - psrad mm4, %6 - psrad mm0, %6 - movq mm2, [8 + %1] ; R4 R0 r4 r0 - movq mm1, [coeffs + 16] ; C4 C4 C4 C4 - pmaddwd mm1, mm2 ; C4R4+C4R0 C4r4+C4r0 - movq mm7, [coeffs + 24] ; -C4 C4 -C4 C4 - pmaddwd mm2, mm7 ; -C4R4+C4R0 -C4r4+C4r0 - movq mm7, [coeffs + 32] ; C6 C2 C6 C2 - psrad mm1, %6 - packssdw mm4, mm1 ; A0 a0 - movq [%5], mm4 - psrad mm2, %6 - packssdw mm0, mm2 ; A1 a1 - movq [16 + %5], mm0 - movq [96 + %5], mm0 - movq [112 + %5], mm4 - movq [32 + %5], mm0 - movq [48 + %5], mm4 - movq [64 + %5], mm4 - movq [80 + %5], mm0 + movq m0, [%1] ; R4 R0 r4 r0 + movhps m0, [%1 + 16] + mova m4, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m4, m0 ; C4R4+C4R0 C4r4+C4r0 + mova m5, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m0, m5 ; -C4R4+C4R0 -C4r4+C4r0 + psrad m4, %6 + psrad m0, %6 + movq m2, [%1 + 8] ; R4 R0 r4 r0 + movhps m2, [%1 + 24] + mova m1, [coeffs + 32] ; C4 C4 C4 C4 + pmaddwd m1, m2 ; C4R4+C4R0 C4r4+C4r0 + mova m7, [coeffs + 48] ; -C4 C4 -C4 C4 + pmaddwd m2, m7 ; -C4R4+C4R0 -C4r4+C4r0 + mova m7, [coeffs + 64] ; C6 C2 C6 C2 + psrad m1, %6 + packssdw m4, m1 ; A0 a0 + pshufd m4, m4, 0xD8 + mova [%5], m4 + psrad m2, %6 + packssdw m0, m2 ; A1 a1 + pshufd m0, m0, 0xD8 + mova [16 + %5], m0 + mova [96 + %5], m0 + mova [112 + %5], m4 + mova [32 + %5], m0 + mova [48 + %5], m4 + mova [64 + %5], m4 + mova [80 + %5], m0 %endmacro %macro IDCT 0 @@ -710,9 +735,7 @@ SECTION .text Z_COND_IDCT 96, 104, 112, 120, rsp + 96, null, 11, %%1 IDCT1 [rsp + 0], [rsp + 64], [rsp + 32], [rsp + 96], blockq + 0, 20 - IDCT1 [rsp + 8], [rsp + 72], [rsp + 40], [rsp + 104], blockq + 4, 20 IDCT1 [rsp + 16], [rsp + 80], [rsp + 48], [rsp + 112], blockq + 8, 20 - IDCT1 [rsp + 24], [rsp + 88], [rsp + 56], [rsp + 120], blockq + 12, 20 jmp %%9 ALIGN 16 @@ -721,9 +744,7 @@ SECTION .text Z_COND_IDCT 96, 104, 112, 120, rsp + 96, null, 11, %%5 IDCT2 [rsp + 0], [rsp + 64], [rsp + 32], [rsp + 96], blockq + 0, 20 - IDCT2 [rsp + 8], [rsp + 72], [rsp + 40], [rsp + 104], blockq + 4, 20 IDCT2 [rsp + 16], [rsp + 80], [rsp + 48], [rsp + 112], blockq + 8, 20 - IDCT2 [rsp + 24], [rsp + 88], [rsp + 56], [rsp + 120], blockq + 12, 20 jmp %%9 ALIGN 16 @@ -731,9 +752,7 @@ SECTION .text Z_COND_IDCT 96, 104, 112, 120, rsp + 96, null, 11, %%7 IDCT3 [rsp + 0], [rsp + 64], [rsp + 32], [rsp + 96], blockq + 0, 20 - IDCT3 [rsp + 8], [rsp + 72], [rsp + 40], [rsp + 104], blockq + 4, 20 IDCT3 [rsp + 16], [rsp + 80], [rsp + 48], [rsp + 112], blockq + 8, 20 - IDCT3 [rsp + 24], [rsp + 88], [rsp + 56], [rsp + 120], blockq + 12, 20 jmp %%9 ALIGN 16 @@ -741,41 +760,33 @@ SECTION .text Z_COND_IDCT 96, 104, 112, 120, rsp + 96, null, 11, %%3 IDCT4 [rsp + 0], [rsp + 64], [rsp + 32], [rsp + 96], blockq + 0, 20 - IDCT4 [rsp + 8], [rsp + 72], [rsp + 40], [rsp + 104], blockq + 4, 20 IDCT4 [rsp + 16], [rsp + 80], [rsp + 48], [rsp + 112], blockq + 8, 20 - IDCT4 [rsp + 24], [rsp + 88], [rsp + 56], [rsp + 120], blockq + 12, 20 jmp %%9 ALIGN 16 %%3: IDCT5 [rsp + 0], [rsp + 64], [rsp + 32], [rsp + 96], blockq + 0, 20 - IDCT5 [rsp + 8], [rsp + 72], [rsp + 40], [rsp + 104], blockq + 4, 20 IDCT5 [rsp + 16], [rsp + 80], [rsp + 48], [rsp + 112], blockq + 8, 20 - IDCT5 [rsp + 24], [rsp + 88], [rsp + 56], [rsp + 120], blockq + 12, 20 jmp %%9 ALIGN 16 %%5: IDCT6 rsp + 0, rsp + 64, rsp + 32, rsp + 96, blockq + 0, 20 - IDCT6 rsp + 16, rsp + 80, rsp + 48, rsp + 112, blockq + 8, 20 jmp %%9 ALIGN 16 %%1: IDCT7 [rsp + 0], [rsp + 64], [rsp + 32], [rsp + 96], blockq + 0, 20 - IDCT7 [rsp + 8], [rsp + 72], [rsp + 40], [rsp + 104], blockq + 4, 20 IDCT7 [rsp + 16], [rsp + 80], [rsp + 48], [rsp + 112], blockq + 8, 20 - IDCT7 [rsp + 24], [rsp + 88], [rsp + 56], [rsp + 120], blockq + 12, 20 jmp %%9 ALIGN 16 %%7: IDCT8 rsp + 0, rsp + 64, rsp + 32, rsp + 96, blockq + 0, 20 - IDCT8 rsp + 16, rsp + 80, rsp + 48, rsp + 112, blockq + 8, 20 %%9: %endmacro @@ -805,15 +816,12 @@ SECTION .text movhps [pixelsq+lsizeq], m0 %endmacro -INIT_MMX mmx +INIT_XMM sse2 cglobal simple_idct, 1, 2, 8, 128, block, t0 IDCT - emms RET -INIT_XMM sse2 - cglobal simple_idct_put, 3, 5, 8, 128, pixels, lsize, block, lsize3, t0 IDCT lea lsize3q, [lsizeq*3] diff --git a/libavcodec/x86/simple_idct.h b/libavcodec/x86/simple_idct.h index 9b64cfe9b..c9ba6aeda 100644 --- a/libavcodec/x86/simple_idct.h +++ b/libavcodec/x86/simple_idct.h @@ -22,10 +22,7 @@ #include #include -void ff_simple_idct_mmx(int16_t *block); -void ff_simple_idct_add_mmx(uint8_t *dest, ptrdiff_t line_size, int16_t *block); -void ff_simple_idct_put_mmx(uint8_t *dest, ptrdiff_t line_size, int16_t *block); - +void ff_simple_idct_sse2(int16_t *block); void ff_simple_idct_add_sse2(uint8_t *dest, ptrdiff_t line_size, int16_t *block); void ff_simple_idct_put_sse2(uint8_t *dest, ptrdiff_t line_size, int16_t *block); diff --git a/libavcodec/x86/synth_filter_init.c b/libavcodec/x86/synth_filter_init.c index e09870b23..93407c92d 100644 --- a/libavcodec/x86/synth_filter_init.c +++ b/libavcodec/x86/synth_filter_init.c @@ -43,15 +43,12 @@ static void synth_filter_##opt(AVTXContext *imdct, \ *synth_buf_offset = (*synth_buf_offset - 32) & 511; \ } \ -#if HAVE_X86ASM SYNTH_FILTER_FUNC(sse2) SYNTH_FILTER_FUNC(avx) SYNTH_FILTER_FUNC(fma3) -#endif /* HAVE_X86ASM */ av_cold void ff_synth_filter_init_x86(SynthFilterContext *s) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE2(cpu_flags)) { @@ -63,5 +60,4 @@ av_cold void ff_synth_filter_init_x86(SynthFilterContext *s) if (EXTERNAL_FMA3_FAST(cpu_flags)) { s->synth_filter_float = synth_filter_fma3; } -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/x86/takdsp_init.c b/libavcodec/x86/takdsp_init.c index 9553f8442..68eb1b8c5 100644 --- a/libavcodec/x86/takdsp_init.c +++ b/libavcodec/x86/takdsp_init.c @@ -21,7 +21,6 @@ #include "libavutil/attributes.h" #include "libavcodec/takdsp.h" #include "libavutil/x86/cpu.h" -#include "config.h" void ff_tak_decorrelate_ls_sse2(const int32_t *p1, int32_t *p2, int length); void ff_tak_decorrelate_ls_avx2(const int32_t *p1, int32_t *p2, int length); @@ -34,7 +33,6 @@ void ff_tak_decorrelate_sf_avx2(int32_t *p1, const int32_t *p2, int length, int av_cold void ff_takdsp_init_x86(TAKDSPContext *c) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE2(cpu_flags)) { @@ -53,5 +51,4 @@ av_cold void ff_takdsp_init_x86(TAKDSPContext *c) c->decorrelate_sm = ff_tak_decorrelate_sm_avx2; c->decorrelate_sf = ff_tak_decorrelate_sf_avx2; } -#endif } diff --git a/libavcodec/x86/ttadsp_init.c b/libavcodec/x86/ttadsp_init.c index f2954e568..b4d518426 100644 --- a/libavcodec/x86/ttadsp_init.c +++ b/libavcodec/x86/ttadsp_init.c @@ -21,7 +21,6 @@ #include "libavutil/attributes.h" #include "libavcodec/ttadsp.h" #include "libavutil/x86/cpu.h" -#include "config.h" void ff_tta_filter_process_ssse3(int32_t *qm, int32_t *dx, int32_t *dl, int32_t *error, int32_t *in, int32_t shift, @@ -32,12 +31,10 @@ void ff_tta_filter_process_sse4(int32_t *qm, int32_t *dx, int32_t *dl, av_cold void ff_ttadsp_init_x86(TTADSPContext *c) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSSE3(cpu_flags)) c->filter_process = ff_tta_filter_process_ssse3; if (EXTERNAL_SSE4(cpu_flags)) c->filter_process = ff_tta_filter_process_sse4; -#endif } diff --git a/libavcodec/x86/ttaencdsp_init.c b/libavcodec/x86/ttaencdsp_init.c index b470142c5..cfe11f967 100644 --- a/libavcodec/x86/ttaencdsp_init.c +++ b/libavcodec/x86/ttaencdsp_init.c @@ -21,7 +21,6 @@ #include "libavutil/attributes.h" #include "libavcodec/ttaencdsp.h" #include "libavutil/x86/cpu.h" -#include "config.h" void ff_ttaenc_filter_process_ssse3(int32_t *qm, int32_t *dx, int32_t *dl, int32_t *error, int32_t *in, int32_t shift, @@ -32,12 +31,10 @@ void ff_ttaenc_filter_process_sse4(int32_t *qm, int32_t *dx, int32_t *dl, av_cold void ff_ttaencdsp_init_x86(TTAEncDSPContext *c) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSSE3(cpu_flags)) c->filter_process = ff_ttaenc_filter_process_ssse3; if (EXTERNAL_SSE4(cpu_flags)) c->filter_process = ff_ttaenc_filter_process_sse4; -#endif } diff --git a/libavcodec/x86/v210-init.c b/libavcodec/x86/v210-init.c index 8b3677b8a..7a879f1dc 100644 --- a/libavcodec/x86/v210-init.c +++ b/libavcodec/x86/v210-init.c @@ -32,34 +32,42 @@ extern void ff_v210_planar_unpack_avx512icl(const uint32_t *src, uint16_t *y, ui av_cold void ff_v210_x86_init(V210DecContext *s) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (s->aligned_input) { if (cpu_flags & AV_CPU_FLAG_SSSE3) s->unpack_frame = ff_v210_planar_unpack_aligned_ssse3; - - if (HAVE_AVX_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX) +#if HAVE_AVX_EXTERNAL + if (cpu_flags & AV_CPU_FLAG_AVX) s->unpack_frame = ff_v210_planar_unpack_aligned_avx; +#endif - if (HAVE_AVX2_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX2) +#if HAVE_AVX2_EXTERNAL + if (cpu_flags & AV_CPU_FLAG_AVX2) s->unpack_frame = ff_v210_planar_unpack_aligned_avx2; +#endif +#if HAVE_AVX512ICL_EXTERNAL if (EXTERNAL_AVX512ICL(cpu_flags)) s->unpack_frame = ff_v210_planar_unpack_avx512icl; +#endif } else { if (cpu_flags & AV_CPU_FLAG_SSSE3) s->unpack_frame = ff_v210_planar_unpack_unaligned_ssse3; - - if (HAVE_AVX_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX) +#if HAVE_AVX_EXTERNAL + if (cpu_flags & AV_CPU_FLAG_AVX) s->unpack_frame = ff_v210_planar_unpack_unaligned_avx; +#endif - if (HAVE_AVX2_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX2) +#if HAVE_AVX2_EXTERNAL + if (cpu_flags & AV_CPU_FLAG_AVX2) s->unpack_frame = ff_v210_planar_unpack_unaligned_avx2; +#endif +#if HAVE_AVX512ICL_EXTERNAL if (EXTERNAL_AVX512ICL(cpu_flags)) s->unpack_frame = ff_v210_planar_unpack_avx512icl; - } #endif + } } diff --git a/libavcodec/x86/v210enc_init.c b/libavcodec/x86/v210enc_init.c index 44f22ca7f..8396ea7a0 100644 --- a/libavcodec/x86/v210enc_init.c +++ b/libavcodec/x86/v210enc_init.c @@ -71,11 +71,12 @@ av_cold void ff_v210enc_init_x86(V210EncContext *s) s->pack_line_10 = ff_v210_planar_pack_10_avx512; #endif } - +#if HAVE_AVX512ICL_EXTERNAL if (EXTERNAL_AVX512ICL(cpu_flags)) { s->sample_factor_8 = 4; s->pack_line_8 = ff_v210_planar_pack_8_avx512icl; s->sample_factor_10 = 4; s->pack_line_10 = ff_v210_planar_pack_10_avx512icl; } +#endif } diff --git a/libavcodec/x86/vc1dsp.h b/libavcodec/x86/vc1dsp.h index fdd4de181..9c16d73fd 100644 --- a/libavcodec/x86/vc1dsp.h +++ b/libavcodec/x86/vc1dsp.h @@ -21,9 +21,14 @@ #ifndef AVCODEC_X86_VC1DSP_H #define AVCODEC_X86_VC1DSP_H +#include "libavutil/x86/asm.h" #include "libavcodec/vc1dsp.h" +#if HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL + void ff_vc1dsp_init_mmx(VC1DSPContext *dsp); void ff_vc1dsp_init_mmxext(VC1DSPContext *dsp); +#endif /* HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL */ + #endif /* AVCODEC_X86_VC1DSP_H */ diff --git a/libavcodec/x86/vc1dsp_init.c b/libavcodec/x86/vc1dsp_init.c index 90b2f3624..e344f233d 100644 --- a/libavcodec/x86/vc1dsp_init.c +++ b/libavcodec/x86/vc1dsp_init.c @@ -52,7 +52,6 @@ static void vc1_h_loop_filter16_ ## EXT(uint8_t *src, ptrdiff_t stride, int pq) ff_vc1_h_loop_filter8_ ## EXT(src+8*stride, stride, pq); \ } -#if HAVE_X86ASM LOOP_FILTER4(mmxext) LOOP_FILTER816(sse2) LOOP_FILTER4(ssse3) @@ -73,17 +72,11 @@ static void vc1_h_loop_filter16_sse4(uint8_t *src, ptrdiff_t stride, int pq) ff_ ## OP ## pixels ## DEPTH ## INSN(dst, src, stride, DEPTH); \ } -DECLARE_FUNCTION(put_, 8, _mmx) +DECLARE_FUNCTION(put_, 8, _sse2) DECLARE_FUNCTION(avg_, 8, _mmxext) DECLARE_FUNCTION(put_, 16, _sse2) DECLARE_FUNCTION(avg_, 16, _sse2) -#endif /* HAVE_X86ASM */ - -void ff_put_vc1_chroma_mc8_nornd_mmx (uint8_t *dst, const uint8_t *src, - ptrdiff_t stride, int h, int x, int y); -void ff_avg_vc1_chroma_mc8_nornd_mmxext(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride, int h, int x, int y); void ff_put_vc1_chroma_mc8_nornd_ssse3(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h, int x, int y); void ff_avg_vc1_chroma_mc8_nornd_ssse3(uint8_t *dst, const uint8_t *src, @@ -102,6 +95,7 @@ av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp) { int cpu_flags = av_get_cpu_flags(); +#if HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL if (HAVE_6REGS && INLINE_MMX(cpu_flags)) if (EXTERNAL_MMX(cpu_flags)) ff_vc1dsp_init_mmx(dsp); @@ -109,6 +103,7 @@ av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp) if (HAVE_6REGS && INLINE_MMXEXT(cpu_flags)) if (EXTERNAL_MMXEXT(cpu_flags)) ff_vc1dsp_init_mmxext(dsp); +#endif /* HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL */ #define ASSIGN_LF4(EXT) \ dsp->vc1_v_loop_filter4 = ff_vc1_v_loop_filter4_ ## EXT; \ @@ -119,15 +114,8 @@ av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp) dsp->vc1_v_loop_filter16 = vc1_v_loop_filter16_ ## EXT; \ dsp->vc1_h_loop_filter16 = vc1_h_loop_filter16_ ## EXT -#if HAVE_X86ASM - if (EXTERNAL_MMX(cpu_flags)) { - dsp->put_no_rnd_vc1_chroma_pixels_tab[0] = ff_put_vc1_chroma_mc8_nornd_mmx; - - dsp->put_vc1_mspel_pixels_tab[1][0] = put_vc1_mspel_mc00_8_mmx; - } if (EXTERNAL_MMXEXT(cpu_flags)) { ASSIGN_LF4(mmxext); - dsp->avg_no_rnd_vc1_chroma_pixels_tab[0] = ff_avg_vc1_chroma_mc8_nornd_mmxext; dsp->avg_vc1_mspel_pixels_tab[1][0] = avg_vc1_mspel_mc00_8_mmxext; @@ -140,6 +128,7 @@ av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp) ASSIGN_LF816(sse2); dsp->put_vc1_mspel_pixels_tab[0][0] = put_vc1_mspel_mc00_16_sse2; + dsp->put_vc1_mspel_pixels_tab[1][0] = put_vc1_mspel_mc00_8_sse2; dsp->avg_vc1_mspel_pixels_tab[0][0] = avg_vc1_mspel_mc00_16_sse2; } if (EXTERNAL_SSSE3(cpu_flags)) { @@ -152,5 +141,4 @@ av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp) dsp->vc1_h_loop_filter8 = ff_vc1_h_loop_filter8_sse4; dsp->vc1_h_loop_filter16 = vc1_h_loop_filter16_sse4; } -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/x86/videodsp.asm b/libavcodec/x86/videodsp.asm index 3cc07878d..81ae2ec10 100644 --- a/libavcodec/x86/videodsp.asm +++ b/libavcodec/x86/videodsp.asm @@ -123,54 +123,43 @@ hvar_fn ; - if (%2 & 8) fills 8 bytes into xmm$next ; - if (%2 & 4) fills 4 bytes into xmm$next ; - if (%2 & 3) fills 1, 2 or 4 bytes in eax -; on mmx, - fills mm0-7 for consecutive sets of 8 pixels -; - if (%2 & 4) fills 4 bytes into mm$next -; - if (%2 & 3) fills 1, 2 or 4 bytes in eax ; writing data out is in the same way %macro READ_NUM_BYTES 2 %assign %%off 0 ; offset in source buffer -%assign %%mmx_idx 0 ; mmx register index %assign %%xmm_idx 0 ; xmm register index %rep %2/mmsize -%if mmsize == 16 movu xmm %+ %%xmm_idx, [srcq+%%off] %assign %%xmm_idx %%xmm_idx+1 -%else ; mmx - movu mm %+ %%mmx_idx, [srcq+%%off] -%assign %%mmx_idx %%mmx_idx+1 -%endif %assign %%off %%off+mmsize %endrep ; %2/mmsize -%if mmsize == 16 %if (%2-%%off) >= 8 %if %2 > 16 && (%2-%%off) > 8 movu xmm %+ %%xmm_idx, [srcq+%2-16] %assign %%xmm_idx %%xmm_idx+1 %assign %%off %2 %else - movq mm %+ %%mmx_idx, [srcq+%%off] -%assign %%mmx_idx %%mmx_idx+1 + movq xmm %+ %%xmm_idx, [srcq+%%off] +%assign %%xmm_idx %%xmm_idx+1 %assign %%off %%off+8 %endif %endif ; (%2-%%off) >= 8 -%endif %if (%2-%%off) >= 4 %if %2 > 8 && (%2-%%off) > 4 - movq mm %+ %%mmx_idx, [srcq+%2-8] + movq xmm %+ %%xmm_idx, [srcq+%2-8] %assign %%off %2 %else - movd mm %+ %%mmx_idx, [srcq+%%off] + movd xmm %+ %%xmm_idx, [srcq+%%off] %assign %%off %%off+4 %endif -%assign %%mmx_idx %%mmx_idx+1 +%assign %%xmm_idx %%xmm_idx+1 %endif ; (%2-%%off) >= 4 %if (%2-%%off) >= 1 %if %2 >= 4 - movd mm %+ %%mmx_idx, [srcq+%2-4] + movd xmm %+ %%xmm_idx, [srcq+%2-4] %elif (%2-%%off) == 1 mov valb, [srcq+%2-1] %elif (%2-%%off) == 2 @@ -185,48 +174,40 @@ hvar_fn %macro WRITE_NUM_BYTES 2 %assign %%off 0 ; offset in destination buffer -%assign %%mmx_idx 0 ; mmx register index %assign %%xmm_idx 0 ; xmm register index %rep %2/mmsize -%if mmsize == 16 movu [dstq+%%off], xmm %+ %%xmm_idx %assign %%xmm_idx %%xmm_idx+1 -%else ; mmx - movu [dstq+%%off], mm %+ %%mmx_idx -%assign %%mmx_idx %%mmx_idx+1 -%endif %assign %%off %%off+mmsize %endrep ; %2/mmsize -%if mmsize == 16 %if (%2-%%off) >= 8 %if %2 > 16 && (%2-%%off) > 8 movu [dstq+%2-16], xmm %+ %%xmm_idx %assign %%xmm_idx %%xmm_idx+1 %assign %%off %2 %else - movq [dstq+%%off], mm %+ %%mmx_idx -%assign %%mmx_idx %%mmx_idx+1 + movq [dstq+%%off], xmm %+ %%xmm_idx +%assign %%xmm_idx %%xmm_idx+1 %assign %%off %%off+8 %endif %endif ; (%2-%%off) >= 8 -%endif %if (%2-%%off) >= 4 %if %2 > 8 && (%2-%%off) > 4 - movq [dstq+%2-8], mm %+ %%mmx_idx + movq [dstq+%2-8], xmm %+ %%xmm_idx %assign %%off %2 %else - movd [dstq+%%off], mm %+ %%mmx_idx + movd [dstq+%%off], xmm %+ %%xmm_idx %assign %%off %%off+4 %endif -%assign %%mmx_idx %%mmx_idx+1 +%assign %%xmm_idx %%xmm_idx+1 %endif ; (%2-%%off) >= 4 %if (%2-%%off) >= 1 %if %2 >= 4 - movd [dstq+%2-4], mm %+ %%mmx_idx + movd [dstq+%2-4], xmm %+ %%xmm_idx %elif (%2-%%off) == 1 mov [dstq+%2-1], valb %elif (%2-%%off) == 2 @@ -318,11 +299,8 @@ cglobal emu_edge_vfix %+ %%n, 1, 5, 1, dst, src, start_y, end_y, bh %endrep ; 1+%2-%1 %endmacro ; VERTICAL_EXTEND -INIT_MMX mmx -VERTICAL_EXTEND 1, 15 - -INIT_XMM sse -VERTICAL_EXTEND 16, 22 +INIT_XMM sse2 +VERTICAL_EXTEND 1, 22 ; left/right (horizontal) fast extend functions ; these are essentially identical to the vertical extend ones above, @@ -337,11 +315,7 @@ VERTICAL_EXTEND 16, 22 imul vald, 0x01010101 %if %1 >= 8 movd m0, vald -%if mmsize == 16 pshufd m0, m0, q0000 -%else - punpckldq m0, m0 -%endif ; mmsize == 16 %endif ; %1 > 16 %endif ; avx2 %endmacro ; READ_V_PIXEL @@ -356,7 +330,6 @@ VERTICAL_EXTEND 16, 22 %assign %%off %%off+mmsize %endrep ; %1/mmsize -%if mmsize == 16 %if %1-%%off >= 8 %if %1 > 16 && %1-%%off > 8 movu [%2+%1-16], m0 @@ -366,7 +339,6 @@ VERTICAL_EXTEND 16, 22 %assign %%off %%off+8 %endif %endif ; %1-%%off >= 8 -%endif ; mmsize == 16 %if %1-%%off >= 4 %if %1 > 8 && %1-%%off > 4 @@ -415,11 +387,8 @@ cglobal emu_edge_hfix %+ %%n, 4, 5, 1, dst, dst_stride, start_x, bh, val %endrep ; 1+(%2-%1)/2 %endmacro ; H_EXTEND -INIT_MMX mmx -H_EXTEND 2, 14 - INIT_XMM sse2 -H_EXTEND 16, 22 +H_EXTEND 2, 22 %if HAVE_AVX2_EXTERNAL INIT_XMM avx2 diff --git a/libavcodec/x86/videodsp_init.c b/libavcodec/x86/videodsp_init.c index ae9db9562..7f3c83722 100644 --- a/libavcodec/x86/videodsp_init.c +++ b/libavcodec/x86/videodsp_init.c @@ -28,7 +28,6 @@ #include "libavutil/x86/cpu.h" #include "libavcodec/videodsp.h" -#if HAVE_X86ASM typedef void emu_edge_vfix_func(uint8_t *dst, x86_reg dst_stride, const uint8_t *src, x86_reg src_stride, x86_reg start_y, x86_reg end_y, x86_reg bh); @@ -37,37 +36,37 @@ typedef void emu_edge_vvar_func(uint8_t *dst, x86_reg dst_stride, x86_reg start_y, x86_reg end_y, x86_reg bh, x86_reg w); -extern emu_edge_vfix_func ff_emu_edge_vfix1_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix2_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix3_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix4_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix5_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix6_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix7_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix8_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix9_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix10_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix11_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix12_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix13_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix14_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix15_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix16_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix17_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix18_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix19_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix20_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix21_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix22_sse; -static emu_edge_vfix_func * const vfixtbl_sse[22] = { - ff_emu_edge_vfix1_mmx, ff_emu_edge_vfix2_mmx, ff_emu_edge_vfix3_mmx, - ff_emu_edge_vfix4_mmx, ff_emu_edge_vfix5_mmx, ff_emu_edge_vfix6_mmx, - ff_emu_edge_vfix7_mmx, ff_emu_edge_vfix8_mmx, ff_emu_edge_vfix9_mmx, - ff_emu_edge_vfix10_mmx, ff_emu_edge_vfix11_mmx, ff_emu_edge_vfix12_mmx, - ff_emu_edge_vfix13_mmx, ff_emu_edge_vfix14_mmx, ff_emu_edge_vfix15_mmx, - ff_emu_edge_vfix16_sse, ff_emu_edge_vfix17_sse, ff_emu_edge_vfix18_sse, - ff_emu_edge_vfix19_sse, ff_emu_edge_vfix20_sse, ff_emu_edge_vfix21_sse, - ff_emu_edge_vfix22_sse +extern emu_edge_vfix_func ff_emu_edge_vfix1_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix2_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix3_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix4_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix5_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix6_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix7_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix8_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix9_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix10_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix11_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix12_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix13_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix14_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix15_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix16_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix17_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix18_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix19_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix20_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix21_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix22_sse2; +static emu_edge_vfix_func * const vfixtbl_sse2[22] = { + ff_emu_edge_vfix1_sse2, ff_emu_edge_vfix2_sse2, ff_emu_edge_vfix3_sse2, + ff_emu_edge_vfix4_sse2, ff_emu_edge_vfix5_sse2, ff_emu_edge_vfix6_sse2, + ff_emu_edge_vfix7_sse2, ff_emu_edge_vfix8_sse2, ff_emu_edge_vfix9_sse2, + ff_emu_edge_vfix10_sse2, ff_emu_edge_vfix11_sse2, ff_emu_edge_vfix12_sse2, + ff_emu_edge_vfix13_sse2, ff_emu_edge_vfix14_sse2, ff_emu_edge_vfix15_sse2, + ff_emu_edge_vfix16_sse2, ff_emu_edge_vfix17_sse2, ff_emu_edge_vfix18_sse2, + ff_emu_edge_vfix19_sse2, ff_emu_edge_vfix20_sse2, ff_emu_edge_vfix21_sse2, + ff_emu_edge_vfix22_sse2 }; extern emu_edge_vvar_func ff_emu_edge_vvar_sse; @@ -76,21 +75,21 @@ typedef void emu_edge_hfix_func(uint8_t *dst, x86_reg dst_stride, typedef void emu_edge_hvar_func(uint8_t *dst, x86_reg dst_stride, x86_reg start_x, x86_reg n_words, x86_reg bh); -extern emu_edge_hfix_func ff_emu_edge_hfix2_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix4_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix6_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix8_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix10_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix12_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix14_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix2_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix4_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix6_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix8_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix10_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix12_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix14_sse2; extern emu_edge_hfix_func ff_emu_edge_hfix16_sse2; extern emu_edge_hfix_func ff_emu_edge_hfix18_sse2; extern emu_edge_hfix_func ff_emu_edge_hfix20_sse2; extern emu_edge_hfix_func ff_emu_edge_hfix22_sse2; static emu_edge_hfix_func * const hfixtbl_sse2[11] = { - ff_emu_edge_hfix2_mmx, ff_emu_edge_hfix4_mmx, ff_emu_edge_hfix6_mmx, - ff_emu_edge_hfix8_mmx, ff_emu_edge_hfix10_mmx, ff_emu_edge_hfix12_mmx, - ff_emu_edge_hfix14_mmx, ff_emu_edge_hfix16_sse2, ff_emu_edge_hfix18_sse2, + ff_emu_edge_hfix2_sse2, ff_emu_edge_hfix4_sse2, ff_emu_edge_hfix6_sse2, + ff_emu_edge_hfix8_sse2, ff_emu_edge_hfix10_sse2, ff_emu_edge_hfix12_sse2, + ff_emu_edge_hfix14_sse2, ff_emu_edge_hfix16_sse2, ff_emu_edge_hfix18_sse2, ff_emu_edge_hfix20_sse2, ff_emu_edge_hfix22_sse2 }; extern emu_edge_hvar_func ff_emu_edge_hvar_sse2; @@ -104,7 +103,7 @@ extern emu_edge_hfix_func ff_emu_edge_hfix18_avx2; extern emu_edge_hfix_func ff_emu_edge_hfix20_avx2; extern emu_edge_hfix_func ff_emu_edge_hfix22_avx2; static emu_edge_hfix_func * const hfixtbl_avx2[11] = { - ff_emu_edge_hfix2_mmx, ff_emu_edge_hfix4_mmx, ff_emu_edge_hfix6_mmx, + ff_emu_edge_hfix2_sse2, ff_emu_edge_hfix4_sse2, ff_emu_edge_hfix6_sse2, ff_emu_edge_hfix8_avx2, ff_emu_edge_hfix10_avx2, ff_emu_edge_hfix12_avx2, ff_emu_edge_hfix14_avx2, ff_emu_edge_hfix16_avx2, ff_emu_edge_hfix18_avx2, ff_emu_edge_hfix20_avx2, ff_emu_edge_hfix22_avx2 @@ -196,7 +195,7 @@ static av_noinline void emulated_edge_mc_sse2(uint8_t *buf, const uint8_t *src, int h) { emulated_edge_mc(buf, src, buf_stride, src_stride, block_w, block_h, - src_x, src_y, w, h, vfixtbl_sse, &ff_emu_edge_vvar_sse, + src_x, src_y, w, h, vfixtbl_sse2, &ff_emu_edge_vvar_sse, hfixtbl_sse2, &ff_emu_edge_hvar_sse2); } @@ -209,17 +208,15 @@ static av_noinline void emulated_edge_mc_avx2(uint8_t *buf, const uint8_t *src, int h) { emulated_edge_mc(buf, src, buf_stride, src_stride, block_w, block_h, - src_x, src_y, w, h, vfixtbl_sse, &ff_emu_edge_vvar_sse, + src_x, src_y, w, h, vfixtbl_sse2, &ff_emu_edge_vvar_sse, hfixtbl_avx2, &ff_emu_edge_hvar_avx2); } #endif /* HAVE_AVX2_EXTERNAL */ -#endif /* HAVE_X86ASM */ void ff_prefetch_mmxext(const uint8_t *buf, ptrdiff_t stride, int h); av_cold void ff_videodsp_init_x86(VideoDSPContext *ctx, int bpc) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_MMXEXT(cpu_flags)) { @@ -233,5 +230,4 @@ av_cold void ff_videodsp_init_x86(VideoDSPContext *ctx, int bpc) ctx->emulated_edge_mc = emulated_edge_mc_avx2; } #endif -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/x86/vp3dsp.asm b/libavcodec/x86/vp3dsp.asm index 005ecbc9a..3fa6584c9 100644 --- a/libavcodec/x86/vp3dsp.asm +++ b/libavcodec/x86/vp3dsp.asm @@ -33,113 +33,125 @@ vp3_idct_data: times 8 dw 64277 times 8 dw 25080 times 8 dw 12785 -pb_7: times 8 db 0x07 -pb_1F: times 8 db 0x1f -pb_81: times 8 db 0x81 - -cextern pb_1 -cextern pb_3 cextern pb_80 cextern pb_FE +cextern pw_4 cextern pw_8 SECTION .text -; this is off by one or two for some cases when filter_limit is greater than 63 -; in: p0 in mm6, p1 in mm4, p2 in mm2, p3 in mm1 -; out: p1 in mm4, p2 in mm3 +; in: p0 in m5, p1 in m4, p2 in m2, p3 in m1, all unpacked; +; m0 must be zeroed +; out: p1 in m4, p2 in m2 %macro VP3_LOOP_FILTER 0 - movq m7, m6 - pand m6, [pb_7] ; p0&7 - psrlw m7, 3 - pand m7, [pb_1F] ; p0>>3 - movq m3, m2 ; p2 - pxor m2, m4 - pand m2, [pb_1] ; (p2^p1)&1 - movq m5, m2 - paddb m2, m2 - paddb m2, m5 ; 3*(p2^p1)&1 - paddb m2, m6 ; extra bits lost in shifts - pcmpeqb m0, m0 - pxor m1, m0 ; 255 - p3 - pavgb m1, m2 ; (256 - p3 + extrabits) >> 1 - pxor m0, m4 ; 255 - p1 - pavgb m0, m3 ; (256 + p2-p1) >> 1 - paddb m1, [pb_3] - pavgb m1, m0 ; 128+2+( p2-p1 - p3) >> 2 - pavgb m1, m0 ; 128+1+(3*(p2-p1) - p3) >> 3 - paddusb m7, m1 ; d+128+1 - movq m6, [pb_81] - psubusb m6, m7 - psubusb m7, [pb_81] + psubw m5, m1 + mova m3, m2 + paddw m5, [pw_4] + psubw m3, m4 + mova m1, m3 + paddw m1, m5 + mova m5, [r2+516] ; 2 * filter limit + paddw m3, m3 + paddw m3, m1 + psraw m3, 3 - movq m5, [r2+516] ; flim - pminub m6, m5 - pminub m7, m5 - movq m0, m6 - movq m1, m7 - paddb m6, m6 - paddb m7, m7 - pminub m6, m5 - pminub m7, m5 - psubb m6, m0 - psubb m7, m1 - paddusb m4, m7 - psubusb m4, m6 - psubusb m3, m7 - paddusb m3, m6 + ; We use that clamp(2clamp(x,2f),2f)-clamp(x,2f) + ; (with f = filter limit and clamping to the interval [-f,f]) + ; gives the desired filter value + psubw m0, m5 + pminsw m3, m5 + pmaxsw m3, m0 + mova m1, m3 + paddw m1, m1 + pminsw m1, m5 + pmaxsw m1, m0 + psubw m1, m3 + psubw m2, m1 + paddw m4, m1 + + packuswb m4, m4 + packuswb m2, m2 %endmacro %macro STORE_4_WORDS 1 +%if ARCH_X86_64 + movq r2, %1 + mov [r0 -1], r2w + shr r2, 16 + mov [r0+r1 -1], r2w + shr r2, 16 +%else movd r2d, %1 mov [r0 -1], r2w psrlq %1, 32 - shr r2, 16 + shr r2d, 16 mov [r0+r1 -1], r2w movd r2d, %1 +%endif mov [r0+r1*2-1], r2w - shr r2, 16 + shr r2d, 16 mov [r0+r3 -1], r2w %endmacro -INIT_MMX mmxext -cglobal vp3_v_loop_filter, 3, 4 - mov r3, r1 +INIT_XMM sse2 +cglobal vp3_v_loop_filter, 3, 3, 6 + movq m1, [r0+r1 ] neg r1 - movq m6, [r0+r1*2] - movq m4, [r0+r1 ] movq m2, [r0 ] - movq m1, [r0+r3 ] + movq m4, [r0+r1 ] + movq m5, [r0+r1*2] + + pxor m0, m0 + punpcklbw m1, m0 + punpcklbw m2, m0 + punpcklbw m4, m0 + punpcklbw m5, m0 VP3_LOOP_FILTER movq [r0+r1], m4 - movq [r0 ], m3 + movq [r0 ], m2 RET -cglobal vp3_h_loop_filter, 3, 4 +%macro TRANSPOSE4x4 1 + movd %1, [r0 -2] + movd m2, [r0+r1 -2] + movd m3, [r0+r1*2-2] + movd m4, [r0+r3 -2] + punpcklbw %1, m2 + punpcklbw m3, m4 + punpcklwd %1, m3 +%endmacro + +INIT_XMM sse2 +cglobal vp3_h_loop_filter, 3, 4, 6 lea r3, [r1*3] - movd m6, [r0 -2] - movd m4, [r0+r1 -2] - movd m2, [r0+r1*2-2] - movd m1, [r0+r3 -2] - lea r0, [r0+r1*4 ] - punpcklbw m6, [r0 -2] - punpcklbw m4, [r0+r1 -2] - punpcklbw m2, [r0+r1*2-2] - punpcklbw m1, [r0+r3 -2] + TRANSPOSE4x4 m5 + lea r0, [r0+r1*4] + TRANSPOSE4x4 m0 + mova m2, m5 + punpckldq m5, m0 + punpckhdq m2, m0 + pxor m0, m0 + mova m4, m5 + punpcklbw m5, m0 + punpckhbw m4, m0 + mova m1, m2 + punpcklbw m2, m0 + punpckhbw m1, m0 + + VP3_LOOP_FILTER + + punpcklbw m4, m2 + mova m2, m4 + punpckhqdq m2, m2 + + STORE_4_WORDS m2 sub r0, r3 sub r0, r1 - - TRANSPOSE4x4B 6, 4, 2, 1, 0 - VP3_LOOP_FILTER - SBUTTERFLY bw, 4, 3, 5 - STORE_4_WORDS m4 - lea r0, [r0+r1*4 ] - STORE_4_WORDS m3 RET %macro PAVGB_NO_RND 0 @@ -508,7 +520,6 @@ cglobal put_vp_no_rnd_pixels8_l2, 5, 6, 0, dst, src1, src2, stride, h, stride3 %endmacro %macro VP3_IDCT 1 -%if mmsize == 16 %define I(x) [%1+16*x] %define O(x) [%1+16*x] %define C(x) [vp3_idct_data+16*(x-1)] @@ -526,37 +537,6 @@ cglobal put_vp_no_rnd_pixels8_l2, 5, 6, 0, dst, src1, src2, stride, h, stride3 %define ADD(x) paddsw x, [pw_8] VP3_1D_IDCT_SSE2 PUT_BLOCK 0, 1, 2, 3, 4, 5, 6, 7 -%else ; mmsize == 8 - ; eax = quantized input - ; ebx = dequantizer matrix - ; ecx = IDCT constants - ; M(I) = ecx + MaskOffset(0) + I * 8 - ; C(I) = ecx + CosineOffset(32) + (I-1) * 8 - ; edx = output - ; r0..r7 = mm0..mm7 -%define OC_8 [pw_8] -%define C(x) [vp3_idct_data+16*(x-1)] - - ; at this point, function has completed dequantization + dezigzag + - ; partial transposition; now do the idct itself -%define I(x) [%1+16*x] -%define J(x) [%1+16*x] - RowIDCT - Transpose - -%define I(x) [%1+16*x+8] -%define J(x) [%1+16*x+8] - RowIDCT - Transpose - -%define I(x) [%1+16* x] -%define J(x) [%1+16*(x-4)+8] - ColumnIDCT - -%define I(x) [%1+16* x +64] -%define J(x) [%1+16*(x-4)+72] - ColumnIDCT -%endif ; mmsize == 16/8 %endmacro %macro vp3_idct_funcs 0 diff --git a/libavcodec/x86/vp3dsp_init.c b/libavcodec/x86/vp3dsp_init.c index edac1764c..42daf9998 100644 --- a/libavcodec/x86/vp3dsp_init.c +++ b/libavcodec/x86/vp3dsp_init.c @@ -18,12 +18,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/x86/cpu.h" -#include "libavcodec/avcodec.h" #include "libavcodec/vp3dsp.h" void ff_vp3_idct_put_sse2(uint8_t *dest, ptrdiff_t stride, int16_t *block); @@ -31,16 +31,16 @@ void ff_vp3_idct_add_sse2(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vp3_idct_dc_add_mmxext(uint8_t *dest, ptrdiff_t stride, int16_t *block); -void ff_vp3_v_loop_filter_mmxext(uint8_t *src, ptrdiff_t stride, - int *bounding_values); -void ff_vp3_h_loop_filter_mmxext(uint8_t *src, ptrdiff_t stride, - int *bounding_values); +void ff_vp3_v_loop_filter_sse2(uint8_t *src, ptrdiff_t stride, + int *bounding_values); +void ff_vp3_h_loop_filter_sse2(uint8_t *src, ptrdiff_t stride, + int *bounding_values); void ff_put_vp_no_rnd_pixels8_l2_mmx(uint8_t *dst, const uint8_t *a, const uint8_t *b, ptrdiff_t stride, int h); -av_cold void ff_vp3dsp_init_x86(VP3DSPContext *c, int flags) +av_cold void ff_vp3dsp_init_x86(VP3DSPContext *c) { int cpu_flags = av_get_cpu_flags(); @@ -50,15 +50,13 @@ av_cold void ff_vp3dsp_init_x86(VP3DSPContext *c, int flags) if (EXTERNAL_MMXEXT(cpu_flags)) { c->idct_dc_add = ff_vp3_idct_dc_add_mmxext; - - if (!(flags & AV_CODEC_FLAG_BITEXACT)) { - c->v_loop_filter = c->v_loop_filter_unaligned = ff_vp3_v_loop_filter_mmxext; - c->h_loop_filter = c->h_loop_filter_unaligned = ff_vp3_h_loop_filter_mmxext; - } } if (EXTERNAL_SSE2(cpu_flags)) { c->idct_put = ff_vp3_idct_put_sse2; c->idct_add = ff_vp3_idct_add_sse2; + + c->v_loop_filter = c->v_loop_filter_unaligned = ff_vp3_v_loop_filter_sse2; + c->h_loop_filter = c->h_loop_filter_unaligned = ff_vp3_h_loop_filter_sse2; } } diff --git a/libavcodec/x86/vp6dsp.asm b/libavcodec/x86/vp6dsp.asm index 010654173..1f7443db6 100644 --- a/libavcodec/x86/vp6dsp.asm +++ b/libavcodec/x86/vp6dsp.asm @@ -1,5 +1,5 @@ ;****************************************************************************** -;* MMX/SSE2-optimized functions for the VP6 decoder +;* SSE2-optimized functions for the VP6 decoder ;* Copyright (C) 2009 Sebastien Lucas ;* Copyright (C) 2009 Zuxy Meng ;* @@ -26,47 +26,55 @@ cextern pw_64 SECTION .text -%macro DIAG4 6 +%macro DIAG4 7 +%if %7 + mova m0, [%1+%2] + mova m1, [%1+%3] +%else movq m0, [%1+%2] movq m1, [%1+%3] punpcklbw m0, m7 punpcklbw m1, m7 +%endif pmullw m0, m4 ; src[x-8 ] * biweight [0] pmullw m1, m5 ; src[x ] * biweight [1] paddw m0, m1 +%if %7 + mova m1, [%1+%4] + mova m2, [%1+%5] +%else movq m1, [%1+%4] movq m2, [%1+%5] punpcklbw m1, m7 punpcklbw m2, m7 +%endif + paddw m0, [pw_64] ; Add 64 pmullw m1, m6 ; src[x+8 ] * biweight [2] pmullw m2, m3 ; src[x+16] * biweight [3] paddw m1, m2 paddsw m0, m1 - paddsw m0, [pw_64] ; Add 64 psraw m0, 7 +%if %7 packuswb m0, m0 movq [%6], m0 +%else + pmaxsw m0, m7 ; clip to 0-255 range + mova [%6], m0 +%endif %endmacro %macro SPLAT4REGS 0 - pshuflw m4, m3, 0x0 - pshuflw m5, m3, 0x55 - pshuflw m6, m3, 0xAA - pshuflw m3, m3, 0xFF - punpcklqdq m4, m4 - punpcklqdq m5, m5 - punpcklqdq m6, m6 - punpcklqdq m3, m3 + punpcklwd m3, m3 + pshufd m4, m3, 0x0 + pshufd m5, m3, 0x55 + pshufd m6, m3, 0xAA + pshufd m3, m3, 0xFF %endmacro ; void ff_vp6_filter_diag4_(uint8_t *dst, uint8_t *src, ptrdiff_t stride, ; const int16_t h_weight[4], const int16_t v_weights[4]) INIT_XMM sse2 -cglobal vp6_filter_diag4, 5, 7, 8 - mov r5, rsp ; backup stack pointer - and rsp, ~(mmsize-1) ; align stack - sub rsp, 8*11 - +cglobal vp6_filter_diag4, 5, 6, 8, -16*11 sub r1, r2 pxor m7, m7 @@ -74,25 +82,24 @@ cglobal vp6_filter_diag4, 5, 7, 8 SPLAT4REGS mov r3, rsp - mov r6, 11 + mov r5d, 11 .nextrow: - DIAG4 r1, -1, 0, 1, 2, r3 - add r3, 8 + DIAG4 r1, -1, 0, 1, 2, r3, 0 + add r3, 16 add r1, r2 - dec r6 + dec r5d jnz .nextrow movq m3, [r4] SPLAT4REGS - lea r3, [rsp+8] - mov r6, 8 + lea r3, [rsp+16] + mov r1d, 8 .nextcol: - DIAG4 r3, -8, 0, 8, 16, r0 - add r3, 8 + DIAG4 r3, -16, 0, 16, 32, r0, 1 + add r3, 16 add r0, r2 - dec r6 + dec r1d jnz .nextcol - mov rsp, r5 ; restore stack pointer RET diff --git a/libavcodec/x86/vp6dsp_init.c b/libavcodec/x86/vp6dsp_init.c index 83d45ec36..db9a95767 100644 --- a/libavcodec/x86/vp6dsp_init.c +++ b/libavcodec/x86/vp6dsp_init.c @@ -25,10 +25,10 @@ #include "libavutil/x86/cpu.h" #include "libavcodec/vp56dsp.h" -void ff_vp6_filter_diag4_sse2(uint8_t *dst, uint8_t *src, ptrdiff_t stride, +void ff_vp6_filter_diag4_sse2(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, const int16_t *h_weights,const int16_t *v_weights); -av_cold void ff_vp6dsp_init_x86(VP56DSPContext *c) +av_cold void ff_vp6dsp_init_x86(VP6DSPContext *c) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/x86/vp8dsp.asm b/libavcodec/x86/vp8dsp.asm index 231c21ea0..22356f687 100644 --- a/libavcodec/x86/vp8dsp.asm +++ b/libavcodec/x86/vp8dsp.asm @@ -1,5 +1,5 @@ ;****************************************************************************** -;* VP8 MMXEXT optimizations +;* VP8 ASM optimizations ;* Copyright (c) 2010 Ronald S. Bultje ;* Copyright (c) 2010 Fiona Glaser ;* @@ -24,43 +24,43 @@ SECTION_RODATA -fourtap_filter_hw_m: times 4 dw -6, 123 - times 4 dw 12, -1 - times 4 dw -9, 93 - times 4 dw 50, -6 - times 4 dw -6, 50 - times 4 dw 93, -9 - times 4 dw -1, 12 - times 4 dw 123, -6 +fourtap_filter4_b_m: times 4 db -6, 123 + times 4 db 12, -1 + times 4 db -9, 93 + times 4 db 50, -6 + times 4 db -6, 50 + times 4 db 93, -9 + times 4 db -1, 12 + times 4 db 123, -6 -sixtap_filter_hw_m: times 4 dw 2, -11 - times 4 dw 108, 36 - times 4 dw -8, 1 - times 4 dw 3, -16 - times 4 dw 77, 77 - times 4 dw -16, 3 - times 4 dw 1, -8 - times 4 dw 36, 108 - times 4 dw -11, 2 +sixtap_filter4_hb_m: times 8 db 2, -11 + times 4 db 108, -8 + times 4 db 36, 1 + times 8 db 3, -16 + times 4 db 77, -16 + times 4 db 77, 3 + times 8 db 1, -8 + times 4 db 36, -11 + times 4 db 108, 2 -fourtap_filter_hb_m: times 8 db -6, 123 - times 8 db 12, -1 - times 8 db -9, 93 - times 8 db 50, -6 - times 8 db -6, 50 - times 8 db 93, -9 - times 8 db -1, 12 - times 8 db 123, -6 +fourtap_filter_b_m: times 8 db -6, 12 + times 8 db 123, -1 + times 8 db -9, 50 + times 8 db 93, -6 + times 8 db -6, 93 + times 8 db 50, -9 + times 8 db -1, 123 + times 8 db 12, -6 -sixtap_filter_hb_m: times 8 db 2, 1 - times 8 db -11, 108 - times 8 db 36, -8 - times 8 db 3, 3 - times 8 db -16, 77 - times 8 db 77, -16 - times 8 db 1, 2 - times 8 db -8, 36 - times 8 db 108, -11 +sixtap_filter_b_m: times 8 db 2, 36 + times 8 db -11, -8 + times 8 db 108, 1 + times 8 db 3, 77 + times 8 db -16, -16 + times 8 db 77, 3 + times 8 db 1, 108 + times 8 db -8, -11 + times 8 db 36, 2 fourtap_filter_v_m: times 8 dw -6 times 8 dw 123 @@ -115,20 +115,20 @@ bilinear_filter_vb_m: times 8 db 7, 1 times 8 db 1, 7 %if PIC -%define fourtap_filter_hw picregq -%define sixtap_filter_hw picregq -%define fourtap_filter_hb picregq -%define sixtap_filter_hb picregq +%define fourtap_filter_b picregq +%define fourtap_filter4_b picregq +%define sixtap_filter_b picregq +%define sixtap_filter4_hb picregq %define fourtap_filter_v picregq %define sixtap_filter_v picregq %define bilinear_filter_vw picregq %define bilinear_filter_vb picregq %define npicregs 1 %else -%define fourtap_filter_hw fourtap_filter_hw_m -%define sixtap_filter_hw sixtap_filter_hw_m -%define fourtap_filter_hb fourtap_filter_hb_m -%define sixtap_filter_hb sixtap_filter_hb_m +%define fourtap_filter_b fourtap_filter_b_m +%define fourtap_filter4_b fourtap_filter4_b_m +%define sixtap_filter_b sixtap_filter_b_m +%define sixtap_filter4_hb sixtap_filter4_hb_m %define fourtap_filter_v fourtap_filter_v_m %define sixtap_filter_v sixtap_filter_v_m %define bilinear_filter_vw bilinear_filter_vw_m @@ -136,12 +136,17 @@ bilinear_filter_vb_m: times 8 db 7, 1 %define npicregs 0 %endif -filter_h2_shuf: db 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 -filter_h4_shuf: db 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10 +filter4_h4_shuf: db 0, 1, 1, 2, 2, 3, 3, 4, 2, 3, 3, 4, 4, 5, 5, 6 +filter4_h6_shuf: db 1, 3, 2, 4, 3, 5, 4, 6, 2, 4, 3, 5, 4, 6, 5, 7 -filter_h6_shuf1: db 0, 5, 1, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12 -filter_h6_shuf2: db 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9 -filter_h6_shuf3: db 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11 +filter_h4_shuf1: db 0, 2, 1, 3, 2, 4, 3, 5, 4, 6, 5, 7, 6, 8, 7, 9 +filter_h4_shuf2: db 1, 3, 2, 4, 3, 5, 4, 6, 5, 7, 6, 8, 7, 9, 8, 10 + +filter_h6_shuf1: db 0, 3, 1, 4, 2, 5, 3, 6, 4, 7, 5, 8, 6, 9, 7, 10 +filter_h6_shuf2: db 1, 4, 2, 5, 3, 6, 4, 7, 5, 8, 6, 9, 7, 10, 8, 11 +filter_h6_shuf3: db 2, 5, 3, 6, 4, 7, 5, 8, 6, 9, 7, 10, 8, 11, 9, 12 + +filter_h2_shuf: db 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 pw_20091: times 4 dw 20091 pw_17734: times 4 dw 17734 @@ -162,72 +167,109 @@ SECTION .text ;------------------------------------------------------------------------------- %macro FILTER_SSSE3 1 -cglobal put_vp8_epel%1_h6, 6, 6 + npicregs, 8, dst, dststride, src, srcstride, height, mx, picreg +%if %1 == 4 +%define MOV movd +%else +%define MOV movq +%endif + +cglobal put_vp8_epel%1_h6, 6, 6 + npicregs, 6+2*(%1==8), dst, dststride, src, srcstride, height, mx, picreg +%if %1 == 4 + mova m3, [filter4_h6_shuf] +%if PIC + lea picregq, [sixtap_filter4_hb_m] +%endif + shl mxd, 4 + mova m4, [sixtap_filter4_hb+mxq-32] + mova m5, [sixtap_filter4_hb+mxq-16] +%else lea mxd, [mxq*3] mova m3, [filter_h6_shuf2] mova m4, [filter_h6_shuf3] %if PIC - lea picregq, [sixtap_filter_hb_m] + lea picregq, [sixtap_filter_b_m] +%endif + mova m5, [sixtap_filter_b+mxq*8-48] ; set up 6tap filter in bytes + mova m6, [sixtap_filter_b+mxq*8-32] + mova m7, [sixtap_filter_b+mxq*8-16] %endif - mova m5, [sixtap_filter_hb+mxq*8-48] ; set up 6tap filter in bytes - mova m6, [sixtap_filter_hb+mxq*8-32] - mova m7, [sixtap_filter_hb+mxq*8-16] .nextrow: +%if %1 == 4 + ; we need nine bytes, so two loads + movq m1, [srcq-1] + movq m0, [srcq-2] + punpcklbw m0, m1 + pshufb m1, m3 + pmaddubsw m1, m5 + pmaddubsw m0, m4 + movhlps m2, m1 +%else movu m0, [srcq-2] mova m1, m0 mova m2, m0 -%if mmsize == 8 -; For epel4, we need 9 bytes, but only 8 get loaded; to compensate, do the -; shuffle with a memory operand - punpcklbw m0, [srcq+3] -%else pshufb m0, [filter_h6_shuf1] -%endif pshufb m1, m3 pshufb m2, m4 pmaddubsw m0, m5 pmaddubsw m1, m6 pmaddubsw m2, m7 - paddsw m0, m1 +%endif + add srcq, srcstrideq + paddw m0, m1 paddsw m0, m2 pmulhrsw m0, [pw_256] packuswb m0, m0 - movh [dstq], m0 ; store + MOV [dstq], m0 ; store ; go to next line add dstq, dststrideq - add srcq, srcstrideq dec heightd ; next row jg .nextrow RET -cglobal put_vp8_epel%1_h4, 6, 6 + npicregs, 7, dst, dststride, src, srcstride, height, mx, picreg - shl mxd, 4 +cglobal put_vp8_epel%1_h4, 6, 6 + npicregs, 6+!!(%1 == 8), dst, dststride, src, srcstride, height, mx, picreg mova m2, [pw_256] - mova m3, [filter_h2_shuf] - mova m4, [filter_h4_shuf] +%if %1 == 8 + shl mxd, 4 + mova m3, [filter_h4_shuf1] + mova m4, [filter_h4_shuf2] %if PIC - lea picregq, [fourtap_filter_hb_m] + lea picregq, [fourtap_filter_b_m] +%endif + mova m5, [fourtap_filter_b+mxq-16] ; set up 4tap filter in bytes + mova m6, [fourtap_filter_b+mxq] +%else + shl mxd, 3 + mova m3, [filter4_h4_shuf] +%if PIC + lea picregq, [fourtap_filter4_b_m] +%endif + mova m5, [fourtap_filter4_b+mxq-8] %endif - mova m5, [fourtap_filter_hb+mxq-16] ; set up 4tap filter in bytes - mova m6, [fourtap_filter_hb+mxq] .nextrow: +%if %1 == 4 + movq m0, [srcq-1] + pshufb m0, m3 + pmaddubsw m0, m5 + movhlps m1, m0 +%else movu m0, [srcq-1] mova m1, m0 pshufb m0, m3 pshufb m1, m4 pmaddubsw m0, m5 pmaddubsw m1, m6 +%endif + add srcq, srcstrideq paddsw m0, m1 pmulhrsw m0, m2 packuswb m0, m0 - movh [dstq], m0 ; store + MOV [dstq], m0 ; store ; go to next line add dstq, dststrideq - add srcq, srcstrideq dec heightd ; next row jg .nextrow RET @@ -235,71 +277,124 @@ cglobal put_vp8_epel%1_h4, 6, 6 + npicregs, 7, dst, dststride, src, srcstride, h cglobal put_vp8_epel%1_v4, 7, 7, 8, dst, dststride, src, srcstride, height, picreg, my shl myd, 4 %if PIC - lea picregq, [fourtap_filter_hb_m] + lea picregq, [fourtap_filter_b_m] %endif - mova m5, [fourtap_filter_hb+myq-16] - mova m6, [fourtap_filter_hb+myq] + mova m5, [fourtap_filter_b+myq-16] + mova m6, [fourtap_filter_b+myq] mova m7, [pw_256] ; read 3 lines - sub srcq, srcstrideq - movh m0, [srcq] - movh m1, [srcq+ srcstrideq] - movh m2, [srcq+2*srcstrideq] - add srcq, srcstrideq + mov picregq, srcstrideq + neg picregq + MOV m0, [srcq+picregq] + MOV m1, [srcq] + MOV m2, [srcq+srcstrideq] + lea srcq, [srcq+2*srcstrideq] + punpcklbw m0, m2 +%if %1 == 4 +.next2rows: + movd m3, [srcq] + movd m4, [srcq+srcstrideq] + punpcklbw m1, m3 + punpcklqdq m0, m1 + punpcklbw m2, m4 + pmaddubsw m0, m5 + punpcklqdq m1, m2 + pmaddubsw m1, m6 + lea srcq, [srcq+2*srcstrideq] + paddsw m1, m0 + pmulhrsw m1, m7 + mova m0, m2 + packuswb m1, m1 + movd [dstq], m1 + mova m2, m4 + psrldq m1, 4 + movd [dstq+dststrideq], m1 + mova m1, m3 + lea dstq, [dstq+2*dststrideq] + sub heightd, 2 + jg .next2rows +%else .nextrow: - movh m3, [srcq+2*srcstrideq] ; read new row - mova m4, m0 + movh m3, [srcq] ; read new row + pmaddubsw m0, m5 + punpcklbw m1, m3 + pmaddubsw m4, m1, m6 + add srcq, srcstrideq + paddsw m4, m0 mova m0, m1 - punpcklbw m4, m1 - mova m1, m2 - punpcklbw m2, m3 - pmaddubsw m4, m5 - pmaddubsw m2, m6 - paddsw m4, m2 - mova m2, m3 pmulhrsw m4, m7 + mova m1, m2 packuswb m4, m4 + mova m2, m3 movh [dstq], m4 ; go to next line add dstq, dststrideq - add srcq, srcstrideq dec heightd ; next row jg .nextrow +%endif RET cglobal put_vp8_epel%1_v6, 7, 7, 8, dst, dststride, src, srcstride, height, picreg, my lea myd, [myq*3] %if PIC - lea picregq, [sixtap_filter_hb_m] + lea picregq, [sixtap_filter_b_m] %endif - lea myq, [sixtap_filter_hb+myq*8] + lea myq, [sixtap_filter_b+myq*8] ; read 5 lines - sub srcq, srcstrideq - sub srcq, srcstrideq - movh m0, [srcq] - movh m1, [srcq+srcstrideq] - movh m2, [srcq+srcstrideq*2] + mov picregq, srcstrideq + neg picregq + MOV m0, [srcq+2*picregq] + MOV m1, [srcq+picregq] + MOV m2, [srcq] + MOV m3, [srcq+srcstrideq] + MOV m4, [srcq+2*srcstrideq] lea srcq, [srcq+srcstrideq*2] - add srcq, srcstrideq - movh m3, [srcq] - movh m4, [srcq+srcstrideq] + punpcklbw m0, m3 + punpcklbw m1, m4 +%if %1 == 4 + punpcklqdq m0, m1 + +.next2rows: + movd m5, [srcq+srcstrideq] + movd m6, [srcq+2*srcstrideq] + pmaddubsw m0, [myq-48] + punpcklbw m2, m5 + punpcklqdq m1, m2 + pmaddubsw m1, [myq-32] + punpcklbw m3, m6 + punpcklqdq m2, m3 + paddw m0, m1 + pmaddubsw m1, m2, [myq-16] + lea srcq, [srcq+2*srcstrideq] + paddsw m1, m0 + mova m0, m2 + pmulhrsw m1, [pw_256] + mova m2, m4 + packuswb m1, m1 + movd [dstq], m1 + mova m4, m6 + psrldq m1, 4 + movd [dstq+dststrideq], m1 + lea dstq, [dstq+2*dststrideq] + mova m1, m3 + mova m3, m5 + sub heightd, 2 + jg .next2rows +%else .nextrow: - movh m5, [srcq+2*srcstrideq] ; read new row - mova m6, m0 - punpcklbw m6, m5 + movh m5, [srcq+srcstrideq] ; read new row + pmaddubsw m0, [myq-48] + punpcklbw m2, m5 + pmaddubsw m6, m1, [myq-32] + pmaddubsw m7, m2, [myq-16] + add srcq, srcstrideq + paddw m6, m0 mova m0, m1 - punpcklbw m1, m2 - mova m7, m3 - punpcklbw m7, m4 - pmaddubsw m6, [myq-48] - pmaddubsw m1, [myq-32] - pmaddubsw m7, [myq-16] - paddsw m6, m1 paddsw m6, m7 mova m1, m2 mova m2, m3 @@ -311,123 +406,16 @@ cglobal put_vp8_epel%1_v6, 7, 7, 8, dst, dststride, src, srcstride, height, picr ; go to next line add dstq, dststrideq - add srcq, srcstrideq dec heightd ; next row jg .nextrow +%endif RET %endmacro -INIT_MMX ssse3 -FILTER_SSSE3 4 INIT_XMM ssse3 +FILTER_SSSE3 4 FILTER_SSSE3 8 -; 4x4 block, H-only 4-tap filter -INIT_MMX mmxext -cglobal put_vp8_epel4_h4, 6, 6 + npicregs, 0, dst, dststride, src, srcstride, height, mx, picreg - shl mxd, 4 -%if PIC - lea picregq, [fourtap_filter_hw_m] -%endif - movq mm4, [fourtap_filter_hw+mxq-16] ; set up 4tap filter in words - movq mm5, [fourtap_filter_hw+mxq] - movq mm7, [pw_64] - pxor mm6, mm6 - -.nextrow: - movq mm1, [srcq-1] ; (ABCDEFGH) load 8 horizontal pixels - - ; first set of 2 pixels - movq mm2, mm1 ; byte ABCD.. - punpcklbw mm1, mm6 ; byte->word ABCD - pshufw mm0, mm2, 9 ; byte CDEF.. - punpcklbw mm0, mm6 ; byte->word CDEF - pshufw mm3, mm1, 0x94 ; word ABBC - pshufw mm1, mm0, 0x94 ; word CDDE - pmaddwd mm3, mm4 ; multiply 2px with F0/F1 - movq mm0, mm1 ; backup for second set of pixels - pmaddwd mm1, mm5 ; multiply 2px with F2/F3 - paddd mm3, mm1 ; finish 1st 2px - - ; second set of 2 pixels, use backup of above - punpckhbw mm2, mm6 ; byte->word EFGH - pmaddwd mm0, mm4 ; multiply backed up 2px with F0/F1 - pshufw mm1, mm2, 0x94 ; word EFFG - pmaddwd mm1, mm5 ; multiply 2px with F2/F3 - paddd mm0, mm1 ; finish 2nd 2px - - ; merge two sets of 2 pixels into one set of 4, round/clip/store - packssdw mm3, mm0 ; merge dword->word (4px) - paddsw mm3, mm7 ; rounding - psraw mm3, 7 - packuswb mm3, mm6 ; clip and word->bytes - movd [dstq], mm3 ; store - - ; go to next line - add dstq, dststrideq - add srcq, srcstrideq - dec heightd ; next row - jg .nextrow - RET - -; 4x4 block, H-only 6-tap filter -INIT_MMX mmxext -cglobal put_vp8_epel4_h6, 6, 6 + npicregs, 0, dst, dststride, src, srcstride, height, mx, picreg - lea mxd, [mxq*3] -%if PIC - lea picregq, [sixtap_filter_hw_m] -%endif - movq mm4, [sixtap_filter_hw+mxq*8-48] ; set up 4tap filter in words - movq mm5, [sixtap_filter_hw+mxq*8-32] - movq mm6, [sixtap_filter_hw+mxq*8-16] - movq mm7, [pw_64] - pxor mm3, mm3 - -.nextrow: - movq mm1, [srcq-2] ; (ABCDEFGH) load 8 horizontal pixels - - ; first set of 2 pixels - movq mm2, mm1 ; byte ABCD.. - punpcklbw mm1, mm3 ; byte->word ABCD - pshufw mm0, mm2, 0x9 ; byte CDEF.. - punpckhbw mm2, mm3 ; byte->word EFGH - punpcklbw mm0, mm3 ; byte->word CDEF - pshufw mm1, mm1, 0x94 ; word ABBC - pshufw mm2, mm2, 0x94 ; word EFFG - pmaddwd mm1, mm4 ; multiply 2px with F0/F1 - pshufw mm3, mm0, 0x94 ; word CDDE - movq mm0, mm3 ; backup for second set of pixels - pmaddwd mm3, mm5 ; multiply 2px with F2/F3 - paddd mm1, mm3 ; add to 1st 2px cache - movq mm3, mm2 ; backup for second set of pixels - pmaddwd mm2, mm6 ; multiply 2px with F4/F5 - paddd mm1, mm2 ; finish 1st 2px - - ; second set of 2 pixels, use backup of above - movd mm2, [srcq+3] ; byte FGHI (prevent overreads) - pmaddwd mm0, mm4 ; multiply 1st backed up 2px with F0/F1 - pmaddwd mm3, mm5 ; multiply 2nd backed up 2px with F2/F3 - paddd mm0, mm3 ; add to 2nd 2px cache - pxor mm3, mm3 - punpcklbw mm2, mm3 ; byte->word FGHI - pshufw mm2, mm2, 0xE9 ; word GHHI - pmaddwd mm2, mm6 ; multiply 2px with F4/F5 - paddd mm0, mm2 ; finish 2nd 2px - - ; merge two sets of 2 pixels into one set of 4, round/clip/store - packssdw mm1, mm0 ; merge dword->word (4px) - paddsw mm1, mm7 ; rounding - psraw mm1, 7 - packuswb mm1, mm3 ; clip and word->bytes - movd [dstq], mm1 ; store - - ; go to next line - add dstq, dststrideq - add srcq, srcstrideq - dec heightd ; next row - jg .nextrow - RET - INIT_XMM sse2 cglobal put_vp8_epel8_h4, 6, 6 + npicregs, 10, dst, dststride, src, srcstride, height, mx, picreg shl mxd, 5 @@ -461,17 +449,17 @@ cglobal put_vp8_epel8_h4, 6, 6 + npicregs, 10, dst, dststride, src, srcstride, h pmullw m2, [mxq+32] pmullw m3, [mxq+48] %endif - paddsw m0, m1 - paddsw m2, m3 + add srcq, srcstrideq + paddw m0, m1 + paddw m2, m3 + paddw m0, m4 paddsw m0, m2 - paddsw m0, m4 psraw m0, 7 packuswb m0, m7 movh [dstq], m0 ; store ; go to next line add dstq, dststrideq - add srcq, srcstrideq dec heightd ; next row jg .nextrow RET @@ -522,26 +510,26 @@ cglobal put_vp8_epel8_h6, 6, 6 + npicregs, 14, dst, dststride, src, srcstride, h pmullw m4, [mxq+64] pmullw m5, [mxq+80] %endif - paddsw m1, m4 - paddsw m0, m5 - paddsw m1, m2 - paddsw m0, m3 + add srcq, srcstrideq + paddw m1, m4 + paddw m0, m5 + paddw m1, m2 + paddw m0, m3 + paddw m1, m6 paddsw m0, m1 - paddsw m0, m6 psraw m0, 7 packuswb m0, m7 movh [dstq], m0 ; store ; go to next line add dstq, dststrideq - add srcq, srcstrideq dec heightd ; next row jg .nextrow RET -%macro FILTER_V 1 +INIT_XMM sse2 ; 4x4 block, V-only 4-tap filter -cglobal put_vp8_epel%1_v4, 7, 7, 8, dst, dststride, src, srcstride, height, picreg, my +cglobal put_vp8_epel8_v4, 7, 7, 8, dst, dststride, src, srcstride, height, picreg, my shl myd, 5 %if PIC lea picregq, [fourtap_filter_v_m] @@ -568,33 +556,33 @@ cglobal put_vp8_epel%1_v4, 7, 7, 8, dst, dststride, src, srcstride, height, picr mova m3, m4 pmullw m0, [myq+0] pmullw m4, m5 - paddsw m4, m0 + paddw m4, m0 ; then calculate positive taps mova m0, m1 pmullw m1, [myq+16] - paddsw m4, m1 + paddw m4, m1 mova m1, m2 pmullw m2, [myq+32] + paddw m4, m6 + add srcq, srcstrideq paddsw m4, m2 mova m2, m3 ; round/clip/store - paddsw m4, m6 psraw m4, 7 packuswb m4, m7 movh [dstq], m4 ; go to next line add dstq, dststrideq - add srcq, srcstrideq dec heightd ; next row jg .nextrow RET ; 4x4 block, V-only 6-tap filter -cglobal put_vp8_epel%1_v6, 7, 7, 8, dst, dststride, src, srcstride, height, picreg, my +cglobal put_vp8_epel8_v6, 7, 7, 8, dst, dststride, src, srcstride, height, picreg, my shl myd, 4 lea myq, [myq*3] %if PIC @@ -604,15 +592,14 @@ cglobal put_vp8_epel%1_v6, 7, 7, 8, dst, dststride, src, srcstride, height, picr pxor m7, m7 ; read 5 lines - sub srcq, srcstrideq - sub srcq, srcstrideq - movh m0, [srcq] - movh m1, [srcq+srcstrideq] - movh m2, [srcq+srcstrideq*2] + mov picregq, srcstrideq + neg picregq + movh m0, [srcq+2*picregq] + movh m1, [srcq+picregq] + movh m2, [srcq] + movh m3, [srcq+srcstrideq] + movh m4, [srcq+2*srcstrideq] lea srcq, [srcq+srcstrideq*2] - add srcq, srcstrideq - movh m3, [srcq] - movh m4, [srcq+srcstrideq] punpcklbw m0, m7 punpcklbw m1, m7 punpcklbw m2, m7 @@ -625,19 +612,21 @@ cglobal put_vp8_epel%1_v6, 7, 7, 8, dst, dststride, src, srcstride, height, picr pmullw m5, [myq+16] mova m6, m4 pmullw m6, [myq+64] - paddsw m6, m5 + paddw m6, m5 ; then calculate positive taps - movh m5, [srcq+2*srcstrideq] ; read new row + movh m5, [srcq+srcstrideq] ; read new row punpcklbw m5, m7 pmullw m0, [myq+0] - paddsw m6, m0 + paddw m6, [pw_64] + paddw m6, m0 mova m0, m1 mova m1, m2 pmullw m2, [myq+32] - paddsw m6, m2 + paddw m6, m2 mova m2, m3 pmullw m3, [myq+48] + add srcq, srcstrideq paddsw m6, m3 mova m3, m4 mova m4, m5 @@ -645,23 +634,15 @@ cglobal put_vp8_epel%1_v6, 7, 7, 8, dst, dststride, src, srcstride, height, picr paddsw m6, m5 ; round/clip/store - paddsw m6, [pw_64] psraw m6, 7 packuswb m6, m7 movh [dstq], m6 ; go to next line add dstq, dststrideq - add srcq, srcstrideq dec heightd ; next row jg .nextrow RET -%endmacro - -INIT_MMX mmxext -FILTER_V 4 -INIT_XMM sse2 -FILTER_V 8 %macro FILTER_BILINEAR 1 %if cpuflag(ssse3) @@ -672,14 +653,15 @@ cglobal put_vp8_bilinear%1_v, 7, 7, 5, dst, dststride, src, srcstride, height, p %endif pxor m4, m4 mova m3, [bilinear_filter_vb+myq-16] -.nextrow: movh m0, [srcq+srcstrideq*0] +.nextrow: movh m1, [srcq+srcstrideq*1] movh m2, [srcq+srcstrideq*2] punpcklbw m0, m1 punpcklbw m1, m2 pmaddubsw m0, m3 pmaddubsw m1, m3 + lea srcq, [srcq+srcstrideq*2] psraw m0, 2 psraw m1, 2 pavgw m0, m4 @@ -694,6 +676,7 @@ cglobal put_vp8_bilinear%1_v, 7, 7, 5, dst, dststride, src, srcstride, height, p movh [dstq+dststrideq*0], m0 movhps [dstq+dststrideq*1], m0 %endif + mova m0, m2 %else ; cpuflag(ssse3) cglobal put_vp8_bilinear%1_v, 7, 7, 7, dst, dststride, src, srcstride, height, picreg, my shl myd, 4 @@ -716,26 +699,19 @@ cglobal put_vp8_bilinear%1_v, 7, 7, 7, dst, dststride, src, srcstride, height, p pmullw m1, m5 pmullw m2, m4 pmullw m3, m5 - paddsw m0, m1 - paddsw m2, m3 + lea srcq, [srcq+srcstrideq*2] + paddw m0, m1 + paddw m2, m3 psraw m0, 2 psraw m2, 2 pavgw m0, m6 pavgw m2, m6 -%if mmsize == 8 - packuswb m0, m0 - packuswb m2, m2 - movh [dstq+dststrideq*0], m0 - movh [dstq+dststrideq*1], m2 -%else packuswb m0, m2 movh [dstq+dststrideq*0], m0 movhps [dstq+dststrideq*1], m0 -%endif %endif ; cpuflag(ssse3) lea dstq, [dstq+dststrideq*2] - lea srcq, [srcq+srcstrideq*2] sub heightd, 2 jg .nextrow RET @@ -756,6 +732,7 @@ cglobal put_vp8_bilinear%1_h, 6, 6 + npicregs, 5, dst, dststride, src, srcstride pshufb m1, m2 pmaddubsw m0, m3 pmaddubsw m1, m3 + lea srcq, [srcq+srcstrideq*2] psraw m0, 2 psraw m1, 2 pavgw m0, m4 @@ -793,33 +770,24 @@ cglobal put_vp8_bilinear%1_h, 6, 6 + npicregs, 7, dst, dststride, src, srcstride pmullw m1, m5 pmullw m2, m4 pmullw m3, m5 - paddsw m0, m1 - paddsw m2, m3 + lea srcq, [srcq+srcstrideq*2] + paddw m0, m1 + paddw m2, m3 psraw m0, 2 psraw m2, 2 pavgw m0, m6 pavgw m2, m6 -%if mmsize == 8 - packuswb m0, m0 - packuswb m2, m2 - movh [dstq+dststrideq*0], m0 - movh [dstq+dststrideq*1], m2 -%else packuswb m0, m2 movh [dstq+dststrideq*0], m0 movhps [dstq+dststrideq*1], m0 -%endif %endif ; cpuflag(ssse3) lea dstq, [dstq+dststrideq*2] - lea srcq, [srcq+srcstrideq*2] sub heightd, 2 jg .nextrow RET %endmacro -INIT_MMX mmxext -FILTER_BILINEAR 4 INIT_XMM sse2 FILTER_BILINEAR 8 INIT_MMX ssse3 @@ -827,14 +795,22 @@ FILTER_BILINEAR 4 INIT_XMM ssse3 FILTER_BILINEAR 8 -INIT_MMX mmx -cglobal put_vp8_pixels8, 5, 5, 0, dst, dststride, src, srcstride, height +INIT_XMM sse2 +cglobal put_vp8_pixels8, 5, 5+2*ARCH_X86_64, 2, dst, dststride, src, srcstride, height .nextrow: - movq mm0, [srcq+srcstrideq*0] - movq mm1, [srcq+srcstrideq*1] +%if ARCH_X86_64 + mov r5q, [srcq+srcstrideq*0] + mov r6q, [srcq+srcstrideq*1] lea srcq, [srcq+srcstrideq*2] - movq [dstq+dststrideq*0], mm0 - movq [dstq+dststrideq*1], mm1 + mov [dstq+dststrideq*0], r5q + mov [dstq+dststrideq*1], r6q +%else + movq m0, [srcq+srcstrideq*0] + movq m1, [srcq+srcstrideq*1] + lea srcq, [srcq+srcstrideq*2] + movq [dstq+dststrideq*0], m0 + movq [dstq+dststrideq*1], m1 +%endif lea dstq, [dstq+dststrideq*2] sub heightd, 2 jg .nextrow diff --git a/libavcodec/x86/vp8dsp_init.c b/libavcodec/x86/vp8dsp_init.c index bd20da1fc..828b038cd 100644 --- a/libavcodec/x86/vp8dsp_init.c +++ b/libavcodec/x86/vp8dsp_init.c @@ -26,24 +26,9 @@ #include "libavutil/x86/cpu.h" #include "libavcodec/vp8dsp.h" -#if HAVE_X86ASM - /* * MC functions */ -void ff_put_vp8_epel4_h4_mmxext(uint8_t *dst, ptrdiff_t dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, int mx, int my); -void ff_put_vp8_epel4_h6_mmxext(uint8_t *dst, ptrdiff_t dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, int mx, int my); -void ff_put_vp8_epel4_v4_mmxext(uint8_t *dst, ptrdiff_t dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, int mx, int my); -void ff_put_vp8_epel4_v6_mmxext(uint8_t *dst, ptrdiff_t dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, int mx, int my); - void ff_put_vp8_epel8_h4_sse2 (uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, ptrdiff_t srcstride, int height, int mx, int my); @@ -82,9 +67,6 @@ void ff_put_vp8_epel8_v6_ssse3 (uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, ptrdiff_t srcstride, int height, int mx, int my); -void ff_put_vp8_bilinear4_h_mmxext(uint8_t *dst, ptrdiff_t dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, int mx, int my); void ff_put_vp8_bilinear8_h_sse2 (uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, ptrdiff_t srcstride, int height, int mx, int my); @@ -95,9 +77,6 @@ void ff_put_vp8_bilinear8_h_ssse3 (uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, ptrdiff_t srcstride, int height, int mx, int my); -void ff_put_vp8_bilinear4_v_mmxext(uint8_t *dst, ptrdiff_t dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, int mx, int my); void ff_put_vp8_bilinear8_v_sse2 (uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, ptrdiff_t srcstride, int height, int mx, int my); @@ -109,7 +88,7 @@ void ff_put_vp8_bilinear8_v_ssse3 (uint8_t *dst, ptrdiff_t dststride, int height, int mx, int my); -void ff_put_vp8_pixels8_mmx (uint8_t *dst, ptrdiff_t dststride, +void ff_put_vp8_pixels8_sse2(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, ptrdiff_t srcstride, int height, int mx, int my); void ff_put_vp8_pixels16_sse(uint8_t *dst, ptrdiff_t dststride, @@ -126,16 +105,6 @@ static void ff_put_vp8_ ## FILTERTYPE ## 16_ ## TAPTYPE ## _ ## OPT( \ ff_put_vp8_ ## FILTERTYPE ## 8_ ## TAPTYPE ## _ ## OPT( \ dst + 8, dststride, src + 8, srcstride, height, mx, my); \ } -#define TAP_W8(OPT, FILTERTYPE, TAPTYPE) \ -static void ff_put_vp8_ ## FILTERTYPE ## 8_ ## TAPTYPE ## _ ## OPT( \ - uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \ - ptrdiff_t srcstride, int height, int mx, int my) \ -{ \ - ff_put_vp8_ ## FILTERTYPE ## 4_ ## TAPTYPE ## _ ## OPT( \ - dst, dststride, src, srcstride, height, mx, my); \ - ff_put_vp8_ ## FILTERTYPE ## 4_ ## TAPTYPE ## _ ## OPT( \ - dst + 4, dststride, src + 4, srcstride, height, mx, my); \ -} TAP_W16(sse2, epel, h6) TAP_W16(sse2, epel, v6) @@ -161,14 +130,6 @@ static void ff_put_vp8_epel ## SIZE ## _h ## TAPNUMX ## v ## TAPNUMY ## _ ## OPT dst, dststride, tmpptr, SIZE, height, mx, my); \ } -#define HVTAPMMX(x, y) \ -HVTAP(mmxext, 8, x, y, 4, 8) - -HVTAPMMX(4, 4) -HVTAPMMX(4, 6) -HVTAPMMX(6, 4) -HVTAPMMX(6, 6) - #define HVTAPSSE2(x, y, w) \ HVTAP(sse2, 16, x, y, w, 16) \ HVTAP(ssse3, 16, x, y, w, 16) @@ -196,7 +157,6 @@ static void ff_put_vp8_bilinear ## SIZE ## _hv_ ## OPT( \ dst, dststride, tmp, SIZE, height, mx, my); \ } -HVBILIN(mmxext, 8, 4, 8) HVBILIN(sse2, 8, 8, 16) HVBILIN(sse2, 8, 16, 16) HVBILIN(ssse3, 8, 4, 8) @@ -254,8 +214,6 @@ DECLARE_LOOP_FILTER(sse2) DECLARE_LOOP_FILTER(ssse3) DECLARE_LOOP_FILTER(sse4) -#endif /* HAVE_X86ASM */ - #define VP8_LUMA_MC_FUNC(IDX, SIZE, OPT) \ c->put_vp8_epel_pixels_tab[IDX][0][2] = ff_put_vp8_epel ## SIZE ## _h6_ ## OPT; \ c->put_vp8_epel_pixels_tab[IDX][2][0] = ff_put_vp8_epel ## SIZE ## _v6_ ## OPT; \ @@ -282,33 +240,24 @@ DECLARE_LOOP_FILTER(sse4) av_cold void ff_vp78dsp_init_x86(VP8DSPContext *c) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); - if (EXTERNAL_MMX(cpu_flags)) { - c->put_vp8_epel_pixels_tab[1][0][0] = - c->put_vp8_bilinear_pixels_tab[1][0][0] = ff_put_vp8_pixels8_mmx; - } - - /* note that 4-tap width=16 functions are missing because w=16 - * is only used for luma, and luma is always a copy or sixtap. */ - if (EXTERNAL_MMXEXT(cpu_flags)) { - VP8_MC_FUNC(2, 4, mmxext); - VP8_BILINEAR_MC_FUNC(2, 4, mmxext); - } - if (EXTERNAL_SSE(cpu_flags)) { c->put_vp8_epel_pixels_tab[0][0][0] = c->put_vp8_bilinear_pixels_tab[0][0][0] = ff_put_vp8_pixels16_sse; } if (EXTERNAL_SSE2_SLOW(cpu_flags)) { + c->put_vp8_epel_pixels_tab[1][0][0] = + c->put_vp8_bilinear_pixels_tab[1][0][0] = ff_put_vp8_pixels8_sse2; VP8_LUMA_MC_FUNC(0, 16, sse2); VP8_MC_FUNC(1, 8, sse2); VP8_BILINEAR_MC_FUNC(0, 16, sse2); VP8_BILINEAR_MC_FUNC(1, 8, sse2); } + /* note that 4-tap width=16 functions are missing because w=16 + * is only used for luma, and luma is always a copy or sixtap. */ if (EXTERNAL_SSSE3(cpu_flags)) { VP8_LUMA_MC_FUNC(0, 16, ssse3); VP8_MC_FUNC(1, 8, ssse3); @@ -317,12 +266,10 @@ av_cold void ff_vp78dsp_init_x86(VP8DSPContext *c) VP8_BILINEAR_MC_FUNC(1, 8, ssse3); VP8_BILINEAR_MC_FUNC(2, 4, ssse3); } -#endif /* HAVE_X86ASM */ } av_cold void ff_vp8dsp_init_x86(VP8DSPContext *c) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_MMX(cpu_flags)) { @@ -379,5 +326,4 @@ av_cold void ff_vp8dsp_init_x86(VP8DSPContext *c) c->vp8_h_loop_filter16y = ff_vp8_h_loop_filter16y_mbedge_sse4; c->vp8_h_loop_filter8uv = ff_vp8_h_loop_filter8uv_mbedge_sse4; } -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/x86/vp9dsp_init.c b/libavcodec/x86/vp9dsp_init.c index 8d11dbc34..e479fd25e 100644 --- a/libavcodec/x86/vp9dsp_init.c +++ b/libavcodec/x86/vp9dsp_init.c @@ -26,8 +26,6 @@ #include "libavcodec/vp9dsp.h" #include "libavcodec/x86/vp9dsp_init.h" -#if HAVE_X86ASM - decl_fpel_func(put, 4, , mmx); decl_fpel_func(put, 8, , mmx); decl_fpel_func(put, 16, , sse); @@ -43,13 +41,17 @@ decl_fpel_func(put, 64, , avx); decl_fpel_func(avg, 32, _8, avx2); decl_fpel_func(avg, 64, _8, avx2); -decl_mc_funcs(4, mmxext, int16_t, 8, 8); decl_mc_funcs(8, sse2, int16_t, 8, 8); decl_mc_funcs(4, ssse3, int8_t, 32, 8); decl_mc_funcs(8, ssse3, int8_t, 32, 8); #if ARCH_X86_64 decl_mc_funcs(16, ssse3, int8_t, 32, 8); decl_mc_funcs(32, avx2, int8_t, 32, 8); +decl_subpel_asm( 4, 8, avx512icl); +decl_subpel_asm( 8, 8, avx512icl); +decl_subpel_asm(16, 8, avx512icl); +decl_subpel_asm(32, 8, avx512icl); +decl_subpel_asm(64, 8, avx512icl); #endif mc_rep_funcs(16, 8, 8, sse2, int16_t, 8, 8) @@ -67,10 +69,11 @@ mc_rep_funcs(64, 32, 32, avx2, int8_t, 32, 8) extern const int8_t ff_filters_ssse3[3][15][4][32]; extern const int16_t ff_filters_sse2[3][15][8][8]; -filters_8tap_2d_fn2(put, 16, 8, 1, mmxext, sse2, sse2) -filters_8tap_2d_fn2(avg, 16, 8, 1, mmxext, sse2, sse2) -filters_8tap_2d_fn2(put, 16, 8, 1, ssse3, ssse3, ssse3) -filters_8tap_2d_fn2(avg, 16, 8, 1, ssse3, ssse3, ssse3) +filters_8tap_2d_fn2(put, 16, 8, 1, sse2, sse2) +filters_8tap_2d_fn2(avg, 16, 8, 1, sse2, sse2) +filters_8tap_2d_fn3(put, 16, 8, 1, ssse3, ssse3) +filters_8tap_2d_fn3(avg, 16, 8, 1, ssse3, ssse3) + #if ARCH_X86_64 && HAVE_AVX2_EXTERNAL filters_8tap_2d_fn(put, 64, 32, 8, 1, avx2, ssse3) filters_8tap_2d_fn(put, 32, 32, 8, 1, avx2, ssse3) @@ -78,10 +81,10 @@ filters_8tap_2d_fn(avg, 64, 32, 8, 1, avx2, ssse3) filters_8tap_2d_fn(avg, 32, 32, 8, 1, avx2, ssse3) #endif -filters_8tap_1d_fn3(put, 8, mmxext, sse2, sse2) -filters_8tap_1d_fn3(avg, 8, mmxext, sse2, sse2) -filters_8tap_1d_fn3(put, 8, ssse3, ssse3, ssse3) -filters_8tap_1d_fn3(avg, 8, ssse3, ssse3, ssse3) +filters_8tap_1d_fn3(put, 8, sse2, sse2) +filters_8tap_1d_fn3(avg, 8, sse2, sse2) +filters_8tap_1d_fn4(put, 8, ssse3, ssse3) +filters_8tap_1d_fn4(avg, 8, ssse3, ssse3) #if ARCH_X86_64 && HAVE_AVX2_EXTERNAL filters_8tap_1d_fn2(put, 64, 8, avx2, ssse3) filters_8tap_1d_fn2(put, 32, 8, avx2, ssse3) @@ -98,23 +101,24 @@ itxfm_func(iadst, idct, size, opt); \ itxfm_func(idct, iadst, size, opt); \ itxfm_func(iadst, iadst, size, opt) -itxfm_func(idct, idct, 4, mmxext); itxfm_func(idct, iadst, 4, sse2); itxfm_func(iadst, idct, 4, sse2); itxfm_func(iadst, iadst, 4, sse2); itxfm_funcs(4, ssse3); +itxfm_funcs(4, avx2); itxfm_funcs(8, sse2); itxfm_funcs(8, ssse3); -itxfm_funcs(8, avx); +itxfm_funcs(8, avx2); itxfm_funcs(16, sse2); itxfm_funcs(16, ssse3); -itxfm_funcs(16, avx); itxfm_func(idct, idct, 32, sse2); itxfm_func(idct, idct, 32, ssse3); -itxfm_func(idct, idct, 32, avx); itxfm_func(iwht, iwht, 4, mmx); +itxfm_func(iwht, iwht, 4, avx2); itxfm_funcs(16, avx2); +itxfm_funcs(16, avx512icl); itxfm_func(idct, idct, 32, avx2); +itxfm_func(idct, idct, 32, avx512icl); #undef itxfm_func #undef itxfm_funcs @@ -149,6 +153,8 @@ lpf_funcs(88, 16, avx); void ff_vp9_ipred_##type##_##size##x##size##_##opt(uint8_t *dst, ptrdiff_t stride, \ const uint8_t *l, const uint8_t *a) +ipred_func(4, hd, mmxext); +ipred_func(4, vl, mmxext); ipred_func(8, v, mmx); #define ipred_dc_funcs(size, opt) \ @@ -156,9 +162,6 @@ ipred_func(size, dc, opt); \ ipred_func(size, dc_left, opt); \ ipred_func(size, dc_top, opt) -ipred_dc_funcs(4, mmxext); -ipred_dc_funcs(8, mmxext); - #define ipred_dir_tm_funcs(size, opt) \ ipred_func(size, tm, opt); \ ipred_func(size, dl, opt); \ @@ -168,8 +171,6 @@ ipred_func(size, hu, opt); \ ipred_func(size, vl, opt); \ ipred_func(size, vr, opt) -ipred_dir_tm_funcs(4, mmxext); - ipred_func(16, v, sse); ipred_func(32, v, sse); @@ -200,22 +201,16 @@ ipred_dir_tm_h_funcs(8, avx); ipred_dir_tm_h_funcs(16, avx); ipred_dir_tm_h_funcs(32, avx); -ipred_func(32, v, avx); - -ipred_dc_funcs(32, avx2); -ipred_func(32, h, avx2); -ipred_func(32, tm, avx2); +ipred_all_funcs(32, avx2); +ipred_func(32, v, avx2); #undef ipred_func #undef ipred_dir_tm_h_funcs #undef ipred_dir_tm_funcs #undef ipred_dc_funcs -#endif /* HAVE_X86ASM */ - av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact) { -#if HAVE_X86ASM int cpu_flags; if (bpp == 10) { @@ -286,14 +281,10 @@ av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact) dsp->loop_filter_8[0][1] = ff_vp9_loop_filter_v_4_8_mmxext; dsp->loop_filter_8[1][0] = ff_vp9_loop_filter_h_8_8_mmxext; dsp->loop_filter_8[1][1] = ff_vp9_loop_filter_v_8_8_mmxext; - init_subpel2(4, 0, 4, put, 8, mmxext); - init_subpel2(4, 1, 4, avg, 8, mmxext); init_fpel_func(4, 1, 4, avg, _8, mmxext); init_fpel_func(3, 1, 8, avg, _8, mmxext); - dsp->itxfm_add[TX_4X4][DCT_DCT] = ff_vp9_idct_idct_4x4_add_mmxext; - init_dc_ipred(4, mmxext); - init_dc_ipred(8, mmxext); - init_dir_tm_ipred(4, mmxext); + dsp->intra_pred[TX_4X4][HOR_DOWN_PRED] = ff_vp9_ipred_hd_4x4_mmxext; + dsp->intra_pred[TX_4X4][VERT_LEFT_PRED] = ff_vp9_ipred_vl_4x4_mmxext; } if (EXTERNAL_SSE(cpu_flags)) { @@ -361,18 +352,6 @@ av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact) } if (EXTERNAL_AVX(cpu_flags)) { - dsp->itxfm_add[TX_8X8][DCT_DCT] = ff_vp9_idct_idct_8x8_add_avx; - dsp->itxfm_add[TX_8X8][ADST_DCT] = ff_vp9_idct_iadst_8x8_add_avx; - dsp->itxfm_add[TX_8X8][DCT_ADST] = ff_vp9_iadst_idct_8x8_add_avx; - dsp->itxfm_add[TX_8X8][ADST_ADST] = ff_vp9_iadst_iadst_8x8_add_avx; - dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_avx; - dsp->itxfm_add[TX_16X16][ADST_DCT] = ff_vp9_idct_iadst_16x16_add_avx; - dsp->itxfm_add[TX_16X16][DCT_ADST] = ff_vp9_iadst_idct_16x16_add_avx; - dsp->itxfm_add[TX_16X16][ADST_ADST] = ff_vp9_iadst_iadst_16x16_add_avx; - dsp->itxfm_add[TX_32X32][ADST_ADST] = - dsp->itxfm_add[TX_32X32][ADST_DCT] = - dsp->itxfm_add[TX_32X32][DCT_ADST] = - dsp->itxfm_add[TX_32X32][DCT_DCT] = ff_vp9_idct_idct_32x32_add_avx; init_lpf(avx); init_dir_tm_h_ipred(8, avx); init_dir_tm_h_ipred(16, avx); @@ -381,7 +360,6 @@ av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact) if (EXTERNAL_AVX_FAST(cpu_flags)) { init_fpel_func(1, 0, 32, put, , avx); init_fpel_func(0, 0, 64, put, , avx); - init_ipred(32, avx, v, VERT); } if (EXTERNAL_AVX2_FAST(cpu_flags)) { @@ -389,6 +367,18 @@ av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact) init_fpel_func(0, 1, 64, avg, _8, avx2); if (ARCH_X86_64) { #if ARCH_X86_64 && HAVE_AVX2_EXTERNAL + dsp->itxfm_add[4 /* lossless */][DCT_DCT] = + dsp->itxfm_add[4 /* lossless */][ADST_DCT] = + dsp->itxfm_add[4 /* lossless */][DCT_ADST] = + dsp->itxfm_add[4 /* lossless */][ADST_ADST] = ff_vp9_iwht_iwht_4x4_add_avx2; + dsp->itxfm_add[TX_4X4][DCT_DCT] = ff_vp9_idct_idct_4x4_add_avx2; + dsp->itxfm_add[TX_4X4][ADST_DCT] = ff_vp9_idct_iadst_4x4_add_avx2; + dsp->itxfm_add[TX_4X4][DCT_ADST] = ff_vp9_iadst_idct_4x4_add_avx2; + dsp->itxfm_add[TX_4X4][ADST_ADST] = ff_vp9_iadst_iadst_4x4_add_avx2; + dsp->itxfm_add[TX_8X8][DCT_DCT] = ff_vp9_idct_idct_8x8_add_avx2; + dsp->itxfm_add[TX_8X8][ADST_DCT] = ff_vp9_idct_iadst_8x8_add_avx2; + dsp->itxfm_add[TX_8X8][DCT_ADST] = ff_vp9_iadst_idct_8x8_add_avx2; + dsp->itxfm_add[TX_8X8][ADST_ADST] = ff_vp9_iadst_iadst_8x8_add_avx2; dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_avx2; dsp->itxfm_add[TX_16X16][ADST_DCT] = ff_vp9_idct_iadst_16x16_add_avx2; dsp->itxfm_add[TX_16X16][DCT_ADST] = ff_vp9_iadst_idct_16x16_add_avx2; @@ -401,15 +391,30 @@ av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact) init_subpel3_32_64(1, avg, 8, avx2); #endif } - init_dc_ipred(32, avx2); - init_ipred(32, avx2, h, HOR); - init_ipred(32, avx2, tm, TM_VP8); + init_all_ipred(32, avx2); + init_ipred(32, avx2, v, VERT); } +#if ARCH_X86_64 + if (EXTERNAL_AVX512ICL(cpu_flags)) { + dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_avx512icl; + dsp->itxfm_add[TX_16X16][ADST_DCT] = ff_vp9_idct_iadst_16x16_add_avx512icl; + dsp->itxfm_add[TX_16X16][DCT_ADST] = ff_vp9_iadst_idct_16x16_add_avx512icl; + dsp->itxfm_add[TX_16X16][ADST_ADST] = ff_vp9_iadst_iadst_16x16_add_avx512icl; + dsp->itxfm_add[TX_32X32][ADST_ADST] = + dsp->itxfm_add[TX_32X32][ADST_DCT] = + dsp->itxfm_add[TX_32X32][DCT_ADST] = + dsp->itxfm_add[TX_32X32][DCT_DCT] = ff_vp9_idct_idct_32x32_add_avx512icl; + init_subpel_asm(4, 4, 8, avx512icl); + init_subpel_asm(3, 8, 8, avx512icl); + init_subpel_asm(2, 16, 8, avx512icl); + init_subpel_asm(1, 32, 8, avx512icl); + init_subpel_asm(0, 64, 8, avx512icl); + } +#endif + #undef init_fpel #undef init_subpel1 #undef init_subpel2 #undef init_subpel3 - -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/x86/vp9dsp_init.h b/libavcodec/x86/vp9dsp_init.h index fc1e0557f..64747173c 100644 --- a/libavcodec/x86/vp9dsp_init.h +++ b/libavcodec/x86/vp9dsp_init.h @@ -107,12 +107,15 @@ filter_8tap_1d_fn(op, sz, FILTER_8TAP_SMOOTH, f_opt, smooth, dir, dvar, bpp, o filters_8tap_1d_fn(op, sz, h, mx, bpp, opt, f_opt) \ filters_8tap_1d_fn(op, sz, v, my, bpp, opt, f_opt) -#define filters_8tap_1d_fn3(op, bpp, opt4, opt8, f_opt) \ +#define filters_8tap_1d_fn3(op, bpp, opt8, f_opt) \ filters_8tap_1d_fn2(op, 64, bpp, opt8, f_opt) \ filters_8tap_1d_fn2(op, 32, bpp, opt8, f_opt) \ filters_8tap_1d_fn2(op, 16, bpp, opt8, f_opt) \ filters_8tap_1d_fn2(op, 8, bpp, opt8, f_opt) \ -filters_8tap_1d_fn2(op, 4, bpp, opt4, f_opt) + +#define filters_8tap_1d_fn4(op, bpp, opt, f_opt) \ +filters_8tap_1d_fn3(op, bpp, opt, f_opt) \ +filters_8tap_1d_fn2(op, 4, bpp, opt, f_opt) \ #define filter_8tap_2d_fn(op, sz, f, f_opt, fname, align, bpp, bytes, opt) \ static void op##_8tap_##fname##_##sz##hv_##bpp##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \ @@ -133,12 +136,15 @@ filter_8tap_2d_fn(op, sz, FILTER_8TAP_REGULAR, f_opt, regular, align, bpp, bytes filter_8tap_2d_fn(op, sz, FILTER_8TAP_SHARP, f_opt, sharp, align, bpp, bytes, opt) \ filter_8tap_2d_fn(op, sz, FILTER_8TAP_SMOOTH, f_opt, smooth, align, bpp, bytes, opt) -#define filters_8tap_2d_fn2(op, align, bpp, bytes, opt4, opt8, f_opt) \ +#define filters_8tap_2d_fn2(op, align, bpp, bytes, opt8, f_opt) \ filters_8tap_2d_fn(op, 64, align, bpp, bytes, opt8, f_opt) \ filters_8tap_2d_fn(op, 32, align, bpp, bytes, opt8, f_opt) \ filters_8tap_2d_fn(op, 16, align, bpp, bytes, opt8, f_opt) \ filters_8tap_2d_fn(op, 8, align, bpp, bytes, opt8, f_opt) \ -filters_8tap_2d_fn(op, 4, align, bpp, bytes, opt4, f_opt) + +#define filters_8tap_2d_fn3(op, align, bpp, bytes, opt, f_opt) \ +filters_8tap_2d_fn2(op, align, bpp, bytes, opt, f_opt) \ +filters_8tap_2d_fn(op, 4, align, bpp, bytes, opt, f_opt) #define init_fpel_func(idx1, idx2, sz, type, bpp, opt) \ dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][0][0] = \ @@ -172,6 +178,37 @@ filters_8tap_2d_fn(op, 4, align, bpp, bytes, opt4, f_opt) init_subpel3_8to64(idx, type, bpp, opt); \ init_subpel2(4, idx, 4, type, bpp, opt) +#define decl_subpel_asm_fn(type) \ + void ff_vp9_put_8tap_##type(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, int mx, int my); \ + void ff_vp9_avg_8tap_##type(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, int mx, int my) + +#define decl_subpel_asm_dir(type) \ + decl_subpel_asm_fn(regular_##type); \ + decl_subpel_asm_fn(smooth_##type); \ + decl_subpel_asm_fn(sharp_##type) + +#define decl_subpel_asm(sz, bpp, opt) \ + decl_subpel_asm_dir(sz##h_##bpp##_##opt); \ + decl_subpel_asm_dir(sz##v_##bpp##_##opt); \ + decl_subpel_asm_dir(sz##hv_##bpp##_##opt) + +#define init_subpel_asm_dir(idx1, idx2, idx3, type) \ + dsp->mc[idx1][FILTER_8TAP_REGULAR][0][idx2][idx3] = ff_vp9_put_8tap_regular_##type; \ + dsp->mc[idx1][FILTER_8TAP_SHARP ][0][idx2][idx3] = ff_vp9_put_8tap_sharp_##type; \ + dsp->mc[idx1][FILTER_8TAP_SMOOTH ][0][idx2][idx3] = ff_vp9_put_8tap_smooth_##type; \ + dsp->mc[idx1][FILTER_8TAP_REGULAR][1][idx2][idx3] = ff_vp9_avg_8tap_regular_##type; \ + dsp->mc[idx1][FILTER_8TAP_SHARP ][1][idx2][idx3] = ff_vp9_avg_8tap_sharp_##type; \ + dsp->mc[idx1][FILTER_8TAP_SMOOTH ][1][idx2][idx3] = ff_vp9_avg_8tap_smooth_##type + +#define init_subpel_asm(idx, sz, bpp, opt) \ + init_subpel_asm_dir(idx, 1, 0, sz##h_##bpp##_##opt); \ + init_subpel_asm_dir(idx, 0, 1, sz##v_##bpp##_##opt); \ + init_subpel_asm_dir(idx, 1, 1, sz##hv_##bpp##_##opt) + #define init_ipred_func(type, enum, sz, bpp, opt) \ dsp->intra_pred[TX_##sz##X##sz][enum##_PRED] = \ cat(ff_vp9_ipred_##type##_##sz##x##sz##_, bpp, _##opt) diff --git a/libavcodec/x86/vp9dsp_init_16bpp.c b/libavcodec/x86/vp9dsp_init_16bpp.c index e5afea151..2d2f01ba5 100644 --- a/libavcodec/x86/vp9dsp_init_16bpp.c +++ b/libavcodec/x86/vp9dsp_init_16bpp.c @@ -26,8 +26,6 @@ #include "libavcodec/vp9dsp.h" #include "libavcodec/x86/vp9dsp_init.h" -#if HAVE_X86ASM - decl_fpel_func(put, 8, , mmx); decl_fpel_func(avg, 8, _16, mmxext); decl_fpel_func(put, 16, , sse); @@ -68,11 +66,9 @@ decl_ipred_dir_funcs(vl); decl_ipred_dir_funcs(vr); decl_ipred_dir_funcs(hu); decl_ipred_dir_funcs(hd); -#endif /* HAVE_X86ASM */ av_cold void ff_vp9dsp_init_16bpp_x86(VP9DSPContext *dsp) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_MMX(cpu_flags)) { @@ -147,6 +143,4 @@ av_cold void ff_vp9dsp_init_16bpp_x86(VP9DSPContext *dsp) init_ipred_func(dr, DIAG_DOWN_RIGHT, 32, 16, avx2); #endif } - -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/x86/vp9dsp_init_16bpp_template.c b/libavcodec/x86/vp9dsp_init_16bpp_template.c index f93ea2468..969db94d3 100644 --- a/libavcodec/x86/vp9dsp_init_16bpp_template.c +++ b/libavcodec/x86/vp9dsp_init_16bpp_template.c @@ -26,8 +26,6 @@ #include "libavcodec/vp9dsp.h" #include "libavcodec/x86/vp9dsp_init.h" -#if HAVE_X86ASM - extern const int16_t ff_filters_16bpp[3][15][4][16]; decl_mc_funcs(4, sse2, int16_t, 16, BPC); @@ -42,8 +40,8 @@ mc_rep_funcs(32, 16, 32, avx2, int16_t, 16, BPC) mc_rep_funcs(64, 32, 64, avx2, int16_t, 16, BPC) #endif -filters_8tap_2d_fn2(put, 16, BPC, 2, sse2, sse2, 16bpp) -filters_8tap_2d_fn2(avg, 16, BPC, 2, sse2, sse2, 16bpp) +filters_8tap_2d_fn3(put, 16, BPC, 2, sse2, 16bpp) +filters_8tap_2d_fn3(avg, 16, BPC, 2, sse2, 16bpp) #if HAVE_AVX2_EXTERNAL filters_8tap_2d_fn(put, 64, 32, BPC, 2, avx2, 16bpp) filters_8tap_2d_fn(avg, 64, 32, BPC, 2, avx2, 16bpp) @@ -53,8 +51,8 @@ filters_8tap_2d_fn(put, 16, 32, BPC, 2, avx2, 16bpp) filters_8tap_2d_fn(avg, 16, 32, BPC, 2, avx2, 16bpp) #endif -filters_8tap_1d_fn3(put, BPC, sse2, sse2, 16bpp) -filters_8tap_1d_fn3(avg, BPC, sse2, sse2, 16bpp) +filters_8tap_1d_fn4(put, BPC, sse2, 16bpp) +filters_8tap_1d_fn4(avg, BPC, sse2, 16bpp) #if HAVE_AVX2_EXTERNAL filters_8tap_1d_fn2(put, 64, BPC, avx2, 16bpp) filters_8tap_1d_fn2(avg, 64, BPC, avx2, 16bpp) @@ -125,8 +123,9 @@ decl_ipred_fns(tm, BPC, mmxext, sse2); decl_itxfm_func(iwht, iwht, 4, BPC, mmxext); #if BPC == 10 -decl_itxfm_func(idct, idct, 4, BPC, mmxext); decl_itxfm_funcs(4, BPC, ssse3); +decl_itxfm_funcs(16, BPC, avx512icl); +decl_itxfm_func(idct, idct, 32, BPC, avx512icl); #else decl_itxfm_func(idct, idct, 4, BPC, sse2); #endif @@ -136,11 +135,9 @@ decl_itxfm_func(iadst, iadst, 4, BPC, sse2); decl_itxfm_funcs(8, BPC, sse2); decl_itxfm_funcs(16, BPC, sse2); decl_itxfm_func(idct, idct, 32, BPC, sse2); -#endif /* HAVE_X86ASM */ av_cold void INIT_FUNC(VP9DSPContext *dsp, int bitexact) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); #define init_lpf_8_func(idx1, idx2, dir, wd, bpp, opt) \ @@ -186,9 +183,6 @@ av_cold void INIT_FUNC(VP9DSPContext *dsp, int bitexact) init_ipred_func(tm, TM_VP8, 4, BPC, mmxext); if (!bitexact) { init_itx_func_one(4 /* lossless */, iwht, iwht, 4, BPC, mmxext); -#if BPC == 10 - init_itx_func(TX_4X4, DCT_DCT, idct, idct, 4, 10, mmxext); -#endif } } @@ -233,7 +227,12 @@ av_cold void INIT_FUNC(VP9DSPContext *dsp, int bitexact) #endif } -#endif /* HAVE_X86ASM */ +#if ARCH_X86_64 && BPC == 10 + if (EXTERNAL_AVX512ICL(cpu_flags)) { + init_itx_funcs(TX_16X16, 16, BPC, avx512icl); + init_itx_func_one(TX_32X32, idct, idct, 32, BPC, avx512icl); + } +#endif ff_vp9dsp_init_16bpp_x86(dsp); } diff --git a/libavcodec/x86/vp9intrapred.asm b/libavcodec/x86/vp9intrapred.asm index 31f7d449f..22390ca83 100644 --- a/libavcodec/x86/vp9intrapred.asm +++ b/libavcodec/x86/vp9intrapred.asm @@ -2,6 +2,7 @@ ;* VP9 Intra prediction SIMD optimizations ;* ;* Copyright (c) 2013 Ronald S. Bultje +;* Copyright (c) 2025 Two Orioles, LLC ;* ;* Parts based on: ;* H.264 intra prediction asm optimizations @@ -92,21 +93,14 @@ SECTION .text ; dc_NxN(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, const uint8_t *a) -%macro DC_4to8_FUNCS 0 +INIT_MMX ssse3 cglobal vp9_ipred_dc_4x4, 4, 4, 0, dst, stride, l, a movd m0, [lq] punpckldq m0, [aq] pxor m1, m1 psadbw m0, m1 -%if cpuflag(ssse3) pmulhrsw m0, [pw_4096] pshufb m0, m1 -%else - paddw m0, [pw_4] - psraw m0, 3 - punpcklbw m0, m0 - pshufw m0, m0, q0000 -%endif movd [dstq+strideq*0], m0 movd [dstq+strideq*1], m0 lea dstq, [dstq+strideq*2] @@ -123,15 +117,8 @@ cglobal vp9_ipred_dc_8x8, 4, 4, 0, dst, stride, l, a psadbw m0, m2 psadbw m1, m2 paddw m0, m1 -%if cpuflag(ssse3) pmulhrsw m0, [pw_2048] pshufb m0, m2 -%else - paddw m0, [pw_8] - psraw m0, 4 - punpcklbw m0, m0 - pshufw m0, m0, q0000 -%endif movq [dstq+strideq*0], m0 movq [dstq+strideq*1], m0 movq [dstq+strideq*2], m0 @@ -142,12 +129,7 @@ cglobal vp9_ipred_dc_8x8, 4, 4, 0, dst, stride, l, a movq [dstq+strideq*2], m0 movq [dstq+stride3q ], m0 RET -%endmacro -INIT_MMX mmxext -DC_4to8_FUNCS -INIT_MMX ssse3 -DC_4to8_FUNCS %macro DC_16to32_FUNCS 0 cglobal vp9_ipred_dc_16x16, 4, 4, 3, dst, stride, l, a @@ -230,40 +212,6 @@ DC_16to32_FUNCS INIT_XMM ssse3 DC_16to32_FUNCS -%if HAVE_AVX2_EXTERNAL -INIT_YMM avx2 -cglobal vp9_ipred_dc_32x32, 4, 4, 3, dst, stride, l, a - mova m0, [lq] - mova m1, [aq] - DEFINE_ARGS dst, stride, stride3, cnt - lea stride3q, [strideq*3] - pxor m2, m2 - psadbw m0, m2 - psadbw m1, m2 - paddw m0, m1 - vextracti128 xm1, m0, 1 - paddw xm0, xm1 - movhlps xm1, xm0 - paddw xm0, xm1 - pmulhrsw xm0, [pw_512] - vpbroadcastb m0, xm0 - mov cntd, 4 -.loop: - mova [dstq+strideq*0], m0 - mova [dstq+strideq*1], m0 - mova [dstq+strideq*2], m0 - mova [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - mova [dstq+strideq*0], m0 - mova [dstq+strideq*1], m0 - mova [dstq+strideq*2], m0 - mova [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - dec cntd - jg .loop - RET -%endif - ; dc_top/left_NxN(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, const uint8_t *a) %macro DC_1D_4to8_FUNCS 2 ; dir (top or left), arg (a or l) @@ -271,15 +219,8 @@ cglobal vp9_ipred_dc_%1_4x4, 4, 4, 0, dst, stride, l, a movd m0, [%2q] pxor m1, m1 psadbw m0, m1 -%if cpuflag(ssse3) pmulhrsw m0, [pw_8192] pshufb m0, m1 -%else - paddw m0, [pw_2] - psraw m0, 2 - punpcklbw m0, m0 - pshufw m0, m0, q0000 -%endif movd [dstq+strideq*0], m0 movd [dstq+strideq*1], m0 lea dstq, [dstq+strideq*2] @@ -293,15 +234,8 @@ cglobal vp9_ipred_dc_%1_8x8, 4, 4, 0, dst, stride, l, a lea stride3q, [strideq*3] pxor m1, m1 psadbw m0, m1 -%if cpuflag(ssse3) pmulhrsw m0, [pw_4096] pshufb m0, m1 -%else - paddw m0, [pw_4] - psraw m0, 3 - punpcklbw m0, m0 - pshufw m0, m0, q0000 -%endif movq [dstq+strideq*0], m0 movq [dstq+strideq*1], m0 movq [dstq+strideq*2], m0 @@ -314,9 +248,6 @@ cglobal vp9_ipred_dc_%1_8x8, 4, 4, 0, dst, stride, l, a RET %endmacro -INIT_MMX mmxext -DC_1D_4to8_FUNCS top, a -DC_1D_4to8_FUNCS left, l INIT_MMX ssse3 DC_1D_4to8_FUNCS top, a DC_1D_4to8_FUNCS left, l @@ -395,44 +326,6 @@ INIT_XMM ssse3 DC_1D_16to32_FUNCS top, a DC_1D_16to32_FUNCS left, l -%macro DC_1D_AVX2_FUNCS 2 ; dir (top or left), arg (a or l) -%if HAVE_AVX2_EXTERNAL -cglobal vp9_ipred_dc_%1_32x32, 4, 4, 3, dst, stride, l, a - mova m0, [%2q] - DEFINE_ARGS dst, stride, stride3, cnt - lea stride3q, [strideq*3] - pxor m2, m2 - psadbw m0, m2 - vextracti128 xm1, m0, 1 - paddw xm0, xm1 - movhlps xm1, xm0 - paddw xm0, xm1 - pmulhrsw xm0, [pw_1024] - vpbroadcastb m0, xm0 - mov cntd, 4 -.loop: - mova [dstq+strideq*0], m0 - mova [dstq+strideq*1], m0 - mova [dstq+strideq*2], m0 - mova [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - mova [dstq+strideq*0], m0 - mova [dstq+strideq*1], m0 - mova [dstq+strideq*2], m0 - mova [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - dec cntd - jg .loop - RET -%endif -%endmacro - -INIT_YMM avx2 -DC_1D_AVX2_FUNCS top, a -DC_1D_AVX2_FUNCS left, l - -; v - INIT_MMX mmx cglobal vp9_ipred_v_8x8, 4, 4, 0, dst, stride, l, a movq m0, [aq] @@ -486,29 +379,6 @@ cglobal vp9_ipred_v_32x32, 4, 4, 2, dst, stride, l, a jg .loop RET -INIT_YMM avx -cglobal vp9_ipred_v_32x32, 4, 4, 1, dst, stride, l, a - mova m0, [aq] - DEFINE_ARGS dst, stride, stride3, cnt - lea stride3q, [strideq*3] - mov cntd, 4 -.loop: - mova [dstq+strideq*0], m0 - mova [dstq+strideq*1], m0 - mova [dstq+strideq*2], m0 - mova [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - mova [dstq+strideq*0], m0 - mova [dstq+strideq*1], m0 - mova [dstq+strideq*2], m0 - mova [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - dec cntd - jg .loop - RET - -; h - %macro H_XMM_FUNCS 2 %if notcpuflag(avx) cglobal vp9_ipred_h_4x4, 3, 4, 1, dst, stride, l, stride3 @@ -642,61 +512,22 @@ H_XMM_FUNCS 4, 8 INIT_XMM avx H_XMM_FUNCS 4, 8 -%if HAVE_AVX2_EXTERNAL -INIT_YMM avx2 -cglobal vp9_ipred_h_32x32, 3, 5, 8, dst, stride, l, stride3, cnt - mova m5, [pb_1] - mova m6, [pb_2] - mova m7, [pb_3] - pxor m4, m4 - lea stride3q, [strideq*3] - mov cntq, 7 -.loop: - movd xm3, [lq+cntq*4] - vinserti128 m3, m3, xm3, 1 - pshufb m0, m3, m7 - pshufb m1, m3, m6 - mova [dstq+strideq*0], m0 - mova [dstq+strideq*1], m1 - pshufb m2, m3, m5 - pshufb m3, m4 - mova [dstq+strideq*2], m2 - mova [dstq+stride3q ], m3 - lea dstq, [dstq+strideq*4] - dec cntq - jge .loop - RET -%endif - -; tm - -%macro TM_MMX_FUNCS 0 +INIT_MMX ssse3 cglobal vp9_ipred_tm_4x4, 4, 4, 0, dst, stride, l, a pxor m1, m1 movd m0, [aq] pinsrw m2, [aq-1], 0 punpcklbw m0, m1 DEFINE_ARGS dst, stride, l, cnt -%if cpuflag(ssse3) mova m3, [pw_m256] mova m1, [pw_m255] pshufb m2, m3 -%else - punpcklbw m2, m1 - pshufw m2, m2, q0000 -%endif psubw m0, m2 mov cntq, 1 .loop: pinsrw m2, [lq+cntq*2], 0 -%if cpuflag(ssse3) pshufb m4, m2, m1 pshufb m2, m3 -%else - punpcklbw m2, m1 - pshufw m4, m2, q1111 - pshufw m2, m2, q0000 -%endif paddw m4, m0 paddw m2, m0 packuswb m4, m4 @@ -707,12 +538,6 @@ cglobal vp9_ipred_tm_4x4, 4, 4, 0, dst, stride, l, a dec cntq jge .loop RET -%endmacro - -INIT_MMX mmxext -TM_MMX_FUNCS -INIT_MMX ssse3 -TM_MMX_FUNCS %macro TM_XMM_FUNCS 0 cglobal vp9_ipred_tm_8x8, 4, 4, 5, dst, stride, l, a @@ -898,65 +723,19 @@ TM_XMM_FUNCS INIT_XMM avx TM_XMM_FUNCS -%if HAVE_AVX2_EXTERNAL -INIT_YMM avx2 -cglobal vp9_ipred_tm_32x32, 4, 4, 8, dst, stride, l, a - pxor m3, m3 - pinsrw xm2, [aq-1], 0 - vinserti128 m2, m2, xm2, 1 - mova m0, [aq] - DEFINE_ARGS dst, stride, l, cnt - mova m4, [pw_m256] - mova m5, [pw_m255] - pshufb m2, m4 - punpckhbw m1, m0, m3 - punpcklbw m0, m3 - psubw m1, m2 - psubw m0, m2 - mov cntq, 15 -.loop: - pinsrw xm7, [lq+cntq*2], 0 - vinserti128 m7, m7, xm7, 1 - pshufb m3, m7, m5 - pshufb m7, m4 - paddw m2, m3, m0 - paddw m3, m1 - paddw m6, m7, m0 - paddw m7, m1 - packuswb m2, m3 - packuswb m6, m7 - mova [dstq+strideq*0], m2 - mova [dstq+strideq*1], m6 - lea dstq, [dstq+strideq*2] - dec cntq - jge .loop - RET -%endif - -; dl - -%macro LOWPASS 4 ; left [dst], center, right, tmp +%macro LOWPASS 4-5 [pb_1] ; left [dst], center, right, tmp, pb_1 pxor m%4, m%1, m%3 - pand m%4, [pb_1] + pand m%4, %5 pavgb m%1, m%3 psubusb m%1, m%4 pavgb m%1, m%2 %endmacro -%macro DL_MMX_FUNCS 0 +INIT_MMX ssse3 cglobal vp9_ipred_dl_4x4, 4, 4, 0, dst, stride, l, a movq m1, [aq] -%if cpuflag(ssse3) pshufb m0, m1, [pb_0to5_2x7] pshufb m2, m1, [pb_2to6_3x7] -%else - punpckhbw m3, m1, m1 ; 44556677 - pand m0, m1, [pb_6xm1_2x0] ; 012345__ - pand m3, [pb_6x0_2xm1] ; ______77 - psrlq m2, m1, 16 ; 234567__ - por m0, m3 ; 01234577 - por m2, m3 ; 23456777 -%endif psrlq m1, 8 LOWPASS 0, 1, 2, 3 @@ -969,12 +748,6 @@ cglobal vp9_ipred_dl_4x4, 4, 4, 0, dst, stride, l, a movd [dstq+strideq*0], m0 movd [dstq+strideq*2], m1 RET -%endmacro - -INIT_MMX mmxext -DL_MMX_FUNCS -INIT_MMX ssse3 -DL_MMX_FUNCS %macro DL_XMM_FUNCS 0 cglobal vp9_ipred_dl_8x8, 4, 4, 4, dst, stride, stride5, a @@ -1123,14 +896,14 @@ DL_XMM_FUNCS ; dr -%macro DR_MMX_FUNCS 0 +INIT_MMX ssse3 cglobal vp9_ipred_dr_4x4, 4, 4, 0, dst, stride, l, a movd m0, [lq] punpckldq m0, [aq-1] movd m1, [aq+3] DEFINE_ARGS dst, stride, stride3 lea stride3q, [strideq*3] - PALIGNR m1, m0, 1, m3 + palignr m1, m0, 1 psrlq m2, m1, 8 LOWPASS 0, 1, 2, 3 @@ -1142,12 +915,6 @@ cglobal vp9_ipred_dr_4x4, 4, 4, 0, dst, stride, l, a psrlq m0, 8 movd [dstq+strideq*0], m0 RET -%endmacro - -INIT_MMX mmxext -DR_MMX_FUNCS -INIT_MMX ssse3 -DR_MMX_FUNCS %macro DR_XMM_FUNCS 0 cglobal vp9_ipred_dr_8x8, 4, 4, 4, dst, stride, l, a @@ -1425,7 +1192,7 @@ VL_XMM_FUNCS ; vr -%macro VR_MMX_FUNCS 0 +INIT_MMX ssse3 cglobal vp9_ipred_vr_4x4, 4, 4, 0, dst, stride, l, a movq m1, [aq-1] punpckldq m2, [lq] @@ -1433,7 +1200,7 @@ cglobal vp9_ipred_vr_4x4, 4, 4, 0, dst, stride, l, a DEFINE_ARGS dst, stride, stride3 lea stride3q, [strideq*3] pavgb m0, m1 - PALIGNR m1, m2, 5, m3 + palignr m1, m2, 5 psrlq m2, m1, 8 psllq m3, m1, 8 LOWPASS 2, 1, 3, 4 @@ -1443,7 +1210,6 @@ cglobal vp9_ipred_vr_4x4, 4, 4, 0, dst, stride, l, a ; IABC | m0 contains ABCDxxxx ; JEFG | m2 contains xJIEFGHx -%if cpuflag(ssse3) punpckldq m0, m2 pshufb m2, [pb_13456_3xm1] movd [dstq+strideq*0], m0 @@ -1452,24 +1218,7 @@ cglobal vp9_ipred_vr_4x4, 4, 4, 0, dst, stride, l, a psrlq m2, 8 movd [dstq+strideq*2], m0 movd [dstq+strideq*1], m2 -%else - psllq m1, m2, 40 - psrlq m2, 24 - movd [dstq+strideq*0], m0 - movd [dstq+strideq*1], m2 - PALIGNR m0, m1, 7, m3 - psllq m1, 8 - PALIGNR m2, m1, 7, m3 - movd [dstq+strideq*2], m0 - movd [dstq+stride3q ], m2 -%endif RET -%endmacro - -INIT_MMX mmxext -VR_MMX_FUNCS -INIT_MMX ssse3 -VR_MMX_FUNCS %macro VR_XMM_FUNCS 1 ; n_xmm_regs for 16x16 cglobal vp9_ipred_vr_8x8, 4, 4, 5, dst, stride, l, a @@ -1847,16 +1596,10 @@ HD_XMM_FUNCS INIT_XMM avx HD_XMM_FUNCS -%macro HU_MMX_FUNCS 0 +INIT_MMX ssse3 cglobal vp9_ipred_hu_4x4, 3, 3, 0, dst, stride, l movd m0, [lq] -%if cpuflag(ssse3) pshufb m0, [pb_0to2_5x3] -%else - punpcklbw m1, m0, m0 ; 00112233 - pshufw m1, m1, q3333 ; 33333333 - punpckldq m0, m1 ; 01233333 -%endif psrlq m1, m0, 8 psrlq m2, m1, 8 LOWPASS 2, 1, 0, 3 @@ -1864,7 +1607,7 @@ cglobal vp9_ipred_hu_4x4, 3, 3, 0, dst, stride, l DEFINE_ARGS dst, stride, stride3 lea stride3q, [strideq*3] SBUTTERFLY bw, 1, 2, 0 - PALIGNR m2, m1, 2, m0 + palignr m2, m1, 2 movd [dstq+strideq*0], m1 movd [dstq+strideq*1], m2 punpckhdq m1, m1 @@ -1872,12 +1615,6 @@ cglobal vp9_ipred_hu_4x4, 3, 3, 0, dst, stride, l movd [dstq+strideq*2], m1 movd [dstq+stride3q ], m2 RET -%endmacro - -INIT_MMX mmxext -HU_MMX_FUNCS -INIT_MMX ssse3 -HU_MMX_FUNCS %macro HU_XMM_FUNCS 1 ; n_xmm_regs in hu_32x32 cglobal vp9_ipred_hu_8x8, 3, 4, 4, dst, stride, l @@ -2041,4 +1778,306 @@ HU_XMM_FUNCS 7 INIT_XMM avx HU_XMM_FUNCS 7 +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +cglobal vp9_ipred_dc_32x32, 4, 4, 3, dst, stride, l, a + pxor m1, m1 + psadbw m0, m1, [lq] + psadbw m1, [aq] + movd xm2, [pw_512] + paddw m0, m1 + vextracti128 xm1, m0, 1 +.main: + paddw xm0, xm1 + punpckhqdq xm1, xm0, xm0 + paddw xm0, xm1 + pmulhrsw xm0, xm2 + vpbroadcastb m0, xm0 +.main2: + lea r2, [strideq*3] + mov r3d, 8 +.loop: + mova [dstq+strideq*0], m0 + mova [dstq+strideq*1], m0 + mova [dstq+strideq*2], m0 + mova [dstq+r2 ], m0 + lea dstq, [dstq+strideq*4] + dec r3d + jg .loop + RET + +cglobal vp9_ipred_dc_top_32x32, 0, 4, 3, dst, stride, l, a + mov lq, amp +%if ARCH_X86_32 + jmp mangle(private_prefix %+ _vp9_ipred_dc_left_32x32 %+ SUFFIX).main +%endif + +%assign function_align 1 +cglobal vp9_ipred_dc_left_32x32, 0, 4, 3, dst, stride, l, a + movifnidn lq, lmp +.main: + movifnidn dstq, dstmp + movifnidn strideq, stridemp + pxor xm1, xm1 + psadbw xm0, xm1, [lq] + psadbw xm1, [lq+16] + movd xm2, [pw_1024] + jmp mangle(private_prefix %+ _vp9_ipred_dc_32x32 %+ SUFFIX).main + +cglobal vp9_ipred_v_32x32, 2, 4, 3, dst, stride, l, a + movifnidn aq, amp + mova m0, [aq] + jmp mangle(private_prefix %+ _vp9_ipred_dc_32x32 %+ SUFFIX).main2 + +%assign function_align 16 +cglobal vp9_ipred_h_32x32, 3, 5, 6, dst, stride, l + vpbroadcastd m2, [pb_3] + mov r3d, 7 + vpbroadcastd m3, [pb_2] + pxor m5, m5 + vpbroadcastd m4, [pb_1] + lea r4, [strideq*3] +.loop: + vpbroadcastd m1, [lq+r3*4] + pshufb m0, m1, m2 + mova [dstq+strideq*0], m0 + pshufb m0, m1, m3 + mova [dstq+strideq*1], m0 + pshufb m0, m1, m4 + mova [dstq+strideq*2], m0 + pshufb m1, m5 + mova [dstq+r4 ], m1 + lea dstq, [dstq+strideq*4] + dec r3d + jge .loop + RET + +cglobal vp9_ipred_tm_32x32, 4, 4, 8, dst, stride, l, a + vpbroadcastd m0, [aq-1] + mova m7, [aq] + pxor m1, m1 + vpbroadcastd m4, [pw_m255] + mov r3d, 15 + vpbroadcastd m5, [pw_m256] + pshufb m0, m5 + punpcklbw m6, m7, m1 + punpckhbw m7, m1 + psubw m6, m0 + psubw m7, m0 +.loop: + vpbroadcastd m3, [lq+r3*2] + pshufb m2, m3, m4 + pshufb m3, m5 + paddw m0, m2, m6 + paddw m2, m7 + paddw m1, m3, m6 + paddw m3, m7 + packuswb m0, m2 + packuswb m1, m3 + mova [dstq+strideq*0], m0 + mova [dstq+strideq*1], m1 + lea dstq, [dstq+strideq*2] + dec r3d + jge .loop + RET + +cglobal vp9_ipred_dl_32x32, 2, 5, 6, dst, stride, l, a + movifnidn aq, amp + vpbroadcastb m2, [aq+31] + vinserti128 m3, m2, [aq+16], 0 + mova m0, [aq+ 0] + vpbroadcastd m5, [pb_1] + palignr m4, m3, m0, 2 + lea r3, [strideq*2] + palignr m3, m0, 1 + LOWPASS 0, 3, 4, 1, m5 + lea r4, [strideq*3] + vperm2i128 m1, m0, m2, 0x31 + mov r2d, 8 +.loop: + shufpd m3, m0, m1, 0x05 + mova [dstq+r3*0], m0 + punpckhqdq m4, m1, m2 + mova [dstq+r3*4], m3 + palignr m0, m1, m0, 1 + mova [dstq+r3*8], m1 + palignr m1, m2, m1, 1 + mova [dstq+r4*8], m4 + add dstq, strideq + dec r2d + jg .loop + RET + +cglobal vp9_ipred_dr_32x32, 4, 5, 7, dst, stride, l, a + mova m3, [lq+ 0] + movu m1, [aq- 1] + mova m0, [aq+ 0] + vpbroadcastd m6, [pb_1] + vperm2i128 m2, m3, m1, 0x21 + lea r3, [strideq*2] + palignr m4, m1, m2, 15 + LOWPASS 0, 1, 4, 5, m6 + pslldq xm4, xm3, 1 + palignr m2, m3, 1 + vinserti128 m4, [lq+15], 1 + LOWPASS 2, 3, 4, 5, m6 + lea r4, [strideq*3] + vperm2i128 m1, m2, m0, 0x21 + mov r2d, 8 +.loop: + shufpd m3, m1, m0, 0x05 + mova [dstq+r3*0], m0 + shufpd m4, m2, m1, 0x05 + mova [dstq+r3*4], m3 + palignr m0, m1, 15 + mova [dstq+r3*8], m1 + palignr m1, m2, 15 + mova [dstq+r4*8], m4 + add dstq, strideq + pslldq m2, 1 + dec r2d + jg .loop + RET + +cglobal vp9_ipred_hd_32x32, 4, 6, 7, dst, stride, l, a + movu m1, [aq-1] + mova m0, [lq] + vpbroadcastd m6, [pb_1] + vperm2i128 m4, m0, m1, 0x21 + palignr m3, m4, m0, 1 + palignr m4, m0, 2 + LOWPASS 4, 3, 0, 2, m6 + pavgb m3, m0 + movu xm0, [aq+15] + punpcklbw m2, m3, m4 + punpckhbw m3, m4 + palignr m4, m0, m1, 2 + palignr m0, m1, 1 + LOWPASS 4, 0, 1, 5, m6 + lea r2, [strideq*8] + vinserti128 m0, m2, xm3, 1 + lea r3, [dstq+r2*1] + vpblendd m1, m2, m3, 0x0f + lea r4, [dstq+r2*2] + vperm2i128 m2, m3, 0x31 + lea r5, [r3 +r2*2] + vperm2i128 m3, m4, 0x21 +.loop: + sub r2, strideq + mova [r5 +r2], m0 + palignr m0, m1, m0, 2 + mova [r4 +r2], m1 + palignr m1, m2, m1, 2 + mova [r3 +r2], m2 + palignr m2, m3, m2, 2 + mova [dstq+r2], m3 + palignr m3, m4, m3, 2 + psrldq m4, 2 + jg .loop + RET + +cglobal vp9_ipred_hu_32x32, 3, 5, 6, dst, stride, l, a + mova m0, [lq] + vpbroadcastb xm3, [lq+31] + vpbroadcastd m1, [pb_1] + vbroadcasti128 m4, [pb_2toE_3xF] + vperm2i128 m3, m0, 0x03 + palignr m5, m3, m0, 2 + palignr m3, m0, 1 + LOWPASS 5, 3, 0, 2, m1 + vpbroadcastd m1, [pb_15] + pavgb m3, m0 + punpcklbw m2, m3, m5 + punpckhbw m3, m5 + vinserti128 m0, m2, xm3, 1 + pshufb m5, m1 + vperm2i128 m1, m2, m3, 0x12 + lea r3, [strideq*2] + vperm2i128 m2, m3, 0x31 + lea r4, [strideq*3] + vperm2i128 m3, m5, 0x31 + mov r2d, 8 +.loop: + mova [dstq+r3*0], m0 + palignr m0, m1, m0, 2 + mova [dstq+r3*4], m1 + palignr m1, m2, m1, 2 + mova [dstq+r3*8], m2 + palignr m2, m3, m2, 2 + mova [dstq+r4*8], m3 + pshufb m3, m4 + add dstq, strideq + dec r2d + jg .loop + RET + +cglobal vp9_ipred_vl_32x32, 2, 5, 6, dst, stride, l, a + movifnidn aq, amp + vpbroadcastb m4, [aq+31] + vinserti128 m0, m4, [aq+16], 0 + mova m1, [aq+ 0] + vpbroadcastd m5, [pb_1] + palignr m2, m0, m1, 2 + palignr m0, m1, 1 + LOWPASS 2, 0, 1, 3, m5 + pavgb m0, m1 + lea r3, [strideq*2] + vperm2i128 m1, m0, m4, 0x31 + lea r4, [strideq+r3*8] + vperm2i128 m3, m2, m4, 0x31 + mov r2d, 8 +.loop: + shufpd m4, m0, m1, 0x05 + mova [dstq+strideq*0], m0 + shufpd m5, m2, m3, 0x05 + mova [dstq+strideq*1], m2 + palignr m0, m1, m0, 1 + mova [dstq+r3*8 ], m4 + psrldq m1, 1 + mova [dstq+r4 ], m5 + palignr m2, m3, m2, 1 + add dstq, r3 + psrldq m3, 1 + dec r2d + jg .loop + RET + +cglobal vp9_ipred_vr_32x32, 4, 5, 7, dst, stride, l, a + mova m4, [lq+ 0] + movu m0, [aq- 1] + vpbroadcastd m6, [pb_1] + vperm2i128 m2, m4, m0, 0x21 + pslldq xm5, xm4, 1 + palignr m3, m2, m4, 1 + vinserti128 m5, [lq+15], 1 + LOWPASS 3, 4, 5, 1, m6 + mova m1, [aq+ 0] + vbroadcasti128 m4, [pb_02468ACE_13579BDF] + palignr m2, m0, m2, 15 + LOWPASS 2, 0, 1, 5, m6 + pshufb m3, m4 + lea r3, [strideq*2] + vpermq m3, m3, q2031 + pavgb m0, m1 + vinserti128 m1, m3, xm0, 1 + lea r4, [strideq+r3*8] + vperm2i128 m3, m2, 0x21 + mov r2d, 8 +.loop: + shufpd m4, m1, m0, 0x05 + mova [dstq+strideq*0], m0 + shufpd m5, m3, m2, 0x05 + mova [dstq+strideq*1], m2 + palignr m0, m1, 15 + mova [dstq+r3*8 ], m4 + pslldq m1, 1 + mova [dstq+r4 ], m5 + palignr m2, m3, 15 + add dstq, r3 + pslldq m3, 1 + dec r2d + jg .loop + RET +%endif + ; FIXME 127, 128, 129 ? diff --git a/libavcodec/x86/vp9itxfm.asm b/libavcodec/x86/vp9itxfm.asm index 2f290f2f8..bd5966646 100644 --- a/libavcodec/x86/vp9itxfm.asm +++ b/libavcodec/x86/vp9itxfm.asm @@ -24,36 +24,36 @@ %include "libavutil/x86/x86util.asm" %include "vp9itxfm_template.asm" -SECTION_RODATA 32 +SECTION_RODATA 16 %macro VP9_IDCT_COEFFS 2-3 0 const pw_m%1_%2 -times 8 dw -%1, %2 +times 4 dw -%1, %2 const pw_%2_%1 -times 8 dw %2, %1 +times 4 dw %2, %1 %if %3 == 1 const pw_m%2_m%1 -times 8 dw -%2, -%1 +times 4 dw -%2, -%1 %if %1 != %2 const pw_m%2_%1 -times 8 dw -%2, %1 +times 4 dw -%2, %1 const pw_%1_%2 -times 8 dw %1, %2 +times 4 dw %1, %2 %endif %endif %if %1 < 11585 -pw_m%1x2: times 16 dw -%1*2 +pw_m%1x2: times 8 dw -%1*2 %elif %1 > 11585 -pw_%1x2: times 16 dw %1*2 +pw_%1x2: times 8 dw %1*2 %else const pw_%1x2 -times 16 dw %1*2 +times 8 dw %1*2 %endif %if %2 != %1 -pw_%2x2: times 16 dw %2*2 +pw_%2x2: times 8 dw %2*2 %endif %endmacro @@ -127,24 +127,13 @@ SECTION .text %endmacro %macro VP9_STORE_2X 5-6 dstq ; reg1, reg2, tmp1, tmp2, zero, dst -%if mmsize == 32 - pmovzxbw m%3, [%6] - pmovzxbw m%4, [%6+strideq] -%else movh m%3, [%6] movh m%4, [%6+strideq] punpcklbw m%3, m%5 punpcklbw m%4, m%5 -%endif paddw m%3, m%1 paddw m%4, m%2 -%if mmsize == 32 - packuswb m%3, m%4 - ; Intel... - vpermq m%3, m%3, q3120 - mova [%6], xm%3 - vextracti128 [%6+strideq], m%3, 1 -%elif mmsize == 16 +%if mmsize == 16 packuswb m%3, m%4 movh [%6], m%3 movhps [%6+strideq], m%3 @@ -234,49 +223,28 @@ cglobal vp9_iwht_iwht_4x4_add, 3, 3, 0, dst, stride, block, eob VP9_STORE_2X 2, 3, 6, 7, 4 %endmacro -%macro IDCT_4x4_FN 1 -INIT_MMX %1 +INIT_MMX ssse3 cglobal vp9_idct_idct_4x4_add, 4, 4, 0, dst, stride, block, eob -%if cpuflag(ssse3) cmp eobd, 4 ; 2x2 or smaller jg .idctfull cmp eobd, 1 ; faster path for when only DC is set jne .idct2x2 -%else - cmp eobd, 1 - jg .idctfull -%endif -%if cpuflag(ssse3) movd m0, [blockq] mova m5, [pw_11585x2] pmulhrsw m0, m5 pmulhrsw m0, m5 -%else - DEFINE_ARGS dst, stride, block, coef - movsx coefd, word [blockq] - imul coefd, 11585 - add coefd, 8192 - sar coefd, 14 - imul coefd, 11585 - add coefd, (8 << 14) + 8192 - sar coefd, 14 + 4 - movd m0, coefd -%endif pshufw m0, m0, 0 pxor m4, m4 movh [blockq], m4 -%if cpuflag(ssse3) pmulhrsw m0, [pw_2048] ; (x*2048 + (1<<14))>>15 <=> (x+8)>>4 -%endif VP9_STORE_2X 0, 0, 6, 7, 4 lea dstq, [dstq+2*strideq] VP9_STORE_2X 0, 0, 6, 7, 4 RET -%if cpuflag(ssse3) ; faster path for when only top left 2x2 block is set .idct2x2: movd m0, [blockq+0] @@ -296,16 +264,13 @@ cglobal vp9_idct_idct_4x4_add, 4, 4, 0, dst, stride, block, eob movh [blockq+ 8], m4 VP9_IDCT4_WRITEOUT RET -%endif .idctfull: ; generic full 4x4 idct/idct mova m0, [blockq+ 0] mova m1, [blockq+ 8] mova m2, [blockq+16] mova m3, [blockq+24] -%if cpuflag(ssse3) mova m6, [pw_11585x2] -%endif mova m7, [pd_8192] ; rounding VP9_IDCT4_1D TRANSPOSE4x4W 0, 1, 2, 3, 4 @@ -317,10 +282,6 @@ cglobal vp9_idct_idct_4x4_add, 4, 4, 0, dst, stride, block, eob mova [blockq+24], m4 VP9_IDCT4_WRITEOUT RET -%endmacro - -IDCT_4x4_FN mmxext -IDCT_4x4_FN ssse3 ;------------------------------------------------------------------------------------------- ; void vp9_iadst_iadst_4x4_add_(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob); @@ -474,7 +435,6 @@ IADST4_FN iadst, IADST4, iadst, IADST4, ssse3 pmulhrsw m7, W_11585x2_REG ; m7=t5 pmulhrsw m5, W_11585x2_REG ; m5=t6 SWAP 5, 1 - ; merged VP9_IDCT8_1D_FINALIZE to make register-sharing w/ avx easier psubw m6, m0, m3 ; m6=t0-t7 paddw m3, m0 ; m3=t0+t7 psubw m2, m0, m1 ; m2=t1-t6 @@ -722,7 +682,6 @@ cglobal vp9_idct_idct_8x8_add, 4, 4, %2, dst, stride, block, eob VP9_IDCT_IDCT_8x8_ADD_XMM sse2, 12 VP9_IDCT_IDCT_8x8_ADD_XMM ssse3, 13 -VP9_IDCT_IDCT_8x8_ADD_XMM avx, 13 ;--------------------------------------------------------------------------------------------- ; void vp9_iadst_iadst_8x8_add_(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob); @@ -896,11 +855,8 @@ IADST8_FN idct, IDCT8, iadst, IADST8, sse2, 15 IADST8_FN iadst, IADST8, idct, IDCT8, sse2, 15 IADST8_FN iadst, IADST8, iadst, IADST8, sse2, 15 IADST8_FN idct, IDCT8, iadst, IADST8, ssse3, 16 -IADST8_FN idct, IDCT8, iadst, IADST8, avx, 16 IADST8_FN iadst, IADST8, idct, IDCT8, ssse3, 16 -IADST8_FN iadst, IADST8, idct, IDCT8, avx, 16 IADST8_FN iadst, IADST8, iadst, IADST8, ssse3, 16 -IADST8_FN iadst, IADST8, iadst, IADST8, avx, 16 ;--------------------------------------------------------------------------------------------- ; void vp9_idct_idct_16x16_add_(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob); @@ -1438,7 +1394,6 @@ cglobal vp9_idct_idct_16x16_add, 4, 6, 16, 512, dst, stride, block, eob VP9_IDCT_IDCT_16x16_ADD_XMM sse2 VP9_IDCT_IDCT_16x16_ADD_XMM ssse3 -VP9_IDCT_IDCT_16x16_ADD_XMM avx %macro VP9_IDCT16_YMM_1D 0 VP9_UNPACK_MULSUB_2W_4X 1, 15, 16305, 1606, [pd_8192], 0, 4 ; t8, t15 @@ -1534,83 +1489,6 @@ VP9_IDCT_IDCT_16x16_ADD_XMM avx vextracti128 [dstq+stride3q], m%4, 1 %endmacro -%if ARCH_X86_64 && HAVE_AVX2_EXTERNAL -INIT_YMM avx2 -cglobal vp9_idct_idct_16x16_add, 4, 4, 16, dst, stride, block, eob - cmp eobd, 1 ; faster path for when only DC is set - jg .idctfull - - ; dc-only - mova m1, [pw_11585x2] - vpbroadcastw m0, [blockq] - pmulhrsw m0, m1 - pmulhrsw m0, m1 - pxor m5, m5 - pmulhrsw m0, [pw_512] - movd [blockq], xm5 - - DEFINE_ARGS dst, stride, stride3, cnt - mov cntd, 4 - lea stride3q, [strideq*3] -.loop_dc: - VP9_STORE_YMM_DC_4X 0, 1, 2, 3, 4, 5 - lea dstq, [dstq+4*strideq] - dec cntd - jg .loop_dc - RET - - DEFINE_ARGS dst, stride, block, eob -.idctfull: - mova m1, [blockq+ 32] - mova m2, [blockq+ 64] - mova m3, [blockq+ 96] - mova m5, [blockq+160] - mova m6, [blockq+192] - mova m7, [blockq+224] - mova m8, [blockq+256] - mova m9, [blockq+288] - mova m10, [blockq+320] - mova m11, [blockq+352] - mova m12, [blockq+384] - mova m13, [blockq+416] - mova m14, [blockq+448] - mova m15, [blockq+480] - - VP9_IDCT16_YMM_1D - TRANSPOSE16x16W 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \ - [blockq+192], [blockq+128], 1 - mova [blockq+ 0], m0 - VP9_IDCT16_YMM_1D - - mova [blockq+224], m7 - - ; store - VP9_IDCT8_WRITEx2 0, 1, 6, 7, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 2, 3, 6, 7, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 4, 5, 6, 7, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - mova m6, [blockq+192] - mova m7, [blockq+224] - VP9_IDCT8_WRITEx2 6, 7, 1, 2, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 8, 9, 1, 2, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 10, 11, 1, 2, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 12, 13, 1, 2, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 14, 15, 1, 2, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - - ; at the end of the loop, m0 should still be zero - ; use that to zero out block coefficients - pxor m0, m0 - ZERO_BLOCK blockq, 32, 16, m0 - RET -%endif - ;--------------------------------------------------------------------------------------------- ; void vp9_iadst_iadst_16x16_add_(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob); ;--------------------------------------------------------------------------------------------- @@ -1982,9 +1860,6 @@ IADST16_FN iadst, IADST16, iadst, IADST16, sse2 IADST16_FN idct, IDCT16, iadst, IADST16, ssse3 IADST16_FN iadst, IADST16, idct, IDCT16, ssse3 IADST16_FN iadst, IADST16, iadst, IADST16, ssse3 -IADST16_FN idct, IDCT16, iadst, IADST16, avx -IADST16_FN iadst, IADST16, idct, IDCT16, avx -IADST16_FN iadst, IADST16, iadst, IADST16, avx ; in: data in m[0-15] except m0/m4, which are in [blockq+0] and [blockq+128] ; out: m[0-15] except m6, which is in [blockq+192] @@ -2094,65 +1969,6 @@ IADST16_FN iadst, IADST16, iadst, IADST16, avx SWAP 5, 9, 15 %endmacro -%if ARCH_X86_64 && HAVE_AVX2_EXTERNAL -%macro IADST16_YMM_FN 4 -INIT_YMM avx2 -cglobal vp9_%1_%3_16x16_add, 4, 4, 16, dst, stride, block, eob - mova m1, [blockq+ 32] - mova m2, [blockq+ 64] - mova m3, [blockq+ 96] - mova m5, [blockq+160] - mova m6, [blockq+192] - mova m7, [blockq+224] - mova m8, [blockq+256] - mova m9, [blockq+288] - mova m10, [blockq+320] - mova m11, [blockq+352] - mova m12, [blockq+384] - mova m13, [blockq+416] - mova m14, [blockq+448] - mova m15, [blockq+480] - - VP9_%2_YMM_1D - TRANSPOSE16x16W 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \ - [blockq+192], [blockq+128], 1 - mova [blockq+ 0], m0 - VP9_%4_YMM_1D - - mova [blockq+224], m7 - - ; store - VP9_IDCT8_WRITEx2 0, 1, 6, 7, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 2, 3, 6, 7, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 4, 5, 6, 7, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - mova m6, [blockq+192] - mova m7, [blockq+224] - VP9_IDCT8_WRITEx2 6, 7, 1, 2, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 8, 9, 1, 2, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 10, 11, 1, 2, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 12, 13, 1, 2, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - VP9_IDCT8_WRITEx2 14, 15, 1, 2, unused, [pw_512], 6 - lea dstq, [dstq+2*strideq] - - ; at the end of the loop, m0 should still be zero - ; use that to zero out block coefficients - pxor m0, m0 - ZERO_BLOCK blockq, 32, 16, m0 - RET -%endmacro - -IADST16_YMM_FN idct, IDCT16, iadst, IADST16 -IADST16_YMM_FN iadst, IADST16, idct, IDCT16 -IADST16_YMM_FN iadst, IADST16, iadst, IADST16 -%endif - ;--------------------------------------------------------------------------------------------- ; void vp9_idct_idct_32x32_add_(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob); ;--------------------------------------------------------------------------------------------- @@ -2468,115 +2284,6 @@ IADST16_YMM_FN iadst, IADST16, iadst, IADST16 SUMSUB_BA w, 5, 13, 8 mova m10, [tmpq+28*%%str] ; t7 SUMSUB_BA w, 4, 10, 8 -%if cpuflag(avx2) - ; the "shitty" about this idct is that the final pass does the outermost - ; interleave sumsubs (t0/31, t1/30, etc) but the tN for the 16x16 need - ; to be sequential, which means I need to load/store half of the sumsub - ; intermediates back to/from memory to get a 16x16 transpose going... - ; This would be easier if we had more (e.g. 32) YMM regs here. - mova [tmpq+ 7*%%str], m9 - mova [tmpq+11*%%str], m12 - mova [tmpq+15*%%str], m11 - mova [tmpq+19*%%str], m2 - mova [tmpq+23*%%str], m3 - mova [tmpq+27*%%str], m13 - mova [tmpq+31*%%str], m10 - mova [tmpq+12*%%str], m5 - - mova m13, [tmpq+30*%%str] ; t8 - mova m12, [tmpq+26*%%str] ; t9 - mova m11, [tmpq+22*%%str] ; t10 - mova m10, [tmpq+18*%%str] ; t11 - mova m9, [tmpq+17*%%str] ; t20 - mova m8, [tmpq+ 1*%%str] ; t21 - mova m3, [tmpq+25*%%str] ; t22 - mova m2, [tmpq+ 5*%%str] ; t23 - - SUMSUB_BA w, 9, 10, 5 - SUMSUB_BA w, 8, 11, 5 - SUMSUB_BA w, 3, 12, 5 - SUMSUB_BA w, 2, 13, 5 - mova [tmpq+ 1*%%str], m10 - mova [tmpq+ 5*%%str], m11 - mova [tmpq+17*%%str], m12 - mova [tmpq+25*%%str], m13 - - mova m13, [tmpq+14*%%str] ; t12 - mova m12, [tmpq+10*%%str] ; t13 - mova m11, [tmpq+ 9*%%str] ; t18 - mova m10, [tmpq+13*%%str] ; t19 - - SUMSUB_BA w, 11, 12, 5 - SUMSUB_BA w, 10, 13, 5 - mova [tmpq+ 9*%%str], m13 - mova [tmpq+13*%%str], m12 - mova [tmpq+10*%%str], m10 - mova [tmpq+14*%%str], m11 - - mova m13, [tmpq+ 6*%%str] ; t14 - mova m12, [tmpq+ 2*%%str] ; t15 - mova m11, [tmpq+21*%%str] ; t16 - mova m10, [tmpq+29*%%str] ; t17 - SUMSUB_BA w, 11, 12, 5 - SUMSUB_BA w, 10, 13, 5 - mova [tmpq+21*%%str], m12 - mova [tmpq+29*%%str], m13 - mova m12, [tmpq+10*%%str] - mova m13, [tmpq+14*%%str] - - TRANSPOSE16x16W 6, 0, 15, 14, 1, 7, 5, 4, \ - 2, 3, 8, 9, 12, 13, 10, 11, \ - [tmpq+12*%%str], [tmpq+ 8*%%str], 1 - mova [tmpq+ 0*%%str], m6 - mova [tmpq+ 2*%%str], m0 - mova [tmpq+ 4*%%str], m15 - mova [tmpq+ 6*%%str], m14 - mova [tmpq+10*%%str], m7 - mova [tmpq+12*%%str], m5 - mova [tmpq+14*%%str], m4 - mova [tmpq+16*%%str], m2 - mova [tmpq+18*%%str], m3 - mova [tmpq+20*%%str], m8 - mova [tmpq+22*%%str], m9 - mova [tmpq+24*%%str], m12 - mova [tmpq+26*%%str], m13 - mova [tmpq+28*%%str], m10 - mova [tmpq+30*%%str], m11 - - mova m0, [tmpq+21*%%str] - mova m1, [tmpq+29*%%str] - mova m2, [tmpq+13*%%str] - mova m3, [tmpq+ 9*%%str] - mova m4, [tmpq+ 1*%%str] - mova m5, [tmpq+ 5*%%str] - mova m7, [tmpq+25*%%str] - mova m8, [tmpq+31*%%str] - mova m9, [tmpq+27*%%str] - mova m10, [tmpq+23*%%str] - mova m11, [tmpq+19*%%str] - mova m12, [tmpq+15*%%str] - mova m13, [tmpq+11*%%str] - mova m14, [tmpq+ 7*%%str] - mova m15, [tmpq+ 3*%%str] - TRANSPOSE16x16W 0, 1, 2, 3, 4, 5, 6, 7, \ - 8, 9, 10, 11, 12, 13, 14, 15, \ - [tmpq+17*%%str], [tmpq+ 9*%%str], 1 - mova [tmpq+ 1*%%str], m0 - mova [tmpq+ 3*%%str], m1 - mova [tmpq+ 5*%%str], m2 - mova [tmpq+ 7*%%str], m3 - mova [tmpq+11*%%str], m5 - mova [tmpq+13*%%str], m6 - mova [tmpq+15*%%str], m7 - mova [tmpq+17*%%str], m8 - mova [tmpq+19*%%str], m9 - mova [tmpq+21*%%str], m10 - mova [tmpq+23*%%str], m11 - mova [tmpq+25*%%str], m12 - mova [tmpq+27*%%str], m13 - mova [tmpq+29*%%str], m14 - mova [tmpq+31*%%str], m15 -%else ; !avx2 TRANSPOSE8x8W 6, 0, 15, 14, 1, 7, 5, 4, 8 mova [tmpq+ 0*%%str], m6 mova [tmpq+ 4*%%str], m0 @@ -2645,7 +2352,6 @@ IADST16_YMM_FN iadst, IADST16, iadst, IADST16 mova [tmpq+22*%%str], m13 mova [tmpq+26*%%str], m14 mova [tmpq+30*%%str], m15 -%endif ; avx2 %else mova m2, [tmpq+24*%%str] ; t6 mova m3, [tmpq+28*%%str] ; t7 @@ -3093,107 +2799,3 @@ cglobal vp9_idct_idct_32x32_add, 0, 6 + ARCH_X86_64 * 3, 16, 2048, dst, stride, VP9_IDCT_IDCT_32x32_ADD_XMM sse2 VP9_IDCT_IDCT_32x32_ADD_XMM ssse3 -VP9_IDCT_IDCT_32x32_ADD_XMM avx - -; this is almost identical to VP9_STORE_2X, but it does two rows -; for slightly improved interleaving, and it omits vpermq since the -; input is DC so all values are identical -%macro VP9_STORE_YMM_DC_2X2 6 ; reg, tmp1, tmp2, tmp3, tmp4, zero - mova m%2, [dstq] - mova m%4, [dstq+strideq] - punpckhbw m%3, m%2, m%6 - punpcklbw m%2, m%6 - punpckhbw m%5, m%4, m%6 - punpcklbw m%4, m%6 - paddw m%3, m%1 - paddw m%2, m%1 - paddw m%5, m%1 - paddw m%4, m%1 - packuswb m%2, m%3 - packuswb m%4, m%5 - mova [dstq+strideq*0], m%2 - mova [dstq+strideq*1], m%4 -%endmacro - -%if ARCH_X86_64 && HAVE_AVX2_EXTERNAL -INIT_YMM avx2 -cglobal vp9_idct_idct_32x32_add, 4, 9, 16, 2048, dst, stride, block, eob - cmp eobd, 135 - jg .idctfull - cmp eobd, 1 - jg .idct16x16 - - ; dc-only case - mova m1, [pw_11585x2] - vpbroadcastw m0, [blockq] - pmulhrsw m0, m1 - pmulhrsw m0, m1 - pxor m5, m5 - pmulhrsw m0, [pw_512] - movd [blockq], xm5 - - DEFINE_ARGS dst, stride, cnt - mov cntd, 16 -.loop_dc: - VP9_STORE_YMM_DC_2X2 0, 1, 2, 3, 4, 5 - lea dstq, [dstq+2*strideq] - dec cntd - jg .loop_dc - RET - - DEFINE_ARGS dst_bak, stride, block, cnt, dst, stride30, dst_end, stride2, tmp -.idct16x16: - mov tmpq, rsp - VP9_IDCT32_1D blockq, 1, 16 - - mov stride30q, strideq ; stride - lea stride2q, [strideq*2] ; stride*2 - shl stride30q, 5 ; stride*32 - mov cntd, 2 - sub stride30q, stride2q ; stride*30 -.loop2_16x16: - mov dstq, dst_bakq - lea dst_endq, [dstq+stride30q] - VP9_IDCT32_1D tmpq, 2, 16 - add dst_bakq, 16 - add tmpq, 32 - dec cntd - jg .loop2_16x16 - - ; at the end of the loop, m1 should still be zero - ; use that to zero out block coefficients - ZERO_BLOCK blockq, 64, 16, m1 - RET - -.idctfull: - mov cntd, 2 - mov tmpq, rsp -.loop1_full: - VP9_IDCT32_1D blockq, 1 - add blockq, 32 - add tmpq, 1024 - dec cntd - jg .loop1_full - - sub blockq, 64 - - mov stride30q, strideq ; stride - lea stride2q, [strideq*2] ; stride*2 - shl stride30q, 5 ; stride*32 - mov cntd, 2 - mov tmpq, rsp - sub stride30q, stride2q ; stride*30 -.loop2_full: - mov dstq, dst_bakq - lea dst_endq, [dstq+stride30q] - VP9_IDCT32_1D tmpq, 2 - add dst_bakq, 16 - add tmpq, 32 - dec cntd - jg .loop2_full - - ; at the end of the loop, m1 should still be zero - ; use that to zero out block coefficients - ZERO_BLOCK blockq, 64, 32, m1 - RET -%endif diff --git a/libavcodec/x86/vp9itxfm_16bpp.asm b/libavcodec/x86/vp9itxfm_16bpp.asm index ebe622228..161c73f5a 100644 --- a/libavcodec/x86/vp9itxfm_16bpp.asm +++ b/libavcodec/x86/vp9itxfm_16bpp.asm @@ -243,29 +243,21 @@ IWHT4_FN 12, 4095 ; 4x4 coefficients are 5+depth+sign bits, so for 10bpp, everything still fits ; in 15+1 words without additional effort, since the coefficients are 15bpp. -%macro IDCT4_10_FN 0 +INIT_MMX ssse3 cglobal vp9_idct_idct_4x4_add_10, 4, 4, 8, dst, stride, block, eob cmp eobd, 1 jg .idctfull ; dc-only pxor m4, m4 -%if cpuflag(ssse3) movd m0, [blockq] movd [blockq], m4 mova m5, [pw_11585x2] pmulhrsw m0, m5 pmulhrsw m0, m5 -%else - DEFINE_ARGS dst, stride, block, coef - DC_ONLY 4, m4 - movd m0, coefd -%endif pshufw m0, m0, 0 mova m5, [pw_1023] -%if cpuflag(ssse3) pmulhrsw m0, [pw_2048] ; (x*2048 + (1<<14))>>15 <=> (x+8)>>4 -%endif VP9_STORE_2X 0, 0, 6, 7, 4, 5 lea dstq, [dstq+2*strideq] VP9_STORE_2X 0, 0, 6, 7, 4, 5 @@ -281,9 +273,7 @@ cglobal vp9_idct_idct_4x4_add_10, 4, 4, 8, dst, stride, block, eob packssdw m2, [blockq+2*16+8] packssdw m3, [blockq+3*16+8] -%if cpuflag(ssse3) mova m6, [pw_11585x2] -%endif mova m7, [pd_8192] ; rounding VP9_IDCT4_1D TRANSPOSE4x4W 0, 1, 2, 3, 4 @@ -293,12 +283,6 @@ cglobal vp9_idct_idct_4x4_add_10, 4, 4, 8, dst, stride, block, eob ZERO_BLOCK blockq, 16, 4, m4 VP9_IDCT4_WRITEOUT RET -%endmacro - -INIT_MMX mmxext -IDCT4_10_FN -INIT_MMX ssse3 -IDCT4_10_FN %macro IADST4_FN 4 cglobal vp9_%1_%3_4x4_add_10, 3, 3, 0, dst, stride, block, eob diff --git a/libavcodec/x86/vp9itxfm_16bpp_avx512.asm b/libavcodec/x86/vp9itxfm_16bpp_avx512.asm new file mode 100644 index 000000000..192423346 --- /dev/null +++ b/libavcodec/x86/vp9itxfm_16bpp_avx512.asm @@ -0,0 +1,1165 @@ +;****************************************************************************** +;* VP9 IDCT SIMD optimizations +;* +;* Copyright (C) 2025 Two Orioles, LLC +;* +;* 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/x86/x86util.asm" + +%if ARCH_X86_64 && HAVE_AVX512ICL_EXTERNAL + +SECTION_RODATA 64 + +; The following set of constants are ordered to form the +; qword shuffle mask { 0, 2, 4, 6, 1, 3, 5, 7 } +%define deintq_perm pd_5520 +pd_5520: dd 5520 +pd_9760: dd 9760 +pd_10394: dd 10394 +pd_15426: dd 15426 +pd_804: dd 804 +pd_2404: dd 2404 +pd_6270: dd 6270 +pd_9102: dd 9102 +pd_11585: dd 11585 +pd_12665: dd 12665 +pd_7723: dd 7723 +pd_14811: dd 14811 +pd_7005: dd 7005 +pd_14053: dd 14053 +pd_8423: dd 8423 +pd_13623: dd 13623 + +pixel_clip: times 2 dw 0x7c00 +pixel_clip6: dd 2031648 ; 32 + (pixel_clip << 6) +pd_532480: dd 532480 ; 8192 + (32 << 14) +pd_8192: dd 8192 + +pd_1606: dd 1606 +pd_3196: dd 3196 +pd_3981: dd 3981 +pd_4756: dd 4756 +pd_11003: dd 11003 +pd_12140: dd 12140 +pd_13160: dd 13160 +pd_14449: dd 14449 +pd_15137: dd 15137 +pd_15679: dd 15679 +pd_15893: dd 15893 +pd_16069: dd 16069 +pd_16207: dd 16207 +pd_16305: dd 16305 +pd_16364: dd 16364 + +SECTION .text + +%define o_base (deintq_perm+128) +%define o(x) (r5 - o_base + (x)) +%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX) + +; dst1 = (src1 * coef1 - src2 * coef2 + rnd) >> 12 +; dst2 = (src1 * coef2 + src2 * coef1 + rnd) >> 12 +; skip round/shift if rnd is not a number +%macro ITX_MULSUB_2D 8-9 0 ; dst/src[1-2], tmp[1-3], rnd, coef[1-2], inv_dst2 +%if %8 < 32 + pmulld m%4, m%1, m%8 + pmulld m%3, m%2, m%8 +%else + vpbroadcastd m%3, [o(pd_%8)] + pmulld m%4, m%1, m%3 + pmulld m%3, m%2 +%endif +%if %7 < 32 + pmulld m%1, m%7 + pmulld m%2, m%7 +%else + vpbroadcastd m%5, [o(pd_%7)] + pmulld m%1, m%5 + pmulld m%2, m%5 +%endif +%if %9 + psubd m%4, m%6, m%4 + psubd m%2, m%4, m%2 +%else +%ifnum %6 + paddd m%4, m%6 +%endif + paddd m%2, m%4 +%endif +%ifnum %6 + paddd m%1, m%6 +%endif + psubd m%1, m%3 +%ifnum %6 + psrad m%2, 14 + psrad m%1, 14 +%endif +%endmacro + +%macro WRAP_YMM 1+ + INIT_YMM cpuname + %1 + INIT_ZMM cpuname +%endmacro + +%macro TRANSPOSE_4D 5 ; in[1-4], tmp + punpckhdq m%5, m%3, m%4 ; c2 d2 c3 d3 + punpckldq m%3, m%4 ; c0 d0 c1 d1 + punpckhdq m%4, m%1, m%2 ; a2 b2 a3 b3 + punpckldq m%1, m%2 ; a0 b0 a1 b1 + punpckhqdq m%2, m%1, m%3 ; a1 b1 c1 d1 + punpcklqdq m%1, m%3 ; a0 b0 c0 d0 + punpcklqdq m%3, m%4, m%5 ; a2 b2 c2 d2 + punpckhqdq m%4, m%5 ; a3 b3 c3 d3 +%endmacro + +%macro TRANSPOSE_4DQ 5 ; in[1-4], tmp + vshufi32x4 m%5, m%3, m%4, q3232 ; c2 c3 d2 d3 + vinserti32x8 m%3, ym%4, 1 ; c0 c1 d0 d1 + vshufi32x4 m%4, m%1, m%2, q3232 ; a2 a3 b2 b3 + vinserti32x8 m%1, ym%2, 1 ; a0 a1 b0 b1 + vshufi32x4 m%2, m%1, m%3, q3131 ; a1 b1 c1 d1 + vshufi32x4 m%1, m%3, q2020 ; a0 b0 c0 d0 + vshufi32x4 m%3, m%4, m%5, q2020 ; a2 b2 c2 d2 + vshufi32x4 m%4, m%5, q3131 ; a3 b3 c3 d3 +%endmacro + +%macro INV_TXFM_FN 3-4 0 ; type1, type2, size, eob_offset +cglobal vp9_i%1_i%2_%3_add_10, 4, 5, 0, dst, stride, c, eob, tx2 + %define %%p1 m(vp9_i%1_%3_internal_10) + lea r5, [o_base] + ; Jump to the 1st txfm function if we're not taking the fast path, which + ; in turn performs an indirect jump to the 2nd txfm function. + lea tx2q, [m(vp9_i%2_%3_internal_10).pass2] +%ifidn %1_%2, dct_dct + dec eobd + jnz %%p1 +%else +%if %4 + add eobd, %4 +%endif + ; jump to the 1st txfm function unless it's located directly after this + times ((%%end - %%p1) >> 31) & 1 jmp %%p1 +ALIGN function_align +%%end: +%endif +%endmacro + +%macro INV_TXFM_16X16_FN 2-3 0 ; type1, type2, eob_offset + INV_TXFM_FN %1, %2, 16x16, %3 +%ifidn %1_%2, dct_dct + imul r6d, [cq], 11585 + vpbroadcastd ym3, [o(pixel_clip)] + mov [cq], r3d + add r6d, 8192 + sar r6d, 14 + imul r6d, 11585 + or r3d, 8 + add r6d, 532480 + sar r6d, 20 + vpbroadcastw ym2, r6d + paddsw ym2, ym3 +.dconly_loop: + paddsw ym0, ym2, [dstq+strideq*0] + paddsw ym1, ym2, [dstq+strideq*1] + psubusw ym0, ym3 + psubusw ym1, ym3 + mova [dstq+strideq*0], ym0 + mova [dstq+strideq*1], ym1 + lea dstq, [dstq+strideq*2] + dec r3d + jg .dconly_loop + RET +%endif +%endmacro + +%macro IDCT16_PART1 0 +%if mmsize == 64 +.main_part1_fast: +%endif + pmulld m15, m1, [o(pd_16305)] {bcstd} ; t15a + pmulld m1, [o(pd_1606)] {bcstd} ; t8a + pmulld m9, m7, [o(pd_10394)] {bcstd} ; t9a + pmulld m7, [o(pd_12665)] {bcstd} ; t14a + pmulld m11, m5, [o(pd_14449)] {bcstd} ; t13a + pmulld m5, [o(pd_7723)] {bcstd} ; t10a + pmulld m13, m3, [o(pd_4756)] {bcstd} ; t11a + pmulld m3, [o(pd_15679)] {bcstd} ; t12a + pmulld m10, m6, [o(pd_9102)] {bcstd} ; t5a + pmulld m6, [o(pd_13623)] {bcstd} ; t6a + pmulld m14, m2, [o(pd_16069)] {bcstd} ; t7a + pmulld m2, [o(pd_3196)] {bcstd} ; t4a + pmulld m12, m4, [o(pd_15137)] {bcstd} ; t3 + pmulld m4, [o(pd_6270)] {bcstd} ; t2 + pmulld m0, m21 + REPX {psubd x, m20, x}, m9, m13, m10 + paddd m0, m20 + mova m18, m0 +%if mmsize == 64 ; for the ymm variant we only ever use the fast path + jmp %%main_part1b +.main_part1: + ITX_MULSUB_2D 1, 15, 16, 17, 18, _, 1606, 16305 ; t8a, t15a + ITX_MULSUB_2D 9, 7, 16, 17, 18, _, 12665, 10394 ; t9a, t14a + ITX_MULSUB_2D 5, 11, 16, 17, 18, _, 7723, 14449 ; t10a, t13a + ITX_MULSUB_2D 13, 3, 16, 17, 18, _, 15679, 4756 ; t11a, t12a + ITX_MULSUB_2D 10, 6, 16, 17, 18, _, 13623, 9102 ; t5a, t6a + ITX_MULSUB_2D 2, 14, 16, 17, 18, _, 3196, 16069 ; t4a, t7a + ITX_MULSUB_2D 4, 12, 16, 17, 18, _, 6270, 15137 ; t2, t3 + pmulld m0, m21 + pmulld m8, m21 + REPX {paddd x, m20}, m0, m9, m13, m10 + psubd m18, m0, m8 ; t1 + paddd m0, m8 ; t0 +%%main_part1b: +%endif + vpbroadcastd m19, [o(pd_15137)] + vpbroadcastd m16, [o(pd_6270)] + REPX {paddd x, m20}, m15, m7, m1, m11, m3, m5 + REPX {psrad x, 14 }, m15, m7, m1, m9, m11, m3, m5, m13 + paddd m17, m15, m7 ; t15 + psubd m15, m7 ; t14 + psubd m7, m3, m11 ; t13 + paddd m3, m11 ; t12 + psubd m11, m13, m5 ; t10 + paddd m5, m13 ; t11 + psubd m13, m1, m9 ; t9 + paddd m1, m9 ; t8 + ITX_MULSUB_2D 15, 13, 8, 9, _, 20, 16, 19 ; t9a, t14a + ITX_MULSUB_2D 7, 11, 8, 9, _, 20, 16, 19, 2 ; t13a, t10a + paddd m16, m1, m5 ; t8a + psubd m1, m5 ; t11a + paddd m8, m15, m11 ; t9 + psubd m15, m11 ; t10 + psubd m11, m17, m3 ; t12a + paddd m17, m3 ; t15a + psubd m9, m13, m7 ; t13 + paddd m13, m7 ; t14 + REPX {pmulld x, m21}, m11, m9, m1, m15 + REPX {paddd x, m20}, m2, m6, m14 + REPX {psrad x, 14 }, m10, m2, m6, m14 + psubd m3, m2, m10 ; t5a + paddd m10, m2 ; t4 + paddd m11, m20 + psubd m5, m11, m1 ; t11 + paddd m11, m1 ; t12 + psubd m1, m14, m6 ; t6a + paddd m14, m6 ; t7 + pmulld m1, m21 + pmulld m3, m21 + paddd m4, m20 + paddd m12, m20 + REPX {psrad x, 14 }, m4, m12, m0, m18 + paddd m9, m20 + paddd m2, m9, m15 ; t13a + psubd m9, m15 ; t10a + paddd m1, m20 + psubd m6, m1, m3 ; t5 + paddd m1, m3 ; t6 + REPX {psrad x, 14}, m6, m1, m11, m5, m2, m9 +%endmacro + +%macro IDCT16_PART2 0 + psubd m3, m0, m12 ; t3 + paddd m0, m12 ; t0 + psubd m12, m18, m4 ; t2 + paddd m18, m4 ; t1 + psubd m4, m3, m10 ; t4 + paddd m3, m10 ; t3 + psubd m10, m12, m6 ; t5 + paddd m12, m6 ; t2 + psubd m6, m18, m1 ; t6 + paddd m1, m18 ; t1 + psubd m7, m0, m14 ; t7 + paddd m0, m14 ; t0 + psubd m15, m0, m17 ; out15 + paddd m0, m17 ; out0 + psubd m14, m1, m13 ; out14 + paddd m1, m13 ; out1 + psubd m13, m12, m2 ; out13 + paddd m2, m12 ; out2 + psubd m12, m3, m11 ; out12 + paddd m3, m11 ; out3 + psubd m11, m4, m5 ; out11 + paddd m4, m5 ; out4 + paddd m5, m10, m9 ; out5 + psubd m10, m9 ; out10 + psubd m9, m6, m8 ; out9 + paddd m6, m8 ; out6 + psubd m8, m7, m16 ; out8 + paddd m7, m16 ; out7 +%endmacro + +INIT_ZMM avx512icl +INV_TXFM_16X16_FN dct, dct +INV_TXFM_16X16_FN dct, adst, 39-23-1 + +cglobal vp9_idct_16x16_internal_10, 0, 7, 22, dst, stride, c, eob, tx2 + mova m0, [cq+64* 0] + mova m1, [cq+64* 1] + mova m2, [cq+64* 2] + mova m3, [cq+64* 3] + mova m4, [cq+64* 4] + mova m5, [cq+64* 5] + mova m6, [cq+64* 6] + mova m7, [cq+64* 7] + vpbroadcastd m20, [o(pd_8192)] + vpbroadcastd m21, [o(pd_11585)] + sub eobd, 38 + jl .pass1_fast + mova m8, [cq+64* 8] + mova m9, [cq+64* 9] + mova m10, [cq+64*10] + mova m11, [cq+64*11] + mova m12, [cq+64*12] + mova m13, [cq+64*13] + mova m14, [cq+64*14] + mova m15, [cq+64*15] + call .main_part1 + call .main_part2 +.pass1_end: + TRANSPOSE_4DQ 0, 4, 8, 12, 16 + TRANSPOSE_4DQ 1, 5, 9, 13, 16 + TRANSPOSE_4DQ 2, 6, 10, 14, 16 + TRANSPOSE_4DQ 3, 7, 11, 15, 16 + TRANSPOSE_4D 8, 9, 10, 11, 16 + TRANSPOSE_4D 12, 13, 14, 15, 16 + mov r6d, 64*12 + jmp .pass1_transpose_end +.pass1_fast: + WRAP_YMM IDCT16_PART1 + WRAP_YMM IDCT16_PART2 +.pass1_fast_end: + vinserti32x8 m0, ym4, 1 + vinserti32x8 m8, ym12, 1 + vinserti32x8 m1, ym5, 1 + vinserti32x8 m9, ym13, 1 + vinserti32x8 m2, ym6, 1 + vinserti32x8 m10, ym14, 1 + vinserti32x8 m3, ym7, 1 + vinserti32x8 m11, ym15, 1 + vshufi32x4 m4, m0, m8, q3131 + vshufi32x4 m0, m8, q2020 + vshufi32x4 m5, m1, m9, q3131 + vshufi32x4 m1, m9, q2020 + vshufi32x4 m6, m2, m10, q3131 + vshufi32x4 m2, m10, q2020 + vshufi32x4 m7, m3, m11, q3131 + vshufi32x4 m3, m11, q2020 + mov r6d, 64*4 +.pass1_transpose_end: + pxor m16, m16 +.zero_loop: + mova [cq+r6+64*0], m16 + mova [cq+r6+64*1], m16 + mova [cq+r6+64*2], m16 + mova [cq+r6+64*3], m16 + sub r6d, 64*4 + jge .zero_loop + TRANSPOSE_4D 0, 1, 2, 3, 16 + TRANSPOSE_4D 4, 5, 6, 7, 16 + jmp tx2q +.pass2: + test eobd, eobd + jl .pass2_fast + call .main_part1 + jmp .pass2_end +.pass2_fast: + call .main_part1_fast +.pass2_end: + vpbroadcastd m3, [o(pixel_clip6)] + paddd m0, m3 + paddd m18, m3 + call .main_part2 + REPX {psrad x, 6}, m0, m1, m2, m3 + packssdw m0, m1 + lea r6, [strideq*3] + packssdw m1, m2, m3 + mova m2, [o(deintq_perm)] + vpbroadcastd m3, [o(pixel_clip)] + REPX {psrad x, 6}, m4, m5, m6, m7 + call .write_16x4 + packssdw m0, m4, m5 + packssdw m1, m6, m7 + REPX {psrad x, 6}, m8, m9, m10, m11 + call .write_16x4 + packssdw m0, m8, m9 + packssdw m1, m10, m11 +.pass2_end2: + REPX {psrad x, 6}, m12, m13, m14, m15 + call .write_16x4 + packssdw m0, m12, m13 + packssdw m1, m14, m15 + call .write_16x4 + RET +ALIGN function_align +.write_16x4: + mova ym16, [dstq+strideq*0] + vinserti32x8 m16, [dstq+strideq*1], 1 + mova ym17, [dstq+strideq*2] + vinserti32x8 m17, [dstq+r6 ], 1 + vpermq m0, m2, m0 + vpermq m1, m2, m1 + paddsw m16, m0 + paddsw m17, m1 + psubusw m16, m3 + psubusw m17, m3 + mova [dstq+strideq*0], ym16 + vextracti32x8 [dstq+strideq*1], m16, 1 + mova [dstq+strideq*2], ym17 + vextracti32x8 [dstq+r6 ], m17, 1 + lea dstq, [dstq+strideq*4] + ret +ALIGN function_align + IDCT16_PART1 + ret +ALIGN function_align +.main_part2: + IDCT16_PART2 + ret + +%macro IADST16_PART1 0 +%if mmsize == 64 +.main_part1_fast: +%endif + pmulld m15, m0, [o(pd_16364)] {bcstd} ; t1 + pmulld m0, [o(pd_804)] {bcstd} ; t0 + pmulld m13, m2, [o(pd_15893)] {bcstd} ; t3 + pmulld m2, [o(pd_3981)] {bcstd} ; t2 + pmulld m11, m4, [o(pd_14811)] {bcstd} ; t5 + pmulld m4, [o(pd_7005)] {bcstd} ; t4 + pmulld m9, m6, [o(pd_13160)] {bcstd} ; t7 + pmulld m6, [o(pd_9760)] {bcstd} ; t6 + pmulld m8, m7, [o(pd_11003)] {bcstd} ; t8 + pmulld m7, [o(pd_12140)] {bcstd} ; t9 + pmulld m10, m5, [o(pd_8423)] {bcstd} ; t10 + pmulld m5, [o(pd_14053)] {bcstd} ; t11 + pmulld m12, m3, [o(pd_5520)] {bcstd} ; t12 + pmulld m3, [o(pd_15426)] {bcstd} ; t13 + pmulld m14, m1, [o(pd_2404)] {bcstd} ; t14 + pmulld m1, [o(pd_16207)] {bcstd} ; t15 + REPX {psubd x, m20, x}, m15, m13, m11, m9 +%if mmsize == 64 ; for the ymm variant we only ever use the fast path + jmp %%main_part1b +ALIGN function_align +.main_part1: + ITX_MULSUB_2D 15, 0, 16, 17, 18, _, 804, 16364 ; t1, t0 + ITX_MULSUB_2D 13, 2, 16, 17, 18, _, 3981, 15893 ; t3, t2 + ITX_MULSUB_2D 11, 4, 16, 17, 18, _, 7005, 14811 ; t5, t4 + ITX_MULSUB_2D 9, 6, 16, 17, 18, _, 9760, 13160 ; t7, t6 + ITX_MULSUB_2D 7, 8, 16, 17, 18, _, 12140, 11003 ; t9, t8 + ITX_MULSUB_2D 5, 10, 16, 17, 18, _, 14053, 8423 ; t11, t10 + ITX_MULSUB_2D 3, 12, 16, 17, 18, _, 15426, 5520 ; t13, t12 + ITX_MULSUB_2D 1, 14, 16, 17, 18, _, 16207, 2404 ; t15, t14 + REPX {paddd x, m20}, m15, m13, m11, m9 +%%main_part1b: +%endif + REPX {paddd x, m20}, m0, m2, m4, m6 + psubd m16, m2, m10 ; t10a + paddd m2, m10 ; t2a + psubd m10, m9, m1 ; t15a + paddd m9, m1 ; t7a + psubd m1, m13, m5 ; t11a + paddd m13, m5 ; t3a + psubd m5, m6, m14 ; t14a + paddd m6, m14 ; t6a + REPX {psrad x, 14}, m16, m10, m1, m5 + psubd m14, m0, m8 ; t8a + paddd m0, m8 ; t0a + psubd m8, m15, m7 ; t9a + paddd m15, m7 ; t1a + psubd m7, m4, m12 ; t12a + paddd m4, m12 ; t4a + paddd m12, m11, m3 ; t5a + psubd m11, m3 ; t13a + REPX {psrad x, 14}, m14, m8, m7, m11 + vpbroadcastd m19, [o(pd_9102)] + vpbroadcastd m18, [o(pd_13623)] + ITX_MULSUB_2D 16, 1, 3, 17, _, _, 18, 19 ; t11, t10 + ITX_MULSUB_2D 10, 5, 3, 17, _, _, 19, 18 ; t14, t15 + vpbroadcastd m19, [o(pd_16069)] + vpbroadcastd m18, [o(pd_3196)] + ITX_MULSUB_2D 14, 8, 3, 17, _, _, 18, 19 ; t9, t8 + ITX_MULSUB_2D 11, 7, 3, 17, _, _, 19, 18 ; t12, t13 + vpbroadcastd m19, [o(pd_6270)] + vpbroadcastd m18, [o(pd_15137)] + REPX {psrad x, 14}, m15, m12, m0, m4 + psubd m3, m15, m12 ; t5 + paddd m15, m12 ; t1 + psubd m12, m0, m4 ; t4 + paddd m0, m4 ; t0 + REPX {psrad x, 14}, m2, m6, m13, m9 + psubd m4, m2, m6 ; t6 + paddd m2, m6 ; t2 + psubd m6, m13, m9 ; t7 + paddd m9, m13 ; t3 + REPX {paddd x, m20}, m8, m14, m1, m16 + psubd m13, m8, m11 ; t12a + paddd m8, m11 ; t8a + psubd m11, m14, m7 ; t13a + paddd m14, m7 ; t9a + psubd m7, m1, m10 ; t14a + paddd m1, m10 ; t10a + psubd m10, m16, m5 ; t15a + paddd m16, m5 ; t11a + REPX {psrad x, 14}, m13, m11, m7, m10 + ITX_MULSUB_2D 12, 3, 5, 17, _, _, 19, 18 ; t5a, t4a + ITX_MULSUB_2D 6, 4, 5, 17, _, _, 18, 19 ; t6a, t7a + ITX_MULSUB_2D 13, 11, 5, 17, _, _, 19, 18 ; t13, t12 + ITX_MULSUB_2D 10, 7, 5, 17, _, _, 18, 19 ; t14, t15 + REPX {psrad x, 14}, m8, m1, m14, m16 + psubd m5, m8, m1 ; t10 + paddd m1, m8 ; -out1 + psubd m8, m15, m9 ; t3a + paddd m15, m9 ; -out15 + psubd m9, m14, m16 ; t11 + paddd m14, m16 ; out14 + psubd m16, m0, m2 ; t2a + paddd m0, m2 ; out0 + REPX {paddd x, m20}, m11, m13, m12, m3 + paddd m2, m11, m10 ; out2 + psubd m11, m10 ; t14a + psubd m10, m13, m7 ; t15a + paddd m13, m7 ; -out13 + psubd m7, m12, m4 ; t7 + paddd m12, m4 ; out12 + psubd m4, m3, m6 ; t6 + paddd m3, m6 ; -out3 + REPX {psrad x, 14}, m10, m7, m11, m4 + REPX {pmulld x, m21}, m9, m10, m7, m8, m5, m11, m4, m16 + REPX {psrad x, 14}, m2, m13, m12, m3 +%endmacro + +%macro IADST16_PART2 0 + paddd m9, m20 + psubd m10, m20, m10 + paddd m7, m20 + psubd m8, m20, m8 + paddd m6, m9, m5 ; out6 + psubd m9, m5 ; out9 + psubd m5, m10, m11 ; out5 + paddd m10, m11 ; out10 + psubd m11, m7, m4 ; out11 + paddd m4, m7 ; out4 + psubd m7, m8, m16 ; out7 + paddd m8, m16 ; out8 +%endmacro + +%macro IADST16_PASS1_END 0 + pxor m16, m16 + psubd m1, m16, m1 + psubd m3, m16, m3 + psubd m13, m16, m13 + psubd m15, m16, m15 + REPX {psrad x, 14}, m4, m5, m6, m7, m8, m9, m10, m11 +%endmacro + +INV_TXFM_16X16_FN adst, dct, 39-18 +INV_TXFM_16X16_FN adst, adst + +cglobal vp9_iadst_16x16_internal_10, 0, 7, 22, dst, stride, c, eob, tx2 + mova m0, [cq+64* 0] + mova m1, [cq+64* 1] + mova m2, [cq+64* 2] + mova m3, [cq+64* 3] + mova m4, [cq+64* 4] + mova m5, [cq+64* 5] + mova m6, [cq+64* 6] + mova m7, [cq+64* 7] + vpbroadcastd m20, [o(pd_8192)] + vpbroadcastd m21, [o(pd_11585)] + sub eobd, 39 + jl .pass1_fast + mova m8, [cq+64* 8] + mova m9, [cq+64* 9] + mova m10, [cq+64*10] + mova m11, [cq+64*11] + mova m12, [cq+64*12] + mova m13, [cq+64*13] + mova m14, [cq+64*14] + mova m15, [cq+64*15] + call .main_part1 + call .main_part2 + IADST16_PASS1_END + jmp m(vp9_idct_16x16_internal_10).pass1_end +.pass1_fast: + WRAP_YMM IADST16_PART1 + WRAP_YMM IADST16_PART2 + WRAP_YMM IADST16_PASS1_END + jmp m(vp9_idct_16x16_internal_10).pass1_fast_end +.pass2: + test eobd, eobd + jl .pass2_fast + call .main_part1 + jmp .pass2_end +.pass2_fast: + call .main_part1_fast +.pass2_end: + vpbroadcastd m20, [o(pd_532480)] + call .main_part2 + vpbroadcastd m16, [o(pixel_clip6)] + REPX {paddd x, m16}, m0, m2, m12, m14 + REPX {psubd x, m16, x}, m1, m3, m13, m15 + REPX {psrad x, 6}, m0, m1, m2, m3 + packssdw m0, m1 + lea r6, [strideq*3] + packssdw m1, m2, m3 + mova m2, [o(deintq_perm)] + vpbroadcastd m3, [o(pixel_clip)] + REPX {psrad x, 20}, m4, m5, m6, m7 + call m(vp9_idct_16x16_internal_10).write_16x4 + packssdw m0, m4, m5 + packssdw m1, m6, m7 + paddsw m0, m3 + paddsw m1, m3 + REPX {psrad x, 20}, m8, m9, m10, m11 + call m(vp9_idct_16x16_internal_10).write_16x4 + packssdw m0, m8, m9 + packssdw m1, m10, m11 + paddsw m0, m3 + paddsw m1, m3 + jmp m(vp9_idct_16x16_internal_10).pass2_end2 +ALIGN function_align + IADST16_PART1 + ret +ALIGN function_align +.main_part2: + IADST16_PART2 + ret + +cglobal vp9_idct_idct_32x32_add_10, 4, 7, 23, 64*64, dst, stride, c, eob +%undef cmp + lea r5, [o_base] + dec eobd + jnz .pass1 + imul r6d, [cq], 11585 + vpbroadcastd m3, [o(pixel_clip)] + mov [cq], r3d + add r6d, 8192 + sar r6d, 14 + imul r6d, 11585 + or r3d, 16 + add r6d, 532480 + sar r6d, 20 + vpbroadcastw m2, r6d + paddsw m2, m3 +.dconly_loop: + paddsw m0, m2, [dstq+strideq*0] + paddsw m1, m2, [dstq+strideq*1] + psubusw m0, m3 + psubusw m1, m3 + mova [dstq+strideq*0], m0 + mova [dstq+strideq*1], m1 + lea dstq, [dstq+strideq*2] + dec r3d + jg .dconly_loop + RET +.pass1: + vpbroadcastd m20, [o(pd_8192)] + vpbroadcastd m21, [o(pd_11585)] + cmp eobd, 135 + jl .pass1_fast + add cq, 64 + lea r4, [rsp+64*8] + cmp eobd, 579 + jl .pass1_right_fast + mov r6d, 128*28 + call .pass1_main + jmp .pass1_right_end +.pass1_right_fast: ; bottomright quadrant is zero + mova m0, [cq+128* 1] + mova m1, [cq+128* 3] + mova m2, [cq+128* 5] + mova m3, [cq+128* 7] + mova m4, [cq+128* 9] + mova m5, [cq+128*11] + mova m6, [cq+128*13] + mova m7, [cq+128*15] + call .main_fast + mova m0, [cq+128* 0] + mova m1, [cq+128* 2] + mova m2, [cq+128* 4] + mova m3, [cq+128* 6] + mova m4, [cq+128* 8] + mova m5, [cq+128*10] + mova m6, [cq+128*12] + mova m7, [cq+128*14] + call m(vp9_idct_16x16_internal_10).main_part1_fast + mov r6d, 128*12 + call .pass1_main_end +.pass1_right_end: + mova [r4+64* 8], m0 + mova [r4+64* 9], m1 + mova [r4+64*10], m2 + mova [r4+64*11], m3 + mova [r4+64*12], m4 + mova [r4+64*13], m5 + mova [r4+64*14], m6 + mova [r4+64*15], m7 + mova [r4+64*16], m16 + mova [r4+64*17], m17 + mova [r4+64*18], m18 + mova [r4+64*19], m19 + mova [r4+64*20], m8 + mova [r4+64*21], m9 + mova [r4+64*22], m10 + mova [r4+64*23], m11 + sub cq, 64 + sub r4, 64*8 + mov r6d, 128*28 + call .pass1_main + mova m12, [r4+64*20] + mova m13, [r4+64*21] + mova m14, [r4+64*22] + mova m15, [r4+64*23] + mova [r4+64*20], m8 + mova [r4+64*21], m9 + mova [r4+64*22], m10 + mova [r4+64*23], m11 + mova m8, [r4+64*16] + mova m9, [r4+64*17] + mova m10, [r4+64*18] + mova m11, [r4+64*19] + mova [r4+64*16], m16 + mova [r4+64*17], m17 + mova [r4+64*18], m18 + mova [r4+64*19], m19 + call .main + mova m0, [r4+64*16] + mova m1, [r4+64*17] + mova m2, [r4+64*18] + mova m3, [r4+64*19] + mova m4, [r4+64*20] + mova m5, [r4+64*21] + mova m6, [r4+64*22] + mova m7, [r4+64*23] + mova m8, [r4+64*24] + mova m9, [r4+64*25] + mova m10, [r4+64*26] + mova m11, [r4+64*27] + mova m12, [r4+64*28] + mova m13, [r4+64*29] + mova m14, [r4+64*30] + mova m15, [r4+64*31] + call m(vp9_idct_16x16_internal_10).main_part1 + call .pass2_main_left + mova m8, [r4+64* 8] + mova m9, [r4+64* 9] + mova m10, [r4+64*10] + mova m11, [r4+64*11] + mova m12, [r4+64*12] + mova m13, [r4+64*13] + mova m14, [r4+64*14] + mova m15, [r4+64*15] + TRANSPOSE_4DQ 8, 10, 12, 14, 16 + TRANSPOSE_4DQ 9, 11, 13, 15, 16 + call .main + call .pass2_main_right + mova m8, [r4+64*24] + mova m9, [r4+64*25] + mova m10, [r4+64*26] + mova m11, [r4+64*27] + mova m12, [r4+64*28] + mova m13, [r4+64*29] + mova m14, [r4+64*30] + mova m15, [r4+64*31] + TRANSPOSE_4DQ 8, 10, 12, 14, 16 + TRANSPOSE_4DQ 9, 11, 13, 15, 16 + call m(vp9_idct_16x16_internal_10).main_part1 + jmp .pass2_end +.pass1_fast: + mova m0, [cq+128* 1] + mova m1, [cq+128* 3] + mova m2, [cq+128* 5] + mova m3, [cq+128* 7] + mova m4, [cq+128* 9] + mova m5, [cq+128*11] + mova m6, [cq+128*13] + mova m7, [cq+128*15] + mov r4, rsp + call .main_fast + mova m0, [cq+128* 0] + mova m1, [cq+128* 2] + mova m2, [cq+128* 4] + mova m3, [cq+128* 6] + mova m4, [cq+128* 8] + mova m5, [cq+128*10] + mova m6, [cq+128*12] + mova m7, [cq+128*14] + call m(vp9_idct_16x16_internal_10).main_part1_fast + call m(vp9_idct_16x16_internal_10).main_part2 + mov r6d, 128*12 + call .pass1_main_end2 + mova [r4+64*16], m16 + mova [r4+64*17], m17 + mova [r4+64*18], m18 + mova [r4+64*19], m19 + mova [r4+64*20], m8 + mova [r4+64*21], m9 + mova [r4+64*22], m10 + mova [r4+64*23], m11 + call .main_fast + mova m0, [r4+64*16] + mova m1, [r4+64*17] + mova m2, [r4+64*18] + mova m3, [r4+64*19] + mova m4, [r4+64*20] + mova m5, [r4+64*21] + mova m6, [r4+64*22] + mova m7, [r4+64*23] + call m(vp9_idct_16x16_internal_10).main_part1_fast + call .pass2_main_left + call .main_fast + call .pass2_main_right + call m(vp9_idct_16x16_internal_10).main_part1_fast +.pass2_end: + paddd m0, m22 + paddd m18, m22 + call m(vp9_idct_16x16_internal_10).main_part2 + mova m20, [o(deintq_perm)] + rorx r2, strideq, 59 ; strideq*32 + vpbroadcastd m21, [o(pixel_clip)] + add r2, dstq +%assign i 0 +%rep 16 + mova m16, [r4+64*(15-i)] + mova m17, [r4+64*(i-16)] + mova m18, [r4-64*(17+i)] + paddd m19, m %+ i, m16 + psubd m0, m %+ i, m16 + call .write_32x2 + %assign i i+1 +%endrep + RET +ALIGN function_align +.write_32x2: + paddd m16, m17, m18 + psubd m17, m18 + REPX {psrad x, 6}, m19, m16, m0, m17 + packssdw m16, m19 + packssdw m17, m0 + sub r2, strideq + vpermq m16, m20, m16 + vpermq m17, m20, m17 + paddsw m16, [dstq] + paddsw m17, [r2 ] + psubusw m16, m21 + psubusw m17, m21 + mova [dstq], m16 + mova [r2 ], m17 + add dstq, strideq + ret +ALIGN function_align +.pass1_main: + mova m0, [cq+128* 1] + mova m1, [cq+128* 3] + mova m2, [cq+128* 5] + mova m3, [cq+128* 7] + mova m4, [cq+128* 9] + mova m5, [cq+128*11] + mova m6, [cq+128*13] + mova m7, [cq+128*15] + mova m8, [cq+128*17] + mova m9, [cq+128*19] + mova m10, [cq+128*21] + mova m11, [cq+128*23] + mova m12, [cq+128*25] + mova m13, [cq+128*27] + mova m14, [cq+128*29] + mova m15, [cq+128*31] + call .main + mova m0, [cq+128* 0] + mova m1, [cq+128* 2] + mova m2, [cq+128* 4] + mova m3, [cq+128* 6] + mova m4, [cq+128* 8] + mova m5, [cq+128*10] + mova m6, [cq+128*12] + mova m7, [cq+128*14] + mova m8, [cq+128*16] + mova m9, [cq+128*18] + mova m10, [cq+128*20] + mova m11, [cq+128*22] + mova m12, [cq+128*24] + mova m13, [cq+128*26] + mova m14, [cq+128*28] + mova m15, [cq+128*30] + call m(vp9_idct_16x16_internal_10).main_part1 +.pass1_main_end: + call m(vp9_idct_16x16_internal_10).main_part2 +.pass1_main_end2: + pxor m16, m16 +.pass1_zero_loop: + mova [cq+r6+128*0], m16 + mova [cq+r6+128*1], m16 + mova [cq+r6+128*2], m16 + mova [cq+r6+128*3], m16 + sub r6d, 128*4 + jge .pass1_zero_loop + mova m16, [r4+64*15] + mova m19, [r4+64*14] + mova m22, [r4+64*13] + mova m17, [r4+64*12] + psubd m18, m0, m16 + paddd m16, m0 + paddd m0, m19, m1 + psubd m19, m1, m19 + paddd m1, m17, m3 + psubd m3, m17 + paddd m17, m2, m22 + psubd m2, m22 + TRANSPOSE_4D 3, 2, 19, 18, 22 ; 28 29 30 31 + TRANSPOSE_4D 16, 0, 17, 1, 22 ; 0 1 2 3 + mova [r4+64*54], m3 + mova [r4+64*55], m19 + mova [r4+64*38], m2 + mova [r4+64*39], m18 + mova m2, [r4+64*11] + mova m19, [r4+64*10] + mova m3, [r4+64* 9] + mova m22, [r4+64* 8] + paddd m18, m4, m2 + psubd m4, m2 + paddd m2, m5, m19 + psubd m5, m19 + paddd m19, m6, m3 + psubd m6, m3 + paddd m3, m7, m22 + psubd m7, m22 + TRANSPOSE_4D 7, 6, 5, 4, 22 ; 24 25 26 27 + TRANSPOSE_4D 18, 2, 19, 3, 22 ; 4 5 6 7 + mova [r4+64*52], m7 + mova [r4+64*53], m5 + mova [r4+64*36], m6 + mova [r4+64*37], m4 + mova m7, [r4+64* 7] + mova m4, [r4+64* 6] + mova m5, [r4+64* 5] + mova m22, [r4+64* 4] + psubd m6, m8, m7 + paddd m8, m7 + psubd m7, m9, m4 + paddd m4, m9 + paddd m9, m10, m5 + psubd m10, m5 + paddd m5, m11, m22 + psubd m11, m22 + TRANSPOSE_4D 11, 10, 7, 6, 22 ; 20 21 22 23 + TRANSPOSE_4D 8, 4, 9, 5, 22 ; 8 9 10 11 + mova [r4+64*50], m11 + mova [r4+64*51], m7 + mova [r4+64*34], m10 + mova [r4+64*35], m6 + mova m6, [r4+64* 3] + mova m11, [r4+64* 2] + mova m7, [r4+64* 1] + mova m22, [r4+64* 0] + paddd m10, m12, m6 + psubd m12, m6 + paddd m6, m13, m11 + psubd m13, m11 + paddd m11, m14, m7 + psubd m14, m7 + paddd m7, m15, m22 + psubd m15, m22 + TRANSPOSE_4D 15, 14, 13, 12, 22 ; 16 17 18 19 + TRANSPOSE_4D 10, 6, 11, 7, 22 ; 12 13 14 15 + mova [r4+64*48], m15 + mova [r4+64*49], m13 + mova [r4+64*32], m14 + mova [r4+64*33], m12 + TRANSPOSE_4DQ 0, 2, 4, 6, 22 + TRANSPOSE_4DQ 1, 3, 5, 7, 22 + TRANSPOSE_4DQ 16, 18, 8, 10, 22 + TRANSPOSE_4DQ 17, 19, 9, 11, 22 + ret +ALIGN function_align +.pass2_main_left: + vpbroadcastd m22, [o(pixel_clip6)] + paddd m0, m22 + paddd m18, m22 + call m(vp9_idct_16x16_internal_10).main_part2 + mova [r4+64*16], m0 + mova [r4+64*17], m1 + mova [r4+64*18], m2 + mova [r4+64*19], m3 + mova [r4+64*20], m4 + mova [r4+64*21], m5 + mova [r4+64*22], m6 + mova [r4+64*23], m7 + mova [r4+64*24], m8 + mova [r4+64*25], m9 + mova [r4+64*26], m10 + mova [r4+64*27], m11 + mova [r4+64*28], m12 + mova [r4+64*29], m13 + mova [r4+64*30], m14 + mova [r4+64*31], m15 + add r4, 64*32 + mova m0, [r4+64* 0] + mova m1, [r4+64* 1] + mova m2, [r4+64* 2] + mova m3, [r4+64* 3] + mova m4, [r4+64* 4] + mova m5, [r4+64* 5] + mova m6, [r4+64* 6] + mova m7, [r4+64* 7] + jmp .pass2_main_transpose +ALIGN function_align +.pass2_main_right: + mova m0, [r4+64*16] + mova m1, [r4+64*17] + mova m2, [r4+64*18] + mova m3, [r4+64*19] + mova m4, [r4+64*20] + mova m5, [r4+64*21] + mova m6, [r4+64*22] + mova m7, [r4+64*23] +.pass2_main_transpose: + TRANSPOSE_4DQ 0, 2, 4, 6, 8 + TRANSPOSE_4DQ 1, 3, 5, 7, 8 + ret +ALIGN function_align +.main_fast: + pmulld m15, m0, [o(pd_16364)] {1to16} ; t31a + pmulld m0, [o(pd_804)] {1to16} ; t16a + pmulld m8, m7, [o(pd_11003)] {1to16} ; t17a + pmulld m7, [o(pd_12140)] {1to16} ; t30a + pmulld m11, m4, [o(pd_14811)] {1to16} ; t29a + pmulld m4, [o(pd_7005)] {1to16} ; t18a + pmulld m12, m3, [o(pd_5520)] {1to16} ; t19a + pmulld m3, [o(pd_15426)] {1to16} ; t28a + pmulld m13, m2, [o(pd_15893)] {1to16} ; t27a + pmulld m2, [o(pd_3981)] {1to16} ; t20a + pmulld m10, m5, [o(pd_8423)] {1to16} ; t21a + pmulld m5, [o(pd_14053)] {1to16} ; t26a + pmulld m9, m6, [o(pd_13160)] {1to16} ; t25a + pmulld m6, [o(pd_9760)] {1to16} ; t22a + pmulld m14, m1, [o(pd_2404)] {1to16} ; t23a + pmulld m1, [o(pd_16207)] {1to16} ; t24a + REPX {psubd x, m20, x}, m8, m12, m10, m14 + jmp .main2 +ALIGN function_align +.main: + ITX_MULSUB_2D 0, 15, 16, 17, 18, _, 804, 16364 ; t16a, t31a + ITX_MULSUB_2D 8, 7, 16, 17, 18, _, 12140, 11003 ; t17a, t30a + ITX_MULSUB_2D 4, 11, 16, 17, 18, _, 7005, 14811 ; t18a, t29a + ITX_MULSUB_2D 12, 3, 16, 17, 18, _, 15426, 5520 ; t19a, t28a + ITX_MULSUB_2D 2, 13, 16, 17, 18, _, 3981, 15893 ; t20a, t27a + ITX_MULSUB_2D 10, 5, 16, 17, 18, _, 14053, 8423 ; t21a, t26a + ITX_MULSUB_2D 6, 9, 16, 17, 18, _, 9760, 13160 ; t22a, t25a + ITX_MULSUB_2D 14, 1, 16, 17, 18, _, 16207, 2404 ; t23a, t24a + REPX {paddd x, m20}, m8, m12, m10, m14 +.main2: + REPX {paddd x, m20}, m0, m15, m7, m4, m3, m11 + REPX {psrad x, 14 }, m8, m0, m15, m7, m12, m4, m3, m11 + psubd m16, m0, m8 ; t17 + paddd m0, m8 ; t16 + psubd m8, m15, m7 ; t30 + paddd m15, m7 ; t31 + paddd m7, m12, m4 ; t19 + psubd m12, m4 ; t18 + paddd m4, m3, m11 ; t28 + psubd m3, m11 ; t29 + REPX {paddd x, m20}, m2, m13, m5, m6, m1, m9 + REPX {psrad x, 14 }, m10, m2, m13, m5, m14, m6, m1, m9 + psubd m11, m2, m10 ; t21 + paddd m2, m10 ; t20 + psubd m10, m13, m5 ; t26 + paddd m13, m5 ; t27 + psubd m5, m14, m6 ; t22 + paddd m6, m14 ; t23 + psubd m14, m1, m9 ; t25 + paddd m9, m1 ; t24 + vpbroadcastd m19, [o(pd_16069)] + vpbroadcastd m18, [o(pd_3196)] + ITX_MULSUB_2D 8, 16, 1, 17, _, 20, 18, 19 ; t17a, t30a + ITX_MULSUB_2D 3, 12, 1, 17, _, 20, 18, 19, 1 ; t29a, t18a + vpbroadcastd m19, [o(pd_9102)] + vpbroadcastd m18, [o(pd_13623)] + ITX_MULSUB_2D 10, 11, 1, 17, _, 20, 18, 19 ; t21a, t26a + ITX_MULSUB_2D 14, 5, 1, 17, _, 20, 18, 19, 1 ; t25a, t22a + paddd m1, m6, m2 ; t23a + psubd m6, m2 ; t20a + psubd m2, m9, m13 ; t27a + paddd m9, m13 ; t24a + psubd m13, m15, m4 ; t28a + paddd m15, m4 ; t31a + psubd m4, m8, m12 ; t18 + paddd m8, m12 ; t17 + psubd m12, m0, m7 ; t19a + paddd m0, m7 ; t16a + psubd m7, m16, m3 ; t29 + paddd m3, m16 ; t30 + paddd m16, m5, m10 ; t22 + psubd m5, m10 ; t21 + psubd m10, m14, m11 ; t26 + paddd m14, m11 ; t25 + vpbroadcastd m19, [o(pd_15137)] + vpbroadcastd m18, [o(pd_6270)] + ITX_MULSUB_2D 13, 12, 11, 17, _, 20, 18, 19 ; t19, t28 + ITX_MULSUB_2D 2, 6, 11, 17, _, 20, 18, 19, 1 ; t27, t20 + ITX_MULSUB_2D 7, 4, 11, 17, _, 20, 18, 19 ; t18a, t29a + ITX_MULSUB_2D 10, 5, 11, 17, _, 20, 18, 19, 1 ; t26a, t21a + psubd m11, m0, m1 ; t23 + paddd m0, m1 ; t16 + paddd m1, m16, m8 ; t17a + psubd m16, m8, m16 ; t22a + psubd m8, m15, m9 ; t24 + paddd m15, m9 ; t31 + psubd m9, m3, m14 ; t25a + paddd m14, m3 ; t30a + paddd m3, m6, m13 ; t19a + psubd m6, m13, m6 ; t20a + paddd m13, m10, m4 ; t29 + psubd m10, m4, m10 ; t26 + psubd m4, m12, m2 ; t27a + paddd m12, m2 ; t28a + paddd m2, m7, m5 ; t18 + psubd m7, m5 ; t21 + REPX {pmulld x, m21}, m10, m8, m4, m9, m7, m11, m6, m16 + mova [r4+64* 0], m0 + mova [r4+64* 1], m1 + mova [r4+64* 2], m2 + mova [r4+64* 3], m3 + mova [r4+64*12], m12 + mova [r4+64*13], m13 + mova [r4+64*14], m14 + mova [r4+64*15], m15 + REPX {paddd x, m20}, m10, m8, m4, m9 + psubd m5, m10, m7 ; t21a + paddd m10, m7 ; t26a + psubd m7, m8, m11 ; t23a + paddd m8, m11 ; t24a + REPX {psrad x, 14 }, m5, m10, m7, m8 + paddd m11, m4, m6 ; t27 + psubd m4, m6 ; t20 + psubd m6, m9, m16 ; t22 + paddd m9, m16 ; t25 + REPX {psrad x, 14 }, m11, m4, m6, m9 + mova [r4+64* 4], m4 + mova [r4+64* 5], m5 + mova [r4+64* 6], m6 + mova [r4+64* 7], m7 + mova [r4+64* 8], m8 + mova [r4+64* 9], m9 + mova [r4+64*10], m10 + mova [r4+64*11], m11 + ret + +%endif diff --git a/libavcodec/x86/vp9itxfm_avx2.asm b/libavcodec/x86/vp9itxfm_avx2.asm new file mode 100644 index 000000000..c5ee2426e --- /dev/null +++ b/libavcodec/x86/vp9itxfm_avx2.asm @@ -0,0 +1,1640 @@ +;****************************************************************************** +;* VP9 IDCT SIMD optimizations +;* +;* Copyright (C) 2025 Two Orioles, LLC +;* +;* 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/x86/x86util.asm" + +%if ARCH_X86_64 && HAVE_AVX2_EXTERNAL + +SECTION_RODATA 16 + +deint_shuf: db 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 + +pw_512: times 2 dw 512 ; 16-byte aligned +pd_8192: dd 8192 +pw_m512: times 2 dw -512 +pw_2048: times 2 dw 2048 +pw_1024: times 2 dw 1024 ; 16-byte aligned + +pw_804x2: times 2 dw 804*2 +pw_1606x2: times 2 dw 1606*2 +pw_3196x2: times 2 dw 3196*2 +pw_3981x2: times 2 dw 3981*2 +pw_6270x2: times 2 dw 6270*2 +pw_7005x2: times 2 dw 7005*2 +pw_7723x2: times 2 dw 7723*2 +pw_9760x2: times 2 dw 9760*2 +pw_11585x2: times 2 dw 11585*2 +pw_12140x2: times 2 dw 12140*2 +pw_12665x2: times 2 dw 12665*2 +pw_13160x2: times 2 dw 13160*2 +pw_13623x2: times 2 dw 13623*2 +pw_14053x2: times 2 dw 14053*2 +pw_14449x2: times 2 dw 14449*2 +pw_14811x2: times 2 dw 14811*2 +pw_15137x2: times 2 dw 15137*2 +pw_15426x2: times 2 dw 15426*2 +pw_15679x2: times 2 dw 15679*2 +pw_15893x2: times 2 dw 15893*2 +pw_16069x2: times 2 dw 16069*2 +pw_16207x2: times 2 dw 16207*2 +pw_16305x2: times 2 dw 16305*2 +pw_16364x2: times 2 dw 16364*2 +pw_m2404x2: times 2 dw -2404*2 +pw_m4756x2: times 2 dw -4756*2 +pw_m5520x2: times 2 dw -5520*2 +pw_m8423x2: times 2 dw -8423*2 +pw_m9102x2: times 2 dw -9102*2 +pw_m10394x2: times 2 dw -10394*2 +pw_m11003x2: times 2 dw -11003*2 +pw_m11585x2: times 2 dw -11585*2 + +%macro COEF_PAIR 2-3 +pw_%1_%2: dw %1, %2 +pw_m%2_%1: dw -%2, %1 +%if %0 == 3 +pw_m%1_m%2: dw -%1, -%2 +%endif +%endmacro + +COEF_PAIR 804, 16364 +COEF_PAIR 1606, 16305 +COEF_PAIR 3196, 16069, 1 +COEF_PAIR 3981, 15893 +COEF_PAIR 6270, 15137, 1 +COEF_PAIR 7005, 14811 +COEF_PAIR 7723, 14449 +COEF_PAIR 9102, 13623 +COEF_PAIR 9760, 13160 +COEF_PAIR 11585, 11585 +COEF_PAIR 12140, 11003 +COEF_PAIR 12665, 10394 +COEF_PAIR 13623, 9102, 1 +COEF_PAIR 14053, 8423 +COEF_PAIR 15137, 6270 +COEF_PAIR 15426, 5520 +COEF_PAIR 15679, 4756 +COEF_PAIR 16069, 3196 +COEF_PAIR 16207, 2404 + +; ADST4-only: +pw_0_13377: dw 0, 13377 +pw_13377_m13377: dw 13377, -13377 +pw_m13377_m5283: dw -13377, -5283 +pw_13377_m15212: dw 13377, -15212 +pw_9929_m5283: dw 9929, -5283 +pw_5283_15212: dw 5283, 15212 +pw_13377_9929: dw 13377, 9929 + +; ADST16-only: +pw_8423_3981: dw 8423, 3981 +pw_m8423_3981: dw -8423, 3981 +pw_14053_m15893: dw 14053, -15893 +pw_m14053_m15893: dw -14053, -15893 +pw_2404_9760: dw 2404, 9760 +pw_m2404_9760: dw -2404, 9760 +pw_16207_m13160: dw 16207, -13160 +pw_m16207_m13160: dw -16207, -13160 +pw_11003_804: dw 11003, 804 +pw_m11003_804: dw -11003, 804 +pw_12140_m16364: dw 12140, -16364 +pw_m12140_m16364: dw -12140, -16364 +pw_5520_7005: dw 5520, 7005 +pw_m5520_7005: dw -5520, 7005 +pw_15426_m14811: dw 15426, -14811 +pw_m15426_m14811: dw -15426, -14811 + +SECTION .text + +%define o_base pw_512 + 128 +%define o(x) (r6 - (o_base) + (x)) +%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX) + +%macro IWHT4_1D_PACKED 0 + psubw m2, m0, m3 + paddw m0, m3 + punpckhqdq m2, m2 ; t2 t2 + punpcklqdq m0, m0 ; t0 t0 + psubw m1, m0, m2 + psraw m1, 1 + psubw m1, m3 ; t1 t3 + psubw m0, m1 ; ____ out0 + paddw m2, m1 ; out3 ____ +%endmacro + +INIT_XMM avx2 +cglobal vp9_iwht_iwht_4x4_add, 3, 3, 6, dst, stride, c + mova m0, [cq+16*0] + mova m1, [cq+16*1] + pxor m2, m2 + mova [cq+16*0], m2 + mova [cq+16*1], m2 + lea r2, [dstq+strideq*2] + punpckhqdq m3, m0, m1 ; in1 in3 + punpcklqdq m0, m1 ; in0 in2 + movd m4, [r2 +strideq*0] + pinsrd m4, [dstq+strideq*1], 1 + movd m5, [r2 +strideq*1] + pinsrd m5, [dstq+strideq*0], 1 + psraw m3, 2 + psraw m0, 2 + IWHT4_1D_PACKED + punpckhwd m0, m1 + punpcklwd m1, m2 + punpckhdq m2, m0, m1 + punpckldq m0, m1 + punpckhqdq m3, m0, m2 + punpcklqdq m0, m2 + IWHT4_1D_PACKED + pmovzxbw m4, m4 + pmovzxbw m5, m5 + vpblendd m0, m2, 0x03 + paddw m1, m4 + paddw m0, m5 + packuswb m0, m1 + pextrd [dstq+strideq*0], m0, 1 + pextrd [dstq+strideq*1], m0, 3 + pextrd [r2 +strideq*0], m0, 2 + movd [r2 +strideq*1], m0 + RET + +%macro ITX_MUL2X_PACK 6-7 0 ; dst/src, tmp[1-2], rnd, coef[1-2], swap +%if %7 + vpbroadcastd m%2, [o(pw_%5_%6)] + vpbroadcastd m%3, [o(pw_m%6_%5)] +%else + vpbroadcastd m%2, [o(pw_m%6_%5)] + vpbroadcastd m%3, [o(pw_%5_%6)] +%endif + pmaddwd m%2, m%1 + pmaddwd m%1, m%3 + paddd m%2, m%4 + paddd m%1, m%4 + psrad m%2, 14 + psrad m%1, 14 + packssdw m%1, m%2 +%endmacro + +; dst1 = (src1 * coef1 - src2 * coef2 + rnd) >> 12 +; dst2 = (src1 * coef2 + src2 * coef1 + rnd) >> 12 +%macro ITX_MULSUB_2W 7 ; dst/src[1-2], tmp[1-2], rnd, coef[1-2] + punpckhwd m%3, m%2, m%1 + punpcklwd m%2, m%1 +%if %7 < 32 + pmaddwd m%1, m%7, m%2 + pmaddwd m%4, m%7, m%3 +%else + vpbroadcastd m%1, [o(pw_m%7_%6)] + pmaddwd m%4, m%3, m%1 + pmaddwd m%1, m%2 +%endif + paddd m%4, m%5 + paddd m%1, m%5 + psrad m%4, 14 + psrad m%1, 14 + packssdw m%1, m%4 +%if %7 < 32 + pmaddwd m%3, m%6 + pmaddwd m%2, m%6 +%else + vpbroadcastd m%4, [o(pw_%6_%7)] + pmaddwd m%3, m%4 + pmaddwd m%2, m%4 +%endif + paddd m%3, m%5 + paddd m%2, m%5 + psrad m%3, 14 + psrad m%2, 14 + packssdw m%2, m%3 +%endmacro + +%macro ADST_MULSUB_2W 8-10 ; dst/src[1-2], dst[3-4], tmp, rnd, coef[1-4] + vpbroadcastd m%3, [o(pw_m%8_%7)] + vpbroadcastd m%4, [o(pw_%7_%8)] + pmaddwd m%3, m%1 + pmaddwd m%1, m%4 +%if %0 == 8 + vpbroadcastd m%5, [o(pw_%8_%7)] + vpbroadcastd m%4, [o(pw_m%7_%8)] +%else + vpbroadcastd m%5, [o(pw_m%10_%9)] + vpbroadcastd m%4, [o(pw_%9_%10)] +%endif + pmaddwd m%5, m%2 + pmaddwd m%4, m%2 + paddd m%3, m%6 + paddd m%1, m%6 + psubd m%2, m%1, m%4 + paddd m%1, m%4 + psubd m%4, m%3, m%5 + paddd m%3, m%5 +%endmacro + +%macro ADST_MULSUB_4W 12-14 ; dst/src[1-4], tmp[1-5], rnd, coef[1-4] + vpbroadcastd m%8, [o(pw_%11_%12)] + vpbroadcastd m%7, [o(pw_m%12_%11)] + punpckhwd m%5, m%2, m%1 + punpcklwd m%2, m%1 +%if %0 == 12 + vpbroadcastd m%1, [o(pw_m%11_%12)] + vpbroadcastd m%9, [o(pw_%12_%11)] +%else + vpbroadcastd m%1, [o(pw_%13_%14)] + vpbroadcastd m%9, [o(pw_m%14_%13)] +%endif + pmaddwd m%6, m%5, m%8 + pmaddwd m%8, m%2 + pmaddwd m%5, m%7 + pmaddwd m%2, m%7 + punpckhwd m%7, m%4, m%3 + punpcklwd m%4, m%3 + pmaddwd m%3, m%7, m%1 + pmaddwd m%1, m%4 + pmaddwd m%7, m%9 + pmaddwd m%9, m%4 + REPX {paddd x, m%10}, m%6, m%8, m%5, m%2 + psubd m%4, m%6, m%3 + paddd m%6, m%3 + psubd m%3, m%8, m%1 + paddd m%1, m%8 + REPX {psrad x, 14}, m%4, m%3, m%6, m%1 + psubd m%8, m%5, m%7 + paddd m%5, m%7 + packssdw m%3, m%4 + psubd m%4, m%2, m%9 + paddd m%2, m%9 + packssdw m%1, m%6 + REPX {psrad x, 14}, m%8, m%4, m%5, m%2 + packssdw m%4, m%8 + packssdw m%2, m%5 +%endmacro + +%macro INV_TXFM_FN 3-4 0 ; type1, type2, size, eob_offset +cglobal vp9_i%1_i%2_%3_add, 4, 5, 0, dst, stride, c, eob, tx2 + %undef cmp + %define %%p1 m(vp9_i%1_%3_internal) + lea r6, [o_base] + ; Jump to the 1st txfm function if we're not taking the fast path, which + ; in turn performs an indirect jump to the 2nd txfm function. + lea tx2q, [m(vp9_i%2_%3_internal).pass2] +%ifidn %1_%2, dct_dct + cmp eobd, 1 + jne %%p1 +%else +%if %4 + add eobd, %4 +%endif + ; jump to the 1st txfm function unless it's located directly after this + times ((%%end - %%p1) >> 31) & 1 jmp %%p1 +ALIGN function_align +%%end: +%endif +%endmacro + +%macro INV_TXFM_4X4_FN 2 ; type1, type2 + INV_TXFM_FN %1, %2, 4x4 +%ifidn %1_%2, dct_dct + vpbroadcastw m0, [cq] + vpbroadcastd m1, [o(pw_11585x2)] + pmulhrsw m0, m1 + pmulhrsw m0, m1 + mova m1, m0 + jmp m(vp9_idct_4x4_internal).pass2_end +%endif +%endmacro + +INV_TXFM_4X4_FN dct, dct +INV_TXFM_4X4_FN dct, adst + +cglobal vp9_idct_4x4_internal, 0, 5, 6, dst, stride, c, eob, tx2 + mova m0, [cq+16*0] + mova m1, [cq+16*1] + call .main +.pass1_end: + mova m2, [o(deint_shuf)] + shufps m3, m0, m1, q1331 + shufps m0, m1, q0220 + pshufb m0, m2 + pshufb m1, m3, m2 + jmp tx2q +.pass2: + call .main +.pass2_end: + vpbroadcastd m2, [o(pw_2048)] + pmulhrsw m0, m2 + pmulhrsw m1, m2 + lea r3, [dstq+strideq*2] + movd m2, [dstq+strideq*0] + pinsrd m2, [dstq+strideq*1], 1 + movd m3, [r3 +strideq*1] + pinsrd m3, [r3 +strideq*0], 1 + pxor m4, m4 + pmovzxbw m2, m2 + mova [cq+16*0], m4 + pmovzxbw m3, m3 + mova [cq+16*1], m4 + paddw m0, m2 + paddw m1, m3 + packuswb m0, m1 + movd [dstq+strideq*0], m0 + pextrd [dstq+strideq*1], m0, 1 + pextrd [r3 +strideq*0], m0, 3 + pextrd [r3 +strideq*1], m0, 2 + RET +ALIGN function_align +.main: + vpbroadcastd m4, [o(pd_8192)] + punpckhwd m2, m1, m0 + psubw m3, m0, m1 + paddw m0, m1 + punpcklqdq m0, m3 + ITX_MUL2X_PACK 2, 1, 3, 4, 6270, 15137 + vpbroadcastd m4, [o(pw_11585x2)] + pmulhrsw m0, m4 ; t0 t1 + psubw m1, m0, m2 ; out3 out2 + paddw m0, m2 ; out0 out1 + ret + +INV_TXFM_4X4_FN adst, dct +INV_TXFM_4X4_FN adst, adst + +cglobal vp9_iadst_4x4_internal, 0, 5, 6, dst, stride, c, eob, tx2 + mova m0, [cq+16*0] + mova m1, [cq+16*1] + call .main + jmp m(vp9_idct_4x4_internal).pass1_end +.pass2: + call .main + jmp m(vp9_idct_4x4_internal).pass2_end +ALIGN function_align +.main: + vpbroadcastd m4, [o(pw_0_13377)] + punpckhwd m2, m0, m1 + vpbroadcastd m5, [o(pw_13377_m13377)] + punpcklwd m0, m1 + vpbroadcastd m1, [o(pw_m13377_m5283)] + vpbroadcastd m3, [o(pw_13377_m15212)] + pmaddwd m4, m2 + pmaddwd m5, m0 + pmaddwd m1, m2 + pmaddwd m3, m2 + paddd m4, m5 ; 2 + vpbroadcastd m5, [o(pw_9929_m5283)] + pmaddwd m5, m0 + paddd m1, m5 + paddd m3, m5 ; 1 + vpbroadcastd m5, [o(pw_5283_15212)] + pmaddwd m0, m5 + vpbroadcastd m5, [o(pw_13377_9929)] + pmaddwd m2, m5 + vpbroadcastd m5, [o(pd_8192)] + paddd m4, m5 + paddd m0, m5 + paddd m3, m5 + paddd m1, m0 ; 3 + paddd m0, m2 ; 0 + REPX {psrad x, 14}, m4, m1, m3, m0 + packssdw m1, m4 ; out3 out2 + packssdw m0, m3 ; out0 out1 + ret + +%macro WRITE_8X4 4-7 strideq*1, strideq*2, r3 ; coefs[1-2], tmp[1-2], off[1-3] + movq xm%3, [dstq ] + movhps xm%3, [dstq+%5] + movq xm%4, [dstq+%6] + movhps xm%4, [dstq+%7] + pmovzxbw m%3, xm%3 + pmovzxbw m%4, xm%4 + paddw m%3, m%1 + paddw m%4, m%2 + packuswb m%3, m%4 + vextracti128 xm%4, m%3, 1 + movq [dstq ], xm%3 + movhps [dstq+%6], xm%3 + movq [dstq+%5], xm%4 + movhps [dstq+%7], xm%4 +%endmacro + +%macro INV_TXFM_8X8_FN 2 ; type1, type2 + INV_TXFM_FN %1, %2, 8x8 +%ifidn %1_%2, dct_dct + vpbroadcastw xm2, [cq] + vpbroadcastd xm1, [o(pw_11585x2)] + vpbroadcastd xm0, [o(pw_1024)] + mov word [cq], 0 + pmulhrsw xm2, xm1 + add r3d, 3 + pmulhrsw xm2, xm1 + pmulhrsw xm2, xm0 +.dconly_loop: + pmovzxbw xm0, [dstq+strideq*0] + pmovzxbw xm1, [dstq+strideq*1] + paddw xm0, xm2 + paddw xm1, xm2 + packuswb xm0, xm1 + movq [dstq+strideq*0], xm0 + movhps [dstq+strideq*1], xm0 + lea dstq, [dstq+strideq*2] + dec r3d + jg .dconly_loop + RET +%endif +%endmacro + +INIT_YMM avx2 +INV_TXFM_8X8_FN dct, dct +INV_TXFM_8X8_FN dct, adst + +cglobal vp9_idct_8x8_internal, 0, 5, 8, dst, stride, c, eob, tx2 + vpermq m0, [cq+32*0], q3120 ; 0 1 + vpermq m3, [cq+32*3], q3120 ; 6 7 + vpermq m2, [cq+32*2], q3120 ; 4 5 + vpermq m1, [cq+32*1], q3120 ; 2 3 + call .main + shufps m4, m0, m1, q0220 + shufps m5, m0, m1, q1331 + vbroadcasti128 m0, [o(deint_shuf)] + shufps m1, m2, m3, q0220 + shufps m3, m2, m3, q1331 + REPX {pshufb x, m0}, m4, m5, m1, m3 + vinserti128 m0, m4, xm1, 1 + vperm2i128 m2, m4, m1, 0x31 + vinserti128 m1, m5, xm3, 1 + vperm2i128 m3, m5, m3, 0x31 + jmp tx2q +.pass2: + call .main + vpbroadcastd m4, [o(pw_1024)] + vpermq m1, m1, q2031 + vpermq m3, m3, q2031 +.end: + vpermq m0, m0, q3120 + vpermq m2, m2, q3120 + REPX {pmulhrsw x, m4}, m0, m1, m2, m3 + pxor m4, m4 + REPX {mova [cq+32*x], m4}, 0, 1, 2, 3 + lea r3, [strideq*3] + WRITE_8X4 0, 1, 4, 5 + lea dstq, [dstq+strideq*4] + WRITE_8X4 2, 3, 4, 5 + RET +ALIGN function_align +.main: + vpbroadcastd m6, [o(pd_8192)] + punpckhwd m5, m3, m0 ; in7 in1 + punpckhwd m4, m1, m2 ; in3 in5 + punpcklwd m3, m1 ; in2 in6 + psubw m1, m0, m2 + paddw m0, m2 + punpcklqdq m0, m1 ; in0+in4 in0-in4 + ITX_MUL2X_PACK 5, 1, 2, 6, 3196, 16069, 1 ; t4a t7a + ITX_MUL2X_PACK 4, 1, 2, 6, 13623, 9102, 1 ; t5a t6a + ITX_MUL2X_PACK 3, 1, 2, 6, 6270, 15137 ; t3 t2 + vpbroadcastd m6, [o(pw_11585x2)] + psubw m2, m5, m4 ; t4 t7 + paddw m5, m4 ; t5a t6a + pshufd m4, m2, q1032 + psubw m1, m2, m4 + paddw m4, m2 + vpblendd m4, m1, 0xcc + pmulhrsw m0, m6 ; t0 t1 + pmulhrsw m4, m6 ; t6 t5 + psubw m1, m0, m3 ; tmp3 tmp2 + paddw m0, m3 ; tmp0 tmp1 + shufps m2, m5, m4, q1032 + vpblendd m5, m4, 0xcc + psubw m3, m0, m2 ; out7 out6 + paddw m0, m2 ; out0 out1 + psubw m2, m1, m5 ; out4 out5 + paddw m1, m5 ; out3 out2 + ret + +INV_TXFM_8X8_FN adst, dct +INV_TXFM_8X8_FN adst, adst + +cglobal vp9_iadst_8x8_internal, 0, 5, 8, dst, stride, c, eob, tx2 + vpermq m4, [cq+32*0], q1302 ; 1 0 + vpermq m3, [cq+32*3], q3120 ; 6 7 + vpermq m5, [cq+32*1], q1302 ; 3 2 + vpermq m2, [cq+32*2], q3120 ; 4 5 + call .main + punpcklwd m4, m0, m1 + punpckhwd m0, m1 + punpcklwd m1, m2, m3 + punpckhwd m2, m3 + pxor m3, m3 + psubw m0, m3, m0 + psubw m2, m3, m2 + punpcklwd m3, m4, m0 + punpckhwd m4, m0 + punpcklwd m0, m1, m2 + punpckhwd m1, m2 + vperm2i128 m2, m3, m0, 0x31 + vinserti128 m0, m3, xm0, 1 + vperm2i128 m3, m4, m1, 0x31 + vinserti128 m1, m4, xm1, 1 + jmp tx2q +.pass2: + pshufd m4, m0, q1032 + pshufd m5, m1, q1032 + call .main + vpbroadcastd m5, [o(pw_1024)] + vpbroadcastd xm4, [o(pw_2048)] + psubw m4, m5 ; lower half = 1024, upper half = -1024 + REPX {vpermq x, x, q3120}, m1, m3 + jmp m(vp9_idct_8x8_internal).end +ALIGN function_align +.main: + vpbroadcastd m7, [o(pd_8192)] + punpckhwd m0, m4, m3 ; 0 7 + punpckhwd m1, m5, m2 ; 2 5 + punpcklwd m2, m5 ; 4 3 + punpcklwd m3, m4 ; 6 1 + ADST_MULSUB_2W 0, 2, 4, 5, 6, 7, 1606, 16305, 12665, 10394 ; t0, t4, t1, t5 + pslld m2, 2 + REPX {psrad x, 14}, m0, m5, m4 + pblendw m2, m5, 0x55 ; t5 t4 + packssdw m0, m4 ; t0 t1 + ADST_MULSUB_2W 1, 3, 4, 5, 6, 7, 7723, 14449, 15679, 4756 ; t2, t6, t3, t7 + pslld m5, 2 + REPX {psrad x, 14}, m3, m1, m4 + pblendw m3, m5, 0xaa ; t6 t7 + packssdw m1, m4 ; t2 t3 + ADST_MULSUB_2W 2, 3, 4, 5, 6, 7, 6270, 15137 ; t4, t6, t5, t7 + REPX {psrad x, 14}, m3, m2, m5, m4 + packssdw m3, m5 ; t6 t7 + packssdw m2, m4 ; -out1 out6 + vpbroadcastd m5, [o(pw_11585x2)] + psubw m4, m0, m1 ; t2 t3 + paddw m0, m1 ; out0 -out7 + punpckhqdq m1, m4, m3 ; t3 t7 + punpcklqdq m4, m3 ; t2 t6 + punpckhqdq m3, m2, m0 ; out6 -out7 + punpcklqdq m0, m2 ; out0 -out1 + psubw m2, m4, m1 + paddw m1, m4 + pshufd m1, m1, q1032 + pmulhrsw m2, m5 ; out4 -out5 + pmulhrsw m1, m5 ; out2 -out3 + ret + +%macro WRITE_16X2 6 ; coefs[1-2], tmp[1-2], offset[1-2] + pmovzxbw m%3, [dstq+%5] +%ifnum %1 + paddw m%3, m%1 +%else + paddw m%3, %1 +%endif + pmovzxbw m%4, [dstq+%6] +%ifnum %2 + paddw m%4, m%2 +%else + paddw m%4, %2 +%endif + packuswb m%3, m%4 + vpermq m%3, m%3, q3120 + mova [dstq+%5], xm%3 + vextracti128 [dstq+%6], m%3, 1 +%endmacro + +%macro INV_TXFM_16X16_FN 2-3 0 ; type1, type2, eob_offset + INV_TXFM_FN %1, %2, 16x16, %3 +%ifidn %1_%2, dct_dct + movd xm0, [o(pw_11585x2)] + pmulhrsw xm3, xm0, [cq] + pxor m2, m2 + pmulhrsw xm3, xm0 + pmulhrsw xm3, [o(pw_512)] + movd [cq], xm2 + add r3d, 7 + vpbroadcastw m3, xm3 +.dconly_loop: + mova xm1, [dstq+strideq*0] + vinserti128 m1, [dstq+strideq*1], 1 + punpcklbw m0, m1, m2 + punpckhbw m1, m2 + paddw m0, m3 + paddw m1, m3 + packuswb m0, m1 + mova [dstq+strideq*0], xm0 + vextracti128 [dstq+strideq*1], m0, 1 + lea dstq, [dstq+strideq*2] + dec r3d + jg .dconly_loop + RET +%endif +%endmacro + +%macro IDCT16_MAIN 2 ; name, idct32 (uses 32-bit intermediates for 11585 multiplies) +%1_fast: + vpbroadcastd m10, [o(pw_m9102x2)] + vpbroadcastd m8, [o(pw_13623x2)] + vpbroadcastd m14, [o(pw_16069x2)] + vpbroadcastd m15, [o(pw_3196x2)] + pmulhrsw m10, m6 + vpbroadcastd m12, [o(pw_15137x2)] + pmulhrsw m6, m8 + vpbroadcastd m8, [o(pw_6270x2)] + pmulhrsw m14, m2 + vpbroadcastd m9, [o(pw_11585x2)] + pmulhrsw m2, m15 + vpbroadcastd m15, [o(pd_8192)] + pmulhrsw m12, m4 + pmulhrsw m4, m8 + pmulhrsw m0, m9 + mova m8, m0 + jmp %%main2 +ALIGN function_align +%1: + mova [rsp+gprsize+32*1], m13 + mova [rsp+gprsize+32*2], m9 + vpbroadcastd m15, [o(pd_8192)] + ITX_MULSUB_2W 10, 6, 9, 13, 15, 13623, 9102 ; t5a, t6a + ITX_MULSUB_2W 2, 14, 9, 13, 15, 3196, 16069 ; t4a, t7a + ITX_MULSUB_2W 4, 12, 9, 13, 15, 6270, 15137 ; t2, t3 + ITX_MULSUB_2W 0, 8, 9, 13, 15, 11585, 11585 ; t1, t0 +%%main2: + paddw m13, m14, m6 ; t7 + psubw m14, m6 ; t6a + paddw m6, m2, m10 ; t4 + psubw m2, m10 ; t5a +%if %2 + ITX_MULSUB_2W 14, 2, 9, 10, 15, 11585, 11585 ; t5, t6 + psubw m10, m0, m4 ; t2 + paddw m4, m0 ; t1 + paddw m0, m8, m12 ; t0 + psubw m8, m12 ; t3 + psubw m9, m4, m2 ; t6 + paddw m2, m4 ; t1 + psubw m4, m8, m6 ; t4 + paddw m8, m6 ; t3 + psubw m6, m10, m14 ; t5 + paddw m10, m14 ; t2 +%else + vpbroadcastd m9, [o(pw_11585x2)] + psubw m10, m14, m2 + paddw m2, m14 + pmulhrsw m10, m9 ; t5 + pmulhrsw m2, m9 ; t6 + psubw m14, m0, m4 ; t2 + paddw m4, m0 ; t1 + paddw m0, m8, m12 ; t0 + psubw m8, m12 ; t3 + psubw m9, m4, m2 ; t6 + paddw m2, m4 ; t1 + psubw m4, m8, m6 ; t4 + paddw m8, m6 ; t3 + psubw m6, m14, m10 ; t5 + paddw m10, m14 ; t2 +%endif + psubw m14, m0, m13 ; t7 + paddw m0, m13 ; t0 + test eobd, eobd + jl %%main3_fast + mova m12, [rsp+gprsize+32*2] ; in9 + mova [rsp+gprsize+32*2], m14 + mova m13, [rsp+gprsize+32*1] ; in13 + mova [rsp+gprsize+32*1], m2 + mova m14, [rsp+gprsize+32*0] ; in15 + mova [rsp+gprsize+32*0], m8 + ITX_MULSUB_2W 1, 14, 2, 8, 15, 1606, 16305 ; t8a, t15a + ITX_MULSUB_2W 12, 7, 2, 8, 15, 12665, 10394 ; t9a, t14a + ITX_MULSUB_2W 5, 11, 2, 8, 15, 7723, 14449 ; t10a, t13a + ITX_MULSUB_2W 13, 3, 2, 8, 15, 15679, 4756 ; t11a, t12a + jmp %%main3 +%%main3_fast: + mova [rsp+gprsize+32*2], m14 + mova [rsp+gprsize+32*1], m2 + mova [rsp+gprsize+32*0], m8 + vpbroadcastd m14, [o(pw_16305x2)] + vpbroadcastd m2, [o(pw_1606x2)] + vpbroadcastd m12, [o(pw_m10394x2)] + vpbroadcastd m8, [o(pw_12665x2)] + pmulhrsw m14, m1 + vpbroadcastd m11, [o(pw_14449x2)] + pmulhrsw m1, m2 + vpbroadcastd m2, [o(pw_7723x2)] + pmulhrsw m12, m7 + vpbroadcastd m13, [o(pw_m4756x2)] + pmulhrsw m7, m8 + vpbroadcastd m8, [o(pw_15679x2)] + pmulhrsw m11, m5 + pmulhrsw m5, m2 + pmulhrsw m13, m3 + pmulhrsw m3, m8 +%%main3: + paddw m2, m11, m3 ; t12 + psubw m3, m11 ; t13 + psubw m11, m14, m7 ; t14 + paddw m14, m7 ; t15 + psubw m7, m13, m5 ; t10 + paddw m5, m13 ; t11 + psubw m13, m1, m12 ; t9 + paddw m12, m1 ; t8 + ITX_MULSUB_2W 11, 13, 1, 8, 15, 6270, 15137 ; t9a, t14a + ITX_MULSUB_2W 3, 7, 1, 8, 15, m15137, 6270 ; t10a, t13a +%if %2 + psubw m1, m12, m5 ; t11a + paddw m12, m5 ; t8a + psubw m5, m13, m7 ; t13 + paddw m13, m7 ; t14 + psubw m7, m14, m2 ; t12a + paddw m14, m2 ; t15a + psubw m2, m11, m3 ; t10 + paddw m3, m11 ; t9 + ITX_MULSUB_2W 5, 2, 8, 11, 15, 11585, 11585 ; t10a, t13a + ITX_MULSUB_2W 7, 1, 8, 11, 15, 11585, 11585 ; t11, t12 +%else + vpbroadcastd m15, [o(pw_11585x2)] + psubw m8, m12, m5 ; t11a + paddw m12, m5 ; t8a + psubw m5, m13, m7 ; t13 + paddw m13, m7 ; t14 + psubw m7, m14, m2 ; t12a + paddw m14, m2 ; t15a + psubw m1, m11, m3 ; t10 + paddw m3, m11 ; t9 + paddw m2, m5, m1 ; t13a + psubw m5, m1 ; t10a + paddw m1, m7, m8 ; t12 + psubw m7, m8 ; t11 + REPX {pmulhrsw x, m15}, m2, m5, m1, m7 +%endif + mova m8, [rsp+gprsize+32*1] ; t1 + psubw m15, m0, m14 ; out15 + paddw m0, m14 ; out0 + psubw m14, m8, m13 ; out14 + paddw m8, m13 ; out1 + psubw m13, m10, m2 ; out13 + paddw m2, m10 ; out2 + psubw m11, m4, m7 ; out11 + paddw m4, m7 ; out4 + mova m7, [rsp+gprsize+32*2] ; t7 + psubw m10, m6, m5 ; out10 + paddw m5, m6 ; out5 + paddw m6, m9, m3 ; out6 + psubw m9, m3 ; out9 + mova m3, [rsp+gprsize+32*0] ; t3 + mova [rsp+gprsize+32*1], m8 + psubw m8, m7, m12 ; out8 + paddw m7, m12 ; out7 + psubw m12, m3, m1 ; out12 + paddw m3, m1 ; out3 +%endmacro + +INV_TXFM_16X16_FN dct, dct +INV_TXFM_16X16_FN dct, adst, 39-23 + +cglobal vp9_idct_16x16_internal, 0, 5, 16, 32*6, dst, stride, c, eob, tx2 + mova m0, [cq+32*0] + mova m1, [cq+32*1] + mova m2, [cq+32*2] + mova m3, [cq+32*3] + mova m4, [cq+32*4] + mova m5, [cq+32*5] + mova m6, [cq+32*6] + mova m7, [cq+32*7] + sub eobd, 39 + jl .pass1_fast + add cq, 32*12 + mova m8, [cq-32*4] + mova m9, [cq-32*3] + mova m10, [cq-32*2] + mova m11, [cq-32*1] + mova m12, [cq+32*0] + mova m13, [cq+32*1] + mova m14, [cq+32*2] + mova m15, [cq+32*3] + mova [rsp], m15 + call .main + vextracti128 [rsp+16*4], m0, 1 + mova [rsp+16*0], xm0 +.pass1_end: + vextracti128 [rsp+16*5], m8, 1 + mova [rsp+16*1], xm8 + mova xm1, [rsp+32*1+16*0] + vinserti128 m8, m9, [rsp+32*1+16*1], 0 + vinserti128 m1, xm9, 1 + vperm2i128 m9, m2, m10, 0x31 + vinserti128 m2, xm10, 1 + vperm2i128 m10, m3, m11, 0x31 + vinserti128 m3, xm11, 1 + vperm2i128 m11, m4, m12, 0x31 + vinserti128 m4, xm12, 1 + vperm2i128 m12, m5, m13, 0x31 + vinserti128 m5, xm13, 1 + vperm2i128 m13, m6, m14, 0x31 + vinserti128 m6, xm14, 1 + vperm2i128 m14, m7, m15, 0x31 + vinserti128 m7, xm15, 1 + mova m15, [rsp+32*2] + pxor m0, m0 + mov r3, -32*12 +.zero_loop: + mova [cq+r3+32*0], m0 + mova [cq+r3+32*1], m0 + mova [cq+r3+32*2], m0 + mova [cq+r3+32*3], m0 + add r3, 32*4 + jle .zero_loop + punpcklwd m0, m9, m10 + punpckhwd m9, m10 + punpcklwd m10, m15, m8 + punpckhwd m15, m8 + punpckhwd m8, m11, m12 + punpcklwd m11, m12 + punpckhwd m12, m13, m14 + punpcklwd m13, m14 + punpckhdq m14, m11, m13 + punpckldq m11, m13 + punpckldq m13, m15, m9 + punpckhdq m15, m9 + punpckldq m9, m10, m0 + punpckhdq m10, m0 + punpckhdq m0, m8, m12 + punpckldq m8, m12 + punpcklqdq m12, m13, m8 + punpckhqdq m13, m8 + punpcklqdq m8, m9, m11 + punpckhqdq m9, m11 + punpckhqdq m11, m10, m14 + punpcklqdq m10, m14 + punpcklqdq m14, m15, m0 + punpckhqdq m15, m0 + mova m0, [rsp] + mova [rsp], m15 + punpckhwd m15, m4, m5 + punpcklwd m4, m5 + punpckhwd m5, m0, m1 + punpcklwd m0, m1 + punpckhwd m1, m6, m7 + punpcklwd m6, m7 + punpckhwd m7, m2, m3 + punpcklwd m2, m3 + punpckhdq m3, m0, m2 + punpckldq m0, m2 + punpckldq m2, m4, m6 + punpckhdq m4, m6 + punpckhdq m6, m5, m7 + punpckldq m5, m7 + punpckldq m7, m15, m1 + punpckhdq m15, m1 + punpckhqdq m1, m0, m2 + punpcklqdq m0, m2 + punpcklqdq m2, m3, m4 + punpckhqdq m3, m4 + punpcklqdq m4, m5, m7 + punpckhqdq m5, m7 + punpckhqdq m7, m6, m15 + punpcklqdq m6, m15 + jmp tx2q +.pass1_fast: + call .main_fast + mova xm1, [rsp+32*1] +.pass1_fast_end: + vinserti128 m0, xm8, 1 + vinserti128 m1, xm9, 1 + vinserti128 m2, xm10, 1 + vinserti128 m3, xm11, 1 + vinserti128 m4, xm12, 1 + vinserti128 m5, xm13, 1 + vinserti128 m6, xm14, 1 + vinserti128 m7, xm15, 1 + pxor m8, m8 + REPX {mova [cq+32*x], m8}, 0, 1, 2, 3, 4, 5, 6, 7 + call .transpose_8x8 + jmp tx2q +.pass2: + test eobd, eobd + jl .pass2_fast + call .main + jmp .pass2_end +.pass2_fast: + call .main_fast +.pass2_end: + vpbroadcastd m1, [o(pw_512)] + REPX {pmulhrsw x, m1}, m0, m2, m4, m5, m6, m7, m8, m9, m10, m11, m12, m14 +.end: + REPX {pmulhrsw x, m1}, m3, m13, m15 + pmulhrsw m1, [rsp+32*1] + mova [rsp], m6 + lea r3, [strideq*3] + WRITE_16X2 0, 1, 6, 0, strideq*0, strideq*1 + WRITE_16X2 2, 3, 0, 1, strideq*2, r3 + lea dstq, [dstq+strideq*4] + WRITE_16X2 4, 5, 0, 1, strideq*0, strideq*1 + WRITE_16X2 [rsp], 7, 0, 1, strideq*2, r3 + lea dstq, [dstq+strideq*4] + WRITE_16X2 8, 9, 0, 1, strideq*0, strideq*1 + WRITE_16X2 10, 11, 0, 1, strideq*2, r3 + lea dstq, [dstq+strideq*4] + WRITE_16X2 12, 13, 0, 1, strideq*0, strideq*1 + WRITE_16X2 14, 15, 0, 1, strideq*2, r3 + RET +ALIGN function_align + IDCT16_MAIN .main, 0 + ret +ALIGN function_align +.transpose_8x8: + punpckhwd m8, m4, m5 + punpcklwd m4, m5 + punpckhwd m5, m0, m1 + punpcklwd m0, m1 + punpckhwd m1, m6, m7 + punpcklwd m6, m7 + punpckhwd m7, m2, m3 + punpcklwd m2, m3 + punpckhdq m3, m0, m2 + punpckldq m0, m2 + punpckldq m2, m4, m6 + punpckhdq m4, m6 + punpckhdq m6, m5, m7 + punpckldq m5, m7 + punpckldq m7, m8, m1 + punpckhdq m8, m1 + punpckhqdq m1, m0, m2 + punpcklqdq m0, m2 + punpcklqdq m2, m3, m4 + punpckhqdq m3, m4 + punpcklqdq m4, m5, m7 + punpckhqdq m5, m7 + punpckhqdq m7, m6, m8 + punpcklqdq m6, m8 + ret + +%macro ADST_MULSUB_4W_FAST 12 ; dst/src[1-4], tmp[1-3], rnd, coef[1-4] + vpbroadcastd m%5, [o(pw_%11_m%10)] + vpbroadcastd m%6, [o(pw_m%11_m%10)] + punpckhwd m%7, m%3, m%2 + punpcklwd m%3, m%2 + pmaddwd m%2, m%3, m%5 + pmaddwd m%5, m%7 + pmaddwd m%4, m%3, m%6 + pmaddwd m%6, m%7 + REPX {paddd x, m%8}, m%2, m%5, m%4, m%6 + REPX {psrad x, 14 }, m%2, m%5, m%4, m%6 + packssdw m%2, m%5 + vpbroadcastd m%5, [o(pw_%12_%9)] + packssdw m%4, m%6 + vpbroadcastd m%6, [o(pw_m%12_%9)] + pmaddwd m%1, m%3, m%5 + pmaddwd m%5, m%7 + pmaddwd m%3, m%6 + pmaddwd m%6, m%7 + REPX {paddd x, m%8}, m%1, m%5, m%3, m%6 + REPX {psrad x, 14 }, m%1, m%5, m%3, m%6 + packssdw m%1, m%5 + packssdw m%3, m%6 +%endmacro + +INV_TXFM_16X16_FN adst, dct, 39-18 +INV_TXFM_16X16_FN adst, adst + +cglobal vp9_iadst_16x16_internal, 0, 5, 16, 32*6, dst, stride, c, eob, tx2 + mova m0, [cq+32*0] + mova m1, [cq+32*1] + mova m2, [cq+32*2] + mova m3, [cq+32*3] + mova m4, [cq+32*4] + mova m5, [cq+32*5] + mova m6, [cq+32*6] + mova m7, [cq+32*7] + sub eobd, 39 + jl .pass1_fast + add cq, 32*12 + mova m8, [cq-32*4] + mova m9, [cq-32*3] + mova m10, [cq-32*2] + mova m11, [cq-32*1] + mova m12, [cq+32*0] + mova m13, [cq+32*1] + mova m14, [cq+32*2] + mova m15, [cq+32*3] + mova [rsp+32*0], m15 + call .main + call .pass1_main_part2 + mova [rsp+32*1], m1 + jmp m(vp9_idct_16x16_internal).pass1_end +.pass1_fast: + call .main_fast + call .pass1_main_part2 + mova xm0, [rsp+32*0] + jmp m(vp9_idct_16x16_internal).pass1_fast_end +.pass2: + test eobd, eobd + jl .pass2_fast + call .main + jmp .pass2_end +.pass2_fast: + call .main_fast +.pass2_end: + ; In pass 2 we're going to clip to pixels afterwards anyway, so clipping to + ; 16-bit here will produce the same result as using 32-bit intermediates. + paddsw m5, m10, m11 ; -out5 + psubsw m10, m11 ; out10 + psubsw m11, m8, m4 ; out11 + paddsw m4, m8 ; out4 + psubsw m8, m7, m9 ; out8 + paddsw m7, m9 ; -out7 + psubsw m9, m6, m1 ; out9 + paddsw m6, m1 ; out6 + vpbroadcastd m1, [o(pw_11585x2)] + REPX {pmulhrsw x, m1}, m4, m6, m8, m9, m10, m11 + vpbroadcastd m1, [o(pw_m11585x2)] + pmulhrsw m5, m1 + pmulhrsw m7, m1 + vpbroadcastd m1, [o(pw_512)] + REPX {pmulhrsw x, m1}, m0, m2, m4, m5, m6, m7, m8, m9, m10, m11, m12, m14 + vpbroadcastd m1, [o(pw_m512)] + jmp m(vp9_idct_16x16_internal).end +ALIGN function_align +.main_fast: + mova [rsp+gprsize+32*1], m0 + mova [rsp+gprsize+32*2], m3 + mova [rsp+gprsize+32*3], m4 + vpbroadcastd m15, [o(pd_8192)] + ADST_MULSUB_4W_FAST 13, 2, 5, 10, 0, 3, 4, 15, 3981, 15893, 14053, 8423 + ADST_MULSUB_4W_FAST 9, 6, 1, 14, 0, 3, 4, 15, 9760, 13160, 16207, 2404 + jmp .main2 +ALIGN function_align +.main: + mova [rsp+gprsize+32*1], m0 + mova [rsp+gprsize+32*2], m3 + mova [rsp+gprsize+32*3], m4 + mova [rsp+gprsize+32*4], m12 + mova [rsp+gprsize+32*5], m8 + vpbroadcastd m15, [o(pd_8192)] + ADST_MULSUB_4W 13, 2, 5, 10, 0, 3, 4, 8, 12, 15, 3981, 15893, 14053, 8423 ; t2a, t3a, t10a, t11a + ADST_MULSUB_4W 9, 6, 1, 14, 0, 3, 4, 8, 12, 15, 9760, 13160, 16207, 2404 ; t6a, t7a, t14a, t15a +.main2: + ADST_MULSUB_4W 5, 10, 14, 1, 0, 3, 4, 8, 12, 15, 13623, 9102 ; t10a, t11a, t14a, t15a + psubw m4, m2, m6 ; t7 + paddw m2, m6 ; t3 + psubw m8, m13, m9 ; t6 + paddw m13, m9 ; t2 + mova m0, [rsp+gprsize+32*0] ; in15 + mova [rsp+gprsize+32*0], m10 + mova m10, [rsp+gprsize+32*1] ; in0 + mova [rsp+gprsize+32*1], m13 + mova m13, [rsp+gprsize+32*2] ; in3 + mova [rsp+gprsize+32*2], m1 + mova m6, [rsp+gprsize+32*3] ; in4 + mova [rsp+gprsize+32*3], m2 + mova m2, [rsp+gprsize+32*4] ; in12 + mova [rsp+gprsize+32*4], m5 + mova m5, [rsp+gprsize+32*5] ; in8 + mova [rsp+gprsize+32*5], m14 + test eobd, eobd + jl .main3_fast + ADST_MULSUB_4W 0, 10, 7, 5, 1, 3, 9, 12, 14, 15, 804, 16364, 12140, 11003 ; t0a, t1a, t8a, t9a + ADST_MULSUB_4W 11, 6, 13, 2, 1, 3, 9, 12, 14, 15, 7005, 14811, 15426, 5520 ; t4a, t5a, t12a, t13a + jmp .main3 +.main3_fast: + ADST_MULSUB_4W_FAST 0, 10, 7, 5, 1, 3, 9, 15, 804, 16364, 12140, 11003 + ADST_MULSUB_4W_FAST 11, 6, 13, 2, 1, 3, 9, 15, 7005, 14811, 15426, 5520 +.main3: + ADST_MULSUB_4W 7, 5, 2, 13, 1, 3, 9, 12, 14, 15, 3196, 16069 ; t8a, t9a, t12a, t13a + psubw m3, m0, m11 ; t4 + paddw m0, m11 ; t0 + psubw m12, m10, m6 ; t5 + paddw m10, m6 ; t1 + mova m11, [rsp+gprsize+32*5] ; t14a + mova [rsp+gprsize+32*5], m10 + mova m10, [rsp+gprsize+32*2] ; t15a + mova [rsp+gprsize+32*2], m0 + ADST_MULSUB_4W 2, 13, 10, 11, 0, 1, 6, 9, 14, 15, 6270, 15137 ; out2, -out13, t14a, t15a + ADST_MULSUB_4W 3, 12, 4, 8, 0, 1, 6, 9, 14, 15, 6270, 15137 ; -out3, out12, t6, t7 + mova m6, [rsp+gprsize+32*4] ; t10a + mova m14, [rsp+gprsize+32*0] ; t11a + mova m9, [rsp+gprsize+32*1] ; t2 + mova m0, [rsp+gprsize+32*2] ; t0 + mova m15, [rsp+gprsize+32*5] ; t1 + psubw m1, m7, m6 ; t10 + paddw m7, m6 ; -out1 + psubw m6, m5, m14 ; t11 + paddw m14, m5 ; out14 + mova m5, [rsp+gprsize+32*3] ; t3 + mova [rsp+gprsize+32*1], m7 + psubw m7, m0, m9 ; t2a + paddw m0, m9 ; out0 + psubw m9, m15, m5 ; t3a + paddw m15, m5 ; -out15 + ret +ALIGN function_align +.pass1_main_part2: + mova [rsp+gprsize+16*0], xm0 + vextracti128 [rsp+gprsize+16*4], m0, 1 + mova [rsp+gprsize+32*3], m15 + mova [rsp+gprsize+32*4], m13 + mova [rsp+gprsize+32*5], m3 + vpbroadcastd m15, [o(pw_m11585_11585)] + vpbroadcastd m13, [o(pw_11585_11585)] + vpbroadcastd m3, [o(pd_8192)] + punpcklwd m5, m11, m10 + punpckhwd m11, m10 + pmaddwd m10, m15, m5 + pmaddwd m0, m15, m11 + pmaddwd m5, m13 + pmaddwd m11, m13 + paddd m10, m3 + paddd m0, m3 + psubd m5, m3, m5 + psubd m11, m3, m11 + REPX {psrad x, 14}, m10, m0, m5, m11 + packssdw m10, m0 ; out10 + packssdw m5, m11 ; out5 + punpcklwd m11, m8, m4 + punpckhwd m8, m4 + pmaddwd m4, m13, m11 + pmaddwd m0, m13, m8 + pmaddwd m11, m15 + pmaddwd m8, m15 + paddd m4, m3 + paddd m0, m3 + psubd m11, m3, m11 + psubd m8, m3, m8 + REPX {psrad x, 14}, m4, m0, m11, m8 + packssdw m4, m0 ; out4 + packssdw m11, m8 ; out11 + punpcklwd m8, m9, m7 + punpckhwd m9, m7 + pmaddwd m7, m13, m8 + pmaddwd m0, m13, m9 + pmaddwd m8, m15 + pmaddwd m9, m15 + psubd m7, m3, m7 + psubd m0, m3, m0 + paddd m8, m3 + paddd m9, m3 + REPX {psrad x, 14}, m7, m0, m8, m9 + packssdw m7, m0 ; out7 + packssdw m8, m9 ; out8 + punpckhwd m0, m6, m1 + punpcklwd m6, m1 + pmaddwd m1, m15, m0 + pmaddwd m9, m15, m6 + pmaddwd m0, m13 + pmaddwd m6, m13 + psubd m1, m3, m1 + psubd m9, m3, m9 + paddd m0, m3 + paddd m6, m3 + pxor m3, m3 + psubw m15, m3, [rsp+gprsize+32*3] ; out15 + REPX {psrad x, 14}, m1, m9, m0, m6 + psubw m13, m3, [rsp+gprsize+32*4] ; out13 + packssdw m9, m1 ; out7 + psubw m1, m3, [rsp+gprsize+32*1] ; out1 + packssdw m6, m0 ; out8 + psubw m3, [rsp+gprsize+32*5] ; out3 + ret + +%macro LOAD_8ROWS 2 ; src, stride + mova m0, [%1+%2*0] + mova m1, [%1+%2*1] + mova m2, [%1+%2*2] + mova m3, [%1+%2*3] + mova m4, [%1+%2*4] + mova m5, [%1+%2*5] + mova m6, [%1+%2*6] + mova m7, [%1+%2*7] +%endmacro + +%macro LOAD_8ROWS_H 2 ; src, stride + mova m8, [%1+%2*0] + mova m9, [%1+%2*1] + mova m10, [%1+%2*2] + mova m11, [%1+%2*3] + mova m12, [%1+%2*4] + mova m13, [%1+%2*5] + mova m14, [%1+%2*6] + mova m15, [%1+%2*7] +%endmacro + +; Perform the final sumsub step and YMM lane shuffling +%macro IDCT32_PASS1_END 4 ; row[1-2], tmp[1-2] + mova m%3, [tmp2q+32*( 3-%1)] + psubw m%4, m%1, m%3 + paddw m%1, m%3 + mova m%3, [tmp1q+32*(11-%2)] + mova [tmp1q+32*(11-%2)+16], xm%4 + vextracti128 [tmp2q+32*( 3-%1)+16], m%4, 1 + paddw m%4, m%2, m%3 + psubw m%2, m%3 + mova [tmp1q+32*(11-%2)], xm%2 + vextracti128 [tmp2q+32*( 3-%1)], m%2, 1 + vperm2i128 m%2, m%1, m%4, 0x31 + vinserti128 m%1, xm%4, 1 +%endmacro + +%macro IDCT32_PASS2_END 7 ; coefs[1-2], tmp[1-2], rnd, offset[1-2] + mova m%4, [%2] + paddw m%3, m%1, m%4 + psubw m%1, m%4 + pmovzxbw m%4, [dstq+%6] + pmulhrsw m%3, m%5 + pmulhrsw m%1, m%5 + paddw m%3, m%4 + pmovzxbw m%4, [r2+%7] + paddw m%1, m%4 + packuswb m%3, m%1 + vpermq m%3, m%3, q3120 + mova [dstq+%6], xm%3 + vextracti128 [r2+%7], m%3, 1 +%endmacro + +cglobal vp9_idct_idct_32x32_add, 4, 4, 0, dst, stride, c, eob + lea r6, [o_base] + sub eobd, 1 + jnz .pass1 + movd xm0, [o(pw_11585x2)] + pmulhrsw xm5, xm0, [cq] + pxor m4, m4 + pmulhrsw xm5, xm0 + pmulhrsw xm5, [o(pw_512)] + movd [cq], xm4 + or r3d, 16 + vpbroadcastw m5, xm5 +.dconly_loop: + mova m2, [dstq+strideq*0] + mova m3, [dstq+strideq*1] + punpcklbw m0, m2, m4 + punpckhbw m2, m4 + punpcklbw m1, m3, m4 + punpckhbw m3, m4 + REPX {paddw x, m5}, m0, m2, m1, m3 + packuswb m0, m2 + packuswb m1, m3 + mova [dstq+strideq*0], m0 + mova [dstq+strideq*1], m1 + lea dstq, [dstq+strideq*2] + dec r3d + jg .dconly_loop + RET +.pass1: + PROLOGUE 0, 9, 16, 32*67, dst, stride, c, eob, tmp1, \ + tmp2, base, tmp3, tmp4 + %undef cmp + lea tmp1q, [rsp+32*7] + sub eobd, 135 + lea tmp2q, [tmp1q+32*8] + mov tmp4d, eobd +.pass1_loop: + LOAD_8ROWS cq+64*1, 64*2 + test eobd, eobd + jl .pass1_fast + LOAD_8ROWS_H cq+64*17, 64*2 + call .main + LOAD_8ROWS_H cq+64*16, 64*2 + mova [rsp], m15 + LOAD_8ROWS cq+64*0, 64*2 + call .idct16 + mov tmp3d, 64*30 + jmp .pass1_loop_end +.pass1_fast: + call .main_fast + LOAD_8ROWS cq+64*0, 64*2 + call .idct16_fast + mov tmp3d, 64*14 +.pass1_loop_end: + pxor m1, m1 +.zero_loop: + mova [cq+tmp3q+64*1], m1 + mova [cq+tmp3q+64*0], m1 + mova [cq+tmp3q-64*1], m1 + mova [cq+tmp3q-64*2], m1 + sub tmp3d, 64*4 + jg .zero_loop + mova [rsp+32*0], m9 + IDCT32_PASS1_END 0, 8, 1, 9 + IDCT32_PASS1_END 2, 10, 1, 9 + IDCT32_PASS1_END 3, 11, 1, 9 + IDCT32_PASS1_END 4, 12, 1, 9 + IDCT32_PASS1_END 5, 13, 1, 9 + IDCT32_PASS1_END 6, 14, 1, 9 + IDCT32_PASS1_END 7, 15, 1, 9 + mova m1, [rsp+32*1] + mova m9, [rsp+32*0] + mova [rsp+32*0], m6 + mova [rsp+32*1], m7 + IDCT32_PASS1_END 1, 9, 6, 7 + mova m7, [rsp+32*1] + punpckhwd m6, m12, m13 + punpcklwd m12, m13 + punpckhwd m13, m8, m9 + punpcklwd m8, m9 + punpckhwd m9, m14, m15 + punpcklwd m14, m15 + punpckhwd m15, m10, m11 + punpcklwd m10, m11 + punpckhdq m11, m8, m10 + punpckldq m8, m10 + punpckldq m10, m12, m14 + punpckhdq m12, m14 + punpckhdq m14, m13, m15 + punpckldq m13, m15 + punpckldq m15, m6, m9 + punpckhdq m6, m9 + punpckhqdq m9, m8, m10 + punpcklqdq m8, m10 + punpcklqdq m10, m11, m12 + punpckhqdq m11, m12 + punpcklqdq m12, m13, m15 + punpckhqdq m13, m15 + punpckhqdq m15, m14, m6 + punpcklqdq m14, m6 + mova m6, [rsp+32*0] + mova [rsp+32*0], m8 + call m(vp9_idct_16x16_internal).transpose_8x8 + lea tmp3q, [tmp1q+32*32] + mova m8, [rsp] + mova [tmp3q-32*4], m0 + mova [tmp3q-32*3], m2 + mova [tmp3q-32*2], m4 + mova [tmp3q-32*1], m6 + mova [tmp3q+32*0], m8 + mova [tmp3q+32*1], m10 + mova [tmp3q+32*2], m12 + mova [tmp3q+32*3], m14 + add tmp3q, 32*8 + mova [tmp3q-32*4], m1 + mova [tmp3q-32*3], m3 + mova [tmp3q-32*2], m5 + mova [tmp3q-32*1], m7 + mova [tmp3q+32*0], m9 + mova [tmp3q+32*1], m11 + mova [tmp3q+32*2], m13 + mova [tmp3q+32*3], m15 + mova m0, [tmp1q-32*4] + mova m1, [tmp1q-32*3] + mova m2, [tmp1q-32*2] + mova m3, [tmp1q-32*1] + mova m4, [tmp1q+32*0] + mova m5, [tmp1q+32*1] + mova m6, [tmp1q+32*2] + mova m7, [tmp1q+32*3] + call m(vp9_idct_16x16_internal).transpose_8x8 + mova [tmp1q-32*4], m0 + mova m0, [tmp2q-32*4] + mova [tmp2q-32*4], m1 + mova m1, [tmp2q-32*3] + mova [tmp1q-32*3], m2 + mova m2, [tmp2q-32*2] + mova [tmp2q-32*3], m3 + mova m3, [tmp2q-32*1] + mova [tmp1q-32*2], m4 + mova m4, [tmp2q+32*0] + mova [tmp2q-32*2], m5 + mova m5, [tmp2q+32*1] + mova [tmp1q-32*1], m6 + mova m6, [tmp2q+32*2] + mova [tmp2q-32*1], m7 + mova m7, [tmp2q+32*3] + call m(vp9_idct_16x16_internal).transpose_8x8 + mova [tmp1q+32*0], m0 + mova [tmp2q+32*0], m1 + mova [tmp1q+32*1], m2 + mova [tmp2q+32*1], m3 + mova [tmp1q+32*2], m4 + mova [tmp2q+32*2], m5 + mova [tmp1q+32*3], m6 + mova [tmp2q+32*3], m7 + add cq, 32 + add tmp1q, 32*16 + add tmp2q, 32*16 + add tmp4d, 0x80000000 + jnc .pass1_loop + add tmp1q, 32*24 + imul r2, strideq, 19 + lea tmp4q, [strideq*3] + add r2, dstq + test eobd, eobd + jge .pass2_loop + add tmp1q, 32*16 + add tmp2q, 32*16 + add tmp3q, 32*16 +.pass2_loop: + LOAD_8ROWS tmp2q-32*4, 32 + test eobd, eobd + jl .pass2_fast + LOAD_8ROWS_H tmp3q-32*4, 32 + call .main + sub tmp3q, 32*8 + LOAD_8ROWS_H tmp3q-32*4, 32 + sub tmp3q, 32*16 + LOAD_8ROWS tmp3q-32*4, 32 + mova [rsp], m15 + call .idct16 + jmp .pass2_loop_end +.pass2_fast: + call .main_fast + sub tmp3q, 32*24 + LOAD_8ROWS tmp3q-32*4, 32 + call .idct16_fast +.pass2_loop_end: + mova [rsp+32*0], m7 + mova [rsp+32*2], m15 + vpbroadcastd m15, [o(pw_512)] + IDCT32_PASS2_END 0, tmp2q+32*3, 1, 7, 15, strideq*0, tmp4q*4 + IDCT32_PASS2_END 4, tmp2q-32*1, 0, 7, 15, strideq*4, strideq*8 + IDCT32_PASS2_END 8, tmp1q+32*3, 0, 4, 15, strideq*8, strideq*4 + IDCT32_PASS2_END 12, tmp1q-32*1, 0, 4, 15, tmp4q*4, strideq*0 + add dstq, strideq + sub r2, strideq + mova m1, [rsp+32*1] + IDCT32_PASS2_END 1, tmp2q+32*2, 0, 4, 15, strideq*0, tmp4q*4 + IDCT32_PASS2_END 5, tmp2q-32*2, 0, 4, 15, strideq*4, strideq*8 + IDCT32_PASS2_END 9, tmp1q+32*2, 0, 4, 15, strideq*8, strideq*4 + IDCT32_PASS2_END 13, tmp1q-32*2, 0, 4, 15, tmp4q*4, strideq*0 + add dstq, strideq + sub r2, strideq + IDCT32_PASS2_END 2, tmp2q+32*1, 0, 4, 15, strideq*0, tmp4q*4 + IDCT32_PASS2_END 6, tmp2q-32*3, 0, 4, 15, strideq*4, strideq*8 + IDCT32_PASS2_END 10, tmp1q+32*1, 0, 4, 15, strideq*8, strideq*4 + IDCT32_PASS2_END 14, tmp1q-32*3, 0, 4, 15, tmp4q*4, strideq*0 + add dstq, strideq + sub r2, strideq + mova m7, [rsp+32*0] + mova m1, [rsp+32*2] + IDCT32_PASS2_END 3, tmp2q+32*0, 0, 4, 15, strideq*0, tmp4q*4 + IDCT32_PASS2_END 7, tmp2q-32*4, 0, 4, 15, strideq*4, strideq*8 + IDCT32_PASS2_END 11, tmp1q+32*0, 0, 4, 15, strideq*8, strideq*4 + IDCT32_PASS2_END 1, tmp1q-32*4, 0, 4, 15, tmp4q*4, strideq*0 + lea tmp3q, [tmp1q-32*32] + cmp tmp2q, tmp3q + jb .ret + sub tmp2q, 32*32 + sub dstq, tmp4q + lea r2, [r2+tmp4q+16] + add dstq, 16 + jmp .pass2_loop +.ret: + RET +ALIGN function_align + IDCT16_MAIN .idct16, 1 + ret +ALIGN function_align +.main_fast: + mova [tmp1q+32*0], m7 + vpbroadcastd m11, [o(pw_14811x2)] + vpbroadcastd m7, [o(pw_7005x2)] + vpbroadcastd m12, [o(pw_m5520x2)] + vpbroadcastd m8, [o(pw_15426x2)] + vpbroadcastd m13, [o(pw_15893x2)] + vpbroadcastd m15, [o(pw_3981x2)] + pmulhrsw m11, m4 ; t29a + vpbroadcastd m10, [o(pw_m8423x2)] + pmulhrsw m4, m7 ; t18a + vpbroadcastd m7, [o(pw_14053x2)] + pmulhrsw m12, m3 ; t19a + vpbroadcastd m9, [o(pw_13160x2)] + pmulhrsw m3, m8 ; t28a + vpbroadcastd m8, [o(pw_9760x2)] + pmulhrsw m13, m2 ; t27a + vpbroadcastd m14, [o(pw_m2404x2)] + pmulhrsw m2, m15 ; t20a + vpbroadcastd m15, [o(pw_16207x2)] + pmulhrsw m10, m5 ; t21a + pmulhrsw m5, m7 ; t26a + pmulhrsw m9, m6 ; t25a + pmulhrsw m6, m8 ; t22a + pmulhrsw m14, m1 ; t23a + pmulhrsw m1, m15 ; t24a + vpbroadcastd m15, [o(pd_8192)] + jmp .main2 +ALIGN function_align +.main: + mova [tmp1q+32*0], m7 + mova [tmp1q-32*1], m15 + mova [tmp1q-32*2], m8 + vpbroadcastd m15, [o(pd_8192)] + ITX_MULSUB_2W 4, 11, 7, 8, 15, 7005, 14811 ; t18a, t29a + ITX_MULSUB_2W 12, 3, 7, 8, 15, 15426, 5520 ; t19a, t28a + ITX_MULSUB_2W 2, 13, 7, 8, 15, 3981, 15893 ; t20a, t27a + ITX_MULSUB_2W 10, 5, 7, 8, 15, 14053, 8423 ; t21a, t26a + ITX_MULSUB_2W 6, 9, 7, 8, 15, 9760, 13160 ; t22a, t25a + ITX_MULSUB_2W 14, 1, 7, 8, 15, 16207, 2404 ; t23a, t24a +.main2: + psubw m7, m12, m4 ; t18 + paddw m12, m4 ; t19 + psubw m4, m2, m10 ; t21 + paddw m2, m10 ; t20 + psubw m10, m14, m6 ; t22 + paddw m14, m6 ; t23 + psubw m6, m1, m9 ; t25 + paddw m1, m9 ; t24 + psubw m9, m13, m5 ; t26 + paddw m13, m5 ; t27 + psubw m5, m3, m11 ; t29 + paddw m3, m11 ; t28 + ITX_MULSUB_2W 5, 7, 8, 11, 15, m16069, 3196 ; t18a, t29a + ITX_MULSUB_2W 9, 4, 8, 11, 15, 13623, 9102 ; t21a, t26a + ITX_MULSUB_2W 6, 10, 8, 11, 15, m9102, 13623 ; t22a, t25a + psubw m8, m14, m2 ; t20a + paddw m14, m2 ; t23a + psubw m2, m1, m13 ; t27a + paddw m1, m13 ; t24a + psubw m13, m6, m9 ; t21 + paddw m6, m9 ; t22 + psubw m9, m10, m4 ; t26 + paddw m10, m4 ; t25 + ITX_MULSUB_2W 2, 8, 4, 11, 15, m15137, 6270 ; t20, t27 + ITX_MULSUB_2W 9, 13, 4, 11, 15, m15137, 6270 ; t21a, t26a + mova [tmp1q+32*1], m6 + mova [tmp1q+32*2], m14 + mova [tmp1q+32*3], m1 + mova m4, [tmp1q+32*0] ; in15 + test eobd, eobd + jl .main3_fast + mova m6, [tmp1q-32*1] ; in31 + mova m14, [tmp1q-32*2] ; in17 + ITX_MULSUB_2W 0, 6, 1, 11, 15, 804, 16364 ; t16a, t31a + ITX_MULSUB_2W 14, 4, 1, 11, 15, 12140, 11003 ; t17a, t30a + jmp .main3 +.main3_fast: + vpbroadcastd m6, [o(pw_16364x2)] + vpbroadcastd m1, [o(pw_804x2)] + vpbroadcastd m14, [o(pw_m11003x2)] + vpbroadcastd m11, [o(pw_12140x2)] + pmulhrsw m6, m0 ; t31a + pmulhrsw m0, m1 ; t16a + pmulhrsw m14, m4 ; t17a + pmulhrsw m4, m11 ; t30a +.main3: + psubw m1, m0, m14 ; t17 + paddw m0, m14 ; t16 + psubw m14, m6, m4 ; t30 + paddw m4, m6 ; t31 + ITX_MULSUB_2W 14, 1, 6, 11, 15, 3196, 16069 ; t17a, t30a + psubw m6, m0, m12 ; t19a + paddw m0, m12 ; t16a + psubw m12, m4, m3 ; t28a + paddw m4, m3 ; t31a + psubw m3, m14, m5 ; t18 + paddw m14, m5 ; t17 + psubw m5, m1, m7 ; t29 + paddw m1, m7 ; t30 + ITX_MULSUB_2W 5, 3, 7, 11, 15, 6270, 15137 ; t18a, t29a + ITX_MULSUB_2W 12, 6, 7, 11, 15, 6270, 15137 ; t19, t28 + psubw m7, m1, m10 ; t25a + paddw m1, m10 ; t30a + psubw m10, m5, m9 ; t21 + paddw m5, m9 ; t18 + psubw m9, m12, m2 ; t20a + paddw m12, m2 ; t19a + psubw m2, m3, m13 ; t26 + paddw m3, m13 ; t29 + psubw m13, m6, m8 ; t27a + paddw m6, m8 ; t28a + mova [tmp1q-32*2], m5 + mova [tmp1q-32*1], m12 + mova [tmp2q+32*0], m6 + mova [tmp2q+32*1], m3 + mova [tmp2q+32*2], m1 + mova m5, [tmp1q+32*1] ; t22 + mova m6, [tmp1q+32*2] ; t23 + mova m3, [tmp1q+32*3] ; t24a + psubw m1, m14, m5 ; t22a + paddw m14, m5 ; t17a + psubw m5, m0, m6 ; t23 + paddw m0, m6 ; t16 + psubw m6, m4, m3 ; t24 + paddw m4, m3 ; t31 + vpbroadcastd m8, [o(pw_m11585_11585)] + vpbroadcastd m3, [o(pw_11585_11585)] + mova [tmp1q-32*4], m0 + mova [tmp1q-32*3], m14 + mova [tmp2q+32*3], m4 + ITX_MULSUB_2W 13, 9, 0, 4, 15, 3, 8 ; t20, t27 + ITX_MULSUB_2W 2, 10, 0, 4, 15, 3, 8 ; t21a, t26a + ITX_MULSUB_2W 7, 1, 0, 4, 15, 3, 8 ; t22, t25 + ITX_MULSUB_2W 6, 5, 0, 4, 15, 3, 8 ; t23a, t24a + mova [tmp1q+32*0], m13 + mova [tmp1q+32*1], m2 + mova [tmp1q+32*2], m7 + mova [tmp1q+32*3], m6 + mova [tmp2q-32*4], m5 + mova [tmp2q-32*3], m1 + mova [tmp2q-32*2], m10 + mova [tmp2q-32*1], m9 + ret + +%endif diff --git a/libavcodec/x86/vp9itxfm_avx512.asm b/libavcodec/x86/vp9itxfm_avx512.asm new file mode 100644 index 000000000..d51c50756 --- /dev/null +++ b/libavcodec/x86/vp9itxfm_avx512.asm @@ -0,0 +1,1629 @@ +;****************************************************************************** +;* VP9 IDCT SIMD optimizations +;* +;* Copyright (C) 2025 Two Orioles, LLC +;* +;* 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/x86/x86util.asm" + +%if ARCH_X86_64 && HAVE_AVX512ICL_EXTERNAL + +SECTION_RODATA 64 + +dup16_perm: db 0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7 + db 8, 9, 8, 9, 10, 11, 10, 11, 12, 13, 12, 13, 14, 15, 14, 15 + db 16, 17, 16, 17, 18, 19, 18, 19, 20, 21, 20, 21, 22, 23, 22, 23 + db 24, 25, 24, 25, 26, 27, 26, 27, 28, 29, 28, 29, 30, 31, 30, 31 +itx_perm: dq 0x0000000820150440, 0x0000000231372604 + dq 0x0000000ca8041551, 0x00000006b9263715 + dq 0x00000001ec9d8c62, 0x0000000bfdbfae26 + dq 0x00000005648c9d73, 0x0000000f75aebf37 +deint_shuf: db 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 +int_shuf1: db 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15 +int_shuf2: db 8, 9, 0, 1, 10, 11, 2, 3, 12, 13, 4, 5, 14, 15, 6, 7 +pw_512: times 4 dw 512 +pw_m512: times 4 dw -512 +pw_15137_6270x2x4: times 4 dw 15137*2 + times 4 dw 6270*2 +pw_11585_m11585x2x4: times 4 dw 11585*2 +pw_m11585_11585x2x4: times 4 dw -11585*2 +pw_11585_11585x2: times 4 dw 11585*2 +int_mshift: db 142, 150, 0, 0, 174, 182, 0, 0 +pd_8192: dd 8192 +pw_804x2: times 2 dw 804*2 +pw_1606x2: times 2 dw 1606*2 +pw_3196x2: times 2 dw 3196*2 +pw_3981x2: times 2 dw 3981*2 +pw_6270x2: times 2 dw 6270*2 +pw_7005x2: times 2 dw 7005*2 +pw_7723x2: times 2 dw 7723*2 +pw_9760x2: times 2 dw 9760*2 +pw_12140x2: times 2 dw 12140*2 +pw_12665x2: times 2 dw 12665*2 +pw_13160x2: times 2 dw 13160*2 +pw_13623x2: times 2 dw 13623*2 +pw_14053x2: times 2 dw 14053*2 +pw_14449x2: times 2 dw 14449*2 +pw_14811x2: times 2 dw 14811*2 +pw_15137x2: times 2 dw 15137*2 +pw_15426x2: times 2 dw 15426*2 +pw_15679x2: times 2 dw 15679*2 +pw_15893x2: times 2 dw 15893*2 +pw_16069x2: times 2 dw 16069*2 +pw_16207x2: times 2 dw 16207*2 +pw_16305x2: times 2 dw 16305*2 +pw_16364x2: times 2 dw 16364*2 +pw_m2404x2: times 2 dw -2404*2 +pw_m4756x2: times 2 dw -4756*2 +pw_m5520x2: times 2 dw -5520*2 +pw_m8423x2: times 2 dw -8423*2 +pw_m9102x2: times 2 dw -9102*2 +pw_m10394x2: times 2 dw -10394*2 +pw_m11003x2: times 2 dw -11003*2 +pw_804_16364x2: dw 804*2, 16364*2 +pw_1606_16305x2: dw 1606*2, 16305*2 +pw_3196_16069x2: dw 3196*2, 16069*2 +pw_3981_15893x2: dw 3981*2, 15893*2 +pw_7005_14811x2: dw 7005*2, 14811*2 +pw_7723_14449x2: dw 7723*2, 14449*2 +pw_9760_13160x2: dw 9760*2, 13160*2 +pw_m2404_16207x2: dw -2404*2, 16207*2 +pw_m4756_15679x2: dw -4756*2, 15679*2 +pw_m5520_15426x2: dw -5520*2, 15426*2 +pw_m8423_14053x2: dw -8423*2, 14053*2 +pw_m9102_13623x2: dw -9102*2, 13623*2 +pw_m10394_12665x2: dw -10394*2, 12665*2 +pw_m11003_12140x2: dw -11003*2, 12140*2 + +%macro COEF_PAIR 2-3 0 +%if %3 & 4 +pw_%1_m%2: dw %1, -%2 +%else +pw_%1_%2: dw %1, %2 +%if %3 & 2 +pw_m%1_%2: dw -%1, %2 +%else +pw_m%2_%1: dw -%2, %1 +%endif +%endif +%if %3 & 1 +pw_m%1_m%2: dw -%1, -%2 +%endif +%endmacro + +COEF_PAIR 804, 16364 +COEF_PAIR 1606, 16305 +COEF_PAIR 3196, 16069, 1 +COEF_PAIR 3981, 15893 +COEF_PAIR 6270, 15137, 1 +COEF_PAIR 7005, 14811 +COEF_PAIR 7723, 14449 +COEF_PAIR 9102, 13623 +COEF_PAIR 9760, 13160 +COEF_PAIR 11585, 11585, 1 +COEF_PAIR 12140, 11003 +COEF_PAIR 12665, 10394 +COEF_PAIR 13623, 9102, 1 +COEF_PAIR 14053, 8423 +COEF_PAIR 15137, 6270 +COEF_PAIR 15426, 5520 +COEF_PAIR 15679, 4756 +COEF_PAIR 16069, 3196 +COEF_PAIR 16207, 2404 + +; ADST16-only: +COEF_PAIR 2404, 9760, 2 +COEF_PAIR 5520, 7005, 2 +COEF_PAIR 8423, 3981, 2 +COEF_PAIR 11003, 804, 2 +COEF_PAIR 12140, 16364, 5 +COEF_PAIR 14053, 15893, 5 +COEF_PAIR 15426, 14811, 5 +COEF_PAIR 16207, 13160, 5 +pw_11585_m11585: dw 11585, -11585 +pw_16069_m3196: dw 16069, -3196 +pw_9102_m13623: dw 9102, -13623 +pw_15137_m6270: dw 15137, -6270 +pw_6270_m15137: dw 6270, -15137 + +%define pw_11585x2 pw_11585_11585x2 +%define pw_m11585x2 pw_m11585_11585x2x4 + +SECTION .text + +%define o_base pw_512 + 128 +%define o(x) (r6 - (o_base) + (x)) +%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX) + +; flags: 1 = swap, 2 = interleave (l), 4 = interleave (t), 8 = no_pack, +; 16 = special_mul1, 32 = special_mul2, 64 = dst_in_tmp1 +%macro ITX_MUL2X_PACK 6-7 0 ; dst/src, tmp[1-2], rnd, coef[1-2], flags + mova m%2, m%4 +%if %7 & 16 + vpdpwssd m%2, m%1, [o(pw_%5)] {bcstd} + mova m%3, m%4 +%if %7 & 32 + vpdpwssd m%3, m%1, [o(pw_%6)] {bcstd} +%else + vpdpwssd m%3, m%1, m%6 +%endif +%elif %7 & 32 + vpdpwssd m%2, m%1, m%5 + mova m%3, m%4 + vpdpwssd m%3, m%1, [o(pw_%6)] {bcstd} +%elif %6 < 32 + vpdpwssd m%2, m%1, m%5 + mova m%3, m%4 + vpdpwssd m%3, m%1, m%6 +%elif %7 & 1 + vpdpwssd m%2, m%1, [o(pw_%5_%6)] {bcstd} + mova m%3, m%4 + vpdpwssd m%3, m%1, [o(pw_m%6_%5)] {bcstd} +%else + vpdpwssd m%2, m%1, [o(pw_m%6_%5)] {bcstd} + mova m%3, m%4 + vpdpwssd m%3, m%1, [o(pw_%5_%6)] {bcstd} +%endif +%if %7 & 2 + psrld m%2, 14 + pslld m%3, 2 + vpshrdd m%1, m%3, m%2, 16 +%elif %7 & 4 + ; compared to using shifts (as above) this has better throughput, + ; but worse latency and requires setting up the opmask/index + ; registers, so only use this method for the larger transforms +%if %7 & 64 + pslld m%2, 2 + vpmultishiftqb m%2{k7}, m13, m%3 +%else + pslld m%1, m%2, 2 + vpmultishiftqb m%1{k7}, m13, m%3 +%endif +%else + psrad m%2, 14 + psrad m%3, 14 +%if %7 & 8 == 0 + packssdw m%1, m%3, m%2 +%endif +%endif +%endmacro + +; dst1 = (src1 * coef1 - src2 * coef2 + rnd) >> 12 +; dst2 = (src1 * coef2 + src2 * coef1 + rnd) >> 12 +%macro ITX_MULSUB_2W 7 ; dst/src[1-2], tmp[1-2], rnd, coef[1-2] + punpcklwd m%3, m%2, m%1 + punpckhwd m%2, m%1 +%if %7 < 32 + mova m%1, m%5 + vpdpwssd m%1, m%3, m%7 + mova m%4, m%5 + vpdpwssd m%4, m%2, m%7 +%else + mova m%1, m%5 + vpdpwssd m%1, m%3, [o(pw_m%7_%6)] {bcstd} + mova m%4, m%5 + vpdpwssd m%4, m%2, [o(pw_m%7_%6)] {bcstd} +%endif + psrad m%1, 14 + psrad m%4, 14 + packssdw m%1, m%4 + mova m%4, m%5 +%if %7 < 32 + vpdpwssd m%4, m%2, m%6 + mova m%2, m%5 + vpdpwssd m%2, m%3, m%6 +%else + vpdpwssd m%4, m%2, [o(pw_%6_%7)] {bcstd} + mova m%2, m%5 + vpdpwssd m%2, m%3, [o(pw_%6_%7)] {bcstd} +%endif + psrad m%4, 14 + psrad m%2, 14 + packssdw m%2, m%4 +%endmacro + +; flags: 1 = swap, 2 = invert2, 4 = invert1 +%macro ADST_MULSUB_4W 10-11 0 ; dst1/src1, src2, dst2, tmp[1-2], rnd, coef[1-4], flags + mova m%3, m%6 +%if %11 & 1 + vpdpwssd m%3, m%1, [o(pw_m%8_%7)] {bcstd} +%else + vpdpwssd m%3, m%1, [o(pw_%7_%8)] {bcstd} +%endif +%if %11 & 4 + vpbroadcastd m%4, [o(pw_m%9_%10)] +%elif %11 & 2 + vpbroadcastd m%4, [o(pw_%9_m%10)] +%elif %11 & 1 + vpbroadcastd m%4, [o(pw_%10_%9)] +%else + vpbroadcastd m%4, [o(pw_%9_%10)] +%endif + pmaddwd m%4, m%2 + mova m%5, m%6 +%if %11 & 4 + vpdpwssd m%5, m%1, [o(pw_%8_m%7)] {bcstd} +%elif %11 & 1 + vpdpwssd m%5, m%1, [o(pw_%7_%8)] {bcstd} +%else + vpdpwssd m%5, m%1, [o(pw_m%8_%7)] {bcstd} +%endif +%if %11 & 2 + vpbroadcastd m%1, [o(pw_%10_%9)] +%elif %11 & 1 + vpbroadcastd m%1, [o(pw_%9_m%10)] +%else + vpbroadcastd m%1, [o(pw_m%10_%9)] +%endif + pmaddwd m%2, m%1 + paddd m%1, m%3, m%4 + psubd m%3, m%4 + paddd m%4, m%5, m%2 + psubd m%5, m%2 + pslld m%1, 2 + pslld m%3, 2 + vpmultishiftqb m%1{k7}, m13, m%4 + vpmultishiftqb m%3{k7}, m13, m%5 +%endmacro + +%macro WRAP_YMM 1+ + INIT_YMM cpuname + %1 + INIT_ZMM cpuname +%endmacro + +%macro INV_TXFM_FN 3-4 0 ; type1, type2, size, eob_offset +cglobal vp9_i%1_i%2_%3_add, 4, 5, 0, dst, stride, c, eob, tx2 + %undef cmp + %define %%p1 m(vp9_i%1_%3_internal) + lea r6, [o_base] + ; Jump to the 1st txfm function if we're not taking the fast path, which + ; in turn performs an indirect jump to the 2nd txfm function. + lea tx2q, [m(vp9_i%2_%3_internal).pass2] +%ifidn %1_%2, dct_dct + cmp eobd, 1 + jne %%p1 +%else +%if %4 + add eobd, %4 +%endif + ; jump to the 1st txfm function unless it's located directly after this + times ((%%end - %%p1) >> 31) & 1 jmp %%p1 +ALIGN function_align +%%end: +%endif +%endmacro + +%macro INV_TXFM_16X16_FN 2-3 0 ; type1, type2, eob_offset + INV_TXFM_FN %1, %2, 16x16, %3 +%ifidn %1_%2, dct_dct + movd xmm0, [o(pw_11585x2)] + pmulhrsw xmm3, xmm0, [cq] + pxor ym2, ym2 + pmulhrsw xmm3, xmm0 + pmulhrsw xmm3, [o(pw_512)] + mova [cq], xm2 + add r3d, 7 + vpbroadcastw ym3, xmm3 +.dconly_loop: + mova xm1, [dstq+strideq*0] + vinserti32x4 ym1, [dstq+strideq*1], 1 + punpcklbw ym0, ym1, ym2 + punpckhbw ym1, ym2 + paddw ym0, ym3 + paddw ym1, ym3 + packuswb ym0, ym1 + mova [dstq+strideq*0], xm0 + vextracti32x4 [dstq+strideq*1], ym0, 1 + lea dstq, [dstq+strideq*2] + dec r3d + jg .dconly_loop + RET +%endif +%endmacro + +%macro IDCT16_MAIN 0-1 0 ; idct32 +%if mmsize == 64 && %1 == 0 +.main_fast: +%endif + vpbroadcastd m2, [o(pw_1606_16305x2)] + vpbroadcastd m4, [o(pw_m10394_12665x2)] + vpbroadcastd m11, [o(pw_7723_14449x2)] + vpbroadcastd m12, [o(pw_m4756_15679x2)] + pmulhrsw m8, m2 ; t8a t15a + vpbroadcastd m2, [o(pw_3196_16069x2)] + pmulhrsw m0, m4 ; t9a t14a + vpbroadcastd m4, [o(pw_m9102_13623x2)] + pmulhrsw m5, m11 ; t10a t13a + vpbroadcastd m11, [o(pw_11585_11585x2)] + pmulhrsw m1, m12 ; t11a t12a + vbroadcasti32x4 m12, [o(pw_15137_6270x2x4)] + pmulhrsw m7, m2 ; t4a t7a + pmulhrsw m3, m4 ; t5a t6a + pmulhrsw m9, m11 ; t0 t1 + pmulhrsw m6, m12 ; t3 t2 +%if mmsize == 64 && %1 == 0 + jmp %%main2 +ALIGN function_align +.main: + punpckhwd m8, m7, m0 ; dct16 in15 in1 + punpcklwd m9, m4, m0 ; dct4 in2 in0 + punpckhwd m0, m3, m4 ; dct16 in7 in9 + punpcklwd m7, m1 ; dct8 in7 in1 + punpckhwd m1, m6 ; dct16 in3 in13 + punpcklwd m3, m5 ; dct8 in3 in5 + punpckhwd m5, m2 ; dct16 in11 in5 + punpcklwd m6, m2 ; dct4 in3 in1 + ITX_MUL2X_PACK 8, 2, 4, 10, 1606, 16305, 5 ; t8a t15a + ITX_MUL2X_PACK 0, 2, 4, 10, 12665, 10394, 5 ; t9a t14a + ITX_MUL2X_PACK 5, 2, 4, 10, 7723, 14449, 5 ; t10a t13a + ITX_MUL2X_PACK 1, 2, 4, 10, 15679, 4756, 5 ; t11a t12a + ITX_MUL2X_PACK 7, 2, 4, 10, 3196, 16069, 5 ; t4a t7a + ITX_MUL2X_PACK 3, 2, 4, 10, 13623, 9102, 5 ; t5a t6a + ITX_MUL2X_PACK 9, 2, 4, 10, 11585, 11585 ; t0 t1 + ITX_MUL2X_PACK 6, 2, 4, 10, 6270, 15137 ; t3 t2 +%%main2: +%endif + psubw m2, m8, m0 ; t9 t14 + paddw m8, m0 ; t8 t15 + psubw m4, m1, m5 ; t10 t13 + paddw m1, m5 ; t11 t12 + ITX_MUL2X_PACK 2, 0, 5, 10, 6270, 15137, (1|%1*4) ; t9a t14a + ITX_MUL2X_PACK 4, 0, 5, 10, m15137, 6270, (1|%1*4) ; t10a t13a + vbroadcasti32x4 m5, [o(deint_shuf)] + psubw m0, m8, m1 ; t11a t12a + paddw m8, m1 ; t8a t15a + psubw m1, m7, m3 ; t5a t6a + paddw m7, m3 ; t4 t7 + pshufb m8, m5 + pshufb m7, m5 + paddw m3, m2, m4 ; t9 t14 + psubw m2, m4 ; t10 t13 +%if %1 + vpbroadcastd m12, [o(pw_11585_11585)] + vpbroadcastd m11, [o(pw_m11585_11585)] + pshufb m3, m5 + ITX_MUL2X_PACK 1, 4, 5, 10, 12, 11 ; t5 t6 + ITX_MUL2X_PACK 0, 4, 5, 10, 11, 12, 8 ; t11 t12 + ITX_MUL2X_PACK 2, 0, 11, 10, 11, 12, 8 ; t10a t13a + packssdw m5, m11 ; t12 t13a + packssdw m4, m0 ; t11 t10a +%else + pshufb m0, m5 + ITX_MUL2X_PACK 1, 4, 5, 10, 11585_11585, m11585_11585, 48 ; t5 t6 + vpbroadcastd m11, [o(pw_11585x2)] + punpckhqdq m5, m0, m2 ; t12a t13 + punpcklqdq m0, m2 ; t11a t10 + psubw m4, m5, m0 + paddw m5, m0 + pmulhrsw m4, m11 ; t11 t10a + pmulhrsw m5, m11 ; t12 t13a +%endif + punpckhqdq m2, m7, m1 ; t7 t6 + punpcklqdq m7, m1 ; t4 t5 + psubw m1, m9, m6 ; t3 t2 + paddw m9, m6 ; t0 t1 + punpckhqdq m0, m8, m3 ; t15a t14 + punpcklqdq m8, m3 ; t8a t9 + psubw m3, m9, m2 ; t7 t6 + paddw m9, m2 ; t0 t1 + psubw m2, m1, m7 ; t4 t5 + paddw m1, m7 ; t3 t2 + psubw m7, m9, m0 ; out15 out14 + paddw m0, m9 ; out0 out1 + psubw m6, m1, m5 ; out12 out13 + paddw m1, m5 ; out3 out2 + psubw m5, m2, m4 ; out11 out10 + paddw m2, m4 ; out4 out5 + psubw m4, m3, m8 ; out8 out9 + paddw m3, m8 ; out7 out6 +%endmacro + +INIT_ZMM avx512icl +INV_TXFM_16X16_FN dct, dct +INV_TXFM_16X16_FN dct, adst, 39-23 + +cglobal vp9_idct_16x16_internal, 0, 5, 16, dst, stride, c, eob, tx2 + mova m15, [o(itx_perm)] + vpbroadcastd m10, [o(pd_8192)] + vpbroadcastq m13, [o(int_mshift)] + vpcmpub k7, m13, m10, 6 + sub eobd, 39 + jl .pass1_fast + vpermq m0, m15, [cq+64*0] + vpermq m1, m15, [cq+64*1] + vpermq m2, m15, [cq+64*2] + vpermq m3, m15, [cq+64*3] + vpermq m4, m15, [cq+64*4] + vpermq m5, m15, [cq+64*5] + vpermq m6, m15, [cq+64*6] + vpermq m7, m15, [cq+64*7] + call .main + vbroadcasti32x4 m12, [o(int_shuf1)] + vbroadcasti32x4 m11, [o(int_shuf2)] + pshufb m0, m12 + pshufb m8, m1, m11 + pshufb m2, m12 + pshufb m9, m3, m11 + pshufb m4, m12 + pshufb m14, m5, m11 + pshufb m6, m12 + pshufb m11, m7, m11 + punpckhdq m1, m0, m8 + punpckldq m0, m8 + punpckhdq m3, m2, m9 + punpckldq m2, m9 + punpckhdq m5, m4, m14 + punpckldq m4, m14 + punpckhdq m7, m6, m11 + punpckldq m6, m11 +.pass1_end: + vshufi32x4 m8, m4, m6, q3232 + vinserti32x8 m4, ym6, 1 + vshufi32x4 m6, m0, m2, q3232 + vinserti32x8 m0, ym2, 1 + vshufi32x4 m9, m5, m7, q3232 + vinserti32x8 m5, ym7, 1 + vshufi32x4 m7, m1, m3, q3232 + vinserti32x8 m1, ym3, 1 + vshufi32x4 m2, m0, m4, q3131 ; 4 5 + vshufi32x4 m0, m4, q2020 ; 0 1 + vshufi32x4 m4, m6, m8, q2020 ; 8 9 + vshufi32x4 m6, m8, q3131 ; 12 13 + vshufi32x4 m3, m1, m5, q3131 ; 6 7 + vshufi32x4 m1, m5, q2020 ; 2 3 + vshufi32x4 m5, m7, m9, q2020 ; 10 11 + vshufi32x4 m7, m9, q3131 ; 14 1 + jmp tx2q +.pass1_fast: + mova ym3, [o(dup16_perm)] + vbroadcasti32x4 ym9, [cq+32*0] + vbroadcasti32x4 ym6, [cq+32*4] + vpermb ym8, ym3, [cq+32*1] + vpermb ym0, ym3, [cq+32*7] + vpermb ym5, ym3, [cq+32*5] + vpermb ym1, ym3, [cq+32*3] + vpermb ym7, ym3, [cq+32*2] + vpermb ym3, ym3, [cq+32*6] + shufpd ym9, ym9, 0x0c + shufpd ym6, ym6, 0x0c + WRAP_YMM IDCT16_MAIN + vbroadcasti32x4 m8, [o(int_shuf1)] + vbroadcasti32x4 m9, [o(int_shuf2)] + vinserti32x8 m0, ym2, 1 ; 0 1 | 4 5 + vinserti32x8 m4, ym6, 1 ; 8 9 | 12 13 + vinserti32x8 m1, ym3, 1 ; 3 2 | 7 6 + vinserti32x8 m5, ym7, 1 ; 11 10 | 15 14 + vshufi32x4 m2, m0, m4, q3131 + vshufi32x4 m0, m4, q2020 + vshufi32x4 m4, m1, m5, q2020 + vshufi32x4 m1, m5, q3131 + pshufb m2, m8 + pshufb m0, m8 + pshufb m4, m9 + pshufb m1, m9 + punpckhdq m3, m2, m1 ; 6-7 + punpckldq m2, m1 ; 4-5 + punpckhdq m1, m0, m4 ; 2-3 + punpckldq m0, m4 ; 0-1 + jmp tx2q +.pass2: + test eobd, eobd + jl .pass2_fast + call .main + jmp .pass2_end +.pass2_fast: + punpcklqdq m9, m0, m0 + punpckhwd m8, m0, m0 + punpcklwd m7, m1, m1 + punpckhwd m1, m1 + punpcklqdq m6, m2, m2 + punpckhwd m5, m2, m2 + punpckhwd m0, m3, m3 + punpcklwd m3, m3 + call .main_fast +.pass2_end: + psrldq m8, m15, 1 + psrlq m12, m15, 12 + psrldq m9, m15, 2 + psrlq m13, m15, 20 + mova m10, m8 + vpermi2q m8, m0, m2 ; 0 1 4 5 + vpermt2q m0, m12, m2 + mova m11, m9 + vpermi2q m9, m1, m3 ; 2 3 6 7 + vpermt2q m1, m13, m3 + vpbroadcastd m2, [o(pw_512)] + vpermi2q m10, m4, m6 ; 8 9 12 13 + vpermt2q m4, m12, m6 + vpermi2q m11, m5, m7 ; 10 11 14 15 + vpermt2q m5, m13, m7 + REPX {pmulhrsw x, m2}, m0, m1, m4, m5, m8, m9, m10, m11 +.pass2_end2: + lea r3, [strideq*3] + lea r4, [dstq+strideq*4] + lea r5, [dstq+strideq*8] + lea r6, [r4 +strideq*8] + mova xm3, [dstq+strideq*0] + mova xm6, [dstq+strideq*2] + vinserti32x4 ym3, [dstq+strideq*1], 1 + vinserti32x4 ym6, [dstq+r3 ], 1 + vinserti32x4 m3, [r4+strideq*0], 2 + vinserti32x4 m6, [r4+strideq*2], 2 + vinserti32x4 m3, [r4+strideq*1], 3 + vinserti32x4 m6, [r4+r3 ], 3 + mova xm12, [r5+strideq*0] + mova xm13, [r5+strideq*2] + vinserti32x4 ym12, [r5+strideq*1], 1 + vinserti32x4 ym13, [r5+r3 ], 1 + vinserti32x4 m12, [r6+strideq*0], 2 + vinserti32x4 m13, [r6+strideq*2], 2 + vinserti32x4 m12, [r6+strideq*1], 3 + vinserti32x4 m13, [r6+r3 ], 3 + pxor m7, m7 + REPX {mova [cq+64*x], m7}, 0, 1, 2, 3, 4, 5, 6, 7 + punpcklbw m2, m3, m7 + punpckhbw m3, m7 + paddw m0, m2 + paddw m8, m3 + packuswb m0, m8 + punpcklbw m2, m6, m7 + punpckhbw m6, m7 + paddw m1, m2 + paddw m9, m6 + packuswb m1, m9 + punpcklbw m2, m12, m7 + punpckhbw m12, m7 + paddw m2, m4 + paddw m10, m12 + packuswb m2, m10 + punpcklbw m3, m13, m7 + punpckhbw m13, m7 + paddw m3, m5 + paddw m11, m13 + packuswb m3, m11 + mova [dstq+strideq*0], xm0 + vextracti32x4 [dstq+strideq*1], ym0, 1 + mova [dstq+strideq*2], xm1 + vextracti32x4 [dstq+r3 ], ym1, 1 + vextracti32x4 [r4+strideq*0], m0, 2 + vextracti32x4 [r4+strideq*1], m0, 3 + vextracti32x4 [r4+strideq*2], m1, 2 + vextracti32x4 [r4+r3 ], m1, 3 + mova [r5+strideq*0], xm2 + vextracti32x4 [r5+strideq*1], ym2, 1 + mova [r5+strideq*2], xm3 + vextracti32x4 [r5+r3 ], ym3, 1 + vextracti32x4 [r6+strideq*0], m2, 2 + vextracti32x4 [r6+strideq*1], m2, 3 + vextracti32x4 [r6+strideq*2], m3, 2 + vextracti32x4 [r6+r3 ], m3, 3 + RET +ALIGN function_align + IDCT16_MAIN + ret + +%macro IADST16_MAIN 0 +%if mmsize == 64 +.main_fast: +%endif + punpcklwd m4, m3, m0 ; in7 in0 + punpcklwd m11, m1, m2 ; in3 in4 + punpckhwd m9, m2, m1 ; in5 in2 + punpckhwd m7, m0, m3 ; in1 in6 + ITX_MUL2X_PACK 4, 0, 6, 10, 11003_804, 12140_m16364, 116 ; t1a t0a + ITX_MUL2X_PACK 4, 5, 6, 10, m11003_804, m12140_m16364, 52 ; t9a t8a + ITX_MUL2X_PACK 11, 2, 6, 10, 5520_7005, 15426_m14811, 116 ; t5a t4a + ITX_MUL2X_PACK 11, 5, 6, 10, m5520_7005, m15426_m14811, 52 ; t13a t12a + ITX_MUL2X_PACK 9, 1, 6, 10, 8423_3981, 14053_m15893, 116 ; t3a t2a + ITX_MUL2X_PACK 9, 5, 6, 10, m8423_3981, m14053_m15893, 52 ; t11a t10a + ITX_MUL2X_PACK 7, 3, 6, 10, 2404_9760, 16207_m13160, 116 ; t7a t6a + ITX_MUL2X_PACK 7, 5, 6, 10, m2404_9760, m16207_m13160, 52 ; t15a t14a +%if mmsize == 64 ; for the ymm variant we only ever use the fast path + jmp %%main2 +ALIGN function_align +.main: + punpckhwd m8, m7, m0 ; in14 in1 + punpcklwd m0, m7 ; in0 in15 + punpcklwd m7, m6, m1 ; in12 in3 + punpckhwd m1, m6 ; in2 in13 + punpckhwd m6, m5, m2 ; in10 in5 + punpcklwd m2, m5 ; in4 in11 + punpcklwd m5, m4, m3 ; in8 in7 + punpckhwd m3, m4 ; in6 in9 + ADST_MULSUB_4W 0, 5, 4, 9, 11, 10, 804, 16364, 12140, 11003 ; t1a t0a, t9a t8a + ADST_MULSUB_4W 2, 7, 11, 5, 9, 10, 7005, 14811, 15426, 5520 ; t5a t4a, t13a t12a + ADST_MULSUB_4W 1, 6, 9, 5, 7, 10, 3981, 15893, 14053, 8423 ; t3a t2a, t11a t10a + ADST_MULSUB_4W 3, 8, 7, 5, 6, 10, 9760, 13160, 16207, 2404 ; t7a t6a, t15a t14a +%%main2: +%endif + psubw m5, m1, m3 ; t7 t6 + paddw m6, m1, m3 ; t3 t2 + psubw m1, m0, m2 ; t5 t4 + paddw m2, m0 ; t1 t0 + ADST_MULSUB_4W 4, 11, 8, 3, 0, 10, 3196, 16069, 16069, 3196, 1 ; t8a t9a, t12a t13a + ADST_MULSUB_4W 9, 7, 0, 3, 11, 10, 13623, 9102, 9102, 13623, 1 ; t10a t11a, t14a t15a + ADST_MULSUB_4W 1, 5, 11, 3, 7, 10, 6270, 15137, 15137, 6270, 2 ; out12 -out3, t7 t6 + psubw m3, m2, m6 ; t3a t2a + paddw m2, m6 ; -out15 out0 + ADST_MULSUB_4W 8, 0, 5, 6, 7, 10, 15137, 6270, 6270, 15137, 6 ; -out13 out2, t15a t14 + vbroadcasti32x4 m12, [o(deint_shuf)] + paddw m0, m4, m9 ; -out1 out14 + psubw m4, m9 ; t10 t11 + pshufb m2, m12 + pshufb m1, m12 + pshufb m8, m12 + pshufb m0, m12 + punpcklqdq m6, m1, m8 ; out12 -out13 + shufps m7, m0, m2, q1032 ; out14 -out15 +%endmacro + +%macro IADST16_PASS1_END 0 + shufps m0, m2, m0, q1032 ; out0 -out1 + punpckhqdq m1, m8, m1 ; out2 -out3 + mova m2, m10 + vpdpwssd m2, m5, [o(pw_m11585_m11585)] {bcstd} ; out5 + mova m8, m10 + vpdpwssd m8, m11, [o(pw_11585_11585)] {bcstd} ; out4 + mova m9, m10 + vpdpwssd m9, m5, [o(pw_m11585_11585)] {bcstd} ; out10 + mova m5, m10 + vpdpwssd m5, m11, [o(pw_11585_m11585)] {bcstd} ; out11 + mova m11, m10 + vpdpwssd m11, m3, [o(pw_m11585_m11585)] {bcstd} ; out7 + mova m14, m10 + vpdpwssd m14, m4, [o(pw_11585_11585)] {bcstd} ; out6 + mova m12, m10 + vpdpwssd m12, m3, [o(pw_m11585_11585)] {bcstd} ; out8 + mova m3, m10 + vpdpwssd m3, m4, [o(pw_m11585_11585)] {bcstd} ; out9 +%endmacro + +INV_TXFM_16X16_FN adst, dct, 39-18 +INV_TXFM_16X16_FN adst, adst + +cglobal vp9_iadst_16x16_internal, 0, 5, 16, dst, stride, c, eob, tx2 + mova m15, [o(itx_perm)] + psrlq m7, m15, 4 + vpermq m0, m15, [cq+64*0] ; 0 1 + vpermq m1, m7, [cq+64*1] ; 3 2 + vpermq m2, m15, [cq+64*2] ; 4 5 + vpermq m3, m7, [cq+64*3] ; 7 6 + vpbroadcastd m10, [o(pd_8192)] + vpbroadcastq m13, [o(int_mshift)] + vpcmpub k7, m13, m10, 6 + sub eobd, 39 + jl .pass1_fast + vpermq m4, m15, [cq+64*4] ; 8 9 + vpermq m5, m7, [cq+64*5] ; 11 10 + vpermq m6, m15, [cq+64*6] ; 12 13 + vpermq m7, m7, [cq+64*7] ; 15 14 + call .main + IADST16_PASS1_END + REPX {psrad x, 14}, m2, m8, m9, m5, m11, m14, m12, m3 + packssdw m2, m8, m2 ; out4 out5 + packssdw m5, m9, m5 ; out10 out11 + packssdw m4, m12, m3 ; out8 out9 + packssdw m3, m14, m11 ; out6 out7 + pxor m9, m9 + punpckhwd m8, m0, m1 + punpcklwd m0, m1 + psubw m8, m9, m8 + punpckhwd m1, m0, m8 + punpcklwd m0, m8 + punpckhwd m8, m2, m3 + punpcklwd m2, m3 + punpckhwd m3, m2, m8 + punpcklwd m2, m8 + punpckhwd m8, m4, m5 + punpcklwd m4, m5 + punpckhwd m5, m4, m8 + punpcklwd m4, m8 + punpckhwd m8, m6, m7 + punpcklwd m6, m7 + psubw m8, m9, m8 + punpckhwd m7, m6, m8 + punpcklwd m6, m8 + jmp m(vp9_idct_16x16_internal).pass1_end +.pass1_fast: + WRAP_YMM IADST16_MAIN + WRAP_YMM IADST16_PASS1_END + vinserti32x8 m0, ym6, 1 + vinserti32x8 m1, ym7, 1 + vinserti32x8 m8, ym12, 1 + vinserti32x8 m2, ym3, 1 + vinserti32x8 m14, ym9, 1 + vinserti32x8 m11, ym5, 1 + pslld m14, 2 + pslld m11, 2 + punpckhwd m4, m0, m1 + punpcklwd m0, m1 + vpmultishiftqb m14{k7}, m13, m8 + vpmultishiftqb m11{k7}, m13, m2 + psrlq m1, m15, 24 + pxor m2, m2 + psubw m2, m4 + punpckhwd m3, m0, m2 + punpcklwd m0, m2 + psrlq m2, m15, 28 + punpckhwd m4, m14, m11 + punpcklwd m14, m11 + mova m5, m2 + vpermi2q m2, m0, m14 + vpermt2q m0, m1, m14 + vpermi2q m1, m3, m4 + vpermt2q m3, m5, m4 + jmp tx2q +.pass2: + pshufd m1, m1, q1032 + pshufd m3, m3, q1032 + test eobd, eobd + jl .pass2_fast + pshufd m5, m5, q1032 + pshufd m7, m7, q1032 + call .main + jmp .pass2_end +.pass2_fast: + call .main_fast +.pass2_end: + vbroadcasti32x4 m9, [o(pw_11585_m11585x2x4)] + vbroadcasti32x4 m10, [o(pw_m11585_11585x2x4)] + punpckhqdq m1, m8 ; -out3 out2 + shufps m0, m2, q3210 ; -out1 out0 + pshufb m2, m11, m12 + pshufb m5, m12 + pshufb m3, m12 + pshufb m4, m12 + vbroadcasti32x4 m11, [o(pw_512)] + vpbroadcastd m12, [o(pw_512)] + punpcklqdq m8, m5, m2 ; t15a t7 + punpckhqdq m5, m2 ; t14a t6 + shufps m2, m3, m4, q1032 ; t2a t10 + shufps m3, m4, q3210 ; t3a t11 + psubsw m4, m2, m3 + paddsw m3, m2 + paddsw m2, m5, m8 + psubsw m5, m8 + pmulhrsw m4, m9 ; out8 out9 + pmulhrsw m3, m10 ; out7 out6 + pmulhrsw m2, m10 ; out5 out4 + pmulhrsw m5, m9 ; out10 out11 + pmulhrsw m6, m11 + pmulhrsw m7, m11 + pshufd m11, m11, q1032 + pmulhrsw m0, m11 + pmulhrsw m1, m11 + REPX {pmulhrsw x, m12}, m2, m3, m4, m5 + psrldq m8, m15, 2 + psrlq m12, m15, 20 + psrldq m10, m15, 1 + psrlq m13, m15, 12 + mova m9, m8 + vpermi2q m8, m0, m2 ; 0 1 4 5 + vpermt2q m0, m12, m2 + vpermi2q m9, m1, m3 ; 2 3 6 7 + vpermt2q m1, m12, m3 + mova m11, m10 + vpermi2q m10, m4, m6 ; 8 9 12 13 + vpermt2q m4, m13, m6 + vpermi2q m11, m5, m7 ; 10 11 14 15 + vpermt2q m5, m13, m7 + jmp m(vp9_idct_16x16_internal).pass2_end2 +ALIGN function_align + IADST16_MAIN + ret + +%macro IDCT_32x32_END 4 ; src, mem, stride[1-2] + pmovzxbw m10, [dstq+%3] + pmovzxbw m11, [r3 +%4] +%if %2 < 8 + paddw m8, m%2, m%1 + psubw m9, m%2, m%1 +%else + mova m9, [rsp+64*(%2-8)] + paddw m8, m9, m%1 + psubw m9, m%1 +%endif + pmulhrsw m8, m12 + pmulhrsw m9, m12 + paddw m8, m10 + paddw m9, m11 + packuswb m8, m9 + vpermq m8, m13, m8 + mova [dstq+%3], ym8 + vextracti32x8 [r3 +%4], m8, 1 +%if %2 == 3 || %2 == 7 || %2 == 11 + add dstq, r5 + sub r3, r5 +%endif +%endmacro + +cglobal vp9_idct_idct_32x32_add, 4, 7, 0, dst, stride, c, eob +%undef cmp + lea r6, [o_base] + cmp eobd, 1 + jne .pass1 + movd xmm0, [o(pw_11585x2)] + pmulhrsw xmm3, xmm0, [cq] + pxor m2, m2 + pmulhrsw xmm3, xmm0 + pmulhrsw xmm3, [o(pw_512)] + movd [cq], xm2 + add r3d, 15 + vpbroadcastw m3, xmm3 +.dconly_loop: + mova ym1, [dstq+strideq*0] + vinserti32x8 m1, [dstq+strideq*1], 1 + punpcklbw m0, m1, m2 + punpckhbw m1, m2 + paddw m0, m3 + paddw m1, m3 + packuswb m0, m1 + mova [dstq+strideq*0], ym0 + vextracti32x8 [dstq+strideq*1], m0, 1 + lea dstq, [dstq+strideq*2] + dec r3d + jg .dconly_loop + RET +.pass1: + PROLOGUE 0, 7, 30, 64*16, dst, stride, c, eob + sub eobd, 135 + jl .fast + mova m0, [cq+64* 0] + mova m14, [cq+64* 2] + mova m1, [cq+64* 4] + mova m15, [cq+64* 6] + mova m2, [cq+64* 8] + mova m16, [cq+64*10] + mova m3, [cq+64*12] + mova m17, [cq+64*14] + mova m4, [cq+64*16] + mova m18, [cq+64*18] + mova m5, [cq+64*20] + mova m19, [cq+64*22] + mova m6, [cq+64*24] + mova m20, [cq+64*26] + mova m7, [cq+64*28] + mova m21, [cq+64*30] + call .idct16 + mova [rsp+64*0], m14 + mova [rsp+64*1], m15 + mova [rsp+64*2], m16 + mova [rsp+64*3], m17 + mova [rsp+64*4], m18 + mova [rsp+64*5], m19 + mova [rsp+64*6], m20 + mova [rsp+64*7], m21 + mova m22, [cq+64* 1] + mova m23, [cq+64* 3] + mova m24, [cq+64* 5] + mova m25, [cq+64* 7] + mova m26, [cq+64* 9] + mova m27, [cq+64*11] + mova m28, [cq+64*13] + mova m29, [cq+64*15] + mova m14, [cq+64*17] + mova m15, [cq+64*19] + mova m16, [cq+64*21] + mova m17, [cq+64*23] + mova m18, [cq+64*25] + mova m19, [cq+64*27] + mova m20, [cq+64*29] + mova m21, [cq+64*31] + call .main + psubw m13, m0, m29 ; 31 + paddw m0, m29 ; 0 + psubw m29, m1, m28 ; 30 + paddw m1, m28 ; 1 + psubw m28, m2, m27 ; 29 + paddw m2, m27 ; 2 + psubw m27, m3, m26 ; 28 + paddw m3, m26 ; 3 + psubw m26, m4, m25 ; 27 + paddw m4, m25 ; 4 + psubw m25, m5, m24 ; 26 + paddw m5, m24 ; 5 + psubw m24, m6, m23 ; 25 + paddw m6, m23 ; 6 + psubw m23, m7, m22 ; 24 + paddw m7, m22 ; 7 + punpckhwd m8, m0, m1 ; a4 b4 a5 b5 a6 b6 a7 b7 + punpcklwd m0, m1 ; a0 b0 a1 b1 a2 b2 a3 b3 + punpckhwd m1, m2, m3 ; c4 d4 c5 d5 c6 d6 c7 d7 + punpcklwd m2, m3 ; c0 d0 c1 d1 c2 d2 c3 d3 + punpckhwd m22, m4, m5 ; e4 f4 e5 f5 e6 f6 e7 f7 + punpcklwd m4, m5 ; e0 f0 e1 f1 e2 f2 e3 f3 + punpckhwd m5, m6, m7 ; g4 h4 g5 h5 g6 h6 g7 h7 + punpcklwd m6, m7 ; g0 h0 g1 h1 g2 h2 g3 h3 + punpckhwd m3, m23, m24 + punpcklwd m23, m24 + punpckhwd m24, m25, m26 + punpcklwd m25, m26 + punpckhwd m26, m27, m28 + punpcklwd m27, m28 + punpckhwd m28, m29, m13 + punpcklwd m29, m13 + punpckhdq m7, m0, m2 ; a2 b2 c2 d2 a3 b3 c3 d3 + punpckldq m0, m2 ; a0 b0 c0 d0 a1 b1 c1 d1 + punpckhdq m2, m4, m6 ; e2 f2 g2 h2 e3 f3 g3 h3 + punpckldq m4, m6 ; e0 f0 g0 h0 e1 f1 g1 h1 + punpckhdq m6, m8, m1 ; a6 b6 c6 d6 a7 b7 c7 d7 + punpckldq m8, m1 ; a4 b4 c4 d4 a5 b5 c5 d5 + punpckhdq m1, m22, m5 ; e6 f6 g6 h6 e7 f7 g7 h7 + punpckldq m22, m5 ; e4 f4 g4 h5 e5 f5 g5 h5 + punpckhdq m13, m23, m25 + punpckldq m23, m25 + punpckhdq m25, m27, m29 + punpckldq m27, m29 + punpckhdq m9, m3, m24 + punpckldq m3, m24 + punpckhdq m24, m26, m28 + punpckldq m26, m28 + punpcklqdq m5, m23, m27 ; d00 d08 d16 d24 + punpckhqdq m23, m27 ; d01 d09 d17 d25 + punpckhqdq m27, m13, m25 ; d03 d11 d19 d27 + punpcklqdq m13, m25 ; d02 d10 d18 d26 + punpckhqdq m25, m3, m26 ; d05 d13 d21 d29 + punpcklqdq m3, m26 ; d04 d12 d20 d28 + punpckhqdq m26, m9, m24 ; d07 d15 d23 d31 + punpcklqdq m9, m24 ; d06 d14 d22 d30 + mova [rsp+64*12], m23 + mova [rsp+64*13], m27 + mova [rsp+64*14], m25 + mova [rsp+64*15], m26 + punpckhqdq m24, m8, m22 ; a05 a13 a21 a29 + punpcklqdq m8, m22 ; a04 a12 a20 a28 + punpckhqdq m22, m0, m4 ; a01 a09 a17 a25 + punpcklqdq m0, m4 ; a00 a08 a16 a24 + punpckhqdq m23, m7, m2 ; a03 a11 a19 a27 + punpcklqdq m7, m2 ; a02 a10 a18 a26 + punpckhqdq m25, m6, m1 ; a07 a15 a23 a31 + punpcklqdq m6, m1 ; a06 a14 a22 a30 + mova m2, [rsp+64*0] + mova m11, [rsp+64*1] + mova m12, [rsp+64*2] + mova m29, [rsp+64*3] + mova m27, [rsp+64*4] + mova m26, [rsp+64*5] + mova m4, [rsp+64*6] + mova m28, [rsp+64*7] + psubw m1, m2, m21 ; 23 + paddw m2, m21 ; 8 + psubw m21, m11, m20 ; 22 + paddw m11, m20 ; 9 + psubw m20, m12, m19 ; 21 + paddw m12, m19 ; 10 + psubw m19, m29, m18 ; 20 + paddw m29, m18 ; 11 + psubw m18, m27, m17 ; 19 + paddw m27, m17 ; 12 + psubw m17, m26, m16 ; 18 + paddw m26, m16 ; 13 + paddw m16, m4, m15 ; 14 + psubw m4, m15 ; 17 + mova m15, m6 + psubw m6, m28, m14 ; 16 + paddw m28, m14 ; 15 + mova m14, m7 + punpcklwd m7, m6, m4 + punpckhwd m6, m4 + punpckhwd m4, m17, m18 + punpcklwd m17, m18 + punpckhwd m18, m19, m20 + punpcklwd m19, m20 + punpckhwd m20, m21, m1 + punpcklwd m21, m1 + punpckhwd m1, m2, m11 ; i4 j4 i5 j5 i6 j6 i7 j7 + punpcklwd m2, m11 ; i0 j1 i1 j1 i2 j2 i3 j3 + punpckhwd m11, m12, m29 ; k4 l4 k5 l5 k6 l6 k7 l7 + punpcklwd m12, m29 ; k0 l0 k1 l1 k2 l2 k3 l3 + punpckhwd m29, m27, m26 ; m4 n4 m5 n5 m6 n6 m7 n7 + punpcklwd m27, m26 ; m0 n0 m1 n1 m2 n2 m3 n3 + punpckhwd m26, m16, m28 ; o4 p4 o5 p5 o6 p6 o7 p7 + punpcklwd m16, m28 ; o0 p0 o1 p1 o2 p2 o3 p3 + punpckhdq m28, m2, m12 ; i2 j2 k2 l2 i3 j3 k3 l3 + punpckldq m2, m12 ; i0 j0 k0 l0 i1 j1 k1 l1 + punpckhdq m12, m27, m16 ; m2 n2 o2 p2 m3 n3 o3 p3 + punpckldq m27, m16 ; m0 n0 o0 p0 m1 n1 o1 p1 + punpckhdq m16, m1, m11 ; i6 j6 k6 l6 i7 j7 k7 l7 + punpckldq m1, m11 ; i4 j4 k4 l4 i5 j5 k5 l5 + punpckhdq m11, m29, m26 ; m6 n6 o6 p6 m7 n7 o7 p7 + punpckldq m29, m26 ; m4 n4 o4 p4 m5 n5 o5 p5 + punpckhdq m26, m19, m21 + punpckldq m19, m21 + punpckhdq m21, m6, m4 + punpckldq m6, m4 + punpckhdq m4, m18, m20 + punpckldq m18, m20 + punpckhdq m20, m7, m17 + punpckldq m7, m17 + punpcklqdq m17, m28, m12 ; b02 b10 b18 b26 + punpckhqdq m28, m12 ; b03 b11 b19 b27 + punpckhqdq m12, m2, m27 ; b01 b09 b17 b25 + punpcklqdq m2, m27 ; b00 b08 b16 b24 + punpckhqdq m27, m1, m29 ; b05 b13 b21 b29 + punpcklqdq m1, m29 ; b04 b12 b20 b28 + punpckhqdq m29, m16, m11 ; b07 b15 b23 b31 + punpcklqdq m16, m11 ; b06 b14 b22 b30 + mova [rsp+64* 8], m12 + mova [rsp+64* 9], m28 + mova [rsp+64*10], m27 + mova [rsp+64*11], m29 + punpckhqdq m27, m20, m26 ; c03 c11 c19 c27 + punpcklqdq m20, m26 ; c02 c10 c18 c26 + punpckhqdq m26, m7, m19 ; c01 c09 c17 c25 + punpcklqdq m7, m19 ; c00 c08 c16 c24 + punpckhqdq m28, m6, m18 ; c05 c13 c21 c29 + punpcklqdq m6, m18 ; c04 c12 c20 c28 + punpckhqdq m29, m21, m4 ; c07 c15 c23 c31 + punpcklqdq m21, m4 ; c06 c14 c22 c30 + mov r3d, 64*28 + pxor m4, m4 +.zero_loop: + mova [cq+r3+64*0], m4 + mova [cq+r3+64*1], m4 + mova [cq+r3+64*2], m4 + mova [cq+r3+64*3], m4 + sub r3d, 64*4 + jge .zero_loop + vshufi32x4 m4, m0, m2, q3232 ; a16 a24 b16 b24 + vinserti32x8 m0, ym2, 1 ; a00 a08 b00 b08 + vshufi32x4 m2, m7, m5, q3232 ; c16 c24 d16 d24 + vinserti32x8 m7, ym5, 1 ; c00 c08 d00 d08 + vshufi32x4 m5, m8, m1, q3232 ; a20 a28 b20 b28 + vinserti32x8 m1, m8, ym1, 1 ; a04 a12 b04 b12 + vshufi32x4 m8, m6, m3, q3232 ; c20 c28 d20 d28 + vinserti32x8 m6, ym3, 1 ; c04 c12 d04 d12 + vshufi32x4 m3, m1, m6, q3131 ; 12 + vshufi32x4 m1, m6, q2020 ; 4 + vshufi32x4 m6, m4, m2, q3131 ; 24 + vshufi32x4 m4, m2, q2020 ; 16 + vshufi32x4 m2, m0, m7, q3131 ; 8 + vshufi32x4 m0, m7, q2020 ; 0 + vshufi32x4 m7, m5, m8, q3131 ; 28 + vshufi32x4 m5, m8, q2020 ; 20 + vshufi32x4 m18, m14, m17, q3232 ; a18 a26 b18 b26 + vinserti32x8 m14, ym17, 1 ; a02 a10 b02 b10 + vshufi32x4 m17, m20, m13, q3232 ; c18 c26 d18 d26 + vinserti32x8 m20, ym13, 1 ; c02 c10 d02 d10 + vshufi32x4 m13, m21, m9, q3232 ; c22 c30 d22 d30 + vinserti32x8 m21, ym9, 1 ; c06 c14 d06 d14 + vshufi32x4 m19, m15, m16, q3232 ; a22 a30 b22 b30 + vinserti32x8 m15, ym16, 1 ; a06 a14 b06 b14 + vshufi32x4 m16, m14, m20, q3131 ; 10 + vshufi32x4 m14, m20, q2020 ; 2 + vshufi32x4 m20, m18, m17, q3131 ; 26 + vshufi32x4 m18, m17, q2020 ; 18 + vshufi32x4 m17, m15, m21, q3131 ; 14 + vshufi32x4 m15, m21, q2020 ; 6 + vshufi32x4 m21, m19, m13, q3131 ; 30 + vshufi32x4 m19, m13, q2020 ; 22 + call .idct16 + mova [rsp+64*0], m14 + mova [rsp+64*1], m15 + mova [rsp+64*2], m16 + mova [rsp+64*3], m17 + mova [rsp+64*4], m18 + mova [rsp+64*5], m19 + mova [rsp+64*6], m20 + mova [rsp+64*7], m21 + mova m15, [rsp+64* 8] + mova m16, [rsp+64* 9] + mova m17, [rsp+64*10] + mova m19, [rsp+64*11] + mova m20, [rsp+64*12] + mova m21, [rsp+64*13] + mova m13, [rsp+64*14] + mova m18, [rsp+64*15] + vshufi32x4 m14, m22, m15, q3232 ; a17 a25 b17 b25 + vinserti32x8 m22, ym15, 1 ; a01 a09 b01 b09 + vshufi32x4 m15, m23, m16, q3232 ; a19 a27 b19 b27 + vinserti32x8 m23, ym16, 1 ; a03 a11 b03 b11 + vshufi32x4 m16, m24, m17, q3232 ; a21 a29 b21 b29 + vinserti32x8 m24, ym17, 1 ; a05 a13 b05 b13 + vshufi32x4 m17, m25, m19, q3232 ; a23 a31 b23 b31 + vinserti32x8 m25, ym19, 1 ; a07 a15 b07 b15 + vinserti32x8 m8, m26, ym20, 1 ; c01 c09 d01 d09 + vshufi32x4 m26, m20, q3232 ; c17 c25 d17 d25 + vinserti32x8 m9, m27, ym21, 1 ; c03 c11 d03 d11 + vshufi32x4 m27, m21, q3232 ; c19 c27 d19 d27 + vinserti32x8 m11, m28, ym13, 1 ; c05 c13 d05 d13 + vshufi32x4 m28, m13, q3232 ; c21 c29 d21 d29 + vinserti32x8 m12, m29, ym18, 1 ; c07 c15 d07 d15 + vshufi32x4 m29, m18, q3232 ; c23 c31 d23 d31 + vshufi32x4 m18, m14, m26, q3131 ; 25 + vshufi32x4 m14, m26, q2020 ; 17 + vshufi32x4 m19, m15, m27, q3131 ; 27 + vshufi32x4 m15, m27, q2020 ; 19 + vshufi32x4 m20, m16, m28, q3131 ; 29 + vshufi32x4 m16, m28, q2020 ; 21 + vshufi32x4 m21, m17, m29, q3131 ; 31 + vshufi32x4 m17, m29, q2020 ; 23 + vshufi32x4 m26, m22, m8, q3131 ; 9 + vshufi32x4 m22, m8, q2020 ; 1 + vshufi32x4 m27, m23, m9, q3131 ; 11 + vshufi32x4 m23, m9, q2020 ; 3 + vshufi32x4 m28, m24, m11, q3131 ; 13 + vshufi32x4 m24, m11, q2020 ; 5 + vshufi32x4 m29, m25, m12, q3131 ; 15 + vshufi32x4 m25, m12, q2020 ; 7 + call .main + jmp .end +.fast: + mova m14, [o(dup16_perm)] + pmovzxbw m9, [cq+64*0] + pmovzxbw m6, [cq+64*8] + vpermb m8, m14, [cq+64* 2] + vpermb m0, m14, [cq+64*14] + vpermb m5, m14, [cq+64*10] + vpermb m1, m14, [cq+64* 6] + vpermb m7, m14, [cq+64* 4] + vpermb m3, m14, [cq+64*12] + vpbroadcastd m10, [o(pd_8192)] + vpbroadcastq m13, [o(int_mshift)] + packuswb m9, m9 + packuswb m6, m6 + vpcmpub k7, m13, m10, 6 + IDCT16_MAIN 1 + vpermb m21, m14, [cq+64* 1] + vpermb m17, m14, [cq+64*15] + vpermb m20, m14, [cq+64* 9] + vpermb m15, m14, [cq+64* 7] + vpermb m18, m14, [cq+64* 5] + vpermb m16, m14, [cq+64*11] + vpermb m19, m14, [cq+64*13] + vpermb m14, m14, [cq+64* 3] + call .main_packed_fast + punpcklwd m8, m0, m2 + punpckhwd m0, m2 + punpcklwd m2, m1, m3 + punpckhwd m1, m3 + punpcklwd m3, m4, m6 + punpckhwd m4, m6 + punpcklwd m6, m5, m7 + punpckhwd m5, m7 + punpcklwd m7, m14, m16 + punpckhwd m14, m16 + punpcklwd m16, m15, m17 + punpckhwd m15, m17 + punpcklwd m17, m19, m21 + punpckhwd m19, m21 + punpckhwd m21, m18, m20 + punpcklwd m18, m20 + punpcklwd m20, m8, m1 + punpckhwd m8, m1 + punpcklwd m1, m0, m2 + punpckhwd m0, m2 + punpcklwd m2, m3, m5 + punpckhwd m3, m5 + punpcklwd m5, m4, m6 + punpckhwd m4, m6 + punpcklwd m6, m7, m15 + punpckhwd m7, m15 + punpcklwd m15, m14, m16 + punpckhwd m14, m16 + punpckhwd m16, m18, m19 + punpcklwd m18, m19 + punpcklwd m19, m21, m17 + punpckhwd m21, m17 + punpcklwd m17, m8, m0 ; a2 a6 aa ae + punpckhwd m8, m0 ; a3 a7 ab af + punpcklwd m0, m20, m1 ; a0 a4 a8 ac + punpckhwd m20, m1 ; a1 a5 a9 ad + punpcklwd m1, m2, m5 ; b0 b4 b8 bc + punpckhwd m2, m5 ; b1 b5 b9 bd + punpcklwd m5, m3, m4 ; b2 b6 ba be + punpckhwd m3, m4 ; b3 b7 bb bf + punpcklwd m4, m6, m15 ; c0 c4 c8 cc + punpckhwd m6, m15 ; c1 c5 c9 cd + punpcklwd m15, m7, m14 ; c2 c6 ca ce + punpckhwd m7, m14 ; c3 c7 cb cf + punpcklwd m14, m18, m19 ; d0 d4 d8 dc + punpckhwd m18, m19 ; d1 d5 d9 dd + punpcklwd m9, m16, m21 ; d2 d6 da de + punpckhwd m16, m21 ; d3 d7 db df + mov r3d, 64*12 + pxor ym21, ym21 +.fast_zero_loop: + mova [cq+r3+64*0], ym21 + mova [cq+r3+64*1], ym21 + mova [cq+r3+64*2], ym21 + mova [cq+r3+64*3], ym21 + sub r3d, 64*4 + jge .fast_zero_loop + vshufi32x4 m21, m0, m1, q3232 ; a8 ac b8 bc + vinserti32x8 m0, ym1, 1 ; a0 a4 b0 b4 + vinserti32x8 m1, m17, ym5, 1 ; a2 a6 b2 b6 + vshufi32x4 m5, m17, m5, q3232 ; aa ae ba be + vinserti32x8 m17, m8, ym3, 1 ; a3 a7 b3 b7 + vshufi32x4 m19, m8, m3, q3232 ; ab af bb bf + vinserti32x8 m3, m4, ym14, 1 ; c0 c4 d0 d4 + vshufi32x4 m4, m14, q3232 ; c8 cc d8 dc + vinserti32x8 m14, m20, ym2, 1 ; a1 a5 b1 b5 + vshufi32x4 m20, m2, q3232 ; a9 ad b9 bd + vinserti32x8 m2, m6, ym18, 1 ; c1 c5 d1 d5 + vshufi32x4 m6, m18, q3232 ; c9 cd d9 dd + vinserti32x8 m18, m15, ym9, 1 ; c2 c6 d2 d6 + vshufi32x4 m15, m9, q3232 ; ca ce da de + vinserti32x8 m9, m7, ym16, 1 ; c3 c7 d3 d7 + vshufi32x4 m7, m16, q3232 ; cb cf db df + vshufi32x4 m22, m14, m2, q2020 ; 1 + vshufi32x4 m24, m14, m2, q3131 ; 5 + vshufi32x4 m23, m17, m9, q2020 ; 3 + vshufi32x4 m25, m17, m9, q3131 ; 7 + vshufi32x4 m16, m5, m15, q2020 ; 10 + vshufi32x4 m17, m5, m15, q3131 ; 14 + vshufi32x4 m14, m1, m18, q2020 ; 2 + vshufi32x4 m15, m1, m18, q3131 ; 6 + vshufi32x4 m1, m0, m3, q3131 ; 4 + vshufi32x4 m0, m3, q2020 ; 0 + vshufi32x4 m3, m21, m4, q3131 ; 12 + vshufi32x4 m2, m21, m4, q2020 ; 8 + vshufi32x4 m26, m20, m6, q2020 ; 9 + vshufi32x4 m28, m20, m6, q3131 ; 13 + vshufi32x4 m27, m19, m7, q2020 ; 11 + vshufi32x4 m29, m19, m7, q3131 ; 15 + call .idct16_fast + mova [rsp+64*0], m14 + mova [rsp+64*1], m15 + mova [rsp+64*2], m16 + mova [rsp+64*3], m17 + mova [rsp+64*4], m18 + mova [rsp+64*5], m19 + mova [rsp+64*6], m20 + mova [rsp+64*7], m21 + call .main_fast +.end: + lea r4, [strideq*3] + vpbroadcastd m12, [o(pw_512)] + movshdup m13, [o(itx_perm)] + lea r3, [dstq+r4*8] + lea r5, [strideq+r4] ; stride*4 + add r3, r5 ; dst+stride*28 + IDCT_32x32_END 29, 0, strideq*0, r4 + IDCT_32x32_END 28, 1, strideq*1, strideq*2 + IDCT_32x32_END 27, 2, strideq*2, strideq*1 + IDCT_32x32_END 26, 3, r4 , strideq*0 + IDCT_32x32_END 25, 4, strideq*0, r4 + IDCT_32x32_END 24, 5, strideq*1, strideq*2 + IDCT_32x32_END 23, 6, strideq*2, strideq*1 + IDCT_32x32_END 22, 7, r4 , strideq*0 + IDCT_32x32_END 21, 8, strideq*0, r4 + IDCT_32x32_END 20, 9, strideq*1, strideq*2 + IDCT_32x32_END 19, 10, strideq*2, strideq*1 + IDCT_32x32_END 18, 11, r4 , strideq*0 + IDCT_32x32_END 17, 12, strideq*0, r4 + IDCT_32x32_END 16, 13, strideq*1, strideq*2 + IDCT_32x32_END 15, 14, strideq*2, strideq*1 + IDCT_32x32_END 14, 15, r4 , strideq*0 + RET +ALIGN function_align +.idct16_fast: + vpbroadcastd m21, [o(pw_16305x2)] + vpbroadcastd m8, [o(pw_1606x2)] + vpbroadcastd m18, [o(pw_m10394x2)] + vpbroadcastd m9, [o(pw_12665x2)] + pmulhrsw m21, m14 ; t15a + vpbroadcastd m19, [o(pw_14449x2)] + pmulhrsw m14, m8 ; t8a + vpbroadcastd m8, [o(pw_7723x2)] + pmulhrsw m18, m17 ; t9a + vpbroadcastd m20, [o(pw_m4756x2)] + pmulhrsw m17, m9 ; t14a + vpbroadcastd m9, [o(pw_15679x2)] + pmulhrsw m19, m16 ; t13a + vpbroadcastd m5, [o(pw_m9102x2)] + pmulhrsw m16, m8 ; t10a + vpbroadcastd m8, [o(pw_13623x2)] + pmulhrsw m20, m15 ; t11a + vpbroadcastd m7, [o(pw_16069x2)] + pmulhrsw m15, m9 ; t12a + vpbroadcastd m9, [o(pw_3196x2)] + pmulhrsw m5, m3 ; t5a + vpbroadcastd m6, [o(pw_15137x2)] + pmulhrsw m3, m8 ; t6a + vpbroadcastd m8, [o(pw_6270x2)] + pmulhrsw m7, m1 ; t7a + vpbroadcastd m4, [o(pw_11585x2)] + pmulhrsw m1, m9 ; t4 + vpbroadcastd m10, [o(pd_8192)] + pmulhrsw m6, m2 ; t3 + pmulhrsw m2, m8 ; t2 + pmulhrsw m4, m0 ; t0 + mova m0, m4 ; t1 + jmp .idct16b +ALIGN function_align +.idct16: + vpbroadcastd m10, [o(pd_8192)] + ITX_MULSUB_2W 14, 21, 8, 9, 10, 1606, 16305 ; t8a, t15a + ITX_MULSUB_2W 18, 17, 8, 9, 10, 12665, 10394 ; t9a, t14a + ITX_MULSUB_2W 16, 19, 8, 9, 10, 7723, 14449 ; t10a, t13a + ITX_MULSUB_2W 20, 15, 8, 9, 10, 15679, 4756 ; t11a, t12 + ITX_MULSUB_2W 5, 3, 8, 9, 10, 13623, 9102 ; t5a, t6a + ITX_MULSUB_2W 1, 7, 8, 9, 10, 3196, 16069 ; t4a, t7a + ITX_MULSUB_2W 2, 6, 8, 9, 10, 6270, 15137 ; t2, t3 + ITX_MULSUB_2W 0, 4, 8, 9, 10, 11585, 11585 ; t1, t0 +.idct16b: + paddw m8, m20, m16 ; t11 + psubw m20, m16 ; t10 + paddw m16, m15, m19 ; t12 + psubw m15, m19 ; t13 + psubw m19, m14, m18 ; t9 + paddw m14, m18 ; t8 + psubw m18, m21, m17 ; t14 + paddw m21, m17 ; t15 + vpbroadcastd m11, [o(pw_6270_15137)] + vpbroadcastd m12, [o(pw_m15137_6270)] + ITX_MULSUB_2W 18, 19, 9, 17, 10, 11, 12 ; t9a, t14a + vpbroadcastd m11, [o(pw_m6270_m15137)] + ITX_MULSUB_2W 15, 20, 9, 17, 10, 12, 11 ; t10a, t13a + vpbroadcastd m11, [o(pw_11585_11585)] + vpbroadcastd m12, [o(pw_m11585_11585)] + paddw m9, m7, m3 ; t7 + psubw m3, m7, m3 ; t6a + paddw m7, m1, m5 ; t4 + psubw m1, m5 ; t5a + psubw m17, m14, m8 ; t11a + paddw m8, m14 ; t8a + paddw m14, m18, m15 ; t9 + psubw m18, m15 ; t10 + psubw m15, m19, m20 ; t13 + paddw m19, m20 ; t14 + paddw m20, m21, m16 ; t15a + psubw m16, m21, m16 ; t12a + ITX_MULSUB_2W 3, 1, 5, 21, 10, 11, 12 ; t5, t6 + ITX_MULSUB_2W 15, 18, 5, 21, 10, 11, 12 ; t10a, t13a + ITX_MULSUB_2W 16, 17, 5, 21, 10, 11, 12 ; t11, t12 + psubw m5, m0, m2 ; t2 + paddw m2, m0 ; t1 + paddw m0, m4, m6 ; t0 + psubw m4, m6 ; t3 + psubw m6, m2, m1 ; t6 + paddw m1, m2 ; t1 + paddw m2, m5, m3 ; t2 + psubw m5, m3 ; t5 + paddw m3, m4, m7 ; t3 + psubw m4, m7 ; t4 + psubw m7, m0, m9 ; t7 + paddw m0, m9 ; t0 + psubw m21, m0, m20 ; out15 + paddw m0, m20 ; out0 + psubw m20, m1, m19 ; out14 + paddw m1, m19 ; out1 + psubw m19, m2, m18 ; out13 + paddw m2, m18 ; out2 + psubw m18, m3, m17 ; out12 + paddw m3, m17 ; out3 + psubw m17, m4, m16 ; out11 + paddw m4, m16 ; out4 + psubw m16, m5, m15 ; out10 + paddw m5, m15 ; out5 + psubw m15, m6, m14 ; out9 + paddw m6, m14 ; out6 + psubw m14, m7, m8 ; out8 + paddw m7, m8 ; out7 + ret +ALIGN function_align +.main_fast: + vpbroadcastd m21, [o(pw_16364x2)] + vpbroadcastd m8, [o(pw_804x2)] + vpbroadcastd m14, [o(pw_m11003x2)] + vpbroadcastd m9, [o(pw_12140x2)] + pmulhrsw m21, m22 ; t31a + vpbroadcastd m17, [o(pw_14811x2)] + pmulhrsw m22, m8 ; t16a + vpbroadcastd m8, [o(pw_7005x2)] + pmulhrsw m14, m29 ; t30a + vpbroadcastd m18, [o(pw_m5520x2)] + pmulhrsw m29, m9 ; t17a + vpbroadcastd m9, [o(pw_15426x2)] + pmulhrsw m17, m26 ; t29a + vpbroadcastd m19, [o(pw_15893x2)] + pmulhrsw m26, m8 ; t18a + vpbroadcastd m8, [o(pw_3981x2)] + pmulhrsw m18, m25 ; t19a + vpbroadcastd m16, [o(pw_m8423x2)] + pmulhrsw m25, m9 ; t28a + vpbroadcastd m9, [o(pw_14053x2)] + pmulhrsw m19, m24 ; t27a + vpbroadcastd m15, [o(pw_13160x2)] + pmulhrsw m24, m8 ; t20a + vpbroadcastd m8, [o(pw_9760x2)] + pmulhrsw m16, m27 ; t21a + vpbroadcastd m20, [o(pw_m2404x2)] + pmulhrsw m27, m9 ; t26a + vpbroadcastd m9, [o(pw_16207x2)] + pmulhrsw m15, m28 ; t25a + pmulhrsw m28, m8 ; t22a + pmulhrsw m20, m23 ; t23a + pmulhrsw m23, m9 ; t24a + jmp .main2 +ALIGN function_align +.main: + ITX_MULSUB_2W 22, 21, 8, 9, 10, 804, 16364 ; t16a, t31a + ITX_MULSUB_2W 14, 29, 8, 9, 10, 12140, 11003 ; t17a, t30a + ITX_MULSUB_2W 26, 17, 8, 9, 10, 7005, 14811 ; t18a, t29a + ITX_MULSUB_2W 18, 25, 8, 9, 10, 15426, 5520 ; t19a, t28a + ITX_MULSUB_2W 24, 19, 8, 9, 10, 3981, 15893 ; t20a, t27a + ITX_MULSUB_2W 16, 27, 8, 9, 10, 14053, 8423 ; t21a, t26a + ITX_MULSUB_2W 28, 15, 8, 9, 10, 9760, 13160 ; t22a, t25a + ITX_MULSUB_2W 20, 23, 8, 9, 10, 16207, 2404 ; t23a, t24a +.main2: + psubw m8, m22, m14 ; t17 + paddw m22, m14 ; t16 + paddw m14, m18, m26 ; t19 + psubw m18, m26 ; t18 + psubw m26, m24, m16 ; t21 + paddw m24, m16 ; t20 + psubw m16, m20, m28 ; t22 + paddw m28, m20 ; t23 + psubw m20, m23, m15 ; t25 + paddw m23, m15 ; t24 + psubw m15, m21, m29 ; t30 + paddw m21, m29 ; t31 + psubw m29, m19, m27 ; t26 + paddw m19, m27 ; t27 + paddw m27, m25, m17 ; t28 + psubw m25, m17 ; t29 + ITX_MULSUB_2W 15, 8, 9, 17, 10, 3196, 16069 ; t17a, t30a + ITX_MULSUB_2W 25, 18, 9, 17, 10, m16069, 3196 ; t18a, t29a + ITX_MULSUB_2W 29, 26, 9, 17, 10, 13623, 9102 ; t21a, t26a + ITX_MULSUB_2W 20, 16, 9, 17, 10, m9102, 13623 ; t22a, t25a + psubw m17, m21, m27 ; t28a + paddw m21, m27 ; t31a + psubw m27, m15, m25 ; t18 + paddw m15, m25 ; t17 + psubw m25, m20, m29 ; t21 + paddw m20, m29 ; t22 + psubw m29, m8, m18 ; t29 + paddw m8, m18 ; t30 + psubw m18, m22, m14 ; t19a + paddw m22, m14 ; t16a + psubw m14, m28, m24 ; t20a + paddw m24, m28 ; t23a + paddw m28, m16, m26 ; t25 + psubw m16, m26 ; t26 + psubw m26, m23, m19 ; t27a + paddw m23, m19 ; t24a + vpbroadcastd m12, [o(pw_m15137_6270)] + vpbroadcastd m11, [o(pw_6270_15137)] + ITX_MULSUB_2W 29, 27, 9, 19, 10, 11, 12 ; t18a, t29a + ITX_MULSUB_2W 17, 18, 9, 19, 10, 11, 12 ; t19, t28 + vpbroadcastd m11, [o(pw_m6270_m15137)] + ITX_MULSUB_2W 16, 25, 9, 19, 10, 12, 11 ; t21a, t26a + ITX_MULSUB_2W 26, 14, 9, 19, 10, 12, 11 ; t20, t27 + vpbroadcastd m12, [o(pw_m11585_11585)] + vpbroadcastd m11, [o(pw_11585_11585)] + psubw m19, m27, m25 ; t26 + paddw m27, m25 ; t29 + psubw m25, m17, m26 ; t20a + paddw m17, m26 ; t19a + paddw m26, m18, m14 ; t28a + psubw m18, m14 ; t27a + paddw m14, m22, m24 ; t16 + psubw m22, m24 ; t23 + psubw m24, m29, m16 ; t21 + paddw m16, m29 ; t18 + paddw m29, m21, m23 ; t31 + psubw m21, m23 ; t24 + psubw m23, m15, m20 ; t22a + paddw m15, m20 ; t17a + psubw m20, m8, m28 ; t25a + paddw m28, m8 ; t30a + ITX_MULSUB_2W 18, 25, 8, 9, 10, 11, 12 ; t20, t27 + ITX_MULSUB_2W 19, 24, 8, 9, 10, 11, 12 ; t21a, t26a + ITX_MULSUB_2W 21, 22, 8, 9, 10, 11, 12 ; t23a, t24a + ITX_MULSUB_2W 20, 23, 8, 9, 10, 11, 12 ; t22, t25 + ret +ALIGN function_align +.main_packed_fast: + vpbroadcastd m8, [o(pw_804_16364x2)] + vpbroadcastd m9, [o(pw_m11003_12140x2)] + vpbroadcastd m11, [o(pw_7005_14811x2)] + vpbroadcastd m12, [o(pw_m5520_15426x2)] + pmulhrsw m21, m8 ; t16a, t31a + vpbroadcastd m8, [o(pw_3981_15893x2)] + pmulhrsw m17, m9 ; t17a, t30a + vpbroadcastd m9, [o(pw_m8423_14053x2)] + pmulhrsw m20, m11 ; t18a, t29a + vpbroadcastd m11, [o(pw_9760_13160x2)] + pmulhrsw m15, m12 ; t19a, t28a + vpbroadcastd m12, [o(pw_m2404_16207x2)] + pmulhrsw m18, m8 ; t20a, t27a + pmulhrsw m16, m9 ; t21a, t26a + pmulhrsw m19, m11 ; t22a, t25a + pmulhrsw m14, m12 ; t23a, t24a + psubw m8, m21, m17 ; t17 t30 + paddw m21, m17 ; t16 t31 + psubw m17, m15, m20 ; t18 t29 + paddw m20, m15 ; t19 t28 + psubw m15, m18, m16 ; t21 t26 + paddw m18, m16 ; t20 t27 + psubw m16, m14, m19 ; t22 t25 + paddw m14, m19 ; t23 t24 + ITX_MUL2X_PACK 8, 9, 19, 10, 3196, 16069, 5 ; t17a t30a + ITX_MUL2X_PACK 17, 9, 19, 10, m16069, 3196, 5 ; t18a t29a + ITX_MUL2X_PACK 15, 9, 19, 10, 13623, 9102, 5 ; t21a t26a + ITX_MUL2X_PACK 16, 9, 19, 10, m9102, 13623, 5 ; t22a t25a + vpbroadcastd m11, [o(pw_m15137_6270)] + psubw m19, m21, m20 ; t19a t28a + paddw m21, m20 ; t16a t31a + psubw m20, m14, m18 ; t20a t27a + paddw m14, m18 ; t23a t24a + psubw m18, m8, m17 ; t18 t29 + paddw m8, m17 ; t17 t30 + psubw m17, m16, m15 ; t21 t26 + paddw m15, m16 ; t22 t25 + ITX_MUL2X_PACK 18, 9, 16, 10, 6270_15137, 11, 20 ; t18a t29a + ITX_MUL2X_PACK 19, 9, 16, 10, 6270_15137, 11, 20 ; t19 t28 + ITX_MUL2X_PACK 20, 9, 16, 10, 11, m6270_m15137, 36 ; t20 t27 + ITX_MUL2X_PACK 17, 9, 16, 10, 11, m6270_m15137, 36 ; t21a t26a + vbroadcasti32x4 m9, [o(deint_shuf)] + psubw m16, m21, m14 ; t23 t24 + paddw m14, m21 ; t16 t31 + psubw m21, m8, m15 ; t22a t25a + paddw m15, m8 ; t17a t30a + psubw m8, m18, m17 ; t21 t26 + paddw m18, m17 ; t18 t29 + paddw m17, m19, m20 ; t19a t28a + psubw m19, m20 ; t20a t27a + vpbroadcastd m11, [o(pw_m11585_11585)] + vpbroadcastd m12, [o(pw_11585_11585)] + REPX {pshufb x, m9}, m14, m15, m18, m17 + mova m9, m10 + vpdpwssd m9, m16, m11 + mova m20, m10 + vpdpwssd m20, m21, m11 + psrad m9, 14 + psrad m20, 14 + packssdw m9, m20 ; t23a t22 + mova m20, m10 + vpdpwssd m20, m16, m12 + mova m16, m10 + vpdpwssd m16, m21, m12 + psrad m20, 14 + psrad m16, 14 + packssdw m16, m20, m16 ; t24a t25 + ITX_MUL2X_PACK 8, 21, 20, 10, 11, 12, 8 ; t21a t26a + ITX_MUL2X_PACK 19, 8, 11, 10, 11, 12, 8 ; t20 t27 + packssdw m11, m20 ; t27 t26a + packssdw m8, m21 ; t20 t21a + punpcklqdq m20, m14, m15 ; t16 t17a + punpckhqdq m14, m15 ; t31 t30a + punpckhqdq m15, m17, m18 ; t28a t29 + punpcklqdq m17, m18 ; t19a t18 + psubw m21, m0, m14 ; out31 out30 + paddw m0, m14 ; out0 out1 + psubw m14, m7, m20 ; out16 out17 + paddw m7, m20 ; out15 out14 + psubw m20, m1, m15 ; out28 out29 + paddw m1, m15 ; out3 out2 + psubw m15, m6, m17 ; out19 out18 + paddw m6, m17 ; out12 out13 + psubw m17, m4, m9 ; out23 out22 + paddw m4, m9 ; out8 out9 + psubw m18, m3, m16 ; out24 out25 + paddw m3, m16 ; out7 out6 + psubw m16, m5, m8 ; out20 out21 + paddw m5, m8 ; out11 out10 + psubw m19, m2, m11 ; out27 out26 + paddw m2, m11 ; out4 out5 + ret + +%endif diff --git a/libavcodec/x86/vp9lpf.asm b/libavcodec/x86/vp9lpf.asm index 4e7ede223..92e5d03ad 100644 --- a/libavcodec/x86/vp9lpf.asm +++ b/libavcodec/x86/vp9lpf.asm @@ -818,8 +818,7 @@ cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 2, 6, 16, %3 + %4 + %%ext, dst, stride ; (m0: hev, m1: p0', m2: q0-p0, m3: fm, m7: q0', [m8: flat8out], m10..13: p1 p0 q0 q1, m14: pb_10, [m15: flat8in], ) ; filter4() - mova m4, m2 - paddsb m2, m4 ; 2 * (q0 - p0) + paddsb m4, m2, m2 ; 2 * (q0 - p0) paddsb m2, m4 ; 3 * (q0 - p0) paddsb m6, m2, [pb_4] ; m6: f1 = clip(f + 4, 127) paddsb m2, [pb_3] ; m2: f2 = clip(f + 3, 127) diff --git a/libavcodec/x86/vp9mc.asm b/libavcodec/x86/vp9mc.asm index efc4cfbef..0e6aa627d 100644 --- a/libavcodec/x86/vp9mc.asm +++ b/libavcodec/x86/vp9mc.asm @@ -2,6 +2,7 @@ ;* VP9 motion compensation SIMD optimizations ;* ;* Copyright (c) 2013 Ronald S. Bultje +;* Copyright (c) 2025 Two Orioles, LLC ;* ;* This file is part of FFmpeg. ;* @@ -52,66 +53,124 @@ times 8 dw %5, %6 times 8 dw %7, %8 %endmacro -%macro FILTER 1 -const filters_%1 ; smooth - F8_TAPS -3, -1, 32, 64, 38, 1, -3, 0 - F8_TAPS -2, -2, 29, 63, 41, 2, -3, 0 - F8_TAPS -2, -2, 26, 63, 43, 4, -4, 0 - F8_TAPS -2, -3, 24, 62, 46, 5, -4, 0 - F8_TAPS -2, -3, 21, 60, 49, 7, -4, 0 - F8_TAPS -1, -4, 18, 59, 51, 9, -4, 0 - F8_TAPS -1, -4, 16, 57, 53, 12, -4, -1 - F8_TAPS -1, -4, 14, 55, 55, 14, -4, -1 - F8_TAPS -1, -4, 12, 53, 57, 16, -4, -1 - F8_TAPS 0, -4, 9, 51, 59, 18, -4, -1 - F8_TAPS 0, -4, 7, 49, 60, 21, -3, -2 - F8_TAPS 0, -4, 5, 46, 62, 24, -3, -2 - F8_TAPS 0, -4, 4, 43, 63, 26, -2, -2 - F8_TAPS 0, -3, 2, 41, 63, 29, -2, -2 - F8_TAPS 0, -3, 1, 38, 64, 32, -1, -3 - ; regular - F8_TAPS 0, 1, -5, 126, 8, -3, 1, 0 - F8_TAPS -1, 3, -10, 122, 18, -6, 2, 0 - F8_TAPS -1, 4, -13, 118, 27, -9, 3, -1 - F8_TAPS -1, 4, -16, 112, 37, -11, 4, -1 - F8_TAPS -1, 5, -18, 105, 48, -14, 4, -1 - F8_TAPS -1, 5, -19, 97, 58, -16, 5, -1 - F8_TAPS -1, 6, -19, 88, 68, -18, 5, -1 - F8_TAPS -1, 6, -19, 78, 78, -19, 6, -1 - F8_TAPS -1, 5, -18, 68, 88, -19, 6, -1 - F8_TAPS -1, 5, -16, 58, 97, -19, 5, -1 - F8_TAPS -1, 4, -14, 48, 105, -18, 5, -1 - F8_TAPS -1, 4, -11, 37, 112, -16, 4, -1 - F8_TAPS -1, 3, -9, 27, 118, -13, 4, -1 - F8_TAPS 0, 2, -6, 18, 122, -10, 3, -1 - F8_TAPS 0, 1, -3, 8, 126, -5, 1, 0 - ; sharp - F8_TAPS -1, 3, -7, 127, 8, -3, 1, 0 - F8_TAPS -2, 5, -13, 125, 17, -6, 3, -1 - F8_TAPS -3, 7, -17, 121, 27, -10, 5, -2 - F8_TAPS -4, 9, -20, 115, 37, -13, 6, -2 - F8_TAPS -4, 10, -23, 108, 48, -16, 8, -3 - F8_TAPS -4, 10, -24, 100, 59, -19, 9, -3 - F8_TAPS -4, 11, -24, 90, 70, -21, 10, -4 - F8_TAPS -4, 11, -23, 80, 80, -23, 11, -4 - F8_TAPS -4, 10, -21, 70, 90, -24, 11, -4 - F8_TAPS -3, 9, -19, 59, 100, -24, 10, -4 - F8_TAPS -3, 8, -16, 48, 108, -23, 10, -4 - F8_TAPS -2, 6, -13, 37, 115, -20, 9, -4 - F8_TAPS -2, 5, -10, 27, 121, -17, 7, -3 - F8_TAPS -1, 3, -6, 17, 125, -13, 5, -2 - F8_TAPS 0, 1, -3, 8, 127, -7, 3, -1 +%macro FILTER 0-1 +%if %0 > 0 +%1 %+ _smooth: +%endif + ; smooth + F8_TAPS -3, -1, 32, 64, 38, 1, -3, 0 + F8_TAPS -2, -2, 29, 63, 41, 2, -3, 0 + F8_TAPS -2, -2, 26, 63, 43, 4, -4, 0 + F8_TAPS -2, -3, 24, 62, 46, 5, -4, 0 + F8_TAPS -2, -3, 21, 60, 49, 7, -4, 0 + F8_TAPS -1, -4, 18, 59, 51, 9, -4, 0 + F8_TAPS -1, -4, 16, 57, 53, 12, -4, -1 + F8_TAPS -1, -4, 14, 55, 55, 14, -4, -1 + F8_TAPS -1, -4, 12, 53, 57, 16, -4, -1 + F8_TAPS 0, -4, 9, 51, 59, 18, -4, -1 + F8_TAPS 0, -4, 7, 49, 60, 21, -3, -2 + F8_TAPS 0, -4, 5, 46, 62, 24, -3, -2 + F8_TAPS 0, -4, 4, 43, 63, 26, -2, -2 + F8_TAPS 0, -3, 2, 41, 63, 29, -2, -2 + F8_TAPS 0, -3, 1, 38, 64, 32, -1, -3 +%if %0 > 0 +%1 %+ _regular: +%endif + ; regular + F8_TAPS 0, 1, -5, 126, 8, -3, 1, 0 + F8_TAPS -1, 3, -10, 122, 18, -6, 2, 0 + F8_TAPS -1, 4, -13, 118, 27, -9, 3, -1 + F8_TAPS -1, 4, -16, 112, 37, -11, 4, -1 + F8_TAPS -1, 5, -18, 105, 48, -14, 4, -1 + F8_TAPS -1, 5, -19, 97, 58, -16, 5, -1 + F8_TAPS -1, 6, -19, 88, 68, -18, 5, -1 + F8_TAPS -1, 6, -19, 78, 78, -19, 6, -1 + F8_TAPS -1, 5, -18, 68, 88, -19, 6, -1 + F8_TAPS -1, 5, -16, 58, 97, -19, 5, -1 + F8_TAPS -1, 4, -14, 48, 105, -18, 5, -1 + F8_TAPS -1, 4, -11, 37, 112, -16, 4, -1 + F8_TAPS -1, 3, -9, 27, 118, -13, 4, -1 + F8_TAPS 0, 2, -6, 18, 122, -10, 3, -1 + F8_TAPS 0, 1, -3, 8, 126, -5, 1, 0 +%if %0 > 0 +%1 %+ _sharp: +%endif + ; sharp + F8_TAPS -1, 3, -7, 127, 8, -3, 1, 0 + F8_TAPS -2, 5, -13, 125, 17, -6, 3, -1 + F8_TAPS -3, 7, -17, 121, 27, -10, 5, -2 + F8_TAPS -4, 9, -20, 115, 37, -13, 6, -2 + F8_TAPS -4, 10, -23, 108, 48, -16, 8, -3 + F8_TAPS -4, 10, -24, 100, 59, -19, 9, -3 + F8_TAPS -4, 11, -24, 90, 70, -21, 10, -4 + F8_TAPS -4, 11, -23, 80, 80, -23, 11, -4 + F8_TAPS -4, 10, -21, 70, 90, -24, 11, -4 + F8_TAPS -3, 9, -19, 59, 100, -24, 10, -4 + F8_TAPS -3, 8, -16, 48, 108, -23, 10, -4 + F8_TAPS -2, 6, -13, 37, 115, -20, 9, -4 + F8_TAPS -2, 5, -10, 27, 121, -17, 7, -3 + F8_TAPS -1, 3, -6, 17, 125, -13, 5, -2 + F8_TAPS 0, 1, -3, 8, 127, -7, 3, -1 %endmacro %define F8_TAPS F8_SSSE3_TAPS ; int8_t ff_filters_ssse3[3][15][4][32] -FILTER ssse3 +const filters_ssse3 +FILTER %define F8_TAPS F8_SSE2_TAPS ; int16_t ff_filters_sse2[3][15][8][8] -FILTER sse2 +const filters_sse2 +FILTER %define F8_TAPS F8_16BPP_TAPS ; int16_t ff_filters_16bpp[3][15][4][16] -FILTER 16bpp +const filters_16bpp +FILTER + +filter4_h_perm0: db 0, 1, 1, 2, 2, 3, 3, 4, 2, 3, 3, 4, 4, 5, 5, 6 +filter4_h_perm1: db 1, 2, 2, 3, 3, 4, 4, 5, 3, 4, 4, 5, 5, 6, 6, 7 + +%if HAVE_AVX512ICL_EXTERNAL && ARCH_X86_64 +ALIGN 64 +spel_h_perm16: db 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6 + db 8, 9, 10, 11, 9, 10, 11, 12, 10, 11, 12, 13, 11, 12, 13, 14 + db 32, 33, 34, 35, 33, 34, 35, 36, 34, 35, 36, 37, 35, 36, 37, 38 + db 40, 41, 42, 43, 41, 42, 43, 44, 42, 43, 44, 45, 43, 44, 45, 46 +spel_v_perm16: db 32, 0, 33, 1, 34, 2, 35, 3, 36, 4, 37, 5, 38, 6, 39, 7 + db 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 + db 40, 16, 41, 17, 42, 18, 43, 19, 44, 20, 45, 21, 46, 22, 47, 23 + db 16, 24, 17, 25, 18, 26, 19, 27, 20, 28, 21, 29, 22, 30, 23, 31 +spel_v_perm32: db 0, 32, 1, 33, 2, 34, 3, 35, 4, 36, 5, 37, 6, 38, 7, 39 + db 8, 40, 9, 41, 10, 42, 11, 43, 12, 44, 13, 45, 14, 46, 15, 47 + db 16, 48, 17, 49, 18, 50, 19, 51, 20, 52, 21, 53, 22, 54, 23, 55 + db 24, 56, 25, 57, 26, 58, 27, 59, 28, 60, 29, 61, 30, 62, 31, 63 +spel_hv_perm4: db 16, 32, 48, 8, 18, 34, 50, 10, 20, 36, 52, 12, 22, 38, 54, 14 + db 32, 48, 8, 24, 34, 50, 10, 26, 36, 52, 12, 28, 38, 54, 14, 30 + db 48, 8, 24, 40, 50, 10, 26, 42, 52, 12, 28, 44, 54, 14, 30, 46 + db 8, 24, 40, 56, 10, 26, 42, 58, 12, 28, 44, 60, 14, 30, 46, 62 +spel_hv_perm8: db 16, 32, 48, 8, 17, 33, 49, 9, 18, 34, 50, 10, 19, 35, 51, 11 + db 32, 48, 8, 24, 33, 49, 9, 25, 34, 50, 10, 26, 35, 51, 11, 27 + db 48, 8, 24, 40, 49, 9, 25, 41, 50, 10, 26, 42, 51, 11, 27, 43 + db 8, 24, 40, 56, 9, 25, 41, 57, 10, 26, 42, 58, 11, 27, 43, 59 +spel_hv_perm16: db 32, 8, 33, 9, 34, 10, 35, 11, 36, 12, 37, 13, 38, 14, 39, 15 + db 8, 40, 9, 41, 10, 42, 11, 43, 12, 44, 13, 45, 14, 46, 15, 47 + db 48, 24, 49, 25, 50, 26, 51, 27, 52, 28, 53, 29, 54, 30, 55, 31 + db 24, 56, 25, 57, 26, 58, 27, 59, 28, 60, 29, 61, 30, 62, 31, 63 +spel_h_shufB: db 4, 5, 6, 7, 5, 6, 7, 8, 6, 7, 8, 9, 7, 8, 9, 10 + +%define spel_h_shufA (spel_h_perm16+ 0) +%define spel_h_shufC (spel_h_perm16+16) + +%macro F8_AVX512_TAPS 8 +db %1, %2, %3, %4, %5, %6, %7, %8 +%endmacro +%define F8_TAPS F8_AVX512_TAPS +FILTER vp9_spel_filter + +pb_02461357: db 0, 2, 4, 6, 1, 3, 5, 7 +pd_64: dd 64 +pw_m33: times 2 dw -33 +pb_4: times 4 db 4 +%endif SECTION .text @@ -121,7 +180,7 @@ cglobal vp9_%1_8tap_1d_h_ %+ %%px %+ _8, 6, 6, 15, dst, dstride, src, sstride, h pxor m5, m5 mova m6, [pw_64] mova m7, [filteryq+ 0] -%if ARCH_X86_64 && mmsize > 8 +%if ARCH_X86_64 mova m8, [filteryq+ 16] mova m9, [filteryq+ 32] mova m10, [filteryq+ 48] @@ -142,7 +201,7 @@ cglobal vp9_%1_8tap_1d_h_ %+ %%px %+ _8, 6, 6, 15, dst, dstride, src, sstride, h punpcklbw m3, m5 punpcklbw m4, m5 pmullw m0, m7 -%if ARCH_X86_64 && mmsize > 8 +%if ARCH_X86_64 pmullw m1, m8 pmullw m2, m9 pmullw m3, m10 @@ -163,7 +222,7 @@ cglobal vp9_%1_8tap_1d_h_ %+ %%px %+ _8, 6, 6, 15, dst, dstride, src, sstride, h punpcklbw m1, m5 punpcklbw m3, m5 punpcklbw m4, m5 -%if ARCH_X86_64 && mmsize > 8 +%if ARCH_X86_64 pmullw m1, m12 pmullw m3, m13 pmullw m4, m14 @@ -192,20 +251,55 @@ cglobal vp9_%1_8tap_1d_h_ %+ %%px %+ _8, 6, 6, 15, dst, dstride, src, sstride, h RET %endmacro -INIT_MMX mmxext -filter_sse2_h_fn put -filter_sse2_h_fn avg - INIT_XMM sse2 filter_sse2_h_fn put filter_sse2_h_fn avg +%macro filter4_h_fn 2 +cglobal vp9_%1_8tap_1d_h_4_8, 6, 6, %2, dst, dstride, src, sstride, h, filtery + mova m2, [filter4_h_perm0] + mova m3, [filter4_h_perm1] + pcmpeqw m4, m4 + movu m5, [filteryq+24] + movu m6, [filteryq+88] + psllw m4, 6 ; pw_m64 +.loop: + movq m0, [srcq-3] + movq m1, [srcq+0] + pshufb m0, m2 + pshufb m1, m3 + pmaddubsw m0, m5 + pmaddubsw m1, m6 +%ifidn %1, avg + movd m7, [dstq] +%endif + add srcq, sstrideq + paddw m0, m1 + movhlps m1, m0 + psubw m0, m4 + paddsw m0, m1 + psraw m0, 7 + packuswb m0, m0 +%ifidn %1, avg + pavgb m0, m7 +%endif + movd [dstq], m0 + add dstq, dstrideq + sub hd, 1 + jg .loop + RET +%endmacro + +INIT_XMM ssse3 +filter4_h_fn put, 7 +filter4_h_fn avg, 8 + %macro filter_h_fn 1 %assign %%px mmsize/2 cglobal vp9_%1_8tap_1d_h_ %+ %%px %+ _8, 6, 6, 11, dst, dstride, src, sstride, h, filtery mova m6, [pw_256] mova m7, [filteryq+ 0] -%if ARCH_X86_64 && mmsize > 8 +%ifdef m8 mova m8, [filteryq+32] mova m9, [filteryq+64] mova m10, [filteryq+96] @@ -225,7 +319,7 @@ cglobal vp9_%1_8tap_1d_h_ %+ %%px %+ _8, 6, 6, 11, dst, dstride, src, sstride, h punpcklbw m4, m5 punpcklbw m1, m3 pmaddubsw m0, m7 -%if ARCH_X86_64 && mmsize > 8 +%ifdef m8 pmaddubsw m2, m8 pmaddubsw m4, m9 pmaddubsw m1, m10 @@ -252,10 +346,6 @@ cglobal vp9_%1_8tap_1d_h_ %+ %%px %+ _8, 6, 6, 11, dst, dstride, src, sstride, h RET %endmacro -INIT_MMX ssse3 -filter_h_fn put -filter_h_fn avg - INIT_XMM ssse3 filter_h_fn put filter_h_fn avg @@ -337,7 +427,7 @@ cglobal vp9_%1_8tap_1d_v_ %+ %%px %+ _8, 4, 7, 15, dst, dstride, src, sstride, f lea src4q, [srcq+sstrideq] sub srcq, sstride3q mova m7, [filteryq+ 0] -%if ARCH_X86_64 && mmsize > 8 +%ifdef m8 mova m8, [filteryq+ 16] mova m9, [filteryq+ 32] mova m10, [filteryq+ 48] @@ -362,7 +452,7 @@ cglobal vp9_%1_8tap_1d_v_ %+ %%px %+ _8, 4, 7, 15, dst, dstride, src, sstride, f punpcklbw m3, m5 punpcklbw m4, m5 pmullw m0, m7 -%if ARCH_X86_64 && mmsize > 8 +%ifdef m8 pmullw m1, m8 pmullw m2, m9 pmullw m3, m10 @@ -383,7 +473,7 @@ cglobal vp9_%1_8tap_1d_v_ %+ %%px %+ _8, 4, 7, 15, dst, dstride, src, sstride, f punpcklbw m1, m5 punpcklbw m3, m5 punpcklbw m4, m5 -%if ARCH_X86_64 && mmsize > 8 +%ifdef m8 pmullw m1, m12 pmullw m3, m13 pmullw m4, m14 @@ -412,20 +502,88 @@ cglobal vp9_%1_8tap_1d_v_ %+ %%px %+ _8, 4, 7, 15, dst, dstride, src, sstride, f RET %endmacro -INIT_MMX mmxext -filter_sse2_v_fn put -filter_sse2_v_fn avg - INIT_XMM sse2 filter_sse2_v_fn put filter_sse2_v_fn avg -%macro filter_v_fn 1 -%assign %%px mmsize/2 +%macro filter4_v_fn 1 %if ARCH_X86_64 -cglobal vp9_%1_8tap_1d_v_ %+ %%px %+ _8, 6, 8, 11, dst, dstride, src, sstride, h, filtery, src4, sstride3 +cglobal vp9_%1_8tap_1d_v_4_8, 6, 7, 8, dst, dstride, src, sstride, h, filtery, sstride3 %else -cglobal vp9_%1_8tap_1d_v_ %+ %%px %+ _8, 4, 7, 11, dst, dstride, src, sstride, filtery, src4, sstride3 +cglobal vp9_%1_8tap_1d_v_4_8, 4, 5, 8, dst, dstride, src, sstride, filtery +%define hd r4mp +%define sstride3q filteryq +%endif + lea sstride3q, [sstrideq*3] + sub srcq, sstride3q + movd m0, [srcq] + movd m1, [srcq+sstrideq] + movd m2, [srcq+sstrideq*2] + movd m3, [srcq+sstride3q] + lea srcq, [srcq+sstrideq*4] + movd m4, [srcq] + movd m5, [srcq+sstrideq] + punpcklbw m0, m1 + punpcklbw m1, m2 + punpcklbw m2, m3 + punpcklbw m3, m4 + punpcklqdq m0, m1 + movd m1, [srcq+sstrideq*2] + add srcq, sstride3q +%if ARCH_X86_32 + mov filteryq, r5mp +%endif + punpcklqdq m2, m3 + punpcklbw m4, m5 + punpcklbw m5, m1 + punpcklqdq m4, m5 +.loop: + pmaddubsw m0, [filteryq] + movd m3, [srcq] + movd m5, [srcq+sstrideq] + pmaddubsw m7, m4, [filteryq+64] + pmaddubsw m6, m2, [filteryq+32] + punpcklbw m1, m3 + punpcklbw m3, m5 + punpcklqdq m1, m3 + pmaddubsw m3, m1, [filteryq+96] + paddw m0, [pw_64] + lea srcq, [srcq+2*sstrideq] + paddw m7, m0 + mova m0, m2 + mova m2, m4 +%ifidn %1, avg + movd m4, [dstq] +%endif + paddw m6, m3 +%ifidn %1, avg + movd m3, [dstq+dstrideq] +%endif + paddsw m6, m7 + psraw m6, 7 + packuswb m6, m6 + pshuflw m7, m6, 0xE +%ifidn %1, avg + pavgb m6, m4 +%endif + movd [dstq], m6 + mova m4, m1 +%ifidn %1, avg + pavgb m7, m3 +%endif + movd [dstq+dstrideq], m7 + lea dstq, [dstq+2*dstrideq] + mova m1, m5 + sub hd, 2 + jg .loop + RET +%endmacro + +%macro filter_v_fn 1 +%if ARCH_X86_64 +cglobal vp9_%1_8tap_1d_v_8_8, 6, 8, 11, dst, dstride, src, sstride, h, filtery, src4, sstride3 +%else +cglobal vp9_%1_8tap_1d_v_8_8, 4, 7, 11, dst, dstride, src, sstride, filtery, src4, sstride3 mov filteryq, r5mp %define hd r4mp %endif @@ -434,7 +592,7 @@ cglobal vp9_%1_8tap_1d_v_ %+ %%px %+ _8, 4, 7, 11, dst, dstride, src, sstride, f lea src4q, [srcq+sstrideq] sub srcq, sstride3q mova m7, [filteryq+ 0] -%if ARCH_X86_64 && mmsize > 8 +%if ARCH_X86_64 mova m8, [filteryq+32] mova m9, [filteryq+64] mova m10, [filteryq+96] @@ -457,7 +615,7 @@ cglobal vp9_%1_8tap_1d_v_ %+ %%px %+ _8, 4, 7, 11, dst, dstride, src, sstride, f punpcklbw m4, m5 punpcklbw m1, m3 pmaddubsw m0, m7 -%if ARCH_X86_64 && mmsize > 8 +%if ARCH_X86_64 pmaddubsw m2, m8 pmaddubsw m4, m9 pmaddubsw m1, m10 @@ -484,9 +642,9 @@ cglobal vp9_%1_8tap_1d_v_ %+ %%px %+ _8, 4, 7, 11, dst, dstride, src, sstride, f RET %endmacro -INIT_MMX ssse3 -filter_v_fn put -filter_v_fn avg +INIT_XMM ssse3 +filter4_v_fn put +filter4_v_fn avg INIT_XMM ssse3 filter_v_fn put @@ -678,3 +836,785 @@ fpel_fn avg, 128, mmsize, mmsize*2, mmsize*3, 1, 16 %undef d16 %undef s32 %undef d32 + +%if HAVE_AVX512ICL_EXTERNAL && ARCH_X86_64 +%macro PUT_8TAP_H 4-5 0 ; dst/src, tmp[1-3], vpermb +%if %5 + vpermb m%2, m6, m%1 + vpermb m%3, m7, m%1 + vpermb m%4, m8, m%1 +%else +%if %2 < %4 ; reuse a previous value if possible + pshufb m%2, m%1, m6 +%endif + pshufb m%3, m%1, m7 + pshufb m%4, m%1, m8 +%endif + mova m%1, m5 + vpdpbusd m%1, m%2, m9 + mova m%2, m5 + vpdpbusd m%2, m%3, m9 + vpdpbusd m%1, m%3, m10 + vpdpbusd m%2, m%4, m10 + packusdw m%1, m%2 + psrlw m%1, 7 +%endmacro + +%macro SPEL_H_INIT 2 ; put/avg, w +cglobal vp9_%1_8tap_smooth_%2h_8, 4, 7, 0 + lea r6, [vp9_spel_filter_smooth-8] + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_%2h_8 %+ SUFFIX).main +cglobal vp9_%1_8tap_sharp_%2h_8, 4, 7, 0 + lea r6, [vp9_spel_filter_sharp-8] + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_%2h_8 %+ SUFFIX).main +cglobal vp9_%1_8tap_regular_%2h_8, 4, 7, 0, dst, ds, src, ss, h, mx + lea r6, [vp9_spel_filter_regular-8] +.main: + mov mxd, mxm + movifnidn hd, hm + sub srcq, 3 + vpbroadcastd m5, [pd_64] + vpbroadcastd m9, [r6+mxq*8+0] + vpbroadcastd m10, [r6+mxq*8+4] +%endmacro + +%macro SPEL_V_INIT 2 ; put/avg, w +cglobal vp9_%1_8tap_smooth_%2v_8, 4, 7, 0 + lea r5, [vp9_spel_filter_smooth-8] + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_%2v_8 %+ SUFFIX).main +cglobal vp9_%1_8tap_sharp_%2v_8, 4, 7, 0 + lea r5, [vp9_spel_filter_sharp-8] + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_%2v_8 %+ SUFFIX).main +cglobal vp9_%1_8tap_regular_%2v_8, 4, 7, 0, dst, ds, src, ss, h, mx, my + lea r5, [vp9_spel_filter_regular-8] +.main: + mov myd, mym + movifnidn hd, hm + lea myq, [r5+myq*8] + vpbroadcastd m7, [pw_256] + vpbroadcastw m8, [myq+0] + vpbroadcastw m9, [myq+2] + lea r5, [ssq*3] + vpbroadcastw m10, [myq+4] + sub srcq, r5 + vpbroadcastw m11, [myq+6] +%endmacro + +%macro SPEL_HV_INIT 2 ; put/avg, w +cglobal vp9_%1_8tap_smooth_%2hv_8, 4, 8, 0 + lea r6, [vp9_spel_filter_smooth-8] + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_%2hv_8 %+ SUFFIX).main +cglobal vp9_%1_8tap_sharp_%2hv_8, 4, 8, 0 + lea r6, [vp9_spel_filter_sharp-8] + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_%2hv_8 %+ SUFFIX).main +cglobal vp9_%1_8tap_regular_%2hv_8, 4, 8, 0, dst, ds, src, ss, h, mx, my + lea r6, [vp9_spel_filter_regular-8] +.main: +%if %2 == 16 + xor r7d, r7d +.main2: +%endif + mov mxd, mxm + movifnidn hd, hm + sub srcq, 3 + vpbroadcastd m9, [r6+mxq*8+0] + vpbroadcastd m10, [r6+mxq*8+4] + mov mxd, mym + vpbroadcastd m5, [pd_64] + lea myq, [r6+mxq*8] + lea r5, [ssq*3] + sub srcq, r5 +%endmacro + +%macro MC_AVX512 1 ; put/avg + SPEL_H_INIT %1, 4 + vbroadcasti32x4 m6, [spel_h_shufA] + lea r5, [ssq*3] + vbroadcasti32x4 m7, [spel_h_shufB] + lea r6, [dsq*3] + vbroadcasti32x4 m8, [spel_h_shufC] +.h_w4_loop: + movu xm0, [srcq+ssq*0] + vinserti32x4 ym0, [srcq+ssq*1], 1 + vinserti32x4 m0, [srcq+ssq*2], 2 + vinserti32x4 m0, [srcq+r5 ], 3 + lea srcq, [srcq+ssq*4] + pshufb m1, m0, m6 + pshufb m0, m7 + mova m2, m5 + vpdpbusd m2, m1, m9 + vpdpbusd m2, m0, m10 + vpmovsdw ym0, m2 + psraw ym0, 7 + packuswb ym0, ym0 + vextracti32x4 xm1, ym0, 1 +%ifidn %1, avg + movd xmm2, [dstq+dsq*0] + pinsrd xmm2, [dstq+dsq*1], 1 + movd xmm3, [dstq+dsq*2] + pinsrd xmm3, [dstq+r6 ], 1 + pavgb xm0, xmm2 + pavgb xm1, xmm3 +%endif + movd [dstq+dsq*0], xm0 + pextrd [dstq+dsq*1], xm0, 1 + movd [dstq+dsq*2], xm1 + pextrd [dstq+r6 ], xm1, 1 + lea dstq, [dstq+dsq*4] + sub hd, 4 + jg .h_w4_loop + RET + + SPEL_H_INIT %1, 8 + vbroadcasti32x4 m6, [spel_h_shufA] + lea r5, [ssq*3] + vbroadcasti32x4 m7, [spel_h_shufB] + lea r6, [dsq*3] + vbroadcasti32x4 m8, [spel_h_shufC] +.h_w8_loop: + movu xm0, [srcq+ssq*0] + vinserti32x4 ym0, [srcq+ssq*1], 1 + vinserti32x4 m0, [srcq+ssq*2], 2 + vinserti32x4 m0, [srcq+r5 ], 3 + lea srcq, [srcq+ssq*4] + PUT_8TAP_H 0, 1, 2, 3 + vpmovuswb ym0, m0 + vextracti32x4 xm1, ym0, 1 +%ifidn %1, avg + movq xmm2, [dstq+dsq*0] + movhps xmm2, [dstq+dsq*1] + movq xmm3, [dstq+dsq*2] + movhps xmm3, [dstq+r6 ] + pavgb xm0, xmm2 + pavgb xm1, xmm3 +%endif + movq [dstq+dsq*0], xm0 + movhps [dstq+dsq*1], xm0 + movq [dstq+dsq*2], xm1 + movhps [dstq+r6 ], xm1 + lea dstq, [dstq+dsq*4] + sub hd, 4 + jg .h_w8_loop + RET + + SPEL_H_INIT %1, 16 + mova m6, [spel_h_perm16] + vpbroadcastd m8, [pb_4] + paddb m7, m8, m6 + paddb m8, m7 +.h_w16_loop: + movu ym0, [srcq+ssq*0] + vinserti32x8 m0, [srcq+ssq*1], 1 + lea srcq, [srcq+ssq*2] + PUT_8TAP_H 0, 1, 2, 3, 1 + vpmovuswb ym0, m0 +%ifidn %1, avg + movu xm1, [dstq+dsq*0] + vinserti32x4 ym1, [dstq+dsq*1], 1 + pavgb ym0, ym1 +%endif + mova [dstq+dsq*0], xm0 + vextracti128 [dstq+dsq*1], ym0, 1 + lea dstq, [dstq+dsq*2] + sub hd, 2 + jg .h_w16_loop + RET + + SPEL_H_INIT %1, 32 + vbroadcasti32x4 m6, [spel_h_shufA] + vbroadcasti32x4 m7, [spel_h_shufB] + vbroadcasti32x4 m8, [spel_h_shufC] +.h_w32_loop: + movu ym0, [srcq+ssq*0+8*0] + vinserti32x8 m0, [srcq+ssq*1+8*0], 1 + movu ym1, [srcq+ssq*0+8*1] + vinserti32x8 m1, [srcq+ssq*1+8*1], 1 + lea srcq, [srcq+ssq*2] + PUT_8TAP_H 0, 2, 3, 4 + PUT_8TAP_H 1, 4, 3, 2 + packuswb m0, m1 +%ifidn %1, avg + movu ym1, [dstq+dsq*0] + vinserti32x8 m1, [dstq+dsq*1], 1 + pavgb m0, m1 +%endif + mova [dstq+dsq*0], ym0 + vextracti32x8 [dstq+dsq*1], m0, 1 + lea dstq, [dstq+dsq*2] + sub hd, 2 + jg .h_w32_loop + RET + + SPEL_H_INIT %1, 64 + vbroadcasti32x4 m6, [spel_h_shufA] + vbroadcasti32x4 m7, [spel_h_shufB] + vbroadcasti32x4 m8, [spel_h_shufC] +.h_w64_loop: + movu m0, [srcq+8*0] + movu m1, [srcq+8*1] + add srcq, ssq + PUT_8TAP_H 0, 2, 3, 4 + PUT_8TAP_H 1, 4, 3, 2 + packuswb m0, m1 +%ifidn %1, avg + pavgb m0, [dstq] +%endif + mova [dstq], m0 + add dstq, dsq + dec hd + jg .h_w64_loop + RET + + SPEL_V_INIT %1, 4 + movd xmm2, [srcq+ssq*0] + pinsrd xmm2, [srcq+ssq*1], 1 + pinsrd xmm2, [srcq+ssq*2], 2 + add srcq, r5 + pinsrd xmm2, [srcq+ssq*0], 3 ; 0 1 2 3 + movd xmm3, [srcq+ssq*1] + vpbroadcastd xmm1, [srcq+ssq*2] + add srcq, r5 + vpbroadcastd xmm0, [srcq+ssq*0] + vpblendd xmm3, xmm3, xmm1, 0x02 ; 4 5 + vpblendd xmm1, xmm1, xmm0, 0x02 ; 5 6 + palignr xmm4, xmm3, xmm2, 4 ; 1 2 3 4 + punpcklbw xmm3, xmm1 ; 45 56 + punpcklbw xmm1, xmm2, xmm4 ; 01 12 + punpckhbw xmm2, xmm4 ; 23 34 +%if WIN64 + movaps [rsp+8], xmm6 +%endif +.v_w4_loop: + vpbroadcastd xmm4, [srcq+ssq*1] + lea srcq, [srcq+ssq*2] + pmaddubsw xmm5, xmm1, xm8 ; a0 b0 + mova xmm1, xmm2 + pmaddubsw xmm6, xmm2, xm9 ; a1 b1 + mova xmm2, xmm3 + pmaddubsw xmm3, xm10 ; a2 b2 + paddw xmm5, xmm3 + vpblendd xmm3, xmm0, xmm4, 0x02 ; 6 7 + vpbroadcastd xmm0, [srcq+ssq*0] + vpblendd xmm4, xmm0, 0x02 ; 7 8 + punpcklbw xmm3, xmm4 ; 67 78 + pmaddubsw xmm4, xmm3, xm11 ; a3 b3 + paddw xmm6, xmm4 + paddsw xmm5, xmm6 + pmulhrsw xmm5, xm7 + packuswb xmm5, xmm5 +%ifidn %1, avg + movd xmm4, [dstq+dsq*0] + pinsrd xmm4, [dstq+dsq*1], 1 + pavgb xmm5, xmm4 +%endif + movd [dstq+dsq*0], xmm5 + pextrd [dstq+dsq*1], xmm5, 1 + lea dstq, [dstq+dsq*2] + sub hd, 2 + jg .v_w4_loop +%if WIN64 + movaps xmm6, [rsp+8] +%endif + RET + + SPEL_V_INIT %1, 8 + movq xmm1, [srcq+ssq*0] + vpbroadcastq ymm0, [srcq+ssq*1] + vpbroadcastq ymm2, [srcq+ssq*2] + add srcq, r5 + vpbroadcastq ymm5, [srcq+ssq*0] + vpbroadcastq ymm3, [srcq+ssq*1] + vpbroadcastq ymm4, [srcq+ssq*2] + add srcq, r5 + vpblendd ymm1, ymm0, 0x30 + vpblendd ymm0, ymm2, 0x30 + punpcklbw ymm1, ymm0 ; 01 12 + vpbroadcastq ymm0, [srcq+ssq*0] + vpblendd ymm2, ymm5, 0x30 + vpblendd ymm5, ymm3, 0x30 + punpcklbw ymm2, ymm5 ; 23 34 + vpblendd ymm3, ymm4, 0x30 + vpblendd ymm4, ymm0, 0x30 + punpcklbw ymm3, ymm4 ; 45 56 +%if WIN64 + movaps [rsp+8], xmm6 +%endif +.v_w8_loop: + vpbroadcastq ymm4, [srcq+ssq*1] + lea srcq, [srcq+ssq*2] + pmaddubsw ymm5, ymm1, ym8 ; a0 b0 + mova ymm1, ymm2 + pmaddubsw ymm6, ymm2, ym9 ; a1 b1 + mova ymm2, ymm3 + pmaddubsw ymm3, ym10 ; a2 b2 + paddw ymm5, ymm3 + vpblendd ymm3, ymm0, ymm4, 0x30 + vpbroadcastq ymm0, [srcq+ssq*0] + vpblendd ymm4, ymm4, ymm0, 0x30 + punpcklbw ymm3, ymm4 ; 67 78 + pmaddubsw ymm4, ymm3, ym11 ; a3 b3 + paddw ymm6, ymm4 + paddsw ymm5, ymm6 + pmulhrsw ymm5, ym7 + vextracti128 xmm4, ymm5, 1 + packuswb xmm5, xmm4 +%ifidn %1, avg + movq xmm4, [dstq+dsq*0] + movhps xmm4, [dstq+dsq*1] + pavgb xmm5, xmm4 +%endif + movq [dstq+dsq*0], xmm5 + movhps [dstq+dsq*1], xmm5 + lea dstq, [dstq+dsq*2] + sub hd, 2 + jg .v_w8_loop +%if WIN64 + movaps xmm6, [rsp+8] +%endif + vzeroupper + RET + + SPEL_V_INIT %1, 16 + mova m12, [spel_v_perm16] + vbroadcasti32x4 m1, [srcq+ssq*0] + vbroadcasti32x4 ym4, [srcq+ssq*1] + mov r6d, 0x0f + vbroadcasti32x4 m2, [srcq+ssq*2] + add srcq, r5 + vbroadcasti32x4 ym5, [srcq+ssq*0] + kmovb k1, r6d + vbroadcasti32x4 m3, [srcq+ssq*1] + vbroadcasti32x4 ym6, [srcq+ssq*2] + add srcq, r5 + vbroadcasti32x4 m0, [srcq+ssq*0] + vshufpd m1{k1}, m4, m2, 0xcc + vshufpd m2{k1}, m5, m3, 0xcc + vshufpd m3{k1}, m6, m0, 0xcc + vpermb m1, m12, m1 ; 01 12 + vpermb m2, m12, m2 ; 23 34 + vpermb m3, m12, m3 ; 45 56 +.v_w16_loop: + pmaddubsw m4, m1, m8 ; a0 b0 + mova m1, m2 + pmaddubsw m5, m2, m9 ; a1 b1 + mova m2, m3 + pmaddubsw m6, m3, m10 ; a2 b2 + mova m3, m0 + paddw m4, m6 + vbroadcasti32x4 ym6, [srcq+ssq*1] + lea srcq, [srcq+ssq*2] + vbroadcasti32x4 m0, [srcq+ssq*0] + vshufpd m3{k1}, m6, m0, 0xcc + vpermb m3, m12, m3 ; 67 78 + pmaddubsw m6, m3, m11 ; a3 b3 + paddw m5, m6 + paddsw m4, m5 + pmulhrsw m4, m7 + vextracti32x8 ym5, m4, 1 + packuswb ym4, ym5 +%ifidn %1, avg + mova xm5, [dstq+dsq*0] + vinserti32x4 ym5, [dstq+dsq*1], 1 + pavgb ym4, ym5 +%endif + mova [dstq+dsq*0], xm4 + vextracti32x4 [dstq+dsq*1], ym4, 1 + lea dstq, [dstq+dsq*2] + sub hd, 2 + jg .v_w16_loop + RET + + SPEL_V_INIT %1, 32 + mova m12, [spel_v_perm32] + pmovzxbq m14, [pb_02461357] + vpshrdw m13, m12, m12, 8 + movu ym0, [srcq+ssq*0] + vinserti32x8 m0, [srcq+ssq*1], 1 + vpermb m1, m12, m0 ; 01 + vinserti32x8 m0, [srcq+ssq*2], 0 + add srcq, r5 + vpermb m2, m13, m0 ; 12 + vinserti32x8 m0, [srcq+ssq*0], 1 + vpermb m3, m12, m0 ; 23 + vinserti32x8 m0, [srcq+ssq*1], 0 + vpermb m4, m13, m0 ; 34 + vinserti32x8 m0, [srcq+ssq*2], 1 + add srcq, r5 + vpermb m5, m12, m0 ; 45 + vinserti32x8 m0, [srcq+ssq*0], 0 + vpermb m6, m13, m0 ; 56 +.v_w32_loop: + vinserti32x8 m0, [srcq+ssq*1], 1 + lea srcq, [srcq+ssq*2] + pmaddubsw m15, m1, m8 + mova m1, m3 + pmaddubsw m16, m2, m8 + mova m2, m4 + pmaddubsw m17, m3, m9 + mova m3, m5 + pmaddubsw m18, m4, m9 + mova m4, m6 + pmaddubsw m19, m5, m10 + vpermb m5, m12, m0 ; 67 + vinserti32x8 m0, [srcq+ssq*0], 0 + pmaddubsw m20, m6, m10 + vpermb m6, m13, m0 ; 78 + paddw m15, m19 + pmaddubsw m19, m5, m11 + paddw m16, m20 + pmaddubsw m20, m6, m11 + paddw m17, m19 + paddw m18, m20 + paddsw m15, m17 + paddsw m16, m18 + pmulhrsw m15, m7 + pmulhrsw m16, m7 + packuswb m15, m16 + vpermq m15, m14, m15 +%ifidn %1, avg + mova ym16, [dstq+dsq*0] + vinserti32x8 m16, [dstq+dsq*1], 1 + pavgb m15, m16 +%endif + mova [dstq+dsq*0], ym15 + vextracti32x8 [dstq+dsq*1], m15, 1 + lea dstq, [dstq+dsq*2] + sub hd, 2 + jg .v_w32_loop + vzeroupper + RET + + SPEL_V_INIT %1, 64 + movu m2, [srcq+ssq*0] + movu m4, [srcq+ssq*1] + movu m6, [srcq+ssq*2] + add srcq, r5 + movu m13, [srcq+ssq*0] + movu m15, [srcq+ssq*1] + movu m17, [srcq+ssq*2] + add srcq, r5 + movu m0, [srcq+ssq*0] + punpcklbw m1, m2, m4 ; 01l + punpckhbw m2, m4 ; 01h + punpcklbw m3, m4, m6 ; 12l + punpckhbw m4, m6 ; 12h + punpcklbw m5, m6, m13 ; 23l + punpckhbw m6, m13 ; 23h + punpcklbw m12, m13, m15 ; 34l + punpckhbw m13, m15 ; 34h + punpcklbw m14, m15, m17 ; 45l + punpckhbw m15, m17 ; 45h + punpcklbw m16, m17, m0 ; 56l + punpckhbw m17, m0 ; 56h +%if WIN64 + movaps [rsp+8], xmm6 +%endif +.v_w64_loop: + movu m22, [srcq+ssq*1] + pmaddubsw m1, m8 ; a0l + pmaddubsw m18, m14, m10 ; a2l + lea srcq, [srcq+ssq*2] + pmaddubsw m2, m8 ; a0h + pmaddubsw m19, m15, m10 ; a2h + paddw m18, m1 + mova m1, m5 + paddw m19, m2 + mova m2, m6 + pmaddubsw m20, m5, m9 ; a1l + mova m5, m14 + pmaddubsw m21, m6, m9 ; a1h + mova m6, m15 + punpcklbw m14, m0, m22 ; 67l + punpckhbw m15, m0, m22 ; 67h + pmaddubsw m0, m14, m11 ; a3l + paddw m20, m0 + pmaddubsw m0, m15, m11 ; a3h + paddw m21, m0 + movu m0, [srcq+ssq*0] + paddsw m18, m20 + paddsw m19, m21 + pmaddubsw m3, m8 ; b0l + pmaddubsw m20, m16, m10 ; b2l + pmaddubsw m4, m8 ; b0h + pmaddubsw m21, m17, m10 ; b2h + pmulhrsw m18, m7 + pmulhrsw m19, m7 + paddw m20, m3 + mova m3, m12 + paddw m21, m4 + mova m4, m13 + packuswb m18, m19 +%ifidn %1, avg + pavgb m18, [dstq+dsq*0] +%endif + mova [dstq+dsq*0], m18 + pmaddubsw m18, m12, m9 ; b1l + mova m12, m16 + punpcklbw m16, m22, m0 ; 78l + pmaddubsw m19, m13, m9 ; b1h + mova m13, m17 + punpckhbw m17, m22, m0 ; 78h + pmaddubsw m22, m16, m11 ; b3l + paddw m18, m22 + pmaddubsw m22, m17, m11 ; b3h + paddw m19, m22 + paddsw m18, m20 + paddsw m19, m21 + pmulhrsw m18, m7 + pmulhrsw m19, m7 + packuswb m18, m19 +%ifidn %1, avg + pavgb m18, [dstq+dsq*1] +%endif + mova [dstq+dsq*1], m18 + lea dstq, [dstq+dsq*2] + sub hd, 2 + jg .v_w64_loop +%if WIN64 + movaps xmm6, [rsp+8] +%endif + vzeroupper + RET + + SPEL_HV_INIT %1, 4 + vbroadcasti32x4 ym2, [srcq+ssq*0] + vinserti32x4 m2, [srcq+ssq*1], 2 + vbroadcasti32x4 m6, [spel_h_shufA] + vinserti32x4 m2, [srcq+ssq*2], 3 ; _ 0 1 2 + add srcq, r5 + movu xm0, [srcq+ssq*0] + vinserti32x4 ym0, [srcq+ssq*1], 1 + vbroadcasti32x4 m7, [spel_h_shufB] + vinserti32x4 m0, [srcq+ssq*2], 2 + add srcq, r5 + vpbroadcastd m11, [myq+0] + vinserti32x4 m0, [srcq+ssq*0], 3 ; 3 4 5 6 + vpbroadcastd m12, [myq+4] + lea r6, [dsq*3] + mova m8, [spel_hv_perm4] + pshufb m4, m2, m6 + mova m1, m5 + vpdpbusd m1, m4, m9 + pshufb m4, m0, m6 + mova m3, m5 + vpdpbusd m3, m4, m9 + pshufb m2, m7 + pshufb m0, m7 + vpdpbusd m1, m2, m10 + vpdpbusd m3, m0, m10 + psrad m1, 7 + psrad m0, m3, 7 + packuswb m1, m0 ; _3 04 15 26 + vpermb m1, m8, m1 ; 0123 1234 2345 3456 +.hv_w4_loop: + movu xm4, [srcq+ssq*1] + vinserti32x4 ym4, [srcq+ssq*2], 1 + vinserti32x4 m4, [srcq+r5 ], 2 + lea srcq, [srcq+ssq*4] + vinserti32x4 m4, [srcq+ssq*0], 3 ; 7 8 9 a + mova m3, m5 + pshufb m2, m4, m6 + vpdpbusd m3, m2, m9 + mova m2, m5 + vpdpbusd m2, m1, m11 + pshufb m4, m7 + vpdpbusd m3, m4, m10 + psrad m3, 7 + packuswb m1, m0, m3 ; 37 48 59 6a + mova m0, m3 + vpermb m1, m8, m1 ; 4567 5678 6789 789a + vpdpbusd m2, m1, m12 + psrad m2, 7 + vpmovdw ym2, m2 + packuswb ym2, ym2 + vextracti32x4 xm3, ym2, 1 +%ifidn %1, avg + movd xmm4, [dstq+dsq*0] + pinsrd xmm4, [dstq+dsq*1], 1 + pavgb xm2, xmm4 + movd xmm4, [dstq+dsq*2] + pinsrd xmm4, [dstq+r6 ], 1 + pavgb xm3, xmm4 +%endif + movd [dstq+dsq*0], xm2 + pextrd [dstq+dsq*1], xm2, 1 + movd [dstq+dsq*2], xm3 + pextrd [dstq+r6 ], xm3, 1 + lea dstq, [dstq+dsq*4] + sub hd, 4 + jg .hv_w4_loop + RET + + SPEL_HV_INIT %1, 8 + vbroadcasti32x4 ym2, [srcq+ssq*0] + vinserti32x4 m2, [srcq+ssq*1], 2 + vbroadcasti32x4 m6, [spel_h_shufA] + vinserti32x4 m2, [srcq+ssq*2], 3 ; _ 0 1 2 + add srcq, r5 + movu xm0, [srcq+ssq*0] + vinserti32x4 ym0, [srcq+ssq*1], 1 + vbroadcasti32x4 m7, [spel_h_shufB] + vinserti32x4 m0, [srcq+ssq*2], 2 + add srcq, r5 + vpbroadcastd m11, [myq+0] + vinserti32x4 m0, [srcq+ssq*0], 3 ; 3 4 5 6 + vpbroadcastd m12, [myq+4] + lea r6, [dsq*3] + vbroadcasti32x4 m8, [spel_h_shufC] + mova m13, [spel_hv_perm8] + vpaddd m14, m13, [pb_4] {1to16} + PUT_8TAP_H 2, 1, 3, 4 + PUT_8TAP_H 0, 1, 3, 4 + packuswb m2, m0 ; _3 04 15 26 + vpermb m1, m13, m2 ; 0123 1234 2345 3456 (abcd) + vpermb m2, m14, m2 ; 0123 1234 2345 3456 (efgh) +.hv_w8_loop: + movu xm18, [srcq+ssq*1] + vinserti128 ym18, [srcq+ssq*2], 1 + vinserti32x4 m18, [srcq+r5 ], 2 + lea srcq, [srcq+ssq*4] + vinserti32x4 m18, [srcq+ssq*0], 3 ; 7 8 9 a + PUT_8TAP_H 18, 4, 16, 17 + mova m16, m5 + vpdpbusd m16, m1, m11 + mova m17, m5 + vpdpbusd m17, m2, m11 + packuswb m2, m0, m18 ; 37 48 59 6a + mova m0, m18 + vpermb m1, m13, m2 ; 4567 5678 6789 789a (abcd) + vpermb m2, m14, m2 ; 4567 5678 6789 789a (efgh) + vpdpbusd m16, m1, m12 + vpdpbusd m17, m2, m12 + packusdw m16, m17 + psrlw m16, 7 + vpmovuswb ym16, m16 + vextracti128 xm17, ym16, 1 +%ifidn %1, avg + movq xm18, [dstq+dsq*0] + movhps xm18, [dstq+dsq*1] + pavgb xm16, xm18 + movq xm18, [dstq+dsq*2] + movhps xm18, [dstq+r6 ] + pavgb xm17, xm18 +%endif + movq [dstq+dsq*0], xm16 + movhps [dstq+dsq*1], xm16 + movq [dstq+dsq*2], xm17 + movhps [dstq+r6 ], xm17 + lea dstq, [dstq+dsq*4] + sub hd, 4 + jg .hv_w8_loop + vzeroupper + RET + +cglobal vp9_%1_8tap_smooth_32hv_8, 4, 8, 0 + lea r6, [vp9_spel_filter_smooth-8] + mov r7d, 256*1 + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_16hv_8 %+ SUFFIX).main2 +cglobal vp9_%1_8tap_sharp_32hv_8, 4, 8, 0 + lea r6, [vp9_spel_filter_sharp-8] + mov r7d, 256*1 + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_16hv_8 %+ SUFFIX).main2 +cglobal vp9_%1_8tap_regular_32hv_8, 4, 8, 0, dst, ds, src, ss, h, mx, my + lea r6, [vp9_spel_filter_regular-8] + mov r7d, 256*1 + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_16hv_8 %+ SUFFIX).main2 +cglobal vp9_%1_8tap_smooth_64hv_8, 4, 8, 0 + lea r6, [vp9_spel_filter_smooth-8] + mov r7d, 256*3 + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_16hv_8 %+ SUFFIX).main2 +cglobal vp9_%1_8tap_sharp_64hv_8, 4, 8, 0 + lea r6, [vp9_spel_filter_sharp-8] + mov r7d, 256*3 + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_16hv_8 %+ SUFFIX).main2 +cglobal vp9_%1_8tap_regular_64hv_8, 4, 8, 0, dst, ds, src, ss, h, mx, my + lea r6, [vp9_spel_filter_regular-8] + mov r7d, 256*3 + jmp mangle(private_prefix %+ _vp9_%1_8tap_regular_16hv_8 %+ SUFFIX).main2 + + SPEL_HV_INIT %1, 16 + vpbroadcastw m11, [myq+0] + mova m6, [spel_h_perm16] + vpbroadcastw m12, [myq+2] + vpbroadcastd m8, [pb_4] + vpbroadcastw m13, [myq+4] + vpbroadcastd m15, [pw_256] + vpbroadcastw m14, [myq+6] + mova m19, [spel_hv_perm16] + vpandd m20, m19, [pw_m33] {1to16} ; even indices & ~32 + paddb m7, m6, m8 + lea r6d, [hq+r7] + paddb m8, m7 +%if WIN64 + push r8 +%endif +.hv_w16_loop0: + movu ym16, [srcq+ssq*0] ; 0 + movu ym17, [srcq+ssq*1] + lea r7, [srcq+r5] + vinserti32x8 m17, [srcq+ssq*2], 1 ; 1 2 + movu ym18, [r7+ssq*0] + mov r8, dstq + vinserti32x8 m18, [r7+ssq*1], 1 ; 3 4 + movu ym0, [r7+ssq*2] + add r7, r5 + vinserti32x8 m0, [r7+ssq*0], 1 ; 5 6 +INIT_YMM avx512icl + PUT_8TAP_H 16, 1, 2, 3, 1 +INIT_ZMM avx512icl + PUT_8TAP_H 17, 1, 2, 3, 1 + PUT_8TAP_H 18, 1, 2, 3, 1 + PUT_8TAP_H 0, 1, 2, 3, 1 + packuswb m16, m17 + packuswb m17, m18 + packuswb m18, m0 + vpermb m1, m20, m16 ; 01 12 + vpermb m2, m19, m17 ; 23 34 + vpermb m3, m19, m18 ; 45 56 +.hv_w16_loop: + movu ym18, [r7+ssq*1] + lea r7, [r7+ssq*2] + vinserti32x8 m18, [r7+ssq*0], 1 + PUT_8TAP_H 18, 4, 16, 17, 1 + pmaddubsw m16, m1, m11 ; a0 b0 + mova m1, m2 + pmaddubsw m17, m2, m12 ; a1 b1 + mova m2, m3 + pmaddubsw m3, m13 ; a2 b2 + packuswb m4, m0, m18 + paddw m16, m3 + vpermb m3, m19, m4 ; 67 78 + mova m0, m18 + pmaddubsw m4, m3, m14 ; a3 b3 + paddw m17, m4 + paddsw m16, m17 + pmulhrsw m16, m15 + vextracti32x8 ym17, m16, 1 + packuswb ym16, ym17 +%ifidn %1, avg + mova xm17, [r8+dsq*0] + vinserti128 ym17, [r8+dsq*1], 1 + pavgb ym16, ym17 +%endif + mova [r8+dsq*0], xm16 + vextracti128 [r8+dsq*1], ym16, 1 + lea r8, [r8+dsq*2] + sub hd, 2 + jg .hv_w16_loop + add srcq, 16 + add dstq, 16 + movzx hd, r6b + sub r6d, 1<<8 + jg .hv_w16_loop0 + vzeroupper +%if WIN64 + pop r8 +%endif + RET +%endmacro + +INIT_ZMM avx512icl +MC_AVX512 put +MC_AVX512 avg + +%endif diff --git a/libavcodec/x86/vp9mc_16bpp.asm b/libavcodec/x86/vp9mc_16bpp.asm index 9a462eaf8..d86a89ccb 100644 --- a/libavcodec/x86/vp9mc_16bpp.asm +++ b/libavcodec/x86/vp9mc_16bpp.asm @@ -24,8 +24,7 @@ SECTION_RODATA 32 -pd_64: times 8 dd 64 - +cextern pd_64 cextern pw_1023 cextern pw_4095 diff --git a/libavcodec/x86/vvc/Makefile b/libavcodec/x86/vvc/Makefile index aa59aa59c..0cebfb4e9 100644 --- a/libavcodec/x86/vvc/Makefile +++ b/libavcodec/x86/vvc/Makefile @@ -1,11 +1,13 @@ clean:: $(RM) $(CLEANSUFFIXES:%=libavcodec/x86/vvc/%) $(CLEANSUFFIXES:%=libavcodec/x86/h26x/%) -OBJS-$(CONFIG_VVC_DECODER) += x86/vvc/vvcdsp_init.o \ - x86/h26x/h2656dsp.o -X86ASM-OBJS-$(CONFIG_VVC_DECODER) += x86/vvc/vvc_alf.o \ - x86/vvc/vvc_dmvr.o \ - x86/vvc/vvc_mc.o \ - x86/vvc/vvc_of.o \ - x86/vvc/vvc_sad.o \ +X86ASM-OBJS-$(CONFIG_VVC_DECODER) += x86/vvc/dsp_init.o \ + x86/vvc/alf.o \ + x86/vvc/dmvr.o \ + x86/vvc/mc.o \ + x86/vvc/of.o \ + x86/vvc/sad.o \ + x86/vvc/sao.o \ + x86/vvc/sao_10bit.o \ + x86/h26x/h2656dsp.o \ x86/h26x/h2656_inter.o diff --git a/libavcodec/x86/vvc/vvc_alf.asm b/libavcodec/x86/vvc/alf.asm similarity index 82% rename from libavcodec/x86/vvc/vvc_alf.asm rename to libavcodec/x86/vvc/alf.asm index f69a69f05..22205c3ca 100644 --- a/libavcodec/x86/vvc/vvc_alf.asm +++ b/libavcodec/x86/vvc/alf.asm @@ -41,12 +41,10 @@ PARAM_SHUFFE 2 PARAM_SHUFFE 3 CLASSIFY_SHUFFE: times 2 db 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 -TRANSPOSE_PERMUTE: dd 0, 1, 4, 5, 2, 3, 6, 7 ARG_VAR_SHUFFE: times 2 db 0, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4 +cextern pd_64 dd448: times 8 dd 512 - 64 -dw64: times 8 dd 64 -dd2: times 8 dd 2 dw3: times 8 dd 3 dw5: times 8 dd 5 dd15: times 8 dd 15 @@ -60,15 +58,17 @@ SECTION .text ;%1-%3 out ;%4 clip or filter -%macro LOAD_LUMA_PARAMS_W16 4 - lea offsetq, [3 * xq] ;xq * ALF_NUM_COEFF_LUMA / ALF_BLOCK_SIZE - movu m%1, [%4q + 2 * offsetq + 0 * 32] ; 2 * for sizeof(int16_t) - movu m%2, [%4q + 2 * offsetq + 1 * 32] - movu m%3, [%4q + 2 * offsetq + 2 * 32] +%macro LOAD_LUMA_PARAMS 4 + movu m%1, [%4q + 0 * mmsize] + movu m%2, [%4q + 1 * mmsize] + movu m%3, [%4q + 2 * mmsize] + ; we process mmsize/(2*ALF_BLOCK_SIZE) alf blocks, + ; consuming ALF_NUM_COEFF_LUMA int16_t coeffs per alf block + add %4q, 3 * mmsize %endmacro %macro LOAD_LUMA_PARAMS_W16 6 - LOAD_LUMA_PARAMS_W16 %1, %2, %3, %4 + LOAD_LUMA_PARAMS %1, %2, %3, %4 ;m%1 = 03 02 01 00 ;m%2 = 07 06 05 04 ;m%3 = 11 10 09 08 @@ -85,18 +85,32 @@ SECTION .text vpermpd m%3, m%3, 10000111b ;11 08 05 02 %endmacro +%macro LOAD_LUMA_PARAMS_W8 5 + LOAD_LUMA_PARAMS %2, %3, %5, %4 + ;m%2 = 01 00 + ;m%3 = 03 02 + ;m%5 = 05 04 + + shufpd m%1, m%2, m%3, 10b ;03 00 + shufpd m%2, m%2, m%5, 01b ;04 01 + shufpd m%3, m%3, m%5, 10b ;05 02 +%endmacro + ; %1-%3 out ; %4 clip or filter ; %5-%6 tmp %macro LOAD_LUMA_PARAMS 6 +%if mmsize == 32 LOAD_LUMA_PARAMS_W16 %1, %2, %3, %4, %5, %6 +%else + LOAD_LUMA_PARAMS_W8 %1, %2, %3, %4, %5 +%endif %endmacro %macro LOAD_CHROMA_PARAMS 4 ; LOAD_CHROMA_PARAMS_W %+ WIDTH %1, %2, %3, %4 - movq xm%1, [%3q] + vpbroadcastq m%1, [%3q] movd xm%2, [%3q + 8] - vpbroadcastq m%1, xm%1 vpbroadcastq m%2, xm%2 %endmacro @@ -174,68 +188,62 @@ SECTION .text neg src_strideq %if LUMA - cmp vb_posq, 0 + cmp vb_posd, 0 je %%vb_bottom - cmp vb_posq, 4 + cmp vb_posd, 4 jne %%vb_end -%else - cmp vb_posq, 2 - jne %%vb_end - cmp %1, 2 - jge %%vb_bottom -%endif - %%vb_above: - ; above + ; above: vb_pos == 4 ; p1 = (y + i == vb_pos - 1) ? p0 : p1; ; p2 = (y + i == vb_pos - 1) ? p0 : p2; ; p3 = (y + i >= vb_pos - 2) ? p1 : p3; ; p4 = (y + i >= vb_pos - 2) ? p2 : p4; ; p5 = (y + i >= vb_pos - 3) ? p3 : p5; ; p6 = (y + i >= vb_pos - 3) ? p4 : p6; - dec vb_posq - cmp vb_posq, %1 + cmp %1, 3 cmove s1q, srcq cmove s2q, srcq - dec vb_posq - cmp vb_posq, %1 - cmovbe s3q, s1q - cmovbe s4q, s2q + cmp %1, 1 + cmova s3q, s1q + cmova s4q, s2q - dec vb_posq -%if LUMA - cmp vb_posq, %1 - cmovbe s5q, s3q - cmovbe s6q, s4q -%endif - add vb_posq, 3 + cmovae s5q, s3q + cmovae s6q, s4q jmp %%vb_end %%vb_bottom: - ; bottom + ; bottom: vb_pos == 0 ; p1 = (y + i == vb_pos ) ? p0 : p1; ; p2 = (y + i == vb_pos ) ? p0 : p2; ; p3 = (y + i <= vb_pos + 1) ? p1 : p3; ; p4 = (y + i <= vb_pos + 1) ? p2 : p4; ; p5 = (y + i <= vb_pos + 2) ? p3 : p5; ; p6 = (y + i <= vb_pos + 2) ? p4 : p6; - cmp vb_posq, %1 + cmp %1, 0 cmove s1q, srcq cmove s2q, srcq - inc vb_posq - cmp vb_posq, %1 - cmovae s3q, s1q - cmovae s4q, s2q + cmp %1, 2 + cmovb s3q, s1q + cmovb s4q, s2q - inc vb_posq -%if LUMA - cmp vb_posq, %1 - cmovae s5q, s3q - cmovae s6q, s4q + cmovbe s5q, s3q + cmovbe s6q, s4q +%else ; chroma + cmp vb_posd, 2 + jne %%vb_end + cmp %1, 2 + jge %%vb_bottom +%%vb_above: + cmp %1, 1 +%%vb_bottom: + cmove s1q, srcq + cmove s2q, srcq + + mov s3q, s1q + mov s4q, s2q %endif - sub vb_posq, 2 %%vb_end: %endmacro @@ -253,18 +261,18 @@ SECTION .text je %%near_below jmp %%no_vb %%near_above: - cmp vb_posq, 4 + cmp vb_posd, 4 je %%near_vb jmp %%no_vb %%near_below: - cmp vb_posq, 0 + cmp vb_posd, 0 je %%near_vb %else cmp %1, 0 je %%no_vb cmp %1, 3 je %%no_vb - cmp vb_posq, 2 + cmp vb_posd, 2 je %%near_vb %endif %%no_vb: @@ -287,8 +295,8 @@ SECTION .text ; output: m0, m1 ; temp: s0q...s1q %macro FILTER_VB 1 - vpbroadcastd m0, [dw64] - vpbroadcastd m1, [dw64] + vpbroadcastd m0, [pd_64] + vpbroadcastd m1, [pd_64] GET_SRCS %1 %if LUMA @@ -354,13 +362,8 @@ SECTION .text cmp %3, 8 jl .w4 STORE_PIXELS_W8 %1, %2 - cmp %3, 12 - %if ps == 2 - vpermq m%2, m%2, q0302 - %else - vpermq m%2, m%2, q0101 - %endif - jl .end + je .end + vextracti128 xm%2, m%2, 1 STORE_PIXELS_W4 %1, %2, 8 jmp .end .w4: @@ -368,120 +371,147 @@ SECTION .text .end: %endmacro -; STORE_PIXELS(dst, src, width) -%macro STORE_PIXELS 3 - %if ps == 1 - packuswb m%2, m%2 - vpermq m%2, m%2, 0x8 - %endif - +; STORE_PIXELS(dst, src, width, tmp reg) +%macro STORE_PIXELS 4 %ifidn %3, 16 + %if ps == 1 + vextracti128 xm%4, m%2, 1 + packuswb xm%2, xm%4 + %endif STORE_PIXELS_W16 %1, %2 %else %if LUMA + %if ps == 1 + packuswb xm%2, xm%2 + %endif STORE_PIXELS_W8 %1, %2 %else + %if ps == 1 + packuswb m%2, m%2 + %endif STORE_PIXELS_W8LE %1, %2, %3 %endif %endif %endmacro -%macro FILTER_16x4 1 +%macro FILTER_16x4 2 %if LUMA push clipq - push strideq - %define s1q clipq - %define s2q strideq -%else - %define s1q s5q - %define s2q s6q + %define s6q clipq %endif - %define s3q pixel_maxq - %define s4q offsetq - push xq - - xor xq, xq + xor xd, xd %%filter_16x4_loop: LOAD_PIXELS m2, [srcq] ;p0 - FILTER_VB xq + FILTER_VB xd ; sum += curr paddsw m0, m2 +%if ps != 1 ; clip to pixel CLIPW m0, m14, m15 +%endif - STORE_PIXELS dstq, 0, %1 + STORE_PIXELS dstq, 0, %1, 2 lea srcq, [srcq + src_strideq] lea dstq, [dstq + dst_strideq] - inc xq - cmp xq, 4 + inc xd + cmp xd, 4 jl %%filter_16x4_loop +%ifnidn %2, 0 mov xq, src_strideq neg xq - lea srcq, [srcq + xq * 4] + lea srcq, [srcq + xq * 4 + %2] mov xq, dst_strideq neg xq - lea dstq, [dstq + xq * 4] - - pop xq + lea dstq, [dstq + xq * 4 + %2] +%endif %if LUMA - pop strideq pop clipq %endif %endmacro -; FILTER(bpc, luma/chroma) -%macro ALF_FILTER 2 -%xdefine BPC %1 +; FILTER(bd, luma/chroma, bd of implementation to use) +%macro ALF_FILTER 3 %ifidn %2, luma %xdefine LUMA 1 %else %xdefine LUMA 0 %endif +%assign ps (%1+7) / 8 ; pixel size ; ****************************** -; void vvc_alf_filter_%2_%1bpc_avx2(uint8_t *dst, ptrdiff_t dst_stride, -; const uint8_t *src, ptrdiff_t src_stride, const ptrdiff_t width, cosnt ptr_diff_t height, -; const int16_t *filter, const int16_t *clip, ptrdiff_t stride, ptrdiff_t vb_pos, ptrdiff_t pixel_max); +; void ff_vvc_alf_filter_%2_%1_avx2(uint8_t *dst, ptrdiff_t dst_stride, +; const uint8_t *src, ptrdiff_t src_stride, int width, int height, +; const int16_t *filter, const int16_t *clip, int vb_pos); ; ****************************** -cglobal vvc_alf_filter_%2_%1bpc, 11, 15, 16, 0-0x30, dst, dst_stride, src, src_stride, width, height, filter, clip, stride, vb_pos, pixel_max, \ - offset, x, s5, s6 -%define ps (%1 / 8) ; pixel size - movd xm15, pixel_maxd - vpbroadcastw m15, xm15 +cglobal vvc_alf_filter_%2_%1 +%if !LUMA +; chroma does not use registers m5 and m8. Swap them to reduce the amount +; of nonvolatile registers on Win64. It also reduces codesize generally +; as encodings with high registers (m8-m15) take more bytes. + %if ps != 1 + SWAP 5,15 + SWAP 8,14 + %else + SWAP 5,12 + SWAP 8,13 + %endif +%elif WIN64 && (ps != 1) +; Swap m5 and m15, so that the register for the maximum pixel value +; ends up in a volatile register + SWAP 5,15 +%endif +%if ps != 1 + ; create pw_pixelmax for clipping + pcmpeqw m15, m15 + psrlw m15, 16 - %1 +%endif + +%if %1 != %3 + jmp vvc_alf_filter_%2_%3_prologue +%else +vvc_alf_filter_%2_%1_prologue: + PROLOGUE 9, 14+LUMA, 12+2*(ps!=1)+2*LUMA, dst, dst_stride, src, src_stride, width, height, filter, clip, vb_pos, \ + x, s1, s2, s3, s4, s5 +%if ps != 1 pxor m14, m14 +%endif .loop: push srcq push dstq push widthq - xor xq, xq .loop_w: - cmp widthq, 16 + cmp widthd, 16 jl .loop_w_end LOAD_PARAMS - FILTER_16x4 16 + FILTER_16x4 16, 16 * ps - add srcq, 16 * ps - add dstq, 16 * ps - add xq, 16 - sub widthq, 16 + sub widthd, 16 jmp .loop_w .loop_w_end: - cmp widthq, 0 + cmp widthd, 0 je .w_end +%if LUMA +SAVE_MM_PERMUTATION +INIT_XMM cpuname +LOAD_MM_PERMUTATION +%endif LOAD_PARAMS - FILTER_16x4 widthq + FILTER_16x4 widthd, 0 +%if LUMA +INIT_YMM cpuname +%endif .w_end: @@ -491,19 +521,17 @@ cglobal vvc_alf_filter_%2_%1bpc, 11, 15, 16, 0-0x30, dst, dst_stride, src, src_s lea srcq, [srcq + 4 * src_strideq] lea dstq, [dstq + 4 * dst_strideq] - lea filterq, [filterq + 2 * strideq] - lea clipq, [clipq + 2 * strideq] - - sub vb_posq, 4 - sub heightq, 4 + sub vb_posd, 4 + sub heightd, 4 jg .loop RET +%endif %endmacro -; FILTER(bpc) -%macro ALF_FILTER 1 - ALF_FILTER %1, luma - ALF_FILTER %1, chroma +; FILTER(bd, bd of implementation to use) +%macro ALF_FILTER 2 + ALF_FILTER %1, luma, %2 + ALF_FILTER %1, chroma, %2 %endmacro %define ALF_GRADIENT_BORDER 2 @@ -566,8 +594,7 @@ cglobal vvc_alf_classify_grad_%1bpc, 6, 14, 16, gradient_sum, src, src_stride, w pblendw m0, m1, m6, 0x55 paddw m0, m0 ; c - movu m1, [CLASSIFY_SHUFFE] - pshufb m1, m0, m1 ; d + pshufb m1, m0, [CLASSIFY_SHUFFE] ; d paddw m9, m14 ; n + s psubw m9, m0 ; (n + s) - c @@ -613,23 +640,23 @@ cglobal vvc_alf_classify_grad_%1bpc, 6, 14, 16, gradient_sum, src, src_stride, w ; SAVE_CLASSIFY_PARAM_W16(dest, src) %macro SAVE_CLASSIFY_PARAM_W16 2 + vpermq m%2, m%2, 11011000b lea tempq, [%1q + xq] movu [tempq], xm%2 - vperm2i128 m%2, m%2, m%2, 1 + vextracti128 xm%2, m%2, 1 movu [tempq + widthq], xm%2 %endmacro ; SAVE_CLASSIFY_PARAM_W8 %macro SAVE_CLASSIFY_PARAM_W8 2 movq [%1], xm%2 - vperm2i128 m%2, m%2, m%2, 1 - movq [%1 + widthq], xm%2 + movhps [%1 + widthq], xm%2 %endmacro ; SAVE_CLASSIFY_PARAM_W4 %macro SAVE_CLASSIFY_PARAM_W4 2 movd [%1], xm%2 - vperm2i128 m%2, m%2, m%2, 1 + punpckhqdq xm%2, xm%2 movd [%1 + widthq], xm%2 %endmacro @@ -639,10 +666,9 @@ cglobal vvc_alf_classify_grad_%1bpc, 6, 14, 16, gradient_sum, src, src_stride, w cmp wd, 8 jl %%w4 SAVE_CLASSIFY_PARAM_W8 tempq, %2 - vpermq m%2, m%2, 00010011b - add tempq, 8 - cmp wd, 8 je %%end + vextracti128 xm%2, m%2, 1 + add tempq, 8 %%w4: SAVE_CLASSIFY_PARAM_W4 tempq, %2 %%end: @@ -655,16 +681,15 @@ cglobal vvc_alf_classify_grad_%1bpc, 6, 14, 16, gradient_sum, src, src_stride, w movu m1, [gradq + sum_strideq] movu m2, [gradq + 2 * sum_strideq] - pcmpeqb m11, m11 movd xm13, yd - vpbroadcastd m13, xm13 movd xm12, vb_posd - vpbroadcastd m12, xm12 - pcmpeqd m13, m12 ; y == vb_pos - pandn m13, m11 ; y != vb_pos + pcmpeqb xm11, xm11 + pcmpeqd xm13, xm12 ; y == vb_pos + pxor xm13, xm11 ; y != vb_pos + vpbroadcastd m13, xm13 vpbroadcastd m14, [dw3] - pblendvb m14, m14, [dd2], m13 ; ac + paddd m14, m13 ; ac = (y != vb_pos) ? 2 : 3 pblendvb m3, m15, [gradq + sum_stride3q], m13 @@ -740,7 +765,6 @@ cglobal vvc_alf_classify_grad_%1bpc, 6, 14, 16, gradient_sum, src, src_stride, w paddd m11, m7, m7 paddd m11, m4 paddd m10, m11 - vpermq m10, m10, 11011000b SAVE_CLASSIFY_PARAM transpose_idx, 10 psrlq m10, m8, 32 @@ -760,12 +784,18 @@ cglobal vvc_alf_classify_grad_%1bpc, 6, 14, 16, gradient_sum, src, src_stride, w pblendvb m2, m5, m8, m1 ; hvd1 pblendvb m3, m6, m9, m1 ; hvd0 +%if ps != 1 ; high bit depth movd xm5, bit_depthd vpbroadcastd m5, xm5 +%endif ;*class_idx = arg_var[av_clip_uintp2(sum_hv * ac >> (BIT_DEPTH - 1), 4)]; pmulld m0, m14 ; sum_hv * ac +%if ps != 1 vpsrlvd m0, m0, m5 +%else + psrld m0, 8 +%endif pminsd m0, [dd15] movu m6, [ARG_VAR_SHUFFE] pshufb m6, m0 ; class_idx @@ -791,7 +821,6 @@ cglobal vvc_alf_classify_grad_%1bpc, 6, 14, 16, gradient_sum, src, src_stride, w pandn m1, m7 paddd m1, m1 ; dir1 << 1 paddd m6, m1 ; class_idx - vpermq m6, m6, 11011000b SAVE_CLASSIFY_PARAM class_idx, 6 %endmacro @@ -818,7 +847,9 @@ ALF_CLASSIFY_GRAD %1 cglobal vvc_alf_classify_%1bpc, 7, 15, 16, class_idx, transpose_idx, gradient_sum, width, height, vb_pos, bit_depth, \ x, y, grad, sum_stride, sum_stride3, temp, w - sub bit_depthq, 1 +%if ps != 1 + sub bit_depthd, 1 +%endif ; now we can use gradient to get class idx and transpose idx lea sum_strideq, [widthd + ALF_GRADIENT_BORDER * 2] @@ -868,9 +899,10 @@ cglobal vvc_alf_classify_%1bpc, 7, 15, 16, class_idx, transpose_idx, gradient_su %if ARCH_X86_64 %if HAVE_AVX2_EXTERNAL INIT_YMM avx2 -ALF_FILTER 16 -ALF_FILTER 8 +ALF_FILTER 12, 10 +ALF_FILTER 10, 10 ALF_CLASSIFY 16 +ALF_FILTER 8, 8 ALF_CLASSIFY 8 %endif %endif diff --git a/libavcodec/x86/vvc/vvc_dmvr.asm b/libavcodec/x86/vvc/dmvr.asm similarity index 100% rename from libavcodec/x86/vvc/vvc_dmvr.asm rename to libavcodec/x86/vvc/dmvr.asm diff --git a/libavcodec/x86/vvc/vvcdsp_init.c b/libavcodec/x86/vvc/dsp_init.c similarity index 57% rename from libavcodec/x86/vvc/vvcdsp_init.c rename to libavcodec/x86/vvc/dsp_init.c index 3a128b21e..680229479 100644 --- a/libavcodec/x86/vvc/vvcdsp_init.c +++ b/libavcodec/x86/vvc/dsp_init.c @@ -23,6 +23,7 @@ #include "config.h" +#include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/x86/cpu.h" #include "libavcodec/vvc/dec.h" @@ -30,64 +31,11 @@ #include "libavcodec/vvc/dsp.h" #include "libavcodec/x86/h26x/h2656dsp.h" -#define PUT_PROTOTYPE(name, depth, opt) \ -void ff_vvc_put_ ## name ## _ ## depth ## _##opt(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, int height, const int8_t *hf, const int8_t *vf, int width); - -#define PUT_PROTOTYPES(name, bitd, opt) \ - PUT_PROTOTYPE(name##2, bitd, opt) \ - PUT_PROTOTYPE(name##4, bitd, opt) \ - PUT_PROTOTYPE(name##8, bitd, opt) \ - PUT_PROTOTYPE(name##12, bitd, opt) \ - PUT_PROTOTYPE(name##16, bitd, opt) \ - PUT_PROTOTYPE(name##24, bitd, opt) \ - PUT_PROTOTYPE(name##32, bitd, opt) \ - PUT_PROTOTYPE(name##48, bitd, opt) \ - PUT_PROTOTYPE(name##64, bitd, opt) \ - PUT_PROTOTYPE(name##128, bitd, opt) - -#define PUT_BPC_PROTOTYPES(name, opt) \ - PUT_PROTOTYPES(name, 8, opt) \ - PUT_PROTOTYPES(name, 10, opt) \ - PUT_PROTOTYPES(name, 12, opt) - -#define PUT_TAP_PROTOTYPES(n, opt) \ - PUT_BPC_PROTOTYPES(n##tap_h, opt) \ - PUT_BPC_PROTOTYPES(n##tap_v, opt) \ - PUT_BPC_PROTOTYPES(n##tap_hv, opt) - -PUT_BPC_PROTOTYPES(pixels, sse4) -PUT_BPC_PROTOTYPES(pixels, avx2) - -PUT_TAP_PROTOTYPES(4, sse4) -PUT_TAP_PROTOTYPES(8, sse4) -PUT_TAP_PROTOTYPES(4, avx2) -PUT_TAP_PROTOTYPES(8, avx2) +#if ARCH_X86_64 #define bf(fn, bd, opt) fn##_##bd##_##opt #define BF(fn, bpc, opt) fn##_##bpc##bpc_##opt -#define AVG_BPC_PROTOTYPES(bpc, opt) \ -void BF(ff_vvc_avg, bpc, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, intptr_t width, intptr_t height, intptr_t pixel_max); \ -void BF(ff_vvc_w_avg, bpc, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, intptr_t width, intptr_t height, \ - intptr_t denom, intptr_t w0, intptr_t w1, intptr_t o0, intptr_t o1, intptr_t pixel_max); - -#define AVG_PROTOTYPES(bd, opt) \ -void bf(ff_vvc_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, int width, int height); \ -void bf(ff_vvc_w_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, int width, int height, \ - int denom, int w0, int w1, int o0, int o1); - -AVG_BPC_PROTOTYPES( 8, avx2) -AVG_BPC_PROTOTYPES(16, avx2) - -AVG_PROTOTYPES( 8, avx2) -AVG_PROTOTYPES(10, avx2) -AVG_PROTOTYPES(12, avx2) - - #define DMVR_PROTOTYPES(bd, opt) \ void ff_vvc_dmvr_##bd##_##opt(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, \ int height, intptr_t mx, intptr_t my, int width); \ @@ -102,66 +50,31 @@ DMVR_PROTOTYPES( 8, avx2) DMVR_PROTOTYPES(10, avx2) DMVR_PROTOTYPES(12, avx2) -#define OF_PROTOTYPES(bd, opt) \ -void ff_vvc_apply_bdof_##bd##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, int w, int h); \ - -OF_PROTOTYPES( 8, avx2) -OF_PROTOTYPES(10, avx2) -OF_PROTOTYPES(12, avx2) - -#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL -void ff_vvc_apply_bdof_avx2(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, int w, int h, int pixel_max); \ - -#define OF_FUNC(bd, opt) \ -void ff_vvc_apply_bdof_##bd##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, int w, int h) \ -{ \ - ff_vvc_apply_bdof##_##opt(dst, dst_stride, src0, src1, w, h, (1 << bd) - 1); \ -} \ - -OF_FUNC( 8, avx2) -OF_FUNC(10, avx2) -OF_FUNC(12, avx2) -#endif +#define OF_INIT(BD, OPT) do { \ +void ff_vvc_apply_bdof_## BD ## _ ## OPT(uint8_t *dst, ptrdiff_t dst_stride, \ + const int16_t *src0, const int16_t *src1, \ + int w, int h); \ + c->inter.apply_bdof = ff_vvc_apply_bdof_## BD ##_## OPT; \ +} while (0) #define ALF_BPC_PROTOTYPES(bpc, opt) \ -void BF(ff_vvc_alf_filter_luma, bpc, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ - const uint8_t *src, ptrdiff_t src_stride, ptrdiff_t width, ptrdiff_t height, \ - const int16_t *filter, const int16_t *clip, ptrdiff_t stride, ptrdiff_t vb_pos, ptrdiff_t pixel_max); \ -void BF(ff_vvc_alf_filter_chroma, bpc, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ - const uint8_t *src, ptrdiff_t src_stride, ptrdiff_t width, ptrdiff_t height, \ - const int16_t *filter, const int16_t *clip, ptrdiff_t stride, ptrdiff_t vb_pos, ptrdiff_t pixel_max); \ void BF(ff_vvc_alf_classify_grad, bpc, opt)(int *gradient_sum, \ const uint8_t *src, ptrdiff_t src_stride, intptr_t width, intptr_t height, intptr_t vb_pos); \ void BF(ff_vvc_alf_classify, bpc, opt)(int *class_idx, int *transpose_idx, const int *gradient_sum, \ intptr_t width, intptr_t height, intptr_t vb_pos, intptr_t bit_depth); \ -#define ALF_PROTOTYPES(bpc, bd, opt) \ -void bf(ff_vvc_alf_filter_luma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, \ - int width, int height, const int16_t *filter, const int16_t *clip, const int vb_pos); \ -void bf(ff_vvc_alf_filter_chroma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, \ - int width, int height, const int16_t *filter, const int16_t *clip, const int vb_pos); \ -void bf(ff_vvc_alf_classify, bd, opt)(int *class_idx, int *transpose_idx, \ - const uint8_t *src, ptrdiff_t src_stride, int width, int height, int vb_pos, int *gradient_tmp); \ - ALF_BPC_PROTOTYPES(8, avx2) ALF_BPC_PROTOTYPES(16, avx2) -ALF_PROTOTYPES(8, 8, avx2) -ALF_PROTOTYPES(16, 10, avx2) -ALF_PROTOTYPES(16, 12, avx2) - #if ARCH_X86_64 -#if HAVE_SSE4_EXTERNAL #define FW_PUT(name, depth, opt) \ -void ff_vvc_put_ ## name ## _ ## depth ## _##opt(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, \ +static void vvc_put_ ## name ## _ ## depth ## _##opt(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, \ int height, const int8_t *hf, const int8_t *vf, int width) \ { \ ff_h2656_put_## name ## _ ## depth ## _##opt(dst, 2 * MAX_PB_SIZE, src, srcstride, height, hf, vf, width); \ } +#if HAVE_SSE4_EXTERNAL #define FW_PUT_TAP(fname, bitd, opt ) \ FW_PUT(fname##4, bitd, opt ) \ FW_PUT(fname##8, bitd, opt ) \ @@ -230,39 +143,8 @@ FW_PUT_AVX2(12) FW_PUT_16BPC_AVX2(10) FW_PUT_16BPC_AVX2(12) -#define AVG_FUNCS(bpc, bd, opt) \ -void bf(ff_vvc_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, int width, int height) \ -{ \ - BF(ff_vvc_avg, bpc, opt)(dst, dst_stride, src0, src1, width, height, (1 << bd) - 1); \ -} \ -void bf(ff_vvc_w_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, int width, int height, \ - int denom, int w0, int w1, int o0, int o1) \ -{ \ - BF(ff_vvc_w_avg, bpc, opt)(dst, dst_stride, src0, src1, width, height, \ - denom, w0, w1, o0, o1, (1 << bd) - 1); \ -} - -AVG_FUNCS(8, 8, avx2) -AVG_FUNCS(16, 10, avx2) -AVG_FUNCS(16, 12, avx2) - #define ALF_FUNCS(bpc, bd, opt) \ -void bf(ff_vvc_alf_filter_luma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, \ - int width, int height, const int16_t *filter, const int16_t *clip, const int vb_pos) \ -{ \ - const int param_stride = (width >> 2) * ALF_NUM_COEFF_LUMA; \ - BF(ff_vvc_alf_filter_luma, bpc, opt)(dst, dst_stride, src, src_stride, width, height, \ - filter, clip, param_stride, vb_pos, (1 << bd) - 1); \ -} \ -void bf(ff_vvc_alf_filter_chroma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, \ - int width, int height, const int16_t *filter, const int16_t *clip, const int vb_pos) \ -{ \ - BF(ff_vvc_alf_filter_chroma, bpc, opt)(dst, dst_stride, src, src_stride, width, height, \ - filter, clip, 0, vb_pos,(1 << bd) - 1); \ -} \ -void bf(ff_vvc_alf_classify, bd, opt)(int *class_idx, int *transpose_idx, \ +static void bf(vvc_alf_classify, bd, opt)(int *class_idx, int *transpose_idx, \ const uint8_t *src, ptrdiff_t src_stride, int width, int height, int vb_pos, int *gradient_tmp) \ { \ BF(ff_vvc_alf_classify_grad, bpc, opt)(gradient_tmp, src, src_stride, width, height, vb_pos); \ @@ -275,8 +157,63 @@ ALF_FUNCS(16, 12, avx2) #endif +#define SAO_FILTER_FUNC(wd, bitd, opt) \ +void ff_vvc_sao_band_filter_##wd##_##bitd##_##opt(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + const int16_t *sao_offset_val, int sao_left_class, int width, int height); \ +void ff_vvc_sao_edge_filter_##wd##_##bitd##_##opt(uint8_t *_dst, const uint8_t *_src, ptrdiff_t stride_dst, \ + const int16_t *sao_offset_val, int eo, int width, int height); \ + +#define SAO_FILTER_FUNCS(bitd, opt) \ + SAO_FILTER_FUNC(8, bitd, opt) \ + SAO_FILTER_FUNC(16, bitd, opt) \ + SAO_FILTER_FUNC(32, bitd, opt) \ + SAO_FILTER_FUNC(48, bitd, opt) \ + SAO_FILTER_FUNC(64, bitd, opt) \ + SAO_FILTER_FUNC(80, bitd, opt) \ + SAO_FILTER_FUNC(96, bitd, opt) \ + SAO_FILTER_FUNC(112, bitd, opt) \ + SAO_FILTER_FUNC(128, bitd, opt) \ + +SAO_FILTER_FUNCS(8, avx2) +SAO_FILTER_FUNCS(10, avx2) +SAO_FILTER_FUNCS(12, avx2) + +#define SAO_FILTER_INIT(type, bitd, opt) do { \ + c->sao.type##_filter[0] = ff_vvc_sao_##type##_filter_8_##bitd##_##opt; \ + c->sao.type##_filter[1] = ff_vvc_sao_##type##_filter_16_##bitd##_##opt; \ + c->sao.type##_filter[2] = ff_vvc_sao_##type##_filter_32_##bitd##_##opt; \ + c->sao.type##_filter[3] = ff_vvc_sao_##type##_filter_48_##bitd##_##opt; \ + c->sao.type##_filter[4] = ff_vvc_sao_##type##_filter_64_##bitd##_##opt; \ + c->sao.type##_filter[5] = ff_vvc_sao_##type##_filter_80_##bitd##_##opt; \ + c->sao.type##_filter[6] = ff_vvc_sao_##type##_filter_96_##bitd##_##opt; \ + c->sao.type##_filter[7] = ff_vvc_sao_##type##_filter_112_##bitd##_##opt; \ + c->sao.type##_filter[8] = ff_vvc_sao_##type##_filter_128_##bitd##_##opt; \ +} while (0) + +#define SAO_INIT(bitd, opt) do { \ + SAO_FILTER_INIT(band, bitd, opt); \ + SAO_FILTER_INIT(edge, bitd, opt); \ +} while (0) + +#define AVG_INIT(bd, opt) do { \ +void bf(ff_vvc_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ + const int16_t *src0, const int16_t *src1, int width, int height);\ +void bf(ff_vvc_w_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ + const int16_t *src0, const int16_t *src1, int width, int height, \ + int denom, int w0, int w1, int o); \ + c->inter.avg = bf(ff_vvc_avg, bd, opt); \ + c->inter.w_avg = bf(ff_vvc_w_avg, bd, opt); \ +} while (0) + +#define DMVR_INIT(bd) do { \ + c->inter.dmvr[0][0] = ff_vvc_dmvr_##bd##_avx2; \ + c->inter.dmvr[0][1] = ff_vvc_dmvr_h_##bd##_avx2; \ + c->inter.dmvr[1][0] = ff_vvc_dmvr_v_##bd##_avx2; \ + c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_##bd##_avx2; \ +} while (0) + #define PEL_LINK(dst, C, W, idx1, idx2, name, D, opt) \ - dst[C][W][idx1][idx2] = ff_vvc_put_## name ## _ ## D ## _##opt; \ + dst[C][W][idx1][idx2] = vvc_put_## name ## _ ## D ## _##opt; \ dst ## _uni[C][W][idx1][idx2] = ff_h2656_put_uni_ ## name ## _ ## D ## _##opt; \ #define MC_TAP_LINKS(pointer, C, my, mx, fname, bitd, opt ) \ @@ -340,78 +277,96 @@ ALF_FUNCS(16, 12, avx2) MC_TAP_LINKS_16BPC_AVX2(LUMA, 8, bd); \ MC_TAP_LINKS_16BPC_AVX2(CHROMA, 4, bd); -#define AVG_INIT(bd, opt) do { \ - c->inter.avg = bf(ff_vvc_avg, bd, opt); \ - c->inter.w_avg = bf(ff_vvc_w_avg, bd, opt); \ -} while (0) - -#define DMVR_INIT(bd) do { \ - c->inter.dmvr[0][0] = ff_vvc_dmvr_##bd##_avx2; \ - c->inter.dmvr[0][1] = ff_vvc_dmvr_h_##bd##_avx2; \ - c->inter.dmvr[1][0] = ff_vvc_dmvr_v_##bd##_avx2; \ - c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_##bd##_avx2; \ -} while (0) - -#define OF_INIT(bd) do { \ - c->inter.apply_bdof = ff_vvc_apply_bdof_##bd##_avx2; \ -} while (0) - -#define ALF_INIT(bd) do { \ - c->alf.filter[LUMA] = ff_vvc_alf_filter_luma_##bd##_avx2; \ - c->alf.filter[CHROMA] = ff_vvc_alf_filter_chroma_##bd##_avx2; \ - c->alf.classify = ff_vvc_alf_classify_##bd##_avx2; \ -} while (0) - int ff_vvc_sad_avx2(const int16_t *src0, const int16_t *src1, int dx, int dy, int block_w, int block_h); #define SAD_INIT() c->inter.sad = ff_vvc_sad_avx2 + +#define ALF_INIT(bd, opt) do { \ +void bf(ff_vvc_alf_filter_luma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, int width, int height, \ + const int16_t *filter, const int16_t *clip, int vb_pos); \ +void bf(ff_vvc_alf_filter_chroma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, int width, int height, \ + const int16_t *filter, const int16_t *clip, int vb_pos); \ + c->alf.filter[LUMA] = bf(ff_vvc_alf_filter_luma, bd, opt); \ + c->alf.filter[CHROMA] = bf(ff_vvc_alf_filter_chroma, bd, opt); \ + c->alf.classify = bf(vvc_alf_classify, bd, opt); \ +} while (0) + #endif -void ff_vvc_dsp_init_x86(VVCDSPContext *const c, const int bd) + +#endif // ARCH_X86_64 + +av_cold void ff_vvc_dsp_init_x86(VVCDSPContext *const c, const int bd) { #if ARCH_X86_64 const int cpu_flags = av_get_cpu_flags(); switch (bd) { case 8: +#if HAVE_SSE4_EXTERNAL if (EXTERNAL_SSE4(cpu_flags)) { MC_LINK_SSE4(8); } +#endif +#if HAVE_AVX2_EXTERNAL if (EXTERNAL_AVX2_FAST(cpu_flags)) { - ALF_INIT(8); + // inter AVG_INIT(8, avx2); - MC_LINKS_AVX2(8); - OF_INIT(8); DMVR_INIT(8); + MC_LINKS_AVX2(8); + OF_INIT(8, avx2); SAD_INIT(); + + // filter + ALF_INIT(8, avx2); + SAO_INIT(8, avx2); } +#endif break; case 10: +#if HAVE_SSE4_EXTERNAL if (EXTERNAL_SSE4(cpu_flags)) { MC_LINK_SSE4(10); } +#endif +#if HAVE_AVX2_EXTERNAL if (EXTERNAL_AVX2_FAST(cpu_flags)) { - ALF_INIT(10); + // inter AVG_INIT(10, avx2); + DMVR_INIT(10); MC_LINKS_AVX2(10); MC_LINKS_16BPC_AVX2(10); - OF_INIT(10); - DMVR_INIT(10); + OF_INIT(10, avx2); SAD_INIT(); + + // filter + ALF_INIT(10, avx2); + SAO_INIT(10, avx2); } +#endif break; case 12: +#if HAVE_SSE4_EXTERNAL if (EXTERNAL_SSE4(cpu_flags)) { MC_LINK_SSE4(12); } +#endif +#if HAVE_AVX2_EXTERNAL if (EXTERNAL_AVX2_FAST(cpu_flags)) { - ALF_INIT(12); + // inter AVG_INIT(12, avx2); + DMVR_INIT(12); MC_LINKS_AVX2(12); MC_LINKS_16BPC_AVX2(12); - OF_INIT(12); - DMVR_INIT(12); + OF_INIT(12, avx2); SAD_INIT(); + + // filter + ALF_INIT(12, avx2); + SAO_INIT(12, avx2); } +#endif break; default: break; diff --git a/libavcodec/x86/vvc/vvc_mc.asm b/libavcodec/x86/vvc/mc.asm similarity index 59% rename from libavcodec/x86/vvc/vvc_mc.asm rename to libavcodec/x86/vvc/mc.asm index 30aa97c65..4f078ea8d 100644 --- a/libavcodec/x86/vvc/vvc_mc.asm +++ b/libavcodec/x86/vvc/mc.asm @@ -29,33 +29,27 @@ %define MAX_PB_SIZE 128 -SECTION_RODATA 32 +SECTION_RODATA %if ARCH_X86_64 %if HAVE_AVX2_EXTERNAL -pw_0 times 2 dw 0 -pw_1 times 2 dw 1 -pw_4 times 2 dw 4 -pw_12 times 2 dw 12 -pw_256 times 2 dw 256 - -%macro AVG_JMP_TABLE 3-* - %xdefine %1_%2_%3_table (%%table - 2*%4) - %xdefine %%base %1_%2_%3_table - %xdefine %%prefix mangle(private_prefix %+ _vvc_%1_%2bpc_%3) +%macro AVG_JMP_TABLE 4-* + %xdefine %1_%2_%4_table (%%table - 2*%5) + %xdefine %%base %1_%2_%4_table + %xdefine %%prefix mangle(private_prefix %+ _vvc_%1_%3_%4) %%table: - %rep %0 - 3 - dd %%prefix %+ .w%4 - %%base + %rep %0 - 4 + dd %%prefix %+ .w%5 - %%base %rotate 1 %endrep %endmacro -AVG_JMP_TABLE avg, 8, avx2, 2, 4, 8, 16, 32, 64, 128 -AVG_JMP_TABLE avg, 16, avx2, 2, 4, 8, 16, 32, 64, 128 -AVG_JMP_TABLE w_avg, 8, avx2, 2, 4, 8, 16, 32, 64, 128 -AVG_JMP_TABLE w_avg, 16, avx2, 2, 4, 8, 16, 32, 64, 128 +AVG_JMP_TABLE avg, 8, 8, avx2, 2, 4, 8, 16, 32, 64, 128 +AVG_JMP_TABLE avg, 16, 10, avx2, 2, 4, 8, 16, 32, 64, 128 +AVG_JMP_TABLE w_avg, 8, 8, avx2, 2, 4, 8, 16, 32, 64, 128 +AVG_JMP_TABLE w_avg, 16, 10, avx2, 2, 4, 8, 16, 32, 64, 128 SECTION .text @@ -64,27 +58,29 @@ SECTION .text %rep %3 %define off %%i AVG_LOAD_W16 0, off - %2 + %2 %1, 16 AVG_SAVE_W16 %1, 0, off AVG_LOAD_W16 1, off - %2 + %2 %1, 16 AVG_SAVE_W16 %1, 1, off %assign %%i %%i+1 %endrep %endmacro -%macro AVG_FN 2 ; bpc, op +%macro AVG_FN 2-3 1; bpc, op, instantiate implementation jmp wq +%if %3 +INIT_XMM cpuname .w2: movd xm0, [src0q] pinsrd xm0, [src0q + AVG_SRC_STRIDE], 1 movd xm1, [src1q] pinsrd xm1, [src1q + AVG_SRC_STRIDE], 1 - %2 + %2 %1, 2 AVG_SAVE_W2 %1 AVG_LOOP_END .w2 @@ -93,17 +89,18 @@ SECTION .text pinsrq xm0, [src0q + AVG_SRC_STRIDE], 1 movq xm1, [src1q] pinsrq xm1, [src1q + AVG_SRC_STRIDE], 1 - %2 + %2 %1, 4 AVG_SAVE_W4 %1 AVG_LOOP_END .w4 +INIT_YMM cpuname .w8: - vinserti128 m0, m0, [src0q], 0 + movu xm0, [src0q] + movu xm1, [src1q] vinserti128 m0, m0, [src0q + AVG_SRC_STRIDE], 1 - vinserti128 m1, m1, [src1q], 0 vinserti128 m1, m1, [src1q + AVG_SRC_STRIDE], 1 - %2 + %2 %1, 8 AVG_SAVE_W8 %1 AVG_LOOP_END .w8 @@ -130,27 +127,38 @@ SECTION .text .ret: RET +%endif %endmacro -%macro AVG 0 +%macro AVG 2 ; bpc, width paddsw m0, m1 pmulhrsw m0, m2 +%if %1 != 8 CLIPW m0, m3, m4 +%endif %endmacro -%macro W_AVG 0 +%macro W_AVG 2 ; bpc, width +%if %2 > 2 punpckhwd m5, m0, m1 pmaddwd m5, m3 paddd m5, m4 psrad m5, xm2 +%endif punpcklwd m0, m0, m1 pmaddwd m0, m3 paddd m0, m4 psrad m0, xm2 +%if %2 == 2 + packssdw m0, m0 +%else packssdw m0, m5 +%endif +%if %1 != 8 CLIPW m0, m6, m7 +%endif %endmacro %macro AVG_LOAD_W16 2 ; line, offset @@ -160,7 +168,7 @@ SECTION .text %macro AVG_SAVE_W2 1 ;bpc %if %1 == 16 - pextrd [dstq], xm0, 0 + movd [dstq], xm0 pextrd [dstq + strideq], xm0, 1 %else packuswb m0, m0 @@ -171,23 +179,23 @@ SECTION .text %macro AVG_SAVE_W4 1 ;bpc %if %1 == 16 - pextrq [dstq], xm0, 0 + movq [dstq], xm0 pextrq [dstq + strideq], xm0, 1 %else packuswb m0, m0 - pextrd [dstq], xm0, 0 + movd [dstq], xm0 pextrd [dstq + strideq], xm0, 1 %endif %endmacro %macro AVG_SAVE_W8 1 ;bpc %if %1 == 16 - vextracti128 [dstq], m0, 0 + movu [dstq], xm0 vextracti128 [dstq + strideq], m0, 1 %else packuswb m0, m0 vpermq m0, m0, 1000b - pextrq [dstq], xm0, 0 + movq [dstq], xm0 pextrq [dstq + strideq], xm0, 1 %endif %endmacro @@ -198,7 +206,7 @@ SECTION .text %else packuswb m0, m0 vpermq m0, m0, 1000b - vextracti128 [dstq + %2 * strideq + %3 * 16], m0, 0 + movu [dstq + %2 * strideq + %3 * 16], xm0 %endif %endmacro @@ -214,89 +222,87 @@ SECTION .text %define AVG_SRC_STRIDE MAX_PB_SIZE*2 -;void ff_vvc_avg_%1bpc_avx2(uint8_t *dst, ptrdiff_t dst_stride, -; const int16_t *src0, const int16_t *src1, intptr_t width, intptr_t height, intptr_t pixel_max); -%macro VVC_AVG_AVX2 1 -cglobal vvc_avg_%1bpc, 4, 7, 5, dst, stride, src0, src1, w, h, bd +;void ff_vvc_avg_%1_avx2(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src0, +; const int16_t *src1, int width, int height); +%macro VVC_AVG_AVX2 3 +cglobal vvc_avg_%2, 4, 7, 5, dst, stride, src0, src1, w, h movifnidn hd, hm + pcmpeqw m2, m2 +%if %1 != 8 pxor m3, m3 ; pixel min - vpbroadcastw m4, bdm ; pixel max - - movifnidn bdd, bdm - inc bdd - tzcnt bdd, bdd ; bit depth - - sub bdd, 8 - movd xm0, bdd - vpbroadcastd m1, [pw_4] - pminuw m0, m1 - vpbroadcastd m2, [pw_256] - psllw m2, xm0 ; shift +%endif lea r6, [avg_%1 %+ SUFFIX %+ _table] tzcnt wd, wm movsxd wq, dword [r6+wq*4] + psrlw m4, m2, 16-%2 ; pixel max + psubw m2, m4, m2 ; 1 << bpp add wq, r6 - AVG_FN %1, AVG + AVG_FN %1, AVG, %3 %endmacro -;void ff_vvc_w_avg_%1bpc_avx(uint8_t *dst, ptrdiff_t dst_stride, -; const int16_t *src0, const int16_t *src1, intptr_t width, intptr_t height, -; intptr_t denom, intptr_t w0, intptr_t w1, intptr_t o0, intptr_t o1, intptr_t pixel_max); -%macro VVC_W_AVG_AVX2 1 -cglobal vvc_w_avg_%1bpc, 4, 8, 8, dst, stride, src0, src1, w, h, t0, t1 +;void ff_vvc_w_avg_%2_avx(uint8_t *dst, ptrdiff_t dst_stride, +; const int16_t *src0, const int16_t *src1, int width, int height, +; int denom, intptr_t w0, int w1, int o); +%macro VVC_W_AVG_AVX2 3 +cglobal vvc_w_avg_%2, 4, 7+2*UNIX64, 6+2*(%1 != 8), dst, stride, src0, src1, w, h +%if UNIX64 + ; r6-r8 are volatile and not used for parameter passing + DECLARE_REG_TMP 6, 7, 8 +%else ; Win64 + ; r4-r6 are volatile and not used for parameter passing + DECLARE_REG_TMP 4, 5, 6 +%endif - movifnidn hd, hm - - movifnidn t0d, r8m ; w1 - shl t0d, 16 - mov t0w, r7m ; w0 - movd xm3, t0d + mov t1d, r6m ; denom + mov t0d, r9m ; o0 + o1 + movifnidn t2d, r8m ; w1 + add t1d, 15-%2 +%if %2 != 8 + shl t0d, %2 - 8 +%endif + movd xm2, t1d ; shift + inc t0d ; ((o0 + o1) << (BIT_DEPTH - 8)) + 1 + shl t2d, 16 + movd xm4, t0d + mov t2w, r7m ; w0 + movd xm3, t2d vpbroadcastd m3, xm3 ; w0, w1 - pxor m6, m6 ;pixel min - vpbroadcastw m7, r11m ;pixel max - - mov t1q, rcx ; save ecx - mov ecx, r11m - inc ecx ; bd - tzcnt ecx, ecx - sub ecx, 8 - mov t0d, r9m ; o0 - add t0d, r10m ; o1 - shl t0d, cl - inc t0d ;((o0 + o1) << (BIT_DEPTH - 8)) + 1 - - neg ecx - add ecx, 4 ; bd - 12 - cmovl ecx, [pw_0] - add ecx, 3 - add ecx, r6m - movd xm2, ecx ; shift - - dec ecx - shl t0d, cl - movd xm4, t0d - vpbroadcastd m4, xm4 ; offset - mov rcx, t1q ; restore ecx +%if %1 != 8 + pcmpeqw m7, m7 + pxor m6, m6 ; pixel min + psrlw m7, 16-%2 ; pixel max +%endif lea r6, [w_avg_%1 %+ SUFFIX %+ _table] tzcnt wd, wm movsxd wq, dword [r6+wq*4] + + pslld xm4, xm2 + psrad xm4, 1 + vpbroadcastd m4, xm4 ; offset + + movifnidn hd, hm + add wq, r6 - AVG_FN %1, W_AVG + AVG_FN %1, W_AVG, %3 %endmacro INIT_YMM avx2 -VVC_AVG_AVX2 16 +VVC_AVG_AVX2 16, 12, 0 -VVC_AVG_AVX2 8 +VVC_W_AVG_AVX2 16, 12, 0 -VVC_W_AVG_AVX2 16 +VVC_AVG_AVX2 16, 10, 1 -VVC_W_AVG_AVX2 8 +VVC_W_AVG_AVX2 16, 10, 1 + +VVC_AVG_AVX2 8, 8, 1 + +VVC_W_AVG_AVX2 8, 8, 1 %endif %endif diff --git a/libavcodec/x86/vvc/vvc_of.asm b/libavcodec/x86/vvc/of.asm similarity index 82% rename from libavcodec/x86/vvc/vvc_of.asm rename to libavcodec/x86/vvc/of.asm index 5893bfb23..eca52f244 100644 --- a/libavcodec/x86/vvc/vvc_of.asm +++ b/libavcodec/x86/vvc/of.asm @@ -32,9 +32,8 @@ SECTION_RODATA 32 pd_15 times 8 dd 15 pd_m15 times 8 dd -15 -pb_shuffle_w8 times 2 db 0, 1, 0xff, 0xff, 8, 9, 0xff, 0xff, 6, 7, 0xff, 0xff, 14, 15, 0xff, 0xff -pb_shuffle_w16 times 2 db 0, 1, 0xff, 0xff, 6, 7, 0xff, 0xff, 8, 9, 0xff, 0xff, 14, 15, 0xff, 0xff -pd_perm_w16 dd 0, 2, 1, 4, 3, 6, 5, 7 +pb_shuffle times 2 db 0, 1, 0xff, 0xff, 8, 9, 0xff, 0xff, 6, 7, 0xff, 0xff, 14, 15, 0xff, 0xff +pd_perm_w16 dd 0, 1, 2, 4, 3, 5, 6, 7 %if ARCH_X86_64 %if HAVE_AVX2_EXTERNAL @@ -70,45 +69,44 @@ INIT_YMM avx2 paddw %4, [src1q + (%5 + 1) * SRC_STRIDE + SRC_PS] paddsw %1, %4 ; src0[x] + src1[x] + bdof_offset pmulhrsw %1, m11 - CLIPW %1, m9, m10 %endmacro -%macro SAVE_8BPC 2 ; dst, src - packuswb m%2, m%2 - vpermq m%2, m%2, q0020 - - cmp wd, 16 - je %%w16 - movq %1, xm%2 - jmp %%wend -%%w16: - movu %1, xm%2 -%%wend: -%endmacro - -%macro SAVE_16BPC 2 ; dst, src - cmp wd, 16 - je %%w16 - movu %1, xm%2 - jmp %%wend -%%w16: - movu %1, m%2 -%%wend: -%endmacro - -%macro SAVE 2 ; dst, src +%macro SAVE 2-3 ""; dst, src, jump target cmp pixel_maxd, (1 << 8) - 1 jne %%save_16bpc - SAVE_8BPC %1, %2 + + packuswb m%2, m%2 + + cmp wd, 16 + je %%w16_8 + movq %1, xm%2 +%ifnidn %3, "" + jmp %3 +%else jmp %%end +%endif + %%save_16bpc: - SAVE_16BPC %1, %2 + CLIPW m%2, m9, m10 + cmp wd, 16 + jne %%w8_16 + movu %1, m%2 +%ifnidn %3, "" + jmp %3 +%else + jmp %%end +%endif + +%%w16_8: + vpermq m%2, m%2, q0020 +%%w8_16: + movu %1, xm%2 %%end: %endmacro ; [rsp + even * mmsize] are gradient_h[0] - gradient_h[1] ; [rsp + odd * mmsize] are gradient_v[0] - gradient_v[1] -%macro APPLY_BDOF_MIN_BLOCK 4 ; block_num, vx, vy, bd +%macro APPLY_BDOF_MIN_BLOCK 3-4 ""; block_num, vx, vy, jump target pxor m9, m9 movd xm10, pixel_maxd @@ -128,7 +126,7 @@ INIT_YMM avx2 SAVE [dstq + 2 * dsq], 6 APPLY_BDOF_MIN_BLOCK_LINE m6, %2, %3, m7, (%1) * 4 + 3 - SAVE [dstq + ds3q], 6 + SAVE [dstq + ds3q], 6, %4 %endmacro %macro SUM_MIN_BLOCK_W16 4 ; src/dst, shuffle, perm, tmp @@ -186,6 +184,9 @@ INIT_YMM avx2 DIFF ndiff, c1, c0, SHIFT2, t0 ; -diff + ; use t0, t1 as temporary buffers + mova t0, [pb_shuffle] + psignw m7, ndiff, m8 ; sgxdi psignw m9, ndiff, m6 ; sgydi psignw m10, m8, m6 ; sgxgy @@ -193,11 +194,9 @@ INIT_YMM avx2 pabsw m6, m6 ; sgy2 pabsw m8, m8 ; sgx2 - ; use t0, t1 as temporary buffers cmp wd, 16 je %%w16 - mova t0, [pb_shuffle_w8] SUM_MIN_BLOCK_W8 m6, t0, m11 SUM_MIN_BLOCK_W8 m7, t0, m11 SUM_MIN_BLOCK_W8 m8, t0, m11 @@ -206,7 +205,6 @@ INIT_YMM avx2 jmp %%wend %%w16: - mova t0, [pb_shuffle_w16] mova t1, [pd_perm_w16] SUM_MIN_BLOCK_W16 m6, t0, t1, m11 SUM_MIN_BLOCK_W16 m7, t0, t1, m11 @@ -231,14 +229,20 @@ INIT_YMM avx2 pshufhw m6, m6, q2301 paddw m8, m6, m11 ; 4 x (4sgx2, 4sgy2, 4sgxdi, 4sgydi) -%if (%1) == 0 || (%2) - ; pad for top and bottom +%if (%1) == 0 + ; pad for top and directly output to m12, m13 + paddw m12, m8, m8 + paddw m13, m10, m10 +%else +%if (%2) + ; pad for bottom paddw m8, m8 paddw m10, m10 %endif paddw m12, m8 paddw m13, m10 +%endif %endmacro @@ -252,21 +256,25 @@ INIT_YMM avx2 psrlw %3, %4 %endmacro -%macro LOG2 2 ; dst/src, offset - pextrw tmp0d, xm%1, %2 +%macro LOG2 3 ; dst, src, offset + pextrw tmp0d, xm%2, %3 bsr tmp0d, tmp0d - pinsrw xm%1, tmp0d, %2 +%if %3 != 0 + pinsrw xm%1, tmp0d, %3 +%else + movd xm%1, tmp0d +%endif %endmacro -%macro LOG2 1 ; dst/src - LOG2 %1, 0 - LOG2 %1, 1 - LOG2 %1, 2 - LOG2 %1, 3 - LOG2 %1, 4 - LOG2 %1, 5 - LOG2 %1, 6 - LOG2 %1, 7 +%macro LOG2 2 ; dst, src + LOG2 %1, %2, 0 + LOG2 %1, %2, 1 + LOG2 %1, %2, 2 + LOG2 %1, %2, 3 + LOG2 %1, %2, 4 + LOG2 %1, %2, 5 + LOG2 %1, %2, 6 + LOG2 %1, %2, 7 %endmacro ; %1: 4 (sgx2, sgy2, sgxdi, gydi) @@ -278,8 +286,7 @@ INIT_YMM avx2 punpcklqdq m8, m%1, m7 ; 4 (sgx2, sgy2) punpckhqdq m9, m%1, m7 ; 4 (sgxdi, sgydi) - mova m10, m8 - LOG2 10 ; 4 (log2(sgx2), log2(sgy2)) + LOG2 10, 8 ; 4 (log2(sgx2), log2(sgy2)) ; Promote to dword since vpsrlvw is AVX-512 only pmovsxwd m8, xm8 @@ -319,41 +326,59 @@ INIT_YMM avx2 movu m3, [src1q + 0 * SRC_STRIDE + SRC_PS] movu m4, [src1q + 1 * SRC_STRIDE + SRC_PS] - pxor m12, m12 - pxor m13, m13 - BDOF_PROF_GRAD 0, 0 %endif + BDOF_PROF_GRAD %1 * 4 + 1, 0 + BDOF_PROF_GRAD %1 * 4 + 2, 0 + +%if (%2) + BDOF_PROF_GRAD %1 * 4 + 3, %2 + BDOF_VX_VY 12, 13 +%if UNIX64 + APPLY_BDOF_MIN_BLOCK %1, m12, m13 +%else + APPLY_BDOF_MIN_BLOCK %1, m12, m13, .end +%endif + +%else mova m14, m12 mova m15, m13 pxor m12, m12 pxor m13, m13 - BDOF_PROF_GRAD %1 * 4 + 1, 0 - BDOF_PROF_GRAD %1 * 4 + 2, 0 - paddw m14, m12 - paddw m15, m13 - - pxor m12, m12 - pxor m13, m13 - BDOF_PROF_GRAD %1 * 4 + 3, %2 -%if (%2) == 0 + BDOF_PROF_GRAD %1 * 4 + 3, 0 BDOF_PROF_GRAD %1 * 4 + 4, 0 -%endif paddw m14, m12 paddw m15, m13 BDOF_VX_VY 14, 15 - APPLY_BDOF_MIN_BLOCK %1, m14, m15, bd + APPLY_BDOF_MIN_BLOCK %1, m14, m15 lea dstq, [dstq + 4 * dsq] +%endif %endmacro -;void ff_vvc_apply_bdof_%1(uint8_t *dst, const ptrdiff_t dst_stride, int16_t *src0, int16_t *src1, -; const int w, const int h, const int int pixel_max) -%macro BDOF_AVX2 0 -cglobal vvc_apply_bdof, 7, 10, 16, BDOF_STACK_SIZE*32, dst, ds, src0, src1, w, h, pixel_max, ds3, tmp0, tmp1 +%macro BDOF_WRAPPER 2 ; bpp, is_nonadjacent +;void ff_vvc_apply_bdof_%1(uint8_t *dst, const ptrdiff_t dst_stride, const int16_t *src0, +; const int16_t *src1, const int w, const int h) +cglobal vvc_apply_bdof_%1 + ; r6 is not used for parameter passing and is volatile both on UNIX64 + ; and Win64, so it can be freely used + mov r6d, (1<<%1)-1 +%if %2 + jmp vvc_apply_bdof_ %+ cpuname +%endif +%endmacro +%macro VVC_OF_AVX2 0 + BDOF_WRAPPER 12, 1 + BDOF_WRAPPER 8, 1 + BDOF_WRAPPER 10, 0 + +vvc_apply_bdof_ %+ cpuname: +; the prologue on Win64 is big (10 xmm regs need saving), so use PROLOGUE +; to avoid duplicating it. +PROLOGUE 6, 9, 16, BDOF_STACK_SIZE*32, dst, ds, src0, src1, w, h, pixel_max, ds3, tmp0 lea ds3q, [dsq * 3] sub src0q, SRC_STRIDE + SRC_PS sub src1q, SRC_STRIDE + SRC_PS @@ -363,7 +388,11 @@ cglobal vvc_apply_bdof, 7, 10, 16, BDOF_STACK_SIZE*32, dst, ds, src0, src1, w, h cmp hd, 16 je .h16 BDOF_MINI_BLOCKS 1, 1 +%if UNIX64 + RET +%else jmp .end +%endif .h16: BDOF_MINI_BLOCKS 1, 0 @@ -374,10 +403,6 @@ cglobal vvc_apply_bdof, 7, 10, 16, BDOF_STACK_SIZE*32, dst, ds, src0, src1, w, h RET %endmacro -%macro VVC_OF_AVX2 0 - BDOF_AVX2 -%endmacro - VVC_OF_AVX2 %endif ; HAVE_AVX2_EXTERNAL diff --git a/libavcodec/x86/vvc/vvc_sad.asm b/libavcodec/x86/vvc/sad.asm similarity index 100% rename from libavcodec/x86/vvc/vvc_sad.asm rename to libavcodec/x86/vvc/sad.asm diff --git a/libavcodec/x86/vvc/sao.asm b/libavcodec/x86/vvc/sao.asm new file mode 100644 index 000000000..5f7d7e535 --- /dev/null +++ b/libavcodec/x86/vvc/sao.asm @@ -0,0 +1,73 @@ +;****************************************************************************** +;* SIMD optimized SAO functions for VVC 8bit decoding +;* +;* Copyright (c) 2024 Shaun Loo +;* Copyright (c) 2024 Nuo Mi +;* +;* 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 +;****************************************************************************** + +%define MAX_PB_SIZE 128 +%include "libavcodec/x86/h26x/h2656_sao.asm" + +%macro VVC_SAO_BAND_FILTER 2 + H2656_SAO_BAND_FILTER vvc, %1, %2 +%endmacro + +%macro VVC_SAO_BAND_FILTER_FUNCS 0 +VVC_SAO_BAND_FILTER 8, 0 +VVC_SAO_BAND_FILTER 16, 1 +VVC_SAO_BAND_FILTER 32, 2 +VVC_SAO_BAND_FILTER 48, 2 +VVC_SAO_BAND_FILTER 64, 4 +VVC_SAO_BAND_FILTER 80, 4 +VVC_SAO_BAND_FILTER 96, 6 +VVC_SAO_BAND_FILTER 112, 6 +VVC_SAO_BAND_FILTER 128, 8 +%endmacro + +%if HAVE_AVX2_EXTERNAL +INIT_XMM avx2 +VVC_SAO_BAND_FILTER 8, 0 +VVC_SAO_BAND_FILTER 16, 1 +INIT_YMM avx2 +VVC_SAO_BAND_FILTER 32, 1 +VVC_SAO_BAND_FILTER 48, 1 +VVC_SAO_BAND_FILTER 64, 2 +VVC_SAO_BAND_FILTER 80, 2 +VVC_SAO_BAND_FILTER 96, 3 +VVC_SAO_BAND_FILTER 112, 3 +VVC_SAO_BAND_FILTER 128, 4 +%endif + +%macro VVC_SAO_EDGE_FILTER 2-3 + H2656_SAO_EDGE_FILTER vvc, %{1:-1} +%endmacro + +%if HAVE_AVX2_EXTERNAL +INIT_XMM avx2 +VVC_SAO_EDGE_FILTER 8, 0 +VVC_SAO_EDGE_FILTER 16, 1, a +INIT_YMM avx2 +VVC_SAO_EDGE_FILTER 32, 1, a +VVC_SAO_EDGE_FILTER 48, 1, u +VVC_SAO_EDGE_FILTER 64, 2, a +VVC_SAO_EDGE_FILTER 80, 2, u +VVC_SAO_EDGE_FILTER 96, 3, a +VVC_SAO_EDGE_FILTER 112, 3, u +VVC_SAO_EDGE_FILTER 128, 4, a +%endif diff --git a/libavcodec/x86/vvc/sao_10bit.asm b/libavcodec/x86/vvc/sao_10bit.asm new file mode 100644 index 000000000..ccf14a34a --- /dev/null +++ b/libavcodec/x86/vvc/sao_10bit.asm @@ -0,0 +1,75 @@ +;****************************************************************************** +;* SIMD optimized SAO functions for VVC 10/12bit decoding +;* +;* Copyright (c) 2024 Shaun Loo +;* Copyright (c) 2024 Nuo Mi +;* +;* 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 +;****************************************************************************** + +%define MAX_PB_SIZE 128 +%include "libavcodec/x86/h26x/h2656_sao_10bit.asm" + +%macro VVC_SAO_BAND_FILTER 3 + H2656_SAO_BAND_FILTER vvc, %1, %2, %3 +%endmacro + +%if HAVE_AVX2_EXTERNAL + +%macro VVC_SAO_BAND_FILTER_FUNCS_AVX2 1 + INIT_XMM avx2 + VVC_SAO_BAND_FILTER %1, 8, 1 + INIT_YMM avx2 + VVC_SAO_BAND_FILTER %1, 16, 1 + VVC_SAO_BAND_FILTER %1, 32, 2 + VVC_SAO_BAND_FILTER %1, 48, 3 + VVC_SAO_BAND_FILTER %1, 64, 4 + VVC_SAO_BAND_FILTER %1, 80, 5 + VVC_SAO_BAND_FILTER %1, 96, 6 + VVC_SAO_BAND_FILTER %1, 112, 7 + VVC_SAO_BAND_FILTER %1, 128, 8 +%endmacro + +VVC_SAO_BAND_FILTER_FUNCS_AVX2 10 +VVC_SAO_BAND_FILTER_FUNCS_AVX2 12 + +%endif ; HAVE_AVX2_EXTERNAL + +%macro VVC_SAO_EDGE_FILTER 3 + H2656_SAO_EDGE_FILTER vvc, %1, %2, %3 +%endmacro + +%if HAVE_AVX2_EXTERNAL + +%macro VVC_SAO_EDGE_FILTER_FUNCS_AVX2 1 + INIT_XMM avx2 + VVC_SAO_EDGE_FILTER %1, 8, 1 + INIT_YMM avx2 + VVC_SAO_EDGE_FILTER %1, 16, 1 + VVC_SAO_EDGE_FILTER %1, 32, 2 + VVC_SAO_EDGE_FILTER %1, 48, 3 + VVC_SAO_EDGE_FILTER %1, 64, 4 + VVC_SAO_EDGE_FILTER %1, 80, 5 + VVC_SAO_EDGE_FILTER %1, 96, 6 + VVC_SAO_EDGE_FILTER %1, 112, 7 + VVC_SAO_EDGE_FILTER %1, 128, 8 +%endmacro + +VVC_SAO_EDGE_FILTER_FUNCS_AVX2 10 +VVC_SAO_EDGE_FILTER_FUNCS_AVX2 12 + +%endif ; HAVE_AVX2_EXTERNAL diff --git a/libavcodec/x86/xvididct.asm b/libavcodec/x86/xvididct.asm index 4197551cd..c3bfabb95 100644 --- a/libavcodec/x86/xvididct.asm +++ b/libavcodec/x86/xvididct.asm @@ -24,7 +24,7 @@ ; ; More details at http://skal.planet-d.net/coding/dct.html ; -; ======= MMX and XMM forward discrete cosine transform ======= +; =========== XMM forward discrete cosine transform =========== ; ; Copyright(C) 2001 Peter Ross ; @@ -67,7 +67,6 @@ %include "libavutil/x86/x86util.asm" SECTION_RODATA -; Similar to tg_1_16 in MMX code tan1: times 8 dw 13036 tan2: times 8 dw 27146 tan3: times 8 dw 43790 @@ -91,7 +90,6 @@ iTab4: dw 0x4b42, 0x6254, 0xb4be, 0x9dac, 0x4b42, 0xd746, 0x4b42, 0xd746 dw 0x3b21, 0x14c3, 0x587e, 0xeb3d, 0x14c3, 0x587e, 0x14c3, 0xc4df dw 0x6862, 0x587e, 0x979e, 0xc4df, 0x3b21, 0x979e, 0x587e, 0x979e -; Similar to rounder_0 in MMX code ; 4 first similar, then: 4*8->6*16 5*8->4*16 6/7*8->5*16 walkenIdctRounders: times 4 dd 65536 times 4 dd 3597 @@ -99,9 +97,6 @@ walkenIdctRounders: times 4 dd 65536 times 4 dd 1203 times 4 dd 120 times 4 dd 512 - times 2 dd 0 - -pb_127: times 8 db 127 SECTION .text @@ -167,36 +162,47 @@ SECTION .text %define TAN1 xmm2 %endif -%macro JZ 2 - test %1, %1 +%macro JZ 3 + test %1%3, %1%3 jz .%2 %endmacro -%macro JNZ 2 - test %1, %1 +%macro JNZ 3 + test %1%3, %1%3 jnz .%2 %endmacro %macro TEST_ONE_ROW 4 ; src, reg, clear, arg %3 %4 - movq mm1, [%1] - por mm1, [%1 + 8] - paddusb mm1, mm0 - pmovmskb %2, mm1 + mova m1, [%1] + ; due to signed saturation, m1 is all zero iff m1 is all zero after packing + packsswb m1, m1 +%if ARCH_X86_64 + movq %2, m1 +%else + packsswb m1, m1 + movd %2, m1 +%endif %endmacro ;row1, row2, reg1, reg2, clear1, arg1, clear2, arg2 %macro TEST_TWO_ROWS 8 %5 %6 %7 %8 - movq mm1, [%1 + 0] - por mm1, [%1 + 8] - movq mm2, [%2 + 0] - por mm2, [%2 + 8] - paddusb mm1, mm0 - paddusb mm2, mm0 - pmovmskb %3, mm1 - pmovmskb %4, mm2 + mova m1, [%1] + packsswb m1, [%2] + packsswb m1, m1 +%if ARCH_X86_64 + movq %4, m1 + mov %3d, %4d + shr %4q, 32 +%else + packsswb m1, m1 + movd %3, m1 + mov %4, %3 + shr %4, 16 + and %3, 0xFFFF +%endif %endmacro ; IDCT pass on rows. @@ -499,16 +505,16 @@ SECTION .text %macro IDCT_SSE2 1 ; 0=normal 1=put 2=add %if %1 == 0 || ARCH_X86_32 - %define GPR0 r1d - %define GPR1 r2d - %define GPR2 r3d - %define GPR3 r4d + %define GPR0 r1 + %define GPR1 r2 + %define GPR2 r3 + %define GPR3 r4 %define NUM_GPRS 5 %else - %define GPR0 r3d - %define GPR1 r4d - %define GPR2 r5d - %define GPR3 r6d + %define GPR0 r3 + %define GPR1 r4 + %define GPR2 r5 + %define GPR3 r6 %define NUM_GPRS 7 %endif %if %1 == 0 @@ -527,34 +533,33 @@ cglobal xvid_idct_add, 0, NUM_GPRS, 8+7*ARCH_X86_64, dest, stride, block %xdefine BLOCK r0q %endif %endif - movq mm0, [pb_127] iMTX_MULT BLOCK + 0*16, iTab1, PUT_EVEN, ROW0, 0*16 iMTX_MULT BLOCK + 1*16, iTab2, PUT_ODD, ROW1, 1*16 iMTX_MULT BLOCK + 2*16, iTab3, PUT_EVEN, ROW2, 2*16 TEST_TWO_ROWS BLOCK + 3*16, BLOCK + 4*16, GPR0, GPR1, CLEAR_ODD, ROW3, CLEAR_EVEN, ROW4 ; a, c - JZ GPR0, col1 + JZ GPR0, col1, d iMTX_MULT BLOCK + 3*16, iTab4, PUT_ODD, ROW3, 3*16 .col1: TEST_TWO_ROWS BLOCK + 5*16, BLOCK + 6*16, GPR0, GPR2, CLEAR_ODD, ROW5, CLEAR_EVEN, ROW6 ; a, d TEST_ONE_ROW BLOCK + 7*16, GPR3, CLEAR_ODD, ROW7 ; esi iLLM_HEAD - JNZ GPR1, 2 - JNZ GPR0, 3 - JNZ GPR2, 4 - JNZ GPR3, 5 + JNZ GPR1, 2, d + JNZ GPR0, 3, d + JNZ GPR2, 4, d + JNZ GPR3, 5, q iLLM_PASS_SPARSE BLOCK, %1 jmp .6 .2: iMTX_MULT BLOCK + 4*16, iTab1, PUT_EVEN, ROW4 .3: iMTX_MULT BLOCK + 5*16, iTab4, PUT_ODD, ROW5, 4*16 - JZ GPR2, col2 + JZ GPR2, col2, d .4: iMTX_MULT BLOCK + 6*16, iTab3, PUT_EVEN, ROW6, 5*16 .col2: - JZ GPR3, col3 + JZ GPR3, col3, q .5: iMTX_MULT BLOCK + 7*16, iTab2, PUT_ODD, ROW7, 5*16 .col3: diff --git a/libavcodec/x86/xvididct_init.c b/libavcodec/x86/xvididct_init.c index fda34cc63..81575e93e 100644 --- a/libavcodec/x86/xvididct_init.c +++ b/libavcodec/x86/xvididct_init.c @@ -16,7 +16,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/x86/cpu.h" @@ -25,22 +24,14 @@ #include "xvididct.h" -av_cold void ff_xvid_idct_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth) +av_cold void ff_xvid_idct_init_x86(IDCTDSPContext *c) { -#if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); - if (high_bit_depth || - !(avctx->idct_algo == FF_IDCT_AUTO || - avctx->idct_algo == FF_IDCT_XVID)) - return; - if (EXTERNAL_SSE2(cpu_flags)) { c->idct_put = ff_xvid_idct_put_sse2; c->idct_add = ff_xvid_idct_add_sse2; c->idct = ff_xvid_idct_sse2; c->perm_type = FF_IDCT_PERM_SSE2; } -#endif /* HAVE_X86ASM */ } diff --git a/libavcodec/xbm_parser.c b/libavcodec/xbm_parser.c index 28aae49ee..50e448080 100644 --- a/libavcodec/xbm_parser.c +++ b/libavcodec/xbm_parser.c @@ -24,9 +24,13 @@ * XBM parser */ -#include "libavutil/common.h" +#include + +#include "libavutil/attributes.h" +#include "libavutil/avutil.h" #include "parser.h" +#include "parser_internal.h" typedef struct XBMParseContext { ParseContext pc; @@ -41,7 +45,7 @@ typedef struct XBMParseContext { #define END ((';' << 8) | ('\n' << 0)) -static int xbm_init(AVCodecParserContext *s) +static av_cold int xbm_init(AVCodecParserContext *s) { XBMParseContext *bpc = s->priv_data; @@ -97,10 +101,10 @@ static int xbm_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_xbm_parser = { - .codec_ids = { AV_CODEC_ID_XBM }, +const FFCodecParser ff_xbm_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_XBM), .priv_data_size = sizeof(XBMParseContext), - .parser_init = xbm_init, - .parser_parse = xbm_parse, - .parser_close = ff_parse_close, + .init = xbm_init, + .parse = xbm_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/xbmenc.c b/libavcodec/xbmenc.c index 5231d4691..8454fefe5 100644 --- a/libavcodec/xbmenc.c +++ b/libavcodec/xbmenc.c @@ -93,6 +93,5 @@ const FFCodec ff_xbm_encoder = { .p.id = AV_CODEC_ID_XBM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(xbm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_MONOWHITE, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_MONOWHITE), }; diff --git a/libavcodec/xfaceenc.c b/libavcodec/xfaceenc.c index 4998d42ea..640ef02df 100644 --- a/libavcodec/xfaceenc.c +++ b/libavcodec/xfaceenc.c @@ -217,7 +217,7 @@ const FFCodec ff_xface_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_XFACE, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_MONOWHITE, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_MONOWHITE), .priv_data_size = sizeof(XFaceContext), FF_CODEC_ENCODE_CB(xface_encode_frame), }; diff --git a/libavcodec/xma_parser.c b/libavcodec/xma_parser.c index dc8a197c6..5768b603d 100644 --- a/libavcodec/xma_parser.c +++ b/libavcodec/xma_parser.c @@ -21,7 +21,8 @@ * XMA2 audio parser */ -#include "parser.h" +#include "avcodec.h" +#include "parser_internal.h" typedef struct XMAParserContext{ int skip_packets; @@ -55,8 +56,8 @@ static int xma_parse(AVCodecParserContext *s1, AVCodecContext *avctx, return buf_size; } -const AVCodecParser ff_xma_parser = { - .codec_ids = { AV_CODEC_ID_XMA2 }, +const FFCodecParser ff_xma_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_XMA2), .priv_data_size = sizeof(XMAParserContext), - .parser_parse = xma_parse, + .parse = xma_parse, }; diff --git a/libavcodec/xvididct.c b/libavcodec/xvididct.c index 01072d80a..9d971a21d 100644 --- a/libavcodec/xvididct.c +++ b/libavcodec/xvididct.c @@ -32,7 +32,6 @@ #include "config.h" #include "libavutil/attributes.h" -#include "avcodec.h" #include "idctdsp.h" #include "xvididct.h" @@ -330,27 +329,16 @@ static void xvid_idct_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block) ff_add_pixels_clamped_c(block, dest, line_size); } -av_cold void ff_xvid_idct_init(IDCTDSPContext *c, AVCodecContext *avctx) +av_cold void ff_xvid_idct_init(IDCTDSPContext *c) { - const unsigned high_bit_depth = avctx->bits_per_raw_sample > 8; + c->idct_put = xvid_idct_put; + c->idct_add = xvid_idct_add; + c->idct = ff_xvid_idct; + c->perm_type = FF_IDCT_PERM_NONE; - if (high_bit_depth || avctx->lowres || - !(avctx->idct_algo == FF_IDCT_AUTO || - avctx->idct_algo == FF_IDCT_XVID)) - return; - - if (avctx->idct_algo == FF_IDCT_XVID) { - c->idct_put = xvid_idct_put; - c->idct_add = xvid_idct_add; - c->idct = ff_xvid_idct; - c->perm_type = FF_IDCT_PERM_NONE; - } - -#if ARCH_X86 - ff_xvid_idct_init_x86(c, avctx, high_bit_depth); +#if ARCH_X86 && HAVE_X86ASM + ff_xvid_idct_init_x86(c); #elif ARCH_MIPS - ff_xvid_idct_init_mips(c, avctx, high_bit_depth); + ff_xvid_idct_init_mips(c); #endif - - ff_init_scantable_permutation(c->idct_permutation, c->perm_type); } diff --git a/libavcodec/xvididct.h b/libavcodec/xvididct.h index e0bc1a2b9..496071a03 100644 --- a/libavcodec/xvididct.h +++ b/libavcodec/xvididct.h @@ -21,16 +21,13 @@ #include -#include "avcodec.h" #include "idctdsp.h" void ff_xvid_idct(int16_t *const in); -void ff_xvid_idct_init(IDCTDSPContext *c, AVCodecContext *avctx); +void ff_xvid_idct_init(IDCTDSPContext *c); -void ff_xvid_idct_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth); -void ff_xvid_idct_init_mips(IDCTDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth); +void ff_xvid_idct_init_x86(IDCTDSPContext *c); +void ff_xvid_idct_init_mips(IDCTDSPContext *c); #endif /* AVCODEC_XVIDIDCT_H */ diff --git a/libavcodec/xwd_parser.c b/libavcodec/xwd_parser.c index ab5fe8607..5d7b2f10b 100644 --- a/libavcodec/xwd_parser.c +++ b/libavcodec/xwd_parser.c @@ -26,6 +26,7 @@ #include "libavutil/intreadwrite.h" #include "parser.h" +#include "parser_internal.h" #include "xwd.h" typedef struct XWDParseContext { @@ -95,9 +96,9 @@ static int xwd_parse(AVCodecParserContext *s, AVCodecContext *avctx, return next; } -const AVCodecParser ff_xwd_parser = { - .codec_ids = { AV_CODEC_ID_XWD }, +const FFCodecParser ff_xwd_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_XWD), .priv_data_size = sizeof(XWDParseContext), - .parser_parse = xwd_parse, - .parser_close = ff_parse_close, + .parse = xwd_parse, + .close = ff_parse_close, }; diff --git a/libavcodec/xwdenc.c b/libavcodec/xwdenc.c index 40bee2010..1d8b7d900 100644 --- a/libavcodec/xwdenc.c +++ b/libavcodec/xwdenc.c @@ -219,26 +219,12 @@ const FFCodec ff_xwd_encoder = { .p.id = AV_CODEC_ID_XWD, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(xwd_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGRA, - AV_PIX_FMT_RGBA, - AV_PIX_FMT_ARGB, - AV_PIX_FMT_ABGR, - AV_PIX_FMT_RGB24, - AV_PIX_FMT_BGR24, - AV_PIX_FMT_RGB565BE, - AV_PIX_FMT_RGB565LE, - AV_PIX_FMT_BGR565BE, - AV_PIX_FMT_BGR565LE, - AV_PIX_FMT_RGB555BE, - AV_PIX_FMT_RGB555LE, - AV_PIX_FMT_BGR555BE, - AV_PIX_FMT_BGR555LE, - AV_PIX_FMT_RGB8, - AV_PIX_FMT_BGR8, - AV_PIX_FMT_RGB4_BYTE, - AV_PIX_FMT_BGR4_BYTE, - AV_PIX_FMT_PAL8, - AV_PIX_FMT_GRAY8, - AV_PIX_FMT_MONOWHITE, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_BGRA, AV_PIX_FMT_RGBA, AV_PIX_FMT_ARGB, + AV_PIX_FMT_ABGR, AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, + AV_PIX_FMT_RGB565BE, AV_PIX_FMT_RGB565LE, AV_PIX_FMT_BGR565BE, + AV_PIX_FMT_BGR565LE, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_RGB555LE, + AV_PIX_FMT_BGR555BE, AV_PIX_FMT_BGR555LE, + AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, + AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, + AV_PIX_FMT_PAL8, AV_PIX_FMT_GRAY8, AV_PIX_FMT_MONOWHITE), }; diff --git a/libavcodec/y41penc.c b/libavcodec/y41penc.c index e86769da6..b0044b35e 100644 --- a/libavcodec/y41penc.c +++ b/libavcodec/y41penc.c @@ -85,6 +85,5 @@ const FFCodec ff_y41p_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = y41p_encode_init, FF_CODEC_ENCODE_CB(y41p_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV411P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV411P), }; diff --git a/libavcodec/yop.c b/libavcodec/yop.c index 77b8d6e05..225bc71f5 100644 --- a/libavcodec/yop.c +++ b/libavcodec/yop.c @@ -232,12 +232,6 @@ static int yop_decode_frame(AVCodecContext *avctx, AVFrame *rframe, (palette[i + firstcolor] >> 6) & 0x30303; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - for (y = 0; y < avctx->height; y += 2) { for (x = 0; x < avctx->width; x += 2) { if (s->srcptr - avpkt->data >= avpkt->size) { diff --git a/libavcodec/yuv4enc.c b/libavcodec/yuv4enc.c index 2a9d3442c..093038142 100644 --- a/libavcodec/yuv4enc.c +++ b/libavcodec/yuv4enc.c @@ -76,6 +76,6 @@ const FFCodec ff_yuv4_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_YUV4, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), FF_CODEC_ENCODE_CB(yuv4_encode_frame), }; diff --git a/libavcodec/zerocodec.c b/libavcodec/zerocodec.c index 48f78d1d8..a19ca6283 100644 --- a/libavcodec/zerocodec.c +++ b/libavcodec/zerocodec.c @@ -22,6 +22,7 @@ #include "codec_internal.h" #include "decode.h" #include "zlib_wrapper.h" +#include "libavutil/attributes.h" #include "libavutil/common.h" typedef struct ZeroCodecContext { @@ -126,7 +127,7 @@ static av_cold int zerocodec_decode_init(AVCodecContext *avctx) return ff_inflate_init(&zc->zstream, avctx); } -static void zerocodec_decode_flush(AVCodecContext *avctx) +static av_cold void zerocodec_decode_flush(AVCodecContext *avctx) { ZeroCodecContext *zc = avctx->priv_data; diff --git a/libavcodec/zmbv.c b/libavcodec/zmbv.c index 6ece6e301..fe12f3f84 100644 --- a/libavcodec/zmbv.c +++ b/libavcodec/zmbv.c @@ -152,7 +152,7 @@ static int zmbv_decode_xor_8(ZmbvContext *c) prev += c->width * c->bh; } if (src - c->decomp_buf != c->decomp_len) - av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n", + av_log(c->avctx, AV_LOG_ERROR, "Used %td of %i bytes\n", src-c->decomp_buf, c->decomp_len); return 0; } @@ -230,7 +230,7 @@ static int zmbv_decode_xor_16(ZmbvContext *c) prev += c->width * c->bh; } if (src - c->decomp_buf != c->decomp_len) - av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n", + av_log(c->avctx, AV_LOG_ERROR, "Used %td of %i bytes\n", src-c->decomp_buf, c->decomp_len); return 0; } @@ -317,7 +317,7 @@ static int zmbv_decode_xor_24(ZmbvContext *c) prev += stride * c->bh; } if (src - c->decomp_buf != c->decomp_len) - av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n", + av_log(c->avctx, AV_LOG_ERROR, "Used %td of %i bytes\n", src-c->decomp_buf, c->decomp_len); return 0; } @@ -396,7 +396,7 @@ static int zmbv_decode_xor_32(ZmbvContext *c) prev += c->width * c->bh; } if (src - c->decomp_buf != c->decomp_len) - av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n", + av_log(c->avctx, AV_LOG_ERROR, "Used %td of %i bytes\n", src-c->decomp_buf, c->decomp_len); return 0; } diff --git a/libavcodec/zmbvenc.c b/libavcodec/zmbvenc.c index 04889b97d..17eb3caa2 100644 --- a/libavcodec/zmbvenc.c +++ b/libavcodec/zmbvenc.c @@ -410,6 +410,17 @@ static av_cold int encode_init(AVCodecContext *avctx) return ff_deflate_init(&c->zstream, lvl, avctx); } +static const enum AVPixelFormat zmbv_pixfmts_list[] = { + AV_PIX_FMT_PAL8, + AV_PIX_FMT_RGB555LE, + AV_PIX_FMT_RGB565LE, +#ifdef ZMBV_ENABLE_24BPP + AV_PIX_FMT_BGR24, +#endif + AV_PIX_FMT_BGR0, + AV_PIX_FMT_NONE +}; + const FFCodec ff_zmbv_encoder = { .p.name = "zmbv", CODEC_LONG_NAME("Zip Motion Blocks Video"), @@ -420,13 +431,6 @@ const FFCodec ff_zmbv_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_PAL8, - AV_PIX_FMT_RGB555LE, - AV_PIX_FMT_RGB565LE, -#ifdef ZMBV_ENABLE_24BPP - AV_PIX_FMT_BGR24, -#endif //ZMBV_ENABLE_24BPP - AV_PIX_FMT_BGR0, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS_ARRAY(zmbv_pixfmts_list), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavdevice/Makefile b/libavdevice/Makefile index c30449201..a226368d1 100644 --- a/libavdevice/Makefile +++ b/libavdevice/Makefile @@ -18,7 +18,6 @@ OBJS-$(CONFIG_ALSA_OUTDEV) += alsa_enc.o alsa.o OBJS-$(CONFIG_ANDROID_CAMERA_INDEV) += android_camera.o OBJS-$(CONFIG_AUDIOTOOLBOX_OUTDEV) += audiotoolbox.o OBJS-$(CONFIG_AVFOUNDATION_INDEV) += avfoundation.o -OBJS-$(CONFIG_BKTR_INDEV) += bktr.o OBJS-$(CONFIG_CACA_OUTDEV) += caca.o OBJS-$(CONFIG_DECKLINK_OUTDEV) += decklink_enc.o decklink_enc_c.o decklink_common.o OBJS-$(CONFIG_DECKLINK_INDEV) += decklink_dec.o decklink_dec_c.o decklink_common.o @@ -35,14 +34,12 @@ OBJS-$(CONFIG_JACK_INDEV) += jack.o timefilter.o OBJS-$(CONFIG_KMSGRAB_INDEV) += kmsgrab.o OBJS-$(CONFIG_LAVFI_INDEV) += lavfi.o OBJS-$(CONFIG_OPENAL_INDEV) += openal-dec.o -OBJS-$(CONFIG_OPENGL_OUTDEV) += opengl_enc.o OBJS-$(CONFIG_OSS_INDEV) += oss_dec.o oss.o OBJS-$(CONFIG_OSS_OUTDEV) += oss_enc.o oss.o OBJS-$(CONFIG_PULSE_INDEV) += pulse_audio_dec.o \ pulse_audio_common.o timefilter.o OBJS-$(CONFIG_PULSE_OUTDEV) += pulse_audio_enc.o \ pulse_audio_common.o -OBJS-$(CONFIG_SDL2_OUTDEV) += sdl2.o OBJS-$(CONFIG_SNDIO_INDEV) += sndio_dec.o sndio.o OBJS-$(CONFIG_SNDIO_OUTDEV) += sndio_enc.o sndio.o OBJS-$(CONFIG_V4L2_INDEV) += v4l2.o v4l2-common.o timefilter.o diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c index 9b9a9146c..573595f41 100644 --- a/libavdevice/alldevices.c +++ b/libavdevice/alldevices.c @@ -20,8 +20,8 @@ #include "libavutil/attributes.h" #include "libavutil/attributes_internal.h" +#include "libavformat/avformat_internal.h" #include "libavformat/demux.h" -#include "libavformat/internal.h" #include "libavformat/mux.h" #include "avdevice.h" @@ -32,7 +32,6 @@ extern const FFOutputFormat ff_alsa_muxer; extern const FFInputFormat ff_android_camera_demuxer; extern const FFOutputFormat ff_audiotoolbox_muxer; extern const FFInputFormat ff_avfoundation_demuxer; -extern const FFInputFormat ff_bktr_demuxer; extern const FFOutputFormat ff_caca_muxer; extern const FFInputFormat ff_decklink_demuxer; extern const FFOutputFormat ff_decklink_muxer; @@ -45,12 +44,10 @@ extern const FFInputFormat ff_jack_demuxer; extern const FFInputFormat ff_kmsgrab_demuxer; extern const FFInputFormat ff_lavfi_demuxer; extern const FFInputFormat ff_openal_demuxer; -extern const FFOutputFormat ff_opengl_muxer; extern const FFInputFormat ff_oss_demuxer; extern const FFOutputFormat ff_oss_muxer; extern const FFInputFormat ff_pulse_demuxer; extern const FFOutputFormat ff_pulse_muxer; -extern const FFOutputFormat ff_sdl2_muxer; extern const FFInputFormat ff_sndio_demuxer; extern const FFOutputFormat ff_sndio_muxer; extern const FFInputFormat ff_v4l2_demuxer; diff --git a/libavdevice/alsa.c b/libavdevice/alsa.c index d62ccc09c..cfdb28ff4 100644 --- a/libavdevice/alsa.c +++ b/libavdevice/alsa.c @@ -127,7 +127,8 @@ switch(format) {\ case FORMAT_F32: s->reorder_func = alsa_reorder_f32_out_ ##layout; break;\ } -static av_cold int find_reorder_func(AlsaData *s, int codec_id, AVChannelLayout *layout, int out) +static av_cold int find_reorder_func(AlsaData *s, int codec_id, + const AVChannelLayout *layout, int out) { int format; @@ -172,10 +173,9 @@ static av_cold int find_reorder_func(AlsaData *s, int codec_id, AVChannelLayout av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, unsigned int *sample_rate, - int channels, enum AVCodecID *codec_id) + const AVChannelLayout *layout, enum AVCodecID *codec_id) { AlsaData *s = ctx->priv_data; - AVChannelLayout *layout = &ctx->streams[0]->codecpar->ch_layout; const char *audio_device; int res, flags = 0; snd_pcm_format_t format; @@ -193,7 +193,7 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, av_log(ctx, AV_LOG_ERROR, "sample format 0x%04x is not supported\n", *codec_id); return AVERROR(ENOSYS); } - s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * channels; + s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * layout->nb_channels; if (ctx->flags & AVFMT_FLAG_NONBLOCK) { flags = SND_PCM_NONBLOCK; @@ -240,10 +240,10 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, goto fail; } - res = snd_pcm_hw_params_set_channels(h, hw_params, channels); + res = snd_pcm_hw_params_set_channels(h, hw_params, layout->nb_channels); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set channel count to %d (%s)\n", - channels, snd_strerror(res)); + layout->nb_channels, snd_strerror(res)); goto fail; } @@ -277,7 +277,7 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, snd_pcm_hw_params_free(hw_params); - if (channels > 2 && layout->order != AV_CHANNEL_ORDER_UNSPEC) { + if (layout->nb_channels > 2 && layout->order != AV_CHANNEL_ORDER_UNSPEC) { if (find_reorder_func(s, *codec_id, layout, mode == SND_PCM_STREAM_PLAYBACK) < 0) { char name[128]; av_channel_layout_describe(layout, name, sizeof(name)); diff --git a/libavdevice/alsa.h b/libavdevice/alsa.h index 07783c983..d3dfa478c 100644 --- a/libavdevice/alsa.h +++ b/libavdevice/alsa.h @@ -35,6 +35,7 @@ #include "libavutil/log.h" #include "timefilter.h" #include "avdevice.h" +#include "version.h" /* XXX: we make the assumption that the soundcard accepts this format */ /* XXX: find better solution with "preinit" method, needed also in @@ -51,7 +52,10 @@ typedef struct AlsaData { int frame_size; ///< bytes per sample * channels int period_size; ///< preferred size for reads and writes, in frames int sample_rate; ///< sample rate set by user +#if FF_API_ALSA_CHANNELS int channels; ///< number of channels set by user +#endif + AVChannelLayout ch_layout; ///< Channel layout set by user int last_period; TimeFilter *timefilter; void (*reorder_func)(const void *, void *, int); @@ -68,7 +72,7 @@ typedef struct AlsaData { * @param mode either SND_PCM_STREAM_CAPTURE or SND_PCM_STREAM_PLAYBACK * @param sample_rate in: requested sample rate; * out: actually selected sample rate - * @param channels number of channels + * @param layout channel layout * @param codec_id in: requested AVCodecID or AV_CODEC_ID_NONE; * out: actually selected AVCodecID, changed only if * AV_CODEC_ID_NONE was requested @@ -78,7 +82,7 @@ typedef struct AlsaData { av_warn_unused_result int ff_alsa_open(AVFormatContext *s, snd_pcm_stream_t mode, unsigned int *sample_rate, - int channels, enum AVCodecID *codec_id); + const AVChannelLayout *layout, enum AVCodecID *codec_id); /** * Close the ALSA PCM. diff --git a/libavdevice/alsa_dec.c b/libavdevice/alsa_dec.c index 018afaef0..63409a778 100644 --- a/libavdevice/alsa_dec.c +++ b/libavdevice/alsa_dec.c @@ -73,7 +73,14 @@ static av_cold int audio_read_header(AVFormatContext *s1) } codec_id = s1->audio_codec_id; - ret = ff_alsa_open(s1, SND_PCM_STREAM_CAPTURE, &s->sample_rate, s->channels, +#if FF_API_ALSA_CHANNELS + if (s->channels > 0) { + av_channel_layout_uninit(&s->ch_layout); + s->ch_layout.nb_channels = s->channels; + } +#endif + + ret = ff_alsa_open(s1, SND_PCM_STREAM_CAPTURE, &s->sample_rate, &s->ch_layout, &codec_id); if (ret < 0) { return AVERROR(EIO); @@ -83,20 +90,24 @@ static av_cold int audio_read_header(AVFormatContext *s1) st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; st->codecpar->codec_id = codec_id; st->codecpar->sample_rate = s->sample_rate; - st->codecpar->ch_layout.nb_channels = s->channels; + ret = av_channel_layout_copy(&st->codecpar->ch_layout, &s->ch_layout); + if (ret < 0) + goto fail; st->codecpar->frame_size = s->frame_size; avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ /* microseconds instead of seconds, MHz instead of Hz */ s->timefilter = ff_timefilter_new(1000000.0 / s->sample_rate, s->period_size, 1.5E-6); - if (!s->timefilter) + if (!s->timefilter) { + ret = AVERROR(EIO); goto fail; + } return 0; fail: snd_pcm_close(s->h); - return AVERROR(EIO); + return ret; } static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) @@ -146,7 +157,10 @@ static int audio_get_device_list(AVFormatContext *h, AVDeviceInfoList *device_li static const AVOption options[] = { { "sample_rate", "", offsetof(AlsaData, sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, - { "channels", "", offsetof(AlsaData, channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, +#if FF_API_ALSA_CHANNELS + { "channels", "", offsetof(AlsaData, channels), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_DEPRECATED }, +#endif + { "ch_layout", "", offsetof(AlsaData, ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str = "2C"}, INT_MIN, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, { NULL }, }; diff --git a/libavdevice/alsa_enc.c b/libavdevice/alsa_enc.c index 0b4c7834f..971cff688 100644 --- a/libavdevice/alsa_enc.c +++ b/libavdevice/alsa_enc.c @@ -66,7 +66,7 @@ static av_cold int audio_write_header(AVFormatContext *s1) sample_rate = st->codecpar->sample_rate; codec_id = st->codecpar->codec_id; res = ff_alsa_open(s1, SND_PCM_STREAM_PLAYBACK, &sample_rate, - st->codecpar->ch_layout.nb_channels, &codec_id); + &st->codecpar->ch_layout, &codec_id); if (sample_rate != st->codecpar->sample_rate) { av_log(s1, AV_LOG_ERROR, "sample rate %d not available, nearest is %d\n", diff --git a/libavdevice/android_camera.c b/libavdevice/android_camera.c index 5de44e6d8..843328629 100644 --- a/libavdevice/android_camera.c +++ b/libavdevice/android_camera.c @@ -421,7 +421,7 @@ static void image_available(void *context, AImageReader *reader) } } - pkt_buffer_size = av_image_get_buffer_size(ctx->image_format, ctx->width, ctx->height, 32); + pkt_buffer_size = av_image_get_buffer_size(ctx->image_format, ctx->width, ctx->height, 1); AImage_getTimestamp(image, &image_timestamp); AImage_getPlaneRowStride(image, 0, &image_linestrides[0]); @@ -460,7 +460,7 @@ static void image_available(void *context, AImageReader *reader) av_image_copy_to_buffer(pkt.data, pkt_buffer_size, (const uint8_t * const *) image_plane_data, image_linestrides, ctx->image_format, - ctx->width, ctx->height, 32); + ctx->width, ctx->height, 1); ret = av_thread_message_queue_send(ctx->input_queue, &pkt, AV_THREAD_MESSAGE_NONBLOCK); diff --git a/libavdevice/audiotoolbox.m b/libavdevice/audiotoolbox.m index 7d95c3459..32ab15185 100644 --- a/libavdevice/audiotoolbox.m +++ b/libavdevice/audiotoolbox.m @@ -247,7 +247,7 @@ static int at_write_packet(AVFormatContext *avctx, AVPacket *pkt) // will be unlocked by queue callback pthread_mutex_lock(&ctx->buffer_lock[ctx->cur_buf]); - // (re-)allocate the buffer if not existant or of different size + // (re-)allocate the buffer if not existent or of different size if (!ctx->buffer[ctx->cur_buf] || ctx->buffer[ctx->cur_buf]->mAudioDataBytesCapacity != pkt->size) { err = AudioQueueAllocateBuffer(ctx->queue, pkt->size, &ctx->buffer[ctx->cur_buf]); if (check_status(avctx, &err, "AudioQueueAllocateBuffer")) { diff --git a/libavdevice/avdevice.h b/libavdevice/avdevice.h index 887fd5e3c..10ffaf4c5 100644 --- a/libavdevice/avdevice.h +++ b/libavdevice/avdevice.h @@ -372,7 +372,7 @@ void avdevice_free_list_devices(AVDeviceInfoList **device_list); * List devices. * * Returns available device names and their parameters. - * These are convinient wrappers for avdevice_list_devices(). + * These are convenient wrappers for avdevice_list_devices(). * Device context is allocated and deallocated internally. * * @param device device format. May be NULL if device name is set. diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index c5a09c656..ebec1ac4f 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -150,7 +150,7 @@ static void unlock_frames(AVFContext* ctx) pthread_mutex_unlock(&ctx->frame_lock); } -/** FrameReciever class - delegate for AVCaptureSession +/** FrameReceiver class - delegate for AVCaptureSession */ @interface AVFFrameReceiver : NSObject { @@ -242,7 +242,7 @@ static void unlock_frames(AVFContext* ctx) @end -/** AudioReciever class - delegate for AVCaptureSession +/** AudioReceiver class - delegate for AVCaptureSession */ @interface AVFAudioReceiver : NSObject { @@ -632,7 +632,6 @@ static int get_video_config(AVFormatContext *s) { AVFContext *ctx = (AVFContext*)s->priv_data; CVImageBufferRef image_buffer; - CMBlockBufferRef block_buffer; CGSize image_buffer_size; AVStream* stream = avformat_new_stream(s, NULL); @@ -652,7 +651,6 @@ static int get_video_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame); - block_buffer = CMSampleBufferGetDataBuffer(ctx->current_frame); if (image_buffer) { image_buffer_size = CVImageBufferGetEncodedSize(image_buffer); @@ -816,8 +814,10 @@ static NSArray* getDevicesWithMediaType(AVMediaType mediaType) { mediaType:mediaType position:AVCaptureDevicePositionUnspecified]; return [captureDeviceDiscoverySession devices]; -#else +#elif TARGET_OS_OSX return [AVCaptureDevice devicesWithMediaType:mediaType]; +#else + return nil; #endif } diff --git a/libavdevice/bktr.c b/libavdevice/bktr.c deleted file mode 100644 index eed75a9a9..000000000 --- a/libavdevice/bktr.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * *BSD video grab interface - * Copyright (c) 2002 Steve O'Hara-Smith - * based on - * Linux video grab interface - * Copyright (c) 2000, 2001 Fabrice Bellard - * and - * simple_grab.c Copyright (c) 1999 Roger Hardiman - * - * 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 "libavformat/demux.h" -#include "libavformat/internal.h" -#include "libavutil/file_open.h" -#include "libavutil/internal.h" -#include "libavutil/log.h" -#include "libavutil/mem.h" -#include "libavutil/opt.h" -#include "libavutil/parseutils.h" -#include "libavutil/time.h" -#if HAVE_DEV_BKTR_IOCTL_METEOR_H && HAVE_DEV_BKTR_IOCTL_BT848_H -# include -# include -#elif HAVE_MACHINE_IOCTL_METEOR_H && HAVE_MACHINE_IOCTL_BT848_H -# include -# include -#elif HAVE_DEV_VIDEO_METEOR_IOCTL_METEOR_H && HAVE_DEV_VIDEO_BKTR_IOCTL_BT848_H -# include -# include -#elif HAVE_DEV_IC_BT8XX_H -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include "avdevice.h" - -typedef struct VideoData { - AVClass *class; - int video_fd; - int tuner_fd; - int width, height; - uint64_t per_frame; - int standard; - char *framerate; /**< Set by a private option. */ -} VideoData; - - -#define PAL 1 -#define PALBDGHI 1 -#define NTSC 2 -#define NTSCM 2 -#define SECAM 3 -#define PALN 4 -#define PALM 5 -#define NTSCJ 6 - -/* PAL is 768 x 576. NTSC is 640 x 480 */ -#define PAL_HEIGHT 576 -#define SECAM_HEIGHT 576 -#define NTSC_HEIGHT 480 - -#ifndef VIDEO_FORMAT -#define VIDEO_FORMAT NTSC -#endif - -static const int bktr_dev[] = { METEOR_DEV0, METEOR_DEV1, METEOR_DEV2, - METEOR_DEV3, METEOR_DEV_SVIDEO }; - -uint8_t *video_buf; -size_t video_buf_size; -uint64_t last_frame_time; -volatile sig_atomic_t nsignals; - - -static void catchsignal(int signal) -{ - nsignals++; - return; -} - -static av_cold int bktr_init(const char *video_device, int width, int height, - int format, int *video_fd, int *tuner_fd, int idev, double frequency) -{ - struct meteor_geomet geo; - int h_max; - long ioctl_frequency; - char *arg; - int c; - struct sigaction act, old; - int ret; - char errbuf[128]; - - if (idev < 0 || idev > 4) - { - arg = getenv ("BKTR_DEV"); - if (arg) - idev = atoi (arg); - if (idev < 0 || idev > 4) - idev = 1; - } - - if (format < 1 || format > 6) - { - arg = getenv ("BKTR_FORMAT"); - if (arg) - format = atoi (arg); - if (format < 1 || format > 6) - format = VIDEO_FORMAT; - } - - if (frequency <= 0) - { - arg = getenv ("BKTR_FREQUENCY"); - if (arg) - frequency = atof (arg); - if (frequency <= 0) - frequency = 0.0; - } - - memset(&act, 0, sizeof(act)); - sigemptyset(&act.sa_mask); - act.sa_handler = catchsignal; - sigaction(SIGUSR1, &act, &old); - - *tuner_fd = avpriv_open("/dev/tuner0", O_RDONLY); - if (*tuner_fd < 0) - av_log(NULL, AV_LOG_ERROR, "Warning. Tuner not opened, continuing: %s\n", strerror(errno)); - - *video_fd = avpriv_open(video_device, O_RDONLY); - if (*video_fd < 0) { - ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(NULL, AV_LOG_ERROR, "%s: %s\n", video_device, errbuf); - return ret; - } - - geo.rows = height; - geo.columns = width; - geo.frames = 1; - geo.oformat = METEOR_GEO_YUV_422 | METEOR_GEO_YUV_12; - - switch (format) { - case PAL: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALBDGHI; break; - case PALN: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALN; break; - case PALM: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALM; break; - case SECAM: h_max = SECAM_HEIGHT; c = BT848_IFORM_F_SECAM; break; - case NTSC: h_max = NTSC_HEIGHT; c = BT848_IFORM_F_NTSCM; break; - case NTSCJ: h_max = NTSC_HEIGHT; c = BT848_IFORM_F_NTSCJ; break; - default: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALBDGHI; break; - } - - if (height <= h_max / 2) - geo.oformat |= METEOR_GEO_EVEN_ONLY; - - if (ioctl(*video_fd, METEORSETGEO, &geo) < 0) { - ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(NULL, AV_LOG_ERROR, "METEORSETGEO: %s\n", errbuf); - return ret; - } - - if (ioctl(*video_fd, BT848SFMT, &c) < 0) { - ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(NULL, AV_LOG_ERROR, "BT848SFMT: %s\n", errbuf); - return ret; - } - - c = bktr_dev[idev]; - if (ioctl(*video_fd, METEORSINPUT, &c) < 0) { - ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(NULL, AV_LOG_ERROR, "METEORSINPUT: %s\n", errbuf); - return ret; - } - - video_buf_size = width * height * 12 / 8; - - video_buf = (uint8_t *)mmap((caddr_t)0, video_buf_size, - PROT_READ, MAP_SHARED, *video_fd, (off_t)0); - if (video_buf == MAP_FAILED) { - ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(NULL, AV_LOG_ERROR, "mmap: %s\n", errbuf); - return ret; - } - - if (frequency != 0.0) { - ioctl_frequency = (unsigned long)(frequency*16); - if (ioctl(*tuner_fd, TVTUNER_SETFREQ, &ioctl_frequency) < 0) - av_log(NULL, AV_LOG_ERROR, "TVTUNER_SETFREQ: %s\n", strerror(errno)); - } - - c = AUDIO_UNMUTE; - if (ioctl(*tuner_fd, BT848_SAUDIO, &c) < 0) - av_log(NULL, AV_LOG_ERROR, "TVTUNER_SAUDIO: %s\n", strerror(errno)); - - c = METEOR_CAP_CONTINOUS; - ioctl(*video_fd, METEORCAPTUR, &c); - - c = SIGUSR1; - ioctl(*video_fd, METEORSSIGNAL, &c); - - return 0; -} - -static void bktr_getframe(uint64_t per_frame) -{ - uint64_t curtime; - - curtime = av_gettime_relative(); - if (!last_frame_time - || ((last_frame_time + per_frame) > curtime)) { - if (!usleep(last_frame_time + per_frame + per_frame / 8 - curtime)) { - if (!nsignals) - av_log(NULL, AV_LOG_INFO, - "SLEPT NO signals - %d microseconds late\n", - (int)(av_gettime_relative() - last_frame_time - per_frame)); - } - } - nsignals = 0; - last_frame_time = curtime; -} - - -/* note: we support only one picture read at a time */ -static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt) -{ - VideoData *s = s1->priv_data; - - if (av_new_packet(pkt, video_buf_size) < 0) - return AVERROR(EIO); - - bktr_getframe(s->per_frame); - - pkt->pts = av_gettime(); - memcpy(pkt->data, video_buf, video_buf_size); - - return video_buf_size; -} - -static int grab_read_header(AVFormatContext *s1) -{ - VideoData *s = s1->priv_data; - AVStream *st; - AVRational framerate; - int ret = 0; - - av_log(s1, AV_LOG_WARNING, "bktr input is deprecated and will be removed. " - "Please contact the developers if you are interested in maintaining it.\n"); - - if (!s->framerate) - switch (s->standard) { - case PAL: s->framerate = av_strdup("pal"); break; - case NTSC: s->framerate = av_strdup("ntsc"); break; - case SECAM: s->framerate = av_strdup("25"); break; - default: - av_log(s1, AV_LOG_ERROR, "Unknown standard.\n"); - ret = AVERROR(EINVAL); - goto out; - } - if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) { - av_log(s1, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", s->framerate); - goto out; - } - - st = avformat_new_stream(s1, NULL); - if (!st) { - ret = AVERROR(ENOMEM); - goto out; - } - avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in use */ - - s->per_frame = ((uint64_t)1000000 * framerate.den) / framerate.num; - - st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; - st->codecpar->format = AV_PIX_FMT_YUV420P; - st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; - st->codecpar->width = s->width; - st->codecpar->height = s->height; - st->avg_frame_rate = framerate; - - if (bktr_init(s1->url, s->width, s->height, s->standard, - &s->video_fd, &s->tuner_fd, -1, 0.0) < 0) { - ret = AVERROR(EIO); - goto out; - } - - nsignals = 0; - last_frame_time = 0; - -out: - return ret; -} - -static int grab_read_close(AVFormatContext *s1) -{ - VideoData *s = s1->priv_data; - int c; - - c = METEOR_CAP_STOP_CONT; - ioctl(s->video_fd, METEORCAPTUR, &c); - close(s->video_fd); - - c = AUDIO_MUTE; - ioctl(s->tuner_fd, BT848_SAUDIO, &c); - close(s->tuner_fd); - - munmap((caddr_t)video_buf, video_buf_size); - - return 0; -} - -#define OFFSET(x) offsetof(VideoData, x) -#define DEC AV_OPT_FLAG_DECODING_PARAM -static const AVOption options[] = { - { "standard", "", offsetof(VideoData, standard), AV_OPT_TYPE_INT, {.i64 = VIDEO_FORMAT}, PAL, NTSCJ, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "PAL", "", 0, AV_OPT_TYPE_CONST, {.i64 = PAL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "NTSC", "", 0, AV_OPT_TYPE_CONST, {.i64 = NTSC}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "SECAM", "", 0, AV_OPT_TYPE_CONST, {.i64 = SECAM}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "PALN", "", 0, AV_OPT_TYPE_CONST, {.i64 = PALN}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "PALM", "", 0, AV_OPT_TYPE_CONST, {.i64 = PALM}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "NTSCJ", "", 0, AV_OPT_TYPE_CONST, {.i64 = NTSCJ}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = "vga"}, 0, 0, DEC }, - { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, - { NULL }, -}; - -static const AVClass bktr_class = { - .class_name = "BKTR grab indev", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, - .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, -}; - -const FFInputFormat ff_bktr_demuxer = { - .p.name = "bktr", - .p.long_name = NULL_IF_CONFIG_SMALL("video grab"), - .p.flags = AVFMT_NOFILE, - .p.priv_class = &bktr_class, - .priv_data_size = sizeof(VideoData), - .read_header = grab_read_header, - .read_packet = grab_read_packet, - .read_close = grab_read_close, -}; diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp index 47de7ef6b..fe187cd2c 100644 --- a/libavdevice/decklink_common.cpp +++ b/libavdevice/decklink_common.cpp @@ -25,7 +25,12 @@ extern "C" { #include "libavformat/internal.h" } +#include #include +#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0e030000 +#include +#endif + #ifdef _WIN32 #include #else @@ -512,8 +517,8 @@ int ff_decklink_list_devices(AVFormatContext *avctx, return AVERROR(EIO); while (ret == 0 && iter->Next(&dl) == S_OK) { - IDeckLinkOutput *output_config; - IDeckLinkInput *input_config; + IDeckLinkOutput_v14_2_1 *output_config; + IDeckLinkInput_v14_2_1 *input_config; const char *display_name = NULL; const char *unique_name = NULL; AVDeviceInfo *new_device = NULL; @@ -527,14 +532,14 @@ int ff_decklink_list_devices(AVFormatContext *avctx, goto next; if (show_outputs) { - if (dl->QueryInterface(IID_IDeckLinkOutput, (void **)&output_config) == S_OK) { + if (dl->QueryInterface(IID_IDeckLinkOutput_v14_2_1, (void **)&output_config) == S_OK) { output_config->Release(); add = 1; } } if (show_inputs) { - if (dl->QueryInterface(IID_IDeckLinkInput, (void **)&input_config) == S_OK) { + if (dl->QueryInterface(IID_IDeckLinkInput_v14_2_1, (void **)&input_config) == S_OK) { input_config->Release(); add = 1; } diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h index 6b32dc2d0..095b438bc 100644 --- a/libavdevice/decklink_common.h +++ b/libavdevice/decklink_common.h @@ -29,6 +29,23 @@ #define IDeckLinkProfileAttributes IDeckLinkAttributes #endif +#if BLACKMAGIC_DECKLINK_API_VERSION < 0x0e030000 +#define IDeckLinkInput_v14_2_1 IDeckLinkInput +#define IDeckLinkInputCallback_v14_2_1 IDeckLinkInputCallback +#define IDeckLinkMemoryAllocator_v14_2_1 IDeckLinkMemoryAllocator +#define IDeckLinkOutput_v14_2_1 IDeckLinkOutput +#define IDeckLinkVideoFrame_v14_2_1 IDeckLinkVideoFrame +#define IDeckLinkVideoInputFrame_v14_2_1 IDeckLinkVideoInputFrame +#define IDeckLinkVideoOutputCallback_v14_2_1 IDeckLinkVideoOutputCallback +#define IID_IDeckLinkInput_v14_2_1 IID_IDeckLinkInput +#define IID_IDeckLinkInputCallback_v14_2_1 IID_IDeckLinkInputCallback +#define IID_IDeckLinkMemoryAllocator_v14_2_1 IID_IDeckLinkMemoryAllocator +#define IID_IDeckLinkOutput_v14_2_1 IID_IDeckLinkOutput +#define IID_IDeckLinkVideoFrame_v14_2_1 IID_IDeckLinkVideoFrame +#define IID_IDeckLinkVideoInputFrame_v14_2_1 IID_IDeckLinkVideoInputFrame +#define IID_IDeckLinkVideoOutputCallback_v14_2_1 IID_IDeckLinkVideoOutputCallback +#endif + extern "C" { #include "libavutil/mem.h" #include "libavcodec/packet_internal.h" @@ -76,6 +93,16 @@ static char *dup_cfstring_to_utf8(CFStringRef w) #define DECKLINK_FREE(s) free((void *) s) #endif +#ifdef _WIN32 +#include // REFIID, IsEqualIID() +#define DECKLINK_IsEqualIID IsEqualIID +#else +static inline bool DECKLINK_IsEqualIID(const REFIID& riid1, const REFIID& riid2) +{ + return memcmp(&riid1, &riid2, sizeof(REFIID)) == 0; +} +#endif + class decklink_output_callback; class decklink_input_callback; @@ -93,8 +120,8 @@ typedef struct DecklinkPacketQueue { struct decklink_ctx { /* DeckLink SDK interfaces */ IDeckLink *dl; - IDeckLinkOutput *dlo; - IDeckLinkInput *dli; + IDeckLinkOutput_v14_2_1 *dlo; + IDeckLinkInput_v14_2_1 *dli; IDeckLinkConfiguration *cfg; IDeckLinkProfileAttributes *attr; decklink_output_callback *output_callback; diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp index 418701e4e..883077999 100644 --- a/libavdevice/decklink_dec.cpp +++ b/libavdevice/decklink_dec.cpp @@ -31,7 +31,11 @@ extern "C" { #include "libavformat/internal.h" } +#include #include +#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0e030000 +#include +#endif extern "C" { #include "config.h" @@ -105,7 +109,7 @@ static VANCLineNumber vanc_line_numbers[] = { {bmdModeUnknown, 0, -1, -1, -1} }; -class decklink_allocator : public IDeckLinkMemoryAllocator +class decklink_allocator : public IDeckLinkMemoryAllocator_v14_2_1 { public: decklink_allocator(): _refs(1) { } @@ -129,7 +133,21 @@ public: virtual HRESULT STDMETHODCALLTYPE Decommit() { return S_OK; } // IUnknown methods - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppv) + { + if (DECKLINK_IsEqualIID(riid, IID_IUnknown)) { + *ppv = static_cast(this); + } else if (DECKLINK_IsEqualIID(riid, IID_IDeckLinkMemoryAllocator_v14_2_1)) { + *ppv = static_cast(this); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; + } + virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++_refs; } virtual ULONG STDMETHODCALLTYPE Release(void) { @@ -472,7 +490,7 @@ skip_packet: } -static void handle_klv(AVFormatContext *avctx, decklink_ctx *ctx, IDeckLinkVideoInputFrame *videoFrame, int64_t pts) +static void handle_klv(AVFormatContext *avctx, decklink_ctx *ctx, IDeckLinkVideoInputFrame_v14_2_1 *videoFrame, int64_t pts) { const uint8_t KLV_DID = 0x44; const uint8_t KLV_IN_VANC_SDID = 0x04; @@ -574,17 +592,30 @@ static void handle_klv(AVFormatContext *avctx, decklink_ctx *ctx, IDeckLinkVideo } } -class decklink_input_callback : public IDeckLinkInputCallback +class decklink_input_callback : public IDeckLinkInputCallback_v14_2_1 { public: explicit decklink_input_callback(AVFormatContext *_avctx); ~decklink_input_callback(); - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppv) + { + if (DECKLINK_IsEqualIID(riid, IID_IUnknown)) { + *ppv = static_cast(this); + } else if (DECKLINK_IsEqualIID(riid, IID_IDeckLinkInputCallback_v14_2_1)) { + *ppv = static_cast(this); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; + } virtual ULONG STDMETHODCALLTYPE AddRef(void); virtual ULONG STDMETHODCALLTYPE Release(void); virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode*, BMDDetectedVideoInputFormatFlags); - virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*); + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame_v14_2_1*, IDeckLinkAudioInputPacket*); private: std::atomic _refs; @@ -593,7 +624,7 @@ private: int no_video; int64_t initial_video_pts; int64_t initial_audio_pts; - IDeckLinkVideoInputFrame* last_video_frame; + IDeckLinkVideoInputFrame_v14_2_1* last_video_frame; }; decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : _refs(1) @@ -625,7 +656,7 @@ ULONG decklink_input_callback::Release(void) return ret; } -static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame, +static int64_t get_pkt_pts(IDeckLinkVideoInputFrame_v14_2_1 *videoFrame, IDeckLinkAudioInputPacket *audioFrame, int64_t wallclock, int64_t abs_wallclock, @@ -679,7 +710,7 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame, return pts; } -static int get_bmd_timecode(AVFormatContext *avctx, AVTimecode *tc, AVRational frame_rate, BMDTimecodeFormat tc_format, IDeckLinkVideoInputFrame *videoFrame) +static int get_bmd_timecode(AVFormatContext *avctx, AVTimecode *tc, AVRational frame_rate, BMDTimecodeFormat tc_format, IDeckLinkVideoInputFrame_v14_2_1 *videoFrame) { IDeckLinkTimecode *timecode; int ret = AVERROR(ENOENT); @@ -701,7 +732,7 @@ static int get_bmd_timecode(AVFormatContext *avctx, AVTimecode *tc, AVRational f return ret; } -static int get_frame_timecode(AVFormatContext *avctx, decklink_ctx *ctx, AVTimecode *tc, IDeckLinkVideoInputFrame *videoFrame) +static int get_frame_timecode(AVFormatContext *avctx, decklink_ctx *ctx, AVTimecode *tc, IDeckLinkVideoInputFrame_v14_2_1 *videoFrame) { AVRational frame_rate = ctx->video_st->r_frame_rate; int ret; @@ -726,7 +757,7 @@ static int get_frame_timecode(AVFormatContext *avctx, decklink_ctx *ctx, AVTimec } HRESULT decklink_input_callback::VideoInputFrameArrived( - IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioFrame) + IDeckLinkVideoInputFrame_v14_2_1 *videoFrame, IDeckLinkAudioInputPacket *audioFrame) { void *frameBytes; void *audioFrameBytes; @@ -1141,7 +1172,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) goto error; /* Get input device. */ - if (ctx->dl->QueryInterface(IID_IDeckLinkInput, (void **) &ctx->dli) != S_OK) { + if (ctx->dl->QueryInterface(IID_IDeckLinkInput_v14_2_1, (void **) &ctx->dli) != S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not open input device from '%s'\n", avctx->url); ret = AVERROR(EIO); diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp index cb8f91730..d2e246c81 100644 --- a/libavdevice/decklink_enc.cpp +++ b/libavdevice/decklink_enc.cpp @@ -28,7 +28,11 @@ extern "C" { #include "libavformat/internal.h" } +#include #include +#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0e030000 +#include +#endif extern "C" { #include "libavformat/avformat.h" @@ -48,7 +52,7 @@ extern "C" { #endif /* DeckLink callback class declaration */ -class decklink_frame : public IDeckLinkVideoFrame +class decklink_frame : public IDeckLinkVideoFrame_v14_2_1 { public: decklink_frame(struct decklink_ctx *ctx, AVFrame *avframe, AVCodecID codec_id, int height, int width) : @@ -111,7 +115,20 @@ public: _ancillary->AddRef(); return S_OK; } - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppv) + { + if (DECKLINK_IsEqualIID(riid, IID_IUnknown)) { + *ppv = static_cast(this); + } else if (DECKLINK_IsEqualIID(riid, IID_IDeckLinkVideoFrame_v14_2_1)) { + *ppv = static_cast(this); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; + } virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++_refs; } virtual ULONG STDMETHODCALLTYPE Release(void) { @@ -138,10 +155,10 @@ private: std::atomic _refs; }; -class decklink_output_callback : public IDeckLinkVideoOutputCallback +class decklink_output_callback : public IDeckLinkVideoOutputCallback_v14_2_1 { public: - virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(IDeckLinkVideoFrame *_frame, BMDOutputFrameCompletionResult result) + virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(IDeckLinkVideoFrame_v14_2_1 *_frame, BMDOutputFrameCompletionResult result) { decklink_frame *frame = static_cast(_frame); struct decklink_ctx *ctx = frame->_ctx; @@ -159,7 +176,20 @@ public: return S_OK; } virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped(void) { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppv) + { + if (DECKLINK_IsEqualIID(riid, IID_IUnknown)) { + *ppv = static_cast(this); + } else if (DECKLINK_IsEqualIID(riid, IID_IDeckLinkVideoOutputCallback_v14_2_1)) { + *ppv = static_cast(this); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; + } virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 1; } virtual ULONG STDMETHODCALLTYPE Release(void) { return 1; } }; @@ -739,7 +769,7 @@ static int decklink_write_video_packet(AVFormatContext *avctx, AVPacket *pkt) ctx->first_pts = pkt->pts; /* Schedule frame for playback. */ - hr = ctx->dlo->ScheduleVideoFrame((class IDeckLinkVideoFrame *) frame, + hr = ctx->dlo->ScheduleVideoFrame(frame, pkt->pts * ctx->bmd_tb_num, ctx->bmd_tb_num, ctx->bmd_tb_den); /* Pass ownership to DeckLink, or release on failure */ @@ -874,7 +904,7 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) return ret; /* Get output device. */ - if (ctx->dl->QueryInterface(IID_IDeckLinkOutput, (void **) &ctx->dlo) != S_OK) { + if (ctx->dl->QueryInterface(IID_IDeckLinkOutput_v14_2_1, (void **) &ctx->dlo) != S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not open output device from '%s'\n", avctx->url); ret = AVERROR(EIO); diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c index 84db15157..6e9730485 100644 --- a/libavdevice/dshow.c +++ b/libavdevice/dshow.c @@ -985,8 +985,8 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype, } } else { WAVEFORMATEX *fx; - AUDIO_STREAM_CONFIG_CAPS *acaps = caps; #if DSHOWDEBUG + AUDIO_STREAM_CONFIG_CAPS *acaps = caps; ff_print_AUDIO_STREAM_CONFIG_CAPS(acaps); #endif if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) { diff --git a/libavdevice/lavfi.c b/libavdevice/lavfi.c index ce10d61f8..0de2bbdcf 100644 --- a/libavdevice/lavfi.c +++ b/libavdevice/lavfi.c @@ -249,16 +249,19 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx) AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL, }; - ret = avfilter_graph_create_filter(&sink, abuffersink, - inout->name, NULL, - NULL, lavfi->graph); - if (ret >= 0) - ret = av_opt_set_bin(sink, "sample_fmts", (const uint8_t*)sample_fmts, - sizeof(sample_fmts), AV_OPT_SEARCH_CHILDREN); + sink = avfilter_graph_alloc_filter(lavfi->graph, abuffersink, inout->name); + if (!sink) { + ret = AVERROR(ENOMEM); + goto end; + } + + ret = av_opt_set_array(sink, "sample_formats", AV_OPT_SEARCH_CHILDREN, 0, + FF_ARRAY_ELEMS(sample_fmts), AV_OPT_TYPE_SAMPLE_FMT, + sample_fmts); if (ret < 0) goto end; - ret = av_opt_set_int(sink, "all_channel_counts", 1, - AV_OPT_SEARCH_CHILDREN); + + ret = avfilter_init_dict(sink, NULL); if (ret < 0) goto end; } else { @@ -347,11 +350,6 @@ static int create_subcc_packet(AVFormatContext *avctx, AVFrame *frame, memcpy(lavfi->subcc_packet.data, sd->data, sd->size); lavfi->subcc_packet.stream_index = stream_idx; lavfi->subcc_packet.pts = frame->pts; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - lavfi->subcc_packet.pos = frame->pkt_pos; -FF_ENABLE_DEPRECATION_WARNINGS -#endif return 0; } @@ -460,11 +458,6 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt) pkt->stream_index = stream_idx; pkt->pts = frame->pts; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - pkt->pos = frame->pkt_pos; -FF_ENABLE_DEPRECATION_WARNINGS -#endif av_frame_free(&frame_to_free); diff --git a/libavdevice/opengl_enc.c b/libavdevice/opengl_enc.c deleted file mode 100644 index 93d395988..000000000 --- a/libavdevice/opengl_enc.c +++ /dev/null @@ -1,1325 +0,0 @@ -/* - * Copyright (c) 2014 Lukasz Marek - * - * 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 - */ - -//TODO: support for more formats -//TODO: support for more systems. -//TODO: implement X11, Windows, Mac OS native default window. SDL 1.2 doesn't allow to render to custom thread. - -#include -#include -#include -#include - -#include "config.h" - -#if HAVE_WINDOWS_H -#include -#endif -#if HAVE_OPENGL_GL3_H -#include -#elif HAVE_ES2_GL_H -#include -#else -#include -#include -#endif -#if HAVE_GLXGETPROCADDRESS -#include -#endif - -#if CONFIG_SDL2 -#include -#endif - -#include "libavutil/common.h" -#include "libavutil/frame.h" -#include "libavutil/mem.h" -#include "libavutil/pixdesc.h" -#include "libavutil/log.h" -#include "libavutil/opt.h" -#include "libavutil/avassert.h" -#include "libavformat/avformat.h" -#include "libavformat/internal.h" -#include "libavformat/mux.h" -#include "libavdevice/avdevice.h" -#include "opengl_enc_shaders.h" - -#ifndef APIENTRY -#define APIENTRY -#endif - -/* FF_GL_RED_COMPONENT is used for planar pixel types. - * Only red component is sampled in shaders. - * On some platforms GL_RED is not available and GL_LUMINANCE have to be used, - * but since OpenGL 3.0 GL_LUMINANCE is deprecated. - * GL_RED produces RGBA = value, 0, 0, 1. - * GL_LUMINANCE produces RGBA = value, value, value, 1. - * Note: GL_INTENSITY may also be used which produce RGBA = value, value, value, value. */ -#if defined(GL_RED) -#define FF_GL_RED_COMPONENT GL_RED -#elif defined(GL_LUMINANCE) -#define FF_GL_RED_COMPONENT GL_LUMINANCE -#else -#define FF_GL_RED_COMPONENT 0x1903; //GL_RED -#endif - -/* Constants not defined for iOS */ -#define FF_GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define FF_GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define FF_GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define FF_GL_UNPACK_ROW_LENGTH 0x0CF2 - -/* MinGW exposes only OpenGL 1.1 API */ -#define FF_GL_ARRAY_BUFFER 0x8892 -#define FF_GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define FF_GL_STATIC_DRAW 0x88E4 -#define FF_GL_FRAGMENT_SHADER 0x8B30 -#define FF_GL_VERTEX_SHADER 0x8B31 -#define FF_GL_COMPILE_STATUS 0x8B81 -#define FF_GL_LINK_STATUS 0x8B82 -#define FF_GL_INFO_LOG_LENGTH 0x8B84 -typedef void (APIENTRY *FF_PFNGLACTIVETEXTUREPROC) (GLenum texture); -typedef void (APIENTRY *FF_PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); -typedef void (APIENTRY *FF_PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); -typedef void (APIENTRY *FF_PFNGLBUFFERDATAPROC) (GLenum target, ptrdiff_t size, const GLvoid *data, GLenum usage); -typedef void (APIENTRY *FF_PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); -typedef GLint (APIENTRY *FF_PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const char *name); -typedef void (APIENTRY *FF_PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRY *FF_PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uintptr_t pointer); -typedef GLint (APIENTRY *FF_PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const char *name); -typedef void (APIENTRY *FF_PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); -typedef void (APIENTRY *FF_PFNGLUNIFORM1IPROC) (GLint location, GLint v0); -typedef void (APIENTRY *FF_PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef GLuint (APIENTRY *FF_PFNGLCREATEPROGRAMPROC) (void); -typedef void (APIENTRY *FF_PFNGLDELETEPROGRAMPROC) (GLuint program); -typedef void (APIENTRY *FF_PFNGLUSEPROGRAMPROC) (GLuint program); -typedef void (APIENTRY *FF_PFNGLLINKPROGRAMPROC) (GLuint program); -typedef void (APIENTRY *FF_PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); -typedef void (APIENTRY *FF_PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, char *infoLog); -typedef void (APIENTRY *FF_PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); -typedef GLuint (APIENTRY *FF_PFNGLCREATESHADERPROC) (GLenum type); -typedef void (APIENTRY *FF_PFNGLDELETESHADERPROC) (GLuint shader); -typedef void (APIENTRY *FF_PFNGLCOMPILESHADERPROC) (GLuint shader); -typedef void (APIENTRY *FF_PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const char* *string, const GLint *length); -typedef void (APIENTRY *FF_PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); -typedef void (APIENTRY *FF_PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, char *infoLog); - -typedef struct FFOpenGLFunctions { - FF_PFNGLACTIVETEXTUREPROC glActiveTexture; //Require GL ARB multitexture - FF_PFNGLGENBUFFERSPROC glGenBuffers; //Require GL_ARB_vertex_buffer_object - FF_PFNGLDELETEBUFFERSPROC glDeleteBuffers; //Require GL_ARB_vertex_buffer_object - FF_PFNGLBUFFERDATAPROC glBufferData; //Require GL_ARB_vertex_buffer_object - FF_PFNGLBINDBUFFERPROC glBindBuffer; //Require GL_ARB_vertex_buffer_object - FF_PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; //Require GL_ARB_vertex_shader - FF_PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; //Require GL_ARB_vertex_shader - FF_PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; //Require GL_ARB_vertex_shader - FF_PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; //Require GL_ARB_shader_objects - FF_PFNGLUNIFORM1FPROC glUniform1f; //Require GL_ARB_shader_objects - FF_PFNGLUNIFORM1IPROC glUniform1i; //Require GL_ARB_shader_objects - FF_PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; //Require GL_ARB_shader_objects - FF_PFNGLCREATEPROGRAMPROC glCreateProgram; //Require GL_ARB_shader_objects - FF_PFNGLDELETEPROGRAMPROC glDeleteProgram; //Require GL_ARB_shader_objects - FF_PFNGLUSEPROGRAMPROC glUseProgram; //Require GL_ARB_shader_objects - FF_PFNGLLINKPROGRAMPROC glLinkProgram; //Require GL_ARB_shader_objects - FF_PFNGLGETPROGRAMIVPROC glGetProgramiv; //Require GL_ARB_shader_objects - FF_PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; //Require GL_ARB_shader_objects - FF_PFNGLATTACHSHADERPROC glAttachShader; //Require GL_ARB_shader_objects - FF_PFNGLCREATESHADERPROC glCreateShader; //Require GL_ARB_shader_objects - FF_PFNGLDELETESHADERPROC glDeleteShader; //Require GL_ARB_shader_objects - FF_PFNGLCOMPILESHADERPROC glCompileShader; //Require GL_ARB_shader_objects - FF_PFNGLSHADERSOURCEPROC glShaderSource; //Require GL_ARB_shader_objects - FF_PFNGLGETSHADERIVPROC glGetShaderiv; //Require GL_ARB_shader_objects - FF_PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; //Require GL_ARB_shader_objects -} FFOpenGLFunctions; - -#define OPENGL_ERROR_CHECK(ctx) \ -{\ - GLenum err_code; \ - if ((err_code = glGetError()) != GL_NO_ERROR) { \ - av_log(ctx, AV_LOG_ERROR, "OpenGL error occurred in '%s', line %d: %d\n", __func__, __LINE__, err_code); \ - goto fail; \ - } \ -}\ - -typedef struct OpenGLVertexInfo -{ - float x, y, z; ///texture_name); - opengl->texture_name[0] = opengl->texture_name[1] = - opengl->texture_name[2] = opengl->texture_name[3] = 0; - if (opengl->glprocs.glUseProgram) - opengl->glprocs.glUseProgram(0); - if (opengl->glprocs.glDeleteProgram) { - opengl->glprocs.glDeleteProgram(opengl->program); - opengl->program = 0; - } - if (opengl->glprocs.glDeleteShader) { - opengl->glprocs.glDeleteShader(opengl->vertex_shader); - opengl->glprocs.glDeleteShader(opengl->fragment_shader); - opengl->vertex_shader = opengl->fragment_shader = 0; - } - if (opengl->glprocs.glBindBuffer) { - opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, 0); - opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, 0); - } - if (opengl->glprocs.glDeleteBuffers) { - opengl->glprocs.glDeleteBuffers(2, &opengl->index_buffer); - opengl->vertex_buffer = opengl->index_buffer = 0; - } -} - -static int opengl_resize(AVFormatContext *h, int width, int height) -{ - int ret = 0; - OpenGLContext *opengl = h->priv_data; - opengl->window_width = width; - opengl->window_height = height; - if (opengl->inited) { - if (opengl->no_window && - (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n"); - goto end; - } - if ((ret = opengl_prepare_vertex(h)) < 0) - goto end; - ret = opengl_draw(h, NULL, 1, 0); - } - end: - return ret; -} - -static int opengl_control_message(AVFormatContext *h, int type, void *data, size_t data_size) -{ - OpenGLContext *opengl = h->priv_data; - switch(type) { - case AV_APP_TO_DEV_WINDOW_SIZE: - if (data) { - AVDeviceRect *message = data; - return opengl_resize(h, message->width, message->height); - } - return AVERROR(EINVAL); - case AV_APP_TO_DEV_WINDOW_REPAINT: - return opengl_resize(h, opengl->window_width, opengl->window_height); - } - return AVERROR(ENOSYS); -} - -#if CONFIG_SDL2 -static int opengl_sdl_process_events(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - AVDeviceRect message; - SDL_Event event; - SDL_PumpEvents(); - while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) > 0) { - switch (event.type) { - case SDL_QUIT: - return AVERROR(EIO); - case SDL_KEYDOWN: - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - case SDLK_q: - return AVERROR(EIO); - } - return 0; - case SDL_WINDOWEVENT: - switch(event.window.event) { - case SDL_WINDOWEVENT_RESIZED: - case SDL_WINDOWEVENT_SIZE_CHANGED: - SDL_GL_GetDrawableSize(opengl->window, &message.width, &message.height); - return opengl_control_message(h, AV_APP_TO_DEV_WINDOW_SIZE, &message, sizeof(AVDeviceRect)); - default: - break; - } - } - } - return 0; -} - -static int av_cold opengl_sdl_create_window(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - AVDeviceRect message; - if (SDL_Init(SDL_INIT_VIDEO)) { - av_log(opengl, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError()); - return AVERROR_EXTERNAL; - } - opengl->window = SDL_CreateWindow(opengl->window_title, - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - opengl->window_width, opengl->window_height, - SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL); - if (!opengl->window) { - av_log(opengl, AV_LOG_ERROR, "Unable to create default window: %s\n", SDL_GetError()); - return AVERROR_EXTERNAL; - } - opengl->glcontext = SDL_GL_CreateContext(opengl->window); - if (!opengl->glcontext) { - av_log(opengl, AV_LOG_ERROR, "Unable to create OpenGL context on default window: %s\n", SDL_GetError()); - return AVERROR_EXTERNAL; - } - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - av_log(opengl, AV_LOG_INFO, "SDL driver: '%s'.\n", SDL_GetCurrentVideoDriver()); - SDL_GL_GetDrawableSize(opengl->window, &message.width, &message.height); - return opengl_control_message(h, AV_APP_TO_DEV_WINDOW_SIZE, &message, sizeof(AVDeviceRect)); -} - -static int av_cold opengl_sdl_load_procedures(OpenGLContext *opengl) -{ - FFOpenGLFunctions *procs = &opengl->glprocs; - -#define LOAD_OPENGL_FUN(name, type) \ - procs->name = (type)SDL_GL_GetProcAddress(#name); \ - if (!procs->name) { \ - av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \ - return AVERROR(ENOSYS); \ - } - - LOAD_OPENGL_FUN(glActiveTexture, FF_PFNGLACTIVETEXTUREPROC) - LOAD_OPENGL_FUN(glGenBuffers, FF_PFNGLGENBUFFERSPROC) - LOAD_OPENGL_FUN(glDeleteBuffers, FF_PFNGLDELETEBUFFERSPROC) - LOAD_OPENGL_FUN(glBufferData, FF_PFNGLBUFFERDATAPROC) - LOAD_OPENGL_FUN(glBindBuffer, FF_PFNGLBINDBUFFERPROC) - LOAD_OPENGL_FUN(glGetAttribLocation, FF_PFNGLGETATTRIBLOCATIONPROC) - LOAD_OPENGL_FUN(glGetUniformLocation, FF_PFNGLGETUNIFORMLOCATIONPROC) - LOAD_OPENGL_FUN(glUniform1f, FF_PFNGLUNIFORM1FPROC) - LOAD_OPENGL_FUN(glUniform1i, FF_PFNGLUNIFORM1IPROC) - LOAD_OPENGL_FUN(glUniformMatrix4fv, FF_PFNGLUNIFORMMATRIX4FVPROC) - LOAD_OPENGL_FUN(glCreateProgram, FF_PFNGLCREATEPROGRAMPROC) - LOAD_OPENGL_FUN(glDeleteProgram, FF_PFNGLDELETEPROGRAMPROC) - LOAD_OPENGL_FUN(glUseProgram, FF_PFNGLUSEPROGRAMPROC) - LOAD_OPENGL_FUN(glLinkProgram, FF_PFNGLLINKPROGRAMPROC) - LOAD_OPENGL_FUN(glGetProgramiv, FF_PFNGLGETPROGRAMIVPROC) - LOAD_OPENGL_FUN(glGetProgramInfoLog, FF_PFNGLGETPROGRAMINFOLOGPROC) - LOAD_OPENGL_FUN(glAttachShader, FF_PFNGLATTACHSHADERPROC) - LOAD_OPENGL_FUN(glCreateShader, FF_PFNGLCREATESHADERPROC) - LOAD_OPENGL_FUN(glDeleteShader, FF_PFNGLDELETESHADERPROC) - LOAD_OPENGL_FUN(glCompileShader, FF_PFNGLCOMPILESHADERPROC) - LOAD_OPENGL_FUN(glShaderSource, FF_PFNGLSHADERSOURCEPROC) - LOAD_OPENGL_FUN(glGetShaderiv, FF_PFNGLGETSHADERIVPROC) - LOAD_OPENGL_FUN(glGetShaderInfoLog, FF_PFNGLGETSHADERINFOLOGPROC) - LOAD_OPENGL_FUN(glEnableVertexAttribArray, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC) - LOAD_OPENGL_FUN(glVertexAttribPointer, FF_PFNGLVERTEXATTRIBPOINTERPROC) - - return 0; - -#undef LOAD_OPENGL_FUN -} -#endif /* CONFIG_SDL2 */ - -#if defined(__APPLE__) -static int av_cold opengl_load_procedures(OpenGLContext *opengl) -{ - FFOpenGLFunctions *procs = &opengl->glprocs; - -#if CONFIG_SDL2 - if (!opengl->no_window) - return opengl_sdl_load_procedures(opengl); -#endif - - procs->glActiveTexture = glActiveTexture; - procs->glGenBuffers = glGenBuffers; - procs->glDeleteBuffers = glDeleteBuffers; - procs->glBufferData = glBufferData; - procs->glBindBuffer = glBindBuffer; - procs->glGetAttribLocation = glGetAttribLocation; - procs->glGetUniformLocation = glGetUniformLocation; - procs->glUniform1f = glUniform1f; - procs->glUniform1i = glUniform1i; - procs->glUniformMatrix4fv = glUniformMatrix4fv; - procs->glCreateProgram = glCreateProgram; - procs->glDeleteProgram = glDeleteProgram; - procs->glUseProgram = glUseProgram; - procs->glLinkProgram = glLinkProgram; - procs->glGetProgramiv = glGetProgramiv; - procs->glGetProgramInfoLog = glGetProgramInfoLog; - procs->glAttachShader = glAttachShader; - procs->glCreateShader = glCreateShader; - procs->glDeleteShader = glDeleteShader; - procs->glCompileShader = glCompileShader; - procs->glShaderSource = glShaderSource; - procs->glGetShaderiv = glGetShaderiv; - procs->glGetShaderInfoLog = glGetShaderInfoLog; - procs->glEnableVertexAttribArray = glEnableVertexAttribArray; - procs->glVertexAttribPointer = (FF_PFNGLVERTEXATTRIBPOINTERPROC) glVertexAttribPointer; - return 0; -} -#else -static int av_cold opengl_load_procedures(OpenGLContext *opengl) -{ - FFOpenGLFunctions *procs = &opengl->glprocs; - -#if HAVE_GLXGETPROCADDRESS -#define SelectedGetProcAddress glXGetProcAddress -#elif HAVE_WGLGETPROCADDRESS -#define SelectedGetProcAddress wglGetProcAddress -#endif - -#define LOAD_OPENGL_FUN(name, type) \ - procs->name = (type)SelectedGetProcAddress(#name); \ - if (!procs->name) { \ - av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \ - return AVERROR(ENOSYS); \ - } - -#if CONFIG_SDL2 - if (!opengl->no_window) - return opengl_sdl_load_procedures(opengl); -#endif - - LOAD_OPENGL_FUN(glActiveTexture, FF_PFNGLACTIVETEXTUREPROC) - LOAD_OPENGL_FUN(glGenBuffers, FF_PFNGLGENBUFFERSPROC) - LOAD_OPENGL_FUN(glDeleteBuffers, FF_PFNGLDELETEBUFFERSPROC) - LOAD_OPENGL_FUN(glBufferData, FF_PFNGLBUFFERDATAPROC) - LOAD_OPENGL_FUN(glBindBuffer, FF_PFNGLBINDBUFFERPROC) - LOAD_OPENGL_FUN(glGetAttribLocation, FF_PFNGLGETATTRIBLOCATIONPROC) - LOAD_OPENGL_FUN(glGetUniformLocation, FF_PFNGLGETUNIFORMLOCATIONPROC) - LOAD_OPENGL_FUN(glUniform1f, FF_PFNGLUNIFORM1FPROC) - LOAD_OPENGL_FUN(glUniform1i, FF_PFNGLUNIFORM1IPROC) - LOAD_OPENGL_FUN(glUniformMatrix4fv, FF_PFNGLUNIFORMMATRIX4FVPROC) - LOAD_OPENGL_FUN(glCreateProgram, FF_PFNGLCREATEPROGRAMPROC) - LOAD_OPENGL_FUN(glDeleteProgram, FF_PFNGLDELETEPROGRAMPROC) - LOAD_OPENGL_FUN(glUseProgram, FF_PFNGLUSEPROGRAMPROC) - LOAD_OPENGL_FUN(glLinkProgram, FF_PFNGLLINKPROGRAMPROC) - LOAD_OPENGL_FUN(glGetProgramiv, FF_PFNGLGETPROGRAMIVPROC) - LOAD_OPENGL_FUN(glGetProgramInfoLog, FF_PFNGLGETPROGRAMINFOLOGPROC) - LOAD_OPENGL_FUN(glAttachShader, FF_PFNGLATTACHSHADERPROC) - LOAD_OPENGL_FUN(glCreateShader, FF_PFNGLCREATESHADERPROC) - LOAD_OPENGL_FUN(glDeleteShader, FF_PFNGLDELETESHADERPROC) - LOAD_OPENGL_FUN(glCompileShader, FF_PFNGLCOMPILESHADERPROC) - LOAD_OPENGL_FUN(glShaderSource, FF_PFNGLSHADERSOURCEPROC) - LOAD_OPENGL_FUN(glGetShaderiv, FF_PFNGLGETSHADERIVPROC) - LOAD_OPENGL_FUN(glGetShaderInfoLog, FF_PFNGLGETSHADERINFOLOGPROC) - LOAD_OPENGL_FUN(glEnableVertexAttribArray, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC) - LOAD_OPENGL_FUN(glVertexAttribPointer, FF_PFNGLVERTEXATTRIBPOINTERPROC) - - return 0; - -#undef SelectedGetProcAddress -#undef LOAD_OPENGL_FUN -} -#endif - -static void opengl_make_identity(float matrix[16]) -{ - memset(matrix, 0, 16 * sizeof(float)); - matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f; -} - -static void opengl_make_ortho(float matrix[16], float left, float right, - float bottom, float top, float nearZ, float farZ) -{ - float ral = right + left; - float rsl = right - left; - float tab = top + bottom; - float tsb = top - bottom; - float fan = farZ + nearZ; - float fsn = farZ - nearZ; - - memset(matrix, 0, 16 * sizeof(float)); - matrix[0] = 2.0f / rsl; - matrix[5] = 2.0f / tsb; - matrix[10] = -2.0f / fsn; - matrix[12] = -ral / rsl; - matrix[13] = -tab / tsb; - matrix[14] = -fan / fsn; - matrix[15] = 1.0f; -} - -static av_cold int opengl_read_limits(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - static const struct{ - const char *extension; - int major; - int minor; - } required_extensions[] = { - { "GL_ARB_multitexture", 1, 3 }, - { "GL_ARB_vertex_buffer_object", 1, 5 }, //GLX_ARB_vertex_buffer_object - { "GL_ARB_vertex_shader", 2, 0 }, - { "GL_ARB_fragment_shader", 2, 0 }, - { "GL_ARB_shader_objects", 2, 0 }, - { NULL, 0, 0 } - }; - int i, major, minor; - const char *extensions, *version; - - version = glGetString(GL_VERSION); - extensions = glGetString(GL_EXTENSIONS); - if (!version || !extensions) { - av_log(h, AV_LOG_ERROR, "No OpenGL context initialized for the current thread\n"); - return AVERROR(ENOSYS); - } - - av_log(h, AV_LOG_DEBUG, "OpenGL version: %s\n", version); - if (sscanf(version, "%d.%d", &major, &minor) != 2) - return AVERROR(ENOSYS); - - for (i = 0; required_extensions[i].extension; i++) { - if (major < required_extensions[i].major && - (major == required_extensions[i].major && minor < required_extensions[i].minor) && - !strstr(extensions, required_extensions[i].extension)) { - av_log(h, AV_LOG_ERROR, "Required extension %s is not supported.\n", - required_extensions[i].extension); - av_log(h, AV_LOG_DEBUG, "Supported extensions are: %s\n", extensions); - return AVERROR(ENOSYS); - } - } - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &opengl->max_texture_size); - glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &opengl->max_viewport_width); - opengl->non_pow_2_textures = major >= 2 || strstr(extensions, "GL_ARB_texture_non_power_of_two"); -#if defined(GL_ES_VERSION_2_0) - opengl->unpack_subimage = !!strstr(extensions, "GL_EXT_unpack_subimage"); -#else - opengl->unpack_subimage = 1; -#endif - - av_log(h, AV_LOG_DEBUG, "Non Power of 2 textures support: %s\n", opengl->non_pow_2_textures ? "Yes" : "No"); - av_log(h, AV_LOG_DEBUG, "Unpack Subimage extension support: %s\n", opengl->unpack_subimage ? "Yes" : "No"); - av_log(h, AV_LOG_DEBUG, "Max texture size: %dx%d\n", opengl->max_texture_size, opengl->max_texture_size); - av_log(h, AV_LOG_DEBUG, "Max viewport size: %dx%d\n", - opengl->max_viewport_width, opengl->max_viewport_height); - - OPENGL_ERROR_CHECK(opengl); - return 0; - fail: - return AVERROR_EXTERNAL; -} - -static const char* opengl_get_fragment_shader_code(enum AVPixelFormat format) -{ - int i; - for (i = 0; i < FF_ARRAY_ELEMS(opengl_format_desc); i++) { - if (opengl_format_desc[i].fixel_format == format) - return *opengl_format_desc[i].fragment_shader; - } - return NULL; -} - -static int opengl_type_size(GLenum type) -{ - switch(type) { - case GL_UNSIGNED_SHORT: - case FF_GL_UNSIGNED_SHORT_1_5_5_5_REV: - case GL_UNSIGNED_SHORT_5_6_5: - return 2; - case GL_UNSIGNED_BYTE: - case FF_GL_UNSIGNED_BYTE_3_3_2: - case FF_GL_UNSIGNED_BYTE_2_3_3_REV: - default: - break; - } - return 1; -} - -static av_cold void opengl_get_texture_params(OpenGLContext *opengl) -{ - int i; - for (i = 0; i < FF_ARRAY_ELEMS(opengl_format_desc); i++) { - if (opengl_format_desc[i].fixel_format == opengl->pix_fmt) { - opengl->format = opengl_format_desc[i].format; - opengl->type = opengl_format_desc[i].type; - break; - } - } -} - -static void opengl_compute_display_area(AVFormatContext *s) -{ - AVRational sar, dar; /* sample and display aspect ratios */ - OpenGLContext *opengl = s->priv_data; - AVStream *st = s->streams[0]; - AVCodecParameters *par = st->codecpar; - - /* compute overlay width and height from the codec context information */ - sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 }; - dar = av_mul_q(sar, (AVRational){ par->width, par->height }); - - /* we suppose the screen has a 1/1 sample aspect ratio */ - /* fit in the window */ - if (av_cmp_q(dar, (AVRational){ opengl->window_width, opengl->window_height }) > 0) { - /* fit in width */ - opengl->picture_width = opengl->window_width; - opengl->picture_height = av_rescale(opengl->picture_width, dar.den, dar.num); - } else { - /* fit in height */ - opengl->picture_height = opengl->window_height; - opengl->picture_width = av_rescale(opengl->picture_height, dar.num, dar.den); - } -} - -static av_cold void opengl_get_texture_size(OpenGLContext *opengl, int in_width, int in_height, - int *out_width, int *out_height) -{ - if (opengl->non_pow_2_textures) { - *out_width = in_width; - *out_height = in_height; - } else { - int max = FFMIN(FFMAX(in_width, in_height), opengl->max_texture_size); - unsigned power_of_2 = 1; - while (power_of_2 < max) - power_of_2 *= 2; - *out_height = power_of_2; - *out_width = power_of_2; - av_log(opengl, AV_LOG_DEBUG, "Texture size calculated from %dx%d into %dx%d\n", - in_width, in_height, *out_width, *out_height); - } -} - -static av_cold void opengl_fill_color_map(OpenGLContext *opengl) -{ - const AVPixFmtDescriptor *desc; - int shift; - enum AVPixelFormat pix_fmt = opengl->pix_fmt; - - /* We need order of components, not exact position, some minor HACKs here */ - if (pix_fmt == AV_PIX_FMT_RGB565 || pix_fmt == AV_PIX_FMT_BGR555 || - pix_fmt == AV_PIX_FMT_BGR8 || pix_fmt == AV_PIX_FMT_RGB8) - pix_fmt = AV_PIX_FMT_RGB24; - else if (pix_fmt == AV_PIX_FMT_BGR565 || pix_fmt == AV_PIX_FMT_RGB555) - pix_fmt = AV_PIX_FMT_BGR24; - - desc = av_pix_fmt_desc_get(pix_fmt); - if (!(desc->flags & AV_PIX_FMT_FLAG_RGB)) - return; - -#define FILL_COMPONENT(i) { \ - shift = (desc->comp[i].depth - 1) >> 3; \ - opengl->color_map[(i << 2) + (desc->comp[i].offset >> shift)] = 1.0; \ - } - - memset(opengl->color_map, 0, sizeof(opengl->color_map)); - FILL_COMPONENT(0); - FILL_COMPONENT(1); - FILL_COMPONENT(2); - if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) - FILL_COMPONENT(3); - -#undef FILL_COMPONENT -} - -static av_cold GLuint opengl_load_shader(OpenGLContext *opengl, GLenum type, const char *source) -{ - GLuint shader = opengl->glprocs.glCreateShader(type); - GLint result; - if (!shader) { - av_log(opengl, AV_LOG_ERROR, "glCreateShader() failed\n"); - return 0; - } - opengl->glprocs.glShaderSource(shader, 1, &source, NULL); - opengl->glprocs.glCompileShader(shader); - - opengl->glprocs.glGetShaderiv(shader, FF_GL_COMPILE_STATUS, &result); - if (!result) { - char *log; - opengl->glprocs.glGetShaderiv(shader, FF_GL_INFO_LOG_LENGTH, &result); - if (result) { - if ((log = av_malloc(result))) { - opengl->glprocs.glGetShaderInfoLog(shader, result, NULL, log); - av_log(opengl, AV_LOG_ERROR, "Compile error: %s\n", log); - av_free(log); - } - } - goto fail; - } - OPENGL_ERROR_CHECK(opengl); - return shader; - fail: - opengl->glprocs.glDeleteShader(shader); - return 0; -} - -static av_cold int opengl_compile_shaders(OpenGLContext *opengl, enum AVPixelFormat pix_fmt) -{ - GLint result; - const char *fragment_shader_code = opengl_get_fragment_shader_code(pix_fmt); - - if (!fragment_shader_code) { - av_log(opengl, AV_LOG_ERROR, "Provided pixel format '%s' is not supported\n", - av_get_pix_fmt_name(pix_fmt)); - return AVERROR(EINVAL); - } - - opengl->vertex_shader = opengl_load_shader(opengl, FF_GL_VERTEX_SHADER, - FF_OPENGL_VERTEX_SHADER); - if (!opengl->vertex_shader) { - av_log(opengl, AV_LOG_ERROR, "Vertex shader loading failed.\n"); - goto fail; - } - opengl->fragment_shader = opengl_load_shader(opengl, FF_GL_FRAGMENT_SHADER, - fragment_shader_code); - if (!opengl->fragment_shader) { - av_log(opengl, AV_LOG_ERROR, "Fragment shader loading failed.\n"); - goto fail; - } - - opengl->program = opengl->glprocs.glCreateProgram(); - if (!opengl->program) - goto fail; - - opengl->glprocs.glAttachShader(opengl->program, opengl->vertex_shader); - opengl->glprocs.glAttachShader(opengl->program, opengl->fragment_shader); - opengl->glprocs.glLinkProgram(opengl->program); - - opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_LINK_STATUS, &result); - if (!result) { - char *log; - opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_INFO_LOG_LENGTH, &result); - if (result) { - log = av_malloc(result); - if (!log) - goto fail; - opengl->glprocs.glGetProgramInfoLog(opengl->program, result, NULL, log); - av_log(opengl, AV_LOG_ERROR, "Link error: %s\n", log); - av_free(log); - } - goto fail; - } - - opengl->position_attrib = opengl->glprocs.glGetAttribLocation(opengl->program, "a_position"); - opengl->texture_coords_attrib = opengl->glprocs.glGetAttribLocation(opengl->program, "a_textureCoords"); - opengl->projection_matrix_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_projectionMatrix"); - opengl->model_view_matrix_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_modelViewMatrix"); - opengl->color_map_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_colorMap"); - opengl->texture_location[0] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture0"); - opengl->texture_location[1] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture1"); - opengl->texture_location[2] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture2"); - opengl->texture_location[3] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture3"); - opengl->chroma_div_w_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_chroma_div_w"); - opengl->chroma_div_h_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_chroma_div_h"); - - OPENGL_ERROR_CHECK(opengl); - return 0; - fail: - opengl->glprocs.glDeleteShader(opengl->vertex_shader); - opengl->glprocs.glDeleteShader(opengl->fragment_shader); - opengl->glprocs.glDeleteProgram(opengl->program); - opengl->fragment_shader = opengl->vertex_shader = opengl->program = 0; - return AVERROR_EXTERNAL; -} - -static av_cold int opengl_configure_texture(OpenGLContext *opengl, GLuint texture, - GLsizei width, GLsizei height) -{ - if (texture) { - int new_width, new_height; - opengl_get_texture_size(opengl, width, height, &new_width, &new_height); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, opengl->format, new_width, new_height, 0, - opengl->format, opengl->type, NULL); - OPENGL_ERROR_CHECK(NULL); - } - return 0; - fail: - return AVERROR_EXTERNAL; -} - -static av_cold int opengl_prepare_vertex(AVFormatContext *s) -{ - OpenGLContext *opengl = s->priv_data; - int tex_w, tex_h; - - if (opengl->window_width > opengl->max_viewport_width || opengl->window_height > opengl->max_viewport_height) { - opengl->window_width = FFMIN(opengl->window_width, opengl->max_viewport_width); - opengl->window_height = FFMIN(opengl->window_height, opengl->max_viewport_height); - av_log(opengl, AV_LOG_WARNING, "Too big viewport requested, limited to %dx%d", opengl->window_width, opengl->window_height); - } - glViewport(0, 0, opengl->window_width, opengl->window_height); - opengl_make_ortho(opengl->projection_matrix, - - (float)opengl->window_width / 2.0f, (float)opengl->window_width / 2.0f, - - (float)opengl->window_height / 2.0f, (float)opengl->window_height / 2.0f, - 1.0f, -1.0f); - opengl_make_identity(opengl->model_view_matrix); - - opengl_compute_display_area(s); - - opengl->vertex[0].z = opengl->vertex[1].z = opengl->vertex[2].z = opengl->vertex[3].z = 0.0f; - opengl->vertex[0].x = opengl->vertex[1].x = - (float)opengl->picture_width / 2.0f; - opengl->vertex[2].x = opengl->vertex[3].x = (float)opengl->picture_width / 2.0f; - opengl->vertex[1].y = opengl->vertex[2].y = - (float)opengl->picture_height / 2.0f; - opengl->vertex[0].y = opengl->vertex[3].y = (float)opengl->picture_height / 2.0f; - - opengl_get_texture_size(opengl, opengl->width, opengl->height, &tex_w, &tex_h); - - opengl->vertex[0].s0 = 0.0f; - opengl->vertex[0].t0 = 0.0f; - opengl->vertex[1].s0 = 0.0f; - opengl->vertex[1].t0 = (float)opengl->height / (float)tex_h; - opengl->vertex[2].s0 = (float)opengl->width / (float)tex_w; - opengl->vertex[2].t0 = (float)opengl->height / (float)tex_h; - opengl->vertex[3].s0 = (float)opengl->width / (float)tex_w; - opengl->vertex[3].t0 = 0.0f; - - opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, opengl->vertex_buffer); - opengl->glprocs.glBufferData(FF_GL_ARRAY_BUFFER, sizeof(opengl->vertex), opengl->vertex, FF_GL_STATIC_DRAW); - opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, 0); - OPENGL_ERROR_CHECK(opengl); - return 0; - fail: - return AVERROR_EXTERNAL; -} - -static int opengl_prepare(OpenGLContext *opengl) -{ - int i; - opengl->glprocs.glUseProgram(opengl->program); - opengl->glprocs.glUniformMatrix4fv(opengl->projection_matrix_location, 1, GL_FALSE, opengl->projection_matrix); - opengl->glprocs.glUniformMatrix4fv(opengl->model_view_matrix_location, 1, GL_FALSE, opengl->model_view_matrix); - for (i = 0; i < 4; i++) - if (opengl->texture_location[i] != -1) { - opengl->glprocs.glActiveTexture(GL_TEXTURE0 + i); - glBindTexture(GL_TEXTURE_2D, opengl->texture_name[i]); - opengl->glprocs.glUniform1i(opengl->texture_location[i], i); - } - if (opengl->color_map_location != -1) - opengl->glprocs.glUniformMatrix4fv(opengl->color_map_location, 1, GL_FALSE, opengl->color_map); - if (opengl->chroma_div_h_location != -1) - opengl->glprocs.glUniform1f(opengl->chroma_div_h_location, opengl->chroma_div_h); - if (opengl->chroma_div_w_location != -1) - opengl->glprocs.glUniform1f(opengl->chroma_div_w_location, opengl->chroma_div_w); - - OPENGL_ERROR_CHECK(opengl); - return 0; - fail: - return AVERROR_EXTERNAL; -} - -static int opengl_create_window(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - int ret; - - if (!opengl->no_window) { -#if CONFIG_SDL2 - if ((ret = opengl_sdl_create_window(h)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Cannot create default SDL window.\n"); - return ret; - } -#else - av_log(opengl, AV_LOG_ERROR, "FFmpeg is compiled without SDL. Cannot create default window.\n"); - return AVERROR(ENOSYS); -#endif - } else { - AVDeviceRect message; - message.x = message.y = 0; - message.width = opengl->window_width; - message.height = opengl->window_height; - if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_CREATE_WINDOW_BUFFER, - &message , sizeof(message))) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to create window buffer.\n"); - return ret; - } - if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n"); - return ret; - } - } - return 0; -} - -static int opengl_release_window(AVFormatContext *h) -{ - int ret; - OpenGLContext *opengl = h->priv_data; - if (!opengl->no_window) { -#if CONFIG_SDL2 - SDL_GL_DeleteContext(opengl->glcontext); - SDL_DestroyWindow(opengl->window); - SDL_Quit(); -#endif - } else if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to release window buffer.\n"); - return ret; - } - return 0; -} - -static av_cold int opengl_write_trailer(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - - if (opengl->no_window && - avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0) < 0) - av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n"); - - opengl_deinit_context(opengl); - opengl_release_window(h); - - return 0; -} - -static av_cold int opengl_init_context(OpenGLContext *opengl) -{ - int i, ret; - const AVPixFmtDescriptor *desc; - - if ((ret = opengl_compile_shaders(opengl, opengl->pix_fmt)) < 0) - goto fail; - - desc = av_pix_fmt_desc_get(opengl->pix_fmt); - av_assert0(desc->nb_components > 0 && desc->nb_components <= 4); - glGenTextures(desc->nb_components, opengl->texture_name); - - opengl->glprocs.glGenBuffers(2, &opengl->index_buffer); - if (!opengl->index_buffer || !opengl->vertex_buffer) { - av_log(opengl, AV_LOG_ERROR, "Buffer generation failed.\n"); - ret = AVERROR_EXTERNAL; - goto fail; - } - - opengl_configure_texture(opengl, opengl->texture_name[0], opengl->width, opengl->height); - if (desc->nb_components > 1) { - int has_alpha = desc->flags & AV_PIX_FMT_FLAG_ALPHA; - int num_planes = desc->nb_components - (has_alpha ? 1 : 0); - if (opengl->non_pow_2_textures) { - opengl->chroma_div_w = 1.0f; - opengl->chroma_div_h = 1.0f; - } else { - opengl->chroma_div_w = 1 << desc->log2_chroma_w; - opengl->chroma_div_h = 1 << desc->log2_chroma_h; - } - for (i = 1; i < num_planes; i++) - if (opengl->non_pow_2_textures) - opengl_configure_texture(opengl, opengl->texture_name[i], - AV_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w), - AV_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h)); - else - opengl_configure_texture(opengl, opengl->texture_name[i], opengl->width, opengl->height); - if (has_alpha) - opengl_configure_texture(opengl, opengl->texture_name[3], opengl->width, opengl->height); - } - - opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer); - opengl->glprocs.glBufferData(FF_GL_ELEMENT_ARRAY_BUFFER, sizeof(g_index), g_index, FF_GL_STATIC_DRAW); - opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, 0); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glClearColor((float)opengl->background[0] / 255.0f, (float)opengl->background[1] / 255.0f, - (float)opengl->background[2] / 255.0f, 1.0f); - - ret = AVERROR_EXTERNAL; - OPENGL_ERROR_CHECK(opengl); - - return 0; - fail: - return ret; -} - -static av_cold int opengl_write_header(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - AVCodecParameters *par = h->streams[0]->codecpar; - AVStream *st; - int ret; - - if (!opengl->warned) { - av_log(opengl, AV_LOG_WARNING, - "The opengl output device is deprecated due to being fundamentally incompatible with libavformat API. " - "For monitoring purposes in ffmpeg you can output to a file or use pipes and a video player.\n" - "Example: ffmpeg -i INPUT -f nut -c:v rawvideo - | ffplay -loglevel warning -vf setpts=0 -\n" - ); - opengl->warned = 1; - } - - if (h->nb_streams != 1 || - par->codec_type != AVMEDIA_TYPE_VIDEO || - (par->codec_id != AV_CODEC_ID_WRAPPED_AVFRAME && par->codec_id != AV_CODEC_ID_RAWVIDEO)) { - av_log(opengl, AV_LOG_ERROR, "Only a single raw or wrapped avframe video stream is supported.\n"); - return AVERROR(EINVAL); - } - st = h->streams[0]; - opengl->width = st->codecpar->width; - opengl->height = st->codecpar->height; - opengl->pix_fmt = st->codecpar->format; - if (!opengl->window_width) - opengl->window_width = opengl->width; - if (!opengl->window_height) - opengl->window_height = opengl->height; - - if (!opengl->window_title && !opengl->no_window) - opengl->window_title = av_strdup(h->url); - - if ((ret = opengl_create_window(h))) - goto fail; - - if ((ret = opengl_read_limits(h)) < 0) - goto fail; - - if (opengl->width > opengl->max_texture_size || opengl->height > opengl->max_texture_size) { - av_log(opengl, AV_LOG_ERROR, "Too big picture %dx%d, max supported size is %dx%d\n", - opengl->width, opengl->height, opengl->max_texture_size, opengl->max_texture_size); - ret = AVERROR(EINVAL); - goto fail; - } - - if ((ret = opengl_load_procedures(opengl)) < 0) - goto fail; - - opengl_fill_color_map(opengl); - opengl_get_texture_params(opengl); - - if ((ret = opengl_init_context(opengl)) < 0) - goto fail; - - if ((ret = opengl_prepare_vertex(h)) < 0) - goto fail; - - glClear(GL_COLOR_BUFFER_BIT); - -#if CONFIG_SDL2 - if (!opengl->no_window) - SDL_GL_SwapWindow(opengl->window); -#endif - if (opengl->no_window && - (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n"); - goto fail; - } - - ret = AVERROR_EXTERNAL; - OPENGL_ERROR_CHECK(opengl); - - opengl->inited = 1; - return 0; - - fail: - opengl_write_trailer(h); - return ret; -} - -static uint8_t* opengl_get_plane_pointer(OpenGLContext *opengl, AVPacket *pkt, int comp_index, - const AVPixFmtDescriptor *desc) -{ - uint8_t *data = pkt->data; - int wordsize = opengl_type_size(opengl->type); - int width_chroma = AV_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w); - int height_chroma = AV_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h); - int plane = desc->comp[comp_index].plane; - - switch(plane) { - case 0: - break; - case 1: - data += opengl->width * opengl->height * wordsize; - break; - case 2: - data += opengl->width * opengl->height * wordsize; - data += width_chroma * height_chroma * wordsize; - break; - case 3: - data += opengl->width * opengl->height * wordsize; - data += 2 * width_chroma * height_chroma * wordsize; - break; - default: - return NULL; - } - return data; -} - -#define LOAD_TEXTURE_DATA(comp_index, sub) \ -{ \ - int width = sub ? AV_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w) : opengl->width; \ - int height = sub ? AV_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h): opengl->height; \ - uint8_t *data; \ - int plane = desc->comp[comp_index].plane; \ - \ - glBindTexture(GL_TEXTURE_2D, opengl->texture_name[comp_index]); \ - if (!is_pkt) { \ - GLint length = ((AVFrame *)input)->linesize[plane]; \ - int bytes_per_pixel = opengl_type_size(opengl->type); \ - if (!(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) \ - bytes_per_pixel *= desc->nb_components; \ - data = ((AVFrame *)input)->data[plane]; \ - if (!(length % bytes_per_pixel) && \ - (opengl->unpack_subimage || ((length / bytes_per_pixel) == width))) { \ - length /= bytes_per_pixel; \ - if (length != width) \ - glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, length); \ - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \ - opengl->format, opengl->type, data); \ - if (length != width) \ - glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, 0); \ - } else { \ - int h; \ - for (h = 0; h < height; h++) { \ - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, h, width, 1, \ - opengl->format, opengl->type, data); \ - data += length; \ - } \ - } \ - } else { \ - data = opengl_get_plane_pointer(opengl, input, comp_index, desc); \ - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \ - opengl->format, opengl->type, data); \ - } \ -} - -static int opengl_draw(AVFormatContext *h, void *input, int repaint, int is_pkt) -{ - OpenGLContext *opengl = h->priv_data; - enum AVPixelFormat pix_fmt = h->streams[0]->codecpar->format; - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - int ret; - -#if CONFIG_SDL2 - /* At this point, opengl->glcontext implies opengl->glcontext */ - if (opengl->glcontext) - SDL_GL_MakeCurrent(opengl->window, opengl->glcontext); - - if (!opengl->no_window && (ret = opengl_sdl_process_events(h)) < 0) - goto fail; -#endif - if (opengl->no_window && - (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n"); - goto fail; - } - - glClear(GL_COLOR_BUFFER_BIT); - - if (!repaint) { - if (is_pkt) - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - LOAD_TEXTURE_DATA(0, 0) - if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) { - LOAD_TEXTURE_DATA(1, 1) - LOAD_TEXTURE_DATA(2, 1) - if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) - LOAD_TEXTURE_DATA(3, 0) - } - } - ret = AVERROR_EXTERNAL; - OPENGL_ERROR_CHECK(opengl); - - if ((ret = opengl_prepare(opengl)) < 0) - goto fail; - - opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, opengl->vertex_buffer); - opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer); - opengl->glprocs.glVertexAttribPointer(opengl->position_attrib, 3, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 0); - opengl->glprocs.glEnableVertexAttribArray(opengl->position_attrib); - opengl->glprocs.glVertexAttribPointer(opengl->texture_coords_attrib, 2, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 12); - opengl->glprocs.glEnableVertexAttribArray(opengl->texture_coords_attrib); - - glDrawElements(GL_TRIANGLES, FF_ARRAY_ELEMS(g_index), GL_UNSIGNED_SHORT, 0); - - ret = AVERROR_EXTERNAL; - OPENGL_ERROR_CHECK(opengl); - -#if CONFIG_SDL2 - if (!opengl->no_window) - SDL_GL_SwapWindow(opengl->window); -#endif - if (opengl->no_window && - (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n"); - goto fail; - } - - return 0; - fail: - return ret; -} - -static int opengl_write_packet(AVFormatContext *h, AVPacket *pkt) -{ - AVCodecParameters *par = h->streams[0]->codecpar; - if (par->codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) { - AVFrame *frame = (AVFrame *)pkt->data; - return opengl_draw(h, frame, 0, 0); - } else { - return opengl_draw(h, pkt, 0, 1); - } -} - -static int opengl_write_frame(AVFormatContext *h, int stream_index, - AVFrame **frame, unsigned flags) -{ - if ((flags & AV_WRITE_UNCODED_FRAME_QUERY)) - return 0; - return opengl_draw(h, *frame, 0, 0); -} - -#define OFFSET(x) offsetof(OpenGLContext, x) -#define ENC AV_OPT_FLAG_ENCODING_PARAM -static const AVOption options[] = { - { "background", "set background color", OFFSET(background), AV_OPT_TYPE_COLOR, {.str = "black"}, 0, 0, ENC }, - { "no_window", "disable default window", OFFSET(no_window), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, ENC }, - { "window_title", "set window title", OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, ENC }, - { "window_size", "set window size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, ENC }, - { NULL } -}; - -static const AVClass opengl_class = { - .class_name = "opengl outdev", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, - .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT, -}; - -const FFOutputFormat ff_opengl_muxer = { - .p.name = "opengl", - .p.long_name = NULL_IF_CONFIG_SMALL("OpenGL output"), - .p.audio_codec = AV_CODEC_ID_NONE, - .p.video_codec = AV_CODEC_ID_WRAPPED_AVFRAME, - .p.flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS, - .p.priv_class = &opengl_class, - .priv_data_size = sizeof(OpenGLContext), - .write_header = opengl_write_header, - .write_packet = opengl_write_packet, - .write_uncoded_frame = opengl_write_frame, - .write_trailer = opengl_write_trailer, - .control_message = opengl_control_message, -}; diff --git a/libavdevice/opengl_enc_shaders.h b/libavdevice/opengl_enc_shaders.h deleted file mode 100644 index 67ee0ae7b..000000000 --- a/libavdevice/opengl_enc_shaders.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2014 Lukasz Marek - * - * 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 AVDEVICE_OPENGL_ENC_SHADERS_H -#define AVDEVICE_OPENGL_ENC_SHADERS_H - -#include "libavutil/pixfmt.h" - -static const char * const FF_OPENGL_VERTEX_SHADER = - "uniform mat4 u_projectionMatrix;" - "uniform mat4 u_modelViewMatrix;" - - "attribute vec4 a_position;" - "attribute vec2 a_textureCoords;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "gl_Position = u_projectionMatrix * (a_position * u_modelViewMatrix);" - "texture_coordinate = a_textureCoords;" - "}"; - -/** - * Fragment shader for packet RGBA formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform mat4 u_colorMap;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "gl_FragColor = texture2D(u_texture0, texture_coordinate) * u_colorMap;" - "}"; - -/** - * Fragment shader for packet RGB formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform mat4 u_colorMap;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "gl_FragColor = vec4((texture2D(u_texture0, texture_coordinate) * u_colorMap).rgb, 1.0);" - "}"; - -/** - * Fragment shader for planar RGBA formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform sampler2D u_texture1;" - "uniform sampler2D u_texture2;" - "uniform sampler2D u_texture3;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "gl_FragColor = vec4(texture2D(u_texture0, texture_coordinate).r," - "texture2D(u_texture1, texture_coordinate).r," - "texture2D(u_texture2, texture_coordinate).r," - "texture2D(u_texture3, texture_coordinate).r);" - "}"; - -/** - * Fragment shader for planar RGB formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform sampler2D u_texture1;" - "uniform sampler2D u_texture2;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "gl_FragColor = vec4(texture2D(u_texture0, texture_coordinate).r," - "texture2D(u_texture1, texture_coordinate).r," - "texture2D(u_texture2, texture_coordinate).r," - "1.0);" - "}"; - -/** - * Fragment shader for planar YUV formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform sampler2D u_texture1;" - "uniform sampler2D u_texture2;" - "uniform float u_chroma_div_w;" - "uniform float u_chroma_div_h;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "vec3 yuv;" - - "yuv.r = texture2D(u_texture0, texture_coordinate).r - 0.0625;" - "yuv.g = texture2D(u_texture1, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;" - "yuv.b = texture2D(u_texture2, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;" - - "gl_FragColor = clamp(vec4(mat3(1.1643, 1.16430, 1.1643," - "0.0, -0.39173, 2.0170," - "1.5958, -0.81290, 0.0) * yuv, 1.0), 0.0, 1.0);" - - "}"; - -/** - * Fragment shader for planar YUVA formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform sampler2D u_texture1;" - "uniform sampler2D u_texture2;" - "uniform sampler2D u_texture3;" - "uniform float u_chroma_div_w;" - "uniform float u_chroma_div_h;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "vec3 yuv;" - - "yuv.r = texture2D(u_texture0, texture_coordinate).r - 0.0625;" - "yuv.g = texture2D(u_texture1, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;" - "yuv.b = texture2D(u_texture2, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;" - - "gl_FragColor = clamp(vec4(mat3(1.1643, 1.16430, 1.1643," - "0.0, -0.39173, 2.0170," - "1.5958, -0.81290, 0.0) * yuv, texture2D(u_texture3, texture_coordinate).r), 0.0, 1.0);" - "}"; - -static const char * const FF_OPENGL_FRAGMENT_SHADER_GRAY = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "varying vec2 texture_coordinate;" - "void main()" - "{" - "float c = texture2D(u_texture0, texture_coordinate).r;" - "gl_FragColor = vec4(c, c, c, 1.0);" - "}"; - -#endif /* AVDEVICE_OPENGL_ENC_SHADERS_H */ diff --git a/libavdevice/pulse_audio_enc.c b/libavdevice/pulse_audio_enc.c index 80136d1e2..d1652bf8d 100644 --- a/libavdevice/pulse_audio_enc.c +++ b/libavdevice/pulse_audio_enc.c @@ -796,11 +796,7 @@ const FFOutputFormat ff_pulse_muxer = { .get_output_timestamp = pulse_get_output_timestamp, .get_device_list = pulse_get_device_list, .control_message = pulse_control_message, -#if FF_API_ALLOW_FLUSH - .p.flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH, -#else .p.flags = AVFMT_NOFILE, -#endif .p.priv_class = &pulse_muxer_class, .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH, }; diff --git a/libavdevice/sdl2.c b/libavdevice/sdl2.c deleted file mode 100644 index 491c8dafe..000000000 --- a/libavdevice/sdl2.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (c) 2016 Josh de Kock - * - * 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 - * libSDL2 output device - */ - -#include -#include - -#include "libavutil/imgutils.h" -#include "libavutil/mem.h" -#include "libavutil/opt.h" -#include "libavutil/pixdesc.h" -#include "libavformat/mux.h" - -typedef struct { - AVClass *class; - SDL_Window *window; - SDL_Renderer *renderer; - char *window_title; - int window_width, window_height; /**< size of the window */ - int window_x, window_y; /**< position of the window */ - int window_fullscreen; - int window_borderless; - int enable_quit_action; - - SDL_Texture *texture; - int texture_fmt; - SDL_Rect texture_rect; - - int inited; - int warned; -} SDLContext; - -static const struct sdl_texture_format_entry { - enum AVPixelFormat format; int texture_fmt; -} sdl_texture_format_map[] = { - /* - * Not implemented in FFmpeg, but leaving here for completeness. - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ARGB4444 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_RGBA4444 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ABGR4444 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_BGRA4444 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ARGB1555 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_RGBA5551 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ABGR1555 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_BGRA5551 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ARGB2101010 }, - */ - { AV_PIX_FMT_RGB8, SDL_PIXELFORMAT_RGB332 }, - { AV_PIX_FMT_RGB444, SDL_PIXELFORMAT_RGB444 }, - { AV_PIX_FMT_RGB555, SDL_PIXELFORMAT_RGB555 }, - { AV_PIX_FMT_BGR555, SDL_PIXELFORMAT_BGR555 }, - { AV_PIX_FMT_RGB565, SDL_PIXELFORMAT_RGB565 }, - { AV_PIX_FMT_BGR565, SDL_PIXELFORMAT_BGR565 }, - { AV_PIX_FMT_RGB24, SDL_PIXELFORMAT_RGB24 }, - { AV_PIX_FMT_BGR24, SDL_PIXELFORMAT_BGR24 }, - { AV_PIX_FMT_0RGB32, SDL_PIXELFORMAT_RGB888 }, - { AV_PIX_FMT_0BGR32, SDL_PIXELFORMAT_BGR888 }, -#if HAVE_BIGENDIAN - { AV_PIX_FMT_RGB0, SDL_PIXELFORMAT_RGBX8888 }, - { AV_PIX_FMT_BGR0, SDL_PIXELFORMAT_BGRX8888 }, -#else - { AV_PIX_FMT_0BGR, SDL_PIXELFORMAT_RGBX8888 }, - { AV_PIX_FMT_0RGB, SDL_PIXELFORMAT_BGRX8888 }, -#endif - { AV_PIX_FMT_RGB32, SDL_PIXELFORMAT_ARGB8888 }, - { AV_PIX_FMT_RGB32_1, SDL_PIXELFORMAT_RGBA8888 }, - { AV_PIX_FMT_BGR32, SDL_PIXELFORMAT_ABGR8888 }, - { AV_PIX_FMT_BGR32_1, SDL_PIXELFORMAT_BGRA8888 }, - { AV_PIX_FMT_YUV420P, SDL_PIXELFORMAT_IYUV }, - { AV_PIX_FMT_YUYV422, SDL_PIXELFORMAT_YUY2 }, - { AV_PIX_FMT_UYVY422, SDL_PIXELFORMAT_UYVY }, - { AV_PIX_FMT_NONE, 0 }, -}; - -static void compute_texture_rect(AVFormatContext *s) -{ - AVRational sar, dar; /* sample and display aspect ratios */ - SDLContext *sdl = s->priv_data; - AVStream *st = s->streams[0]; - AVCodecParameters *codecpar = st->codecpar; - SDL_Rect *texture_rect = &sdl->texture_rect; - - /* compute texture width and height from the codec context information */ - sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 }; - dar = av_mul_q(sar, (AVRational){ codecpar->width, codecpar->height }); - - /* we suppose the screen has a 1/1 sample aspect ratio */ - if (sdl->window_width && sdl->window_height) { - /* fit in the window */ - if (av_cmp_q(dar, (AVRational){ sdl->window_width, sdl->window_height }) > 0) { - /* fit in width */ - texture_rect->w = sdl->window_width; - texture_rect->h = av_rescale(texture_rect->w, dar.den, dar.num); - } else { - /* fit in height */ - texture_rect->h = sdl->window_height; - texture_rect->w = av_rescale(texture_rect->h, dar.num, dar.den); - } - } else { - if (sar.num > sar.den) { - texture_rect->w = codecpar->width; - texture_rect->h = av_rescale(texture_rect->w, dar.den, dar.num); - } else { - texture_rect->h = codecpar->height; - texture_rect->w = av_rescale(texture_rect->h, dar.num, dar.den); - } - sdl->window_width = texture_rect->w; - sdl->window_height = texture_rect->h; - } - - texture_rect->x = (sdl->window_width - texture_rect->w) / 2; - texture_rect->y = (sdl->window_height - texture_rect->h) / 2; -} - -static int sdl2_write_trailer(AVFormatContext *s) -{ - SDLContext *sdl = s->priv_data; - - if (sdl->texture) - SDL_DestroyTexture(sdl->texture); - sdl->texture = NULL; - - if (sdl->renderer) - SDL_DestroyRenderer(sdl->renderer); - sdl->renderer = NULL; - - if (sdl->window) - SDL_DestroyWindow(sdl->window); - sdl->window = NULL; - - if (!sdl->inited) - SDL_Quit(); - - return 0; -} - -static int sdl2_write_header(AVFormatContext *s) -{ - SDLContext *sdl = s->priv_data; - AVStream *st = s->streams[0]; - AVCodecParameters *codecpar = st->codecpar; - int i, ret = 0; - int flags = 0; - - if (!sdl->warned) { - av_log(sdl, AV_LOG_WARNING, - "The sdl output device is deprecated due to being fundamentally incompatible with libavformat API. " - "For monitoring purposes in ffmpeg you can output to a file or use pipes and a video player.\n" - "Example: ffmpeg -i INPUT -f nut -c:v rawvideo - | ffplay -loglevel warning -vf setpts=0 -\n" - ); - sdl->warned = 1; - } - - if (!sdl->window_title) - sdl->window_title = av_strdup(s->url); - - if (SDL_WasInit(SDL_INIT_VIDEO)) { - av_log(s, AV_LOG_WARNING, - "SDL video subsystem was already inited, you could have multiple SDL outputs. This may cause unknown behaviour.\n"); - sdl->inited = 1; - } - - if ( s->nb_streams > 1 - || codecpar->codec_type != AVMEDIA_TYPE_VIDEO - || codecpar->codec_id != AV_CODEC_ID_RAWVIDEO) { - av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n"); - goto fail; - } - - for (i = 0; sdl_texture_format_map[i].format != AV_PIX_FMT_NONE; i++) { - if (sdl_texture_format_map[i].format == codecpar->format) { - sdl->texture_fmt = sdl_texture_format_map[i].texture_fmt; - break; - } - } - - if (!sdl->texture_fmt) { - av_log(s, AV_LOG_ERROR, - "Unsupported pixel format '%s'.\n", - av_get_pix_fmt_name(codecpar->format)); - goto fail; - } - - /* resize texture to width and height from the codec context information */ - flags = SDL_WINDOW_HIDDEN | - (sdl->window_fullscreen ? SDL_WINDOW_FULLSCREEN : 0) | - (sdl->window_borderless ? SDL_WINDOW_BORDERLESS : SDL_WINDOW_RESIZABLE); - - /* initialization */ - if (!sdl->inited){ - if (SDL_Init(SDL_INIT_VIDEO) != 0) { - av_log(s, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError()); - goto fail; - } - } - - compute_texture_rect(s); - - if (SDL_CreateWindowAndRenderer(sdl->window_width, sdl->window_height, - flags, &sdl->window, &sdl->renderer) != 0){ - av_log(sdl, AV_LOG_ERROR, "Couldn't create window and renderer: %s\n", SDL_GetError()); - goto fail; - } - - SDL_SetWindowTitle(sdl->window, sdl->window_title); - SDL_SetWindowPosition(sdl->window, sdl->window_x, sdl->window_y); - SDL_ShowWindow(sdl->window); - - sdl->texture = SDL_CreateTexture(sdl->renderer, sdl->texture_fmt, SDL_TEXTUREACCESS_STREAMING, - codecpar->width, codecpar->height); - - if (!sdl->texture) { - av_log(sdl, AV_LOG_ERROR, "Unable to set create mode: %s\n", SDL_GetError()); - goto fail; - } - - av_log(s, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s -> w:%d h:%d\n", - codecpar->width, codecpar->height, av_get_pix_fmt_name(codecpar->format), - sdl->window_width, sdl->window_height); - - sdl->inited = 1; - - return 0; -fail: - sdl2_write_trailer(s); - return ret; -} - -static int sdl2_write_packet(AVFormatContext *s, AVPacket *pkt) -{ - int ret, quit = 0; - SDLContext *sdl = s->priv_data; - AVCodecParameters *codecpar = s->streams[0]->codecpar; - uint8_t *data[4]; - int linesize[4]; - - SDL_Event event; - if (SDL_PollEvent(&event)){ - switch (event.type) { - case SDL_KEYDOWN: - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - case SDLK_q: - quit = 1; - break; - default: - break; - } - break; - case SDL_QUIT: - quit = 1; - break; - case SDL_WINDOWEVENT: - switch(event.window.event){ - case SDL_WINDOWEVENT_RESIZED: - case SDL_WINDOWEVENT_SIZE_CHANGED: - sdl->window_width = event.window.data1; - sdl->window_height = event.window.data2; - compute_texture_rect(s); - break; - default: - break; - } - break; - default: - break; - } - } - - if (quit && sdl->enable_quit_action) { - sdl2_write_trailer(s); - return AVERROR(EIO); - } - - av_image_fill_arrays(data, linesize, pkt->data, codecpar->format, codecpar->width, codecpar->height, 1); - switch (sdl->texture_fmt) { - /* case SDL_PIXELFORMAT_ARGB4444: - * case SDL_PIXELFORMAT_RGBA4444: - * case SDL_PIXELFORMAT_ABGR4444: - * case SDL_PIXELFORMAT_BGRA4444: - * case SDL_PIXELFORMAT_ARGB1555: - * case SDL_PIXELFORMAT_RGBA5551: - * case SDL_PIXELFORMAT_ABGR1555: - * case SDL_PIXELFORMAT_BGRA5551: - * case SDL_PIXELFORMAT_ARGB2101010: - */ - case SDL_PIXELFORMAT_IYUV: - case SDL_PIXELFORMAT_YUY2: - case SDL_PIXELFORMAT_UYVY: - ret = SDL_UpdateYUVTexture(sdl->texture, NULL, - data[0], linesize[0], - data[1], linesize[1], - data[2], linesize[2]); - break; - case SDL_PIXELFORMAT_RGB332: - case SDL_PIXELFORMAT_RGB444: - case SDL_PIXELFORMAT_RGB555: - case SDL_PIXELFORMAT_BGR555: - case SDL_PIXELFORMAT_RGB565: - case SDL_PIXELFORMAT_BGR565: - case SDL_PIXELFORMAT_RGB24: - case SDL_PIXELFORMAT_BGR24: - case SDL_PIXELFORMAT_RGB888: - case SDL_PIXELFORMAT_RGBX8888: - case SDL_PIXELFORMAT_BGR888: - case SDL_PIXELFORMAT_BGRX8888: - case SDL_PIXELFORMAT_ARGB8888: - case SDL_PIXELFORMAT_RGBA8888: - case SDL_PIXELFORMAT_ABGR8888: - case SDL_PIXELFORMAT_BGRA8888: - ret = SDL_UpdateTexture(sdl->texture, NULL, data[0], linesize[0]); - break; - default: - av_log(NULL, AV_LOG_FATAL, "Unsupported pixel format\n"); - ret = -1; - break; - } - SDL_RenderClear(sdl->renderer); - SDL_RenderCopy(sdl->renderer, sdl->texture, NULL, &sdl->texture_rect); - SDL_RenderPresent(sdl->renderer); - return ret; -} - -#define OFFSET(x) offsetof(SDLContext,x) - -static const AVOption options[] = { - { "window_title", "set SDL window title", OFFSET(window_title), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_size", "set SDL window forced size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_x", "set SDL window x position", OFFSET(window_x), AV_OPT_TYPE_INT, { .i64 = SDL_WINDOWPOS_CENTERED }, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_y", "set SDL window y position", OFFSET(window_y), AV_OPT_TYPE_INT, { .i64 = SDL_WINDOWPOS_CENTERED }, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_fullscreen", "set SDL window fullscreen", OFFSET(window_fullscreen), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_borderless", "set SDL window border off", OFFSET(window_borderless), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_enable_quit", "set if quit action is available", OFFSET(enable_quit_action), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, - { NULL }, -}; - -static const AVClass sdl2_class = { - .class_name = "sdl2 outdev", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, - .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT, -}; - -const FFOutputFormat ff_sdl2_muxer = { - .p.name = "sdl,sdl2", - .p.long_name = NULL_IF_CONFIG_SMALL("SDL2 output device"), - .priv_data_size = sizeof(SDLContext), - .p.audio_codec = AV_CODEC_ID_NONE, - .p.video_codec = AV_CODEC_ID_RAWVIDEO, - .write_header = sdl2_write_header, - .write_packet = sdl2_write_packet, - .write_trailer = sdl2_write_trailer, - .p.flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS, - .p.priv_class = &sdl2_class, -}; diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c index 0ae687233..c38ecbb37 100644 --- a/libavdevice/v4l2.c +++ b/libavdevice/v4l2.c @@ -111,7 +111,7 @@ struct video_data { int (*open_f)(const char *file, int oflag, ...); int (*close_f)(int fd); int (*dup_f)(int fd); -#if HAVE_POSIX_IOCTL +#if HAVE_IOCTL_POSIX int (*ioctl_f)(int fd, int request, ...); #else int (*ioctl_f)(int fd, unsigned long int request, ...); diff --git a/libavdevice/version.h b/libavdevice/version.h index 7608a8602..6db29e7d4 100644 --- a/libavdevice/version.h +++ b/libavdevice/version.h @@ -30,7 +30,7 @@ #include "version_major.h" #define LIBAVDEVICE_VERSION_MINOR 3 -#define LIBAVDEVICE_VERSION_MICRO 100 +#define LIBAVDEVICE_VERSION_MICRO 101 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ LIBAVDEVICE_VERSION_MINOR, \ diff --git a/libavdevice/version_major.h b/libavdevice/version_major.h index f16abb690..191511cdc 100644 --- a/libavdevice/version_major.h +++ b/libavdevice/version_major.h @@ -25,7 +25,7 @@ * Libavdevice version macros */ -#define LIBAVDEVICE_VERSION_MAJOR 61 +#define LIBAVDEVICE_VERSION_MAJOR 62 /** * FF_API_* defines may be placed below to indicate public API that will be @@ -33,11 +33,6 @@ * the public API and may change, break or disappear at any time. */ -// reminder to remove the bktr device on next major bump -#define FF_API_BKTR_DEVICE (LIBAVDEVICE_VERSION_MAJOR < 62) -// reminder to remove the opengl device on next major bump -#define FF_API_OPENGL_DEVICE (LIBAVDEVICE_VERSION_MAJOR < 62) -// reminder to remove the sdl2 device on next major bump -#define FF_API_SDL2_DEVICE (LIBAVDEVICE_VERSION_MAJOR < 62) +#define FF_API_ALSA_CHANNELS (LIBAVDEVICE_VERSION_MAJOR < 63) #endif /* AVDEVICE_VERSION_MAJOR_H */ diff --git a/libavdevice/xcbgrab.c b/libavdevice/xcbgrab.c index c736ec0cb..d0b2c6e0b 100644 --- a/libavdevice/xcbgrab.c +++ b/libavdevice/xcbgrab.c @@ -830,7 +830,7 @@ static av_cold int xcbgrab_read_header(AVFormatContext *s) *display_name = 0; if(sscanf(s->url, "+%d,%d", &c->x, &c->y) != 2) { if (*s->url) - av_log(s, AV_LOG_WARNING, "Ambigous URL: %s\n", s->url); + av_log(s, AV_LOG_WARNING, "Ambiguous URL: %s\n", s->url); } } diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 91487afb2..a530cfae2 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -24,6 +24,9 @@ OBJS = allfilters.o \ version.o \ video.o \ +include $(SRC_PATH)/libavfilter/dnn/Makefile +include $(SRC_PATH)/libavfilter/vulkan/Makefile + OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o OBJS-$(HAVE_THREADS) += pthread.o @@ -31,7 +34,6 @@ OBJS-$(HAVE_THREADS) += pthread.o OBJS-$(CONFIG_QSVVPP) += qsvvpp.o OBJS-$(CONFIG_SCENE_SAD) += scene_sad.o OBJS-$(CONFIG_DNN) += dnn_filter_common.o -include $(SRC_PATH)/libavfilter/dnn/Makefile # audio filters OBJS-$(CONFIG_AAP_FILTER) += af_aap.o @@ -186,6 +188,8 @@ OBJS-$(CONFIG_HILBERT_FILTER) += asrc_hilbert.o OBJS-$(CONFIG_SINC_FILTER) += asrc_sinc.o OBJS-$(CONFIG_SINE_FILTER) += asrc_sine.o +OBJS-$(CONFIG_WHISPER_FILTER) += af_whisper.o + OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o # video filters @@ -206,6 +210,7 @@ OBJS-$(CONFIG_BILATERAL_FILTER) += vf_bilateral.o OBJS-$(CONFIG_BILATERAL_CUDA_FILTER) += vf_bilateral_cuda.o vf_bilateral_cuda.ptx.o OBJS-$(CONFIG_BITPLANENOISE_FILTER) += vf_bitplanenoise.o OBJS-$(CONFIG_BLACKDETECT_FILTER) += vf_blackdetect.o +OBJS-$(CONFIG_BLACKDETECT_VULKAN_FILTER) += vf_blackdetect_vulkan.o OBJS-$(CONFIG_BLACKFRAME_FILTER) += vf_blackframe.o OBJS-$(CONFIG_BLEND_FILTER) += vf_blend.o framesync.o OBJS-$(CONFIG_BLEND_VULKAN_FILTER) += vf_blend_vulkan.o framesync.o vulkan.o vulkan_filter.o @@ -234,6 +239,7 @@ OBJS-$(CONFIG_COLORBALANCE_FILTER) += vf_colorbalance.o OBJS-$(CONFIG_COLORCHANNELMIXER_FILTER) += vf_colorchannelmixer.o OBJS-$(CONFIG_COLORCONTRAST_FILTER) += vf_colorcontrast.o OBJS-$(CONFIG_COLORCORRECT_FILTER) += vf_colorcorrect.o +OBJS-$(CONFIG_COLORDETECT_FILTER) += vf_colordetect.o OBJS-$(CONFIG_COLORIZE_FILTER) += vf_colorize.o OBJS-$(CONFIG_COLORKEY_FILTER) += vf_colorkey.o OBJS-$(CONFIG_COLORKEY_OPENCL_FILTER) += vf_colorkey_opencl.o opencl.o \ @@ -270,6 +276,7 @@ OBJS-$(CONFIG_DECONVOLVE_FILTER) += vf_convolve.o framesync.o OBJS-$(CONFIG_DEDOT_FILTER) += vf_dedot.o OBJS-$(CONFIG_DEFLATE_FILTER) += vf_neighbor.o OBJS-$(CONFIG_DEFLICKER_FILTER) += vf_deflicker.o +OBJS-$(CONFIG_DEINTERLACE_D3D12_FILTER) += vf_deinterlace_d3d12.o OBJS-$(CONFIG_DEINTERLACE_QSV_FILTER) += vf_vpp_qsv.o OBJS-$(CONFIG_DEINTERLACE_VAAPI_FILTER) += vf_deinterlace_vaapi.o vaapi_vpp.o OBJS-$(CONFIG_DEJUDDER_FILTER) += vf_dejudder.o @@ -292,6 +299,7 @@ OBJS-$(CONFIG_DRAWBOX_FILTER) += vf_drawbox.o OBJS-$(CONFIG_DRAWGRAPH_FILTER) += f_drawgraph.o OBJS-$(CONFIG_DRAWGRID_FILTER) += vf_drawbox.o OBJS-$(CONFIG_DRAWTEXT_FILTER) += vf_drawtext.o textutils.o +OBJS-$(CONFIG_DRAWVG_FILTER) += vf_drawvg.o textutils.o OBJS-$(CONFIG_EDGEDETECT_FILTER) += vf_edgedetect.o edge_common.o OBJS-$(CONFIG_ELBG_FILTER) += vf_elbg.o OBJS-$(CONFIG_ENTROPY_FILTER) += vf_entropy.o @@ -322,7 +330,7 @@ OBJS-$(CONFIG_FRAMESTEP_FILTER) += vf_framestep.o OBJS-$(CONFIG_FREEZEDETECT_FILTER) += vf_freezedetect.o OBJS-$(CONFIG_FREEZEFRAMES_FILTER) += vf_freezeframes.o OBJS-$(CONFIG_FREI0R_FILTER) += vf_frei0r.o -OBJS-$(CONFIG_FSPP_FILTER) += vf_fspp.o qp_table.o +OBJS-$(CONFIG_FSPP_FILTER) += vf_fspp.o vf_fsppdsp.o qp_table.o OBJS-$(CONFIG_FSYNC_FILTER) += vf_fsync.o OBJS-$(CONFIG_GBLUR_FILTER) += vf_gblur.o OBJS-$(CONFIG_GBLUR_VULKAN_FILTER) += vf_gblur_vulkan.o vulkan.o vulkan_filter.o @@ -352,10 +360,11 @@ OBJS-$(CONFIG_HYSTERESIS_FILTER) += vf_hysteresis.o framesync.o OBJS-$(CONFIG_ICCDETECT_FILTER) += vf_iccdetect.o fflcms2.o OBJS-$(CONFIG_ICCGEN_FILTER) += vf_iccgen.o fflcms2.o OBJS-$(CONFIG_IDENTITY_FILTER) += vf_identity.o framesync.o -OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o +OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o vf_idetdsp.o OBJS-$(CONFIG_IL_FILTER) += vf_il.o OBJS-$(CONFIG_INFLATE_FILTER) += vf_neighbor.o OBJS-$(CONFIG_INTERLACE_FILTER) += vf_tinterlace.o +OBJS-$(CONFIG_INTERLACE_VULKAN_FILTER) += vf_interlace_vulkan.o vulkan.o vulkan_filter.o OBJS-$(CONFIG_INTERLEAVE_FILTER) += f_interleave.o OBJS-$(CONFIG_KERNDEINT_FILTER) += vf_kerndeint.o OBJS-$(CONFIG_KIRSCH_FILTER) += vf_convolution.o @@ -387,6 +396,7 @@ OBJS-$(CONFIG_MCDEINT_FILTER) += vf_mcdeint.o OBJS-$(CONFIG_MEDIAN_FILTER) += vf_median.o OBJS-$(CONFIG_MERGEPLANES_FILTER) += vf_mergeplanes.o framesync.o OBJS-$(CONFIG_MESTIMATE_FILTER) += vf_mestimate.o motion_estimation.o +OBJS-$(CONFIG_MESTIMATE_D3D12_FILTER) += vf_mestimate_d3d12.o OBJS-$(CONFIG_METADATA_FILTER) += f_metadata.o OBJS-$(CONFIG_MIDEQUALIZER_FILTER) += vf_midequalizer.o framesync.o OBJS-$(CONFIG_MINTERPOLATE_FILTER) += vf_minterpolate.o motion_estimation.o @@ -394,6 +404,7 @@ OBJS-$(CONFIG_MIX_FILTER) += vf_mix.o framesync.o OBJS-$(CONFIG_MONOCHROME_FILTER) += vf_monochrome.o OBJS-$(CONFIG_MORPHO_FILTER) += vf_morpho.o framesync.o OBJS-$(CONFIG_MPDECIMATE_FILTER) += vf_mpdecimate.o +OBJS-$(CONFIG_MSAD_FILTER) += vf_identity.o framesync.o OBJS-$(CONFIG_MULTIPLY_FILTER) += vf_multiply.o framesync.o OBJS-$(CONFIG_NEGATE_FILTER) += vf_negate.o OBJS-$(CONFIG_NLMEANS_FILTER) += vf_nlmeans.o @@ -406,6 +417,7 @@ OBJS-$(CONFIG_NORMALIZE_FILTER) += vf_normalize.o OBJS-$(CONFIG_NULL_FILTER) += vf_null.o OBJS-$(CONFIG_OCR_FILTER) += vf_ocr.o OBJS-$(CONFIG_OCV_FILTER) += vf_libopencv.o +OBJS-$(CONFIG_OCIO_FILTER) += vf_opencolorio.o ocio_wrapper.o OBJS-$(CONFIG_OSCILLOSCOPE_FILTER) += vf_datascope.o OBJS-$(CONFIG_OVERLAY_FILTER) += vf_overlay.o framesync.o OBJS-$(CONFIG_OVERLAY_CUDA_FILTER) += vf_overlay_cuda.o framesync.o vf_overlay_cuda.ptx.o \ @@ -417,6 +429,7 @@ OBJS-$(CONFIG_OVERLAY_VAAPI_FILTER) += vf_overlay_vaapi.o framesync.o v OBJS-$(CONFIG_OVERLAY_VULKAN_FILTER) += vf_overlay_vulkan.o vulkan.o vulkan_filter.o OBJS-$(CONFIG_OWDENOISE_FILTER) += vf_owdenoise.o OBJS-$(CONFIG_PAD_FILTER) += vf_pad.o +OBJS-$(CONFIG_PAD_CUDA_FILTER) += vf_pad_cuda.o vf_pad_cuda.ptx.o cuda/load_helper.o OBJS-$(CONFIG_PAD_OPENCL_FILTER) += vf_pad_opencl.o opencl.o opencl/pad.o OBJS-$(CONFIG_PALETTEGEN_FILTER) += vf_palettegen.o palette.o OBJS-$(CONFIG_PALETTEUSE_FILTER) += vf_paletteuse.o framesync.o palette.o @@ -427,8 +440,8 @@ OBJS-$(CONFIG_PHOTOSENSITIVITY_FILTER) += vf_photosensitivity.o OBJS-$(CONFIG_PIXDESCTEST_FILTER) += vf_pixdesctest.o OBJS-$(CONFIG_PIXELIZE_FILTER) += vf_pixelize.o OBJS-$(CONFIG_PIXSCOPE_FILTER) += vf_datascope.o -OBJS-$(CONFIG_PP_FILTER) += vf_pp.o qp_table.o OBJS-$(CONFIG_PP7_FILTER) += vf_pp7.o qp_table.o +OBJS-$(CONFIG_PREMULTIPLY_DYNAMIC_FILTER) += vf_premultiply.o framesync.o OBJS-$(CONFIG_PREMULTIPLY_FILTER) += vf_premultiply.o framesync.o OBJS-$(CONFIG_PREWITT_FILTER) += vf_convolution.o OBJS-$(CONFIG_PREWITT_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o \ @@ -436,7 +449,7 @@ OBJS-$(CONFIG_PREWITT_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o OBJS-$(CONFIG_PROCAMP_VAAPI_FILTER) += vf_procamp_vaapi.o vaapi_vpp.o OBJS-$(CONFIG_PROGRAM_OPENCL_FILTER) += vf_program_opencl.o opencl.o framesync.o OBJS-$(CONFIG_PSEUDOCOLOR_FILTER) += vf_pseudocolor.o -OBJS-$(CONFIG_PSNR_FILTER) += vf_psnr.o framesync.o +OBJS-$(CONFIG_PSNR_FILTER) += vf_psnr.o framesync.o psnr.o OBJS-$(CONFIG_PULLUP_FILTER) += vf_pullup.o OBJS-$(CONFIG_QP_FILTER) += vf_qp.o OBJS-$(CONFIG_QUIRC_FILTER) += vf_quirc.o @@ -458,6 +471,8 @@ OBJS-$(CONFIG_ROBERTS_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o OBJS-$(CONFIG_ROTATE_FILTER) += vf_rotate.o OBJS-$(CONFIG_SAB_FILTER) += vf_sab.o OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o scale_eval.o framesync.o +OBJS-$(CONFIG_SCALE_D3D11_FILTER) += vf_scale_d3d11.o scale_eval.o +OBJS-$(CONFIG_SCALE_D3D12_FILTER) += vf_scale_d3d12.o scale_eval.o OBJS-$(CONFIG_SCALE_CUDA_FILTER) += vf_scale_cuda.o scale_eval.o \ vf_scale_cuda.ptx.o cuda/load_helper.o OBJS-$(CONFIG_SCALE_NPP_FILTER) += vf_scale_npp.o scale_eval.o @@ -468,6 +483,7 @@ OBJS-$(CONFIG_SCALE_VULKAN_FILTER) += vf_scale_vulkan.o vulkan.o vulka OBJS-$(CONFIG_SCALE2REF_FILTER) += vf_scale.o scale_eval.o framesync.o OBJS-$(CONFIG_SCALE2REF_NPP_FILTER) += vf_scale_npp.o scale_eval.o OBJS-$(CONFIG_SCDET_FILTER) += vf_scdet.o +OBJS-$(CONFIG_SCDET_VULKAN_FILTER) += vf_scdet_vulkan.o OBJS-$(CONFIG_SCHARR_FILTER) += vf_convolution.o OBJS-$(CONFIG_SCROLL_FILTER) += vf_scroll.o OBJS-$(CONFIG_SEGMENT_FILTER) += f_segment.o @@ -501,6 +517,7 @@ OBJS-$(CONFIG_SITI_FILTER) += vf_siti.o OBJS-$(CONFIG_SPLIT_FILTER) += split.o OBJS-$(CONFIG_SPP_FILTER) += vf_spp.o qp_table.o OBJS-$(CONFIG_SR_FILTER) += vf_sr.o +OBJS-$(CONFIG_SR_AMF_FILTER) += vf_sr_amf.o scale_eval.o vf_amf_common.o OBJS-$(CONFIG_SSIM_FILTER) += vf_ssim.o framesync.o OBJS-$(CONFIG_SSIM360_FILTER) += vf_ssim360.o framesync.o OBJS-$(CONFIG_STEREO3D_FILTER) += vf_stereo3d.o @@ -554,6 +571,7 @@ OBJS-$(CONFIG_VIDSTABTRANSFORM_FILTER) += vidstabutils.o vf_vidstabtransfo OBJS-$(CONFIG_VIF_FILTER) += vf_vif.o framesync.o OBJS-$(CONFIG_VIGNETTE_FILTER) += vf_vignette.o OBJS-$(CONFIG_VMAFMOTION_FILTER) += vf_vmafmotion.o framesync.o +OBJS-$(CONFIG_VPP_AMF_FILTER) += vf_vpp_amf.o scale_eval.o vf_amf_common.o OBJS-$(CONFIG_VPP_QSV_FILTER) += vf_vpp_qsv.o OBJS-$(CONFIG_VSTACK_FILTER) += vf_stack.o framesync.o OBJS-$(CONFIG_W3FDIF_FILTER) += vf_w3fdif.o @@ -565,7 +583,7 @@ OBJS-$(CONFIG_XFADE_FILTER) += vf_xfade.o OBJS-$(CONFIG_XFADE_OPENCL_FILTER) += vf_xfade_opencl.o opencl.o opencl/xfade.o OBJS-$(CONFIG_XFADE_VULKAN_FILTER) += vf_xfade_vulkan.o vulkan.o vulkan_filter.o OBJS-$(CONFIG_XMEDIAN_FILTER) += vf_xmedian.o framesync.o -OBJS-$(CONFIG_XPSNR_FILTER) += vf_xpsnr.o framesync.o +OBJS-$(CONFIG_XPSNR_FILTER) += vf_xpsnr.o framesync.o psnr.o OBJS-$(CONFIG_XSTACK_FILTER) += vf_stack.o framesync.o OBJS-$(CONFIG_YADIF_FILTER) += vf_yadif.o yadif_common.o OBJS-$(CONFIG_YADIF_CUDA_FILTER) += vf_yadif_cuda.o vf_yadif_cuda.ptx.o \ @@ -596,6 +614,7 @@ OBJS-$(CONFIG_COLORSPECTRUM_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_COREIMAGESRC_FILTER) += vf_coreimage.o OBJS-$(CONFIG_DDAGRAB_FILTER) += vsrc_ddagrab.o OBJS-$(CONFIG_FREI0R_SRC_FILTER) += vf_frei0r.o +OBJS-$(CONFIG_GFXCAPTURE_FILTER) += vsrc_gfxcapture.o vsrc_gfxcapture_winrt.o OBJS-$(CONFIG_GRADIENTS_FILTER) += vsrc_gradients.o OBJS-$(CONFIG_HALDCLUTSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_LIFE_FILTER) += vsrc_life.o @@ -615,6 +634,7 @@ OBJS-$(CONFIG_SMPTEHDBARS_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_COLOR_VULKAN_FILTER) += vsrc_testsrc_vulkan.o vulkan.o vulkan_filter.o OBJS-$(CONFIG_TESTSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_TESTSRC2_FILTER) += vsrc_testsrc.o +OBJS-$(CONFIG_AMF_CAPTURE_FILTER) += vsrc_amf.o OBJS-$(CONFIG_YUVTESTSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_ZONEPLATE_FILTER) += vsrc_testsrc.o @@ -658,31 +678,26 @@ SHLIBOBJS-$(HAVE_GNU_WINDRES) += avfilterres.o SKIPHEADERS-$(CONFIG_LCMS2) += fflcms2.h SKIPHEADERS-$(CONFIG_LIBVIDSTAB) += vidstabutils.h +SKIPHEADERS-$(CONFIG_AMF) += vf_amf_common.h SKIPHEADERS-$(CONFIG_QSVVPP) += qsvvpp.h stack_internal.h SKIPHEADERS-$(CONFIG_OPENCL) += opencl.h SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_vpp.h stack_internal.h -SKIPHEADERS-$(CONFIG_VULKAN) += vulkan.h vulkan_filter.h -SKIPHEADERS-$(CONFIG_LIBSHADERC) += vulkan_spirv.h -SKIPHEADERS-$(CONFIG_LIBGLSLANG) += vulkan_spirv.h +SKIPHEADERS-$(CONFIG_VULKAN) += vulkan_filter.h +SKIPHEADERS-$(CONFIG_SCALE_CUDA_FILTER) += vf_scale_cuda.h TOOLS = graph2dot TESTPROGS = drawutils filtfmts formats integral +TESTPROGS-$(CONFIG_DRAWVG_FILTER) += drawvg + TOOLS-$(CONFIG_LIBZMQ) += zmqsend clean:: $(RM) $(CLEANSUFFIXES:%=libavfilter/dnn/%) $(CLEANSUFFIXES:%=libavfilter/opencl/%) \ - $(CLEANSUFFIXES:%=libavfilter/metal/%) \ - $(CLEANSUFFIXES:%=libavfilter/vulkan/%) + $(CLEANSUFFIXES:%=libavfilter/metal/%) OPENCL = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavfilter/opencl/*.cl)) .SECONDARY: $(OPENCL:.cl=.c) libavfilter/opencl/%.c: TAG = OPENCL libavfilter/opencl/%.c: $(SRC_PATH)/libavfilter/opencl/%.cl $(M)$(SRC_PATH)/tools/source2c $< $@ - -VULKAN = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavfilter/vulkan/*.comp)) -.SECONDARY: $(VULKAN:.comp=.c) -libavfilter/vulkan/%.c: TAG = OPENCL -libavfilter/vulkan/%.c: $(SRC_PATH)/libavfilter/vulkan/%.comp - $(M)$(SRC_PATH)/tools/source2c $< $@ diff --git a/libavfilter/aarch64/Makefile b/libavfilter/aarch64/Makefile index b68209bc9..c7b7e1846 100644 --- a/libavfilter/aarch64/Makefile +++ b/libavfilter/aarch64/Makefile @@ -1,5 +1,7 @@ OBJS-$(CONFIG_BWDIF_FILTER) += aarch64/vf_bwdif_init_aarch64.o +OBJS-$(CONFIG_COLORDETECT_FILTER) += aarch64/vf_colordetect_init.o OBJS-$(CONFIG_NLMEANS_FILTER) += aarch64/vf_nlmeans_init.o NEON-OBJS-$(CONFIG_BWDIF_FILTER) += aarch64/vf_bwdif_neon.o +NEON-OBJS-$(CONFIG_COLORDETECT_FILTER) += aarch64/vf_colordetect_neon.o NEON-OBJS-$(CONFIG_NLMEANS_FILTER) += aarch64/vf_nlmeans_neon.o diff --git a/libavfilter/aarch64/vf_bwdif_neon.S b/libavfilter/aarch64/vf_bwdif_neon.S index bf268b12f..d078f6f6f 100644 --- a/libavfilter/aarch64/vf_bwdif_neon.S +++ b/libavfilter/aarch64/vf_bwdif_neon.S @@ -148,7 +148,7 @@ // static const uint16_t coef_hf[3] = { 5570, 3801, 1016 }; // static const uint16_t coef_sp[2] = { 5077, 981 }; -const coeffs, align=4 // align 4 means align on 2^4 boundry +const coeffs, align=4 // align 4 means align on 2^4 boundary .hword 4309 * 4, 213 * 4 // lf[0]*4 = v0.h[0] .hword 5570, 3801, 1016, -3801 // hf[0] = v0.h[2], -hf[1] = v0.h[5] .hword 5077, 981 // sp[0] = v0.h[6] diff --git a/libavfilter/aarch64/vf_colordetect_init.c b/libavfilter/aarch64/vf_colordetect_init.c new file mode 100644 index 000000000..2fd23513e --- /dev/null +++ b/libavfilter/aarch64/vf_colordetect_init.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 Zhao Zhili + * + * 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/aarch64/cpu.h" +#include "libavfilter/vf_colordetectdsp.h" + +int ff_detect_alpha_full_neon(const uint8_t *color, ptrdiff_t color_stride, + const uint8_t *alpha, ptrdiff_t alpha_stride, + ptrdiff_t width, ptrdiff_t height, + int alpha_max, int mpeg_range, int offset); + +int ff_detect_alpha16_full_neon(const uint8_t *color, ptrdiff_t color_stride, + const uint8_t *alpha, ptrdiff_t alpha_stride, + ptrdiff_t width, ptrdiff_t height, + int alpha_max, int mpeg_range, int offset); + +int ff_detect_alpha_limited_neon(const uint8_t *color, ptrdiff_t color_stride, + const uint8_t *alpha, ptrdiff_t alpha_stride, + ptrdiff_t width, ptrdiff_t height, + int alpha_max, int mpeg_range, int offset); + +int ff_detect_alpha16_limited_neon(const uint8_t *color, ptrdiff_t color_stride, + const uint8_t *alpha, ptrdiff_t alpha_stride, + ptrdiff_t width, ptrdiff_t height, + int alpha_max, int mpeg_range, int offset); + +int ff_detect_range_neon(const uint8_t *data, ptrdiff_t stride, + ptrdiff_t width, ptrdiff_t height, + int mpeg_min, int mpeg_max); + +int ff_detect_range16_neon(const uint8_t *data, ptrdiff_t stride, + ptrdiff_t width, ptrdiff_t height, + int mpeg_min, int mpeg_max); + +av_cold void ff_color_detect_dsp_init_aarch64(FFColorDetectDSPContext *dsp, int depth, + enum AVColorRange color_range) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + dsp->detect_range = depth > 8 ? ff_detect_range16_neon : ff_detect_range_neon; + if (color_range == AVCOL_RANGE_JPEG) + dsp->detect_alpha = depth > 8 ? ff_detect_alpha16_full_neon : ff_detect_alpha_full_neon; + else + dsp->detect_alpha = depth > 8 ? ff_detect_alpha16_limited_neon : ff_detect_alpha_limited_neon; + } +} diff --git a/libavfilter/aarch64/vf_colordetect_neon.S b/libavfilter/aarch64/vf_colordetect_neon.S new file mode 100644 index 000000000..f3cca16fe --- /dev/null +++ b/libavfilter/aarch64/vf_colordetect_neon.S @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2025 Zhao Zhili + * + * 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/aarch64/asm.S" + +#define FF_ALPHA_TRANSPARENT (1 << 0) +#define FF_ALPHA_STRAIGHT ((1 << 1) | FF_ALPHA_TRANSPARENT) + +const mask + .byte 255, 255, 255, 255, 255, 255, 255, 255 + .byte 255, 255, 255, 255, 255, 255, 255, 255 +mask_start: + .byte 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0 + .byte 255, 255, 255, 255, 255, 255, 255, 255 + .byte 255, 255, 255, 255, 255, 255, 255, 255 +endconst + +.macro load_mask_zero, shift=0 + movrel x9, mask_start + sub x9, x9, x7, lsl #(\shift) + ldr q3, [x9] +.endm + +.macro load_mask, shift=0 + movrel x9, mask_start + sub x9, x9, x7, lsl #(\shift) + ld1 {v3.16b, v4.16b}, [x9] +.endm + +/* x0: const uint8_t *data + * x1: ptrdiff_t stride + * x2: ptrdiff_t width + * x3: ptrdiff_t height + * w4: int mpeg_min + * w5: int mpeg_max + */ +function ff_detect_range_neon, export=1 + ands x7, x2, #15 // width % 16 + bic x8, x2, #15 // width / 16 * 16 + bic x6, x2, #31 // width / 32 * 32 + and x10, x2, #16 // check x8 != x6 + dup v0.16b, w4 // mpeg_min + dup v1.16b, w5 // mpeg_max + movi v2.16b, #0 // cond + sub x1, x1, x8 + b.eq 1f + load_mask_zero +1: + cbz x6, 20f // width < 32 + mov x12, x6 +2: + ld1 {v5.16b, v6.16b}, [x0], #32 + cmhi v16.16b, v0.16b, v5.16b + cmhi v17.16b, v5.16b, v1.16b + cmhi v18.16b, v0.16b, v6.16b + cmhi v19.16b, v6.16b, v1.16b + orr v20.16b, v16.16b, v17.16b + orr v21.16b, v18.16b, v19.16b + subs x12, x12, #32 + orr v20.16b, v20.16b, v21.16b + orr v2.16b, v2.16b, v20.16b + b.gt 2b +20: + cbz x10, 3f // width < 16 + ldr q20, [x0], #16 + cmhi v16.16b, v0.16b, v20.16b + cmhi v17.16b, v20.16b, v1.16b + orr v16.16b, v16.16b, v17.16b + orr v2.16b, v2.16b, v16.16b +3: + cbz x7, 4f + ldr q21, [x0] + cmhi v18.16b, v0.16b, v21.16b + cmhi v19.16b, v21.16b, v1.16b + orr v16.16b, v18.16b, v19.16b + and v16.16b, v16.16b, v3.16b + orr v2.16b, v2.16b, v16.16b +4: + umaxv b4, v2.16b + subs x3, x3, #1 + umov w9, v4.b[0] + add x0, x0, x1 + cbnz w9, 8f + b.gt 1b + mov x0, #0 + ret +8: + mov x0, #1 + ret +endfunc + +/* x0: const uint8_t *data + * x1: ptrdiff_t stride + * x2: ptrdiff_t width + * x3: ptrdiff_t height + * w4: int mpeg_min + * w5: int mpeg_max + */ +function ff_detect_range16_neon, export=1 + ands x7, x2, #7 // width % 7 + bic x8, x2, #7 // width / 8 * 8 + bic x6, x2, #15 // width / 16 * 16 + and x10, x2, #8 // check x8 != x6 + dup v0.8h, w4 // mpeg_min + dup v1.8h, w5 // mpeg_max + movi v2.16b, #0 // cond + sub x1, x1, x8, lsl #1 + b.eq 1f + load_mask_zero shift=1 +1: + cbz x6, 20f // width < 16 + mov x12, x6 +2: + ld1 {v5.8h, v6.8h}, [x0], #32 + cmhi v16.8h, v0.8h, v5.8h + cmhi v17.8h, v5.8h, v1.8h + cmhi v18.8h, v0.8h, v6.8h + cmhi v19.8h, v6.8h, v1.8h + orr v20.16b, v16.16b, v17.16b + orr v21.16b, v18.16b, v19.16b + subs x12, x12, #16 + orr v20.16b, v20.16b, v21.16b + orr v2.16b, v2.16b, v20.16b + b.gt 2b +20: + cbz x10, 3f // width < 8 + ldr q20, [x0], #16 + cmhi v16.8h, v0.8h, v20.8h + cmhi v17.8h, v20.8h, v1.8h + orr v16.16b, v16.16b, v17.16b + orr v2.16b, v2.16b, v16.16b +3: + cbz x7, 4f + ldr q21, [x0] + cmhi v18.8h, v0.8h, v21.8h + cmhi v19.8h, v21.8h, v1.8h + orr v16.16b, v18.16b, v19.16b + and v16.16b, v16.16b, v3.16b + orr v2.16b, v2.16b, v16.16b +4: + umaxv h4, v2.8h + subs x3, x3, #1 + umov w9, v4.h[0] + add x0, x0, x1 + cbnz w9, 8f + b.gt 1b + mov x0, #0 + ret +8: + mov x0, #1 + ret +endfunc + +/* + * x0: const uint8_t *color, + * x1: ptrdiff_t color_stride, + * x2: const uint8_t *alpha, + * x3: ptrdiff_t alpha_stride, + * x4: ptrdiff_t width, + * x5: ptrdiff_t height, + * w6: int alpha_max, + */ +function ff_detect_alpha_full_neon, export=1 + ands x7, x4, #15 // width % 16 + bic x8, x4, #15 // width / 16 * 16 + movi v0.16b, #0 + movi v1.16b, #255 + dup v2.16b, w6 // alpha_max + sub x1, x1, x8 // color_stride - aligned_width + sub x3, x3, x8 // alpha_stride - aligned_width + b.eq 1f + + // Create mask for non-aligned width + load_mask +1: + cbz x8, 20f // width < 16 + mov x12, x8 // w12: aligned_width +2: + ldr q5, [x0], #16 + ldr q6, [x2], #16 + subs x12, x12, #16 + cmhi v7.16b, v5.16b, v6.16b + cmeq v16.16b, v6.16b, v2.16b + orr v0.16b, v0.16b, v7.16b + and v1.16b, v1.16b, v16.16b + b.gt 2b +20: + cbz w7, 3f + // handle loop tail + ldr q5, [x0] + ldr q6, [x2] + cmhi v7.16b, v5.16b, v6.16b + cmeq v16.16b, v6.16b, v2.16b + and v7.16b, v7.16b, v3.16b + orr v16.16b, v16.16b, v4.16b + orr v0.16b, v0.16b, v7.16b + and v1.16b, v1.16b, v16.16b +3: + umaxv b17, v0.16b + subs x5, x5, #1 + umov w9, v17.b[0] + add x0, x0, x1 + add x2, x2, x3 + cbnz w9, 4f + b.gt 1b + + uminv b1, v1.16b + umov w9, v1.b[0] + mov x0, #0 + cbnz w9, 5f + mov x0, #FF_ALPHA_TRANSPARENT + ret +4: + mov x0, #FF_ALPHA_STRAIGHT +5: + ret +endfunc + +/* + * x0: const uint8_t *color, + * x1: ptrdiff_t color_stride, + * x2: const uint8_t *alpha, + * x3: ptrdiff_t alpha_stride, + * x4: ptrdiff_t width, + * x5: ptrdiff_t height, + * w6: int alpha_max, + */ +function ff_detect_alpha16_full_neon, export=1 + ands x7, x4, #7 // width % 8 + bic x8, x4, #7 // width / 8 * 8 + movi v0.8h, #0 + movi v1.16b, #255 + dup v2.8h, w6 // alpha_max + sub x1, x1, x8, lsl #1 // color_stride - (aligned_width * 2) + sub x3, x3, x8, lsl #1 // alpha_stride - (aligned_width * 2) + b.eq 1f + + // Create mask for non-aligned width + load_mask shift=1 +1: + cbz x8, 20f // width < 8 + mov x12, x8 // w12: aligned_width +2: + ldr q5, [x0], #16 + ldr q6, [x2], #16 + subs x12, x12, #8 + cmhi v7.8h, v5.8h, v6.8h + cmeq v16.8h, v6.8h, v2.8h + orr v0.16b, v0.16b, v7.16b + and v1.16b, v1.16b, v16.16b + b.gt 2b +20: + cbz w7, 3f + // handle loop tail + ldr q5, [x0] + ldr q6, [x2] + cmhi v7.8h, v5.8h, v6.8h + cmeq v16.8h, v6.8h, v2.8h + and v7.16b, v7.16b, v3.16b + orr v16.16b, v16.16b, v4.16b + orr v0.16b, v0.16b, v7.16b + and v1.16b, v1.16b, v16.16b +3: + umaxv h17, v0.8h + subs x5, x5, #1 + umov w9, v17.h[0] + add x0, x0, x1 + add x2, x2, x3 + cbnz w9, 4f + b.gt 1b + + uminv h1, v1.8h + umov w9, v1.h[0] + mov x0, #0 + cbnz w9, 5f + mov x0, #FF_ALPHA_TRANSPARENT + ret +4: + mov x0, #FF_ALPHA_STRAIGHT +5: + ret +endfunc + +/* + * x0: const uint8_t *color, + * x1: ptrdiff_t color_stride, + * x2: const uint8_t *alpha, + * x3: ptrdiff_t alpha_stride, + * x4: ptrdiff_t width, + * x5: ptrdiff_t height, + * w6: int alpha_max, + * w7: int mpeg_range + * [sp]: int offset + */ +function ff_detect_alpha_limited_neon, export=1 + dup v17.16b, w7 // mpeg_range + ldr w13, [sp] + movi v0.16b, #0 + movi v1.16b, #255 + dup v2.16b, w6 // alpha_max + ands x7, x4, #15 // width % 16 + bic x8, x4, #15 // width / 16 * 16 + dup v18.8h, w13 // offset + sub x1, x1, x8 // color_stride - aligned_width + sub x3, x3, x8 // alpha_stride - aligned_width + b.eq 1f + + // Create mask for non-aligned width + load_mask +1: + cbz x8, 20f // width < 16 + mov x12, x8 // w12: aligned_width +2: + ldr q5, [x0], #16 // color + ldr q6, [x2], #16 // alpha + umull v19.8h, v2.8b, v5.8b // alpha_max * color + umull2 v20.8h, v2.16b, v5.16b // alpha_max * color + umull v21.8h, v17.8b, v6.8b // range * alpha + umull2 v22.8h, v17.16b, v6.16b // range * alpha + cmeq v16.16b, v6.16b, v2.16b + subs x12, x12, #16 + uqsub v19.8h, v19.8h, v18.8h // alpha_max * color - offset + uqsub v20.8h, v20.8h, v18.8h // alpha_max * color - offset + + cmhi v19.8h, v19.8h, v21.8h + cmhi v20.8h, v20.8h, v22.8h + orr v7.16b, v19.16b, v20.16b + orr v0.16b, v0.16b, v7.16b + and v1.16b, v1.16b, v16.16b + b.gt 2b +20: + cbz w7, 3f + // handle loop tail + ldr q5, [x0] + ldr q6, [x2] + umull v19.8h, v2.8b, v5.8b // alpha_max * color + umull2 v20.8h, v2.16b, v5.16b // alpha_max * color + umull v21.8h, v17.8b, v6.8b // range * alpha + umull2 v22.8h, v17.16b, v6.16b // range * alpha + uqsub v19.8h, v19.8h, v18.8h // alpha_max * color - offset + uqsub v20.8h, v20.8h, v18.8h // alpha_max * color - offset + + cmhi v19.8h, v19.8h, v21.8h + cmhi v20.8h, v20.8h, v22.8h + uqxtn v7.8b, v19.8h + uqxtn2 v7.16b, v20.8h + cmeq v16.16b, v6.16b, v2.16b + + and v7.16b, v7.16b, v3.16b + orr v16.16b, v16.16b, v4.16b + orr v0.16b, v0.16b, v7.16b + and v1.16b, v1.16b, v16.16b +3: + umaxv b23, v0.16b + subs x5, x5, #1 + umov w9, v23.b[0] + add x0, x0, x1 + add x2, x2, x3 + cbnz w9, 4f + b.gt 1b + + uminv b1, v1.16b + umov w9, v1.b[0] + mov x0, #0 + cbnz w9, 5f + mov x0, #FF_ALPHA_TRANSPARENT + ret +4: + mov x0, #FF_ALPHA_STRAIGHT +5: + ret +endfunc + +/* + * x0: const uint8_t *color, + * x1: ptrdiff_t color_stride, + * x2: const uint8_t *alpha, + * x3: ptrdiff_t alpha_stride, + * x4: ptrdiff_t width, + * x5: ptrdiff_t height, + * w6: int alpha_max, + * w7: int mpeg_range + * [sp]: int offset + */ +function ff_detect_alpha16_limited_neon, export=1 + dup v17.8h, w7 // mpeg_range + ldr w13, [sp] + movi v0.8h, #0 + movi v1.16b, #255 + dup v2.8h, w6 // alpha_max + ands x7, x4, #7 // width % 8 + bic x8, x4, #7 // width / 8 * 8 + dup v18.4s, w13 // offset + sub x1, x1, x8, lsl #1 // color_stride - (aligned_width * 2) + sub x3, x3, x8, lsl #1 // alpha_stride - (aligned_width * 2) + b.eq 1f + + // Create mask for non-aligned width + load_mask shift=1 +1: + cbz x8, 20f // width < 8 + mov x12, x8 // w12: aligned_width +2: + ldr q5, [x0], #16 + ldr q6, [x2], #16 + umull v19.4s, v2.4h, v5.4h // alpha_max * color + umull2 v20.4s, v2.8h, v5.8h // alpha_max * color + umull v21.4s, v17.4h, v6.4h // range * alpha + umull2 v22.4s, v17.8h, v6.8h // range * alpha + cmeq v16.8h, v6.8h, v2.8h + subs x12, x12, #8 + uqsub v19.4s, v19.4s, v18.4s // alpha_max * color - offset + uqsub v20.4s, v20.4s, v18.4s // alpha_max * color - offset + + cmhi v19.4s, v19.4s, v21.4s + cmhi v20.4s, v20.4s, v22.4s + orr v7.16b, v19.16b, v20.16b + orr v0.16b, v0.16b, v7.16b + and v1.16b, v1.16b, v16.16b + b.gt 2b +20: + cbz w7, 3f + // handle loop tail + ldr q5, [x0] + ldr q6, [x2] + umull v19.4s, v2.4h, v5.4h // alpha_max * color + umull2 v20.4s, v2.8h, v5.8h // alpha_max * color + umull v21.4s, v17.4h, v6.4h // range * alpha + umull2 v22.4s, v17.8h, v6.8h // range * alpha + uqsub v19.4s, v19.4s, v18.4s // alpha_max * color - offset + uqsub v20.4s, v20.4s, v18.4s // alpha_max * color - offset + + cmhi v19.4s, v19.4s, v21.4s + cmhi v20.4s, v20.4s, v22.4s + uqxtn v7.4h, v19.4s + uqxtn2 v7.8h, v20.4s + cmeq v16.8h, v6.8h, v2.8h + + and v7.16b, v7.16b, v3.16b + orr v16.16b, v16.16b, v4.16b + orr v0.16b, v0.16b, v7.16b + and v1.16b, v1.16b, v16.16b +3: + umaxv s23, v0.4s + subs x5, x5, #1 + umov w9, v23.s[0] + add x0, x0, x1 + add x2, x2, x3 + cbnz w9, 4f + b.gt 1b + + uminv h1, v1.8h + umov w9, v1.h[0] + mov x0, #0 + cbnz w9, 5f + mov x0, #FF_ALPHA_TRANSPARENT + ret +4: + mov x0, #FF_ALPHA_STRAIGHT +5: + ret +endfunc diff --git a/libavfilter/aarch64/vf_nlmeans_init.c b/libavfilter/aarch64/vf_nlmeans_init.c index 6793370a4..fbee33632 100644 --- a/libavfilter/aarch64/vf_nlmeans_init.c +++ b/libavfilter/aarch64/vf_nlmeans_init.c @@ -25,10 +25,23 @@ void ff_compute_safe_ssd_integral_image_neon(uint32_t *dst, ptrdiff_t dst_linesi const uint8_t *s2, ptrdiff_t linesize2, int w, int h); +void ff_compute_weights_line_neon(const uint32_t *const iia, + const uint32_t *const iib, + const uint32_t *const iid, + const uint32_t *const iie, + const uint8_t *const src, + float *total_weight, + float *sum, + const float *const weight_lut, + ptrdiff_t max_meaningful_diff, + ptrdiff_t startx, ptrdiff_t endx); + av_cold void ff_nlmeans_init_aarch64(NLMeansDSPContext *dsp) { int cpu_flags = av_get_cpu_flags(); - if (have_neon(cpu_flags)) + if (have_neon(cpu_flags)) { dsp->compute_safe_ssd_integral_image = ff_compute_safe_ssd_integral_image_neon; + dsp->compute_weights_line = ff_compute_weights_line_neon; + } } diff --git a/libavfilter/aarch64/vf_nlmeans_neon.S b/libavfilter/aarch64/vf_nlmeans_neon.S index a788cffd8..fd8eca8f7 100644 --- a/libavfilter/aarch64/vf_nlmeans_neon.S +++ b/libavfilter/aarch64/vf_nlmeans_neon.S @@ -78,3 +78,129 @@ function ff_compute_safe_ssd_integral_image_neon, export=1 b.ne 1b ret endfunc + +function ff_compute_weights_line_neon, export=1 + // x0 = iia, x1 = iib, x2 = iid, x3 = iie + // x4 = src, x5 = total_weight, x6 = sum, x7 = weight_lut + // stack: [sp+0] = max_meaningful_diff, [sp+8] = startx, [sp+16] = endx + + ldr w13, [sp, #0] // max_meaningful_diff + ldr w9, [sp, #8] // startx + ldr w10, [sp, #16] // endx + + cmp w9, w10 + b.ge 9f // if startx >= endx return + + // Offset pointers + lsl x11, x9, #2 // startx * 4 (for uint32/float) + add x0, x0, x11 // iia += startx + add x1, x1, x11 // iib += startx + add x2, x2, x11 // iid += startx + add x3, x3, x11 // iie += startx + add x5, x5, x11 // total_weight += startx + add x6, x6, x11 // sum += startx + + // src is uint8, so offset is just startx + add x4, x4, x9 // src += startx + + dup v7.4s, w13 // v7 = max_meaningful_diff (for vector ops) + + sub w10, w10, w9 // count = endx - startx + +1: // Main loop + cmp w10, #4 + b.lt 2f // Handle leftovers + + // Load integral image values + ld1 {v0.4s}, [x0], #16 // iia + ld1 {v1.4s}, [x1], #16 // iib + ld1 {v2.4s}, [x2], #16 // iid + ld1 {v3.4s}, [x3], #16 // iie + + // diff = a - b + e - d = e - d - b + a + sub v0.4s, v0.4s, v1.4s // v0 = a - b + sub v3.4s, v3.4s, v2.4s // v3 = e - d + add v3.4s, v3.4s, v0.4s // v3 = diff (a - b + e - d) + + // min(diff, max) + umin v3.4s, v3.4s, v7.4s + + // Schedule independent loads early + ld1 {v0.4s}, [x5] // v0 = total_weight + ld1 {v1.s}[0], [x4], #4 // v1 = src pixels (low 4 bytes) + ld1 {v2.4s}, [x6] // v2 = sum + + // Move to scalar registers to address lut + mov w8, v3.s[0] + mov w9, v3.s[1] + mov w11, v3.s[2] + mov w12, v3.s[3] + + // Load 4 float weights using scalar registers + // Interleave with src conversion to hide latency + ldr s3, [x7, w8, uxtw #2] // w0 -> v3.s[0] (v3 is now free) + ldr s4, [x7, w9, uxtw #2] // w1 -> v4.s[0] + ldr s5, [x7, w11, uxtw #2] // w2 -> v5.s[0] + ldr s6, [x7, w12, uxtw #2] // w3 -> v6.s[0] + + // Convert src pixels to float (independent of weights) + uxtl v1.8h, v1.8b + uxtl v1.4s, v1.4h + ucvtf v1.4s, v1.4s + + // Merge weights into v3.4s + trn1 v3.2s, v3.2s, v4.2s // v3 = [w0, w1, ?, ?] + trn1 v5.2s, v5.2s, v6.2s // v5 = [w2, w3, ?, ?] + trn1 v3.2d, v3.2d, v5.2d // v3 = [w0, w1, w2, w3] + + // Update total_weight and sum + fadd v0.4s, v0.4s, v3.4s // total_weight += weight + fmla v2.4s, v1.4s, v3.4s // sum += src * weight + + // Store back + st1 {v0.4s}, [x5], #16 + st1 {v2.4s}, [x6], #16 + + sub w10, w10, #4 + b 1b + +2: // Leftovers + cmp w10, #0 + b.le 9f + + // Single pixel handling + ldr w8, [x0], #4 // iia (reuse w8) + ldr w9, [x1], #4 // iib (reuse w9) + ldr w11, [x2], #4 // iid (reuse w11) + ldr w12, [x3], #4 // iie (reuse w12) + + sub w12, w12, w11 + sub w12, w12, w9 + add w12, w12, w8 + + // min (unsigned comparison) - use preloaded w13 + cmp w12, w13 + csel w12, w12, w13, ls // unsigned lower or same + + // Load weight + ldr s0, [x7, w12, uxtw #2] + + // Load src + ldrb w8, [x4], #1 // src (reuse w8) + ucvtf s1, w8 + + // Load acc + ldr s2, [x5] + ldr s3, [x6] + + fadd s2, s2, s0 + fmadd s3, s1, s0, s3 + + str s2, [x5], #4 + str s3, [x6], #4 + + sub w10, w10, #1 + b 2b + +9: ret +endfunc diff --git a/libavfilter/aeval.c b/libavfilter/aeval.c index 0e7ba8df8..baea5886f 100644 --- a/libavfilter/aeval.c +++ b/libavfilter/aeval.c @@ -114,9 +114,10 @@ static int parse_channel_expressions(AVFilterContext *ctx, if (!args1) return AVERROR(ENOMEM); - if (!eval->exprs) { + if (!eval->exprs || !*eval->exprs) { av_log(ctx, AV_LOG_ERROR, "Channels expressions list is empty\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto end; } if (!strcmp(ctx->filter->name, "aeval")) { @@ -252,7 +253,7 @@ static int query_formats(const AVFilterContext *ctx, int sample_rates[] = { eval->sample_rate, -1 }; int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; @@ -320,17 +321,16 @@ static const AVFilterPad aevalsrc_outputs[] = { }, }; -const AVFilter ff_asrc_aevalsrc = { - .name = "aevalsrc", - .description = NULL_IF_CONFIG_SMALL("Generate an audio signal generated by an expression."), +const FFFilter ff_asrc_aevalsrc = { + .p.name = "aevalsrc", + .p.description = NULL_IF_CONFIG_SMALL("Generate an audio signal generated by an expression."), + .p.priv_class = &aevalsrc_class, .init = init, .uninit = uninit, .activate = activate, .priv_size = sizeof(EvalContext), - .inputs = NULL, FILTER_OUTPUTS(aevalsrc_outputs), FILTER_QUERY_FUNC2(query_formats), - .priv_class = &aevalsrc_class, }; #endif /* CONFIG_AEVALSRC_FILTER */ @@ -372,7 +372,7 @@ static int aeval_query_formats(const AVFilterContext *ctx, return ret; } - if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts)) < 0) + if ((ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts)) < 0) return ret; return 0; @@ -462,17 +462,17 @@ static const AVFilterPad aeval_outputs[] = { }, }; -const AVFilter ff_af_aeval = { - .name = "aeval", - .description = NULL_IF_CONFIG_SMALL("Filter audio signal according to a specified expression."), +const FFFilter ff_af_aeval = { + .p.name = "aeval", + .p.description = NULL_IF_CONFIG_SMALL("Filter audio signal according to a specified expression."), + .p.priv_class = &aeval_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .init = init, .uninit = uninit, .priv_size = sizeof(EvalContext), FILTER_INPUTS(aeval_inputs), FILTER_OUTPUTS(aeval_outputs), FILTER_QUERY_FUNC2(aeval_query_formats), - .priv_class = &aeval_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; #endif /* CONFIG_AEVAL_FILTER */ diff --git a/libavfilter/af_aap.c b/libavfilter/af_aap.c index 05608d7fb..d23e5cdab 100644 --- a/libavfilter/af_aap.c +++ b/libavfilter/af_aap.c @@ -107,7 +107,7 @@ static int query_formats(const AVFilterContext *ctx, }; int ret; - if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, + if ((ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts[s->precision])) < 0) return ret; @@ -315,18 +315,18 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_aap = { - .name = "aap", - .description = NULL_IF_CONFIG_SMALL("Apply Affine Projection algorithm to first audio stream."), +const FFFilter ff_af_aap = { + .p.name = "aap", + .p.description = NULL_IF_CONFIG_SMALL("Apply Affine Projection algorithm to first audio stream."), + .p.priv_class = &aap_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioAPContext), - .priv_class = &aap_class, .init = init, .uninit = uninit, .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_acontrast.c b/libavfilter/af_acontrast.c index e520b1b66..b99a65b2f 100644 --- a/libavfilter/af_acontrast.c +++ b/libavfilter/af_acontrast.c @@ -169,11 +169,11 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_acontrast = { - .name = "acontrast", - .description = NULL_IF_CONFIG_SMALL("Simple audio dynamic range compression/expansion filter."), +const FFFilter ff_af_acontrast = { + .p.name = "acontrast", + .p.description = NULL_IF_CONFIG_SMALL("Simple audio dynamic range compression/expansion filter."), + .p.priv_class = &acontrast_class, .priv_size = sizeof(AudioContrastContext), - .priv_class = &acontrast_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, diff --git a/libavfilter/af_acopy.c b/libavfilter/af_acopy.c index 9d06e2d4b..e886a2ce2 100644 --- a/libavfilter/af_acopy.c +++ b/libavfilter/af_acopy.c @@ -53,10 +53,10 @@ static const AVFilterPad acopy_inputs[] = { }, }; -const AVFilter ff_af_acopy = { - .name = "acopy", - .description = NULL_IF_CONFIG_SMALL("Copy the input audio unchanged to the output."), - .flags = AVFILTER_FLAG_METADATA_ONLY, +const FFFilter ff_af_acopy = { + .p.name = "acopy", + .p.description = NULL_IF_CONFIG_SMALL("Copy the input audio unchanged to the output."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(acopy_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), }; diff --git a/libavfilter/af_acrossover.c b/libavfilter/af_acrossover.c index 3fd5c1d24..fedf281d5 100644 --- a/libavfilter/af_acrossover.c +++ b/libavfilter/af_acrossover.c @@ -138,7 +138,7 @@ static int query_formats(const AVFilterContext *ctx, default: break; } - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts_list); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts_list); if (ret < 0) return ret; @@ -588,15 +588,7 @@ static int activate(AVFilterContext *ctx) return 0; } - for (int i = 0; i < ctx->nb_outputs; i++) { - if (ff_outlink_get_status(ctx->outputs[i])) - continue; - - if (ff_outlink_frame_wanted(ctx->outputs[i])) { - ff_inlink_request_frame(inlink); - return 0; - } - } + FF_FILTER_FORWARD_WANTED_ANY(ctx, inlink); return FFERROR_NOT_READY; } @@ -617,17 +609,17 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_acrossover = { - .name = "acrossover", - .description = NULL_IF_CONFIG_SMALL("Split audio into per-bands streams."), +const FFFilter ff_af_acrossover = { + .p.name = "acrossover", + .p.description = NULL_IF_CONFIG_SMALL("Split audio into per-bands streams."), + .p.priv_class = &acrossover_class, + .p.outputs = NULL, + .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioCrossoverContext), - .priv_class = &acrossover_class, .init = init, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), - .outputs = NULL, FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_acrusher.c b/libavfilter/af_acrusher.c index f064f5b04..3ec38269d 100644 --- a/libavfilter/af_acrusher.c +++ b/libavfilter/af_acrusher.c @@ -326,15 +326,15 @@ static const AVFilterPad avfilter_af_acrusher_inputs[] = { }, }; -const AVFilter ff_af_acrusher = { - .name = "acrusher", - .description = NULL_IF_CONFIG_SMALL("Reduce audio bit resolution."), +const FFFilter ff_af_acrusher = { + .p.name = "acrusher", + .p.description = NULL_IF_CONFIG_SMALL("Reduce audio bit resolution."), + .p.priv_class = &acrusher_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(ACrusherContext), - .priv_class = &acrusher_class, .uninit = uninit, FILTER_INPUTS(avfilter_af_acrusher_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c index 819ad2ab5..043435b18 100644 --- a/libavfilter/af_adeclick.c +++ b/libavfilter/af_adeclick.c @@ -778,18 +778,18 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_adeclick = { - .name = "adeclick", - .description = NULL_IF_CONFIG_SMALL("Remove impulsive noise from input audio."), +const FFFilter ff_af_adeclick = { + .p.name = "adeclick", + .p.description = NULL_IF_CONFIG_SMALL("Remove impulsive noise from input audio."), + .p.priv_class = &adeclick_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioDeclickContext), - .priv_class = &adeclick_class, .init = init, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; static const AVOption adeclip_options[] = { @@ -814,16 +814,16 @@ static const AVOption adeclip_options[] = { AVFILTER_DEFINE_CLASS(adeclip); -const AVFilter ff_af_adeclip = { - .name = "adeclip", - .description = NULL_IF_CONFIG_SMALL("Remove clipping from input audio."), +const FFFilter ff_af_adeclip = { + .p.name = "adeclip", + .p.description = NULL_IF_CONFIG_SMALL("Remove clipping from input audio."), + .p.priv_class = &adeclip_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioDeclickContext), - .priv_class = &adeclip_class, .init = init, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_adecorrelate.c b/libavfilter/af_adecorrelate.c index 5cde9e7e1..8991bf207 100644 --- a/libavfilter/af_adecorrelate.c +++ b/libavfilter/af_adecorrelate.c @@ -231,15 +231,15 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_adecorrelate = { - .name = "adecorrelate", - .description = NULL_IF_CONFIG_SMALL("Apply decorrelation to input audio."), +const FFFilter ff_af_adecorrelate = { + .p.name = "adecorrelate", + .p.description = NULL_IF_CONFIG_SMALL("Apply decorrelation to input audio."), + .p.priv_class = &adecorrelate_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ADecorrelateContext), - .priv_class = &adecorrelate_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c index ab2d66044..c0d076fe6 100644 --- a/libavfilter/af_adelay.c +++ b/libavfilter/af_adelay.c @@ -465,17 +465,17 @@ static const AVFilterPad adelay_inputs[] = { }, }; -const AVFilter ff_af_adelay = { - .name = "adelay", - .description = NULL_IF_CONFIG_SMALL("Delay one or more audio channels."), +const FFFilter ff_af_adelay = { + .p.name = "adelay", + .p.description = NULL_IF_CONFIG_SMALL("Delay one or more audio channels."), + .p.priv_class = &adelay_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioDelayContext), - .priv_class = &adelay_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(adelay_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = process_command, }; diff --git a/libavfilter/af_adenorm.c b/libavfilter/af_adenorm.c index 7dc3c0f73..0d61eed1d 100644 --- a/libavfilter/af_adenorm.c +++ b/libavfilter/af_adenorm.c @@ -262,15 +262,15 @@ static const AVOption adenorm_options[] = { AVFILTER_DEFINE_CLASS(adenorm); -const AVFilter ff_af_adenorm = { - .name = "adenorm", - .description = NULL_IF_CONFIG_SMALL("Remedy denormals by adding extremely low-level noise."), +const FFFilter ff_af_adenorm = { + .p.name = "adenorm", + .p.description = NULL_IF_CONFIG_SMALL("Remedy denormals by adding extremely low-level noise."), + .p.priv_class = &adenorm_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ADenormContext), FILTER_INPUTS(adenorm_inputs), FILTER_OUTPUTS(adenorm_outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), - .priv_class = &adenorm_class, .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_aderivative.c b/libavfilter/af_aderivative.c index 1254aa945..7ac730836 100644 --- a/libavfilter/af_aderivative.c +++ b/libavfilter/af_aderivative.c @@ -160,27 +160,27 @@ static const AVOption aderivative_options[] = { AVFILTER_DEFINE_CLASS_EXT(aderivative, "aderivative/aintegral", aderivative_options); -const AVFilter ff_af_aderivative = { - .name = "aderivative", - .description = NULL_IF_CONFIG_SMALL("Compute derivative of input audio."), +const FFFilter ff_af_aderivative = { + .p.name = "aderivative", + .p.description = NULL_IF_CONFIG_SMALL("Compute derivative of input audio."), + .p.priv_class = &aderivative_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(ADerivativeContext), - .priv_class = &aderivative_class, .uninit = uninit, FILTER_INPUTS(aderivative_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; -const AVFilter ff_af_aintegral = { - .name = "aintegral", - .description = NULL_IF_CONFIG_SMALL("Compute integral of input audio."), +const FFFilter ff_af_aintegral = { + .p.name = "aintegral", + .p.description = NULL_IF_CONFIG_SMALL("Compute integral of input audio."), + .p.priv_class = &aderivative_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(ADerivativeContext), - .priv_class = &aderivative_class, .uninit = uninit, FILTER_INPUTS(aderivative_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_adrc.c b/libavfilter/af_adrc.c index 7410b99ed..9e3becdf2 100644 --- a/libavfilter/af_adrc.c +++ b/libavfilter/af_adrc.c @@ -486,17 +486,17 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_adrc = { - .name = "adrc", - .description = NULL_IF_CONFIG_SMALL("Audio Spectral Dynamic Range Controller."), +const FFFilter ff_af_adrc = { + .p.name = "adrc", + .p.description = NULL_IF_CONFIG_SMALL("Audio Spectral Dynamic Range Controller."), + .p.priv_class = &adrc_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioDRCContext), - .priv_class = &adrc_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .activate = activate, .process_command = process_command, }; diff --git a/libavfilter/af_adynamicequalizer.c b/libavfilter/af_adynamicequalizer.c index ba03faff6..44db821b1 100644 --- a/libavfilter/af_adynamicequalizer.c +++ b/libavfilter/af_adynamicequalizer.c @@ -122,7 +122,7 @@ static int query_formats(const AVFilterContext *ctx, }; int ret; - if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, + if ((ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts[s->precision])) < 0) return ret; @@ -273,16 +273,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_adynamicequalizer = { - .name = "adynamicequalizer", - .description = NULL_IF_CONFIG_SMALL("Apply Dynamic Equalization of input audio."), +const FFFilter ff_af_adynamicequalizer = { + .p.name = "adynamicequalizer", + .p.description = NULL_IF_CONFIG_SMALL("Apply Dynamic Equalization of input audio."), + .p.priv_class = &adynamicequalizer_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioDynamicEqualizerContext), - .priv_class = &adynamicequalizer_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_adynamicsmooth.c b/libavfilter/af_adynamicsmooth.c index a0276616c..aa729c9c1 100644 --- a/libavfilter/af_adynamicsmooth.c +++ b/libavfilter/af_adynamicsmooth.c @@ -121,15 +121,15 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_adynamicsmooth = { - .name = "adynamicsmooth", - .description = NULL_IF_CONFIG_SMALL("Apply Dynamic Smoothing of input audio."), +const FFFilter ff_af_adynamicsmooth = { + .p.name = "adynamicsmooth", + .p.description = NULL_IF_CONFIG_SMALL("Apply Dynamic Smoothing of input audio."), + .p.priv_class = &adynamicsmooth_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioDynamicSmoothContext), - .priv_class = &adynamicsmooth_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_aecho.c b/libavfilter/af_aecho.c index b1c656e03..ff316eaa6 100644 --- a/libavfilter/af_aecho.c +++ b/libavfilter/af_aecho.c @@ -336,11 +336,11 @@ static const AVFilterPad aecho_outputs[] = { }, }; -const AVFilter ff_af_aecho = { - .name = "aecho", - .description = NULL_IF_CONFIG_SMALL("Add echoing to the audio."), +const FFFilter ff_af_aecho = { + .p.name = "aecho", + .p.description = NULL_IF_CONFIG_SMALL("Add echoing to the audio."), + .p.priv_class = &aecho_class, .priv_size = sizeof(AudioEchoContext), - .priv_class = &aecho_class, .init = init, .activate = activate, .uninit = uninit, diff --git a/libavfilter/af_aemphasis.c b/libavfilter/af_aemphasis.c index 4bde91671..d35111f89 100644 --- a/libavfilter/af_aemphasis.c +++ b/libavfilter/af_aemphasis.c @@ -361,16 +361,16 @@ static const AVFilterPad avfilter_af_aemphasis_inputs[] = { }, }; -const AVFilter ff_af_aemphasis = { - .name = "aemphasis", - .description = NULL_IF_CONFIG_SMALL("Audio emphasis."), +const FFFilter ff_af_aemphasis = { + .p.name = "aemphasis", + .p.description = NULL_IF_CONFIG_SMALL("Audio emphasis."), + .p.priv_class = &aemphasis_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioEmphasisContext), - .priv_class = &aemphasis_class, .uninit = uninit, FILTER_INPUTS(avfilter_af_aemphasis_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_aexciter.c b/libavfilter/af_aexciter.c index 3fe7ce799..188693716 100644 --- a/libavfilter/af_aexciter.c +++ b/libavfilter/af_aexciter.c @@ -265,15 +265,15 @@ static const AVFilterPad avfilter_af_aexciter_inputs[] = { }, }; -const AVFilter ff_af_aexciter = { - .name = "aexciter", - .description = NULL_IF_CONFIG_SMALL("Enhance high frequency part of audio."), +const FFFilter ff_af_aexciter = { + .p.name = "aexciter", + .p.description = NULL_IF_CONFIG_SMALL("Enhance high frequency part of audio."), + .p.priv_class = &aexciter_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AExciterContext), - .priv_class = &aexciter_class, .uninit = uninit, FILTER_INPUTS(avfilter_af_aexciter_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c index 7cc5182d1..055f234f7 100644 --- a/libavfilter/af_afade.c +++ b/libavfilter/af_afade.c @@ -25,6 +25,8 @@ #include "config_components.h" +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" @@ -32,6 +34,7 @@ typedef struct AudioFadeContext { const AVClass *class; + int nb_inputs; int type; int curve, curve2; int64_t nb_samples; @@ -41,9 +44,8 @@ typedef struct AudioFadeContext { double silence; double unity; int overlap; - int status[2]; - int passthrough; int64_t pts; + int xfade_idx; void (*fade_samples)(uint8_t **dst, uint8_t * const *src, int nb_samples, int channels, int direction, @@ -433,17 +435,17 @@ static const AVFilterPad avfilter_af_afade_outputs[] = { }, }; -const AVFilter ff_af_afade = { - .name = "afade", - .description = NULL_IF_CONFIG_SMALL("Fade in/out input audio."), +const FFFilter ff_af_afade = { + .p.name = "afade", + .p.description = NULL_IF_CONFIG_SMALL("Fade in/out input audio."), + .p.priv_class = &afade_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(AudioFadeContext), .init = init, FILTER_INPUTS(avfilter_af_afade_inputs), FILTER_OUTPUTS(avfilter_af_afade_outputs), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), - .priv_class = &afade_class, .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; #endif /* CONFIG_AFADE_FILTER */ @@ -451,6 +453,8 @@ const AVFilter ff_af_afade = { #if CONFIG_ACROSSFADE_FILTER static const AVOption acrossfade_options[] = { + { "inputs", "set number of input files to cross fade", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT32_MAX, FLAGS }, + { "n", "set number of input files to cross fade", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT32_MAX, FLAGS }, { "nb_samples", "set number of samples for cross fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT64, {.i64 = 44100}, 1, INT32_MAX/10, FLAGS }, { "ns", "set number of samples for cross fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT64, {.i64 = 44100}, 1, INT32_MAX/10, FLAGS }, { "duration", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0 }, 0, 60000000, FLAGS }, @@ -540,141 +544,239 @@ CROSSFADE(flt, float) CROSSFADE(s16, int16_t) CROSSFADE(s32, int32_t) -static int check_input(AVFilterLink *inlink) +static int pass_frame(AVFilterLink *inlink, AVFilterLink *outlink, int64_t *pts) { - const int queued_samples = ff_inlink_queued_samples(inlink); + AVFrame *in; + int ret = ff_inlink_consume_frame(inlink, &in); + if (ret < 0) + return ret; + av_assert1(ret); + in->pts = *pts; + *pts += av_rescale_q(in->nb_samples, + (AVRational){ 1, outlink->sample_rate }, outlink->time_base); + return ff_filter_frame(outlink, in); +} - return ff_inlink_check_available_samples(inlink, queued_samples + 1) == 1; +static int pass_samples(AVFilterLink *inlink, AVFilterLink *outlink, unsigned nb_samples, int64_t *pts) +{ + AVFrame *in; + int ret = ff_inlink_consume_samples(inlink, nb_samples, nb_samples, &in); + if (ret < 0) + return ret; + av_assert1(ret); + in->pts = *pts; + *pts += av_rescale_q(in->nb_samples, + (AVRational){ 1, outlink->sample_rate }, outlink->time_base); + return ff_filter_frame(outlink, in); +} + +static int pass_crossfade(AVFilterContext *ctx, const int idx0, const int idx1) +{ + AudioFadeContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *out, *cf[2] = { NULL }; + int ret; + + AVFilterLink *in0 = ctx->inputs[idx0]; + AVFilterLink *in1 = ctx->inputs[idx1]; + int queued_samples0 = ff_inlink_queued_samples(in0); + int queued_samples1 = ff_inlink_queued_samples(in1); + + /* Limit to the relevant region */ + av_assert1(queued_samples0 <= s->nb_samples); + if (ff_outlink_get_status(in1) && idx1 < s->nb_inputs - 1) + queued_samples1 /= 2; /* reserve second half for next fade-out */ + queued_samples1 = FFMIN(queued_samples1, s->nb_samples); + + if (s->overlap) { + int nb_samples = FFMIN(queued_samples0, queued_samples1); + if (nb_samples < s->nb_samples) { + av_log(ctx, AV_LOG_WARNING, "Input %d duration (%d samples) " + "is shorter than crossfade duration (%"PRId64" samples), " + "crossfade will be shorter by %"PRId64" samples.\n", + queued_samples0 <= queued_samples1 ? idx0 : idx1, + nb_samples, s->nb_samples, s->nb_samples - nb_samples); + + if (queued_samples0 > nb_samples) { + ret = pass_samples(in0, outlink, queued_samples0 - nb_samples, &s->pts); + if (ret < 0) + return ret; + } + + if (!nb_samples) + return 0; /* either input was completely empty */ + } + + av_assert1(nb_samples > 0); + out = ff_get_audio_buffer(outlink, nb_samples); + if (!out) + return AVERROR(ENOMEM); + + ret = ff_inlink_consume_samples(in0, nb_samples, nb_samples, &cf[0]); + if (ret < 0) { + av_frame_free(&out); + return ret; + } + + ret = ff_inlink_consume_samples(in1, nb_samples, nb_samples, &cf[1]); + if (ret < 0) { + av_frame_free(&cf[0]); + av_frame_free(&out); + return ret; + } + + s->crossfade_samples(out->extended_data, cf[0]->extended_data, + cf[1]->extended_data, nb_samples, + out->ch_layout.nb_channels, s->curve, s->curve2); + out->pts = s->pts; + s->pts += av_rescale_q(nb_samples, + (AVRational){ 1, outlink->sample_rate }, outlink->time_base); + av_frame_free(&cf[0]); + av_frame_free(&cf[1]); + return ff_filter_frame(outlink, out); + } else { + if (queued_samples0 < s->nb_samples) { + av_log(ctx, AV_LOG_WARNING, "Input %d duration (%d samples) " + "is shorter than crossfade duration (%"PRId64" samples), " + "fade-out will be shorter by %"PRId64" samples.\n", + idx0, queued_samples0, s->nb_samples, + s->nb_samples - queued_samples0); + if (!queued_samples0) + goto fade_in; + } + + out = ff_get_audio_buffer(outlink, queued_samples0); + if (!out) + return AVERROR(ENOMEM); + + ret = ff_inlink_consume_samples(in0, queued_samples0, queued_samples0, &cf[0]); + if (ret < 0) { + av_frame_free(&out); + return ret; + } + + s->fade_samples(out->extended_data, cf[0]->extended_data, cf[0]->nb_samples, + outlink->ch_layout.nb_channels, -1, cf[0]->nb_samples - 1, cf[0]->nb_samples, s->curve, 0., 1.); + out->pts = s->pts; + s->pts += av_rescale_q(cf[0]->nb_samples, + (AVRational){ 1, outlink->sample_rate }, outlink->time_base); + av_frame_free(&cf[0]); + ret = ff_filter_frame(outlink, out); + if (ret < 0) + return ret; + + fade_in: + if (queued_samples1 < s->nb_samples) { + av_log(ctx, AV_LOG_WARNING, "Input %d duration (%d samples) " + "is shorter than crossfade duration (%"PRId64" samples), " + "fade-in will be shorter by %"PRId64" samples.\n", + idx1, ff_inlink_queued_samples(in1), s->nb_samples, + s->nb_samples - queued_samples1); + if (!queued_samples1) + return 0; + } + + out = ff_get_audio_buffer(outlink, queued_samples1); + if (!out) + return AVERROR(ENOMEM); + + ret = ff_inlink_consume_samples(in1, queued_samples1, queued_samples1, &cf[1]); + if (ret < 0) { + av_frame_free(&out); + return ret; + } + + s->fade_samples(out->extended_data, cf[1]->extended_data, cf[1]->nb_samples, + outlink->ch_layout.nb_channels, 1, 0, cf[1]->nb_samples, s->curve2, 0., 1.); + out->pts = s->pts; + s->pts += av_rescale_q(cf[1]->nb_samples, + (AVRational){ 1, outlink->sample_rate }, outlink->time_base); + av_frame_free(&cf[1]); + return ff_filter_frame(outlink, out); + } } static int activate(AVFilterContext *ctx) { AudioFadeContext *s = ctx->priv; + const int idx0 = s->xfade_idx; + const int idx1 = s->xfade_idx + 1; AVFilterLink *outlink = ctx->outputs[0]; - AVFrame *in = NULL, *out, *cf[2] = { NULL }; - int ret = 0, nb_samples, status; - int64_t pts; + AVFilterLink *in0 = ctx->inputs[idx0]; FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx); - if (s->passthrough && s->status[0]) { - ret = ff_inlink_consume_frame(ctx->inputs[1], &in); - if (ret > 0) { - in->pts = s->pts; - s->pts += av_rescale_q(in->nb_samples, - (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - return ff_filter_frame(outlink, in); - } else if (ret < 0) { - return ret; - } else if (ff_inlink_acknowledge_status(ctx->inputs[1], &status, &pts)) { - ff_outlink_set_status(outlink, status, pts); - return 0; - } else if (!ret) { - if (ff_outlink_frame_wanted(outlink)) { - ff_inlink_request_frame(ctx->inputs[1]); - return 0; - } - } + if (idx0 == s->nb_inputs - 1) { + /* Last active input, read until EOF */ + if (ff_inlink_queued_frames(in0)) + return pass_frame(in0, outlink, &s->pts); + FF_FILTER_FORWARD_STATUS(in0, outlink); + FF_FILTER_FORWARD_WANTED(outlink, in0); + return FFERROR_NOT_READY; } - nb_samples = ff_inlink_queued_samples(ctx->inputs[0]); - if (nb_samples > s->nb_samples) { - nb_samples -= s->nb_samples; - s->passthrough = 1; - ret = ff_inlink_consume_samples(ctx->inputs[0], nb_samples, nb_samples, &in); + AVFilterLink *in1 = ctx->inputs[idx1]; + int queued_samples0 = ff_inlink_queued_samples(in0); + if (queued_samples0 > s->nb_samples) { + AVFrame *frame = ff_inlink_peek_frame(in0, 0); + if (queued_samples0 - s->nb_samples >= frame->nb_samples) + return pass_frame(in0, outlink, &s->pts); + } + + /* Continue reading until EOF */ + if (ff_outlink_get_status(in0)) { + if (queued_samples0 > s->nb_samples) + return pass_samples(in0, outlink, queued_samples0 - s->nb_samples, &s->pts); + } else { + FF_FILTER_FORWARD_WANTED(outlink, in0); + return FFERROR_NOT_READY; + } + + /* At this point, in0 has reached EOF with no more samples remaining + * except those that we want to crossfade */ + av_assert0(queued_samples0 <= s->nb_samples); + int queued_samples1 = ff_inlink_queued_samples(in1); + + /* If this clip is sandwiched between two other clips, buffer at least + * twice the total crossfade duration to ensure that we won't reach EOF + * during the second fade (in which case we would shorten the fade) */ + int needed_samples = s->nb_samples; + if (idx1 < s->nb_inputs - 1) + needed_samples *= 2; + + if (queued_samples1 >= needed_samples || ff_outlink_get_status(in1)) { + /* The first filter may EOF before delivering any samples, in which + * case it's possible for pass_crossfade() to be a no-op. Just ensure + * the activate() function runs again after incrementing the index to + * ensure we correctly move on to the next input in that case. */ + s->xfade_idx++; + ff_filter_set_ready(ctx, 10); + return pass_crossfade(ctx, idx0, idx1); + } else { + FF_FILTER_FORWARD_WANTED(outlink, in1); + return FFERROR_NOT_READY; + } +} + +static av_cold int acrossfade_init(AVFilterContext *ctx) +{ + AudioFadeContext *s = ctx->priv; + int ret; + + for (int i = 0; i < s->nb_inputs; i++) { + AVFilterPad pad = { + .name = av_asprintf("crossfade%d", i), + .type = AVMEDIA_TYPE_AUDIO, + }; + if (!pad.name) + return AVERROR(ENOMEM); + + ret = ff_append_inpad_free_name(ctx, &pad); if (ret < 0) return ret; - in->pts = s->pts; - s->pts += av_rescale_q(in->nb_samples, - (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - return ff_filter_frame(outlink, in); - } else if (s->status[0] && nb_samples >= s->nb_samples && - ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples) { - if (s->overlap) { - out = ff_get_audio_buffer(outlink, s->nb_samples); - if (!out) - return AVERROR(ENOMEM); - - ret = ff_inlink_consume_samples(ctx->inputs[0], s->nb_samples, s->nb_samples, &cf[0]); - if (ret < 0) { - av_frame_free(&out); - return ret; - } - - ret = ff_inlink_consume_samples(ctx->inputs[1], s->nb_samples, s->nb_samples, &cf[1]); - if (ret < 0) { - av_frame_free(&out); - return ret; - } - - s->crossfade_samples(out->extended_data, cf[0]->extended_data, - cf[1]->extended_data, - s->nb_samples, out->ch_layout.nb_channels, - s->curve, s->curve2); - out->pts = s->pts; - s->pts += av_rescale_q(s->nb_samples, - (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - s->passthrough = 1; - av_frame_free(&cf[0]); - av_frame_free(&cf[1]); - return ff_filter_frame(outlink, out); - } else { - out = ff_get_audio_buffer(outlink, s->nb_samples); - if (!out) - return AVERROR(ENOMEM); - - ret = ff_inlink_consume_samples(ctx->inputs[0], s->nb_samples, s->nb_samples, &cf[0]); - if (ret < 0) { - av_frame_free(&out); - return ret; - } - - s->fade_samples(out->extended_data, cf[0]->extended_data, s->nb_samples, - outlink->ch_layout.nb_channels, -1, s->nb_samples - 1, s->nb_samples, s->curve, 0., 1.); - out->pts = s->pts; - s->pts += av_rescale_q(s->nb_samples, - (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - av_frame_free(&cf[0]); - ret = ff_filter_frame(outlink, out); - if (ret < 0) - return ret; - - out = ff_get_audio_buffer(outlink, s->nb_samples); - if (!out) - return AVERROR(ENOMEM); - - ret = ff_inlink_consume_samples(ctx->inputs[1], s->nb_samples, s->nb_samples, &cf[1]); - if (ret < 0) { - av_frame_free(&out); - return ret; - } - - s->fade_samples(out->extended_data, cf[1]->extended_data, s->nb_samples, - outlink->ch_layout.nb_channels, 1, 0, s->nb_samples, s->curve2, 0., 1.); - out->pts = s->pts; - s->pts += av_rescale_q(s->nb_samples, - (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - s->passthrough = 1; - av_frame_free(&cf[1]); - return ff_filter_frame(outlink, out); - } - } else if (ff_outlink_frame_wanted(outlink)) { - if (!s->status[0] && check_input(ctx->inputs[0])) - s->status[0] = AVERROR_EOF; - s->passthrough = !s->status[0]; - if (check_input(ctx->inputs[1])) { - s->status[1] = AVERROR_EOF; - ff_outlink_set_status(outlink, AVERROR_EOF, AV_NOPTS_VALUE); - return 0; - } - if (!s->status[0]) - ff_inlink_request_frame(ctx->inputs[0]); - else - ff_inlink_request_frame(ctx->inputs[1]); - return 0; } - return ret; + return 0; } static int acrossfade_config_output(AVFilterLink *outlink) @@ -700,29 +802,6 @@ static int acrossfade_config_output(AVFilterLink *outlink) return 0; } -static AVFrame *get_audio_buffer(AVFilterLink *inlink, int nb_samples) -{ - AVFilterContext *ctx = inlink->dst; - AudioFadeContext *s = ctx->priv; - - return s->passthrough ? - ff_null_get_audio_buffer (inlink, nb_samples) : - ff_default_get_audio_buffer(inlink, nb_samples); -} - -static const AVFilterPad avfilter_af_acrossfade_inputs[] = { - { - .name = "crossfade0", - .type = AVMEDIA_TYPE_AUDIO, - .get_buffer.audio = get_audio_buffer, - }, - { - .name = "crossfade1", - .type = AVMEDIA_TYPE_AUDIO, - .get_buffer.audio = get_audio_buffer, - }, -}; - static const AVFilterPad avfilter_af_acrossfade_outputs[] = { { .name = "default", @@ -731,13 +810,14 @@ static const AVFilterPad avfilter_af_acrossfade_outputs[] = { }, }; -const AVFilter ff_af_acrossfade = { - .name = "acrossfade", - .description = NULL_IF_CONFIG_SMALL("Cross fade two input audio streams."), +const FFFilter ff_af_acrossfade = { + .p.name = "acrossfade", + .p.description = NULL_IF_CONFIG_SMALL("Cross fade two input audio streams."), + .p.priv_class = &acrossfade_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(AudioFadeContext), + .init = acrossfade_init, .activate = activate, - .priv_class = &acrossfade_class, - FILTER_INPUTS(avfilter_af_acrossfade_inputs), FILTER_OUTPUTS(avfilter_af_acrossfade_outputs), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), }; diff --git a/libavfilter/af_afftdn.c b/libavfilter/af_afftdn.c index fd6b2b268..e97dfe1f0 100644 --- a/libavfilter/af_afftdn.c +++ b/libavfilter/af_afftdn.c @@ -379,7 +379,7 @@ static void process_frame(AVFilterContext *ctx, noisy_data[i] = mag = hypot(fft_data_dbl[i].re, fft_data_dbl[i].im); break; default: - av_assert2(0); + av_assert0(0); } power = mag * mag; @@ -541,8 +541,9 @@ static void set_band_parameters(AudioFFTDeNoiseContext *s, dnch->noise_band_auto_var[i] = dnch->max_var * exp((process_get_band_noise(s, dnch, i) - 2.0) * C); } -static void read_custom_noise(AudioFFTDeNoiseContext *s, int ch) +static void read_custom_noise(AVFilterContext *ctx, int ch) { + AudioFFTDeNoiseContext *s = ctx->priv; DeNoiseChannel *dnch = &s->dnch[ch]; char *custom_noise_str, *p, *arg, *saveptr = NULL; double band_noise[NB_PROFILE_BANDS] = { 0.f }; @@ -565,7 +566,7 @@ static void read_custom_noise(AudioFFTDeNoiseContext *s, int ch) ret = av_sscanf(arg, "%f", &noise); if (ret != 1) { - av_log(s, AV_LOG_ERROR, "Custom band noise must be float.\n"); + av_log(ctx, AV_LOG_ERROR, "Custom band noise must be float.\n"); break; } @@ -735,7 +736,7 @@ static int config_input(AVFilterLink *inlink) dnch->band_noise[i] = get_band_noise(s, i, 1.0, 500.0, 1.0E10); break; case CUSTOM_NOISE: - read_custom_noise(s, ch); + read_custom_noise(ctx, ch); break; default: return AVERROR_BUG; @@ -1009,10 +1010,11 @@ static void finish_sample_noise(AudioFFTDeNoiseContext *s, } } -static void set_noise_profile(AudioFFTDeNoiseContext *s, +static void set_noise_profile(AVFilterContext *ctx, DeNoiseChannel *dnch, double *sample_noise) { + AudioFFTDeNoiseContext *s = ctx->priv; double new_band_noise[NB_PROFILE_BANDS]; double temp[NB_PROFILE_BANDS]; double sum = 0.0; @@ -1036,13 +1038,13 @@ static void set_noise_profile(AudioFFTDeNoiseContext *s, reduce_mean(temp); - av_log(s, AV_LOG_INFO, "bn="); + av_log(ctx, AV_LOG_INFO, "bn="); for (int m = 0; m < NB_PROFILE_BANDS; m++) { new_band_noise[m] = temp[m]; new_band_noise[m] = av_clipd(new_band_noise[m], -24.0, 24.0); - av_log(s, AV_LOG_INFO, "%f ", new_band_noise[m]); + av_log(ctx, AV_LOG_INFO, "%f ", new_band_noise[m]); } - av_log(s, AV_LOG_INFO, "\n"); + av_log(ctx, AV_LOG_INFO, "\n"); memcpy(dnch->band_noise, new_band_noise, sizeof(new_band_noise)); } @@ -1182,7 +1184,7 @@ static int output_frame(AVFilterLink *inlink, AVFrame *in) if (s->sample_noise_blocks <= 0) break; finish_sample_noise(s, dnch, sample_noise); - set_noise_profile(s, dnch, sample_noise); + set_noise_profile(ctx, dnch, sample_noise); set_parameters(s, dnch, 1, 1); } s->sample_noise = 0; @@ -1363,17 +1365,17 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_afftdn = { - .name = "afftdn", - .description = NULL_IF_CONFIG_SMALL("Denoise audio samples using FFT."), +const FFFilter ff_af_afftdn = { + .p.name = "afftdn", + .p.description = NULL_IF_CONFIG_SMALL("Denoise audio samples using FFT."), + .p.priv_class = &afftdn_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioFFTDeNoiseContext), - .priv_class = &afftdn_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_afftfilt.c b/libavfilter/af_afftfilt.c index 98b09e666..08cdcae2f 100644 --- a/libavfilter/af_afftfilt.c +++ b/libavfilter/af_afftfilt.c @@ -439,16 +439,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_afftfilt = { - .name = "afftfilt", - .description = NULL_IF_CONFIG_SMALL("Apply arbitrary expressions to samples in frequency domain."), +const FFFilter ff_af_afftfilt = { + .p.name = "afftfilt", + .p.description = NULL_IF_CONFIG_SMALL("Apply arbitrary expressions to samples in frequency domain."), + .p.priv_class = &afftfilt_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AFFTFiltContext), - .priv_class = &afftfilt_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), .activate = activate, .uninit = uninit, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_afir.c b/libavfilter/af_afir.c index c641893d4..fa6b063e4 100644 --- a/libavfilter/af_afir.c +++ b/libavfilter/af_afir.c @@ -569,7 +569,7 @@ static int query_formats(const AVFilterContext *ctx, } } - if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, + if ((ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts[s->precision])) < 0) return ret; @@ -777,18 +777,18 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_afir = { - .name = "afir", - .description = NULL_IF_CONFIG_SMALL("Apply Finite Impulse Response filter with supplied coefficients in additional stream(s)."), +const FFFilter ff_af_afir = { + .p.name = "afir", + .p.description = NULL_IF_CONFIG_SMALL("Apply Finite Impulse Response filter with supplied coefficients in additional stream(s)."), + .p.priv_class = &afir_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS | + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioFIRContext), - .priv_class = &afir_class, FILTER_QUERY_FUNC2(query_formats), FILTER_OUTPUTS(outputs), .init = init, .activate = activate, .uninit = uninit, .process_command = process_command, - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS | - AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_afirdsp.h b/libavfilter/af_afirdsp.h index 827e067a9..4ca859dfd 100644 --- a/libavfilter/af_afirdsp.h +++ b/libavfilter/af_afirdsp.h @@ -70,14 +70,14 @@ static void dcmul_add_c(double *sum, const double *t, const double *c, ptrdiff_t sum[2 * n] += t[2 * n] * c[2 * n]; } -static av_unused void ff_afir_init(AudioFIRDSPContext *dsp) +av_unused static void ff_afir_init(AudioFIRDSPContext *dsp) { dsp->fcmul_add = fcmul_add_c; dsp->dcmul_add = dcmul_add_c; #if ARCH_RISCV ff_afir_init_riscv(dsp); -#elif ARCH_X86 +#elif ARCH_X86 && HAVE_X86ASM ff_afir_init_x86(dsp); #endif } diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c index a7d05a9ce..ce54e045e 100644 --- a/libavfilter/af_aformat.c +++ b/libavfilter/af_aformat.c @@ -112,7 +112,7 @@ static int query_formats(const AVFilterContext *ctx, int ret; if (s->nb_formats) { - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, s->formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, s->formats); if (ret < 0) return ret; } @@ -132,13 +132,13 @@ static int query_formats(const AVFilterContext *ctx, return 0; } -const AVFilter ff_af_aformat = { - .name = "aformat", - .description = NULL_IF_CONFIG_SMALL("Convert the input audio to one of the specified formats."), +const FFFilter ff_af_aformat = { + .p.name = "aformat", + .p.description = NULL_IF_CONFIG_SMALL("Convert the input audio to one of the specified formats."), + .p.priv_class = &aformat_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .init = init, .priv_size = sizeof(AFormatContext), - .priv_class = &aformat_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), diff --git a/libavfilter/af_afreqshift.c b/libavfilter/af_afreqshift.c index fa93eed99..68969f2fd 100644 --- a/libavfilter/af_afreqshift.c +++ b/libavfilter/af_afreqshift.c @@ -366,18 +366,18 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_afreqshift = { - .name = "afreqshift", - .description = NULL_IF_CONFIG_SMALL("Apply frequency shifting to input audio."), +const FFFilter ff_af_afreqshift = { + .p.name = "afreqshift", + .p.description = NULL_IF_CONFIG_SMALL("Apply frequency shifting to input audio."), + .p.priv_class = &afreqshift_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AFreqShift), - .priv_class = &afreqshift_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; static const AVOption aphaseshift_options[] = { @@ -389,16 +389,16 @@ static const AVOption aphaseshift_options[] = { AVFILTER_DEFINE_CLASS(aphaseshift); -const AVFilter ff_af_aphaseshift = { - .name = "aphaseshift", - .description = NULL_IF_CONFIG_SMALL("Apply phase shifting to input audio."), +const FFFilter ff_af_aphaseshift = { + .p.name = "aphaseshift", + .p.description = NULL_IF_CONFIG_SMALL("Apply phase shifting to input audio."), + .p.priv_class = &aphaseshift_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AFreqShift), - .priv_class = &aphaseshift_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_afwtdn.c b/libavfilter/af_afwtdn.c index fb172f26c..12a2c751c 100644 --- a/libavfilter/af_afwtdn.c +++ b/libavfilter/af_afwtdn.c @@ -1301,17 +1301,17 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_afwtdn = { - .name = "afwtdn", - .description = NULL_IF_CONFIG_SMALL("Denoise audio stream using Wavelets."), +const FFFilter ff_af_afwtdn = { + .p.name = "afwtdn", + .p.description = NULL_IF_CONFIG_SMALL("Denoise audio stream using Wavelets."), + .p.priv_class = &afwtdn_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioFWTDNContext), - .priv_class = &afwtdn_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_agate.c b/libavfilter/af_agate.c index 09655b7f8..abac821e8 100644 --- a/libavfilter/af_agate.c +++ b/libavfilter/af_agate.c @@ -228,16 +228,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_agate = { - .name = "agate", - .description = NULL_IF_CONFIG_SMALL("Audio gate."), - .priv_class = &agate_sidechaingate_class, +const FFFilter ff_af_agate = { + .p.name = "agate", + .p.description = NULL_IF_CONFIG_SMALL("Audio gate."), + .p.priv_class = &agate_sidechaingate_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(AudioGateContext), FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; #endif /* CONFIG_AGATE_FILTER */ @@ -328,7 +328,7 @@ static int scquery_formats(const AVFilterContext *ctx, if (ret < 0) return ret; - if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts)) < 0) + if ((ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts)) < 0) return ret; return 0; @@ -378,10 +378,11 @@ static const AVFilterPad sidechaingate_outputs[] = { }, }; -const AVFilter ff_af_sidechaingate = { - .name = "sidechaingate", - .description = NULL_IF_CONFIG_SMALL("Audio sidechain gate."), - .priv_class = &agate_sidechaingate_class, +const FFFilter ff_af_sidechaingate = { + .p.name = "sidechaingate", + .p.description = NULL_IF_CONFIG_SMALL("Audio sidechain gate."), + .p.priv_class = &agate_sidechaingate_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioGateContext), .activate = activate, .uninit = uninit, @@ -389,6 +390,5 @@ const AVFilter ff_af_sidechaingate = { FILTER_OUTPUTS(sidechaingate_outputs), FILTER_QUERY_FUNC2(scquery_formats), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; #endif /* CONFIG_SIDECHAINGATE_FILTER */ diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c index dfeeb34c9..2111a08c5 100644 --- a/libavfilter/af_aiir.c +++ b/libavfilter/af_aiir.c @@ -95,13 +95,13 @@ static int query_formats(const AVFilterContext *ctx, int ret; if (s->response) { - formats = ff_make_format_list(pix_fmts); + formats = ff_make_pixel_format_list(pix_fmts); if ((ret = ff_formats_ref(formats, &cfg_out[1]->formats)) < 0) return ret; } sample_fmts[0] = s->sample_format; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; @@ -1038,7 +1038,7 @@ static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color int font_height; int i; - font = avpriv_cga_font, font_height = 8; + font = avpriv_cga_font_get(), font_height = 8; for (i = 0; txt[i]; i++) { int char_y, mask; @@ -1560,15 +1560,15 @@ static const AVOption aiir_options[] = { AVFILTER_DEFINE_CLASS(aiir); -const AVFilter ff_af_aiir = { - .name = "aiir", - .description = NULL_IF_CONFIG_SMALL("Apply Infinite Impulse Response filter with supplied coefficients."), +const FFFilter ff_af_aiir = { + .p.name = "aiir", + .p.description = NULL_IF_CONFIG_SMALL("Apply Infinite Impulse Response filter with supplied coefficients."), + .p.priv_class = &aiir_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioIIRContext), - .priv_class = &aiir_class, .init = init, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_alimiter.c b/libavfilter/af_alimiter.c index a08616f69..61ea7beb6 100644 --- a/libavfilter/af_alimiter.c +++ b/libavfilter/af_alimiter.c @@ -421,16 +421,16 @@ static const AVFilterPad alimiter_outputs[] = { }, }; -const AVFilter ff_af_alimiter = { - .name = "alimiter", - .description = NULL_IF_CONFIG_SMALL("Audio lookahead limiter."), +const FFFilter ff_af_alimiter = { + .p.name = "alimiter", + .p.description = NULL_IF_CONFIG_SMALL("Audio lookahead limiter."), + .p.priv_class = &alimiter_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(AudioLimiterContext), - .priv_class = &alimiter_class, .init = init, .uninit = uninit, FILTER_INPUTS(alimiter_inputs), FILTER_OUTPUTS(alimiter_outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c index dccbbd841..8c574f7bd 100644 --- a/libavfilter/af_amerge.c +++ b/libavfilter/af_amerge.c @@ -23,6 +23,7 @@ * Audio merging filter */ +#include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" @@ -43,14 +44,27 @@ typedef struct AMergeContext { struct amerge_input { int nb_ch; /**< number of channels for the input */ } *in; + int layout_mode; /**< the method for determining the output channel layout */ } AMergeContext; #define OFFSET(x) offsetof(AMergeContext, x) #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM +enum LayoutModes { + LM_LEGACY, + LM_RESET, + LM_NORMAL, + NB_LAYOUTMODES +}; + static const AVOption amerge_options[] = { { "inputs", "specify the number of inputs", OFFSET(nb_inputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, SWR_CH_MAX, FLAGS }, + { "layout_mode", "method used to determine the output channel layout", OFFSET(layout_mode), + AV_OPT_TYPE_INT, { .i64 = LM_LEGACY }, 0, NB_LAYOUTMODES - 1, FLAGS, .unit = "layout_mode"}, + { "legacy", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = LM_LEGACY }, 0, 0, FLAGS, .unit = "layout_mode" }, + { "reset", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = LM_RESET }, 0, 0, FLAGS, .unit = "layout_mode" }, + { "normal", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = LM_NORMAL }, 0, 0, FLAGS, .unit = "layout_mode" }, { NULL } }; @@ -63,6 +77,8 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->in); } +#define INLAYOUT(ctx, i) (&(ctx)->inputs[i]->incfg.channel_layouts->channel_layouts[0]) + static int query_formats(AVFilterContext *ctx) { static const enum AVSampleFormat packed_sample_fmts[] = { @@ -74,10 +90,11 @@ static int query_formats(AVFilterContext *ctx) AV_SAMPLE_FMT_NONE }; AMergeContext *s = ctx->priv; - AVChannelLayout *inlayout[SWR_CH_MAX] = { NULL }, outlayout = { 0 }; + AVChannelLayout outlayout = { 0 }; uint64_t outmask = 0; AVFilterChannelLayouts *layouts; int i, ret, nb_ch = 0; + int native_layout_routes[SWR_CH_MAX] = { 0 }; for (i = 0; i < s->nb_inputs; i++) { if (!ctx->inputs[i]->incfg.channel_layouts || @@ -86,62 +103,85 @@ static int query_formats(AVFilterContext *ctx) "No channel layout for input %d\n", i + 1); return AVERROR(EAGAIN); } - inlayout[i] = &ctx->inputs[i]->incfg.channel_layouts->channel_layouts[0]; if (ctx->inputs[i]->incfg.channel_layouts->nb_channel_layouts > 1) { char buf[256]; - av_channel_layout_describe(inlayout[i], buf, sizeof(buf)); + av_channel_layout_describe(INLAYOUT(ctx, i), buf, sizeof(buf)); av_log(ctx, AV_LOG_INFO, "Using \"%s\" for input %d\n", buf, i + 1); } - s->in[i].nb_ch = inlayout[i]->nb_channels; - for (int j = 0; j < s->in[i].nb_ch; j++) { - enum AVChannel id = av_channel_layout_channel_from_index(inlayout[i], j); - if (id >= 0 && id < 64) - outmask |= (1ULL << id); - } + s->in[i].nb_ch = INLAYOUT(ctx, i)->nb_channels; nb_ch += s->in[i].nb_ch; } if (nb_ch > SWR_CH_MAX) { av_log(ctx, AV_LOG_ERROR, "Too many channels (max %d)\n", SWR_CH_MAX); return AVERROR(EINVAL); } - if (av_popcount64(outmask) != nb_ch) { - av_log(ctx, AV_LOG_WARNING, - "Input channel layouts overlap: " - "output layout will be determined by the number of distinct input channels\n"); - for (i = 0; i < nb_ch; i++) - s->route[i] = i; - av_channel_layout_default(&outlayout, nb_ch); - if (!KNOWN(&outlayout) && nb_ch) - av_channel_layout_from_mask(&outlayout, 0xFFFFFFFFFFFFFFFFULL >> (64 - nb_ch)); - } else { - int *route[SWR_CH_MAX]; - int c, out_ch_number = 0; - - av_channel_layout_from_mask(&outlayout, outmask); - route[0] = s->route; - for (i = 1; i < s->nb_inputs; i++) - route[i] = route[i - 1] + s->in[i - 1].nb_ch; - for (c = 0; c < 64; c++) - for (i = 0; i < s->nb_inputs; i++) - if (av_channel_layout_index_from_channel(inlayout[i], c) >= 0) - *(route[i]++) = out_ch_number++; - } - if ((ret = ff_set_common_formats_from_list(ctx, packed_sample_fmts)) < 0) + ret = av_channel_layout_custom_init(&outlayout, nb_ch); + if (ret < 0) return ret; + for (int i = 0, ch_idx = 0; i < s->nb_inputs; i++) { + for (int j = 0; j < s->in[i].nb_ch; j++) { + enum AVChannel id = av_channel_layout_channel_from_index(INLAYOUT(ctx, i), j); + if (INLAYOUT(ctx, i)->order == AV_CHANNEL_ORDER_CUSTOM) + outlayout.u.map[ch_idx] = INLAYOUT(ctx, i)->u.map[j]; + else + outlayout.u.map[ch_idx].id = (id == AV_CHAN_NONE ? AV_CHAN_UNKNOWN : id); + if (id >= 0 && id < 64) { + outmask |= (1ULL << id); + native_layout_routes[id] = ch_idx; + } + s->route[ch_idx] = ch_idx; + ch_idx++; + } + } + switch (s->layout_mode) { + case LM_LEGACY: + av_channel_layout_uninit(&outlayout); + if (av_popcount64(outmask) != nb_ch) { + av_log(ctx, AV_LOG_WARNING, + "Input channel layouts overlap: " + "output layout will be determined by the number of distinct input channels\n"); + av_channel_layout_default(&outlayout, nb_ch); + if (!KNOWN(&outlayout) && nb_ch) + av_channel_layout_from_mask(&outlayout, 0xFFFFFFFFFFFFFFFFULL >> (64 - nb_ch)); + } else { + for (int c = 0, ch_idx = 0; c < 64; c++) + if ((1ULL << c) & outmask) + s->route[native_layout_routes[c]] = ch_idx++; + av_channel_layout_from_mask(&outlayout, outmask); + } + break; + case LM_RESET: + av_channel_layout_uninit(&outlayout); + outlayout.order = AV_CHANNEL_ORDER_UNSPEC; + outlayout.nb_channels = nb_ch; + break; + case LM_NORMAL: + ret = av_channel_layout_retype(&outlayout, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL); + if (ret < 0) + goto out; + break; + default: + av_unreachable("Invalid layout_mode"); + } + if ((ret = ff_set_sample_formats_from_list(ctx, packed_sample_fmts)) < 0) + goto out; for (i = 0; i < s->nb_inputs; i++) { layouts = NULL; - if ((ret = ff_add_channel_layout(&layouts, inlayout[i])) < 0) - return ret; + if ((ret = ff_add_channel_layout(&layouts, INLAYOUT(ctx, i))) < 0) + goto out; if ((ret = ff_channel_layouts_ref(layouts, &ctx->inputs[i]->outcfg.channel_layouts)) < 0) - return ret; + goto out; } layouts = NULL; if ((ret = ff_add_channel_layout(&layouts, &outlayout)) < 0) - return ret; + goto out; if ((ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->incfg.channel_layouts)) < 0) - return ret; + goto out; - return ff_set_common_all_samplerates(ctx); + ret = ff_set_common_all_samplerates(ctx); +out: + av_channel_layout_uninit(&outlayout); + return ret; } static int config_output(AVFilterLink *outlink) @@ -337,17 +377,17 @@ static const AVFilterPad amerge_outputs[] = { }, }; -const AVFilter ff_af_amerge = { - .name = "amerge", - .description = NULL_IF_CONFIG_SMALL("Merge two or more audio streams into " +const FFFilter ff_af_amerge = { + .p.name = "amerge", + .p.description = NULL_IF_CONFIG_SMALL("Merge two or more audio streams into " "a single multi-channel stream."), + .p.inputs = NULL, + .p.priv_class = &amerge_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(AMergeContext), .init = init, .uninit = uninit, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(amerge_outputs), FILTER_QUERY_FUNC(query_formats), - .priv_class = &amerge_class, - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c index bc9720092..082d69b97 100644 --- a/libavfilter/af_amix.c +++ b/libavfilter/af_amix.c @@ -616,18 +616,18 @@ static const AVFilterPad avfilter_af_amix_outputs[] = { }, }; -const AVFilter ff_af_amix = { - .name = "amix", - .description = NULL_IF_CONFIG_SMALL("Audio mixing."), +const FFFilter ff_af_amix = { + .p.name = "amix", + .p.description = NULL_IF_CONFIG_SMALL("Audio mixing."), + .p.priv_class = &amix_class, + .p.inputs = NULL, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(MixContext), - .priv_class = &amix_class, .init = init, .uninit = uninit, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(avfilter_af_amix_outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_amultiply.c b/libavfilter/af_amultiply.c index 5090098c1..6b6d3e0a5 100644 --- a/libavfilter/af_amultiply.c +++ b/libavfilter/af_amultiply.c @@ -169,9 +169,9 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_amultiply = { - .name = "amultiply", - .description = NULL_IF_CONFIG_SMALL("Multiply two audio streams."), +const FFFilter ff_af_amultiply = { + .p.name = "amultiply", + .p.description = NULL_IF_CONFIG_SMALL("Multiply two audio streams."), .priv_size = sizeof(AudioMultiplyContext), .init = init, .uninit = uninit, diff --git a/libavfilter/af_anequalizer.c b/libavfilter/af_anequalizer.c index 26e9c3cdd..2f39e94cc 100644 --- a/libavfilter/af_anequalizer.c +++ b/libavfilter/af_anequalizer.c @@ -230,12 +230,12 @@ static int query_formats(const AVFilterContext *ctx, int ret; if (s->draw_curves) { - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, pix_fmts); + ret = ff_set_pixel_formats_from_list2(ctx, cfg_in, cfg_out, pix_fmts); if (ret < 0) return ret; } - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; @@ -752,18 +752,18 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_anequalizer = { - .name = "anequalizer", - .description = NULL_IF_CONFIG_SMALL("Apply high-order audio parametric multi band equalizer."), +const FFFilter ff_af_anequalizer = { + .p.name = "anequalizer", + .p.description = NULL_IF_CONFIG_SMALL("Apply high-order audio parametric multi band equalizer."), + .p.priv_class = &anequalizer_class, + .p.outputs = NULL, + .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioNEqualizerContext), - .priv_class = &anequalizer_class, .init = init, .uninit = uninit, FILTER_INPUTS(inputs), - .outputs = NULL, FILTER_QUERY_FUNC2(query_formats), .process_command = process_command, - .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | - AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_anlmdn.c b/libavfilter/af_anlmdn.c index f8e4f92c4..ce91eb1cf 100644 --- a/libavfilter/af_anlmdn.c +++ b/libavfilter/af_anlmdn.c @@ -116,7 +116,7 @@ void ff_anlmdn_init(AudioNLMDNDSPContext *dsp) dsp->compute_distance_ssd = compute_distance_ssd_c; dsp->compute_cache = compute_cache_c; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_anlmdn_init_x86(dsp); #endif } @@ -349,17 +349,17 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_anlmdn = { - .name = "anlmdn", - .description = NULL_IF_CONFIG_SMALL("Reduce broadband noise from stream using Non-Local Means."), +const FFFilter ff_af_anlmdn = { + .p.name = "anlmdn", + .p.description = NULL_IF_CONFIG_SMALL("Reduce broadband noise from stream using Non-Local Means."), + .p.priv_class = &anlmdn_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioNLMeansContext), - .priv_class = &anlmdn_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_anlms.c b/libavfilter/af_anlms.c index 4e83a0501..3ac20bcc7 100644 --- a/libavfilter/af_anlms.c +++ b/libavfilter/af_anlms.c @@ -99,7 +99,7 @@ static int query_formats(const AVFilterContext *ctx, }; int ret; - if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, + if ((ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts[s->precision])) < 0) return ret; @@ -251,34 +251,34 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_anlms = { - .name = "anlms", - .description = NULL_IF_CONFIG_SMALL("Apply Normalized Least-Mean-Squares algorithm to first audio stream."), +const FFFilter ff_af_anlms = { + .p.name = "anlms", + .p.description = NULL_IF_CONFIG_SMALL("Apply Normalized Least-Mean-Squares algorithm to first audio stream."), + .p.priv_class = &anlms_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioNLMSContext), - .priv_class = &anlms_class, .init = init, .uninit = uninit, .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = ff_filter_process_command, }; -const AVFilter ff_af_anlmf = { - .name = "anlmf", - .description = NULL_IF_CONFIG_SMALL("Apply Normalized Least-Mean-Fourth algorithm to first audio stream."), +const FFFilter ff_af_anlmf = { + .p.name = "anlmf", + .p.description = NULL_IF_CONFIG_SMALL("Apply Normalized Least-Mean-Fourth algorithm to first audio stream."), + .p.priv_class = &anlms_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioNLMSContext), - .priv_class = &anlms_class, .init = init, .uninit = uninit, .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_anull.c b/libavfilter/af_anull.c index d7645fd0e..6df598261 100644 --- a/libavfilter/af_anull.c +++ b/libavfilter/af_anull.c @@ -27,10 +27,10 @@ #include "filters.h" #include "libavutil/internal.h" -const AVFilter ff_af_anull = { - .name = "anull", - .description = NULL_IF_CONFIG_SMALL("Pass the source unchanged to the output."), - .flags = AVFILTER_FLAG_METADATA_ONLY, +const FFFilter ff_af_anull = { + .p.name = "anull", + .p.description = NULL_IF_CONFIG_SMALL("Pass the source unchanged to the output."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(ff_audio_default_filterpad), }; diff --git a/libavfilter/af_apad.c b/libavfilter/af_apad.c index 6cdfd1597..cc214f7cc 100644 --- a/libavfilter/af_apad.c +++ b/libavfilter/af_apad.c @@ -194,14 +194,14 @@ static const AVFilterPad apad_outputs[] = { }, }; -const AVFilter ff_af_apad = { - .name = "apad", - .description = NULL_IF_CONFIG_SMALL("Pad audio with silence."), +const FFFilter ff_af_apad = { + .p.name = "apad", + .p.description = NULL_IF_CONFIG_SMALL("Pad audio with silence."), + .p.priv_class = &apad_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .init = init, .activate = activate, .priv_size = sizeof(APadContext), FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(apad_outputs), - .priv_class = &apad_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_aphaser.c b/libavfilter/af_aphaser.c index b070f4d2a..8d7f62482 100644 --- a/libavfilter/af_aphaser.c +++ b/libavfilter/af_aphaser.c @@ -256,9 +256,10 @@ static const AVFilterPad aphaser_outputs[] = { }, }; -const AVFilter ff_af_aphaser = { - .name = "aphaser", - .description = NULL_IF_CONFIG_SMALL("Add a phasing effect to the audio."), +const FFFilter ff_af_aphaser = { + .p.name = "aphaser", + .p.description = NULL_IF_CONFIG_SMALL("Add a phasing effect to the audio."), + .p.priv_class = &aphaser_class, .priv_size = sizeof(AudioPhaserContext), .init = init, .uninit = uninit, @@ -268,5 +269,4 @@ const AVFilter ff_af_aphaser = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P), - .priv_class = &aphaser_class, }; diff --git a/libavfilter/af_apsyclip.c b/libavfilter/af_apsyclip.c index 5afc3930c..35ef2cef1 100644 --- a/libavfilter/af_apsyclip.c +++ b/libavfilter/af_apsyclip.c @@ -637,17 +637,17 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_apsyclip = { - .name = "apsyclip", - .description = NULL_IF_CONFIG_SMALL("Audio Psychoacoustic Clipper."), +const FFFilter ff_af_apsyclip = { + .p.name = "apsyclip", + .p.description = NULL_IF_CONFIG_SMALL("Audio Psychoacoustic Clipper."), + .p.priv_class = &apsyclip_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioPsyClipContext), - .priv_class = &apsyclip_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .activate = activate, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_apulsator.c b/libavfilter/af_apulsator.c index 4272e5f3a..bf462df12 100644 --- a/libavfilter/af_apulsator.c +++ b/libavfilter/af_apulsator.c @@ -200,7 +200,7 @@ static int query_formats(const AVFilterContext *ctx, int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret < 0) return ret; @@ -249,11 +249,11 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_apulsator = { - .name = "apulsator", - .description = NULL_IF_CONFIG_SMALL("Audio pulsator."), +const FFFilter ff_af_apulsator = { + .p.name = "apulsator", + .p.description = NULL_IF_CONFIG_SMALL("Audio pulsator."), + .p.priv_class = &apulsator_class, .priv_size = sizeof(AudioPulsatorContext), - .priv_class = &apulsator_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c index d6de07404..7c6f9141a 100644 --- a/libavfilter/af_aresample.c +++ b/libavfilter/af_aresample.c @@ -26,6 +26,7 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/downmix_info.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "libavutil/avassert.h" @@ -42,7 +43,6 @@ typedef struct AResampleContext { struct SwrContext *swr; int64_t next_pts; int more_data; - int eof; } AResampleContext; static av_cold int preinit(AVFilterContext *ctx) @@ -105,8 +105,8 @@ static int query_formats(const AVFilterContext *ctx, return ret; if(out_format != AV_SAMPLE_FMT_NONE) { - int formatlist[] = { out_format, -1 }; - out_formats = ff_make_format_list(formatlist); + enum AVSampleFormat formatlist[] = { out_format, AV_SAMPLE_FMT_NONE }; + out_formats = ff_make_sample_format_list(formatlist); } else out_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO); if ((ret = ff_formats_ref(out_formats, &cfg_out[0]->formats)) < 0) @@ -123,6 +123,7 @@ static int query_formats(const AVFilterContext *ctx, return ff_channel_layouts_ref(out_layouts, &cfg_out[0]->channel_layouts); } +#define SWR_CH_MAX 64 static int config_output(AVFilterLink *outlink) { @@ -132,6 +133,7 @@ static int config_output(AVFilterLink *outlink) AResampleContext *aresample = ctx->priv; AVChannelLayout out_layout = { 0 }; int64_t out_rate; + const AVFrameSideData *sd; enum AVSampleFormat out_format; char inchl_buf[128], outchl_buf[128]; @@ -142,6 +144,44 @@ static int config_output(AVFilterLink *outlink) if (ret < 0) return ret; + sd = av_frame_side_data_get(inlink->side_data, inlink->nb_side_data, + AV_FRAME_DATA_DOWNMIX_INFO); + if (sd) { + const AVDownmixInfo *di = (AVDownmixInfo *)sd->data; + enum AVMatrixEncoding matrix_encoding = AV_MATRIX_ENCODING_NONE; + double center_mix_level, surround_mix_level; + + switch (di->preferred_downmix_type) { + case AV_DOWNMIX_TYPE_LTRT: + matrix_encoding = AV_MATRIX_ENCODING_DOLBY; + center_mix_level = di->center_mix_level_ltrt; + surround_mix_level = di->surround_mix_level_ltrt; + break; + case AV_DOWNMIX_TYPE_DPLII: + matrix_encoding = AV_MATRIX_ENCODING_DPLII; + center_mix_level = di->center_mix_level_ltrt; + surround_mix_level = di->surround_mix_level_ltrt; + break; + default: + center_mix_level = di->center_mix_level; + surround_mix_level = di->surround_mix_level; + break; + } + + av_log(ctx, AV_LOG_VERBOSE, "Mix levels: center %f - " + "surround %f - lfe %f.\n", + center_mix_level, surround_mix_level, di->lfe_mix_level); + + av_opt_set_double(aresample->swr, "clev", center_mix_level, 0); + av_opt_set_double(aresample->swr, "slev", surround_mix_level, 0); + av_opt_set_double(aresample->swr, "lfe_mix_level", di->lfe_mix_level, 0); + av_opt_set_int(aresample->swr, "matrix_encoding", matrix_encoding, 0); + + if (av_channel_layout_compare(&outlink->ch_layout, &out_layout)) + av_frame_side_data_remove(&outlink->side_data, &outlink->nb_side_data, + AV_FRAME_DATA_DOWNMIX_INFO); + } + ret = swr_init(aresample->swr); if (ret < 0) return ret; @@ -168,7 +208,7 @@ static int config_output(AVFilterLink *outlink) return 0; } -static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref) +static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref, AVFrame **outsamplesref_ret) { AVFilterContext *ctx = inlink->dst; AResampleContext *aresample = ctx->priv; @@ -179,27 +219,28 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref) AVFrame *outsamplesref; int ret; + *outsamplesref_ret = NULL; delay = swr_get_delay(aresample->swr, outlink->sample_rate); if (delay > 0) n_out += FFMIN(delay, FFMAX(4096, n_out)); outsamplesref = ff_get_audio_buffer(outlink, n_out); - - if(!outsamplesref) { - av_frame_free(&insamplesref); + if (!outsamplesref) return AVERROR(ENOMEM); - } av_frame_copy_props(outsamplesref, insamplesref); outsamplesref->format = outlink->format; ret = av_channel_layout_copy(&outsamplesref->ch_layout, &outlink->ch_layout); if (ret < 0) { av_frame_free(&outsamplesref); - av_frame_free(&insamplesref); return ret; } outsamplesref->sample_rate = outlink->sample_rate; + if (av_channel_layout_compare(&outsamplesref->ch_layout, &insamplesref->ch_layout)) + av_frame_side_data_remove_by_props(&outsamplesref->side_data, &outsamplesref->nb_side_data, + AV_SIDE_DATA_PROP_CHANNEL_DEPENDENT); + if(insamplesref->pts != AV_NOPTS_VALUE) { int64_t inpts = av_rescale(insamplesref->pts, inlink->time_base.num * (int64_t)outlink->sample_rate * inlink->sample_rate, inlink->time_base.den); int64_t outpts= swr_next_pts(aresample->swr, inpts); @@ -212,8 +253,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref) (void *)insamplesref->extended_data, n_in); if (n_out <= 0) { av_frame_free(&outsamplesref); - av_frame_free(&insamplesref); - ff_inlink_request_frame(inlink); return 0; } @@ -221,9 +260,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref) outsamplesref->nb_samples = n_out; - ret = ff_filter_frame(outlink, outsamplesref); - av_frame_free(&insamplesref); - return ret; + *outsamplesref_ret = outsamplesref; + return 1; } static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref_ret) @@ -246,7 +284,7 @@ static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out, final ? NULL : (void*)outsamplesref->extended_data, 0); if (n_out <= 0) { av_frame_free(&outsamplesref); - return (n_out == 0) ? AVERROR_EOF : n_out; + return n_out; } outsamplesref->sample_rate = outlink->sample_rate; @@ -254,73 +292,63 @@ static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref outsamplesref->pts = pts; - return 0; + return 1; } -static int request_frame(AVFilterLink *outlink) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; AResampleContext *aresample = ctx->priv; + AVFrame *frame; int ret = 0, status; int64_t pts; + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + // First try to get data from the internal buffers if (aresample->more_data) { AVFrame *outsamplesref; - if (flush_frame(outlink, 0, &outsamplesref) >= 0) { - return ff_filter_frame(outlink, outsamplesref); - } - } - aresample->more_data = 0; - - if (!aresample->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) - aresample->eof = 1; - - // Second request more data from the input - if (!aresample->eof) - FF_FILTER_FORWARD_WANTED(outlink, inlink); - - // Third if we hit the end flush - if (aresample->eof) { - AVFrame *outsamplesref; - - if ((ret = flush_frame(outlink, 1, &outsamplesref)) < 0) { - if (ret == AVERROR_EOF) { - ff_outlink_set_status(outlink, AVERROR_EOF, aresample->next_pts); - return 0; - } - return ret; - } - - return ff_filter_frame(outlink, outsamplesref); - } - - ff_filter_set_ready(ctx, 100); - return 0; -} - -static int activate(AVFilterContext *ctx) -{ - AResampleContext *aresample = ctx->priv; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; - - FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); - - if (!aresample->eof && ff_inlink_queued_frames(inlink)) { - AVFrame *frame = NULL; - int ret; - - ret = ff_inlink_consume_frame(inlink, &frame); + ret = flush_frame(outlink, 0, &outsamplesref); if (ret < 0) return ret; if (ret > 0) - return filter_frame(inlink, frame); + return ff_filter_frame(outlink, outsamplesref); + } + aresample->more_data = 0; + + // Then consume frames from inlink + while ((ret = ff_inlink_consume_frame(inlink, &frame))) { + AVFrame *outsamplesref; + if (ret < 0) + return ret; + + ret = filter_frame(inlink, frame, &outsamplesref); + av_frame_free(&frame); + if (ret < 0) + return ret; + if (ret > 0) + return ff_filter_frame(outlink, outsamplesref); } - return request_frame(outlink); + // If we hit the end flush + if (ff_inlink_acknowledge_status(inlink, &status, &pts)) { + AVFrame *outsamplesref; + + ret = flush_frame(outlink, 1, &outsamplesref); + if (ret < 0) + return ret; + if (ret > 0) + return ff_filter_frame(outlink, outsamplesref); + ff_outlink_set_status(outlink, status, aresample->next_pts); + return 0; + } + + // If not, request more data from the input + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; } static const AVClass *resample_child_class_iterate(void **iter) @@ -361,14 +389,14 @@ static const AVFilterPad aresample_outputs[] = { }, }; -const AVFilter ff_af_aresample = { - .name = "aresample", - .description = NULL_IF_CONFIG_SMALL("Resample audio data."), +const FFFilter ff_af_aresample = { + .p.name = "aresample", + .p.description = NULL_IF_CONFIG_SMALL("Resample audio data."), + .p.priv_class = &aresample_class, .preinit = preinit, .activate = activate, .uninit = uninit, .priv_size = sizeof(AResampleContext), - .priv_class = &aresample_class, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(aresample_outputs), FILTER_QUERY_FUNC2(query_formats), diff --git a/libavfilter/af_arls.c b/libavfilter/af_arls.c index 3f182454e..da000f181 100644 --- a/libavfilter/af_arls.c +++ b/libavfilter/af_arls.c @@ -96,7 +96,7 @@ static int query_formats(const AVFilterContext *ctx, }; int ret; - if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, + if ((ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts[s->precision])) < 0) return ret; @@ -281,18 +281,18 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_arls = { - .name = "arls", - .description = NULL_IF_CONFIG_SMALL("Apply Recursive Least Squares algorithm to first audio stream."), +const FFFilter ff_af_arls = { + .p.name = "arls", + .p.description = NULL_IF_CONFIG_SMALL("Apply Recursive Least Squares algorithm to first audio stream."), + .p.priv_class = &arls_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioRLSContext), - .priv_class = &arls_class, .init = init, .uninit = uninit, .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_arnndn.c b/libavfilter/af_arnndn.c index 3c2ae6370..23eeb1785 100644 --- a/libavfilter/af_arnndn.c +++ b/libavfilter/af_arnndn.c @@ -337,7 +337,7 @@ static int query_formats(const AVFilterContext *ctx, }; int ret, sample_rates[] = { 48000, -1 }; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; @@ -361,9 +361,9 @@ static int config_input(AVFilterLink *inlink) DenoiseState *st = &s->st[i]; st->rnn[0].model = s->model[0]; - st->rnn[0].vad_gru_state = av_calloc(sizeof(float), FFALIGN(s->model[0]->vad_gru_size, 16)); - st->rnn[0].noise_gru_state = av_calloc(sizeof(float), FFALIGN(s->model[0]->noise_gru_size, 16)); - st->rnn[0].denoise_gru_state = av_calloc(sizeof(float), FFALIGN(s->model[0]->denoise_gru_size, 16)); + st->rnn[0].vad_gru_state = av_calloc(FFALIGN(s->model[0]->vad_gru_size, 16), sizeof(float)); + st->rnn[0].noise_gru_state = av_calloc(FFALIGN(s->model[0]->noise_gru_size, 16), sizeof(float)); + st->rnn[0].denoise_gru_state = av_calloc(FFALIGN(s->model[0]->denoise_gru_size, 16), sizeof(float)); if (!st->rnn[0].vad_gru_state || !st->rnn[0].noise_gru_state || !st->rnn[0].denoise_gru_state) @@ -1596,18 +1596,18 @@ static const AVOption arnndn_options[] = { AVFILTER_DEFINE_CLASS(arnndn); -const AVFilter ff_af_arnndn = { - .name = "arnndn", - .description = NULL_IF_CONFIG_SMALL("Reduce noise from speech using Recurrent Neural Networks."), +const FFFilter ff_af_arnndn = { + .p.name = "arnndn", + .p.description = NULL_IF_CONFIG_SMALL("Reduce noise from speech using Recurrent Neural Networks."), + .p.priv_class = &arnndn_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioRNNContext), - .priv_class = &arnndn_class, .activate = activate, .init = init, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = process_command, }; diff --git a/libavfilter/af_asdr.c b/libavfilter/af_asdr.c index 7765690fd..ea7494017 100644 --- a/libavfilter/af_asdr.c +++ b/libavfilter/af_asdr.c @@ -266,45 +266,45 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_asdr = { - .name = "asdr", - .description = NULL_IF_CONFIG_SMALL("Measure Audio Signal-to-Distortion Ratio."), +const FFFilter ff_af_asdr = { + .p.name = "asdr", + .p.description = NULL_IF_CONFIG_SMALL("Measure Audio Signal-to-Distortion Ratio."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY | + AVFILTER_FLAG_SLICE_THREADS | + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioSDRContext), .activate = activate, .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY | - AVFILTER_FLAG_SLICE_THREADS | - AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), }; -const AVFilter ff_af_apsnr = { - .name = "apsnr", - .description = NULL_IF_CONFIG_SMALL("Measure Audio Peak Signal-to-Noise Ratio."), +const FFFilter ff_af_apsnr = { + .p.name = "apsnr", + .p.description = NULL_IF_CONFIG_SMALL("Measure Audio Peak Signal-to-Noise Ratio."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY | + AVFILTER_FLAG_SLICE_THREADS | + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioSDRContext), .activate = activate, .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY | - AVFILTER_FLAG_SLICE_THREADS | - AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), }; -const AVFilter ff_af_asisdr = { - .name = "asisdr", - .description = NULL_IF_CONFIG_SMALL("Measure Audio Scale-Invariant Signal-to-Distortion Ratio."), +const FFFilter ff_af_asisdr = { + .p.name = "asisdr", + .p.description = NULL_IF_CONFIG_SMALL("Measure Audio Scale-Invariant Signal-to-Distortion Ratio."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY | + AVFILTER_FLAG_SLICE_THREADS | + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioSDRContext), .activate = activate, .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY | - AVFILTER_FLAG_SLICE_THREADS | - AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c index 3d2d99dae..137fab940 100644 --- a/libavfilter/af_asetnsamples.c +++ b/libavfilter/af_asetnsamples.c @@ -102,14 +102,14 @@ static int activate(AVFilterContext *ctx) return FFERROR_NOT_READY; } -const AVFilter ff_af_asetnsamples = { - .name = "asetnsamples", - .description = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."), +const FFFilter ff_af_asetnsamples = { + .p.name = "asetnsamples", + .p.description = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."), + .p.priv_class = &asetnsamples_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(ASNSContext), - .priv_class = &asetnsamples_class, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(ff_audio_default_filterpad), .activate = activate, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_asetrate.c b/libavfilter/af_asetrate.c index 061edebdf..9cf4cb806 100644 --- a/libavfilter/af_asetrate.c +++ b/libavfilter/af_asetrate.c @@ -111,14 +111,14 @@ static const AVFilterPad asetrate_outputs[] = { }, }; -const AVFilter ff_af_asetrate = { - .name = "asetrate", - .description = NULL_IF_CONFIG_SMALL("Change the sample rate without " +const FFFilter ff_af_asetrate = { + .p.name = "asetrate", + .p.description = NULL_IF_CONFIG_SMALL("Change the sample rate without " "altering the data."), + .p.priv_class = &asetrate_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(ASetRateContext), FILTER_INPUTS(asetrate_inputs), FILTER_OUTPUTS(asetrate_outputs), FILTER_QUERY_FUNC2(query_formats), - .priv_class = &asetrate_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, }; diff --git a/libavfilter/af_ashowinfo.c b/libavfilter/af_ashowinfo.c index b83847b86..ebcd5c996 100644 --- a/libavfilter/af_ashowinfo.c +++ b/libavfilter/af_ashowinfo.c @@ -120,7 +120,7 @@ static void print_peak(AVFilterContext *ctx, const char *str, uint32_t peak) if (!peak) av_log(ctx, AV_LOG_INFO, "unknown"); else - av_log(ctx, AV_LOG_INFO, "%f", (float)peak / UINT32_MAX); + av_log(ctx, AV_LOG_INFO, "%f", peak / 100000.0f); av_log(ctx, AV_LOG_INFO, ", "); } @@ -168,7 +168,7 @@ static void dump_audio_service_type(AVFilterContext *ctx, AVFrameSideData *sd) static void dump_unknown(AVFilterContext *ctx, AVFrameSideData *sd) { av_log(ctx, AV_LOG_INFO, "unknown side data type: %d, size " - "%"SIZE_SPECIFIER" bytes", sd->type, sd->size); + "%zu bytes", sd->type, sd->size); } static int filter_frame(AVFilterLink *inlink, AVFrame *buf) @@ -241,12 +241,12 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_ashowinfo = { - .name = "ashowinfo", - .description = NULL_IF_CONFIG_SMALL("Show textual information for each audio frame."), +const FFFilter ff_af_ashowinfo = { + .p.name = "ashowinfo", + .p.description = NULL_IF_CONFIG_SMALL("Show textual information for each audio frame."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(AShowInfoContext), .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), }; diff --git a/libavfilter/af_asoftclip.c b/libavfilter/af_asoftclip.c index 232ed05c0..19923f2c3 100644 --- a/libavfilter/af_asoftclip.c +++ b/libavfilter/af_asoftclip.c @@ -473,16 +473,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_asoftclip = { - .name = "asoftclip", - .description = NULL_IF_CONFIG_SMALL("Audio Soft Clipper."), +const FFFilter ff_af_asoftclip = { + .p.name = "asoftclip", + .p.description = NULL_IF_CONFIG_SMALL("Audio Soft Clipper."), + .p.priv_class = &asoftclip_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASoftClipContext), - .priv_class = &asoftclip_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), .uninit = uninit, .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_aspectralstats.c b/libavfilter/af_aspectralstats.c index ca7939551..ac7da748e 100644 --- a/libavfilter/af_aspectralstats.c +++ b/libavfilter/af_aspectralstats.c @@ -608,15 +608,15 @@ static const AVFilterPad aspectralstats_outputs[] = { }, }; -const AVFilter ff_af_aspectralstats = { - .name = "aspectralstats", - .description = NULL_IF_CONFIG_SMALL("Show frequency domain statistics about audio frames."), +const FFFilter ff_af_aspectralstats = { + .p.name = "aspectralstats", + .p.description = NULL_IF_CONFIG_SMALL("Show frequency domain statistics about audio frames."), + .p.priv_class = &aspectralstats_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioSpectralStatsContext), - .priv_class = &aspectralstats_class, .uninit = uninit, .activate = activate, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(aspectralstats_outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), - .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_asr.c b/libavfilter/af_asr.c index 8e8eeb19a..f596e82a3 100644 --- a/libavfilter/af_asr.c +++ b/libavfilter/af_asr.c @@ -139,7 +139,7 @@ static int query_formats(const AVFilterContext *ctx, int sample_rates[] = { s->rate, -1 }; int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret < 0) return ret; @@ -173,14 +173,14 @@ static const AVFilterPad asr_inputs[] = { }, }; -const AVFilter ff_af_asr = { - .name = "asr", - .description = NULL_IF_CONFIG_SMALL("Automatic Speech Recognition."), +const FFFilter ff_af_asr = { + .p.name = "asr", + .p.description = NULL_IF_CONFIG_SMALL("Automatic Speech Recognition."), + .p.priv_class = &asr_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(ASRContext), - .priv_class = &asr_class, .init = asr_init, .uninit = asr_uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(asr_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), diff --git a/libavfilter/af_astats.c b/libavfilter/af_astats.c index 62ebc3f83..6ef69ff10 100644 --- a/libavfilter/af_astats.c +++ b/libavfilter/af_astats.c @@ -210,7 +210,7 @@ static int config_output(AVFilterLink *outlink) { AudioStatsContext *s = outlink->src->priv; - s->chstats = av_calloc(sizeof(*s->chstats), outlink->ch_layout.nb_channels); + s->chstats = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->chstats)); if (!s->chstats) return AVERROR(ENOMEM); @@ -836,7 +836,7 @@ static void print_stats(AVFilterContext *ctx) av_log(ctx, AV_LOG_INFO, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(p->max_sigma_x2))); if (s->measure_perchannel & MEASURE_RMS_TROUGH) if (p->min_sigma_x2 != 1) - av_log(ctx, AV_LOG_INFO, "RMS trough dB: %f\n",LINEAR_TO_DB(sqrt(p->min_sigma_x2))); + av_log(ctx, AV_LOG_INFO, "RMS through dB: %f\n",LINEAR_TO_DB(sqrt(p->min_sigma_x2))); if (s->measure_perchannel & MEASURE_CREST_FACTOR) av_log(ctx, AV_LOG_INFO, "Crest factor: %f\n", p->sigma_x2 ? FFMAX(-p->nmin, p->nmax) / sqrt(p->sigma_x2 / p->nb_samples) : 1); if (s->measure_perchannel & MEASURE_FLAT_FACTOR) @@ -896,7 +896,7 @@ static void print_stats(AVFilterContext *ctx) av_log(ctx, AV_LOG_INFO, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(max_sigma_x2))); if (s->measure_overall & MEASURE_RMS_TROUGH) if (min_sigma_x2 != 1) - av_log(ctx, AV_LOG_INFO, "RMS trough dB: %f\n", LINEAR_TO_DB(sqrt(min_sigma_x2))); + av_log(ctx, AV_LOG_INFO, "RMS through dB: %f\n", LINEAR_TO_DB(sqrt(min_sigma_x2))); if (s->measure_overall & MEASURE_FLAT_FACTOR) av_log(ctx, AV_LOG_INFO, "Flat factor: %f\n", LINEAR_TO_DB((min_runs + max_runs) / (min_count + max_count))); if (s->measure_overall & MEASURE_PEAK_COUNT) @@ -956,11 +956,12 @@ static const AVFilterPad astats_outputs[] = { }, }; -const AVFilter ff_af_astats = { - .name = "astats", - .description = NULL_IF_CONFIG_SMALL("Show time domain statistics about audio frames."), +const FFFilter ff_af_astats = { + .p.name = "astats", + .p.description = NULL_IF_CONFIG_SMALL("Show time domain statistics about audio frames."), + .p.priv_class = &astats_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(AudioStatsContext), - .priv_class = &astats_class, .uninit = uninit, FILTER_INPUTS(astats_inputs), FILTER_OUTPUTS(astats_outputs), @@ -969,5 +970,4 @@ const AVFilter ff_af_astats = { AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_METADATA_ONLY, }; diff --git a/libavfilter/af_asubboost.c b/libavfilter/af_asubboost.c index 5698f5028..58135626b 100644 --- a/libavfilter/af_asubboost.c +++ b/libavfilter/af_asubboost.c @@ -238,16 +238,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_asubboost = { - .name = "asubboost", - .description = NULL_IF_CONFIG_SMALL("Boost subwoofer frequencies."), +const FFFilter ff_af_asubboost = { + .p.name = "asubboost", + .p.description = NULL_IF_CONFIG_SMALL("Boost subwoofer frequencies."), + .p.priv_class = &asubboost_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASubBoostContext), - .priv_class = &asubboost_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_asupercut.c b/libavfilter/af_asupercut.c index 76e9d4b96..3e032d74b 100644 --- a/libavfilter/af_asupercut.c +++ b/libavfilter/af_asupercut.c @@ -333,18 +333,18 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_asupercut = { - .name = "asupercut", - .description = NULL_IF_CONFIG_SMALL("Cut super frequencies."), +const FFFilter ff_af_asupercut = { + .p.name = "asupercut", + .p.description = NULL_IF_CONFIG_SMALL("Cut super frequencies."), + .p.priv_class = &asupercut_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASuperCutContext), - .priv_class = &asupercut_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; static const AVOption asubcut_options[] = { @@ -356,18 +356,18 @@ static const AVOption asubcut_options[] = { AVFILTER_DEFINE_CLASS(asubcut); -const AVFilter ff_af_asubcut = { - .name = "asubcut", - .description = NULL_IF_CONFIG_SMALL("Cut subwoofer frequencies."), +const FFFilter ff_af_asubcut = { + .p.name = "asubcut", + .p.description = NULL_IF_CONFIG_SMALL("Cut subwoofer frequencies."), + .p.priv_class = &asubcut_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASuperCutContext), - .priv_class = &asubcut_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; static const AVOption asuperpass_asuperstop_options[] = { @@ -381,30 +381,30 @@ static const AVOption asuperpass_asuperstop_options[] = { AVFILTER_DEFINE_CLASS_EXT(asuperpass_asuperstop, "asuperpass/asuperstop", asuperpass_asuperstop_options); -const AVFilter ff_af_asuperpass = { - .name = "asuperpass", - .description = NULL_IF_CONFIG_SMALL("Apply high order Butterworth band-pass filter."), - .priv_class = &asuperpass_asuperstop_class, +const FFFilter ff_af_asuperpass = { + .p.name = "asuperpass", + .p.description = NULL_IF_CONFIG_SMALL("Apply high order Butterworth band-pass filter."), + .p.priv_class = &asuperpass_asuperstop_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASuperCutContext), .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; -const AVFilter ff_af_asuperstop = { - .name = "asuperstop", - .description = NULL_IF_CONFIG_SMALL("Apply high order Butterworth band-stop filter."), - .priv_class = &asuperpass_asuperstop_class, +const FFFilter ff_af_asuperstop = { + .p.name = "asuperstop", + .p.description = NULL_IF_CONFIG_SMALL("Apply high order Butterworth band-stop filter."), + .p.priv_class = &asuperpass_asuperstop_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASuperCutContext), .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_atempo.c b/libavfilter/af_atempo.c index 3b03caa4d..768840d99 100644 --- a/libavfilter/af_atempo.c +++ b/libavfilter/af_atempo.c @@ -112,7 +112,7 @@ typedef struct ATempoContext { // number of channels: int channels; - // row of bytes to skip from one sample to next, across multple channels; + // row of bytes to skip from one sample to next, across multiple channels; // stride = (number-of-channels * bits-per-sample-per-channel) / 8 int stride; @@ -1176,14 +1176,14 @@ static const AVFilterPad atempo_outputs[] = { }, }; -const AVFilter ff_af_atempo = { - .name = "atempo", - .description = NULL_IF_CONFIG_SMALL("Adjust audio tempo."), +const FFFilter ff_af_atempo = { + .p.name = "atempo", + .p.description = NULL_IF_CONFIG_SMALL("Adjust audio tempo."), + .p.priv_class = &atempo_class, .init = init, .uninit = uninit, .process_command = process_command, .priv_size = sizeof(ATempoContext), - .priv_class = &atempo_class, FILTER_INPUTS(atempo_inputs), FILTER_OUTPUTS(atempo_outputs), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), diff --git a/libavfilter/af_atilt.c b/libavfilter/af_atilt.c index c8f4ba1e9..b2cdef8fb 100644 --- a/libavfilter/af_atilt.c +++ b/libavfilter/af_atilt.c @@ -246,16 +246,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_atilt = { - .name = "atilt", - .description = NULL_IF_CONFIG_SMALL("Apply spectral tilt to audio."), +const FFFilter ff_af_atilt = { + .p.name = "atilt", + .p.description = NULL_IF_CONFIG_SMALL("Apply spectral tilt to audio."), + .p.priv_class = &atilt_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ATiltContext), - .priv_class = &atilt_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_axcorrelate.c b/libavfilter/af_axcorrelate.c index b887c07bf..eb61536c4 100644 --- a/libavfilter/af_axcorrelate.c +++ b/libavfilter/af_axcorrelate.c @@ -454,11 +454,11 @@ static const AVOption axcorrelate_options[] = { AVFILTER_DEFINE_CLASS(axcorrelate); -const AVFilter ff_af_axcorrelate = { - .name = "axcorrelate", - .description = NULL_IF_CONFIG_SMALL("Cross-correlate two audio streams."), +const FFFilter ff_af_axcorrelate = { + .p.name = "axcorrelate", + .p.description = NULL_IF_CONFIG_SMALL("Cross-correlate two audio streams."), + .p.priv_class = &axcorrelate_class, .priv_size = sizeof(AudioXCorrelateContext), - .priv_class = &axcorrelate_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c index dc7f19d7e..565da3039 100644 --- a/libavfilter/af_biquads.c +++ b/libavfilter/af_biquads.c @@ -190,7 +190,7 @@ static int query_formats(const AVFilterContext *ctx, sample_fmts_list = auto_sample_fmts; break; } - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts_list); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts_list); if (ret < 0) return ret; @@ -1453,10 +1453,12 @@ static av_cold int name_##_init(AVFilterContext *ctx) \ return 0; \ } \ \ -const AVFilter ff_af_##name_ = { \ - .name = #name_, \ - .description = NULL_IF_CONFIG_SMALL(description_), \ - .priv_class = &priv_class_##_class, \ +const FFFilter ff_af_##name_ = { \ + .p.name = #name_, \ + .p.description = NULL_IF_CONFIG_SMALL(description_), \ + .p.priv_class = &priv_class_##_class, \ + .p.flags = AVFILTER_FLAG_SLICE_THREADS | \ + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, \ .priv_size = sizeof(BiquadsContext), \ .init = name_##_init, \ .activate = activate, \ @@ -1465,7 +1467,6 @@ const AVFilter ff_af_##name_ = { \ FILTER_OUTPUTS(outputs), \ FILTER_QUERY_FUNC2(query_formats), \ .process_command = process_command, \ - .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, \ } #define DEFINE_BIQUAD_FILTER(name, description) \ diff --git a/libavfilter/af_bs2b.c b/libavfilter/af_bs2b.c index 006c8564f..1ef92df9e 100644 --- a/libavfilter/af_bs2b.c +++ b/libavfilter/af_bs2b.c @@ -113,7 +113,7 @@ static int query_formats(const AVFilterContext *ctx, if (ret < 0) return ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; @@ -205,11 +205,11 @@ static const AVFilterPad bs2b_outputs[] = { }, }; -const AVFilter ff_af_bs2b = { - .name = "bs2b", - .description = NULL_IF_CONFIG_SMALL("Bauer stereo-to-binaural filter."), +const FFFilter ff_af_bs2b = { + .p.name = "bs2b", + .p.description = NULL_IF_CONFIG_SMALL("Bauer stereo-to-binaural filter."), + .p.priv_class = &bs2b_class, .priv_size = sizeof(Bs2bContext), - .priv_class = &bs2b_class, .init = init, .uninit = uninit, FILTER_INPUTS(bs2b_inputs), diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c index 7a99ac778..b86431731 100644 --- a/libavfilter/af_channelmap.c +++ b/libavfilter/af_channelmap.c @@ -290,6 +290,7 @@ static av_cold int channelmap_init(AVFilterContext *ctx) for (i = 0; i < s->nch; i++) { s->map[i].in_channel_idx = i; s->map[i].out_channel_idx = i; + s->map[i].out_channel = av_channel_layout_channel_from_index(&s->output_layout, i); } } else if (s->nch != s->output_layout.nb_channels) { char buf[256]; @@ -444,13 +445,13 @@ static const AVFilterPad avfilter_af_channelmap_inputs[] = { }, }; -const AVFilter ff_af_channelmap = { - .name = "channelmap", - .description = NULL_IF_CONFIG_SMALL("Remap audio channels."), +const FFFilter ff_af_channelmap = { + .p.name = "channelmap", + .p.description = NULL_IF_CONFIG_SMALL("Remap audio channels."), + .p.priv_class = &channelmap_class, .init = channelmap_init, .uninit = channelmap_uninit, .priv_size = sizeof(ChannelMapContext), - .priv_class = &channelmap_class, FILTER_INPUTS(avfilter_af_channelmap_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(channelmap_query_formats), diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c index 64b6c7a1e..638e81593 100644 --- a/libavfilter/af_channelsplit.c +++ b/libavfilter/af_channelsplit.c @@ -228,29 +228,20 @@ static int activate(AVFilterContext *ctx) return 0; } - for (int i = 0; i < ctx->nb_outputs; i++) { - if (ff_outlink_get_status(ctx->outputs[i])) - continue; - - if (ff_outlink_frame_wanted(ctx->outputs[i])) { - ff_inlink_request_frame(inlink); - return 0; - } - } + FF_FILTER_FORWARD_WANTED_ANY(ctx, inlink); return FFERROR_NOT_READY; } -const AVFilter ff_af_channelsplit = { - .name = "channelsplit", - .description = NULL_IF_CONFIG_SMALL("Split audio into per-channel streams."), +const FFFilter ff_af_channelsplit = { + .p.name = "channelsplit", + .p.description = NULL_IF_CONFIG_SMALL("Split audio into per-channel streams."), + .p.priv_class = &channelsplit_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, .priv_size = sizeof(ChannelSplitContext), - .priv_class = &channelsplit_class, .init = init, .activate = activate, .uninit = uninit, FILTER_INPUTS(ff_audio_default_filterpad), - .outputs = NULL, FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, }; diff --git a/libavfilter/af_chorus.c b/libavfilter/af_chorus.c index 7b3f5be9a..f7eeea3a2 100644 --- a/libavfilter/af_chorus.c +++ b/libavfilter/af_chorus.c @@ -339,11 +339,11 @@ static const AVFilterPad chorus_outputs[] = { }, }; -const AVFilter ff_af_chorus = { - .name = "chorus", - .description = NULL_IF_CONFIG_SMALL("Add a chorus effect to the audio."), +const FFFilter ff_af_chorus = { + .p.name = "chorus", + .p.description = NULL_IF_CONFIG_SMALL("Add a chorus effect to the audio."), + .p.priv_class = &chorus_class, .priv_size = sizeof(ChorusContext), - .priv_class = &chorus_class, .init = init, .uninit = uninit, FILTER_INPUTS(chorus_inputs), diff --git a/libavfilter/af_compand.c b/libavfilter/af_compand.c index 1aedc0f6b..69de1360f 100644 --- a/libavfilter/af_compand.c +++ b/libavfilter/af_compand.c @@ -542,12 +542,12 @@ static const AVFilterPad compand_outputs[] = { }; -const AVFilter ff_af_compand = { - .name = "compand", - .description = NULL_IF_CONFIG_SMALL( +const FFFilter ff_af_compand = { + .p.name = "compand", + .p.description = NULL_IF_CONFIG_SMALL( "Compress or expand audio dynamic range."), + .p.priv_class = &compand_class, .priv_size = sizeof(CompandContext), - .priv_class = &compand_class, .init = init, .uninit = uninit, FILTER_INPUTS(compand_inputs), diff --git a/libavfilter/af_compensationdelay.c b/libavfilter/af_compensationdelay.c index 9d307fd1f..67f0b8f29 100644 --- a/libavfilter/af_compensationdelay.c +++ b/libavfilter/af_compensationdelay.c @@ -166,15 +166,15 @@ static const AVFilterPad compensationdelay_inputs[] = { }, }; -const AVFilter ff_af_compensationdelay = { - .name = "compensationdelay", - .description = NULL_IF_CONFIG_SMALL("Audio Compensation Delay Line."), +const FFFilter ff_af_compensationdelay = { + .p.name = "compensationdelay", + .p.description = NULL_IF_CONFIG_SMALL("Audio Compensation Delay Line."), + .p.priv_class = &compensationdelay_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(CompensationDelayContext), - .priv_class = &compensationdelay_class, .uninit = uninit, FILTER_INPUTS(compensationdelay_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_crossfeed.c b/libavfilter/af_crossfeed.c index 1d70e4064..6260313fc 100644 --- a/libavfilter/af_crossfeed.c +++ b/libavfilter/af_crossfeed.c @@ -63,7 +63,7 @@ static int query_formats(const AVFilterContext *ctx, int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret < 0) return ret; @@ -373,16 +373,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_crossfeed = { - .name = "crossfeed", - .description = NULL_IF_CONFIG_SMALL("Apply headphone crossfeed filter."), +const FFFilter ff_af_crossfeed = { + .p.name = "crossfeed", + .p.description = NULL_IF_CONFIG_SMALL("Apply headphone crossfeed filter."), + .p.priv_class = &crossfeed_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(CrossfeedContext), - .priv_class = &crossfeed_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = process_command, }; diff --git a/libavfilter/af_crystalizer.c b/libavfilter/af_crystalizer.c index f7f4b063b..3cb5dc71d 100644 --- a/libavfilter/af_crystalizer.c +++ b/libavfilter/af_crystalizer.c @@ -233,17 +233,17 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_crystalizer = { - .name = "crystalizer", - .description = NULL_IF_CONFIG_SMALL("Simple audio noise sharpening filter."), +const FFFilter ff_af_crystalizer = { + .p.name = "crystalizer", + .p.description = NULL_IF_CONFIG_SMALL("Simple audio noise sharpening filter."), + .p.priv_class = &crystalizer_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(CrystalizerContext), - .priv_class = &crystalizer_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_dcshift.c b/libavfilter/af_dcshift.c index bea15e51d..9aec777e1 100644 --- a/libavfilter/af_dcshift.c +++ b/libavfilter/af_dcshift.c @@ -122,14 +122,14 @@ static const AVFilterPad dcshift_inputs[] = { }, }; -const AVFilter ff_af_dcshift = { - .name = "dcshift", - .description = NULL_IF_CONFIG_SMALL("Apply a DC shift to the audio."), +const FFFilter ff_af_dcshift = { + .p.name = "dcshift", + .p.description = NULL_IF_CONFIG_SMALL("Apply a DC shift to the audio."), + .p.priv_class = &dcshift_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(DCShiftContext), - .priv_class = &dcshift_class, .init = init, FILTER_INPUTS(dcshift_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_S32P), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/af_deesser.c b/libavfilter/af_deesser.c index b5fad9789..657604267 100644 --- a/libavfilter/af_deesser.c +++ b/libavfilter/af_deesser.c @@ -194,14 +194,14 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_deesser = { - .name = "deesser", - .description = NULL_IF_CONFIG_SMALL("Apply de-essing to the audio."), +const FFFilter ff_af_deesser = { + .p.name = "deesser", + .p.description = NULL_IF_CONFIG_SMALL("Apply de-essing to the audio."), + .p.priv_class = &deesser_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(DeesserContext), - .priv_class = &deesser_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_dialoguenhance.c b/libavfilter/af_dialoguenhance.c index cae837554..ecd2be23a 100644 --- a/libavfilter/af_dialoguenhance.c +++ b/libavfilter/af_dialoguenhance.c @@ -82,7 +82,7 @@ static int query_formats(const AVFilterContext *ctx, AVFilterChannelLayouts *in_layout = NULL, *out_layout = NULL; int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret < 0) return ret; @@ -217,16 +217,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_dialoguenhance = { - .name = "dialoguenhance", - .description = NULL_IF_CONFIG_SMALL("Audio Dialogue Enhancement."), +const FFFilter ff_af_dialoguenhance = { + .p.name = "dialoguenhance", + .p.description = NULL_IF_CONFIG_SMALL("Audio Dialogue Enhancement."), + .p.priv_class = &dialoguenhance_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioDialogueEnhanceContext), - .priv_class = &dialoguenhance_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .activate = activate, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_drmeter.c b/libavfilter/af_drmeter.c index e5859e9d8..7eae49c0b 100644 --- a/libavfilter/af_drmeter.c +++ b/libavfilter/af_drmeter.c @@ -138,7 +138,7 @@ static void print_stats(AVFilterContext *ctx) int peak_bin = BINS; if (!p->nb_samples) { - av_log(ctx, AV_LOG_INFO, "No data, dynamic range not meassurable\n"); + av_log(ctx, AV_LOG_INFO, "No data, dynamic range not measurable\n"); return; } @@ -197,13 +197,13 @@ static const AVFilterPad drmeter_outputs[] = { }, }; -const AVFilter ff_af_drmeter = { - .name = "drmeter", - .description = NULL_IF_CONFIG_SMALL("Measure audio dynamic range."), +const FFFilter ff_af_drmeter = { + .p.name = "drmeter", + .p.description = NULL_IF_CONFIG_SMALL("Measure audio dynamic range."), + .p.priv_class = &drmeter_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(DRMeterContext), - .priv_class = &drmeter_class, .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(drmeter_inputs), FILTER_OUTPUTS(drmeter_outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), diff --git a/libavfilter/af_dynaudnorm.c b/libavfilter/af_dynaudnorm.c index 90b3f8bbe..ddeedf625 100644 --- a/libavfilter/af_dynaudnorm.c +++ b/libavfilter/af_dynaudnorm.c @@ -1020,9 +1020,12 @@ static const AVFilterPad avfilter_af_dynaudnorm_inputs[] = { }, }; -const AVFilter ff_af_dynaudnorm = { - .name = "dynaudnorm", - .description = NULL_IF_CONFIG_SMALL("Dynamic Audio Normalizer."), +const FFFilter ff_af_dynaudnorm = { + .p.name = "dynaudnorm", + .p.description = NULL_IF_CONFIG_SMALL("Dynamic Audio Normalizer."), + .p.priv_class = &dynaudnorm_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(DynamicAudioNormalizerContext), .init = init, .uninit = uninit, @@ -1030,8 +1033,5 @@ const AVFilter ff_af_dynaudnorm = { FILTER_INPUTS(avfilter_af_dynaudnorm_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .priv_class = &dynaudnorm_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = process_command, }; diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c index a45748174..ff7b0dde7 100644 --- a/libavfilter/af_earwax.c +++ b/libavfilter/af_earwax.c @@ -95,7 +95,7 @@ static int query_formats(const AVFilterContext *ctx, int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret < 0) return ret; @@ -236,9 +236,9 @@ static const AVFilterPad earwax_inputs[] = { }, }; -const AVFilter ff_af_earwax = { - .name = "earwax", - .description = NULL_IF_CONFIG_SMALL("Widen the stereo image."), +const FFFilter ff_af_earwax = { + .p.name = "earwax", + .p.description = NULL_IF_CONFIG_SMALL("Widen the stereo image."), .priv_size = sizeof(EarwaxContext), .uninit = uninit, FILTER_INPUTS(earwax_inputs), diff --git a/libavfilter/af_extrastereo.c b/libavfilter/af_extrastereo.c index e511a2b96..a6b6e86f5 100644 --- a/libavfilter/af_extrastereo.c +++ b/libavfilter/af_extrastereo.c @@ -57,7 +57,7 @@ static int query_formats(const AVFilterContext *ctx, int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret < 0) return ret; @@ -122,14 +122,14 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_extrastereo = { - .name = "extrastereo", - .description = NULL_IF_CONFIG_SMALL("Increase difference between stereo audio channels."), +const FFFilter ff_af_extrastereo = { + .p.name = "extrastereo", + .p.description = NULL_IF_CONFIG_SMALL("Increase difference between stereo audio channels."), + .p.priv_class = &extrastereo_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(ExtraStereoContext), - .priv_class = &extrastereo_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_firequalizer.c b/libavfilter/af_firequalizer.c index 1ce8cabbd..f14983b43 100644 --- a/libavfilter/af_firequalizer.c +++ b/libavfilter/af_firequalizer.c @@ -957,14 +957,14 @@ static const AVFilterPad firequalizer_outputs[] = { }, }; -const AVFilter ff_af_firequalizer = { - .name = "firequalizer", - .description = NULL_IF_CONFIG_SMALL("Finite Impulse Response Equalizer."), +const FFFilter ff_af_firequalizer = { + .p.name = "firequalizer", + .p.description = NULL_IF_CONFIG_SMALL("Finite Impulse Response Equalizer."), + .p.priv_class = &firequalizer_class, .uninit = uninit, .process_command = process_command, .priv_size = sizeof(FIREqualizerContext), FILTER_INPUTS(firequalizer_inputs), FILTER_OUTPUTS(firequalizer_outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), - .priv_class = &firequalizer_class, }; diff --git a/libavfilter/af_flanger.c b/libavfilter/af_flanger.c index 092ffcaa2..c5c70d76f 100644 --- a/libavfilter/af_flanger.c +++ b/libavfilter/af_flanger.c @@ -195,11 +195,11 @@ static const AVFilterPad flanger_inputs[] = { }, }; -const AVFilter ff_af_flanger = { - .name = "flanger", - .description = NULL_IF_CONFIG_SMALL("Apply a flanging effect to the audio."), +const FFFilter ff_af_flanger = { + .p.name = "flanger", + .p.description = NULL_IF_CONFIG_SMALL("Apply a flanging effect to the audio."), + .p.priv_class = &flanger_class, .priv_size = sizeof(FlangerContext), - .priv_class = &flanger_class, .init = init, .uninit = uninit, FILTER_INPUTS(flanger_inputs), diff --git a/libavfilter/af_haas.c b/libavfilter/af_haas.c index 6726c8529..bb6d243ca 100644 --- a/libavfilter/af_haas.c +++ b/libavfilter/af_haas.c @@ -95,7 +95,7 @@ static int query_formats(const AVFilterContext *ctx, }; int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret < 0) return ret; @@ -218,11 +218,11 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_haas = { - .name = "haas", - .description = NULL_IF_CONFIG_SMALL("Apply Haas Stereo Enhancer."), +const FFFilter ff_af_haas = { + .p.name = "haas", + .p.description = NULL_IF_CONFIG_SMALL("Apply Haas Stereo Enhancer."), + .p.priv_class = &haas_class, .priv_size = sizeof(HaasContext), - .priv_class = &haas_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c index c9d992d01..f5c105565 100644 --- a/libavfilter/af_hdcd.c +++ b/libavfilter/af_hdcd.c @@ -1636,12 +1636,12 @@ static int query_formats(const AVFilterContext *ctx, if (ret < 0) return ret; - in_formats = ff_make_format_list(sample_fmts_in); + in_formats = ff_make_sample_format_list(sample_fmts_in); ret = ff_formats_ref(in_formats, &cfg_in[0]->formats); if (ret < 0) return ret; - out_formats = ff_make_format_list(sample_fmts_out); + out_formats = ff_make_sample_format_list(sample_fmts_out); ret = ff_formats_ref(out_formats, &cfg_out[0]->formats); if (ret < 0) return ret; @@ -1758,11 +1758,11 @@ static const AVFilterPad avfilter_af_hdcd_inputs[] = { }, }; -const AVFilter ff_af_hdcd = { - .name = "hdcd", - .description = NULL_IF_CONFIG_SMALL("Apply High Definition Compatible Digital (HDCD) decoding."), +const FFFilter ff_af_hdcd = { + .p.name = "hdcd", + .p.description = NULL_IF_CONFIG_SMALL("Apply High Definition Compatible Digital (HDCD) decoding."), + .p.priv_class = &hdcd_class, .priv_size = sizeof(HDCDContext), - .priv_class = &hdcd_class, .init = init, .uninit = uninit, FILTER_INPUTS(avfilter_af_hdcd_inputs), diff --git a/libavfilter/af_headphone.c b/libavfilter/af_headphone.c index fccd8d3f1..a053ec03d 100644 --- a/libavfilter/af_headphone.c +++ b/libavfilter/af_headphone.c @@ -610,7 +610,7 @@ static int query_formats(const AVFilterContext *ctx, AVFilterChannelLayouts *hrir_layouts = NULL; int ret, i; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret) return ret; @@ -776,16 +776,15 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_headphone = { - .name = "headphone", - .description = NULL_IF_CONFIG_SMALL("Apply headphone binaural spatialization with HRTFs in additional streams."), +const FFFilter ff_af_headphone = { + .p.name = "headphone", + .p.description = NULL_IF_CONFIG_SMALL("Apply headphone binaural spatialization with HRTFs in additional streams."), + .p.priv_class = &headphone_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(HeadphoneContext), - .priv_class = &headphone_class, .init = init, .uninit = uninit, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c index 0ea53248b..de13f8f2d 100644 --- a/libavfilter/af_join.c +++ b/libavfilter/af_join.c @@ -595,17 +595,16 @@ static const AVFilterPad avfilter_af_join_outputs[] = { }, }; -const AVFilter ff_af_join = { - .name = "join", - .description = NULL_IF_CONFIG_SMALL("Join multiple audio streams into " +const FFFilter ff_af_join = { + .p.name = "join", + .p.description = NULL_IF_CONFIG_SMALL("Join multiple audio streams into " "multi-channel output."), + .p.priv_class = &join_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(JoinContext), - .priv_class = &join_class, .init = join_init, .uninit = join_uninit, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(avfilter_af_join_outputs), FILTER_QUERY_FUNC2(join_query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_ladspa.c b/libavfilter/af_ladspa.c index 35ff90b1a..ea5eb1a2e 100644 --- a/libavfilter/af_ladspa.c +++ b/libavfilter/af_ladspa.c @@ -702,7 +702,7 @@ static int query_formats(const AVFilterContext *ctx, AVFilterChannelLayouts *layouts; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + int ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; @@ -810,16 +810,15 @@ static const AVFilterPad ladspa_outputs[] = { }, }; -const AVFilter ff_af_ladspa = { - .name = "ladspa", - .description = NULL_IF_CONFIG_SMALL("Apply LADSPA effect."), +const FFFilter ff_af_ladspa = { + .p.name = "ladspa", + .p.description = NULL_IF_CONFIG_SMALL("Apply LADSPA effect."), + .p.priv_class = &ladspa_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(LADSPAContext), - .priv_class = &ladspa_class, .init = init, .uninit = uninit, .process_command = process_command, - .inputs = 0, FILTER_OUTPUTS(ladspa_outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_loudnorm.c b/libavfilter/af_loudnorm.c index d63a71381..7ca3f2e6f 100644 --- a/libavfilter/af_loudnorm.c +++ b/libavfilter/af_loudnorm.c @@ -20,6 +20,7 @@ /* http://k.ylo.ph/2016/04/04/loudnorm.html */ +#include "libavutil/file_open.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" @@ -63,7 +64,9 @@ typedef struct LoudNormContext { double offset; int linear; int dual_mono; - enum PrintFormat print_format; + /* enum PrintFormat */ + int print_format; + char *stats_file_str; double *buf; int buf_size; @@ -121,6 +124,7 @@ static const AVOption loudnorm_options[] = { { "none", 0, 0, AV_OPT_TYPE_CONST, {.i64 = NONE}, 0, 0, FLAGS, .unit = "print_format" }, { "json", 0, 0, AV_OPT_TYPE_CONST, {.i64 = JSON}, 0, 0, FLAGS, .unit = "print_format" }, { "summary", 0, 0, AV_OPT_TYPE_CONST, {.i64 = SUMMARY}, 0, 0, FLAGS, .unit = "print_format" }, + { "stats_file", "set stats output file", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS }, { NULL } }; @@ -740,7 +744,7 @@ static int query_formats(const AVFilterContext *ctx, }; int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; @@ -774,7 +778,7 @@ static int config_input(AVFilterLink *inlink) return AVERROR(ENOMEM); s->limiter_buf_size = frame_size(inlink->sample_rate, 210) * inlink->ch_layout.nb_channels; - s->limiter_buf = av_malloc_array(s->buf_size, sizeof(*s->limiter_buf)); + s->limiter_buf = av_malloc_array(s->limiter_buf_size, sizeof(*s->limiter_buf)); if (!s->limiter_buf) return AVERROR(ENOMEM); @@ -803,6 +807,11 @@ static av_cold int init(AVFilterContext *ctx) LoudNormContext *s = ctx->priv; s->frame_type = FIRST_FRAME; + if (s->stats_file_str && s->print_format == NONE) { + av_log(ctx, AV_LOG_ERROR, "stats_file requested but print_format not specified\n"); + return AVERROR(EINVAL); + } + if (s->linear) { double offset, offset_tp; offset = s->target_i - s->measured_i; @@ -824,6 +833,7 @@ static av_cold void uninit(AVFilterContext *ctx) LoudNormContext *s = ctx->priv; double i_in, i_out, lra_in, lra_out, thresh_in, thresh_out, tp_in, tp_out; int c; + FILE *stats_file = NULL; if (!s->r128_in || !s->r128_out) goto end; @@ -848,13 +858,30 @@ static av_cold void uninit(AVFilterContext *ctx) tp_out = tmp; } + + if (s->stats_file_str) { + if (!strcmp(s->stats_file_str, "-")) { + stats_file = stdout; + } else { + stats_file = avpriv_fopen_utf8(s->stats_file_str, "w"); + if (!stats_file) { + int err = AVERROR(errno); + av_log(ctx, AV_LOG_ERROR, "Could not open stats file %s: %s\n", + s->stats_file_str, av_err2str(err)); + goto end; + } + } + } + switch(s->print_format) { case NONE: break; case JSON: - av_log(ctx, AV_LOG_INFO, - "\n{\n" + case SUMMARY: { + char stats[1024]; + const char *const format = s->print_format == JSON ? + "{\n" "\t\"input_i\" : \"%.2f\",\n" "\t\"input_tp\" : \"%.2f\",\n" "\t\"input_lra\" : \"%.2f\",\n" @@ -865,23 +892,7 @@ static av_cold void uninit(AVFilterContext *ctx) "\t\"output_thresh\" : \"%.2f\",\n" "\t\"normalization_type\" : \"%s\",\n" "\t\"target_offset\" : \"%.2f\"\n" - "}\n", - i_in, - 20. * log10(tp_in), - lra_in, - thresh_in, - i_out, - 20. * log10(tp_out), - lra_out, - thresh_out, - s->frame_type == LINEAR_MODE ? "linear" : "dynamic", - s->target_i - i_out - ); - break; - - case SUMMARY: - av_log(ctx, AV_LOG_INFO, - "\n" + "}\n" : "Input Integrated: %+6.1f LUFS\n" "Input True Peak: %+6.1f dBTP\n" "Input LRA: %6.1f LU\n" @@ -893,7 +904,9 @@ static av_cold void uninit(AVFilterContext *ctx) "Output Threshold: %+6.1f LUFS\n" "\n" "Normalization Type: %s\n" - "Target Offset: %+6.1f LU\n", + "Target Offset: %+6.1f LU\n"; + + snprintf(stats, sizeof(stats), format, i_in, 20. * log10(tp_in), lra_in, @@ -902,13 +915,20 @@ static av_cold void uninit(AVFilterContext *ctx) 20. * log10(tp_out), lra_out, thresh_out, - s->frame_type == LINEAR_MODE ? "Linear" : "Dynamic", + s->frame_type == LINEAR_MODE ? (s->print_format == JSON ? "linear" : "Linear") + : (s->print_format == JSON ? "dynamic" : "Dynamic"), s->target_i - i_out ); + av_log(ctx, AV_LOG_INFO, "\n%s", stats); + if (stats_file) + fprintf(stats_file, "%s", stats); break; } + } end: + if (stats_file && stats_file != stdout) + fclose(stats_file); if (s->r128_in) ff_ebur128_destroy(&s->r128_in); if (s->r128_out) @@ -926,11 +946,11 @@ static const AVFilterPad avfilter_af_loudnorm_inputs[] = { }, }; -const AVFilter ff_af_loudnorm = { - .name = "loudnorm", - .description = NULL_IF_CONFIG_SMALL("EBU R128 loudness normalization"), +const FFFilter ff_af_loudnorm = { + .p.name = "loudnorm", + .p.description = NULL_IF_CONFIG_SMALL("EBU R128 loudness normalization"), + .p.priv_class = &loudnorm_class, .priv_size = sizeof(LoudNormContext), - .priv_class = &loudnorm_class, .init = init, .activate = activate, .uninit = uninit, diff --git a/libavfilter/af_lv2.c b/libavfilter/af_lv2.c index adb153523..c34f6eb30 100644 --- a/libavfilter/af_lv2.c +++ b/libavfilter/af_lv2.c @@ -167,8 +167,9 @@ static const char *uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid) return NULL; } -static void connect_ports(LV2Context *s, AVFrame *in, AVFrame *out) +static void connect_ports(AVFilterContext *ctx, AVFrame *in, AVFrame *out) { + LV2Context *s = ctx->priv; int ich = 0, och = 0, i; for (i = 0; i < s->nb_ports; i++) { @@ -181,7 +182,7 @@ static void connect_ports(LV2Context *s, AVFrame *in, AVFrame *out) } else if (lilv_port_is_a(s->plugin, port, s->lv2_OutputPort)) { lilv_instance_connect_port(s->instance, i, out->extended_data[och++]); } else { - av_log(s, AV_LOG_WARNING, "port %d neither input nor output, skipping\n", i); + av_log(ctx, AV_LOG_WARNING, "port %d neither input nor output, skipping\n", i); } } else if (lilv_port_is_a(s->plugin, port, s->atom_AtomPort)) { if (lilv_port_is_a(s->plugin, port, s->lv2_InputPort)) { @@ -218,7 +219,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_copy_props(out, in); } - connect_ports(s, in, out); + connect_ports(ctx, in, out); lilv_instance_run(s->instance, in->nb_samples); @@ -246,7 +247,7 @@ static int request_frame(AVFilterLink *outlink) if (!out) return AVERROR(ENOMEM); - connect_ports(s, out, out); + connect_ports(ctx, out, out); lilv_instance_run(s->instance, out->nb_samples); @@ -303,7 +304,7 @@ static int config_output(AVFilterLink *outlink) s->instance = lilv_plugin_instantiate(s->plugin, sample_rate, s->features); if (!s->instance) { - av_log(s, AV_LOG_ERROR, "Failed to instantiate <%s>\n", lilv_node_as_uri(lilv_plugin_get_uri(s->plugin))); + av_log(ctx, AV_LOG_ERROR, "Failed to instantiate <%s>\n", lilv_node_as_uri(lilv_plugin_get_uri(s->plugin))); return AVERROR(EINVAL); } @@ -371,7 +372,7 @@ static int config_output(AVFilterLink *outlink) port = lilv_plugin_get_port_by_symbol(s->plugin, sym); lilv_node_free(sym); if (!port) { - av_log(s, AV_LOG_WARNING, "Unknown option: <%s>\n", str); + av_log(ctx, AV_LOG_WARNING, "Unknown option: <%s>\n", str); } else { index = lilv_port_get_index(s->plugin, port); s->controls[index] = val; @@ -408,7 +409,7 @@ static av_cold int init(AVFilterContext *ctx) uri = lilv_new_uri(s->world, s->plugin_uri); if (!uri) { - av_log(s, AV_LOG_ERROR, "Invalid plugin URI <%s>\n", s->plugin_uri); + av_log(ctx, AV_LOG_ERROR, "Invalid plugin URI <%s>\n", s->plugin_uri); return AVERROR(EINVAL); } @@ -418,7 +419,7 @@ static av_cold int init(AVFilterContext *ctx) lilv_node_free(uri); if (!plugin) { - av_log(s, AV_LOG_ERROR, "Plugin <%s> not found\n", s->plugin_uri); + av_log(ctx, AV_LOG_ERROR, "Plugin <%s> not found\n", s->plugin_uri); return AVERROR(EINVAL); } @@ -486,7 +487,7 @@ static int query_formats(const AVFilterContext *ctx, AVFilterChannelLayouts *layouts; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + int ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; @@ -553,7 +554,7 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar port = lilv_plugin_get_port_by_symbol(s->plugin, sym); lilv_node_free(sym); if (!port) { - av_log(s, AV_LOG_WARNING, "Unknown option: <%s>\n", cmd); + av_log(ctx, AV_LOG_WARNING, "Unknown option: <%s>\n", cmd); } else { index = lilv_port_get_index(s->plugin, port); s->controls[index] = atof(args); @@ -596,16 +597,15 @@ static const AVFilterPad lv2_outputs[] = { }, }; -const AVFilter ff_af_lv2 = { - .name = "lv2", - .description = NULL_IF_CONFIG_SMALL("Apply LV2 effect."), +const FFFilter ff_af_lv2 = { + .p.name = "lv2", + .p.description = NULL_IF_CONFIG_SMALL("Apply LV2 effect."), + .p.priv_class = &lv2_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(LV2Context), - .priv_class = &lv2_class, .init = init, .uninit = uninit, .process_command = process_command, - .inputs = 0, FILTER_OUTPUTS(lv2_outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_mcompand.c b/libavfilter/af_mcompand.c index b2f61fc5f..855d89355 100644 --- a/libavfilter/af_mcompand.c +++ b/libavfilter/af_mcompand.c @@ -634,12 +634,12 @@ static const AVFilterPad mcompand_outputs[] = { }; -const AVFilter ff_af_mcompand = { - .name = "mcompand", - .description = NULL_IF_CONFIG_SMALL( +const FFFilter ff_af_mcompand = { + .p.name = "mcompand", + .p.description = NULL_IF_CONFIG_SMALL( "Multiband Compress or expand audio dynamic range."), + .p.priv_class = &mcompand_class, .priv_size = sizeof(MCompandContext), - .priv_class = &mcompand_class, .uninit = uninit, FILTER_INPUTS(mcompand_inputs), FILTER_OUTPUTS(mcompand_outputs), diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c index 13c7d517e..32bd28fe0 100644 --- a/libavfilter/af_pan.c +++ b/libavfilter/af_pan.c @@ -416,11 +416,11 @@ static const AVFilterPad pan_inputs[] = { }, }; -const AVFilter ff_af_pan = { - .name = "pan", - .description = NULL_IF_CONFIG_SMALL("Remix channels with coefficients (panning)."), +const FFFilter ff_af_pan = { + .p.name = "pan", + .p.description = NULL_IF_CONFIG_SMALL("Remix channels with coefficients (panning)."), + .p.priv_class = &pan_class, .priv_size = sizeof(PanContext), - .priv_class = &pan_class, .init = init, .uninit = uninit, FILTER_INPUTS(pan_inputs), diff --git a/libavfilter/af_replaygain.c b/libavfilter/af_replaygain.c index e3e2e921c..1ebae32ec 100644 --- a/libavfilter/af_replaygain.c +++ b/libavfilter/af_replaygain.c @@ -343,7 +343,7 @@ static int query_formats(const AVFilterContext *ctx, int i, ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret < 0) return ret; @@ -643,12 +643,12 @@ static const AVOption replaygain_options[] = { AVFILTER_DEFINE_CLASS(replaygain); -const AVFilter ff_af_replaygain = { - .name = "replaygain", - .description = NULL_IF_CONFIG_SMALL("ReplayGain scanner."), +const FFFilter ff_af_replaygain = { + .p.name = "replaygain", + .p.description = NULL_IF_CONFIG_SMALL("ReplayGain scanner."), + .p.priv_class = &replaygain_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(ReplayGainContext), - .priv_class = &replaygain_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(replaygain_inputs), FILTER_OUTPUTS(replaygain_outputs), FILTER_QUERY_FUNC2(query_formats), diff --git a/libavfilter/af_rubberband.c b/libavfilter/af_rubberband.c index cf055f77d..eedd96b19 100644 --- a/libavfilter/af_rubberband.c +++ b/libavfilter/af_rubberband.c @@ -205,11 +205,11 @@ static const AVFilterPad rubberband_inputs[] = { }, }; -const AVFilter ff_af_rubberband = { - .name = "rubberband", - .description = NULL_IF_CONFIG_SMALL("Apply time-stretching and pitch-shifting."), +const FFFilter ff_af_rubberband = { + .p.name = "rubberband", + .p.description = NULL_IF_CONFIG_SMALL("Apply time-stretching and pitch-shifting."), + .p.priv_class = &rubberband_class, .priv_size = sizeof(RubberBandContext), - .priv_class = &rubberband_class, .uninit = uninit, .activate = activate, FILTER_INPUTS(rubberband_inputs), diff --git a/libavfilter/af_sidechaincompress.c b/libavfilter/af_sidechaincompress.c index d2bc63f5d..06555cbd2 100644 --- a/libavfilter/af_sidechaincompress.c +++ b/libavfilter/af_sidechaincompress.c @@ -314,7 +314,7 @@ static int query_formats(const AVFilterContext *ctx, if (ret < 0) return ret; - if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts)) < 0) + if ((ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts)) < 0) return ret; return 0; @@ -363,10 +363,10 @@ static const AVFilterPad sidechaincompress_outputs[] = { }, }; -const AVFilter ff_af_sidechaincompress = { - .name = "sidechaincompress", - .description = NULL_IF_CONFIG_SMALL("Sidechain compressor."), - .priv_class = &sidechaincompress_acompressor_class, +const FFFilter ff_af_sidechaincompress = { + .p.name = "sidechaincompress", + .p.description = NULL_IF_CONFIG_SMALL("Sidechain compressor."), + .p.priv_class = &sidechaincompress_acompressor_class, .priv_size = sizeof(SidechainCompressContext), .activate = activate, .uninit = uninit, @@ -424,10 +424,10 @@ static const AVFilterPad acompressor_outputs[] = { }, }; -const AVFilter ff_af_acompressor = { - .name = "acompressor", - .description = NULL_IF_CONFIG_SMALL("Audio compressor."), - .priv_class = &sidechaincompress_acompressor_class, +const FFFilter ff_af_acompressor = { + .p.name = "acompressor", + .p.description = NULL_IF_CONFIG_SMALL("Audio compressor."), + .p.priv_class = &sidechaincompress_acompressor_class, .priv_size = sizeof(SidechainCompressContext), FILTER_INPUTS(acompressor_inputs), FILTER_OUTPUTS(acompressor_outputs), diff --git a/libavfilter/af_silencedetect.c b/libavfilter/af_silencedetect.c index 9bb17400e..bcdc90f8e 100644 --- a/libavfilter/af_silencedetect.c +++ b/libavfilter/af_silencedetect.c @@ -45,7 +45,7 @@ typedef struct SilenceDetectContext { int last_sample_rate; ///< last sample rate to check for sample rate changes AVRational time_base; ///< time_base - void (*silencedetect)(struct SilenceDetectContext *s, AVFrame *insamples, + void (*silencedetect)(AVFilterContext *ctx, AVFrame *insamples, int nb_samples, int64_t nb_samples_notify, AVRational time_base); } SilenceDetectContext; @@ -75,10 +75,11 @@ static void set_meta(AVFrame *insamples, int channel, const char *key, char *val snprintf(key2, sizeof(key2), "lavfi.%s", key); av_dict_set(&insamples->metadata, key2, value, 0); } -static av_always_inline void update(SilenceDetectContext *s, AVFrame *insamples, +static av_always_inline void update(AVFilterContext *ctx, AVFrame *insamples, int is_silence, int current_sample, int64_t nb_samples_notify, AVRational time_base) { + SilenceDetectContext *s = ctx->priv; int channel = current_sample % s->independent_channels; if (is_silence) { if (s->start[channel] == INT64_MIN) { @@ -89,8 +90,8 @@ static av_always_inline void update(SilenceDetectContext *s, AVFrame *insamples, set_meta(insamples, s->mono ? channel + 1 : 0, "silence_start", av_ts2timestr(s->start[channel], &time_base)); if (s->mono) - av_log(s, AV_LOG_INFO, "channel: %d | ", channel); - av_log(s, AV_LOG_INFO, "silence_start: %s\n", + av_log(ctx, AV_LOG_INFO, "channel: %d | ", channel); + av_log(ctx, AV_LOG_INFO, "silence_start: %s\n", av_ts2timestr(s->start[channel], &time_base)); } } @@ -107,8 +108,8 @@ static av_always_inline void update(SilenceDetectContext *s, AVFrame *insamples, av_ts2timestr(duration_ts, &time_base)); } if (s->mono) - av_log(s, AV_LOG_INFO, "channel: %d | ", channel); - av_log(s, AV_LOG_INFO, "silence_end: %s | silence_duration: %s\n", + av_log(ctx, AV_LOG_INFO, "channel: %d | ", channel); + av_log(ctx, AV_LOG_INFO, "silence_end: %s | silence_duration: %s\n", av_ts2timestr(end_pts, &time_base), av_ts2timestr(duration_ts, &time_base)); } @@ -118,24 +119,26 @@ static av_always_inline void update(SilenceDetectContext *s, AVFrame *insamples, } #define SILENCE_DETECT(name, type) \ -static void silencedetect_##name(SilenceDetectContext *s, AVFrame *insamples, \ +static void silencedetect_##name(AVFilterContext *ctx, AVFrame *insamples, \ int nb_samples, int64_t nb_samples_notify, \ AVRational time_base) \ { \ + SilenceDetectContext *s = ctx->priv; \ const type *p = (const type *)insamples->data[0]; \ const type noise = s->noise; \ int i; \ \ for (i = 0; i < nb_samples; i++, p++) \ - update(s, insamples, *p < noise && *p > -noise, i, \ + update(ctx, insamples, *p < noise && *p > -noise, i, \ nb_samples_notify, time_base); \ } #define SILENCE_DETECT_PLANAR(name, type) \ -static void silencedetect_##name(SilenceDetectContext *s, AVFrame *insamples, \ +static void silencedetect_##name(AVFilterContext *ctx, AVFrame *insamples, \ int nb_samples, int64_t nb_samples_notify, \ AVRational time_base) \ { \ + SilenceDetectContext *s = ctx->priv; \ const int channels = insamples->ch_layout.nb_channels; \ const type noise = s->noise; \ \ @@ -143,7 +146,7 @@ static void silencedetect_##name(SilenceDetectContext *s, AVFrame *insamples, for (int i = 0; i < nb_samples; i++) { \ for (int ch = 0; ch < insamples->ch_layout.nb_channels; ch++) { \ const type *p = (const type *)insamples->extended_data[ch]; \ - update(s, insamples, p[i] < noise && p[i] > -noise, \ + update(ctx, insamples, p[i] < noise && p[i] > -noise, \ channels * i + ch, \ nb_samples_notify, time_base); \ } \ @@ -173,7 +176,7 @@ static int config_input(AVFilterLink *inlink) sizeof(*s->nb_null_samples)); if (!s->nb_null_samples) return AVERROR(ENOMEM); - s->start = av_malloc_array(sizeof(*s->start), s->independent_channels); + s->start = av_malloc_array(s->independent_channels, sizeof(*s->start)); if (!s->start) return AVERROR(ENOMEM); for (c = 0; c < s->independent_channels; c++) @@ -209,7 +212,8 @@ static int config_input(AVFilterLink *inlink) static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) { - SilenceDetectContext *s = inlink->dst->priv; + AVFilterContext *ctx = inlink->dst; + SilenceDetectContext *s = ctx->priv; const int nb_channels = inlink->ch_layout.nb_channels; const int srate = inlink->sample_rate; const int nb_samples = insamples->nb_samples * nb_channels; @@ -226,7 +230,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) s->frame_end = insamples->pts + av_rescale_q(insamples->nb_samples, (AVRational){ 1, s->last_sample_rate }, inlink->time_base); - s->silencedetect(s, insamples, nb_samples, nb_samples_notify, + s->silencedetect(ctx, insamples, nb_samples, nb_samples_notify, inlink->time_base); return ff_filter_frame(inlink->dst->outputs[0], insamples); @@ -239,7 +243,7 @@ static av_cold void uninit(AVFilterContext *ctx) for (c = 0; c < s->independent_channels; c++) if (s->start[c] > INT64_MIN) - update(s, NULL, 0, c, 0, s->time_base); + update(ctx, NULL, 0, c, 0, s->time_base); av_freep(&s->nb_null_samples); av_freep(&s->start); } @@ -253,9 +257,11 @@ static const AVFilterPad silencedetect_inputs[] = { }, }; -const AVFilter ff_af_silencedetect = { - .name = "silencedetect", - .description = NULL_IF_CONFIG_SMALL("Detect silence."), +const FFFilter ff_af_silencedetect = { + .p.name = "silencedetect", + .p.description = NULL_IF_CONFIG_SMALL("Detect silence."), + .p.priv_class = &silencedetect_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(SilenceDetectContext), .uninit = uninit, FILTER_INPUTS(silencedetect_inputs), @@ -264,6 +270,4 @@ const AVFilter ff_af_silencedetect = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P), - .priv_class = &silencedetect_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, }; diff --git a/libavfilter/af_silenceremove.c b/libavfilter/af_silenceremove.c index 3cc518a7e..fe12fd598 100644 --- a/libavfilter/af_silenceremove.c +++ b/libavfilter/af_silenceremove.c @@ -478,11 +478,12 @@ static const AVFilterPad silenceremove_outputs[] = { }, }; -const AVFilter ff_af_silenceremove = { - .name = "silenceremove", - .description = NULL_IF_CONFIG_SMALL("Remove silence."), +const FFFilter ff_af_silenceremove = { + .p.name = "silenceremove", + .p.description = NULL_IF_CONFIG_SMALL("Remove silence."), + .p.priv_class = &silenceremove_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(SilenceRemoveContext), - .priv_class = &silenceremove_class, .init = init, .activate = activate, .uninit = uninit, @@ -491,5 +492,4 @@ const AVFilter ff_af_silenceremove = { FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_sofalizer.c b/libavfilter/af_sofalizer.c index 178b9c0b5..ed05dc103 100644 --- a/libavfilter/af_sofalizer.c +++ b/libavfilter/af_sofalizer.c @@ -646,7 +646,7 @@ static int query_formats(const AVFilterContext *ctx, AV_SAMPLE_FMT_NONE }; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret) return ret; @@ -734,7 +734,7 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int AVComplexFloat *fft_in_r = NULL; float *data_ir_l = NULL; float *data_ir_r = NULL; - int offset = 0; /* used for faster pointer arithmetics in for-loop */ + int offset = 0; /* used for faster pointer arithmetic in for-loop */ int i, j, azim_orig = azim, elev_orig = elev; int ret = 0; int n_current; @@ -954,7 +954,7 @@ fail: av_freep(&data_hrtf_l); /* free temporary HRTF memory */ av_freep(&data_hrtf_r); - av_freep(&data_ir_l); /* free temprary IR memory */ + av_freep(&data_ir_l); /* free temporary IR memory */ av_freep(&data_ir_r); av_freep(&fft_out_l); /* free temporary FFT memory */ @@ -1088,16 +1088,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_sofalizer = { - .name = "sofalizer", - .description = NULL_IF_CONFIG_SMALL("SOFAlizer (Spatially Oriented Format for Acoustics)."), +const FFFilter ff_af_sofalizer = { + .p.name = "sofalizer", + .p.description = NULL_IF_CONFIG_SMALL("SOFAlizer (Spatially Oriented Format for Acoustics)."), + .p.priv_class = &sofalizer_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(SOFAlizerContext), - .priv_class = &sofalizer_class, .init = init, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_speechnorm.c b/libavfilter/af_speechnorm.c index 840c432c1..9e2ba6381 100644 --- a/libavfilter/af_speechnorm.c +++ b/libavfilter/af_speechnorm.c @@ -590,16 +590,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_speechnorm = { - .name = "speechnorm", - .description = NULL_IF_CONFIG_SMALL("Speech Normalizer."), +const FFFilter ff_af_speechnorm = { + .p.name = "speechnorm", + .p.description = NULL_IF_CONFIG_SMALL("Speech Normalizer."), + .p.priv_class = &speechnorm_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(SpeechNormalizerContext), - .priv_class = &speechnorm_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = process_command, }; diff --git a/libavfilter/af_stereotools.c b/libavfilter/af_stereotools.c index bbbc88cd4..b18f6e6be 100644 --- a/libavfilter/af_stereotools.c +++ b/libavfilter/af_stereotools.c @@ -117,7 +117,7 @@ static int query_formats(const AVFilterContext *ctx, int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret < 0) return ret; @@ -379,15 +379,15 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_stereotools = { - .name = "stereotools", - .description = NULL_IF_CONFIG_SMALL("Apply various stereo tools."), +const FFFilter ff_af_stereotools = { + .p.name = "stereotools", + .p.description = NULL_IF_CONFIG_SMALL("Apply various stereo tools."), + .p.priv_class = &stereotools_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(StereoToolsContext), - .priv_class = &stereotools_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_stereowiden.c b/libavfilter/af_stereowiden.c index 66aa24a03..456b4d5aa 100644 --- a/libavfilter/af_stereowiden.c +++ b/libavfilter/af_stereowiden.c @@ -69,7 +69,7 @@ static int query_formats(const AVFilterContext *ctx, int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret < 0) return ret; @@ -161,15 +161,15 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_stereowiden = { - .name = "stereowiden", - .description = NULL_IF_CONFIG_SMALL("Apply stereo widening effect."), +const FFFilter ff_af_stereowiden = { + .p.name = "stereowiden", + .p.description = NULL_IF_CONFIG_SMALL("Apply stereo widening effect."), + .p.priv_class = &stereowiden_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(StereoWidenContext), - .priv_class = &stereowiden_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_superequalizer.c b/libavfilter/af_superequalizer.c index bdf6e12af..402d9d0af 100644 --- a/libavfilter/af_superequalizer.c +++ b/libavfilter/af_superequalizer.c @@ -350,11 +350,11 @@ static const AVOption superequalizer_options[] = { AVFILTER_DEFINE_CLASS(superequalizer); -const AVFilter ff_af_superequalizer = { - .name = "superequalizer", - .description = NULL_IF_CONFIG_SMALL("Apply 18 band equalization filter."), +const FFFilter ff_af_superequalizer = { + .p.name = "superequalizer", + .p.description = NULL_IF_CONFIG_SMALL("Apply 18 band equalization filter."), + .p.priv_class = &superequalizer_class, .priv_size = sizeof(SuperEqualizerContext), - .priv_class = &superequalizer_class, .init = init, .activate = activate, .uninit = uninit, diff --git a/libavfilter/af_surround.c b/libavfilter/af_surround.c index 95efe4685..6c973f518 100644 --- a/libavfilter/af_surround.c +++ b/libavfilter/af_surround.c @@ -159,7 +159,7 @@ static int query_formats(const AVFilterContext *ctx, AVFilterChannelLayouts *layouts = NULL; int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret) return ret; @@ -1510,17 +1510,17 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_surround = { - .name = "surround", - .description = NULL_IF_CONFIG_SMALL("Apply audio surround upmix filter."), +const FFFilter ff_af_surround = { + .p.name = "surround", + .p.description = NULL_IF_CONFIG_SMALL("Apply audio surround upmix filter."), + .p.priv_class = &surround_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioSurroundContext), - .priv_class = &surround_class, .init = init, .uninit = uninit, .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SLICE_THREADS, .process_command = process_command, }; diff --git a/libavfilter/af_tremolo.c b/libavfilter/af_tremolo.c index 0c781a2de..d6bf06e21 100644 --- a/libavfilter/af_tremolo.c +++ b/libavfilter/af_tremolo.c @@ -122,14 +122,14 @@ static const AVFilterPad avfilter_af_tremolo_inputs[] = { }, }; -const AVFilter ff_af_tremolo = { - .name = "tremolo", - .description = NULL_IF_CONFIG_SMALL("Apply tremolo effect."), +const FFFilter ff_af_tremolo = { + .p.name = "tremolo", + .p.description = NULL_IF_CONFIG_SMALL("Apply tremolo effect."), + .p.priv_class = &tremolo_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(TremoloContext), - .priv_class = &tremolo_class, .uninit = uninit, FILTER_INPUTS(avfilter_af_tremolo_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/af_vibrato.c b/libavfilter/af_vibrato.c index a3bf90ae8..f4fd697a7 100644 --- a/libavfilter/af_vibrato.c +++ b/libavfilter/af_vibrato.c @@ -166,14 +166,14 @@ static const AVFilterPad avfilter_af_vibrato_inputs[] = { }, }; -const AVFilter ff_af_vibrato = { - .name = "vibrato", - .description = NULL_IF_CONFIG_SMALL("Apply vibrato effect."), +const FFFilter ff_af_vibrato = { + .p.name = "vibrato", + .p.description = NULL_IF_CONFIG_SMALL("Apply vibrato effect."), + .p.priv_class = &vibrato_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(VibratoContext), - .priv_class = &vibrato_class, .uninit = uninit, FILTER_INPUTS(avfilter_af_vibrato_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/af_virtualbass.c b/libavfilter/af_virtualbass.c index d2f28ab1a..28a6d13e4 100644 --- a/libavfilter/af_virtualbass.c +++ b/libavfilter/af_virtualbass.c @@ -60,7 +60,7 @@ static int query_formats(const AVFilterContext *ctx, AVFilterChannelLayouts *in_layout = NULL, *out_layout = NULL; int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret < 0) return ret; @@ -171,14 +171,14 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_virtualbass = { - .name = "virtualbass", - .description = NULL_IF_CONFIG_SMALL("Audio Virtual Bass."), +const FFFilter ff_af_virtualbass = { + .p.name = "virtualbass", + .p.description = NULL_IF_CONFIG_SMALL("Audio Virtual Bass."), + .p.priv_class = &virtualbass_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioVirtualBassContext), - .priv_class = &virtualbass_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c index ed924cf45..cd4001434 100644 --- a/libavfilter/af_volume.c +++ b/libavfilter/af_volume.c @@ -48,9 +48,6 @@ static const char *const var_names[] = { "nb_channels", ///< number of channels "nb_consumed_samples", ///< number of samples consumed by the filter "nb_samples", ///< number of samples in the current frame -#if FF_API_FRAME_PKT - "pos", ///< position in the file of the frame -#endif "pts", ///< frame presentation timestamp "sample_rate", ///< sample rate "startpts", ///< PTS at start of stream @@ -158,7 +155,7 @@ static int query_formats(const AVFilterContext *ctx, }; int ret; - ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts[vol->precision]); + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts[vol->precision]); if (ret < 0) return ret; @@ -239,7 +236,7 @@ static av_cold void volume_init(VolumeContext *vol) break; } -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_volume_init_x86(vol); #endif } @@ -289,9 +286,6 @@ static int config_output(AVFilterLink *outlink) vol->var_values[VAR_N] = vol->var_values[VAR_NB_CONSUMED_SAMPLES] = vol->var_values[VAR_NB_SAMPLES] = -#if FF_API_FRAME_PKT - vol->var_values[VAR_POS] = -#endif vol->var_values[VAR_PTS] = vol->var_values[VAR_STARTPTS] = vol->var_values[VAR_STARTT] = @@ -383,15 +377,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) vol->var_values[VAR_T ] = TS2T(buf->pts, inlink->time_base); vol->var_values[VAR_N ] = inl->frame_count_out; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - { - int64_t pos; - pos = buf->pkt_pos; - vol->var_values[VAR_POS] = pos == -1 ? NAN : pos; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif if (vol->eval_mode == EVAL_MODE_FRAME) set_volume(ctx); @@ -471,16 +456,16 @@ static const AVFilterPad avfilter_af_volume_outputs[] = { }, }; -const AVFilter ff_af_volume = { - .name = "volume", - .description = NULL_IF_CONFIG_SMALL("Change input volume."), +const FFFilter ff_af_volume = { + .p.name = "volume", + .p.description = NULL_IF_CONFIG_SMALL("Change input volume."), + .p.priv_class = &volume_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(VolumeContext), - .priv_class = &volume_class, .init = init, .uninit = uninit, FILTER_INPUTS(avfilter_af_volume_inputs), FILTER_OUTPUTS(avfilter_af_volume_outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .process_command = process_command, }; diff --git a/libavfilter/af_volume.h b/libavfilter/af_volume.h index c3756ee96..e9527eea8 100644 --- a/libavfilter/af_volume.h +++ b/libavfilter/af_volume.h @@ -47,9 +47,6 @@ enum VolumeVarName { VAR_NB_CHANNELS, VAR_NB_CONSUMED_SAMPLES, VAR_NB_SAMPLES, -#if FF_API_FRAME_PKT - VAR_POS, -#endif VAR_PTS, VAR_SAMPLE_RATE, VAR_STARTPTS, diff --git a/libavfilter/af_volumedetect.c b/libavfilter/af_volumedetect.c index 25f7bf569..6437687c8 100644 --- a/libavfilter/af_volumedetect.c +++ b/libavfilter/af_volumedetect.c @@ -122,12 +122,12 @@ static const AVFilterPad volumedetect_inputs[] = { }, }; -const AVFilter ff_af_volumedetect = { - .name = "volumedetect", - .description = NULL_IF_CONFIG_SMALL("Detect audio volume."), +const FFFilter ff_af_volumedetect = { + .p.name = "volumedetect", + .p.description = NULL_IF_CONFIG_SMALL("Detect audio volume."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(VolDetectContext), .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(volumedetect_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P), diff --git a/libavfilter/af_whisper.c b/libavfilter/af_whisper.c new file mode 100644 index 000000000..299a8bca7 --- /dev/null +++ b/libavfilter/af_whisper.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2025 Vittorio Palmisano + * + * 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 + +#include + +#include "libavutil/avutil.h" +#include "libavutil/opt.h" +#include "libavutil/channel_layout.h" +#include "libavutil/samplefmt.h" +#include "libavfilter/avfilter.h" +#include "libavfilter/audio.h" +#include "libavutil/mem.h" +#include "libavutil/avstring.h" +#include "libavutil/internal.h" +#include "libavformat/avio.h" +#include "libavutil/thread.h" + +#include "formats.h" + +typedef struct WhisperContext { + const AVClass *class; + char *model_path; + char *language; + bool use_gpu; + int gpu_device; + char *vad_model_path; + float vad_threshold; + int64_t vad_min_speech_duration; + int64_t vad_min_silence_duration; + + int64_t queue; + char *destination; + char *format; + int max_len; + + struct whisper_context *ctx_wsp; + struct whisper_vad_context *ctx_vad; + struct whisper_vad_params vad_params; + + float *audio_buffer; + int audio_buffer_queue_size; + int audio_buffer_fill_size; + int audio_buffer_vad_size; + int64_t audio_buffer_start_ms; + + int eof; + int64_t next_pts; + + AVIOContext *avio_context; + int index; +} WhisperContext; + +static void cb_log(enum ggml_log_level level, const char *text, void *user_data) +{ + AVFilterContext *ctx = user_data; + int av_log_level = AV_LOG_DEBUG; + switch (level) { + case GGML_LOG_LEVEL_ERROR: + av_log_level = AV_LOG_ERROR; + break; + case GGML_LOG_LEVEL_WARN: + av_log_level = AV_LOG_WARNING; + break; + } + av_log(ctx, av_log_level, "%s", text); +} + +static int init(AVFilterContext *ctx) +{ + WhisperContext *wctx = ctx->priv; + + static AVOnce init_static_once = AV_ONCE_INIT; + ff_thread_once(&init_static_once, ggml_backend_load_all); + + whisper_log_set(cb_log, ctx); + + // Init whisper context + if (!wctx->model_path) { + av_log(ctx, AV_LOG_ERROR, "No whisper model path specified. Use the 'model' option.\n"); + return AVERROR(EINVAL); + } + + struct whisper_context_params params = whisper_context_default_params(); + params.use_gpu = wctx->use_gpu; + params.gpu_device = wctx->gpu_device; + + wctx->ctx_wsp = whisper_init_from_file_with_params(wctx->model_path, params); + if (wctx->ctx_wsp == NULL) { + av_log(ctx, AV_LOG_ERROR, "Failed to initialize whisper context from model: %s\n", wctx->model_path); + return AVERROR(EIO); + } + + // Init buffer + wctx->audio_buffer_queue_size = av_rescale(wctx->queue, WHISPER_SAMPLE_RATE, AV_TIME_BASE); + wctx->audio_buffer = av_malloc_array(wctx->audio_buffer_queue_size, sizeof(*wctx->audio_buffer)); + if (!wctx->audio_buffer) + return AVERROR(ENOMEM); + + // Init VAD model context + if (wctx->vad_model_path) { + struct whisper_vad_context_params ctx_params = whisper_vad_default_context_params(); + ctx_params.n_threads = ff_filter_get_nb_threads(ctx); + // ctx_params.use_gpu = wctx->use_gpu; TODO (see: whisper_vad_init_context) + ctx_params.gpu_device = wctx->gpu_device; + wctx->ctx_vad = whisper_vad_init_from_file_with_params(wctx->vad_model_path, ctx_params); + + wctx->vad_params = whisper_vad_default_params(); + wctx->vad_params.threshold = wctx->vad_threshold; + wctx->vad_params.min_speech_duration_ms = av_rescale(wctx->vad_min_speech_duration, 1000, AV_TIME_BASE); + wctx->vad_params.min_silence_duration_ms = av_rescale(wctx->vad_min_silence_duration, 1000, AV_TIME_BASE); + wctx->vad_params.max_speech_duration_s = av_rescale(wctx->queue, 1, AV_TIME_BASE); + wctx->vad_params.speech_pad_ms = 0; + wctx->vad_params.samples_overlap = 0; + } + + wctx->next_pts = AV_NOPTS_VALUE; + + if (wctx->destination && strcmp("", wctx->destination)) { + const char *dst = wctx->destination; + if (!strcmp("-", dst)) + dst = "pipe:1"; + int ret = avio_open(&wctx->avio_context, dst, AVIO_FLAG_WRITE); + + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Could not open %s: %s\n", wctx->destination, av_err2str(ret)); + return ret; + } + + wctx->avio_context->direct = AVIO_FLAG_DIRECT; + } + + av_log(ctx, AV_LOG_INFO, + "Whisper filter initialized: model: %s lang: %s queue: %" PRId64 " ms\n", + wctx->model_path, wctx->language, wctx->queue / 1000); + + return 0; +} + +static void uninit(AVFilterContext *ctx) +{ + WhisperContext *wctx = ctx->priv; + + if (wctx->audio_buffer_fill_size > 0) { + av_log(ctx, AV_LOG_WARNING, + "Remaining audio buffer %d samples (%d seconds) after stopping\n", + wctx->audio_buffer_fill_size, wctx->audio_buffer_fill_size / WHISPER_SAMPLE_RATE); + } + + if (wctx->ctx_vad) { + whisper_vad_free(wctx->ctx_vad); + wctx->ctx_vad = NULL; + } + + if (wctx->ctx_wsp) { + whisper_free(wctx->ctx_wsp); + wctx->ctx_wsp = NULL; + } + + av_freep(&wctx->audio_buffer); + + if (wctx->avio_context) + avio_closep(&wctx->avio_context); +} + +static void run_transcription(AVFilterContext *ctx, AVFrame *frame, int samples) +{ + WhisperContext *wctx = ctx->priv; + samples = FFMAX(0, FFMIN(samples, wctx->audio_buffer_fill_size)); + + if (!wctx->ctx_wsp || samples == 0) + return; + + const int64_t timestamp_ms = wctx->audio_buffer_start_ms; + const float duration = (float) samples / WHISPER_SAMPLE_RATE; + + av_log(ctx, AV_LOG_INFO, + "run transcription at %" PRId64 " ms, %d/%d samples (%.2f seconds)...\n", + timestamp_ms, samples, wctx->audio_buffer_fill_size, duration); + + struct whisper_full_params params = whisper_full_default_params(WHISPER_SAMPLING_GREEDY); + params.language = wctx->language; + params.n_threads = ff_filter_get_nb_threads(ctx); + params.print_special = 0; + params.print_progress = 0; + params.print_realtime = 0; + params.print_timestamps = 0; + params.max_len = wctx->max_len; + params.token_timestamps = (wctx->max_len > 0); + + if (whisper_full(wctx->ctx_wsp, params, wctx->audio_buffer, samples) != 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to process audio with whisper.cpp\n"); + return; + } + + const int n_segments = whisper_full_n_segments(wctx->ctx_wsp); + char *segments_text = NULL; + + for (int i = 0; i < n_segments; ++i) { + const char *text = whisper_full_get_segment_text(wctx->ctx_wsp, i); + if (av_isspace(text[0])) + text++; + char *text_cleaned = av_strireplace(text, "[BLANK_AUDIO]", ""); + + if (av_strnlen(text_cleaned, 1) == 0) { + av_freep(&text_cleaned); + continue; + } + + // Skip segments that are parts of [BLANK_AUDIO] when max_len splits them + if (wctx->max_len > 0 && (strcmp(text_cleaned, "[") == 0 || strcmp(text_cleaned, "]") == 0 || + strcmp(text_cleaned, "BLANK") == 0 || strcmp(text_cleaned, "_") == 0 || + strcmp(text_cleaned, "AUDIO") == 0)) { + av_freep(&text_cleaned); + continue; + } + + const bool turn = whisper_full_get_segment_speaker_turn_next(wctx->ctx_wsp, i); + const int64_t t0_ms = whisper_full_get_segment_t0(wctx->ctx_wsp, i) * 10; + const int64_t t1_ms = whisper_full_get_segment_t1(wctx->ctx_wsp, i) * 10; + + av_log(ctx, AV_LOG_DEBUG, " [%" PRId64 "-%" PRId64 "%s]: \"%s\"\n", + timestamp_ms + t0_ms, timestamp_ms + t1_ms, turn ? " (turn)" : "", text_cleaned); + + if (segments_text) { + char *new_text = av_asprintf("%s%s", segments_text, text_cleaned); + av_freep(&segments_text); + segments_text = new_text; + } else + segments_text = av_strdup(text_cleaned); + + if (wctx->avio_context) { + const int64_t start_t = timestamp_ms + t0_ms; + const int64_t end_t = timestamp_ms + t1_ms; + char *buf = NULL; + + if (!av_strcasecmp(wctx->format, "srt")) { + buf = + av_asprintf + ("%d\n%02" PRId64 ":%02" PRId64 ":%02" PRId64 ",%03" PRId64 " --> %02" PRId64 ":%02" PRId64 ":%02" PRId64 ",%03" PRId64 "\n%s\n\n", + wctx->index, start_t / 3600000, + (start_t / 60000) % 60, (start_t / 1000) % 60, + start_t % 1000, end_t / 3600000, (end_t / 60000) % 60, + (end_t / 1000) % 60, end_t % 1000, text_cleaned); + + wctx->index++; + } else if (!av_strcasecmp(wctx->format, "json")) { + buf = av_asprintf("{\"start\":%" PRId64 ",\"end\":%" PRId64 ",\"text\":\"%s\"}\n", start_t, end_t, text_cleaned); + } else + buf = av_asprintf("%s\n", text_cleaned); + + if (buf) { + avio_write(wctx->avio_context, buf, strlen(buf)); + av_freep(&buf); + } + } + + av_freep(&text_cleaned); + } + + AVDictionary **metadata = &frame->metadata; + if (metadata && segments_text) { + av_dict_set(metadata, "lavfi.whisper.text", segments_text, 0); + char *duration_text = av_asprintf("%f", duration); + av_dict_set(metadata, "lavfi.whisper.duration", duration_text, AV_DICT_DONT_STRDUP_VAL); + } + av_freep(&segments_text); + + if (wctx->audio_buffer_fill_size > samples) { + memcpy(wctx->audio_buffer, wctx->audio_buffer + samples, + (wctx->audio_buffer_fill_size - samples) * sizeof(*wctx->audio_buffer)); + wctx->audio_buffer_start_ms += duration * 1000; + } + wctx->audio_buffer_fill_size -= samples; + wctx->audio_buffer_vad_size = wctx->audio_buffer_fill_size; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +{ + AVFilterContext *ctx = inlink->dst; + WhisperContext *wctx = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + + const int samples = frame->nb_samples; + const float *input_data = (const float *) frame->data[0]; + + if (wctx->audio_buffer_fill_size + samples > wctx->audio_buffer_queue_size) { + run_transcription(ctx, frame, wctx->audio_buffer_fill_size); + } + + if (!wctx->audio_buffer_fill_size) + wctx->audio_buffer_start_ms = av_rescale_q(frame->pts, + (AVRational) {1000, 1}, + (AVRational) {inlink->time_base.den, inlink->time_base.num}); + memcpy(wctx->audio_buffer + wctx->audio_buffer_fill_size, input_data, samples * sizeof(*wctx->audio_buffer)); + wctx->audio_buffer_fill_size += samples; + + if (wctx->ctx_vad + && (wctx->audio_buffer_fill_size - wctx->audio_buffer_vad_size) >= + av_rescale(wctx->vad_min_speech_duration + wctx->vad_min_silence_duration, WHISPER_SAMPLE_RATE, AV_TIME_BASE)) { + struct whisper_vad_segments *segments = whisper_vad_segments_from_samples(wctx->ctx_vad, + wctx->vad_params, + wctx->audio_buffer, + wctx->audio_buffer_fill_size); + wctx->audio_buffer_vad_size = wctx->audio_buffer_fill_size; + + if (!segments) { + av_log(ctx, AV_LOG_ERROR, "failed to detect VAD\n"); + } else { + int n_segments = whisper_vad_segments_n_segments(segments); + + if (n_segments > 0) { + const float start_ms = whisper_vad_segments_get_segment_t0(segments, 0) * 10.0; + const float end_ms = whisper_vad_segments_get_segment_t1(segments, n_segments - 1) * 10.0; + int end_pos = (int) (end_ms * WHISPER_SAMPLE_RATE / 1000); + + if (end_pos <= wctx->audio_buffer_fill_size - + av_rescale(wctx->vad_min_silence_duration, WHISPER_SAMPLE_RATE, AV_TIME_BASE)) { + av_log(ctx, AV_LOG_INFO, + "VAD detected %d segments, start: %.0f ms, end: %.0f ms (buffer: %d ms)\n", + n_segments, start_ms, end_ms, 1000 * wctx->audio_buffer_fill_size / WHISPER_SAMPLE_RATE); + run_transcription(ctx, frame, end_pos); + } + } + + whisper_vad_free_segments(segments); + } + } else if (wctx->audio_buffer_fill_size >= wctx->audio_buffer_queue_size) + run_transcription(ctx, frame, wctx->audio_buffer_fill_size); + + wctx->next_pts = frame->pts + av_rescale_q(samples, (AVRational) { + 1, inlink->sample_rate} + , inlink->time_base); + return ff_filter_frame(outlink, frame); +} + +static int push_last_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + WhisperContext *wctx = ctx->priv; + AVFrame *frame; + int n_out = 1; + + if (ctx->is_disabled || wctx->audio_buffer_fill_size == 0) + return 0; + frame = ff_get_audio_buffer(outlink, n_out); + if (!frame) + return AVERROR(ENOMEM); + + av_samples_set_silence(frame->extended_data, 0, n_out, frame->ch_layout.nb_channels, frame->format); + + frame->pts = wctx->next_pts; + if (wctx->next_pts != AV_NOPTS_VALUE) + wctx->next_pts += av_rescale_q(n_out, (AVRational) { + 1, outlink->sample_rate} + , outlink->time_base); + + run_transcription(ctx, frame, wctx->audio_buffer_fill_size); + + return ff_filter_frame(outlink, frame); +} + +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + WhisperContext *wctx = ctx->priv; + int64_t pts; + int status; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (!wctx->eof && ff_inlink_queued_frames(inlink)) { + AVFrame *frame = NULL; + int ret; + + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + if (ret > 0) + return filter_frame(inlink, frame); + } + + if (!wctx->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) + wctx->eof = status == AVERROR_EOF; + + if (wctx->eof) { + push_last_frame(outlink); + + ff_outlink_set_status(outlink, AVERROR_EOF, wctx->next_pts); + return 0; + } + + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) +{ + static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; + AVChannelLayout chlayouts[] = { FF_COUNT2LAYOUT(1), { 0 } }; + int sample_rates[] = { WHISPER_SAMPLE_RATE, -1 }; + int ret; + + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + if (ret < 0) + return ret; + + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); + if (ret < 0) + return ret; + + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); +} + +#define OFFSET(x) offsetof(WhisperContext, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM +#define HOURS 3600000000 + +static const AVOption whisper_options[] = { + { "model", "Path to the whisper.cpp model file", OFFSET(model_path), AV_OPT_TYPE_STRING,.flags = FLAGS }, + { "language", "Language for transcription ('auto' for auto-detect)", OFFSET(language), AV_OPT_TYPE_STRING, {.str = "auto"}, .flags = FLAGS }, + { "queue", "Audio queue size", OFFSET(queue), AV_OPT_TYPE_DURATION, {.i64 = 3000000}, 20000, HOURS, .flags = FLAGS }, + { "use_gpu", "Use GPU for processing", OFFSET(use_gpu), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, .flags = FLAGS }, + { "gpu_device", "GPU device to use", OFFSET(gpu_device), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, .flags = FLAGS }, + { "destination", "Output destination", OFFSET(destination), AV_OPT_TYPE_STRING, {.str = ""}, .flags = FLAGS }, + { "format", "Output format (text|srt|json)", OFFSET(format), AV_OPT_TYPE_STRING, {.str = "text"},.flags = FLAGS }, + { "max_len", "Max segment length in characters", OFFSET(max_len), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, .flags = FLAGS }, + { "vad_model", "Path to the VAD model file", OFFSET(vad_model_path), AV_OPT_TYPE_STRING,.flags = FLAGS }, + { "vad_threshold", "VAD threshold", OFFSET(vad_threshold), AV_OPT_TYPE_FLOAT, {.dbl = 0.5}, 0.0, 1.0, .flags = FLAGS }, + { "vad_min_speech_duration", "Minimum speech duration for VAD", OFFSET(vad_min_speech_duration), AV_OPT_TYPE_DURATION, {.i64 = 100000}, 20000, HOURS, .flags = FLAGS }, + { "vad_min_silence_duration", "Minimum silence duration for VAD", OFFSET(vad_min_silence_duration), AV_OPT_TYPE_DURATION, {.i64 = 500000}, 0, HOURS, .flags = FLAGS }, + { NULL } +}; + +static const AVClass whisper_class = { + .class_name = "whisper", + .item_name = av_default_item_name, + .option = whisper_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFFilter ff_af_whisper = { + .p.name = "whisper", + .p.description = NULL_IF_CONFIG_SMALL("Transcribe audio using whisper.cpp."), + .p.priv_class = &whisper_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, + .init = init, + .uninit = uninit, + .activate = activate, + .priv_size = sizeof(WhisperContext), + FILTER_INPUTS(ff_audio_default_filterpad), + FILTER_OUTPUTS(ff_audio_default_filterpad), + FILTER_QUERY_FUNC2(query_formats), +}; diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 9819f0f95..e26859e15 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -20,602 +20,619 @@ */ #include "avfilter.h" +#include "filters.h" -extern const AVFilter ff_af_aap; -extern const AVFilter ff_af_abench; -extern const AVFilter ff_af_acompressor; -extern const AVFilter ff_af_acontrast; -extern const AVFilter ff_af_acopy; -extern const AVFilter ff_af_acue; -extern const AVFilter ff_af_acrossfade; -extern const AVFilter ff_af_acrossover; -extern const AVFilter ff_af_acrusher; -extern const AVFilter ff_af_adeclick; -extern const AVFilter ff_af_adeclip; -extern const AVFilter ff_af_adecorrelate; -extern const AVFilter ff_af_adelay; -extern const AVFilter ff_af_adenorm; -extern const AVFilter ff_af_aderivative; -extern const AVFilter ff_af_adrc; -extern const AVFilter ff_af_adynamicequalizer; -extern const AVFilter ff_af_adynamicsmooth; -extern const AVFilter ff_af_aecho; -extern const AVFilter ff_af_aemphasis; -extern const AVFilter ff_af_aeval; -extern const AVFilter ff_af_aexciter; -extern const AVFilter ff_af_afade; -extern const AVFilter ff_af_afftdn; -extern const AVFilter ff_af_afftfilt; -extern const AVFilter ff_af_afir; -extern const AVFilter ff_af_aformat; -extern const AVFilter ff_af_afreqshift; -extern const AVFilter ff_af_afwtdn; -extern const AVFilter ff_af_agate; -extern const AVFilter ff_af_aiir; -extern const AVFilter ff_af_aintegral; -extern const AVFilter ff_af_ainterleave; -extern const AVFilter ff_af_alatency; -extern const AVFilter ff_af_alimiter; -extern const AVFilter ff_af_allpass; -extern const AVFilter ff_af_aloop; -extern const AVFilter ff_af_amerge; -extern const AVFilter ff_af_ametadata; -extern const AVFilter ff_af_amix; -extern const AVFilter ff_af_amultiply; -extern const AVFilter ff_af_anequalizer; -extern const AVFilter ff_af_anlmdn; -extern const AVFilter ff_af_anlmf; -extern const AVFilter ff_af_anlms; -extern const AVFilter ff_af_anull; -extern const AVFilter ff_af_apad; -extern const AVFilter ff_af_aperms; -extern const AVFilter ff_af_aphaser; -extern const AVFilter ff_af_aphaseshift; -extern const AVFilter ff_af_apsnr; -extern const AVFilter ff_af_apsyclip; -extern const AVFilter ff_af_apulsator; -extern const AVFilter ff_af_arealtime; -extern const AVFilter ff_af_aresample; -extern const AVFilter ff_af_areverse; -extern const AVFilter ff_af_arls; -extern const AVFilter ff_af_arnndn; -extern const AVFilter ff_af_asdr; -extern const AVFilter ff_af_asegment; -extern const AVFilter ff_af_aselect; -extern const AVFilter ff_af_asendcmd; -extern const AVFilter ff_af_asetnsamples; -extern const AVFilter ff_af_asetpts; -extern const AVFilter ff_af_asetrate; -extern const AVFilter ff_af_asettb; -extern const AVFilter ff_af_ashowinfo; -extern const AVFilter ff_af_asidedata; -extern const AVFilter ff_af_asisdr; -extern const AVFilter ff_af_asoftclip; -extern const AVFilter ff_af_aspectralstats; -extern const AVFilter ff_af_asplit; -extern const AVFilter ff_af_asr; -extern const AVFilter ff_af_astats; -extern const AVFilter ff_af_astreamselect; -extern const AVFilter ff_af_asubboost; -extern const AVFilter ff_af_asubcut; -extern const AVFilter ff_af_asupercut; -extern const AVFilter ff_af_asuperpass; -extern const AVFilter ff_af_asuperstop; -extern const AVFilter ff_af_atempo; -extern const AVFilter ff_af_atilt; -extern const AVFilter ff_af_atrim; -extern const AVFilter ff_af_axcorrelate; -extern const AVFilter ff_af_azmq; -extern const AVFilter ff_af_bandpass; -extern const AVFilter ff_af_bandreject; -extern const AVFilter ff_af_bass; -extern const AVFilter ff_af_biquad; -extern const AVFilter ff_af_bs2b; -extern const AVFilter ff_af_channelmap; -extern const AVFilter ff_af_channelsplit; -extern const AVFilter ff_af_chorus; -extern const AVFilter ff_af_compand; -extern const AVFilter ff_af_compensationdelay; -extern const AVFilter ff_af_crossfeed; -extern const AVFilter ff_af_crystalizer; -extern const AVFilter ff_af_dcshift; -extern const AVFilter ff_af_deesser; -extern const AVFilter ff_af_dialoguenhance; -extern const AVFilter ff_af_drmeter; -extern const AVFilter ff_af_dynaudnorm; -extern const AVFilter ff_af_earwax; -extern const AVFilter ff_af_ebur128; -extern const AVFilter ff_af_equalizer; -extern const AVFilter ff_af_extrastereo; -extern const AVFilter ff_af_firequalizer; -extern const AVFilter ff_af_flanger; -extern const AVFilter ff_af_haas; -extern const AVFilter ff_af_hdcd; -extern const AVFilter ff_af_headphone; -extern const AVFilter ff_af_highpass; -extern const AVFilter ff_af_highshelf; -extern const AVFilter ff_af_join; -extern const AVFilter ff_af_ladspa; -extern const AVFilter ff_af_loudnorm; -extern const AVFilter ff_af_lowpass; -extern const AVFilter ff_af_lowshelf; -extern const AVFilter ff_af_lv2; -extern const AVFilter ff_af_mcompand; -extern const AVFilter ff_af_pan; -extern const AVFilter ff_af_replaygain; -extern const AVFilter ff_af_rubberband; -extern const AVFilter ff_af_sidechaincompress; -extern const AVFilter ff_af_sidechaingate; -extern const AVFilter ff_af_silencedetect; -extern const AVFilter ff_af_silenceremove; -extern const AVFilter ff_af_sofalizer; -extern const AVFilter ff_af_speechnorm; -extern const AVFilter ff_af_stereotools; -extern const AVFilter ff_af_stereowiden; -extern const AVFilter ff_af_superequalizer; -extern const AVFilter ff_af_surround; -extern const AVFilter ff_af_tiltshelf; -extern const AVFilter ff_af_treble; -extern const AVFilter ff_af_tremolo; -extern const AVFilter ff_af_vibrato; -extern const AVFilter ff_af_virtualbass; -extern const AVFilter ff_af_volume; -extern const AVFilter ff_af_volumedetect; +extern const FFFilter ff_af_aap; +extern const FFFilter ff_af_abench; +extern const FFFilter ff_af_acompressor; +extern const FFFilter ff_af_acontrast; +extern const FFFilter ff_af_acopy; +extern const FFFilter ff_af_acue; +extern const FFFilter ff_af_acrossfade; +extern const FFFilter ff_af_acrossover; +extern const FFFilter ff_af_acrusher; +extern const FFFilter ff_af_adeclick; +extern const FFFilter ff_af_adeclip; +extern const FFFilter ff_af_adecorrelate; +extern const FFFilter ff_af_adelay; +extern const FFFilter ff_af_adenorm; +extern const FFFilter ff_af_aderivative; +extern const FFFilter ff_af_adrc; +extern const FFFilter ff_af_adynamicequalizer; +extern const FFFilter ff_af_adynamicsmooth; +extern const FFFilter ff_af_aecho; +extern const FFFilter ff_af_aemphasis; +extern const FFFilter ff_af_aeval; +extern const FFFilter ff_af_aexciter; +extern const FFFilter ff_af_afade; +extern const FFFilter ff_af_afftdn; +extern const FFFilter ff_af_afftfilt; +extern const FFFilter ff_af_afir; +extern const FFFilter ff_af_aformat; +extern const FFFilter ff_af_afreqshift; +extern const FFFilter ff_af_afwtdn; +extern const FFFilter ff_af_agate; +extern const FFFilter ff_af_aiir; +extern const FFFilter ff_af_aintegral; +extern const FFFilter ff_af_ainterleave; +extern const FFFilter ff_af_alatency; +extern const FFFilter ff_af_alimiter; +extern const FFFilter ff_af_allpass; +extern const FFFilter ff_af_aloop; +extern const FFFilter ff_af_amerge; +extern const FFFilter ff_af_ametadata; +extern const FFFilter ff_af_amix; +extern const FFFilter ff_af_amultiply; +extern const FFFilter ff_af_anequalizer; +extern const FFFilter ff_af_anlmdn; +extern const FFFilter ff_af_anlmf; +extern const FFFilter ff_af_anlms; +extern const FFFilter ff_af_anull; +extern const FFFilter ff_af_apad; +extern const FFFilter ff_af_aperms; +extern const FFFilter ff_af_aphaser; +extern const FFFilter ff_af_aphaseshift; +extern const FFFilter ff_af_apsnr; +extern const FFFilter ff_af_apsyclip; +extern const FFFilter ff_af_apulsator; +extern const FFFilter ff_af_arealtime; +extern const FFFilter ff_af_aresample; +extern const FFFilter ff_af_areverse; +extern const FFFilter ff_af_arls; +extern const FFFilter ff_af_arnndn; +extern const FFFilter ff_af_asdr; +extern const FFFilter ff_af_asegment; +extern const FFFilter ff_af_aselect; +extern const FFFilter ff_af_asendcmd; +extern const FFFilter ff_af_asetnsamples; +extern const FFFilter ff_af_asetpts; +extern const FFFilter ff_af_asetrate; +extern const FFFilter ff_af_asettb; +extern const FFFilter ff_af_ashowinfo; +extern const FFFilter ff_af_asidedata; +extern const FFFilter ff_af_asisdr; +extern const FFFilter ff_af_asoftclip; +extern const FFFilter ff_af_aspectralstats; +extern const FFFilter ff_af_asplit; +extern const FFFilter ff_af_asr; +extern const FFFilter ff_af_astats; +extern const FFFilter ff_af_astreamselect; +extern const FFFilter ff_af_asubboost; +extern const FFFilter ff_af_asubcut; +extern const FFFilter ff_af_asupercut; +extern const FFFilter ff_af_asuperpass; +extern const FFFilter ff_af_asuperstop; +extern const FFFilter ff_af_atempo; +extern const FFFilter ff_af_atilt; +extern const FFFilter ff_af_atrim; +extern const FFFilter ff_af_axcorrelate; +extern const FFFilter ff_af_azmq; +extern const FFFilter ff_af_bandpass; +extern const FFFilter ff_af_bandreject; +extern const FFFilter ff_af_bass; +extern const FFFilter ff_af_biquad; +extern const FFFilter ff_af_bs2b; +extern const FFFilter ff_af_channelmap; +extern const FFFilter ff_af_channelsplit; +extern const FFFilter ff_af_chorus; +extern const FFFilter ff_af_compand; +extern const FFFilter ff_af_compensationdelay; +extern const FFFilter ff_af_crossfeed; +extern const FFFilter ff_af_crystalizer; +extern const FFFilter ff_af_dcshift; +extern const FFFilter ff_af_deesser; +extern const FFFilter ff_af_dialoguenhance; +extern const FFFilter ff_af_drmeter; +extern const FFFilter ff_af_dynaudnorm; +extern const FFFilter ff_af_earwax; +extern const FFFilter ff_af_ebur128; +extern const FFFilter ff_af_equalizer; +extern const FFFilter ff_af_extrastereo; +extern const FFFilter ff_af_firequalizer; +extern const FFFilter ff_af_flanger; +extern const FFFilter ff_af_haas; +extern const FFFilter ff_af_hdcd; +extern const FFFilter ff_af_headphone; +extern const FFFilter ff_af_highpass; +extern const FFFilter ff_af_highshelf; +extern const FFFilter ff_af_join; +extern const FFFilter ff_af_ladspa; +extern const FFFilter ff_af_loudnorm; +extern const FFFilter ff_af_lowpass; +extern const FFFilter ff_af_lowshelf; +extern const FFFilter ff_af_lv2; +extern const FFFilter ff_af_mcompand; +extern const FFFilter ff_af_pan; +extern const FFFilter ff_af_replaygain; +extern const FFFilter ff_af_rubberband; +extern const FFFilter ff_af_sidechaincompress; +extern const FFFilter ff_af_sidechaingate; +extern const FFFilter ff_af_silencedetect; +extern const FFFilter ff_af_silenceremove; +extern const FFFilter ff_af_sofalizer; +extern const FFFilter ff_af_speechnorm; +extern const FFFilter ff_af_stereotools; +extern const FFFilter ff_af_stereowiden; +extern const FFFilter ff_af_superequalizer; +extern const FFFilter ff_af_surround; +extern const FFFilter ff_af_tiltshelf; +extern const FFFilter ff_af_treble; +extern const FFFilter ff_af_tremolo; +extern const FFFilter ff_af_vibrato; +extern const FFFilter ff_af_virtualbass; +extern const FFFilter ff_af_volume; +extern const FFFilter ff_af_volumedetect; +extern const FFFilter ff_af_whisper; -extern const AVFilter ff_asrc_aevalsrc; -extern const AVFilter ff_asrc_afdelaysrc; -extern const AVFilter ff_asrc_afireqsrc; -extern const AVFilter ff_asrc_afirsrc; -extern const AVFilter ff_asrc_anoisesrc; -extern const AVFilter ff_asrc_anullsrc; -extern const AVFilter ff_asrc_flite; -extern const AVFilter ff_asrc_hilbert; -extern const AVFilter ff_asrc_sinc; -extern const AVFilter ff_asrc_sine; +extern const FFFilter ff_asrc_aevalsrc; +extern const FFFilter ff_asrc_afdelaysrc; +extern const FFFilter ff_asrc_afireqsrc; +extern const FFFilter ff_asrc_afirsrc; +extern const FFFilter ff_asrc_anoisesrc; +extern const FFFilter ff_asrc_anullsrc; +extern const FFFilter ff_asrc_flite; +extern const FFFilter ff_asrc_hilbert; +extern const FFFilter ff_asrc_sinc; +extern const FFFilter ff_asrc_sine; -extern const AVFilter ff_asink_anullsink; +extern const FFFilter ff_asink_anullsink; -extern const AVFilter ff_vf_addroi; -extern const AVFilter ff_vf_alphaextract; -extern const AVFilter ff_vf_alphamerge; -extern const AVFilter ff_vf_amplify; -extern const AVFilter ff_vf_ass; -extern const AVFilter ff_vf_atadenoise; -extern const AVFilter ff_vf_avgblur; -extern const AVFilter ff_vf_avgblur_opencl; -extern const AVFilter ff_vf_avgblur_vulkan; -extern const AVFilter ff_vf_backgroundkey; -extern const AVFilter ff_vf_bbox; -extern const AVFilter ff_vf_bench; -extern const AVFilter ff_vf_bilateral; -extern const AVFilter ff_vf_bilateral_cuda; -extern const AVFilter ff_vf_bitplanenoise; -extern const AVFilter ff_vf_blackdetect; -extern const AVFilter ff_vf_blackframe; -extern const AVFilter ff_vf_blend; -extern const AVFilter ff_vf_blend_vulkan; -extern const AVFilter ff_vf_blockdetect; -extern const AVFilter ff_vf_blurdetect; -extern const AVFilter ff_vf_bm3d; -extern const AVFilter ff_vf_boxblur; -extern const AVFilter ff_vf_boxblur_opencl; -extern const AVFilter ff_vf_bwdif; -extern const AVFilter ff_vf_bwdif_cuda; -extern const AVFilter ff_vf_bwdif_vulkan; -extern const AVFilter ff_vf_cas; -extern const AVFilter ff_vf_ccrepack; -extern const AVFilter ff_vf_chromaber_vulkan; -extern const AVFilter ff_vf_chromahold; -extern const AVFilter ff_vf_chromakey; -extern const AVFilter ff_vf_chromakey_cuda; -extern const AVFilter ff_vf_chromanr; -extern const AVFilter ff_vf_chromashift; -extern const AVFilter ff_vf_ciescope; -extern const AVFilter ff_vf_codecview; -extern const AVFilter ff_vf_colorbalance; -extern const AVFilter ff_vf_colorchannelmixer; -extern const AVFilter ff_vf_colorcontrast; -extern const AVFilter ff_vf_colorcorrect; -extern const AVFilter ff_vf_colorize; -extern const AVFilter ff_vf_colorkey; -extern const AVFilter ff_vf_colorkey_opencl; -extern const AVFilter ff_vf_colorhold; -extern const AVFilter ff_vf_colorlevels; -extern const AVFilter ff_vf_colormap; -extern const AVFilter ff_vf_colormatrix; -extern const AVFilter ff_vf_colorspace; -extern const AVFilter ff_vf_colorspace_cuda; -extern const AVFilter ff_vf_colortemperature; -extern const AVFilter ff_vf_convolution; -extern const AVFilter ff_vf_convolution_opencl; -extern const AVFilter ff_vf_convolve; -extern const AVFilter ff_vf_copy; -extern const AVFilter ff_vf_coreimage; -extern const AVFilter ff_vf_corr; -extern const AVFilter ff_vf_cover_rect; -extern const AVFilter ff_vf_crop; -extern const AVFilter ff_vf_cropdetect; -extern const AVFilter ff_vf_cue; -extern const AVFilter ff_vf_curves; -extern const AVFilter ff_vf_datascope; -extern const AVFilter ff_vf_dblur; -extern const AVFilter ff_vf_dctdnoiz; -extern const AVFilter ff_vf_deband; -extern const AVFilter ff_vf_deblock; -extern const AVFilter ff_vf_decimate; -extern const AVFilter ff_vf_deconvolve; -extern const AVFilter ff_vf_dedot; -extern const AVFilter ff_vf_deflate; -extern const AVFilter ff_vf_deflicker; -extern const AVFilter ff_vf_deinterlace_qsv; -extern const AVFilter ff_vf_deinterlace_vaapi; -extern const AVFilter ff_vf_dejudder; -extern const AVFilter ff_vf_delogo; -extern const AVFilter ff_vf_denoise_vaapi; -extern const AVFilter ff_vf_derain; -extern const AVFilter ff_vf_deshake; -extern const AVFilter ff_vf_deshake_opencl; -extern const AVFilter ff_vf_despill; -extern const AVFilter ff_vf_detelecine; -extern const AVFilter ff_vf_dilation; -extern const AVFilter ff_vf_dilation_opencl; -extern const AVFilter ff_vf_displace; -extern const AVFilter ff_vf_dnn_classify; -extern const AVFilter ff_vf_dnn_detect; -extern const AVFilter ff_vf_dnn_processing; -extern const AVFilter ff_vf_doubleweave; -extern const AVFilter ff_vf_drawbox; -extern const AVFilter ff_vf_drawgraph; -extern const AVFilter ff_vf_drawgrid; -extern const AVFilter ff_vf_drawtext; -extern const AVFilter ff_vf_edgedetect; -extern const AVFilter ff_vf_elbg; -extern const AVFilter ff_vf_entropy; -extern const AVFilter ff_vf_epx; -extern const AVFilter ff_vf_eq; -extern const AVFilter ff_vf_erosion; -extern const AVFilter ff_vf_erosion_opencl; -extern const AVFilter ff_vf_estdif; -extern const AVFilter ff_vf_exposure; -extern const AVFilter ff_vf_extractplanes; -extern const AVFilter ff_vf_fade; -extern const AVFilter ff_vf_feedback; -extern const AVFilter ff_vf_fftdnoiz; -extern const AVFilter ff_vf_fftfilt; -extern const AVFilter ff_vf_field; -extern const AVFilter ff_vf_fieldhint; -extern const AVFilter ff_vf_fieldmatch; -extern const AVFilter ff_vf_fieldorder; -extern const AVFilter ff_vf_fillborders; -extern const AVFilter ff_vf_find_rect; -extern const AVFilter ff_vf_flip_vulkan; -extern const AVFilter ff_vf_floodfill; -extern const AVFilter ff_vf_format; -extern const AVFilter ff_vf_fps; -extern const AVFilter ff_vf_framepack; -extern const AVFilter ff_vf_framerate; -extern const AVFilter ff_vf_framestep; -extern const AVFilter ff_vf_freezedetect; -extern const AVFilter ff_vf_freezeframes; -extern const AVFilter ff_vf_frei0r; -extern const AVFilter ff_vf_fspp; -extern const AVFilter ff_vf_fsync; -extern const AVFilter ff_vf_gblur; -extern const AVFilter ff_vf_gblur_vulkan; -extern const AVFilter ff_vf_geq; -extern const AVFilter ff_vf_gradfun; -extern const AVFilter ff_vf_graphmonitor; -extern const AVFilter ff_vf_grayworld; -extern const AVFilter ff_vf_greyedge; -extern const AVFilter ff_vf_guided; -extern const AVFilter ff_vf_haldclut; -extern const AVFilter ff_vf_hflip; -extern const AVFilter ff_vf_hflip_vulkan; -extern const AVFilter ff_vf_histeq; -extern const AVFilter ff_vf_histogram; -extern const AVFilter ff_vf_hqdn3d; -extern const AVFilter ff_vf_hqx; -extern const AVFilter ff_vf_hstack; -extern const AVFilter ff_vf_hsvhold; -extern const AVFilter ff_vf_hsvkey; -extern const AVFilter ff_vf_hue; -extern const AVFilter ff_vf_huesaturation; -extern const AVFilter ff_vf_hwdownload; -extern const AVFilter ff_vf_hwmap; -extern const AVFilter ff_vf_hwupload; -extern const AVFilter ff_vf_hwupload_cuda; -extern const AVFilter ff_vf_hysteresis; -extern const AVFilter ff_vf_iccdetect; -extern const AVFilter ff_vf_iccgen; -extern const AVFilter ff_vf_identity; -extern const AVFilter ff_vf_idet; -extern const AVFilter ff_vf_il; -extern const AVFilter ff_vf_inflate; -extern const AVFilter ff_vf_interlace; -extern const AVFilter ff_vf_interleave; -extern const AVFilter ff_vf_kerndeint; -extern const AVFilter ff_vf_kirsch; -extern const AVFilter ff_vf_lagfun; -extern const AVFilter ff_vf_latency; -extern const AVFilter ff_vf_lcevc; -extern const AVFilter ff_vf_lenscorrection; -extern const AVFilter ff_vf_lensfun; -extern const AVFilter ff_vf_libplacebo; -extern const AVFilter ff_vf_libvmaf; -extern const AVFilter ff_vf_libvmaf_cuda; -extern const AVFilter ff_vf_limitdiff; -extern const AVFilter ff_vf_limiter; -extern const AVFilter ff_vf_loop; -extern const AVFilter ff_vf_lumakey; -extern const AVFilter ff_vf_lut; -extern const AVFilter ff_vf_lut1d; -extern const AVFilter ff_vf_lut2; -extern const AVFilter ff_vf_lut3d; -extern const AVFilter ff_vf_lutrgb; -extern const AVFilter ff_vf_lutyuv; -extern const AVFilter ff_vf_maskedclamp; -extern const AVFilter ff_vf_maskedmax; -extern const AVFilter ff_vf_maskedmerge; -extern const AVFilter ff_vf_maskedmin; -extern const AVFilter ff_vf_maskedthreshold; -extern const AVFilter ff_vf_maskfun; -extern const AVFilter ff_vf_mcdeint; -extern const AVFilter ff_vf_median; -extern const AVFilter ff_vf_mergeplanes; -extern const AVFilter ff_vf_mestimate; -extern const AVFilter ff_vf_metadata; -extern const AVFilter ff_vf_midequalizer; -extern const AVFilter ff_vf_minterpolate; -extern const AVFilter ff_vf_mix; -extern const AVFilter ff_vf_monochrome; -extern const AVFilter ff_vf_morpho; -extern const AVFilter ff_vf_mpdecimate; -extern const AVFilter ff_vf_msad; -extern const AVFilter ff_vf_multiply; -extern const AVFilter ff_vf_negate; -extern const AVFilter ff_vf_nlmeans; -extern const AVFilter ff_vf_nlmeans_opencl; -extern const AVFilter ff_vf_nlmeans_vulkan; -extern const AVFilter ff_vf_nnedi; -extern const AVFilter ff_vf_noformat; -extern const AVFilter ff_vf_noise; -extern const AVFilter ff_vf_normalize; -extern const AVFilter ff_vf_null; -extern const AVFilter ff_vf_ocr; -extern const AVFilter ff_vf_ocv; -extern const AVFilter ff_vf_oscilloscope; -extern const AVFilter ff_vf_overlay; -extern const AVFilter ff_vf_overlay_opencl; -extern const AVFilter ff_vf_overlay_qsv; -extern const AVFilter ff_vf_overlay_vaapi; -extern const AVFilter ff_vf_overlay_vulkan; -extern const AVFilter ff_vf_overlay_cuda; -extern const AVFilter ff_vf_owdenoise; -extern const AVFilter ff_vf_pad; -extern const AVFilter ff_vf_pad_opencl; -extern const AVFilter ff_vf_palettegen; -extern const AVFilter ff_vf_paletteuse; -extern const AVFilter ff_vf_perms; -extern const AVFilter ff_vf_perspective; -extern const AVFilter ff_vf_phase; -extern const AVFilter ff_vf_photosensitivity; -extern const AVFilter ff_vf_pixdesctest; -extern const AVFilter ff_vf_pixelize; -extern const AVFilter ff_vf_pixscope; -extern const AVFilter ff_vf_pp; -extern const AVFilter ff_vf_pp7; -extern const AVFilter ff_vf_premultiply; -extern const AVFilter ff_vf_prewitt; -extern const AVFilter ff_vf_prewitt_opencl; -extern const AVFilter ff_vf_procamp_vaapi; -extern const AVFilter ff_vf_program_opencl; -extern const AVFilter ff_vf_pseudocolor; -extern const AVFilter ff_vf_psnr; -extern const AVFilter ff_vf_pullup; -extern const AVFilter ff_vf_qp; -extern const AVFilter ff_vf_qrencode; -extern const AVFilter ff_vf_quirc; -extern const AVFilter ff_vf_random; -extern const AVFilter ff_vf_readeia608; -extern const AVFilter ff_vf_readvitc; -extern const AVFilter ff_vf_realtime; -extern const AVFilter ff_vf_remap; -extern const AVFilter ff_vf_remap_opencl; -extern const AVFilter ff_vf_removegrain; -extern const AVFilter ff_vf_removelogo; -extern const AVFilter ff_vf_repeatfields; -extern const AVFilter ff_vf_reverse; -extern const AVFilter ff_vf_rgbashift; -extern const AVFilter ff_vf_roberts; -extern const AVFilter ff_vf_roberts_opencl; -extern const AVFilter ff_vf_rotate; -extern const AVFilter ff_vf_sab; -extern const AVFilter ff_vf_scale; -extern const AVFilter ff_vf_scale_cuda; -extern const AVFilter ff_vf_scale_npp; -extern const AVFilter ff_vf_scale_qsv; -extern const AVFilter ff_vf_scale_vaapi; -extern const AVFilter ff_vf_scale_vt; -extern const AVFilter ff_vf_scale_vulkan; -extern const AVFilter ff_vf_scale2ref; -extern const AVFilter ff_vf_scale2ref_npp; -extern const AVFilter ff_vf_scdet; -extern const AVFilter ff_vf_scharr; -extern const AVFilter ff_vf_scroll; -extern const AVFilter ff_vf_segment; -extern const AVFilter ff_vf_select; -extern const AVFilter ff_vf_selectivecolor; -extern const AVFilter ff_vf_sendcmd; -extern const AVFilter ff_vf_separatefields; -extern const AVFilter ff_vf_setdar; -extern const AVFilter ff_vf_setfield; -extern const AVFilter ff_vf_setparams; -extern const AVFilter ff_vf_setpts; -extern const AVFilter ff_vf_setrange; -extern const AVFilter ff_vf_setsar; -extern const AVFilter ff_vf_settb; -extern const AVFilter ff_vf_sharpen_npp; -extern const AVFilter ff_vf_sharpness_vaapi; -extern const AVFilter ff_vf_shear; -extern const AVFilter ff_vf_showinfo; -extern const AVFilter ff_vf_showpalette; -extern const AVFilter ff_vf_shuffleframes; -extern const AVFilter ff_vf_shufflepixels; -extern const AVFilter ff_vf_shuffleplanes; -extern const AVFilter ff_vf_sidedata; -extern const AVFilter ff_vf_signalstats; -extern const AVFilter ff_vf_signature; -extern const AVFilter ff_vf_siti; -extern const AVFilter ff_vf_smartblur; -extern const AVFilter ff_vf_sobel; -extern const AVFilter ff_vf_sobel_opencl; -extern const AVFilter ff_vf_split; -extern const AVFilter ff_vf_spp; -extern const AVFilter ff_vf_sr; -extern const AVFilter ff_vf_ssim; -extern const AVFilter ff_vf_ssim360; -extern const AVFilter ff_vf_stereo3d; -extern const AVFilter ff_vf_streamselect; -extern const AVFilter ff_vf_subtitles; -extern const AVFilter ff_vf_super2xsai; -extern const AVFilter ff_vf_swaprect; -extern const AVFilter ff_vf_swapuv; -extern const AVFilter ff_vf_tblend; -extern const AVFilter ff_vf_telecine; -extern const AVFilter ff_vf_thistogram; -extern const AVFilter ff_vf_threshold; -extern const AVFilter ff_vf_thumbnail; -extern const AVFilter ff_vf_thumbnail_cuda; -extern const AVFilter ff_vf_tile; -extern const AVFilter ff_vf_tiltandshift; -extern const AVFilter ff_vf_tinterlace; -extern const AVFilter ff_vf_tlut2; -extern const AVFilter ff_vf_tmedian; -extern const AVFilter ff_vf_tmidequalizer; -extern const AVFilter ff_vf_tmix; -extern const AVFilter ff_vf_tonemap; -extern const AVFilter ff_vf_tonemap_opencl; -extern const AVFilter ff_vf_tonemap_vaapi; -extern const AVFilter ff_vf_tpad; -extern const AVFilter ff_vf_transpose; -extern const AVFilter ff_vf_transpose_npp; -extern const AVFilter ff_vf_transpose_opencl; -extern const AVFilter ff_vf_transpose_vaapi; -extern const AVFilter ff_vf_transpose_vt; -extern const AVFilter ff_vf_transpose_vulkan; -extern const AVFilter ff_vf_trim; -extern const AVFilter ff_vf_unpremultiply; -extern const AVFilter ff_vf_unsharp; -extern const AVFilter ff_vf_unsharp_opencl; -extern const AVFilter ff_vf_untile; -extern const AVFilter ff_vf_uspp; -extern const AVFilter ff_vf_v360; -extern const AVFilter ff_vf_vaguedenoiser; -extern const AVFilter ff_vf_varblur; -extern const AVFilter ff_vf_vectorscope; -extern const AVFilter ff_vf_vflip; -extern const AVFilter ff_vf_vflip_vulkan; -extern const AVFilter ff_vf_vfrdet; -extern const AVFilter ff_vf_vibrance; -extern const AVFilter ff_vf_vidstabdetect; -extern const AVFilter ff_vf_vidstabtransform; -extern const AVFilter ff_vf_vif; -extern const AVFilter ff_vf_vignette; -extern const AVFilter ff_vf_vmafmotion; -extern const AVFilter ff_vf_vpp_qsv; -extern const AVFilter ff_vf_vstack; -extern const AVFilter ff_vf_w3fdif; -extern const AVFilter ff_vf_waveform; -extern const AVFilter ff_vf_weave; -extern const AVFilter ff_vf_xbr; -extern const AVFilter ff_vf_xcorrelate; -extern const AVFilter ff_vf_xfade; -extern const AVFilter ff_vf_xfade_opencl; -extern const AVFilter ff_vf_xfade_vulkan; -extern const AVFilter ff_vf_xmedian; -extern const AVFilter ff_vf_xpsnr; -extern const AVFilter ff_vf_xstack; -extern const AVFilter ff_vf_yadif; -extern const AVFilter ff_vf_yadif_cuda; -extern const AVFilter ff_vf_yadif_videotoolbox; -extern const AVFilter ff_vf_yaepblur; -extern const AVFilter ff_vf_zmq; -extern const AVFilter ff_vf_zoompan; -extern const AVFilter ff_vf_zscale; -extern const AVFilter ff_vf_hstack_vaapi; -extern const AVFilter ff_vf_vstack_vaapi; -extern const AVFilter ff_vf_xstack_vaapi; -extern const AVFilter ff_vf_hstack_qsv; -extern const AVFilter ff_vf_vstack_qsv; -extern const AVFilter ff_vf_xstack_qsv; -extern const AVFilter ff_vf_pad_vaapi; -extern const AVFilter ff_vf_drawbox_vaapi; +extern const FFFilter ff_vf_addroi; +extern const FFFilter ff_vf_alphaextract; +extern const FFFilter ff_vf_alphamerge; +extern const FFFilter ff_vf_amplify; +extern const FFFilter ff_vf_ass; +extern const FFFilter ff_vf_atadenoise; +extern const FFFilter ff_vf_avgblur; +extern const FFFilter ff_vf_avgblur_opencl; +extern const FFFilter ff_vf_avgblur_vulkan; +extern const FFFilter ff_vf_backgroundkey; +extern const FFFilter ff_vf_bbox; +extern const FFFilter ff_vf_bench; +extern const FFFilter ff_vf_bilateral; +extern const FFFilter ff_vf_bilateral_cuda; +extern const FFFilter ff_vf_bitplanenoise; +extern const FFFilter ff_vf_blackdetect; +extern const FFFilter ff_vf_blackdetect_vulkan; +extern const FFFilter ff_vf_blackframe; +extern const FFFilter ff_vf_blend; +extern const FFFilter ff_vf_blend_vulkan; +extern const FFFilter ff_vf_blockdetect; +extern const FFFilter ff_vf_blurdetect; +extern const FFFilter ff_vf_bm3d; +extern const FFFilter ff_vf_boxblur; +extern const FFFilter ff_vf_boxblur_opencl; +extern const FFFilter ff_vf_bwdif; +extern const FFFilter ff_vf_bwdif_cuda; +extern const FFFilter ff_vf_bwdif_vulkan; +extern const FFFilter ff_vf_cas; +extern const FFFilter ff_vf_ccrepack; +extern const FFFilter ff_vf_chromaber_vulkan; +extern const FFFilter ff_vf_chromahold; +extern const FFFilter ff_vf_chromakey; +extern const FFFilter ff_vf_chromakey_cuda; +extern const FFFilter ff_vf_chromanr; +extern const FFFilter ff_vf_chromashift; +extern const FFFilter ff_vf_ciescope; +extern const FFFilter ff_vf_codecview; +extern const FFFilter ff_vf_colorbalance; +extern const FFFilter ff_vf_colorchannelmixer; +extern const FFFilter ff_vf_colorcontrast; +extern const FFFilter ff_vf_colorcorrect; +extern const FFFilter ff_vf_colordetect; +extern const FFFilter ff_vf_colorize; +extern const FFFilter ff_vf_colorkey; +extern const FFFilter ff_vf_colorkey_opencl; +extern const FFFilter ff_vf_colorhold; +extern const FFFilter ff_vf_colorlevels; +extern const FFFilter ff_vf_colormap; +extern const FFFilter ff_vf_colormatrix; +extern const FFFilter ff_vf_colorspace; +extern const FFFilter ff_vf_colorspace_cuda; +extern const FFFilter ff_vf_colortemperature; +extern const FFFilter ff_vf_convolution; +extern const FFFilter ff_vf_convolution_opencl; +extern const FFFilter ff_vf_convolve; +extern const FFFilter ff_vf_copy; +extern const FFFilter ff_vf_coreimage; +extern const FFFilter ff_vf_corr; +extern const FFFilter ff_vf_cover_rect; +extern const FFFilter ff_vf_crop; +extern const FFFilter ff_vf_cropdetect; +extern const FFFilter ff_vf_cue; +extern const FFFilter ff_vf_curves; +extern const FFFilter ff_vf_datascope; +extern const FFFilter ff_vf_dblur; +extern const FFFilter ff_vf_dctdnoiz; +extern const FFFilter ff_vf_deband; +extern const FFFilter ff_vf_deblock; +extern const FFFilter ff_vf_decimate; +extern const FFFilter ff_vf_deconvolve; +extern const FFFilter ff_vf_dedot; +extern const FFFilter ff_vf_deflate; +extern const FFFilter ff_vf_deflicker; +extern const FFFilter ff_vf_deinterlace_qsv; +extern const FFFilter ff_vf_deinterlace_d3d12; +extern const FFFilter ff_vf_deinterlace_vaapi; +extern const FFFilter ff_vf_dejudder; +extern const FFFilter ff_vf_delogo; +extern const FFFilter ff_vf_denoise_vaapi; +extern const FFFilter ff_vf_derain; +extern const FFFilter ff_vf_deshake; +extern const FFFilter ff_vf_deshake_opencl; +extern const FFFilter ff_vf_despill; +extern const FFFilter ff_vf_detelecine; +extern const FFFilter ff_vf_dilation; +extern const FFFilter ff_vf_dilation_opencl; +extern const FFFilter ff_vf_displace; +extern const FFFilter ff_vf_dnn_classify; +extern const FFFilter ff_vf_dnn_detect; +extern const FFFilter ff_vf_dnn_processing; +extern const FFFilter ff_vf_doubleweave; +extern const FFFilter ff_vf_drawbox; +extern const FFFilter ff_vf_drawgraph; +extern const FFFilter ff_vf_drawgrid; +extern const FFFilter ff_vf_drawtext; +extern const FFFilter ff_vf_drawvg; +extern const FFFilter ff_vf_edgedetect; +extern const FFFilter ff_vf_elbg; +extern const FFFilter ff_vf_entropy; +extern const FFFilter ff_vf_epx; +extern const FFFilter ff_vf_eq; +extern const FFFilter ff_vf_erosion; +extern const FFFilter ff_vf_erosion_opencl; +extern const FFFilter ff_vf_estdif; +extern const FFFilter ff_vf_exposure; +extern const FFFilter ff_vf_extractplanes; +extern const FFFilter ff_vf_fade; +extern const FFFilter ff_vf_feedback; +extern const FFFilter ff_vf_fftdnoiz; +extern const FFFilter ff_vf_fftfilt; +extern const FFFilter ff_vf_field; +extern const FFFilter ff_vf_fieldhint; +extern const FFFilter ff_vf_fieldmatch; +extern const FFFilter ff_vf_fieldorder; +extern const FFFilter ff_vf_fillborders; +extern const FFFilter ff_vf_find_rect; +extern const FFFilter ff_vf_flip_vulkan; +extern const FFFilter ff_vf_floodfill; +extern const FFFilter ff_vf_format; +extern const FFFilter ff_vf_fps; +extern const FFFilter ff_vf_framepack; +extern const FFFilter ff_vf_framerate; +extern const FFFilter ff_vf_framestep; +extern const FFFilter ff_vf_freezedetect; +extern const FFFilter ff_vf_freezeframes; +extern const FFFilter ff_vf_frei0r; +extern const FFFilter ff_vf_fspp; +extern const FFFilter ff_vf_fsync; +extern const FFFilter ff_vf_gblur; +extern const FFFilter ff_vf_gblur_vulkan; +extern const FFFilter ff_vf_geq; +extern const FFFilter ff_vf_gradfun; +extern const FFFilter ff_vf_graphmonitor; +extern const FFFilter ff_vf_grayworld; +extern const FFFilter ff_vf_greyedge; +extern const FFFilter ff_vf_guided; +extern const FFFilter ff_vf_haldclut; +extern const FFFilter ff_vf_hflip; +extern const FFFilter ff_vf_hflip_vulkan; +extern const FFFilter ff_vf_histeq; +extern const FFFilter ff_vf_histogram; +extern const FFFilter ff_vf_hqdn3d; +extern const FFFilter ff_vf_hqx; +extern const FFFilter ff_vf_hstack; +extern const FFFilter ff_vf_hsvhold; +extern const FFFilter ff_vf_hsvkey; +extern const FFFilter ff_vf_hue; +extern const FFFilter ff_vf_huesaturation; +extern const FFFilter ff_vf_hwdownload; +extern const FFFilter ff_vf_hwmap; +extern const FFFilter ff_vf_hwupload; +extern const FFFilter ff_vf_hwupload_cuda; +extern const FFFilter ff_vf_hysteresis; +extern const FFFilter ff_vf_iccdetect; +extern const FFFilter ff_vf_iccgen; +extern const FFFilter ff_vf_identity; +extern const FFFilter ff_vf_idet; +extern const FFFilter ff_vf_il; +extern const FFFilter ff_vf_inflate; +extern const FFFilter ff_vf_interlace; +extern const FFFilter ff_vf_interlace_vulkan; +extern const FFFilter ff_vf_interleave; +extern const FFFilter ff_vf_kerndeint; +extern const FFFilter ff_vf_kirsch; +extern const FFFilter ff_vf_lagfun; +extern const FFFilter ff_vf_latency; +extern const FFFilter ff_vf_lcevc; +extern const FFFilter ff_vf_lenscorrection; +extern const FFFilter ff_vf_lensfun; +extern const FFFilter ff_vf_libplacebo; +extern const FFFilter ff_vf_libvmaf; +extern const FFFilter ff_vf_libvmaf_cuda; +extern const FFFilter ff_vf_limitdiff; +extern const FFFilter ff_vf_limiter; +extern const FFFilter ff_vf_loop; +extern const FFFilter ff_vf_lumakey; +extern const FFFilter ff_vf_lut; +extern const FFFilter ff_vf_lut1d; +extern const FFFilter ff_vf_lut2; +extern const FFFilter ff_vf_lut3d; +extern const FFFilter ff_vf_lutrgb; +extern const FFFilter ff_vf_lutyuv; +extern const FFFilter ff_vf_maskedclamp; +extern const FFFilter ff_vf_maskedmax; +extern const FFFilter ff_vf_maskedmerge; +extern const FFFilter ff_vf_maskedmin; +extern const FFFilter ff_vf_maskedthreshold; +extern const FFFilter ff_vf_maskfun; +extern const FFFilter ff_vf_mcdeint; +extern const FFFilter ff_vf_median; +extern const FFFilter ff_vf_mergeplanes; +extern const FFFilter ff_vf_mestimate; +extern const FFFilter ff_vf_mestimate_d3d12; +extern const FFFilter ff_vf_metadata; +extern const FFFilter ff_vf_midequalizer; +extern const FFFilter ff_vf_minterpolate; +extern const FFFilter ff_vf_mix; +extern const FFFilter ff_vf_monochrome; +extern const FFFilter ff_vf_morpho; +extern const FFFilter ff_vf_mpdecimate; +extern const FFFilter ff_vf_msad; +extern const FFFilter ff_vf_multiply; +extern const FFFilter ff_vf_negate; +extern const FFFilter ff_vf_nlmeans; +extern const FFFilter ff_vf_nlmeans_opencl; +extern const FFFilter ff_vf_nlmeans_vulkan; +extern const FFFilter ff_vf_nnedi; +extern const FFFilter ff_vf_noformat; +extern const FFFilter ff_vf_noise; +extern const FFFilter ff_vf_normalize; +extern const FFFilter ff_vf_null; +extern const FFFilter ff_vf_ocr; +extern const FFFilter ff_vf_ocv; +extern const FFFilter ff_vf_oscilloscope; +extern const FFFilter ff_vf_ocio; +extern const FFFilter ff_vf_overlay; +extern const FFFilter ff_vf_overlay_opencl; +extern const FFFilter ff_vf_overlay_qsv; +extern const FFFilter ff_vf_overlay_vaapi; +extern const FFFilter ff_vf_overlay_vulkan; +extern const FFFilter ff_vf_overlay_cuda; +extern const FFFilter ff_vf_owdenoise; +extern const FFFilter ff_vf_pad; +extern const FFFilter ff_vf_pad_cuda; +extern const FFFilter ff_vf_pad_opencl; +extern const FFFilter ff_vf_palettegen; +extern const FFFilter ff_vf_paletteuse; +extern const FFFilter ff_vf_perms; +extern const FFFilter ff_vf_perspective; +extern const FFFilter ff_vf_phase; +extern const FFFilter ff_vf_photosensitivity; +extern const FFFilter ff_vf_pixdesctest; +extern const FFFilter ff_vf_pixelize; +extern const FFFilter ff_vf_pixscope; +extern const FFFilter ff_vf_pp7; +extern const FFFilter ff_vf_premultiply; +extern const FFFilter ff_vf_premultiply_dynamic; +extern const FFFilter ff_vf_prewitt; +extern const FFFilter ff_vf_prewitt_opencl; +extern const FFFilter ff_vf_procamp_vaapi; +extern const FFFilter ff_vf_program_opencl; +extern const FFFilter ff_vf_pseudocolor; +extern const FFFilter ff_vf_psnr; +extern const FFFilter ff_vf_pullup; +extern const FFFilter ff_vf_qp; +extern const FFFilter ff_vf_qrencode; +extern const FFFilter ff_vf_quirc; +extern const FFFilter ff_vf_random; +extern const FFFilter ff_vf_readeia608; +extern const FFFilter ff_vf_readvitc; +extern const FFFilter ff_vf_realtime; +extern const FFFilter ff_vf_remap; +extern const FFFilter ff_vf_remap_opencl; +extern const FFFilter ff_vf_removegrain; +extern const FFFilter ff_vf_removelogo; +extern const FFFilter ff_vf_repeatfields; +extern const FFFilter ff_vf_reverse; +extern const FFFilter ff_vf_rgbashift; +extern const FFFilter ff_vf_roberts; +extern const FFFilter ff_vf_roberts_opencl; +extern const FFFilter ff_vf_rotate; +extern const FFFilter ff_vf_sab; +extern const FFFilter ff_vf_scale; +extern const FFFilter ff_vf_vpp_amf; +extern const FFFilter ff_vf_sr_amf; +extern const FFFilter ff_vf_scale_cuda; +extern const FFFilter ff_vf_scale_d3d11; +extern const FFFilter ff_vf_scale_d3d12; +extern const FFFilter ff_vf_scale_npp; +extern const FFFilter ff_vf_scale_qsv; +extern const FFFilter ff_vf_scale_vaapi; +extern const FFFilter ff_vf_scale_vt; +extern const FFFilter ff_vf_scale_vulkan; +extern const FFFilter ff_vf_scale2ref; +extern const FFFilter ff_vf_scale2ref_npp; +extern const FFFilter ff_vf_scdet; +extern const FFFilter ff_vf_scdet_vulkan; +extern const FFFilter ff_vf_scharr; +extern const FFFilter ff_vf_scroll; +extern const FFFilter ff_vf_segment; +extern const FFFilter ff_vf_select; +extern const FFFilter ff_vf_selectivecolor; +extern const FFFilter ff_vf_sendcmd; +extern const FFFilter ff_vf_separatefields; +extern const FFFilter ff_vf_setdar; +extern const FFFilter ff_vf_setfield; +extern const FFFilter ff_vf_setparams; +extern const FFFilter ff_vf_setpts; +extern const FFFilter ff_vf_setrange; +extern const FFFilter ff_vf_setsar; +extern const FFFilter ff_vf_settb; +extern const FFFilter ff_vf_sharpen_npp; +extern const FFFilter ff_vf_sharpness_vaapi; +extern const FFFilter ff_vf_shear; +extern const FFFilter ff_vf_showinfo; +extern const FFFilter ff_vf_showpalette; +extern const FFFilter ff_vf_shuffleframes; +extern const FFFilter ff_vf_shufflepixels; +extern const FFFilter ff_vf_shuffleplanes; +extern const FFFilter ff_vf_sidedata; +extern const FFFilter ff_vf_signalstats; +extern const FFFilter ff_vf_signature; +extern const FFFilter ff_vf_siti; +extern const FFFilter ff_vf_smartblur; +extern const FFFilter ff_vf_sobel; +extern const FFFilter ff_vf_sobel_opencl; +extern const FFFilter ff_vf_split; +extern const FFFilter ff_vf_spp; +extern const FFFilter ff_vf_sr; +extern const FFFilter ff_vf_ssim; +extern const FFFilter ff_vf_ssim360; +extern const FFFilter ff_vf_stereo3d; +extern const FFFilter ff_vf_streamselect; +extern const FFFilter ff_vf_subtitles; +extern const FFFilter ff_vf_super2xsai; +extern const FFFilter ff_vf_swaprect; +extern const FFFilter ff_vf_swapuv; +extern const FFFilter ff_vf_tblend; +extern const FFFilter ff_vf_telecine; +extern const FFFilter ff_vf_thistogram; +extern const FFFilter ff_vf_threshold; +extern const FFFilter ff_vf_thumbnail; +extern const FFFilter ff_vf_thumbnail_cuda; +extern const FFFilter ff_vf_tile; +extern const FFFilter ff_vf_tiltandshift; +extern const FFFilter ff_vf_tinterlace; +extern const FFFilter ff_vf_tlut2; +extern const FFFilter ff_vf_tmedian; +extern const FFFilter ff_vf_tmidequalizer; +extern const FFFilter ff_vf_tmix; +extern const FFFilter ff_vf_tonemap; +extern const FFFilter ff_vf_tonemap_opencl; +extern const FFFilter ff_vf_tonemap_vaapi; +extern const FFFilter ff_vf_tpad; +extern const FFFilter ff_vf_transpose; +extern const FFFilter ff_vf_transpose_npp; +extern const FFFilter ff_vf_transpose_opencl; +extern const FFFilter ff_vf_transpose_vaapi; +extern const FFFilter ff_vf_transpose_vt; +extern const FFFilter ff_vf_transpose_vulkan; +extern const FFFilter ff_vf_trim; +extern const FFFilter ff_vf_unpremultiply; +extern const FFFilter ff_vf_unsharp; +extern const FFFilter ff_vf_unsharp_opencl; +extern const FFFilter ff_vf_untile; +extern const FFFilter ff_vf_uspp; +extern const FFFilter ff_vf_v360; +extern const FFFilter ff_vf_vaguedenoiser; +extern const FFFilter ff_vf_varblur; +extern const FFFilter ff_vf_vectorscope; +extern const FFFilter ff_vf_vflip; +extern const FFFilter ff_vf_vflip_vulkan; +extern const FFFilter ff_vf_vfrdet; +extern const FFFilter ff_vf_vibrance; +extern const FFFilter ff_vf_vidstabdetect; +extern const FFFilter ff_vf_vidstabtransform; +extern const FFFilter ff_vf_vif; +extern const FFFilter ff_vf_vignette; +extern const FFFilter ff_vf_vmafmotion; +extern const FFFilter ff_vf_vpp_qsv; +extern const FFFilter ff_vf_vstack; +extern const FFFilter ff_vf_w3fdif; +extern const FFFilter ff_vf_waveform; +extern const FFFilter ff_vf_weave; +extern const FFFilter ff_vf_xbr; +extern const FFFilter ff_vf_xcorrelate; +extern const FFFilter ff_vf_xfade; +extern const FFFilter ff_vf_xfade_opencl; +extern const FFFilter ff_vf_xfade_vulkan; +extern const FFFilter ff_vf_xmedian; +extern const FFFilter ff_vf_xpsnr; +extern const FFFilter ff_vf_xstack; +extern const FFFilter ff_vf_yadif; +extern const FFFilter ff_vf_yadif_cuda; +extern const FFFilter ff_vf_yadif_videotoolbox; +extern const FFFilter ff_vf_yaepblur; +extern const FFFilter ff_vf_zmq; +extern const FFFilter ff_vf_zoompan; +extern const FFFilter ff_vf_zscale; +extern const FFFilter ff_vf_hstack_vaapi; +extern const FFFilter ff_vf_vstack_vaapi; +extern const FFFilter ff_vf_xstack_vaapi; +extern const FFFilter ff_vf_hstack_qsv; +extern const FFFilter ff_vf_vstack_qsv; +extern const FFFilter ff_vf_xstack_qsv; +extern const FFFilter ff_vf_pad_vaapi; +extern const FFFilter ff_vf_drawbox_vaapi; -extern const AVFilter ff_vsrc_allrgb; -extern const AVFilter ff_vsrc_allyuv; -extern const AVFilter ff_vsrc_cellauto; -extern const AVFilter ff_vsrc_color; -extern const AVFilter ff_vsrc_color_vulkan; -extern const AVFilter ff_vsrc_colorchart; -extern const AVFilter ff_vsrc_colorspectrum; -extern const AVFilter ff_vsrc_coreimagesrc; -extern const AVFilter ff_vsrc_ddagrab; -extern const AVFilter ff_vsrc_frei0r_src; -extern const AVFilter ff_vsrc_gradients; -extern const AVFilter ff_vsrc_haldclutsrc; -extern const AVFilter ff_vsrc_life; -extern const AVFilter ff_vsrc_mandelbrot; -extern const AVFilter ff_vsrc_mptestsrc; -extern const AVFilter ff_vsrc_nullsrc; -extern const AVFilter ff_vsrc_openclsrc; -extern const AVFilter ff_vsrc_qrencodesrc; -extern const AVFilter ff_vsrc_pal75bars; -extern const AVFilter ff_vsrc_pal100bars; -extern const AVFilter ff_vsrc_perlin; -extern const AVFilter ff_vsrc_rgbtestsrc; -extern const AVFilter ff_vsrc_sierpinski; -extern const AVFilter ff_vsrc_smptebars; -extern const AVFilter ff_vsrc_smptehdbars; -extern const AVFilter ff_vsrc_testsrc; -extern const AVFilter ff_vsrc_testsrc2; -extern const AVFilter ff_vsrc_yuvtestsrc; -extern const AVFilter ff_vsrc_zoneplate; +extern const FFFilter ff_vsrc_allrgb; +extern const FFFilter ff_vsrc_allyuv; +extern const FFFilter ff_vsrc_amf_capture; +extern const FFFilter ff_vsrc_cellauto; +extern const FFFilter ff_vsrc_color; +extern const FFFilter ff_vsrc_color_vulkan; +extern const FFFilter ff_vsrc_colorchart; +extern const FFFilter ff_vsrc_colorspectrum; +extern const FFFilter ff_vsrc_coreimagesrc; +extern const FFFilter ff_vsrc_ddagrab; +extern const FFFilter ff_vsrc_frei0r_src; +extern const FFFilter ff_vsrc_gfxcapture; +extern const FFFilter ff_vsrc_gradients; +extern const FFFilter ff_vsrc_haldclutsrc; +extern const FFFilter ff_vsrc_life; +extern const FFFilter ff_vsrc_mandelbrot; +extern const FFFilter ff_vsrc_mptestsrc; +extern const FFFilter ff_vsrc_nullsrc; +extern const FFFilter ff_vsrc_openclsrc; +extern const FFFilter ff_vsrc_qrencodesrc; +extern const FFFilter ff_vsrc_pal75bars; +extern const FFFilter ff_vsrc_pal100bars; +extern const FFFilter ff_vsrc_perlin; +extern const FFFilter ff_vsrc_rgbtestsrc; +extern const FFFilter ff_vsrc_sierpinski; +extern const FFFilter ff_vsrc_smptebars; +extern const FFFilter ff_vsrc_smptehdbars; +extern const FFFilter ff_vsrc_testsrc; +extern const FFFilter ff_vsrc_testsrc2; +extern const FFFilter ff_vsrc_yuvtestsrc; +extern const FFFilter ff_vsrc_zoneplate; -extern const AVFilter ff_vsink_nullsink; +extern const FFFilter ff_vsink_nullsink; /* multimedia filters */ -extern const AVFilter ff_avf_a3dscope; -extern const AVFilter ff_avf_abitscope; -extern const AVFilter ff_avf_adrawgraph; -extern const AVFilter ff_avf_agraphmonitor; -extern const AVFilter ff_avf_ahistogram; -extern const AVFilter ff_avf_aphasemeter; -extern const AVFilter ff_avf_avectorscope; -extern const AVFilter ff_avf_concat; -extern const AVFilter ff_avf_showcqt; -extern const AVFilter ff_avf_showcwt; -extern const AVFilter ff_avf_showfreqs; -extern const AVFilter ff_avf_showspatial; -extern const AVFilter ff_avf_showspectrum; -extern const AVFilter ff_avf_showspectrumpic; -extern const AVFilter ff_avf_showvolume; -extern const AVFilter ff_avf_showwaves; -extern const AVFilter ff_avf_showwavespic; -extern const AVFilter ff_vaf_spectrumsynth; +extern const FFFilter ff_avf_a3dscope; +extern const FFFilter ff_avf_abitscope; +extern const FFFilter ff_avf_adrawgraph; +extern const FFFilter ff_avf_agraphmonitor; +extern const FFFilter ff_avf_ahistogram; +extern const FFFilter ff_avf_aphasemeter; +extern const FFFilter ff_avf_avectorscope; +extern const FFFilter ff_avf_concat; +extern const FFFilter ff_avf_showcqt; +extern const FFFilter ff_avf_showcwt; +extern const FFFilter ff_avf_showfreqs; +extern const FFFilter ff_avf_showspatial; +extern const FFFilter ff_avf_showspectrum; +extern const FFFilter ff_avf_showspectrumpic; +extern const FFFilter ff_avf_showvolume; +extern const FFFilter ff_avf_showwaves; +extern const FFFilter ff_avf_showwavespic; +extern const FFFilter ff_vaf_spectrumsynth; /* multimedia sources */ -extern const AVFilter ff_avsrc_avsynctest; -extern const AVFilter ff_avsrc_amovie; -extern const AVFilter ff_avsrc_movie; +extern const FFFilter ff_avsrc_avsynctest; +extern const FFFilter ff_avsrc_amovie; +extern const FFFilter ff_avsrc_movie; /* those filters are part of public or internal API, * they are formatted to not be found by the grep * as they are manually added again (due to their 'names' * being the same while having different 'types'). */ -extern const AVFilter ff_asrc_abuffer; -extern const AVFilter ff_vsrc_buffer; -extern const AVFilter ff_asink_abuffer; -extern const AVFilter ff_vsink_buffer; +extern const FFFilter ff_asrc_abuffer; +extern const FFFilter ff_vsrc_buffer; +extern const FFFilter ff_asink_abuffer; +extern const FFFilter ff_vsink_buffer; #include "libavfilter/filter_list.c" @@ -623,12 +640,14 @@ extern const AVFilter ff_vsink_buffer; const AVFilter *av_filter_iterate(void **opaque) { uintptr_t i = (uintptr_t)*opaque; - const AVFilter *f = filter_list[i]; + const FFFilter *f = filter_list[i]; - if (f) + if (f) { *opaque = (void*)(i + 1); + return &f->p; + } - return f; + return NULL; } const AVFilter *avfilter_get_by_name(const char *name) diff --git a/libavfilter/asink_anullsink.c b/libavfilter/asink_anullsink.c index 5ba1c7288..e65705177 100644 --- a/libavfilter/asink_anullsink.c +++ b/libavfilter/asink_anullsink.c @@ -36,10 +36,10 @@ static const AVFilterPad avfilter_asink_anullsink_inputs[] = { }, }; -const AVFilter ff_asink_anullsink = { - .name = "anullsink", - .description = NULL_IF_CONFIG_SMALL("Do absolutely nothing with the input audio."), +const FFFilter ff_asink_anullsink = { + .p.name = "anullsink", + .p.description = NULL_IF_CONFIG_SMALL("Do absolutely nothing with the input audio."), + .p.outputs = NULL, .priv_size = 0, FILTER_INPUTS(avfilter_asink_anullsink_inputs), - .outputs = NULL, }; diff --git a/libavfilter/asrc_afdelaysrc.c b/libavfilter/asrc_afdelaysrc.c index c235f0c27..6d9df77ee 100644 --- a/libavfilter/asrc_afdelaysrc.c +++ b/libavfilter/asrc_afdelaysrc.c @@ -80,22 +80,24 @@ static int activate(AVFilterContext *ctx) return ff_filter_frame(outlink, frame); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AFDelaySrcContext *s = ctx->priv; + const AFDelaySrcContext *s = ctx->priv; AVChannelLayout chlayouts[] = { s->chlayout, { 0 } }; int sample_rates[] = { s->sample_rate, -1 }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static int config_output(AVFilterLink *outlink) @@ -138,13 +140,12 @@ static const AVOption afdelaysrc_options[] = { AVFILTER_DEFINE_CLASS(afdelaysrc); -const AVFilter ff_asrc_afdelaysrc = { - .name = "afdelaysrc", - .description = NULL_IF_CONFIG_SMALL("Generate a Fractional delay FIR coefficients."), +const FFFilter ff_asrc_afdelaysrc = { + .p.name = "afdelaysrc", + .p.description = NULL_IF_CONFIG_SMALL("Generate a Fractional delay FIR coefficients."), + .p.priv_class = &afdelaysrc_class, .priv_size = sizeof(AFDelaySrcContext), - .priv_class = &afdelaysrc_class, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(afdelaysrc_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_afirsrc.c b/libavfilter/asrc_afirsrc.c index bc450ec82..01125cb45 100644 --- a/libavfilter/asrc_afirsrc.c +++ b/libavfilter/asrc_afirsrc.c @@ -92,7 +92,7 @@ static av_cold int init(AVFilterContext *ctx) AudioFIRSourceContext *s = ctx->priv; if (!(s->nb_taps & 1)) { - av_log(s, AV_LOG_WARNING, "Number of taps %d must be odd length.\n", s->nb_taps); + av_log(ctx, AV_LOG_WARNING, "Number of taps %d must be odd length.\n", s->nb_taps); s->nb_taps |= 1; } @@ -113,24 +113,26 @@ static av_cold void uninit(AVFilterContext *ctx) av_tx_uninit(&s->itx_ctx); } -static av_cold int query_formats(AVFilterContext *ctx) +static av_cold int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioFIRSourceContext *s = ctx->priv; + const AudioFIRSourceContext *s = ctx->priv; static const AVChannelLayout chlayouts[] = { AV_CHANNEL_LAYOUT_MONO, { 0 } }; int sample_rates[] = { s->sample_rate, -1 }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static int parse_string(char *str, float **items, int *nb_items, int *items_size) @@ -295,17 +297,16 @@ static const AVFilterPad afirsrc_outputs[] = { }, }; -const AVFilter ff_asrc_afirsrc = { - .name = "afirsrc", - .description = NULL_IF_CONFIG_SMALL("Generate a FIR coefficients audio stream."), +const FFFilter ff_asrc_afirsrc = { + .p.name = "afirsrc", + .p.description = NULL_IF_CONFIG_SMALL("Generate a FIR coefficients audio stream."), + .p.priv_class = &afirsrc_class, .init = init, .uninit = uninit, .activate = activate, .priv_size = sizeof(AudioFIRSourceContext), - .inputs = NULL, FILTER_OUTPUTS(afirsrc_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &afirsrc_class, + FILTER_QUERY_FUNC2(query_formats), }; #define DEFAULT_BANDS "25 40 63 100 160 250 400 630 1000 1600 2500 4000 6300 10000 16000 24000" @@ -577,14 +578,13 @@ static const AVFilterPad afireqsrc_outputs[] = { }, }; -const AVFilter ff_asrc_afireqsrc = { - .name = "afireqsrc", - .description = NULL_IF_CONFIG_SMALL("Generate a FIR equalizer coefficients audio stream."), +const FFFilter ff_asrc_afireqsrc = { + .p.name = "afireqsrc", + .p.description = NULL_IF_CONFIG_SMALL("Generate a FIR equalizer coefficients audio stream."), + .p.priv_class = &afireqsrc_class, .uninit = uninit, .activate = activate, .priv_size = sizeof(AudioFIRSourceContext), - .inputs = NULL, FILTER_OUTPUTS(afireqsrc_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &afireqsrc_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_anoisesrc.c b/libavfilter/asrc_anoisesrc.c index a67b2abe9..d22ca255f 100644 --- a/libavfilter/asrc_anoisesrc.c +++ b/libavfilter/asrc_anoisesrc.c @@ -83,24 +83,26 @@ static const AVOption anoisesrc_options[] = { AVFILTER_DEFINE_CLASS(anoisesrc); -static av_cold int query_formats(AVFilterContext *ctx) +static av_cold int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - ANoiseSrcContext *s = ctx->priv; + const ANoiseSrcContext *s = ctx->priv; static const AVChannelLayout chlayouts[] = { AV_CHANNEL_LAYOUT_MONO, { 0 } }; int sample_rates[] = { s->sample_rate, -1 }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static double white_filter(double white, double *buf) @@ -237,13 +239,12 @@ static const AVFilterPad anoisesrc_outputs[] = { }, }; -const AVFilter ff_asrc_anoisesrc = { - .name = "anoisesrc", - .description = NULL_IF_CONFIG_SMALL("Generate a noise audio signal."), +const FFFilter ff_asrc_anoisesrc = { + .p.name = "anoisesrc", + .p.description = NULL_IF_CONFIG_SMALL("Generate a noise audio signal."), + .p.priv_class = &anoisesrc_class, .priv_size = sizeof(ANoiseSrcContext), - .inputs = NULL, .activate = activate, FILTER_OUTPUTS(anoisesrc_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &anoisesrc_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_anullsrc.c b/libavfilter/asrc_anullsrc.c index 3249cc33a..7d74319df 100644 --- a/libavfilter/asrc_anullsrc.c +++ b/libavfilter/asrc_anullsrc.c @@ -61,18 +61,20 @@ static const AVOption anullsrc_options[]= { AVFILTER_DEFINE_CLASS(anullsrc); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - ANullContext *null = ctx->priv; + const ANullContext *null = ctx->priv; const AVChannelLayout chlayouts[] = { null->ch_layout, { 0 } }; int sample_rates[] = { null->sample_rate, -1 }; int ret; - if ((ret = ff_set_common_formats (ctx, ff_all_formats (AVMEDIA_TYPE_AUDIO))) < 0 || - (ret = ff_set_common_samplerates_from_list(ctx, sample_rates)) < 0) + ret = ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); + if (ret < 0) return ret; - return ff_set_common_channel_layouts_from_list(ctx, chlayouts); + return ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); } static av_cold int config_props(AVFilterLink *outlink) @@ -118,13 +120,12 @@ static const AVFilterPad avfilter_asrc_anullsrc_outputs[] = { }, }; -const AVFilter ff_asrc_anullsrc = { - .name = "anullsrc", - .description = NULL_IF_CONFIG_SMALL("Null audio source, return empty audio frames."), +const FFFilter ff_asrc_anullsrc = { + .p.name = "anullsrc", + .p.description = NULL_IF_CONFIG_SMALL("Null audio source, return empty audio frames."), + .p.priv_class = &anullsrc_class, .priv_size = sizeof(ANullContext), - .inputs = NULL, FILTER_OUTPUTS(avfilter_asrc_anullsrc_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .activate = activate, - .priv_class = &anullsrc_class, }; diff --git a/libavfilter/asrc_flite.c b/libavfilter/asrc_flite.c index 5962bf55b..a7471607c 100644 --- a/libavfilter/asrc_flite.c +++ b/libavfilter/asrc_flite.c @@ -255,24 +255,35 @@ static av_cold void uninit(AVFilterContext *ctx) av_audio_fifo_free(flite->fifo); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - FliteContext *flite = ctx->priv; + const FliteContext *flite = ctx->priv; + + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_NONE, + }; + int sample_rates[] = { flite->sample_rate, -1 }; + AVChannelLayout layouts[2] = { + { .nb_channels = 0 }, + }; + int ret; - AVFilterChannelLayouts *chlayouts = NULL; - AVFilterFormats *sample_formats = NULL; - AVFilterFormats *sample_rates = NULL; - AVChannelLayout chlayout = { 0 }; + av_channel_layout_default(&layouts[0], flite->nb_channels); - av_channel_layout_default(&chlayout, flite->nb_channels); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) + return ret; - if ((ret = ff_add_channel_layout (&chlayouts , &chlayout )) < 0 || - (ret = ff_set_common_channel_layouts (ctx , chlayouts )) < 0 || - (ret = ff_add_format (&sample_formats, AV_SAMPLE_FMT_S16 )) < 0 || - (ret = ff_set_common_formats (ctx , sample_formats )) < 0 || - (ret = ff_add_format (&sample_rates , flite->sample_rate )) < 0 || - (ret = ff_set_common_samplerates (ctx , sample_rates )) < 0) + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) + return ret; + + ret = ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); + if (ret < 0) return ret; return 0; @@ -339,15 +350,14 @@ static const AVFilterPad flite_outputs[] = { }, }; -const AVFilter ff_asrc_flite = { - .name = "flite", - .description = NULL_IF_CONFIG_SMALL("Synthesize voice from text using libflite."), +const FFFilter ff_asrc_flite = { + .p.name = "flite", + .p.description = NULL_IF_CONFIG_SMALL("Synthesize voice from text using libflite."), + .p.priv_class = &flite_class, .init = init, .uninit = uninit, .priv_size = sizeof(FliteContext), .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(flite_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &flite_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_hilbert.c b/libavfilter/asrc_hilbert.c index e38af7123..e6f69b024 100644 --- a/libavfilter/asrc_hilbert.c +++ b/libavfilter/asrc_hilbert.c @@ -61,7 +61,7 @@ static av_cold int init(AVFilterContext *ctx) HilbertContext *s = ctx->priv; if (!(s->nb_taps & 1)) { - av_log(s, AV_LOG_ERROR, "Number of taps %d must be odd length.\n", s->nb_taps); + av_log(ctx, AV_LOG_ERROR, "Number of taps %d must be odd length.\n", s->nb_taps); return AVERROR(EINVAL); } @@ -75,7 +75,9 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->taps); } -static av_cold int query_formats(AVFilterContext *ctx) +static av_cold int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { HilbertContext *s = ctx->priv; static const AVChannelLayout chlayouts[] = { AV_CHANNEL_LAYOUT_MONO, { 0 } }; @@ -84,15 +86,15 @@ static av_cold int query_formats(AVFilterContext *ctx) AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static av_cold int config_props(AVFilterLink *outlink) @@ -159,15 +161,14 @@ static const AVFilterPad hilbert_outputs[] = { }, }; -const AVFilter ff_asrc_hilbert = { - .name = "hilbert", - .description = NULL_IF_CONFIG_SMALL("Generate a Hilbert transform FIR coefficients."), +const FFFilter ff_asrc_hilbert = { + .p.name = "hilbert", + .p.description = NULL_IF_CONFIG_SMALL("Generate a Hilbert transform FIR coefficients."), + .p.priv_class = &hilbert_class, .init = init, .uninit = uninit, .activate = activate, .priv_size = sizeof(HilbertContext), - .inputs = NULL, FILTER_OUTPUTS(hilbert_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &hilbert_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_sinc.c b/libavfilter/asrc_sinc.c index 94046f76b..98c3c8dc0 100644 --- a/libavfilter/asrc_sinc.c +++ b/libavfilter/asrc_sinc.c @@ -74,22 +74,24 @@ static int activate(AVFilterContext *ctx) return ff_filter_frame(outlink, frame); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - SincContext *s = ctx->priv; + const SincContext *s = ctx->priv; static const AVChannelLayout chlayouts[] = { AV_CHANNEL_LAYOUT_MONO, { 0 } }; int sample_rates[] = { s->sample_rate, -1 }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static float *make_lpf(int num_taps, float Fc, float beta, float rho, @@ -199,8 +201,9 @@ static float safe_log(float x) return -26; } -static int fir_to_phase(SincContext *s, float **h, int *len, int *post_len, float phase) +static int fir_to_phase(AVFilterContext *ctx, float **h, int *len, int *post_len, float phase) { + SincContext *s = ctx->priv; float *pi_wraps, *work, phase1 = (phase > 50.f ? 100.f - phase : phase) / 50.f; int i, work_len, begin, end, imp_peak = 0, peak = 0, ret; float imp_sum = 0, peak_imp_sum = 0, scale = 1.f; @@ -311,7 +314,7 @@ static int fir_to_phase(SincContext *s, float **h, int *len, int *post_len, floa } *post_len = phase > 50 ? peak - begin : begin + *len - (peak + 1); - av_log(s, AV_LOG_DEBUG, "%d nPI=%g peak-sum@%i=%g (val@%i=%g); len=%i post=%i (%g%%)\n", + av_log(ctx, AV_LOG_DEBUG, "%d nPI=%g peak-sum@%i=%g (val@%i=%g); len=%i post=%i (%g%%)\n", work_len, pi_wraps[work_len >> 1] / M_PI, peak, peak_imp_sum, imp_peak, work[imp_peak], *len, *post_len, 100.f - 100.f * *post_len / (*len - 1)); @@ -327,7 +330,7 @@ static int config_output(AVFilterLink *outlink) SincContext *s = ctx->priv; float Fn = s->sample_rate * .5f; float *h[2]; - int i, n, post_peak, longer; + int i, n, post_peak, longer, ret; outlink->sample_rate = s->sample_rate; s->pts = 0; @@ -358,9 +361,9 @@ static int config_output(AVFilterLink *outlink) } if (s->phase != 50.f) { - int ret = fir_to_phase(s, &h[longer], &n, &post_peak, s->phase); + ret = fir_to_phase(ctx, &h[longer], &n, &post_peak, s->phase); if (ret < 0) - return ret; + goto cleanup; } else { post_peak = n >> 1; } @@ -368,17 +371,21 @@ static int config_output(AVFilterLink *outlink) s->n = 1 << (av_log2(n) + 1); s->rdft_len = 1 << av_log2(n); s->coeffs = av_calloc(s->n, sizeof(*s->coeffs)); - if (!s->coeffs) - return AVERROR(ENOMEM); + if (!s->coeffs) { + ret = AVERROR(ENOMEM); + goto cleanup; + } for (i = 0; i < n; i++) s->coeffs[i] = h[longer][i]; - av_free(h[longer]); av_tx_uninit(&s->tx); av_tx_uninit(&s->itx); + ret = 0; - return 0; +cleanup: + av_free(h[longer]); + return ret; } static av_cold void uninit(AVFilterContext *ctx) @@ -419,14 +426,13 @@ static const AVOption sinc_options[] = { AVFILTER_DEFINE_CLASS(sinc); -const AVFilter ff_asrc_sinc = { - .name = "sinc", - .description = NULL_IF_CONFIG_SMALL("Generate a sinc kaiser-windowed low-pass, high-pass, band-pass, or band-reject FIR coefficients."), +const FFFilter ff_asrc_sinc = { + .p.name = "sinc", + .p.description = NULL_IF_CONFIG_SMALL("Generate a sinc kaiser-windowed low-pass, high-pass, band-pass, or band-reject FIR coefficients."), + .p.priv_class = &sinc_class, .priv_size = sizeof(SincContext), - .priv_class = &sinc_class, .uninit = uninit, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(sinc_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_sine.c b/libavfilter/asrc_sine.c index 2e444ba19..2f8a83529 100644 --- a/libavfilter/asrc_sine.c +++ b/libavfilter/asrc_sine.c @@ -30,6 +30,14 @@ #include "filters.h" #include "formats.h" +typedef struct SamplingContext { + uint32_t phi; ///< current phase of the sine (2pi = 1<<32) + uint32_t dphi; ///< phase increment between two samples + int phi_rem; ///< current fractional phase in 1/dphi_den subfractions + int dphi_rem; + int dphi_den; +} SamplingContext; + typedef struct SineContext { const AVClass *class; double frequency; @@ -40,13 +48,11 @@ typedef struct SineContext { int64_t duration; int16_t *sin; int64_t pts; - uint32_t phi; ///< current phase of the sine (2pi = 1<<32) - uint32_t dphi; ///< phase increment between two samples + SamplingContext signal; + SamplingContext beep; unsigned beep_period; unsigned beep_index; unsigned beep_length; - uint32_t phi_beep; ///< current phase of the beep - uint32_t dphi_beep; ///< phase increment of the beep } SineContext; #define CONTEXT SineContext @@ -143,6 +149,35 @@ enum { VAR_VARS_NB }; +static void sampling_init(SamplingContext *c, double frequency, int sample_rate) +{ + AVRational r; + int r_den, max_r_den; + + max_r_den = INT_MAX / sample_rate; + frequency = fmod(frequency, sample_rate); + r = av_d2q(fmod(frequency, 1.0), max_r_den); + r_den = FFMIN(r.den, max_r_den); + c->dphi = ldexp(frequency, 32) / sample_rate; + c->dphi_den = r_den * sample_rate; + c->dphi_rem = round((ldexp(frequency, 32) / sample_rate - c->dphi) * c->dphi_den); + if (c->dphi_rem >= c->dphi_den) { + c->dphi++; + c->dphi_rem = 0; + } + c->phi_rem = (-c->dphi_den - 1) / 2; +} + +static av_always_inline void sampling_advance(SamplingContext *c) +{ + c->phi += c->dphi; + c->phi_rem += c->dphi_rem; + if (c->phi_rem >= 0) { + c->phi_rem -= c->dphi_den; + c->phi++; + } +} + static av_cold int init(AVFilterContext *ctx) { int ret; @@ -150,14 +185,13 @@ static av_cold int init(AVFilterContext *ctx) if (!(sine->sin = av_malloc(sizeof(*sine->sin) << LOG_PERIOD))) return AVERROR(ENOMEM); - sine->dphi = ldexp(sine->frequency, 32) / sine->sample_rate + 0.5; + sampling_init(&sine->signal, sine->frequency, sine->sample_rate); make_sin_table(sine->sin); if (sine->beep_factor) { sine->beep_period = sine->sample_rate; sine->beep_length = sine->beep_period / 25; - sine->dphi_beep = ldexp(sine->beep_factor * sine->frequency, 32) / - sine->sample_rate + 0.5; + sampling_init(&sine->beep, sine->beep_factor * sine->frequency, sine->sample_rate); } ret = av_expr_parse(&sine->samples_per_frame_expr, @@ -178,22 +212,24 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&sine->sin); } -static av_cold int query_formats(AVFilterContext *ctx) +static av_cold int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - SineContext *sine = ctx->priv; + const SineContext *sine = ctx->priv; static const AVChannelLayout chlayouts[] = { AV_CHANNEL_LAYOUT_MONO, { 0 } }; int sample_rates[] = { sine->sample_rate, -1 }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static av_cold int config_props(AVFilterLink *outlink) @@ -221,7 +257,7 @@ static int activate(AVFilterContext *ctx) if (!ff_outlink_frame_wanted(outlink)) return FFERROR_NOT_READY; if (nb_samples <= 0) { - av_log(sine, AV_LOG_WARNING, "nb samples expression evaluated to %d, " + av_log(ctx, AV_LOG_WARNING, "nb samples expression evaluated to %d, " "defaulting to 1024\n", nb_samples); nb_samples = 1024; } @@ -239,11 +275,11 @@ static int activate(AVFilterContext *ctx) samples = (int16_t *)frame->data[0]; for (i = 0; i < nb_samples; i++) { - samples[i] = sine->sin[sine->phi >> (32 - LOG_PERIOD)]; - sine->phi += sine->dphi; + samples[i] = sine->sin[sine->signal.phi >> (32 - LOG_PERIOD)]; + sampling_advance(&sine->signal); if (sine->beep_index < sine->beep_length) { - samples[i] += sine->sin[sine->phi_beep >> (32 - LOG_PERIOD)] * 2; - sine->phi_beep += sine->dphi_beep; + samples[i] += sine->sin[sine->beep.phi >> (32 - LOG_PERIOD)] * 2; + sampling_advance(&sine->beep); } if (++sine->beep_index == sine->beep_period) sine->beep_index = 0; @@ -262,15 +298,14 @@ static const AVFilterPad sine_outputs[] = { }, }; -const AVFilter ff_asrc_sine = { - .name = "sine", - .description = NULL_IF_CONFIG_SMALL("Generate sine wave audio signal."), +const FFFilter ff_asrc_sine = { + .p.name = "sine", + .p.description = NULL_IF_CONFIG_SMALL("Generate sine wave audio signal."), + .p.priv_class = &sine_class, .init = init, .uninit = uninit, .activate = activate, .priv_size = sizeof(SineContext), - .inputs = NULL, FILTER_OUTPUTS(sine_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &sine_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_a3dscope.c b/libavfilter/avf_a3dscope.c index dd0899051..07957dcfe 100644 --- a/libavfilter/avf_a3dscope.c +++ b/libavfilter/avf_a3dscope.c @@ -73,30 +73,21 @@ static const AVOption a3dscope_options[] = { AVFILTER_DEFINE_CLASS(a3dscope); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; int ret; - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref (formats, &inlink->outcfg.formats )) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) - return ret; - - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) - return ret; - - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -344,15 +335,15 @@ static const AVFilterPad audio3dscope_outputs[] = { }, }; -const AVFilter ff_avf_a3dscope = { - .name = "a3dscope", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to 3d scope video output."), +const FFFilter ff_avf_a3dscope = { + .p.name = "a3dscope", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to 3d scope video output."), + .p.priv_class = &a3dscope_class, .uninit = uninit, .priv_size = sizeof(Audio3dScopeContext), .activate = activate, FILTER_INPUTS(audio3dscope_inputs), FILTER_OUTPUTS(audio3dscope_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &a3dscope_class, + FILTER_QUERY_FUNC2(query_formats), .process_command = ff_filter_process_command, }; diff --git a/libavfilter/avf_abitscope.c b/libavfilter/avf_abitscope.c index 30ed7d95e..3a9249036 100644 --- a/libavfilter/avf_abitscope.c +++ b/libavfilter/avf_abitscope.c @@ -65,12 +65,11 @@ static const AVOption abitscope_options[] = { AVFILTER_DEFINE_CLASS(abitscope); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S64P, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, @@ -78,22 +77,12 @@ static int query_formats(AVFilterContext *ctx) static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; int ret; - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; - layouts = ff_all_channel_counts(); - if (!layouts) - return AVERROR(ENOMEM); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) - return ret; - - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -316,14 +305,14 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_avf_abitscope = { - .name = "abitscope", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to audio bit scope video output."), +const FFFilter ff_avf_abitscope = { + .p.name = "abitscope", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to audio bit scope video output."), + .p.priv_class = &abitscope_class, .priv_size = sizeof(AudioBitScopeContext), FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .uninit = uninit, .activate = activate, - .priv_class = &abitscope_class, }; diff --git a/libavfilter/avf_ahistogram.c b/libavfilter/avf_ahistogram.c index b77307f13..33f0e68db 100644 --- a/libavfilter/avf_ahistogram.c +++ b/libavfilter/avf_ahistogram.c @@ -92,28 +92,21 @@ static const AVOption ahistogram_options[] = { AVFILTER_DEFINE_CLASS(ahistogram); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE }; int ret = AVERROR(EINVAL); - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref (formats, &inlink->outcfg.formats )) < 0 || - (layouts = ff_all_channel_counts()) == NULL || - (ret = ff_channel_layouts_ref (layouts, &inlink->outcfg.channel_layouts)) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) - return ret; - - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -501,14 +494,14 @@ static const AVFilterPad ahistogram_outputs[] = { }, }; -const AVFilter ff_avf_ahistogram = { - .name = "ahistogram", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to histogram video output."), +const FFFilter ff_avf_ahistogram = { + .p.name = "ahistogram", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to histogram video output."), + .p.priv_class = &ahistogram_class, .uninit = uninit, .priv_size = sizeof(AudioHistogramContext), .activate = activate, FILTER_INPUTS(ahistogram_inputs), FILTER_OUTPUTS(ahistogram_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &ahistogram_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_aphasemeter.c b/libavfilter/avf_aphasemeter.c index fe0968c97..a55115870 100644 --- a/libavfilter/avf_aphasemeter.c +++ b/libavfilter/avf_aphasemeter.c @@ -90,35 +90,32 @@ static const AVOption aphasemeter_options[] = { AVFILTER_DEFINE_CLASS(aphasemeter); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioPhaseMeterContext *s = ctx->priv; + const AudioPhaseMeterContext *s = ctx->priv; AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layout = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; int ret; - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref (formats, &inlink->outcfg.formats )) < 0 || - (ret = ff_formats_ref (formats, &outlink->incfg.formats )) < 0 || - (ret = ff_add_channel_layout (&layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO )) < 0 || - (ret = ff_channel_layouts_ref (layout , &inlink->outcfg.channel_layouts)) < 0 || - (ret = ff_channel_layouts_ref (layout , &outlink->incfg.channel_layouts)) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0 || + (ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0 || - (ret = ff_formats_ref(formats, &outlink->incfg.samplerates)) < 0) + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) return ret; if (s->do_video) { - AVFilterLink *outlink = ctx->outputs[1]; - - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[1]->formats)) < 0) return ret; } @@ -174,8 +171,9 @@ static inline void add_metadata(AVFrame *insamples, const char *key, char *value av_dict_set(&insamples->metadata, buf, value, 0); } -static inline void update_mono_detection(AudioPhaseMeterContext *s, AVFrame *insamples, int mono_measurement) +static inline void update_mono_detection(AVFilterContext *ctx, AVFrame *insamples, int mono_measurement) { + AudioPhaseMeterContext *s = ctx->priv; int64_t mono_duration; if (!s->is_mono && mono_measurement) { s->is_mono = 1; @@ -187,7 +185,7 @@ static inline void update_mono_detection(AudioPhaseMeterContext *s, AVFrame *ins mono_duration = get_duration(s->mono_idx); if (mono_duration >= s->duration) { add_metadata(insamples, "mono_start", av_ts2timestr(s->mono_idx[0], &s->time_base)); - av_log(s, AV_LOG_INFO, "mono_start: %s\n", av_ts2timestr(s->mono_idx[0], &s->time_base)); + av_log(ctx, AV_LOG_INFO, "mono_start: %s\n", av_ts2timestr(s->mono_idx[0], &s->time_base)); s->start_mono_presence = 0; } } @@ -199,14 +197,15 @@ static inline void update_mono_detection(AudioPhaseMeterContext *s, AVFrame *ins add_metadata(insamples, "mono_end", av_ts2timestr(s->mono_idx[1], &s->time_base)); add_metadata(insamples, "mono_duration", av_ts2timestr(mono_duration, &s->time_base)); } - av_log(s, AV_LOG_INFO, "mono_end: %s | mono_duration: %s\n", av_ts2timestr(s->mono_idx[1], &s->time_base), av_ts2timestr(mono_duration, &s->time_base)); + av_log(ctx, AV_LOG_INFO, "mono_end: %s | mono_duration: %s\n", av_ts2timestr(s->mono_idx[1], &s->time_base), av_ts2timestr(mono_duration, &s->time_base)); } s->is_mono = 0; } } -static inline void update_out_phase_detection(AudioPhaseMeterContext *s, AVFrame *insamples, int out_phase_measurement) +static inline void update_out_phase_detection(AVFilterContext *ctx, AVFrame *insamples, int out_phase_measurement) { + AudioPhaseMeterContext *s = ctx->priv; int64_t out_phase_duration; if (!s->is_out_phase && out_phase_measurement) { s->is_out_phase = 1; @@ -218,7 +217,7 @@ static inline void update_out_phase_detection(AudioPhaseMeterContext *s, AVFrame out_phase_duration = get_duration(s->out_phase_idx); if (out_phase_duration >= s->duration) { add_metadata(insamples, "out_phase_start", av_ts2timestr(s->out_phase_idx[0], &s->time_base)); - av_log(s, AV_LOG_INFO, "out_phase_start: %s\n", av_ts2timestr(s->out_phase_idx[0], &s->time_base)); + av_log(ctx, AV_LOG_INFO, "out_phase_start: %s\n", av_ts2timestr(s->out_phase_idx[0], &s->time_base)); s->start_out_phase_presence = 0; } } @@ -230,7 +229,7 @@ static inline void update_out_phase_detection(AudioPhaseMeterContext *s, AVFrame add_metadata(insamples, "out_phase_end", av_ts2timestr(s->out_phase_idx[1], &s->time_base)); add_metadata(insamples, "out_phase_duration", av_ts2timestr(out_phase_duration, &s->time_base)); } - av_log(s, AV_LOG_INFO, "out_phase_end: %s | out_phase_duration: %s\n", av_ts2timestr(s->out_phase_idx[1], &s->time_base), av_ts2timestr(out_phase_duration, &s->time_base)); + av_log(ctx, AV_LOG_INFO, "out_phase_end: %s | out_phase_duration: %s\n", av_ts2timestr(s->out_phase_idx[1], &s->time_base), av_ts2timestr(out_phase_duration, &s->time_base)); } s->is_out_phase = 0; } @@ -325,8 +324,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) mono_measurement = (tolerance - fphase) < FLT_EPSILON; out_phase_measurement = (angle - fphase) > FLT_EPSILON; - update_mono_detection(s, in, mono_measurement); - update_out_phase_detection(s, in, out_phase_measurement); + update_mono_detection(ctx, in, mono_measurement); + update_out_phase_detection(ctx, in, out_phase_measurement); } if (s->do_video) @@ -389,8 +388,8 @@ static av_cold void uninit(AVFilterContext *ctx) AudioPhaseMeterContext *s = ctx->priv; if (s->do_phasing_detection) { - update_mono_detection(s, NULL, 0); - update_out_phase_detection(s, NULL, 0); + update_mono_detection(ctx, NULL, 0); + update_out_phase_detection(ctx, NULL, 0); } av_frame_free(&s->out); } @@ -431,16 +430,15 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_avf_aphasemeter = { - .name = "aphasemeter", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to phase meter video output."), +const FFFilter ff_avf_aphasemeter = { + .p.name = "aphasemeter", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to phase meter video output."), + .p.priv_class = &aphasemeter_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, .init = init, .uninit = uninit, .priv_size = sizeof(AudioPhaseMeterContext), FILTER_INPUTS(inputs), .activate = activate, - .outputs = NULL, - FILTER_QUERY_FUNC(query_formats), - .priv_class = &aphasemeter_class, - .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_avectorscope.c b/libavfilter/avf_avectorscope.c index 96bef32e2..4e477627b 100644 --- a/libavfilter/avf_avectorscope.c +++ b/libavfilter/avf_avectorscope.c @@ -230,28 +230,29 @@ static int fade(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) return 0; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layout = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; int ret; - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref (formats, &inlink->outcfg.formats )) < 0 || - (ret = ff_add_channel_layout (&layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_channel_layouts_ref (layout , &inlink->outcfg.channel_layouts)) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref (formats, &cfg_in[0]->formats )) < 0) return ret; - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) return ret; - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -485,16 +486,16 @@ static const AVFilterPad audiovectorscope_outputs[] = { }, }; -const AVFilter ff_avf_avectorscope = { - .name = "avectorscope", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to vectorscope video output."), +const FFFilter ff_avf_avectorscope = { + .p.name = "avectorscope", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to vectorscope video output."), + .p.priv_class = &avectorscope_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .uninit = uninit, .priv_size = sizeof(AudioVectorScopeContext), .activate = activate, FILTER_INPUTS(audiovectorscope_inputs), FILTER_OUTPUTS(audiovectorscope_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &avectorscope_class, - .flags = AVFILTER_FLAG_SLICE_THREADS, + FILTER_QUERY_FUNC2(query_formats), .process_command = ff_filter_process_command, }; diff --git a/libavfilter/avf_concat.c b/libavfilter/avf_concat.c index 2a3d4c8b5..531aa071a 100644 --- a/libavfilter/avf_concat.c +++ b/libavfilter/avf_concat.c @@ -72,9 +72,11 @@ static const AVOption concat_options[] = { AVFILTER_DEFINE_CLASS(concat); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - ConcatContext *cat = ctx->priv; + const ConcatContext *cat = ctx->priv; unsigned type, nb_str, idx0 = 0, idx, str, seg; AVFilterFormats *formats, *rates = NULL; AVFilterChannelLayouts *layouts = NULL; @@ -87,25 +89,25 @@ static int query_formats(AVFilterContext *ctx) /* Set the output formats */ formats = ff_all_formats(type); - if ((ret = ff_formats_ref(formats, &ctx->outputs[idx]->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[idx]->formats)) < 0) return ret; if (type == AVMEDIA_TYPE_AUDIO) { rates = ff_all_samplerates(); - if ((ret = ff_formats_ref(rates, &ctx->outputs[idx]->incfg.samplerates)) < 0) + if ((ret = ff_formats_ref(rates, &cfg_out[idx]->samplerates)) < 0) return ret; layouts = ff_all_channel_layouts(); - if ((ret = ff_channel_layouts_ref(layouts, &ctx->outputs[idx]->incfg.channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(layouts, &cfg_out[idx]->channel_layouts)) < 0) return ret; } /* Set the same formats for each corresponding input */ for (seg = 0; seg < cat->nb_segments; seg++) { - if ((ret = ff_formats_ref(formats, &ctx->inputs[idx]->outcfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[idx]->formats)) < 0) return ret; if (type == AVMEDIA_TYPE_AUDIO) { - if ((ret = ff_formats_ref(rates, &ctx->inputs[idx]->outcfg.samplerates)) < 0 || - (ret = ff_channel_layouts_ref(layouts, &ctx->inputs[idx]->outcfg.channel_layouts)) < 0) + if ((ret = ff_formats_ref(rates, &cfg_in[idx]->samplerates)) < 0 || + (ret = ff_channel_layouts_ref(layouts, &cfg_in[idx]->channel_layouts)) < 0) return ret; } idx += ctx->nb_outputs; @@ -449,17 +451,17 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar return ret; } -const AVFilter ff_avf_concat = { - .name = "concat", - .description = NULL_IF_CONFIG_SMALL("Concatenate audio and video streams."), +const FFFilter ff_avf_concat = { + .p.name = "concat", + .p.description = NULL_IF_CONFIG_SMALL("Concatenate audio and video streams."), + .p.inputs = NULL, + .p.outputs = NULL, + .p.priv_class = &concat_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS | AVFILTER_FLAG_DYNAMIC_OUTPUTS, .init = init, .uninit = uninit, .activate = activate, .priv_size = sizeof(ConcatContext), - .inputs = NULL, - .outputs = NULL, - .priv_class = &concat_class, - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS | AVFILTER_FLAG_DYNAMIC_OUTPUTS, - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .process_command = process_command, }; diff --git a/libavfilter/avf_showcqt.c b/libavfilter/avf_showcqt.c index 9fc5b00dd..7395b0bfc 100644 --- a/libavfilter/avf_showcqt.c +++ b/libavfilter/avf_showcqt.c @@ -404,33 +404,31 @@ static int init_axis_empty(ShowCQTContext *s) static int init_axis_from_file(ShowCQTContext *s) { - uint8_t *tmp_data[4] = { NULL }; - int tmp_linesize[4]; - enum AVPixelFormat tmp_format; - int tmp_w, tmp_h, ret; - - if ((ret = ff_load_image(tmp_data, tmp_linesize, &tmp_w, &tmp_h, &tmp_format, - s->axisfile, s->ctx)) < 0) - goto error; + AVFrame *tmp_frame; + int ret = ff_load_image(&tmp_frame, s->axisfile, s->ctx); + if (ret < 0) + return ret; ret = AVERROR(ENOMEM); if (!(s->axis_frame = av_frame_alloc())) goto error; - if ((ret = ff_scale_image(s->axis_frame->data, s->axis_frame->linesize, s->width, s->axis_h, - convert_axis_pixel_format(s->format), tmp_data, tmp_linesize, tmp_w, tmp_h, - tmp_format, s->ctx)) < 0) + ret = ff_scale_image(s->axis_frame->data, s->axis_frame->linesize, s->width, s->axis_h, + convert_axis_pixel_format(s->format), + tmp_frame->data, tmp_frame->linesize, tmp_frame->width, tmp_frame->height, + tmp_frame->format, s->ctx); + if (ret < 0) { + av_frame_free(&s->axis_frame); goto error; + } s->axis_frame->width = s->width; s->axis_frame->height = s->axis_h; s->axis_frame->format = convert_axis_pixel_format(s->format); - av_freep(tmp_data); - return 0; + ret = 0; error: - av_frame_free(&s->axis_frame); - av_freep(tmp_data); + av_frame_free(&tmp_frame); return ret; } @@ -619,7 +617,7 @@ static int render_fontconfig(ShowCQTContext *s, AVFrame *tmp, char* font) FcDefaultSubstitute(pat); if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) { - av_log(s->ctx, AV_LOG_ERROR, "could not substitue fontconfig options.\n"); + av_log(s->ctx, AV_LOG_ERROR, "could not substitute fontconfig options.\n"); FcPatternDestroy(pat); FcConfigDestroy(fontconfig); return AVERROR(ENOMEM); @@ -655,6 +653,7 @@ fail: static int render_default_font(AVFrame *tmp) { const char *str = "EF G A BC D "; + const uint8_t *vga16_font = avpriv_vga16_font_get(); int x, u, v, mask; uint8_t *data = tmp->data[0]; int linesize = tmp->linesize[0]; @@ -666,7 +665,7 @@ static int render_default_font(AVFrame *tmp) for (v = 0; v < height; v++) { uint8_t *p = startptr + v * linesize + height/2 * 4 * u; for (mask = 0x80; mask; mask >>= 1, p += 4) { - if (mask & avpriv_vga16_font[str[u] * 16 + v]) + if (mask & vga16_font[str[u] * 16 + v]) p[3] = 255; else p[3] = 0; @@ -1314,12 +1313,11 @@ static av_cold void uninit(AVFilterContext *ctx) common_uninit(ctx->priv); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, @@ -1330,21 +1328,17 @@ static int query_formats(AVFilterContext *ctx) int ret; /* set input audio formats */ - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; - layouts = ff_make_channel_layout_list(channel_layouts); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, channel_layouts); + if (ret < 0) return ret; /* set output video format */ - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -1419,7 +1413,7 @@ static int config_output(AVFilterLink *outlink) s->update_sono = update_sono_yuv; } -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_showcqt_init_x86(s); #endif @@ -1603,15 +1597,15 @@ static const AVFilterPad showcqt_outputs[] = { }, }; -const AVFilter ff_avf_showcqt = { - .name = "showcqt", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a CQT (Constant/Clamped Q Transform) spectrum video output."), +const FFFilter ff_avf_showcqt = { + .p.name = "showcqt", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a CQT (Constant/Clamped Q Transform) spectrum video output."), + .p.priv_class = &showcqt_class, .init = init, .activate = activate, .uninit = uninit, .priv_size = sizeof(ShowCQTContext), FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(showcqt_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showcqt_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_showcwt.c b/libavfilter/avf_showcwt.c index f26b89a81..839bdc798 100644 --- a/libavfilter/avf_showcwt.c +++ b/libavfilter/avf_showcwt.c @@ -222,30 +222,21 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->fdsp); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE }; int ret; - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) - return ret; - - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -1327,15 +1318,15 @@ static const AVFilterPad showcwt_outputs[] = { }, }; -const AVFilter ff_avf_showcwt = { - .name = "showcwt", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a CWT (Continuous Wavelet Transform) spectrum video output."), +const FFFilter ff_avf_showcwt = { + .p.name = "showcwt", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a CWT (Continuous Wavelet Transform) spectrum video output."), + .p.priv_class = &showcwt_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .uninit = uninit, .priv_size = sizeof(ShowCWTContext), FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(showcwt_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .activate = activate, - .priv_class = &showcwt_class, - .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/avf_showfreqs.c b/libavfilter/avf_showfreqs.c index da31b3215..bbbce2e42 100644 --- a/libavfilter/avf_showfreqs.c +++ b/libavfilter/avf_showfreqs.c @@ -116,32 +116,23 @@ static const AVOption showfreqs_options[] = { AVFILTER_DEFINE_CLASS(showfreqs); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; int ret; /* set input audio formats */ - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) - return ret; - - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; /* set output video format */ - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -558,14 +549,14 @@ static const AVFilterPad showfreqs_outputs[] = { }, }; -const AVFilter ff_avf_showfreqs = { - .name = "showfreqs", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a frequencies video output."), +const FFFilter ff_avf_showfreqs = { + .p.name = "showfreqs", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a frequencies video output."), + .p.priv_class = &showfreqs_class, .uninit = uninit, .priv_size = sizeof(ShowFreqsContext), .activate = activate, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(showfreqs_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showfreqs_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_showspatial.c b/libavfilter/avf_showspatial.c index f7380f885..db8484c56 100644 --- a/libavfilter/avf_showspatial.c +++ b/libavfilter/avf_showspatial.c @@ -80,28 +80,26 @@ static av_cold void uninit(AVFilterContext *ctx) av_audio_fifo_free(s->fifo); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layout = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GBRP, AV_PIX_FMT_NONE }; + static const AVChannelLayout layouts[] = { AV_CHANNEL_LAYOUT_STEREO, { .nb_channels = 0 } }; int ret; - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref (formats, &inlink->outcfg.formats )) < 0 || - (ret = ff_add_channel_layout (&layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_channel_layouts_ref (layout , &inlink->outcfg.channel_layouts)) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) return ret; - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -323,15 +321,15 @@ static const AVFilterPad showspatial_outputs[] = { }, }; -const AVFilter ff_avf_showspatial = { - .name = "showspatial", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spatial video output."), +const FFFilter ff_avf_showspatial = { + .p.name = "showspatial", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a spatial video output."), + .p.priv_class = &showspatial_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .uninit = uninit, .priv_size = sizeof(ShowSpatialContext), FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(showspatial_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .activate = spatial_activate, - .priv_class = &showspatial_class, - .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index 565f23c28..67bbc7715 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -358,32 +358,23 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->frames); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE }; int ret; /* set input audio formats */ - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) - return ret; - - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; /* set output video format */ - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -501,7 +492,7 @@ static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o) const uint8_t *font; int font_height; - font = avpriv_cga_font, font_height = 8; + font = avpriv_cga_font_get(), font_height = 8; for (int i = 0; txt[i]; i++) { int char_y, mask; @@ -1689,17 +1680,17 @@ static const AVFilterPad showspectrum_outputs[] = { }, }; -const AVFilter ff_avf_showspectrum = { - .name = "showspectrum", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output."), +const FFFilter ff_avf_showspectrum = { + .p.name = "showspectrum", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output."), + .p.priv_class = &showspectrum_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .uninit = uninit, .priv_size = sizeof(ShowSpectrumContext), FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(showspectrum_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .activate = activate, - .priv_class = &showspectrum_class, - .flags = AVFILTER_FLAG_SLICE_THREADS, }; #endif // CONFIG_SHOWSPECTRUM_FILTER @@ -1876,16 +1867,16 @@ static const AVFilterPad showspectrumpic_outputs[] = { }, }; -const AVFilter ff_avf_showspectrumpic = { - .name = "showspectrumpic", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output single picture."), +const FFFilter ff_avf_showspectrumpic = { + .p.name = "showspectrumpic", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output single picture."), + .p.priv_class = &showspectrumpic_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .uninit = uninit, .priv_size = sizeof(ShowSpectrumContext), FILTER_INPUTS(showspectrumpic_inputs), FILTER_OUTPUTS(showspectrumpic_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showspectrumpic_class, - .flags = AVFILTER_FLAG_SLICE_THREADS, + FILTER_QUERY_FUNC2(query_formats), }; #endif // CONFIG_SHOWSPECTRUMPIC_FILTER diff --git a/libavfilter/avf_showvolume.c b/libavfilter/avf_showvolume.c index d26fc8841..25959cab9 100644 --- a/libavfilter/avf_showvolume.c +++ b/libavfilter/avf_showvolume.c @@ -110,30 +110,21 @@ static av_cold int init(AVFilterContext *ctx) return 0; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; int ret; - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) - return ret; - - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -234,7 +225,7 @@ static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o) int font_height; int i; - font = avpriv_cga_font, font_height = 8; + font = avpriv_cga_font_get(), font_height = 8; for (i = 0; txt[i]; i++) { int char_y, mask; @@ -511,15 +502,15 @@ static const AVFilterPad showvolume_outputs[] = { }, }; -const AVFilter ff_avf_showvolume = { - .name = "showvolume", - .description = NULL_IF_CONFIG_SMALL("Convert input audio volume to video output."), +const FFFilter ff_avf_showvolume = { + .p.name = "showvolume", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio volume to video output."), + .p.priv_class = &showvolume_class, .init = init, .activate = activate, .uninit = uninit, .priv_size = sizeof(ShowVolumeContext), FILTER_INPUTS(showvolume_inputs), FILTER_OUTPUTS(showvolume_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showvolume_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c index 868e6a22d..dda15c530 100644 --- a/libavfilter/avf_showwaves.c +++ b/libavfilter/avf_showwaves.c @@ -155,32 +155,23 @@ static av_cold void uninit(AVFilterContext *ctx) } } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }; int ret; /* set input audio formats */ - formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) - return ret; - - layouts = ff_all_channel_layouts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + formats = ff_make_sample_format_list(sample_fmts); + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; /* set output video format */ - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + formats = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -805,17 +796,17 @@ static const AVFilterPad showwaves_outputs[] = { }, }; -const AVFilter ff_avf_showwaves = { - .name = "showwaves", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output."), +const FFFilter ff_avf_showwaves = { + .p.name = "showwaves", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output."), + .p.priv_class = &showwaves_class, .init = init, .uninit = uninit, .priv_size = sizeof(ShowWavesContext), FILTER_INPUTS(ff_audio_default_filterpad), .activate = activate, FILTER_OUTPUTS(showwaves_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showwaves_class, + FILTER_QUERY_FUNC2(query_formats), }; #endif // CONFIG_SHOWWAVES_FILTER @@ -917,16 +908,16 @@ static const AVFilterPad showwavespic_outputs[] = { }, }; -const AVFilter ff_avf_showwavespic = { - .name = "showwavespic", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output single picture."), +const FFFilter ff_avf_showwavespic = { + .p.name = "showwavespic", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output single picture."), + .p.priv_class = &showwavespic_class, .init = init, .uninit = uninit, .priv_size = sizeof(ShowWavesContext), FILTER_INPUTS(showwavespic_inputs), FILTER_OUTPUTS(showwavespic_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showwavespic_class, + FILTER_QUERY_FUNC2(query_formats), }; #endif // CONFIG_SHOWWAVESPIC_FILTER diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 058fb233d..bb0b665f0 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -80,10 +80,11 @@ static void tlog_ref(void *ctx, AVFrame *ref, int end) static void command_queue_pop(AVFilterContext *filter) { - AVFilterCommand *c= filter->command_queue; + FFFilterContext *ctxi = fffilterctx(filter); + AVFilterCommand *c = ctxi->command_queue; av_freep(&c->arg); av_freep(&c->command); - filter->command_queue= c->next; + ctxi->command_queue = c->next; av_free(c); } @@ -159,7 +160,8 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad, src->outputs[srcpad] || dst->inputs[dstpad]) return AVERROR(EINVAL); - if (!fffilterctx(src)->initialized || !fffilterctx(dst)->initialized) { + if (!(fffilterctx(src)->state_flags & AV_CLASS_STATE_INITIALIZED) || + !(fffilterctx(dst)->state_flags & AV_CLASS_STATE_INITIALIZED)) { av_log(src, AV_LOG_ERROR, "Filters must be initialized before linking.\n"); return AVERROR(EINVAL); } @@ -204,23 +206,13 @@ static void link_free(AVFilterLink **link) ff_framequeue_free(&li->fifo); ff_frame_pool_uninit(&li->frame_pool); av_channel_layout_uninit(&(*link)->ch_layout); + av_frame_side_data_free(&(*link)->side_data, &(*link)->nb_side_data); av_buffer_unref(&li->l.hw_frames_ctx); av_freep(link); } -#if FF_API_LINK_PUBLIC -void avfilter_link_free(AVFilterLink **link) -{ - link_free(link); -} -int avfilter_config_links(AVFilterContext *filter) -{ - return ff_filter_config_links(filter); -} -#endif - static void update_link_current_pts(FilterLinkInternal *li, int64_t pts) { AVFilterLink *const link = &li->l.pub; @@ -236,7 +228,8 @@ static void update_link_current_pts(FilterLinkInternal *li, int64_t pts) void ff_filter_set_ready(AVFilterContext *filter, unsigned priority) { - filter->ready = FFMAX(filter->ready, priority); + FFFilterContext *ctxi = fffilterctx(filter); + ctxi->ready = FFMAX(ctxi->ready, priority); } /** @@ -319,6 +312,9 @@ int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, if (link->outcfg.color_ranges) ff_formats_changeref(&link->outcfg.color_ranges, &filt->outputs[filt_dstpad_idx]->outcfg.color_ranges); + if (link->outcfg.alpha_modes) + ff_formats_changeref(&link->outcfg.alpha_modes, + &filt->outputs[filt_dstpad_idx]->outcfg.alpha_modes); if (link->outcfg.samplerates) ff_formats_changeref(&link->outcfg.samplerates, &filt->outputs[filt_dstpad_idx]->outcfg.samplerates); @@ -373,7 +369,22 @@ int ff_filter_config_links(AVFilterContext *filter) "callbacks on all outputs\n"); return AVERROR(EINVAL); } - } else if ((ret = config_link(link)) < 0) { + } + + /* Copy side data before link->srcpad->config_props() is called, so the filter + * may remove it for the next filter in the chain */ + if (inlink && inlink->nb_side_data && !link->nb_side_data) { + for (int j = 0; j < inlink->nb_side_data; j++) { + ret = av_frame_side_data_clone(&link->side_data, &link->nb_side_data, + inlink->side_data[j], 0); + if (ret < 0) { + av_frame_side_data_free(&link->side_data, &link->nb_side_data); + return ret; + } + } + } + + if (config_link && (ret = config_link(link)) < 0) { av_log(link->src, AV_LOG_ERROR, "Failed to configure output pad on %s\n", link->src->name); @@ -415,7 +426,7 @@ int ff_filter_config_links(AVFilterContext *filter) } if (link->src->nb_inputs && - !(link->src->filter->flags_internal & FF_FILTER_FLAG_HWFRAME_AWARE)) { + !(fffilter(link->src->filter)->flags_internal & FF_FILTER_FLAG_HWFRAME_AWARE)) { FilterLink *l0 = ff_filter_link(link->src->inputs[0]); av_assert0(!li->l.hw_frames_ctx && @@ -475,13 +486,13 @@ int ff_request_frame(AVFilterLink *link) FF_TPRINTF_START(NULL, request_frame); ff_tlog_link(NULL, link, 1); - av_assert1(!link->dst->filter->activate); + av_assert1(!fffilter(link->dst->filter)->activate); if (li->status_out) return li->status_out; if (li->status_in) { if (ff_framequeue_queued_frames(&li->fifo)) { av_assert1(!li->frame_wanted_out); - av_assert1(link->dst->ready >= 300); + av_assert1(fffilterctx(link->dst)->ready >= 300); return 0; } else { /* Acknowledge status change. Filters using ff_request_frame() will @@ -518,7 +529,7 @@ static int64_t guess_status_pts(AVFilterContext *ctx, int status, AVRational lin return AV_NOPTS_VALUE; } -static int ff_request_frame_to_filter(AVFilterLink *link) +static int request_frame_to_filter(AVFilterLink *link) { FilterLinkInternal * const li = ff_link_internal(link); int ret = -1; @@ -542,9 +553,6 @@ static int ff_request_frame_to_filter(AVFilterLink *link) static const char *const var_names[] = { "t", "n", -#if FF_API_FRAME_PKT - "pos", -#endif "w", "h", NULL @@ -553,19 +561,17 @@ static const char *const var_names[] = { enum { VAR_T, VAR_N, -#if FF_API_FRAME_PKT - VAR_POS, -#endif VAR_W, VAR_H, VAR_VARS_NB }; -static int set_enable_expr(AVFilterContext *ctx, const char *expr) +static int set_enable_expr(FFFilterContext *ctxi, const char *expr) { + AVFilterContext *ctx = &ctxi->p; int ret; char *expr_dup; - AVExpr *old = ctx->enable; + AVExpr *old = ctxi->enable; if (!(ctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)) { av_log(ctx, AV_LOG_ERROR, "Timeline ('enable' option) not supported " @@ -577,15 +583,15 @@ static int set_enable_expr(AVFilterContext *ctx, const char *expr) if (!expr_dup) return AVERROR(ENOMEM); - if (!ctx->var_values) { - ctx->var_values = av_calloc(VAR_VARS_NB, sizeof(*ctx->var_values)); - if (!ctx->var_values) { + if (!ctxi->var_values) { + ctxi->var_values = av_calloc(VAR_VARS_NB, sizeof(*ctxi->var_values)); + if (!ctxi->var_values) { av_free(expr_dup); return AVERROR(ENOMEM); } } - ret = av_expr_parse((AVExpr**)&ctx->enable, expr_dup, var_names, + ret = av_expr_parse(&ctxi->enable, expr_dup, var_names, NULL, NULL, NULL, NULL, 0, ctx->priv); if (ret < 0) { av_log(ctx->priv, AV_LOG_ERROR, @@ -615,16 +621,16 @@ int avfilter_process_command(AVFilterContext *filter, const char *cmd, const cha av_log(filter, AV_LOG_INFO, "%s", res); return 0; }else if(!strcmp(cmd, "enable")) { - return set_enable_expr(filter, arg); - }else if(filter->filter->process_command) { - return filter->filter->process_command(filter, cmd, arg, res, res_len, flags); + return set_enable_expr(fffilterctx(filter), arg); + }else if (fffilter(filter->filter)->process_command) { + return fffilter(filter->filter)->process_command(filter, cmd, arg, res, res_len, flags); } return AVERROR(ENOSYS); } unsigned avfilter_filter_pad_count(const AVFilter *filter, int is_output) { - return is_output ? filter->nb_outputs : filter->nb_inputs; + return is_output ? fffilter(filter)->nb_outputs : fffilter(filter)->nb_inputs; } static const char *default_filter_name(void *filter_ctx) @@ -676,6 +682,7 @@ static const AVClass avfilter_class = { .child_next = filter_child_next, .child_class_iterate = filter_child_class_iterate, .option = avfilter_options, + .state_flags_offset = offsetof(FFFilterContext, state_flags), }; static int default_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, @@ -695,6 +702,7 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) { FFFilterContext *ctx; AVFilterContext *ret; + const FFFilter *const fi = fffilter(filter); int preinited = 0; if (!filter) @@ -708,13 +716,13 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) ret->av_class = &avfilter_class; ret->filter = filter; ret->name = inst_name ? av_strdup(inst_name) : NULL; - if (filter->priv_size) { - ret->priv = av_mallocz(filter->priv_size); + if (fi->priv_size) { + ret->priv = av_mallocz(fi->priv_size); if (!ret->priv) goto err; } - if (filter->preinit) { - if (filter->preinit(ret) < 0) + if (fi->preinit) { + if (fi->preinit(ret) < 0) goto err; preinited = 1; } @@ -727,7 +735,7 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) ctx->execute = default_execute; - ret->nb_inputs = filter->nb_inputs; + ret->nb_inputs = fi->nb_inputs; if (ret->nb_inputs ) { ret->input_pads = av_memdup(filter->inputs, ret->nb_inputs * sizeof(*filter->inputs)); if (!ret->input_pads) @@ -737,7 +745,7 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) goto err; } - ret->nb_outputs = filter->nb_outputs; + ret->nb_outputs = fi->nb_outputs; if (ret->nb_outputs) { ret->output_pads = av_memdup(filter->outputs, ret->nb_outputs * sizeof(*filter->outputs)); if (!ret->output_pads) @@ -751,7 +759,7 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) err: if (preinited) - filter->uninit(ret); + fi->uninit(ret); av_freep(&ret->inputs); av_freep(&ret->input_pads); ret->nb_inputs = 0; @@ -779,6 +787,8 @@ static void free_link(AVFilterLink *link) ff_formats_unref(&link->outcfg.color_spaces); ff_formats_unref(&link->incfg.color_ranges); ff_formats_unref(&link->outcfg.color_ranges); + ff_formats_unref(&link->incfg.alpha_modes); + ff_formats_unref(&link->outcfg.alpha_modes); ff_formats_unref(&link->incfg.samplerates); ff_formats_unref(&link->outcfg.samplerates); ff_channel_layouts_unref(&link->incfg.channel_layouts); @@ -788,16 +798,18 @@ static void free_link(AVFilterLink *link) void avfilter_free(AVFilterContext *filter) { + FFFilterContext *ctxi; int i; if (!filter) return; + ctxi = fffilterctx(filter); if (filter->graph) ff_filter_graph_remove_filter(filter->graph, filter); - if (filter->filter->uninit) - filter->filter->uninit(filter); + if (fffilter(filter->filter)->uninit) + fffilter(filter->filter)->uninit(filter); for (i = 0; i < filter->nb_inputs; i++) { free_link(filter->inputs[i]); @@ -821,13 +833,12 @@ void avfilter_free(AVFilterContext *filter) av_freep(&filter->inputs); av_freep(&filter->outputs); av_freep(&filter->priv); - while(filter->command_queue){ + while (ctxi->command_queue) command_queue_pop(filter); - } av_opt_free(filter); - av_expr_free(filter->enable); - filter->enable = NULL; - av_freep(&filter->var_values); + av_expr_free(ctxi->enable); + ctxi->enable = NULL; + av_freep(&ctxi->var_values); av_free(filter); } @@ -909,7 +920,7 @@ int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options) FFFilterContext *ctxi = fffilterctx(ctx); int ret = 0; - if (ctxi->initialized) { + if (ctxi->state_flags & AV_CLASS_STATE_INITIALIZED) { av_log(ctx, AV_LOG_ERROR, "Filter already initialized\n"); return AVERROR(EINVAL); } @@ -929,18 +940,18 @@ int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options) ctx->thread_type = 0; } - if (ctx->filter->init) - ret = ctx->filter->init(ctx); + if (fffilter(ctx->filter)->init) + ret = fffilter(ctx->filter)->init(ctx); if (ret < 0) return ret; if (ctx->enable_str) { - ret = set_enable_expr(ctx, ctx->enable_str); + ret = set_enable_expr(ctxi, ctx->enable_str); if (ret < 0) return ret; } - ctxi->initialized = 1; + ctxi->state_flags |= AV_CLASS_STATE_INITIALIZED; return 0; } @@ -983,12 +994,45 @@ enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx) return pads[pad_idx].type; } +AVBufferRef *avfilter_link_get_hw_frames_ctx(AVFilterLink *link) +{ + FilterLink *plink = ff_filter_link(link); + if (plink->hw_frames_ctx) + return av_buffer_ref(plink->hw_frames_ctx); + + return NULL; +} + static int default_filter_frame(AVFilterLink *link, AVFrame *frame) { return ff_filter_frame(link->dst->outputs[0], frame); } -static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) +/** + * Evaluate the timeline expression of the link for the time and properties + * of the frame. + * @return >0 if enabled, 0 if disabled + * @note It does not update link->dst->is_disabled. + */ +static int evaluate_timeline_at_frame(AVFilterLink *link, const AVFrame *frame) +{ + FilterLink *l = ff_filter_link(link); + AVFilterContext *dstctx = link->dst; + FFFilterContext *dsti = fffilterctx(dstctx); + int64_t pts = frame->pts; + + if (!dstctx->enable_str) + return 1; + + dsti->var_values[VAR_N] = l->frame_count_out; + dsti->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base); + dsti->var_values[VAR_W] = link->w; + dsti->var_values[VAR_H] = link->h; + + return fabs(av_expr_eval(dsti->enable, dsti->var_values, NULL)) >= 0.5; +} + +static int filter_frame_framed(AVFilterLink *link, AVFrame *frame) { FilterLink *l = ff_filter_link(link); int (*filter_frame)(AVFilterLink *, AVFrame *); @@ -1006,7 +1050,7 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) } ff_inlink_process_commands(link, frame); - dstctx->is_disabled = !ff_inlink_evaluate_timeline_at_frame(link, frame); + dstctx->is_disabled = !evaluate_timeline_at_frame(link, frame); if (dstctx->is_disabled && (dstctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC)) @@ -1032,13 +1076,14 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame) strcmp(link->dst->filter->name, "format") && strcmp(link->dst->filter->name, "idet") && strcmp(link->dst->filter->name, "null") && - strcmp(link->dst->filter->name, "scale")) { + strcmp(link->dst->filter->name, "scale") && + strcmp(link->dst->filter->name, "libplacebo")) { av_assert1(frame->format == link->format); av_assert1(frame->width == link->w); av_assert1(frame->height == link->h); + if (av_pix_fmt_desc_get(link->format)->flags & AV_PIX_FMT_FLAG_ALPHA) + av_assert1(frame->alpha_mode == link->alpha_mode); } - - frame->sample_aspect_ratio = link->sample_aspect_ratio; } else { if (frame->format != link->format) { av_log(link->dst, AV_LOG_ERROR, "Format change is not supported\n"); @@ -1142,7 +1187,7 @@ static int take_samples(FilterLinkInternal *li, unsigned min, unsigned max, return 0; } -static int ff_filter_frame_to_filter(AVFilterLink *link) +static int filter_frame_to_filter(AVFilterLink *link) { FilterLinkInternal * const li = ff_link_internal(link); AVFrame *frame = NULL; @@ -1162,9 +1207,9 @@ static int ff_filter_frame_to_filter(AVFilterLink *link) produce one or more: unblock its outputs. */ filter_unblock(dst); /* AVFilterPad.filter_frame() expect frame_count_out to have the value - before the frame; ff_filter_frame_framed() will re-increment it. */ + before the frame; filter_frame_framed() will re-increment it. */ li->l.frame_count_out--; - ret = ff_filter_frame_framed(link, frame); + ret = filter_frame_framed(link, frame); if (ret < 0 && ret != li->status_out) { link_set_out_status(link, ret, AV_NOPTS_VALUE); } else { @@ -1191,7 +1236,7 @@ static int forward_status_change(AVFilterContext *filter, FilterLinkInternal *li if (!li_out->status_in) { progress++; - ret = ff_request_frame_to_filter(filter->outputs[out]); + ret = request_frame_to_filter(filter->outputs[out]); if (ret < 0) return ret; } @@ -1210,7 +1255,7 @@ static int forward_status_change(AVFilterContext *filter, FilterLinkInternal *li return 0; } -static int ff_filter_activate_default(AVFilterContext *filter) +static int filter_activate_default(AVFilterContext *filter) { unsigned i; int nb_eofs = 0; @@ -1226,7 +1271,7 @@ static int ff_filter_activate_default(AVFilterContext *filter) for (i = 0; i < filter->nb_inputs; i++) { FilterLinkInternal *li = ff_link_internal(filter->inputs[i]); if (samples_ready(li, li->l.min_samples)) { - return ff_filter_frame_to_filter(filter->inputs[i]); + return filter_frame_to_filter(filter->inputs[i]); } } for (i = 0; i < filter->nb_inputs; i++) { @@ -1240,9 +1285,18 @@ static int ff_filter_activate_default(AVFilterContext *filter) FilterLinkInternal * const li = ff_link_internal(filter->outputs[i]); if (li->frame_wanted_out && !li->frame_blocked_in) { - return ff_request_frame_to_filter(filter->outputs[i]); + return request_frame_to_filter(filter->outputs[i]); } } + for (i = 0; i < filter->nb_outputs; i++) { + FilterLinkInternal * const li = ff_link_internal(filter->outputs[i]); + if (li->frame_wanted_out) + return request_frame_to_filter(filter->outputs[i]); + } + if (!filter->nb_outputs) { + ff_inlink_request_frame(filter->inputs[0]); + return 0; + } return FFERROR_NOT_READY; } @@ -1376,18 +1430,30 @@ static int ff_filter_activate_default(AVFilterContext *filter) Rationale: checking frame_blocked_in is necessary to avoid requesting repeatedly on a blocked input if another is not blocked (example: [buffersrc1][testsrc1][buffersrc2][testsrc2]concat=v=2). + + - If an output has frame_wanted_out > 0 call request_frame(). + + Rationale: even if all inputs are blocked an activate callback should + request a frame on some if its inputs if a frame is requested on any of + its output. + + - Request a frame on the input for sinks. + + Rationale: sinks using the old api have no way to request a frame on their + input, so we need to do it for them. */ int ff_filter_activate(AVFilterContext *filter) { + FFFilterContext *ctxi = fffilterctx(filter); + const FFFilter *const fi = fffilter(filter->filter); int ret; /* Generic timeline support is not yet implemented but should be easy */ - av_assert1(!(filter->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC && - filter->filter->activate)); - filter->ready = 0; - ret = filter->filter->activate ? filter->filter->activate(filter) : - ff_filter_activate_default(filter); + av_assert1(!(fi->p.flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC && + fi->activate)); + ctxi->ready = 0; + ret = fi->activate ? fi->activate(filter) : filter_activate_default(filter); if (ret == FFERROR_NOT_READY) ret = 0; return ret; @@ -1441,7 +1507,7 @@ static void consume_update(FilterLinkInternal *li, const AVFrame *frame) update_link_current_pts(li, frame->pts); ff_inlink_process_commands(link, frame); if (link == link->dst->inputs[0]) - link->dst->is_disabled = !ff_inlink_evaluate_timeline_at_frame(link, frame); + link->dst->is_disabled = !evaluate_timeline_at_frame(link, frame); li->l.frame_count_out++; li->l.sample_count_out += frame->nb_samples; } @@ -1535,7 +1601,8 @@ int ff_inlink_make_frame_writable(AVFilterLink *link, AVFrame **rframe) int ff_inlink_process_commands(AVFilterLink *link, const AVFrame *frame) { - AVFilterCommand *cmd = link->dst->command_queue; + FFFilterContext *ctxi = fffilterctx(link->dst); + AVFilterCommand *cmd = ctxi->command_queue; while(cmd && cmd->time <= frame->pts * av_q2d(link->time_base)){ av_log(link->dst, AV_LOG_DEBUG, @@ -1543,36 +1610,11 @@ int ff_inlink_process_commands(AVFilterLink *link, const AVFrame *frame) cmd->time, cmd->command, cmd->arg); avfilter_process_command(link->dst, cmd->command, cmd->arg, 0, 0, cmd->flags); command_queue_pop(link->dst); - cmd= link->dst->command_queue; + cmd = ctxi->command_queue; } return 0; } -int ff_inlink_evaluate_timeline_at_frame(AVFilterLink *link, const AVFrame *frame) -{ - FilterLink *l = ff_filter_link(link); - AVFilterContext *dstctx = link->dst; - int64_t pts = frame->pts; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - int64_t pos = frame->pkt_pos; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - - if (!dstctx->enable_str) - return 1; - - dstctx->var_values[VAR_N] = l->frame_count_out; - dstctx->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base); - dstctx->var_values[VAR_W] = link->w; - dstctx->var_values[VAR_H] = link->h; -#if FF_API_FRAME_PKT - dstctx->var_values[VAR_POS] = pos == -1 ? NAN : pos; -#endif - - return fabs(av_expr_eval(dstctx->enable, dstctx->var_values, NULL)) >= 0.5; -} - void ff_inlink_request_frame(AVFilterLink *link) { av_unused FilterLinkInternal *li = ff_link_internal(link); diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index 1401577c5..02b58c42c 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -43,7 +43,6 @@ #include "libavutil/dict.h" #include "libavutil/frame.h" #include "libavutil/log.h" -#include "libavutil/samplefmt.h" #include "libavutil/pixfmt.h" #include "libavutil/rational.h" @@ -70,7 +69,6 @@ const char *avfilter_configuration(void); */ const char *avfilter_license(void); -typedef struct AVFilterContext AVFilterContext; typedef struct AVFilterLink AVFilterLink; typedef struct AVFilterPad AVFilterPad; typedef struct AVFilterFormats AVFilterFormats; @@ -98,6 +96,18 @@ const char *avfilter_pad_get_name(const AVFilterPad *pads, int pad_idx); */ enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx); +/** + * Get the hardware frames context of a filter link. + * + * @param link an AVFilterLink + * + * @return a ref-counted copy of the link's hw_frames_ctx field if there is + * a hardware frames context associated with the link or NULL otherwise. + * The returned AVBufferRef needs to be released with av_buffer_unref() + * when it is no longer used. + */ +AVBufferRef* avfilter_link_get_hw_frames_ctx(AVFilterLink *link); + /** * Lists of formats / etc. supported by an end of a link. * @@ -131,6 +141,11 @@ typedef struct AVFilterFormatsConfig { AVFilterFormats *color_spaces; ///< AVColorSpace AVFilterFormats *color_ranges; ///< AVColorRange + /** + * List of supported alpha modes, only for video with an alpha channel. + */ + AVFilterFormats *alpha_modes; ///< AVAlphaMode + } AVFilterFormatsConfig; /** @@ -243,204 +258,6 @@ typedef struct AVFilter { * A combination of AVFILTER_FLAG_* */ int flags; - - /***************************************************************** - * All fields below this line are not part of the public API. They - * may not be used outside of libavfilter and can be changed and - * removed at will. - * New public fields should be added right above. - ***************************************************************** - */ - - /** - * The number of entries in the list of inputs. - */ - uint8_t nb_inputs; - - /** - * The number of entries in the list of outputs. - */ - uint8_t nb_outputs; - - /** - * This field determines the state of the formats union. - * It is an enum FilterFormatsState value. - */ - uint8_t formats_state; - - /** - * Filter pre-initialization function - * - * This callback will be called immediately after the filter context is - * allocated, to allow allocating and initing sub-objects. - * - * If this callback is not NULL, the uninit callback will be called on - * allocation failure. - * - * @return 0 on success, - * AVERROR code on failure (but the code will be - * dropped and treated as ENOMEM by the calling code) - */ - int (*preinit)(AVFilterContext *ctx); - - /** - * Filter initialization function. - * - * This callback will be called only once during the filter lifetime, after - * all the options have been set, but before links between filters are - * established and format negotiation is done. - * - * Basic filter initialization should be done here. Filters with dynamic - * inputs and/or outputs should create those inputs/outputs here based on - * provided options. No more changes to this filter's inputs/outputs can be - * done after this callback. - * - * This callback must not assume that the filter links exist or frame - * parameters are known. - * - * @ref AVFilter.uninit "uninit" is guaranteed to be called even if - * initialization fails, so this callback does not have to clean up on - * failure. - * - * @return 0 on success, a negative AVERROR on failure - */ - int (*init)(AVFilterContext *ctx); - - /** - * Filter uninitialization function. - * - * Called only once right before the filter is freed. Should deallocate any - * memory held by the filter, release any buffer references, etc. It does - * not need to deallocate the AVFilterContext.priv memory itself. - * - * This callback may be called even if @ref AVFilter.init "init" was not - * called or failed, so it must be prepared to handle such a situation. - */ - void (*uninit)(AVFilterContext *ctx); - - /** - * The state of the following union is determined by formats_state. - * See the documentation of enum FilterFormatsState in internal.h. - */ - union { - /** - * Query formats supported by the filter on its inputs and outputs. - * - * This callback is called after the filter is initialized (so the inputs - * and outputs are fixed), shortly before the format negotiation. This - * callback may be called more than once. - * - * This callback must set ::AVFilterLink's - * @ref AVFilterFormatsConfig.formats "outcfg.formats" - * on every input link and - * @ref AVFilterFormatsConfig.formats "incfg.formats" - * on every output link to a list of pixel/sample formats that the filter - * supports on that link. - * For video links, this filter may also set - * @ref AVFilterFormatsConfig.color_spaces "incfg.color_spaces" - * / - * @ref AVFilterFormatsConfig.color_spaces "outcfg.color_spaces" - * and @ref AVFilterFormatsConfig.color_ranges "incfg.color_ranges" - * / - * @ref AVFilterFormatsConfig.color_ranges "outcfg.color_ranges" - * analogously. - * For audio links, this filter must also set - * @ref AVFilterFormatsConfig.samplerates "incfg.samplerates" - * / - * @ref AVFilterFormatsConfig.samplerates "outcfg.samplerates" - * and @ref AVFilterFormatsConfig.channel_layouts "incfg.channel_layouts" - * / - * @ref AVFilterFormatsConfig.channel_layouts "outcfg.channel_layouts" - * analogously. - * - * This callback must never be NULL if the union is in this state. - * - * @return zero on success, a negative value corresponding to an - * AVERROR code otherwise - */ - int (*query_func)(AVFilterContext *); - - /** - * Same as query_func(), except this function writes the results into - * provided arrays. - * - * @param cfg_in array of input format configurations with as many - * members as the filters has inputs (NULL when there are - * no inputs); - * @param cfg_out array of output format configurations with as many - * members as the filters has outputs (NULL when there - * are no outputs); - */ - int (*query_func2)(const AVFilterContext *, - struct AVFilterFormatsConfig **cfg_in, - struct AVFilterFormatsConfig **cfg_out); - /** - * A pointer to an array of admissible pixel formats delimited - * by AV_PIX_FMT_NONE. The generic code will use this list - * to indicate that this filter supports each of these pixel formats, - * provided that all inputs and outputs use the same pixel format. - * - * In addition to that the generic code will mark all inputs - * and all outputs as supporting all color spaces and ranges, as - * long as all inputs and outputs use the same color space/range. - * - * This list must never be NULL if the union is in this state. - * The type of all inputs and outputs of filters using this must - * be AVMEDIA_TYPE_VIDEO. - */ - const enum AVPixelFormat *pixels_list; - /** - * Analogous to pixels, but delimited by AV_SAMPLE_FMT_NONE - * and restricted to filters that only have AVMEDIA_TYPE_AUDIO - * inputs and outputs. - * - * In addition to that the generic code will mark all inputs - * and all outputs as supporting all sample rates and every - * channel count and channel layout, as long as all inputs - * and outputs use the same sample rate and channel count/layout. - */ - const enum AVSampleFormat *samples_list; - /** - * Equivalent to { pix_fmt, AV_PIX_FMT_NONE } as pixels_list. - */ - enum AVPixelFormat pix_fmt; - /** - * Equivalent to { sample_fmt, AV_SAMPLE_FMT_NONE } as samples_list. - */ - enum AVSampleFormat sample_fmt; - } formats; - - int priv_size; ///< size of private data to allocate for the filter - - int flags_internal; ///< Additional flags for avfilter internal use only. - - /** - * Make the filter instance process a command. - * - * @param cmd the command to process, for handling simplicity all commands must be alphanumeric only - * @param arg the argument for the command - * @param res a buffer with size res_size where the filter(s) can return a response. This must not change when the command is not supported. - * @param flags if AVFILTER_CMD_FLAG_FAST is set and the command would be - * time consuming then a filter should treat it like an unsupported command - * - * @returns >=0 on success otherwise an error code. - * AVERROR(ENOSYS) on unsupported commands - */ - int (*process_command)(AVFilterContext *, const char *cmd, const char *arg, char *res, int res_len, int flags); - - /** - * Filter activation function. - * - * Called when any processing is needed from the filter, instead of any - * filter_frame and request_frame on pads. - * - * The function must examine inlinks and outlinks and perform a single - * step of processing. If there is nothing to do, the function must do - * nothing and not return an error. If more steps are or may be - * possible, it must use ff_filter_set_ready() to schedule another - * activation. - */ - int (*activate)(AVFilterContext *ctx); } AVFilter; /** @@ -454,7 +271,7 @@ unsigned avfilter_filter_pad_count(const AVFilter *filter, int is_output); #define AVFILTER_THREAD_SLICE (1 << 0) /** An instance of a filter */ -struct AVFilterContext { +typedef struct AVFilterContext { const AVClass *av_class; ///< needed for av_log() and filters common options const AVFilter *filter; ///< the AVFilter of which this is an instance @@ -498,12 +315,32 @@ struct AVFilterContext { */ int nb_threads; +#if FF_API_CONTEXT_PUBLIC + /** + * @deprecated unused + */ + attribute_deprecated struct AVFilterCommand *command_queue; +#endif char *enable_str; ///< enable expression string - void *enable; ///< parsed expression (AVExpr*) - double *var_values; ///< variable values for the enable expression - int is_disabled; ///< the enabled state from the last expression evaluation +#if FF_API_CONTEXT_PUBLIC + /** + * @deprecated unused + */ + attribute_deprecated + void *enable; + /** + * @deprecated unused + */ + double *var_values; +#endif + /** + * MUST NOT be accessed from outside avfilter. + * + * the enabled state from the last expression evaluation + */ + int is_disabled; /** * For filters which will create hardware frames, sets the device the @@ -518,12 +355,13 @@ struct AVFilterContext { */ AVBufferRef *hw_device_ctx; +#if FF_API_CONTEXT_PUBLIC /** - * Ready status of the filter. - * A non-0 value means that the filter needs activating; - * a higher value suggests a more urgent activation. + * @deprecated this field should never have been accessed by callers */ + attribute_deprecated unsigned ready; +#endif /** * Sets the number of extra hardware frames which the filter will @@ -540,7 +378,7 @@ struct AVFilterContext { * configured. */ int extra_hw_frames; -}; +} AVFilterContext; /** * A link between two filters. This contains pointers to the source and @@ -592,6 +430,11 @@ struct AVFilterLink { */ AVRational time_base; + AVFrameSideData **side_data; + int nb_side_data; + + enum AVAlphaMode alpha_mode; ///< alpha mode (for videos with an alpha channel) + /***************************************************************** * All fields below this line are not part of the public API. They * may not be used outside of libavfilter and can be changed and @@ -623,20 +466,6 @@ struct AVFilterLink { int avfilter_link(AVFilterContext *src, unsigned srcpad, AVFilterContext *dst, unsigned dstpad); -#if FF_API_LINK_PUBLIC -/** - * @deprecated this function should never be called by users - */ -attribute_deprecated -void avfilter_link_free(AVFilterLink **link); - -/** - * @deprecated this function should never be called by users - */ -attribute_deprecated -int avfilter_config_links(AVFilterContext *filter); -#endif - #define AVFILTER_CMD_FLAG_ONE 1 ///< Stop once a filter understood the command (for target=all for example), fast filters are favored automatically #define AVFILTER_CMD_FLAG_FAST 2 ///< Only execute command when its fast (like a video out that supports contrast adjustment in hw) @@ -807,6 +636,14 @@ typedef struct AVFilterGraph { avfilter_execute_func *execute; char *aresample_swr_opts; ///< swr options to use for the auto-inserted aresample filters, Access ONLY through AVOptions + + /** + * Sets the maximum number of buffered frames in the filtergraph combined. + * + * Zero means no limit. This field must be set before calling + * avfilter_graph_config(). + */ + unsigned max_buffered_frames; } AVFilterGraph; /** @@ -845,9 +682,9 @@ AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph, AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name); /** - * Create and add a filter instance into an existing graph. - * The filter instance is created from the filter filt and inited - * with the parameter args. opaque is currently ignored. + * A convenience wrapper that allocates and initializes a filter in a single + * step. The filter instance is created from the filter filt and inited with the + * parameter args. opaque is currently ignored. * * In case of success put in *filt_ctx the pointer to the created * filter instance, otherwise set *filt_ctx to NULL. @@ -856,6 +693,12 @@ AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *nam * @param graph_ctx the filter graph * @return a negative AVERROR error code in case of failure, a non * negative value otherwise + * + * @warning Since the filter is initialized after this function successfully + * returns, you MUST NOT set any further options on it. If you need to + * do that, call ::avfilter_graph_alloc_filter(), followed by setting + * the options, followed by ::avfilter_init_dict() instead of this + * function. */ int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt, const char *name, const char *args, void *opaque, @@ -1062,7 +905,7 @@ typedef struct AVFilterParams { char *instance_name; /** - * Options to be apllied to the filter. + * Options to be applied to the filter. * * Filled by avfilter_graph_segment_parse(). Afterwards may be freely * modified by the caller. @@ -1245,7 +1088,7 @@ int avfilter_graph_segment_init(AVFilterGraphSegment *seg, int flags); * Unlabeled outputs are * - linked to the first unlinked unlabeled input in the next non-disabled * filter in the chain, if one exists - * - exported in the ouputs linked list otherwise, with NULL label + * - exported in the outputs linked list otherwise, with NULL label * * Similarly, unlinked input pads are exported in the inputs linked list. * diff --git a/libavfilter/avfilter_internal.h b/libavfilter/avfilter_internal.h index ec3933b1d..cad4b2124 100644 --- a/libavfilter/avfilter_internal.h +++ b/libavfilter/avfilter_internal.h @@ -100,9 +100,22 @@ typedef struct FFFilterContext { avfilter_execute_func *execute; - // 1 when avfilter_init_*() was successfully called on this filter - // 0 otherwise - int initialized; + // AV_CLASS_STATE_FLAG_* + unsigned state_flags; + + /** + * Ready status of the filter. + * A non-0 value means that the filter needs activating; + * a higher value suggests a more urgent activation. + */ + unsigned ready; + + /// parsed expression + struct AVExpr *enable; + /// variable values for the enable expression + double *var_values; + + struct AVFilterCommand *command_queue; } FFFilterContext; static inline FFFilterContext *fffilterctx(AVFilterContext *ctx) @@ -209,12 +222,4 @@ int ff_filter_graph_run_once(AVFilterGraph *graph); */ int ff_inlink_process_commands(AVFilterLink *link, const AVFrame *frame); -/** - * Evaluate the timeline expression of the link for the time and properties - * of the frame. - * @return >0 if enabled, 0 if disabled - * @note It does not update link->dst->is_disabled. - */ -int ff_inlink_evaluate_timeline_at_frame(AVFilterLink *link, const AVFrame *frame); - #endif /* AVFILTER_AVFILTER_INTERNAL_H */ diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 1744298ee..ad81d91bb 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -56,6 +56,8 @@ static const AVOption filtergraph_options[] = { AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, F|V }, {"aresample_swr_opts" , "default aresample filter options" , OFFSET(aresample_swr_opts) , AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, F|A }, + {"max_buffered_frames" , "maximum number of buffered frames allowed", OFFSET(max_buffered_frames), + AV_OPT_TYPE_UINT, {.i64 = 0}, 0, UINT_MAX, F|V|A }, { NULL }, }; @@ -301,7 +303,8 @@ static int filter_link_check_formats(void *log, AVFilterLink *link, AVFilterForm case AVMEDIA_TYPE_VIDEO: if ((ret = ff_formats_check_pixel_formats(log, cfg->formats)) < 0 || (ret = ff_formats_check_color_spaces(log, cfg->color_spaces)) < 0 || - (ret = ff_formats_check_color_ranges(log, cfg->color_ranges)) < 0) + (ret = ff_formats_check_color_ranges(log, cfg->color_ranges)) < 0 || + (ret = ff_formats_check_alpha_modes(log, cfg->alpha_modes)) < 0) return ret; break; @@ -343,16 +346,17 @@ static int filter_check_formats(AVFilterContext *ctx) static int filter_query_formats(AVFilterContext *ctx) { + const FFFilter *const filter = fffilter(ctx->filter); int ret; - if (ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC) { - if ((ret = ctx->filter->formats.query_func(ctx)) < 0) { + if (filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC) { + if ((ret = filter->formats.query_func(ctx)) < 0) { if (ret != AVERROR(EAGAIN)) av_log(ctx, AV_LOG_ERROR, "Query format failed for '%s': %s\n", ctx->name, av_err2str(ret)); return ret; } - } else if (ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) { + } else if (filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) { AVFilterFormatsConfig *cfg_in_stack[64], *cfg_out_stack[64]; AVFilterFormatsConfig **cfg_in_dyn = NULL, **cfg_out_dyn = NULL; AVFilterFormatsConfig **cfg_in, **cfg_out; @@ -385,7 +389,7 @@ static int filter_query_formats(AVFilterContext *ctx) cfg_out[i] = &l->incfg; } - ret = ctx->filter->formats.query_func2(ctx, cfg_in, cfg_out); + ret = filter->formats.query_func2(ctx, cfg_in, cfg_out); av_freep(&cfg_in_dyn); av_freep(&cfg_out_dyn); if (ret < 0) { @@ -396,8 +400,8 @@ static int filter_query_formats(AVFilterContext *ctx) } } - if (ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC || - ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) { + if (filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC || + filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) { ret = filter_check_formats(ctx); if (ret < 0) return ret; @@ -415,7 +419,8 @@ static int formats_declared(AVFilterContext *f) return 0; if (f->inputs[i]->type == AVMEDIA_TYPE_VIDEO && !(f->inputs[i]->outcfg.color_ranges && - f->inputs[i]->outcfg.color_spaces)) + f->inputs[i]->outcfg.color_spaces && + f->inputs[i]->outcfg.alpha_modes)) return 0; if (f->inputs[i]->type == AVMEDIA_TYPE_AUDIO && !(f->inputs[i]->outcfg.samplerates && @@ -427,7 +432,8 @@ static int formats_declared(AVFilterContext *f) return 0; if (f->outputs[i]->type == AVMEDIA_TYPE_VIDEO && !(f->outputs[i]->incfg.color_ranges && - f->outputs[i]->incfg.color_spaces)) + f->outputs[i]->incfg.color_spaces && + f->outputs[i]->incfg.alpha_modes)) return 0; if (f->outputs[i]->type == AVMEDIA_TYPE_AUDIO && !(f->outputs[i]->incfg.samplerates && @@ -437,6 +443,76 @@ static int formats_declared(AVFilterContext *f) return 1; } +static void print_link_formats(void *log_ctx, int level, const AVFilterLink *l, + const AVFilterFormatsMerger *mergers[], + int nb_mergers) +{ + if (av_log_get_level() < level) + return; + + AVBPrint bp; + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + + av_log(log_ctx, level, "Link '%s.%s' -> '%s.%s':\n", + l->src->name, l->srcpad->name, l->dst->name, l->dstpad->name); + + for (unsigned i = 0; i < nb_mergers; i++) { + const AVFilterFormatsMerger *m = mergers[i]; + av_log(log_ctx, level, " %s:\n", m->name); + m->print_list(&bp, FF_FIELD_AT(void *, m->offset, l->incfg)); + if (av_bprint_is_complete(&bp)) + av_log(log_ctx, level, " src: %s\n", bp.str); + av_bprint_clear(&bp); + + m->print_list(&bp, FF_FIELD_AT(void *, m->offset, l->outcfg)); + if (av_bprint_is_complete(&bp)) + av_log(log_ctx, level, " dst: %s\n", bp.str); + av_bprint_clear(&bp); + } + + av_bprint_finalize(&bp, NULL); +} + +static void print_filter_formats(void *log_ctx, int level, const AVFilterContext *f) +{ + if (av_log_get_level() < level) + return; + + AVBPrint bp; + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + + av_log(log_ctx, level, "Filter '%s' formats:\n", f->name); + for (int i = 0; i < f->nb_inputs; i++) { + const AVFilterLink *in = f->inputs[i]; + const AVFilterNegotiation *neg = ff_filter_get_negotiation(in); + av_log(log_ctx, level, " in[%d] '%s':\n", i, f->input_pads[i].name); + + for (unsigned i = 0; i < neg->nb_mergers; i++) { + const AVFilterFormatsMerger *m = &neg->mergers[i]; + m->print_list(&bp, FF_FIELD_AT(void *, m->offset, in->outcfg)); + if (av_bprint_is_complete(&bp)) + av_log(log_ctx, level, " %s: %s\n", m->name, bp.str); + av_bprint_clear(&bp); + } + } + + for (int i = 0; i < f->nb_outputs; i++) { + const AVFilterLink *out = f->outputs[i]; + const AVFilterNegotiation *neg = ff_filter_get_negotiation(out); + av_log(log_ctx, level, " out[%d] '%s':\n", i, f->output_pads[i].name); + + for (unsigned i = 0; i < neg->nb_mergers; i++) { + const AVFilterFormatsMerger *m = &neg->mergers[i]; + m->print_list(&bp, FF_FIELD_AT(void *, m->offset, out->incfg)); + if (av_bprint_is_complete(&bp)) + av_log(log_ctx, level, " %s: %s\n", m->name, bp.str); + av_bprint_clear(&bp); + } + } + + av_bprint_finalize(&bp, NULL); +} + /** * Perform one round of query_formats() and merging formats lists on the * filter graph. @@ -449,7 +525,7 @@ static int formats_declared(AVFilterContext *f) */ static int query_formats(AVFilterGraph *graph, void *log_ctx) { - int i, j, ret; + int i, j, k, ret; int converter_count = 0; int count_queried = 0; /* successful calls to query_formats() */ int count_merged = 0; /* successful merge of formats lists */ @@ -464,18 +540,24 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) if (ret < 0 && ret != AVERROR(EAGAIN)) return ret; /* note: EAGAIN could indicate a partial success, not counted yet */ - count_queried += ret >= 0; + if (ret >= 0) { + print_filter_formats(log_ctx, AV_LOG_DEBUG, f); + count_queried++; + } } /* go through and merge as many format lists as possible */ +retry: for (i = 0; i < graph->nb_filters; i++) { AVFilterContext *filter = graph->filters[i]; for (j = 0; j < filter->nb_inputs; j++) { AVFilterLink *link = filter->inputs[j]; const AVFilterNegotiation *neg; - unsigned neg_step; - int convert_needed = 0; + AVFilterContext *conv[4]; + const AVFilterFormatsMerger *mergers[4]; /* triggered mergers */ + const char *conv_filters[4], *conv_opts[4] = {0}; + unsigned neg_step, num_conv = 0, num_mergers = 0; if (!link) continue; @@ -487,8 +569,19 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) void *a = FF_FIELD_AT(void *, m->offset, link->incfg); void *b = FF_FIELD_AT(void *, m->offset, link->outcfg); if (a && b && a != b && !m->can_merge(a, b)) { - convert_needed = 1; - break; + for (k = 0; k < num_conv; k++) { + if (!strcmp(conv_filters[k], m->conversion_filter)) + break; + } + if (k == num_conv) { + av_assert1(num_conv < FF_ARRAY_ELEMS(conv_filters)); + conv_filters[num_conv] = m->conversion_filter; + if (m->conversion_opts_offset) + conv_opts[num_conv] = FF_FIELD_AT(char *, m->conversion_opts_offset, *graph); + num_conv++; + } + av_assert1(num_mergers < FF_ARRAY_ELEMS(mergers)); + mergers[num_mergers++] = m; } } for (neg_step = 0; neg_step < neg->nb_mergers; neg_step++) { @@ -499,52 +592,63 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) count_delayed++; } else if (a == b) { count_already_merged++; - } else if (!convert_needed) { + } else if (!num_conv) { count_merged++; ret = m->merge(a, b); if (ret < 0) return ret; - if (!ret) - convert_needed = 1; + if (!ret) { + mergers[num_mergers++] = m; + conv_filters[num_conv] = m->conversion_filter; + if (m->conversion_opts_offset) + conv_opts[num_conv] = FF_FIELD_AT(char *, m->conversion_opts_offset, *graph); + num_conv++; + } } } - if (convert_needed) { - AVFilterContext *convert; + /** + * Couldn't merge format lists; auto-insert conversion filters + * in reverse order to keep the order consistent with the list + * of mergers, since they are prepended onto the existing link + */ + for (k = num_conv - 1; k >= 0; k--) { const AVFilter *filter; - AVFilterLink *inlink, *outlink; char inst_name[30]; - const char *opts; if (fffiltergraph(graph)->disable_auto_convert) { av_log(log_ctx, AV_LOG_ERROR, "The filters '%s' and '%s' do not have a common format " "and automatic conversion is disabled.\n", link->src->name, link->dst->name); + print_link_formats(log_ctx, AV_LOG_ERROR, link, mergers, num_mergers); return AVERROR(EINVAL); } - /* couldn't merge format lists. auto-insert conversion filter */ - if (!(filter = avfilter_get_by_name(neg->conversion_filter))) { + if (!(filter = avfilter_get_by_name(conv_filters[k]))) { av_log(log_ctx, AV_LOG_ERROR, "'%s' filter not present, cannot convert formats.\n", - neg->conversion_filter); + conv_filters[k]); + print_link_formats(log_ctx, AV_LOG_ERROR, link, mergers, num_mergers); return AVERROR(EINVAL); } snprintf(inst_name, sizeof(inst_name), "auto_%s_%d", - neg->conversion_filter, converter_count++); - opts = FF_FIELD_AT(char *, neg->conversion_opts_offset, *graph); - ret = avfilter_graph_create_filter(&convert, filter, inst_name, opts, NULL, graph); + conv_filters[k], converter_count++); + ret = avfilter_graph_create_filter(&conv[k], filter, inst_name, + conv_opts[k], NULL, graph); if (ret < 0) return ret; - if ((ret = avfilter_insert_filter(link, convert, 0, 0)) < 0) + if ((ret = avfilter_insert_filter(link, conv[k], 0, 0)) < 0) return ret; - if ((ret = filter_query_formats(convert)) < 0) + if ((ret = filter_query_formats(conv[k])) < 0) return ret; + } - inlink = convert->inputs[0]; - outlink = convert->outputs[0]; + /* preemptively settle formats of auto filters */ + for (k = 0; k < num_conv; k++) { + AVFilterLink *inlink = conv[k]->inputs[0]; + AVFilterLink *outlink = conv[k]->outputs[0]; av_assert0( inlink->incfg.formats->refcount > 0); av_assert0( inlink->outcfg.formats->refcount > 0); av_assert0(outlink->incfg.formats->refcount > 0); @@ -558,6 +662,10 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) av_assert0( inlink->outcfg.color_ranges->refcount > 0); av_assert0(outlink-> incfg.color_ranges->refcount > 0); av_assert0(outlink->outcfg.color_ranges->refcount > 0); + av_assert0( inlink-> incfg.alpha_modes->refcount > 0); + av_assert0( inlink->outcfg.alpha_modes->refcount > 0); + av_assert0(outlink-> incfg.alpha_modes->refcount > 0); + av_assert0(outlink->outcfg.alpha_modes->refcount > 0); } else if (outlink->type == AVMEDIA_TYPE_AUDIO) { av_assert0( inlink-> incfg.samplerates->refcount > 0); av_assert0( inlink->outcfg.samplerates->refcount > 0); @@ -568,11 +676,15 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) av_assert0(outlink-> incfg.channel_layouts->refcount > 0); av_assert0(outlink->outcfg.channel_layouts->refcount > 0); } + #define MERGE(merger, link) \ ((merger)->merge(FF_FIELD_AT(void *, (merger)->offset, (link)->incfg), \ FF_FIELD_AT(void *, (merger)->offset, (link)->outcfg))) + for (neg_step = 0; neg_step < neg->nb_mergers; neg_step++) { const AVFilterFormatsMerger *m = &neg->mergers[neg_step]; + if (strcmp(m->conversion_filter, conv_filters[k])) + continue; if ((ret = MERGE(m, inlink)) <= 0 || (ret = MERGE(m, outlink)) <= 0) { if (ret < 0) @@ -580,10 +692,21 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) av_log(log_ctx, AV_LOG_ERROR, "Impossible to convert between the formats supported by the filter " "'%s' and the filter '%s'\n", link->src->name, link->dst->name); + print_link_formats(log_ctx, AV_LOG_ERROR, inlink, &m, 1); + print_link_formats(log_ctx, AV_LOG_ERROR, outlink, &m, 1); return AVERROR(ENOSYS); + } else { + count_merged += 2; } } } + + /* if there is an auto filter, we may need another round to fully + * settle formats due to possible cross-incompatibilities between + * the auto filters themselves, or between the auto filters and + * a different attribute of the filter they are modifying */ + if (num_conv) + goto retry; } } @@ -724,8 +847,8 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref) swfmt = AV_PIX_FMT_YUV420P; } + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(swfmt); if (!ff_fmt_is_regular_yuv(swfmt)) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(swfmt); /* These fields are explicitly documented as affecting YUV only, * so set them to sane values for other formats. */ if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) @@ -760,6 +883,19 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref) link->color_range = link->incfg.color_ranges->formats[0]; } } + + if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) { + if (!link->incfg.alpha_modes->nb_formats) { + av_log(link->src, AV_LOG_ERROR, "Cannot select alpha mode for" + " the link between filters %s and %s.\n", link->src->name, + link->dst->name); + return AVERROR(EINVAL); + } + link->incfg.alpha_modes->nb_formats = 1; + link->alpha_mode = link->incfg.alpha_modes->formats[0]; + } else { + link->alpha_mode = AVALPHA_MODE_UNSPECIFIED; + } } else if (link->type == AVMEDIA_TYPE_AUDIO) { int ret; @@ -798,6 +934,8 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref) ff_formats_unref(&link->outcfg.color_spaces); ff_formats_unref(&link->incfg.color_ranges); ff_formats_unref(&link->outcfg.color_ranges); + ff_formats_unref(&link->incfg.alpha_modes); + ff_formats_unref(&link->outcfg.alpha_modes); return 0; } @@ -851,6 +989,8 @@ static int reduce_formats_on_filter(AVFilterContext *filter) nb_formats, ff_add_format); REDUCE_FORMATS(int, AVFilterFormats, color_ranges, formats, nb_formats, ff_add_format); + REDUCE_FORMATS(int, AVFilterFormats, alpha_modes, formats, + nb_formats, ff_add_format); /* reduce channel layouts */ for (i = 0; i < filter->nb_inputs; i++) { @@ -1295,6 +1435,8 @@ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx) { int ret; + if (graphctx->max_buffered_frames) + fffiltergraph(graphctx)->frame_queues.max_queued = graphctx->max_buffered_frames; if ((ret = graph_check_validity(graphctx, log_ctx))) return ret; if ((ret = graph_config_formats(graphctx, log_ctx))) @@ -1348,8 +1490,9 @@ int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const for (i = 0; i < graph->nb_filters; i++) { AVFilterContext *filter = graph->filters[i]; + FFFilterContext *ctxi = fffilterctx(filter); if(filter && (!strcmp(target, "all") || !strcmp(target, filter->name) || !strcmp(target, filter->filter->name))){ - AVFilterCommand **queue = &filter->command_queue, *next; + AVFilterCommand **queue = &ctxi->command_queue, *next; while (*queue && (*queue)->time <= ts) queue = &(*queue)->next; next = *queue; @@ -1432,7 +1575,7 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph) while (graphi->sink_links_count) { oldesti = graphi->sink_links[0]; oldest = &oldesti->l.pub; - if (oldest->dst->filter->activate) { + if (fffilter(oldest->dst->filter)->activate) { r = av_buffersink_get_frame_flags(oldest->dst, NULL, AV_BUFFERSINK_FLAG_PEEK); if (r != AVERROR_EOF) @@ -1453,11 +1596,13 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph) } if (!graphi->sink_links_count) return AVERROR_EOF; - av_assert1(!oldest->dst->filter->activate); + av_assert1(!fffilter(oldest->dst->filter)->activate); av_assert1(oldesti->age_index >= 0); frame_count = oldesti->l.frame_count_out; while (frame_count == oldesti->l.frame_count_out) { r = ff_filter_graph_run_once(graph); + if (r == FFERROR_BUFFERSRC_EMPTY) + r = 0; if (r == AVERROR(EAGAIN) && !oldesti->frame_wanted_out && !oldesti->frame_blocked_in && !oldesti->status_in) @@ -1470,15 +1615,19 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph) int ff_filter_graph_run_once(AVFilterGraph *graph) { - AVFilterContext *filter; + FFFilterContext *ctxi; unsigned i; av_assert0(graph->nb_filters); - filter = graph->filters[0]; - for (i = 1; i < graph->nb_filters; i++) - if (graph->filters[i]->ready > filter->ready) - filter = graph->filters[i]; - if (!filter->ready) + ctxi = fffilterctx(graph->filters[0]); + for (i = 1; i < graph->nb_filters; i++) { + FFFilterContext *ctxi_other = fffilterctx(graph->filters[i]); + + if (ctxi_other->ready > ctxi->ready) + ctxi = ctxi_other; + } + + if (!ctxi->ready) return AVERROR(EAGAIN); - return ff_filter_activate(filter); + return ff_filter_activate(&ctxi->p); } diff --git a/libavfilter/blend_modes.c b/libavfilter/blend_modes.c index 9b1e78b14..981c15a02 100644 --- a/libavfilter/blend_modes.c +++ b/libavfilter/blend_modes.c @@ -34,16 +34,21 @@ #define MAX 255 #define HALF 128 #define CLIP(x) (av_clip_uint8(x)) +#define BUILD_TYPE_SPECIFIC_FUNCS #elif DEPTH == 32 #define PIXEL float #define MAX 1.f #define HALF 0.5f #define CLIP(x) (x) +#define BUILD_TYPE_SPECIFIC_FUNCS #else #define PIXEL uint16_t #define MAX ((1 << DEPTH) - 1) #define HALF (1 << (DEPTH - 1)) #define CLIP(x) ((int)av_clip_uintp2(x, DEPTH)) +#if DEPTH == 16 +#define BUILD_TYPE_SPECIFIC_FUNCS +#endif #endif #undef MULTIPLY @@ -92,34 +97,27 @@ static void fn0(NAME)(const uint8_t *_top, ptrdiff_t top_linesize, \ ptrdiff_t width, ptrdiff_t height, \ FilterParams *param, SliceParams *sliceparam) \ { \ - const PIXEL *top = (const PIXEL *)_top; \ - const PIXEL *bottom = (const PIXEL *)_bottom; \ - PIXEL *dst = (PIXEL *)_dst; \ const float opacity = param->opacity; \ \ - dst_linesize /= sizeof(PIXEL); \ - top_linesize /= sizeof(PIXEL); \ - bottom_linesize /= sizeof(PIXEL); \ - \ for (int i = 0; i < height; i++) { \ + const PIXEL *top = (const PIXEL *)_top; \ + const PIXEL *bottom = (const PIXEL *)_bottom; \ + PIXEL *dst = (PIXEL *)_dst; \ for (int j = 0; j < width; j++) { \ dst[j] = top[j] + ((EXPR)-top[j]) * opacity; \ } \ - dst += dst_linesize; \ - top += top_linesize; \ - bottom += bottom_linesize; \ + _dst += dst_linesize; \ + _top += top_linesize; \ + _bottom += bottom_linesize; \ } \ } fn(addition, FFMIN(MAX, A + B)) fn(grainmerge, CLIP(A + B - HALF)) -fn(average, (A + B) / 2) -fn(subtract, FFMAX(0, A - B)) fn(multiply, MULTIPLY(1, A, B)) fn(multiply128,CLIP((A - HALF) * B / MDIV + HALF)) fn(negation, MAX - FFABS(MAX - A - B)) fn(extremity, FFABS(MAX - A - B)) -fn(difference, FFABS(A - B)) fn(grainextract, CLIP(HALF + A - B)) fn(screen, SCREEN(1, A, B)) fn(overlay, (A < HALF) ? MULTIPLY(2, A, B) : SCREEN(2, A, B)) @@ -127,8 +125,6 @@ fn(hardlight, (B < HALF) ? MULTIPLY(2, B, A) : SCREEN(2, B, A)) fn(hardmix, (A < (MAX - B)) ? 0: MAX) fn(heat, (A == 0) ? 0 : MAX - FFMIN(((MAX - B) * (MAX - B)) / A, MAX)) fn(freeze, (B == 0) ? 0 : MAX - FFMIN(((MAX - A) * (MAX - A)) / B, MAX)) -fn(darken, FFMIN(A, B)) -fn(lighten, FFMAX(A, B)) fn(divide, CLIP(B == 0 ? MAX : MAX * A / B)) fn(dodge, DODGE(A, B)) fn(burn, BURN(A, B)) @@ -138,15 +134,24 @@ fn(pinlight, (B < HALF) ? FFMIN(A, 2 * B) : FFMAX(A, 2 * (B - HALF))) fn(phoenix, FFMIN(A, B) - FFMAX(A, B) + MAX) fn(reflect, (B == MAX) ? B : FFMIN(MAX, (A * A / (MAX - B)))) fn(glow, (A == MAX) ? A : FFMIN(MAX, (B * B / (MAX - A)))) -fn(and, INT2FLOAT(FLOAT2INT(A) & FLOAT2INT(B))) -fn(or, INT2FLOAT(FLOAT2INT(A) | FLOAT2INT(B))) -fn(xor, INT2FLOAT(FLOAT2INT(A) ^ FLOAT2INT(B))) fn(vividlight, (A < HALF) ? BURN(2 * A, B) : DODGE(2 * (A - HALF), B)) fn(linearlight,CLIP((B < HALF) ? B + 2 * A - MAX : B + 2 * (A - HALF))) fn(softdifference,CLIP((A > B) ? (B == MAX) ? 0 : (A - B) * MAX / (MAX - B) : (B == 0) ? 0 : (B - A) * MAX / B)) -fn(geometric, GEOMETRIC(A, B)) -fn(harmonic, A == 0 && B == 0 ? 0 : 2LL * A * B / (A + B)) fn(bleach, (MAX - B) + (MAX - A) - MAX) fn(stain, 2 * MAX - A - B) fn(interpolate,LRINTF(MAX * (2 - cosf(A * M_PI / MAX) - cosf(B * M_PI / MAX)) * 0.25f)) fn(hardoverlay,A == MAX ? MAX : FFMIN(MAX, MAX * B / (2 * MAX - 2 * A) * (A > HALF) + 2 * A * B / MAX * (A <= HALF))) + +#ifdef BUILD_TYPE_SPECIFIC_FUNCS +fn(average, (A + B) / 2) +fn(subtract, FFMAX(0, A - B)) +fn(difference, FFABS(A - B)) +fn(darken, FFMIN(A, B)) +fn(lighten, FFMAX(A, B)) +fn(and, INT2FLOAT(FLOAT2INT(A) & FLOAT2INT(B))) +fn(or, INT2FLOAT(FLOAT2INT(A) | FLOAT2INT(B))) +fn(xor, INT2FLOAT(FLOAT2INT(A) ^ FLOAT2INT(B))) +fn(geometric, GEOMETRIC(A, B)) +fn(harmonic, A == 0 && B == 0 ? 0 : 2LL * A * B / (A + B)) +#undef BUILD_TYPE_SPECIFIC_FUNCS +#endif diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c index 5811720c6..75b93cee3 100644 --- a/libavfilter/buffersink.c +++ b/libavfilter/buffersink.c @@ -28,6 +28,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" @@ -42,28 +43,54 @@ typedef struct BufferSinkContext { const AVClass *class; unsigned warning_limit; + unsigned frame_size; /* only used for video */ +#if FF_API_BUFFERSINK_OPTS enum AVPixelFormat *pixel_fmts; ///< list of accepted pixel formats int pixel_fmts_size; enum AVColorSpace *color_spaces; ///< list of accepted color spaces int color_spaces_size; enum AVColorRange *color_ranges; ///< list of accepted color ranges int color_ranges_size; + enum AVAlphaMode *alpha_modes; ///< list of accepted alpha modes + int alpha_modes_size; +#endif + + enum AVPixelFormat *pixel_formats; + unsigned nb_pixel_formats; + + int *colorspaces; + unsigned nb_colorspaces; + + int *colorranges; + unsigned nb_colorranges; + + int *alphamodes; + unsigned nb_alphamodes; /* only used for audio */ +#if FF_API_BUFFERSINK_OPTS enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats int sample_fmts_size; char *channel_layouts_str; ///< list of accepted channel layouts int all_channel_counts; int *sample_rates; ///< list of accepted sample rates int sample_rates_size; +#endif + + enum AVSampleFormat *sample_formats; + unsigned nb_sample_formats; + + int *samplerates; + unsigned nb_samplerates; + + AVChannelLayout *channel_layouts; + unsigned nb_channel_layouts; AVFrame *peeked_frame; } BufferSinkContext; -#define NB_ITEMS(list) (list ## _size / sizeof(*list)) - int attribute_align_arg av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame) { return av_buffersink_get_frame_flags(ctx, frame, 0); @@ -91,6 +118,7 @@ static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, i int status, ret; AVFrame *cur_frame; int64_t pts; + int buffersrc_empty = 0; if (buf->peeked_frame) return return_or_keep_frame(buf, frame, buf->peeked_frame, flags); @@ -109,8 +137,15 @@ static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, i return AVERROR(EAGAIN); } else if (li->frame_wanted_out) { ret = ff_filter_graph_run_once(ctx->graph); - if (ret < 0) + if (ret == FFERROR_BUFFERSRC_EMPTY) { + buffersrc_empty = 1; + } else if (ret == AVERROR(EAGAIN)) { + if (buffersrc_empty) + return ret; + ff_inlink_request_frame(inlink); + } else if (ret < 0) { return ret; + } } else { ff_inlink_request_frame(inlink); } @@ -133,10 +168,117 @@ static av_cold int common_init(AVFilterContext *ctx) { BufferSinkContext *buf = ctx->priv; +#if FF_API_BUFFERSINK_OPTS + +#define CHECK_LIST_SIZE(field) \ + if (buf->field ## _size % sizeof(*buf->field)) { \ + av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \ + "should be multiple of %d\n", \ + buf->field ## _size, (int)sizeof(*buf->field)); \ + return AVERROR(EINVAL); \ + } + + if (ctx->input_pads[0].type == AVMEDIA_TYPE_VIDEO) { + if ((buf->pixel_fmts_size || buf->color_spaces_size || buf->color_ranges_size || buf->alpha_modes_size) && + (buf->nb_pixel_formats || buf->nb_colorspaces || buf->nb_colorranges || buf->nb_alphamodes)) { + av_log(ctx, AV_LOG_ERROR, "Cannot combine old and new format lists\n"); + return AVERROR(EINVAL); + } + + CHECK_LIST_SIZE(pixel_fmts) + CHECK_LIST_SIZE(color_spaces) + CHECK_LIST_SIZE(color_ranges) + CHECK_LIST_SIZE(alpha_modes) + } else { + if ((buf->sample_fmts_size || buf->channel_layouts_str || buf->sample_rates_size) && + (buf->nb_sample_formats || buf->nb_samplerates || buf->nb_channel_layouts)) { + av_log(ctx, AV_LOG_ERROR, "Cannot combine old and new format lists\n"); + return AVERROR(EINVAL); + } + + CHECK_LIST_SIZE(sample_fmts) + CHECK_LIST_SIZE(sample_rates) + + if (buf->channel_layouts_str) { + const char *cur = buf->channel_layouts_str; + + if (buf->all_channel_counts) + av_log(ctx, AV_LOG_WARNING, + "Conflicting all_channel_counts and list in options\n"); + + while (cur) { + void *tmp; + char *next = strchr(cur, '|'); + if (next) + *next++ = 0; + + // +2 for the new element and terminator + tmp = av_realloc_array(buf->channel_layouts, buf->nb_channel_layouts + 2, + sizeof(*buf->channel_layouts)); + if (!tmp) + return AVERROR(ENOMEM); + + buf->channel_layouts = tmp; + memset(&buf->channel_layouts[buf->nb_channel_layouts], 0, + sizeof(*buf->channel_layouts) * 2); + buf->nb_channel_layouts++; + + int ret = av_channel_layout_from_string(&buf->channel_layouts[buf->nb_channel_layouts - 1], cur); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: %s.\n", cur); + return ret; + } + + cur = next; + } + + if (buf->nb_channel_layouts) + buf->channel_layouts[buf->nb_channel_layouts] = (AVChannelLayout){ 0 }; + } + } + +#undef CHECK_LIST_SIZE + +#endif + buf->warning_limit = 100; return 0; } +#define TERMINATE_ARRAY(arr, val) \ + if (s->arr) { \ + void *tmp = av_realloc_array(s->arr, s->nb_ ## arr + 1, sizeof(*s->arr)); \ + if (!tmp) \ + return AVERROR(ENOMEM); \ + s->arr = tmp; \ + s->arr[s->nb_ ## arr] = val; \ + } + +static int init_video(AVFilterContext *ctx) +{ + BufferSinkContext *s = ctx->priv; + + TERMINATE_ARRAY(pixel_formats, AV_PIX_FMT_NONE); + TERMINATE_ARRAY(colorranges, -1); + TERMINATE_ARRAY(colorspaces, -1); + TERMINATE_ARRAY(alphamodes, -1); + + return common_init(ctx); +} + +static int init_audio(AVFilterContext *ctx) +{ + BufferSinkContext *s = ctx->priv; + + TERMINATE_ARRAY(sample_formats, AV_SAMPLE_FMT_NONE); + TERMINATE_ARRAY(samplerates, -1); + TERMINATE_ARRAY(channel_layouts, (AVChannelLayout){ .nb_channels = 0 }); + + return common_init(ctx); +} + +#undef TERMINATE_ARRAY + static void uninit(AVFilterContext *ctx) { BufferSinkContext *buf = ctx->priv; @@ -162,16 +304,30 @@ static int activate(AVFilterContext *ctx) return 0; } +static int config_input_audio(AVFilterLink *inlink) +{ + BufferSinkContext *buf = inlink->dst->priv; + FilterLink *l = ff_filter_link(inlink); + + l->min_samples = l->max_samples = buf->frame_size; + + return 0; +} + void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size) { - FilterLink *inlink = ff_filter_link(ctx->inputs[0]); + BufferSinkContext *buf = ctx->priv; + buf->frame_size = frame_size; - inlink->min_samples = inlink->max_samples = frame_size; + if (ctx->inputs && ctx->inputs[0]) { + FilterLink *l = ff_filter_link(ctx->inputs[0]); + l->min_samples = l->max_samples = buf->frame_size; + } } #define MAKE_AVFILTERLINK_ACCESSOR(type, field) \ type av_buffersink_get_##field(const AVFilterContext *ctx) { \ - av_assert0(ctx->filter->activate == activate); \ + av_assert0(fffilter(ctx->filter)->activate == activate); \ return ctx->inputs[0]->field; \ } @@ -184,26 +340,27 @@ MAKE_AVFILTERLINK_ACCESSOR(int , h ) MAKE_AVFILTERLINK_ACCESSOR(AVRational , sample_aspect_ratio) MAKE_AVFILTERLINK_ACCESSOR(enum AVColorSpace, colorspace) MAKE_AVFILTERLINK_ACCESSOR(enum AVColorRange, color_range) +MAKE_AVFILTERLINK_ACCESSOR(enum AVAlphaMode , alpha_mode) MAKE_AVFILTERLINK_ACCESSOR(int , sample_rate ) AVRational av_buffersink_get_frame_rate(const AVFilterContext *ctx) { FilterLink *l = ff_filter_link(ctx->inputs[0]); - av_assert0(ctx->filter->activate == activate); + av_assert0(fffilter(ctx->filter)->activate == activate); return l->frame_rate; } AVBufferRef* av_buffersink_get_hw_frames_ctx(const AVFilterContext *ctx) { FilterLink *l = ff_filter_link(ctx->inputs[0]); - av_assert0(ctx->filter->activate == activate); + av_assert0(fffilter(ctx->filter)->activate == activate); return l->hw_frames_ctx; } int av_buffersink_get_channels(const AVFilterContext *ctx) { - av_assert0(ctx->filter->activate == activate); + av_assert0(fffilter(ctx->filter)->activate == activate); return ctx->inputs[0]->ch_layout.nb_channels; } @@ -212,7 +369,7 @@ int av_buffersink_get_ch_layout(const AVFilterContext *ctx, AVChannelLayout *out AVChannelLayout ch_layout = { 0 }; int ret; - av_assert0(ctx->filter->activate == activate); + av_assert0(fffilter(ctx->filter)->activate == activate); ret = av_channel_layout_copy(&ch_layout, &ctx->inputs[0]->ch_layout); if (ret < 0) return ret; @@ -220,28 +377,57 @@ int av_buffersink_get_ch_layout(const AVFilterContext *ctx, AVChannelLayout *out return 0; } -#define CHECK_LIST_SIZE(field) \ - if (buf->field ## _size % sizeof(*buf->field)) { \ - av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \ - "should be multiple of %d\n", \ - buf->field ## _size, (int)sizeof(*buf->field)); \ - return AVERROR(EINVAL); \ - } -static int vsink_query_formats(AVFilterContext *ctx) +const AVFrameSideData *const *av_buffersink_get_side_data(const AVFilterContext *ctx, + int *nb_side_data) { - BufferSinkContext *buf = ctx->priv; - unsigned i; + av_assert0(fffilter(ctx->filter)->activate == activate); + *nb_side_data = ctx->inputs[0]->nb_side_data; + return (const AVFrameSideData *const *)ctx->inputs[0]->side_data; +} + +#if FF_API_BUFFERSINK_OPTS +#define NB_ITEMS(list) (list ## _size / sizeof(*list)) +#endif + +static int vsink_query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) +{ + const BufferSinkContext *buf = ctx->priv; int ret; - CHECK_LIST_SIZE(pixel_fmts) - CHECK_LIST_SIZE(color_spaces) - CHECK_LIST_SIZE(color_ranges) +#if FF_API_BUFFERSINK_OPTS + if (buf->nb_pixel_formats || buf->nb_colorspaces || buf->nb_colorranges || buf->nb_alphamodes) { +#endif + if (buf->nb_pixel_formats) { + ret = ff_set_pixel_formats_from_list2(ctx, cfg_in, cfg_out, buf->pixel_formats); + if (ret < 0) + return ret; + } + if (buf->nb_colorspaces) { + ret = ff_set_common_color_spaces_from_list2(ctx, cfg_in, cfg_out, buf->colorspaces); + if (ret < 0) + return ret; + } + if (buf->nb_colorranges) { + ret = ff_set_common_color_ranges_from_list2(ctx, cfg_in, cfg_out, buf->colorranges); + if (ret < 0) + return ret; + } + if (buf->nb_alphamodes) { + ret = ff_set_common_alpha_modes_from_list2(ctx, cfg_in, cfg_out, buf->alphamodes); + if (ret < 0) + return ret; + } +#if FF_API_BUFFERSINK_OPTS + } else { + unsigned i; if (buf->pixel_fmts_size) { AVFilterFormats *formats = NULL; for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++) if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0) return ret; - if ((ret = ff_set_common_formats(ctx, formats)) < 0) + if ((ret = ff_set_common_formats2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; } @@ -250,7 +436,7 @@ static int vsink_query_formats(AVFilterContext *ctx) for (i = 0; i < NB_ITEMS(buf->color_spaces); i++) if ((ret = ff_add_format(&formats, buf->color_spaces[i])) < 0) return ret; - if ((ret = ff_set_common_color_spaces(ctx, formats)) < 0) + if ((ret = ff_set_common_color_spaces2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; } @@ -259,64 +445,65 @@ static int vsink_query_formats(AVFilterContext *ctx) for (i = 0; i < NB_ITEMS(buf->color_ranges); i++) if ((ret = ff_add_format(&formats, buf->color_ranges[i])) < 0) return ret; - if ((ret = ff_set_common_color_ranges(ctx, formats)) < 0) + if ((ret = ff_set_common_color_ranges2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; } + if (buf->alpha_modes_size) { + AVFilterFormats *formats = NULL; + for (i = 0; i < NB_ITEMS(buf->alpha_modes); i++) + if ((ret = ff_add_format(&formats, buf->alpha_modes[i])) < 0) + return ret; + if ((ret = ff_set_common_alpha_modes2(ctx, cfg_in, cfg_out, formats)) < 0) + return ret; + } + } +#endif + return 0; } -static int asink_query_formats(AVFilterContext *ctx) +static int asink_query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - BufferSinkContext *buf = ctx->priv; - AVFilterFormats *formats = NULL; - AVChannelLayout layout = { 0 }; - AVFilterChannelLayouts *layouts = NULL; - unsigned i; + const BufferSinkContext *buf = ctx->priv; int ret; - CHECK_LIST_SIZE(sample_fmts) - CHECK_LIST_SIZE(sample_rates) +#if FF_API_BUFFERSINK_OPTS + if (buf->nb_sample_formats || buf->nb_samplerates || buf->nb_channel_layouts) { +#endif + if (buf->nb_sample_formats) { + ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, buf->sample_formats); + if (ret < 0) + return ret; + } + if (buf->nb_samplerates) { + ret = ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, buf->samplerates); + if (ret < 0) + return ret; + } + if (buf->nb_channel_layouts) { + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, buf->channel_layouts); + if (ret < 0) + return ret; + } +#if FF_API_BUFFERSINK_OPTS + } else { + AVFilterFormats *formats = NULL; + unsigned i; if (buf->sample_fmts_size) { for (i = 0; i < NB_ITEMS(buf->sample_fmts); i++) if ((ret = ff_add_format(&formats, buf->sample_fmts[i])) < 0) return ret; - if ((ret = ff_set_common_formats(ctx, formats)) < 0) + if ((ret = ff_set_common_formats2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; } - if (buf->channel_layouts_str || buf->all_channel_counts) { - if (buf->channel_layouts_str) { - const char *cur = buf->channel_layouts_str; - - while (cur) { - char *next = strchr(cur, '|'); - if (next) - *next++ = 0; - - ret = av_channel_layout_from_string(&layout, cur); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: %s.\n", cur); - return ret; - } - ret = ff_add_channel_layout(&layouts, &layout); - av_channel_layout_uninit(&layout); - if (ret < 0) - return ret; - - cur = next; - } - } - - if (buf->all_channel_counts) { - if (layouts) - av_log(ctx, AV_LOG_WARNING, - "Conflicting all_channel_counts and list in options\n"); - else if (!(layouts = ff_all_channel_counts())) - return AVERROR(ENOMEM); - } - if ((ret = ff_set_common_channel_layouts(ctx, layouts)) < 0) + if (buf->nb_channel_layouts) { + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, buf->channel_layouts); + if (ret < 0) return ret; } @@ -325,9 +512,11 @@ static int asink_query_formats(AVFilterContext *ctx) for (i = 0; i < NB_ITEMS(buf->sample_rates); i++) if ((ret = ff_add_format(&formats, buf->sample_rates[i])) < 0) return ret; - if ((ret = ff_set_common_samplerates(ctx, formats)) < 0) + if ((ret = ff_set_common_samplerates2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; } + } +#endif return 0; } @@ -335,19 +524,40 @@ static int asink_query_formats(AVFilterContext *ctx) #define OFFSET(x) offsetof(BufferSinkContext, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM static const AVOption buffersink_options[] = { - { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, - { "color_spaces", "set the supported color spaces", OFFSET(color_spaces), AV_OPT_TYPE_BINARY, .flags = FLAGS }, - { "color_ranges", "set the supported color ranges", OFFSET(color_ranges), AV_OPT_TYPE_BINARY, .flags = FLAGS }, +#if FF_API_BUFFERSINK_OPTS + { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "color_spaces", "set the supported color spaces", OFFSET(color_spaces), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "color_ranges", "set the supported color ranges", OFFSET(color_ranges), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, +#endif + + { "pixel_formats", "array of supported pixel formats", OFFSET(pixel_formats), + AV_OPT_TYPE_PIXEL_FMT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "colorspaces", "array of supported color spaces", OFFSET(colorspaces), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "colorranges", "array of supported color ranges", OFFSET(colorranges), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "alphamodes", "array of supported color ranges", OFFSET(alphamodes), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { NULL }, }; #undef FLAGS #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM static const AVOption abuffersink_options[] = { - { "sample_fmts", "set the supported sample formats", OFFSET(sample_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, - { "sample_rates", "set the supported sample rates", OFFSET(sample_rates), AV_OPT_TYPE_BINARY, .flags = FLAGS }, +#if FF_API_BUFFERSINK_OPTS + { "sample_fmts", "set the supported sample formats", OFFSET(sample_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "sample_rates", "set the supported sample rates", OFFSET(sample_rates), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, { "ch_layouts", "set a '|'-separated list of supported channel layouts", - OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = FLAGS }, - { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS }, + OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS | AV_OPT_FLAG_DEPRECATED }, +#endif + + { "sample_formats", "array of supported sample formats", OFFSET(sample_formats), + AV_OPT_TYPE_SAMPLE_FMT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "samplerates", "array of supported sample formats", OFFSET(samplerates), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "channel_layouts", "array of supported channel layouts", OFFSET(channel_layouts), + AV_OPT_TYPE_CHLAYOUT | AV_OPT_TYPE_FLAG_ARRAY, .flags = FLAGS }, { NULL }, }; #undef FLAGS @@ -355,28 +565,36 @@ static const AVOption abuffersink_options[] = { AVFILTER_DEFINE_CLASS(buffersink); AVFILTER_DEFINE_CLASS(abuffersink); -const AVFilter ff_vsink_buffer = { - .name = "buffersink", - .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), +const FFFilter ff_vsink_buffer = { + .p.name = "buffersink", + .p.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), + .p.priv_class = &buffersink_class, + .p.outputs = NULL, .priv_size = sizeof(BufferSinkContext), - .priv_class = &buffersink_class, - .init = common_init, + .init = init_video, .uninit = uninit, .activate = activate, FILTER_INPUTS(ff_video_default_filterpad), - .outputs = NULL, - FILTER_QUERY_FUNC(vsink_query_formats), + FILTER_QUERY_FUNC2(vsink_query_formats), }; -const AVFilter ff_asink_abuffer = { - .name = "abuffersink", - .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), - .priv_class = &abuffersink_class, +static const AVFilterPad inputs_audio[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_input_audio, + }, +}; + +const FFFilter ff_asink_abuffer = { + .p.name = "abuffersink", + .p.description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), + .p.priv_class = &abuffersink_class, + .p.outputs = NULL, .priv_size = sizeof(BufferSinkContext), - .init = common_init, + .init = init_audio, .uninit = uninit, .activate = activate, - FILTER_INPUTS(ff_audio_default_filterpad), - .outputs = NULL, - FILTER_QUERY_FUNC(asink_query_formats), + FILTER_INPUTS(inputs_audio), + FILTER_QUERY_FUNC2(asink_query_formats), }; diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h index 361d60367..4e658a979 100644 --- a/libavfilter/buffersink.h +++ b/libavfilter/buffersink.h @@ -48,26 +48,21 @@ * - av_buffersink_get_channels(), * - av_buffersink_get_ch_layout(), * - av_buffersink_get_sample_rate(). + * - av_buffersink_get_side_data(). * * The layout returned by av_buffersink_get_ch_layout() must de uninitialized * by the caller. * * The format can be constrained by setting options, using av_opt_set() and * related functions with the AV_OPT_SEARCH_CHILDREN flag. - * - pix_fmts (int list), - * - color_spaces (int list), - * - color_ranges (int list), - * - sample_fmts (int list), - * - sample_rates (int list), - * - ch_layouts (string), - * - channel_counts (int list), - * - all_channel_counts (bool). - * Most of these options are of type binary, and should be set using - * av_opt_set_int_list() or av_opt_set_bin(). If they are not set, all - * corresponding formats are accepted. - * - * As a special case, if ch_layouts is not set, all valid channel layouts are - * accepted except for UNSPEC layouts, unless all_channel_counts is set. + * - pixel_formats (array of pixel formats), + * - colorspaces (array of int), + * - colorranges (array of int), + * - alphamodes (array of int), + * - sample_formats (array of sample formats), + * - samplerates (array of int), + * - channel_layouts (array of channel layouts) + * If an option is not set, all corresponding formats are accepted. */ /** @@ -121,6 +116,7 @@ int av_buffersink_get_h (const AVFilterContext *c AVRational av_buffersink_get_sample_aspect_ratio (const AVFilterContext *ctx); enum AVColorSpace av_buffersink_get_colorspace (const AVFilterContext *ctx); enum AVColorRange av_buffersink_get_color_range (const AVFilterContext *ctx); +enum AVAlphaMode av_buffersink_get_alpha_mode (const AVFilterContext *ctx); int av_buffersink_get_channels (const AVFilterContext *ctx); int av_buffersink_get_ch_layout (const AVFilterContext *ctx, @@ -129,6 +125,9 @@ int av_buffersink_get_sample_rate (const AVFilterContext *c AVBufferRef * av_buffersink_get_hw_frames_ctx (const AVFilterContext *ctx); +const AVFrameSideData *const *av_buffersink_get_side_data(const AVFilterContext *ctx, + int *nb_side_data); + /** @} */ /** diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index f9b206194..b18d3f24d 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -52,6 +52,7 @@ typedef struct BufferSourceContext { enum AVPixelFormat pix_fmt, prev_pix_fmt; enum AVColorSpace color_space, prev_color_space; enum AVColorRange color_range, prev_color_range; + enum AVAlphaMode alpha_mode, prev_alpha_mode; AVRational pixel_aspect; AVBufferRef *hw_frames_ctx; @@ -60,25 +61,26 @@ typedef struct BufferSourceContext { int sample_rate; enum AVSampleFormat sample_fmt; int channels; - char *channel_layout_str; AVChannelLayout ch_layout; + AVFrameSideData **side_data; + int nb_side_data; int eof; int64_t last_pts; int link_delta, prev_delta; } BufferSourceContext; -#define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format, csp, range, pts)\ +#define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format, csp, range, alpha, pts)\ c->link_delta = c->w != width || c->h != height || c->pix_fmt != format ||\ - c->color_space != csp || c->color_range != range;\ + c->color_space != csp || c->color_range != range || c->alpha_mode != alpha;\ c->prev_delta = c->prev_w != width || c->prev_h != height || c->prev_pix_fmt != format ||\ - c->prev_color_space != csp || c->prev_color_range != range;\ + c->prev_color_space != csp || c->prev_color_range != range || c->prev_alpha_mode != alpha;\ if (c->link_delta) {\ int loglevel = c->prev_delta ? AV_LOG_WARNING : AV_LOG_DEBUG;\ av_log(s, loglevel, "Changing video frame properties on the fly is not supported by all filters.\n");\ - av_log(s, loglevel, "filter context - w: %d h: %d fmt: %d csp: %s range: %s, incoming frame - w: %d h: %d fmt: %d csp: %s range: %s pts_time: %s\n",\ - c->w, c->h, c->pix_fmt, av_color_space_name(c->color_space), av_color_range_name(c->color_range),\ - width, height, format, av_color_space_name(csp), av_color_range_name(range),\ + av_log(s, loglevel, "filter context - w: %d h: %d fmt: %d csp: %s range: %s alpha: %s, incoming frame - w: %d h: %d fmt: %d csp: %s range: %s alpha: %s pts_time: %s\n",\ + c->w, c->h, c->pix_fmt, av_color_space_name(c->color_space), av_color_range_name(c->color_range), av_alpha_mode_name(c->alpha_mode),\ + width, height, format, av_color_space_name(csp), av_color_range_name(range), av_alpha_mode_name(alpha),\ av_ts2timestr(pts, &s->outputs[0]->time_base));\ }\ if (c->prev_delta) {\ @@ -89,6 +91,7 @@ typedef struct BufferSourceContext { c->prev_pix_fmt = format;\ c->prev_color_space = csp;\ c->prev_color_range = range;\ + c->prev_alpha_mode = alpha;\ } #define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, layout, format, pts)\ @@ -110,6 +113,7 @@ AVBufferSrcParameters *av_buffersrc_parameters_alloc(void) par->format = -1; par->color_range = AVCOL_RANGE_UNSPECIFIED; par->color_space = AVCOL_SPC_UNSPECIFIED; + par->alpha_mode = AVALPHA_MODE_UNSPECIFIED; return par; } @@ -144,6 +148,8 @@ int av_buffersrc_parameters_set(AVFilterContext *ctx, AVBufferSrcParameters *par s->color_space = s->prev_color_space = param->color_space; if (param->color_range != AVCOL_RANGE_UNSPECIFIED) s->color_range = s->prev_color_range = param->color_range; + if (param->alpha_mode != AVALPHA_MODE_UNSPECIFIED) + s->alpha_mode = s->prev_alpha_mode = param->alpha_mode; break; case AVMEDIA_TYPE_AUDIO: if (param->format != AV_SAMPLE_FMT_NONE) { @@ -161,6 +167,17 @@ int av_buffersrc_parameters_set(AVFilterContext *ctx, AVBufferSrcParameters *par return AVERROR_BUG; } + if (param->nb_side_data > 0) + av_frame_side_data_free(&s->side_data, &s->nb_side_data); + for (int i = 0; i < param->nb_side_data; i++) { + int ret = av_frame_side_data_clone(&s->side_data, &s->nb_side_data, + param->side_data[i], 0); + if (ret < 0) { + av_frame_side_data_free(&s->side_data, &s->nb_side_data); + return ret; + } + } + return 0; } @@ -183,7 +200,7 @@ static int push_frame(AVFilterGraph *graph) ret = ff_filter_graph_run_once(graph); if (ret == AVERROR(EAGAIN)) break; - if (ret < 0) + if (ret < 0 && ret != FFERROR_BUFFERSRC_EMPTY) return ret; } return 0; @@ -212,7 +229,7 @@ int attribute_align_arg av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFra case AVMEDIA_TYPE_VIDEO: CHECK_VIDEO_PARAM_CHANGE(ctx, s, frame->width, frame->height, frame->format, frame->colorspace, - frame->color_range, frame->pts); + frame->color_range, frame->alpha_mode, frame->pts); break; case AVMEDIA_TYPE_AUDIO: /* For layouts unknown on input but known on link after negotiation. */ @@ -240,26 +257,12 @@ int attribute_align_arg av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFra return AVERROR(ENOMEM); } -#if FF_API_INTERLACED_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - if (copy->interlaced_frame) - copy->flags |= AV_FRAME_FLAG_INTERLACED; - if (copy->top_field_first) - copy->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - -#if FF_API_FRAME_KEY -FF_DISABLE_DEPRECATION_WARNINGS - if (copy->key_frame) - copy->flags |= AV_FRAME_FLAG_KEY; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (copy->colorspace == AVCOL_SPC_UNSPECIFIED) copy->colorspace = ctx->outputs[0]->colorspace; if (copy->color_range == AVCOL_RANGE_UNSPECIFIED) copy->color_range = ctx->outputs[0]->color_range; + if (copy->alpha_mode == AVALPHA_MODE_UNSPECIFIED) + copy->alpha_mode = ctx->outputs[0]->alpha_mode; ret = ff_filter_frame(ctx->outputs[0], copy); if (ret < 0) @@ -301,6 +304,13 @@ static av_cold int init_video(AVFilterContext *ctx) av_log(ctx, AV_LOG_ERROR, "Unspecified pixel format\n"); return AVERROR(EINVAL); } + if (av_pix_fmt_desc_get(c->pix_fmt)->flags & AV_PIX_FMT_FLAG_HWACCEL) { + if (!c->hw_frames_ctx) { + av_log(ctx, AV_LOG_ERROR, "Setting BufferSourceContext.pix_fmt " + "to a HW format requires hw_frames_ctx to be non-NULL!\n"); + return AVERROR(EINVAL); + } + } if (c->w <= 0 || c->h <= 0) { av_log(ctx, AV_LOG_ERROR, "Invalid size %dx%d\n", c->w, c->h); return AVERROR(EINVAL); @@ -310,11 +320,12 @@ static av_cold int init_video(AVFilterContext *ctx) return AVERROR(EINVAL); } - av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d pixfmt:%s tb:%d/%d fr:%d/%d sar:%d/%d csp:%s range:%s\n", + av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d pixfmt:%s tb:%d/%d fr:%d/%d sar:%d/%d csp:%s range:%s alpha:%s\n", c->w, c->h, av_get_pix_fmt_name(c->pix_fmt), c->time_base.num, c->time_base.den, c->frame_rate.num, c->frame_rate.den, c->pixel_aspect.num, c->pixel_aspect.den, - av_color_space_name(c->color_space), av_color_range_name(c->color_range)); + av_color_space_name(c->color_space), av_color_range_name(c->color_range), + av_alpha_mode_name(c->alpha_mode)); return 0; } @@ -364,6 +375,11 @@ static const AVOption buffer_options[] = { { "full", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, V, .unit = "range"}, { "pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, V, .unit = "range"}, { "jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, V, .unit = "range"}, + { "alpha_mode", "select alpha mode", OFFSET(alpha_mode), AV_OPT_TYPE_INT, {.i64=AVALPHA_MODE_UNSPECIFIED}, 0, AVCOL_RANGE_NB-1, V, .unit = "alpha"}, + { "unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVALPHA_MODE_UNSPECIFIED}, 0, 0, V, .unit = "alpha"}, + { "unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVALPHA_MODE_UNSPECIFIED}, 0, 0, V, .unit = "alpha"}, + { "straight", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVALPHA_MODE_STRAIGHT}, 0, 0, V, .unit = "alpha"}, + { "premultiplied", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVALPHA_MODE_PREMULTIPLIED}, 0, 0, V, .unit = "alpha"}, { NULL }, }; @@ -373,7 +389,7 @@ static const AVOption abuffer_options[] = { { "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, INT_MAX, A }, { "sample_rate", NULL, OFFSET(sample_rate), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, A }, { "sample_fmt", NULL, OFFSET(sample_fmt), AV_OPT_TYPE_SAMPLE_FMT, { .i64 = AV_SAMPLE_FMT_NONE }, .min = AV_SAMPLE_FMT_NONE, .max = INT_MAX, .flags = A }, - { "channel_layout", NULL, OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A }, + { "channel_layout", NULL, OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, .flags = A }, { "channels", NULL, OFFSET(channels), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, A }, { NULL }, }; @@ -391,18 +407,9 @@ static av_cold int init_audio(AVFilterContext *ctx) return AVERROR(EINVAL); } - if (s->channel_layout_str || s->ch_layout.nb_channels) { + if (av_channel_layout_check(&s->ch_layout)) { int n; - if (!s->ch_layout.nb_channels) { - ret = av_channel_layout_from_string(&s->ch_layout, s->channel_layout_str); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n", - s->channel_layout_str); - return AVERROR(EINVAL); - } - } - n = s->ch_layout.nb_channels; av_channel_layout_describe(&s->ch_layout, buf, sizeof(buf)); if (s->channels) { @@ -445,36 +452,34 @@ static av_cold void uninit(AVFilterContext *ctx) BufferSourceContext *s = ctx->priv; av_buffer_unref(&s->hw_frames_ctx); av_channel_layout_uninit(&s->ch_layout); + av_frame_side_data_free(&s->side_data, &s->nb_side_data); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - BufferSourceContext *c = ctx->priv; + const BufferSourceContext *c = ctx->priv; AVFilterChannelLayouts *channel_layouts = NULL; AVFilterFormats *formats = NULL; AVFilterFormats *samplerates = NULL; AVFilterFormats *color_spaces = NULL; AVFilterFormats *color_ranges = NULL; + AVFilterFormats *alpha_modes = NULL; int ret; switch (ctx->outputs[0]->type) { case AVMEDIA_TYPE_VIDEO: { enum AVPixelFormat swfmt = c->pix_fmt; - if (av_pix_fmt_desc_get(swfmt)->flags & AV_PIX_FMT_FLAG_HWACCEL) { - if (!c->hw_frames_ctx) { - av_log(ctx, AV_LOG_ERROR, "Setting BufferSourceContext.pix_fmt " - "to a HW format requires hw_frames_ctx to be non-NULL!\n"); - return AVERROR(EINVAL); - } + if (av_pix_fmt_desc_get(swfmt)->flags & AV_PIX_FMT_FLAG_HWACCEL) swfmt = ((AVHWFramesContext *) c->hw_frames_ctx->data)->sw_format; - } if ((ret = ff_add_format (&formats, c->pix_fmt)) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0) + (ret = ff_set_common_formats2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; /* force specific colorspace/range downstream only for ordinary YUV */ if (ff_fmt_is_regular_yuv(swfmt)) { if ((ret = ff_add_format(&color_spaces, c->color_space)) < 0 || - (ret = ff_set_common_color_spaces(ctx, color_spaces)) < 0) + (ret = ff_set_common_color_spaces2(ctx, cfg_in, cfg_out, color_spaces)) < 0) return ret; if (ff_fmt_is_forced_full_range(swfmt)) { if ((ret = ff_add_format(&color_ranges, AVCOL_RANGE_JPEG)) < 0) @@ -488,21 +493,32 @@ static int query_formats(AVFilterContext *ctx) return ret; } } - if ((ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0) + if ((ret = ff_set_common_color_ranges2(ctx, cfg_in, cfg_out, color_ranges)) < 0) + return ret; + } + if (av_pix_fmt_desc_get(swfmt)->flags & AV_PIX_FMT_FLAG_ALPHA) { + if ((ret = ff_add_format(&alpha_modes, c->alpha_mode)) < 0) + return ret; + if (c->alpha_mode == AVALPHA_MODE_UNSPECIFIED) { + /* allow implicitly promoting unspecified to straight */ + if ((ret = ff_add_format(&alpha_modes, AVALPHA_MODE_STRAIGHT)) < 0) + return ret; + } + if ((ret = ff_set_common_alpha_modes2(ctx, cfg_in, cfg_out, alpha_modes)) < 0) return ret; } break; } case AVMEDIA_TYPE_AUDIO: if ((ret = ff_add_format (&formats , c->sample_fmt )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || + (ret = ff_set_common_formats2 (ctx, cfg_in, cfg_out, formats)) < 0 || (ret = ff_add_format (&samplerates, c->sample_rate)) < 0 || - (ret = ff_set_common_samplerates (ctx , samplerates )) < 0) + (ret = ff_set_common_samplerates2(ctx, cfg_in, cfg_out, samplerates)) < 0) return ret; if ((ret = ff_add_channel_layout(&channel_layouts, &c->ch_layout)) < 0) return ret; - if ((ret = ff_set_common_channel_layouts(ctx, channel_layouts)) < 0) + if ((ret = ff_set_common_channel_layouts2(ctx, cfg_in, cfg_out, channel_layouts)) < 0) return ret; break; default: @@ -540,6 +556,17 @@ static int config_props(AVFilterLink *link) return AVERROR(EINVAL); } + for (int i = 0; i < c->nb_side_data; i++) { + int ret; + + ret = av_frame_side_data_clone(&link->side_data, &link->nb_side_data, + c->side_data[i], 0); + if (ret < 0) { + av_frame_side_data_free(&link->side_data, &link->nb_side_data); + return ret; + } + } + link->time_base = c->time_base; l->frame_rate = c->frame_rate; return 0; @@ -560,7 +587,7 @@ static int activate(AVFilterContext *ctx) return 0; } c->nb_failed_requests++; - return FFERROR_NOT_READY; + return FFERROR_BUFFERSRC_EMPTY; } static const AVFilterPad avfilter_vsrc_buffer_outputs[] = { @@ -571,18 +598,17 @@ static const AVFilterPad avfilter_vsrc_buffer_outputs[] = { }, }; -const AVFilter ff_vsrc_buffer = { - .name = "buffer", - .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."), +const FFFilter ff_vsrc_buffer = { + .p.name = "buffer", + .p.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."), + .p.priv_class = &buffer_class, .priv_size = sizeof(BufferSourceContext), .activate = activate, .init = init_video, .uninit = uninit, - .inputs = NULL, FILTER_OUTPUTS(avfilter_vsrc_buffer_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &buffer_class, + FILTER_QUERY_FUNC2(query_formats), }; static const AVFilterPad avfilter_asrc_abuffer_outputs[] = { @@ -593,16 +619,15 @@ static const AVFilterPad avfilter_asrc_abuffer_outputs[] = { }, }; -const AVFilter ff_asrc_abuffer = { - .name = "abuffer", - .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."), +const FFFilter ff_asrc_abuffer = { + .p.name = "abuffer", + .p.description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."), + .p.priv_class = &abuffer_class, .priv_size = sizeof(BufferSourceContext), .activate = activate, .init = init_audio, .uninit = uninit, - .inputs = NULL, FILTER_OUTPUTS(avfilter_asrc_abuffer_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &abuffer_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/buffersrc.h b/libavfilter/buffersrc.h index 4bc8fba14..c7225b675 100644 --- a/libavfilter/buffersrc.h +++ b/libavfilter/buffersrc.h @@ -120,6 +120,14 @@ typedef struct AVBufferSrcParameters { */ enum AVColorSpace color_space; enum AVColorRange color_range; + + AVFrameSideData **side_data; + int nb_side_data; + + /** + * Video only, the alpha mode. + */ + enum AVAlphaMode alpha_mode; } AVBufferSrcParameters; /** diff --git a/libavfilter/bwdifdsp.c b/libavfilter/bwdifdsp.c index e87fe414e..58e18f0a9 100644 --- a/libavfilter/bwdifdsp.c +++ b/libavfilter/bwdifdsp.c @@ -218,7 +218,7 @@ av_cold void ff_bwdif_init_filter_line(BWDIFDSPContext *s, int bit_depth) s->filter_edge = ff_bwdif_filter_edge_c; } -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_bwdif_init_x86(s, bit_depth); #elif ARCH_AARCH64 ff_bwdif_init_aarch64(s, bit_depth); diff --git a/libavfilter/colorspacedsp.c b/libavfilter/colorspacedsp.c index 72207ffaf..9c51385de 100644 --- a/libavfilter/colorspacedsp.c +++ b/libavfilter/colorspacedsp.c @@ -143,7 +143,7 @@ void ff_colorspacedsp_init(ColorSpaceDSPContext *dsp) dsp->multiply3x3 = multiply3x3_c; -#if ARCH_X86 +#if ARCH_X86 && HAVE_X86ASM ff_colorspacedsp_x86_init(dsp); #endif } diff --git a/libavfilter/convolution.h b/libavfilter/convolution.h index d664c990a..71ec3b680 100644 --- a/libavfilter/convolution.h +++ b/libavfilter/convolution.h @@ -130,7 +130,7 @@ static inline void ff_sobel_init(ConvolutionContext *s, int depth, int nb_planes if (s->depth > 8) for (int i = 0; i < 4; i++) s->filter[i] = filter16_sobel; -#if ARCH_X86_64 +#if ARCH_X86_64 && HAVE_X86ASM ff_sobel_init_x86(s, depth, nb_planes); #endif } diff --git a/libavfilter/cuda/load_helper.c b/libavfilter/cuda/load_helper.c index b049ec713..d64dce72b 100644 --- a/libavfilter/cuda/load_helper.c +++ b/libavfilter/cuda/load_helper.c @@ -23,9 +23,8 @@ #include "libavutil/cuda_check.h" #include "libavutil/mem.h" -#if CONFIG_PTX_COMPRESSION -#include -#define CHUNK_SIZE 1024 * 64 +#if CONFIG_SHADER_COMPRESSION +#include "libavutil/zlib_utils.h" #endif #include "load_helper.h" @@ -37,59 +36,16 @@ int ff_cuda_load_module(void *avctx, AVCUDADeviceContext *hwctx, CUmodule *cu_mo { CudaFunctions *cu = hwctx->internal->cuda_dl; -#if CONFIG_PTX_COMPRESSION - z_stream stream = { 0 }; - uint8_t *buf, *tmp; - uint64_t buf_size; - int ret; +#if CONFIG_SHADER_COMPRESSION + uint8_t *out; + size_t out_len; + int ret = ff_zlib_expand(avctx, &out, &out_len, + data, length); + if (ret < 0) + return ret; - if (inflateInit2(&stream, 32 + 15) != Z_OK) { - av_log(avctx, AV_LOG_ERROR, "Error during zlib initialisation: %s\n", stream.msg); - return AVERROR(ENOSYS); - } - - buf_size = CHUNK_SIZE * 4; - buf = av_realloc(NULL, buf_size); - if (!buf) { - inflateEnd(&stream); - return AVERROR(ENOMEM); - } - - stream.next_in = data; - stream.avail_in = length; - - do { - stream.avail_out = buf_size - stream.total_out; - stream.next_out = buf + stream.total_out; - - ret = inflate(&stream, Z_FINISH); - if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) { - av_log(avctx, AV_LOG_ERROR, "zlib inflate error(%d): %s\n", ret, stream.msg); - inflateEnd(&stream); - av_free(buf); - return AVERROR(EINVAL); - } - - if (stream.avail_out == 0) { - buf_size += CHUNK_SIZE; - tmp = av_realloc(buf, buf_size); - if (!tmp) { - inflateEnd(&stream); - av_free(buf); - return AVERROR(ENOMEM); - } - buf = tmp; - } - } while (ret != Z_STREAM_END); - - // NULL-terminate string - // there is guaranteed to be space for this, due to condition in loop - buf[stream.total_out] = 0; - - inflateEnd(&stream); - - ret = CHECK_CU(cu->cuModuleLoadData(cu_module, buf)); - av_free(buf); + ret = CHECK_CU(cu->cuModuleLoadData(cu_module, out)); + av_free(out); return ret; #else return CHECK_CU(cu->cuModuleLoadData(cu_module, data)); diff --git a/libavfilter/dnn/dnn_backend_openvino.c b/libavfilter/dnn/dnn_backend_openvino.c index 2f6706dcd..ec46e29b8 100644 --- a/libavfilter/dnn/dnn_backend_openvino.c +++ b/libavfilter/dnn/dnn_backend_openvino.c @@ -1331,7 +1331,7 @@ static int get_output_ov(DNNModel *model, const char *input_name, int input_widt #endif ret = init_model_ov(ov_model, input_name, output_name ? &output_name : NULL, 1); if (ret != 0) { - av_log(ctx, AV_LOG_ERROR, "Failed init OpenVINO exectuable network or inference request\n"); + av_log(ctx, AV_LOG_ERROR, "Failed init OpenVINO executable network or inference request\n"); return ret; } } @@ -1487,7 +1487,7 @@ static int dnn_execute_model_ov(const DNNModel *model, DNNExecBaseParams *exec_p ret = init_model_ov(ov_model, exec_params->input_name, exec_params->output_names, exec_params->nb_output); if (ret != 0) { - av_log(ctx, AV_LOG_ERROR, "Failed init OpenVINO exectuable network or inference request\n"); + av_log(ctx, AV_LOG_ERROR, "Failed init OpenVINO executable network or inference request\n"); return ret; } } diff --git a/libavfilter/dnn/dnn_backend_torch.cpp b/libavfilter/dnn/dnn_backend_torch.cpp index 2e4326d9d..99f55165f 100644 --- a/libavfilter/dnn/dnn_backend_torch.cpp +++ b/libavfilter/dnn/dnn_backend_torch.cpp @@ -118,27 +118,24 @@ static void dnn_free_model_th(DNNModel **model) if (!model || !*model) return; - th_model = (THModel *) (*model); - while (ff_safe_queue_size(th_model->request_queue) != 0) { - THRequestItem *item = (THRequestItem *)ff_safe_queue_pop_front(th_model->request_queue); - destroy_request_item(&item); - } - ff_safe_queue_destroy(th_model->request_queue); + th_model = (THModel *)(*model); - while (ff_queue_size(th_model->lltask_queue) != 0) { - LastLevelTaskItem *item = (LastLevelTaskItem *)ff_queue_pop_front(th_model->lltask_queue); - av_freep(&item); + if (th_model->request_queue) { + while (ff_safe_queue_size(th_model->request_queue) != 0) { + THRequestItem *item = (THRequestItem *)ff_safe_queue_pop_front(th_model->request_queue); + destroy_request_item(&item); + } + ff_safe_queue_destroy(th_model->request_queue); } - ff_queue_destroy(th_model->lltask_queue); - while (ff_queue_size(th_model->task_queue) != 0) { - TaskItem *item = (TaskItem *)ff_queue_pop_front(th_model->task_queue); - av_frame_free(&item->in_frame); - av_frame_free(&item->out_frame); - av_freep(&item); - } - ff_queue_destroy(th_model->task_queue); - delete th_model->jit_model; + if (th_model->lltask_queue) + ff_queue_destroy(th_model->lltask_queue); + if (th_model->task_queue) + ff_queue_destroy(th_model->task_queue); + + if (th_model->jit_model) + delete th_model->jit_model; + av_freep(&th_model); *model = NULL; } @@ -340,12 +337,14 @@ static int execute_model_th(THRequestItem *request, Queue *lltask_queue) th_model = (THModel *)task->model; ret = fill_model_input_th(th_model, request); - if ( ret != 0) { + if (ret != 0) { goto err; } + if (task->async) { - avpriv_report_missing_feature(th_model->ctx, "LibTorch async"); + return ff_dnn_start_inference_async(th_model->ctx, &request->exec_module); } else { + // Synchronous execution path ret = th_start_inference((void *)(request)); if (ret != 0) { goto err; @@ -435,7 +434,11 @@ static DNNModel *dnn_load_model_th(DnnContext *ctx, DNNFunctionType func_type, A av_log(ctx, AV_LOG_ERROR, "No XPU device found\n"); goto fail; } +#if TORCH_VERSION_MAJOR > 2 || (TORCH_VERSION_MAJOR == 2 && TORCH_VERSION_MINOR >= 6) + at::detail::getXPUHooks().init(); +#else at::detail::getXPUHooks().initXPU(); +#endif } else if (!device.is_cpu()) { av_log(ctx, AV_LOG_ERROR, "Not supported device:\"%s\"\n", device_name); goto fail; @@ -459,12 +462,11 @@ static DNNModel *dnn_load_model_th(DnnContext *ctx, DNNFunctionType func_type, A if (!item) { goto fail; } - item->lltask = NULL; item->infer_request = th_create_inference_request(); if (!item->infer_request) { - av_log(NULL, AV_LOG_ERROR, "Failed to allocate memory for Torch inference request\n"); goto fail; } + item->exec_module.start_inference = &th_start_inference; item->exec_module.callback = &infer_completion_callback; item->exec_module.args = item; @@ -475,14 +477,7 @@ static DNNModel *dnn_load_model_th(DnnContext *ctx, DNNFunctionType func_type, A item = NULL; th_model->task_queue = ff_queue_create(); - if (!th_model->task_queue) { - goto fail; - } - th_model->lltask_queue = ff_queue_create(); - if (!th_model->lltask_queue) { - goto fail; - } model->get_input = &get_input_th; model->get_output = &get_output_th; @@ -493,7 +488,6 @@ static DNNModel *dnn_load_model_th(DnnContext *ctx, DNNFunctionType func_type, A fail: if (item) { destroy_request_item(&item); - av_freep(&item); } dnn_free_model_th(&model); return NULL; @@ -519,7 +513,7 @@ static int dnn_execute_model_th(const DNNModel *model, DNNExecBaseParams *exec_p return AVERROR(ENOMEM); } - ret = ff_dnn_fill_task(task, exec_params, th_model, 0, 1); + ret = ff_dnn_fill_task(task, exec_params, th_model, ctx->async, 1); if (ret != 0) { av_freep(&task); av_log(ctx, AV_LOG_ERROR, "unable to fill task.\n"); diff --git a/libavfilter/dnn/dnn_interface.c b/libavfilter/dnn/dnn_interface.c index c4e410756..7080ab12e 100644 --- a/libavfilter/dnn/dnn_interface.c +++ b/libavfilter/dnn/dnn_interface.c @@ -98,6 +98,8 @@ void ff_dnn_init_child_class(DnnContext *ctx) for (int i = 0; i < FF_ARRAY_ELEMS(dnn_backend_info_list); i++) { const AVClass **ptr = (const AVClass **) ((char *) ctx + dnn_backend_info_list[i].offset); *ptr = dnn_backend_info_list[i].class; + // Set default values after the class pointer is set + av_opt_set_defaults(ptr); } } diff --git a/libavfilter/drawutils.c b/libavfilter/drawutils.c index 95525d38b..75bf8f475 100644 --- a/libavfilter/drawutils.c +++ b/libavfilter/drawutils.c @@ -32,24 +32,23 @@ enum { RED = 0, GREEN, BLUE, ALPHA }; -int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt) +static int fill_map(const AVPixFmtDescriptor *desc, uint8_t *map) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - if (!(desc->flags & AV_PIX_FMT_FLAG_RGB)) - return AVERROR(EINVAL); - if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) + if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL | + AV_PIX_FMT_FLAG_BAYER | AV_PIX_FMT_FLAG_XYZ | AV_PIX_FMT_FLAG_PAL)) return AVERROR(EINVAL); av_assert0(desc->nb_components == 3 + !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)); if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) { - rgba_map[RED] = desc->comp[0].plane; - rgba_map[GREEN] = desc->comp[1].plane; - rgba_map[BLUE] = desc->comp[2].plane; - rgba_map[ALPHA] = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? desc->comp[3].plane : 3; + if (desc->nb_components != av_pix_fmt_count_planes(av_pix_fmt_desc_get_id(desc))) + return AVERROR(EINVAL); + map[RED] = desc->comp[0].plane; + map[GREEN] = desc->comp[1].plane; + map[BLUE] = desc->comp[2].plane; + map[ALPHA] = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? desc->comp[3].plane : 3; } else { int had0 = 0; unsigned depthb = 0; - unsigned i; - for (i = 0; i < desc->nb_components; i++) { + for (unsigned i = 0; i < desc->nb_components; i++) { /* all components must have same depth in bytes */ unsigned db = (desc->comp[i].depth + 7) / 8; unsigned pos = desc->comp[i].offset / db; @@ -60,31 +59,47 @@ int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt) return AVERROR(ENOSYS); had0 |= pos == 0; - rgba_map[i] = pos; + map[i] = pos; depthb = db; } if (desc->nb_components == 3) - rgba_map[ALPHA] = had0 ? 3 : 0; + map[ALPHA] = had0 ? 3 : 0; } - av_assert0(rgba_map[RED] != rgba_map[GREEN]); - av_assert0(rgba_map[GREEN] != rgba_map[BLUE]); - av_assert0(rgba_map[BLUE] != rgba_map[RED]); - av_assert0(rgba_map[RED] != rgba_map[ALPHA]); - av_assert0(rgba_map[GREEN] != rgba_map[ALPHA]); - av_assert0(rgba_map[BLUE] != rgba_map[ALPHA]); + av_assert0(map[RED] != map[GREEN]); + av_assert0(map[GREEN] != map[BLUE]); + av_assert0(map[BLUE] != map[RED]); + av_assert0(map[RED] != map[ALPHA]); + av_assert0(map[GREEN] != map[ALPHA]); + av_assert0(map[BLUE] != map[ALPHA]); return 0; } +int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + if (!(desc->flags & AV_PIX_FMT_FLAG_RGB)) + return AVERROR(EINVAL); + return fill_map(desc, rgba_map); +} + +int ff_fill_ayuv_map(uint8_t *ayuv_map, enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + if (desc->flags & AV_PIX_FMT_FLAG_RGB) + return AVERROR(EINVAL); + return fill_map(desc, ayuv_map); +} + int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSpace csp, - enum AVColorRange range, unsigned flags) + enum AVColorRange range, enum AVAlphaMode alpha, unsigned flags) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format); const AVLumaCoefficients *luma = NULL; const AVComponentDescriptor *c; - unsigned i, nb_planes = 0; + unsigned nb_planes = 0; int pixelstep[MAX_PLANES] = { 0 }; int depthb = 0; @@ -105,7 +120,7 @@ int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSp ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; if (range != AVCOL_RANGE_JPEG && range != AVCOL_RANGE_MPEG) return AVERROR(EINVAL); - for (i = 0; i < desc->nb_components; i++) { + for (unsigned i = 0; i < desc->nb_components; i++) { int db; c = &desc->comp[i]; /* for now, only 8-16 bits formats */ @@ -140,6 +155,7 @@ int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSp draw->nb_planes = nb_planes; draw->range = range; draw->csp = csp; + draw->alpha = alpha; draw->flags = flags; if (luma) ff_fill_rgb2yuv_table(luma, draw->rgb2yuv); @@ -149,14 +165,19 @@ int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSp return 0; } +int ff_draw_init_from_link(FFDrawContext *draw, const AVFilterLink *link, + unsigned flags) +{ + return ff_draw_init2(draw, link->format, link->colorspace, link->color_range, link->alpha_mode, flags); +} + int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags) { - return ff_draw_init2(draw, format, AVCOL_SPC_UNSPECIFIED, AVCOL_RANGE_UNSPECIFIED, flags); + return ff_draw_init2(draw, format, AVCOL_SPC_UNSPECIFIED, AVCOL_RANGE_UNSPECIFIED, AVALPHA_MODE_UNSPECIFIED, flags); } void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4]) { - unsigned i; double yuvad[4]; double rgbad[4]; const AVPixFmtDescriptor *desc = draw->desc; @@ -169,6 +190,11 @@ void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4 for (int i = 0; i < 4; i++) rgbad[i] = color->rgba[i] / 255.; + if (draw->alpha == AVALPHA_MODE_PREMULTIPLIED) { + for (int i = 0; i < 3; i++) + rgbad[i] *= rgbad[3]; + } + if (draw->desc->flags & AV_PIX_FMT_FLAG_RGB) memcpy(yuvad, rgbad, sizeof(double) * 3); else @@ -190,7 +216,7 @@ void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4 if (desc->nb_components <= 2) yuvad[1] = yuvad[3]; - for (i = 0; i < desc->nb_components; i++) { + for (unsigned i = 0; i < desc->nb_components; i++) { unsigned val = yuvad[i] * ((1 << (draw->desc->comp[i].depth + draw->desc->comp[i].shift)) - 1) + 0.5; if (desc->comp[i].depth > 8) color->comp[desc->comp[i].plane].u16[desc->comp[i].offset / 2] = val; @@ -213,15 +239,15 @@ void ff_copy_rectangle2(FFDrawContext *draw, int dst_x, int dst_y, int src_x, int src_y, int w, int h) { - int plane, y, wp, hp; + int wp, hp; uint8_t *p, *q; - for (plane = 0; plane < draw->nb_planes; plane++) { + for (int plane = 0; plane < draw->nb_planes; plane++) { p = pointer_at(draw, src, src_linesize, plane, src_x, src_y); q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y); wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]) * draw->pixelstep[plane]; hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]); - for (y = 0; y < hp; y++) { + for (int y = 0; y < hp; y++) { memcpy(q, p, wp); p += src_linesize[plane]; q += dst_linesize[plane]; @@ -233,11 +259,11 @@ void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_x, int dst_y, int w, int h) { - int plane, x, y, wp, hp; + int wp, hp; uint8_t *p0, *p; FFDrawColor color_tmp = *color; - for (plane = 0; plane < draw->nb_planes; plane++) { + for (int plane = 0; plane < draw->nb_planes; plane++) { p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y); wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]); hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]); @@ -246,19 +272,19 @@ void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color, p = p0; if (HAVE_BIGENDIAN && draw->desc->comp[0].depth > 8) { - for (x = 0; 2*x < draw->pixelstep[plane]; x++) + for (int x = 0; 2*x < draw->pixelstep[plane]; x++) color_tmp.comp[plane].u16[x] = av_bswap16(color_tmp.comp[plane].u16[x]); } /* copy first line from color */ - for (x = 0; x < wp; x++) { + for (int x = 0; x < wp; x++) { memcpy(p, color_tmp.comp[plane].u8, draw->pixelstep[plane]); p += draw->pixelstep[plane]; } wp *= draw->pixelstep[plane]; /* copy next lines from first line */ p = p0 + dst_linesize[plane]; - for (y = 1; y < hp; y++) { + for (int y = 1; y < hp; y++) { memcpy(p, p0, wp); p += dst_linesize[plane]; } @@ -309,14 +335,13 @@ static void blend_line(uint8_t *dst, unsigned src, unsigned alpha, { unsigned asrc = alpha * src; unsigned tau = 0x1010101 - alpha; - int x; if (left) { unsigned suba = (left * alpha) >> hsub; *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24; dst += dx; } - for (x = 0; x < w; x++) { + for (int x = 0; x < w; x++) { *dst = (*dst * tau + asrc) >> 24; dst += dx; } @@ -331,7 +356,6 @@ static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha, { unsigned asrc = alpha * src; unsigned tau = 0x10001 - alpha; - int x; if (left) { unsigned suba = (left * alpha) >> hsub; @@ -339,7 +363,7 @@ static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha, AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16); dst += dx; } - for (x = 0; x < w; x++) { + for (int x = 0; x < w; x++) { uint16_t value = AV_RL16(dst); AV_WL16(dst, (value * tau + asrc) >> 16); dst += dx; @@ -356,8 +380,8 @@ void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, int dst_w, int dst_h, int x0, int y0, int w, int h) { - unsigned alpha, nb_planes, nb_comp, plane, comp; - int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y; + unsigned alpha, nb_planes, nb_comp; + int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom; uint8_t *p0, *p; nb_comp = draw->desc->nb_components - @@ -377,7 +401,7 @@ void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, } nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA)); nb_planes += !nb_planes; - for (plane = 0; plane < nb_planes; plane++) { + for (unsigned plane = 0; plane < nb_planes; plane++) { p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0); w_sub = w; h_sub = h; @@ -385,7 +409,7 @@ void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, y_sub = y0; subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right); subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom); - for (comp = 0; comp < nb_comp; comp++) { + for (unsigned comp = 0; comp < nb_comp; comp++) { const int depth = draw->desc->comp[comp].depth; const int offset = draw->desc->comp[comp].offset; const int index = offset / ((depth + 7) / 8); @@ -406,14 +430,14 @@ void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, p += dst_linesize[plane]; } if (depth <= 8) { - for (y = 0; y < h_sub; y++) { + for (int y = 0; y < h_sub; y++) { blend_line(p, color->comp[plane].u8[index], alpha, draw->pixelstep[plane], w_sub, draw->hsub[plane], left, right); p += dst_linesize[plane]; } } else { - for (y = 0; y < h_sub; y++) { + for (int y = 0; y < h_sub; y++) { blend_line16(p, color->comp[plane].u16[index], alpha, draw->pixelstep[plane], w_sub, draw->hsub[plane], left, right); @@ -439,16 +463,16 @@ static void blend_pixel16(uint8_t *dst, unsigned src, unsigned alpha, const uint8_t *mask, int mask_linesize, int l2depth, unsigned w, unsigned h, unsigned shift, unsigned xm0) { - unsigned xm, x, y, t = 0; + unsigned t = 0; unsigned xmshf = 3 - l2depth; unsigned xmmod = 7 >> l2depth; unsigned mbits = (1 << (1 << l2depth)) - 1; unsigned mmult = 255 / mbits; uint16_t value = AV_RL16(dst); - for (y = 0; y < h; y++) { - xm = xm0; - for (x = 0; x < w; x++) { + for (unsigned y = 0; y < h; y++) { + unsigned xm = xm0; + for (unsigned x = 0; x < w; x++) { t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits) * mmult; xm++; @@ -463,15 +487,15 @@ static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha, const uint8_t *mask, int mask_linesize, int l2depth, unsigned w, unsigned h, unsigned shift, unsigned xm0) { - unsigned xm, x, y, t = 0; + unsigned t = 0; unsigned xmshf = 3 - l2depth; unsigned xmmod = 7 >> l2depth; unsigned mbits = (1 << (1 << l2depth)) - 1; unsigned mmult = 255 / mbits; - for (y = 0; y < h; y++) { - xm = xm0; - for (x = 0; x < w; x++) { + for (unsigned y = 0; y < h; y++) { + unsigned xm = xm0; + for (unsigned x = 0; x < w; x++) { t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits) * mmult; xm++; @@ -488,7 +512,6 @@ static void blend_line_hv16(uint8_t *dst, int dst_delta, unsigned hsub, unsigned vsub, int xm, int left, int right, int hband) { - int x; if (left) { blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth, @@ -496,7 +519,7 @@ static void blend_line_hv16(uint8_t *dst, int dst_delta, dst += dst_delta; xm += left; } - for (x = 0; x < w; x++) { + for (int x = 0; x < w; x++) { blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth, 1 << hsub, hband, hsub + vsub, xm); dst += dst_delta; @@ -513,7 +536,6 @@ static void blend_line_hv(uint8_t *dst, int dst_delta, unsigned hsub, unsigned vsub, int xm, int left, int right, int hband) { - int x; if (left) { blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth, @@ -521,7 +543,7 @@ static void blend_line_hv(uint8_t *dst, int dst_delta, dst += dst_delta; xm += left; } - for (x = 0; x < w; x++) { + for (int x = 0; x < w; x++) { blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth, 1 << hsub, hband, hsub + vsub, xm); dst += dst_delta; @@ -537,9 +559,9 @@ void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, const uint8_t *mask, int mask_linesize, int mask_w, int mask_h, int l2depth, unsigned endianness, int x0, int y0) { - unsigned alpha, nb_planes, nb_comp, plane, comp; - int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y; - uint8_t *p0, *p; + unsigned alpha, nb_planes, nb_comp; + int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom; + uint8_t *p; const uint8_t *m; nb_comp = draw->desc->nb_components - @@ -559,15 +581,15 @@ void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, } nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA)); nb_planes += !nb_planes; - for (plane = 0; plane < nb_planes; plane++) { - p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0); + for (unsigned plane = 0; plane < nb_planes; plane++) { + uint8_t *p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0); w_sub = mask_w; h_sub = mask_h; x_sub = x0; y_sub = y0; subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right); subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom); - for (comp = 0; comp < nb_comp; comp++) { + for (unsigned comp = 0; comp < nb_comp; comp++) { const int depth = draw->desc->comp[comp].depth; const int offset = draw->desc->comp[comp].offset; const int index = offset / ((depth + 7) / 8); @@ -594,7 +616,7 @@ void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, m += top * mask_linesize; } if (depth <= 8) { - for (y = 0; y < h_sub; y++) { + for (int y = 0; y < h_sub; y++) { blend_line_hv(p, draw->pixelstep[plane], color->comp[plane].u8[index], alpha, m, mask_linesize, l2depth, w_sub, @@ -604,7 +626,7 @@ void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, m += mask_linesize << draw->vsub[plane]; } } else { - for (y = 0; y < h_sub; y++) { + for (int y = 0; y < h_sub; y++) { blend_line_hv16(p, draw->pixelstep[plane], color->comp[plane].u16[index], alpha, m, mask_linesize, l2depth, w_sub, @@ -647,12 +669,11 @@ int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir, AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags) { - enum AVPixelFormat i; FFDrawContext draw; AVFilterFormats *fmts = NULL; int ret; - for (i = 0; av_pix_fmt_desc_get(i); i++) + for (enum AVPixelFormat i = 0; av_pix_fmt_desc_get(i); i++) if (ff_draw_init(&draw, i, flags) >= 0 && (ret = ff_add_format(&fmts, i)) < 0) return NULL; diff --git a/libavfilter/drawutils.h b/libavfilter/drawutils.h index 90df55107..a7fc967a8 100644 --- a/libavfilter/drawutils.h +++ b/libavfilter/drawutils.h @@ -29,6 +29,7 @@ #include "libavutil/pixfmt.h" int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt); +int ff_fill_ayuv_map(uint8_t *ayuv_map, enum AVPixelFormat pix_fmt); #define MAX_PLANES 4 @@ -44,6 +45,7 @@ typedef struct FFDrawContext { enum AVColorRange range; unsigned flags; enum AVColorSpace csp; + enum AVAlphaMode alpha; double rgb2yuv[3][3]; } FFDrawContext; @@ -77,7 +79,14 @@ typedef struct FFDrawColor { * @return 0 for success, < 0 for error */ int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSpace csp, - enum AVColorRange range, unsigned flags); + enum AVColorRange range, enum AVAlphaMode alpha, unsigned flags); + +/** + * Init a draw context, taking the format, colorspace and range from the given + * filter link. + */ +int ff_draw_init_from_link(FFDrawContext *draw, const AVFilterLink *link, + unsigned flags); /* * Legacy wrapper for ff_draw_init2. diff --git a/libavfilter/f_bench.c b/libavfilter/f_bench.c index 3f1fa23ae..2546adc28 100644 --- a/libavfilter/f_bench.c +++ b/libavfilter/f_bench.c @@ -80,7 +80,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) s->n++; s->min = FFMIN(s->min, diff); s->max = FFMAX(s->max, diff); - av_log(s, AV_LOG_INFO, "t:%f avg:%f max:%f min:%f\n", + av_log(ctx, AV_LOG_INFO, "t:%f avg:%f max:%f min:%f\n", T2F(diff), T2F(s->sum / s->n), T2F(s->max), T2F(s->min)); } av_dict_set(&in->metadata, START_TIME_KEY, NULL, 0); @@ -101,15 +101,15 @@ static const AVFilterPad bench_inputs[] = { }, }; -const AVFilter ff_vf_bench = { - .name = "bench", - .description = NULL_IF_CONFIG_SMALL("Benchmark part of a filtergraph."), +const FFFilter ff_vf_bench = { + .p.name = "bench", + .p.description = NULL_IF_CONFIG_SMALL("Benchmark part of a filtergraph."), + .p.priv_class = &bench_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(BenchContext), .init = init, FILTER_INPUTS(bench_inputs), FILTER_OUTPUTS(ff_video_default_filterpad), - .priv_class = &bench_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, }; #endif /* CONFIG_BENCH_FILTER */ @@ -125,14 +125,14 @@ static const AVFilterPad abench_inputs[] = { }, }; -const AVFilter ff_af_abench = { - .name = "abench", - .description = NULL_IF_CONFIG_SMALL("Benchmark part of a filtergraph."), +const FFFilter ff_af_abench = { + .p.name = "abench", + .p.description = NULL_IF_CONFIG_SMALL("Benchmark part of a filtergraph."), + .p.priv_class = &abench_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(BenchContext), .init = init, FILTER_INPUTS(abench_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - .priv_class = &abench_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, }; #endif /* CONFIG_ABENCH_FILTER */ diff --git a/libavfilter/f_cue.c b/libavfilter/f_cue.c index 38500bb51..63027c7c2 100644 --- a/libavfilter/f_cue.c +++ b/libavfilter/f_cue.c @@ -100,10 +100,10 @@ static const AVOption options[] = { AVFILTER_DEFINE_CLASS_EXT(cue_acue, "(a)cue", options); #if CONFIG_CUE_FILTER -const AVFilter ff_vf_cue = { - .name = "cue", - .description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."), - .priv_class = &cue_acue_class, +const FFFilter ff_vf_cue = { + .p.name = "cue", + .p.description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."), + .p.priv_class = &cue_acue_class, .priv_size = sizeof(CueContext), FILTER_INPUTS(ff_video_default_filterpad), FILTER_OUTPUTS(ff_video_default_filterpad), @@ -112,12 +112,12 @@ const AVFilter ff_vf_cue = { #endif /* CONFIG_CUE_FILTER */ #if CONFIG_ACUE_FILTER -const AVFilter ff_af_acue = { - .name = "acue", - .description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."), - .priv_class = &cue_acue_class, +const FFFilter ff_af_acue = { + .p.name = "acue", + .p.description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."), + .p.priv_class = &cue_acue_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(CueContext), - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(ff_audio_default_filterpad), .activate = activate, diff --git a/libavfilter/f_drawgraph.c b/libavfilter/f_drawgraph.c index 7c6a83be7..c9ac6c0ca 100644 --- a/libavfilter/f_drawgraph.c +++ b/libavfilter/f_drawgraph.c @@ -127,17 +127,18 @@ static av_cold int init(AVFilterContext *ctx) return 0; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; int ret; - AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(fmts_list, &outlink->incfg.formats)) < 0) + AVFilterFormats *fmts_list = ff_make_pixel_format_list(pix_fmts); + if ((ret = ff_formats_ref(fmts_list, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -473,16 +474,16 @@ static const AVFilterPad drawgraph_inputs[] = { }, }; -const AVFilter ff_vf_drawgraph = { - .name = "drawgraph", - .description = NULL_IF_CONFIG_SMALL("Draw a graph using input video metadata."), +const FFFilter ff_vf_drawgraph = { + .p.name = "drawgraph", + .p.description = NULL_IF_CONFIG_SMALL("Draw a graph using input video metadata."), + .p.priv_class = &drawgraph_class, .priv_size = sizeof(DrawGraphContext), - .priv_class = &drawgraph_class, .init = init, .uninit = uninit, FILTER_INPUTS(drawgraph_inputs), FILTER_OUTPUTS(drawgraph_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; #endif // CONFIG_DRAWGRAPH_FILTER @@ -497,15 +498,15 @@ static const AVFilterPad adrawgraph_inputs[] = { }, }; -const AVFilter ff_avf_adrawgraph = { - .name = "adrawgraph", - .description = NULL_IF_CONFIG_SMALL("Draw a graph using input audio metadata."), - .priv_class = &drawgraph_class, +const FFFilter ff_avf_adrawgraph = { + .p.name = "adrawgraph", + .p.description = NULL_IF_CONFIG_SMALL("Draw a graph using input audio metadata."), + .p.priv_class = &drawgraph_class, .priv_size = sizeof(DrawGraphContext), .init = init, .uninit = uninit, FILTER_INPUTS(adrawgraph_inputs), FILTER_OUTPUTS(drawgraph_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; #endif // CONFIG_ADRAWGRAPH_FILTER diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c index f71c230b4..46ff702e6 100644 --- a/libavfilter/f_ebur128.c +++ b/libavfilter/f_ebur128.c @@ -43,6 +43,8 @@ #include "formats.h" #include "video.h" +#include "f_ebur128.h" + #define ABS_THRES -70 ///< silence gate: we discard anything below this absolute (LUFS) threshold #define ABS_UP_THRES 10 ///< upper loud limit to consider (ABS_THRES being the minimum) #define HIST_GRAIN 100 ///< defines histogram precision @@ -62,7 +64,7 @@ struct hist_entry { }; struct integrator { - double **cache; ///< window of filtered samples (N ms) + double *cache; ///< window of filtered samples (N ms) int cache_pos; ///< focus on the last added bin in the cache array int cache_size; double *sum; ///< sum of the last N ms filtered samples (cache content) @@ -77,6 +79,7 @@ struct rect { int x, y, w, h; }; typedef struct EBUR128Context { const AVClass *class; ///< AVClass context for log and options purpose + EBUR128DSPContext dsp; /* peak metering */ int peak_mode; ///< enabled peak modes @@ -113,16 +116,6 @@ typedef struct EBUR128Context { int idx_insample; ///< current sample position of processed samples in single input frame AVFrame *insamples; ///< input samples reference, updated regularly - /* Filter caches. - * The mult by 3 in the following is for X[i], X[i-1] and X[i-2] */ - double *x; ///< 3 input samples cache for each channel - double *y; ///< 3 pre-filter samples cache for each channel - double *z; ///< 3 RLB-filter samples cache for each channel - double pre_b[3]; ///< pre-filter numerator coefficients - double pre_a[3]; ///< pre-filter denominator coefficients - double rlb_b[3]; ///< rlb-filter numerator coefficients - double rlb_a[3]; ///< rlb-filter denominator coefficients - struct integrator i400; ///< 400ms integrator, used for Momentary loudness (M), and Integrated loudness (I) struct integrator i3000; ///< 3s integrator, used for Short term loudness (S), and Loudness Range (LRA) @@ -253,8 +246,8 @@ static void drawtext(AVFrame *pic, int x, int y, int ftid, const uint8_t *color, int font_height; va_list vl; - if (ftid == FONT16) font = avpriv_vga16_font, font_height = 16; - else if (ftid == FONT8) font = avpriv_cga_font, font_height = 8; + if (ftid == FONT16) font = avpriv_vga16_font_get(), font_height = 16; + else if (ftid == FONT8) font = avpriv_cga_font_get(), font_height = 8; else return; va_start(vl, fmt); @@ -406,21 +399,21 @@ static int config_audio_input(AVFilterLink *inlink) double a0 = 1.0 + K / Q + K * K; - ebur128->pre_b[0] = (Vh + Vb * K / Q + K * K) / a0; - ebur128->pre_b[1] = 2.0 * (K * K - Vh) / a0; - ebur128->pre_b[2] = (Vh - Vb * K / Q + K * K) / a0; - ebur128->pre_a[1] = 2.0 * (K * K - 1.0) / a0; - ebur128->pre_a[2] = (1.0 - K / Q + K * K) / a0; + ebur128->dsp.pre.b0 = (Vh + Vb * K / Q + K * K) / a0; + ebur128->dsp.pre.b1 = 2.0 * (K * K - Vh) / a0; + ebur128->dsp.pre.b2 = (Vh - Vb * K / Q + K * K) / a0; + ebur128->dsp.pre.a1 = 2.0 * (K * K - 1.0) / a0; + ebur128->dsp.pre.a2 = (1.0 - K / Q + K * K) / a0; f0 = 38.13547087602444; Q = 0.5003270373238773; K = tan(M_PI * f0 / (double)inlink->sample_rate); - ebur128->rlb_b[0] = 1.0; - ebur128->rlb_b[1] = -2.0; - ebur128->rlb_b[2] = 1.0; - ebur128->rlb_a[1] = 2.0 * (K * K - 1.0) / (1.0 + K / Q + K * K); - ebur128->rlb_a[2] = (1.0 - K / Q + K * K) / (1.0 + K / Q + K * K); + ebur128->dsp.rlb.b0 = 1.0; + ebur128->dsp.rlb.b1 = -2.0; + ebur128->dsp.rlb.b2 = 1.0; + ebur128->dsp.rlb.a1 = 2.0 * (K * K - 1.0) / (1.0 + K / Q + K * K); + ebur128->dsp.rlb.a2 = (1.0 - K / Q + K * K) / (1.0 + K / Q + K * K); /* Force 100ms framing in case of metadata injection: the frames must have * a granularity of the window overlap to be accurately exploited. @@ -446,20 +439,21 @@ static int config_audio_output(AVFilterLink *outlink) AV_CH_SURROUND_DIRECT_LEFT |AV_CH_SURROUND_DIRECT_RIGHT) ebur128->nb_channels = nb_channels; - ebur128->x = av_calloc(nb_channels, 3 * sizeof(*ebur128->x)); - ebur128->y = av_calloc(nb_channels, 3 * sizeof(*ebur128->y)); - ebur128->z = av_calloc(nb_channels, 3 * sizeof(*ebur128->z)); + ebur128->dsp.y = av_calloc(nb_channels, 3 * sizeof(*ebur128->dsp.y)); + ebur128->dsp.z = av_calloc(nb_channels, 3 * sizeof(*ebur128->dsp.z)); ebur128->ch_weighting = av_calloc(nb_channels, sizeof(*ebur128->ch_weighting)); - if (!ebur128->ch_weighting || !ebur128->x || !ebur128->y || !ebur128->z) + if (!ebur128->ch_weighting || !ebur128->dsp.y || !ebur128->dsp.z) return AVERROR(ENOMEM); #define I400_BINS(x) ((x) * 4 / 10) #define I3000_BINS(x) ((x) * 3) + ebur128->i400.cache_size = I400_BINS(outlink->sample_rate); + ebur128->i3000.cache_size = I3000_BINS(outlink->sample_rate); ebur128->i400.sum = av_calloc(nb_channels, sizeof(*ebur128->i400.sum)); ebur128->i3000.sum = av_calloc(nb_channels, sizeof(*ebur128->i3000.sum)); - ebur128->i400.cache = av_calloc(nb_channels, sizeof(*ebur128->i400.cache)); - ebur128->i3000.cache = av_calloc(nb_channels, sizeof(*ebur128->i3000.cache)); + ebur128->i400.cache = av_calloc(nb_channels * ebur128->i400.cache_size, sizeof(*ebur128->i400.cache)); + ebur128->i3000.cache = av_calloc(nb_channels * ebur128->i3000.cache_size, sizeof(*ebur128->i3000.cache)); if (!ebur128->i400.sum || !ebur128->i3000.sum || !ebur128->i400.cache || !ebur128->i3000.cache) return AVERROR(ENOMEM); @@ -474,17 +468,6 @@ static int config_audio_output(AVFilterLink *outlink) } else { ebur128->ch_weighting[i] = 1.0; } - - if (!ebur128->ch_weighting[i]) - continue; - - /* bins buffer for the two integration window (400ms and 3s) */ - ebur128->i400.cache_size = I400_BINS(outlink->sample_rate); - ebur128->i3000.cache_size = I3000_BINS(outlink->sample_rate); - ebur128->i400.cache[i] = av_calloc(ebur128->i400.cache_size, sizeof(*ebur128->i400.cache[0])); - ebur128->i3000.cache[i] = av_calloc(ebur128->i3000.cache_size, sizeof(*ebur128->i3000.cache[0])); - if (!ebur128->i400.cache[i] || !ebur128->i3000.cache[i]) - return AVERROR(ENOMEM); } #if CONFIG_SWRESAMPLE @@ -519,6 +502,9 @@ static int config_audio_output(AVFilterLink *outlink) return AVERROR(ENOMEM); } +#if ARCH_X86 && HAVE_X86ASM + ff_ebur128_init_x86(&ebur128->dsp, nb_channels); +#endif return 0; } @@ -596,6 +582,8 @@ static av_cold int init(AVFilterContext *ctx) /* summary */ av_log(ctx, AV_LOG_VERBOSE, "EBU +%d scale\n", ebur128->meter); + ebur128->dsp.filter_channels = ff_ebur128_filter_channels_c; + ebur128->dsp.find_peak = ff_ebur128_find_peak_c; return 0; } @@ -626,11 +614,65 @@ static int gate_update(struct integrator *integ, double power, return gate_hist_pos; } +void ff_ebur128_filter_channels_c(const EBUR128DSPContext *dsp, + const double *restrict samples, + double *restrict cache_400, + double *restrict cache_3000, + double *restrict sum_400, + double *restrict sum_3000, + const int nb_channels) +{ + const EBUR128Biquad pre = dsp->pre; + const EBUR128Biquad rlb = dsp->rlb; + + for (int ch = 0; ch < nb_channels; ch++) { + /* Y[i] = X[i]*b0 + X[i-1]*b1 + X[i-2]*b2 - Y[i-1]*a1 - Y[i-2]*a2 */ +#define FILTER(DST, SRC, FILT) do { \ + const double tmp = DST[0] = FILT.b0 * SRC + DST[1]; \ + DST[1] = FILT.b1 * SRC + DST[2] - FILT.a1 * tmp; \ + DST[2] = FILT.b2 * SRC - FILT.a2 * tmp; \ +} while (0) + + const double x = samples[ch]; + double *restrict y = &dsp->y[3 * ch]; + double *restrict z = &dsp->z[3 * ch]; + + // TODO: merge both filters in one? + FILTER(y, x, pre); // apply pre-filter + FILTER(z, *y, rlb); // apply RLB-filter + + /* add the new value, and limit the sum to the cache size (400ms or 3s) + * by removing the oldest one */ + const double bin = *z * *z; + sum_400 [ch] += bin - cache_400[ch]; + sum_3000[ch] += bin - cache_3000[ch]; + cache_400[ch] = cache_3000[ch] = bin; + } +} + +double ff_ebur128_find_peak_c(double *restrict ch_peaks, const int nb_channels, + const double *samples, const int nb_samples) +{ + double maxpeak = 0.0; + for (int ch = 0; ch < nb_channels; ch++) { + double ch_peak = ch_peaks[ch]; + for (int i = 0; i < nb_samples; i++) { + const double sample = fabs(samples[i * nb_channels + ch]); + ch_peak = FFMAX(ch_peak, sample); + } + maxpeak = FFMAX(maxpeak, ch_peak); + ch_peaks[ch] = ch_peak; + } + + return maxpeak; +} + static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) { - int i, ch, idx_insample, ret; + int ret; AVFilterContext *ctx = inlink->dst; EBUR128Context *ebur128 = ctx->priv; + const EBUR128DSPContext *dsp = &ebur128->dsp; const int nb_channels = ebur128->nb_channels; const int nb_samples = insamples->nb_samples; const double *samples = (double *)insamples->data[0]; @@ -643,87 +685,48 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) (const uint8_t **)insamples->data, nb_samples); if (ret < 0) return ret; - for (ch = 0; ch < nb_channels; ch++) - ebur128->true_peaks_per_frame[ch] = 0.0; - for (idx_insample = 0; idx_insample < ret; idx_insample++) { - for (ch = 0; ch < nb_channels; ch++) { - ebur128->true_peaks[ch] = FFMAX(ebur128->true_peaks[ch], fabs(*swr_samples)); - ebur128->true_peaks_per_frame[ch] = FFMAX(ebur128->true_peaks_per_frame[ch], - fabs(*swr_samples)); - swr_samples++; - } + + memset(ebur128->true_peaks_per_frame, 0, + nb_channels * sizeof(*ebur128->true_peaks_per_frame)); + + double peak = dsp->find_peak(ebur128->true_peaks_per_frame, nb_channels, + swr_samples, ret); + + for (int ch = 0; ch < nb_channels; ch++) { + peak = FFMAX(peak, ebur128->true_peaks[ch]); + ebur128->true_peaks[ch] = FFMAX(ebur128->true_peaks[ch], + ebur128->true_peaks_per_frame[ch]); } + + ebur128->true_peak = DBFS(peak); } #endif - for (idx_insample = ebur128->idx_insample; idx_insample < nb_samples; idx_insample++) { - const int bin_id_400 = ebur128->i400.cache_pos; - const int bin_id_3000 = ebur128->i3000.cache_pos; + if (ebur128->peak_mode & PEAK_MODE_SAMPLES_PEAKS) { + double peak = dsp->find_peak(ebur128->sample_peaks, nb_channels, + samples, nb_samples); + ebur128->sample_peak = DBFS(peak); + } -#define MOVE_TO_NEXT_CACHED_ENTRY(time) do { \ - ebur128->i##time.cache_pos++; \ - if (ebur128->i##time.cache_pos == \ - ebur128->i##time.cache_size) { \ - ebur128->i##time.filled = 1; \ - ebur128->i##time.cache_pos = 0; \ - } \ -} while (0) + for (int idx_insample = ebur128->idx_insample; idx_insample < nb_samples; idx_insample++) { + const int bin_id_400 = ebur128->i400.cache_pos++; + const int bin_id_3000 = ebur128->i3000.cache_pos++; - MOVE_TO_NEXT_CACHED_ENTRY(400); - MOVE_TO_NEXT_CACHED_ENTRY(3000); - - for (ch = 0; ch < nb_channels; ch++) { - double bin; - - if (ebur128->peak_mode & PEAK_MODE_SAMPLES_PEAKS) - ebur128->sample_peaks[ch] = FFMAX(ebur128->sample_peaks[ch], fabs(samples[idx_insample * nb_channels + ch])); - - ebur128->x[ch * 3] = samples[idx_insample * nb_channels + ch]; // set X[i] - - if (!ebur128->ch_weighting[ch]) - continue; - - /* Y[i] = X[i]*b0 + X[i-1]*b1 + X[i-2]*b2 - Y[i-1]*a1 - Y[i-2]*a2 */ -#define FILTER(Y, X, NUM, DEN) do { \ - double *dst = ebur128->Y + ch*3; \ - double *src = ebur128->X + ch*3; \ - dst[2] = dst[1]; \ - dst[1] = dst[0]; \ - dst[0] = src[0]*NUM[0] + src[1]*NUM[1] + src[2]*NUM[2] \ - - dst[1]*DEN[1] - dst[2]*DEN[2]; \ -} while (0) - - // TODO: merge both filters in one? - FILTER(y, x, ebur128->pre_b, ebur128->pre_a); // apply pre-filter - ebur128->x[ch * 3 + 2] = ebur128->x[ch * 3 + 1]; - ebur128->x[ch * 3 + 1] = ebur128->x[ch * 3 ]; - FILTER(z, y, ebur128->rlb_b, ebur128->rlb_a); // apply RLB-filter - - bin = ebur128->z[ch * 3] * ebur128->z[ch * 3]; - - /* add the new value, and limit the sum to the cache size (400ms or 3s) - * by removing the oldest one */ - ebur128->i400.sum [ch] = ebur128->i400.sum [ch] + bin - ebur128->i400.cache [ch][bin_id_400]; - ebur128->i3000.sum[ch] = ebur128->i3000.sum[ch] + bin - ebur128->i3000.cache[ch][bin_id_3000]; - - /* override old cache entry with the new value */ - ebur128->i400.cache [ch][bin_id_400 ] = bin; - ebur128->i3000.cache[ch][bin_id_3000] = bin; + if (ebur128->i400.cache_pos == ebur128->i400.cache_size) { + ebur128->i400.filled = 1; + ebur128->i400.cache_pos = 0; } -#define FIND_PEAK(global, sp, ptype) do { \ - int ch; \ - double maxpeak; \ - maxpeak = 0.0; \ - if (ebur128->peak_mode & PEAK_MODE_ ## ptype ## _PEAKS) { \ - for (ch = 0; ch < ebur128->nb_channels; ch++) \ - maxpeak = FFMAX(maxpeak, sp[ch]); \ - global = DBFS(maxpeak); \ - } \ -} while (0) + if (ebur128->i3000.cache_pos == ebur128->i3000.cache_size) { + ebur128->i3000.filled = 1; + ebur128->i3000.cache_pos = 0; + } - FIND_PEAK(ebur128->sample_peak, ebur128->sample_peaks, SAMPLES); - FIND_PEAK(ebur128->true_peak, ebur128->true_peaks, TRUE); + dsp->filter_channels(dsp, &samples[idx_insample * nb_channels], + &ebur128->i400.cache[bin_id_400 * nb_channels], + &ebur128->i3000.cache[bin_id_3000 * nb_channels], + ebur128->i400.sum, ebur128->i3000.sum, + nb_channels); /* For integrated loudness, gating blocks are 400ms long with 75% * overlap (see BS.1770-2 p5), so a re-computation is needed each 100ms @@ -741,7 +744,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) #define COMPUTE_LOUDNESS(m, time) do { \ if (ebur128->i##time.filled) { \ /* weighting sum of the last